From 864957742be37ec5d6ce1a2b2984eebe1fa9ab87 Mon Sep 17 00:00:00 2001 From: AwesomeLogic <36323763+Awesome-Logic@users.noreply.github.com> Date: Thu, 7 May 2020 18:57:26 +0530 Subject: [PATCH 001/417] Added os.chdir() in ballistica_server.py I realized the script couldn't be executed from other directories so I added the chdir function. Now the script can be properly executed from anywhere. If that was intended, feel free to reject the request. Also first pull request :) --- assets/src/server/ballisticacore_server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index 8ce43e83..b8a42dae 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -31,6 +31,10 @@ from threading import Thread, Lock, current_thread from pathlib import Path from typing import TYPE_CHECKING +# We change our working directory according to file's path +# so that the script can be properly executed from anywhere +os.chdir(os.path.abspath(os.path.dirname(__file__))) + # We make use of the bacommon and efro packages as well as site-packages # included with our bundled Ballistica dist. sys.path += [ From 7b50b1e3b5d70fe39f7f6c5aa0197669c53de4e4 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 7 May 2020 20:00:40 +0530 Subject: [PATCH 002/417] Fixed Formatting --- assets/src/server/ballisticacore_server.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index b8a42dae..f3933baa 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -22,16 +22,21 @@ """BallisticaCore server manager.""" from __future__ import annotations -import sys -import os import json +import os import subprocess +import sys import time -from threading import Thread, Lock, current_thread from pathlib import Path +from threading import Lock, Thread, current_thread from typing import TYPE_CHECKING -# We change our working directory according to file's path +from bacommon.servermanager import ServerConfig, StartServerModeCommand +from efro.dataclasses import dataclass_assign, dataclass_validate +from efro.error import CleanError +from efro.terminal import Clr + +# We change our working directory according to file's path # so that the script can be properly executed from anywhere os.chdir(os.path.abspath(os.path.dirname(__file__))) @@ -42,10 +47,6 @@ sys.path += [ str(Path(os.getcwd(), 'dist', 'ba_data', 'python-site-packages')) ] -from efro.terminal import Clr -from efro.error import CleanError -from efro.dataclasses import dataclass_assign, dataclass_validate -from bacommon.servermanager import (ServerConfig, StartServerModeCommand) if TYPE_CHECKING: from typing import Optional, List, Dict, Union, Tuple From 49d4cf356084688360c4f04b3eb0fea583180a1e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 11:52:53 -0700 Subject: [PATCH 003/417] Syncing latest changes between public/private. --- .efrocachemap | 24 +++++++++++----------- assets/src/server/ballisticacore_server.py | 1 - 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 0ef6ded0..7e5897a3 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/eb/d0/41ac3000831997f7311ab1c12619", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5e/34/501f1f0d214b0b71a83f8fc22096", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dc/6c/52b76d1e1d0202a0184860b9ff6e", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/45/989dfb31fe5af86bd43089e5181a", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d5/2b/be060358811b7ea5108c18a12d9d", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bd/f8/777aa2abf6debb13619d2d59bb25", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/88/a2cf99e4c0813b76e1ac19b7a956", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ed/86/249605f11e08d0211d198146d368", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/26/2b/cee80a566e95d637cecfd667e124", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8a/23/40ae61cee91379aef206966d3de1", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/17/92/a8664301169a06904ed31c0f9648", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/de/f4/3908b1cca896ddd96be9d339179f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/5f/2700a5e06a86a81604894a3b2240", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/de/e71297599ee09eee5cdb60b7966a", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/84/d6/c465935f4ddfdbf4dbece8bd2235", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/10/4cc139ad708ca715a4b434c1f4d3", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/91/89d0eb1dffc8983107f43509fd26", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/01/c9221265bdd1e66a82a39257c167", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e5/fa/298fe760d4a2805360a2ab29643c", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/f0/383cdaad06072de360ac9e1b1983", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bf/fc/a23ac37afd819f3c9ba33703b458", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/44/4a/b819a375166fc20d49172fd43c9e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dc/00/7c8757b96a90061bb7bc0adb6e0f", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/14/68/10beaa487882d09f9a2be90d5e1d" } \ No newline at end of file diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index f3933baa..926043b5 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -47,7 +47,6 @@ sys.path += [ str(Path(os.getcwd(), 'dist', 'ba_data', 'python-site-packages')) ] - if TYPE_CHECKING: from typing import Optional, List, Dict, Union, Tuple from types import FrameType From dfb2ba4779878383ec39209667bfc70b8c5b50d8 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Thu, 7 May 2020 22:35:53 +0300 Subject: [PATCH 004/417] Change-Character-Attack protection If chooser changes character too quickly, server just breaks down with some error (but it not restarts, just does not let anyone in) This protections kicks players what changes characters too quickly and too much) --- assets/src/ba_data/python/ba/_lobby.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index e755849f..9d23ab84 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -35,6 +35,10 @@ if TYPE_CHECKING: import ba +MAX_QUICK_CHANGE_COUNT = 30 +QUICK_CHANGE_INTERVAL = 0.05 + + # Hmm should we move this to actors?.. class JoinInfo: """Display useful info for joiners.""" @@ -169,6 +173,7 @@ class Chooser: self._profilenames: List[str] = [] self._ready: bool = False self.character_names: List[str] = [] + self.last_change: Sequence[Union[float, count]] = (0, 0) # Hmm does this need to be public? self.profiles: Dict[str, Dict[str, Any]] = {} @@ -663,6 +668,13 @@ class Chooser: def handlemessage(self, msg: Any) -> Any: """Standard generic message handler.""" if isinstance(msg, ChangeMessage): + now = ba.time() + count = self.last_change[1] + 1 + if now - self.last_change[0] < QUICK_CHANGE_INTERVAL and count > MAX_QUICK_CHANGE_COUNT: + # Hmm maybe we should notify client? + _ba.disconnect_client(self._player.get_input_device().client_id) + self.last_change = (now, count) +0 # If we've been removed from the lobby, ignore this stuff. if self._dead: From e43ef6d48b0cf99d018e83ff0565900e9f039c30 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Thu, 7 May 2020 23:26:17 +0300 Subject: [PATCH 005/417] preflight --- assets/src/ba_data/python/ba/_lobby.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 9d23ab84..adf525a2 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -34,7 +34,6 @@ if TYPE_CHECKING: from typing import Optional, List, Dict, Any, Sequence, Union import ba - MAX_QUICK_CHANGE_COUNT = 30 QUICK_CHANGE_INTERVAL = 0.05 @@ -173,7 +172,7 @@ class Chooser: self._profilenames: List[str] = [] self._ready: bool = False self.character_names: List[str] = [] - self.last_change: Sequence[Union[float, count]] = (0, 0) + self.last_change: Sequence[Union[float, int]] = (0, 0) # Hmm does this need to be public? self.profiles: Dict[str, Dict[str, Any]] = {} @@ -668,13 +667,14 @@ class Chooser: def handlemessage(self, msg: Any) -> Any: """Standard generic message handler.""" if isinstance(msg, ChangeMessage): - now = ba.time() + now = _ba.time() count = self.last_change[1] + 1 - if now - self.last_change[0] < QUICK_CHANGE_INTERVAL and count > MAX_QUICK_CHANGE_COUNT: + if (now - self.last_change[0] < QUICK_CHANGE_INTERVAL + and count > MAX_QUICK_CHANGE_COUNT): # Hmm maybe we should notify client? - _ba.disconnect_client(self._player.get_input_device().client_id) + _ba.disconnect_client( + self._player.get_input_device().client_id) self.last_change = (now, count) -0 # If we've been removed from the lobby, ignore this stuff. if self._dead: From cb01f00ed876f85746e4b6574e39076c0192b44d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 13:50:30 -0700 Subject: [PATCH 006/417] Changing Activity.settings to Activity.settings_raw to make way for type-safe replacement --- .efrocachemap | 24 +++---- assets/src/ba_data/python/ba/_activity.py | 11 +++- assets/src/ba_data/python/ba/_coopgame.py | 5 +- assets/src/ba_data/python/ba/_gameactivity.py | 14 ++-- .../python/bastd/activity/drawscore.py | 2 +- .../python/bastd/activity/dualteamscore.py | 2 +- .../bastd/activity/freeforallvictory.py | 2 +- .../python/bastd/activity/multiteamvictory.py | 5 +- .../src/ba_data/python/bastd/game/assault.py | 21 +++--- .../python/bastd/game/capturetheflag.py | 29 +++++---- .../ba_data/python/bastd/game/chosenone.py | 26 ++++---- .../src/ba_data/python/bastd/game/conquest.py | 9 +-- .../ba_data/python/bastd/game/deathmatch.py | 15 +++-- .../ba_data/python/bastd/game/elimination.py | 13 ++-- .../src/ba_data/python/bastd/game/football.py | 14 ++-- .../src/ba_data/python/bastd/game/hockey.py | 14 ++-- .../src/ba_data/python/bastd/game/keepaway.py | 14 ++-- .../python/bastd/game/kingofthehill.py | 14 ++-- .../ba_data/python/bastd/game/meteorshower.py | 23 +++++-- .../ba_data/python/bastd/game/ninjafight.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 64 +++++++++---------- .../ba_data/python/bastd/game/runaround.py | 2 +- .../python/bastd/game/targetpractice.py | 6 +- .../ba_data/python/bastd/game/thelaststand.py | 2 +- docs/ba_module.md | 21 +++--- tools/snippets | 4 +- 26 files changed, 195 insertions(+), 163 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 7e5897a3..9281a2bb 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/5f/2700a5e06a86a81604894a3b2240", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/de/e71297599ee09eee5cdb60b7966a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/84/d6/c465935f4ddfdbf4dbece8bd2235", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/10/4cc139ad708ca715a4b434c1f4d3", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/91/89d0eb1dffc8983107f43509fd26", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/01/c9221265bdd1e66a82a39257c167", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e5/fa/298fe760d4a2805360a2ab29643c", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/f0/383cdaad06072de360ac9e1b1983", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bf/fc/a23ac37afd819f3c9ba33703b458", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/44/4a/b819a375166fc20d49172fd43c9e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dc/00/7c8757b96a90061bb7bc0adb6e0f", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/14/68/10beaa487882d09f9a2be90d5e1d" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/b0/12e2602010f316e3c26da125bf25", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/50/12/5a87ef4e3b502f1e62f5f2c65985", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/04/0d/5e5e5783775b70d06de5113904d7", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/46/fd8487f22aaaf68d310e66c8b5de", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/39/04b55a4b918602fbf06dccc4f3c3", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/ab/5b265ac08141fae86f6102fb362c", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/a7/c2f6454984d5639c39abd5bd871f", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/3a/f67ce2222af11d3ee614ba55e1f0", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/01/f33e921238d1bded473de5964ce4", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/1b/16fa91c7ccba5b20ea9a4ca3e0a4", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5c/6a/8e947d1317c67dc84856c5649fee", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7d/aa/901e45f5991e3907f0d9033ccdcf" } \ No newline at end of file diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 97294640..904fe28e 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -45,8 +45,11 @@ class Activity(DependencyComponent): Attributes: - settings + settings_raw The settings dict passed in when the activity was made. + This attribute is deprecated and should be avoided when possible; + activities should pull all values they need from the 'settings' arg + passed to the Activity __init__ call. teams The list of ba.Teams in the Activity. This gets populated just before @@ -64,7 +67,7 @@ class Activity(DependencyComponent): # pylint: disable=too-many-public-methods # Annotating attr types at the class level lets us introspect them. - settings: Dict[str, Any] + settings_raw: Dict[str, Any] teams: List[ba.Team] players: List[ba.Player] @@ -102,7 +105,9 @@ class Activity(DependencyComponent): if _ba.getactivity(doraise=False) is not self: raise Exception('invalid context state') - self.settings = settings + # Should perhaps kill this; activities should validate/store whatever + # settings they need at init time (in a more type-safe way). + self.settings_raw = settings self._has_transitioned_in = False self._has_begun = False diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index b48187a2..bcad453d 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -70,7 +70,7 @@ class CoopGameActivity(GameActivity): campaign = self.session.campaign assert campaign is not None config_str = (str(len(self.players)) + 'p' + campaign.get_level( - self.settings['name']).get_score_version_string().replace( + self.settings_raw['name']).get_score_version_string().replace( ' ', '_')) _ba.get_scores_to_beat(levelname, config_str, _general.WeakCall(self._on_got_scores_to_beat)) @@ -126,7 +126,8 @@ class CoopGameActivity(GameActivity): def _get_coop_level_name(self) -> str: assert self.session.campaign is not None - return self.session.campaign.name + ':' + str(self.settings['name']) + return self.session.campaign.name + ':' + str( + self.settings_raw['name']) def celebrate(self, duration: float) -> None: """Tells all existing player-controlled characters to celebrate. diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index e9b16efd..9acceb3f 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -370,7 +370,7 @@ class GameActivity(Activity): def get_instance_display_string(self) -> ba.Lstr: """Return a name for this particular game instance.""" - return self.get_display_string(self.settings) + return self.get_display_string(self.settings_raw) def get_instance_scoreboard_display_string(self) -> ba.Lstr: """Return a name for this particular game instance. @@ -410,7 +410,7 @@ class GameActivity(Activity): # and can properly translate to 'Anota 3 goles.' in Spanish. # If we just returned the string 'Score 3 Goals' here, there would # have to be a translation entry for each specific number. ew. - return ['Score ${ARG1} goals.', self.settings['Score to Win']] + return ['Score ${ARG1} goals.', self.settings_raw['Score to Win']] This way the first string can be consistently translated, with any arg values then substituted into the result. ${ARG1} will be replaced with @@ -436,7 +436,7 @@ class GameActivity(Activity): # and can properly translate to 'anota 3 goles' in Spanish. # If we just returned the string 'score 3 goals' here, there would # have to be a translation entry for each specific number. ew. - return ['score ${ARG1} goals', self.settings['Score to Win']] + return ['score ${ARG1} goals', self.settings_raw['Score to Win']] This way the first string can be consistently translated, with any arg values then substituted into the result. ${ARG1} will be replaced @@ -816,7 +816,7 @@ class GameActivity(Activity): subs=subs) # do some standard filters (epic mode, etc) - if 'Epic Mode' in self.settings and self.settings['Epic Mode']: + if self.settings_raw.get('Epic Mode', False): translation = Lstr(resource='epicDescriptionFilterText', subs=[('${DESCRIPTION}', translation)]) vrmode = _ba.app.vr_mode @@ -1021,9 +1021,9 @@ class GameActivity(Activity): else: respawn_time = 7.0 - # if this standard setting is present, factor it in - if 'Respawn Times' in self.settings: - respawn_time *= self.settings['Respawn Times'] + # If this standard setting is present, factor it in + if 'Respawn Times' in self.settings_raw: + respawn_time *= self.settings_raw['Respawn Times'] # we want whole seconds assert respawn_time is not None diff --git a/assets/src/ba_data/python/bastd/activity/drawscore.py b/assets/src/ba_data/python/bastd/activity/drawscore.py index e2fc96cd..4c5a5658 100644 --- a/assets/src/ba_data/python/bastd/activity/drawscore.py +++ b/assets/src/ba_data/python/bastd/activity/drawscore.py @@ -54,4 +54,4 @@ class DrawScoreScreenActivity(MultiTeamScoreScreenActivity): trail=False, jitter=1.0).autoretain() ba.timer(0.35, ba.Call(ba.playsound, self._score_display_sound)) - self.show_player_scores(results=self.settings.get('results', None)) + self.show_player_scores(results=self.settings_raw.get('results', None)) diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index 24387dad..408495cc 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -80,7 +80,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): i * 0.2, shift_time - (i * 0.150 + 0.150))) ba.timer(i * 0.150 + 0.5, ba.Call(ba.playsound, self._score_display_sound_small)) - scored = (team is self.settings['winner']) + scored = (team is self.settings_raw['winner']) delay = 0.2 if scored: delay = 1.2 diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py index d20481e1..72726d80 100644 --- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py +++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py @@ -78,7 +78,7 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): delay3 += 1.5 ba.timer(0.3, ba.Call(ba.playsound, self._score_display_sound)) - results = self.settings['results'] + results = self.settings_raw['results'] assert isinstance(results, ba.TeamGameResults) self.show_player_scores(delay=0.001, results=results, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 8f934b63..3a6aeaae 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -63,11 +63,12 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): self._show_up_next = False self._custom_continue_message = sval super().on_begin() - winning_team = self.settings['winner'] + winning_team = self.settings_raw['winner'] # Pause a moment before playing victory music. ba.timer(0.6, ba.WeakCall(self._play_victory_music)) - ba.timer(4.4, ba.WeakCall(self._show_winner, self.settings['winner'])) + ba.timer(4.4, + ba.WeakCall(self._show_winner, self.settings_raw['winner'])) ba.timer(4.6, ba.Call(ba.playsound, self._score_display_sound)) # Score / Name / Player-record. diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index fd60dc01..0c8aec67 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -76,26 +76,27 @@ class AssaultGame(ba.TeamGameActivity): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True self._last_score_time = 0.0 self._score_sound = ba.getsound('score') self._base_region_materials: Dict[int, ba.Material] = {} def get_instance_description(self) -> Union[str, Sequence]: - if self.settings['Score to Win'] == 1: + if self.settings_raw['Score to Win'] == 1: return 'Touch the enemy flag.' return ('Touch the enemy flag ${ARG1} times.', - self.settings['Score to Win']) + self.settings_raw['Score to Win']) def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - if self.settings['Score to Win'] == 1: + if self.settings_raw['Score to Win'] == 1: return 'touch 1 flag' - return 'touch ${ARG1} flags', self.settings['Score to Win'] + return 'touch ${ARG1} flags', self.settings_raw['Score to Win'] def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.FORWARD_MARCH) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.FORWARD_MARCH) super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: @@ -105,7 +106,7 @@ class AssaultGame(ba.TeamGameActivity): def on_begin(self) -> None: from bastd.actor.flag import Flag super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() for team in self.teams: mat = self._base_region_materials[team.get_id()] = ba.Material() @@ -237,7 +238,7 @@ class AssaultGame(ba.TeamGameActivity): player_team.gamedata['score'] += 1 self._update_scoreboard() if (player_team.gamedata['score'] >= - self.settings['Score to Win']): + self.settings_raw['Score to Win']): self.end_game() def end_game(self) -> None: @@ -249,4 +250,4 @@ class AssaultGame(ba.TeamGameActivity): def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['score'], - self.settings['Score to Win']) + self.settings_raw['Score to Win']) diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 68fe9b87..579d932a 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -59,9 +59,9 @@ class CTFFlag(stdflag.Flag): def reset_return_times(self) -> None: """Clear flag related times in the activity.""" self.time_out_respawn_time = int( - self.activity.settings['Flag Idle Return Time']) + self.activity.settings_raw['Flag Idle Return Time']) self.touch_return_time = float( - self.activity.settings['Flag Touch Return Time']) + self.activity.settings_raw['Flag Touch Return Time']) @property def team(self) -> ba.Team: @@ -122,7 +122,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True self._alarmsound = ba.getsound('alarm') self._ticking_sound = ba.getsound('ticking') @@ -133,19 +133,20 @@ class CaptureTheFlagGame(ba.TeamGameActivity): self._last_home_flag_notice_print_time = 0.0 def get_instance_description(self) -> Union[str, Sequence]: - if self.settings['Score to Win'] == 1: + if self.settings_raw['Score to Win'] == 1: return 'Steal the enemy flag.' return ('Steal the enemy flag ${ARG1} times.', - self.settings['Score to Win']) + self.settings_raw['Score to Win']) def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - if self.settings['Score to Win'] == 1: + if self.settings_raw['Score to Win'] == 1: return 'return 1 flag' - return 'return ${ARG1} flags', self.settings['Score to Win'] + return 'return ${ARG1} flags', self.settings_raw['Score to Win'] def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.FLAG_CATCHER) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.FLAG_CATCHER) super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: @@ -218,7 +219,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() ba.timer(1.0, call=self._tick, repeat=True) @@ -330,7 +331,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): if not reset_team.gamedata['home_flag_at_base']: reset_team.gamedata['flag'].handlemessage(ba.DieMessage()) reset_team.gamedata['enemy_flag_at_base'] = False - if team.gamedata['score'] >= self.settings['Score to Win']: + if team.gamedata['score'] >= self.settings_raw['Score to Win']: self.end_game() def end_game(self) -> None: @@ -390,7 +391,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): for player in team.players: if player.gamedata['touching_own_flag'] > 0: return_score = 10 + 5 * int( - self.settings['Flag Touch Return Time']) + self.settings_raw['Flag Touch Return Time']) self.stats.player_scored(player, return_score, screenmessage=False) @@ -418,7 +419,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): # If return-time is zero, just kill it immediately.. otherwise keep # track of touches and count down. - if float(self.settings['Flag Touch Return Time']) <= 0.0: + if float(self.settings_raw['Flag Touch Return Time']) <= 0.0: if (not team.gamedata['home_flag_at_base'] and team.gamedata['flag'].held_count == 0): @@ -496,7 +497,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['score'], - self.settings['Score to Win']) + self.settings_raw['Score to Win']) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerSpazDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 32a5613b..64478af3 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -92,7 +92,7 @@ class ChosenOneGame(ba.TeamGameActivity): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True self._scoreboard = Scoreboard() self._chosen_one_player: Optional[ba.Player] = None @@ -118,12 +118,13 @@ class ChosenOneGame(ba.TeamGameActivity): return 'There can be only one.' def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.CHOSEN_ONE) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.CHOSEN_ONE) super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: - team.gamedata['time_remaining'] = self.settings['Chosen One Time'] + team.gamedata['time_remaining'] = self.settings_raw['Chosen One Time'] self._update_scoreboard() def on_player_leave(self, player: ba.Player) -> None: @@ -133,7 +134,7 @@ class ChosenOneGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) self.project_flag_stand(self._flag_spawn_pos) @@ -243,7 +244,7 @@ class ChosenOneGame(ba.TeamGameActivity): results = ba.TeamGameResults() for team in self.teams: results.set_team_score( - team, self.settings['Chosen One Time'] - + team, self.settings_raw['Chosen One Time'] - team.gamedata['time_remaining']) self.end(results=results, announce_delay=0) @@ -280,10 +281,10 @@ class ChosenOneGame(ba.TeamGameActivity): self._chosen_one_player = player if player.actor: - if self.settings['Chosen One Gets Shield']: + if self.settings_raw['Chosen One Gets Shield']: player.actor.handlemessage( ba.PowerupMessage('shield')) - if self.settings['Chosen One Gets Gloves']: + if self.settings_raw['Chosen One Gets Gloves']: player.actor.handlemessage( ba.PowerupMessage('punch')) @@ -334,7 +335,8 @@ class ChosenOneGame(ba.TeamGameActivity): def _update_scoreboard(self) -> None: for team in self.teams: - self._scoreboard.set_team_value(team, - team.gamedata['time_remaining'], - self.settings['Chosen One Time'], - countdown=True) + self._scoreboard.set_team_value( + team, + team.gamedata['time_remaining'], + self.settings_raw['Chosen One Time'], + countdown=True) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index bf3f1731..d3ac9983 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -102,7 +102,7 @@ class ConquestGame(ba.TeamGameActivity): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True self._scoreboard = Scoreboard() self._score_sound = ba.getsound('score') @@ -123,8 +123,9 @@ class ConquestGame(ba.TeamGameActivity): return 'secure all ${ARG1} flags', len(self.map.flag_points) def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.GRAND_ROMP) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.GRAND_ROMP) super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: @@ -141,7 +142,7 @@ class ConquestGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() # Set up flags with marker lights. diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index a37e21ee..b4798d82 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -98,7 +98,7 @@ class DeathMatchGame(ba.TeamGameActivity): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True # Print messages when players die since it matters here. @@ -115,8 +115,9 @@ class DeathMatchGame(ba.TeamGameActivity): return 'kill ${ARG1} enemies', self._score_to_win def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.TO_THE_DEATH) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.TO_THE_DEATH) super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: @@ -126,14 +127,14 @@ class DeathMatchGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() if self.teams: self._score_to_win = ( - self.settings['Kills to Win Per Player'] * + self.settings_raw['Kills to Win Per Player'] * max(1, max(len(t.players) for t in self.teams))) else: - self._score_to_win = self.settings['Kills to Win Per Player'] + self._score_to_win = self.settings_raw['Kills to Win Per Player'] self._update_scoreboard() def handlemessage(self, msg: Any) -> Any: @@ -157,7 +158,7 @@ class DeathMatchGame(ba.TeamGameActivity): # In free-for-all, killing yourself loses you a point. if isinstance(self.session, ba.FreeForAllSession): new_score = player.team.gamedata['score'] - 1 - if not self.settings['Allow Negative Scores']: + if not self.settings_raw['Allow Negative Scores']: new_score = max(0, new_score) player.team.gamedata['score'] = new_score diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 4d53150c..57ee5e1d 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -223,7 +223,7 @@ class EliminationGame(ba.TeamGameActivity): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True # Show messages when players die since it's meaningful here. @@ -244,8 +244,9 @@ class EliminationGame(ba.TeamGameActivity): self.session, ba.DualTeamSession) else 'last one standing wins' def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.SURVIVAL) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.SURVIVAL) super().on_transition_in() self._start_time = ba.time() @@ -273,7 +274,7 @@ class EliminationGame(ba.TeamGameActivity): color=(0, 1, 0)) return - player.gamedata['lives'] = self.settings['Lives Per Player'] + player.gamedata['lives'] = self.settings_raw['Lives Per Player'] if self._solo_mode: player.gamedata['icons'] = [] @@ -443,7 +444,7 @@ class EliminationGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() if self._solo_mode: self._vs_text = ba.NodeActor( @@ -464,7 +465,7 @@ class EliminationGame(ba.TeamGameActivity): # If balance-team-lives is on, add lives to the smaller team until # total lives match. if (isinstance(self.session, ba.DualTeamSession) - and self.settings['Balance Total Lives'] + and self.settings_raw['Balance Total Lives'] and self.teams[0].players and self.teams[1].players): if self._get_total_team_lives( self.teams[0]) < self._get_total_team_lives(self.teams[1]): diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 3a2cea69..5f3be039 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -135,8 +135,8 @@ class FootballTeamGame(ba.TeamGameActivity): self._flag_respawn_light: Optional[ba.NodeActor] = None def get_instance_description(self) -> Union[str, Sequence]: - touchdowns = self.settings['Score to Win'] / 7 - # NOTE: if use just touchdowns = self.settings['Score to Win'] // 7 + touchdowns = self.settings_raw['Score to Win'] / 7 + # NOTE: if use just touchdowns = self.settings_raw['Score to Win'] // 7 # and we will need to score, for example, 27 points, # we will be required to score 3 (not 4) goals .. touchdowns = math.ceil(touchdowns) @@ -145,7 +145,7 @@ class FootballTeamGame(ba.TeamGameActivity): return 'Score a touchdown.' def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - touchdowns = self.settings['Score to Win'] / 7 + touchdowns = self.settings_raw['Score to Win'] / 7 touchdowns = math.ceil(touchdowns) if touchdowns > 1: return 'score ${ARG1} touchdowns', touchdowns @@ -157,7 +157,7 @@ class FootballTeamGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() self._flag_spawn_pos = (self.map.get_flag_position(None)) self._spawn_flag() @@ -221,7 +221,7 @@ class FootballTeamGame(ba.TeamGameActivity): 50, big_message=True) # end game if we won - if team.gamedata['score'] >= self.settings['Score to Win']: + if team.gamedata['score'] >= self.settings_raw['Score to Win']: self.end_game() ba.playsound(self._score_sound) ba.playsound(self._cheer_sound) @@ -248,7 +248,7 @@ class FootballTeamGame(ba.TeamGameActivity): self.end(results=results, announce_delay=0.8) def _update_scoreboard(self) -> None: - win_score = self.settings['Score to Win'] + win_score = self.settings_raw['Score to Win'] assert self._scoreboard is not None for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['score'], @@ -356,7 +356,7 @@ class FootballCoopGame(ba.CoopGameActivity): def __init__(self, settings: Dict[str, Any]): settings['map'] = 'Football Stadium' super().__init__(settings) - self._preset = self.settings.get('preset', 'rookie') + self._preset = self.settings_raw.get('preset', 'rookie') # Load some media we need. self._cheer_sound = ba.getsound('cheer') diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 9aaca842..b530cfc8 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -198,14 +198,14 @@ class HockeyGame(ba.TeamGameActivity): self._puck: Optional[Puck] = None def get_instance_description(self) -> Union[str, Sequence]: - if self.settings['Score to Win'] == 1: + if self.settings_raw['Score to Win'] == 1: return 'Score a goal.' - return 'Score ${ARG1} goals.', self.settings['Score to Win'] + return 'Score ${ARG1} goals.', self.settings_raw['Score to Win'] def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - if self.settings['Score to Win'] == 1: + if self.settings_raw['Score to Win'] == 1: return 'score a goal' - return 'score ${ARG1} goals', self.settings['Score to Win'] + return 'score ${ARG1} goals', self.settings_raw['Score to Win'] def on_transition_in(self) -> None: self.default_music = ba.MusicType.HOCKEY @@ -214,7 +214,7 @@ class HockeyGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() self._puck_spawn_pos = self.map.get_flag_position(None) self._spawn_puck() @@ -299,7 +299,7 @@ class HockeyGame(ba.TeamGameActivity): big_message=True) # End game if we won. - if team.gamedata['score'] >= self.settings['Score to Win']: + if team.gamedata['score'] >= self.settings_raw['Score to Win']: self.end_game() ba.playsound(self._foghorn_sound) @@ -330,7 +330,7 @@ class HockeyGame(ba.TeamGameActivity): def _update_scoreboard(self) -> None: """ update scoreboard and check for winners """ - winscore = self.settings['Score to Win'] + winscore = self.settings_raw['Score to Win'] for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['score'], winscore) diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index c7dc0085..9ab2f09e 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -117,23 +117,23 @@ class KeepAwayGame(ba.TeamGameActivity): def get_instance_description(self) -> Union[str, Sequence]: return ('Carry the flag for ${ARG1} seconds.', - self.settings['Hold Time']) + self.settings_raw['Hold Time']) def get_instance_scoreboard_description(self) -> Union[str, Sequence]: return ('carry the flag for ${ARG1} seconds', - self.settings['Hold Time']) + self.settings_raw['Hold Time']) def on_transition_in(self) -> None: self.default_music = ba.MusicType.KEEP_AWAY super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: - team.gamedata['time_remaining'] = self.settings['Hold Time'] + team.gamedata['time_remaining'] = self.settings_raw['Hold Time'] self._update_scoreboard() def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) self._spawn_flag() @@ -183,8 +183,8 @@ class KeepAwayGame(ba.TeamGameActivity): results = ba.TeamGameResults() for team in self.teams: results.set_team_score( - team, - self.settings['Hold Time'] - team.gamedata['time_remaining']) + team, self.settings_raw['Hold Time'] - + team.gamedata['time_remaining']) self.end(results=results, announce_delay=0) def _update_flag_state(self) -> None: @@ -264,7 +264,7 @@ class KeepAwayGame(ba.TeamGameActivity): for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['time_remaining'], - self.settings['Hold Time'], + self.settings_raw['Hold Time'], countdown=True) def handlemessage(self, msg: Any) -> Any: diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 63331254..61d5caab 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -126,18 +126,18 @@ class KingOfTheHillGame(ba.TeamGameActivity): def get_instance_description(self) -> Union[str, Sequence]: return ('Secure the flag for ${ARG1} seconds.', - self.settings['Hold Time']) + self.settings_raw['Hold Time']) def get_instance_scoreboard_description(self) -> Union[str, Sequence]: return ('secure the flag for ${ARG1} seconds', - self.settings['Hold Time']) + self.settings_raw['Hold Time']) def on_transition_in(self) -> None: self.default_music = ba.MusicType.SCARY super().on_transition_in() def on_team_join(self, team: ba.Team) -> None: - team.gamedata['time_remaining'] = self.settings['Hold Time'] + team.gamedata['time_remaining'] = self.settings_raw['Hold Time'] self._update_scoreboard() def on_player_join(self, player: ba.Player) -> None: @@ -146,7 +146,7 @@ class KingOfTheHillGame(ba.TeamGameActivity): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() self._flag_pos = self.map.get_flag_position(None) ba.timer(1.0, self._tick, repeat=True) @@ -222,8 +222,8 @@ class KingOfTheHillGame(ba.TeamGameActivity): results = ba.TeamGameResults() for team in self.teams: results.set_team_score( - team, - self.settings['Hold Time'] - team.gamedata['time_remaining']) + team, self.settings_raw['Hold Time'] - + team.gamedata['time_remaining']) self.end(results=results, announce_delay=0) def _update_flag_state(self) -> None: @@ -273,7 +273,7 @@ class KingOfTheHillGame(ba.TeamGameActivity): for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['time_remaining'], - self.settings['Hold Time'], + self.settings_raw['Hold Time'], countdown=True) def handlemessage(self, msg: Any) -> Any: diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 94f8609f..4b5ac4d2 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -26,6 +26,7 @@ from __future__ import annotations import random +from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -37,6 +38,17 @@ if TYPE_CHECKING: from bastd.actor.onscreentimer import OnScreenTimer +@dataclass +class GameSettings: + """Configurable settings for our game.""" + epic_mode: bool + + +@dataclass +class PlayerData: + """Data we store per player.""" + + # ba_meta export game class MeteorShowerGame(ba.TeamGameActivity): """Minigame involving dodging falling bombs.""" @@ -78,7 +90,7 @@ class MeteorShowerGame(ba.TeamGameActivity): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True # Print messages when players die (since its meaningful in this game). @@ -91,8 +103,9 @@ class MeteorShowerGame(ba.TeamGameActivity): # Called when our game is transitioning in but not ready to start; # ..we can go ahead and set our music and whatnot. def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC if self.settings['Epic Mode'] - else ba.MusicType.SURVIVAL) + self.default_music = (ba.MusicType.EPIC + if self.settings_raw['Epic Mode'] else + ba.MusicType.SURVIVAL) super().on_transition_in() # Called when our game actually starts. @@ -105,13 +118,13 @@ class MeteorShowerGame(ba.TeamGameActivity): # between waves ..lets have things increase faster if we have fewer # players. delay = 5.0 if len(self.players) > 2 else 2.5 - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: delay *= 0.25 ba.timer(delay, self._decrement_meteor_time, repeat=True) # Kick off the first wave in a few seconds. delay = 3.0 - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: delay *= 0.25 ba.timer(delay, self._set_meteor_timer) diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 5f19131a..212408bc 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -90,7 +90,7 @@ class NinjaFightGame(ba.TeamGameActivity): # Called when our game actually begins. def on_begin(self) -> None: super().on_begin() - is_pro = self.settings.get('preset') == 'pro' + is_pro = self.settings_raw.get('preset') == 'pro' # In pro mode there's no powerups. if not is_pro: diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index bdf0a513..c4b39d4a 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -134,7 +134,7 @@ class RaceGame(ba.TeamGameActivity): self._race_started = False super().__init__(settings) self._scoreboard = Scoreboard() - if self.settings['Epic Mode']: + if self.settings_raw['Epic Mode']: self.slow_motion = True self._score_sound = ba.getsound('score') self._swipsound = ba.getsound('swip') @@ -156,24 +156,24 @@ class RaceGame(ba.TeamGameActivity): self._bomb_spawn_timer: Optional[ba.Timer] = None def get_instance_description(self) -> Union[str, Sequence]: - if isinstance(self.session, ba.DualTeamSession) and self.settings.get( - 'Entire Team Must Finish', False): + if (isinstance(self.session, ba.DualTeamSession) + and self.settings_raw.get('Entire Team Must Finish', False)): t_str = ' Your entire team has to finish.' else: t_str = '' - if self.settings['Laps'] > 1: - return 'Run ${ARG1} laps.' + t_str, self.settings['Laps'] + if self.settings_raw['Laps'] > 1: + return 'Run ${ARG1} laps.' + t_str, self.settings_raw['Laps'] return 'Run 1 lap.' + t_str def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - if self.settings['Laps'] > 1: - return 'run ${ARG1} laps', self.settings['Laps'] + if self.settings_raw['Laps'] > 1: + return 'run ${ARG1} laps', self.settings_raw['Laps'] return 'run 1 lap' def on_transition_in(self) -> None: self.default_music = (ba.MusicType.EPIC_RACE - if self.settings['Epic Mode'] else + if self.settings_raw['Epic Mode'] else ba.MusicType.RACE) super().on_transition_in() @@ -245,15 +245,15 @@ class RaceGame(ba.TeamGameActivity): player.gamedata['last_region'] = this_region if last_region >= len(self._regions) - 2 and this_region == 0: team = player.team - player.gamedata['lap'] = min(self.settings['Laps'], + player.gamedata['lap'] = min(self.settings_raw['Laps'], player.gamedata['lap'] + 1) # In teams mode with all-must-finish on, the team lap # value is the min of all team players. # Otherwise its the max. - if isinstance(self.session, - ba.DualTeamSession) and self.settings.get( - 'Entire Team Must Finish'): + if isinstance( + self.session, ba.DualTeamSession + ) and self.settings_raw.get('Entire Team Must Finish'): team.gamedata['lap'] = min( [p.gamedata['lap'] for p in team.players]) else: @@ -261,7 +261,7 @@ class RaceGame(ba.TeamGameActivity): [p.gamedata['lap'] for p in team.players]) # A player is finishing. - if player.gamedata['lap'] == self.settings['Laps']: + if player.gamedata['lap'] == self.settings_raw['Laps']: # In teams mode, hand out points based on the order # players come in. @@ -285,7 +285,7 @@ class RaceGame(ba.TeamGameActivity): player.gamedata['distance'] = 9999.0 # If the whole team has finished the race. - if team.gamedata['lap'] == self.settings['Laps']: + if team.gamedata['lap'] == self.settings_raw['Laps']: ba.playsound(self._score_sound) player.team.gamedata['finished'] = True assert self._timer is not None @@ -318,12 +318,12 @@ class RaceGame(ba.TeamGameActivity): }) player.actor.node.connectattr( 'torso_position', mathnode, 'input2') - tstr = ba.Lstr(resource='lapNumberText', - subs=[('${CURRENT}', - str(player.gamedata['lap'] + - 1)), - ('${TOTAL}', - str(self.settings['Laps']))]) + tstr = ba.Lstr( + resource='lapNumberText', + subs=[('${CURRENT}', + str(player.gamedata['lap'] + 1)), + ('${TOTAL}', + str(self.settings_raw['Laps']))]) txtnode = ba.newnode('text', owner=mathnode, attrs={ @@ -365,7 +365,7 @@ class RaceGame(ba.TeamGameActivity): # is on (otherwise in teams mode everyone could just leave except the # leading player to win). if (isinstance(self.session, ba.DualTeamSession) - and self.settings.get('Entire Team Must Finish')): + and self.settings_raw.get('Entire Team Must Finish')): ba.screenmessage(ba.Lstr( translate=('statements', '${TEAM} is disqualified because ${PLAYER} left'), @@ -397,21 +397,21 @@ class RaceGame(ba.TeamGameActivity): teams_dist = 0 else: if (isinstance(self.session, ba.DualTeamSession) - and self.settings.get('Entire Team Must Finish')): + and self.settings_raw.get('Entire Team Must Finish')): teams_dist = min(distances) else: teams_dist = max(distances) self._scoreboard.set_team_value( team, teams_dist, - self.settings['Laps'], - flash=(teams_dist >= float(self.settings['Laps'])), + self.settings_raw['Laps'], + flash=(teams_dist >= float(self.settings_raw['Laps'])), show_value=False) def on_begin(self) -> None: from bastd.actor.onscreentimer import OnScreenTimer super().on_begin() - self.setup_standard_time_limit(self.settings['Time Limit']) + self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() self._team_finish_pts = 100 @@ -431,14 +431,14 @@ class RaceGame(ba.TeamGameActivity): })) self._timer = OnScreenTimer() - if self.settings['Mine Spawning'] != 0: + if self.settings_raw['Mine Spawning'] != 0: self._race_mines = [ RaceMine(point=p, mine=None) for p in self.map.get_def_points('race_mine') ] if self._race_mines: self._race_mine_timer = ba.Timer( - 0.001 * self.settings['Mine Spawning'], + 0.001 * self.settings_raw['Mine Spawning'], self._update_race_mine, repeat=True) @@ -518,11 +518,11 @@ class RaceGame(ba.TeamGameActivity): assert self._timer is not None self._timer.start() - if self.settings['Bomb Spawning'] != 0: - self._bomb_spawn_timer = ba.Timer(0.001 * - self.settings['Bomb Spawning'], - self._spawn_bomb, - repeat=True) + if self.settings_raw['Bomb Spawning'] != 0: + self._bomb_spawn_timer = ba.Timer( + 0.001 * self.settings_raw['Bomb Spawning'], + self._spawn_bomb, + repeat=True) self._race_started = True diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 013e4abf..0ea9dc1c 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -75,7 +75,7 @@ class RunaroundGame(ba.CoopGameActivity): def __init__(self, settings: Dict[str, Any]): settings['map'] = 'Tower D' super().__init__(settings) - self._preset = self.settings.get('preset', 'pro') + self._preset = self.settings_raw.get('preset', 'pro') self._player_death_sound = ba.getsound('playerDeath') self._new_wave_sound = ba.getsound('scoreHit01') diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index e6c7be7e..61c2e0c0 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -95,7 +95,7 @@ class TargetPracticeGame(ba.TeamGameActivity): self.update_scoreboard() # Number of targets is based on player count. - num_targets = self.settings['Target Count'] + num_targets = self.settings_raw['Target Count'] for i in range(num_targets): ba.timer(5.0 + i * 1.0, self._spawn_target) @@ -114,9 +114,9 @@ class TargetPracticeGame(ba.TeamGameActivity): # Give players permanent triple impact bombs and wire them up # to tell us when they drop a bomb. - if self.settings['Enable Impact Bombs']: + if self.settings_raw['Enable Impact Bombs']: spaz.bomb_type = 'impact' - if self.settings['Enable Triple Bombs']: + if self.settings_raw['Enable Triple Bombs']: spaz.set_bomb_count(3) spaz.add_dropped_bomb_callback(self._on_spaz_dropped_bomb) return spaz diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 0bb069c3..ff6a5b94 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -68,7 +68,7 @@ class TheLastStandGame(ba.CoopGameActivity): self._tntspawnpos = (0, 5.5, -6) self._powerup_center = (0, 7, -4.14) self._powerup_spread = (7, 2) - self._preset = self.settings.get('preset', 'default') + self._preset = self.settings_raw.get('preset', 'default') self._excludepowerups: List[str] = [] self._scoreboard: Optional[Scoreboard] = None self._score = 0 diff --git a/docs/ba_module.md b/docs/ba_module.md index d69ae731..c7bd31af 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

last updated on 2020-05-07 for Ballistica version 1.5.0 build 20015

+

last updated on 2020-05-07 for Ballistica version 1.5.0 build 20016

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!


@@ -320,7 +320,7 @@ actually award achievements.

can overlap during transitions.

Attributes:

-
players, session, settings, stats, teams
+
players, session, settings_raw, stats, teams

players

List[ba.Player]

@@ -336,9 +336,12 @@ join or leave the game.

Raises a ba.SessionNotFoundError if the Session no longer exists.

-

settings

+

settings_raw

Dict[str, Any]

-

The settings dict passed in when the activity was made.

+

The settings dict passed in when the activity was made. +This attribute is deprecated and should be avoided when possible; +activities should pull all values they need from the 'settings' arg +passed to the Activity __init__ call.

stats

@@ -1426,7 +1429,7 @@ start_long_action(callback_when_done=ba.ContextC

Attributes Inherited:

-
players, settings, teams
+
players, settings_raw, teams

Attributes Defined Here:

map, session, stats
@@ -1929,7 +1932,7 @@ its time with lingering corpses, sound effects, etc.

Attributes Inherited:

-
players, settings, teams
+
players, settings_raw, teams

Attributes Defined Here:

map, session, stats
@@ -2072,7 +2075,7 @@ form instead of just a string:

# and can properly translate to 'Anota 3 goles.' in Spanish. # If we just returned the string 'Score 3 Goals' here, there would # have to be a translation entry for each specific number. ew. -return ['Score ${ARG1} goals.', self.settings['Score to Win']] +return ['Score ${ARG1} goals.', self.settings_raw['Score to Win']]

This way the first string can be consistently translated, with any arg values then substituted into the result. ${ARG1} will be replaced with @@ -2105,7 +2108,7 @@ instead of just a string:

# and can properly translate to 'anota 3 goles' in Spanish. # If we just returned the string 'score 3 goals' here, there would # have to be a translation entry for each specific number. ew. -return ['score ${ARG1} goals', self.settings['Score to Win']] +return ['score ${ARG1} goals', self.settings_raw['Score to Win']]

This way the first string can be consistently translated, with any arg values then substituted into the result. ${ARG1} will be replaced @@ -4515,7 +4518,7 @@ of the session.

Attributes Inherited:

-
players, settings, teams
+
players, settings_raw, teams

Attributes Defined Here:

map, session, stats
diff --git a/tools/snippets b/tools/snippets index e90822c7..3e5948dd 100755 --- a/tools/snippets +++ b/tools/snippets @@ -36,12 +36,14 @@ import sys from typing import TYPE_CHECKING # Pull in some standard snippets we want to expose. +# pylint: disable=unused-import # noinspection PyUnresolvedReferences -from efrotools.snippets import ( # pylint: disable=unused-import +from efrotools.snippets import ( PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile, cpplint, pylint, mypy, dmypy, tool_config_install, sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, makefile_target_list, spelling, spelling_all, compile_python_files, pytest) +# pylint: enable=unused-import if TYPE_CHECKING: from typing import Optional From 7aed70dfb534073fba53702e92e61c2765687a7a Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 15:24:07 -0700 Subject: [PATCH 007/417] Modernized meteor shower code --- .efrocachemap | 24 +++--- .idea/dictionaries/ericf.xml | 1 + assets/.asset_manifest_public.json | 2 + assets/Makefile | 7 ++ assets/src/ba_data/python/ba/__init__.py | 1 + assets/src/ba_data/python/ba/_player.py | 54 ++++++++++++ .../ba_data/python/bastd/game/meteorshower.py | 83 +++++++++---------- docs/ba_module.md | 26 ++++++ 8 files changed, 142 insertions(+), 56 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_player.py diff --git a/.efrocachemap b/.efrocachemap index 9281a2bb..ee0cbcbd 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/b0/12e2602010f316e3c26da125bf25", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/50/12/5a87ef4e3b502f1e62f5f2c65985", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/04/0d/5e5e5783775b70d06de5113904d7", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/46/fd8487f22aaaf68d310e66c8b5de", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/39/04b55a4b918602fbf06dccc4f3c3", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/ab/5b265ac08141fae86f6102fb362c", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/a7/c2f6454984d5639c39abd5bd871f", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/3a/f67ce2222af11d3ee614ba55e1f0", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/01/f33e921238d1bded473de5964ce4", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/1b/16fa91c7ccba5b20ea9a4ca3e0a4", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5c/6a/8e947d1317c67dc84856c5649fee", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7d/aa/901e45f5991e3907f0d9033ccdcf" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/22/a3/c6b38e5c76464077f400415eef8f", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/35/42/3802bdafafffea388132ccb27197", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/fb/bbb656b6d0b56ff92d30f13fcb10", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/75/2eee67afef4e0f446cba5a466521", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/31/fe8c9e100c0f99daaf1d11d702c0", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/27/7ddbe58f02af52884fff485c98dd", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d4/11/0f9806ff32156d9af2fb5c88e49c", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/55/2cd36310f00e3a187a70b3f122ee", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/8e/b4d365f9aa49cf247d6a73dfd5ee", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b0/1a/20b48edf6830ad53a1c0049c129b", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/00/52/42d85a6502daf27271ce48634b5b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b2/1c/1afeac6051ad9973e06f945f98ce" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index c56af62a..a1274851 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1319,6 +1319,7 @@ pipname pkey pkgutil + playerdata playerlostspaz playernode playerpt diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index f90691dc..767104c3 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -38,6 +38,7 @@ "ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc", @@ -90,6 +91,7 @@ "ba_data/python/ba/_music.py", "ba_data/python/ba/_netutils.py", "ba_data/python/ba/_nodeactor.py", + "ba_data/python/ba/_player.py", "ba_data/python/ba/_playlist.py", "ba_data/python/ba/_powerup.py", "ba_data/python/ba/_profile.py", diff --git a/assets/Makefile b/assets/Makefile index 0aeb2198..1d135437 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -167,6 +167,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_tips.py \ build/ba_data/python/ba/_store.py \ build/ba_data/python/ba/_activitytypes.py \ + build/ba_data/python/ba/_player.py \ build/ba_data/python/ba/__init__.py \ build/ba_data/python/ba/_assetmanager.py \ build/ba_data/python/ba/_session.py \ @@ -392,6 +393,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc \ @@ -729,6 +731,11 @@ build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_player.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/__init__.py @echo Compiling script: $^ diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 887e2415..201b4cb3 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -40,6 +40,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, charstr, textwidget, time, timer, open_url, widget) from ba._activity import Activity from ba._actor import Actor +from ba._player import BasePlayerData from ba._nodeactor import NodeActor from ba._app import App from ba._coopgame import CoopGameActivity diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py new file mode 100644 index 00000000..9d3100d1 --- /dev/null +++ b/assets/src/ba_data/python/ba/_player.py @@ -0,0 +1,54 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Player related functionality.""" +from __future__ import annotations +from typing import TYPE_CHECKING, TypeVar + +if TYPE_CHECKING: + from typing import Type + import ba + +T = TypeVar('T') + + +class BasePlayerData: + """Base class for custom player data. + + Category: Gameplay Classes + + A convenience class that can be used as a base class for custom + per-game player data. It simply provides the ability to easily fetch + an instance of itself for a given ba.Player. + """ + + @classmethod + def get(cls: Type[T], player: ba.Player) -> T: + """Return the custom player data associated with a player. + + If one does not exist, it will be created. + """ + + # Store/return an instance of ourself in the player's per-game dict. + data = player.gamedata.get('playerdata') + if data is None: + player.gamedata['playerdata'] = data = cls() + assert isinstance(data, cls) + return data diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 4b5ac4d2..27c17d60 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -30,23 +30,18 @@ from dataclasses import dataclass from typing import TYPE_CHECKING import ba -from bastd.actor import bomb -from bastd.actor import playerspaz +from bastd.actor.bomb import Bomb +from bastd.actor.playerspaz import PlayerSpazDeathMessage if TYPE_CHECKING: - from typing import Any, Tuple, Sequence, Optional, List, Dict, Type + from typing import Any, Tuple, Sequence, Optional, List, Dict, Type, Type from bastd.actor.onscreentimer import OnScreenTimer @dataclass -class GameSettings: - """Configurable settings for our game.""" - epic_mode: bool - - -@dataclass -class PlayerData: +class PlayerData(ba.BasePlayerData): """Data we store per player.""" + death_time: Optional[float] = None # ba_meta export game @@ -90,23 +85,19 @@ class MeteorShowerGame(ba.TeamGameActivity): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) - if self.settings_raw['Epic Mode']: - self.slow_motion = True - - # Print messages when players die (since its meaningful in this game). - self.announce_player_deaths = True - + self._epic_mode = settings.get('Epic Mode', False) self._last_player_death_time: Optional[float] = None self._meteor_time = 2.0 self._timer: Optional[OnScreenTimer] = None - # Called when our game is transitioning in but not ready to start; - # ..we can go ahead and set our music and whatnot. - def on_transition_in(self) -> None: + # Some base class overrides: self.default_music = (ba.MusicType.EPIC - if self.settings_raw['Epic Mode'] else - ba.MusicType.SURVIVAL) - super().on_transition_in() + if self._epic_mode else ba.MusicType.SURVIVAL) + if self._epic_mode: + self.slow_motion = True + + # Print messages when players die (since its meaningful in this game). + self.announce_player_deaths = True # Called when our game actually starts. def on_begin(self) -> None: @@ -118,13 +109,13 @@ class MeteorShowerGame(ba.TeamGameActivity): # between waves ..lets have things increase faster if we have fewer # players. delay = 5.0 if len(self.players) > 2 else 2.5 - if self.settings_raw['Epic Mode']: + if self._epic_mode: delay *= 0.25 ba.timer(delay, self._decrement_meteor_time, repeat=True) # Kick off the first wave in a few seconds. delay = 3.0 - if self.settings_raw['Epic Mode']: + if self._epic_mode: delay *= 0.25 ba.timer(delay, self._set_meteor_timer) @@ -145,7 +136,7 @@ class MeteorShowerGame(ba.TeamGameActivity): # For score purposes, mark them as having died right as the # game started. assert self._timer is not None - player.gamedata['death_time'] = self._timer.getstarttime() + PlayerData.get(player).death_time = self._timer.getstarttime() return self.spawn_player(player) @@ -172,15 +163,15 @@ class MeteorShowerGame(ba.TeamGameActivity): # Various high-level game events come through this method. def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - death_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + curtime = ba.time() # Record the player's moment of death. - msg.spaz.player.gamedata['death_time'] = death_time + PlayerData.get(msg.spaz.player).death_time = curtime # In co-op mode, end the game the instant everyone dies # (more accurate looking). @@ -192,7 +183,7 @@ class MeteorShowerGame(ba.TeamGameActivity): ba.pushcall(self._check_end_game) # Also record this for a final setting of the clock. - self._last_player_death_time = death_time + self._last_player_death_time = curtime else: ba.timer(1.0, self._check_end_game) @@ -247,36 +238,36 @@ class MeteorShowerGame(ba.TeamGameActivity): def _drop_bomb(self, position: Sequence[float], velocity: Sequence[float]) -> None: - bomb.Bomb(position=position, velocity=velocity).autoretain() + Bomb(position=position, velocity=velocity).autoretain() def _decrement_meteor_time(self) -> None: self._meteor_time = max(0.01, self._meteor_time * 0.9) def end_game(self) -> None: - cur_time = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) + cur_time = ba.time() assert self._timer is not None - start_time = self._timer.getstarttime( - timeformat=ba.TimeFormat.MILLISECONDS) + start_time = self._timer.getstarttime() - # Mark 'death-time' as now for any still-living players + # Mark death-time as now for any still-living players # and award players points for how long they lasted. # (these per-player scores are only meaningful in team-games) for team in self.teams: for player in team.players: + playerdata = PlayerData.get(player) + survived = False # Throw an extra fudge factor in so teams that # didn't die come out ahead of teams that did. - if 'death_time' not in player.gamedata: - player.gamedata['death_time'] = cur_time + 1 + if playerdata.death_time is None: + survived = True + playerdata.death_time = cur_time + 1 # Award a per-player score depending on how many seconds # they lasted (per-player scores only affect teams mode; # everywhere else just looks at the per-team score). - score = int(player.gamedata['death_time'] - - self._timer.getstarttime( - timeformat=ba.TimeFormat.MILLISECONDS)) - if 'death_time' not in player.gamedata: - score += 50 # a bit extra for survivors + score = int(playerdata.death_time - self._timer.getstarttime()) + if survived: + score += 50 # A bit extra for survivors. self.stats.player_scored(player, score, screenmessage=False) # Stop updating our time text, and set the final time to match @@ -294,10 +285,14 @@ class MeteorShowerGame(ba.TeamGameActivity): # Set the team score to the max time survived by any player on # that team. - longest_life = 0 + longest_life = 0.0 for player in team.players: + playerdata = PlayerData.get(player) + assert playerdata.death_time is not None longest_life = max(longest_life, - player.gamedata['death_time'] - start_time) - results.set_team_score(team, longest_life) + playerdata.death_time - start_time) + + # Submit the score value in milliseconds. + results.set_team_score(team, int(1000.0 * longest_life)) self.end(results=results) diff --git a/docs/ba_module.md b/docs/ba_module.md index c7bd31af..2647f24b 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -19,6 +19,7 @@
  • ba.Map
  • ba.NodeActor
  • +
  • ba.BasePlayerData
  • ba.Chooser
  • ba.InputDevice
  • ba.Level
  • @@ -1083,6 +1084,31 @@ when done.

    Behavior is similar to ba.gettexture()

    +
    +
    +
    +

    ba.BasePlayerData

    +

    <top level class> +

    +

    Base class for custom player data.

    + +

    Category: Gameplay Classes

    + +

    A convenience class that can be used as a base class for custom + per-game player data. It simply provides the ability to easily fetch + an instance of itself for a given ba.Player. +

    + +

    Methods:

    +
    +

    get()

    +
    <class method>
    +

    get(player: ba.Player) -> T

    + +

    Return the custom player data associated with a player.

    + +

    If one does not exist, it will be created.

    +

    From f0583ac816e720503255a5db3f6e1222b88d6152 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 16:48:25 -0700 Subject: [PATCH 008/417] Added proper types for game score info --- .efrocachemap | 24 ++--- .idea/dictionaries/ericf.xml | 1 + assets/.asset_manifest_public.json | 2 + assets/Makefile | 7 ++ assets/src/ba_data/python/ba/__init__.py | 1 + assets/src/ba_data/python/ba/_coopsession.py | 22 ++-- assets/src/ba_data/python/ba/_gameactivity.py | 56 +--------- assets/src/ba_data/python/ba/_gameresults.py | 25 ++--- assets/src/ba_data/python/ba/_level.py | 3 +- assets/src/ba_data/python/ba/_score.py | 74 +++++++++++++ .../ba_data/python/bastd/game/chosenone.py | 4 +- .../python/bastd/game/easteregghunt.py | 4 +- .../ba_data/python/bastd/game/elimination.py | 10 +- .../src/ba_data/python/bastd/game/football.py | 4 +- .../src/ba_data/python/bastd/game/keepaway.py | 4 +- .../python/bastd/game/kingofthehill.py | 4 +- .../ba_data/python/bastd/game/meteorshower.py | 10 +- .../ba_data/python/bastd/game/ninjafight.py | 10 +- assets/src/ba_data/python/bastd/game/race.py | 10 +- docs/ba_module.md | 102 ++++++++++++------ 20 files changed, 224 insertions(+), 153 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_score.py diff --git a/.efrocachemap b/.efrocachemap index ee0cbcbd..8b1559ef 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/22/a3/c6b38e5c76464077f400415eef8f", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/35/42/3802bdafafffea388132ccb27197", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/fb/bbb656b6d0b56ff92d30f13fcb10", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/75/2eee67afef4e0f446cba5a466521", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/31/fe8c9e100c0f99daaf1d11d702c0", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/27/7ddbe58f02af52884fff485c98dd", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d4/11/0f9806ff32156d9af2fb5c88e49c", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/55/2cd36310f00e3a187a70b3f122ee", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/8e/b4d365f9aa49cf247d6a73dfd5ee", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b0/1a/20b48edf6830ad53a1c0049c129b", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/00/52/42d85a6502daf27271ce48634b5b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b2/1c/1afeac6051ad9973e06f945f98ce" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e8/b7/d1b41fb68d9f65901d47267b9287", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/40/04/9b0dc90152d5729485488b628429", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/15/aa58294e041cca7485375e7a49ad", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/04/86/d3adc7e35a753aad5e6d62758e7c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/91/81/30196355ca6b2044140131f6da89", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/3b/e0171b94d0b24c153a88b7724797", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/97/10/3b2aded25bb43ce4451f54c42731", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e3/ca/e0788b1f5cc69e92fed8d4d9a61f", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/69/78/3a1f6f6f808f671c749d48b0b5a6", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1a/fc/f3b36c2964d64ef2c1685cf8c893", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/22/8d/fdf637a15162f92f699f92eca9e7", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/72/34/a37deb6cbc29025a38c161ce7cba" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index a1274851..4e45609f 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1577,6 +1577,7 @@ scorescreen scoreteam scoretxt + scoretype scoreval scorever scorings diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index 767104c3..92c51171 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -42,6 +42,7 @@ "ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc", @@ -95,6 +96,7 @@ "ba_data/python/ba/_playlist.py", "ba_data/python/ba/_powerup.py", "ba_data/python/ba/_profile.py", + "ba_data/python/ba/_score.py", "ba_data/python/ba/_servermode.py", "ba_data/python/ba/_session.py", "ba_data/python/ba/_stats.py", diff --git a/assets/Makefile b/assets/Makefile index 1d135437..82113061 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -179,6 +179,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_tournament.py \ build/ba_data/python/ba/_messages.py \ build/ba_data/python/ba/_freeforallsession.py \ + build/ba_data/python/ba/_score.py \ build/ba_data/python/ba/_playlist.py \ build/ba_data/python/ba/_team.py \ build/ba_data/python/ba/_multiteamsession.py \ @@ -405,6 +406,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc \ @@ -791,6 +793,11 @@ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_score.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_playlist.py @echo Compiling script: $^ diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 201b4cb3..0277bf92 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -61,6 +61,7 @@ from ba._lang import Lstr, setlanguage, get_valid_languages from ba._map import Map, getmaps from ba._session import Session from ba._servermode import ServerController +from ba._score import ScoreType, ScoreInfo from ba._stats import PlayerScoredMessage, PlayerRecord, Stats from ba._team import Team from ba._teamgame import TeamGameActivity diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index d1c28fd0..bcaa1ceb 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -254,6 +254,7 @@ class CoopSession(Session): from ba._general import WeakCall from ba._coopgame import CoopGameActivity from ba._gameresults import TeamGameResults + from ba._score import ScoreType from bastd.tutorial import TutorialActivity from bastd.activity.coopscore import CoopScoreScreen @@ -349,18 +350,23 @@ class CoopSession(Session): fail_message = None score_order = ('decreasing' if results.get_lower_is_better() else 'increasing') - if results.get_score_type() in ('seconds', 'milliseconds', - 'time'): + if results.get_score_type() in (ScoreType.SECONDS, + ScoreType.MILLISECONDS): score_type = 'time' - # Results contains milliseconds; ScoreScreen wants - # hundredths; need to fix :-/ + # ScoreScreen wants hundredths of a second. if score is not None: - score //= 10 + if results.get_score_type() is ScoreType.SECONDS: + score *= 100 + elif (results.get_score_type() is + ScoreType.MILLISECONDS): + score //= 10 + else: + raise RuntimeError('FIXME') else: - if results.get_score_type() != 'points': - print(("Unknown score type: '" + - results.get_score_type() + "'")) + if results.get_score_type() is not ScoreType.POINTS: + print(f'Unknown ScoreType:' + f' "{results.get_score_type()}"') score_type = 'points' # Old coop-game-specific results; should migrate away from these. diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 9acceb3f..b3131c4e 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -28,6 +28,7 @@ from typing import TYPE_CHECKING import _ba from ba._activity import Activity +from ba._score import ScoreInfo from ba._lang import Lstr if TYPE_CHECKING: @@ -75,58 +76,9 @@ class GameActivity(Activity): completion_call) @classmethod - def get_score_info(cls) -> Dict[str, Any]: - """Return info about game scoring setup; should be overridden by games. - - They should return a dict containing any of the following (missing - values will be default): - - 'score_name': a label shown to the user for scores; 'Score', - 'Time Survived', etc. 'Score' is the default. - - 'lower_is_better': a boolean telling whether lower scores are - preferable instead of higher (the default). - - 'none_is_winner': specifies whether a score value of None is considered - better than other scores or worse. Default is False. - - 'score_type': can be 'seconds', 'milliseconds', or 'points'. - - 'score_version': to change high-score lists used by a game without - renaming the game, change this. Defaults to empty string. - """ - return {} - - @classmethod - def get_resolved_score_info(cls) -> Dict[str, Any]: - """ - Call this to return a game's score info with all missing values - filled in with defaults. This should not be overridden; override - get_score_info() instead. - """ - values = cls.get_score_info() - if 'score_name' not in values: - values['score_name'] = 'Score' - if 'lower_is_better' not in values: - values['lower_is_better'] = False - if 'none_is_winner' not in values: - values['none_is_winner'] = False - if 'score_type' not in values: - values['score_type'] = 'points' - if 'score_version' not in values: - values['score_version'] = '' - - if values['score_type'] not in ['seconds', 'milliseconds', 'points']: - raise Exception("invalid score_type value: '" + - values['score_type'] + "'") - - # make sure they didn't misspell anything in there.. - for name in list(values.keys()): - if name not in ('score_name', 'lower_is_better', 'none_is_winner', - 'score_type', 'score_version'): - print('WARNING: invalid key in score_info: "' + name + '"') - - return values + def get_score_info(cls) -> ba.ScoreInfo: + """Return info about game scoring setup; can be overridden by games.""" + return ScoreInfo() @classmethod def get_name(cls) -> str: diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 46c484a4..d4fe7147 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -57,9 +57,9 @@ class TeamGameResults: self._teams: Optional[List[ReferenceType[ba.Team]]] = None self._player_info: Optional[List[Dict[str, Any]]] = None self._lower_is_better: Optional[bool] = None - self._score_name: Optional[str] = None + self._score_label: Optional[str] = None self._none_is_winner: Optional[bool] = None - self._score_type: Optional[str] = None + self._score_type: Optional[ba.ScoreType] = None def set_game(self, game: ba.GameActivity) -> None: """Set the game instance these results are applying to.""" @@ -67,12 +67,12 @@ class TeamGameResults: raise RuntimeError('Game set twice for TeamGameResults.') self._game_set = True self._teams = [weakref.ref(team) for team in game.teams] - score_info = game.get_resolved_score_info() + score_info = game.get_score_info() self._player_info = copy.deepcopy(game.initial_player_info) - self._lower_is_better = score_info['lower_is_better'] - self._score_name = score_info['score_name'] - self._none_is_winner = score_info['none_is_winner'] - self._score_type = score_info['score_type'] + self._lower_is_better = score_info.lower_is_better + self._score_label = score_info.label + self._none_is_winner = score_info.none_is_winner + self._score_type = score_info.scoretype def set_team_score(self, team: ba.Team, score: int) -> None: """Set the score for a given ba.Team. @@ -118,17 +118,18 @@ class TeamGameResults: from ba._gameutils import timestring from ba._lang import Lstr from ba._enums import TimeFormat + from ba._score import ScoreType if not self._game_set: raise RuntimeError("Can't get team-score-str until game is set.") for score in list(self._scores.values()): if score[0]() is team: if score[1] is None: return Lstr(value='-') - if self._score_type == 'seconds': + if self._score_type is ScoreType.SECONDS: return timestring(score[1] * 1000, centi=False, timeformat=TimeFormat.MILLISECONDS) - if self._score_type == 'milliseconds': + if self._score_type is ScoreType.MILLISECONDS: return timestring(score[1], centi=True, timeformat=TimeFormat.MILLISECONDS) @@ -142,7 +143,7 @@ class TeamGameResults: assert self._player_info is not None return self._player_info - def get_score_type(self) -> str: + def get_score_type(self) -> ba.ScoreType: """Get the type of score.""" if not self._game_set: raise RuntimeError("Can't get score-type until game is set.") @@ -153,8 +154,8 @@ class TeamGameResults: """Get the name associated with scores ('points', etc).""" if not self._game_set: raise RuntimeError("Can't get score-name until game is set.") - assert self._score_name is not None - return self._score_name + assert self._score_label is not None + return self._score_label def get_lower_is_better(self) -> bool: """Return whether lower scores are better.""" diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py index 44f805fa..f6471028 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -144,8 +144,7 @@ class Level: can be changed to separate its new high score lists/etc. from the old. """ if self._score_version_string is None: - scorever = ( - self._gametype.get_resolved_score_info()['score_version']) + scorever = self._gametype.get_score_info().version if scorever != '': scorever = ' ' + scorever self._score_version_string = scorever diff --git a/assets/src/ba_data/python/ba/_score.py b/assets/src/ba_data/python/ba/_score.py new file mode 100644 index 00000000..83432b0f --- /dev/null +++ b/assets/src/ba_data/python/ba/_score.py @@ -0,0 +1,74 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Score related functionality.""" + +from __future__ import annotations + +from enum import Enum, unique +from dataclasses import dataclass +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import ba + + +@unique +class ScoreType(Enum): + """Type of scores. + + Category: Enums + """ + SECONDS = 's' + MILLISECONDS = 'ms' + POINTS = 'p' + + +@dataclass +class ScoreInfo: + """Info about a game's scoring setup. + + Category: Gameplay Classes + + Attrs: + + label + A label show to the user for scores; 'Score', 'Time Survived', etc. + + scoretype + How the score value should be displayed. + + lower_is_better + Whether lower scores are preferable. Higher scores are by default. + + none_is_winner + Whether a value of None is considered better than other scores. + By default it is not. + + version + To change high-score lists used by a game without renaming the game, + change this. Defaults to an empty string. + + """ + label: str = 'Score' + scoretype: ba.ScoreType = ScoreType.POINTS + lower_is_better: bool = False + none_is_winner: bool = False + version: str = '' diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 64478af3..7dae8184 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -49,8 +49,8 @@ class ChosenOneGame(ba.TeamGameActivity): return 'Chosen One' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return {'score_name': 'Time Held'} + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Time Held') @classmethod def get_description(cls, sessiontype: Type[ba.Session]) -> str: diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 514e8f10..72259d2e 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -47,8 +47,8 @@ class EasterEggHuntGame(ba.TeamGameActivity): return 'Easter Egg Hunt' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return {'score_name': 'Score', 'score_type': 'points'} + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Score', scoretype=ba.ScoreType.POINTS) @classmethod def get_description(cls, sessiontype: Type[ba.Session]) -> str: diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 57ee5e1d..d5ad91d5 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -172,12 +172,10 @@ class EliminationGame(ba.TeamGameActivity): return 'Elimination' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return { - 'score_name': 'Survived', - 'score_type': 'seconds', - 'none_is_winner': True - } + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Survived', + scoretype=ba.ScoreType.SECONDS, + none_is_winner=True) @classmethod def get_description(cls, sessiontype: Type[ba.Session]) -> str: diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 5f3be039..96e4bba9 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -332,8 +332,8 @@ class FootballCoopGame(ba.CoopGameActivity): return 'Football' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return {'score_type': 'milliseconds', 'score_version': 'B'} + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(scoretype=ba.ScoreType.MILLISECONDS, version='B') # FIXME: Need to update co-op games to use get_score_info. def get_score_type(self) -> str: diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 9ab2f09e..2b17c606 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -54,8 +54,8 @@ class KeepAwayGame(ba.TeamGameActivity): return 'Carry the flag for a set length of time.' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return {'score_name': 'Time Held'} + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Time Held') @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 61d5caab..9e7c7ca3 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -56,8 +56,8 @@ class KingOfTheHillGame(ba.TeamGameActivity): return 'Secure the flag for a set length of time.' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return {'score_name': 'Time Held'} + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Time Held') @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 27c17d60..daf5bacd 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -53,12 +53,10 @@ class MeteorShowerGame(ba.TeamGameActivity): return 'Meteor Shower' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return { - 'score_name': 'Survived', - 'score_type': 'milliseconds', - 'score_version': 'B' - } + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Survived', + scoretype=ba.ScoreType.MILLISECONDS, + version='B') @classmethod def get_description(cls, sessiontype: Type[ba.Session]) -> str: diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 212408bc..2cf667b9 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -49,12 +49,10 @@ class NinjaFightGame(ba.TeamGameActivity): return 'Ninja Fight' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return { - 'score_type': 'milliseconds', - 'lower_is_better': True, - 'score_name': 'Time' - } + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Time', + scoretype=ba.ScoreType.MILLISECONDS, + lower_is_better=True) @classmethod def get_description(cls, sessiontype: Type[ba.Session]) -> str: diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index c4b39d4a..f2ace834 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -79,12 +79,10 @@ class RaceGame(ba.TeamGameActivity): return 'Run real fast!' @classmethod - def get_score_info(cls) -> Dict[str, Any]: - return { - 'score_name': 'Time', - 'lower_is_better': True, - 'score_type': 'milliseconds' - } + def get_score_info(cls) -> ba.ScoreInfo: + return ba.ScoreInfo(label='Time', + lower_is_better=True, + scoretype=ba.ScoreType.MILLISECONDS) @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: diff --git a/docs/ba_module.md b/docs/ba_module.md index 2647f24b..992a54ea 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-07 for Ballistica version 1.5.0 build 20016

    +

    last updated on 2020-05-07 for Ballistica version 1.5.0 build 20018

    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!


    @@ -28,6 +28,7 @@
  • ba.Node
  • ba.Player
  • ba.PlayerRecord
  • +
  • ba.ScoreInfo
  • ba.Session
    • ba.CoopSession
    • @@ -172,6 +173,7 @@
    • ba.MusicPlayMode
    • ba.MusicType
    • ba.Permission
    • +
    • ba.ScoreType
    • ba.SpecialChar
    • ba.TimeFormat
    • ba.TimeType
    • @@ -1482,7 +1484,7 @@ start_long_action(callback_when_done=ba.ContextC

      Methods Inherited:

      -
      add_actor_weak_ref(), begin(), continue_or_end_game(), create_config_ui(), create_player_node(), dep_is_present(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_resolved_score_info(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), start_transition_in()
      +
      add_actor_weak_ref(), begin(), continue_or_end_game(), create_config_ui(), create_player_node(), dep_is_present(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), start_transition_in()

      Methods Defined or Overridden:

      <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
      @@ -1987,7 +1989,7 @@ its time with lingering corpses, sound effects, etc.

      Methods Inherited:

      add_actor_weak_ref(), begin(), create_player_node(), dep_is_present(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), retain_actor(), set_has_ended(), set_immediate_end(), start_transition_in()

      Methods Defined or Overridden:

      -
      <constructor>, continue_or_end_game(), create_config_ui(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_resolved_score_info(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
      +
      <constructor>, continue_or_end_game(), create_config_ui(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

      <constructor>

      ba.GameActivity(settings: Dict[str, Any])

      @@ -2156,38 +2158,12 @@ of the screen, so it should be as concise as possible.

      Return a str name for this game type.

      -
      -

      get_resolved_score_info()

      -
      <class method>
      -

      get_resolved_score_info() -> Dict[str, Any]

      - -

      Call this to return a game's score info with all missing values -filled in with defaults. This should not be overridden; override -get_score_info() instead.

      -

      get_score_info()

      <class method>
      -

      get_score_info() -> Dict[str, Any]

      +

      get_score_info() -> ba.ScoreInfo

      -

      Return info about game scoring setup; should be overridden by games.

      - -

      They should return a dict containing any of the following (missing -values will be default):

      - -

      'score_name': a label shown to the user for scores; 'Score', - 'Time Survived', etc. 'Score' is the default.

      - -

      'lower_is_better': a boolean telling whether lower scores are - preferable instead of higher (the default).

      - -

      'none_is_winner': specifies whether a score value of None is considered - better than other scores or worse. Default is False.

      - -

      'score_type': can be 'seconds', 'milliseconds', or 'points'.

      - -

      'score_version': to change high-score lists used by a game without - renaming the game, change this. Defaults to empty string.

      +

      Return info about game scoring setup; can be overridden by games.

      get_settings()

      @@ -4008,6 +3984,66 @@ cause the powerup box to make a sound and disappear or whatnot.


      +

      ba.ScoreInfo

      +

      <top level class> +

      +

      Info about a game's scoring setup.

      + +

      Category: Gameplay Classes

      + +

      Attributes:

      +
      label, lower_is_better, none_is_winner, scoretype, version
      +
      +

      label

      +

      str

      +

      A label show to the user for scores; 'Score', 'Time Survived', etc.

      + +
      +

      lower_is_better

      +

      bool

      +

      Whether lower scores are preferable. Higher scores are by default.

      + +
      +

      none_is_winner

      +

      bool

      +

      Whether a value of None is considered better than other scores. +By default it is not.

      + +
      +

      scoretype

      +

      ba.ScoreType

      +

      How the score value should be displayed.

      + +
      +

      version

      +

      str

      +

      To change high-score lists used by a game without renaming the game, +change this. Defaults to an empty string.

      + +
      +
      +

      Methods:

      +
      +

      <constructor>

      +

      ba.ScoreInfo(label: 'str' = 'Score', scoretype: 'ba.ScoreType' = <ScoreType.POINTS: 'p'>, lower_is_better: 'bool' = False, none_is_winner: 'bool' = False, version: 'str' = '')

      + +
      +
      +
      +

      ba.ScoreType

      +

      inherits from: enum.Enum

      +

      Type of scores.

      + +

      Category: Enums +

      + +

      Values:

      +
        +
      • SECONDS
      • +
      • MILLISECONDS
      • +
      • POINTS
      • +
      +

      ba.ServerController

      <top level class>

      @@ -4571,7 +4607,7 @@ of the session.

      Methods Inherited:

      -
      add_actor_weak_ref(), begin(), continue_or_end_game(), create_config_ui(), create_player_node(), dep_is_present(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_resolved_score_info(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), start_transition_in()
      +
      add_actor_weak_ref(), begin(), continue_or_end_game(), create_config_ui(), create_player_node(), dep_is_present(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), start_transition_in()

      Methods Defined or Overridden:

      <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
      @@ -4669,7 +4705,7 @@ Results for a completed ba.TeamGameActivity

      get_score_type()

      -

      get_score_type(self) -> str

      +

      get_score_type(self) -> ba.ScoreType

      Get the type of score.

      From dd6a4b625b7f5374ab4e9ab3dd46bb35d7c5da03 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 17:06:57 -0700 Subject: [PATCH 009/417] Tidying --- .efrocachemap | 24 +++++++++---------- .../python/bastd/game/capturetheflag.py | 2 +- .../ba_data/python/bastd/game/chosenone.py | 2 +- .../ba_data/python/bastd/game/elimination.py | 2 +- .../python/bastd/game/kingofthehill.py | 2 +- .../ba_data/python/bastd/game/meteorshower.py | 3 +-- assets/src/ba_data/python/bastd/game/race.py | 4 ++-- tools/snippets | 10 ++++---- 8 files changed, 25 insertions(+), 24 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 8b1559ef..434682a4 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e8/b7/d1b41fb68d9f65901d47267b9287", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/40/04/9b0dc90152d5729485488b628429", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/15/aa58294e041cca7485375e7a49ad", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/04/86/d3adc7e35a753aad5e6d62758e7c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/91/81/30196355ca6b2044140131f6da89", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/3b/e0171b94d0b24c153a88b7724797", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/97/10/3b2aded25bb43ce4451f54c42731", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e3/ca/e0788b1f5cc69e92fed8d4d9a61f", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/69/78/3a1f6f6f808f671c749d48b0b5a6", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1a/fc/f3b36c2964d64ef2c1685cf8c893", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/22/8d/fdf637a15162f92f699f92eca9e7", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/72/34/a37deb6cbc29025a38c161ce7cba" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8c/7f/91dc078e8cfc8e003a90e91e1762", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e0/ee/e2f283b6b432d2aecf105138482e", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/0f/15f10e5ed1ec1a80bf4fd443594f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/25/6a/20ce70fc081376c90d8e154d0978", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7d/7b/35302bd8dee3631b9d9ddc8acfda", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/7e/8444f1e9bfdf287c9ad53af65192", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/c8/59ba42aeceb0ccf0ce728e25da15", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5a/c2/b9d745b8dff2fbcf3d782c60c325", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/37/ba/8f6ae8a0694207c90e19fcb31dcc", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/72/03/5f1f17bcae5f1cec82fb324de89f", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/85/bc/a8d4ba4f6cc15b06ec7220a8b7c6", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bc/97/e9e8ba547055185dbcf3b70989b3" } \ No newline at end of file diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 579d932a..35e4a20a 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -465,7 +465,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): """Intercept new spazzes and add our team material for them.""" # (chill pylint; we're passing our exact args to parent call) # pylint: disable=signature-differs - spaz = ba.TeamGameActivity.spawn_player_spaz(self, *args, **keywds) + spaz = super().spawn_player_spaz(*args, **keywds) player = spaz.player player.gamedata['touching_own_flag'] = 0 diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 7dae8184..7ae3fd06 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -128,7 +128,7 @@ class ChosenOneGame(ba.TeamGameActivity): self._update_scoreboard() def on_player_leave(self, player: ba.Player) -> None: - ba.TeamGameActivity.on_player_leave(self, player) + super().on_player_leave(player) if self._get_chosen_one_player() is player: self._set_chosen_one_player(None) diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index d5ad91d5..6dfe3006 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -428,7 +428,7 @@ class EliminationGame(ba.TeamGameActivity): position=player.node.position).autoretain() def on_player_leave(self, player: ba.Player) -> None: - ba.TeamGameActivity.on_player_leave(self, player) + super().on_player_leave(player) player.gamedata['icons'] = None # Remove us from spawn-order. diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 9e7c7ca3..024589ba 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -141,7 +141,7 @@ class KingOfTheHillGame(ba.TeamGameActivity): self._update_scoreboard() def on_player_join(self, player: ba.Player) -> None: - ba.TeamGameActivity.on_player_join(self, player) + super().on_player_join(player) player.gamedata['at_flag'] = 0 def on_begin(self) -> None: diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index daf5bacd..c757cbc4 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -97,7 +97,6 @@ class MeteorShowerGame(ba.TeamGameActivity): # Print messages when players die (since its meaningful in this game). self.announce_player_deaths = True - # Called when our game actually starts. def on_begin(self) -> None: from bastd.actor.onscreentimer import OnScreenTimer @@ -140,7 +139,7 @@ class MeteorShowerGame(ba.TeamGameActivity): def on_player_leave(self, player: ba.Player) -> None: # Augment default behavior. - ba.TeamGameActivity.on_player_leave(self, player) + super().on_player_leave(player) # A departing player may trigger game-over. self._check_end_game() diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index f2ace834..2fac27bb 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -354,10 +354,10 @@ class RaceGame(ba.TeamGameActivity): player.gamedata['distance'] = 0.0 player.gamedata['finished'] = False player.gamedata['rank'] = None - ba.TeamGameActivity.on_player_join(self, player) + super().on_player_join(player) def on_player_leave(self, player: ba.Player) -> None: - ba.TeamGameActivity.on_player_leave(self, player) + super().on_player_leave(player) # A player leaving disqualifies the team if 'Entire Team Must Finish' # is on (otherwise in teams mode everyone could just leave except the diff --git a/tools/snippets b/tools/snippets index 3e5948dd..d270f01e 100755 --- a/tools/snippets +++ b/tools/snippets @@ -559,18 +559,20 @@ def lazy_increment_build() -> None: from efro.terminal import Clr from efrotools import get_files_hash from efrotools.code import get_code_filenames - codehash = get_files_hash(get_code_filenames(PROJROOT)) + codefiles = get_code_filenames(PROJROOT) + codehash = get_files_hash(codefiles) hashfilename = '.cache/lazy_increment_build' try: with open(hashfilename) as infile: lasthash = infile.read() except FileNotFoundError: lasthash = '' - if codehash == lasthash: - pass - else: + if codehash != lasthash: print(f'{Clr.SMAG}Source(s) changed; incrementing build...{Clr.RST}') subprocess.run(['tools/version_utils', 'incrementbuild'], check=True) + + # We just changed code, so we need to re-calc the current hash. + codehash = get_files_hash(codefiles) os.makedirs(os.path.dirname(hashfilename), exist_ok=True) with open(hashfilename, 'w') as outfile: outfile.write(codehash) From 40ebc0f46dc56dbcf813b520a92b93cb9c830079 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 17:22:05 -0700 Subject: [PATCH 010/417] Test --- .efrocachemap | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 434682a4..6fedc037 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8c/7f/91dc078e8cfc8e003a90e91e1762", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e0/ee/e2f283b6b432d2aecf105138482e", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/0f/15f10e5ed1ec1a80bf4fd443594f", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/25/6a/20ce70fc081376c90d8e154d0978", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7d/7b/35302bd8dee3631b9d9ddc8acfda", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/7e/8444f1e9bfdf287c9ad53af65192", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/c8/59ba42aeceb0ccf0ce728e25da15", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5a/c2/b9d745b8dff2fbcf3d782c60c325", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/37/ba/8f6ae8a0694207c90e19fcb31dcc", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/72/03/5f1f17bcae5f1cec82fb324de89f", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/85/bc/a8d4ba4f6cc15b06ec7220a8b7c6", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bc/97/e9e8ba547055185dbcf3b70989b3" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/27/40/1fe45427eee5496a07e8fbf47b4c", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/6c/b48dc6c0f69baea72d6d26ae8d56", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/ca/067894b1d810ba35f2bfa408934c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9d/4e/64254465e3457b7f300b6bd7e549", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3d/80/1d977155edb45a17fb998de6cc92", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/2e/812cb421ad169bf02801bf55d763", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/45/47/5052ab655d8fe5cb6dec1f521128", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/03/a8/600e4d7c0a56402ffcfd81e80f96", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/55/8a/2e363e2cfb9ae1d37c17b5028ea0", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/42/dc/e340d39693e8b42bea4ca63a7174", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9b/eb/0b123f5051f48ad8e8093eafd21a", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/78/9c/b4a377a15ca70ad25bdd8f8d7859" } \ No newline at end of file From b1d7d9638685926b0cd42e8b6e72772992e79ea2 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 7 May 2020 17:24:35 -0700 Subject: [PATCH 011/417] Test2 --- .../ba_data/python/bastd/game/chosenone.py | 50 ++++++++++--------- 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 7ae3fd06..47247396 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -65,29 +65,33 @@ class ChosenOneGame(ba.TeamGameActivity): def get_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [('Chosen One Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), ('Chosen One Gets Gloves', { - 'default': True - }), ('Chosen One Gets Shield', { - 'default': False - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), - ('Normal', 1.0), ('Long', 2.0), - ('Longer', 4.0)], - 'default': 1.0 - }), ('Epic Mode', { - 'default': False - })] + return [ + ('Chosen One Time', { + 'min_value': 10, + 'default': 30, + 'increment': 10 + }), + ('Chosen One Gets Gloves', { + 'default': True + }), + ('Chosen One Gets Shield', { + 'default': False + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard From fab6a54ff8ceb68c2869d31647f65f8b026c2ef9 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 10 May 2020 13:12:09 -0700 Subject: [PATCH 012/417] Fixed paths issue with server script --- .idea/dictionaries/ericf.xml | 1 + assets/src/server/ballisticacore_server.py | 25 +++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 4e45609f..3fa055ba 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -319,6 +319,7 @@ cnode codecsmodule codefilenames + codefiles codehash codeop collapsable diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index 926043b5..969d5884 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -31,22 +31,19 @@ from pathlib import Path from threading import Lock, Thread, current_thread from typing import TYPE_CHECKING +# We make use of the bacommon and efro packages as well as site-packages +# included with our bundled Ballistica dist, so we need to add those paths +# before we import them. +sys.path += [ + str(Path(Path(__file__).parent, 'dist', 'ba_data', 'python')), + str(Path(Path(__file__).parent, 'dist', 'ba_data', 'python-site-packages')) +] + from bacommon.servermanager import ServerConfig, StartServerModeCommand from efro.dataclasses import dataclass_assign, dataclass_validate from efro.error import CleanError from efro.terminal import Clr -# We change our working directory according to file's path -# so that the script can be properly executed from anywhere -os.chdir(os.path.abspath(os.path.dirname(__file__))) - -# We make use of the bacommon and efro packages as well as site-packages -# included with our bundled Ballistica dist. -sys.path += [ - str(Path(os.getcwd(), 'dist', 'ba_data', 'python')), - str(Path(os.getcwd(), 'dist', 'ba_data', 'python-site-packages')) -] - if TYPE_CHECKING: from typing import Optional, List, Dict, Union, Tuple from types import FrameType @@ -54,7 +51,7 @@ if TYPE_CHECKING: # Not sure how much versioning we'll do with this, but this will get # printed at startup in case we need it. -VERSION_STR = '1.0' +VERSION_STR = '1.0.1' class ServerManagerApp: @@ -432,6 +429,10 @@ class ServerManagerApp: def main() -> None: """Run a BallisticaCore server manager in interactive mode.""" try: + # Change our working directory according to file's path + # so that this script can be run from anywhere. + os.chdir(os.path.abspath(os.path.dirname(__file__))) + ServerManagerApp().run_interactive() except CleanError as exc: # For clean errors, do a simple print and fail; no tracebacks/etc. From c3b5a8807c5d04ee3f57f98bbe07a058804c28b5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 10 May 2020 13:16:51 -0700 Subject: [PATCH 013/417] Simplifying some thread pool worker counts to just use cpu_count --- tools/efrotools/code.py | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 3b18a02d..387331c7 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -66,13 +66,8 @@ def formatcode(projroot: Path, full: bool) -> None: sys.stdout.flush() return {'f': filename, 't': duration} - # NOTE: using fewer workers than we have logical procs for now; - # we're bottlenecked by one or two long running instances - # so it actually helps to lighten the load around them. - # may want to revisit later when we have everything chopped up - # better - with concurrent.futures.ThreadPoolExecutor(max_workers=cpu_count() // - 2) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=cpu_count()) as executor: # Converting this to a list will propagate any errors. list(executor.map(format_file, dirtyfiles)) @@ -122,7 +117,7 @@ def cpplint(projroot: Path, full: bool) -> None: if result != 0: raise Exception(f'Linting failed for {filename}') - with ThreadPoolExecutor(max_workers=cpu_count() // 2) as executor: + with ThreadPoolExecutor(max_workers=cpu_count()) as executor: # Converting this to a list will propagate any errors. list(executor.map(lint_file, dirtyfiles)) @@ -178,12 +173,7 @@ def formatscripts(projroot: Path, full: bool) -> None: print(f'Formatted {filename} in {duration:.2f} seconds.') sys.stdout.flush() - # NOTE: using fewer workers than we have logical procs for now; - # we're bottlenecked by one or two long running instances - # so it actually helps to lighten the load around them. - # may want to revisit later when we have everything chopped up - # better - with ThreadPoolExecutor(max_workers=cpu_count() // 2) as executor: + with ThreadPoolExecutor(max_workers=cpu_count()) as executor: # Convert the futures to a list to propagate any errors even # though there are no return values we use. list(executor.map(format_file, dirtyfiles)) From 1ccf33e41dc72835aa4520739b8ab40829c0e0d8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 18 May 2020 01:47:52 -0700 Subject: [PATCH 014/417] Added per-game team and player types --- .idea/dictionaries/ericf.xml | 19 + CHANGELOG.md | 3 + Makefile | 39 +- assets/src/ba_data/python/_ba.py | 116 ++- assets/src/ba_data/python/ba/__init__.py | 21 +- assets/src/ba_data/python/ba/_activity.py | 692 +++++++++------ .../src/ba_data/python/ba/_activitytypes.py | 11 +- assets/src/ba_data/python/ba/_actor.py | 34 +- assets/src/ba_data/python/ba/_benchmark.py | 2 +- assets/src/ba_data/python/ba/_coopgame.py | 9 +- assets/src/ba_data/python/ba/_coopsession.py | 8 +- assets/src/ba_data/python/ba/_error.py | 24 +- assets/src/ba_data/python/ba/_gameactivity.py | 25 +- assets/src/ba_data/python/ba/_gameresults.py | 45 +- assets/src/ba_data/python/ba/_general.py | 2 +- assets/src/ba_data/python/ba/_hooks.py | 12 +- assets/src/ba_data/python/ba/_lobby.py | 49 +- assets/src/ba_data/python/ba/_messages.py | 10 + .../ba_data/python/ba/_multiteamsession.py | 12 +- assets/src/ba_data/python/ba/_netutils.py | 2 +- assets/src/ba_data/python/ba/_player.py | 183 +++- assets/src/ba_data/python/ba/_session.py | 519 ++++------- assets/src/ba_data/python/ba/_stats.py | 71 +- assets/src/ba_data/python/ba/_team.py | 99 ++- assets/src/ba_data/python/ba/_teamgame.py | 14 +- .../python/bastd/activity/coopscore.py | 6 +- .../python/bastd/activity/dualteamscore.py | 13 +- .../python/bastd/activity/multiteamscore.py | 12 +- .../python/bastd/activity/multiteamvictory.py | 4 +- .../ba_data/python/bastd/actor/playerspaz.py | 51 +- .../ba_data/python/bastd/actor/respawnicon.py | 2 +- .../ba_data/python/bastd/actor/scoreboard.py | 28 +- .../src/ba_data/python/bastd/actor/spazbot.py | 2 +- .../src/ba_data/python/bastd/game/assault.py | 70 +- .../python/bastd/game/capturetheflag.py | 275 +++--- .../ba_data/python/bastd/game/chosenone.py | 4 +- .../src/ba_data/python/bastd/game/conquest.py | 4 +- .../ba_data/python/bastd/game/deathmatch.py | 4 +- .../python/bastd/game/easteregghunt.py | 4 +- .../ba_data/python/bastd/game/elimination.py | 11 +- .../src/ba_data/python/bastd/game/football.py | 22 +- .../src/ba_data/python/bastd/game/hockey.py | 26 +- .../src/ba_data/python/bastd/game/keepaway.py | 4 +- .../python/bastd/game/kingofthehill.py | 4 +- .../ba_data/python/bastd/game/meteorshower.py | 59 +- .../ba_data/python/bastd/game/ninjafight.py | 4 +- .../ba_data/python/bastd/game/onslaught.py | 4 +- assets/src/ba_data/python/bastd/game/race.py | 4 +- .../ba_data/python/bastd/game/runaround.py | 6 +- .../python/bastd/game/targetpractice.py | 4 +- .../ba_data/python/bastd/game/thelaststand.py | 4 +- assets/src/ba_data/python/bastd/mainmenu.py | 10 +- assets/src/ba_data/python/bastd/tutorial.py | 2 +- assets/src/server/ballisticacore_server.py | 25 +- config/toolconfigsrc/mypy.ini | 15 + config/toolconfigsrc/pylintrc | 1 + docs/ba_module.md | 816 +++++++++++------- tools/bacloud | 4 +- tools/batools/build.py | 6 +- tools/efro/entity/_field.py | 6 +- tools/efro/entity/_value.py | 4 +- tools/efro/util.py | 18 +- tools/efrotools/__init__.py | 4 +- tools/efrotools/code.py | 173 ++-- tools/efrotools/pylintplugins.py | 64 +- tools/efrotools/snippets.py | 224 +++-- tools/snippets | 15 +- tools/update_project | 53 +- 68 files changed, 2383 insertions(+), 1709 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 4e45609f..78083559 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -319,6 +319,7 @@ cnode codecsmodule codefilenames + codefiles codehash codeop collapsable @@ -727,8 +728,10 @@ gamepads gamepadselect gameplay + gameplayer gameport gameresults + gameteam gametype gametypes gameutils @@ -762,6 +765,7 @@ getsession getsockname getsound + getspaz getstarttime gettext gettexture @@ -893,6 +897,7 @@ inputfiles inputhash inputnode + inputtype inpututils inspectdir insta @@ -1319,6 +1324,7 @@ pipname pkey pkgutil + playercast playerdata playerlostspaz playernode @@ -1326,6 +1332,8 @@ playerpts playerrec playerspaz + playerteamdata + playertype playerval playlistui playmode @@ -1358,6 +1366,7 @@ positionadjusted posixpath posixsubprocess + postinit poststr powerdown powersgiven @@ -1368,6 +1377,7 @@ poweruptype powervr ppos + pproxy pragmas prch prec @@ -1547,6 +1557,7 @@ runmypy runonly runpy + runpylint runswindows rval safecolor @@ -1610,6 +1621,8 @@ sessiondata sessionglobals sessionname + sessionplayer + sessionteam sessiontype setalpha setbuild @@ -1685,6 +1698,7 @@ srcnode srcpath srcpathfull + srcplayer srcpy srcpydata srcstr @@ -1720,6 +1734,7 @@ strftime stringprep stringptr + strippable strobing strptime strt @@ -1785,11 +1800,13 @@ tdelay tdval teambasesession + teamdata teamgame teamnamescolors teamsize teamsscorescreen teamssession + teamtype teeeeeeeesssssttttdddddddd teehee teleporting @@ -1867,11 +1884,13 @@ toplevel totaldudes totalpts + totype touchpad tournamententry tournamentscores tplayer tpos + tproxy tracebacks tracemalloc tradeoff diff --git a/CHANGELOG.md b/CHANGELOG.md index b0c46787..424485c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,9 @@ - The bs.Vector class is no more; in its place is a shiny new ba.Vec3 which is implemented internally in C++ so its nice and speedy. Will probably update certain things like vector node attrs to support this class in the future since it makes vector math nice and convenient. - Ok you get the point.. +### 1.4.155 (14377) +- Added protection against a repeated-input attack in lobbies. + ### 1.4.151 (14371) - Added Chinese-Traditional language and improved translations for others. diff --git a/Makefile b/Makefile index 99a72509..28aca96d 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ # Targets in this top level Makefile do not expect -jX to be passed to them # and generally handle spawning an appropriate number of child jobs themselves. -# Prefix used for output of docs/changelogs/etc targets for use in webpages. +# Prefix used for output of docs/changelogs/etc. targets for use in webpages. DOCPREFIX = "ballisticacore_" @@ -475,12 +475,12 @@ update-check: prereqs # Run formatting on all files in the project considered 'dirty'. format: @${MAKE} -j3 format-code format-scripts format-makefile - @echo Formatting complete! + @tools/snippets echo GRN Formatting complete! # Same but always formats; ignores dirty state. format-full: @${MAKE} -j3 format-code-full format-scripts-full format-makefile - @echo Formatting complete! + @tools/snippets echo GRN Formatting complete! # Run formatting for compiled code sources (.cc, .h, etc.). format-code: prereqs @@ -515,22 +515,22 @@ format-makefile: prereqs # Run all project checks. (static analysis) check: update-check @${MAKE} -j3 cpplint pylint mypy - @echo ALL CHECKS PASSED! + @tools/snippets echo GRN ALL CHECKS PASSED! # Same as check but no caching (all files are checked). check-full: update-check @${MAKE} -j3 cpplint-full pylint-full mypy-full - @echo ALL CHECKS PASSED! + @tools/snippets echo GRN ALL CHECKS PASSED! # Same as 'check' plus optional/slow extra checks. check2: update-check @${MAKE} -j4 cpplint pylint mypy pycharm - @echo ALL CHECKS PASSED! + @tools/snippets echo GRN ALL CHECKS PASSED! # Same as check2 but no caching (all files are checked). check2-full: update-check @${MAKE} -j4 cpplint-full pylint-full mypy-full pycharm-full - @echo ALL CHECKS PASSED! + @tools/snippets echo GRN ALL CHECKS PASSED! # Run Cpplint checks on all C/C++ code. cpplint: prereqs @@ -586,6 +586,7 @@ pycharm-full: prereqs # Run all tests. (live execution verification) test: prereqs + @tools/snippets echo BLU Running all tests... @tools/snippets pytest -v tests # Run tests with any caching disabled. @@ -615,28 +616,28 @@ preflight: @${MAKE} format @${MAKE} update @${MAKE} -j4 cpplint pylint mypy test - @echo PREFLIGHT SUCCESSFUL! + @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! # Same as 'preflight' without caching (all files are visited). preflight-full: @${MAKE} format-full @${MAKE} update @${MAKE} -j4 cpplint-full pylint-full mypy-full test-full - @echo PREFLIGHT SUCCESSFUL! + @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! # Same as 'preflight' plus optional/slow extra checks. preflight2: @${MAKE} format @${MAKE} update @${MAKE} -j5 cpplint pylint mypy pycharm test - @echo PREFLIGHT SUCCESSFUL! + @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! # Same as 'preflight2' but without caching (all files visited). preflight2-full: @${MAKE} format-full @${MAKE} update @${MAKE} -j5 cpplint-full pylint-full mypy-full pycharm-full test-full - @echo PREFLIGHT SUCCESSFUL! + @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! # Tell make which of these targets don't represent files. .PHONY: preflight preflight-full preflight2 preflight2-full @@ -675,28 +676,28 @@ TOOL_CFG_SRC = tools/efrotools/snippets.py config/config.json ENV_SRC = tools/snippets tools/batools/build.py .clang-format: config/toolconfigsrc/clang-format ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .style.yapf: config/toolconfigsrc/style.yapf ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .pylintrc: config/toolconfigsrc/pylintrc ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .projectile: config/toolconfigsrc/projectile ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .editorconfig: config/toolconfigsrc/editorconfig ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .dir-locals.el: config/toolconfigsrc/dir-locals.el ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .mypy.ini: config/toolconfigsrc/mypy.ini ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ .pycheckers: config/toolconfigsrc/pycheckers ${TOOL_CFG_SRC} - ${TOOL_CFG_INST} $< $@ + @${TOOL_CFG_INST} $< $@ # Include anything as sources here that should require .cache/checkenv: ${ENV_SRC} diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index e73d0521..e9207771 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=233656876767477563471907026700832716822 +# SOURCES_HASH=266649817838802754126771358652920545389 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -259,7 +259,7 @@ class InputDevice: allows_configuring: bool Whether the input-device can be configured. - player: Optional[ba.Player] + player: Optional[ba.SessionPlayer] The player associated with this input device. client_id: int @@ -292,7 +292,7 @@ class InputDevice: """ exists: bool allows_configuring: bool - player: Optional[ba.Player] + player: Optional[ba.SessionPlayer] client_id: int name: str unique_identifier: str @@ -648,6 +648,14 @@ class Node: billboard_texture: Optional[ba.Texture] = None billboard_cross_out: bool = False billboard_opacity: float = 0.0 + slow_motion: bool = False + music: str = '' + vr_camera_offset: Sequence[float] = (0.0, 0.0, 0.0) + vr_overlay_center: Sequence[float] = (0.0, 0.0, 0.0) + vr_overlay_center_enabled: bool = False + vignette_outer: Sequence[float] = (0.0, 0.0) + vignette_inner: Sequence[float] = (0.0, 0.0) + tint: Sequence[float] = (1.0, 1.0, 1.0) def add_death_action(self, action: Callable[[], None]) -> None: """add_death_action(action: Callable[[], None]) -> None @@ -737,31 +745,36 @@ class Node: return None -class Player: - """A reference to a player in the game. +class SessionData: + """(internal)""" + + def exists(self) -> bool: + """exists() -> bool + + Returns whether the SessionData still exists. + Most functionality will fail on a nonexistent instance. + """ + return bool() + + +class SessionPlayer: + """A reference to a player in the ba.Session. Category: Gameplay Classes These are created and managed internally and provided to your Session/Activity instances. - Be aware that, like ba.Nodes, ba.Player objects are 'weak' + Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak' references under-the-hood; a player can leave the game at any point. For this reason, you should make judicious use of the - ba.Player.exists attribute (or boolean operator) to ensure that a - Player is still present if retaining references to one for any - length of time. + ba.SessionPlayer.exists attribute (or boolean operator) to ensure + that a SessionPlayer is still present if retaining references to one + for any length of time. Attributes: - actor: Optional[ba.Actor] - The current ba.Actor associated with this Player. - This may be None - - node: Optional[ba.Node] - A ba.Node of type 'player' associated with this Player. - This Node exists in the currently active game and can be used - to get a generic player position/etc. - This will be None if the Player is not in a game. + id: int + The unique numeric ID of the Player. exists: bool Whether the player still exists. @@ -775,10 +788,10 @@ class Player: This bool value will be True once the Player has completed any lobby character/team selection. - team: ba.Team - The ba.Team this Player is on. If the Player is - still in its lobby selecting a team/etc. then a - ba.TeamNotFoundError will be raised. + team: ba.SessionTeam + The ba.SessionTeam this Player is on. If the SessionPlayer + is still in its lobby selecting a team/etc. then a + ba.SessionTeamNotFoundError will be raised. sessiondata: Dict A dict for use by the current ba.Session for @@ -792,7 +805,7 @@ class Player: color: Sequence[float] The base color for this Player. - In team games this will match the ba.Team's color. + In team games this will match the ba.SessionTeam's color. highlight: Sequence[float] A secondary color for this player. @@ -802,17 +815,20 @@ class Player: character: str The character this player has selected in their profile. + + gameplayer: Optional[ba.Player] + The current game-specific instance for this player. """ - actor: Optional[ba.Actor] - node: Optional[ba.Node] + id: int exists: bool in_game: bool - team: ba.Team + team: ba.SessionTeam sessiondata: Dict gamedata: Dict color: Sequence[float] highlight: Sequence[float] character: str + gameplayer: Optional[ba.Player] def assign_input_call(self, type: Union[str, Tuple[str, ...]], call: Callable) -> None: @@ -855,13 +871,6 @@ class Player: """ return {'foo': 'bar'} - def get_id(self) -> int: - """get_id() -> int - - Returns the unique numeric player ID for this player. - """ - return int() - def get_input_device(self) -> ba.InputDevice: """get_input_device() -> ba.InputDevice @@ -878,14 +887,6 @@ class Player: """ return str() - def is_alive(self) -> bool: - """is_alive() -> bool - - Returns True if the player has a ba.Actor assigned and its - is_alive() method return True. False is returned otherwise. - """ - return bool() - def remove_from_game(self) -> None: """remove_from_game() -> None @@ -914,17 +915,10 @@ class Player: """ return None - def set_actor(self, actor: Optional[ba.Actor]) -> None: - """set_actor(actor: Optional[ba.Actor]) -> None - - Set the player's associated ba.Actor. - """ - return None - - def set_data(self, team: ba.Team, character: str, color: Sequence[float], - highlight: Sequence[float]) -> None: - """set_data(team: ba.Team, character: str, color: Sequence[float], - highlight: Sequence[float]) -> None + def set_data(self, team: ba.SessionTeam, character: str, + color: Sequence[float], highlight: Sequence[float]) -> None: + """set_data(team: ba.SessionTeam, character: str, + color: Sequence[float], highlight: Sequence[float]) -> None (internal) """ @@ -961,18 +955,6 @@ class Player: return None -class SessionData: - """(internal)""" - - def exists(self) -> bool: - """exists() -> bool - - Returns whether the SessionData still exists. - Most functionality will fail on a nonexistent instance. - """ - return bool() - - class Sound: """A reference to a sound. @@ -2011,7 +1993,7 @@ def get_foreground_host_activity() -> Optional[ba.Activity]: is none. """ import ba # pylint: disable=cyclic-import - return ba.Activity({}) + return ba.Activity(settings={}) def get_foreground_host_session() -> Optional[ba.Session]: @@ -2348,7 +2330,7 @@ def getactivity(doraise: bool = True) -> ba.Activity: False then None is returned instead. """ import ba # pylint: disable=cyclic-import - return ba.Activity({}) + return ba.Activity(settings={}) def getcollidemodel(name: str) -> ba.CollideModel: @@ -2905,7 +2887,7 @@ def new_activity(activity_type: Type[ba.Activity], instantiated; You must go through this function. """ import ba # pylint: disable=cyclic-import - return ba.Activity({}) + return ba.Activity(settings={}) def new_host_session(sessiontype: Type[ba.Session], diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 0277bf92..1c5d157c 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -29,8 +29,8 @@ In some specific cases you may need to pull in individual submodules instead. # pylint: disable=redefined-builtin from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, - Material, Model, Node, Player, Sound, Texture, Timer, Vec3, - Widget, buttonwidget, camerashake, checkboxwidget, + Material, Model, Node, SessionPlayer, Sound, Texture, Timer, + Vec3, Widget, buttonwidget, camerashake, checkboxwidget, columnwidget, containerwidget, do_once, emitfx, get_collision_info, getactivity, getcollidemodel, getmodel, getnodes, getsession, getsound, gettexture, hscrollwidget, @@ -40,7 +40,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, charstr, textwidget, time, timer, open_url, widget) from ba._activity import Activity from ba._actor import Actor -from ba._player import BasePlayerData +from ba._player import Player, playercast, playercast_o from ba._nodeactor import NodeActor from ba._app import App from ba._coopgame import CoopGameActivity @@ -48,11 +48,12 @@ from ba._coopsession import CoopSession from ba._dependency import (Dependency, DependencyComponent, DependencySet, AssetPackage) from ba._enums import TimeType, Permission, TimeFormat, SpecialChar -from ba._error import (UNHANDLED, print_exception, print_error, NotFoundError, - PlayerNotFoundError, NodeNotFoundError, - ActorNotFoundError, InputDeviceNotFoundError, - WidgetNotFoundError, ActivityNotFoundError, - TeamNotFoundError, SessionNotFoundError, +from ba._error import (print_exception, print_error, NotFoundError, + PlayerNotFoundError, SessionPlayerNotFoundError, + NodeNotFoundError, ActorNotFoundError, + InputDeviceNotFoundError, WidgetNotFoundError, + ActivityNotFoundError, TeamNotFoundError, + SessionTeamNotFoundError, SessionNotFoundError, DependencyError) from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity @@ -63,7 +64,7 @@ from ba._session import Session from ba._servermode import ServerController from ba._score import ScoreType, ScoreInfo from ba._stats import PlayerScoredMessage, PlayerRecord, Stats -from ba._team import Team +from ba._team import SessionTeam, Team from ba._teamgame import TeamGameActivity from ba._dualteamsession import DualTeamSession from ba._achievement import Achievement @@ -77,7 +78,7 @@ from ba._general import WeakCall, Call from ba._level import Level from ba._lobby import Lobby, Chooser from ba._math import normalized_color, is_point_in_box, vec3validate -from ba._messages import (OutOfBoundsMessage, DeathType, DieMessage, +from ba._messages import (UNHANDLED, OutOfBoundsMessage, DeathType, DieMessage, StandMessage, PickUpMessage, DropMessage, PickedUpMessage, DroppedMessage, ShouldShatterMessage, ImpactDamageMessage, diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 904fe28e..4098788f 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -22,10 +22,13 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Generic, TypeVar -import _ba +from ba._team import Team +from ba._player import Player +from ba._error import print_exception, print_error, SessionTeamNotFoundError from ba._dependency import DependencyComponent +import _ba if TYPE_CHECKING: from weakref import ReferenceType @@ -33,8 +36,11 @@ if TYPE_CHECKING: import ba from bastd.actor.respawnicon import RespawnIcon +PlayerType = TypeVar('PlayerType', bound=Player) +TeamType = TypeVar('TeamType', bound=Team) -class Activity(DependencyComponent): + +class Activity(DependencyComponent, Generic[PlayerType, TeamType]): """Units of execution wrangled by a ba.Session. Category: Gameplay Classes @@ -66,13 +72,73 @@ class Activity(DependencyComponent): # pylint: disable=too-many-public-methods - # Annotating attr types at the class level lets us introspect them. + # Annotating attr types at the class level lets us introspect at runtime. settings_raw: Dict[str, Any] - teams: List[ba.Team] - players: List[ba.Player] + teams: List[TeamType] + players: List[PlayerType] + + # Whether to print every time a player dies. This can be pertinent + # in games such as Death-Match but can be annoying in games where it + # doesn't matter. + announce_player_deaths = False + + # Joining activities are for waiting for initial player joins. + # They are treated slightly differently than regular activities, + # mainly in that all players are passed to the activity at once + # instead of as each joins. + is_joining_activity = False + + # Whether game-time should still progress when in menus/etc. + allow_pausing = False + + # Whether idle players can potentially be kicked (should not happen in + # menus/etc). + allow_kick_idle_players = True + + # In vr mode, this determines whether overlay nodes (text, images, etc) + # are created at a fixed position in space or one that moves based on + # the current map. Generally this should be on for games and off for + # transitions/score-screens/etc. that persist between maps. + use_fixed_vr_overlay = False + + # If True, runs in slow motion and turns down sound pitch. + slow_motion = False + + # Set this to True to inherit slow motion setting from previous + # activity (useful for transitions to avoid hitches). + inherits_slow_motion = False + + # Set this to True to keep playing the music from the previous activity + # (without even restarting it). + inherits_music = False + + # Set this to true to inherit VR camera offsets from the previous + # activity (useful for preventing sporadic camera movement + # during transitions). + inherits_camera_vr_offset = False + + # Set this to true to inherit (non-fixed) VR overlay positioning from + # the previous activity (useful for prevent sporadic overlay jostling + # during transitions). + inherits_vr_overlay_center = False + + # Set this to true to inherit screen tint/vignette colors from the + # previous activity (useful to prevent sudden color changes during + # transitions). + inherits_tint = False + + # If the activity fades or transitions in, it should set the length of + # time here so that previous activities will be kept alive for that + # long (avoiding 'holes' in the screen) + # This value is given in real-time seconds. + transition_time = 0.0 + + # Is it ok to show an ad after this activity ends before showing + # the next activity? + can_show_ad_on_death = False def __init__(self, settings: Dict[str, Any]): - """Creates an activity in the current ba.Session. + """Creates an Activity in the current ba.Session. The activity will not be actually run until ba.Session.set_activity() is called. 'settings' should be a dict of key/value pairs specific @@ -84,14 +150,20 @@ class Activity(DependencyComponent): """ super().__init__() - # FIXME: Relocate this stuff. + # Create our internal engine data. + self._activity_data = _ba.register_activity(self) + + # Player/Team types should have been specified as type args; + # grab those. + self._playertype: Type[PlayerType] + self._teamtype: Type[TeamType] + self._setup_player_and_team_types() + + # FIXME: Relocate or remove the need for this stuff. self.sharedobjs: Dict[str, Any] = {} self.paused_text: Optional[ba.Actor] = None self.spaz_respawn_icons_right: Dict[int, RespawnIcon] - # Create our internal engine data. - self._activity_data = _ba.register_activity(self) - session = _ba.getsession() if session is None: raise Exception('No current session') @@ -105,8 +177,9 @@ class Activity(DependencyComponent): if _ba.getactivity(doraise=False) is not self: raise Exception('invalid context state') - # Should perhaps kill this; activities should validate/store whatever - # settings they need at init time (in a more type-safe way). + # Hopefully can eventually kill this; activities should + # validate/store whatever settings they need at init time + # (in a more type-safe way). self.settings_raw = settings self._has_transitioned_in = False @@ -122,66 +195,6 @@ class Activity(DependencyComponent): self._activity_death_check_timer: Optional[ba.Timer] = None self._expired = False - # Whether to print every time a player dies. This can be pertinent - # in games such as Death-Match but can be annoying in games where it - # doesn't matter. - self.announce_player_deaths = False - - # Joining activities are for waiting for initial player joins. - # They are treated slightly differently than regular activities, - # mainly in that all players are passed to the activity at once - # instead of as each joins. - self.is_joining_activity = False - - # Whether game-time should still progress when in menus/etc. - self.allow_pausing = False - - # Whether idle players can potentially be kicked (should not happen in - # menus/etc). - self.allow_kick_idle_players = True - - # In vr mode, this determines whether overlay nodes (text, images, etc) - # are created at a fixed position in space or one that moves based on - # the current map. Generally this should be on for games and off for - # transitions/score-screens/etc. that persist between maps. - self.use_fixed_vr_overlay = False - - # If True, runs in slow motion and turns down sound pitch. - self.slow_motion = False - - # Set this to True to inherit slow motion setting from previous - # activity (useful for transitions to avoid hitches). - self.inherits_slow_motion = False - - # Set this to True to keep playing the music from the previous activity - # (without even restarting it). - self.inherits_music = False - - # Set this to true to inherit VR camera offsets from the previous - # activity (useful for preventing sporadic camera movement - # during transitions). - self.inherits_camera_vr_offset = False - - # Set this to true to inherit (non-fixed) VR overlay positioning from - # the previous activity (useful for prevent sporadic overlay jostling - # during transitions). - self.inherits_vr_overlay_center = False - - # Set this to true to inherit screen tint/vignette colors from the - # previous activity (useful to prevent sudden color changes during - # transitions). - self.inherits_tint = False - - # If the activity fades or transitions in, it should set the length of - # time here so that previous activities will be kept alive for that - # long (avoiding 'holes' in the screen) - # This value is given in real-time seconds. - self.transition_time = 0.0 - - # Is it ok to show an ad after this activity ends before showing - # the next activity? - self.can_show_ad_on_death = False - # This gets set once another activity has begun transitioning in but # before this one is killed. The on_transition_out() method is also # called at this time. Make sure to not assign player inputs, @@ -194,48 +207,16 @@ class Activity(DependencyComponent): # is dying. self._actor_refs: List[ba.Actor] = [] self._actor_weak_refs: List[ReferenceType[ba.Actor]] = [] - self._last_dead_object_prune_time = _ba.time() + self._last_prune_dead_actors_time = _ba.time() + self._prune_dead_actors_timer: Optional[ba.Timer] = None # This stuff gets filled in just before on_begin() is called. self.teams = [] self.players = [] + self.lobby = None self._stats: Optional[ba.Stats] = None - self.lobby = None - self._prune_dead_objects_timer: Optional[ba.Timer] = None - - @property - def stats(self) -> ba.Stats: - """The stats instance accessible while the activity is running. - - If access is attempted before or after, raises a ba.NotFoundError. - """ - if self._stats is None: - from ba._error import NotFoundError - raise NotFoundError() - return self._stats - - def on_expire(self) -> None: - """Called when your activity is being expired. - - If your activity has created anything explicitly that may be retaining - a strong reference to the activity and preventing it from dying, you - should clear that out here. From this point on your activity's sole - purpose in life is to hit zero references and die so the next activity - can begin. - """ - - def is_expired(self) -> bool: - """Return whether the activity is expired. - - An activity is set as expired when shutting down. - At this point no new nodes, timers, etc should be made, - run, etc, and the activity should be considered a 'zombie'. - """ - return self._expired - def __del__(self) -> None: - from ba._apputils import garbage_collect, call_after_ad # If the activity has been run then we should have already cleaned @@ -259,6 +240,47 @@ class Activity(DependencyComponent): else: _ba.pushcall(session.begin_next_activity) + @property + def stats(self) -> ba.Stats: + """The stats instance accessible while the activity is running. + + If access is attempted before or after, raises a ba.NotFoundError. + """ + if self._stats is None: + from ba._error import NotFoundError + raise NotFoundError() + return self._stats + + def on_expire(self) -> None: + """Called when your activity is being expired. + + If your activity has created anything explicitly that may be retaining + a strong reference to the activity and preventing it from dying, you + should clear that out here. From this point on your activity's sole + purpose in life is to hit zero references and die so the next activity + can begin. + """ + + @property + def expired(self) -> bool: + """Whether the activity is expired. + + An activity is set as expired when shutting down. + At this point no new nodes, timers, etc should be made, + run, etc, and the activity should be considered a 'zombie'. + """ + return self._expired + + @property + def playertype(self) -> Type[PlayerType]: + """The type of ba.Player this Activity is using.""" + return self._playertype + + @property + def teamtype(self) -> Type[TeamType]: + """The type of ba.Team this Activity is using.""" + return self._teamtype + def set_has_ended(self, val: bool) -> None: """(internal)""" self._has_ended = val @@ -277,18 +299,11 @@ class Activity(DependencyComponent): self._should_end_immediately_results = results self._should_end_immediately_delay = delay - def _get_player_icon(self, player: ba.Player) -> Dict[str, Any]: + def destroy(self) -> None: + """Begin the process of tearing down the activity. - # Do we want to cache these somehow? - info = player.get_icon_info() - return { - 'texture': _ba.gettexture(info['texture']), - 'tint_texture': _ba.gettexture(info['tint_texture']), - 'tint_color': info['tint_color'], - 'tint2_color': info['tint2_color'] - } - - def _destroy(self) -> None: + (internal) + """ from ba._general import Call from ba._enums import TimeType @@ -313,7 +328,8 @@ class Activity(DependencyComponent): with _ba.Context('empty'): self._expire() else: - raise Exception('_destroy() called multiple times') + raise RuntimeError(f'destroy() called when' + f' already expired for {self}') @classmethod def _check_activity_death(cls, activity_ref: ReferenceType[Activity], @@ -351,54 +367,54 @@ class Activity(DependencyComponent): _ba.quit() except Exception: - from ba import _error - _error.print_exception('exception on _check_activity_death:') + print_exception('exception on _check_activity_death:') def _expire(self) -> None: - from ba import _error + """Put the activity in a state where it can be garbage-collected. + + This involves clearing anything that might be holding a reference + to it, etc. + """ + assert not self._expired self._expired = True - # Do some default cleanup. try: - try: - self.on_expire() - except Exception: - _error.print_exception('Error in activity on_expire()', self) - - # Send finalize notices to all remaining actors. - for actor_ref in self._actor_weak_refs: - try: - actor = actor_ref() - if actor is not None: - actor.on_expire() - except Exception: - _error.print_exception( - 'Exception on ba.Activity._expire()' - ' in actor on_expire():', actor_ref()) - - # Reset all players. - # (releases any attached actors, clears game-data, etc) - for player in self.players: - if player: - try: - player.reset() - player.set_activity(None) - except Exception: - _error.print_exception( - 'Exception on ba.Activity._expire()' - ' resetting player:', player) - - # Ditto with teams. - for team in self.teams: - try: - team.reset() - except Exception: - _error.print_exception( - 'Exception on ba.Activity._expire() resetting team:', - team) - + self.on_expire() except Exception: - _error.print_exception('Exception during ba.Activity._expire():') + print_exception(f'Error in Activity on_expire() for {self}') + + # Send expire notices to all remaining actors. + for actor_ref in self._actor_weak_refs: + try: + actor = actor_ref() + if actor is not None: + actor.on_expire() + except Exception: + print_exception(f'Error expiring Actor {actor_ref()}') + + # Reset all Players. + # (releases any attached actors, clears game-data, etc) + for player in self.players: + if player: + try: + sessionplayer = player.sessionplayer + sessionplayer.set_node(None) + sessionplayer.set_activity(None) + sessionplayer.gameplayer = None + sessionplayer.reset() + except Exception: + print_exception(f'Error resetting Player {player}') + + # Ditto with Teams. + for team in self.teams: + try: + sessionteam = team.sessionteam + sessionteam.gameteam = None + sessionteam.reset_gamedata() + except SessionTeamNotFoundError: + pass + except Exception: + print_exception(f'Error resetting Team {team}') # Regardless of what happened here, we want to destroy our data, as # our activity might not go down if we don't. This will kill all @@ -407,13 +423,13 @@ class Activity(DependencyComponent): try: self._activity_data.destroy() except Exception: - _error.print_exception( + print_exception( 'Exception during ba.Activity._expire() destroying data:') - def _prune_dead_objects(self) -> None: + def _prune_dead_actors(self) -> None: self._actor_refs = [a for a in self._actor_refs if a] self._actor_weak_refs = [a for a in self._actor_weak_refs if a()] - self._last_dead_object_prune_time = _ba.time() + self._last_prune_dead_actors_time = _ba.time() def retain_actor(self, actor: ba.Actor) -> None: """Add a strong-reference to a ba.Actor to this Activity. @@ -423,16 +439,14 @@ class Activity(DependencyComponent): is a convenient way to access this same functionality. """ from ba import _actor as bsactor - from ba import _error if not isinstance(actor, bsactor.Actor): raise Exception('non-actor passed to _retain_actor') if (self.has_transitioned_in() - and _ba.time() - self._last_dead_object_prune_time > 10.0): - _error.print_error('it looks like nodes/actors are not' - ' being pruned in your activity;' - ' did you call Activity.on_transition_in()' - ' from your subclass?; ' + str(self) + - ' (loc. a)') + and _ba.time() - self._last_prune_dead_actors_time > 10.0): + print_error('it looks like nodes/actors are not' + ' being pruned in your activity;' + ' did you call Activity.on_transition_in()' + ' from your subclass?; ' + str(self) + ' (loc. a)') self._actor_refs.append(actor) def add_actor_weak_ref(self, actor: ba.Actor) -> None: @@ -441,16 +455,14 @@ class Activity(DependencyComponent): (called by the ba.Actor base class) """ from ba import _actor as bsactor - from ba import _error if not isinstance(actor, bsactor.Actor): raise Exception('non-actor passed to _add_actor_weak_ref') if (self.has_transitioned_in() - and _ba.time() - self._last_dead_object_prune_time > 10.0): - _error.print_error('it looks like nodes/actors are ' - 'not being pruned in your activity;' - ' did you call Activity.on_transition_in()' - ' from your subclass?; ' + str(self) + - ' (loc. b)') + and _ba.time() - self._last_prune_dead_actors_time > 10.0): + print_error('it looks like nodes/actors are ' + 'not being pruned in your activity;' + ' did you call Activity.on_transition_in()' + ' from your subclass?; ' + str(self) + ' (loc. b)') self._actor_weak_refs.append(weakref.ref(actor)) @property @@ -465,48 +477,38 @@ class Activity(DependencyComponent): raise SessionNotFoundError() return session - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: PlayerType) -> None: """Called when a new ba.Player has joined the Activity. (including the initial set of Players) """ - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: PlayerType) -> None: """Called when a ba.Player is leaving the Activity.""" - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: TeamType) -> None: """Called when a new ba.Team joins the Activity. (including the initial set of Teams) """ - def on_team_leave(self, team: ba.Team) -> None: + def on_team_leave(self, team: TeamType) -> None: """Called when a ba.Team leaves the Activity.""" def on_transition_in(self) -> None: """Called when the Activity is first becoming visible. Upon this call, the Activity should fade in backgrounds, - start playing music, etc. It does not yet have access to ba.Players - or ba.Teams, however. They remain owned by the previous Activity + start playing music, etc. It does not yet have access to players + or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called. """ - from ba._general import WeakCall - self._called_activity_on_transition_in = True - # Start pruning our transient actors periodically. - self._prune_dead_objects_timer = _ba.Timer( - 5.17, WeakCall(self._prune_dead_objects), repeat=True) - self._prune_dead_objects() - - # Also start our low-level scene-graph running. - self._activity_data.start() - def on_transition_out(self) -> None: """Called when your activity begins transitioning out. - Note that this may happen at any time even if finish() has not been + Note that this may happen at any time even if end() has not been called. """ @@ -552,110 +554,223 @@ class Activity(DependencyComponent): """Return whether on_transition_out() has been called.""" return self._transitioning_out - def start_transition_in(self) -> None: - """Called by Session to kick of transition-in. + def transition_in(self, prev_globals: Optional[ba.Node]) -> None: + """Called by Session to kick off transition-in. (internal) """ + from ba._general import WeakCall + from ba._gameutils import sharedobj assert not self._has_transitioned_in self._has_transitioned_in = True - self.on_transition_in() - def create_player_node(self, player: ba.Player) -> ba.Node: - """Create the 'player' node associated with the provided ba.Player.""" - from ba._nodeactor import NodeActor + # Set up the globals node based on our settings. with _ba.Context(self): - node = _ba.newnode('player', attrs={'playerID': player.get_id()}) - # FIXME: Should add a dedicated slot for this on ba.Player - # instead of cluttering up their gamedata dict. - player.gamedata['_playernode'] = NodeActor(node) - return node - - def begin(self, session: ba.Session) -> None: - """Begin the activity. (should only be called by Session). - - (internal)""" - - # pylint: disable=too-many-branches - from ba import _error - - if self._has_begun: - _error.print_error("_begin called twice; this shouldn't happen") - return - - self._stats = session.stats - - # Operate on the subset of session players who have passed team/char - # selection. - players = [] - chooser_players = [] - for player in session.players: - assert player # should we ever have invalid players?.. - if player: - try: - team: Optional[ba.Team] = player.team - except _error.TeamNotFoundError: - team = None - - if team is not None: - player.reset_input() - players.append(player) - else: - # Simply ignore players sitting in the lobby. - # (though this technically shouldn't happen anymore since - # choosers now get cleared when starting new activities.) - print('unexpected: got no-team player in _begin') - chooser_players.append(player) + # Now that it's going to be front and center, + # set some global values based on what the activity wants. + glb = sharedobj('globals') + glb.use_fixed_vr_overlay = self.use_fixed_vr_overlay + glb.allow_kick_idle_players = self.allow_kick_idle_players + if self.inherits_slow_motion and prev_globals is not None: + glb.slow_motion = prev_globals.slow_motion else: - _error.print_error( - 'got nonexistent player in Activity._begin()') + glb.slow_motion = self.slow_motion + if self.inherits_music and prev_globals is not None: + glb.music_continuous = True # Prevent restarting same music. + glb.music = prev_globals.music + glb.music_count += 1 + if self.inherits_camera_vr_offset and prev_globals is not None: + glb.vr_camera_offset = prev_globals.vr_camera_offset + if self.inherits_vr_overlay_center and prev_globals is not None: + glb.vr_overlay_center = prev_globals.vr_overlay_center + glb.vr_overlay_center_enabled = ( + prev_globals.vr_overlay_center_enabled) - # Add teams in one by one and send team-joined messages for each. - for team in session.teams: - if team in self.teams: - raise Exception('Duplicate Team Entry') + # If they want to inherit tint from the previous self. + if self.inherits_tint and prev_globals is not None: + glb.tint = prev_globals.tint + glb.vignette_outer = prev_globals.vignette_outer + glb.vignette_inner = prev_globals.vignette_inner + + # Start pruning our transient actors periodically. + self._prune_dead_actors_timer = _ba.Timer( + 5.17, WeakCall(self._prune_dead_actors), repeat=True) + self._prune_dead_actors() + + # Also start our low-level scene running. + self._activity_data.start() + + try: + self.on_transition_in() + except Exception: + print_exception('Error in on_transition_in for', self) + + # Tell the C++ layer that this activity is the main one, so it uses + # settings from our globals, directs various events to us, etc. + self._activity_data.make_foreground() + + def transition_out(self) -> None: + """Called by the Session to start us transitioning out.""" + assert not self._transitioning_out + self._transitioning_out = True + with _ba.Context(self): + try: + self.on_transition_out() + except Exception: + print_exception('Error in on_transition_out for', self) + + def create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType: + """Create the Player instance for this Activity. + + Subclasses can override this if the activity's player class + requires a custom constructor; otherwise it will be called with + no args. Note that the player object should not be used at this + point as it is not yet fully wired up; wait for on_player_join() + for that. + """ + del sessionplayer # Unused + player = self._playertype() + return player + + def create_team(self, sessionteam: ba.SessionTeam) -> TeamType: + """Create the Team instance for this Activity. + + Subclasses can override this if the activity's team class + requires a custom constructor; otherwise it will be called with + no args. Note that the team object should not be used at this + point as it is not yet fully wired up; wait for on_team_join() + for that. + """ + del sessionteam # Unused. + team = self._teamtype() + return team + + def add_player(self, sessionplayer: ba.SessionPlayer) -> None: + """(internal)""" + assert sessionplayer.team is not None + + sessionplayer.reset_input() + sessionteam = sessionplayer.team + assert sessionplayer in sessionteam.players + team = sessionteam.gameteam + assert team is not None + sessionplayer.set_activity(self) + with _ba.Context(self): + sessionplayer.gameplayer = player = self.create_player( + sessionplayer) + player.postinit(sessionplayer) + team.players.append(player) + self.players.append(player) + try: + self.on_player_join(player) + except Exception: + print_exception('Error in on_player_join for', self) + + def remove_player(self, sessionplayer: ba.SessionPlayer) -> None: + """(internal)""" + + # This should only be called on unexpired activities + # the player has been added to. + assert not self.expired + player = sessionplayer.gameplayer + assert isinstance(player, self._playertype) + assert player in self.players + + self.players.remove(player) + with _ba.Context(self): + # Make a decent attempt to persevere if user code breaks. + try: + self.on_player_leave(player) + except Exception: + print_exception(f'Error in on_player_leave for {self}') + try: + sessionplayer.reset() + sessionplayer.set_node(None) + sessionplayer.set_activity(None) + except Exception: + print_exception(f'Error resetting player for {self}') + + def add_team(self, sessionteam: ba.SessionTeam) -> None: + """(internal)""" + assert not self.expired + + with _ba.Context(self): + sessionteam.gameteam = team = self.create_team(sessionteam) + team.postinit(sessionteam) self.teams.append(team) try: - with _ba.Context(self): - self.on_team_join(team) + self.on_team_join(team) except Exception: - _error.print_exception('Error in on_team_join for', self) + print_exception(f'Error in on_team_join for {self}') - # Now add each player to the activity and to its team's list, - # and send player-joined messages for each. - for player in players: - self.players.append(player) - player.team.players.append(player) - player.set_activity(self) - pnode = self.create_player_node(player) - player.set_node(pnode) - try: - with _ba.Context(self): - self.on_player_join(player) - except Exception: - _error.print_exception('Error in on_player_join for', self) + def remove_team(self, sessionteam: ba.SessionTeam) -> None: + """(internal)""" + # This should only be called on unexpired activities the team has + # been added to. + assert not self.expired + assert sessionteam.gameteam is not None + assert sessionteam.gameteam in self.teams + + team = sessionteam.gameteam + assert isinstance(team, self._teamtype) + self.teams.remove(team) with _ba.Context(self): - # And finally tell the game to start. - self._has_begun = True - self.on_begin() + # Make a decent attempt to persevere if user code breaks. + try: + self.on_team_leave(team) + except Exception: + print_exception(f'Error in on_team_leave for {self}') + try: + sessionteam.reset_gamedata() + except Exception: + print_exception(f'Error in reset_gamedata for {self}') + sessionteam.gameteam = None - # Make sure that ba.Activity.on_transition_in() got called - # at some point. + def _sanity_check_begin_call(self) -> None: + # Make sure ba.Activity.on_transition_in() got called at some point. if not self._called_activity_on_transition_in: - _error.print_error( + print_error( 'ba.Activity.on_transition_in() never got called for ' + str(self) + '; did you forget to call it' ' in your on_transition_in override?') - # Make sure that ba.Activity.on_begin() got called at some point. if not self._called_activity_on_begin: - _error.print_error( + print_error( 'ba.Activity.on_begin() never got called for ' + str(self) + '; did you forget to call it in your on_begin override?') - # If the whole session wants to die and was waiting on us, can get - # that going now. + def begin(self, session: ba.Session) -> None: + """Begin the activity. + + (internal) + """ + + # Is this ever still happening?... + if self._has_begun: + print_error("_begin called twice; this shouldn't happen") + return + + # Inherit stats from the session. + self._stats = session.stats + + # Add session's teams in. + for team in session.teams: + self.add_team(team) + + # Add session's players in. + for player in session.players: + self.add_player(player) + + # And finally tell the game to start. + with _ba.Context(self): + self._has_begun = True + self.on_begin() + + self._sanity_check_begin_call() + + # If the whole session wants to die and was waiting on us, + # can kick off that process now. if session.wants_to_end: session.launch_end_session_activity() else: @@ -663,3 +778,30 @@ class Activity(DependencyComponent): if self._should_end_immediately: self.end(self._should_end_immediately_results, self._should_end_immediately_delay) + + # noinspection PyUnresolvedReferences + def _setup_player_and_team_types(self) -> None: + """Pull player and team types from our typing.Generic params.""" + + # TODO: There are proper calls for pulling these in Python 3.8; + # should update this code when we adopt that. + # NOTE: If we get Any as PlayerType or TeamType (generally due + # to no generic params being passed) we automatically use the + # base class types, but also warn the user since this will mean + # less type safety for that class. (its better to pass the base + # types explicitly vs. having them be Any) + if not TYPE_CHECKING: + self._playertype = type(self).__orig_bases__[-1].__args__[0] + if not isinstance(self._playertype, type): + self._playertype = Player + print(f'ERROR: {type(self)} was not passed a Player' + f' type argument; please explicitly pass ba.Player' + f' if you do not want to override it.') + self._teamtype = type(self).__orig_bases__[-1].__args__[1] + if not isinstance(self._teamtype, type): + self._teamtype = Team + print(f'ERROR: {type(self)} was not passed a Team' + f' type argument; please explicitly pass ba.Team' + f' if you do not want to override it.') + assert issubclass(self._playertype, Player) + assert issubclass(self._teamtype, Team) diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index 9e53b6a6..20986457 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -26,6 +26,9 @@ from typing import TYPE_CHECKING import _ba from ba._activity import Activity from ba._music import setmusic, MusicType +# False positive due to our class_generics_filter custom pylint filter. +from ba._player import Player # pylint: disable=W0611 +from ba._team import Team # pylint: disable=W0611 if TYPE_CHECKING: from typing import Any, Dict, Optional @@ -33,7 +36,7 @@ if TYPE_CHECKING: from ba._lobby import JoinInfo -class EndSessionActivity(Activity): +class EndSessionActivity(Activity[Player, Team]): """Special ba.Activity to fade out and end the current ba.Session.""" def __init__(self, settings: Dict[str, Any]): @@ -61,7 +64,7 @@ class EndSessionActivity(Activity): call_after_ad(Call(_ba.new_host_session, MainMenuSession)) -class JoinActivity(Activity): +class JoinActivity(Activity[Player, Team]): """Standard activity for waiting for players to join. It shows tips and other info and waits for all players to check ready. @@ -98,7 +101,7 @@ class JoinActivity(Activity): _ba.set_analytics_screen('Joining Screen') -class TransitionActivity(Activity): +class TransitionActivity(Activity[Player, Team]): """A simple overlay fade out/in. Useful as a bare minimum transition between two level based activities. @@ -131,7 +134,7 @@ class TransitionActivity(Activity): _ba.timer(0.1, self.end) -class ScoreScreenActivity(Activity): +class ScoreScreenActivity(Activity[Player, Team]): """A standard score screen that fades in and shows stuff for a while. After a specified delay, player input is assigned to end the activity. diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index d45ea744..cfffb64b 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -25,8 +25,8 @@ from __future__ import annotations import weakref from typing import TYPE_CHECKING, TypeVar -from ba._messages import DieMessage, DeathType, OutOfBoundsMessage -from ba import _error +from ba._messages import DieMessage, DeathType, OutOfBoundsMessage, UNHANDLED +from ba._error import print_error, print_exception, ActivityNotFoundError import _ba if TYPE_CHECKING: @@ -97,10 +97,10 @@ class Actor: # Non-expired Actors send themselves a DieMessage when going down. # That way we can treat DieMessage handling as the single # point-of-action for death. - if not self.is_expired(): + if not self.expired: self.handlemessage(DieMessage()) except Exception: - _error.print_exception('exception in ba.Actor.__del__() for', self) + print_exception('exception in ba.Actor.__del__() for', self) def handlemessage(self, msg: Any) -> Any: """General message handling; can be passed any message object.""" @@ -111,7 +111,7 @@ class Actor: if isinstance(msg, OutOfBoundsMessage): return self.handlemessage(DieMessage(how=DeathType.OUT_OF_BOUNDS)) - return _error.UNHANDLED + return UNHANDLED def autoretain(self: T) -> T: """Keep this Actor alive without needing to hold a reference to it. @@ -126,7 +126,7 @@ class Actor: """ activity = self._activity() if activity is None: - raise _error.ActivityNotFoundError() + raise ActivityNotFoundError() activity.retain_actor(self) return self @@ -144,13 +144,14 @@ class Actor: likely result in errors. """ - def is_expired(self) -> bool: - """Returns whether the Actor is expired. + @property + def expired(self) -> bool: + """Whether the Actor is expired. (see ba.Actor.on_expire()) """ activity = self.getactivity(doraise=False) - return True if activity is None else activity.is_expired() + return True if activity is None else activity.expired def exists(self) -> bool: """Returns whether the Actor is still present in a meaningful way. @@ -195,13 +196,12 @@ class Actor: avoided. """ if not __debug__: - _error.print_error('This should only be called in __debug__ mode.', - once=True) + print_error('This should only be called in __debug__ mode.', + once=True) if not getattr(self, '_root_actor_init_called', False): - _error.print_error('Root Actor __init__() not called.') - if self.is_expired(): - _error.print_error( - f'handlemessage() called on expired actor: {self}') + print_error('Root Actor __init__() not called.') + if self.expired: + print_error(f'handlemessage() called on expired actor: {self}') @property def activity(self) -> ba.Activity: @@ -211,7 +211,7 @@ class Actor: """ activity = self._activity() if activity is None: - raise _error.ActivityNotFoundError() + raise ActivityNotFoundError() return activity def getactivity(self, doraise: bool = True) -> Optional[ba.Activity]: @@ -222,5 +222,5 @@ class Actor: """ activity = self._activity() if activity is None and doraise: - raise _error.ActivityNotFoundError() + raise ActivityNotFoundError() return activity diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index e31ee809..ac9fb011 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -62,7 +62,7 @@ def run_cpu_benchmark() -> None: cfg['Graphics Quality'] = self._old_quality cfg.apply() - def on_player_request(self, player: ba.Player) -> bool: + def on_player_request(self, player: ba.SessionPlayer) -> bool: return False _ba.new_host_session(BenchmarkSession, benchmark_type='cpu') diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index bcad453d..89421b82 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -21,7 +21,7 @@ """Functionality related to co-op games.""" from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar import _ba from ba._gameactivity import GameActivity @@ -31,8 +31,11 @@ if TYPE_CHECKING: from bastd.actor.playerspaz import PlayerSpaz import ba +PlayerType = TypeVar('PlayerType', bound='ba.Player') +TeamType = TypeVar('TeamType', bound='ba.Team') -class CoopGameActivity(GameActivity): + +class CoopGameActivity(GameActivity[PlayerType, TeamType]): """Base class for cooperative-mode games. Category: Gameplay Classes @@ -187,7 +190,7 @@ class CoopGameActivity(GameActivity): vval -= 55 def spawn_player_spaz(self, - player: ba.Player, + player: PlayerType, position: Sequence[float] = (0.0, 0.0, 0.0), angle: float = None) -> PlayerSpaz: """Spawn and wire up a standard player spaz.""" diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index bcaa1ceb..b6c008ec 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -173,9 +173,9 @@ class CoopSession(Session): def get_custom_menu_entries(self) -> List[Dict[str, Any]]: return self._custom_menu_ui - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None: from ba._general import WeakCall - super().on_player_leave(player) + super().on_player_leave(sessionplayer) # If all our players leave we wanna quit out of the session. _ba.timer(2.0, WeakCall(self._end_session_if_empty)) @@ -213,7 +213,7 @@ class CoopSession(Session): from bastd.ui.tournamententry import TournamentEntryWindow from ba._gameactivity import GameActivity activity = self.getactivity() - if activity is not None and not activity.is_expired(): + if activity is not None and not activity.expired: assert self.tournament_id is not None assert isinstance(activity, GameActivity) TournamentEntryWindow(tournament_id=self.tournament_id, @@ -235,7 +235,7 @@ class CoopSession(Session): # This method may get called from the UI context so make sure we # explicitly run in the activity's context. activity = self.getactivity() - if activity is not None and not activity.is_expired(): + if activity is not None and not activity.expired: activity.can_show_ad_on_death = True with _ba.Context(activity): activity.end(results={'outcome': 'restart'}, force=True) diff --git a/assets/src/ba_data/python/ba/_error.py b/assets/src/ba_data/python/ba/_error.py index 5beb6936..2f54e07b 100644 --- a/assets/src/ba_data/python/ba/_error.py +++ b/assets/src/ba_data/python/ba/_error.py @@ -31,16 +31,6 @@ if TYPE_CHECKING: import ba -class _UnhandledType: - pass - - -# A special value that should be returned from handlemessage() -# functions for unhandled message types. This may result -# in fallback message types being attempted/etc. -UNHANDLED = _UnhandledType() - - class DependencyError(Exception): """Exception raised when one or more ba.Dependency items are missing. @@ -73,6 +63,13 @@ class PlayerNotFoundError(NotFoundError): """ +class SessionPlayerNotFoundError(NotFoundError): + """Exception raised when an expected ba.SessionPlayer does not exist. + + category: Exception Classes + """ + + class TeamNotFoundError(NotFoundError): """Exception raised when an expected ba.Team does not exist. @@ -80,6 +77,13 @@ class TeamNotFoundError(NotFoundError): """ +class SessionTeamNotFoundError(NotFoundError): + """Exception raised when an expected ba.SessionTeam does not exist. + + category: Exception Classes + """ + + class NodeNotFoundError(NotFoundError): """Exception raised when an expected ba.Node does not exist. diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index b3131c4e..869d2eb2 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -24,12 +24,12 @@ from __future__ import annotations import random -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar -import _ba from ba._activity import Activity from ba._score import ScoreInfo from ba._lang import Lstr +import _ba if TYPE_CHECKING: from typing import (List, Optional, Dict, Type, Any, Callable, Sequence, @@ -38,8 +38,11 @@ if TYPE_CHECKING: from bastd.actor.bomb import TNTSpawner import ba +PlayerType = TypeVar('PlayerType', bound='ba.Player') +TeamType = TypeVar('TeamType', bound='ba.Team') -class GameActivity(Activity): + +class GameActivity(Activity[PlayerType, TeamType]): """Common base class for all game ba.Activities. category: Gameplay Classes @@ -606,13 +609,13 @@ class GameActivity(Activity): self._setup_tournament_time_limit( max(5, data_t[0]['timeRemaining'])) - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: PlayerType) -> None: super().on_player_join(player) # By default, just spawn a dude. self.spawn_player(player) - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: PlayerType) -> None: from ba._general import Call from ba._messages import DieMessage, DeathType @@ -632,7 +635,7 @@ class GameActivity(Activity): from bastd.actor.playerspaz import PlayerSpazDeathMessage if isinstance(msg, PlayerSpazDeathMessage): - player = msg.spaz.player + player = msg.getspaz(self).player killer = msg.killerplayer # Inform our score-set of the demise. @@ -642,7 +645,7 @@ class GameActivity(Activity): # Award the killer points if he's on a different team. if killer and killer.team is not player.team: - pts, importance = msg.spaz.get_death_points(msg.how) + pts, importance = msg.getspaz(self).get_death_points(msg.how) if not self.has_ended(): self.stats.player_scored(killer, pts, @@ -928,7 +931,7 @@ class GameActivity(Activity): print('WARNING: default end_game() implementation called;' ' your game should override this.') - def spawn_player_if_exists(self, player: ba.Player) -> None: + def spawn_player_if_exists(self, player: PlayerType) -> None: """ A utility method which calls self.spawn_player() *only* if the ba.Player provided still exists; handy for use in timers and whatnot. @@ -938,7 +941,7 @@ class GameActivity(Activity): if player: self.spawn_player(player) - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: PlayerType) -> ba.Actor: """Spawn *something* for the provided ba.Player. The default implementation simply calls spawn_player_spaz(). @@ -949,7 +952,7 @@ class GameActivity(Activity): return self.spawn_player_spaz(player) def respawn_player(self, - player: ba.Player, + player: PlayerType, respawn_time: Optional[float] = None) -> None: """ Given a ba.Player, sets up a standard respawn timer, @@ -989,7 +992,7 @@ class GameActivity(Activity): player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) def spawn_player_spaz(self, - player: ba.Player, + player: PlayerType, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz: """Create and wire up a ba.PlayerSpaz for the provided ba.Player.""" diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index d4fe7147..9376cf69 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -26,9 +26,11 @@ import weakref from dataclasses import dataclass from typing import TYPE_CHECKING +from ba._team import Team + if TYPE_CHECKING: from weakref import ReferenceType - from typing import Sequence, Tuple, Any, Optional, Dict, List + from typing import Sequence, Tuple, Any, Optional, Dict, List, Union import ba @@ -36,7 +38,7 @@ if TYPE_CHECKING: class WinnerGroup: """Entry for a winning team or teams calculated by game-results.""" score: Optional[int] - teams: Sequence[ba.Team] + teams: Sequence[ba.SessionTeam] class TeamGameResults: @@ -52,9 +54,9 @@ class TeamGameResults: def __init__(self) -> None: """Instantiate a results instance.""" self._game_set = False - self._scores: Dict[int, Tuple[ReferenceType[ba.Team], + self._scores: Dict[int, Tuple[ReferenceType[ba.SessionTeam], Optional[int]]] = {} - self._teams: Optional[List[ReferenceType[ba.Team]]] = None + self._teams: Optional[List[ReferenceType[ba.SessionTeam]]] = None self._player_info: Optional[List[Dict[str, Any]]] = None self._lower_is_better: Optional[bool] = None self._score_label: Optional[str] = None @@ -74,16 +76,22 @@ class TeamGameResults: self._none_is_winner = score_info.none_is_winner self._score_type = score_info.scoretype - def set_team_score(self, team: ba.Team, score: int) -> None: + def set_team_score(self, team: Union[ba.SessionTeam, ba.Team], + score: int) -> None: """Set the score for a given ba.Team. This can be a number or None. (see the none_is_winner arg in the constructor) """ - self._scores[team.get_id()] = (weakref.ref(team), score) + if isinstance(team, Team): + team = team.sessionteam + self._scores[team.id] = (weakref.ref(team), score) - def get_team_score(self, team: ba.Team) -> Optional[int]: + def get_team_score(self, team: Union[ba.SessionTeam, + ba.Team]) -> Optional[int]: """Return the score for a given team.""" + if isinstance(team, Team): + team = team.sessionteam for score in list(self._scores.values()): if score[0]() is team: return score[1] @@ -91,8 +99,8 @@ class TeamGameResults: # If we have no score value, assume None. return None - def get_teams(self) -> List[ba.Team]: - """Return all ba.Teams in the results.""" + def get_teams(self) -> List[ba.SessionTeam]: + """Return all ba.SessionTeams in the results.""" if not self._game_set: raise RuntimeError("Can't get teams until game is set.") teams = [] @@ -103,12 +111,9 @@ class TeamGameResults: teams.append(team) return teams - def has_score_for_team(self, team: ba.Team) -> bool: + def has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool: """Return whether there is a score for a given team.""" - for score in list(self._scores.values()): - if score[0]() is team: - return True - return False + return any(s[0]() is sessionteam for s in self._scores.values()) def get_team_score_str(self, team: ba.Team) -> ba.Lstr: """Return the score for the given ba.Team as an Lstr. @@ -122,7 +127,7 @@ class TeamGameResults: if not self._game_set: raise RuntimeError("Can't get team-score-str until game is set.") for score in list(self._scores.values()): - if score[0]() is team: + if score[0]() is team.sessionteam: if score[1] is None: return Lstr(value='-') if self._score_type is ScoreType.SECONDS: @@ -164,7 +169,7 @@ class TeamGameResults: assert self._lower_is_better is not None return self._lower_is_better - def get_winning_team(self) -> Optional[ba.Team]: + def get_winning_team(self) -> Optional[ba.SessionTeam]: """Get the winning ba.Team if there is exactly one; None otherwise.""" if not self._game_set: raise RuntimeError("Can't get winners until game is set.") @@ -179,7 +184,7 @@ class TeamGameResults: raise RuntimeError("Can't get winners until game is set.") # Group by best scoring teams. - winners: Dict[int, List[ba.Team]] = {} + winners: Dict[int, List[ba.SessionTeam]] = {} scores = [ score for score in self._scores.values() if score[0]() is not None and score[1] is not None @@ -191,11 +196,11 @@ class TeamGameResults: assert team is not None sval.append(team) results: List[Tuple[Optional[int], - List[ba.Team]]] = list(winners.items()) + List[ba.SessionTeam]]] = list(winners.items()) results.sort(reverse=not self._lower_is_better, key=lambda x: x[0]) # Also group the 'None' scores. - none_teams: List[ba.Team] = [] + none_teams: List[ba.SessionTeam] = [] for score in self._scores.values(): scoreteam = score[0]() if scoreteam is not None and score[1] is None: @@ -205,7 +210,7 @@ class TeamGameResults: # depending on the rules). if none_teams: nones: List[Tuple[Optional[int], - List[ba.Team]]] = [(None, none_teams)] + List[ba.SessionTeam]]] = [(None, none_teams)] if self._none_is_winner: results = nones + results else: diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 73945d5d..ed61f77d 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -29,7 +29,7 @@ import _ba if TYPE_CHECKING: from typing import Any, Type - from efro.call import Call + from efro.call import Call as Call # 'as Call' so we re-export. T = TypeVar('T') diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index fdafedd7..7c1d2c3c 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -36,7 +36,7 @@ from typing import TYPE_CHECKING import _ba if TYPE_CHECKING: - from typing import List, Sequence, Optional + from typing import List, Sequence, Optional, Dict, Any import ba @@ -346,3 +346,13 @@ def local_chat_message(msg: str) -> None: def handle_remote_achievement_list(completed_achievements: List[str]) -> None: from ba import _achievement _achievement.set_completed_achievements(completed_achievements) + + +def get_player_icon(sessionplayer: ba.SessionPlayer) -> Dict[str, Any]: + info = sessionplayer.get_icon_info() + return { + 'texture': _ba.gettexture(info['texture']), + 'tint_texture': _ba.gettexture(info['tint_texture']), + 'tint_color': info['tint_color'], + 'tint2_color': info['tint2_color'] + } diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index adf525a2..198338e7 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -36,6 +36,7 @@ if TYPE_CHECKING: MAX_QUICK_CHANGE_COUNT = 30 QUICK_CHANGE_INTERVAL = 0.05 +QUICK_CHANGE_RESET_INTERVAL = 1.0 # Hmm should we move this to actors?.. @@ -147,7 +148,7 @@ class Chooser: if self._text_node: self._text_node.delete() - def __init__(self, vpos: float, player: _ba.Player, + def __init__(self, vpos: float, player: _ba.SessionPlayer, lobby: 'Lobby') -> None: # FIXME: Tidy up around here. # pylint: disable=too-many-branches @@ -326,7 +327,7 @@ class Chooser: self._inited = True @property - def player(self) -> ba.Player: + def player(self) -> ba.SessionPlayer: """The ba.Player associated with this chooser.""" return self._player @@ -343,7 +344,7 @@ class Chooser: """(internal)""" self._dead = val - def get_team(self) -> ba.Team: + def get_team(self) -> ba.SessionTeam: """Return this chooser's selected ba.Team.""" return self.lobby.teams[self._selected_team_index] @@ -641,18 +642,17 @@ class Chooser: # choosers that have been marked as ready. team_player_counts = {} for team in teams: - team_player_counts[team.get_id()] = (len(team.players)) + team_player_counts[team.id] = (len(team.players)) for chooser in lobby.choosers: if chooser.ready: - team_player_counts[ - chooser.get_team().get_id()] += 1 + team_player_counts[chooser.get_team().id] += 1 largest_team_size = max(team_player_counts.values()) smallest_team_size = (min(team_player_counts.values())) # Force switch if we're on the biggest team # and there's a smaller one available. if (largest_team_size != smallest_team_size - and team_player_counts[self.get_team().get_id()] >= + and team_player_counts[self.get_team().id] >= largest_team_size): force_team_switch = True @@ -664,17 +664,24 @@ class Chooser: _ba.playsound(self._punchsound) self._set_ready(ready) - def handlemessage(self, msg: Any) -> Any: - """Standard generic message handler.""" - if isinstance(msg, ChangeMessage): - now = _ba.time() - count = self.last_change[1] + 1 - if (now - self.last_change[0] < QUICK_CHANGE_INTERVAL - and count > MAX_QUICK_CHANGE_COUNT): - # Hmm maybe we should notify client? + # TODO: should handle this at the engine layer so this is unnecessary. + def _handle_repeat_message_attack(self) -> None: + now = _ba.time() + count = self.last_change[1] + if now - self.last_change[0] < QUICK_CHANGE_INTERVAL: + count += 1 + if count > MAX_QUICK_CHANGE_COUNT: _ba.disconnect_client( self._player.get_input_device().client_id) - self.last_change = (now, count) + elif now - self.last_change[0] > QUICK_CHANGE_RESET_INTERVAL: + count = 0 + self.last_change = (now, count) + + def handlemessage(self, msg: Any) -> Any: + """Standard generic message handler.""" + + if isinstance(msg, ChangeMessage): + self._handle_repeat_message_attack() # If we've been removed from the lobby, ignore this stuff. if self._dead: @@ -806,7 +813,7 @@ class Chooser: highlight[(max_index + 2) % 3] += diff * 0.2 return highlight - def getplayer(self) -> ba.Player: + def getplayer(self) -> ba.SessionPlayer: """Return the player associated with this chooser.""" return self._player @@ -890,7 +897,7 @@ class Lobby: if teams is not None: self._teams = [weakref.ref(team) for team in teams] else: - self._dummy_teams = bs_team.Team() + self._dummy_teams = bs_team.SessionTeam() self._teams = [weakref.ref(self._dummy_teams)] v_offset = (-150 if isinstance(session, _coopsession.CoopSession) else -50) @@ -920,7 +927,7 @@ class Lobby: return self._use_team_colors @property - def teams(self) -> List[ba.Team]: + def teams(self) -> List[ba.SessionTeam]: """Teams available in this lobby.""" allteams = [] for tref in self._teams: @@ -974,14 +981,14 @@ class Lobby: """Return whether all choosers are marked ready.""" return all(chooser.ready for chooser in self.choosers) - def add_chooser(self, player: ba.Player) -> None: + def add_chooser(self, player: ba.SessionPlayer) -> None: """Add a chooser to the lobby for the provided player.""" self.choosers.append( Chooser(vpos=self._vpos, player=player, lobby=self)) self._next_add_team = (self._next_add_team + 1) % len(self._teams) self._vpos -= 48 - def remove_chooser(self, player: ba.Player) -> None: + def remove_chooser(self, player: ba.SessionPlayer) -> None: """Remove a single player's chooser; does not kick him. This is used when a player enters the game and no longer diff --git a/assets/src/ba_data/python/ba/_messages.py b/assets/src/ba_data/python/ba/_messages.py index 9ac55859..eb0fda5a 100644 --- a/assets/src/ba_data/python/ba/_messages.py +++ b/assets/src/ba_data/python/ba/_messages.py @@ -33,6 +33,16 @@ if TYPE_CHECKING: import ba +class _UnhandledType: + pass + + +# A special value that should be returned from handlemessage() +# functions for unhandled message types. This may result +# in fallback message types being attempted/etc. +UNHANDLED = _UnhandledType() + + @dataclass class OutOfBoundsMessage: """A message telling an object that it is out of bounds. diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index e94815f2..84097208 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -27,6 +27,7 @@ from typing import TYPE_CHECKING import _ba from ba._session import Session +from ba._error import NotFoundError, print_error if TYPE_CHECKING: from typing import Optional, Any, Dict, List, Type, Sequence @@ -155,7 +156,7 @@ class MultiTeamSession(Session): """Returns which game in the series is currently being played.""" return self._game_number - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: ba.SessionTeam) -> None: team.sessiondata['previous_score'] = team.sessiondata['score'] = 0 def get_max_players(self) -> int: @@ -171,7 +172,6 @@ class MultiTeamSession(Session): def on_activity_end(self, activity: ba.Activity, results: Any) -> None: # pylint: disable=cyclic-import - from ba import _error from bastd.tutorial import TutorialActivity from bastd.activity.multiteamvictory import ( TeamSeriesVictoryScoreScreenActivity) @@ -223,7 +223,7 @@ class MultiTeamSession(Session): # (ie: no longer sitting in the lobby). try: has_team = (player.team is not None) - except _error.TeamNotFoundError: + except NotFoundError: has_team = False if has_team: self.stats.register_player(player) @@ -238,9 +238,8 @@ class MultiTeamSession(Session): def _switch_to_score_screen(self, results: Any) -> None: """Switch to a score screen after leaving a round.""" - from ba import _error del results # Unused arg. - _error.print_error('this should be overridden') + print_error('this should be overridden') def announce_game_results(self, activity: ba.GameActivity, @@ -269,7 +268,8 @@ class MultiTeamSession(Session): if winning_team is not None: # Have all players celebrate. celebrate_msg = CelebrateMessage(duration=10.0) - for player in winning_team.players: + assert winning_team.gameteam is not None + for player in winning_team.gameteam.players: if player.actor: player.actor.handlemessage(celebrate_msg) cameraflash() diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index 1f290972..afeffd15 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -94,7 +94,7 @@ class ServerCallThread(threading.Thread): # this check manually? if self._activity is not None: activity = self._activity() - if activity is None or activity.is_expired(): + if activity is None or activity.expired: return # Technically we could do the same check for session contexts, diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 9d3100d1..2779717c 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -20,35 +20,178 @@ # ----------------------------------------------------------------------------- """Player related functionality.""" from __future__ import annotations -from typing import TYPE_CHECKING, TypeVar + +from typing import TYPE_CHECKING, TypeVar, Generic if TYPE_CHECKING: - from typing import Type + from typing import (Type, Optional, Sequence, Dict, Any, Union, Tuple, + Callable) import ba -T = TypeVar('T') +TeamType = TypeVar('TeamType', bound='ba.Team') -class BasePlayerData: - """Base class for custom player data. +class Player(Generic[TeamType]): + """Testing.""" - Category: Gameplay Classes + # Defining these types at the class level instead of in __init__ so + # that types are introspectable (these are still instance attrs). + team: TeamType + character: str + actor: Optional[ba.Actor] + color: Sequence[float] + highlight: Sequence[float] + _sessionplayer: ba.SessionPlayer + _nodeactor: Optional[ba.NodeActor] - A convenience class that can be used as a base class for custom - per-game player data. It simply provides the ability to easily fetch - an instance of itself for a given ba.Player. - """ + # Should aim to kill this eventually (at least gamedata). + # Game-specific data can be tacked on to the per-game player class. + sessiondata: Dict + gamedata: Dict - @classmethod - def get(cls: Type[T], player: ba.Player) -> T: - """Return the custom player data associated with a player. + # NOTE: avoiding having any __init__() here since it seems to not + # get called by default if a dataclass inherits from us. - If one does not exist, it will be created. + def postinit(self, sessionplayer: ba.SessionPlayer) -> None: + """Wire up a newly created player. + + (internal) """ + from ba._nodeactor import NodeActor + import _ba + self.actor = None + self.character = '' + self._nodeactor: Optional[ba.NodeActor] = None + self._sessionplayer = sessionplayer + self.character = sessionplayer.character + self.color = sessionplayer.color + self.highlight = sessionplayer.highlight + self.team = sessionplayer.team.gameteam # type: ignore + assert self.team is not None + self.sessiondata = sessionplayer.sessiondata + self.gamedata = sessionplayer.gamedata - # Store/return an instance of ourself in the player's per-game dict. - data = player.gamedata.get('playerdata') - if data is None: - player.gamedata['playerdata'] = data = cls() - assert isinstance(data, cls) - return data + # Create our player node in the current activity. + node = _ba.newnode('player', attrs={'playerID': sessionplayer.id}) + self._nodeactor = NodeActor(node) + sessionplayer.set_node(node) + + @property + def sessionplayer(self) -> ba.SessionPlayer: + """Return the ba.SessionPlayer corresponding to this Player. + + Throws a ba.SessionPlayerNotFoundError if it does not exist. + """ + if bool(self._sessionplayer): + return self._sessionplayer + from ba import _error + raise _error.SessionPlayerNotFoundError() + + @property + def node(self) -> ba.Node: + """A ba.Node of type 'player' associated with this Player. + + This node can be used to get a generic player position/etc. + """ + if not self._nodeactor: + from ba import _error + raise _error.NodeNotFoundError + return self._nodeactor.node + + @property + def exists(self) -> bool: + """Whether the player still exists. + + Most functionality will fail on a nonexistent player. + Note that you can also use the boolean operator for this same + functionality, so a statement such as "if player" will do + the right thing both for Player objects and values of None. + """ + return bool(self._sessionplayer) + + def get_name(self, full: bool = False, icon: bool = True) -> str: + """get_name(full: bool = False, icon: bool = True) -> str + + Returns the player's name. If icon is True, the long version of the + name may include an icon. + """ + return self._sessionplayer.get_name(full=full, icon=icon) + + def set_actor(self, actor: Optional[ba.Actor]) -> None: + """set_actor(actor: Optional[ba.Actor]) -> None + + Set the player's associated ba.Actor. + """ + self.actor = actor + + def is_alive(self) -> bool: + """is_alive() -> bool + + Returns True if the player has a ba.Actor assigned and its + is_alive() method return True. False is returned otherwise. + """ + return self.actor is not None and self.actor.is_alive() + + def get_icon(self) -> Dict[str, Any]: + """get_icon() -> Dict[str, Any] + + Returns the character's icon (images, colors, etc contained in a dict) + """ + return self._sessionplayer.get_icon() + + def assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], + call: Callable) -> None: + """assign_input_call(type: Union[str, Tuple[str, ...]], + call: Callable) -> None + + Set the python callable to be run for one or more types of input. + Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', + 'punchRelease','bombPress', 'bombRelease', 'pickUpPress', + 'pickUpRelease', 'upDown','leftRight','upPress', 'upRelease', + 'downPress', 'downRelease', 'leftPress','leftRelease','rightPress', + 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', + 'startRelease' + """ + return self._sessionplayer.assign_input_call(type=inputtype, call=call) + + def reset_input(self) -> None: + """reset_input() -> None + + Clears out the player's assigned input actions. + """ + self._sessionplayer.reset_input() + + def __bool__(self) -> bool: + return bool(self._sessionplayer) + + +PlayerType = TypeVar('PlayerType', bound='ba.Player') + + +def playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType: + """Cast a ba.Player to a specific ba.Player subclass. + + Category: Gameplay Functions + + When writing type-checked code, sometimes code will deal with raw + ba.Player objects which need to be cast back to the game's actual + player type so that access can be properly type-checked. This function + is a safe way to do so. It ensures that Optional values are not cast + into Non-Optional, etc. + """ + assert isinstance(player, totype) + return player + + +# NOTE: ideally we should have a single playercast() call and use overloads +# for the optional variety, but that currently seems to not be working. +# See: https://github.com/python/mypy/issues/8800 +def playercast_o(totype: Type[PlayerType], + player: Optional[ba.Player]) -> Optional[PlayerType]: + """A variant of ba.playercast() for use with optional ba.Player values. + + Category: Gameplay Functions + """ + # noinspection PyTypeHints + assert isinstance(player, (totype, type(None))) + return player diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 1a5c4a7d..dbb47fd8 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -25,11 +25,12 @@ import weakref from typing import TYPE_CHECKING import _ba +from ba._error import print_error, print_exception +from ba._lang import Lstr +from ba._player import Player if TYPE_CHECKING: - from weakref import ReferenceType from typing import Sequence, List, Dict, Any, Optional, Set - import ba @@ -81,8 +82,8 @@ class Session: lobby: ba.Lobby max_players: int min_players: int - players: List[ba.Player] - teams: List[ba.Team] + players: List[ba.SessionPlayer] + teams: List[ba.SessionTeam] def __init__(self, depsets: Sequence[ba.DependencySet], @@ -104,9 +105,11 @@ class Session: from ba._stats import Stats from ba._gameutils import sharedobj from ba._gameactivity import GameActivity - from ba._team import Team + from ba._activity import Activity + from ba._team import SessionTeam from ba._error import DependencyError from ba._dependency import Dependency, AssetPackage + from efro.util import empty_weakref # First off, resolve all dependency-sets we were passed. # If things are missing, we'll try to gather them into a single @@ -143,21 +146,12 @@ class Session: # print('Would set host-session asset-reqs to:', # required_asset_packages) - # First thing, wire up our internal engine data. + # Stuff in this section should be removed from this class if possible. self._sessiondata = _ba.register_session(self) - self.tournament_id: Optional[str] = None - - # FIXME: This stuff shouldn't be here. self.sharedobjs: Dict[str, Any] = {} - - # TeamGameActivity uses this to display a help overlay on the first - # activity only. self.have_shown_controls_help_overlay = False - self.campaign = None - - # FIXME: Should be able to kill this I think. self.campaign_state: Dict[str, str] = {} self._use_teams = (team_names is not None) @@ -171,13 +165,7 @@ class Session: self._activity_retained: Optional[ba.Activity] = None self.launch_end_session_activity_time: Optional[float] = None self._activity_end_timer: Optional[ba.Timer] = None - - # Hacky way to create empty weak ref; must be a better way. - class _EmptyObj: - pass - - self._activity_weak: ReferenceType[ba.Activity] - self._activity_weak = weakref.ref(_EmptyObj()) # type: ignore + self._activity_weak = empty_weakref(Activity) if self._activity_weak() is not None: raise Exception('Error creating empty activity weak ref.') @@ -192,10 +180,10 @@ class Session: assert team_names is not None assert team_colors is not None for i, color in enumerate(team_colors): - team = Team(team_id=self._next_team_id, - name=GameActivity.get_team_display_string( - team_names[i]), - color=color) + team = SessionTeam(team_id=self._next_team_id, + name=GameActivity.get_team_display_string( + team_names[i]), + color=color) self.teams.append(team) self._next_team_id += 1 @@ -203,15 +191,12 @@ class Session: with _ba.Context(self): self.on_team_join(team) except Exception: - from ba import _error - _error.print_exception( - f'Error in on_team_join for {self}.') + print_exception(f'Error in on_team_join for {self}.') self.lobby = Lobby() self.stats = Stats() - # Instantiate our session globals node - # (so it can apply default settings). + # Instantiate our session globals node which will apply its settings. sharedobj('globals') @property @@ -224,12 +209,11 @@ class Session: """(internal)""" return self._use_team_colors - def on_player_request(self, player: ba.Player) -> bool: + def on_player_request(self, player: ba.SessionPlayer) -> bool: """Called when a new ba.Player wants to join the Session. This should return True or False to accept/reject. """ - from ba._lang import Lstr # Limit player counts *unless* we're in a stress test. if _ba.app.stress_test_reset_timer is None: @@ -250,144 +234,88 @@ class Session: _ba.playsound(_ba.getsound('dripity')) return True - def on_player_leave(self, player: ba.Player) -> None: - """Called when a previously-accepted ba.Player leaves the session.""" - # pylint: disable=too-many-statements + def on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None: + """Called when a previously-accepted ba.SessionPlayer leaves.""" # pylint: disable=too-many-branches - # pylint: disable=cyclic-import - from ba._freeforallsession import FreeForAllSession - from ba._lang import Lstr - from ba import _error - # Remove them from the game rosters. - if player in self.players: - - _ba.playsound(_ba.getsound('playerLeft')) - - team: Optional[ba.Team] - - # The player will have no team if they are still in the lobby. - try: - team = player.team - except _error.TeamNotFoundError: - team = None - - activity = self._activity_weak() - - # If he had no team, he's in the lobby. - # If we have a current activity with a lobby, ask them to - # remove him. - if team is None: - with _ba.Context(self): - try: - self.lobby.remove_chooser(player) - except Exception: - _error.print_exception( - 'Error in Lobby.remove_chooser()') - - # *If* they were actually in the game, announce their departure. - if team is not None: - _ba.screenmessage( - Lstr(resource='playerLeftText', - subs=[('${PLAYER}', player.get_name(full=True))])) - - # Remove him from his team and session lists. - # (he may not be on the team list since player are re-added to - # team lists every activity) - if team is not None and player in team.players: - - # Testing; can remove this eventually. - if isinstance(self, FreeForAllSession): - if len(team.players) != 1: - _error.print_error('expected 1 player in FFA team') - team.players.remove(player) - - # Remove player from any current activity. - if activity is not None and player in activity.players: - activity.players.remove(player) - - # Run the activity callback unless its been expired. - if not activity.is_expired(): - try: - with _ba.Context(activity): - activity.on_player_leave(player) - except Exception: - _error.print_exception( - 'exception in on_player_leave for activity', - activity) - else: - _error.print_error('expired activity in on_player_leave;' - " shouldn't happen") - - player.set_activity(None) - player.set_node(None) - - # Reset the player; this will remove its actor-ref and clear - # its calls/etc - try: - with _ba.Context(activity): - player.reset() - except Exception: - _error.print_exception( - 'exception in player.reset in' - ' on_player_leave for player', player) - - # If we're a non-team session, remove the player's team completely. - if not self._use_teams and team is not None: - - # If the team's in an activity, call its on_team_leave - # callback. - if activity is not None and team in activity.teams: - activity.teams.remove(team) - - if not activity.is_expired(): - try: - with _ba.Context(activity): - activity.on_team_leave(team) - except Exception: - _error.print_exception( - 'exception in on_team_leave for activity', - activity) - else: - _error.print_error( - 'expired activity in on_player_leave p2' - "; shouldn't happen") - - # Clear the team's game-data (so dying stuff will - # have proper context). - try: - with _ba.Context(activity): - team.reset_gamedata() - except Exception: - _error.print_exception( - 'exception clearing gamedata for team:', team, - 'for player:', player, 'in activity:', activity) - - # Remove the team from the session. - self.teams.remove(team) - try: - with _ba.Context(self): - self.on_team_leave(team) - except Exception: - _error.print_exception( - 'exception in on_team_leave for session', self) - - # Clear the team's session-data (so dying stuff will - # have proper context). - try: - with _ba.Context(self): - team.reset_sessiondata() - except Exception: - _error.print_exception( - 'exception clearing sessiondata for team:', team, - 'in session:', self) - - # Now remove them from the session list. - self.players.remove(player) - - else: + if sessionplayer not in self.players: print('ERROR: Session.on_player_leave called' ' for player not in our list.') + return + + _ba.playsound(_ba.getsound('playerLeft')) + + activity = self._activity_weak() + + if not sessionplayer.in_game: + # Ok, the player's still in the lobby. Simply remove them from it. + with _ba.Context(self): + try: + self.lobby.remove_chooser(sessionplayer) + except Exception: + print_exception('Error in Lobby.remove_chooser().') + else: + # Ok, they've already entered the game. Remove them from + # teams/activities/etc. + sessionteam = sessionplayer.team + assert sessionteam is not None + assert sessionplayer in sessionteam.players + + _ba.screenmessage( + Lstr(resource='playerLeftText', + subs=[('${PLAYER}', sessionplayer.get_name(full=True))])) + + # Remove them from their SessionTeam. + if sessionplayer in sessionteam.players: + sessionteam.players.remove(sessionplayer) + else: + print('SessionPlayer not found in SessionTeam' + ' in on_player_leave.') + + # Grab their activity-specific player instance. + player = sessionplayer.gameplayer + assert isinstance(player, (Player, type(None))) + + # Remove them from any current Activity. + if activity is not None: + if player in activity.players: + activity.remove_player(sessionplayer) + else: + print('Player not found in Activity in on_player_leave.') + + # If we're a non-team session, remove their team too. + if not self._use_teams: + + # They should have been the only one on their team. + assert not sessionteam.players + + # Remove their Team from the Activity. + if activity is not None: + if sessionteam.gameteam in activity.teams: + activity.remove_team(sessionteam) + else: + print('Team not found in Activity in on_player_leave.') + + # And then from the Session. + with _ba.Context(self): + if sessionteam in self.teams: + try: + self.teams.remove(sessionteam) + self.on_team_leave(sessionteam) + except Exception: + print_exception( + f'Error in on_team_leave for Session {self}.') + else: + print('Team no in Session teams in on_player_leave.') + try: + sessionteam.reset_sessiondata() + except Exception: + print_exception( + f'Error clearing sessiondata' + f' for team {sessionteam} in session {self}.') + + # Now remove them from the session list. + self.players.remove(sessionplayer) def end(self) -> None: """Initiates an end to the session and a return to the main menu. @@ -401,7 +329,6 @@ class Session: def launch_end_session_activity(self) -> None: """(internal)""" - from ba import _error from ba._activitytypes import EndSessionActivity from ba._enums import TimeType with _ba.Context(self): @@ -412,18 +339,18 @@ class Session: since_last = (curtime - self.launch_end_session_activity_time) if since_last < 30.0: return - _error.print_error( + print_error( 'launch_end_session_activity called twice (since_last=' + str(since_last) + ')') self.launch_end_session_activity_time = curtime self.set_activity(_ba.new_activity(EndSessionActivity)) self.wants_to_end = False - self._ending = True # Prevent further activity-mucking. + self._ending = True # Prevent further actions. - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: ba.SessionTeam) -> None: """Called when a new ba.Team joins the session.""" - def on_team_leave(self, team: ba.Team) -> None: + def on_team_leave(self, team: ba.SessionTeam) -> None: """Called when a ba.Team is leaving the session.""" def _complete_end_activity(self, activity: ba.Activity, @@ -433,10 +360,8 @@ class Session: with _ba.Context(self): self.on_activity_end(activity, results) except Exception: - from ba import _error - _error.print_exception( - 'exception in on_activity_end() for session', self, 'activity', - activity, 'with results', results) + print_exception('exception in on_activity_end() for session', self, + 'activity', activity, 'with results', results) def end_activity(self, activity: ba.Activity, results: Any, delay: float, force: bool) -> None: @@ -473,8 +398,7 @@ class Session: def handlemessage(self, msg: Any) -> Any: """General message handling; can be passed any message object.""" from ba._lobby import PlayerReadyMessage - from ba._error import UNHANDLED - from ba._messages import PlayerProfilesChangedMessage + from ba._messages import PlayerProfilesChangedMessage, UNHANDLED if isinstance(msg, PlayerReadyMessage): self._on_player_ready(msg.chooser) return None @@ -496,84 +420,46 @@ class Session: (on_transition_in, etc) to get it. (so you can't do session.set_activity(foo) and then ba.newnode() to add a node to foo) """ - # pylint: disable=too-many-statements - # pylint: disable=too-many-branches - from ba import _error from ba._gameutils import sharedobj from ba._enums import TimeType # Sanity test: make sure this doesn't get called recursively. if self._in_set_activity: - raise Exception( + raise RuntimeError( 'Session.set_activity() cannot be called recursively.') + self._in_set_activity = True if activity.session is not _ba.getsession(): - raise Exception("Provided Activity's Session is not current.") + raise RuntimeError("Provided Activity's Session is not current.") # Quietly ignore this if the whole session is going down. if self._ending: return if activity is self._activity_retained: - _error.print_error('activity set to already-current activity') + print_error('activity set to already-current activity') return if self._next_activity is not None: - raise Exception('Activity switch already in progress (to ' + - str(self._next_activity) + ')') - - self._in_set_activity = True + raise RuntimeError('Activity switch already in progress (to ' + + str(self._next_activity) + ')') prev_activity = self._activity_retained - if prev_activity is not None: with _ba.Context(prev_activity): - gprev = sharedobj('globals') + prev_globals = sharedobj('globals') else: - gprev = None + prev_globals = None - with _ba.Context(activity): - - # Now that it's going to be front and center, - # set some global values based on what the activity wants. - glb = sharedobj('globals') - glb.use_fixed_vr_overlay = activity.use_fixed_vr_overlay - glb.allow_kick_idle_players = activity.allow_kick_idle_players - if activity.inherits_slow_motion and gprev is not None: - glb.slow_motion = gprev.slow_motion - else: - glb.slow_motion = activity.slow_motion - if activity.inherits_music and gprev is not None: - glb.music_continuous = True # Prevent restarting same music. - glb.music = gprev.music - glb.music_count += 1 - if activity.inherits_camera_vr_offset and gprev is not None: - glb.vr_camera_offset = gprev.vr_camera_offset - if activity.inherits_vr_overlay_center and gprev is not None: - glb.vr_overlay_center = gprev.vr_overlay_center - glb.vr_overlay_center_enabled = gprev.vr_overlay_center_enabled - - # If they want to inherit tint from the previous activity. - if activity.inherits_tint and gprev is not None: - glb.tint = gprev.tint - glb.vignette_outer = gprev.vignette_outer - glb.vignette_inner = gprev.vignette_inner - - # Let the activity do its thing. - activity.start_transition_in() + # Let the activity do its thing. + activity.transition_in(prev_globals) self._next_activity = activity # If we have a current activity, tell it it's transitioning out; # the next one will become current once this one dies. if prev_activity is not None: - # pylint: disable=protected-access - prev_activity._transitioning_out = True - # pylint: enable=protected-access - - # Activity will be None until the next one begins. - with _ba.Context(prev_activity): - prev_activity.on_transition_out() + prev_activity.transition_out() # Setting this to None should free up the old activity to die, # which will call begin_next_activity. @@ -586,35 +472,15 @@ class Session: else: self.begin_next_activity() - # Tell the C layer that this new activity is now 'foregrounded'. - # This means that its globals node controls global stuff and stuff - # like console operations, keyboard shortcuts, etc will run in it. - # pylint: disable=protected-access - # noinspection PyProtectedMember - activity._activity_data.make_foreground() - # pylint: enable=protected-access - - # We want to call _destroy() for the previous activity once it should - # tear itself down, clear out any self-refs, etc. If the new activity - # has a transition-time, set it up to be called after that passes; - # otherwise call it immediately. After this call the activity should - # have no refs left to it and should die (which will trigger the next - # activity to run). + # We want to call destroy() for the previous activity once it should + # tear itself down, clear out any self-refs, etc. After this call + # the activity should have no refs left to it and should die (which + # will trigger the next activity to run). if prev_activity is not None: - if activity.transition_time > 0.0: - # FIXME: We should tweak the activity to not allow - # node-creation/etc when we call _destroy (or after). - with _ba.Context('ui'): - # pylint: disable=protected-access - # noinspection PyProtectedMember - _ba.timer(activity.transition_time, - prev_activity._destroy, - timetype=TimeType.REAL) - - # Just run immediately. - else: - # noinspection PyProtectedMember - prev_activity._destroy() # pylint: disable=protected-access + with _ba.Context('ui'): + _ba.timer(max(0.0, activity.transition_time), + prev_activity.destroy, + timetype=TimeType.REAL) self._in_set_activity = False def getactivity(self) -> Optional[ba.Activity]: @@ -631,34 +497,29 @@ class Session: """ return [] - def _request_player(self, player: ba.Player) -> bool: + def _request_player(self, sessionplayer: ba.SessionPlayer) -> bool: + """Called by the C++ layer when players want to join.""" # If we're ending, allow no new players. if self._ending: return False - # Ask the user. + # Ask the session subclass to approve/deny this request. try: with _ba.Context(self): - result = self.on_player_request(player) + result = self.on_player_request(sessionplayer) except Exception: - from ba import _error - _error.print_exception('error in on_player_request call for', self) + print_exception('error in on_player_request call for', self) result = False # If the user said yes, add the player to the session list. if result: - self.players.append(player) - - # If we have a current activity with a lobby, - # ask it to bring up a chooser for this player. - # otherwise they'll have to wait around for the next activity. + self.players.append(sessionplayer) with _ba.Context(self): try: - self.lobby.add_chooser(player) + self.lobby.add_chooser(sessionplayer) except Exception: - from ba import _error - _error.print_exception('exception in lobby.add_chooser()') + print_exception('exception in lobby.add_chooser()') return result @@ -683,17 +544,12 @@ class Session: self._activity_weak = weakref.ref(self._next_activity) self._next_activity = None - # Lets kick out any players sitting in the lobby since - # new activities such as score screens could cover them up; - # better to have them rejoin. + # Kick out anyone loitering in the lobby. self.lobby.remove_all_choosers_and_kick_players() - activity = self._activity_weak() - assert activity is not None - activity.begin(self) + self._activity_retained.begin(self) def _on_player_ready(self, chooser: ba.Chooser) -> None: """Called when a ba.Player has checked themself ready.""" - from ba._lang import Lstr lobby = chooser.lobby activity = self._activity_weak() @@ -711,10 +567,11 @@ class Session: # Get our next activity going. self._complete_end_activity(activity, {}) else: - _ba.screenmessage(Lstr(resource='notEnoughPlayersText', - subs=[('${COUNT}', str(min_players)) - ]), - color=(1, 1, 0)) + _ba.screenmessage( + Lstr(resource='notEnoughPlayersText', + subs=[('${COUNT}', str(min_players))]), + color=(1, 1, 0), + ) _ba.playsound(_ba.getsound('error')) else: return @@ -724,24 +581,19 @@ class Session: self._add_chosen_player(chooser) lobby.remove_chooser(chooser.getplayer()) - def _add_chosen_player(self, chooser: ba.Chooser) -> ba.Player: - # pylint: disable=too-many-statements - # pylint: disable=too-many-branches - from ba import _error - from ba._lang import Lstr - from ba._team import Team - from ba import _freeforallsession - player = chooser.getplayer() - if player not in self.players: - _error.print_error('player not found in session ' - 'player-list after chooser selection') + def _add_chosen_player(self, chooser: ba.Chooser) -> ba.SessionPlayer: + from ba._team import SessionTeam + sessionplayer = chooser.getplayer() + assert sessionplayer in self.players, ( + 'SessionPlayer not found in session ' + 'player-list after chooser selection.') activity = self._activity_weak() assert activity is not None - # We need to reset the player's input here, as it is currently + # Reset the player's input here, as it is probably # referencing the chooser which could inadvertently keep it alive. - player.reset_input() + sessionplayer.reset_input() # Pass it to the current activity if it has already begun # (otherwise it'll get passed once begin is called). @@ -749,74 +601,51 @@ class Session: and not activity.is_joining_activity) # If we're not allowing mid-game joins, don't pass; just announce - # the arrival. + # the arrival and say they'll partake next round. if pass_to_activity: if not self._allow_mid_activity_joins: pass_to_activity = False with _ba.Context(self): - _ba.screenmessage(Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', - player.get_name(full=True)) - ]), - color=(0, 1, 0)) + _ba.screenmessage( + Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', + sessionplayer.get_name(full=True))]), + color=(0, 1, 0), + ) - # If we're a non-team game, each player gets their own team + # If we're a non-team session, each player gets their own team. # (keeps mini-game coding simpler if we can always deal with teams). if self._use_teams: - team = chooser.get_team() + sessionteam = chooser.get_team() else: our_team_id = self._next_team_id - team = Team(team_id=our_team_id, - name=chooser.getplayer().get_name(full=True, - icon=False), - color=chooser.get_color()) - self.teams.append(team) self._next_team_id += 1 + sessionteam = SessionTeam( + team_id=our_team_id, + color=chooser.get_color(), + name=chooser.getplayer().get_name(full=True, icon=False), + ) + + # Add player's team to the Session. + self.teams.append(sessionteam) try: with _ba.Context(self): - self.on_team_join(team) + self.on_team_join(sessionteam) except Exception: - _error.print_exception(f'exception in on_team_join for {self}') + print_exception(f'exception in on_team_join for {self}') + # Add player's team to the Activity. if pass_to_activity: - if team in activity.teams: - _error.print_error( - 'Duplicate team ID in ba.Session._add_chosen_player') - activity.teams.append(team) - try: - with _ba.Context(activity): - activity.on_team_join(team) - except Exception: - _error.print_exception( - f'ERROR: exception in on_team_join for {activity}') + activity.add_team(sessionteam) - player.set_data(team=team, - character=chooser.get_character_name(), - color=chooser.get_color(), - highlight=chooser.get_highlight()) + assert sessionplayer not in sessionteam.players + sessionteam.players.append(sessionplayer) + sessionplayer.set_data(team=sessionteam, + character=chooser.get_character_name(), + color=chooser.get_color(), + highlight=chooser.get_highlight()) - self.stats.register_player(player) + self.stats.register_player(sessionplayer) if pass_to_activity: - if isinstance(self, _freeforallsession.FreeForAllSession): - if player.team.players: - _error.print_error('expected 0 players in FFA team') - - # Don't actually add the player to their team list if we're not - # in an activity. (players get (re)added to their team lists - # when the activity begins). - player.team.players.append(player) - if player in activity.players: - _error.print_exception( - f'Dup player in ba.Session._add_chosen_player: {player}') - else: - activity.players.append(player) - player.set_activity(activity) - pnode = activity.create_player_node(player) - player.set_node(pnode) - try: - with _ba.Context(activity): - activity.on_player_join(player) - except Exception: - _error.print_exception( - f'Error on on_player_join for {activity}') - return player + activity.add_player(sessionplayer) + return sessionplayer diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index d62ac24f..7cfad6e9 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -19,7 +19,6 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Functionality related to scores and statistics.""" - from __future__ import annotations import random @@ -28,6 +27,8 @@ from typing import TYPE_CHECKING from dataclasses import dataclass import _ba +from ba._error import (print_exception, print_error, SessionTeamNotFoundError, + SessionPlayerNotFoundError) if TYPE_CHECKING: import ba @@ -37,12 +38,11 @@ if TYPE_CHECKING: @dataclass class PlayerScoredMessage: - # noinspection PyUnresolvedReferences """Informs something that a ba.Player scored. Category: Message Classes - Attributes: + Attrs: score The score value. @@ -61,7 +61,7 @@ class PlayerRecord: """ character: str - def __init__(self, name: str, name_full: str, player: ba.Player, + def __init__(self, name: str, name_full: str, player: ba.SessionPlayer, stats: ba.Stats): self.name = name self.name_full = name_full @@ -74,34 +74,34 @@ class PlayerRecord: self._multi_kill_timer: Optional[ba.Timer] = None self._multi_kill_count = 0 self._stats = weakref.ref(stats) - self._last_player: Optional[ba.Player] = None - self._player: Optional[ba.Player] = None - self._team: Optional[ReferenceType[ba.Team]] = None + self._last_player: Optional[ba.SessionPlayer] = None + self._player: Optional[ba.SessionPlayer] = None + self._team: Optional[ReferenceType[ba.SessionTeam]] = None self.streak = 0 self.associate_with_player(player) @property - def team(self) -> ba.Team: - """The ba.Team the last associated player was last on. + def team(self) -> ba.SessionTeam: + """The ba.SessionTeam the last associated player was last on. This can still return a valid result even if the player is gone. - Raises a ba.TeamNotFoundError if the team no longer exists. + Raises a ba.SessionTeamNotFoundError if the team no longer exists. """ assert self._team is not None team = self._team() if team is None: - from ba._error import TeamNotFoundError - raise TeamNotFoundError() + raise SessionTeamNotFoundError() return team @property - def player(self) -> ba.Player: - """Return the instance's associated ba.Player. + def player(self) -> ba.SessionPlayer: + """Return the instance's associated ba.SessionPlayer. - Raises a ba.PlayerNotFoundError if the player no longer exists.""" + Raises a ba.SessionPlayerNotFoundError if the player + no longer exists. + """ if not self._player: - from ba._error import PlayerNotFoundError - raise PlayerNotFoundError() + raise SessionPlayerNotFoundError() return self._player def get_name(self, full: bool = False) -> str: @@ -127,7 +127,7 @@ class PlayerRecord: return stats.getactivity() return None - def associate_with_player(self, player: ba.Player) -> None: + def associate_with_player(self, player: ba.SessionPlayer) -> None: """Associate this entry with a ba.Player.""" self._team = weakref.ref(player.team) self.character = player.character @@ -139,7 +139,7 @@ class PlayerRecord: self._multi_kill_timer = None self._multi_kill_count = 0 - def get_last_player(self) -> ba.Player: + def get_last_player(self) -> ba.SessionPlayer: """Return the last ba.Player we were associated with.""" assert self._last_player is not None return self._last_player @@ -203,10 +203,13 @@ class PlayerRecord: from bastd.actor.popuptext import PopupText # Only award this if they're still alive and we can get - # their pos. - if self._player is not None and self._player.node: - our_pos = self._player.node.position - else: + # a current position for them. + our_pos: Optional[Sequence[float]] = None + if self._player is not None: + if self._player.gameplayer is not None: + if self._player.gameplayer.node: + our_pos = self._player.gameplayer.node.position + if our_pos is None: return # Jitter position a bit since these often come in clusters. @@ -263,9 +266,8 @@ class Stats: # Load our media into this activity's context. if activity is not None: - if activity.is_expired(): - from ba import _error - _error.print_error('unexpected finalized activity') + if activity.expired: + print_error('unexpected finalized activity') else: with _ba.Context(activity): self._load_activity_media() @@ -303,7 +305,7 @@ class Stats: s_player.accum_killed_count = 0 s_player.streak = 0 - def register_player(self, player: ba.Player) -> None: + def register_player(self, player: ba.SessionPlayer) -> None: """Register a player with this score-set.""" name = player.get_name() name_full = player.get_name(full=True) @@ -329,7 +331,7 @@ class Stats: records[record_id] = record return records - def player_got_hit(self, player: ba.Player) -> None: + def player_got_hit(self, player: ba.SessionPlayer) -> None: """Call this when a player got hit.""" s_player = self._player_records[player.get_name()] s_player.streak = 0 @@ -388,8 +390,7 @@ class Stats: subs=[('${NAME}', name_full)]), color=_math.normalized_color(player.team.color)) except Exception: - from ba import _error - _error.print_exception('error showing big_message') + print_exception('error showing big_message') # If we currently have a actor, pop up a score over it. if display and showpoints: @@ -430,8 +431,7 @@ class Stats: color=player.color, image=player.get_icon()) except Exception: - from ba import _error - _error.print_exception('error announcing score') + print_exception('error announcing score') s_player.score += points s_player.accumscore += points @@ -458,14 +458,14 @@ class Stats: prec.killed_count += 1 try: if killed and _ba.getactivity().announce_player_deaths: - if killer == player: + if killer is player: _ba.screenmessage(Lstr(resource='nameSuicideText', subs=[('${NAME}', name)]), top=True, color=player.color, image=player.get_icon()) elif killer is not None: - if killer.team == player.team: + if killer.team is player.team: _ba.screenmessage(Lstr(resource='nameBetrayedText', subs=[('${NAME}', killer.get_name()), @@ -488,5 +488,4 @@ class Stats: color=player.color, image=player.get_icon()) except Exception: - from ba import _error - _error.print_exception('error announcing kill') + print_exception('error announcing kill') diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index 31e2e9d1..7c30d959 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -21,15 +21,17 @@ """Defines Team class.""" from __future__ import annotations -from typing import TYPE_CHECKING +import weakref +from typing import TYPE_CHECKING, TypeVar, Generic if TYPE_CHECKING: - from typing import Dict, List, Sequence, Any, Tuple, Union + from weakref import ReferenceType + from typing import Dict, List, Sequence, Tuple, Union, Optional import ba -class Team: - """A team of one or more ba.Players. +class SessionTeam: + """A team of one or more ba.SessionPlayers. Category: Gameplay Classes @@ -42,11 +44,14 @@ class Team: name The team's name. + id + The unique numeric id of the team. + color The team's color. players - The list of ba.Players on the team. + The list of ba.SessionPlayers on the team. gamedata A dict for use by the current ba.Activity @@ -62,56 +67,82 @@ class Team: # Annotate our attr types at the class level so they're introspectable. name: Union[ba.Lstr, str] - color: Tuple[float, ...] - players: List[ba.Player] + color: Tuple[float, ...] # FIXME: can't we make this fixed len? + players: List[ba.SessionPlayer] gamedata: Dict sessiondata: Dict + id: int def __init__(self, team_id: int = 0, name: Union[ba.Lstr, str] = '', color: Sequence[float] = (1.0, 1.0, 1.0)): - """Instantiate a ba.Team. + """Instantiate a ba.SessionTeam. In most cases, all teams are provided to you by the ba.Session, ba.Session, so calling this shouldn't be necessary. """ - # TODO: Once we spin off team copies for each activity, we don't - # need to bother with trying to lock things down, since it won't - # matter at that point if the activity mucks with them. - - # Temporarily allow us to set our own attrs - # (keeps pylint happier than using __setattr__ explicitly for all). - object.__setattr__(self, '_locked', False) - self._team_id: int = team_id + self.id = team_id self.name = name self.color = tuple(color) self.players = [] self.gamedata = {} self.sessiondata = {} - - # Now prevent further attr sets. - self._locked = True - - def get_id(self) -> int: - """Returns the numeric team ID.""" - return self._team_id - - def reset(self) -> None: - """(internal)""" - self.reset_gamedata() - object.__setattr__(self, 'players', []) + self.gameteam: Optional[Team] = None def reset_gamedata(self) -> None: """(internal)""" - object.__setattr__(self, 'gamedata', {}) + self.gamedata = {} def reset_sessiondata(self) -> None: """(internal)""" - object.__setattr__(self, 'sessiondata', {}) + self.sessiondata = {} - def __setattr__(self, name: str, value: Any) -> None: - if self._locked: - raise Exception("can't set attrs on ba.Team objects") - object.__setattr__(self, name, value) + +PlayerType = TypeVar('PlayerType', bound='ba.Player') + + +class Team(Generic[PlayerType]): + """Testing.""" + + # Defining these types at the class level instead of in __init__ so + # that types are introspectable (these are still instance attrs). + players: List[PlayerType] + id: int + name: Union[ba.Lstr, str] + color: Tuple[float, ...] # FIXME: can't we make this fixed len? + _sessionteam: ReferenceType[SessionTeam] + + # TODO: kill these. + gamedata: Dict + sessiondata: Dict + + # NOTE: avoiding having any __init__() here since it seems to not + # get called by default if a dataclass inherits from us. + + def postinit(self, sessionteam: SessionTeam) -> None: + """Wire up a newly created SessionTeam. + + (internal) + """ + self.players = [] + self._sessionteam = weakref.ref(sessionteam) + self.id = sessionteam.id + self.name = sessionteam.name + self.color = sessionteam.color + self.gamedata = sessionteam.gamedata + self.sessiondata = sessionteam.sessiondata + + @property + def sessionteam(self) -> SessionTeam: + """Return the ba.SessionTeam corresponding to this Team. + + Throws a ba.SessionTeamNotFoundError if there is none. + """ + if self._sessionteam is not None: + sessionteam = self._sessionteam() + if sessionteam is not None: + return sessionteam + from ba import _error + raise _error.SessionTeamNotFoundError() diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index 7c13f6ab..ceb9b330 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -22,21 +22,24 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar -import _ba from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity from ba._gameresults import TeamGameResults from ba._dualteamsession import DualTeamSession +import _ba if TYPE_CHECKING: from typing import Any, Dict, Type, Sequence from bastd.actor.playerspaz import PlayerSpaz import ba +PlayerType = TypeVar('PlayerType', bound='ba.Player') +TeamType = TypeVar('TeamType', bound='ba.Team') -class TeamGameActivity(GameActivity): + +class TeamGameActivity(GameActivity[PlayerType, TeamType]): """Base class for teams and free-for-all mode games. Category: Gameplay Classes @@ -56,6 +59,7 @@ class TeamGameActivity(GameActivity): or issubclass(sessiontype, FreeForAllSession)) def __init__(self, settings: Dict[str, Any]): + super().__init__(settings) # By default we don't show kill-points in free-for-all. @@ -104,7 +108,7 @@ class TeamGameActivity(GameActivity): _error.print_exception() def spawn_player_spaz(self, - player: ba.Player, + player: PlayerType, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz: """ @@ -117,7 +121,7 @@ class TeamGameActivity(GameActivity): if position is None: # In teams-mode get our team-start-location. if isinstance(self.session, DualTeamSession): - position = (self.map.get_start_position(player.team.get_id())) + position = (self.map.get_start_position(player.team.id)) else: # Otherwise do free-for-all spawn locations. position = self.map.get_ffa_start_position(self.players) diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 23604e2b..20e20d8e 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -38,12 +38,12 @@ if TYPE_CHECKING: from bastd.ui.league.rankbutton import LeagueRankButton -class CoopScoreScreen(ba.Activity): +class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): """Score screen showing the results of a cooperative game.""" def __init__(self, settings: Dict[str, Any]): # pylint: disable=too-many-statements - super().__init__(settings=settings) + super().__init__(settings) # Keep prev activity alive while we fade in self.transition_time = 0.5 @@ -1008,7 +1008,7 @@ class CoopScoreScreen(ba.Activity): # We need to manually run this in the context of our activity # and only if we aren't shutting down. # (really should make the submit_score call handle that stuff itself) - if self.is_expired(): + if self.expired: return with ba.Context(self): # Delay a bit if results come in too fast. diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index 408495cc..6fcb0305 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -73,7 +73,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): scale=0.25, color=(0.5, 0.5, 0.5, 1.0), jitter=3.0).autoretain() - for team in self.teams: + for team in self.session.teams: ba.timer( i * 0.15 + 0.15, ba.WeakCall(self._show_team_name, vval - i * height, team, @@ -99,8 +99,8 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): i += 1 self.show_player_scores() - def _show_team_name(self, pos_v: float, team: ba.Team, kill_delay: float, - shiftdelay: float) -> None: + def _show_team_name(self, pos_v: float, team: ba.SessionTeam, + kill_delay: float, shiftdelay: float) -> None: del kill_delay # unused arg ZoomText(ba.Lstr(value='${A}:', subs=[('${A}', team.name)]), position=(100, pos_v), @@ -113,7 +113,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): color=team.color, jitter=1.0).autoretain() - def _show_team_old_score(self, pos_v: float, team: ba.Team, + def _show_team_old_score(self, pos_v: float, team: ba.SessionTeam, shiftdelay: float) -> None: ZoomText(str(team.sessiondata['score'] - 1), position=(150, pos_v), @@ -127,8 +127,9 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): h_align='left', jitter=1.0).autoretain() - def _show_team_score(self, pos_v: float, team: ba.Team, scored: bool, - kill_delay: float, shiftdelay: float) -> None: + def _show_team_score(self, pos_v: float, team: ba.SessionTeam, + scored: bool, kill_delay: float, + shiftdelay: float) -> None: del kill_delay # unused arg ZoomText(str(team.sessiondata['score']), position=(150, pos_v), diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index 1f5a9a47..b58d43dd 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -19,13 +19,14 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Functionality related to teams mode score screen.""" - from __future__ import annotations from typing import TYPE_CHECKING import ba from ba.internal import ScoreScreenActivity +from bastd.actor.text import Text +from bastd.actor.image import Image if TYPE_CHECKING: from typing import Any, Dict, Optional, Union @@ -42,7 +43,6 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): self._show_up_next: bool = True def on_begin(self) -> None: - from bastd.actor.text import Text super().on_begin() session = self.session if self._show_up_next and isinstance(session, ba.MultiTeamSession): @@ -77,8 +77,6 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): """Show scores for individual players.""" # pylint: disable=too-many-locals # pylint: disable=too-many-statements - from bastd.actor.text import Text - from bastd.actor.image import Image ts_v_offset = 150.0 + y_offset ts_h_offs = 80.0 + x_offset @@ -90,6 +88,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): def _get_prec_score(p_rec: ba.PlayerRecord) -> Optional[int]: if is_free_for_all and results is not None: assert isinstance(results, ba.TeamGameResults) + assert p_rec.team.gameteam is not None val = results.get_team_score(p_rec.team) return val return p_rec.accumscore @@ -97,7 +96,8 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): def _get_prec_score_str(p_rec: ba.PlayerRecord) -> Union[str, ba.Lstr]: if is_free_for_all and results is not None: assert isinstance(results, ba.TeamGameResults) - val = results.get_team_score_str(p_rec.team) + assert p_rec.team.gameteam is not None + val = results.get_team_score_str(p_rec.team.gameteam) assert val is not None return val return str(p_rec.accumscore) @@ -113,7 +113,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): valid_players = list(self.stats.get_records().items()) def _get_player_score_set_entry( - player: ba.Player) -> Optional[ba.PlayerRecord]: + player: ba.SessionPlayer) -> Optional[ba.PlayerRecord]: for p_rec in valid_players: # PyCharm incorrectly thinks valid_players is a List[str] # noinspection PyUnresolvedReferences diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 3a6aeaae..e4146da3 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -142,7 +142,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): h_align=Text.HAlign.CENTER, transition_delay=t_incr * 4).autoretain() - win_score = (session.get_series_length() - 1) / 2 + 1 + win_score = (session.get_series_length() - 1) // 2 + 1 lose_score = 0 for team in self.teams: if team.sessiondata['score'] != win_score: @@ -344,7 +344,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): if not self.is_transitioning_out(): ba.setmusic(ba.MusicType.VICTORY) - def _show_winner(self, team: ba.Team) -> None: + def _show_winner(self, team: ba.SessionTeam) -> None: from bastd.actor.image import Image from bastd.actor.zoomtext import ZoomText if not self._is_ffa: diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 82a1c0b7..f8ca79f1 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -22,13 +22,16 @@ from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Generic, TypeVar import ba from bastd.actor.spaz import Spaz if TYPE_CHECKING: - from typing import Any, Optional, Sequence, Tuple + from typing import Any, Sequence, Tuple, Optional + +PlayerType = TypeVar('PlayerType', bound=ba.Player) +TeamType = TypeVar('TeamType', bound=ba.Team) class PlayerSpazDeathMessage: @@ -38,9 +41,6 @@ class PlayerSpazDeathMessage: Attributes: - spaz - The ba.PlayerSpaz that died. - killed If True, the spaz was killed; If False, they left the game or the round ended. @@ -55,11 +55,22 @@ class PlayerSpazDeathMessage: def __init__(self, spaz: PlayerSpaz, was_killed: bool, killerplayer: Optional[ba.Player], how: ba.DeathType): """Instantiate a message with the given values.""" - self.spaz = spaz + self._spaz = spaz self.killed = was_killed self.killerplayer = killerplayer self.how = how + def getspaz( + self, activity: ba.Activity[PlayerType, + TeamType]) -> PlayerSpaz[PlayerType]: + """Return the spaz that died. + + The current activity is required as an argument so the exact type of + PlayerSpaz can be determined by the type checker. + """ + del activity # Unused + return self._spaz + class PlayerSpazHurtMessage: """A message saying a ba.PlayerSpaz was hurt. @@ -77,7 +88,7 @@ class PlayerSpazHurtMessage: self.spaz = spaz -class PlayerSpaz(Spaz): +class PlayerSpaz(Spaz, Generic[PlayerType]): """A ba.Spaz subclass meant to be controlled by a ba.Player. category: Gameplay Classes @@ -91,10 +102,10 @@ class PlayerSpaz(Spaz): """ def __init__(self, + player: PlayerType, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), character: str = 'Spaz', - player: ba.Player = None, powerups_expire: bool = True): """Create a spaz for the provided ba.Player. @@ -108,12 +119,13 @@ class PlayerSpaz(Spaz): source_player=player, start_invincible=True, powerups_expire=powerups_expire) - self.last_player_attacked_by: Optional[ba.Player] = None + self.last_player_attacked_by: Optional[PlayerType] = None self.last_attacked_time = 0.0 self.last_attacked_type: Optional[Tuple[str, str]] = None self.held_count = 0 - self.last_player_held_by: Optional[ba.Player] = None + self.last_player_held_by: Optional[PlayerType] = None self._player = player + self.playertype = type(player) # Grab the node for this player and wire it to follow our spaz # (so players' controllers know where to draw their guides, etc). @@ -123,7 +135,7 @@ class PlayerSpaz(Spaz): self.node.connectattr('torso_position', player.node, 'position') @property - def player(self) -> ba.Player: + def player(self) -> PlayerType: """The ba.Player associated with this Spaz. If the player no longer exists, raises an ba.PlayerNotFoundError. @@ -132,7 +144,7 @@ class PlayerSpaz(Spaz): raise ba.PlayerNotFoundError() return self._player - def getplayer(self) -> Optional[ba.Player]: + def getplayer(self) -> Optional[PlayerType]: """Get the ba.Player associated with this Spaz. Note that this may return None if the player has left. @@ -226,7 +238,8 @@ class PlayerSpaz(Spaz): if isinstance(msg, ba.PickedUpMessage): super().handlemessage(msg) # Augment standard behavior. self.held_count += 1 - picked_up_by = msg.node.source_player + picked_up_by = ba.playercast_o(self.playertype, + msg.node.source_player) if picked_up_by: self.last_player_held_by = picked_up_by elif isinstance(msg, ba.DroppedMessage): @@ -237,11 +250,12 @@ class PlayerSpaz(Spaz): # Let's count someone dropping us as an attack. try: - picked_up_by = msg.node.source_player + picked_up_by_2 = ba.playercast_o(self.playertype, + msg.node.source_player) except Exception: - picked_up_by = None - if picked_up_by: - self.last_player_attacked_by = picked_up_by + picked_up_by_2 = None + if picked_up_by_2: + self.last_player_attacked_by = picked_up_by_2 self.last_attacked_time = ba.time() self.last_attacked_type = ('picked_up', 'default') elif isinstance(msg, ba.DieMessage): @@ -296,7 +310,8 @@ class PlayerSpaz(Spaz): # Keep track of the player who last hit us for point rewarding. elif isinstance(msg, ba.HitMessage): if msg.source_player: - self.last_player_attacked_by = msg.source_player + srcplayer = ba.playercast_o(self.playertype, msg.source_player) + self.last_player_attacked_by = srcplayer self.last_attacked_time = ba.time() self.last_attacked_type = (msg.hit_type, msg.hit_subtype) super().handlemessage(msg) # Augment standard behavior. diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py index a6d91b74..44e41e0b 100644 --- a/assets/src/ba_data/python/bastd/actor/respawnicon.py +++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py @@ -136,7 +136,7 @@ class RespawnIcon: """Return info on where we should be shown and stored.""" activity = ba.getactivity() if isinstance(ba.getsession(), ba.DualTeamSession): - on_right = player.team.get_id() % 2 == 1 + on_right = player.team.id % 2 == 1 # Store a list of icons in the team. try: diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py index c229ca55..52ff65c8 100644 --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py @@ -317,7 +317,7 @@ class _EntryProxy: self._scoreboard = weakref.ref(scoreboard) # have to store ID here instead of a weak-ref since the team will be # dead when we die and need to remove it - self._team_id = team.get_id() + self._team_id = team.id def __del__(self) -> None: scoreboard = self._scoreboard() @@ -366,7 +366,7 @@ class Scoreboard: flash: bool = True, show_value: bool = True) -> None: """Update the score-board display for the given ba.Team.""" - if not team.get_id() in self._entries: + if not team.id in self._entries: self._add_team(team) # create a proxy in the team which will kill # our entry when it dies (for convenience) @@ -374,21 +374,21 @@ class Scoreboard: raise Exception('existing _EntryProxy found') team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team) # now set the entry.. - self._entries[team.get_id()].set_value(score=score, - max_score=max_score, - countdown=countdown, - flash=flash, - show_value=show_value) + self._entries[team.id].set_value(score=score, + max_score=max_score, + countdown=countdown, + flash=flash, + show_value=show_value) def _add_team(self, team: ba.Team) -> None: - if team.get_id() in self._entries: + if team.id in self._entries: raise Exception('Duplicate team add') - self._entries[team.get_id()] = _Entry(self, - team, - do_cover=self._do_cover, - scale=self._scale, - label=self._label, - flash_length=self._flash_length) + self._entries[team.id] = _Entry(self, + team, + do_cover=self._do_cover, + scale=self._scale, + label=self._label, + flash_length=self._flash_length) self._update_teams() def remove_team(self, team_id: int) -> None: diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index 1b5e4b8c..e62d0b97 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -998,7 +998,7 @@ class BotSet: # Don't do this if the activity is shutting down or dead. activity: Optional[ba.Activity] = ba.getactivity(doraise=False) - if activity is None or activity.is_expired(): + if activity is None or activity.expired: return for i in range(len(self._bot_lists)): diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 0c8aec67..092c9495 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -29,14 +29,14 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz +from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Sequence, Union # ba_meta export game -class AssaultGame(ba.TeamGameActivity): +class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Game where you score by touching the other team's flag.""" @classmethod @@ -109,7 +109,7 @@ class AssaultGame(ba.TeamGameActivity): self.setup_standard_time_limit(self.settings_raw['Time Limit']) self.setup_standard_powerup_drops() for team in self.teams: - mat = self._base_region_materials[team.get_id()] = ba.Material() + mat = self._base_region_materials[team.id] = ba.Material() mat.add_actions(conditions=('they_have_material', ba.sharedobj('player_material')), actions=(('modify_part_collision', 'collide', @@ -121,8 +121,7 @@ class AssaultGame(ba.TeamGameActivity): # Create a score region and flag for each team. for team in self.teams: - team.gamedata['base_pos'] = self.map.get_flag_position( - team.get_id()) + team.gamedata['base_pos'] = self.map.get_flag_position(team.id) ba.newnode('light', attrs={ @@ -139,20 +138,20 @@ class AssaultGame(ba.TeamGameActivity): position=team.gamedata['base_pos'], color=team.color) basepos = team.gamedata['base_pos'] - ba.newnode( - 'region', - owner=team.gamedata['flag'].node, - attrs={ - 'position': (basepos[0], basepos[1] + 0.75, basepos[2]), - 'scale': (0.5, 0.5, 0.5), - 'type': 'sphere', - 'materials': [self._base_region_materials[team.get_id()]] - }) + ba.newnode('region', + owner=team.gamedata['flag'].node, + attrs={ + 'position': + (basepos[0], basepos[1] + 0.75, basepos[2]), + 'scale': (0.5, 0.5, 0.5), + 'type': 'sphere', + 'materials': [self._base_region_materials[team.id]] + }) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): super().handlemessage(msg) # Augment standard. - self.respawn_player(msg.spaz.player) + self.respawn_player(msg.getspaz(self).player) else: super().handlemessage(msg) @@ -173,14 +172,15 @@ class AssaultGame(ba.TeamGameActivity): cnode = ba.get_collision_info('opposing_node') assert isinstance(cnode, ba.Node) actor = cnode.getdelegate() - if not isinstance(actor, playerspaz.PlayerSpaz): + if not isinstance(actor, PlayerSpaz): return + player = actor.getplayer() - if not player or not player.is_alive(): + if not player or not player.actor: return # If its another team's player, they scored. - player_team = player.team + player_team: ba.Team[ba.Player] = player.team if player_team is not team: # Prevent multiple simultaneous scores. @@ -194,24 +194,22 @@ class AssaultGame(ba.TeamGameActivity): # and add flashes of light so its noticeable. for player in player_team.players: if player.is_alive(): - if player.node: - pos = player.node.position - light = ba.newnode('light', - attrs={ - 'position': pos, - 'color': player_team.color, - 'height_attenuated': False, - 'radius': 0.4 - }) - ba.timer(0.5, light.delete) - ba.animate(light, 'intensity', { - 0: 0, - 0.1: 1.0, - 0.5: 0 - }) + pos = player.node.position + light = ba.newnode('light', + attrs={ + 'position': pos, + 'color': player_team.color, + 'height_attenuated': False, + 'radius': 0.4 + }) + ba.timer(0.5, light.delete) + ba.animate(light, 'intensity', { + 0: 0, + 0.1: 1.0, + 0.5: 0 + }) - new_pos = (self.map.get_start_position( - player_team.get_id())) + new_pos = (self.map.get_start_position(player_team.id)) light = ba.newnode('light', attrs={ 'position': new_pos, diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 35e4a20a..09ce7be6 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -25,11 +25,13 @@ from __future__ import annotations +from dataclasses import dataclass from typing import TYPE_CHECKING import ba from bastd.actor import flag as stdflag from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Sequence, Union, Optional @@ -38,9 +40,10 @@ if TYPE_CHECKING: class CTFFlag(stdflag.Flag): """Special flag type for ctf games.""" - def __init__(self, team: ba.Team): - super().__init__(materials=[team.gamedata['flagmaterial']], - position=team.gamedata['base_pos'], + def __init__(self, team: Team): + assert team.flagmaterial is not None + super().__init__(materials=[team.flagmaterial], + position=team.base_pos, color=team.color) self._team = team self.held_count = 0 @@ -52,7 +55,7 @@ class CTFFlag(stdflag.Flag): 'h_align': 'center' }) self.reset_return_times() - self.last_player_to_hold: Optional[ba.Player] = None + self.last_player_to_hold: Optional[Player] = None self.time_out_respawn_time: Optional[int] = None self.touch_return_time: Optional[float] = None @@ -64,7 +67,7 @@ class CTFFlag(stdflag.Flag): self.activity.settings_raw['Flag Touch Return Time']) @property - def team(self) -> ba.Team: + def team(self) -> Team: """return the flag's team.""" return self._team @@ -77,8 +80,33 @@ class CTFFlag(stdflag.Flag): return delegate if isinstance(delegate, CTFFlag) else None +@dataclass +class Player(ba.Player['Team']): + """Our player type for this game.""" + touching_own_flag: int = 0 + + +@dataclass +class Team(ba.Team[Player]): + """Our team type for this game.""" + base_pos: Sequence[float] + base_region_material: ba.Material + base_region: ba.Node + spaz_material_no_flag_physical: ba.Material + spaz_material_no_flag_collide: ba.Material + flagmaterial: ba.Material + score: int = 0 + flag_return_touches: int = 0 + home_flag_at_base: bool = True + touch_return_timer: Optional[ba.Timer] = None + enemy_flag_at_base: bool = False + flag: Optional[CTFFlag] = None + last_flag_leave_time: Optional[float] = None + touch_return_timer_ticking: Optional[ba.NodeActor] = None + + # ba_meta export game -class CaptureTheFlagGame(ba.TeamGameActivity): +class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): """Game of stealing other team's flag and returning it to your base.""" @classmethod @@ -102,24 +130,37 @@ class CaptureTheFlagGame(ba.TeamGameActivity): cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: return [ - ('Score to Win', {'min_value': 1, 'default': 3}), + ('Score to Win', { + 'min_value': 1, + 'default': 3 + }), ('Flag Touch Return Time', { - 'min_value': 0, 'default': 0, 'increment': 1}), + 'min_value': 0, + 'default': 0, + 'increment': 1 + }), ('Flag Idle Return Time', { - 'min_value': 5, 'default': 30, 'increment': 5}), + 'min_value': 5, + 'default': 30, + 'increment': 5 + }), ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], - 'default': 0}), + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), ('Respawn Times', { 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0}), - ('Epic Mode', {'default': False})] # yapf: disable + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() if self.settings_raw['Epic Mode']: @@ -149,29 +190,24 @@ class CaptureTheFlagGame(ba.TeamGameActivity): ba.MusicType.FLAG_CATCHER) super().on_transition_in() - def on_team_join(self, team: ba.Team) -> None: - team.gamedata['score'] = 0 - team.gamedata['flag_return_touches'] = 0 - team.gamedata['home_flag_at_base'] = True - team.gamedata['touch_return_timer'] = None - team.gamedata['enemy_flag_at_base'] = False - team.gamedata['base_pos'] = (self.map.get_flag_position(team.get_id())) + def create_team(self, sessionteam: ba.SessionTeam) -> Team: - self.project_flag_stand(team.gamedata['base_pos']) + base_pos = self.map.get_flag_position(sessionteam.id) + self.project_flag_stand(base_pos) ba.newnode('light', attrs={ - 'position': team.gamedata['base_pos'], + 'position': base_pos, 'intensity': 0.6, 'height_attenuated': False, 'volume_intensity_scale': 0.1, 'radius': 0.1, - 'color': team.color + 'color': sessionteam.color }) - base_region_mat = team.gamedata['base_region_material'] = ba.Material() - pos = team.gamedata['base_pos'] - team.gamedata['base_region'] = ba.newnode( + base_region_mat = ba.Material() + pos = base_pos + base_region = ba.newnode( 'region', attrs={ 'position': (pos[0], pos[1] + 0.75, pos[2]), @@ -180,22 +216,28 @@ class CaptureTheFlagGame(ba.TeamGameActivity): 'materials': [base_region_mat, self._all_bases_material] }) - # create some materials for this team - spaz_mat_no_flag_physical = team.gamedata[ - 'spaz_material_no_flag_physical'] = ba.Material() - spaz_mat_no_flag_collide = team.gamedata[ - 'spaz_material_no_flag_collide'] = ba.Material() - flagmat = team.gamedata['flagmaterial'] = ba.Material() + spaz_mat_no_flag_physical = ba.Material() + spaz_mat_no_flag_collide = ba.Material() + flagmat = ba.Material() + + team = Team(base_pos=base_pos, + base_region_material=base_region_mat, + base_region=base_region, + spaz_material_no_flag_physical=spaz_mat_no_flag_physical, + spaz_material_no_flag_collide=spaz_mat_no_flag_collide, + flagmaterial=flagmat) # Some parts of our spazzes don't collide physically with our # flags but generate callbacks. spaz_mat_no_flag_physical.add_actions( conditions=('they_have_material', flagmat), - actions=(('modify_part_collision', 'physical', - False), ('call', 'at_connect', - lambda: self._handle_hit_own_flag(team, 1)), - ('call', 'at_disconnect', - lambda: self._handle_hit_own_flag(team, 0)))) + actions=( + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + lambda: self._handle_hit_own_flag(team, 1)), + ('call', 'at_disconnect', + lambda: self._handle_hit_own_flag(team, 0)), + )) # Other parts of our spazzes don't collide with our flags at all. spaz_mat_no_flag_collide.add_actions(conditions=('they_have_material', @@ -214,6 +256,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity): ('call', 'at_disconnect', lambda: self._handle_flag_left_base(team)))) + return team + + def on_team_join(self, team: Team) -> None: self._spawn_flag_for_team(team) self._update_scoreboard() @@ -223,14 +268,14 @@ class CaptureTheFlagGame(ba.TeamGameActivity): self.setup_standard_powerup_drops() ba.timer(1.0, call=self._tick, repeat=True) - def _spawn_flag_for_team(self, team: ba.Team) -> None: - flag = team.gamedata['flag'] = CTFFlag(team) - team.gamedata['flag_return_touches'] = 0 + def _spawn_flag_for_team(self, team: Team) -> None: + team.flag = CTFFlag(team) + team.flag_return_touches = 0 self._flash_base(team, length=1.0) - assert flag.node - ba.playsound(self._swipsound, position=flag.node.position) + assert team.flag.node + ba.playsound(self._swipsound, position=team.flag.node.position) - def _handle_flag_entered_base(self, team: ba.Team) -> None: + def _handle_flag_entered_base(self, team: Team) -> None: node = ba.get_collision_info('opposing_node') assert isinstance(node, (ba.Node, type(None))) flag = CTFFlag.from_node(node) @@ -239,14 +284,14 @@ class CaptureTheFlagGame(ba.TeamGameActivity): return if flag.team is team: - team.gamedata['home_flag_at_base'] = True + team.home_flag_at_base = True # If the enemy flag is already here, score! - if team.gamedata['enemy_flag_at_base']: + if team.enemy_flag_at_base: self._score(team) else: - team.gamedata['enemy_flag_at_base'] = True - if team.gamedata['home_flag_at_base']: + team.enemy_flag_at_base = True + if team.home_flag_at_base: # Award points to whoever was carrying the enemy flag. player = flag.last_player_to_hold if player and player.team is team: @@ -262,7 +307,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): curtime = ba.time(ba.TimeType.BASE) if curtime - self._last_home_flag_notice_print_time > 5.0: self._last_home_flag_notice_print_time = curtime - bpos = team.gamedata['base_pos'] + bpos = team.base_pos tval = ba.Lstr(resource='ownFlagAtYourBaseWarning') tnode = ba.newnode( 'text', @@ -286,10 +331,10 @@ class CaptureTheFlagGame(ba.TeamGameActivity): # If either flag is away from base and not being held, tick down its # respawn timer. for team in self.teams: - flag = team.gamedata['flag'] + flag = team.flag + assert flag is not None - if (not team.gamedata['home_flag_at_base'] - and flag.held_count == 0): + if not team.home_flag_at_base and flag.held_count == 0: time_out_counting_down = True if flag.time_out_respawn_time is None: flag.reset_return_times() @@ -307,16 +352,16 @@ class CaptureTheFlagGame(ba.TeamGameActivity): # If there's no self-touches on this flag, set its text # to show its auto-return counter. (if there's self-touches # its showing that time). - if team.gamedata['flag_return_touches'] == 0: - flag.counter.text = (str(flag.time_out_respawn_time) if - (time_out_counting_down - and flag.time_out_respawn_time <= 10) - else '') + if team.flag_return_touches == 0: + flag.counter.text = (str(flag.time_out_respawn_time) if ( + time_out_counting_down + and flag.time_out_respawn_time is not None + and flag.time_out_respawn_time <= 10) else '') flag.counter.color = (1, 1, 1, 0.5) flag.counter.scale = 0.014 - def _score(self, team: ba.Team) -> None: - team.gamedata['score'] += 1 + def _score(self, team: Team) -> None: + team.score += 1 ba.playsound(self._score_sound) self._flash_base(team) self._update_scoreboard() @@ -328,58 +373,57 @@ class CaptureTheFlagGame(ba.TeamGameActivity): # Reset all flags/state. for reset_team in self.teams: - if not reset_team.gamedata['home_flag_at_base']: - reset_team.gamedata['flag'].handlemessage(ba.DieMessage()) - reset_team.gamedata['enemy_flag_at_base'] = False - if team.gamedata['score'] >= self.settings_raw['Score to Win']: + if not reset_team.home_flag_at_base: + assert reset_team.flag is not None + reset_team.flag.handlemessage(ba.DieMessage()) + reset_team.enemy_flag_at_base = False + if team.score >= self.settings_raw['Score to Win']: self.end_game() def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score(team, team.gamedata['score']) + results.set_team_score(team, team.score) self.end(results=results, announce_delay=0.8) - def _handle_flag_left_base(self, team: ba.Team) -> None: + def _handle_flag_left_base(self, team: Team) -> None: cur_time = ba.time() op_node = ba.get_collision_info('opposing_node') assert isinstance(op_node, (ba.Node, type(None))) flag = CTFFlag.from_node(op_node) if not flag: return - if flag.team is team: # Check times here to prevent too much flashing. - if ('last_flag_leave_time' not in team.gamedata - or cur_time - team.gamedata['last_flag_leave_time'] > 3.0): - ba.playsound(self._alarmsound, - position=team.gamedata['base_pos']) + if (team.last_flag_leave_time is None + or cur_time - team.last_flag_leave_time > 3.0): + ba.playsound(self._alarmsound, position=team.base_pos) self._flash_base(team) - team.gamedata['last_flag_leave_time'] = cur_time - team.gamedata['home_flag_at_base'] = False + team.last_flag_leave_time = cur_time + team.home_flag_at_base = False else: - team.gamedata['enemy_flag_at_base'] = False - - def _touch_return_update(self, team: ba.Team) -> None: + team.enemy_flag_at_base = False + def _touch_return_update(self, team: Team) -> None: # Count down only while its away from base and not being held. - if (team.gamedata['home_flag_at_base'] - or team.gamedata['flag'].held_count > 0): - team.gamedata['touch_return_timer_ticking'] = None + assert team.flag is not None + if team.home_flag_at_base or team.flag.held_count > 0: + team.touch_return_timer_ticking = None return # No need to return when its at home. - if team.gamedata['touch_return_timer_ticking'] is None: - team.gamedata['touch_return_timer_ticking'] = ba.NodeActor( + if team.touch_return_timer_ticking is None: + team.touch_return_timer_ticking = ba.NodeActor( ba.newnode('sound', attrs={ 'sound': self._ticking_sound, 'positional': False, 'loop': True })) - flag = team.gamedata['flag'] + flag = team.flag + assert flag.touch_return_time is not None flag.touch_return_time -= 0.1 if flag.counter: - flag.counter.text = '%.1f' % flag.touch_return_time + flag.counter.text = f'{flag.touch_return_time:.1f}' flag.counter.color = (1, 1, 0, 1) flag.counter.scale = 0.02 @@ -387,9 +431,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity): self._award_players_touching_own_flag(team) flag.handlemessage(ba.DieMessage()) - def _award_players_touching_own_flag(self, team: ba.Team) -> None: + def _award_players_touching_own_flag(self, team: Team) -> None: for player in team.players: - if player.gamedata['touching_own_flag'] > 0: + if player.touching_own_flag > 0: return_score = 10 + 5 * int( self.settings_raw['Flag Touch Return Time']) self.stats.player_scored(player, @@ -397,7 +441,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): screenmessage=False) @staticmethod - def _player_from_node(node: Optional[ba.Node]) -> Optional[ba.Player]: + def _player_from_node(node: Optional[ba.Node]) -> Optional[Player]: """Return a player if given a node that is part of one's actor.""" if not node: return None @@ -406,7 +450,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity): return None return delegate.getplayer() - def _handle_hit_own_flag(self, team: ba.Team, val: int) -> None: + def _handle_hit_own_flag(self, team: Team, val: int) -> None: """ keep track of when each player is touching their own flag so we can award points when returned @@ -415,13 +459,13 @@ class CaptureTheFlagGame(ba.TeamGameActivity): assert isinstance(srcnode, (ba.Node, type(None))) player = self._player_from_node(srcnode) if player: - player.gamedata['touching_own_flag'] += (1 if val else -1) + player.touching_own_flag += (1 if val else -1) # If return-time is zero, just kill it immediately.. otherwise keep # track of touches and count down. if float(self.settings_raw['Flag Touch Return Time']) <= 0.0: - if (not team.gamedata['home_flag_at_base'] - and team.gamedata['flag'].held_count == 0): + assert team.flag is not None + if not team.home_flag_at_base and team.flag.held_count == 0: # Use a node message to kill the flag instead of just killing # our team's. (avoids redundantly killing new flags if @@ -434,26 +478,26 @@ class CaptureTheFlagGame(ba.TeamGameActivity): # Takes a non-zero amount of time to return. else: if val: - team.gamedata['flag_return_touches'] += 1 - if team.gamedata['flag_return_touches'] == 1: - team.gamedata['touch_return_timer'] = ba.Timer( + team.flag_return_touches += 1 + if team.flag_return_touches == 1: + team.touch_return_timer = ba.Timer( 0.1, call=ba.Call(self._touch_return_update, team), repeat=True) - team.gamedata['touch_return_timer_ticking'] = None + team.touch_return_timer_ticking = None else: - team.gamedata['flag_return_touches'] -= 1 - if team.gamedata['flag_return_touches'] == 0: - team.gamedata['touch_return_timer'] = None - team.gamedata['touch_return_timer_ticking'] = None - if team.gamedata['flag_return_touches'] < 0: + team.flag_return_touches -= 1 + if team.flag_return_touches == 0: + team.touch_return_timer = None + team.touch_return_timer_ticking = None + if team.flag_return_touches < 0: ba.print_error( "CTF: flag_return_touches < 0; this shouldn't happen.") - def _flash_base(self, team: ba.Team, length: float = 2.0) -> None: + def _flash_base(self, team: Team, length: float = 2.0) -> None: light = ba.newnode('light', attrs={ - 'position': team.gamedata['base_pos'], + 'position': team.base_pos, 'height_attenuated': False, 'radius': 0.3, 'color': team.color @@ -461,22 +505,21 @@ class CaptureTheFlagGame(ba.TeamGameActivity): ba.animate(light, 'intensity', {0.0: 0, 0.25: 2.0, 0.5: 0}, loop=True) ba.timer(length, light.delete) - def spawn_player_spaz(self, *args: Any, **keywds: Any) -> Any: + def spawn_player_spaz(self, + player: Player, + position: Sequence[float] = None, + angle: float = None) -> PlayerSpaz: """Intercept new spazzes and add our team material for them.""" - # (chill pylint; we're passing our exact args to parent call) - # pylint: disable=signature-differs - spaz = super().spawn_player_spaz(*args, **keywds) + spaz = super().spawn_player_spaz(player, position, angle) player = spaz.player - player.gamedata['touching_own_flag'] = 0 - - # Ignore false alarm for gamedata member. - no_physical_mats = [ - player.team.gamedata['spaz_material_no_flag_physical'] + team: Team = player.team + player.touching_own_flag = 0 + no_physical_mats: List[ba.Material] = [ + team.spaz_material_no_flag_physical ] - no_collide_mats = [ - player.team.gamedata['spaz_material_no_flag_collide'] + no_collide_mats: List[ba.Material] = [ + team.spaz_material_no_flag_collide ] - # pylint: enable=arguments-differ # Our normal parts should still collide; just not physically # (so we can calc restores). @@ -496,14 +539,14 @@ class CaptureTheFlagGame(ba.TeamGameActivity): def _update_scoreboard(self) -> None: for team in self.teams: - self._scoreboard.set_team_value(team, team.gamedata['score'], + self._scoreboard.set_team_value(team, team.score, self.settings_raw['Score to Win']) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.spaz.player) + self.respawn_player(msg.getspaz(self).player) elif isinstance(msg, stdflag.FlagDeathMessage): assert isinstance(msg.flag, CTFFlag) ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 47247396..65b41a4c 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -37,7 +37,7 @@ if TYPE_CHECKING: # ba_meta export game -class ChosenOneGame(ba.TeamGameActivity): +class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): """ Game involving trying to remain the one 'chosen one' for a set length of time while everyone else tries to @@ -327,7 +327,7 @@ class ChosenOneGame(ba.TeamGameActivity): if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - player = msg.spaz.player + player = msg.getspaz(self).player if player is self._get_chosen_one_player(): killerplayer = msg.killerplayer self._set_chosen_one_player(None if ( diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index d3ac9983..2ffac1a0 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -57,7 +57,7 @@ class ConquestFlag(Flag): # ba_meta export game -class ConquestGame(ba.TeamGameActivity): +class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): """A game where teams try to claim all flags on the map.""" @classmethod @@ -254,7 +254,7 @@ class ConquestGame(ba.TeamGameActivity): super().handlemessage(msg) # Respawn only if this team has a flag. - player = msg.spaz.player + player = msg.getspaz(self).player if player.team.gamedata['flags_held'] > 0: self.respawn_player(player) else: diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index b4798d82..3b5237c2 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -35,7 +35,7 @@ if TYPE_CHECKING: # ba_meta export game -class DeathMatchGame(ba.TeamGameActivity): +class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): """A game type based on acquiring kills.""" @classmethod @@ -145,7 +145,7 @@ class DeathMatchGame(ba.TeamGameActivity): # Augment standard behavior. super().handlemessage(msg) - player = msg.spaz.player + player = msg.getspaz(self).player self.respawn_player(player) killer = msg.killerplayer diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 72259d2e..eebdef24 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -39,7 +39,7 @@ if TYPE_CHECKING: # ba_meta export game -class EasterEggHuntGame(ba.TeamGameActivity): +class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): """A game where score is based on collecting eggs.""" @classmethod @@ -212,7 +212,7 @@ class EasterEggHuntGame(ba.TeamGameActivity): # Augment standard behavior. super().handlemessage(msg) - player = msg.spaz.getplayer() + player = msg.getspaz(self).getplayer() if not player: return self.stats.player_was_killed(player) diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 6dfe3006..047db791 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -164,7 +164,7 @@ class Icon(ba.Actor): # ba_meta export game -class EliminationGame(ba.TeamGameActivity): +class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Game type where last player(s) left alive win.""" @classmethod @@ -330,7 +330,7 @@ class EliminationGame(ba.TeamGameActivity): # Now for each team, cycle through our available players # adding icons. for team in self.teams: - if team.get_id() == 0: + if team.id == 0: xval = -60 x_offs = -78 else: @@ -362,7 +362,7 @@ class EliminationGame(ba.TeamGameActivity): # Non-solo mode. else: for team in self.teams: - if team.get_id() == 0: + if team.id == 0: xval = -50 x_offs = -85 else: @@ -395,8 +395,7 @@ class EliminationGame(ba.TeamGameActivity): player_pos = ba.Vec3(living_player_pos) points: List[Tuple[float, ba.Vec3]] = [] for team in self.teams: - start_pos = ba.Vec3( - self.map.get_start_position(team.get_id())) + start_pos = ba.Vec3(self.map.get_start_position(team.id)) points.append( ((start_pos - player_pos).length(), start_pos)) # Hmm.. we need to sorting vectors too? @@ -492,7 +491,7 @@ class EliminationGame(ba.TeamGameActivity): # Augment standard behavior. super().handlemessage(msg) - player = msg.spaz.player + player = msg.getspaz(self).player player.gamedata['lives'] -= 1 if player.gamedata['lives'] < 0: diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 96e4bba9..f5e630ca 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -67,7 +67,7 @@ class FootballFlag(stdflag.Flag): # ba_meta export game -class FootballTeamGame(ba.TeamGameActivity): +class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Football game for teams mode.""" @classmethod @@ -204,7 +204,7 @@ class FootballTeamGame(ba.TeamGameActivity): if region == self._score_regions[i].node: break for team in self.teams: - if team.get_id() == i: + if team.id == i: team.gamedata['score'] += 7 # Tell all players to celebrate. @@ -274,7 +274,7 @@ class FootballTeamGame(ba.TeamGameActivity): elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.spaz.player) + self.respawn_player(msg.getspaz(self).player) # Respawn dead flags. elif isinstance(msg, stdflag.FlagDeathMessage): @@ -320,7 +320,7 @@ class FootballTeamGame(ba.TeamGameActivity): self._flag = FootballFlag(position=self._flag_spawn_pos) -class FootballCoopGame(ba.CoopGameActivity): +class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): """ Co-op variant of football """ @@ -508,7 +508,11 @@ class FootballCoopGame(ba.CoopGameActivity): # Make a bogus team for our bots. bad_team_name = self.get_team_display_string('Bad Guys') - self._bot_team = ba.Team(1, bad_team_name, (0.5, 0.4, 0.4)) + # self._bot_team = ba.Team(1, bad_team_name, (0.5, 0.4, 0.4)) + self._bot_team = ba.Team() + self._bot_team.id = 1 + self._bot_team.name = bad_team_name + self._bot_team.color = (0.5, 0.4, 0.4) for team in [self.teams[0], self._bot_team]: team.gamedata['score'] = 0 @@ -562,7 +566,7 @@ class FootballCoopGame(ba.CoopGameActivity): spaz_type: Type[spazbot.SpazBot], immediate: bool = False) -> None: assert self._bot_team is not None - pos = self.map.get_start_position(self._bot_team.get_id()) + pos = self.map.get_start_position(self._bot_team.id) self._bots.spawn_bot(spaz_type, pos=pos, spawn_time=0.001 if immediate else 3.0, @@ -668,7 +672,7 @@ class FootballCoopGame(ba.CoopGameActivity): for team in [self.teams[0], self._bot_team]: assert team is not None - if team.get_id() == i: + if team.id == i: team.gamedata['score'] += 7 # Tell all players (or bots) to celebrate. @@ -808,7 +812,7 @@ class FootballCoopGame(ba.CoopGameActivity): from bastd.actor import respawnicon # Respawn dead players. - player = msg.spaz.player + player = msg.getspaz(self).player self.stats.player_was_killed(player) assert self.initial_player_info is not None respawn_time = 2.0 + len(self.initial_player_info) * 1.0 @@ -871,7 +875,7 @@ class FootballCoopGame(ba.CoopGameActivity): def spawn_player(self, player: ba.Player) -> ba.Actor: spaz = self.spawn_player_spaz(player, position=self.map.get_start_position( - player.team.get_id())) + player.team.id)) if self._preset in ['rookie_easy', 'pro_easy', 'uber_easy']: spaz.impact_scale = 0.25 spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index b530cfc8..daa2b354 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -100,14 +100,13 @@ class Puck(ba.Actor): if activity: if msg.source_player in activity.players: self.last_players_to_touch[ - msg.source_player.team.get_id( - )] = msg.source_player + msg.source_player.team.id] = msg.source_player else: super().handlemessage(msg) # ba_meta export game -class HockeyGame(ba.TeamGameActivity): +class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Ice hockey game.""" @classmethod @@ -255,8 +254,10 @@ class HockeyGame(ba.TeamGameActivity): player = playernode.getdelegate().getplayer() except Exception: player = puck = None + assert isinstance(player, ba.Player) + assert isinstance(puck, Puck) if player and puck: - puck.last_players_to_touch[player.team.get_id()] = player + puck.last_players_to_touch[player.team.id] = player def _kill_puck(self) -> None: self._puck = None @@ -279,7 +280,7 @@ class HockeyGame(ba.TeamGameActivity): break for team in self.teams: - if team.get_id() == index: + if team.id == index: scoring_team = team team.gamedata['score'] += 1 @@ -290,13 +291,12 @@ class HockeyGame(ba.TeamGameActivity): # If we've got the player from the scoring team that last # touched us, give them points. - if (scoring_team.get_id() in self._puck.last_players_to_touch - and self._puck.last_players_to_touch[ - scoring_team.get_id()]): - self.stats.player_scored(self._puck.last_players_to_touch[ - scoring_team.get_id()], - 100, - big_message=True) + if (scoring_team.id in self._puck.last_players_to_touch + and self._puck.last_players_to_touch[scoring_team.id]): + self.stats.player_scored( + self._puck.last_players_to_touch[scoring_team.id], + 100, + big_message=True) # End game if we won. if team.gamedata['score'] >= self.settings_raw['Score to Win']: @@ -341,7 +341,7 @@ class HockeyGame(ba.TeamGameActivity): if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior... super().handlemessage(msg) - self.respawn_player(msg.spaz.player) + self.respawn_player(msg.getspaz(self).player) # Respawn dead pucks. elif isinstance(msg, PuckDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 2b17c606..2a8839e9 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -37,7 +37,7 @@ if TYPE_CHECKING: # ba_meta export game -class KeepAwayGame(ba.TeamGameActivity): +class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Game where you try to keep the flag away from your enemies.""" FLAG_NEW = 0 @@ -271,7 +271,7 @@ class KeepAwayGame(ba.TeamGameActivity): if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.spaz.player) + self.respawn_player(msg.getspaz(self).player) elif isinstance(msg, stdflag.FlagDeathMessage): self._spawn_flag() elif isinstance( diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 024589ba..3d0f5d8a 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -39,7 +39,7 @@ if TYPE_CHECKING: # ba_meta export game -class KingOfTheHillGame(ba.TeamGameActivity): +class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Game where a team wins by holding a 'hill' for a set amount of time.""" FLAG_NEW = 0 @@ -281,7 +281,7 @@ class KingOfTheHillGame(ba.TeamGameActivity): super().handlemessage(msg) # Augment default. # No longer can count as at_flag once dead. - player = msg.spaz.player + player = msg.getspaz(self).player player.gamedata['at_flag'] = 0 self._update_flag_state() self.respawn_player(player) diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index c757cbc4..e87e6249 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -26,26 +26,31 @@ from __future__ import annotations import random -from dataclasses import dataclass from typing import TYPE_CHECKING import ba from bastd.actor.bomb import Bomb from bastd.actor.playerspaz import PlayerSpazDeathMessage +from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: from typing import Any, Tuple, Sequence, Optional, List, Dict, Type, Type - from bastd.actor.onscreentimer import OnScreenTimer -@dataclass -class PlayerData(ba.BasePlayerData): - """Data we store per player.""" - death_time: Optional[float] = None +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + super().__init__() + self.death_time: Optional[float] = None + + +class Team(ba.Team[Player]): + """Our team type for this game.""" # ba_meta export game -class MeteorShowerGame(ba.TeamGameActivity): +class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): """Minigame involving dodging falling bombs.""" @classmethod @@ -80,6 +85,9 @@ class MeteorShowerGame(ba.TeamGameActivity): or issubclass(sessiontype, ba.FreeForAllSession) or issubclass(sessiontype, ba.CoopSession)) + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True + def __init__(self, settings: Dict[str, Any]): super().__init__(settings) @@ -94,12 +102,7 @@ class MeteorShowerGame(ba.TeamGameActivity): if self._epic_mode: self.slow_motion = True - # Print messages when players die (since its meaningful in this game). - self.announce_player_deaths = True - def on_begin(self) -> None: - from bastd.actor.onscreentimer import OnScreenTimer - super().on_begin() # Drop a wave every few seconds.. and every so often drop the time @@ -122,22 +125,23 @@ class MeteorShowerGame(ba.TeamGameActivity): # Check for immediate end (if we've only got 1 player, etc). ba.timer(5.0, self._check_end_game) - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: Player) -> None: # Don't allow joining after we start # (would enable leave/rejoin tomfoolery). if self.has_begun(): - ba.screenmessage(ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', - player.get_name(full=True))]), - color=(0, 1, 0)) + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.get_name(full=True))]), + color=(0, 1, 0), + ) # For score purposes, mark them as having died right as the # game started. assert self._timer is not None - PlayerData.get(player).death_time = self._timer.getstarttime() + player.death_time = self._timer.getstarttime() return self.spawn_player(player) - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: Player) -> None: # Augment default behavior. super().on_player_leave(player) @@ -145,7 +149,7 @@ class MeteorShowerGame(ba.TeamGameActivity): self._check_end_game() # overriding the default character spawning.. - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: spaz = self.spawn_player_spaz(player) # Let's reconnect this player's controls to this @@ -168,7 +172,8 @@ class MeteorShowerGame(ba.TeamGameActivity): curtime = ba.time() # Record the player's moment of death. - PlayerData.get(msg.spaz.player).death_time = curtime + # assert isinstance(msg.spaz.player + msg.getspaz(self).player.death_time = curtime # In co-op mode, end the game the instant everyone dies # (more accurate looking). @@ -250,19 +255,18 @@ class MeteorShowerGame(ba.TeamGameActivity): # (these per-player scores are only meaningful in team-games) for team in self.teams: for player in team.players: - playerdata = PlayerData.get(player) survived = False # Throw an extra fudge factor in so teams that # didn't die come out ahead of teams that did. - if playerdata.death_time is None: + if player.death_time is None: survived = True - playerdata.death_time = cur_time + 1 + player.death_time = cur_time + 1 # Award a per-player score depending on how many seconds # they lasted (per-player scores only affect teams mode; # everywhere else just looks at the per-team score). - score = int(playerdata.death_time - self._timer.getstarttime()) + score = int(player.death_time - self._timer.getstarttime()) if survived: score += 50 # A bit extra for survivors. self.stats.player_scored(player, score, screenmessage=False) @@ -284,10 +288,9 @@ class MeteorShowerGame(ba.TeamGameActivity): # that team. longest_life = 0.0 for player in team.players: - playerdata = PlayerData.get(player) - assert playerdata.death_time is not None + assert player.death_time is not None longest_life = max(longest_life, - playerdata.death_time - start_time) + player.death_time - start_time) # Submit the score value in milliseconds. results.set_team_score(team, int(1000.0 * longest_life)) diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 2cf667b9..24a262b9 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -38,7 +38,7 @@ if TYPE_CHECKING: # ba_meta export game -class NinjaFightGame(ba.TeamGameActivity): +class NinjaFightGame(ba.TeamGameActivity[ba.Player, ba.Team]): """ A co-op game where you try to defeat a group of Ninjas as fast as possible @@ -148,7 +148,7 @@ class NinjaFightGame(ba.TeamGameActivity): # A player has died. if isinstance(msg, playerspaz.PlayerSpazDeathMessage): super().handlemessage(msg) # do standard stuff - self.respawn_player(msg.spaz.player) # kick off a respawn + self.respawn_player(msg.getspaz(self).player) # kick off a respawn # A spaz-bot has died. elif isinstance(msg, spazbot.SpazBotDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 50648987..88d62efa 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -38,7 +38,7 @@ if TYPE_CHECKING: from bastd.actor.scoreboard import Scoreboard -class OnslaughtGame(ba.CoopGameActivity): +class OnslaughtGame(ba.CoopGameActivity[ba.Player, ba.Team]): """Co-op game where players try to survive attacking waves of enemies.""" tips: List[Union[str, Dict[str, Any]]] = [ @@ -1163,7 +1163,7 @@ class OnslaughtGame(ba.CoopGameActivity): elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): super().handlemessage(msg) # Augment standard behavior. - player = msg.spaz.getplayer() + player = msg.getspaz(self).getplayer() assert player is not None self._a_player_has_been_hurt = True diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 2fac27bb..89eb04aa 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -67,7 +67,7 @@ class RaceRegion(ba.Actor): # ba_meta export game -class RaceGame(ba.TeamGameActivity): +class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Game of racing around a track.""" @classmethod @@ -733,7 +733,7 @@ class RaceGame(ba.TeamGameActivity): if isinstance(msg, PlayerSpazDeathMessage): # Augment default behavior. super().handlemessage(msg) - player = msg.spaz.getplayer() + player = msg.getspaz(self).getplayer() if not player: ba.print_error('got no player in PlayerSpazDeathMessage') return diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 0ea9dc1c..5c6e2f06 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -38,7 +38,7 @@ if TYPE_CHECKING: from typing import Type, Any, List, Dict, Tuple, Sequence, Optional -class RunaroundGame(ba.CoopGameActivity): +class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): """Game involving trying to bomb bots as they walk through the map.""" tips = [ @@ -48,7 +48,7 @@ class RunaroundGame(ba.CoopGameActivity): ] # How fast our various bot types walk. - _bot_speed_map = { + _bot_speed_map: Dict[Type[spazbot.SpazBot], float] = { spazbot.BomberBot: 0.48, spazbot.BomberBotPro: 0.48, spazbot.BomberBotProShielded: 0.48, @@ -1127,7 +1127,7 @@ class RunaroundGame(ba.CoopGameActivity): elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): from bastd.actor import respawnicon self._a_player_has_been_killed = True - player = msg.spaz.getplayer() + player = msg.getspaz(self).getplayer() if player is None: ba.print_error('FIXME: getplayer() should no' ' longer ever be returning None') diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 61c2e0c0..ad3d1fce 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -38,7 +38,7 @@ if TYPE_CHECKING: # ba_meta export game -class TargetPracticeGame(ba.TeamGameActivity): +class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Game where players try to hit targets with bombs.""" @classmethod @@ -187,7 +187,7 @@ class TargetPracticeGame(ba.TeamGameActivity): # When players die, respawn them. if isinstance(msg, playerspaz.PlayerSpazDeathMessage): super().handlemessage(msg) # Do standard stuff. - player = msg.spaz.getplayer() + player = msg.getspaz(self).getplayer() assert player is not None self.respawn_player(player) # Kick off a respawn. elif isinstance(msg, Target.TargetHitMessage): diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index ff6a5b94..a59fbbec 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -35,7 +35,7 @@ if TYPE_CHECKING: from bastd.actor.scoreboard import Scoreboard -class TheLastStandGame(ba.CoopGameActivity): +class TheLastStandGame(ba.CoopGameActivity[ba.Player, ba.Team]): """Slow motion how-long-can-you-last game.""" tips = [ @@ -257,7 +257,7 @@ class TheLastStandGame(ba.CoopGameActivity): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, playerspaz.PlayerSpazDeathMessage): - player = msg.spaz.getplayer() + player = msg.getspaz(self).getplayer() if player is None: ba.print_error('FIXME: getplayer() should no longer ' 'ever be returning None.') diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index ff81f237..ad071ec1 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -27,9 +27,9 @@ import time import weakref from typing import TYPE_CHECKING -import _ba import ba from bastd.actor import spaz +import _ba if TYPE_CHECKING: from typing import Any, List, Optional @@ -43,7 +43,7 @@ if TYPE_CHECKING: # noinspection PyAttributeOutsideInit -class MainMenuActivity(ba.Activity): +class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): """Activity showing the rotating main menu bg stuff.""" _stdassets = ba.Dependency(ba.AssetPackage, 'stdassets@1') @@ -358,7 +358,7 @@ class MainMenuActivity(ba.Activity): # need to make nodes and stuff.. should fix the serverget # call so it. activity = self._activity() - if activity is None or activity.is_expired(): + if activity is None or activity.expired: return with ba.Context(activity): @@ -830,7 +830,7 @@ class MainMenuActivity(ba.Activity): def _start_preloads(self) -> None: # FIXME: The func that calls us back doesn't save/restore state # or check for a dead activity so we have to do that ourself. - if self.is_expired(): + if self.expired: return with ba.Context(self): _preload1() @@ -929,6 +929,6 @@ class MainMenuSession(ba.Session): # Any ending activity leads us into the main menu one. self.set_activity(ba.new_activity(MainMenuActivity)) - def on_player_request(self, player: ba.Player) -> bool: + def on_player_request(self, player: ba.SessionPlayer) -> bool: # Reject all player requests. return False diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index ff912995..0aca2a2f 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -181,7 +181,7 @@ class ButtonRelease: timeformat=ba.TimeFormat.MILLISECONDS) -class TutorialActivity(ba.Activity): +class TutorialActivity(ba.Activity[ba.Player, ba.Team]): def __init__(self, settings: Dict[str, Any] = None): from bastd.maps import Rampage diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index 926043b5..969d5884 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -31,22 +31,19 @@ from pathlib import Path from threading import Lock, Thread, current_thread from typing import TYPE_CHECKING +# We make use of the bacommon and efro packages as well as site-packages +# included with our bundled Ballistica dist, so we need to add those paths +# before we import them. +sys.path += [ + str(Path(Path(__file__).parent, 'dist', 'ba_data', 'python')), + str(Path(Path(__file__).parent, 'dist', 'ba_data', 'python-site-packages')) +] + from bacommon.servermanager import ServerConfig, StartServerModeCommand from efro.dataclasses import dataclass_assign, dataclass_validate from efro.error import CleanError from efro.terminal import Clr -# We change our working directory according to file's path -# so that the script can be properly executed from anywhere -os.chdir(os.path.abspath(os.path.dirname(__file__))) - -# We make use of the bacommon and efro packages as well as site-packages -# included with our bundled Ballistica dist. -sys.path += [ - str(Path(os.getcwd(), 'dist', 'ba_data', 'python')), - str(Path(os.getcwd(), 'dist', 'ba_data', 'python-site-packages')) -] - if TYPE_CHECKING: from typing import Optional, List, Dict, Union, Tuple from types import FrameType @@ -54,7 +51,7 @@ if TYPE_CHECKING: # Not sure how much versioning we'll do with this, but this will get # printed at startup in case we need it. -VERSION_STR = '1.0' +VERSION_STR = '1.0.1' class ServerManagerApp: @@ -432,6 +429,10 @@ class ServerManagerApp: def main() -> None: """Run a BallisticaCore server manager in interactive mode.""" try: + # Change our working directory according to file's path + # so that this script can be run from anywhere. + os.chdir(os.path.abspath(os.path.dirname(__file__))) + ServerManagerApp().run_interactive() except CleanError as exc: # For clean errors, do a simple print and fail; no tracebacks/etc. diff --git a/config/toolconfigsrc/mypy.ini b/config/toolconfigsrc/mypy.ini index 299b6668..249b3f67 100644 --- a/config/toolconfigsrc/mypy.ini +++ b/config/toolconfigsrc/mypy.ini @@ -3,6 +3,21 @@ mypy_path = __EFRO_PROJECT_ROOT__/tools:__EFRO_PROJECT_ROOT__/assets/src/ba_data __EFRO_MYPY_STANDARD_SETTINGS__ +# We have mypy alert us if we use any vars that have been imported +# by other modules; we want to import everything directly from its +# source. However there are some modules that are explicitly exist +# to reexport things, so let's let those pass. +# (we could also set __all__ in those modules, but that's a lot of +# repeating ourself) +[mypy-ba] +no_implicit_reexport = False +[mypy-efro.entity] +no_implicit_reexport = False +[mypy-ba.internal] +no_implicit_reexport = False +[mypy-ba.deprecated] +no_implicit_reexport = False + [mypy-pylint.*] ignore_missing_imports = True diff --git a/config/toolconfigsrc/pylintrc b/config/toolconfigsrc/pylintrc index 8d17ef52..89e19ab4 100644 --- a/config/toolconfigsrc/pylintrc +++ b/config/toolconfigsrc/pylintrc @@ -79,6 +79,7 @@ good-names=i, v2, ex, Run, + id, T, S, U, diff --git a/docs/ba_module.md b/docs/ba_module.md index 992a54ea..9e6cd0d2 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

      last updated on 2020-05-07 for Ballistica version 1.5.0 build 20018

      +

      last updated on 2020-05-18 for Ballistica version 1.5.0 build 20021

      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!


      @@ -19,14 +19,12 @@
    • ba.Map
    • ba.NodeActor
    -
  • ba.BasePlayerData
  • ba.Chooser
  • ba.InputDevice
  • ba.Level
  • ba.Lobby
  • ba.Material
  • ba.Node
  • -
  • ba.Player
  • ba.PlayerRecord
  • ba.ScoreInfo
  • ba.Session
  • @@ -38,8 +36,9 @@
  • ba.FreeForAllSession
  • +
  • ba.SessionPlayer
  • +
  • ba.SessionTeam
  • ba.Stats
  • -
  • ba.Team
  • ba.TeamGameResults
  • Gameplay Functions

    @@ -54,6 +53,8 @@
  • ba.getnodes()
  • ba.getsession()
  • ba.newnode()
  • +
  • ba.playercast()
  • +
  • ba.playercast_o()
  • ba.playsound()
  • ba.printnodes()
  • ba.setmusic()
  • @@ -189,10 +190,17 @@
  • ba.NodeNotFoundError
  • ba.PlayerNotFoundError
  • ba.SessionNotFoundError
  • +
  • ba.SessionPlayerNotFoundError
  • +
  • ba.SessionTeamNotFoundError
  • ba.TeamNotFoundError
  • ba.WidgetNotFoundError
  • +

    Misc Classes

    +

    ba.Achievement

    <top level class> @@ -313,7 +321,7 @@ actually award achievements.


    ba.Activity

    -

    inherits from: ba.DependencyComponent

    +

    inherits from: ba.DependencyComponent, typing.Generic

    Units of execution wrangled by a ba.Session.

    Category: Gameplay Classes

    @@ -323,14 +331,28 @@ actually award achievements.

    can overlap during transitions.

    Attributes:

    -
    players, session, settings_raw, stats, teams
    +
    expired, players, playertype, session, settings_raw, stats, teams, teamtype
    +

    expired

    +

    bool

    +

    Whether the activity is expired.

    + +

    An activity is set as expired when shutting down. + At this point no new nodes, timers, etc should be made, + run, etc, and the activity should be considered a 'zombie'.

    + +

    players

    -

    List[ba.Player]

    +

    List[PlayerType]

    The list of ba.Players in the Activity. This gets populated just before on_begin() is called and is updated automatically as players join or leave the game.

    +
    +

    playertype

    +

    Type[PlayerType]

    +

    The type of ba.Player this Activity is using.

    +

    session

    ba.Session

    @@ -355,24 +377,29 @@ passed to the Activity __init__ call.

    teams

    -

    List[ba.Team]

    +

    List[TeamType]

    The list of ba.Teams in the Activity. This gets populated just before before on_begin() is called and is updated automatically as players join or leave the game. (at least in free-for-all mode where every player gets their own team; in teams mode there are always 2 teams regardless of the player count).

    +
    +

    teamtype

    +

    Type[TeamType]

    +

    The type of ba.Team this Activity is using.

    +

    Methods Inherited:

    dep_is_present(), get_dynamic_deps()

    Methods Defined or Overridden:

    -
    <constructor>, add_actor_weak_ref(), create_player_node(), end(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), on_begin(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), retain_actor()
    +
    <constructor>, add_actor_weak_ref(), create_player(), create_team(), end(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_begin(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), retain_actor(), transition_out()

    <constructor>

    ba.Activity(settings: Dict[str, Any])

    -

    Creates an activity in the current ba.Session.

    +

    Creates an Activity in the current ba.Session.

    The activity will not be actually run until ba.Session.set_activity() is called. 'settings' should be a dict of key/value pairs specific @@ -391,10 +418,28 @@ are transitioned in.

    (called by the ba.Actor base class)

    -

    create_player_node()

    -

    create_player_node(self, player: ba.Player) -> ba.Node

    +

    create_player()

    +

    create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType

    -

    Create the 'player' node associated with the provided ba.Player.

    +

    Create the Player instance for this Activity.

    + +

    Subclasses can override this if the activity's player class +requires a custom constructor; otherwise it will be called with +no args. Note that the player object should not be used at this +point as it is not yet fully wired up; wait for on_player_join() +for that.

    + +
    +

    create_team()

    +

    create_team(self, sessionteam: ba.SessionTeam) -> TeamType

    + +

    Create the Team instance for this Activity.

    + +

    Subclasses can override this if the activity's team class +requires a custom constructor; otherwise it will be called with +no args. Note that the team object should not be used at this +point as it is not yet fully wired up; wait for on_team_join() +for that.

    end()

    @@ -431,16 +476,6 @@ will replace the old.

    Return whether on_transition_in() has been called.

    -
    -

    is_expired()

    -

    is_expired(self) -> bool

    - -

    Return whether the activity is expired.

    - -

    An activity is set as expired when shutting down. -At this point no new nodes, timers, etc should be made, -run, etc, and the activity should be considered a 'zombie'.

    -

    is_transitioning_out()

    is_transitioning_out(self) -> bool

    @@ -470,7 +505,7 @@ can begin.

    on_player_join()

    -

    on_player_join(self, player: ba.Player) -> None

    +

    on_player_join(self, player: PlayerType) -> None

    Called when a new ba.Player has joined the Activity.

    @@ -478,13 +513,13 @@ can begin.

    on_player_leave()

    -

    on_player_leave(self, player: ba.Player) -> None

    +

    on_player_leave(self, player: PlayerType) -> None

    Called when a ba.Player is leaving the Activity.

    on_team_join()

    -

    on_team_join(self, team: ba.Team) -> None

    +

    on_team_join(self, team: TeamType) -> None

    Called when a new ba.Team joins the Activity.

    @@ -492,7 +527,7 @@ can begin.

    on_team_leave()

    -

    on_team_leave(self, team: ba.Team) -> None

    +

    on_team_leave(self, team: TeamType) -> None

    Called when a ba.Team leaves the Activity.

    @@ -503,8 +538,8 @@ can begin.

    Called when the Activity is first becoming visible.

    Upon this call, the Activity should fade in backgrounds, -start playing music, etc. It does not yet have access to ba.Players -or ba.Teams, however. They remain owned by the previous Activity +start playing music, etc. It does not yet have access to players +or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called.

    @@ -513,7 +548,7 @@ up until ba.Activity.on_begin() is c

    Called when your activity begins transitioning out.

    -

    Note that this may happen at any time even if finish() has not been +

    Note that this may happen at any time even if end() has not been called.

    @@ -526,6 +561,12 @@ called.

    returns False for the Actor. The ba.Actor.autoretain() method is a convenient way to access this same functionality.

    + +

    transition_out()

    +

    transition_out(self) -> None

    + +

    Called by the Session to start us transitioning out.

    +

    @@ -588,6 +629,7 @@ is a convenient way to access this same functionality.

    Attributes:

    +
    activity, expired

    activity

    ba.Activity

    @@ -595,10 +637,17 @@ is a convenient way to access this same functionality.

    Raises a ba.ActivityNotFoundError if the Activity no longer exists.

    +
    +

    expired

    +

    bool

    +

    Whether the Actor is expired.

    + +

    (see ba.Actor.on_expire())

    +

    Methods:

    -
    <constructor>, autoretain(), exists(), getactivity(), handlemessage(), is_alive(), is_expired(), on_expire()
    +
    <constructor>, autoretain(), exists(), getactivity(), handlemessage(), is_alive(), on_expire()

    <constructor>

    ba.Actor()

    @@ -665,14 +714,6 @@ It is not a requirement for Actors to be able to die; just that they report whether they are Alive or not.

    -
    -

    is_expired()

    -

    is_expired(self) -> bool

    - -

    Returns whether the Actor is expired.

    - -

    (see ba.Actor.on_expire())

    -

    on_expire()

    on_expire(self) -> None

    @@ -684,7 +725,7 @@ or other references which have the potential of keeping the ba.Activity alive inadvertently (Activities can not exit cleanly while any Python references to them remain.)

    -

    Once an actor is expired (see ba.Actor.is_expired()) it should no +

    Once an actor is expired (see ba.Actor.is_expired()) it should no longer perform any game-affecting operations (creating, modifying, or deleting nodes, media, timers, etc.) Attempts to do so will likely result in errors.

    @@ -1086,31 +1127,6 @@ when done.

    Behavior is similar to ba.gettexture()

    -
    -
    -
    -

    ba.BasePlayerData

    -

    <top level class> -

    -

    Base class for custom player data.

    - -

    Category: Gameplay Classes

    - -

    A convenience class that can be used as a base class for custom - per-game player data. It simply provides the ability to easily fetch - an instance of itself for a given ba.Player. -

    - -

    Methods:

    -
    -

    get()

    -
    <class method>
    -

    get(player: ba.Player) -> T

    - -

    Return the custom player data associated with a player.

    - -

    If one does not exist, it will be created.

    -

    @@ -1261,7 +1277,7 @@ mycall()

    player

    -

    ba.Player

    +

    ba.SessionPlayer

    The ba.Player associated with this chooser.

    @@ -1275,7 +1291,7 @@ mycall()
    <constructor>, get_character_name(), get_color(), get_highlight(), get_lobby(), get_team(), getplayer(), handlemessage(), reload_profiles(), update_from_player_profiles(), update_position()

    <constructor>

    -

    ba.Chooser(vpos: float, player: _ba.Player, lobby: "Lobby")

    +

    ba.Chooser(vpos: float, player: _ba.SessionPlayer, lobby: "Lobby")

    get_character_name()

    @@ -1303,13 +1319,13 @@ mycall()

    get_team()

    -

    get_team(self) -> ba.Team

    +

    get_team(self) -> ba.SessionTeam

    Return this chooser's selected ba.Team.

    getplayer()

    -

    getplayer(self) -> ba.Player

    +

    getplayer(self) -> ba.SessionPlayer

    Return the player associated with this chooser.

    @@ -1450,7 +1466,7 @@ start_long_action(callback_when_done=ba.ContextC

    ba.CoopGameActivity

    -

    inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent

    +

    inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent, typing.Generic

    Base class for cooperative-mode games.

    Category: Gameplay Classes @@ -1459,14 +1475,28 @@ start_long_action(callback_when_done=ba.ContextC

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    map, session, stats
    +
    expired, map, playertype, session, stats, teamtype
    +

    expired

    +

    bool

    +

    Whether the activity is expired.

    + +

    An activity is set as expired when shutting down. + At this point no new nodes, timers, etc should be made, + run, etc, and the activity should be considered a 'zombie'.

    + +

    map

    ba.Map

    The map being used for this game.

    Raises a ba.NotFoundError if the map does not currently exist.

    +
    +

    playertype

    +

    Type[PlayerType]

    +

    The type of ba.Player this Activity is using.

    +

    session

    ba.Session

    @@ -1481,10 +1511,15 @@ start_long_action(callback_when_done=ba.ContextC

    If access is attempted before or after, raises a ba.NotFoundError.

    +
    +

    teamtype

    +

    Type[TeamType]

    +

    The type of ba.Team this Activity is using.

    +

    Methods Inherited:

    -
    add_actor_weak_ref(), begin(), continue_or_end_game(), create_config_ui(), create_player_node(), dep_is_present(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), start_transition_in()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -1532,7 +1567,7 @@ and it should begin its actual game logic.

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: ba.Player, position: Sequence[float] = (0.0, 0.0, 0.0), angle: float = None) -> PlayerSpaz

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0.0, 0.0, 0.0), angle: float = None) -> PlayerSpaz

    Spawn and wire up a standard player spaz.

    @@ -1596,9 +1631,9 @@ is pressed.

    on_player_leave()

    -

    on_player_leave(self, player: ba.Player) -> None

    +

    on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None

    -

    Called when a previously-accepted ba.Player leaves the session.

    +

    Called when a previously-accepted ba.SessionPlayer leaves.

    restart()

    @@ -1953,7 +1988,7 @@ its time with lingering corpses, sound effects, etc.


    ba.GameActivity

    -

    inherits from: ba.Activity, ba.DependencyComponent

    +

    inherits from: ba.Activity, ba.DependencyComponent, typing.Generic

    Common base class for all game ba.Activities.

    Category: Gameplay Classes @@ -1962,14 +1997,28 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    map, session, stats
    +
    expired, map, playertype, session, stats, teamtype
    +

    expired

    +

    bool

    +

    Whether the activity is expired.

    + +

    An activity is set as expired when shutting down. + At this point no new nodes, timers, etc should be made, + run, etc, and the activity should be considered a 'zombie'.

    + +

    map

    ba.Map

    The map being used for this game.

    Raises a ba.NotFoundError if the map does not currently exist.

    +
    +

    playertype

    +

    Type[PlayerType]

    +

    The type of ba.Player this Activity is using.

    +

    session

    ba.Session

    @@ -1984,10 +2033,15 @@ its time with lingering corpses, sound effects, etc.

    If access is attempted before or after, raises a ba.NotFoundError.

    +
    +

    teamtype

    +

    Type[TeamType]

    +

    The type of ba.Team this Activity is using.

    +

    Methods Inherited:

    -
    add_actor_weak_ref(), begin(), create_player_node(), dep_is_present(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), retain_actor(), set_has_ended(), set_immediate_end(), start_transition_in()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), set_immediate_end(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, continue_or_end_game(), create_config_ui(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    @@ -2274,7 +2328,7 @@ whatever is relevant to keep the game going.

    on_player_join()

    -

    on_player_join(self, player: ba.Player) -> None

    +

    on_player_join(self, player: PlayerType) -> None

    Called when a new ba.Player has joined the Activity.

    @@ -2282,7 +2336,7 @@ whatever is relevant to keep the game going.

    on_player_leave()

    -

    on_player_leave(self, player: ba.Player) -> None

    +

    on_player_leave(self, player: PlayerType) -> None

    Called when a ba.Player is leaving the Activity.

    @@ -2293,8 +2347,8 @@ whatever is relevant to keep the game going.

    Called when the Activity is first becoming visible.

    Upon this call, the Activity should fade in backgrounds, -start playing music, etc. It does not yet have access to ba.Players -or ba.Teams, however. They remain owned by the previous Activity +start playing music, etc. It does not yet have access to players +or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called.

    @@ -2308,7 +2362,7 @@ movable flag originated from.

    respawn_player()

    -

    respawn_player(self, player: ba.Player, respawn_time: Optional[float] = None) -> None

    +

    respawn_player(self, player: PlayerType, respawn_time: Optional[float] = None) -> None

    Given a ba.Player, sets up a standard respawn timer, along with the standard counter display, etc. @@ -2355,7 +2409,7 @@ and short description of the game.

    spawn_player()

    -

    spawn_player(self, player: ba.Player) -> ba.Actor

    +

    spawn_player(self, player: PlayerType) -> ba.Actor

    Spawn *something* for the provided ba.Player.

    @@ -2363,7 +2417,7 @@ and short description of the game.

    spawn_player_if_exists()

    -

    spawn_player_if_exists(self, player: ba.Player) -> None

    +

    spawn_player_if_exists(self, player: PlayerType) -> None

    A utility method which calls self.spawn_player() *only* if the ba.Player provided still exists; handy for use in timers and whatnot.

    @@ -2372,7 +2426,7 @@ and short description of the game.

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: ba.Player, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz

    Create and wire up a ba.PlayerSpaz for the provided ba.Player.

    @@ -2485,7 +2539,7 @@ client.

    player

    -

    Optional[ba.Player]

    +

    Optional[ba.SessionPlayer]

    The player associated with this input device.

    @@ -2656,7 +2710,7 @@ can be changed to separate its new high score lists/etc. from the old.

    teams, use_team_colors

    teams

    -

    List[ba.Team]

    +

    List[ba.SessionTeam]

    Teams available in this lobby.

    @@ -2676,7 +2730,7 @@ can be changed to separate its new high score lists/etc. from the old.

    add_chooser()

    -

    add_chooser(self, player: ba.Player) -> None

    +

    add_chooser(self, player: ba.SessionPlayer) -> None

    Add a chooser to the lobby for the provided player.

    @@ -2723,7 +2777,7 @@ Intended for use in initial joining-screens.

    remove_chooser()

    -

    remove_chooser(self, player: ba.Player) -> None

    +

    remove_chooser(self, player: ba.SessionPlayer) -> None

    Remove a single player's chooser; does not kick him.

    @@ -2826,6 +2880,7 @@ etc.

    Attributes:

    +
    activity, expired

    activity

    ba.Activity

    @@ -2833,10 +2888,17 @@ etc.

    Raises a ba.ActivityNotFoundError if the Activity no longer exists.

    +
    +

    expired

    +

    bool

    +

    Whether the Actor is expired.

    + +

    (see ba.Actor.on_expire())

    +

    Methods Inherited:

    -
    autoretain(), getactivity(), is_alive(), is_expired(), on_expire()
    +
    autoretain(), getactivity(), is_alive(), on_expire()

    Methods Defined or Overridden:

    <constructor>, exists(), get_def_bound_box(), get_def_point(), get_def_points(), get_ffa_start_position(), get_flag_position(), get_music_type(), get_name(), get_play_types(), get_preview_texture_name(), get_start_position(), handlemessage(), is_point_near_edge(), on_preload(), preload()
    @@ -3237,7 +3299,7 @@ another ba.Activity.

    on_team_join()

    -

    on_team_join(self, team: ba.Team) -> None

    +

    on_team_join(self, team: ba.SessionTeam) -> None

    Called when a new ba.Team joins the session.

    @@ -3493,6 +3555,7 @@ acting as an alternative to setting node attributes.

    Attributes:

    +
    activity, expired

    activity

    ba.Activity

    @@ -3500,10 +3563,17 @@ acting as an alternative to setting node attributes.

    Raises a ba.ActivityNotFoundError if the Activity no longer exists.

    +
    +

    expired

    +

    bool

    +

    Whether the Actor is expired.

    + +

    (see ba.Actor.on_expire())

    +

    Methods Inherited:

    -
    autoretain(), getactivity(), is_alive(), is_expired(), on_expire()
    +
    autoretain(), getactivity(), is_alive(), on_expire()

    Methods Defined or Overridden:

    <constructor>, exists(), handlemessage()
    @@ -3636,101 +3706,45 @@ even if myactor is set to None.


    ba.Player

    -

    <top level class> -

    -

    A reference to a player in the game.

    - -

    Category: Gameplay Classes

    - -

    These are created and managed internally and -provided to your Session/Activity instances. -Be aware that, like ba.Nodes, ba.Player objects are 'weak' -references under-the-hood; a player can leave the game at - any point. For this reason, you should make judicious use of the -ba.Player.exists attribute (or boolean operator) to ensure that a -Player is still present if retaining references to one for any -length of time.

    +

    inherits from: typing.Generic

    +

    Testing.

    Attributes:

    -
    actor, character, color, exists, gamedata, highlight, in_game, node, sessiondata, team
    +
    exists, node, sessionplayer
    -

    actor

    -

    Optional[ba.Actor]

    -

    The current ba.Actor associated with this Player. -This may be None

    - -
    -

    character

    -

    str

    -

    The character this player has selected in their profile.

    - -
    -

    color

    -

    Sequence[float]

    -

    The base color for this Player. -In team games this will match the ba.Team's color.

    - -

    exists

    -

    bool

    -

    Whether the player still exists. -Most functionality will fail on a nonexistent player.

    +

    bool

    +

    Whether the player still exists.

    -

    Note that you can also use the boolean operator for this same -functionality, so a statement such as "if player" will do -the right thing both for Player objects and values of None.

    - -
    -

    gamedata

    -

    Dict

    -

    A dict for use by the current ba.Activity for -storing data associated with this Player. -This gets cleared for each new ba.Activity.

    - -
    -

    highlight

    -

    Sequence[float]

    -

    A secondary color for this player. -This is used for minor highlights and accents -to allow a player to stand apart from his teammates -who may all share the same team (primary) color.

    - -
    -

    in_game

    -

    bool

    -

    This bool value will be True once the Player has completed -any lobby character/team selection.

    +

    Most functionality will fail on a nonexistent player. + Note that you can also use the boolean operator for this same + functionality, so a statement such as "if player" will do + the right thing both for Player objects and values of None.

    node

    -

    Optional[ba.Node]

    -

    A ba.Node of type 'player' associated with this Player. -This Node exists in the currently active game and can be used -to get a generic player position/etc. -This will be None if the Player is not in a game.

    +

    ba.Node

    +

    A ba.Node of type 'player' associated with this Player.

    + +

    This node can be used to get a generic player position/etc.

    -

    sessiondata

    -

    Dict

    -

    A dict for use by the current ba.Session for -storing data associated with this player. -This persists for the duration of the session.

    +

    sessionplayer

    +

    ba.SessionPlayer

    +

    Return the ba.SessionPlayer corresponding to this Player.

    -
    -

    team

    -

    ba.Team

    -

    The ba.Team this Player is on. If the Player is -still in its lobby selecting a team/etc. then a -ba.TeamNotFoundError will be raised.

    +

    Throws a ba.SessionPlayerNotFoundError if it does not exist.

    Methods:

    -
    assign_input_call(), get_account_id(), get_icon(), get_id(), get_input_device(), get_name(), is_alive(), remove_from_game(), reset_input(), set_actor(), set_name()
    +
    assign_input_call(), get_icon(), get_name(), is_alive(), reset_input(), set_actor()

    assign_input_call()

    -

    assign_input_call(type: Union[str, Tuple[str, ...]], - call: Callable) -> None

    +

    assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    + +

    assign_input_call(type: Union[str, Tuple[str, ...]], + call: Callable) -> None

    Set the python callable to be run for one or more types of input. Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', @@ -3740,76 +3754,48 @@ Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', 'startRelease'

    -
    -

    get_account_id()

    -

    get_account_id() -> str

    - -

    Return the Account ID this player is signed in under, if -there is one and it can be determined with relative certainty. -Returns None otherwise. Note that this may require an active -internet connection (especially for network-connected players) -and may return None for a short while after a player initially -joins (while verification occurs).

    -

    get_icon()

    -

    get_icon() -> Dict[str, Any]

    +

    get_icon(self) -> Dict[str, Any]

    + +

    get_icon() -> Dict[str, Any]

    Returns the character's icon (images, colors, etc contained in a dict)

    -
    -

    get_id()

    -

    get_id() -> int

    - -

    Returns the unique numeric player ID for this player.

    - -
    -

    get_input_device()

    -

    get_input_device() -> ba.InputDevice

    - -

    Returns the player's input device.

    -

    get_name()

    -

    get_name(full: bool = False, icon: bool = True) -> str

    +

    get_name(self, full: bool = False, icon: bool = True) -> str

    + +

    get_name(full: bool = False, icon: bool = True) -> str

    Returns the player's name. If icon is True, the long version of the name may include an icon.

    is_alive()

    -

    is_alive() -> bool

    +

    is_alive(self) -> bool

    + +

    is_alive() -> bool

    Returns True if the player has a ba.Actor assigned and its is_alive() method return True. False is returned otherwise.

    -
    -

    remove_from_game()

    -

    remove_from_game() -> None

    - -

    Removes the player from the game.

    -

    reset_input()

    -

    reset_input() -> None

    +

    reset_input(self) -> None

    + +

    reset_input() -> None

    Clears out the player's assigned input actions.

    set_actor()

    -

    set_actor(actor: Optional[ba.Actor]) -> None

    +

    set_actor(self, actor: Optional[ba.Actor]) -> None

    + +

    set_actor(actor: Optional[ba.Actor]) -> None

    Set the player's associated ba.Actor.

    -
    -

    set_name()

    -

    set_name(name: str, full_name: str = None, real: bool = True) - -> None

    - -

    Set the player's name to the provided string. -A number will automatically be appended if the name is not unique from -other players.

    -

    @@ -3839,18 +3825,19 @@ other players.

    player, team

    player

    -

    ba.Player

    -

    Return the instance's associated ba.Player.

    +

    ba.SessionPlayer

    +

    Return the instance's associated ba.SessionPlayer.

    -

    Raises a ba.PlayerNotFoundError if the player no longer exists.

    +

    Raises a ba.SessionPlayerNotFoundError if the player + no longer exists.

    team

    -

    ba.Team

    -

    The ba.Team the last associated player was last on.

    +

    ba.SessionTeam

    +

    The ba.SessionTeam the last associated player was last on.

    This can still return a valid result even if the player is gone. - Raises a ba.TeamNotFoundError if the team no longer exists.

    + Raises a ba.SessionTeamNotFoundError if the team no longer exists.

    @@ -3858,11 +3845,11 @@ other players.

    <constructor>, associate_with_player(), cancel_multi_kill_timer(), get_icon(), get_last_player(), get_name(), getactivity(), submit_kill()

    <constructor>

    -

    ba.PlayerRecord(name: str, name_full: str, player: ba.Player, stats: ba.Stats)

    +

    ba.PlayerRecord(name: str, name_full: str, player: ba.SessionPlayer, stats: ba.Stats)

    associate_with_player()

    -

    associate_with_player(self, player: ba.Player) -> None

    +

    associate_with_player(self, player: ba.SessionPlayer) -> None

    Associate this entry with a ba.Player.

    @@ -3880,7 +3867,7 @@ other players.

    get_last_player()

    -

    get_last_player(self) -> ba.Player

    +

    get_last_player(self) -> ba.SessionPlayer

    Return the last ba.Player we were associated with.

    @@ -4137,14 +4124,14 @@ to proceed past the initial joining screen.

    players

    -

    List[ba.Player]

    +

    List[ba.SessionPlayer]

    All ba.Players in the Session. Most things should use the player list in ba.Activity; not this. Some players, such as those who have not yet selected a character, will only appear on this list.

    teams

    -

    List[ba.Team]

    +

    List[ba.SessionTeam]

    All the ba.Teams in the Session. Most things should use the team list in ba.Activity; not this.

    @@ -4223,13 +4210,13 @@ another ba.Activity.

    on_player_leave()

    -

    on_player_leave(self, player: ba.Player) -> None

    +

    on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None

    -

    Called when a previously-accepted ba.Player leaves the session.

    +

    Called when a previously-accepted ba.SessionPlayer leaves.

    on_player_request()

    -

    on_player_request(self, player: ba.Player) -> bool

    +

    on_player_request(self, player: ba.SessionPlayer) -> bool

    Called when a new ba.Player wants to join the Session.

    @@ -4237,13 +4224,13 @@ another ba.Activity.

    on_team_join()

    -

    on_team_join(self, team: ba.Team) -> None

    +

    on_team_join(self, team: ba.SessionTeam) -> None

    Called when a new ba.Team joins the session.

    on_team_leave()

    -

    on_team_leave(self, team: ba.Team) -> None

    +

    on_team_leave(self, team: ba.SessionTeam) -> None

    Called when a ba.Team is leaving the session.

    @@ -4268,6 +4255,244 @@ session.set_activity(foo) and then ba.newnode

    Category: Exception Classes

    +

    Methods:

    +

    <all methods inherited from ba.NotFoundError>

    +
    +

    ba.SessionPlayer

    +

    <top level class> +

    +

    A reference to a player in the ba.Session.

    + +

    Category: Gameplay Classes

    + +

    These are created and managed internally and +provided to your Session/Activity instances. +Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak' +references under-the-hood; a player can leave the game at + any point. For this reason, you should make judicious use of the +ba.SessionPlayer.exists attribute (or boolean operator) to ensure +that a SessionPlayer is still present if retaining references to one +for any length of time.

    + +

    Attributes:

    +
    character, color, exists, gamedata, gameplayer, highlight, id, in_game, sessiondata, team
    +
    +

    character

    +

    str

    +

    The character this player has selected in their profile.

    + +
    +

    color

    +

    Sequence[float]

    +

    The base color for this Player. +In team games this will match the ba.SessionTeam's color.

    + +
    +

    exists

    +

    bool

    +

    Whether the player still exists. +Most functionality will fail on a nonexistent player.

    + +

    Note that you can also use the boolean operator for this same +functionality, so a statement such as "if player" will do +the right thing both for Player objects and values of None.

    + +
    +

    gamedata

    +

    Dict

    +

    A dict for use by the current ba.Activity for +storing data associated with this Player. +This gets cleared for each new ba.Activity.

    + +
    +

    gameplayer

    +

    Optional[ba.Player]

    +

    The current game-specific instance for this player.

    + +
    +

    highlight

    +

    Sequence[float]

    +

    A secondary color for this player. +This is used for minor highlights and accents +to allow a player to stand apart from his teammates +who may all share the same team (primary) color.

    + +
    +

    id

    +

    int

    +

    The unique numeric ID of the Player.

    + +
    +

    in_game

    +

    bool

    +

    This bool value will be True once the Player has completed +any lobby character/team selection.

    + +
    +

    sessiondata

    +

    Dict

    +

    A dict for use by the current ba.Session for +storing data associated with this player. +This persists for the duration of the session.

    + +
    +

    team

    +

    ba.SessionTeam

    +

    The ba.SessionTeam this Player is on. If the SessionPlayer +is still in its lobby selecting a team/etc. then a +ba.SessionTeamNotFoundError will be raised.

    + +
    +
    +

    Methods:

    +
    assign_input_call(), get_account_id(), get_icon(), get_input_device(), get_name(), remove_from_game(), reset_input(), set_name()
    +
    +

    assign_input_call()

    +

    assign_input_call(type: Union[str, Tuple[str, ...]], + call: Callable) -> None

    + +

    Set the python callable to be run for one or more types of input. +Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', + 'punchRelease','bombPress', 'bombRelease', 'pickUpPress', + 'pickUpRelease', 'upDown','leftRight','upPress', 'upRelease', + 'downPress', 'downRelease', 'leftPress','leftRelease','rightPress', + 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', + 'startRelease'

    + +
    +

    get_account_id()

    +

    get_account_id() -> str

    + +

    Return the Account ID this player is signed in under, if +there is one and it can be determined with relative certainty. +Returns None otherwise. Note that this may require an active +internet connection (especially for network-connected players) +and may return None for a short while after a player initially +joins (while verification occurs).

    + +
    +

    get_icon()

    +

    get_icon() -> Dict[str, Any]

    + +

    Returns the character's icon (images, colors, etc contained in a dict)

    + +
    +

    get_input_device()

    +

    get_input_device() -> ba.InputDevice

    + +

    Returns the player's input device.

    + +
    +

    get_name()

    +

    get_name(full: bool = False, icon: bool = True) -> str

    + +

    Returns the player's name. If icon is True, the long version of the +name may include an icon.

    + +
    +

    remove_from_game()

    +

    remove_from_game() -> None

    + +

    Removes the player from the game.

    + +
    +

    reset_input()

    +

    reset_input() -> None

    + +

    Clears out the player's assigned input actions.

    + +
    +

    set_name()

    +

    set_name(name: str, full_name: str = None, real: bool = True) + -> None

    + +

    Set the player's name to the provided string. +A number will automatically be appended if the name is not unique from +other players.

    + +
    +
    +
    +

    ba.SessionPlayerNotFoundError

    +

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Exception raised when an expected ba.SessionPlayer does not exist.

    + +

    Category: Exception Classes +

    + +

    Methods:

    +

    <all methods inherited from ba.NotFoundError>

    +
    +

    ba.SessionTeam

    +

    <top level class> +

    +

    A team of one or more ba.SessionPlayers.

    + +

    Category: Gameplay Classes

    + +

    Note that a player *always* has a team; + in some cases, such as free-for-all ba.Sessions, + each team consists of just one ba.Player.

    + +

    Attributes:

    +
    color, gamedata, id, name, players, sessiondata
    +
    +

    color

    +

    Tuple[float, ...]

    +

    The team's color.

    + +
    +

    gamedata

    +

    Dict

    +

    A dict for use by the current ba.Activity +for storing data associated with this team. +This gets cleared for each new ba.Activity.

    + +
    +

    id

    +

    int

    +

    The unique numeric id of the team.

    + +
    +

    name

    +

    Union[ba.Lstr, str]

    +

    The team's name.

    + +
    +

    players

    +

    List[ba.SessionPlayer]

    +

    The list of ba.SessionPlayers on the team.

    + +
    +

    sessiondata

    +

    Dict

    +

    A dict for use by the current ba.Session for +storing data associated with this team. +Unlike gamedata, this persists for the duration +of the session.

    + +
    +
    +

    Methods:

    +
    +

    <constructor>

    +

    ba.SessionTeam(team_id: 'int' = 0, name: 'Union[ba.Lstr, str]' = '', color: 'Sequence[float]' = (1.0, 1.0, 1.0))

    + +

    Instantiate a ba.SessionTeam.

    + +

    In most cases, all teams are provided to you by the ba.Session, +ba.Session, so calling this shouldn't be necessary.

    + +
    +
    +
    +

    ba.SessionTeamNotFoundError

    +

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Exception raised when an expected ba.SessionTeam does not exist.

    + +

    Category: Exception Classes +

    +

    Methods:

    <all methods inherited from ba.NotFoundError>


    @@ -4459,7 +4684,7 @@ session.set_activity(foo) and then ba.newnode

    player_got_hit()

    -

    player_got_hit(self, player: ba.Player) -> None

    +

    player_got_hit(self, player: ba.SessionPlayer) -> None

    Call this when a player got hit.

    @@ -4479,7 +4704,7 @@ session.set_activity(foo) and then ba.newnode

    register_player()

    -

    register_player(self, player: ba.Player) -> None

    +

    register_player(self, player: ba.SessionPlayer) -> None

    Register a player with this score-set.

    @@ -4505,72 +4730,22 @@ session.set_activity(foo) and then ba.newnode

    ba.Team

    -

    <top level class> -

    -

    A team of one or more ba.Players.

    - -

    Category: Gameplay Classes

    - -

    Note that a player *always* has a team; - in some cases, such as free-for-all ba.Sessions, - each team consists of just one ba.Player.

    +

    inherits from: typing.Generic

    +

    Testing.

    Attributes:

    -
    color, gamedata, name, players, sessiondata
    -

    color

    -

    Tuple[float, ...]

    -

    The team's color.

    +

    sessionteam

    +

    SessionTeam

    +

    Return the ba.SessionTeam corresponding to this Team.

    -
    -

    gamedata

    -

    Dict

    -

    A dict for use by the current ba.Activity -for storing data associated with this team. -This gets cleared for each new ba.Activity.

    - -
    -

    name

    -

    Union[ba.Lstr, str]

    -

    The team's name.

    - -
    -

    players

    -

    List[ba.Player]

    -

    The list of ba.Players on the team.

    - -
    -

    sessiondata

    -

    Dict

    -

    A dict for use by the current ba.Session for -storing data associated with this team. -Unlike gamedata, this persists for the duration -of the session.

    - -
    -
    -

    Methods:

    -
    <constructor>, get_id()
    -
    -

    <constructor>

    -

    ba.Team(team_id: 'int' = 0, name: 'Union[ba.Lstr, str]' = '', color: 'Sequence[float]' = (1.0, 1.0, 1.0))

    - -

    Instantiate a ba.Team.

    - -

    In most cases, all teams are provided to you by the ba.Session, -ba.Session, so calling this shouldn't be necessary.

    - -
    -

    get_id()

    -

    get_id(self) -> int

    - -

    Returns the numeric team ID.

    +

    Throws a ba.SessionTeamNotFoundError if there is none.


    ba.TeamGameActivity

    -

    inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent

    +

    inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent, typing.Generic

    Base class for teams and free-for-all mode games.

    Category: Gameplay Classes

    @@ -4582,14 +4757,28 @@ of the session.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    map, session, stats
    +
    expired, map, playertype, session, stats, teamtype
    +

    expired

    +

    bool

    +

    Whether the activity is expired.

    + +

    An activity is set as expired when shutting down. + At this point no new nodes, timers, etc should be made, + run, etc, and the activity should be considered a 'zombie'.

    + +

    map

    ba.Map

    The map being used for this game.

    Raises a ba.NotFoundError if the map does not currently exist.

    +
    +

    playertype

    +

    Type[PlayerType]

    +

    The type of ba.Player this Activity is using.

    +

    session

    ba.Session

    @@ -4604,10 +4793,15 @@ of the session.

    If access is attempted before or after, raises a ba.NotFoundError.

    +
    +

    teamtype

    +

    Type[TeamType]

    +

    The type of ba.Team this Activity is using.

    +

    Methods Inherited:

    -
    add_actor_weak_ref(), begin(), continue_or_end_game(), create_config_ui(), create_player_node(), dep_is_present(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_expired(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), start_transition_in()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    @@ -4640,13 +4834,13 @@ and it should begin its actual game logic.

    Called when the Activity is first becoming visible.

    Upon this call, the Activity should fade in backgrounds, -start playing music, etc. It does not yet have access to ba.Players -or ba.Teams, however. They remain owned by the previous Activity +start playing music, etc. It does not yet have access to players +or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called.

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: ba.Player, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz

    Method override; spawns and wires up a standard ba.PlayerSpaz for a ba.Player.

    @@ -4711,7 +4905,7 @@ Results for a completed ba.TeamGameActivity

    get_team_score()

    -

    get_team_score(self, team: ba.Team) -> Optional[int]

    +

    get_team_score(self, team: Union[ba.SessionTeam, ba.Team]) -> Optional[int]

    Return the score for a given team.

    @@ -4725,9 +4919,9 @@ Results for a completed ba.TeamGameActivity

    get_teams()

    -

    get_teams(self) -> List[ba.Team]

    +

    get_teams(self) -> List[ba.SessionTeam]

    -

    Return all ba.Teams in the results.

    +

    Return all ba.SessionTeams in the results.

    get_winners()

    @@ -4737,13 +4931,13 @@ Results for a completed ba.TeamGameActivity

    get_winning_team()

    -

    get_winning_team(self) -> Optional[ba.Team]

    +

    get_winning_team(self) -> Optional[ba.SessionTeam]

    Get the winning ba.Team if there is exactly one; None otherwise.

    has_score_for_team()

    -

    has_score_for_team(self, team: ba.Team) -> bool

    +

    has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool

    Return whether there is a score for a given team.

    @@ -4755,7 +4949,7 @@ Results for a completed ba.TeamGameActivity

    set_team_score()

    -

    set_team_score(self, team: ba.Team, score: int) -> None

    +

    set_team_score(self, team: Union[ba.SessionTeam, ba.Team], score: int) -> None

    Set the score for a given ba.Team.

    @@ -5680,6 +5874,28 @@ object dies. 'owner' can be another node or a ba.Actor

    Open the provided url in a web-browser, or display the URL string in a window if that isn't possible.

    +
    +

    ba.playercast()

    +

    playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType

    + +

    Cast a ba.Player to a specific ba.Player subclass.

    + +

    Category: Gameplay Functions

    + +

    When writing type-checked code, sometimes code will deal with raw +ba.Player objects which need to be cast back to the game's actual +player type so that access can be properly type-checked. This function +is a safe way to do so. It ensures that Optional values are not cast +into Non-Optional, etc.

    + +
    +

    ba.playercast_o()

    +

    playercast_o(totype: Type[PlayerType], player: Optional[ba.Player]) -> Optional[PlayerType]

    + +

    A variant of ba.playercast() for use with optional ba.Player values.

    + +

    Category: Gameplay Functions

    +

    ba.playsound()

    playsound(sound: Sound, volume: float = 1.0, diff --git a/tools/bacloud b/tools/bacloud index 65efdff2..51c3b050 100755 --- a/tools/bacloud +++ b/tools/bacloud @@ -237,7 +237,7 @@ class App: with open(self._state_data_path, 'r') as infile: self._state = StateData(**json.loads(infile.read())) except Exception: - print(f'{Clr.SRED}Error loading {TOOL_NAME} data;' + print(f'{Clr.RED}Error loading {TOOL_NAME} data;' f' resetting to defaults.{Clr.RST}') def _save_state(self) -> None: @@ -285,7 +285,7 @@ class App: return response def _upload_file(self, filename: str, call: str, args: Dict) -> None: - print(f'{Clr.SBLU}Uploading {filename}{Clr.RST}', flush=True) + print(f'{Clr.BLU}Uploading {filename}{Clr.RST}', flush=True) with tempfile.TemporaryDirectory() as tempdir: srcpath = Path(filename) gzpath = Path(tempdir, 'file.gz') diff --git a/tools/batools/build.py b/tools/batools/build.py index cf762d60..db1c366e 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -112,7 +112,7 @@ def _lazybuild_check_paths(inpaths: List[str], category: SourceCategory, # Now see this path is newer than our target.. if mtime is None or os.path.getmtime(path) >= mtime: print(f'{Clr.SMAG}Build of {tnamepretty} triggered by' - f' {path}{Clr.RST}') + f" '{path}'{Clr.RST}") return True return False @@ -483,7 +483,7 @@ def _vstr(nums: Sequence[int]) -> str: def checkenv() -> None: """Check for tools necessary to build and run the app.""" from efrotools import PYTHON_BIN - print('Checking environment...', flush=True) + print(f'{Clr.BLD}Checking environment...{Clr.RST}', flush=True) # Make sure they've got curl. if subprocess.run(['which', 'curl'], check=False, @@ -539,7 +539,7 @@ def checkenv() -> None: 'Alternately, "tools/snippets install_pip_reqs"' ' will update all pip requirements.') - print('Environment ok.', flush=True) + print(f'{Clr.BLD}Environment ok.{Clr.RST}', flush=True) def get_pip_reqs() -> List[str]: diff --git a/tools/efro/entity/_field.py b/tools/efro/entity/_field.py index 4a0a4714..f540141b 100644 --- a/tools/efro/entity/_field.py +++ b/tools/efro/entity/_field.py @@ -26,9 +26,9 @@ import copy import logging from typing import TYPE_CHECKING, Generic, TypeVar, overload -from efro.entity._support import (BaseField, BoundCompoundValue, - BoundListField, BoundDictField, - BoundCompoundListField, +from efro.entity._base import BaseField +from efro.entity._support import (BoundCompoundValue, BoundListField, + BoundDictField, BoundCompoundListField, BoundCompoundDictField) from efro.entity.util import have_matching_fields diff --git a/tools/efro/entity/_value.py b/tools/efro/entity/_value.py index 30e8abc3..44bf4ec9 100644 --- a/tools/efro/entity/_value.py +++ b/tools/efro/entity/_value.py @@ -27,7 +27,9 @@ import inspect import logging from collections import abc from enum import Enum -from typing import TYPE_CHECKING, TypeVar, Tuple, Optional, Generic +from typing import TYPE_CHECKING, TypeVar, Generic +# Our Pylint class_generics_filter gives us a false-positive unused-import. +from typing import Tuple, Optional # pylint: disable=W0611 from efro.entity._base import DataHandler, BaseField from efro.entity.util import compound_eq diff --git a/tools/efro/util.py b/tools/efro/util.py index a236db37..fc74c96f 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -24,17 +24,24 @@ from __future__ import annotations import datetime import time +import weakref from typing import TYPE_CHECKING, cast, TypeVar, Generic if TYPE_CHECKING: import asyncio - from typing import Any, Dict, Callable, Optional + from weakref import ReferenceType + from typing import Any, Dict, Callable, Optional, Type +T = TypeVar('T') TVAL = TypeVar('TVAL') TARG = TypeVar('TARG') TRET = TypeVar('TRET') +class _EmptyObj: + pass + + def utc_now() -> datetime.datetime: """Get offset-aware current utc time. @@ -46,6 +53,15 @@ def utc_now() -> datetime.datetime: return datetime.datetime.now(datetime.timezone.utc) +def empty_weakref(objtype: Type[T]) -> ReferenceType[T]: + """Return an invalidated weak-reference for the specified type.""" + # At runtime, all weakrefs are the same; our type arg is just + # for the static type checker. + del objtype # Unused. + # Just create an object and let it die. Is there a cleaner way to do this? + return weakref.ref(_EmptyObj()) # type: ignore + + def data_size_str(bytecount: int) -> str: """Given a size in bytes, returns a short human readable string. diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index fc70e5ee..cbb2cf98 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -187,7 +187,7 @@ def _py_symbol_at_column(line: str, col: int) -> str: return line[start:end] -def py_examine(filename: Path, line: int, column: int, +def py_examine(projroot: Path, filename: Path, line: int, column: int, selection: Optional[str], operation: str) -> None: """Given file position info, performs some code inspection.""" # pylint: disable=too-many-locals @@ -242,7 +242,7 @@ def py_examine(filename: Path, line: int, column: int, with tmppath.open('w') as outfile: outfile.write('\n'.join(flines)) try: - code.runmypy([str(tmppath)], check=False) + code.runmypy(projroot, [str(tmppath)], check=False) except Exception as exc: print('error running mypy:', exc) tmppath.unlink() diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 3b18a02d..4d921ab2 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -38,8 +38,8 @@ def formatcode(projroot: Path, full: bool) -> None: """Run clang-format on all of our source code (multithreaded).""" import time import concurrent.futures - from efrotools import get_files_hash from multiprocessing import cpu_count + from efrotools import get_files_hash os.chdir(projroot) cachepath = Path(projroot, 'config/.cache-formatcode') if full and cachepath.exists(): @@ -66,13 +66,8 @@ def formatcode(projroot: Path, full: bool) -> None: sys.stdout.flush() return {'f': filename, 't': duration} - # NOTE: using fewer workers than we have logical procs for now; - # we're bottlenecked by one or two long running instances - # so it actually helps to lighten the load around them. - # may want to revisit later when we have everything chopped up - # better - with concurrent.futures.ThreadPoolExecutor(max_workers=cpu_count() // - 2) as executor: + with concurrent.futures.ThreadPoolExecutor( + max_workers=cpu_count()) as executor: # Converting this to a list will propagate any errors. list(executor.map(format_file, dirtyfiles)) @@ -88,8 +83,9 @@ def formatcode(projroot: Path, full: bool) -> None: def cpplint(projroot: Path, full: bool) -> None: """Run lint-checking on all code deemed lint-able.""" from concurrent.futures import ThreadPoolExecutor - from efrotools import get_config from multiprocessing import cpu_count + from efrotools import get_config + from efro.terminal import Clr os.chdir(projroot) filenames = get_code_filenames(projroot) @@ -115,21 +111,24 @@ def cpplint(projroot: Path, full: bool) -> None: dirtyfiles = cache.get_dirty_files() if dirtyfiles: - print(f'CppLint checking {len(dirtyfiles)} file(s)...') + print(f'{Clr.BLU}CppLint checking' + f' {len(dirtyfiles)} file(s)...{Clr.RST}') def lint_file(filename: str) -> None: result = subprocess.call(['cpplint', '--root=src', filename]) if result != 0: raise Exception(f'Linting failed for {filename}') - with ThreadPoolExecutor(max_workers=cpu_count() // 2) as executor: + with ThreadPoolExecutor(max_workers=cpu_count()) as executor: # Converting this to a list will propagate any errors. list(executor.map(lint_file, dirtyfiles)) if dirtyfiles: cache.mark_clean(filenames) cache.write() - print(f'CppLint: all {len(filenames)} files are passing.', flush=True) + print( + f'{Clr.GRN}CppLint: all {len(filenames)} files are passing.{Clr.RST}', + flush=True) def get_code_filenames(projroot: Path) -> List[str]: @@ -153,8 +152,8 @@ def formatscripts(projroot: Path, full: bool) -> None: """Runs yapf on all our scripts (multithreaded).""" import time from concurrent.futures import ThreadPoolExecutor - from efrotools import get_files_hash from multiprocessing import cpu_count + from efrotools import get_files_hash os.chdir(projroot) cachepath = Path(projroot, 'config/.cache-formatscripts') if full and cachepath.exists(): @@ -178,12 +177,7 @@ def formatscripts(projroot: Path, full: bool) -> None: print(f'Formatted {filename} in {duration:.2f} seconds.') sys.stdout.flush() - # NOTE: using fewer workers than we have logical procs for now; - # we're bottlenecked by one or two long running instances - # so it actually helps to lighten the load around them. - # may want to revisit later when we have everything chopped up - # better - with ThreadPoolExecutor(max_workers=cpu_count() // 2) as executor: + with ThreadPoolExecutor(max_workers=cpu_count()) as executor: # Convert the futures to a list to propagate any errors even # though there are no return values we use. list(executor.map(format_file, dirtyfiles)) @@ -235,9 +229,27 @@ def get_script_filenames(projroot: Path) -> List[str]: return sorted(list(f for f in filenames if 'flycheck_' not in f)) +def runpylint(projroot: Path, filenames: List[str]) -> None: + """Run Pylint explicitly on files.""" + + pylintrc = Path(projroot, '.pylintrc') + if not os.path.isfile(pylintrc): + raise Exception('pylintrc not found where expected') + + # Technically we could just run pylint standalone via command line here, + # but let's go ahead and run it inline so we're consistent with our cached + # full-project version. + _run_pylint(projroot, + pylintrc, + cache=None, + dirtyfiles=filenames, + allfiles=None) + + def pylint(projroot: Path, full: bool, fast: bool) -> None: - """Run lint-checking on all scripts deemed lint-able.""" + """Run Pylint on all scripts in our project (with smart dep tracking).""" from efrotools import get_files_hash + from efro.terminal import Clr pylintrc = Path(projroot, '.pylintrc') if not os.path.isfile(pylintrc): raise Exception('pylintrc not found where expected') @@ -270,22 +282,17 @@ def pylint(projroot: Path, full: bool, fast: bool) -> None: dirtyfiles.sort(reverse=True, key=lambda f: os.stat(f).st_mtime) if dirtyfiles: - print(f'Pylint checking {len(dirtyfiles)} file(s)...', flush=True) + print( + f'{Clr.BLU}Pylint checking {len(dirtyfiles)} file(s)...{Clr.RST}', + flush=True) try: - _run_script_lint(projroot, pylintrc, cache, dirtyfiles, filenames) - except Exception: - # Note: even if we fail here, we still want to + _run_pylint(projroot, pylintrc, cache, dirtyfiles, filenames) + finally: + # No matter what happens, we still want to # update our disk cache (since some lints may have passed). - print('Pylint failed.', flush=True) - - # Hmm; this can be handy sometimes; perhaps should add an env - # var to control it? - if bool(False): - import traceback - traceback.print_exc() cache.write() - sys.exit(255) - print(f'Pylint: all {len(filenames)} files are passing.', flush=True) + print(f'{Clr.GRN}Pylint: all {len(filenames)} files are passing.{Clr.RST}', + flush=True) cache.write() @@ -349,32 +356,39 @@ def _dirty_dep_check(fname: str, filestates: Dict[str, bool], cache: FileCache, return dirty -def _run_script_lint(projroot: Path, pylintrc: Union[Path, str], - cache: FileCache, dirtyfiles: List[str], - allfiles: List[str]) -> Dict[str, Any]: +def _run_pylint(projroot: Path, pylintrc: Union[Path, str], + cache: Optional[FileCache], dirtyfiles: List[str], + allfiles: Optional[List[str]]) -> Dict[str, Any]: import time from pylint import lint + from efro.error import CleanError + from efro.terminal import Clr start_time = time.time() - args = ['--rcfile', str(pylintrc)] + args = ['--rcfile', str(pylintrc), '--output-format=colorized'] args += dirtyfiles name = f'{len(dirtyfiles)} file(s)' run = lint.Run(args, do_exit=False) - result = _apply_pylint_run_to_cache(projroot, run, dirtyfiles, allfiles, - cache) - if result != 0: - raise Exception(f'Linting failed for {result} file(s).') + if cache is not None: + assert allfiles is not None + result = _apply_pylint_run_to_cache(projroot, run, dirtyfiles, + allfiles, cache) + if result != 0: + raise CleanError(f'Linting failed for {result} file(s).') + + # Sanity check: when the linter fails we should always be failing too. + # If not, it means we're probably missing something and incorrectly + # marking a failed file as clean. + if run.linter.msg_status != 0 and result == 0: + raise RuntimeError('Pylint linter returned non-zero result' + ' but we did not; this is probably a bug.') + else: + if run.linter.msg_status != 0: + raise CleanError('Pylint failed.') - # Sanity check: when the linter fails we should always be failing too. - # If not, it means we're probably missing something and incorrectly - # marking a failed file as clean. - if run.linter.msg_status != 0 and result == 0: - raise Exception('linter returned non-zero result but we did not;' - ' this is probably a bug.') - # result = run.linter.msg_status - # we can run duration = time.time() - start_time - print(f'Pylint passed for {name} in {duration:.1f} seconds.') + print(f'{Clr.GRN}Pylint passed for {name}' + f' in {duration:.1f} seconds.{Clr.RST}') sys.stdout.flush() return {'f': dirtyfiles, 't': duration} @@ -415,7 +429,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], # Update dependencies for what we just ran. # A run leaves us with a map of modules to a list of the modules that - # imports them. We want the opposite though: for each of our modules + # imports them. We want the opposite though: for each of our modules # we want a list of the modules it imports. reversedeps = {} @@ -453,10 +467,8 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], for fname in dirtyfiles: fmod = paths_to_names[fname] if fmod not in deps: - - # Since this code is a bit flaky, lets always announce when - # we come up empty and keep a whitelist of expected values to - # ignore. + # Since this code is a bit flaky, lets always announce when we + # come up empty and keep a whitelist of expected values to ignore. no_deps_modules.add(fmod) depsval: List[str] = [] else: @@ -512,14 +524,16 @@ def _filter_module_name(mpath: str) -> str: return mpath[:-9] if mpath.endswith('.__init__') else mpath -def runmypy(filenames: List[str], +def runmypy(projroot: Path, + filenames: List[str], full: bool = False, check: bool = True) -> None: """Run MyPy on provided filenames.""" from efrotools import PYTHON_BIN args = [ PYTHON_BIN, '-m', 'mypy', '--pretty', '--no-error-summary', - '--config-file', '.mypy.ini' + '--config-file', + str(Path(projroot, '.mypy.ini')) ] + filenames if full: args.insert(args.index('mypy') + 1, '--no-incremental') @@ -529,22 +543,26 @@ def runmypy(filenames: List[str], def mypy(projroot: Path, full: bool) -> None: """Type check all of our scripts using mypy.""" import time + from efro.terminal import Clr + from efro.error import CleanError filenames = get_script_filenames(projroot) - print('Running Mypy ' + ('(full)' if full else '(incremental)') + '...', - flush=True) + desc = '(full)' if full else '(incremental)' + print(f'{Clr.BLU}Running Mypy {desc}...{Clr.RST}', flush=True) starttime = time.time() try: - runmypy(filenames, full) + runmypy(projroot, filenames, full) except Exception: - print('Mypy: fail.') - sys.exit(255) + raise CleanError('Mypy: fail.') duration = time.time() - starttime - print(f'Mypy passed in {duration:.1f} seconds.', flush=True) + print(f'{Clr.GRN}Mypy passed in {duration:.1f} seconds.{Clr.RST}', + flush=True) def dmypy(projroot: Path) -> None: """Type check all of our scripts using mypy in daemon mode.""" import time + from efro.terminal import Clr + from efro.error import CleanError filenames = get_script_filenames(projroot) # Special case; explicitly kill the daemon. @@ -561,10 +579,10 @@ def dmypy(projroot: Path) -> None: ] + filenames subprocess.run(args, check=True) except Exception: - print('Mypy: fail.') - sys.exit(255) + raise CleanError('Mypy daemon: fail.') duration = time.time() - starttime - print(f'Mypy daemon passed in {duration:.1f} seconds.', flush=True) + print(f'{Clr.GRN}Mypy daemon passed in {duration:.1f} seconds.{Clr.RST}', + flush=True) def _parse_idea_results(path: Path) -> int: @@ -615,8 +633,13 @@ def _run_idea_inspections(projroot: Path, import tempfile import time import datetime + from efro.error import CleanError + from efro.terminal import Clr start_time = time.time() - print(f'{displayname} checking', len(scripts), 'file(s)...', flush=True) + print( + f'{Clr.BLU}{displayname} checking' + f' {len(scripts)} file(s)...{Clr.RST}', + flush=True) tmpdir = tempfile.TemporaryDirectory() iprof = Path(projroot, '.idea/inspectionProfiles/Default.xml') if not iprof.exists(): @@ -659,13 +682,12 @@ def _run_idea_inspections(projroot: Path, for fname in files: total_errors += _parse_idea_results(Path(tmpdir.name, fname)) if total_errors > 0: - raise RuntimeError( - f'{displayname} inspection found {total_errors} error(s).') + raise CleanError(f'{Clr.SRED}{displayname} inspection' + f' found {total_errors} error(s).{Clr.RST}') duration = time.time() - start_time - print( - f'{displayname} passed for {len(scripts)} files' - f' in {duration:.1f} seconds.', + f'{Clr.GRN}{displayname} passed for {len(scripts)} files' + f' in {duration:.1f} seconds.{Clr.RST}', flush=True) @@ -680,6 +702,7 @@ def _run_idea_inspections_cached(cachepath: Path, # pylint: disable=too-many-locals import hashlib import json + from efro.terminal import Clr md5 = hashlib.md5() # Let's calc a single hash from the contents of all script files and only @@ -717,8 +740,10 @@ def _run_idea_inspections_cached(cachepath: Path, inspectdir=inspectdir) with open(cachepath, 'w') as outfile: outfile.write(json.dumps({'hash': current_hash})) - print(f'{displayname}: all {len(filenames)} files are passing.', - flush=True) + print( + f'{Clr.GRN}{displayname}: all {len(filenames)}' + f' files are passing.{Clr.RST}', + flush=True) def pycharm(projroot: Path, full: bool, verbose: bool) -> None: diff --git a/tools/efrotools/pylintplugins.py b/tools/efrotools/pylintplugins.py index d897ff38..3db6760b 100644 --- a/tools/efrotools/pylintplugins.py +++ b/tools/efrotools/pylintplugins.py @@ -28,7 +28,7 @@ import astroid if TYPE_CHECKING: from astroid import node_classes as nc - from typing import Set, Dict, Any + from typing import Set, Dict, Any, List VERBOSE = False @@ -199,9 +199,49 @@ def var_annotations_filter(node: nc.NodeNG) -> nc.NodeNG: return node +# Stripping subscripts on some generics seems to cause +# more harm than good, so we leave some intact. +ALLOWED_GENERICS = {'Sequence'} + + +def _is_strippable_subscript(node: nc.NodeNG) -> bool: + if isinstance(node, astroid.Subscript): + # We can strip if its not in our allowed list. + if not (isinstance(node.value, astroid.Name) + and node.value.name in ALLOWED_GENERICS): + return True + return False + + +def class_generics_filter(node: nc.NodeNG) -> nc.NodeNG: + """Filter generics subscripts out of class declarations.""" + + # First, quick-out if nothing here should be filtered. + found = False + for base in node.bases: + if _is_strippable_subscript(base): + found = True + + if not found: + return node + + # Now strip subscripts from base classes. + new_bases: List[nc.NodeNG] = [] + for base in node.bases: + if _is_strippable_subscript(base): + new_bases.append(base.value) + base.value.parent = node + else: + new_bases.append(base) + node.bases = new_bases + + return node + + def register_plugins(manager: astroid.Manager) -> None: """Apply our transforms to a given astroid manager object.""" + # Hmm; is this still necessary? if VERBOSE: manager.register_failed_import_hook(failed_import_hook) @@ -210,16 +250,30 @@ def register_plugins(manager: astroid.Manager) -> None: # check code as if it doesn't exist at all. manager.register_transform(astroid.If, ignore_type_check_filter) + # We use 'reveal_type()' quite often, which tells mypy to print + # the type of an expression. Let's ignore it in Pylint's eyes so + # we don't see an ugly error there. manager.register_transform(astroid.Call, ignore_reveal_type_call) - # Annotations on variables within a function are defer-eval'ed - # in some cases, so lets replace them with simple strings in those - # cases to avoid type complaints. - # (mypy will still properly alert us to type errors for them) + # We make use of 'from __future__ import annotations' which causes Python + # to receive annotations as strings, and also 'if TYPE_CHECKING:' blocks, + # which lets us do imports and whatnot that are limited to type-checking. + # Let's make Pylint understand these. manager.register_transform(astroid.AnnAssign, var_annotations_filter) manager.register_transform(astroid.FunctionDef, func_annotations_filter) manager.register_transform(astroid.AsyncFunctionDef, func_annotations_filter) + # Pylint doesn't seem to support Generics much right now, and it seems + # to lead to some buggy behavior and slowdowns. So let's filter them + # out. So instead of this: + # class MyClass(MyType[T]): + # Pylint will see this: + # class MyClass(MyType): + # I've opened a github issue related to the problems I was hitting, + # so we can revisit the need for this if that gets resolved. + # https://github.com/PyCQA/pylint/issues/3605 + manager.register_transform(astroid.ClassDef, class_generics_filter) + register_plugins(astroid.MANAGER) diff --git a/tools/efrotools/snippets.py b/tools/efrotools/snippets.py index 6fd7f7d7..d2f206ba 100644 --- a/tools/efrotools/snippets.py +++ b/tools/efrotools/snippets.py @@ -54,7 +54,7 @@ def snippets_main(globs: Dict[str, Any]) -> None: show_help = False retval = 0 if len(sys.argv) < 2: - print(f'{Clr.SRED}ERROR: command expected.{Clr.RST}') + print(f'{Clr.RED}ERROR: command expected.{Clr.RST}') show_help = True retval = 255 else: @@ -67,13 +67,17 @@ def snippets_main(globs: Dict[str, Any]) -> None: else: docs = _trim_docstring( getattr(funcs[sys.argv[2]], '__doc__', '')) - print('\nsnippets ' + sys.argv[2] + ':\n' + docs + '\n') + print(f'\n{Clr.MAG}{Clr.BLD}snippets {sys.argv[2]}:{Clr.RST}\n' + f'{Clr.MAG}{docs}{Clr.RST}\n') elif sys.argv[1] in funcs: try: funcs[sys.argv[1]]() + except KeyboardInterrupt as exc: + print(f'{Clr.RED}{exc}{Clr.RST}') + sys.exit(1) except CleanError as exc: exc.pretty_print() - sys.exit(-1) + sys.exit(1) else: print('Unknown snippets command: "' + sys.argv[1] + '"', file=sys.stderr) @@ -82,11 +86,12 @@ def snippets_main(globs: Dict[str, Any]) -> None: if show_help: print('Snippets contains project related commands too small' ' to warrant full scripts.') - print("Run 'snippets help ' for full command documentation.") + print(f"Run {Clr.MAG}'snippets help {Clr.BLD}'" + f'{Clr.RST} for full command documentation.') print('Available commands:') for func, obj in sorted(funcs.items()): doc = getattr(obj, '__doc__', '').splitlines()[0].strip() - print(f'{Clr.SMAG}{func}{Clr.SBLU} - {doc}{Clr.RST}') + print(f'{Clr.MAG}{func}{Clr.BLU} - {doc}{Clr.RST}') sys.exit(retval) @@ -194,16 +199,16 @@ def check_clean_safety() -> None: def formatcode() -> None: """Run clang-format on all of our source code (multithreaded).""" - from efrotools import code + import efrotools.code full = '-full' in sys.argv - code.formatcode(PROJROOT, full) + efrotools.code.formatcode(PROJROOT, full) def formatscripts() -> None: """Run yapf on all our scripts (multithreaded).""" - from efrotools import code + import efrotools.code full = '-full' in sys.argv - code.formatscripts(PROJROOT, full) + efrotools.code.formatscripts(PROJROOT, full) def formatmakefile() -> None: @@ -222,9 +227,9 @@ def formatmakefile() -> None: def cpplint() -> None: """Run lint-checking on all code deemed lint-able.""" - from efrotools import code + import efrotools.code full = '-full' in sys.argv - code.cpplint(PROJROOT, full) + efrotools.code.cpplint(PROJROOT, full) def scriptfiles() -> None: @@ -232,8 +237,8 @@ def scriptfiles() -> None: Pass -lines to use newlines as separators. The default is spaces. """ - from efrotools import code - paths = code.get_script_filenames(projroot=PROJROOT) + import efrotools.code + paths = efrotools.code.get_script_filenames(projroot=PROJROOT) assert not any(' ' in path for path in paths) if '-lines' in sys.argv: print('\n'.join(paths)) @@ -243,101 +248,102 @@ def scriptfiles() -> None: def pylint() -> None: """Run pylint checks on our scripts.""" - from efrotools import code + from efro.error import CleanError + import efrotools.code full = ('-full' in sys.argv) fast = ('-fast' in sys.argv) - code.pylint(PROJROOT, full, fast) + try: + efrotools.code.pylint(PROJROOT, full, fast) + except Exception: + raise CleanError('Pylint failed.') + + +def runpylint() -> None: + """Run pylint checks on provided filenames.""" + import os + from efro.terminal import Clr + from efro.error import CleanError + import efrotools.code + if len(sys.argv) < 3: + raise CleanError('Expected at least 1 filename arg.') + filenames = sys.argv[2:] + try: + efrotools.code.runpylint(PROJROOT, filenames) + print(f'{Clr.GRN}Pylint Passed.{Clr.RST}') + except Exception: + if os.environ.get('VERBOSE') == '1': + import traceback + traceback.print_exc() + raise CleanError('Pylint Failed.') def mypy() -> None: """Run mypy checks on our scripts.""" - from efrotools import code + import efrotools.code full = ('-full' in sys.argv) - code.mypy(PROJROOT, full) + efrotools.code.mypy(PROJROOT, full) + + +def runmypy() -> None: + """Run mypy checks on provided filenames.""" + from efro.terminal import Clr + from efro.error import CleanError + import efrotools.code + if len(sys.argv) < 3: + raise CleanError('Expected at least 1 filename arg.') + filenames = sys.argv[2:] + try: + efrotools.code.runmypy(PROJROOT, filenames) + print(f'{Clr.GRN}Mypy Passed.{Clr.RST}') + except Exception: + raise CleanError('Mypy Failed.') def dmypy() -> None: """Run mypy checks on our scripts using the mypy daemon.""" - from efrotools import code - code.dmypy(PROJROOT) + import efrotools.code + efrotools.code.dmypy(PROJROOT) def pycharm() -> None: """Run PyCharm checks on our scripts.""" - from efrotools import code + import efrotools.code full = '-full' in sys.argv verbose = '-v' in sys.argv - code.pycharm(PROJROOT, full, verbose) + efrotools.code.pycharm(PROJROOT, full, verbose) def clioncode() -> None: """Run CLion checks on our code.""" - from efrotools import code + import efrotools.code full = '-full' in sys.argv verbose = '-v' in sys.argv - code.clioncode(PROJROOT, full, verbose) + efrotools.code.clioncode(PROJROOT, full, verbose) def androidstudiocode() -> None: """Run Android Studio checks on our code.""" - from efrotools import code + import efrotools.code full = '-full' in sys.argv verbose = '-v' in sys.argv - code.androidstudiocode(PROJROOT, full, verbose) + efrotools.code.androidstudiocode(PROJROOT, full, verbose) def tool_config_install() -> None: """Install a tool config file (with some filtering).""" - from efrotools import get_config - import textwrap + from efro.terminal import Clr if len(sys.argv) != 4: raise Exception('expected 2 args') src = Path(sys.argv[2]) dst = Path(sys.argv[3]) + + print(f'Creating tool config: {Clr.BLD}{dst}{Clr.RST}') + with src.open() as infile: cfg = infile.read() - # Do a bit of filtering. - - # Stick project-root wherever they want. - cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(PROJROOT)) - - # Short project name. - short_names = {'ballistica-internal': 'ba-int', 'ballistica': 'ba'} - shortname = short_names.get(PROJROOT.name, PROJROOT.name) - cfg = cfg.replace('__EFRO_PROJECT_SHORTNAME__', shortname) - - stdsettings = textwrap.dedent(""" - # We don't want all of our plain scripts complaining - # about __main__ being redefined. - scripts_are_modules = True - - # Try to be as strict as we can about using types everywhere. - warn_unused_ignores = True - warn_return_any = True - warn_redundant_casts = True - warn_unreachable=True - disallow_incomplete_defs = True - disallow_untyped_defs = True - disallow_untyped_decorators = True - disallow_untyped_calls = True - disallow_any_unimported = True - strict_equality = True - """).strip() - - cfg = cfg.replace('__EFRO_MYPY_STANDARD_SETTINGS__', stdsettings) - - # Gen a pylint init to set up our python paths: - pylint_init_tag = '__EFRO_PYLINT_INIT__' - if pylint_init_tag in cfg: - pypaths = get_config(PROJROOT).get('python_paths') - if pypaths is None: - raise RuntimeError('python_paths not set in project config') - cstr = "init-hook='import sys;" - for path in pypaths: - cstr += f" sys.path.append('{PROJROOT}/{path}');" - cstr += "'" - cfg = cfg.replace(pylint_init_tag, cstr) + # Rome substitutions, etc. + cfg = _filter_tool_config(cfg) # Add an auto-generated notice. comment = None @@ -356,6 +362,57 @@ def tool_config_install() -> None: outfile.write(cfg) +def _filter_tool_config(cfg: str) -> str: + import textwrap + from efrotools import get_config + + # Stick project-root wherever they want. + cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(PROJROOT)) + + # Short project name. + short_names = {'ballistica-internal': 'ba-int', 'ballistica': 'ba'} + shortname = short_names.get(PROJROOT.name, PROJROOT.name) + cfg = cfg.replace('__EFRO_PROJECT_SHORTNAME__', shortname) + + mypy_standard_settings = textwrap.dedent(""" + # We don't want all of our plain scripts complaining + # about __main__ being redefined. + scripts_are_modules = True + + # Try to be as strict as we can about using types everywhere. + warn_unused_ignores = True + warn_return_any = True + warn_redundant_casts = True + warn_unreachable = True + warn_unused_configs = True + disallow_incomplete_defs = True + disallow_untyped_defs = True + disallow_untyped_decorators = True + disallow_untyped_calls = True + disallow_any_unimported = True + disallow_subclassing_any = True + strict_equality = True + local_partial_types = True + no_implicit_reexport = True + """).strip() + + cfg = cfg.replace('__EFRO_MYPY_STANDARD_SETTINGS__', + mypy_standard_settings) + + # Gen a pylint init to set up our python paths: + pylint_init_tag = '__EFRO_PYLINT_INIT__' + if pylint_init_tag in cfg: + pypaths = get_config(PROJROOT).get('python_paths') + if pypaths is None: + raise RuntimeError('python_paths not set in project config') + cstr = "init-hook='import sys;" + for path in pypaths: + cstr += f" sys.path.append('{PROJROOT}/{path}');" + cstr += "'" + cfg = cfg.replace(pylint_init_tag, cstr) + return cfg + + def sync_all() -> None: """Runs full syncs between all efrotools projects. @@ -368,7 +425,7 @@ def sync_all() -> None: import concurrent.futures from efro.error import CleanError from efro.terminal import Clr - print(f'{Clr.SBLU}Updating formatting for all projects...{Clr.RST}') + print(f'{Clr.BLU}Updating formatting for all projects...{Clr.RST}') projects_str = os.environ.get('EFROTOOLS_SYNC_PROJECTS') if projects_str is None: raise CleanError('EFROTOOL_SYNC_PROJECTS is not defined.') @@ -399,17 +456,17 @@ def sync_all() -> None: # Real mode for i in range(2): if i == 0: - print(Clr.SBLU + 'Running sync pass 1:' + print(Clr.BLU + 'Running sync pass 1:' ' (ensures all changes at dsts are pushed to src)' + Clr.RST) else: - print(Clr.SBLU + 'Running sync pass 2:' + print(Clr.BLU + 'Running sync pass 2:' ' (ensures latest src is pulled to all dsts)' + Clr.RST) for project in projects_str.split(':'): cmd = f'cd "{project}" && make sync-full' print(cmd) subprocess.run(cmd, shell=True, check=True) - print(Clr.SBLU + 'Sync-all successful!' + Clr.RST) + print(Clr.BLU + 'Sync-all successful!' + Clr.RST) def sync() -> None: @@ -530,5 +587,26 @@ def makefile_target_list() -> None: continue print('\n' + entry.title + '\n' + '-' * len(entry.title)) elif entry.kind == 'target': - print(Clr.SMAG + entry.title + Clr.SBLU + + print(Clr.MAG + entry.title + Clr.BLU + _docstr(lines, entry.line) + Clr.RST) + + +def echo() -> None: + """Echo with support for efro.terminal.Clr args (RED, GRN, BLU, etc). + + Prints a Clr.RST at the end so that can be omitted. + """ + from efro.terminal import Clr + clrnames = {n for n in dir(Clr) if n.isupper() and not n.startswith('_')} + first = True + out: List[str] = [] + for arg in sys.argv[2:]: + if arg in clrnames: + out.append(getattr(Clr, arg)) + else: + if not first: + out.append(' ') + first = False + out.append(arg) + out.append(Clr.RST) + print(''.join(out)) diff --git a/tools/snippets b/tools/snippets index d270f01e..b5c0405e 100755 --- a/tools/snippets +++ b/tools/snippets @@ -40,9 +40,10 @@ from typing import TYPE_CHECKING # noinspection PyUnresolvedReferences from efrotools.snippets import ( PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile, - cpplint, pylint, mypy, dmypy, tool_config_install, sync, sync_all, - scriptfiles, pycharm, clioncode, androidstudiocode, makefile_target_list, - spelling, spelling_all, compile_python_files, pytest) + cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install, + sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, + makefile_target_list, spelling, spelling_all, compile_python_files, pytest, + echo) # pylint: enable=unused-import if TYPE_CHECKING: @@ -259,7 +260,7 @@ def clean_orphaned_assets() -> None: # Operate from dist root.. os.chdir(PROJROOT) - # Our manifest is split into 2 files (public and non-public) + # Our manifest is split into 2 files (public and private) with open('assets/.asset_manifest_public.json') as infile: manifest = set(json.loads(infile.read())) with open('assets/.asset_manifest_private.json') as infile: @@ -303,7 +304,8 @@ def py_examine() -> None: sys.path.append(scriptsdir) if toolsdir not in sys.path: sys.path.append(toolsdir) - efrotools.py_examine(filename, line, column, selection, operation) + efrotools.py_examine(PROJROOT, filename, line, column, selection, + operation) def push_ipa() -> None: @@ -553,6 +555,9 @@ def lazy_increment_build() -> None: """Increment build number only if C++ sources have changed. This is convenient to place in automatic commit/push scripts. + It could make sense to auto update build number when scripts/assets + change too, but a build number change requires rebuilding all binaries + so I'll leave that as an explicit choice to save work. """ import os import subprocess diff --git a/tools/update_project b/tools/update_project index a66fb333..72e82c7f 100755 --- a/tools/update_project +++ b/tools/update_project @@ -133,9 +133,9 @@ class App: self._update_docs_md() if self._check: - print('Check-Builds: Everything up to date.') + print(f'{Clr.BLU}Check-Builds: Everything up to date.{Clr.RST}') else: - print('Update-Builds: SUCCESS!') + print(f'{Clr.GRN}Update-Project: SUCCESS!{Clr.RST}') def _update_dummy_module(self) -> None: # Update our dummy _ba module. @@ -144,8 +144,8 @@ class App: # been updated. if os.path.exists('tools/gendummymodule.py'): if os.system('tools/gendummymodule.py' + self._checkarg) != 0: - print(Clr.SRED + 'Error checking/updating dummy module' + - Clr.RST) + print( + f'{Clr.RED}Error checking/updating dummy module{Clr.RST}') sys.exit(255) def _update_docs_md(self) -> None: @@ -157,8 +157,8 @@ class App: if os.path.exists('tools/gendocs.py'): if os.system('tools/snippets update_docs_md' + self._checkarg) != 0: - print(Clr.SRED + 'Error checking/updating docs markdown.' + - Clr.RST) + print(f'{Clr.RED}Error checking/updating' + f' docs markdown.{Clr.RST}') sys.exit(255) def _update_compile_commands_file(self) -> None: @@ -166,7 +166,7 @@ class App: # our cmake stuff. Do this at end so cmake changes already happened. if not self._check and os.path.exists('ballisticacore-cmake'): if os.system('make .irony/compile_commands.json') != 0: - print(Clr.SRED + 'Error updating compile-commands.' + Clr.RST) + print(f'{Clr.RED}Error updating compile-commands.{Clr.RST}') sys.exit(255) def _apply_file_changes(self) -> None: @@ -184,11 +184,11 @@ class App: unchanged_project_count += 1 else: if self._check: - print(f'{Clr.SRED}ERROR: found out-of-date' + print(f'{Clr.RED}ERROR: found out-of-date' f' project file: {fname}{Clr.RST}') sys.exit(255) - print(f'{Clr.SBLU}Writing project file: {fname}{Clr.RST}') + print(f'{Clr.BLU}Writing project file: {fname}{Clr.RST}') with open(fname, 'w') as outfile: outfile.write(fcode) if unchanged_project_count > 0: @@ -211,16 +211,16 @@ class App: # If there are any manual-only entries, list then and bail. # (Don't wanna allow auto-apply unless it fixes everything) if manual_changes: - print(f'{Clr.SRED}Found erroneous lines ' + print(f'{Clr.RED}Found erroneous lines ' f'requiring manual correction:{Clr.RST}') for change in manual_changes: print( - f'{Clr.SRED}{change[0]}:{change[1].line_number + 1}:' + f'{Clr.RED}{change[0]}:{change[1].line_number + 1}:' f' Expected line to be:\n {change[1].expected}{Clr.RST}') # Make a note on copyright lines that this can be disabled. if 'Copyright' in change[1].expected: - print(f'{Clr.SRED}NOTE: You can disable copyright' + print(f'{Clr.RED}NOTE: You can disable copyright' f' checks by adding "copyright_checks": false\n' f'to the root dict in config/localconfig.json.\n' f'see https://github.com/efroemling/ballistica/wiki' @@ -232,22 +232,21 @@ class App: if auto_changes: if not self._fix: for i, change in enumerate(auto_changes): - print(f'{Clr.SRED}#{i}: {change[0]}:{Clr.RST}') + print(f'{Clr.RED}#{i}: {change[0]}:{Clr.RST}') print( - f'{Clr.SRED} Expected "{change[1].expected}"{Clr.RST}' - ) + f'{Clr.RED} Expected "{change[1].expected}"{Clr.RST}') with open(change[0]) as infile: lines = infile.read().splitlines() line = lines[change[1].line_number] - print(f'{Clr.SRED} Found "{line}"{Clr.RST}') - print(Clr.SRED + + print(f'{Clr.RED} Found "{line}"{Clr.RST}') + print(Clr.RED + f'All {len(auto_changes)} errors are auto-fixable;' ' run tools/update_project --fix to apply corrections.' + Clr.RST) sys.exit(255) else: for i, change in enumerate(auto_changes): - print(f'{Clr.SBLU}Correcting file: {change[0]}{Clr.RST}') + print(f'{Clr.BLU}Correcting file: {change[0]}{Clr.RST}') with open(change[0]) as infile: lines = infile.read().splitlines() lines[change[1].line_number] = change[1].expected @@ -269,7 +268,7 @@ class App: # Could just ignore these but it probably means I intended # to save something and forgot. if '/.#' in fsrc: - print(f'{Clr.SRED}' + print(f'{Clr.RED}' f'ERROR: Found an unsaved emacs file: "{fsrc}"' f'{Clr.RST}') sys.exit(255) @@ -393,7 +392,7 @@ class App: 'tools/devtool', 'tools/version_utils', 'tools/vmshell' ]: if not contents.startswith('#!/usr/bin/env python3.7'): - print(f'{Clr.SRED}Incorrect shebang (first line) for ' + print(f'{Clr.RED}Incorrect shebang (first line) for ' f'{fname}.{Clr.RST}') sys.exit(255) else: @@ -482,7 +481,7 @@ class App: if ('__pycache__' not in root and os.path.basename(root) != '.vscode'): if '__init__.py' not in files: - print(Clr.SRED + + print(Clr.RED + 'Error: no __init__.py in package dir: ' + root + Clr.RST) sys.exit(255) @@ -630,14 +629,14 @@ class App: # Make sure none of our sync targets have been mucked with since # their last sync. if os.system('tools/snippets sync check') != 0: - print(Clr.SRED + 'Sync check failed; you may need to run "sync".' + + print(Clr.RED + 'Sync check failed; you may need to run "sync".' + Clr.RST) sys.exit(255) def _update_assets_makefile(self) -> None: if os.path.exists('tools/update_assets_makefile'): if os.system('tools/update_assets_makefile' + self._checkarg) != 0: - print(Clr.SRED + 'Error checking/updating assets Makefile' + + print(Clr.RED + 'Error checking/updating assets Makefile' + Clr.RST) sys.exit(255) @@ -645,7 +644,7 @@ class App: if os.path.exists('tools/update_generated_code_makefile'): if os.system('tools/update_generated_code_makefile' + self._checkarg) != 0: - print(Clr.SRED + + print(Clr.RED + 'Error checking/updating generated-code Makefile' + Clr.RST) sys.exit(255) @@ -654,7 +653,7 @@ class App: if os.path.exists('tools/update_resources_makefile'): if os.system('tools/update_resources_makefile' + self._checkarg) != 0: - print(Clr.SRED + 'Error checking/updating resources Makefile' + + print(Clr.RED + 'Error checking/updating resources Makefile' + Clr.RST) sys.exit(255) @@ -662,8 +661,8 @@ class App: if os.path.exists('tools/update_python_enums_module'): if os.system('tools/update_python_enums_module' + self._checkarg) != 0: - print(Clr.SRED + - 'Error checking/updating python enums module' + Clr.RST) + print(Clr.RED + 'Error checking/updating python enums module' + + Clr.RST) sys.exit(255) From 6d0b257934104f63a81e3b666510a597d408142e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 18 May 2020 15:44:52 -0700 Subject: [PATCH 015/417] Modernized CTF a bit --- assets/src/ba_data/python/ba/_gameactivity.py | 2 +- assets/src/ba_data/python/ba/_teamgame.py | 3 +- .../python/bastd/game/capturetheflag.py | 54 +++++++++++-------- docs/ba_module.md | 4 +- 4 files changed, 36 insertions(+), 27 deletions(-) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 869d2eb2..2bd99ab6 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -994,7 +994,7 @@ class GameActivity(Activity[PlayerType, TeamType]): def spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), - angle: float = None) -> PlayerSpaz: + angle: float = None) -> PlayerSpaz[PlayerType]: """Create and wire up a ba.PlayerSpaz for the provided ba.Player.""" # pylint: disable=too-many-locals # pylint: disable=cyclic-import diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index ceb9b330..bb149d3a 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -110,7 +110,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): def spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, - angle: float = None) -> PlayerSpaz: + angle: float = None) -> PlayerSpaz[PlayerType]: """ Method override; spawns and wires up a standard ba.PlayerSpaz for a ba.Player. @@ -128,6 +128,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): return super().spawn_player_spaz(player, position, angle) + # FIXME: need to unify these arguments with GameActivity.end() def end( # type: ignore self, results: Any = None, diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 09ce7be6..8934eede 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -38,7 +38,9 @@ if TYPE_CHECKING: class CTFFlag(stdflag.Flag): - """Special flag type for ctf games.""" + """Special flag type for CTF games.""" + + activity: CaptureTheFlagGame def __init__(self, team: Team): assert team.flagmaterial is not None @@ -63,8 +65,7 @@ class CTFFlag(stdflag.Flag): """Clear flag related times in the activity.""" self.time_out_respawn_time = int( self.activity.settings_raw['Flag Idle Return Time']) - self.touch_return_time = float( - self.activity.settings_raw['Flag Touch Return Time']) + self.touch_return_time = float(self.activity.flag_touch_return_time) @property def team(self) -> Team: @@ -163,8 +164,6 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) self._scoreboard = Scoreboard() - if self.settings_raw['Epic Mode']: - self.slow_motion = True self._alarmsound = ba.getsound('alarm') self._ticking_sound = ba.getsound('ticking') self._last_score_time = 0 @@ -172,26 +171,36 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self._swipsound = ba.getsound('swip') self._all_bases_material = ba.Material() self._last_home_flag_notice_print_time = 0.0 + self._score_to_win = int(settings['Score to Win']) + self._flag_touch_return_time = float( + settings['Flag Touch Return Time']) + self._epic_mode = bool(settings['Epic Mode']) + self._time_limit = float(settings['Time Limit']) + + # Base class overrides + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.FLAG_CATCHER) + + @property + def flag_touch_return_time(self) -> float: + """How long a flag must be touched for to return it to base.""" + return self._flag_touch_return_time def get_instance_description(self) -> Union[str, Sequence]: - if self.settings_raw['Score to Win'] == 1: + if self._score_to_win == 1: return 'Steal the enemy flag.' - return ('Steal the enemy flag ${ARG1} times.', - self.settings_raw['Score to Win']) + return 'Steal the enemy flag ${ARG1} times.', self._score_to_win def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - if self.settings_raw['Score to Win'] == 1: + if self._score_to_win == 1: return 'return 1 flag' - return 'return ${ARG1} flags', self.settings_raw['Score to Win'] - - def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC - if self.settings_raw['Epic Mode'] else - ba.MusicType.FLAG_CATCHER) - super().on_transition_in() + return 'return ${ARG1} flags', self._score_to_win def create_team(self, sessionteam: ba.SessionTeam) -> Team: + # Create our team instance and its initial values. + base_pos = self.map.get_flag_position(sessionteam.id) self.project_flag_stand(base_pos) @@ -264,7 +273,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() ba.timer(1.0, call=self._tick, repeat=True) @@ -377,7 +386,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): assert reset_team.flag is not None reset_team.flag.handlemessage(ba.DieMessage()) reset_team.enemy_flag_at_base = False - if team.score >= self.settings_raw['Score to Win']: + if team.score >= self._score_to_win: self.end_game() def end_game(self) -> None: @@ -434,8 +443,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def _award_players_touching_own_flag(self, team: Team) -> None: for player in team.players: if player.touching_own_flag > 0: - return_score = 10 + 5 * int( - self.settings_raw['Flag Touch Return Time']) + return_score = 10 + 5 * int(self._flag_touch_return_time) self.stats.player_scored(player, return_score, screenmessage=False) @@ -463,7 +471,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # If return-time is zero, just kill it immediately.. otherwise keep # track of touches and count down. - if float(self.settings_raw['Flag Touch Return Time']) <= 0.0: + if float(self._flag_touch_return_time) <= 0.0: assert team.flag is not None if not team.home_flag_at_base and team.flag.held_count == 0: @@ -508,7 +516,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def spawn_player_spaz(self, player: Player, position: Sequence[float] = None, - angle: float = None) -> PlayerSpaz: + angle: float = None) -> PlayerSpaz[Player]: """Intercept new spazzes and add our team material for them.""" spaz = super().spawn_player_spaz(player, position, angle) player = spaz.player @@ -540,7 +548,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, team.score, - self.settings_raw['Score to Win']) + self._score_to_win) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerSpazDeathMessage): diff --git a/docs/ba_module.md b/docs/ba_module.md index 9e6cd0d2..20ca4906 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -2426,7 +2426,7 @@ and short description of the game.

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz[PlayerType]

    Create and wire up a ba.PlayerSpaz for the provided ba.Player.

    @@ -4840,7 +4840,7 @@ up until ba.Activity.on_begin() is c

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz[PlayerType]

    Method override; spawns and wires up a standard ba.PlayerSpaz for a ba.Player.

    From 0742bce678988554bd75278aaec6d631c17762a4 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 18 May 2020 16:39:30 -0700 Subject: [PATCH 016/417] Modernized assault code a bit --- assets/src/ba_data/python/ba/_gameactivity.py | 5 +- .../ba_data/python/bastd/actor/playerspaz.py | 10 +- .../src/ba_data/python/bastd/game/assault.py | 182 ++++++++++-------- .../python/bastd/game/capturetheflag.py | 4 +- .../ba_data/python/bastd/game/chosenone.py | 2 +- .../src/ba_data/python/bastd/game/conquest.py | 2 +- .../ba_data/python/bastd/game/deathmatch.py | 2 +- .../python/bastd/game/easteregghunt.py | 2 +- .../ba_data/python/bastd/game/elimination.py | 2 +- .../src/ba_data/python/bastd/game/football.py | 4 +- .../src/ba_data/python/bastd/game/hockey.py | 2 +- .../src/ba_data/python/bastd/game/keepaway.py | 2 +- .../python/bastd/game/kingofthehill.py | 2 +- .../ba_data/python/bastd/game/meteorshower.py | 2 +- .../ba_data/python/bastd/game/ninjafight.py | 3 +- .../ba_data/python/bastd/game/onslaught.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 2 +- .../ba_data/python/bastd/game/runaround.py | 2 +- .../python/bastd/game/targetpractice.py | 2 +- .../ba_data/python/bastd/game/thelaststand.py | 2 +- 20 files changed, 132 insertions(+), 104 deletions(-) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 2bd99ab6..e59ff9fb 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -635,7 +635,7 @@ class GameActivity(Activity[PlayerType, TeamType]): from bastd.actor.playerspaz import PlayerSpazDeathMessage if isinstance(msg, PlayerSpazDeathMessage): - player = msg.getspaz(self).player + player = msg.playerspaz(self).player killer = msg.killerplayer # Inform our score-set of the demise. @@ -645,7 +645,8 @@ class GameActivity(Activity[PlayerType, TeamType]): # Award the killer points if he's on a different team. if killer and killer.team is not player.team: - pts, importance = msg.getspaz(self).get_death_points(msg.how) + pts, importance = msg.playerspaz(self).get_death_points( + msg.how) if not self.has_ended(): self.stats.player_scored(killer, pts, diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index f8ca79f1..5c66414c 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -60,7 +60,7 @@ class PlayerSpazDeathMessage: self.killerplayer = killerplayer self.how = how - def getspaz( + def playerspaz( self, activity: ba.Activity[PlayerType, TeamType]) -> PlayerSpaz[PlayerType]: """Return the spaz that died. @@ -149,7 +149,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): Note that this may return None if the player has left. """ - # Convert invalid references to None. + # Return None in the case of a no-longer-valid reference. return self._player if self._player else None def connect_controls_to_player(self, @@ -295,9 +295,9 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): else: killerplayer = None - # Convert dead-refs to None. - if not killerplayer: - killerplayer = None + # We should never wind up with a dead-reference here; + # we want to use None in that case. + assert killerplayer is None or killerplayer # Only report if both the player and the activity still exist. if killed and activity is not None and self.getplayer(): diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 092c9495..efc46df3 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -26,17 +26,32 @@ from __future__ import annotations import random +from dataclasses import dataclass from typing import TYPE_CHECKING import ba from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.flag import Flag if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Sequence, Union +@dataclass +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +@dataclass +class Team(ba.Team[Player]): + """Our team type for this game.""" + base_pos: Sequence[float] + flag: Flag + score: int = 0 + + # ba_meta export game -class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class AssaultGame(ba.TeamGameActivity[Player, Team]): """Game where you score by touching the other team's flag.""" @classmethod @@ -59,106 +74,114 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [('Score to Win', {'min_value': 1, 'default': 3}), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], - 'default': 0}), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), - ('Normal', 1.0), ('Long', 2.0), - ('Longer', 4.0)], - 'default': 1.0}), - ('Epic Mode', {'default': False})] # yapf: disable + return [ + ('Score to Win', { + 'min_value': 1, + 'default': 3 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() - if self.settings_raw['Epic Mode']: - self.slow_motion = True self._last_score_time = 0.0 self._score_sound = ba.getsound('score') self._base_region_materials: Dict[int, ba.Material] = {} + self._epic_mode = bool(settings['Epic Mode']) + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) + + # Base class overrides + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.FORWARD_MARCH) def get_instance_description(self) -> Union[str, Sequence]: - if self.settings_raw['Score to Win'] == 1: + if self._score_to_win == 1: return 'Touch the enemy flag.' - return ('Touch the enemy flag ${ARG1} times.', - self.settings_raw['Score to Win']) + return 'Touch the enemy flag ${ARG1} times.', self._score_to_win def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - if self.settings_raw['Score to Win'] == 1: + if self._score_to_win == 1: return 'touch 1 flag' - return 'touch ${ARG1} flags', self.settings_raw['Score to Win'] + return 'touch ${ARG1} flags', self._score_to_win - def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC - if self.settings_raw['Epic Mode'] else - ba.MusicType.FORWARD_MARCH) - super().on_transition_in() + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + base_pos = self.map.get_flag_position(sessionteam.id) + ba.newnode('light', + attrs={ + 'position': base_pos, + 'intensity': 0.6, + 'height_attenuated': False, + 'volume_intensity_scale': 0.1, + 'radius': 0.1, + 'color': sessionteam.color + }) + self.project_flag_stand(base_pos) + flag = Flag(touchable=False, + position=base_pos, + color=sessionteam.color) + team = Team(base_pos=base_pos, flag=flag) - def on_team_join(self, team: ba.Team) -> None: - team.gamedata['score'] = 0 + mat = self._base_region_materials[sessionteam.id] = ba.Material() + mat.add_actions( + conditions=('they_have_material', ba.sharedobj('player_material')), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', ba.Call(self._handle_base_collide, + team)), + ), + ) + + ba.newnode( + 'region', + owner=flag.node, + attrs={ + 'position': (base_pos[0], base_pos[1] + 0.75, base_pos[2]), + 'scale': (0.5, 0.5, 0.5), + 'type': 'sphere', + 'materials': [self._base_region_materials[sessionteam.id]] + }) + + return team + + def on_team_join(self, team: Team) -> None: + # Can't do this in create_team because the team's color/etc. have + # not been wired up yet at that point. self._update_scoreboard() def on_begin(self) -> None: - from bastd.actor.flag import Flag super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - for team in self.teams: - mat = self._base_region_materials[team.id] = ba.Material() - mat.add_actions(conditions=('they_have_material', - ba.sharedobj('player_material')), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', - 'physical', False), - ('call', 'at_connect', - ba.Call(self._handle_base_collide, - team)))) - - # Create a score region and flag for each team. - for team in self.teams: - team.gamedata['base_pos'] = self.map.get_flag_position(team.id) - - ba.newnode('light', - attrs={ - 'position': team.gamedata['base_pos'], - 'intensity': 0.6, - 'height_attenuated': False, - 'volume_intensity_scale': 0.1, - 'radius': 0.1, - 'color': team.color - }) - - self.project_flag_stand(team.gamedata['base_pos']) - team.gamedata['flag'] = Flag(touchable=False, - position=team.gamedata['base_pos'], - color=team.color) - basepos = team.gamedata['base_pos'] - ba.newnode('region', - owner=team.gamedata['flag'].node, - attrs={ - 'position': - (basepos[0], basepos[1] + 0.75, basepos[2]), - 'scale': (0.5, 0.5, 0.5), - 'type': 'sphere', - 'materials': [self._base_region_materials[team.id]] - }) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerSpazDeathMessage): super().handlemessage(msg) # Augment standard. - self.respawn_player(msg.getspaz(self).player) + self.respawn_player(msg.playerspaz(self).player) else: super().handlemessage(msg) - def _flash_base(self, team: ba.Team, length: float = 2.0) -> None: + def _flash_base(self, team: Team, length: float = 2.0) -> None: light = ba.newnode('light', attrs={ - 'position': team.gamedata['base_pos'], + 'position': team.base_pos, 'height_attenuated': False, 'radius': 0.3, 'color': team.color @@ -166,7 +189,7 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]): ba.animate(light, 'intensity', {0: 0, 0.25: 2.0, 0.5: 0}, loop=True) ba.timer(length, light.delete) - def _handle_base_collide(self, team: ba.Team) -> None: + def _handle_base_collide(self, team: Team) -> None: # Attempt to pull a living ba.Player from what we hit. cnode = ba.get_collision_info('opposing_node') @@ -179,8 +202,10 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]): if not player or not player.actor: return + assert isinstance(player, Player) + # If its another team's player, they scored. - player_team: ba.Team[ba.Player] = player.team + player_team = player.team if player_team is not team: # Prevent multiple simultaneous scores. @@ -233,19 +258,18 @@ class AssaultGame(ba.TeamGameActivity[ba.Player, ba.Team]): if player.actor: player.actor.handlemessage(ba.CelebrateMessage(2.0)) - player_team.gamedata['score'] += 1 + player_team.score += 1 self._update_scoreboard() - if (player_team.gamedata['score'] >= - self.settings_raw['Score to Win']): + if player_team.score >= self._score_to_win: self.end_game() def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score(team, team.gamedata['score']) + results.set_team_score(team, team.score) self.end(results=results) def _update_scoreboard(self) -> None: for team in self.teams: - self._scoreboard.set_team_value(team, team.gamedata['score'], - self.settings_raw['Score to Win']) + self._scoreboard.set_team_value(team, team.score, + self._score_to_win) diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 8934eede..50c1e09a 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -268,6 +268,8 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): return team def on_team_join(self, team: Team) -> None: + # Can't do this in create_team because the team's color/etc. have + # not been wired up yet at that point. self._spawn_flag_for_team(team) self._update_scoreboard() @@ -554,7 +556,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): if isinstance(msg, PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.getspaz(self).player) + self.respawn_player(msg.playerspaz(self).player) elif isinstance(msg, stdflag.FlagDeathMessage): assert isinstance(msg.flag, CTFFlag) ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 65b41a4c..ce87a50d 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -327,7 +327,7 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - player = msg.getspaz(self).player + player = msg.playerspaz(self).player if player is self._get_chosen_one_player(): killerplayer = msg.killerplayer self._set_chosen_one_player(None if ( diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 2ffac1a0..361039bb 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -254,7 +254,7 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): super().handlemessage(msg) # Respawn only if this team has a flag. - player = msg.getspaz(self).player + player = msg.playerspaz(self).player if player.team.gamedata['flags_held'] > 0: self.respawn_player(player) else: diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 3b5237c2..e6d64d2e 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -145,7 +145,7 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): # Augment standard behavior. super().handlemessage(msg) - player = msg.getspaz(self).player + player = msg.playerspaz(self).player self.respawn_player(player) killer = msg.killerplayer diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index eebdef24..41f61ece 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -212,7 +212,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): # Augment standard behavior. super().handlemessage(msg) - player = msg.getspaz(self).getplayer() + player = msg.playerspaz(self).getplayer() if not player: return self.stats.player_was_killed(player) diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 047db791..96e9bb91 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -491,7 +491,7 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): # Augment standard behavior. super().handlemessage(msg) - player = msg.getspaz(self).player + player = msg.playerspaz(self).player player.gamedata['lives'] -= 1 if player.gamedata['lives'] < 0: diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index f5e630ca..1b98def2 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -274,7 +274,7 @@ class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]): elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.getspaz(self).player) + self.respawn_player(msg.playerspaz(self).player) # Respawn dead flags. elif isinstance(msg, stdflag.FlagDeathMessage): @@ -812,7 +812,7 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): from bastd.actor import respawnicon # Respawn dead players. - player = msg.getspaz(self).player + player = msg.playerspaz(self).player self.stats.player_was_killed(player) assert self.initial_player_info is not None respawn_time = 2.0 + len(self.initial_player_info) * 1.0 diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index daa2b354..fa611c6b 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -341,7 +341,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior... super().handlemessage(msg) - self.respawn_player(msg.getspaz(self).player) + self.respawn_player(msg.playerspaz(self).player) # Respawn dead pucks. elif isinstance(msg, PuckDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 2a8839e9..41ea50a5 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -271,7 +271,7 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.getspaz(self).player) + self.respawn_player(msg.playerspaz(self).player) elif isinstance(msg, stdflag.FlagDeathMessage): self._spawn_flag() elif isinstance( diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 3d0f5d8a..c0fc84bf 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -281,7 +281,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): super().handlemessage(msg) # Augment default. # No longer can count as at_flag once dead. - player = msg.getspaz(self).player + player = msg.playerspaz(self).player player.gamedata['at_flag'] = 0 self._update_flag_state() self.respawn_player(player) diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index e87e6249..462ea14a 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -173,7 +173,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): # Record the player's moment of death. # assert isinstance(msg.spaz.player - msg.getspaz(self).player.death_time = curtime + msg.playerspaz(self).player.death_time = curtime # In co-op mode, end the game the instant everyone dies # (more accurate looking). diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 24a262b9..04c44ef2 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -148,7 +148,8 @@ class NinjaFightGame(ba.TeamGameActivity[ba.Player, ba.Team]): # A player has died. if isinstance(msg, playerspaz.PlayerSpazDeathMessage): super().handlemessage(msg) # do standard stuff - self.respawn_player(msg.getspaz(self).player) # kick off a respawn + self.respawn_player( + msg.playerspaz(self).player) # kick off a respawn # A spaz-bot has died. elif isinstance(msg, spazbot.SpazBotDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 88d62efa..192da89f 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -1163,7 +1163,7 @@ class OnslaughtGame(ba.CoopGameActivity[ba.Player, ba.Team]): elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): super().handlemessage(msg) # Augment standard behavior. - player = msg.getspaz(self).getplayer() + player = msg.playerspaz(self).getplayer() assert player is not None self._a_player_has_been_hurt = True diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 89eb04aa..0260de26 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -733,7 +733,7 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): if isinstance(msg, PlayerSpazDeathMessage): # Augment default behavior. super().handlemessage(msg) - player = msg.getspaz(self).getplayer() + player = msg.playerspaz(self).getplayer() if not player: ba.print_error('got no player in PlayerSpazDeathMessage') return diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 5c6e2f06..302494a2 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -1127,7 +1127,7 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): from bastd.actor import respawnicon self._a_player_has_been_killed = True - player = msg.getspaz(self).getplayer() + player = msg.playerspaz(self).getplayer() if player is None: ba.print_error('FIXME: getplayer() should no' ' longer ever be returning None') diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index ad3d1fce..505dec52 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -187,7 +187,7 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): # When players die, respawn them. if isinstance(msg, playerspaz.PlayerSpazDeathMessage): super().handlemessage(msg) # Do standard stuff. - player = msg.getspaz(self).getplayer() + player = msg.playerspaz(self).getplayer() assert player is not None self.respawn_player(player) # Kick off a respawn. elif isinstance(msg, Target.TargetHitMessage): diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index a59fbbec..2cc04437 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -257,7 +257,7 @@ class TheLastStandGame(ba.CoopGameActivity[ba.Player, ba.Team]): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, playerspaz.PlayerSpazDeathMessage): - player = msg.getspaz(self).getplayer() + player = msg.playerspaz(self).getplayer() if player is None: ba.print_error('FIXME: getplayer() should no longer ' 'ever be returning None.') From d29cb35ff10401601b3ee363728892f4099c135e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 19 May 2020 01:34:24 -0700 Subject: [PATCH 017/417] More minigame modernizing --- .efrocachemap | 24 +- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/_activity.py | 462 +++++++++--------- assets/src/ba_data/python/ba/_gameresults.py | 2 +- assets/src/ba_data/python/ba/_player.py | 12 + assets/src/ba_data/python/ba/_team.py | 21 + .../src/ba_data/python/bastd/actor/spazbot.py | 22 +- .../src/ba_data/python/bastd/game/assault.py | 4 +- .../python/bastd/game/capturetheflag.py | 4 +- .../ba_data/python/bastd/game/chosenone.py | 232 ++++----- .../ba_data/python/bastd/game/elimination.py | 274 ++++++----- .../src/ba_data/python/bastd/game/football.py | 48 +- .../src/ba_data/python/bastd/game/keepaway.py | 41 +- .../python/bastd/game/kingofthehill.py | 139 +++--- .../ba_data/python/bastd/game/meteorshower.py | 4 + .../ba_data/python/bastd/game/onslaught.py | 17 +- assets/src/ba_data/python/bastd/game/race.py | 40 +- .../python/bastd/game/targetpractice.py | 72 +-- .../ba_data/python/bastd/game/thelaststand.py | 15 +- docs/ba_module.md | 13 +- 20 files changed, 798 insertions(+), 650 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 82c262cf..c17d98c1 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/33/81/1bf0d898c26582776d0c2ef76b68", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/b6/9cf8cb137735545a5d9c5d2abc14", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/a0/b18786c5c4a3b8c8ec9417167412", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/41/1bf6ad4d57a589fb26cece393563", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/6d/39d0af901ac06b9ad655a9837a6d", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/98/0d/0d4594d20813a5b3dacb3aa2022f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8e/73/1e215e66ce6fd155b4af840465f2", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a2/21/aad47597886fe15f228386fdf0a5", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/e5/bdd60cba90f6955ba7a4a932bd45", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4f/b7/86dec4a8ab32edaf850d3c0fe2c2", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/09/ab/48ca17f389375fd4db02295bab73", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f4/12/6fb56bf6484b5b93fbfd3206bbdf" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/75/82/99d3b14b1c7ccab2de8c64bf9dea", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/78/0e5383f059887070323d08f6fa9a", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0d/23/a18e8d3f8a70f9865938d95d7184", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/27/57/8f95c8da763731b971488a18d9b4", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e9/c6/cd1d7d7568edf9f5e3d313e75eca", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7e/92/c4407e3e9017523745e381f681d8", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/57/5273080f7d383a3de8e3a519f96b", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7d/d3/01ce8f52b62fc308a358d9a5470e", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c6/44/bd76f8dc1be8b2b862876d112420", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/86/6e1418947d35a647d563aff2aebe", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9f/3d/f091bf3ed6b286a29f660a1e14cc", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a0/b3/ad0fa29417f197bed6f3fb184a3f" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index e9207771..fe13f9ad 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=266649817838802754126771358652920545389 +# SOURCES_HASH=122350585846084418668853979161934598264 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 4098788f..87bbca24 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -331,106 +331,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): raise RuntimeError(f'destroy() called when' f' already expired for {self}') - @classmethod - def _check_activity_death(cls, activity_ref: ReferenceType[Activity], - counter: List[int]) -> None: - """Sanity check to make sure an Activity was destroyed properly. - - Receives a weakref to a ba.Activity which should have torn itself - down due to no longer being referenced anywhere. Will complain - and/or print debugging info if the Activity still exists. - """ - try: - import gc - import types - activity = activity_ref() - print('ERROR: Activity is not dying when expected:', activity, - '(warning ' + str(counter[0] + 1) + ')') - print('This means something is still strong-referencing it.') - counter[0] += 1 - - # FIXME: Running the code below shows us references but winds up - # keeping the object alive; need to figure out why. - # For now we just print refs if the count gets to 3, and then we - # kill the app at 4 so it doesn't matter anyway. - if counter[0] == 3: - print('Activity references for', activity, ':') - refs = list(gc.get_referrers(activity)) - i = 1 - for ref in refs: - if isinstance(ref, types.FrameType): - continue - print(' reference', i, ':', ref) - i += 1 - if counter[0] == 4: - print('Killing app due to stuck activity... :-(') - _ba.quit() - - except Exception: - print_exception('exception on _check_activity_death:') - - def _expire(self) -> None: - """Put the activity in a state where it can be garbage-collected. - - This involves clearing anything that might be holding a reference - to it, etc. - """ - assert not self._expired - self._expired = True - - try: - self.on_expire() - except Exception: - print_exception(f'Error in Activity on_expire() for {self}') - - # Send expire notices to all remaining actors. - for actor_ref in self._actor_weak_refs: - try: - actor = actor_ref() - if actor is not None: - actor.on_expire() - except Exception: - print_exception(f'Error expiring Actor {actor_ref()}') - - # Reset all Players. - # (releases any attached actors, clears game-data, etc) - for player in self.players: - if player: - try: - sessionplayer = player.sessionplayer - sessionplayer.set_node(None) - sessionplayer.set_activity(None) - sessionplayer.gameplayer = None - sessionplayer.reset() - except Exception: - print_exception(f'Error resetting Player {player}') - - # Ditto with Teams. - for team in self.teams: - try: - sessionteam = team.sessionteam - sessionteam.gameteam = None - sessionteam.reset_gamedata() - except SessionTeamNotFoundError: - pass - except Exception: - print_exception(f'Error resetting Team {team}') - - # Regardless of what happened here, we want to destroy our data, as - # our activity might not go down if we don't. This will kill all - # Timers, Nodes, etc, which should clear up any remaining refs to our - # Actors and Activity and allow us to die peacefully. - try: - self._activity_data.destroy() - except Exception: - print_exception( - 'Exception during ba.Activity._expire() destroying data:') - - def _prune_dead_actors(self) -> None: - self._actor_refs = [a for a in self._actor_refs if a] - self._actor_weak_refs = [a for a in self._actor_weak_refs if a()] - self._last_prune_dead_actors_time = _ba.time() - def retain_actor(self, actor: ba.Actor) -> None: """Add a strong-reference to a ba.Actor to this Activity. @@ -619,127 +519,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): except Exception: print_exception('Error in on_transition_out for', self) - def create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType: - """Create the Player instance for this Activity. - - Subclasses can override this if the activity's player class - requires a custom constructor; otherwise it will be called with - no args. Note that the player object should not be used at this - point as it is not yet fully wired up; wait for on_player_join() - for that. - """ - del sessionplayer # Unused - player = self._playertype() - return player - - def create_team(self, sessionteam: ba.SessionTeam) -> TeamType: - """Create the Team instance for this Activity. - - Subclasses can override this if the activity's team class - requires a custom constructor; otherwise it will be called with - no args. Note that the team object should not be used at this - point as it is not yet fully wired up; wait for on_team_join() - for that. - """ - del sessionteam # Unused. - team = self._teamtype() - return team - - def add_player(self, sessionplayer: ba.SessionPlayer) -> None: - """(internal)""" - assert sessionplayer.team is not None - - sessionplayer.reset_input() - sessionteam = sessionplayer.team - assert sessionplayer in sessionteam.players - team = sessionteam.gameteam - assert team is not None - sessionplayer.set_activity(self) - with _ba.Context(self): - sessionplayer.gameplayer = player = self.create_player( - sessionplayer) - player.postinit(sessionplayer) - team.players.append(player) - self.players.append(player) - try: - self.on_player_join(player) - except Exception: - print_exception('Error in on_player_join for', self) - - def remove_player(self, sessionplayer: ba.SessionPlayer) -> None: - """(internal)""" - - # This should only be called on unexpired activities - # the player has been added to. - assert not self.expired - player = sessionplayer.gameplayer - assert isinstance(player, self._playertype) - assert player in self.players - - self.players.remove(player) - with _ba.Context(self): - # Make a decent attempt to persevere if user code breaks. - try: - self.on_player_leave(player) - except Exception: - print_exception(f'Error in on_player_leave for {self}') - try: - sessionplayer.reset() - sessionplayer.set_node(None) - sessionplayer.set_activity(None) - except Exception: - print_exception(f'Error resetting player for {self}') - - def add_team(self, sessionteam: ba.SessionTeam) -> None: - """(internal)""" - assert not self.expired - - with _ba.Context(self): - sessionteam.gameteam = team = self.create_team(sessionteam) - team.postinit(sessionteam) - self.teams.append(team) - try: - self.on_team_join(team) - except Exception: - print_exception(f'Error in on_team_join for {self}') - - def remove_team(self, sessionteam: ba.SessionTeam) -> None: - """(internal)""" - - # This should only be called on unexpired activities the team has - # been added to. - assert not self.expired - assert sessionteam.gameteam is not None - assert sessionteam.gameteam in self.teams - - team = sessionteam.gameteam - assert isinstance(team, self._teamtype) - self.teams.remove(team) - with _ba.Context(self): - # Make a decent attempt to persevere if user code breaks. - try: - self.on_team_leave(team) - except Exception: - print_exception(f'Error in on_team_leave for {self}') - try: - sessionteam.reset_gamedata() - except Exception: - print_exception(f'Error in reset_gamedata for {self}') - sessionteam.gameteam = None - - def _sanity_check_begin_call(self) -> None: - # Make sure ba.Activity.on_transition_in() got called at some point. - if not self._called_activity_on_transition_in: - print_error( - 'ba.Activity.on_transition_in() never got called for ' + - str(self) + '; did you forget to call it' - ' in your on_transition_in override?') - # Make sure that ba.Activity.on_begin() got called at some point. - if not self._called_activity_on_begin: - print_error( - 'ba.Activity.on_begin() never got called for ' + str(self) + - '; did you forget to call it in your on_begin override?') - def begin(self, session: ba.Session) -> None: """Begin the activity. @@ -779,6 +558,146 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self.end(self._should_end_immediately_results, self._should_end_immediately_delay) + def create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType: + """Create the Player instance for this Activity. + + Subclasses can override this if the activity's player class + requires a custom constructor; otherwise it will be called with + no args. Note that the player object should not be used at this + point as it is not yet fully wired up; wait for on_player_join() + for that. + """ + del sessionplayer # Unused + player = self._playertype() + return player + + def create_team(self, sessionteam: ba.SessionTeam) -> TeamType: + """Create the Team instance for this Activity. + + Subclasses can override this if the activity's team class + requires a custom constructor; otherwise it will be called with + no args. Note that the team object should not be used at this + point as it is not yet fully wired up; wait for on_team_join() + for that. + """ + del sessionteam # Unused. + team = self._teamtype() + return team + + def add_player(self, sessionplayer: ba.SessionPlayer) -> None: + """(internal)""" + assert sessionplayer.team is not None + sessionplayer.reset_input() + sessionteam = sessionplayer.team + assert sessionplayer in sessionteam.players + team = sessionteam.gameteam + assert team is not None + sessionplayer.set_activity(self) + with _ba.Context(self): + sessionplayer.gameplayer = player = self.create_player( + sessionplayer) + player.postinit(sessionplayer) + + assert player not in team.players + team.players.append(player) + assert player in team.players + + assert player not in self.players + self.players.append(player) + assert player in self.players + + try: + self.on_player_join(player) + except Exception: + print_exception('Error in on_player_join for', self) + + def remove_player(self, sessionplayer: ba.SessionPlayer) -> None: + """(internal)""" + + # This should only be called on unexpired activities + # the player has been added to. + assert not self.expired + + player: Any = sessionplayer.gameplayer + assert isinstance(player, self._playertype) + team: Any = sessionplayer.team.gameteam + assert isinstance(team, self._teamtype) + + assert player in team.players + team.players.remove(player) + assert player not in team.players + + assert player in self.players + self.players.remove(player) + assert player not in self.players + + with _ba.Context(self): + # Make a decent attempt to persevere if user code breaks. + try: + self.on_player_leave(player) + except Exception: + print_exception(f'Error in on_player_leave for {self}') + try: + sessionplayer.reset() + sessionplayer.set_node(None) + sessionplayer.set_activity(None) + except Exception: + print_exception(f'Error resetting player for {self}') + + def add_team(self, sessionteam: ba.SessionTeam) -> None: + """(internal)""" + assert not self.expired + + with _ba.Context(self): + sessionteam.gameteam = team = self.create_team(sessionteam) + team.postinit(sessionteam) + self.teams.append(team) + try: + self.on_team_join(team) + except Exception: + print_exception(f'Error in on_team_join for {self}') + + def remove_team(self, sessionteam: ba.SessionTeam) -> None: + """(internal)""" + + # This should only be called on unexpired activities the team has + # been added to. + assert not self.expired + assert sessionteam.gameteam is not None + assert sessionteam.gameteam in self.teams + + team = sessionteam.gameteam + assert isinstance(team, self._teamtype) + + assert team in self.teams + self.teams.remove(team) + assert team not in self.teams + + with _ba.Context(self): + # Make a decent attempt to persevere if user code breaks. + try: + self.on_team_leave(team) + except Exception: + print_exception(f'Error in on_team_leave for {self}') + try: + sessionteam.reset_gamedata() + except Exception: + print_exception(f'Error in reset_gamedata for {self}') + sessionteam.gameteam = None + + def _sanity_check_begin_call(self) -> None: + # Make sure ba.Activity.on_transition_in() got called at some point. + if not self._called_activity_on_transition_in: + print_error( + 'ba.Activity.on_transition_in() never got called for ' + + str(self) + '; did you forget to call it' + ' in your on_transition_in override?') + # Make sure that ba.Activity.on_begin() got called at some point. + if not self._called_activity_on_begin: + print_error( + 'ba.Activity.on_begin() never got called for ' + str(self) + + '; did you forget to call it in your on_begin override?') + # noinspection PyUnresolvedReferences def _setup_player_and_team_types(self) -> None: """Pull player and team types from our typing.Generic params.""" @@ -805,3 +724,104 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): f' if you do not want to override it.') assert issubclass(self._playertype, Player) assert issubclass(self._teamtype, Team) + + @classmethod + def _check_activity_death(cls, activity_ref: ReferenceType[Activity], + counter: List[int]) -> None: + """Sanity check to make sure an Activity was destroyed properly. + + Receives a weakref to a ba.Activity which should have torn itself + down due to no longer being referenced anywhere. Will complain + and/or print debugging info if the Activity still exists. + """ + try: + import gc + import types + activity = activity_ref() + print('ERROR: Activity is not dying when expected:', activity, + '(warning ' + str(counter[0] + 1) + ')') + print('This means something is still strong-referencing it.') + counter[0] += 1 + + # FIXME: Running the code below shows us references but winds up + # keeping the object alive; need to figure out why. + # For now we just print refs if the count gets to 3, and then we + # kill the app at 4 so it doesn't matter anyway. + if counter[0] == 3: + print('Activity references for', activity, ':') + refs = list(gc.get_referrers(activity)) + i = 1 + for ref in refs: + if isinstance(ref, types.FrameType): + continue + print(' reference', i, ':', ref) + i += 1 + if counter[0] == 4: + print('Killing app due to stuck activity... :-(') + _ba.quit() + + except Exception: + print_exception('exception on _check_activity_death:') + + def _expire(self) -> None: + """Put the activity in a state where it can be garbage-collected. + + This involves clearing anything that might be holding a reference + to it, etc. + """ + assert not self._expired + self._expired = True + + try: + self.on_expire() + except Exception: + print_exception(f'Error in Activity on_expire() for {self}') + + # Send expire notices to all remaining actors. + for actor_ref in self._actor_weak_refs: + try: + actor = actor_ref() + if actor is not None: + actor.on_expire() + except Exception: + print_exception(f'Error expiring Actor {actor_ref()}') + + # Reset all Players. + # (releases any attached actors, clears game-data, etc) + for player in self.players: + if player: + try: + sessionplayer = player.sessionplayer + sessionplayer.set_node(None) + sessionplayer.set_activity(None) + sessionplayer.gameplayer = None + sessionplayer.reset() + except Exception: + print_exception(f'Error resetting Player {player}') + + # Ditto with Teams. + for team in self.teams: + try: + sessionteam = team.sessionteam + sessionteam.gameteam = None + sessionteam.reset_gamedata() + except SessionTeamNotFoundError: + pass + # print_exception(f'Error resetting Team {team}') + except Exception: + print_exception(f'Error resetting Team {team}') + + # Regardless of what happened here, we want to destroy our data, as + # our activity might not go down if we don't. This will kill all + # Timers, Nodes, etc, which should clear up any remaining refs to our + # Actors and Activity and allow us to die peacefully. + try: + self._activity_data.destroy() + except Exception: + print_exception( + 'Exception during ba.Activity._expire() destroying data:') + + def _prune_dead_actors(self) -> None: + self._actor_refs = [a for a in self._actor_refs if a] + self._actor_weak_refs = [a for a in self._actor_weak_refs if a()] + self._last_prune_dead_actors_time = _ba.time() diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 9376cf69..a4997e37 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -77,7 +77,7 @@ class TeamGameResults: self._score_type = score_info.scoretype def set_team_score(self, team: Union[ba.SessionTeam, ba.Team], - score: int) -> None: + score: Optional[int]) -> None: """Set the score for a given ba.Team. This can be a number or None. diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 2779717c..baf64908 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -59,6 +59,18 @@ class Player(Generic[TeamType]): """ from ba._nodeactor import NodeActor import _ba + + # Sanity check; if a dataclass is created that inherits from us, + # it will define an equality operator by default which will break + # internal game logic. So complain loudly if we find one. + if type(self).__eq__ is not object.__eq__: + raise RuntimeError( + f'Player class {type(self)} defines an equality' + f' operator (__eq__) which will break internal' + f' logic. Please remove it.\n' + f'For dataclasses you can do "dataclass(eq=False)"' + f' in the class decorator.') + self.actor = None self.character = '' self._nodeactor: Optional[ba.NodeActor] = None diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index 7c30d959..8a6beaae 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -126,6 +126,18 @@ class Team(Generic[PlayerType]): (internal) """ + + # Sanity check; if a dataclass is created that inherits from us, + # it will define an equality operator by default which will break + # internal game logic. So complain loudly if we find one. + if type(self).__eq__ is not object.__eq__: + raise RuntimeError( + f'Team class {type(self)} defines an equality' + f' operator (__eq__) which will break internal' + f' logic. Please remove it.\n' + f'For dataclasses you can do "dataclass(eq=False)"' + f' in the class decorator.') + self.players = [] self._sessionteam = weakref.ref(sessionteam) self.id = sessionteam.id @@ -134,6 +146,15 @@ class Team(Generic[PlayerType]): self.gamedata = sessionteam.gamedata self.sessiondata = sessionteam.sessiondata + def manual_init(self, team_id: int, name: Union[ba.Lstr, str], + color: Tuple[float, ...]) -> None: + """Manually init a team for uses such as bots.""" + self.id = team_id + self.name = name + self.color = color + self.gamedata = {} + self.sessiondata = {} + @property def sessionteam(self) -> SessionTeam: """Return the ba.SessionTeam corresponding to this Team. diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index e62d0b97..d0602951 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -28,7 +28,7 @@ import weakref from typing import TYPE_CHECKING import ba -from bastd.actor import spaz as basespaz +from bastd.actor.spaz import Spaz if TYPE_CHECKING: from typing import Any, Optional, List, Tuple, Sequence, Type, Callable @@ -87,7 +87,7 @@ class SpazBotDeathMessage: self.how = how -class SpazBot(basespaz.Spaz): +class SpazBot(Spaz): """A really dumb AI version of ba.Spaz. category: Bot Classes @@ -127,13 +127,12 @@ class SpazBot(basespaz.Spaz): def __init__(self) -> None: """Instantiate a spaz-bot.""" - basespaz.Spaz.__init__(self, - color=self.color, - highlight=self.highlight, - character=self.character, - source_player=None, - start_invincible=False, - can_accept_powerups=False) + super().__init__(color=self.color, + highlight=self.highlight, + character=self.character, + source_player=None, + start_invincible=False, + can_accept_powerups=False) # If you need to add custom behavior to a bot, set this to a callable # which takes one arg (the bot) and returns False if the bot's normal @@ -503,7 +502,7 @@ class SpazBot(basespaz.Spaz): ba.getactivity().handlemessage(SpazBotPunchedMessage(self, damage)) def on_expire(self) -> None: - basespaz.Spaz.on_expire(self) + super().on_expire() # We're being torn down; release our callback(s) so there's # no chance of them keeping activities or other things alive. @@ -980,9 +979,10 @@ class BotSet: # Update our list of player points for the bots to use. player_pts = [] for player in ba.getactivity().players: + assert isinstance(player, ba.Player) try: if player.is_alive(): - assert isinstance(player.actor, basespaz.Spaz) + assert isinstance(player.actor, Spaz) assert player.actor.node player_pts.append((ba.Vec3(player.actor.node.position), ba.Vec3(player.actor.node.velocity))) diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index efc46df3..c7542650 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -37,12 +37,12 @@ if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Sequence, Union -@dataclass +@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" -@dataclass +@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" base_pos: Sequence[float] diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 50c1e09a..c190da31 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -81,13 +81,13 @@ class CTFFlag(stdflag.Flag): return delegate if isinstance(delegate, CTFFlag) else None -@dataclass +@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" touching_own_flag: int = 0 -@dataclass +@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" base_pos: Sequence[float] diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index ce87a50d..92fd55b0 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -25,19 +25,31 @@ from __future__ import annotations from typing import TYPE_CHECKING +from dataclasses import dataclass import ba -from bastd.actor import flag -from bastd.actor import playerspaz -from bastd.actor import spaz +from bastd.actor.flag import Flag +from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: from typing import (Any, Type, List, Dict, Tuple, Optional, Sequence, Union) +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + chosen_light: Optional[ba.NodeActor] = None + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + time_remaining: int + + # ba_meta export game -class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class ChosenOneGame(ba.TeamGameActivity[Player, Team]): """ Game involving trying to remain the one 'chosen one' for a set length of time while everyone else tries to @@ -96,10 +108,8 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings_raw['Epic Mode']: - self.slow_motion = True self._scoreboard = Scoreboard() - self._chosen_one_player: Optional[ba.Player] = None + self._chosen_one_player: Optional[Player] = None self._swipsound = ba.getsound('swip') self._countdownsounds: Dict[int, ba.Sound] = { 10: ba.getsound('announceTen'), @@ -115,30 +125,36 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): } self._flag_spawn_pos: Optional[Sequence[float]] = None self._reset_region_material: Optional[ba.Material] = None - self._flag: Optional[flag.Flag] = None + self._flag: Optional[Flag] = None self._reset_region: Optional[ba.Node] = None + self._epic_mode = bool(settings['Epic Mode']) + self._chosen_one_time = int(settings['Chosen One Time']) + self._time_limit = float(settings['Time Limit']) + self._chosen_one_gets_shield = bool(settings['Chosen One Gets Shield']) + self._chosen_one_gets_gloves = bool(settings['Chosen One Gets Gloves']) + + # Base class overrides + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.CHOSEN_ONE) def get_instance_description(self) -> Union[str, Sequence]: return 'There can be only one.' - def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC - if self.settings_raw['Epic Mode'] else - ba.MusicType.CHOSEN_ONE) - super().on_transition_in() + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + return Team(time_remaining=self._chosen_one_time) - def on_team_join(self, team: ba.Team) -> None: - team.gamedata['time_remaining'] = self.settings_raw['Chosen One Time'] + def on_team_join(self, team: Team) -> None: self._update_scoreboard() - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) if self._get_chosen_one_player() is player: self._set_chosen_one_player(None) def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) self.project_flag_stand(self._flag_spawn_pos) @@ -164,7 +180,7 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): 'materials': [mat] }) - def _get_chosen_one_player(self) -> Optional[ba.Player]: + def _get_chosen_one_player(self) -> Optional[Player]: if self._chosen_one_player: return self._chosen_one_player return None @@ -173,13 +189,11 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): # If we have a chosen one, ignore these. if self._get_chosen_one_player() is not None: return - try: - player = (ba.get_collision_info( - 'opposing_node').getdelegate().getplayer()) - except Exception: - return - if player is not None and player.is_alive(): - self._set_chosen_one_player(player) + delegate = ba.get_collision_info('opposing_node').getdelegate() + if isinstance(delegate, PlayerSpaz): + player = ba.playercast_o(Player, delegate.getplayer()) + if player is not None and player.is_alive(): + self._set_chosen_one_player(player) def _flash_flag_spawn(self) -> None: light = ba.newnode('light', @@ -210,29 +224,24 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): screenmessage=False, display=False) - scoring_team.gamedata['time_remaining'] = max( - 0, scoring_team.gamedata['time_remaining'] - 1) + scoring_team.time_remaining = max( + 0, scoring_team.time_remaining - 1) - # show the count over their head - try: - if scoring_team.gamedata['time_remaining'] > 0: - if isinstance(player.actor, spaz.Spaz): - player.actor.set_score_text( - str(scoring_team.gamedata['time_remaining'])) - except Exception: - pass + # Show the count over their head + if scoring_team.time_remaining > 0: + if isinstance(player.actor, PlayerSpaz) and player.actor: + player.actor.set_score_text( + str(scoring_team.time_remaining)) self._update_scoreboard() # announce numbers we have sounds for - try: - ba.playsound(self._countdownsounds[ - scoring_team.gamedata['time_remaining']]) - except Exception: - pass + if scoring_team.time_remaining in self._countdownsounds: + ba.playsound( + self._countdownsounds[scoring_team.time_remaining]) # Winner! - if scoring_team.gamedata['time_remaining'] <= 0: + if scoring_team.time_remaining <= 0: self.end_game() else: @@ -247,89 +256,81 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score( - team, self.settings_raw['Chosen One Time'] - - team.gamedata['time_remaining']) + results.set_team_score(team, + self._chosen_one_time - team.time_remaining) self.end(results=results, announce_delay=0) - def _set_chosen_one_player(self, player: Optional[ba.Player]) -> None: - try: - for p_other in self.players: - p_other.gamedata['chosen_light'] = None - ba.playsound(self._swipsound) - if not player: - assert self._flag_spawn_pos is not None - self._flag = flag.Flag(color=(1, 0.9, 0.2), - position=self._flag_spawn_pos, - touchable=False) - self._chosen_one_player = None + def _set_chosen_one_player(self, player: Optional[Player]) -> None: + for p_other in self.players: + p_other.chosen_light = None + ba.playsound(self._swipsound) + if not player: + assert self._flag_spawn_pos is not None + self._flag = Flag(color=(1, 0.9, 0.2), + position=self._flag_spawn_pos, + touchable=False) + self._chosen_one_player = None - # Create a light to highlight the flag; - # this will go away when the flag dies. - ba.newnode('light', - owner=self._flag.node, - attrs={ - 'position': self._flag_spawn_pos, - 'intensity': 0.6, - 'height_attenuated': False, - 'volume_intensity_scale': 0.1, - 'radius': 0.1, - 'color': (1.2, 1.2, 0.4) - }) + # Create a light to highlight the flag; + # this will go away when the flag dies. + ba.newnode('light', + owner=self._flag.node, + attrs={ + 'position': self._flag_spawn_pos, + 'intensity': 0.6, + 'height_attenuated': False, + 'volume_intensity_scale': 0.1, + 'radius': 0.1, + 'color': (1.2, 1.2, 0.4) + }) - # Also an extra momentary flash. - self._flash_flag_spawn() - else: - if player.actor is not None: - self._flag = None - self._chosen_one_player = player + # Also an extra momentary flash. + self._flash_flag_spawn() + else: + if player.actor: + self._flag = None + self._chosen_one_player = player - if player.actor: - if self.settings_raw['Chosen One Gets Shield']: - player.actor.handlemessage( - ba.PowerupMessage('shield')) - if self.settings_raw['Chosen One Gets Gloves']: - player.actor.handlemessage( - ba.PowerupMessage('punch')) + if self._chosen_one_gets_shield: + player.actor.handlemessage(ba.PowerupMessage('shield')) + if self._chosen_one_gets_gloves: + player.actor.handlemessage(ba.PowerupMessage('punch')) - # Use a color that's partway between their team color - # and white. - color = [ - 0.3 + c * 0.7 - for c in ba.normalized_color(player.team.color) - ] - light = player.gamedata['chosen_light'] = ba.NodeActor( - ba.newnode('light', - attrs={ - 'intensity': 0.6, - 'height_attenuated': False, - 'volume_intensity_scale': 0.1, - 'radius': 0.13, - 'color': color - })) + # Use a color that's partway between their team color + # and white. + color = [ + 0.3 + c * 0.7 + for c in ba.normalized_color(player.team.color) + ] + light = player.chosen_light = ba.NodeActor( + ba.newnode('light', + attrs={ + 'intensity': 0.6, + 'height_attenuated': False, + 'volume_intensity_scale': 0.1, + 'radius': 0.13, + 'color': color + })) - assert light.node - ba.animate(light.node, - 'intensity', { - 0: 1.0, - 0.2: 0.4, - 0.4: 1.0 - }, - loop=True) - assert isinstance(player.actor, playerspaz.PlayerSpaz) - player.actor.node.connectattr('position', light.node, - 'position') - - except Exception: - ba.print_exception('EXC in _set_chosen_one_player') + assert light.node + ba.animate(light.node, + 'intensity', { + 0: 1.0, + 0.2: 0.4, + 0.4: 1.0 + }, + loop=True) + assert isinstance(player.actor, PlayerSpaz) + player.actor.node.connectattr('position', light.node, + 'position') def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) player = msg.playerspaz(self).player if player is self._get_chosen_one_player(): - killerplayer = msg.killerplayer + killerplayer = ba.playercast_o(Player, msg.killerplayer) self._set_chosen_one_player(None if ( killerplayer is None or killerplayer is player or not killerplayer.is_alive()) else killerplayer) @@ -339,8 +340,7 @@ class ChosenOneGame(ba.TeamGameActivity[ba.Player, ba.Team]): def _update_scoreboard(self) -> None: for team in self.teams: - self._scoreboard.set_team_value( - team, - team.gamedata['time_remaining'], - self.settings_raw['Chosen One Time'], - countdown=True) + self._scoreboard.set_team_value(team, + team.time_remaining, + self._chosen_one_time, + countdown=True) diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 96e9bb91..cb805901 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -25,6 +25,7 @@ from __future__ import annotations +from dataclasses import dataclass, field from typing import TYPE_CHECKING import ba @@ -40,7 +41,7 @@ class Icon(ba.Actor): """Creates in in-game icon on screen.""" def __init__(self, - player: ba.Player, + player: Player, position: Tuple[float, float], scale: float, show_lives: bool = True, @@ -117,7 +118,7 @@ class Icon(ba.Actor): def update_for_lives(self) -> None: """Update for the target player's current lives.""" if self._player: - lives = self._player.gamedata['lives'] + lives = self._player.lives else: lives = 0 if self._show_lives: @@ -158,13 +159,27 @@ class Icon(ba.Actor): 0.50: 1.0, 0.55: 0.2 }) - lives = self._player.gamedata['lives'] + lives = self._player.lives if lives == 0: ba.timer(0.6, self.update_for_lives) +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + lives: int = 0 + icons: List[Icon] = field(default_factory=list) + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + survival_seconds: Optional[int] = None + spawn_order: List[Player] = field(default_factory=list) + + # ba_meta export game -class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class EliminationGame(ba.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" @classmethod @@ -196,13 +211,15 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: settings: List[Tuple[str, Dict[str, Any]]] = [ ('Lives Per Player', { - 'default': 1, 'min_value': 1, - 'max_value': 10, 'increment': 1 + 'default': 1, + 'min_value': 1, + 'max_value': 10, + 'increment': 1 }), ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], 'default': 0 }), ('Respawn Times', { @@ -210,7 +227,10 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): ('Long', 2.0), ('Longer', 4.0)], 'default': 1.0 }), - ('Epic Mode', {'default': False})] # yapf: disable + ('Epic Mode', { + 'default': False + }), + ] if issubclass(sessiontype, ba.DualTeamSession): settings.append(('Solo Mode', {'default': False})) @@ -221,17 +241,23 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings_raw['Epic Mode']: - self.slow_motion = True - - # Show messages when players die since it's meaningful here. - self.announce_player_deaths = True - - self._solo_mode = settings.get('Solo Mode', False) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None self._vs_text: Optional[ba.Actor] = None self._round_end_timer: Optional[ba.Timer] = None + self._epic_mode = bool(settings['Epic Mode']) + self._lives_per_player = int(settings['Lives Per Player']) + self._time_limit = float(settings['Time Limit']) + self._balance_total_lives = bool( + settings.get('Balance Total Lives', False)) + self._solo_mode = bool(settings.get('Solo Mode', False)) + + # Base class overrides: + # Show messages when players die since it's meaningful here. + self.announce_player_deaths = True + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC + if self._epic_mode else ba.MusicType.SURVIVAL) def get_instance_description(self) -> Union[str, Sequence]: return 'Last team standing wins.' if isinstance( @@ -241,65 +267,93 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): return 'last team standing wins' if isinstance( self.session, ba.DualTeamSession) else 'last one standing wins' - def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC - if self.settings_raw['Epic Mode'] else - ba.MusicType.SURVIVAL) - super().on_transition_in() - self._start_time = ba.time() - - def on_team_join(self, team: ba.Team) -> None: - team.gamedata['survival_seconds'] = None - team.gamedata['spawn_order'] = [] - - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: Player) -> None: # No longer allowing mid-game joiners here; too easy to exploit. if self.has_begun(): - player.gamedata['lives'] = 0 - player.gamedata['icons'] = [] # Make sure our team has survival seconds set if they're all dead # (otherwise blocked new ffa players would be considered 'still # alive' in score tallying). - if self._get_total_team_lives( - player.team - ) == 0 and player.team.gamedata['survival_seconds'] is None: - player.team.gamedata['survival_seconds'] = 0 - ba.screenmessage(ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', - player.get_name(full=True))]), - color=(0, 1, 0)) + if (self._get_total_team_lives(player.team) == 0 + and player.team.survival_seconds is None): + player.team.survival_seconds = 0 + ba.screenmessage( + ba.Lstr(resource='playerDelayedJoinText', + subs=[('${PLAYER}', player.get_name(full=True))]), + color=(0, 1, 0), + ) return - player.gamedata['lives'] = self.settings_raw['Lives Per Player'] + player.lives = self._lives_per_player if self._solo_mode: - player.gamedata['icons'] = [] - player.team.gamedata['spawn_order'].append(player) + player.team.spawn_order.append(player) self._update_solo_mode() else: # Create our icon and spawn. - player.gamedata['icons'] = [ - Icon(player, position=(0, 50), scale=0.8) - ] - if player.gamedata['lives'] > 0: + player.icons = [Icon(player, position=(0, 50), scale=0.8)] + if player.lives > 0: self.spawn_player(player) # Don't waste time doing this until begin. if self.has_begun(): self._update_icons() + def on_begin(self) -> None: + super().on_begin() + self._start_time = ba.time() + self.setup_standard_time_limit(self._time_limit) + self.setup_standard_powerup_drops() + if self._solo_mode: + self._vs_text = ba.NodeActor( + ba.newnode('text', + attrs={ + 'position': (0, 105), + 'h_attach': 'center', + 'h_align': 'center', + 'maxwidth': 200, + 'shadow': 0.5, + 'vr_depth': 390, + 'scale': 0.6, + 'v_attach': 'bottom', + 'color': (0.8, 0.8, 0.3, 1.0), + 'text': ba.Lstr(resource='vsText') + })) + + # If balance-team-lives is on, add lives to the smaller team until + # total lives match. + if (isinstance(self.session, ba.DualTeamSession) + and self._balance_total_lives and self.teams[0].players + and self.teams[1].players): + if self._get_total_team_lives( + self.teams[0]) < self._get_total_team_lives(self.teams[1]): + lesser_team = self.teams[0] + greater_team = self.teams[1] + else: + lesser_team = self.teams[1] + greater_team = self.teams[0] + add_index = 0 + while (self._get_total_team_lives(lesser_team) < + self._get_total_team_lives(greater_team)): + lesser_team.players[add_index].lives += 1 + add_index = (add_index + 1) % len(lesser_team.players) + + self._update_icons() + + # We could check game-over conditions at explicit trigger points, + # but lets just do the simple thing and poll it. + ba.timer(1.0, self._update, repeat=True) + def _update_solo_mode(self) -> None: # For both teams, find the first player on the spawn order list with # lives remaining and spawn them if they're not alive. for team in self.teams: # Prune dead players from the spawn order. - team.gamedata['spawn_order'] = [ - p for p in team.gamedata['spawn_order'] if p - ] - for player in team.gamedata['spawn_order']: - if player.gamedata['lives'] > 0: + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: if not player.is_alive(): self.spawn_player(player) break @@ -315,7 +369,7 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): for team in self.teams: if len(team.players) == 1: player = team.players[0] - for icon in player.gamedata['icons']: + for icon in player.icons: icon.set_position_and_scale((xval, 30), 0.7) icon.update_for_lives() xval += x_offs @@ -325,7 +379,7 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): if self._solo_mode: # First off, clear out all icons. for player in self.players: - player.gamedata['icons'] = [] + player.icons = [] # Now for each team, cycle through our available players # adding icons. @@ -340,13 +394,13 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): test_lives = 1 while True: players_with_lives = [ - p for p in team.gamedata['spawn_order'] - if p and p.gamedata['lives'] >= test_lives + p for p in team.spawn_order + if p and p.lives >= test_lives ] if not players_with_lives: break for player in players_with_lives: - player.gamedata['icons'].append( + player.icons.append( Icon(player, position=(xval, (40 if is_first else 25)), scale=1.0 if is_first else 0.5, @@ -369,12 +423,12 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): xval = 50 x_offs = 85 for player in team.players: - for icon in player.gamedata['icons']: + for icon in player.icons: icon.set_position_and_scale((xval, 30), 0.7) icon.update_for_lives() xval += x_offs - def _get_spawn_point(self, player: ba.Player) -> Optional[ba.Vec3]: + def _get_spawn_point(self, player: Player) -> Optional[ba.Vec3]: del player # Unused. # In solo-mode, if there's an existing live player on the map, spawn at @@ -403,119 +457,76 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): return points[-1][1] return None - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: actor = self.spawn_player_spaz(player, self._get_spawn_point(player)) if not self._solo_mode: ba.timer(0.3, ba.Call(self._print_lives, player)) # If we have any icons, update their state. - for icon in player.gamedata['icons']: + for icon in player.icons: icon.handle_player_spawned() return actor - def _print_lives(self, player: ba.Player) -> None: + def _print_lives(self, player: Player) -> None: from bastd.actor import popuptext - assert player # Shouldn't be passing invalid refs around. + + # We get called in a timer so it's possible our player has left/etc. if not player or not player.is_alive() or not player.node: return - popuptext.PopupText('x' + str(player.gamedata['lives'] - 1), + popuptext.PopupText('x' + str(player.lives - 1), color=(1, 1, 0, 1), offset=(0, -0.8, 0), random_offset=0.0, scale=1.8, position=player.node.position).autoretain() - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) - player.gamedata['icons'] = None + player.icons = [] # Remove us from spawn-order. if self._solo_mode: - if player in player.team.gamedata['spawn_order']: - player.team.gamedata['spawn_order'].remove(player) + if player in player.team.spawn_order: + player.team.spawn_order.remove(player) # Update icons in a moment since our team will be gone from the # list then. ba.timer(0, self._update_icons) - def on_begin(self) -> None: - super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) - self.setup_standard_powerup_drops() - if self._solo_mode: - self._vs_text = ba.NodeActor( - ba.newnode('text', - attrs={ - 'position': (0, 105), - 'h_attach': 'center', - 'h_align': 'center', - 'maxwidth': 200, - 'shadow': 0.5, - 'vr_depth': 390, - 'scale': 0.6, - 'v_attach': 'bottom', - 'color': (0.8, 0.8, 0.3, 1.0), - 'text': ba.Lstr(resource='vsText') - })) - - # If balance-team-lives is on, add lives to the smaller team until - # total lives match. - if (isinstance(self.session, ba.DualTeamSession) - and self.settings_raw['Balance Total Lives'] - and self.teams[0].players and self.teams[1].players): - if self._get_total_team_lives( - self.teams[0]) < self._get_total_team_lives(self.teams[1]): - lesser_team = self.teams[0] - greater_team = self.teams[1] - else: - lesser_team = self.teams[1] - greater_team = self.teams[0] - add_index = 0 - while self._get_total_team_lives( - lesser_team) < self._get_total_team_lives(greater_team): - lesser_team.players[add_index].gamedata['lives'] += 1 - add_index = (add_index + 1) % len(lesser_team.players) - - self._update_icons() - - # We could check game-over conditions at explicit trigger points, - # but lets just do the simple thing and poll it. - ba.timer(1.0, self._update, repeat=True) - - def _get_total_team_lives(self, team: ba.Team) -> int: - return sum(player.gamedata['lives'] for player in team.players) + def _get_total_team_lives(self, team: Team) -> int: + return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: if isinstance(msg, playerspaz.PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) - player = msg.playerspaz(self).player + player: Player = msg.playerspaz(self).player - player.gamedata['lives'] -= 1 - if player.gamedata['lives'] < 0: + player.lives -= 1 + if player.lives < 0: ba.print_error( "Got lives < 0 in Elim; this shouldn't happen. solo:" + str(self._solo_mode)) - player.gamedata['lives'] = 0 + player.lives = 0 # If we have any icons, update their state. - for icon in player.gamedata['icons']: + for icon in player.icons: icon.handle_player_died() # Play big death sound on our last death # or for every one in solo mode. - if self._solo_mode or player.gamedata['lives'] == 0: + if self._solo_mode or player.lives == 0: ba.playsound(spaz.get_factory().single_player_death_sound) # If we hit zero lives, we're dead (and our team might be too). - if player.gamedata['lives'] == 0: + if player.lives == 0: # If the whole team is now dead, mark their survival time. if self._get_total_team_lives(player.team) == 0: assert self._start_time is not None - player.team.gamedata['survival_seconds'] = int( - ba.time() - self._start_time) + player.team.survival_seconds = int(ba.time() - + self._start_time) else: # Otherwise, in regular mode, respawn. if not self._solo_mode: @@ -523,8 +534,8 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): # In solo, put ourself at the back of the spawn order. if self._solo_mode: - player.team.gamedata['spawn_order'].remove(player) - player.team.gamedata['spawn_order'].append(player) + player.team.spawn_order.remove(player) + player.team.spawn_order.append(player) def _update(self) -> None: if self._solo_mode: @@ -532,11 +543,10 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): # list with lives remaining and spawn them if they're not alive. for team in self.teams: # Prune dead players from the spawn order. - team.gamedata['spawn_order'] = [ - p for p in team.gamedata['spawn_order'] if p - ] - for player in team.gamedata['spawn_order']: - if player.gamedata['lives'] > 0: + team.spawn_order = [p for p in team.spawn_order if p] + for player in team.spawn_order: + assert isinstance(player, Player) + if player.lives > 0: if not player.is_alive(): self.spawn_player(player) self._update_icons() @@ -548,10 +558,10 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): if len(self._get_living_teams()) < 2: self._round_end_timer = ba.Timer(0.5, self.end_game) - def _get_living_teams(self) -> List[ba.Team]: + def _get_living_teams(self) -> List[Team]: return [ team for team in self.teams - if len(team.players) > 0 and any(player.gamedata['lives'] > 0 + if len(team.players) > 0 and any(player.lives > 0 for player in team.players) ] @@ -561,5 +571,5 @@ class EliminationGame(ba.TeamGameActivity[ba.Player, ba.Team]): results = ba.TeamGameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: - results.set_team_score(team, team.gamedata['survival_seconds']) + results.set_team_score(team, team.survival_seconds) self.end(results=results) diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 1b98def2..be96698c 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -26,14 +26,15 @@ from __future__ import annotations import random +from dataclasses import dataclass from typing import TYPE_CHECKING import math import ba -from bastd.actor import bomb as stdbomb -from bastd.actor import flag as stdflag -from bastd.actor import playerspaz from bastd.actor import spazbot +from bastd.actor import flag as stdflag +from bastd.actor.bomb import TNTSpawner +from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: @@ -66,8 +67,18 @@ class FootballFlag(stdflag.Flag): self.node.connectattr('position', self.light, 'position') +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class FootballTeamGame(ba.TeamGameActivity[Player, Team]): """Football game for teams mode.""" @classmethod @@ -183,7 +194,7 @@ class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._update_scoreboard() ba.playsound(self._chant_sound) - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: team.gamedata['score'] = 0 self._update_scoreboard() @@ -271,7 +282,7 @@ class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]): msg.flag.held_count -= 1 # Respawn dead players if they're still in the game. - elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): + elif isinstance(msg, PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) self.respawn_player(msg.playerspaz(self).player) @@ -320,7 +331,7 @@ class FootballTeamGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._flag = FootballFlag(position=self._flag_spawn_pos) -class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): +class FootballCoopGame(ba.CoopGameActivity[Player, Team]): """ Co-op variant of football """ @@ -385,15 +396,15 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): self._bot_types_initial: Optional[List[Type[spazbot.SpazBot]]] = None self._bot_types_7: Optional[List[Type[spazbot.SpazBot]]] = None self._bot_types_14: Optional[List[Type[spazbot.SpazBot]]] = None - self._bot_team: Optional[ba.Team] = None + self._bot_team: Optional[Team] = None self._starttime_ms: Optional[int] = None self._time_text: Optional[ba.NodeActor] = None self._time_text_input: Optional[ba.NodeActor] = None - self._tntspawner: Optional[stdbomb.TNTSpawner] = None + self._tntspawner: Optional[TNTSpawner] = None self._bots = spazbot.BotSet() self._bot_spawn_timer: Optional[ba.Timer] = None self._powerup_drop_timer: Optional[ba.Timer] = None - self.scoring_team: Optional[ba.Team] = None + self.scoring_team: Optional[Team] = None self._final_time_ms: Optional[int] = None self._time_text_timer: Optional[ba.Timer] = None self._flag_respawn_light: Optional[ba.Actor] = None @@ -508,11 +519,10 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): # Make a bogus team for our bots. bad_team_name = self.get_team_display_string('Bad Guys') - # self._bot_team = ba.Team(1, bad_team_name, (0.5, 0.4, 0.4)) - self._bot_team = ba.Team() - self._bot_team.id = 1 - self._bot_team.name = bad_team_name - self._bot_team.color = (0.5, 0.4, 0.4) + self._bot_team = Team() + self._bot_team.manual_init(team_id=1, + name=bad_team_name, + color=(0.5, 0.4, 0.4)) for team in [self.teams[0], self._bot_team]: team.gamedata['score'] = 0 @@ -547,7 +557,7 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): # Our TNT spawner (if applicable). if self._have_tnt: - self._tntspawner = stdbomb.TNTSpawner(position=(0, 1, -1)) + self._tntspawner = TNTSpawner(position=(0, 1, -1)) self._bots = spazbot.BotSet() self._bot_spawn_timer = ba.Timer(1.0, self._update_bots, repeat=True) @@ -588,7 +598,7 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): if self._flag.node: for player in self.players: if player.actor: - assert isinstance(player.actor, playerspaz.PlayerSpaz) + assert isinstance(player.actor, PlayerSpaz) if (player.actor.is_alive() and player.actor.node.hold_node == self._flag.node): return @@ -808,7 +818,7 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): def handlemessage(self, msg: Any) -> Any: """ handle high-level game messages """ - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): from bastd.actor import respawnicon # Respawn dead players. @@ -872,7 +882,7 @@ class FootballCoopGame(ba.CoopGameActivity[ba.Player, ba.Team]): del player # Unused. self._player_has_punched = True - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: spaz = self.spawn_player_spaz(player, position=self.map.get_start_position( player.team.id)) diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 41ea50a5..117cd5bb 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -25,19 +25,31 @@ from __future__ import annotations +from dataclasses import dataclass from typing import TYPE_CHECKING import ba -from bastd.actor import flag as stdflag -from bastd.actor import playerspaz +from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDeathMessage, + FlagPickedUpMessage) +from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: from typing import (Any, Type, List, Tuple, Dict, Optional, Sequence, Union) +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class KeepAwayGame(ba.TeamGameActivity[Player, Team]): """Game where you try to keep the flag away from your enemies.""" FLAG_NEW = 0 @@ -109,11 +121,11 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): } self._flag_spawn_pos: Optional[Sequence[float]] = None self._update_timer: Optional[ba.Timer] = None - self._holding_players: List[ba.Player] = [] + self._holding_players: List[Player] = [] self._flag_state: Optional[int] = None self._flag_light: Optional[ba.Node] = None - self._scoring_team: Optional[ba.Team] = None - self._flag: Optional[stdflag.Flag] = None + self._scoring_team: Optional[Team] = None + self._flag: Optional[Flag] = None def get_instance_description(self) -> Union[str, Sequence]: return ('Carry the flag for ${ARG1} seconds.', @@ -127,7 +139,7 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): self.default_music = ba.MusicType.KEEP_AWAY super().on_transition_in() - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: team.gamedata['time_remaining'] = self.settings_raw['Hold Time'] self._update_scoreboard() @@ -194,8 +206,8 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): for player in self.players: holding_flag = False try: - assert isinstance(player.actor, playerspaz.PlayerSpaz) - if (player.actor.is_alive() and player.actor.node + assert isinstance(player.actor, (PlayerSpaz, type(None))) + if (player.actor and player.actor.node and player.actor.node.hold_node): holding_flag = ( player.actor.node.hold_node.getnodetype() == 'flag') @@ -235,8 +247,7 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): ba.playsound(self._swipsound) self._flash_flag_spawn() assert self._flag_spawn_pos is not None - self._flag = stdflag.Flag(dropped_timeout=20, - position=self._flag_spawn_pos) + self._flag = Flag(dropped_timeout=20, position=self._flag_spawn_pos) self._flag_state = self.FLAG_NEW self._flag_light = ba.newnode('light', owner=self._flag.node, @@ -268,15 +279,13 @@ class KeepAwayGame(ba.TeamGameActivity[ba.Player, ba.Team]): countdown=True) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): # Augment standard behavior. super().handlemessage(msg) self.respawn_player(msg.playerspaz(self).player) - elif isinstance(msg, stdflag.FlagDeathMessage): + elif isinstance(msg, FlagDeathMessage): self._spawn_flag() - elif isinstance( - msg, - (stdflag.FlagDroppedMessage, stdflag.FlagPickedUpMessage)): + elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)): self._update_flag_state() else: super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index c0fc84bf..d01f8e3b 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -26,11 +26,12 @@ from __future__ import annotations import weakref +from dataclasses import dataclass from typing import TYPE_CHECKING import ba -from bastd.actor import flag as stdflag -from bastd.actor import playerspaz +from bastd.actor.flag import Flag +from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: from weakref import ReferenceType @@ -38,8 +39,20 @@ if TYPE_CHECKING: Union) +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + time_at_flag: int = 0 + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + time_remaining: int + + # ba_meta export game -class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): """Game where a team wins by holding a 'hill' for a set amount of time.""" FLAG_NEW = 0 @@ -71,23 +84,24 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [('Hold Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), - ('Normal', 1.0), ('Long', 2.0), - ('Longer', 4.0)], - 'default': 1.0 - })] + return [ + ('Hold Time', { + 'min_value': 10, + 'default': 30, + 'increment': 10 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ] def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard @@ -109,9 +123,11 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): } self._flag_pos: Optional[Sequence[float]] = None self._flag_state: Optional[int] = None - self._flag: Optional[stdflag.Flag] = None + self._flag: Optional[Flag] = None self._flag_light: Optional[ba.Node] = None - self._scoring_team: Optional[ReferenceType[ba.Team]] = None + self._scoring_team: Optional[ReferenceType[Team]] = None + self._hold_time = int(settings['Hold Time']) + self._time_limit = float(settings['Time Limit']) self._flag_region_material = ba.Material() self._flag_region_material.add_actions( @@ -124,38 +140,30 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): ba.Call(self._handle_player_flag_region_collide, False)))) + # Base class overrides. + self.default_music = ba.MusicType.SCARY + def get_instance_description(self) -> Union[str, Sequence]: - return ('Secure the flag for ${ARG1} seconds.', - self.settings_raw['Hold Time']) + return 'Secure the flag for ${ARG1} seconds.', self._hold_time def get_instance_scoreboard_description(self) -> Union[str, Sequence]: - return ('secure the flag for ${ARG1} seconds', - self.settings_raw['Hold Time']) + return 'secure the flag for ${ARG1} seconds', self._hold_time - def on_transition_in(self) -> None: - self.default_music = ba.MusicType.SCARY - super().on_transition_in() - - def on_team_join(self, team: ba.Team) -> None: - team.gamedata['time_remaining'] = self.settings_raw['Hold Time'] - self._update_scoreboard() - - def on_player_join(self, player: ba.Player) -> None: - super().on_player_join(player) - player.gamedata['at_flag'] = 0 + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + return Team(time_remaining=self._hold_time) def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_pos = self.map.get_flag_position(None) ba.timer(1.0, self._tick, repeat=True) self._flag_state = self.FLAG_NEW self.project_flag_stand(self._flag_pos) - self._flag = stdflag.Flag(position=self._flag_pos, - touchable=False, - color=(1, 1, 1)) + self._flag = Flag(position=self._flag_pos, + touchable=False, + color=(1, 1, 1)) self._flag_light = ba.newnode('light', attrs={ 'position': self._flag_pos, @@ -184,51 +192,47 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): # Give holding players points. for player in self.players: - if player.gamedata['at_flag'] > 0: + if player.time_at_flag > 0: self.stats.player_scored(player, 3, screenmessage=False, display=False) - if self._scoring_team is None: scoring_team = None else: scoring_team = self._scoring_team() if scoring_team: - if scoring_team.gamedata['time_remaining'] > 0: + if scoring_team.time_remaining > 0: ba.playsound(self._tick_sound) - scoring_team.gamedata['time_remaining'] = max( - 0, scoring_team.gamedata['time_remaining'] - 1) + scoring_team.time_remaining = max(0, + scoring_team.time_remaining - 1) self._update_scoreboard() - if scoring_team.gamedata['time_remaining'] > 0: + if scoring_team.time_remaining > 0: assert self._flag is not None - self._flag.set_score_text( - str(scoring_team.gamedata['time_remaining'])) + self._flag.set_score_text(str(scoring_team.time_remaining)) # Announce numbers we have sounds for. try: - ba.playsound(self._countdownsounds[ - scoring_team.gamedata['time_remaining']]) + ba.playsound( + self._countdownsounds[scoring_team.time_remaining]) except Exception: pass # winner - if scoring_team.gamedata['time_remaining'] <= 0: + if scoring_team.time_remaining <= 0: self.end_game() def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score( - team, self.settings_raw['Hold Time'] - - team.gamedata['time_remaining']) + results.set_team_score(team, self._hold_time - team.time_remaining) self.end(results=results, announce_delay=0) def _update_flag_state(self) -> None: holding_teams = set(player.team for player in self.players - if player.gamedata['at_flag']) + if player.time_at_flag) prev_state = self._flag_state assert self._flag_light assert self._flag is not None @@ -253,35 +257,36 @@ class KingOfTheHillGame(ba.TeamGameActivity[ba.Player, ba.Team]): ba.playsound(self._swipsound) def _handle_player_flag_region_collide(self, colliding: bool) -> None: - playernode = ba.get_collision_info('opposing_node') - try: - player = playernode.getdelegate().getplayer() - except Exception: + delegate = ba.get_collision_info('opposing_node').getdelegate() + if not isinstance(delegate, PlayerSpaz): + return + player = ba.playercast_o(Player, delegate.getplayer()) + if not player: return # Different parts of us can collide so a single value isn't enough # also don't count it if we're dead (flying heads shouldn't be able to # win the game :-) if colliding and player.is_alive(): - player.gamedata['at_flag'] += 1 + player.time_at_flag += 1 else: - player.gamedata['at_flag'] = max(0, player.gamedata['at_flag'] - 1) + player.time_at_flag = max(0, player.time_at_flag - 1) self._update_flag_state() def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, - team.gamedata['time_remaining'], - self.settings_raw['Hold Time'], + team.time_remaining, + self._hold_time, countdown=True) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): super().handlemessage(msg) # Augment default. - # No longer can count as at_flag once dead. + # No longer can count as time_at_flag once dead. player = msg.playerspaz(self).player - player.gamedata['at_flag'] = 0 + player.time_at_flag = 0 self._update_flag_state() self.respawn_player(player) diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 462ea14a..8b5853ea 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -255,6 +255,10 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): # (these per-player scores are only meaningful in team-games) for team in self.teams: for player in team.players: + + if not player: + print(f'GOT DEAD PLAYER {id(player)}') + survived = False # Throw an extra fudge factor in so teams that diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 192da89f..c9df8d80 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -27,6 +27,7 @@ from __future__ import annotations import math import random +from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -38,7 +39,17 @@ if TYPE_CHECKING: from bastd.actor.scoreboard import Scoreboard -class OnslaughtGame(ba.CoopGameActivity[ba.Player, ba.Team]): +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + + +class OnslaughtGame(ba.CoopGameActivity[Player, Team]): """Co-op game where players try to survive attacking waves of enemies.""" tips: List[Union[str, Dict[str, Any]]] = [ @@ -622,7 +633,7 @@ class OnslaughtGame(ba.CoopGameActivity[ba.Player, ba.Team]): return groups - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: # We keep track of who got hurt each wave for score purposes. player.gamedata['has_been_hurt'] = False @@ -816,7 +827,7 @@ class OnslaughtGame(ba.CoopGameActivity[ba.Player, ba.Team]): self._score += self._time_bonus self._update_scores() - def _award_flawless_bonus(self, player: ba.Player) -> None: + def _award_flawless_bonus(self, player: Player) -> None: ba.playsound(self._cashregistersound) try: if player.is_alive(): diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 0260de26..60b80066 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -66,8 +66,19 @@ class RaceRegion(ba.Actor): }) +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + distance_txt: Optional[ba.Node] = None + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class RaceGame(ba.TeamGameActivity[Player, Team]): """Game of racing around a track.""" @classmethod @@ -186,7 +197,7 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): for rpt in pts: self._regions.append(RaceRegion(rpt, len(self._regions))) - def _flash_player(self, player: ba.Player, scale: float) -> None: + def _flash_player(self, player: Player, scale: float) -> None: assert isinstance(player.actor, PlayerSpaz) assert player.actor.node pos = player.actor.node.position @@ -214,7 +225,7 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): region = region_node.getdelegate() if not player or not region: return - assert isinstance(player, ba.Player) + assert isinstance(player, Player) assert isinstance(region, RaceRegion) last_region = player.gamedata['last_region'] @@ -342,13 +353,13 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): except Exception as exc: print('Exception printing lap:', exc) - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: team.gamedata['time'] = None team.gamedata['lap'] = 0 team.gamedata['finished'] = False self._update_scoreboard() - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: Player) -> None: player.gamedata['last_region'] = 0 player.gamedata['lap'] = 0 player.gamedata['distance'] = 0.0 @@ -356,7 +367,7 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): player.gamedata['rank'] = None super().on_player_join(player) - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: Player) -> None: super().on_player_leave(player) # A player leaving disqualifies the team if 'Entire Team Must Finish' @@ -550,16 +561,16 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): player.gamedata['distance'] = amt # Sort players by distance and update their ranks. - p_list = [[player.gamedata['distance'], player] + p_list = [(player.gamedata['distance'], player) for player in self.players] p_list.sort(reverse=True, key=lambda x: x[0]) for i, plr in enumerate(p_list): try: plr[1].gamedata['rank'] = i - if plr[1].actor is not None: + if plr[1].actor: # noinspection PyUnresolvedReferences - node = plr[1].actor.distance_txt + node = plr[1].distance_txt if node: node.text = str(i + 1) if plr[1].is_alive() else '' except Exception: @@ -620,10 +631,11 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._flash_mine(m_index) ba.timer(0.95, ba.Call(self._make_mine, m_index)) - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: if player.team.gamedata['finished']: - # FIXME: This is not type-safe - # (this call is expected to return an Actor). + # FIXME: This is not type-safe! + # This call is expected to always return an Actor! + # Perhaps we need something like can_spawn_player()... # noinspection PyTypeChecker return None # type: ignore pos = self._regions[player.gamedata['last_region']].pos @@ -661,9 +673,7 @@ class RaceGame(ba.TeamGameActivity[ba.Player, ba.Team]): 'scale': 0.02, 'h_align': 'center' }) - # FIXME store this in a type-safe way - # noinspection PyTypeHints - spaz.distance_txt = distance_txt # type: ignore + player.distance_txt = distance_txt mathnode.connectattr('output', distance_txt, 'position') return spaz diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 505dec52..3c18deb4 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -26,6 +26,7 @@ from __future__ import annotations import random +from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -37,8 +38,20 @@ if TYPE_CHECKING: from bastd.actor.bomb import Bomb, Blast +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + streak: int = 0 + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + score: int = 0 + + # ba_meta export game -class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): """Game where players try to hit targets with bombs.""" @classmethod @@ -63,14 +76,18 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [('Target Count', { - 'min_value': 1, - 'default': 3 - }), ('Enable Impact Bombs', { - 'default': True - }), ('Enable Triple Bombs', { - 'default': True - })] + return [ + ('Target Count', { + 'min_value': 1, + 'default': 3 + }), + ('Enable Impact Bombs', { + 'default': True + }), + ('Enable Triple Bombs', { + 'default': True + }), + ] def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard @@ -79,13 +96,14 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._targets: List[Target] = [] self._update_timer: Optional[ba.Timer] = None self._countdown: Optional[OnScreenCountdown] = None + self._target_count = int(settings['Target Count']) + self._enable_impact_bombs = bool(settings['Enable Impact Bombs']) + self._enable_triple_bombs = bool(settings['Enable Triple Bombs']) - def on_transition_in(self) -> None: + # Base class overrides self.default_music = ba.MusicType.FORWARD_MARCH - super().on_transition_in() - def on_team_join(self, team: ba.Team) -> None: - team.gamedata['score'] = 0 + def on_team_join(self, team: Team) -> None: if self.has_begun(): self.update_scoreboard() @@ -95,28 +113,27 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): self.update_scoreboard() # Number of targets is based on player count. - num_targets = self.settings_raw['Target Count'] - for i in range(num_targets): + for i in range(self._target_count): ba.timer(5.0 + i * 1.0, self._spawn_target) self._update_timer = ba.Timer(1.0, self._update, repeat=True) self._countdown = OnScreenCountdown(60, endcall=self.end_game) ba.timer(4.0, self._countdown.start) - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: spawn_center = (0, 3, -5) pos = (spawn_center[0] + random.uniform(-1.5, 1.5), spawn_center[1], spawn_center[2] + random.uniform(-1.5, 1.5)) # Reset their streak. - player.gamedata['streak'] = 0 + player.streak = 0 spaz = self.spawn_player_spaz(player, position=pos) # Give players permanent triple impact bombs and wire them up # to tell us when they drop a bomb. - if self.settings_raw['Enable Impact Bombs']: + if self._enable_impact_bombs: spaz.bomb_type = 'impact' - if self.settings_raw['Enable Triple Bombs']: + if self._enable_triple_bombs: spaz.set_bomb_count(3) spaz.add_dropped_bomb_callback(self._on_spaz_dropped_bomb) return spaz @@ -166,7 +183,7 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): # Feed the explosion point to all our targets and get points in return. # Note: we operate on a copy of self._targets since the list may change # under us if we hit stuff (don't wanna get points for new targets). - player = bomb.get_source_player() + player = ba.playercast_o(Player, bomb.get_source_player()) if not player: return # could happen if they leave after throwing a bomb.. @@ -174,9 +191,9 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): target.do_hit_at_position(pos, player) for target in list(self._targets)) if bullseye: - player.gamedata['streak'] += 1 + player.streak += 1 else: - player.gamedata['streak'] = 0 + player.streak = 0 def _update(self) -> None: """Misc. periodic updating.""" @@ -200,12 +217,12 @@ class TargetPracticeGame(ba.TeamGameActivity[ba.Player, ba.Team]): def update_scoreboard(self) -> None: """Update the game scoreboard with current team values.""" for team in self.teams: - self._scoreboard.set_team_value(team, team.gamedata['score']) + self._scoreboard.set_team_value(team, team.score) def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score(team, team.gamedata['score']) + results.set_team_score(team, team.score) self.end(results) @@ -278,8 +295,7 @@ class Target(ba.Actor): """Given a point, returns distance squared from it.""" return (ba.Vec3(pos) - self._position).length() - def do_hit_at_position(self, pos: Sequence[float], - player: ba.Player) -> bool: + def do_hit_at_position(self, pos: Sequence[float], player: Player) -> bool: """Handle a bomb hit at the given position.""" # pylint: disable=too-many-statements from bastd.actor import popuptext @@ -316,7 +332,7 @@ class Target(ba.Actor): ba.animate_array(self._nodes[0], 'color', 3, keys, loop=True) popupscale = 1.8 popupcolor = (1, 1, 0, 1) - streak = player.gamedata['streak'] + streak = player.streak points = 10 + min(20, streak * 2) ba.playsound(ba.getsound('bellHigh')) if streak > 0: @@ -357,7 +373,7 @@ class Target(ba.Actor): scale=popupscale).autoretain() # Give this player's team points and update the score-board. - player.team.gamedata['score'] += points + player.team.score += points assert isinstance(activity, TargetPracticeGame) activity.update_scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 2cc04437..cff0e3c4 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -23,6 +23,7 @@ from __future__ import annotations import random +from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -35,7 +36,17 @@ if TYPE_CHECKING: from bastd.actor.scoreboard import Scoreboard -class TheLastStandGame(ba.CoopGameActivity[ba.Player, ba.Team]): +@dataclass(eq=False) +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +@dataclass(eq=False) +class Team(ba.Team[Player]): + """Our team type for this game.""" + + +class TheLastStandGame(ba.CoopGameActivity[Player, Team]): """Slow motion how-long-can-you-last game.""" tips = [ @@ -118,7 +129,7 @@ class TheLastStandGame(ba.CoopGameActivity[ba.Player, ba.Team]): self._tntspawner = TNTSpawner(position=self._tntspawnpos, respawn_time=10.0) - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: pos = (self._spawn_center[0] + random.uniform(-1.5, 1.5), self._spawn_center[1], self._spawn_center[2] + random.uniform(-1.5, 1.5)) diff --git a/docs/ba_module.md b/docs/ba_module.md index 20ca4906..d041935b 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-18 for Ballistica version 1.5.0 build 20021

    +

    last updated on 2020-05-19 for Ballistica version 1.5.0 build 20021

    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!


    @@ -4741,6 +4741,15 @@ of the session.

    Throws a ba.SessionTeamNotFoundError if there is none.

    +
    +
    +

    Methods:

    +
    +

    manual_init()

    +

    manual_init(self, team_id: int, name: Union[ba.Lstr, str], color: Tuple[float, ...]) -> None

    + +

    Manually init a team for uses such as bots.

    +

    @@ -4949,7 +4958,7 @@ Results for a completed ba.TeamGameActivity

    set_team_score()

    -

    set_team_score(self, team: Union[ba.SessionTeam, ba.Team], score: int) -> None

    +

    set_team_score(self, team: Union[ba.SessionTeam, ba.Team], score: Optional[int]) -> None

    Set the score for a given ba.Team.

    From 5828881f3d9bd9b91c9cb5fdf94805ba7e37c860 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 19 May 2020 13:56:28 -0700 Subject: [PATCH 018/417] Updated a few camelCase attr names to pep8_style --- .efrocachemap | 24 +++++++++---------- .../python/bastd/game/easteregghunt.py | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index c17d98c1..0e2e2414 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/75/82/99d3b14b1c7ccab2de8c64bf9dea", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/78/0e5383f059887070323d08f6fa9a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0d/23/a18e8d3f8a70f9865938d95d7184", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/27/57/8f95c8da763731b971488a18d9b4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e9/c6/cd1d7d7568edf9f5e3d313e75eca", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7e/92/c4407e3e9017523745e381f681d8", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/57/5273080f7d383a3de8e3a519f96b", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7d/d3/01ce8f52b62fc308a358d9a5470e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c6/44/bd76f8dc1be8b2b862876d112420", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/86/6e1418947d35a647d563aff2aebe", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9f/3d/f091bf3ed6b286a29f660a1e14cc", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a0/b3/ad0fa29417f197bed6f3fb184a3f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/b6/bbdb904d5cea6023a50d4dc2c9e9", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/17/34/76b4411678f95106d2e3e368c79b", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/83/b9/a679a7aaeb67227f94286ea9fffb", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/95/a0/7a95002b5cc7d1bacbda49098fd9", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/b8/1b547866b77a98fcc5ca43c93a07", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ee/c4/0e92e825c67a249a77b16bb7a4fa", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/31/1e/2d282dff8a9331b121908061c6bc", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/eb/9bf8367a161f3e9fb29b4f61216e", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4a/22/30984f1fd3a430755ea62c80ec76", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fe/f5/e99958f225c4b342c1bd4ecb0c23", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/fd/b26b46b083240ad3855ba93cb42d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a7/ee/ec0ee56e6f7254b460c4f1116a0c" } \ No newline at end of file diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 41f61ece..6a68eeff 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -272,7 +272,7 @@ class Egg(ba.Actor): 'body': 'capsule', 'reflection': 'soft', 'model_scale': 0.5, - 'bodyScale': 0.6, + 'body_scale': 0.6, 'density': 4.0, 'reflection_scale': [0.15], 'shadow_size': 0.6, From 3ff115272f68625c8201881709712ed0c8864194 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 19 May 2020 17:27:40 -0700 Subject: [PATCH 019/417] Added shorthand ways to define some game attrs --- assets/src/ba_data/python/ba/_coopsession.py | 4 +- assets/src/ba_data/python/ba/_gameactivity.py | 59 ++++-- assets/src/ba_data/python/ba/_playlist.py | 2 +- .../src/ba_data/python/bastd/game/assault.py | 69 +++--- .../python/bastd/game/capturetheflag.py | 78 +++---- .../ba_data/python/bastd/game/chosenone.py | 78 +++---- .../src/ba_data/python/bastd/game/conquest.py | 53 ++--- .../ba_data/python/bastd/game/deathmatch.py | 59 +++--- .../python/bastd/game/easteregghunt.py | 23 +- .../ba_data/python/bastd/game/elimination.py | 46 ++-- .../src/ba_data/python/bastd/game/football.py | 69 +++--- .../src/ba_data/python/bastd/game/hockey.py | 52 ++--- .../src/ba_data/python/bastd/game/keepaway.py | 87 ++++---- .../python/bastd/game/kingofthehill.py | 114 +++++----- .../ba_data/python/bastd/game/meteorshower.py | 34 +-- .../ba_data/python/bastd/game/ninjafight.py | 18 +- .../ba_data/python/bastd/game/onslaught.py | 15 +- assets/src/ba_data/python/bastd/game/race.py | 50 ++--- .../ba_data/python/bastd/game/runaround.py | 10 +- .../python/bastd/game/targetpractice.py | 51 ++--- .../ba_data/python/bastd/game/thelaststand.py | 19 +- .../python/bastd/ui/playlist/editgame.py | 2 +- docs/ba_module.md | 198 +++++++++--------- 23 files changed, 511 insertions(+), 679 deletions(-) diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index b6c008ec..569aecc9 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -124,7 +124,7 @@ class CoopSession(Session): settings = level.get_settings() # Make sure all settings the game expects are present. - neededsettings = gametype.get_settings(type(self)) + neededsettings = gametype.get_game_settings(type(self)) for settingname, setting in neededsettings: if settingname not in settings: settings[settingname] = setting['default'] @@ -147,7 +147,7 @@ class CoopSession(Session): settings = nextlevel.get_settings() # Make sure all settings the game expects are present. - neededsettings = gametype.get_settings(type(self)) + neededsettings = gametype.get_game_settings(type(self)) for settingname, setting in neededsettings: if settingname not in settings: settings[settingname] = setting['default'] diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index e59ff9fb..d8f62401 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -51,6 +51,18 @@ class GameActivity(Activity[PlayerType, TeamType]): tips: List[Union[str, Dict[str, Any]]] = [] + # Default get_name() will return this if not None. + name: Optional[str] = None + + # Default get_description() will return this if not None. + description: Optional[str] = None + + # Default get_game_settings() will return this if not None. + game_settings: Optional[List[Tuple[str, Dict[str, Any]]]] = None + + # Default get_score_info() will return this if not None. + score_info: Optional[ba.ScoreInfo] = None + @classmethod def create_config_ui( cls, @@ -69,9 +81,9 @@ class GameActivity(Activity[PlayerType, TeamType]): success or None on cancel. Generally subclasses don't need to override this; if they override - ba.GameActivity.get_settings() and ba.GameActivity.get_supported_maps() - they can just rely on the default implementation here which calls those - methods. + ba.GameActivity.get_game_settings() and + ba.GameActivity.get_supported_maps() they can just rely on + the default implementation here which calls those methods. """ delegate = _ba.app.delegate assert delegate is not None @@ -81,15 +93,15 @@ class GameActivity(Activity[PlayerType, TeamType]): @classmethod def get_score_info(cls) -> ba.ScoreInfo: """Return info about game scoring setup; can be overridden by games.""" - return ScoreInfo() + return cls.score_info if cls.score_info is not None else ScoreInfo() @classmethod def get_name(cls) -> str: - """Return a str name for this game type.""" - try: - return cls.__module__.replace('_', ' ') - except Exception: - return 'Untitled Game' + """Return a str name for this game type. + + This default implementation simply returns the 'name' class attr. + """ + return cls.name if cls.name is not None else 'Untitled Game' @classmethod def get_display_string(cls, settings: Optional[Dict] = None) -> ba.Lstr: @@ -119,13 +131,14 @@ class GameActivity(Activity[PlayerType, TeamType]): @classmethod def get_description(cls, sessiontype: Type[ba.Session]) -> str: - """ - Subclasses should override this to return a description for this - activity type (in English) within the context of the given - ba.Session type. + """Get a str description of this game type. + + The default implementation simply returns the 'description' class var. + Classes which want to change their description depending on the session + can override this method. """ del sessiontype # unused arg - return '' + return cls.description if cls.description is not None else '' @classmethod def get_description_display_string( @@ -138,7 +151,7 @@ class GameActivity(Activity[PlayerType, TeamType]): return Lstr(translate=('gameDescriptions', description)) @classmethod - def get_settings( + def get_game_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: """ @@ -162,9 +175,9 @@ class GameActivity(Activity[PlayerType, TeamType]): 'increment': Value increment for int/float settings. - # example get_settings() implementation for a capture-the-flag game: + # example get_game_settings() for a capture-the-flag game: @classmethod - def get_settings(cls,sessiontype): + def get_game_settings(cls, sessiontype): return [("Score to Win", { 'default': 3, 'min_value': 1 @@ -199,7 +212,7 @@ class GameActivity(Activity[PlayerType, TeamType]): })] """ del sessiontype # Unused arg. - return [] + return [] if cls.game_settings is None else cls.game_settings @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: @@ -353,7 +366,7 @@ class GameActivity(Activity[PlayerType, TeamType]): This is shown in the center of the screen below the game name at the start of a game. It should start with a capital letter and end with a period, and can be a bit more verbose than the version returned by - get_instance_scoreboard_description(). + get_instance_description_short(). Note that translation is applied by looking up the specific returned value as a key, so the number of returned variations should be limited; @@ -361,7 +374,7 @@ class GameActivity(Activity[PlayerType, TeamType]): description, you can return a sequence of values in the following form instead of just a string: - # this will give us something like 'Score 3 goals.' in English + # This will give us something like 'Score 3 goals.' in English # and can properly translate to 'Anota 3 goles.' in Spanish. # If we just returned the string 'Score 3 Goals' here, there would # have to be a translation entry for each specific number. ew. @@ -373,7 +386,7 @@ class GameActivity(Activity[PlayerType, TeamType]): """ return self.get_description(type(self.session)) - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: """Return a short description for this game instance in English. This description is used above the game scoreboard in the @@ -387,7 +400,7 @@ class GameActivity(Activity[PlayerType, TeamType]): description, you can return a sequence of values in the following form instead of just a string: - # this will give us something like 'score 3 goals' in English + # This will give us something like 'score 3 goals' in English # and can properly translate to 'anota 3 goles' in Spanish. # If we just returned the string 'score 3 goals' here, there would # have to be a translation entry for each specific number. ew. @@ -669,7 +682,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # the description can be either a string or a sequence with args # to swap in post-translation - sb_desc_in = self.get_instance_scoreboard_description() + sb_desc_in = self.get_instance_description_short() sb_desc_l: Sequence if isinstance(sb_desc_in, str): sb_desc_l = [sb_desc_in] # handle simple string case diff --git a/assets/src/ba_data/python/ba/_playlist.py b/assets/src/ba_data/python/ba/_playlist.py index b50b1c6c..1786ee21 100644 --- a/assets/src/ba_data/python/ba/_playlist.py +++ b/assets/src/ba_data/python/ba/_playlist.py @@ -151,7 +151,7 @@ def filter_playlist(playlist: PlaylistType, entry['is_unowned_game'] = True # Make sure all settings the game defines are present. - neededsettings = gameclass.get_settings(sessiontype) + neededsettings = gameclass.get_game_settings(sessiontype) for setting_name, setting in neededsettings: if (setting_name not in entry['settings'] and 'default' in setting): diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index c7542650..334571df 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -26,7 +26,6 @@ from __future__ import annotations import random -from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -34,33 +33,48 @@ from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage from bastd.actor.flag import Flag if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Tuple, Sequence, Union + from typing import Any, Type, List, Dict, Sequence, Union -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" - base_pos: Sequence[float] - flag: Flag - score: int = 0 + + def __init__(self, base_pos: Sequence[float], flag: Flag) -> None: + self.base_pos = base_pos + self.flag = flag + self.score = 0 # ba_meta export game class AssaultGame(ba.TeamGameActivity[Player, Team]): """Game where you score by touching the other team's flag.""" - @classmethod - def get_name(cls) -> str: - return 'Assault' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Reach the enemy flag to score.' + name = 'Assault' + description = 'Reach the enemy flag to score.' + game_settings = [ + ('Score to Win', { + 'min_value': 1, + 'default': 3 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -70,31 +84,6 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('team_flag') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Score to Win', { - 'min_value': 1, - 'default': 3 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), - ] - def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) @@ -116,7 +105,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): return 'Touch the enemy flag.' return 'Touch the enemy flag ${ARG1} times.', self._score_to_win - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: if self._score_to_win == 1: return 'touch 1 flag' return 'touch ${ARG1} flags', self._score_to_win diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index c190da31..99f617b4 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -34,7 +34,7 @@ from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Tuple, Sequence, Union, Optional + from typing import Any, Type, List, Dict, Sequence, Union, Optional class CTFFlag(stdflag.Flag): @@ -110,13 +110,38 @@ class Team(ba.Team[Player]): class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): """Game of stealing other team's flag and returning it to your base.""" - @classmethod - def get_name(cls) -> str: - return 'Capture the Flag' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Return the enemy flag to score.' + name = 'Capture the Flag' + description = 'Return the enemy flag to score.' + game_settings = [ + ('Score to Win', { + 'min_value': 1, + 'default': 3 + }), + ('Flag Touch Return Time', { + 'min_value': 0, + 'default': 0, + 'increment': 1 + }), + ('Flag Idle Return Time', { + 'min_value': 5, + 'default': 30, + 'increment': 5 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -126,41 +151,6 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('team_flag') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Score to Win', { - 'min_value': 1, - 'default': 3 - }), - ('Flag Touch Return Time', { - 'min_value': 0, - 'default': 0, - 'increment': 1 - }), - ('Flag Idle Return Time', { - 'min_value': 5, - 'default': 30, - 'increment': 5 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), - ] - def __init__(self, settings: Dict[str, Any]): super().__init__(settings) self._scoreboard = Scoreboard() @@ -192,7 +182,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): return 'Steal the enemy flag.' return 'Steal the enemy flag ${ARG1} times.', self._score_to_win - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: if self._score_to_win == 1: return 'return 1 flag' return 'return ${ARG1} flags', self._score_to_win diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 92fd55b0..db166dc0 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -32,8 +32,7 @@ from bastd.actor.flag import Flag from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: - from typing import (Any, Type, List, Dict, Tuple, Optional, Sequence, - Union) + from typing import Any, Type, List, Dict, Optional, Sequence, Union @dataclass(eq=False) @@ -56,55 +55,42 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): kill you and become the chosen one themselves. """ - @classmethod - def get_name(cls) -> str: - return 'Chosen One' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Time Held') - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return ('Be the chosen one for a length of time to win.\n' - 'Kill the chosen one to become it.') + name = 'Chosen One' + description = ('Be the chosen one for a length of time to win.\n' + 'Kill the chosen one to become it.') + game_settings = [ + ('Chosen One Time', { + 'min_value': 10, + 'default': 30, + 'increment': 10 + }), + ('Chosen One Gets Gloves', { + 'default': True + }), + ('Chosen One Gets Shield', { + 'default': False + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] + score_info = ba.ScoreInfo(label='Time Held') @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('keep_away') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Chosen One Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Chosen One Gets Gloves', { - 'default': True - }), - ('Chosen One Gets Shield', { - 'default': False - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), - ] - def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 361039bb..b459e147 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -33,8 +33,7 @@ from bastd.actor.flag import Flag from bastd.actor.playerspaz import PlayerSpazDeathMessage if TYPE_CHECKING: - from typing import (Any, Optional, Type, List, Tuple, Dict, Sequence, - Union) + from typing import Any, Optional, Type, List, Dict, Sequence, Union class ConquestFlag(Flag): @@ -60,13 +59,24 @@ class ConquestFlag(Flag): class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): """A game where teams try to claim all flags on the map.""" - @classmethod - def get_name(cls) -> str: - return 'Conquest' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Secure all flags on the map to win.' + name = 'Conquest' + description = 'Secure all flags on the map to win.' + game_settings = [ + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ('Epic Mode', { + 'default': False + }), + ] @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -76,29 +86,6 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('conquest') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), - ('5 Minutes', 300), - ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), - ('Short', 0.5), - ('Normal', 1.0), - ('Long', 2.0), - ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', {'default': False})] # yapf: disable - def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) @@ -119,7 +106,7 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_instance_description(self) -> Union[str, Sequence]: return 'Secure all ${ARG1} flags.', len(self.map.flag_points) - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: return 'secure all ${ARG1} flags', len(self.map.flag_points) def on_transition_in(self) -> None: diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index e6d64d2e..e2f37062 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -38,25 +38,14 @@ if TYPE_CHECKING: class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): """A game type based on acquiring kills.""" - @classmethod - def get_name(cls) -> str: - return 'Death Match' + name = 'Death Match' + description = 'Kill a set number of enemies to win.' + + # Print messages when players die since it matters here. + announce_player_deaths = True @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Kill a set number of enemies to win.' - - @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') - - @classmethod - def get_settings( + def get_game_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: settings: List[Tuple[str, Dict[str, Any]]] = [ @@ -66,24 +55,20 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): 'increment': 1 }), ('Time Limit', { - 'choices': - [('None', 0), - ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 }), ('Respawn Times', { - 'choices': - [('Shorter', 0.25), ('Short', 0.5), - ('Normal', 1.0), ('Long', 2.0), - ('Longer', 4.0)], - 'default': 1.0 + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 }), ('Epic Mode', { 'default': False - }) - ] # yapf: disable + }), + ] # In teams mode, a suicide gives a point to the other team, but in # free-for-all it subtracts from your own score. By default we clamp @@ -95,15 +80,21 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): return settings + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('melee') + def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) if self.settings_raw['Epic Mode']: self.slow_motion = True - # Print messages when players die since it matters here. - self.announce_player_deaths = True - self._scoreboard = Scoreboard() self._score_to_win = None self._dingsound = ba.getsound('dingSmall') @@ -111,7 +102,7 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_instance_description(self) -> Union[str, Sequence]: return 'Crush ${ARG1} of your enemies.', self._score_to_win - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: return 'kill ${ARG1} enemies', self._score_to_win def on_transition_in(self) -> None: diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 6a68eeff..79e5382b 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -33,6 +33,7 @@ from bastd.actor import bomb from bastd.actor import playerspaz from bastd.actor import spazbot from bastd.actor.onscreencountdown import OnScreenCountdown +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Type, Dict, List, Tuple, Optional @@ -42,17 +43,10 @@ if TYPE_CHECKING: class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): """A game where score is based on collecting eggs.""" - @classmethod - def get_name(cls) -> str: - return 'Easter Egg Hunt' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Score', scoretype=ba.ScoreType.POINTS) - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Gather eggs!' + name = 'Easter Egg Hunt' + description = 'Gather eggs!' + game_settings = [('Pro Mode', {'default': False})] + score_info = ba.ScoreInfo(label='Score', scoretype=ba.ScoreType.POINTS) # We're currently hard-coded for one map. @classmethod @@ -66,14 +60,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): or issubclass(sessiontype, ba.DualTeamSession) or issubclass(sessiontype, ba.FreeForAllSession)) - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [('Pro Mode', {'default': False})] - def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._last_player_death_time = None self._scoreboard = Scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index cb805901..ffe07ce3 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -182,31 +182,16 @@ class Team(ba.Team[Player]): class EliminationGame(ba.TeamGameActivity[Player, Team]): """Game type where last player(s) left alive win.""" - @classmethod - def get_name(cls) -> str: - return 'Elimination' + name = 'Elimination' + description = 'Last remaining alive wins.' + score_info = ba.ScoreInfo(label='Survived', + scoretype=ba.ScoreType.SECONDS, + none_is_winner=True) + # Show messages when players die since it's meaningful here. + announce_player_deaths = True @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Survived', - scoretype=ba.ScoreType.SECONDS, - none_is_winner=True) - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Last remaining alive wins.' - - @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return (issubclass(sessiontype, ba.DualTeamSession) - or issubclass(sessiontype, ba.FreeForAllSession)) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('melee') - - @classmethod - def get_settings( + def get_game_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: settings: List[Tuple[str, Dict[str, Any]]] = [ @@ -231,13 +216,20 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): 'default': False }), ] - if issubclass(sessiontype, ba.DualTeamSession): settings.append(('Solo Mode', {'default': False})) settings.append(('Balance Total Lives', {'default': False})) - return settings + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return (issubclass(sessiontype, ba.DualTeamSession) + or issubclass(sessiontype, ba.FreeForAllSession)) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('melee') + def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) @@ -253,8 +245,6 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): self._solo_mode = bool(settings.get('Solo Mode', False)) # Base class overrides: - # Show messages when players die since it's meaningful here. - self.announce_player_deaths = True self.slow_motion = self._epic_mode self.default_music = (ba.MusicType.EPIC if self._epic_mode else ba.MusicType.SURVIVAL) @@ -263,7 +253,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): return 'Last team standing wins.' if isinstance( self.session, ba.DualTeamSession) else 'Last one standing wins.' - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: return 'last team standing wins' if isinstance( self.session, ba.DualTeamSession) else 'last one standing wins' diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index be96698c..d8cdbccc 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -38,8 +38,7 @@ from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: - from typing import (Any, List, Tuple, Type, Dict, Sequence, Optional, - Union) + from typing import Any, List, Type, Dict, Sequence, Optional, Union from bastd.actor.spaz import Spaz @@ -81,46 +80,36 @@ class Team(ba.Team[Player]): class FootballTeamGame(ba.TeamGameActivity[Player, Team]): """Football game for teams mode.""" - @classmethod - def get_name(cls) -> str: - return 'Football' + name = 'Football' + description = 'Get the flag to the enemy end zone.' + game_settings = [ + ('Score to Win', { + 'min_value': 7, + 'default': 21, + 'increment': 7 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ] @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: # We only support two-team play. return issubclass(sessiontype, ba.DualTeamSession) - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Get the flag to the enemy end zone.' - @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('football') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Score to Win', { - 'min_value': 7, - 'default': 21, - 'increment': 7 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }) - ] # yapf: disable - def __init__(self, settings: Dict[str, Any]): super().__init__(settings) self._scoreboard: Optional[Scoreboard] = Scoreboard() @@ -131,7 +120,6 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self._score_sound = ba.getsound('score') self._swipsound = ba.getsound('swip') self._whistle_sound = ba.getsound('refWhistle') - self.score_region_material = ba.Material() self.score_region_material.add_actions( conditions=('they_have_material', @@ -147,6 +135,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): def get_instance_description(self) -> Union[str, Sequence]: touchdowns = self.settings_raw['Score to Win'] / 7 + # NOTE: if use just touchdowns = self.settings_raw['Score to Win'] // 7 # and we will need to score, for example, 27 points, # we will be required to score 3 (not 4) goals .. @@ -155,7 +144,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): return 'Score ${ARG1} touchdowns.', touchdowns return 'Score a touchdown.' - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: touchdowns = self.settings_raw['Score to Win'] / 7 touchdowns = math.ceil(touchdowns) if touchdowns > 1: @@ -336,15 +325,9 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): Co-op variant of football """ + name = 'Football' tips = ['Use the pick-up button to grab the flag < ${PICKUP} >'] - - @classmethod - def get_name(cls) -> str: - return 'Football' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(scoretype=ba.ScoreType.MILLISECONDS, version='B') + score_info = ba.ScoreInfo(scoretype=ba.ScoreType.MILLISECONDS, version='B') # FIXME: Need to update co-op games to use get_score_info. def get_score_type(self) -> str: @@ -357,7 +340,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): return 'Score ${ARG1} touchdowns.', touchdowns return 'Score a touchdown.' - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: touchdowns = self._score_to_win / 7 touchdowns = math.ceil(touchdowns) if touchdowns > 1: diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index fa611c6b..de4a813a 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -31,8 +31,7 @@ import ba from bastd.actor import playerspaz if TYPE_CHECKING: - from typing import (Any, Sequence, Dict, Type, List, Tuple, Optional, - Union) + from typing import Any, Sequence, Dict, Type, List, Optional, Union class PuckDeathMessage: @@ -109,13 +108,26 @@ class Puck(ba.Actor): class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): """Ice hockey game.""" - @classmethod - def get_name(cls) -> str: - return 'Hockey' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Score some goals.' + name = 'Hockey' + description = 'Score some goals.' + game_settings = [ + ('Score to Win', { + 'min_value': 1, + 'default': 1, + 'increment': 1 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ] @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -125,26 +137,6 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('hockey') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Score to Win', { - 'min_value': 1, 'default': 1, 'increment': 1 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - })] # yapf: disable - def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard from bastd.actor import powerupbox @@ -201,7 +193,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): return 'Score a goal.' return 'Score ${ARG1} goals.', self.settings_raw['Score to Win'] - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: if self.settings_raw['Score to Win'] == 1: return 'score a goal' return 'score ${ARG1} goals', self.settings_raw['Score to Win'] diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 117cd5bb..b3ea1d54 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -25,7 +25,7 @@ from __future__ import annotations -from dataclasses import dataclass +from enum import Enum from typing import TYPE_CHECKING import ba @@ -34,16 +34,21 @@ from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDeathMessage, from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: - from typing import (Any, Type, List, Tuple, Dict, Optional, Sequence, - Union) + from typing import Any, Type, List, Dict, Optional, Sequence, Union + + +class FlagState(Enum): + """States our single flag can be in.""" + NEW = 0 + UNCONTESTED = 1 + CONTESTED = 2 + HELD = 3 -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" @@ -52,22 +57,27 @@ class Team(ba.Team[Player]): class KeepAwayGame(ba.TeamGameActivity[Player, Team]): """Game where you try to keep the flag away from your enemies.""" - FLAG_NEW = 0 - FLAG_UNCONTESTED = 1 - FLAG_CONTESTED = 2 - FLAG_HELD = 3 - - @classmethod - def get_name(cls) -> str: - return 'Keep Away' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Carry the flag for a set length of time.' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Time Held') + name = 'Keep Away' + description = 'Carry the flag for a set length of time.' + game_settings = [ + ('Hold Time', { + 'min_value': 10, + 'default': 30, + 'increment': 10 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ] + score_info = ba.ScoreInfo(label='Time Held') @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -78,29 +88,6 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('keep_away') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Hold Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }) - ] # yapf: disable - def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) @@ -122,7 +109,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): self._flag_spawn_pos: Optional[Sequence[float]] = None self._update_timer: Optional[ba.Timer] = None self._holding_players: List[Player] = [] - self._flag_state: Optional[int] = None + self._flag_state: Optional[FlagState] = None self._flag_light: Optional[ba.Node] = None self._scoring_team: Optional[Team] = None self._flag: Optional[Flag] = None @@ -131,7 +118,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): return ('Carry the flag for ${ARG1} seconds.', self.settings_raw['Hold Time']) - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: return ('carry the flag for ${ARG1} seconds', self.settings_raw['Hold Time']) @@ -224,18 +211,18 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): assert self._flag_light assert self._flag.node if len(holding_teams) > 1: - self._flag_state = self.FLAG_CONTESTED + self._flag_state = FlagState.CONTESTED self._scoring_team = None self._flag_light.color = (0.6, 0.6, 0.1) self._flag.node.color = (1.0, 1.0, 0.4) elif len(holding_teams) == 1: holding_team = list(holding_teams)[0] - self._flag_state = self.FLAG_HELD + self._flag_state = FlagState.HELD self._scoring_team = holding_team self._flag_light.color = ba.normalized_color(holding_team.color) self._flag.node.color = holding_team.color else: - self._flag_state = self.FLAG_UNCONTESTED + self._flag_state = FlagState.UNCONTESTED self._scoring_team = None self._flag_light.color = (0.2, 0.2, 0.2) self._flag.node.color = (1, 1, 1) @@ -248,7 +235,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): self._flash_flag_spawn() assert self._flag_spawn_pos is not None self._flag = Flag(dropped_timeout=20, position=self._flag_spawn_pos) - self._flag_state = self.FLAG_NEW + self._flag_state = FlagState.NEW self._flag_light = ba.newnode('light', owner=self._flag.node, attrs={ diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index d01f8e3b..b69be0f4 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -26,51 +26,66 @@ from __future__ import annotations import weakref -from dataclasses import dataclass +from enum import Enum from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from weakref import ReferenceType - from typing import (Any, Type, List, Dict, Tuple, Optional, Sequence, - Union) + from typing import Any, Type, List, Dict, Optional, Sequence, Union + + +class FlagState(Enum): + """States our single flag can be in.""" + NEW = 0 + UNCONTESTED = 1 + CONTESTED = 2 + HELD = 3 -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" - time_at_flag: int = 0 + + def __init__(self) -> None: + self.time_at_flag = 0 -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" - time_remaining: int + + def __init__(self, time_remaining: int) -> None: + self.time_remaining = time_remaining # ba_meta export game class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): """Game where a team wins by holding a 'hill' for a set amount of time.""" - FLAG_NEW = 0 - FLAG_UNCONTESTED = 1 - FLAG_CONTESTED = 2 - FLAG_HELD = 3 - - @classmethod - def get_name(cls) -> str: - return 'King of the Hill' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Secure the flag for a set length of time.' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Time Held') + name = 'King of the Hill' + description = 'Secure the flag for a set length of time.' + game_settings = [ + ('Hold Time', { + 'min_value': 10, + 'default': 30, + 'increment': 10 + }), + ('Time Limit', { + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], + 'default': 0 + }), + ('Respawn Times', { + 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), + ('Long', 2.0), ('Longer', 4.0)], + 'default': 1.0 + }), + ] + score_info = ba.ScoreInfo(label='Time Held') @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -80,31 +95,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('king_of_the_hill') - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Hold Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ] - def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._swipsound = ba.getsound('swip') @@ -122,23 +113,23 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): 1: ba.getsound('announceOne') } self._flag_pos: Optional[Sequence[float]] = None - self._flag_state: Optional[int] = None + self._flag_state: Optional[FlagState] = None self._flag: Optional[Flag] = None self._flag_light: Optional[ba.Node] = None self._scoring_team: Optional[ReferenceType[Team]] = None self._hold_time = int(settings['Hold Time']) self._time_limit = float(settings['Time Limit']) - self._flag_region_material = ba.Material() self._flag_region_material.add_actions( conditions=('they_have_material', ba.sharedobj('player_material')), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('call', 'at_connect', - ba.Call(self._handle_player_flag_region_collide, True)), - ('call', 'at_disconnect', - ba.Call(self._handle_player_flag_region_collide, - False)))) + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + ba.Call(self._handle_player_flag_region_collide, True)), + ('call', 'at_disconnect', + ba.Call(self._handle_player_flag_region_collide, False)), + )) # Base class overrides. self.default_music = ba.MusicType.SCARY @@ -146,7 +137,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): def get_instance_description(self) -> Union[str, Sequence]: return 'Secure the flag for ${ARG1} seconds.', self._hold_time - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: return 'secure the flag for ${ARG1} seconds', self._hold_time def create_team(self, sessionteam: ba.SessionTeam) -> Team: @@ -158,7 +149,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): self.setup_standard_powerup_drops() self._flag_pos = self.map.get_flag_position(None) ba.timer(1.0, self._tick, repeat=True) - self._flag_state = self.FLAG_NEW + self._flag_state = FlagState.NEW self.project_flag_stand(self._flag_pos) self._flag = Flag(position=self._flag_pos, @@ -172,7 +163,6 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): 'radius': 0.4, 'color': (0.2, 0.2, 0.2) }) - # Flag region. flagmats = [ self._flag_region_material, @@ -238,18 +228,18 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): assert self._flag is not None assert self._flag.node if len(holding_teams) > 1: - self._flag_state = self.FLAG_CONTESTED + self._flag_state = FlagState.CONTESTED self._scoring_team = None self._flag_light.color = (0.6, 0.6, 0.1) self._flag.node.color = (1.0, 1.0, 0.4) elif len(holding_teams) == 1: holding_team = list(holding_teams)[0] - self._flag_state = self.FLAG_HELD + self._flag_state = FlagState.HELD self._scoring_team = weakref.ref(holding_team) self._flag_light.color = ba.normalized_color(holding_team.color) self._flag.node.color = holding_team.color else: - self._flag_state = self.FLAG_UNCONTESTED + self._flag_state = FlagState.UNCONTESTED self._scoring_team = None self._flag_light.color = (0.2, 0.2, 0.2) self._flag.node.color = (1, 1, 1) diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 8b5853ea..3e1103dd 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -34,7 +34,7 @@ from bastd.actor.playerspaz import PlayerSpazDeathMessage from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: - from typing import Any, Tuple, Sequence, Optional, List, Dict, Type, Type + from typing import Any, Sequence, Optional, List, Dict, Type, Type class Player(ba.Player['Team']): @@ -53,31 +53,21 @@ class Team(ba.Team[Player]): class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): """Minigame involving dodging falling bombs.""" - @classmethod - def get_name(cls) -> str: - return 'Meteor Shower' + name = 'Meteor Shower' + description = 'Dodge the falling bombs.' + game_settings = [('Epic Mode', {'default': False})] + score_info = ba.ScoreInfo(label='Survived', + scoretype=ba.ScoreType.MILLISECONDS, + version='B') - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Survived', - scoretype=ba.ScoreType.MILLISECONDS, - version='B') - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Dodge the falling bombs.' + # Print messages when players die (since its meaningful in this game). + announce_player_deaths = True # we're currently hard-coded for one map.. @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ['Rampage'] - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [('Epic Mode', {'default': False})] - # We support teams, free-for-all, and co-op sessions. @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -85,9 +75,6 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): or issubclass(sessiontype, ba.FreeForAllSession) or issubclass(sessiontype, ba.CoopSession)) - # Print messages when players die (since its meaningful in this game). - announce_player_deaths = True - def __init__(self, settings: Dict[str, Any]): super().__init__(settings) @@ -256,9 +243,6 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): for team in self.teams: for player in team.players: - if not player: - print(f'GOT DEAD PLAYER {id(player)}') - survived = False # Throw an extra fudge factor in so teams that diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 04c44ef2..85a71656 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -44,19 +44,11 @@ class NinjaFightGame(ba.TeamGameActivity[ba.Player, ba.Team]): of Ninjas as fast as possible """ - @classmethod - def get_name(cls) -> str: - return 'Ninja Fight' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Time', - scoretype=ba.ScoreType.MILLISECONDS, - lower_is_better=True) - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'How fast can you defeat the ninjas?' + name = 'Ninja Fight' + description = 'How fast can you defeat the ninjas?' + score_info = ba.ScoreInfo(label='Time', + scoretype=ba.ScoreType.MILLISECONDS, + lower_is_better=True) @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index c9df8d80..225b4773 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -52,6 +52,9 @@ class Team(ba.Team[Player]): class OnslaughtGame(ba.CoopGameActivity[Player, Team]): """Co-op game where players try to survive attacking waves of enemies.""" + name = 'Onslaught' + description = 'Defeat all enemies.' + tips: List[Union[str, Dict[str, Any]]] = [ 'Hold any button to run.' ' (Trigger buttons work well if you have them)', @@ -63,13 +66,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): 'Your punches do much more damage if you are running or spinning.' ] - @classmethod - def get_name(cls) -> str: - return 'Onslaught' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Defeat all enemies.' + # Show messages when players die since it matters here. + announce_player_deaths = True def __init__(self, settings: Dict[str, Any]): @@ -88,9 +86,6 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): super().__init__(settings) - # Show messages when players die since it matters here. - self.announce_player_deaths = True - self._new_wave_sound = ba.getsound('scoreHit01') self._winsound = ba.getsound('score') self._cashregistersound = ba.getsound('cashRegister') diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 60b80066..d55054b9 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -81,30 +81,14 @@ class Team(ba.Team[Player]): class RaceGame(ba.TeamGameActivity[Player, Team]): """Game of racing around a track.""" - @classmethod - def get_name(cls) -> str: - return 'Race' + name = 'Race' + description = 'Run real fast!' + score_info = ba.ScoreInfo(label='Time', + lower_is_better=True, + scoretype=ba.ScoreType.MILLISECONDS) @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Run real fast!' - - @classmethod - def get_score_info(cls) -> ba.ScoreInfo: - return ba.ScoreInfo(label='Time', - lower_is_better=True, - scoretype=ba.ScoreType.MILLISECONDS) - - @classmethod - def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - return issubclass(sessiontype, ba.MultiTeamSession) - - @classmethod - def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: - return ba.getmaps('race') - - @classmethod - def get_settings( + def get_game_settings( cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: settings: List[Tuple[str, Dict[str, Any]]] = [ @@ -114,9 +98,9 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): 'increment': 1 }), ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), - ('2 Minutes', 120), ('5 Minutes', 300), - ('10 Minutes', 600), ('20 Minutes', 1200)], + 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), + ('5 Minutes', 300), ('10 Minutes', 600), + ('20 Minutes', 1200)], 'default': 0 }), ('Mine Spawning', { @@ -128,16 +112,26 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): 'choices': [('None', 0), ('8 Seconds', 8000), ('4 Seconds', 4000), ('2 Seconds', 2000), ('1 Second', 1000)], - 'default': 2000 + 'default': 2000 }), ('Epic Mode', { 'default': False - })] # yapf: disable + }), + ] + # We have some specific settings in teams mode. if issubclass(sessiontype, ba.DualTeamSession): settings.append(('Entire Team Must Finish', {'default': False})) return settings + @classmethod + def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: + return issubclass(sessiontype, ba.MultiTeamSession) + + @classmethod + def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: + return ba.getmaps('race') + def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard self._race_started = False @@ -175,7 +169,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): return 'Run ${ARG1} laps.' + t_str, self.settings_raw['Laps'] return 'Run 1 lap.' + t_str - def get_instance_scoreboard_description(self) -> Union[str, Sequence]: + def get_instance_description_short(self) -> Union[str, Sequence]: if self.settings_raw['Laps'] > 1: return 'run ${ARG1} laps', self.settings_raw['Laps'] return 'run 1 lap' diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 302494a2..8e7d360f 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -41,6 +41,8 @@ if TYPE_CHECKING: class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): """Game involving trying to bomb bots as they walk through the map.""" + name = 'Runaround' + description = 'Prevent enemies from reaching the exit.' tips = [ 'Jump just as you\'re throwing to get bombs up to the highest levels.', 'No, you can\'t get up on the ledge. You have to throw bombs.', @@ -64,14 +66,6 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): spazbot.StickyBot: 0.5 } - @classmethod - def get_name(cls) -> str: - return 'Runaround' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Prevent enemies from reaching the exit.' - def __init__(self, settings: Dict[str, Any]): settings['map'] = 'Tower D' super().__init__(settings) diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 3c18deb4..9ff37d9b 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -26,41 +26,49 @@ from __future__ import annotations import random -from dataclasses import dataclass from typing import TYPE_CHECKING import ba from bastd.actor import playerspaz if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Optional, Tuple, Sequence + from typing import Any, Type, List, Dict, Optional, Sequence from bastd.actor.onscreencountdown import OnScreenCountdown from bastd.actor.bomb import Bomb, Blast -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" - streak: int = 0 + + def __init__(self) -> None: + self.streak = 0 -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" - score: int = 0 + + def __init__(self) -> None: + self.score = 0 # ba_meta export game class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): """Game where players try to hit targets with bombs.""" - @classmethod - def get_name(cls) -> str: - return 'Target Practice' - - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Bomb as many targets as you can.' + name = 'Target Practice' + description = 'Bomb as many targets as you can.' + game_settings = [ + ('Target Count', { + 'min_value': 1, + 'default': 3 + }), + ('Enable Impact Bombs', { + 'default': True + }), + ('Enable Triple Bombs', { + 'default': True + }), + ] @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: @@ -72,23 +80,6 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): return (issubclass(sessiontype, ba.CoopSession) or issubclass(sessiontype, ba.MultiTeamSession)) - @classmethod - def get_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - return [ - ('Target Count', { - 'min_value': 1, - 'default': 3 - }), - ('Enable Impact Bombs', { - 'default': True - }), - ('Enable Triple Bombs', { - 'default': True - }), - ] - def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index cff0e3c4..dafea99b 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -49,29 +49,22 @@ class Team(ba.Team[Player]): class TheLastStandGame(ba.CoopGameActivity[Player, Team]): """Slow motion how-long-can-you-last game.""" + name = 'The Last Stand' + description = 'Final glorious epic slow motion battle to the death.' tips = [ 'This level never ends, but a high score here\n' 'will earn you eternal respect throughout the world.' ] - @classmethod - def get_name(cls) -> str: - return 'The Last Stand' + # Show messages when players die since it matters here. + announce_player_deaths = True - @classmethod - def get_description(cls, sessiontype: Type[ba.Session]) -> str: - return 'Final glorious epic slow motion battle to the death.' + # And of course the most important part. + slow_motion = True def __init__(self, settings: Dict[str, Any]): settings['map'] = 'Rampage' super().__init__(settings) - - # Show messages when players die since it matters here. - self.announce_player_deaths = True - - # And of course the most important part. - self.slow_motion = True - self._new_wave_sound = ba.getsound('scoreHit01') self._winsound = ba.getsound('score') self._cashregistersound = ba.getsound('cashRegister') diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index 60fc3aa0..3912bfe3 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -72,7 +72,7 @@ class PlaylistEditGameWindow(ba.Window): ba.screenmessage(ba.Lstr(resource='noValidMapsErrorText')) raise Exception('No valid maps') - self._settings_defs = gameclass.get_settings(sessiontype) + self._settings_defs = gameclass.get_game_settings(sessiontype) self._completion_call = completion_call # To start with, pick a random map out of the ones we own. diff --git a/docs/ba_module.md b/docs/ba_module.md index d041935b..17580518 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-19 for Ballistica version 1.5.0 build 20021

    +

    last updated on 2020-05-19 for Ballistica version 1.5.0 build 20023

    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!


    @@ -1519,7 +1519,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -2043,7 +2043,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), set_immediate_end(), transition_in(), transition_out()

    Methods Defined or Overridden:

    -
    <constructor>, continue_or_end_game(), create_config_ui(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    +
    <constructor>, continue_or_end_game(), create_config_ui(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    ba.GameActivity(settings: Dict[str, Any])

    @@ -2073,9 +2073,9 @@ and calls either end_game or continue_game depending on the result

    success or None on cancel.

    Generally subclasses don't need to override this; if they override -ba.GameActivity.get_settings() and ba.GameActivity.get_supported_maps() -they can just rely on the default implementation here which calls those -methods.

    +ba.GameActivity.get_game_settings() and +ba.GameActivity.get_supported_maps() they can just rely on +the default implementation here which calls those methods.

    end()

    @@ -2114,9 +2114,11 @@ is up next in a series.

    <class method>

    get_description(sessiontype: Type[ba.Session]) -> str

    -

    Subclasses should override this to return a description for this -activity type (in English) within the context of the given -ba.Session type.

    +

    Get a str description of this game type.

    + +

    The default implementation simply returns the 'description' class var. +Classes which want to change their description depending on the session +can override this method.

    get_description_display_string()

    @@ -2137,92 +2139,9 @@ activity type (in English) within the context of the given

    Subclasses should override get_name(); not this.

    -

    get_instance_description()

    -

    get_instance_description(self) -> Union[str, Sequence]

    - -

    Return a description for this game instance, in English.

    - -

    This is shown in the center of the screen below the game name at the -start of a game. It should start with a capital letter and end with a -period, and can be a bit more verbose than the version returned by -get_instance_scoreboard_description().

    - -

    Note that translation is applied by looking up the specific returned -value as a key, so the number of returned variations should be limited; -ideally just one or two. To include arbitrary values in the -description, you can return a sequence of values in the following -form instead of just a string:

    - -
    # this will give us something like 'Score 3 goals.' in English
    -# and can properly translate to 'Anota 3 goles.' in Spanish.
    -# If we just returned the string 'Score 3 Goals' here, there would
    -# have to be a translation entry for each specific number. ew.
    -return ['Score ${ARG1} goals.', self.settings_raw['Score to Win']]
    - -

    This way the first string can be consistently translated, with any arg -values then substituted into the result. ${ARG1} will be replaced with -the first value, ${ARG2} with the second, etc.

    - -
    -

    get_instance_display_string()

    -

    get_instance_display_string(self) -> ba.Lstr

    - -

    Return a name for this particular game instance.

    - -
    -

    get_instance_scoreboard_description()

    -

    get_instance_scoreboard_description(self) -> Union[str, Sequence]

    - -

    Return a short description for this game instance in English.

    - -

    This description is used above the game scoreboard in the -corner of the screen, so it should be as concise as possible. -It should be lowercase and should not contain periods or other -punctuation.

    - -

    Note that translation is applied by looking up the specific returned -value as a key, so the number of returned variations should be limited; -ideally just one or two. To include arbitrary values in the -description, you can return a sequence of values in the following form -instead of just a string:

    - -
    # this will give us something like 'score 3 goals' in English
    -# and can properly translate to 'anota 3 goles' in Spanish.
    -# If we just returned the string 'score 3 goals' here, there would
    -# have to be a translation entry for each specific number. ew.
    -return ['score ${ARG1} goals', self.settings_raw['Score to Win']]
    - -

    This way the first string can be consistently translated, with any arg -values then substituted into the result. ${ARG1} will be replaced -with the first value, ${ARG2} with the second, etc.

    - -
    -

    get_instance_scoreboard_display_string()

    -

    get_instance_scoreboard_display_string(self) -> ba.Lstr

    - -

    Return a name for this particular game instance.

    - -

    This name is used above the game scoreboard in the corner -of the screen, so it should be as concise as possible.

    - -
    -

    get_name()

    +

    get_game_settings()

    <class method>
    -

    get_name() -> str

    - -

    Return a str name for this game type.

    - -
    -

    get_score_info()

    -
    <class method>
    -

    get_score_info() -> ba.ScoreInfo

    - -

    Return info about game scoring setup; can be overridden by games.

    - -
    -

    get_settings()

    -
    <class method>
    -

    get_settings(sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]

    +

    get_game_settings(sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]

    Called by the default ba.GameActivity.create_config_ui() implementation; should return a dict of config options to be presented @@ -2244,9 +2163,9 @@ of a name and a dict of options.

    'increment': Value increment for int/float settings.

    -
    # example get_settings() implementation for a capture-the-flag game:
    +
    # example get_game_settings() for a capture-the-flag game:
     @classmethod
    -def get_settings(cls,sessiontype):
    +def get_game_settings(cls, sessiontype):
         return [("Score to Win", {
                     'default': 3,
                     'min_value': 1
    @@ -2280,6 +2199,91 @@ def get_settings(cls,sessiontype):
                     'default': False
                 })]
    +
    +

    get_instance_description()

    +

    get_instance_description(self) -> Union[str, Sequence]

    + +

    Return a description for this game instance, in English.

    + +

    This is shown in the center of the screen below the game name at the +start of a game. It should start with a capital letter and end with a +period, and can be a bit more verbose than the version returned by +get_instance_description_short().

    + +

    Note that translation is applied by looking up the specific returned +value as a key, so the number of returned variations should be limited; +ideally just one or two. To include arbitrary values in the +description, you can return a sequence of values in the following +form instead of just a string:

    + +
    # This will give us something like 'Score 3 goals.' in English
    +# and can properly translate to 'Anota 3 goles.' in Spanish.
    +# If we just returned the string 'Score 3 Goals' here, there would
    +# have to be a translation entry for each specific number. ew.
    +return ['Score ${ARG1} goals.', self.settings_raw['Score to Win']]
    + +

    This way the first string can be consistently translated, with any arg +values then substituted into the result. ${ARG1} will be replaced with +the first value, ${ARG2} with the second, etc.

    + +
    +

    get_instance_description_short()

    +

    get_instance_description_short(self) -> Union[str, Sequence]

    + +

    Return a short description for this game instance in English.

    + +

    This description is used above the game scoreboard in the +corner of the screen, so it should be as concise as possible. +It should be lowercase and should not contain periods or other +punctuation.

    + +

    Note that translation is applied by looking up the specific returned +value as a key, so the number of returned variations should be limited; +ideally just one or two. To include arbitrary values in the +description, you can return a sequence of values in the following form +instead of just a string:

    + +
    # This will give us something like 'score 3 goals' in English
    +# and can properly translate to 'anota 3 goles' in Spanish.
    +# If we just returned the string 'score 3 goals' here, there would
    +# have to be a translation entry for each specific number. ew.
    +return ['score ${ARG1} goals', self.settings_raw['Score to Win']]
    + +

    This way the first string can be consistently translated, with any arg +values then substituted into the result. ${ARG1} will be replaced +with the first value, ${ARG2} with the second, etc.

    + +
    +

    get_instance_display_string()

    +

    get_instance_display_string(self) -> ba.Lstr

    + +

    Return a name for this particular game instance.

    + +
    +

    get_instance_scoreboard_display_string()

    +

    get_instance_scoreboard_display_string(self) -> ba.Lstr

    + +

    Return a name for this particular game instance.

    + +

    This name is used above the game scoreboard in the corner +of the screen, so it should be as concise as possible.

    + +
    +

    get_name()

    +
    <class method>
    +

    get_name() -> str

    + +

    Return a str name for this game type.

    + +

    This default implementation simply returns the 'name' class attr.

    + +
    +

    get_score_info()

    +
    <class method>
    +

    get_score_info() -> ba.ScoreInfo

    + +

    Return info about game scoring setup; can be overridden by games.

    +

    get_supported_maps()

    <class method>
    @@ -4810,7 +4814,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_display_string(), get_instance_scoreboard_description(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    From 1ef716a2f2d619a82649f0cef740da9c22b0413d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 19 May 2020 18:08:03 -0700 Subject: [PATCH 020/417] Tidying --- assets/src/ba_data/python/ba/_gameactivity.py | 12 +++--- .../ba_data/python/ba/_multiteamsession.py | 2 +- .../python/bastd/game/capturetheflag.py | 41 +++++++++++-------- .../ba_data/python/bastd/game/chosenone.py | 11 ++--- .../ba_data/python/bastd/game/elimination.py | 15 +++---- .../src/ba_data/python/bastd/game/football.py | 3 -- .../ba_data/python/bastd/game/ninjafight.py | 12 +++++- .../ba_data/python/bastd/game/onslaught.py | 3 -- assets/src/ba_data/python/bastd/game/race.py | 6 +-- .../python/bastd/game/targetpractice.py | 4 +- .../ba_data/python/bastd/game/thelaststand.py | 3 -- .../ba_data/python/bastd/ui/playlist/edit.py | 15 ++++--- .../bastd/ui/playlist/editcontroller.py | 12 +++--- .../ba_data/python/bastd/ui/playoptions.py | 2 +- docs/ba_module.md | 34 +++++++-------- 15 files changed, 92 insertions(+), 83 deletions(-) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index d8f62401..8432620e 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -64,10 +64,10 @@ class GameActivity(Activity[PlayerType, TeamType]): score_info: Optional[ba.ScoreInfo] = None @classmethod - def create_config_ui( + def create_settings_ui( cls, sessionclass: Type[ba.Session], - config: Optional[Dict[str, Any]], + settings: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None], ) -> None: """Launch an in-game UI to configure settings for a game type. @@ -87,7 +87,7 @@ class GameActivity(Activity[PlayerType, TeamType]): """ delegate = _ba.app.delegate assert delegate is not None - delegate.create_default_game_config_ui(cls, sessionclass, config, + delegate.create_default_game_config_ui(cls, sessionclass, settings, completion_call) @classmethod @@ -155,7 +155,7 @@ class GameActivity(Activity[PlayerType, TeamType]): cls, sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: """ - Called by the default ba.GameActivity.create_config_ui() + Called by the default ba.GameActivity.create_settings_ui() implementation; should return a dict of config options to be presented to the user for the given ba.Session type. @@ -217,7 +217,7 @@ class GameActivity(Activity[PlayerType, TeamType]): @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: """ - Called by the default ba.GameActivity.create_config_ui() + Called by the default ba.GameActivity.create_settings_ui() implementation; should return a list of map names valid for this game-type for the given ba.Session type. """ @@ -226,7 +226,7 @@ class GameActivity(Activity[PlayerType, TeamType]): return _map.getmaps('melee') @classmethod - def get_config_display_string(cls, config: Dict[str, Any]) -> ba.Lstr: + def get_settings_display_string(cls, config: Dict[str, Any]) -> ba.Lstr: """Given a game config dict, return a short description for it. This is used when viewing game-lists or showing what game diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 84097208..ad427931 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -150,7 +150,7 @@ class MultiTeamSession(Session): from ba._gameactivity import GameActivity gametype: Type[GameActivity] = self._next_game_spec['resolved_type'] assert issubclass(gametype, GameActivity) - return gametype.get_config_display_string(self._next_game_spec) + return gametype.get_settings_display_string(self._next_game_spec) def get_game_number(self) -> int: """Returns which game in the series is currently being played.""" diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 99f617b4..6b1e028c 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -25,7 +25,6 @@ from __future__ import annotations -from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -81,29 +80,35 @@ class CTFFlag(stdflag.Flag): return delegate if isinstance(delegate, CTFFlag) else None -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" - touching_own_flag: int = 0 + + def __init__(self) -> None: + self.touching_own_flag = 0 -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" - base_pos: Sequence[float] - base_region_material: ba.Material - base_region: ba.Node - spaz_material_no_flag_physical: ba.Material - spaz_material_no_flag_collide: ba.Material - flagmaterial: ba.Material - score: int = 0 - flag_return_touches: int = 0 - home_flag_at_base: bool = True - touch_return_timer: Optional[ba.Timer] = None - enemy_flag_at_base: bool = False - flag: Optional[CTFFlag] = None - last_flag_leave_time: Optional[float] = None - touch_return_timer_ticking: Optional[ba.NodeActor] = None + + def __init__(self, base_pos: Sequence[float], + base_region_material: ba.Material, base_region: ba.Node, + spaz_material_no_flag_physical: ba.Material, + spaz_material_no_flag_collide: ba.Material, + flagmaterial: ba.Material): + self.base_pos = base_pos + self.base_region_material = base_region_material + self.base_region = base_region + self.spaz_material_no_flag_physical = spaz_material_no_flag_physical + self.spaz_material_no_flag_collide = spaz_material_no_flag_collide + self.flagmaterial = flagmaterial + self.score = 0 + self.flag_return_touches = 0 + self.home_flag_at_base = True + self.touch_return_timer: Optional[ba.Timer] = None + self.enemy_flag_at_base = False + self.flag: Optional[CTFFlag] = None + self.last_flag_leave_time: Optional[float] = None + self.touch_return_timer_ticking: Optional[ba.NodeActor] = None # ba_meta export game diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index db166dc0..e750c390 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -25,7 +25,6 @@ from __future__ import annotations from typing import TYPE_CHECKING -from dataclasses import dataclass import ba from bastd.actor.flag import Flag @@ -35,16 +34,18 @@ if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence, Union -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" - chosen_light: Optional[ba.NodeActor] = None + + def __init__(self) -> None: + self.chosen_light: Optional[ba.NodeActor] = None -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" - time_remaining: int + + def __init__(self, time_remaining: int) -> None: + self.time_remaining = time_remaining # ba_meta export game diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index ffe07ce3..d94c7988 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -25,7 +25,6 @@ from __future__ import annotations -from dataclasses import dataclass, field from typing import TYPE_CHECKING import ba @@ -164,18 +163,20 @@ class Icon(ba.Actor): ba.timer(0.6, self.update_for_lives) -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" - lives: int = 0 - icons: List[Icon] = field(default_factory=list) + + def __init__(self) -> None: + self.lives = 0 + self.icons: List[Icon] = [] -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" - survival_seconds: Optional[int] = None - spawn_order: List[Player] = field(default_factory=list) + + def __init__(self) -> None: + self.survival_seconds: Optional[int] = None + self.spawn_order: List[Player] = [] # ba_meta export game diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index d8cdbccc..2e281b84 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -26,7 +26,6 @@ from __future__ import annotations import random -from dataclasses import dataclass from typing import TYPE_CHECKING import math @@ -66,12 +65,10 @@ class FootballFlag(stdflag.Flag): self.node.connectattr('position', self.light, 'position') -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 85a71656..93c9e26a 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -37,8 +37,16 @@ if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class NinjaFightGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class NinjaFightGame(ba.TeamGameActivity[Player, Team]): """ A co-op game where you try to defeat a group of Ninjas as fast as possible @@ -116,7 +124,7 @@ class NinjaFightGame(ba.TeamGameActivity[ba.Player, ba.Team]): spazbot.ChargerBot, pos=(0, 3, 1), spawn_time=3.0)) # Called for each spawning player. - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: # Let's spawn close to the center. spawn_center = (0, 3, -2) diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 225b4773..11856451 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -27,7 +27,6 @@ from __future__ import annotations import math import random -from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -39,12 +38,10 @@ if TYPE_CHECKING: from bastd.actor.scoreboard import Scoreboard -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index d55054b9..86950240 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -66,13 +66,13 @@ class RaceRegion(ba.Actor): }) -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" - distance_txt: Optional[ba.Node] = None + + def __init__(self) -> None: + self.distance_txt: Optional[ba.Node] = None -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 9ff37d9b..d34ee538 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -29,7 +29,7 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz +from bastd.actor.playerspaz import PlayerSpazDeathMessage if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence @@ -193,7 +193,7 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: # When players die, respawn them. - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, PlayerSpazDeathMessage): super().handlemessage(msg) # Do standard stuff. player = msg.playerspaz(self).getplayer() assert player is not None diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index dafea99b..3eb3eaad 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -23,7 +23,6 @@ from __future__ import annotations import random -from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -36,12 +35,10 @@ if TYPE_CHECKING: from bastd.actor.scoreboard import Scoreboard -@dataclass(eq=False) class Player(ba.Player['Team']): """Our player type for this game.""" -@dataclass(eq=False) class Team(ba.Team[Player]): """Our team type for this game.""" diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index 1d5b123d..7675928d 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -24,8 +24,8 @@ from __future__ import annotations from typing import TYPE_CHECKING, cast -import _ba import ba +import _ba if TYPE_CHECKING: from typing import Optional, List @@ -253,13 +253,13 @@ class PlaylistEditWindow(ba.Window): get_root_widget()) def _add(self) -> None: - # store list name then tell the session to perform an add + # Store list name then tell the session to perform an add. self._editcontroller.set_name( cast(str, ba.textwidget(query=self._text_field))) self._editcontroller.add_game_pressed() def _edit(self) -> None: - # store list name then tell the session to perform an add + # Store list name then tell the session to perform an add. self._editcontroller.set_name( cast(str, ba.textwidget(query=self._text_field))) self._editcontroller.edit_game_pressed() @@ -283,6 +283,7 @@ class PlaylistEditWindow(ba.Window): ba.Lstr(resource=self._r + '.cantSaveEmptyListText')) ba.playsound(ba.getsound('error')) return + # We couldn't actually replace the default list anyway, but disallow # using its exact name to avoid confusion. if new_name == self._editcontroller.get_default_list_name().evaluate(): @@ -291,7 +292,7 @@ class PlaylistEditWindow(ba.Window): ba.playsound(ba.getsound('error')) return - # if we had an old one, delete it + # If we had an old one, delete it. if self._editcontroller.get_existing_playlist_name() is not None: _ba.add_transaction({ 'type': @@ -326,6 +327,7 @@ class PlaylistEditWindow(ba.Window): def _refresh(self) -> None: from ba.internal import getclass + # Need to grab this here as rebuilding the list will # change it otherwise. old_selection_index = self._editcontroller.get_selected_index() @@ -336,7 +338,7 @@ class PlaylistEditWindow(ba.Window): try: cls = getclass(pentry['type'], subclassof=ba.GameActivity) - desc = cls.get_config_display_string(pentry) + desc = cls.get_settings_display_string(pentry) except Exception: ba.print_exception() desc = "(invalid: '" + pentry['type'] + "')" @@ -353,7 +355,8 @@ class PlaylistEditWindow(ba.Window): v_align='center', selectable=True) ba.widget(edit=txtw, show_buffer_top=50, show_buffer_bottom=50) - # wanna be able to jump up to the text field from the top one + + # Wanna be able to jump up to the text field from the top one. if index == 0: ba.widget(edit=txtw, up_widget=self._text_field) self._list_widgets.append(txtw) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py index ff03485c..52fc2aef 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py @@ -162,7 +162,7 @@ class PlaylistEditController: self._show_edit_ui(gametype=getclass( self._playlist[self._selected_index]['type'], subclassof=ba.GameActivity), - config=self._playlist[self._selected_index]) + settings=self._playlist[self._selected_index]) def add_game_cancelled(self) -> None: """(internal)""" @@ -173,16 +173,16 @@ class PlaylistEditController: editcontroller=self, transition='in_left').get_root_widget()) def _show_edit_ui(self, gametype: Type[ba.GameActivity], - config: Optional[Dict[str, Any]]) -> None: - self._editing_game = (config is not None) + settings: Optional[Dict[str, Any]]) -> None: + self._editing_game = (settings is not None) self._editing_game_type = gametype assert self._sessiontype is not None - gametype.create_config_ui(self._sessiontype, copy.deepcopy(config), - self._edit_game_done) + gametype.create_settings_ui(self._sessiontype, copy.deepcopy(settings), + self._edit_game_done) def add_game_type_selected(self, gametype: Type[ba.GameActivity]) -> None: """(internal)""" - self._show_edit_ui(gametype=gametype, config=None) + self._show_edit_ui(gametype=gametype, settings=None) def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: from bastd.ui.playlist import edit as pedit diff --git a/assets/src/ba_data/python/bastd/ui/playoptions.py b/assets/src/ba_data/python/bastd/ui/playoptions.py index f312e3fd..a62b56e9 100644 --- a/assets/src/ba_data/python/bastd/ui/playoptions.py +++ b/assets/src/ba_data/python/bastd/ui/playoptions.py @@ -204,7 +204,7 @@ class PlayOptionsWindow(popup.PopupWindow): try: desc = getclass(entry['type'], subclassof=ba.GameActivity - ).get_config_display_string(entry) + ).get_settings_display_string(entry) if not owned: desc = ba.Lstr( value='${DESC}\n${UNLOCK}', diff --git a/docs/ba_module.md b/docs/ba_module.md index 17580518..41b164e5 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1519,7 +1519,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -2043,7 +2043,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), set_immediate_end(), transition_in(), transition_out()

    Methods Defined or Overridden:

    -
    <constructor>, continue_or_end_game(), create_config_ui(), end(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    +
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    ba.GameActivity(settings: Dict[str, Any])

    @@ -2058,9 +2058,9 @@ its time with lingering corpses, sound effects, etc.

    and calls either end_game or continue_game depending on the result

    -

    create_config_ui()

    +

    create_settings_ui()

    <class method>
    -

    create_config_ui(sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None

    +

    create_settings_ui(sessionclass: Type[ba.Session], settings: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None

    Launch an in-game UI to configure settings for a game type.

    @@ -2099,16 +2099,6 @@ immediately. This method should be overridden by subclasses.

    there is no 'winner' yet; this way things like the standard time-limit (ba.GameActivity.setup_standard_time_limit()) will work with the game.

    -
    -

    get_config_display_string()

    -
    <class method>
    -

    get_config_display_string(config: Dict[str, Any]) -> ba.Lstr

    - -

    Given a game config dict, return a short description for it.

    - -

    This is used when viewing game-lists or showing what game -is up next in a series.

    -

    get_description()

    <class method>
    @@ -2143,7 +2133,7 @@ can override this method.

    <class method>

    get_game_settings(sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]

    -

    Called by the default ba.GameActivity.create_config_ui() +

    Called by the default ba.GameActivity.create_settings_ui() implementation; should return a dict of config options to be presented to the user for the given ba.Session type.

    @@ -2284,12 +2274,22 @@ of the screen, so it should be as concise as possible.

    Return info about game scoring setup; can be overridden by games.

    +
    +

    get_settings_display_string()

    +
    <class method>
    +

    get_settings_display_string(config: Dict[str, Any]) -> ba.Lstr

    + +

    Given a game config dict, return a short description for it.

    + +

    This is used when viewing game-lists or showing what game +is up next in a series.

    +

    get_supported_maps()

    <class method>

    get_supported_maps(sessiontype: Type[ba.Session]) -> List[str]

    -

    Called by the default ba.GameActivity.create_config_ui() +

    Called by the default ba.GameActivity.create_settings_ui() implementation; should return a list of map names valid for this game-type for the given ba.Session type.

    @@ -4814,7 +4814,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_config_ui(), create_player(), create_team(), dep_is_present(), destroy(), end_game(), get_config_display_string(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    From acb38415eb8eaeb0b51e1329712e9bce95dfcecb Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 20 May 2020 00:06:36 -0700 Subject: [PATCH 021/417] Cleaned up Session args --- assets/src/ba_data/python/ba/_coopsession.py | 21 ++++------ .../src/ba_data/python/ba/_dualteamsession.py | 7 ++-- .../ba_data/python/ba/_freeforallsession.py | 3 +- assets/src/ba_data/python/ba/_lobby.py | 14 +++---- .../ba_data/python/ba/_multiteamsession.py | 7 ++-- assets/src/ba_data/python/ba/_session.py | 41 +++++++------------ .../ba_data/python/bastd/game/deathmatch.py | 30 +++++++++----- .../ba_data/python/bastd/game/meteorshower.py | 1 - docs/ba_module.md | 4 +- 9 files changed, 57 insertions(+), 71 deletions(-) diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 569aecc9..764f755a 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -30,8 +30,8 @@ if TYPE_CHECKING: from typing import Any, List, Dict, Optional, Callable, Sequence import ba -TEAM_COLORS = ((0.2, 0.4, 1.6), ) -TEAM_NAMES = ('Good Guys', ) +TEAM_COLORS = [(0.2, 0.4, 1.6)] +TEAM_NAMES = ['Good Guys'] class CoopSession(Session): @@ -43,6 +43,9 @@ class CoopSession(Session): the computer and include functionality such as high score lists. """ + use_teams = True + use_team_colors = False + allow_mid_activity_joins = False def __init__(self) -> None: """Instantiate a co-op mode session.""" @@ -51,7 +54,6 @@ class CoopSession(Session): from bastd.activity.coopjoin import CoopJoinActivity _ba.increment_analytics_count('Co-op session start') - app = _ba.app # If they passed in explicit min/max, honor that. @@ -63,14 +65,7 @@ class CoopSession(Session): if 'max_players' in app.coop_session_args: max_players = app.coop_session_args['max_players'] else: - try: - max_players = app.config['Coop Game Max Players'] - except Exception: - # Old pref value. - try: - max_players = app.config['Challenge Game Max Players'] - except Exception: - max_players = 4 + max_players = app.config.get('Coop Game Max Players', 4) # print('FIXME: COOP SESSION WOULD CALC DEPS.') depsets: Sequence[ba.DependencySet] = [] @@ -78,10 +73,8 @@ class CoopSession(Session): super().__init__(depsets, team_names=TEAM_NAMES, team_colors=TEAM_COLORS, - use_team_colors=False, min_players=min_players, - max_players=max_players, - allow_mid_activity_joins=False) + max_players=max_players) # Tournament-ID if we correspond to a co-op tournament (otherwise None) self.tournament_id = (app.coop_session_args['tournament_id'] diff --git a/assets/src/ba_data/python/ba/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py index a011e678..dee8e74f 100644 --- a/assets/src/ba_data/python/ba/_dualteamsession.py +++ b/assets/src/ba_data/python/ba/_dualteamsession.py @@ -24,18 +24,19 @@ from __future__ import annotations from typing import TYPE_CHECKING import _ba -from ba import _multiteamsession +from ba._multiteamsession import MultiTeamSession if TYPE_CHECKING: import ba -class DualTeamSession(_multiteamsession.MultiTeamSession): +class DualTeamSession(MultiTeamSession): """ba.Session type for teams mode games. Category: Gameplay Classes """ - _use_teams = True + use_teams = True + use_team_colors = True _playlist_selection_var = 'Team Tournament Playlist Selection' _playlist_randomize_var = 'Team Tournament Playlist Randomize' _playlists_var = 'Team Tournament Playlists' diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index 89c5c5c1..bad02faa 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -37,7 +37,8 @@ class FreeForAllSession(MultiTeamSession): Category: Gameplay Classes """ - _use_teams = False + use_teams = False + use_team_colors = True _playlist_selection_var = 'Free-for-All Playlist Selection' _playlist_randomize_var = 'Free-for-All Playlist Randomize' _playlists_var = 'Free-for-All Playlists' diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 198338e7..b8c08820 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -889,18 +889,16 @@ class Lobby: player.reset() def __init__(self) -> None: - from ba import _team as bs_team - from ba import _coopsession + from ba._team import SessionTeam + from ba._coopsession import CoopSession session = _ba.getsession() - teams = session.teams if session.use_teams else None self._use_team_colors = session.use_team_colors - if teams is not None: - self._teams = [weakref.ref(team) for team in teams] + if session.use_teams: + self._teams = [weakref.ref(team) for team in session.teams] else: - self._dummy_teams = bs_team.SessionTeam() + self._dummy_teams = SessionTeam() self._teams = [weakref.ref(self._dummy_teams)] - v_offset = (-150 - if isinstance(session, _coopsession.CoopSession) else -50) + v_offset = (-150 if isinstance(session, CoopSession) else -50) self.choosers: List[Chooser] = [] self.base_v_offset = v_offset self.update_positions() diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index ad427931..d25165f1 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -59,7 +59,7 @@ class MultiTeamSession(Session): app = _ba.app cfg = app.config - if self._use_teams: + if self.use_teams: team_names = cfg.get('Custom Team Names', DEFAULT_TEAM_NAMES) team_colors = cfg.get('Custom Team Colors', DEFAULT_TEAM_COLORS) else: @@ -72,7 +72,6 @@ class MultiTeamSession(Session): super().__init__(depsets, team_names=team_names, team_colors=team_colors, - use_team_colors=self._use_teams, min_players=1, max_players=self.get_max_players()) @@ -107,7 +106,7 @@ class MultiTeamSession(Session): # got it and we don't want that to affect our config. playlist = copy.deepcopy(playlists[self._playlist_name]) else: - if self._use_teams: + if self.use_teams: playlist = _playlist.get_default_teams_playlist() else: playlist = _playlist.get_default_free_for_all_playlist() @@ -161,7 +160,7 @@ class MultiTeamSession(Session): def get_max_players(self) -> int: """Return max number of ba.Players allowed to join the game at once.""" - if self._use_teams: + if self.use_teams: return _ba.app.config.get('Team Game Max Players', 8) return _ba.app.config.get('Free-for-All Max Players', 8) diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index dbb47fd8..cbd8ec11 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -75,6 +75,9 @@ class Session: there is no associated Campaign. """ + use_teams = False + use_team_colors = True + allow_mid_activity_joins = True # Note: even though these are instance vars, we annotate them at the # class level so that docs generation can access their types. @@ -89,10 +92,8 @@ class Session: depsets: Sequence[ba.DependencySet], team_names: Sequence[str] = None, team_colors: Sequence[Sequence[float]] = None, - use_team_colors: bool = True, min_players: int = 1, - max_players: int = 8, - allow_mid_activity_joins: bool = True): + max_players: int = 8): """Instantiate a session. depsets should be a sequence of successfully resolved ba.DependencySet @@ -154,16 +155,12 @@ class Session: self.campaign = None self.campaign_state: Dict[str, str] = {} - self._use_teams = (team_names is not None) - self._use_team_colors = use_team_colors - self._in_set_activity = False - self._allow_mid_activity_joins = allow_mid_activity_joins - self.teams = [] self.players = [] + self._in_set_activity = False self._next_team_id = 0 self._activity_retained: Optional[ba.Activity] = None - self.launch_end_session_activity_time: Optional[float] = None + self._launch_end_session_activity_time: Optional[float] = None self._activity_end_timer: Optional[ba.Timer] = None self._activity_weak = empty_weakref(Activity) if self._activity_weak() is not None: @@ -175,8 +172,8 @@ class Session: self.min_players = min_players self.max_players = max_players - # Create Teams. - if self._use_teams: + # Create static teams if we're using them. + if self.use_teams: assert team_names is not None assert team_colors is not None for i, color in enumerate(team_colors): @@ -199,16 +196,6 @@ class Session: # Instantiate our session globals node which will apply its settings. sharedobj('globals') - @property - def use_teams(self) -> bool: - """(internal)""" - return self._use_teams - - @property - def use_team_colors(self) -> bool: - """(internal)""" - return self._use_team_colors - def on_player_request(self, player: ba.SessionPlayer) -> bool: """Called when a new ba.Player wants to join the Session. @@ -284,7 +271,7 @@ class Session: print('Player not found in Activity in on_player_leave.') # If we're a non-team session, remove their team too. - if not self._use_teams: + if not self.use_teams: # They should have been the only one on their team. assert not sessionteam.players @@ -335,14 +322,14 @@ class Session: curtime = _ba.time(TimeType.REAL) if self._ending: # Ignore repeats unless its been a while. - assert self.launch_end_session_activity_time is not None - since_last = (curtime - self.launch_end_session_activity_time) + assert self._launch_end_session_activity_time is not None + since_last = (curtime - self._launch_end_session_activity_time) if since_last < 30.0: return print_error( 'launch_end_session_activity called twice (since_last=' + str(since_last) + ')') - self.launch_end_session_activity_time = curtime + self._launch_end_session_activity_time = curtime self.set_activity(_ba.new_activity(EndSessionActivity)) self.wants_to_end = False self._ending = True # Prevent further actions. @@ -603,7 +590,7 @@ class Session: # If we're not allowing mid-game joins, don't pass; just announce # the arrival and say they'll partake next round. if pass_to_activity: - if not self._allow_mid_activity_joins: + if not self.allow_mid_activity_joins: pass_to_activity = False with _ba.Context(self): _ba.screenmessage( @@ -615,7 +602,7 @@ class Session: # If we're a non-team session, each player gets their own team. # (keeps mini-game coding simpler if we can always deal with teams). - if self._use_teams: + if self.use_teams: sessionteam = chooser.get_team() else: our_team_id = self._next_team_id diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index e2f37062..71199095 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -34,8 +34,19 @@ if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + pass + + # ba_meta export game -class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class DeathMatchGame(ba.TeamGameActivity[Player, Team]): """A game type based on acquiring kills.""" name = 'Death Match' @@ -92,12 +103,15 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): def __init__(self, settings: Dict[str, Any]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) - if self.settings_raw['Epic Mode']: - self.slow_motion = True - self._scoreboard = Scoreboard() self._score_to_win = None self._dingsound = ba.getsound('dingSmall') + self._epic_mode = bool(settings['Epic Mode']) + + # Base class overrides. + self.slow_motion = self._epic_mode + self.default_music = (ba.MusicType.EPIC if self._epic_mode else + ba.MusicType.TO_THE_DEATH) def get_instance_description(self) -> Union[str, Sequence]: return 'Crush ${ARG1} of your enemies.', self._score_to_win @@ -105,13 +119,7 @@ class DeathMatchGame(ba.TeamGameActivity[ba.Player, ba.Team]): def get_instance_description_short(self) -> Union[str, Sequence]: return 'kill ${ARG1} enemies', self._score_to_win - def on_transition_in(self) -> None: - self.default_music = (ba.MusicType.EPIC - if self.settings_raw['Epic Mode'] else - ba.MusicType.TO_THE_DEATH) - super().on_transition_in() - - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: team.gamedata['score'] = 0 if self.has_begun(): self._update_scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 3e1103dd..53d404ec 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -242,7 +242,6 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): # (these per-player scores are only meaningful in team-games) for team in self.teams: for player in team.players: - survived = False # Throw an extra fudge factor in so teams that diff --git a/docs/ba_module.md b/docs/ba_module.md index 41b164e5..ecfa922a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-19 for Ballistica version 1.5.0 build 20023

    +

    last updated on 2020-05-20 for Ballistica version 1.5.0 build 20023

    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!


    @@ -4145,7 +4145,7 @@ list in ba.Activity; not this.

    <constructor>, begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity()

    <constructor>

    -

    ba.Session(depsets: Sequence[ba.DependencySet], team_names: Sequence[str] = None, team_colors: Sequence[Sequence[float]] = None, use_team_colors: bool = True, min_players: int = 1, max_players: int = 8, allow_mid_activity_joins: bool = True)

    +

    ba.Session(depsets: Sequence[ba.DependencySet], team_names: Sequence[str] = None, team_colors: Sequence[Sequence[float]] = None, min_players: int = 1, max_players: int = 8)

    Instantiate a session.

    From e32aa01088c8633d6ec3f79e4425f30668ab2e4f Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 20 May 2020 01:09:39 -0700 Subject: [PATCH 022/417] Tidying --- .efrocachemap | 24 +++---- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/_lobby.py | 2 +- assets/src/ba_data/python/ba/_player.py | 11 +++- assets/src/ba_data/python/ba/_session.py | 22 +++++-- assets/src/ba_data/python/ba/_team.py | 15 +++-- .../ba_data/python/bastd/game/elimination.py | 6 +- docs/ba_module.md | 63 ++++++++++++++----- 8 files changed, 101 insertions(+), 44 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 0e2e2414..d6c71862 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/b6/bbdb904d5cea6023a50d4dc2c9e9", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/17/34/76b4411678f95106d2e3e368c79b", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/83/b9/a679a7aaeb67227f94286ea9fffb", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/95/a0/7a95002b5cc7d1bacbda49098fd9", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/b8/1b547866b77a98fcc5ca43c93a07", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ee/c4/0e92e825c67a249a77b16bb7a4fa", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/31/1e/2d282dff8a9331b121908061c6bc", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/eb/9bf8367a161f3e9fb29b4f61216e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4a/22/30984f1fd3a430755ea62c80ec76", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fe/f5/e99958f225c4b342c1bd4ecb0c23", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/fd/b26b46b083240ad3855ba93cb42d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a7/ee/ec0ee56e6f7254b460c4f1116a0c" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/fd/1edae1d48773436f72ceaf5c4588", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/07/88/2e60127c99cd8018f4b7a77c455b", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/ef/2c661b395a46f1abbd6c2042cb50", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/ad/d73757e8902b9c5c36c73469773b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/e3/9ad5acc492f343a24e790be07ed0", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/1f/5ae4c3d9b710b24ea2464c1f62ab", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/83/f9/de5c6a7a1dd65f305565bd5a0897", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/29/1f1d904b57ef0379654421737c6b", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/7b/308923feba6216c72c565cb9a942", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ce/44/4d2658f31d74fb342604e38bf12a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/53/d7/89dfbf816f8fe6824cf9f62f81f6", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1c/b8/d9def95f52348a50d01b4a9a3996" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index fe13f9ad..6b5325df 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=122350585846084418668853979161934598264 +# SOURCES_HASH=68384686054944380533078060197841658129 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index b8c08820..ac7971ee 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -987,7 +987,7 @@ class Lobby: self._vpos -= 48 def remove_chooser(self, player: ba.SessionPlayer) -> None: - """Remove a single player's chooser; does not kick him. + """Remove a single player's chooser; does not kick them. This is used when a player enters the game and no longer needs a chooser.""" diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index baf64908..6622e609 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -19,6 +19,7 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Player related functionality.""" + from __future__ import annotations from typing import TYPE_CHECKING, TypeVar, Generic @@ -32,7 +33,13 @@ TeamType = TypeVar('TeamType', bound='ba.Team') class Player(Generic[TeamType]): - """Testing.""" + """A player in a specific ba.Activity. + + Category: Gameplay Classes + + These correspond to ba.SessionPlayer objects, but are created per activity + so that the activity can use its own custom player subclass. + """ # Defining these types at the class level instead of in __init__ so # that types are introspectable (these are still instance attrs). @@ -112,7 +119,7 @@ class Player(Generic[TeamType]): @property def exists(self) -> bool: - """Whether the player still exists. + """Whether the underlying player still exists. Most functionality will fail on a nonexistent player. Note that you can also use the boolean operator for this same diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index cbd8ec11..e46d7a10 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -46,7 +46,7 @@ class Session: ba.Activity instances such as mini-games and score-screens, and for maintaining state between them (players, teams, score tallies, etc). - Attributes: + Attrs: teams All the ba.Teams in the Session. Most things should use the team @@ -74,10 +74,24 @@ class Session: The ba.Campaign instance this Session represents, or None if there is no associated Campaign. + use_teams + Whether this session groups players into an explicit set of + teams. If this is off, a unique team is generated for each + player that joins. + + use_team_colors + Whether players on a team should all adopt the colors of that + team instead of their own profile colors. This only applies if + use_teams is enabled. + + allow_mid_activity_joins + Whether players should be allowed to join in the middle of + activities. + """ - use_teams = False - use_team_colors = True - allow_mid_activity_joins = True + use_teams: bool = False + use_team_colors: bool = True + allow_mid_activity_joins: bool = True # Note: even though these are instance vars, we annotate them at the # class level so that docs generation can access their types. diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index 8a6beaae..2e92d4e9 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -18,7 +18,8 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ----------------------------------------------------------------------------- -"""Defines Team class.""" +"""Team related functionality.""" + from __future__ import annotations import weakref @@ -35,9 +36,9 @@ class SessionTeam: Category: Gameplay Classes - Note that a player *always* has a team; + Note that a SessionPlayer *always* has a SessionTeam; in some cases, such as free-for-all ba.Sessions, - each team consists of just one ba.Player. + each SessionTeam consists of just one SessionPlayer. Attributes: @@ -104,7 +105,13 @@ PlayerType = TypeVar('PlayerType', bound='ba.Player') class Team(Generic[PlayerType]): - """Testing.""" + """A team in a specific ba.Activity. + + Category: Gameplay Classes + + These correspond to ba.SessionTeam objects, but are created per activity + so that the activity can use its own custom team subclass. + """ # Defining these types at the class level instead of in __init__ so # that types are introspectable (these are still instance attrs). diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index d94c7988..97361733 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -263,9 +263,9 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): # No longer allowing mid-game joiners here; too easy to exploit. if self.has_begun(): - # Make sure our team has survival seconds set if they're all dead - # (otherwise blocked new ffa players would be considered 'still - # alive' in score tallying). + # Make sure their team has survival seconds set if they're all dead + # (otherwise blocked new ffa players are considered 'still alive' + # in score tallying). if (self._get_total_team_lives(player.team) == 0 and player.team.survival_seconds is None): player.team.survival_seconds = 0 diff --git a/docs/ba_module.md b/docs/ba_module.md index ecfa922a..8ec9e7f4 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-20 for Ballistica version 1.5.0 build 20023

    +

    last updated on 2020-05-20 for Ballistica version 1.5.0 build 20024

    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!


    @@ -25,6 +25,7 @@
  • ba.Lobby
  • ba.Material
  • ba.Node
  • +
  • ba.Player
  • ba.PlayerRecord
  • ba.ScoreInfo
  • ba.Session
  • @@ -39,6 +40,7 @@
  • ba.SessionPlayer
  • ba.SessionTeam
  • ba.Stats
  • +
  • ba.Team
  • ba.TeamGameResults
  • Gameplay Functions

    @@ -196,11 +198,6 @@
  • ba.WidgetNotFoundError
  • -

    Misc Classes

    -

    ba.Achievement

    <top level class> @@ -1593,7 +1590,7 @@ and it should begin its actual game logic.

    Attributes Inherited:

    -
    campaign, lobby, max_players, min_players, players, teams
    +
    allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Methods Inherited:

    begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_request(), on_team_join(), on_team_leave(), set_activity()

    Methods Defined or Overridden:

    @@ -1926,7 +1923,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    -
    campaign, lobby, max_players, min_players, players, teams
    +
    allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Methods Inherited:

    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity()

    Methods Defined or Overridden:

    @@ -1947,7 +1944,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    -
    campaign, lobby, max_players, min_players, players, teams
    +
    allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Methods Inherited:

    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity()

    Methods Defined or Overridden:

    @@ -2783,7 +2780,7 @@ Intended for use in initial joining-screens.

    remove_chooser()

    remove_chooser(self, player: ba.SessionPlayer) -> None

    -

    Remove a single player's chooser; does not kick him.

    +

    Remove a single player's chooser; does not kick them.

    This is used when a player enters the game and no longer needs a chooser.

    @@ -3240,7 +3237,7 @@ Use ba.getmodel() to instantiate one.

    Attributes Inherited:

    -
    campaign, lobby, max_players, min_players, players, teams
    +
    allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Methods Inherited:

    begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_leave(), on_player_request(), on_team_leave(), set_activity()

    Methods Defined or Overridden:

    @@ -3711,14 +3708,20 @@ even if myactor is set to None.


    ba.Player

    inherits from: typing.Generic

    -

    Testing.

    +

    A player in a specific ba.Activity.

    + +

    Category: Gameplay Classes

    + +

    These correspond to ba.SessionPlayer objects, but are created per activity + so that the activity can use its own custom player subclass. +

    Attributes:

    exists, node, sessionplayer

    exists

    bool

    -

    Whether the player still exists.

    +

    Whether the underlying player still exists.

    Most functionality will fail on a nonexistent player. Note that you can also use the boolean operator for this same @@ -4100,8 +4103,14 @@ Pass 0 or a negative number for no ban time.

    maintaining state between them (players, teams, score tallies, etc).

    Attributes:

    -
    campaign, lobby, max_players, min_players, players, teams
    +
    allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +

    allow_mid_activity_joins

    +

    bool

    +

    Whether players should be allowed to join in the middle of +activities.

    + +

    campaign

    Optional[ba.Campaign]

    The ba.Campaign instance this Session represents, or None if @@ -4139,6 +4148,20 @@ not yet selected a character, will only appear on this list.

    All the ba.Teams in the Session. Most things should use the team list in ba.Activity; not this.

    +
    +

    use_team_colors

    +

    bool

    +

    Whether players on a team should all adopt the colors of that +team instead of their own profile colors. This only applies if +use_teams is enabled.

    + +
    +

    use_teams

    +

    bool

    +

    Whether this session groups players into an explicit set of +teams. If this is off, a unique team is generated for each +player that joins.

    +

    Methods:

    @@ -4434,9 +4457,9 @@ other players.

    Category: Gameplay Classes

    -

    Note that a player *always* has a team; +

    Note that a SessionPlayer *always* has a SessionTeam; in some cases, such as free-for-all ba.Sessions, - each team consists of just one ba.Player.

    + each SessionTeam consists of just one SessionPlayer.

    Attributes:

    color, gamedata, id, name, players, sessiondata
    @@ -4735,7 +4758,13 @@ of the session.


    ba.Team

    inherits from: typing.Generic

    -

    Testing.

    +

    A team in a specific ba.Activity.

    + +

    Category: Gameplay Classes

    + +

    These correspond to ba.SessionTeam objects, but are created per activity + so that the activity can use its own custom team subclass. +

    Attributes:

    From 69c9fc3140fcd9f05d3014280781c15be65f2fd6 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Wed, 20 May 2020 21:21:35 +0300 Subject: [PATCH 023/417] fix profile colors in ffa session --- assets/src/ba_data/python/ba/_freeforallsession.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index bad02faa..e338e370 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -38,7 +38,7 @@ class FreeForAllSession(MultiTeamSession): Category: Gameplay Classes """ use_teams = False - use_team_colors = True + use_team_colors = False _playlist_selection_var = 'Free-for-All Playlist Selection' _playlist_randomize_var = 'Free-for-All Playlist Randomize' _playlists_var = 'Free-for-All Playlists' From 6ff484a7779227acd25b0e7c2555c433443061f0 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Wed, 20 May 2020 21:36:57 +0300 Subject: [PATCH 024/417] avoid using `except Exception` for logic --- assets/src/ba_data/python/ba/_profile.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/assets/src/ba_data/python/ba/_profile.py b/assets/src/ba_data/python/ba/_profile.py index b49e04e7..3a7bcf93 100644 --- a/assets/src/ba_data/python/ba/_profile.py +++ b/assets/src/ba_data/python/ba/_profile.py @@ -54,12 +54,12 @@ def get_player_profile_icon(profilename: str) -> str: icon: str try: is_global = bs_config['Player Profiles'][profilename]['global'] - except Exception: + except KeyError: is_global = False if is_global: try: icon = bs_config['Player Profiles'][profilename]['icon'] - except Exception: + except KeyError: icon = _ba.charstr(SpecialChar.LOGO) else: icon = '' @@ -82,9 +82,9 @@ def get_player_profile_colors( highlight = (0.4, 0.4, 0.5) else: try: - assert profilename is not None color = profiles[profilename]['color'] - except Exception: + assert profilename is not None + except KeyError: # key off name if possible if profilename is None: # first 6 are bright-ish @@ -94,9 +94,9 @@ def get_player_profile_colors( color = PLAYER_COLORS[sum([ord(c) for c in profilename]) % 6] try: - assert profilename is not None highlight = profiles[profilename]['highlight'] - except Exception: + assert profilename is not None + except KeyError: # key off name if possible if profilename is None: # last 2 are grey and white; ignore those or we From 051dab69cd81cfe4e15b7c5e989712bbe0d826b9 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Wed, 20 May 2020 21:49:06 +0300 Subject: [PATCH 025/417] observe type-checking :/ --- assets/src/ba_data/python/ba/_profile.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/src/ba_data/python/ba/_profile.py b/assets/src/ba_data/python/ba/_profile.py index 3a7bcf93..e29384c6 100644 --- a/assets/src/ba_data/python/ba/_profile.py +++ b/assets/src/ba_data/python/ba/_profile.py @@ -82,9 +82,9 @@ def get_player_profile_colors( highlight = (0.4, 0.4, 0.5) else: try: - color = profiles[profilename]['color'] assert profilename is not None - except KeyError: + color = profiles[profilename]['color'] + except (KeyError, AssertionError): # key off name if possible if profilename is None: # first 6 are bright-ish @@ -94,9 +94,9 @@ def get_player_profile_colors( color = PLAYER_COLORS[sum([ord(c) for c in profilename]) % 6] try: - highlight = profiles[profilename]['highlight'] assert profilename is not None - except KeyError: + highlight = profiles[profilename]['highlight'] + except (KeyError, AssertionError): # key off name if possible if profilename is None: # last 2 are grey and white; ignore those or we From 783d1ccd19cf67ba89f0aa60e4dedc1222f528a4 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 20 May 2020 18:36:21 -0700 Subject: [PATCH 026/417] More type checking cleanup --- .efrocachemap | 24 +-- .idea/dictionaries/ericf.xml | 4 + .idea/inspectionProfiles/Default.xml | 1 + assets/src/ba_data/python/_ba.py | 27 ++-- assets/src/ba_data/python/ba/__init__.py | 6 +- assets/src/ba_data/python/ba/_gameactivity.py | 18 ++- assets/src/ba_data/python/ba/_general.py | 30 +++- assets/src/ba_data/python/ba/_messages.py | 83 +++++++++- assets/src/ba_data/python/ba/_player.py | 9 +- assets/src/ba_data/python/bastd/actor/bomb.py | 8 +- .../ba_data/python/bastd/actor/playerspaz.py | 50 +----- assets/src/ba_data/python/bastd/actor/spaz.py | 5 +- .../src/ba_data/python/bastd/actor/spazbot.py | 5 +- .../src/ba_data/python/bastd/game/assault.py | 6 +- .../python/bastd/game/capturetheflag.py | 6 +- .../ba_data/python/bastd/game/chosenone.py | 9 +- .../src/ba_data/python/bastd/game/conquest.py | 31 ++-- .../ba_data/python/bastd/game/deathmatch.py | 66 ++++---- .../python/bastd/game/easteregghunt.py | 40 +++-- .../ba_data/python/bastd/game/elimination.py | 9 +- .../src/ba_data/python/bastd/game/football.py | 15 +- .../src/ba_data/python/bastd/game/hockey.py | 29 ++-- .../src/ba_data/python/bastd/game/keepaway.py | 6 +- .../python/bastd/game/kingofthehill.py | 6 +- .../ba_data/python/bastd/game/meteorshower.py | 5 +- .../ba_data/python/bastd/game/ninjafight.py | 14 +- .../ba_data/python/bastd/game/onslaught.py | 5 +- assets/src/ba_data/python/bastd/game/race.py | 8 +- .../ba_data/python/bastd/game/runaround.py | 28 ++-- .../python/bastd/game/targetpractice.py | 5 +- .../ba_data/python/bastd/game/thelaststand.py | 10 +- .../python/bastd/ui/settings/gamepad.py | 2 +- docs/ba_module.md | 145 ++++++++++++++---- 33 files changed, 440 insertions(+), 275 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index d6c71862..e461c85c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/fd/1edae1d48773436f72ceaf5c4588", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/07/88/2e60127c99cd8018f4b7a77c455b", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/01/ef/2c661b395a46f1abbd6c2042cb50", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/ad/d73757e8902b9c5c36c73469773b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/e3/9ad5acc492f343a24e790be07ed0", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/1f/5ae4c3d9b710b24ea2464c1f62ab", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/83/f9/de5c6a7a1dd65f305565bd5a0897", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/29/1f1d904b57ef0379654421737c6b", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/7b/308923feba6216c72c565cb9a942", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ce/44/4d2658f31d74fb342604e38bf12a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/53/d7/89dfbf816f8fe6824cf9f62f81f6", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1c/b8/d9def95f52348a50d01b4a9a3996" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/68/37e1f6d2afd5d6a4cbbcebba2f3e", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dc/d4/f954892306c82ca4d9c74d335c15", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4d/b8/4cfc2035ec4cdeba78be2aee8aff", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/98/9edf61a1b38432213e93b9342a4e", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/43/f76e498f45bb42f2383986d3c15b", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/d6/a9dd60f83d58eb09b1b4c0771588", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/4f/9ded4658cf6e8d8d7fdf9477ae86", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/6b/56d9fa2709eb43be73c00aacb1b5", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a9/41/2e78f2f5dfa4273ce70fc5a59e0e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9e/3d/12c0ba5235b6750ec0f37726de6e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8f/9c/edea76ee92634ef9565988c9ef6e", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/35/86/2aeb9cfac9f7639676e149e1323b" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 78083559..fe3fd86d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -578,6 +578,8 @@ execlocals executils exhash + existable + existables expatbuilder expatreader explodable @@ -752,6 +754,7 @@ getcurrency getcwd getdata + getkillerplayer getlevelname getmaps getmodel @@ -1688,6 +1691,7 @@ spinoff spinoffdata spinoffs + splayer splitlen splitnumstr squadcore diff --git a/.idea/inspectionProfiles/Default.xml b/.idea/inspectionProfiles/Default.xml index 869f7d0f..9f30bcb5 100644 --- a/.idea/inspectionProfiles/Default.xml +++ b/.idea/inspectionProfiles/Default.xml @@ -50,6 +50,7 @@ + diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 6b5325df..b65a4fff 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=68384686054944380533078060197841658129 +# SOURCES_HASH=86859069497661939825754704003122742687 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -253,9 +253,6 @@ class InputDevice: Attributes: - exists: bool - Whether the underlying device for this object is still present. - allows_configuring: bool Whether the input-device can be configured. @@ -290,7 +287,6 @@ class InputDevice: client. """ - exists: bool allows_configuring: bool player: Optional[ba.SessionPlayer] client_id: int @@ -301,6 +297,13 @@ class InputDevice: is_controller_app: bool is_remote_client: bool + def exists(self) -> bool: + """exists() -> bool + + Return whether the underlying device for this object is still present. + """ + return bool() + def get_account_name(self, full: bool) -> str: """get_account_name(full: bool) -> str @@ -767,7 +770,7 @@ class SessionPlayer: Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak' references under-the-hood; a player can leave the game at any point. For this reason, you should make judicious use of the - ba.SessionPlayer.exists attribute (or boolean operator) to ensure + ba.SessionPlayer.exists() method (or boolean operator) to ensure that a SessionPlayer is still present if retaining references to one for any length of time. @@ -776,10 +779,6 @@ class SessionPlayer: id: int The unique numeric ID of the Player. - exists: bool - Whether the player still exists. - Most functionality will fail on a nonexistent player. - Note that you can also use the boolean operator for this same functionality, so a statement such as "if player" will do the right thing both for Player objects and values of None. @@ -820,7 +819,6 @@ class SessionPlayer: The current game-specific instance for this player. """ id: int - exists: bool in_game: bool team: ba.SessionTeam sessiondata: Dict @@ -845,6 +843,13 @@ class SessionPlayer: """ return None + def exists(self) -> bool: + """exists() -> bool + + Return whether the underlying player is still in the game. + """ + return bool() + def get_account_id(self) -> str: """get_account_id() -> str diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 1c5d157c..ef418c72 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -74,13 +74,13 @@ from ba._apputils import is_browser_likely_available from ba._campaign import Campaign from ba._gameutils import (animate, animate_array, show_damage_count, sharedobj, timestring, cameraflash) -from ba._general import WeakCall, Call +from ba._general import WeakCall, Call, existing from ba._level import Level from ba._lobby import Lobby, Chooser from ba._math import normalized_color, is_point_in_box, vec3validate from ba._messages import (UNHANDLED, OutOfBoundsMessage, DeathType, DieMessage, - StandMessage, PickUpMessage, DropMessage, - PickedUpMessage, DroppedMessage, + PlayerDiedMessage, StandMessage, PickUpMessage, + DropMessage, PickedUpMessage, DroppedMessage, ShouldShatterMessage, ImpactDamageMessage, FreezeMessage, ThawMessage, HitMessage, CelebrateMessage) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 8432620e..c2b6b03d 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -29,6 +29,7 @@ from typing import TYPE_CHECKING, TypeVar from ba._activity import Activity from ba._score import ScoreInfo from ba._lang import Lstr +from ba._messages import PlayerDiedMessage import _ba if TYPE_CHECKING: @@ -645,21 +646,24 @@ class GameActivity(Activity[PlayerType, TeamType]): player.set_actor(None) def handlemessage(self, msg: Any) -> Any: - from bastd.actor.playerspaz import PlayerSpazDeathMessage - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, PlayerDiedMessage): + # pylint: disable=cyclic-import + from bastd.actor.spaz import Spaz - player = msg.playerspaz(self).player - killer = msg.killerplayer + player = msg.getplayer(self.playertype) + killer = msg.getkillerplayer(self.playertype) - # Inform our score-set of the demise. + # Inform our stats of the demise. self.stats.player_was_killed(player, killed=msg.killed, killer=killer) # Award the killer points if he's on a different team. + # FIXME: This should not be linked to Spaz actors. + # (should move get_death_points to Actor or make it a message) if killer and killer.team is not player.team: - pts, importance = msg.playerspaz(self).get_death_points( - msg.how) + assert isinstance(killer.actor, Spaz) + pts, importance = killer.actor.get_death_points(msg.how) if not self.has_ended(): self.stats.player_scored(killer, pts, diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index ed61f77d..a535b00d 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -28,12 +28,40 @@ from typing import TYPE_CHECKING, TypeVar import _ba if TYPE_CHECKING: - from typing import Any, Type + from typing import Any, Type, Optional + from typing_extensions import Protocol from efro.call import Call as Call # 'as Call' so we re-export. + class Existable(Protocol): + """Protocol for objects supporting an exists() method.""" + + def exists(self) -> bool: + """Whether this object exists.""" + ... + + ExistableType = TypeVar('ExistableType', bound=Existable) + T = TypeVar('T') +def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]: + """Convert invalid references to None. + + Category: Gameplay Functions + + 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 dead + objects into functions expecting only live ones, etc. + This call can be used on any 'existable' object (one with an exists() + method) and will convert it to a None value if it does not exist. + For more info, see notes on 'existables' here: + https://github.com/efroemling/ballistica/wiki/Coding-Style-Guide + """ + assert obj is None or hasattr(obj, 'exists'), f'No "exists" on {obj}' + return obj if obj is not None and obj.exists() else None + + def getclass(name: str, subclassof: Type[T]) -> Type[T]: """Given a full class name such as foo.bar.MyClass, return the class. diff --git a/assets/src/ba_data/python/ba/_messages.py b/assets/src/ba_data/python/ba/_messages.py index eb0fda5a..ed309833 100644 --- a/assets/src/ba_data/python/ba/_messages.py +++ b/assets/src/ba_data/python/ba/_messages.py @@ -23,13 +23,13 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar from enum import Enum import _ba if TYPE_CHECKING: - from typing import Sequence + from typing import Sequence, Optional, Type, Any import ba @@ -88,6 +88,64 @@ class DieMessage: how: DeathType = DeathType.GENERIC +PlayerType = TypeVar('PlayerType', bound='ba.Player') + + +class PlayerDiedMessage: + """A message saying a ba.PlayerSpaz has died. + + category: Message Classes + + Attributes: + + killed + If True, the spaz was killed; + If False, they left the game or the round ended. + + how + The particular type of death. + """ + killed: bool + how: ba.DeathType + + def __init__(self, player: ba.Player, was_killed: bool, + killerplayer: Optional[ba.Player], how: ba.DeathType): + """Instantiate a message with the given values.""" + + # Invalid refs should never be passed as args. + assert player.exists() + self._player = player + + # Invalid refs should never be passed as args. + assert killerplayer is None or killerplayer.exists() + self._killerplayer = killerplayer + self.killed = was_killed + self.how = how + + def getkillerplayer(self, + playertype: Type[PlayerType]) -> Optional[PlayerType]: + """Return the ba.Player responsible for the killing, if any. + + Pass the Player type being used by the current game. + """ + assert isinstance(self._killerplayer, (playertype, type(None))) + return self._killerplayer + + def getplayer(self, playertype: Type[PlayerType]) -> PlayerType: + """Return the spaz that died. + + The current activity is required as an argument so the exact type of + PlayerSpaz can be determined by the type checker. + """ + player: Any = self._player + assert isinstance(player, playertype) + + # We should never be delivering invalid refs. + # (could theoretically happen if someone holds on to us) + assert player.exists() + return player + + @dataclass class StandMessage: """A message telling an object to move to a position in space. @@ -212,7 +270,6 @@ class CelebrateMessage: duration: float = 10.0 -@dataclass(init=False) class HitMessage: """Tells an object it has been hit in some way. @@ -243,7 +300,10 @@ class HitMessage: self.magnitude = magnitude self.velocity_magnitude = velocity_magnitude self.radius = radius - self.source_player = source_player + + # Invalid refs should never be passed to things. + assert source_player is None or source_player.exists() + self._source_player = source_player self.kick_back = kick_back self.flat_damage = flat_damage self.hit_type = hit_type @@ -251,6 +311,21 @@ class HitMessage: self.force_direction = (force_direction if force_direction is not None else velocity) + def get_source_player( + self, playertype: Type[PlayerType]) -> Optional[PlayerType]: + """Return the spaz that died. + + The current activity is required as an argument so the exact type of + PlayerSpaz can be determined by the type checker. + """ + player: Any = self._source_player + assert isinstance(player, (playertype, type(None))) + + # We should not be delivering invalid refs. + # (technically if someone holds on to this message this can happen) + assert player is None or player.exists() + return player + @dataclass class PlayerProfilesChangedMessage: diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 6622e609..56e490e9 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -29,6 +29,7 @@ if TYPE_CHECKING: Callable) import ba +PlayerType = TypeVar('PlayerType', bound='ba.Player') TeamType = TypeVar('TeamType', bound='ba.Team') @@ -117,7 +118,6 @@ class Player(Generic[TeamType]): raise _error.NodeNotFoundError return self._nodeactor.node - @property def exists(self) -> bool: """Whether the underlying player still exists. @@ -126,7 +126,7 @@ class Player(Generic[TeamType]): functionality, so a statement such as "if player" will do the right thing both for Player objects and values of None. """ - return bool(self._sessionplayer) + return self._sessionplayer.exists() def get_name(self, full: bool = False, icon: bool = True) -> str: """get_name(full: bool = False, icon: bool = True) -> str @@ -181,10 +181,7 @@ class Player(Generic[TeamType]): self._sessionplayer.reset_input() def __bool__(self) -> bool: - return bool(self._sessionplayer) - - -PlayerType = TypeVar('PlayerType', bound='ba.Player') + return self._sessionplayer.exists() def playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType: diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index bf4aca77..d88a5d69 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -623,7 +623,8 @@ class Blast(ba.Actor): hit_type=self.hit_type, hit_subtype=self.hit_subtype, radius=self.radius, - source_player=self.source_player)) + source_player=ba.existing( + self.source_player))) if self.blast_type == 'ice': ba.playsound(get_factory().freeze_sound, 10, @@ -987,8 +988,9 @@ class Bomb(ba.Actor): # Also lets change the owner of the bomb to whoever is setting # us off. (this way points for big chain reactions go to the # person causing them). - if msg.source_player not in [None]: - self.source_player = msg.source_player + source_player = msg.get_source_player(ba.Player) + if source_player is not None: + self.source_player = source_player # Also inherit the hit type (if a landmine sets off by a bomb, # the credit should go to the mine) diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 5c66414c..1c620736 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -34,44 +34,6 @@ PlayerType = TypeVar('PlayerType', bound=ba.Player) TeamType = TypeVar('TeamType', bound=ba.Team) -class PlayerSpazDeathMessage: - """A message saying a ba.PlayerSpaz has died. - - category: Message Classes - - Attributes: - - killed - If True, the spaz was killed; - If False, they left the game or the round ended. - - killerplayer - The ba.Player that did the killing, or None. - - how - The particular type of death. - """ - - def __init__(self, spaz: PlayerSpaz, was_killed: bool, - killerplayer: Optional[ba.Player], how: ba.DeathType): - """Instantiate a message with the given values.""" - self._spaz = spaz - self.killed = was_killed - self.killerplayer = killerplayer - self.how = how - - def playerspaz( - self, activity: ba.Activity[PlayerType, - TeamType]) -> PlayerSpaz[PlayerType]: - """Return the spaz that died. - - The current activity is required as an argument so the exact type of - PlayerSpaz can be determined by the type checker. - """ - del activity # Unused - return self._spaz - - class PlayerSpazHurtMessage: """A message saying a ba.PlayerSpaz was hurt. @@ -93,7 +55,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): category: Gameplay Classes - When a PlayerSpaz dies, it delivers a ba.PlayerSpazDeathMessage + When a PlayerSpaz dies, it delivers a ba.PlayerDiedMessage to the current ba.Activity. (unless the death was the result of the player leaving the game, in which case no message is sent) @@ -302,16 +264,16 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): # Only report if both the player and the activity still exist. if killed and activity is not None and self.getplayer(): activity.handlemessage( - PlayerSpazDeathMessage(self, killed, killerplayer, - msg.how)) + ba.PlayerDiedMessage(self.player, killed, killerplayer, + msg.how)) super().handlemessage(msg) # Augment standard behavior. # Keep track of the player who last hit us for point rewarding. elif isinstance(msg, ba.HitMessage): - if msg.source_player: - srcplayer = ba.playercast_o(self.playertype, msg.source_player) - self.last_player_attacked_by = srcplayer + source_player = msg.get_source_player(self.playertype) + if source_player: + self.last_player_attacked_by = source_player self.last_attacked_time = ba.time() self.last_attacked_type = (msg.hit_type, msg.hit_subtype) super().handlemessage(msg) # Augment standard behavior. diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index 96c713c4..c61827d8 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -1089,8 +1089,9 @@ class Spaz(ba.Actor): # If we're cursed, *any* damage blows us up. if self._cursed and damage > 0: ba.timer( - 0.05, ba.WeakCall(self.curse_explode, - msg.source_player)) + 0.05, + ba.WeakCall(self.curse_explode, + msg.get_source_player(ba.Player))) # if we're frozen, shatter.. otherwise die if we hit zero if self.frozen and (damage > 200 or self.hitpoints <= 0): self.shatter() diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index d0602951..5457cb20 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -574,8 +574,9 @@ class SpazBot(Spaz): # Keep track of the player who last hit us for point rewarding. elif isinstance(msg, ba.HitMessage): - if msg.source_player: - self.last_player_attacked_by = msg.source_player + source_player = msg.get_source_player(ba.Player) + if source_player: + self.last_player_attacked_by = source_player self.last_attacked_time = ba.time() self.last_attacked_type = (msg.hit_type, msg.hit_subtype) super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 334571df..cf4821a8 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -29,7 +29,7 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.flag import Flag if TYPE_CHECKING: @@ -161,9 +161,9 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): self.setup_standard_powerup_drops() def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): super().handlemessage(msg) # Augment standard. - self.respawn_player(msg.playerspaz(self).player) + self.respawn_player(msg.getplayer(Player)) else: super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 6b1e028c..f2f6e540 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -29,7 +29,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor import flag as stdflag -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: @@ -548,10 +548,10 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self._score_to_win) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.playerspaz(self).player) + self.respawn_player(msg.getplayer(Player)) elif isinstance(msg, stdflag.FlagDeathMessage): assert isinstance(msg.flag, CTFFlag) ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index e750c390..212f57d5 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -28,7 +28,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence, Union @@ -312,12 +312,13 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): 'position') def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - player = msg.playerspaz(self).player + player = msg.getplayer(Player) if player is self._get_chosen_one_player(): - killerplayer = ba.playercast_o(Player, msg.killerplayer) + killerplayer = ba.playercast_o(Player, + msg.getkillerplayer(Player)) self._set_chosen_one_player(None if ( killerplayer is None or killerplayer is player or not killerplayer.is_alive()) else killerplayer) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index b459e147..11430f35 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -30,7 +30,6 @@ from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag -from bastd.actor.playerspaz import PlayerSpazDeathMessage if TYPE_CHECKING: from typing import Any, Optional, Type, List, Dict, Sequence, Union @@ -41,22 +40,30 @@ class ConquestFlag(Flag): def __init__(self, *args: Any, **keywds: Any): super().__init__(*args, **keywds) - self._team: Optional[ba.Team] = None + self._team: Optional[Team] = None self.light: Optional[ba.Node] = None @property - def team(self) -> Optional[ba.Team]: + def team(self) -> Optional[Team]: """The team that owns this flag.""" return self._team @team.setter - def team(self, team: ba.Team) -> None: + def team(self, team: Team) -> None: """Set the team that owns this flag.""" self._team = team +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class ConquestGame(ba.TeamGameActivity[Player, Team]): """A game where teams try to claim all flags on the map.""" name = 'Conquest' @@ -115,12 +122,12 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): ba.MusicType.GRAND_ROMP) super().on_transition_in() - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: if self.has_begun(): self._update_scores() team.gamedata['flags_held'] = 0 - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: Player) -> None: player.gamedata['respawn_timer'] = None # Only spawn if this player's team has a flag currently. @@ -213,7 +220,7 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): flag = flagnode.getdelegate() except Exception: return # Player may have left and his body hit the flag. - assert isinstance(player, ba.Player) + assert isinstance(player, Player) assert isinstance(flag, ConquestFlag) assert flag.light @@ -236,12 +243,12 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): self.spawn_player(otherplayer) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) # Respawn only if this team has a flag. - player = msg.playerspaz(self).player + player = msg.getplayer(Player) if player.team.gamedata['flags_held'] > 0: self.respawn_player(player) else: @@ -250,12 +257,12 @@ class ConquestGame(ba.TeamGameActivity[ba.Player, ba.Team]): else: super().handlemessage(msg) - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: # We spawn players at different places based on what flags are held. return self.spawn_player_spaz(player, self._get_player_spawn_position(player)) - def _get_player_spawn_position(self, player: ba.Player) -> Sequence[float]: + def _get_player_spawn_position(self, player: Player) -> Sequence[float]: # Iterate until we find a spawn owned by this team. spawn_count = len(self.map.spawn_by_flag_points) diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 71199095..03e48d08 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -27,11 +27,10 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz -from bastd.actor import spaz as stdspaz +from bastd.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: - from typing import Any, Type, List, Dict, Tuple, Union, Sequence + from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional class Player(ba.Player['Team']): @@ -42,7 +41,7 @@ class Team(ba.Team[Player]): """Our team type for this game.""" def __init__(self) -> None: - pass + self.score = 0 # ba_meta export game @@ -104,9 +103,14 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() - self._score_to_win = None + self._score_to_win: Optional[int] = None self._dingsound = ba.getsound('dingSmall') self._epic_mode = bool(settings['Epic Mode']) + self._kills_to_win_per_player = int( + settings['Kills to Win Per Player']) + self._time_limit = float(settings['Time Limit']) + self._allow_negative_scores = bool( + settings.get('Allow Negative Scores', False)) # Base class overrides. self.slow_motion = self._epic_mode @@ -120,34 +124,30 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): return 'kill ${ARG1} enemies', self._score_to_win def on_team_join(self, team: Team) -> None: - team.gamedata['score'] = 0 if self.has_begun(): self._update_scoreboard() def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() - if self.teams: - self._score_to_win = ( - self.settings_raw['Kills to Win Per Player'] * - max(1, max(len(t.players) for t in self.teams))) - else: - self._score_to_win = self.settings_raw['Kills to Win Per Player'] + + # Base kills needed to win on the size of the largest team. + self._score_to_win = (self._kills_to_win_per_player * + max(1, max(len(t.players) for t in self.teams))) self._update_scoreboard() def handlemessage(self, msg: Any) -> Any: - # pylint: disable=too-many-branches - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - player = msg.playerspaz(self).player + player = msg.getplayer(Player) self.respawn_player(player) - killer = msg.killerplayer + killer = msg.getkillerplayer(Player) if killer is None: return @@ -156,41 +156,37 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): # In free-for-all, killing yourself loses you a point. if isinstance(self.session, ba.FreeForAllSession): - new_score = player.team.gamedata['score'] - 1 - if not self.settings_raw['Allow Negative Scores']: + new_score = player.team.score - 1 + if not self._allow_negative_scores: new_score = max(0, new_score) - player.team.gamedata['score'] = new_score + player.team.score = new_score # In teams-mode it gives a point to the other team. else: ba.playsound(self._dingsound) for team in self.teams: if team is not killer.team: - team.gamedata['score'] += 1 + team.score += 1 # Killing someone on another team nets a kill. else: - killer.team.gamedata['score'] += 1 + killer.team.score += 1 ba.playsound(self._dingsound) # In FFA show scores since its hard to find on the scoreboard. - try: - if isinstance(killer.actor, stdspaz.Spaz): - killer.actor.set_score_text( - str(killer.team.gamedata['score']) + '/' + - str(self._score_to_win), - color=killer.team.color, - flash=True) - except Exception: - pass + if isinstance(killer.actor, PlayerSpaz) and killer.actor: + killer.actor.set_score_text(str(killer.team.score) + '/' + + str(self._score_to_win), + color=killer.team.color, + flash=True) self._update_scoreboard() # If someone has won, set a timer to end shortly. # (allows the dust to clear and draws to occur if deaths are # close enough) - if any(team.gamedata['score'] >= self._score_to_win - for team in self.teams): + assert self._score_to_win is not None + if any(team.score >= self._score_to_win for team in self.teams): ba.timer(0.5, self.end_game) else: @@ -198,11 +194,11 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): def _update_scoreboard(self) -> None: for team in self.teams: - self._scoreboard.set_team_value(team, team.gamedata['score'], + self._scoreboard.set_team_value(team, team.score, self._score_to_win) def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score(team, team.gamedata['score']) + results.set_team_score(team, team.score) self.end(results=results) diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 79e5382b..96ea4ef9 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -29,9 +29,9 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import bomb -from bastd.actor import playerspaz -from bastd.actor import spazbot +from bastd.actor.bomb import Bomb +from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.spazbot import BotSet, BouncyBot, SpazBotDeathMessage from bastd.actor.onscreencountdown import OnScreenCountdown from bastd.actor.scoreboard import Scoreboard @@ -39,8 +39,16 @@ if TYPE_CHECKING: from typing import Any, Type, Dict, List, Tuple, Optional +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): """A game where score is based on collecting eggs.""" name = 'Easter Egg Hunt' @@ -78,7 +86,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._eggs: List[Egg] = [] self._update_timer: Optional[ba.Timer] = None self._countdown: Optional[OnScreenCountdown] = None - self._bots: Optional[spazbot.BotSet] = None + self._bots: Optional[BotSet] = None # Called when our game is transitioning in but not ready to start. # ..we can go ahead and set our music and whatnot. @@ -87,7 +95,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): self.default_music = ba.MusicType.FORWARD_MARCH super().on_transition_in() - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: team.gamedata['score'] = 0 if self.has_begun(): self._update_scoreboard() @@ -106,23 +114,21 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._update_timer = ba.Timer(0.25, self._update, repeat=True) self._countdown = OnScreenCountdown(60, endcall=self.end_game) ba.timer(4.0, self._countdown.start) - self._bots = spazbot.BotSet() + self._bots = BotSet() # Spawn evil bunny in co-op only. if isinstance(self.session, ba.CoopSession) and self._pro_mode: self._spawn_evil_bunny() # Overriding the default character spawning. - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: spaz = self.spawn_player_spaz(player) spaz.connect_controls_to_player() return spaz def _spawn_evil_bunny(self) -> None: assert self._bots is not None - self._bots.spawn_bot(spazbot.BouncyBot, - pos=(6, 4, -7.8), - spawn_time=10.0) + self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0) def _on_egg_player_collide(self) -> None: if not self.has_ended(): @@ -132,7 +138,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): egg = egg_node.getdelegate() assert isinstance(egg, Egg) spaz = playernode.getdelegate() - assert isinstance(spaz, playerspaz.PlayerSpaz) + assert isinstance(spaz, PlayerSpaz) player = (spaz.getplayer() if hasattr(spaz, 'getplayer') else None) if player and egg: @@ -184,8 +190,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): # Occasionally spawn a land-mine in addition. if self._pro_mode and random.random() < 0.25: - mine = bomb.Bomb(position=(xpos, ypos, zpos), - bomb_type='land_mine').autoretain() + mine = Bomb(position=(xpos, ypos, zpos), + bomb_type='land_mine').autoretain() mine.arm() else: self._eggs.append(Egg(position=(xpos, ypos, zpos))) @@ -194,12 +200,12 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): def handlemessage(self, msg: Any) -> Any: # Respawn dead players. - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): from bastd.actor import respawnicon # Augment standard behavior. super().handlemessage(msg) - player = msg.playerspaz(self).getplayer() + player = msg.getplayer(Player) if not player: return self.stats.player_was_killed(player) @@ -213,7 +219,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[ba.Player, ba.Team]): player, respawn_time) # Whenever our evil bunny dies, respawn him and spew some eggs. - elif isinstance(msg, spazbot.SpazBotDeathMessage): + elif isinstance(msg, SpazBotDeathMessage): self._spawn_evil_bunny() assert msg.badguy.node pos = msg.badguy.node.position diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 97361733..b38eff49 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -28,8 +28,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz -from bastd.actor import spaz +from bastd.actor.spaz import get_factory if TYPE_CHECKING: from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, @@ -489,11 +488,11 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): return sum(player.lives for player in team.players) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - player: Player = msg.playerspaz(self).player + player: Player = msg.getplayer(Player) player.lives -= 1 if player.lives < 0: @@ -509,7 +508,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): # Play big death sound on our last death # or for every one in solo mode. if self._solo_mode or player.lives == 0: - ba.playsound(spaz.get_factory().single_player_death_sound) + ba.playsound(get_factory().single_player_death_sound) # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 2e281b84..bfb77ec1 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -33,8 +33,9 @@ import ba from bastd.actor import spazbot from bastd.actor import flag as stdflag from bastd.actor.bomb import TNTSpawner -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard +from bastd.actor.respawnicon import RespawnIcon if TYPE_CHECKING: from typing import Any, List, Type, Dict, Sequence, Optional, Union @@ -268,10 +269,10 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): msg.flag.held_count -= 1 # Respawn dead players if they're still in the game. - elif isinstance(msg, PlayerSpazDeathMessage): + elif isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.playerspaz(self).player) + self.respawn_player(msg.getplayer(Player)) # Respawn dead flags. elif isinstance(msg, stdflag.FlagDeathMessage): @@ -798,11 +799,10 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: """ handle high-level game messages """ - if isinstance(msg, PlayerSpazDeathMessage): - from bastd.actor import respawnicon + if isinstance(msg, ba.PlayerDiedMessage): # Respawn dead players. - player = msg.playerspaz(self).player + player = msg.getplayer(Player) self.stats.player_was_killed(player) assert self.initial_player_info is not None respawn_time = 2.0 + len(self.initial_player_info) * 1.0 @@ -810,8 +810,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): # Respawn them shortly. player.gamedata['respawn_timer'] = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) - player.gamedata['respawn_icon'] = respawnicon.RespawnIcon( - player, respawn_time) + player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) # Augment standard behavior. super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index de4a813a..da8386fb 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -28,7 +28,6 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -50,7 +49,7 @@ class Puck(ba.Actor): # Spawn just above the provided point. self._spawn_pos = (position[0], position[1] + 1.0, position[2]) - self.last_players_to_touch: Dict[int, ba.Player] = {} + self.last_players_to_touch: Dict[int, Player] = {} self.scored = False assert activity is not None assert isinstance(activity, HockeyGame) @@ -94,18 +93,26 @@ class Puck(ba.Actor): msg.force_direction[2]) # If this hit came from a player, log them as the last to touch us. - if msg.source_player is not None: + splayer = msg.get_source_player(Player) + if splayer is not None: activity = self._activity() if activity: - if msg.source_player in activity.players: - self.last_players_to_touch[ - msg.source_player.team.id] = msg.source_player + if splayer in activity.players: + self.last_players_to_touch[splayer.team.id] = splayer else: super().handlemessage(msg) +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + # ba_meta export game -class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): +class HockeyGame(ba.TeamGameActivity[Player, Team]): """Ice hockey game.""" name = 'Hockey' @@ -234,7 +241,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): self._update_scoreboard() ba.playsound(self._chant_sound) - def on_team_join(self, team: ba.Team) -> None: + def on_team_join(self, team: Team) -> None: team.gamedata['score'] = 0 self._update_scoreboard() @@ -246,7 +253,7 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): player = playernode.getdelegate().getplayer() except Exception: player = puck = None - assert isinstance(player, ba.Player) + assert isinstance(player, Player) assert isinstance(puck, Puck) if player and puck: puck.last_players_to_touch[player.team.id] = player @@ -330,10 +337,10 @@ class HockeyGame(ba.TeamGameActivity[ba.Player, ba.Team]): def handlemessage(self, msg: Any) -> Any: # Respawn dead players if they're still in the game. - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior... super().handlemessage(msg) - self.respawn_player(msg.playerspaz(self).player) + self.respawn_player(msg.getplayer(Player)) # Respawn dead pucks. elif isinstance(msg, PuckDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index b3ea1d54..9e924b20 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -29,9 +29,9 @@ from enum import Enum from typing import TYPE_CHECKING import ba +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDeathMessage, FlagPickedUpMessage) -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence, Union @@ -266,10 +266,10 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): countdown=True) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) - self.respawn_player(msg.playerspaz(self).player) + self.respawn_player(msg.getplayer(Player)) elif isinstance(msg, FlagDeathMessage): self._spawn_flag() elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)): diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index b69be0f4..a20a721a 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -31,7 +31,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: @@ -272,11 +272,11 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): countdown=True) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): super().handlemessage(msg) # Augment default. # No longer can count as time_at_flag once dead. - player = msg.playerspaz(self).player + player = msg.getplayer(Player) player.time_at_flag = 0 self._update_flag_state() self.respawn_player(player) diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 53d404ec..fac0f292 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -30,7 +30,6 @@ from typing import TYPE_CHECKING import ba from bastd.actor.bomb import Bomb -from bastd.actor.playerspaz import PlayerSpazDeathMessage from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: @@ -151,7 +150,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): # Various high-level game events come through this method. def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment standard behavior. super().handlemessage(msg) @@ -160,7 +159,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): # Record the player's moment of death. # assert isinstance(msg.spaz.player - msg.playerspaz(self).player.death_time = curtime + msg.getplayer(Player).death_time = curtime # In co-op mode, end the game the instant everyone dies # (more accurate looking). diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 93c9e26a..52503bd9 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -29,9 +29,8 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import onscreentimer -from bastd.actor import playerspaz from bastd.actor import spazbot +from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: from typing import Any, Type, Dict, List, Optional @@ -76,7 +75,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): super().__init__(settings) self._winsound = ba.getsound('score') self._won = False - self._timer: Optional[onscreentimer.OnScreenTimer] = None + self._timer: Optional[OnScreenTimer] = None self._bots = spazbot.BotSet() # Called when our game is transitioning in but not ready to begin; @@ -95,7 +94,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self.setup_standard_powerup_drops() # Make our on-screen timer and start it roughly when our bots appear. - self._timer = onscreentimer.OnScreenTimer() + self._timer = OnScreenTimer() ba.timer(4.0, self._timer.start) # Spawn some baddies. @@ -146,10 +145,9 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: # A player has died. - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): - super().handlemessage(msg) # do standard stuff - self.respawn_player( - msg.playerspaz(self).player) # kick off a respawn + if isinstance(msg, ba.PlayerDiedMessage): + super().handlemessage(msg) # Augment standard behavior. + self.respawn_player(msg.getplayer(Player)) # A spaz-bot has died. elif isinstance(msg, spazbot.SpazBotDeathMessage): diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 11856451..8f58c609 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -1164,10 +1164,9 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._score += msg.score self._update_scores() - elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): + elif isinstance(msg, ba.PlayerDiedMessage): super().handlemessage(msg) # Augment standard behavior. - player = msg.playerspaz(self).getplayer() - assert player is not None + player = msg.getplayer(Player) self._a_player_has_been_hurt = True # Make note with the player when they can respawn: diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 86950240..0bd2bac9 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -31,7 +31,7 @@ from dataclasses import dataclass import ba from bastd.actor.bomb import Bomb -from bastd.actor.playerspaz import PlayerSpaz, PlayerSpazDeathMessage +from bastd.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, @@ -734,12 +734,12 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): ba.DualTeamSession)) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): # Augment default behavior. super().handlemessage(msg) - player = msg.playerspaz(self).getplayer() + player = msg.getplayer(Player) if not player: - ba.print_error('got no player in PlayerSpazDeathMessage') + ba.print_error('got no player in PlayerDiedMessage') return if not player.gamedata['finished']: self.respawn_player(player, respawn_time=1) diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 8e7d360f..6f985b9e 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -29,16 +29,24 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz from bastd.actor import spazbot from bastd.actor.bomb import TNTSpawner from bastd.actor.scoreboard import Scoreboard +from bastd.actor.respawnicon import RespawnIcon if TYPE_CHECKING: from typing import Type, Any, List, Dict, Tuple, Sequence, Optional -class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): +class Player(ba.Player['Team']): + """Our player type for this game.""" + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + +class RunaroundGame(ba.CoopGameActivity[Player, Team]): """Game involving trying to bomb bots as they walk through the map.""" name = 'Runaround' @@ -457,7 +465,7 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): self._lives_text.node.text = str(self._lives) self._bots.start_moving() - def spawn_player(self, player: ba.Player) -> ba.Actor: + def spawn_player(self, player: Player) -> ba.Actor: pos = (self._spawn_center[0] + random.uniform(-1.5, 1.5), self._spawn_center[1], self._spawn_center[2] + random.uniform(-1.5, 1.5)) @@ -1118,16 +1126,9 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): self._update_scores() # Respawn dead players. - elif isinstance(msg, playerspaz.PlayerSpazDeathMessage): - from bastd.actor import respawnicon + elif isinstance(msg, ba.PlayerDiedMessage): self._a_player_has_been_killed = True - player = msg.playerspaz(self).getplayer() - if player is None: - ba.print_error('FIXME: getplayer() should no' - ' longer ever be returning None') - return - if not player: - return + player = msg.getplayer(Player) self.stats.player_was_killed(player) # Respawn them shortly. @@ -1135,8 +1136,7 @@ class RunaroundGame(ba.CoopGameActivity[ba.Player, ba.Team]): respawn_time = 2.0 + len(self.initial_player_info) * 1.0 player.gamedata['respawn_timer'] = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) - player.gamedata['respawn_icon'] = respawnicon.RespawnIcon( - player, respawn_time) + player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) elif isinstance(msg, spazbot.SpazBotDeathMessage): if msg.how is ba.DeathType.REACHED_GOAL: diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index d34ee538..33972629 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -29,7 +29,6 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor.playerspaz import PlayerSpazDeathMessage if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence @@ -193,9 +192,9 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: # When players die, respawn them. - if isinstance(msg, PlayerSpazDeathMessage): + if isinstance(msg, ba.PlayerDiedMessage): super().handlemessage(msg) # Do standard stuff. - player = msg.playerspaz(self).getplayer() + player = msg.getplayer(Player) assert player is not None self.respawn_player(player) # Kick off a respawn. elif isinstance(msg, Target.TargetHitMessage): diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 3eb3eaad..147bd279 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -257,14 +257,8 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): self._scoreboard.set_team_value(self.teams[0], score, max_score=None) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, playerspaz.PlayerSpazDeathMessage): - player = msg.playerspaz(self).getplayer() - if player is None: - ba.print_error('FIXME: getplayer() should no longer ' - 'ever be returning None.') - return - if not player: - return + if isinstance(msg, ba.PlayerDiedMessage): + player = msg.getplayer(Player) self.stats.player_was_killed(player) ba.timer(0.1, self._checkroundover) diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index 046f9b12..758b432f 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -836,7 +836,7 @@ class AwaitGamepadInputWindow(ba.Window): assert isinstance(input_device, ba.InputDevice) # Update - we now allow *any* input device of this type. - if input_device.exists and input_device.name == self._input.name: + if input_device.exists() and input_device.name == self._input.name: self._callback(self._capture_button, event, self) def _decrement(self) -> None: diff --git a/docs/ba_module.md b/docs/ba_module.md index 8ec9e7f4..7a27b536 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -50,6 +50,7 @@
  • ba.cameraflash()
  • ba.camerashake()
  • ba.emitfx()
  • +
  • ba.existing()
  • ba.get_collision_info()
  • ba.getactivity()
  • ba.getnodes()
  • @@ -127,6 +128,7 @@
  • ba.OutOfBoundsMessage
  • ba.PickedUpMessage
  • ba.PickUpMessage
  • +
  • ba.PlayerDiedMessage
  • ba.PlayerScoredMessage
  • ba.PowerupAcceptMessage
  • ba.PowerupMessage
  • @@ -2453,12 +2455,22 @@ and short description of the game.

    Methods:

    +
    <constructor>, get_source_player()

    <constructor>

    ba.HitMessage(srcnode: 'ba.Node' = None, pos: 'Sequence[float]' = None, velocity: 'Sequence[float]' = None, magnitude: 'float' = 1.0, velocity_magnitude: 'float' = 0.0, radius: 'float' = 1.0, source_player: 'ba.Player' = None, kick_back: 'float' = 1.0, flat_damage: 'float' = None, hit_type: 'str' = 'generic', force_direction: 'Sequence[float]' = None, hit_subtype: 'str' = 'default')

    Instantiate a message with given values.

    +
    +

    get_source_player()

    +

    get_source_player(self, playertype: Type[PlayerType]) -> Optional[PlayerType]

    + +

    Return the spaz that died.

    + +

    The current activity is required as an argument so the exact type of +PlayerSpaz can be determined by the type checker.

    +

    @@ -2493,7 +2505,7 @@ and short description of the game.

    Category: Gameplay Classes

    Attributes:

    -
    allows_configuring, client_id, exists, id, instance_number, is_controller_app, is_remote_client, name, player, unique_identifier
    +
    allows_configuring, client_id, id, instance_number, is_controller_app, is_remote_client, name, player, unique_identifier

    allows_configuring

    bool

    @@ -2506,11 +2518,6 @@ and short description of the game.

    This is only meaningful for remote client inputs; for all local devices this will be -1.

    -
    -

    exists

    -

    bool

    -

    Whether the underlying device for this object is still present.

    -

    id

    int

    @@ -2553,8 +2560,14 @@ prefs, etc.

    Methods:

    -
    get_account_name(), get_axis_name(), get_button_name()
    +
    exists(), get_account_name(), get_axis_name(), get_button_name()
    +

    exists()

    +

    exists() -> bool

    + +

    Return whether the underlying device for this object is still present.

    + +

    get_account_name()

    get_account_name(full: bool) -> str

    @@ -3717,18 +3730,8 @@ even if myactor is set to None.

    Attributes:

    -
    exists, node, sessionplayer
    +
    node, sessionplayer
    -

    exists

    -

    bool

    -

    Whether the underlying player still exists.

    - -

    Most functionality will fail on a nonexistent player. - Note that you can also use the boolean operator for this same - functionality, so a statement such as "if player" will do - the right thing both for Player objects and values of None.

    - -

    node

    ba.Node

    A ba.Node of type 'player' associated with this Player.

    @@ -3745,7 +3748,7 @@ even if myactor is set to None.

    Methods:

    -
    assign_input_call(), get_icon(), get_name(), is_alive(), reset_input(), set_actor()
    +
    assign_input_call(), exists(), get_icon(), get_name(), is_alive(), reset_input(), set_actor()

    assign_input_call()

    assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    @@ -3761,6 +3764,17 @@ Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', 'startRelease'

    +
    +

    exists()

    +

    exists(self) -> bool

    + +

    Whether the underlying player still exists.

    + +

    Most functionality will fail on a nonexistent player. +Note that you can also use the boolean operator for this same +functionality, so a statement such as "if player" will do +the right thing both for Player objects and values of None.

    +

    get_icon()

    get_icon(self) -> Dict[str, Any]

    @@ -3803,6 +3817,56 @@ is_alive() method return True. False is returned otherwise.

    Set the player's associated ba.Actor.

    +
    +
    +
    +

    ba.PlayerDiedMessage

    +

    <top level class> +

    +

    A message saying a ba.PlayerSpaz has died.

    + +

    Category: Message Classes

    + +

    Attributes:

    +
    how, killed
    +
    +

    how

    +

    ba.DeathType

    +

    The particular type of death.

    + +
    +

    killed

    +

    bool

    +

    If True, the spaz was killed; +If False, they left the game or the round ended.

    + +
    +
    +

    Methods:

    +
    <constructor>, getkillerplayer(), getplayer()
    +
    +

    <constructor>

    +

    ba.PlayerDiedMessage(player: ba.Player, was_killed: bool, killerplayer: Optional[ba.Player], how: ba.DeathType)

    + +

    Instantiate a message with the given values.

    + +
    +

    getkillerplayer()

    +

    getkillerplayer(self, playertype: Type[PlayerType]) -> Optional[PlayerType]

    + +

    Return the ba.Player responsible for the killing, if any.

    + +

    Pass the Player type being used by the current game.

    + +
    +

    getplayer()

    +

    getplayer(self, playertype: Type[PlayerType]) -> PlayerType

    + +

    Return the spaz that died.

    + +

    The current activity is required as an argument so the exact type of +PlayerSpaz can be determined by the type checker.

    +

    @@ -4297,12 +4361,12 @@ provided to your Session/Activity instances. Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak' references under-the-hood; a player can leave the game at any point. For this reason, you should make judicious use of the -ba.SessionPlayer.exists attribute (or boolean operator) to ensure +ba.SessionPlayer.exists() method (or boolean operator) to ensure that a SessionPlayer is still present if retaining references to one for any length of time.

    Attributes:

    -
    character, color, exists, gamedata, gameplayer, highlight, id, in_game, sessiondata, team
    +
    character, color, gamedata, gameplayer, highlight, id, in_game, sessiondata, team

    character

    str

    @@ -4314,16 +4378,6 @@ for any length of time.

    The base color for this Player. In team games this will match the ba.SessionTeam's color.

    -
    -

    exists

    -

    bool

    -

    Whether the player still exists. -Most functionality will fail on a nonexistent player.

    - -

    Note that you can also use the boolean operator for this same -functionality, so a statement such as "if player" will do -the right thing both for Player objects and values of None.

    -

    gamedata

    Dict

    @@ -4349,6 +4403,10 @@ who may all share the same team (primary) color.

    int

    The unique numeric ID of the Player.

    +

    Note that you can also use the boolean operator for this same +functionality, so a statement such as "if player" will do +the right thing both for Player objects and values of None.

    +

    in_game

    bool

    @@ -4372,7 +4430,7 @@ is still in its lobby selecting a team/etc. then a

    Methods:

    -
    assign_input_call(), get_account_id(), get_icon(), get_input_device(), get_name(), remove_from_game(), reset_input(), set_name()
    +
    assign_input_call(), exists(), get_account_id(), get_icon(), get_input_device(), get_name(), remove_from_game(), reset_input(), set_name()

    assign_input_call()

    assign_input_call(type: Union[str, Tuple[str, ...]], @@ -4386,6 +4444,12 @@ Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', 'startRelease'

    +
    +

    exists()

    +

    exists() -> bool

    + +

    Return whether the underlying player is still in the game.

    +

    get_account_id()

    get_account_id() -> str

    @@ -5622,6 +5686,23 @@ the background and just looks pretty; it does not affect gameplay. Note that the actual amount emitted may vary depending on graphics settings, exiting element counts, or other factors.

    +
    +

    ba.existing()

    +

    existing(obj: Optional[ExistableType]) -> Optional[ExistableType]

    + +

    Convert invalid references to None.

    + +

    Category: Gameplay Functions

    + +

    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 dead +objects into functions expecting only live ones, etc. +This call can be used on any 'existable' object (one with an exists() +method) and will convert it to a None value if it does not exist. +For more info, see notes on 'existables' here: +https://github.com/efroemling/ballistica/wiki/Coding-Style-Guide

    +

    ba.get_collision_info()

    get_collision_info(*args: Any) -> Any

    From 53cd32bb46aaa58942aa0e6cf2ae33e1e4cd6c54 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 20 May 2020 19:03:38 -0700 Subject: [PATCH 027/417] Syncing latest changes between public/private. --- docs/ba_module.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ba_module.md b/docs/ba_module.md index 7a27b536..f0de70cc 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-20 for Ballistica version 1.5.0 build 20024

    +

    last updated on 2020-05-20 for Ballistica version 1.5.0 build 20025

    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!


    From 06600d9eeba05c85c785f8fca679267f3eba7fc6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 20 May 2020 19:14:50 -0700 Subject: [PATCH 028/417] Tidying --- assets/src/ba_data/python/ba/_messages.py | 16 ++++++++-------- docs/ba_module.md | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/assets/src/ba_data/python/ba/_messages.py b/assets/src/ba_data/python/ba/_messages.py index ed309833..e97a561a 100644 --- a/assets/src/ba_data/python/ba/_messages.py +++ b/assets/src/ba_data/python/ba/_messages.py @@ -92,14 +92,14 @@ PlayerType = TypeVar('PlayerType', bound='ba.Player') class PlayerDiedMessage: - """A message saying a ba.PlayerSpaz has died. + """A message saying a ba.Player has died. category: Message Classes Attributes: killed - If True, the spaz was killed; + If True, the player was killed; If False, they left the game or the round ended. how @@ -132,10 +132,10 @@ class PlayerDiedMessage: return self._killerplayer def getplayer(self, playertype: Type[PlayerType]) -> PlayerType: - """Return the spaz that died. + """Return the ba.Player that died. - The current activity is required as an argument so the exact type of - PlayerSpaz can be determined by the type checker. + The type of player for the current activity should be passed so that + the type-checker properly identifies the returned value as one. """ player: Any = self._player assert isinstance(player, playertype) @@ -313,10 +313,10 @@ class HitMessage: def get_source_player( self, playertype: Type[PlayerType]) -> Optional[PlayerType]: - """Return the spaz that died. + """Return the source-player if there is one and they still exist. - The current activity is required as an argument so the exact type of - PlayerSpaz can be determined by the type checker. + The type of player for the current activity should be passed so that + the type-checker properly identifies the returned value as one. """ player: Any = self._source_player assert isinstance(player, (playertype, type(None))) diff --git a/docs/ba_module.md b/docs/ba_module.md index f0de70cc..dc9024c2 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -2466,10 +2466,10 @@ and short description of the game.

    get_source_player()

    get_source_player(self, playertype: Type[PlayerType]) -> Optional[PlayerType]

    -

    Return the spaz that died.

    +

    Return the source-player if there is one and they still exist.

    -

    The current activity is required as an argument so the exact type of -PlayerSpaz can be determined by the type checker.

    +

    The type of player for the current activity should be passed so that +the type-checker properly identifies the returned value as one.

    @@ -3823,7 +3823,7 @@ is_alive() method return True. False is returned otherwise.

    ba.PlayerDiedMessage

    <top level class>

    -

    A message saying a ba.PlayerSpaz has died.

    +

    A message saying a ba.Player has died.

    Category: Message Classes

    @@ -3837,7 +3837,7 @@ is_alive() method return True. False is returned otherwise.

    killed

    bool

    -

    If True, the spaz was killed; +

    If True, the player was killed; If False, they left the game or the round ended.

    @@ -3862,10 +3862,10 @@ If False, they left the game or the round ended.

    getplayer()

    getplayer(self, playertype: Type[PlayerType]) -> PlayerType

    -

    Return the spaz that died.

    +

    Return the ba.Player that died.

    -

    The current activity is required as an argument so the exact type of -PlayerSpaz can be determined by the type checker.

    +

    The type of player for the current activity should be passed so that +the type-checker properly identifies the returned value as one.

    From 9d7085cb3171e22548362bbc5fbee352f11de4eb Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 21 May 2020 01:14:58 -0700 Subject: [PATCH 029/417] more game modernizing and bug fixes --- .efrocachemap | 24 +-- .idea/inspectionProfiles/Default.xml | 2 +- assets/src/ba_data/python/ba/_activity.py | 1 - assets/src/ba_data/python/ba/_gameutils.py | 5 - assets/src/ba_data/python/ba/_netutils.py | 1 - assets/src/ba_data/python/ba/_powerup.py | 1 - .../python/bastd/activity/multiteamscore.py | 2 - .../ba_data/python/bastd/actor/scoreboard.py | 13 +- .../src/ba_data/python/bastd/game/assault.py | 2 +- .../python/bastd/game/capturetheflag.py | 17 +- .../src/ba_data/python/bastd/game/conquest.py | 66 ++++--- .../python/bastd/game/easteregghunt.py | 27 +-- .../ba_data/python/bastd/game/elimination.py | 6 + .../src/ba_data/python/bastd/game/football.py | 58 +++--- assets/src/ba_data/python/bastd/game/race.py | 183 ++++++++---------- assets/src/ba_data/python/bastd/maps.py | 13 -- .../ba_data/python/bastd/ui/colorpicker.py | 1 - docs/ba_module.md | 2 +- tools/snippets | 1 - 19 files changed, 205 insertions(+), 220 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e461c85c..582089b5 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/68/37e1f6d2afd5d6a4cbbcebba2f3e", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dc/d4/f954892306c82ca4d9c74d335c15", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4d/b8/4cfc2035ec4cdeba78be2aee8aff", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/98/9edf61a1b38432213e93b9342a4e", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/43/f76e498f45bb42f2383986d3c15b", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/d6/a9dd60f83d58eb09b1b4c0771588", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/4f/9ded4658cf6e8d8d7fdf9477ae86", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/6b/56d9fa2709eb43be73c00aacb1b5", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a9/41/2e78f2f5dfa4273ce70fc5a59e0e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9e/3d/12c0ba5235b6750ec0f37726de6e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8f/9c/edea76ee92634ef9565988c9ef6e", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/35/86/2aeb9cfac9f7639676e149e1323b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/15/2016db42f7d9d0cd341b29d4cf85", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/74/7a/5361dbc0c2dae7ab52c5501fc21d", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/04/9f/20f97048d27b7eff224cc280a5c3", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/d1/c023095a1fc0f2683e6214142ea2", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/50/1b6f2eb8ec843e1cf3a96ab0e458", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d6/0a/b979206cca7a41baa8c81d8f6225", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/23/4dcfca7889611fd21ece1c39bec5", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7e/6a/093312688ce930585cf2651860b3", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/81/73/63cb8f8ce715a5156bbd3127cee1", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2c/de/9d59be806cb4a45fa50414276eb1", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f6/af/3eb4c3046770371ea72717e3442e", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5f/3b/645e268f5f3a74acd23edc46ba2f" } \ No newline at end of file diff --git a/.idea/inspectionProfiles/Default.xml b/.idea/inspectionProfiles/Default.xml index 9f30bcb5..f6b77a63 100644 --- a/.idea/inspectionProfiles/Default.xml +++ b/.idea/inspectionProfiles/Default.xml @@ -52,7 +52,7 @@ - +

    ba.ActivityNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Activity does not exist.

    Category: Exception Classes @@ -733,7 +737,7 @@ likely result in errors.


    ba.ActorNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Actor does not exist.

    Category: Exception Classes @@ -949,7 +953,7 @@ to resume.


    ba.AppConfig

    -

    inherits from: dict

    +

    Inherits from: dict

    A special dict that holds the game's persistent configuration values.

    Category: App Classes

    @@ -1063,7 +1067,7 @@ when done.


    ba.AssetPackage

    -

    inherits from: ba.DependencyComponent

    +

    Inherits from: ba.DependencyComponent

    ba.DependencyComponent representing a bundled package of game assets.

    Category: Asset Classes @@ -1465,7 +1469,7 @@ start_long_action(callback_when_done=ba.ContextC


    ba.CoopGameActivity

    -

    inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent, typing.Generic

    +

    Inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent, typing.Generic

    Base class for cooperative-mode games.

    Category: Gameplay Classes @@ -1581,7 +1585,7 @@ and it should begin its actual game logic.


    ba.CoopSession

    -

    inherits from: ba.Session

    +

    Inherits from: ba.Session

    A ba.Session which runs cooperative-mode games.

    Category: Gameplay Classes

    @@ -1669,7 +1673,7 @@ the data object is requested and when it's value is accessed.


    ba.DeathType

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    A reason for a death.

    Category: Enums @@ -1686,7 +1690,7 @@ the data object is requested and when it's value is accessed.


    ba.Dependency

    -

    inherits from: typing.Generic

    +

    Inherits from: typing.Generic

    A dependency on a DependencyComponent (with an optional config).

    Category: Dependency Classes

    @@ -1759,7 +1763,7 @@ on the dep config value. (for instance a map required by a game type)


    ba.DependencyError

    -

    inherits from: Exception, BaseException

    +

    Inherits from: Exception, BaseException

    Exception raised when one or more ba.Dependency items are missing.

    Category: Exception Classes

    @@ -1786,7 +1790,7 @@ on the dep config value. (for instance a map required by a game type)


    ba.DependencySet

    -

    inherits from: typing.Generic

    +

    Inherits from: typing.Generic

    Set of resolved dependencies and their associated data.

    Category: Dependency Classes

    @@ -1918,7 +1922,7 @@ its time with lingering corpses, sound effects, etc.


    ba.DualTeamSession

    -

    inherits from: ba.MultiTeamSession, ba.Session

    +

    Inherits from: ba.MultiTeamSession, ba.Session

    ba.Session type for teams mode games.

    Category: Gameplay Classes @@ -1935,11 +1939,28 @@ its time with lingering corpses, sound effects, etc.

    Set up playlists and launches a ba.Activity to accept joiners.

    + + +
    +

    ba.Existable

    +

    Inherits from: typing_extensions.Protocol

    +

    A Protocol for objects supporting an exists() method.

    + +

    Category: Protocols +

    + +

    Methods:

    +
    +

    exists()

    +

    exists(self) -> bool

    + +

    Whether this object exists.

    +

    ba.FreeForAllSession

    -

    inherits from: ba.MultiTeamSession, ba.Session

    +

    Inherits from: ba.MultiTeamSession, ba.Session

    ba.Session type for free-for-all mode games.

    Category: Gameplay Classes @@ -1987,7 +2008,7 @@ its time with lingering corpses, sound effects, etc.


    ba.GameActivity

    -

    inherits from: ba.Activity, ba.DependencyComponent, typing.Generic

    +

    Inherits from: ba.Activity, ba.DependencyComponent, typing.Generic

    Common base class for all game ba.Activities.

    Category: Gameplay Classes @@ -2591,7 +2612,7 @@ prefs, etc.


    ba.InputDeviceNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.InputDevice does not exist.

    Category: Exception Classes @@ -2884,7 +2905,7 @@ etc.


    ba.Map

    -

    inherits from: ba.Actor

    +

    Inherits from: ba.Actor

    A game map.

    Category: Gameplay Classes

    @@ -3240,7 +3261,7 @@ Use ba.getmodel() to instantiate one.


    ba.MultiTeamSession

    -

    inherits from: ba.Session

    +

    Inherits from: ba.Session

    Common base class for ba.DualTeamSession and ba.FreeForAllSession.

    Category: Gameplay Classes

    @@ -3404,7 +3425,7 @@ signify that the default soundtrack should be used..


    ba.MusicPlayMode

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Influences behavior when playing music.

    Category: Enums @@ -3417,7 +3438,7 @@ signify that the default soundtrack should be used..


    ba.MusicType

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Types of music available to play in-game.

    Category: Enums

    @@ -3559,7 +3580,7 @@ acting as an alternative to setting node attributes.


    ba.NodeActor

    -

    inherits from: ba.Actor

    +

    Inherits from: ba.Actor

    A simple ba.Actor type that wraps a single ba.Node.

    Category: Gameplay Classes

    @@ -3626,7 +3647,7 @@ even if myactor is set to None.


    ba.NodeNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Node does not exist.

    Category: Exception Classes @@ -3636,7 +3657,7 @@ even if myactor is set to None.

    <all methods inherited from ba.NotFoundError>


    ba.NotFoundError

    -

    inherits from: Exception, BaseException

    +

    Inherits from: Exception, BaseException

    Exception raised when a referenced object does not exist.

    Category: Exception Classes @@ -3662,7 +3683,7 @@ even if myactor is set to None.


    ba.Permission

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Permissions that can be requested from the OS.

    Category: Enums @@ -3720,7 +3741,7 @@ even if myactor is set to None.


    ba.Player

    -

    inherits from: typing.Generic

    +

    Inherits from: typing.Generic

    A player in a specific ba.Activity.

    Category: Gameplay Classes

    @@ -3879,7 +3900,7 @@ the type-checker properly identifies the returned value as one.


    ba.PlayerNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Player does not exist.

    Category: Exception Classes @@ -4097,7 +4118,7 @@ change this. Defaults to an empty string.


    ba.ScoreType

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Type of scores.

    Category: Enums @@ -4348,7 +4369,7 @@ session.set_activity(foo) and then ba.newnode


    ba.SessionNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Session does not exist.

    Category: Exception Classes @@ -4513,7 +4534,7 @@ other players.


    ba.SessionPlayerNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.SessionPlayer does not exist.

    Category: Exception Classes @@ -4586,7 +4607,7 @@ of the session.


    ba.SessionTeamNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.SessionTeam does not exist.

    Category: Exception Classes @@ -4622,7 +4643,7 @@ of the session.


    ba.SpecialChar

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Special characters the game can print.

    Category: Enums @@ -4829,7 +4850,7 @@ of the session.


    ba.Team

    -

    inherits from: typing.Generic

    +

    Inherits from: typing.Generic

    A team in a specific ba.Activity.

    Category: Gameplay Classes

    @@ -4859,7 +4880,7 @@ of the session.


    ba.TeamGameActivity

    -

    inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent, typing.Generic

    +

    Inherits from: ba.GameActivity, ba.Activity, ba.DependencyComponent, typing.Generic

    Base class for teams and free-for-all mode games.

    Category: Gameplay Classes

    @@ -5074,7 +5095,7 @@ Results for a completed ba.TeamGameActivity

    ba.TeamNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Team does not exist.

    Category: Exception Classes @@ -5110,7 +5131,7 @@ Results for a completed ba.TeamGameActivity


    ba.TimeFormat

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Specifies the format time values are provided in.

    Category: Enums @@ -5188,7 +5209,7 @@ self.t = ba.Timer(0.3, say_it, repeat=True)


    ba.TimeType

    -

    inherits from: enum.Enum

    +

    Inherits from: enum.Enum

    Specifies the type of time for various operations to target/use.

    Category: Enums

    @@ -5427,7 +5448,7 @@ widgets.


    ba.WidgetNotFoundError

    -

    inherits from: ba.NotFoundError, Exception, BaseException

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    Exception raised when an expected ba.Widget does not exist.

    Category: Exception Classes @@ -5698,7 +5719,7 @@ settings, exiting element counts, or other factors.

    ba.existing()

    existing(obj: Optional[ExistableType]) -> Optional[ExistableType]

    -

    Convert invalid references to None.

    +

    Convert invalid references to None for any ba.Existable type.

    Category: Gameplay Functions

    diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 4d921ab2..bc6a4eb7 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -374,7 +374,7 @@ def _run_pylint(projroot: Path, pylintrc: Union[Path, str], result = _apply_pylint_run_to_cache(projroot, run, dirtyfiles, allfiles, cache) if result != 0: - raise CleanError(f'Linting failed for {result} file(s).') + raise CleanError(f'Pylint failed for {result} file(s).') # Sanity check: when the linter fails we should always be failing too. # If not, it means we're probably missing something and incorrectly @@ -400,6 +400,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], # pylint: disable=too-many-statements from astroid import modutils from efrotools import get_config + from efro.error import CleanError # First off, build a map of dirtyfiles to module names # (and the corresponding reverse map). @@ -456,8 +457,8 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], untracked_deps = set(dep for dep in untracked_deps if dep not in ignored_untracked_deps) if untracked_deps: - raise Exception( - f'Found untracked dependencies: {untracked_deps}.' + raise CleanError( + f'Pylint found untracked dependencies: {untracked_deps}.' ' If these are external to your project, add them to' ' "pylint_ignored_untracked_deps" in the project config.') @@ -552,7 +553,7 @@ def mypy(projroot: Path, full: bool) -> None: try: runmypy(projroot, filenames, full) except Exception: - raise CleanError('Mypy: fail.') + raise CleanError('Mypy failed.') duration = time.time() - starttime print(f'{Clr.GRN}Mypy passed in {duration:.1f} seconds.{Clr.RST}', flush=True) diff --git a/tools/efrotools/snippets.py b/tools/efrotools/snippets.py index d2f206ba..12e07cea 100644 --- a/tools/efrotools/snippets.py +++ b/tools/efrotools/snippets.py @@ -248,33 +248,22 @@ def scriptfiles() -> None: def pylint() -> None: """Run pylint checks on our scripts.""" - from efro.error import CleanError import efrotools.code full = ('-full' in sys.argv) fast = ('-fast' in sys.argv) - try: - efrotools.code.pylint(PROJROOT, full, fast) - except Exception: - raise CleanError('Pylint failed.') + efrotools.code.pylint(PROJROOT, full, fast) def runpylint() -> None: """Run pylint checks on provided filenames.""" - import os from efro.terminal import Clr from efro.error import CleanError import efrotools.code if len(sys.argv) < 3: raise CleanError('Expected at least 1 filename arg.') filenames = sys.argv[2:] - try: - efrotools.code.runpylint(PROJROOT, filenames) - print(f'{Clr.GRN}Pylint Passed.{Clr.RST}') - except Exception: - if os.environ.get('VERBOSE') == '1': - import traceback - traceback.print_exc() - raise CleanError('Pylint Failed.') + efrotools.code.runpylint(PROJROOT, filenames) + print(f'{Clr.GRN}Pylint Passed.{Clr.RST}') def mypy() -> None: From d2ec793625bbeadd250332afe0a24f74f30f26c3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 22 May 2020 16:40:39 -0700 Subject: [PATCH 041/417] Update ci.yml Added typing_extensions to fix windows ci --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a0a64d4..704be58b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest + pip install pytest typing_extensions - name: Run tests run: python tools/snippets pytest -v tests From 374ce7ee116c7037f221cd47b62b12068c2f8e6a Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 22 May 2020 17:27:30 -0700 Subject: [PATCH 042/417] url fixes --- assets/src/ba_data/python/ba/_general.py | 2 +- assets/src/ba_data/python/ba/_meta.py | 2 +- assets/src/ba_data/python/bastd/game/assault.py | 2 +- assets/src/ba_data/python/bastd/game/capturetheflag.py | 2 +- assets/src/ba_data/python/bastd/game/chosenone.py | 3 ++- assets/src/ba_data/python/bastd/game/conquest.py | 2 +- assets/src/ba_data/python/bastd/game/deathmatch.py | 3 ++- assets/src/ba_data/python/bastd/game/easteregghunt.py | 2 +- assets/src/ba_data/python/bastd/game/elimination.py | 2 +- assets/src/ba_data/python/bastd/game/football.py | 2 +- assets/src/ba_data/python/bastd/game/hockey.py | 2 +- assets/src/ba_data/python/bastd/game/keepaway.py | 2 +- assets/src/ba_data/python/bastd/game/kingofthehill.py | 2 +- assets/src/ba_data/python/bastd/game/meteorshower.py | 2 +- assets/src/ba_data/python/bastd/game/ninjafight.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 2 +- assets/src/ba_data/python/bastd/game/targetpractice.py | 2 +- docs/ba_module.md | 2 +- tools/update_project | 2 +- 19 files changed, 21 insertions(+), 19 deletions(-) diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 159c6561..46f6be9b 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -60,7 +60,7 @@ def existing(obj: Optional[ExistableType]) -> Optional[ExistableType]: This call can be used on any 'existable' object (one with an exists() method) and will convert it to a None value if it does not exist. For more info, see notes on 'existables' here: - https://github.com/efroemling/ballistica/wiki/Coding-Style-Guide + https://ballistica.net/wiki/Coding-Style-Guide """ assert obj is None or hasattr(obj, 'exists'), f'No "exists" on {obj}' return obj if obj is not None and obj.exists() else None diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index ff499419..e25de5bb 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -37,7 +37,7 @@ if TYPE_CHECKING: # The meta api version of this build of the game. # Only packages and modules requiring this exact api version # will be considered when scanning directories. -# See: https://github.com/efroemling/ballistica/wiki/Meta-Tags +# See: https://ballistica.net/wiki/Meta-Tags CURRENT_API_VERSION = 6 diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 9f532b4e..62c30758 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -21,7 +21,7 @@ """Defines assault minigame.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 84dc7276..f8240bab 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -21,7 +21,7 @@ """Defines a capture-the-flag game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 212f57d5..085d146b 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -21,7 +21,8 @@ """Provides the chosen-one mini-game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 7c76c8e3..bdf439a8 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -21,7 +21,7 @@ """Provides the Conquest game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 03e48d08..cccac016 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -21,7 +21,8 @@ """DeathMatch game and support classes.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 48f29b64..af902c42 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -21,7 +21,7 @@ """Provides an easter egg hunt game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index cf8eb951..56fd6843 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -21,7 +21,7 @@ """Elimination mini-game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 7e9dbca5..b3a3eb16 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -21,7 +21,7 @@ """Implements football games (both co-op and teams varieties).""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index da8386fb..e36748b7 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -21,7 +21,7 @@ """Hockey game and support classes.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 9e924b20..15fbfc24 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -21,7 +21,7 @@ """Defines a keep-away game type.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index a20a721a..de9192ad 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -21,7 +21,7 @@ """Defines the King of the Hill game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index fac0f292..ac269515 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -21,7 +21,7 @@ """Defines a bomb-dodging mini-game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 52503bd9..ba9c964b 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -21,7 +21,7 @@ """Provides Ninja Fight mini-game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 2036da7d..14b875ec 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -21,7 +21,7 @@ """Defines Race mini-game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 33972629..4a4efaaf 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -21,7 +21,7 @@ """Implements Target Practice game.""" # ba_meta require api 6 -# (see https://github.com/efroemling/ballistica/wiki/Meta-Tags) +# (see https://ballistica.net/wiki/meta-tag-system) from __future__ import annotations diff --git a/docs/ba_module.md b/docs/ba_module.md index 2e8fdb04..ff8aa38f 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -5730,7 +5730,7 @@ objects into functions expecting only live ones, etc. This call can be used on any 'existable' object (one with an exists() method) and will convert it to a None value if it does not exist. For more info, see notes on 'existables' here: -https://github.com/efroemling/ballistica/wiki/Coding-Style-Guide

    +https://ballistica.net/wiki/Coding-Style-Guide


    ba.get_collision_info()

    diff --git a/tools/update_project b/tools/update_project index 72e82c7f..897d9942 100755 --- a/tools/update_project +++ b/tools/update_project @@ -223,7 +223,7 @@ class App: print(f'{Clr.RED}NOTE: You can disable copyright' f' checks by adding "copyright_checks": false\n' f'to the root dict in config/localconfig.json.\n' - f'see https://github.com/efroemling/ballistica/wiki' + f'see https://ballistica.net/wiki' f'/Knowledge-Nuggets#' f'hello-world-creating-a-new-game-type{Clr.RST}') sys.exit(-1) From e6755d9be881b57699a22deaa74f532063eceff5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 23 May 2020 12:07:00 -0700 Subject: [PATCH 043/417] Tidying --- assets/src/ba_data/python/ba/_gameactivity.py | 2 +- assets/src/ba_data/python/ba/_teamgame.py | 2 +- .../ba_data/python/bastd/actor/playerspaz.py | 68 ++-- .../src/ba_data/python/bastd/game/assault.py | 4 +- .../python/bastd/game/capturetheflag.py | 8 +- .../ba_data/python/bastd/game/chosenone.py | 4 +- .../src/ba_data/python/bastd/game/conquest.py | 2 +- .../ba_data/python/bastd/game/deathmatch.py | 2 +- .../python/bastd/game/easteregghunt.py | 3 +- .../ba_data/python/bastd/game/elimination.py | 2 +- .../src/ba_data/python/bastd/game/hockey.py | 6 +- .../src/ba_data/python/bastd/game/keepaway.py | 2 +- .../python/bastd/game/kingofthehill.py | 2 +- .../ba_data/python/bastd/game/ninjafight.py | 18 +- .../ba_data/python/bastd/game/onslaught.py | 334 +++++++++--------- assets/src/ba_data/python/bastd/game/race.py | 2 +- .../python/bastd/game/targetpractice.py | 27 +- .../ba_data/python/bastd/game/thelaststand.py | 17 +- docs/ba_module.md | 6 +- 19 files changed, 261 insertions(+), 250 deletions(-) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 02b34008..fb418c0b 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -1012,7 +1012,7 @@ class GameActivity(Activity[PlayerType, TeamType]): def spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), - angle: float = None) -> PlayerSpaz[PlayerType]: + angle: float = None) -> PlayerSpaz: """Create and wire up a ba.PlayerSpaz for the provided ba.Player.""" # pylint: disable=too-many-locals # pylint: disable=cyclic-import diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index bb149d3a..128b959b 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -110,7 +110,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): def spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, - angle: float = None) -> PlayerSpaz[PlayerType]: + angle: float = None) -> PlayerSpaz: """ Method override; spawns and wires up a standard ba.PlayerSpaz for a ba.Player. diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index ea346360..6948c98f 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -22,13 +22,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Generic, TypeVar +from typing import TYPE_CHECKING, TypeVar, overload import ba from bastd.actor.spaz import Spaz if TYPE_CHECKING: - from typing import Any, Sequence, Tuple, Optional + from typing import Any, Sequence, Tuple, Optional, Type + from typing_extensions import Literal PlayerType = TypeVar('PlayerType', bound=ba.Player) TeamType = TypeVar('TeamType', bound=ba.Team) @@ -50,7 +51,7 @@ class PlayerSpazHurtMessage: self.spaz = spaz -class PlayerSpaz(Spaz, Generic[PlayerType]): +class PlayerSpaz(Spaz): """A ba.Spaz subclass meant to be controlled by a ba.Player. category: Gameplay Classes @@ -64,7 +65,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): """ def __init__(self, - player: PlayerType, + player: ba.Player, color: Sequence[float] = (1.0, 1.0, 1.0), highlight: Sequence[float] = (0.5, 0.5, 0.5), character: str = 'Spaz', @@ -81,31 +82,51 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): source_player=player, start_invincible=True, powerups_expire=powerups_expire) - self.last_player_attacked_by: Optional[PlayerType] = None + self.last_player_attacked_by: Optional[ba.Player] = None self.last_attacked_time = 0.0 self.last_attacked_type: Optional[Tuple[str, str]] = None self.held_count = 0 - self.last_player_held_by: Optional[PlayerType] = None + self.last_player_held_by: Optional[ba.Player] = None self._player = player self._drive_player_position() - @property - def player(self) -> PlayerType: - """The ba.Player associated with this Spaz. + # @property + # def player(self, playertype: Type[PlayerType]) -> PlayerType: + # """The ba.Player associated with this Spaz. - If the player no longer exists, raises an ba.PlayerNotFoundError. - """ - if not self._player: - raise ba.PlayerNotFoundError() - return self._player + # If the player no longer exists, raises an ba.PlayerNotFoundError. + # """ + # player = self._player + # assert isinstance(player, playertype) + # if not player: + # raise ba.PlayerNotFoundError() + # return player - def getplayer(self) -> Optional[PlayerType]: + @overload + def getplayer(self, + playertype: Type[PlayerType], + doraise: Literal[False] = False) -> Optional[PlayerType]: + ... + + @overload + def getplayer(self, playertype: Type[PlayerType], + doraise: Literal[True]) -> PlayerType: + ... + + def getplayer(self, + playertype: Type[PlayerType], + doraise: bool = False) -> Optional[PlayerType]: """Get the ba.Player associated with this Spaz. - Note that this may return None if the player has left. + By default this will return None if the Player no longer exists. + If you are logically certain that the Player still exists, pass + doraise=False to get a non-optional return type. """ - # Return None in the case of a no-longer-valid reference. - return self._player if self._player else None + player: Any = self._player + assert isinstance(player, playertype) + if not player.exists() and doraise: + raise ba.PlayerNotFoundError() + return player if player.exists() else None def connect_controls_to_player(self, enable_jump: bool = True, @@ -120,7 +141,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): but can be selectively limited by passing False to specific arguments. """ - player = self.getplayer() + player = self.getplayer(ba.Player) assert player # Reset any currently connected player and/or the player we're @@ -232,6 +253,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): activity = self._activity() + player = self.getplayer(ba.Player, doraise=False) if not killed: killerplayer = None else: @@ -254,7 +276,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): # ok, call it a suicide unless we're in co-op if (activity is not None and not isinstance( activity.session, ba.CoopSession)): - killerplayer = self.getplayer() + killerplayer = player else: killerplayer = None @@ -263,9 +285,9 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): assert killerplayer is None or killerplayer # Only report if both the player and the activity still exist. - if killed and activity is not None and self.getplayer(): + if killed and activity is not None and player: activity.handlemessage( - ba.PlayerDiedMessage(self.player, killed, killerplayer, + ba.PlayerDiedMessage(player, killed, killerplayer, msg.how)) super().handlemessage(msg) # Augment standard behavior. @@ -279,7 +301,7 @@ class PlayerSpaz(Spaz, Generic[PlayerType]): self.last_attacked_type = (msg.hit_type, msg.hit_subtype) super().handlemessage(msg) # Augment standard behavior. activity = self._activity() - if activity is not None: + if activity is not None and self._player.exists(): activity.handlemessage(PlayerSpazHurtMessage(self)) else: super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 62c30758..6b402b88 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -187,12 +187,10 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): if not isinstance(actor, PlayerSpaz): return - player = actor.getplayer() + player = actor.getplayer(Player) if not player or not player.actor: return - assert isinstance(player, Player) - # If its another team's player, they scored. player_team = player.team if player_team is not team: diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index f8240bab..e897797a 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -170,7 +170,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self._time_limit = float(settings['Time Limit']) self.flag_touch_return_time = float(settings['Flag Touch Return Time']) - self.flag_idle_return_time = float(settings['Flag Idle return Time']) + self.flag_idle_return_time = float(settings['Flag Idle Return Time']) # Base class overrides self.slow_motion = self._epic_mode @@ -448,7 +448,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): delegate = node.getdelegate() if not isinstance(delegate, PlayerSpaz): return None - return delegate.getplayer() + return delegate.getplayer(Player) def _handle_hit_own_flag(self, team: Team, val: int) -> None: """ @@ -508,10 +508,10 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def spawn_player_spaz(self, player: Player, position: Sequence[float] = None, - angle: float = None) -> PlayerSpaz[Player]: + angle: float = None) -> PlayerSpaz: """Intercept new spazzes and add our team material for them.""" spaz = super().spawn_player_spaz(player, position, angle) - player = spaz.player + player = spaz.getplayer(Player, doraise=True) team: Team = player.team player.touching_own_flag = 0 no_physical_mats: List[ba.Material] = [ diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 085d146b..bc1e2394 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -30,6 +30,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence, Union @@ -94,7 +95,6 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('keep_away') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._chosen_one_player: Optional[Player] = None @@ -179,7 +179,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): return delegate = ba.get_collision_info('opposing_node').getdelegate() if isinstance(delegate, PlayerSpaz): - player = ba.playercast_o(Player, delegate.getplayer()) + player = delegate.getplayer(Player) if player is not None and player.is_alive(): self._set_chosen_one_player(player) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index bdf439a8..0f301525 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -30,6 +30,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Optional, Type, List, Dict, Sequence, Union @@ -116,7 +117,6 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('conquest') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._score_sound = ba.getsound('score') diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index cccac016..2c2395d6 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -29,6 +29,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Type, List, Dict, Tuple, Union, Sequence, Optional @@ -101,7 +102,6 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('melee') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._score_to_win: Optional[int] = None diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index af902c42..e8b21055 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -142,8 +142,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): assert isinstance(egg, Egg) spaz = playernode.getdelegate() assert isinstance(spaz, PlayerSpaz) - player = (spaz.getplayer() - if hasattr(spaz, 'getplayer') else None) + player = spaz.getplayer(Player) if player and egg: player.team.score += 1 diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 56fd6843..3bebe0d2 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -29,6 +29,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.spaz import get_factory +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import (Any, Tuple, Dict, Type, List, Sequence, Optional, @@ -237,7 +238,6 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('melee') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index e36748b7..5cf8c564 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -28,13 +28,15 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba +from bastd.actor.scoreboard import Scoreboard +from bastd.actor import powerupbox if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union class PuckDeathMessage: - """Inform an object that a puck has died.""" + """Inform something that a puck has died.""" def __init__(self, puck: Puck): self.puck = puck @@ -145,8 +147,6 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('hockey') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard - from bastd.actor import powerupbox super().__init__(settings) self._scoreboard = Scoreboard() self._cheer_sound = ba.getsound('cheer') diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 15fbfc24..31e9a407 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -30,6 +30,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDeathMessage, FlagPickedUpMessage) @@ -89,7 +90,6 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('keep_away') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._swipsound = ba.getsound('swip') diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index de9192ad..4aea7d06 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -250,7 +250,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): delegate = ba.get_collision_info('opposing_node').getdelegate() if not isinstance(delegate, PlayerSpaz): return - player = ba.playercast_o(Player, delegate.getplayer()) + player = delegate.getplayer(Player) if not player: return diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index ba9c964b..8176178f 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -29,7 +29,7 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import spazbot +from bastd.actor.spazbot import BotSet, ChargerBot, SpazBotDeathMessage from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: @@ -76,7 +76,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self._winsound = ba.getsound('score') self._won = False self._timer: Optional[OnScreenTimer] = None - self._bots = spazbot.BotSet() + self._bots = BotSet() # Called when our game is transitioning in but not ready to begin; # we can go ahead and start creating stuff, playing music, etc. @@ -100,27 +100,27 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): # Spawn some baddies. ba.timer( 1.0, lambda: self._bots.spawn_bot( - spazbot.ChargerBot, pos=(3, 3, -2), spawn_time=3.0)) + ChargerBot, pos=(3, 3, -2), spawn_time=3.0)) ba.timer( 2.0, lambda: self._bots.spawn_bot( - spazbot.ChargerBot, pos=(-3, 3, -2), spawn_time=3.0)) + ChargerBot, pos=(-3, 3, -2), spawn_time=3.0)) ba.timer( 3.0, lambda: self._bots.spawn_bot( - spazbot.ChargerBot, pos=(5, 3, -2), spawn_time=3.0)) + ChargerBot, pos=(5, 3, -2), spawn_time=3.0)) ba.timer( 4.0, lambda: self._bots.spawn_bot( - spazbot.ChargerBot, pos=(-5, 3, -2), spawn_time=3.0)) + ChargerBot, pos=(-5, 3, -2), spawn_time=3.0)) # Add some extras for multiplayer or pro mode. assert self.initial_player_info is not None if len(self.initial_player_info) > 2 or is_pro: ba.timer( 5.0, lambda: self._bots.spawn_bot( - spazbot.ChargerBot, pos=(0, 3, -5), spawn_time=3.0)) + ChargerBot, pos=(0, 3, -5), spawn_time=3.0)) if len(self.initial_player_info) > 3 or is_pro: ba.timer( 6.0, lambda: self._bots.spawn_bot( - spazbot.ChargerBot, pos=(0, 3, 1), spawn_time=3.0)) + ChargerBot, pos=(0, 3, 1), spawn_time=3.0)) # Called for each spawning player. def spawn_player(self, player: Player) -> ba.Actor: @@ -150,7 +150,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self.respawn_player(msg.getplayer(Player)) # A spaz-bot has died. - elif isinstance(msg, spazbot.SpazBotDeathMessage): + elif isinstance(msg, SpazBotDeathMessage): # Unfortunately the bot-set will always tell us there are living # bots if we ask here (the currently-dying bot isn't officially # marked dead yet) ..so lets push a call into the event loop to diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 8f58c609..e48c74fe 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -30,17 +30,28 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import bomb as stdbomb -from bastd.actor import playerspaz, spazbot +from bastd.actor.bomb import TNTSpawner +from bastd.actor.playerspaz import PlayerSpazHurtMessage +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.spazbot import ( + SpazBotDeathMessage, BotSet, ChargerBot, StickyBot, BomberBot, + BomberBotLite, BrawlerBot, BrawlerBotLite, TriggerBot, BomberBotStaticLite, + TriggerBotStatic, BomberBotProStatic, TriggerBotPro, ExplodeyBot, + BrawlerBotProShielded, ChargerBotProShielded, BomberBotPro, + TriggerBotProShielded, BrawlerBotPro, BomberBotProShielded) if TYPE_CHECKING: from typing import Any, Type, Dict, Optional, List, Tuple, Union, Sequence - from bastd.actor.scoreboard import Scoreboard + from bastd.actor.spazbot import SpazBot class Player(ba.Player['Team']): """Our player type for this game.""" + def __init__(self) -> None: + self.has_been_hurt = False + self.respawn_wave = 0 + class Team(ba.Team[Player]): """Our team type for this game.""" @@ -114,8 +125,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._have_tnt = False self._excludepowerups: Optional[List[str]] = None self._waves: Optional[List[Dict[str, Any]]] = None - self._tntspawner: Optional[stdbomb.TNTSpawner] = None - self._bots: Optional[spazbot.BotSet] = None + self._tntspawner: Optional[TNTSpawner] = None + self._bots: Optional[BotSet] = None self._powerup_drop_timer: Optional[ba.Timer] = None self._time_bonus_timer: Optional[ba.Timer] = None self._time_bonus_text: Optional[ba.NodeActor] = None @@ -127,17 +138,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._tnt_kills = 0 def on_transition_in(self) -> None: - from bastd.actor.scoreboard import Scoreboard super().on_transition_in() - + session = ba.getsession() # Show special landmine tip on rookie preset. if self._preset in ['rookie', 'rookie_easy']: # Show once per session only (then we revert to regular tips). - if not hasattr(ba.getsession(), - '_g_showed_onslaught_land_mine_tip'): - # pylint: disable=protected-access - ba.getsession( # type: ignore - )._g_showed_onslaught_land_mine_tip = True + if not getattr(session, '_g_showed_onslaught_landmine_tip', False): + setattr(session, '_g_showed_onslaught_landmine_tip', True) self.tips = [{ 'tip': 'Land-mines are a good way' ' to stop speedy enemies.', @@ -148,10 +155,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # Show special tnt tip on pro preset. if self._preset in ['pro', 'pro_easy']: # Show once per session only (then we revert to regular tips). - if not hasattr(ba.getsession(), '_g_showed_onslaught_tnt_tip'): - # pylint: disable=protected-access - ba.getsession( # type: ignore - )._g_showed_onslaught_tnt_tip = True + if not getattr(session, '_g_showed_onslaught_tnt_tip', False): + setattr(session, '_g_showed_onslaught_tnt_tip', True) self.tips = [{ 'tip': 'Take out a group of enemies by\n' 'setting off a bomb near a TNT box.', @@ -162,10 +167,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # Show special curse tip on uber preset. if self._preset in ['uber', 'uber_easy']: # Show once per session only (then we revert to regular tips). - if not hasattr(ba.getsession(), '_g_showed_onslaught_curse_tip'): - # pylint: disable=protected-access - ba.getsession( # type: ignore - )._g_showed_onslaught_curse_tip = True + if not getattr(session, '_g_showed_onslaught_curse_tip', False): + setattr(session, '_g_showed_onslaught_curse_tip', True) self.tips = [{ 'tip': 'Curse boxes turn you into a ticking time bomb.\n' 'The only cure is to quickly grab a health-pack.', @@ -203,38 +206,38 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._waves = [ {'base_angle': 195, 'entries': [ - {'type': spazbot.BomberBotLite, 'spacing': 5}, + {'type': BomberBotLite, 'spacing': 5}, ] * player_count}, {'base_angle': 130, 'entries': [ - {'type': spazbot.BrawlerBotLite, 'spacing': 5}, + {'type': BrawlerBotLite, 'spacing': 5}, ] * player_count}, {'base_angle': 195, 'entries': [ - {'type': spazbot.BomberBotLite, 'spacing': 10}, + {'type': BomberBotLite, 'spacing': 10}, ] * (player_count + 1)}, {'base_angle': 130, 'entries': [ - {'type': spazbot.BrawlerBotLite, 'spacing': 10}, + {'type': BrawlerBotLite, 'spacing': 10}, ] * (player_count + 1)}, {'base_angle': 130, 'entries': [ - {'type': spazbot.BrawlerBotLite, 'spacing': 5} + {'type': BrawlerBotLite, 'spacing': 5} if player_count > 1 else None, - {'type': spazbot.BrawlerBotLite, 'spacing': 5}, + {'type': BrawlerBotLite, 'spacing': 5}, {'type': None, 'spacing': 30}, - {'type': spazbot.BomberBotLite, 'spacing': 5} + {'type': BomberBotLite, 'spacing': 5} if player_count > 3 else None, - {'type': spazbot.BomberBotLite, 'spacing': 5}, + {'type': BomberBotLite, 'spacing': 5}, {'type': None, 'spacing': 30}, - {'type': spazbot.BrawlerBotLite, 'spacing': 5}, - {'type': spazbot.BrawlerBotLite, 'spacing': 5} + {'type': BrawlerBotLite, 'spacing': 5}, + {'type': BrawlerBotLite, 'spacing': 5} if player_count > 2 else None, ]}, {'base_angle': 195, 'entries': [ - {'type': spazbot.TriggerBot, 'spacing': 90}, - {'type': spazbot.TriggerBot, 'spacing': 90} + {'type': TriggerBot, 'spacing': 90}, + {'type': TriggerBot, 'spacing': 90} if player_count > 1 else None, ]}, ] # yapf: disable @@ -244,60 +247,60 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._excludepowerups = ['curse'] self._waves = [ {'entries': [ - {'type': spazbot.ChargerBot, 'point': 'left_upper_more'} + {'type': ChargerBot, 'point': 'left_upper_more'} if player_count > 2 else None, - {'type': spazbot.ChargerBot, 'point': 'left_upper'}, + {'type': ChargerBot, 'point': 'left_upper'}, ]}, {'entries': [ - {'type': spazbot.BomberBotStaticLite, + {'type': BomberBotStaticLite, 'point': 'turret_top_right'}, - {'type': spazbot.BrawlerBotLite, 'point': 'right_upper'}, - {'type': spazbot.BrawlerBotLite, 'point': 'right_lower'} + {'type': BrawlerBotLite, 'point': 'right_upper'}, + {'type': BrawlerBotLite, 'point': 'right_lower'} if player_count > 1 else None, - {'type': spazbot.BomberBotStaticLite, + {'type': BomberBotStaticLite, 'point': 'turret_bottom_right'} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.BomberBotStaticLite, + {'type': BomberBotStaticLite, 'point': 'turret_bottom_left'}, - {'type': spazbot.TriggerBot, 'point': 'left'}, - {'type': spazbot.TriggerBot, 'point': 'left_lower'} + {'type': TriggerBot, 'point': 'left'}, + {'type': TriggerBot, 'point': 'left_lower'} if player_count > 1 else None, - {'type': spazbot.TriggerBot, 'point': 'left_upper'} + {'type': TriggerBot, 'point': 'left_upper'} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.BrawlerBotLite, 'point': 'top_right'}, - {'type': spazbot.BrawlerBot, 'point': 'top_half_right'} + {'type': BrawlerBotLite, 'point': 'top_right'}, + {'type': BrawlerBot, 'point': 'top_half_right'} if player_count > 1 else None, - {'type': spazbot.BrawlerBotLite, 'point': 'top_left'}, - {'type': spazbot.BrawlerBotLite, 'point': 'top_half_left'} + {'type': BrawlerBotLite, 'point': 'top_left'}, + {'type': BrawlerBotLite, 'point': 'top_half_left'} if player_count > 2 else None, - {'type': spazbot.BrawlerBot, 'point': 'top'}, - {'type': spazbot.BomberBotStaticLite, + {'type': BrawlerBot, 'point': 'top'}, + {'type': BomberBotStaticLite, 'point': 'turret_top_middle'}, ]}, {'entries': [ - {'type': spazbot.TriggerBotStatic, + {'type': TriggerBotStatic, 'point': 'turret_bottom_left'}, - {'type': spazbot.TriggerBotStatic, + {'type': TriggerBotStatic, 'point': 'turret_bottom_right'}, - {'type': spazbot.TriggerBot, 'point': 'bottom'}, - {'type': spazbot.TriggerBot, 'point': 'bottom_half_right'} + {'type': TriggerBot, 'point': 'bottom'}, + {'type': TriggerBot, 'point': 'bottom_half_right'} if player_count > 1 else None, - {'type': spazbot.TriggerBot, 'point': 'bottom_half_left'} + {'type': TriggerBot, 'point': 'bottom_half_left'} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.BomberBotStaticLite, + {'type': BomberBotStaticLite, 'point': 'turret_top_left'}, - {'type': spazbot.BomberBotStaticLite, + {'type': BomberBotStaticLite, 'point': 'turret_top_right'}, - {'type': spazbot.ChargerBot, 'point': 'bottom'}, - {'type': spazbot.ChargerBot, 'point': 'bottom_half_left'} + {'type': ChargerBot, 'point': 'bottom'}, + {'type': ChargerBot, 'point': 'bottom_half_left'} if player_count > 1 else None, - {'type': spazbot.ChargerBot, 'point': 'bottom_half_right'} + {'type': ChargerBot, 'point': 'bottom_half_right'} if player_count > 2 else None, ]}, ] # yapf: disable @@ -308,78 +311,78 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._waves = [ {'base_angle': -50, 'entries': [ - {'type': spazbot.BrawlerBot, 'spacing': 12} + {'type': BrawlerBot, 'spacing': 12} if player_count > 3 else None, - {'type': spazbot.BrawlerBot, 'spacing': 12}, - {'type': spazbot.BomberBot, 'spacing': 6}, - {'type': spazbot.BomberBot, 'spacing': 6} + {'type': BrawlerBot, 'spacing': 12}, + {'type': BomberBot, 'spacing': 6}, + {'type': BomberBot, 'spacing': 6} if self._preset == 'pro' else None, - {'type': spazbot.BomberBot, 'spacing': 6} + {'type': BomberBot, 'spacing': 6} if player_count > 1 else None, - {'type': spazbot.BrawlerBot, 'spacing': 12}, - {'type': spazbot.BrawlerBot, 'spacing': 12} + {'type': BrawlerBot, 'spacing': 12}, + {'type': BrawlerBot, 'spacing': 12} if player_count > 2 else None, ]}, {'base_angle': 180, 'entries': [ - {'type': spazbot.BrawlerBot, 'spacing': 6} + {'type': BrawlerBot, 'spacing': 6} if player_count > 3 else None, - {'type': spazbot.BrawlerBot, 'spacing': 6} + {'type': BrawlerBot, 'spacing': 6} if self._preset == 'pro' else None, - {'type': spazbot.BrawlerBot, 'spacing': 6}, - {'type': spazbot.ChargerBot, 'spacing': 45}, - {'type': spazbot.ChargerBot, 'spacing': 45} + {'type': BrawlerBot, 'spacing': 6}, + {'type': ChargerBot, 'spacing': 45}, + {'type': ChargerBot, 'spacing': 45} if player_count > 1 else None, - {'type': spazbot.BrawlerBot, 'spacing': 6}, - {'type': spazbot.BrawlerBot, 'spacing': 6} + {'type': BrawlerBot, 'spacing': 6}, + {'type': BrawlerBot, 'spacing': 6} if self._preset == 'pro' else None, - {'type': spazbot.BrawlerBot, 'spacing': 6} + {'type': BrawlerBot, 'spacing': 6} if player_count > 2 else None, ]}, {'base_angle': 0, 'entries': [ - {'type': spazbot.ChargerBot, 'spacing': 30}, - {'type': spazbot.TriggerBot, 'spacing': 30}, - {'type': spazbot.TriggerBot, 'spacing': 30}, - {'type': spazbot.TriggerBot, 'spacing': 30} + {'type': ChargerBot, 'spacing': 30}, + {'type': TriggerBot, 'spacing': 30}, + {'type': TriggerBot, 'spacing': 30}, + {'type': TriggerBot, 'spacing': 30} if self._preset == 'pro' else None, - {'type': spazbot.TriggerBot, 'spacing': 30} + {'type': TriggerBot, 'spacing': 30} if player_count > 1 else None, - {'type': spazbot.TriggerBot, 'spacing': 30} + {'type': TriggerBot, 'spacing': 30} if player_count > 3 else None, - {'type': spazbot.ChargerBot, 'spacing': 30}, + {'type': ChargerBot, 'spacing': 30}, ]}, {'base_angle': 90, 'entries': [ - {'type': spazbot.StickyBot, 'spacing': 50}, - {'type': spazbot.StickyBot, 'spacing': 50} + {'type': StickyBot, 'spacing': 50}, + {'type': StickyBot, 'spacing': 50} if self._preset == 'pro' else None, - {'type': spazbot.StickyBot, 'spacing': 50}, - {'type': spazbot.StickyBot, 'spacing': 50} + {'type': StickyBot, 'spacing': 50}, + {'type': StickyBot, 'spacing': 50} if player_count > 1 else None, - {'type': spazbot.StickyBot, 'spacing': 50} + {'type': StickyBot, 'spacing': 50} if player_count > 3 else None, ]}, {'base_angle': 0, 'entries': [ - {'type': spazbot.TriggerBot, 'spacing': 72}, - {'type': spazbot.TriggerBot, 'spacing': 72}, - {'type': spazbot.TriggerBot, 'spacing': 72} + {'type': TriggerBot, 'spacing': 72}, + {'type': TriggerBot, 'spacing': 72}, + {'type': TriggerBot, 'spacing': 72} if self._preset == 'pro' else None, - {'type': spazbot.TriggerBot, 'spacing': 72}, - {'type': spazbot.TriggerBot, 'spacing': 72}, - {'type': spazbot.TriggerBot, 'spacing': 36} + {'type': TriggerBot, 'spacing': 72}, + {'type': TriggerBot, 'spacing': 72}, + {'type': TriggerBot, 'spacing': 36} if player_count > 2 else None, ]}, {'base_angle': 30, 'entries': [ - {'type': spazbot.ChargerBotProShielded, 'spacing': 50}, - {'type': spazbot.ChargerBotProShielded, 'spacing': 50}, - {'type': spazbot.ChargerBotProShielded, 'spacing': 50} + {'type': ChargerBotProShielded, 'spacing': 50}, + {'type': ChargerBotProShielded, 'spacing': 50}, + {'type': ChargerBotProShielded, 'spacing': 50} if self._preset == 'pro' else None, - {'type': spazbot.ChargerBotProShielded, 'spacing': 50} + {'type': ChargerBotProShielded, 'spacing': 50} if player_count > 1 else None, - {'type': spazbot.ChargerBotProShielded, 'spacing': 50} + {'type': ChargerBotProShielded, 'spacing': 50} if player_count > 2 else None, ]} ] # yapf: disable @@ -395,84 +398,84 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._excludepowerups = [] self._waves = [ {'entries': [ - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_middle_left'} if hard else None, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_middle_right'}, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_left'} if player_count > 2 else None, - {'type': spazbot.ExplodeyBot, 'point': 'top_right'}, + {'type': ExplodeyBot, 'point': 'top_right'}, {'type': 'delay', 'duration': 4.0}, - {'type': spazbot.ExplodeyBot, 'point': 'top_left'}, + {'type': ExplodeyBot, 'point': 'top_left'}, ]}, {'entries': [ - {'type': spazbot.ChargerBot, 'point': 'left'}, - {'type': spazbot.ChargerBot, 'point': 'right'}, - {'type': spazbot.ChargerBot, 'point': 'right_upper_more'} + {'type': ChargerBot, 'point': 'left'}, + {'type': ChargerBot, 'point': 'right'}, + {'type': ChargerBot, 'point': 'right_upper_more'} if player_count > 2 else None, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_left'}, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_right'}, ]}, {'entries': [ - {'type': spazbot.TriggerBotPro, 'point': 'top_right'}, - {'type': spazbot.TriggerBotPro, + {'type': TriggerBotPro, 'point': 'top_right'}, + {'type': TriggerBotPro, 'point': 'right_upper_more'} if player_count > 1 else None, - {'type': spazbot.TriggerBotPro, 'point': 'right_upper'}, - {'type': spazbot.TriggerBotPro, 'point': 'right_lower'} + {'type': TriggerBotPro, 'point': 'right_upper'}, + {'type': TriggerBotPro, 'point': 'right_lower'} if hard else None, - {'type': spazbot.TriggerBotPro, + {'type': TriggerBotPro, 'point': 'right_lower_more'} if player_count > 2 else None, - {'type': spazbot.TriggerBotPro, 'point': 'bottom_right'}, + {'type': TriggerBotPro, 'point': 'bottom_right'}, ]}, {'entries': [ - {'type': spazbot.ChargerBotProShielded, + {'type': ChargerBotProShielded, 'point': 'bottom_right'}, - {'type': spazbot.ChargerBotProShielded, 'point': 'bottom'} + {'type': ChargerBotProShielded, 'point': 'bottom'} if player_count > 2 else None, - {'type': spazbot.ChargerBotProShielded, + {'type': ChargerBotProShielded, 'point': 'bottom_left'}, - {'type': spazbot.ChargerBotProShielded, 'point': 'top'} + {'type': ChargerBotProShielded, 'point': 'top'} if hard else None, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_middle'}, ]}, {'entries': [ - {'type': spazbot.ExplodeyBot, 'point': 'left_upper'}, + {'type': ExplodeyBot, 'point': 'left_upper'}, {'type': 'delay', 'duration': 1.0}, - {'type': spazbot.BrawlerBotProShielded, + {'type': BrawlerBotProShielded, 'point': 'left_lower'}, - {'type': spazbot.BrawlerBotProShielded, + {'type': BrawlerBotProShielded, 'point': 'left_lower_more'}, {'type': 'delay', 'duration': 4.0}, - {'type': spazbot.ExplodeyBot, 'point': 'right_upper'}, + {'type': ExplodeyBot, 'point': 'right_upper'}, {'type': 'delay', 'duration': 1.0}, - {'type': spazbot.BrawlerBotProShielded, + {'type': BrawlerBotProShielded, 'point': 'right_lower'}, - {'type': spazbot.BrawlerBotProShielded, + {'type': BrawlerBotProShielded, 'point': 'right_upper_more'}, {'type': 'delay', 'duration': 4.0}, - {'type': spazbot.ExplodeyBot, 'point': 'left'}, + {'type': ExplodeyBot, 'point': 'left'}, {'type': 'delay', 'duration': 5.0}, - {'type': spazbot.ExplodeyBot, 'point': 'right'}, + {'type': ExplodeyBot, 'point': 'right'}, ]}, {'entries': [ - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_left'}, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_right'}, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_bottom_left'}, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_bottom_right'}, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_middle_left'} if hard else None, - {'type': spazbot.BomberBotProStatic, + {'type': BomberBotProStatic, 'point': 'turret_top_middle_right'} if hard else None, ] }] # yapf: disable @@ -498,11 +501,11 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # Our TNT spawner (if applicable). if self._have_tnt: - self._tntspawner = stdbomb.TNTSpawner(position=self._tntspawnpos) + self._tntspawner = TNTSpawner(position=self._tntspawnpos) self.setup_low_life_warning_sound() self._update_scores() - self._bots = spazbot.BotSet() + self._bots = BotSet() ba.timer(4.0, self._start_updating_waves) def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None: @@ -852,11 +855,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): assert self._waves is not None if (not player.is_alive() and (self._preset in ['endless', 'endless_tournament'] or - (player.gamedata['respawn_wave'] <= len(self._waves)))): + (player.respawn_wave <= len(self._waves)))): rtxt = ba.Lstr(resource='onslaughtRespawnText', subs=[('${PLAYER}', player.get_name()), - ('${WAVE}', - str(player.gamedata['respawn_wave'])) + ('${WAVE}', str(player.respawn_wave)) ]) text = ba.Lstr(value='${A}${B}\n', subs=[ @@ -881,7 +883,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if self._wave > 1 and not self.is_waiting_for_continue(): for player in self.players: if (not player.is_alive() - and player.gamedata['respawn_wave'] == self._wave): + and player.respawn_wave == self._wave): self.spawn_player(player) self._update_player_spawn_info() self.show_zoom_message(ba.Lstr(value='${A} ${B}', @@ -907,40 +909,34 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if self._preset in ['endless', 'endless_tournament']: level = self._wave bot_types2 = [ - spazbot.BomberBot, spazbot.BrawlerBot, spazbot.TriggerBot, - spazbot.ChargerBot, spazbot.BomberBotPro, - spazbot.BrawlerBotPro, spazbot.TriggerBotPro, - spazbot.BomberBotProShielded, spazbot.ExplodeyBot, - spazbot.ChargerBotProShielded, spazbot.StickyBot, - spazbot.BrawlerBotProShielded, spazbot.TriggerBotProShielded + BomberBot, BrawlerBot, TriggerBot, ChargerBot, BomberBotPro, + BrawlerBotPro, TriggerBotPro, BomberBotProShielded, + ExplodeyBot, ChargerBotProShielded, StickyBot, + BrawlerBotProShielded, TriggerBotProShielded ] if level > 5: bot_types2 += [ - spazbot.ExplodeyBot, - spazbot.TriggerBotProShielded, - spazbot.BrawlerBotProShielded, - spazbot.ChargerBotProShielded, + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, ] if level > 7: bot_types2 += [ - spazbot.ExplodeyBot, - spazbot.TriggerBotProShielded, - spazbot.BrawlerBotProShielded, - spazbot.ChargerBotProShielded, + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, ] if level > 10: bot_types2 += [ - spazbot.TriggerBotProShielded, - spazbot.TriggerBotProShielded, - spazbot.TriggerBotProShielded, - spazbot.TriggerBotProShielded + TriggerBotProShielded, TriggerBotProShielded, + TriggerBotProShielded, TriggerBotProShielded ] if level > 13: bot_types2 += [ - spazbot.TriggerBotProShielded, - spazbot.TriggerBotProShielded, - spazbot.TriggerBotProShielded, - spazbot.TriggerBotProShielded + TriggerBotProShielded, TriggerBotProShielded, + TriggerBotProShielded, TriggerBotProShielded ] bot_levels = [[b for b in bot_types2 if b.points_mult == 1], @@ -1096,7 +1092,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def add_bot_at_point(self, point: str, - spaz_type: Type[spazbot.SpazBot], + spaz_type: Type[SpazBot], spawn_time: float = 1.0) -> None: """Add a new bot at a specified named point.""" if self._game_over: @@ -1107,7 +1103,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def add_bot_at_angle(self, angle: float, - spaz_type: Type[spazbot.SpazBot], + spaz_type: Type[SpazBot], spawn_time: float = 1.0) -> None: """Add a new bot at a specified angle (for circular maps).""" if self._game_over: @@ -1153,11 +1149,9 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # pylint: disable=too-many-statements # pylint: disable=too-many-branches - if isinstance(msg, playerspaz.PlayerSpazHurtMessage): - player = msg.spaz.getplayer() - if not player: - return - player.gamedata['has_been_hurt'] = True + if isinstance(msg, PlayerSpazHurtMessage): + player = msg.spaz.getplayer(Player, doraise=True) + player.has_been_hurt = True self._a_player_has_been_hurt = True elif isinstance(msg, ba.PlayerScoredMessage): @@ -1171,15 +1165,15 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # Make note with the player when they can respawn: if self._wave < 10: - player.gamedata['respawn_wave'] = max(2, self._wave + 1) + player.respawn_wave = max(2, self._wave + 1) elif self._wave < 15: - player.gamedata['respawn_wave'] = max(2, self._wave + 2) + player.respawn_wave = max(2, self._wave + 2) else: - player.gamedata['respawn_wave'] = max(2, self._wave + 3) + player.respawn_wave = max(2, self._wave + 3) ba.timer(0.1, self._update_player_spawn_info) ba.timer(0.1, self._checkroundover) - elif isinstance(msg, spazbot.SpazBotDeathMessage): + elif isinstance(msg, SpazBotDeathMessage): pts, importance = msg.badguy.get_death_points(msg.how) if msg.killerplayer is not None: diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 14b875ec..05bc93f0 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -32,6 +32,7 @@ from dataclasses import dataclass import ba from bastd.actor.bomb import Bomb from bastd.actor.playerspaz import PlayerSpaz +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, @@ -143,7 +144,6 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): return ba.getmaps('race') def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard self._race_started = False super().__init__(settings) self._scoreboard = Scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 4a4efaaf..c842750e 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -29,11 +29,14 @@ import random from typing import TYPE_CHECKING import ba +from bastd.actor.scoreboard import Scoreboard +from bastd.actor.onscreencountdown import OnScreenCountdown +from bastd.actor.bomb import Bomb +from bastd.actor.popuptext import PopupText if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence - from bastd.actor.onscreencountdown import OnScreenCountdown - from bastd.actor.bomb import Bomb, Blast + from bastd.actor.bomb import Blast class Player(ba.Player['Team']): @@ -80,7 +83,6 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): or issubclass(sessiontype, ba.MultiTeamSession)) def __init__(self, settings: Dict[str, Any]): - from bastd.actor.scoreboard import Scoreboard super().__init__(settings) self._scoreboard = Scoreboard() self._targets: List[Target] = [] @@ -98,7 +100,6 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): self.update_scoreboard() def on_begin(self) -> None: - from bastd.actor.onscreencountdown import OnScreenCountdown super().on_begin() self.update_scoreboard() @@ -141,9 +142,9 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): ypos = random.uniform(-1.0, 1.0) if xpos * xpos + ypos * ypos < 1.0: break - points.append((8.0 * xpos, 2.2, -3.5 + 5.0 * ypos)) + points.append(ba.Vec3(8.0 * xpos, 2.2, -3.5 + 5.0 * ypos)) - def get_min_dist_from_target(pnt: Sequence[float]) -> float: + def get_min_dist_from_target(pnt: ba.Vec3) -> float: return min((t.get_dist_from_point(pnt) for t in self._targets)) # If we have existing targets, use the point with the highest @@ -157,7 +158,6 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): def _on_spaz_dropped_bomb(self, spaz: ba.Actor, bomb: ba.Actor) -> None: del spaz # Unused. - from bastd.actor.bomb import Bomb # Wire up this bomb to inform us when it blows up. assert isinstance(bomb, Bomb) @@ -281,14 +281,13 @@ class Target(ba.Actor): else: super().handlemessage(msg) - def get_dist_from_point(self, pos: Sequence[float]) -> float: + def get_dist_from_point(self, pos: ba.Vec3) -> float: """Given a point, returns distance squared from it.""" - return (ba.Vec3(pos) - self._position).length() + return (pos - self._position).length() def do_hit_at_position(self, pos: Sequence[float], player: Player) -> bool: """Handle a bomb hit at the given position.""" # pylint: disable=too-many-statements - from bastd.actor import popuptext activity = self.activity # Ignore hits if the game is over or if we've already been hit @@ -357,10 +356,10 @@ class Target(ba.Actor): if len(activity.players) > 1: popupcolor = ba.safecolor(player.color, target_intensity=0.75) popupstr += ' ' + player.get_name() - popuptext.PopupText(popupstr, - position=self._position, - color=popupcolor, - scale=popupscale).autoretain() + PopupText(popupstr, + position=self._position, + color=popupcolor, + scale=popupscale).autoretain() # Give this player's team points and update the score-board. player.team.score += points diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 147bd279..e651aae7 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -26,13 +26,13 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import playerspaz from bastd.actor import spazbot +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.bomb import TNTSpawner +from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: from typing import Any, Dict, Type, List, Optional, Sequence - from bastd.actor.scoreboard import Scoreboard class Player(ba.Player['Team']): @@ -59,6 +59,8 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): # And of course the most important part. slow_motion = True + default_music = ba.MusicType.EPIC + def __init__(self, settings: Dict[str, Any]): settings['map'] = 'Rampage' super().__init__(settings) @@ -98,8 +100,6 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): } # yapf: disable def on_transition_in(self) -> None: - from bastd.actor.scoreboard import Scoreboard - self.default_music = ba.MusicType.EPIC super().on_transition_in() ba.timer(1.3, ba.Call(ba.playsound, self._new_wave_sound)) self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'), @@ -198,11 +198,11 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): for player in self.players: try: if player.is_alive(): - assert isinstance(player.actor, playerspaz.PlayerSpaz) + assert isinstance(player.actor, PlayerSpaz) assert player.actor.node playerpts.append(player.actor.node.position) - except Exception as exc: - print('ERROR in _update_bots', exc) + except Exception: + ba.print_exception('Error updating bots') for i in range(3): for playerpt in playerpts: dists[i] += abs(playerpt[0] - botspawnpts[i][0]) @@ -244,7 +244,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): spawntype[1][1] += spawntype[1][2] # incr spawn rate incr rate def _update_scores(self) -> None: - # Achievements in default preset only. + # Do achievements in default preset only. score = self._score if self._preset == 'default': if score >= 250: @@ -298,7 +298,6 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): super().handlemessage(msg) def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None: - # FIXME: Unify args. self._show_standard_scores_to_beat_ui(scores) def end_game(self) -> None: diff --git a/docs/ba_module.md b/docs/ba_module.md index ff8aa38f..795b4dea 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-22 for Ballistica version 1.5.0 build 20026

    +

    last updated on 2020-05-23 for Ballistica version 1.5.0 build 20026

    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!


    @@ -2450,7 +2450,7 @@ and short description of the game.

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz[PlayerType]

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), angle: float = None) -> PlayerSpaz

    Create and wire up a ba.PlayerSpaz for the provided ba.Player.

    @@ -4975,7 +4975,7 @@ up until ba.Activity.on_begin() is c

    spawn_player_spaz()

    -

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz[PlayerType]

    +

    spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = None, angle: float = None) -> PlayerSpaz

    Method override; spawns and wires up a standard ba.PlayerSpaz for a ba.Player.

    From 72be5c0b8d9233f50fc1b6634539269a56c2f920 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 24 May 2020 01:40:38 -0700 Subject: [PATCH 044/417] Modernized onslaught code and other cleanup --- .efrocachemap | 24 +- assets/src/ba_data/python/ba/_activity.py | 8 +- assets/src/ba_data/python/ba/_gameactivity.py | 6 +- assets/src/ba_data/python/ba/_player.py | 6 + assets/src/ba_data/python/bastd/actor/flag.py | 4 +- .../ba_data/python/bastd/actor/playerspaz.py | 12 - .../ba_data/python/bastd/actor/powerupbox.py | 34 +- assets/src/ba_data/python/bastd/actor/spaz.py | 33 +- .../python/bastd/game/capturetheflag.py | 2 +- .../src/ba_data/python/bastd/game/football.py | 62 +- .../src/ba_data/python/bastd/game/hockey.py | 10 +- .../src/ba_data/python/bastd/game/keepaway.py | 4 +- .../ba_data/python/bastd/game/onslaught.py | 1082 +++++++++-------- .../ba_data/python/bastd/game/runaround.py | 13 +- .../python/bastd/game/targetpractice.py | 4 +- .../ba_data/python/bastd/game/thelaststand.py | 10 +- assets/src/ba_data/python/bastd/mainmenu.py | 4 +- docs/ba_module.md | 2 +- 18 files changed, 669 insertions(+), 651 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 7e8a39bf..8c2365bf 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b1/22/e87fa53bad26b90154a8ac2383b5", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/75/8f/4eabb293c30168da4ef63047c8de", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7d/cf/0260a6399173881606846ea7080b", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/04/29/28d7d0ef9ac8fc9816bf002afaa8", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/56/3b/09554ebdb31e64d3ddc145bc1eb8", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6f/2b/d0629250709393bc39dd30f54043", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/30/f7120527ef4a402a656f38af1e65", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/66/963c96391fcb5dae4da0999d04dc", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/84/fd/db055e722538fba088572f9c7423", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7b/f0/82920a407e5627da5b32bd3d7364", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d0/0c/a8bb182f1762d13521da694d0a3c", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6d/57/baa2f3d7ba2345d94535ff2f04cb" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/42/5238d5de1cf94a07a513ea2b3e1b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/48/2f0e4350a080373301de625e2cc4", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c0/1d/dbc0a5e2ca05b626cbeffd6def6c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/a8/5c58d6b5e1d844640334c35ad3af", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3d/0a/76b615f9bcb9bf4f0ca745060d40", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/6b/0f623ac481e3553e352c1cd3cb7e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c4/a5/3cad1ced77551369dc56c6bca5fb", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/3f/55094817619cae66f941a9f6db8c", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/6b/7aa29831a746672f9984cbb1dbf1", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/07/4c/00a6136d0bd5573946d10e294720", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/8d/af068e67244cbb28444b27ae66d7", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f4/62/eb7cb26c952df481b757dcf53f9c" } \ No newline at end of file diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index f7690ed1..05f3508d 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -525,10 +525,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): (internal) """ - # Is this ever still happening?... - if self._has_begun: - print_error("_begin called twice; this shouldn't happen") - return + assert not self._has_begun # Inherit stats from the session. self._stats = session.stats @@ -791,6 +788,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): if player: try: sessionplayer = player.sessionplayer + player.reset() sessionplayer.set_node(None) sessionplayer.set_activity(None) sessionplayer.gameplayer = None @@ -818,7 +816,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._activity_data.destroy() except Exception: print_exception( - 'Exception during ba.Activity._expire() destroying data:') + 'Error during ba.Activity._expire() destroying data:') def _prune_dead_actors(self) -> None: self._actor_refs = [a for a in self._actor_refs if a] diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index fb418c0b..9d0de5ee 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -1094,10 +1094,10 @@ class GameActivity(Activity[PlayerType, TeamType]): def _standard_drop_powerup(self, index: int, expire: bool = True) -> None: # pylint: disable=cyclic-import - from bastd.actor import powerupbox - powerupbox.PowerupBox( + from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory + PowerupBox( position=self.map.powerup_spawn_points[index], - poweruptype=powerupbox.get_factory().get_random_powerup_type(), + poweruptype=PowerupBoxFactory.get().get_random_powerup_type(), expire=expire).autoretain() def _standard_drop_powerups(self) -> None: diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 20615269..9df3e897 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -99,6 +99,12 @@ class Player(Generic[TeamType]): self._nodeactor = NodeActor(node) sessionplayer.set_node(node) + def reset(self) -> None: + """(internal)""" + self._nodeactor = None + self.actor = None + self.team = None # type: ignore + @property def sessionplayer(self) -> ba.SessionPlayer: """Return the ba.SessionPlayer corresponding to this Player. diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index f9784336..31de6e7e 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -139,7 +139,7 @@ class FlagPickedUpMessage: @dataclass -class FlagDeathMessage: +class FlagDiedMessage: """A message saying a ba.Flag has died. category: Message Classes @@ -335,7 +335,7 @@ class Flag(ba.Actor): if self.node: self.node.delete() if not msg.immediate: - self.activity.handlemessage(FlagDeathMessage(self)) + self.activity.handlemessage(FlagDiedMessage(self)) elif isinstance(msg, ba.HitMessage): assert self.node assert msg.force_direction is not None diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 6948c98f..1a3375a1 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -90,18 +90,6 @@ class PlayerSpaz(Spaz): self._player = player self._drive_player_position() - # @property - # def player(self, playertype: Type[PlayerType]) -> PlayerType: - # """The ba.Player associated with this Spaz. - - # If the player no longer exists, raises an ba.PlayerNotFoundError. - # """ - # player = self._player - # assert isinstance(player, playertype) - # if not player: - # raise ba.PlayerNotFoundError() - # return player - @overload def getplayer(self, playertype: Type[PlayerType], diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py index 6f0e47b9..f04fc25a 100644 --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py @@ -182,21 +182,21 @@ class PowerupBoxFactory: self._lastpoweruptype = ptype return ptype - -def get_factory() -> PowerupBoxFactory: - """Return a shared ba.PowerupBoxFactory object, creating if necessary.""" - activity = ba.getactivity() - if activity is None: - raise RuntimeError('no current activity') - try: - # FIXME: et better way to store stuff with activity - # pylint: disable=protected-access - # noinspection PyProtectedMember - return activity._shared_powerup_factory # type: ignore - except Exception: - factory = activity._shared_powerup_factory = ( # type: ignore - PowerupBoxFactory()) - return factory + @staticmethod + def get() -> PowerupBoxFactory: + """Return a shared ba.PowerupBoxFactory object, creating if needed.""" + activity = ba.getactivity() + if activity is None: + raise RuntimeError('no current activity') + try: + # FIXME: et better way to store stuff with activity + # pylint: disable=protected-access + # noinspection PyProtectedMember + return activity._shared_powerup_factory # type: ignore + except Exception: + factory = activity._shared_powerup_factory = ( # type: ignore + PowerupBoxFactory()) + return factory class PowerupBox(ba.Actor): @@ -229,7 +229,7 @@ class PowerupBox(ba.Actor): super().__init__() - factory = get_factory() + factory = PowerupBoxFactory.get() self.poweruptype = poweruptype self._powersgiven = False @@ -293,7 +293,7 @@ class PowerupBox(ba.Actor): self._handlemessage_sanity_check() if isinstance(msg, ba.PowerupAcceptMessage): - factory = get_factory() + factory = PowerupBoxFactory.get() assert self.node if self.poweruptype == 'health': ba.playsound(factory.health_powerup_sound, diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index b1d64372..5c599ec2 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -28,7 +28,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor import bomb as stdbomb -from bastd.actor import powerupbox +from bastd.actor.powerupbox import PowerupBoxFactory if TYPE_CHECKING: from typing import (Any, Sequence, Optional, Dict, List, Union, Callable, @@ -147,7 +147,7 @@ class Spaz(ba.Actor): extras_material = [] if can_accept_powerups: - pam = powerupbox.get_factory().powerup_accept_material + pam = PowerupBoxFactory.get().powerup_accept_material materials.append(pam) roller_materials.append(pam) extras_material.append(pam) @@ -252,7 +252,7 @@ class Spaz(ba.Actor): self._score_text_hide_timer: Optional[ba.Timer] = None self._last_stand_pos: Optional[Sequence[float]] = None - # deprecated stuff.. need to make these into lists + # Deprecated stuff.. should make these into lists. self.punch_callback: Optional[Callable[[Spaz], Any]] = None self.pick_up_powerup_callback: Optional[Callable[[Spaz], Any]] = None @@ -273,6 +273,7 @@ class Spaz(ba.Actor): Add a call to be run whenever this Spaz drops a bomb. The spaz and the newly-dropped bomb are passed as arguments. """ + assert not self.expired self._dropped_bomb_callbacks.append(call) def is_alive(self) -> bool: @@ -725,7 +726,7 @@ class Spaz(ba.Actor): if self.pick_up_powerup_callback is not None: self.pick_up_powerup_callback(self) if msg.poweruptype == 'triple_bombs': - tex = powerupbox.get_factory().tex_bomb + tex = PowerupBoxFactory.get().tex_bomb self._flash_billboard(tex) self.set_bomb_count(3) if self.powerups_expire: @@ -785,7 +786,7 @@ class Spaz(ba.Actor): timeformat=ba.TimeFormat.MILLISECONDS)) elif msg.poweruptype == 'punch': self._has_boxing_gloves = True - tex = powerupbox.get_factory().tex_punch + tex = PowerupBoxFactory.get().tex_punch self._flash_billboard(tex) self.equip_boxing_gloves() if self.powerups_expire: @@ -845,7 +846,7 @@ class Spaz(ba.Actor): if m != factory.curse_material)) self.node.curse_death_time = 0 self.hitpoints = self.hitpoints_max - self._flash_billboard(powerupbox.get_factory().tex_health) + self._flash_billboard(PowerupBoxFactory.get().tex_health) self.node.hurt = 0 self._last_hit_time = None self._num_times_hit = 0 @@ -1292,7 +1293,7 @@ class Spaz(ba.Actor): if self.land_mine_count != 0: self.node.counter_text = 'x' + str(self.land_mine_count) self.node.counter_texture = ( - powerupbox.get_factory().tex_land_mines) + PowerupBoxFactory.get().tex_land_mines) else: self.node.counter_text = '' @@ -1380,13 +1381,13 @@ class Spaz(ba.Actor): ba.playsound(sound, position=pos, volume=5.0) def _get_bomb_type_tex(self) -> ba.Texture: - bomb_factory = powerupbox.get_factory() + factory = PowerupBoxFactory.get() if self.bomb_type == 'sticky': - return bomb_factory.tex_sticky_bombs + return factory.tex_sticky_bombs if self.bomb_type == 'ice': - return bomb_factory.tex_ice_bombs + return factory.tex_ice_bombs if self.bomb_type == 'impact': - return bomb_factory.tex_impact_bombs + return factory.tex_impact_bombs raise ValueError('invalid bomb type') def _flash_billboard(self, tex: ba.Texture) -> None: @@ -1411,7 +1412,7 @@ class Spaz(ba.Actor): def _gloves_wear_off_flash(self) -> None: if self.node: self.node.boxing_gloves_flashing = True - self.node.billboard_texture = powerupbox.get_factory().tex_punch + self.node.billboard_texture = PowerupBoxFactory.get().tex_punch self.node.billboard_opacity = 1.0 self.node.billboard_cross_out = True @@ -1425,21 +1426,21 @@ class Spaz(ba.Actor): self._punch_cooldown = factory.punch_cooldown self._has_boxing_gloves = False if self.node: - ba.playsound(powerupbox.get_factory().powerdown_sound, + ba.playsound(PowerupBoxFactory.get().powerdown_sound, position=self.node.position) self.node.boxing_gloves = False self.node.billboard_opacity = 0.0 def _multi_bomb_wear_off_flash(self) -> None: if self.node: - self.node.billboard_texture = powerupbox.get_factory().tex_bomb + self.node.billboard_texture = PowerupBoxFactory.get().tex_bomb self.node.billboard_opacity = 1.0 self.node.billboard_cross_out = True def _multi_bomb_wear_off(self) -> None: self.set_bomb_count(self.default_bomb_count) if self.node: - ba.playsound(powerupbox.get_factory().powerdown_sound, + ba.playsound(PowerupBoxFactory.get().powerdown_sound, position=self.node.position) self.node.billboard_opacity = 0.0 @@ -1452,6 +1453,6 @@ class Spaz(ba.Actor): def _bomb_wear_off(self) -> None: self.bomb_type = self.bomb_type_default if self.node: - ba.playsound(powerupbox.get_factory().powerdown_sound, + ba.playsound(PowerupBoxFactory.get().powerdown_sound, position=self.node.position) self.node.billboard_opacity = 0.0 diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index e897797a..e99cb251 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -547,7 +547,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # Augment standard behavior. super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) - elif isinstance(msg, stdflag.FlagDeathMessage): + elif isinstance(msg, stdflag.FlagDiedMessage): assert isinstance(msg.flag, CTFFlag) ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) elif isinstance(msg, stdflag.FlagPickedUpMessage): diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index b3a3eb16..4c4f5c72 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -36,6 +36,7 @@ from bastd.actor.bomb import TNTSpawner from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon +from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox if TYPE_CHECKING: from typing import Any, List, Type, Dict, Sequence, Optional, Union @@ -105,6 +106,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): 'default': 1.0 }), ] + default_music = ba.MusicType.FOOTBALL @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -125,13 +127,15 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self._score_sound = ba.getsound('score') self._swipsound = ba.getsound('swip') self._whistle_sound = ba.getsound('refWhistle') - self.score_region_material = ba.Material() - self.score_region_material.add_actions( + self._score_region_material = ba.Material() + self._score_region_material.add_actions( conditions=('they_have_material', stdflag.get_factory().flagmaterial), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('call', 'at_connect', self._handle_score))) + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score), + )) self._flag_spawn_pos: Optional[Sequence[float]] = None self._score_regions: List[ba.NodeActor] = [] self._flag: Optional[FootballFlag] = None @@ -158,10 +162,6 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): return 'score ${ARG1} touchdowns', touchdowns return 'score a touchdown' - def on_transition_in(self) -> None: - self.default_music = ba.MusicType.FOOTBALL - super().on_transition_in() - def on_begin(self) -> None: super().on_begin() self.setup_standard_time_limit(self._time_limit) @@ -176,7 +176,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): 'position': defs.boxes['goal1'][0:3], 'scale': defs.boxes['goal1'][6:9], 'type': 'box', - 'materials': (self.score_region_material, ) + 'materials': (self._score_region_material, ) }))) self._score_regions.append( ba.NodeActor( @@ -185,7 +185,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): 'position': defs.boxes['goal2'][0:3], 'scale': defs.boxes['goal2'][6:9], 'type': 'box', - 'materials': (self.score_region_material, ) + 'materials': (self._score_region_material, ) }))) self._update_scoreboard() ba.playsound(self._chant_sound) @@ -282,7 +282,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self.respawn_player(msg.getplayer(Player)) # Respawn dead flags. - elif isinstance(msg, stdflag.FlagDeathMessage): + elif isinstance(msg, stdflag.FlagDiedMessage): if not self.has_ended(): self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag) self._flag_respawn_light = ba.NodeActor( @@ -333,6 +333,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): name = 'Football' tips = ['Use the pick-up button to grab the flag < ${PICKUP} >'] score_info = ba.ScoreInfo(scoretype=ba.ScoreType.MILLISECONDS, version='B') + default_music = ba.MusicType.FOOTBALL # FIXME: Need to update co-op games to use get_score_info. def get_score_type(self) -> str: @@ -369,16 +370,18 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._score_region_material.add_actions( conditions=('they_have_material', stdflag.get_factory().flagmaterial), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('call', 'at_connect', self._handle_score))) + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_score), + )) self._powerup_center = (0, 2, 0) self._powerup_spread = (10, 5.5) self._player_has_dropped_bomb = False self._player_has_punched = False self._scoreboard: Optional[Scoreboard] = None self._flag_spawn_pos: Optional[Sequence[float]] = None - self.score_regions: List[ba.NodeActor] = [] + self._score_regions: List[ba.NodeActor] = [] self._exclude_powerups: List[str] = [] self._have_tnt = False self._bot_types_initial: Optional[List[Type[spazbot.SpazBot]]] = None @@ -392,14 +395,13 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._bots = spazbot.BotSet() self._bot_spawn_timer: Optional[ba.Timer] = None self._powerup_drop_timer: Optional[ba.Timer] = None - self.scoring_team: Optional[Team] = None + self._scoring_team: Optional[Team] = None self._final_time_ms: Optional[int] = None self._time_text_timer: Optional[ba.Timer] = None self._flag_respawn_light: Optional[ba.Actor] = None self._flag: Optional[FootballFlag] = None def on_transition_in(self) -> None: - self.default_music = ba.MusicType.FOOTBALL super().on_transition_in() self._scoreboard = Scoreboard() self._flag_spawn_pos = self.map.get_flag_position(None) @@ -407,7 +409,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): # Set up the two score regions. defs = self.map.defs - self.score_regions.append( + self._score_regions.append( ba.NodeActor( ba.newnode('region', attrs={ @@ -416,7 +418,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): 'type': 'box', 'materials': [self._score_region_material] }))) - self.score_regions.append( + self._score_regions.append( ba.NodeActor( ba.newnode('region', attrs={ @@ -608,12 +610,11 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): closest_bot.target_flag = self._flag def _drop_powerup(self, index: int, poweruptype: str = None) -> None: - from bastd.actor import powerupbox if poweruptype is None: - poweruptype = (powerupbox.get_factory().get_random_powerup_type( + poweruptype = (PowerupBoxFactory.get().get_random_powerup_type( excludetypes=self._exclude_powerups)) - powerupbox.PowerupBox(position=self.map.powerup_spawn_points[index], - poweruptype=poweruptype).autoretain() + PowerupBox(position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype).autoretain() def _start_powerup_drops(self) -> None: self._powerup_drop_timer = ba.Timer(3.0, @@ -624,7 +625,6 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): standard_points: bool = False, poweruptype: str = None) -> None: """Generic powerup drop.""" - from bastd.actor import powerupbox if standard_points: spawnpoints = self.map.powerup_spawn_points for i, _point in enumerate(spawnpoints): @@ -638,9 +638,9 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): -self._powerup_spread[1], self._powerup_spread[1])) # Drop one random one somewhere. - powerupbox.PowerupBox( + PowerupBox( position=point, - poweruptype=powerupbox.get_factory().get_random_powerup_type( + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( excludetypes=self._exclude_powerups)).autoretain() def _kill_flag(self) -> None: @@ -664,8 +664,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): # See which score region it was. region = ba.get_collision_info('source_node') i = None - for i in range(len(self.score_regions)): - if region == self.score_regions[i].node: + for i in range(len(self._score_regions)): + if region == self._score_regions[i].node: break for team in [self.teams[0], self._bot_team]: @@ -740,7 +740,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._scoreboard.set_team_value(team, team.score, win_score) if team.score >= win_score: if not have_scoring_team: - self.scoring_team = team + self._scoring_team = team if team is self._bot_team: self.continue_or_end_game() else: @@ -835,7 +835,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._award_achievement('Super Mega Punch') # Respawn dead flags. - elif isinstance(msg, stdflag.FlagDeathMessage): + elif isinstance(msg, stdflag.FlagDiedMessage): assert isinstance(msg.flag, FootballFlag) msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag) self._flag_respawn_light = ba.NodeActor( diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 5cf8c564..b027c3eb 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -29,7 +29,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.scoreboard import Scoreboard -from bastd.actor import powerupbox +from bastd.actor.powerupbox import PowerupBoxFactory if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -137,6 +137,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): 'default': 1.0 }), ] + default_music = ba.MusicType.HOCKEY @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -182,7 +183,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): # We want the puck to kill powerups; not get stopped by them self.puck_material.add_actions( conditions=('they_have_material', - powerupbox.get_factory().powerup_material), + PowerupBoxFactory.get().powerup_material), actions=(('modify_part_collision', 'physical', False), ('message', 'their_node', 'at_connect', ba.DieMessage()))) self._score_region_material = ba.Material() @@ -205,10 +206,6 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): return 'score a goal' return 'score ${ARG1} goals', self.settings_raw['Score to Win'] - def on_transition_in(self) -> None: - self.default_music = ba.MusicType.HOCKEY - super().on_transition_in() - def on_begin(self) -> None: super().on_begin() @@ -328,7 +325,6 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): self.end(results=results) def _update_scoreboard(self) -> None: - """ update scoreboard and check for winners """ winscore = self.settings_raw['Score to Win'] for team in self.teams: self._scoreboard.set_team_value(team, team.gamedata['score'], diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 31e9a407..e0d065dc 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -31,7 +31,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard -from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDeathMessage, +from bastd.actor.flag import (Flag, FlagDroppedMessage, FlagDiedMessage, FlagPickedUpMessage) if TYPE_CHECKING: @@ -270,7 +270,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): # Augment standard behavior. super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) - elif isinstance(msg, FlagDeathMessage): + elif isinstance(msg, FlagDiedMessage): self._spawn_flag() elif isinstance(msg, (FlagDroppedMessage, FlagPickedUpMessage)): self._update_flag_state() diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index e48c74fe..05f45aa5 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -27,12 +27,17 @@ from __future__ import annotations import math import random +from enum import Enum, unique +from dataclasses import dataclass from typing import TYPE_CHECKING import ba +from bastd.actor.popuptext import PopupText from bastd.actor.bomb import TNTSpawner from bastd.actor.playerspaz import PlayerSpazHurtMessage from bastd.actor.scoreboard import Scoreboard +from bastd.actor.controlsguide import ControlsGuide +from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory from bastd.actor.spazbot import ( SpazBotDeathMessage, BotSet, ChargerBot, StickyBot, BomberBot, BomberBotLite, BrawlerBot, BrawlerBotLite, TriggerBot, BomberBotStaticLite, @@ -45,6 +50,79 @@ if TYPE_CHECKING: from bastd.actor.spazbot import SpazBot +@dataclass +class Wave: + """A wave of enemies.""" + entries: List[Union[Bot, Spacing, Delay, None]] + base_angle: float = 0.0 + + +@dataclass +class Bot: + """A bot in a wave.""" + bottype: Union[Type[SpazBot], str] + point: Optional[Point] = None + spacing: float = 5.0 + + +@dataclass +class Spacing: + """Empty space in a wave.""" + spacing: float = 5.0 + + +@dataclass +class Delay: + """A delay in a wave.""" + duration: float + + +class Preset(Enum): + """Game presets we support.""" + TRAINING = 'training' + TRAINING_EASY = 'training_easy' + ROOKIE = 'rookie' + ROOKIE_EASY = 'rookie_easy' + PRO = 'pro' + PRO_EASY = 'pro_easy' + UBER = 'uber' + UBER_EASY = 'uber_easy' + ENDLESS = 'endless' + ENDLESS_TOURNAMENT = 'endless_tournament' + + +@unique +class Point(Enum): + """Points on the map to spawn at.""" + LEFT_UPPER_MORE = 'left_upper_more' + LEFT_UPPER = 'left_upper' + TURRET_TOP_RIGHT = 'turret_top_right' + RIGHT_UPPER = 'right_upper' + TURRET_TOP_MIDDLE_LEFT = 'turret_top_middle_left' + TURRET_TOP_MIDDLE_RIGHT = 'turret_top_middle_right' + TURRET_TOP_LEFT = 'turret_top_left' + TOP_RIGHT = 'top_right' + TOP_LEFT = 'top_left' + TOP = 'top' + BOTTOM = 'bottom' + LEFT = 'left' + RIGHT = 'right' + RIGHT_UPPER_MORE = 'right_upper_more' + RIGHT_LOWER = 'right_lower' + RIGHT_LOWER_MORE = 'right_lower_more' + BOTTOM_RIGHT = 'bottom_right' + BOTTOM_LEFT = 'bottom_left' + TURRET_BOTTOM_RIGHT = 'turret_bottom_right' + TURRET_BOTTOM_LEFT = 'turret_bottom_left' + LEFT_LOWER = 'left_lower' + LEFT_LOWER_MORE = 'left_lower_more' + TURRET_TOP_MIDDLE = 'turret_top_middle' + BOTTOM_HALF_RIGHT = 'bottom_half_right' + BOTTOM_HALF_LEFT = 'bottom_half_left' + TOP_HALF_RIGHT = 'top_half_right' + TOP_HALF_LEFT = 'top_half_left' + + class Player(ba.Player['Team']): """Our player type for this game.""" @@ -79,15 +157,11 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): - self._preset = settings.get('preset', 'training') - if self._preset in [ - 'training', - 'training_easy', - 'pro', - 'pro_easy', - 'endless', - 'endless_tournament', - ]: + self._preset = Preset(settings.get('preset', 'training')) + if self._preset in { + Preset.TRAINING, Preset.TRAINING_EASY, Preset.PRO, + Preset.PRO_EASY, Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT + }: settings['map'] = 'Doom Shroom' else: settings['map'] = 'Courtyard' @@ -123,8 +197,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._dingsound = ba.getsound('dingSmall') self._dingsoundhigh = ba.getsound('dingSmallHigh') self._have_tnt = False - self._excludepowerups: Optional[List[str]] = None - self._waves: Optional[List[Dict[str, Any]]] = None + self._excluded_powerups: Optional[List[str]] = None + self._waves: List[Wave] = [] self._tntspawner: Optional[TNTSpawner] = None self._bots: Optional[BotSet] = None self._powerup_drop_timer: Optional[ba.Timer] = None @@ -141,7 +215,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): super().on_transition_in() session = ba.getsession() # Show special landmine tip on rookie preset. - if self._preset in ['rookie', 'rookie_easy']: + if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: # Show once per session only (then we revert to regular tips). if not getattr(session, '_g_showed_onslaught_landmine_tip', False): setattr(session, '_g_showed_onslaught_landmine_tip', True) @@ -153,7 +227,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): }] # Show special tnt tip on pro preset. - if self._preset in ['pro', 'pro_easy']: + if self._preset in {Preset.PRO, Preset.PRO_EASY}: # Show once per session only (then we revert to regular tips). if not getattr(session, '_g_showed_onslaught_tnt_tip', False): setattr(session, '_g_showed_onslaught_tnt_tip', True) @@ -165,7 +239,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): }] # Show special curse tip on uber preset. - if self._preset in ['uber', 'uber_easy']: + if self._preset in {Preset.UBER, Preset.UBER_EASY}: # Show once per session only (then we revert to regular tips). if not getattr(session, '_g_showed_onslaught_curse_tip', False): setattr(session, '_g_showed_onslaught_curse_tip', True) @@ -192,202 +266,193 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): score_split=0.5) def on_begin(self) -> None: - from bastd.actor.controlsguide import ControlsGuide super().on_begin() player_count = len(self.players) - hard = self._preset not in [ - 'training_easy', 'rookie_easy', 'pro_easy', 'uber_easy' - ] - if self._preset in ['training', 'training_easy']: + hard = self._preset not in { + Preset.TRAINING_EASY, Preset.ROOKIE_EASY, Preset.PRO_EASY, + Preset.UBER_EASY + } + if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}: ControlsGuide(delay=3.0, lifespan=10.0, bright=True).autoretain() self._have_tnt = False - self._excludepowerups = ['curse', 'land_mines'] + self._excluded_powerups = ['curse', 'land_mines'] self._waves = [ - {'base_angle': 195, - 'entries': [ - {'type': BomberBotLite, 'spacing': 5}, - ] * player_count}, - {'base_angle': 130, - 'entries': [ - {'type': BrawlerBotLite, 'spacing': 5}, - ] * player_count}, - {'base_angle': 195, - 'entries': [ - {'type': BomberBotLite, 'spacing': 10}, - ] * (player_count + 1)}, - {'base_angle': 130, - 'entries': [ - {'type': BrawlerBotLite, 'spacing': 10}, - ] * (player_count + 1)}, - {'base_angle': 130, - 'entries': [ - {'type': BrawlerBotLite, 'spacing': 5} + Wave(base_angle=195, + entries=[ + Bot(BomberBotLite, spacing=5), + ] * player_count), + Wave(base_angle=130, + entries=[ + Bot(BrawlerBotLite, spacing=5), + ] * player_count), + Wave(base_angle=195, + entries=[Bot(BomberBotLite, spacing=10)] * + (player_count + 1)), + Wave(base_angle=130, + entries=[ + Bot(BrawlerBotLite, spacing=10), + ] * (player_count + 1)), + Wave(base_angle=130, + entries=[ + Bot(BrawlerBotLite, spacing=5) if player_count > 1 else None, - {'type': BrawlerBotLite, 'spacing': 5}, - {'type': None, 'spacing': 30}, - {'type': BomberBotLite, 'spacing': 5} + Bot(BrawlerBotLite, spacing=5), + Spacing(30), + Bot(BomberBotLite, spacing=5) if player_count > 3 else None, - {'type': BomberBotLite, 'spacing': 5}, - {'type': None, 'spacing': 30}, - {'type': BrawlerBotLite, 'spacing': 5}, - {'type': BrawlerBotLite, 'spacing': 5} + Bot(BomberBotLite, spacing=5), + Spacing(30), + Bot(BrawlerBotLite, spacing=5), + Bot(BrawlerBotLite, spacing=5) if player_count > 2 else None, - ]}, - {'base_angle': 195, - 'entries': [ - {'type': TriggerBot, 'spacing': 90}, - {'type': TriggerBot, 'spacing': 90} + ]), + Wave(base_angle=195, + entries=[ + Bot(TriggerBot, spacing=90), + Bot(TriggerBot, spacing=90) if player_count > 1 else None, - ]}, - ] # yapf: disable + ]), + ] - elif self._preset in ['rookie', 'rookie_easy']: + elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: self._have_tnt = False - self._excludepowerups = ['curse'] + self._excluded_powerups = ['curse'] self._waves = [ - {'entries': [ - {'type': ChargerBot, 'point': 'left_upper_more'} - if player_count > 2 else None, - {'type': ChargerBot, 'point': 'left_upper'}, - ]}, - {'entries': [ - {'type': BomberBotStaticLite, - 'point': 'turret_top_right'}, - {'type': BrawlerBotLite, 'point': 'right_upper'}, - {'type': BrawlerBotLite, 'point': 'right_lower'} - if player_count > 1 else None, - {'type': BomberBotStaticLite, - 'point': 'turret_bottom_right'} - if player_count > 2 else None, - ]}, - {'entries': [ - {'type': BomberBotStaticLite, - 'point': 'turret_bottom_left'}, - {'type': TriggerBot, 'point': 'left'}, - {'type': TriggerBot, 'point': 'left_lower'} - if player_count > 1 else None, - {'type': TriggerBot, 'point': 'left_upper'} - if player_count > 2 else None, - ]}, - {'entries': [ - {'type': BrawlerBotLite, 'point': 'top_right'}, - {'type': BrawlerBot, 'point': 'top_half_right'} - if player_count > 1 else None, - {'type': BrawlerBotLite, 'point': 'top_left'}, - {'type': BrawlerBotLite, 'point': 'top_half_left'} - if player_count > 2 else None, - {'type': BrawlerBot, 'point': 'top'}, - {'type': BomberBotStaticLite, - 'point': 'turret_top_middle'}, - ]}, - {'entries': [ - {'type': TriggerBotStatic, - 'point': 'turret_bottom_left'}, - {'type': TriggerBotStatic, - 'point': 'turret_bottom_right'}, - {'type': TriggerBot, 'point': 'bottom'}, - {'type': TriggerBot, 'point': 'bottom_half_right'} - if player_count > 1 else None, - {'type': TriggerBot, 'point': 'bottom_half_left'} - if player_count > 2 else None, - ]}, - {'entries': [ - {'type': BomberBotStaticLite, - 'point': 'turret_top_left'}, - {'type': BomberBotStaticLite, - 'point': 'turret_top_right'}, - {'type': ChargerBot, 'point': 'bottom'}, - {'type': ChargerBot, 'point': 'bottom_half_left'} - if player_count > 1 else None, - {'type': ChargerBot, 'point': 'bottom_half_right'} - if player_count > 2 else None, - ]}, - ] # yapf: disable + Wave(entries=[ + Bot(ChargerBot, Point.LEFT_UPPER_MORE + ) if player_count > 2 else None, + Bot(ChargerBot, Point.LEFT_UPPER), + ]), + Wave(entries=[ + Bot(BomberBotStaticLite, Point.TURRET_TOP_RIGHT), + Bot(BrawlerBotLite, Point.RIGHT_UPPER), + Bot(BrawlerBotLite, Point.RIGHT_LOWER + ) if player_count > 1 else None, + Bot(BomberBotStaticLite, Point.TURRET_BOTTOM_RIGHT + ) if player_count > 2 else None, + ]), + Wave(entries=[ + Bot(BomberBotStaticLite, Point.TURRET_BOTTOM_LEFT), + Bot(TriggerBot, Point.LEFT), + Bot(TriggerBot, Point.LEFT_LOWER + ) if player_count > 1 else None, + Bot(TriggerBot, Point.LEFT_UPPER + ) if player_count > 2 else None, + ]), + Wave(entries=[ + Bot(BrawlerBotLite, Point.TOP_RIGHT), + Bot(BrawlerBot, Point.TOP_HALF_RIGHT + ) if player_count > 1 else None, + Bot(BrawlerBotLite, Point.TOP_LEFT), + Bot(BrawlerBotLite, Point.TOP_HALF_LEFT + ) if player_count > 2 else None, + Bot(BrawlerBot, Point.TOP), + Bot(BomberBotStaticLite, Point.TURRET_TOP_MIDDLE), + ]), + Wave(entries=[ + Bot(TriggerBotStatic, Point.TURRET_BOTTOM_LEFT), + Bot(TriggerBotStatic, Point.TURRET_BOTTOM_RIGHT), + Bot(TriggerBot, Point.BOTTOM), + Bot(TriggerBot, Point.BOTTOM_HALF_RIGHT + ) if player_count > 1 else None, + Bot(TriggerBot, Point.BOTTOM_HALF_LEFT + ) if player_count > 2 else None, + ]), + Wave(entries=[ + Bot(BomberBotStaticLite, Point.TURRET_TOP_LEFT), + Bot(BomberBotStaticLite, Point.TURRET_TOP_RIGHT), + Bot(ChargerBot, Point.BOTTOM), + Bot(ChargerBot, Point.BOTTOM_HALF_LEFT + ) if player_count > 1 else None, + Bot(ChargerBot, Point.BOTTOM_HALF_RIGHT + ) if player_count > 2 else None, + ]), + ] - elif self._preset in ['pro', 'pro_easy']: - self._excludepowerups = ['curse'] + elif self._preset in {Preset.PRO, Preset.PRO_EASY}: + self._excluded_powerups = ['curse'] self._have_tnt = True self._waves = [ - {'base_angle': -50, - 'entries': [ - {'type': BrawlerBot, 'spacing': 12} + Wave(base_angle=-50, + entries=[ + Bot(BrawlerBot, spacing=12) if player_count > 3 else None, - {'type': BrawlerBot, 'spacing': 12}, - {'type': BomberBot, 'spacing': 6}, - {'type': BomberBot, 'spacing': 6} - if self._preset == 'pro' else None, - {'type': BomberBot, 'spacing': 6} + Bot(BrawlerBot, spacing=12), + Bot(BomberBot, spacing=6), + Bot(BomberBot, spacing=6) + if self._preset is Preset.PRO else None, + Bot(BomberBot, spacing=6) if player_count > 1 else None, - {'type': BrawlerBot, 'spacing': 12}, - {'type': BrawlerBot, 'spacing': 12} + Bot(BrawlerBot, spacing=12), + Bot(BrawlerBot, spacing=12) if player_count > 2 else None, - ]}, - {'base_angle': 180, - 'entries': [ - {'type': BrawlerBot, 'spacing': 6} + ]), + Wave(base_angle=180, + entries=[ + Bot(BrawlerBot, spacing=6) if player_count > 3 else None, - {'type': BrawlerBot, 'spacing': 6} - if self._preset == 'pro' else None, - {'type': BrawlerBot, 'spacing': 6}, - {'type': ChargerBot, 'spacing': 45}, - {'type': ChargerBot, 'spacing': 45} + Bot(BrawlerBot, spacing=6) + if self._preset is Preset.PRO else None, + Bot(BrawlerBot, spacing=6), + Bot(ChargerBot, spacing=45), + Bot(ChargerBot, spacing=45) if player_count > 1 else None, - {'type': BrawlerBot, 'spacing': 6}, - {'type': BrawlerBot, 'spacing': 6} - if self._preset == 'pro' else None, - {'type': BrawlerBot, 'spacing': 6} + Bot(BrawlerBot, spacing=6), + Bot(BrawlerBot, spacing=6) + if self._preset is Preset.PRO else None, + Bot(BrawlerBot, spacing=6) if player_count > 2 else None, - ]}, - {'base_angle': 0, - 'entries': [ - {'type': ChargerBot, 'spacing': 30}, - {'type': TriggerBot, 'spacing': 30}, - {'type': TriggerBot, 'spacing': 30}, - {'type': TriggerBot, 'spacing': 30} - if self._preset == 'pro' else None, - {'type': TriggerBot, 'spacing': 30} + ]), + Wave(base_angle=0, + entries=[ + Bot(ChargerBot, spacing=30), + Bot(TriggerBot, spacing=30), + Bot(TriggerBot, spacing=30), + Bot(TriggerBot, spacing=30) + if self._preset is Preset.PRO else None, + Bot(TriggerBot, spacing=30) if player_count > 1 else None, - {'type': TriggerBot, 'spacing': 30} + Bot(TriggerBot, spacing=30) if player_count > 3 else None, - {'type': ChargerBot, 'spacing': 30}, - ]}, - {'base_angle': 90, - 'entries': [ - {'type': StickyBot, 'spacing': 50}, - {'type': StickyBot, 'spacing': 50} - if self._preset == 'pro' else None, - {'type': StickyBot, 'spacing': 50}, - {'type': StickyBot, 'spacing': 50} - if player_count > 1 else None, - {'type': StickyBot, 'spacing': 50} - if player_count > 3 else None, - ]}, - {'base_angle': 0, - 'entries': [ - {'type': TriggerBot, 'spacing': 72}, - {'type': TriggerBot, 'spacing': 72}, - {'type': TriggerBot, 'spacing': 72} - if self._preset == 'pro' else None, - {'type': TriggerBot, 'spacing': 72}, - {'type': TriggerBot, 'spacing': 72}, - {'type': TriggerBot, 'spacing': 36} - if player_count > 2 else None, - ]}, - {'base_angle': 30, - 'entries': [ - {'type': ChargerBotProShielded, 'spacing': 50}, - {'type': ChargerBotProShielded, 'spacing': 50}, - {'type': ChargerBotProShielded, 'spacing': 50} - if self._preset == 'pro' else None, - {'type': ChargerBotProShielded, 'spacing': 50} + Bot(ChargerBot, spacing=30), + ]), + Wave(base_angle=90, + entries=[ + Bot(StickyBot, spacing=50), + Bot(StickyBot, spacing=50) + if self._preset is Preset.PRO else None, + Bot(StickyBot, spacing=50), + Bot(StickyBot, spacing=50) if player_count > 1 else None, - {'type': ChargerBotProShielded, 'spacing': 50} + Bot(StickyBot, spacing=50) + if player_count > 3 else None, + ]), + Wave(base_angle=0, + entries=[ + Bot(TriggerBot, spacing=72), + Bot(TriggerBot, spacing=72), + Bot(TriggerBot, spacing=72) + if self._preset is Preset.PRO else None, + Bot(TriggerBot, spacing=72), + Bot(TriggerBot, spacing=72), + Bot(TriggerBot, spacing=36) if player_count > 2 else None, - ]} - ] # yapf: disable + ]), + Wave(base_angle=30, + entries=[ + Bot(ChargerBotProShielded, spacing=50), + Bot(ChargerBotProShielded, spacing=50), + Bot(ChargerBotProShielded, spacing=50) + if self._preset is Preset.PRO else None, + Bot(ChargerBotProShielded, spacing=50) + if player_count > 1 else None, + Bot(ChargerBotProShielded, spacing=50) + if player_count > 2 else None, + ]) + ] - elif self._preset in ['uber', 'uber_easy']: + elif self._preset in {Preset.UBER, Preset.UBER_EASY}: # Show controls help in kiosk mode. if ba.app.kiosk_mode: @@ -395,95 +460,75 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): bright=True).autoretain() self._have_tnt = True - self._excludepowerups = [] + self._excluded_powerups = [] self._waves = [ - {'entries': [ - {'type': BomberBotProStatic, - 'point': 'turret_top_middle_left'} - if hard else None, - {'type': BomberBotProStatic, - 'point': 'turret_top_middle_right'}, - {'type': BomberBotProStatic, - 'point': 'turret_top_left'} - if player_count > 2 else None, - {'type': ExplodeyBot, 'point': 'top_right'}, - {'type': 'delay', 'duration': 4.0}, - {'type': ExplodeyBot, 'point': 'top_left'}, - ]}, - {'entries': [ - {'type': ChargerBot, 'point': 'left'}, - {'type': ChargerBot, 'point': 'right'}, - {'type': ChargerBot, 'point': 'right_upper_more'} - if player_count > 2 else None, - {'type': BomberBotProStatic, - 'point': 'turret_top_left'}, - {'type': BomberBotProStatic, - 'point': 'turret_top_right'}, - ]}, - {'entries': [ - {'type': TriggerBotPro, 'point': 'top_right'}, - {'type': TriggerBotPro, - 'point': 'right_upper_more'} - if player_count > 1 else None, - {'type': TriggerBotPro, 'point': 'right_upper'}, - {'type': TriggerBotPro, 'point': 'right_lower'} - if hard else None, - {'type': TriggerBotPro, - 'point': 'right_lower_more'} - if player_count > 2 else None, - {'type': TriggerBotPro, 'point': 'bottom_right'}, - ]}, - {'entries': [ - {'type': ChargerBotProShielded, - 'point': 'bottom_right'}, - {'type': ChargerBotProShielded, 'point': 'bottom'} - if player_count > 2 else None, - {'type': ChargerBotProShielded, - 'point': 'bottom_left'}, - {'type': ChargerBotProShielded, 'point': 'top'} - if hard else None, - {'type': BomberBotProStatic, - 'point': 'turret_top_middle'}, - ]}, - {'entries': [ - {'type': ExplodeyBot, 'point': 'left_upper'}, - {'type': 'delay', 'duration': 1.0}, - {'type': BrawlerBotProShielded, - 'point': 'left_lower'}, - {'type': BrawlerBotProShielded, - 'point': 'left_lower_more'}, - {'type': 'delay', 'duration': 4.0}, - {'type': ExplodeyBot, 'point': 'right_upper'}, - {'type': 'delay', 'duration': 1.0}, - {'type': BrawlerBotProShielded, - 'point': 'right_lower'}, - {'type': BrawlerBotProShielded, - 'point': 'right_upper_more'}, - {'type': 'delay', 'duration': 4.0}, - {'type': ExplodeyBot, 'point': 'left'}, - {'type': 'delay', 'duration': 5.0}, - {'type': ExplodeyBot, 'point': 'right'}, - ]}, - {'entries': [ - {'type': BomberBotProStatic, - 'point': 'turret_top_left'}, - {'type': BomberBotProStatic, - 'point': 'turret_top_right'}, - {'type': BomberBotProStatic, - 'point': 'turret_bottom_left'}, - {'type': BomberBotProStatic, - 'point': 'turret_bottom_right'}, - {'type': BomberBotProStatic, - 'point': 'turret_top_middle_left'} if hard else None, - {'type': BomberBotProStatic, - 'point': 'turret_top_middle_right'} if hard else None, - ] - }] # yapf: disable + Wave(entries=[ + Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT + ) if hard else None, + Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT), + Bot(BomberBotProStatic, Point.TURRET_TOP_LEFT + ) if player_count > 2 else None, + Bot(ExplodeyBot, Point.TOP_RIGHT), + Delay(4.0), + Bot(ExplodeyBot, Point.TOP_LEFT), + ]), + Wave(entries=[ + Bot(ChargerBot, Point.LEFT), + Bot(ChargerBot, Point.RIGHT), + Bot(ChargerBot, Point.RIGHT_UPPER_MORE + ) if player_count > 2 else None, + Bot(BomberBotProStatic, Point.TURRET_TOP_LEFT), + Bot(BomberBotProStatic, Point.TURRET_TOP_RIGHT), + ]), + Wave(entries=[ + Bot(TriggerBotPro, Point.TOP_RIGHT), + Bot(TriggerBotPro, Point.RIGHT_UPPER_MORE + ) if player_count > 1 else None, + Bot(TriggerBotPro, Point.RIGHT_UPPER), + Bot(TriggerBotPro, Point.RIGHT_LOWER) if hard else None, + Bot(TriggerBotPro, Point.RIGHT_LOWER_MORE + ) if player_count > 2 else None, + Bot(TriggerBotPro, Point.BOTTOM_RIGHT), + ]), + Wave(entries=[ + Bot(ChargerBotProShielded, Point.BOTTOM_RIGHT), + Bot(ChargerBotProShielded, Point.BOTTOM + ) if player_count > 2 else None, + Bot(ChargerBotProShielded, Point.BOTTOM_LEFT), + Bot(ChargerBotProShielded, Point.TOP) if hard else None, + Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE), + ]), + Wave(entries=[ + Bot(ExplodeyBot, Point.LEFT_UPPER), + Delay(1.0), + Bot(BrawlerBotProShielded, Point.LEFT_LOWER), + Bot(BrawlerBotProShielded, Point.LEFT_LOWER_MORE), + Delay(4.0), + Bot(ExplodeyBot, Point.RIGHT_UPPER), + Delay(1.0), + Bot(BrawlerBotProShielded, Point.RIGHT_LOWER), + Bot(BrawlerBotProShielded, Point.RIGHT_UPPER_MORE), + Delay(4.0), + Bot(ExplodeyBot, Point.LEFT), + Delay(5.0), + Bot(ExplodeyBot, Point.RIGHT), + ]), + Wave(entries=[ + Bot(BomberBotProStatic, Point.TURRET_TOP_LEFT), + Bot(BomberBotProStatic, Point.TURRET_TOP_RIGHT), + Bot(BomberBotProStatic, Point.TURRET_BOTTOM_LEFT), + Bot(BomberBotProStatic, Point.TURRET_BOTTOM_RIGHT), + Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT + ) if hard else None, + Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT + ) if hard else None, + ]) + ] # We generate these on the fly in endless. - elif self._preset in ['endless', 'endless_tournament']: + elif self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: self._have_tnt = True - self._excludepowerups = [] + self._excluded_powerups = [] self._waves = [] else: @@ -492,11 +537,11 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # FIXME: Should migrate to use setup_standard_powerup_drops(). # Spit out a few powerups and start dropping more shortly. - self._drop_powerups( - standard_points=True, - poweruptype='curse' if self._preset in ['uber', 'uber_easy'] else - ('land_mines' - if self._preset in ['rookie', 'rookie_easy'] else None)) + self._drop_powerups(standard_points=True, + poweruptype='curse' if self._preset + in [Preset.UBER, Preset.UBER_EASY] else + ('land_mines' if self._preset + in [Preset.ROOKIE, Preset.ROOKIE_EASY] else None)) ba.timer(4.0, self._start_powerup_drops) # Our TNT spawner (if applicable). @@ -631,14 +676,15 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def spawn_player(self, player: Player) -> ba.Actor: # We keep track of who got hurt each wave for score purposes. - player.gamedata['has_been_hurt'] = False + player.has_been_hurt = False pos = (self._spawn_center[0] + random.uniform(-1.5, 1.5), self._spawn_center[1], self._spawn_center[2] + random.uniform(-1.5, 1.5)) spaz = self.spawn_player_spaz(player, position=pos) - if self._preset in [ - 'training_easy', 'rookie_easy', 'pro_easy', 'uber_easy' - ]: + if self._preset in { + Preset.TRAINING_EASY, Preset.ROOKIE_EASY, Preset.PRO_EASY, + Preset.UBER_EASY + }: spaz.impact_scale = 0.25 spaz.add_dropped_bomb_callback(self._handle_player_dropped_bomb) return spaz @@ -649,11 +695,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._player_has_dropped_bomb = True def _drop_powerup(self, index: int, poweruptype: str = None) -> None: - from bastd.actor import powerupbox - poweruptype = (powerupbox.get_factory().get_random_powerup_type( - forcetype=poweruptype, excludetypes=self._excludepowerups)) - powerupbox.PowerupBox(position=self.map.powerup_spawn_points[index], - poweruptype=poweruptype).autoretain() + poweruptype = (PowerupBoxFactory.get().get_random_powerup_type( + forcetype=poweruptype, excludetypes=self._excluded_powerups)) + PowerupBox(position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype).autoretain() def _start_powerup_drops(self) -> None: self._powerup_drop_timer = ba.Timer(3.0, @@ -664,7 +709,6 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): standard_points: bool = False, poweruptype: str = None) -> None: """Generic powerup drop.""" - from bastd.actor import powerupbox if standard_points: points = self.map.powerup_spawn_points for i in range(len(points)): @@ -680,10 +724,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): -self._powerup_spread[1], self._powerup_spread[1])) # Drop one random one somewhere. - powerupbox.PowerupBox( + PowerupBox( position=point, - poweruptype=powerupbox.get_factory().get_random_powerup_type( - excludetypes=self._excludepowerups)).autoretain() + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( + excludetypes=self._excluded_powerups)).autoretain() def do_end(self, outcome: str, delay: float = 0.0) -> None: """End the game with the specified outcome.""" @@ -705,9 +749,23 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): }, delay=delay) + def _award_completion_achievements(self) -> None: + if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}: + self._award_achievement('Onslaught Training Victory', sound=False) + if not self._player_has_dropped_bomb: + self._award_achievement('Boxer', sound=False) + elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: + self._award_achievement('Rookie Onslaught Victory', sound=False) + if not self._a_player_has_been_hurt: + self._award_achievement('Flawless Victory', sound=False) + elif self._preset in {Preset.PRO, Preset.PRO_EASY}: + self._award_achievement('Pro Onslaught Victory', sound=False) + if not self._player_has_dropped_bomb: + self._award_achievement('Pro Boxer', sound=False) + elif self._preset in {Preset.UBER, Preset.UBER_EASY}: + self._award_achievement('Uber Onslaught Victory', sound=False) + def _update_waves(self) -> None: - # pylint: disable=too-many-branches - # pylint: disable=too-many-statements # If we have no living bots, go to the next wave. assert self._bots is not None @@ -716,15 +774,14 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._can_end_wave = False self._time_bonus_timer = None self._time_bonus_text = None - if self._preset in ['endless', 'endless_tournament']: + if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: won = False else: - assert self._waves is not None won = (self._wave == len(self._waves)) - # Reward time bonus. base_delay = 4.0 if won else 0.0 + # Reward time bonus. if self._time_bonus > 0: ba.timer(0, lambda: ba.playsound(self._cashregistersound)) ba.timer(base_delay, @@ -735,13 +792,12 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if self._wave > 0: have_flawless = False for player in self.players: - if (player.is_alive() - and not player.gamedata['has_been_hurt']): + if player.is_alive() and not player.has_been_hurt: have_flawless = True ba.timer( base_delay, ba.WeakCall(self._award_flawless_bonus, player)) - player.gamedata['has_been_hurt'] = False # reset + player.has_been_hurt = False # reset if have_flawless: base_delay += 1.0 @@ -751,26 +807,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): duration=4.0) self.celebrate(20.0) - # Rookie onslaught completion. - if self._preset in ['training', 'training_easy']: - self._award_achievement('Onslaught Training Victory', - sound=False) - if not self._player_has_dropped_bomb: - self._award_achievement('Boxer', sound=False) - elif self._preset in ['rookie', 'rookie_easy']: - self._award_achievement('Rookie Onslaught Victory', - sound=False) - if not self._a_player_has_been_hurt: - self._award_achievement('Flawless Victory', - sound=False) - elif self._preset in ['pro', 'pro_easy']: - self._award_achievement('Pro Onslaught Victory', - sound=False) - if not self._player_has_dropped_bomb: - self._award_achievement('Pro Boxer', sound=False) - elif self._preset in ['uber', 'uber_easy']: - self._award_achievement('Uber Onslaught Victory', - sound=False) + self._award_completion_achievements() ba.timer(base_delay, ba.WeakCall(self._award_completion_bonus)) base_delay += 0.85 @@ -809,16 +846,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): ba.print_exception() def _award_time_bonus(self, bonus: int) -> None: - from bastd.actor import popuptext ba.playsound(self._cashregistersound) - popuptext.PopupText(ba.Lstr(value='+${A} ${B}', - subs=[('${A}', str(bonus)), - ('${B}', - ba.Lstr(resource='timeBonusText')) - ]), - color=(1, 1, 0.5, 1), - scale=1.0, - position=(0, 3, -1)).autoretain() + PopupText(ba.Lstr(value='+${A} ${B}', + subs=[('${A}', str(bonus)), + ('${B}', ba.Lstr(resource='timeBonusText'))]), + color=(1, 1, 0.5, 1), + scale=1.0, + position=(0, 3, -1)).autoretain() self._score += self._time_bonus self._update_scores() @@ -852,10 +886,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): else: text: Union[str, ba.Lstr] = '' for player in self.players: - assert self._waves is not None - if (not player.is_alive() and - (self._preset in ['endless', 'endless_tournament'] or - (player.respawn_wave <= len(self._waves)))): + if (not player.is_alive() + and (self._preset + in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] or + (player.respawn_wave <= len(self._waves)))): rtxt = ba.Lstr(resource='onslaughtRespawnText', subs=[('${PLAYER}', player.get_name()), ('${WAVE}', str(player.respawn_wave)) @@ -867,18 +901,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): ]) self._spawn_info_text.node.text = text - def _start_next_wave(self) -> None: - - # FIXME; tidy up - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements - # pylint: disable=too-many-branches - - # This could happen if we beat a wave as we die. - # We don't wanna respawn players and whatnot if this happens. - if self._game_over: - return - + def _respawn_players_for_wave(self) -> None: # Respawn applicable players. if self._wave > 1 and not self.is_waiting_for_continue(): for player in self.players: @@ -886,14 +909,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): and player.respawn_wave == self._wave): self.spawn_player(player) self._update_player_spawn_info() - self.show_zoom_message(ba.Lstr(value='${A} ${B}', - subs=[('${A}', - ba.Lstr(resource='waveText')), - ('${B}', str(self._wave))]), - scale=1.0, - duration=1.0, - trail=True) - ba.timer(0.4, ba.Call(ba.playsound, self._new_wave_sound)) + + def _setup_wave_spawns(self, wave: Wave) -> None: tval = 0.0 dtime = 0.2 if self._wave == 1: @@ -902,132 +919,34 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): else: spawn_time = 2.648 - # Populate waves: - - # Generate random waves in endless mode. - wave: Dict[str, Any] - if self._preset in ['endless', 'endless_tournament']: - level = self._wave - bot_types2 = [ - BomberBot, BrawlerBot, TriggerBot, ChargerBot, BomberBotPro, - BrawlerBotPro, TriggerBotPro, BomberBotProShielded, - ExplodeyBot, ChargerBotProShielded, StickyBot, - BrawlerBotProShielded, TriggerBotProShielded - ] - if level > 5: - bot_types2 += [ - ExplodeyBot, - TriggerBotProShielded, - BrawlerBotProShielded, - ChargerBotProShielded, - ] - if level > 7: - bot_types2 += [ - ExplodeyBot, - TriggerBotProShielded, - BrawlerBotProShielded, - ChargerBotProShielded, - ] - if level > 10: - bot_types2 += [ - TriggerBotProShielded, TriggerBotProShielded, - TriggerBotProShielded, TriggerBotProShielded - ] - if level > 13: - bot_types2 += [ - TriggerBotProShielded, TriggerBotProShielded, - TriggerBotProShielded, TriggerBotProShielded - ] - - bot_levels = [[b for b in bot_types2 if b.points_mult == 1], - [b for b in bot_types2 if b.points_mult == 2], - [b for b in bot_types2 if b.points_mult == 3], - [b for b in bot_types2 if b.points_mult == 4]] - - # Make sure all lists have something in them - if not all(bot_levels): - raise Exception() - - target_points = level * 3 - 2 - min_dudes = min(1 + level // 3, 10) - max_dudes = min(10, level + 1) - max_level = 4 if level > 6 else (3 if level > 3 else - (2 if level > 2 else 1)) - group_count = 3 - distribution = self._get_distribution(target_points, min_dudes, - max_dudes, group_count, - max_level) - - all_entries: List[Optional[Dict[str, Any]]] = [] - for group in distribution: - entries: List[Optional[Dict[str, Any]]] = [] - for entry in group: - bot_level = bot_levels[entry[0] - 1] - bot_type = bot_level[random.randrange(len(bot_level))] - rval = random.random() - if rval < 0.5: - spacing = 10 - elif rval < 0.9: - spacing = 20 - else: - spacing = 40 - split = random.random() > 0.3 - for i in range(entry[1]): - if split and i % 2 == 0: - entries.insert(0, { - 'type': bot_type, - 'spacing': spacing - }) - else: - entries.append({ - 'type': bot_type, - 'spacing': spacing - }) - if entries: - all_entries += entries - all_entries.append({ - 'type': None, - 'spacing': 40 if random.random() < 0.5 else 80 - }) - - angle_rand = random.random() - if angle_rand > 0.75: - base_angle = 130.0 - elif angle_rand > 0.5: - base_angle = 210.0 - elif angle_rand > 0.25: - base_angle = 20.0 - else: - base_angle = -30.0 - base_angle += (0.5 - random.random()) * 20.0 - wave = {'base_angle': base_angle, 'entries': all_entries} - else: - assert self._waves is not None - wave = self._waves[self._wave - 1] - entries = [] - bot_angle = wave.get('base_angle', 0.0) - entries += wave['entries'] - this_time_bonus = 0 - this_flawless_bonus = 0 - for info in entries: + bot_angle = wave.base_angle + self._time_bonus = 0 + self._flawless_bonus = 0 + for info in wave.entries: if info is None: continue - bot_type_2 = info['type'] - if bot_type_2 == 'delay': - spawn_time += info['duration'] + if isinstance(info, Delay): + spawn_time += info.duration continue + if isinstance(info, Spacing): + bot_angle += info.spacing + continue + bot_type_2 = info.bottype if bot_type_2 is not None: - this_time_bonus += bot_type_2.points_mult * 20 - this_flawless_bonus += bot_type_2.points_mult * 5 - # if its got a position, use that - point = info.get('point', None) + assert not isinstance(bot_type_2, str) + self._time_bonus += bot_type_2.points_mult * 20 + self._flawless_bonus += bot_type_2.points_mult * 5 + + # If its got a position, use that. + point = info.point if point is not None: + assert bot_type_2 is not None spcall = ba.WeakCall(self.add_bot_at_point, point, bot_type_2, spawn_time) ba.timer(tval, spcall) tval += dtime else: - spacing = info.get('spacing', 5.0) + spacing = info.spacing bot_angle += spacing * 0.5 if bot_type_2 is not None: tcall = ba.WeakCall(self.add_bot_at_angle, bot_angle, @@ -1040,9 +959,33 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): ba.timer(tval + spawn_time - dtime + 0.01, ba.WeakCall(self._set_can_end_wave)) + def _start_next_wave(self) -> None: + + # This can happen if we beat a wave as we die. + # We don't wanna respawn players and whatnot if this happens. + if self._game_over: + return + + self._respawn_players_for_wave() + if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: + wave = self._generate_random_wave() + else: + wave = self._waves[self._wave - 1] + self._setup_wave_spawns(wave) + self._update_wave_ui_and_bonuses() + ba.timer(0.4, ba.Call(ba.playsound, self._new_wave_sound)) + + def _update_wave_ui_and_bonuses(self) -> None: + + self.show_zoom_message(ba.Lstr(value='${A} ${B}', + subs=[('${A}', + ba.Lstr(resource='waveText')), + ('${B}', str(self._wave))]), + scale=1.0, + duration=1.0, + trail=True) + # Reset our time bonus. - self._time_bonus = this_time_bonus - self._flawless_bonus = this_flawless_bonus tbtcolor = (1, 1, 0, 1) tbttxt = ba.Lstr(value='${A}: ${B}', subs=[ @@ -1066,15 +1009,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): ba.timer(5.0, ba.WeakCall(self._start_time_bonus_timer)) wtcolor = (1, 1, 1, 1) - assert self._waves is not None wttxt = ba.Lstr( value='${A} ${B}', - subs=[ - ('${A}', ba.Lstr(resource='waveText')), - ('${B}', str(self._wave) + - ('' if self._preset in ['endless', 'endless_tournament'] else - ('/' + str(len(self._waves))))) - ]) + subs=[('${A}', ba.Lstr(resource='waveText')), + ('${B}', str(self._wave) + + ('' if self._preset + in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] else + ('/' + str(len(self._waves)))))]) self._wave_text = ba.NodeActor( ba.newnode('text', attrs={ @@ -1090,14 +1031,112 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): 'text': wttxt })) + def _bot_levels_for_wave(self) -> List[List[Type[SpazBot]]]: + level = self._wave + bot_types = [ + BomberBot, BrawlerBot, TriggerBot, ChargerBot, BomberBotPro, + BrawlerBotPro, TriggerBotPro, BomberBotProShielded, ExplodeyBot, + ChargerBotProShielded, StickyBot, BrawlerBotProShielded, + TriggerBotProShielded + ] + if level > 5: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 7: + bot_types += [ + ExplodeyBot, + TriggerBotProShielded, + BrawlerBotProShielded, + ChargerBotProShielded, + ] + if level > 10: + bot_types += [ + TriggerBotProShielded, TriggerBotProShielded, + TriggerBotProShielded, TriggerBotProShielded + ] + if level > 13: + bot_types += [ + TriggerBotProShielded, TriggerBotProShielded, + TriggerBotProShielded, TriggerBotProShielded + ] + bot_levels = [[b for b in bot_types if b.points_mult == 1], + [b for b in bot_types if b.points_mult == 2], + [b for b in bot_types if b.points_mult == 3], + [b for b in bot_types if b.points_mult == 4]] + # Make sure all lists have something in them + if not all(bot_levels): + raise RuntimeError('Got empty bot level') + return bot_levels + + def _add_entries_for_distribution_group( + self, group: List[Tuple[int, int]], + bot_levels: List[List[Type[SpazBot]]], + all_entries: List[Union[Bot, Spacing, Delay, None]]) -> None: + entries: List[Union[Bot, Spacing, Delay, None]] = [] + for entry in group: + bot_level = bot_levels[entry[0] - 1] + bot_type = bot_level[random.randrange(len(bot_level))] + rval = random.random() + if rval < 0.5: + spacing = 10.0 + elif rval < 0.9: + spacing = 20.0 + else: + spacing = 40.0 + split = random.random() > 0.3 + for i in range(entry[1]): + if split and i % 2 == 0: + entries.insert(0, Bot(bot_type, spacing=spacing)) + else: + entries.append(Bot(bot_type, spacing=spacing)) + if entries: + all_entries += entries + all_entries.append( + Spacing(40.0 if random.random() < 0.5 else 80.0)) + + def _generate_random_wave(self) -> Wave: + level = self._wave + bot_levels = self._bot_levels_for_wave() + + target_points = level * 3 - 2 + min_dudes = min(1 + level // 3, 10) + max_dudes = min(10, level + 1) + max_level = 4 if level > 6 else (3 if level > 3 else + (2 if level > 2 else 1)) + group_count = 3 + distribution = self._get_distribution(target_points, min_dudes, + max_dudes, group_count, + max_level) + all_entries: List[Union[Bot, Spacing, Delay, None]] = [] + for group in distribution: + self._add_entries_for_distribution_group(group, bot_levels, + all_entries) + angle_rand = random.random() + if angle_rand > 0.75: + base_angle = 130.0 + elif angle_rand > 0.5: + base_angle = 210.0 + elif angle_rand > 0.25: + base_angle = 20.0 + else: + base_angle = -30.0 + base_angle += (0.5 - random.random()) * 20.0 + wave = Wave(base_angle=base_angle, entries=all_entries) + return wave + def add_bot_at_point(self, - point: str, + point: Point, spaz_type: Type[SpazBot], spawn_time: float = 1.0) -> None: """Add a new bot at a specified named point.""" if self._game_over: return - pointpos = self.map.defs.points['bot_spawn_' + point] + assert isinstance(point.value, str) + pointpos = self.map.defs.points['bot_spawn_' + point.value] assert self._bots is not None self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) @@ -1133,7 +1172,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _update_scores(self) -> None: score = self._score - if self._preset == 'endless': + if self._preset is Preset.ENDLESS: if score >= 500: self._award_achievement('Onslaught Master') if score >= 1000: @@ -1145,10 +1184,6 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: - # FIXME; tidy this up - # pylint: disable=too-many-statements - # pylint: disable=too-many-branches - if isinstance(msg, PlayerSpazHurtMessage): player = msg.spaz.getplayer(Player, doraise=True) player.has_been_hurt = True @@ -1176,52 +1211,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): elif isinstance(msg, SpazBotDeathMessage): pts, importance = msg.badguy.get_death_points(msg.how) if msg.killerplayer is not None: - - # Toss-off-map achievement: - if self._preset in ['training', 'training_easy']: - if msg.badguy.last_attacked_type == ('picked_up', - 'default'): - self._throw_off_kills += 1 - if self._throw_off_kills >= 3: - self._award_achievement('Off You Go Then') - - # Land-mine achievement: - elif self._preset in ['rookie', 'rookie_easy']: - if msg.badguy.last_attacked_type == ('explosion', - 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 3: - self._award_achievement('Mine Games') - - # TNT achievement: - elif self._preset in ['pro', 'pro_easy']: - if msg.badguy.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 3: - ba.timer( - 0.5, - ba.WeakCall(self._award_achievement, - 'Boom Goes the Dynamite')) - - elif self._preset in ['uber', 'uber_easy']: - - # Uber mine achievement: - if msg.badguy.last_attacked_type == ('explosion', - 'land_mine'): - if not hasattr(self, '_land_mine_kills'): - self._land_mine_kills = 0 - self._land_mine_kills += 1 - if self._land_mine_kills >= 6: - self._award_achievement('Gold Miner') - - # Uber tnt achievement: - if msg.badguy.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 6: - ba.timer( - 0.5, - ba.WeakCall(self._award_achievement, - 'TNT Terror')) + self._handle_kill_achievements(msg) target: Optional[Sequence[float]] try: @@ -1252,6 +1242,48 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): else: super().handlemessage(msg) + def _handle_kill_achievements(self, msg: SpazBotDeathMessage) -> None: + # pylint: disable=too-many-branches + # Toss-off-map achievement: + if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}: + if msg.badguy.last_attacked_type == ('picked_up', 'default'): + self._throw_off_kills += 1 + if self._throw_off_kills >= 3: + self._award_achievement('Off You Go Then') + + # Land-mine achievement: + elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: + if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 3: + self._award_achievement('Mine Games') + + # TNT achievement: + elif self._preset in {Preset.PRO, Preset.PRO_EASY}: + if msg.badguy.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 3: + ba.timer( + 0.5, + ba.WeakCall(self._award_achievement, + 'Boom Goes the Dynamite')) + + elif self._preset in {Preset.UBER, Preset.UBER_EASY}: + + # Uber mine achievement: + if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 6: + self._award_achievement('Gold Miner') + + # Uber tnt achievement: + if msg.badguy.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 6: + ba.timer( + 0.5, ba.WeakCall(self._award_achievement, + 'TNT Terror')) + def _set_can_end_wave(self) -> None: self._can_end_wave = True diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 8b382cac..46dc7f02 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -33,6 +33,7 @@ from bastd.actor import spazbot from bastd.actor.bomb import TNTSpawner from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon +from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory if TYPE_CHECKING: from typing import Type, Any, List, Dict, Tuple, Sequence, Optional @@ -482,12 +483,11 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._player_has_picked_up_powerup = True def _drop_powerup(self, index: int, poweruptype: str = None) -> None: - from bastd.actor import powerupbox if poweruptype is None: - poweruptype = (powerupbox.get_factory().get_random_powerup_type( + poweruptype = (PowerupBoxFactory.get().get_random_powerup_type( excludetypes=self._exclude_powerups)) - powerupbox.PowerupBox(position=self.map.powerup_spawn_points[index], - poweruptype=poweruptype).autoretain() + PowerupBox(position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype).autoretain() def _start_powerup_drops(self) -> None: ba.timer(3.0, self._drop_powerups, repeat=True) @@ -496,7 +496,6 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): standard_points: bool = False, force_first: str = None) -> None: """ Generic powerup drop """ - from bastd.actor import powerupbox # If its been a minute since our last wave finished emerging, stop # giving out land-mine powerups. (prevents players from waiting @@ -522,9 +521,9 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): # drop one random one somewhere.. assert self._exclude_powerups is not None - powerupbox.PowerupBox( + PowerupBox( position=pos, - poweruptype=powerupbox.get_factory().get_random_powerup_type( + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( excludetypes=self._exclude_powerups + extra_excludes)).autoretain() diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index c842750e..ea34c785 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -71,6 +71,7 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): 'default': True }), ] + default_music = ba.MusicType.FORWARD_MARCH @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: @@ -92,9 +93,6 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): self._enable_impact_bombs = bool(settings['Enable Impact Bombs']) self._enable_triple_bombs = bool(settings['Enable Triple Bombs']) - # Base class overrides - self.default_music = ba.MusicType.FORWARD_MARCH - def on_team_join(self, team: Team) -> None: if self.has_begun(): self.update_scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index e651aae7..14c3f54e 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -30,6 +30,7 @@ from bastd.actor import spazbot from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.bomb import TNTSpawner from bastd.actor.scoreboard import Scoreboard +from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox if TYPE_CHECKING: from typing import Any, Dict, Type, List, Optional, Sequence @@ -137,12 +138,11 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): ba.WeakCall(self._update_bots)) def _drop_powerup(self, index: int, poweruptype: str = None) -> None: - from bastd.actor import powerupbox if poweruptype is None: - poweruptype = (powerupbox.get_factory().get_random_powerup_type( + poweruptype = (PowerupBoxFactory.get().get_random_powerup_type( excludetypes=self._excludepowerups)) - powerupbox.PowerupBox(position=self.map.powerup_spawn_points[index], - poweruptype=poweruptype).autoretain() + PowerupBox(position=self.map.powerup_spawn_points[index], + poweruptype=poweruptype).autoretain() def _start_powerup_drops(self) -> None: self._powerup_drop_timer = ba.Timer(3.0, @@ -171,7 +171,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): # Drop one random one somewhere. powerupbox.PowerupBox( position=drop_pt, - poweruptype=powerupbox.get_factory().get_random_powerup_type( + poweruptype=PowerupBoxFactory.get().get_random_powerup_type( excludetypes=self._excludepowerups)).autoretain() def do_end(self, outcome: str) -> None: diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index ad071ec1..1856296c 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -858,8 +858,8 @@ def _preload1() -> None: ]: ba.gettexture(tex) ba.gettexture('bg') - from bastd.actor import powerupbox - powerupbox.get_factory() + from bastd.actor.powerupbox import PowerupBoxFactory + PowerupBoxFactory.get() ba.timer(0.1, _preload2) diff --git a/docs/ba_module.md b/docs/ba_module.md index 795b4dea..943b679a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-23 for Ballistica version 1.5.0 build 20026

    +

    last updated on 2020-05-24 for Ballistica version 1.5.0 build 20026

    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!


    From 808ea7dcdd8bc0139a55a8e12e54e33c40119f34 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 25 May 2020 01:55:30 -0700 Subject: [PATCH 045/417] More modernizing and cleanup --- .efrocachemap | 28 +- .idea/dictionaries/ericf.xml | 5 + assets/.asset_manifest_public.json | 2 + assets/Makefile | 7 + assets/src/ba_data/python/_ba.py | 30 +- assets/src/ba_data/python/ba/__init__.py | 15 +- assets/src/ba_data/python/ba/_activity.py | 23 +- assets/src/ba_data/python/ba/_collision.py | 84 ++++ assets/src/ba_data/python/ba/_gameutils.py | 1 - assets/src/ba_data/python/ba/_player.py | 1 - assets/src/ba_data/python/ba/_powerup.py | 1 + assets/src/ba_data/python/bastd/actor/bomb.py | 62 ++- assets/src/ba_data/python/bastd/actor/flag.py | 25 +- .../ba_data/python/bastd/actor/powerupbox.py | 8 +- assets/src/ba_data/python/bastd/actor/spaz.py | 12 +- .../src/ba_data/python/bastd/actor/spazbot.py | 15 +- .../src/ba_data/python/bastd/game/assault.py | 13 +- .../python/bastd/game/capturetheflag.py | 52 +-- .../ba_data/python/bastd/game/chosenone.py | 9 +- .../src/ba_data/python/bastd/game/conquest.py | 16 +- .../python/bastd/game/easteregghunt.py | 85 ++-- .../src/ba_data/python/bastd/game/football.py | 116 +++-- .../src/ba_data/python/bastd/game/hockey.py | 18 +- .../python/bastd/game/kingofthehill.py | 6 +- .../ba_data/python/bastd/game/ninjafight.py | 6 +- .../ba_data/python/bastd/game/onslaught.py | 296 ++++++------ assets/src/ba_data/python/bastd/game/race.py | 14 +- .../ba_data/python/bastd/game/runaround.py | 425 +++++++++--------- .../ba_data/python/bastd/game/thelaststand.py | 74 ++- assets/src/ba_data/python/bastd/mainmenu.py | 4 +- assets/src/ba_data/python/bastd/ui/party.py | 1 - docs/ba_module.md | 76 +++- tests/test_efro/test_dataclasses.py | 1 - tests/test_efro/test_entity.py | 3 - tools/efro/entity/_entity.py | 1 - tools/efro/util.py | 2 +- 36 files changed, 820 insertions(+), 717 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_collision.py diff --git a/.efrocachemap b/.efrocachemap index 8c2365bf..8b7ec793 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/e2/2c/e609bb55002f672528428db9306c", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/da/06/8e06488b46a0a213abde3cfeb364", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/0c/cd/798753aa6c55f3a4cdccda0b23ab", @@ -442,7 +442,7 @@ "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/6c/35/cc4d440d0c7a613860c3898e81d7", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a9/bc/ea61ebd23066c685fb779e23d10f", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/78/5e/d24967ddaa15e0a574bd274544db", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/42/5238d5de1cf94a07a513ea2b3e1b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/48/2f0e4350a080373301de625e2cc4", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c0/1d/dbc0a5e2ca05b626cbeffd6def6c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/a8/5c58d6b5e1d844640334c35ad3af", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3d/0a/76b615f9bcb9bf4f0ca745060d40", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/6b/0f623ac481e3553e352c1cd3cb7e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c4/a5/3cad1ced77551369dc56c6bca5fb", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/3f/55094817619cae66f941a9f6db8c", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/6b/7aa29831a746672f9984cbb1dbf1", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/07/4c/00a6136d0bd5573946d10e294720", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/8d/af068e67244cbb28444b27ae66d7", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f4/62/eb7cb26c952df481b757dcf53f9c" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/f0/c3261a8a7391a2b654da82c35c21", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/33/e2/85a8cbf23404612e6761cf02348b", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/0d/d906be5fc2a75b5214a94cafe6ca", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/53/72d665caf5dfed84312ae6862642", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/68/2d98f2d1ee67b6d54adbdf76c863", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/3a/33f8f311260542126acea44d05e2", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/18/eb/dd39bcfa33983864089d3fb7f666", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/1d/3440010fcbcf18c5a6b2966f7fca", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9b/fa/b4ad4b8b82fefe1faad610065b9f", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7f/b9/03af92db6140135ddfa467a1545d", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/b9/687fc5fa38c3faf7a47eb4241a3c", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cf/2b/589db924b489972981e10850a4e3" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index fe3fd86d..898fe13e 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -416,6 +416,7 @@ deathmatch deek defs + defsline deivit depcls depdata @@ -749,6 +750,7 @@ getclass getcollide getcollidemodel + getcollision getconf getconfig getcurrency @@ -1285,6 +1287,7 @@ outname outpath ouya + overloadsigs packagedir packagedirs packagename @@ -1888,6 +1891,7 @@ toplevel totaldudes totalpts + totalwaves totype touchpad tournamententry @@ -2022,6 +2026,7 @@ waaah wanttype wasdead + wavenum weakref weakrefs weakrefset diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index 92c51171..fea31d89 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -13,6 +13,7 @@ "ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc", @@ -67,6 +68,7 @@ "ba_data/python/ba/_assetmanager.py", "ba_data/python/ba/_benchmark.py", "ba_data/python/ba/_campaign.py", + "ba_data/python/ba/_collision.py", "ba_data/python/ba/_coopgame.py", "ba_data/python/ba/_coopsession.py", "ba_data/python/ba/_dependency.py", diff --git a/assets/Makefile b/assets/Makefile index 82113061..c77bdbb8 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -153,6 +153,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_coopgame.py \ build/ba_data/python/ba/_meta.py \ build/ba_data/python/ba/_math.py \ + build/ba_data/python/ba/_collision.py \ build/ba_data/python/ba/_servermode.py \ build/ba_data/python/ba/_appconfig.py \ build/ba_data/python/ba/_gameresults.py \ @@ -380,6 +381,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \ @@ -663,6 +665,11 @@ build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_collision.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_servermode.py @echo Compiling script: $^ diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 30763c4a..6b593af3 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=146544975806995156523304218095856323339 +# SOURCES_HASH=164420280597992494471294420110866243586 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -51,16 +51,19 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. from __future__ import annotations -from typing import TYPE_CHECKING, overload, Sequence +from typing import TYPE_CHECKING, overload, Sequence, TypeVar from ba._enums import TimeFormat, TimeType if TYPE_CHECKING: from typing import (Any, Dict, Callable, Tuple, List, Optional, Union, List, Type) + from typing_extensions import Literal from ba._app import App import ba +_T = TypeVar('_T') + app: App @@ -713,13 +716,26 @@ class Node: """ return str() - def getdelegate(self) -> Any: - """getdelegate() -> Any + @overload + def getdelegate(self, + type: Type[_T], + doraise: Literal[False] = False) -> Optional[_T]: + ... - Returns the node's current delegate, which is the Python object - designated to handle the Node's messages. + @overload + def getdelegate(self, type: Type[_T], doraise: Literal[True]) -> _T: + ... + + def getdelegate(self, type: Any, doraise: bool = False) -> Any: + """getdelegate(type: Type, doraise: bool = False) -> + + Return the node's current delegate object if it matches a certain type. + + If the node has no delegate or it is not an instance of the passed + type, then None will be returned. If 'doraise' is True, then an + Exception will be raised instead in such cases. """ - return _uninferrable() + return None def getnodetype(self) -> str: """getnodetype() -> str diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 3435ad09..25869a72 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -30,13 +30,13 @@ In some specific cases you may need to pull in individual submodules instead. from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, Material, Model, Node, SessionPlayer, Sound, Texture, Timer, Vec3, Widget, buttonwidget, camerashake, checkboxwidget, - columnwidget, containerwidget, do_once, emitfx, - get_collision_info, getactivity, getcollidemodel, getmodel, - getnodes, getsession, getsound, gettexture, hscrollwidget, - imagewidget, log, new_activity, newnode, playsound, - printnodes, printobjects, pushcall, quit, rowwidget, - safecolor, screenmessage, scrollwidget, set_analytics_screen, - charstr, textwidget, time, timer, open_url, widget) + columnwidget, containerwidget, do_once, emitfx, getactivity, + getcollidemodel, getmodel, getnodes, getsession, getsound, + gettexture, hscrollwidget, imagewidget, log, new_activity, + newnode, playsound, printnodes, printobjects, pushcall, quit, + rowwidget, safecolor, screenmessage, scrollwidget, + set_analytics_screen, charstr, textwidget, time, timer, + open_url, widget) from ba._activity import Activity from ba._actor import Actor from ba._player import Player, playercast, playercast_o @@ -87,6 +87,7 @@ from ba._music import setmusic, MusicPlayer, MusicType, MusicPlayMode from ba._powerup import PowerupMessage, PowerupAcceptMessage from ba._multiteamsession import MultiTeamSession from ba.ui import Window, UIController, uicleanupcheck +from ba._collision import Collision, getcollision app: App diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 05f3508d..c372069d 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -343,7 +343,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): raise TypeError('non-actor passed to retain_actor') if (self.has_transitioned_in() and _ba.time() - self._last_prune_dead_actors_time > 10.0): - print_error('it looks like nodes/actors are not' + print_error('It looks like nodes/actors are not' ' being pruned in your activity;' ' did you call Activity.on_transition_in()' ' from your subclass?; ' + str(self) + ' (loc. a)') @@ -775,12 +775,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # Send expire notices to all remaining actors. for actor_ref in self._actor_weak_refs: - try: - actor = actor_ref() - if actor is not None: + actor = actor_ref() + if actor is not None: + try: actor.on_expire() - except Exception: - print_exception(f'Error expiring Actor {actor_ref()}') + except Exception: + print_exception(f'Error expiring Actor {actor_ref()}') # Reset all Players. # (releases any attached actors, clears game-data, etc) @@ -804,7 +804,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): sessionteam.reset_gamedata() except SessionTeamNotFoundError: pass - # print_exception(f'Error resetting Team {team}') except Exception: print_exception(f'Error resetting Team {team}') @@ -819,6 +818,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): 'Error during ba.Activity._expire() destroying data:') def _prune_dead_actors(self) -> None: - self._actor_refs = [a for a in self._actor_refs if a] - self._actor_weak_refs = [a for a in self._actor_weak_refs if a()] self._last_prune_dead_actors_time = _ba.time() + + # Prune our strong refs when the Actor's exists() call gives False + self._actor_refs = [a for a in self._actor_refs if a.exists()] + + # Prune our weak refs once the Actor object has been freed. + self._actor_weak_refs = [ + a for a in self._actor_weak_refs if a() is not None + ] diff --git a/assets/src/ba_data/python/ba/_collision.py b/assets/src/ba_data/python/ba/_collision.py new file mode 100644 index 00000000..b41aa104 --- /dev/null +++ b/assets/src/ba_data/python/ba/_collision.py @@ -0,0 +1,84 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Collision related functionality.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import _ba +from ba._error import NodeNotFoundError + +if TYPE_CHECKING: + import ba + + +class Collision: + """A class providing info about occurring collisions.""" + + @property + def position(self) -> ba.Vec3: + """The position of the current collision.""" + return _ba.Vec3(_ba.get_collision_info('position')) + + @property + def source_node(self) -> ba.Node: + """The node containing the material triggering the current callback. + + Throws a ba.NodeNotFoundError if the node does not exist, though + the node should always exist (at least at the start of the collision + callback). + """ + node = _ba.get_collision_info('source_node') + assert isinstance(node, (_ba.Node, type(None))) + if not node: + raise NodeNotFoundError() + return node + + @property + def opposing_node(self) -> ba.Node: + """The node the current callback material node is hitting. + + Throws a ba.NodeNotFoundError if the node does not exist. + This can be expected in some cases such as in 'disconnect' + callbacks triggered by deleting a currently-colliding node. + """ + node = _ba.get_collision_info('opposing_node') + assert isinstance(node, (_ba.Node, type(None))) + if not node: + raise NodeNotFoundError() + return node + + @property + def opposing_body(self) -> int: + """The body index on the opposing node in the current collision.""" + body = _ba.get_collision_info('opposing_body') + assert isinstance(body, int) + return body + + +# Simply recycle one instance... +_collision = Collision() + + +def getcollision() -> Collision: + """Return the in-progress collision.""" + return _collision diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 61b62458..fcaf3f4b 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -447,7 +447,6 @@ def cameraflash(duration: float = 999.0) -> None: # Store this on the current activity so we only have one at a time. # FIXME: Need a type safe way to do this. activity = _ba.getactivity() - # noinspection PyTypeHints activity.camera_flash_data = [] # type: ignore for i in range(6): light = NodeActor( diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 9df3e897..bc5c44bb 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -226,6 +226,5 @@ def playercast_o(totype: Type[PlayerType], Category: Gameplay Functions """ - # noinspection PyTypeHints assert isinstance(player, (totype, type(None))) return player diff --git a/assets/src/ba_data/python/ba/_powerup.py b/assets/src/ba_data/python/ba/_powerup.py index dbef03fb..0e3d2d83 100644 --- a/assets/src/ba_data/python/ba/_powerup.py +++ b/assets/src/ba_data/python/ba/_powerup.py @@ -19,6 +19,7 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Powerup related functionality.""" + from __future__ import annotations from typing import TYPE_CHECKING diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 7f362867..068dd7c9 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -265,7 +265,6 @@ class BombFactory: actions=('message', 'our_node', 'at_connect', SplatMessage())) -# noinspection PyTypeHints def get_factory() -> BombFactory: """Get/create a shared bastd.actor.bomb.BombFactory object.""" activity = ba.getactivity() @@ -602,34 +601,28 @@ class Blast(ba.Actor): self.node.delete() elif isinstance(msg, ExplodeHitMessage): - node = ba.get_collision_info('opposing_node') - if node: - assert self.node - nodepos = self.node.position + node = ba.getcollision().opposing_node + assert self.node + nodepos = self.node.position + mag = 2000.0 + if self.blast_type == 'ice': + mag *= 0.5 + elif self.blast_type == 'land_mine': + mag *= 2.5 + elif self.blast_type == 'tnt': + mag *= 2.0 - # new - mag = 2000.0 - if self.blast_type == 'ice': - mag *= 0.5 - elif self.blast_type == 'land_mine': - mag *= 2.5 - elif self.blast_type == 'tnt': - mag *= 2.0 - - node.handlemessage( - ba.HitMessage(pos=nodepos, - velocity=(0, 0, 0), - magnitude=mag, - hit_type=self.hit_type, - hit_subtype=self.hit_subtype, - radius=self.radius, - source_player=ba.existing( - self.source_player))) - if self.blast_type == 'ice': - ba.playsound(get_factory().freeze_sound, - 10, - position=nodepos) - node.handlemessage(ba.FreezeMessage()) + node.handlemessage( + ba.HitMessage(pos=nodepos, + velocity=(0, 0, 0), + magnitude=mag, + hit_type=self.hit_type, + hit_subtype=self.hit_subtype, + radius=self.radius, + source_player=ba.existing(self.source_player))) + if self.blast_type == 'ice': + ba.playsound(get_factory().freeze_sound, 10, position=nodepos) + node.handlemessage(ba.FreezeMessage()) else: super().handlemessage(msg) @@ -850,14 +843,13 @@ class Bomb(ba.Actor): self.handlemessage(ba.DieMessage()) def _handle_impact(self) -> None: - node = ba.get_collision_info('opposing_node') - # if we're an impact bomb and we came from this node, don't explode... + node = ba.getcollision().opposing_node + + # If we're an impact bomb and we came from this node, don't explode... # alternately if we're hitting another impact-bomb from the same # source, don't explode... - try: - node_delegate = node.getdelegate() - except Exception: - node_delegate = None + # try: + node_delegate = node.getdelegate(object) if node: if (self.bomb_type == 'impact' and (node is self.owner or @@ -883,7 +875,7 @@ class Bomb(ba.Actor): lambda: _safesetattr(self.node, 'stick_to_owner', True)) def _handle_splat(self) -> None: - node = ba.get_collision_info('opposing_node') + node = ba.getcollision().opposing_node if (node is not self.owner and ba.time() - self._last_sticky_sound_time > 1.0): self._last_sticky_sound_time = ba.time() diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index 31de6e7e..e06ea38a 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -105,19 +105,16 @@ class FlagFactory: self.flag_texture = ba.gettexture('flagColor') - -# noinspection PyTypeHints -def get_factory() -> FlagFactory: - """Get/create a shared bastd.actor.flag.FlagFactory object.""" - activity = ba.getactivity() - factory: FlagFactory - try: - # FIXME: Find elegant way to handle shared data like this. - factory = activity.shared_flag_factory # type: ignore - except Exception: - factory = activity.shared_flag_factory = FlagFactory() # type: ignore - assert isinstance(factory, FlagFactory) - return factory + @staticmethod + def get() -> FlagFactory: + """Get/create a shared FlagFactory instance.""" + activity = ba.getactivity() + factory = getattr(activity, 'shared_flag_factory', None) + if factory is None: + factory = FlagFactory() + setattr(activity, 'shared_flag_factory', factory) + assert isinstance(factory, FlagFactory) + return factory @dataclass @@ -201,7 +198,7 @@ class Flag(ba.Actor): self._initial_position: Optional[Sequence[float]] = None self._has_moved = False - factory = get_factory() + factory = FlagFactory.get() if materials is None: materials = [] diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py index f04fc25a..2bbe156b 100644 --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py @@ -305,11 +305,9 @@ class PowerupBox(ba.Actor): elif isinstance(msg, _TouchedMessage): if not self._powersgiven: - node = ba.get_collision_info('opposing_node') - if node: - node.handlemessage( - ba.PowerupMessage(self.poweruptype, - source_node=self.node)) + node = ba.getcollision().opposing_node + node.handlemessage( + ba.PowerupMessage(self.poweruptype, source_node=self.node)) elif isinstance(msg, ba.DieMessage): if self.node: diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index 5c599ec2..ba314e21 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -62,7 +62,6 @@ def get_factory() -> SpazFactory: activity = ba.getactivity() factory = getattr(activity, 'shared_spaz_factory', None) if factory is None: - # noinspection PyTypeHints factory = activity.shared_spaz_factory = SpazFactory() # type: ignore assert isinstance(factory, SpazFactory) return factory @@ -1144,7 +1143,7 @@ class Spaz(ba.Actor): elif isinstance(msg, PunchHitMessage): if not self.node: return None - node = ba.get_collision_info('opposing_node') + node = ba.getcollision().opposing_node # Only allow one hit per node per punch. if node and (node not in self._punched_nodes): @@ -1203,10 +1202,11 @@ class Spaz(ba.Actor): if not self.node: return None - opposing_node, opposing_body = ba.get_collision_info( - 'opposing_node', 'opposing_body') - - if opposing_node is None or not opposing_node: + try: + collision = ba.getcollision() + opposing_node = collision.opposing_node + opposing_body = collision.opposing_body + except ba.NotFoundError: return True # Don't allow picking up of invincible dudes. diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index 5457cb20..d86cc1b2 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -62,7 +62,7 @@ class SpazBotPunchedMessage: self.damage = damage -class SpazBotDeathMessage: +class SpazBotDiedMessage: """A message saying a ba.SpazBot has died. category: Message Classes @@ -98,7 +98,7 @@ class SpazBot(Spaz): navigate obstacles and so should only be used on wide-open maps. - When a SpazBot is killed, it delivers a ba.SpazBotDeathMessage + When a SpazBot is killed, it delivers a ba.SpazBotDiedMessage to the current activity. When a SpazBot is punched, it delivers a ba.SpazBotPunchedMessage @@ -569,7 +569,7 @@ class SpazBot(Spaz): killerplayer = None if activity is not None: activity.handlemessage( - SpazBotDeathMessage(self, killerplayer, msg.how)) + SpazBotDiedMessage(self, killerplayer, msg.how)) super().handlemessage(msg) # Augment standard behavior. # Keep track of the player who last hit us for point rewarding. @@ -894,7 +894,7 @@ class ExplodeyBotShielded(ExplodeyBot): points_mult = 5 -class BotSet: +class SpazBotSet: """A container/controller for one or more ba.SpazBots. category: Bot Classes @@ -963,9 +963,7 @@ class BotSet: def _update(self) -> None: # Update one of our bot lists each time through. - # First off, remove dead bots from the list. Note that we check - # exists() here via the bool operator instead of dead; we want to - # keep them around even if they're just a corpse. + # First off, remove no-longer-existing bots from the list. try: bot_list = self._bot_lists[self._bot_update_list] = ([ b for b in self._bot_lists[self._bot_update_list] if b @@ -982,6 +980,9 @@ class BotSet: for player in ba.getactivity().players: assert isinstance(player, ba.Player) try: + # TODO: could use abstracted player.position here so we + # don't have to assume their actor type, but we have no + # abstracted velocity as of yet. if player.is_alive(): assert isinstance(player.actor, Spaz) assert player.actor.node diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 6b402b88..7f2d814d 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -179,16 +179,9 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): ba.timer(length, light.delete) def _handle_base_collide(self, team: Team) -> None: - - # Attempt to pull a living ba.Player from what we hit. - cnode = ba.get_collision_info('opposing_node') - assert isinstance(cnode, ba.Node) - actor = cnode.getdelegate() - if not isinstance(actor, PlayerSpaz): - return - - player = actor.getplayer(Player) - if not player or not player.actor: + player = ba.getcollision().opposing_node.getdelegate( + PlayerSpaz, True).getplayer(Player) + if not player or not player.is_alive(): return # If its another team's player, they scored. diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index e99cb251..55d59a8e 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -28,15 +28,16 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -from bastd.actor import flag as stdflag from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard +from bastd.actor.flag import (FlagFactory, Flag, FlagPickedUpMessage, + FlagDroppedMessage, FlagDiedMessage) if TYPE_CHECKING: from typing import Any, Type, List, Dict, Sequence, Union, Optional -class CTFFlag(stdflag.Flag): +class CTFFlag(Flag): """Special flag type for CTF games.""" activity: CaptureTheFlagGame @@ -73,10 +74,7 @@ class CTFFlag(stdflag.Flag): @classmethod def from_node(cls, node: Optional[ba.Node]) -> Optional[CTFFlag]: """Attempt to get a CTFFlag from a flag node.""" - if not node: - return None - delegate = node.getdelegate() - return delegate if isinstance(delegate, CTFFlag) else None + return node.getdelegate(CTFFlag) if node else None class Player(ba.Player['Team']): @@ -246,8 +244,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # We wanna know when *any* flag enters/leaves our base. base_region_mat.add_actions( - conditions=('they_have_material', - stdflag.get_factory().flagmaterial), + conditions=('they_have_material', FlagFactory.get().flagmaterial), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', @@ -277,9 +274,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._swipsound, position=team.flag.node.position) def _handle_flag_entered_base(self, team: Team) -> None: - node = ba.get_collision_info('opposing_node') - assert isinstance(node, (ba.Node, type(None))) - flag = CTFFlag.from_node(node) + flag = CTFFlag.from_node(ba.getcollision().opposing_node) if not flag: print('Unable to get flag in _handle_flag_entered_base') return @@ -389,9 +384,12 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def _handle_flag_left_base(self, team: Team) -> None: cur_time = ba.time() - op_node = ba.get_collision_info('opposing_node') - assert isinstance(op_node, (ba.Node, type(None))) - flag = CTFFlag.from_node(op_node) + try: + flag = CTFFlag.from_node(ba.getcollision().opposing_node) + except ba.NodeNotFoundError: + # We still get this call even if the flag stopped touching us + # because it was deleted; that's ok. + flag = None if not flag: return if flag.team is team: @@ -445,19 +443,15 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): """Return a player if given a node that is part of one's actor.""" if not node: return None - delegate = node.getdelegate() - if not isinstance(delegate, PlayerSpaz): - return None - return delegate.getplayer(Player) + delegate = node.getdelegate(PlayerSpaz) + return None if delegate is None else delegate.getplayer(Player) def _handle_hit_own_flag(self, team: Team, val: int) -> None: """ keep track of when each player is touching their own flag so we can award points when returned """ - srcnode = ba.get_collision_info('source_node') - assert isinstance(srcnode, (ba.Node, type(None))) - player = self._player_from_node(srcnode) + player = self._player_from_node(ba.getcollision().source_node) if player: player.touching_own_flag += (1 if val else -1) @@ -470,10 +464,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # Use a node message to kill the flag instead of just killing # our team's. (avoids redundantly killing new flags if # multiple body parts generate callbacks in one step). - node = ba.get_collision_info('opposing_node') - if node: - self._award_players_touching_own_flag(team) - node.handlemessage(ba.DieMessage()) + node = ba.getcollision().opposing_node + self._award_players_touching_own_flag(team) + node.handlemessage(ba.DieMessage()) # Takes a non-zero amount of time to return. else: @@ -547,16 +540,17 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # Augment standard behavior. super().handlemessage(msg) self.respawn_player(msg.getplayer(Player)) - elif isinstance(msg, stdflag.FlagDiedMessage): + elif isinstance(msg, FlagDiedMessage): assert isinstance(msg.flag, CTFFlag) ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) - elif isinstance(msg, stdflag.FlagPickedUpMessage): + elif isinstance(msg, FlagPickedUpMessage): # Store the last player to hold the flag for scoring purposes. assert isinstance(msg.flag, CTFFlag) - msg.flag.last_player_to_hold = msg.node.getdelegate().getplayer() + msg.flag.last_player_to_hold = msg.node.getdelegate( + PlayerSpaz, True).getplayer(Player) msg.flag.held_count += 1 msg.flag.reset_return_times() - elif isinstance(msg, stdflag.FlagDroppedMessage): + elif isinstance(msg, FlagDroppedMessage): # Store the last player to hold the flag for scoring purposes. assert isinstance(msg.flag, CTFFlag) msg.flag.held_count -= 1 diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index bc1e2394..63cb7401 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -177,11 +177,10 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): # If we have a chosen one, ignore these. if self._get_chosen_one_player() is not None: return - delegate = ba.get_collision_info('opposing_node').getdelegate() - if isinstance(delegate, PlayerSpaz): - player = delegate.getplayer(Player) - if player is not None and player.is_alive(): - self._set_chosen_one_player(player) + player = ba.getcollision().opposing_node.getdelegate( + PlayerSpaz, True).getplayer(Player) + if player is not None and player.is_alive(): + self._set_chosen_one_player(player) def _flash_flag_spawn(self) -> None: light = ba.newnode('light', diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 0f301525..a9511482 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -31,6 +31,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.flag import Flag from bastd.actor.scoreboard import Scoreboard +from bastd.actor.playerspaz import PlayerSpaz if TYPE_CHECKING: from typing import Any, Optional, Type, List, Dict, Sequence, Union @@ -233,15 +234,12 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): ba.timer(length, light.delete) def _handle_flag_player_collide(self) -> None: - flagnode, playernode = ba.get_collision_info('source_node', - 'opposing_node') - try: - player = playernode.getdelegate().getplayer() - flag = flagnode.getdelegate() - except Exception: - return # Player may have left and his body hit the flag. - assert isinstance(player, Player) - assert isinstance(flag, ConquestFlag) + collision = ba.getcollision() + flag = collision.source_node.getdelegate(ConquestFlag) + player = collision.opposing_node.getdelegate(PlayerSpaz, + True).getplayer(Player) + if not flag or not player: + return assert flag.light if flag.team is not player.team: diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index e8b21055..a03b40ce 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -31,7 +31,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor.bomb import Bomb from bastd.actor.playerspaz import PlayerSpaz -from bastd.actor.spazbot import BotSet, BouncyBot, SpazBotDeathMessage +from bastd.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage from bastd.actor.onscreencountdown import OnScreenCountdown from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon @@ -94,7 +94,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): self._eggs: List[Egg] = [] self._update_timer: Optional[ba.Timer] = None self._countdown: Optional[OnScreenCountdown] = None - self._bots: Optional[BotSet] = None + self._bots: Optional[SpazBotSet] = None # Base class overrides self.default_music = ba.MusicType.FORWARD_MARCH @@ -117,7 +117,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): self._update_timer = ba.Timer(0.25, self._update, repeat=True) self._countdown = OnScreenCountdown(60, endcall=self.end_game) ba.timer(4.0, self._countdown.start) - self._bots = BotSet() + self._bots = SpazBotSet() # Spawn evil bunny in co-op only. if isinstance(self.session, ba.CoopSession) and self._pro_mode: @@ -134,49 +134,44 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): self._bots.spawn_bot(BouncyBot, pos=(6, 4, -7.8), spawn_time=10.0) def _on_egg_player_collide(self) -> None: - if not self.has_ended(): - egg_node, playernode = ba.get_collision_info( - 'source_node', 'opposing_node') - if egg_node is not None and playernode is not None: - egg = egg_node.getdelegate() - assert isinstance(egg, Egg) - spaz = playernode.getdelegate() - assert isinstance(spaz, PlayerSpaz) - player = spaz.getplayer(Player) - if player and egg: - player.team.score += 1 + if self.has_ended(): + return + collision = ba.getcollision() + egg = collision.source_node.getdelegate(Egg) + player = collision.opposing_node.getdelegate(PlayerSpaz, + True).getplayer(Player) + if player and egg: + player.team.score += 1 - # Displays a +1 (and adds to individual player score in - # teams mode). - self.stats.player_scored(player, 1, screenmessage=False) - if self._max_eggs < 5: - self._max_eggs += 1.0 - elif self._max_eggs < 10: - self._max_eggs += 0.5 - elif self._max_eggs < 30: - self._max_eggs += 0.3 - self._update_scoreboard() - ba.playsound(self._collect_sound, - 0.5, - position=egg.node.position) + # Displays a +1 (and adds to individual player score in + # teams mode). + self.stats.player_scored(player, 1, screenmessage=False) + if self._max_eggs < 5: + self._max_eggs += 1.0 + elif self._max_eggs < 10: + self._max_eggs += 0.5 + elif self._max_eggs < 30: + self._max_eggs += 0.3 + self._update_scoreboard() + ba.playsound(self._collect_sound, 0.5, position=egg.node.position) - # Create a flash. - light = ba.newnode('light', - attrs={ - 'position': egg_node.position, - 'height_attenuated': False, - 'radius': 0.1, - 'color': (1, 1, 0) - }) - ba.animate(light, - 'intensity', { - 0: 0, - 0.1: 1.0, - 0.2: 0 - }, - loop=False) - ba.timer(0.200, light.delete) - egg.handlemessage(ba.DieMessage()) + # Create a flash. + light = ba.newnode('light', + attrs={ + 'position': egg.node.position, + 'height_attenuated': False, + 'radius': 0.1, + 'color': (1, 1, 0) + }) + ba.animate(light, + 'intensity', { + 0: 0, + 0.1: 1.0, + 0.2: 0 + }, + loop=False) + ba.timer(0.200, light.delete) + egg.handlemessage(ba.DieMessage()) def _update(self) -> None: # Misc. periodic updating. @@ -219,7 +214,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): player.respawn_icon = RespawnIcon(player, respawn_time) # Whenever our evil bunny dies, respawn him and spew some eggs. - elif isinstance(msg, SpazBotDeathMessage): + elif isinstance(msg, SpazBotDiedMessage): self._spawn_evil_bunny() assert msg.badguy.node pos = msg.badguy.node.position diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 4c4f5c72..a9b472e0 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -30,20 +30,26 @@ from typing import TYPE_CHECKING import math import ba -from bastd.actor import spazbot -from bastd.actor import flag as stdflag from bastd.actor.bomb import TNTSpawner from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox +from bastd.actor.flag import (FlagFactory, Flag, FlagPickedUpMessage, + FlagDroppedMessage, FlagDiedMessage) +from bastd.actor.spazbot import (SpazBotDiedMessage, SpazBotPunchedMessage, + SpazBotSet, BrawlerBotLite, BrawlerBot, + BomberBotLite, BomberBot, TriggerBot, + ChargerBot, TriggerBotPro, BrawlerBotPro, + StickyBot, ExplodeyBot) if TYPE_CHECKING: from typing import Any, List, Type, Dict, Sequence, Optional, Union from bastd.actor.spaz import Spaz + from bastd.actor.spazbot import SpazBot -class FootballFlag(stdflag.Flag): +class FootballFlag(Flag): """Custom flag class for football games.""" def __init__(self, position: Sequence[float]): @@ -129,8 +135,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self._whistle_sound = ba.getsound('refWhistle') self._score_region_material = ba.Material() self._score_region_material.add_actions( - conditions=('they_have_material', - stdflag.get_factory().flagmaterial), + conditions=('they_have_material', FlagFactory.get().flagmaterial), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), @@ -204,7 +209,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): assert self._flag is not None if self._flag.scored: return - region = ba.get_collision_info('source_node') + region = ba.getcollision().source_node i = None for i in range(len(self._score_regions)): if region == self._score_regions[i].node: @@ -238,7 +243,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): ba.timer(1.0, self._kill_flag) light = ba.newnode('light', attrs={ - 'position': ba.get_collision_info('position'), + 'position': ba.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) @@ -260,18 +265,14 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self._score_to_win) def handlemessage(self, msg: Any) -> Any: - if isinstance(msg, stdflag.FlagPickedUpMessage): + if isinstance(msg, FlagPickedUpMessage): assert isinstance(msg.flag, FootballFlag) - try: - player = msg.node.getdelegate().getplayer() - if player: - msg.flag.last_holding_player = player - msg.flag.held_count += 1 - except Exception: - ba.print_exception('exception in Football FlagPickedUpMessage;' - " this shouldn't happen") + player = msg.node.getdelegate(PlayerSpaz, True).getplayer(Player) + if player: + msg.flag.last_holding_player = player + msg.flag.held_count += 1 - elif isinstance(msg, stdflag.FlagDroppedMessage): + elif isinstance(msg, FlagDroppedMessage): assert isinstance(msg.flag, FootballFlag) msg.flag.held_count -= 1 @@ -282,7 +283,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self.respawn_player(msg.getplayer(Player)) # Respawn dead flags. - elif isinstance(msg, stdflag.FlagDiedMessage): + elif isinstance(msg, FlagDiedMessage): if not self.has_ended(): self._flag_respawn_timer = ba.Timer(3.0, self._spawn_flag) self._flag_respawn_light = ba.NodeActor( @@ -368,8 +369,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._score_to_win = 21 self._score_region_material = ba.Material() self._score_region_material.add_actions( - conditions=('they_have_material', - stdflag.get_factory().flagmaterial), + conditions=('they_have_material', FlagFactory.get().flagmaterial), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), @@ -384,15 +384,15 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._score_regions: List[ba.NodeActor] = [] self._exclude_powerups: List[str] = [] self._have_tnt = False - self._bot_types_initial: Optional[List[Type[spazbot.SpazBot]]] = None - self._bot_types_7: Optional[List[Type[spazbot.SpazBot]]] = None - self._bot_types_14: Optional[List[Type[spazbot.SpazBot]]] = None + self._bot_types_initial: Optional[List[Type[SpazBot]]] = None + self._bot_types_7: Optional[List[Type[SpazBot]]] = None + self._bot_types_14: Optional[List[Type[SpazBot]]] = None self._bot_team: Optional[Team] = None self._starttime_ms: Optional[int] = None self._time_text: Optional[ba.NodeActor] = None self._time_text_input: Optional[ba.NodeActor] = None self._tntspawner: Optional[TNTSpawner] = None - self._bots = spazbot.BotSet() + self._bots = SpazBotSet() self._bot_spawn_timer: Optional[ba.Timer] = None self._powerup_drop_timer: Optional[ba.Timer] = None self._scoring_team: Optional[Team] = None @@ -440,64 +440,56 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): controlsguide.ControlsGuide(delay=3.0, lifespan=10.0, bright=True).autoretain() assert self.initial_player_info is not None - abot: Type[spazbot.SpazBot] - bbot: Type[spazbot.SpazBot] - cbot: Type[spazbot.SpazBot] + abot: Type[SpazBot] + bbot: Type[SpazBot] + cbot: Type[SpazBot] if self._preset in ['rookie', 'rookie_easy']: self._exclude_powerups = ['curse'] self._have_tnt = False - abot = (spazbot.BrawlerBotLite - if self._preset == 'rookie_easy' else spazbot.BrawlerBot) + abot = (BrawlerBotLite + if self._preset == 'rookie_easy' else BrawlerBot) self._bot_types_initial = [abot] * len(self.initial_player_info) - bbot = (spazbot.BomberBotLite - if self._preset == 'rookie_easy' else spazbot.BomberBot) + bbot = (BomberBotLite + if self._preset == 'rookie_easy' else BomberBot) self._bot_types_7 = ( [bbot] * (1 if len(self.initial_player_info) < 3 else 2)) - cbot = (spazbot.BomberBot - if self._preset == 'rookie_easy' else spazbot.TriggerBot) + cbot = (BomberBot if self._preset == 'rookie_easy' else TriggerBot) self._bot_types_14 = ( [cbot] * (1 if len(self.initial_player_info) < 3 else 2)) elif self._preset == 'tournament': self._exclude_powerups = [] self._have_tnt = True self._bot_types_initial = ( - [spazbot.BrawlerBot] * - (1 if len(self.initial_player_info) < 2 else 2)) + [BrawlerBot] * (1 if len(self.initial_player_info) < 2 else 2)) self._bot_types_7 = ( - [spazbot.TriggerBot] * - (1 if len(self.initial_player_info) < 3 else 2)) + [TriggerBot] * (1 if len(self.initial_player_info) < 3 else 2)) self._bot_types_14 = ( - [spazbot.ChargerBot] * - (1 if len(self.initial_player_info) < 4 else 2)) + [ChargerBot] * (1 if len(self.initial_player_info) < 4 else 2)) elif self._preset in ['pro', 'pro_easy', 'tournament_pro']: self._exclude_powerups = ['curse'] self._have_tnt = True - self._bot_types_initial = [spazbot.ChargerBot] * len( + self._bot_types_initial = [ChargerBot] * len( self.initial_player_info) - abot = (spazbot.BrawlerBot - if self._preset == 'pro' else spazbot.BrawlerBotLite) - typed_bot_list: List[Type[spazbot.SpazBot]] = [] + abot = (BrawlerBot if self._preset == 'pro' else BrawlerBotLite) + typed_bot_list: List[Type[SpazBot]] = [] self._bot_types_7 = ( - typed_bot_list + [abot] + [spazbot.BomberBot] * + typed_bot_list + [abot] + [BomberBot] * (1 if len(self.initial_player_info) < 3 else 2)) - bbot = (spazbot.TriggerBotPro - if self._preset == 'pro' else spazbot.TriggerBot) + bbot = (TriggerBotPro if self._preset == 'pro' else TriggerBot) self._bot_types_14 = ( [bbot] * (1 if len(self.initial_player_info) < 3 else 2)) elif self._preset in ['uber', 'uber_easy']: self._exclude_powerups = [] self._have_tnt = True - abot = (spazbot.BrawlerBotPro - if self._preset == 'uber' else spazbot.BrawlerBot) - bbot = (spazbot.TriggerBotPro - if self._preset == 'uber' else spazbot.TriggerBot) - typed_bot_list_2: List[Type[spazbot.SpazBot]] = [] - self._bot_types_initial = (typed_bot_list_2 + [spazbot.StickyBot] + + abot = (BrawlerBotPro if self._preset == 'uber' else BrawlerBot) + bbot = (TriggerBotPro if self._preset == 'uber' else TriggerBot) + typed_bot_list_2: List[Type[SpazBot]] = [] + self._bot_types_initial = (typed_bot_list_2 + [StickyBot] + [abot] * len(self.initial_player_info)) self._bot_types_7 = ( [bbot] * (1 if len(self.initial_player_info) < 3 else 2)) self._bot_types_14 = ( - [spazbot.ExplodeyBot] * + [ExplodeyBot] * (1 if len(self.initial_player_info) < 3 else 2)) else: raise Exception() @@ -549,7 +541,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): if self._have_tnt: self._tntspawner = TNTSpawner(position=(0, 1, -1)) - self._bots = spazbot.BotSet() + self._bots = SpazBotSet() self._bot_spawn_timer = ba.Timer(1.0, self._update_bots, repeat=True) for bottype in self._bot_types_initial: @@ -558,12 +550,12 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None: self._show_standard_scores_to_beat_ui(scores) - def _on_bot_spawn(self, spaz: spazbot.SpazBot) -> None: + def _on_bot_spawn(self, spaz: SpazBot) -> None: # We want to move to the left by default. spaz.target_point_default = ba.Vec3(0, 0, 0) def _spawn_bot(self, - spaz_type: Type[spazbot.SpazBot], + spaz_type: Type[SpazBot], immediate: bool = False) -> None: assert self._bot_team is not None pos = self.map.get_start_position(self._bot_team.id) @@ -594,7 +586,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): return flagpos = ba.Vec3(self._flag.node.position) - closest_bot: Optional[spazbot.SpazBot] = None + closest_bot: Optional[SpazBot] = None closest_dist = 0.0 # Always gets assigned first time through. for bot in bots: # If a bot is picked up, he should forget about the flag. @@ -662,7 +654,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): return # See which score region it was. - region = ba.get_collision_info('source_node') + region = ba.getcollision().source_node i = None for i in range(len(self._score_regions)): if region == self._score_regions[i].node: @@ -707,7 +699,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self.update_scores() light = ba.newnode('light', attrs={ - 'position': ba.get_collision_info('position'), + 'position': ba.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) @@ -821,12 +813,12 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): # Augment standard behavior. super().handlemessage(msg) - elif isinstance(msg, spazbot.SpazBotDeathMessage): + elif isinstance(msg, SpazBotDiedMessage): # Every time a bad guy dies, spawn a new one. ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.badguy)))) - elif isinstance(msg, spazbot.SpazBotPunchedMessage): + elif isinstance(msg, SpazBotPunchedMessage): if self._preset in ['rookie', 'rookie_easy']: if msg.damage >= 500: self._award_achievement('Super Punch') @@ -835,7 +827,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._award_achievement('Super Mega Punch') # Respawn dead flags. - elif isinstance(msg, stdflag.FlagDiedMessage): + elif isinstance(msg, FlagDiedMessage): assert isinstance(msg.flag, FootballFlag) msg.flag.respawn_timer = ba.Timer(3.0, self._spawn_flag) self._flag_respawn_light = ba.NodeActor( diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index b027c3eb..805480ef 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -28,6 +28,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba +from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard from bastd.actor.powerupbox import PowerupBoxFactory @@ -243,15 +244,10 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): self._update_scoreboard() def _handle_puck_player_collide(self) -> None: - try: - pucknode, playernode = ba.get_collision_info( - 'source_node', 'opposing_node') - puck = pucknode.getdelegate() - player = playernode.getdelegate().getplayer() - except Exception: - player = puck = None - assert isinstance(player, Player) - assert isinstance(puck, Puck) + collision = ba.getcollision() + puck = collision.source_node.getdelegate(Puck) + player = collision.opposing_node.getdelegate(PlayerSpaz, + True).getplayer(Player) if player and puck: puck.last_players_to_touch[player.team.id] = player @@ -269,7 +265,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): if self._puck.scored: return - region = ba.get_collision_info('source_node') + region = ba.getcollision().source_node index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: @@ -308,7 +304,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): light = ba.newnode('light', attrs={ - 'position': ba.get_collision_info('position'), + 'position': ba.getcollision().position, 'height_attenuated': False, 'color': (1, 0, 0) }) diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 4aea7d06..e1a4cef5 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -247,10 +247,8 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._swipsound) def _handle_player_flag_region_collide(self, colliding: bool) -> None: - delegate = ba.get_collision_info('opposing_node').getdelegate() - if not isinstance(delegate, PlayerSpaz): - return - player = delegate.getplayer(Player) + player = ba.getcollision().opposing_node.getdelegate( + PlayerSpaz, True).getplayer(Player) if not player: return diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 8176178f..439aab2a 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -29,7 +29,7 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor.spazbot import BotSet, ChargerBot, SpazBotDeathMessage +from bastd.actor.spazbot import SpazBotSet, ChargerBot, SpazBotDiedMessage from bastd.actor.onscreentimer import OnScreenTimer if TYPE_CHECKING: @@ -76,7 +76,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self._winsound = ba.getsound('score') self._won = False self._timer: Optional[OnScreenTimer] = None - self._bots = BotSet() + self._bots = SpazBotSet() # Called when our game is transitioning in but not ready to begin; # we can go ahead and start creating stuff, playing music, etc. @@ -150,7 +150,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self.respawn_player(msg.getplayer(Player)) # A spaz-bot has died. - elif isinstance(msg, SpazBotDeathMessage): + elif isinstance(msg, SpazBotDiedMessage): # Unfortunately the bot-set will always tell us there are living # bots if we ask here (the currently-dying bot isn't officially # marked dead yet) ..so lets push a call into the event loop to diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 05f45aa5..dd7bf670 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -39,7 +39,7 @@ from bastd.actor.scoreboard import Scoreboard from bastd.actor.controlsguide import ControlsGuide from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory from bastd.actor.spazbot import ( - SpazBotDeathMessage, BotSet, ChargerBot, StickyBot, BomberBot, + SpazBotDiedMessage, SpazBotSet, ChargerBot, StickyBot, BomberBot, BomberBotLite, BrawlerBot, BrawlerBotLite, TriggerBot, BomberBotStaticLite, TriggerBotStatic, BomberBotProStatic, TriggerBotPro, ExplodeyBot, BrawlerBotProShielded, ChargerBotProShielded, BomberBotPro, @@ -189,7 +189,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): raise Exception('Unsupported map: ' + str(settings['map'])) self._scoreboard: Optional[Scoreboard] = None self._game_over = False - self._wave = 0 + self._wavenum = 0 self._can_end_wave = True self._score = 0 self._time_bonus = 0 @@ -200,7 +200,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._excluded_powerups: Optional[List[str]] = None self._waves: List[Wave] = [] self._tntspawner: Optional[TNTSpawner] = None - self._bots: Optional[BotSet] = None + self._bots: Optional[SpazBotSet] = None self._powerup_drop_timer: Optional[ba.Timer] = None self._time_bonus_timer: Optional[ba.Timer] = None self._time_bonus_text: Optional[ba.NodeActor] = None @@ -214,6 +214,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def on_transition_in(self) -> None: super().on_transition_in() session = ba.getsession() + # Show special landmine tip on rookie preset. if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: # Show once per session only (then we revert to regular tips). @@ -550,33 +551,28 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self.setup_low_life_warning_sound() self._update_scores() - self._bots = BotSet() + self._bots = SpazBotSet() ba.timer(4.0, self._start_updating_waves) def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None: self._show_standard_scores_to_beat_ui(scores) + def _get_dist_grp_totals(self, grps: List[Any]) -> Tuple[int, int]: + totalpts = 0 + totaldudes = 0 + for grp in grps: + for grpentry in grp: + dudes = grpentry[1] + totalpts += grpentry[0] * dudes + totaldudes += dudes + return totalpts, totaldudes + def _get_distribution(self, target_points: int, min_dudes: int, max_dudes: int, group_count: int, max_level: int) -> List[List[Tuple[int, int]]]: - """ calculate a distribution of bad guys given some params """ - # FIXME; This method wears the cone of shame - # pylint: disable=too-many-branches - # pylint: disable=too-many-statements - # pylint: disable=too-many-locals - # pylint: disable=too-many-nested-blocks + """Calculate a distribution of bad guys given some params.""" max_iterations = 10 + max_dudes * 2 - def _get_totals(grps: List[Any]) -> Tuple[int, int]: - totalpts = 0 - totaldudes = 0 - for grp in grps: - for grpentry in grp: - dudes = grpentry[1] - totalpts += grpentry[0] * dudes - totaldudes += dudes - return totalpts, totaldudes - groups: List[List[Tuple[int, int]]] = [] for _g in range(group_count): groups.append([]) @@ -588,83 +584,29 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if max_level > 3: types.append(4) for iteration in range(max_iterations): + diff = self._add_dist_entry_if_possible(groups, max_dudes, + target_points, types) - # See how much we're off our target by. - total_points, total_dudes = _get_totals(groups) - diff = target_points - total_points - dudes_diff = max_dudes - total_dudes - - # Add an entry if one will fit. - value = types[random.randrange(len(types))] - group = groups[random.randrange(len(groups))] - if not group: - max_count = random.randint(1, 6) - else: - max_count = 2 * random.randint(1, 3) - max_count = min(max_count, dudes_diff) - count = min(max_count, diff // value) - if count > 0: - group.append((value, count)) - total_points += value * count - total_dudes += count - diff = target_points - total_points - - total_points, total_dudes = _get_totals(groups) + total_points, total_dudes = self._get_dist_grp_totals(groups) full = (total_points >= target_points) if full: # Every so often, delete a random entry just to # shake up our distribution. if random.random() < 0.2 and iteration != max_iterations - 1: - entry_count = 0 - for group in groups: - for _ in group: - entry_count += 1 - if entry_count > 1: - del_entry = random.randrange(entry_count) - entry_count = 0 - for group in groups: - for entry in group: - if entry_count == del_entry: - group.remove(entry) - break - entry_count += 1 + self._delete_random_dist_entry(groups) # If we don't have enough dudes, kill the group with # the biggest point value. elif (total_dudes < min_dudes and iteration != max_iterations - 1): - biggest_value = 9999 - biggest_entry = None - biggest_entry_group = None - for group in groups: - for entry in group: - if (entry[0] > biggest_value - or biggest_entry is None): - biggest_value = entry[0] - biggest_entry = entry - biggest_entry_group = group - if biggest_entry is not None: - assert biggest_entry_group is not None - biggest_entry_group.remove(biggest_entry) + self._delete_biggest_dist_entry(groups) # If we've got too many dudes, kill the group with the # smallest point value. elif (total_dudes > max_dudes and iteration != max_iterations - 1): - smallest_value = 9999 - smallest_entry = None - smallest_entry_group = None - for group in groups: - for entry in group: - if (entry[0] < smallest_value - or smallest_entry is None): - smallest_value = entry[0] - smallest_entry = entry - smallest_entry_group = group - assert smallest_entry is not None - assert smallest_entry_group is not None - smallest_entry_group.remove(smallest_entry) + self._delete_smallest_dist_entry(groups) # Close enough.. we're done. else: @@ -673,6 +615,76 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): return groups + def _add_dist_entry_if_possible(self, groups: List[List[Tuple[int, int]]], + max_dudes: int, target_points: int, + types: List[int]) -> int: + # See how much we're off our target by. + total_points, total_dudes = self._get_dist_grp_totals(groups) + diff = target_points - total_points + dudes_diff = max_dudes - total_dudes + + # Add an entry if one will fit. + value = types[random.randrange(len(types))] + group = groups[random.randrange(len(groups))] + if not group: + max_count = random.randint(1, 6) + else: + max_count = 2 * random.randint(1, 3) + max_count = min(max_count, dudes_diff) + count = min(max_count, diff // value) + if count > 0: + group.append((value, count)) + total_points += value * count + total_dudes += count + diff = target_points - total_points + return diff + + def _delete_smallest_dist_entry( + self, groups: List[List[Tuple[int, int]]]) -> None: + smallest_value = 9999 + smallest_entry = None + smallest_entry_group = None + for group in groups: + for entry in group: + if entry[0] < smallest_value or smallest_entry is None: + smallest_value = entry[0] + smallest_entry = entry + smallest_entry_group = group + assert smallest_entry is not None + assert smallest_entry_group is not None + smallest_entry_group.remove(smallest_entry) + + def _delete_biggest_dist_entry( + self, groups: List[List[Tuple[int, int]]]) -> None: + biggest_value = 9999 + biggest_entry = None + biggest_entry_group = None + for group in groups: + for entry in group: + if entry[0] > biggest_value or biggest_entry is None: + biggest_value = entry[0] + biggest_entry = entry + biggest_entry_group = group + if biggest_entry is not None: + assert biggest_entry_group is not None + biggest_entry_group.remove(biggest_entry) + + def _delete_random_dist_entry(self, + groups: List[List[Tuple[int, int]]]) -> None: + entry_count = 0 + for group in groups: + for _ in group: + entry_count += 1 + if entry_count > 1: + del_entry = random.randrange(entry_count) + entry_count = 0 + for group in groups: + for entry in group: + if entry_count == del_entry: + group.remove(entry) + break + entry_count += 1 + def spawn_player(self, player: Player) -> ba.Actor: # We keep track of who got hurt each wave for score purposes. @@ -734,7 +746,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if outcome == 'defeat': self.fade_to_red() score: Optional[int] - if self._wave >= 2: + if self._wavenum >= 2: score = self._score fail_message = None else: @@ -777,7 +789,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: won = False else: - won = (self._wave == len(self._waves)) + won = (self._wavenum == len(self._waves)) base_delay = 4.0 if won else 0.0 @@ -789,7 +801,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): base_delay += 1.0 # Reward flawless bonus. - if self._wave > 0: + if self._wavenum > 0: have_flawless = False for player in self.players: if player.is_alive() and not player.has_been_hurt: @@ -806,9 +818,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): scale=1.0, duration=4.0) self.celebrate(20.0) - self._award_completion_achievements() - ba.timer(base_delay, ba.WeakCall(self._award_completion_bonus)) base_delay += 0.85 ba.playsound(self._winsound) @@ -822,10 +832,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): ba.timer(base_delay, ba.WeakCall(self.do_end, 'victory')) return - self._wave += 1 + self._wavenum += 1 # Short celebration after waves. - if self._wave > 1: + if self._wavenum > 1: self.celebrate(0.5) ba.timer(base_delay, ba.WeakCall(self._start_next_wave)) @@ -903,17 +913,17 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _respawn_players_for_wave(self) -> None: # Respawn applicable players. - if self._wave > 1 and not self.is_waiting_for_continue(): + if self._wavenum > 1 and not self.is_waiting_for_continue(): for player in self.players: if (not player.is_alive() - and player.respawn_wave == self._wave): + and player.respawn_wave == self._wavenum): self.spawn_player(player) self._update_player_spawn_info() def _setup_wave_spawns(self, wave: Wave) -> None: tval = 0.0 dtime = 0.2 - if self._wave == 1: + if self._wavenum == 1: spawn_time = 3.973 tval += 0.5 else: @@ -970,7 +980,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: wave = self._generate_random_wave() else: - wave = self._waves[self._wave - 1] + wave = self._waves[self._wavenum - 1] self._setup_wave_spawns(wave) self._update_wave_ui_and_bonuses() ba.timer(0.4, ba.Call(ba.playsound, self._new_wave_sound)) @@ -980,7 +990,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self.show_zoom_message(ba.Lstr(value='${A} ${B}', subs=[('${A}', ba.Lstr(resource='waveText')), - ('${B}', str(self._wave))]), + ('${B}', str(self._wavenum))]), scale=1.0, duration=1.0, trail=True) @@ -1012,7 +1022,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): wttxt = ba.Lstr( value='${A} ${B}', subs=[('${A}', ba.Lstr(resource='waveText')), - ('${B}', str(self._wave) + + ('${B}', str(self._wavenum) + ('' if self._preset in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] else ('/' + str(len(self._waves)))))]) @@ -1032,7 +1042,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): })) def _bot_levels_for_wave(self) -> List[List[Type[SpazBot]]]: - level = self._wave + level = self._wavenum bot_types = [ BomberBot, BrawlerBot, TriggerBot, ChargerBot, BomberBotPro, BrawlerBotPro, TriggerBotPro, BomberBotProShielded, ExplodeyBot, @@ -1067,6 +1077,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): [b for b in bot_types if b.points_mult == 2], [b for b in bot_types if b.points_mult == 3], [b for b in bot_types if b.points_mult == 4]] + # Make sure all lists have something in them if not all(bot_levels): raise RuntimeError('Got empty bot level') @@ -1099,7 +1110,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): Spacing(40.0 if random.random() < 0.5 else 80.0)) def _generate_random_wave(self) -> Wave: - level = self._wave + level = self._wavenum bot_levels = self._bot_levels_for_wave() target_points = level * 3 - 2 @@ -1199,20 +1210,19 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._a_player_has_been_hurt = True # Make note with the player when they can respawn: - if self._wave < 10: - player.respawn_wave = max(2, self._wave + 1) - elif self._wave < 15: - player.respawn_wave = max(2, self._wave + 2) + if self._wavenum < 10: + player.respawn_wave = max(2, self._wavenum + 1) + elif self._wavenum < 15: + player.respawn_wave = max(2, self._wavenum + 2) else: - player.respawn_wave = max(2, self._wave + 3) + player.respawn_wave = max(2, self._wavenum + 3) ba.timer(0.1, self._update_player_spawn_info) ba.timer(0.1, self._checkroundover) - elif isinstance(msg, SpazBotDeathMessage): + elif isinstance(msg, SpazBotDiedMessage): pts, importance = msg.badguy.get_death_points(msg.how) if msg.killerplayer is not None: self._handle_kill_achievements(msg) - target: Optional[Sequence[float]] try: assert msg.badguy.node @@ -1242,47 +1252,57 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): else: super().handlemessage(msg) - def _handle_kill_achievements(self, msg: SpazBotDeathMessage) -> None: - # pylint: disable=too-many-branches - # Toss-off-map achievement: + def _handle_kill_achievements(self, msg: SpazBotDiedMessage) -> None: if self._preset in {Preset.TRAINING, Preset.TRAINING_EASY}: - if msg.badguy.last_attacked_type == ('picked_up', 'default'): - self._throw_off_kills += 1 - if self._throw_off_kills >= 3: - self._award_achievement('Off You Go Then') - - # Land-mine achievement: + self._handle_training_kill_achievements(msg) elif self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: - if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 3: - self._award_achievement('Mine Games') + self._handle_rookie_kill_achievements(msg) + elif self._preset in {Preset.PRO, Preset.PRO_EASY}: + self._handle_pro_kill_achievements(msg) + elif self._preset in {Preset.UBER, Preset.UBER_EASY}: + self._handle_uber_kill_achievements(msg) + + def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: + + # Uber mine achievement: + if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 6: + self._award_achievement('Gold Miner') + + # Uber tnt achievement: + if msg.badguy.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 6: + ba.timer(0.5, ba.WeakCall(self._award_achievement, + 'TNT Terror')) + + def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: # TNT achievement: - elif self._preset in {Preset.PRO, Preset.PRO_EASY}: - if msg.badguy.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 3: - ba.timer( - 0.5, - ba.WeakCall(self._award_achievement, - 'Boom Goes the Dynamite')) + if msg.badguy.last_attacked_type == ('explosion', 'tnt'): + self._tnt_kills += 1 + if self._tnt_kills >= 3: + ba.timer( + 0.5, + ba.WeakCall(self._award_achievement, + 'Boom Goes the Dynamite')) - elif self._preset in {Preset.UBER, Preset.UBER_EASY}: + def _handle_rookie_kill_achievements(self, + msg: SpazBotDiedMessage) -> None: + # Land-mine achievement: + if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): + self._land_mine_kills += 1 + if self._land_mine_kills >= 3: + self._award_achievement('Mine Games') - # Uber mine achievement: - if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): - self._land_mine_kills += 1 - if self._land_mine_kills >= 6: - self._award_achievement('Gold Miner') - - # Uber tnt achievement: - if msg.badguy.last_attacked_type == ('explosion', 'tnt'): - self._tnt_kills += 1 - if self._tnt_kills >= 6: - ba.timer( - 0.5, ba.WeakCall(self._award_achievement, - 'TNT Terror')) + def _handle_training_kill_achievements(self, + msg: SpazBotDiedMessage) -> None: + # Toss-off-map achievement: + if msg.badguy.last_attacked_type == ('picked_up', 'default'): + self._throw_off_kills += 1 + if self._throw_off_kills >= 3: + self._award_achievement('Off You Go Then') def _set_can_end_wave(self) -> None: self._can_end_wave = True @@ -1308,7 +1328,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): return if not any(player.is_alive() for player in self.teams[0].players): # Allow continuing after wave 1. - if self._wave > 1: + if self._wavenum > 1: self.continue_or_end_game() else: self.end_game() diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 05bc93f0..ecb6e38f 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -226,17 +226,13 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-nested-blocks - region_node, playernode = ba.get_collision_info( - 'source_node', 'opposing_node') - try: - player = playernode.getdelegate().getplayer() - except Exception: - player = None - region = region_node.getdelegate() + collision = ba.getcollision() + region = collision.source_node.getdelegate(RaceRegion) + playerspaz = collision.opposing_node.getdelegate(PlayerSpaz, + doraise=False) + player = playerspaz.getplayer(Player) if playerspaz else None if not player or not region: return - assert isinstance(player, Player) - assert isinstance(region, RaceRegion) last_region = player.last_region this_region = region.index diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 46dc7f02..fbcce6e7 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -29,11 +29,16 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import spazbot +from bastd.actor.popuptext import PopupText from bastd.actor.bomb import TNTSpawner from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory +from bastd.actor.spazbot import ( + SpazBotSet, SpazBot, SpazBotDiedMessage, BomberBot, BrawlerBot, TriggerBot, + TriggerBotPro, BomberBotProShielded, TriggerBotProShielded, ChargerBot, + ChargerBotProShielded, StickyBot, ExplodeyBot, BrawlerBotProShielded, + BomberBotPro, BrawlerBotPro) if TYPE_CHECKING: from typing import Type, Any, List, Dict, Tuple, Sequence, Optional @@ -57,22 +62,23 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): 'No, you can\'t get up on the ledge. You have to throw bombs.', 'Whip back and forth to get more distance on your throws..' ] + default_music = ba.MusicType.MARCHING # How fast our various bot types walk. - _bot_speed_map: Dict[Type[spazbot.SpazBot], float] = { - spazbot.BomberBot: 0.48, - spazbot.BomberBotPro: 0.48, - spazbot.BomberBotProShielded: 0.48, - spazbot.BrawlerBot: 0.57, - spazbot.BrawlerBotPro: 0.57, - spazbot.BrawlerBotProShielded: 0.57, - spazbot.TriggerBot: 0.73, - spazbot.TriggerBotPro: 0.78, - spazbot.TriggerBotProShielded: 0.78, - spazbot.ChargerBot: 1.0, - spazbot.ChargerBotProShielded: 1.0, - spazbot.ExplodeyBot: 1.0, - spazbot.StickyBot: 0.5 + _bot_speed_map: Dict[Type[SpazBot], float] = { + BomberBot: 0.48, + BomberBotPro: 0.48, + BomberBotProShielded: 0.48, + BrawlerBot: 0.57, + BrawlerBotPro: 0.57, + BrawlerBotProShielded: 0.57, + TriggerBot: 0.73, + TriggerBotPro: 0.78, + TriggerBotProShielded: 0.78, + ChargerBot: 1.0, + ChargerBotProShielded: 1.0, + ExplodeyBot: 1.0, + StickyBot: 0.5 } def __init__(self, settings: Dict[str, Any]): @@ -108,7 +114,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._player_has_picked_up_powerup = False self._scoreboard: Optional[Scoreboard] = None self._game_over = False - self._wave = 0 + self._wavenum = 0 self._can_end_wave = True self._score = 0 self._time_bonus = 0 @@ -118,7 +124,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._exclude_powerups: Optional[List[str]] = None self._have_tnt: Optional[bool] = None self._waves: Optional[List[Dict[str, Any]]] = None - self._bots = spazbot.BotSet() + self._bots = SpazBotSet() self._tntspawner: Optional[TNTSpawner] = None self._lives_bg: Optional[ba.NodeActor] = None self._start_lives = 10 @@ -133,7 +139,6 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._wave_update_timer: Optional[ba.Timer] = None def on_transition_in(self) -> None: - self.default_music = ba.MusicType.MARCHING super().on_transition_in() self._scoreboard = Scoreboard(label=ba.Lstr(resource='scoreText'), score_split=0.5) @@ -157,110 +162,110 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._have_tnt = True self._waves = [ {'entries': [ - {'type': spazbot.BomberBot, 'path': 3 if hard else 2}, - {'type': spazbot.BomberBot, 'path': 2}, - {'type': spazbot.BomberBot, 'path': 2} if hard else None, - {'type': spazbot.BomberBot, 'path': 2} if player_count > 1 + {'type': BomberBot, 'path': 3 if hard else 2}, + {'type': BomberBot, 'path': 2}, + {'type': BomberBot, 'path': 2} if hard else None, + {'type': BomberBot, 'path': 2} if player_count > 1 else None, - {'type': spazbot.BomberBot, 'path': 1} if hard else None, - {'type': spazbot.BomberBot, 'path': 1} if player_count > 2 + {'type': BomberBot, 'path': 1} if hard else None, + {'type': BomberBot, 'path': 1} if player_count > 2 else None, - {'type': spazbot.BomberBot, 'path': 1} if player_count > 3 + {'type': BomberBot, 'path': 1} if player_count > 3 else None, ]}, {'entries': [ - {'type': spazbot.BomberBot, 'path': 1} if hard else None, - {'type': spazbot.BomberBot, 'path': 2} if hard else None, - {'type': spazbot.BomberBot, 'path': 2}, - {'type': spazbot.BomberBot, 'path': 2}, - {'type': spazbot.BomberBot, 'path': 2} if player_count > 3 + {'type': BomberBot, 'path': 1} if hard else None, + {'type': BomberBot, 'path': 2} if hard else None, + {'type': BomberBot, 'path': 2}, + {'type': BomberBot, 'path': 2}, + {'type': BomberBot, 'path': 2} if player_count > 3 else None, - {'type': spazbot.BrawlerBot, 'path': 3}, - {'type': spazbot.BrawlerBot, 'path': 3}, - {'type': spazbot.BrawlerBot, 'path': 3} if hard else None, - {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 1 + {'type': BrawlerBot, 'path': 3}, + {'type': BrawlerBot, 'path': 3}, + {'type': BrawlerBot, 'path': 3} if hard else None, + {'type': BrawlerBot, 'path': 3} if player_count > 1 else None, - {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 2 + {'type': BrawlerBot, 'path': 3} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.ChargerBot, 'path': 2} if hard else None, - {'type': spazbot.ChargerBot, 'path': 2} if player_count > 2 + {'type': ChargerBot, 'path': 2} if hard else None, + {'type': ChargerBot, 'path': 2} if player_count > 2 else None, - {'type': spazbot.TriggerBot, 'path': 2}, - {'type': spazbot.TriggerBot, 'path': 2} if player_count > 1 + {'type': TriggerBot, 'path': 2}, + {'type': TriggerBot, 'path': 2} if player_count > 1 else None, {'type': 'spacing', 'duration': 3.0}, - {'type': spazbot.BomberBot, 'path': 2} if hard else None, - {'type': spazbot.BomberBot, 'path': 2} if hard else None, - {'type': spazbot.BomberBot, 'path': 2}, - {'type': spazbot.BomberBot, 'path': 3} if hard else None, - {'type': spazbot.BomberBot, 'path': 3}, - {'type': spazbot.BomberBot, 'path': 3}, - {'type': spazbot.BomberBot, 'path': 3} if player_count > 3 + {'type': BomberBot, 'path': 2} if hard else None, + {'type': BomberBot, 'path': 2} if hard else None, + {'type': BomberBot, 'path': 2}, + {'type': BomberBot, 'path': 3} if hard else None, + {'type': BomberBot, 'path': 3}, + {'type': BomberBot, 'path': 3}, + {'type': BomberBot, 'path': 3} if player_count > 3 else None, ]}, {'entries': [ - {'type': spazbot.TriggerBot, 'path': 1} if hard else None, + {'type': TriggerBot, 'path': 1} if hard else None, {'type': 'spacing', 'duration': 1.0} if hard else None, - {'type': spazbot.TriggerBot, 'path': 2}, + {'type': TriggerBot, 'path': 2}, {'type': 'spacing', 'duration': 1.0}, - {'type': spazbot.TriggerBot, 'path': 3}, + {'type': TriggerBot, 'path': 3}, {'type': 'spacing', 'duration': 1.0}, - {'type': spazbot.TriggerBot, 'path': 1} if hard else None, + {'type': TriggerBot, 'path': 1} if hard else None, {'type': 'spacing', 'duration': 1.0} if hard else None, - {'type': spazbot.TriggerBot, 'path': 2}, + {'type': TriggerBot, 'path': 2}, {'type': 'spacing', 'duration': 1.0}, - {'type': spazbot.TriggerBot, 'path': 3}, + {'type': TriggerBot, 'path': 3}, {'type': 'spacing', 'duration': 1.0}, - {'type': spazbot.TriggerBot, 'path': 1} + {'type': TriggerBot, 'path': 1} if (player_count > 1 and hard) else None, {'type': 'spacing', 'duration': 1.0}, - {'type': spazbot.TriggerBot, 'path': 2} if player_count > 2 + {'type': TriggerBot, 'path': 2} if player_count > 2 else None, {'type': 'spacing', 'duration': 1.0}, - {'type': spazbot.TriggerBot, 'path': 3} if player_count > 3 + {'type': TriggerBot, 'path': 3} if player_count > 3 else None, {'type': 'spacing', 'duration': 1.0}, ]}, {'entries': [ - {'type': spazbot.ChargerBotProShielded if hard - else spazbot.ChargerBot, 'path': 1}, - {'type': spazbot.BrawlerBot, 'path': 2} if hard else None, - {'type': spazbot.BrawlerBot, 'path': 2}, - {'type': spazbot.BrawlerBot, 'path': 2}, - {'type': spazbot.BrawlerBot, 'path': 3} if hard else None, - {'type': spazbot.BrawlerBot, 'path': 3}, - {'type': spazbot.BrawlerBot, 'path': 3}, - {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 1 + {'type': ChargerBotProShielded if hard + else ChargerBot, 'path': 1}, + {'type': BrawlerBot, 'path': 2} if hard else None, + {'type': BrawlerBot, 'path': 2}, + {'type': BrawlerBot, 'path': 2}, + {'type': BrawlerBot, 'path': 3} if hard else None, + {'type': BrawlerBot, 'path': 3}, + {'type': BrawlerBot, 'path': 3}, + {'type': BrawlerBot, 'path': 3} if player_count > 1 else None, - {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 2 + {'type': BrawlerBot, 'path': 3} if player_count > 2 else None, - {'type': spazbot.BrawlerBot, 'path': 3} if player_count > 3 + {'type': BrawlerBot, 'path': 3} if player_count > 3 else None, ]}, {'entries': [ - {'type': spazbot.BomberBotProShielded, 'path': 3}, + {'type': BomberBotProShielded, 'path': 3}, {'type': 'spacing', 'duration': 1.5}, - {'type': spazbot.BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 2}, {'type': 'spacing', 'duration': 1.5}, - {'type': spazbot.BomberBotProShielded, 'path': 1} if hard + {'type': BomberBotProShielded, 'path': 1} if hard else None, {'type': 'spacing', 'duration': 1.0} if hard else None, - {'type': spazbot.BomberBotProShielded, 'path': 3}, + {'type': BomberBotProShielded, 'path': 3}, {'type': 'spacing', 'duration': 1.5}, - {'type': spazbot.BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 2}, {'type': 'spacing', 'duration': 1.5}, - {'type': spazbot.BomberBotProShielded, 'path': 1} if hard + {'type': BomberBotProShielded, 'path': 1} if hard else None, {'type': 'spacing', 'duration': 1.5} if hard else None, - {'type': spazbot.BomberBotProShielded, 'path': 3} + {'type': BomberBotProShielded, 'path': 3} if player_count > 1 else None, {'type': 'spacing', 'duration': 1.5}, - {'type': spazbot.BomberBotProShielded, 'path': 2} + {'type': BomberBotProShielded, 'path': 2} if player_count > 2 else None, {'type': 'spacing', 'duration': 1.5}, - {'type': spazbot.BomberBotProShielded, 'path': 1} + {'type': BomberBotProShielded, 'path': 1} if player_count > 3 else None, ]}, ] # yapf: disable @@ -269,84 +274,84 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._have_tnt = True self._waves = [ {'entries': [ - {'type': spazbot.TriggerBot, 'path': 1} if hard else None, - {'type': spazbot.TriggerBot, 'path': 2}, - {'type': spazbot.TriggerBot, 'path': 2}, - {'type': spazbot.TriggerBot, 'path': 3}, - {'type': spazbot.BrawlerBotPro if hard - else spazbot.BrawlerBot, 'point': 'bottom_left'}, - {'type': spazbot.BrawlerBotPro, 'point': 'bottom_right'} + {'type': TriggerBot, 'path': 1} if hard else None, + {'type': TriggerBot, 'path': 2}, + {'type': TriggerBot, 'path': 2}, + {'type': TriggerBot, 'path': 3}, + {'type': BrawlerBotPro if hard + else BrawlerBot, 'point': 'bottom_left'}, + {'type': BrawlerBotPro, 'point': 'bottom_right'} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.ChargerBot, 'path': 2}, - {'type': spazbot.ChargerBot, 'path': 3}, - {'type': spazbot.ChargerBot, 'path': 1} if hard else None, - {'type': spazbot.ChargerBot, 'path': 2}, - {'type': spazbot.ChargerBot, 'path': 3}, - {'type': spazbot.ChargerBot, 'path': 1} if player_count > 2 + {'type': ChargerBot, 'path': 2}, + {'type': ChargerBot, 'path': 3}, + {'type': ChargerBot, 'path': 1} if hard else None, + {'type': ChargerBot, 'path': 2}, + {'type': ChargerBot, 'path': 3}, + {'type': ChargerBot, 'path': 1} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.BomberBotProShielded, 'path': 1} if hard + {'type': BomberBotProShielded, 'path': 1} if hard else None, - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.BomberBotProShielded, 'path': 3}, - {'type': spazbot.BomberBotProShielded, 'path': 3}, - {'type': spazbot.ChargerBot, 'point': 'bottom_right'}, - {'type': spazbot.ChargerBot, 'point': 'bottom_left'} + {'type': BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 3}, + {'type': BomberBotProShielded, 'path': 3}, + {'type': ChargerBot, 'point': 'bottom_right'}, + {'type': ChargerBot, 'point': 'bottom_left'} if player_count > 2 else None, ]}, {'entries': [ - {'type': spazbot.TriggerBotPro, 'path': 1} + {'type': TriggerBotPro, 'path': 1} if hard else None, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2}, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2} + {'type': TriggerBotPro, 'path': 1 if hard else 2}, + {'type': TriggerBotPro, 'path': 1 if hard else 2}, + {'type': TriggerBotPro, 'path': 1 if hard else 2}, + {'type': TriggerBotPro, 'path': 1 if hard else 2}, + {'type': TriggerBotPro, 'path': 1 if hard else 2}, + {'type': TriggerBotPro, 'path': 1 if hard else 2} if player_count > 1 else None, - {'type': spazbot.TriggerBotPro, 'path': 1 if hard else 2} + {'type': TriggerBotPro, 'path': 1 if hard else 2} if player_count > 3 else None, ]}, {'entries': [ - {'type': spazbot.TriggerBotProShielded if hard - else spazbot.TriggerBotPro, 'point': 'bottom_left'}, - {'type': spazbot.TriggerBotProShielded, + {'type': TriggerBotProShielded if hard + else TriggerBotPro, 'point': 'bottom_left'}, + {'type': TriggerBotProShielded, 'point': 'bottom_right'} if hard else None, - {'type': spazbot.TriggerBotProShielded, + {'type': TriggerBotProShielded, 'point': 'bottom_right'} if player_count > 2 else None, - {'type': spazbot.BomberBot, 'path': 3}, - {'type': spazbot.BomberBot, 'path': 3}, + {'type': BomberBot, 'path': 3}, + {'type': BomberBot, 'path': 3}, {'type': 'spacing', 'duration': 5.0}, - {'type': spazbot.BrawlerBot, 'path': 2}, - {'type': spazbot.BrawlerBot, 'path': 2}, + {'type': BrawlerBot, 'path': 2}, + {'type': BrawlerBot, 'path': 2}, {'type': 'spacing', 'duration': 5.0}, - {'type': spazbot.TriggerBot, 'path': 1} if hard else None, - {'type': spazbot.TriggerBot, 'path': 1} if hard else None, + {'type': TriggerBot, 'path': 1} if hard else None, + {'type': TriggerBot, 'path': 1} if hard else None, ]}, {'entries': [ - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.BomberBotProShielded, 'path': 2} if hard + {'type': BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 2} if hard else None, - {'type': spazbot.StickyBot, 'point': 'bottom_right'}, - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.StickyBot, 'point': 'bottom_right'} + {'type': StickyBot, 'point': 'bottom_right'}, + {'type': BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 2}, + {'type': StickyBot, 'point': 'bottom_right'} if player_count > 2 else None, - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.ExplodeyBot, 'point': 'bottom_left'}, - {'type': spazbot.BomberBotProShielded, 'path': 2}, - {'type': spazbot.BomberBotProShielded, 'path': 2} + {'type': BomberBotProShielded, 'path': 2}, + {'type': ExplodeyBot, 'point': 'bottom_left'}, + {'type': BomberBotProShielded, 'path': 2}, + {'type': BomberBotProShielded, 'path': 2} if player_count > 1 else None, {'type': 'spacing', 'duration': 5.0}, - {'type': spazbot.StickyBot, 'point': 'bottom_left'}, + {'type': StickyBot, 'point': 'bottom_left'}, {'type': 'spacing', 'duration': 2.0}, - {'type': spazbot.ExplodeyBot, 'point': 'bottom_right'}, + {'type': ExplodeyBot, 'point': 'bottom_right'}, ]}, ] # yapf: disable elif self._preset in ['endless', 'endless_tournament']: @@ -401,9 +406,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): ba.timer(2.0, self._start_updating_waves) def _handle_reached_end(self) -> None: - oppnode = ba.get_collision_info('opposing_node') - spaz = oppnode.getdelegate() - + spaz = ba.getcollision().opposing_node.getdelegate(SpazBot, True) if not spaz.is_alive(): return # Ignore bodies flying in. @@ -495,7 +498,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): def _drop_powerups(self, standard_points: bool = False, force_first: str = None) -> None: - """ Generic powerup drop """ + """Generic powerup drop.""" # If its been a minute since our last wave finished emerging, stop # giving out land-mine powerups. (prevents players from waiting @@ -528,14 +531,6 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): extra_excludes)).autoretain() def end_game(self) -> None: - - # FIXME: If we don't start our bots moving again we get stuck. This - # is because the bot-set never prunes itself while movement is off - # and on_expire() never gets called for some bots because - # _prune_dead_objects() saw them as dead and pulled them off the - # weak-ref lists. this is an architectural issue; can hopefully fix - # this by having _actor_weak_refs not look at exists(). - self._bots.start_moving() ba.pushcall(ba.Call(self.do_end, 'defeat')) ba.setmusic(None) ba.playsound(self._player_death_sound) @@ -550,7 +545,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): delay = 0 score: Optional[int] - if self._wave >= 2: + if self._wavenum >= 2: score = self._score fail_message = None else: @@ -583,7 +578,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): won = False else: assert self._waves is not None - won = (self._wave == len(self._waves)) + won = (self._wavenum == len(self._waves)) # Reward time bonus. base_delay = 4.0 if won else 0 @@ -594,7 +589,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): base_delay += 1.0 # Reward flawless bonus. - if self._wave > 0 and self._flawless: + if self._wavenum > 0 and self._flawless: ba.timer(base_delay, self._award_flawless_bonus) base_delay += 1.0 @@ -636,69 +631,60 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): ba.timer(base_delay, ba.Call(self.do_end, 'victory')) return - self._wave += 1 + self._wavenum += 1 # Short celebration after waves. - if self._wave > 1: + if self._wavenum > 1: self.celebrate(0.5) ba.timer(base_delay, self._start_next_wave) def _award_completion_bonus(self) -> None: - from bastd.actor import popuptext bonus = 200 ba.playsound(self._cashregistersound) - popuptext.PopupText(ba.Lstr( - value='+${A} ${B}', - subs=[('${A}', str(bonus)), - ('${B}', ba.Lstr(resource='completionBonusText'))]), - color=(0.7, 0.7, 1.0, 1), - scale=1.6, - position=(0, 1.5, -1)).autoretain() + PopupText(ba.Lstr(value='+${A} ${B}', + subs=[('${A}', str(bonus)), + ('${B}', + ba.Lstr(resource='completionBonusText'))]), + color=(0.7, 0.7, 1.0, 1), + scale=1.6, + position=(0, 1.5, -1)).autoretain() self._score += bonus self._update_scores() def _award_lives_bonus(self) -> None: - from bastd.actor import popuptext bonus = self._lives * 30 ba.playsound(self._cashregistersound) - popuptext.PopupText(ba.Lstr(value='+${A} ${B}', - subs=[('${A}', str(bonus)), - ('${B}', - ba.Lstr(resource='livesBonusText')) - ]), - color=(0.7, 1.0, 0.3, 1), - scale=1.3, - position=(0, 1, -1)).autoretain() + PopupText(ba.Lstr(value='+${A} ${B}', + subs=[('${A}', str(bonus)), + ('${B}', ba.Lstr(resource='livesBonusText'))]), + color=(0.7, 1.0, 0.3, 1), + scale=1.3, + position=(0, 1, -1)).autoretain() self._score += bonus self._update_scores() def _award_time_bonus(self, bonus: int) -> None: - from bastd.actor import popuptext ba.playsound(self._cashregistersound) - popuptext.PopupText(ba.Lstr(value='+${A} ${B}', - subs=[('${A}', str(bonus)), - ('${B}', - ba.Lstr(resource='timeBonusText')) - ]), - color=(1, 1, 0.5, 1), - scale=1.0, - position=(0, 3, -1)).autoretain() + PopupText(ba.Lstr(value='+${A} ${B}', + subs=[('${A}', str(bonus)), + ('${B}', ba.Lstr(resource='timeBonusText'))]), + color=(1, 1, 0.5, 1), + scale=1.0, + position=(0, 3, -1)).autoretain() self._score += self._time_bonus self._update_scores() def _award_flawless_bonus(self) -> None: - from bastd.actor import popuptext ba.playsound(self._cashregistersound) - popuptext.PopupText(ba.Lstr(value='+${A} ${B}', - subs=[('${A}', str(self._flawless_bonus)), - ('${B}', - ba.Lstr(resource='perfectWaveText')) - ]), - color=(1, 1, 0.2, 1), - scale=1.2, - position=(0, 2, -1)).autoretain() + PopupText(ba.Lstr(value='+${A} ${B}', + subs=[('${A}', str(self._flawless_bonus)), + ('${B}', ba.Lstr(resource='perfectWaveText')) + ]), + color=(1, 1, 0.2, 1), + scale=1.2, + position=(0, 2, -1)).autoretain() assert self._flawless_bonus is not None self._score += self._flawless_bonus @@ -717,7 +703,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self.show_zoom_message(ba.Lstr(value='${A} ${B}', subs=[('${A}', ba.Lstr(resource='waveText')), - ('${B}', str(self._wave))]), + ('${B}', str(self._wavenum))]), scale=1.0, duration=1.0, trail=True) @@ -728,52 +714,49 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): bot_types: List[Optional[Dict[str, Any]]] = [] if self._preset in ['endless', 'endless_tournament']: - level = self._wave + level = self._wavenum target_points = (level + 1) * 8.0 group_count = random.randint(1, 3) entries = [] - spaz_types: List[Tuple[Type[spazbot.SpazBot], float]] = [] + spaz_types: List[Tuple[Type[SpazBot], float]] = [] if level < 6: - spaz_types += [(spazbot.BomberBot, 5.0)] + spaz_types += [(BomberBot, 5.0)] if level < 10: - spaz_types += [(spazbot.BrawlerBot, 5.0)] + spaz_types += [(BrawlerBot, 5.0)] if level < 15: - spaz_types += [(spazbot.TriggerBot, 6.0)] + spaz_types += [(TriggerBot, 6.0)] if level > 5: - spaz_types += [(spazbot.TriggerBotPro, 7.5) - ] * (1 + (level - 5) // 7) + spaz_types += [(TriggerBotPro, 7.5)] * (1 + (level - 5) // 7) if level > 2: - spaz_types += [(spazbot.BomberBotProShielded, 8.0) + spaz_types += [(BomberBotProShielded, 8.0) ] * (1 + (level - 2) // 6) if level > 6: - spaz_types += [(spazbot.TriggerBotProShielded, 12.0) + spaz_types += [(TriggerBotProShielded, 12.0) ] * (1 + (level - 6) // 5) if level > 1: - spaz_types += ([(spazbot.ChargerBot, 10.0)] * - (1 + (level - 1) // 4)) + spaz_types += ([(ChargerBot, 10.0)] * (1 + (level - 1) // 4)) if level > 7: - spaz_types += [(spazbot.ChargerBotProShielded, 15.0) + spaz_types += [(ChargerBotProShielded, 15.0) ] * (1 + (level - 7) // 3) # Bot type, their effect on target points. - defender_types: List[Tuple[Type[spazbot.SpazBot], float]] = [ - (spazbot.BomberBot, 0.9), - (spazbot.BrawlerBot, 0.9), - (spazbot.TriggerBot, 0.85), + defender_types: List[Tuple[Type[SpazBot], float]] = [ + (BomberBot, 0.9), + (BrawlerBot, 0.9), + (TriggerBot, 0.85), ] if level > 2: - defender_types += [(spazbot.ChargerBot, 0.75)] + defender_types += [(ChargerBot, 0.75)] if level > 4: - defender_types += ([(spazbot.StickyBot, 0.7)] * - (1 + (level - 5) // 6)) + defender_types += ([(StickyBot, 0.7)] * (1 + (level - 5) // 6)) if level > 6: - defender_types += ([(spazbot.ExplodeyBot, 0.7)] * - (1 + (level - 5) // 5)) + defender_types += ([(ExplodeyBot, 0.7)] * (1 + + (level - 5) // 5)) if level > 8: - defender_types += ([(spazbot.BrawlerBotProShielded, 0.65)] * + defender_types += ([(BrawlerBotProShielded, 0.65)] * (1 + (level - 5) // 4)) if level > 10: - defender_types += ([(spazbot.TriggerBotProShielded, 0.6)] * + defender_types += ([(TriggerBotProShielded, 0.6)] * (1 + (level - 6) // 3)) for group in range(group_count): @@ -821,8 +804,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): elif path == 6: this_target_point_s *= 0.7 - def _add_defender(defender_type: Tuple[Type[spazbot.SpazBot], - float], + def _add_defender(defender_type: Tuple[Type[SpazBot], float], pnt: str) -> Tuple[float, Dict[str, Any]]: # FIXME: should look into this warning # pylint: disable=cell-var-from-loop @@ -884,7 +866,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): else: assert self._waves is not None - wave = self._waves[self._wave - 1] + wave = self._waves[self._wavenum - 1] bot_types += wave['entries'] self._time_bonus_mult = 1.0 @@ -965,15 +947,13 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): # dropping land-mines powerups at some point (otherwise a crafty # player could fill the whole map with them) self._last_wave_end_time = ba.time() + t_sec - assert self._waves is not None + totalwaves = str(len(self._waves)) if self._waves is not None else '??' txtval = ba.Lstr( value='${A} ${B}', - subs=[ - ('${A}', ba.Lstr(resource='waveText')), - ('${B}', str(self._wave) + - ('' if self._preset in ['endless', 'endless_tournament'] else - ('/' + str(len(self._waves))))) - ]) + subs=[('${A}', ba.Lstr(resource='waveText')), + ('${B}', str(self._wavenum) + + ('' if self._preset in ['endless', 'endless_tournament'] + else f'/{totalwaves}'))]) self._wave_text = ba.NodeActor( ba.newnode('text', attrs={ @@ -989,16 +969,16 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): 'text': txtval })) - # noinspection PyTypeHints - def _on_bot_spawn(self, path: int, spaz: spazbot.SpazBot) -> None: + def _on_bot_spawn(self, path: int, spaz: SpazBot) -> None: + # Add our custom update callback and set some info for this bot. spaz_type = type(spaz) assert spaz is not None spaz.update_callback = self._update_bot - # FIXME: Do this in a type-safe way. - spaz.r_walk_row = path # type: ignore - spaz.r_walk_speed = self._get_bot_speed(spaz_type) # type: ignore + # Tack some custom attrs onto the spaz. + setattr(spaz, 'r_walk_row', path) + setattr(spaz, 'r_walk_speed', self._get_bot_speed(spaz_type)) def add_bot_at_point(self, point: str, @@ -1047,7 +1027,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): assert self._scoreboard is not None self._scoreboard.set_team_value(self.teams[0], score, max_score=None) - def _update_bot(self, bot: spazbot.SpazBot) -> bool: + def _update_bot(self, bot: SpazBot) -> bool: # Yup; that's a lot of return statements right there. # pylint: disable=too-many-return-statements @@ -1057,8 +1037,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): assert bot.node # FIXME: Do this in a type safe way. - r_walk_speed: float = bot.r_walk_speed # type: ignore - r_walk_row: int = bot.r_walk_row # type: ignore + r_walk_speed: float = getattr(bot, 'r_walk_speed') + r_walk_row: int = getattr(bot, 'r_walk_row') speed = r_walk_speed pos = bot.node.position @@ -1109,6 +1089,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): if ((ba.is_point_in_box(pos, boxes['b8']) and not ba.is_point_in_box(pos, boxes['b9'])) or pos == (0.0, 0.0, 0.0)): + # Default to walking right if we're still in the walking area. bot.node.move_left_right = speed bot.node.move_up_down = 0 @@ -1136,7 +1117,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): respawn_time, ba.Call(self.spawn_player_if_exists, player)) player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) - elif isinstance(msg, spazbot.SpazBotDeathMessage): + elif isinstance(msg, SpazBotDiedMessage): if msg.how is ba.DeathType.REACHED_GOAL: return pts, importance = msg.badguy.get_death_points(msg.how) @@ -1161,7 +1142,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._dingsoundhigh, volume=0.6) except Exception as exc: - print('EXC in Runaround on SpazBotDeathMessage:', exc) + print('EXC in Runaround on SpazBotDiedMessage:', exc) # Normally we pull scores from the score-set, but if there's no # player lets be explicit. @@ -1172,7 +1153,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): else: super().handlemessage(msg) - def _get_bot_speed(self, bot_type: Type[spazbot.SpazBot]) -> float: + def _get_bot_speed(self, bot_type: Type[SpazBot]) -> float: speed = self._bot_speed_map.get(bot_type) if speed is None: raise TypeError('Invalid bot type to _get_bot_speed(): ' + diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 14c3f54e..6840f909 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -26,14 +26,20 @@ import random from typing import TYPE_CHECKING import ba -from bastd.actor import spazbot from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.bomb import TNTSpawner from bastd.actor.scoreboard import Scoreboard from bastd.actor.powerupbox import PowerupBoxFactory, PowerupBox +from bastd.actor.spazbot import (SpazBotSet, SpazBotDiedMessage, BomberBot, + BomberBotPro, BomberBotProShielded, + BrawlerBot, BrawlerBotPro, + BrawlerBotProShielded, TriggerBot, + TriggerBotPro, TriggerBotProShielded, + ChargerBot, StickyBot, ExplodeyBot) if TYPE_CHECKING: from typing import Any, Dict, Type, List, Optional, Sequence + from bastd.actor.spazbot import SpazBot class Player(ba.Player['Team']): @@ -76,7 +82,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): self._excludepowerups: List[str] = [] self._scoreboard: Optional[Scoreboard] = None self._score = 0 - self._bots = spazbot.BotSet() + self._bots = SpazBotSet() self._dingsound = ba.getsound('dingSmall') self._dingsoundhigh = ba.getsound('dingSmallHigh') self._tntspawner: Optional[TNTSpawner] = None @@ -86,18 +92,18 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): # For each bot type: [spawn-rate, increase, d_increase] self._bot_spawn_types = { - spazbot.BomberBot: [1.00, 0.00, 0.000], - spazbot.BomberBotPro: [0.00, 0.05, 0.001], - spazbot.BomberBotProShielded: [0.00, 0.02, 0.002], - spazbot.BrawlerBot: [1.00, 0.00, 0.000], - spazbot.BrawlerBotPro: [0.00, 0.05, 0.001], - spazbot.BrawlerBotProShielded: [0.00, 0.02, 0.002], - spazbot.TriggerBot: [0.30, 0.00, 0.000], - spazbot.TriggerBotPro: [0.00, 0.05, 0.001], - spazbot.TriggerBotProShielded: [0.00, 0.02, 0.002], - spazbot.ChargerBot: [0.30, 0.05, 0.000], - spazbot.StickyBot: [0.10, 0.03, 0.001], - spazbot.ExplodeyBot: [0.05, 0.02, 0.002] + BomberBot: [1.00, 0.00, 0.000], + BomberBotPro: [0.00, 0.05, 0.001], + BomberBotProShielded: [0.00, 0.02, 0.002], + BrawlerBot: [1.00, 0.00, 0.000], + BrawlerBotPro: [0.00, 0.05, 0.001], + BrawlerBotProShielded: [0.00, 0.02, 0.002], + TriggerBot: [0.30, 0.00, 0.000], + TriggerBotPro: [0.00, 0.05, 0.001], + TriggerBotProShielded: [0.00, 0.02, 0.002], + ChargerBot: [0.30, 0.05, 0.000], + StickyBot: [0.10, 0.03, 0.001], + ExplodeyBot: [0.05, 0.02, 0.002] } # yapf: disable def on_transition_in(self) -> None: @@ -206,9 +212,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): for i in range(3): for playerpt in playerpts: dists[i] += abs(playerpt[0] - botspawnpts[i][0]) - - # Little random variation. - dists[i] += random.random() * 5.0 + dists[i] += random.random() * 5.0 # Minor random variation. if dists[0] > dists[1] and dists[0] > dists[2]: spawnpt = botspawnpts[0] elif dists[1] > dists[2]: @@ -227,7 +231,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): # Now go back through and see where this value falls. total = 0 - bottype: Optional[Type[spazbot.SpazBot]] = None + bottype: Optional[Type[SpazBot]] = None for spawntype in self._bot_spawn_types.items(): total += spawntype[1][0] if randval <= total: @@ -244,8 +248,9 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): spawntype[1][1] += spawntype[1][2] # incr spawn rate incr rate def _update_scores(self) -> None: - # Do achievements in default preset only. score = self._score + + # Achievements apply to the default preset only. if self._preset == 'default': if score >= 250: self._award_achievement('Last Stand Master') @@ -266,28 +271,21 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): self._score += msg.score self._update_scores() - elif isinstance(msg, spazbot.SpazBotDeathMessage): + elif isinstance(msg, SpazBotDiedMessage): pts, importance = msg.badguy.get_death_points(msg.how) target: Optional[Sequence[float]] if msg.killerplayer: - try: - assert msg.badguy.node - target = msg.badguy.node.position - except Exception: - ba.print_exception() - target = None - try: - self.stats.player_scored(msg.killerplayer, - pts, - target=target, - kill=True, - screenmessage=False, - importance=importance) - ba.playsound(self._dingsound - if importance == 1 else self._dingsoundhigh, - volume=0.6) - except Exception as exc: - print('EXC on last-stand SpazBotDeathMessage', exc) + assert msg.badguy.node + target = msg.badguy.node.position + self.stats.player_scored(msg.killerplayer, + pts, + target=target, + kill=True, + screenmessage=False, + importance=importance) + ba.playsound(self._dingsound + if importance == 1 else self._dingsoundhigh, + volume=0.6) # Normally we pull scores from the score-set, but if there's no # player lets be explicit. diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 1856296c..391c082e 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -906,8 +906,8 @@ def _preload4() -> None: ba.getmodel(mname) for sname in ['metalHit', 'metalSkid', 'refWhistle', 'achievement']: ba.getsound(sname) - from bastd.actor.flag import get_factory - get_factory() + from bastd.actor.flag import FlagFactory + FlagFactory.get() class MainMenuSession(ba.Session): diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py index a60787ab..9782d494 100644 --- a/assets/src/ba_data/python/bastd/ui/party.py +++ b/assets/src/ba_data/python/bastd/ui/party.py @@ -464,7 +464,6 @@ def handle_party_invite(name: str, invite_id: str) -> None: # FIXME: Ugly. # Let's store the invite-id away on the confirm window so we know if # we need to kill it later. - # noinspection PyTypeHints conf.party_invite_id = invite_id # type: ignore # store a weak-ref so we can get at this later diff --git a/docs/ba_module.md b/docs/ba_module.md index 943b679a..281527df 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-24 for Ballistica version 1.5.0 build 20026

    +

    last updated on 2020-05-25 for Ballistica version 1.5.0 build 20027

    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!


    @@ -51,7 +51,6 @@
  • ba.camerashake()
  • ba.emitfx()
  • ba.existing()
  • -
  • ba.get_collision_info()
  • ba.getactivity()
  • ba.getnodes()
  • ba.getsession()
  • @@ -200,6 +199,14 @@
  • ba.WidgetNotFoundError
  • +

    Misc Classes

    + +

    Misc Functions

    +

    Protocols

    • ba.Existable
    • @@ -1368,6 +1375,44 @@ mycall()

      Use ba.getcollidemodel() to instantiate one.

      +
      +

      ba.Collision

      +

      <top level class> +

      +

      A class providing info about occurring collisions.

      + +

      Attributes:

      +
      opposing_body, opposing_node, position, source_node
      +
      +

      opposing_body

      +

      int

      +

      The body index on the opposing node in the current collision.

      + +
      +

      opposing_node

      +

      ba.Node

      +

      The node the current callback material node is hitting.

      + +

      Throws a ba.NodeNotFoundError if the node does not exist. + This can be expected in some cases such as in 'disconnect' + callbacks triggered by deleting a currently-colliding node.

      + +
      +

      position

      +

      ba.Vec3

      +

      The position of the current collision.

      + +
      +

      source_node

      +

      ba.Node

      +

      The node containing the material triggering the current callback.

      + +

      Throws a ba.NodeNotFoundError if the node does not exist, though + the node should always exist (at least at the start of the collision + callback).

      + +
      +

      ba.Context

      <top level class> @@ -3547,10 +3592,13 @@ the right thing both for Node objects and values of None.

    getdelegate()

    -

    getdelegate() -> Any

    +

    getdelegate(type: Type, doraise: bool = False) -> <varies>

    -

    Returns the node's current delegate, which is the Python object -designated to handle the Node's messages.

    +

    Return the node's current delegate object if it matches a certain type.

    + +

    If the node has no delegate or it is not an instance of the passed +type, then None will be returned. If 'doraise' is True, then an +Exception will be raised instead in such cases.

    getnodetype()

    @@ -5732,18 +5780,6 @@ method) and will convert it to a None value if it does not exist. For more info, see notes on 'existables' here: https://ballistica.net/wiki/Coding-Style-Guide

    -
    -

    ba.get_collision_info()

    -

    get_collision_info(*args: Any) -> Any

    - -

    Return collision related values

    - -

    Category: Gameplay Functions

    - -

    Returns a single collision value or tuple of values such as location, -depth, nodes involved, etc. Only call this in the handler of a -collision-triggered callback or message

    -

    ba.get_valid_languages()

    get_valid_languages() -> List[str]

    @@ -5785,6 +5821,12 @@ to be loaded. To avoid hitches, instantiate your media objects in advance of when you will be using them, allowing time for them to load in the background if necessary.

    +
    +

    ba.getcollision()

    +

    getcollision() -> Collision

    + +

    Return the in-progress collision.

    +

    ba.getmaps()

    getmaps(playtype: str) -> List[str]

    diff --git a/tests/test_efro/test_dataclasses.py b/tests/test_efro/test_dataclasses.py index 4bd6a911..a2bf51f5 100644 --- a/tests/test_efro/test_dataclasses.py +++ b/tests/test_efro/test_dataclasses.py @@ -149,7 +149,6 @@ def test_validate() -> None: dataclass_validate(tclass) # No longer valid. - # noinspection PyTypeHints tclass.ival = None # type: ignore with pytest.raises(TypeError): dataclass_validate(tclass) diff --git a/tests/test_efro/test_entity.py b/tests/test_efro/test_entity.py index 063ab689..97354d92 100644 --- a/tests/test_efro/test_entity.py +++ b/tests/test_efro/test_entity.py @@ -80,7 +80,6 @@ class EntityTest(entity.Entity): fval2 = entity.Field('f2', entity.Float3Value()) -# noinspection PyTypeHints def test_entity_values() -> None: """Test various entity assigns for value and type correctness.""" ent = EntityTest() @@ -134,7 +133,6 @@ def test_entity_values() -> None: assert dict(ent.str_int_dict.items()) == {'foo': 123} -# noinspection PyTypeHints def test_entity_values_2() -> None: """Test various entity assigns for value and type correctness.""" @@ -191,7 +189,6 @@ def test_entity_values_2() -> None: assert static_type_equals(ent.grp.compoundlist[0].subval, bool) -# noinspection PyTypeHints def test_field_copies() -> None: """Test copying various values between fields.""" ent1 = EntityTest() diff --git a/tools/efro/entity/_entity.py b/tools/efro/entity/_entity.py index 144fec0f..9f66ab10 100644 --- a/tools/efro/entity/_entity.py +++ b/tools/efro/entity/_entity.py @@ -121,7 +121,6 @@ class EntityMixin: self.d_data = target.d_data # Make sure target blows up if someone tries to use it. - # noinspection PyTypeHints target.d_data = None # type: ignore def pruned_data(self) -> Dict[str, Any]: diff --git a/tools/efro/util.py b/tools/efro/util.py index fc74c96f..c7a2b69a 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -99,7 +99,7 @@ class DispatchMethodWrapper(Generic[TARG, TRET]): registry: Dict[Any, Callable] -# noinspection PyTypeHints, PyProtectedMember +# noinspection PyProtectedMember def dispatchmethod( func: Callable[[Any, TARG], TRET]) -> DispatchMethodWrapper[TARG, TRET]: From 06dfa73d0137cc119f28adcab9ee84b6b803d84a Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 25 May 2020 21:20:16 -0700 Subject: [PATCH 046/417] More modernizing --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 8 + assets/src/ba_data/python/_ba.py | 80 +-- assets/src/ba_data/python/ba/__init__.py | 2 +- assets/src/ba_data/python/ba/_app.py | 7 +- assets/src/ba_data/python/ba/_apputils.py | 4 +- assets/src/ba_data/python/ba/_collision.py | 12 +- assets/src/ba_data/python/ba/_error.py | 7 + assets/src/ba_data/python/ba/_gameutils.py | 23 +- assets/src/ba_data/python/ba/_hooks.py | 2 +- assets/src/ba_data/python/ba/_lobby.py | 501 ++++++++---------- assets/src/ba_data/python/ba/_powerup.py | 6 +- assets/src/ba_data/python/ba/_session.py | 12 +- assets/src/ba_data/python/bastd/actor/bomb.py | 6 +- .../python/bastd/actor/controlsguide.py | 10 +- .../ba_data/python/bastd/actor/powerupbox.py | 4 +- assets/src/ba_data/python/bastd/actor/spaz.py | 22 +- .../src/ba_data/python/bastd/game/assault.py | 2 +- .../python/bastd/game/capturetheflag.py | 52 +- .../ba_data/python/bastd/game/chosenone.py | 2 +- .../src/ba_data/python/bastd/game/conquest.py | 6 +- .../python/bastd/game/easteregghunt.py | 6 +- .../src/ba_data/python/bastd/game/football.py | 4 +- .../src/ba_data/python/bastd/game/hockey.py | 8 +- .../python/bastd/game/kingofthehill.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 6 +- .../ba_data/python/bastd/game/runaround.py | 2 +- .../python/bastd/ui/settings/controls.py | 6 +- docs/ba_module.md | 60 ++- 29 files changed, 432 insertions(+), 454 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 8b7ec793..26963766 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/f0/c3261a8a7391a2b654da82c35c21", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/33/e2/85a8cbf23404612e6761cf02348b", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5b/0d/d906be5fc2a75b5214a94cafe6ca", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/53/72d665caf5dfed84312ae6862642", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/68/2d98f2d1ee67b6d54adbdf76c863", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/3a/33f8f311260542126acea44d05e2", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/18/eb/dd39bcfa33983864089d3fb7f666", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/1d/3440010fcbcf18c5a6b2966f7fca", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9b/fa/b4ad4b8b82fefe1faad610065b9f", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7f/b9/03af92db6140135ddfa467a1545d", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/b9/687fc5fa38c3faf7a47eb4241a3c", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cf/2b/589db924b489972981e10850a4e3" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/97/fd0e5553917019236912a7010d38", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/43/32/c48a4da7fcc8c17132077da852d7", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/75/13/2bc3ae9026386d1b515ede107e17", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/9a/b112f788f528ec9e3627622698ac", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/87/fdb3e925f3be1cc353db94d61c5a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/ba/125457c69bc2940850ab84c4cc6a", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/d4/5efcef1f85b2bfea7bbb81800580", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/66/75a3a0f27d07131473e804a5b937", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/51/6c/911ba80ba913e6dac1cafa5c8a74", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/cc/cf896173a8d5731ada2aace59146", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a2/12/aa1f0ca5506f0b57f93ca9adf7be", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e1/5f/f372d0ba9591b99284b9b50d7cdf" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 898fe13e..1cf96c30 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -480,6 +480,7 @@ downmix dpad dpath + dprofilename drawscore drawscreen dripity @@ -756,8 +757,10 @@ getcurrency getcwd getdata + getinputdevice getkillerplayer getlevelname + getlog getmaps getmodel getnodes @@ -937,6 +940,7 @@ joedeshon johab joinable + joinmsg jovica jsonstr jsonstrbase @@ -1267,6 +1271,8 @@ openssh operasinger oppnode + opposingbody + opposingnode opstr optparse orchestrahitsound @@ -1504,6 +1510,7 @@ qrencode qual quoprimime + rando randommodule randval rankbutton @@ -1672,6 +1679,7 @@ soundtrackname sourceimages sourcelines + sourcenode spacelen spacingstr spammers diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 6b593af3..f1f90179 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=164420280597992494471294420110866243586 +# SOURCES_HASH=318889180473540875493180206824864665481 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -691,8 +691,8 @@ class Node: def delete(self, ignore_missing: bool = True) -> None: """delete(ignore_missing: bool = True) -> None - Delete the node. Ignores already-deleted nodes unless ignore_missing - is False, in which case an Exception is thrown. + Delete the node. Ignores already-deleted nodes if ignore_missing + is True; otherwise a ba.NodeNotFoundError is thrown. """ return None @@ -716,6 +716,7 @@ class Node: """ return str() + # Show that ur return type varies based on "doraise" value: @overload def getdelegate(self, type: Type[_T], @@ -733,7 +734,7 @@ class Node: If the node has no delegate or it is not an instance of the passed type, then None will be returned. If 'doraise' is True, then an - Exception will be raised instead in such cases. + ba.DelegateNotFoundError will be raised instead. """ return None @@ -818,6 +819,9 @@ class SessionPlayer: storing data associated with this Player. This gets cleared for each new ba.Activity. + inputdevice: ba.InputDevice + The input device associated with the player. + color: Sequence[float] The base color for this Player. In team games this will match the ba.SessionTeam's color. @@ -839,6 +843,7 @@ class SessionPlayer: team: ba.SessionTeam sessiondata: Dict gamedata: Dict + inputdevice: ba.InputDevice color: Sequence[float] highlight: Sequence[float] character: str @@ -892,14 +897,6 @@ class SessionPlayer: """ return {'foo': 'bar'} - def get_input_device(self) -> ba.InputDevice: - """get_input_device() -> ba.InputDevice - - Returns the player's input device. - """ - import ba # pylint: disable=cyclic-import - return ba.InputDevice() - def get_name(self, full: bool = False, icon: bool = True) -> str: """get_name(full: bool = False, icon: bool = True) -> str @@ -2065,22 +2062,6 @@ def get_idle_time() -> int: return int() -def get_input_device(name: str, - unique_id: str, - doraise: bool = True) -> ba.InputDevice: - """get_input_device(name: str, unique_id: str, doraise: bool = True) - -> ba.InputDevice - - (internal) - - Given a type name and a unique identifier, returns an InputDevice. - Throws an Exception if the input-device is not found, or returns None - if 'doraise' is False. - """ - import ba # pylint: disable=cyclic-import - return ba.InputDevice() - - def get_local_active_input_devices_count() -> int: """get_local_active_input_devices_count() -> int @@ -2089,14 +2070,6 @@ def get_local_active_input_devices_count() -> int: return int() -def get_log() -> str: - """get_log() -> str - - (internal) - """ - return str() - - def get_log_file_path() -> str: """get_log_file_path() -> str @@ -2389,6 +2362,41 @@ def getdata(name: str) -> ba.Data: return ba.Data() +# Show that our return type varies based on "doraise" value: +@overload +def getinputdevice(name: str, + unique_id: str, + doraise: Literal[True] = True) -> ba.InputDevice: + ... + + +@overload +def getinputdevice(name: str, unique_id: str, + doraise: Literal[False]) -> Optional[ba.InputDevice]: + ... + + +def getinputdevice(name: str, unique_id: str, doraise: bool = True) -> Any: + """getinputdevice(name: str, unique_id: str, doraise: bool = True) + -> + + (internal) + + Given a type name and a unique identifier, returns an InputDevice. + Throws an Exception if the input-device is not found, or returns None + if 'doraise' is False. + """ + return None + + +def getlog() -> str: + """getlog() -> str + + (internal) + """ + return str() + + def getmodel(name: str) -> ba.Model: """getmodel(name: str) -> ba.Model diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 25869a72..9e808242 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -53,7 +53,7 @@ from ba._error import (print_exception, print_error, NotFoundError, InputDeviceNotFoundError, WidgetNotFoundError, ActivityNotFoundError, TeamNotFoundError, SessionTeamNotFoundError, SessionNotFoundError, - DependencyError) + DelegateNotFoundError, DependencyError) from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity from ba._gameresults import TeamGameResults diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 484e1e67..99129efc 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -22,6 +22,7 @@ from __future__ import annotations import time +import random from typing import TYPE_CHECKING import _ba @@ -376,7 +377,7 @@ class App: # Lobby. self.lobby_random_profile_index: int = 1 - self.lobby_random_char_index_offset: Optional[int] = None + self.lobby_random_char_index_offset = random.randrange(1000) self.lobby_account_profile_device_id: Optional[int] = None # Main Menu. @@ -722,7 +723,7 @@ class App: game: str, force: bool = False, args: Dict = None) -> bool: - """High level way to launch a co-op session locally.""" + """High level way to launch a local co-op session.""" # pylint: disable=cyclic-import from ba._campaign import get_campaign from bastd.ui.coop.level import CoopLevelLockedWindow @@ -788,7 +789,7 @@ class App: color=(1, 1, 0)), timetype=TimeType.REAL) - def shutdown(self) -> None: + def on_app_shutdown(self) -> None: """(internal)""" self.music.on_app_shutdown() diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index 25a77d7d..1c8b1da5 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -43,7 +43,7 @@ def is_browser_likely_available() -> bool: """ app = _ba.app platform = app.platform - touchscreen = _ba.get_input_device('TouchScreen', '#1', doraise=False) + touchscreen = _ba.getinputdevice('TouchScreen', '#1', doraise=False) # If we're on a vr device or an android device with no touchscreen, # assume no browser. @@ -100,7 +100,7 @@ def handle_log() -> None: except Exception: activityname = 'unavailable' info = { - 'log': _ba.get_log(), + 'log': _ba.getlog(), 'version': app.version, 'build': app.build_number, 'userAgentString': app.user_agent_string, diff --git a/assets/src/ba_data/python/ba/_collision.py b/assets/src/ba_data/python/ba/_collision.py index b41aa104..7d4261dd 100644 --- a/assets/src/ba_data/python/ba/_collision.py +++ b/assets/src/ba_data/python/ba/_collision.py @@ -40,37 +40,37 @@ class Collision: return _ba.Vec3(_ba.get_collision_info('position')) @property - def source_node(self) -> ba.Node: + def sourcenode(self) -> ba.Node: """The node containing the material triggering the current callback. Throws a ba.NodeNotFoundError if the node does not exist, though the node should always exist (at least at the start of the collision callback). """ - node = _ba.get_collision_info('source_node') + node = _ba.get_collision_info('sourcenode') assert isinstance(node, (_ba.Node, type(None))) if not node: raise NodeNotFoundError() return node @property - def opposing_node(self) -> ba.Node: + def opposingnode(self) -> ba.Node: """The node the current callback material node is hitting. Throws a ba.NodeNotFoundError if the node does not exist. This can be expected in some cases such as in 'disconnect' callbacks triggered by deleting a currently-colliding node. """ - node = _ba.get_collision_info('opposing_node') + node = _ba.get_collision_info('opposingnode') assert isinstance(node, (_ba.Node, type(None))) if not node: raise NodeNotFoundError() return node @property - def opposing_body(self) -> int: + def opposingbody(self) -> int: """The body index on the opposing node in the current collision.""" - body = _ba.get_collision_info('opposing_body') + body = _ba.get_collision_info('opposingbody') assert isinstance(body, int) return body diff --git a/assets/src/ba_data/python/ba/_error.py b/assets/src/ba_data/python/ba/_error.py index 42e8cd89..afb36569 100644 --- a/assets/src/ba_data/python/ba/_error.py +++ b/assets/src/ba_data/python/ba/_error.py @@ -77,6 +77,13 @@ class TeamNotFoundError(NotFoundError): """ +class DelegateNotFoundError(NotFoundError): + """Exception raised when an expected delegate object does not exist. + + category: Exception Classes + """ + + class SessionTeamNotFoundError(NotFoundError): """Exception raised when an expected ba.SessionTeam does not exist. diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index fcaf3f4b..e6cb6adf 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -194,10 +194,10 @@ def animate(node: ba.Node, # Temp sanity check while we transition from milliseconds to seconds # based time values. - if _ba.app.test_build and not suppress_format_warning: - for item in items: - # (PyCharm seems to think item is a float, not a tuple) - _ba.time_format_check(timeformat, item[0]) + if __debug__: + if not suppress_format_warning: + for item in items: + _ba.time_format_check(timeformat, item[0]) curve = _ba.newnode('animcurve', owner=node, @@ -221,7 +221,6 @@ def animate(node: ba.Node, # FIXME: Even if we are looping we should have a way to die once we # get disconnected. if not loop: - # (PyCharm seems to think item is a float, not a tuple) _ba.timer(int(mult * items[-1][0]) + 1000, curve.delete, timeformat=TimeFormat.MILLISECONDS) @@ -259,10 +258,11 @@ def animate_array(node: ba.Node, # Temp sanity check while we transition from milliseconds to seconds # based time values. - if _ba.app.test_build and not suppress_format_warning: - for item in items: - # (PyCharm seems to think item is a float, not a tuple) - _ba.time_format_check(timeformat, item[0]) + if __debug__: + if not suppress_format_warning: + for item in items: + # (PyCharm seems to think item is a float, not a tuple) + _ba.time_format_check(timeformat, item[0]) if timeformat is TimeFormat.SECONDS: mult = 1000 @@ -381,8 +381,9 @@ def timestring(timeval: float, # Temp sanity check while we transition from milliseconds to seconds # based time values. - if _ba.app.test_build and not suppress_format_warning: - _ba.time_format_check(timeformat, timeval) + if __debug__: + if not suppress_format_warning: + _ba.time_format_check(timeformat, timeval) # We operate on milliseconds internally. if timeformat is TimeFormat.SECONDS: diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index 7c1d2c3c..c12b3c25 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -293,7 +293,7 @@ def do_quit() -> None: def shutdown() -> None: - _ba.app.shutdown() + _ba.app.on_app_shutdown() def gc_disable() -> None: diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 30a08245..8d4716fe 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -19,16 +19,19 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Implements lobby system for gathering before games, char select, etc.""" -# pylint: disable=too-many-lines from __future__ import annotations -import random import weakref from dataclasses import dataclass from typing import TYPE_CHECKING import _ba +from ba._error import print_exception, print_error, NotFoundError +from ba._gameutils import animate, animate_array +from ba._lang import Lstr +from ba._enums import SpecialChar +from ba._profile import get_player_profile_colors if TYPE_CHECKING: from typing import Optional, List, Dict, Any, Sequence, Union @@ -44,45 +47,22 @@ class JoinInfo: """Display useful info for joiners.""" def __init__(self, lobby: ba.Lobby): - # pylint: disable=too-many-locals - from ba import _input - from ba._lang import Lstr from ba._nodeactor import NodeActor from ba._general import WeakCall - from ba._enums import SpecialChar - can_switch_teams = (len(lobby.teams) > 1) self._state = 0 - press_to_punch: Union[str, - ba.Lstr] = _ba.charstr(SpecialChar.LEFT_BUTTON) - press_to_bomb: Union[str, - ba.Lstr] = _ba.charstr(SpecialChar.RIGHT_BUTTON) + self._press_to_punch: Union[str, ba.Lstr] = _ba.charstr( + SpecialChar.LEFT_BUTTON) + self._press_to_bomb: Union[str, ba.Lstr] = _ba.charstr( + SpecialChar.RIGHT_BUTTON) + self._joinmsg = Lstr(resource='pressAnyButtonToJoinText') + can_switch_teams = (len(lobby.teams) > 1) # If we have a keyboard, grab keys for punch and pickup. # FIXME: This of course is only correct on the local device; # Should change this for net games. - keyboard: Optional[ba.InputDevice] = _ba.get_input_device( - 'Keyboard', '#1', doraise=False) + keyboard = _ba.getinputdevice('Keyboard', '#1', doraise=False) if keyboard is not None: - punch_key = keyboard.get_button_name( - _input.get_device_value(keyboard, 'buttonPunch')) - press_to_punch = Lstr(resource='orText', - subs=[('${A}', - Lstr(value='\'${K}\'', - subs=[('${K}', punch_key)])), - ('${B}', press_to_punch)]) - bomb_key = keyboard.get_button_name( - _input.get_device_value(keyboard, 'buttonBomb')) - press_to_bomb = Lstr(resource='orText', - subs=[('${A}', - Lstr(value='\'${K}\'', - subs=[('${K}', bomb_key)])), - ('${B}', press_to_bomb)]) - join_str = Lstr(value='${A} < ${B} >', - subs=[('${A}', - Lstr(resource='pressPunchToJoinText')), - ('${B}', press_to_punch)]) - else: - join_str = Lstr(resource='pressAnyButtonToJoinText') + self._update_for_keyboard(keyboard) flatness = 1.0 if _ba.app.vr_mode else 0.0 self._text = NodeActor( @@ -94,11 +74,11 @@ class JoinInfo: 'h_align': 'center', 'color': (0.7, 0.7, 0.95, 1.0), 'flatness': flatness, - 'text': join_str + 'text': self._joinmsg })) if _ba.app.kiosk_mode: - self._messages = [join_str] + self._messages = [self._joinmsg] else: msg1 = Lstr(resource='pressToSelectProfileText', subs=[ @@ -108,15 +88,38 @@ class JoinInfo: msg2 = Lstr(resource='pressToOverrideCharacterText', subs=[('${BUTTONS}', Lstr(resource='bombBoldText'))]) msg3 = Lstr(value='${A} < ${B} >', - subs=[('${A}', msg2), ('${B}', press_to_bomb)]) + subs=[('${A}', msg2), ('${B}', self._press_to_bomb)]) self._messages = (([ - Lstr(resource='pressToSelectTeamText', - subs=[('${BUTTONS}', _ba.charstr(SpecialChar.LEFT_ARROW) + - ' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))]) - ] if can_switch_teams else []) + [msg1] + [msg3] + [join_str]) + Lstr( + resource='pressToSelectTeamText', + subs=[('${BUTTONS}', _ba.charstr(SpecialChar.LEFT_ARROW) + + ' ' + _ba.charstr(SpecialChar.RIGHT_ARROW))], + ) + ] if can_switch_teams else []) + [msg1] + [msg3] + [self._joinmsg]) self._timer = _ba.Timer(4.0, WeakCall(self._update), repeat=True) + def _update_for_keyboard(self, keyboard: ba.InputDevice) -> None: + from ba import _input + punch_key = keyboard.get_button_name( + _input.get_device_value(keyboard, 'buttonPunch')) + self._press_to_punch = Lstr(resource='orText', + subs=[('${A}', + Lstr(value='\'${K}\'', + subs=[('${K}', punch_key)])), + ('${B}', self._press_to_punch)]) + bomb_key = keyboard.get_button_name( + _input.get_device_value(keyboard, 'buttonBomb')) + self._press_to_bomb = Lstr(resource='orText', + subs=[('${A}', + Lstr(value='\'${K}\'', + subs=[('${K}', bomb_key)])), + ('${B}', self._press_to_bomb)]) + self._joinmsg = Lstr(value='${A} < ${B} >', + subs=[('${A}', + Lstr(resource='pressPunchToJoinText')), + ('${B}', self._press_to_punch)]) + def _update(self) -> None: assert self._text.node self._text.node.text = self._messages[self._state] @@ -150,13 +153,6 @@ class Chooser: def __init__(self, vpos: float, player: _ba.SessionPlayer, lobby: 'Lobby') -> None: - # FIXME: Tidy up around here. - # pylint: disable=too-many-branches - # pylint: disable=too-many-statements - from ba import _gameutils - from ba import _profile - from ba import _lang - app = _ba.app self._deek_sound = _ba.getsound('deek') self._click_sound = _ba.getsound('click01') self._punchsound = _ba.getsound('punch01') @@ -172,11 +168,16 @@ class Chooser: self._profilename = '' self._profilenames: List[str] = [] self._ready: bool = False - self.character_names: List[str] = [] - self.last_change: Sequence[Union[float, int]] = (0, 0) + self._character_names: List[str] = [] + self._last_change: Sequence[Union[float, int]] = (0, 0) + self._profiles: Dict[str, Dict[str, Any]] = {} - # Hmm does this need to be public? - self.profiles: Dict[str, Dict[str, Any]] = {} + app = _ba.app + + # try: + # print(player.inputdevice) + # except Exception as exc: + # print('GOT EXC', type(exc)) # Load available profiles either from the local config or from the # remote device. @@ -186,109 +187,26 @@ class Chooser: # the team-id! self._selected_team_index: int = self.lobby.next_add_team - # Store a persistent random character index; we'll use this for the - # '_random' profile. Let's use their input_device id to seed it. This - # will give a persistent character for them between games and will - # distribute characters nicely if everyone is random. - try: - input_device_id = self._player.get_input_device().id - except Exception: - from ba import _error - _error.print_exception('Error getting device-id on chooser create') - input_device_id = 0 + # Store a persistent random character index and colors; we'll use this + # for the '_random' profile. Let's use their input_device id to seed + # it. This will give a persistent character for them between games + # and will distribute characters nicely if everyone is random. + self._random_color, self._random_highlight = ( + get_player_profile_colors(None)) - if app.lobby_random_char_index_offset is None: - - # We want the first device that asks for a chooser to always get - # spaz as a random character.. - # scratch that.. we now kinda accomplish the same thing with - # account profiles so lets just be fully random here. - app.lobby_random_char_index_offset = (random.randrange(1000)) - - # To calc our random index we pick a random character out of our + # To calc our random character we pick a random one out of our # unlocked list and then locate that character's index in the full # list. char_index_offset = app.lobby_random_char_index_offset - assert char_index_offset is not None - self._random_character_index = ((input_device_id + char_index_offset) % - len(self.character_names)) - self._random_color, self._random_highlight = ( - _profile.get_player_profile_colors(None)) + self._random_character_index = ( + (player.inputdevice.id + char_index_offset) % + len(self._character_names)) - # Attempt to pick an initial profile based on what's been stored - # for this input device. - input_device = self._player.get_input_device() - try: - name = input_device.name - unique_id = input_device.unique_identifier - self._profilename = ( - app.config['Default Player Profiles'][name + ' ' + unique_id]) - self._profileindex = self._profilenames.index(self._profilename) + # Attempt to set an initial profile based on what was used previously + # for this input-device, etc. + self._profileindex = self._select_initial_profile() + self._profilename = self._profilenames[self._profileindex] - # If this one is __account__ and is local and we haven't marked - # anyone as the account-profile device yet, mark this guy as it. - # (prevents the next joiner from getting the account profile too). - if (self._profilename == '__account__' - and not input_device.is_remote_client - and app.lobby_account_profile_device_id is None): - app.lobby_account_profile_device_id = input_device_id - - # Well hmm that didn't work.. pick __account__, _random, or some - # other random profile. - except Exception: - - profilenames = self._profilenames - - # We want the first local input-device in the game to latch on to - # the account profile. - if (not input_device.is_remote_client - and not input_device.is_controller_app): - if (app.lobby_account_profile_device_id is None - and '__account__' in profilenames): - app.lobby_account_profile_device_id = input_device_id - - # If this is the designated account-profile-device, try to default - # to the account profile. - if (input_device_id == app.lobby_account_profile_device_id - and '__account__' in profilenames): - self._profileindex = profilenames.index('__account__') - else: - - # If this is the controller app, it defaults to using a random - # profile (since we can pull the random name from the app). - if input_device.is_controller_app: - self._profileindex = profilenames.index('_random') - else: - - # If its a client connection, for now just force - # the account profile if possible.. (need to provide a - # way for clients to specify/remember their default - # profile on remote servers that do not already know them). - if (input_device.is_remote_client - and '__account__' in profilenames): - self._profileindex = profilenames.index('__account__') - else: - - # Cycle through our non-random profiles once; after - # that, everyone gets random. - while (app.lobby_random_profile_index < - len(profilenames) - and profilenames[app.lobby_random_profile_index] - in ('_random', '__account__', '_edit')): - app.lobby_random_profile_index += 1 - if (app.lobby_random_profile_index < - len(profilenames)): - self._profileindex = ( - app.lobby_random_profile_index) - app.lobby_random_profile_index += 1 - else: - self._profileindex = profilenames.index('_random') - - self._profilename = profilenames[self._profileindex] - - self.character_index = self._random_character_index - self._color = self._random_color - self._highlight = self._random_highlight self._text_node = _ba.newnode('text', delegate=self, attrs={ @@ -300,8 +218,7 @@ class Chooser: 'v_align': 'center', 'v_attach': 'top' }) - - _gameutils.animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) + animate(self._text_node, 'scale', {0: 0, 0.1: 1.0}) self.icon = _ba.newnode('image', owner=self._text_node, attrs={ @@ -311,20 +228,83 @@ class Chooser: 'attach': 'topCenter' }) - _gameutils.animate_array(self.icon, 'scale', 2, { - 0: (0, 0), - 0.1: (45, 45) - }) + animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) + + # Set our initial name to '' in case anyone asks. + self._player.set_name(Lstr(resource='choosingPlayerText').evaluate(), + real=False) + + # Init these to our rando but they should get switched to the + # selected profile (if any) right after. + self._character_index = self._random_character_index + self._color = self._random_color + self._highlight = self._random_highlight + + self.update_from_profile() + self.update_position() + self._inited = True self._set_ready(False) - # Set our initial name to '' in case anyone asks. - self._player.set_name( - _lang.Lstr(resource='choosingPlayerText').evaluate(), real=False) + def _select_initial_profile(self) -> int: + app = _ba.app + profilenames = self._profilenames + inputdevice = self._player.inputdevice - self.update_from_player_profiles() - self.update_position() - self._inited = True + # If we've got a set profile name for this device, work backwards + # from that to get our index. + dprofilename = (app.config.get('Default Player Profiles', + {}).get(inputdevice.name + ' ' + + inputdevice.unique_identifier)) + if dprofilename is not None and dprofilename in profilenames: + # If we got '__account__' and its local and we haven't marked + # anyone as the 'account profile' device yet, mark this guy as + # it. (prevents the next joiner from getting the account + # profile too). + if (dprofilename == '__account__' + and not inputdevice.is_remote_client + and app.lobby_account_profile_device_id is None): + app.lobby_account_profile_device_id = inputdevice.id + return profilenames.index(dprofilename) + + # We want to mark the first local input-device in the game + # as the 'account profile' device. + if (not inputdevice.is_remote_client + and not inputdevice.is_controller_app): + if (app.lobby_account_profile_device_id is None + and '__account__' in profilenames): + app.lobby_account_profile_device_id = inputdevice.id + + # If this is the designated account-profile-device, try to default + # to the account profile. + if (inputdevice.id == app.lobby_account_profile_device_id + and '__account__' in profilenames): + return profilenames.index('__account__') + + # If this is the controller app, it defaults to using a random + # profile (since we can pull the random name from the app). + if inputdevice.is_controller_app and '_random' in profilenames: + return profilenames.index('_random') + + # If its a client connection, for now just force + # the account profile if possible.. (need to provide a + # way for clients to specify/remember their default + # profile on remote servers that do not already know them). + if inputdevice.is_remote_client and '__account__' in profilenames: + return profilenames.index('__account__') + + # Cycle through our non-random profiles once; after + # that, everyone gets random. + while (app.lobby_random_profile_index < len(profilenames) + and profilenames[app.lobby_random_profile_index] + in ('_random', '__account__', '_edit')): + app.lobby_random_profile_index += 1 + if app.lobby_random_profile_index < len(profilenames): + profileindex = app.lobby_random_profile_index + app.lobby_random_profile_index += 1 + return profileindex + assert '_random' in profilenames + return profilenames.index('_random') @property def player(self) -> ba.SessionPlayer: @@ -353,44 +333,39 @@ class Chooser: """The chooser's ba.Lobby.""" lobby = self._lobby() if lobby is None: - from ba import _error - raise _error.NotFoundError('Lobby does not exist.') + raise NotFoundError('Lobby does not exist.') return lobby def get_lobby(self) -> Optional[ba.Lobby]: """Return this chooser's lobby if it still exists; otherwise None.""" return self._lobby() - def update_from_player_profiles(self) -> None: - """Set character based on profile; otherwise use pre-picked random.""" - try: - from ba import _profile - - # Store the name even though we usually use index (in case - # the profile list changes) - self._profilename = self._profilenames[self._profileindex] - character = self.profiles[self._profilename]['character'] + def update_from_profile(self) -> None: + """Set character/colors based on the current profile.""" + self._profilename = self._profilenames[self._profileindex] + if self._profilename == '_edit': + pass + elif self._profilename == '_random': + self._character_index = self._random_character_index + self._color = self._random_color + self._highlight = self._random_highlight + else: + character = self._profiles[self._profilename]['character'] # At the moment we're not properly pulling the list # of available characters from clients, so profiles might use a # character not in their list. For now, just go ahead and add # a character name to their list as long as we're aware of it. # This just means they won't always be able to override their - # character to others they own, but profile characters should work - # (and we validate profiles on the master server so no exploit - # opportunities) - if (character not in self.character_names + # character to others they own, but profile characters + # should work (and we validate profiles on the master server + # so no exploit opportunities) + if (character not in self._character_names and character in _ba.app.spaz_appearances): - self.character_names.append(character) - self.character_index = self.character_names.index(character) - self._color, self._highlight = (_profile.get_player_profile_colors( - self._profilename, profiles=self.profiles)) - except Exception: - # FIXME: Should never use top level Exception for logic; only - # error catching (and they should always be logged). - self.character_index = self._random_character_index - self._color = self._random_color - self._highlight = self._random_highlight + self._character_names.append(character) + self._character_index = self._character_names.index(character) + self._color, self._highlight = (get_player_profile_colors( + self._profilename, profiles=self._profiles)) self._update_icon() self._update_text() @@ -401,52 +376,51 @@ class Chooser: # Re-construct our profile index and other stuff since the profile # list might have changed. - input_device = self._player.get_input_device() + input_device = self._player.inputdevice is_remote = input_device.is_remote_client is_test_input = input_device.name.startswith('TestInput') # Pull this player's list of unlocked characters. if is_remote: - # FIXME: Pull this from remote player (but make sure to - # filter it to ones we've got). - self.character_names = ['Spaz'] + # TODO: Pull this from the remote player. + # (but make sure to filter it to the ones we've got). + self._character_names = ['Spaz'] else: - self.character_names = self.lobby.character_names_local_unlocked + self._character_names = self.lobby.character_names_local_unlocked # If we're a local player, pull our local profiles from the config. # Otherwise ask the remote-input-device for its profile list. if is_remote: - self.profiles = input_device.get_player_profiles() + self._profiles = input_device.get_player_profiles() else: - self.profiles = app.config.get('Player Profiles', {}) + self._profiles = app.config.get('Player Profiles', {}) # These may have come over the wire from an older # (non-unicode/non-json) version. # Make sure they conform to our standards # (unicode strings, no tuples, etc) - self.profiles = json_prep(self.profiles) + self._profiles = json_prep(self._profiles) # Filter out any characters we're unaware of. - for profile in list(self.profiles.items()): + for profile in list(self._profiles.items()): if profile[1].get('character', '') not in app.spaz_appearances: profile[1]['character'] = 'Spaz' - # Add in a random one so we're ok even if there's no - # user-created profiles. - self.profiles['_random'] = {} + # Add in a random one so we're ok even if there's no user profiles. + self._profiles['_random'] = {} # In kiosk mode we disable account profiles to force random. if app.kiosk_mode: - if '__account__' in self.profiles: - del self.profiles['__account__'] + if '__account__' in self._profiles: + del self._profiles['__account__'] # For local devices, add it an 'edit' option which will pop up # the profile window. if not is_remote and not is_test_input and not app.kiosk_mode: - self.profiles['_edit'] = {} + self._profiles['_edit'] = {} # Build a sorted name list we can iterate through. - self._profilenames = list(self.profiles.keys()) + self._profilenames = list(self._profiles.keys()) self._profilenames.sort(key=lambda x: x.lower()) if self._profilename in self._profilenames: @@ -457,90 +431,66 @@ class Chooser: def update_position(self) -> None: """Update this chooser's position.""" - from ba import _gameutils - # Hmmm this shouldn't be happening. - if not self._text_node: - print('Error: chooser text nonexistent..') - import traceback - traceback.print_stack() - return + assert self._text_node spacing = 350 teams = self.lobby.teams offs = (spacing * -0.5 * len(teams) + spacing * self._selected_team_index + 250) if len(teams) > 1: offs -= 35 - _gameutils.animate_array(self._text_node, 'position', 2, { + animate_array(self._text_node, 'position', 2, { 0: self._text_node.position, 0.1: (-100 + offs, self._vpos + 23) }) - _gameutils.animate_array(self.icon, 'position', 2, { + animate_array(self.icon, 'position', 2, { 0: self.icon.position, 0.1: (-130 + offs, self._vpos + 22) }) def get_character_name(self) -> str: """Return the selected character name.""" - return self.character_names[self.character_index] + return self._character_names[self._character_index] def _do_nothing(self) -> None: """Does nothing! (hacky way to disable callbacks)""" def _get_name(self, full: bool = False) -> str: - # FIXME: Needs cleanup. - # pylint: disable=too-many-branches - from ba._lang import Lstr - from ba._enums import SpecialChar name_raw = name = self._profilenames[self._profileindex] clamp = False if name == '_random': - input_device: Optional[ba.InputDevice] try: - input_device = self._player.get_input_device() + name = (self._player.inputdevice.get_default_player_name()) except Exception: - input_device = None - if input_device is not None: - name = input_device.get_default_player_name() - else: + print_exception('Error getting _random chooser name.') name = 'Invalid' - if not full: - clamp = True + clamp = not full elif name == '__account__': try: - input_device = self._player.get_input_device() + name = self._player.inputdevice.get_account_name(full) except Exception: - input_device = None - if input_device is not None: - name = input_device.get_account_name(full) - else: + print_exception('Error getting account name for chooser.') name = 'Invalid' - if not full: - clamp = True + clamp = not full elif name == '_edit': - # FIXME: This causes problems as an Lstr, but its ok to - # explicitly translate for now since this is only shown on the - # host. (also should elaborate; don't remember what problems this - # caused) + # Explicitly flattening this to a str; it's only relevant on + # the host so that's ok. name = (Lstr( resource='createEditPlayerText', fallback_resource='editProfileWindow.titleNewText').evaluate()) else: - # If we have a regular profile marked as global with an icon, # use it (for full only). if full: try: - if self.profiles[name_raw].get('global', False): - icon = (self.profiles[name_raw]['icon'] - if 'icon' in self.profiles[name_raw] else + if self._profiles[name_raw].get('global', False): + icon = (self._profiles[name_raw]['icon'] + if 'icon' in self._profiles[name_raw] else _ba.charstr(SpecialChar.LOGO)) name = icon + name except Exception: - from ba import _error - _error.print_exception('Error applying global icon') + print_exception('Error applying global icon.') else: - # We now clamp non-full versions of names so there's at # least some hope of reading them in-game. clamp = True @@ -561,9 +511,9 @@ class Chooser: with _ba.Context('ui'): pbrowser.ProfileBrowserWindow(in_main_menu=False) - # give their input-device UI ownership too + # Give their input-device UI ownership too # (prevent someone else from snatching it in crowded games) - _ba.set_ui_input_device(self._player.get_input_device()) + _ba.set_ui_input_device(self._player.inputdevice) return if not ready: @@ -597,7 +547,7 @@ class Chooser: Call(self.handlemessage, ChangeMessage('ready', 0))) # Store the last profile picked by this input for reuse. - input_device = self._player.get_input_device() + input_device = self._player.inputdevice name = input_device.name unique_id = input_device.unique_identifier device_profiles = _ba.app.config.setdefault( @@ -607,7 +557,8 @@ class Chooser: # to random; in that case we'll want to start picking up custom # profiles if/when one is made so keep our setting cleared. special = ('_random', '_edit', '__account__') - have_custom_profiles = any(p not in special for p in self.profiles) + have_custom_profiles = any(p not in special + for p in self._profiles) profilekey = name + ' ' + unique_id if profilename == '_random' and not have_custom_profiles: @@ -643,7 +594,7 @@ class Chooser: # choosers that have been marked as ready. team_player_counts = {} for team in teams: - team_player_counts[team.id] = (len(team.players)) + team_player_counts[team.id] = len(team.players) for chooser in lobby.choosers: if chooser.ready: team_player_counts[chooser.get_team().id] += 1 @@ -668,15 +619,14 @@ class Chooser: # TODO: should handle this at the engine layer so this is unnecessary. def _handle_repeat_message_attack(self) -> None: now = _ba.time() - count = self.last_change[1] - if now - self.last_change[0] < QUICK_CHANGE_INTERVAL: + count = self._last_change[1] + if now - self._last_change[0] < QUICK_CHANGE_INTERVAL: count += 1 if count > MAX_QUICK_CHANGE_COUNT: - _ba.disconnect_client( - self._player.get_input_device().client_id) - elif now - self.last_change[0] > QUICK_CHANGE_RESET_INTERVAL: + _ba.disconnect_client(self._player.inputdevice.client_id) + elif now - self._last_change[0] > QUICK_CHANGE_RESET_INTERVAL: count = 0 - self.last_change = (now, count) + self._last_change = (now, count) def handlemessage(self, msg: Any) -> Any: """Standard generic message handler.""" @@ -686,13 +636,11 @@ class Chooser: # If we've been removed from the lobby, ignore this stuff. if self._dead: - from ba import _error - _error.print_error('chooser got ChangeMessage after dying') + print_error('chooser got ChangeMessage after dying') return if not self._text_node: - from ba import _error - _error.print_error('got ChangeMessage after nodes died') + print_error('got ChangeMessage after nodes died') return if msg.what == 'team': @@ -718,13 +666,13 @@ class Chooser: _ba.playsound(self._deek_sound) self._profileindex = ((self._profileindex + msg.value) % len(self._profilenames)) - self.update_from_player_profiles() + self.update_from_profile() elif msg.what == 'character': _ba.playsound(self._click_sound) # update our index in our local list of characters - self.character_index = ((self.character_index + msg.value) % - len(self.character_names)) + self._character_index = ((self._character_index + msg.value) % + len(self._character_names)) self._update_text() self._update_icon() @@ -732,8 +680,6 @@ class Chooser: self._handle_ready_msg(bool(msg.value)) def _update_text(self) -> None: - from ba import _gameutils - from ba._lang import Lstr assert self._text_node is not None if self._ready: @@ -751,7 +697,7 @@ class Chooser: # Flash as we're coming in. fin_color = _ba.safecolor(self.get_color()) + (1, ) if not self._inited: - _gameutils.animate_array(self._text_node, 'color', 4, { + animate_array(self._text_node, 'color', 4, { 0.15: fin_color, 0.25: (2, 2, 2, 1), 0.35: fin_color @@ -760,7 +706,7 @@ class Chooser: # Blend if we're in teams mode; switch instantly otherwise. if can_switch_teams: - _gameutils.animate_array(self._text_node, 'color', 4, { + animate_array(self._text_node, 'color', 4, { 0: self._text_node.color, 0.1: fin_color }) @@ -772,8 +718,6 @@ class Chooser: def get_color(self) -> Sequence[float]: """Return the currently selected color.""" val: Sequence[float] - # if self._profilenames[self._profileindex] == '_edit': - # val = (0, 1, 0) if self.lobby.use_team_colors: val = self.lobby.teams[self._selected_team_index].color else: @@ -819,7 +763,6 @@ class Chooser: return self._player def _update_icon(self) -> None: - from ba import _gameutils if self._profilenames[self._profileindex] == '_edit': tex = _ba.gettexture('black') tint_tex = _ba.gettexture('black') @@ -830,13 +773,12 @@ class Chooser: return try: - tex_name = (_ba.app.spaz_appearances[self.character_names[ - self.character_index]].icon_texture) - tint_tex_name = (_ba.app.spaz_appearances[self.character_names[ - self.character_index]].icon_mask_texture) + tex_name = (_ba.app.spaz_appearances[self._character_names[ + self._character_index]].icon_texture) + tint_tex_name = (_ba.app.spaz_appearances[self._character_names[ + self._character_index]].icon_mask_texture) except Exception: - from ba import _error - _error.print_exception('Error updating char icon list') + print_exception('Error updating char icon list') tex_name = 'neoSpazIcon' tint_tex_name = 'neoSpazIconColorMask' @@ -853,7 +795,7 @@ class Chooser: # If we're initing, flash. if not self._inited: - _gameutils.animate_array(self.icon, 'color', 3, { + animate_array(self.icon, 'color', 3, { 0.15: (1, 1, 1), 0.25: (2, 2, 2), 0.35: (1, 1, 1) @@ -861,7 +803,7 @@ class Chooser: # Blend in teams mode; switch instantly in ffa-mode. if can_switch_teams: - _gameutils.animate_array(self.icon, 'tint_color', 3, { + animate_array(self.icon, 'tint_color', 3, { 0: self.icon.tint_color, 0.1: clr }) @@ -963,10 +905,9 @@ class Lobby: for chooser in self.choosers: try: chooser.reload_profiles() - chooser.update_from_player_profiles() + chooser.update_from_profile() except Exception: - from ba import _error - _error.print_exception('error reloading profiles') + print_exception('Error reloading profiles.') def update_positions(self) -> None: """Update positions for all choosers.""" @@ -1005,11 +946,9 @@ class Lobby: self.choosers.remove(chooser) break if not found: - from ba import _error - _error.print_error(f'remove_chooser did not find player {player}') + print_error(f'remove_chooser did not find player {player}') elif chooser in self.choosers: - from ba import _error - _error.print_error(f'chooser remains after removal for {player}') + print_error(f'chooser remains after removal for {player}') self.update_positions() def remove_all_choosers(self) -> None: diff --git a/assets/src/ba_data/python/ba/_powerup.py b/assets/src/ba_data/python/ba/_powerup.py index 0e3d2d83..950cc9ce 100644 --- a/assets/src/ba_data/python/ba/_powerup.py +++ b/assets/src/ba_data/python/ba/_powerup.py @@ -44,14 +44,14 @@ class PowerupMessage: The type of powerup to be granted (a string). See ba.Powerup.poweruptype for available type values. - source_node + sourcenode The node the powerup game from, or None otherwise. If a powerup is accepted, a ba.PowerupAcceptMessage should be sent - back to the source_node to inform it of the fact. This will generally + back to the sourcenode to inform it of the fact. This will generally cause the powerup box to make a sound and disappear or whatnot. """ poweruptype: str - source_node: Optional[ba.Node] = None + sourcenode: Optional[ba.Node] = None @dataclass diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index e46d7a10..cf9fb06a 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -224,12 +224,12 @@ class Session: # Print a rejection message *only* to the client trying to # join (prevents spamming everyone else in the game). _ba.playsound(_ba.getsound('error')) - _ba.screenmessage( - Lstr(resource='playerLimitReachedText', - subs=[('${COUNT}', str(self.max_players))]), - color=(0.8, 0.0, 0.0), - clients=[player.get_input_device().client_id], - transient=True) + _ba.screenmessage(Lstr(resource='playerLimitReachedText', + subs=[('${COUNT}', + str(self.max_players))]), + color=(0.8, 0.0, 0.0), + clients=[player.inputdevice.client_id], + transient=True) return False _ba.playsound(_ba.getsound('dripity')) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 068dd7c9..cb2e9025 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -601,7 +601,7 @@ class Blast(ba.Actor): self.node.delete() elif isinstance(msg, ExplodeHitMessage): - node = ba.getcollision().opposing_node + node = ba.getcollision().opposingnode assert self.node nodepos = self.node.position mag = 2000.0 @@ -843,7 +843,7 @@ class Bomb(ba.Actor): self.handlemessage(ba.DieMessage()) def _handle_impact(self) -> None: - node = ba.getcollision().opposing_node + node = ba.getcollision().opposingnode # If we're an impact bomb and we came from this node, don't explode... # alternately if we're hitting another impact-bomb from the same @@ -875,7 +875,7 @@ class Bomb(ba.Actor): lambda: _safesetattr(self.node, 'stick_to_owner', True)) def _handle_splat(self) -> None: - node = ba.getcollision().opposing_node + node = ba.getcollision().opposingnode if (node is not self.owner and ba.time() - self._last_sticky_sound_time > 1.0): self._last_sticky_sound_time = ba.time() diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py index 3b54729d..a149ba75 100644 --- a/assets/src/ba_data/python/bastd/actor/controlsguide.py +++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py @@ -264,16 +264,14 @@ class ControlsGuide(ba.Actor): # If we have a touchscreen, we only fade in if we have a player with # an input device that is *not* the touchscreen. - touchscreen: Optional[ba.InputDevice] = _ba.get_input_device( + touchscreen: Optional[ba.InputDevice] = _ba.getinputdevice( 'TouchScreen', '#1', doraise=False) if touchscreen is not None: # We look at the session's players; not the activity's. # We want to get ones who are still in the process of # selecting a character, etc. - input_devices = [ - p.get_input_device() for p in ba.getsession().players - ] + input_devices = [p.inputdevice for p in ba.getsession().players] input_devices = [ i for i in input_devices if i and i is not touchscreen ] @@ -325,13 +323,13 @@ class ControlsGuide(ba.Actor): # We look at the session's players; not the activity's - we want to # get ones who are still in the process of selecting a character, etc. - input_devices = [p.get_input_device() for p in ba.getsession().players] + input_devices = [p.inputdevice for p in ba.getsession().players] input_devices = [i for i in input_devices if i] # If there's no players with input devices yet, try to default to # showing keyboard controls. if not input_devices: - kbd = _ba.get_input_device('Keyboard', '#1', doraise=False) + kbd = _ba.getinputdevice('Keyboard', '#1', doraise=False) if kbd is not None: input_devices.append(kbd) diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py index 2bbe156b..77dc6ab9 100644 --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py @@ -305,9 +305,9 @@ class PowerupBox(ba.Actor): elif isinstance(msg, _TouchedMessage): if not self._powersgiven: - node = ba.getcollision().opposing_node + node = ba.getcollision().opposingnode node.handlemessage( - ba.PowerupMessage(self.poweruptype, source_node=self.node)) + ba.PowerupMessage(self.poweruptype, sourcenode=self.node)) elif isinstance(msg, ba.DieMessage): if self.node: diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index ba314e21..cf710b07 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -851,8 +851,8 @@ class Spaz(ba.Actor): self._num_times_hit = 0 self.node.handlemessage('flash') - if msg.source_node: - msg.source_node.handlemessage(ba.PowerupAcceptMessage()) + if msg.sourcenode: + msg.sourcenode.handlemessage(ba.PowerupAcceptMessage()) return True elif isinstance(msg, ba.FreezeMessage): @@ -1143,7 +1143,7 @@ class Spaz(ba.Actor): elif isinstance(msg, PunchHitMessage): if not self.node: return None - node = ba.getcollision().opposing_node + node = ba.getcollision().opposingnode # Only allow one hit per node per punch. if node and (node not in self._punched_nodes): @@ -1204,23 +1204,23 @@ class Spaz(ba.Actor): try: collision = ba.getcollision() - opposing_node = collision.opposing_node - opposing_body = collision.opposing_body + opposingnode = collision.opposingnode + opposingbody = collision.opposingbody except ba.NotFoundError: return True # Don't allow picking up of invincible dudes. try: - if opposing_node.invincible: + if opposingnode.invincible: return True except Exception: pass # If we're grabbing the pelvis of a non-shattered spaz, we wanna # grab the torso instead. - if (opposing_node.getnodetype() == 'spaz' - and not opposing_node.shattered and opposing_body == 4): - opposing_body = 1 + if (opposingnode.getnodetype() == 'spaz' + and not opposingnode.shattered and opposingbody == 4): + opposingbody = 1 # Special case - if we're holding a flag, don't replace it # (hmm - should make this customizable or more low level). @@ -1229,8 +1229,8 @@ class Spaz(ba.Actor): return True # Note: hold_body needs to be set before hold_node. - self.node.hold_body = opposing_body - self.node.hold_node = opposing_node + self.node.hold_body = opposingbody + self.node.hold_node = opposingnode elif isinstance(msg, ba.CelebrateMessage): if self.node: self.node.handlemessage('celebrate', int(msg.duration * 1000)) diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 7f2d814d..0020bb0c 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -179,7 +179,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): ba.timer(length, light.delete) def _handle_base_collide(self, team: Team) -> None: - player = ba.getcollision().opposing_node.getdelegate( + player = ba.getcollision().opposingnode.getdelegate( PlayerSpaz, True).getplayer(Player) if not player or not player.is_alive(): return diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 55d59a8e..43ff82e4 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -158,9 +158,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self._scoreboard = Scoreboard() self._alarmsound = ba.getsound('alarm') self._ticking_sound = ba.getsound('ticking') - self._last_score_time = 0 self._score_sound = ba.getsound('score') self._swipsound = ba.getsound('swip') + self._last_score_time = 0 self._all_bases_material = ba.Material() self._last_home_flag_notice_print_time = 0.0 self._score_to_win = int(settings['Score to Win']) @@ -237,20 +237,22 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): )) # Other parts of our spazzes don't collide with our flags at all. - spaz_mat_no_flag_collide.add_actions(conditions=('they_have_material', - flagmat), - actions=('modify_part_collision', - 'collide', False)) + spaz_mat_no_flag_collide.add_actions( + conditions=('they_have_material', flagmat), + actions=('modify_part_collision', 'collide', False), + ) # We wanna know when *any* flag enters/leaves our base. base_region_mat.add_actions( conditions=('they_have_material', FlagFactory.get().flagmaterial), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('call', 'at_connect', - lambda: self._handle_flag_entered_base(team)), - ('call', 'at_disconnect', - lambda: self._handle_flag_left_base(team)))) + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + lambda: self._handle_flag_entered_base(team)), + ('call', 'at_disconnect', + lambda: self._handle_flag_left_base(team)), + )) return team @@ -274,7 +276,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._swipsound, position=team.flag.node.position) def _handle_flag_entered_base(self, team: Team) -> None: - flag = CTFFlag.from_node(ba.getcollision().opposing_node) + flag = CTFFlag.from_node(ba.getcollision().opposingnode) if not flag: print('Unable to get flag in _handle_flag_entered_base') return @@ -362,7 +364,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self._flash_base(team) self._update_scoreboard() - # Have teammates celebrate + # Have teammates celebrate. for player in team.players: if player.actor: player.actor.handlemessage(ba.CelebrateMessage(2.0)) @@ -385,7 +387,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def _handle_flag_left_base(self, team: Team) -> None: cur_time = ba.time() try: - flag = CTFFlag.from_node(ba.getcollision().opposing_node) + flag = CTFFlag.from_node(ba.getcollision().opposingnode) except ba.NodeNotFoundError: # We still get this call even if the flag stopped touching us # because it was deleted; that's ok. @@ -447,11 +449,12 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): return None if delegate is None else delegate.getplayer(Player) def _handle_hit_own_flag(self, team: Team, val: int) -> None: + """Called when a player touches their own team flag. + + We keep track of when each player is touching their + own flag so we can award points when returned. """ - keep track of when each player is touching their - own flag so we can award points when returned - """ - player = self._player_from_node(ba.getcollision().source_node) + player = self._player_from_node(ba.getcollision().sourcenode) if player: player.touching_own_flag += (1 if val else -1) @@ -464,7 +467,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # Use a node message to kill the flag instead of just killing # our team's. (avoids redundantly killing new flags if # multiple body parts generate callbacks in one step). - node = ba.getcollision().opposing_node + node = ba.getcollision().opposingnode self._award_players_touching_own_flag(team) node.handlemessage(ba.DieMessage()) @@ -484,8 +487,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): team.touch_return_timer = None team.touch_return_timer_ticking = None if team.flag_return_touches < 0: - ba.print_error( - "CTF: flag_return_touches < 0; this shouldn't happen.") + ba.print_error('CTF flag_return_touches < 0') def _flash_base(self, team: Team, length: float = 2.0) -> None: light = ba.newnode('light', @@ -536,13 +538,15 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self._score_to_win) def handlemessage(self, msg: Any) -> Any: + if isinstance(msg, ba.PlayerDiedMessage): - # Augment standard behavior. - super().handlemessage(msg) + super().handlemessage(msg) # Augment standard behavior. self.respawn_player(msg.getplayer(Player)) + elif isinstance(msg, FlagDiedMessage): assert isinstance(msg.flag, CTFFlag) ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) + elif isinstance(msg, FlagPickedUpMessage): # Store the last player to hold the flag for scoring purposes. assert isinstance(msg.flag, CTFFlag) @@ -550,9 +554,11 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): PlayerSpaz, True).getplayer(Player) msg.flag.held_count += 1 msg.flag.reset_return_times() + elif isinstance(msg, FlagDroppedMessage): # Store the last player to hold the flag for scoring purposes. assert isinstance(msg.flag, CTFFlag) msg.flag.held_count -= 1 + else: super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 63cb7401..3100dd5c 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -177,7 +177,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): # If we have a chosen one, ignore these. if self._get_chosen_one_player() is not None: return - player = ba.getcollision().opposing_node.getdelegate( + player = ba.getcollision().opposingnode.getdelegate( PlayerSpaz, True).getplayer(Player) if player is not None and player.is_alive(): self._set_chosen_one_player(player) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index a9511482..0f1e51e9 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -235,9 +235,9 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): def _handle_flag_player_collide(self) -> None: collision = ba.getcollision() - flag = collision.source_node.getdelegate(ConquestFlag) - player = collision.opposing_node.getdelegate(PlayerSpaz, - True).getplayer(Player) + flag = collision.sourcenode.getdelegate(ConquestFlag) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer(Player) if not flag or not player: return assert flag.light diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index a03b40ce..ae0c0f48 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -137,9 +137,9 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): if self.has_ended(): return collision = ba.getcollision() - egg = collision.source_node.getdelegate(Egg) - player = collision.opposing_node.getdelegate(PlayerSpaz, - True).getplayer(Player) + egg = collision.sourcenode.getdelegate(Egg) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer(Player) if player and egg: player.team.score += 1 diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index a9b472e0..c428a64d 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -209,7 +209,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): assert self._flag is not None if self._flag.scored: return - region = ba.getcollision().source_node + region = ba.getcollision().sourcenode i = None for i in range(len(self._score_regions)): if region == self._score_regions[i].node: @@ -654,7 +654,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): return # See which score region it was. - region = ba.getcollision().source_node + region = ba.getcollision().sourcenode i = None for i in range(len(self._score_regions)): if region == self._score_regions[i].node: diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 805480ef..26af046c 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -245,9 +245,9 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): def _handle_puck_player_collide(self) -> None: collision = ba.getcollision() - puck = collision.source_node.getdelegate(Puck) - player = collision.opposing_node.getdelegate(PlayerSpaz, - True).getplayer(Player) + puck = collision.sourcenode.getdelegate(Puck) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer(Player) if player and puck: puck.last_players_to_touch[player.team.id] = player @@ -265,7 +265,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): if self._puck.scored: return - region = ba.getcollision().source_node + region = ba.getcollision().sourcenode index = 0 for index in range(len(self._score_regions)): if region == self._score_regions[index].node: diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index e1a4cef5..4b11464c 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -247,7 +247,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._swipsound) def _handle_player_flag_region_collide(self, colliding: bool) -> None: - player = ba.getcollision().opposing_node.getdelegate( + player = ba.getcollision().opposingnode.getdelegate( PlayerSpaz, True).getplayer(Player) if not player: return diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index ecb6e38f..df6de7bf 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -227,9 +227,9 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): # pylint: disable=too-many-branches # pylint: disable=too-many-nested-blocks collision = ba.getcollision() - region = collision.source_node.getdelegate(RaceRegion) - playerspaz = collision.opposing_node.getdelegate(PlayerSpaz, - doraise=False) + region = collision.sourcenode.getdelegate(RaceRegion) + playerspaz = collision.opposingnode.getdelegate(PlayerSpaz, + doraise=False) player = playerspaz.getplayer(Player) if playerspaz else None if not player or not region: return diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index fbcce6e7..d5d0637c 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -406,7 +406,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): ba.timer(2.0, self._start_updating_waves) def _handle_reached_end(self) -> None: - spaz = ba.getcollision().opposing_node.getdelegate(SpazBot, True) + spaz = ba.getcollision().opposingnode.getdelegate(SpazBot, True) if not spaz.is_alive(): return # Ignore bodies flying in. diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index 00e81723..9805557e 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -91,7 +91,7 @@ class ControlsSettingsWindow(ba.Window): height += space_height show_keyboard = False - if _ba.get_input_device('Keyboard', '#1', doraise=False) is not None: + if _ba.getinputdevice('Keyboard', '#1', doraise=False) is not None: show_keyboard = True height += spacing * 2 show_keyboard_p2 = False if app.vr_mode else show_keyboard @@ -393,7 +393,7 @@ class ControlsSettingsWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') ba.app.main_menu_window = (keyboard.ConfigKeyboardWindow( - _ba.get_input_device('Keyboard', '#1')).get_root_widget()) + _ba.getinputdevice('Keyboard', '#1')).get_root_widget()) def _config_keyboard2(self) -> None: # pylint: disable=cyclic-import @@ -401,7 +401,7 @@ class ControlsSettingsWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') ba.app.main_menu_window = (keyboard.ConfigKeyboardWindow( - _ba.get_input_device('Keyboard', '#2')).get_root_widget()) + _ba.getinputdevice('Keyboard', '#2')).get_root_widget()) def _do_mobile_devices(self) -> None: # pylint: disable=cyclic-import diff --git a/docs/ba_module.md b/docs/ba_module.md index 281527df..c7da0733 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-25 for Ballistica version 1.5.0 build 20027

    +

    last updated on 2020-05-25 for Ballistica version 1.5.0 build 20028

    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!


    @@ -189,6 +189,7 @@
    +

    ba.DelegateNotFoundError

    +

    Inherits from: ba.NotFoundError, Exception, BaseException

    +

    Exception raised when an expected delegate object does not exist.

    + +

    Category: Exception Classes +

    + +

    Methods:

    +

    <all methods inherited from ba.NotFoundError>

    +

    ba.Dependency

    Inherits from: typing.Generic

    A dependency on a DependencyComponent (with an optional config).

    @@ -3569,8 +3580,8 @@ loc.connectattr('position', light, 'position')

    delete()

    delete(ignore_missing: bool = True) -> None

    -

    Delete the node. Ignores already-deleted nodes unless ignore_missing -is False, in which case an Exception is thrown.

    +

    Delete the node. Ignores already-deleted nodes if ignore_missing +is True; otherwise a ba.NodeNotFoundError is thrown.

    exists()

    @@ -3598,7 +3609,7 @@ the right thing both for Node objects and values of None.

    If the node has no delegate or it is not an instance of the passed type, then None will be returned. If 'doraise' is True, then an -Exception will be raised instead in such cases.

    +ba.DelegateNotFoundError will be raised instead.

    getnodetype()

    @@ -4094,7 +4105,7 @@ the type-checker properly identifies the returned value as one.

    This message is normally received by touching a ba.PowerupBox.

    Attributes:

    -
    poweruptype, source_node
    +
    poweruptype, sourcenode

    poweruptype

    str

    @@ -4102,11 +4113,11 @@ the type-checker properly identifies the returned value as one.

    See ba.Powerup.poweruptype for available type values.

    -

    source_node

    +

    sourcenode

    Optional[ba.Node]

    The node the powerup game from, or None otherwise. If a powerup is accepted, a ba.PowerupAcceptMessage should be sent -back to the source_node to inform it of the fact. This will generally +back to the sourcenode to inform it of the fact. This will generally cause the powerup box to make a sound and disappear or whatnot.

    @@ -4114,7 +4125,7 @@ cause the powerup box to make a sound and disappear or whatnot.

    Methods:

    <constructor>

    -

    ba.PowerupMessage(poweruptype: str, source_node: Optional[ba.Node] = None)

    +

    ba.PowerupMessage(poweruptype: str, sourcenode: Optional[ba.Node] = None)

    @@ -4443,7 +4454,7 @@ that a SessionPlayer is still present if retaining references to one for any length of time.

    Attributes:

    -
    character, color, gamedata, gameplayer, highlight, id, in_game, sessiondata, team
    +
    character, color, gamedata, gameplayer, highlight, id, in_game, inputdevice, sessiondata, team

    character

    str

    @@ -4490,6 +4501,11 @@ the right thing both for Player objects and values of None.

    This bool value will be True once the Player has completed any lobby character/team selection.

    +
    +

    inputdevice

    +

    ba.InputDevice

    +

    The input device associated with the player.

    +

    sessiondata

    Dict

    @@ -4507,7 +4523,7 @@ is still in its lobby selecting a team/etc. then a

    Methods:

    -
    assign_input_call(), exists(), get_account_id(), get_icon(), get_input_device(), get_name(), remove_from_game(), reset_input(), set_name()
    +
    assign_input_call(), exists(), get_account_id(), get_icon(), get_name(), remove_from_game(), reset_input(), set_name()

    assign_input_call()

    assign_input_call(type: Union[str, Tuple[str, ...]], @@ -4544,12 +4560,6 @@ joins (while verification occurs).

    Returns the character's icon (images, colors, etc contained in a dict)

    -
    -

    get_input_device()

    -

    get_input_device() -> ba.InputDevice

    - -

    Returns the player's input device.

    -

    get_name()

    get_name(full: bool = False, icon: bool = True) -> str

    From 849bd117953db5072cb87dff7a82383e497d6581 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 25 May 2020 23:01:24 -0700 Subject: [PATCH 047/417] Improved type checking on time functionality --- .efrocachemap | 24 ++++++------ .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 32 ++++++++++++++-- assets/src/ba_data/python/ba/_store.py | 2 +- .../python/bastd/actor/onscreentimer.py | 37 ++++++++++++++----- .../ba_data/python/bastd/game/ninjafight.py | 18 ++++----- docs/ba_module.md | 4 +- 7 files changed, 80 insertions(+), 38 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 26963766..9e595257 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/97/fd0e5553917019236912a7010d38", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/43/32/c48a4da7fcc8c17132077da852d7", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/75/13/2bc3ae9026386d1b515ede107e17", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/9a/b112f788f528ec9e3627622698ac", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/87/fdb3e925f3be1cc353db94d61c5a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/ba/125457c69bc2940850ab84c4cc6a", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/d4/5efcef1f85b2bfea7bbb81800580", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/66/75a3a0f27d07131473e804a5b937", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/51/6c/911ba80ba913e6dac1cafa5c8a74", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/cc/cf896173a8d5731ada2aace59146", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a2/12/aa1f0ca5506f0b57f93ca9adf7be", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e1/5f/f372d0ba9591b99284b9b50d7cdf" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/35/3b6bc5c5609b1dd37bd65c39df45", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/bc/c2c7231dc6bf085eda15d6198554", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/fd/020ed9bb0e8c8a18b2d793fee8bd", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/0b/78c8bacb215abaf50dcb3284eef7", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/e1/e0dc64b5c00661cce19530c0e836", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e6/74/73a514993d626a6bc75717d185ef", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/7d/dbd2624759a1fdce2a20d53cab1a", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/01/4833ec215cc6c53f7e4ebf850608", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b1/57/b72500d2a568df5afa36556f89dd", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/48/ea/c83f97f44703b16eeec794d29da6", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a3/16/284b9953c7ef4a841ff907079cbd", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/12/43/d0513cf8f8dac0712cbf42d4b94b" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 1cf96c30..16a51b7c 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1114,6 +1114,7 @@ mhsh microprotocols mikirog + millisecs mimetypes mimportedby mindepth diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index f1f90179..3e0e0d1f 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=318889180473540875493180206824864665481 +# SOURCES_HASH=223083205204988067566025188831386474803 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -3729,11 +3729,35 @@ def textwidget(edit: Widget = None, return Widget() +# Overloads to return a type based on requested format. + + +@overload +def time( + timetype: ba.TimeType = TimeType.SIM, + timeformat: Literal[TimeFormat.SECONDS] = TimeFormat.SECONDS) -> float: + ... + + +# This "*" keyword-only hack lets us accept 1 arg (timeformat=MILLISECS) forms. +@overload def time(timetype: ba.TimeType = TimeType.SIM, - timeformat: ba.TimeFormat = TimeFormat.SECONDS) -> Union[float, int]: + *, + timeformat: Literal[TimeFormat.MILLISECONDS]) -> int: + ... + + +@overload +def time(timetype: ba.TimeType, + timeformat: Literal[TimeFormat.MILLISECONDS]) -> int: + ... + + +def time(timetype: ba.TimeType = TimeType.SIM, + timeformat: ba.TimeFormat = TimeFormat.SECONDS) -> Any: """time(timetype: ba.TimeType = TimeType.SIM, timeformat: ba.TimeFormat = TimeFormat.SECONDS) - -> Union[float, int] + -> Return the current time. @@ -3766,7 +3790,7 @@ def time(timetype: ba.TimeType = TimeType.SIM, Note: If you need pure unfiltered clock time, just use the standard Python functions such as time.time(). """ - return 0.0 + return None def time_format_check(time_format: ba.TimeFormat, length: Union[float, diff --git a/assets/src/ba_data/python/ba/_store.py b/assets/src/ba_data/python/ba/_store.py index 09e27e01..c68aa6f8 100644 --- a/assets/src/ba_data/python/ba/_store.py +++ b/assets/src/ba_data/python/ba/_store.py @@ -494,7 +494,7 @@ def get_available_sale_time(tab: str) -> Optional[int]: assert app.pro_sale_start_val is not None val: Optional[int] = max( 0, app.pro_sale_start_val - - (int(_ba.time(TimeType.REAL, TimeFormat.MILLISECONDS)) - + (_ba.time(TimeType.REAL, TimeFormat.MILLISECONDS) - app.pro_sale_start_time)) # Keep the value in the config up to date. I suppose we should diff --git a/assets/src/ba_data/python/bastd/actor/onscreentimer.py b/assets/src/ba_data/python/bastd/actor/onscreentimer.py index 422a630c..8b5699b6 100644 --- a/assets/src/ba_data/python/bastd/actor/onscreentimer.py +++ b/assets/src/ba_data/python/bastd/actor/onscreentimer.py @@ -21,12 +21,13 @@ """Defines Actor(s).""" from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, overload import ba if TYPE_CHECKING: from typing import Optional, Union, Any + from typing_extensions import Literal class OnScreenTimer(ba.Actor): @@ -39,7 +40,7 @@ class OnScreenTimer(ba.Actor): def __init__(self) -> None: super().__init__() - self._starttime: Optional[int] = None + self._starttime_ms: Optional[int] = None self.node = ba.newnode('text', attrs={ 'v_attach': 'top', @@ -63,13 +64,13 @@ class OnScreenTimer(ba.Actor): """Start the timer.""" tval = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) assert isinstance(tval, int) - self._starttime = tval - self.inputnode.time1 = self._starttime + self._starttime_ms = tval + self.inputnode.time1 = self._starttime_ms ba.sharedobj('globals').connectattr('time', self.inputnode, 'time2') def has_started(self) -> bool: """Return whether this timer has started yet.""" - return self._starttime is not None + return self._starttime_ms is not None def stop(self, endtime: Union[int, float] = None, @@ -85,7 +86,7 @@ class OnScreenTimer(ba.Actor): endtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) timeformat = ba.TimeFormat.MILLISECONDS - if self._starttime is None: + if self._starttime_ms is None: print('Warning: OnScreenTimer.stop() called without start() first') else: endtime_ms: int @@ -97,7 +98,20 @@ class OnScreenTimer(ba.Actor): else: raise ValueError(f'invalid timeformat: {timeformat}') - self.inputnode.timemax = endtime_ms - self._starttime + self.inputnode.timemax = endtime_ms - self._starttime_ms + + # Overloads so type checker knows our exact return type based in args. + @overload + def getstarttime( + self, + timeformat: Literal[ba.TimeFormat.SECONDS] = ba.TimeFormat.SECONDS + ) -> float: + ... + + @overload + def getstarttime(self, + timeformat: Literal[ba.TimeFormat.MILLISECONDS]) -> int: + ... def getstarttime( self, @@ -109,11 +123,11 @@ class OnScreenTimer(ba.Actor): milliseconds if it is MILLISECONDS. """ val_ms: Any - if self._starttime is None: + if self._starttime_ms is None: print('WARNING: getstarttime() called on un-started timer') val_ms = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) else: - val_ms = self._starttime + val_ms = self._starttime_ms assert isinstance(val_ms, int) if timeformat is ba.TimeFormat.SECONDS: return 0.001 * val_ms @@ -121,6 +135,11 @@ class OnScreenTimer(ba.Actor): return val_ms raise ValueError(f'invalid timeformat: {timeformat}') + @property + def starttime(self) -> float: + """Shortcut for start time in seconds.""" + return self.getstarttime() + def handlemessage(self, msg: Any) -> Any: # if we're asked to die, just kill our node/timer if isinstance(msg, ba.DieMessage): diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 439aab2a..42e73e51 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -77,6 +77,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self._won = False self._timer: Optional[OnScreenTimer] = None self._bots = SpazBotSet() + self._preset = str(settings['preset']) # Called when our game is transitioning in but not ready to begin; # we can go ahead and start creating stuff, playing music, etc. @@ -87,7 +88,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): # Called when our game actually begins. def on_begin(self) -> None: super().on_begin() - is_pro = self.settings_raw.get('preset') == 'pro' + is_pro = self._preset == 'pro' # In pro mode there's no powerups. if not is_pro: @@ -156,9 +157,11 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): # marked dead yet) ..so lets push a call into the event loop to # check once this guy has finished dying. ba.pushcall(self._check_if_won) + + # Let the base class handle anything we don't. else: - # Let the base class handle anything we don't. - super().handlemessage(msg) + return super().handlemessage(msg) + return None # When this is called, we should fill out results and end the game # *regardless* of whether is has been won. (this may be called due @@ -171,17 +174,12 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): results = ba.TeamGameResults() - # If we won, set our score to the elapsed time + # If we won, set our score to the elapsed time in milliseconds. # (there should just be 1 team here since this is co-op). # ..if we didn't win, leave scores as default (None) which means # we lost. if self._won: - curtime = ba.time(timeformat=ba.TimeFormat.MILLISECONDS) - assert isinstance(curtime, int) - starttime = self._timer.getstarttime( - timeformat=ba.TimeFormat.MILLISECONDS) - assert isinstance(starttime, int) - elapsed_time_ms = curtime - starttime + elapsed_time_ms = int((ba.time() - self._timer.starttime) * 1000.0) ba.cameraflash() ba.playsound(self._winsound) for team in self.teams: diff --git a/docs/ba_module.md b/docs/ba_module.md index c7da0733..d6b1b011 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-25 for Ballistica version 1.5.0 build 20028

    +

    last updated on 2020-05-25 for Ballistica version 1.5.0 build 20029

    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!


    @@ -6382,7 +6382,7 @@ are applied to the Widget.

    ba.time()

    time(timetype: ba.TimeType = TimeType.SIM, timeformat: ba.TimeFormat = TimeFormat.SECONDS) - -> Union[float, int]

    + -> <varies>

    Return the current time.

    From 08ea64bdc52fcbc726e4df72dee015480129c9b2 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 27 May 2020 17:43:41 -0700 Subject: [PATCH 048/417] More modernizing --- .efrocachemap | 24 +++---- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/__init__.py | 3 +- assets/src/ba_data/python/ba/_activity.py | 62 +++++++++++------- assets/src/ba_data/python/ba/_general.py | 63 ++++++++++++++++--- assets/src/ba_data/python/ba/_profile.py | 18 +++--- assets/src/ba_data/python/ba/_session.py | 15 +++++ .../ba_data/python/bastd/actor/respawnicon.py | 29 ++++----- .../ba_data/python/bastd/actor/scoreboard.py | 23 ++++--- .../src/ba_data/python/bastd/actor/spazbot.py | 12 ++-- .../python/bastd/game/easteregghunt.py | 4 +- .../src/ba_data/python/bastd/game/football.py | 2 +- .../src/ba_data/python/bastd/game/hockey.py | 35 ++++++----- .../ba_data/python/bastd/game/onslaught.py | 16 ++--- assets/src/ba_data/python/bastd/game/race.py | 13 ++-- .../ba_data/python/bastd/game/runaround.py | 21 ++++--- .../ba_data/python/bastd/game/thelaststand.py | 6 +- assets/src/ba_data/python/bastd/tutorial.py | 35 ++++++++--- docs/ba_module.md | 21 +++++-- tools/efrotools/filecache.py | 5 +- 20 files changed, 261 insertions(+), 148 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 9e595257..4179fd4f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/35/3b6bc5c5609b1dd37bd65c39df45", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/bc/c2c7231dc6bf085eda15d6198554", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/fd/020ed9bb0e8c8a18b2d793fee8bd", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/0b/78c8bacb215abaf50dcb3284eef7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/e1/e0dc64b5c00661cce19530c0e836", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e6/74/73a514993d626a6bc75717d185ef", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/7d/dbd2624759a1fdce2a20d53cab1a", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/01/4833ec215cc6c53f7e4ebf850608", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b1/57/b72500d2a568df5afa36556f89dd", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/48/ea/c83f97f44703b16eeec794d29da6", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a3/16/284b9953c7ef4a841ff907079cbd", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/12/43/d0513cf8f8dac0712cbf42d4b94b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/db/9c7cfd4e4f4a1f7a7adc980bca42", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/0b/231e38ff29d932df7552050891c5", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/56/bb316ec28ee98ece5c0c3a04b77f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/92/d787c99db6cc85f70b7131ff2c0c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/97/b9/9c6c3c90f10d319250a9f3d287b3", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/2a/60bdf1c4d4e13bdbb5f4df121e3e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/66/25/79ea606983dc91ac0cd79c1e7da6", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/70/c6/0ab2cdf222ffcadade37dd3b8462", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/65/450a67dab189c0832b6bf28a9e9c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/a9/e1ab6defb8bcf536dff46d0c62b2", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/fc/d00336dae2b1c7323b31518b52aa", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ed/98/dbea1af1da83bfa1a3283175b234" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 3e0e0d1f..9df9b873 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=223083205204988067566025188831386474803 +# SOURCES_HASH=265401783818737452594582363319036908124 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 9e808242..12225c01 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -73,7 +73,8 @@ from ba._apputils import is_browser_likely_available from ba._campaign import Campaign from ba._gameutils import (animate, animate_array, show_damage_count, sharedobj, timestring, cameraflash) -from ba._general import WeakCall, Call, existing, Existable +from ba._general import (WeakCall, Call, existing, Existable, + verify_object_death) from ba._level import Level from ba._lobby import Lobby, Chooser from ba._math import normalized_color, is_point_in_box, vec3validate diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index c372069d..241d1d70 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -28,6 +28,7 @@ from ba._team import Team from ba._player import Player from ba._error import print_exception, print_error, SessionTeamNotFoundError from ba._dependency import DependencyComponent +from ba._general import Call, verify_object_death import _ba if TYPE_CHECKING: @@ -217,7 +218,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._stats: Optional[ba.Stats] = None def __del__(self) -> None: - from ba._apputils import garbage_collect, call_after_ad # If the activity has been run then we should have already cleaned # it up, but we still need to run expire calls for un-run activities. @@ -225,20 +225,13 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): with _ba.Context('empty'): self._expire() - # Since we're mostly between activities at this point, lets run a cycle - # of garbage collection; hopefully it won't cause hitches here. - garbage_collect(session_end=False) - - # Now that our object is officially gonna be dead, tell the session it - # can fire up the next activity. + # Inform our owner that we're officially kicking the bucket. if self._transitioning_out: session = self._session() if session is not None: - with _ba.Context(session): - if self.can_show_ad_on_death: - call_after_ad(session.begin_next_activity) - else: - _ba.pushcall(session.begin_next_activity) + _ba.pushcall( + Call(session.transitioning_out_activity_was_freed, + self.can_show_ad_on_death)) @property def stats(self) -> ba.Stats: @@ -304,7 +297,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): (internal) """ - from ba._general import Call from ba._enums import TimeType # Create a real-timer that watches a weak-ref of this activity @@ -628,6 +620,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self.players.remove(player) assert player not in self.players + # This should allow our ba.Player instance to die. + # Complain if that doesn't happen. + # verify_object_death(player) + with _ba.Context(self): # Make a decent attempt to persevere if user code breaks. try: @@ -670,6 +666,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self.teams.remove(team) assert team not in self.teams + # This should allow our ba.Team instance to die. Complain + # if that doesn't happen. + # verify_object_death(team) + with _ba.Context(self): # Make a decent attempt to persevere if user code breaks. try: @@ -680,6 +680,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): sessionteam.reset_gamedata() except Exception: print_exception(f'Error in reset_gamedata for {self}') + sessionteam.gameteam = None def _sanity_check_begin_call(self) -> None: @@ -777,32 +778,45 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): for actor_ref in self._actor_weak_refs: actor = actor_ref() if actor is not None: + verify_object_death(actor) try: actor.on_expire() except Exception: - print_exception(f'Error expiring Actor {actor_ref()}') + print_exception(f'Error in Actor.on_expire()' + f' for {actor_ref()}') # Reset all Players. # (releases any attached actors, clears game-data, etc) for player in self.players: - if player: - try: - sessionplayer = player.sessionplayer - player.reset() - sessionplayer.set_node(None) - sessionplayer.set_activity(None) - sessionplayer.gameplayer = None - sessionplayer.reset() - except Exception: - print_exception(f'Error resetting Player {player}') + try: + # This should allow our ba.Player instance to die. + # Complain if that doesn't happen. + # verify_object_death(player) + sessionplayer = player.sessionplayer + player.reset() + sessionplayer.set_node(None) + sessionplayer.set_activity(None) + + sessionplayer.gameplayer = None + sessionplayer.reset() + except Exception: + print_exception(f'Error resetting Player {player}') # Ditto with Teams. for team in self.teams: try: sessionteam = team.sessionteam + + # This should allow our ba.Team instance to die. + # Complain if that doesn't happen. + # verify_object_death(sessionteam.gameteam) sessionteam.gameteam = None sessionteam.reset_gamedata() except SessionTeamNotFoundError: + # It is expected that Team objects may last longer than + # the SessionTeam they came from (game objects may hold + # team references past the point at which the underlying + # player/team leaves) pass except Exception: print_exception(f'Error resetting Team {team}') diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 46f6be9b..5ff0acd2 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -21,16 +21,22 @@ """Utility snippets applying to generic Python code.""" from __future__ import annotations +import gc import types import weakref +import random from typing import TYPE_CHECKING, TypeVar from typing_extensions import Protocol +from efro.terminal import Clr +from ba._error import print_error, print_exception +from ba._enums import TimeType import _ba if TYPE_CHECKING: from typing import Any, Type, Optional from efro.call import Call as Call # 'as Call' so we re-export. + from weakref import ReferenceType class Existable(Protocol): @@ -100,22 +106,18 @@ def json_prep(data: Any) -> Any: if isinstance(data, list): return [json_prep(element) for element in data] if isinstance(data, tuple): - from ba import _error - _error.print_error('json_prep encountered tuple', once=True) + print_error('json_prep encountered tuple', once=True) return [json_prep(element) for element in data] if isinstance(data, bytes): try: return data.decode(errors='ignore') except Exception: from ba import _error - _error.print_error('json_prep encountered utf-8 decode error', - once=True) + print_error('json_prep encountered utf-8 decode error', once=True) return data.decode(errors='ignore') if not isinstance(data, (str, float, bool, type(None), int)): - from ba import _error - _error.print_error('got unsupported type in json_prep:' + - str(type(data)), - once=True) + print_error('got unsupported type in json_prep:' + str(type(data)), + once=True) return data @@ -135,7 +137,6 @@ def utf8_all(data: Any) -> Any: def print_refs(obj: Any) -> None: """Print a list of known live references to an object.""" - import gc # Hmmm; I just noticed that calling this on an object # seems to keep it alive. Should figure out why. @@ -291,3 +292,47 @@ class WeakMethod: def __str__(self) -> str: return '' + + +def verify_object_death(obj: object) -> None: + """Warn if an object does not get freed within a short period. + + Category: General Utility Functions + + This can be handy to detect and prevent memory/resource leaks. + """ + try: + ref = weakref.ref(obj) + except Exception: + print_exception('Unable to create weak-ref in verify_object_death') + + # Use a slight range for our checks so they don't all land at once + # if we queue a lot of them. + delay = random.uniform(2.0, 5.5) + with _ba.Context('ui'): + _ba.timer(delay, + lambda: _verify_object_death(ref), + timetype=TimeType.REAL) + + +def _verify_object_death(wref: ReferenceType) -> None: + obj = wref() + if obj is None: + return + + try: + name = type(obj).__name__ + except Exception: + print(f'Note: unable to get type name for {obj}') + name = 'object' + + print(f'{Clr.RED}Error: {name} not dying' + f' when expected to: {Clr.BLD}{obj}{Clr.RST}') + refs = list(gc.get_referrers(obj)) + print(f'{Clr.YLW}Active References:{Clr.RST}') + i = 1 + for ref in refs: + # if isinstance(ref, types.FrameType): + # continue + print(f'{Clr.YLW} reference {i}:{Clr.BLU} {ref}{Clr.RST}') + i += 1 diff --git a/assets/src/ba_data/python/ba/_profile.py b/assets/src/ba_data/python/ba/_profile.py index e29384c6..86fa1c56 100644 --- a/assets/src/ba_data/python/ba/_profile.py +++ b/assets/src/ba_data/python/ba/_profile.py @@ -35,7 +35,7 @@ PLAYER_COLORS = [(1, 0.15, 0.15), (0.2, 1, 0.2), (0.1, 0.1, 1), (0.2, 1, 1), (0.5, 0.25, 1.0), (1, 1, 0), (1, 0.5, 0), (1, 0.3, 0.5), (0.1, 0.1, 0.5), (0.4, 0.2, 0.1), (0.1, 0.35, 0.1), (1, 0.8, 0.5), (0.4, 0.05, 0.05), (0.13, 0.13, 0.13), - (0.5, 0.5, 0.5), (1, 1, 1)] # yapf: disable + (0.5, 0.5, 0.5), (1, 1, 1)] def get_player_colors() -> List[Tuple[float, float, float]]: @@ -75,8 +75,8 @@ def get_player_profile_colors( if profiles is None: profiles = bs_config['Player Profiles'] - # special case - when being asked for a random color in kiosk mode, - # always return default purple + # Special case: when being asked for a random color in kiosk mode, + # always return default purple. if _ba.app.kiosk_mode and profilename is None: color = (0.5, 0.4, 1.0) highlight = (0.4, 0.4, 0.5) @@ -85,22 +85,22 @@ def get_player_profile_colors( assert profilename is not None color = profiles[profilename]['color'] except (KeyError, AssertionError): - # key off name if possible + # Key off name if possible. if profilename is None: - # first 6 are bright-ish + # First 6 are bright-ish. color = PLAYER_COLORS[random.randrange(6)] else: - # first 6 are bright-ish + # First 6 are bright-ish. color = PLAYER_COLORS[sum([ord(c) for c in profilename]) % 6] try: assert profilename is not None highlight = profiles[profilename]['highlight'] except (KeyError, AssertionError): - # key off name if possible + # Key off name if possible. if profilename is None: - # last 2 are grey and white; ignore those or we - # get lots of old-looking players + # Last 2 are grey and white; ignore those or we + # get lots of old-looking players. highlight = PLAYER_COLORS[random.randrange( len(PLAYER_COLORS) - 2)] else: diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index cf9fb06a..c84e42ea 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -582,6 +582,21 @@ class Session: self._add_chosen_player(chooser) lobby.remove_chooser(chooser.getplayer()) + def transitioning_out_activity_was_freed( + self, can_show_ad_on_death: bool) -> None: + """(internal)""" + from ba._apputils import garbage_collect, call_after_ad + + # Since we're mostly between activities at this point, lets run a cycle + # of garbage collection; hopefully it won't cause hitches here. + garbage_collect(session_end=False) + + with _ba.Context(self): + if can_show_ad_on_death: + call_after_ad(self.begin_next_activity) + else: + _ba.pushcall(self.begin_next_activity) + def _add_chosen_player(self, chooser: ba.Chooser) -> ba.SessionPlayer: from ba._team import SessionTeam sessionplayer = chooser.getplayer() diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py index 44e41e0b..b2c7adba 100644 --- a/assets/src/ba_data/python/bastd/actor/respawnicon.py +++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py @@ -40,18 +40,17 @@ class RespawnIcon: """ def __init__(self, player: ba.Player, respawn_time: float): - """ - Instantiate with a given ba.Player and respawn_time (in seconds) - """ + """Instantiate with a ba.Player and respawn_time (in seconds).""" self._visible = True on_right, offs_extra, respawn_icons = self._get_context(player) - try: - mask_tex = (player.team.gamedata['_spaz_respawn_icons_mask_tex']) - except Exception: - mask_tex = player.team.gamedata['_spaz_respawn_icons_mask_tex'] = ( - ba.gettexture('characterIconMask')) + # Cache our mask tex on the team for easy access. + mask_tex = getattr(player.team, '_spaz_respawn_icons_mask_tex', None) + if mask_tex is None: + mask_tex = ba.gettexture('characterIconMask') + setattr(player.team, '_spaz_respawn_icons_mask_tex', mask_tex) + assert isinstance(mask_tex, ba.Texture) # Now find the first unused slot and use that. index = 0 @@ -139,12 +138,14 @@ class RespawnIcon: on_right = player.team.id % 2 == 1 # Store a list of icons in the team. - try: - respawn_icons = ( - player.team.gamedata['_spaz_respawn_icons_right']) - except Exception: - respawn_icons = ( - player.team.gamedata['_spaz_respawn_icons_right']) = {} + respawn_icons = getattr(player.team, '_spaz_respawn_icons_right', + None) + if respawn_icons is None: + respawn_icons = {} + setattr(player.team, '_spaz_respawn_icons_right', + respawn_icons) + assert isinstance(respawn_icons, dict) + offs_extra = -20 else: on_right = False diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py index 6b3c2374..7ed874fc 100644 --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py @@ -200,7 +200,8 @@ class _Entry: def set_position(self, position: Sequence[float]) -> None: """Set the entry's position.""" - # abort if we've been killed + + # Abort if we've been killed if not self._backing.node: return self._pos = tuple(position) @@ -315,13 +316,15 @@ class _EntryProxy: def __init__(self, scoreboard: Scoreboard, team: ba.Team): self._scoreboard = weakref.ref(scoreboard) - # have to store ID here instead of a weak-ref since the team will be - # dead when we die and need to remove it + + # Have to store ID here instead of a weak-ref since the team will be + # dead when we die and need to remove it. self._team_id = team.id def __del__(self) -> None: scoreboard = self._scoreboard() - # remove our team from the scoreboard if its still around + + # Remove our team from the scoreboard if its still around. if scoreboard is not None: scoreboard.remove_team(self._team_id) @@ -343,7 +346,7 @@ class Scoreboard: self._label = label self.score_split = score_split - # for free-for-all we go simpler since we have one per player + # For free-for-all we go simpler since we have one per player. self._pos: Sequence[float] if isinstance(ba.getsession(), ba.FreeForAllSession): self._do_cover = False @@ -368,11 +371,11 @@ class Scoreboard: """Update the score-board display for the given ba.Team.""" if not team.id in self._entries: self._add_team(team) - # create a proxy in the team which will kill + + # Create a proxy in the team which will kill # our entry when it dies (for convenience) - if '_scoreboard_entry' in team.gamedata: - raise Exception('existing _EntryProxy found') - team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team) + assert not hasattr(team, '_scoreboard_entry') + setattr(team, '_scoreboard_entry', _EntryProxy(self, team)) # Now set the entry. self._entries[team.id].set_value(score=score, @@ -383,7 +386,7 @@ class Scoreboard: def _add_team(self, team: ba.Team) -> None: if team.id in self._entries: - raise Exception('Duplicate team add') + raise RuntimeError('Duplicate team add') self._entries[team.id] = _Entry(self, team, do_cover=self._do_cover, diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index d86cc1b2..984d209d 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -49,16 +49,16 @@ class SpazBotPunchedMessage: Attributes: - badguy + spazbot The ba.SpazBot that got punched. damage How much damage was done to the ba.SpazBot. """ - def __init__(self, badguy: SpazBot, damage: int): + def __init__(self, spazbot: SpazBot, damage: int): """Instantiate a message with the given values.""" - self.badguy = badguy + self.spazbot = spazbot self.damage = damage @@ -69,7 +69,7 @@ class SpazBotDiedMessage: Attributes: - badguy + spazbot The ba.SpazBot that was killed. killerplayer @@ -79,10 +79,10 @@ class SpazBotDiedMessage: The particular type of death. """ - def __init__(self, badguy: SpazBot, killerplayer: Optional[ba.Player], + def __init__(self, spazbot: SpazBot, killerplayer: Optional[ba.Player], how: ba.DeathType): """Instantiate with given values.""" - self.badguy = badguy + self.spazbot = spazbot self.killerplayer = killerplayer self.how = how diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index ae0c0f48..503d4196 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -216,8 +216,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): # Whenever our evil bunny dies, respawn him and spew some eggs. elif isinstance(msg, SpazBotDiedMessage): self._spawn_evil_bunny() - assert msg.badguy.node - pos = msg.badguy.node.position + assert msg.spazbot.node + pos = msg.spazbot.node.position for _i in range(6): spread = 0.4 self._eggs.append( diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index c428a64d..5ded7ace 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -816,7 +816,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): elif isinstance(msg, SpazBotDiedMessage): # Every time a bad guy dies, spawn a new one. - ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.badguy)))) + ba.timer(3.0, ba.Call(self._spawn_bot, (type(msg.spazbot)))) elif isinstance(msg, SpazBotPunchedMessage): if self._preset in ['rookie', 'rookie_easy']: diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 26af046c..bfb6e196 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -36,7 +36,7 @@ if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union -class PuckDeathMessage: +class PuckDiedMessage: """Inform something that a puck has died.""" def __init__(self, puck: Puck): @@ -78,7 +78,7 @@ class Puck(ba.Actor): self.node.delete() activity = self._activity() if activity and not msg.immediate: - activity.handlemessage(PuckDeathMessage(self)) + activity.handlemessage(PuckDiedMessage(self)) # If we go out of bounds, move back to where we started. elif isinstance(msg, ba.OutOfBoundsMessage): @@ -113,6 +113,9 @@ class Player(ba.Player['Team']): class Team(ba.Team[Player]): """Our team type for this game.""" + def __init__(self) -> None: + self.score = 0 + # ba_meta export game class HockeyGame(ba.TeamGameActivity[Player, Team]): @@ -196,26 +199,28 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): self._puck_spawn_pos: Optional[Sequence[float]] = None self._score_regions: Optional[List[ba.NodeActor]] = None self._puck: Optional[Puck] = None + self._score_to_win = int(settings['Score to Win']) + self._time_limit = float(settings['Time Limit']) def get_instance_description(self) -> Union[str, Sequence]: - if self.settings_raw['Score to Win'] == 1: + if self._score_to_win == 1: return 'Score a goal.' - return 'Score ${ARG1} goals.', self.settings_raw['Score to Win'] + return 'Score ${ARG1} goals.', self._score_to_win def get_instance_description_short(self) -> Union[str, Sequence]: - if self.settings_raw['Score to Win'] == 1: + if self._score_to_win == 1: return 'score a goal' - return 'score ${ARG1} goals', self.settings_raw['Score to Win'] + return 'score ${ARG1} goals', self._score_to_win def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._puck_spawn_pos = self.map.get_flag_position(None) self._spawn_puck() - # set up the two score regions + # Set up the two score regions. defs = self.map.defs self._score_regions = [] self._score_regions.append( @@ -240,7 +245,6 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._chant_sound) def on_team_join(self, team: Team) -> None: - team.gamedata['score'] = 0 self._update_scoreboard() def _handle_puck_player_collide(self) -> None: @@ -274,7 +278,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): for team in self.teams: if team.id == index: scoring_team = team - team.gamedata['score'] += 1 + team.score += 1 # Tell all players to celebrate. for player in team.players: @@ -291,7 +295,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): big_message=True) # End game if we won. - if team.gamedata['score'] >= self.settings_raw['Score to Win']: + if team.score >= self._score_to_win: self.end_game() ba.playsound(self._foghorn_sound) @@ -317,14 +321,13 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score(team, team.gamedata['score']) + results.set_team_score(team, team.score) self.end(results=results) def _update_scoreboard(self) -> None: - winscore = self.settings_raw['Score to Win'] + winscore = self._score_to_win for team in self.teams: - self._scoreboard.set_team_value(team, team.gamedata['score'], - winscore) + self._scoreboard.set_team_value(team, team.score, winscore) def handlemessage(self, msg: Any) -> Any: @@ -335,7 +338,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): self.respawn_player(msg.getplayer(Player)) # Respawn dead pucks. - elif isinstance(msg, PuckDeathMessage): + elif isinstance(msg, PuckDiedMessage): if not self.has_ended(): ba.timer(3.0, self._spawn_puck) else: diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index dd7bf670..2ba9846d 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -1220,13 +1220,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): ba.timer(0.1, self._checkroundover) elif isinstance(msg, SpazBotDiedMessage): - pts, importance = msg.badguy.get_death_points(msg.how) + pts, importance = msg.spazbot.get_death_points(msg.how) if msg.killerplayer is not None: self._handle_kill_achievements(msg) target: Optional[Sequence[float]] try: - assert msg.badguy.node - target = msg.badguy.node.position + assert msg.spazbot.node + target = msg.spazbot.node.position except Exception: ba.print_exception() target = None @@ -1265,13 +1265,13 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _handle_uber_kill_achievements(self, msg: SpazBotDiedMessage) -> None: # Uber mine achievement: - if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): self._land_mine_kills += 1 if self._land_mine_kills >= 6: self._award_achievement('Gold Miner') # Uber tnt achievement: - if msg.badguy.last_attacked_type == ('explosion', 'tnt'): + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): self._tnt_kills += 1 if self._tnt_kills >= 6: ba.timer(0.5, ba.WeakCall(self._award_achievement, @@ -1280,7 +1280,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _handle_pro_kill_achievements(self, msg: SpazBotDiedMessage) -> None: # TNT achievement: - if msg.badguy.last_attacked_type == ('explosion', 'tnt'): + if msg.spazbot.last_attacked_type == ('explosion', 'tnt'): self._tnt_kills += 1 if self._tnt_kills >= 3: ba.timer( @@ -1291,7 +1291,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _handle_rookie_kill_achievements(self, msg: SpazBotDiedMessage) -> None: # Land-mine achievement: - if msg.badguy.last_attacked_type == ('explosion', 'land_mine'): + if msg.spazbot.last_attacked_type == ('explosion', 'land_mine'): self._land_mine_kills += 1 if self._land_mine_kills >= 3: self._award_achievement('Mine Games') @@ -1299,7 +1299,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _handle_training_kill_achievements(self, msg: SpazBotDiedMessage) -> None: # Toss-off-map achievement: - if msg.badguy.last_attacked_type == ('picked_up', 'default'): + if msg.spazbot.last_attacked_type == ('picked_up', 'default'): self._throw_off_kills += 1 if self._throw_off_kills >= 3: self._award_achievement('Off You Go Then') diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index df6de7bf..41485b2e 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -180,18 +180,18 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): def get_instance_description(self) -> Union[str, Sequence]: if (isinstance(self.session, ba.DualTeamSession) - and self.settings_raw.get('Entire Team Must Finish', False)): + and self._entire_team_must_finish): t_str = ' Your entire team has to finish.' else: t_str = '' - if self.settings_raw['Laps'] > 1: - return 'Run ${ARG1} laps.' + t_str, self.settings_raw['Laps'] + if self._laps > 1: + return 'Run ${ARG1} laps.' + t_str, self._laps return 'Run 1 lap.' + t_str def get_instance_description_short(self) -> Union[str, Sequence]: - if self.settings_raw['Laps'] > 1: - return 'run ${ARG1} laps', self.settings_raw['Laps'] + if self._laps > 1: + return 'run ${ARG1} laps', self._laps return 'run 1 lap' def on_transition_in(self) -> None: @@ -715,8 +715,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.PlayerDiedMessage): - # Augment default behavior. - super().handlemessage(msg) + super().handlemessage(msg) # Augment default behavior. player = msg.getplayer(Player) if not player.finished: self.respawn_player(player, respawn_time=1) diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index d5d0637c..f134816a 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -47,6 +47,10 @@ if TYPE_CHECKING: class Player(ba.Player['Team']): """Our player type for this game.""" + def __init__(self) -> None: + self.respawn_timer: Optional[ba.Timer] = None + self.respawn_icon: Optional[RespawnIcon] = None + class Team(ba.Team[Player]): """Our team type for this game.""" @@ -1113,20 +1117,20 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): # Respawn them shortly. assert self.initial_player_info is not None respawn_time = 2.0 + len(self.initial_player_info) * 1.0 - player.gamedata['respawn_timer'] = ba.Timer( + player.respawn_timer = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) - player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) + player.respawn_icon = RespawnIcon(player, respawn_time) elif isinstance(msg, SpazBotDiedMessage): if msg.how is ba.DeathType.REACHED_GOAL: - return - pts, importance = msg.badguy.get_death_points(msg.how) + return None + pts, importance = msg.spazbot.get_death_points(msg.how) if msg.killerplayer is not None: target: Optional[Sequence[float]] try: - assert msg.badguy is not None - assert msg.badguy.node - target = msg.badguy.node.position + assert msg.spazbot is not None + assert msg.spazbot.node + target = msg.spazbot.node.position except Exception: ba.print_exception() target = None @@ -1151,7 +1155,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._update_scores() else: - super().handlemessage(msg) + return super().handlemessage(msg) + return None def _get_bot_speed(self, bot_type: Type[SpazBot]) -> float: speed = self._bot_speed_map.get(bot_type) diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 6840f909..ae9a1a9a 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -272,11 +272,11 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): self._update_scores() elif isinstance(msg, SpazBotDiedMessage): - pts, importance = msg.badguy.get_death_points(msg.how) + pts, importance = msg.spazbot.get_death_points(msg.how) target: Optional[Sequence[float]] if msg.killerplayer: - assert msg.badguy.node - target = msg.badguy.node.position + assert msg.spazbot.node + target = msg.spazbot.node.position self.stats.player_scored(msg.killerplayer, pts, target=target, diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index 0aca2a2f..2d9f3ffa 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -28,8 +28,8 @@ # pylint: disable=missing-function-docstring, missing-class-docstring # pylint: disable=invalid-name # pylint: disable=too-many-locals -# pylint: disable=unused-variable # pylint: disable=unused-argument +# pylint: disable=unused-variable from __future__ import annotations @@ -181,7 +181,21 @@ class ButtonRelease: timeformat=ba.TimeFormat.MILLISECONDS) -class TutorialActivity(ba.Activity[ba.Player, ba.Team]): +class Player(ba.Player['Team']): + """Our player type for this game.""" + + def __init__(self) -> None: + self.pressed = False + + +class Team(ba.Team[Player]): + """Our team type for this game.""" + + def __init__(self) -> None: + pass + + +class TutorialActivity(ba.Activity[Player, Team]): def __init__(self, settings: Dict[str, Any] = None): from bastd.maps import Rampage @@ -462,6 +476,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]): n.opacity = 0.0 a.set_stick_image_position(0, 0) + # Can be used for debugging. class SetSpeed: def __init__(self, speed: int): @@ -2330,7 +2345,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]): ba.WeakCall(self._read_entries)) def _update_skip_votes(self) -> None: - count = sum(1 for player in self.players if player.gamedata['pressed']) + count = sum(1 for player in self.players if player.pressed) assert self._skip_count_text self._skip_count_text.text = ba.Lstr( resource=self._r + '.skipVoteCountText', @@ -2349,7 +2364,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]): self._skip_text.text = '' self.end() - def _player_pressed_button(self, player: ba.Player) -> None: + def _player_pressed_button(self, player: Player) -> None: # Special case: if there's only one player, we give them a # warning on their first press (some players were thinking the @@ -2363,7 +2378,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]): self._skip_text.scale = 1.3 incr = 50 t = incr - for i in range(6): + for _i in range(6): ba.timer(t, ba.Call(setattr, self._skip_text, 'color', (1, 0.5, 0.1)), @@ -2376,7 +2391,7 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]): ba.timer(6.0, ba.WeakCall(self._revert_confirm)) return - player.gamedata['pressed'] = True + player.pressed = True # test... if not all(self.players): @@ -2393,15 +2408,15 @@ class TutorialActivity(ba.Activity[ba.Player, ba.Team]): self._skip_text.color = (1, 1, 1) self._issued_warning = False - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: Player) -> None: super().on_player_join(player) - player.gamedata['pressed'] = False - # we just wanna know if this player presses anything.. + + # We just wanna know if this player presses anything. player.assign_input_call( ('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'), ba.Call(self._player_pressed_button, player)) - def on_player_leave(self, player: ba.Player) -> None: + def on_player_leave(self, player: Player) -> None: if not all(self.players): ba.print_error('Nonexistent player in on_player_leave: ' + str([str(p) for p in self.players]) + ': we are ' + diff --git a/docs/ba_module.md b/docs/ba_module.md index d6b1b011..7ad463ee 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-25 for Ballistica version 1.5.0 build 20029

    +

    last updated on 2020-05-27 for Ballistica version 1.5.0 build 20030

    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!


    @@ -97,6 +97,7 @@
  • ba.timer()
  • ba.timestring()
  • ba.vec3validate()
  • +
  • ba.verify_object_death()
  • Asset Classes

      @@ -1644,7 +1645,7 @@ and it should begin its actual game logic.

      Attributes Inherited:

      allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

      Methods Inherited:

      -
      begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_request(), on_team_join(), on_team_leave(), set_activity()
      +
      begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

      Methods Defined or Overridden:

      <constructor>, get_current_game_instance(), get_custom_menu_entries(), on_activity_end(), on_player_leave(), restart()
      @@ -1987,7 +1988,7 @@ its time with lingering corpses, sound effects, etc.

      Attributes Inherited:

      allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

      Methods Inherited:

      -
      announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity()
      +
      announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

      Methods Defined or Overridden:

      <constructor>

      @@ -2025,7 +2026,7 @@ its time with lingering corpses, sound effects, etc.

      Attributes Inherited:

      allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

      Methods Inherited:

      -
      announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity()
      +
      announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

      Methods Defined or Overridden:

      <constructor>, get_ffa_point_awards()
      @@ -3329,7 +3330,7 @@ Use ba.getmodel() to instantiate one.

      Attributes Inherited:

      allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

      Methods Inherited:

      -
      begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_leave(), on_player_request(), on_team_leave(), set_activity()
      +
      begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_leave(), on_player_request(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

      Methods Defined or Overridden:

      <constructor>, announce_game_results(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), on_activity_end(), on_team_join()
      @@ -6522,6 +6523,16 @@ so this can be used to disambiguate 'Any' types). Generally this should be used in 'if __debug__' or assert clauses to keep runtime overhead minimal.

      +
      +

      ba.verify_object_death()

      +

      verify_object_death(obj: object) -> None

      + +

      Warn if an object does not get freed within a short period.

      + +

      Category: General Utility Functions

      + +

      This can be handy to detect and prevent memory/resource leaks.

      +

      ba.widget()

      widget(edit: ba.Widget = None, up_widget: ba.Widget = None, diff --git a/tools/efrotools/filecache.py b/tools/efrotools/filecache.py index 6d1fa12b..4dcf9634 100644 --- a/tools/efrotools/filecache.py +++ b/tools/efrotools/filecache.py @@ -26,6 +26,7 @@ import json import os from typing import TYPE_CHECKING +from efro.terminal import Clr from efrotools import get_files_hash if TYPE_CHECKING: @@ -104,8 +105,8 @@ class FileCache: # if anything has been modified, don't write. for fname, mtime in self.mtimes.items(): if os.path.getmtime(fname) != mtime: - print('File changed during run: "' + fname + '";' + - ' cache not updated.') + print(f'{Clr.YLW}File changed during run:' + f' "{fname}"; cache not updated.{Clr.RST}') return out = json.dumps(self.entries) with open(self._path, 'w') as outfile: From e1f1cf0ed99ab04711bc75116dcc5580413fff0b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 28 May 2020 00:50:37 -0700 Subject: [PATCH 049/417] More modernizing and cleanup --- .efrocachemap | 24 +++--- assets/src/ba_data/python/_ba.py | 44 +++++++--- assets/src/ba_data/python/ba/__init__.py | 15 ++-- assets/src/ba_data/python/ba/_achievement.py | 15 ++-- assets/src/ba_data/python/ba/_activity.py | 2 +- assets/src/ba_data/python/ba/_apputils.py | 72 +++------------- assets/src/ba_data/python/ba/_coopgame.py | 35 ++++---- assets/src/ba_data/python/ba/_coopsession.py | 61 +++++++------ assets/src/ba_data/python/ba/_error.py | 10 +++ assets/src/ba_data/python/ba/_gameactivity.py | 86 +++++++++---------- assets/src/ba_data/python/ba/_gameresults.py | 4 +- assets/src/ba_data/python/ba/_gameutils.py | 8 +- assets/src/ba_data/python/ba/_netutils.py | 2 +- assets/src/ba_data/python/ba/_player.py | 11 +++ assets/src/ba_data/python/ba/_session.py | 19 ++-- .../ba_data/python/bastd/activity/coopjoin.py | 20 +++-- .../python/bastd/activity/coopscore.py | 12 ++- .../python/bastd/activity/dualteamscore.py | 4 +- .../src/ba_data/python/bastd/actor/spazbot.py | 2 +- docs/ba_module.md | 73 +++++++++++----- 20 files changed, 284 insertions(+), 235 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 4179fd4f..e1ace103 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/db/9c7cfd4e4f4a1f7a7adc980bca42", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/0b/231e38ff29d932df7552050891c5", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/56/bb316ec28ee98ece5c0c3a04b77f", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/92/d787c99db6cc85f70b7131ff2c0c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/97/b9/9c6c3c90f10d319250a9f3d287b3", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/2a/60bdf1c4d4e13bdbb5f4df121e3e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/66/25/79ea606983dc91ac0cd79c1e7da6", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/70/c6/0ab2cdf222ffcadade37dd3b8462", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/65/450a67dab189c0832b6bf28a9e9c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/a9/e1ab6defb8bcf536dff46d0c62b2", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/fc/d00336dae2b1c7323b31518b52aa", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ed/98/dbea1af1da83bfa1a3283175b234" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/95/a8/318c6db7a9c94989c601f9388211", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/53/dda3c28a824749358279d01d85a6", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cb/5e/04efb608c6a0d3fc80baee7f2c0e", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/91/74/c92748de53d860aa936f969c4699", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/a0/202236991664bc72a33affee2911", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/1a/7f626564f3659f4cbd00d62cbd5a", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/94/b8/4f2c26af58e4386d58f2de2b8f3f", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8e/f3/40da5e70872c27cb1716a0e7bc10", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a0/a9/9ca7e5a2a62c7198f6dccf29a1e2", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/54/e7/fd4f9d4af81fed229a1fd2d486f1", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/5f/90a09221a6cb5ca24cf2a6b0f4e7", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c2/14/82ced0d7340340cd09a73987c82f" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 9df9b873..10e4bbe4 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=265401783818737452594582363319036908124 +# SOURCES_HASH=317793613698101603244532998583646381571 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -2310,21 +2310,31 @@ def get_ui_input_device() -> ba.InputDevice: return ba.InputDevice() -def getactivity(doraise: bool = True) -> ba.Activity: - """getactivity(doraise: bool = True) -> ba.Activity +# Show that our return type varies based on "doraise" value: +@overload +def getactivity(doraise: Literal[True] = True) -> ba.Activity: + ... - Returns the current ba.Activity instance. + +@overload +def getactivity(doraise: Literal[False]) -> Optional[ba.Activity]: + ... + + +def getactivity(doraise: bool = True) -> Optional[ba.Activity]: + """getactivity(doraise: bool = True) -> + + Return the current ba.Activity instance. Category: Gameplay Functions Note that this is based on context; thus code run in a timer generated in Activity 'foo' will properly return 'foo' here, even if another Activity has since been created or is transitioning in. - If there is no current Activity an Exception is raised, or if doraise is - False then None is returned instead. + If there is no current Activity, raises a ba.ActivityNotFoundError. + If doraise is False, None will be returned instead in that case. """ - import ba # pylint: disable=cyclic-import - return ba.Activity(settings={}) + return None def getcollidemodel(name: str) -> ba.CollideModel: @@ -2422,8 +2432,19 @@ def getnodes() -> list: return list() -def getsession(doraise: bool = True) -> ba.Session: - """getsession(doraise: bool = True) -> ba.Session +# Show that our return type varies based on "doraise" value: +@overload +def getsession(doraise: Literal[True] = True) -> ba.Session: + ... + + +@overload +def getsession(doraise: Literal[False]) -> Optional[ba.Session]: + ... + + +def getsession(doraise: bool = True) -> Optional[ba.Session]: + """getsession(doraise: bool = True) -> Category: Gameplay Functions @@ -2433,8 +2454,7 @@ def getsession(doraise: bool = True) -> ba.Session: exists, etc. If there is no current Session, an Exception is raised, or if doraise is False then None is returned instead. """ - import ba # pylint: disable=cyclic-import - return ba.Session([]) + return None def getsound(name: str) -> ba.Sound: diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 12225c01..6b79f6e0 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -39,7 +39,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, open_url, widget) from ba._activity import Activity from ba._actor import Actor -from ba._player import Player, playercast, playercast_o +from ba._player import PlayerInfo, Player, playercast, playercast_o from ba._nodeactor import NodeActor from ba._app import App from ba._coopgame import CoopGameActivity @@ -47,13 +47,12 @@ from ba._coopsession import CoopSession from ba._dependency import (Dependency, DependencyComponent, DependencySet, AssetPackage) from ba._enums import TimeType, Permission, TimeFormat, SpecialChar -from ba._error import (print_exception, print_error, NotFoundError, - PlayerNotFoundError, SessionPlayerNotFoundError, - NodeNotFoundError, ActorNotFoundError, - InputDeviceNotFoundError, WidgetNotFoundError, - ActivityNotFoundError, TeamNotFoundError, - SessionTeamNotFoundError, SessionNotFoundError, - DelegateNotFoundError, DependencyError) +from ba._error import ( + print_exception, print_error, ContextError, NotFoundError, + PlayerNotFoundError, SessionPlayerNotFoundError, NodeNotFoundError, + ActorNotFoundError, InputDeviceNotFoundError, WidgetNotFoundError, + ActivityNotFoundError, TeamNotFoundError, SessionTeamNotFoundError, + SessionNotFoundError, DelegateNotFoundError, DependencyError) from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity from ba._gameresults import TeamGameResults diff --git a/assets/src/ba_data/python/ba/_achievement.py b/assets/src/ba_data/python/ba/_achievement.py index c024dfbd..44292c28 100644 --- a/assets/src/ba_data/python/ba/_achievement.py +++ b/assets/src/ba_data/python/ba/_achievement.py @@ -373,6 +373,7 @@ class Achievement: # pylint: disable=cyclic-import from ba._lang import Lstr from ba._enums import SpecialChar + from ba._coopsession import CoopSession from bastd.actor.image import Image from bastd.actor.text import Text @@ -404,12 +405,16 @@ class Achievement: hmo = False else: try: - campaign = _ba.getsession().campaign - assert campaign is not None - hmo = (self._hard_mode_only and campaign.name == 'Easy') + session = _ba.getsession() + if isinstance(session, CoopSession): + campaign = session.campaign + assert campaign is not None + hmo = (self._hard_mode_only and campaign.name == 'Easy') + else: + hmo = False except Exception: from ba import _error - _error.print_exception('unable to determine campaign') + _error.print_exception('Error determining campaign') hmo = False objs: List[ba.Actor] @@ -678,7 +683,7 @@ class Achievement: # Just piggy-back onto any current activity # (should we use the session instead?..) - activity: Optional[ba.Activity] = _ba.getactivity(doraise=False) + activity = _ba.getactivity(doraise=False) # If this gets called while this achievement is occupying a slot # already, ignore it. (probably should never happen in real diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 241d1d70..fe501643 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -351,7 +351,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): raise TypeError('non-actor passed to add_actor_weak_ref') if (self.has_transitioned_in() and _ba.time() - self._last_prune_dead_actors_time > 10.0): - print_error('it looks like nodes/actors are ' + print_error('It looks like nodes/actors are ' 'not being pruned in your activity;' ' did you call Activity.on_transition_in()' ' from your subclass?; ' + str(self) + ' (loc. b)') diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index 1c8b1da5..cf0f0137 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -73,7 +73,6 @@ def suppress_debug_reports() -> None: This should be called in devel/debug situations to avoid spamming the master server with spurious logs. """ - # _ba.screenmessage("Suppressing debug reports.", color=(1, 0, 0)) _ba.app.suppress_debug_reports = True @@ -189,21 +188,23 @@ def print_live_object_warnings(when: Any, """Print warnings for remaining objects in the current context.""" # pylint: disable=cyclic-import import gc - from ba import _session as bs_session - from ba import _actor as bs_actor - from ba import _activity as bs_activity + from ba._session import Session + from ba._actor import Actor + from ba._activity import Activity sessions: List[ba.Session] = [] activities: List[ba.Activity] = [] - actors = [] + actors: List[ba.Actor] = [] + + # Once we come across leaked stuff, printing again is probably + # redundant. if _ba.app.printed_live_object_warning: - # print 'skipping live obj check due to previous found live object(s)' return for obj in gc.get_objects(): - if isinstance(obj, bs_actor.Actor): + if isinstance(obj, Actor): actors.append(obj) - elif isinstance(obj, bs_session.Session): + elif isinstance(obj, Session): sessions.append(obj) - elif isinstance(obj, bs_activity.Activity): + elif isinstance(obj, Activity): activities.append(obj) # Complain about any remaining sessions. @@ -211,66 +212,19 @@ def print_live_object_warnings(when: Any, if session is ignore_session: continue _ba.app.printed_live_object_warning = True - print('ERROR: Session found', when, ':', session) - # refs = list(gc.get_referrers(session)) - # i = 1 - # for ref in refs: - # if type(ref) is types.FrameType: continue - # print ' ref', i, ':', ref - # i += 1 - # if type(ref) is list or type(ref) is tuple or type(ref) is dict: - # refs2 = list(gc.get_referrers(ref)) - # j = 1 - # for ref2 in refs2: - # if type(ref2) is types.FrameType: continue - # print ' ref\'s ref', j, ':', ref2 - # j += 1 + print(f'ERROR: Session found {when}: {session}') # Complain about any remaining activities. for activity in activities: if activity is ignore_activity: continue _ba.app.printed_live_object_warning = True - print('ERROR: Activity found', when, ':', activity) - # refs = list(gc.get_referrers(activity)) - # i = 1 - # for ref in refs: - # if type(ref) is types.FrameType: continue - # print ' ref', i, ':', ref - # i += 1 - # if type(ref) is list or type(ref) is tuple or type(ref) is dict: - # refs2 = list(gc.get_referrers(ref)) - # j = 1 - # for ref2 in refs2: - # if type(ref2) is types.FrameType: continue - # print ' ref\'s ref', j, ':', ref2 - # j += 1 + print(f'ERROR: Activity found {when}: {activity}') # Complain about any remaining actors. for actor in actors: _ba.app.printed_live_object_warning = True - print('ERROR: Actor found', when, ':', actor) - # if isinstance(actor, bs_actor.Actor): - # try: - # if actor.node: - # print(' - contains node:', - # actor.node.getnodetype(), ';', - # actor.node.get_name()) - # except Exception as exc: - # print(' - exception checking actor node:', exc) - # refs = list(gc.get_referrers(actor)) - # i = 1 - # for ref in refs: - # if type(ref) is types.FrameType: continue - # print ' ref', i, ':', ref - # i += 1 - # if type(ref) is list or type(ref) is tuple or type(ref) is dict: - # refs2 = list(gc.get_referrers(ref)) - # j = 1 - # for ref2 in refs2: - # if type(ref2) is types.FrameType: continue - # print ' ref\'s ref', j, ':', ref2 - # j += 1 + print(f'ERROR: Actor found {when}: {actor}') def print_corrupt_file_error() -> None: diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index 89421b82..ee60ea96 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -25,6 +25,7 @@ from typing import TYPE_CHECKING, TypeVar import _ba from ba._gameactivity import GameActivity +from ba._general import WeakCall if TYPE_CHECKING: from typing import Type, Dict, Any, Set, List, Sequence, Optional @@ -41,10 +42,13 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): Category: Gameplay Classes """ + # We can assume our session is a CoopSession. + session: ba.CoopSession + @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: - from ba import _coopsession - return issubclass(sessiontype, _coopsession.CoopSession) + from ba._coopsession import CoopSession + return issubclass(sessiontype, CoopSession) def __init__(self, settings: Dict[str, Any]): super().__init__(settings) @@ -57,16 +61,14 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): self._warn_beeps_sound = _ba.getsound('warnBeeps') def on_begin(self) -> None: - from ba import _general super().on_begin() # Show achievements remaining. if not _ba.app.kiosk_mode: - _ba.timer(3.8, - _general.WeakCall(self._show_remaining_achievements)) + _ba.timer(3.8, WeakCall(self._show_remaining_achievements)) # Preload achievement images in case we get some. - _ba.timer(2.0, _general.WeakCall(self._preload_achievements)) + _ba.timer(2.0, WeakCall(self._preload_achievements)) # Let's ask the server for a 'time-to-beat' value. levelname = self._get_coop_level_name() @@ -76,7 +78,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): self.settings_raw['name']).get_score_version_string().replace( ' ', '_')) _ba.get_scores_to_beat(levelname, config_str, - _general.WeakCall(self._on_got_scores_to_beat)) + WeakCall(self._on_got_scores_to_beat)) def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None: pass @@ -153,18 +155,18 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): def _show_remaining_achievements(self) -> None: # pylint: disable=cyclic-import - from ba import _achievement - from ba import _lang + from ba._achievement import get_achievements_for_coop_level + from ba._lang import Lstr from bastd.actor.text import Text ts_h_offs = 30 v_offs = -200 achievements = [ - a for a in _achievement.get_achievements_for_coop_level( + a for a in get_achievements_for_coop_level( self._get_coop_level_name()) if not a.complete ] vrmode = _ba.app.vr_mode if achievements: - Text(_lang.Lstr(resource='achievementsRemainingText'), + Text(Lstr(resource='achievementsRemainingText'), host_only=True, position=(ts_h_offs - 10 + 40, v_offs - 10), transition=Text.Transition.FADE_IN, @@ -208,12 +210,12 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): Returns True if a banner will be shown; False otherwise """ - from ba import _achievement + from ba._achievement import get_achievement if achievement_name in self._achievements_awarded: return - ach = _achievement.get_achievement(achievement_name) + ach = get_achievement(achievement_name) # If we're in the easy campaign and this achievement is hard-mode-only, # ignore it. @@ -223,8 +225,8 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): if ach.hard_mode_only and campaign.name == 'Easy': return except Exception: - from ba import _error - _error.print_exception() + from ba._error import print_exception + print_exception() # If we haven't awarded this one, check to see if we've got it. # If not, set it through the game service *and* add a transaction @@ -261,10 +263,9 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): def setup_low_life_warning_sound(self) -> None: """Set up a beeping noise to play when any players are near death.""" - from ba import _general self._life_warning_beep = None self._life_warning_beep_timer = _ba.Timer( - 1.0, _general.WeakCall(self._update_life_warning), repeat=True) + 1.0, WeakCall(self._update_life_warning), repeat=True) def _update_life_warning(self) -> None: # Beep continuously if anyone is close to death. diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index be5f5450..9fdd94fa 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -42,11 +42,21 @@ class CoopSession(Session): These generally consist of 1-4 players against the computer and include functionality such as high score lists. + + Attrs: + + campaign + The ba.Campaign instance this Session represents, or None if + there is no associated Campaign. """ use_teams = True use_team_colors = False allow_mid_activity_joins = False + # Note: even though these are instance vars, we annotate them at the + # class level so that docs generation can access their types. + campaign: Optional[ba.Campaign] + def __init__(self) -> None: """Instantiate a co-op mode session.""" # pylint: disable=cyclic-import @@ -77,16 +87,11 @@ class CoopSession(Session): max_players=max_players) # Tournament-ID if we correspond to a co-op tournament (otherwise None) - self.tournament_id = (app.coop_session_args['tournament_id'] - if 'tournament_id' in app.coop_session_args else - None) + self.tournament_id: Optional[str] = ( + app.coop_session_args.get('tournament_id')) - # FIXME: Could be nice to pass this in as actual args. - self.campaign_state = { - 'campaign': (app.coop_session_args['campaign']), - 'level': app.coop_session_args['level'] - } - self.campaign = get_campaign(self.campaign_state['campaign']) + self.campaign = get_campaign(app.coop_session_args['campaign']) + self.campaign_level_name: str = app.coop_session_args['level'] self._ran_tutorial_activity = False self._tutorial_activity: Optional[ba.Activity] = None @@ -96,7 +101,7 @@ class CoopSession(Session): self.set_activity(_ba.new_activity(CoopJoinActivity)) self._next_game_instance: Optional[ba.GameActivity] = None - self._next_game_name: Optional[str] = None + self._next_game_level_name: Optional[str] = None self._update_on_deck_game_instances() def get_current_game_instance(self) -> ba.GameActivity: @@ -107,12 +112,11 @@ class CoopSession(Session): # pylint: disable=cyclic-import from ba._gameactivity import GameActivity - # Instantiates levels we might be running soon - # so they have time to load. + # Instantiate levels we may be running soon to let them load in the bg. # Build an instance for the current level. assert self.campaign is not None - level = self.campaign.get_level(self.campaign_state['level']) + level = self.campaign.get_level(self.campaign_level_name) gametype = level.gametype settings = level.get_settings() @@ -128,7 +132,7 @@ class CoopSession(Session): # Find the next level and build an instance for it too. levels = self.campaign.get_levels() - level = self.campaign.get_level(self.campaign_state['level']) + level = self.campaign.get_level(self.campaign_level_name) nextlevel: Optional[ba.Level] if level.index < len(levels) - 1: @@ -149,15 +153,15 @@ class CoopSession(Session): newactivity = _ba.new_activity(gametype, settings) assert isinstance(newactivity, GameActivity) self._next_game_instance = newactivity - self._next_game_name = nextlevel.name + self._next_game_level_name = nextlevel.name else: self._next_game_instance = None - self._next_game_name = None + self._next_game_level_name = None # Special case: # If our current level is 'onslaught training', instantiate # our tutorial so its ready to go. (if we haven't run it yet). - if (self.campaign_state['level'] == 'Onslaught Training' + if (self.campaign_level_name == 'Onslaught Training' and self._tutorial_activity is None and not self._ran_tutorial_activity): from bastd.tutorial import TutorialActivity @@ -248,6 +252,7 @@ class CoopSession(Session): from ba._coopgame import CoopGameActivity from ba._gameresults import TeamGameResults from ba._score import ScoreType + from ba._player import PlayerInfo from bastd.tutorial import TutorialActivity from bastd.activity.coopscore import CoopScoreScreen @@ -278,9 +283,9 @@ class CoopSession(Session): if outcome == 'next_level': if self._next_game_instance is None: - raise Exception() - assert self._next_game_name is not None - self.campaign_state['level'] = self._next_game_name + raise RuntimeError() + assert self._next_game_level_name is not None + self.campaign_level_name = self._next_game_level_name next_game = self._next_game_instance else: next_game = self._current_game_instance @@ -289,10 +294,10 @@ class CoopSession(Session): # and will be going into onslaught-training, show the # tutorial first. if (isinstance(activity, JoinActivity) - and self.campaign_state['level'] == 'Onslaught Training' + and self.campaign_level_name == 'Onslaught Training' and not app.kiosk_mode): if self._tutorial_activity is None: - raise RuntimeError('tutorial not preloaded properly') + raise RuntimeError('Tutorial not preloaded properly.') self.set_activity(self._tutorial_activity) self._tutorial_activity = None self._ran_tutorial_activity = True @@ -336,6 +341,8 @@ class CoopSession(Session): self.set_activity(_ba.new_activity(TransitionActivity)) else: + player_info: List[ba.PlayerInfo] + # Generic team games. if isinstance(results, TeamGameResults): player_info = results.get_player_info() @@ -364,8 +371,7 @@ class CoopSession(Session): # Old coop-game-specific results; should migrate away from these. else: - player_info = (results['player_info'] - if 'player_info' in results else None) + player_info = results.get('player_info') score = results['score'] if 'score' in results else None fail_message = (results['fail_message'] if 'fail_message' in results else None) @@ -376,6 +382,11 @@ class CoopSession(Session): assert activity_score_type is not None score_type = activity_score_type + # Validate types. + if player_info is not None: + assert isinstance(player_info, list) + assert (isinstance(i, PlayerInfo) for i in player_info) + # Looks like we were in a round - check the outcome and # go from there. if outcome == 'restart': @@ -393,7 +404,7 @@ class CoopSession(Session): 'score_type': score_type, 'outcome': outcome, 'campaign': self.campaign, - 'level': self.campaign_state['level'] + 'level': self.campaign_level_name })) # No matter what, get the next 2 levels ready to go. diff --git a/assets/src/ba_data/python/ba/_error.py b/assets/src/ba_data/python/ba/_error.py index afb36569..bf1db183 100644 --- a/assets/src/ba_data/python/ba/_error.py +++ b/assets/src/ba_data/python/ba/_error.py @@ -49,6 +49,16 @@ class DependencyError(Exception): return self._deps +class ContextError(Exception): + """Exception raised when a call is made in an invalid context. + + category: Exception Classes + + Examples of this include calling UI functions within an Activity context + or calling scene manipulation functions outside of a game context. + """ + + class NotFoundError(Exception): """Exception raised when a referenced object does not exist. diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 9d0de5ee..dad009cd 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -30,6 +30,7 @@ from ba._activity import Activity from ba._score import ScoreInfo from ba._lang import Lstr from ba._messages import PlayerDiedMessage +from ba._error import NotFoundError, print_error, print_exception import _ba if TYPE_CHECKING: @@ -273,15 +274,18 @@ class GameActivity(Activity[PlayerType, TeamType]): # Set some defaults. self.allow_pausing = True self.allow_kick_idle_players = True - self._spawn_sound = _ba.getsound('spawn') # Whether to show points for kills. - self._show_kill_points = True + self.show_kill_points = True # If not None, the music type that should play in on_transition_in() # (unless overridden by the map). self.default_music: Optional[ba.MusicType] = None + # Holds some flattened info about the player set at the point + # when on_begin() is called. + self.initial_player_info: Optional[List[ba.PlayerInfo]] = None + # Go ahead and get our map loading. map_name: str if 'map' in settings: @@ -298,13 +302,13 @@ class GameActivity(Activity[PlayerType, TeamType]): _ba.screenmessage(Lstr(resource='noValidMapsErrorText')) raise Exception('No valid maps') map_name = valid_maps[random.randrange(len(valid_maps))] + self._spawn_sound = _ba.getsound('spawn') self._map_type = _map.get_map_class(map_name) self._map_type.preload() self._map: Optional[ba.Map] = None self._powerup_drop_timer: Optional[ba.Timer] = None self._tnt_spawners: Optional[Dict[int, TNTSpawner]] = None self._tnt_drop_timer: Optional[ba.Timer] = None - self.initial_player_info: Optional[List[Dict[str, Any]]] = None self._game_scoreboard_name_text: Optional[ba.Actor] = None self._game_scoreboard_description_text: Optional[ba.Actor] = None self._standard_time_limit_time: Optional[int] = None @@ -333,7 +337,6 @@ class GameActivity(Activity[PlayerType, TeamType]): Raises a ba.NotFoundError if the map does not currently exist. """ if self._map is None: - from ba._error import NotFoundError raise NotFoundError return self._map @@ -355,10 +358,9 @@ class GameActivity(Activity[PlayerType, TeamType]): campaign = self.session.campaign assert campaign is not None return campaign.get_level( - self.session.campaign_state['level']).displayname + self.session.campaign_level_name).displayname except Exception: - from ba import _error - _error.print_error('error getting campaign level name') + print_error('error getting campaign level name') return self.get_instance_display_string() def get_instance_description(self) -> Union[str, Sequence]: @@ -415,19 +417,15 @@ class GameActivity(Activity[PlayerType, TeamType]): return '' def on_transition_in(self) -> None: - super().on_transition_in() # Make our map. self._map = self._map_type() - music = self.default_music - - # give our map a chance to override the music - # (for happy-thoughts and other such themed maps) - override_music = self._map_type.get_music_type() - if override_music is not None: - music = override_music + # Give our map a chance to override the music + # (for happy-thoughts and other such themed maps). + map_music = self._map_type.get_music_type() + music = map_music if map_music is not None else self.default_music if music is not None: from ba import _music @@ -470,9 +468,9 @@ class GameActivity(Activity[PlayerType, TeamType]): and calls either end_game or continue_game depending on the result""" # pylint: disable=too-many-nested-blocks # pylint: disable=cyclic-import - from bastd.ui import continues - from ba import _gameutils - from ba import _general + from bastd.ui.continues import ContinuesWindow + from ba._gameutils import sharedobj + from ba._general import WeakCall from ba._coopsession import CoopSession from ba._enums import TimeType @@ -490,7 +488,7 @@ class GameActivity(Activity[PlayerType, TeamType]): if isinstance(session, CoopSession): assert session.campaign is not None if session.campaign.sequential: - gnode = _gameutils.sharedobj('globals') + gnode = sharedobj('globals') # Only attempt this if we're not currently paused # and there appears to be no UI. @@ -501,19 +499,18 @@ class GameActivity(Activity[PlayerType, TeamType]): with _ba.Context('ui'): _ba.timer( 0.5, - lambda: continues.ContinuesWindow( + lambda: ContinuesWindow( self, self._continue_cost, - continue_call=_general.WeakCall( + continue_call=WeakCall( self._continue_choice, True), - cancel_call=_general.WeakCall( + cancel_call=WeakCall( self._continue_choice, False)), timetype=TimeType.REAL) return except Exception: - from ba import _error - _error.print_exception('error continuing game') + print_exception('error continuing game') self.end_game() @@ -525,8 +522,8 @@ class GameActivity(Activity[PlayerType, TeamType]): from ba._freeforallsession import FreeForAllSession from ba._coopsession import CoopSession session = self.session - campaign = session.campaign if isinstance(session, CoopSession): + campaign = session.campaign assert campaign is not None _ba.set_analytics_screen( 'Coop Game: ' + campaign.name + ' ' + @@ -576,13 +573,13 @@ class GameActivity(Activity[PlayerType, TeamType]): def on_begin(self) -> None: from ba._general import WeakCall + from ba._player import PlayerInfo super().on_begin() try: self._game_begin_analytics() except Exception: - from ba import _error - _error.print_exception('error in game-begin-analytics') + print_exception('error in game-begin-analytics') # We don't do this in on_transition_in because it may depend on # players/teams which aren't available until now. @@ -591,26 +588,27 @@ class GameActivity(Activity[PlayerType, TeamType]): _ba.timer(2.5, WeakCall(self._show_tip)) # Store some basic info about players present at start time. - self.initial_player_info = [{ - 'name': p.get_name(full=True), - 'character': p.character - } for p in self.players] + self.initial_player_info = [ + PlayerInfo(name=p.get_name(full=True), character=p.character) + for p in self.players + ] # Sort this by name so high score lists/etc will be consistent # regardless of player join order. - self.initial_player_info.sort(key=lambda x: x['name']) + self.initial_player_info.sort(key=lambda x: x.name) # If this is a tournament, query info about it such as how much # time is left. tournament_id = self.session.tournament_id if tournament_id is not None: - _ba.tournament_query(args={ - 'tournamentIDs': [tournament_id], - 'source': 'in-game time remaining query' - }, - callback=WeakCall( - self._on_tournament_query_response)) + _ba.tournament_query( + args={ + 'tournamentIDs': [tournament_id], + 'source': 'in-game time remaining query' + }, + callback=WeakCall(self._on_tournament_query_response), + ) def _on_tournament_query_response(self, data: Optional[Dict[str, Any]]) -> None: @@ -670,7 +668,7 @@ class GameActivity(Activity[PlayerType, TeamType]): kill=True, victim_player=player, importance=importance, - showpoints=self._show_kill_points) + showpoints=self.show_kill_points) def show_scoreboard_info(self) -> None: """Create the game info display. @@ -916,19 +914,19 @@ class GameActivity(Activity[PlayerType, TeamType]): force: bool = False) -> None: from ba._gameresults import TeamGameResults - # if results is a standard team-game-results, associate it with us - # so it can grab our score prefs + # If results is a standard team-game-results, associate it with us + # so it can grab our score prefs. if isinstance(results, TeamGameResults): results.set_game(self) - # if we had a standard time-limit that had not expired, stop it so - # it doesnt tick annoyingly + # If we had a standard time-limit that had not expired, stop it so + # it doesnt tick annoyingly. if (self._standard_time_limit_time is not None and self._standard_time_limit_time > 0): self._standard_time_limit_timer = None self._standard_time_limit_text = None - # ditto with tournament time limits + # Ditto with tournament time limits. if (self._tournament_time_limit is not None and self._tournament_time_limit > 0): self._tournament_time_limit_timer = None diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index a4997e37..ff185d56 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -57,7 +57,7 @@ class TeamGameResults: self._scores: Dict[int, Tuple[ReferenceType[ba.SessionTeam], Optional[int]]] = {} self._teams: Optional[List[ReferenceType[ba.SessionTeam]]] = None - self._player_info: Optional[List[Dict[str, Any]]] = None + self._player_info: Optional[List[ba.PlayerInfo]] = None self._lower_is_better: Optional[bool] = None self._score_label: Optional[str] = None self._none_is_winner: Optional[bool] = None @@ -141,7 +141,7 @@ class TeamGameResults: return Lstr(value=str(score[1])) return Lstr(value='-') - def get_player_info(self) -> List[Dict[str, Any]]: + def get_player_info(self) -> List[ba.PlayerInfo]: """Get info about the players represented by the results.""" if not self._game_set: raise RuntimeError("Can't get player-info until game is set.") diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index e6cb6adf..491f4140 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -97,7 +97,7 @@ def sharedobj(name: str) -> Any: # We store these on the current context; whether its an activity or # session. - activity: Optional[ba.Activity] = _ba.getactivity(doraise=False) + activity = _ba.getactivity(doraise=False) if activity is not None: # Grab shared-objs dict. @@ -105,8 +105,8 @@ def sharedobj(name: str) -> Any: # Grab item out of it. try: - return sharedobjs[name] - except Exception: + return sharedobjs[name] # (pylint bug?) pylint: disable=E1136 + except KeyError: pass obj: Any @@ -141,7 +141,7 @@ def sharedobj(name: str) -> Any: "unrecognized shared object (activity context): '" + name + "'") else: - session: Optional[ba.Session] = _ba.getsession(doraise=False) + session = _ba.getsession(doraise=False) if session is not None: # Grab shared-objs dict (creating if necessary). diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index d7a7b371..dc0180c4 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -83,7 +83,7 @@ class ServerCallThread(threading.Thread): self._context = _ba.Context('current') # Save and restore the context we were created from. - activity: Optional[ba.Activity] = _ba.getactivity(doraise=False) + activity = _ba.getactivity(doraise=False) self._activity = weakref.ref( activity) if activity is not None else None diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index bc5c44bb..d4f6a7bf 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -22,6 +22,7 @@ from __future__ import annotations +from dataclasses import dataclass from typing import TYPE_CHECKING, TypeVar, Generic import _ba @@ -35,6 +36,16 @@ PlayerType = TypeVar('PlayerType', bound='ba.Player') TeamType = TypeVar('TeamType', bound='ba.Team') +@dataclass +class PlayerInfo: + """Holds basic info about a player. + + Category: Gameplay Classes + """ + name: str + character: str + + class Player(Generic[TeamType]): """A player in a specific ba.Activity. diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index c84e42ea..30b4f8b7 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -70,10 +70,6 @@ class Session: Be aware this value may be None if a Session does not allow any such selection. - campaign - The ba.Campaign instance this Session represents, or None if - there is no associated Campaign. - use_teams Whether this session groups players into an explicit set of teams. If this is off, a unique team is generated for each @@ -95,7 +91,6 @@ class Session: # Note: even though these are instance vars, we annotate them at the # class level so that docs generation can access their types. - campaign: Optional[ba.Campaign] lobby: ba.Lobby max_players: int min_players: int @@ -161,30 +156,28 @@ class Session: # print('Would set host-session asset-reqs to:', # required_asset_packages) - # Stuff in this section should be removed from this class if possible. + # Init our C++ layer data. self._sessiondata = _ba.register_session(self) + + # Stuff in this section should be removed from this class if possible. self.tournament_id: Optional[str] = None self.sharedobjs: Dict[str, Any] = {} self.have_shown_controls_help_overlay = False - self.campaign = None - self.campaign_state: Dict[str, str] = {} self.teams = [] self.players = [] + self.min_players = min_players + self.max_players = max_players + self._in_set_activity = False self._next_team_id = 0 self._activity_retained: Optional[ba.Activity] = None self._launch_end_session_activity_time: Optional[float] = None self._activity_end_timer: Optional[ba.Timer] = None self._activity_weak = empty_weakref(Activity) - if self._activity_weak() is not None: - raise Exception('Error creating empty activity weak ref.') - self._next_activity: Optional[ba.Activity] = None self.wants_to_end = False self._ending = False - self.min_players = min_players - self.max_players = max_players # Create static teams if we're using them. if self.use_teams: diff --git a/assets/src/ba_data/python/bastd/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py index 048dfa68..78addd43 100644 --- a/assets/src/ba_data/python/bastd/activity/coopjoin.py +++ b/assets/src/ba_data/python/bastd/activity/coopjoin.py @@ -35,17 +35,21 @@ if TYPE_CHECKING: class CoopJoinActivity(JoinActivity): """Join-screen for co-op mode.""" + # We can assume our session is a CoopSession. + session: ba.CoopSession + def __init__(self, settings: Dict[str, Any]): super().__init__(settings) - session = ba.getsession() + session = self.session + assert isinstance(session, ba.CoopSession) # Let's show a list of scores-to-beat for 1 player at least. assert session.campaign is not None level_name_full = (session.campaign.name + ':' + - session.campaign_state['level']) - config_str = ( - '1p' + session.campaign.get_level(session.campaign_state['level']). - get_score_version_string().replace(' ', '_')) + session.campaign_level_name) + config_str = ('1p' + session.campaign.get_level( + session.campaign_level_name).get_score_version_string().replace( + ' ', '_')) _ba.get_scores_to_beat(level_name_full, config_str, ba.WeakCall(self._on_got_scores_to_beat)) @@ -53,9 +57,10 @@ class CoopJoinActivity(JoinActivity): from bastd.actor.controlsguide import ControlsGuide from bastd.actor.text import Text super().on_transition_in() + assert isinstance(self.session, ba.CoopSession) assert self.session.campaign Text(self.session.campaign.get_level( - self.session.campaign_state['level']).displayname, + self.session.campaign_level_name).displayname, scale=1.3, h_attach=Text.HAttach.CENTER, h_align=Text.HAlign.CENTER, @@ -163,8 +168,9 @@ class CoopJoinActivity(JoinActivity): # Now list our remaining achievements for this level. assert self.session.campaign is not None + assert isinstance(self.session, ba.CoopSession) levelname = (self.session.campaign.name + ':' + - self.session.campaign_state['level']) + self.session.campaign_level_name) ts_h_offs = 60 if not ba.app.kiosk_mode: diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 80dfe6e9..4e1bacdb 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -137,7 +137,10 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._tournament_time_remaining_text: Optional[Text] = None self._tournament_time_remaining_text_timer: Optional[ba.Timer] = None - self._player_info = settings['player_info'] + self._player_info: List[ba.PlayerInfo] = settings['player_info'] + assert isinstance(self._player_info, list) + assert (isinstance(i, ba.PlayerInfo) for i in self._player_info) + self._score: Optional[int] = settings['score'] assert isinstance(self._score, (int, type(None))) @@ -633,7 +636,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): ba.pushcall(ba.WeakCall(self._show_fail)) self._name_str = name_str = ', '.join( - [p['name'] for p in self._player_info]) + [p.name for p in self._player_info]) if self._show_friend_scores: self._friends_loading_status = Text( @@ -668,7 +671,10 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): if self._score is not None: our_score: Optional[list] = [ self._score, { - 'players': self._player_info + 'players': [{ + 'name': p.name, + 'character': p.character + } for p in self._player_info] } ] our_high_scores.append(our_score) diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index 6fcb0305..eb354366 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -37,6 +37,8 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): def __init__(self, settings: Dict[str, Any]): super().__init__(settings=settings) + self._winner: ba.SessionTeam = settings['winner'] + assert isinstance(self._winner, ba.SessionTeam) def on_begin(self) -> None: from ba.deprecated import get_resource @@ -80,7 +82,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): i * 0.2, shift_time - (i * 0.150 + 0.150))) ba.timer(i * 0.150 + 0.5, ba.Call(ba.playsound, self._score_display_sound_small)) - scored = (team is self.settings_raw['winner']) + scored = (team is self._winner) delay = 0.2 if scored: delay = 1.2 diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index 984d209d..303beb37 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -999,7 +999,7 @@ class SpazBotSet: """Immediately clear out any bots in the set.""" # Don't do this if the activity is shutting down or dead. - activity: Optional[ba.Activity] = ba.getactivity(doraise=False) + activity = ba.getactivity(doraise=False) if activity is None or activity.expired: return diff --git a/docs/ba_module.md b/docs/ba_module.md index 7ad463ee..d1e9401b 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

      last updated on 2020-05-27 for Ballistica version 1.5.0 build 20030

      +

      last updated on 2020-05-28 for Ballistica version 1.5.0 build 20031

      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!


      @@ -26,6 +26,7 @@
    • ba.Material
    • ba.Node
    • ba.Player
    • +
    • ba.PlayerInfo
    • ba.PlayerRecord
    • ba.ScoreInfo
    • ba.Session
    • @@ -185,6 +186,7 @@

    Exception Classes

    +
    +
    +

    ba.PlayerInfo

    +

    <top level class> +

    +

    Holds basic info about a player.

    + +

    Category: Gameplay Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.PlayerInfo(name: str, character: str)

    +

    @@ -4256,19 +4295,13 @@ Pass 0 or a negative number for no ban time.

    maintaining state between them (players, teams, score tallies, etc).

    Attributes:

    -
    allow_mid_activity_joins, campaign, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    allow_mid_activity_joins

    bool

    Whether players should be allowed to join in the middle of activities.

    -
    -

    campaign

    -

    Optional[ba.Campaign]

    -

    The ba.Campaign instance this Session represents, or None if -there is no associated Campaign.

    -

    lobby

    ba.Lobby

    @@ -5081,7 +5114,7 @@ Results for a completed ba.TeamGameActivity

    get_player_info()

    -

    get_player_info(self) -> List[Dict[str, Any]]

    +

    get_player_info(self) -> List[ba.PlayerInfo]

    Get info about the players represented by the results.

    @@ -5804,17 +5837,17 @@ version of the game are ignored.


    ba.getactivity()

    -

    getactivity(doraise: bool = True) -> ba.Activity

    +

    getactivity(doraise: bool = True) -> <varies>

    -

    Returns the current ba.Activity instance.

    +

    Return the current ba.Activity instance.

    Category: Gameplay Functions

    Note that this is based on context; thus code run in a timer generated in Activity 'foo' will properly return 'foo' here, even if another Activity has since been created or is transitioning in. -If there is no current Activity an Exception is raised, or if doraise is -False then None is returned instead.

    +If there is no current Activity, raises a ba.ActivityNotFoundError. +If doraise is False, None will be returned instead in that case.


    ba.getcollidemodel()

    @@ -5908,7 +5941,7 @@ Category: Gameplay Functions

    ba.getsession()

    -

    getsession(doraise: bool = True) -> ba.Session

    +

    getsession(doraise: bool = True) -> <varies>

    Category: Gameplay Functions

    From c7835388313e2d100a27568aec46a57d938d6839 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 28 May 2020 16:48:55 -0700 Subject: [PATCH 050/417] More type work --- .efrocachemap | 24 +++++++-------- .idea/dictionaries/ericf.xml | 1 + README.md | 4 +-- assets/src/ba_data/python/_ba.py | 3 +- assets/src/ba_data/python/ba/_actor.py | 15 ++++++++-- assets/src/ba_data/python/bastd/actor/bomb.py | 13 ++++---- assets/src/ba_data/python/bastd/actor/flag.py | 15 ++-------- .../ba_data/python/bastd/game/chosenone.py | 30 +++++++++++++------ docs/ba_module.md | 2 +- 9 files changed, 60 insertions(+), 47 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e1ace103..e70c719a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/95/a8/318c6db7a9c94989c601f9388211", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/53/dda3c28a824749358279d01d85a6", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cb/5e/04efb608c6a0d3fc80baee7f2c0e", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/91/74/c92748de53d860aa936f969c4699", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/a0/202236991664bc72a33affee2911", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/1a/7f626564f3659f4cbd00d62cbd5a", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/94/b8/4f2c26af58e4386d58f2de2b8f3f", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8e/f3/40da5e70872c27cb1716a0e7bc10", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a0/a9/9ca7e5a2a62c7198f6dccf29a1e2", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/54/e7/fd4f9d4af81fed229a1fd2d486f1", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/5f/90a09221a6cb5ca24cf2a6b0f4e7", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c2/14/82ced0d7340340cd09a73987c82f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/29/c569224bc159225daed5cabdd517", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/52/a015232b381b5a361e26cc4e33d6", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b5/31/c229f5293e5ec5b3b8feb9308216", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/8c/2b05b2168897862e0eefc0d5ddaa", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/e5/923be95c40b9e7432f941bb98f79", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/3e/f929b7330662fc64f91e9613d6b3", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e9/3a/25571131b13d74f19150e8fdf786", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4f/b3/9627d8ee06297e66f7238fbc4838", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fe/45/5646002baebd720592914c7f1c5b", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f3/ee/10a2c2eaf9783c9abd81141ee5e8", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/7b/e121ed5e35abf9cce71415fdecac", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/16/d7/b53476ad786d0b1636fcf1906578" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 16a51b7c..1586fccd 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1642,6 +1642,7 @@ setbuild setlanguage setmusic + setsticky settingname setversion sgrn diff --git a/README.md b/README.md index bf2b990d..162a1e9d 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,10 @@ The Ballistica project is the foundation for the next generation of [BombSquad]( ### Frequently Asked Questions * **Q: What's with this new name? Is BombSquad getting renamed?** -* A: No, BombSquad is still BombSquad. 'Ballistica' is simply the new name for the engine/app-framework. This way it can also be used for other game/app projects without causing confusion (though that is mostly theoretical at this point). As a modder, the biggest changes you will notice is 'ba' prefixes in the API instead of 'bs' and naming that follows Python PEP8 standards (underscores and lowercase instead of camel-case). So `bs.playSound(mySound)` in the old system might look like `ba.playsound(mysound)` in the new. You may also see the word 'BallisticaCore' show up various places, which in actual releases gets replaced by 'BombSquad'. +* A: No, BombSquad is still BombSquad. 'Ballistica' is simply the new name for the engine/app-framework. This way it can also be used for other game/app projects without causing confusion (though that is mostly theoretical at this point). As a modder, the biggest changes you will notice is 'ba' prefixes in the API instead of 'bs' and naming that follows Python PEP8 standards (underscores and lowercase instead of camel-case). So `bs.playSound(mySound)` in the old system might look like `ba.playsound(my_sound)` in the new. You may also see the word 'BallisticaCore' show up various places, which in actual releases gets replaced by 'BombSquad'. * **Q: Does this mean BombSquad is open source?** * A: Yes and no. All code contained in this repo is MIT licensed and free for use anywhere. This includes game scripts, pipeline tools, etc. Over time I hope to expand this to include at least some of the binary engine sources. Anything not directly contained in this repository, however, even if automatically downloaded by build scripts, is still proprietary and cannot be redistributed without explicit consent. This includes assets and game binaries. So in a nutshell: create and share mods to your heart's content, but please don't distribute your own complete copies of the game without permission. Please email support@froemling.net if you have any questions about this. * **Q: Will my existing BombSquad 1.4.x mods still work?** -* A: No. All mods will need to be explicitly updated to work with the new ballistica apis in 1.5+. This may or may not be a significant amount of work depending on the mod. I would highly suggest tinkering around with some of the new features in 1.5 such as type-safe Python and dynamic assets before attempting to port any old mods, as some things are done significantly differently now. You may also want to consider simply sticking with 1.4 builds for a while longer, especially for server duties, since they will remain fully compatible with clients running 1.5. The new ballistica APIs may be changing significantly for at least a while as the dust settles, but they will be worth switching to in the end, I promise! +* A: Not 'out of the box'. All mods will need to be explicitly updated to work with the new ballistica apis in 1.5+. This may or may not be a significant amount of work depending on the mod. I would highly suggest tinkering around with some of the new features in 1.5 such as type-safe Python and dynamic assets before attempting to port any old mods, as some things are done significantly differently now. You may also want to consider simply sticking with 1.4 builds for a while longer, especially for server duties, since they will remain fully compatible with clients running 1.5. The new ballistica APIs may be changing significantly for at least a while as the dust settles, but they will be worth switching to in the end, I promise! diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 10e4bbe4..796e7e29 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=317793613698101603244532998583646381571 +# SOURCES_HASH=237466057120267570582079835997969754357 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -628,6 +628,7 @@ class Node: hold_position_pressed: bool = False knockout: float = 0.0 invincible: bool = False + stick_to_owner: bool = False damage: int = 0 run: float = 0.0 move_up_down: float = 0.0 diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index cfffb64b..c3e2a8cd 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -23,7 +23,7 @@ from __future__ import annotations import weakref -from typing import TYPE_CHECKING, TypeVar +from typing import TYPE_CHECKING, TypeVar, overload from ba._messages import DieMessage, DeathType, OutOfBoundsMessage, UNHANDLED from ba._error import print_error, print_exception, ActivityNotFoundError @@ -31,6 +31,7 @@ import _ba if TYPE_CHECKING: from typing import Any, Optional + from typing_extensions import Literal import ba @@ -94,7 +95,7 @@ class Actor: def __del__(self) -> None: try: - # Non-expired Actors send themselves a DieMessage when going down. + # Unexpired Actors send themselves a DieMessage when going down. # That way we can treat DieMessage handling as the single # point-of-action for death. if not self.expired: @@ -214,6 +215,16 @@ class Actor: raise ActivityNotFoundError() return activity + # Overloads to convey our exact return type depending on 'doraise' value. + + @overload + def getactivity(self, doraise: Literal[True] = True) -> ba.Activity: + ... + + @overload + def getactivity(self, doraise: Literal[False]) -> Optional[ba.Activity]: + ... + def getactivity(self, doraise: bool = True) -> Optional[ba.Activity]: """Return the ba.Activity this Actor is associated with. diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index cb2e9025..ec6cf25e 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -863,16 +863,14 @@ class Bomb(ba.Actor): self.arm_timer = ba.Timer( 1.25, ba.WeakCall(self.handlemessage, ArmMessage())) - # once we've thrown a sticky bomb we can stick to it.. + # Once we've thrown a sticky bomb we can stick to it. elif self.bomb_type == 'sticky': - def _safesetattr(node: Optional[ba.Node], attr: str, - value: Any) -> None: + def _setsticky(node: ba.Node) -> None: if node: - setattr(node, attr, value) + node.stick_to_owner = True - ba.timer(0.25, - lambda: _safesetattr(self.node, 'stick_to_owner', True)) + ba.timer(0.25, lambda: _setsticky(self.node)) def _handle_splat(self) -> None: node = ba.getcollision().opposingnode @@ -896,8 +894,7 @@ class Bomb(ba.Actor): if self._exploded: return self._exploded = True - activity = self.getactivity() - if activity is not None and self.node: + if self.node: blast = Blast(position=self.node.position, velocity=self.node.velocity, blast_radius=self.blast_radius, diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index e06ea38a..f7df8bd3 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -325,7 +325,6 @@ class Flag(ba.Actor): 1.0, ba.WeakCall(self._hide_score_text)) def handlemessage(self, msg: Any) -> Any: - # pylint: disable=too-many-branches if __debug__: self._handlemessage_sanity_check() if isinstance(msg, ba.DieMessage): @@ -341,24 +340,16 @@ class Flag(ba.Actor): msg.velocity[1], msg.velocity[2], msg.magnitude, msg.velocity_magnitude, msg.radius, 0, msg.force_direction[0], msg.force_direction[1], msg.force_direction[2]) - elif isinstance(msg, ba.OutOfBoundsMessage): - # We just kill ourselves when out-of-bounds.. would we ever not - # want this?.. - self.handlemessage(ba.DieMessage(how=ba.DeathType.FALL)) elif isinstance(msg, ba.PickedUpMessage): self._held_count += 1 if self._held_count == 1 and self._counter is not None: self._counter.text = '' - activity = self.getactivity() - if activity is not None: - activity.handlemessage(FlagPickedUpMessage(self, msg.node)) + self.activity.handlemessage(FlagPickedUpMessage(self, msg.node)) elif isinstance(msg, ba.DroppedMessage): self._held_count -= 1 if self._held_count < 0: - print('Flag held count < 0') + print('Flag held count < 0.') self._held_count = 0 - activity = self.getactivity() - if activity is not None: - activity.handlemessage(FlagDroppedMessage(self, msg.node)) + self.activity.handlemessage(FlagDroppedMessage(self, msg.node)) else: super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 3100dd5c..256ea606 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -152,12 +152,18 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): ba.timer(1.0, call=self._tick, repeat=True) mat = self._reset_region_material = ba.Material() - mat.add_actions(conditions=('they_have_material', - ba.sharedobj('player_material')), - actions=(('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', False), - ('call', 'at_connect', - ba.WeakCall(self._handle_reset_collide)))) + mat.add_actions( + conditions=( + 'they_have_material', + ba.sharedobj('player_material'), + ), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + ba.WeakCall(self._handle_reset_collide)), + ), + ) self._reset_region = ba.newnode('region', attrs={ @@ -177,9 +183,15 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): # If we have a chosen one, ignore these. if self._get_chosen_one_player() is not None: return - player = ba.getcollision().opposingnode.getdelegate( - PlayerSpaz, True).getplayer(Player) - if player is not None and player.is_alive(): + + # Attempt to get a Player controlling a Spaz that we hit. + try: + player = ba.getcollision().opposingnode.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: + return + + if player.is_alive(): self._set_chosen_one_player(player) def _flash_flag_spawn(self) -> None: diff --git a/docs/ba_module.md b/docs/ba_module.md index d1e9401b..844b2a5d 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-28 for Ballistica version 1.5.0 build 20031

    +

    last updated on 2020-05-28 for Ballistica version 1.5.0 build 20032

    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!


    From a44821e03ef3642a95b0c821632d300bed1c52e5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 28 May 2020 23:19:12 -0700 Subject: [PATCH 051/417] More type safety cleanup --- .idea/dictionaries/ericf.xml | 5 + assets/.asset_manifest_public.json | 4 + assets/Makefile | 14 + assets/src/ba_data/python/ba/_activity.py | 3 + assets/src/ba_data/python/ba/_actor.py | 3 +- assets/src/ba_data/python/ba/_analytics.py | 91 +++++++ assets/src/ba_data/python/ba/_gameactivity.py | 251 ++++++------------ assets/src/ba_data/python/ba/_gameutils.py | 11 + assets/src/ba_data/python/ba/_meta.py | 4 +- assets/src/ba_data/python/ba/_teamgame.py | 9 +- assets/src/ba_data/python/bastd/actor/flag.py | 71 +++-- .../src/ba_data/python/bastd/game/assault.py | 2 +- .../python/bastd/game/capturetheflag.py | 2 +- .../ba_data/python/bastd/game/chosenone.py | 2 +- .../src/ba_data/python/bastd/game/conquest.py | 3 +- .../python/bastd/game/easteregghunt.py | 9 +- .../src/ba_data/python/bastd/game/football.py | 17 +- .../src/ba_data/python/bastd/game/keepaway.py | 2 +- .../python/bastd/game/kingofthehill.py | 2 +- .../ba_data/python/bastd/game/runaround.py | 7 +- .../ba_data/python/bastd/game/thelaststand.py | 58 ++-- assets/src/ba_data/python/bastd/gameutils.py | 28 ++ docs/ba_module.md | 35 +-- 23 files changed, 355 insertions(+), 278 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_analytics.py create mode 100644 assets/src/ba_data/python/bastd/gameutils.py diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 1586fccd..4859d5d1 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -438,6 +438,7 @@ diemessages difflib dilateerode + dincrease dingsound dingsoundhigh dirmanifest @@ -1539,6 +1540,8 @@ resample resourcetypeinfo respawn + respawnable + respawned respawnicon responsetype returncode @@ -1689,8 +1692,10 @@ sparx spawner spawners + spawninfo spawnpoints spawnpt + spawnrate spawntype spaz spazappearance diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index fea31d89..24552382 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -6,6 +6,7 @@ "ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc", @@ -61,6 +62,7 @@ "ba_data/python/ba/_activity.py", "ba_data/python/ba/_activitytypes.py", "ba_data/python/ba/_actor.py", + "ba_data/python/ba/_analytics.py", "ba_data/python/ba/_app.py", "ba_data/python/ba/_appconfig.py", "ba_data/python/ba/_appdelegate.py", @@ -124,6 +126,7 @@ "ba_data/python/bastd/__init__.py", "ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc", "ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc", + "ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc", "ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc", "ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc", "ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc", @@ -227,6 +230,7 @@ "ba_data/python/bastd/game/runaround.py", "ba_data/python/bastd/game/targetpractice.py", "ba_data/python/bastd/game/thelaststand.py", + "ba_data/python/bastd/gameutils.py", "ba_data/python/bastd/mainmenu.py", "ba_data/python/bastd/mapdata/__init__.py", "ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc", diff --git a/assets/Makefile b/assets/Makefile index c77bdbb8..4af402bb 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -179,6 +179,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_benchmark.py \ build/ba_data/python/ba/_tournament.py \ build/ba_data/python/ba/_messages.py \ + build/ba_data/python/ba/_analytics.py \ build/ba_data/python/ba/_freeforallsession.py \ build/ba_data/python/ba/_score.py \ build/ba_data/python/ba/_playlist.py \ @@ -200,6 +201,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_nodeactor.py \ build/ba_data/python/ba/_teamgame.py \ build/ba_data/python/ba/ui/__init__.py \ + build/ba_data/python/bastd/gameutils.py \ build/ba_data/python/bastd/mainmenu.py \ build/ba_data/python/bastd/maps.py \ build/ba_data/python/bastd/appdelegate.py \ @@ -407,6 +409,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc \ @@ -428,6 +431,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc \ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc \ @@ -795,6 +799,11 @@ build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_analytics.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_freeforallsession.py @echo Compiling script: $^ @@ -900,6 +909,11 @@ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/gameutils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mainmenu.py @echo Compiling script: $^ diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index fe501643..6088ed89 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -29,6 +29,7 @@ from ba._player import Player from ba._error import print_exception, print_error, SessionTeamNotFoundError from ba._dependency import DependencyComponent from ba._general import Call, verify_object_death +from ba._messages import UNHANDLED import _ba if TYPE_CHECKING: @@ -414,6 +415,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): def handlemessage(self, msg: Any) -> Any: """General message handling; can be passed any message object.""" + del msg # Unused arg. + return UNHANDLED def end(self, results: Any = None, diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index c3e2a8cd..c86a7be1 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -46,7 +46,8 @@ class Actor: Actors act as controllers, combining some number of ba.Nodes, ba.Textures, ba.Sounds, etc. into a high-level cohesive unit. - Some example actors include Bomb, Flag, and Spaz classes in bastd. + Some example actors include the Bomb, Flag, and Spaz classes that + live in the bastd.actor.* modules. One key feature of Actors is that they generally 'die' (killing off or transitioning out their nodes) when the last Python diff --git a/assets/src/ba_data/python/ba/_analytics.py b/assets/src/ba_data/python/ba/_analytics.py new file mode 100644 index 00000000..948629e0 --- /dev/null +++ b/assets/src/ba_data/python/ba/_analytics.py @@ -0,0 +1,91 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Functionality related to analytics.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import _ba + +if TYPE_CHECKING: + pass + + +def game_begin_analytics() -> None: + """Update analytics events for the start of a game.""" + # pylint: disable=too-many-branches + # pylint: disable=cyclic-import + from ba._dualteamsession import DualTeamSession + from ba._freeforallsession import FreeForAllSession + from ba._coopsession import CoopSession + from ba._gameactivity import GameActivity + activity = _ba.getactivity(False) + session = _ba.getsession(False) + + # Fail gracefully if we didn't cleanly get a session and game activity. + if not activity or not session or not isinstance(activity, GameActivity): + return + + if isinstance(session, CoopSession): + campaign = session.campaign + assert campaign is not None + _ba.set_analytics_screen( + 'Coop Game: ' + campaign.name + ' ' + + campaign.get_level(_ba.app.coop_session_args['level']).name) + _ba.increment_analytics_count('Co-op round start') + if len(activity.players) == 1: + _ba.increment_analytics_count('Co-op round start 1 human player') + elif len(activity.players) == 2: + _ba.increment_analytics_count('Co-op round start 2 human players') + elif len(activity.players) == 3: + _ba.increment_analytics_count('Co-op round start 3 human players') + elif len(activity.players) >= 4: + _ba.increment_analytics_count('Co-op round start 4+ human players') + + elif isinstance(session, DualTeamSession): + _ba.set_analytics_screen('Teams Game: ' + activity.get_name()) + _ba.increment_analytics_count('Teams round start') + if len(activity.players) == 1: + _ba.increment_analytics_count('Teams round start 1 human player') + elif 1 < len(activity.players) < 8: + _ba.increment_analytics_count('Teams round start ' + + str(len(activity.players)) + + ' human players') + elif len(activity.players) >= 8: + _ba.increment_analytics_count('Teams round start 8+ human players') + + elif isinstance(session, FreeForAllSession): + _ba.set_analytics_screen('FreeForAll Game: ' + activity.get_name()) + _ba.increment_analytics_count('Free-for-all round start') + if len(activity.players) == 1: + _ba.increment_analytics_count( + 'Free-for-all round start 1 human player') + elif 1 < len(activity.players) < 8: + _ba.increment_analytics_count('Free-for-all round start ' + + str(len(activity.players)) + + ' human players') + elif len(activity.players) >= 8: + _ba.increment_analytics_count( + 'Free-for-all round start 8+ human players') + + # For some analytics tracking on the c layer. + _ba.reset_game_activity_tracking() diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index dad009cd..b2bc28fa 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -29,8 +29,11 @@ from typing import TYPE_CHECKING, TypeVar from ba._activity import Activity from ba._score import ScoreInfo from ba._lang import Lstr -from ba._messages import PlayerDiedMessage +from ba._messages import PlayerDiedMessage, StandMessage, DieMessage, DeathType from ba._error import NotFoundError, print_error, print_exception +from ba._general import Call, WeakCall +from ba._player import PlayerInfo +from ba import _map import _ba if TYPE_CHECKING: @@ -65,6 +68,17 @@ class GameActivity(Activity[PlayerType, TeamType]): # Default get_score_info() will return this if not None. score_info: Optional[ba.ScoreInfo] = None + # Override some defaults. + allow_pausing = True + allow_kick_idle_players = True + + # Whether to show points for kills. + show_kill_points = True + + # If not None, the music type that should play in on_transition_in() + # (unless overridden by the map). + default_music: Optional[ba.MusicType] = None + @classmethod def create_settings_ui( cls, @@ -139,7 +153,7 @@ class GameActivity(Activity[PlayerType, TeamType]): Classes which want to change their description depending on the session can override this method. """ - del sessiontype # unused arg + del sessiontype # Unused arg. return cls.description if cls.description is not None else '' @classmethod @@ -223,8 +237,7 @@ class GameActivity(Activity[PlayerType, TeamType]): implementation; should return a list of map names valid for this game-type for the given ba.Session type. """ - from ba import _map - del sessiontype # unused arg + del sessiontype # Unused arg. return _map.getmaps('melee') @classmethod @@ -234,7 +247,6 @@ class GameActivity(Activity[PlayerType, TeamType]): This is used when viewing game-lists or showing what game is up next in a series. """ - from ba import _map name = cls.get_display_string(config['settings']) # In newer configs, map is in settings; it used to be in the @@ -268,42 +280,16 @@ class GameActivity(Activity[PlayerType, TeamType]): def __init__(self, settings: Dict[str, Any]): """Instantiate the Activity.""" - from ba import _map super().__init__(settings) - # Set some defaults. - self.allow_pausing = True - self.allow_kick_idle_players = True - - # Whether to show points for kills. - self.show_kill_points = True - - # If not None, the music type that should play in on_transition_in() - # (unless overridden by the map). - self.default_music: Optional[ba.MusicType] = None - # Holds some flattened info about the player set at the point # when on_begin() is called. self.initial_player_info: Optional[List[ba.PlayerInfo]] = None # Go ahead and get our map loading. - map_name: str - if 'map' in settings: - map_name = settings['map'] - else: - # If settings doesn't specify a map, pick a random one from the - # list of supported ones. - unowned_maps = _map.get_unowned_maps() - valid_maps: List[str] = [ - m for m in self.get_supported_maps(type(self.session)) - if m not in unowned_maps - ] - if not valid_maps: - _ba.screenmessage(Lstr(resource='noValidMapsErrorText')) - raise Exception('No valid maps') - map_name = valid_maps[random.randrange(len(valid_maps))] + self._map_type = _map.get_map_class(self._calc_map_name(settings)) + self._spawn_sound = _ba.getsound('spawn') - self._map_type = _map.get_map_class(map_name) self._map_type.preload() self._map: Optional[ba.Map] = None self._powerup_drop_timer: Optional[ba.Timer] = None @@ -422,8 +408,8 @@ class GameActivity(Activity[PlayerType, TeamType]): # Make our map. self._map = self._map_type() - # Give our map a chance to override the music - # (for happy-thoughts and other such themed maps). + # Give our map a chance to override the music. + # (for happy-thoughts and other such themed maps) map_music = self._map_type.get_music_type() music = map_music if map_music is not None else self.default_music @@ -470,13 +456,11 @@ class GameActivity(Activity[PlayerType, TeamType]): # pylint: disable=cyclic-import from bastd.ui.continues import ContinuesWindow from ba._gameutils import sharedobj - from ba._general import WeakCall from ba._coopsession import CoopSession from ba._enums import TimeType try: if _ba.get_account_misc_read_val('enableContinues', False): - session = self.session # We only support continuing in non-tournament games. @@ -510,82 +494,21 @@ class GameActivity(Activity[PlayerType, TeamType]): return except Exception: - print_exception('error continuing game') + print_exception('Error handling continues.') self.end_game() - # FIXME: this logic should live in the session classes. - def _game_begin_analytics(self) -> None: - """Update analytics events for the start of the game.""" - # pylint: disable=too-many-branches - from ba._dualteamsession import DualTeamSession - from ba._freeforallsession import FreeForAllSession - from ba._coopsession import CoopSession - session = self.session - if isinstance(session, CoopSession): - campaign = session.campaign - assert campaign is not None - _ba.set_analytics_screen( - 'Coop Game: ' + campaign.name + ' ' + - campaign.get_level(_ba.app.coop_session_args['level']).name) - _ba.increment_analytics_count('Co-op round start') - if len(self.players) == 1: - _ba.increment_analytics_count( - 'Co-op round start 1 human player') - elif len(self.players) == 2: - _ba.increment_analytics_count( - 'Co-op round start 2 human players') - elif len(self.players) == 3: - _ba.increment_analytics_count( - 'Co-op round start 3 human players') - elif len(self.players) >= 4: - _ba.increment_analytics_count( - 'Co-op round start 4+ human players') - elif isinstance(session, DualTeamSession): - _ba.set_analytics_screen('Teams Game: ' + self.get_name()) - _ba.increment_analytics_count('Teams round start') - if len(self.players) == 1: - _ba.increment_analytics_count( - 'Teams round start 1 human player') - elif 1 < len(self.players) < 8: - _ba.increment_analytics_count('Teams round start ' + - str(len(self.players)) + - ' human players') - elif len(self.players) >= 8: - _ba.increment_analytics_count( - 'Teams round start 8+ human players') - elif isinstance(session, FreeForAllSession): - _ba.set_analytics_screen('FreeForAll Game: ' + self.get_name()) - _ba.increment_analytics_count('Free-for-all round start') - if len(self.players) == 1: - _ba.increment_analytics_count( - 'Free-for-all round start 1 human player') - elif 1 < len(self.players) < 8: - _ba.increment_analytics_count('Free-for-all round start ' + - str(len(self.players)) + - ' human players') - elif len(self.players) >= 8: - _ba.increment_analytics_count( - 'Free-for-all round start 8+ human players') - - # For some analytics tracking on the c layer. - _ba.reset_game_activity_tracking() - def on_begin(self) -> None: - from ba._general import WeakCall - from ba._player import PlayerInfo + from ba._analytics import game_begin_analytics super().on_begin() - try: - self._game_begin_analytics() - except Exception: - print_exception('error in game-begin-analytics') + game_begin_analytics() # We don't do this in on_transition_in because it may depend on # players/teams which aren't available until now. - _ba.timer(0.001, WeakCall(self.show_scoreboard_info)) - _ba.timer(1.0, WeakCall(self.show_info)) - _ba.timer(2.5, WeakCall(self._show_tip)) + _ba.timer(0.001, self._show_scoreboard_info) + _ba.timer(1.0, self._show_info) + _ba.timer(2.5, self._show_tip) # Store some basic info about players present at start time. self.initial_player_info = [ @@ -600,7 +523,6 @@ class GameActivity(Activity[PlayerType, TeamType]): # If this is a tournament, query info about it such as how much # time is left. tournament_id = self.session.tournament_id - if tournament_id is not None: _ba.tournament_query( args={ @@ -628,9 +550,6 @@ class GameActivity(Activity[PlayerType, TeamType]): self.spawn_player(player) def on_player_leave(self, player: PlayerType) -> None: - from ba._general import Call - from ba._messages import DieMessage, DeathType - super().on_player_leave(player) # If the player has an actor, send it a deferred die message. @@ -669,8 +588,10 @@ class GameActivity(Activity[PlayerType, TeamType]): victim_player=player, importance=importance, showpoints=self.show_kill_points) + return None + return super().handlemessage(msg) - def show_scoreboard_info(self) -> None: + def _show_scoreboard_info(self) -> None: """Create the game info display. This is the thing in the top left corner showing the name @@ -682,8 +603,8 @@ class GameActivity(Activity[PlayerType, TeamType]): from ba._nodeactor import NodeActor sb_name = self.get_instance_scoreboard_display_string() - # the description can be either a string or a sequence with args - # to swap in post-translation + # The description can be either a string or a sequence with args + # to swap in post-translation. sb_desc_in = self.get_instance_description_short() sb_desc_l: Sequence if isinstance(sb_desc_in, str): @@ -754,10 +675,9 @@ class GameActivity(Activity[PlayerType, TeamType]): 1.0: 1.0 }) - def show_info(self) -> None: + def _show_info(self) -> None: """Show the game description.""" from ba._gameutils import animate - from ba._general import Call from bastd.actor.zoomtext import ZoomText name = self.get_instance_display_string() ZoomText(name, @@ -786,7 +706,7 @@ class GameActivity(Activity[PlayerType, TeamType]): translation = Lstr(translate=('gameDescriptions', desc_l[0]), subs=subs) - # do some standard filters (epic mode, etc) + # Do some standard filters (epic mode, etc). if self.settings_raw.get('Epic Mode', False): translation = Lstr(resource='epicDescriptionFilterText', subs=[('${DESCRIPTION}', translation)]) @@ -822,7 +742,8 @@ class GameActivity(Activity[PlayerType, TeamType]): # pylint: disable=too-many-locals from ba._gameutils import animate from ba._enums import SpecialChar - # if there's any tips left on the list, display one.. + + # If there's any tips left on the list, display one. if self.tips: tip = self.tips.pop(random.randrange(len(self.tips))) tip_title = Lstr(value='${A}:', @@ -837,7 +758,7 @@ class GameActivity(Activity[PlayerType, TeamType]): tip = tip['tip'] assert isinstance(tip, str) - # a few subs.. + # A few substitutions... tip_lstr = Lstr(translate=('tips', tip), subs=[('${PICKUP}', _ba.charstr(SpecialChar.TOP_BUTTON))]) @@ -947,26 +868,6 @@ class GameActivity(Activity[PlayerType, TeamType]): print('WARNING: default end_game() implementation called;' ' your game should override this.') - def spawn_player_if_exists(self, player: PlayerType) -> None: - """ - A utility method which calls self.spawn_player() *only* if the - ba.Player provided still exists; handy for use in timers and whatnot. - - There is no need to override this; just override spawn_player(). - """ - if player: - self.spawn_player(player) - - def spawn_player(self, player: PlayerType) -> ba.Actor: - """Spawn *something* for the provided ba.Player. - - The default implementation simply calls spawn_player_spaz(). - """ - if not player: - raise TypeError('spawn_player() called for nonexistent player') - - return self.spawn_player_spaz(player) - def respawn_player(self, player: PlayerType, respawn_time: Optional[float] = None) -> None: @@ -992,21 +893,39 @@ class GameActivity(Activity[PlayerType, TeamType]): else: respawn_time = 7.0 - # If this standard setting is present, factor it in + # If this standard setting is present, factor it in. if 'Respawn Times' in self.settings_raw: respawn_time *= self.settings_raw['Respawn Times'] - # we want whole seconds + # We want whole seconds. assert respawn_time is not None respawn_time = round(max(1.0, respawn_time), 0) if player.actor and not self.has_ended(): - from ba._general import WeakCall from bastd.actor.respawnicon import RespawnIcon player.gamedata['respawn_timer'] = _ba.Timer( respawn_time, WeakCall(self.spawn_player_if_exists, player)) player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) + def spawn_player_if_exists(self, player: PlayerType) -> None: + """ + A utility method which calls self.spawn_player() *only* if the + ba.Player provided still exists; handy for use in timers and whatnot. + + There is no need to override this; just override spawn_player(). + """ + if player: + self.spawn_player(player) + + def spawn_player(self, player: PlayerType) -> ba.Actor: + """Spawn *something* for the provided ba.Player. + + The default implementation simply calls spawn_player_spaz(). + """ + assert player # Dead references should never be passed as args. + + return self.spawn_player_spaz(player) + def spawn_player_spaz(self, player: PlayerType, position: Sequence[float] = (0, 0, 0), @@ -1015,7 +934,6 @@ class GameActivity(Activity[PlayerType, TeamType]): # pylint: disable=too-many-locals # pylint: disable=cyclic-import from ba import _math - from ba import _messages from ba._gameutils import animate from ba._coopsession import CoopSession from bastd.actor.playerspaz import PlayerSpaz @@ -1051,7 +969,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # Move to the stand position and add a flash of light. spaz.handlemessage( - _messages.StandMessage( + StandMessage( position, angle if angle is not None else random.uniform(0, 360))) _ba.playsound(self._spawn_sound, 1, position=spaz.node.position) @@ -1061,30 +979,14 @@ class GameActivity(Activity[PlayerType, TeamType]): _ba.timer(0.5, light.delete) return spaz - def project_flag_stand(self, pos: Sequence[float]) -> None: - """Project a flag-stand onto the ground at the given position. - - Useful for games such as capture-the-flag to show where a - movable flag originated from. - """ - from ba._general import WeakCall - - # Need to do this in a timer for it to work.. need to look into that. - # (might not still be the case?...) - _ba.pushcall(WeakCall(self._project_flag_stand, pos[:3])) - - def _project_flag_stand(self, pos: Sequence[float]) -> None: - _ba.emitfx(position=pos, emit_type='flag_stand') - def setup_standard_powerup_drops(self, enable_tnt: bool = True) -> None: """Create standard powerup drops for the current map.""" # pylint: disable=cyclic-import - from bastd.actor import powerupbox - from ba import _general - self._powerup_drop_timer = _ba.Timer( - powerupbox.DEFAULT_POWERUP_INTERVAL, - _general.WeakCall(self._standard_drop_powerups), - repeat=True) + from bastd.actor.powerupbox import DEFAULT_POWERUP_INTERVAL + self._powerup_drop_timer = _ba.Timer(DEFAULT_POWERUP_INTERVAL, + WeakCall( + self._standard_drop_powerups), + repeat=True) self._standard_drop_powerups() if enable_tnt: self._tnt_spawners = {} @@ -1100,19 +1002,16 @@ class GameActivity(Activity[PlayerType, TeamType]): def _standard_drop_powerups(self) -> None: """Standard powerup drop.""" - from ba import _general # Drop one powerup per point. points = self.map.powerup_spawn_points for i in range(len(points)): - _ba.timer(i * 0.4, _general.WeakCall(self._standard_drop_powerup, - i)) + _ba.timer(i * 0.4, WeakCall(self._standard_drop_powerup, i)) def _setup_standard_tnt_drops(self) -> None: """Standard tnt drop.""" # pylint: disable=cyclic-import from bastd.actor.bomb import TNTSpawner - for i, point in enumerate(self.map.tnt_points): assert self._tnt_spawners is not None if self._tnt_spawners.get(i) is None: @@ -1126,7 +1025,6 @@ class GameActivity(Activity[PlayerType, TeamType]): If the time-limit expires, end_game() will be called. """ from ba._gameutils import sharedobj - from ba._general import WeakCall from ba._nodeactor import NodeActor if duration <= 0.0: return @@ -1200,7 +1098,6 @@ class GameActivity(Activity[PlayerType, TeamType]): This will be displayed at the top of the screen. If the time-limit expires, end_game() will be called. """ - from ba._general import WeakCall from ba._nodeactor import NodeActor from ba._enums import TimeType if duration <= 0.0: @@ -1337,3 +1234,21 @@ class GameActivity(Activity[PlayerType, TeamType]): maxwidth=800, trail=trail, color=color).autoretain() + + def _calc_map_name(self, settings: Dict[str, Any]) -> str: + map_name: str + if 'map' in settings: + map_name = settings['map'] + else: + # If settings doesn't specify a map, pick a random one from the + # list of supported ones. + unowned_maps = _map.get_unowned_maps() + valid_maps: List[str] = [ + m for m in self.get_supported_maps(type(self.session)) + if m not in unowned_maps + ] + if not valid_maps: + _ba.screenmessage(Lstr(resource='noValidMapsErrorText')) + raise Exception('No valid maps') + map_name = valid_maps[random.randrange(len(valid_maps))] + return map_name diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 491f4140..7391925d 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -19,9 +19,11 @@ # SOFTWARE. # ----------------------------------------------------------------------------- """Utility functionality pertaining to gameplay.""" + from __future__ import annotations from typing import TYPE_CHECKING +# from typing_extensions import Protocol import _ba from ba._enums import TimeType, TimeFormat, SpecialChar @@ -39,6 +41,15 @@ TROPHY_CHARS = { '4': SpecialChar.TROPHY4 } +# class Respawnable(Protocol): +# """A Protocol for objects able to be respawned. + +# Category: Protocols +# """ + +# respawn_timer: Optional[ba.Timer] +# respawn_icon: Optional[RespawnIcon] + def get_trophy_string(trophy_id: str) -> str: """Given a trophy id, returns a string to visualize it.""" diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index e25de5bb..1de050db 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -271,7 +271,7 @@ class DirectoryScan: cbits = lbits[1].split('(') if len(cbits) > 1 and cbits[0].isidentifier(): classname = cbits[0] - break # success! + break # Success! if classname is None: self.results.warnings += ( 'Warning: ' + str(subpath) + ': class definition not found' @@ -291,7 +291,7 @@ class DirectoryScan: and l[1] == 'require' and l[2] == 'api' and l[3].isdigit() ] - # we're successful if we find exactly one properly formatted line + # We're successful if we find exactly one properly formatted line. if len(lines) == 1: return int(lines[0][3]) diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index 128b959b..47c86520 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -59,14 +59,13 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): or issubclass(sessiontype, FreeForAllSession)) def __init__(self, settings: Dict[str, Any]): - super().__init__(settings) - # By default we don't show kill-points in free-for-all. + # By default we don't show kill-points in free-for-all sessions. # (there's usually some activity-specific score and we don't # wanna confuse things) - if isinstance(_ba.getsession(), FreeForAllSession): - self._show_kill_points = False + if isinstance(self.session, FreeForAllSession): + self.show_kill_points = False def on_transition_in(self) -> None: # pylint: disable=cyclic-import @@ -78,7 +77,6 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): # (unless we're being run in co-op mode, in which case we leave # it up to them) if not isinstance(self.session, CoopSession): - # FIXME: Need an elegant way to store on session. if not self.session.have_shown_controls_help_overlay: delay = 4.0 lifespan = 10.0 @@ -151,6 +149,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): if not isinstance(session, CoopSession): do_announce = not self.has_ended() super().end(results, delay=2.0 + announce_delay, force=force) + # Need to do this *after* end end call so that results is valid. assert isinstance(results, TeamGameResults) if do_announce and isinstance(session, MultiTeamSession): diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index f7df8bd3..59515af0 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -67,41 +67,58 @@ class FlagFactory: self.flagmaterial = ba.Material() self.flagmaterial.add_actions( - conditions=(('we_are_younger_than', 100), - 'and', ('they_have_material', - ba.sharedobj('object_material'))), - actions=('modify_node_collision', 'collide', False)) + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', ba.sharedobj('object_material')), + ), + actions=('modify_node_collision', 'collide', False), + ) self.flagmaterial.add_actions( - conditions=('they_have_material', - ba.sharedobj('footing_material')), - actions=(('message', 'our_node', 'at_connect', 'footing', 1), - ('message', 'our_node', 'at_disconnect', 'footing', -1))) + conditions=( + 'they_have_material', + ba.sharedobj('footing_material'), + ), + actions=( + ('message', 'our_node', 'at_connect', 'footing', 1), + ('message', 'our_node', 'at_disconnect', 'footing', -1), + ), + ) self.impact_sound = ba.getsound('metalHit') self.skid_sound = ba.getsound('metalSkid') self.flagmaterial.add_actions( - conditions=('they_have_material', - ba.sharedobj('footing_material')), - actions=(('impact_sound', self.impact_sound, 2, 5), - ('skid_sound', self.skid_sound, 2, 5))) + conditions=( + 'they_have_material', + ba.sharedobj('footing_material'), + ), + actions=( + ('impact_sound', self.impact_sound, 2, 5), + ('skid_sound', self.skid_sound, 2, 5), + ), + ) self.no_hit_material = ba.Material() self.no_hit_material.add_actions( - conditions=(('they_have_material', - ba.sharedobj('pickup_material')), - 'or', ('they_have_material', - ba.sharedobj('attack_material'))), - actions=('modify_part_collision', 'collide', False)) + conditions=( + ('they_have_material', ba.sharedobj('pickup_material')), + 'or', + ('they_have_material', ba.sharedobj('attack_material')), + ), + actions=('modify_part_collision', 'collide', False), + ) # We also don't want anything moving it. self.no_hit_material.add_actions( - conditions=(('they_have_material', - ba.sharedobj('object_material')), 'or', - ('they_dont_have_material', - ba.sharedobj('footing_material'))), + conditions=( + ('they_have_material', ba.sharedobj('object_material')), + 'or', + ('they_dont_have_material', ba.sharedobj('footing_material')), + ), actions=(('modify_part_collision', 'collide', False), - ('modify_part_collision', 'physical', False))) + ('modify_part_collision', 'physical', False)), + ) self.flag_texture = ba.gettexture('flagColor') @@ -353,3 +370,13 @@ class Flag(ba.Actor): self.activity.handlemessage(FlagDroppedMessage(self, msg.node)) else: super().handlemessage(msg) + + @staticmethod + def project_stand(pos: Sequence[float]) -> None: + """Project a flag-stand onto the ground at the given position. + + Useful for games such as capture-the-flag to show where a + movable flag originated from. + """ + assert len(pos) == 3 + ba.emitfx(position=pos, emit_type='flag_stand') diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 0020bb0c..062a030e 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -121,7 +121,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): 'radius': 0.1, 'color': sessionteam.color }) - self.project_flag_stand(base_pos) + Flag.project_stand(base_pos) flag = Flag(touchable=False, position=base_pos, color=sessionteam.color) diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 43ff82e4..711672d9 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -190,7 +190,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): # Create our team instance and its initial values. base_pos = self.map.get_flag_position(sessionteam.id) - self.project_flag_stand(base_pos) + Flag.project_stand(base_pos) ba.newnode('light', attrs={ diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 256ea606..f65d12c8 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -145,7 +145,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) - self.project_flag_stand(self._flag_spawn_pos) + Flag.project_stand(self._flag_spawn_pos) self._set_chosen_one_player(None) pos = self._flag_spawn_pos diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 0f1e51e9..c6ba9c4d 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -167,8 +167,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): touchable=False, materials=[self._extraflagmat]) self._flags.append(flag) - # FIXME: Move next few lines to the flag class. - self.project_flag_stand(point) + Flag.project_stand(point) flag.light = ba.newnode('light', owner=flag.node, attrs={ diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 503d4196..244e79d4 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -198,15 +198,11 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): # Respawn dead players. if isinstance(msg, ba.PlayerDiedMessage): - # Augment standard behavior. super().handlemessage(msg) - player = msg.getplayer(Player) - if not player: - return - self.stats.player_was_killed(player) # Respawn them shortly. + player = msg.getplayer(Player) assert self.initial_player_info is not None respawn_time = 2.0 + len(self.initial_player_info) * 1.0 player.respawn_timer = ba.Timer( @@ -226,7 +222,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): pos[2] + random.uniform(-spread, spread)))) else: # Default handler. - super().handlemessage(msg) + return super().handlemessage(msg) + return None def _update_scoreboard(self) -> None: for team in self.teams: diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 5ded7ace..e0f5d7b0 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -798,21 +798,17 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: """ handle high-level game messages """ if isinstance(msg, ba.PlayerDiedMessage): - - # Respawn dead players. - player = msg.getplayer(Player) - self.stats.player_was_killed(player) - assert self.initial_player_info is not None - respawn_time = 2.0 + len(self.initial_player_info) * 1.0 + # Augment standard behavior. + super().handlemessage(msg) # Respawn them shortly. + player = msg.getplayer(Player) + assert self.initial_player_info is not None + respawn_time = 2.0 + len(self.initial_player_info) * 1.0 player.respawn_timer = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) player.respawn_icon = RespawnIcon(player, respawn_time) - # Augment standard behavior. - super().handlemessage(msg) - elif isinstance(msg, SpazBotDiedMessage): # Every time a bad guy dies, spawn a new one. @@ -848,7 +844,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): loop=True) ba.timer(3.0, self._flag_respawn_light.node.delete) else: - super().handlemessage(msg) + return super().handlemessage(msg) + return None def _handle_player_dropped_bomb(self, player: Spaz, bomb: ba.Actor) -> None: diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index e0d065dc..fae6bada 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -138,7 +138,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): self._spawn_flag() self._update_timer = ba.Timer(1.0, call=self._tick, repeat=True) self._update_flag_state() - self.project_flag_stand(self._flag_spawn_pos) + Flag.project_stand(self._flag_spawn_pos) def _tick(self) -> None: self._update_flag_state() diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 4b11464c..b0dfe47c 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -150,7 +150,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): self._flag_pos = self.map.get_flag_position(None) ba.timer(1.0, self._tick, repeat=True) self._flag_state = FlagState.NEW - self.project_flag_stand(self._flag_pos) + Flag.project_stand(self._flag_pos) self._flag = Flag(position=self._flag_pos, touchable=False, diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index f134816a..7f6ca1d7 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -1108,13 +1108,14 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._score += msg.score self._update_scores() - # Respawn dead players. elif isinstance(msg, ba.PlayerDiedMessage): + # Augment standard behavior. + super().handlemessage(msg) + self._a_player_has_been_killed = True - player = msg.getplayer(Player) - self.stats.player_was_killed(player) # Respawn them shortly. + player = msg.getplayer(Player) assert self.initial_player_info is not None respawn_time = 2.0 + len(self.initial_player_info) * 1.0 player.respawn_timer = ba.Timer( diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index ae9a1a9a..20c4b626 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -23,6 +23,7 @@ from __future__ import annotations import random +from dataclasses import dataclass from typing import TYPE_CHECKING import ba @@ -42,6 +43,14 @@ if TYPE_CHECKING: from bastd.actor.spazbot import SpazBot +@dataclass +class SpawnInfo: + """Spawning info for a particular bot type.""" + spawnrate: float + increase: float + dincrease: float + + class Player(ba.Player['Team']): """Our player type for this game.""" @@ -78,7 +87,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): self._tntspawnpos = (0, 5.5, -6) self._powerup_center = (0, 7, -4.14) self._powerup_spread = (7, 2) - self._preset = self.settings_raw.get('preset', 'default') + self._preset = str(settings.get('preset', 'default')) self._excludepowerups: List[str] = [] self._scoreboard: Optional[Scoreboard] = None self._score = 0 @@ -90,21 +99,22 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): self._bot_update_timer: Optional[ba.Timer] = None self._powerup_drop_timer = None - # For each bot type: [spawn-rate, increase, d_increase] + # For each bot type: [spawnrate, increase, d_increase] self._bot_spawn_types = { - BomberBot: [1.00, 0.00, 0.000], - BomberBotPro: [0.00, 0.05, 0.001], - BomberBotProShielded: [0.00, 0.02, 0.002], - BrawlerBot: [1.00, 0.00, 0.000], - BrawlerBotPro: [0.00, 0.05, 0.001], - BrawlerBotProShielded: [0.00, 0.02, 0.002], - TriggerBot: [0.30, 0.00, 0.000], - TriggerBotPro: [0.00, 0.05, 0.001], - TriggerBotProShielded: [0.00, 0.02, 0.002], - ChargerBot: [0.30, 0.05, 0.000], - StickyBot: [0.10, 0.03, 0.001], - ExplodeyBot: [0.05, 0.02, 0.002] - } # yapf: disable + BomberBot: SpawnInfo(1.00, 0.00, 0.000), + BomberBotPro: SpawnInfo(0.00, 0.05, 0.001), + BomberBotProShielded: SpawnInfo(0.00, 0.02, 0.002), + BrawlerBot: SpawnInfo(1.00, 0.00, 0.000), + BrawlerBotPro: SpawnInfo(0.00, 0.05, 0.001), + BrawlerBotProShielded: SpawnInfo(0.00, 0.02, 0.002), + TriggerBot: SpawnInfo(0.30, 0.00, 0.000), + TriggerBotPro: SpawnInfo(0.00, 0.05, 0.001), + TriggerBotProShielded: SpawnInfo(0.00, 0.02, 0.002), + ChargerBot: SpawnInfo(0.30, 0.05, 0.000), + StickyBot: SpawnInfo(0.10, 0.03, 0.001), + ExplodeyBot: SpawnInfo(0.05, 0.02, 0.002) + } # yapf: disable + def on_transition_in(self) -> None: super().on_transition_in() @@ -121,8 +131,6 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): ba.timer(0.001, ba.WeakCall(self._start_bot_updates)) self.setup_low_life_warning_sound() self._update_scores() - - # Our TNT spawner (if applicable). self._tntspawner = TNTSpawner(position=self._tntspawnpos, respawn_time=10.0) @@ -225,17 +233,17 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): # Normalize our bot type total and find a random number within that. total = 0.0 - for spawntype in self._bot_spawn_types.items(): - total += spawntype[1][0] + for spawninfo in self._bot_spawn_types.values(): + total += spawninfo.spawnrate randval = random.random() * total # Now go back through and see where this value falls. total = 0 bottype: Optional[Type[SpazBot]] = None - for spawntype in self._bot_spawn_types.items(): - total += spawntype[1][0] + for spawntype, spawninfo in self._bot_spawn_types.items(): + total += spawninfo.spawnrate if randval <= total: - bottype = spawntype[0] + bottype = spawntype break spawn_time = 1.0 assert bottype is not None @@ -243,9 +251,9 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): # After every spawn we adjust our ratios slightly to get more # difficult. - for spawntype in self._bot_spawn_types.items(): - spawntype[1][0] += spawntype[1][1] # incr spawn rate - spawntype[1][1] += spawntype[1][2] # incr spawn rate incr rate + for spawninfo in self._bot_spawn_types.values(): + spawninfo.spawnrate += spawninfo.increase + spawninfo.increase += spawninfo.dincrease def _update_scores(self) -> None: score = self._score diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py new file mode 100644 index 00000000..17cf39a8 --- /dev/null +++ b/assets/src/ba_data/python/bastd/gameutils.py @@ -0,0 +1,28 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Various utilities useful for gameplay.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import Sequence diff --git a/docs/ba_module.md b/docs/ba_module.md index 844b2a5d..dbdf5458 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-28 for Ballistica version 1.5.0 build 20032

    +

    last updated on 2020-05-28 for Ballistica version 1.5.0 build 20033

    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!


    @@ -604,7 +604,8 @@ is a convenient way to access this same functionality.

    Actors act as controllers, combining some number of ba.Nodes, ba.Textures, ba.Sounds, etc. into a high-level cohesive unit.

    -

    Some example actors include Bomb, Flag, and Spaz classes in bastd.

    +

    Some example actors include the Bomb, Flag, and Spaz classes that + live in the bastd.actor.* modules.

    One key feature of Actors is that they generally 'die' (killing off or transitioning out their nodes) when the last Python @@ -1584,7 +1585,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -2143,7 +2144,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), set_immediate_end(), transition_in(), transition_out()

    Methods Defined or Overridden:

    -
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), project_flag_stand(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    +
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    ba.GameActivity(settings: Dict[str, Any])

    @@ -2455,15 +2456,6 @@ start playing music, etc. It does not yet have access to players or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called.

    -
    -

    project_flag_stand()

    -

    project_flag_stand(self, pos: Sequence[float]) -> None

    - -

    Project a flag-stand onto the ground at the given position.

    - -

    Useful for games such as capture-the-flag to show where a -movable flag originated from.

    -

    respawn_player()

    respawn_player(self, player: PlayerType, respawn_time: Optional[float] = None) -> None

    @@ -2490,21 +2482,6 @@ duration in seconds. This will be displayed at the top of the screen. If the time-limit expires, end_game() will be called.

    -
    -

    show_info()

    -

    show_info(self) -> None

    - -

    Show the game description.

    - -
    -

    show_scoreboard_info()

    -

    show_scoreboard_info(self) -> None

    - -

    Create the game info display.

    - -

    This is the thing in the top left corner showing the name -and short description of the game.

    -

    show_zoom_message()

    show_zoom_message(self, message: ba.Lstr, color: Sequence[float] = (0.9, 0.4, 0.0), scale: float = 0.8, duration: float = 2.0, trail: bool = False) -> None

    @@ -5028,7 +5005,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), project_flag_stand(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_info(), show_scoreboard_info(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    From 4e15d72e4f669e40969e4000373c11ceb20be178 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 29 May 2020 13:59:10 -0700 Subject: [PATCH 052/417] Moved shared-objects to bastd --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 3 + assets/src/ba_data/python/_ba.py | 21 +- assets/src/ba_data/python/ba/__init__.py | 5 +- assets/src/ba_data/python/ba/_activity.py | 105 ++++----- assets/src/ba_data/python/ba/_app.py | 5 +- assets/src/ba_data/python/ba/_coopgame.py | 4 +- assets/src/ba_data/python/ba/_gameactivity.py | 10 +- assets/src/ba_data/python/ba/_gameutils.py | 147 ++----------- assets/src/ba_data/python/ba/_map.py | 2 +- assets/src/ba_data/python/ba/_music.py | 2 +- assets/src/ba_data/python/ba/_player.py | 10 + assets/src/ba_data/python/ba/_session.py | 41 ++-- assets/src/ba_data/python/bastd/actor/bomb.py | 207 +++++++++++------- assets/src/ba_data/python/bastd/actor/flag.py | 23 +- .../python/bastd/actor/onscreencountdown.py | 5 +- .../python/bastd/actor/onscreentimer.py | 3 +- .../ba_data/python/bastd/actor/powerupbox.py | 25 ++- assets/src/ba_data/python/bastd/actor/spaz.py | 18 +- .../ba_data/python/bastd/actor/spazfactory.py | 97 ++++---- .../src/ba_data/python/bastd/game/assault.py | 4 +- .../ba_data/python/bastd/game/chosenone.py | 7 +- .../src/ba_data/python/bastd/game/conquest.py | 4 +- .../python/bastd/game/easteregghunt.py | 7 +- .../src/ba_data/python/bastd/game/football.py | 4 +- .../src/ba_data/python/bastd/game/hockey.py | 33 +-- .../python/bastd/game/kingofthehill.py | 10 +- assets/src/ba_data/python/bastd/game/race.py | 14 +- .../ba_data/python/bastd/game/runaround.py | 4 +- .../python/bastd/game/targetpractice.py | 4 +- assets/src/ba_data/python/bastd/gameutils.py | 139 +++++++++++- assets/src/ba_data/python/bastd/mainmenu.py | 2 +- assets/src/ba_data/python/bastd/maps.py | 144 ++++++------ docs/ba_module.md | 139 +++++++----- 34 files changed, 724 insertions(+), 548 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e70c719a..46f06447 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/29/c569224bc159225daed5cabdd517", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/52/a015232b381b5a361e26cc4e33d6", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b5/31/c229f5293e5ec5b3b8feb9308216", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/8c/2b05b2168897862e0eefc0d5ddaa", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/e5/923be95c40b9e7432f941bb98f79", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/3e/f929b7330662fc64f91e9613d6b3", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e9/3a/25571131b13d74f19150e8fdf786", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4f/b3/9627d8ee06297e66f7238fbc4838", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fe/45/5646002baebd720592914c7f1c5b", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f3/ee/10a2c2eaf9783c9abd81141ee5e8", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/7b/e121ed5e35abf9cce71415fdecac", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/16/d7/b53476ad786d0b1636fcf1906578" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8d/c2/9fd3ab19a28b05160f818f787115", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/67/25/34c42457f20c9d87d538f4f69320", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/3d/39326060f1a1df1b18070d75ade8", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/b7/d63ab7e13f1b9d931b83ef652262", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/45/f4d0bbe6dfa0286b1faaad5d4c0e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a8/2b/251dcadd37ae0d2c08a0f3bb683d", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/1a/b80f37d9802d40e625b2df3696b1", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/46/fd/6400f9eba88a419487f5d3732e54", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7d/6a/3dc3c77c340471c0a7b79bf077a4", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/97/5d/824c5c71f61d871c904c61fabc56", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/91/92/1f309a3edf4b4aa595ea83472e7a", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d5/3c/fefdeed4e8048332724167fe1442" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 4859d5d1..9ab6b481 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -186,6 +186,7 @@ bname bndl boffs + bombfactory bombsquad bombsquadcb bombsquadgame @@ -1637,6 +1638,7 @@ sessionclass sessiondata sessionglobals + sessionglobalsnode sessionname sessionplayer sessionteam @@ -1655,6 +1657,7 @@ sharedobjs shiftdelay shiftposition + shobs shortname shouldn showpoints diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 796e7e29..942dc9d2 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=237466057120267570582079835997969754357 +# SOURCES_HASH=214732868903831008614942145147141302125 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -527,7 +527,7 @@ class Material: # example 3: play some sounds when we're contacting the ground: m = ba.Material() m.add_actions(conditions=('they_have_material', - ba.sharedobj('footing_material')), + shared.footing_material), actions=(('impact_sound', ba.getsound('metalHit'), 2, 5), ('skid_sound', ba.getsound('metalSkid'), 2, 5))) @@ -635,6 +635,10 @@ class Node: move_left_right: float = 0.0 curse_death_time: int = 0 boxing_gloves: bool = False + use_fixed_vr_overlay: bool = False + allow_kick_idle_players: bool = False + music_continuous: bool = False + music_count: int = 0 hurt: float = 0.0 always_show_health_bar: bool = False mini_billboard_1_texture: Optional[ba.Texture] = None @@ -648,7 +652,20 @@ class Node: mini_billboard_3_end_time: int = 0 boxing_gloves_flashing: bool = False dead: bool = False + floor_reflection: bool = False + debris_friction: float = 0.0 + debris_kill_height: float = 0.0 + vr_near_clip: float = 0.0 + shadow_ortho: bool = False + happy_thoughts_mode: bool = False + shadow_offset: Sequence[float] = (0.0, 0.0) + paused: bool = False + time: int = 0 + ambient_color: Sequence[float] = (1.0, 1.0, 1.0) + camera_mode: str = 'rotate' frozen: bool = False + area_of_interest_bounds: Sequence[float] = (-1, -1, -1, 1, 1, 1) + shadow_range: Sequence[float] = (0, 0, 0, 0) counter_text: str = '' counter_texture: Optional[ba.Texture] = None shattered: int = 0 diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 6b79f6e0..3576a2cd 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -39,7 +39,8 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, open_url, widget) from ba._activity import Activity from ba._actor import Actor -from ba._player import PlayerInfo, Player, playercast, playercast_o +from ba._player import (PlayerInfo, Player, playercast, playercast_o, + StandLocation) from ba._nodeactor import NodeActor from ba._app import App from ba._coopgame import CoopGameActivity @@ -71,7 +72,7 @@ from ba._appdelegate import AppDelegate from ba._apputils import is_browser_likely_available from ba._campaign import Campaign from ba._gameutils import (animate, animate_array, show_damage_count, - sharedobj, timestring, cameraflash) + timestring, cameraflash) from ba._general import (WeakCall, Call, existing, Existable, verify_object_death) from ba._level import Level diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 6088ed89..e46bb06d 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -26,7 +26,8 @@ from typing import TYPE_CHECKING, Generic, TypeVar from ba._team import Team from ba._player import Player -from ba._error import print_exception, print_error, SessionTeamNotFoundError +from ba._error import (print_exception, SessionTeamNotFoundError, + NodeNotFoundError) from ba._dependency import DependencyComponent from ba._general import Call, verify_object_death from ba._messages import UNHANDLED @@ -155,6 +156,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # Create our internal engine data. self._activity_data = _ba.register_activity(self) + assert isinstance(settings, dict) + assert _ba.getactivity() is self + + self._globalsnode: Optional[ba.Node] = None + # Player/Team types should have been specified as type args; # grab those. self._playertype: Type[PlayerType] @@ -174,11 +180,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # Preloaded data for actors, maps, etc; indexed by type. self.preloads: Dict[Type, Any] = {} - if not isinstance(settings, dict): - raise TypeError('expected dict for settings') - if _ba.getactivity(doraise=False) is not self: - raise Exception('invalid context state') - # Hopefully can eventually kill this; activities should # validate/store whatever settings they need at init time # (in a more type-safe way). @@ -191,9 +192,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._should_end_immediately_results: ( Optional[ba.TeamGameResults]) = None self._should_end_immediately_delay = 0.0 - self._called_activity_on_transition_in = False - self._called_activity_on_begin = False - self._activity_death_check_timer: Optional[ba.Timer] = None self._expired = False @@ -234,6 +232,16 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): Call(session.transitioning_out_activity_was_freed, self.can_show_ad_on_death)) + @property + def globalsnode(self) -> ba.Node: + """The 'globals' ba.Node for the activity. This contains various + global controls and values. + """ + node = self._globalsnode + if not node: + raise NodeNotFoundError() + return node + @property def stats(self) -> ba.Stats: """The stats instance accessible while the activity is running. @@ -334,12 +342,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): from ba import _actor as bsactor if not isinstance(actor, bsactor.Actor): raise TypeError('non-actor passed to retain_actor') - if (self.has_transitioned_in() - and _ba.time() - self._last_prune_dead_actors_time > 10.0): - print_error('It looks like nodes/actors are not' - ' being pruned in your activity;' - ' did you call Activity.on_transition_in()' - ' from your subclass?; ' + str(self) + ' (loc. a)') + + # Make sure our pruning is happening... + assert (not self.has_transitioned_in() + or _ba.time() - self._last_prune_dead_actors_time < 10.0) + self._actor_refs.append(actor) def add_actor_weak_ref(self, actor: ba.Actor) -> None: @@ -350,12 +357,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): from ba import _actor as bsactor if not isinstance(actor, bsactor.Actor): raise TypeError('non-actor passed to add_actor_weak_ref') - if (self.has_transitioned_in() - and _ba.time() - self._last_prune_dead_actors_time > 10.0): - print_error('It looks like nodes/actors are ' - 'not being pruned in your activity;' - ' did you call Activity.on_transition_in()' - ' from your subclass?; ' + str(self) + ' (loc. b)') + + # Make sure our pruning is happening... + assert (not self.has_transitioned_in() + or _ba.time() - self._last_prune_dead_actors_time < 10.0) + self._actor_weak_refs.append(weakref.ref(actor)) @property @@ -396,7 +402,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): or teams, however. They remain owned by the previous Activity up until ba.Activity.on_begin() is called. """ - self._called_activity_on_transition_in = True def on_transition_out(self) -> None: """Called when your activity begins transitioning out. @@ -411,28 +416,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): At this point the activity's initial players and teams are filled in and it should begin its actual game logic. """ - self._called_activity_on_begin = True def handlemessage(self, msg: Any) -> Any: """General message handling; can be passed any message object.""" del msg # Unused arg. return UNHANDLED - def end(self, - results: Any = None, - delay: float = 0.0, - force: bool = False) -> None: - """Commences Activity shutdown and delivers results to the ba.Session. - - 'delay' is the time delay before the Activity actually ends - (in seconds). Further calls to end() will be ignored up until - this time, unless 'force' is True, in which case the new results - will replace the old. - """ - - # Ask the session to end us. - self.session.end_activity(self, results, delay, force) - def has_transitioned_in(self) -> bool: """Return whether on_transition_in() has been called.""" return self._has_transitioned_in @@ -455,15 +444,15 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): (internal) """ from ba._general import WeakCall - from ba._gameutils import sharedobj assert not self._has_transitioned_in self._has_transitioned_in = True # Set up the globals node based on our settings. with _ba.Context(self): + glb = self._globalsnode = _ba.newnode('globals') + # Now that it's going to be front and center, # set some global values based on what the activity wants. - glb = sharedobj('globals') glb.use_fixed_vr_overlay = self.use_fixed_vr_overlay glb.allow_kick_idle_players = self.allow_kick_idle_players if self.inherits_slow_motion and prev_globals is not None: @@ -498,7 +487,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_transition_in() except Exception: - print_exception('Error in on_transition_in for', self) + print_exception(f'Error in on_transition_in for {self}') # Tell the C++ layer that this activity is the main one, so it uses # settings from our globals, directs various events to us, etc. @@ -538,8 +527,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._has_begun = True self.on_begin() - self._sanity_check_begin_call() - # If the whole session wants to die and was waiting on us, # can kick off that process now. if session.wants_to_end: @@ -550,6 +537,21 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self.end(self._should_end_immediately_results, self._should_end_immediately_delay) + def end(self, + results: Any = None, + delay: float = 0.0, + force: bool = False) -> None: + """Commences Activity shutdown and delivers results to the ba.Session. + + 'delay' is the time delay before the Activity actually ends + (in seconds). Further calls to end() will be ignored up until + this time, unless 'force' is True, in which case the new results + will replace the old. + """ + + # Ask the session to end us. + self.session.end_activity(self, results, delay, force) + def create_player(self, sessionplayer: ba.SessionPlayer) -> PlayerType: """Create the Player instance for this Activity. @@ -559,7 +561,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): point as it is not yet fully wired up; wait for on_player_join() for that. """ - del sessionplayer # Unused + del sessionplayer # Unused. player = self._playertype() return player @@ -686,19 +688,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): sessionteam.gameteam = None - def _sanity_check_begin_call(self) -> None: - # Make sure ba.Activity.on_transition_in() got called at some point. - if not self._called_activity_on_transition_in: - print_error( - 'ba.Activity.on_transition_in() never got called for ' + - str(self) + '; did you forget to call it' - ' in your on_transition_in override?') - # Make sure that ba.Activity.on_begin() got called at some point. - if not self._called_activity_on_begin: - print_error( - 'ba.Activity.on_begin() never got called for ' + str(self) + - '; did you forget to call it in your on_begin override?') - def _setup_player_and_team_types(self) -> None: """Pull player and team types from our typing.Generic params.""" @@ -819,7 +808,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # It is expected that Team objects may last longer than # the SessionTeam they came from (game objects may hold # team references past the point at which the underlying - # player/team leaves) + # player/team has left the game) pass except Exception: print_exception(f'Error resetting Team {team}') diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 99129efc..8847c13c 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -623,7 +623,7 @@ class App: # FIXME: Shouldn't be touching scene stuff here; # should just pass the request on to the host-session. with _ba.Context(activity): - globs = _gameutils.sharedobj('globals') + globs = activity.globalsnode if not globs.paused: _ba.playsound(_ba.getsound('refWhistle')) globs.paused = True @@ -645,14 +645,13 @@ class App: If there's a foreground host-activity that's currently paused, tell it to resume. """ - from ba._gameutils import sharedobj # FIXME: Shouldn't be touching scene stuff here; # should just pass the request on to the host-session. activity = _ba.get_foreground_host_activity() if activity is not None: with _ba.Context(activity): - globs = sharedobj('globals') + globs = activity.globalsnode if globs.paused: _ba.playsound(_ba.getsound('refWhistle')) globs.paused = False diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index ee60ea96..08c72572 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -249,7 +249,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): def fade_to_red(self) -> None: """Fade the screen to red; (such as when the good guys have lost).""" from ba import _gameutils - c_existing = _gameutils.sharedobj('globals').tint + c_existing = self.globalsnode.tint cnode = _ba.newnode('combine', attrs={ 'input0': c_existing[0], @@ -259,7 +259,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): }) _gameutils.animate(cnode, 'input1', {0: c_existing[1], 2.0: 0}) _gameutils.animate(cnode, 'input2', {0: c_existing[2], 2.0: 0}) - cnode.connectattr('output', _gameutils.sharedobj('globals'), 'tint') + cnode.connectattr('output', self.globalsnode, 'tint') def setup_low_life_warning_sound(self) -> None: """Set up a beeping noise to play when any players are near death.""" diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index b2bc28fa..aa74790a 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -403,6 +403,7 @@ class GameActivity(Activity[PlayerType, TeamType]): return '' def on_transition_in(self) -> None: + super().on_transition_in() # Make our map. @@ -455,7 +456,6 @@ class GameActivity(Activity[PlayerType, TeamType]): # pylint: disable=too-many-nested-blocks # pylint: disable=cyclic-import from bastd.ui.continues import ContinuesWindow - from ba._gameutils import sharedobj from ba._coopsession import CoopSession from ba._enums import TimeType @@ -472,7 +472,7 @@ class GameActivity(Activity[PlayerType, TeamType]): if isinstance(session, CoopSession): assert session.campaign is not None if session.campaign.sequential: - gnode = sharedobj('globals') + gnode = self.globalsnode # Only attempt this if we're not currently paused # and there appears to be no UI. @@ -1024,7 +1024,6 @@ class GameActivity(Activity[PlayerType, TeamType]): This will be displayed at the top of the screen. If the time-limit expires, end_game() will be called. """ - from ba._gameutils import sharedobj from ba._nodeactor import NodeActor if duration <= 0.0: return @@ -1048,8 +1047,9 @@ class GameActivity(Activity[PlayerType, TeamType]): 'time2': duration * 1000, 'timemin': 0 })) - sharedobj('globals').connectattr( - 'time', self._standard_time_limit_text_input.node, 'time1') + self.globalsnode.connectattr('time', + self._standard_time_limit_text_input.node, + 'time1') assert self._standard_time_limit_text_input.node assert self._standard_time_limit_text.node self._standard_time_limit_text_input.node.connectattr( diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 7391925d..8c48ce76 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -23,10 +23,10 @@ from __future__ import annotations from typing import TYPE_CHECKING -# from typing_extensions import Protocol import _ba from ba._enums import TimeType, TimeFormat, SpecialChar +from ba._error import ActivityNotFoundError if TYPE_CHECKING: from typing import Any, Dict, Sequence, Optional @@ -41,15 +41,6 @@ TROPHY_CHARS = { '4': SpecialChar.TROPHY4 } -# class Respawnable(Protocol): -# """A Protocol for objects able to be respawned. - -# Category: Protocols -# """ - -# respawn_timer: Optional[ba.Timer] -# respawn_icon: Optional[RespawnIcon] - def get_trophy_string(trophy_id: str) -> str: """Given a trophy id, returns a string to visualize it.""" @@ -58,125 +49,6 @@ def get_trophy_string(trophy_id: str) -> str: return '?' -def sharedobj(name: str) -> Any: - """Return a predefined object for the current Activity, creating if needed. - - Category: Gameplay Functions - - Available values for 'name': - - 'globals': returns the 'globals' ba.Node, containing various global - controls & values. - - 'object_material': a ba.Material that should be applied to any small, - normal, physical objects such as bombs, boxes, players, etc. Other - materials often check for the presence of this material as a - prerequisite for performing certain actions (such as disabling collisions - between initially-overlapping objects) - - 'player_material': a ba.Material to be applied to player parts. Generally, - materials related to the process of scoring when reaching a goal, etc - will look for the presence of this material on things that hit them. - - 'pickup_material': a ba.Material; collision shapes used for picking things - up will have this material applied. To prevent an object from being - picked up, you can add a material that disables collisions against things - containing this material. - - 'footing_material': anything that can be 'walked on' should have this - ba.Material applied; generally just terrain and whatnot. A character will - snap upright whenever touching something with this material so it should - not be applied to props, etc. - - 'attack_material': a ba.Material applied to explosion shapes, punch - shapes, etc. An object not wanting to receive impulse/etc messages can - disable collisions against this material. - - 'death_material': a ba.Material that sends a ba.DieMessage() to anything - that touches it; handy for terrain below a cliff, etc. - - 'region_material': a ba.Material used for non-physical collision shapes - (regions); collisions can generally be allowed with this material even - when initially overlapping since it is not physical. - - 'railing_material': a ba.Material with a very low friction/stiffness/etc - that can be applied to invisible 'railings' useful for gently keeping - characters from falling off of cliffs. - """ - # pylint: disable=too-many-branches - from ba._messages import DieMessage - - # We store these on the current context; whether its an activity or - # session. - activity = _ba.getactivity(doraise=False) - if activity is not None: - - # Grab shared-objs dict. - sharedobjs = getattr(activity, 'sharedobjs', None) - - # Grab item out of it. - try: - return sharedobjs[name] # (pylint bug?) pylint: disable=E1136 - except KeyError: - pass - - obj: Any - - # Hmm looks like it doesn't yet exist; create it if its a valid value. - if name == 'globals': - node_obj = _ba.newnode('globals') - obj = node_obj - elif name in [ - 'object_material', 'player_material', 'pickup_material', - 'footing_material', 'attack_material' - ]: - obj = _ba.Material() - elif name == 'death_material': - mat = obj = _ba.Material() - mat.add_actions( - ('message', 'their_node', 'at_connect', DieMessage())) - elif name == 'region_material': - obj = _ba.Material() - elif name == 'railing_material': - mat = obj = _ba.Material() - mat.add_actions(('modify_part_collision', 'collide', False)) - mat.add_actions(('modify_part_collision', 'stiffness', 0.003)) - mat.add_actions(('modify_part_collision', 'damping', 0.00001)) - mat.add_actions(conditions=('they_have_material', - sharedobj('player_material')), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', - 'friction', 0.0))) - else: - raise ValueError( - "unrecognized shared object (activity context): '" + name + - "'") - else: - session = _ba.getsession(doraise=False) - if session is not None: - - # Grab shared-objs dict (creating if necessary). - sharedobjs = session.sharedobjs - - # Grab item out of it. - obj = sharedobjs.get(name) - if obj is not None: - return obj - - # Hmm looks like it doesn't yet exist; create if its a valid value. - if name == 'globals': - obj = _ba.newnode('sessionglobals') - else: - raise ValueError('unrecognized shared object ' - "(session context): '" + name + "'") - else: - raise RuntimeError('no current activity or session context') - - # Ok, got a shiny new shared obj; store it for quick access next time. - sharedobjs[name] = obj - return obj - - def animate(node: ba.Node, attr: str, keys: Dict[float, float], @@ -238,7 +110,14 @@ def animate(node: ba.Node, # Do the connects last so all our attrs are in place when we push initial # values through. - sharedobj('globals').connectattr(driver, curve, 'in') + + # We operate in either activities or sessions.. + try: + globalsnode = _ba.getactivity().globalsnode + except ActivityNotFoundError: + globalsnode = _ba.getsession().sessionglobalsnode + + globalsnode.connectattr(driver, curve, 'in') curve.connectattr('out', node, attr) return curve @@ -282,12 +161,18 @@ def animate_array(node: ba.Node, else: raise ValueError('invalid timeformat value: "' + str(timeformat) + '"') + # We operate in either activities or sessions.. + try: + globalsnode = _ba.getactivity().globalsnode + except ActivityNotFoundError: + globalsnode = _ba.getsession().sessionglobalsnode + for i in range(size): curve = _ba.newnode('animcurve', owner=node, name=('Driving ' + str(node) + ' \'' + attr + '\' member ' + str(i))) - sharedobj('globals').connectattr(driver, curve, 'in') + globalsnode.connectattr(driver, curve, 'in') curve.times = [int(mult * time) for time, val in items] curve.values = [val[i] for time, val in items] curve.offset = _ba.time(timeformat=TimeFormat.MILLISECONDS) + int( diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py index 9af476a8..ead68a99 100644 --- a/assets/src/ba_data/python/ba/_map.py +++ b/assets/src/ba_data/python/ba/_map.py @@ -226,7 +226,7 @@ class Map(Actor): ' staticmethod in the activity constructor') # Set various globals. - gnode = _gameutils.sharedobj('globals') + gnode = _ba.getactivity().globalsnode # Set area-of-interest bounds. aoi_bounds = self.get_def_bound_box('area_of_interest_bounds') diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py index a1962adb..48bf5005 100644 --- a/assets/src/ba_data/python/ba/_music.py +++ b/assets/src/ba_data/python/ba/_music.py @@ -506,7 +506,7 @@ def setmusic(musictype: Optional[MusicType], continuous: bool = False) -> None: # the do_play_music call in our music controller. This way we can # seamlessly support custom soundtracks in replays/etc since we're being # driven purely by node data. - gnode = _gameutils.sharedobj('globals') + gnode = _ba.getactivity().globalsnode gnode.music_continuous = continuous gnode.music = '' if musictype is None else musictype.value gnode.music_count += 1 diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index d4f6a7bf..9bea0bae 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -46,6 +46,16 @@ class PlayerInfo: character: str +@dataclass +class StandLocation: + """Describes a point in space and an angle to face. + + Category: Gameplay Classes + """ + position: _ba.Vec3 + angle: Optional[float] = None + + class Player(Generic[TeamType]): """A player in a specific ba.Activity. diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 30b4f8b7..913ee62e 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -25,7 +25,7 @@ import weakref from typing import TYPE_CHECKING import _ba -from ba._error import print_error, print_exception +from ba._error import print_error, print_exception, NodeNotFoundError from ba._lang import Lstr from ba._player import Player @@ -113,7 +113,6 @@ class Session: # pylint: disable=cyclic-import from ba._lobby import Lobby from ba._stats import Stats - from ba._gameutils import sharedobj from ba._gameactivity import GameActivity from ba._activity import Activity from ba._team import SessionTeam @@ -201,7 +200,15 @@ class Session: self.stats = Stats() # Instantiate our session globals node which will apply its settings. - sharedobj('globals') + self._sessionglobalsnode = _ba.newnode('sessionglobals') + + @property + def sessionglobalsnode(self) -> ba.Node: + """The sessionglobals ba.Node for the session.""" + node = self._sessionglobalsnode + if not node: + raise NodeNotFoundError() + return node def on_player_request(self, player: ba.SessionPlayer) -> bool: """Called when a new ba.Player wants to join the Session. @@ -347,16 +354,6 @@ class Session: def on_team_leave(self, team: ba.SessionTeam) -> None: """Called when a ba.Team is leaving the session.""" - def _complete_end_activity(self, activity: ba.Activity, - results: Any) -> None: - # Run the subclass callback in the session context. - try: - with _ba.Context(self): - self.on_activity_end(activity, results) - except Exception: - print_exception('exception in on_activity_end() for session', self, - 'activity', activity, 'with results', results) - def end_activity(self, activity: ba.Activity, results: Any, delay: float, force: bool) -> None: """Commence shutdown of a ba.Activity (if not already occurring). @@ -414,7 +411,6 @@ class Session: (on_transition_in, etc) to get it. (so you can't do session.set_activity(foo) and then ba.newnode() to add a node to foo) """ - from ba._gameutils import sharedobj from ba._enums import TimeType # Sanity test: make sure this doesn't get called recursively. @@ -439,11 +435,8 @@ class Session: str(self._next_activity) + ')') prev_activity = self._activity_retained - if prev_activity is not None: - with _ba.Context(prev_activity): - prev_globals = sharedobj('globals') - else: - prev_globals = None + prev_globals = (prev_activity.globalsnode + if prev_activity is not None else None) # Let the activity do its thing. activity.transition_in(prev_globals) @@ -491,6 +484,16 @@ class Session: """ return [] + def _complete_end_activity(self, activity: ba.Activity, + results: Any) -> None: + # Run the subclass callback in the session context. + try: + with _ba.Context(self): + self.on_activity_end(activity, results) + except Exception: + print_exception('exception in on_activity_end() for session', self, + 'activity', activity, 'with results', results) + def _request_player(self, sessionplayer: ba.SessionPlayer) -> bool: """Called by the C++ layer when players want to join.""" diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index ec6cf25e..7eb080b8 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -26,12 +26,19 @@ from __future__ import annotations import random -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, TypeVar import ba +from bastd.gameutils import SharedObjects if TYPE_CHECKING: - from typing import Any, Sequence, Optional, Callable, List, Tuple + from typing import Any, Sequence, Optional, Callable, List, Tuple, Type + +# Attr we store these objects as on the current activity. +# (based on our module so hopefully avoids conflicts) +STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_bombfactory' + +PlayerType = TypeVar('PlayerType', bound='ba.Player') class BombFactory: @@ -153,6 +160,7 @@ class BombFactory: You shouldn't need to do this; call bastd.actor.bomb.get_factory() to get a shared instance. """ + shared = SharedObjects.get() self.bomb_model = ba.getmodel('bomb') self.sticky_bomb_model = ba.getmodel('bombSticky') @@ -191,17 +199,24 @@ class BombFactory: self.sticky_material = ba.Material() self.bomb_material.add_actions( - conditions=((('we_are_younger_than', 100), 'or', - ('they_are_younger_than', 100)), - 'and', ('they_have_material', - ba.sharedobj('object_material'))), - actions=('modify_node_collision', 'collide', False)) + conditions=( + ( + ('we_are_younger_than', 100), + 'or', + ('they_are_younger_than', 100), + ), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) # we want pickup materials to always hit us even if we're currently not # colliding with their node (generally due to the above rule) - self.bomb_material.add_actions( - conditions=('they_have_material', ba.sharedobj('pickup_material')), - actions=('modify_part_collision', 'use_node_collide', False)) + self.bomb_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'use_node_collide', False)) self.bomb_material.add_actions(actions=('modify_part_collision', 'friction', 0.3)) @@ -209,36 +224,54 @@ class BombFactory: self.land_mine_no_explode_material = ba.Material() self.land_mine_blast_material = ba.Material() self.land_mine_blast_material.add_actions( - conditions=(('we_are_older_than', - 200), 'and', ('they_are_older_than', - 200), 'and', ('eval_colliding', ), - 'and', (('they_dont_have_material', - self.land_mine_no_explode_material), 'and', - (('they_have_material', - ba.sharedobj('object_material')), 'or', - ('they_have_material', - ba.sharedobj('player_material'))))), - actions=('message', 'our_node', 'at_connect', ImpactMessage())) + conditions=( + ('we_are_older_than', 200), + 'and', + ('they_are_older_than', 200), + 'and', + ('eval_colliding', ), + 'and', + ( + ('they_dont_have_material', + self.land_mine_no_explode_material), + 'and', + ( + ('they_have_material', shared.object_material), + 'or', + ('they_have_material', shared.player_material), + ), + ), + ), + actions=('message', 'our_node', 'at_connect', ImpactMessage()), + ) self.impact_blast_material = ba.Material() self.impact_blast_material.add_actions( - conditions=(('we_are_older_than', - 200), 'and', ('they_are_older_than', - 200), 'and', ('eval_colliding', ), - 'and', (('they_have_material', - ba.sharedobj('footing_material')), 'or', - ('they_have_material', - ba.sharedobj('object_material')))), - actions=('message', 'our_node', 'at_connect', ImpactMessage())) + conditions=( + ('we_are_older_than', 200), + 'and', + ('they_are_older_than', 200), + 'and', + ('eval_colliding', ), + 'and', + ( + ('they_have_material', shared.footing_material), + 'or', + ('they_have_material', shared.object_material), + ), + ), + actions=('message', 'our_node', 'at_connect', ImpactMessage()), + ) self.blast_material = ba.Material() self.blast_material.add_actions( - conditions=(('they_have_material', - ba.sharedobj('object_material'))), - actions=(('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', - False), ('message', 'our_node', 'at_connect', - ExplodeHitMessage()))) + conditions=(('they_have_material', shared.object_material), ), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', ExplodeHitMessage()), + ), + ) self.dink_sounds = (ba.getsound('bombDrop01'), ba.getsound('bombDrop02')) @@ -247,10 +280,11 @@ class BombFactory: # collision sounds self.normal_sound_material.add_actions( - conditions=('they_have_material', - ba.sharedobj('footing_material')), - actions=(('impact_sound', self.dink_sounds, 2, 0.8), - ('roll_sound', self.roll_sound, 3, 6))) + conditions=('they_have_material', shared.footing_material), + actions=( + ('impact_sound', self.dink_sounds, 2, 0.8), + ('roll_sound', self.roll_sound, 3, 6), + )) self.sticky_material.add_actions(actions=(('modify_part_collision', 'stiffness', 0.1), @@ -258,24 +292,22 @@ class BombFactory: 'damping', 1.0))) self.sticky_material.add_actions( - conditions=(('they_have_material', - ba.sharedobj('player_material')), - 'or', ('they_have_material', - ba.sharedobj('footing_material'))), - actions=('message', 'our_node', 'at_connect', SplatMessage())) + conditions=( + ('they_have_material', shared.player_material), + 'or', + ('they_have_material', shared.footing_material), + ), + actions=('message', 'our_node', 'at_connect', SplatMessage()), + ) def get_factory() -> BombFactory: """Get/create a shared bastd.actor.bomb.BombFactory object.""" activity = ba.getactivity() - - # FIXME: Need to figure out an elegant way to store - # shared actor data with an activity. - factory: BombFactory - try: - factory = activity.shared_bomb_factory # type: ignore - except Exception: - factory = activity.shared_bomb_factory = BombFactory() # type: ignore + factory = getattr(activity, STORAGE_ATTR_NAME, None) + if factory is None: + factory = BombFactory() + setattr(activity, STORAGE_ATTR_NAME, factory) assert isinstance(factory, BombFactory) return factory @@ -329,26 +361,27 @@ class Blast(ba.Actor): super().__init__() + shared = SharedObjects.get() factory = get_factory() self.blast_type = blast_type - self.source_player = source_player + self._source_player = source_player self.hit_type = hit_type self.hit_subtype = hit_subtype self.radius = blast_radius # set our position a bit lower so we throw more things upward - rmats = (factory.blast_material, ba.sharedobj('attack_material')) - self.node = ba.newnode('region', - delegate=self, - attrs={ - 'position': (position[0], position[1] - 0.1, - position[2]), - 'scale': - (self.radius, self.radius, self.radius), - 'type': 'sphere', - 'materials': rmats - }) + rmats = (factory.blast_material, shared.attack_material) + self.node = ba.newnode( + 'region', + delegate=self, + attrs={ + 'position': (position[0], position[1] - 0.1, position[2]), + 'scale': (self.radius, self.radius, self.radius), + 'type': 'sphere', + 'materials': rmats + }, + ) ba.timer(0.05, self.node.delete) @@ -619,7 +652,7 @@ class Blast(ba.Actor): hit_type=self.hit_type, hit_subtype=self.hit_subtype, radius=self.radius, - source_player=ba.existing(self.source_player))) + source_player=ba.existing(self._source_player))) if self.blast_type == 'ice': ba.playsound(get_factory().freeze_sound, 10, position=nodepos) node.handlemessage(ba.FreezeMessage()) @@ -654,6 +687,7 @@ class Bomb(ba.Actor): """ super().__init__() + shared = SharedObjects.get() factory = get_factory() if bomb_type not in ('ice', 'impact', 'land_mine', 'normal', 'sticky', @@ -681,7 +715,7 @@ class Bomb(ba.Actor): self._explode_callbacks: List[Callable[[Bomb, Blast], Any]] = [] # the player this came from - self.source_player = source_player + self._source_player = source_player # by default our hit type/subtype is our own, but we pick up types of # whoever sets us off so we know what caused a chain reaction @@ -702,12 +736,10 @@ class Bomb(ba.Actor): # ground.. perhaps we don't wanna add this even in the tnt case?.. materials: Tuple[ba.Material, ...] if self.bomb_type == 'tnt': - materials = (factory.bomb_material, - ba.sharedobj('footing_material'), - ba.sharedobj('object_material')) + materials = (factory.bomb_material, shared.footing_material, + shared.object_material) else: - materials = (factory.bomb_material, - ba.sharedobj('object_material')) + materials = (factory.bomb_material, shared.object_material) if self.bomb_type == 'impact': materials = materials + (factory.impact_blast_material, ) @@ -824,11 +856,20 @@ class Bomb(ba.Actor): ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) - def get_source_player(self) -> Optional[ba.Player]: - """Returns a ba.Player representing the source of this bomb. + def get_source_player( + self, playertype: Type[PlayerType]) -> Optional[PlayerType]: + """Return the source-player if there is one and they still exist. - Be prepared for values of None or invalid Player refs.""" - return self.source_player + The type of player for the current activity should be passed so that + the type-checker properly identifies the returned value as one. + """ + player: Any = self._source_player + assert isinstance(player, (playertype, type(None))) + + # We should not be delivering invalid refs. + # (technically if someone holds on to this message this can happen) + assert player is None or player.exists() + return player def on_expire(self) -> None: super().on_expire() @@ -899,7 +940,7 @@ class Bomb(ba.Actor): velocity=self.node.velocity, blast_radius=self.blast_radius, blast_type=self.bomb_type, - source_player=self.source_player, + source_player=ba.existing(self._source_player), hit_type=self.hit_type, hit_subtype=self.hit_subtype).autoretain() for callback in self._explode_callbacks: @@ -979,7 +1020,7 @@ class Bomb(ba.Actor): # person causing them). source_player = msg.get_source_player(ba.Player) if source_player is not None: - self.source_player = source_player + self._source_player = source_player # Also inherit the hit type (if a landmine sets off by a bomb, # the credit should go to the mine) @@ -1007,12 +1048,14 @@ class Bomb(ba.Actor): self.explode() elif isinstance(msg, ImpactMessage): self._handle_impact() - elif isinstance(msg, ba.PickedUpMessage): - # change our source to whoever just picked us up *only* if its None - # this way we can get points for killing bots with their own bombs - # hmm would there be a downside to this?... - if self.source_player is not None: - self.source_player = msg.node.source_player + # Ok the logic below looks like it was backwards to me. Disabling + # until further notice. + # elif isinstance(msg, ba.PickedUpMessage): + # # Change our source to whoever just picked us up *only* if it + # # is None. This way we can get points for killing bots with their + # # own bombs. Hmm would there be a downside to this? + # if self._source_player is not None: + # self._source_player = msg.node.source_player elif isinstance(msg, SplatMessage): self._handle_splat() elif isinstance(msg, ba.DroppedMessage): diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index 59515af0..0e5b014f 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -26,6 +26,7 @@ from dataclasses import dataclass from typing import TYPE_CHECKING import ba +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional @@ -64,13 +65,13 @@ class FlagFactory: You shouldn't need to do this; call bastd.actor.flag.get_factory() to get a shared instance. """ - + shared = SharedObjects.get() self.flagmaterial = ba.Material() self.flagmaterial.add_actions( conditions=( ('we_are_younger_than', 100), 'and', - ('they_have_material', ba.sharedobj('object_material')), + ('they_have_material', shared.object_material), ), actions=('modify_node_collision', 'collide', False), ) @@ -78,7 +79,7 @@ class FlagFactory: self.flagmaterial.add_actions( conditions=( 'they_have_material', - ba.sharedobj('footing_material'), + shared.footing_material, ), actions=( ('message', 'our_node', 'at_connect', 'footing', 1), @@ -91,7 +92,7 @@ class FlagFactory: self.flagmaterial.add_actions( conditions=( 'they_have_material', - ba.sharedobj('footing_material'), + shared.footing_material, ), actions=( ('impact_sound', self.impact_sound, 2, 5), @@ -102,9 +103,9 @@ class FlagFactory: self.no_hit_material = ba.Material() self.no_hit_material.add_actions( conditions=( - ('they_have_material', ba.sharedobj('pickup_material')), + ('they_have_material', shared.pickup_material), 'or', - ('they_have_material', ba.sharedobj('attack_material')), + ('they_have_material', shared.attack_material), ), actions=('modify_part_collision', 'collide', False), ) @@ -112,9 +113,9 @@ class FlagFactory: # We also don't want anything moving it. self.no_hit_material.add_actions( conditions=( - ('they_have_material', ba.sharedobj('object_material')), + ('they_have_material', shared.object_material), 'or', - ('they_dont_have_material', ba.sharedobj('footing_material')), + ('they_dont_have_material', shared.footing_material), ), actions=(('modify_part_collision', 'collide', False), ('modify_part_collision', 'physical', False)), @@ -215,6 +216,7 @@ class Flag(ba.Actor): self._initial_position: Optional[Sequence[float]] = None self._has_moved = False + shared = SharedObjects.get() factory = FlagFactory.get() if materials is None: @@ -225,9 +227,8 @@ class Flag(ba.Actor): if not touchable: materials = [factory.no_hit_material] + materials - finalmaterials = ( - [ba.sharedobj('object_material'), factory.flagmaterial] + - materials) + finalmaterials = ([shared.object_material, factory.flagmaterial] + + materials) self.node = ba.newnode('flag', attrs={ 'position': diff --git a/assets/src/ba_data/python/bastd/actor/onscreencountdown.py b/assets/src/ba_data/python/bastd/actor/onscreencountdown.py index 59b5070c..6e767e54 100644 --- a/assets/src/ba_data/python/bastd/actor/onscreencountdown.py +++ b/assets/src/ba_data/python/bastd/actor/onscreencountdown.py @@ -79,7 +79,7 @@ class OnScreenCountdown(ba.Actor): def start(self) -> None: """Start the timer.""" - globalsnode = ba.sharedobj('globals') + globalsnode = ba.getactivity().globalsnode globalsnode.connectattr('time', self.inputnode, 'time1') self.inputnode.time2 = (globalsnode.time + (self._timeremaining + 1) * 1000) @@ -87,7 +87,8 @@ class OnScreenCountdown(ba.Actor): def on_expire(self) -> None: super().on_expire() - # release callbacks/refs + + # Release callbacks/refs. self._endcall = None def _update(self, forcevalue: int = None) -> None: diff --git a/assets/src/ba_data/python/bastd/actor/onscreentimer.py b/assets/src/ba_data/python/bastd/actor/onscreentimer.py index 8b5699b6..3facd7e3 100644 --- a/assets/src/ba_data/python/bastd/actor/onscreentimer.py +++ b/assets/src/ba_data/python/bastd/actor/onscreentimer.py @@ -66,7 +66,8 @@ class OnScreenTimer(ba.Actor): assert isinstance(tval, int) self._starttime_ms = tval self.inputnode.time1 = self._starttime_ms - ba.sharedobj('globals').connectattr('time', self.inputnode, 'time2') + ba.getactivity().globalsnode.connectattr('time', self.inputnode, + 'time2') def has_started(self) -> bool: """Return whether this timer has started yet.""" diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py index 77dc6ab9..2af9a7fd 100644 --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py @@ -26,6 +26,7 @@ import random from typing import TYPE_CHECKING import ba +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import List, Any, Optional, Sequence @@ -104,6 +105,7 @@ class PowerupBoxFactory: to get a shared instance. """ from ba.internal import get_default_powerup_distribution + shared = SharedObjects.get() self._lastpoweruptype: Optional[str] = None self.model = ba.getmodel('powerup') self.model_simple = ba.getmodel('powerupSimple') @@ -130,19 +132,22 @@ class PowerupBoxFactory: # Pass a powerup-touched message to applicable stuff. self.powerup_material.add_actions( conditions=('they_have_material', self.powerup_accept_material), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('message', 'our_node', 'at_connect', _TouchedMessage()))) + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', _TouchedMessage()), + )) # We don't wanna be picked up. self.powerup_material.add_actions( - conditions=('they_have_material', ba.sharedobj('pickup_material')), - actions=('modify_part_collision', 'collide', False)) + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'collide', False), + ) self.powerup_material.add_actions( - conditions=('they_have_material', - ba.sharedobj('footing_material')), - actions=('impact_sound', self.drop_sound, 0.5, 0.1)) + conditions=('they_have_material', shared.footing_material), + actions=('impact_sound', self.drop_sound, 0.5, 0.1), + ) self._powerupdist: List[str] = [] for powerup, freq in get_default_powerup_distribution(): @@ -228,7 +233,7 @@ class PowerupBox(ba.Actor): """ super().__init__() - + shared = SharedObjects.get() factory = PowerupBoxFactory.get() self.poweruptype = poweruptype self._powersgiven = False @@ -270,7 +275,7 @@ class PowerupBox(ba.Actor): 'reflection': 'powerup', 'reflection_scale': [1.0], 'materials': (factory.powerup_material, - ba.sharedobj('object_material')) + shared.object_material) }) # yapf: disable # Animate in. diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index cf710b07..5d769078 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -29,6 +29,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor import bomb as stdbomb from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import (Any, Sequence, Optional, Dict, List, Union, Callable, @@ -108,6 +109,7 @@ class Spaz(ba.Actor): # pylint: disable=too-many-statements super().__init__() + shared = SharedObjects.get() activity = self.activity factory = get_factory() @@ -126,7 +128,7 @@ class Spaz(ba.Actor): self._punch_power_scale = 1.2 else: self._punch_power_scale = factory.punch_power_scale - self.fly = ba.sharedobj('globals').happy_thoughts_mode + self.fly = ba.getactivity().globalsnode.happy_thoughts_mode if isinstance(activity, ba.GameActivity): self._hockey = activity.map.is_hockey else: @@ -135,14 +137,10 @@ class Spaz(ba.Actor): self._cursed = False self._connected_to_player: Optional[ba.Player] = None materials = [ - factory.spaz_material, - ba.sharedobj('object_material'), - ba.sharedobj('player_material') - ] - roller_materials = [ - factory.roller_material, - ba.sharedobj('player_material') + factory.spaz_material, shared.object_material, + shared.player_material ] + roller_materials = [factory.roller_material, shared.player_material] extras_material = [] if can_accept_powerups: @@ -152,8 +150,8 @@ class Spaz(ba.Actor): extras_material.append(pam) media = factory.get_media(character) - punchmats = (factory.punch_material, ba.sharedobj('attack_material')) - pickupmats = (factory.pickup_material, ba.sharedobj('pickup_material')) + punchmats = (factory.punch_material, shared.attack_material) + pickupmats = (factory.pickup_material, shared.pickup_material) self.node: ba.Node = ba.newnode( type='spaz', delegate=self, diff --git a/assets/src/ba_data/python/bastd/actor/spazfactory.py b/assets/src/ba_data/python/bastd/actor/spazfactory.py index ac7e8983..6946088a 100644 --- a/assets/src/ba_data/python/bastd/actor/spazfactory.py +++ b/assets/src/ba_data/python/bastd/actor/spazfactory.py @@ -24,9 +24,11 @@ from __future__ import annotations from typing import TYPE_CHECKING -import _ba import ba -from bastd.actor import spaz as basespaz +from bastd.gameutils import SharedObjects +from bastd.actor.spaz import (PickupMessage, PunchHitMessage, + CurseExplodeMessage) +import _ba if TYPE_CHECKING: from typing import Any, Dict @@ -101,6 +103,7 @@ class SpazFactory: def __init__(self) -> None: """Instantiate a factory object.""" + shared = SharedObjects.get() self.impact_sounds_medium = (ba.getsound('impactMedium'), ba.getsound('impactMedium2')) self.impact_sounds_hard = (ba.getsound('impactHard'), @@ -123,14 +126,14 @@ class SpazFactory: self.pickup_material = ba.Material() self.curse_material = ba.Material() - footing_material = ba.sharedobj('footing_material') - object_material = ba.sharedobj('object_material') - player_material = ba.sharedobj('player_material') - region_material = ba.sharedobj('region_material') + footing_material = shared.footing_material + object_material = shared.object_material + player_material = shared.player_material + region_material = shared.region_material - # send footing messages to spazzes so they know when they're on solid - # ground. - # eww this should really just be built into the spaz node + # Send footing messages to spazzes so they know when they're on + # solid ground. + # Eww; this probably should just be built into the spaz node. self.roller_material.add_actions( conditions=('they_have_material', footing_material), actions=(('message', 'our_node', 'at_connect', 'footing', 1), @@ -140,27 +143,36 @@ class SpazFactory: conditions=('they_have_material', footing_material), actions=(('message', 'our_node', 'at_connect', 'footing', 1), ('message', 'our_node', 'at_disconnect', 'footing', -1))) - # punches + + # Punches. self.punch_material.add_actions( conditions=('they_are_different_node_than_us', ), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('message', 'our_node', 'at_connect', - basespaz.PunchHitMessage()))) - # pickups + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', PunchHitMessage()), + )) + + # Pickups. self.pickup_material.add_actions( conditions=(('they_are_different_node_than_us', ), 'and', ('they_have_material', object_material)), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('message', 'our_node', 'at_connect', - basespaz.PickupMessage()))) - # curse + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('message', 'our_node', 'at_connect', PickupMessage()), + )) + + # Curse. self.curse_material.add_actions( - conditions=(('they_are_different_node_than_us', ), 'and', - ('they_have_material', player_material)), + conditions=( + ('they_are_different_node_than_us', ), + 'and', + ('they_have_material', player_material), + ), actions=('message', 'our_node', 'at_connect', - basespaz.CurseExplodeMessage())) + CurseExplodeMessage()), + ) self.foot_impact_sounds = (ba.getsound('footImpact01'), ba.getsound('footImpact02'), @@ -171,34 +183,45 @@ class SpazFactory: self.roller_material.add_actions( conditions=('they_have_material', footing_material), - actions=(('impact_sound', self.foot_impact_sounds, 1, - 0.2), ('skid_sound', self.foot_skid_sound, 20, 0.3), - ('roll_sound', self.foot_roll_sound, 20, 3.0))) + actions=( + ('impact_sound', self.foot_impact_sounds, 1, 0.2), + ('skid_sound', self.foot_skid_sound, 20, 0.3), + ('roll_sound', self.foot_roll_sound, 20, 3.0), + )) self.skid_sound = ba.getsound('gravelSkid') self.spaz_material.add_actions( conditions=('they_have_material', footing_material), - actions=(('impact_sound', self.foot_impact_sounds, 20, - 6), ('skid_sound', self.skid_sound, 2.0, 1), - ('roll_sound', self.skid_sound, 2.0, 1))) + actions=( + ('impact_sound', self.foot_impact_sounds, 20, 6), + ('skid_sound', self.skid_sound, 2.0, 1), + ('roll_sound', self.skid_sound, 2.0, 1), + )) self.shield_up_sound = ba.getsound('shieldUp') self.shield_down_sound = ba.getsound('shieldDown') self.shield_hit_sound = ba.getsound('shieldHit') - # we don't want to collide with stuff we're initially overlapping - # (unless its marked with a special region material) + # We don't want to collide with stuff we're initially overlapping + # (unless its marked with a special region material). self.spaz_material.add_actions( - conditions=((('we_are_younger_than', 51), 'and', - ('they_are_different_node_than_us', )), 'and', - ('they_dont_have_material', region_material)), - actions=('modify_node_collision', 'collide', False)) + conditions=( + ( + ('we_are_younger_than', 51), + 'and', + ('they_are_different_node_than_us', ), + ), + 'and', + ('they_dont_have_material', region_material), + ), + actions=('modify_node_collision', 'collide', False), + ) self.spaz_media: Dict[str, Any] = {} - # lets load some basic rules (allows them to be tweaked from the - # master server) + # Lets load some basic rules. + # (allows them to be tweaked from the master server) self.shield_decay_rate = _ba.get_account_misc_read_val('rsdr', 10.0) self.punch_cooldown = _ba.get_account_misc_read_val('rpc', 400) self.punch_cooldown_gloves = (_ba.get_account_misc_read_val( diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 062a030e..8e0bf524 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -32,6 +32,7 @@ import ba from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.flag import Flag from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Type, List, Dict, Sequence, Union @@ -111,6 +112,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): return 'touch ${ARG1} flags', self._score_to_win def create_team(self, sessionteam: ba.SessionTeam) -> Team: + shared = SharedObjects.get() base_pos = self.map.get_flag_position(sessionteam.id) ba.newnode('light', attrs={ @@ -129,7 +131,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): mat = self._base_region_materials[sessionteam.id] = ba.Material() mat.add_actions( - conditions=('they_have_material', ba.sharedobj('player_material')), + conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index f65d12c8..740631bc 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -31,6 +31,7 @@ import ba from bastd.actor.flag import Flag from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Type, List, Dict, Optional, Sequence, Union @@ -142,6 +143,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() + shared = SharedObjects.get() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) @@ -155,7 +157,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): mat.add_actions( conditions=( 'they_have_material', - ba.sharedobj('player_material'), + shared.player_material, ), actions=( ('modify_part_collision', 'collide', True), @@ -329,8 +331,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): super().handlemessage(msg) player = msg.getplayer(Player) if player is self._get_chosen_one_player(): - killerplayer = ba.playercast_o(Player, - msg.getkillerplayer(Player)) + killerplayer = msg.getkillerplayer(Player) self._set_chosen_one_player(None if ( killerplayer is None or killerplayer is player or not killerplayer.is_alive()) else killerplayer) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index c6ba9c4d..938b4c51 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -32,6 +32,7 @@ import ba from bastd.actor.flag import Flag from bastd.actor.scoreboard import Scoreboard from bastd.actor.playerspaz import PlayerSpaz +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Optional, Type, List, Dict, Sequence, Union @@ -119,6 +120,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) + shared = SharedObjects.get() self._scoreboard = Scoreboard() self._score_sound = ba.getsound('score') self._swipsound = ba.getsound('swip') @@ -134,7 +136,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): # We want flags to tell us they've been hit but not react physically. self._extraflagmat.add_actions( - conditions=('they_have_material', ba.sharedobj('player_material')), + conditions=('they_have_material', shared.player_material), actions=(('modify_part_collision', 'collide', True), ('call', 'at_connect', self._handle_flag_player_collide))) diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 244e79d4..31262e3a 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -35,6 +35,7 @@ from bastd.actor.spazbot import SpazBotSet, BouncyBot, SpazBotDiedMessage from bastd.actor.onscreencountdown import OnScreenCountdown from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Type, Dict, List, Tuple, Optional @@ -78,6 +79,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) + shared = SharedObjects.get() self._last_player_death_time = None self._scoreboard = Scoreboard() self.egg_model = ba.getmodel('egg') @@ -89,7 +91,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): self._max_eggs = 1.0 self.egg_material = ba.Material() self.egg_material.add_actions( - conditions=('they_have_material', ba.sharedobj('player_material')), + conditions=('they_have_material', shared.player_material), actions=(('call', 'at_connect', self._on_egg_player_collide), )) self._eggs: List[Egg] = [] self._update_timer: Optional[ba.Timer] = None @@ -243,12 +245,13 @@ class Egg(ba.Actor): super().__init__() activity = self.activity assert isinstance(activity, EasterEggHuntGame) + shared = SharedObjects.get() # Spawn just above the provided point. self._spawn_pos = (position[0], position[1] + 1.0, position[2]) ctex = (activity.egg_tex_1, activity.egg_tex_2, activity.egg_tex_3)[random.randrange(3)] - mats = [ba.sharedobj('object_material'), activity.egg_material] + mats = [shared.object_material, activity.egg_material] self.node = ba.newnode('prop', delegate=self, attrs={ diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index e0f5d7b0..d44573a7 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -530,8 +530,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): })) self._time_text_input = ba.NodeActor( ba.newnode('timedisplay', attrs={'showsubseconds': True})) - ba.sharedobj('globals').connectattr('time', self._time_text_input.node, - 'time2') + self.globalsnode.connectattr('time', self._time_text_input.node, + 'time2') assert self._time_text_input.node assert self._time_text.node self._time_text_input.node.connectattr('output', self._time_text.node, diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index bfb6e196..333a5d19 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -31,6 +31,7 @@ import ba from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Dict, Type, List, Optional, Union @@ -48,6 +49,7 @@ class Puck(ba.Actor): def __init__(self, position: Sequence[float] = (0.0, 1.0, 0.0)): super().__init__() + shared = SharedObjects.get() activity = self.getactivity() # Spawn just above the provided point. @@ -56,7 +58,7 @@ class Puck(ba.Actor): self.scored = False assert activity is not None assert isinstance(activity, HockeyGame) - pmats = [ba.sharedobj('object_material'), activity.puck_material] + pmats = [shared.object_material, activity.puck_material] self.node = ba.newnode('prop', delegate=self, attrs={ @@ -153,6 +155,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) + shared = SharedObjects.get() self._scoreboard = Scoreboard() self._cheer_sound = ba.getsound('cheer') self._chant_sound = ba.getsound('crowdChant') @@ -165,22 +168,26 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): self.puck_material = ba.Material() self.puck_material.add_actions(actions=(('modify_part_collision', 'friction', 0.5))) + self.puck_material.add_actions(conditions=('they_have_material', + shared.pickup_material), + actions=('modify_part_collision', + 'collide', False)) self.puck_material.add_actions( - conditions=('they_have_material', ba.sharedobj('pickup_material')), - actions=('modify_part_collision', 'collide', False)) - self.puck_material.add_actions( - conditions=(('we_are_younger_than', 100), - 'and', ('they_have_material', - ba.sharedobj('object_material'))), - actions=('modify_node_collision', 'collide', False)) - self.puck_material.add_actions( - conditions=('they_have_material', - ba.sharedobj('footing_material')), - actions=('impact_sound', self._puck_sound, 0.2, 5)) + conditions=( + ('we_are_younger_than', 100), + 'and', + ('they_have_material', shared.object_material), + ), + actions=('modify_node_collision', 'collide', False), + ) + self.puck_material.add_actions(conditions=('they_have_material', + shared.footing_material), + actions=('impact_sound', + self._puck_sound, 0.2, 5)) # Keep track of which player last touched the puck self.puck_material.add_actions( - conditions=('they_have_material', ba.sharedobj('player_material')), + conditions=('they_have_material', shared.player_material), actions=(('call', 'at_connect', self._handle_puck_player_collide), )) diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index b0dfe47c..4b70add0 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -33,6 +33,7 @@ import ba from bastd.actor.flag import Flag from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from weakref import ReferenceType @@ -97,6 +98,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): super().__init__(settings) + shared = SharedObjects.get() self._scoreboard = Scoreboard() self._swipsound = ba.getsound('swip') self._tick_sound = ba.getsound('tick') @@ -121,7 +123,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): self._time_limit = float(settings['Time Limit']) self._flag_region_material = ba.Material() self._flag_region_material.add_actions( - conditions=('they_have_material', ba.sharedobj('player_material')), + conditions=('they_have_material', shared.player_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), @@ -145,6 +147,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() + shared = SharedObjects.get() self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_pos = self.map.get_flag_position(None) @@ -164,10 +167,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): 'color': (0.2, 0.2, 0.2) }) # Flag region. - flagmats = [ - self._flag_region_material, - ba.sharedobj('region_material') - ] + flagmats = [self._flag_region_material, shared.region_material] ba.newnode('region', attrs={ 'position': self._flag_pos, diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 41485b2e..f28d2736 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -33,6 +33,7 @@ import ba from bastd.actor.bomb import Bomb from bastd.actor.playerspaz import PlayerSpaz from bastd.actor.scoreboard import Scoreboard +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import (Any, Type, Tuple, List, Sequence, Optional, Dict, @@ -196,14 +197,17 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): def on_transition_in(self) -> None: super().on_transition_in() + shared = SharedObjects.get() pts = self.map.get_def_points('race_point') mat = self.race_region_material = ba.Material() mat.add_actions(conditions=('they_have_material', - ba.sharedobj('player_material')), - actions=(('modify_part_collision', 'collide', True), - ('modify_part_collision', 'physical', - False), ('call', 'at_connect', - self._handle_race_point_collide))) + shared.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', + self._handle_race_point_collide), + )) for rpt in pts: self._regions.append(RaceRegion(rpt, len(self._regions))) diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 7f6ca1d7..b268fe4f 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -34,6 +34,7 @@ from bastd.actor.bomb import TNTSpawner from bastd.actor.scoreboard import Scoreboard from bastd.actor.respawnicon import RespawnIcon from bastd.actor.powerupbox import PowerupBox, PowerupBoxFactory +from bastd.gameutils import SharedObjects from bastd.actor.spazbot import ( SpazBotSet, SpazBot, SpazBotDiedMessage, BomberBot, BrawlerBot, TriggerBot, TriggerBotPro, BomberBotProShielded, TriggerBotProShielded, ChargerBot, @@ -88,6 +89,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): def __init__(self, settings: Dict[str, Any]): settings['map'] = 'Tower D' super().__init__(settings) + shared = SharedObjects.get() self._preset = self.settings_raw.get('preset', 'pro') self._player_death_sound = ba.getsound('playerDeath') @@ -109,7 +111,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._score_region_material = ba.Material() self._score_region_material.add_actions( - conditions=('they_have_material', ba.sharedobj('player_material')), + conditions=('they_have_material', shared.player_material), actions=(('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), ('call', 'at_connect', self._handle_reached_end))) diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index ea34c785..0c4c0252 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -171,9 +171,9 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): # Feed the explosion point to all our targets and get points in return. # Note: we operate on a copy of self._targets since the list may change # under us if we hit stuff (don't wanna get points for new targets). - player = ba.playercast_o(Player, bomb.get_source_player()) + player = bomb.get_source_player(Player) if not player: - return # could happen if they leave after throwing a bomb.. + return # Could happen if they leave after throwing a bomb. bullseye = any( target.do_hit_at_position(pos, player) diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py index 17cf39a8..4519e988 100644 --- a/assets/src/ba_data/python/bastd/gameutils.py +++ b/assets/src/ba_data/python/bastd/gameutils.py @@ -24,5 +24,142 @@ from __future__ import annotations from typing import TYPE_CHECKING +import ba + if TYPE_CHECKING: - from typing import Sequence + from typing import Sequence, Optional + +# Attr we store these objects as on the current activity. +# (based on our module so hopefully avoids conflicts) +STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_sharedobjs' + + +class SharedObjects: + """Various common components for use in games. + + Category: Gameplay Classes + + Objects contained here are created on-demand as accessed and shared + by everything in the current activity. This includes things such as + standard materials. + """ + + def __init__(self) -> None: + activity = ba.getactivity() + if hasattr(activity, STORAGE_ATTR_NAME): + raise RuntimeError('Use SharedObjects.get() to fetch the' + ' shared instance for this activity.') + self._object_material: Optional[ba.Material] = None + self._player_material: Optional[ba.Material] = None + self._pickup_material: Optional[ba.Material] = None + self._footing_material: Optional[ba.Material] = None + self._attack_material: Optional[ba.Material] = None + self._death_material: Optional[ba.Material] = None + self._region_material: Optional[ba.Material] = None + self._railing_material: Optional[ba.Material] = None + + @staticmethod + def get() -> SharedObjects: + """Fetch/create the instance of this class for the current activity.""" + activity = ba.getactivity() + shobs = getattr(activity, STORAGE_ATTR_NAME, None) + if shobs is None: + shobs = SharedObjects() + setattr(activity, STORAGE_ATTR_NAME, shobs) + assert isinstance(shobs, SharedObjects) + return shobs + + @property + def player_material(self) -> ba.Material: + """a ba.Material to be applied to player parts. Generally, + materials related to the process of scoring when reaching a goal, etc + will look for the presence of this material on things that hit them. + """ + if self._player_material is None: + self._player_material = ba.Material() + return self._player_material + + @property + def object_material(self) -> ba.Material: + """A ba.Material that should be applied to any small, + normal, physical objects such as bombs, boxes, players, etc. Other + materials often check for the presence of this material as a + prerequisite for performing certain actions (such as disabling + collisions between initially-overlapping objects) + """ + if self._object_material is None: + self._object_material = ba.Material() + return self._object_material + + @property + def pickup_material(self) -> ba.Material: + """A ba.Material; collision shapes used for picking things + up will have this material applied. To prevent an object from being + picked up, you can add a material that disables collisions against + things containing this material. + """ + if self._pickup_material is None: + self._pickup_material = ba.Material() + return self._pickup_material + + @property + def footing_material(self) -> ba.Material: + """Anything that can be 'walked on' should have this + ba.Material applied; generally just terrain and whatnot. A character + will snap upright whenever touching something with this material so it + should not be applied to props, etc. + """ + if self._footing_material is None: + self._footing_material = ba.Material() + return self._footing_material + + @property + def attack_material(self) -> ba.Material: + """A ba.Material applied to explosion shapes, punch + shapes, etc. An object not wanting to receive impulse/etc messages can + disable collisions against this material. + """ + if self._attack_material is None: + self._attack_material = ba.Material() + return self._attack_material + + @property + def death_material(self) -> ba.Material: + """A ba.Material that sends a ba.DieMessage() to anything + that touches it; handy for terrain below a cliff, etc. + """ + if self._death_material is None: + mat = self._death_material = ba.Material() + mat.add_actions( + ('message', 'their_node', 'at_connect', ba.DieMessage())) + return self._death_material + + @property + def region_material(self) -> ba.Material: + """A ba.Material used for non-physical collision shapes + (regions); collisions can generally be allowed with this material even + when initially overlapping since it is not physical. + """ + if self._region_material is None: + self._region_material = ba.Material() + return self._region_material + + @property + def railing_material(self) -> ba.Material: + """A ba.Material with a very low friction/stiffness/etc + that can be applied to invisible 'railings' useful for gently keeping + characters from falling off of cliffs. + """ + if self._railing_material is None: + mat = self._railing_material = ba.Material() + mat.add_actions(('modify_part_collision', 'collide', False)) + mat.add_actions(('modify_part_collision', 'stiffness', 0.003)) + mat.add_actions(('modify_part_collision', 'damping', 0.00001)) + mat.add_actions( + conditions=('they_have_material', self.player_material), + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'friction', 0.0), + ), + ) + return self._railing_material diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 391c082e..61cfb0f2 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -182,7 +182,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): vr_bottom_fill_model = ba.getmodel('thePadVRFillBottom') vr_top_fill_model = ba.getmodel('thePadVRFillTop') - gnode = ba.sharedobj('globals') + gnode = self.globalsnode gnode.camera_mode = 'rotate' tint = (1.14, 1.1, 1.0) diff --git a/assets/src/ba_data/python/bastd/maps.py b/assets/src/ba_data/python/bastd/maps.py index 1e5158c6..29de16eb 100644 --- a/assets/src/ba_data/python/bastd/maps.py +++ b/assets/src/ba_data/python/bastd/maps.py @@ -26,7 +26,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -# from bastd import stdmap +from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, List, Dict @@ -65,6 +65,7 @@ class HockeyStadium(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode('terrain', delegate=self, attrs={ @@ -75,7 +76,7 @@ class HockeyStadium(ba.Map): 'color_texture': self.preloaddata['tex'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['ice_material'] ] }) @@ -87,9 +88,7 @@ class HockeyStadium(ba.Map): 'background': True, 'color_texture': self.preloaddata['stands_tex'] }) - mats = [ - ba.sharedobj('footing_material'), self.preloaddata['ice_material'] - ] + mats = [shared.footing_material, self.preloaddata['ice_material']] self.floor = ba.newnode('terrain', attrs={ 'model': self.preloaddata['models'][1], @@ -105,7 +104,7 @@ class HockeyStadium(ba.Map): 'visible_in_reflections': False, 'color_texture': self.preloaddata['stands_tex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.floor_reflection = True gnode.debris_friction = 0.3 gnode.debris_kill_height = -0.3 @@ -145,6 +144,7 @@ class FootballStadium(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -152,7 +152,7 @@ class FootballStadium(ba.Map): 'model': self.preloaddata['model'], 'collide_model': self.preloaddata['collide_model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) ba.newnode('terrain', attrs={ @@ -162,7 +162,7 @@ class FootballStadium(ba.Map): 'background': True, 'color_texture': self.preloaddata['tex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.3, 1.2, 1.0) gnode.ambient_color = (1.3, 1.2, 1.0) gnode.vignette_outer = (0.57, 0.57, 0.57) @@ -218,6 +218,7 @@ class Bridgit(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -225,7 +226,7 @@ class Bridgit(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model_top'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -253,7 +254,7 @@ class Bridgit(ba.Map): 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) self.bg_collide = ba.newnode('terrain', @@ -261,12 +262,12 @@ class Bridgit(ba.Map): 'collide_model': self.preloaddata['collide_bg'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['bg_material'], - ba.sharedobj('death_material') + shared.death_material ] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.1, 1.2, 1.3) gnode.ambient_color = (1.1, 1.2, 1.3) gnode.vignette_outer = (0.65, 0.6, 0.55) @@ -312,6 +313,7 @@ class BigG(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -320,7 +322,7 @@ class BigG(ba.Map): 'color': (0.7, 0.7, 0.7), 'model': self.preloaddata['model_top'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -349,7 +351,7 @@ class BigG(ba.Map): 'terrain', attrs={ 'collide_model': self.preloaddata['bumper_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) self.bg_collide = ba.newnode('terrain', @@ -357,12 +359,12 @@ class BigG(ba.Map): 'collide_model': self.preloaddata['collide_bg'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['bg_material'], - ba.sharedobj('death_material') + shared.death_material ] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.1, 1.2, 1.3) gnode.ambient_color = (1.1, 1.2, 1.3) gnode.vignette_outer = (0.65, 0.6, 0.55) @@ -406,6 +408,7 @@ class Roundabout(ba.Map): def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -1, 1)) + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -413,7 +416,7 @@ class Roundabout(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -442,19 +445,19 @@ class Roundabout(ba.Map): 'collide_model': self.preloaddata['collide_bg'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['bg_material'], - ba.sharedobj('death_material') + shared.death_material ] }) self.railing = ba.newnode( 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.0, 1.05, 1.1) gnode.ambient_color = (1.0, 1.05, 1.1) gnode.shadow_ortho = True @@ -499,6 +502,7 @@ class MonkeyFace(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -506,7 +510,7 @@ class MonkeyFace(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -535,19 +539,19 @@ class MonkeyFace(ba.Map): 'collide_model': self.preloaddata['collide_bg'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['bg_material'], - ba.sharedobj('death_material') + shared.death_material ] }) self.railing = ba.newnode( 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.1, 1.2, 1.2) gnode.ambient_color = (1.2, 1.3, 1.3) gnode.vignette_outer = (0.60, 0.62, 0.66) @@ -593,6 +597,7 @@ class ZigZag(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -600,7 +605,7 @@ class ZigZag(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.background = ba.newnode( 'terrain', @@ -628,19 +633,19 @@ class ZigZag(ba.Map): 'collide_model': self.preloaddata['collide_bg'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['bg_material'], - ba.sharedobj('death_material') + shared.death_material ] }) self.railing = ba.newnode( 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.0, 1.15, 1.15) gnode.ambient_color = (1.0, 1.15, 1.15) gnode.vignette_outer = (0.57, 0.59, 0.63) @@ -682,6 +687,7 @@ class ThePad(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -689,7 +695,7 @@ class ThePad(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -709,7 +715,7 @@ class ThePad(ba.Map): 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) ba.newnode('terrain', @@ -721,7 +727,7 @@ class ThePad(ba.Map): 'background': True, 'color_texture': self.preloaddata['vr_fill_mound_tex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.1, 1.1, 1.0) gnode.ambient_color = (1.1, 1.1, 1.0) gnode.vignette_outer = (0.7, 0.65, 0.75) @@ -760,6 +766,7 @@ class DoomShroom(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -767,7 +774,7 @@ class DoomShroom(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.background = ba.newnode( 'terrain', @@ -791,16 +798,13 @@ class DoomShroom(ba.Map): 'lighting': False, 'color_texture': self.preloaddata['tex'] }) - self.bg_collide = ba.newnode('terrain', - attrs={ - 'collide_model': - self.preloaddata['collide_bg'], - 'materials': [ - ba.sharedobj('footing_material'), - ba.sharedobj('death_material') - ] - }) - gnode = ba.sharedobj('globals') + self.bg_collide = ba.newnode( + 'terrain', + attrs={ + 'collide_model': self.preloaddata['collide_bg'], + 'materials': [shared.footing_material, shared.death_material] + }) + gnode = ba.getactivity().globalsnode gnode.tint = (0.82, 1.10, 1.15) gnode.ambient_color = (0.9, 1.3, 1.1) gnode.shadow_ortho = False @@ -854,6 +858,7 @@ class LakeFrigid(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode('terrain', delegate=self, attrs={ @@ -864,7 +869,7 @@ class LakeFrigid(ba.Map): 'color_texture': self.preloaddata['tex'], 'materials': [ - ba.sharedobj('footing_material'), + shared.footing_material, self.preloaddata['ice_material'] ] }) @@ -890,7 +895,7 @@ class LakeFrigid(ba.Map): 'background': True, 'color_texture': self.preloaddata['tex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1, 1, 1) gnode.ambient_color = (1, 1, 1) gnode.shadow_ortho = True @@ -931,6 +936,7 @@ class TipTop(ba.Map): def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -0.2, 2.5)) + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -939,7 +945,7 @@ class TipTop(ba.Map): 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], 'color': (0.7, 0.7, 0.7), - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -961,10 +967,10 @@ class TipTop(ba.Map): 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (0.8, 0.9, 1.3) gnode.ambient_color = (0.8, 0.9, 1.3) gnode.vignette_outer = (0.79, 0.79, 0.69) @@ -1006,6 +1012,7 @@ class CragCastle(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -1013,7 +1020,7 @@ class CragCastle(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -1033,7 +1040,7 @@ class CragCastle(ba.Map): 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) ba.newnode('terrain', @@ -1045,7 +1052,7 @@ class CragCastle(ba.Map): 'background': True, 'color_texture': self.preloaddata['vr_fill_mound_tex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.shadow_ortho = True gnode.shadow_offset = (0, 0, -5.0) gnode.tint = (1.15, 1.05, 0.75) @@ -1106,6 +1113,7 @@ class TowerD(ba.Map): def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, 1, 1)) + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -1113,7 +1121,7 @@ class TowerD(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.node_bottom = ba.newnode( 'terrain', @@ -1147,7 +1155,7 @@ class TowerD(ba.Map): 'affect_bg_dynamics': False, 'materials': [self.preloaddata['player_wall_material']] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.15, 1.11, 1.03) gnode.ambient_color = (1.2, 1.1, 1.0) gnode.vignette_outer = (0.7, 0.73, 0.7) @@ -1209,6 +1217,7 @@ class HappyThoughts(ba.Map): def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -3.7, 2.5)) + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -1216,7 +1225,7 @@ class HappyThoughts(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.bottom = ba.newnode('terrain', attrs={ @@ -1241,7 +1250,7 @@ class HappyThoughts(ba.Map): 'background': True, 'color_texture': self.preloaddata['vr_fill_mound_tex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.happy_thoughts_mode = True gnode.shadow_offset = (0.0, 8.0, 5.0) gnode.tint = (1.3, 1.23, 1.0) @@ -1309,6 +1318,7 @@ class StepRightUp(ba.Map): def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, -1, 2)) + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -1316,7 +1326,7 @@ class StepRightUp(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.node_bottom = ba.newnode( 'terrain', @@ -1343,7 +1353,7 @@ class StepRightUp(ba.Map): 'background': True, 'color_texture': self.preloaddata['bgtex'] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.2, 1.1, 1.0) gnode.ambient_color = (1.2, 1.1, 1.0) gnode.vignette_outer = (0.7, 0.65, 0.75) @@ -1394,6 +1404,7 @@ class Courtyard(ba.Map): def __init__(self) -> None: super().__init__() + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -1401,7 +1412,7 @@ class Courtyard(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.background = ba.newnode( 'terrain', @@ -1437,7 +1448,7 @@ class Courtyard(ba.Map): 'affect_bg_dynamics': False, 'materials': [self.preloaddata['player_wall_material']] }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.2, 1.17, 1.1) gnode.ambient_color = (1.2, 1.17, 1.1) gnode.vignette_outer = (0.6, 0.6, 0.64) @@ -1489,6 +1500,7 @@ class Rampage(ba.Map): def __init__(self) -> None: super().__init__(vr_overlay_offset=(0, 0, 2)) + shared = SharedObjects.get() self.node = ba.newnode( 'terrain', delegate=self, @@ -1496,7 +1508,7 @@ class Rampage(ba.Map): 'collide_model': self.preloaddata['collide_model'], 'model': self.preloaddata['model'], 'color_texture': self.preloaddata['tex'], - 'materials': [ba.sharedobj('footing_material')] + 'materials': [shared.footing_material] }) self.background = ba.newnode( 'terrain', @@ -1531,10 +1543,10 @@ class Rampage(ba.Map): 'terrain', attrs={ 'collide_model': self.preloaddata['railing_collide_model'], - 'materials': [ba.sharedobj('railing_material')], + 'materials': [shared.railing_material], 'bumper': True }) - gnode = ba.sharedobj('globals') + gnode = ba.getactivity().globalsnode gnode.tint = (1.2, 1.1, 0.97) gnode.ambient_color = (1.3, 1.2, 1.03) gnode.vignette_outer = (0.62, 0.64, 0.69) diff --git a/docs/ba_module.md b/docs/ba_module.md index dbdf5458..75bccd57 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-28 for Ballistica version 1.5.0 build 20033

    +

    last updated on 2020-05-29 for Ballistica version 1.5.0 build 20033

    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!


    @@ -40,6 +40,7 @@
  • ba.SessionPlayer
  • ba.SessionTeam
  • +
  • ba.StandLocation
  • ba.Stats
  • ba.Team
  • ba.TeamGameResults
  • @@ -61,7 +62,6 @@
  • ba.playsound()
  • ba.printnodes()
  • ba.setmusic()
  • -
  • ba.sharedobj()
  • ba.show_damage_count()
  • General Utility Classes

    @@ -345,7 +345,7 @@ actually award achievements.

    can overlap during transitions.

    Attributes:

    -
    expired, players, playertype, session, settings_raw, stats, teams, teamtype
    +
    expired, globalsnode, players, playertype, session, settings_raw, stats, teams, teamtype

    expired

    bool

    @@ -355,6 +355,12 @@ actually award achievements.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    globalsnode

    +

    ba.Node

    +

    The 'globals' ba.Node for the activity. This contains various + global controls and values.

    +

    players

    List[PlayerType]

    @@ -1541,7 +1547,7 @@ start_long_action(callback_when_done=ba.ContextC

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, map, playertype, session, stats, teamtype
    +
    expired, globalsnode, map, playertype, session, stats, teamtype

    expired

    bool

    @@ -1551,6 +1557,12 @@ start_long_action(callback_when_done=ba.ContextC At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    globalsnode

    +

    ba.Node

    +

    The 'globals' ba.Node for the activity. This contains various + global controls and values.

    +

    map

    ba.Map

    @@ -1660,12 +1672,18 @@ and it should begin its actual game logic.

    Attributes Inherited:

    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Attributes Defined Here:

    +
    campaign, sessionglobalsnode

    campaign

    Optional[ba.Campaign]

    The ba.Campaign instance this Session represents, or None if there is no associated Campaign.

    +
    +

    sessionglobalsnode

    +

    ba.Node

    +

    The sessionglobals ba.Node for the session.

    +

    Methods Inherited:

    @@ -2011,6 +2029,14 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +

    Attributes Defined Here:

    +
    +

    sessionglobalsnode

    +

    ba.Node

    +

    The sessionglobals ba.Node for the session.

    + +
    +

    Methods Inherited:

    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    @@ -2049,6 +2075,14 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +

    Attributes Defined Here:

    +
    +

    sessionglobalsnode

    +

    ba.Node

    +

    The sessionglobals ba.Node for the session.

    + +
    +

    Methods Inherited:

    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    @@ -2098,7 +2132,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, map, playertype, session, stats, teamtype
    +
    expired, globalsnode, map, playertype, session, stats, teamtype

    expired

    bool

    @@ -2108,6 +2142,12 @@ its time with lingering corpses, sound effects, etc.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    globalsnode

    +

    ba.Node

    +

    The 'globals' ba.Node for the activity. This contains various + global controls and values.

    +

    map

    ba.Map

    @@ -3299,7 +3339,7 @@ m.add_actions(actions=(('modify_part_collision', 'physical', False),
    # example 3: play some sounds when we're contacting the ground:
     m = ba.Material()
     m.add_actions(conditions=('they_have_material',
    -                          ba.sharedobj('footing_material')),
    +                          shared.footing_material),
                   actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),
                            ('skid_sound', ba.getsound('metalSkid'), 2, 5)))
    @@ -3329,6 +3369,14 @@ Use ba.getmodel() to instantiate one.

    Attributes Inherited:

    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +

    Attributes Defined Here:

    +
    +

    sessionglobalsnode

    +

    ba.Node

    +

    The sessionglobals ba.Node for the session.

    + +
    +

    Methods Inherited:

    begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_leave(), on_player_request(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    @@ -4272,7 +4320,7 @@ Pass 0 or a negative number for no ban time.

    maintaining state between them (players, teams, score tallies, etc).

    Attributes:

    -
    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, lobby, max_players, min_players, players, sessionglobalsnode, teams, use_team_colors, use_teams

    allow_mid_activity_joins

    bool

    @@ -4305,6 +4353,11 @@ to proceed past the initial joining screen.

    list in ba.Activity; not this. Some players, such as those who have not yet selected a character, will only appear on this list.

    +
    +

    sessionglobalsnode

    +

    ba.Node

    +

    The sessionglobals ba.Node for the session.

    +

    teams

    List[ba.SessionTeam]

    @@ -4812,6 +4865,22 @@ of the session.

  • MIKIROG

  • +

    ba.StandLocation

    +

    <top level class> +

    +

    Describes a point in space and an angle to face.

    + +

    Category: Gameplay Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.StandLocation(position: _ba.Vec3, angle: Optional[float] = None)

    + +
    +
    +

    ba.StandMessage

    <top level class>

    @@ -4961,7 +5030,7 @@ of the session.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, map, playertype, session, stats, teamtype
    +
    expired, globalsnode, map, playertype, session, stats, teamtype

    expired

    bool

    @@ -4971,6 +5040,12 @@ of the session.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    globalsnode

    +

    ba.Node

    +

    The 'globals' ba.Node for the activity. This contains various + global controls and values.

    +

    map

    ba.Map

    @@ -6303,54 +6378,6 @@ user can override particular game music with their own.

    if 'continuous' is True and musictype is the same as what is already playing, the playing track will not be restarted.

    -
    -

    ba.sharedobj()

    -

    sharedobj(name: str) -> Any

    - -

    Return a predefined object for the current Activity, creating if needed.

    - -

    Category: Gameplay Functions

    - -

    Available values for 'name':

    - -

    'globals': returns the 'globals' ba.Node, containing various global - controls & values.

    - -

    'object_material': a ba.Material that should be applied to any small, - normal, physical objects such as bombs, boxes, players, etc. Other - materials often check for the presence of this material as a - prerequisite for performing certain actions (such as disabling collisions - between initially-overlapping objects)

    - -

    'player_material': a ba.Material to be applied to player parts. Generally, - materials related to the process of scoring when reaching a goal, etc - will look for the presence of this material on things that hit them.

    - -

    'pickup_material': a ba.Material; collision shapes used for picking things - up will have this material applied. To prevent an object from being - picked up, you can add a material that disables collisions against things - containing this material.

    - -

    'footing_material': anything that can be 'walked on' should have this - ba.Material applied; generally just terrain and whatnot. A character will - snap upright whenever touching something with this material so it should - not be applied to props, etc.

    - -

    'attack_material': a ba.Material applied to explosion shapes, punch - shapes, etc. An object not wanting to receive impulse/etc messages can - disable collisions against this material.

    - -

    'death_material': a ba.Material that sends a ba.DieMessage() to anything - that touches it; handy for terrain below a cliff, etc.

    - -

    'region_material': a ba.Material used for non-physical collision shapes - (regions); collisions can generally be allowed with this material even - when initially overlapping since it is not physical.

    - -

    'railing_material': a ba.Material with a very low friction/stiffness/etc - that can be applied to invisible 'railings' useful for gently keeping - characters from falling off of cliffs.

    -

    ba.show_damage_count()

    show_damage_count(damage: str, position: Sequence[float], direction: Sequence[float]) -> None

    From 89d50df4aaea9bea5096b3e95c672d533ad0729b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 29 May 2020 14:23:11 -0700 Subject: [PATCH 053/417] Fix for broken material --- assets/src/ba_data/python/bastd/actor/bomb.py | 81 +++++++++---------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 7eb080b8..757af48d 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -192,8 +192,8 @@ class BombFactory: self.activate_sound = ba.getsound('activateBeep') self.warn_sound = ba.getsound('warnBeep') - # set up our material so new bombs don't collide with objects - # that they are initially overlapping + # Set up our material so new bombs don't collide with objects + # that they are initially overlapping. self.bomb_material = ba.Material() self.normal_sound_material = ba.Material() self.sticky_material = ba.Material() @@ -211,12 +211,12 @@ class BombFactory: actions=('modify_node_collision', 'collide', False), ) - # we want pickup materials to always hit us even if we're currently not - # colliding with their node (generally due to the above rule) - self.bomb_material.add_actions(conditions=('they_have_material', - shared.pickup_material), - actions=('modify_part_collision', - 'use_node_collide', False)) + # We want pickup materials to always hit us even if we're currently + # not colliding with their node. (generally due to the above rule) + self.bomb_material.add_actions( + conditions=('they_have_material', shared.pickup_material), + actions=('modify_part_collision', 'use_node_collide', False), + ) self.bomb_material.add_actions(actions=('modify_part_collision', 'friction', 0.3)) @@ -265,7 +265,7 @@ class BombFactory: self.blast_material = ba.Material() self.blast_material.add_actions( - conditions=(('they_have_material', shared.object_material), ), + conditions=('they_have_material', shared.object_material), actions=( ('modify_part_collision', 'collide', True), ('modify_part_collision', 'physical', False), @@ -278,7 +278,7 @@ class BombFactory: self.sticky_impact_sound = ba.getsound('stickyImpact') self.roll_sound = ba.getsound('bombRoll01') - # collision sounds + # Collision sounds. self.normal_sound_material.add_actions( conditions=('they_have_material', shared.footing_material), actions=( @@ -370,7 +370,7 @@ class Blast(ba.Actor): self.hit_subtype = hit_subtype self.radius = blast_radius - # set our position a bit lower so we throw more things upward + # Set our position a bit lower so we throw more things upward. rmats = (factory.blast_material, shared.attack_material) self.node = ba.newnode( 'region', @@ -385,7 +385,7 @@ class Blast(ba.Actor): ba.timer(0.05, self.node.delete) - # throw in an explosion and flash + # Throw in an explosion and flash. evel = (velocity[0], max(-1.0, velocity[1]), velocity[2]) explosion = ba.newnode('explosion', attrs={ @@ -414,7 +414,7 @@ class Blast(ba.Actor): emit_type='distortion', spread=1.0 if self.blast_type == 'tnt' else 2.0) - # and emit some shrapnel.. + # And emit some shrapnel. if self.blast_type == 'ice': def emit() -> None: @@ -426,7 +426,7 @@ class Blast(ba.Actor): chunk_type='ice', emit_type='stickers') - # looks better if we delay a bit + # It looks better if we delay a bit. ba.timer(0.05, emit) elif self.blast_type == 'sticky': @@ -462,10 +462,10 @@ class Blast(ba.Actor): spread=1.5, chunk_type='spark') - # looks better if we delay a bit + # It looks better if we delay a bit. ba.timer(0.05, emit) - elif self.blast_type == 'impact': # regular bomb shrapnel + elif self.blast_type == 'impact': def emit() -> None: ba.emitfx(position=position, @@ -491,10 +491,10 @@ class Blast(ba.Actor): spread=1.5, chunk_type='spark') - # looks better if we delay a bit + # It looks better if we delay a bit. ba.timer(0.05, emit) - else: # regular or land mine bomb shrapnel + else: # Regular or land mine bomb shrapnel. def emit() -> None: if self.blast_type != 'tnt': @@ -520,7 +520,7 @@ class Blast(ba.Actor): spread=1.5, chunk_type='spark') - # tnt throws splintery chunks + # TNT throws splintery chunks. if self.blast_type == 'tnt': def emit_splinters() -> None: @@ -533,7 +533,7 @@ class Blast(ba.Actor): ba.timer(0.01, emit_splinters) - # every now and then do a sparky one + # Every now and then do a sparky one. if self.blast_type == 'tnt' or random.random() < 0.1: def emit_extra_sparks() -> None: @@ -546,7 +546,7 @@ class Blast(ba.Actor): ba.timer(0.02, emit_extra_sparks) - # looks better if we delay a bit + # It looks better if we delay a bit. ba.timer(0.05, emit) lcolor = ((0.6, 0.6, 1.0) if self.blast_type == 'ice' else @@ -588,7 +588,7 @@ class Blast(ba.Actor): }) ba.timer(scl * 3.0, light.delete) - # make a scorch that fades over time + # Make a scorch that fades over time. scorch = ba.newnode('scorch', attrs={ 'position': position, @@ -610,7 +610,7 @@ class Blast(ba.Actor): ba.camerashake(intensity=5.0 if self.blast_type == 'tnt' else 1.0) - # tnt is more epic.. + # TNT is more epic. if self.blast_type == 'tnt': ba.playsound(factory.random_explode_sound(), position=lpos) @@ -667,7 +667,7 @@ class Bomb(ba.Actor): category: Gameplay Classes """ - # Ew; should try to clean this up later + # Ew; should try to clean this up later. # pylint: disable=too-many-locals # pylint: disable=too-many-branches # pylint: disable=too-many-statements @@ -714,26 +714,21 @@ class Bomb(ba.Actor): self._explode_callbacks: List[Callable[[Bomb, Blast], Any]] = [] - # the player this came from + # The player this came from. self._source_player = source_player - # by default our hit type/subtype is our own, but we pick up types of - # whoever sets us off so we know what caused a chain reaction + # By default our hit type/subtype is our own, but we pick up types of + # whoever sets us off so we know what caused a chain reaction. self.hit_type = 'explosion' self.hit_subtype = self.bomb_type - # if no owner was provided, use an unconnected node ref - # (nevermind; trying to use None in these type cases instead) - # if owner is None: - # owner = ba.Node(None) - - # the node this came from + # The node this came from. self.owner = owner - # adding footing-materials to things can screw up jumping and flying - # since players carrying those things - # and thus touching footing objects will think they're on solid - # ground.. perhaps we don't wanna add this even in the tnt case?.. + # Adding footing-materials to things can screw up jumping and flying + # since players carrying those things and thus touching footing + # objects will think they're on solid ground.. perhaps we don't + # wanna add this even in the tnt case? materials: Tuple[ba.Material, ...] if self.bomb_type == 'tnt': materials = (factory.bomb_material, shared.footing_material, @@ -873,7 +868,8 @@ class Bomb(ba.Actor): def on_expire(self) -> None: super().on_expire() - # release callbacks/refs so we don't wind up with dependency loops.. + + # Release callbacks/refs so we don't wind up with dependency loops. self._explode_callbacks = [] def _handle_die(self) -> None: @@ -946,8 +942,8 @@ class Bomb(ba.Actor): for callback in self._explode_callbacks: callback(self, blast) - # we blew up so we need to go away - # FIXME; was there a reason we need this delay? + # We blew up so we need to go away. + # NOTE TO SELF: do we actually need this delay? ba.timer(0.001, ba.WeakCall(self.handlemessage, ba.DieMessage())) def _handle_warn(self) -> None: @@ -983,6 +979,7 @@ class Bomb(ba.Actor): 'input_textures': intex }) ba.timer(0.5, self.texture_sequence.delete) + # We now make it explodable. ba.timer( 0.25, @@ -1048,8 +1045,8 @@ class Bomb(ba.Actor): self.explode() elif isinstance(msg, ImpactMessage): self._handle_impact() - # Ok the logic below looks like it was backwards to me. Disabling - # until further notice. + # Ok the logic below looks like it was backwards to me. + # Disabling for now; can bring back if need be. # elif isinstance(msg, ba.PickedUpMessage): # # Change our source to whoever just picked us up *only* if it # # is None. This way we can get points for killing bots with their From 6d861f4088b20e6ade4c28ef37252a78c74bdb97 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 29 May 2020 15:51:36 -0700 Subject: [PATCH 054/417] Simplified handlemessage sanity checks --- assets/src/ba_data/python/ba/_actor.py | 27 ++++--------------- .../ba_data/python/bastd/actor/background.py | 3 +-- assets/src/ba_data/python/bastd/actor/bomb.py | 3 +-- .../python/bastd/actor/controlsguide.py | 3 +-- assets/src/ba_data/python/bastd/actor/flag.py | 3 +-- .../src/ba_data/python/bastd/actor/image.py | 3 +-- .../ba_data/python/bastd/actor/playerspaz.py | 14 +++++----- .../ba_data/python/bastd/actor/popuptext.py | 3 +-- .../ba_data/python/bastd/actor/powerupbox.py | 7 +++-- assets/src/ba_data/python/bastd/actor/spaz.py | 7 +++-- .../src/ba_data/python/bastd/actor/spazbot.py | 3 +-- assets/src/ba_data/python/bastd/actor/text.py | 3 +-- .../ba_data/python/bastd/actor/tipstext.py | 3 +-- .../ba_data/python/bastd/actor/zoomtext.py | 3 +-- docs/ba_module.md | 8 +++--- tools/efrotools/filecache.py | 2 +- 16 files changed, 34 insertions(+), 61 deletions(-) diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index c86a7be1..2121940e 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -26,7 +26,7 @@ import weakref from typing import TYPE_CHECKING, TypeVar, overload from ba._messages import DieMessage, DeathType, OutOfBoundsMessage, UNHANDLED -from ba._error import print_error, print_exception, ActivityNotFoundError +from ba._error import print_exception, ActivityNotFoundError import _ba if TYPE_CHECKING: @@ -106,8 +106,7 @@ class Actor: def handlemessage(self, msg: Any) -> Any: """General message handling; can be passed any message object.""" - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired # By default, actors going out-of-bounds simply kill themselves. if isinstance(msg, OutOfBoundsMessage): @@ -135,9 +134,9 @@ class Actor: def on_expire(self) -> None: """Called for remaining ba.Actors when their ba.Activity shuts down. - Actors can use this opportunity to clear callbacks - or other references which have the potential of keeping the - ba.Activity alive inadvertently (Activities can not exit cleanly while + Actors can use this opportunity to clear callbacks or other + references which have the potential of keeping the ba.Activity + alive inadvertently (Activities can not exit cleanly while any Python references to them remain.) Once an actor is expired (see ba.Actor.is_expired()) it should no @@ -189,22 +188,6 @@ class Actor: """ return True - def _handlemessage_sanity_check(self) -> None: - """Make sure things are kosher in handlemessage(). - - Place this in an 'if __debug__:' clause at the top of handlemessage() - overrides. This will will complain if anything is sending the Actor - messages after the activity has ended, which should be explicitly - avoided. - """ - if not __debug__: - print_error('This should only be called in __debug__ mode.', - once=True) - if not getattr(self, '_root_actor_init_called', False): - print_error('Root Actor __init__() not called.') - if self.expired: - print_error(f'handlemessage() called on expired actor: {self}') - @property def activity(self) -> ba.Activity: """The Activity this Actor was created in. diff --git a/assets/src/ba_data/python/bastd/actor/background.py b/assets/src/ba_data/python/bastd/actor/background.py index 86b0031a..60f05f44 100644 --- a/assets/src/ba_data/python/bastd/actor/background.py +++ b/assets/src/ba_data/python/bastd/actor/background.py @@ -150,8 +150,7 @@ class Background(ba.Actor): ba.timer(self.fade_time + 0.1, self.node.delete) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): self._die(msg.immediate) else: diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 757af48d..e33852a5 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -626,8 +626,7 @@ class Blast(ba.Actor): ba.timer(0.4, _extra_debris_sound) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if self.node: diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py index a149ba75..bfb33de6 100644 --- a/assets/src/ba_data/python/bastd/actor/controlsguide.py +++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py @@ -468,8 +468,7 @@ class ControlsGuide(ba.Actor): return not self._dead def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if msg.immediate: self._die() diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index 0e5b014f..b8cad76e 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -343,8 +343,7 @@ class Flag(ba.Actor): 1.0, ba.WeakCall(self._hide_score_text)) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if self.node: self.node.delete() diff --git a/assets/src/ba_data/python/bastd/actor/image.py b/assets/src/ba_data/python/bastd/actor/image.py index 05aff991..9ef97066 100644 --- a/assets/src/ba_data/python/bastd/actor/image.py +++ b/assets/src/ba_data/python/bastd/actor/image.py @@ -181,8 +181,7 @@ class Image(ba.Actor): ba.WeakCall(self.handlemessage, ba.DieMessage())) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if self.node: self.node.delete() diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 1a3375a1..1c706cd0 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -90,6 +90,8 @@ class PlayerSpaz(Spaz): self._player = player self._drive_player_position() + # Overloads to tell the type system our return type based on doraise val. + @overload def getplayer(self, playertype: Type[PlayerType], @@ -144,9 +146,9 @@ class PlayerSpaz(Spaz): player.assign_input_call('upDown', self.on_move_up_down) player.assign_input_call('leftRight', self.on_move_left_right) player.assign_input_call('holdPositionPress', - self._on_hold_position_press) + self.on_hold_position_press) player.assign_input_call('holdPositionRelease', - self._on_hold_position_release) + self.on_hold_position_release) if enable_jump: player.assign_input_call('jumpPress', self.on_jump_press) player.assign_input_call('jumpRelease', self.on_jump_release) @@ -179,7 +181,7 @@ class PlayerSpaz(Spaz): # Send releases for anything in case its held. self.on_move_up_down(0) self.on_move_left_right(0) - self._on_hold_position_release() + self.on_hold_position_release() self.on_jump_release() self.on_pickup_release() self.on_punch_release() @@ -195,8 +197,7 @@ class PlayerSpaz(Spaz): # pylint: disable=too-many-branches # pylint: disable=too-many-statements # pylint: disable=too-many-nested-blocks - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired # Keep track of if we're being held and by who most recently. if isinstance(msg, ba.PickedUpMessage): @@ -292,7 +293,8 @@ class PlayerSpaz(Spaz): if activity is not None and self._player.exists(): activity.handlemessage(PlayerSpazHurtMessage(self)) else: - super().handlemessage(msg) + return super().handlemessage(msg) + return None def _drive_player_position(self) -> None: """Drive our ba.Player's official position diff --git a/assets/src/ba_data/python/bastd/actor/popuptext.py b/assets/src/ba_data/python/bastd/actor/popuptext.py index 134811fe..c3e23809 100644 --- a/assets/src/ba_data/python/bastd/actor/popuptext.py +++ b/assets/src/ba_data/python/bastd/actor/popuptext.py @@ -122,8 +122,7 @@ class PopupText(ba.Actor): lifespan, ba.WeakCall(self.handlemessage, ba.DieMessage())) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if self.node: self.node.delete() diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py index 2af9a7fd..0a4053e1 100644 --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py @@ -293,9 +293,7 @@ class PowerupBox(ba.Actor): self.node.flashing = True def handlemessage(self, msg: Any) -> Any: - # pylint: disable=too-many-branches - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.PowerupAcceptMessage): factory = PowerupBoxFactory.get() @@ -330,4 +328,5 @@ class PowerupBox(ba.Actor): if msg.hit_type != 'punch': self.handlemessage(ba.DieMessage()) else: - super().handlemessage(msg) + return super().handlemessage(msg) + return None diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index 5d769078..8e13d6a4 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -428,7 +428,7 @@ class Spaz(ba.Actor): return self.node.pickup_pressed = False - def _on_hold_position_press(self) -> None: + def on_hold_position_press(self) -> None: """ Called to 'press hold-position' on this spaz; used for player or AI connections. @@ -438,7 +438,7 @@ class Spaz(ba.Actor): self.node.hold_position_pressed = True self._turbo_filter_add_press('holdposition') - def _on_hold_position_release(self) -> None: + def on_hold_position_release(self) -> None: """ Called to 'release hold-position' on this spaz; used for player or AI connections. @@ -695,8 +695,7 @@ class Spaz(ba.Actor): # pylint: disable=too-many-return-statements # pylint: disable=too-many-statements # pylint: disable=too-many-branches - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.PickedUpMessage): if self.node: diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index 303beb37..bd7ebc23 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -510,8 +510,7 @@ class SpazBot(Spaz): def handlemessage(self, msg: Any) -> Any: # pylint: disable=too-many-branches - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired # Keep track of if we're being held and by who most recently. if isinstance(msg, ba.PickedUpMessage): diff --git a/assets/src/ba_data/python/bastd/actor/text.py b/assets/src/ba_data/python/bastd/actor/text.py index 0afccf5b..5864768f 100644 --- a/assets/src/ba_data/python/bastd/actor/text.py +++ b/assets/src/ba_data/python/bastd/actor/text.py @@ -229,8 +229,7 @@ class Text(ba.Actor): ba.WeakCall(self.handlemessage, ba.DieMessage())) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if self.node: self.node.delete() diff --git a/assets/src/ba_data/python/bastd/actor/tipstext.py b/assets/src/ba_data/python/bastd/actor/tipstext.py index 3bd77347..33df2801 100644 --- a/assets/src/ba_data/python/bastd/actor/tipstext.py +++ b/assets/src/ba_data/python/bastd/actor/tipstext.py @@ -103,8 +103,7 @@ class TipsText(ba.Actor): self.node.text = next_tip def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if self.node: self.node.delete() diff --git a/assets/src/ba_data/python/bastd/actor/zoomtext.py b/assets/src/ba_data/python/bastd/actor/zoomtext.py index cade5ca0..192c6d18 100644 --- a/assets/src/ba_data/python/bastd/actor/zoomtext.py +++ b/assets/src/ba_data/python/bastd/actor/zoomtext.py @@ -171,8 +171,7 @@ class ZoomText(ba.Actor): ba.DieMessage())) def handlemessage(self, msg: Any) -> Any: - if __debug__: - self._handlemessage_sanity_check() + assert not self.expired if isinstance(msg, ba.DieMessage): if not self._dying and self.node: self._dying = True diff --git a/docs/ba_module.md b/docs/ba_module.md index 75bccd57..456f465d 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-29 for Ballistica version 1.5.0 build 20033

    +

    last updated on 2020-05-29 for Ballistica version 1.5.0 build 20034

    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!


    @@ -741,9 +741,9 @@ they are Alive or not.

    Called for remaining ba.Actors when their ba.Activity shuts down.

    -

    Actors can use this opportunity to clear callbacks -or other references which have the potential of keeping the -ba.Activity alive inadvertently (Activities can not exit cleanly while +

    Actors can use this opportunity to clear callbacks or other +references which have the potential of keeping the ba.Activity +alive inadvertently (Activities can not exit cleanly while any Python references to them remain.)

    Once an actor is expired (see ba.Actor.is_expired()) it should no diff --git a/tools/efrotools/filecache.py b/tools/efrotools/filecache.py index 4dcf9634..1d582e38 100644 --- a/tools/efrotools/filecache.py +++ b/tools/efrotools/filecache.py @@ -105,7 +105,7 @@ class FileCache: # if anything has been modified, don't write. for fname, mtime in self.mtimes.items(): if os.path.getmtime(fname) != mtime: - print(f'{Clr.YLW}File changed during run:' + print(f'{Clr.MAG}File changed during run:' f' "{fname}"; cache not updated.{Clr.RST}') return out = json.dumps(self.entries) From 95c93a455fd0cbe68ee82e7145b2b60a83243811 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 29 May 2020 16:34:20 -0700 Subject: [PATCH 055/417] Fixed a bug with get_source_player --- assets/src/ba_data/python/ba/_messages.py | 16 +++++++--------- assets/src/ba_data/python/bastd/actor/bomb.py | 14 +++----------- assets/src/ba_data/python/bastd/game/hockey.py | 8 ++++---- .../ba_data/python/bastd/game/targetpractice.py | 3 ++- docs/ba_module.md | 5 +---- 5 files changed, 17 insertions(+), 29 deletions(-) diff --git a/assets/src/ba_data/python/ba/_messages.py b/assets/src/ba_data/python/ba/_messages.py index e97a561a..dba1bfd6 100644 --- a/assets/src/ba_data/python/ba/_messages.py +++ b/assets/src/ba_data/python/ba/_messages.py @@ -301,7 +301,7 @@ class HitMessage: self.velocity_magnitude = velocity_magnitude self.radius = radius - # Invalid refs should never be passed to things. + # We should not be getting passed an invalid ref. assert source_player is None or source_player.exists() self._source_player = source_player self.kick_back = kick_back @@ -313,18 +313,16 @@ class HitMessage: def get_source_player( self, playertype: Type[PlayerType]) -> Optional[PlayerType]: - """Return the source-player if there is one and they still exist. - - The type of player for the current activity should be passed so that - the type-checker properly identifies the returned value as one. - """ + """Return the source-player if one exists and is the provided type.""" player: Any = self._source_player - assert isinstance(player, (playertype, type(None))) # We should not be delivering invalid refs. - # (technically if someone holds on to this message this can happen) + # (we could translate to None here but technically we are changing + # the message delivered which seems wrong) assert player is None or player.exists() - return player + + # Return the player *only* if they're the type given. + return player if isinstance(player, playertype) else None @dataclass diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index e33852a5..6cf5477a 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -852,18 +852,10 @@ class Bomb(ba.Actor): def get_source_player( self, playertype: Type[PlayerType]) -> Optional[PlayerType]: - """Return the source-player if there is one and they still exist. - - The type of player for the current activity should be passed so that - the type-checker properly identifies the returned value as one. - """ + """Return the source-player if one exists and is the provided type.""" player: Any = self._source_player - assert isinstance(player, (playertype, type(None))) - - # We should not be delivering invalid refs. - # (technically if someone holds on to this message this can happen) - assert player is None or player.exists() - return player + return (player if isinstance(player, playertype) and player.exists() + else None) def on_expire(self) -> None: super().on_expire() diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 333a5d19..644f9da3 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -98,12 +98,12 @@ class Puck(ba.Actor): msg.force_direction[2]) # If this hit came from a player, log them as the last to touch us. - splayer = msg.get_source_player(Player) - if splayer is not None: + s_player = msg.get_source_player(Player) + if s_player is not None: activity = self._activity() if activity: - if splayer in activity.players: - self.last_players_to_touch[splayer.team.id] = splayer + if s_player in activity.players: + self.last_players_to_touch[s_player.team.id] = s_player else: super().handlemessage(msg) diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 0c4c0252..7a94f331 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -173,7 +173,8 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): # under us if we hit stuff (don't wanna get points for new targets). player = bomb.get_source_player(Player) if not player: - return # Could happen if they leave after throwing a bomb. + # It's possible the player left after throwing the bomb. + return bullseye = any( target.do_hit_at_position(pos, player) diff --git a/docs/ba_module.md b/docs/ba_module.md index 456f465d..ae318809 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -2584,10 +2584,7 @@ If the time-limit expires, end_game() will be called.

    get_source_player()

    get_source_player(self, playertype: Type[PlayerType]) -> Optional[PlayerType]

    -

    Return the source-player if there is one and they still exist.

    - -

    The type of player for the current activity should be passed so that -the type-checker properly identifies the returned value as one.

    +

    Return the source-player if one exists and is the provided type.

    From c98e645f74c0cdbb223d7a80bd0402206d5b5859 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 29 May 2020 18:22:04 -0700 Subject: [PATCH 056/417] A few game logic bug fixes --- .efrocachemap | 24 ++++---- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/__init__.py | 3 +- assets/src/ba_data/python/ba/_activity.py | 58 ++++++++++--------- assets/src/ba_data/python/ba/_gameactivity.py | 27 ++++----- assets/src/ba_data/python/ba/_player.py | 13 ++--- assets/src/ba_data/python/ba/_session.py | 44 ++++++++++---- assets/src/ba_data/python/bastd/actor/bomb.py | 42 +++++++------- .../ba_data/python/bastd/actor/playerspaz.py | 19 +++--- .../ba_data/python/bastd/actor/scoreboard.py | 4 +- assets/src/ba_data/python/bastd/mainmenu.py | 4 +- docs/ba_module.md | 58 ++++--------------- 12 files changed, 142 insertions(+), 156 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 46f06447..ed3f1d9d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8d/c2/9fd3ab19a28b05160f818f787115", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/67/25/34c42457f20c9d87d538f4f69320", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/3d/39326060f1a1df1b18070d75ade8", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/b7/d63ab7e13f1b9d931b83ef652262", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/45/f4d0bbe6dfa0286b1faaad5d4c0e", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a8/2b/251dcadd37ae0d2c08a0f3bb683d", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/1a/b80f37d9802d40e625b2df3696b1", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/46/fd/6400f9eba88a419487f5d3732e54", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7d/6a/3dc3c77c340471c0a7b79bf077a4", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/97/5d/824c5c71f61d871c904c61fabc56", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/91/92/1f309a3edf4b4aa595ea83472e7a", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d5/3c/fefdeed4e8048332724167fe1442" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/6c/17cfdbdfeac96070b5134251a451", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/52/25/297b9a00058301b85ddb02f6ee09", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/94/a8/e1477ff611c1e1a5a625bffff60c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c6/d8/20917734baac0fdec68f72c41ed7", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ed/2b/0f91bf6faf8efd08890a687d48d7", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1b/cc/88ba8eb1dbd3cc30181d75b4d16e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9e/df/8560a3f6a5394d6e1e4eff3c4225", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/73/e2/8d816aa46639e1200a63c387ad5a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/85/9a/d64a09c882fe8ddd061d37547ea3", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d9/f8/ede540a4757ea9c246b4818abc93", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/33/00/49adaf80c83df4d6d806691676c0", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5e/e3/4a2fd651c619449b0ac47580b442" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 942dc9d2..4afc871e 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=214732868903831008614942145147141302125 +# SOURCES_HASH=34814525496434113316994893689868607574 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 3576a2cd..3a2d949a 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -39,8 +39,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, open_url, widget) from ba._activity import Activity from ba._actor import Actor -from ba._player import (PlayerInfo, Player, playercast, playercast_o, - StandLocation) +from ba._player import PlayerInfo, Player, StandLocation from ba._nodeactor import NodeActor from ba._app import App from ba._coopgame import CoopGameActivity diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index e46bb06d..fb02787c 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -30,7 +30,7 @@ from ba._error import (print_exception, SessionTeamNotFoundError, NodeNotFoundError) from ba._dependency import DependencyComponent from ba._general import Call, verify_object_death -from ba._messages import UNHANDLED +from ba._messages import UNHANDLED, DieMessage, DeathType import _ba if TYPE_CHECKING: @@ -224,7 +224,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): with _ba.Context('empty'): self._expire() - # Inform our owner that we're officially kicking the bucket. + # Inform our owner that we officially kicked the bucket. if self._transitioning_out: session = self._session() if session is not None: @@ -287,19 +287,19 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): """(internal)""" self._has_ended = val - def set_immediate_end(self, results: ba.TeamGameResults, delay: float, - force: bool) -> None: - """Set the activity to die immediately after beginning. + # def set_immediate_end(self, results: ba.TeamGameResults, delay: float, + # force: bool) -> None: + # """Set the activity to die immediately after beginning. - (internal) - """ - if self.has_begun(): - raise RuntimeError('This should only be called for Activities' - 'that have not yet begun.') - if not self._should_end_immediately or force: - self._should_end_immediately = True - self._should_end_immediately_results = results - self._should_end_immediately_delay = delay + # (internal) + # """ + # if self.has_begun(): + # raise RuntimeError('This should only be called for Activities' + # 'that have not yet begun.') + # if not self._should_end_immediately or force: + # self._should_end_immediately = True + # self._should_end_immediately_results = results + # self._should_end_immediately_delay = delay def destroy(self) -> None: """Begin the process of tearing down the activity. @@ -522,20 +522,14 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): for player in session.players: self.add_player(player) - # And finally tell the game to start. - with _ba.Context(self): - self._has_begun = True - self.on_begin() + self._has_begun = True - # If the whole session wants to die and was waiting on us, - # can kick off that process now. - if session.wants_to_end: - session.launch_end_session_activity() - else: - # Otherwise, if we've already been told to die, do so now. - if self._should_end_immediately: - self.end(self._should_end_immediately_results, - self._should_end_immediately_delay) + # Let the activity do its thing. + with _ba.Context(self): + # Note: do we want to catch errors here? + # Currently I believe we wind up canceling the + # activity launch; just wanna be sure that is intentional. + self.on_begin() def end(self, results: Any = None, @@ -636,6 +630,16 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): except Exception: print_exception(f'Error in on_player_leave for {self}') try: + # If they have an actor, kill it. + if player.actor: + player.actor.handlemessage( + DieMessage(how=DeathType.LEFT_GAME)) + player.actor = None + except Exception: + print_exception( + f'Error killing player actor on leave for {self}') + try: + player.reset() sessionplayer.reset() sessionplayer.set_node(None) sessionplayer.set_activity(None) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index aa74790a..a46c5367 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -29,7 +29,7 @@ from typing import TYPE_CHECKING, TypeVar from ba._activity import Activity from ba._score import ScoreInfo from ba._lang import Lstr -from ba._messages import PlayerDiedMessage, StandMessage, DieMessage, DeathType +from ba._messages import PlayerDiedMessage, StandMessage from ba._error import NotFoundError, print_error, print_exception from ba._general import Call, WeakCall from ba._player import PlayerInfo @@ -549,18 +549,19 @@ class GameActivity(Activity[PlayerType, TeamType]): # By default, just spawn a dude. self.spawn_player(player) - def on_player_leave(self, player: PlayerType) -> None: - super().on_player_leave(player) + # def on_player_leave(self, player: PlayerType) -> None: + # super().on_player_leave(player) - # If the player has an actor, send it a deferred die message. - # This way the player will be completely gone from the game - # when the message goes through, making it less likely games - # will incorrectly try to respawn them, etc. - actor = player.actor - if actor is not None: - _ba.pushcall( - Call(actor.handlemessage, DieMessage(how=DeathType.LEFT_GAME))) - player.set_actor(None) + # # If the player has an actor, send it a deferred die message. + # # This way the player will be completely gone from the game + # # when the message goes through, making it less likely games + # # will incorrectly try to respawn them, etc. + # actor = player.actor + # if actor is not None: + # _ba.pushcall( + # Call(actor.handlemessage, + # DieMessage(how=DeathType.LEFT_GAME))) + # player.actor = None def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerDiedMessage): @@ -948,7 +949,7 @@ class GameActivity(Activity[PlayerType, TeamType]): character=player.character, player=player) - player.set_actor(spaz) + player.actor = spaz assert spaz.node # If this is co-op and we're on Courtyard or Runaround, add the diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 9bea0bae..ecc27b4d 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -175,13 +175,6 @@ class Player(Generic[TeamType]): """ return self._sessionplayer.get_name(full=full, icon=icon) - def set_actor(self, actor: Optional[ba.Actor]) -> None: - """set_actor(actor: Optional[ba.Actor]) -> None - - Set the player's associated ba.Actor. - """ - self.actor = actor - def is_alive(self) -> bool: """is_alive() -> bool @@ -223,6 +216,12 @@ class Player(Generic[TeamType]): return self.exists() +# NOTE: It seems we might not need these playercast() calls; have gone +# the direction where things returning players generally take a type arg +# and do this themselves; that way the user is 'forced' to deal with types +# instead of requiring extra work by them. + + def playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType: """Cast a ba.Player to a specific ba.Player subclass. diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 913ee62e..12be8c93 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -175,8 +175,12 @@ class Session: self._activity_end_timer: Optional[ba.Timer] = None self._activity_weak = empty_weakref(Activity) self._next_activity: Optional[ba.Activity] = None - self.wants_to_end = False + self._wants_to_end = False self._ending = False + self._activity_should_end_immediately = False + self._activity_should_end_immediately_results: ( + Optional[ba.TeamGameResults]) = None + self._activity_should_end_immediately_delay = 0.0 # Create static teams if we're using them. if self.use_teams: @@ -324,11 +328,11 @@ class Session: Note that this happens asynchronously, allowing the session and its activities to shut down gracefully. """ - self.wants_to_end = True + self._wants_to_end = True if self._next_activity is None: - self.launch_end_session_activity() + self._launch_end_session_activity() - def launch_end_session_activity(self) -> None: + def _launch_end_session_activity(self) -> None: """(internal)""" from ba._activitytypes import EndSessionActivity from ba._enums import TimeType @@ -341,11 +345,11 @@ class Session: if since_last < 30.0: return print_error( - 'launch_end_session_activity called twice (since_last=' + + '_launch_end_session_activity called twice (since_last=' + str(since_last) + ')') self._launch_end_session_activity_time = curtime self.set_activity(_ba.new_activity(EndSessionActivity)) - self.wants_to_end = False + self._wants_to_end = False self._ending = True # Prevent further actions. def on_team_join(self, team: ba.SessionTeam) -> None: @@ -373,7 +377,11 @@ class Session: # If this activity hasn't begun yet, just set it up to end immediately # once it does. if not activity.has_begun(): - activity.set_immediate_end(results, delay, force) + # activity.set_immediate_end(results, delay, force) + if not self._activity_should_end_immediately or force: + self._activity_should_end_immediately = True + self._activity_should_end_immediately_results = results + self._activity_should_end_immediately_delay = delay # The activity has already begun; get ready to end it. else: @@ -506,7 +514,7 @@ class Session: with _ba.Context(self): result = self.on_player_request(sessionplayer) except Exception: - print_exception('error in on_player_request call for', self) + print_exception(f'Error in on_player_request for {self}') result = False # If the user said yes, add the player to the session list. @@ -540,11 +548,25 @@ class Session: self._activity_retained = self._next_activity self._activity_weak = weakref.ref(self._next_activity) self._next_activity = None + self._activity_should_end_immediately = False # Kick out anyone loitering in the lobby. self.lobby.remove_all_choosers_and_kick_players() + + # Kick off the activity. self._activity_retained.begin(self) + # If we want to go down, we're now free to kick off that process. + if self._wants_to_end: + self._launch_end_session_activity() + else: + # Otherwise, if the activity has already been told to end, + # do so now. + if self._activity_should_end_immediately: + self._activity_retained.end( + self._activity_should_end_immediately_results, + self._activity_should_end_immediately_delay) + def _on_player_ready(self, chooser: ba.Chooser) -> None: """Called when a ba.Player has checked themself ready.""" lobby = chooser.lobby @@ -607,13 +629,13 @@ class Session: # referencing the chooser which could inadvertently keep it alive. sessionplayer.reset_input() - # Pass it to the current activity if it has already begun + # We can pass it to the current activity if it has already begun # (otherwise it'll get passed once begin is called). pass_to_activity = (activity.has_begun() and not activity.is_joining_activity) - # If we're not allowing mid-game joins, don't pass; just announce - # the arrival and say they'll partake next round. + # However, if we're not allowing mid-game joins, don't actually pass; + # just announce the arrival and say they'll partake next round. if pass_to_activity: if not self.allow_mid_activity_joins: pass_to_activity = False diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 6cf5477a..f5a4b6cd 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -150,6 +150,17 @@ class BombFactory: ba.Sound for a rolling bomb. """ + @staticmethod + def get() -> BombFactory: + """Get/create a shared bastd.actor.bomb.BombFactory object.""" + activity = ba.getactivity() + factory = getattr(activity, STORAGE_ATTR_NAME, None) + if factory is None: + factory = BombFactory() + setattr(activity, STORAGE_ATTR_NAME, factory) + assert isinstance(factory, BombFactory) + return factory + def random_explode_sound(self) -> ba.Sound: """Return a random explosion ba.Sound from the factory.""" return self.explode_sounds[random.randrange(len(self.explode_sounds))] @@ -301,17 +312,6 @@ class BombFactory: ) -def get_factory() -> BombFactory: - """Get/create a shared bastd.actor.bomb.BombFactory object.""" - activity = ba.getactivity() - factory = getattr(activity, STORAGE_ATTR_NAME, None) - if factory is None: - factory = BombFactory() - setattr(activity, STORAGE_ATTR_NAME, factory) - assert isinstance(factory, BombFactory) - return factory - - class SplatMessage: """Tells an object to make a splat noise.""" @@ -335,9 +335,6 @@ class WarnMessage: class ExplodeHitMessage: """Tell an object it was hit by an explosion.""" - def __init__(self) -> None: - pass - class Blast(ba.Actor): """An explosion, as generated by a bomb or some other object. @@ -362,7 +359,7 @@ class Blast(ba.Actor): super().__init__() shared = SharedObjects.get() - factory = get_factory() + factory = BombFactory.get() self.blast_type = blast_type self._source_player = source_player @@ -653,11 +650,14 @@ class Blast(ba.Actor): radius=self.radius, source_player=ba.existing(self._source_player))) if self.blast_type == 'ice': - ba.playsound(get_factory().freeze_sound, 10, position=nodepos) + ba.playsound(BombFactory.get().freeze_sound, + 10, + position=nodepos) node.handlemessage(ba.FreezeMessage()) else: - super().handlemessage(msg) + return super().handlemessage(msg) + return None class Bomb(ba.Actor): @@ -687,7 +687,7 @@ class Bomb(ba.Actor): super().__init__() shared = SharedObjects.get() - factory = get_factory() + factory = BombFactory.get() if bomb_type not in ('ice', 'impact', 'land_mine', 'normal', 'sticky', 'tnt'): @@ -906,7 +906,7 @@ class Bomb(ba.Actor): and ba.time() - self._last_sticky_sound_time > 1.0): self._last_sticky_sound_time = ba.time() assert self.node - ba.playsound(get_factory().sticky_impact_sound, + ba.playsound(BombFactory.get().sticky_impact_sound, 2.0, position=self.node.position) @@ -940,7 +940,7 @@ class Bomb(ba.Actor): def _handle_warn(self) -> None: if self.texture_sequence and self.node: self.texture_sequence.rate = 30 - ba.playsound(get_factory().warn_sound, + ba.playsound(BombFactory.get().warn_sound, 0.5, position=self.node.position) @@ -959,7 +959,7 @@ class Bomb(ba.Actor): """ if not self.node: return - factory = get_factory() + factory = BombFactory.get() intex: Sequence[ba.Texture] if self.bomb_type == 'land_mine': intex = (factory.land_mine_lit_tex, factory.land_mine_tex) diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 1c706cd0..0019b7d8 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -201,26 +201,23 @@ class PlayerSpaz(Spaz): # Keep track of if we're being held and by who most recently. if isinstance(msg, ba.PickedUpMessage): - super().handlemessage(msg) # Augment standard behavior. + # Augment standard behavior. + super().handlemessage(msg) self.held_count += 1 - picked_up_by = ba.playercast_o(type(self._player), - msg.node.source_player) + picked_up_by = msg.node.source_player if picked_up_by: self.last_player_held_by = picked_up_by elif isinstance(msg, ba.DroppedMessage): - super().handlemessage(msg) # Augment standard behavior. + # Augment standard behavior. + super().handlemessage(msg) self.held_count -= 1 if self.held_count < 0: print('ERROR: spaz held_count < 0') # Let's count someone dropping us as an attack. - try: - picked_up_by_2 = ba.playercast_o(type(self._player), - msg.node.source_player) - except Exception: - picked_up_by_2 = None - if picked_up_by_2: - self.last_player_attacked_by = picked_up_by_2 + picked_up_by = msg.node.source_player + if picked_up_by: + self.last_player_attacked_by = picked_up_by self.last_attacked_time = ba.time() self.last_attacked_type = ('picked_up', 'default') elif isinstance(msg, ba.StandMessage): diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py index 7ed874fc..1dd1659b 100644 --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py @@ -325,8 +325,10 @@ class _EntryProxy: scoreboard = self._scoreboard() # Remove our team from the scoreboard if its still around. + # (but deferred, in case we die in a sim step or something where + # its illegal to modify nodes) if scoreboard is not None: - scoreboard.remove_team(self._team_id) + ba.pushcall(ba.Call(scoreboard.remove_team, self._team_id)) class Scoreboard: diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 61cfb0f2..9a70b78b 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -880,8 +880,8 @@ def _preload2() -> None: 'dripity', 'spawn', 'gong' ]: ba.getsound(sname) - from bastd.actor import bomb - bomb.get_factory() + from bastd.actor.bomb import BombFactory + BombFactory.get() ba.timer(0.1, _preload3) diff --git a/docs/ba_module.md b/docs/ba_module.md index ae318809..71e4cb0a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-29 for Ballistica version 1.5.0 build 20034

    +

    last updated on 2020-05-29 for Ballistica version 1.5.0 build 20035

    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!


    @@ -57,8 +57,6 @@
  • ba.getnodes()
  • ba.getsession()
  • ba.newnode()
  • -
  • ba.playercast()
  • -
  • ba.playercast_o()
  • ba.playsound()
  • ba.printnodes()
  • ba.setmusic()
  • @@ -1597,7 +1595,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -1687,7 +1685,7 @@ there is no associated Campaign.

    Methods Inherited:

    -
    begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>, get_current_game_instance(), get_custom_menu_entries(), on_activity_end(), on_player_leave(), restart()
    @@ -2038,7 +2036,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    -
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>

    @@ -2084,7 +2082,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    -
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), launch_end_session_activity(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>, get_ffa_point_awards()
    @@ -2182,9 +2180,9 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), set_immediate_end(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), transition_in(), transition_out()

    Methods Defined or Overridden:

    -
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_player_leave(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    +
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    ba.GameActivity(settings: Dict[str, Any])

    @@ -2479,12 +2477,6 @@ whatever is relevant to keep the game going.

    (including the initial set of Players)

    -
    -

    on_player_leave()

    -

    on_player_leave(self, player: PlayerType) -> None

    - -

    Called when a ba.Player is leaving the Activity.

    -

    on_transition_in()

    on_transition_in(self) -> None

    @@ -3375,7 +3367,7 @@ Use ba.getmodel() to instantiate one.

    Methods Inherited:

    -
    begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), launch_end_session_activity(), on_player_leave(), on_player_request(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), on_player_leave(), on_player_request(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>, announce_game_results(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), on_activity_end(), on_team_join()
    @@ -3882,7 +3874,7 @@ even if myactor is set to None.

    Methods:

    -
    assign_input_call(), exists(), get_icon(), get_name(), is_alive(), reset_input(), set_actor()
    +
    assign_input_call(), exists(), get_icon(), get_name(), is_alive(), reset_input()

    assign_input_call()

    assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    @@ -3943,14 +3935,6 @@ is_alive() method return True. False is returned otherwise.

    Clears out the player's assigned input actions.

    -
    -

    set_actor()

    -

    set_actor(self, actor: Optional[ba.Actor]) -> None

    - -

    set_actor(actor: Optional[ba.Actor]) -> None

    - -

    Set the player's associated ba.Actor.

    -

    @@ -5077,7 +5061,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), set_immediate_end(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    @@ -6161,28 +6145,6 @@ object dies. 'owner' can be another node or a ba.Actor

    Open the provided url in a web-browser, or display the URL string in a window if that isn't possible.

    -
    -

    ba.playercast()

    -

    playercast(totype: Type[PlayerType], player: ba.Player) -> PlayerType

    - -

    Cast a ba.Player to a specific ba.Player subclass.

    - -

    Category: Gameplay Functions

    - -

    When writing type-checked code, sometimes code will deal with raw -ba.Player objects which need to be cast back to the game's actual -player type so that access can be properly type-checked. This function -is a safe way to do so. It ensures that Optional values are not cast -into Non-Optional, etc.

    - -
    -

    ba.playercast_o()

    -

    playercast_o(totype: Type[PlayerType], player: Optional[ba.Player]) -> Optional[PlayerType]

    - -

    A variant of ba.playercast() for use with optional ba.Player values.

    - -

    Category: Gameplay Functions

    -

    ba.playsound()

    playsound(sound: Sound, volume: float = 1.0, From 83e7388d497101d3e9aceb4b5fcce6545862d5a6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 30 May 2020 12:21:44 -0700 Subject: [PATCH 057/417] Tidying --- assets/src/ba_data/python/ba/_activity.py | 9 ++------ .../src/ba_data/python/ba/_activitytypes.py | 6 ++--- assets/src/ba_data/python/ba/_actor.py | 1 - assets/src/ba_data/python/ba/_benchmark.py | 12 +++++----- assets/src/ba_data/python/ba/_gameactivity.py | 23 ++++--------------- .../ba_data/python/ba/_multiteamsession.py | 23 ++++++++++--------- assets/src/ba_data/python/ba/_session.py | 5 +--- assets/src/ba_data/python/ba/_teamgame.py | 5 ++-- .../python/bastd/activity/coopscore.py | 2 +- .../python/bastd/activity/drawscore.py | 9 ++------ .../ba_data/python/bastd/game/runaround.py | 2 +- docs/ba_module.md | 2 +- 12 files changed, 37 insertions(+), 62 deletions(-) diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index fb02787c..95a1ae80 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -118,7 +118,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # Set this to true to inherit VR camera offsets from the previous # activity (useful for preventing sporadic camera movement # during transitions). - inherits_camera_vr_offset = False + inherits_vr_camera_offset = False # Set this to true to inherit (non-fixed) VR overlay positioning from # the previous activity (useful for prevent sporadic overlay jostling @@ -168,7 +168,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._setup_player_and_team_types() # FIXME: Relocate or remove the need for this stuff. - self.sharedobjs: Dict[str, Any] = {} self.paused_text: Optional[ba.Actor] = None self.spaz_respawn_icons_right: Dict[int, RespawnIcon] @@ -188,10 +187,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._has_transitioned_in = False self._has_begun = False self._has_ended = False - self._should_end_immediately = False - self._should_end_immediately_results: ( - Optional[ba.TeamGameResults]) = None - self._should_end_immediately_delay = 0.0 self._activity_death_check_timer: Optional[ba.Timer] = None self._expired = False @@ -463,7 +458,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): glb.music_continuous = True # Prevent restarting same music. glb.music = prev_globals.music glb.music_count += 1 - if self.inherits_camera_vr_offset and prev_globals is not None: + if self.inherits_vr_camera_offset and prev_globals is not None: glb.vr_camera_offset = prev_globals.vr_camera_offset if self.inherits_vr_overlay_center and prev_globals is not None: glb.vr_overlay_center = prev_globals.vr_overlay_center diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index 20986457..be0b79d8 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -46,7 +46,7 @@ class EndSessionActivity(Activity[Player, Team]): self.transition_time = 0.25 self.inherits_tint = True self.inherits_slow_motion = True - self.inherits_camera_vr_offset = True + self.inherits_vr_camera_offset = True self.inherits_vr_overlay_center = True def on_transition_in(self) -> None: @@ -114,7 +114,7 @@ class TransitionActivity(Activity[Player, Team]): self.transition_time = 0.5 self.inherits_slow_motion = True # Don't change. self.inherits_tint = True # Don't change. - self.inherits_camera_vr_offset = True # Don't change. + self.inherits_vr_camera_offset = True # Don't change. self.inherits_vr_overlay_center = True self.use_fixed_vr_overlay = True self._background: Optional[ba.Actor] = None @@ -144,7 +144,7 @@ class ScoreScreenActivity(Activity[Player, Team]): super().__init__(settings) self.transition_time = 0.5 self.inherits_tint = True - self.inherits_camera_vr_offset = True + self.inherits_vr_camera_offset = True self.use_fixed_vr_overlay = True self.default_music: Optional[MusicType] = MusicType.SCORES self._birth_time = _ba.time() diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index 2121940e..6fa9ea57 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -171,7 +171,6 @@ class Actor: so a simple "if myactor" test will conveniently do the right thing even if myactor is set to None. """ - return True def __bool__(self) -> bool: diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index ac9fb011..31be7db1 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -78,7 +78,7 @@ def run_stress_test(playlist_type: str = 'Random', from ba._enums import TimeType _ba.screenmessage( 'Beginning stress test.. use ' - '\'End Game\' to stop testing.', + "'End Game' to stop testing.", color=(1, 1, 0)) with _ba.Context('ui'): start_stress_test({ @@ -112,7 +112,7 @@ def start_stress_test(args: Dict[str, Any]) -> None: from ba._dualteamsession import DualTeamSession from ba._freeforallsession import FreeForAllSession from ba._enums import TimeType, TimeFormat - bs_config = _ba.app.config + appconfig = _ba.app.config playlist_type = args['playlist_type'] if playlist_type == 'Random': if random.random() < 0.5: @@ -122,15 +122,15 @@ def start_stress_test(args: Dict[str, Any]) -> None: _ba.screenmessage('Running Stress Test (listType="' + playlist_type + '", listName="' + args['playlist_name'] + '")...') if playlist_type == 'Teams': - bs_config['Team Tournament Playlist Selection'] = args['playlist_name'] - bs_config['Team Tournament Playlist Randomize'] = 1 + appconfig['Team Tournament Playlist Selection'] = args['playlist_name'] + appconfig['Team Tournament Playlist Randomize'] = 1 _ba.timer(1.0, Call(_ba.pushcall, Call(_ba.new_host_session, DualTeamSession)), timetype=TimeType.REAL) else: - bs_config['Free-for-All Playlist Selection'] = args['playlist_name'] - bs_config['Free-for-All Playlist Randomize'] = 1 + appconfig['Free-for-All Playlist Selection'] = args['playlist_name'] + appconfig['Free-for-All Playlist Randomize'] = 1 _ba.timer(1.0, Call(_ba.pushcall, Call(_ba.new_host_session, FreeForAllSession)), diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index a46c5367..1fdd940f 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -549,20 +549,6 @@ class GameActivity(Activity[PlayerType, TeamType]): # By default, just spawn a dude. self.spawn_player(player) - # def on_player_leave(self, player: PlayerType) -> None: - # super().on_player_leave(player) - - # # If the player has an actor, send it a deferred die message. - # # This way the player will be completely gone from the game - # # when the message goes through, making it less likely games - # # will incorrectly try to respawn them, etc. - # actor = player.actor - # if actor is not None: - # _ba.pushcall( - # Call(actor.handlemessage, - # DieMessage(how=DeathType.LEFT_GAME))) - # player.actor = None - def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerDiedMessage): # pylint: disable=cyclic-import @@ -759,7 +745,7 @@ class GameActivity(Activity[PlayerType, TeamType]): tip = tip['tip'] assert isinstance(tip, str) - # A few substitutions... + # Do a few substitutions. tip_lstr = Lstr(translate=('tips', tip), subs=[('${PICKUP}', _ba.charstr(SpecialChar.TOP_BUTTON))]) @@ -1104,10 +1090,11 @@ class GameActivity(Activity[PlayerType, TeamType]): if duration <= 0.0: return self._tournament_time_limit = int(duration) - # we want this timer to match the server's time as close as possible, - # so lets go with base-time.. theoretically we should do real-time but + + # We want this timer to match the server's time as close as possible, + # so lets go with base-time. Theoretically we should do real-time but # then we have to mess with contexts and whatnot since its currently - # not available in activity contexts... :-/ + # not available in activity contexts. :-/ self._tournament_time_limit_timer = _ba.Timer( 1.0, WeakCall(self._tournament_time_limit_tick), diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index d25165f1..25f5ab9f 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -254,14 +254,14 @@ class MultiTeamSession(Session): """ # pylint: disable=cyclic-import # pylint: disable=too-many-locals - from ba import _math - from ba import _general + from ba._math import normalized_color + from ba._general import Call from ba._gameutils import cameraflash - from ba import _lang + from ba._lang import Lstr from ba._freeforallsession import FreeForAllSession from ba._messages import CelebrateMessage - _ba.timer(delay, - _general.Call(_ba.playsound, _ba.getsound('boxingBell'))) + _ba.timer(delay, Call(_ba.playsound, _ba.getsound('boxingBell'))) + if announce_winning_team: winning_team = results.get_winning_team() if winning_team is not None: @@ -278,12 +278,13 @@ class MultiTeamSession(Session): wins_resource = 'winsPlayerText' else: wins_resource = 'winsTeamText' - wins_text = _lang.Lstr(resource=wins_resource, - subs=[('${NAME}', winning_team.name)]) - activity.show_zoom_message(wins_text, - scale=0.85, - color=_math.normalized_color( - winning_team.color)) + wins_text = Lstr(resource=wins_resource, + subs=[('${NAME}', winning_team.name)]) + activity.show_zoom_message( + wins_text, + scale=0.85, + color=normalized_color(winning_team.color), + ) class ShuffleList: diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 12be8c93..61154cca 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -158,10 +158,8 @@ class Session: # Init our C++ layer data. self._sessiondata = _ba.register_session(self) - # Stuff in this section should be removed from this class if possible. + # Should remove this if possible. self.tournament_id: Optional[str] = None - self.sharedobjs: Dict[str, Any] = {} - self.have_shown_controls_help_overlay = False self.teams = [] self.players = [] @@ -193,7 +191,6 @@ class Session: color=color) self.teams.append(team) self._next_team_id += 1 - try: with _ba.Context(self): self.on_team_join(team) diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index 47c86520..c34a67b4 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -77,7 +77,8 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): # (unless we're being run in co-op mode, in which case we leave # it up to them) if not isinstance(self.session, CoopSession): - if not self.session.have_shown_controls_help_overlay: + attrname = '_have_shown_ctrl_help_overlay' + if not getattr(self.session, attrname, False): delay = 4.0 lifespan = 10.0 if self.slow_motion: @@ -87,7 +88,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): scale=0.8, position=(380, 200), bright=True).autoretain() - self.session.have_shown_controls_help_overlay = True + setattr(self.session, attrname, True) def on_begin(self) -> None: super().on_begin() diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 4e1bacdb..e09d8d4c 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -48,7 +48,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): # Keep prev activity alive while we fade in self.transition_time = 0.5 self.inherits_tint = True - self.inherits_camera_vr_offset = True + self.inherits_vr_camera_offset = True self.inherits_music = True self.use_fixed_vr_overlay = True diff --git a/assets/src/ba_data/python/bastd/activity/drawscore.py b/assets/src/ba_data/python/bastd/activity/drawscore.py index 4c5a5658..9508325e 100644 --- a/assets/src/ba_data/python/bastd/activity/drawscore.py +++ b/assets/src/ba_data/python/bastd/activity/drawscore.py @@ -26,6 +26,7 @@ from typing import TYPE_CHECKING import ba from bastd.activity.multiteamscore import MultiTeamScoreScreenActivity +from bastd.actor.zoomtext import ZoomText if TYPE_CHECKING: from typing import Any, Dict @@ -34,15 +35,9 @@ if TYPE_CHECKING: class DrawScoreScreenActivity(MultiTeamScoreScreenActivity): """Score screen shown after a draw.""" - def __init__(self, settings: Dict[str, Any]): - super().__init__(settings=settings) - - def on_transition_in(self) -> None: - self.default_music = None # Awkward silence... - super().on_transition_in() + default_music = None # Awkward silence... def on_begin(self) -> None: - from bastd.actor.zoomtext import ZoomText ba.set_analytics_screen('Draw Score Screen') super().on_begin() ZoomText(ba.Lstr(resource='drawText'), diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index b268fe4f..c303f557 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -90,7 +90,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): settings['map'] = 'Tower D' super().__init__(settings) shared = SharedObjects.get() - self._preset = self.settings_raw.get('preset', 'pro') + self._preset = str(settings.get('preset', 'pro')) self._player_death_sound = ba.getsound('playerDeath') self._new_wave_sound = ba.getsound('scoreHit01') diff --git a/docs/ba_module.md b/docs/ba_module.md index 71e4cb0a..ae19599f 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-29 for Ballistica version 1.5.0 build 20035

    +

    last updated on 2020-05-30 for Ballistica version 1.5.0 build 20035

    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!


    From 1c0e4896fa3797965488368072c27bacefc8d272 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 30 May 2020 15:05:28 -0700 Subject: [PATCH 058/417] Bit more tidying --- .efrocachemap | 24 +++--- assets/src/ba_data/python/_ba.py | 20 ++--- assets/src/ba_data/python/ba/_activity.py | 14 --- assets/src/ba_data/python/ba/_analytics.py | 4 +- assets/src/ba_data/python/ba/_gameactivity.py | 14 +-- assets/src/ba_data/python/ba/_input.py | 14 +-- assets/src/ba_data/python/ba/_lobby.py | 10 +-- assets/src/ba_data/python/ba/_map.py | 6 +- assets/src/ba_data/python/ba/_player.py | 6 +- assets/src/ba_data/python/ba/_profile.py | 10 +-- assets/src/ba_data/python/ba/_session.py | 85 ++++++++++-------- assets/src/ba_data/python/ba/_stats.py | 20 ++--- .../bastd/activity/freeforallvictory.py | 6 +- .../python/bastd/activity/multiteamscore.py | 2 +- .../python/bastd/activity/multiteamvictory.py | 4 +- .../ba_data/python/bastd/actor/respawnicon.py | 2 +- .../ba_data/python/bastd/game/elimination.py | 4 +- .../ba_data/python/bastd/game/meteorshower.py | 2 +- .../ba_data/python/bastd/game/onslaught.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 4 +- .../python/bastd/game/targetpractice.py | 2 +- .../ba_data/python/bastd/ui/coop/browser.py | 2 +- assets/src/ba_data/python/bastd/ui/kiosk.py | 30 +++---- .../src/ba_data/python/bastd/ui/mainmenu.py | 2 +- .../python/bastd/ui/playlist/browser.py | 8 +- .../ba_data/python/bastd/ui/playlist/edit.py | 2 +- .../bastd/ui/playlist/editcontroller.py | 12 +-- .../ba_data/python/bastd/ui/profile/edit.py | 8 +- .../python/bastd/ui/profile/upgrade.py | 2 +- .../python/bastd/ui/settings/keyboard.py | 14 ++- .../python/bastd/ui/soundtrack/edit.py | 10 +-- .../python/bastd/ui/teamnamescolors.py | 6 +- docs/ba_module.md | 86 +++++++++---------- 33 files changed, 216 insertions(+), 221 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index ed3f1d9d..837369e8 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/6c/17cfdbdfeac96070b5134251a451", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/52/25/297b9a00058301b85ddb02f6ee09", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/94/a8/e1477ff611c1e1a5a625bffff60c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c6/d8/20917734baac0fdec68f72c41ed7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ed/2b/0f91bf6faf8efd08890a687d48d7", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1b/cc/88ba8eb1dbd3cc30181d75b4d16e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9e/df/8560a3f6a5394d6e1e4eff3c4225", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/73/e2/8d816aa46639e1200a63c387ad5a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/85/9a/d64a09c882fe8ddd061d37547ea3", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d9/f8/ede540a4757ea9c246b4818abc93", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/33/00/49adaf80c83df4d6d806691676c0", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5e/e3/4a2fd651c619449b0ac47580b442" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/36/5a/025457e87759c13a5067617816cd", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/49/fb5663472ab1f4bd32f5748ba4d7", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/3e/6eb652f11d24c22f87ae8aab399b", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f4/57/7e48692454b644a7111902f12b58", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/55/246021de09b021993e8bdbdb19a6", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/ea/079aa2649359d2024b7c20dd19d0", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/05/5d/2608f732d75799cfe09c6947736a", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/20/4f2abb279d24dced1f11f83fbe78", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f9/36/28081d9962d3f91c286663357e80", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/51/55/83ceb6ffb806c75815e5f9e88008", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/ea/461f76e113d3a02da3c61ea04bdb", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/83/af/a8ce32760e4dc300ac861f745615" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 4afc871e..8471f307 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=34814525496434113316994893689868607574 +# SOURCES_HASH=33373537027192610824913965080968605548 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -727,13 +727,6 @@ class Node: """ return bool() - def get_name(self) -> str: - """get_name() -> str - - Return the name assigned to a Node; used mainly for debugging - """ - return str() - # Show that ur return type varies based on "doraise" value: @overload def getdelegate(self, @@ -756,6 +749,13 @@ class Node: """ return None + def getname(self) -> str: + """getname() -> str + + Return the name assigned to a Node; used mainly for debugging + """ + return str() + def getnodetype(self) -> str: """getnodetype() -> str @@ -915,8 +915,8 @@ class SessionPlayer: """ return {'foo': 'bar'} - def get_name(self, full: bool = False, icon: bool = True) -> str: - """get_name(full: bool = False, icon: bool = True) -> str + def getname(self, full: bool = False, icon: bool = True) -> str: + """getname(full: bool = False, icon: bool = True) -> str Returns the player's name. If icon is True, the long version of the name may include an icon. diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 95a1ae80..ff9203c0 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -282,20 +282,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): """(internal)""" self._has_ended = val - # def set_immediate_end(self, results: ba.TeamGameResults, delay: float, - # force: bool) -> None: - # """Set the activity to die immediately after beginning. - - # (internal) - # """ - # if self.has_begun(): - # raise RuntimeError('This should only be called for Activities' - # 'that have not yet begun.') - # if not self._should_end_immediately or force: - # self._should_end_immediately = True - # self._should_end_immediately_results = results - # self._should_end_immediately_delay = delay - def destroy(self) -> None: """Begin the process of tearing down the activity. diff --git a/assets/src/ba_data/python/ba/_analytics.py b/assets/src/ba_data/python/ba/_analytics.py index 948629e0..8448c963 100644 --- a/assets/src/ba_data/python/ba/_analytics.py +++ b/assets/src/ba_data/python/ba/_analytics.py @@ -62,7 +62,7 @@ def game_begin_analytics() -> None: _ba.increment_analytics_count('Co-op round start 4+ human players') elif isinstance(session, DualTeamSession): - _ba.set_analytics_screen('Teams Game: ' + activity.get_name()) + _ba.set_analytics_screen('Teams Game: ' + activity.getname()) _ba.increment_analytics_count('Teams round start') if len(activity.players) == 1: _ba.increment_analytics_count('Teams round start 1 human player') @@ -74,7 +74,7 @@ def game_begin_analytics() -> None: _ba.increment_analytics_count('Teams round start 8+ human players') elif isinstance(session, FreeForAllSession): - _ba.set_analytics_screen('FreeForAll Game: ' + activity.get_name()) + _ba.set_analytics_screen('FreeForAll Game: ' + activity.getname()) _ba.increment_analytics_count('Free-for-all round start') if len(activity.players) == 1: _ba.increment_analytics_count( diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 1fdd940f..099ca094 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -56,7 +56,7 @@ class GameActivity(Activity[PlayerType, TeamType]): tips: List[Union[str, Dict[str, Any]]] = [] - # Default get_name() will return this if not None. + # Default getname() will return this if not None. name: Optional[str] = None # Default get_description() will return this if not None. @@ -112,7 +112,7 @@ class GameActivity(Activity[PlayerType, TeamType]): return cls.score_info if cls.score_info is not None else ScoreInfo() @classmethod - def get_name(cls) -> str: + def getname(cls) -> str: """Return a str name for this game type. This default implementation simply returns the 'name' class attr. @@ -123,9 +123,9 @@ class GameActivity(Activity[PlayerType, TeamType]): def get_display_string(cls, settings: Optional[Dict] = None) -> ba.Lstr: """Return a descriptive name for this game/settings combo. - Subclasses should override get_name(); not this. + Subclasses should override getname(); not this. """ - name = Lstr(translate=('gameNames', cls.get_name())) + name = Lstr(translate=('gameNames', cls.getname())) # A few substitutions for 'Epic', 'Solo' etc. modes. # FIXME: Should provide a way for game types to define filters of @@ -512,7 +512,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # Store some basic info about players present at start time. self.initial_player_info = [ - PlayerInfo(name=p.get_name(full=True), character=p.character) + PlayerInfo(name=p.getname(full=True), character=p.character) for p in self.players ] @@ -924,7 +924,7 @@ class GameActivity(Activity[PlayerType, TeamType]): from ba._gameutils import animate from ba._coopsession import CoopSession from bastd.actor.playerspaz import PlayerSpaz - name = player.get_name() + name = player.getname() color = player.color highlight = player.highlight @@ -941,7 +941,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # If this is co-op and we're on Courtyard or Runaround, add the # material that allows us to collide with the player-walls. # FIXME: Need to generalize this. - if isinstance(self.session, CoopSession) and self.map.get_name() in [ + if isinstance(self.session, CoopSession) and self.map.getname() in [ 'Courtyard', 'Tower D' ]: mat = self.map.preloaddata['collide_with_wall_material'] diff --git a/assets/src/ba_data/python/ba/_input.py b/assets/src/ba_data/python/ba/_input.py index b4d87cec..403e0a13 100644 --- a/assets/src/ba_data/python/ba/_input.py +++ b/assets/src/ba_data/python/ba/_input.py @@ -45,11 +45,11 @@ def get_device_value(device: ba.InputDevice, name: str) -> Any: useragentstring = app.user_agent_string platform = app.platform subplatform = app.subplatform - bs_config = _ba.app.config + appconfig = _ba.app.config # If there's an entry in our config for this controller, use it. - if 'Controllers' in bs_config: - ccfgs = bs_config['Controllers'] + if 'Controllers' in appconfig: + ccfgs = appconfig['Controllers'] if devicename in ccfgs: mapping = None if unique_id in ccfgs[devicename]: @@ -621,15 +621,15 @@ def get_last_player_name_from_input_device(device: ba.InputDevice) -> str: (generally the last one used there) """ - bs_config = _ba.app.config + appconfig = _ba.app.config # Look for a default player profile name for them; # otherwise default to their current random name. profilename = '_random' key_name = device.name + ' ' + device.unique_identifier - if ('Default Player Profiles' in bs_config - and key_name in bs_config['Default Player Profiles']): - profilename = bs_config['Default Player Profiles'][key_name] + if ('Default Player Profiles' in appconfig + and key_name in appconfig['Default Player Profiles']): + profilename = appconfig['Default Player Profiles'][key_name] if profilename == '_random': profilename = device.get_default_player_name() if profilename == '__account__': diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 8d4716fe..efd5b084 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -455,7 +455,7 @@ class Chooser: def _do_nothing(self) -> None: """Does nothing! (hacky way to disable callbacks)""" - def _get_name(self, full: bool = False) -> str: + def _getname(self, full: bool = False) -> str: name_raw = name = self._profilenames[self._profileindex] clamp = False if name == '_random': @@ -569,8 +569,8 @@ class Chooser: _ba.app.config.commit() # Set this player's short and full name. - self._player.set_name(self._get_name(), - self._get_name(full=True), + self._player.set_name(self._getname(), + self._getname(full=True), real=True) self._ready = True self._update_text() @@ -685,12 +685,12 @@ class Chooser: # Once we're ready, we've saved the name, so lets ask the system # for it so we get appended numbers and stuff. - text = Lstr(value=self._player.get_name(full=True)) + text = Lstr(value=self._player.getname(full=True)) text = Lstr(value='${A} (${B})', subs=[('${A}', text), ('${B}', Lstr(resource='readyText'))]) else: - text = Lstr(value=self._get_name(full=True)) + text = Lstr(value=self._getname(full=True)) can_switch_teams = len(self.lobby.teams) > 1 diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py index ead68a99..005c236f 100644 --- a/assets/src/ba_data/python/ba/_map.py +++ b/assets/src/ba_data/python/ba/_map.py @@ -192,7 +192,7 @@ class Map(Actor): return None @classmethod - def get_name(cls) -> str: + def getname(cls) -> str: """Return the unique name of this map, in English.""" return cls.name @@ -231,14 +231,14 @@ class Map(Actor): # Set area-of-interest bounds. aoi_bounds = self.get_def_bound_box('area_of_interest_bounds') if aoi_bounds is None: - print('WARNING: no "aoi_bounds" found for map:', self.get_name()) + print('WARNING: no "aoi_bounds" found for map:', self.getname()) aoi_bounds = (-1, -1, -1, 1, 1, 1) gnode.area_of_interest_bounds = aoi_bounds # Set map bounds. map_bounds = self.get_def_bound_box('map_bounds') if map_bounds is None: - print('WARNING: no "map_bounds" found for map:', self.get_name()) + print('WARNING: no "map_bounds" found for map:', self.getname()) map_bounds = (-30, -10, -30, 30, 100, 30) _ba.set_map_bounds(map_bounds) diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index ecc27b4d..a688deae 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -167,13 +167,13 @@ class Player(Generic[TeamType]): """ return self._sessionplayer.exists() - def get_name(self, full: bool = False, icon: bool = True) -> str: - """get_name(full: bool = False, icon: bool = True) -> str + def getname(self, full: bool = False, icon: bool = True) -> str: + """getname(full: bool = False, icon: bool = True) -> str Returns the player's name. If icon is True, the long version of the name may include an icon. """ - return self._sessionplayer.get_name(full=full, icon=icon) + return self._sessionplayer.getname(full=full, icon=icon) def is_alive(self) -> bool: """is_alive() -> bool diff --git a/assets/src/ba_data/python/ba/_profile.py b/assets/src/ba_data/python/ba/_profile.py index 86fa1c56..8448baae 100644 --- a/assets/src/ba_data/python/ba/_profile.py +++ b/assets/src/ba_data/python/ba/_profile.py @@ -50,15 +50,15 @@ def get_player_profile_icon(profilename: str) -> str: """ from ba._enums import SpecialChar - bs_config = _ba.app.config + appconfig = _ba.app.config icon: str try: - is_global = bs_config['Player Profiles'][profilename]['global'] + is_global = appconfig['Player Profiles'][profilename]['global'] except KeyError: is_global = False if is_global: try: - icon = bs_config['Player Profiles'][profilename]['icon'] + icon = appconfig['Player Profiles'][profilename]['icon'] except KeyError: icon = _ba.charstr(SpecialChar.LOGO) else: @@ -71,9 +71,9 @@ def get_player_profile_colors( profiles: Dict[str, Dict[str, Any]] = None ) -> Tuple[Tuple[float, float, float], Tuple[float, float, float]]: """Given a profile, return colors for them.""" - bs_config = _ba.app.config + appconfig = _ba.app.config if profiles is None: - profiles = bs_config['Player Profiles'] + profiles = appconfig['Player Profiles'] # Special case: when being asked for a random color in kiosk mode, # always return default purple. diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 61154cca..e454dc62 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -238,7 +238,6 @@ class Session: def on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None: """Called when a previously-accepted ba.SessionPlayer leaves.""" - # pylint: disable=too-many-branches if sessionplayer not in self.players: print('ERROR: Session.on_player_leave called' @@ -250,7 +249,8 @@ class Session: activity = self._activity_weak() if not sessionplayer.in_game: - # Ok, the player's still in the lobby. Simply remove them from it. + + # Ok, the player is still in the lobby; simply remove them. with _ba.Context(self): try: self.lobby.remove_chooser(sessionplayer) @@ -261,11 +261,10 @@ class Session: # teams/activities/etc. sessionteam = sessionplayer.team assert sessionteam is not None - assert sessionplayer in sessionteam.players _ba.screenmessage( Lstr(resource='playerLeftText', - subs=[('${PLAYER}', sessionplayer.get_name(full=True))])) + subs=[('${PLAYER}', sessionplayer.getname(full=True))])) # Remove them from their SessionTeam. if sessionplayer in sessionteam.players: @@ -287,38 +286,42 @@ class Session: # If we're a non-team session, remove their team too. if not self.use_teams: - - # They should have been the only one on their team. - assert not sessionteam.players - - # Remove their Team from the Activity. - if activity is not None: - if sessionteam.gameteam in activity.teams: - activity.remove_team(sessionteam) - else: - print('Team not found in Activity in on_player_leave.') - - # And then from the Session. - with _ba.Context(self): - if sessionteam in self.teams: - try: - self.teams.remove(sessionteam) - self.on_team_leave(sessionteam) - except Exception: - print_exception( - f'Error in on_team_leave for Session {self}.') - else: - print('Team no in Session teams in on_player_leave.') - try: - sessionteam.reset_sessiondata() - except Exception: - print_exception( - f'Error clearing sessiondata' - f' for team {sessionteam} in session {self}.') + self._remove_player_team(sessionteam, activity) # Now remove them from the session list. self.players.remove(sessionplayer) + def _remove_player_team(self, sessionteam: ba.SessionTeam, + activity: Optional[ba.Activity]) -> None: + """Remove the player-specific team in non-teams mode.""" + + # They should have been the only one on their team. + assert not sessionteam.players + + # Remove their Team from the Activity. + if activity is not None: + if sessionteam.gameteam in activity.teams: + activity.remove_team(sessionteam) + else: + print('Team not found in Activity in on_player_leave.') + + # And then from the Session. + with _ba.Context(self): + if sessionteam in self.teams: + try: + self.teams.remove(sessionteam) + self.on_team_leave(sessionteam) + except Exception: + print_exception( + f'Error in on_team_leave for Session {self}.') + else: + print('Team no in Session teams in on_player_leave.') + try: + sessionteam.reset_sessiondata() + except Exception: + print_exception(f'Error clearing sessiondata' + f' for team {sessionteam} in session {self}.') + def end(self) -> None: """Initiates an end to the session and a return to the main menu. @@ -408,6 +411,15 @@ class Session: return UNHANDLED + class _SetActivityLock: + + def __init__(self, session: ba.Session) -> None: + self._session = session + self._session._in_set_activity = True + + def __del__(self) -> None: + self._session._in_set_activity = False + def set_activity(self, activity: ba.Activity) -> None: """Assign a new current ba.Activity for the session. @@ -420,8 +432,7 @@ class Session: # Sanity test: make sure this doesn't get called recursively. if self._in_set_activity: - raise RuntimeError( - 'Session.set_activity() cannot be called recursively.') + raise RuntimeError('Session.set_activity() called recursively.') self._in_set_activity = True if activity.session is not _ba.getsession(): @@ -432,7 +443,7 @@ class Session: return if activity is self._activity_retained: - print_error('activity set to already-current activity') + print_error('Activity set to already-current activity.') return if self._next_activity is not None: @@ -640,7 +651,7 @@ class Session: _ba.screenmessage( Lstr(resource='playerDelayedJoinText', subs=[('${PLAYER}', - sessionplayer.get_name(full=True))]), + sessionplayer.getname(full=True))]), color=(0, 1, 0), ) @@ -654,7 +665,7 @@ class Session: sessionteam = SessionTeam( team_id=our_team_id, color=chooser.get_color(), - name=chooser.getplayer().get_name(full=True, icon=False), + name=chooser.getplayer().getname(full=True, icon=False), ) # Add player's team to the Session. diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 7cfad6e9..091452f4 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -104,7 +104,7 @@ class PlayerRecord: raise SessionPlayerNotFoundError() return self._player - def get_name(self, full: bool = False) -> str: + def getname(self, full: bool = False) -> str: """Return the player entry's name.""" return self.name_full if full else self.name @@ -307,8 +307,8 @@ class Stats: def register_player(self, player: ba.SessionPlayer) -> None: """Register a player with this score-set.""" - name = player.get_name() - name_full = player.get_name(full=True) + name = player.getname() + name_full = player.getname(full=True) try: # If the player already exists, update his character and such as # it may have changed. @@ -327,13 +327,13 @@ class Stats: # corresponds to a player with that name. for record_id, record in self._player_records.items(): lastplayer = record.get_last_player() - if lastplayer and lastplayer.get_name() == record_id: + if lastplayer and lastplayer.getname() == record_id: records[record_id] = record return records def player_got_hit(self, player: ba.SessionPlayer) -> None: """Call this when a player got hit.""" - s_player = self._player_records[player.get_name()] + s_player = self._player_records[player.getname()] s_player.streak = 0 def player_scored(self, @@ -364,7 +364,7 @@ class Stats: from ba._gameactivity import GameActivity from ba._lang import Lstr del victim_player # Currently unused. - name = player.get_name() + name = player.getname() s_player = self._player_records[name] if kill: @@ -384,7 +384,7 @@ class Stats: assert self._activity is not None activity = self._activity() if isinstance(activity, GameActivity): - name_full = player.get_name(full=True, icon=False) + name_full = player.getname(full=True, icon=False) activity.show_zoom_message( Lstr(resource='nameScoresText', subs=[('${NAME}', name_full)]), @@ -450,7 +450,7 @@ class Stats: killer: ba.Player = None) -> None: """Should be called when a player is killed.""" from ba._lang import Lstr - name = player.get_name() + name = player.getname() prec = self._player_records[name] prec.streak = 0 if killed: @@ -468,7 +468,7 @@ class Stats: if killer.team is player.team: _ba.screenmessage(Lstr(resource='nameBetrayedText', subs=[('${NAME}', - killer.get_name()), + killer.getname()), ('${VICTIM}', name)]), top=True, color=killer.color, @@ -476,7 +476,7 @@ class Stats: else: _ba.screenmessage(Lstr(resource='nameKilledText', subs=[('${NAME}', - killer.get_name()), + killer.getname()), ('${VICTIM}', name)]), top=True, color=killer.color, diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py index 72726d80..e0bcf462 100644 --- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py +++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py @@ -61,12 +61,12 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): player_order_prev.sort( reverse=True, key=lambda p: - (p.team.sessiondata['previous_score'], p.get_name(full=True))) + (p.team.sessiondata['previous_score'], p.getname(full=True))) player_order = list(self.players) player_order.sort(reverse=True, key=lambda p: (p.team.sessiondata['score'], p.team.sessiondata[ - 'score'], p.get_name(full=True))) + 'score'], p.getname(full=True))) v_offs = -74.0 + spacing * len(player_order_prev) * 0.5 delay1 = 1.3 + 0.1 @@ -161,7 +161,7 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): 0: ts_h_offs - 72.0 * scale, transtime2: ts_h_offs - (72.0 + slide_amt) * scale })) - txt = Text(ba.Lstr(value=player.get_name(full=True)), + txt = Text(ba.Lstr(value=player.getname(full=True)), maxwidth=130.0, scale=0.75 * scale, position=(ts_h_offs - 50.0 * scale, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index 8fd34a3e..75bf8e64 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -212,7 +212,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): scale=(30.0 * scale, 30.0 * scale), transition=Image.Transition.IN_LEFT, transition_delay=tdelay).autoretain() - Text(ba.Lstr(value=playerrec.get_name(full=True)), + Text(ba.Lstr(value=playerrec.getname(full=True)), maxwidth=160, scale=0.75 * scale, position=(ts_h_offs + 10.0 * scale, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index e4146da3..5742bedb 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -80,7 +80,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): if prec.player.in_game: player_entries.append( (prec.player.team.sessiondata['score'], - prec.get_name(full=True), prec)) + prec.getname(full=True), prec)) player_entries.sort(reverse=True, key=lambda x: x[0]) else: for _pkey, prec in self.stats.get_records().items(): @@ -364,7 +364,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): assert i.node ba.animate(i.node, 'opacity', {0.0: 0.0, 0.25: 1.0}) ZoomText(ba.Lstr( - value=team.players[0].get_name(full=True, icon=False)), + value=team.players[0].getname(full=True, icon=False)), position=(0, 97 + offs_v), color=team.color, scale=1.15, diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py index b2c7adba..965174c8 100644 --- a/assets/src/ba_data/python/bastd/actor/respawnicon.py +++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py @@ -88,7 +88,7 @@ class RespawnIcon: attrs={ 'v_attach': 'top', 'h_attach': 'right' if on_right else 'left', - 'text': ba.Lstr(value=player.get_name()), + 'text': ba.Lstr(value=player.getname()), 'maxwidth': 100, 'h_align': 'center', 'v_align': 'center', diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 3bebe0d2..a2acd319 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -75,7 +75,7 @@ class Icon(ba.Actor): 'text', owner=self.node, attrs={ - 'text': ba.Lstr(value=player.get_name()), + 'text': ba.Lstr(value=player.getname()), 'color': ba.safecolor(player.team.color), 'h_align': 'center', 'v_align': 'center', @@ -276,7 +276,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): player.team.survival_seconds = 0 ba.screenmessage( ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.get_name(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) return diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index ac269515..c9887da8 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -117,7 +117,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): if self.has_begun(): ba.screenmessage( ba.Lstr(resource='playerDelayedJoinText', - subs=[('${PLAYER}', player.get_name(full=True))]), + subs=[('${PLAYER}', player.getname(full=True))]), color=(0, 1, 0), ) # For score purposes, mark them as having died right as the diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 2ba9846d..84a77e74 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -901,7 +901,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): in [Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT] or (player.respawn_wave <= len(self._waves)))): rtxt = ba.Lstr(resource='onslaughtRespawnText', - subs=[('${PLAYER}', player.get_name()), + subs=[('${PLAYER}', player.getname()), ('${WAVE}', str(player.respawn_wave)) ]) text = ba.Lstr(value='${A}${B}\n', diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index f28d2736..48056066 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -253,7 +253,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): ba.screenmessage(ba.Lstr( translate=('statements', 'Killing ${NAME} for' ' skipping part of the track!'), - subs=[('${NAME}', player.get_name(full=True))]), + subs=[('${NAME}', player.getname(full=True))]), color=(1, 0, 0)) else: # If this player is in first, note that this is the @@ -368,7 +368,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): translate=('statements', '${TEAM} is disqualified because ${PLAYER} left'), subs=[('${TEAM}', player.team.name), - ('${PLAYER}', player.get_name(full=True))]), + ('${PLAYER}', player.getname(full=True))]), color=(1, 1, 0)) player.team.finished = True player.team.time = None diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 7a94f331..7832b038 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -354,7 +354,7 @@ class Target(ba.Actor): # names and colors so they know who got the hit. if len(activity.players) > 1: popupcolor = ba.safecolor(player.color, target_intensity=0.75) - popupstr += ' ' + player.get_name() + popupstr += ' ' + player.getname() PopupText(popupstr, position=self._position, color=popupcolor, diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 8bf89822..721f4c6d 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -935,7 +935,7 @@ class CoopBrowserWindow(ba.Window): # add all custom user levels here.. # items += [ - # 'User:' + l.get_name() + # 'User:' + l.getname() # for l in get_campaign('User').get_levels() # ] diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index 724113d3..f1f7d88a 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -389,20 +389,20 @@ class KioskWindow(ba.Window): pass else: # Also make sure there's no player profiles. - bs_config = ba.app.config - bs_config['Player Profiles'] = {} + appconfig = ba.app.config + appconfig['Player Profiles'] = {} def _do_game(self, mode: str) -> None: self._save_state() if mode in ['epic', 'ctf', 'hockey']: - bs_config = ba.app.config - if 'Team Tournament Playlists' not in bs_config: - bs_config['Team Tournament Playlists'] = {} - if 'Free-for-All Playlists' not in bs_config: - bs_config['Free-for-All Playlists'] = {} - bs_config['Show Tutorial'] = False + appconfig = ba.app.config + if 'Team Tournament Playlists' not in appconfig: + appconfig['Team Tournament Playlists'] = {} + if 'Free-for-All Playlists' not in appconfig: + appconfig['Free-for-All Playlists'] = {} + appconfig['Show Tutorial'] = False if mode == 'epic': - bs_config['Free-for-All Playlists']['Just Epic Elim'] = [{ + appconfig['Free-for-All Playlists']['Just Epic Elim'] = [{ 'settings': { 'Epic Mode': 1, 'Lives Per Player': 1, @@ -412,7 +412,7 @@ class KioskWindow(ba.Window): }, 'type': 'bs_elimination.EliminationGame' }] - bs_config['Free-for-All Playlist Selection'] = 'Just Epic Elim' + appconfig['Free-for-All Playlist Selection'] = 'Just Epic Elim' _ba.fade_screen(False, endcall=ba.Call( ba.pushcall, @@ -420,7 +420,7 @@ class KioskWindow(ba.Window): ba.FreeForAllSession))) else: if mode == 'ctf': - bs_config['Team Tournament Playlists']['Just CTF'] = [{ + appconfig['Team Tournament Playlists']['Just CTF'] = [{ 'settings': { 'Epic Mode': False, 'Flag Idle Return Time': 30, @@ -432,10 +432,10 @@ class KioskWindow(ba.Window): }, 'type': 'bs_capture_the_flag.CTFGame' }] - bs_config[ + appconfig[ 'Team Tournament Playlist Selection'] = 'Just CTF' else: - bs_config['Team Tournament Playlists']['Just Hockey'] = [{ + appconfig['Team Tournament Playlists']['Just Hockey'] = [{ 'settings': { 'Respawn Times': 1.0, 'Score to Win': 1, @@ -444,8 +444,8 @@ class KioskWindow(ba.Window): }, 'type': 'bs_hockey.HockeyGame' }] - bs_config['Team Tournament Playlist Selection'] = \ - 'Just Hockey' + appconfig['Team Tournament Playlist Selection'] = ( + 'Just Hockey') _ba.fade_screen(False, endcall=ba.Call( ba.pushcall, diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 177b7b1a..bbc4dd5c 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -708,7 +708,7 @@ class MainMenuWindow(ba.Window): # Player name if applicable. if self._input_player: - player_name = self._input_player.get_name() + player_name = self._input_player.getname() h, v, scale = positions[self._p_index] v += 35 ba.textwidget(parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index c081fe62..2311eebd 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -338,7 +338,7 @@ class PlaylistBrowserWindow(ba.Window): v_align='center') index = 0 - bs_config = ba.app.config + appconfig = ba.app.config model_opaque = ba.getmodel('level_select_button_opaque') model_transparent = ba.getmodel('level_select_button_transparent') @@ -418,13 +418,13 @@ class PlaylistBrowserWindow(ba.Window): raise Exception('unrecognized session-type: ' + str(self._sessiontype)) else: - if name not in bs_config[self._pvars.config_name + + if name not in appconfig[self._pvars.config_name + ' Playlists']: print( 'NOT FOUND ERR', - bs_config[self._pvars.config_name + + appconfig[self._pvars.config_name + ' Playlists']) - playlist = bs_config[self._pvars.config_name + + playlist = appconfig[self._pvars.config_name + ' Playlists'][name] playlist = filter_playlist(playlist, self._sessiontype, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index 7675928d..ae279f93 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -110,7 +110,7 @@ class PlaylistEditWindow(ba.Window): parent=self._root_widget, position=(210 + x_inset, v + 7), size=(self._scroll_width - 53, 43), - text=self._editcontroller.get_name(), + text=self._editcontroller.getname(), h_align='left', v_align='center', max_chars=40, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py index 52fc2aef..2e6753ac 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py @@ -44,7 +44,7 @@ class PlaylistEditController: from bastd.ui import playlist as playlistui from bastd.ui.playlist import edit as peditui - bs_config = ba.app.config + appconfig = ba.app.config # Since we may be showing our map list momentarily, # lets go ahead and preload all map preview textures. @@ -58,8 +58,8 @@ class PlaylistEditController: self._config_name_full = self._pvars.config_name + ' Playlists' # Make sure config exists. - if self._config_name_full not in bs_config: - bs_config[self._config_name_full] = {} + if self._config_name_full not in appconfig: + appconfig[self._config_name_full] = {} self._selected_index = 0 if existing_playlist_name: @@ -67,7 +67,7 @@ class PlaylistEditController: # Filter out invalid games. self._playlist = filter_playlist( - bs_config[self._pvars.config_name + + appconfig[self._pvars.config_name + ' Playlists'][existing_playlist_name], sessiontype=sessiontype, remove_unowned=False) @@ -87,7 +87,7 @@ class PlaylistEditController: self._name = ( self._pvars.default_new_list_name.evaluate() + ((' ' + str(i)) if i > 1 else '')) - if self._name not in bs_config[self._pvars.config_name + + if self._name not in appconfig[self._pvars.config_name + ' Playlists']: break i += 1 @@ -115,7 +115,7 @@ class PlaylistEditController: """(internal)""" self._edit_ui_selection = selection - def get_name(self) -> str: + def getname(self) -> str: """(internal)""" return self._name diff --git a/assets/src/ba_data/python/bastd/ui/profile/edit.py b/assets/src/ba_data/python/bastd/ui/profile/edit.py index 53a681ff..d1c520b6 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/edit.py +++ b/assets/src/ba_data/python/bastd/ui/profile/edit.py @@ -41,7 +41,7 @@ class EditProfileWindow(ba.Window): """Transitions out and recreates ourself.""" ba.containerwidget(edit=self._root_widget, transition='out_left') ba.app.main_menu_window = EditProfileWindow( - self.get_name(), self._in_main_menu).get_root_widget() + self.getname(), self._in_main_menu).get_root_widget() def __init__(self, existing_profile: Optional[str], @@ -605,7 +605,7 @@ class EditProfileWindow(ba.Window): def _update_clipped_name(self) -> None: if not self._clipped_name_text: return - name = self.get_name() + name = self.getname() if name == '__account__': name = (_ba.get_account_name() if _ba.get_account_state() == 'signed_in' else '???') @@ -630,7 +630,7 @@ class EditProfileWindow(ba.Window): if self._icon_button_label: ba.textwidget(edit=self._icon_button_label, text=self._icon) - def get_name(self) -> str: + def getname(self) -> str: """Return the current profile name value.""" if self._is_account_profile: new_name = '__account__' @@ -643,7 +643,7 @@ class EditProfileWindow(ba.Window): def save(self, transition_out: bool = True) -> bool: """Save has been selected.""" from bastd.ui.profile import browser as pbrowser - new_name = self.get_name().strip() + new_name = self.getname().strip() if not new_name: ba.screenmessage(ba.Lstr(resource='nameNotEmptyText')) diff --git a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py index 50ca401e..86ccaf07 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py +++ b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py @@ -48,7 +48,7 @@ class ProfileUpgradeWindow(ba.Window): self._base_scale = (2.05 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.2) self._upgrade_start_time: Optional[float] = None - self._name = edit_profile_window.get_name() + self._name = edit_profile_window.getname() self._edit_profile_window = weakref.ref(edit_profile_window) top_extra = 15 if ba.app.small_ui else 15 diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index 7ca300f1..b7c04984 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -55,7 +55,6 @@ class ConfigKeyboardWindow(ba.Window): stack_offset=(0, -10) if ba.app.small_ui else (0, 0), transition=transition)) - # don't ask to config joysticks while we're in here.. self._rebuild_ui() def _rebuild_ui(self) -> None: @@ -63,7 +62,7 @@ class ConfigKeyboardWindow(ba.Window): for widget in self._root_widget.get_children(): widget.delete() - # fill our temp config with present values + # Fill our temp config with present values. self._settings: Dict[str, int] = {} for button in [ 'buttonJump', 'buttonPunch', 'buttonBomb', 'buttonPickUp', @@ -197,8 +196,10 @@ class ConfigKeyboardWindow(ba.Window): label='', color=color) - # do this deferred so it shows up on top of other buttons + # Do this deferred so it shows up on top of other buttons. (ew.) def doit() -> None: + if not self._root_widget: + return uiscale = 0.66 * scale * 2.0 maxwidth = 76.0 * scale txt = ba.textwidget(parent=self._root_widget, @@ -288,17 +289,14 @@ class AwaitKeyboardInputWindow(ba.Window): color=(1, 1, 1, 0.3), text=str(self._counter)) self._decrement_timer: Optional[ba.Timer] = ba.Timer( - 1.0, - ba.Call(self._decrement), - repeat=True, - timetype=ba.TimeType.REAL) + 1.0, self._decrement, repeat=True, timetype=ba.TimeType.REAL) _ba.capture_keyboard_input(ba.WeakCall(self._button_callback)) def __del__(self) -> None: _ba.release_keyboard_input() def _die(self) -> None: - # this strong-refs us; killing it allow us to die now + # This strong-refs us; killing it allows us to die now. self._decrement_timer = None if self._root_widget: ba.containerwidget(edit=self._root_widget, transition='out_left') diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py index cf0507ab..7373bf18 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py @@ -39,7 +39,7 @@ class SoundtrackEditWindow(ba.Window): existing_soundtrack: Optional[Union[str, Dict[str, Any]]], transition: str = 'in_right'): # pylint: disable=too-many-statements - bs_config = ba.app.config + appconfig = ba.app.config self._r = 'editSoundtrackWindow' self._folder_tex = ba.gettexture('folder') self._file_tex = ba.gettexture('file') @@ -81,8 +81,8 @@ class SoundtrackEditWindow(ba.Window): v_align='center', maxwidth=280) v = self._height - 110 - if 'Soundtracks' not in bs_config: - bs_config['Soundtracks'] = {} + if 'Soundtracks' not in appconfig: + appconfig['Soundtracks'] = {} self._soundtrack_name: Optional[str] self._existing_soundtrack_name: Optional[str] @@ -90,7 +90,7 @@ class SoundtrackEditWindow(ba.Window): # if they passed just a name, pull info from that soundtrack if isinstance(existing_soundtrack, str): self._soundtrack = copy.deepcopy( - bs_config['Soundtracks'][existing_soundtrack]) + appconfig['Soundtracks'][existing_soundtrack]) self._soundtrack_name = existing_soundtrack self._existing_soundtrack_name = existing_soundtrack self._last_edited_song_type = None @@ -129,7 +129,7 @@ class SoundtrackEditWindow(ba.Window): while True: self._soundtrack_name = st_name_text.replace( '${COUNT}', str(i)) - if self._soundtrack_name not in bs_config['Soundtracks']: + if self._soundtrack_name not in appconfig['Soundtracks']: break i += 1 diff --git a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py index 8af30be8..543dce62 100644 --- a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py +++ b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py @@ -48,16 +48,16 @@ class TeamNamesColorsWindow(popup.PopupWindow): size=(self._width, self._height), scale=scale) - bs_config = ba.app.config + appconfig = ba.app.config self._names = list( - bs_config.get('Custom Team Names', DEFAULT_TEAM_NAMES)) + appconfig.get('Custom Team Names', DEFAULT_TEAM_NAMES)) # We need to flatten the translation since it will be an # editable string. self._names = [ ba.Lstr(translate=('teamNames', n)).evaluate() for n in self._names ] self._colors = list( - bs_config.get('Custom Team Colors', DEFAULT_TEAM_COLORS)) + appconfig.get('Custom Team Colors', DEFAULT_TEAM_COLORS)) self._color_buttons: List[ba.Widget] = [] self._color_text_fields: List[ba.Widget] = [] diff --git a/docs/ba_module.md b/docs/ba_module.md index ae19599f..777f081a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-30 for Ballistica version 1.5.0 build 20035

    +

    last updated on 2020-05-30 for Ballistica version 1.5.0 build 20036

    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!


    @@ -1595,7 +1595,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -2182,7 +2182,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), transition_in(), transition_out()

    Methods Defined or Overridden:

    -
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    +
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    ba.GameActivity(settings: Dict[str, Any])

    @@ -2265,7 +2265,7 @@ can override this method.

    Return a descriptive name for this game/settings combo.

    -

    Subclasses should override get_name(); not this.

    +

    Subclasses should override getname(); not this.

    get_game_settings()

    @@ -2397,15 +2397,6 @@ with the first value, ${ARG2} with the second, etc.

    This name is used above the game scoreboard in the corner of the screen, so it should be as concise as possible.

    -
    -

    get_name()

    -
    <class method>
    -

    get_name() -> str

    - -

    Return a str name for this game type.

    - -

    This default implementation simply returns the 'name' class attr.

    -

    get_score_info()

    <class method>
    @@ -2439,6 +2430,15 @@ for this game-type for the given ba.Session type

    Given a team name, returns a localized version of it.

    +
    +

    getname()

    +
    <class method>
    +

    getname() -> str

    + +

    Return a str name for this game type.

    + +

    This default implementation simply returns the 'name' class attr.

    +

    handlemessage()

    handlemessage(self, msg: Any) -> Any

    @@ -3021,7 +3021,7 @@ etc.

    Methods Inherited:

    autoretain(), getactivity(), is_alive(), on_expire()

    Methods Defined or Overridden:

    -
    <constructor>, exists(), get_def_bound_box(), get_def_point(), get_def_points(), get_ffa_start_position(), get_flag_position(), get_music_type(), get_name(), get_play_types(), get_preview_texture_name(), get_start_position(), handlemessage(), is_point_near_edge(), on_preload(), preload()
    +
    <constructor>, exists(), get_def_bound_box(), get_def_point(), get_def_points(), get_ffa_start_position(), get_flag_position(), get_music_type(), get_play_types(), get_preview_texture_name(), get_start_position(), getname(), handlemessage(), is_point_near_edge(), on_preload(), preload()

    <constructor>

    ba.Map(vr_overlay_offset: Optional[Sequence[float]] = None)

    @@ -3096,13 +3096,6 @@ as far from these players as possible.

    If None is returned, default music will be used.

    -
    -

    get_name()

    -
    <class method>
    -

    get_name() -> str

    - -

    Return the unique name of this map, in English.

    -

    get_play_types()

    <class method>
    @@ -3123,6 +3116,13 @@ as far from these players as possible.

    Return a random starting position for the given team index.

    +
    +

    getname()

    +
    <class method>
    +

    getname() -> str

    + +

    Return the unique name of this map, in English.

    +

    handlemessage()

    handlemessage(self, msg: Any) -> Any

    @@ -3590,7 +3590,7 @@ a live node in the game.

    Node reference (sometimes used as attr values/etc).

    Methods:

    -
    add_death_action(), connectattr(), delete(), exists(), get_name(), getdelegate(), getnodetype(), handlemessage()
    +
    add_death_action(), connectattr(), delete(), exists(), getdelegate(), getname(), getnodetype(), handlemessage()

    add_death_action()

    add_death_action(action: Callable[[], None]) -> None

    @@ -3633,12 +3633,6 @@ idea to check this.

    functionality, so a statement such as "if mynode" will do the right thing both for Node objects and values of None.

    -
    -

    get_name()

    -

    get_name() -> str

    - -

    Return the name assigned to a Node; used mainly for debugging

    -

    getdelegate()

    getdelegate(type: Type, doraise: bool = False) -> <varies>

    @@ -3649,6 +3643,12 @@ the right thing both for Node objects and values of None.

    type, then None will be returned. If 'doraise' is True, then an ba.DelegateNotFoundError will be raised instead.

    +
    +

    getname()

    +

    getname() -> str

    + +

    Return the name assigned to a Node; used mainly for debugging

    +

    getnodetype()

    getnodetype() -> str

    @@ -3874,7 +3874,7 @@ even if myactor is set to None.

    Methods:

    -
    assign_input_call(), exists(), get_icon(), get_name(), is_alive(), reset_input()
    +
    assign_input_call(), exists(), get_icon(), getname(), is_alive(), reset_input()

    assign_input_call()

    assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    @@ -3910,10 +3910,10 @@ the right thing both for Player objects and values of None.

    Returns the character's icon (images, colors, etc contained in a dict)

    -

    get_name()

    -

    get_name(self, full: bool = False, icon: bool = True) -> str

    +

    getname()

    +

    getname(self, full: bool = False, icon: bool = True) -> str

    -

    get_name(full: bool = False, icon: bool = True) -> str

    +

    getname(full: bool = False, icon: bool = True) -> str

    Returns the player's name. If icon is True, the long version of the name may include an icon.

    @@ -4047,7 +4047,7 @@ the type-checker properly identifies the returned value as one.

    Methods:

    -
    <constructor>, associate_with_player(), cancel_multi_kill_timer(), get_icon(), get_last_player(), get_name(), getactivity(), submit_kill()
    +
    <constructor>, associate_with_player(), cancel_multi_kill_timer(), get_icon(), get_last_player(), getactivity(), getname(), submit_kill()

    <constructor>

    ba.PlayerRecord(name: str, name_full: str, player: ba.SessionPlayer, stats: ba.Stats)

    @@ -4076,12 +4076,6 @@ the type-checker properly identifies the returned value as one.

    Return the last ba.Player we were associated with.

    -
    -

    get_name()

    -

    get_name(self, full: bool = False) -> str

    - -

    Return the player entry's name.

    -

    getactivity()

    getactivity(self) -> Optional[ba.Activity]

    @@ -4090,6 +4084,12 @@ the type-checker properly identifies the returned value as one.

    Returns None if the activity no longer exists.

    +
    +

    getname()

    +

    getname(self, full: bool = False) -> str

    + +

    Return the player entry's name.

    +

    submit_kill()

    submit_kill(self, showpoints: bool = True) -> None

    @@ -4568,7 +4568,7 @@ is still in its lobby selecting a team/etc. then a

    Methods:

    -
    assign_input_call(), exists(), get_account_id(), get_icon(), get_name(), remove_from_game(), reset_input(), set_name()
    +
    assign_input_call(), exists(), get_account_id(), get_icon(), getname(), remove_from_game(), reset_input(), set_name()

    assign_input_call()

    assign_input_call(type: Union[str, Tuple[str, ...]], @@ -4606,8 +4606,8 @@ joins (while verification occurs).

    Returns the character's icon (images, colors, etc contained in a dict)

    -

    get_name()

    -

    get_name(full: bool = False, icon: bool = True) -> str

    +

    getname()

    +

    getname(full: bool = False, icon: bool = True) -> str

    Returns the player's name. If icon is True, the long version of the name may include an icon.

    @@ -5061,7 +5061,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_name(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    From a2bb5b97510a230d0a27730f78d605a5d52861f9 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 31 May 2020 18:15:29 -0700 Subject: [PATCH 059/417] Cleaned up player and team lifecycle logic --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 13 + assets/src/ba_data/python/_ba.py | 85 +++---- assets/src/ba_data/python/ba/_activity.py | 236 ++++++++++++------ .../src/ba_data/python/ba/_activitytypes.py | 2 +- assets/src/ba_data/python/ba/_benchmark.py | 4 +- assets/src/ba_data/python/ba/_coopsession.py | 14 +- .../src/ba_data/python/ba/_dualteamsession.py | 6 +- .../ba_data/python/ba/_freeforallsession.py | 6 +- assets/src/ba_data/python/ba/_lobby.py | 153 ++++++------ .../ba_data/python/ba/_multiteamsession.py | 10 +- assets/src/ba_data/python/ba/_player.py | 161 +++++++++--- assets/src/ba_data/python/ba/_session.py | 114 +++++---- assets/src/ba_data/python/ba/_stats.py | 2 +- assets/src/ba_data/python/ba/_team.py | 68 ++++- .../ba_data/python/bastd/actor/playerspaz.py | 41 ++- .../ba_data/python/bastd/actor/respawnicon.py | 29 +-- .../ba_data/python/bastd/actor/scoreboard.py | 56 +++-- .../src/ba_data/python/bastd/game/assault.py | 10 +- .../python/bastd/game/capturetheflag.py | 37 +-- .../src/ba_data/python/bastd/game/conquest.py | 10 +- .../python/bastd/game/easteregghunt.py | 64 +++-- .../src/ba_data/python/bastd/game/football.py | 8 +- .../src/ba_data/python/bastd/game/hockey.py | 14 +- .../python/bastd/game/kingofthehill.py | 7 +- .../ba_data/python/bastd/game/onslaught.py | 3 +- assets/src/ba_data/python/bastd/game/race.py | 11 +- assets/src/ba_data/python/bastd/mainmenu.py | 4 +- assets/src/ba_data/python/bastd/tutorial.py | 2 +- .../ba_data/python/bastd/ui/playlist/edit.py | 4 +- .../bastd/ui/playlist/editcontroller.py | 2 +- docs/ba_module.md | 215 +++++++++++----- 32 files changed, 869 insertions(+), 546 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 837369e8..13656eaf 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/36/5a/025457e87759c13a5067617816cd", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/49/fb5663472ab1f4bd32f5748ba4d7", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/3e/6eb652f11d24c22f87ae8aab399b", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f4/57/7e48692454b644a7111902f12b58", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/55/246021de09b021993e8bdbdb19a6", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/ea/079aa2649359d2024b7c20dd19d0", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/05/5d/2608f732d75799cfe09c6947736a", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/20/4f2abb279d24dced1f11f83fbe78", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f9/36/28081d9962d3f91c286663357e80", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/51/55/83ceb6ffb806c75815e5f9e88008", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/ea/461f76e113d3a02da3c61ea04bdb", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/83/af/a8ce32760e4dc300ac861f745615" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/cc/837483543f1d6b184f64b5e6a950", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/e6/d372324c7c08b5b300490fa5594e", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0e/11/3dda0974b64f51be4961628f572c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/76/3f6356dd599091f5955ce349593b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/23/3fe78cdef456a99140837ede7e49", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1c/bd/4c73637ee172630ee00145032ce7", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/a7/342bea2a6ec2f94d5de7bb52a59f", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/24/5426cb7e6ca01b9e5d67ad3217b0", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cb/73/469fe3eb016f1e9c7f5c7811b182", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7c/fb/7e0880c1ab90b0484cdedc41c8ae", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f3/f2/097e861cf6ca981b18191e4c43b5", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6b/7c/8407f4a7326b8b19f3e187d3ffcb" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 9ab6b481..a91841b1 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -105,6 +105,7 @@ assetpath assettype assettypestr + assigninput astc astcenc astroid @@ -765,6 +766,7 @@ getlog getmaps getmodel + getname getnodes getnodetype getopt @@ -1382,6 +1384,7 @@ posixpath posixsubprocess postinit + postinited poststr powerdown powersgiven @@ -1539,6 +1542,7 @@ reqtype reqtypes resample + resetinput resourcetypeinfo respawn respawnable @@ -1557,6 +1561,7 @@ rfudge rgba rlcompleter + rlock rmats rmine robotparser @@ -1580,6 +1585,7 @@ rval safecolor safesetattr + safesetcolor saitek samsung sandboxing @@ -1641,12 +1647,18 @@ sessionglobalsnode sessionname sessionplayer + sessionplayers sessionteam + sessionteams sessiontype + setactivity setalpha setbuild + setdata setlanguage setmusic + setname + setnode setsticky settingname setversion @@ -2053,6 +2065,7 @@ webpages whatevs wheee + whos widgetdeathtime wiimote wiimotes diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 8471f307..e85e61f2 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=33373537027192610824913965080968605548 +# SOURCES_HASH=172645630847706592745162067676099526148 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -76,13 +76,6 @@ def _uninferrable() -> Any: class ActivityData: """(internal)""" - def destroy(self) -> None: - """destroy() -> None - - Destroys the internal data for the activity - """ - return None - def exists(self) -> bool: """exists() -> bool @@ -91,6 +84,13 @@ class ActivityData: """ return bool() + def expire(self) -> None: + """expire() -> None + + Expires the internal data for the activity + """ + return None + def make_foreground(self) -> None: """make_foreground() -> None @@ -832,11 +832,6 @@ class SessionPlayer: storing data associated with this player. This persists for the duration of the session. - gamedata: Dict - A dict for use by the current ba.Activity for - storing data associated with this Player. - This gets cleared for each new ba.Activity. - inputdevice: ba.InputDevice The input device associated with the player. @@ -860,16 +855,15 @@ class SessionPlayer: in_game: bool team: ba.SessionTeam sessiondata: Dict - gamedata: Dict inputdevice: ba.InputDevice color: Sequence[float] highlight: Sequence[float] character: str gameplayer: Optional[ba.Player] - def assign_input_call(self, type: Union[str, Tuple[str, ...]], - call: Callable) -> None: - """assign_input_call(type: Union[str, Tuple[str, ...]], + def assigninput(self, type: Union[str, Tuple[str, ...]], + call: Callable) -> None: + """assigninput(type: Union[str, Tuple[str, ...]], call: Callable) -> None Set the python callable to be run for one or more types of input. @@ -930,36 +924,13 @@ class SessionPlayer: """ return None - def reset(self) -> None: - """reset() -> None - - (internal) - """ - return None - - def reset_input(self) -> None: - """reset_input() -> None + def resetinput(self) -> None: + """resetinput() -> None Clears out the player's assigned input actions. """ return None - def set_activity(self, activity: Optional[ba.Activity]) -> None: - """set_activity(activity: Optional[ba.Activity]) -> None - - (internal) - """ - return None - - def set_data(self, team: ba.SessionTeam, character: str, - color: Sequence[float], highlight: Sequence[float]) -> None: - """set_data(team: ba.SessionTeam, character: str, - color: Sequence[float], highlight: Sequence[float]) -> None - - (internal) - """ - return None - def set_icon_info(self, texture: str, tint_texture: str, tint_color: Sequence[float], tint2_color: Sequence[float]) -> None: @@ -970,11 +941,27 @@ class SessionPlayer: """ return None - def set_name(self, - name: str, - full_name: str = None, - real: bool = True) -> None: - """set_name(name: str, full_name: str = None, real: bool = True) + def setactivity(self, activity: Optional[ba.Activity]) -> None: + """setactivity(activity: Optional[ba.Activity]) -> None + + (internal) + """ + return None + + def setdata(self, team: ba.SessionTeam, character: str, + color: Sequence[float], highlight: Sequence[float]) -> None: + """setdata(team: ba.SessionTeam, character: str, + color: Sequence[float], highlight: Sequence[float]) -> None + + (internal) + """ + return None + + def setname(self, + name: str, + full_name: str = None, + real: bool = True) -> None: + """setname(name: str, full_name: str = None, real: bool = True) -> None Set the player's name to the provided string. @@ -983,8 +970,8 @@ class SessionPlayer: """ return None - def set_node(self, node: Optional[Node]) -> None: - """set_node(node: Optional[Node]) -> None + def setnode(self, node: Optional[Node]) -> None: + """setnode(node: Optional[Node]) -> None (internal) """ diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index ff9203c0..c5c5b8f7 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -27,10 +27,10 @@ from typing import TYPE_CHECKING, Generic, TypeVar from ba._team import Team from ba._player import Player from ba._error import (print_exception, SessionTeamNotFoundError, - NodeNotFoundError) + SessionPlayerNotFoundError, NodeNotFoundError) from ba._dependency import DependencyComponent from ba._general import Call, verify_object_death -from ba._messages import UNHANDLED, DieMessage, DeathType +from ba._messages import UNHANDLED import _ba if TYPE_CHECKING: @@ -143,7 +143,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): def __init__(self, settings: Dict[str, Any]): """Creates an Activity in the current ba.Session. - The activity will not be actually run until ba.Session.set_activity() + The activity will not be actually run until ba.Session.setactivity() is called. 'settings' should be a dict of key/value pairs specific to the activity. @@ -189,6 +189,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._has_ended = False self._activity_death_check_timer: Optional[ba.Timer] = None self._expired = False + self._delay_delete_players: List[PlayerType] = [] + self._delay_delete_teams: List[TeamType] = [] + self._players_that_left: List[ReferenceType[PlayerType]] = [] + self._teams_that_left: List[ReferenceType[TeamType]] = [] # This gets set once another activity has begun transitioning in but # before this one is killed. The on_transition_out() method is also @@ -208,8 +212,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # This stuff gets filled in just before on_begin() is called. self.teams = [] self.players = [] + self.lobby = None self._stats: Optional[ba.Stats] = None + self._gamedata: Optional[dict] = {} def __del__(self) -> None: @@ -258,6 +264,17 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): can begin. """ + @property + def gamedata(self) -> dict: + """Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities. + """ + assert not self._expired + assert isinstance(self._gamedata, dict) + return self._gamedata + @property def expired(self) -> bool: """Whether the activity is expired. @@ -282,7 +299,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): """(internal)""" self._has_ended = val - def destroy(self) -> None: + def expire(self) -> None: """Begin the process of tearing down the activity. (internal) @@ -424,7 +441,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): (internal) """ - from ba._general import WeakCall assert not self._has_transitioned_in self._has_transitioned_in = True @@ -457,10 +473,13 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): glb.vignette_outer = prev_globals.vignette_outer glb.vignette_inner = prev_globals.vignette_inner - # Start pruning our transient actors periodically. - self._prune_dead_actors_timer = _ba.Timer( - 5.17, WeakCall(self._prune_dead_actors), repeat=True) + # Start pruning our various things periodically. self._prune_dead_actors() + self._prune_dead_actors_timer = _ba.Timer(5.17, + self._prune_dead_actors, + repeat=True) + + _ba.timer(13.3, self._prune_delay_deletes, repeat=True) # Also start our low-level scene running. self._activity_data.start() @@ -556,12 +575,12 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): def add_player(self, sessionplayer: ba.SessionPlayer) -> None: """(internal)""" assert sessionplayer.team is not None - sessionplayer.reset_input() + sessionplayer.resetinput() sessionteam = sessionplayer.team assert sessionplayer in sessionteam.players team = sessionteam.gameteam assert team is not None - sessionplayer.set_activity(self) + sessionplayer.setactivity(self) with _ba.Context(self): sessionplayer.gameplayer = player = self.create_player( sessionplayer) @@ -581,10 +600,10 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): print_exception('Error in on_player_join for', self) def remove_player(self, sessionplayer: ba.SessionPlayer) -> None: - """(internal)""" + """Remove a player from the Activity while it is running. - # This should only be called on unexpired activities - # the player has been added to. + (internal) + """ assert not self.expired player: Any = sessionplayer.gameplayer @@ -605,30 +624,29 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # verify_object_death(player) with _ba.Context(self): - # Make a decent attempt to persevere if user code breaks. try: self.on_player_leave(player) except Exception: print_exception(f'Error in on_player_leave for {self}') try: - # If they have an actor, kill it. - if player.actor: - player.actor.handlemessage( - DieMessage(how=DeathType.LEFT_GAME)) - player.actor = None + player.leave() except Exception: - print_exception( - f'Error killing player actor on leave for {self}') - try: - player.reset() - sessionplayer.reset() - sessionplayer.set_node(None) - sessionplayer.set_activity(None) - except Exception: - print_exception(f'Error resetting player for {self}') + print_exception(f'Error on leave for {player} in {self}') + + self._reset_session_player_for_no_activity(sessionplayer) + + # Add the player to a list to keep it around for a while. This is + # to discourage logic from firing on player object death, which + # may not happen until activity end if something is holding refs + # to it. + self._delay_delete_players.append(player) + self._players_that_left.append(weakref.ref(player)) def add_team(self, sessionteam: ba.SessionTeam) -> None: - """(internal)""" + """Add a team to the Activity + + (internal) + """ assert not self.expired with _ba.Context(self): @@ -641,25 +659,20 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): print_exception(f'Error in on_team_join for {self}') def remove_team(self, sessionteam: ba.SessionTeam) -> None: - """(internal)""" + """Remove a team from a Running Activity - # This should only be called on unexpired activities the team has - # been added to. + (internal) + """ assert not self.expired assert sessionteam.gameteam is not None - assert sessionteam.gameteam in self.teams - team = sessionteam.gameteam + team: Any = sessionteam.gameteam assert isinstance(team, self._teamtype) assert team in self.teams self.teams.remove(team) assert team not in self.teams - # This should allow our ba.Team instance to die. Complain - # if that doesn't happen. - # verify_object_death(team) - with _ba.Context(self): # Make a decent attempt to persevere if user code breaks. try: @@ -667,12 +680,42 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): except Exception: print_exception(f'Error in on_team_leave for {self}') try: - sessionteam.reset_gamedata() + team.leave() except Exception: - print_exception(f'Error in reset_gamedata for {self}') + print_exception(f'Error on leave for {team} in {self}') sessionteam.gameteam = None + # Add the team to a list to keep it around for a while. This is + # to discourage logic from firing on team object death, which + # may not happen until activity end if something is holding refs + # to it. + self._delay_delete_teams.append(team) + self._teams_that_left.append(weakref.ref(team)) + + def _reset_session_player_for_no_activity( + self, sessionplayer: ba.SessionPlayer) -> None: + + # Let's be extra-defensive here: killing a node/input-call/etc + # could trigger user-code resulting in errors, but we would still + # like to complete the reset if possible. + try: + sessionplayer.setnode(None) + except Exception: + print_exception( + f'Error resetting SessionPlayer node on {sessionplayer}' + f' for {self}') + try: + sessionplayer.resetinput() + except Exception: + print_exception( + f'Error resetting SessionPlayer input on {sessionplayer}' + f' for {self}') + + # These should never fail I think... + sessionplayer.setactivity(None) + sessionplayer.gameplayer = None + def _setup_player_and_team_types(self) -> None: """Pull player and team types from our typing.Generic params.""" @@ -682,7 +725,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # to no generic params being passed) we automatically use the # base class types, but also warn the user since this will mean # less type safety for that class. (its better to pass the base - # types explicitly vs. having them be Any) + # player/team types explicitly vs. having them be Any) if not TYPE_CHECKING: self._playertype = type(self).__orig_bases__[-1].__args__[0] if not isinstance(self._playertype, type): @@ -749,9 +792,31 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_expire() except Exception: - print_exception(f'Error in Activity on_expire() for {self}') + print_exception(f'Error in Activity on_expire() for {self}.') - # Send expire notices to all remaining actors. + try: + self._gamedata = None + except Exception: + print_exception(f'Error clearing gamedata for {self}.') + + # Don't want to be holding any delay-delete refs at this point. + self._prune_delay_deletes() + + self._expire_actors() + self._expire_players() + self._expire_teams() + + # This will kill all low level stuff: Timers, Nodes, etc., which + # should clear up any remaining refs to our Activity and allow us + # to die peacefully. + try: + self._activity_data.expire() + except Exception: + print_exception( + 'Error during ba.Activity._expire() destroying data:') + + def _expire_actors(self) -> None: + # Expire all Actors. for actor_ref in self._actor_weak_refs: actor = actor_ref() if actor is not None: @@ -760,35 +825,58 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): actor.on_expire() except Exception: print_exception(f'Error in Actor.on_expire()' - f' for {actor_ref()}') + f' for {actor_ref()}.') + + def _expire_players(self) -> None: + + # Issue warnings for any players that left the game but don't + # get freed soon. + for ex_player in (p() for p in self._players_that_left): + if ex_player is not None: + verify_object_death(ex_player) - # Reset all Players. - # (releases any attached actors, clears game-data, etc) for player in self.players: + # This should allow our ba.Player instance to be freed. + # Complain if that doesn't happen. + verify_object_death(player) + try: - # This should allow our ba.Player instance to die. - # Complain if that doesn't happen. - # verify_object_death(player) - sessionplayer = player.sessionplayer - player.reset() - sessionplayer.set_node(None) - sessionplayer.set_activity(None) - - sessionplayer.gameplayer = None - sessionplayer.reset() + player.expire() except Exception: - print_exception(f'Error resetting Player {player}') + print_exception(f'Error expiring {player}') + + # Reset the SessionPlayer to a not-in-an-activity state. + try: + sessionplayer = player.sessionplayer + self._reset_session_player_for_no_activity(sessionplayer) + except SessionPlayerNotFoundError: + # Conceivably, someone could have held on to a Player object + # until now whos underlying SessionPlayer left long ago... + pass + except Exception: + print_exception(f'Error expiring {player}') + + def _expire_teams(self) -> None: + + # Issue warnings for any teams that left the game but don't + # get freed soon. + for ex_team in (p() for p in self._teams_that_left): + if ex_team is not None: + verify_object_death(ex_team) - # Ditto with Teams. for team in self.teams: + # This should allow our ba.Team instance to die. + # Complain if that doesn't happen. + verify_object_death(team) + + try: + team.expire() + except Exception: + print_exception(f'Error expiring {team}') + try: sessionteam = team.sessionteam - - # This should allow our ba.Team instance to die. - # Complain if that doesn't happen. - # verify_object_death(sessionteam.gameteam) sessionteam.gameteam = None - sessionteam.reset_gamedata() except SessionTeamNotFoundError: # It is expected that Team objects may last longer than # the SessionTeam they came from (game objects may hold @@ -796,17 +884,19 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # player/team has left the game) pass except Exception: - print_exception(f'Error resetting Team {team}') + print_exception(f'Error expiring Team {team}') - # Regardless of what happened here, we want to destroy our data, as - # our activity might not go down if we don't. This will kill all - # Timers, Nodes, etc, which should clear up any remaining refs to our - # Actors and Activity and allow us to die peacefully. - try: - self._activity_data.destroy() - except Exception: - print_exception( - 'Error during ba.Activity._expire() destroying data:') + def _prune_delay_deletes(self) -> None: + self._delay_delete_players.clear() + self._delay_delete_teams.clear() + + # Clear out any dead weak-refs. + self._teams_that_left = [ + t for t in self._teams_that_left if t() is not None + ] + self._players_that_left = [ + p for p in self._players_that_left if p() is not None + ] def _prune_dead_actors(self) -> None: self._last_prune_dead_actors_time = _ba.time() diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index be0b79d8..afca3247 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -229,6 +229,6 @@ class ScoreScreenActivity(Activity[Player, Team]): # Just to be extra careful, don't assign if we're transitioning out. # (though theoretically that would be ok). if not self.is_transitioning_out() and player: - player.assign_input_call( + player.assigninput( ('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'), self._player_press) diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index 31be7db1..7646f03a 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -53,7 +53,7 @@ def run_cpu_benchmark() -> None: cfg['Graphics Quality'] = 'Low' cfg.apply() self.benchmark_type = 'cpu' - self.set_activity(_ba.new_activity(tutorial.TutorialActivity)) + self.setactivity(_ba.new_activity(tutorial.TutorialActivity)) def __del__(self) -> None: @@ -91,7 +91,7 @@ def run_stress_test(playlist_type: str = 'Random', Call(_ba.screenmessage, ('stats will be written to ' + _modutils.get_human_readable_user_scripts_path() + - '/stressTestStats.csv')), + '/stress_test_stats.csv')), timetype=TimeType.REAL) diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 9fdd94fa..052a77d0 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -98,7 +98,7 @@ class CoopSession(Session): self._custom_menu_ui: List[Dict[str, Any]] = [] # Start our joining screen. - self.set_activity(_ba.new_activity(CoopJoinActivity)) + self.setactivity(_ba.new_activity(CoopJoinActivity)) self._next_game_instance: Optional[ba.GameActivity] = None self._next_game_level_name: Optional[str] = None @@ -298,7 +298,7 @@ class CoopSession(Session): and not app.kiosk_mode): if self._tutorial_activity is None: raise RuntimeError('Tutorial not preloaded properly.') - self.set_activity(self._tutorial_activity) + self.setactivity(self._tutorial_activity) self._tutorial_activity = None self._ran_tutorial_activity = True self._custom_menu_ui = [] @@ -313,10 +313,10 @@ class CoopSession(Session): # Skip players that are still choosing a team. if player.in_game: self.stats.register_player(player) - self.stats.set_activity(next_game) + self.stats.setactivity(next_game) # Now flip the current activity. - self.set_activity(next_game) + self.setactivity(next_game) if not app.kiosk_mode: if self.tournament_id is not None: @@ -338,7 +338,7 @@ class CoopSession(Session): # If we were in a tutorial, just pop a transition to get to the # actual round. elif isinstance(activity, TutorialActivity): - self.set_activity(_ba.new_activity(TransitionActivity)) + self.setactivity(_ba.new_activity(TransitionActivity)) else: player_info: List[ba.PlayerInfo] @@ -392,9 +392,9 @@ class CoopSession(Session): if outcome == 'restart': # This will pop up back in the same round. - self.set_activity(_ba.new_activity(TransitionActivity)) + self.setactivity(_ba.new_activity(TransitionActivity)) else: - self.set_activity( + self.setactivity( _ba.new_activity( CoopScoreScreen, { 'player_info': player_info, diff --git a/assets/src/ba_data/python/ba/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py index dee8e74f..4cdef7de 100644 --- a/assets/src/ba_data/python/ba/_dualteamsession.py +++ b/assets/src/ba_data/python/ba/_dualteamsession.py @@ -56,7 +56,7 @@ class DualTeamSession(MultiTeamSession): # If everyone has the same score, call it a draw. if len(winners) < 2: - self.set_activity(_ba.new_activity(DrawScoreScreenActivity)) + self.setactivity(_ba.new_activity(DrawScoreScreenActivity)) else: winner = winners[0].teams[0] winner.sessiondata['score'] += 1 @@ -64,10 +64,10 @@ class DualTeamSession(MultiTeamSession): # If a team has won, show final victory screen. if winner.sessiondata['score'] >= (self._series_length - 1) / 2 + 1: - self.set_activity( + self.setactivity( _ba.new_activity(TeamSeriesVictoryScoreScreenActivity, {'winner': winner})) else: - self.set_activity( + self.setactivity( _ba.new_activity(TeamVictoryScoreScreenActivity, {'winner': winner})) diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index e338e370..f7b1eeef 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -81,7 +81,7 @@ class FreeForAllSession(MultiTeamSession): # If there's multiple players and everyone has the same score, # call it a draw. if len(self.players) > 1 and len(winners) < 2: - self.set_activity( + self.setactivity( _ba.new_activity(DrawScoreScreenActivity, {'results': results})) else: @@ -105,10 +105,10 @@ class FreeForAllSession(MultiTeamSession): or (len(series_winners) > 1 and series_winners[0].sessiondata['score'] != series_winners[1].sessiondata['score'])): - self.set_activity( + self.setactivity( _ba.new_activity(TeamSeriesVictoryScoreScreenActivity, {'winner': series_winners[0]})) else: - self.set_activity( + self.setactivity( _ba.new_activity(FreeForAllVictoryScoreScreenActivity, {'results': results})) diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index efd5b084..10cfa563 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -55,7 +55,7 @@ class JoinInfo: self._press_to_bomb: Union[str, ba.Lstr] = _ba.charstr( SpecialChar.RIGHT_BUTTON) self._joinmsg = Lstr(resource='pressAnyButtonToJoinText') - can_switch_teams = (len(lobby.teams) > 1) + can_switch_teams = (len(lobby.sessionteams) > 1) # If we have a keyboard, grab keys for punch and pickup. # FIXME: This of course is only correct on the local device; @@ -151,7 +151,7 @@ class Chooser: if self._text_node: self._text_node.delete() - def __init__(self, vpos: float, player: _ba.SessionPlayer, + def __init__(self, vpos: float, sessionplayer: _ba.SessionPlayer, lobby: 'Lobby') -> None: self._deek_sound = _ba.getsound('deek') self._click_sound = _ba.getsound('click01') @@ -161,7 +161,7 @@ class Chooser: self._mask_texture = _ba.gettexture('characterIconMask') self._vpos = vpos self._lobby = weakref.ref(lobby) - self._player = player + self._sessionplayer = sessionplayer self._inited = False self._dead = False self._text_node: Optional[ba.Node] = None @@ -174,13 +174,8 @@ class Chooser: app = _ba.app - # try: - # print(player.inputdevice) - # except Exception as exc: - # print('GOT EXC', type(exc)) - - # Load available profiles either from the local config or from the - # remote device. + # Load available player profiles either from the local config or + # from the remote device. self.reload_profiles() # Note: this is just our local index out of available teams; *not* @@ -199,7 +194,7 @@ class Chooser: # list. char_index_offset = app.lobby_random_char_index_offset self._random_character_index = ( - (player.inputdevice.id + char_index_offset) % + (sessionplayer.inputdevice.id + char_index_offset) % len(self._character_names)) # Attempt to set an initial profile based on what was used previously @@ -231,8 +226,8 @@ class Chooser: animate_array(self.icon, 'scale', 2, {0: (0, 0), 0.1: (45, 45)}) # Set our initial name to '' in case anyone asks. - self._player.set_name(Lstr(resource='choosingPlayerText').evaluate(), - real=False) + self._sessionplayer.setname( + Lstr(resource='choosingPlayerText').evaluate(), real=False) # Init these to our rando but they should get switched to the # selected profile (if any) right after. @@ -249,7 +244,7 @@ class Chooser: def _select_initial_profile(self) -> int: app = _ba.app profilenames = self._profilenames - inputdevice = self._player.inputdevice + inputdevice = self._sessionplayer.inputdevice # If we've got a set profile name for this device, work backwards # from that to get our index. @@ -307,9 +302,9 @@ class Chooser: return profilenames.index('_random') @property - def player(self) -> ba.SessionPlayer: - """The ba.Player associated with this chooser.""" - return self._player + def sessionplayer(self) -> ba.SessionPlayer: + """The ba.SessionPlayer associated with this chooser.""" + return self._sessionplayer @property def ready(self) -> bool: @@ -324,9 +319,10 @@ class Chooser: """(internal)""" self._dead = val - def get_team(self) -> ba.SessionTeam: - """Return this chooser's selected ba.Team.""" - return self.lobby.teams[self._selected_team_index] + @property + def sessionteam(self) -> ba.SessionTeam: + """Return this chooser's currently selected ba.SessionTeam.""" + return self.lobby.sessionteams[self._selected_team_index] @property def lobby(self) -> ba.Lobby: @@ -376,7 +372,7 @@ class Chooser: # Re-construct our profile index and other stuff since the profile # list might have changed. - input_device = self._player.inputdevice + input_device = self._sessionplayer.inputdevice is_remote = input_device.is_remote_client is_test_input = input_device.name.startswith('TestInput') @@ -434,10 +430,10 @@ class Chooser: assert self._text_node spacing = 350 - teams = self.lobby.teams - offs = (spacing * -0.5 * len(teams) + + sessionteams = self.lobby.sessionteams + offs = (spacing * -0.5 * len(sessionteams) + spacing * self._selected_team_index + 250) - if len(teams) > 1: + if len(sessionteams) > 1: offs -= 35 animate_array(self._text_node, 'position', 2, { 0: self._text_node.position, @@ -460,14 +456,15 @@ class Chooser: clamp = False if name == '_random': try: - name = (self._player.inputdevice.get_default_player_name()) + name = ( + self._sessionplayer.inputdevice.get_default_player_name()) except Exception: print_exception('Error getting _random chooser name.') name = 'Invalid' clamp = not full elif name == '__account__': try: - name = self._player.inputdevice.get_account_name(full) + name = self._sessionplayer.inputdevice.get_account_name(full) except Exception: print_exception('Error getting account name for chooser.') name = 'Invalid' @@ -513,41 +510,41 @@ class Chooser: # Give their input-device UI ownership too # (prevent someone else from snatching it in crowded games) - _ba.set_ui_input_device(self._player.inputdevice) + _ba.set_ui_input_device(self._sessionplayer.inputdevice) return if not ready: - self._player.assign_input_call( + self._sessionplayer.assigninput( 'leftPress', Call(self.handlemessage, ChangeMessage('team', -1))) - self._player.assign_input_call( + self._sessionplayer.assigninput( 'rightPress', Call(self.handlemessage, ChangeMessage('team', 1))) - self._player.assign_input_call( + self._sessionplayer.assigninput( 'bombPress', Call(self.handlemessage, ChangeMessage('character', 1))) - self._player.assign_input_call( + self._sessionplayer.assigninput( 'upPress', Call(self.handlemessage, ChangeMessage('profileindex', -1))) - self._player.assign_input_call( + self._sessionplayer.assigninput( 'downPress', Call(self.handlemessage, ChangeMessage('profileindex', 1))) - self._player.assign_input_call( + self._sessionplayer.assigninput( ('jumpPress', 'pickUpPress', 'punchPress'), Call(self.handlemessage, ChangeMessage('ready', 1))) self._ready = False self._update_text() - self._player.set_name('untitled', real=False) + self._sessionplayer.setname('untitled', real=False) else: - self._player.assign_input_call( + self._sessionplayer.assigninput( ('leftPress', 'rightPress', 'upPress', 'downPress', 'jumpPress', 'bombPress', 'pickUpPress'), self._do_nothing) - self._player.assign_input_call( + self._sessionplayer.assigninput( ('jumpPress', 'bombPress', 'pickUpPress', 'punchPress'), Call(self.handlemessage, ChangeMessage('ready', 0))) # Store the last profile picked by this input for reuse. - input_device = self._player.inputdevice + input_device = self._sessionplayer.inputdevice name = input_device.name unique_id = input_device.unique_identifier device_profiles = _ba.app.config.setdefault( @@ -569,9 +566,9 @@ class Chooser: _ba.app.config.commit() # Set this player's short and full name. - self._player.set_name(self._getname(), - self._getname(full=True), - real=True) + self._sessionplayer.setname(self._getname(), + self._getname(full=True), + real=True) self._ready = True self._update_text() @@ -586,25 +583,26 @@ class Chooser: if not self._ready: if _ba.app.config.get('Auto Balance Teams', False): lobby = self.lobby - teams = lobby.teams - if len(teams) > 1: + sessionteams = lobby.sessionteams + if len(sessionteams) > 1: # First, calc how many players are on each team # ..we need to count both active players and # choosers that have been marked as ready. team_player_counts = {} - for team in teams: - team_player_counts[team.id] = len(team.players) + for sessionteam in sessionteams: + team_player_counts[sessionteam.id] = len( + sessionteam.players) for chooser in lobby.choosers: if chooser.ready: - team_player_counts[chooser.get_team().id] += 1 + team_player_counts[chooser.sessionteam.id] += 1 largest_team_size = max(team_player_counts.values()) smallest_team_size = (min(team_player_counts.values())) - # Force switch if we're on the biggest team + # Force switch if we're on the biggest sessionteam # and there's a smaller one available. if (largest_team_size != smallest_team_size - and team_player_counts[self.get_team().id] >= + and team_player_counts[self.sessionteam.id] >= largest_team_size): force_team_switch = True @@ -623,7 +621,8 @@ class Chooser: if now - self._last_change[0] < QUICK_CHANGE_INTERVAL: count += 1 if count > MAX_QUICK_CHANGE_COUNT: - _ba.disconnect_client(self._player.inputdevice.client_id) + _ba.disconnect_client( + self._sessionplayer.inputdevice.client_id) elif now - self._last_change[0] > QUICK_CHANGE_RESET_INTERVAL: count = 0 self._last_change = (now, count) @@ -644,11 +643,12 @@ class Chooser: return if msg.what == 'team': - teams = self.lobby.teams - if len(teams) > 1: + sessionteams = self.lobby.sessionteams + if len(sessionteams) > 1: _ba.playsound(self._swish_sound) self._selected_team_index = ( - (self._selected_team_index + msg.value) % len(teams)) + (self._selected_team_index + msg.value) % + len(sessionteams)) self._update_text() self.update_position() self._update_icon() @@ -685,14 +685,14 @@ class Chooser: # Once we're ready, we've saved the name, so lets ask the system # for it so we get appended numbers and stuff. - text = Lstr(value=self._player.getname(full=True)) + text = Lstr(value=self._sessionplayer.getname(full=True)) text = Lstr(value='${A} (${B})', subs=[('${A}', text), ('${B}', Lstr(resource='readyText'))]) else: text = Lstr(value=self._getname(full=True)) - can_switch_teams = len(self.lobby.teams) > 1 + can_switch_teams = len(self.lobby.sessionteams) > 1 # Flash as we're coming in. fin_color = _ba.safecolor(self.get_color()) + (1, ) @@ -719,7 +719,7 @@ class Chooser: """Return the currently selected color.""" val: Sequence[float] if self.lobby.use_team_colors: - val = self.lobby.teams[self._selected_team_index].color + val = self.lobby.sessionteams[self._selected_team_index].color else: val = self._color if len(val) != 3: @@ -736,17 +736,17 @@ class Chooser: # isn't too close to any other team's color. highlight = list(self._highlight) if self.lobby.use_team_colors: - for i, team in enumerate(self.lobby.teams): + for i, sessionteam in enumerate(self.lobby.sessionteams): if i != self._selected_team_index: - # Find the dominant component of this team's color + # Find the dominant component of this sessionteam's color # and adjust ours so that the component is # not super-dominant. max_val = 0.0 max_index = 0 for j in range(3): - if team.color[j] > max_val: - max_val = team.color[j] + if sessionteam.color[j] > max_val: + max_val = sessionteam.color[j] max_index = j that_color_for_us = highlight[max_index] our_second_biggest = max(highlight[(max_index + 1) % 3], @@ -760,7 +760,7 @@ class Chooser: def getplayer(self) -> ba.SessionPlayer: """Return the player associated with this chooser.""" - return self._player + return self._sessionplayer def _update_icon(self) -> None: if self._profilenames[self._profileindex] == '_edit': @@ -791,7 +791,7 @@ class Chooser: clr = self.get_color() clr2 = self.get_highlight() - can_switch_teams = len(self.lobby.teams) > 1 + can_switch_teams = len(self.lobby.sessionteams) > 1 # If we're initing, flash. if not self._inited: @@ -812,7 +812,7 @@ class Chooser: self.icon.tint2_color = clr2 # Store the icon info the the player. - self._player.set_icon_info(tex_name, tint_tex_name, clr, clr2) + self._sessionplayer.set_icon_info(tex_name, tint_tex_name, clr, clr2) class Lobby: @@ -823,13 +823,13 @@ class Lobby: def __del__(self) -> None: - # Reset any players that still have a chooser in us + # Reset any players that still have a chooser in us. # (should allow the choosers to die). - players = [ - chooser.player for chooser in self.choosers if chooser.player + sessionplayers = [ + c.sessionplayer for c in self.choosers if c.sessionplayer ] - for player in players: - player.reset() + for sessionplayer in sessionplayers: + sessionplayer.resetinput() def __init__(self) -> None: from ba._team import SessionTeam @@ -837,10 +837,10 @@ class Lobby: session = _ba.getsession() self._use_team_colors = session.use_team_colors if session.use_teams: - self._teams = [weakref.ref(team) for team in session.teams] + self._sessionteams = [weakref.ref(team) for team in session.teams] else: self._dummy_teams = SessionTeam() - self._teams = [weakref.ref(self._dummy_teams)] + self._sessionteams = [weakref.ref(self._dummy_teams)] v_offset = (-150 if isinstance(session, CoopSession) else -50) self.choosers: List[Chooser] = [] self.base_v_offset = v_offset @@ -868,10 +868,10 @@ class Lobby: return self._use_team_colors @property - def teams(self) -> List[ba.SessionTeam]: - """Teams available in this lobby.""" + def sessionteams(self) -> List[ba.SessionTeam]: + """ba.SessionTeams available in this lobby.""" allteams = [] - for tref in self._teams: + for tref in self._sessionteams: team = tref() assert team is not None allteams.append(team) @@ -921,11 +921,12 @@ class Lobby: """Return whether all choosers are marked ready.""" return all(chooser.ready for chooser in self.choosers) - def add_chooser(self, player: ba.SessionPlayer) -> None: + def add_chooser(self, sessionplayer: ba.SessionPlayer) -> None: """Add a chooser to the lobby for the provided player.""" self.choosers.append( - Chooser(vpos=self._vpos, player=player, lobby=self)) - self._next_add_team = (self._next_add_team + 1) % len(self._teams) + Chooser(vpos=self._vpos, sessionplayer=sessionplayer, lobby=self)) + self._next_add_team = (self._next_add_team + 1) % len( + self._sessionteams) self._vpos -= 48 def remove_chooser(self, player: ba.SessionPlayer) -> None: @@ -964,6 +965,6 @@ class Lobby: # Copy the list; it can change under us otherwise. for chooser in list(self.choosers): - if chooser.player: - chooser.player.remove_from_game() + if chooser.sessionplayer: + chooser.sessionplayer.remove_from_game() self.remove_all_choosers() diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 25f5ab9f..38016cf7 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -133,7 +133,7 @@ class MultiTeamSession(Session): self._instantiate_next_game() # Start in our custom join screen. - self.set_activity(_ba.new_activity(MultiTeamJoinActivity)) + self.setactivity(_ba.new_activity(MultiTeamJoinActivity)) def get_ffa_series_length(self) -> int: """Return free-for-all series length.""" @@ -179,14 +179,14 @@ class MultiTeamSession(Session): # If we have a tutorial to show, that's the first thing we do no # matter what. if self._tutorial_activity_instance is not None: - self.set_activity(self._tutorial_activity_instance) + self.setactivity(self._tutorial_activity_instance) self._tutorial_activity_instance = None # If we're leaving the tutorial activity, pop a transition activity # to transition us into a round gracefully (otherwise we'd snap from # one terrain to another instantly). elif isinstance(activity, TutorialActivity): - self.set_activity( + self.setactivity( _ba.new_activity(_activitytypes.TransitionActivity)) # If we're in a between-round activity or a restart-activity, hop @@ -226,10 +226,10 @@ class MultiTeamSession(Session): has_team = False if has_team: self.stats.register_player(player) - self.stats.set_activity(next_game) + self.stats.setactivity(next_game) # Now flip the current activity. - self.set_activity(next_game) + self.setactivity(next_game) # If we're leaving a round, go to the score screen. else: diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index a688deae..c889d86a 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -26,6 +26,8 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, TypeVar, Generic import _ba +from ba._error import SessionPlayerNotFoundError, print_exception +from ba._messages import DeathType, DieMessage if TYPE_CHECKING: from typing import (Type, Optional, Sequence, Dict, Any, Union, Tuple, @@ -52,7 +54,7 @@ class StandLocation: Category: Gameplay Classes """ - position: _ba.Vec3 + position: ba.Vec3 angle: Optional[float] = None @@ -61,27 +63,35 @@ class Player(Generic[TeamType]): Category: Gameplay Classes - These correspond to ba.SessionPlayer objects, but are created per activity - so that the activity can use its own custom player subclass. + These correspond to ba.SessionPlayer objects, but are associated with a + single ba.Activity instance. This allows activities to specify their + own custom ba.Player types. + + Attributes: + + actor + The ba.Actor associated with the player. + """ - # Defining these types at the class level instead of in __init__ so - # that types are introspectable (these are still instance attrs). - team: TeamType + # These are instance attrs but we define them at the type level so + # their type annotations are introspectable (for docs generation). character: str actor: Optional[ba.Actor] color: Sequence[float] highlight: Sequence[float] + _team: TeamType _sessionplayer: ba.SessionPlayer _nodeactor: Optional[ba.NodeActor] - - # Should aim to kill this eventually (at least gamedata). - # Game-specific data can be tacked on to the per-game player class. - sessiondata: Dict - gamedata: Dict + _expired: bool + _postinited: bool + sessiondata: dict + _gamedata: dict # NOTE: avoiding having any __init__() here since it seems to not # get called by default if a dataclass inherits from us. + # This also lets us keep trivial player classes cleaner by skipping + # the super().__init__() line. def postinit(self, sessionplayer: ba.SessionPlayer) -> None: """Wire up a newly created player. @@ -108,23 +118,82 @@ class Player(Generic[TeamType]): self.character = sessionplayer.character self.color = sessionplayer.color self.highlight = sessionplayer.highlight - self.team = sessionplayer.team.gameteam # type: ignore - assert self.team is not None + self._team = sessionplayer.team.gameteam # type: ignore + assert self._team is not None self.sessiondata = sessionplayer.sessiondata - self.gamedata = sessionplayer.gamedata - - # Create our player node in the current activity. - # Note: do we want to save a few cycles here by managing our player - # node manually instead of wrapping it in a NodeActor? + self._gamedata = {} + self._expired = False + self._postinited = True node = _ba.newnode('player', attrs={'playerID': sessionplayer.id}) self._nodeactor = NodeActor(node) - sessionplayer.set_node(node) + sessionplayer.setnode(node) + + def leave(self) -> None: + """Called when the Player leaves a running game. + + (internal) + """ + assert self._postinited + assert not self._expired + try: + # If they still have an actor, kill it. + if self.actor: + self.actor.handlemessage(DieMessage(how=DeathType.LEFT_GAME)) + self.actor = None + except Exception: + print_exception(f'Error killing actor on leave for {self}') + self._nodeactor = None + del self._team + del self._gamedata + + def expire(self) -> None: + """Called when the Player is expiring (when its Activity does so). + + (internal) + """ + assert self._postinited + assert not self._expired + self._expired = True + + try: + self.on_expire() + except Exception: + print_exception(f'Error in on_expire for {self}.') - def reset(self) -> None: - """(internal)""" self._nodeactor = None self.actor = None - self.team = None # type: ignore + del self._team + del self._gamedata + + def on_expire(self) -> None: + """Can be overridden to handle player expiration. + + The player expires when the Activity it is a part of expires. + Expired players should no longer run any game logic (which will + likely error). They should, however, remove any references to + players/teams/games/etc. which could prevent them from being freed. + """ + + @property + def team(self) -> TeamType: + """The ba.Team for this player.""" + assert self._postinited + assert not self._expired + return self._team + + @property + def gamedata(self) -> dict: + """Arbitrary values associated with the player. + Though it is encouraged that most player values be properly defined + on the ba.Player subclass, it may be useful for player-agnostic + objects to store values here. This dict is cleared when the player + leaves or expires so objects stored here will be disposed of at + the expected time, unlike the Player instance itself which may + continue to be referenced after it is no longer part of the game. + """ + assert self._postinited + assert not self._expired + return self._gamedata @property def sessionplayer(self) -> ba.SessionPlayer: @@ -132,10 +201,10 @@ class Player(Generic[TeamType]): Throws a ba.SessionPlayerNotFoundError if it does not exist. """ + assert self._postinited if bool(self._sessionplayer): return self._sessionplayer - from ba import _error - raise _error.SessionPlayerNotFoundError() + raise SessionPlayerNotFoundError() @property def node(self) -> ba.Node: @@ -143,29 +212,35 @@ class Player(Generic[TeamType]): This node can be used to get a generic player position/etc. """ - if not self._nodeactor: - from ba import _error - raise _error.NodeNotFoundError + assert self._postinited + assert not self._expired + assert self._nodeactor return self._nodeactor.node @property def position(self) -> ba.Vec3: - """The position of the player, as defined by its current Actor. + """The position of the player, as defined by its current ba.Actor. - This value should not be used when the player has no Actor, as - it is undefined in that case. + This value is undefined when the player has no Actor. """ + assert self._postinited + assert not self._expired + assert self.actor is not None return _ba.Vec3(self.node.position) def exists(self) -> bool: """Whether the underlying player still exists. + This will return False if the underlying ba.SessionPlayer has + left the game or if the ba.Activity this player was associated + with has ended. Most functionality will fail on a nonexistent player. Note that you can also use the boolean operator for this same functionality, so a statement such as "if player" will do the right thing both for Player objects and values of None. """ - return self._sessionplayer.exists() + assert self._postinited + return self._sessionplayer.exists() and not self._expired def getname(self, full: bool = False, icon: bool = True) -> str: """getname(full: bool = False, icon: bool = True) -> str @@ -173,6 +248,8 @@ class Player(Generic[TeamType]): Returns the player's name. If icon is True, the long version of the name may include an icon. """ + assert self._postinited + assert not self._expired return self._sessionplayer.getname(full=full, icon=icon) def is_alive(self) -> bool: @@ -181,6 +258,8 @@ class Player(Generic[TeamType]): Returns True if the player has a ba.Actor assigned and its is_alive() method return True. False is returned otherwise. """ + assert self._postinited + assert not self._expired return self.actor is not None and self.actor.is_alive() def get_icon(self) -> Dict[str, Any]: @@ -188,11 +267,13 @@ class Player(Generic[TeamType]): Returns the character's icon (images, colors, etc contained in a dict) """ + assert self._postinited + assert not self._expired return self._sessionplayer.get_icon() - def assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], - call: Callable) -> None: - """assign_input_call(type: Union[str, Tuple[str, ...]], + def assigninput(self, inputtype: Union[str, Tuple[str, ...]], + call: Callable) -> None: + """assigninput(type: Union[str, Tuple[str, ...]], call: Callable) -> None Set the python callable to be run for one or more types of input. @@ -203,14 +284,18 @@ class Player(Generic[TeamType]): 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', 'startRelease' """ - return self._sessionplayer.assign_input_call(type=inputtype, call=call) + assert self._postinited + assert not self._expired + return self._sessionplayer.assigninput(type=inputtype, call=call) - def reset_input(self) -> None: - """reset_input() -> None + def resetinput(self) -> None: + """resetinput() -> None Clears out the player's assigned input actions. """ - self._sessionplayer.reset_input() + assert self._postinited + assert not self._expired + self._sessionplayer.resetinput() def __bool__(self) -> bool: return self.exists() diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index e454dc62..2de441ba 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -348,7 +348,7 @@ class Session: '_launch_end_session_activity called twice (since_last=' + str(since_last) + ')') self._launch_end_session_activity_time = curtime - self.set_activity(_ba.new_activity(EndSessionActivity)) + self.setactivity(_ba.new_activity(EndSessionActivity)) self._wants_to_end = False self._ending = True # Prevent further actions. @@ -398,42 +398,44 @@ class Session: """General message handling; can be passed any message object.""" from ba._lobby import PlayerReadyMessage from ba._messages import PlayerProfilesChangedMessage, UNHANDLED + if isinstance(msg, PlayerReadyMessage): self._on_player_ready(msg.chooser) - return None - if isinstance(msg, PlayerProfilesChangedMessage): + elif isinstance(msg, PlayerProfilesChangedMessage): # If we have a current activity with a lobby, ask it to reload # profiles. with _ba.Context(self): self.lobby.reload_profiles() return None - return UNHANDLED + else: + return UNHANDLED + return None - class _SetActivityLock: + class _SetActivityScopedLock: def __init__(self, session: ba.Session) -> None: self._session = session + if session._in_set_activity: + raise RuntimeError('Session.setactivity() called recursively.') self._session._in_set_activity = True def __del__(self) -> None: self._session._in_set_activity = False - def set_activity(self, activity: ba.Activity) -> None: + def setactivity(self, activity: ba.Activity) -> None: """Assign a new current ba.Activity for the session. Note that this will not change the current context to the new Activity's. Code must be run in the new activity's methods (on_transition_in, etc) to get it. (so you can't do - session.set_activity(foo) and then ba.newnode() to add a node to foo) + session.setactivity(foo) and then ba.newnode() to add a node to foo) """ from ba._enums import TimeType - # Sanity test: make sure this doesn't get called recursively. - if self._in_set_activity: - raise RuntimeError('Session.set_activity() called recursively.') - self._in_set_activity = True + # Make sure we don't get called recursively. + _rlock = self._SetActivityScopedLock(self) if activity.session is not _ba.getsession(): raise RuntimeError("Provided Activity's Session is not current.") @@ -482,7 +484,7 @@ class Session: if prev_activity is not None: with _ba.Context('ui'): _ba.timer(max(0.0, activity.transition_time), - prev_activity.destroy, + prev_activity.expire, timetype=TimeType.REAL) self._in_set_activity = False @@ -507,17 +509,17 @@ class Session: with _ba.Context(self): self.on_activity_end(activity, results) except Exception: - print_exception('exception in on_activity_end() for session', self, - 'activity', activity, 'with results', results) + print_exception(f'Error in on_activity_end() for session {self}' + f' activity {activity} with results {results}') def _request_player(self, sessionplayer: ba.SessionPlayer) -> bool: - """Called by the C++ layer when players want to join.""" + """Called by the native layer when a player wants to join.""" # If we're ending, allow no new players. if self._ending: return False - # Ask the session subclass to approve/deny this request. + # Ask the ba.Session subclass to approve/deny this request. try: with _ba.Context(self): result = self.on_player_request(sessionplayer) @@ -525,14 +527,14 @@ class Session: print_exception(f'Error in on_player_request for {self}') result = False - # If the user said yes, add the player to the session list. + # If they said yes, add the player to the lobby. if result: self.players.append(sessionplayer) with _ba.Context(self): try: self.lobby.add_chooser(sessionplayer) except Exception: - print_exception('exception in lobby.add_chooser()') + print_exception('Error in lobby.add_chooser().') return result @@ -548,39 +550,42 @@ class Session: This means we're ready to begin the next one """ - if self._next_activity is not None: + if self._next_activity is None: + # Should this ever happen? + print_error('begin_next_activity() called with no _next_activity') + return - # We store both a weak and a strong ref to the new activity; - # the strong is to keep it alive and the weak is so we can access - # it even after we've released the strong-ref to allow it to die. - self._activity_retained = self._next_activity - self._activity_weak = weakref.ref(self._next_activity) - self._next_activity = None - self._activity_should_end_immediately = False + # We store both a weak and a strong ref to the new activity; + # the strong is to keep it alive and the weak is so we can access + # it even after we've released the strong-ref to allow it to die. + self._activity_retained = self._next_activity + self._activity_weak = weakref.ref(self._next_activity) + self._next_activity = None + self._activity_should_end_immediately = False - # Kick out anyone loitering in the lobby. - self.lobby.remove_all_choosers_and_kick_players() + # Kick out anyone loitering in the lobby. + self.lobby.remove_all_choosers_and_kick_players() - # Kick off the activity. - self._activity_retained.begin(self) + # Kick off the activity. + self._activity_retained.begin(self) - # If we want to go down, we're now free to kick off that process. - if self._wants_to_end: - self._launch_end_session_activity() - else: - # Otherwise, if the activity has already been told to end, - # do so now. - if self._activity_should_end_immediately: - self._activity_retained.end( - self._activity_should_end_immediately_results, - self._activity_should_end_immediately_delay) + # If we want to completely end the session, we can now kick that off. + if self._wants_to_end: + self._launch_end_session_activity() + else: + # Otherwise, if the activity has already been told to end, + # do so now. + if self._activity_should_end_immediately: + self._activity_retained.end( + self._activity_should_end_immediately_results, + self._activity_should_end_immediately_delay) def _on_player_ready(self, chooser: ba.Chooser) -> None: """Called when a ba.Player has checked themself ready.""" lobby = chooser.lobby activity = self._activity_weak() - # In joining activities, we wait till all choosers are ready + # In joining-activities, we wait till all choosers are ready # and then create all players at once. if activity is not None and activity.is_joining_activity: if lobby.check_all_ready(): @@ -613,8 +618,10 @@ class Session: """(internal)""" from ba._apputils import garbage_collect, call_after_ad - # Since we're mostly between activities at this point, lets run a cycle - # of garbage collection; hopefully it won't cause hitches here. + # Since things should be generally still right now, it's a good time + # to run garbage collection to clear out any circular dependency + # loops. We keep this disabled normally to avoid non-deterministic + # hitches. garbage_collect(session_end=False) with _ba.Context(self): @@ -635,7 +642,7 @@ class Session: # Reset the player's input here, as it is probably # referencing the chooser which could inadvertently keep it alive. - sessionplayer.reset_input() + sessionplayer.resetinput() # We can pass it to the current activity if it has already begun # (otherwise it'll get passed once begin is called). @@ -658,7 +665,7 @@ class Session: # If we're a non-team session, each player gets their own team. # (keeps mini-game coding simpler if we can always deal with teams). if self.use_teams: - sessionteam = chooser.get_team() + sessionteam = chooser.sessionteam else: our_team_id = self._next_team_id self._next_team_id += 1 @@ -670,11 +677,12 @@ class Session: # Add player's team to the Session. self.teams.append(sessionteam) - try: - with _ba.Context(self): + + with _ba.Context(self): + try: self.on_team_join(sessionteam) - except Exception: - print_exception(f'exception in on_team_join for {self}') + except Exception: + print_exception(f'Error in on_team_join for {self}.') # Add player's team to the Activity. if pass_to_activity: @@ -682,10 +690,10 @@ class Session: assert sessionplayer not in sessionteam.players sessionteam.players.append(sessionplayer) - sessionplayer.set_data(team=sessionteam, - character=chooser.get_character_name(), - color=chooser.get_color(), - highlight=chooser.get_highlight()) + sessionplayer.setdata(team=sessionteam, + character=chooser.get_character_name(), + color=chooser.get_color(), + highlight=chooser.get_highlight()) self.stats.register_player(sessionplayer) if pass_to_activity: diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 091452f4..19db090d 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -259,7 +259,7 @@ class Stats: self.orchestrahitsound3: Optional[ba.Sound] = None self.orchestrahitsound4: Optional[ba.Sound] = None - def set_activity(self, activity: Optional[ba.Activity]) -> None: + def setactivity(self, activity: Optional[ba.Activity]) -> None: """Set the current activity for this instance.""" self._activity = None if activity is None else weakref.ref(activity) diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index 2e92d4e9..b60d294d 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -25,6 +25,8 @@ from __future__ import annotations import weakref from typing import TYPE_CHECKING, TypeVar, Generic +from ba._error import print_exception + if TYPE_CHECKING: from weakref import ReferenceType from typing import Dict, List, Sequence, Tuple, Union, Optional @@ -88,14 +90,9 @@ class SessionTeam: self.name = name self.color = tuple(color) self.players = [] - self.gamedata = {} self.sessiondata = {} self.gameteam: Optional[Team] = None - def reset_gamedata(self) -> None: - """(internal)""" - self.gamedata = {} - def reset_sessiondata(self) -> None: """(internal)""" self.sessiondata = {} @@ -118,12 +115,14 @@ class Team(Generic[PlayerType]): players: List[PlayerType] id: int name: Union[ba.Lstr, str] - color: Tuple[float, ...] # FIXME: can't we make this fixed len? + color: Tuple[float, ...] # FIXME: can't we make this fixed length? _sessionteam: ReferenceType[SessionTeam] + _expired: bool + _postinited: bool + _gamedata: dict # TODO: kill these. - gamedata: Dict - sessiondata: Dict + sessiondata: dict # NOTE: avoiding having any __init__() here since it seems to not # get called by default if a dataclass inherits from us. @@ -150,8 +149,10 @@ class Team(Generic[PlayerType]): self.id = sessionteam.id self.name = sessionteam.name self.color = sessionteam.color - self.gamedata = sessionteam.gamedata self.sessiondata = sessionteam.sessiondata + self._gamedata = {} + self._expired = False + self._postinited = True def manual_init(self, team_id: int, name: Union[ba.Lstr, str], color: Tuple[float, ...]) -> None: @@ -159,8 +160,54 @@ class Team(Generic[PlayerType]): self.id = team_id self.name = name self.color = color - self.gamedata = {} + self._gamedata = {} self.sessiondata = {} + self._expired = False + self._postinited = True + + @property + def gamedata(self) -> dict: + """Arbitrary values associated with the team. + Though it is encouraged that most player values be properly defined + on the ba.Team subclass, it may be useful for player-agnostic + objects to store values here. This dict is cleared when the team + leaves or expires so objects stored here will be disposed of at + the expected time, unlike the Team instance itself which may + continue to be referenced after it is no longer part of the game. + """ + assert self._postinited + assert not self._expired + return self._gamedata + + def leave(self) -> None: + """Called when the Team leaves a running game. + + (internal) + """ + assert self._postinited + assert not self._expired + del self._gamedata + del self.players + + def expire(self) -> None: + """Called when the Team is expiring (due to the Activity expiring). + + (internal) + """ + assert self._postinited + assert not self._expired + self._expired = True + + try: + self.on_expire() + except Exception: + print_exception(f'Error in on_expire for {self}.') + + del self._gamedata + del self.players + + def on_expire(self) -> None: + """Can be overridden to handle team expiration.""" @property def sessionteam(self) -> SessionTeam: @@ -168,6 +215,7 @@ class Team(Generic[PlayerType]): Throws a ba.SessionTeamNotFoundError if there is none. """ + assert self._postinited if self._sessionteam is not None: sessionteam = self._sessionteam() if sessionteam is not None: diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 0019b7d8..7d8da8d5 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -138,34 +138,33 @@ class PlayerSpaz(Spaz): # wiring up. if self._connected_to_player: if player != self._connected_to_player: - player.reset_input() + player.resetinput() self.disconnect_controls_from_player() else: - player.reset_input() + player.resetinput() - player.assign_input_call('upDown', self.on_move_up_down) - player.assign_input_call('leftRight', self.on_move_left_right) - player.assign_input_call('holdPositionPress', - self.on_hold_position_press) - player.assign_input_call('holdPositionRelease', - self.on_hold_position_release) + player.assigninput('upDown', self.on_move_up_down) + player.assigninput('leftRight', self.on_move_left_right) + player.assigninput('holdPositionPress', self.on_hold_position_press) + player.assigninput('holdPositionRelease', + self.on_hold_position_release) if enable_jump: - player.assign_input_call('jumpPress', self.on_jump_press) - player.assign_input_call('jumpRelease', self.on_jump_release) + player.assigninput('jumpPress', self.on_jump_press) + player.assigninput('jumpRelease', self.on_jump_release) if enable_pickup: - player.assign_input_call('pickUpPress', self.on_pickup_press) - player.assign_input_call('pickUpRelease', self.on_pickup_release) + player.assigninput('pickUpPress', self.on_pickup_press) + player.assigninput('pickUpRelease', self.on_pickup_release) if enable_punch: - player.assign_input_call('punchPress', self.on_punch_press) - player.assign_input_call('punchRelease', self.on_punch_release) + player.assigninput('punchPress', self.on_punch_press) + player.assigninput('punchRelease', self.on_punch_release) if enable_bomb: - player.assign_input_call('bombPress', self.on_bomb_press) - player.assign_input_call('bombRelease', self.on_bomb_release) + player.assigninput('bombPress', self.on_bomb_press) + player.assigninput('bombRelease', self.on_bomb_release) if enable_run: - player.assign_input_call('run', self.on_run) + player.assigninput('run', self.on_run) if enable_fly: - player.assign_input_call('flyPress', self.on_fly_press) - player.assign_input_call('flyRelease', self.on_fly_release) + player.assigninput('flyPress', self.on_fly_press) + player.assigninput('flyRelease', self.on_fly_release) self._connected_to_player = player @@ -175,7 +174,7 @@ class PlayerSpaz(Spaz): ba.Player from control of this spaz. """ if self._connected_to_player: - self._connected_to_player.reset_input() + self._connected_to_player.resetinput() self._connected_to_player = None # Send releases for anything in case its held. @@ -239,7 +238,7 @@ class PlayerSpaz(Spaz): activity = self._activity() - player = self.getplayer(ba.Player, doraise=False) + player = self.getplayer(ba.Player, False) if not killed: killerplayer = None else: diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py index 965174c8..9682bb98 100644 --- a/assets/src/ba_data/python/bastd/actor/respawnicon.py +++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py @@ -46,10 +46,10 @@ class RespawnIcon: on_right, offs_extra, respawn_icons = self._get_context(player) # Cache our mask tex on the team for easy access. - mask_tex = getattr(player.team, '_spaz_respawn_icons_mask_tex', None) + mask_tex = player.team.gamedata.get('_spaz_respawn_icons_mask_tex') if mask_tex is None: mask_tex = ba.gettexture('characterIconMask') - setattr(player.team, '_spaz_respawn_icons_mask_tex', mask_tex) + player.team.gamedata['_spaz_respawn_icons_mask_tex'] = mask_tex assert isinstance(mask_tex, ba.Texture) # Now find the first unused slot and use that. @@ -134,34 +134,31 @@ class RespawnIcon: def _get_context(self, player: ba.Player) -> Tuple[bool, float, Dict]: """Return info on where we should be shown and stored.""" activity = ba.getactivity() + if isinstance(ba.getsession(), ba.DualTeamSession): on_right = player.team.id % 2 == 1 # Store a list of icons in the team. - respawn_icons = getattr(player.team, '_spaz_respawn_icons_right', - None) - if respawn_icons is None: - respawn_icons = {} - setattr(player.team, '_spaz_respawn_icons_right', - respawn_icons) - assert isinstance(respawn_icons, dict) + icons = player.team.gamedata.get('_spaz_respawn_icons') + if icons is None: + player.team.gamedata['_spaz_respawn_icons'] = icons = {} + assert isinstance(icons, dict) offs_extra = -20 else: on_right = False # Store a list of icons in the activity. - # FIXME: Need an elegant way to store our shared stuff with - # the activity. - try: - respawn_icons = activity.spaz_respawn_icons_right - except Exception: - respawn_icons = activity.spaz_respawn_icons_right = {} + icons = activity.gamedata.get('_spaz_respawn_icons') + if icons is None: + activity.gamedata['_spaz_respawn_icons'] = icons = {} + assert isinstance(icons, dict) + if isinstance(activity.session, ba.FreeForAllSession): offs_extra = -150 else: offs_extra = -20 - return on_right, offs_extra, respawn_icons + return on_right, offs_extra, icons def _update(self) -> None: remaining = int(round(self._respawn_time - ba.time())) diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py index 1dd1659b..16431102 100644 --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py @@ -30,14 +30,12 @@ import ba if TYPE_CHECKING: from typing import Any, Optional, Sequence, Dict, Union -# This could use some tidying up when I get a chance.. -# pylint: disable=too-many-statements - class _Entry: def __init__(self, scoreboard: Scoreboard, team: ba.Team, do_cover: bool, scale: float, label: Optional[ba.Lstr], flash_length: float): + # pylint: disable=too-many-statements self._scoreboard = weakref.ref(scoreboard) self._do_cover = do_cover self._scale = scale @@ -58,7 +56,7 @@ class _Entry: safe_team_color = ba.safecolor(team.color, target_intensity=1.0) # FIXME: Should not do things conditionally for vr-mode, as there may - # be non-vr clients connected. + # be non-vr clients connected which will also get these value. vrmode = ba.app.vr_mode if self._do_cover: @@ -152,11 +150,11 @@ class _Entry: else: team_name_label = team.name - # we do our own clipping here; should probably try to tap into some - # existing functionality + # We do our own clipping here; should probably try to tap into some + # existing functionality. if isinstance(team_name_label, ba.Lstr): - # hmmm; if the team-name is a non-translatable value lets go + # Hmmm; if the team-name is a non-translatable value lets go # ahead and clip it otherwise we leave it as-is so # translation can occur.. if team_name_label.is_flat_value(): @@ -204,6 +202,7 @@ class _Entry: # Abort if we've been killed if not self._backing.node: return + self._pos = tuple(position) self._backing.node.position = (position[0] + self._width / 2, position[1] - self._height / 2) @@ -226,29 +225,29 @@ class _Entry: def _set_flash_colors(self, flash: bool) -> None: self._flash_colors = flash - def _safesetattr(node: Optional[ba.Node], attr: str, val: Any) -> None: + def _safesetcolor(node: Optional[ba.Node], val: Any) -> None: if node: - setattr(node, attr, val) + node.color = val if flash: scale = 2.0 - _safesetattr( - self._backing.node, 'color', + _safesetcolor( + self._backing.node, (self._backing_color[0] * scale, self._backing_color[1] * scale, self._backing_color[2] * scale)) - _safesetattr(self._bar.node, 'color', - (self._barcolor[0] * scale, self._barcolor[1] * scale, - self._barcolor[2] * scale)) + _safesetcolor(self._bar.node, + (self._barcolor[0] * scale, self._barcolor[1] * + scale, self._barcolor[2] * scale)) if self._do_cover: - _safesetattr( - self._cover.node, 'color', + _safesetcolor( + self._cover.node, (self._cover_color[0] * scale, self._cover_color[1] * scale, self._cover_color[2] * scale)) else: - _safesetattr(self._backing.node, 'color', self._backing_color) - _safesetattr(self._bar.node, 'color', self._barcolor) + _safesetcolor(self._backing.node, self._backing_color) + _safesetcolor(self._bar.node, self._barcolor) if self._do_cover: - _safesetattr(self._cover.node, 'color', self._cover_color) + _safesetcolor(self._cover.node, self._cover_color) def _do_flash(self) -> None: assert self._flash_counter is not None @@ -266,8 +265,8 @@ class _Entry: show_value: bool = True) -> None: """Set the value for the scoreboard entry.""" - # if we have no score yet, just set it.. otherwise compare - # and see if we should flash + # If we have no score yet, just set it.. otherwise compare + # and see if we should flash. if self._score is None: self._score = score else: @@ -327,8 +326,15 @@ class _EntryProxy: # Remove our team from the scoreboard if its still around. # (but deferred, in case we die in a sim step or something where # its illegal to modify nodes) - if scoreboard is not None: + if scoreboard is None: + return + + try: ba.pushcall(ba.Call(scoreboard.remove_team, self._team_id)) + except ba.ContextError: + # This happens if we fire after the activity expires. + # In that case we don't need to do anything. + pass class Scoreboard: @@ -338,7 +344,7 @@ class Scoreboard: """ def __init__(self, label: ba.Lstr = None, score_split: float = 0.7): - """Instantiate a score-board. + """Instantiate a scoreboard. Label can be something like 'points' and will show up on boards if provided. @@ -376,8 +382,8 @@ class Scoreboard: # Create a proxy in the team which will kill # our entry when it dies (for convenience) - assert not hasattr(team, '_scoreboard_entry') - setattr(team, '_scoreboard_entry', _EntryProxy(self, team)) + assert '_scoreboard_entry' not in team.gamedata + team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team) # Now set the entry. self._entries[team.id].set_value(score=score, diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 8e0bf524..f58594af 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -181,9 +181,13 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): ba.timer(length, light.delete) def _handle_base_collide(self, team: Team) -> None: - player = ba.getcollision().opposingnode.getdelegate( - PlayerSpaz, True).getplayer(Player) - if not player or not player.is_alive(): + try: + player = ba.getcollision().opposingnode.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: + return + + if not player.is_alive(): return # If its another team's player, they scored. diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 711672d9..dd293beb 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -231,9 +231,9 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): actions=( ('modify_part_collision', 'physical', False), ('call', 'at_connect', - lambda: self._handle_hit_own_flag(team, 1)), + lambda: self._handle_touching_own_flag(team, True)), ('call', 'at_disconnect', - lambda: self._handle_hit_own_flag(team, 0)), + lambda: self._handle_touching_own_flag(team, False)), )) # Other parts of our spazzes don't collide with our flags at all. @@ -448,32 +448,28 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): delegate = node.getdelegate(PlayerSpaz) return None if delegate is None else delegate.getplayer(Player) - def _handle_hit_own_flag(self, team: Team, val: int) -> None: - """Called when a player touches their own team flag. + def _handle_touching_own_flag(self, team: Team, connecting: bool) -> None: + """Called when a player touches or stops touching their own team flag. - We keep track of when each player is touching their - own flag so we can award points when returned. + We keep track of when each player is touching their own flag so we + can award points when returned. """ player = self._player_from_node(ba.getcollision().sourcenode) if player: - player.touching_own_flag += (1 if val else -1) + player.touching_own_flag += (1 if connecting else -1) # If return-time is zero, just kill it immediately.. otherwise keep # track of touches and count down. if float(self.flag_touch_return_time) <= 0.0: assert team.flag is not None - if not team.home_flag_at_base and team.flag.held_count == 0: - - # Use a node message to kill the flag instead of just killing - # our team's. (avoids redundantly killing new flags if - # multiple body parts generate callbacks in one step). - node = ba.getcollision().opposingnode + if (connecting and not team.home_flag_at_base + and team.flag.held_count == 0): self._award_players_touching_own_flag(team) - node.handlemessage(ba.DieMessage()) + ba.getcollision().opposingnode.handlemessage(ba.DieMessage()) # Takes a non-zero amount of time to return. else: - if val: + if connecting: team.flag_return_touches += 1 if team.flag_return_touches == 1: team.touch_return_timer = ba.Timer( @@ -506,7 +502,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): angle: float = None) -> PlayerSpaz: """Intercept new spazzes and add our team material for them.""" spaz = super().spawn_player_spaz(player, position, angle) - player = spaz.getplayer(Player, doraise=True) + player = spaz.getplayer(Player, True) team: Team = player.team player.touching_own_flag = 0 no_physical_mats: List[ba.Material] = [ @@ -548,10 +544,15 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): ba.timer(0.1, ba.Call(self._spawn_flag_for_team, msg.flag.team)) elif isinstance(msg, FlagPickedUpMessage): + # Store the last player to hold the flag for scoring purposes. assert isinstance(msg.flag, CTFFlag) - msg.flag.last_player_to_hold = msg.node.getdelegate( - PlayerSpaz, True).getplayer(Player) + try: + msg.flag.last_player_to_hold = msg.node.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: + pass + msg.flag.held_count += 1 msg.flag.reset_return_times() diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 938b4c51..744484d9 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -236,10 +236,12 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): def _handle_flag_player_collide(self) -> None: collision = ba.getcollision() - flag = collision.sourcenode.getdelegate(ConquestFlag) - player = collision.opposingnode.getdelegate(PlayerSpaz, - True).getplayer(Player) - if not flag or not player: + try: + flag = collision.sourcenode.getdelegate(ConquestFlag, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: return assert flag.light diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 31262e3a..c29301c4 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -139,41 +139,39 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): if self.has_ended(): return collision = ba.getcollision() - egg = collision.sourcenode.getdelegate(Egg) - player = collision.opposingnode.getdelegate(PlayerSpaz, - True).getplayer(Player) - if player and egg: - player.team.score += 1 + try: + egg = collision.sourcenode.getdelegate(Egg, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except Exception: + return - # Displays a +1 (and adds to individual player score in - # teams mode). - self.stats.player_scored(player, 1, screenmessage=False) - if self._max_eggs < 5: - self._max_eggs += 1.0 - elif self._max_eggs < 10: - self._max_eggs += 0.5 - elif self._max_eggs < 30: - self._max_eggs += 0.3 - self._update_scoreboard() - ba.playsound(self._collect_sound, 0.5, position=egg.node.position) + player.team.score += 1 - # Create a flash. - light = ba.newnode('light', - attrs={ - 'position': egg.node.position, - 'height_attenuated': False, - 'radius': 0.1, - 'color': (1, 1, 0) - }) - ba.animate(light, - 'intensity', { - 0: 0, - 0.1: 1.0, - 0.2: 0 - }, - loop=False) - ba.timer(0.200, light.delete) - egg.handlemessage(ba.DieMessage()) + # Displays a +1 (and adds to individual player score in + # teams mode). + self.stats.player_scored(player, 1, screenmessage=False) + if self._max_eggs < 5: + self._max_eggs += 1.0 + elif self._max_eggs < 10: + self._max_eggs += 0.5 + elif self._max_eggs < 30: + self._max_eggs += 0.3 + self._update_scoreboard() + ba.playsound(self._collect_sound, 0.5, position=egg.node.position) + + # Create a flash. + light = ba.newnode('light', + attrs={ + 'position': egg.node.position, + 'height_attenuated': False, + 'radius': 0.1, + 'color': (1, 1, 0) + }) + ba.animate(light, 'intensity', {0: 0, 0.1: 1.0, 0.2: 0}, loop=False) + ba.timer(0.200, light.delete) + egg.handlemessage(ba.DieMessage()) def _update(self) -> None: # Misc. periodic updating. diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index d44573a7..111ad9e3 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -267,9 +267,11 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, FlagPickedUpMessage): assert isinstance(msg.flag, FootballFlag) - player = msg.node.getdelegate(PlayerSpaz, True).getplayer(Player) - if player: - msg.flag.last_holding_player = player + try: + msg.flag.last_holding_player = msg.node.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: + pass msg.flag.held_count += 1 elif isinstance(msg, FlagDroppedMessage): diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 644f9da3..0f13c998 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -256,11 +256,15 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): def _handle_puck_player_collide(self) -> None: collision = ba.getcollision() - puck = collision.sourcenode.getdelegate(Puck) - player = collision.opposingnode.getdelegate(PlayerSpaz, - True).getplayer(Player) - if player and puck: - puck.last_players_to_touch[player.team.id] = player + try: + puck = collision.sourcenode.getdelegate(Puck, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: + return + + puck.last_players_to_touch[player.team.id] = player def _kill_puck(self) -> None: self._puck = None diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 4b70add0..aa940744 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -247,9 +247,10 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._swipsound) def _handle_player_flag_region_collide(self, colliding: bool) -> None: - player = ba.getcollision().opposingnode.getdelegate( - PlayerSpaz, True).getplayer(Player) - if not player: + try: + player = ba.getcollision().opposingnode.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: return # Different parts of us can collide so a single value isn't enough diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 84a77e74..e08d0d78 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -1196,8 +1196,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, PlayerSpazHurtMessage): - player = msg.spaz.getplayer(Player, doraise=True) - player.has_been_hurt = True + msg.spaz.getplayer(Player, True).has_been_hurt = True self._a_player_has_been_hurt = True elif isinstance(msg, ba.PlayerScoredMessage): diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 48056066..cc90ff7a 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -231,11 +231,12 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): # pylint: disable=too-many-branches # pylint: disable=too-many-nested-blocks collision = ba.getcollision() - region = collision.sourcenode.getdelegate(RaceRegion) - playerspaz = collision.opposingnode.getdelegate(PlayerSpaz, - doraise=False) - player = playerspaz.getplayer(Player) if playerspaz else None - if not player or not region: + try: + region = collision.sourcenode.getdelegate(RaceRegion, True) + player = collision.opposingnode.getdelegate(PlayerSpaz, + True).getplayer( + Player, True) + except ba.NotFoundError: return last_region = player.last_region diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 9a70b78b..e0e39deb 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -920,14 +920,14 @@ class MainMenuSession(ba.Session): super().__init__([self._activity_deps]) self._locked = False - self.set_activity(ba.new_activity(MainMenuActivity)) + self.setactivity(ba.new_activity(MainMenuActivity)) def on_activity_end(self, activity: ba.Activity, results: Any) -> None: if self._locked: _ba.unlock_all_input() # Any ending activity leads us into the main menu one. - self.set_activity(ba.new_activity(MainMenuActivity)) + self.setactivity(ba.new_activity(MainMenuActivity)) def on_player_request(self, player: ba.SessionPlayer) -> bool: # Reject all player requests. diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index 2d9f3ffa..8e95c00e 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -2412,7 +2412,7 @@ class TutorialActivity(ba.Activity[Player, Team]): super().on_player_join(player) # We just wanna know if this player presses anything. - player.assign_input_call( + player.assigninput( ('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'), ba.Call(self._player_pressed_button, player)) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index ae279f93..3603963b 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -254,13 +254,13 @@ class PlaylistEditWindow(ba.Window): def _add(self) -> None: # Store list name then tell the session to perform an add. - self._editcontroller.set_name( + self._editcontroller.setname( cast(str, ba.textwidget(query=self._text_field))) self._editcontroller.add_game_pressed() def _edit(self) -> None: # Store list name then tell the session to perform an add. - self._editcontroller.set_name( + self._editcontroller.setname( cast(str, ba.textwidget(query=self._text_field))) self._editcontroller.edit_game_pressed() diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py index 2e6753ac..5828f643 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py @@ -119,7 +119,7 @@ class PlaylistEditController: """(internal)""" return self._name - def set_name(self, name: str) -> None: + def setname(self, name: str) -> None: """(internal)""" self._name = name diff --git a/docs/ba_module.md b/docs/ba_module.md index 777f081a..9768dcf4 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-30 for Ballistica version 1.5.0 build 20036

    +

    last updated on 2020-05-31 for Ballistica version 1.5.0 build 20036

    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!


    @@ -343,7 +343,7 @@ actually award achievements.

    can overlap during transitions.

    Attributes:

    -
    expired, globalsnode, players, playertype, session, settings_raw, stats, teams, teamtype
    +
    expired, gamedata, globalsnode, players, playertype, session, settings_raw, stats, teams, teamtype

    expired

    bool

    @@ -353,6 +353,14 @@ actually award achievements.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    gamedata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    +

    globalsnode

    ba.Node

    @@ -419,7 +427,7 @@ regardless of the player count).

    Creates an Activity in the current ba.Session.

    -

    The activity will not be actually run until ba.Session.set_activity() +

    The activity will not be actually run until ba.Session.setactivity() is called. 'settings' should be a dict of key/value pairs specific to the activity.

    @@ -1288,29 +1296,34 @@ mycall()

    Attributes:

    -
    lobby, player, ready
    +
    lobby, ready, sessionplayer, sessionteam

    lobby

    ba.Lobby

    The chooser's ba.Lobby.

    -
    -

    player

    -

    ba.SessionPlayer

    -

    The ba.Player associated with this chooser.

    -

    ready

    bool

    Whether this chooser is checked in as ready.

    +
    +

    sessionplayer

    +

    ba.SessionPlayer

    +

    The ba.SessionPlayer associated with this chooser.

    + +
    +

    sessionteam

    +

    ba.SessionTeam

    +

    Return this chooser's currently selected ba.SessionTeam.

    +

    Methods:

    -
    <constructor>, get_character_name(), get_color(), get_highlight(), get_lobby(), get_team(), getplayer(), handlemessage(), reload_profiles(), update_from_profile(), update_position()
    +
    <constructor>, get_character_name(), get_color(), get_highlight(), get_lobby(), getplayer(), handlemessage(), reload_profiles(), update_from_profile(), update_position()

    <constructor>

    -

    ba.Chooser(vpos: float, player: _ba.SessionPlayer, lobby: "Lobby")

    +

    ba.Chooser(vpos: float, sessionplayer: _ba.SessionPlayer, lobby: "Lobby")

    get_character_name()

    @@ -1336,12 +1349,6 @@ mycall()

    Return this chooser's lobby if it still exists; otherwise None.

    -
    -

    get_team()

    -

    get_team(self) -> ba.SessionTeam

    - -

    Return this chooser's selected ba.Team.

    -

    getplayer()

    getplayer(self) -> ba.SessionPlayer

    @@ -1545,7 +1552,7 @@ start_long_action(callback_when_done=ba.ContextC

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, globalsnode, map, playertype, session, stats, teamtype
    +
    expired, gamedata, globalsnode, map, playertype, session, stats, teamtype

    expired

    bool

    @@ -1555,6 +1562,14 @@ start_long_action(callback_when_done=ba.ContextC At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    gamedata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    +

    globalsnode

    ba.Node

    @@ -1595,7 +1610,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), end(), end_game(), expire(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -1685,7 +1700,7 @@ there is no associated Campaign.

    Methods Inherited:

    -
    begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    begin_next_activity(), end(), end_activity(), getactivity(), handlemessage(), on_player_request(), on_team_join(), on_team_leave(), setactivity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>, get_current_game_instance(), get_custom_menu_entries(), on_activity_end(), on_player_leave(), restart()
    @@ -2036,7 +2051,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    -
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), setactivity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>

    @@ -2082,7 +2097,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    -
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    announce_game_results(), begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), setactivity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>, get_ffa_point_awards()
    @@ -2130,7 +2145,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, globalsnode, map, playertype, session, stats, teamtype
    +
    expired, gamedata, globalsnode, map, playertype, session, stats, teamtype

    expired

    bool

    @@ -2140,6 +2155,14 @@ its time with lingering corpses, sound effects, etc.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    gamedata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    +

    globalsnode

    ba.Node

    @@ -2180,7 +2203,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), destroy(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), expire(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    @@ -2828,11 +2851,11 @@ can be changed to separate its new high score lists/etc. from the old.

    Attributes:

    -
    teams, use_team_colors
    +
    sessionteams, use_team_colors
    -

    teams

    +

    sessionteams

    List[ba.SessionTeam]

    -

    Teams available in this lobby.

    +

    ba.SessionTeams available in this lobby.

    use_team_colors

    @@ -2851,7 +2874,7 @@ can be changed to separate its new high score lists/etc. from the old.

    add_chooser()

    -

    add_chooser(self, player: ba.SessionPlayer) -> None

    +

    add_chooser(self, sessionplayer: ba.SessionPlayer) -> None

    Add a chooser to the lobby for the provided player.

    @@ -3367,7 +3390,7 @@ Use ba.getmodel() to instantiate one.

    Methods Inherited:

    -
    begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), on_player_leave(), on_player_request(), on_team_leave(), set_activity(), transitioning_out_activity_was_freed()
    +
    begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), on_player_leave(), on_player_request(), on_team_leave(), setactivity(), transitioning_out_activity_was_freed()

    Methods Defined or Overridden:

    <constructor>, announce_game_results(), get_ffa_series_length(), get_game_number(), get_max_players(), get_next_game_description(), get_series_length(), on_activity_end(), on_team_join()
    @@ -3843,13 +3866,29 @@ even if myactor is set to None.

    Category: Gameplay Classes

    -

    These correspond to ba.SessionPlayer objects, but are created per activity - so that the activity can use its own custom player subclass. -

    +

    These correspond to ba.SessionPlayer objects, but are associated with a + single ba.Activity instance. This allows activities to specify their + own custom ba.Player types.

    Attributes:

    -
    node, position, sessionplayer
    +
    actor, gamedata, node, position, sessionplayer, team
    +

    actor

    +

    Optional[ba.Actor]

    +

    The ba.Actor associated with the player.

    + +
    +

    gamedata

    +

    dict

    +

    Arbitrary values associated with the player. + Though it is encouraged that most player values be properly defined + on the ba.Player subclass, it may be useful for player-agnostic + objects to store values here. This dict is cleared when the player + leaves or expires so objects stored here will be disposed of at + the expected time, unlike the Player instance itself which may + continue to be referenced after it is no longer part of the game.

    + +

    node

    ba.Node

    A ba.Node of type 'player' associated with this Player.

    @@ -3859,10 +3898,9 @@ even if myactor is set to None.

    position

    ba.Vec3

    -

    The position of the player, as defined by its current Actor.

    +

    The position of the player, as defined by its current ba.Actor.

    -

    This value should not be used when the player has no Actor, as - it is undefined in that case.

    +

    This value is undefined when the player has no Actor.

    sessionplayer

    @@ -3871,15 +3909,20 @@ even if myactor is set to None.

    Throws a ba.SessionPlayerNotFoundError if it does not exist.

    +
    +

    team

    +

    TeamType

    +

    The ba.Team for this player.

    +

    Methods:

    -
    assign_input_call(), exists(), get_icon(), getname(), is_alive(), reset_input()
    +
    assigninput(), exists(), get_icon(), getname(), is_alive(), on_expire(), resetinput()
    -

    assign_input_call()

    -

    assign_input_call(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    +

    assigninput()

    +

    assigninput(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    -

    assign_input_call(type: Union[str, Tuple[str, ...]], +

    assigninput(type: Union[str, Tuple[str, ...]], call: Callable) -> None

    Set the python callable to be run for one or more types of input. @@ -3896,7 +3939,10 @@ Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress',

    Whether the underlying player still exists.

    -

    Most functionality will fail on a nonexistent player. +

    This will return False if the underlying ba.SessionPlayer has +left the game or if the ba.Activity this player was associated +with has ended. +Most functionality will fail on a nonexistent player. Note that you can also use the boolean operator for this same functionality, so a statement such as "if player" will do the right thing both for Player objects and values of None.

    @@ -3928,10 +3974,21 @@ name may include an icon.

    is_alive() method return True. False is returned otherwise.

    -

    reset_input()

    -

    reset_input(self) -> None

    +

    on_expire()

    +

    on_expire(self) -> None

    -

    reset_input() -> None

    +

    Can be overridden to handle player expiration.

    + +

    The player expires when the Activity it is a part of expires. +Expired players should no longer run any game logic (which will +likely error). They should, however, remove any references to +players/teams/games/etc. which could prevent them from being freed.

    + +
    +

    resetinput()

    +

    resetinput(self) -> None

    + +

    resetinput() -> None

    Clears out the player's assigned input actions.

    @@ -4362,7 +4419,7 @@ player that joins.

    Methods:

    -
    <constructor>, begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), set_activity()
    +
    <constructor>, begin_next_activity(), end(), end_activity(), get_custom_menu_entries(), getactivity(), handlemessage(), on_activity_end(), on_player_leave(), on_player_request(), on_team_join(), on_team_leave(), setactivity()

    <constructor>

    ba.Session(depsets: Sequence[ba.DependencySet], team_names: Sequence[str] = None, team_colors: Sequence[Sequence[float]] = None, min_players: int = 1, max_players: int = 8)

    @@ -4459,15 +4516,15 @@ another ba.Activity.

    Called when a ba.Team is leaving the session.

    -

    set_activity()

    -

    set_activity(self, activity: ba.Activity) -> None

    +

    setactivity()

    +

    setactivity(self, activity: ba.Activity) -> None

    Assign a new current ba.Activity for the session.

    Note that this will not change the current context to the new Activity's. Code must be run in the new activity's methods (on_transition_in, etc) to get it. (so you can't do -session.set_activity(foo) and then ba.newnode() to add a node to foo)

    +session.setactivity(foo) and then ba.newnode() to add a node to foo)

    @@ -4499,7 +4556,7 @@ that a SessionPlayer is still present if retaining references to one for any length of time.

    Attributes:

    -
    character, color, gamedata, gameplayer, highlight, id, in_game, inputdevice, sessiondata, team
    +
    character, color, gameplayer, highlight, id, in_game, inputdevice, sessiondata, team

    character

    str

    @@ -4511,13 +4568,6 @@ for any length of time.

    The base color for this Player. In team games this will match the ba.SessionTeam's color.

    -
    -

    gamedata

    -

    Dict

    -

    A dict for use by the current ba.Activity for -storing data associated with this Player. -This gets cleared for each new ba.Activity.

    -

    gameplayer

    Optional[ba.Player]

    @@ -4568,10 +4618,10 @@ is still in its lobby selecting a team/etc. then a

    Methods:

    -
    assign_input_call(), exists(), get_account_id(), get_icon(), getname(), remove_from_game(), reset_input(), set_name()
    +
    assigninput(), exists(), get_account_id(), get_icon(), getname(), remove_from_game(), resetinput(), setname()
    -

    assign_input_call()

    -

    assign_input_call(type: Union[str, Tuple[str, ...]], +

    assigninput()

    +

    assigninput(type: Union[str, Tuple[str, ...]], call: Callable) -> None

    Set the python callable to be run for one or more types of input. @@ -4619,14 +4669,14 @@ name may include an icon.

    Removes the player from the game.

    -

    reset_input()

    -

    reset_input() -> None

    +

    resetinput()

    +

    resetinput() -> None

    Clears out the player's assigned input actions.

    -

    set_name()

    -

    set_name(name: str, full_name: str = None, real: bool = True) +

    setname()

    +

    setname(name: str, full_name: str = None, real: bool = True) -> None

    Set the player's name to the provided string. @@ -4857,7 +4907,7 @@ of the session.

    Methods:

    <constructor>

    -

    ba.StandLocation(position: _ba.Vec3, angle: Optional[float] = None)

    +

    ba.StandLocation(position: ba.Vec3, angle: Optional[float] = None)

    @@ -4902,7 +4952,7 @@ of the session.

    Methods:

    -
    <constructor>, get_records(), getactivity(), player_got_hit(), player_scored(), player_was_killed(), register_player(), reset(), reset_accum(), set_activity()
    +
    <constructor>, get_records(), getactivity(), player_got_hit(), player_scored(), player_was_killed(), register_player(), reset(), reset_accum(), setactivity()

    <constructor>

    ba.Stats()

    @@ -4960,8 +5010,8 @@ of the session.

    Reset per-sound sub-scores.

    -

    set_activity()

    -

    set_activity(self, activity: Optional[ba.Activity]) -> None

    +

    setactivity()

    +

    setactivity(self, activity: Optional[ba.Activity]) -> None

    Set the current activity for this instance.

    @@ -4979,7 +5029,19 @@ of the session.

    Attributes:

    +
    gamedata, sessionteam
    +

    gamedata

    +

    dict

    +

    Arbitrary values associated with the team. + Though it is encouraged that most player values be properly defined + on the ba.Team subclass, it may be useful for player-agnostic + objects to store values here. This dict is cleared when the team + leaves or expires so objects stored here will be disposed of at + the expected time, unlike the Team instance itself which may + continue to be referenced after it is no longer part of the game.

    + +

    sessionteam

    SessionTeam

    Return the ba.SessionTeam corresponding to this Team.

    @@ -4989,12 +5051,19 @@ of the session.

    Methods:

    +
    manual_init(), on_expire()

    manual_init()

    manual_init(self, team_id: int, name: Union[ba.Lstr, str], color: Tuple[float, ...]) -> None

    Manually init a team for uses such as bots.

    +
    +

    on_expire()

    +

    on_expire(self) -> None

    + +

    Can be overridden to handle team expiration.

    +

    @@ -5011,7 +5080,7 @@ of the session.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, globalsnode, map, playertype, session, stats, teamtype
    +
    expired, gamedata, globalsnode, map, playertype, session, stats, teamtype

    expired

    bool

    @@ -5021,6 +5090,14 @@ of the session.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    +
    +

    gamedata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    +

    globalsnode

    ba.Node

    @@ -5061,7 +5138,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), destroy(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), end_game(), expire(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    From 5d7c72c3659c25db5810aa91abeee2579f8e4f47 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 1 Jun 2020 15:24:36 -0700 Subject: [PATCH 060/417] C++ layer cleanup --- .efrocachemap | 24 +++--- .idea/dictionaries/ericf.xml | 18 +++++ assets/src/ba_data/python/ba/_appdelegate.py | 4 +- assets/src/ba_data/python/ba/_gameactivity.py | 4 +- .../src/ba_data/python/bastd/appdelegate.py | 2 +- config/config.json | 3 +- config/toolconfigsrc/mypy.ini | 3 + docs/ba_module.md | 6 +- tests/test_efro/test_dataclasses.py | 78 ++++++++++++++----- tools/bacommon/servermanager.py | 10 ++- tools/batools/build.py | 16 +++- tools/efro/dataclasses.py | 73 +++++++++++------ tools/efrotools/code.py | 55 ++++++++++--- 13 files changed, 218 insertions(+), 78 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 13656eaf..ce583a6d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/cc/837483543f1d6b184f64b5e6a950", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/e6/d372324c7c08b5b300490fa5594e", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0e/11/3dda0974b64f51be4961628f572c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/76/3f6356dd599091f5955ce349593b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e1/23/3fe78cdef456a99140837ede7e49", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1c/bd/4c73637ee172630ee00145032ce7", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/a7/342bea2a6ec2f94d5de7bb52a59f", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/24/5426cb7e6ca01b9e5d67ad3217b0", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cb/73/469fe3eb016f1e9c7f5c7811b182", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7c/fb/7e0880c1ab90b0484cdedc41c8ae", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f3/f2/097e861cf6ca981b18191e4c43b5", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6b/7c/8407f4a7326b8b19f3e187d3ffcb" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/d6/ebdfb7bda48f2dec85c5df52ced9", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/0e/d344541dc2ae2a6eaf1024c99f7c", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/c3/fe2482149437800c83fed338140e", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/00/78f77d5ab9cc74a2f624f3a7253b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ea/d1/017aaa42a7ace25a7b1f782632e5", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/b3/b149964180b661161e5f86109d99", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/97/177b59dcf24b839ca2d932200bb8", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/55/9edbc1eea06cf354fe37b50d68d2", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fc/ec/eb46555d63e5e3fd55497d1c1079", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/71/73/b8d329287a0a46cc8ed2ef08a7d9", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/62/79/66fc05a4388c4b5a9e9a7fd68a46", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/5d/eb6c20729c0572e717c907482205" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index a91841b1..cc614da7 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -262,6 +262,7 @@ centeuro centiseconds cfconfig + cfenv cfgdir cfgkey cfgkeys @@ -280,6 +281,7 @@ charname charstr chatmessage + cheadersline checkarg checkboxwidget checkenv @@ -323,6 +325,7 @@ codefilenames codefiles codehash + codelines codeop collapsable collidemodel @@ -374,6 +377,7 @@ cpplintcode cpplintcodefull cpplintfull + cpplintmodule cpuinfo cpus cpython @@ -398,6 +402,7 @@ cutscenes cval cwdg + cxxabi cyaml cygwinccompiler darwiin @@ -750,6 +755,7 @@ genmapjson genstartercache genutils + getaccountid getactivity getclass getcollide @@ -833,6 +839,7 @@ hatmotion hattach hdpi + headercheckline headerregistry heapqmodule hehe @@ -960,6 +967,7 @@ keywd keywds khronos + kickable kickin kickstart killcount @@ -987,6 +995,7 @@ lazybuilddir lbits lbld + lbval lcfg lcolor lcrypto @@ -999,8 +1008,10 @@ levelmodule levelname lfull + lfval libcrypto libegl + libgen libinst liblzma libmain @@ -1034,6 +1045,7 @@ lintscriptsfast listobj listvalidconfigs + lival llzma lmerged lmod @@ -1070,6 +1082,7 @@ lstart lstr lstrs + lsval ltex lzma lzmamodule @@ -1208,6 +1221,7 @@ ndkpath neededsettings ness + netlink nettesting netutils nevermind @@ -1576,6 +1590,7 @@ rsdr rsms rstr + rtnetlink rtxt runmypy runonly @@ -1667,6 +1682,7 @@ sharedctypes sharedobj sharedobjs + shellapi shiftdelay shiftposition shobs @@ -1792,6 +1808,8 @@ subrepos subsel subval + subvalue + subvaluetype successfull suiciding sunau diff --git a/assets/src/ba_data/python/ba/_appdelegate.py b/assets/src/ba_data/python/ba/_appdelegate.py index b3d7c768..a1bcb9de 100644 --- a/assets/src/ba_data/python/ba/_appdelegate.py +++ b/assets/src/ba_data/python/ba/_appdelegate.py @@ -34,7 +34,7 @@ class AppDelegate: Category: App Classes """ - def create_default_game_config_ui( + def create_default_game_settings_ui( self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], @@ -47,4 +47,4 @@ class AppDelegate: del gameclass, sessionclass, config, completion_call # unused from ba import _error _error.print_error( - "create_default_game_config_ui needs to be overridden") + "create_default_game_settings_ui needs to be overridden") diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 099ca094..6ed91a80 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -103,8 +103,8 @@ class GameActivity(Activity[PlayerType, TeamType]): """ delegate = _ba.app.delegate assert delegate is not None - delegate.create_default_game_config_ui(cls, sessionclass, settings, - completion_call) + delegate.create_default_game_settings_ui(cls, sessionclass, settings, + completion_call) @classmethod def get_score_info(cls) -> ba.ScoreInfo: diff --git a/assets/src/ba_data/python/bastd/appdelegate.py b/assets/src/ba_data/python/bastd/appdelegate.py index 91e24ac0..11b145d4 100644 --- a/assets/src/ba_data/python/bastd/appdelegate.py +++ b/assets/src/ba_data/python/bastd/appdelegate.py @@ -32,7 +32,7 @@ if TYPE_CHECKING: class AppDelegate(ba.AppDelegate): """Defines handlers for high level app functionality.""" - def create_default_game_config_ui( + def create_default_game_settings_ui( self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], diff --git a/config/config.json b/config/config.json index d3c4e230..793059ca 100644 --- a/config/config.json +++ b/config/config.json @@ -12,7 +12,8 @@ "pytz", "yaml", "requests", - "typing_extensions" + "typing_extensions", + "cpplint" ], "python_paths": [ "assets/src/ba_data/python", diff --git a/config/toolconfigsrc/mypy.ini b/config/toolconfigsrc/mypy.ini index 249b3f67..021dc310 100644 --- a/config/toolconfigsrc/mypy.ini +++ b/config/toolconfigsrc/mypy.ini @@ -21,6 +21,9 @@ no_implicit_reexport = False [mypy-pylint.*] ignore_missing_imports = True +[mypy-cpplint.*] +ignore_missing_imports = True + [mypy-xml.*] ignore_missing_imports = True diff --git a/docs/ba_module.md b/docs/ba_module.md index 9768dcf4..79375f9e 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-05-31 for Ballistica version 1.5.0 build 20036

    +

    last updated on 2020-06-01 for Ballistica version 1.5.0 build 20037

    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!


    @@ -1079,8 +1079,8 @@ manually.

    Methods:

    -

    create_default_game_config_ui()

    -

    create_default_game_config_ui(self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None

    +

    create_default_game_settings_ui()

    +

    create_default_game_settings_ui(self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None

    Launch a UI to configure the given game config.

    diff --git a/tests/test_efro/test_dataclasses.py b/tests/test_efro/test_dataclasses.py index a2bf51f5..f00c4aa9 100644 --- a/tests/test_efro/test_dataclasses.py +++ b/tests/test_efro/test_dataclasses.py @@ -22,7 +22,7 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import TYPE_CHECKING import pytest @@ -30,11 +30,12 @@ import pytest from efro.dataclasses import dataclass_assign, dataclass_validate if TYPE_CHECKING: - from typing import Optional + from typing import Optional, List def test_assign() -> None: """Testing various assignments.""" + # pylint: disable=too-many-statements @dataclass class _TestClass: @@ -46,6 +47,10 @@ def test_assign() -> None: osval: Optional[str] = None obval: Optional[bool] = None ofval: Optional[float] = None + lsval: List[str] = field(default_factory=list) + lival: List[int] = field(default_factory=list) + lbval: List[bool] = field(default_factory=list) + lfval: List[float] = field(default_factory=list) tclass = _TestClass() @@ -66,24 +71,39 @@ def test_assign() -> None: dataclass_assign(tclass, {'nonexistent': 'foo'}) # Correct types. - dataclass_assign(tclass, { - 'ival': 1, - 'sval': 'foo', - 'bval': True, - 'fval': 2.0, - }) - dataclass_assign(tclass, { - 'oival': None, - 'osval': None, - 'obval': None, - 'ofval': None, - }) - dataclass_assign(tclass, { - 'oival': 1, - 'osval': 'foo', - 'obval': True, - 'ofval': 2.0, - }) + dataclass_assign( + tclass, { + 'ival': 1, + 'sval': 'foo', + 'bval': True, + 'fval': 2.0, + 'lsval': ['foo'], + 'lival': [10], + 'lbval': [False], + 'lfval': [1.0] + }) + dataclass_assign( + tclass, { + 'oival': None, + 'osval': None, + 'obval': None, + 'ofval': None, + 'lsval': [], + 'lival': [], + 'lbval': [], + 'lfval': [] + }) + dataclass_assign( + tclass, { + 'oival': 1, + 'osval': 'foo', + 'obval': True, + 'ofval': 2.0, + 'lsval': ['foo', 'bar', 'eep'], + 'lival': [10, 11, 12], + 'lbval': [False, True], + 'lfval': [1.0, 2.0, 3.0] + }) # Type mismatches. with pytest.raises(TypeError): @@ -107,6 +127,21 @@ def test_assign() -> None: with pytest.raises(TypeError): dataclass_assign(tclass, {'ofval': 'blah'}) + with pytest.raises(TypeError): + dataclass_assign(tclass, {'lsval': 'blah'}) + + with pytest.raises(TypeError): + dataclass_assign(tclass, {'lsval': [1]}) + + with pytest.raises(TypeError): + dataclass_assign(tclass, {'lbval': [None]}) + + with pytest.raises(TypeError): + dataclass_assign(tclass, {'lival': ['foo']}) + + with pytest.raises(TypeError): + dataclass_assign(tclass, {'lfval': [True]}) + # More subtle ones (we currently require EXACT type matches) with pytest.raises(TypeError): dataclass_assign(tclass, {'ival': True}) @@ -120,6 +155,9 @@ def test_assign() -> None: with pytest.raises(TypeError): dataclass_assign(tclass, {'ofval': 1}) + with pytest.raises(TypeError): + dataclass_assign(tclass, {'lfval': [1]}) + def test_validate() -> None: """Testing validation.""" diff --git a/tools/bacommon/servermanager.py b/tools/bacommon/servermanager.py index c00d2db8..afa1d87d 100644 --- a/tools/bacommon/servermanager.py +++ b/tools/bacommon/servermanager.py @@ -22,7 +22,7 @@ from __future__ import annotations from enum import Enum -from dataclasses import dataclass +from dataclasses import dataclass, field from typing import TYPE_CHECKING if TYPE_CHECKING: @@ -45,6 +45,14 @@ class ServerConfig: # be enabled unless you are hosting on a LAN with no internet connection. authenticate_clients: bool = True + # IDs of server admins. Server admins are not kickable through the default + # kick vote system and they are able to kick players without a vote. To get + # your account id, enter 'getaccountid' in settings->advanced->enter-code. + admins: List[str] = field(default_factory=list) + + # Whether the default kick-voting system is enabled. + enable_default_kick_voting: bool = True + # UDP port to host on. Change this to work around firewalls or run multiple # servers on one machine. # 43210 is the default and the only port that will show up in the LAN diff --git a/tools/batools/build.py b/tools/batools/build.py index db1c366e..c4fa9561 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -33,7 +33,7 @@ from typing import TYPE_CHECKING from efro.terminal import Clr if TYPE_CHECKING: - from typing import List, Sequence, Optional + from typing import List, Sequence, Optional, Any # Python pip packages we require for this project. @@ -612,7 +612,11 @@ def _get_server_config_template_yaml(projroot: str) -> str: assert vname.endswith(':') vname = vname[:-1] assert veq == '=' - vval = eval(vval_raw) # pylint: disable=eval-used + vval: Any + if vval_raw == 'field(default_factory=list)': + vval = [] + else: + vval = eval(vval_raw) # pylint: disable=eval-used # Filter/override a few things. if vname == 'playlist_code': @@ -621,7 +625,13 @@ def _get_server_config_template_yaml(projroot: str) -> str: elif vname == 'stats_url': vval = ('https://mystatssite.com/' 'showstats?player=${ACCOUNT}') - lines_out.append('#' + yaml.dump({vname: vval}).strip()) + elif vname == 'admins': + vval = ['pb-yOuRAccOuNtIdHErE', 'pb-aNdMayBeAnotherHeRE'] + lines_out += [ + '#' + l for l in yaml.dump({ + vname: vval + }).strip().splitlines() + ] else: # Convert comments referring to python bools to yaml bools. line = line.replace('True', 'true').replace('False', 'false') diff --git a/tools/efro/dataclasses.py b/tools/efro/dataclasses.py index c313fb2f..38edc2d2 100644 --- a/tools/efro/dataclasses.py +++ b/tools/efro/dataclasses.py @@ -30,9 +30,9 @@ if TYPE_CHECKING: # For fields with these string types, we require a passed value's type # to exactly match one of the tuple values to consider the assignment valid. _SIMPLE_ASSIGN_TYPES: Dict[str, Tuple[Type, ...]] = { - 'bool': (bool, ), - 'str': (str, ), 'int': (int, ), + 'str': (str, ), + 'bool': (bool, ), 'float': (float, ), 'Optional[int]': (int, type(None)), 'Optional[str]': (str, type(None)), @@ -40,6 +40,13 @@ _SIMPLE_ASSIGN_TYPES: Dict[str, Tuple[Type, ...]] = { 'Optional[float]': (float, type(None)), } +_LIST_ASSIGN_TYPES: Dict[str, Tuple[Type, ...]] = { + 'List[int]': (int, ), + 'List[str]': (str, ), + 'List[bool]': (bool, ), + 'List[float]': (float, ), +} + def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None: """Safely assign values from a dict to a dataclass instance. @@ -60,6 +67,22 @@ def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None: the increased safety checks may be worth the speed tradeoff in some cases. """ + _dataclass_validate(instance, values) + for key, value in values.items(): + setattr(instance, key, value) + + +def dataclass_validate(instance: Any) -> None: + """Ensure values in a dataclass are correct types. + + Note that this will always fail if a dataclass contains field types + not supported by this module. + """ + _dataclass_validate(instance, dataclasses.asdict(instance)) + + +def _dataclass_validate(instance: Any, values: Dict[str, Any]) -> None: + # pylint: disable=too-many-branches if not dataclasses.is_dataclass(instance): raise TypeError(f'Passed instance {instance} is not a dataclass.') if not isinstance(values, dict): @@ -82,10 +105,10 @@ def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None: f' been created without "from __future__ import annotations";' f' those dataclasses are unsupported here.') - reqtypes = _SIMPLE_ASSIGN_TYPES.get(fieldtype) - if reqtypes is not None: - # pylint: disable=unidiomatic-typecheck - if not any(type(value) is t for t in reqtypes): + if fieldtype in _SIMPLE_ASSIGN_TYPES: + reqtypes = _SIMPLE_ASSIGN_TYPES[fieldtype] + valuetype = type(value) + if not any(valuetype is t for t in reqtypes): if len(reqtypes) == 1: expected = reqtypes[0].__name__ else: @@ -93,23 +116,25 @@ def dataclass_assign(instance: Any, values: Dict[str, Any]) -> None: expected = f'Union[{names}]' raise TypeError(f'Invalid value type for "{key}";' f' expected "{expected}", got' - f' "{type(value).__name__}".') + f' "{valuetype.__name__}".') + + elif fieldtype in _LIST_ASSIGN_TYPES: + reqtypes = _LIST_ASSIGN_TYPES[fieldtype] + if not isinstance(value, list): + raise TypeError( + f'Invalid value for "{key}";' + f' expected a list, got a "{type(value).__name__}"') + for subvalue in value: + subvaluetype = type(subvalue) + if not any(subvaluetype is t for t in reqtypes): + if len(reqtypes) == 1: + expected = reqtypes[0].__name__ + else: + names = ', '.join(t.__name__ for t in reqtypes) + expected = f'Union[{names}]' + raise TypeError(f'Invalid value type for "{key}";' + f' expected list of "{expected}", found' + f' "{subvaluetype.__name__}".') + else: raise TypeError(f'Field type "{fieldtype}" is unsupported here.') - - # Ok, if we made it here, the value is kosher. Do the assign. - setattr(instance, key, value) - - -def dataclass_validate(instance: Any) -> None: - """Ensure values in a dataclass are correct types. - - Note that this will always fail if a dataclass contains field types - not supported by this module. - """ - # We currently simply operate by grabbing dataclass values as a dict - # and passing them through dataclass_assign(). - # It would be possible to write slightly more efficient custom code, - # this, but this keeps things simple and will allow us to easily - # incorporate things like value coercion later if we add that. - dataclass_assign(instance, dataclasses.asdict(instance)) diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index bc6a4eb7..aea849f8 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -82,15 +82,19 @@ def formatcode(projroot: Path, full: bool) -> None: def cpplint(projroot: Path, full: bool) -> None: """Run lint-checking on all code deemed lint-able.""" + # pylint: disable=too-many-locals + import tempfile from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count from efrotools import get_config from efro.terminal import Clr + from efro.error import CleanError os.chdir(projroot) filenames = get_code_filenames(projroot) - if any(' ' in name for name in filenames): - raise Exception('found space in path; unexpected') + for fpath in filenames: + if ' ' in fpath: + raise Exception(f'Found space in path {fpath}; unexpected.') # Check the config for a list of ones to ignore. code_blacklist: List[str] = get_config(projroot).get( @@ -114,14 +118,47 @@ def cpplint(projroot: Path, full: bool) -> None: print(f'{Clr.BLU}CppLint checking' f' {len(dirtyfiles)} file(s)...{Clr.RST}') - def lint_file(filename: str) -> None: - result = subprocess.call(['cpplint', '--root=src', filename]) - if result != 0: - raise Exception(f'Linting failed for {filename}') + # We want to do a few custom modifications to the cpplint module... + try: + import cpplint as cpplintmodule + except Exception: + raise CleanError('Unable to import cpplint') + with open(cpplintmodule.__file__) as infile: + codelines = infile.read().splitlines() + cheadersline = codelines.index('_C_HEADERS = frozenset([') - with ThreadPoolExecutor(max_workers=cpu_count()) as executor: - # Converting this to a list will propagate any errors. - list(executor.map(lint_file, dirtyfiles)) + # Extra headers we consider as valid C system headers. + c_headers = [ + 'malloc.h', 'tchar.h', 'jni.h', 'android/log.h', 'EGL/egl.h', + 'libgen.h', 'linux/netlink.h', 'linux/rtnetlink.h', 'android/bitmap.h', + 'android/log.h', 'uuid/uuid.h', 'cxxabi.h', 'direct.h', 'shellapi.h', + 'rpc.h', 'io.h' + ] + codelines.insert(cheadersline + 1, ''.join(f"'{h}'," for h in c_headers)) + + # Skip unapproved C++ headers check (it flags , , etc.) + headercheckline = codelines.index( + " if include and include.group(1) in ('cfenv',") + codelines[headercheckline] = ( + " if False and include and include.group(1) in ('cfenv',") + + def lint_file(filename: str) -> None: + result = subprocess.call(['cpplint', '--root=src', filename], env=env) + if result != 0: + raise CleanError( + f'{Clr.RED}Cpplint failed for {filename}.{Clr.RST}') + + with tempfile.TemporaryDirectory() as tmpdir: + + # Write our replacement module, make it discoverable, then run. + with open(tmpdir + '/cpplint.py', 'w') as outfile: + outfile.write('\n'.join(codelines)) + env = os.environ.copy() + env['PYTHONPATH'] = tmpdir + + with ThreadPoolExecutor(max_workers=cpu_count()) as executor: + # Converting this to a list will propagate any errors. + list(executor.map(lint_file, dirtyfiles)) if dirtyfiles: cache.mark_clean(filenames) From 7788f61e6ce80839b2f3fa31e971eb51b138991e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 1 Jun 2020 15:56:39 -0700 Subject: [PATCH 061/417] Added cpplint requirement --- tools/batools/build.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/batools/build.py b/tools/batools/build.py index c4fa9561..524b3043 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -49,6 +49,7 @@ PIP_REQUIREMENTS = [ PipRequirement(modulename='pylint', minversion=[2, 5, 2]), PipRequirement(modulename='mypy', minversion=[0, 770]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), + PipRequirement(modulename='cpplint', minversion=[1, 5, 0]), PipRequirement(modulename='typing_extensions'), PipRequirement(modulename='pytz'), PipRequirement(modulename='yaml', pipname='PyYAML'), @@ -526,7 +527,10 @@ def checkenv() -> None: f'To install it, try: "{PYTHON_BIN}' f' -m pip install {packagename}"') if minver is not None: - ver_line = results.stdout.decode().splitlines()[0] + verlines = results.stdout.decode().splitlines() + if verlines[0].startswith('Cpplint fork'): + verlines = verlines[1:] + ver_line = verlines[0] assert modname in ver_line vnums = [int(x) for x in ver_line.split()[-1].split('.')] assert len(vnums) == len(minver) From e0c827cd0ecf940c901fef2c7e0bf5331d464168 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 1 Jun 2020 18:12:44 -0700 Subject: [PATCH 062/417] Added server admin functionality. --- .efrocachemap | 36 ++++++++++----------- .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 18 ++++++++++- assets/src/ba_data/python/ba/_servermode.py | 6 ++++ docs/ba_module.md | 2 +- tools/snippets | 4 +-- 6 files changed, 45 insertions(+), 22 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index ce583a6d..c6f8425d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,24 +420,24 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/da/06/8e06488b46a0a213abde3cfeb364", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/98/6d/e6de20b119fd6a5914982cd468b6", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/0c/cd/798753aa6c55f3a4cdccda0b23ab", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/15/1b/3e0690b975c7cafbfa65e3aafad3", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/aa/91/2411c0728bae33619c21237a2689", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f2/90/62968ad28a2499a8d182a5740a85", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", - "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/94/bb/79fd4608f4a3e22526442ba77090", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/b4/fe/f33399347c16a13f17e920c7e33c", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/95/9b/66e9080c82ef76387832dedee9b4", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/9d/00/a8c4ef9f0a25e789c046bd741203", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/d7/54/541b617f3c00e3914ee5faef9d10", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/e7/ff/638467708af1e2eea569e9225906", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/7a/64/04464dc6ee8a45632857fa436bff", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/4f/1e/334843131d672fa6b5f6f1056e56", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/8e/e7/38e093014a917418e6cf7aa9315d", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/05/fbdf4d90b85609e4fa258e1ce814", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06", @@ -447,7 +447,7 @@ "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/78/5e/d24967ddaa15e0a574bd274544db", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/bf/1f/f9f707434db43126746a5be6e878", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/90/d9/0f8f5b03bbe2dfebfb544cee6bd6", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/b6/c9/999c95ff8d917126352a306d89a3", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/e0/f7/f6daa488dc29e303dea69aae864b", @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/d6/ebdfb7bda48f2dec85c5df52ced9", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/0e/d344541dc2ae2a6eaf1024c99f7c", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/c3/fe2482149437800c83fed338140e", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/00/78f77d5ab9cc74a2f624f3a7253b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ea/d1/017aaa42a7ace25a7b1f782632e5", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/b3/b149964180b661161e5f86109d99", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/97/177b59dcf24b839ca2d932200bb8", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/55/9edbc1eea06cf354fe37b50d68d2", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fc/ec/eb46555d63e5e3fd55497d1c1079", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/71/73/b8d329287a0a46cc8ed2ef08a7d9", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/62/79/66fc05a4388c4b5a9e9a7fd68a46", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/5d/eb6c20729c0572e717c907482205" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/96/a0/04fd3bb8245edd1d4e5845cc4629", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/7e/82399a3b10f5a9d73a76c1cfb16e", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/30/f0/cfd79764333c0282c8ffdec3c942", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/02/51/5ac1a2bc29cf8639ba65629fa009", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/ff/e78f3f17b45eea5d0359e68c311a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/bf/dade39164bd18003c8bd51b05119", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/7e/30bfdd3a09b468014a4cde5cf3b7", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/cf/b25179f9e1db8b6b774ba6a31e82", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/71/fd/90b17177aee6354de45cc205f65c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c2/ac/d87356932ec11dc4bac0d988145e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ce/7b/6ec6f8b2da73e1b2b64b64192712", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/78/78/3639288018f221c9e978f391abd8" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index cc614da7..58339e57 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -2045,6 +2045,7 @@ vartype vcxproj venv + verlines versioning versionpredicate vert diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index e85e61f2..f33fbb95 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=172645630847706592745162067676099526148 +# SOURCES_HASH=247084187994045015646460724420234222242 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -3347,6 +3347,14 @@ def scrollwidget(edit: ba.Widget = None, return ba.Widget() +def set_admins(admins: List[str]) -> None: + """set_admins(admins: List[str]) -> None + + (internal) + """ + return None + + def set_analytics_screen(screen: str) -> None: """set_analytics_screen(screen: str) -> None @@ -3379,6 +3387,14 @@ def set_debug_speed_exponent(speed: int) -> None: return None +def set_enable_default_kick_voting(enable: bool) -> None: + """set_enable_default_kick_voting(enable: bool) -> None + + (internal) + """ + return None + + def set_have_mods(have_mods: bool) -> None: """set_have_mods(have_mods: bool) -> None diff --git a/assets/src/ba_data/python/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py index 0ffd8fa8..882aa6ac 100644 --- a/assets/src/ba_data/python/ba/_servermode.py +++ b/assets/src/ba_data/python/ba/_servermode.py @@ -65,6 +65,7 @@ def _cmd(command_data: bytes) -> None: if isinstance(command, ScreenMessageCommand): assert _ba.app.server is not None + # Note: we have to do transient messages if # clients is specified, so they won't show up # in replays. @@ -241,6 +242,7 @@ class ServerController: f' joinable from the internet.{poststr}{Clr.RST}') def _prepare_to_serve(self) -> None: + """Run in a timer to do prep before beginning to serve.""" signed_in = _ba.get_account_state() == 'signed_in' if not signed_in: @@ -339,6 +341,10 @@ class ServerController: _ba.set_authenticate_clients(self._config.authenticate_clients) + _ba.set_enable_default_kick_voting( + self._config.enable_default_kick_voting) + _ba.set_admins(self._config.admins) + # Call set-enabled last (will push state to the cloud). _ba.set_public_party_max_size(self._config.max_party_size) _ba.set_public_party_name(self._config.party_name) diff --git a/docs/ba_module.md b/docs/ba_module.md index 79375f9e..34fb6596 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-01 for Ballistica version 1.5.0 build 20037

    +

    last updated on 2020-06-01 for Ballistica version 1.5.0 build 20039

    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!


    diff --git a/tools/snippets b/tools/snippets index 09733841..2a052e4b 100755 --- a/tools/snippets +++ b/tools/snippets @@ -113,9 +113,9 @@ def resize_image() -> None: src = sys.argv[4] dst = sys.argv[5] if not dst.endswith('.png'): - raise Exception('dst must be a png') + raise RuntimeError(f'dst must be a png; got "{dst}"') if not src.endswith('.png'): - raise Exception('src must be a png') + raise RuntimeError(f'src must be a png; got "{src}"') print('Creating: ' + os.path.basename(dst), file=sys.stderr) efrotools.run(f'convert "{src}" -resize {width}x{height} "{dst}"') From ae0c9dde20e63cf5131adb144a6e0325cf044ffe Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 1 Jun 2020 22:08:59 -0700 Subject: [PATCH 063/417] Modernized keepaway code --- .efrocachemap | 24 +++--- .idea/dictionaries/ericf.xml | 4 + .../python/bastd/game/capturetheflag.py | 2 +- .../src/ba_data/python/bastd/game/keepaway.py | 81 +++++++++---------- 4 files changed, 55 insertions(+), 56 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index c6f8425d..62ce73ba 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/96/a0/04fd3bb8245edd1d4e5845cc4629", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/7e/82399a3b10f5a9d73a76c1cfb16e", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/30/f0/cfd79764333c0282c8ffdec3c942", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/02/51/5ac1a2bc29cf8639ba65629fa009", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/ff/e78f3f17b45eea5d0359e68c311a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/bf/dade39164bd18003c8bd51b05119", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/7e/30bfdd3a09b468014a4cde5cf3b7", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/cf/b25179f9e1db8b6b774ba6a31e82", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/71/fd/90b17177aee6354de45cc205f65c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c2/ac/d87356932ec11dc4bac0d988145e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ce/7b/6ec6f8b2da73e1b2b64b64192712", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/78/78/3639288018f221c9e978f391abd8" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/2c/d64f68f0e4ecbb55f3731ad95530", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/cd/c8c9b3e4a265ac816c5d249e4638", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/29/92/c312438bf1dbdb599bd020a5c220", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/75/6686aa5b6e0f88e1a40d444fd013", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c1/bc/23b3f5d0929adf8c497accad24bb", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/81/07/d95b4d6354acf4003f70307ba7cb", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2c/bd/18dff8eda46be2d2edeee0a7ece9", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/64/a0beab66455ed6be694583fb6d53", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a2/ba/1e71e85b38eed56a55f8e0d85821", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dd/38/d98994fed8732ab774e879b0c8a5", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2c/e0/97ebbdf740a3bfbc5324f510204e", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4e/69/2af7295ec87bcf480e57f41e19a7" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 58339e57..f8e28694 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -856,6 +856,9 @@ hmmm hmmmm hoffs + holdingflag + holdingteam + holdingteams holdposition homebook homebrew @@ -1427,6 +1430,7 @@ premultiply preprocessing prereqs + prevstate priceraw printcolors printnodes diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index dd293beb..79528594 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -170,7 +170,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self.flag_touch_return_time = float(settings['Flag Touch Return Time']) self.flag_idle_return_time = float(settings['Flag Idle Return Time']) - # Base class overrides + # Base class overrides. self.slow_motion = self._epic_mode self.default_music = (ba.MusicType.EPIC if self._epic_mode else ba.MusicType.FLAG_CATCHER) diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index fae6bada..0dda4482 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -53,6 +53,10 @@ class Player(ba.Player['Team']): class Team(ba.Team[Player]): """Our team type for this game.""" + def __init__(self, timeremaining: int) -> None: + self.timeremaining = timeremaining + self.holdingflag = False + # ba_meta export game class KeepAwayGame(ba.TeamGameActivity[Player, Team]): @@ -79,6 +83,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): }), ] score_info = ba.ScoreInfo(label='Time Held') + default_music = ba.MusicType.KEEP_AWAY @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: @@ -113,26 +118,24 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): self._flag_light: Optional[ba.Node] = None self._scoring_team: Optional[Team] = None self._flag: Optional[Flag] = None + self._hold_time = int(settings['Hold Time']) + self._time_limit = float(settings['Time Limit']) def get_instance_description(self) -> Union[str, Sequence]: - return ('Carry the flag for ${ARG1} seconds.', - self.settings_raw['Hold Time']) + return 'Carry the flag for ${ARG1} seconds.', self._hold_time def get_instance_description_short(self) -> Union[str, Sequence]: - return ('carry the flag for ${ARG1} seconds', - self.settings_raw['Hold Time']) + return 'carry the flag for ${ARG1} seconds', self._hold_time - def on_transition_in(self) -> None: - self.default_music = ba.MusicType.KEEP_AWAY - super().on_transition_in() + def create_team(self, sessionteam: ba.SessionTeam) -> Team: + return Team(timeremaining=self._hold_time) def on_team_join(self, team: Team) -> None: - team.gamedata['time_remaining'] = self.settings_raw['Hold Time'] self._update_scoreboard() def on_begin(self) -> None: super().on_begin() - self.setup_standard_time_limit(self.settings_raw['Time Limit']) + self.setup_standard_time_limit(self._time_limit) self.setup_standard_powerup_drops() self._flag_spawn_pos = self.map.get_flag_position(None) self._spawn_flag() @@ -152,82 +155,74 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): screenmessage=False, display=False) - scoring_team = self._scoring_team + scoreteam = self._scoring_team - if scoring_team is not None: + if scoreteam is not None: - if scoring_team.gamedata['time_remaining'] > 0: + if scoreteam.timeremaining > 0: ba.playsound(self._tick_sound) - scoring_team.gamedata['time_remaining'] = max( - 0, scoring_team.gamedata['time_remaining'] - 1) + scoreteam.timeremaining = max(0, scoreteam.timeremaining - 1) self._update_scoreboard() - if scoring_team.gamedata['time_remaining'] > 0: + if scoreteam.timeremaining > 0: assert self._flag is not None - self._flag.set_score_text( - str(scoring_team.gamedata['time_remaining'])) + self._flag.set_score_text(str(scoreteam.timeremaining)) # Announce numbers we have sounds for. - try: - ba.playsound(self._countdownsounds[ - scoring_team.gamedata['time_remaining']]) - except Exception: - pass + if scoreteam.timeremaining in self._countdownsounds: + ba.playsound(self._countdownsounds[scoreteam.timeremaining]) # Winner. - if scoring_team.gamedata['time_remaining'] <= 0: + if scoreteam.timeremaining <= 0: self.end_game() def end_game(self) -> None: results = ba.TeamGameResults() for team in self.teams: - results.set_team_score( - team, self.settings_raw['Hold Time'] - - team.gamedata['time_remaining']) + results.set_team_score(team, self._hold_time - team.timeremaining) self.end(results=results, announce_delay=0) def _update_flag_state(self) -> None: for team in self.teams: - team.gamedata['holding_flag'] = False + team.holdingflag = False self._holding_players = [] for player in self.players: - holding_flag = False + holdingflag = False try: assert isinstance(player.actor, (PlayerSpaz, type(None))) if (player.actor and player.actor.node and player.actor.node.hold_node): - holding_flag = ( + holdingflag = ( player.actor.node.hold_node.getnodetype() == 'flag') except Exception: ba.print_exception('exception checking hold flag') - if holding_flag: + if holdingflag: self._holding_players.append(player) - player.team.gamedata['holding_flag'] = True + player.team.holdingflag = True - holding_teams = set(t for t in self.teams - if t.gamedata['holding_flag']) - prev_state = self._flag_state + holdingteams = set(t for t in self.teams if t.holdingflag) + prevstate = self._flag_state assert self._flag is not None assert self._flag_light assert self._flag.node - if len(holding_teams) > 1: + if len(holdingteams) > 1: self._flag_state = FlagState.CONTESTED self._scoring_team = None self._flag_light.color = (0.6, 0.6, 0.1) self._flag.node.color = (1.0, 1.0, 0.4) - elif len(holding_teams) == 1: - holding_team = list(holding_teams)[0] + elif len(holdingteams) == 1: + holdingteam = list(holdingteams)[0] self._flag_state = FlagState.HELD - self._scoring_team = holding_team - self._flag_light.color = ba.normalized_color(holding_team.color) - self._flag.node.color = holding_team.color + self._scoring_team = holdingteam + self._flag_light.color = ba.normalized_color(holdingteam.color) + self._flag.node.color = holdingteam.color else: self._flag_state = FlagState.UNCONTESTED self._scoring_team = None self._flag_light.color = (0.2, 0.2, 0.2) self._flag.node.color = (1, 1, 1) - if self._flag_state != prev_state: + if self._flag_state != prevstate: ba.playsound(self._swipsound) def _spawn_flag(self) -> None: @@ -261,8 +256,8 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): def _update_scoreboard(self) -> None: for team in self.teams: self._scoreboard.set_team_value(team, - team.gamedata['time_remaining'], - self.settings_raw['Hold Time'], + team.timeremaining, + self._hold_time, countdown=True) def handlemessage(self, msg: Any) -> Any: From 24f279223474f1370820846212538f0b81067437 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 01:45:12 -0700 Subject: [PATCH 064/417] More type safety and simplifying --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 16 ++ assets/src/ba_data/python/_ba.py | 12 +- assets/src/ba_data/python/ba/__init__.py | 2 +- assets/src/ba_data/python/ba/_activity.py | 18 +- .../src/ba_data/python/ba/_activitytypes.py | 19 +- assets/src/ba_data/python/ba/_coopsession.py | 42 ++- .../src/ba_data/python/ba/_dualteamsession.py | 7 +- .../ba_data/python/ba/_freeforallsession.py | 16 +- assets/src/ba_data/python/ba/_gameactivity.py | 11 +- assets/src/ba_data/python/ba/_gameresults.py | 93 +++---- assets/src/ba_data/python/ba/_general.py | 43 +++- .../ba_data/python/ba/_multiteamsession.py | 17 +- assets/src/ba_data/python/ba/_player.py | 18 +- assets/src/ba_data/python/ba/_session.py | 4 +- assets/src/ba_data/python/ba/_stats.py | 34 +-- assets/src/ba_data/python/ba/_team.py | 37 +-- .../python/bastd/activity/coopscore.py | 28 +- .../python/bastd/activity/dualteamscore.py | 12 +- .../bastd/activity/freeforallvictory.py | 37 +-- .../python/bastd/activity/multiteamscore.py | 8 +- .../python/bastd/activity/multiteamvictory.py | 8 +- .../ba_data/python/bastd/actor/respawnicon.py | 15 +- .../ba_data/python/bastd/actor/scoreboard.py | 6 +- .../src/ba_data/python/bastd/game/conquest.py | 10 +- .../python/bastd/game/easteregghunt.py | 4 +- .../src/ba_data/python/bastd/game/football.py | 33 ++- .../python/bastd/game/kingofthehill.py | 1 - .../ba_data/python/bastd/game/ninjafight.py | 6 +- .../ba_data/python/bastd/game/onslaught.py | 6 +- .../ba_data/python/bastd/game/runaround.py | 6 +- .../ba_data/python/bastd/game/thelaststand.py | 2 +- docs/ba_module.md | 240 +++++++++--------- 33 files changed, 444 insertions(+), 391 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 62ce73ba..6ff19b51 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/2c/d64f68f0e4ecbb55f3731ad95530", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/86/cd/c8c9b3e4a265ac816c5d249e4638", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/29/92/c312438bf1dbdb599bd020a5c220", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/75/6686aa5b6e0f88e1a40d444fd013", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c1/bc/23b3f5d0929adf8c497accad24bb", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/81/07/d95b4d6354acf4003f70307ba7cb", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2c/bd/18dff8eda46be2d2edeee0a7ece9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/64/a0beab66455ed6be694583fb6d53", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a2/ba/1e71e85b38eed56a55f8e0d85821", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dd/38/d98994fed8732ab774e879b0c8a5", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2c/e0/97ebbdf740a3bfbc5324f510204e", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4e/69/2af7295ec87bcf480e57f41e19a7" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/15/7a/d4e39ad022b8365418ecee4d026b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/ad/7e371dfb7ed7b10d46f0bf9497d8", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/92/28/faa6501d779b381dec7fb9ac19c5", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/57/97d03c6230cfc4d9f0687249f408", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/e1/a3a86c40804f1e724c59ee04f1a2", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ae/78/7a6522e860506fe1046808ce7b0b", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/08/71/09be3ad2f8cf99f885549a7296a0", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/49/3c1d3c8a995df400e46df3470b02", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/43/d4/48ec85af308fd027d7dd06eaa650", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cc/1b/303089d3c1f3b7620c632ee864c3", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f2/55/890f1b498ccf5988dee573d5f3ca", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b9/b1/d96d693c3ad52cedd4f517fd9d94" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index f8e28694..1763add7 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -398,6 +398,7 @@ curstate curtime curtimestr + customdata customizebrowser cutscenes cval @@ -604,6 +605,7 @@ factoryclass fallbacks farthestpt + fback fbase fclose fcmd @@ -874,6 +876,7 @@ icns iconpicker iconscale + iconsstorename ident idevices ifeq @@ -910,6 +913,7 @@ infotextcolor inidividual initializers + initialplayerinfos initing inits inmobi @@ -1110,6 +1114,8 @@ mapselect maptype markupbase + masktex + masktexstorename mathmodule mathnode mathutils @@ -1163,6 +1169,7 @@ moduledir modulefinder modulename + modulepath modutils moola mopaque @@ -1204,6 +1211,7 @@ myhome myinput mylist + mymodule mynode myobj myprojname @@ -1214,6 +1222,7 @@ mypytype mysound mytextnode + mythingie myweakcall mywidget namedarg @@ -1360,6 +1369,7 @@ pkgutil playercast playerdata + playerinfos playerlostspaz playernode playerpt @@ -1533,6 +1543,7 @@ qrcode qrencode qual + qualname quoprimime rando randommodule @@ -1786,8 +1797,10 @@ steelseries stickman storable + storagename storedhash storeitemui + storename strftime stringprep stringptr @@ -1913,6 +1926,7 @@ thanvannispen thelaststand themself + thingie threadtype throwiness timedisplay @@ -2095,6 +2109,8 @@ willeval wincfg wincount + winnergroup + winnergroups winplt winprj winref diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index f33fbb95..fb7554fd 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=247084187994045015646460724420234222242 +# SOURCES_HASH=214847179904844500339904334878206016957 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -822,16 +822,11 @@ class SessionPlayer: This bool value will be True once the Player has completed any lobby character/team selection. - team: ba.SessionTeam + sessionteam: ba.SessionTeam The ba.SessionTeam this Player is on. If the SessionPlayer is still in its lobby selecting a team/etc. then a ba.SessionTeamNotFoundError will be raised. - sessiondata: Dict - A dict for use by the current ba.Session for - storing data associated with this player. - This persists for the duration of the session. - inputdevice: ba.InputDevice The input device associated with the player. @@ -853,8 +848,7 @@ class SessionPlayer: """ id: int in_game: bool - team: ba.SessionTeam - sessiondata: Dict + sessionteam: ba.SessionTeam inputdevice: ba.InputDevice color: Sequence[float] highlight: Sequence[float] diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 3a2d949a..936cdef6 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -73,7 +73,7 @@ from ba._campaign import Campaign from ba._gameutils import (animate, animate_array, show_damage_count, timestring, cameraflash) from ba._general import (WeakCall, Call, existing, Existable, - verify_object_death) + verify_object_death, storagename) from ba._level import Level from ba._lobby import Lobby, Chooser from ba._math import normalized_color, is_point_in_box, vec3validate diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index c5c5b8f7..6c494c5f 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -215,7 +215,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self.lobby = None self._stats: Optional[ba.Stats] = None - self._gamedata: Optional[dict] = {} + self._customdata: Optional[dict] = {} def __del__(self) -> None: @@ -265,15 +265,15 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): """ @property - def gamedata(self) -> dict: + def customdata(self) -> dict: """Entities needing to store simple data with an activity can put it here. This dict will be deleted when the activity expires, so contained objects generally do not need to worry about handling expired activities. """ assert not self._expired - assert isinstance(self._gamedata, dict) - return self._gamedata + assert isinstance(self._customdata, dict) + return self._customdata @property def expired(self) -> bool: @@ -574,9 +574,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): def add_player(self, sessionplayer: ba.SessionPlayer) -> None: """(internal)""" - assert sessionplayer.team is not None + assert sessionplayer.sessionteam is not None sessionplayer.resetinput() - sessionteam = sessionplayer.team + sessionteam = sessionplayer.sessionteam assert sessionplayer in sessionteam.players team = sessionteam.gameteam assert team is not None @@ -608,7 +608,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): player: Any = sessionplayer.gameplayer assert isinstance(player, self._playertype) - team: Any = sessionplayer.team.gameteam + team: Any = sessionplayer.sessionteam.gameteam assert isinstance(team, self._teamtype) assert player in team.players @@ -795,9 +795,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): print_exception(f'Error in Activity on_expire() for {self}.') try: - self._gamedata = None + self._customdata = None except Exception: - print_exception(f'Error clearing gamedata for {self}.') + print_exception(f'Error clearing customdata for {self}.') # Don't want to be holding any delay-delete refs at this point. self._prune_delay_deletes() diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index afca3247..cb03c75c 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -27,8 +27,8 @@ import _ba from ba._activity import Activity from ba._music import setmusic, MusicType # False positive due to our class_generics_filter custom pylint filter. -from ba._player import Player # pylint: disable=W0611 -from ba._team import Team # pylint: disable=W0611 +from ba import _player +from ba import _team if TYPE_CHECKING: from typing import Any, Dict, Optional @@ -36,6 +36,17 @@ if TYPE_CHECKING: from ba._lobby import JoinInfo +# Even though we don't need custom Player/Team types, define empty ones +# so we don't have ba.Player[Any] and ba.Team[Any] as our types which +# reduces type safety. +class Player(_player.Player['Team']): + """Our player type for this game.""" + + +class Team(_team.Team[Player]): + """Our team type for this game.""" + + class EndSessionActivity(Activity[Player, Team]): """Special ba.Activity to fade out and end the current ba.Session.""" @@ -158,7 +169,7 @@ class ScoreScreenActivity(Activity[Player, Team]): self._custom_continue_message: Optional[ba.Lstr] = None self._server_transitioning: Optional[bool] = None - def on_player_join(self, player: ba.Player) -> None: + def on_player_join(self, player: Player) -> None: from ba import _general super().on_player_join(player) time_till_assign = max( @@ -224,7 +235,7 @@ class ScoreScreenActivity(Activity[Player, Team]): # Otherwise end the activity normally. self.end() - def _safe_assign(self, player: ba.Player) -> None: + def _safe_assign(self, player: Player) -> None: # Just to be extra careful, don't assign if we're transitioning out. # (though theoretically that would be ok). diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 052a77d0..22456491 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -341,37 +341,35 @@ class CoopSession(Session): self.setactivity(_ba.new_activity(TransitionActivity)) else: - player_info: List[ba.PlayerInfo] + playerinfos: List[ba.PlayerInfo] # Generic team games. if isinstance(results, TeamGameResults): - player_info = results.get_player_info() - score = results.get_team_score(results.get_teams()[0]) + playerinfos = results.playerinfos + score = results.get_team_score(results.sessionteams[0]) fail_message = None - score_order = ('decreasing' if results.get_lower_is_better() - else 'increasing') - if results.get_score_type() in (ScoreType.SECONDS, - ScoreType.MILLISECONDS): - score_type = 'time' + score_order = ('decreasing' + if results.lower_is_better else 'increasing') + if results.scoretype in (ScoreType.SECONDS, + ScoreType.MILLISECONDS): + scoretype = 'time' # ScoreScreen wants hundredths of a second. if score is not None: - if results.get_score_type() is ScoreType.SECONDS: + if results.scoretype is ScoreType.SECONDS: score *= 100 - elif (results.get_score_type() is - ScoreType.MILLISECONDS): + elif results.scoretype is ScoreType.MILLISECONDS: score //= 10 else: raise RuntimeError('FIXME') else: - if results.get_score_type() is not ScoreType.POINTS: - print(f'Unknown ScoreType:' - f' "{results.get_score_type()}"') - score_type = 'points' + if results.scoretype is not ScoreType.POINTS: + print(f'Unknown ScoreType:' f' "{results.scoretype}"') + scoretype = 'points' # Old coop-game-specific results; should migrate away from these. else: - player_info = results.get('player_info') + playerinfos = results.get('playerinfos') score = results['score'] if 'score' in results else None fail_message = (results['fail_message'] if 'fail_message' in results else None) @@ -380,12 +378,12 @@ class CoopSession(Session): activity_score_type = (activity.get_score_type() if isinstance( activity, CoopGameActivity) else None) assert activity_score_type is not None - score_type = activity_score_type + scoretype = activity_score_type # Validate types. - if player_info is not None: - assert isinstance(player_info, list) - assert (isinstance(i, PlayerInfo) for i in player_info) + if playerinfos is not None: + assert isinstance(playerinfos, list) + assert (isinstance(i, PlayerInfo) for i in playerinfos) # Looks like we were in a round - check the outcome and # go from there. @@ -397,11 +395,11 @@ class CoopSession(Session): self.setactivity( _ba.new_activity( CoopScoreScreen, { - 'player_info': player_info, + 'playerinfos': playerinfos, 'score': score, 'fail_message': fail_message, 'score_order': score_order, - 'score_type': score_type, + 'score_type': scoretype, 'outcome': outcome, 'campaign': self.campaign, 'level': self.campaign_level_name diff --git a/assets/src/ba_data/python/ba/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py index 4cdef7de..c07e0451 100644 --- a/assets/src/ba_data/python/ba/_dualteamsession.py +++ b/assets/src/ba_data/python/ba/_dualteamsession.py @@ -52,18 +52,17 @@ class DualTeamSession(MultiTeamSession): TeamVictoryScoreScreenActivity) from bastd.activity.multiteamvictory import ( TeamSeriesVictoryScoreScreenActivity) - winners = results.get_winners() + winners = results.winnergroups # If everyone has the same score, call it a draw. if len(winners) < 2: self.setactivity(_ba.new_activity(DrawScoreScreenActivity)) else: winner = winners[0].teams[0] - winner.sessiondata['score'] += 1 + winner.customdata['score'] += 1 # If a team has won, show final victory screen. - if winner.sessiondata['score'] >= (self._series_length - - 1) / 2 + 1: + if winner.customdata['score'] >= (self._series_length - 1) / 2 + 1: self.setactivity( _ba.new_activity(TeamSeriesVictoryScoreScreenActivity, {'winner': winner})) diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index f7b1eeef..71ac1088 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -76,7 +76,7 @@ class FreeForAllSession(MultiTeamSession): TeamSeriesVictoryScoreScreenActivity) from bastd.activity.freeforallvictory import ( FreeForAllVictoryScoreScreenActivity) - winners = results.get_winners() + winners = results.winnergroups # If there's multiple players and everyone has the same score, # call it a draw. @@ -91,20 +91,20 @@ class FreeForAllSession(MultiTeamSession): for i, winner in enumerate(winners): for team in winner.teams: points = (point_awards[i] if i in point_awards else 0) - team.sessiondata['previous_score'] = ( - team.sessiondata['score']) - team.sessiondata['score'] += points + team.customdata['previous_score'] = ( + team.customdata['score']) + team.customdata['score'] += points series_winners = [ team for team in self.teams - if team.sessiondata['score'] >= self._ffa_series_length + if team.customdata['score'] >= self._ffa_series_length ] series_winners.sort(reverse=True, - key=lambda tm: (tm.sessiondata['score'])) + key=lambda tm: (tm.customdata['score'])) if (len(series_winners) == 1 or (len(series_winners) > 1 - and series_winners[0].sessiondata['score'] != - series_winners[1].sessiondata['score'])): + and series_winners[0].customdata['score'] != + series_winners[1].customdata['score'])): self.setactivity( _ba.new_activity(TeamSeriesVictoryScoreScreenActivity, {'winner': series_winners[0]})) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 6ed91a80..370bc7a5 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -284,7 +284,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # Holds some flattened info about the player set at the point # when on_begin() is called. - self.initial_player_info: Optional[List[ba.PlayerInfo]] = None + self.initialplayerinfos: Optional[List[ba.PlayerInfo]] = None # Go ahead and get our map loading. self._map_type = _map.get_map_class(self._calc_map_name(settings)) @@ -511,14 +511,14 @@ class GameActivity(Activity[PlayerType, TeamType]): _ba.timer(2.5, self._show_tip) # Store some basic info about players present at start time. - self.initial_player_info = [ + self.initialplayerinfos = [ PlayerInfo(name=p.getname(full=True), character=p.character) for p in self.players ] # Sort this by name so high score lists/etc will be consistent # regardless of player join order. - self.initial_player_info.sort(key=lambda x: x.name) + self.initialplayerinfos.sort(key=lambda x: x.name) # If this is a tournament, query info about it such as how much # time is left. @@ -890,9 +890,10 @@ class GameActivity(Activity[PlayerType, TeamType]): if player.actor and not self.has_ended(): from bastd.actor.respawnicon import RespawnIcon - player.gamedata['respawn_timer'] = _ba.Timer( + player.customdata['respawn_timer'] = _ba.Timer( respawn_time, WeakCall(self.spawn_player_if_exists, player)) - player.gamedata['respawn_icon'] = RespawnIcon(player, respawn_time) + player.customdata['respawn_icon'] = RespawnIcon( + player, respawn_time) def spawn_player_if_exists(self, player: PlayerType) -> None: """ diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index ff185d56..c7009ff4 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -26,8 +26,6 @@ import weakref from dataclasses import dataclass from typing import TYPE_CHECKING -from ba._team import Team - if TYPE_CHECKING: from weakref import ReferenceType from typing import Sequence, Tuple, Any, Optional, Dict, List, Union @@ -56,56 +54,54 @@ class TeamGameResults: self._game_set = False self._scores: Dict[int, Tuple[ReferenceType[ba.SessionTeam], Optional[int]]] = {} - self._teams: Optional[List[ReferenceType[ba.SessionTeam]]] = None - self._player_info: Optional[List[ba.PlayerInfo]] = None + self._sessionteams: Optional[List[ReferenceType[ + ba.SessionTeam]]] = None + self._playerinfos: Optional[List[ba.PlayerInfo]] = None self._lower_is_better: Optional[bool] = None self._score_label: Optional[str] = None self._none_is_winner: Optional[bool] = None - self._score_type: Optional[ba.ScoreType] = None + self._scoretype: Optional[ba.ScoreType] = None def set_game(self, game: ba.GameActivity) -> None: """Set the game instance these results are applying to.""" if self._game_set: raise RuntimeError('Game set twice for TeamGameResults.') self._game_set = True - self._teams = [weakref.ref(team) for team in game.teams] + self._sessionteams = [weakref.ref(team) for team in game.teams] score_info = game.get_score_info() - self._player_info = copy.deepcopy(game.initial_player_info) + self._playerinfos = copy.deepcopy(game.initialplayerinfos) self._lower_is_better = score_info.lower_is_better self._score_label = score_info.label self._none_is_winner = score_info.none_is_winner - self._score_type = score_info.scoretype + self._scoretype = score_info.scoretype - def set_team_score(self, team: Union[ba.SessionTeam, ba.Team], - score: Optional[int]) -> None: + def set_team_score(self, team: ba.Team, score: Optional[int]) -> None: """Set the score for a given ba.Team. This can be a number or None. (see the none_is_winner arg in the constructor) """ - if isinstance(team, Team): - team = team.sessionteam - self._scores[team.id] = (weakref.ref(team), score) + sessionteam = team.sessionteam + self._scores[sessionteam.id] = (weakref.ref(sessionteam), score) - def get_team_score(self, team: Union[ba.SessionTeam, - ba.Team]) -> Optional[int]: - """Return the score for a given team.""" - if isinstance(team, Team): - team = team.sessionteam + def get_team_score(self, + sessionteam: Union[ba.SessionTeam]) -> Optional[int]: + """Return the score for a given ba.SessionTeam.""" for score in list(self._scores.values()): - if score[0]() is team: + if score[0]() is sessionteam: return score[1] # If we have no score value, assume None. return None - def get_teams(self) -> List[ba.SessionTeam]: + @property + def sessionteams(self) -> List[ba.SessionTeam]: """Return all ba.SessionTeams in the results.""" if not self._game_set: raise RuntimeError("Can't get teams until game is set.") teams = [] - assert self._teams is not None - for team_ref in self._teams: + assert self._sessionteams is not None + for team_ref in self._sessionteams: team = team_ref() if team is not None: teams.append(team) @@ -130,55 +126,61 @@ class TeamGameResults: if score[0]() is team.sessionteam: if score[1] is None: return Lstr(value='-') - if self._score_type is ScoreType.SECONDS: + if self._scoretype is ScoreType.SECONDS: return timestring(score[1] * 1000, centi=False, timeformat=TimeFormat.MILLISECONDS) - if self._score_type is ScoreType.MILLISECONDS: + if self._scoretype is ScoreType.MILLISECONDS: return timestring(score[1], centi=True, timeformat=TimeFormat.MILLISECONDS) return Lstr(value=str(score[1])) return Lstr(value='-') - def get_player_info(self) -> List[ba.PlayerInfo]: + @property + def playerinfos(self) -> List[ba.PlayerInfo]: """Get info about the players represented by the results.""" if not self._game_set: raise RuntimeError("Can't get player-info until game is set.") - assert self._player_info is not None - return self._player_info + assert self._playerinfos is not None + return self._playerinfos - def get_score_type(self) -> ba.ScoreType: - """Get the type of score.""" + @property + def scoretype(self) -> ba.ScoreType: + """The type of score.""" if not self._game_set: raise RuntimeError("Can't get score-type until game is set.") - assert self._score_type is not None - return self._score_type + assert self._scoretype is not None + return self._scoretype - def get_score_name(self) -> str: - """Get the name associated with scores ('points', etc).""" + @property + def score_label(self) -> str: + """The label associated with scores ('points', etc).""" if not self._game_set: - raise RuntimeError("Can't get score-name until game is set.") + raise RuntimeError("Can't get score-label until game is set.") assert self._score_label is not None return self._score_label - def get_lower_is_better(self) -> bool: - """Return whether lower scores are better.""" + @property + def lower_is_better(self) -> bool: + """Whether lower scores are better.""" if not self._game_set: raise RuntimeError("Can't get lower-is-better until game is set.") assert self._lower_is_better is not None return self._lower_is_better - def get_winning_team(self) -> Optional[ba.SessionTeam]: - """Get the winning ba.Team if there is exactly one; None otherwise.""" + @property + def winning_team(self) -> Optional[ba.SessionTeam]: + """The winning ba.SessionTeam if there is exactly one, or else None.""" if not self._game_set: raise RuntimeError("Can't get winners until game is set.") - winners = self.get_winners() + winners = self.winnergroups if winners and len(winners[0].teams) == 1: return winners[0].teams[0] return None - def get_winners(self) -> List[WinnerGroup]: + @property + def winnergroups(self) -> List[WinnerGroup]: """Get an ordered list of winner groups.""" if not self._game_set: raise RuntimeError("Can't get winners until game is set.") @@ -200,17 +202,18 @@ class TeamGameResults: results.sort(reverse=not self._lower_is_better, key=lambda x: x[0]) # Also group the 'None' scores. - none_teams: List[ba.SessionTeam] = [] + none_sessionteams: List[ba.SessionTeam] = [] for score in self._scores.values(): scoreteam = score[0]() if scoreteam is not None and score[1] is None: - none_teams.append(scoreteam) + none_sessionteams.append(scoreteam) # Add the Nones to the list (either as winners or losers # depending on the rules). - if none_teams: - nones: List[Tuple[Optional[int], - List[ba.SessionTeam]]] = [(None, none_teams)] + if none_sessionteams: + nones: List[Tuple[Optional[int], List[ba.SessionTeam]]] = [ + (None, none_sessionteams) + ] if self._none_is_winner: results = nones + results else: diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 5ff0acd2..bb1f3bb5 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -25,6 +25,7 @@ import gc import types import weakref import random +import inspect from typing import TYPE_CHECKING, TypeVar from typing_extensions import Protocol @@ -332,7 +333,45 @@ def _verify_object_death(wref: ReferenceType) -> None: print(f'{Clr.YLW}Active References:{Clr.RST}') i = 1 for ref in refs: - # if isinstance(ref, types.FrameType): - # continue print(f'{Clr.YLW} reference {i}:{Clr.BLU} {ref}{Clr.RST}') i += 1 + + +def storagename(basename: str) -> str: + """Generate a (hopefully) unique name for storing things in public places. + + Category: General Utility Functions + + This consists of a leading underscore, the module path at the + call site with dots replaced by underscores, the class name, and + the provided suffix. When storing data in public places such as + 'customdata' dicts, this minimizes the chance of collisions if a + module or class is duplicated or renamed. + + # Example: generate a unique name for storage purposes: + class MyThingie: + + # This will give something like '_mymodule_submodule_mythingie_data'. + _STORENAME = ba.storagename('data') + + def __init__(self, activity): + # Store some data in the Activity we were passed + activity.customdata[self._STORENAME] = {} + """ + frame = inspect.currentframe() + if frame is None: + raise RuntimeError('Cannot get current stack frame.') + fback = frame.f_back + if fback is None: + raise RuntimeError('Cannot get parent stack frame.') + modulepath = fback.f_globals.get('__name__') + if modulepath is None: + raise RuntimeError('Cannot get parent stack module path.') + assert isinstance(modulepath, str) + qualname = fback.f_locals.get('__qualname__') + if qualname is not None: + assert isinstance(qualname, str) + fullpath = f'_{modulepath}_{qualname.lower()}_{basename}' + else: + fullpath = f'_{modulepath}_{basename}' + return fullpath.replace('.', '_') diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 38016cf7..91a17e5c 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -156,7 +156,7 @@ class MultiTeamSession(Session): return self._game_number def on_team_join(self, team: ba.SessionTeam) -> None: - team.sessiondata['previous_score'] = team.sessiondata['score'] = 0 + team.customdata['previous_score'] = team.customdata['score'] = 0 def get_max_players(self) -> int: """Return max number of ba.Players allowed to join the game at once.""" @@ -174,7 +174,8 @@ class MultiTeamSession(Session): from bastd.tutorial import TutorialActivity from bastd.activity.multiteamvictory import ( TeamSeriesVictoryScoreScreenActivity) - from ba import _activitytypes + from ba._activitytypes import (TransitionActivity, JoinActivity, + ScoreScreenActivity) # If we have a tutorial to show, that's the first thing we do no # matter what. @@ -186,22 +187,20 @@ class MultiTeamSession(Session): # to transition us into a round gracefully (otherwise we'd snap from # one terrain to another instantly). elif isinstance(activity, TutorialActivity): - self.setactivity( - _ba.new_activity(_activitytypes.TransitionActivity)) + self.setactivity(_ba.new_activity(TransitionActivity)) # If we're in a between-round activity or a restart-activity, hop # into a round. elif isinstance( activity, - (_activitytypes.JoinActivity, _activitytypes.TransitionActivity, - _activitytypes.ScoreScreenActivity)): + (JoinActivity, TransitionActivity, ScoreScreenActivity)): # If we're coming from a series-end activity, reset scores. if isinstance(activity, TeamSeriesVictoryScoreScreenActivity): self.stats.reset() self._game_number = 0 for team in self.teams: - team.sessiondata['score'] = 0 + team.customdata['score'] = 0 # Otherwise just set accum (per-game) scores. else: @@ -221,7 +220,7 @@ class MultiTeamSession(Session): # ..but only ones who have been placed on a team # (ie: no longer sitting in the lobby). try: - has_team = (player.team is not None) + has_team = (player.sessionteam is not None) except NotFoundError: has_team = False if has_team: @@ -263,7 +262,7 @@ class MultiTeamSession(Session): _ba.timer(delay, Call(_ba.playsound, _ba.getsound('boxingBell'))) if announce_winning_team: - winning_team = results.get_winning_team() + winning_team = results.winning_team if winning_team is not None: # Have all players celebrate. celebrate_msg = CelebrateMessage(duration=10.0) diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index c889d86a..b986d04c 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -23,7 +23,7 @@ from __future__ import annotations from dataclasses import dataclass -from typing import TYPE_CHECKING, TypeVar, Generic +from typing import TYPE_CHECKING, TypeVar, Generic, cast import _ba from ba._error import SessionPlayerNotFoundError, print_exception @@ -85,8 +85,7 @@ class Player(Generic[TeamType]): _nodeactor: Optional[ba.NodeActor] _expired: bool _postinited: bool - sessiondata: dict - _gamedata: dict + _customdata: dict # NOTE: avoiding having any __init__() here since it seems to not # get called by default if a dataclass inherits from us. @@ -118,10 +117,9 @@ class Player(Generic[TeamType]): self.character = sessionplayer.character self.color = sessionplayer.color self.highlight = sessionplayer.highlight - self._team = sessionplayer.team.gameteam # type: ignore + self._team = cast(TeamType, sessionplayer.sessionteam.gameteam) assert self._team is not None - self.sessiondata = sessionplayer.sessiondata - self._gamedata = {} + self._customdata = {} self._expired = False self._postinited = True node = _ba.newnode('player', attrs={'playerID': sessionplayer.id}) @@ -144,7 +142,7 @@ class Player(Generic[TeamType]): print_exception(f'Error killing actor on leave for {self}') self._nodeactor = None del self._team - del self._gamedata + del self._customdata def expire(self) -> None: """Called when the Player is expiring (when its Activity does so). @@ -163,7 +161,7 @@ class Player(Generic[TeamType]): self._nodeactor = None self.actor = None del self._team - del self._gamedata + del self._customdata def on_expire(self) -> None: """Can be overridden to handle player expiration. @@ -182,7 +180,7 @@ class Player(Generic[TeamType]): return self._team @property - def gamedata(self) -> dict: + def customdata(self) -> dict: """Arbitrary values associated with the player. Though it is encouraged that most player values be properly defined on the ba.Player subclass, it may be useful for player-agnostic @@ -193,7 +191,7 @@ class Player(Generic[TeamType]): """ assert self._postinited assert not self._expired - return self._gamedata + return self._customdata @property def sessionplayer(self) -> ba.SessionPlayer: diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 2de441ba..98b97728 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -259,7 +259,7 @@ class Session: else: # Ok, they've already entered the game. Remove them from # teams/activities/etc. - sessionteam = sessionplayer.team + sessionteam = sessionplayer.sessionteam assert sessionteam is not None _ba.screenmessage( @@ -317,7 +317,7 @@ class Session: else: print('Team no in Session teams in on_player_leave.') try: - sessionteam.reset_sessiondata() + sessionteam.leave() except Exception: print_exception(f'Error clearing sessiondata' f' for team {sessionteam} in session {self}.') diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 19db090d..cdc0271d 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -74,7 +74,7 @@ class PlayerRecord: self._multi_kill_timer: Optional[ba.Timer] = None self._multi_kill_count = 0 self._stats = weakref.ref(stats) - self._last_player: Optional[ba.SessionPlayer] = None + self._last_sessionplayer: Optional[ba.SessionPlayer] = None self._player: Optional[ba.SessionPlayer] = None self._team: Optional[ReferenceType[ba.SessionTeam]] = None self.streak = 0 @@ -110,7 +110,7 @@ class PlayerRecord: def get_icon(self) -> Dict[str, Any]: """Get the icon for this instance's player.""" - player = self._last_player + player = self._last_sessionplayer assert player is not None return player.get_icon() @@ -127,12 +127,12 @@ class PlayerRecord: return stats.getactivity() return None - def associate_with_player(self, player: ba.SessionPlayer) -> None: - """Associate this entry with a ba.Player.""" - self._team = weakref.ref(player.team) - self.character = player.character - self._last_player = player - self._player = player + def associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None: + """Associate this entry with a ba.SessionPlayer.""" + self._team = weakref.ref(sessionplayer.sessionteam) + self.character = sessionplayer.character + self._last_sessionplayer = sessionplayer + self._player = sessionplayer self.streak = 0 def _end_multi_kill(self) -> None: @@ -141,8 +141,8 @@ class PlayerRecord: def get_last_player(self) -> ba.SessionPlayer: """Return the last ba.Player we were associated with.""" - assert self._last_player is not None - return self._last_player + assert self._last_sessionplayer is not None + return self._last_sessionplayer def submit_kill(self, showpoints: bool = True) -> None: """Submit a kill for this player entry.""" @@ -307,15 +307,14 @@ class Stats: def register_player(self, player: ba.SessionPlayer) -> None: """Register a player with this score-set.""" + assert player.exists() # Invalid refs should never be passed to funcs. name = player.getname() - name_full = player.getname(full=True) - try: + if name in self._player_records: # If the player already exists, update his character and such as # it may have changed. self._player_records[name].associate_with_player(player) - except Exception: - # FIXME: Shouldn't use top level Exception catch for logic. - # Should only have this as a fallback and always log it. + else: + name_full = player.getname(full=True) self._player_records[name] = PlayerRecord(name, name_full, player, self) @@ -331,11 +330,6 @@ class Stats: records[record_id] = record return records - def player_got_hit(self, player: ba.SessionPlayer) -> None: - """Call this when a player got hit.""" - s_player = self._player_records[player.getname()] - s_player.streak = 0 - def player_scored(self, player: ba.Player, base_points: int = 1, diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index b60d294d..fa4be4d6 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -56,15 +56,10 @@ class SessionTeam: players The list of ba.SessionPlayers on the team. - gamedata - A dict for use by the current ba.Activity - for storing data associated with this team. - This gets cleared for each new ba.Activity. - - sessiondata + customdata A dict for use by the current ba.Session for storing data associated with this team. - Unlike gamedata, this persists for the duration + Unlike customdata, this persists for the duration of the session. """ @@ -72,8 +67,7 @@ class SessionTeam: name: Union[ba.Lstr, str] color: Tuple[float, ...] # FIXME: can't we make this fixed len? players: List[ba.SessionPlayer] - gamedata: Dict - sessiondata: Dict + customdata: dict id: int def __init__(self, @@ -90,12 +84,12 @@ class SessionTeam: self.name = name self.color = tuple(color) self.players = [] - self.sessiondata = {} + self.customdata = {} self.gameteam: Optional[Team] = None - def reset_sessiondata(self) -> None: + def leave(self) -> None: """(internal)""" - self.sessiondata = {} + self.customdata = {} PlayerType = TypeVar('PlayerType', bound='ba.Player') @@ -119,10 +113,7 @@ class Team(Generic[PlayerType]): _sessionteam: ReferenceType[SessionTeam] _expired: bool _postinited: bool - _gamedata: dict - - # TODO: kill these. - sessiondata: dict + _customdata: dict # NOTE: avoiding having any __init__() here since it seems to not # get called by default if a dataclass inherits from us. @@ -149,8 +140,7 @@ class Team(Generic[PlayerType]): self.id = sessionteam.id self.name = sessionteam.name self.color = sessionteam.color - self.sessiondata = sessionteam.sessiondata - self._gamedata = {} + self._customdata = {} self._expired = False self._postinited = True @@ -160,13 +150,12 @@ class Team(Generic[PlayerType]): self.id = team_id self.name = name self.color = color - self._gamedata = {} - self.sessiondata = {} + self._customdata = {} self._expired = False self._postinited = True @property - def gamedata(self) -> dict: + def customdata(self) -> dict: """Arbitrary values associated with the team. Though it is encouraged that most player values be properly defined on the ba.Team subclass, it may be useful for player-agnostic @@ -177,7 +166,7 @@ class Team(Generic[PlayerType]): """ assert self._postinited assert not self._expired - return self._gamedata + return self._customdata def leave(self) -> None: """Called when the Team leaves a running game. @@ -186,7 +175,7 @@ class Team(Generic[PlayerType]): """ assert self._postinited assert not self._expired - del self._gamedata + del self._customdata del self.players def expire(self) -> None: @@ -203,7 +192,7 @@ class Team(Generic[PlayerType]): except Exception: print_exception(f'Error in on_expire for {self}.') - del self._gamedata + del self._customdata del self.players def on_expire(self) -> None: diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index e09d8d4c..45d4b0b2 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -137,9 +137,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._tournament_time_remaining_text: Optional[Text] = None self._tournament_time_remaining_text_timer: Optional[ba.Timer] = None - self._player_info: List[ba.PlayerInfo] = settings['player_info'] - assert isinstance(self._player_info, list) - assert (isinstance(i, ba.PlayerInfo) for i in self._player_info) + self._playerinfos: List[ba.PlayerInfo] = settings['playerinfos'] + assert isinstance(self._playerinfos, list) + assert (isinstance(i, ba.PlayerInfo) for i in self._playerinfos) self._score: Optional[int] = settings['score'] assert isinstance(self._score, (int, type(None))) @@ -174,7 +174,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._game_name_str = self._campaign.name + ':' + self._level_name self._game_config_str = str(len( - self._player_info)) + 'p' + self._campaign.get_level( + self._playerinfos)) + 'p' + self._campaign.get_level( self._level_name).get_score_version_string().replace(' ', '_') # If game-center/etc scores are available we show our friends' @@ -580,12 +580,12 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): ba.timer(5.2, ba.Call(ba.playsound, self._dingsound)) offs_x = -195 - if len(self._player_info) > 1: + if len(self._playerinfos) > 1: pstr = ba.Lstr(value='- ${A} -', subs=[('${A}', ba.Lstr(resource='multiPlayerCountText', subs=[('${COUNT}', - str(len(self._player_info))) + str(len(self._playerinfos))) ]))]) else: pstr = ba.Lstr(value='- ${A} -', @@ -636,7 +636,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): ba.pushcall(ba.WeakCall(self._show_fail)) self._name_str = name_str = ', '.join( - [p.name for p in self._player_info]) + [p.name for p in self._playerinfos]) if self._show_friend_scores: self._friends_loading_status = Text( @@ -662,10 +662,10 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): our_high_scores_all = self._campaign.get_level( self._level_name).get_high_scores() try: - our_high_scores = our_high_scores_all[str(len(self._player_info)) + + our_high_scores = our_high_scores_all[str(len(self._playerinfos)) + ' Player'] except Exception: - our_high_scores = our_high_scores_all[str(len(self._player_info)) + + our_high_scores = our_high_scores_all[str(len(self._playerinfos)) + ' Player'] = [] if self._score is not None: @@ -674,7 +674,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): 'players': [{ 'name': p.name, 'character': p.character - } for p in self._player_info] + } for p in self._playerinfos] } ] our_high_scores.append(our_score) @@ -789,7 +789,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): v_offs_extra = 20 v_offs_names = 0 scale = 1.0 - p_count = len(self._player_info) + p_count = len(self._playerinfos) h_offs_extra -= 75 if p_count > 1: h_offs_extra -= 20 @@ -841,7 +841,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): position=(ts_h_offs + 35 + h_offs_extra, v_offs_extra + ts_height / 2 + -ts_height * (i + 1) / 10 + v_offs_names + v_offs + 11.0), - maxwidth=80.0 + 100.0 * len(self._player_info), + maxwidth=80.0 + 100.0 * len(self._playerinfos), v_align=Text.VAlign.CENTER, color=color1, flash=flash, @@ -1086,7 +1086,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): h_offs_extra = 0 v_offs_names = 0 scale = 1.0 - p_count = len(self._player_info) + p_count = len(self._playerinfos) if p_count > 1: h_offs_extra -= 40 if self._score_type != 'points': @@ -1146,7 +1146,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): position=(ts_h_offs + 35 + h_offs_extra, ts_height / 2 + -ts_height * (i + 1) / 10 + v_offs_names + v_offs + 11.0), - maxwidth=80.0 + 100.0 * len(self._player_info), + maxwidth=80.0 + 100.0 * len(self._playerinfos), v_align=Text.VAlign.CENTER, color=color1, flash=flash, diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index eb354366..5c7e28cd 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -103,7 +103,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): def _show_team_name(self, pos_v: float, team: ba.SessionTeam, kill_delay: float, shiftdelay: float) -> None: - del kill_delay # unused arg + del kill_delay # Unused arg. ZoomText(ba.Lstr(value='${A}:', subs=[('${A}', team.name)]), position=(100, pos_v), shiftposition=(-150, pos_v), @@ -115,9 +115,9 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): color=team.color, jitter=1.0).autoretain() - def _show_team_old_score(self, pos_v: float, team: ba.SessionTeam, + def _show_team_old_score(self, pos_v: float, sessionteam: ba.SessionTeam, shiftdelay: float) -> None: - ZoomText(str(team.sessiondata['score'] - 1), + ZoomText(str(sessionteam.customdata['score'] - 1), position=(150, pos_v), maxwidth=100, color=(0.6, 0.6, 0.7), @@ -129,11 +129,11 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): h_align='left', jitter=1.0).autoretain() - def _show_team_score(self, pos_v: float, team: ba.SessionTeam, + def _show_team_score(self, pos_v: float, sessionteam: ba.SessionTeam, scored: bool, kill_delay: float, shiftdelay: float) -> None: - del kill_delay # unused arg - ZoomText(str(team.sessiondata['score']), + del kill_delay # Unused arg. + ZoomText(str(sessionteam.customdata['score']), position=(150, pos_v), maxwidth=100, color=(1.0, 0.9, 0.5) if scored else (0.6, 0.6, 0.7), diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py index e0bcf462..9e0de4e8 100644 --- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py +++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py @@ -28,7 +28,7 @@ import ba from bastd.activity.multiteamscore import MultiTeamScoreScreenActivity if TYPE_CHECKING: - from typing import Any, Dict, Optional, Set + from typing import Any, Dict, Optional, Set, Tuple class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): @@ -60,13 +60,17 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): player_order_prev = list(self.players) player_order_prev.sort( reverse=True, - key=lambda p: - (p.team.sessiondata['previous_score'], p.getname(full=True))) + key=lambda p: ( + p.team.sessionteam.customdata['previous_score'], + p.getname(full=True), + )) player_order = list(self.players) player_order.sort(reverse=True, - key=lambda p: - (p.team.sessiondata['score'], p.team.sessiondata[ - 'score'], p.getname(full=True))) + key=lambda p: ( + p.team.sessionteam.customdata['score'], + p.team.sessionteam.customdata['score'], + p.getname(full=True), + )) v_offs = -74.0 + spacing * len(player_order_prev) * 0.5 delay1 = 1.3 + 0.1 @@ -202,8 +206,9 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): transtime2: ts_h_offs - (95.0 + slide_amt) * scale })) - s_txt = _scoretxt(str(player.team.sessiondata['previous_score']), - 80, 0, False, 0, 1.0) + s_txt = _scoretxt( + str(player.team.sessionteam.customdata['previous_score']), 80, + 0, False, 0, 1.0) ba.timer( tdelay + delay2, ba.WeakCall( @@ -219,8 +224,9 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): transtime2: ts_h_offs + (80.0 - slide_amt) * scale })) - score_change = (player.team.sessiondata['score'] - - player.team.sessiondata['previous_score']) + score_change = ( + player.team.sessionteam.customdata['score'] - + player.team.sessionteam.customdata['previous_score']) if score_change > 0: xval = 113 yval = 3.0 @@ -257,12 +263,11 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): tdelay + delay1, ba.Call(_safesetattr, s_txt.node, 'color', (1, 1, 1, 1))) for j in range(score_change): - ba.timer( - (tdelay + delay1 + 0.15 * j), - ba.Call( - _safesetattr, s_txt.node, 'text', - str(player.team.sessiondata['previous_score'] + j + - 1))) + ba.timer((tdelay + delay1 + 0.15 * j), + ba.Call( + _safesetattr, s_txt.node, 'text', + str(player.team.sessionteam. + customdata['previous_score'] + j + 1))) tfin = tdelay + delay1 + 0.15 * j if tfin not in sound_times: sound_times.add(tfin) diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index 75bf8e64..77b2a5f9 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -121,8 +121,8 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): # Results is already sorted; just convert it into a list of # score-set-entries. - for winner in results.get_winners(): - for team in winner.teams: + for winnergroup in results.winnergroups: + for team in winnergroup.teams: if len(team.players) == 1: player_entry = _get_player_score_set_entry( team.players[0]) @@ -172,8 +172,8 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): _txt(180, 4, ba.Lstr(resource='killsText')) _txt(280, 4, ba.Lstr(resource='deathsText'), maxwidth=100) - score_name = 'Score' if results is None else results.get_score_name() - translated = ba.Lstr(translate=('scoreNames', score_name)) + score_label = 'Score' if results is None else results.score_label + translated = ba.Lstr(translate=('scoreNames', score_label)) _txt(390, 0, translated) diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 5742bedb..39f37f8c 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -79,7 +79,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): for _pkey, prec in self.stats.get_records().items(): if prec.player.in_game: player_entries.append( - (prec.player.team.sessiondata['score'], + (prec.player.sessionteam.customdata['score'], prec.getname(full=True), prec)) player_entries.sort(reverse=True, key=lambda x: x[0]) else: @@ -145,8 +145,8 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): win_score = (session.get_series_length() - 1) // 2 + 1 lose_score = 0 for team in self.teams: - if team.sessiondata['score'] != win_score: - lose_score = team.sessiondata['score'] + if team.sessionteam.customdata['score'] != win_score: + lose_score = team.sessionteam.customdata['score'] if not self._is_ffa: Text(ba.Lstr(resource='gamesToText', @@ -309,7 +309,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): for _score, name, prec in player_entries: tdelay -= 4 * t_incr v_offs -= 40 - Text(str(prec.team.sessiondata['score']) + Text(str(prec.team.customdata['score']) if self._is_ffa else str(prec.score), color=(0.5, 0.5, 0.5, 1.0), position=(ts_h_offs + 230, ts_height / 2 + v_offs), diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py index 9682bb98..6a7deb5e 100644 --- a/assets/src/ba_data/python/bastd/actor/respawnicon.py +++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py @@ -39,6 +39,9 @@ class RespawnIcon: This is used to indicate that a ba.Player is waiting to respawn. """ + _MASKTEXSTORENAME = ba.storagename('masktex') + _ICONSSTORENAME = ba.storagename('icons') + def __init__(self, player: ba.Player, respawn_time: float): """Instantiate with a ba.Player and respawn_time (in seconds).""" self._visible = True @@ -46,10 +49,10 @@ class RespawnIcon: on_right, offs_extra, respawn_icons = self._get_context(player) # Cache our mask tex on the team for easy access. - mask_tex = player.team.gamedata.get('_spaz_respawn_icons_mask_tex') + mask_tex = player.team.customdata.get(self._MASKTEXSTORENAME) if mask_tex is None: mask_tex = ba.gettexture('characterIconMask') - player.team.gamedata['_spaz_respawn_icons_mask_tex'] = mask_tex + player.team.customdata[self._MASKTEXSTORENAME] = mask_tex assert isinstance(mask_tex, ba.Texture) # Now find the first unused slot and use that. @@ -139,9 +142,9 @@ class RespawnIcon: on_right = player.team.id % 2 == 1 # Store a list of icons in the team. - icons = player.team.gamedata.get('_spaz_respawn_icons') + icons = player.team.customdata.get(self._ICONSSTORENAME) if icons is None: - player.team.gamedata['_spaz_respawn_icons'] = icons = {} + player.team.customdata[self._ICONSSTORENAME] = icons = {} assert isinstance(icons, dict) offs_extra = -20 @@ -149,9 +152,9 @@ class RespawnIcon: on_right = False # Store a list of icons in the activity. - icons = activity.gamedata.get('_spaz_respawn_icons') + icons = activity.customdata.get(self._ICONSSTORENAME) if icons is None: - activity.gamedata['_spaz_respawn_icons'] = icons = {} + activity.customdata[self._ICONSSTORENAME] = icons = {} assert isinstance(icons, dict) if isinstance(activity.session, ba.FreeForAllSession): diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py index 16431102..448cd89a 100644 --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py @@ -343,6 +343,8 @@ class Scoreboard: category: Gameplay Classes """ + _STORENAME = ba.storagename('entry') + def __init__(self, label: ba.Lstr = None, score_split: float = 0.7): """Instantiate a scoreboard. @@ -382,8 +384,8 @@ class Scoreboard: # Create a proxy in the team which will kill # our entry when it dies (for convenience) - assert '_scoreboard_entry' not in team.gamedata - team.gamedata['_scoreboard_entry'] = _EntryProxy(self, team) + assert self._STORENAME not in team.customdata + team.customdata[self._STORENAME] = _EntryProxy(self, team) # Now set the entry. self._entries[team.id].set_value(score=score, diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 744484d9..8ae90f0c 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -61,23 +61,25 @@ class ConquestFlag(Flag): class Player(ba.Player['Team']): """Our player type for this game.""" + # FIXME: We shouldn't be using customdata here + # (but need to update respawn funcs accordingly first). @property def respawn_timer(self) -> Optional[ba.Timer]: """Type safe access to standard respawn timer.""" - return self.gamedata.get('respawn_timer', None) + return self.customdata.get('respawn_timer', None) @respawn_timer.setter def respawn_timer(self, value: Optional[ba.Timer]) -> None: - self.gamedata['respawn_timer'] = value + self.customdata['respawn_timer'] = value @property def respawn_icon(self) -> Optional[RespawnIcon]: """Type safe access to standard respawn icon.""" - return self.gamedata.get('respawn_icon', None) + return self.customdata.get('respawn_icon', None) @respawn_icon.setter def respawn_icon(self, value: Optional[RespawnIcon]) -> None: - self.gamedata['respawn_icon'] = value + self.customdata['respawn_icon'] = value class Team(ba.Team[Player]): diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index c29301c4..bef86f60 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -203,8 +203,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): # Respawn them shortly. player = msg.getplayer(Player) - assert self.initial_player_info is not None - respawn_time = 2.0 + len(self.initial_player_info) * 1.0 + assert self.initialplayerinfos is not None + respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 player.respawn_timer = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) player.respawn_icon = RespawnIcon(player, respawn_time) diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 111ad9e3..e8c03711 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -441,7 +441,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): if ba.app.kiosk_mode: controlsguide.ControlsGuide(delay=3.0, lifespan=10.0, bright=True).autoretain() - assert self.initial_player_info is not None + assert self.initialplayerinfos is not None abot: Type[SpazBot] bbot: Type[SpazBot] cbot: Type[SpazBot] @@ -450,36 +450,36 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): self._have_tnt = False abot = (BrawlerBotLite if self._preset == 'rookie_easy' else BrawlerBot) - self._bot_types_initial = [abot] * len(self.initial_player_info) + self._bot_types_initial = [abot] * len(self.initialplayerinfos) bbot = (BomberBotLite if self._preset == 'rookie_easy' else BomberBot) self._bot_types_7 = ( - [bbot] * (1 if len(self.initial_player_info) < 3 else 2)) + [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2)) cbot = (BomberBot if self._preset == 'rookie_easy' else TriggerBot) self._bot_types_14 = ( - [cbot] * (1 if len(self.initial_player_info) < 3 else 2)) + [cbot] * (1 if len(self.initialplayerinfos) < 3 else 2)) elif self._preset == 'tournament': self._exclude_powerups = [] self._have_tnt = True self._bot_types_initial = ( - [BrawlerBot] * (1 if len(self.initial_player_info) < 2 else 2)) + [BrawlerBot] * (1 if len(self.initialplayerinfos) < 2 else 2)) self._bot_types_7 = ( - [TriggerBot] * (1 if len(self.initial_player_info) < 3 else 2)) + [TriggerBot] * (1 if len(self.initialplayerinfos) < 3 else 2)) self._bot_types_14 = ( - [ChargerBot] * (1 if len(self.initial_player_info) < 4 else 2)) + [ChargerBot] * (1 if len(self.initialplayerinfos) < 4 else 2)) elif self._preset in ['pro', 'pro_easy', 'tournament_pro']: self._exclude_powerups = ['curse'] self._have_tnt = True self._bot_types_initial = [ChargerBot] * len( - self.initial_player_info) + self.initialplayerinfos) abot = (BrawlerBot if self._preset == 'pro' else BrawlerBotLite) typed_bot_list: List[Type[SpazBot]] = [] self._bot_types_7 = ( typed_bot_list + [abot] + [BomberBot] * - (1 if len(self.initial_player_info) < 3 else 2)) + (1 if len(self.initialplayerinfos) < 3 else 2)) bbot = (TriggerBotPro if self._preset == 'pro' else TriggerBot) self._bot_types_14 = ( - [bbot] * (1 if len(self.initial_player_info) < 3 else 2)) + [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2)) elif self._preset in ['uber', 'uber_easy']: self._exclude_powerups = [] self._have_tnt = True @@ -487,12 +487,11 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): bbot = (TriggerBotPro if self._preset == 'uber' else TriggerBot) typed_bot_list_2: List[Type[SpazBot]] = [] self._bot_types_initial = (typed_bot_list_2 + [StickyBot] + - [abot] * len(self.initial_player_info)) + [abot] * len(self.initialplayerinfos)) self._bot_types_7 = ( - [bbot] * (1 if len(self.initial_player_info) < 3 else 2)) + [bbot] * (1 if len(self.initialplayerinfos) < 3 else 2)) self._bot_types_14 = ( - [ExplodeyBot] * - (1 if len(self.initial_player_info) < 3 else 2)) + [ExplodeyBot] * (1 if len(self.initialplayerinfos) < 3 else 2)) else: raise Exception() @@ -794,7 +793,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): 'outcome': outcome, 'score': scoreval, 'score_order': 'decreasing', - 'player_info': self.initial_player_info + 'playerinfos': self.initialplayerinfos }) def handlemessage(self, msg: Any) -> Any: @@ -805,8 +804,8 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): # Respawn them shortly. player = msg.getplayer(Player) - assert self.initial_player_info is not None - respawn_time = 2.0 + len(self.initial_player_info) * 1.0 + assert self.initialplayerinfos is not None + respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 player.respawn_timer = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) player.respawn_icon = RespawnIcon(player, respawn_time) diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index aa940744..56c04457 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -154,7 +154,6 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): ba.timer(1.0, self._tick, repeat=True) self._flag_state = FlagState.NEW Flag.project_stand(self._flag_pos) - self._flag = Flag(position=self._flag_pos, touchable=False, color=(1, 1, 1)) diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 42e73e51..72e15581 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -113,12 +113,12 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): ChargerBot, pos=(-5, 3, -2), spawn_time=3.0)) # Add some extras for multiplayer or pro mode. - assert self.initial_player_info is not None - if len(self.initial_player_info) > 2 or is_pro: + assert self.initialplayerinfos is not None + if len(self.initialplayerinfos) > 2 or is_pro: ba.timer( 5.0, lambda: self._bots.spawn_bot( ChargerBot, pos=(0, 3, -5), spawn_time=3.0)) - if len(self.initial_player_info) > 3 or is_pro: + if len(self.initialplayerinfos) > 3 or is_pro: ba.timer( 6.0, lambda: self._bots.spawn_bot( ChargerBot, pos=(0, 3, 1), spawn_time=3.0)) diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index e08d0d78..430a7251 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -757,7 +757,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): 'outcome': outcome, 'score': score, 'fail_message': fail_message, - 'player_info': self.initial_player_info + 'playerinfos': self.initialplayerinfos }, delay=delay) @@ -844,10 +844,10 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): for player in self.players: try: if player.is_alive(): - assert self.initial_player_info is not None + assert self.initialplayerinfos is not None self.stats.player_scored( player, - int(100 / len(self.initial_player_info)), + int(100 / len(self.initialplayerinfos)), scale=1.4, color=(0.6, 0.6, 1.0, 1.0), title=ba.Lstr(resource='completionBonusText'), diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index c303f557..d4b1b6cb 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -563,7 +563,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): 'outcome': outcome, 'score': score, 'fail_message': fail_message, - 'player_info': self.initial_player_info + 'playerinfos': self.initialplayerinfos }) def _on_got_scores_to_beat(self, scores: List[Dict[str, Any]]) -> None: @@ -1118,8 +1118,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): # Respawn them shortly. player = msg.getplayer(Player) - assert self.initial_player_info is not None - respawn_time = 2.0 + len(self.initial_player_info) * 1.0 + assert self.initialplayerinfos is not None + respawn_time = 2.0 + len(self.initialplayerinfos) * 1.0 player.respawn_timer = ba.Timer( respawn_time, ba.Call(self.spawn_player_if_exists, player)) player.respawn_icon = RespawnIcon(player, respawn_time) diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 20c4b626..77c74e81 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -196,7 +196,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): results={ 'outcome': outcome, 'score': self._score, - 'player_info': self.initial_player_info + 'playerinfos': self.initialplayerinfos }) def _update_bots(self) -> None: diff --git a/docs/ba_module.md b/docs/ba_module.md index 34fb6596..af2783a2 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-01 for Ballistica version 1.5.0 build 20039

    +

    last updated on 2020-06-02 for Ballistica version 1.5.0 build 20041

    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!


    @@ -92,6 +92,7 @@
  • ba.screenmessage()
  • ba.set_analytics_screen()
  • ba.setlanguage()
  • +
  • ba.storagename()
  • ba.time()
  • ba.timer()
  • ba.timestring()
  • @@ -343,8 +344,16 @@ actually award achievements.

    can overlap during transitions.

    Attributes:

    -
    expired, gamedata, globalsnode, players, playertype, session, settings_raw, stats, teams, teamtype
    +
    customdata, expired, globalsnode, players, playertype, session, settings_raw, stats, teams, teamtype
    +

    customdata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    + +

    expired

    bool

    Whether the activity is expired.

    @@ -353,14 +362,6 @@ actually award achievements.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    -
    -

    gamedata

    -

    dict

    -

    Entities needing to store simple data with an activity can put it - here. This dict will be deleted when the activity expires, so contained - objects generally do not need to worry about handling expired - activities.

    -

    globalsnode

    ba.Node

    @@ -1552,8 +1553,16 @@ start_long_action(callback_when_done=ba.ContextC

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, gamedata, globalsnode, map, playertype, session, stats, teamtype
    +
    customdata, expired, globalsnode, map, playertype, session, stats, teamtype
    +

    customdata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    + +

    expired

    bool

    Whether the activity is expired.

    @@ -1562,14 +1571,6 @@ start_long_action(callback_when_done=ba.ContextC At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    -
    -

    gamedata

    -

    dict

    -

    Entities needing to store simple data with an activity can put it - here. This dict will be deleted when the activity expires, so contained - objects generally do not need to worry about handling expired - activities.

    -

    globalsnode

    ba.Node

    @@ -2145,8 +2146,16 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, gamedata, globalsnode, map, playertype, session, stats, teamtype
    +
    customdata, expired, globalsnode, map, playertype, session, stats, teamtype
    +

    customdata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    + +

    expired

    bool

    Whether the activity is expired.

    @@ -2155,14 +2164,6 @@ its time with lingering corpses, sound effects, etc.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    -
    -

    gamedata

    -

    dict

    -

    Entities needing to store simple data with an activity can put it - here. This dict will be deleted when the activity expires, so contained - objects generally do not need to worry about handling expired - activities.

    -

    globalsnode

    ba.Node

    @@ -3871,14 +3872,14 @@ even if myactor is set to None.

    own custom ba.Player types.

    Attributes:

    -
    actor, gamedata, node, position, sessionplayer, team
    +
    actor, customdata, node, position, sessionplayer, team

    actor

    Optional[ba.Actor]

    The ba.Actor associated with the player.

    -

    gamedata

    +

    customdata

    dict

    Arbitrary values associated with the player. Though it is encouraged that most player values be properly defined @@ -4111,9 +4112,9 @@ the type-checker properly identifies the returned value as one.

    associate_with_player()

    -

    associate_with_player(self, player: ba.SessionPlayer) -> None

    +

    associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None

    -

    Associate this entry with a ba.Player.

    +

    Associate this entry with a ba.SessionPlayer.

    cancel_multi_kill_timer()

    @@ -4556,7 +4557,7 @@ that a SessionPlayer is still present if retaining references to one for any length of time.

    Attributes:

    -
    character, color, gameplayer, highlight, id, in_game, inputdevice, sessiondata, team
    +
    character, color, gameplayer, highlight, id, in_game, inputdevice, sessionteam

    character

    str

    @@ -4602,14 +4603,7 @@ any lobby character/team selection.

    The input device associated with the player.

    -

    sessiondata

    -

    Dict

    -

    A dict for use by the current ba.Session for -storing data associated with this player. -This persists for the duration of the session.

    - -
    -

    team

    +

    sessionteam

    ba.SessionTeam

    The ba.SessionTeam this Player is on. If the SessionPlayer is still in its lobby selecting a team/etc. then a @@ -4708,18 +4702,19 @@ other players.

    each SessionTeam consists of just one SessionPlayer.

    Attributes:

    -
    color, gamedata, id, name, players, sessiondata
    +
    color, customdata, id, name, players

    color

    Tuple[float, ...]

    The team's color.

    -

    gamedata

    -

    Dict

    -

    A dict for use by the current ba.Activity -for storing data associated with this team. -This gets cleared for each new ba.Activity.

    +

    customdata

    +

    dict

    +

    A dict for use by the current ba.Session for +storing data associated with this team. +Unlike customdata, this persists for the duration +of the session.

    id

    @@ -4736,14 +4731,6 @@ This gets cleared for each new ba.Activity.

    List[ba.SessionPlayer]

    The list of ba.SessionPlayers on the team.

    -
    -

    sessiondata

    -

    Dict

    -

    A dict for use by the current ba.Session for -storing data associated with this team. -Unlike gamedata, this persists for the duration -of the session.

    -

    Methods:

    @@ -4952,7 +4939,7 @@ of the session.

    Methods:

    -
    <constructor>, get_records(), getactivity(), player_got_hit(), player_scored(), player_was_killed(), register_player(), reset(), reset_accum(), setactivity()
    +
    <constructor>, get_records(), getactivity(), player_scored(), player_was_killed(), register_player(), reset(), reset_accum(), setactivity()

    <constructor>

    ba.Stats()

    @@ -4971,12 +4958,6 @@ of the session.

    May return None.

    -
    -

    player_got_hit()

    -

    player_got_hit(self, player: ba.SessionPlayer) -> None

    - -

    Call this when a player got hit.

    -

    player_scored()

    player_scored(self, player: ba.Player, base_points: int = 1, target: Sequence[float] = None, kill: bool = False, victim_player: ba.Player = None, scale: float = 1.0, color: Sequence[float] = None, title: Union[str, ba.Lstr] = None, screenmessage: bool = True, display: bool = True, importance: int = 1, showpoints: bool = True, big_message: bool = False) -> int

    @@ -5029,9 +5010,9 @@ of the session.

    Attributes:

    -
    gamedata, sessionteam
    +
    customdata, sessionteam
    -

    gamedata

    +

    customdata

    dict

    Arbitrary values associated with the team. Though it is encouraged that most player values be properly defined @@ -5080,8 +5061,16 @@ of the session.

    Attributes Inherited:

    players, settings_raw, teams

    Attributes Defined Here:

    -
    expired, gamedata, globalsnode, map, playertype, session, stats, teamtype
    +
    customdata, expired, globalsnode, map, playertype, session, stats, teamtype
    +

    customdata

    +

    dict

    +

    Entities needing to store simple data with an activity can put it + here. This dict will be deleted when the activity expires, so contained + objects generally do not need to worry about handling expired + activities.

    + +

    expired

    bool

    Whether the activity is expired.

    @@ -5090,14 +5079,6 @@ of the session.

    At this point no new nodes, timers, etc should be made, run, etc, and the activity should be considered a 'zombie'.

    -
    -

    gamedata

    -

    dict

    -

    Entities needing to store simple data with an activity can put it - here. This dict will be deleted when the activity expires, so contained - objects generally do not need to worry about handling expired - activities.

    -

    globalsnode

    ba.Node

    @@ -5208,43 +5189,58 @@ Results for a completed ba.TeamGameActivity

    Upon completion, a game should fill one of these out and pass it to its ba.Activity.end() call.

    +

    Attributes:

    +
    lower_is_better, playerinfos, score_label, scoretype, sessionteams, winnergroups, winning_team
    +
    +

    lower_is_better

    +

    bool

    +

    Whether lower scores are better.

    + +
    +

    playerinfos

    +

    List[ba.PlayerInfo]

    +

    Get info about the players represented by the results.

    + +
    +

    score_label

    +

    str

    +

    The label associated with scores ('points', etc).

    + +
    +

    scoretype

    +

    ba.ScoreType

    +

    The type of score.

    + +
    +

    sessionteams

    +

    List[ba.SessionTeam]

    +

    Return all ba.SessionTeams in the results.

    + +
    +

    winnergroups

    +

    List[WinnerGroup]

    +

    Get an ordered list of winner groups.

    + +
    +

    winning_team

    +

    Optional[ba.SessionTeam]

    +

    The winning ba.SessionTeam if there is exactly one, or else None.

    + +
    +

    Methods:

    -
    <constructor>, get_lower_is_better(), get_player_info(), get_score_name(), get_score_type(), get_team_score(), get_team_score_str(), get_teams(), get_winners(), get_winning_team(), has_score_for_team(), set_game(), set_team_score()
    +
    <constructor>, get_team_score(), get_team_score_str(), has_score_for_team(), set_game(), set_team_score()

    <constructor>

    ba.TeamGameResults()

    Instantiate a results instance.

    -
    -

    get_lower_is_better()

    -

    get_lower_is_better(self) -> bool

    - -

    Return whether lower scores are better.

    - -
    -

    get_player_info()

    -

    get_player_info(self) -> List[ba.PlayerInfo]

    - -

    Get info about the players represented by the results.

    - -
    -

    get_score_name()

    -

    get_score_name(self) -> str

    - -

    Get the name associated with scores ('points', etc).

    - -
    -

    get_score_type()

    -

    get_score_type(self) -> ba.ScoreType

    - -

    Get the type of score.

    -

    get_team_score()

    -

    get_team_score(self, team: Union[ba.SessionTeam, ba.Team]) -> Optional[int]

    +

    get_team_score(self, sessionteam: Union[ba.SessionTeam]) -> Optional[int]

    -

    Return the score for a given team.

    +

    Return the score for a given ba.SessionTeam.

    get_team_score_str()

    @@ -5254,24 +5250,6 @@ Results for a completed ba.TeamGameActivity

    (properly formatted for the score type.)

    -
    -

    get_teams()

    -

    get_teams(self) -> List[ba.SessionTeam]

    - -

    Return all ba.SessionTeams in the results.

    - -
    -

    get_winners()

    -

    get_winners(self) -> List[WinnerGroup]

    - -

    Get an ordered list of winner groups.

    - -
    -

    get_winning_team()

    -

    get_winning_team(self) -> Optional[ba.SessionTeam]

    - -

    Get the winning ba.Team if there is exactly one; None otherwise.

    -

    has_score_for_team()

    has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool

    @@ -5286,7 +5264,7 @@ Results for a completed ba.TeamGameActivity

    set_team_score()

    -

    set_team_score(self, team: Union[ba.SessionTeam, ba.Team], score: Optional[int]) -> None

    +

    set_team_score(self, team: ba.Team, score: Optional[int]) -> None

    Set the score for a given ba.Team.

    @@ -6422,6 +6400,30 @@ playing, the playing track will not be restarted.

    Category: Gameplay Functions

    +
    +

    ba.storagename()

    +

    storagename(basename: str) -> str

    + +

    Generate a (hopefully) unique name for storing things in public places.

    + +

    Category: General Utility Functions

    + +

    This consists of a leading underscore, the module path at the +call site with dots replaced by underscores, the class name, and +the provided suffix. When storing data in public places such as +'customdata' dicts, this minimizes the chance of collisions if a +module or class is duplicated or renamed.

    + +
    # Example: generate a unique name for storage purposes:
    +class MyThingie:
    + +
        # This will give something like '_mymodule_submodule_mythingie_data'.
    +    _STORENAME = ba.storagename('data')
    + +

    def __init__(self, activity): + # Store some data in the Activity we were passed + activity.customdata[self._STORENAME] = {}

    +

    ba.textwidget()

    textwidget(edit: Widget = None, parent: Widget = None, From cd239ba3697798cf98ad19de80526cdaf056c9f9 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 13:20:55 -0700 Subject: [PATCH 065/417] Fixing asset builds --- .efrocachemap | 12 +- assets/src/ba_data/python/ba/_hooks.py | 10 +- tools/update_assets_makefile | 372 +++++++++++++++++++++++++ tools/update_project | 10 +- 4 files changed, 388 insertions(+), 16 deletions(-) create mode 100755 tools/update_assets_makefile diff --git a/.efrocachemap b/.efrocachemap index 6ff19b51..a3cd6b95 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4136,12 +4136,12 @@ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/ad/7e371dfb7ed7b10d46f0bf9497d8", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/92/28/faa6501d779b381dec7fb9ac19c5", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/57/97d03c6230cfc4d9f0687249f408", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/e1/a3a86c40804f1e724c59ee04f1a2", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/ec/9a476535716a8798813506f502a5", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ae/78/7a6522e860506fe1046808ce7b0b", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/08/71/09be3ad2f8cf99f885549a7296a0", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/67/ec5ab3ace8d2e740e85f23ebfbb0", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/49/3c1d3c8a995df400e46df3470b02", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/43/d4/48ec85af308fd027d7dd06eaa650", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cc/1b/303089d3c1f3b7620c632ee864c3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f2/55/890f1b498ccf5988dee573d5f3ca", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b9/b1/d96d693c3ad52cedd4f517fd9d94" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7c/6f/c04c002f3a92497f52ff56f62bd3", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/c7/91f468ff6714872fe4329a11b27d", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/85/ef/23050d0205b3449a8e4c74c35e62", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ef/a1/78572099ac9ef2d0734fb14ed164" } \ No newline at end of file diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index c12b3c25..a8718b6f 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -21,11 +21,11 @@ """Snippets of code for use by the internal C++ layer. History: originally I would dynamically compile/eval bits of Python text -from within C++ code, but the major downside there was that I would -never catch code breakage until the code was next run. By defining all -snippets I use here and then capturing references to them all at launch -I can verify everything I'm looking for exists and pylint can do -its magic on this file. +from within C++ code, but the major downside there was that none of that was +type-checked so if names or arguments changed I would never catch code breakage +until the code was next run. By defining all snippets I use here and then +capturing references to them all at launch I can immediately verify everything +I'm looking for exists and pylint/mypy can do their magic on this file. """ # (most of these are self-explanatory) # pylint: disable=missing-function-docstring diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile new file mode 100755 index 00000000..c53c998c --- /dev/null +++ b/tools/update_assets_makefile @@ -0,0 +1,372 @@ +#!/usr/bin/env python3.7 +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Updates assets/Makefile based on source assets present.""" + +from __future__ import annotations + +import json +import os +import sys +from typing import TYPE_CHECKING + +from efro.terminal import Clr + +if TYPE_CHECKING: + from typing import List, Set + +PYC_SUFFIX = '.cpython-37.opt-1.pyc' + + +def _get_targets(varname: str, + inext: str, + outext: str, + all_targets: Set, + limit_to_prefix: str = None) -> str: + """Generic function to map source extension to dst files.""" + + src = 'assets/src' + dst = 'assets/build' + targets = [] + + # Create outext targets for all inext files we find. + for root, _dname, fnames in os.walk(src): + if (limit_to_prefix is not None + and not root.startswith(os.path.join(src, limit_to_prefix))): + continue + + # Write the target to make sense from within assets/ + assert root.startswith(src) + dstrootvar = 'build' + root[len(src):] + dstfin = dst + root[len(src):] + for fname in fnames: + outname = fname[:-len(inext)] + outext + if fname.endswith(inext): + all_targets.add(os.path.join(dstfin, outname)) + targets.append(os.path.join(dstrootvar, outname)) + + return '\n' + varname + ' = \\\n ' + ' \\\n '.join(targets) + + +def _get_py_targets(src: str, dst: str, py_targets: List[str], + pyc_targets: List[str], all_targets: Set[str], + subset: str) -> None: + # pylint: disable=too-many-branches + + # Create py and pyc targets for all scripts in src. + for root, _dname, fnames in os.walk(src): + + # Special case: ignore temp py files in data src. + if root == 'assets/src/ba_data/data/maps': + continue + assert root.startswith(src) + dstrootvar = dst[len('assets') + 1:] + root[len(src):] + dstfin = dst + root[len(src):] + for fname in fnames: + + # Ignore flycheck temp files as well as our _ba dummy module. + if (not fname.endswith('.py') or fname.startswith('flycheck_') + or fname.startswith('.#') or fname == '_ba.py'): + continue + + if root.startswith('assets/src/ba_data/python-site-packages'): + in_subset = 'private-common' + elif (root.startswith('assets/src/ba_data') + or root.startswith('assets/src/server')): + in_subset = 'public' + elif (root.startswith('tools/efro') + and not root.startswith('tools/efrotools')): + # We want to pull just 'efro' out of tools; not efrotools. + in_subset = 'public_tools' + elif root.startswith('tools/bacommon'): + in_subset = 'public_tools' + elif root.startswith('assets/src/windows/x64'): + in_subset = 'private-windows-x64' + elif root.startswith('assets/src/windows/Win32'): + in_subset = 'private-windows-Win32' + elif root.startswith('assets/src/pylib-apple'): + in_subset = 'private-apple' + elif root.startswith('assets/src/pylib-android'): + in_subset = 'private-android' + else: + in_subset = 'private-common' + + if subset == 'all': + pass + elif subset != in_subset: + continue + + # gamedata pass includes only data; otherwise do all else + + # .py: + all_targets.add(os.path.join(dstfin, fname)) + py_targets.append(os.path.join(dstrootvar, fname)) + + # and .pyc: + fname_pyc = fname[:-3] + PYC_SUFFIX + all_targets.add(os.path.join(dstfin, '__pycache__', fname_pyc)) + pyc_targets.append( + os.path.join(dstrootvar, '__pycache__', fname_pyc)) + + +def _get_py_targets_subset(all_targets: Set[str], subset: str, + suffix: str) -> str: + if subset == 'public_tools': + src = 'tools' + dst = 'assets/build/ba_data/python' + copyrule = 'build/ba_data/python/%.py : ../tools/%.py' + else: + src = 'assets/src' + dst = 'assets/build' + copyrule = 'build/%.py : src/%.py' + + # Separate these into '1' and '2'. + py_targets: List[str] = [] + pyc_targets: List[str] = [] + + _get_py_targets(src, + dst, + py_targets, + pyc_targets, + all_targets, + subset=subset) + + out = (f'\nSCRIPT_TARGETS_PY{suffix} = \\\n ' + + ' \\\n '.join(py_targets) + '\n') + + out += (f'\nSCRIPT_TARGETS_PYC{suffix} = \\\n ' + + ' \\\n '.join(pyc_targets) + '\n') + + # We transform all non-public targets into efrocache-fetches in public. + efc = '' if subset.startswith('public') else '#__EFROCACHE_TARGET__\n' + out += ('\n# Rule to copy src asset scripts to dst.\n' + '# (and make non-writable so I\'m less likely to ' + 'accidentally edit them there)\n' + f'{efc}$(SCRIPT_TARGETS_PY{suffix}) : {copyrule}\n' + '\t@echo Copying script: $@\n' + '\t@mkdir -p $(dir $@)\n' + '\t@rm -f $@\n' + '\t@cp $^ $@\n' + '\t@chmod 444 $@\n') + + out += ('\n# Looks like path mangling from py to pyc is too complex for' + ' pattern rules so\n# just generating explicit targets' + ' for each. Could perhaps look into using a\n# fancy for-loop' + ' instead, but perhaps listing these explicitly isn\'t so bad.\n') + + for i, target in enumerate(pyc_targets): + out += ('\n' + target + ': \\\n ' + py_targets[i] + + '\n\t@echo Compiling script: $^\n' + '\t@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^' + ' && chmod 444 $@\n') + + return out + + +def _get_extras_targets_win(all_targets: Set[str], platform: str) -> str: + targets: List[str] = [] + base = 'assets/src/windows' + dstbase = 'build/windows' + for root, _dnames, fnames in os.walk(base): + for fname in fnames: + + # Only include the platform we were passed. + if not root.startswith('assets/src/windows/' + platform): + continue + + ext = os.path.splitext(fname)[-1] + + # "I don't like .DS_Store files. They're coarse and rough and + # irritating and they get everywhere." + if fname == '.DS_Store': + continue + + # Ignore python files as they're handled separately. + if ext in ['.py', '.pyc']: + continue + + # Various stuff we expect to be there... + if ext in [ + '.exe', '.dll', '.bat', '.txt', '.whl', '.ps1', '.css', + '.sample', '.ico', '.pyd', '.ctypes', '.rst', '.fish', + '.csh', '.cat' + ] or fname in [ + 'activate', 'README', 'command_template', 'fetch_macholib' + ]: + targetpath = os.path.join(dstbase + root[len(base):], fname) + targets.append(targetpath) + all_targets.add('assets/' + targetpath) + continue + + # Complain if something new shows up instead of blindly + # including it. + raise RuntimeError(f'Unexpected extras file: {fname}') + + p_up = platform.upper() + out = (f'\nEXTRAS_TARGETS_WIN_{p_up} = \\\n ' + ' \\\n '.join(targets) + + '\n') + + # We transform all these targets into efrocache-fetches in public. + out += ('\n# Rule to copy src extras to build.\n' + f'#__EFROCACHE_TARGET__\n' + f'$(EXTRAS_TARGETS_WIN_{p_up}) : build/% :' + ' src/%\n' + '\t@echo Copying file: $@\n' + '\t@mkdir -p $(dir $@)\n' + '\t@rm -f $@\n' + '\t@cp $^ $@\n') + + return out + + +def main() -> None: + """Main script entry point.""" + # pylint: disable=too-many-locals + from efrotools import get_config + from pathlib import Path + + # In 'check' mode we simply error on differences. + check = ('--check' in sys.argv) + + # Always operate out of dist root dir. + os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..')) + + public = get_config(Path('.'))['public'] + assert isinstance(public, bool) + + fname = 'assets/Makefile' + with open(fname) as infile: + original = infile.read() + lines = original.splitlines() + + auto_start_public = lines.index('#AUTOGENERATED_BEGIN_PUBLIC (this section' + ' is managed by "update_project")') + auto_end_public = lines.index('#AUTOGENERATED_END_PUBLIC') + auto_start_private = lines.index( + '#AUTOGENERATED_BEGIN_PRIVATE (this section' + ' is managed by "update_project")') + auto_end_private = lines.index('#AUTOGENERATED_END_PRIVATE') + + all_targets_public: Set[str] = set() + all_targets_private: Set[str] = set() + + # We always auto-generate the '1' section. + our_lines_public = [ + _get_py_targets_subset(all_targets_public, + subset='public', + suffix='_PUBLIC'), + _get_py_targets_subset(all_targets_public, + subset='public_tools', + suffix='_PUBLIC_TOOLS') + ] + + # Only auto-generate the private section in the private repo. + if public: + our_lines_private = lines[auto_start_private + 1:auto_end_private] + else: + our_lines_private = [ + _get_py_targets_subset(all_targets_private, + subset='private-apple', + suffix='_PRIVATE_APPLE'), + _get_py_targets_subset(all_targets_private, + subset='private-android', + suffix='_PRIVATE_ANDROID'), + _get_py_targets_subset(all_targets_private, + subset='private-common', + suffix='_PRIVATE_COMMON'), + _get_py_targets_subset(all_targets_private, + subset='private-windows-Win32', + suffix='_PRIVATE_WIN_WIN32'), + _get_py_targets_subset(all_targets_private, + subset='private-windows-x64', + suffix='_PRIVATE_WIN_X64'), + _get_targets('COB_TARGETS', '.collidemodel.obj', '.cob', + all_targets_private), + _get_targets('BOB_TARGETS', '.model.obj', '.bob', + all_targets_private), + _get_targets('FONT_TARGETS', '.fdata', '.fdata', + all_targets_private), + _get_targets('DATA_TARGETS', + '.json', + '.json', + all_targets_private, + limit_to_prefix='ba_data/data'), + _get_targets('AUDIO_TARGETS', '.wav', '.ogg', all_targets_private), + _get_targets('TEX2D_DDS_TARGETS', '.tex2d.png', '.dds', + all_targets_private), + _get_targets('TEX2D_PVR_TARGETS', '.tex2d.png', '.pvr', + all_targets_private), + _get_targets('TEX2D_KTX_TARGETS', '.tex2d.png', '.ktx', + all_targets_private), + _get_targets('TEX2D_PREVIEW_PNG_TARGETS', '.tex2d.png', + '_preview.png', all_targets_private), + _get_extras_targets_win(all_targets_private, 'Win32'), + _get_extras_targets_win(all_targets_private, 'x64'), + ] + filtered = (lines[:auto_start_public + 1] + our_lines_public + + lines[auto_end_public:auto_start_private + 1] + + our_lines_private + lines[auto_end_private:]) + out = '\n'.join(filtered) + '\n' + + if out == original: + print(f'{fname} is up to date.') + else: + if check: + print(f'{Clr.SRED}ERROR: file is out of date: {fname}{Clr.RST}') + sys.exit(255) + print(f'{Clr.SBLU}Updating: {fname}{Clr.RST}') + with open(fname, 'w') as outfile: + outfile.write(out) + + # Lastly, write a simple manifest of the things we expect to have + # in build. We can use this to clear out orphaned files as part of builds. + _write_manifest('assets/.asset_manifest_public.json', all_targets_public, + check) + if not public: + _write_manifest('assets/.asset_manifest_private.json', + all_targets_private, check) + + +def _write_manifest(manifest_path: str, all_targets: Set[str], + check: bool) -> None: + # Lastly, write a simple manifest of the things we expect to have + # in build. We can use this to clear out orphaned files as part of builds. + assert all(t.startswith('assets/build/') for t in all_targets) + if not os.path.exists(manifest_path): + existing_manifest = None + else: + with open(manifest_path) as infile: + existing_manifest = json.loads(infile.read()) + manifest = sorted(t[13:] for t in all_targets) + if manifest == existing_manifest: + print(f'{manifest_path} is up to date.') + else: + if check: + print(f'{Clr.SRED}ERROR: file is out of date:' + f' {manifest_path}{Clr.RST}') + sys.exit(255) + print(f'{Clr.SBLU}Updating: {manifest_path}{Clr.RST}') + with open(manifest_path, 'w') as outfile: + outfile.write(json.dumps(manifest, indent=1)) + + +if __name__ == '__main__': + main() diff --git a/tools/update_project b/tools/update_project index 897d9942..008ec748 100755 --- a/tools/update_project +++ b/tools/update_project @@ -634,11 +634,11 @@ class App: sys.exit(255) def _update_assets_makefile(self) -> None: - if os.path.exists('tools/update_assets_makefile'): - if os.system('tools/update_assets_makefile' + self._checkarg) != 0: - print(Clr.RED + 'Error checking/updating assets Makefile' + - Clr.RST) - sys.exit(255) + assert os.path.exists('tools/update_assets_makefile') + if os.system('tools/update_assets_makefile' + self._checkarg) != 0: + print(Clr.RED + 'Error checking/updating assets Makefile' + + Clr.RST) + sys.exit(255) def _update_generated_code_makefile(self) -> None: if os.path.exists('tools/update_generated_code_makefile'): From 16e2bba5eee3ff768bdfe3a52453a9b4d06cd18d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 13:39:45 -0700 Subject: [PATCH 066/417] Debugging ci error --- tools/update_assets_makefile | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile index c53c998c..7122a36c 100755 --- a/tools/update_assets_makefile +++ b/tools/update_assets_makefile @@ -330,7 +330,12 @@ def main() -> None: print(f'{fname} is up to date.') else: if check: - print(f'{Clr.SRED}ERROR: file is out of date: {fname}{Clr.RST}') + print(f"{Clr.SRED}ERROR: file is out of date: '{fname}'.{Clr.RST}") + print(f'EXPECTED ===========================================\n' + f'{out}\n' + f'FOUND ==============================================\n' + f'{original}\n' + f'END COMPARE ========================================') sys.exit(255) print(f'{Clr.SBLU}Updating: {fname}{Clr.RST}') with open(fname, 'w') as outfile: @@ -361,7 +366,7 @@ def _write_manifest(manifest_path: str, all_targets: Set[str], else: if check: print(f'{Clr.SRED}ERROR: file is out of date:' - f' {manifest_path}{Clr.RST}') + f" '{manifest_path}'.{Clr.RST}") sys.exit(255) print(f'{Clr.SBLU}Updating: {manifest_path}{Clr.RST}') with open(manifest_path, 'w') as outfile: From 0cada3316d92a80c5520ea2540d2d0a199f5fd8d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 14:22:58 -0700 Subject: [PATCH 067/417] Making asset Makefile generation deterministic --- assets/Makefile | 2956 +++++++++++++++++----------------- tools/update_assets_makefile | 19 +- 2 files changed, 1491 insertions(+), 1484 deletions(-) diff --git a/assets/Makefile b/assets/Makefile index 4af402bb..4e14626f 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -142,464 +142,464 @@ ASSET_TARGETS_WIN_X64 += $(EXTRAS_TARGETS_WIN_X64) #AUTOGENERATED_BEGIN_PUBLIC (this section is managed by "update_project") SCRIPT_TARGETS_PY_PUBLIC = \ - build/server/ballisticacore_server.py \ - build/ba_data/python/ba/_dualteamsession.py \ - build/ba_data/python/ba/_gameactivity.py \ - build/ba_data/python/ba/_apputils.py \ - build/ba_data/python/ba/_coopsession.py \ - build/ba_data/python/ba/_appdelegate.py \ - build/ba_data/python/ba/macmusicapp.py \ - build/ba_data/python/ba/internal.py \ - build/ba_data/python/ba/_coopgame.py \ - build/ba_data/python/ba/_meta.py \ - build/ba_data/python/ba/_math.py \ - build/ba_data/python/ba/_collision.py \ - build/ba_data/python/ba/_servermode.py \ - build/ba_data/python/ba/_appconfig.py \ - build/ba_data/python/ba/_gameresults.py \ - build/ba_data/python/ba/_profile.py \ - build/ba_data/python/ba/_error.py \ - build/ba_data/python/ba/_achievement.py \ - build/ba_data/python/ba/_map.py \ - build/ba_data/python/ba/_gameutils.py \ - build/ba_data/python/ba/_activity.py \ - build/ba_data/python/ba/deprecated.py \ - build/ba_data/python/ba/_modutils.py \ - build/ba_data/python/ba/_tips.py \ - build/ba_data/python/ba/_store.py \ - build/ba_data/python/ba/_activitytypes.py \ - build/ba_data/python/ba/_player.py \ build/ba_data/python/ba/__init__.py \ - build/ba_data/python/ba/_assetmanager.py \ - build/ba_data/python/ba/_session.py \ - build/ba_data/python/ba/_hooks.py \ - build/ba_data/python/ba/_enums.py \ - build/ba_data/python/ba/_netutils.py \ - build/ba_data/python/ba/_app.py \ - build/ba_data/python/ba/_benchmark.py \ - build/ba_data/python/ba/_tournament.py \ - build/ba_data/python/ba/_messages.py \ - build/ba_data/python/ba/_analytics.py \ - build/ba_data/python/ba/_freeforallsession.py \ - build/ba_data/python/ba/_score.py \ - build/ba_data/python/ba/_playlist.py \ - build/ba_data/python/ba/_team.py \ - build/ba_data/python/ba/_multiteamsession.py \ - build/ba_data/python/ba/_actor.py \ - build/ba_data/python/ba/_powerup.py \ - build/ba_data/python/ba/osmusic.py \ - build/ba_data/python/ba/_campaign.py \ - build/ba_data/python/ba/_lobby.py \ - build/ba_data/python/ba/_stats.py \ - build/ba_data/python/ba/_input.py \ - build/ba_data/python/ba/_level.py \ - build/ba_data/python/ba/_dependency.py \ - build/ba_data/python/ba/_general.py \ build/ba_data/python/ba/_account.py \ - build/ba_data/python/ba/_music.py \ + build/ba_data/python/ba/_achievement.py \ + build/ba_data/python/ba/_activity.py \ + build/ba_data/python/ba/_activitytypes.py \ + build/ba_data/python/ba/_actor.py \ + build/ba_data/python/ba/_analytics.py \ + build/ba_data/python/ba/_app.py \ + build/ba_data/python/ba/_appconfig.py \ + build/ba_data/python/ba/_appdelegate.py \ + build/ba_data/python/ba/_apputils.py \ + build/ba_data/python/ba/_assetmanager.py \ + build/ba_data/python/ba/_benchmark.py \ + build/ba_data/python/ba/_campaign.py \ + build/ba_data/python/ba/_collision.py \ + build/ba_data/python/ba/_coopgame.py \ + build/ba_data/python/ba/_coopsession.py \ + build/ba_data/python/ba/_dependency.py \ + build/ba_data/python/ba/_dualteamsession.py \ + build/ba_data/python/ba/_enums.py \ + build/ba_data/python/ba/_error.py \ + build/ba_data/python/ba/_freeforallsession.py \ + build/ba_data/python/ba/_gameactivity.py \ + build/ba_data/python/ba/_gameresults.py \ + build/ba_data/python/ba/_gameutils.py \ + build/ba_data/python/ba/_general.py \ + build/ba_data/python/ba/_hooks.py \ + build/ba_data/python/ba/_input.py \ build/ba_data/python/ba/_lang.py \ + build/ba_data/python/ba/_level.py \ + build/ba_data/python/ba/_lobby.py \ + build/ba_data/python/ba/_map.py \ + build/ba_data/python/ba/_math.py \ + build/ba_data/python/ba/_messages.py \ + build/ba_data/python/ba/_meta.py \ + build/ba_data/python/ba/_modutils.py \ + build/ba_data/python/ba/_multiteamsession.py \ + build/ba_data/python/ba/_music.py \ + build/ba_data/python/ba/_netutils.py \ build/ba_data/python/ba/_nodeactor.py \ + build/ba_data/python/ba/_player.py \ + build/ba_data/python/ba/_playlist.py \ + build/ba_data/python/ba/_powerup.py \ + build/ba_data/python/ba/_profile.py \ + build/ba_data/python/ba/_score.py \ + build/ba_data/python/ba/_servermode.py \ + build/ba_data/python/ba/_session.py \ + build/ba_data/python/ba/_stats.py \ + build/ba_data/python/ba/_store.py \ + build/ba_data/python/ba/_team.py \ build/ba_data/python/ba/_teamgame.py \ + build/ba_data/python/ba/_tips.py \ + build/ba_data/python/ba/_tournament.py \ + build/ba_data/python/ba/deprecated.py \ + build/ba_data/python/ba/internal.py \ + build/ba_data/python/ba/macmusicapp.py \ + build/ba_data/python/ba/osmusic.py \ build/ba_data/python/ba/ui/__init__.py \ + build/ba_data/python/bastd/__init__.py \ + build/ba_data/python/bastd/activity/__init__.py \ + build/ba_data/python/bastd/activity/coopjoin.py \ + build/ba_data/python/bastd/activity/coopscore.py \ + build/ba_data/python/bastd/activity/drawscore.py \ + build/ba_data/python/bastd/activity/dualteamscore.py \ + build/ba_data/python/bastd/activity/freeforallvictory.py \ + build/ba_data/python/bastd/activity/multiteamjoin.py \ + build/ba_data/python/bastd/activity/multiteamscore.py \ + build/ba_data/python/bastd/activity/multiteamvictory.py \ + build/ba_data/python/bastd/actor/__init__.py \ + build/ba_data/python/bastd/actor/background.py \ + build/ba_data/python/bastd/actor/bomb.py \ + build/ba_data/python/bastd/actor/controlsguide.py \ + build/ba_data/python/bastd/actor/flag.py \ + build/ba_data/python/bastd/actor/image.py \ + build/ba_data/python/bastd/actor/onscreencountdown.py \ + build/ba_data/python/bastd/actor/onscreentimer.py \ + build/ba_data/python/bastd/actor/playerspaz.py \ + build/ba_data/python/bastd/actor/popuptext.py \ + build/ba_data/python/bastd/actor/powerupbox.py \ + build/ba_data/python/bastd/actor/respawnicon.py \ + build/ba_data/python/bastd/actor/scoreboard.py \ + build/ba_data/python/bastd/actor/spawner.py \ + build/ba_data/python/bastd/actor/spaz.py \ + build/ba_data/python/bastd/actor/spazappearance.py \ + build/ba_data/python/bastd/actor/spazbot.py \ + build/ba_data/python/bastd/actor/spazfactory.py \ + build/ba_data/python/bastd/actor/text.py \ + build/ba_data/python/bastd/actor/tipstext.py \ + build/ba_data/python/bastd/actor/zoomtext.py \ + build/ba_data/python/bastd/appdelegate.py \ + build/ba_data/python/bastd/game/__init__.py \ + build/ba_data/python/bastd/game/assault.py \ + build/ba_data/python/bastd/game/capturetheflag.py \ + build/ba_data/python/bastd/game/chosenone.py \ + build/ba_data/python/bastd/game/conquest.py \ + build/ba_data/python/bastd/game/deathmatch.py \ + build/ba_data/python/bastd/game/easteregghunt.py \ + build/ba_data/python/bastd/game/elimination.py \ + build/ba_data/python/bastd/game/football.py \ + build/ba_data/python/bastd/game/hockey.py \ + build/ba_data/python/bastd/game/keepaway.py \ + build/ba_data/python/bastd/game/kingofthehill.py \ + build/ba_data/python/bastd/game/meteorshower.py \ + build/ba_data/python/bastd/game/ninjafight.py \ + build/ba_data/python/bastd/game/onslaught.py \ + build/ba_data/python/bastd/game/race.py \ + build/ba_data/python/bastd/game/runaround.py \ + build/ba_data/python/bastd/game/targetpractice.py \ + build/ba_data/python/bastd/game/thelaststand.py \ build/ba_data/python/bastd/gameutils.py \ build/ba_data/python/bastd/mainmenu.py \ + build/ba_data/python/bastd/mapdata/__init__.py \ + build/ba_data/python/bastd/mapdata/big_g.py \ + build/ba_data/python/bastd/mapdata/bridgit.py \ + build/ba_data/python/bastd/mapdata/courtyard.py \ + build/ba_data/python/bastd/mapdata/crag_castle.py \ + build/ba_data/python/bastd/mapdata/doom_shroom.py \ + build/ba_data/python/bastd/mapdata/football_stadium.py \ + build/ba_data/python/bastd/mapdata/happy_thoughts.py \ + build/ba_data/python/bastd/mapdata/hockey_stadium.py \ + build/ba_data/python/bastd/mapdata/lake_frigid.py \ + build/ba_data/python/bastd/mapdata/monkey_face.py \ + build/ba_data/python/bastd/mapdata/rampage.py \ + build/ba_data/python/bastd/mapdata/roundabout.py \ + build/ba_data/python/bastd/mapdata/step_right_up.py \ + build/ba_data/python/bastd/mapdata/the_pad.py \ + build/ba_data/python/bastd/mapdata/tip_top.py \ + build/ba_data/python/bastd/mapdata/tower_d.py \ + build/ba_data/python/bastd/mapdata/zig_zag.py \ build/ba_data/python/bastd/maps.py \ - build/ba_data/python/bastd/appdelegate.py \ - build/ba_data/python/bastd/tutorial.py \ - build/ba_data/python/bastd/__init__.py \ + build/ba_data/python/bastd/session/__init__.py \ build/ba_data/python/bastd/stdmap.py \ - build/ba_data/python/bastd/ui/playoptions.py \ - build/ba_data/python/bastd/ui/mainmenu.py \ - build/ba_data/python/bastd/ui/getremote.py \ - build/ba_data/python/bastd/ui/tournamententry.py \ - build/ba_data/python/bastd/ui/telnet.py \ - build/ba_data/python/bastd/ui/appinvite.py \ - build/ba_data/python/bastd/ui/gather.py \ - build/ba_data/python/bastd/ui/config.py \ - build/ba_data/python/bastd/ui/colorpicker.py \ - build/ba_data/python/bastd/ui/tabs.py \ - build/ba_data/python/bastd/ui/promocode.py \ - build/ba_data/python/bastd/ui/fileselector.py \ - build/ba_data/python/bastd/ui/feedback.py \ - build/ba_data/python/bastd/ui/teamnamescolors.py \ - build/ba_data/python/bastd/ui/configerror.py \ - build/ba_data/python/bastd/ui/serverdialog.py \ - build/ba_data/python/bastd/ui/getcurrency.py \ + build/ba_data/python/bastd/tutorial.py \ build/ba_data/python/bastd/ui/__init__.py \ - build/ba_data/python/bastd/ui/specialoffer.py \ - build/ba_data/python/bastd/ui/helpui.py \ - build/ba_data/python/bastd/ui/purchase.py \ - build/ba_data/python/bastd/ui/continues.py \ - build/ba_data/python/bastd/ui/play.py \ - build/ba_data/python/bastd/ui/popup.py \ - build/ba_data/python/bastd/ui/onscreenkeyboard.py \ - build/ba_data/python/bastd/ui/kiosk.py \ - build/ba_data/python/bastd/ui/qrcode.py \ - build/ba_data/python/bastd/ui/trophies.py \ - build/ba_data/python/bastd/ui/partyqueue.py \ - build/ba_data/python/bastd/ui/url.py \ - build/ba_data/python/bastd/ui/debug.py \ - build/ba_data/python/bastd/ui/iconpicker.py \ - build/ba_data/python/bastd/ui/watch.py \ + build/ba_data/python/bastd/ui/account/__init__.py \ + build/ba_data/python/bastd/ui/account/link.py \ + build/ba_data/python/bastd/ui/account/settings.py \ + build/ba_data/python/bastd/ui/account/unlink.py \ + build/ba_data/python/bastd/ui/account/viewer.py \ build/ba_data/python/bastd/ui/achievements.py \ - build/ba_data/python/bastd/ui/radiogroup.py \ - build/ba_data/python/bastd/ui/creditslist.py \ - build/ba_data/python/bastd/ui/tournamentscores.py \ + build/ba_data/python/bastd/ui/appinvite.py \ build/ba_data/python/bastd/ui/characterpicker.py \ - build/ba_data/python/bastd/ui/report.py \ - build/ba_data/python/bastd/ui/resourcetypeinfo.py \ + build/ba_data/python/bastd/ui/colorpicker.py \ + build/ba_data/python/bastd/ui/config.py \ + build/ba_data/python/bastd/ui/configerror.py \ build/ba_data/python/bastd/ui/confirm.py \ - build/ba_data/python/bastd/ui/party.py \ - build/ba_data/python/bastd/ui/settings/graphics.py \ - build/ba_data/python/bastd/ui/settings/advanced.py \ - build/ba_data/python/bastd/ui/settings/controls.py \ - build/ba_data/python/bastd/ui/settings/gamepadadvanced.py \ - build/ba_data/python/bastd/ui/settings/gamepadselect.py \ - build/ba_data/python/bastd/ui/settings/touchscreen.py \ - build/ba_data/python/bastd/ui/settings/__init__.py \ - build/ba_data/python/bastd/ui/settings/xbox360controller.py \ - build/ba_data/python/bastd/ui/settings/audio.py \ - build/ba_data/python/bastd/ui/settings/gamepad.py \ - build/ba_data/python/bastd/ui/settings/nettesting.py \ - build/ba_data/python/bastd/ui/settings/remoteapp.py \ - build/ba_data/python/bastd/ui/settings/testing.py \ - build/ba_data/python/bastd/ui/settings/wiimote.py \ - build/ba_data/python/bastd/ui/settings/vrtesting.py \ - build/ba_data/python/bastd/ui/settings/allsettings.py \ - build/ba_data/python/bastd/ui/settings/ps3controller.py \ - build/ba_data/python/bastd/ui/settings/keyboard.py \ - build/ba_data/python/bastd/ui/playlist/customizebrowser.py \ - build/ba_data/python/bastd/ui/playlist/__init__.py \ - build/ba_data/python/bastd/ui/playlist/edit.py \ - build/ba_data/python/bastd/ui/playlist/browser.py \ - build/ba_data/python/bastd/ui/playlist/mapselect.py \ - build/ba_data/python/bastd/ui/playlist/share.py \ - build/ba_data/python/bastd/ui/playlist/editgame.py \ - build/ba_data/python/bastd/ui/playlist/editcontroller.py \ - build/ba_data/python/bastd/ui/playlist/addgame.py \ - build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py \ - build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py \ - build/ba_data/python/bastd/ui/soundtrack/__init__.py \ - build/ba_data/python/bastd/ui/soundtrack/edit.py \ - build/ba_data/python/bastd/ui/soundtrack/browser.py \ + build/ba_data/python/bastd/ui/continues.py \ + build/ba_data/python/bastd/ui/coop/__init__.py \ + build/ba_data/python/bastd/ui/coop/browser.py \ + build/ba_data/python/bastd/ui/coop/gamebutton.py \ + build/ba_data/python/bastd/ui/coop/level.py \ + build/ba_data/python/bastd/ui/creditslist.py \ + build/ba_data/python/bastd/ui/debug.py \ + build/ba_data/python/bastd/ui/feedback.py \ + build/ba_data/python/bastd/ui/fileselector.py \ + build/ba_data/python/bastd/ui/gather.py \ + build/ba_data/python/bastd/ui/getcurrency.py \ + build/ba_data/python/bastd/ui/getremote.py \ + build/ba_data/python/bastd/ui/helpui.py \ + build/ba_data/python/bastd/ui/iconpicker.py \ + build/ba_data/python/bastd/ui/kiosk.py \ build/ba_data/python/bastd/ui/league/__init__.py \ build/ba_data/python/bastd/ui/league/rankbutton.py \ build/ba_data/python/bastd/ui/league/rankwindow.py \ - build/ba_data/python/bastd/ui/coop/gamebutton.py \ - build/ba_data/python/bastd/ui/coop/__init__.py \ - build/ba_data/python/bastd/ui/coop/browser.py \ - build/ba_data/python/bastd/ui/coop/level.py \ + build/ba_data/python/bastd/ui/mainmenu.py \ + build/ba_data/python/bastd/ui/onscreenkeyboard.py \ + build/ba_data/python/bastd/ui/party.py \ + build/ba_data/python/bastd/ui/partyqueue.py \ + build/ba_data/python/bastd/ui/play.py \ + build/ba_data/python/bastd/ui/playlist/__init__.py \ + build/ba_data/python/bastd/ui/playlist/addgame.py \ + build/ba_data/python/bastd/ui/playlist/browser.py \ + build/ba_data/python/bastd/ui/playlist/customizebrowser.py \ + build/ba_data/python/bastd/ui/playlist/edit.py \ + build/ba_data/python/bastd/ui/playlist/editcontroller.py \ + build/ba_data/python/bastd/ui/playlist/editgame.py \ + build/ba_data/python/bastd/ui/playlist/mapselect.py \ + build/ba_data/python/bastd/ui/playlist/share.py \ + build/ba_data/python/bastd/ui/playoptions.py \ + build/ba_data/python/bastd/ui/popup.py \ build/ba_data/python/bastd/ui/profile/__init__.py \ + build/ba_data/python/bastd/ui/profile/browser.py \ build/ba_data/python/bastd/ui/profile/edit.py \ build/ba_data/python/bastd/ui/profile/upgrade.py \ - build/ba_data/python/bastd/ui/profile/browser.py \ - build/ba_data/python/bastd/ui/account/link.py \ - build/ba_data/python/bastd/ui/account/viewer.py \ - build/ba_data/python/bastd/ui/account/__init__.py \ - build/ba_data/python/bastd/ui/account/unlink.py \ - build/ba_data/python/bastd/ui/account/settings.py \ + build/ba_data/python/bastd/ui/promocode.py \ + build/ba_data/python/bastd/ui/purchase.py \ + build/ba_data/python/bastd/ui/qrcode.py \ + build/ba_data/python/bastd/ui/radiogroup.py \ + build/ba_data/python/bastd/ui/report.py \ + build/ba_data/python/bastd/ui/resourcetypeinfo.py \ + build/ba_data/python/bastd/ui/serverdialog.py \ + build/ba_data/python/bastd/ui/settings/__init__.py \ + build/ba_data/python/bastd/ui/settings/advanced.py \ + build/ba_data/python/bastd/ui/settings/allsettings.py \ + build/ba_data/python/bastd/ui/settings/audio.py \ + build/ba_data/python/bastd/ui/settings/controls.py \ + build/ba_data/python/bastd/ui/settings/gamepad.py \ + build/ba_data/python/bastd/ui/settings/gamepadadvanced.py \ + build/ba_data/python/bastd/ui/settings/gamepadselect.py \ + build/ba_data/python/bastd/ui/settings/graphics.py \ + build/ba_data/python/bastd/ui/settings/keyboard.py \ + build/ba_data/python/bastd/ui/settings/nettesting.py \ + build/ba_data/python/bastd/ui/settings/ps3controller.py \ + build/ba_data/python/bastd/ui/settings/remoteapp.py \ + build/ba_data/python/bastd/ui/settings/testing.py \ + build/ba_data/python/bastd/ui/settings/touchscreen.py \ + build/ba_data/python/bastd/ui/settings/vrtesting.py \ + build/ba_data/python/bastd/ui/settings/wiimote.py \ + build/ba_data/python/bastd/ui/settings/xbox360controller.py \ + build/ba_data/python/bastd/ui/soundtrack/__init__.py \ + build/ba_data/python/bastd/ui/soundtrack/browser.py \ + build/ba_data/python/bastd/ui/soundtrack/edit.py \ + build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py \ + build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py \ + build/ba_data/python/bastd/ui/specialoffer.py \ build/ba_data/python/bastd/ui/store/__init__.py \ build/ba_data/python/bastd/ui/store/browser.py \ build/ba_data/python/bastd/ui/store/button.py \ build/ba_data/python/bastd/ui/store/item.py \ - build/ba_data/python/bastd/activity/coopjoin.py \ - build/ba_data/python/bastd/activity/multiteamvictory.py \ - build/ba_data/python/bastd/activity/dualteamscore.py \ - build/ba_data/python/bastd/activity/drawscore.py \ - build/ba_data/python/bastd/activity/__init__.py \ - build/ba_data/python/bastd/activity/freeforallvictory.py \ - build/ba_data/python/bastd/activity/coopscore.py \ - build/ba_data/python/bastd/activity/multiteamjoin.py \ - build/ba_data/python/bastd/activity/multiteamscore.py \ - build/ba_data/python/bastd/game/capturetheflag.py \ - build/ba_data/python/bastd/game/targetpractice.py \ - build/ba_data/python/bastd/game/ninjafight.py \ - build/ba_data/python/bastd/game/easteregghunt.py \ - build/ba_data/python/bastd/game/race.py \ - build/ba_data/python/bastd/game/meteorshower.py \ - build/ba_data/python/bastd/game/thelaststand.py \ - build/ba_data/python/bastd/game/__init__.py \ - build/ba_data/python/bastd/game/football.py \ - build/ba_data/python/bastd/game/kingofthehill.py \ - build/ba_data/python/bastd/game/assault.py \ - build/ba_data/python/bastd/game/keepaway.py \ - build/ba_data/python/bastd/game/elimination.py \ - build/ba_data/python/bastd/game/deathmatch.py \ - build/ba_data/python/bastd/game/onslaught.py \ - build/ba_data/python/bastd/game/hockey.py \ - build/ba_data/python/bastd/game/chosenone.py \ - build/ba_data/python/bastd/game/conquest.py \ - build/ba_data/python/bastd/game/runaround.py \ - build/ba_data/python/bastd/mapdata/bridgit.py \ - build/ba_data/python/bastd/mapdata/big_g.py \ - build/ba_data/python/bastd/mapdata/hockey_stadium.py \ - build/ba_data/python/bastd/mapdata/courtyard.py \ - build/ba_data/python/bastd/mapdata/tower_d.py \ - build/ba_data/python/bastd/mapdata/__init__.py \ - build/ba_data/python/bastd/mapdata/roundabout.py \ - build/ba_data/python/bastd/mapdata/rampage.py \ - build/ba_data/python/bastd/mapdata/crag_castle.py \ - build/ba_data/python/bastd/mapdata/step_right_up.py \ - build/ba_data/python/bastd/mapdata/football_stadium.py \ - build/ba_data/python/bastd/mapdata/the_pad.py \ - build/ba_data/python/bastd/mapdata/happy_thoughts.py \ - build/ba_data/python/bastd/mapdata/monkey_face.py \ - build/ba_data/python/bastd/mapdata/doom_shroom.py \ - build/ba_data/python/bastd/mapdata/zig_zag.py \ - build/ba_data/python/bastd/mapdata/lake_frigid.py \ - build/ba_data/python/bastd/mapdata/tip_top.py \ - build/ba_data/python/bastd/actor/spazfactory.py \ - build/ba_data/python/bastd/actor/bomb.py \ - build/ba_data/python/bastd/actor/spazbot.py \ - build/ba_data/python/bastd/actor/flag.py \ - build/ba_data/python/bastd/actor/scoreboard.py \ - build/ba_data/python/bastd/actor/popuptext.py \ - build/ba_data/python/bastd/actor/background.py \ - build/ba_data/python/bastd/actor/__init__.py \ - build/ba_data/python/bastd/actor/zoomtext.py \ - build/ba_data/python/bastd/actor/spaz.py \ - build/ba_data/python/bastd/actor/spazappearance.py \ - build/ba_data/python/bastd/actor/controlsguide.py \ - build/ba_data/python/bastd/actor/powerupbox.py \ - build/ba_data/python/bastd/actor/text.py \ - build/ba_data/python/bastd/actor/spawner.py \ - build/ba_data/python/bastd/actor/respawnicon.py \ - build/ba_data/python/bastd/actor/playerspaz.py \ - build/ba_data/python/bastd/actor/tipstext.py \ - build/ba_data/python/bastd/actor/onscreencountdown.py \ - build/ba_data/python/bastd/actor/onscreentimer.py \ - build/ba_data/python/bastd/actor/image.py \ - build/ba_data/python/bastd/session/__init__.py + build/ba_data/python/bastd/ui/tabs.py \ + build/ba_data/python/bastd/ui/teamnamescolors.py \ + build/ba_data/python/bastd/ui/telnet.py \ + build/ba_data/python/bastd/ui/tournamententry.py \ + build/ba_data/python/bastd/ui/tournamentscores.py \ + build/ba_data/python/bastd/ui/trophies.py \ + build/ba_data/python/bastd/ui/url.py \ + build/ba_data/python/bastd/ui/watch.py \ + build/server/ballisticacore_server.py SCRIPT_TARGETS_PYC_PUBLIC = \ - build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc \ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc + build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -614,278 +614,143 @@ $(SCRIPT_TARGETS_PY_PUBLIC) : build/%.py : src/%.py # just generating explicit targets for each. Could perhaps look into using a # fancy for-loop instead, but perhaps listing these explicitly isn't so bad. -build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc: \ - build/server/ballisticacore_server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_dualteamsession.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gameactivity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_apputils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_coopsession.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_appdelegate.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/macmusicapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/internal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_coopgame.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_meta.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_math.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_collision.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_servermode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_appconfig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gameresults.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_profile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_error.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_achievement.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_map.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gameutils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_activity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/deprecated.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_modutils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_tips.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_store.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_activitytypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_player.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_assetmanager.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_session.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_hooks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_enums.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_netutils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_app.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_benchmark.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_tournament.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_messages.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_analytics.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_freeforallsession.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_score.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_playlist.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_team.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_multiteamsession.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_actor.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_powerup.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/osmusic.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_campaign.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_lobby.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_stats.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_input.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_level.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_dependency.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_general.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_account.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_music.py +build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_achievement.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_activity.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_activitytypes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_actor.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_analytics.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_app.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_appconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_appdelegate.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_apputils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_assetmanager.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_benchmark.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_campaign.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_collision.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_coopgame.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_coopsession.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_dependency.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_dualteamsession.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_enums.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_error.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_freeforallsession.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_gameactivity.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_gameresults.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_gameutils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_general.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_hooks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_input.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -894,138 +759,523 @@ build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_level.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_lobby.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_map.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_math.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_messages.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_meta.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_modutils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_multiteamsession.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_music.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_netutils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_nodeactor.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_player.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_playlist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_powerup.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_profile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_score.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_servermode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_session.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_stats.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_store.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_team.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_teamgame.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_tips.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_tournament.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/deprecated.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/internal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/macmusicapp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/osmusic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/ui/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/gameutils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mainmenu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/maps.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/appdelegate.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/tutorial.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/coopjoin.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/coopscore.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/drawscore.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/dualteamscore.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/freeforallvictory.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/multiteamjoin.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/multiteamscore.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/activity/multiteamvictory.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/background.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/bomb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/controlsguide.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/flag.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/image.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/onscreencountdown.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/onscreentimer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/playerspaz.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/popuptext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/powerupbox.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/respawnicon.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/scoreboard.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/spawner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/spaz.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/spazappearance.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/spazbot.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/spazfactory.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/text.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/tipstext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/actor/zoomtext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/appdelegate.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/assault.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/capturetheflag.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/chosenone.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/conquest.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/deathmatch.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/easteregghunt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/elimination.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/football.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/hockey.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/keepaway.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/kingofthehill.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/meteorshower.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/ninjafight.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/onslaught.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/race.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/runaround.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/targetpractice.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/game/thelaststand.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/gameutils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mainmenu.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/big_g.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/bridgit.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/courtyard.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/crag_castle.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/doom_shroom.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/football_stadium.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/happy_thoughts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/hockey_stadium.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/lake_frigid.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/monkey_face.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/rampage.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/roundabout.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/step_right_up.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/the_pad.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/tip_top.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/tower_d.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/mapdata/zig_zag.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/maps.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/session/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/stdmap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playoptions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/mainmenu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/getremote.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/tournamententry.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/telnet.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/appinvite.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/gather.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/config.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/colorpicker.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/tabs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/promocode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/fileselector.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/feedback.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/teamnamescolors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/configerror.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/serverdialog.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/getcurrency.py +build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/tutorial.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -1034,766 +1284,516 @@ build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/specialoffer.py +build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/account/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/helpui.py +build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/account/link.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/purchase.py +build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/account/settings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/account/unlink.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/account/viewer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/achievements.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/appinvite.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/characterpicker.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/colorpicker.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/configerror.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/confirm.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/continues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/play.py +build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/coop/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/popup.py +build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/coop/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/onscreenkeyboard.py +build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/coop/gamebutton.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/coop/level.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/creditslist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/debug.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/feedback.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/fileselector.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/gather.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/getcurrency.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/getremote.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/helpui.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/iconpicker.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/kiosk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/qrcode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/trophies.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/partyqueue.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/url.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/debug.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/iconpicker.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/watch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/achievements.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/radiogroup.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/creditslist.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/tournamentscores.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/characterpicker.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/report.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/resourcetypeinfo.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/confirm.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/party.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/graphics.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/advanced.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/controls.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/gamepadadvanced.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/gamepadselect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/touchscreen.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/xbox360controller.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/audio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/gamepad.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/nettesting.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/remoteapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/testing.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/wiimote.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/vrtesting.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/allsettings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/ps3controller.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/keyboard.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/customizebrowser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/edit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/browser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/mapselect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/share.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/editgame.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/editcontroller.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/addgame.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/edit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/browser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankbutton.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankwindow.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/gamebutton.py +build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/mainmenu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/__init__.py +build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/onscreenkeyboard.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/browser.py +build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/party.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/level.py +build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/partyqueue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/__init__.py +build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/play.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/edit.py +build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/upgrade.py +build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/addgame.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/browser.py +build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/link.py +build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/customizebrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/viewer.py +build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/edit.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/editcontroller.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/__init__.py + build/ba_data/python/bastd/ui/playlist/editgame.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/unlink.py +build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playlist/mapselect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/settings.py + build/ba_data/python/bastd/ui/playlist/share.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/playoptions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/popup.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/profile/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/profile/browser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/profile/edit.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/profile/upgrade.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/promocode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/purchase.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/qrcode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/radiogroup.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/report.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/resourcetypeinfo.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/serverdialog.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/advanced.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/allsettings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/audio.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/controls.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/gamepad.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/gamepadadvanced.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/gamepadselect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/graphics.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/keyboard.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/nettesting.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/ps3controller.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/remoteapp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/testing.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/touchscreen.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/vrtesting.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/wiimote.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/settings/xbox360controller.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/soundtrack/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/soundtrack/browser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/soundtrack/edit.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/specialoffer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/button.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/item.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/coopjoin.py +build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/tabs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/multiteamvictory.py +build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/teamnamescolors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/dualteamscore.py +build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/telnet.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/drawscore.py +build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/tournamententry.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/__init__.py +build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/tournamentscores.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/freeforallvictory.py +build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/trophies.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/coopscore.py +build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/url.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/multiteamjoin.py +build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ + build/ba_data/python/bastd/ui/watch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/multiteamscore.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/capturetheflag.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/targetpractice.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/ninjafight.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/easteregghunt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/race.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/meteorshower.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/thelaststand.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/football.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/kingofthehill.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/assault.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/keepaway.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/elimination.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/deathmatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/onslaught.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/hockey.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/chosenone.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/conquest.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/runaround.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/bridgit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/big_g.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/hockey_stadium.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/courtyard.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/tower_d.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/roundabout.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/rampage.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/crag_castle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/step_right_up.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/football_stadium.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/the_pad.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/happy_thoughts.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/monkey_face.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/doom_shroom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/zig_zag.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/lake_frigid.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/tip_top.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spazfactory.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/bomb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spazbot.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/flag.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/scoreboard.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/popuptext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/background.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/zoomtext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spaz.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spazappearance.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/controlsguide.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/powerupbox.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spawner.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/respawnicon.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/playerspaz.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/tipstext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/onscreencountdown.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/onscreentimer.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/image.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/session/__init__.py +build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc: \ + build/server/ballisticacore_server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \ - build/ba_data/python/efro/error.py \ - build/ba_data/python/efro/terminal.py \ - build/ba_data/python/efro/util.py \ - build/ba_data/python/efro/__init__.py \ - build/ba_data/python/efro/dataclasses.py \ - build/ba_data/python/efro/call.py \ - build/ba_data/python/efro/json.py \ - build/ba_data/python/efro/entity/_base.py \ - build/ba_data/python/efro/entity/_support.py \ - build/ba_data/python/efro/entity/util.py \ - build/ba_data/python/efro/entity/_entity.py \ - build/ba_data/python/efro/entity/_field.py \ - build/ba_data/python/efro/entity/__init__.py \ - build/ba_data/python/efro/entity/_value.py \ - build/ba_data/python/bacommon/servermanager.py \ build/ba_data/python/bacommon/__init__.py \ build/ba_data/python/bacommon/assets.py \ - build/ba_data/python/bacommon/err.py + build/ba_data/python/bacommon/err.py \ + build/ba_data/python/bacommon/servermanager.py \ + build/ba_data/python/efro/__init__.py \ + build/ba_data/python/efro/call.py \ + build/ba_data/python/efro/dataclasses.py \ + build/ba_data/python/efro/entity/__init__.py \ + build/ba_data/python/efro/entity/_base.py \ + build/ba_data/python/efro/entity/_entity.py \ + build/ba_data/python/efro/entity/_field.py \ + build/ba_data/python/efro/entity/_support.py \ + build/ba_data/python/efro/entity/_value.py \ + build/ba_data/python/efro/entity/util.py \ + build/ba_data/python/efro/error.py \ + build/ba_data/python/efro/json.py \ + build/ba_data/python/efro/terminal.py \ + build/ba_data/python/efro/util.py SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \ - build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc \ - build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc \ build/ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bacommon/__pycache__/assets.cpython-37.opt-1.pyc \ - build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc + build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc \ + build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -1808,81 +1808,6 @@ $(SCRIPT_TARGETS_PY_PUBLIC_TOOLS) : build/ba_data/python/%.py : ../tools/%.py # just generating explicit targets for each. Could perhaps look into using a # fancy for-loop instead, but perhaps listing these explicitly isn't so bad. -build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/error.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/terminal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/dataclasses.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/call.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/json.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_base.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_support.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_entity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_field.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_value.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc: \ - build/ba_data/python/bacommon/servermanager.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - build/ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/__init__.py @echo Compiling script: $^ @@ -1898,6 +1823,81 @@ build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc: \ + build/ba_data/python/bacommon/servermanager.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/call.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/dataclasses.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/_base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/_entity.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/_field.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/_support.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/_value.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/entity/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/error.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/json.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/terminal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ + build/ba_data/python/efro/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + #AUTOGENERATED_END_PUBLIC #AUTOGENERATED_BEGIN_PRIVATE (this section is managed by "update_project") diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile index 7122a36c..ab9bcde3 100755 --- a/tools/update_assets_makefile +++ b/tools/update_assets_makefile @@ -63,7 +63,7 @@ def _get_targets(varname: str, all_targets.add(os.path.join(dstfin, outname)) targets.append(os.path.join(dstrootvar, outname)) - return '\n' + varname + ' = \\\n ' + ' \\\n '.join(targets) + return '\n' + varname + ' = \\\n ' + ' \\\n '.join(sorted(targets)) def _get_py_targets(src: str, dst: str, py_targets: List[str], @@ -149,6 +149,9 @@ def _get_py_targets_subset(all_targets: Set[str], subset: str, all_targets, subset=subset) + py_targets.sort() + pyc_targets.sort() + out = (f'\nSCRIPT_TARGETS_PY{suffix} = \\\n ' + ' \\\n '.join(py_targets) + '\n') @@ -220,6 +223,7 @@ def _get_extras_targets_win(all_targets: Set[str], platform: str) -> str: # including it. raise RuntimeError(f'Unexpected extras file: {fname}') + targets.sort() p_up = platform.upper() out = (f'\nEXTRAS_TARGETS_WIN_{p_up} = \\\n ' + ' \\\n '.join(targets) + '\n') @@ -331,11 +335,14 @@ def main() -> None: else: if check: print(f"{Clr.SRED}ERROR: file is out of date: '{fname}'.{Clr.RST}") - print(f'EXPECTED ===========================================\n' - f'{out}\n' - f'FOUND ==============================================\n' - f'{original}\n' - f'END COMPARE ========================================') + + # Print exact contents if we need to debug: + if bool(False): + print(f'EXPECTED ===========================================\n' + f'{out}\n' + f'FOUND ==============================================\n' + f'{original}\n' + f'END COMPARE ========================================') sys.exit(255) print(f'{Clr.SBLU}Updating: {fname}{Clr.RST}') with open(fname, 'w') as outfile: From e8d7871de27e3d9ce2f9befcc2a52d4075bfcaf0 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 14:35:54 -0700 Subject: [PATCH 068/417] Deterministic Makefile updates for internal bits --- assets/Makefile | 30522 +++++++++++++++++++++++----------------------- 1 file changed, 15261 insertions(+), 15261 deletions(-) diff --git a/assets/Makefile b/assets/Makefile index 4e14626f..d817bcef 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -1903,860 +1903,860 @@ build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ #AUTOGENERATED_BEGIN_PRIVATE (this section is managed by "update_project") SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ - build/pylib-apple/zipfile.py \ - build/pylib-apple/shutil.py \ - build/pylib-apple/tempfile.py \ - build/pylib-apple/queue.py \ - build/pylib-apple/macpath.py \ - build/pylib-apple/_pyio.py \ - build/pylib-apple/crypt.py \ - build/pylib-apple/pkgutil.py \ - build/pylib-apple/_dummy_thread.py \ - build/pylib-apple/lzma.py \ - build/pylib-apple/asyncore.py \ - build/pylib-apple/__phello__.foo.py \ - build/pylib-apple/_sitebuiltins.py \ - build/pylib-apple/copyreg.py \ - build/pylib-apple/sndhdr.py \ - build/pylib-apple/rlcompleter.py \ - build/pylib-apple/gzip.py \ - build/pylib-apple/ipaddress.py \ - build/pylib-apple/trace.py \ - build/pylib-apple/webbrowser.py \ - build/pylib-apple/nntplib.py \ - build/pylib-apple/_compat_pickle.py \ - build/pylib-apple/dis.py \ - build/pylib-apple/formatter.py \ - build/pylib-apple/bdb.py \ - build/pylib-apple/zipapp.py \ - build/pylib-apple/cmd.py \ - build/pylib-apple/tty.py \ - build/pylib-apple/tabnanny.py \ - build/pylib-apple/_py_abc.py \ - build/pylib-apple/cProfile.py \ - build/pylib-apple/token.py \ - build/pylib-apple/textwrap.py \ - build/pylib-apple/base64.py \ - build/pylib-apple/_markupbase.py \ - build/pylib-apple/bz2.py \ - build/pylib-apple/signal.py \ - build/pylib-apple/sre_constants.py \ - build/pylib-apple/cgitb.py \ - build/pylib-apple/_threading_local.py \ - build/pylib-apple/pyclbr.py \ - build/pylib-apple/gettext.py \ - build/pylib-apple/wave.py \ - build/pylib-apple/weakref.py \ - build/pylib-apple/bisect.py \ - build/pylib-apple/opcode.py \ - build/pylib-apple/netrc.py \ - build/pylib-apple/heapq.py \ - build/pylib-apple/functools.py \ - build/pylib-apple/modulefinder.py \ - build/pylib-apple/_compression.py \ - build/pylib-apple/tracemalloc.py \ - build/pylib-apple/hashlib.py \ - build/pylib-apple/cgi.py \ - build/pylib-apple/codeop.py \ - build/pylib-apple/fnmatch.py \ - build/pylib-apple/traceback.py \ - build/pylib-apple/nturl2path.py \ - build/pylib-apple/warnings.py \ - build/pylib-apple/subprocess.py \ - build/pylib-apple/profile.py \ - build/pylib-apple/imghdr.py \ - build/pylib-apple/this.py \ - build/pylib-apple/filecmp.py \ - build/pylib-apple/codecs.py \ - build/pylib-apple/uu.py \ - build/pylib-apple/_weakrefset.py \ - build/pylib-apple/io.py \ - build/pylib-apple/code.py \ - build/pylib-apple/operator.py \ - build/pylib-apple/fileinput.py \ - build/pylib-apple/os.py \ - build/pylib-apple/difflib.py \ - build/pylib-apple/pydoc.py \ - build/pylib-apple/symbol.py \ - build/pylib-apple/selectors.py \ - build/pylib-apple/decimal.py \ - build/pylib-apple/socketserver.py \ - build/pylib-apple/copy.py \ - build/pylib-apple/genericpath.py \ - build/pylib-apple/linecache.py \ - build/pylib-apple/types.py \ - build/pylib-apple/mimetypes.py \ - build/pylib-apple/xdrlib.py \ - build/pylib-apple/colorsys.py \ - build/pylib-apple/numbers.py \ - build/pylib-apple/_strptime.py \ - build/pylib-apple/dummy_threading.py \ - build/pylib-apple/contextvars.py \ - build/pylib-apple/random.py \ - build/pylib-apple/ftplib.py \ - build/pylib-apple/chunk.py \ - build/pylib-apple/optparse.py \ - build/pylib-apple/pdb.py \ - build/pylib-apple/threading.py \ - build/pylib-apple/platform.py \ - build/pylib-apple/pstats.py \ - build/pylib-apple/glob.py \ - build/pylib-apple/quopri.py \ - build/pylib-apple/symtable.py \ - build/pylib-apple/pprint.py \ - build/pylib-apple/calendar.py \ - build/pylib-apple/inspect.py \ - build/pylib-apple/poplib.py \ - build/pylib-apple/binhex.py \ - build/pylib-apple/plistlib.py \ - build/pylib-apple/pickletools.py \ - build/pylib-apple/pipes.py \ - build/pylib-apple/site.py \ - build/pylib-apple/telnetlib.py \ - build/pylib-apple/keyword.py \ - build/pylib-apple/configparser.py \ - build/pylib-apple/reprlib.py \ - build/pylib-apple/secrets.py \ - build/pylib-apple/shlex.py \ - build/pylib-apple/posixpath.py \ - build/pylib-apple/py_compile.py \ - build/pylib-apple/_osx_support.py \ - build/pylib-apple/stat.py \ - build/pylib-apple/compileall.py \ - build/pylib-apple/csv.py \ - build/pylib-apple/fractions.py \ - build/pylib-apple/sched.py \ - build/pylib-apple/mailbox.py \ - build/pylib-apple/sre_compile.py \ - build/pylib-apple/locale.py \ - build/pylib-apple/ast.py \ - build/pylib-apple/doctest.py \ - build/pylib-apple/argparse.py \ - build/pylib-apple/getpass.py \ - build/pylib-apple/pickle.py \ - build/pylib-apple/pty.py \ - build/pylib-apple/contextlib.py \ - build/pylib-apple/statistics.py \ - build/pylib-apple/_collections_abc.py \ - build/pylib-apple/sunau.py \ build/pylib-apple/__future__.py \ - build/pylib-apple/dataclasses.py \ - build/pylib-apple/shelve.py \ - build/pylib-apple/string.py \ - build/pylib-apple/smtplib.py \ - build/pylib-apple/getopt.py \ - build/pylib-apple/antigravity.py \ - build/pylib-apple/enum.py \ - build/pylib-apple/timeit.py \ - build/pylib-apple/hmac.py \ - build/pylib-apple/tarfile.py \ - build/pylib-apple/stringprep.py \ - build/pylib-apple/typing.py \ - build/pylib-apple/ssl.py \ - build/pylib-apple/socket.py \ - build/pylib-apple/datetime.py \ - build/pylib-apple/sysconfig.py \ - build/pylib-apple/pathlib.py \ - build/pylib-apple/_pydecimal.py \ - build/pylib-apple/ntpath.py \ - build/pylib-apple/tokenize.py \ - build/pylib-apple/uuid.py \ - build/pylib-apple/imp.py \ - build/pylib-apple/smtpd.py \ - build/pylib-apple/re.py \ - build/pylib-apple/mailcap.py \ - build/pylib-apple/aifc.py \ - build/pylib-apple/struct.py \ - build/pylib-apple/asynchat.py \ - build/pylib-apple/sre_parse.py \ - build/pylib-apple/abc.py \ - build/pylib-apple/runpy.py \ + build/pylib-apple/__phello__.foo.py \ build/pylib-apple/_bootlocale.py \ - build/pylib-apple/encodings/mac_romanian.py \ - build/pylib-apple/encodings/mac_farsi.py \ - build/pylib-apple/encodings/idna.py \ - build/pylib-apple/encodings/cp273.py \ - build/pylib-apple/encodings/punycode.py \ - build/pylib-apple/encodings/raw_unicode_escape.py \ - build/pylib-apple/encodings/utf_8.py \ - build/pylib-apple/encodings/cp1252.py \ - build/pylib-apple/encodings/cp869.py \ - build/pylib-apple/encodings/iso8859_14.py \ - build/pylib-apple/encodings/iso8859_2.py \ - build/pylib-apple/encodings/mac_arabic.py \ - build/pylib-apple/encodings/mac_croatian.py \ - build/pylib-apple/encodings/big5hkscs.py \ - build/pylib-apple/encodings/cp1256.py \ - build/pylib-apple/encodings/iso8859_6.py \ - build/pylib-apple/encodings/iso8859_10.py \ - build/pylib-apple/encodings/iso2022_kr.py \ - build/pylib-apple/encodings/cp1140.py \ - build/pylib-apple/encodings/unicode_internal.py \ - build/pylib-apple/encodings/cp1125.py \ - build/pylib-apple/encodings/iso2022_jp_1.py \ - build/pylib-apple/encodings/cp1257.py \ - build/pylib-apple/encodings/cp949.py \ - build/pylib-apple/encodings/cp858.py \ - build/pylib-apple/encodings/iso8859_7.py \ - build/pylib-apple/encodings/iso8859_11.py \ - build/pylib-apple/encodings/hp_roman8.py \ - build/pylib-apple/encodings/koi8_r.py \ - build/pylib-apple/encodings/zlib_codec.py \ - build/pylib-apple/encodings/gbk.py \ - build/pylib-apple/encodings/johab.py \ - build/pylib-apple/encodings/cp1253.py \ - build/pylib-apple/encodings/iso8859_15.py \ - build/pylib-apple/encodings/iso2022_jp_2004.py \ - build/pylib-apple/encodings/mac_iceland.py \ - build/pylib-apple/encodings/iso8859_3.py \ - build/pylib-apple/encodings/mac_greek.py \ - build/pylib-apple/encodings/rot_13.py \ - build/pylib-apple/encodings/utf_16_be.py \ - build/pylib-apple/encodings/euc_kr.py \ - build/pylib-apple/encodings/mac_centeuro.py \ - build/pylib-apple/encodings/euc_jisx0213.py \ - build/pylib-apple/encodings/cp863.py \ - build/pylib-apple/encodings/ascii.py \ - build/pylib-apple/encodings/iso8859_8.py \ - build/pylib-apple/encodings/cp857.py \ - build/pylib-apple/encodings/utf_32_be.py \ - build/pylib-apple/encodings/cp1258.py \ - build/pylib-apple/encodings/oem.py \ - build/pylib-apple/encodings/mac_latin2.py \ - build/pylib-apple/encodings/cp775.py \ - build/pylib-apple/encodings/mac_roman.py \ - build/pylib-apple/encodings/__init__.py \ - build/pylib-apple/encodings/cp852.py \ - build/pylib-apple/encodings/shift_jisx0213.py \ - build/pylib-apple/encodings/cp866.py \ - build/pylib-apple/encodings/utf_7.py \ - build/pylib-apple/encodings/base64_codec.py \ - build/pylib-apple/encodings/cp932.py \ - build/pylib-apple/encodings/cp720.py \ - build/pylib-apple/encodings/cp862.py \ - build/pylib-apple/encodings/cp437.py \ - build/pylib-apple/encodings/palmos.py \ - build/pylib-apple/encodings/iso8859_9.py \ - build/pylib-apple/encodings/cp856.py \ - build/pylib-apple/encodings/aliases.py \ - build/pylib-apple/encodings/latin_1.py \ - build/pylib-apple/encodings/cp875.py \ - build/pylib-apple/encodings/cp950.py \ - build/pylib-apple/encodings/unicode_escape.py \ - build/pylib-apple/encodings/cp737.py \ - build/pylib-apple/encodings/cp865.py \ - build/pylib-apple/encodings/ptcp154.py \ - build/pylib-apple/encodings/big5.py \ - build/pylib-apple/encodings/cp424.py \ - build/pylib-apple/encodings/cp861.py \ - build/pylib-apple/encodings/euc_jp.py \ - build/pylib-apple/encodings/cp855.py \ - build/pylib-apple/encodings/shift_jis.py \ - build/pylib-apple/encodings/utf_32_le.py \ - build/pylib-apple/encodings/cp500.py \ - build/pylib-apple/encodings/undefined.py \ - build/pylib-apple/encodings/cp860.py \ - build/pylib-apple/encodings/uu_codec.py \ - build/pylib-apple/encodings/utf_16_le.py \ - build/pylib-apple/encodings/gb18030.py \ - build/pylib-apple/encodings/cp65001.py \ - build/pylib-apple/encodings/cp874.py \ - build/pylib-apple/encodings/cp850.py \ - build/pylib-apple/encodings/cp864.py \ - build/pylib-apple/encodings/utf_32.py \ - build/pylib-apple/encodings/koi8_u.py \ - build/pylib-apple/encodings/cp1254.py \ - build/pylib-apple/encodings/iso2022_jp_2.py \ - build/pylib-apple/encodings/utf_16.py \ - build/pylib-apple/encodings/iso8859_4.py \ - build/pylib-apple/encodings/euc_jis_2004.py \ - build/pylib-apple/encodings/mbcs.py \ - build/pylib-apple/encodings/cp1250.py \ - build/pylib-apple/encodings/gb2312.py \ - build/pylib-apple/encodings/iso8859_16.py \ - build/pylib-apple/encodings/mac_cyrillic.py \ - build/pylib-apple/encodings/hex_codec.py \ - build/pylib-apple/encodings/tis_620.py \ - build/pylib-apple/encodings/cp037.py \ - build/pylib-apple/encodings/cp1006.py \ - build/pylib-apple/encodings/cp1251.py \ - build/pylib-apple/encodings/mac_turkish.py \ - build/pylib-apple/encodings/iso2022_jp_ext.py \ - build/pylib-apple/encodings/iso8859_1.py \ - build/pylib-apple/encodings/hz.py \ - build/pylib-apple/encodings/bz2_codec.py \ - build/pylib-apple/encodings/quopri_codec.py \ - build/pylib-apple/encodings/kz1048.py \ - build/pylib-apple/encodings/utf_8_sig.py \ - build/pylib-apple/encodings/koi8_t.py \ - build/pylib-apple/encodings/cp1255.py \ - build/pylib-apple/encodings/iso2022_jp_3.py \ - build/pylib-apple/encodings/shift_jis_2004.py \ - build/pylib-apple/encodings/cp1026.py \ - build/pylib-apple/encodings/charmap.py \ - build/pylib-apple/encodings/iso8859_5.py \ - build/pylib-apple/encodings/iso8859_13.py \ - build/pylib-apple/encodings/iso2022_jp.py \ - build/pylib-apple/ctypes/_aix.py \ - build/pylib-apple/ctypes/wintypes.py \ - build/pylib-apple/ctypes/util.py \ - build/pylib-apple/ctypes/__init__.py \ - build/pylib-apple/ctypes/_endian.py \ - build/pylib-apple/ctypes/macholib/dyld.py \ - build/pylib-apple/ctypes/macholib/framework.py \ - build/pylib-apple/ctypes/macholib/__init__.py \ - build/pylib-apple/ctypes/macholib/dylib.py \ - build/pylib-apple/curses/textpad.py \ - build/pylib-apple/curses/ascii.py \ - build/pylib-apple/curses/__init__.py \ - build/pylib-apple/curses/has_key.py \ - build/pylib-apple/curses/panel.py \ - build/pylib-apple/urllib/error.py \ - build/pylib-apple/urllib/request.py \ - build/pylib-apple/urllib/__init__.py \ - build/pylib-apple/urllib/response.py \ - build/pylib-apple/urllib/robotparser.py \ - build/pylib-apple/urllib/parse.py \ - build/pylib-apple/html/__init__.py \ - build/pylib-apple/html/parser.py \ - build/pylib-apple/html/entities.py \ - build/pylib-apple/xml/__init__.py \ - build/pylib-apple/xml/parsers/expat.py \ - build/pylib-apple/xml/parsers/__init__.py \ - build/pylib-apple/xml/sax/handler.py \ - build/pylib-apple/xml/sax/__init__.py \ - build/pylib-apple/xml/sax/saxutils.py \ - build/pylib-apple/xml/sax/xmlreader.py \ - build/pylib-apple/xml/sax/expatreader.py \ - build/pylib-apple/xml/sax/_exceptions.py \ - build/pylib-apple/xml/dom/pulldom.py \ - build/pylib-apple/xml/dom/expatbuilder.py \ - build/pylib-apple/xml/dom/domreg.py \ - build/pylib-apple/xml/dom/minicompat.py \ - build/pylib-apple/xml/dom/__init__.py \ - build/pylib-apple/xml/dom/NodeFilter.py \ - build/pylib-apple/xml/dom/xmlbuilder.py \ - build/pylib-apple/xml/dom/minidom.py \ - build/pylib-apple/xml/etree/ElementPath.py \ - build/pylib-apple/xml/etree/cElementTree.py \ - build/pylib-apple/xml/etree/__init__.py \ - build/pylib-apple/xml/etree/ElementInclude.py \ - build/pylib-apple/xml/etree/ElementTree.py \ - build/pylib-apple/json/decoder.py \ - build/pylib-apple/json/scanner.py \ - build/pylib-apple/json/__init__.py \ - build/pylib-apple/json/encoder.py \ - build/pylib-apple/json/tool.py \ - build/pylib-apple/http/cookies.py \ - build/pylib-apple/http/server.py \ - build/pylib-apple/http/client.py \ - build/pylib-apple/http/__init__.py \ - build/pylib-apple/http/cookiejar.py \ - build/pylib-apple/sqlite3/__init__.py \ - build/pylib-apple/sqlite3/dump.py \ - build/pylib-apple/sqlite3/dbapi2.py \ - build/pylib-apple/concurrent/__init__.py \ - build/pylib-apple/concurrent/futures/_base.py \ - build/pylib-apple/concurrent/futures/thread.py \ - build/pylib-apple/concurrent/futures/__init__.py \ - build/pylib-apple/concurrent/futures/process.py \ - build/pylib-apple/importlib/util.py \ - build/pylib-apple/importlib/_bootstrap.py \ - build/pylib-apple/importlib/__init__.py \ - build/pylib-apple/importlib/_bootstrap_external.py \ - build/pylib-apple/importlib/resources.py \ - build/pylib-apple/importlib/machinery.py \ - build/pylib-apple/importlib/abc.py \ - build/pylib-apple/xmlrpc/server.py \ - build/pylib-apple/xmlrpc/client.py \ - build/pylib-apple/xmlrpc/__init__.py \ + build/pylib-apple/_collections_abc.py \ + build/pylib-apple/_compat_pickle.py \ + build/pylib-apple/_compression.py \ + build/pylib-apple/_dummy_thread.py \ + build/pylib-apple/_markupbase.py \ + build/pylib-apple/_osx_support.py \ + build/pylib-apple/_py_abc.py \ + build/pylib-apple/_pydecimal.py \ + build/pylib-apple/_pyio.py \ + build/pylib-apple/_sitebuiltins.py \ + build/pylib-apple/_strptime.py \ + build/pylib-apple/_threading_local.py \ + build/pylib-apple/_weakrefset.py \ + build/pylib-apple/abc.py \ + build/pylib-apple/aifc.py \ + build/pylib-apple/antigravity.py \ + build/pylib-apple/argparse.py \ + build/pylib-apple/ast.py \ + build/pylib-apple/asynchat.py \ + build/pylib-apple/asyncio/__init__.py \ + build/pylib-apple/asyncio/base_events.py \ + build/pylib-apple/asyncio/base_futures.py \ + build/pylib-apple/asyncio/base_subprocess.py \ + build/pylib-apple/asyncio/base_tasks.py \ + build/pylib-apple/asyncio/constants.py \ + build/pylib-apple/asyncio/coroutines.py \ + build/pylib-apple/asyncio/events.py \ + build/pylib-apple/asyncio/format_helpers.py \ + build/pylib-apple/asyncio/futures.py \ + build/pylib-apple/asyncio/locks.py \ + build/pylib-apple/asyncio/log.py \ + build/pylib-apple/asyncio/proactor_events.py \ + build/pylib-apple/asyncio/protocols.py \ + build/pylib-apple/asyncio/queues.py \ + build/pylib-apple/asyncio/runners.py \ + build/pylib-apple/asyncio/selector_events.py \ + build/pylib-apple/asyncio/sslproto.py \ + build/pylib-apple/asyncio/streams.py \ + build/pylib-apple/asyncio/subprocess.py \ + build/pylib-apple/asyncio/tasks.py \ + build/pylib-apple/asyncio/transports.py \ + build/pylib-apple/asyncio/unix_events.py \ + build/pylib-apple/asyncio/windows_events.py \ + build/pylib-apple/asyncio/windows_utils.py \ + build/pylib-apple/asyncore.py \ + build/pylib-apple/base64.py \ + build/pylib-apple/bdb.py \ + build/pylib-apple/binhex.py \ + build/pylib-apple/bisect.py \ + build/pylib-apple/bz2.py \ + build/pylib-apple/cProfile.py \ + build/pylib-apple/calendar.py \ + build/pylib-apple/cgi.py \ + build/pylib-apple/cgitb.py \ + build/pylib-apple/chunk.py \ + build/pylib-apple/cmd.py \ + build/pylib-apple/code.py \ + build/pylib-apple/codecs.py \ + build/pylib-apple/codeop.py \ build/pylib-apple/collections/__init__.py \ build/pylib-apple/collections/abc.py \ - build/pylib-apple/asyncio/queues.py \ - build/pylib-apple/asyncio/streams.py \ - build/pylib-apple/asyncio/tasks.py \ - build/pylib-apple/asyncio/selector_events.py \ - build/pylib-apple/asyncio/log.py \ - build/pylib-apple/asyncio/protocols.py \ - build/pylib-apple/asyncio/events.py \ - build/pylib-apple/asyncio/base_events.py \ - build/pylib-apple/asyncio/subprocess.py \ - build/pylib-apple/asyncio/constants.py \ - build/pylib-apple/asyncio/proactor_events.py \ - build/pylib-apple/asyncio/format_helpers.py \ - build/pylib-apple/asyncio/locks.py \ - build/pylib-apple/asyncio/__init__.py \ - build/pylib-apple/asyncio/futures.py \ - build/pylib-apple/asyncio/sslproto.py \ - build/pylib-apple/asyncio/base_subprocess.py \ - build/pylib-apple/asyncio/windows_utils.py \ - build/pylib-apple/asyncio/runners.py \ - build/pylib-apple/asyncio/transports.py \ - build/pylib-apple/asyncio/base_tasks.py \ - build/pylib-apple/asyncio/coroutines.py \ - build/pylib-apple/asyncio/windows_events.py \ - build/pylib-apple/asyncio/base_futures.py \ - build/pylib-apple/asyncio/unix_events.py \ - build/pylib-apple/logging/config.py \ - build/pylib-apple/logging/handlers.py \ - build/pylib-apple/logging/__init__.py \ - build/pylib-apple/email/contentmanager.py \ - build/pylib-apple/email/_policybase.py \ - build/pylib-apple/email/header.py \ + build/pylib-apple/colorsys.py \ + build/pylib-apple/compileall.py \ + build/pylib-apple/concurrent/__init__.py \ + build/pylib-apple/concurrent/futures/__init__.py \ + build/pylib-apple/concurrent/futures/_base.py \ + build/pylib-apple/concurrent/futures/process.py \ + build/pylib-apple/concurrent/futures/thread.py \ + build/pylib-apple/configparser.py \ + build/pylib-apple/contextlib.py \ + build/pylib-apple/contextvars.py \ + build/pylib-apple/copy.py \ + build/pylib-apple/copyreg.py \ + build/pylib-apple/crypt.py \ + build/pylib-apple/csv.py \ + build/pylib-apple/ctypes/__init__.py \ + build/pylib-apple/ctypes/_aix.py \ + build/pylib-apple/ctypes/_endian.py \ + build/pylib-apple/ctypes/macholib/__init__.py \ + build/pylib-apple/ctypes/macholib/dyld.py \ + build/pylib-apple/ctypes/macholib/dylib.py \ + build/pylib-apple/ctypes/macholib/framework.py \ + build/pylib-apple/ctypes/util.py \ + build/pylib-apple/ctypes/wintypes.py \ + build/pylib-apple/curses/__init__.py \ + build/pylib-apple/curses/ascii.py \ + build/pylib-apple/curses/has_key.py \ + build/pylib-apple/curses/panel.py \ + build/pylib-apple/curses/textpad.py \ + build/pylib-apple/dataclasses.py \ + build/pylib-apple/datetime.py \ + build/pylib-apple/decimal.py \ + build/pylib-apple/difflib.py \ + build/pylib-apple/dis.py \ + build/pylib-apple/doctest.py \ + build/pylib-apple/dummy_threading.py \ + build/pylib-apple/email/__init__.py \ build/pylib-apple/email/_encoded_words.py \ build/pylib-apple/email/_header_value_parser.py \ - build/pylib-apple/email/policy.py \ - build/pylib-apple/email/__init__.py \ - build/pylib-apple/email/message.py \ - build/pylib-apple/email/encoders.py \ - build/pylib-apple/email/parser.py \ - build/pylib-apple/email/generator.py \ - build/pylib-apple/email/utils.py \ + build/pylib-apple/email/_parseaddr.py \ + build/pylib-apple/email/_policybase.py \ + build/pylib-apple/email/base64mime.py \ build/pylib-apple/email/charset.py \ - build/pylib-apple/email/iterators.py \ - build/pylib-apple/email/quoprimime.py \ + build/pylib-apple/email/contentmanager.py \ + build/pylib-apple/email/encoders.py \ build/pylib-apple/email/errors.py \ build/pylib-apple/email/feedparser.py \ - build/pylib-apple/email/_parseaddr.py \ - build/pylib-apple/email/base64mime.py \ + build/pylib-apple/email/generator.py \ + build/pylib-apple/email/header.py \ build/pylib-apple/email/headerregistry.py \ - build/pylib-apple/email/mime/multipart.py \ + build/pylib-apple/email/iterators.py \ + build/pylib-apple/email/message.py \ build/pylib-apple/email/mime/__init__.py \ - build/pylib-apple/email/mime/message.py \ build/pylib-apple/email/mime/application.py \ + build/pylib-apple/email/mime/audio.py \ + build/pylib-apple/email/mime/base.py \ + build/pylib-apple/email/mime/image.py \ + build/pylib-apple/email/mime/message.py \ + build/pylib-apple/email/mime/multipart.py \ build/pylib-apple/email/mime/nonmultipart.py \ build/pylib-apple/email/mime/text.py \ - build/pylib-apple/email/mime/audio.py \ - build/pylib-apple/email/mime/image.py \ - build/pylib-apple/email/mime/base.py + build/pylib-apple/email/parser.py \ + build/pylib-apple/email/policy.py \ + build/pylib-apple/email/quoprimime.py \ + build/pylib-apple/email/utils.py \ + build/pylib-apple/encodings/__init__.py \ + build/pylib-apple/encodings/aliases.py \ + build/pylib-apple/encodings/ascii.py \ + build/pylib-apple/encodings/base64_codec.py \ + build/pylib-apple/encodings/big5.py \ + build/pylib-apple/encodings/big5hkscs.py \ + build/pylib-apple/encodings/bz2_codec.py \ + build/pylib-apple/encodings/charmap.py \ + build/pylib-apple/encodings/cp037.py \ + build/pylib-apple/encodings/cp1006.py \ + build/pylib-apple/encodings/cp1026.py \ + build/pylib-apple/encodings/cp1125.py \ + build/pylib-apple/encodings/cp1140.py \ + build/pylib-apple/encodings/cp1250.py \ + build/pylib-apple/encodings/cp1251.py \ + build/pylib-apple/encodings/cp1252.py \ + build/pylib-apple/encodings/cp1253.py \ + build/pylib-apple/encodings/cp1254.py \ + build/pylib-apple/encodings/cp1255.py \ + build/pylib-apple/encodings/cp1256.py \ + build/pylib-apple/encodings/cp1257.py \ + build/pylib-apple/encodings/cp1258.py \ + build/pylib-apple/encodings/cp273.py \ + build/pylib-apple/encodings/cp424.py \ + build/pylib-apple/encodings/cp437.py \ + build/pylib-apple/encodings/cp500.py \ + build/pylib-apple/encodings/cp65001.py \ + build/pylib-apple/encodings/cp720.py \ + build/pylib-apple/encodings/cp737.py \ + build/pylib-apple/encodings/cp775.py \ + build/pylib-apple/encodings/cp850.py \ + build/pylib-apple/encodings/cp852.py \ + build/pylib-apple/encodings/cp855.py \ + build/pylib-apple/encodings/cp856.py \ + build/pylib-apple/encodings/cp857.py \ + build/pylib-apple/encodings/cp858.py \ + build/pylib-apple/encodings/cp860.py \ + build/pylib-apple/encodings/cp861.py \ + build/pylib-apple/encodings/cp862.py \ + build/pylib-apple/encodings/cp863.py \ + build/pylib-apple/encodings/cp864.py \ + build/pylib-apple/encodings/cp865.py \ + build/pylib-apple/encodings/cp866.py \ + build/pylib-apple/encodings/cp869.py \ + build/pylib-apple/encodings/cp874.py \ + build/pylib-apple/encodings/cp875.py \ + build/pylib-apple/encodings/cp932.py \ + build/pylib-apple/encodings/cp949.py \ + build/pylib-apple/encodings/cp950.py \ + build/pylib-apple/encodings/euc_jis_2004.py \ + build/pylib-apple/encodings/euc_jisx0213.py \ + build/pylib-apple/encodings/euc_jp.py \ + build/pylib-apple/encodings/euc_kr.py \ + build/pylib-apple/encodings/gb18030.py \ + build/pylib-apple/encodings/gb2312.py \ + build/pylib-apple/encodings/gbk.py \ + build/pylib-apple/encodings/hex_codec.py \ + build/pylib-apple/encodings/hp_roman8.py \ + build/pylib-apple/encodings/hz.py \ + build/pylib-apple/encodings/idna.py \ + build/pylib-apple/encodings/iso2022_jp.py \ + build/pylib-apple/encodings/iso2022_jp_1.py \ + build/pylib-apple/encodings/iso2022_jp_2.py \ + build/pylib-apple/encodings/iso2022_jp_2004.py \ + build/pylib-apple/encodings/iso2022_jp_3.py \ + build/pylib-apple/encodings/iso2022_jp_ext.py \ + build/pylib-apple/encodings/iso2022_kr.py \ + build/pylib-apple/encodings/iso8859_1.py \ + build/pylib-apple/encodings/iso8859_10.py \ + build/pylib-apple/encodings/iso8859_11.py \ + build/pylib-apple/encodings/iso8859_13.py \ + build/pylib-apple/encodings/iso8859_14.py \ + build/pylib-apple/encodings/iso8859_15.py \ + build/pylib-apple/encodings/iso8859_16.py \ + build/pylib-apple/encodings/iso8859_2.py \ + build/pylib-apple/encodings/iso8859_3.py \ + build/pylib-apple/encodings/iso8859_4.py \ + build/pylib-apple/encodings/iso8859_5.py \ + build/pylib-apple/encodings/iso8859_6.py \ + build/pylib-apple/encodings/iso8859_7.py \ + build/pylib-apple/encodings/iso8859_8.py \ + build/pylib-apple/encodings/iso8859_9.py \ + build/pylib-apple/encodings/johab.py \ + build/pylib-apple/encodings/koi8_r.py \ + build/pylib-apple/encodings/koi8_t.py \ + build/pylib-apple/encodings/koi8_u.py \ + build/pylib-apple/encodings/kz1048.py \ + build/pylib-apple/encodings/latin_1.py \ + build/pylib-apple/encodings/mac_arabic.py \ + build/pylib-apple/encodings/mac_centeuro.py \ + build/pylib-apple/encodings/mac_croatian.py \ + build/pylib-apple/encodings/mac_cyrillic.py \ + build/pylib-apple/encodings/mac_farsi.py \ + build/pylib-apple/encodings/mac_greek.py \ + build/pylib-apple/encodings/mac_iceland.py \ + build/pylib-apple/encodings/mac_latin2.py \ + build/pylib-apple/encodings/mac_roman.py \ + build/pylib-apple/encodings/mac_romanian.py \ + build/pylib-apple/encodings/mac_turkish.py \ + build/pylib-apple/encodings/mbcs.py \ + build/pylib-apple/encodings/oem.py \ + build/pylib-apple/encodings/palmos.py \ + build/pylib-apple/encodings/ptcp154.py \ + build/pylib-apple/encodings/punycode.py \ + build/pylib-apple/encodings/quopri_codec.py \ + build/pylib-apple/encodings/raw_unicode_escape.py \ + build/pylib-apple/encodings/rot_13.py \ + build/pylib-apple/encodings/shift_jis.py \ + build/pylib-apple/encodings/shift_jis_2004.py \ + build/pylib-apple/encodings/shift_jisx0213.py \ + build/pylib-apple/encodings/tis_620.py \ + build/pylib-apple/encodings/undefined.py \ + build/pylib-apple/encodings/unicode_escape.py \ + build/pylib-apple/encodings/unicode_internal.py \ + build/pylib-apple/encodings/utf_16.py \ + build/pylib-apple/encodings/utf_16_be.py \ + build/pylib-apple/encodings/utf_16_le.py \ + build/pylib-apple/encodings/utf_32.py \ + build/pylib-apple/encodings/utf_32_be.py \ + build/pylib-apple/encodings/utf_32_le.py \ + build/pylib-apple/encodings/utf_7.py \ + build/pylib-apple/encodings/utf_8.py \ + build/pylib-apple/encodings/utf_8_sig.py \ + build/pylib-apple/encodings/uu_codec.py \ + build/pylib-apple/encodings/zlib_codec.py \ + build/pylib-apple/enum.py \ + build/pylib-apple/filecmp.py \ + build/pylib-apple/fileinput.py \ + build/pylib-apple/fnmatch.py \ + build/pylib-apple/formatter.py \ + build/pylib-apple/fractions.py \ + build/pylib-apple/ftplib.py \ + build/pylib-apple/functools.py \ + build/pylib-apple/genericpath.py \ + build/pylib-apple/getopt.py \ + build/pylib-apple/getpass.py \ + build/pylib-apple/gettext.py \ + build/pylib-apple/glob.py \ + build/pylib-apple/gzip.py \ + build/pylib-apple/hashlib.py \ + build/pylib-apple/heapq.py \ + build/pylib-apple/hmac.py \ + build/pylib-apple/html/__init__.py \ + build/pylib-apple/html/entities.py \ + build/pylib-apple/html/parser.py \ + build/pylib-apple/http/__init__.py \ + build/pylib-apple/http/client.py \ + build/pylib-apple/http/cookiejar.py \ + build/pylib-apple/http/cookies.py \ + build/pylib-apple/http/server.py \ + build/pylib-apple/imghdr.py \ + build/pylib-apple/imp.py \ + build/pylib-apple/importlib/__init__.py \ + build/pylib-apple/importlib/_bootstrap.py \ + build/pylib-apple/importlib/_bootstrap_external.py \ + build/pylib-apple/importlib/abc.py \ + build/pylib-apple/importlib/machinery.py \ + build/pylib-apple/importlib/resources.py \ + build/pylib-apple/importlib/util.py \ + build/pylib-apple/inspect.py \ + build/pylib-apple/io.py \ + build/pylib-apple/ipaddress.py \ + build/pylib-apple/json/__init__.py \ + build/pylib-apple/json/decoder.py \ + build/pylib-apple/json/encoder.py \ + build/pylib-apple/json/scanner.py \ + build/pylib-apple/json/tool.py \ + build/pylib-apple/keyword.py \ + build/pylib-apple/linecache.py \ + build/pylib-apple/locale.py \ + build/pylib-apple/logging/__init__.py \ + build/pylib-apple/logging/config.py \ + build/pylib-apple/logging/handlers.py \ + build/pylib-apple/lzma.py \ + build/pylib-apple/macpath.py \ + build/pylib-apple/mailbox.py \ + build/pylib-apple/mailcap.py \ + build/pylib-apple/mimetypes.py \ + build/pylib-apple/modulefinder.py \ + build/pylib-apple/netrc.py \ + build/pylib-apple/nntplib.py \ + build/pylib-apple/ntpath.py \ + build/pylib-apple/nturl2path.py \ + build/pylib-apple/numbers.py \ + build/pylib-apple/opcode.py \ + build/pylib-apple/operator.py \ + build/pylib-apple/optparse.py \ + build/pylib-apple/os.py \ + build/pylib-apple/pathlib.py \ + build/pylib-apple/pdb.py \ + build/pylib-apple/pickle.py \ + build/pylib-apple/pickletools.py \ + build/pylib-apple/pipes.py \ + build/pylib-apple/pkgutil.py \ + build/pylib-apple/platform.py \ + build/pylib-apple/plistlib.py \ + build/pylib-apple/poplib.py \ + build/pylib-apple/posixpath.py \ + build/pylib-apple/pprint.py \ + build/pylib-apple/profile.py \ + build/pylib-apple/pstats.py \ + build/pylib-apple/pty.py \ + build/pylib-apple/py_compile.py \ + build/pylib-apple/pyclbr.py \ + build/pylib-apple/pydoc.py \ + build/pylib-apple/queue.py \ + build/pylib-apple/quopri.py \ + build/pylib-apple/random.py \ + build/pylib-apple/re.py \ + build/pylib-apple/reprlib.py \ + build/pylib-apple/rlcompleter.py \ + build/pylib-apple/runpy.py \ + build/pylib-apple/sched.py \ + build/pylib-apple/secrets.py \ + build/pylib-apple/selectors.py \ + build/pylib-apple/shelve.py \ + build/pylib-apple/shlex.py \ + build/pylib-apple/shutil.py \ + build/pylib-apple/signal.py \ + build/pylib-apple/site.py \ + build/pylib-apple/smtpd.py \ + build/pylib-apple/smtplib.py \ + build/pylib-apple/sndhdr.py \ + build/pylib-apple/socket.py \ + build/pylib-apple/socketserver.py \ + build/pylib-apple/sqlite3/__init__.py \ + build/pylib-apple/sqlite3/dbapi2.py \ + build/pylib-apple/sqlite3/dump.py \ + build/pylib-apple/sre_compile.py \ + build/pylib-apple/sre_constants.py \ + build/pylib-apple/sre_parse.py \ + build/pylib-apple/ssl.py \ + build/pylib-apple/stat.py \ + build/pylib-apple/statistics.py \ + build/pylib-apple/string.py \ + build/pylib-apple/stringprep.py \ + build/pylib-apple/struct.py \ + build/pylib-apple/subprocess.py \ + build/pylib-apple/sunau.py \ + build/pylib-apple/symbol.py \ + build/pylib-apple/symtable.py \ + build/pylib-apple/sysconfig.py \ + build/pylib-apple/tabnanny.py \ + build/pylib-apple/tarfile.py \ + build/pylib-apple/telnetlib.py \ + build/pylib-apple/tempfile.py \ + build/pylib-apple/textwrap.py \ + build/pylib-apple/this.py \ + build/pylib-apple/threading.py \ + build/pylib-apple/timeit.py \ + build/pylib-apple/token.py \ + build/pylib-apple/tokenize.py \ + build/pylib-apple/trace.py \ + build/pylib-apple/traceback.py \ + build/pylib-apple/tracemalloc.py \ + build/pylib-apple/tty.py \ + build/pylib-apple/types.py \ + build/pylib-apple/typing.py \ + build/pylib-apple/urllib/__init__.py \ + build/pylib-apple/urllib/error.py \ + build/pylib-apple/urllib/parse.py \ + build/pylib-apple/urllib/request.py \ + build/pylib-apple/urllib/response.py \ + build/pylib-apple/urllib/robotparser.py \ + build/pylib-apple/uu.py \ + build/pylib-apple/uuid.py \ + build/pylib-apple/warnings.py \ + build/pylib-apple/wave.py \ + build/pylib-apple/weakref.py \ + build/pylib-apple/webbrowser.py \ + build/pylib-apple/xdrlib.py \ + build/pylib-apple/xml/__init__.py \ + build/pylib-apple/xml/dom/NodeFilter.py \ + build/pylib-apple/xml/dom/__init__.py \ + build/pylib-apple/xml/dom/domreg.py \ + build/pylib-apple/xml/dom/expatbuilder.py \ + build/pylib-apple/xml/dom/minicompat.py \ + build/pylib-apple/xml/dom/minidom.py \ + build/pylib-apple/xml/dom/pulldom.py \ + build/pylib-apple/xml/dom/xmlbuilder.py \ + build/pylib-apple/xml/etree/ElementInclude.py \ + build/pylib-apple/xml/etree/ElementPath.py \ + build/pylib-apple/xml/etree/ElementTree.py \ + build/pylib-apple/xml/etree/__init__.py \ + build/pylib-apple/xml/etree/cElementTree.py \ + build/pylib-apple/xml/parsers/__init__.py \ + build/pylib-apple/xml/parsers/expat.py \ + build/pylib-apple/xml/sax/__init__.py \ + build/pylib-apple/xml/sax/_exceptions.py \ + build/pylib-apple/xml/sax/expatreader.py \ + build/pylib-apple/xml/sax/handler.py \ + build/pylib-apple/xml/sax/saxutils.py \ + build/pylib-apple/xml/sax/xmlreader.py \ + build/pylib-apple/xmlrpc/__init__.py \ + build/pylib-apple/xmlrpc/client.py \ + build/pylib-apple/xmlrpc/server.py \ + build/pylib-apple/zipapp.py \ + build/pylib-apple/zipfile.py SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ - build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ - build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc \ - build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc \ + build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc + build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc \ + build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc \ + build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc \ + build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ + build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc \ + build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc \ + build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc \ + build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc \ + build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc \ + build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ + build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ + build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ + build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -2767,58 +2767,8 @@ $(SCRIPT_TARGETS_PY_PRIVATE_APPLE) : ../.efrocachemap # just generating explicit targets for each. Could perhaps look into using a # fancy for-loop instead, but perhaps listing these explicitly isn't so bad. -build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/pylib-apple/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/pylib-apple/queue.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/pylib-apple/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/pylib-apple/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/pylib-apple/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/pylib-apple/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/pylib-apple/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncore.py +build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc: \ + build/pylib-apple/__future__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -2827,613 +2777,8 @@ build/pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/pylib-apple/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/pylib-apple/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/pylib-apple/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/pylib-apple/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/pylib-apple/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/pylib-apple/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/pylib-apple/trace.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/pylib-apple/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/pylib-apple/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/pylib-apple/dis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/pylib-apple/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/pylib-apple/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/pylib-apple/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/pylib-apple/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/pylib-apple/tty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/pylib-apple/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ - build/pylib-apple/token.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/pylib-apple/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/pylib-apple/base64.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/pylib-apple/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/pylib-apple/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/pylib-apple/signal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/pylib-apple/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/pylib-apple/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/pylib-apple/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/pylib-apple/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/pylib-apple/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/pylib-apple/wave.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/pylib-apple/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/pylib-apple/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/pylib-apple/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/pylib-apple/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/pylib-apple/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/pylib-apple/functools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/pylib-apple/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/pylib-apple/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/pylib-apple/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/pylib-apple/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/pylib-apple/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/pylib-apple/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/pylib-apple/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/pylib-apple/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/pylib-apple/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-apple/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/pylib-apple/profile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/pylib-apple/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ - build/pylib-apple/this.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/pylib-apple/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/pylib-apple/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/pylib-apple/uu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/pylib-apple/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ - build/pylib-apple/io.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ - build/pylib-apple/code.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/pylib-apple/operator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/pylib-apple/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ - build/pylib-apple/os.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/pylib-apple/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/pylib-apple/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/pylib-apple/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/pylib-apple/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/pylib-apple/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/pylib-apple/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/pylib-apple/copy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/pylib-apple/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ - build/pylib-apple/types.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/pylib-apple/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/pylib-apple/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/pylib-apple/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/pylib-apple/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/pylib-apple/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/pylib-apple/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ - build/pylib-apple/random.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/pylib-apple/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/pylib-apple/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/pylib-apple/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/pylib-apple/threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/pylib-apple/platform.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/pylib-apple/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/pylib-apple/glob.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/pylib-apple/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/pylib-apple/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/pylib-apple/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/pylib-apple/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/pylib-apple/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/pylib-apple/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/pylib-apple/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/pylib-apple/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ - build/pylib-apple/site.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/pylib-apple/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/pylib-apple/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/pylib-apple/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/pylib-apple/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/pylib-apple/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/pylib-apple/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/pylib-apple/stat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/pylib-apple/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/pylib-apple/csv.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/pylib-apple/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/pylib-apple/sched.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/pylib-apple/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/pylib-apple/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/pylib-apple/locale.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/pylib-apple/ast.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/pylib-apple/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/pylib-apple/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/pylib-apple/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/pylib-apple/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/pylib-apple/pty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/pylib-apple/statistics.py +build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ + build/pylib-apple/_bootlocale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -3442,98 +2787,33 @@ build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/pylib-apple/sunau.py +build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ + build/pylib-apple/_compat_pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/pylib-apple/__future__.py +build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc: \ + build/pylib-apple/_compression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/pylib-apple/dataclasses.py +build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ + build/pylib-apple/_dummy_thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/pylib-apple/shelve.py +build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ + build/pylib-apple/_markupbase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ - build/pylib-apple/string.py +build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ + build/pylib-apple/_osx_support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/pylib-apple/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/pylib-apple/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/pylib-apple/enum.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/pylib-apple/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/pylib-apple/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/pylib-apple/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/pylib-apple/typing.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/pylib-apple/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/pylib-apple/socket.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/pylib-apple/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/pylib-apple/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/pathlib.py +build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ + build/pylib-apple/_py_abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -3542,58 +2822,28 @@ build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/ntpath.py +build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc: \ + build/pylib-apple/_pyio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/pylib-apple/tokenize.py +build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ + build/pylib-apple/_sitebuiltins.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/pylib-apple/uuid.py +build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc: \ + build/pylib-apple/_strptime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/pylib-apple/imp.py +build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ + build/pylib-apple/_threading_local.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/pylib-apple/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ - build/pylib-apple/re.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/pylib-apple/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/pylib-apple/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/pylib-apple/struct.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/pylib-apple/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/pylib-apple/sre_parse.py +build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ + build/pylib-apple/_weakrefset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -3602,2157 +2852,2907 @@ build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/pylib-apple/runpy.py +build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc: \ + build/pylib-apple/aifc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/pylib-apple/_bootlocale.py +build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc: \ + build/pylib-apple/antigravity.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_romanian.py +build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc: \ + build/pylib-apple/argparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_farsi.py +build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc: \ + build/pylib-apple/ast.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/idna.py +build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc: \ + build/pylib-apple/asynchat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp273.py +build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/punycode.py +build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/base_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/raw_unicode_escape.py +build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/base_futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_8.py +build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/base_subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1252.py +build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/base_tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp869.py +build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_14.py +build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/coroutines.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_2.py +build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_arabic.py +build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/format_helpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_croatian.py +build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/big5hkscs.py +build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/locks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1256.py +build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_6.py +build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/proactor_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_10.py +build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/protocols.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_kr.py +build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1140.py +build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/runners.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/unicode_internal.py +build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/selector_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1125.py +build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/sslproto.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_1.py +build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/streams.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1257.py +build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp949.py +build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp858.py +build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/transports.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_7.py +build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/unix_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_11.py +build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/windows_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/hp_roman8.py +build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncio/windows_utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/koi8_r.py +build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ + build/pylib-apple/asyncore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/zlib_codec.py +build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ + build/pylib-apple/base64.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/gbk.py +build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ + build/pylib-apple/bdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/johab.py +build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ + build/pylib-apple/binhex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1253.py +build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ + build/pylib-apple/bisect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_15.py +build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ + build/pylib-apple/bz2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_2004.py +build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ + build/pylib-apple/cProfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_iceland.py +build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ + build/pylib-apple/calendar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_3.py +build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ + build/pylib-apple/cgi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_greek.py +build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ + build/pylib-apple/cgitb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/rot_13.py +build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ + build/pylib-apple/chunk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_16_be.py +build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ + build/pylib-apple/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_kr.py +build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ + build/pylib-apple/code.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_centeuro.py +build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ + build/pylib-apple/codecs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_jisx0213.py +build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ + build/pylib-apple/codeop.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp863.py +build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ + build/pylib-apple/collections/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/ascii.py +build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ + build/pylib-apple/collections/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_8.py +build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ + build/pylib-apple/colorsys.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp857.py +build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ + build/pylib-apple/compileall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_32_be.py +build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ + build/pylib-apple/concurrent/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1258.py +build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/concurrent/futures/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/oem.py +build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ + build/pylib-apple/concurrent/futures/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_latin2.py +build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ + build/pylib-apple/concurrent/futures/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp775.py +build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ + build/pylib-apple/concurrent/futures/thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_roman.py +build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ + build/pylib-apple/configparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/__init__.py +build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ + build/pylib-apple/contextlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp852.py +build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ + build/pylib-apple/contextvars.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/shift_jisx0213.py +build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ + build/pylib-apple/copy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp866.py +build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ + build/pylib-apple/copyreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_7.py +build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ + build/pylib-apple/crypt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/base64_codec.py +build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ + build/pylib-apple/csv.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/ptcp154.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_8_sig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/koi8_t.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1026.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/charmap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_5.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_13.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/_aix.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ + build/pylib-apple/ctypes/_aix.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_endian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ + build/pylib-apple/ctypes/macholib/dyld.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dylib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/textpad.py +build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ + build/pylib-apple/ctypes/macholib/framework.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/ascii.py +build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ + build/pylib-apple/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ + build/pylib-apple/ctypes/wintypes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ + build/pylib-apple/curses/ascii.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/error.py +build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ + build/pylib-apple/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/request.py +build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ + build/pylib-apple/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/__init__.py +build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/response.py +build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ + build/pylib-apple/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/robotparser.py +build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ + build/pylib-apple/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/parse.py +build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ + build/pylib-apple/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ + build/pylib-apple/doctest.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ + build/pylib-apple/dummy_threading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/_encoded_words.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/_header_value_parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/_parseaddr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/_policybase.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/base64mime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/charset.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/contentmanager.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/encoders.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/errors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/feedparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/generator.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/header.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/headerregistry.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/iterators.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/application.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/audio.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/image.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/multipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/nonmultipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/mime/text.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/policy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/quoprimime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ + build/pylib-apple/email/utils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/aliases.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/ascii.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/base64_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/big5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/big5hkscs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/bz2_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/charmap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp037.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1006.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1026.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1125.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1140.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1250.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1251.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1252.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1253.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1254.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1255.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1256.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1257.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp1258.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp273.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp424.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp437.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp500.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp65001.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp720.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp737.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp775.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp850.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp852.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp855.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp856.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp857.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp858.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp860.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp861.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp862.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp863.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp864.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp865.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp866.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp869.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp874.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp875.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp932.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp949.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/cp950.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/euc_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/euc_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/euc_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/euc_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/gb18030.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/gb2312.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/gbk.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/hex_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/hp_roman8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/hz.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/idna.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_jp_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_jp_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_jp_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_jp_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_jp_ext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso2022_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_10.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_11.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_14.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_15.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_4.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_6.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_7.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/iso8859_9.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/johab.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/koi8_r.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/koi8_t.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/koi8_u.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/kz1048.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/latin_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_arabic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_centeuro.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_croatian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_cyrillic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_farsi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_greek.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_iceland.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_latin2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_roman.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_romanian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mac_turkish.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/mbcs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/oem.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/palmos.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/ptcp154.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/punycode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/quopri_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/raw_unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/rot_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/shift_jis.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/shift_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/shift_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/tis_620.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/undefined.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/unicode_internal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_16_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_16_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_32.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_32_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_32_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_7.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/utf_8_sig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/uu_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ + build/pylib-apple/encodings/zlib_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ + build/pylib-apple/enum.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ + build/pylib-apple/filecmp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ + build/pylib-apple/fileinput.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ + build/pylib-apple/fnmatch.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ + build/pylib-apple/formatter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ + build/pylib-apple/fractions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ + build/pylib-apple/ftplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ + build/pylib-apple/functools.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ + build/pylib-apple/genericpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ + build/pylib-apple/getopt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ + build/pylib-apple/getpass.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ + build/pylib-apple/gettext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ + build/pylib-apple/glob.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ + build/pylib-apple/gzip.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ + build/pylib-apple/hashlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ + build/pylib-apple/heapq.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ + build/pylib-apple/hmac.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-apple/html/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-apple/html/parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-apple/html/entities.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ + build/pylib-apple/html/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ + build/pylib-apple/http/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ + build/pylib-apple/http/client.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ + build/pylib-apple/http/cookiejar.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ + build/pylib-apple/http/cookies.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ + build/pylib-apple/http/server.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ + build/pylib-apple/imghdr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ + build/pylib-apple/imp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/_bootstrap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/_bootstrap_external.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/abc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/machinery.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/resources.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ + build/pylib-apple/importlib/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ + build/pylib-apple/inspect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ + build/pylib-apple/io.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ + build/pylib-apple/ipaddress.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ + build/pylib-apple/json/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ + build/pylib-apple/json/decoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ + build/pylib-apple/json/encoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ + build/pylib-apple/json/scanner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ + build/pylib-apple/json/tool.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ + build/pylib-apple/keyword.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ + build/pylib-apple/linecache.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ + build/pylib-apple/locale.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ + build/pylib-apple/logging/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ + build/pylib-apple/logging/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ + build/pylib-apple/logging/handlers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ + build/pylib-apple/lzma.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ + build/pylib-apple/macpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ + build/pylib-apple/mailbox.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ + build/pylib-apple/mailcap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ + build/pylib-apple/mimetypes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ + build/pylib-apple/modulefinder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ + build/pylib-apple/netrc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ + build/pylib-apple/nntplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ + build/pylib-apple/ntpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ + build/pylib-apple/nturl2path.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ + build/pylib-apple/numbers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ + build/pylib-apple/opcode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ + build/pylib-apple/operator.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ + build/pylib-apple/optparse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ + build/pylib-apple/os.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ + build/pylib-apple/pathlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ + build/pylib-apple/pdb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ + build/pylib-apple/pickle.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ + build/pylib-apple/pickletools.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ + build/pylib-apple/pipes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ + build/pylib-apple/pkgutil.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ + build/pylib-apple/platform.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ + build/pylib-apple/plistlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ + build/pylib-apple/poplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ + build/pylib-apple/posixpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ + build/pylib-apple/pprint.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ + build/pylib-apple/profile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ + build/pylib-apple/pstats.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ + build/pylib-apple/pty.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ + build/pylib-apple/py_compile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ + build/pylib-apple/pyclbr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ + build/pylib-apple/pydoc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ + build/pylib-apple/queue.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ + build/pylib-apple/quopri.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ + build/pylib-apple/random.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ + build/pylib-apple/re.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ + build/pylib-apple/reprlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ + build/pylib-apple/rlcompleter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ + build/pylib-apple/runpy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ + build/pylib-apple/sched.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ + build/pylib-apple/secrets.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ + build/pylib-apple/selectors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ + build/pylib-apple/shelve.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ + build/pylib-apple/shlex.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ + build/pylib-apple/shutil.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ + build/pylib-apple/signal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ + build/pylib-apple/site.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ + build/pylib-apple/smtpd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ + build/pylib-apple/smtplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ + build/pylib-apple/sndhdr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ + build/pylib-apple/socket.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ + build/pylib-apple/socketserver.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ + build/pylib-apple/sqlite3/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ + build/pylib-apple/sqlite3/dbapi2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ + build/pylib-apple/sqlite3/dump.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ + build/pylib-apple/sre_compile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ + build/pylib-apple/sre_constants.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ + build/pylib-apple/sre_parse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ + build/pylib-apple/ssl.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ + build/pylib-apple/stat.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ + build/pylib-apple/statistics.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ + build/pylib-apple/string.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ + build/pylib-apple/stringprep.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ + build/pylib-apple/struct.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ + build/pylib-apple/subprocess.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ + build/pylib-apple/sunau.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ + build/pylib-apple/symbol.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ + build/pylib-apple/symtable.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/sysconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ + build/pylib-apple/tabnanny.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/pylib-apple/tarfile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/telnetlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ + build/pylib-apple/tempfile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ + build/pylib-apple/textwrap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ + build/pylib-apple/this.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ + build/pylib-apple/threading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/timeit.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ + build/pylib-apple/token.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ + build/pylib-apple/tokenize.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/pylib-apple/trace.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ + build/pylib-apple/traceback.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ + build/pylib-apple/tracemalloc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ + build/pylib-apple/tty.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/types.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ + build/pylib-apple/typing.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ + build/pylib-apple/urllib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ + build/pylib-apple/urllib/error.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ + build/pylib-apple/urllib/parse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/urllib/request.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ + build/pylib-apple/urllib/response.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ + build/pylib-apple/urllib/robotparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/uu.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ + build/pylib-apple/uuid.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ + build/pylib-apple/warnings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/wave.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ + build/pylib-apple/weakref.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ + build/pylib-apple/webbrowser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ + build/pylib-apple/xdrlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/parsers/expat.py +build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/parsers/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/handler.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/saxutils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/xmlreader.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/expatreader.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/NodeFilter.py + build/pylib-apple/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/xmlbuilder.py +build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/dom/minicompat.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/dom/pulldom.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/dom/xmlbuilder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/etree/ElementInclude.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/etree/ElementTree.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/etree/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/__init__.py + build/pylib-apple/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/ElementInclude.py +build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/ElementTree.py +build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/decoder.py +build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/scanner.py +build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/__init__.py +build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/encoder.py +build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/tool.py +build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ + build/pylib-apple/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/cookies.py +build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ + build/pylib-apple/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/client.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/cookiejar.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/sqlite3/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/pylib-apple/sqlite3/dump.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/pylib-apple/sqlite3/dbapi2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-apple/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xmlrpc/__init__.py + build/pylib-apple/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/collections/__init__.py +build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ + build/pylib-apple/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/pylib-apple/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/pylib-apple/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/base.py +build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ + build/pylib-apple/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ - build/pylib-android/zipfile.py \ - build/pylib-android/shutil.py \ - build/pylib-android/tempfile.py \ - build/pylib-android/queue.py \ - build/pylib-android/macpath.py \ - build/pylib-android/_pyio.py \ - build/pylib-android/crypt.py \ - build/pylib-android/pkgutil.py \ - build/pylib-android/_dummy_thread.py \ - build/pylib-android/lzma.py \ - build/pylib-android/asyncore.py \ - build/pylib-android/__phello__.foo.py \ - build/pylib-android/_sitebuiltins.py \ - build/pylib-android/copyreg.py \ - build/pylib-android/sndhdr.py \ - build/pylib-android/rlcompleter.py \ - build/pylib-android/gzip.py \ - build/pylib-android/ipaddress.py \ - build/pylib-android/trace.py \ - build/pylib-android/webbrowser.py \ - build/pylib-android/nntplib.py \ - build/pylib-android/_compat_pickle.py \ - build/pylib-android/dis.py \ - build/pylib-android/formatter.py \ - build/pylib-android/bdb.py \ - build/pylib-android/zipapp.py \ - build/pylib-android/cmd.py \ - build/pylib-android/tty.py \ - build/pylib-android/tabnanny.py \ - build/pylib-android/_py_abc.py \ - build/pylib-android/cProfile.py \ - build/pylib-android/token.py \ - build/pylib-android/textwrap.py \ - build/pylib-android/base64.py \ - build/pylib-android/_markupbase.py \ - build/pylib-android/bz2.py \ - build/pylib-android/signal.py \ - build/pylib-android/sre_constants.py \ - build/pylib-android/cgitb.py \ - build/pylib-android/_threading_local.py \ - build/pylib-android/pyclbr.py \ - build/pylib-android/gettext.py \ - build/pylib-android/wave.py \ - build/pylib-android/weakref.py \ - build/pylib-android/bisect.py \ - build/pylib-android/opcode.py \ - build/pylib-android/netrc.py \ - build/pylib-android/heapq.py \ - build/pylib-android/functools.py \ - build/pylib-android/modulefinder.py \ - build/pylib-android/_compression.py \ - build/pylib-android/tracemalloc.py \ - build/pylib-android/hashlib.py \ - build/pylib-android/cgi.py \ - build/pylib-android/codeop.py \ - build/pylib-android/fnmatch.py \ - build/pylib-android/traceback.py \ - build/pylib-android/nturl2path.py \ - build/pylib-android/warnings.py \ - build/pylib-android/subprocess.py \ - build/pylib-android/profile.py \ - build/pylib-android/imghdr.py \ - build/pylib-android/this.py \ - build/pylib-android/filecmp.py \ - build/pylib-android/codecs.py \ - build/pylib-android/uu.py \ - build/pylib-android/_weakrefset.py \ - build/pylib-android/io.py \ - build/pylib-android/code.py \ - build/pylib-android/operator.py \ - build/pylib-android/fileinput.py \ - build/pylib-android/os.py \ - build/pylib-android/difflib.py \ - build/pylib-android/pydoc.py \ - build/pylib-android/symbol.py \ - build/pylib-android/selectors.py \ - build/pylib-android/decimal.py \ - build/pylib-android/socketserver.py \ - build/pylib-android/copy.py \ - build/pylib-android/genericpath.py \ - build/pylib-android/linecache.py \ - build/pylib-android/types.py \ - build/pylib-android/mimetypes.py \ - build/pylib-android/xdrlib.py \ - build/pylib-android/colorsys.py \ - build/pylib-android/numbers.py \ - build/pylib-android/_strptime.py \ - build/pylib-android/dummy_threading.py \ - build/pylib-android/contextvars.py \ - build/pylib-android/random.py \ - build/pylib-android/ftplib.py \ - build/pylib-android/chunk.py \ - build/pylib-android/optparse.py \ - build/pylib-android/pdb.py \ - build/pylib-android/threading.py \ - build/pylib-android/platform.py \ - build/pylib-android/pstats.py \ - build/pylib-android/glob.py \ - build/pylib-android/quopri.py \ - build/pylib-android/symtable.py \ - build/pylib-android/pprint.py \ - build/pylib-android/calendar.py \ - build/pylib-android/inspect.py \ - build/pylib-android/poplib.py \ - build/pylib-android/binhex.py \ - build/pylib-android/plistlib.py \ - build/pylib-android/pickletools.py \ - build/pylib-android/pipes.py \ - build/pylib-android/site.py \ - build/pylib-android/telnetlib.py \ - build/pylib-android/keyword.py \ - build/pylib-android/configparser.py \ - build/pylib-android/reprlib.py \ - build/pylib-android/secrets.py \ - build/pylib-android/shlex.py \ - build/pylib-android/posixpath.py \ - build/pylib-android/py_compile.py \ - build/pylib-android/_osx_support.py \ - build/pylib-android/stat.py \ - build/pylib-android/compileall.py \ - build/pylib-android/csv.py \ - build/pylib-android/fractions.py \ - build/pylib-android/sched.py \ - build/pylib-android/mailbox.py \ - build/pylib-android/sre_compile.py \ - build/pylib-android/locale.py \ - build/pylib-android/ast.py \ - build/pylib-android/doctest.py \ - build/pylib-android/argparse.py \ - build/pylib-android/getpass.py \ - build/pylib-android/pickle.py \ - build/pylib-android/pty.py \ - build/pylib-android/contextlib.py \ - build/pylib-android/statistics.py \ - build/pylib-android/_collections_abc.py \ - build/pylib-android/sunau.py \ build/pylib-android/__future__.py \ - build/pylib-android/dataclasses.py \ - build/pylib-android/shelve.py \ - build/pylib-android/string.py \ - build/pylib-android/smtplib.py \ - build/pylib-android/getopt.py \ - build/pylib-android/antigravity.py \ - build/pylib-android/enum.py \ - build/pylib-android/timeit.py \ - build/pylib-android/hmac.py \ - build/pylib-android/tarfile.py \ - build/pylib-android/stringprep.py \ - build/pylib-android/typing.py \ - build/pylib-android/ssl.py \ - build/pylib-android/socket.py \ - build/pylib-android/datetime.py \ - build/pylib-android/sysconfig.py \ - build/pylib-android/pathlib.py \ - build/pylib-android/_pydecimal.py \ - build/pylib-android/ntpath.py \ - build/pylib-android/tokenize.py \ - build/pylib-android/uuid.py \ - build/pylib-android/imp.py \ - build/pylib-android/smtpd.py \ - build/pylib-android/re.py \ - build/pylib-android/mailcap.py \ - build/pylib-android/aifc.py \ - build/pylib-android/struct.py \ - build/pylib-android/asynchat.py \ - build/pylib-android/sre_parse.py \ - build/pylib-android/abc.py \ - build/pylib-android/runpy.py \ + build/pylib-android/__phello__.foo.py \ build/pylib-android/_bootlocale.py \ - build/pylib-android/encodings/mac_romanian.py \ - build/pylib-android/encodings/mac_farsi.py \ - build/pylib-android/encodings/idna.py \ - build/pylib-android/encodings/cp273.py \ - build/pylib-android/encodings/punycode.py \ - build/pylib-android/encodings/raw_unicode_escape.py \ - build/pylib-android/encodings/utf_8.py \ - build/pylib-android/encodings/cp1252.py \ - build/pylib-android/encodings/cp869.py \ - build/pylib-android/encodings/iso8859_14.py \ - build/pylib-android/encodings/iso8859_2.py \ - build/pylib-android/encodings/mac_arabic.py \ - build/pylib-android/encodings/mac_croatian.py \ - build/pylib-android/encodings/big5hkscs.py \ - build/pylib-android/encodings/cp1256.py \ - build/pylib-android/encodings/iso8859_6.py \ - build/pylib-android/encodings/iso8859_10.py \ - build/pylib-android/encodings/iso2022_kr.py \ - build/pylib-android/encodings/cp1140.py \ - build/pylib-android/encodings/unicode_internal.py \ - build/pylib-android/encodings/cp1125.py \ - build/pylib-android/encodings/iso2022_jp_1.py \ - build/pylib-android/encodings/cp1257.py \ - build/pylib-android/encodings/cp949.py \ - build/pylib-android/encodings/cp858.py \ - build/pylib-android/encodings/iso8859_7.py \ - build/pylib-android/encodings/iso8859_11.py \ - build/pylib-android/encodings/hp_roman8.py \ - build/pylib-android/encodings/koi8_r.py \ - build/pylib-android/encodings/zlib_codec.py \ - build/pylib-android/encodings/gbk.py \ - build/pylib-android/encodings/johab.py \ - build/pylib-android/encodings/cp1253.py \ - build/pylib-android/encodings/iso8859_15.py \ - build/pylib-android/encodings/iso2022_jp_2004.py \ - build/pylib-android/encodings/mac_iceland.py \ - build/pylib-android/encodings/iso8859_3.py \ - build/pylib-android/encodings/mac_greek.py \ - build/pylib-android/encodings/rot_13.py \ - build/pylib-android/encodings/utf_16_be.py \ - build/pylib-android/encodings/euc_kr.py \ - build/pylib-android/encodings/mac_centeuro.py \ - build/pylib-android/encodings/euc_jisx0213.py \ - build/pylib-android/encodings/cp863.py \ - build/pylib-android/encodings/ascii.py \ - build/pylib-android/encodings/iso8859_8.py \ - build/pylib-android/encodings/cp857.py \ - build/pylib-android/encodings/utf_32_be.py \ - build/pylib-android/encodings/cp1258.py \ - build/pylib-android/encodings/oem.py \ - build/pylib-android/encodings/mac_latin2.py \ - build/pylib-android/encodings/cp775.py \ - build/pylib-android/encodings/mac_roman.py \ - build/pylib-android/encodings/__init__.py \ - build/pylib-android/encodings/cp852.py \ - build/pylib-android/encodings/shift_jisx0213.py \ - build/pylib-android/encodings/cp866.py \ - build/pylib-android/encodings/utf_7.py \ - build/pylib-android/encodings/base64_codec.py \ - build/pylib-android/encodings/cp932.py \ - build/pylib-android/encodings/cp720.py \ - build/pylib-android/encodings/cp862.py \ - build/pylib-android/encodings/cp437.py \ - build/pylib-android/encodings/palmos.py \ - build/pylib-android/encodings/iso8859_9.py \ - build/pylib-android/encodings/cp856.py \ - build/pylib-android/encodings/aliases.py \ - build/pylib-android/encodings/latin_1.py \ - build/pylib-android/encodings/cp875.py \ - build/pylib-android/encodings/cp950.py \ - build/pylib-android/encodings/unicode_escape.py \ - build/pylib-android/encodings/cp737.py \ - build/pylib-android/encodings/cp865.py \ - build/pylib-android/encodings/ptcp154.py \ - build/pylib-android/encodings/big5.py \ - build/pylib-android/encodings/cp424.py \ - build/pylib-android/encodings/cp861.py \ - build/pylib-android/encodings/euc_jp.py \ - build/pylib-android/encodings/cp855.py \ - build/pylib-android/encodings/shift_jis.py \ - build/pylib-android/encodings/utf_32_le.py \ - build/pylib-android/encodings/cp500.py \ - build/pylib-android/encodings/undefined.py \ - build/pylib-android/encodings/cp860.py \ - build/pylib-android/encodings/uu_codec.py \ - build/pylib-android/encodings/utf_16_le.py \ - build/pylib-android/encodings/gb18030.py \ - build/pylib-android/encodings/cp65001.py \ - build/pylib-android/encodings/cp874.py \ - build/pylib-android/encodings/cp850.py \ - build/pylib-android/encodings/cp864.py \ - build/pylib-android/encodings/utf_32.py \ - build/pylib-android/encodings/koi8_u.py \ - build/pylib-android/encodings/cp1254.py \ - build/pylib-android/encodings/iso2022_jp_2.py \ - build/pylib-android/encodings/utf_16.py \ - build/pylib-android/encodings/iso8859_4.py \ - build/pylib-android/encodings/euc_jis_2004.py \ - build/pylib-android/encodings/mbcs.py \ - build/pylib-android/encodings/cp1250.py \ - build/pylib-android/encodings/gb2312.py \ - build/pylib-android/encodings/iso8859_16.py \ - build/pylib-android/encodings/mac_cyrillic.py \ - build/pylib-android/encodings/hex_codec.py \ - build/pylib-android/encodings/tis_620.py \ - build/pylib-android/encodings/cp037.py \ - build/pylib-android/encodings/cp1006.py \ - build/pylib-android/encodings/cp1251.py \ - build/pylib-android/encodings/mac_turkish.py \ - build/pylib-android/encodings/iso2022_jp_ext.py \ - build/pylib-android/encodings/iso8859_1.py \ - build/pylib-android/encodings/hz.py \ - build/pylib-android/encodings/bz2_codec.py \ - build/pylib-android/encodings/quopri_codec.py \ - build/pylib-android/encodings/kz1048.py \ - build/pylib-android/encodings/utf_8_sig.py \ - build/pylib-android/encodings/koi8_t.py \ - build/pylib-android/encodings/cp1255.py \ - build/pylib-android/encodings/iso2022_jp_3.py \ - build/pylib-android/encodings/shift_jis_2004.py \ - build/pylib-android/encodings/cp1026.py \ - build/pylib-android/encodings/charmap.py \ - build/pylib-android/encodings/iso8859_5.py \ - build/pylib-android/encodings/iso8859_13.py \ - build/pylib-android/encodings/iso2022_jp.py \ - build/pylib-android/ctypes/_aix.py \ - build/pylib-android/ctypes/wintypes.py \ - build/pylib-android/ctypes/util.py \ - build/pylib-android/ctypes/__init__.py \ - build/pylib-android/ctypes/_endian.py \ - build/pylib-android/ctypes/macholib/dyld.py \ - build/pylib-android/ctypes/macholib/framework.py \ - build/pylib-android/ctypes/macholib/__init__.py \ - build/pylib-android/ctypes/macholib/dylib.py \ - build/pylib-android/curses/textpad.py \ - build/pylib-android/curses/ascii.py \ - build/pylib-android/curses/__init__.py \ - build/pylib-android/curses/has_key.py \ - build/pylib-android/curses/panel.py \ - build/pylib-android/urllib/error.py \ - build/pylib-android/urllib/request.py \ - build/pylib-android/urllib/__init__.py \ - build/pylib-android/urllib/response.py \ - build/pylib-android/urllib/robotparser.py \ - build/pylib-android/urllib/parse.py \ - build/pylib-android/html/__init__.py \ - build/pylib-android/html/parser.py \ - build/pylib-android/html/entities.py \ - build/pylib-android/xml/__init__.py \ - build/pylib-android/xml/parsers/expat.py \ - build/pylib-android/xml/parsers/__init__.py \ - build/pylib-android/xml/sax/handler.py \ - build/pylib-android/xml/sax/__init__.py \ - build/pylib-android/xml/sax/saxutils.py \ - build/pylib-android/xml/sax/xmlreader.py \ - build/pylib-android/xml/sax/expatreader.py \ - build/pylib-android/xml/sax/_exceptions.py \ - build/pylib-android/xml/dom/pulldom.py \ - build/pylib-android/xml/dom/expatbuilder.py \ - build/pylib-android/xml/dom/domreg.py \ - build/pylib-android/xml/dom/minicompat.py \ - build/pylib-android/xml/dom/__init__.py \ - build/pylib-android/xml/dom/NodeFilter.py \ - build/pylib-android/xml/dom/xmlbuilder.py \ - build/pylib-android/xml/dom/minidom.py \ - build/pylib-android/xml/etree/ElementPath.py \ - build/pylib-android/xml/etree/cElementTree.py \ - build/pylib-android/xml/etree/__init__.py \ - build/pylib-android/xml/etree/ElementInclude.py \ - build/pylib-android/xml/etree/ElementTree.py \ - build/pylib-android/json/decoder.py \ - build/pylib-android/json/scanner.py \ - build/pylib-android/json/__init__.py \ - build/pylib-android/json/encoder.py \ - build/pylib-android/json/tool.py \ - build/pylib-android/http/cookies.py \ - build/pylib-android/http/server.py \ - build/pylib-android/http/client.py \ - build/pylib-android/http/__init__.py \ - build/pylib-android/http/cookiejar.py \ - build/pylib-android/sqlite3/__init__.py \ - build/pylib-android/sqlite3/dump.py \ - build/pylib-android/sqlite3/dbapi2.py \ - build/pylib-android/concurrent/__init__.py \ - build/pylib-android/concurrent/futures/_base.py \ - build/pylib-android/concurrent/futures/thread.py \ - build/pylib-android/concurrent/futures/__init__.py \ - build/pylib-android/concurrent/futures/process.py \ - build/pylib-android/importlib/util.py \ - build/pylib-android/importlib/_bootstrap.py \ - build/pylib-android/importlib/__init__.py \ - build/pylib-android/importlib/_bootstrap_external.py \ - build/pylib-android/importlib/resources.py \ - build/pylib-android/importlib/machinery.py \ - build/pylib-android/importlib/abc.py \ - build/pylib-android/xmlrpc/server.py \ - build/pylib-android/xmlrpc/client.py \ - build/pylib-android/xmlrpc/__init__.py \ + build/pylib-android/_collections_abc.py \ + build/pylib-android/_compat_pickle.py \ + build/pylib-android/_compression.py \ + build/pylib-android/_dummy_thread.py \ + build/pylib-android/_markupbase.py \ + build/pylib-android/_osx_support.py \ + build/pylib-android/_py_abc.py \ + build/pylib-android/_pydecimal.py \ + build/pylib-android/_pyio.py \ + build/pylib-android/_sitebuiltins.py \ + build/pylib-android/_strptime.py \ + build/pylib-android/_threading_local.py \ + build/pylib-android/_weakrefset.py \ + build/pylib-android/abc.py \ + build/pylib-android/aifc.py \ + build/pylib-android/antigravity.py \ + build/pylib-android/argparse.py \ + build/pylib-android/ast.py \ + build/pylib-android/asynchat.py \ + build/pylib-android/asyncio/__init__.py \ + build/pylib-android/asyncio/base_events.py \ + build/pylib-android/asyncio/base_futures.py \ + build/pylib-android/asyncio/base_subprocess.py \ + build/pylib-android/asyncio/base_tasks.py \ + build/pylib-android/asyncio/constants.py \ + build/pylib-android/asyncio/coroutines.py \ + build/pylib-android/asyncio/events.py \ + build/pylib-android/asyncio/format_helpers.py \ + build/pylib-android/asyncio/futures.py \ + build/pylib-android/asyncio/locks.py \ + build/pylib-android/asyncio/log.py \ + build/pylib-android/asyncio/proactor_events.py \ + build/pylib-android/asyncio/protocols.py \ + build/pylib-android/asyncio/queues.py \ + build/pylib-android/asyncio/runners.py \ + build/pylib-android/asyncio/selector_events.py \ + build/pylib-android/asyncio/sslproto.py \ + build/pylib-android/asyncio/streams.py \ + build/pylib-android/asyncio/subprocess.py \ + build/pylib-android/asyncio/tasks.py \ + build/pylib-android/asyncio/transports.py \ + build/pylib-android/asyncio/unix_events.py \ + build/pylib-android/asyncio/windows_events.py \ + build/pylib-android/asyncio/windows_utils.py \ + build/pylib-android/asyncore.py \ + build/pylib-android/base64.py \ + build/pylib-android/bdb.py \ + build/pylib-android/binhex.py \ + build/pylib-android/bisect.py \ + build/pylib-android/bz2.py \ + build/pylib-android/cProfile.py \ + build/pylib-android/calendar.py \ + build/pylib-android/cgi.py \ + build/pylib-android/cgitb.py \ + build/pylib-android/chunk.py \ + build/pylib-android/cmd.py \ + build/pylib-android/code.py \ + build/pylib-android/codecs.py \ + build/pylib-android/codeop.py \ build/pylib-android/collections/__init__.py \ build/pylib-android/collections/abc.py \ - build/pylib-android/asyncio/queues.py \ - build/pylib-android/asyncio/streams.py \ - build/pylib-android/asyncio/tasks.py \ - build/pylib-android/asyncio/selector_events.py \ - build/pylib-android/asyncio/log.py \ - build/pylib-android/asyncio/protocols.py \ - build/pylib-android/asyncio/events.py \ - build/pylib-android/asyncio/base_events.py \ - build/pylib-android/asyncio/subprocess.py \ - build/pylib-android/asyncio/constants.py \ - build/pylib-android/asyncio/proactor_events.py \ - build/pylib-android/asyncio/format_helpers.py \ - build/pylib-android/asyncio/locks.py \ - build/pylib-android/asyncio/__init__.py \ - build/pylib-android/asyncio/futures.py \ - build/pylib-android/asyncio/sslproto.py \ - build/pylib-android/asyncio/base_subprocess.py \ - build/pylib-android/asyncio/windows_utils.py \ - build/pylib-android/asyncio/runners.py \ - build/pylib-android/asyncio/transports.py \ - build/pylib-android/asyncio/base_tasks.py \ - build/pylib-android/asyncio/coroutines.py \ - build/pylib-android/asyncio/windows_events.py \ - build/pylib-android/asyncio/base_futures.py \ - build/pylib-android/asyncio/unix_events.py \ - build/pylib-android/logging/config.py \ - build/pylib-android/logging/handlers.py \ - build/pylib-android/logging/__init__.py \ - build/pylib-android/email/contentmanager.py \ - build/pylib-android/email/_policybase.py \ - build/pylib-android/email/header.py \ + build/pylib-android/colorsys.py \ + build/pylib-android/compileall.py \ + build/pylib-android/concurrent/__init__.py \ + build/pylib-android/concurrent/futures/__init__.py \ + build/pylib-android/concurrent/futures/_base.py \ + build/pylib-android/concurrent/futures/process.py \ + build/pylib-android/concurrent/futures/thread.py \ + build/pylib-android/configparser.py \ + build/pylib-android/contextlib.py \ + build/pylib-android/contextvars.py \ + build/pylib-android/copy.py \ + build/pylib-android/copyreg.py \ + build/pylib-android/crypt.py \ + build/pylib-android/csv.py \ + build/pylib-android/ctypes/__init__.py \ + build/pylib-android/ctypes/_aix.py \ + build/pylib-android/ctypes/_endian.py \ + build/pylib-android/ctypes/macholib/__init__.py \ + build/pylib-android/ctypes/macholib/dyld.py \ + build/pylib-android/ctypes/macholib/dylib.py \ + build/pylib-android/ctypes/macholib/framework.py \ + build/pylib-android/ctypes/util.py \ + build/pylib-android/ctypes/wintypes.py \ + build/pylib-android/curses/__init__.py \ + build/pylib-android/curses/ascii.py \ + build/pylib-android/curses/has_key.py \ + build/pylib-android/curses/panel.py \ + build/pylib-android/curses/textpad.py \ + build/pylib-android/dataclasses.py \ + build/pylib-android/datetime.py \ + build/pylib-android/decimal.py \ + build/pylib-android/difflib.py \ + build/pylib-android/dis.py \ + build/pylib-android/doctest.py \ + build/pylib-android/dummy_threading.py \ + build/pylib-android/email/__init__.py \ build/pylib-android/email/_encoded_words.py \ build/pylib-android/email/_header_value_parser.py \ - build/pylib-android/email/policy.py \ - build/pylib-android/email/__init__.py \ - build/pylib-android/email/message.py \ - build/pylib-android/email/encoders.py \ - build/pylib-android/email/parser.py \ - build/pylib-android/email/generator.py \ - build/pylib-android/email/utils.py \ + build/pylib-android/email/_parseaddr.py \ + build/pylib-android/email/_policybase.py \ + build/pylib-android/email/base64mime.py \ build/pylib-android/email/charset.py \ - build/pylib-android/email/iterators.py \ - build/pylib-android/email/quoprimime.py \ + build/pylib-android/email/contentmanager.py \ + build/pylib-android/email/encoders.py \ build/pylib-android/email/errors.py \ build/pylib-android/email/feedparser.py \ - build/pylib-android/email/_parseaddr.py \ - build/pylib-android/email/base64mime.py \ + build/pylib-android/email/generator.py \ + build/pylib-android/email/header.py \ build/pylib-android/email/headerregistry.py \ - build/pylib-android/email/mime/multipart.py \ + build/pylib-android/email/iterators.py \ + build/pylib-android/email/message.py \ build/pylib-android/email/mime/__init__.py \ - build/pylib-android/email/mime/message.py \ build/pylib-android/email/mime/application.py \ + build/pylib-android/email/mime/audio.py \ + build/pylib-android/email/mime/base.py \ + build/pylib-android/email/mime/image.py \ + build/pylib-android/email/mime/message.py \ + build/pylib-android/email/mime/multipart.py \ build/pylib-android/email/mime/nonmultipart.py \ build/pylib-android/email/mime/text.py \ - build/pylib-android/email/mime/audio.py \ - build/pylib-android/email/mime/image.py \ - build/pylib-android/email/mime/base.py + build/pylib-android/email/parser.py \ + build/pylib-android/email/policy.py \ + build/pylib-android/email/quoprimime.py \ + build/pylib-android/email/utils.py \ + build/pylib-android/encodings/__init__.py \ + build/pylib-android/encodings/aliases.py \ + build/pylib-android/encodings/ascii.py \ + build/pylib-android/encodings/base64_codec.py \ + build/pylib-android/encodings/big5.py \ + build/pylib-android/encodings/big5hkscs.py \ + build/pylib-android/encodings/bz2_codec.py \ + build/pylib-android/encodings/charmap.py \ + build/pylib-android/encodings/cp037.py \ + build/pylib-android/encodings/cp1006.py \ + build/pylib-android/encodings/cp1026.py \ + build/pylib-android/encodings/cp1125.py \ + build/pylib-android/encodings/cp1140.py \ + build/pylib-android/encodings/cp1250.py \ + build/pylib-android/encodings/cp1251.py \ + build/pylib-android/encodings/cp1252.py \ + build/pylib-android/encodings/cp1253.py \ + build/pylib-android/encodings/cp1254.py \ + build/pylib-android/encodings/cp1255.py \ + build/pylib-android/encodings/cp1256.py \ + build/pylib-android/encodings/cp1257.py \ + build/pylib-android/encodings/cp1258.py \ + build/pylib-android/encodings/cp273.py \ + build/pylib-android/encodings/cp424.py \ + build/pylib-android/encodings/cp437.py \ + build/pylib-android/encodings/cp500.py \ + build/pylib-android/encodings/cp65001.py \ + build/pylib-android/encodings/cp720.py \ + build/pylib-android/encodings/cp737.py \ + build/pylib-android/encodings/cp775.py \ + build/pylib-android/encodings/cp850.py \ + build/pylib-android/encodings/cp852.py \ + build/pylib-android/encodings/cp855.py \ + build/pylib-android/encodings/cp856.py \ + build/pylib-android/encodings/cp857.py \ + build/pylib-android/encodings/cp858.py \ + build/pylib-android/encodings/cp860.py \ + build/pylib-android/encodings/cp861.py \ + build/pylib-android/encodings/cp862.py \ + build/pylib-android/encodings/cp863.py \ + build/pylib-android/encodings/cp864.py \ + build/pylib-android/encodings/cp865.py \ + build/pylib-android/encodings/cp866.py \ + build/pylib-android/encodings/cp869.py \ + build/pylib-android/encodings/cp874.py \ + build/pylib-android/encodings/cp875.py \ + build/pylib-android/encodings/cp932.py \ + build/pylib-android/encodings/cp949.py \ + build/pylib-android/encodings/cp950.py \ + build/pylib-android/encodings/euc_jis_2004.py \ + build/pylib-android/encodings/euc_jisx0213.py \ + build/pylib-android/encodings/euc_jp.py \ + build/pylib-android/encodings/euc_kr.py \ + build/pylib-android/encodings/gb18030.py \ + build/pylib-android/encodings/gb2312.py \ + build/pylib-android/encodings/gbk.py \ + build/pylib-android/encodings/hex_codec.py \ + build/pylib-android/encodings/hp_roman8.py \ + build/pylib-android/encodings/hz.py \ + build/pylib-android/encodings/idna.py \ + build/pylib-android/encodings/iso2022_jp.py \ + build/pylib-android/encodings/iso2022_jp_1.py \ + build/pylib-android/encodings/iso2022_jp_2.py \ + build/pylib-android/encodings/iso2022_jp_2004.py \ + build/pylib-android/encodings/iso2022_jp_3.py \ + build/pylib-android/encodings/iso2022_jp_ext.py \ + build/pylib-android/encodings/iso2022_kr.py \ + build/pylib-android/encodings/iso8859_1.py \ + build/pylib-android/encodings/iso8859_10.py \ + build/pylib-android/encodings/iso8859_11.py \ + build/pylib-android/encodings/iso8859_13.py \ + build/pylib-android/encodings/iso8859_14.py \ + build/pylib-android/encodings/iso8859_15.py \ + build/pylib-android/encodings/iso8859_16.py \ + build/pylib-android/encodings/iso8859_2.py \ + build/pylib-android/encodings/iso8859_3.py \ + build/pylib-android/encodings/iso8859_4.py \ + build/pylib-android/encodings/iso8859_5.py \ + build/pylib-android/encodings/iso8859_6.py \ + build/pylib-android/encodings/iso8859_7.py \ + build/pylib-android/encodings/iso8859_8.py \ + build/pylib-android/encodings/iso8859_9.py \ + build/pylib-android/encodings/johab.py \ + build/pylib-android/encodings/koi8_r.py \ + build/pylib-android/encodings/koi8_t.py \ + build/pylib-android/encodings/koi8_u.py \ + build/pylib-android/encodings/kz1048.py \ + build/pylib-android/encodings/latin_1.py \ + build/pylib-android/encodings/mac_arabic.py \ + build/pylib-android/encodings/mac_centeuro.py \ + build/pylib-android/encodings/mac_croatian.py \ + build/pylib-android/encodings/mac_cyrillic.py \ + build/pylib-android/encodings/mac_farsi.py \ + build/pylib-android/encodings/mac_greek.py \ + build/pylib-android/encodings/mac_iceland.py \ + build/pylib-android/encodings/mac_latin2.py \ + build/pylib-android/encodings/mac_roman.py \ + build/pylib-android/encodings/mac_romanian.py \ + build/pylib-android/encodings/mac_turkish.py \ + build/pylib-android/encodings/mbcs.py \ + build/pylib-android/encodings/oem.py \ + build/pylib-android/encodings/palmos.py \ + build/pylib-android/encodings/ptcp154.py \ + build/pylib-android/encodings/punycode.py \ + build/pylib-android/encodings/quopri_codec.py \ + build/pylib-android/encodings/raw_unicode_escape.py \ + build/pylib-android/encodings/rot_13.py \ + build/pylib-android/encodings/shift_jis.py \ + build/pylib-android/encodings/shift_jis_2004.py \ + build/pylib-android/encodings/shift_jisx0213.py \ + build/pylib-android/encodings/tis_620.py \ + build/pylib-android/encodings/undefined.py \ + build/pylib-android/encodings/unicode_escape.py \ + build/pylib-android/encodings/unicode_internal.py \ + build/pylib-android/encodings/utf_16.py \ + build/pylib-android/encodings/utf_16_be.py \ + build/pylib-android/encodings/utf_16_le.py \ + build/pylib-android/encodings/utf_32.py \ + build/pylib-android/encodings/utf_32_be.py \ + build/pylib-android/encodings/utf_32_le.py \ + build/pylib-android/encodings/utf_7.py \ + build/pylib-android/encodings/utf_8.py \ + build/pylib-android/encodings/utf_8_sig.py \ + build/pylib-android/encodings/uu_codec.py \ + build/pylib-android/encodings/zlib_codec.py \ + build/pylib-android/enum.py \ + build/pylib-android/filecmp.py \ + build/pylib-android/fileinput.py \ + build/pylib-android/fnmatch.py \ + build/pylib-android/formatter.py \ + build/pylib-android/fractions.py \ + build/pylib-android/ftplib.py \ + build/pylib-android/functools.py \ + build/pylib-android/genericpath.py \ + build/pylib-android/getopt.py \ + build/pylib-android/getpass.py \ + build/pylib-android/gettext.py \ + build/pylib-android/glob.py \ + build/pylib-android/gzip.py \ + build/pylib-android/hashlib.py \ + build/pylib-android/heapq.py \ + build/pylib-android/hmac.py \ + build/pylib-android/html/__init__.py \ + build/pylib-android/html/entities.py \ + build/pylib-android/html/parser.py \ + build/pylib-android/http/__init__.py \ + build/pylib-android/http/client.py \ + build/pylib-android/http/cookiejar.py \ + build/pylib-android/http/cookies.py \ + build/pylib-android/http/server.py \ + build/pylib-android/imghdr.py \ + build/pylib-android/imp.py \ + build/pylib-android/importlib/__init__.py \ + build/pylib-android/importlib/_bootstrap.py \ + build/pylib-android/importlib/_bootstrap_external.py \ + build/pylib-android/importlib/abc.py \ + build/pylib-android/importlib/machinery.py \ + build/pylib-android/importlib/resources.py \ + build/pylib-android/importlib/util.py \ + build/pylib-android/inspect.py \ + build/pylib-android/io.py \ + build/pylib-android/ipaddress.py \ + build/pylib-android/json/__init__.py \ + build/pylib-android/json/decoder.py \ + build/pylib-android/json/encoder.py \ + build/pylib-android/json/scanner.py \ + build/pylib-android/json/tool.py \ + build/pylib-android/keyword.py \ + build/pylib-android/linecache.py \ + build/pylib-android/locale.py \ + build/pylib-android/logging/__init__.py \ + build/pylib-android/logging/config.py \ + build/pylib-android/logging/handlers.py \ + build/pylib-android/lzma.py \ + build/pylib-android/macpath.py \ + build/pylib-android/mailbox.py \ + build/pylib-android/mailcap.py \ + build/pylib-android/mimetypes.py \ + build/pylib-android/modulefinder.py \ + build/pylib-android/netrc.py \ + build/pylib-android/nntplib.py \ + build/pylib-android/ntpath.py \ + build/pylib-android/nturl2path.py \ + build/pylib-android/numbers.py \ + build/pylib-android/opcode.py \ + build/pylib-android/operator.py \ + build/pylib-android/optparse.py \ + build/pylib-android/os.py \ + build/pylib-android/pathlib.py \ + build/pylib-android/pdb.py \ + build/pylib-android/pickle.py \ + build/pylib-android/pickletools.py \ + build/pylib-android/pipes.py \ + build/pylib-android/pkgutil.py \ + build/pylib-android/platform.py \ + build/pylib-android/plistlib.py \ + build/pylib-android/poplib.py \ + build/pylib-android/posixpath.py \ + build/pylib-android/pprint.py \ + build/pylib-android/profile.py \ + build/pylib-android/pstats.py \ + build/pylib-android/pty.py \ + build/pylib-android/py_compile.py \ + build/pylib-android/pyclbr.py \ + build/pylib-android/pydoc.py \ + build/pylib-android/queue.py \ + build/pylib-android/quopri.py \ + build/pylib-android/random.py \ + build/pylib-android/re.py \ + build/pylib-android/reprlib.py \ + build/pylib-android/rlcompleter.py \ + build/pylib-android/runpy.py \ + build/pylib-android/sched.py \ + build/pylib-android/secrets.py \ + build/pylib-android/selectors.py \ + build/pylib-android/shelve.py \ + build/pylib-android/shlex.py \ + build/pylib-android/shutil.py \ + build/pylib-android/signal.py \ + build/pylib-android/site.py \ + build/pylib-android/smtpd.py \ + build/pylib-android/smtplib.py \ + build/pylib-android/sndhdr.py \ + build/pylib-android/socket.py \ + build/pylib-android/socketserver.py \ + build/pylib-android/sqlite3/__init__.py \ + build/pylib-android/sqlite3/dbapi2.py \ + build/pylib-android/sqlite3/dump.py \ + build/pylib-android/sre_compile.py \ + build/pylib-android/sre_constants.py \ + build/pylib-android/sre_parse.py \ + build/pylib-android/ssl.py \ + build/pylib-android/stat.py \ + build/pylib-android/statistics.py \ + build/pylib-android/string.py \ + build/pylib-android/stringprep.py \ + build/pylib-android/struct.py \ + build/pylib-android/subprocess.py \ + build/pylib-android/sunau.py \ + build/pylib-android/symbol.py \ + build/pylib-android/symtable.py \ + build/pylib-android/sysconfig.py \ + build/pylib-android/tabnanny.py \ + build/pylib-android/tarfile.py \ + build/pylib-android/telnetlib.py \ + build/pylib-android/tempfile.py \ + build/pylib-android/textwrap.py \ + build/pylib-android/this.py \ + build/pylib-android/threading.py \ + build/pylib-android/timeit.py \ + build/pylib-android/token.py \ + build/pylib-android/tokenize.py \ + build/pylib-android/trace.py \ + build/pylib-android/traceback.py \ + build/pylib-android/tracemalloc.py \ + build/pylib-android/tty.py \ + build/pylib-android/types.py \ + build/pylib-android/typing.py \ + build/pylib-android/urllib/__init__.py \ + build/pylib-android/urllib/error.py \ + build/pylib-android/urllib/parse.py \ + build/pylib-android/urllib/request.py \ + build/pylib-android/urllib/response.py \ + build/pylib-android/urllib/robotparser.py \ + build/pylib-android/uu.py \ + build/pylib-android/uuid.py \ + build/pylib-android/warnings.py \ + build/pylib-android/wave.py \ + build/pylib-android/weakref.py \ + build/pylib-android/webbrowser.py \ + build/pylib-android/xdrlib.py \ + build/pylib-android/xml/__init__.py \ + build/pylib-android/xml/dom/NodeFilter.py \ + build/pylib-android/xml/dom/__init__.py \ + build/pylib-android/xml/dom/domreg.py \ + build/pylib-android/xml/dom/expatbuilder.py \ + build/pylib-android/xml/dom/minicompat.py \ + build/pylib-android/xml/dom/minidom.py \ + build/pylib-android/xml/dom/pulldom.py \ + build/pylib-android/xml/dom/xmlbuilder.py \ + build/pylib-android/xml/etree/ElementInclude.py \ + build/pylib-android/xml/etree/ElementPath.py \ + build/pylib-android/xml/etree/ElementTree.py \ + build/pylib-android/xml/etree/__init__.py \ + build/pylib-android/xml/etree/cElementTree.py \ + build/pylib-android/xml/parsers/__init__.py \ + build/pylib-android/xml/parsers/expat.py \ + build/pylib-android/xml/sax/__init__.py \ + build/pylib-android/xml/sax/_exceptions.py \ + build/pylib-android/xml/sax/expatreader.py \ + build/pylib-android/xml/sax/handler.py \ + build/pylib-android/xml/sax/saxutils.py \ + build/pylib-android/xml/sax/xmlreader.py \ + build/pylib-android/xmlrpc/__init__.py \ + build/pylib-android/xmlrpc/client.py \ + build/pylib-android/xmlrpc/server.py \ + build/pylib-android/zipapp.py \ + build/pylib-android/zipfile.py SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ - build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ - build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc \ - build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc \ + build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ + build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ + build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc \ + build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc + build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ + build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc \ + build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc \ + build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc \ + build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ + build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc \ + build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc \ + build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc \ + build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc \ + build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc \ + build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ + build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ + build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ + build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ + build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -5763,58 +5763,8 @@ $(SCRIPT_TARGETS_PY_PRIVATE_ANDROID) : ../.efrocachemap # just generating explicit targets for each. Could perhaps look into using a # fancy for-loop instead, but perhaps listing these explicitly isn't so bad. -build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/pylib-android/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/pylib-android/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/pylib-android/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/pylib-android/queue.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/pylib-android/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/pylib-android/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/pylib-android/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/pylib-android/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/pylib-android/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/pylib-android/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncore.py +build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc: \ + build/pylib-android/__future__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -5823,613 +5773,8 @@ build/pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/pylib-android/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/pylib-android/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/pylib-android/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/pylib-android/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/pylib-android/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/pylib-android/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/pylib-android/trace.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/pylib-android/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/pylib-android/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/pylib-android/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/pylib-android/dis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/pylib-android/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/pylib-android/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/pylib-android/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/pylib-android/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/pylib-android/tty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/pylib-android/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/pylib-android/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/pylib-android/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ - build/pylib-android/token.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/pylib-android/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/pylib-android/base64.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/pylib-android/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/pylib-android/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/pylib-android/signal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/pylib-android/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/pylib-android/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/pylib-android/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/pylib-android/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/pylib-android/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/pylib-android/wave.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/pylib-android/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/pylib-android/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/pylib-android/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/pylib-android/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/pylib-android/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/pylib-android/functools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/pylib-android/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/pylib-android/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/pylib-android/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/pylib-android/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/pylib-android/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/pylib-android/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/pylib-android/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/pylib-android/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/pylib-android/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/pylib-android/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-android/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/pylib-android/profile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/pylib-android/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ - build/pylib-android/this.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/pylib-android/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/pylib-android/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/pylib-android/uu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/pylib-android/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ - build/pylib-android/io.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ - build/pylib-android/code.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/pylib-android/operator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/pylib-android/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ - build/pylib-android/os.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/pylib-android/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/pylib-android/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/pylib-android/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/pylib-android/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/pylib-android/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/pylib-android/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/pylib-android/copy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/pylib-android/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/pylib-android/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ - build/pylib-android/types.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/pylib-android/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/pylib-android/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/pylib-android/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/pylib-android/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/pylib-android/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/pylib-android/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/pylib-android/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ - build/pylib-android/random.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/pylib-android/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/pylib-android/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/pylib-android/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/pylib-android/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/pylib-android/threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/pylib-android/platform.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/pylib-android/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/pylib-android/glob.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/pylib-android/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/pylib-android/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/pylib-android/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/pylib-android/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/pylib-android/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/pylib-android/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/pylib-android/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/pylib-android/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/pylib-android/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/pylib-android/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ - build/pylib-android/site.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/pylib-android/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/pylib-android/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/pylib-android/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/pylib-android/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/pylib-android/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/pylib-android/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/pylib-android/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/pylib-android/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/pylib-android/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/pylib-android/stat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/pylib-android/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/pylib-android/csv.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/pylib-android/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/pylib-android/sched.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/pylib-android/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/pylib-android/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/pylib-android/locale.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/pylib-android/ast.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/pylib-android/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/pylib-android/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/pylib-android/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/pylib-android/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/pylib-android/pty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/pylib-android/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/pylib-android/statistics.py +build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ + build/pylib-android/_bootlocale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -6438,98 +5783,33 @@ build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/pylib-android/sunau.py +build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ + build/pylib-android/_compat_pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/pylib-android/__future__.py +build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc: \ + build/pylib-android/_compression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/pylib-android/dataclasses.py +build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ + build/pylib-android/_dummy_thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/pylib-android/shelve.py +build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ + build/pylib-android/_markupbase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ - build/pylib-android/string.py +build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ + build/pylib-android/_osx_support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/pylib-android/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/pylib-android/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/pylib-android/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/pylib-android/enum.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/pylib-android/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/pylib-android/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/pylib-android/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/pylib-android/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/pylib-android/typing.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/pylib-android/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/pylib-android/socket.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/pylib-android/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/pylib-android/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/pylib-android/pathlib.py +build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ + build/pylib-android/_py_abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -6538,58 +5818,28 @@ build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/pylib-android/ntpath.py +build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc: \ + build/pylib-android/_pyio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/pylib-android/tokenize.py +build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ + build/pylib-android/_sitebuiltins.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/pylib-android/uuid.py +build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc: \ + build/pylib-android/_strptime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/pylib-android/imp.py +build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ + build/pylib-android/_threading_local.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/pylib-android/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ - build/pylib-android/re.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/pylib-android/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/pylib-android/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/pylib-android/struct.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/pylib-android/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/pylib-android/sre_parse.py +build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ + build/pylib-android/_weakrefset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -6598,1341 +5848,2091 @@ build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/pylib-android/runpy.py +build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc: \ + build/pylib-android/aifc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/pylib-android/_bootlocale.py +build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc: \ + build/pylib-android/antigravity.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_romanian.py +build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc: \ + build/pylib-android/argparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_farsi.py +build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc: \ + build/pylib-android/ast.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/idna.py +build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc: \ + build/pylib-android/asynchat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp273.py +build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/punycode.py +build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/base_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/raw_unicode_escape.py +build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/base_futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_8.py +build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/base_subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1252.py +build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/base_tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp869.py +build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_14.py +build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/coroutines.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_2.py +build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_arabic.py +build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/format_helpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_croatian.py +build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/big5hkscs.py +build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/locks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1256.py +build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_6.py +build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/proactor_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_10.py +build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/protocols.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_kr.py +build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1140.py +build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/runners.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/unicode_internal.py +build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/selector_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1125.py +build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/sslproto.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_1.py +build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/streams.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1257.py +build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp949.py +build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp858.py +build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/transports.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_7.py +build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/unix_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_11.py +build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/windows_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/hp_roman8.py +build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncio/windows_utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/koi8_r.py +build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ + build/pylib-android/asyncore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/zlib_codec.py +build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ + build/pylib-android/base64.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/gbk.py +build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ + build/pylib-android/bdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/johab.py +build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ + build/pylib-android/binhex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1253.py +build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ + build/pylib-android/bisect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_15.py +build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ + build/pylib-android/bz2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_2004.py +build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ + build/pylib-android/cProfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_iceland.py +build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ + build/pylib-android/calendar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_3.py +build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ + build/pylib-android/cgi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_greek.py +build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ + build/pylib-android/cgitb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/rot_13.py +build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ + build/pylib-android/chunk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_16_be.py +build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ + build/pylib-android/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_kr.py +build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ + build/pylib-android/code.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_centeuro.py +build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ + build/pylib-android/codecs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_jisx0213.py +build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ + build/pylib-android/codeop.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp863.py +build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ + build/pylib-android/collections/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/ascii.py +build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ + build/pylib-android/collections/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_8.py +build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ + build/pylib-android/colorsys.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp857.py +build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ + build/pylib-android/compileall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_32_be.py +build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ + build/pylib-android/concurrent/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1258.py +build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ + build/pylib-android/concurrent/futures/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/oem.py +build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ + build/pylib-android/concurrent/futures/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_latin2.py +build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ + build/pylib-android/concurrent/futures/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp775.py +build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ + build/pylib-android/concurrent/futures/thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_roman.py +build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ + build/pylib-android/configparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/__init__.py +build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ + build/pylib-android/contextlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp852.py +build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ + build/pylib-android/contextvars.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/shift_jisx0213.py +build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ + build/pylib-android/copy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp866.py +build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ + build/pylib-android/copyreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_7.py +build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ + build/pylib-android/crypt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/base64_codec.py +build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ + build/pylib-android/csv.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/ptcp154.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_8_sig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/koi8_t.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1026.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/charmap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_5.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_13.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/_aix.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ + build/pylib-android/ctypes/_aix.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_endian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ + build/pylib-android/ctypes/macholib/dyld.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dylib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/textpad.py +build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ + build/pylib-android/ctypes/macholib/framework.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/ascii.py +build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ + build/pylib-android/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ + build/pylib-android/ctypes/wintypes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-android/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ + build/pylib-android/curses/ascii.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-android/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-android/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/error.py +build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ + build/pylib-android/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/request.py +build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ + build/pylib-android/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/__init__.py +build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ + build/pylib-android/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/response.py +build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ + build/pylib-android/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/robotparser.py +build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ + build/pylib-android/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/parse.py +build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ + build/pylib-android/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ + build/pylib-android/doctest.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ + build/pylib-android/dummy_threading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ + build/pylib-android/email/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ + build/pylib-android/email/_encoded_words.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ + build/pylib-android/email/_header_value_parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ + build/pylib-android/email/_parseaddr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ + build/pylib-android/email/_policybase.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ + build/pylib-android/email/base64mime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ + build/pylib-android/email/charset.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ + build/pylib-android/email/contentmanager.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ + build/pylib-android/email/encoders.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ + build/pylib-android/email/errors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ + build/pylib-android/email/feedparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ + build/pylib-android/email/generator.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ + build/pylib-android/email/header.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ + build/pylib-android/email/headerregistry.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ + build/pylib-android/email/iterators.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ + build/pylib-android/email/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/application.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/audio.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/image.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/multipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/nonmultipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ + build/pylib-android/email/mime/text.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ + build/pylib-android/email/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ + build/pylib-android/email/policy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ + build/pylib-android/email/quoprimime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ + build/pylib-android/email/utils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/aliases.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/ascii.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/base64_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/big5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/big5hkscs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/bz2_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/charmap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp037.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1006.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1026.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1125.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1140.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1250.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1251.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1252.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1253.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1254.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1255.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1256.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1257.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp1258.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp273.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp424.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp437.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp500.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp65001.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp720.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp737.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp775.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp850.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp852.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp855.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp856.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp857.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp858.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp860.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp861.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp862.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp863.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp864.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp865.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp866.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp869.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp874.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp875.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp932.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp949.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/cp950.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/euc_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/euc_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/euc_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/euc_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/gb18030.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/gb2312.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/gbk.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/hex_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/hp_roman8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/hz.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/idna.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_jp_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_jp_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_jp_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_jp_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_jp_ext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso2022_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_10.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_11.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_14.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_15.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_4.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_6.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_7.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/iso8859_9.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/johab.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/koi8_r.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/koi8_t.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/koi8_u.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/kz1048.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/latin_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_arabic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_centeuro.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_croatian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_cyrillic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_farsi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_greek.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_iceland.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_latin2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_roman.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_romanian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mac_turkish.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/mbcs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/oem.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/palmos.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/ptcp154.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/punycode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/quopri_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/raw_unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/rot_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/shift_jis.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/shift_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/shift_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/tis_620.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/undefined.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/unicode_internal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_16_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_16_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_32.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_32_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_32_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_7.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/utf_8_sig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/uu_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ + build/pylib-android/encodings/zlib_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ + build/pylib-android/enum.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ + build/pylib-android/filecmp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ + build/pylib-android/fileinput.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ + build/pylib-android/fnmatch.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ + build/pylib-android/formatter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ + build/pylib-android/fractions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ + build/pylib-android/ftplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ + build/pylib-android/functools.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ + build/pylib-android/genericpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ + build/pylib-android/getopt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ + build/pylib-android/getpass.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ + build/pylib-android/gettext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ + build/pylib-android/glob.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ + build/pylib-android/gzip.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ + build/pylib-android/hashlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ + build/pylib-android/heapq.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ + build/pylib-android/hmac.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-android/html/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-android/html/parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-android/html/entities.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ + build/pylib-android/html/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ + build/pylib-android/http/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ + build/pylib-android/http/client.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ + build/pylib-android/http/cookiejar.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ + build/pylib-android/http/cookies.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ + build/pylib-android/http/server.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ + build/pylib-android/imghdr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ + build/pylib-android/imp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/_bootstrap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/_bootstrap_external.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/abc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/machinery.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/resources.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ + build/pylib-android/importlib/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ + build/pylib-android/inspect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ + build/pylib-android/io.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ + build/pylib-android/ipaddress.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ + build/pylib-android/json/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ + build/pylib-android/json/decoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ + build/pylib-android/json/encoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ + build/pylib-android/json/scanner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ + build/pylib-android/json/tool.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ + build/pylib-android/keyword.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ + build/pylib-android/linecache.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ + build/pylib-android/locale.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ + build/pylib-android/logging/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ + build/pylib-android/logging/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ + build/pylib-android/logging/handlers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ + build/pylib-android/lzma.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ + build/pylib-android/macpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ + build/pylib-android/mailbox.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ + build/pylib-android/mailcap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ + build/pylib-android/mimetypes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ + build/pylib-android/modulefinder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ + build/pylib-android/netrc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ + build/pylib-android/nntplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ + build/pylib-android/ntpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ + build/pylib-android/nturl2path.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ + build/pylib-android/numbers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ + build/pylib-android/opcode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ + build/pylib-android/operator.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ + build/pylib-android/optparse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ + build/pylib-android/os.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ + build/pylib-android/pathlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ + build/pylib-android/pdb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ + build/pylib-android/pickle.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ + build/pylib-android/pickletools.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ + build/pylib-android/pipes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ + build/pylib-android/pkgutil.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ + build/pylib-android/platform.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ + build/pylib-android/plistlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ + build/pylib-android/poplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ + build/pylib-android/posixpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ + build/pylib-android/pprint.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ + build/pylib-android/profile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ + build/pylib-android/pstats.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ + build/pylib-android/pty.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ + build/pylib-android/py_compile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ + build/pylib-android/pyclbr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ + build/pylib-android/pydoc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ + build/pylib-android/queue.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ + build/pylib-android/quopri.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ + build/pylib-android/random.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ + build/pylib-android/re.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ + build/pylib-android/reprlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ + build/pylib-android/rlcompleter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ + build/pylib-android/runpy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ + build/pylib-android/sched.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ + build/pylib-android/secrets.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ + build/pylib-android/selectors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ + build/pylib-android/shelve.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ + build/pylib-android/shlex.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ + build/pylib-android/shutil.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ + build/pylib-android/signal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ + build/pylib-android/site.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ + build/pylib-android/smtpd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ + build/pylib-android/smtplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ + build/pylib-android/sndhdr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ + build/pylib-android/socket.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ + build/pylib-android/socketserver.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ + build/pylib-android/sqlite3/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ + build/pylib-android/sqlite3/dbapi2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ + build/pylib-android/sqlite3/dump.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ + build/pylib-android/sre_compile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ + build/pylib-android/sre_constants.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ + build/pylib-android/sre_parse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ + build/pylib-android/ssl.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ + build/pylib-android/stat.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ + build/pylib-android/statistics.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ + build/pylib-android/string.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ + build/pylib-android/stringprep.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ + build/pylib-android/struct.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ + build/pylib-android/subprocess.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ + build/pylib-android/sunau.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ + build/pylib-android/symbol.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ + build/pylib-android/symtable.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/sysconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ + build/pylib-android/tabnanny.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/pylib-android/tarfile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/telnetlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ + build/pylib-android/tempfile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ + build/pylib-android/textwrap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ + build/pylib-android/this.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ + build/pylib-android/threading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/timeit.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ + build/pylib-android/token.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ + build/pylib-android/tokenize.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/pylib-android/trace.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ + build/pylib-android/traceback.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ + build/pylib-android/tracemalloc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ + build/pylib-android/tty.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/types.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ + build/pylib-android/typing.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ + build/pylib-android/urllib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ + build/pylib-android/urllib/error.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ + build/pylib-android/urllib/parse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/urllib/request.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ + build/pylib-android/urllib/response.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ + build/pylib-android/urllib/robotparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/uu.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ + build/pylib-android/uuid.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ + build/pylib-android/warnings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/wave.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ + build/pylib-android/weakref.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ + build/pylib-android/webbrowser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ + build/pylib-android/xdrlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-android/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/parsers/expat.py +build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/parsers/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/handler.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/saxutils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/xmlreader.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/expatreader.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/NodeFilter.py + build/pylib-android/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/xmlbuilder.py +build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/dom/minicompat.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/dom/pulldom.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/dom/xmlbuilder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/etree/ElementInclude.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/etree/ElementTree.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/etree/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/__init__.py + build/pylib-android/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/ElementInclude.py +build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/ElementTree.py +build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/pylib-android/json/decoder.py +build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/pylib-android/json/scanner.py +build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/json/__init__.py +build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/pylib-android/json/encoder.py +build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/pylib-android/json/tool.py +build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ + build/pylib-android/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/pylib-android/http/cookies.py +build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ + build/pylib-android/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-android/http/server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/pylib-android/http/client.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/http/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/pylib-android/http/cookiejar.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/sqlite3/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/pylib-android/sqlite3/dump.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/pylib-android/sqlite3/dbapi2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-android/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xmlrpc/__init__.py + build/pylib-android/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/collections/__init__.py +build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ + build/pylib-android/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-android/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/pylib-android/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/pylib-android/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/pylib-android/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/pylib-android/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/pylib-android/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-android/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/pylib-android/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-android/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/pylib-android/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/pylib-android/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/pylib-android/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/pylib-android/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/pylib-android/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/pylib-android/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/pylib-android/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/pylib-android/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/pylib-android/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/base.py +build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ + build/pylib-android/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_COMMON = \ build/ba_data/python-site-packages/typing_extensions.py \ - build/ba_data/python-site-packages/yaml/scanner.py \ - build/ba_data/python-site-packages/yaml/error.py \ - build/ba_data/python-site-packages/yaml/constructor.py \ - build/ba_data/python-site-packages/yaml/composer.py \ - build/ba_data/python-site-packages/yaml/events.py \ build/ba_data/python-site-packages/yaml/__init__.py \ - build/ba_data/python-site-packages/yaml/representer.py \ - build/ba_data/python-site-packages/yaml/tokens.py \ - build/ba_data/python-site-packages/yaml/dumper.py \ + build/ba_data/python-site-packages/yaml/composer.py \ + build/ba_data/python-site-packages/yaml/constructor.py \ build/ba_data/python-site-packages/yaml/cyaml.py \ + build/ba_data/python-site-packages/yaml/dumper.py \ + build/ba_data/python-site-packages/yaml/emitter.py \ + build/ba_data/python-site-packages/yaml/error.py \ + build/ba_data/python-site-packages/yaml/events.py \ + build/ba_data/python-site-packages/yaml/loader.py \ + build/ba_data/python-site-packages/yaml/nodes.py \ build/ba_data/python-site-packages/yaml/parser.py \ build/ba_data/python-site-packages/yaml/reader.py \ - build/ba_data/python-site-packages/yaml/loader.py \ + build/ba_data/python-site-packages/yaml/representer.py \ build/ba_data/python-site-packages/yaml/resolver.py \ + build/ba_data/python-site-packages/yaml/scanner.py \ build/ba_data/python-site-packages/yaml/serializer.py \ - build/ba_data/python-site-packages/yaml/nodes.py \ - build/ba_data/python-site-packages/yaml/emitter.py + build/ba_data/python-site-packages/yaml/tokens.py SCRIPT_TARGETS_PYC_PRIVATE_COMMON = \ build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc \ build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc \ build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc \ build/ba_data/python-site-packages/yaml/__pycache__/parser.cpython-37.opt-1.pyc \ build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc \ build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc \ build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc + build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -7948,18 +7948,8 @@ build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt- @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/scanner.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/error.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/constructor.py +build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -7968,23 +7958,13 @@ build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/events.py +build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/constructor.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/representer.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/tokens.py +build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/cyaml.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -7993,8 +7973,28 @@ build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc: @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/cyaml.py +build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/emitter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/error.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/loader.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/nodes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -8008,8 +8008,8 @@ build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc: @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/loader.py +build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/representer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -8018,1361 +8018,1361 @@ build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/scanner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/serializer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/nodes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/emitter.py +build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc: \ + build/ba_data/python-site-packages/yaml/tokens.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ - build/windows/Win32/Lib/zipfile.py \ - build/windows/Win32/Lib/shutil.py \ - build/windows/Win32/Lib/tempfile.py \ - build/windows/Win32/Lib/queue.py \ - build/windows/Win32/Lib/macpath.py \ - build/windows/Win32/Lib/_pyio.py \ - build/windows/Win32/Lib/crypt.py \ - build/windows/Win32/Lib/pkgutil.py \ - build/windows/Win32/Lib/_dummy_thread.py \ - build/windows/Win32/Lib/lzma.py \ - build/windows/Win32/Lib/asyncore.py \ - build/windows/Win32/Lib/__phello__.foo.py \ - build/windows/Win32/Lib/_sitebuiltins.py \ - build/windows/Win32/Lib/copyreg.py \ - build/windows/Win32/Lib/sndhdr.py \ - build/windows/Win32/Lib/rlcompleter.py \ - build/windows/Win32/Lib/gzip.py \ - build/windows/Win32/Lib/ipaddress.py \ - build/windows/Win32/Lib/trace.py \ - build/windows/Win32/Lib/webbrowser.py \ - build/windows/Win32/Lib/nntplib.py \ - build/windows/Win32/Lib/_compat_pickle.py \ - build/windows/Win32/Lib/dis.py \ - build/windows/Win32/Lib/formatter.py \ - build/windows/Win32/Lib/bdb.py \ - build/windows/Win32/Lib/zipapp.py \ - build/windows/Win32/Lib/cmd.py \ - build/windows/Win32/Lib/tty.py \ - build/windows/Win32/Lib/tabnanny.py \ - build/windows/Win32/Lib/_py_abc.py \ - build/windows/Win32/Lib/cProfile.py \ - build/windows/Win32/Lib/token.py \ - build/windows/Win32/Lib/textwrap.py \ - build/windows/Win32/Lib/base64.py \ - build/windows/Win32/Lib/_markupbase.py \ - build/windows/Win32/Lib/bz2.py \ - build/windows/Win32/Lib/signal.py \ - build/windows/Win32/Lib/sre_constants.py \ - build/windows/Win32/Lib/cgitb.py \ - build/windows/Win32/Lib/_threading_local.py \ - build/windows/Win32/Lib/pyclbr.py \ - build/windows/Win32/Lib/gettext.py \ - build/windows/Win32/Lib/wave.py \ - build/windows/Win32/Lib/weakref.py \ - build/windows/Win32/Lib/bisect.py \ - build/windows/Win32/Lib/opcode.py \ - build/windows/Win32/Lib/netrc.py \ - build/windows/Win32/Lib/heapq.py \ - build/windows/Win32/Lib/functools.py \ - build/windows/Win32/Lib/modulefinder.py \ - build/windows/Win32/Lib/_compression.py \ - build/windows/Win32/Lib/tracemalloc.py \ - build/windows/Win32/Lib/hashlib.py \ - build/windows/Win32/Lib/cgi.py \ - build/windows/Win32/Lib/codeop.py \ - build/windows/Win32/Lib/fnmatch.py \ - build/windows/Win32/Lib/traceback.py \ - build/windows/Win32/Lib/nturl2path.py \ - build/windows/Win32/Lib/warnings.py \ - build/windows/Win32/Lib/subprocess.py \ - build/windows/Win32/Lib/profile.py \ - build/windows/Win32/Lib/imghdr.py \ - build/windows/Win32/Lib/this.py \ - build/windows/Win32/Lib/filecmp.py \ - build/windows/Win32/Lib/codecs.py \ - build/windows/Win32/Lib/uu.py \ - build/windows/Win32/Lib/_weakrefset.py \ - build/windows/Win32/Lib/io.py \ - build/windows/Win32/Lib/code.py \ - build/windows/Win32/Lib/operator.py \ - build/windows/Win32/Lib/fileinput.py \ - build/windows/Win32/Lib/os.py \ - build/windows/Win32/Lib/difflib.py \ - build/windows/Win32/Lib/pydoc.py \ - build/windows/Win32/Lib/symbol.py \ - build/windows/Win32/Lib/selectors.py \ - build/windows/Win32/Lib/decimal.py \ - build/windows/Win32/Lib/socketserver.py \ - build/windows/Win32/Lib/copy.py \ - build/windows/Win32/Lib/genericpath.py \ - build/windows/Win32/Lib/linecache.py \ - build/windows/Win32/Lib/types.py \ - build/windows/Win32/Lib/mimetypes.py \ - build/windows/Win32/Lib/xdrlib.py \ - build/windows/Win32/Lib/colorsys.py \ - build/windows/Win32/Lib/numbers.py \ - build/windows/Win32/Lib/_strptime.py \ - build/windows/Win32/Lib/dummy_threading.py \ - build/windows/Win32/Lib/contextvars.py \ - build/windows/Win32/Lib/random.py \ - build/windows/Win32/Lib/ftplib.py \ - build/windows/Win32/Lib/chunk.py \ - build/windows/Win32/Lib/optparse.py \ - build/windows/Win32/Lib/pdb.py \ - build/windows/Win32/Lib/threading.py \ - build/windows/Win32/Lib/turtle.py \ - build/windows/Win32/Lib/platform.py \ - build/windows/Win32/Lib/pstats.py \ - build/windows/Win32/Lib/glob.py \ - build/windows/Win32/Lib/quopri.py \ - build/windows/Win32/Lib/symtable.py \ - build/windows/Win32/Lib/pprint.py \ - build/windows/Win32/Lib/calendar.py \ - build/windows/Win32/Lib/inspect.py \ - build/windows/Win32/Lib/poplib.py \ - build/windows/Win32/Lib/binhex.py \ - build/windows/Win32/Lib/plistlib.py \ - build/windows/Win32/Lib/pickletools.py \ - build/windows/Win32/Lib/pipes.py \ - build/windows/Win32/Lib/site.py \ - build/windows/Win32/Lib/telnetlib.py \ - build/windows/Win32/Lib/keyword.py \ - build/windows/Win32/Lib/configparser.py \ - build/windows/Win32/Lib/reprlib.py \ - build/windows/Win32/Lib/secrets.py \ - build/windows/Win32/Lib/shlex.py \ - build/windows/Win32/Lib/posixpath.py \ - build/windows/Win32/Lib/py_compile.py \ - build/windows/Win32/Lib/_osx_support.py \ - build/windows/Win32/Lib/stat.py \ - build/windows/Win32/Lib/compileall.py \ - build/windows/Win32/Lib/csv.py \ - build/windows/Win32/Lib/fractions.py \ - build/windows/Win32/Lib/sched.py \ - build/windows/Win32/Lib/imaplib.py \ - build/windows/Win32/Lib/mailbox.py \ - build/windows/Win32/Lib/sre_compile.py \ - build/windows/Win32/Lib/locale.py \ - build/windows/Win32/Lib/ast.py \ - build/windows/Win32/Lib/doctest.py \ - build/windows/Win32/Lib/argparse.py \ - build/windows/Win32/Lib/getpass.py \ - build/windows/Win32/Lib/pickle.py \ - build/windows/Win32/Lib/pty.py \ - build/windows/Win32/Lib/contextlib.py \ - build/windows/Win32/Lib/statistics.py \ - build/windows/Win32/Lib/_collections_abc.py \ - build/windows/Win32/Lib/sunau.py \ build/windows/Win32/Lib/__future__.py \ - build/windows/Win32/Lib/dataclasses.py \ - build/windows/Win32/Lib/shelve.py \ - build/windows/Win32/Lib/string.py \ - build/windows/Win32/Lib/smtplib.py \ - build/windows/Win32/Lib/getopt.py \ - build/windows/Win32/Lib/antigravity.py \ - build/windows/Win32/Lib/enum.py \ - build/windows/Win32/Lib/timeit.py \ - build/windows/Win32/Lib/hmac.py \ - build/windows/Win32/Lib/tarfile.py \ - build/windows/Win32/Lib/stringprep.py \ - build/windows/Win32/Lib/typing.py \ - build/windows/Win32/Lib/ssl.py \ - build/windows/Win32/Lib/socket.py \ - build/windows/Win32/Lib/datetime.py \ - build/windows/Win32/Lib/sysconfig.py \ - build/windows/Win32/Lib/pathlib.py \ - build/windows/Win32/Lib/_pydecimal.py \ - build/windows/Win32/Lib/ntpath.py \ - build/windows/Win32/Lib/tokenize.py \ - build/windows/Win32/Lib/uuid.py \ - build/windows/Win32/Lib/imp.py \ - build/windows/Win32/Lib/smtpd.py \ - build/windows/Win32/Lib/re.py \ - build/windows/Win32/Lib/mailcap.py \ - build/windows/Win32/Lib/aifc.py \ - build/windows/Win32/Lib/struct.py \ - build/windows/Win32/Lib/asynchat.py \ - build/windows/Win32/Lib/sre_parse.py \ - build/windows/Win32/Lib/abc.py \ - build/windows/Win32/Lib/runpy.py \ + build/windows/Win32/Lib/__phello__.foo.py \ build/windows/Win32/Lib/_bootlocale.py \ - build/windows/Win32/Lib/encodings/mac_romanian.py \ - build/windows/Win32/Lib/encodings/mac_farsi.py \ - build/windows/Win32/Lib/encodings/idna.py \ - build/windows/Win32/Lib/encodings/cp273.py \ - build/windows/Win32/Lib/encodings/punycode.py \ - build/windows/Win32/Lib/encodings/raw_unicode_escape.py \ - build/windows/Win32/Lib/encodings/utf_8.py \ - build/windows/Win32/Lib/encodings/cp1252.py \ - build/windows/Win32/Lib/encodings/cp869.py \ - build/windows/Win32/Lib/encodings/iso8859_14.py \ - build/windows/Win32/Lib/encodings/iso8859_2.py \ - build/windows/Win32/Lib/encodings/mac_arabic.py \ - build/windows/Win32/Lib/encodings/mac_croatian.py \ - build/windows/Win32/Lib/encodings/big5hkscs.py \ - build/windows/Win32/Lib/encodings/cp1256.py \ - build/windows/Win32/Lib/encodings/iso8859_6.py \ - build/windows/Win32/Lib/encodings/iso8859_10.py \ - build/windows/Win32/Lib/encodings/iso2022_kr.py \ - build/windows/Win32/Lib/encodings/cp1140.py \ - build/windows/Win32/Lib/encodings/unicode_internal.py \ - build/windows/Win32/Lib/encodings/cp1125.py \ - build/windows/Win32/Lib/encodings/iso2022_jp_1.py \ - build/windows/Win32/Lib/encodings/cp1257.py \ - build/windows/Win32/Lib/encodings/cp949.py \ - build/windows/Win32/Lib/encodings/cp858.py \ - build/windows/Win32/Lib/encodings/iso8859_7.py \ - build/windows/Win32/Lib/encodings/iso8859_11.py \ - build/windows/Win32/Lib/encodings/hp_roman8.py \ - build/windows/Win32/Lib/encodings/koi8_r.py \ - build/windows/Win32/Lib/encodings/zlib_codec.py \ - build/windows/Win32/Lib/encodings/gbk.py \ - build/windows/Win32/Lib/encodings/johab.py \ - build/windows/Win32/Lib/encodings/cp1253.py \ - build/windows/Win32/Lib/encodings/iso8859_15.py \ - build/windows/Win32/Lib/encodings/iso2022_jp_2004.py \ - build/windows/Win32/Lib/encodings/mac_iceland.py \ - build/windows/Win32/Lib/encodings/iso8859_3.py \ - build/windows/Win32/Lib/encodings/mac_greek.py \ - build/windows/Win32/Lib/encodings/rot_13.py \ - build/windows/Win32/Lib/encodings/utf_16_be.py \ - build/windows/Win32/Lib/encodings/euc_kr.py \ - build/windows/Win32/Lib/encodings/mac_centeuro.py \ - build/windows/Win32/Lib/encodings/euc_jisx0213.py \ - build/windows/Win32/Lib/encodings/cp863.py \ - build/windows/Win32/Lib/encodings/ascii.py \ - build/windows/Win32/Lib/encodings/iso8859_8.py \ - build/windows/Win32/Lib/encodings/cp857.py \ - build/windows/Win32/Lib/encodings/utf_32_be.py \ - build/windows/Win32/Lib/encodings/cp1258.py \ - build/windows/Win32/Lib/encodings/oem.py \ - build/windows/Win32/Lib/encodings/mac_latin2.py \ - build/windows/Win32/Lib/encodings/cp775.py \ - build/windows/Win32/Lib/encodings/mac_roman.py \ - build/windows/Win32/Lib/encodings/__init__.py \ - build/windows/Win32/Lib/encodings/cp852.py \ - build/windows/Win32/Lib/encodings/shift_jisx0213.py \ - build/windows/Win32/Lib/encodings/cp866.py \ - build/windows/Win32/Lib/encodings/utf_7.py \ - build/windows/Win32/Lib/encodings/base64_codec.py \ - build/windows/Win32/Lib/encodings/cp932.py \ - build/windows/Win32/Lib/encodings/cp720.py \ - build/windows/Win32/Lib/encodings/cp862.py \ - build/windows/Win32/Lib/encodings/cp437.py \ - build/windows/Win32/Lib/encodings/palmos.py \ - build/windows/Win32/Lib/encodings/iso8859_9.py \ - build/windows/Win32/Lib/encodings/cp856.py \ - build/windows/Win32/Lib/encodings/aliases.py \ - build/windows/Win32/Lib/encodings/latin_1.py \ - build/windows/Win32/Lib/encodings/cp875.py \ - build/windows/Win32/Lib/encodings/cp950.py \ - build/windows/Win32/Lib/encodings/unicode_escape.py \ - build/windows/Win32/Lib/encodings/cp737.py \ - build/windows/Win32/Lib/encodings/cp865.py \ - build/windows/Win32/Lib/encodings/ptcp154.py \ - build/windows/Win32/Lib/encodings/big5.py \ - build/windows/Win32/Lib/encodings/cp424.py \ - build/windows/Win32/Lib/encodings/cp861.py \ - build/windows/Win32/Lib/encodings/euc_jp.py \ - build/windows/Win32/Lib/encodings/cp855.py \ - build/windows/Win32/Lib/encodings/shift_jis.py \ - build/windows/Win32/Lib/encodings/utf_32_le.py \ - build/windows/Win32/Lib/encodings/cp500.py \ - build/windows/Win32/Lib/encodings/undefined.py \ - build/windows/Win32/Lib/encodings/cp860.py \ - build/windows/Win32/Lib/encodings/uu_codec.py \ - build/windows/Win32/Lib/encodings/utf_16_le.py \ - build/windows/Win32/Lib/encodings/gb18030.py \ - build/windows/Win32/Lib/encodings/cp65001.py \ - build/windows/Win32/Lib/encodings/cp874.py \ - build/windows/Win32/Lib/encodings/cp850.py \ - build/windows/Win32/Lib/encodings/cp864.py \ - build/windows/Win32/Lib/encodings/utf_32.py \ - build/windows/Win32/Lib/encodings/koi8_u.py \ - build/windows/Win32/Lib/encodings/cp1254.py \ - build/windows/Win32/Lib/encodings/iso2022_jp_2.py \ - build/windows/Win32/Lib/encodings/utf_16.py \ - build/windows/Win32/Lib/encodings/iso8859_4.py \ - build/windows/Win32/Lib/encodings/euc_jis_2004.py \ - build/windows/Win32/Lib/encodings/mbcs.py \ - build/windows/Win32/Lib/encodings/cp1250.py \ - build/windows/Win32/Lib/encodings/gb2312.py \ - build/windows/Win32/Lib/encodings/iso8859_16.py \ - build/windows/Win32/Lib/encodings/mac_cyrillic.py \ - build/windows/Win32/Lib/encodings/hex_codec.py \ - build/windows/Win32/Lib/encodings/tis_620.py \ - build/windows/Win32/Lib/encodings/cp037.py \ - build/windows/Win32/Lib/encodings/cp1006.py \ - build/windows/Win32/Lib/encodings/cp1251.py \ - build/windows/Win32/Lib/encodings/mac_turkish.py \ - build/windows/Win32/Lib/encodings/iso2022_jp_ext.py \ - build/windows/Win32/Lib/encodings/iso8859_1.py \ - build/windows/Win32/Lib/encodings/hz.py \ - build/windows/Win32/Lib/encodings/bz2_codec.py \ - build/windows/Win32/Lib/encodings/quopri_codec.py \ - build/windows/Win32/Lib/encodings/kz1048.py \ - build/windows/Win32/Lib/encodings/utf_8_sig.py \ - build/windows/Win32/Lib/encodings/koi8_t.py \ - build/windows/Win32/Lib/encodings/cp1255.py \ - build/windows/Win32/Lib/encodings/iso2022_jp_3.py \ - build/windows/Win32/Lib/encodings/shift_jis_2004.py \ - build/windows/Win32/Lib/encodings/cp1026.py \ - build/windows/Win32/Lib/encodings/charmap.py \ - build/windows/Win32/Lib/encodings/iso8859_5.py \ - build/windows/Win32/Lib/encodings/iso8859_13.py \ - build/windows/Win32/Lib/encodings/iso2022_jp.py \ - build/windows/Win32/Lib/distutils/_msvccompiler.py \ - build/windows/Win32/Lib/distutils/unixccompiler.py \ - build/windows/Win32/Lib/distutils/filelist.py \ - build/windows/Win32/Lib/distutils/ccompiler.py \ - build/windows/Win32/Lib/distutils/msvc9compiler.py \ - build/windows/Win32/Lib/distutils/archive_util.py \ - build/windows/Win32/Lib/distutils/cmd.py \ - build/windows/Win32/Lib/distutils/config.py \ - build/windows/Win32/Lib/distutils/version.py \ - build/windows/Win32/Lib/distutils/log.py \ - build/windows/Win32/Lib/distutils/util.py \ - build/windows/Win32/Lib/distutils/fancy_getopt.py \ - build/windows/Win32/Lib/distutils/versionpredicate.py \ - build/windows/Win32/Lib/distutils/__init__.py \ - build/windows/Win32/Lib/distutils/file_util.py \ - build/windows/Win32/Lib/distutils/core.py \ - build/windows/Win32/Lib/distutils/cygwinccompiler.py \ - build/windows/Win32/Lib/distutils/extension.py \ - build/windows/Win32/Lib/distutils/debug.py \ - build/windows/Win32/Lib/distutils/spawn.py \ - build/windows/Win32/Lib/distutils/text_file.py \ - build/windows/Win32/Lib/distutils/msvccompiler.py \ - build/windows/Win32/Lib/distutils/errors.py \ - build/windows/Win32/Lib/distutils/dep_util.py \ - build/windows/Win32/Lib/distutils/dir_util.py \ - build/windows/Win32/Lib/distutils/sysconfig.py \ - build/windows/Win32/Lib/distutils/dist.py \ - build/windows/Win32/Lib/distutils/bcppcompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist.py \ - build/windows/Win32/Lib/distutils/tests/test_text_file.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py \ - build/windows/Win32/Lib/distutils/tests/test_version.py \ - build/windows/Win32/Lib/distutils/tests/test_install_lib.py \ - build/windows/Win32/Lib/distutils/tests/test_build_py.py \ - build/windows/Win32/Lib/distutils/tests/test_extension.py \ - build/windows/Win32/Lib/distutils/tests/test_spawn.py \ - build/windows/Win32/Lib/distutils/tests/support.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py \ - build/windows/Win32/Lib/distutils/tests/test_install_data.py \ - build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py \ - build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_filelist.py \ - build/windows/Win32/Lib/distutils/tests/test_core.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py \ - build/windows/Win32/Lib/distutils/tests/test_cmd.py \ - build/windows/Win32/Lib/distutils/tests/__init__.py \ - build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_sysconfig.py \ - build/windows/Win32/Lib/distutils/tests/test_util.py \ - build/windows/Win32/Lib/distutils/tests/test_build_clib.py \ - build/windows/Win32/Lib/distutils/tests/test_register.py \ - build/windows/Win32/Lib/distutils/tests/test_log.py \ - build/windows/Win32/Lib/distutils/tests/test_dep_util.py \ - build/windows/Win32/Lib/distutils/tests/test_build.py \ - build/windows/Win32/Lib/distutils/tests/test_install_scripts.py \ - build/windows/Win32/Lib/distutils/tests/test_build_ext.py \ - build/windows/Win32/Lib/distutils/tests/test_dir_util.py \ - build/windows/Win32/Lib/distutils/tests/test_install_headers.py \ - build/windows/Win32/Lib/distutils/tests/test_clean.py \ - build/windows/Win32/Lib/distutils/tests/test_check.py \ - build/windows/Win32/Lib/distutils/tests/test_config.py \ - build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py \ - build/windows/Win32/Lib/distutils/tests/test_upload.py \ - build/windows/Win32/Lib/distutils/tests/test_build_scripts.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py \ - build/windows/Win32/Lib/distutils/tests/test_file_util.py \ - build/windows/Win32/Lib/distutils/tests/test_dist.py \ - build/windows/Win32/Lib/distutils/tests/test_install.py \ - build/windows/Win32/Lib/distutils/tests/test_config_cmd.py \ - build/windows/Win32/Lib/distutils/tests/test_sdist.py \ - build/windows/Win32/Lib/distutils/tests/test_archive_util.py \ - build/windows/Win32/Lib/distutils/command/build.py \ - build/windows/Win32/Lib/distutils/command/build_ext.py \ - build/windows/Win32/Lib/distutils/command/config.py \ - build/windows/Win32/Lib/distutils/command/clean.py \ - build/windows/Win32/Lib/distutils/command/check.py \ - build/windows/Win32/Lib/distutils/command/install_scripts.py \ - build/windows/Win32/Lib/distutils/command/upload.py \ - build/windows/Win32/Lib/distutils/command/register.py \ - build/windows/Win32/Lib/distutils/command/bdist_wininst.py \ - build/windows/Win32/Lib/distutils/command/install_headers.py \ - build/windows/Win32/Lib/distutils/command/install_lib.py \ - build/windows/Win32/Lib/distutils/command/build_py.py \ - build/windows/Win32/Lib/distutils/command/bdist_dumb.py \ - build/windows/Win32/Lib/distutils/command/__init__.py \ - build/windows/Win32/Lib/distutils/command/sdist.py \ - build/windows/Win32/Lib/distutils/command/bdist.py \ - build/windows/Win32/Lib/distutils/command/build_scripts.py \ - build/windows/Win32/Lib/distutils/command/bdist_rpm.py \ - build/windows/Win32/Lib/distutils/command/build_clib.py \ - build/windows/Win32/Lib/distutils/command/install.py \ - build/windows/Win32/Lib/distutils/command/bdist_msi.py \ - build/windows/Win32/Lib/distutils/command/install_egg_info.py \ - build/windows/Win32/Lib/distutils/command/install_data.py \ - build/windows/Win32/Lib/ctypes/_aix.py \ - build/windows/Win32/Lib/ctypes/wintypes.py \ - build/windows/Win32/Lib/ctypes/util.py \ + build/windows/Win32/Lib/_collections_abc.py \ + build/windows/Win32/Lib/_compat_pickle.py \ + build/windows/Win32/Lib/_compression.py \ + build/windows/Win32/Lib/_dummy_thread.py \ + build/windows/Win32/Lib/_markupbase.py \ + build/windows/Win32/Lib/_osx_support.py \ + build/windows/Win32/Lib/_py_abc.py \ + build/windows/Win32/Lib/_pydecimal.py \ + build/windows/Win32/Lib/_pyio.py \ + build/windows/Win32/Lib/_sitebuiltins.py \ + build/windows/Win32/Lib/_strptime.py \ + build/windows/Win32/Lib/_threading_local.py \ + build/windows/Win32/Lib/_weakrefset.py \ + build/windows/Win32/Lib/abc.py \ + build/windows/Win32/Lib/aifc.py \ + build/windows/Win32/Lib/antigravity.py \ + build/windows/Win32/Lib/argparse.py \ + build/windows/Win32/Lib/ast.py \ + build/windows/Win32/Lib/asynchat.py \ + build/windows/Win32/Lib/asyncio/__init__.py \ + build/windows/Win32/Lib/asyncio/base_events.py \ + build/windows/Win32/Lib/asyncio/base_futures.py \ + build/windows/Win32/Lib/asyncio/base_subprocess.py \ + build/windows/Win32/Lib/asyncio/base_tasks.py \ + build/windows/Win32/Lib/asyncio/constants.py \ + build/windows/Win32/Lib/asyncio/coroutines.py \ + build/windows/Win32/Lib/asyncio/events.py \ + build/windows/Win32/Lib/asyncio/format_helpers.py \ + build/windows/Win32/Lib/asyncio/futures.py \ + build/windows/Win32/Lib/asyncio/locks.py \ + build/windows/Win32/Lib/asyncio/log.py \ + build/windows/Win32/Lib/asyncio/proactor_events.py \ + build/windows/Win32/Lib/asyncio/protocols.py \ + build/windows/Win32/Lib/asyncio/queues.py \ + build/windows/Win32/Lib/asyncio/runners.py \ + build/windows/Win32/Lib/asyncio/selector_events.py \ + build/windows/Win32/Lib/asyncio/sslproto.py \ + build/windows/Win32/Lib/asyncio/streams.py \ + build/windows/Win32/Lib/asyncio/subprocess.py \ + build/windows/Win32/Lib/asyncio/tasks.py \ + build/windows/Win32/Lib/asyncio/transports.py \ + build/windows/Win32/Lib/asyncio/unix_events.py \ + build/windows/Win32/Lib/asyncio/windows_events.py \ + build/windows/Win32/Lib/asyncio/windows_utils.py \ + build/windows/Win32/Lib/asyncore.py \ + build/windows/Win32/Lib/base64.py \ + build/windows/Win32/Lib/bdb.py \ + build/windows/Win32/Lib/binhex.py \ + build/windows/Win32/Lib/bisect.py \ + build/windows/Win32/Lib/bz2.py \ + build/windows/Win32/Lib/cProfile.py \ + build/windows/Win32/Lib/calendar.py \ + build/windows/Win32/Lib/cgi.py \ + build/windows/Win32/Lib/cgitb.py \ + build/windows/Win32/Lib/chunk.py \ + build/windows/Win32/Lib/cmd.py \ + build/windows/Win32/Lib/code.py \ + build/windows/Win32/Lib/codecs.py \ + build/windows/Win32/Lib/codeop.py \ + build/windows/Win32/Lib/collections/__init__.py \ + build/windows/Win32/Lib/collections/abc.py \ + build/windows/Win32/Lib/colorsys.py \ + build/windows/Win32/Lib/compileall.py \ + build/windows/Win32/Lib/concurrent/__init__.py \ + build/windows/Win32/Lib/concurrent/futures/__init__.py \ + build/windows/Win32/Lib/concurrent/futures/_base.py \ + build/windows/Win32/Lib/concurrent/futures/process.py \ + build/windows/Win32/Lib/concurrent/futures/thread.py \ + build/windows/Win32/Lib/configparser.py \ + build/windows/Win32/Lib/contextlib.py \ + build/windows/Win32/Lib/contextvars.py \ + build/windows/Win32/Lib/copy.py \ + build/windows/Win32/Lib/copyreg.py \ + build/windows/Win32/Lib/crypt.py \ + build/windows/Win32/Lib/csv.py \ build/windows/Win32/Lib/ctypes/__init__.py \ + build/windows/Win32/Lib/ctypes/_aix.py \ build/windows/Win32/Lib/ctypes/_endian.py \ - build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py \ - build/windows/Win32/Lib/ctypes/test/test_random_things.py \ - build/windows/Win32/Lib/ctypes/test/test_funcptr.py \ - build/windows/Win32/Lib/ctypes/test/test_callbacks.py \ - build/windows/Win32/Lib/ctypes/test/test_unicode.py \ - build/windows/Win32/Lib/ctypes/test/test_structures.py \ - build/windows/Win32/Lib/ctypes/test/test_cast.py \ - build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py \ - build/windows/Win32/Lib/ctypes/test/test_keeprefs.py \ - build/windows/Win32/Lib/ctypes/test/test_loading.py \ - build/windows/Win32/Lib/ctypes/test/test_memfunctions.py \ - build/windows/Win32/Lib/ctypes/test/test_slicing.py \ - build/windows/Win32/Lib/ctypes/test/test_numbers.py \ - build/windows/Win32/Lib/ctypes/test/test_libc.py \ - build/windows/Win32/Lib/ctypes/test/test_python_api.py \ - build/windows/Win32/Lib/ctypes/test/test_bytes.py \ - build/windows/Win32/Lib/ctypes/test/test_pep3118.py \ + build/windows/Win32/Lib/ctypes/macholib/__init__.py \ + build/windows/Win32/Lib/ctypes/macholib/dyld.py \ + build/windows/Win32/Lib/ctypes/macholib/dylib.py \ + build/windows/Win32/Lib/ctypes/macholib/framework.py \ build/windows/Win32/Lib/ctypes/test/__init__.py \ - build/windows/Win32/Lib/ctypes/test/test_frombuffer.py \ - build/windows/Win32/Lib/ctypes/test/test_parameters.py \ - build/windows/Win32/Lib/ctypes/test/test_wintypes.py \ - build/windows/Win32/Lib/ctypes/test/test_pointers.py \ - build/windows/Win32/Lib/ctypes/test/test_errno.py \ - build/windows/Win32/Lib/ctypes/test/test_arrays.py \ - build/windows/Win32/Lib/ctypes/test/test_cfuncs.py \ - build/windows/Win32/Lib/ctypes/test/test_find.py \ - build/windows/Win32/Lib/ctypes/test/test_refcounts.py \ - build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py \ - build/windows/Win32/Lib/ctypes/test/test_internals.py \ - build/windows/Win32/Lib/ctypes/test/test_prototypes.py \ - build/windows/Win32/Lib/ctypes/test/test_values.py \ - build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py \ - build/windows/Win32/Lib/ctypes/test/test_stringptr.py \ - build/windows/Win32/Lib/ctypes/test/test_as_parameter.py \ - build/windows/Win32/Lib/ctypes/test/test_pickling.py \ - build/windows/Win32/Lib/ctypes/test/test_bitfields.py \ - build/windows/Win32/Lib/ctypes/test/test_byteswap.py \ - build/windows/Win32/Lib/ctypes/test/test_functions.py \ - build/windows/Win32/Lib/ctypes/test/test_repr.py \ - build/windows/Win32/Lib/ctypes/test/test_macholib.py \ - build/windows/Win32/Lib/ctypes/test/test_incomplete.py \ - build/windows/Win32/Lib/ctypes/test/test_strings.py \ - build/windows/Win32/Lib/ctypes/test/test_struct_fields.py \ - build/windows/Win32/Lib/ctypes/test/test_buffers.py \ - build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py \ + build/windows/Win32/Lib/ctypes/test/__main__.py \ build/windows/Win32/Lib/ctypes/test/test_anon.py \ - build/windows/Win32/Lib/ctypes/test/test_init.py \ + build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py \ + build/windows/Win32/Lib/ctypes/test/test_arrays.py \ + build/windows/Win32/Lib/ctypes/test/test_as_parameter.py \ + build/windows/Win32/Lib/ctypes/test/test_bitfields.py \ + build/windows/Win32/Lib/ctypes/test/test_buffers.py \ + build/windows/Win32/Lib/ctypes/test/test_bytes.py \ + build/windows/Win32/Lib/ctypes/test/test_byteswap.py \ + build/windows/Win32/Lib/ctypes/test/test_callbacks.py \ + build/windows/Win32/Lib/ctypes/test/test_cast.py \ + build/windows/Win32/Lib/ctypes/test/test_cfuncs.py \ build/windows/Win32/Lib/ctypes/test/test_checkretval.py \ build/windows/Win32/Lib/ctypes/test/test_delattr.py \ - build/windows/Win32/Lib/ctypes/test/__main__.py \ + build/windows/Win32/Lib/ctypes/test/test_errno.py \ + build/windows/Win32/Lib/ctypes/test/test_find.py \ + build/windows/Win32/Lib/ctypes/test/test_frombuffer.py \ + build/windows/Win32/Lib/ctypes/test/test_funcptr.py \ + build/windows/Win32/Lib/ctypes/test/test_functions.py \ + build/windows/Win32/Lib/ctypes/test/test_incomplete.py \ + build/windows/Win32/Lib/ctypes/test/test_init.py \ + build/windows/Win32/Lib/ctypes/test/test_internals.py \ + build/windows/Win32/Lib/ctypes/test/test_keeprefs.py \ + build/windows/Win32/Lib/ctypes/test/test_libc.py \ + build/windows/Win32/Lib/ctypes/test/test_loading.py \ + build/windows/Win32/Lib/ctypes/test/test_macholib.py \ + build/windows/Win32/Lib/ctypes/test/test_memfunctions.py \ + build/windows/Win32/Lib/ctypes/test/test_numbers.py \ build/windows/Win32/Lib/ctypes/test/test_objects.py \ + build/windows/Win32/Lib/ctypes/test/test_parameters.py \ + build/windows/Win32/Lib/ctypes/test/test_pep3118.py \ + build/windows/Win32/Lib/ctypes/test/test_pickling.py \ + build/windows/Win32/Lib/ctypes/test/test_pointers.py \ + build/windows/Win32/Lib/ctypes/test/test_prototypes.py \ + build/windows/Win32/Lib/ctypes/test/test_python_api.py \ + build/windows/Win32/Lib/ctypes/test/test_random_things.py \ + build/windows/Win32/Lib/ctypes/test/test_refcounts.py \ + build/windows/Win32/Lib/ctypes/test/test_repr.py \ + build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py \ + build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py \ build/windows/Win32/Lib/ctypes/test/test_sizes.py \ + build/windows/Win32/Lib/ctypes/test/test_slicing.py \ + build/windows/Win32/Lib/ctypes/test/test_stringptr.py \ + build/windows/Win32/Lib/ctypes/test/test_strings.py \ + build/windows/Win32/Lib/ctypes/test/test_struct_fields.py \ + build/windows/Win32/Lib/ctypes/test/test_structures.py \ + build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py \ + build/windows/Win32/Lib/ctypes/test/test_unicode.py \ + build/windows/Win32/Lib/ctypes/test/test_values.py \ + build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py \ build/windows/Win32/Lib/ctypes/test/test_win32.py \ - build/windows/Win32/Lib/ctypes/macholib/dyld.py \ - build/windows/Win32/Lib/ctypes/macholib/framework.py \ - build/windows/Win32/Lib/ctypes/macholib/__init__.py \ - build/windows/Win32/Lib/ctypes/macholib/dylib.py \ - build/windows/Win32/Lib/unittest/signals.py \ - build/windows/Win32/Lib/unittest/runner.py \ - build/windows/Win32/Lib/unittest/suite.py \ - build/windows/Win32/Lib/unittest/util.py \ - build/windows/Win32/Lib/unittest/__init__.py \ - build/windows/Win32/Lib/unittest/result.py \ - build/windows/Win32/Lib/unittest/loader.py \ - build/windows/Win32/Lib/unittest/case.py \ - build/windows/Win32/Lib/unittest/main.py \ - build/windows/Win32/Lib/unittest/__main__.py \ - build/windows/Win32/Lib/unittest/mock.py \ - build/windows/Win32/Lib/unittest/test/test_result.py \ - build/windows/Win32/Lib/unittest/test/support.py \ - build/windows/Win32/Lib/unittest/test/test_loader.py \ - build/windows/Win32/Lib/unittest/test/test_skipping.py \ - build/windows/Win32/Lib/unittest/test/test_setups.py \ - build/windows/Win32/Lib/unittest/test/test_functiontestcase.py \ - build/windows/Win32/Lib/unittest/test/__init__.py \ - build/windows/Win32/Lib/unittest/test/test_break.py \ - build/windows/Win32/Lib/unittest/test/test_case.py \ - build/windows/Win32/Lib/unittest/test/test_discovery.py \ - build/windows/Win32/Lib/unittest/test/test_runner.py \ - build/windows/Win32/Lib/unittest/test/test_program.py \ - build/windows/Win32/Lib/unittest/test/test_suite.py \ - build/windows/Win32/Lib/unittest/test/test_assertions.py \ - build/windows/Win32/Lib/unittest/test/_test_warnings.py \ - build/windows/Win32/Lib/unittest/test/dummy.py \ - build/windows/Win32/Lib/unittest/test/__main__.py \ - build/windows/Win32/Lib/unittest/test/testmock/support.py \ - build/windows/Win32/Lib/unittest/test/testmock/testcallable.py \ - build/windows/Win32/Lib/unittest/test/testmock/__init__.py \ - build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py \ - build/windows/Win32/Lib/unittest/test/testmock/testmock.py \ - build/windows/Win32/Lib/unittest/test/testmock/testwith.py \ - build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py \ - build/windows/Win32/Lib/unittest/test/testmock/testpatch.py \ - build/windows/Win32/Lib/unittest/test/testmock/testsealable.py \ - build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py \ - build/windows/Win32/Lib/unittest/test/testmock/__main__.py \ - build/windows/Win32/Lib/curses/textpad.py \ - build/windows/Win32/Lib/curses/ascii.py \ + build/windows/Win32/Lib/ctypes/test/test_wintypes.py \ + build/windows/Win32/Lib/ctypes/util.py \ + build/windows/Win32/Lib/ctypes/wintypes.py \ build/windows/Win32/Lib/curses/__init__.py \ + build/windows/Win32/Lib/curses/ascii.py \ build/windows/Win32/Lib/curses/has_key.py \ build/windows/Win32/Lib/curses/panel.py \ - build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py \ - build/windows/Win32/Lib/multiprocessing/queues.py \ - build/windows/Win32/Lib/multiprocessing/heap.py \ - build/windows/Win32/Lib/multiprocessing/reduction.py \ - build/windows/Win32/Lib/multiprocessing/util.py \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py \ - build/windows/Win32/Lib/multiprocessing/__init__.py \ - build/windows/Win32/Lib/multiprocessing/forkserver.py \ - build/windows/Win32/Lib/multiprocessing/connection.py \ - build/windows/Win32/Lib/multiprocessing/context.py \ - build/windows/Win32/Lib/multiprocessing/spawn.py \ - build/windows/Win32/Lib/multiprocessing/synchronize.py \ - build/windows/Win32/Lib/multiprocessing/process.py \ - build/windows/Win32/Lib/multiprocessing/sharedctypes.py \ - build/windows/Win32/Lib/multiprocessing/popen_fork.py \ - build/windows/Win32/Lib/multiprocessing/pool.py \ - build/windows/Win32/Lib/multiprocessing/popen_forkserver.py \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py \ - build/windows/Win32/Lib/multiprocessing/managers.py \ - build/windows/Win32/Lib/multiprocessing/resource_sharer.py \ - build/windows/Win32/Lib/multiprocessing/dummy/__init__.py \ - build/windows/Win32/Lib/multiprocessing/dummy/connection.py \ - build/windows/Win32/Lib/msilib/sequence.py \ - build/windows/Win32/Lib/msilib/__init__.py \ - build/windows/Win32/Lib/msilib/text.py \ - build/windows/Win32/Lib/msilib/schema.py \ - build/windows/Win32/Lib/urllib/error.py \ - build/windows/Win32/Lib/urllib/request.py \ - build/windows/Win32/Lib/urllib/__init__.py \ - build/windows/Win32/Lib/urllib/response.py \ - build/windows/Win32/Lib/urllib/robotparser.py \ - build/windows/Win32/Lib/urllib/parse.py \ - build/windows/Win32/Lib/html/__init__.py \ - build/windows/Win32/Lib/html/parser.py \ - build/windows/Win32/Lib/html/entities.py \ - build/windows/Win32/Lib/xml/__init__.py \ - build/windows/Win32/Lib/xml/parsers/expat.py \ - build/windows/Win32/Lib/xml/parsers/__init__.py \ - build/windows/Win32/Lib/xml/sax/handler.py \ - build/windows/Win32/Lib/xml/sax/__init__.py \ - build/windows/Win32/Lib/xml/sax/saxutils.py \ - build/windows/Win32/Lib/xml/sax/xmlreader.py \ - build/windows/Win32/Lib/xml/sax/expatreader.py \ - build/windows/Win32/Lib/xml/sax/_exceptions.py \ - build/windows/Win32/Lib/xml/dom/pulldom.py \ - build/windows/Win32/Lib/xml/dom/expatbuilder.py \ - build/windows/Win32/Lib/xml/dom/domreg.py \ - build/windows/Win32/Lib/xml/dom/minicompat.py \ - build/windows/Win32/Lib/xml/dom/__init__.py \ - build/windows/Win32/Lib/xml/dom/NodeFilter.py \ - build/windows/Win32/Lib/xml/dom/xmlbuilder.py \ - build/windows/Win32/Lib/xml/dom/minidom.py \ - build/windows/Win32/Lib/xml/etree/ElementPath.py \ - build/windows/Win32/Lib/xml/etree/cElementTree.py \ - build/windows/Win32/Lib/xml/etree/__init__.py \ - build/windows/Win32/Lib/xml/etree/ElementInclude.py \ - build/windows/Win32/Lib/xml/etree/ElementTree.py \ - build/windows/Win32/Lib/wsgiref/util.py \ - build/windows/Win32/Lib/wsgiref/handlers.py \ - build/windows/Win32/Lib/wsgiref/__init__.py \ - build/windows/Win32/Lib/wsgiref/validate.py \ - build/windows/Win32/Lib/wsgiref/simple_server.py \ - build/windows/Win32/Lib/wsgiref/headers.py \ - build/windows/Win32/Lib/json/decoder.py \ - build/windows/Win32/Lib/json/scanner.py \ - build/windows/Win32/Lib/json/__init__.py \ - build/windows/Win32/Lib/json/encoder.py \ - build/windows/Win32/Lib/json/tool.py \ - build/windows/Win32/Lib/http/cookies.py \ - build/windows/Win32/Lib/http/server.py \ - build/windows/Win32/Lib/http/client.py \ - build/windows/Win32/Lib/http/__init__.py \ - build/windows/Win32/Lib/http/cookiejar.py \ - build/windows/Win32/Lib/sqlite3/__init__.py \ - build/windows/Win32/Lib/sqlite3/dump.py \ - build/windows/Win32/Lib/sqlite3/dbapi2.py \ - build/windows/Win32/Lib/sqlite3/test/backup.py \ - build/windows/Win32/Lib/sqlite3/test/hooks.py \ - build/windows/Win32/Lib/sqlite3/test/regression.py \ - build/windows/Win32/Lib/sqlite3/test/dbapi.py \ - build/windows/Win32/Lib/sqlite3/test/transactions.py \ - build/windows/Win32/Lib/sqlite3/test/__init__.py \ - build/windows/Win32/Lib/sqlite3/test/types.py \ - build/windows/Win32/Lib/sqlite3/test/factory.py \ - build/windows/Win32/Lib/sqlite3/test/dump.py \ - build/windows/Win32/Lib/sqlite3/test/userfunctions.py \ + build/windows/Win32/Lib/curses/textpad.py \ + build/windows/Win32/Lib/dataclasses.py \ + build/windows/Win32/Lib/datetime.py \ + build/windows/Win32/Lib/dbm/__init__.py \ + build/windows/Win32/Lib/dbm/dumb.py \ + build/windows/Win32/Lib/dbm/gnu.py \ + build/windows/Win32/Lib/dbm/ndbm.py \ + build/windows/Win32/Lib/decimal.py \ + build/windows/Win32/Lib/difflib.py \ + build/windows/Win32/Lib/dis.py \ + build/windows/Win32/Lib/distutils/__init__.py \ + build/windows/Win32/Lib/distutils/_msvccompiler.py \ + build/windows/Win32/Lib/distutils/archive_util.py \ + build/windows/Win32/Lib/distutils/bcppcompiler.py \ + build/windows/Win32/Lib/distutils/ccompiler.py \ + build/windows/Win32/Lib/distutils/cmd.py \ + build/windows/Win32/Lib/distutils/command/__init__.py \ + build/windows/Win32/Lib/distutils/command/bdist.py \ + build/windows/Win32/Lib/distutils/command/bdist_dumb.py \ + build/windows/Win32/Lib/distutils/command/bdist_msi.py \ + build/windows/Win32/Lib/distutils/command/bdist_rpm.py \ + build/windows/Win32/Lib/distutils/command/bdist_wininst.py \ + build/windows/Win32/Lib/distutils/command/build.py \ + build/windows/Win32/Lib/distutils/command/build_clib.py \ + build/windows/Win32/Lib/distutils/command/build_ext.py \ + build/windows/Win32/Lib/distutils/command/build_py.py \ + build/windows/Win32/Lib/distutils/command/build_scripts.py \ + build/windows/Win32/Lib/distutils/command/check.py \ + build/windows/Win32/Lib/distutils/command/clean.py \ + build/windows/Win32/Lib/distutils/command/config.py \ + build/windows/Win32/Lib/distutils/command/install.py \ + build/windows/Win32/Lib/distutils/command/install_data.py \ + build/windows/Win32/Lib/distutils/command/install_egg_info.py \ + build/windows/Win32/Lib/distutils/command/install_headers.py \ + build/windows/Win32/Lib/distutils/command/install_lib.py \ + build/windows/Win32/Lib/distutils/command/install_scripts.py \ + build/windows/Win32/Lib/distutils/command/register.py \ + build/windows/Win32/Lib/distutils/command/sdist.py \ + build/windows/Win32/Lib/distutils/command/upload.py \ + build/windows/Win32/Lib/distutils/config.py \ + build/windows/Win32/Lib/distutils/core.py \ + build/windows/Win32/Lib/distutils/cygwinccompiler.py \ + build/windows/Win32/Lib/distutils/debug.py \ + build/windows/Win32/Lib/distutils/dep_util.py \ + build/windows/Win32/Lib/distutils/dir_util.py \ + build/windows/Win32/Lib/distutils/dist.py \ + build/windows/Win32/Lib/distutils/errors.py \ + build/windows/Win32/Lib/distutils/extension.py \ + build/windows/Win32/Lib/distutils/fancy_getopt.py \ + build/windows/Win32/Lib/distutils/file_util.py \ + build/windows/Win32/Lib/distutils/filelist.py \ + build/windows/Win32/Lib/distutils/log.py \ + build/windows/Win32/Lib/distutils/msvc9compiler.py \ + build/windows/Win32/Lib/distutils/msvccompiler.py \ + build/windows/Win32/Lib/distutils/spawn.py \ + build/windows/Win32/Lib/distutils/sysconfig.py \ + build/windows/Win32/Lib/distutils/tests/__init__.py \ + build/windows/Win32/Lib/distutils/tests/support.py \ + build/windows/Win32/Lib/distutils/tests/test_archive_util.py \ + build/windows/Win32/Lib/distutils/tests/test_bdist.py \ + build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py \ + build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py \ + build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py \ + build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py \ + build/windows/Win32/Lib/distutils/tests/test_build.py \ + build/windows/Win32/Lib/distutils/tests/test_build_clib.py \ + build/windows/Win32/Lib/distutils/tests/test_build_ext.py \ + build/windows/Win32/Lib/distutils/tests/test_build_py.py \ + build/windows/Win32/Lib/distutils/tests/test_build_scripts.py \ + build/windows/Win32/Lib/distutils/tests/test_check.py \ + build/windows/Win32/Lib/distutils/tests/test_clean.py \ + build/windows/Win32/Lib/distutils/tests/test_cmd.py \ + build/windows/Win32/Lib/distutils/tests/test_config.py \ + build/windows/Win32/Lib/distutils/tests/test_config_cmd.py \ + build/windows/Win32/Lib/distutils/tests/test_core.py \ + build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py \ + build/windows/Win32/Lib/distutils/tests/test_dep_util.py \ + build/windows/Win32/Lib/distutils/tests/test_dir_util.py \ + build/windows/Win32/Lib/distutils/tests/test_dist.py \ + build/windows/Win32/Lib/distutils/tests/test_extension.py \ + build/windows/Win32/Lib/distutils/tests/test_file_util.py \ + build/windows/Win32/Lib/distutils/tests/test_filelist.py \ + build/windows/Win32/Lib/distutils/tests/test_install.py \ + build/windows/Win32/Lib/distutils/tests/test_install_data.py \ + build/windows/Win32/Lib/distutils/tests/test_install_headers.py \ + build/windows/Win32/Lib/distutils/tests/test_install_lib.py \ + build/windows/Win32/Lib/distutils/tests/test_install_scripts.py \ + build/windows/Win32/Lib/distutils/tests/test_log.py \ + build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py \ + build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py \ + build/windows/Win32/Lib/distutils/tests/test_register.py \ + build/windows/Win32/Lib/distutils/tests/test_sdist.py \ + build/windows/Win32/Lib/distutils/tests/test_spawn.py \ + build/windows/Win32/Lib/distutils/tests/test_sysconfig.py \ + build/windows/Win32/Lib/distutils/tests/test_text_file.py \ + build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py \ + build/windows/Win32/Lib/distutils/tests/test_upload.py \ + build/windows/Win32/Lib/distutils/tests/test_util.py \ + build/windows/Win32/Lib/distutils/tests/test_version.py \ + build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py \ + build/windows/Win32/Lib/distutils/text_file.py \ + build/windows/Win32/Lib/distutils/unixccompiler.py \ + build/windows/Win32/Lib/distutils/util.py \ + build/windows/Win32/Lib/distutils/version.py \ + build/windows/Win32/Lib/distutils/versionpredicate.py \ + build/windows/Win32/Lib/doctest.py \ + build/windows/Win32/Lib/dummy_threading.py \ + build/windows/Win32/Lib/email/__init__.py \ + build/windows/Win32/Lib/email/_encoded_words.py \ + build/windows/Win32/Lib/email/_header_value_parser.py \ + build/windows/Win32/Lib/email/_parseaddr.py \ + build/windows/Win32/Lib/email/_policybase.py \ + build/windows/Win32/Lib/email/base64mime.py \ + build/windows/Win32/Lib/email/charset.py \ + build/windows/Win32/Lib/email/contentmanager.py \ + build/windows/Win32/Lib/email/encoders.py \ + build/windows/Win32/Lib/email/errors.py \ + build/windows/Win32/Lib/email/feedparser.py \ + build/windows/Win32/Lib/email/generator.py \ + build/windows/Win32/Lib/email/header.py \ + build/windows/Win32/Lib/email/headerregistry.py \ + build/windows/Win32/Lib/email/iterators.py \ + build/windows/Win32/Lib/email/message.py \ + build/windows/Win32/Lib/email/mime/__init__.py \ + build/windows/Win32/Lib/email/mime/application.py \ + build/windows/Win32/Lib/email/mime/audio.py \ + build/windows/Win32/Lib/email/mime/base.py \ + build/windows/Win32/Lib/email/mime/image.py \ + build/windows/Win32/Lib/email/mime/message.py \ + build/windows/Win32/Lib/email/mime/multipart.py \ + build/windows/Win32/Lib/email/mime/nonmultipart.py \ + build/windows/Win32/Lib/email/mime/text.py \ + build/windows/Win32/Lib/email/parser.py \ + build/windows/Win32/Lib/email/policy.py \ + build/windows/Win32/Lib/email/quoprimime.py \ + build/windows/Win32/Lib/email/utils.py \ + build/windows/Win32/Lib/encodings/__init__.py \ + build/windows/Win32/Lib/encodings/aliases.py \ + build/windows/Win32/Lib/encodings/ascii.py \ + build/windows/Win32/Lib/encodings/base64_codec.py \ + build/windows/Win32/Lib/encodings/big5.py \ + build/windows/Win32/Lib/encodings/big5hkscs.py \ + build/windows/Win32/Lib/encodings/bz2_codec.py \ + build/windows/Win32/Lib/encodings/charmap.py \ + build/windows/Win32/Lib/encodings/cp037.py \ + build/windows/Win32/Lib/encodings/cp1006.py \ + build/windows/Win32/Lib/encodings/cp1026.py \ + build/windows/Win32/Lib/encodings/cp1125.py \ + build/windows/Win32/Lib/encodings/cp1140.py \ + build/windows/Win32/Lib/encodings/cp1250.py \ + build/windows/Win32/Lib/encodings/cp1251.py \ + build/windows/Win32/Lib/encodings/cp1252.py \ + build/windows/Win32/Lib/encodings/cp1253.py \ + build/windows/Win32/Lib/encodings/cp1254.py \ + build/windows/Win32/Lib/encodings/cp1255.py \ + build/windows/Win32/Lib/encodings/cp1256.py \ + build/windows/Win32/Lib/encodings/cp1257.py \ + build/windows/Win32/Lib/encodings/cp1258.py \ + build/windows/Win32/Lib/encodings/cp273.py \ + build/windows/Win32/Lib/encodings/cp424.py \ + build/windows/Win32/Lib/encodings/cp437.py \ + build/windows/Win32/Lib/encodings/cp500.py \ + build/windows/Win32/Lib/encodings/cp65001.py \ + build/windows/Win32/Lib/encodings/cp720.py \ + build/windows/Win32/Lib/encodings/cp737.py \ + build/windows/Win32/Lib/encodings/cp775.py \ + build/windows/Win32/Lib/encodings/cp850.py \ + build/windows/Win32/Lib/encodings/cp852.py \ + build/windows/Win32/Lib/encodings/cp855.py \ + build/windows/Win32/Lib/encodings/cp856.py \ + build/windows/Win32/Lib/encodings/cp857.py \ + build/windows/Win32/Lib/encodings/cp858.py \ + build/windows/Win32/Lib/encodings/cp860.py \ + build/windows/Win32/Lib/encodings/cp861.py \ + build/windows/Win32/Lib/encodings/cp862.py \ + build/windows/Win32/Lib/encodings/cp863.py \ + build/windows/Win32/Lib/encodings/cp864.py \ + build/windows/Win32/Lib/encodings/cp865.py \ + build/windows/Win32/Lib/encodings/cp866.py \ + build/windows/Win32/Lib/encodings/cp869.py \ + build/windows/Win32/Lib/encodings/cp874.py \ + build/windows/Win32/Lib/encodings/cp875.py \ + build/windows/Win32/Lib/encodings/cp932.py \ + build/windows/Win32/Lib/encodings/cp949.py \ + build/windows/Win32/Lib/encodings/cp950.py \ + build/windows/Win32/Lib/encodings/euc_jis_2004.py \ + build/windows/Win32/Lib/encodings/euc_jisx0213.py \ + build/windows/Win32/Lib/encodings/euc_jp.py \ + build/windows/Win32/Lib/encodings/euc_kr.py \ + build/windows/Win32/Lib/encodings/gb18030.py \ + build/windows/Win32/Lib/encodings/gb2312.py \ + build/windows/Win32/Lib/encodings/gbk.py \ + build/windows/Win32/Lib/encodings/hex_codec.py \ + build/windows/Win32/Lib/encodings/hp_roman8.py \ + build/windows/Win32/Lib/encodings/hz.py \ + build/windows/Win32/Lib/encodings/idna.py \ + build/windows/Win32/Lib/encodings/iso2022_jp.py \ + build/windows/Win32/Lib/encodings/iso2022_jp_1.py \ + build/windows/Win32/Lib/encodings/iso2022_jp_2.py \ + build/windows/Win32/Lib/encodings/iso2022_jp_2004.py \ + build/windows/Win32/Lib/encodings/iso2022_jp_3.py \ + build/windows/Win32/Lib/encodings/iso2022_jp_ext.py \ + build/windows/Win32/Lib/encodings/iso2022_kr.py \ + build/windows/Win32/Lib/encodings/iso8859_1.py \ + build/windows/Win32/Lib/encodings/iso8859_10.py \ + build/windows/Win32/Lib/encodings/iso8859_11.py \ + build/windows/Win32/Lib/encodings/iso8859_13.py \ + build/windows/Win32/Lib/encodings/iso8859_14.py \ + build/windows/Win32/Lib/encodings/iso8859_15.py \ + build/windows/Win32/Lib/encodings/iso8859_16.py \ + build/windows/Win32/Lib/encodings/iso8859_2.py \ + build/windows/Win32/Lib/encodings/iso8859_3.py \ + build/windows/Win32/Lib/encodings/iso8859_4.py \ + build/windows/Win32/Lib/encodings/iso8859_5.py \ + build/windows/Win32/Lib/encodings/iso8859_6.py \ + build/windows/Win32/Lib/encodings/iso8859_7.py \ + build/windows/Win32/Lib/encodings/iso8859_8.py \ + build/windows/Win32/Lib/encodings/iso8859_9.py \ + build/windows/Win32/Lib/encodings/johab.py \ + build/windows/Win32/Lib/encodings/koi8_r.py \ + build/windows/Win32/Lib/encodings/koi8_t.py \ + build/windows/Win32/Lib/encodings/koi8_u.py \ + build/windows/Win32/Lib/encodings/kz1048.py \ + build/windows/Win32/Lib/encodings/latin_1.py \ + build/windows/Win32/Lib/encodings/mac_arabic.py \ + build/windows/Win32/Lib/encodings/mac_centeuro.py \ + build/windows/Win32/Lib/encodings/mac_croatian.py \ + build/windows/Win32/Lib/encodings/mac_cyrillic.py \ + build/windows/Win32/Lib/encodings/mac_farsi.py \ + build/windows/Win32/Lib/encodings/mac_greek.py \ + build/windows/Win32/Lib/encodings/mac_iceland.py \ + build/windows/Win32/Lib/encodings/mac_latin2.py \ + build/windows/Win32/Lib/encodings/mac_roman.py \ + build/windows/Win32/Lib/encodings/mac_romanian.py \ + build/windows/Win32/Lib/encodings/mac_turkish.py \ + build/windows/Win32/Lib/encodings/mbcs.py \ + build/windows/Win32/Lib/encodings/oem.py \ + build/windows/Win32/Lib/encodings/palmos.py \ + build/windows/Win32/Lib/encodings/ptcp154.py \ + build/windows/Win32/Lib/encodings/punycode.py \ + build/windows/Win32/Lib/encodings/quopri_codec.py \ + build/windows/Win32/Lib/encodings/raw_unicode_escape.py \ + build/windows/Win32/Lib/encodings/rot_13.py \ + build/windows/Win32/Lib/encodings/shift_jis.py \ + build/windows/Win32/Lib/encodings/shift_jis_2004.py \ + build/windows/Win32/Lib/encodings/shift_jisx0213.py \ + build/windows/Win32/Lib/encodings/tis_620.py \ + build/windows/Win32/Lib/encodings/undefined.py \ + build/windows/Win32/Lib/encodings/unicode_escape.py \ + build/windows/Win32/Lib/encodings/unicode_internal.py \ + build/windows/Win32/Lib/encodings/utf_16.py \ + build/windows/Win32/Lib/encodings/utf_16_be.py \ + build/windows/Win32/Lib/encodings/utf_16_le.py \ + build/windows/Win32/Lib/encodings/utf_32.py \ + build/windows/Win32/Lib/encodings/utf_32_be.py \ + build/windows/Win32/Lib/encodings/utf_32_le.py \ + build/windows/Win32/Lib/encodings/utf_7.py \ + build/windows/Win32/Lib/encodings/utf_8.py \ + build/windows/Win32/Lib/encodings/utf_8_sig.py \ + build/windows/Win32/Lib/encodings/uu_codec.py \ + build/windows/Win32/Lib/encodings/zlib_codec.py \ build/windows/Win32/Lib/ensurepip/__init__.py \ build/windows/Win32/Lib/ensurepip/__main__.py \ build/windows/Win32/Lib/ensurepip/_uninstall.py \ - build/windows/Win32/Lib/concurrent/__init__.py \ - build/windows/Win32/Lib/concurrent/futures/_base.py \ - build/windows/Win32/Lib/concurrent/futures/thread.py \ - build/windows/Win32/Lib/concurrent/futures/__init__.py \ - build/windows/Win32/Lib/concurrent/futures/process.py \ - build/windows/Win32/Lib/venv/__init__.py \ - build/windows/Win32/Lib/venv/__main__.py \ - build/windows/Win32/Lib/dbm/ndbm.py \ - build/windows/Win32/Lib/dbm/gnu.py \ - build/windows/Win32/Lib/dbm/__init__.py \ - build/windows/Win32/Lib/dbm/dumb.py \ - build/windows/Win32/Lib/importlib/util.py \ - build/windows/Win32/Lib/importlib/_bootstrap.py \ + build/windows/Win32/Lib/enum.py \ + build/windows/Win32/Lib/filecmp.py \ + build/windows/Win32/Lib/fileinput.py \ + build/windows/Win32/Lib/fnmatch.py \ + build/windows/Win32/Lib/formatter.py \ + build/windows/Win32/Lib/fractions.py \ + build/windows/Win32/Lib/ftplib.py \ + build/windows/Win32/Lib/functools.py \ + build/windows/Win32/Lib/genericpath.py \ + build/windows/Win32/Lib/getopt.py \ + build/windows/Win32/Lib/getpass.py \ + build/windows/Win32/Lib/gettext.py \ + build/windows/Win32/Lib/glob.py \ + build/windows/Win32/Lib/gzip.py \ + build/windows/Win32/Lib/hashlib.py \ + build/windows/Win32/Lib/heapq.py \ + build/windows/Win32/Lib/hmac.py \ + build/windows/Win32/Lib/html/__init__.py \ + build/windows/Win32/Lib/html/entities.py \ + build/windows/Win32/Lib/html/parser.py \ + build/windows/Win32/Lib/http/__init__.py \ + build/windows/Win32/Lib/http/client.py \ + build/windows/Win32/Lib/http/cookiejar.py \ + build/windows/Win32/Lib/http/cookies.py \ + build/windows/Win32/Lib/http/server.py \ + build/windows/Win32/Lib/imaplib.py \ + build/windows/Win32/Lib/imghdr.py \ + build/windows/Win32/Lib/imp.py \ build/windows/Win32/Lib/importlib/__init__.py \ + build/windows/Win32/Lib/importlib/_bootstrap.py \ build/windows/Win32/Lib/importlib/_bootstrap_external.py \ - build/windows/Win32/Lib/importlib/resources.py \ - build/windows/Win32/Lib/importlib/machinery.py \ build/windows/Win32/Lib/importlib/abc.py \ - build/windows/Win32/Lib/xmlrpc/server.py \ - build/windows/Win32/Lib/xmlrpc/client.py \ - build/windows/Win32/Lib/xmlrpc/__init__.py \ - build/windows/Win32/Lib/pydoc_data/__init__.py \ - build/windows/Win32/Lib/pydoc_data/topics.py \ - build/windows/Win32/Lib/collections/__init__.py \ - build/windows/Win32/Lib/collections/abc.py \ - build/windows/Win32/Lib/asyncio/queues.py \ - build/windows/Win32/Lib/asyncio/streams.py \ - build/windows/Win32/Lib/asyncio/tasks.py \ - build/windows/Win32/Lib/asyncio/selector_events.py \ - build/windows/Win32/Lib/asyncio/log.py \ - build/windows/Win32/Lib/asyncio/protocols.py \ - build/windows/Win32/Lib/asyncio/events.py \ - build/windows/Win32/Lib/asyncio/base_events.py \ - build/windows/Win32/Lib/asyncio/subprocess.py \ - build/windows/Win32/Lib/asyncio/constants.py \ - build/windows/Win32/Lib/asyncio/proactor_events.py \ - build/windows/Win32/Lib/asyncio/format_helpers.py \ - build/windows/Win32/Lib/asyncio/locks.py \ - build/windows/Win32/Lib/asyncio/__init__.py \ - build/windows/Win32/Lib/asyncio/futures.py \ - build/windows/Win32/Lib/asyncio/sslproto.py \ - build/windows/Win32/Lib/asyncio/base_subprocess.py \ - build/windows/Win32/Lib/asyncio/windows_utils.py \ - build/windows/Win32/Lib/asyncio/runners.py \ - build/windows/Win32/Lib/asyncio/transports.py \ - build/windows/Win32/Lib/asyncio/base_tasks.py \ - build/windows/Win32/Lib/asyncio/coroutines.py \ - build/windows/Win32/Lib/asyncio/windows_events.py \ - build/windows/Win32/Lib/asyncio/base_futures.py \ - build/windows/Win32/Lib/asyncio/unix_events.py \ + build/windows/Win32/Lib/importlib/machinery.py \ + build/windows/Win32/Lib/importlib/resources.py \ + build/windows/Win32/Lib/importlib/util.py \ + build/windows/Win32/Lib/inspect.py \ + build/windows/Win32/Lib/io.py \ + build/windows/Win32/Lib/ipaddress.py \ + build/windows/Win32/Lib/json/__init__.py \ + build/windows/Win32/Lib/json/decoder.py \ + build/windows/Win32/Lib/json/encoder.py \ + build/windows/Win32/Lib/json/scanner.py \ + build/windows/Win32/Lib/json/tool.py \ + build/windows/Win32/Lib/keyword.py \ + build/windows/Win32/Lib/linecache.py \ + build/windows/Win32/Lib/locale.py \ + build/windows/Win32/Lib/logging/__init__.py \ build/windows/Win32/Lib/logging/config.py \ build/windows/Win32/Lib/logging/handlers.py \ - build/windows/Win32/Lib/logging/__init__.py \ - build/windows/Win32/Lib/email/contentmanager.py \ - build/windows/Win32/Lib/email/_policybase.py \ - build/windows/Win32/Lib/email/header.py \ - build/windows/Win32/Lib/email/_encoded_words.py \ - build/windows/Win32/Lib/email/_header_value_parser.py \ - build/windows/Win32/Lib/email/policy.py \ - build/windows/Win32/Lib/email/__init__.py \ - build/windows/Win32/Lib/email/message.py \ - build/windows/Win32/Lib/email/encoders.py \ - build/windows/Win32/Lib/email/parser.py \ - build/windows/Win32/Lib/email/generator.py \ - build/windows/Win32/Lib/email/utils.py \ - build/windows/Win32/Lib/email/charset.py \ - build/windows/Win32/Lib/email/iterators.py \ - build/windows/Win32/Lib/email/quoprimime.py \ - build/windows/Win32/Lib/email/errors.py \ - build/windows/Win32/Lib/email/feedparser.py \ - build/windows/Win32/Lib/email/_parseaddr.py \ - build/windows/Win32/Lib/email/base64mime.py \ - build/windows/Win32/Lib/email/headerregistry.py \ - build/windows/Win32/Lib/email/mime/multipart.py \ - build/windows/Win32/Lib/email/mime/__init__.py \ - build/windows/Win32/Lib/email/mime/message.py \ - build/windows/Win32/Lib/email/mime/application.py \ - build/windows/Win32/Lib/email/mime/nonmultipart.py \ - build/windows/Win32/Lib/email/mime/text.py \ - build/windows/Win32/Lib/email/mime/audio.py \ - build/windows/Win32/Lib/email/mime/image.py \ - build/windows/Win32/Lib/email/mime/base.py + build/windows/Win32/Lib/lzma.py \ + build/windows/Win32/Lib/macpath.py \ + build/windows/Win32/Lib/mailbox.py \ + build/windows/Win32/Lib/mailcap.py \ + build/windows/Win32/Lib/mimetypes.py \ + build/windows/Win32/Lib/modulefinder.py \ + build/windows/Win32/Lib/msilib/__init__.py \ + build/windows/Win32/Lib/msilib/schema.py \ + build/windows/Win32/Lib/msilib/sequence.py \ + build/windows/Win32/Lib/msilib/text.py \ + build/windows/Win32/Lib/multiprocessing/__init__.py \ + build/windows/Win32/Lib/multiprocessing/connection.py \ + build/windows/Win32/Lib/multiprocessing/context.py \ + build/windows/Win32/Lib/multiprocessing/dummy/__init__.py \ + build/windows/Win32/Lib/multiprocessing/dummy/connection.py \ + build/windows/Win32/Lib/multiprocessing/forkserver.py \ + build/windows/Win32/Lib/multiprocessing/heap.py \ + build/windows/Win32/Lib/multiprocessing/managers.py \ + build/windows/Win32/Lib/multiprocessing/pool.py \ + build/windows/Win32/Lib/multiprocessing/popen_fork.py \ + build/windows/Win32/Lib/multiprocessing/popen_forkserver.py \ + build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py \ + build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py \ + build/windows/Win32/Lib/multiprocessing/process.py \ + build/windows/Win32/Lib/multiprocessing/queues.py \ + build/windows/Win32/Lib/multiprocessing/reduction.py \ + build/windows/Win32/Lib/multiprocessing/resource_sharer.py \ + build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py \ + build/windows/Win32/Lib/multiprocessing/sharedctypes.py \ + build/windows/Win32/Lib/multiprocessing/spawn.py \ + build/windows/Win32/Lib/multiprocessing/synchronize.py \ + build/windows/Win32/Lib/multiprocessing/util.py \ + build/windows/Win32/Lib/netrc.py \ + build/windows/Win32/Lib/nntplib.py \ + build/windows/Win32/Lib/ntpath.py \ + build/windows/Win32/Lib/nturl2path.py \ + build/windows/Win32/Lib/numbers.py \ + build/windows/Win32/Lib/opcode.py \ + build/windows/Win32/Lib/operator.py \ + build/windows/Win32/Lib/optparse.py \ + build/windows/Win32/Lib/os.py \ + build/windows/Win32/Lib/pathlib.py \ + build/windows/Win32/Lib/pdb.py \ + build/windows/Win32/Lib/pickle.py \ + build/windows/Win32/Lib/pickletools.py \ + build/windows/Win32/Lib/pipes.py \ + build/windows/Win32/Lib/pkgutil.py \ + build/windows/Win32/Lib/platform.py \ + build/windows/Win32/Lib/plistlib.py \ + build/windows/Win32/Lib/poplib.py \ + build/windows/Win32/Lib/posixpath.py \ + build/windows/Win32/Lib/pprint.py \ + build/windows/Win32/Lib/profile.py \ + build/windows/Win32/Lib/pstats.py \ + build/windows/Win32/Lib/pty.py \ + build/windows/Win32/Lib/py_compile.py \ + build/windows/Win32/Lib/pyclbr.py \ + build/windows/Win32/Lib/pydoc.py \ + build/windows/Win32/Lib/pydoc_data/__init__.py \ + build/windows/Win32/Lib/pydoc_data/topics.py \ + build/windows/Win32/Lib/queue.py \ + build/windows/Win32/Lib/quopri.py \ + build/windows/Win32/Lib/random.py \ + build/windows/Win32/Lib/re.py \ + build/windows/Win32/Lib/reprlib.py \ + build/windows/Win32/Lib/rlcompleter.py \ + build/windows/Win32/Lib/runpy.py \ + build/windows/Win32/Lib/sched.py \ + build/windows/Win32/Lib/secrets.py \ + build/windows/Win32/Lib/selectors.py \ + build/windows/Win32/Lib/shelve.py \ + build/windows/Win32/Lib/shlex.py \ + build/windows/Win32/Lib/shutil.py \ + build/windows/Win32/Lib/signal.py \ + build/windows/Win32/Lib/site.py \ + build/windows/Win32/Lib/smtpd.py \ + build/windows/Win32/Lib/smtplib.py \ + build/windows/Win32/Lib/sndhdr.py \ + build/windows/Win32/Lib/socket.py \ + build/windows/Win32/Lib/socketserver.py \ + build/windows/Win32/Lib/sqlite3/__init__.py \ + build/windows/Win32/Lib/sqlite3/dbapi2.py \ + build/windows/Win32/Lib/sqlite3/dump.py \ + build/windows/Win32/Lib/sqlite3/test/__init__.py \ + build/windows/Win32/Lib/sqlite3/test/backup.py \ + build/windows/Win32/Lib/sqlite3/test/dbapi.py \ + build/windows/Win32/Lib/sqlite3/test/dump.py \ + build/windows/Win32/Lib/sqlite3/test/factory.py \ + build/windows/Win32/Lib/sqlite3/test/hooks.py \ + build/windows/Win32/Lib/sqlite3/test/regression.py \ + build/windows/Win32/Lib/sqlite3/test/transactions.py \ + build/windows/Win32/Lib/sqlite3/test/types.py \ + build/windows/Win32/Lib/sqlite3/test/userfunctions.py \ + build/windows/Win32/Lib/sre_compile.py \ + build/windows/Win32/Lib/sre_constants.py \ + build/windows/Win32/Lib/sre_parse.py \ + build/windows/Win32/Lib/ssl.py \ + build/windows/Win32/Lib/stat.py \ + build/windows/Win32/Lib/statistics.py \ + build/windows/Win32/Lib/string.py \ + build/windows/Win32/Lib/stringprep.py \ + build/windows/Win32/Lib/struct.py \ + build/windows/Win32/Lib/subprocess.py \ + build/windows/Win32/Lib/sunau.py \ + build/windows/Win32/Lib/symbol.py \ + build/windows/Win32/Lib/symtable.py \ + build/windows/Win32/Lib/sysconfig.py \ + build/windows/Win32/Lib/tabnanny.py \ + build/windows/Win32/Lib/tarfile.py \ + build/windows/Win32/Lib/telnetlib.py \ + build/windows/Win32/Lib/tempfile.py \ + build/windows/Win32/Lib/textwrap.py \ + build/windows/Win32/Lib/this.py \ + build/windows/Win32/Lib/threading.py \ + build/windows/Win32/Lib/timeit.py \ + build/windows/Win32/Lib/token.py \ + build/windows/Win32/Lib/tokenize.py \ + build/windows/Win32/Lib/trace.py \ + build/windows/Win32/Lib/traceback.py \ + build/windows/Win32/Lib/tracemalloc.py \ + build/windows/Win32/Lib/tty.py \ + build/windows/Win32/Lib/turtle.py \ + build/windows/Win32/Lib/types.py \ + build/windows/Win32/Lib/typing.py \ + build/windows/Win32/Lib/unittest/__init__.py \ + build/windows/Win32/Lib/unittest/__main__.py \ + build/windows/Win32/Lib/unittest/case.py \ + build/windows/Win32/Lib/unittest/loader.py \ + build/windows/Win32/Lib/unittest/main.py \ + build/windows/Win32/Lib/unittest/mock.py \ + build/windows/Win32/Lib/unittest/result.py \ + build/windows/Win32/Lib/unittest/runner.py \ + build/windows/Win32/Lib/unittest/signals.py \ + build/windows/Win32/Lib/unittest/suite.py \ + build/windows/Win32/Lib/unittest/test/__init__.py \ + build/windows/Win32/Lib/unittest/test/__main__.py \ + build/windows/Win32/Lib/unittest/test/_test_warnings.py \ + build/windows/Win32/Lib/unittest/test/dummy.py \ + build/windows/Win32/Lib/unittest/test/support.py \ + build/windows/Win32/Lib/unittest/test/test_assertions.py \ + build/windows/Win32/Lib/unittest/test/test_break.py \ + build/windows/Win32/Lib/unittest/test/test_case.py \ + build/windows/Win32/Lib/unittest/test/test_discovery.py \ + build/windows/Win32/Lib/unittest/test/test_functiontestcase.py \ + build/windows/Win32/Lib/unittest/test/test_loader.py \ + build/windows/Win32/Lib/unittest/test/test_program.py \ + build/windows/Win32/Lib/unittest/test/test_result.py \ + build/windows/Win32/Lib/unittest/test/test_runner.py \ + build/windows/Win32/Lib/unittest/test/test_setups.py \ + build/windows/Win32/Lib/unittest/test/test_skipping.py \ + build/windows/Win32/Lib/unittest/test/test_suite.py \ + build/windows/Win32/Lib/unittest/test/testmock/__init__.py \ + build/windows/Win32/Lib/unittest/test/testmock/__main__.py \ + build/windows/Win32/Lib/unittest/test/testmock/support.py \ + build/windows/Win32/Lib/unittest/test/testmock/testcallable.py \ + build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py \ + build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py \ + build/windows/Win32/Lib/unittest/test/testmock/testmock.py \ + build/windows/Win32/Lib/unittest/test/testmock/testpatch.py \ + build/windows/Win32/Lib/unittest/test/testmock/testsealable.py \ + build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py \ + build/windows/Win32/Lib/unittest/test/testmock/testwith.py \ + build/windows/Win32/Lib/unittest/util.py \ + build/windows/Win32/Lib/urllib/__init__.py \ + build/windows/Win32/Lib/urllib/error.py \ + build/windows/Win32/Lib/urllib/parse.py \ + build/windows/Win32/Lib/urllib/request.py \ + build/windows/Win32/Lib/urllib/response.py \ + build/windows/Win32/Lib/urllib/robotparser.py \ + build/windows/Win32/Lib/uu.py \ + build/windows/Win32/Lib/uuid.py \ + build/windows/Win32/Lib/venv/__init__.py \ + build/windows/Win32/Lib/venv/__main__.py \ + build/windows/Win32/Lib/warnings.py \ + build/windows/Win32/Lib/wave.py \ + build/windows/Win32/Lib/weakref.py \ + build/windows/Win32/Lib/webbrowser.py \ + build/windows/Win32/Lib/wsgiref/__init__.py \ + build/windows/Win32/Lib/wsgiref/handlers.py \ + build/windows/Win32/Lib/wsgiref/headers.py \ + build/windows/Win32/Lib/wsgiref/simple_server.py \ + build/windows/Win32/Lib/wsgiref/util.py \ + build/windows/Win32/Lib/wsgiref/validate.py \ + build/windows/Win32/Lib/xdrlib.py \ + build/windows/Win32/Lib/xml/__init__.py \ + build/windows/Win32/Lib/xml/dom/NodeFilter.py \ + build/windows/Win32/Lib/xml/dom/__init__.py \ + build/windows/Win32/Lib/xml/dom/domreg.py \ + build/windows/Win32/Lib/xml/dom/expatbuilder.py \ + build/windows/Win32/Lib/xml/dom/minicompat.py \ + build/windows/Win32/Lib/xml/dom/minidom.py \ + build/windows/Win32/Lib/xml/dom/pulldom.py \ + build/windows/Win32/Lib/xml/dom/xmlbuilder.py \ + build/windows/Win32/Lib/xml/etree/ElementInclude.py \ + build/windows/Win32/Lib/xml/etree/ElementPath.py \ + build/windows/Win32/Lib/xml/etree/ElementTree.py \ + build/windows/Win32/Lib/xml/etree/__init__.py \ + build/windows/Win32/Lib/xml/etree/cElementTree.py \ + build/windows/Win32/Lib/xml/parsers/__init__.py \ + build/windows/Win32/Lib/xml/parsers/expat.py \ + build/windows/Win32/Lib/xml/sax/__init__.py \ + build/windows/Win32/Lib/xml/sax/_exceptions.py \ + build/windows/Win32/Lib/xml/sax/expatreader.py \ + build/windows/Win32/Lib/xml/sax/handler.py \ + build/windows/Win32/Lib/xml/sax/saxutils.py \ + build/windows/Win32/Lib/xml/sax/xmlreader.py \ + build/windows/Win32/Lib/xmlrpc/__init__.py \ + build/windows/Win32/Lib/xmlrpc/client.py \ + build/windows/Win32/Lib/xmlrpc/server.py \ + build/windows/Win32/Lib/zipapp.py \ + build/windows/Win32/Lib/zipfile.py SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ - build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc + build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -9383,58 +9383,8 @@ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32) : ../.efrocachemap # just generating explicit targets for each. Could perhaps look into using a # fancy for-loop instead, but perhaps listing these explicitly isn't so bad. -build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/queue.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncore.py +build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/__future__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -9443,623 +9393,8 @@ build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/trace.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/token.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/base64.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/signal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wave.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/functools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/profile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/this.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/uu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/io.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/code.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/operator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/os.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/copy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/types.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/random.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/turtle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/platform.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/glob.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/site.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/stat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/csv.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sched.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/imaplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/locale.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ast.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/statistics.py +build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_bootlocale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -10068,98 +9403,33 @@ build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sunau.py +build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_compat_pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/__future__.py +build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_compression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dataclasses.py +build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_dummy_thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/shelve.py +build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_markupbase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/string.py +build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_osx_support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/enum.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/typing.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/socket.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pathlib.py +build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_py_abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -10168,58 +9438,28 @@ build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ntpath.py +build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_pyio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tokenize.py +build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_sitebuiltins.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/uuid.py +build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_strptime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/imp.py +build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_threading_local.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/re.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/struct.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sre_parse.py +build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/_weakrefset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -10228,3841 +9468,4601 @@ build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/aifc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/antigravity.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/argparse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ast.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asynchat.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/base_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/base_futures.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/base_subprocess.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/base_tasks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/constants.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/coroutines.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/format_helpers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/futures.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/locks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/log.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/proactor_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/protocols.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/queues.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/runners.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/selector_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/sslproto.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/streams.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/subprocess.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/tasks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/transports.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/unix_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/windows_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncio/windows_utils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/asyncore.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/base64.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/bdb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/binhex.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/bisect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/bz2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/cProfile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/calendar.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/cgi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/cgitb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/chunk.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/cmd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/code.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/codecs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/codeop.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/collections/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/collections/abc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/colorsys.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/compileall.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/concurrent/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/concurrent/futures/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/concurrent/futures/_base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/concurrent/futures/process.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/concurrent/futures/thread.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/configparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/contextlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/contextvars.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/copy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/copyreg.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/crypt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/csv.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/_aix.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/_endian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/macholib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/macholib/dyld.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/macholib/dylib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/macholib/framework.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/__main__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_anon.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_arrays.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_as_parameter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_bitfields.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_buffers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_bytes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_byteswap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_callbacks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_cast.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_cfuncs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_checkretval.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_delattr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_errno.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_find.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_frombuffer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_funcptr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_functions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_incomplete.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_init.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_internals.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_keeprefs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_libc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_loading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_macholib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_memfunctions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_numbers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_objects.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_parameters.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_pep3118.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/runpy.py + build/windows/Win32/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_bootlocale.py +build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_romanian.py +build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_farsi.py +build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/idna.py +build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp273.py +build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/punycode.py +build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/raw_unicode_escape.py +build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_8.py +build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1252.py +build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp869.py +build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_14.py +build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_2.py +build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_arabic.py +build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_croatian.py +build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/big5hkscs.py +build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1256.py +build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_6.py +build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_values.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_10.py +build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_kr.py +build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1140.py +build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/unicode_internal.py +build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1125.py +build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ctypes/wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_1.py +build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1257.py +build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/curses/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp949.py +build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp858.py +build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_7.py +build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_11.py +build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/hp_roman8.py +build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/koi8_r.py +build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dbm/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/zlib_codec.py +build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dbm/dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/gbk.py +build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dbm/gnu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/johab.py +build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dbm/ndbm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1253.py +build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_15.py +build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_2004.py +build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_iceland.py +build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_3.py +build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_greek.py +build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/archive_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/rot_13.py +build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_16_be.py +build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/ccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_kr.py +build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_centeuro.py +build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_jisx0213.py +build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/bdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp863.py +build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/ascii.py +build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_8.py +build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp857.py +build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_32_be.py +build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/build.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1258.py +build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/build_clib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/oem.py +build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/build_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_latin2.py +build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/build_py.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp775.py +build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_roman.py +build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/check.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/clean.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/install.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/install_data.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/install_egg_info.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/install_headers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/install_lib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/install_scripts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/register.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/sdist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/command/upload.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/core.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/cygwinccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/debug.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/dep_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/dir_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/dist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/errors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/extension.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/fancy_getopt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/file_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/filelist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/log.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/msvc9compiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/msvccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/spawn.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/sysconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/support.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_archive_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_bdist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_build.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_build_clib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_build_ext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_build_py.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_build_scripts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_check.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_clean.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_cmd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_config_cmd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_core.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_dep_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_dir_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_dist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_extension.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_file_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_filelist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_install.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_install_data.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_install_headers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_install_lib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_install_scripts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_log.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_register.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_sdist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_spawn.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_sysconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_text_file.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_upload.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_version.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/text_file.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/unixccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/version.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/distutils/versionpredicate.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/doctest.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/dummy_threading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/_encoded_words.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/_header_value_parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/_parseaddr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/_policybase.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/base64mime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/charset.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/contentmanager.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/encoders.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/errors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/feedparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/generator.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/header.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/headerregistry.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/iterators.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/application.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/audio.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/image.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/multipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/nonmultipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/mime/text.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/policy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/quoprimime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/email/utils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/aliases.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/ascii.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/base64_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/big5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/big5hkscs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/bz2_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/charmap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp037.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1006.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1026.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1125.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1140.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1250.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1251.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1252.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1253.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1254.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1255.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1256.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1257.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp1258.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp273.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp424.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp437.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp500.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp65001.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp720.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp737.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp775.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp850.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp852.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/shift_jisx0213.py +build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp855.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp856.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp857.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp858.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp860.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp861.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp862.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp863.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp864.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp865.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp866.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp869.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp874.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp875.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp932.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp949.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/cp950.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/euc_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/euc_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/euc_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/euc_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/gb18030.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/gb2312.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/gbk.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/hex_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/hp_roman8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/hz.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/idna.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_jp_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_jp_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_jp_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_jp_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_jp_ext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso2022_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_10.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_11.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_14.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_15.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_4.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_6.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_7.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/iso8859_9.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/johab.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/koi8_r.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/koi8_t.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/koi8_u.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/kz1048.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/latin_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_arabic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_centeuro.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_croatian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_cyrillic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_farsi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_greek.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_iceland.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_latin2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_roman.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_romanian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mac_turkish.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/mbcs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/oem.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/palmos.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/ptcp154.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/punycode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/quopri_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/raw_unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/rot_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/shift_jis.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/shift_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/shift_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/tis_620.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/undefined.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/unicode_internal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/utf_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/utf_16_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/utf_16_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/utf_32.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/utf_32_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/utf_32_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/base64_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/ptcp154.py + build/windows/Win32/Lib/encodings/utf_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/koi8_t.py +build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/uu_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1026.py +build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/encodings/zlib_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/charmap.py + build/windows/Win32/Lib/ensurepip/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_5.py +build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ensurepip/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_13.py +build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ensurepip/_uninstall.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/enum.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/filecmp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/fileinput.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/fnmatch.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/formatter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/fractions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ftplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/functools.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/genericpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/getopt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/getpass.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/gettext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/glob.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/gzip.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/hashlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/heapq.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/hmac.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/html/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/html/entities.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/html/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/http/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/http/client.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/http/cookiejar.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/http/cookies.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/http/server.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/imaplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/imghdr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/imp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/_bootstrap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/_bootstrap_external.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/abc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/machinery.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/resources.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/importlib/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/inspect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/io.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ipaddress.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/json/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/json/decoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/json/encoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/json/scanner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/json/tool.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/keyword.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/linecache.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/locale.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/logging/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/logging/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/logging/handlers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/lzma.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp.py + build/windows/Win32/Lib/macpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/_msvccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/mailbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/unixccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/mailcap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/filelist.py +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/mimetypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/ccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/modulefinder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/msvc9compiler.py +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/msilib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/archive_util.py +build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/msilib/schema.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/cmd.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/msilib/sequence.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/config.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/msilib/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/version.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/log.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/util.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/context.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/fancy_getopt.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/versionpredicate.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/__init__.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/file_util.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/heap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/core.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/managers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/cygwinccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/pool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/extension.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/debug.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/spawn.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/text_file.py +build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/msvccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/errors.py +build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/dep_util.py +build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/reduction.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/dir_util.py +build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/sysconfig.py +build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/dist.py +build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/bcppcompiler.py +build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist.py +build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_text_file.py +build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/multiprocessing/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py +build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/netrc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_version.py +build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/nntplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_lib.py +build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ntpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_py.py +build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/nturl2path.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_extension.py +build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_spawn.py +build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/opcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/support.py +build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/operator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py +build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/optparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_data.py +build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/os.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py +build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pathlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_filelist.py +build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pickletools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_core.py +build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pipes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py +build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pkgutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_cmd.py +build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/platform.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/__init__.py +build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/plistlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py +build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/poplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_sysconfig.py +build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/posixpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_util.py +build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pprint.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_clib.py +build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/profile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_register.py +build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pstats.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_log.py +build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_dep_util.py +build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/py_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build.py +build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pyclbr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_scripts.py +build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pydoc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_ext.py +build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pydoc_data/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_dir_util.py +build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/pydoc_data/topics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_headers.py +build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/queue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_clean.py +build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/quopri.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_check.py +build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/random.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_config.py +build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/re.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py +build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/reprlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_upload.py +build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/rlcompleter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_scripts.py +build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/runpy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py +build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sched.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_file_util.py +build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/secrets.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_dist.py +build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/selectors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install.py +build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/shelve.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_config_cmd.py +build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/shlex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_sdist.py +build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/shutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_archive_util.py +build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/signal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build.py +build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/site.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_ext.py +build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/smtpd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/config.py +build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/smtplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/clean.py +build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sndhdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/check.py +build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/socket.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_scripts.py +build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/socketserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/upload.py +build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/register.py +build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_wininst.py +build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_headers.py +build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_lib.py +build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/backup.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_py.py +build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_dumb.py +build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/__init__.py +build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/factory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/sdist.py +build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist.py +build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/regression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_scripts.py +build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_rpm.py +build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_clib.py +build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install.py +build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sre_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_msi.py +build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sre_constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_egg_info.py +build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sre_parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_data.py +build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/ssl.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/_aix.py +build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/stat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/wintypes.py +build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/statistics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/util.py +build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/string.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/__init__.py +build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/stringprep.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/_endian.py +build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py +build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_random_things.py +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sunau.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_funcptr.py +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/symbol.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_callbacks.py +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/symtable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_unicode.py +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_structures.py +build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/tabnanny.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_cast.py +build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/tarfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py +build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/telnetlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_keeprefs.py +build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/tempfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_loading.py +build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/textwrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_memfunctions.py +build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/this.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_slicing.py +build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_numbers.py +build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/timeit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_libc.py +build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/token.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_python_api.py +build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/tokenize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_bytes.py +build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/trace.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_pep3118.py +build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/traceback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/__init__.py +build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/tracemalloc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_frombuffer.py +build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/tty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_parameters.py +build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/turtle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_wintypes.py +build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_pointers.py +build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/typing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_errno.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_arrays.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_cfuncs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_find.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_refcounts.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_internals.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_prototypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_values.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_stringptr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_as_parameter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_pickling.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_bitfields.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_byteswap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_functions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_repr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_macholib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_incomplete.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_strings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_struct_fields.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_buffers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_anon.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_init.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_checkretval.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_delattr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_objects.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_sizes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_win32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/dylib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/signals.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/runner.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/suite.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/result.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/loader.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/case.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/main.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/case.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/loader.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/main.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/mock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_result.py +build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/runner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/signals.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/suite.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/__main__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/_test_warnings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/dummy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_loader.py +build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_skipping.py +build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_break.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_setups.py +build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_case.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_discovery.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_break.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_case.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_discovery.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_runner.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_program.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_suite.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_assertions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/_test_warnings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/dummy.py + build/windows/Win32/Lib/unittest/test/test_loader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/__main__.py + build/windows/Win32/Lib/unittest/test/test_program.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/support.py +build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testcallable.py +build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_runner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_setups.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_skipping.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/test_suite.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testmock.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testwith.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testpatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testsealable.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/textpad.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/ascii.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/__init__.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/has_key.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/panel.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/queues.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/heap.py +build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/reduction.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/util.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/unittest/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/connection.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/context.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/spawn.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/synchronize.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/process.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/sharedctypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_fork.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/pool.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/managers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/resource_sharer.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/dummy/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/dummy/connection.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/sequence.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/schema.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/error.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/request.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/response.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/urllib/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/robotparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/html/__init__.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/urllib/request.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/html/parser.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/urllib/response.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/html/entities.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/urllib/robotparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/__init__.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/uu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/parsers/expat.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/uuid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/parsers/__init__.py +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/venv/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/handler.py +build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/venv/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/__init__.py +build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/saxutils.py +build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/wave.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/xmlreader.py +build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/weakref.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/expatreader.py +build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/webbrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/NodeFilter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/xmlbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/minidom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/ElementPath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/cElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/ElementInclude.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/ElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/wsgiref/handlers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/wsgiref/headers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/wsgiref/simple_server.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/wsgiref/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/validate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/simple_server.py + build/windows/Win32/Lib/xdrlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/headers.py +build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/decoder.py +build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/scanner.py +build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/__init__.py +build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/encoder.py +build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/tool.py +build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/minicompat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/cookies.py +build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/server.py +build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/pulldom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/client.py +build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/__init__.py +build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/cookiejar.py +build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/__init__.py +build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/dump.py +build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/etree/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/dbapi2.py +build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/backup.py +build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/hooks.py +build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/regression.py +build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/dbapi.py +build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/transactions.py +build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/__init__.py +build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/types.py +build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/factory.py +build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/dump.py +build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/userfunctions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ensurepip/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ensurepip/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ensurepip/_uninstall.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/venv/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/venv/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/ndbm.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/gnu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/dumb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xmlrpc/__init__.py + build/windows/Win32/Lib/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pydoc_data/__init__.py +build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pydoc_data/topics.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/collections/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/base.py +build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ + build/windows/Win32/Lib/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ - build/windows/x64/Lib/zipfile.py \ - build/windows/x64/Lib/shutil.py \ - build/windows/x64/Lib/tempfile.py \ - build/windows/x64/Lib/queue.py \ - build/windows/x64/Lib/macpath.py \ - build/windows/x64/Lib/_pyio.py \ - build/windows/x64/Lib/crypt.py \ - build/windows/x64/Lib/pkgutil.py \ - build/windows/x64/Lib/_dummy_thread.py \ - build/windows/x64/Lib/lzma.py \ - build/windows/x64/Lib/asyncore.py \ - build/windows/x64/Lib/__phello__.foo.py \ - build/windows/x64/Lib/_sitebuiltins.py \ - build/windows/x64/Lib/copyreg.py \ - build/windows/x64/Lib/sndhdr.py \ - build/windows/x64/Lib/rlcompleter.py \ - build/windows/x64/Lib/gzip.py \ - build/windows/x64/Lib/ipaddress.py \ - build/windows/x64/Lib/trace.py \ - build/windows/x64/Lib/webbrowser.py \ - build/windows/x64/Lib/nntplib.py \ - build/windows/x64/Lib/_compat_pickle.py \ - build/windows/x64/Lib/dis.py \ - build/windows/x64/Lib/formatter.py \ - build/windows/x64/Lib/bdb.py \ - build/windows/x64/Lib/zipapp.py \ - build/windows/x64/Lib/cmd.py \ - build/windows/x64/Lib/tty.py \ - build/windows/x64/Lib/tabnanny.py \ - build/windows/x64/Lib/_py_abc.py \ - build/windows/x64/Lib/cProfile.py \ - build/windows/x64/Lib/token.py \ - build/windows/x64/Lib/textwrap.py \ - build/windows/x64/Lib/base64.py \ - build/windows/x64/Lib/_markupbase.py \ - build/windows/x64/Lib/bz2.py \ - build/windows/x64/Lib/signal.py \ - build/windows/x64/Lib/sre_constants.py \ - build/windows/x64/Lib/cgitb.py \ - build/windows/x64/Lib/_threading_local.py \ - build/windows/x64/Lib/pyclbr.py \ - build/windows/x64/Lib/gettext.py \ - build/windows/x64/Lib/wave.py \ - build/windows/x64/Lib/weakref.py \ - build/windows/x64/Lib/bisect.py \ - build/windows/x64/Lib/opcode.py \ - build/windows/x64/Lib/netrc.py \ - build/windows/x64/Lib/heapq.py \ - build/windows/x64/Lib/functools.py \ - build/windows/x64/Lib/modulefinder.py \ - build/windows/x64/Lib/_compression.py \ - build/windows/x64/Lib/tracemalloc.py \ - build/windows/x64/Lib/hashlib.py \ - build/windows/x64/Lib/cgi.py \ - build/windows/x64/Lib/codeop.py \ - build/windows/x64/Lib/fnmatch.py \ - build/windows/x64/Lib/traceback.py \ - build/windows/x64/Lib/nturl2path.py \ - build/windows/x64/Lib/warnings.py \ - build/windows/x64/Lib/subprocess.py \ - build/windows/x64/Lib/profile.py \ - build/windows/x64/Lib/imghdr.py \ - build/windows/x64/Lib/this.py \ - build/windows/x64/Lib/filecmp.py \ - build/windows/x64/Lib/codecs.py \ - build/windows/x64/Lib/uu.py \ - build/windows/x64/Lib/_weakrefset.py \ - build/windows/x64/Lib/io.py \ - build/windows/x64/Lib/code.py \ - build/windows/x64/Lib/operator.py \ - build/windows/x64/Lib/fileinput.py \ - build/windows/x64/Lib/os.py \ - build/windows/x64/Lib/difflib.py \ - build/windows/x64/Lib/pydoc.py \ - build/windows/x64/Lib/symbol.py \ - build/windows/x64/Lib/selectors.py \ - build/windows/x64/Lib/decimal.py \ - build/windows/x64/Lib/socketserver.py \ - build/windows/x64/Lib/copy.py \ - build/windows/x64/Lib/genericpath.py \ - build/windows/x64/Lib/linecache.py \ - build/windows/x64/Lib/types.py \ - build/windows/x64/Lib/mimetypes.py \ - build/windows/x64/Lib/xdrlib.py \ - build/windows/x64/Lib/colorsys.py \ - build/windows/x64/Lib/numbers.py \ - build/windows/x64/Lib/_strptime.py \ - build/windows/x64/Lib/dummy_threading.py \ - build/windows/x64/Lib/contextvars.py \ - build/windows/x64/Lib/random.py \ - build/windows/x64/Lib/ftplib.py \ - build/windows/x64/Lib/chunk.py \ - build/windows/x64/Lib/optparse.py \ - build/windows/x64/Lib/pdb.py \ - build/windows/x64/Lib/threading.py \ - build/windows/x64/Lib/turtle.py \ - build/windows/x64/Lib/platform.py \ - build/windows/x64/Lib/pstats.py \ - build/windows/x64/Lib/glob.py \ - build/windows/x64/Lib/quopri.py \ - build/windows/x64/Lib/symtable.py \ - build/windows/x64/Lib/pprint.py \ - build/windows/x64/Lib/calendar.py \ - build/windows/x64/Lib/inspect.py \ - build/windows/x64/Lib/poplib.py \ - build/windows/x64/Lib/binhex.py \ - build/windows/x64/Lib/plistlib.py \ - build/windows/x64/Lib/pickletools.py \ - build/windows/x64/Lib/pipes.py \ - build/windows/x64/Lib/site.py \ - build/windows/x64/Lib/telnetlib.py \ - build/windows/x64/Lib/keyword.py \ - build/windows/x64/Lib/configparser.py \ - build/windows/x64/Lib/reprlib.py \ - build/windows/x64/Lib/secrets.py \ - build/windows/x64/Lib/shlex.py \ - build/windows/x64/Lib/posixpath.py \ - build/windows/x64/Lib/py_compile.py \ - build/windows/x64/Lib/_osx_support.py \ - build/windows/x64/Lib/stat.py \ - build/windows/x64/Lib/compileall.py \ - build/windows/x64/Lib/csv.py \ - build/windows/x64/Lib/fractions.py \ - build/windows/x64/Lib/sched.py \ - build/windows/x64/Lib/imaplib.py \ - build/windows/x64/Lib/mailbox.py \ - build/windows/x64/Lib/sre_compile.py \ - build/windows/x64/Lib/locale.py \ - build/windows/x64/Lib/ast.py \ - build/windows/x64/Lib/doctest.py \ - build/windows/x64/Lib/argparse.py \ - build/windows/x64/Lib/getpass.py \ - build/windows/x64/Lib/pickle.py \ - build/windows/x64/Lib/pty.py \ - build/windows/x64/Lib/contextlib.py \ - build/windows/x64/Lib/statistics.py \ - build/windows/x64/Lib/_collections_abc.py \ - build/windows/x64/Lib/sunau.py \ build/windows/x64/Lib/__future__.py \ - build/windows/x64/Lib/dataclasses.py \ - build/windows/x64/Lib/shelve.py \ - build/windows/x64/Lib/string.py \ - build/windows/x64/Lib/smtplib.py \ - build/windows/x64/Lib/getopt.py \ - build/windows/x64/Lib/antigravity.py \ - build/windows/x64/Lib/enum.py \ - build/windows/x64/Lib/timeit.py \ - build/windows/x64/Lib/hmac.py \ - build/windows/x64/Lib/tarfile.py \ - build/windows/x64/Lib/stringprep.py \ - build/windows/x64/Lib/typing.py \ - build/windows/x64/Lib/ssl.py \ - build/windows/x64/Lib/socket.py \ - build/windows/x64/Lib/datetime.py \ - build/windows/x64/Lib/sysconfig.py \ - build/windows/x64/Lib/pathlib.py \ - build/windows/x64/Lib/_pydecimal.py \ - build/windows/x64/Lib/ntpath.py \ - build/windows/x64/Lib/tokenize.py \ - build/windows/x64/Lib/uuid.py \ - build/windows/x64/Lib/imp.py \ - build/windows/x64/Lib/smtpd.py \ - build/windows/x64/Lib/re.py \ - build/windows/x64/Lib/mailcap.py \ - build/windows/x64/Lib/aifc.py \ - build/windows/x64/Lib/struct.py \ - build/windows/x64/Lib/asynchat.py \ - build/windows/x64/Lib/sre_parse.py \ - build/windows/x64/Lib/abc.py \ - build/windows/x64/Lib/runpy.py \ + build/windows/x64/Lib/__phello__.foo.py \ build/windows/x64/Lib/_bootlocale.py \ - build/windows/x64/Lib/encodings/mac_romanian.py \ - build/windows/x64/Lib/encodings/mac_farsi.py \ - build/windows/x64/Lib/encodings/idna.py \ - build/windows/x64/Lib/encodings/cp273.py \ - build/windows/x64/Lib/encodings/punycode.py \ - build/windows/x64/Lib/encodings/raw_unicode_escape.py \ - build/windows/x64/Lib/encodings/utf_8.py \ - build/windows/x64/Lib/encodings/cp1252.py \ - build/windows/x64/Lib/encodings/cp869.py \ - build/windows/x64/Lib/encodings/iso8859_14.py \ - build/windows/x64/Lib/encodings/iso8859_2.py \ - build/windows/x64/Lib/encodings/mac_arabic.py \ - build/windows/x64/Lib/encodings/mac_croatian.py \ - build/windows/x64/Lib/encodings/big5hkscs.py \ - build/windows/x64/Lib/encodings/cp1256.py \ - build/windows/x64/Lib/encodings/iso8859_6.py \ - build/windows/x64/Lib/encodings/iso8859_10.py \ - build/windows/x64/Lib/encodings/iso2022_kr.py \ - build/windows/x64/Lib/encodings/cp1140.py \ - build/windows/x64/Lib/encodings/unicode_internal.py \ - build/windows/x64/Lib/encodings/cp1125.py \ - build/windows/x64/Lib/encodings/iso2022_jp_1.py \ - build/windows/x64/Lib/encodings/cp1257.py \ - build/windows/x64/Lib/encodings/cp949.py \ - build/windows/x64/Lib/encodings/cp858.py \ - build/windows/x64/Lib/encodings/iso8859_7.py \ - build/windows/x64/Lib/encodings/iso8859_11.py \ - build/windows/x64/Lib/encodings/hp_roman8.py \ - build/windows/x64/Lib/encodings/koi8_r.py \ - build/windows/x64/Lib/encodings/zlib_codec.py \ - build/windows/x64/Lib/encodings/gbk.py \ - build/windows/x64/Lib/encodings/johab.py \ - build/windows/x64/Lib/encodings/cp1253.py \ - build/windows/x64/Lib/encodings/iso8859_15.py \ - build/windows/x64/Lib/encodings/iso2022_jp_2004.py \ - build/windows/x64/Lib/encodings/mac_iceland.py \ - build/windows/x64/Lib/encodings/iso8859_3.py \ - build/windows/x64/Lib/encodings/mac_greek.py \ - build/windows/x64/Lib/encodings/rot_13.py \ - build/windows/x64/Lib/encodings/utf_16_be.py \ - build/windows/x64/Lib/encodings/euc_kr.py \ - build/windows/x64/Lib/encodings/mac_centeuro.py \ - build/windows/x64/Lib/encodings/euc_jisx0213.py \ - build/windows/x64/Lib/encodings/cp863.py \ - build/windows/x64/Lib/encodings/ascii.py \ - build/windows/x64/Lib/encodings/iso8859_8.py \ - build/windows/x64/Lib/encodings/cp857.py \ - build/windows/x64/Lib/encodings/utf_32_be.py \ - build/windows/x64/Lib/encodings/cp1258.py \ - build/windows/x64/Lib/encodings/oem.py \ - build/windows/x64/Lib/encodings/mac_latin2.py \ - build/windows/x64/Lib/encodings/cp775.py \ - build/windows/x64/Lib/encodings/mac_roman.py \ - build/windows/x64/Lib/encodings/__init__.py \ - build/windows/x64/Lib/encodings/cp852.py \ - build/windows/x64/Lib/encodings/shift_jisx0213.py \ - build/windows/x64/Lib/encodings/cp866.py \ - build/windows/x64/Lib/encodings/utf_7.py \ - build/windows/x64/Lib/encodings/base64_codec.py \ - build/windows/x64/Lib/encodings/cp932.py \ - build/windows/x64/Lib/encodings/cp720.py \ - build/windows/x64/Lib/encodings/cp862.py \ - build/windows/x64/Lib/encodings/cp437.py \ - build/windows/x64/Lib/encodings/palmos.py \ - build/windows/x64/Lib/encodings/iso8859_9.py \ - build/windows/x64/Lib/encodings/cp856.py \ - build/windows/x64/Lib/encodings/aliases.py \ - build/windows/x64/Lib/encodings/latin_1.py \ - build/windows/x64/Lib/encodings/cp875.py \ - build/windows/x64/Lib/encodings/cp950.py \ - build/windows/x64/Lib/encodings/unicode_escape.py \ - build/windows/x64/Lib/encodings/cp737.py \ - build/windows/x64/Lib/encodings/cp865.py \ - build/windows/x64/Lib/encodings/ptcp154.py \ - build/windows/x64/Lib/encodings/big5.py \ - build/windows/x64/Lib/encodings/cp424.py \ - build/windows/x64/Lib/encodings/cp861.py \ - build/windows/x64/Lib/encodings/euc_jp.py \ - build/windows/x64/Lib/encodings/cp855.py \ - build/windows/x64/Lib/encodings/shift_jis.py \ - build/windows/x64/Lib/encodings/utf_32_le.py \ - build/windows/x64/Lib/encodings/cp500.py \ - build/windows/x64/Lib/encodings/undefined.py \ - build/windows/x64/Lib/encodings/cp860.py \ - build/windows/x64/Lib/encodings/uu_codec.py \ - build/windows/x64/Lib/encodings/utf_16_le.py \ - build/windows/x64/Lib/encodings/gb18030.py \ - build/windows/x64/Lib/encodings/cp65001.py \ - build/windows/x64/Lib/encodings/cp874.py \ - build/windows/x64/Lib/encodings/cp850.py \ - build/windows/x64/Lib/encodings/cp864.py \ - build/windows/x64/Lib/encodings/utf_32.py \ - build/windows/x64/Lib/encodings/koi8_u.py \ - build/windows/x64/Lib/encodings/cp1254.py \ - build/windows/x64/Lib/encodings/iso2022_jp_2.py \ - build/windows/x64/Lib/encodings/utf_16.py \ - build/windows/x64/Lib/encodings/iso8859_4.py \ - build/windows/x64/Lib/encodings/euc_jis_2004.py \ - build/windows/x64/Lib/encodings/mbcs.py \ - build/windows/x64/Lib/encodings/cp1250.py \ - build/windows/x64/Lib/encodings/gb2312.py \ - build/windows/x64/Lib/encodings/iso8859_16.py \ - build/windows/x64/Lib/encodings/mac_cyrillic.py \ - build/windows/x64/Lib/encodings/hex_codec.py \ - build/windows/x64/Lib/encodings/tis_620.py \ - build/windows/x64/Lib/encodings/cp037.py \ - build/windows/x64/Lib/encodings/cp1006.py \ - build/windows/x64/Lib/encodings/cp1251.py \ - build/windows/x64/Lib/encodings/mac_turkish.py \ - build/windows/x64/Lib/encodings/iso2022_jp_ext.py \ - build/windows/x64/Lib/encodings/iso8859_1.py \ - build/windows/x64/Lib/encodings/hz.py \ - build/windows/x64/Lib/encodings/bz2_codec.py \ - build/windows/x64/Lib/encodings/quopri_codec.py \ - build/windows/x64/Lib/encodings/kz1048.py \ - build/windows/x64/Lib/encodings/utf_8_sig.py \ - build/windows/x64/Lib/encodings/koi8_t.py \ - build/windows/x64/Lib/encodings/cp1255.py \ - build/windows/x64/Lib/encodings/iso2022_jp_3.py \ - build/windows/x64/Lib/encodings/shift_jis_2004.py \ - build/windows/x64/Lib/encodings/cp1026.py \ - build/windows/x64/Lib/encodings/charmap.py \ - build/windows/x64/Lib/encodings/iso8859_5.py \ - build/windows/x64/Lib/encodings/iso8859_13.py \ - build/windows/x64/Lib/encodings/iso2022_jp.py \ - build/windows/x64/Lib/distutils/_msvccompiler.py \ - build/windows/x64/Lib/distutils/unixccompiler.py \ - build/windows/x64/Lib/distutils/filelist.py \ - build/windows/x64/Lib/distutils/ccompiler.py \ - build/windows/x64/Lib/distutils/msvc9compiler.py \ - build/windows/x64/Lib/distutils/archive_util.py \ - build/windows/x64/Lib/distutils/cmd.py \ - build/windows/x64/Lib/distutils/config.py \ - build/windows/x64/Lib/distutils/version.py \ - build/windows/x64/Lib/distutils/log.py \ - build/windows/x64/Lib/distutils/util.py \ - build/windows/x64/Lib/distutils/fancy_getopt.py \ - build/windows/x64/Lib/distutils/versionpredicate.py \ - build/windows/x64/Lib/distutils/__init__.py \ - build/windows/x64/Lib/distutils/file_util.py \ - build/windows/x64/Lib/distutils/core.py \ - build/windows/x64/Lib/distutils/cygwinccompiler.py \ - build/windows/x64/Lib/distutils/extension.py \ - build/windows/x64/Lib/distutils/debug.py \ - build/windows/x64/Lib/distutils/spawn.py \ - build/windows/x64/Lib/distutils/text_file.py \ - build/windows/x64/Lib/distutils/msvccompiler.py \ - build/windows/x64/Lib/distutils/errors.py \ - build/windows/x64/Lib/distutils/dep_util.py \ - build/windows/x64/Lib/distutils/dir_util.py \ - build/windows/x64/Lib/distutils/sysconfig.py \ - build/windows/x64/Lib/distutils/dist.py \ - build/windows/x64/Lib/distutils/bcppcompiler.py \ - build/windows/x64/Lib/distutils/tests/test_bdist.py \ - build/windows/x64/Lib/distutils/tests/test_text_file.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py \ - build/windows/x64/Lib/distutils/tests/test_version.py \ - build/windows/x64/Lib/distutils/tests/test_install_lib.py \ - build/windows/x64/Lib/distutils/tests/test_build_py.py \ - build/windows/x64/Lib/distutils/tests/test_extension.py \ - build/windows/x64/Lib/distutils/tests/test_spawn.py \ - build/windows/x64/Lib/distutils/tests/support.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py \ - build/windows/x64/Lib/distutils/tests/test_install_data.py \ - build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py \ - build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py \ - build/windows/x64/Lib/distutils/tests/test_unixccompiler.py \ - build/windows/x64/Lib/distutils/tests/test_filelist.py \ - build/windows/x64/Lib/distutils/tests/test_core.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_msi.py \ - build/windows/x64/Lib/distutils/tests/test_cmd.py \ - build/windows/x64/Lib/distutils/tests/__init__.py \ - build/windows/x64/Lib/distutils/tests/test_msvccompiler.py \ - build/windows/x64/Lib/distutils/tests/test_sysconfig.py \ - build/windows/x64/Lib/distutils/tests/test_util.py \ - build/windows/x64/Lib/distutils/tests/test_build_clib.py \ - build/windows/x64/Lib/distutils/tests/test_register.py \ - build/windows/x64/Lib/distutils/tests/test_log.py \ - build/windows/x64/Lib/distutils/tests/test_dep_util.py \ - build/windows/x64/Lib/distutils/tests/test_build.py \ - build/windows/x64/Lib/distutils/tests/test_install_scripts.py \ - build/windows/x64/Lib/distutils/tests/test_build_ext.py \ - build/windows/x64/Lib/distutils/tests/test_dir_util.py \ - build/windows/x64/Lib/distutils/tests/test_install_headers.py \ - build/windows/x64/Lib/distutils/tests/test_clean.py \ - build/windows/x64/Lib/distutils/tests/test_check.py \ - build/windows/x64/Lib/distutils/tests/test_config.py \ - build/windows/x64/Lib/distutils/tests/test_versionpredicate.py \ - build/windows/x64/Lib/distutils/tests/test_upload.py \ - build/windows/x64/Lib/distutils/tests/test_build_scripts.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py \ - build/windows/x64/Lib/distutils/tests/test_file_util.py \ - build/windows/x64/Lib/distutils/tests/test_dist.py \ - build/windows/x64/Lib/distutils/tests/test_install.py \ - build/windows/x64/Lib/distutils/tests/test_config_cmd.py \ - build/windows/x64/Lib/distutils/tests/test_sdist.py \ - build/windows/x64/Lib/distutils/tests/test_archive_util.py \ - build/windows/x64/Lib/distutils/command/build.py \ - build/windows/x64/Lib/distutils/command/build_ext.py \ - build/windows/x64/Lib/distutils/command/config.py \ - build/windows/x64/Lib/distutils/command/clean.py \ - build/windows/x64/Lib/distutils/command/check.py \ - build/windows/x64/Lib/distutils/command/install_scripts.py \ - build/windows/x64/Lib/distutils/command/upload.py \ - build/windows/x64/Lib/distutils/command/register.py \ - build/windows/x64/Lib/distutils/command/bdist_wininst.py \ - build/windows/x64/Lib/distutils/command/install_headers.py \ - build/windows/x64/Lib/distutils/command/install_lib.py \ - build/windows/x64/Lib/distutils/command/build_py.py \ - build/windows/x64/Lib/distutils/command/bdist_dumb.py \ - build/windows/x64/Lib/distutils/command/__init__.py \ - build/windows/x64/Lib/distutils/command/sdist.py \ - build/windows/x64/Lib/distutils/command/bdist.py \ - build/windows/x64/Lib/distutils/command/build_scripts.py \ - build/windows/x64/Lib/distutils/command/bdist_rpm.py \ - build/windows/x64/Lib/distutils/command/build_clib.py \ - build/windows/x64/Lib/distutils/command/install.py \ - build/windows/x64/Lib/distutils/command/bdist_msi.py \ - build/windows/x64/Lib/distutils/command/install_egg_info.py \ - build/windows/x64/Lib/distutils/command/install_data.py \ - build/windows/x64/Lib/ctypes/_aix.py \ - build/windows/x64/Lib/ctypes/wintypes.py \ - build/windows/x64/Lib/ctypes/util.py \ + build/windows/x64/Lib/_collections_abc.py \ + build/windows/x64/Lib/_compat_pickle.py \ + build/windows/x64/Lib/_compression.py \ + build/windows/x64/Lib/_dummy_thread.py \ + build/windows/x64/Lib/_markupbase.py \ + build/windows/x64/Lib/_osx_support.py \ + build/windows/x64/Lib/_py_abc.py \ + build/windows/x64/Lib/_pydecimal.py \ + build/windows/x64/Lib/_pyio.py \ + build/windows/x64/Lib/_sitebuiltins.py \ + build/windows/x64/Lib/_strptime.py \ + build/windows/x64/Lib/_threading_local.py \ + build/windows/x64/Lib/_weakrefset.py \ + build/windows/x64/Lib/abc.py \ + build/windows/x64/Lib/aifc.py \ + build/windows/x64/Lib/antigravity.py \ + build/windows/x64/Lib/argparse.py \ + build/windows/x64/Lib/ast.py \ + build/windows/x64/Lib/asynchat.py \ + build/windows/x64/Lib/asyncio/__init__.py \ + build/windows/x64/Lib/asyncio/base_events.py \ + build/windows/x64/Lib/asyncio/base_futures.py \ + build/windows/x64/Lib/asyncio/base_subprocess.py \ + build/windows/x64/Lib/asyncio/base_tasks.py \ + build/windows/x64/Lib/asyncio/constants.py \ + build/windows/x64/Lib/asyncio/coroutines.py \ + build/windows/x64/Lib/asyncio/events.py \ + build/windows/x64/Lib/asyncio/format_helpers.py \ + build/windows/x64/Lib/asyncio/futures.py \ + build/windows/x64/Lib/asyncio/locks.py \ + build/windows/x64/Lib/asyncio/log.py \ + build/windows/x64/Lib/asyncio/proactor_events.py \ + build/windows/x64/Lib/asyncio/protocols.py \ + build/windows/x64/Lib/asyncio/queues.py \ + build/windows/x64/Lib/asyncio/runners.py \ + build/windows/x64/Lib/asyncio/selector_events.py \ + build/windows/x64/Lib/asyncio/sslproto.py \ + build/windows/x64/Lib/asyncio/streams.py \ + build/windows/x64/Lib/asyncio/subprocess.py \ + build/windows/x64/Lib/asyncio/tasks.py \ + build/windows/x64/Lib/asyncio/transports.py \ + build/windows/x64/Lib/asyncio/unix_events.py \ + build/windows/x64/Lib/asyncio/windows_events.py \ + build/windows/x64/Lib/asyncio/windows_utils.py \ + build/windows/x64/Lib/asyncore.py \ + build/windows/x64/Lib/base64.py \ + build/windows/x64/Lib/bdb.py \ + build/windows/x64/Lib/binhex.py \ + build/windows/x64/Lib/bisect.py \ + build/windows/x64/Lib/bz2.py \ + build/windows/x64/Lib/cProfile.py \ + build/windows/x64/Lib/calendar.py \ + build/windows/x64/Lib/cgi.py \ + build/windows/x64/Lib/cgitb.py \ + build/windows/x64/Lib/chunk.py \ + build/windows/x64/Lib/cmd.py \ + build/windows/x64/Lib/code.py \ + build/windows/x64/Lib/codecs.py \ + build/windows/x64/Lib/codeop.py \ + build/windows/x64/Lib/collections/__init__.py \ + build/windows/x64/Lib/collections/abc.py \ + build/windows/x64/Lib/colorsys.py \ + build/windows/x64/Lib/compileall.py \ + build/windows/x64/Lib/concurrent/__init__.py \ + build/windows/x64/Lib/concurrent/futures/__init__.py \ + build/windows/x64/Lib/concurrent/futures/_base.py \ + build/windows/x64/Lib/concurrent/futures/process.py \ + build/windows/x64/Lib/concurrent/futures/thread.py \ + build/windows/x64/Lib/configparser.py \ + build/windows/x64/Lib/contextlib.py \ + build/windows/x64/Lib/contextvars.py \ + build/windows/x64/Lib/copy.py \ + build/windows/x64/Lib/copyreg.py \ + build/windows/x64/Lib/crypt.py \ + build/windows/x64/Lib/csv.py \ build/windows/x64/Lib/ctypes/__init__.py \ + build/windows/x64/Lib/ctypes/_aix.py \ build/windows/x64/Lib/ctypes/_endian.py \ - build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py \ - build/windows/x64/Lib/ctypes/test/test_random_things.py \ - build/windows/x64/Lib/ctypes/test/test_funcptr.py \ - build/windows/x64/Lib/ctypes/test/test_callbacks.py \ - build/windows/x64/Lib/ctypes/test/test_unicode.py \ - build/windows/x64/Lib/ctypes/test/test_structures.py \ - build/windows/x64/Lib/ctypes/test/test_cast.py \ - build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py \ - build/windows/x64/Lib/ctypes/test/test_keeprefs.py \ - build/windows/x64/Lib/ctypes/test/test_loading.py \ - build/windows/x64/Lib/ctypes/test/test_memfunctions.py \ - build/windows/x64/Lib/ctypes/test/test_slicing.py \ - build/windows/x64/Lib/ctypes/test/test_numbers.py \ - build/windows/x64/Lib/ctypes/test/test_libc.py \ - build/windows/x64/Lib/ctypes/test/test_python_api.py \ - build/windows/x64/Lib/ctypes/test/test_bytes.py \ - build/windows/x64/Lib/ctypes/test/test_pep3118.py \ + build/windows/x64/Lib/ctypes/macholib/__init__.py \ + build/windows/x64/Lib/ctypes/macholib/dyld.py \ + build/windows/x64/Lib/ctypes/macholib/dylib.py \ + build/windows/x64/Lib/ctypes/macholib/framework.py \ build/windows/x64/Lib/ctypes/test/__init__.py \ - build/windows/x64/Lib/ctypes/test/test_frombuffer.py \ - build/windows/x64/Lib/ctypes/test/test_parameters.py \ - build/windows/x64/Lib/ctypes/test/test_wintypes.py \ - build/windows/x64/Lib/ctypes/test/test_pointers.py \ - build/windows/x64/Lib/ctypes/test/test_errno.py \ - build/windows/x64/Lib/ctypes/test/test_arrays.py \ - build/windows/x64/Lib/ctypes/test/test_cfuncs.py \ - build/windows/x64/Lib/ctypes/test/test_find.py \ - build/windows/x64/Lib/ctypes/test/test_refcounts.py \ - build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py \ - build/windows/x64/Lib/ctypes/test/test_internals.py \ - build/windows/x64/Lib/ctypes/test/test_prototypes.py \ - build/windows/x64/Lib/ctypes/test/test_values.py \ - build/windows/x64/Lib/ctypes/test/test_varsize_struct.py \ - build/windows/x64/Lib/ctypes/test/test_stringptr.py \ - build/windows/x64/Lib/ctypes/test/test_as_parameter.py \ - build/windows/x64/Lib/ctypes/test/test_pickling.py \ - build/windows/x64/Lib/ctypes/test/test_bitfields.py \ - build/windows/x64/Lib/ctypes/test/test_byteswap.py \ - build/windows/x64/Lib/ctypes/test/test_functions.py \ - build/windows/x64/Lib/ctypes/test/test_repr.py \ - build/windows/x64/Lib/ctypes/test/test_macholib.py \ - build/windows/x64/Lib/ctypes/test/test_incomplete.py \ - build/windows/x64/Lib/ctypes/test/test_strings.py \ - build/windows/x64/Lib/ctypes/test/test_struct_fields.py \ - build/windows/x64/Lib/ctypes/test/test_buffers.py \ - build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py \ + build/windows/x64/Lib/ctypes/test/__main__.py \ build/windows/x64/Lib/ctypes/test/test_anon.py \ - build/windows/x64/Lib/ctypes/test/test_init.py \ + build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py \ + build/windows/x64/Lib/ctypes/test/test_arrays.py \ + build/windows/x64/Lib/ctypes/test/test_as_parameter.py \ + build/windows/x64/Lib/ctypes/test/test_bitfields.py \ + build/windows/x64/Lib/ctypes/test/test_buffers.py \ + build/windows/x64/Lib/ctypes/test/test_bytes.py \ + build/windows/x64/Lib/ctypes/test/test_byteswap.py \ + build/windows/x64/Lib/ctypes/test/test_callbacks.py \ + build/windows/x64/Lib/ctypes/test/test_cast.py \ + build/windows/x64/Lib/ctypes/test/test_cfuncs.py \ build/windows/x64/Lib/ctypes/test/test_checkretval.py \ build/windows/x64/Lib/ctypes/test/test_delattr.py \ - build/windows/x64/Lib/ctypes/test/__main__.py \ + build/windows/x64/Lib/ctypes/test/test_errno.py \ + build/windows/x64/Lib/ctypes/test/test_find.py \ + build/windows/x64/Lib/ctypes/test/test_frombuffer.py \ + build/windows/x64/Lib/ctypes/test/test_funcptr.py \ + build/windows/x64/Lib/ctypes/test/test_functions.py \ + build/windows/x64/Lib/ctypes/test/test_incomplete.py \ + build/windows/x64/Lib/ctypes/test/test_init.py \ + build/windows/x64/Lib/ctypes/test/test_internals.py \ + build/windows/x64/Lib/ctypes/test/test_keeprefs.py \ + build/windows/x64/Lib/ctypes/test/test_libc.py \ + build/windows/x64/Lib/ctypes/test/test_loading.py \ + build/windows/x64/Lib/ctypes/test/test_macholib.py \ + build/windows/x64/Lib/ctypes/test/test_memfunctions.py \ + build/windows/x64/Lib/ctypes/test/test_numbers.py \ build/windows/x64/Lib/ctypes/test/test_objects.py \ + build/windows/x64/Lib/ctypes/test/test_parameters.py \ + build/windows/x64/Lib/ctypes/test/test_pep3118.py \ + build/windows/x64/Lib/ctypes/test/test_pickling.py \ + build/windows/x64/Lib/ctypes/test/test_pointers.py \ + build/windows/x64/Lib/ctypes/test/test_prototypes.py \ + build/windows/x64/Lib/ctypes/test/test_python_api.py \ + build/windows/x64/Lib/ctypes/test/test_random_things.py \ + build/windows/x64/Lib/ctypes/test/test_refcounts.py \ + build/windows/x64/Lib/ctypes/test/test_repr.py \ + build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py \ + build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py \ build/windows/x64/Lib/ctypes/test/test_sizes.py \ + build/windows/x64/Lib/ctypes/test/test_slicing.py \ + build/windows/x64/Lib/ctypes/test/test_stringptr.py \ + build/windows/x64/Lib/ctypes/test/test_strings.py \ + build/windows/x64/Lib/ctypes/test/test_struct_fields.py \ + build/windows/x64/Lib/ctypes/test/test_structures.py \ + build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py \ + build/windows/x64/Lib/ctypes/test/test_unicode.py \ + build/windows/x64/Lib/ctypes/test/test_values.py \ + build/windows/x64/Lib/ctypes/test/test_varsize_struct.py \ build/windows/x64/Lib/ctypes/test/test_win32.py \ - build/windows/x64/Lib/ctypes/macholib/dyld.py \ - build/windows/x64/Lib/ctypes/macholib/framework.py \ - build/windows/x64/Lib/ctypes/macholib/__init__.py \ - build/windows/x64/Lib/ctypes/macholib/dylib.py \ - build/windows/x64/Lib/unittest/signals.py \ - build/windows/x64/Lib/unittest/runner.py \ - build/windows/x64/Lib/unittest/suite.py \ - build/windows/x64/Lib/unittest/util.py \ - build/windows/x64/Lib/unittest/__init__.py \ - build/windows/x64/Lib/unittest/result.py \ - build/windows/x64/Lib/unittest/loader.py \ - build/windows/x64/Lib/unittest/case.py \ - build/windows/x64/Lib/unittest/main.py \ - build/windows/x64/Lib/unittest/__main__.py \ - build/windows/x64/Lib/unittest/mock.py \ - build/windows/x64/Lib/unittest/test/test_result.py \ - build/windows/x64/Lib/unittest/test/support.py \ - build/windows/x64/Lib/unittest/test/test_loader.py \ - build/windows/x64/Lib/unittest/test/test_skipping.py \ - build/windows/x64/Lib/unittest/test/test_setups.py \ - build/windows/x64/Lib/unittest/test/test_functiontestcase.py \ - build/windows/x64/Lib/unittest/test/__init__.py \ - build/windows/x64/Lib/unittest/test/test_break.py \ - build/windows/x64/Lib/unittest/test/test_case.py \ - build/windows/x64/Lib/unittest/test/test_discovery.py \ - build/windows/x64/Lib/unittest/test/test_runner.py \ - build/windows/x64/Lib/unittest/test/test_program.py \ - build/windows/x64/Lib/unittest/test/test_suite.py \ - build/windows/x64/Lib/unittest/test/test_assertions.py \ - build/windows/x64/Lib/unittest/test/_test_warnings.py \ - build/windows/x64/Lib/unittest/test/dummy.py \ - build/windows/x64/Lib/unittest/test/__main__.py \ - build/windows/x64/Lib/unittest/test/testmock/support.py \ - build/windows/x64/Lib/unittest/test/testmock/testcallable.py \ - build/windows/x64/Lib/unittest/test/testmock/__init__.py \ - build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py \ - build/windows/x64/Lib/unittest/test/testmock/testmock.py \ - build/windows/x64/Lib/unittest/test/testmock/testwith.py \ - build/windows/x64/Lib/unittest/test/testmock/testhelpers.py \ - build/windows/x64/Lib/unittest/test/testmock/testpatch.py \ - build/windows/x64/Lib/unittest/test/testmock/testsealable.py \ - build/windows/x64/Lib/unittest/test/testmock/testsentinel.py \ - build/windows/x64/Lib/unittest/test/testmock/__main__.py \ - build/windows/x64/Lib/curses/textpad.py \ - build/windows/x64/Lib/curses/ascii.py \ + build/windows/x64/Lib/ctypes/test/test_wintypes.py \ + build/windows/x64/Lib/ctypes/util.py \ + build/windows/x64/Lib/ctypes/wintypes.py \ build/windows/x64/Lib/curses/__init__.py \ + build/windows/x64/Lib/curses/ascii.py \ build/windows/x64/Lib/curses/has_key.py \ build/windows/x64/Lib/curses/panel.py \ - build/windows/x64/Lib/multiprocessing/semaphore_tracker.py \ - build/windows/x64/Lib/multiprocessing/queues.py \ - build/windows/x64/Lib/multiprocessing/heap.py \ - build/windows/x64/Lib/multiprocessing/reduction.py \ - build/windows/x64/Lib/multiprocessing/util.py \ - build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py \ - build/windows/x64/Lib/multiprocessing/__init__.py \ - build/windows/x64/Lib/multiprocessing/forkserver.py \ - build/windows/x64/Lib/multiprocessing/connection.py \ - build/windows/x64/Lib/multiprocessing/context.py \ - build/windows/x64/Lib/multiprocessing/spawn.py \ - build/windows/x64/Lib/multiprocessing/synchronize.py \ - build/windows/x64/Lib/multiprocessing/process.py \ - build/windows/x64/Lib/multiprocessing/sharedctypes.py \ - build/windows/x64/Lib/multiprocessing/popen_fork.py \ - build/windows/x64/Lib/multiprocessing/pool.py \ - build/windows/x64/Lib/multiprocessing/popen_forkserver.py \ - build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py \ - build/windows/x64/Lib/multiprocessing/managers.py \ - build/windows/x64/Lib/multiprocessing/resource_sharer.py \ - build/windows/x64/Lib/multiprocessing/dummy/__init__.py \ - build/windows/x64/Lib/multiprocessing/dummy/connection.py \ - build/windows/x64/Lib/msilib/sequence.py \ - build/windows/x64/Lib/msilib/__init__.py \ - build/windows/x64/Lib/msilib/text.py \ - build/windows/x64/Lib/msilib/schema.py \ - build/windows/x64/Lib/urllib/error.py \ - build/windows/x64/Lib/urllib/request.py \ - build/windows/x64/Lib/urllib/__init__.py \ - build/windows/x64/Lib/urllib/response.py \ - build/windows/x64/Lib/urllib/robotparser.py \ - build/windows/x64/Lib/urllib/parse.py \ - build/windows/x64/Lib/html/__init__.py \ - build/windows/x64/Lib/html/parser.py \ - build/windows/x64/Lib/html/entities.py \ - build/windows/x64/Lib/xml/__init__.py \ - build/windows/x64/Lib/xml/parsers/expat.py \ - build/windows/x64/Lib/xml/parsers/__init__.py \ - build/windows/x64/Lib/xml/sax/handler.py \ - build/windows/x64/Lib/xml/sax/__init__.py \ - build/windows/x64/Lib/xml/sax/saxutils.py \ - build/windows/x64/Lib/xml/sax/xmlreader.py \ - build/windows/x64/Lib/xml/sax/expatreader.py \ - build/windows/x64/Lib/xml/sax/_exceptions.py \ - build/windows/x64/Lib/xml/dom/pulldom.py \ - build/windows/x64/Lib/xml/dom/expatbuilder.py \ - build/windows/x64/Lib/xml/dom/domreg.py \ - build/windows/x64/Lib/xml/dom/minicompat.py \ - build/windows/x64/Lib/xml/dom/__init__.py \ - build/windows/x64/Lib/xml/dom/NodeFilter.py \ - build/windows/x64/Lib/xml/dom/xmlbuilder.py \ - build/windows/x64/Lib/xml/dom/minidom.py \ - build/windows/x64/Lib/xml/etree/ElementPath.py \ - build/windows/x64/Lib/xml/etree/cElementTree.py \ - build/windows/x64/Lib/xml/etree/__init__.py \ - build/windows/x64/Lib/xml/etree/ElementInclude.py \ - build/windows/x64/Lib/xml/etree/ElementTree.py \ - build/windows/x64/Lib/wsgiref/util.py \ - build/windows/x64/Lib/wsgiref/handlers.py \ - build/windows/x64/Lib/wsgiref/__init__.py \ - build/windows/x64/Lib/wsgiref/validate.py \ - build/windows/x64/Lib/wsgiref/simple_server.py \ - build/windows/x64/Lib/wsgiref/headers.py \ - build/windows/x64/Lib/json/decoder.py \ - build/windows/x64/Lib/json/scanner.py \ - build/windows/x64/Lib/json/__init__.py \ - build/windows/x64/Lib/json/encoder.py \ - build/windows/x64/Lib/json/tool.py \ - build/windows/x64/Lib/http/cookies.py \ - build/windows/x64/Lib/http/server.py \ - build/windows/x64/Lib/http/client.py \ - build/windows/x64/Lib/http/__init__.py \ - build/windows/x64/Lib/http/cookiejar.py \ - build/windows/x64/Lib/sqlite3/__init__.py \ - build/windows/x64/Lib/sqlite3/dump.py \ - build/windows/x64/Lib/sqlite3/dbapi2.py \ - build/windows/x64/Lib/sqlite3/test/backup.py \ - build/windows/x64/Lib/sqlite3/test/hooks.py \ - build/windows/x64/Lib/sqlite3/test/regression.py \ - build/windows/x64/Lib/sqlite3/test/dbapi.py \ - build/windows/x64/Lib/sqlite3/test/transactions.py \ - build/windows/x64/Lib/sqlite3/test/__init__.py \ - build/windows/x64/Lib/sqlite3/test/types.py \ - build/windows/x64/Lib/sqlite3/test/factory.py \ - build/windows/x64/Lib/sqlite3/test/dump.py \ - build/windows/x64/Lib/sqlite3/test/userfunctions.py \ + build/windows/x64/Lib/curses/textpad.py \ + build/windows/x64/Lib/dataclasses.py \ + build/windows/x64/Lib/datetime.py \ + build/windows/x64/Lib/dbm/__init__.py \ + build/windows/x64/Lib/dbm/dumb.py \ + build/windows/x64/Lib/dbm/gnu.py \ + build/windows/x64/Lib/dbm/ndbm.py \ + build/windows/x64/Lib/decimal.py \ + build/windows/x64/Lib/difflib.py \ + build/windows/x64/Lib/dis.py \ + build/windows/x64/Lib/distutils/__init__.py \ + build/windows/x64/Lib/distutils/_msvccompiler.py \ + build/windows/x64/Lib/distutils/archive_util.py \ + build/windows/x64/Lib/distutils/bcppcompiler.py \ + build/windows/x64/Lib/distutils/ccompiler.py \ + build/windows/x64/Lib/distutils/cmd.py \ + build/windows/x64/Lib/distutils/command/__init__.py \ + build/windows/x64/Lib/distutils/command/bdist.py \ + build/windows/x64/Lib/distutils/command/bdist_dumb.py \ + build/windows/x64/Lib/distutils/command/bdist_msi.py \ + build/windows/x64/Lib/distutils/command/bdist_rpm.py \ + build/windows/x64/Lib/distutils/command/bdist_wininst.py \ + build/windows/x64/Lib/distutils/command/build.py \ + build/windows/x64/Lib/distutils/command/build_clib.py \ + build/windows/x64/Lib/distutils/command/build_ext.py \ + build/windows/x64/Lib/distutils/command/build_py.py \ + build/windows/x64/Lib/distutils/command/build_scripts.py \ + build/windows/x64/Lib/distutils/command/check.py \ + build/windows/x64/Lib/distutils/command/clean.py \ + build/windows/x64/Lib/distutils/command/config.py \ + build/windows/x64/Lib/distutils/command/install.py \ + build/windows/x64/Lib/distutils/command/install_data.py \ + build/windows/x64/Lib/distutils/command/install_egg_info.py \ + build/windows/x64/Lib/distutils/command/install_headers.py \ + build/windows/x64/Lib/distutils/command/install_lib.py \ + build/windows/x64/Lib/distutils/command/install_scripts.py \ + build/windows/x64/Lib/distutils/command/register.py \ + build/windows/x64/Lib/distutils/command/sdist.py \ + build/windows/x64/Lib/distutils/command/upload.py \ + build/windows/x64/Lib/distutils/config.py \ + build/windows/x64/Lib/distutils/core.py \ + build/windows/x64/Lib/distutils/cygwinccompiler.py \ + build/windows/x64/Lib/distutils/debug.py \ + build/windows/x64/Lib/distutils/dep_util.py \ + build/windows/x64/Lib/distutils/dir_util.py \ + build/windows/x64/Lib/distutils/dist.py \ + build/windows/x64/Lib/distutils/errors.py \ + build/windows/x64/Lib/distutils/extension.py \ + build/windows/x64/Lib/distutils/fancy_getopt.py \ + build/windows/x64/Lib/distutils/file_util.py \ + build/windows/x64/Lib/distutils/filelist.py \ + build/windows/x64/Lib/distutils/log.py \ + build/windows/x64/Lib/distutils/msvc9compiler.py \ + build/windows/x64/Lib/distutils/msvccompiler.py \ + build/windows/x64/Lib/distutils/spawn.py \ + build/windows/x64/Lib/distutils/sysconfig.py \ + build/windows/x64/Lib/distutils/tests/__init__.py \ + build/windows/x64/Lib/distutils/tests/support.py \ + build/windows/x64/Lib/distutils/tests/test_archive_util.py \ + build/windows/x64/Lib/distutils/tests/test_bdist.py \ + build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py \ + build/windows/x64/Lib/distutils/tests/test_bdist_msi.py \ + build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py \ + build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py \ + build/windows/x64/Lib/distutils/tests/test_build.py \ + build/windows/x64/Lib/distutils/tests/test_build_clib.py \ + build/windows/x64/Lib/distutils/tests/test_build_ext.py \ + build/windows/x64/Lib/distutils/tests/test_build_py.py \ + build/windows/x64/Lib/distutils/tests/test_build_scripts.py \ + build/windows/x64/Lib/distutils/tests/test_check.py \ + build/windows/x64/Lib/distutils/tests/test_clean.py \ + build/windows/x64/Lib/distutils/tests/test_cmd.py \ + build/windows/x64/Lib/distutils/tests/test_config.py \ + build/windows/x64/Lib/distutils/tests/test_config_cmd.py \ + build/windows/x64/Lib/distutils/tests/test_core.py \ + build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py \ + build/windows/x64/Lib/distutils/tests/test_dep_util.py \ + build/windows/x64/Lib/distutils/tests/test_dir_util.py \ + build/windows/x64/Lib/distutils/tests/test_dist.py \ + build/windows/x64/Lib/distutils/tests/test_extension.py \ + build/windows/x64/Lib/distutils/tests/test_file_util.py \ + build/windows/x64/Lib/distutils/tests/test_filelist.py \ + build/windows/x64/Lib/distutils/tests/test_install.py \ + build/windows/x64/Lib/distutils/tests/test_install_data.py \ + build/windows/x64/Lib/distutils/tests/test_install_headers.py \ + build/windows/x64/Lib/distutils/tests/test_install_lib.py \ + build/windows/x64/Lib/distutils/tests/test_install_scripts.py \ + build/windows/x64/Lib/distutils/tests/test_log.py \ + build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py \ + build/windows/x64/Lib/distutils/tests/test_msvccompiler.py \ + build/windows/x64/Lib/distutils/tests/test_register.py \ + build/windows/x64/Lib/distutils/tests/test_sdist.py \ + build/windows/x64/Lib/distutils/tests/test_spawn.py \ + build/windows/x64/Lib/distutils/tests/test_sysconfig.py \ + build/windows/x64/Lib/distutils/tests/test_text_file.py \ + build/windows/x64/Lib/distutils/tests/test_unixccompiler.py \ + build/windows/x64/Lib/distutils/tests/test_upload.py \ + build/windows/x64/Lib/distutils/tests/test_util.py \ + build/windows/x64/Lib/distutils/tests/test_version.py \ + build/windows/x64/Lib/distutils/tests/test_versionpredicate.py \ + build/windows/x64/Lib/distutils/text_file.py \ + build/windows/x64/Lib/distutils/unixccompiler.py \ + build/windows/x64/Lib/distutils/util.py \ + build/windows/x64/Lib/distutils/version.py \ + build/windows/x64/Lib/distutils/versionpredicate.py \ + build/windows/x64/Lib/doctest.py \ + build/windows/x64/Lib/dummy_threading.py \ + build/windows/x64/Lib/email/__init__.py \ + build/windows/x64/Lib/email/_encoded_words.py \ + build/windows/x64/Lib/email/_header_value_parser.py \ + build/windows/x64/Lib/email/_parseaddr.py \ + build/windows/x64/Lib/email/_policybase.py \ + build/windows/x64/Lib/email/base64mime.py \ + build/windows/x64/Lib/email/charset.py \ + build/windows/x64/Lib/email/contentmanager.py \ + build/windows/x64/Lib/email/encoders.py \ + build/windows/x64/Lib/email/errors.py \ + build/windows/x64/Lib/email/feedparser.py \ + build/windows/x64/Lib/email/generator.py \ + build/windows/x64/Lib/email/header.py \ + build/windows/x64/Lib/email/headerregistry.py \ + build/windows/x64/Lib/email/iterators.py \ + build/windows/x64/Lib/email/message.py \ + build/windows/x64/Lib/email/mime/__init__.py \ + build/windows/x64/Lib/email/mime/application.py \ + build/windows/x64/Lib/email/mime/audio.py \ + build/windows/x64/Lib/email/mime/base.py \ + build/windows/x64/Lib/email/mime/image.py \ + build/windows/x64/Lib/email/mime/message.py \ + build/windows/x64/Lib/email/mime/multipart.py \ + build/windows/x64/Lib/email/mime/nonmultipart.py \ + build/windows/x64/Lib/email/mime/text.py \ + build/windows/x64/Lib/email/parser.py \ + build/windows/x64/Lib/email/policy.py \ + build/windows/x64/Lib/email/quoprimime.py \ + build/windows/x64/Lib/email/utils.py \ + build/windows/x64/Lib/encodings/__init__.py \ + build/windows/x64/Lib/encodings/aliases.py \ + build/windows/x64/Lib/encodings/ascii.py \ + build/windows/x64/Lib/encodings/base64_codec.py \ + build/windows/x64/Lib/encodings/big5.py \ + build/windows/x64/Lib/encodings/big5hkscs.py \ + build/windows/x64/Lib/encodings/bz2_codec.py \ + build/windows/x64/Lib/encodings/charmap.py \ + build/windows/x64/Lib/encodings/cp037.py \ + build/windows/x64/Lib/encodings/cp1006.py \ + build/windows/x64/Lib/encodings/cp1026.py \ + build/windows/x64/Lib/encodings/cp1125.py \ + build/windows/x64/Lib/encodings/cp1140.py \ + build/windows/x64/Lib/encodings/cp1250.py \ + build/windows/x64/Lib/encodings/cp1251.py \ + build/windows/x64/Lib/encodings/cp1252.py \ + build/windows/x64/Lib/encodings/cp1253.py \ + build/windows/x64/Lib/encodings/cp1254.py \ + build/windows/x64/Lib/encodings/cp1255.py \ + build/windows/x64/Lib/encodings/cp1256.py \ + build/windows/x64/Lib/encodings/cp1257.py \ + build/windows/x64/Lib/encodings/cp1258.py \ + build/windows/x64/Lib/encodings/cp273.py \ + build/windows/x64/Lib/encodings/cp424.py \ + build/windows/x64/Lib/encodings/cp437.py \ + build/windows/x64/Lib/encodings/cp500.py \ + build/windows/x64/Lib/encodings/cp65001.py \ + build/windows/x64/Lib/encodings/cp720.py \ + build/windows/x64/Lib/encodings/cp737.py \ + build/windows/x64/Lib/encodings/cp775.py \ + build/windows/x64/Lib/encodings/cp850.py \ + build/windows/x64/Lib/encodings/cp852.py \ + build/windows/x64/Lib/encodings/cp855.py \ + build/windows/x64/Lib/encodings/cp856.py \ + build/windows/x64/Lib/encodings/cp857.py \ + build/windows/x64/Lib/encodings/cp858.py \ + build/windows/x64/Lib/encodings/cp860.py \ + build/windows/x64/Lib/encodings/cp861.py \ + build/windows/x64/Lib/encodings/cp862.py \ + build/windows/x64/Lib/encodings/cp863.py \ + build/windows/x64/Lib/encodings/cp864.py \ + build/windows/x64/Lib/encodings/cp865.py \ + build/windows/x64/Lib/encodings/cp866.py \ + build/windows/x64/Lib/encodings/cp869.py \ + build/windows/x64/Lib/encodings/cp874.py \ + build/windows/x64/Lib/encodings/cp875.py \ + build/windows/x64/Lib/encodings/cp932.py \ + build/windows/x64/Lib/encodings/cp949.py \ + build/windows/x64/Lib/encodings/cp950.py \ + build/windows/x64/Lib/encodings/euc_jis_2004.py \ + build/windows/x64/Lib/encodings/euc_jisx0213.py \ + build/windows/x64/Lib/encodings/euc_jp.py \ + build/windows/x64/Lib/encodings/euc_kr.py \ + build/windows/x64/Lib/encodings/gb18030.py \ + build/windows/x64/Lib/encodings/gb2312.py \ + build/windows/x64/Lib/encodings/gbk.py \ + build/windows/x64/Lib/encodings/hex_codec.py \ + build/windows/x64/Lib/encodings/hp_roman8.py \ + build/windows/x64/Lib/encodings/hz.py \ + build/windows/x64/Lib/encodings/idna.py \ + build/windows/x64/Lib/encodings/iso2022_jp.py \ + build/windows/x64/Lib/encodings/iso2022_jp_1.py \ + build/windows/x64/Lib/encodings/iso2022_jp_2.py \ + build/windows/x64/Lib/encodings/iso2022_jp_2004.py \ + build/windows/x64/Lib/encodings/iso2022_jp_3.py \ + build/windows/x64/Lib/encodings/iso2022_jp_ext.py \ + build/windows/x64/Lib/encodings/iso2022_kr.py \ + build/windows/x64/Lib/encodings/iso8859_1.py \ + build/windows/x64/Lib/encodings/iso8859_10.py \ + build/windows/x64/Lib/encodings/iso8859_11.py \ + build/windows/x64/Lib/encodings/iso8859_13.py \ + build/windows/x64/Lib/encodings/iso8859_14.py \ + build/windows/x64/Lib/encodings/iso8859_15.py \ + build/windows/x64/Lib/encodings/iso8859_16.py \ + build/windows/x64/Lib/encodings/iso8859_2.py \ + build/windows/x64/Lib/encodings/iso8859_3.py \ + build/windows/x64/Lib/encodings/iso8859_4.py \ + build/windows/x64/Lib/encodings/iso8859_5.py \ + build/windows/x64/Lib/encodings/iso8859_6.py \ + build/windows/x64/Lib/encodings/iso8859_7.py \ + build/windows/x64/Lib/encodings/iso8859_8.py \ + build/windows/x64/Lib/encodings/iso8859_9.py \ + build/windows/x64/Lib/encodings/johab.py \ + build/windows/x64/Lib/encodings/koi8_r.py \ + build/windows/x64/Lib/encodings/koi8_t.py \ + build/windows/x64/Lib/encodings/koi8_u.py \ + build/windows/x64/Lib/encodings/kz1048.py \ + build/windows/x64/Lib/encodings/latin_1.py \ + build/windows/x64/Lib/encodings/mac_arabic.py \ + build/windows/x64/Lib/encodings/mac_centeuro.py \ + build/windows/x64/Lib/encodings/mac_croatian.py \ + build/windows/x64/Lib/encodings/mac_cyrillic.py \ + build/windows/x64/Lib/encodings/mac_farsi.py \ + build/windows/x64/Lib/encodings/mac_greek.py \ + build/windows/x64/Lib/encodings/mac_iceland.py \ + build/windows/x64/Lib/encodings/mac_latin2.py \ + build/windows/x64/Lib/encodings/mac_roman.py \ + build/windows/x64/Lib/encodings/mac_romanian.py \ + build/windows/x64/Lib/encodings/mac_turkish.py \ + build/windows/x64/Lib/encodings/mbcs.py \ + build/windows/x64/Lib/encodings/oem.py \ + build/windows/x64/Lib/encodings/palmos.py \ + build/windows/x64/Lib/encodings/ptcp154.py \ + build/windows/x64/Lib/encodings/punycode.py \ + build/windows/x64/Lib/encodings/quopri_codec.py \ + build/windows/x64/Lib/encodings/raw_unicode_escape.py \ + build/windows/x64/Lib/encodings/rot_13.py \ + build/windows/x64/Lib/encodings/shift_jis.py \ + build/windows/x64/Lib/encodings/shift_jis_2004.py \ + build/windows/x64/Lib/encodings/shift_jisx0213.py \ + build/windows/x64/Lib/encodings/tis_620.py \ + build/windows/x64/Lib/encodings/undefined.py \ + build/windows/x64/Lib/encodings/unicode_escape.py \ + build/windows/x64/Lib/encodings/unicode_internal.py \ + build/windows/x64/Lib/encodings/utf_16.py \ + build/windows/x64/Lib/encodings/utf_16_be.py \ + build/windows/x64/Lib/encodings/utf_16_le.py \ + build/windows/x64/Lib/encodings/utf_32.py \ + build/windows/x64/Lib/encodings/utf_32_be.py \ + build/windows/x64/Lib/encodings/utf_32_le.py \ + build/windows/x64/Lib/encodings/utf_7.py \ + build/windows/x64/Lib/encodings/utf_8.py \ + build/windows/x64/Lib/encodings/utf_8_sig.py \ + build/windows/x64/Lib/encodings/uu_codec.py \ + build/windows/x64/Lib/encodings/zlib_codec.py \ build/windows/x64/Lib/ensurepip/__init__.py \ build/windows/x64/Lib/ensurepip/__main__.py \ build/windows/x64/Lib/ensurepip/_uninstall.py \ - build/windows/x64/Lib/concurrent/__init__.py \ - build/windows/x64/Lib/concurrent/futures/_base.py \ - build/windows/x64/Lib/concurrent/futures/thread.py \ - build/windows/x64/Lib/concurrent/futures/__init__.py \ - build/windows/x64/Lib/concurrent/futures/process.py \ - build/windows/x64/Lib/venv/__init__.py \ - build/windows/x64/Lib/venv/__main__.py \ - build/windows/x64/Lib/dbm/ndbm.py \ - build/windows/x64/Lib/dbm/gnu.py \ - build/windows/x64/Lib/dbm/__init__.py \ - build/windows/x64/Lib/dbm/dumb.py \ - build/windows/x64/Lib/importlib/util.py \ - build/windows/x64/Lib/importlib/_bootstrap.py \ + build/windows/x64/Lib/enum.py \ + build/windows/x64/Lib/filecmp.py \ + build/windows/x64/Lib/fileinput.py \ + build/windows/x64/Lib/fnmatch.py \ + build/windows/x64/Lib/formatter.py \ + build/windows/x64/Lib/fractions.py \ + build/windows/x64/Lib/ftplib.py \ + build/windows/x64/Lib/functools.py \ + build/windows/x64/Lib/genericpath.py \ + build/windows/x64/Lib/getopt.py \ + build/windows/x64/Lib/getpass.py \ + build/windows/x64/Lib/gettext.py \ + build/windows/x64/Lib/glob.py \ + build/windows/x64/Lib/gzip.py \ + build/windows/x64/Lib/hashlib.py \ + build/windows/x64/Lib/heapq.py \ + build/windows/x64/Lib/hmac.py \ + build/windows/x64/Lib/html/__init__.py \ + build/windows/x64/Lib/html/entities.py \ + build/windows/x64/Lib/html/parser.py \ + build/windows/x64/Lib/http/__init__.py \ + build/windows/x64/Lib/http/client.py \ + build/windows/x64/Lib/http/cookiejar.py \ + build/windows/x64/Lib/http/cookies.py \ + build/windows/x64/Lib/http/server.py \ + build/windows/x64/Lib/imaplib.py \ + build/windows/x64/Lib/imghdr.py \ + build/windows/x64/Lib/imp.py \ build/windows/x64/Lib/importlib/__init__.py \ + build/windows/x64/Lib/importlib/_bootstrap.py \ build/windows/x64/Lib/importlib/_bootstrap_external.py \ - build/windows/x64/Lib/importlib/resources.py \ - build/windows/x64/Lib/importlib/machinery.py \ build/windows/x64/Lib/importlib/abc.py \ - build/windows/x64/Lib/xmlrpc/server.py \ - build/windows/x64/Lib/xmlrpc/client.py \ - build/windows/x64/Lib/xmlrpc/__init__.py \ - build/windows/x64/Lib/pydoc_data/__init__.py \ - build/windows/x64/Lib/pydoc_data/topics.py \ - build/windows/x64/Lib/collections/__init__.py \ - build/windows/x64/Lib/collections/abc.py \ - build/windows/x64/Lib/asyncio/queues.py \ - build/windows/x64/Lib/asyncio/streams.py \ - build/windows/x64/Lib/asyncio/tasks.py \ - build/windows/x64/Lib/asyncio/selector_events.py \ - build/windows/x64/Lib/asyncio/log.py \ - build/windows/x64/Lib/asyncio/protocols.py \ - build/windows/x64/Lib/asyncio/events.py \ - build/windows/x64/Lib/asyncio/base_events.py \ - build/windows/x64/Lib/asyncio/subprocess.py \ - build/windows/x64/Lib/asyncio/constants.py \ - build/windows/x64/Lib/asyncio/proactor_events.py \ - build/windows/x64/Lib/asyncio/format_helpers.py \ - build/windows/x64/Lib/asyncio/locks.py \ - build/windows/x64/Lib/asyncio/__init__.py \ - build/windows/x64/Lib/asyncio/futures.py \ - build/windows/x64/Lib/asyncio/sslproto.py \ - build/windows/x64/Lib/asyncio/base_subprocess.py \ - build/windows/x64/Lib/asyncio/windows_utils.py \ - build/windows/x64/Lib/asyncio/runners.py \ - build/windows/x64/Lib/asyncio/transports.py \ - build/windows/x64/Lib/asyncio/base_tasks.py \ - build/windows/x64/Lib/asyncio/coroutines.py \ - build/windows/x64/Lib/asyncio/windows_events.py \ - build/windows/x64/Lib/asyncio/base_futures.py \ - build/windows/x64/Lib/asyncio/unix_events.py \ + build/windows/x64/Lib/importlib/machinery.py \ + build/windows/x64/Lib/importlib/resources.py \ + build/windows/x64/Lib/importlib/util.py \ + build/windows/x64/Lib/inspect.py \ + build/windows/x64/Lib/io.py \ + build/windows/x64/Lib/ipaddress.py \ + build/windows/x64/Lib/json/__init__.py \ + build/windows/x64/Lib/json/decoder.py \ + build/windows/x64/Lib/json/encoder.py \ + build/windows/x64/Lib/json/scanner.py \ + build/windows/x64/Lib/json/tool.py \ + build/windows/x64/Lib/keyword.py \ + build/windows/x64/Lib/linecache.py \ + build/windows/x64/Lib/locale.py \ + build/windows/x64/Lib/logging/__init__.py \ build/windows/x64/Lib/logging/config.py \ build/windows/x64/Lib/logging/handlers.py \ - build/windows/x64/Lib/logging/__init__.py \ - build/windows/x64/Lib/email/contentmanager.py \ - build/windows/x64/Lib/email/_policybase.py \ - build/windows/x64/Lib/email/header.py \ - build/windows/x64/Lib/email/_encoded_words.py \ - build/windows/x64/Lib/email/_header_value_parser.py \ - build/windows/x64/Lib/email/policy.py \ - build/windows/x64/Lib/email/__init__.py \ - build/windows/x64/Lib/email/message.py \ - build/windows/x64/Lib/email/encoders.py \ - build/windows/x64/Lib/email/parser.py \ - build/windows/x64/Lib/email/generator.py \ - build/windows/x64/Lib/email/utils.py \ - build/windows/x64/Lib/email/charset.py \ - build/windows/x64/Lib/email/iterators.py \ - build/windows/x64/Lib/email/quoprimime.py \ - build/windows/x64/Lib/email/errors.py \ - build/windows/x64/Lib/email/feedparser.py \ - build/windows/x64/Lib/email/_parseaddr.py \ - build/windows/x64/Lib/email/base64mime.py \ - build/windows/x64/Lib/email/headerregistry.py \ - build/windows/x64/Lib/email/mime/multipart.py \ - build/windows/x64/Lib/email/mime/__init__.py \ - build/windows/x64/Lib/email/mime/message.py \ - build/windows/x64/Lib/email/mime/application.py \ - build/windows/x64/Lib/email/mime/nonmultipart.py \ - build/windows/x64/Lib/email/mime/text.py \ - build/windows/x64/Lib/email/mime/audio.py \ - build/windows/x64/Lib/email/mime/image.py \ - build/windows/x64/Lib/email/mime/base.py + build/windows/x64/Lib/lzma.py \ + build/windows/x64/Lib/macpath.py \ + build/windows/x64/Lib/mailbox.py \ + build/windows/x64/Lib/mailcap.py \ + build/windows/x64/Lib/mimetypes.py \ + build/windows/x64/Lib/modulefinder.py \ + build/windows/x64/Lib/msilib/__init__.py \ + build/windows/x64/Lib/msilib/schema.py \ + build/windows/x64/Lib/msilib/sequence.py \ + build/windows/x64/Lib/msilib/text.py \ + build/windows/x64/Lib/multiprocessing/__init__.py \ + build/windows/x64/Lib/multiprocessing/connection.py \ + build/windows/x64/Lib/multiprocessing/context.py \ + build/windows/x64/Lib/multiprocessing/dummy/__init__.py \ + build/windows/x64/Lib/multiprocessing/dummy/connection.py \ + build/windows/x64/Lib/multiprocessing/forkserver.py \ + build/windows/x64/Lib/multiprocessing/heap.py \ + build/windows/x64/Lib/multiprocessing/managers.py \ + build/windows/x64/Lib/multiprocessing/pool.py \ + build/windows/x64/Lib/multiprocessing/popen_fork.py \ + build/windows/x64/Lib/multiprocessing/popen_forkserver.py \ + build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py \ + build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py \ + build/windows/x64/Lib/multiprocessing/process.py \ + build/windows/x64/Lib/multiprocessing/queues.py \ + build/windows/x64/Lib/multiprocessing/reduction.py \ + build/windows/x64/Lib/multiprocessing/resource_sharer.py \ + build/windows/x64/Lib/multiprocessing/semaphore_tracker.py \ + build/windows/x64/Lib/multiprocessing/sharedctypes.py \ + build/windows/x64/Lib/multiprocessing/spawn.py \ + build/windows/x64/Lib/multiprocessing/synchronize.py \ + build/windows/x64/Lib/multiprocessing/util.py \ + build/windows/x64/Lib/netrc.py \ + build/windows/x64/Lib/nntplib.py \ + build/windows/x64/Lib/ntpath.py \ + build/windows/x64/Lib/nturl2path.py \ + build/windows/x64/Lib/numbers.py \ + build/windows/x64/Lib/opcode.py \ + build/windows/x64/Lib/operator.py \ + build/windows/x64/Lib/optparse.py \ + build/windows/x64/Lib/os.py \ + build/windows/x64/Lib/pathlib.py \ + build/windows/x64/Lib/pdb.py \ + build/windows/x64/Lib/pickle.py \ + build/windows/x64/Lib/pickletools.py \ + build/windows/x64/Lib/pipes.py \ + build/windows/x64/Lib/pkgutil.py \ + build/windows/x64/Lib/platform.py \ + build/windows/x64/Lib/plistlib.py \ + build/windows/x64/Lib/poplib.py \ + build/windows/x64/Lib/posixpath.py \ + build/windows/x64/Lib/pprint.py \ + build/windows/x64/Lib/profile.py \ + build/windows/x64/Lib/pstats.py \ + build/windows/x64/Lib/pty.py \ + build/windows/x64/Lib/py_compile.py \ + build/windows/x64/Lib/pyclbr.py \ + build/windows/x64/Lib/pydoc.py \ + build/windows/x64/Lib/pydoc_data/__init__.py \ + build/windows/x64/Lib/pydoc_data/topics.py \ + build/windows/x64/Lib/queue.py \ + build/windows/x64/Lib/quopri.py \ + build/windows/x64/Lib/random.py \ + build/windows/x64/Lib/re.py \ + build/windows/x64/Lib/reprlib.py \ + build/windows/x64/Lib/rlcompleter.py \ + build/windows/x64/Lib/runpy.py \ + build/windows/x64/Lib/sched.py \ + build/windows/x64/Lib/secrets.py \ + build/windows/x64/Lib/selectors.py \ + build/windows/x64/Lib/shelve.py \ + build/windows/x64/Lib/shlex.py \ + build/windows/x64/Lib/shutil.py \ + build/windows/x64/Lib/signal.py \ + build/windows/x64/Lib/site.py \ + build/windows/x64/Lib/smtpd.py \ + build/windows/x64/Lib/smtplib.py \ + build/windows/x64/Lib/sndhdr.py \ + build/windows/x64/Lib/socket.py \ + build/windows/x64/Lib/socketserver.py \ + build/windows/x64/Lib/sqlite3/__init__.py \ + build/windows/x64/Lib/sqlite3/dbapi2.py \ + build/windows/x64/Lib/sqlite3/dump.py \ + build/windows/x64/Lib/sqlite3/test/__init__.py \ + build/windows/x64/Lib/sqlite3/test/backup.py \ + build/windows/x64/Lib/sqlite3/test/dbapi.py \ + build/windows/x64/Lib/sqlite3/test/dump.py \ + build/windows/x64/Lib/sqlite3/test/factory.py \ + build/windows/x64/Lib/sqlite3/test/hooks.py \ + build/windows/x64/Lib/sqlite3/test/regression.py \ + build/windows/x64/Lib/sqlite3/test/transactions.py \ + build/windows/x64/Lib/sqlite3/test/types.py \ + build/windows/x64/Lib/sqlite3/test/userfunctions.py \ + build/windows/x64/Lib/sre_compile.py \ + build/windows/x64/Lib/sre_constants.py \ + build/windows/x64/Lib/sre_parse.py \ + build/windows/x64/Lib/ssl.py \ + build/windows/x64/Lib/stat.py \ + build/windows/x64/Lib/statistics.py \ + build/windows/x64/Lib/string.py \ + build/windows/x64/Lib/stringprep.py \ + build/windows/x64/Lib/struct.py \ + build/windows/x64/Lib/subprocess.py \ + build/windows/x64/Lib/sunau.py \ + build/windows/x64/Lib/symbol.py \ + build/windows/x64/Lib/symtable.py \ + build/windows/x64/Lib/sysconfig.py \ + build/windows/x64/Lib/tabnanny.py \ + build/windows/x64/Lib/tarfile.py \ + build/windows/x64/Lib/telnetlib.py \ + build/windows/x64/Lib/tempfile.py \ + build/windows/x64/Lib/textwrap.py \ + build/windows/x64/Lib/this.py \ + build/windows/x64/Lib/threading.py \ + build/windows/x64/Lib/timeit.py \ + build/windows/x64/Lib/token.py \ + build/windows/x64/Lib/tokenize.py \ + build/windows/x64/Lib/trace.py \ + build/windows/x64/Lib/traceback.py \ + build/windows/x64/Lib/tracemalloc.py \ + build/windows/x64/Lib/tty.py \ + build/windows/x64/Lib/turtle.py \ + build/windows/x64/Lib/types.py \ + build/windows/x64/Lib/typing.py \ + build/windows/x64/Lib/unittest/__init__.py \ + build/windows/x64/Lib/unittest/__main__.py \ + build/windows/x64/Lib/unittest/case.py \ + build/windows/x64/Lib/unittest/loader.py \ + build/windows/x64/Lib/unittest/main.py \ + build/windows/x64/Lib/unittest/mock.py \ + build/windows/x64/Lib/unittest/result.py \ + build/windows/x64/Lib/unittest/runner.py \ + build/windows/x64/Lib/unittest/signals.py \ + build/windows/x64/Lib/unittest/suite.py \ + build/windows/x64/Lib/unittest/test/__init__.py \ + build/windows/x64/Lib/unittest/test/__main__.py \ + build/windows/x64/Lib/unittest/test/_test_warnings.py \ + build/windows/x64/Lib/unittest/test/dummy.py \ + build/windows/x64/Lib/unittest/test/support.py \ + build/windows/x64/Lib/unittest/test/test_assertions.py \ + build/windows/x64/Lib/unittest/test/test_break.py \ + build/windows/x64/Lib/unittest/test/test_case.py \ + build/windows/x64/Lib/unittest/test/test_discovery.py \ + build/windows/x64/Lib/unittest/test/test_functiontestcase.py \ + build/windows/x64/Lib/unittest/test/test_loader.py \ + build/windows/x64/Lib/unittest/test/test_program.py \ + build/windows/x64/Lib/unittest/test/test_result.py \ + build/windows/x64/Lib/unittest/test/test_runner.py \ + build/windows/x64/Lib/unittest/test/test_setups.py \ + build/windows/x64/Lib/unittest/test/test_skipping.py \ + build/windows/x64/Lib/unittest/test/test_suite.py \ + build/windows/x64/Lib/unittest/test/testmock/__init__.py \ + build/windows/x64/Lib/unittest/test/testmock/__main__.py \ + build/windows/x64/Lib/unittest/test/testmock/support.py \ + build/windows/x64/Lib/unittest/test/testmock/testcallable.py \ + build/windows/x64/Lib/unittest/test/testmock/testhelpers.py \ + build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py \ + build/windows/x64/Lib/unittest/test/testmock/testmock.py \ + build/windows/x64/Lib/unittest/test/testmock/testpatch.py \ + build/windows/x64/Lib/unittest/test/testmock/testsealable.py \ + build/windows/x64/Lib/unittest/test/testmock/testsentinel.py \ + build/windows/x64/Lib/unittest/test/testmock/testwith.py \ + build/windows/x64/Lib/unittest/util.py \ + build/windows/x64/Lib/urllib/__init__.py \ + build/windows/x64/Lib/urllib/error.py \ + build/windows/x64/Lib/urllib/parse.py \ + build/windows/x64/Lib/urllib/request.py \ + build/windows/x64/Lib/urllib/response.py \ + build/windows/x64/Lib/urllib/robotparser.py \ + build/windows/x64/Lib/uu.py \ + build/windows/x64/Lib/uuid.py \ + build/windows/x64/Lib/venv/__init__.py \ + build/windows/x64/Lib/venv/__main__.py \ + build/windows/x64/Lib/warnings.py \ + build/windows/x64/Lib/wave.py \ + build/windows/x64/Lib/weakref.py \ + build/windows/x64/Lib/webbrowser.py \ + build/windows/x64/Lib/wsgiref/__init__.py \ + build/windows/x64/Lib/wsgiref/handlers.py \ + build/windows/x64/Lib/wsgiref/headers.py \ + build/windows/x64/Lib/wsgiref/simple_server.py \ + build/windows/x64/Lib/wsgiref/util.py \ + build/windows/x64/Lib/wsgiref/validate.py \ + build/windows/x64/Lib/xdrlib.py \ + build/windows/x64/Lib/xml/__init__.py \ + build/windows/x64/Lib/xml/dom/NodeFilter.py \ + build/windows/x64/Lib/xml/dom/__init__.py \ + build/windows/x64/Lib/xml/dom/domreg.py \ + build/windows/x64/Lib/xml/dom/expatbuilder.py \ + build/windows/x64/Lib/xml/dom/minicompat.py \ + build/windows/x64/Lib/xml/dom/minidom.py \ + build/windows/x64/Lib/xml/dom/pulldom.py \ + build/windows/x64/Lib/xml/dom/xmlbuilder.py \ + build/windows/x64/Lib/xml/etree/ElementInclude.py \ + build/windows/x64/Lib/xml/etree/ElementPath.py \ + build/windows/x64/Lib/xml/etree/ElementTree.py \ + build/windows/x64/Lib/xml/etree/__init__.py \ + build/windows/x64/Lib/xml/etree/cElementTree.py \ + build/windows/x64/Lib/xml/parsers/__init__.py \ + build/windows/x64/Lib/xml/parsers/expat.py \ + build/windows/x64/Lib/xml/sax/__init__.py \ + build/windows/x64/Lib/xml/sax/_exceptions.py \ + build/windows/x64/Lib/xml/sax/expatreader.py \ + build/windows/x64/Lib/xml/sax/handler.py \ + build/windows/x64/Lib/xml/sax/saxutils.py \ + build/windows/x64/Lib/xml/sax/xmlreader.py \ + build/windows/x64/Lib/xmlrpc/__init__.py \ + build/windows/x64/Lib/xmlrpc/client.py \ + build/windows/x64/Lib/xmlrpc/server.py \ + build/windows/x64/Lib/zipapp.py \ + build/windows/x64/Lib/zipfile.py SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ - build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc \ build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc + build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -14073,58 +14073,8 @@ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_X64) : ../.efrocachemap # just generating explicit targets for each. Could perhaps look into using a # fancy for-loop instead, but perhaps listing these explicitly isn't so bad. -build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/queue.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncore.py +build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/__future__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -14133,623 +14083,8 @@ build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/trace.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/token.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/base64.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/signal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wave.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/functools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/profile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/this.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/uu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/io.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/code.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/operator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/os.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/copy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/types.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/random.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/threading.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/turtle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/platform.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/glob.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/site.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/stat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/csv.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sched.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/imaplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/locale.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ast.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pty.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/statistics.py +build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_bootlocale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -14758,98 +14093,33 @@ build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sunau.py +build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_compat_pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/__future__.py +build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_compression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dataclasses.py +build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_dummy_thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/shelve.py +build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_markupbase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/string.py +build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_osx_support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/enum.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/typing.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/socket.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pathlib.py +build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_py_abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -14858,58 +14128,28 @@ build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ntpath.py +build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_pyio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tokenize.py +build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_sitebuiltins.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/uuid.py +build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_strptime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/imp.py +build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_threading_local.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/re.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/struct.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sre_parse.py +build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/_weakrefset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -14918,5116 +14158,5876 @@ build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/aifc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/antigravity.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/argparse.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ast.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asynchat.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/base_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/base_futures.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/base_subprocess.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/base_tasks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/constants.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/coroutines.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/format_helpers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/futures.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/locks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/log.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/proactor_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/protocols.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/queues.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/runners.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/selector_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/sslproto.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/streams.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/subprocess.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/tasks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/transports.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/unix_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/windows_events.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncio/windows_utils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/asyncore.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/base64.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/bdb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/binhex.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/bisect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/bz2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/cProfile.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/calendar.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/cgi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/cgitb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/chunk.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/cmd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/code.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/codecs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/codeop.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/collections/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/collections/abc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/colorsys.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/compileall.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/concurrent/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/concurrent/futures/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/concurrent/futures/_base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/concurrent/futures/process.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/concurrent/futures/thread.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/configparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/contextlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/contextvars.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/copy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/copyreg.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/crypt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/csv.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/_aix.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/_endian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/macholib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/macholib/dyld.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/macholib/dylib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/macholib/framework.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/__main__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_anon.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_arrays.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_as_parameter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_bitfields.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_buffers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_bytes.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_byteswap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_callbacks.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_cast.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_cfuncs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_checkretval.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_delattr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_errno.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_find.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_frombuffer.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_funcptr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_functions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_incomplete.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_init.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_internals.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_keeprefs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_libc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_loading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_macholib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_memfunctions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_numbers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_objects.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_parameters.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_pep3118.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/runpy.py + build/windows/x64/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_bootlocale.py +build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_romanian.py +build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_farsi.py +build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/idna.py +build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp273.py +build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/punycode.py +build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/raw_unicode_escape.py +build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_8.py +build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1252.py +build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp869.py +build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_14.py +build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_2.py +build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_arabic.py +build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_croatian.py +build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/big5hkscs.py +build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1256.py +build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_6.py +build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_values.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_10.py +build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_kr.py +build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1140.py +build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/unicode_internal.py +build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1125.py +build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ctypes/wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_1.py +build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1257.py +build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/curses/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp949.py +build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp858.py +build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_7.py +build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_11.py +build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/hp_roman8.py +build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/koi8_r.py +build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dbm/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/zlib_codec.py +build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dbm/dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/gbk.py +build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dbm/gnu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/johab.py +build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dbm/ndbm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1253.py +build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_15.py +build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_2004.py +build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_iceland.py +build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_3.py +build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_greek.py +build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/archive_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/rot_13.py +build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_16_be.py +build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/ccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_kr.py +build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_centeuro.py +build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_jisx0213.py +build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/bdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp863.py +build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/ascii.py +build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_8.py +build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp857.py +build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_32_be.py +build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/build.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1258.py +build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/build_clib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/oem.py +build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/build_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_latin2.py +build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/build_py.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp775.py +build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_roman.py +build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/check.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/clean.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/install.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/install_data.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/install_egg_info.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/install_headers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/install_lib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/install_scripts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/register.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/sdist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/command/upload.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/core.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/cygwinccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/debug.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/dep_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/dir_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/dist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/errors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/extension.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/fancy_getopt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/file_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/filelist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/log.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/msvc9compiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/msvccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/spawn.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/sysconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/support.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_archive_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_bdist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_bdist_msi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_build.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_build_clib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_build_ext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_build_py.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_build_scripts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_check.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_clean.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_cmd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_config_cmd.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_core.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_dep_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_dir_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_dist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_extension.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_file_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_filelist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_install.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_install_data.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_install_headers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_install_lib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_install_scripts.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_log.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_msvccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_register.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_sdist.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_spawn.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_sysconfig.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_text_file.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_unixccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_upload.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_version.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/tests/test_versionpredicate.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/text_file.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/unixccompiler.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/version.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/distutils/versionpredicate.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/doctest.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/dummy_threading.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/_encoded_words.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/_header_value_parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/_parseaddr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/_policybase.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/base64mime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/charset.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/contentmanager.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/encoders.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/errors.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/feedparser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/generator.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/header.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/headerregistry.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/iterators.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/application.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/audio.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/base.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/image.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/message.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/multipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/nonmultipart.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/mime/text.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/policy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/quoprimime.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/email/utils.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/aliases.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/ascii.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/base64_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/big5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/big5hkscs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/bz2_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/charmap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp037.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1006.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1026.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1125.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1140.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1250.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1251.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1252.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1253.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1254.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1255.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1256.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1257.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp1258.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp273.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp424.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp437.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp500.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp65001.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp720.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp737.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp775.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp850.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp852.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/shift_jisx0213.py +build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp855.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp856.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp857.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp858.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp860.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp861.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp862.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp863.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp864.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp865.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp866.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp869.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp874.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp875.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp932.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp949.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/cp950.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/euc_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/euc_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/euc_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/euc_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/gb18030.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/gb2312.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/gbk.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/hex_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/hp_roman8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/hz.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/idna.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_jp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_jp_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_jp_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_jp_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_jp_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_jp_ext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso2022_kr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_10.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_11.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_14.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_15.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_3.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_4.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_5.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_6.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_7.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_8.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/iso8859_9.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/johab.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/koi8_r.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/koi8_t.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/koi8_u.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/kz1048.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/latin_1.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_arabic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_centeuro.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_croatian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_cyrillic.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_farsi.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_greek.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_iceland.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_latin2.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_roman.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_romanian.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mac_turkish.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/mbcs.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/oem.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/palmos.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/ptcp154.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/punycode.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/quopri_codec.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/raw_unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/rot_13.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/shift_jis.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/shift_jis_2004.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/shift_jisx0213.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/tis_620.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/undefined.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/unicode_escape.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/unicode_internal.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/utf_16.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/utf_16_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/utf_16_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/utf_32.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/utf_32_be.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/utf_32_le.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/base64_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/ptcp154.py + build/windows/x64/Lib/encodings/utf_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/koi8_t.py +build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/uu_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1026.py +build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/encodings/zlib_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/charmap.py + build/windows/x64/Lib/ensurepip/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_5.py +build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ensurepip/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_13.py +build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ensurepip/_uninstall.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/enum.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/filecmp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/fileinput.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/fnmatch.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/formatter.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/fractions.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ftplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/functools.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/genericpath.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/getopt.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/getpass.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/gettext.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/glob.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/gzip.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/hashlib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/heapq.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/hmac.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/html/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/html/entities.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/html/parser.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/http/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/http/client.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/http/cookiejar.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/http/cookies.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/http/server.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/imaplib.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/imghdr.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/imp.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/_bootstrap.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/_bootstrap_external.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/abc.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/machinery.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/resources.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/importlib/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/inspect.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/io.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ipaddress.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/json/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/json/decoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/json/encoder.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/json/scanner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/json/tool.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/keyword.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/linecache.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/locale.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/logging/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/logging/config.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/logging/handlers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/lzma.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp.py + build/windows/x64/Lib/macpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/_msvccompiler.py +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/mailbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/unixccompiler.py +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/mailcap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/filelist.py +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/mimetypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/ccompiler.py +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/modulefinder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/msvc9compiler.py +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/msilib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/archive_util.py +build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/msilib/schema.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/cmd.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/msilib/sequence.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/config.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/msilib/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/version.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/log.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/util.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/context.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/fancy_getopt.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/versionpredicate.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/__init__.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/file_util.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/heap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/core.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/managers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/cygwinccompiler.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/pool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/extension.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/debug.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/spawn.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/text_file.py +build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/msvccompiler.py +build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/errors.py +build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/dep_util.py +build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/reduction.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/dir_util.py +build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/sysconfig.py +build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/dist.py +build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/bcppcompiler.py +build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist.py +build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_text_file.py +build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/multiprocessing/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py +build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/netrc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_version.py +build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/nntplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_lib.py +build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ntpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_py.py +build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/nturl2path.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_extension.py +build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_spawn.py +build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/opcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/support.py +build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/operator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py +build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/optparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_data.py +build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/os.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py +build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pathlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py +build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_unixccompiler.py +build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_filelist.py +build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pickletools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_core.py +build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pipes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_msi.py +build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pkgutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_cmd.py +build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/platform.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/__init__.py +build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/plistlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_msvccompiler.py +build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/poplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_sysconfig.py +build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/posixpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_util.py +build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pprint.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_clib.py +build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/profile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_register.py +build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pstats.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_log.py +build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_dep_util.py +build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/py_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build.py +build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pyclbr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_scripts.py +build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pydoc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_ext.py +build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pydoc_data/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_dir_util.py +build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/pydoc_data/topics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_headers.py +build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/queue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_clean.py +build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/quopri.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_check.py +build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/random.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_config.py +build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/re.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_versionpredicate.py +build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/reprlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_upload.py +build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/rlcompleter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_scripts.py +build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/runpy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py +build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sched.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_file_util.py +build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/secrets.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_dist.py +build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/selectors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install.py +build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/shelve.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_config_cmd.py +build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/shlex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_sdist.py +build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/shutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_archive_util.py +build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/signal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build.py +build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/site.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_ext.py +build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/smtpd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/config.py +build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/smtplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/clean.py +build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sndhdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/check.py +build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/socket.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_scripts.py +build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/socketserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/upload.py +build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/register.py +build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_wininst.py +build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_headers.py +build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_lib.py +build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/backup.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_py.py +build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_dumb.py +build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/__init__.py +build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/factory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/sdist.py +build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist.py +build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/regression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_scripts.py +build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_rpm.py +build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_clib.py +build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install.py +build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sre_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_msi.py +build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sre_constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_egg_info.py +build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sre_parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_data.py +build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/ssl.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/_aix.py +build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/stat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/wintypes.py +build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/statistics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/util.py +build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/string.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/__init__.py +build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/stringprep.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/_endian.py +build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py +build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_random_things.py +build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sunau.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_funcptr.py +build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/symbol.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_callbacks.py +build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/symtable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_unicode.py +build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_structures.py +build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/tabnanny.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_cast.py +build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/tarfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py +build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/telnetlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_keeprefs.py +build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/tempfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_loading.py +build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/textwrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_memfunctions.py +build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/this.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_slicing.py +build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_numbers.py +build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/timeit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_libc.py +build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/token.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_python_api.py +build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/tokenize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_bytes.py +build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/trace.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_pep3118.py +build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/traceback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/__init__.py +build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/tracemalloc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_frombuffer.py +build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/tty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_parameters.py +build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/turtle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_wintypes.py +build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_pointers.py +build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/typing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_errno.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_arrays.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_cfuncs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_find.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_refcounts.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_internals.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_prototypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_values.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_varsize_struct.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_stringptr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_as_parameter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_pickling.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_bitfields.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_byteswap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_functions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_repr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_macholib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_incomplete.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_strings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_struct_fields.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_buffers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_anon.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_init.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_checkretval.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_delattr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_objects.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_sizes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_win32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/dylib.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/signals.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/runner.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/suite.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/result.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/loader.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/case.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/main.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/case.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/loader.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/main.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/mock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_result.py +build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/runner.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/signals.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/suite.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/__init__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/__main__.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/_test_warnings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/dummy.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_loader.py +build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_skipping.py +build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_break.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_setups.py +build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_case.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_discovery.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_break.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_case.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_discovery.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_runner.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_program.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_suite.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_assertions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/_test_warnings.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/dummy.py + build/windows/x64/Lib/unittest/test/test_loader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/__main__.py + build/windows/x64/Lib/unittest/test/test_program.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/support.py +build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testcallable.py +build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_runner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_setups.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_skipping.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/test_suite.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testmock.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testwith.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testhelpers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testpatch.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testsealable.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testsentinel.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/textpad.py +build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/ascii.py +build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/__init__.py +build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/has_key.py +build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/panel.py +build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/semaphore_tracker.py +build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/queues.py +build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/heap.py +build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/reduction.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/util.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/unittest/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/connection.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/context.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/spawn.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/synchronize.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/process.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/sharedctypes.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_fork.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/pool.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/managers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/resource_sharer.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/dummy/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/dummy/connection.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/sequence.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/schema.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/error.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/request.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/response.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/urllib/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/robotparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/html/__init__.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/urllib/request.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/html/parser.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/urllib/response.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/html/entities.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/urllib/robotparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/__init__.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/uu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/parsers/expat.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/uuid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/parsers/__init__.py +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/venv/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/handler.py +build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/venv/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/__init__.py +build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/saxutils.py +build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/wave.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/xmlreader.py +build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/weakref.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/expatreader.py +build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/webbrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/NodeFilter.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/xmlbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/minidom.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/ElementPath.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/cElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/ElementInclude.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/ElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/wsgiref/handlers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/wsgiref/headers.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/wsgiref/simple_server.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/wsgiref/util.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + +build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/validate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/simple_server.py + build/windows/x64/Lib/xdrlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/headers.py +build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/decoder.py +build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/scanner.py +build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/__init__.py +build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/encoder.py +build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/tool.py +build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/minicompat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/cookies.py +build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/server.py +build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/pulldom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/client.py +build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/__init__.py +build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/cookiejar.py +build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/__init__.py +build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/dump.py +build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/etree/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/dbapi2.py +build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/backup.py +build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/hooks.py +build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/regression.py +build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/dbapi.py +build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/transactions.py +build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/__init__.py +build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/types.py +build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/factory.py +build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/dump.py +build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/userfunctions.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ensurepip/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ensurepip/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ensurepip/_uninstall.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/venv/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/venv/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/ndbm.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/gnu.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/dumb.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xmlrpc/__init__.py + build/windows/x64/Lib/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pydoc_data/__init__.py +build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pydoc_data/topics.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/collections/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/base.py +build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ + build/windows/x64/Lib/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ COB_TARGETS = \ - build/ba_data/models/zigZagLevelBumper.cob \ - build/ba_data/models/rampageBumper.cob \ - build/ba_data/models/bigGBumper.cob \ - build/ba_data/models/roundaboutLevelCollide.cob \ - build/ba_data/models/cragCastleLevelBumper.cob \ - build/ba_data/models/lakeFrigidCollide.cob \ - build/ba_data/models/stepRightUpLevelCollide.cob \ - build/ba_data/models/courtyardPlayerWall.cob \ - build/ba_data/models/rampageLevelCollide.cob \ - build/ba_data/models/monkeyFaceLevelCollide.cob \ - build/ba_data/models/courtyardLevelCollide.cob \ - build/ba_data/models/hockeyStadiumCollide.cob \ - build/ba_data/models/towerDLevelCollide.cob \ - build/ba_data/models/tipTopLevelCollide.cob \ - build/ba_data/models/monkeyFaceLevelBumper.cob \ - build/ba_data/models/zigZagLevelCollide.cob \ - build/ba_data/models/bridgitLevelRailingCollide.cob \ - build/ba_data/models/thePadLevelBumper.cob \ - build/ba_data/models/natureBackgroundCollide.cob \ - build/ba_data/models/doomShroomLevelCollide.cob \ - build/ba_data/models/footballStadiumCollide.cob \ - build/ba_data/models/doomShroomStemCollide.cob \ - build/ba_data/models/bridgitLevelCollide.cob \ build/ba_data/models/alwaysLandLevelCollide.cob \ + build/ba_data/models/bigGBumper.cob \ + build/ba_data/models/bigGCollide.cob \ + build/ba_data/models/bridgitLevelCollide.cob \ + build/ba_data/models/bridgitLevelRailingCollide.cob \ + build/ba_data/models/courtyardLevelCollide.cob \ + build/ba_data/models/courtyardPlayerWall.cob \ + build/ba_data/models/cragCastleLevelBumper.cob \ build/ba_data/models/cragCastleLevelCollide.cob \ + build/ba_data/models/doomShroomLevelCollide.cob \ + build/ba_data/models/doomShroomStemCollide.cob \ + build/ba_data/models/footballStadiumCollide.cob \ + build/ba_data/models/hockeyStadiumCollide.cob \ + build/ba_data/models/lakeFrigidCollide.cob \ + build/ba_data/models/monkeyFaceLevelBumper.cob \ + build/ba_data/models/monkeyFaceLevelCollide.cob \ + build/ba_data/models/natureBackgroundCollide.cob \ + build/ba_data/models/rampageBumper.cob \ + build/ba_data/models/rampageLevelCollide.cob \ build/ba_data/models/roundaboutLevelBumper.cob \ - build/ba_data/models/towerDPlayerWall.cob \ - build/ba_data/models/tipTopLevelBumper.cob \ + build/ba_data/models/roundaboutLevelCollide.cob \ + build/ba_data/models/stepRightUpLevelCollide.cob \ + build/ba_data/models/thePadLevelBumper.cob \ build/ba_data/models/thePadLevelCollide.cob \ - build/ba_data/models/bigGCollide.cob + build/ba_data/models/tipTopLevelBumper.cob \ + build/ba_data/models/tipTopLevelCollide.cob \ + build/ba_data/models/towerDLevelCollide.cob \ + build/ba_data/models/towerDPlayerWall.cob \ + build/ba_data/models/zigZagLevelBumper.cob \ + build/ba_data/models/zigZagLevelCollide.cob BOB_TARGETS = \ - build/ba_data/models/wrestlerToes.bob \ - build/ba_data/models/melTorso.bob \ - build/ba_data/models/gladiatorHead.bob \ - build/ba_data/models/image16x1.bob \ - build/ba_data/models/actionButtonBottom.bob \ - build/ba_data/models/santaUpperLeg.bob \ - build/ba_data/models/thePadBGSmall.bob \ - build/ba_data/models/cowboyForeArm.bob \ - build/ba_data/models/image1x1.bob \ - build/ba_data/models/trees.bob \ - build/ba_data/models/plasticEyesTransparent.bob \ - build/ba_data/models/currencyPlusButton.bob \ - build/ba_data/models/scrollBarThumbOpaque.bob \ - build/ba_data/models/cyborgUpperArm.bob \ - build/ba_data/models/jumpsuitTorso.bob \ - build/ba_data/models/jumpsuitToes.bob \ - build/ba_data/models/natureBackground.bob \ - build/ba_data/models/operaSingerPelvis.bob \ - build/ba_data/models/oldLadyUpperArm.bob \ - build/ba_data/models/hairTuft1.bob \ - build/ba_data/models/neoSpazUpperLeg.bob \ - build/ba_data/models/overlayGuide.bob \ - build/ba_data/models/gladiatorUpperLeg.bob \ - build/ba_data/models/alienTorso.bob \ - build/ba_data/models/zoeTorso.bob \ - build/ba_data/models/operaSingerForeArm.bob \ - build/ba_data/models/buttonTabOpaque.bob \ - build/ba_data/models/wizardToes.bob \ - build/ba_data/models/witchTorso.bob \ - build/ba_data/models/shrapnelBoard.bob \ - build/ba_data/models/puck.bob \ - build/ba_data/models/jumpsuitLowerLeg.bob \ - build/ba_data/models/zoeHand.bob \ - build/ba_data/models/witchLowerLeg.bob \ build/ba_data/models/achievementOutline.bob \ - build/ba_data/models/bonesToes.bob \ - build/ba_data/models/bearToes.bob \ - build/ba_data/models/buttonBackOpaque.bob \ - build/ba_data/models/vrOverlay.bob \ - build/ba_data/models/playerLineup2Transparent.bob \ - build/ba_data/models/kronkToes.bob \ - build/ba_data/models/alwaysLandLevel.bob \ - build/ba_data/models/oldLadyToes.bob \ - build/ba_data/models/superheroHand.bob \ - build/ba_data/models/toolbarBacking.bob \ - build/ba_data/models/bomb.bob \ - build/ba_data/models/currencyMeter.bob \ - build/ba_data/models/cowboyUpperLeg.bob \ - build/ba_data/models/ninjaLowerLeg.bob \ - build/ba_data/models/kronkForeArm.bob \ - build/ba_data/models/ninjaHand.bob \ - build/ba_data/models/windowBGBlotch.bob \ - build/ba_data/models/kronkPelvis.bob \ - build/ba_data/models/agentTorso.bob \ - build/ba_data/models/penguinLowerLeg.bob \ - build/ba_data/models/scrollBarThumbShortOpaque.bob \ - build/ba_data/models/bunnyLowerLeg.bob \ - build/ba_data/models/neoSpazPelvis.bob \ - build/ba_data/models/scrollWidgetShort.bob \ - build/ba_data/models/operaSingerHand.bob \ - build/ba_data/models/image1x1FullScreen.bob \ - build/ba_data/models/ninjaTorso.bob \ - build/ba_data/models/assassinHead.bob \ - build/ba_data/models/jackHead.bob \ - build/ba_data/models/level_select_button_transparent.bob \ - build/ba_data/models/rampageLevelBottom.bob \ - build/ba_data/models/pixieHead.bob \ - build/ba_data/models/toolbarBackingTransparent.bob \ - build/ba_data/models/aliUpperLeg.bob \ - build/ba_data/models/alienToes.bob \ - build/ba_data/models/cyborgLowerLeg.bob \ - build/ba_data/models/runningShoes.bob \ - build/ba_data/models/oldLadyLowerLeg.bob \ - build/ba_data/models/scorch.bob \ - build/ba_data/models/cowboyToes.bob \ - build/ba_data/models/ninjaPelvis.bob \ - build/ba_data/models/wrestlerForeArm.bob \ - build/ba_data/models/heartOpaque.bob \ - build/ba_data/models/level_select_button_opaque.bob \ - build/ba_data/models/frostyUpperLeg.bob \ - build/ba_data/models/bonesForeArm.bob \ - build/ba_data/models/frostyHead.bob \ - build/ba_data/models/witchHand.bob \ - build/ba_data/models/cyborgToes.bob \ - build/ba_data/models/wizardTorso.bob \ - build/ba_data/models/shield.bob \ - build/ba_data/models/image4x1.bob \ - build/ba_data/models/frostyForeArm.bob \ - build/ba_data/models/bunnyUpperArm.bob \ - build/ba_data/models/bridgitLevelTop.bob \ - build/ba_data/models/agentHand.bob \ - build/ba_data/models/flagStand.bob \ - build/ba_data/models/cragCastleLevelBottom.bob \ - build/ba_data/models/doomShroomBG.bob \ - build/ba_data/models/melHead.bob \ - build/ba_data/models/assassinTorso.bob \ - build/ba_data/models/image1x1VRFullScreen.bob \ - build/ba_data/models/witchForeArm.bob \ - build/ba_data/models/penguinUpperArm.bob \ - build/ba_data/models/aliForeArm.bob \ - build/ba_data/models/robotHand.bob \ - build/ba_data/models/lakeFrigidVRFill.bob \ - build/ba_data/models/oldLadyPelvis.bob \ - build/ba_data/models/bunnyHand.bob \ - build/ba_data/models/wing.bob \ - build/ba_data/models/ninjaUpperArm.bob \ - build/ba_data/models/bonesPelvis.bob \ - build/ba_data/models/santaHand.bob \ - build/ba_data/models/neoSpazTorso.bob \ - build/ba_data/models/witchUpperArm.bob \ - build/ba_data/models/superheroForeArm.bob \ - build/ba_data/models/jumpsuitUpperArm.bob \ - build/ba_data/models/hairTuft1b.bob \ - build/ba_data/models/superheroUpperLeg.bob \ - build/ba_data/models/bearPelvis.bob \ - build/ba_data/models/natureBackgroundVRFill.bob \ - build/ba_data/models/penguinHead.bob \ - build/ba_data/models/warriorToes.bob \ - build/ba_data/models/arrowBack.bob \ - build/ba_data/models/zigZagLevel.bob \ - build/ba_data/models/frostyUpperArm.bob \ - build/ba_data/models/tipTopLevelBottom.bob \ - build/ba_data/models/santaLowerLeg.bob \ - build/ba_data/models/playerLineup3Transparent.bob \ - build/ba_data/models/santaForeArm.bob \ - build/ba_data/models/agentToes.bob \ - build/ba_data/models/doomShroomLevel.bob \ - build/ba_data/models/bombSticky.bob \ - build/ba_data/models/zoeForeArm.bob \ - build/ba_data/models/doomShroomVRFill.bob \ - build/ba_data/models/alwaysLandLevelBottom.bob \ - build/ba_data/models/aliUpperArm.bob \ - build/ba_data/models/towerDLevelBottom.bob \ - build/ba_data/models/actionHeroPelvis.bob \ - build/ba_data/models/warriorHand.bob \ - build/ba_data/models/operaSingerTorso.bob \ - build/ba_data/models/frostyTorso.bob \ - build/ba_data/models/toolbarBackingBottom.bob \ - build/ba_data/models/gladiatorLowerLeg.bob \ - build/ba_data/models/neoSpazLowerLeg.bob \ - build/ba_data/models/robotToes.bob \ - build/ba_data/models/bunnyToes.bob \ - build/ba_data/models/santaToes.bob \ - build/ba_data/models/cowboyLowerLeg.bob \ - build/ba_data/models/ninjaUpperLeg.bob \ - build/ba_data/models/windowHSmallVMedOpaque.bob \ - build/ba_data/models/aliHead.bob \ - build/ba_data/models/cowboyHand.bob \ - build/ba_data/models/thePadBG.bob \ - build/ba_data/models/thePadVRFillBottom.bob \ - build/ba_data/models/bearTorso.bob \ - build/ba_data/models/superheroUpperArm.bob \ - build/ba_data/models/buttonLargerOpaque.bob \ - build/ba_data/models/witchUpperLeg.bob \ - build/ba_data/models/eyeBallIris.bob \ - build/ba_data/models/alienHand.bob \ - build/ba_data/models/jumpsuitUpperLeg.bob \ - build/ba_data/models/stepRightUpLevelBottom.bob \ - build/ba_data/models/cyborgHand.bob \ - build/ba_data/models/bunnyUpperLeg.bob \ - build/ba_data/models/witchToes.bob \ - build/ba_data/models/cowboyPelvis.bob \ - build/ba_data/models/penguinUpperLeg.bob \ - build/ba_data/models/melForeArm.bob \ - build/ba_data/models/buttonBackTransparent.bob \ - build/ba_data/models/monkeyFaceLevelBottom.bob \ - build/ba_data/models/frostyPelvis.bob \ - build/ba_data/models/pixieForeArm.bob \ - build/ba_data/models/neoSpazUpperArm.bob \ - build/ba_data/models/gladiatorUpperArm.bob \ - build/ba_data/models/superheroToes.bob \ - build/ba_data/models/oldLadyHand.bob \ - build/ba_data/models/kronkHand.bob \ - build/ba_data/models/oldLadyUpperLeg.bob \ - build/ba_data/models/windowHSmallVSmallTransparent.bob \ - build/ba_data/models/buttonSmallTransparent.bob \ - build/ba_data/models/cyborgUpperLeg.bob \ - build/ba_data/models/box.bob \ - build/ba_data/models/buttonSmallOpaque.bob \ - build/ba_data/models/aliLowerLeg.bob \ - build/ba_data/models/zoeToes.bob \ - build/ba_data/models/bearHand.bob \ - build/ba_data/models/bonesHand.bob \ - build/ba_data/models/alienPelvis.bob \ - build/ba_data/models/lakeFrigid.bob \ - build/ba_data/models/hockeyStadiumStands.bob \ - build/ba_data/models/penguinPelvis.bob \ - build/ba_data/models/superheroTorso.bob \ - build/ba_data/models/footballStadium.bob \ - build/ba_data/models/wrestlerPelvis.bob \ - build/ba_data/models/operaSingerToes.bob \ - build/ba_data/models/actionHeroHead.bob \ - build/ba_data/models/ninjaToes.bob \ - build/ba_data/models/flash.bob \ - build/ba_data/models/santaUpperArm.bob \ - build/ba_data/models/frostyLowerLeg.bob \ - build/ba_data/models/gladiatorTorso.bob \ - build/ba_data/models/superheroPelvis.bob \ - build/ba_data/models/cylinder.bob \ - build/ba_data/models/windowHSmallVSmallOpaque.bob \ - build/ba_data/models/thePadLevelBottom.bob \ - build/ba_data/models/neoSpazHead.bob \ - build/ba_data/models/toolbarBackingOpaque.bob \ - build/ba_data/models/shrapnel1.bob \ - build/ba_data/models/assassinForeArm.bob \ - build/ba_data/models/arrowFront.bob \ - build/ba_data/models/wrestlerHand.bob \ - build/ba_data/models/angryComputerTransparent.bob \ - build/ba_data/models/buttonLargeTransparent.bob \ - build/ba_data/models/wizardHand.bob \ - build/ba_data/models/boxingGlove.bob \ - build/ba_data/models/tipTopLevel.bob \ - build/ba_data/models/bonesTorso.bob \ - build/ba_data/models/lakeFrigidReflections.bob \ - build/ba_data/models/image2x1.bob \ - build/ba_data/models/superheroLowerLeg.bob \ - build/ba_data/models/buttonNull.bob \ - build/ba_data/models/cowboyUpperArm.bob \ - build/ba_data/models/buttonLargeOpaque.bob \ - build/ba_data/models/jumpsuitHand.bob \ - build/ba_data/models/locatorBox.bob \ - build/ba_data/models/cyborgPelvis.bob \ - build/ba_data/models/aliHand.bob \ - build/ba_data/models/cowboyHead.bob \ - build/ba_data/models/wrestlerLowerLeg.bob \ - build/ba_data/models/jackLowerLeg.bob \ - build/ba_data/models/alienLowerLeg.bob \ - build/ba_data/models/hairTuft3.bob \ - build/ba_data/models/pixieToes.bob \ - build/ba_data/models/rampageBG.bob \ - build/ba_data/models/impactBomb.bob \ - build/ba_data/models/alienHead.bob \ - build/ba_data/models/scrollBarThumbShortTransparent.bob \ - build/ba_data/models/assassinToes.bob \ - build/ba_data/models/jackToes.bob \ - build/ba_data/models/actionButtonTop.bob \ - build/ba_data/models/witchPelvis.bob \ - build/ba_data/models/cyborgHead.bob \ - build/ba_data/models/melUpperArm.bob \ - build/ba_data/models/tnt.bob \ - build/ba_data/models/wizardPelvis.bob \ - build/ba_data/models/rampageBG2.bob \ - build/ba_data/models/wizardUpperLeg.bob \ - build/ba_data/models/cowboyTorso.bob \ - build/ba_data/models/locatorCircle.bob \ - build/ba_data/models/frostyToes.bob \ - build/ba_data/models/bunnyForeArm.bob \ - build/ba_data/models/warriorLowerLeg.bob \ - build/ba_data/models/penguinForeArm.bob \ - build/ba_data/models/actionHeroUpperArm.bob \ + build/ba_data/models/actionButtonBottom.bob \ build/ba_data/models/actionButtonLeft.bob \ - build/ba_data/models/actionHeroForeArm.bob \ - build/ba_data/models/powerupSimple.bob \ - build/ba_data/models/robotUpperArm.bob \ - build/ba_data/models/bearForeArm.bob \ - build/ba_data/models/melToes.bob \ - build/ba_data/models/shrapnelSlime.bob \ - build/ba_data/models/lakeFrigidTop.bob \ - build/ba_data/models/pixieUpperLeg.bob \ - build/ba_data/models/operaSingerUpperArm.bob \ - build/ba_data/models/cyborgForeArm.bob \ - build/ba_data/models/shockWave.bob \ - build/ba_data/models/warriorHead.bob \ - build/ba_data/models/assassinPelvis.bob \ - build/ba_data/models/bearLowerLeg.bob \ - build/ba_data/models/penguinToes.bob \ - build/ba_data/models/jackForeArm.bob \ - build/ba_data/models/buttonSquareTransparent.bob \ - build/ba_data/models/aliPelvis.bob \ - build/ba_data/models/bonesLowerLeg.bob \ - build/ba_data/models/toolbarBackingTop.bob \ - build/ba_data/models/thePadLevel.bob \ - build/ba_data/models/kronkUpperLeg.bob \ - build/ba_data/models/tipTopBG.bob \ - build/ba_data/models/wizardForeArm.bob \ - build/ba_data/models/neoSpazHand.bob \ - build/ba_data/models/agentForeArm.bob \ - build/ba_data/models/actionHeroTorso.bob \ - build/ba_data/models/warriorUpperArm.bob \ - build/ba_data/models/logoTransparent.bob \ - build/ba_data/models/wrestlerHead.bob \ - build/ba_data/models/toolbarBackingBottom2.bob \ - build/ba_data/models/melLowerLeg.bob \ - build/ba_data/models/assassinUpperLeg.bob \ - build/ba_data/models/gladiatorToes.bob \ - build/ba_data/models/vrFade.bob \ - build/ba_data/models/rampageVRFill.bob \ - build/ba_data/models/cragCastleVRFillMound.bob \ - build/ba_data/models/courtyardLevel.bob \ - build/ba_data/models/landMine.bob \ - build/ba_data/models/wizardHead.bob \ - build/ba_data/models/oldLadyTorso.bob \ - build/ba_data/models/jackUpperArm.bob \ - build/ba_data/models/wrestlerUpperArm.bob \ - build/ba_data/models/alienUpperArm.bob \ - build/ba_data/models/jumpsuitHead.bob \ - build/ba_data/models/eyeBall.bob \ - build/ba_data/models/textBoxTransparent.bob \ - build/ba_data/models/bridgitLevelBottom.bob \ - build/ba_data/models/oldLadyHead.bob \ - build/ba_data/models/kronkHead.bob \ - build/ba_data/models/bearUpperArm.bob \ - build/ba_data/models/bunnyTorso.bob \ - build/ba_data/models/bonesUpperArm.bob \ - build/ba_data/models/bearHead.bob \ - build/ba_data/models/bonesHead.bob \ - build/ba_data/models/oldLadyForeArm.bob \ - build/ba_data/models/windowHSmallVMedTransparent.bob \ - build/ba_data/models/buttonMediumOpaque.bob \ - build/ba_data/models/roundaboutLevelBottom.bob \ - build/ba_data/models/buttonTabTransparent.bob \ - build/ba_data/models/warriorForeArm.bob \ - build/ba_data/models/operaSingerLowerLeg.bob \ - build/ba_data/models/agentUpperLeg.bob \ - build/ba_data/models/actionHeroLowerLeg.bob \ - build/ba_data/models/robotLowerLeg.bob \ - build/ba_data/models/buttonLargerTransparent.bob \ - build/ba_data/models/robotPelvis.bob \ build/ba_data/models/actionButtonRight.bob \ - build/ba_data/models/zoeUpperLeg.bob \ + build/ba_data/models/actionButtonTop.bob \ + build/ba_data/models/actionHeroForeArm.bob \ build/ba_data/models/actionHeroHand.bob \ - build/ba_data/models/buttonSquareOpaque.bob \ - build/ba_data/models/zoeHead.bob \ - build/ba_data/models/egg.bob \ - build/ba_data/models/hockeyStadiumInner.bob \ - build/ba_data/models/alienUpperLeg.bob \ - build/ba_data/models/jackUpperLeg.bob \ - build/ba_data/models/wrestlerUpperLeg.bob \ - build/ba_data/models/buttonBackSmallTransparent.bob \ - build/ba_data/models/monkeyFaceLevel.bob \ - build/ba_data/models/hairTuft2.bob \ - build/ba_data/models/bunnyPelvis.bob \ - build/ba_data/models/superheroHead.bob \ - build/ba_data/models/meterTransparent.bob \ - build/ba_data/models/warriorUpperLeg.bob \ - build/ba_data/models/gladiatorPelvis.bob \ + build/ba_data/models/actionHeroHead.bob \ + build/ba_data/models/actionHeroLowerLeg.bob \ + build/ba_data/models/actionHeroPelvis.bob \ build/ba_data/models/actionHeroToes.bob \ - build/ba_data/models/jumpsuitPelvis.bob \ - build/ba_data/models/ninjaHead.bob \ - build/ba_data/models/footballStadiumVRFill.bob \ - build/ba_data/models/crossOut.bob \ - build/ba_data/models/checkTransparent.bob \ - build/ba_data/models/operaSingerHead.bob \ - build/ba_data/models/wizardLowerLeg.bob \ - build/ba_data/models/cyborgTorso.bob \ - build/ba_data/models/stepRightUpVRFillMound.bob \ - build/ba_data/models/robotForeArm.bob \ - build/ba_data/models/assassinUpperArm.bob \ - build/ba_data/models/scrollBarThumbShortSimple.bob \ - build/ba_data/models/bigG.bob \ - build/ba_data/models/agentUpperArm.bob \ - build/ba_data/models/courtyardLevelBottom.bob \ - build/ba_data/models/eyeLid.bob \ - build/ba_data/models/pixieLowerLeg.bob \ - build/ba_data/models/gladiatorHand.bob \ - build/ba_data/models/ninjaForeArm.bob \ - build/ba_data/models/penguinTorso.bob \ - build/ba_data/models/toolbarBackingTop2.bob \ - build/ba_data/models/stepRightUpLevel.bob \ - build/ba_data/models/neoSpazToes.bob \ - build/ba_data/models/zoeUpperArm.bob \ - build/ba_data/models/kronkTorso.bob \ - build/ba_data/models/warriorPelvis.bob \ - build/ba_data/models/gladiatorForeArm.bob \ - build/ba_data/models/locator.bob \ - build/ba_data/models/neoSpazForeArm.bob \ - build/ba_data/models/buttonMediumTransparent.bob \ - build/ba_data/models/pixiePelvis.bob \ - build/ba_data/models/logo.bob \ - build/ba_data/models/scrollBarThumbSimple.bob \ - build/ba_data/models/kronkLowerLeg.bob \ - build/ba_data/models/aliTorso.bob \ - build/ba_data/models/scrollBarThumbTransparent.bob \ - build/ba_data/models/locatorCircleOutline.bob \ - build/ba_data/models/alwaysLandVRFillMound.bob \ - build/ba_data/models/alienForeArm.bob \ - build/ba_data/models/bonesUpperLeg.bob \ - build/ba_data/models/softEdgeOutside.bob \ - build/ba_data/models/bearUpperLeg.bob \ - build/ba_data/models/roundaboutLevel.bob \ - build/ba_data/models/wizardUpperArm.bob \ - build/ba_data/models/playerLineup4Transparent.bob \ - build/ba_data/models/zigZagLevelBottom.bob \ - build/ba_data/models/assassinLowerLeg.bob \ - build/ba_data/models/melUpperLeg.bob \ - build/ba_data/models/robotTorso.bob \ - build/ba_data/models/cragCastleLevel.bob \ - build/ba_data/models/zoePelvis.bob \ - build/ba_data/models/agentHead.bob \ - build/ba_data/models/rampageLevel.bob \ - build/ba_data/models/thePadVRFillMound.bob \ - build/ba_data/models/melHand.bob \ - build/ba_data/models/jackTorso.bob \ - build/ba_data/models/pixieTorso.bob \ - build/ba_data/models/santaHead.bob \ - build/ba_data/models/playerLineup1Transparent.bob \ - build/ba_data/models/bigGBottom.bob \ - build/ba_data/models/robotHead.bob \ - build/ba_data/models/frameInset.bob \ - build/ba_data/models/bunnyHead.bob \ - build/ba_data/models/santaTorso.bob \ - build/ba_data/models/penguinHand.bob \ - build/ba_data/models/heartTransparent.bob \ - build/ba_data/models/hairTuft4.bob \ - build/ba_data/models/doomShroomStem.bob \ - build/ba_data/models/buttonBackSmallOpaque.bob \ - build/ba_data/models/pixieHand.bob \ - build/ba_data/models/scrollBarTroughTransparent.bob \ - build/ba_data/models/assassinHand.bob \ - build/ba_data/models/jackHand.bob \ - build/ba_data/models/agentPelvis.bob \ - build/ba_data/models/towerDLevel.bob \ - build/ba_data/models/softEdgeInside.bob \ - build/ba_data/models/aliToes.bob \ - build/ba_data/models/hockeyStadiumOuter.bob \ - build/ba_data/models/warriorTorso.bob \ - build/ba_data/models/image2x1Vertical.bob \ - build/ba_data/models/kronkUpperArm.bob \ - build/ba_data/models/zoeLowerLeg.bob \ - build/ba_data/models/wrestlerTorso.bob \ - build/ba_data/models/frostyHand.bob \ - build/ba_data/models/robotUpperLeg.bob \ - build/ba_data/models/alwaysLandBG.bob \ - build/ba_data/models/jumpsuitForeArm.bob \ + build/ba_data/models/actionHeroTorso.bob \ + build/ba_data/models/actionHeroUpperArm.bob \ build/ba_data/models/actionHeroUpperLeg.bob \ + build/ba_data/models/agentForeArm.bob \ + build/ba_data/models/agentHand.bob \ + build/ba_data/models/agentHead.bob \ build/ba_data/models/agentLowerLeg.bob \ - build/ba_data/models/witchHead.bob \ - build/ba_data/models/operaSingerUpperLeg.bob \ - build/ba_data/models/pixieUpperArm.bob \ + build/ba_data/models/agentPelvis.bob \ + build/ba_data/models/agentToes.bob \ + build/ba_data/models/agentTorso.bob \ + build/ba_data/models/agentUpperArm.bob \ + build/ba_data/models/agentUpperLeg.bob \ + build/ba_data/models/aliForeArm.bob \ + build/ba_data/models/aliHand.bob \ + build/ba_data/models/aliHead.bob \ + build/ba_data/models/aliLowerLeg.bob \ + build/ba_data/models/aliPelvis.bob \ + build/ba_data/models/aliToes.bob \ + build/ba_data/models/aliTorso.bob \ + build/ba_data/models/aliUpperArm.bob \ + build/ba_data/models/aliUpperLeg.bob \ + build/ba_data/models/alienForeArm.bob \ + build/ba_data/models/alienHand.bob \ + build/ba_data/models/alienHead.bob \ + build/ba_data/models/alienLowerLeg.bob \ + build/ba_data/models/alienPelvis.bob \ + build/ba_data/models/alienToes.bob \ + build/ba_data/models/alienTorso.bob \ + build/ba_data/models/alienUpperArm.bob \ + build/ba_data/models/alienUpperLeg.bob \ + build/ba_data/models/alwaysLandBG.bob \ + build/ba_data/models/alwaysLandLevel.bob \ + build/ba_data/models/alwaysLandLevelBottom.bob \ + build/ba_data/models/alwaysLandVRFillMound.bob \ + build/ba_data/models/angryComputerTransparent.bob \ + build/ba_data/models/arrowBack.bob \ + build/ba_data/models/arrowFront.bob \ + build/ba_data/models/assassinForeArm.bob \ + build/ba_data/models/assassinHand.bob \ + build/ba_data/models/assassinHead.bob \ + build/ba_data/models/assassinLowerLeg.bob \ + build/ba_data/models/assassinPelvis.bob \ + build/ba_data/models/assassinToes.bob \ + build/ba_data/models/assassinTorso.bob \ + build/ba_data/models/assassinUpperArm.bob \ + build/ba_data/models/assassinUpperLeg.bob \ + build/ba_data/models/bearForeArm.bob \ + build/ba_data/models/bearHand.bob \ + build/ba_data/models/bearHead.bob \ + build/ba_data/models/bearLowerLeg.bob \ + build/ba_data/models/bearPelvis.bob \ + build/ba_data/models/bearToes.bob \ + build/ba_data/models/bearTorso.bob \ + build/ba_data/models/bearUpperArm.bob \ + build/ba_data/models/bearUpperLeg.bob \ + build/ba_data/models/bigG.bob \ + build/ba_data/models/bigGBottom.bob \ + build/ba_data/models/bomb.bob \ + build/ba_data/models/bombSticky.bob \ + build/ba_data/models/bonesForeArm.bob \ + build/ba_data/models/bonesHand.bob \ + build/ba_data/models/bonesHead.bob \ + build/ba_data/models/bonesLowerLeg.bob \ + build/ba_data/models/bonesPelvis.bob \ + build/ba_data/models/bonesToes.bob \ + build/ba_data/models/bonesTorso.bob \ + build/ba_data/models/bonesUpperArm.bob \ + build/ba_data/models/bonesUpperLeg.bob \ + build/ba_data/models/box.bob \ + build/ba_data/models/boxingGlove.bob \ + build/ba_data/models/bridgitLevelBottom.bob \ + build/ba_data/models/bridgitLevelTop.bob \ + build/ba_data/models/bunnyForeArm.bob \ + build/ba_data/models/bunnyHand.bob \ + build/ba_data/models/bunnyHead.bob \ + build/ba_data/models/bunnyLowerLeg.bob \ + build/ba_data/models/bunnyPelvis.bob \ + build/ba_data/models/bunnyToes.bob \ + build/ba_data/models/bunnyTorso.bob \ + build/ba_data/models/bunnyUpperArm.bob \ + build/ba_data/models/bunnyUpperLeg.bob \ + build/ba_data/models/buttonBackOpaque.bob \ + build/ba_data/models/buttonBackSmallOpaque.bob \ + build/ba_data/models/buttonBackSmallTransparent.bob \ + build/ba_data/models/buttonBackTransparent.bob \ + build/ba_data/models/buttonLargeOpaque.bob \ + build/ba_data/models/buttonLargeTransparent.bob \ + build/ba_data/models/buttonLargerOpaque.bob \ + build/ba_data/models/buttonLargerTransparent.bob \ + build/ba_data/models/buttonMediumOpaque.bob \ + build/ba_data/models/buttonMediumTransparent.bob \ + build/ba_data/models/buttonNull.bob \ + build/ba_data/models/buttonSmallOpaque.bob \ + build/ba_data/models/buttonSmallTransparent.bob \ + build/ba_data/models/buttonSquareOpaque.bob \ + build/ba_data/models/buttonSquareTransparent.bob \ + build/ba_data/models/buttonTabOpaque.bob \ + build/ba_data/models/buttonTabTransparent.bob \ + build/ba_data/models/checkTransparent.bob \ + build/ba_data/models/courtyardLevel.bob \ + build/ba_data/models/courtyardLevelBottom.bob \ + build/ba_data/models/cowboyForeArm.bob \ + build/ba_data/models/cowboyHand.bob \ + build/ba_data/models/cowboyHead.bob \ + build/ba_data/models/cowboyLowerLeg.bob \ + build/ba_data/models/cowboyPelvis.bob \ + build/ba_data/models/cowboyToes.bob \ + build/ba_data/models/cowboyTorso.bob \ + build/ba_data/models/cowboyUpperArm.bob \ + build/ba_data/models/cowboyUpperLeg.bob \ + build/ba_data/models/cragCastleLevel.bob \ + build/ba_data/models/cragCastleLevelBottom.bob \ + build/ba_data/models/cragCastleVRFillMound.bob \ + build/ba_data/models/crossOut.bob \ + build/ba_data/models/currencyMeter.bob \ + build/ba_data/models/currencyPlusButton.bob \ + build/ba_data/models/cyborgForeArm.bob \ + build/ba_data/models/cyborgHand.bob \ + build/ba_data/models/cyborgHead.bob \ + build/ba_data/models/cyborgLowerLeg.bob \ + build/ba_data/models/cyborgPelvis.bob \ + build/ba_data/models/cyborgToes.bob \ + build/ba_data/models/cyborgTorso.bob \ + build/ba_data/models/cyborgUpperArm.bob \ + build/ba_data/models/cyborgUpperLeg.bob \ + build/ba_data/models/cylinder.bob \ + build/ba_data/models/doomShroomBG.bob \ + build/ba_data/models/doomShroomLevel.bob \ + build/ba_data/models/doomShroomStem.bob \ + build/ba_data/models/doomShroomVRFill.bob \ + build/ba_data/models/egg.bob \ + build/ba_data/models/eyeBall.bob \ + build/ba_data/models/eyeBallIris.bob \ + build/ba_data/models/eyeLid.bob \ build/ba_data/models/flagPole.bob \ + build/ba_data/models/flagStand.bob \ + build/ba_data/models/flash.bob \ + build/ba_data/models/footballStadium.bob \ + build/ba_data/models/footballStadiumVRFill.bob \ + build/ba_data/models/frameInset.bob \ + build/ba_data/models/frostyForeArm.bob \ + build/ba_data/models/frostyHand.bob \ + build/ba_data/models/frostyHead.bob \ + build/ba_data/models/frostyLowerLeg.bob \ + build/ba_data/models/frostyPelvis.bob \ + build/ba_data/models/frostyToes.bob \ + build/ba_data/models/frostyTorso.bob \ + build/ba_data/models/frostyUpperArm.bob \ + build/ba_data/models/frostyUpperLeg.bob \ + build/ba_data/models/gladiatorForeArm.bob \ + build/ba_data/models/gladiatorHand.bob \ + build/ba_data/models/gladiatorHead.bob \ + build/ba_data/models/gladiatorLowerLeg.bob \ + build/ba_data/models/gladiatorPelvis.bob \ + build/ba_data/models/gladiatorToes.bob \ + build/ba_data/models/gladiatorTorso.bob \ + build/ba_data/models/gladiatorUpperArm.bob \ + build/ba_data/models/gladiatorUpperLeg.bob \ + build/ba_data/models/hairTuft1.bob \ + build/ba_data/models/hairTuft1b.bob \ + build/ba_data/models/hairTuft2.bob \ + build/ba_data/models/hairTuft3.bob \ + build/ba_data/models/hairTuft4.bob \ + build/ba_data/models/heartOpaque.bob \ + build/ba_data/models/heartTransparent.bob \ + build/ba_data/models/hockeyStadiumInner.bob \ + build/ba_data/models/hockeyStadiumOuter.bob \ + build/ba_data/models/hockeyStadiumStands.bob \ + build/ba_data/models/image16x1.bob \ + build/ba_data/models/image1x1.bob \ + build/ba_data/models/image1x1FullScreen.bob \ + build/ba_data/models/image1x1VRFullScreen.bob \ + build/ba_data/models/image2x1.bob \ + build/ba_data/models/image2x1Vertical.bob \ + build/ba_data/models/image4x1.bob \ + build/ba_data/models/impactBomb.bob \ + build/ba_data/models/jackForeArm.bob \ + build/ba_data/models/jackHand.bob \ + build/ba_data/models/jackHead.bob \ + build/ba_data/models/jackLowerLeg.bob \ + build/ba_data/models/jackToes.bob \ + build/ba_data/models/jackTorso.bob \ + build/ba_data/models/jackUpperArm.bob \ + build/ba_data/models/jackUpperLeg.bob \ + build/ba_data/models/jumpsuitForeArm.bob \ + build/ba_data/models/jumpsuitHand.bob \ + build/ba_data/models/jumpsuitHead.bob \ + build/ba_data/models/jumpsuitLowerLeg.bob \ + build/ba_data/models/jumpsuitPelvis.bob \ + build/ba_data/models/jumpsuitToes.bob \ + build/ba_data/models/jumpsuitTorso.bob \ + build/ba_data/models/jumpsuitUpperArm.bob \ + build/ba_data/models/jumpsuitUpperLeg.bob \ + build/ba_data/models/kronkForeArm.bob \ + build/ba_data/models/kronkHand.bob \ + build/ba_data/models/kronkHead.bob \ + build/ba_data/models/kronkLowerLeg.bob \ + build/ba_data/models/kronkPelvis.bob \ + build/ba_data/models/kronkToes.bob \ + build/ba_data/models/kronkTorso.bob \ + build/ba_data/models/kronkUpperArm.bob \ + build/ba_data/models/kronkUpperLeg.bob \ + build/ba_data/models/lakeFrigid.bob \ + build/ba_data/models/lakeFrigidReflections.bob \ + build/ba_data/models/lakeFrigidTop.bob \ + build/ba_data/models/lakeFrigidVRFill.bob \ + build/ba_data/models/landMine.bob \ + build/ba_data/models/level_select_button_opaque.bob \ + build/ba_data/models/level_select_button_transparent.bob \ + build/ba_data/models/locator.bob \ + build/ba_data/models/locatorBox.bob \ + build/ba_data/models/locatorCircle.bob \ + build/ba_data/models/locatorCircleOutline.bob \ + build/ba_data/models/logo.bob \ + build/ba_data/models/logoTransparent.bob \ + build/ba_data/models/melForeArm.bob \ + build/ba_data/models/melHand.bob \ + build/ba_data/models/melHead.bob \ + build/ba_data/models/melLowerLeg.bob \ + build/ba_data/models/melToes.bob \ + build/ba_data/models/melTorso.bob \ + build/ba_data/models/melUpperArm.bob \ + build/ba_data/models/melUpperLeg.bob \ + build/ba_data/models/meterTransparent.bob \ + build/ba_data/models/monkeyFaceLevel.bob \ + build/ba_data/models/monkeyFaceLevelBottom.bob \ + build/ba_data/models/natureBackground.bob \ + build/ba_data/models/natureBackgroundVRFill.bob \ + build/ba_data/models/neoSpazForeArm.bob \ + build/ba_data/models/neoSpazHand.bob \ + build/ba_data/models/neoSpazHead.bob \ + build/ba_data/models/neoSpazLowerLeg.bob \ + build/ba_data/models/neoSpazPelvis.bob \ + build/ba_data/models/neoSpazToes.bob \ + build/ba_data/models/neoSpazTorso.bob \ + build/ba_data/models/neoSpazUpperArm.bob \ + build/ba_data/models/neoSpazUpperLeg.bob \ + build/ba_data/models/ninjaForeArm.bob \ + build/ba_data/models/ninjaHand.bob \ + build/ba_data/models/ninjaHead.bob \ + build/ba_data/models/ninjaLowerLeg.bob \ + build/ba_data/models/ninjaPelvis.bob \ + build/ba_data/models/ninjaToes.bob \ + build/ba_data/models/ninjaTorso.bob \ + build/ba_data/models/ninjaUpperArm.bob \ + build/ba_data/models/ninjaUpperLeg.bob \ + build/ba_data/models/oldLadyForeArm.bob \ + build/ba_data/models/oldLadyHand.bob \ + build/ba_data/models/oldLadyHead.bob \ + build/ba_data/models/oldLadyLowerLeg.bob \ + build/ba_data/models/oldLadyPelvis.bob \ + build/ba_data/models/oldLadyToes.bob \ + build/ba_data/models/oldLadyTorso.bob \ + build/ba_data/models/oldLadyUpperArm.bob \ + build/ba_data/models/oldLadyUpperLeg.bob \ + build/ba_data/models/operaSingerForeArm.bob \ + build/ba_data/models/operaSingerHand.bob \ + build/ba_data/models/operaSingerHead.bob \ + build/ba_data/models/operaSingerLowerLeg.bob \ + build/ba_data/models/operaSingerPelvis.bob \ + build/ba_data/models/operaSingerToes.bob \ + build/ba_data/models/operaSingerTorso.bob \ + build/ba_data/models/operaSingerUpperArm.bob \ + build/ba_data/models/operaSingerUpperLeg.bob \ + build/ba_data/models/overlayGuide.bob \ + build/ba_data/models/penguinForeArm.bob \ + build/ba_data/models/penguinHand.bob \ + build/ba_data/models/penguinHead.bob \ + build/ba_data/models/penguinLowerLeg.bob \ + build/ba_data/models/penguinPelvis.bob \ + build/ba_data/models/penguinToes.bob \ + build/ba_data/models/penguinTorso.bob \ + build/ba_data/models/penguinUpperArm.bob \ + build/ba_data/models/penguinUpperLeg.bob \ + build/ba_data/models/pixieForeArm.bob \ + build/ba_data/models/pixieHand.bob \ + build/ba_data/models/pixieHead.bob \ + build/ba_data/models/pixieLowerLeg.bob \ + build/ba_data/models/pixiePelvis.bob \ + build/ba_data/models/pixieToes.bob \ + build/ba_data/models/pixieTorso.bob \ + build/ba_data/models/pixieUpperArm.bob \ + build/ba_data/models/pixieUpperLeg.bob \ + build/ba_data/models/plasticEyesTransparent.bob \ + build/ba_data/models/playerLineup1Transparent.bob \ + build/ba_data/models/playerLineup2Transparent.bob \ + build/ba_data/models/playerLineup3Transparent.bob \ + build/ba_data/models/playerLineup4Transparent.bob \ build/ba_data/models/powerup.bob \ - build/ba_data/models/thePadVRFillTop.bob + build/ba_data/models/powerupSimple.bob \ + build/ba_data/models/puck.bob \ + build/ba_data/models/rampageBG.bob \ + build/ba_data/models/rampageBG2.bob \ + build/ba_data/models/rampageLevel.bob \ + build/ba_data/models/rampageLevelBottom.bob \ + build/ba_data/models/rampageVRFill.bob \ + build/ba_data/models/robotForeArm.bob \ + build/ba_data/models/robotHand.bob \ + build/ba_data/models/robotHead.bob \ + build/ba_data/models/robotLowerLeg.bob \ + build/ba_data/models/robotPelvis.bob \ + build/ba_data/models/robotToes.bob \ + build/ba_data/models/robotTorso.bob \ + build/ba_data/models/robotUpperArm.bob \ + build/ba_data/models/robotUpperLeg.bob \ + build/ba_data/models/roundaboutLevel.bob \ + build/ba_data/models/roundaboutLevelBottom.bob \ + build/ba_data/models/runningShoes.bob \ + build/ba_data/models/santaForeArm.bob \ + build/ba_data/models/santaHand.bob \ + build/ba_data/models/santaHead.bob \ + build/ba_data/models/santaLowerLeg.bob \ + build/ba_data/models/santaToes.bob \ + build/ba_data/models/santaTorso.bob \ + build/ba_data/models/santaUpperArm.bob \ + build/ba_data/models/santaUpperLeg.bob \ + build/ba_data/models/scorch.bob \ + build/ba_data/models/scrollBarThumbOpaque.bob \ + build/ba_data/models/scrollBarThumbShortOpaque.bob \ + build/ba_data/models/scrollBarThumbShortSimple.bob \ + build/ba_data/models/scrollBarThumbShortTransparent.bob \ + build/ba_data/models/scrollBarThumbSimple.bob \ + build/ba_data/models/scrollBarThumbTransparent.bob \ + build/ba_data/models/scrollBarTroughTransparent.bob \ + build/ba_data/models/scrollWidgetShort.bob \ + build/ba_data/models/shield.bob \ + build/ba_data/models/shockWave.bob \ + build/ba_data/models/shrapnel1.bob \ + build/ba_data/models/shrapnelBoard.bob \ + build/ba_data/models/shrapnelSlime.bob \ + build/ba_data/models/softEdgeInside.bob \ + build/ba_data/models/softEdgeOutside.bob \ + build/ba_data/models/stepRightUpLevel.bob \ + build/ba_data/models/stepRightUpLevelBottom.bob \ + build/ba_data/models/stepRightUpVRFillMound.bob \ + build/ba_data/models/superheroForeArm.bob \ + build/ba_data/models/superheroHand.bob \ + build/ba_data/models/superheroHead.bob \ + build/ba_data/models/superheroLowerLeg.bob \ + build/ba_data/models/superheroPelvis.bob \ + build/ba_data/models/superheroToes.bob \ + build/ba_data/models/superheroTorso.bob \ + build/ba_data/models/superheroUpperArm.bob \ + build/ba_data/models/superheroUpperLeg.bob \ + build/ba_data/models/textBoxTransparent.bob \ + build/ba_data/models/thePadBG.bob \ + build/ba_data/models/thePadBGSmall.bob \ + build/ba_data/models/thePadLevel.bob \ + build/ba_data/models/thePadLevelBottom.bob \ + build/ba_data/models/thePadVRFillBottom.bob \ + build/ba_data/models/thePadVRFillMound.bob \ + build/ba_data/models/thePadVRFillTop.bob \ + build/ba_data/models/tipTopBG.bob \ + build/ba_data/models/tipTopLevel.bob \ + build/ba_data/models/tipTopLevelBottom.bob \ + build/ba_data/models/tnt.bob \ + build/ba_data/models/toolbarBacking.bob \ + build/ba_data/models/toolbarBackingBottom.bob \ + build/ba_data/models/toolbarBackingBottom2.bob \ + build/ba_data/models/toolbarBackingOpaque.bob \ + build/ba_data/models/toolbarBackingTop.bob \ + build/ba_data/models/toolbarBackingTop2.bob \ + build/ba_data/models/toolbarBackingTransparent.bob \ + build/ba_data/models/towerDLevel.bob \ + build/ba_data/models/towerDLevelBottom.bob \ + build/ba_data/models/trees.bob \ + build/ba_data/models/vrFade.bob \ + build/ba_data/models/vrOverlay.bob \ + build/ba_data/models/warriorForeArm.bob \ + build/ba_data/models/warriorHand.bob \ + build/ba_data/models/warriorHead.bob \ + build/ba_data/models/warriorLowerLeg.bob \ + build/ba_data/models/warriorPelvis.bob \ + build/ba_data/models/warriorToes.bob \ + build/ba_data/models/warriorTorso.bob \ + build/ba_data/models/warriorUpperArm.bob \ + build/ba_data/models/warriorUpperLeg.bob \ + build/ba_data/models/windowBGBlotch.bob \ + build/ba_data/models/windowHSmallVMedOpaque.bob \ + build/ba_data/models/windowHSmallVMedTransparent.bob \ + build/ba_data/models/windowHSmallVSmallOpaque.bob \ + build/ba_data/models/windowHSmallVSmallTransparent.bob \ + build/ba_data/models/wing.bob \ + build/ba_data/models/witchForeArm.bob \ + build/ba_data/models/witchHand.bob \ + build/ba_data/models/witchHead.bob \ + build/ba_data/models/witchLowerLeg.bob \ + build/ba_data/models/witchPelvis.bob \ + build/ba_data/models/witchToes.bob \ + build/ba_data/models/witchTorso.bob \ + build/ba_data/models/witchUpperArm.bob \ + build/ba_data/models/witchUpperLeg.bob \ + build/ba_data/models/wizardForeArm.bob \ + build/ba_data/models/wizardHand.bob \ + build/ba_data/models/wizardHead.bob \ + build/ba_data/models/wizardLowerLeg.bob \ + build/ba_data/models/wizardPelvis.bob \ + build/ba_data/models/wizardToes.bob \ + build/ba_data/models/wizardTorso.bob \ + build/ba_data/models/wizardUpperArm.bob \ + build/ba_data/models/wizardUpperLeg.bob \ + build/ba_data/models/wrestlerForeArm.bob \ + build/ba_data/models/wrestlerHand.bob \ + build/ba_data/models/wrestlerHead.bob \ + build/ba_data/models/wrestlerLowerLeg.bob \ + build/ba_data/models/wrestlerPelvis.bob \ + build/ba_data/models/wrestlerToes.bob \ + build/ba_data/models/wrestlerTorso.bob \ + build/ba_data/models/wrestlerUpperArm.bob \ + build/ba_data/models/wrestlerUpperLeg.bob \ + build/ba_data/models/zigZagLevel.bob \ + build/ba_data/models/zigZagLevelBottom.bob \ + build/ba_data/models/zoeForeArm.bob \ + build/ba_data/models/zoeHand.bob \ + build/ba_data/models/zoeHead.bob \ + build/ba_data/models/zoeLowerLeg.bob \ + build/ba_data/models/zoePelvis.bob \ + build/ba_data/models/zoeToes.bob \ + build/ba_data/models/zoeTorso.bob \ + build/ba_data/models/zoeUpperArm.bob \ + build/ba_data/models/zoeUpperLeg.bob FONT_TARGETS = \ - build/ba_data/fonts/fontSmall1.fdata \ - build/ba_data/fonts/fontSmall3.fdata \ - build/ba_data/fonts/fontSmall7.fdata \ - build/ba_data/fonts/fontSmall5.fdata \ - build/ba_data/fonts/fontSmall2.fdata \ build/ba_data/fonts/fontSmall0.fdata \ + build/ba_data/fonts/fontSmall1.fdata \ + build/ba_data/fonts/fontSmall2.fdata \ + build/ba_data/fonts/fontSmall3.fdata \ build/ba_data/fonts/fontSmall4.fdata \ - build/ba_data/fonts/fontSmall6.fdata + build/ba_data/fonts/fontSmall5.fdata \ + build/ba_data/fonts/fontSmall6.fdata \ + build/ba_data/fonts/fontSmall7.fdata DATA_TARGETS = \ build/ba_data/data/langdata.json \ - build/ba_data/data/maps/monkey_face.json \ - build/ba_data/data/maps/football_stadium.json \ - build/ba_data/data/maps/tip_top.json \ - build/ba_data/data/maps/crag_castle.json \ - build/ba_data/data/maps/doom_shroom.json \ - build/ba_data/data/maps/zig_zag.json \ - build/ba_data/data/maps/step_right_up.json \ - build/ba_data/data/maps/bridgit.json \ - build/ba_data/data/maps/happy_thoughts.json \ - build/ba_data/data/maps/roundabout.json \ - build/ba_data/data/maps/rampage.json \ - build/ba_data/data/maps/lake_frigid.json \ - build/ba_data/data/maps/tower_d.json \ - build/ba_data/data/maps/hockey_stadium.json \ - build/ba_data/data/maps/courtyard.json \ - build/ba_data/data/maps/the_pad.json \ - build/ba_data/data/maps/big_g.json \ build/ba_data/data/languages/arabic.json \ - build/ba_data/data/languages/chinese.json \ - build/ba_data/data/languages/hungarian.json \ - build/ba_data/data/languages/french.json \ - build/ba_data/data/languages/serbian.json \ build/ba_data/data/languages/belarussian.json \ - build/ba_data/data/languages/polish.json \ - build/ba_data/data/languages/persian.json \ - build/ba_data/data/languages/esperanto.json \ + build/ba_data/data/languages/chinese.json \ + build/ba_data/data/languages/chinesetraditional.json \ build/ba_data/data/languages/croatian.json \ - build/ba_data/data/languages/turkish.json \ - build/ba_data/data/languages/german.json \ - build/ba_data/data/languages/vietnamese.json \ - build/ba_data/data/languages/spanish.json \ - build/ba_data/data/languages/portuguese.json \ - build/ba_data/data/languages/korean.json \ - build/ba_data/data/languages/romanian.json \ - build/ba_data/data/languages/english.json \ - build/ba_data/data/languages/russian.json \ - build/ba_data/data/languages/slovak.json \ - build/ba_data/data/languages/ukrainian.json \ - build/ba_data/data/languages/swedish.json \ - build/ba_data/data/languages/gibberish.json \ + build/ba_data/data/languages/czech.json \ + build/ba_data/data/languages/danish.json \ build/ba_data/data/languages/dutch.json \ + build/ba_data/data/languages/english.json \ + build/ba_data/data/languages/esperanto.json \ + build/ba_data/data/languages/french.json \ + build/ba_data/data/languages/german.json \ + build/ba_data/data/languages/gibberish.json \ build/ba_data/data/languages/greek.json \ build/ba_data/data/languages/hindi.json \ - build/ba_data/data/languages/chinesetraditional.json \ - build/ba_data/data/languages/czech.json \ + build/ba_data/data/languages/hungarian.json \ build/ba_data/data/languages/indonesian.json \ build/ba_data/data/languages/italian.json \ - build/ba_data/data/languages/danish.json + build/ba_data/data/languages/korean.json \ + build/ba_data/data/languages/persian.json \ + build/ba_data/data/languages/polish.json \ + build/ba_data/data/languages/portuguese.json \ + build/ba_data/data/languages/romanian.json \ + build/ba_data/data/languages/russian.json \ + build/ba_data/data/languages/serbian.json \ + build/ba_data/data/languages/slovak.json \ + build/ba_data/data/languages/spanish.json \ + build/ba_data/data/languages/swedish.json \ + build/ba_data/data/languages/turkish.json \ + build/ba_data/data/languages/ukrainian.json \ + build/ba_data/data/languages/vietnamese.json \ + build/ba_data/data/maps/big_g.json \ + build/ba_data/data/maps/bridgit.json \ + build/ba_data/data/maps/courtyard.json \ + build/ba_data/data/maps/crag_castle.json \ + build/ba_data/data/maps/doom_shroom.json \ + build/ba_data/data/maps/football_stadium.json \ + build/ba_data/data/maps/happy_thoughts.json \ + build/ba_data/data/maps/hockey_stadium.json \ + build/ba_data/data/maps/lake_frigid.json \ + build/ba_data/data/maps/monkey_face.json \ + build/ba_data/data/maps/rampage.json \ + build/ba_data/data/maps/roundabout.json \ + build/ba_data/data/maps/step_right_up.json \ + build/ba_data/data/maps/the_pad.json \ + build/ba_data/data/maps/tip_top.json \ + build/ba_data/data/maps/tower_d.json \ + build/ba_data/data/maps/zig_zag.json AUDIO_TARGETS = \ - build/ba_data/audio/penguinDeath.ogg \ - build/ba_data/audio/ali1.ogg \ - build/ba_data/audio/whenJohnnyComesMarchingHomeMusic.ogg \ - build/ba_data/audio/kronk4.ogg \ - build/ba_data/audio/bearHit1.ogg \ - build/ba_data/audio/jumpsuitHit1.ogg \ - build/ba_data/audio/skid01.ogg \ - build/ba_data/audio/swish3.ogg \ - build/ba_data/audio/ticking.ogg \ - build/ba_data/audio/agent4.ogg \ - build/ba_data/audio/announceTen.ogg \ - build/ba_data/audio/spazImpact04.ogg \ - build/ba_data/audio/bearFall.ogg \ - build/ba_data/audio/jumpsuitFall.ogg \ - build/ba_data/audio/tap.ogg \ - build/ba_data/audio/wizard4.ogg \ - build/ba_data/audio/jackHit01.ogg \ - build/ba_data/audio/kronk10.ogg \ - build/ba_data/audio/agentHit2.ogg \ - build/ba_data/audio/swish2.ogg \ - build/ba_data/audio/corkPop.ogg \ - build/ba_data/audio/laser.ogg \ - build/ba_data/audio/announceFour.ogg \ - build/ba_data/audio/frostyDeath.ogg \ - build/ba_data/audio/superhero1.ogg \ - build/ba_data/audio/scoreHit02.ogg \ - build/ba_data/audio/warnBeep.ogg \ - build/ba_data/audio/kronk5.ogg \ - build/ba_data/audio/oldLadyHit2.ogg \ - build/ba_data/audio/crowdChant.ogg \ - build/ba_data/audio/scamper01.ogg \ - build/ba_data/audio/ali2.ogg \ - build/ba_data/audio/kronk7.ogg \ - build/ba_data/audio/refWhistle.ogg \ - build/ba_data/audio/bearHit2.ogg \ - build/ba_data/audio/jumpsuitHit2.ogg \ - build/ba_data/audio/superhero3.ogg \ - build/ba_data/audio/jackFall01.ogg \ - build/ba_data/audio/aliDeath.ogg \ - build/ba_data/audio/technoHit01.ogg \ - build/ba_data/audio/frostyFall.ogg \ - build/ba_data/audio/oldLadyFall.ogg \ - build/ba_data/audio/jackHit03.ogg \ - build/ba_data/audio/alien4.ogg \ - build/ba_data/audio/agentFall.ogg \ + build/ba_data/audio/achievement.ogg \ + build/ba_data/audio/actionHero1.ogg \ + build/ba_data/audio/actionHero2.ogg \ + build/ba_data/audio/actionHero3.ogg \ + build/ba_data/audio/actionHero4.ogg \ + build/ba_data/audio/actionHeroDeath.ogg \ + build/ba_data/audio/actionHeroFall.ogg \ + build/ba_data/audio/actionHeroHit1.ogg \ + build/ba_data/audio/actionHeroHit2.ogg \ build/ba_data/audio/activateBeep.ogg \ - build/ba_data/audio/freeze.ogg \ - build/ba_data/audio/jackHit02.ogg \ - build/ba_data/audio/blank.ogg \ - build/ba_data/audio/dingSmall.ogg \ + build/ba_data/audio/agent1.ogg \ + build/ba_data/audio/agent2.ogg \ + build/ba_data/audio/agent3.ogg \ + build/ba_data/audio/agent4.ogg \ + build/ba_data/audio/agentDeath.ogg \ + build/ba_data/audio/agentFall.ogg \ build/ba_data/audio/agentHit1.ogg \ - build/ba_data/audio/superhero2.ogg \ - build/ba_data/audio/scoreHit01.ogg \ - build/ba_data/audio/kronk6.ogg \ - build/ba_data/audio/oldLadyHit1.ogg \ + build/ba_data/audio/agentHit2.ogg \ + build/ba_data/audio/alarm.ogg \ + build/ba_data/audio/ali1.ogg \ + build/ba_data/audio/ali2.ogg \ build/ba_data/audio/ali3.ogg \ - build/ba_data/audio/zoeEff.ogg \ + build/ba_data/audio/ali4.ogg \ + build/ba_data/audio/aliDeath.ogg \ + build/ba_data/audio/aliFall.ogg \ + build/ba_data/audio/aliHit1.ogg \ + build/ba_data/audio/aliHit2.ogg \ + build/ba_data/audio/alien1.ogg \ + build/ba_data/audio/alien2.ogg \ + build/ba_data/audio/alien3.ogg \ + build/ba_data/audio/alien4.ogg \ + build/ba_data/audio/alienDeath.ogg \ + build/ba_data/audio/alienFall.ogg \ + build/ba_data/audio/alienHit1.ogg \ + build/ba_data/audio/alienHit2.ogg \ + build/ba_data/audio/announceEight.ogg \ + build/ba_data/audio/announceFive.ogg \ + build/ba_data/audio/announceFour.ogg \ + build/ba_data/audio/announceNine.ogg \ + build/ba_data/audio/announceOne.ogg \ + build/ba_data/audio/announceSeven.ogg \ + build/ba_data/audio/announceSix.ogg \ + build/ba_data/audio/announceTen.ogg \ + build/ba_data/audio/announceThree.ogg \ + build/ba_data/audio/announceTwo.ogg \ + build/ba_data/audio/assassin1.ogg \ + build/ba_data/audio/assassin2.ogg \ + build/ba_data/audio/assassin3.ogg \ + build/ba_data/audio/assassin4.ogg \ + build/ba_data/audio/assassinDeath.ogg \ + build/ba_data/audio/assassinFall.ogg \ + build/ba_data/audio/assassinHit1.ogg \ + build/ba_data/audio/assassinHit2.ogg \ + build/ba_data/audio/bear1.ogg \ + build/ba_data/audio/bear2.ogg \ + build/ba_data/audio/bear3.ogg \ + build/ba_data/audio/bear4.ogg \ + build/ba_data/audio/bearDeath.ogg \ + build/ba_data/audio/bearFall.ogg \ + build/ba_data/audio/bearHit1.ogg \ + build/ba_data/audio/bearHit2.ogg \ + build/ba_data/audio/bellHigh.ogg \ + build/ba_data/audio/bellLow.ogg \ + build/ba_data/audio/bellMed.ogg \ + build/ba_data/audio/bigImpact.ogg \ + build/ba_data/audio/bigImpact2.ogg \ + build/ba_data/audio/blank.ogg \ + build/ba_data/audio/blip.ogg \ + build/ba_data/audio/block.ogg \ + build/ba_data/audio/bombDrop01.ogg \ + build/ba_data/audio/bombDrop02.ogg \ + build/ba_data/audio/bombRoll01.ogg \ + build/ba_data/audio/bones1.ogg \ + build/ba_data/audio/bones2.ogg \ + build/ba_data/audio/bones3.ogg \ + build/ba_data/audio/bonesDeath.ogg \ + build/ba_data/audio/bonesFall.ogg \ + build/ba_data/audio/boo.ogg \ + build/ba_data/audio/boxDrop.ogg \ + build/ba_data/audio/boxingBell.ogg \ + build/ba_data/audio/bunny1.ogg \ + build/ba_data/audio/bunny2.ogg \ + build/ba_data/audio/bunny3.ogg \ + build/ba_data/audio/bunny4.ogg \ + build/ba_data/audio/bunnyDeath.ogg \ + build/ba_data/audio/bunnyFall.ogg \ + build/ba_data/audio/bunnyHit1.ogg \ + build/ba_data/audio/bunnyHit2.ogg \ + build/ba_data/audio/bunnyJump.ogg \ + build/ba_data/audio/cashRegister.ogg \ + build/ba_data/audio/cashRegister2.ogg \ + build/ba_data/audio/charSelectMusic.ogg \ + build/ba_data/audio/cheer.ogg \ + build/ba_data/audio/click01.ogg \ + build/ba_data/audio/corkPop.ogg \ + build/ba_data/audio/cowboy1.ogg \ + build/ba_data/audio/cowboy2.ogg \ + build/ba_data/audio/cowboy3.ogg \ + build/ba_data/audio/cowboy4.ogg \ + build/ba_data/audio/cowboyDeath.ogg \ + build/ba_data/audio/cowboyFall.ogg \ + build/ba_data/audio/cowboyHit1.ogg \ + build/ba_data/audio/cowboyHit2.ogg \ + build/ba_data/audio/crowdChant.ogg \ + build/ba_data/audio/cyborg1.ogg \ + build/ba_data/audio/cyborg2.ogg \ + build/ba_data/audio/cyborg3.ogg \ + build/ba_data/audio/cyborg4.ogg \ + build/ba_data/audio/cyborgDeath.ogg \ + build/ba_data/audio/cyborgFall.ogg \ + build/ba_data/audio/cyborgHit1.ogg \ + build/ba_data/audio/cyborgHit2.ogg \ + build/ba_data/audio/cymbal.ogg \ + build/ba_data/audio/debrisFall.ogg \ + build/ba_data/audio/deek.ogg \ + build/ba_data/audio/deek2.ogg \ + build/ba_data/audio/ding.ogg \ + build/ba_data/audio/dingSmall.ogg \ + build/ba_data/audio/dingSmallHigh.ogg \ + build/ba_data/audio/dripity.ogg \ + build/ba_data/audio/drumRoll.ogg \ + build/ba_data/audio/error.ogg \ + build/ba_data/audio/explosion01.ogg \ + build/ba_data/audio/explosion02.ogg \ + build/ba_data/audio/explosion03.ogg \ + build/ba_data/audio/explosion04.ogg \ + build/ba_data/audio/explosion05.ogg \ + build/ba_data/audio/fanfare.ogg \ + build/ba_data/audio/flagCatcherMusic.ogg \ + build/ba_data/audio/flyingMusic.ogg \ + build/ba_data/audio/foghorn.ogg \ + build/ba_data/audio/footImpact01.ogg \ + build/ba_data/audio/footImpact02.ogg \ + build/ba_data/audio/footImpact03.ogg \ + build/ba_data/audio/forwardMarchMusic.ogg \ + build/ba_data/audio/freeze.ogg \ + build/ba_data/audio/frosty01.ogg \ + build/ba_data/audio/frosty02.ogg \ + build/ba_data/audio/frosty03.ogg \ + build/ba_data/audio/frosty04.ogg \ + build/ba_data/audio/frosty05.ogg \ + build/ba_data/audio/frostyDeath.ogg \ + build/ba_data/audio/frostyFall.ogg \ + build/ba_data/audio/frostyHit01.ogg \ + build/ba_data/audio/frostyHit02.ogg \ + build/ba_data/audio/frostyHit03.ogg \ + build/ba_data/audio/fuse01.ogg \ + build/ba_data/audio/gladiator1.ogg \ + build/ba_data/audio/gladiator2.ogg \ + build/ba_data/audio/gladiator3.ogg \ + build/ba_data/audio/gladiator4.ogg \ + build/ba_data/audio/gladiatorDeath.ogg \ + build/ba_data/audio/gladiatorFall.ogg \ + build/ba_data/audio/gladiatorHit1.ogg \ + build/ba_data/audio/gladiatorHit2.ogg \ + build/ba_data/audio/gong.ogg \ + build/ba_data/audio/grandRompMusic.ogg \ + build/ba_data/audio/gravelSkid.ogg \ + build/ba_data/audio/gunCocking.ogg \ + build/ba_data/audio/healthPowerup.ogg \ + build/ba_data/audio/hiss.ogg \ + build/ba_data/audio/impactHard.ogg \ + build/ba_data/audio/impactHard2.ogg \ + build/ba_data/audio/impactHard3.ogg \ + build/ba_data/audio/impactMedium.ogg \ + build/ba_data/audio/impactMedium2.ogg \ + build/ba_data/audio/jack01.ogg \ + build/ba_data/audio/jack02.ogg \ + build/ba_data/audio/jack03.ogg \ + build/ba_data/audio/jack04.ogg \ + build/ba_data/audio/jack05.ogg \ + build/ba_data/audio/jack06.ogg \ + build/ba_data/audio/jackDeath01.ogg \ + build/ba_data/audio/jackFall01.ogg \ + build/ba_data/audio/jackHit01.ogg \ + build/ba_data/audio/jackHit02.ogg \ + build/ba_data/audio/jackHit03.ogg \ + build/ba_data/audio/jackHit04.ogg \ + build/ba_data/audio/jackHit05.ogg \ + build/ba_data/audio/jackHit06.ogg \ + build/ba_data/audio/jackHit07.ogg \ + build/ba_data/audio/jumpsuit1.ogg \ + build/ba_data/audio/jumpsuit2.ogg \ + build/ba_data/audio/jumpsuit3.ogg \ + build/ba_data/audio/jumpsuit4.ogg \ + build/ba_data/audio/jumpsuitDeath.ogg \ + build/ba_data/audio/jumpsuitFall.ogg \ + build/ba_data/audio/jumpsuitHit1.ogg \ + build/ba_data/audio/jumpsuitHit2.ogg \ + build/ba_data/audio/kronk1.ogg \ + build/ba_data/audio/kronk10.ogg \ + build/ba_data/audio/kronk2.ogg \ + build/ba_data/audio/kronk3.ogg \ + build/ba_data/audio/kronk4.ogg \ + build/ba_data/audio/kronk5.ogg \ + build/ba_data/audio/kronk6.ogg \ + build/ba_data/audio/kronk7.ogg \ + build/ba_data/audio/kronk8.ogg \ + build/ba_data/audio/kronk9.ogg \ + build/ba_data/audio/kronkDeath.ogg \ + build/ba_data/audio/kronkFall.ogg \ + build/ba_data/audio/laser.ogg \ + build/ba_data/audio/laserReverse.ogg \ + build/ba_data/audio/mel01.ogg \ + build/ba_data/audio/mel02.ogg \ + build/ba_data/audio/mel03.ogg \ + build/ba_data/audio/mel04.ogg \ + build/ba_data/audio/mel05.ogg \ + build/ba_data/audio/mel06.ogg \ + build/ba_data/audio/mel07.ogg \ + build/ba_data/audio/mel08.ogg \ + build/ba_data/audio/mel09.ogg \ + build/ba_data/audio/mel10.ogg \ + build/ba_data/audio/melDeath01.ogg \ + build/ba_data/audio/melFall01.ogg \ + build/ba_data/audio/menuMusic.ogg \ + build/ba_data/audio/metalHit.ogg \ + build/ba_data/audio/metalSkid.ogg \ + build/ba_data/audio/ninjaAttack1.ogg \ + build/ba_data/audio/ninjaAttack2.ogg \ + build/ba_data/audio/ninjaAttack3.ogg \ + build/ba_data/audio/ninjaAttack4.ogg \ + build/ba_data/audio/ninjaAttack5.ogg \ + build/ba_data/audio/ninjaAttack6.ogg \ + build/ba_data/audio/ninjaAttack7.ogg \ + build/ba_data/audio/ninjaDeath1.ogg \ + build/ba_data/audio/ninjaFall1.ogg \ + build/ba_data/audio/ninjaHit1.ogg \ + build/ba_data/audio/ninjaHit2.ogg \ + build/ba_data/audio/ninjaHit3.ogg \ + build/ba_data/audio/ninjaHit4.ogg \ + build/ba_data/audio/ninjaHit5.ogg \ + build/ba_data/audio/ninjaHit6.ogg \ + build/ba_data/audio/ninjaHit7.ogg \ + build/ba_data/audio/ninjaHit8.ogg \ + build/ba_data/audio/oldLady1.ogg \ + build/ba_data/audio/oldLady2.ogg \ + build/ba_data/audio/oldLady3.ogg \ + build/ba_data/audio/oldLady4.ogg \ + build/ba_data/audio/oldLadyDeath.ogg \ + build/ba_data/audio/oldLadyFall.ogg \ + build/ba_data/audio/oldLadyHit1.ogg \ + build/ba_data/audio/oldLadyHit2.ogg \ + build/ba_data/audio/ooh.ogg \ + build/ba_data/audio/operaSinger1.ogg \ + build/ba_data/audio/operaSinger2.ogg \ + build/ba_data/audio/operaSinger3.ogg \ + build/ba_data/audio/operaSinger4.ogg \ + build/ba_data/audio/operaSingerDeath.ogg \ + build/ba_data/audio/operaSingerFall.ogg \ + build/ba_data/audio/operaSingerHit1.ogg \ + build/ba_data/audio/operaSingerHit2.ogg \ + build/ba_data/audio/orchestraHit.ogg \ + build/ba_data/audio/orchestraHit2.ogg \ + build/ba_data/audio/orchestraHit3.ogg \ + build/ba_data/audio/orchestraHit4.ogg \ + build/ba_data/audio/orchestraHitBig1.ogg \ + build/ba_data/audio/orchestraHitBig2.ogg \ + build/ba_data/audio/penguin1.ogg \ + build/ba_data/audio/penguin2.ogg \ + build/ba_data/audio/penguin3.ogg \ + build/ba_data/audio/penguin4.ogg \ + build/ba_data/audio/penguinDeath.ogg \ + build/ba_data/audio/penguinFall.ogg \ + build/ba_data/audio/penguinHit1.ogg \ + build/ba_data/audio/penguinHit2.ogg \ + build/ba_data/audio/pixie1.ogg \ + build/ba_data/audio/pixie2.ogg \ + build/ba_data/audio/pixie3.ogg \ + build/ba_data/audio/pixie4.ogg \ + build/ba_data/audio/pixieDeath.ogg \ + build/ba_data/audio/pixieFall.ogg \ + build/ba_data/audio/pixieHit1.ogg \ + build/ba_data/audio/pixieHit2.ogg \ + build/ba_data/audio/playerDeath.ogg \ + build/ba_data/audio/playerLeft.ogg \ + build/ba_data/audio/pop01.ogg \ + build/ba_data/audio/powerdown01.ogg \ + build/ba_data/audio/powerup01.ogg \ + build/ba_data/audio/punch01.ogg \ + build/ba_data/audio/punchStrong01.ogg \ + build/ba_data/audio/punchStrong02.ogg \ + build/ba_data/audio/punchSwish.ogg \ + build/ba_data/audio/punchWeak01.ogg \ + build/ba_data/audio/raceBeep1.ogg \ + build/ba_data/audio/raceBeep2.ogg \ + build/ba_data/audio/refWhistle.ogg \ + build/ba_data/audio/robot1.ogg \ + build/ba_data/audio/robot2.ogg \ + build/ba_data/audio/robot3.ogg \ + build/ba_data/audio/robot4.ogg \ + build/ba_data/audio/robotDeath.ogg \ + build/ba_data/audio/robotFall.ogg \ + build/ba_data/audio/robotHit1.ogg \ + build/ba_data/audio/robotHit2.ogg \ + build/ba_data/audio/runAwayMusic.ogg \ + build/ba_data/audio/santa01.ogg \ + build/ba_data/audio/santa02.ogg \ + build/ba_data/audio/santa03.ogg \ + build/ba_data/audio/santa04.ogg \ + build/ba_data/audio/santa05.ogg \ + build/ba_data/audio/santaDeath.ogg \ + build/ba_data/audio/santaFall.ogg \ + build/ba_data/audio/santaHit01.ogg \ + build/ba_data/audio/santaHit02.ogg \ + build/ba_data/audio/santaHit03.ogg \ + build/ba_data/audio/santaHit04.ogg \ + build/ba_data/audio/scamper01.ogg \ + build/ba_data/audio/scaryMusic.ogg \ + build/ba_data/audio/score.ogg \ + build/ba_data/audio/scoreHit01.ogg \ + build/ba_data/audio/scoreHit02.ogg \ + build/ba_data/audio/scoreIncrease.ogg \ + build/ba_data/audio/scoresEpicMusic.ogg \ + build/ba_data/audio/shatter.ogg \ + build/ba_data/audio/shieldDown.ogg \ + build/ba_data/audio/shieldHit.ogg \ + build/ba_data/audio/shieldUp.ogg \ + build/ba_data/audio/skid01.ogg \ + build/ba_data/audio/slowEpicMusic.ogg \ + build/ba_data/audio/sparkle01.ogg \ + build/ba_data/audio/sparkle02.ogg \ + build/ba_data/audio/sparkle03.ogg \ + build/ba_data/audio/spawn.ogg \ + build/ba_data/audio/spazAttack01.ogg \ + build/ba_data/audio/spazAttack02.ogg \ + build/ba_data/audio/spazAttack03.ogg \ + build/ba_data/audio/spazAttack04.ogg \ + build/ba_data/audio/spazDeath01.ogg \ + build/ba_data/audio/spazEff.ogg \ + build/ba_data/audio/spazFall01.ogg \ + build/ba_data/audio/spazImpact01.ogg \ + build/ba_data/audio/spazImpact02.ogg \ + build/ba_data/audio/spazImpact03.ogg \ + build/ba_data/audio/spazImpact04.ogg \ + build/ba_data/audio/spazJump01.ogg \ + build/ba_data/audio/spazJump02.ogg \ + build/ba_data/audio/spazJump03.ogg \ + build/ba_data/audio/spazJump04.ogg \ + build/ba_data/audio/spazOw.ogg \ + build/ba_data/audio/spazPickup01.ogg \ + build/ba_data/audio/spazScream01.ogg \ + build/ba_data/audio/splatter.ogg \ + build/ba_data/audio/sportsMusic.ogg \ + build/ba_data/audio/stickyImpact.ogg \ + build/ba_data/audio/superPunch.ogg \ + build/ba_data/audio/superhero1.ogg \ + build/ba_data/audio/superhero2.ogg \ + build/ba_data/audio/superhero3.ogg \ + build/ba_data/audio/superhero4.ogg \ + build/ba_data/audio/superheroDeath.ogg \ + build/ba_data/audio/superheroFall.ogg \ + build/ba_data/audio/superheroHit1.ogg \ + build/ba_data/audio/superheroHit2.ogg \ + build/ba_data/audio/survivalMusic.ogg \ + build/ba_data/audio/swip.ogg \ build/ba_data/audio/swip2.ogg \ build/ba_data/audio/swish.ogg \ - build/ba_data/audio/kronk2.ogg \ - build/ba_data/audio/witchHit2.ogg \ - build/ba_data/audio/penguinHit2.ogg \ - build/ba_data/audio/agent2.ogg \ - build/ba_data/audio/dingSmallHigh.ogg \ - build/ba_data/audio/santaDeath.ogg \ - build/ba_data/audio/alienFall.ogg \ - build/ba_data/audio/jackHit06.ogg \ - build/ba_data/audio/alien1.ogg \ - build/ba_data/audio/spazScream01.ogg \ - build/ba_data/audio/spazImpact02.ogg \ - build/ba_data/audio/wizard3.ogg \ - build/ba_data/audio/spazFall01.ogg \ - build/ba_data/audio/wizard2.ogg \ - build/ba_data/audio/spazImpact03.ogg \ - build/ba_data/audio/scoreIncrease.ogg \ - build/ba_data/audio/jackHit07.ogg \ - build/ba_data/audio/bunnyHit2.ogg \ - build/ba_data/audio/ninjaFall1.ogg \ - build/ba_data/audio/orchestraHit.ogg \ - build/ba_data/audio/agent3.ogg \ - build/ba_data/audio/melFall01.ogg \ - build/ba_data/audio/playerDeath.ogg \ - build/ba_data/audio/alienHit1.ogg \ - build/ba_data/audio/kronk3.ogg \ - build/ba_data/audio/operaSingerDeath.ogg \ - build/ba_data/audio/witchHit1.ogg \ - build/ba_data/audio/kronk1.ogg \ - build/ba_data/audio/bunnyFall.ogg \ - build/ba_data/audio/ali4.ogg \ - build/ba_data/audio/penguinHit1.ogg \ - build/ba_data/audio/superPunch.ogg \ - build/ba_data/audio/agent1.ogg \ - build/ba_data/audio/ooh.ogg \ - build/ba_data/audio/alien2.ogg \ - build/ba_data/audio/jackHit05.ogg \ - build/ba_data/audio/fuse01.ogg \ - build/ba_data/audio/spazImpact01.ogg \ - build/ba_data/audio/flagCatcherMusic.ogg \ - build/ba_data/audio/foghorn.ogg \ - build/ba_data/audio/wizard1.ogg \ - build/ba_data/audio/announceThree.ogg \ - build/ba_data/audio/jackHit04.ogg \ - build/ba_data/audio/alien3.ogg \ - build/ba_data/audio/shieldDown.ogg \ - build/ba_data/audio/penguinFall.ogg \ - build/ba_data/audio/kronkDeath.ogg \ - build/ba_data/audio/witchFall.ogg \ - build/ba_data/audio/spazOw.ogg \ - build/ba_data/audio/bunnyHit1.ogg \ - build/ba_data/audio/superhero4.ogg \ - build/ba_data/audio/punchWeak01.ogg \ - build/ba_data/audio/alienHit2.ogg \ - build/ba_data/audio/deek2.ogg \ - build/ba_data/audio/actionHeroHit2.ogg \ - build/ba_data/audio/pixie3.ogg \ - build/ba_data/audio/ninjaHit2.ogg \ - build/ba_data/audio/warriorDeath.ogg \ - build/ba_data/audio/jumpsuitDeath.ogg \ - build/ba_data/audio/bearDeath.ogg \ - build/ba_data/audio/actionHeroDeath.ogg \ - build/ba_data/audio/oldLady4.ogg \ - build/ba_data/audio/frosty01.ogg \ - build/ba_data/audio/gladiatorHit1.ogg \ - build/ba_data/audio/pixieDeath.ogg \ - build/ba_data/audio/healthPowerup.ogg \ - build/ba_data/audio/impactMedium.ogg \ - build/ba_data/audio/jackDeath01.ogg \ - build/ba_data/audio/zoeImpact01.ogg \ - build/ba_data/audio/forwardMarchMusic.ogg \ - build/ba_data/audio/woodDebrisFall.ogg \ - build/ba_data/audio/ninjaHit3.ogg \ - build/ba_data/audio/pixieHit2.ogg \ - build/ba_data/audio/splatter.ogg \ - build/ba_data/audio/gladiatorFall.ogg \ + build/ba_data/audio/swish2.ogg \ + build/ba_data/audio/swish3.ogg \ + build/ba_data/audio/tap.ogg \ + build/ba_data/audio/technoHit01.ogg \ build/ba_data/audio/tick.ogg \ - build/ba_data/audio/pixie2.ogg \ - build/ba_data/audio/actionHeroHit1.ogg \ - build/ba_data/audio/swip.ogg \ - build/ba_data/audio/ninjaHit1.ogg \ - build/ba_data/audio/zoeImpact03.ogg \ - build/ba_data/audio/zoeFall01.ogg \ - build/ba_data/audio/frosty02.ogg \ - build/ba_data/audio/gladiatorHit2.ogg \ - build/ba_data/audio/pixieFall.ogg \ - build/ba_data/audio/zoeScream01.ogg \ - build/ba_data/audio/frosty03.ogg \ - build/ba_data/audio/actionHeroFall.ogg \ - build/ba_data/audio/menuMusic.ogg \ - build/ba_data/audio/zoeImpact02.ogg \ - build/ba_data/audio/penguin4.ogg \ - build/ba_data/audio/runAwayMusic.ogg \ - build/ba_data/audio/pixieHit1.ogg \ - build/ba_data/audio/pixie1.ogg \ - build/ba_data/audio/metalHit.ogg \ - build/ba_data/audio/hiss.ogg \ - build/ba_data/audio/ninjaHit4.ogg \ - build/ba_data/audio/bunnyJump.ogg \ - build/ba_data/audio/cowboyDeath.ogg \ - build/ba_data/audio/oldLady2.ogg \ - build/ba_data/audio/mel09.ogg \ - build/ba_data/audio/announceSix.ogg \ - build/ba_data/audio/raceBeep2.ogg \ - build/ba_data/audio/announceTwo.ogg \ - build/ba_data/audio/mel08.ogg \ - build/ba_data/audio/oldLady3.ogg \ - build/ba_data/audio/punch01.ogg \ - build/ba_data/audio/penguin1.ogg \ - build/ba_data/audio/orchestraHitBig2.ogg \ - build/ba_data/audio/robotHit2.ogg \ - build/ba_data/audio/ninjaHit5.ogg \ - build/ba_data/audio/pixie4.ogg \ - build/ba_data/audio/operaSingerHit2.ogg \ - build/ba_data/audio/cyborgDeath.ogg \ - build/ba_data/audio/ninjaHit7.ogg \ - build/ba_data/audio/survivalMusic.ogg \ - build/ba_data/audio/penguin3.ogg \ - build/ba_data/audio/oldLady1.ogg \ - build/ba_data/audio/agentDeath.ogg \ - build/ba_data/audio/cashRegister2.ogg \ - build/ba_data/audio/frosty04.ogg \ - build/ba_data/audio/operaSingerFall.ogg \ - build/ba_data/audio/robotFall.ogg \ - build/ba_data/audio/scaryMusic.ogg \ - build/ba_data/audio/raceBeep1.ogg \ - build/ba_data/audio/frosty05.ogg \ - build/ba_data/audio/penguin2.ogg \ - build/ba_data/audio/zoeImpact04.ogg \ - build/ba_data/audio/orchestraHitBig1.ogg \ - build/ba_data/audio/robotHit1.ogg \ - build/ba_data/audio/ninjaHit6.ogg \ - build/ba_data/audio/gong.ogg \ - build/ba_data/audio/operaSingerHit1.ogg \ - build/ba_data/audio/shieldUp.ogg \ - build/ba_data/audio/charSelectMusic.ogg \ - build/ba_data/audio/cyborg2.ogg \ - build/ba_data/audio/santa05.ogg \ - build/ba_data/audio/bones1.ogg \ - build/ba_data/audio/shatter.ogg \ - build/ba_data/audio/kronkFall.ogg \ - build/ba_data/audio/impactHard.ogg \ - build/ba_data/audio/bombRoll01.ogg \ - build/ba_data/audio/explosion05.ogg \ - build/ba_data/audio/announceEight.ogg \ - build/ba_data/audio/superheroFall.ogg \ - build/ba_data/audio/mel06.ogg \ - build/ba_data/audio/santaHit01.ogg \ - build/ba_data/audio/cyborgHit2.ogg \ - build/ba_data/audio/bonesDeath.ogg \ - build/ba_data/audio/deek.ogg \ - build/ba_data/audio/mel07.ogg \ - build/ba_data/audio/gladiator4.ogg \ - build/ba_data/audio/explosion04.ogg \ - build/ba_data/audio/wrestler1.ogg \ - build/ba_data/audio/spazJump01.ogg \ - build/ba_data/audio/santaFall.ogg \ - build/ba_data/audio/superheroHit1.ogg \ - build/ba_data/audio/punchSwish.ogg \ - build/ba_data/audio/santa04.ogg \ - build/ba_data/audio/cyborg3.ogg \ - build/ba_data/audio/zoePickup01.ogg \ - build/ba_data/audio/cyborg1.ogg \ - build/ba_data/audio/spazAttack04.ogg \ - build/ba_data/audio/bigImpact2.ogg \ - build/ba_data/audio/bones2.ogg \ - build/ba_data/audio/ninjaHit8.ogg \ - build/ba_data/audio/announceNine.ogg \ - build/ba_data/audio/spazJump03.ogg \ - build/ba_data/audio/wrestler3.ogg \ - build/ba_data/audio/bunnyDeath.ogg \ - build/ba_data/audio/mel05.ogg \ - build/ba_data/audio/santaHit02.ogg \ - build/ba_data/audio/cyborgHit1.ogg \ - build/ba_data/audio/bear4.ogg \ - build/ba_data/audio/gunCocking.ogg \ - build/ba_data/audio/spawn.ogg \ - build/ba_data/audio/powerdown01.ogg \ - build/ba_data/audio/santaHit03.ogg \ - build/ba_data/audio/assassin4.ogg \ - build/ba_data/audio/mel04.ogg \ - build/ba_data/audio/mel10.ogg \ - build/ba_data/audio/cyborgFall.ogg \ - build/ba_data/audio/wrestler2.ogg \ - build/ba_data/audio/spazJump02.ogg \ - build/ba_data/audio/bones3.ogg \ - build/ba_data/audio/superheroHit2.ogg \ - build/ba_data/audio/bellMed.ogg \ - build/ba_data/audio/santa03.ogg \ - build/ba_data/audio/cyborg4.ogg \ - build/ba_data/audio/powerup01.ogg \ - build/ba_data/audio/robotDeath.ogg \ - build/ba_data/audio/flyingMusic.ogg \ - build/ba_data/audio/shieldHit.ogg \ - build/ba_data/audio/spazAttack01.ogg \ - build/ba_data/audio/sparkle02.ogg \ - build/ba_data/audio/cowboyHit1.ogg \ - build/ba_data/audio/cashRegister.ogg \ - build/ba_data/audio/explosion03.ogg \ - build/ba_data/audio/announceOne.ogg \ - build/ba_data/audio/gladiator3.ogg \ - build/ba_data/audio/impactMedium2.ogg \ - build/ba_data/audio/bear1.ogg \ - build/ba_data/audio/wrestlerDeath.ogg \ - build/ba_data/audio/pop01.ogg \ - build/ba_data/audio/frostyHit01.ogg \ - build/ba_data/audio/cowboyFall.ogg \ - build/ba_data/audio/assassin1.ogg \ - build/ba_data/audio/gladiator2.ogg \ - build/ba_data/audio/mel01.ogg \ - build/ba_data/audio/warriorHit2.ogg \ - build/ba_data/audio/explosion02.ogg \ - build/ba_data/audio/blip.ogg \ - build/ba_data/audio/sparkle03.ogg \ - build/ba_data/audio/bigImpact.ogg \ - build/ba_data/audio/santa02.ogg \ - build/ba_data/audio/boo.ogg \ - build/ba_data/audio/sparkle01.ogg \ - build/ba_data/audio/spazAttack02.ogg \ - build/ba_data/audio/warriorFall.ogg \ - build/ba_data/audio/cymbal.ogg \ - build/ba_data/audio/cowboyHit2.ogg \ - build/ba_data/audio/slowEpicMusic.ogg \ - build/ba_data/audio/laserReverse.ogg \ - build/ba_data/audio/mel03.ogg \ - build/ba_data/audio/bellLow.ogg \ - build/ba_data/audio/bear2.ogg \ - build/ba_data/audio/santaHit04.ogg \ - build/ba_data/audio/assassin3.ogg \ - build/ba_data/audio/zoeOw.ogg \ - build/ba_data/audio/frostyHit03.ogg \ - build/ba_data/audio/frostyHit02.ogg \ - build/ba_data/audio/victoryMusic.ogg \ - build/ba_data/audio/assassin2.ogg \ - build/ba_data/audio/bear3.ogg \ - build/ba_data/audio/gladiator1.ogg \ - build/ba_data/audio/mel02.ogg \ - build/ba_data/audio/warriorHit1.ogg \ - build/ba_data/audio/explosion01.ogg \ - build/ba_data/audio/boxDrop.ogg \ - build/ba_data/audio/wrestler4.ogg \ - build/ba_data/audio/wizardDeath.ogg \ - build/ba_data/audio/spazJump04.ogg \ - build/ba_data/audio/oldLadyDeath.ogg \ - build/ba_data/audio/zoeDeath01.ogg \ - build/ba_data/audio/spazAttack03.ogg \ - build/ba_data/audio/bellHigh.ogg \ - build/ba_data/audio/santa01.ogg \ - build/ba_data/audio/cowboy1.ogg \ - build/ba_data/audio/jack04.ogg \ - build/ba_data/audio/toTheDeathMusic.ogg \ - build/ba_data/audio/jumpsuit3.ogg \ - build/ba_data/audio/ninjaAttack7.ogg \ - build/ba_data/audio/actionHero3.ogg \ - build/ba_data/audio/warrior1.ogg \ - build/ba_data/audio/alienDeath.ogg \ - build/ba_data/audio/zoeAttack03.ogg \ - build/ba_data/audio/orchestraHit3.ogg \ - build/ba_data/audio/bunny4.ogg \ - build/ba_data/audio/boxingBell.ogg \ - build/ba_data/audio/assassinHit2.ogg \ - build/ba_data/audio/operaSinger4.ogg \ - build/ba_data/audio/error.ogg \ - build/ba_data/audio/click01.ogg \ - build/ba_data/audio/achievement.ogg \ - build/ba_data/audio/playerLeft.ogg \ - build/ba_data/audio/aliHit2.ogg \ - build/ba_data/audio/footImpact01.ogg \ - build/ba_data/audio/spazDeath01.ogg \ - build/ba_data/audio/dripity.ogg \ - build/ba_data/audio/stickyImpact.ogg \ - build/ba_data/audio/debrisFall.ogg \ - build/ba_data/audio/orchestraHit2.ogg \ - build/ba_data/audio/zoeAttack02.ogg \ - build/ba_data/audio/actionHero2.ogg \ - build/ba_data/audio/score.ogg \ - build/ba_data/audio/ninjaAttack6.ogg \ - build/ba_data/audio/witch1.ogg \ - build/ba_data/audio/punchStrong02.ogg \ - build/ba_data/audio/wizardHit2.ogg \ - build/ba_data/audio/robot1.ogg \ - build/ba_data/audio/jumpsuit2.ogg \ - build/ba_data/audio/jack05.ogg \ - build/ba_data/audio/superheroDeath.ogg \ - build/ba_data/audio/cowboy2.ogg \ - build/ba_data/audio/drumRoll.ogg \ - build/ba_data/audio/robot3.ogg \ - build/ba_data/audio/ninjaAttack4.ogg \ - build/ba_data/audio/alarm.ogg \ - build/ba_data/audio/witch3.ogg \ - build/ba_data/audio/warrior2.ogg \ - build/ba_data/audio/impactHard3.ogg \ - build/ba_data/audio/aliFall.ogg \ - build/ba_data/audio/spazEff.ogg \ - build/ba_data/audio/wizardFall.ogg \ - build/ba_data/audio/block.ogg \ - build/ba_data/audio/assassinHit1.ogg \ - build/ba_data/audio/footImpact03.ogg \ - build/ba_data/audio/trashRummage.ogg \ - build/ba_data/audio/footImpact02.ogg \ - build/ba_data/audio/aliHit1.ogg \ - build/ba_data/audio/ninjaDeath1.ogg \ - build/ba_data/audio/announceFive.ogg \ - build/ba_data/audio/zoeAttack01.ogg \ - build/ba_data/audio/actionHero1.ogg \ - build/ba_data/audio/impactHard2.ogg \ - build/ba_data/audio/warrior3.ogg \ - build/ba_data/audio/melDeath01.ogg \ - build/ba_data/audio/witch2.ogg \ - build/ba_data/audio/assassinFall.ogg \ - build/ba_data/audio/punchStrong01.ogg \ - build/ba_data/audio/ninjaAttack5.ogg \ - build/ba_data/audio/wizardHit1.ogg \ - build/ba_data/audio/robot2.ogg \ - build/ba_data/audio/announceSeven.ogg \ - build/ba_data/audio/jack06.ogg \ - build/ba_data/audio/cowboy3.ogg \ - build/ba_data/audio/jumpsuit1.ogg \ - build/ba_data/audio/bombDrop01.ogg \ - build/ba_data/audio/zoeJump03.ogg \ - build/ba_data/audio/warnBeeps.ogg \ - build/ba_data/audio/jack02.ogg \ - build/ba_data/audio/ninjaAttack1.ogg \ - build/ba_data/audio/bunny2.ogg \ - build/ba_data/audio/gladiatorDeath.ogg \ - build/ba_data/audio/operaSinger2.ogg \ - build/ba_data/audio/fanfare.ogg \ - build/ba_data/audio/wrestlerHit1.ogg \ + build/ba_data/audio/ticking.ogg \ build/ba_data/audio/tickingCrazy.ogg \ - build/ba_data/audio/metalSkid.ogg \ - build/ba_data/audio/operaSinger3.ogg \ - build/ba_data/audio/actionHero4.ogg \ - build/ba_data/audio/zoeAttack04.ogg \ - build/ba_data/audio/orchestraHit4.ogg \ - build/ba_data/audio/bunny3.ogg \ - build/ba_data/audio/spazPickup01.ogg \ - build/ba_data/audio/wrestlerFall.ogg \ - build/ba_data/audio/cheer.ogg \ - build/ba_data/audio/zoeJump02.ogg \ - build/ba_data/audio/jack03.ogg \ - build/ba_data/audio/jumpsuit4.ogg \ - build/ba_data/audio/bombDrop02.ogg \ - build/ba_data/audio/cowboy4.ogg \ - build/ba_data/audio/jack01.ogg \ - build/ba_data/audio/grandRompMusic.ogg \ - build/ba_data/audio/ninjaAttack2.ogg \ - build/ba_data/audio/kronk8.ogg \ - build/ba_data/audio/bunny1.ogg \ + build/ba_data/audio/toTheDeathMusic.ogg \ + build/ba_data/audio/trashRummage.ogg \ + build/ba_data/audio/victoryMusic.ogg \ + build/ba_data/audio/warnBeep.ogg \ + build/ba_data/audio/warnBeeps.ogg \ + build/ba_data/audio/warrior1.ogg \ + build/ba_data/audio/warrior2.ogg \ + build/ba_data/audio/warrior3.ogg \ build/ba_data/audio/warrior4.ogg \ - build/ba_data/audio/ding.ogg \ - build/ba_data/audio/operaSinger1.ogg \ - build/ba_data/audio/wrestlerHit2.ogg \ - build/ba_data/audio/bonesFall.ogg \ - build/ba_data/audio/scoresEpicMusic.ogg \ - build/ba_data/audio/sportsMusic.ogg \ - build/ba_data/audio/witchDeath.ogg \ - build/ba_data/audio/kronk9.ogg \ - build/ba_data/audio/ninjaAttack3.ogg \ - build/ba_data/audio/assassinDeath.ogg \ + build/ba_data/audio/warriorDeath.ogg \ + build/ba_data/audio/warriorFall.ogg \ + build/ba_data/audio/warriorHit1.ogg \ + build/ba_data/audio/warriorHit2.ogg \ + build/ba_data/audio/whenJohnnyComesMarchingHomeMusic.ogg \ + build/ba_data/audio/witch1.ogg \ + build/ba_data/audio/witch2.ogg \ + build/ba_data/audio/witch3.ogg \ build/ba_data/audio/witch4.ogg \ + build/ba_data/audio/witchDeath.ogg \ + build/ba_data/audio/witchFall.ogg \ + build/ba_data/audio/witchHit1.ogg \ + build/ba_data/audio/witchHit2.ogg \ + build/ba_data/audio/wizard1.ogg \ + build/ba_data/audio/wizard2.ogg \ + build/ba_data/audio/wizard3.ogg \ + build/ba_data/audio/wizard4.ogg \ + build/ba_data/audio/wizardDeath.ogg \ + build/ba_data/audio/wizardFall.ogg \ + build/ba_data/audio/wizardHit1.ogg \ + build/ba_data/audio/wizardHit2.ogg \ + build/ba_data/audio/woodDebrisFall.ogg \ + build/ba_data/audio/wrestler1.ogg \ + build/ba_data/audio/wrestler2.ogg \ + build/ba_data/audio/wrestler3.ogg \ + build/ba_data/audio/wrestler4.ogg \ + build/ba_data/audio/wrestlerDeath.ogg \ + build/ba_data/audio/wrestlerFall.ogg \ + build/ba_data/audio/wrestlerHit1.ogg \ + build/ba_data/audio/wrestlerHit2.ogg \ + build/ba_data/audio/zoeAttack01.ogg \ + build/ba_data/audio/zoeAttack02.ogg \ + build/ba_data/audio/zoeAttack03.ogg \ + build/ba_data/audio/zoeAttack04.ogg \ + build/ba_data/audio/zoeDeath01.ogg \ + build/ba_data/audio/zoeEff.ogg \ + build/ba_data/audio/zoeFall01.ogg \ + build/ba_data/audio/zoeImpact01.ogg \ + build/ba_data/audio/zoeImpact02.ogg \ + build/ba_data/audio/zoeImpact03.ogg \ + build/ba_data/audio/zoeImpact04.ogg \ build/ba_data/audio/zoeJump01.ogg \ - build/ba_data/audio/robot4.ogg \ - build/ba_data/audio/gravelSkid.ogg + build/ba_data/audio/zoeJump02.ogg \ + build/ba_data/audio/zoeJump03.ogg \ + build/ba_data/audio/zoeOw.ogg \ + build/ba_data/audio/zoePickup01.ogg \ + build/ba_data/audio/zoeScream01.ogg TEX2D_DDS_TARGETS = \ - build/ba_data/textures/cyborgIconColorMask.dds \ - build/ba_data/textures/chestOpenIcon.dds \ - build/ba_data/textures/analogStick.dds \ - build/ba_data/textures/circleOutline.dds \ - build/ba_data/textures/white.dds \ - build/ba_data/textures/medalBronze.dds \ - build/ba_data/textures/slash.dds \ - build/ba_data/textures/arrow.dds \ - build/ba_data/textures/ouyaIcon.dds \ - build/ba_data/textures/eyeColor.dds \ - build/ba_data/textures/achievementMedalLarge.dds \ - build/ba_data/textures/cowboyIconColorMask.dds \ - build/ba_data/textures/wings.dds \ - build/ba_data/textures/roundaboutPreview.dds \ - build/ba_data/textures/warriorIcon.dds \ - build/ba_data/textures/windowHSmallVMed.dds \ - build/ba_data/textures/ninjaIconColorMask.dds \ - build/ba_data/textures/reflectionSharpest_+z.dds \ - build/ba_data/textures/stepRightUpLevelColor.dds \ - build/ba_data/textures/fontSmall5.dds \ - build/ba_data/textures/bombButton.dds \ - build/ba_data/textures/aliIconColorMask.dds \ - build/ba_data/textures/chTitleChar2.dds \ - build/ba_data/textures/achievementOnslaught.dds \ - build/ba_data/textures/smoke.dds \ - build/ba_data/textures/lakeFrigidReflections.dds \ - build/ba_data/textures/bunnyColor.dds \ - build/ba_data/textures/leftButton.dds \ - build/ba_data/textures/hockeyStadium.dds \ - build/ba_data/textures/cowboyIcon.dds \ - build/ba_data/textures/lakeFrigid.dds \ - build/ba_data/textures/startButton.dds \ - build/ba_data/textures/footballStadium.dds \ - build/ba_data/textures/crossOutMask.dds \ - build/ba_data/textures/bonesIconColorMask.dds \ - build/ba_data/textures/operaSingerIconColorMask.dds \ - build/ba_data/textures/lakeFrigidPreview.dds \ - build/ba_data/textures/alienIcon.dds \ - build/ba_data/textures/oldLadyColor.dds \ - build/ba_data/textures/ouyaAButton.dds \ - build/ba_data/textures/eggTex3.dds \ - build/ba_data/textures/cyborgIcon.dds \ - build/ba_data/textures/actionHeroColor.dds \ - build/ba_data/textures/achievementTeamPlayer.dds \ - build/ba_data/textures/reflectionSoft_+x.dds \ - build/ba_data/textures/fontExtras3.dds \ - build/ba_data/textures/buttonBomb.dds \ - build/ba_data/textures/star.dds \ - build/ba_data/textures/reflectionSharpest_-y.dds \ - build/ba_data/textures/achievementSharingIsCaring.dds \ - build/ba_data/textures/fontSmall3.dds \ - build/ba_data/textures/powerupSpeed.dds \ - build/ba_data/textures/vrFillMound.dds \ - build/ba_data/textures/agentIconColorMask.dds \ - build/ba_data/textures/kronkIcon.dds \ - build/ba_data/textures/oldLadyIcon.dds \ - build/ba_data/textures/chTitleChar4.dds \ - build/ba_data/textures/nextLevelIcon.dds \ - build/ba_data/textures/gameCircleIcon.dds \ - build/ba_data/textures/bonesIcon.dds \ - build/ba_data/textures/bearIcon.dds \ - build/ba_data/textures/towerDPreview.dds \ - build/ba_data/textures/achievementTNT.dds \ - build/ba_data/textures/medalGold.dds \ - build/ba_data/textures/circleZigZag.dds \ - build/ba_data/textures/bunnyColorMask.dds \ - build/ba_data/textures/black.dds \ - build/ba_data/textures/menuIcon.dds \ - build/ba_data/textures/file.dds \ - build/ba_data/textures/logIcon.dds \ - build/ba_data/textures/controllerIcon.dds \ - build/ba_data/textures/reflectionSharper_-y.dds \ - build/ba_data/textures/operaSingerColorMask.dds \ - build/ba_data/textures/achievementFootballShutout.dds \ - build/ba_data/textures/reflectionPowerup_-x.dds \ - build/ba_data/textures/achievementsIcon.dds \ - build/ba_data/textures/cowboyColor.dds \ - build/ba_data/textures/wrestlerIconColorMask.dds \ - build/ba_data/textures/googlePlayAchievementsIcon.dds \ - build/ba_data/textures/alienIconColorMask.dds \ - build/ba_data/textures/ticketRollBig.dds \ - build/ba_data/textures/wrestlerIcon.dds \ - build/ba_data/textures/egg1.dds \ - build/ba_data/textures/gameCenterIcon.dds \ - build/ba_data/textures/landMineLit.dds \ - build/ba_data/textures/achievementWall.dds \ - build/ba_data/textures/achievementMedalMedium.dds \ - build/ba_data/textures/reflectionChar_-x.dds \ - build/ba_data/textures/softRectVertical.dds \ - build/ba_data/textures/reflectionSharper_+z.dds \ - build/ba_data/textures/wizardIcon.dds \ - build/ba_data/textures/mapPreviewMask.dds \ - build/ba_data/textures/nub.dds \ - build/ba_data/textures/empty.dds \ - build/ba_data/textures/frostyIconColorMask.dds \ - build/ba_data/textures/reflectionSharp_-x.dds \ - build/ba_data/textures/bombColorIce.dds \ - build/ba_data/textures/jumpsuitIcon.dds \ - build/ba_data/textures/footballStadiumPreview.dds \ - build/ba_data/textures/pixieIconColorMask.dds \ - build/ba_data/textures/achievementEmpty.dds \ - build/ba_data/textures/wrestlerColor.dds \ - build/ba_data/textures/shield.dds \ - build/ba_data/textures/iconOnslaught.dds \ - build/ba_data/textures/replayIcon.dds \ - build/ba_data/textures/powerupHealth.dds \ - build/ba_data/textures/bg.dds \ - build/ba_data/textures/chTitleChar3.dds \ - build/ba_data/textures/textClearButton.dds \ - build/ba_data/textures/reflectionSoft_-z.dds \ - build/ba_data/textures/fontSmall4.dds \ - build/ba_data/textures/warriorColor.dds \ - build/ba_data/textures/light.dds \ - build/ba_data/textures/santaColor.dds \ - build/ba_data/textures/jackColor.dds \ - build/ba_data/textures/aliSplash.dds \ - build/ba_data/textures/scorch.dds \ - build/ba_data/textures/zoeIcon.dds \ - build/ba_data/textures/bonesColorMask.dds \ - build/ba_data/textures/pixieColor.dds \ - build/ba_data/textures/actionHeroIconColorMask.dds \ - build/ba_data/textures/treesColor.dds \ - build/ba_data/textures/neoSpazColorMask.dds \ - build/ba_data/textures/superheroIcon.dds \ - build/ba_data/textures/achievementOffYouGo.dds \ - build/ba_data/textures/tipTopBGColor.dds \ - build/ba_data/textures/robotColor.dds \ - build/ba_data/textures/reflectionSharpest_-x.dds \ - build/ba_data/textures/menuButton.dds \ - build/ba_data/textures/powerupStickyBombs.dds \ - build/ba_data/textures/ninjaIcon.dds \ - build/ba_data/textures/witchColorMask.dds \ - build/ba_data/textures/cowboyColorMask.dds \ - build/ba_data/textures/operaSingerIcon.dds \ build/ba_data/textures/achievementBoxer.dds \ - build/ba_data/textures/eggTex2.dds \ - build/ba_data/textures/rampageBGColor.dds \ - build/ba_data/textures/fontExtras2.dds \ - build/ba_data/textures/rampageLevelColor.dds \ - build/ba_data/textures/reflectionSoft_+y.dds \ - build/ba_data/textures/ticketRolls.dds \ - build/ba_data/textures/natureBackgroundColor.dds \ - build/ba_data/textures/santaIconColorMask.dds \ - build/ba_data/textures/reflectionPowerup_+z.dds \ - build/ba_data/textures/characterIconMask.dds \ - build/ba_data/textures/aliColor.dds \ - build/ba_data/textures/ninjaColorMask.dds \ - build/ba_data/textures/buttonPickUp.dds \ - build/ba_data/textures/chTitleChar5.dds \ - build/ba_data/textures/bigGPreview.dds \ - build/ba_data/textures/hockeyStadiumPreview.dds \ - build/ba_data/textures/achievementMedalSmall.dds \ - build/ba_data/textures/fontSmall2.dds \ - build/ba_data/textures/achievementOutline.dds \ - build/ba_data/textures/levelIcon.dds \ - build/ba_data/textures/googlePlayGamesIcon.dds \ - build/ba_data/textures/gladiatorColorMask.dds \ - build/ba_data/textures/boxingGlovesColor.dds \ - build/ba_data/textures/ouyaOButton.dds \ - build/ba_data/textures/leaderboardsIcon.dds \ - build/ba_data/textures/puckColor.dds \ - build/ba_data/textures/reflectionChar_+z.dds \ - build/ba_data/textures/penguinColor.dds \ - build/ba_data/textures/reflectionSharper_-x.dds \ - build/ba_data/textures/googlePlayLeaderboardsIcon.dds \ - build/ba_data/textures/scrollWidget.dds \ - build/ba_data/textures/courtyardPreview.dds \ - build/ba_data/textures/aliColorMask.dds \ - build/ba_data/textures/penguinColorMask.dds \ - build/ba_data/textures/witchIcon.dds \ - build/ba_data/textures/reflectionSharp_+z.dds \ - build/ba_data/textures/graphicsIcon.dds \ - build/ba_data/textures/agentIcon.dds \ - build/ba_data/textures/fontExtras4.dds \ - build/ba_data/textures/reflectionPowerup_-y.dds \ - build/ba_data/textures/storeIcon.dds \ - build/ba_data/textures/doomShroomPreview.dds \ - build/ba_data/textures/null.dds \ - build/ba_data/textures/backIcon.dds \ - build/ba_data/textures/cyborgColor.dds \ - build/ba_data/textures/monkeyFaceLevelColor.dds \ - build/ba_data/textures/santaIcon.dds \ - build/ba_data/textures/alwaysLandBGColor.dds \ - build/ba_data/textures/roundaboutLevelColor.dds \ - build/ba_data/textures/robotIcon.dds \ - build/ba_data/textures/reflectionSharp_-y.dds \ - build/ba_data/textures/bunnyIcon.dds \ - build/ba_data/textures/circleShadow.dds \ - build/ba_data/textures/flagPoleColor.dds \ - build/ba_data/textures/ouyaUButton.dds \ - build/ba_data/textures/reflectionChar_-y.dds \ - build/ba_data/textures/achievementInControl.dds \ - build/ba_data/textures/wizardColorMask.dds \ - build/ba_data/textures/reflectionSharpest_+x.dds \ - build/ba_data/textures/neoSpazColor.dds \ - build/ba_data/textures/zigZagLevelColor.dds \ - build/ba_data/textures/thePadPreview.dds \ - build/ba_data/textures/superheroIconColorMask.dds \ - build/ba_data/textures/fontSmall7.dds \ - build/ba_data/textures/ticketRoll.dds \ - build/ba_data/textures/reflectionSoft_-y.dds \ - build/ba_data/textures/playerLineup.dds \ - build/ba_data/textures/storeCharacterEaster.dds \ - build/ba_data/textures/coin.dds \ - build/ba_data/textures/circleOutlineNoAlpha.dds \ - build/ba_data/textures/scorchBig.dds \ - build/ba_data/textures/logoEaster.dds \ - build/ba_data/textures/warriorColorMask.dds \ - build/ba_data/textures/assassinColor.dds \ - build/ba_data/textures/bombStickyColor.dds \ - build/ba_data/textures/eggTex1.dds \ - build/ba_data/textures/gladiatorIconColorMask.dds \ - build/ba_data/textures/melColorMask.dds \ - build/ba_data/textures/thePadLevelColor.dds \ - build/ba_data/textures/wizardIconColorMask.dds \ - build/ba_data/textures/bar.dds \ - build/ba_data/textures/zoeIconColorMask.dds \ - build/ba_data/textures/windowHSmallVSmall.dds \ - build/ba_data/textures/circleNoAlpha.dds \ - build/ba_data/textures/gladiatorIcon.dds \ - build/ba_data/textures/reflectionSoft_+z.dds \ - build/ba_data/textures/achievementRunaround.dds \ - build/ba_data/textures/wizardColor.dds \ - build/ba_data/textures/touchArrowsActions.dds \ - build/ba_data/textures/advancedIcon.dds \ - build/ba_data/textures/softRect2.dds \ - build/ba_data/textures/achievementMine.dds \ - build/ba_data/textures/rightButton.dds \ - build/ba_data/textures/touchArrows.dds \ - build/ba_data/textures/cyborgColorMask.dds \ - build/ba_data/textures/jumpsuitIconColorMask.dds \ - build/ba_data/textures/bridgitPreview.dds \ - build/ba_data/textures/ninjaColor.dds \ - build/ba_data/textures/santaColorMask.dds \ - build/ba_data/textures/storeCharacter.dds \ - build/ba_data/textures/flagColor.dds \ - build/ba_data/textures/cragCastlePreview.dds \ - build/ba_data/textures/frameInset.dds \ - build/ba_data/textures/lock.dds \ - build/ba_data/textures/agentColor.dds \ - build/ba_data/textures/achievementGotTheMoves.dds \ - build/ba_data/textures/buttonPunch.dds \ - build/ba_data/textures/settingsIcon.dds \ - build/ba_data/textures/rgbStripes.dds \ - build/ba_data/textures/reflectionSharp_+y.dds \ - build/ba_data/textures/powerupImpactBombs.dds \ - build/ba_data/textures/bigG.dds \ - build/ba_data/textures/melIconColorMask.dds \ - build/ba_data/textures/reflectionChar_+y.dds \ - build/ba_data/textures/multiplayerExamples.dds \ - build/ba_data/textures/actionButtons.dds \ - build/ba_data/textures/melIcon.dds \ - build/ba_data/textures/oldLadyIconColorMask.dds \ - build/ba_data/textures/robotIconColorMask.dds \ - build/ba_data/textures/monkeyFacePreview.dds \ - build/ba_data/textures/achievementDualWielding.dds \ - build/ba_data/textures/folder.dds \ - build/ba_data/textures/frostyColorMask.dds \ - build/ba_data/textures/kronkIconColorMask.dds \ - build/ba_data/textures/fontBig.dds \ - build/ba_data/textures/fontSmall1.dds \ - build/ba_data/textures/shadowSoft.dds \ - build/ba_data/textures/powerupLandMines.dds \ - build/ba_data/textures/stepRightUpPreview.dds \ - build/ba_data/textures/bearIconColorMask.dds \ - build/ba_data/textures/kronk.dds \ - build/ba_data/textures/downButton.dds \ - build/ba_data/textures/bombColor.dds \ - build/ba_data/textures/logo.dds \ - build/ba_data/textures/reflectionPowerup_+y.dds \ - build/ba_data/textures/zoeColorMask.dds \ - build/ba_data/textures/jumpsuitColorMask.dds \ - build/ba_data/textures/penguinIcon.dds \ - build/ba_data/textures/powerupPunch.dds \ - build/ba_data/textures/shadow.dds \ - build/ba_data/textures/reflectionChar_-z.dds \ - build/ba_data/textures/assassinIcon.dds \ - build/ba_data/textures/impactBombColor.dds \ - build/ba_data/textures/storeCharacterXmas.dds \ - build/ba_data/textures/jackIcon.dds \ - build/ba_data/textures/pixieIcon.dds \ - build/ba_data/textures/jumpsuitColor.dds \ - build/ba_data/textures/reflectionSharper_+x.dds \ - build/ba_data/textures/jackColorMask.dds \ - build/ba_data/textures/shrapnel1Color.dds \ - build/ba_data/textures/witchColor.dds \ - build/ba_data/textures/achievementFreeLoader.dds \ - build/ba_data/textures/zoeColor.dds \ - build/ba_data/textures/alienColor.dds \ - build/ba_data/textures/inventoryIcon.dds \ - build/ba_data/textures/reflectionSharp_-z.dds \ - build/ba_data/textures/glow.dds \ - build/ba_data/textures/usersButton.dds \ - build/ba_data/textures/reflectionPowerup_-z.dds \ - build/ba_data/textures/melColor.dds \ - build/ba_data/textures/aliControllerQR.dds \ - build/ba_data/textures/frostyIcon.dds \ - build/ba_data/textures/achievementFootballVictory.dds \ - build/ba_data/textures/tickets.dds \ - build/ba_data/textures/cursor.dds \ - build/ba_data/textures/egg3.dds \ - build/ba_data/textures/crossOut.dds \ - build/ba_data/textures/bonesColor.dds \ build/ba_data/textures/achievementCrossHair.dds \ + build/ba_data/textures/achievementDualWielding.dds \ + build/ba_data/textures/achievementEmpty.dds \ + build/ba_data/textures/achievementFlawlessVictory.dds \ + build/ba_data/textures/achievementFootballShutout.dds \ + build/ba_data/textures/achievementFootballVictory.dds \ + build/ba_data/textures/achievementFreeLoader.dds \ + build/ba_data/textures/achievementGotTheMoves.dds \ + build/ba_data/textures/achievementInControl.dds \ + build/ba_data/textures/achievementMedalLarge.dds \ + build/ba_data/textures/achievementMedalMedium.dds \ + build/ba_data/textures/achievementMedalSmall.dds \ + build/ba_data/textures/achievementMine.dds \ + build/ba_data/textures/achievementOffYouGo.dds \ + build/ba_data/textures/achievementOnslaught.dds \ + build/ba_data/textures/achievementOutline.dds \ + build/ba_data/textures/achievementRunaround.dds \ + build/ba_data/textures/achievementSharingIsCaring.dds \ + build/ba_data/textures/achievementStayinAlive.dds \ + build/ba_data/textures/achievementSuperPunch.dds \ + build/ba_data/textures/achievementTNT.dds \ + build/ba_data/textures/achievementTeamPlayer.dds \ + build/ba_data/textures/achievementWall.dds \ + build/ba_data/textures/achievementsIcon.dds \ + build/ba_data/textures/actionButtons.dds \ + build/ba_data/textures/actionHeroColor.dds \ build/ba_data/textures/actionHeroColorMask.dds \ - build/ba_data/textures/chTitleChar1.dds \ - build/ba_data/textures/heart.dds \ - build/ba_data/textures/fontExtras.dds \ - build/ba_data/textures/penguinIconColorMask.dds \ - build/ba_data/textures/eyeColorTintMask.dds \ + build/ba_data/textures/actionHeroIcon.dds \ + build/ba_data/textures/actionHeroIconColorMask.dds \ + build/ba_data/textures/advancedIcon.dds \ + build/ba_data/textures/agentColor.dds \ + build/ba_data/textures/agentColorMask.dds \ + build/ba_data/textures/agentIcon.dds \ + build/ba_data/textures/agentIconColorMask.dds \ + build/ba_data/textures/aliBSRemoteIOSQR.dds \ + build/ba_data/textures/aliColor.dds \ + build/ba_data/textures/aliColorMask.dds \ + build/ba_data/textures/aliControllerQR.dds \ build/ba_data/textures/aliIcon.dds \ - build/ba_data/textures/chestIconMulti.dds \ - build/ba_data/textures/reflectionSoft_-x.dds \ - build/ba_data/textures/uiAtlas.dds \ - build/ba_data/textures/reflectionSharpest_+y.dds \ - build/ba_data/textures/cragCastleLevelColor.dds \ - build/ba_data/textures/assassinColorMask.dds \ - build/ba_data/textures/bridgitLevelColor.dds \ - build/ba_data/textures/fontSmall6.dds \ - build/ba_data/textures/towerDLevelColor.dds \ - build/ba_data/textures/ouyaYButton.dds \ - build/ba_data/textures/lightSharp.dds \ - build/ba_data/textures/buttonSquare.dds \ - build/ba_data/textures/softRect.dds \ - build/ba_data/textures/powerupIceBombs.dds \ - build/ba_data/textures/jackIconColorMask.dds \ - build/ba_data/textures/audioIcon.dds \ - build/ba_data/textures/tv.dds \ - build/ba_data/textures/reflectionSharpest_-z.dds \ - build/ba_data/textures/warriorIconColorMask.dds \ - build/ba_data/textures/googlePlusSignInButton.dds \ - build/ba_data/textures/circle.dds \ - build/ba_data/textures/neoSpazIconColorMask.dds \ - build/ba_data/textures/medalComplete.dds \ + build/ba_data/textures/aliIconColorMask.dds \ + build/ba_data/textures/aliSplash.dds \ + build/ba_data/textures/alienColor.dds \ + build/ba_data/textures/alienColorMask.dds \ + build/ba_data/textures/alienIcon.dds \ + build/ba_data/textures/alienIconColorMask.dds \ + build/ba_data/textures/alwaysLandBGColor.dds \ build/ba_data/textures/alwaysLandLevelColor.dds \ build/ba_data/textures/alwaysLandPreview.dds \ - build/ba_data/textures/egg4.dds \ - build/ba_data/textures/wrestlerColorMask.dds \ - build/ba_data/textures/superheroColorMask.dds \ - build/ba_data/textures/gladiatorColor.dds \ - build/ba_data/textures/aliBSRemoteIOSQR.dds \ - build/ba_data/textures/bearColorMask.dds \ - build/ba_data/textures/doomShroomLevelColor.dds \ - build/ba_data/textures/powerupBomb.dds \ - build/ba_data/textures/chestIcon.dds \ - build/ba_data/textures/upButton.dds \ - build/ba_data/textures/iconRunaround.dds \ - build/ba_data/textures/doomShroomBGColor.dds \ - build/ba_data/textures/superheroColor.dds \ - build/ba_data/textures/landMine.dds \ - build/ba_data/textures/buttonJump.dds \ - build/ba_data/textures/sparks.dds \ - build/ba_data/textures/explosion.dds \ - build/ba_data/textures/tipTopLevelColor.dds \ - build/ba_data/textures/bunnyIconColorMask.dds \ - build/ba_data/textures/reflectionChar_+x.dds \ - build/ba_data/textures/ticketsMore.dds \ - build/ba_data/textures/pixieColorMask.dds \ - build/ba_data/textures/medalSilver.dds \ - build/ba_data/textures/neoSpazIcon.dds \ - build/ba_data/textures/meter.dds \ - build/ba_data/textures/scrollWidgetGlow.dds \ - build/ba_data/textures/achievementFlawlessVictory.dds \ - build/ba_data/textures/zigzagPreview.dds \ - build/ba_data/textures/reflectionSharper_-z.dds \ - build/ba_data/textures/alienColorMask.dds \ - build/ba_data/textures/powerupShield.dds \ - build/ba_data/textures/reflectionSharp_+x.dds \ - build/ba_data/textures/chestIconEmpty.dds \ - build/ba_data/textures/agentColorMask.dds \ - build/ba_data/textures/reflectionPowerup_+x.dds \ - build/ba_data/textures/witchIconColorMask.dds \ - build/ba_data/textures/kronkColorMask.dds \ - build/ba_data/textures/menuBG.dds \ - build/ba_data/textures/fontSmall0.dds \ + build/ba_data/textures/analogStick.dds \ + build/ba_data/textures/arrow.dds \ + build/ba_data/textures/assassinColor.dds \ + build/ba_data/textures/assassinColorMask.dds \ + build/ba_data/textures/assassinIcon.dds \ build/ba_data/textures/assassinIconColorMask.dds \ + build/ba_data/textures/audioIcon.dds \ + build/ba_data/textures/backIcon.dds \ + build/ba_data/textures/bar.dds \ build/ba_data/textures/bearColor.dds \ - build/ba_data/textures/operaSingerColor.dds \ - build/ba_data/textures/rampageBGColor2.dds \ - build/ba_data/textures/fuse.dds \ - build/ba_data/textures/frostyColor.dds \ - build/ba_data/textures/achievementSuperPunch.dds \ - build/ba_data/textures/tipTopPreview.dds \ - build/ba_data/textures/googlePlusIcon.dds \ - build/ba_data/textures/powerupCurse.dds \ - build/ba_data/textures/trophy.dds \ + build/ba_data/textures/bearColorMask.dds \ + build/ba_data/textures/bearIcon.dds \ + build/ba_data/textures/bearIconColorMask.dds \ + build/ba_data/textures/bg.dds \ + build/ba_data/textures/bigG.dds \ + build/ba_data/textures/bigGPreview.dds \ + build/ba_data/textures/black.dds \ + build/ba_data/textures/bombButton.dds \ + build/ba_data/textures/bombColor.dds \ + build/ba_data/textures/bombColorIce.dds \ + build/ba_data/textures/bombStickyColor.dds \ + build/ba_data/textures/bonesColor.dds \ + build/ba_data/textures/bonesColorMask.dds \ + build/ba_data/textures/bonesIcon.dds \ + build/ba_data/textures/bonesIconColorMask.dds \ + build/ba_data/textures/boxingGlovesColor.dds \ + build/ba_data/textures/bridgitLevelColor.dds \ + build/ba_data/textures/bridgitPreview.dds \ + build/ba_data/textures/bunnyColor.dds \ + build/ba_data/textures/bunnyColorMask.dds \ + build/ba_data/textures/bunnyIcon.dds \ + build/ba_data/textures/bunnyIconColorMask.dds \ + build/ba_data/textures/buttonBomb.dds \ + build/ba_data/textures/buttonJump.dds \ + build/ba_data/textures/buttonPickUp.dds \ + build/ba_data/textures/buttonPunch.dds \ + build/ba_data/textures/buttonSquare.dds \ + build/ba_data/textures/chTitleChar1.dds \ + build/ba_data/textures/chTitleChar2.dds \ + build/ba_data/textures/chTitleChar3.dds \ + build/ba_data/textures/chTitleChar4.dds \ + build/ba_data/textures/chTitleChar5.dds \ + build/ba_data/textures/characterIconMask.dds \ + build/ba_data/textures/chestIcon.dds \ + build/ba_data/textures/chestIconEmpty.dds \ + build/ba_data/textures/chestIconMulti.dds \ + build/ba_data/textures/chestOpenIcon.dds \ + build/ba_data/textures/circle.dds \ + build/ba_data/textures/circleNoAlpha.dds \ + build/ba_data/textures/circleOutline.dds \ + build/ba_data/textures/circleOutlineNoAlpha.dds \ + build/ba_data/textures/circleShadow.dds \ + build/ba_data/textures/circleZigZag.dds \ + build/ba_data/textures/coin.dds \ + build/ba_data/textures/controllerIcon.dds \ build/ba_data/textures/courtyardLevelColor.dds \ - build/ba_data/textures/oldLadyColorMask.dds \ - build/ba_data/textures/rampagePreview.dds \ + build/ba_data/textures/courtyardPreview.dds \ + build/ba_data/textures/cowboyColor.dds \ + build/ba_data/textures/cowboyColorMask.dds \ + build/ba_data/textures/cowboyIcon.dds \ + build/ba_data/textures/cowboyIconColorMask.dds \ + build/ba_data/textures/cragCastleLevelColor.dds \ + build/ba_data/textures/cragCastlePreview.dds \ + build/ba_data/textures/crossOut.dds \ + build/ba_data/textures/crossOutMask.dds \ + build/ba_data/textures/cursor.dds \ build/ba_data/textures/cuteSpaz.dds \ - build/ba_data/textures/lightSoft.dds \ - build/ba_data/textures/reflectionSharper_+y.dds \ - build/ba_data/textures/uiAtlas2.dds \ + build/ba_data/textures/cyborgColor.dds \ + build/ba_data/textures/cyborgColorMask.dds \ + build/ba_data/textures/cyborgIcon.dds \ + build/ba_data/textures/cyborgIconColorMask.dds \ + build/ba_data/textures/doomShroomBGColor.dds \ + build/ba_data/textures/doomShroomLevelColor.dds \ + build/ba_data/textures/doomShroomPreview.dds \ + build/ba_data/textures/downButton.dds \ + build/ba_data/textures/egg1.dds \ build/ba_data/textures/egg2.dds \ - build/ba_data/textures/shadowSharp.dds \ - build/ba_data/textures/tnt.dds \ - build/ba_data/textures/actionHeroIcon.dds \ - build/ba_data/textures/robotColorMask.dds \ + build/ba_data/textures/egg3.dds \ + build/ba_data/textures/egg4.dds \ + build/ba_data/textures/eggTex1.dds \ + build/ba_data/textures/eggTex2.dds \ + build/ba_data/textures/eggTex3.dds \ + build/ba_data/textures/empty.dds \ + build/ba_data/textures/explosion.dds \ + build/ba_data/textures/eyeColor.dds \ + build/ba_data/textures/eyeColorTintMask.dds \ + build/ba_data/textures/file.dds \ + build/ba_data/textures/flagColor.dds \ + build/ba_data/textures/flagPoleColor.dds \ + build/ba_data/textures/folder.dds \ + build/ba_data/textures/fontBig.dds \ + build/ba_data/textures/fontExtras.dds \ + build/ba_data/textures/fontExtras2.dds \ + build/ba_data/textures/fontExtras3.dds \ + build/ba_data/textures/fontExtras4.dds \ + build/ba_data/textures/fontSmall0.dds \ + build/ba_data/textures/fontSmall1.dds \ + build/ba_data/textures/fontSmall2.dds \ + build/ba_data/textures/fontSmall3.dds \ + build/ba_data/textures/fontSmall4.dds \ + build/ba_data/textures/fontSmall5.dds \ + build/ba_data/textures/fontSmall6.dds \ + build/ba_data/textures/fontSmall7.dds \ + build/ba_data/textures/footballStadium.dds \ + build/ba_data/textures/footballStadiumPreview.dds \ + build/ba_data/textures/frameInset.dds \ + build/ba_data/textures/frostyColor.dds \ + build/ba_data/textures/frostyColorMask.dds \ + build/ba_data/textures/frostyIcon.dds \ + build/ba_data/textures/frostyIconColorMask.dds \ + build/ba_data/textures/fuse.dds \ + build/ba_data/textures/gameCenterIcon.dds \ + build/ba_data/textures/gameCircleIcon.dds \ + build/ba_data/textures/gladiatorColor.dds \ + build/ba_data/textures/gladiatorColorMask.dds \ + build/ba_data/textures/gladiatorIcon.dds \ + build/ba_data/textures/gladiatorIconColorMask.dds \ + build/ba_data/textures/glow.dds \ + build/ba_data/textures/googlePlayAchievementsIcon.dds \ + build/ba_data/textures/googlePlayGamesIcon.dds \ + build/ba_data/textures/googlePlayLeaderboardsIcon.dds \ + build/ba_data/textures/googlePlusIcon.dds \ + build/ba_data/textures/googlePlusSignInButton.dds \ + build/ba_data/textures/graphicsIcon.dds \ + build/ba_data/textures/heart.dds \ + build/ba_data/textures/hockeyStadium.dds \ + build/ba_data/textures/hockeyStadiumPreview.dds \ + build/ba_data/textures/iconOnslaught.dds \ + build/ba_data/textures/iconRunaround.dds \ + build/ba_data/textures/impactBombColor.dds \ build/ba_data/textures/impactBombColorLit.dds \ - build/ba_data/textures/achievementStayinAlive.dds + build/ba_data/textures/inventoryIcon.dds \ + build/ba_data/textures/jackColor.dds \ + build/ba_data/textures/jackColorMask.dds \ + build/ba_data/textures/jackIcon.dds \ + build/ba_data/textures/jackIconColorMask.dds \ + build/ba_data/textures/jumpsuitColor.dds \ + build/ba_data/textures/jumpsuitColorMask.dds \ + build/ba_data/textures/jumpsuitIcon.dds \ + build/ba_data/textures/jumpsuitIconColorMask.dds \ + build/ba_data/textures/kronk.dds \ + build/ba_data/textures/kronkColorMask.dds \ + build/ba_data/textures/kronkIcon.dds \ + build/ba_data/textures/kronkIconColorMask.dds \ + build/ba_data/textures/lakeFrigid.dds \ + build/ba_data/textures/lakeFrigidPreview.dds \ + build/ba_data/textures/lakeFrigidReflections.dds \ + build/ba_data/textures/landMine.dds \ + build/ba_data/textures/landMineLit.dds \ + build/ba_data/textures/leaderboardsIcon.dds \ + build/ba_data/textures/leftButton.dds \ + build/ba_data/textures/levelIcon.dds \ + build/ba_data/textures/light.dds \ + build/ba_data/textures/lightSharp.dds \ + build/ba_data/textures/lightSoft.dds \ + build/ba_data/textures/lock.dds \ + build/ba_data/textures/logIcon.dds \ + build/ba_data/textures/logo.dds \ + build/ba_data/textures/logoEaster.dds \ + build/ba_data/textures/mapPreviewMask.dds \ + build/ba_data/textures/medalBronze.dds \ + build/ba_data/textures/medalComplete.dds \ + build/ba_data/textures/medalGold.dds \ + build/ba_data/textures/medalSilver.dds \ + build/ba_data/textures/melColor.dds \ + build/ba_data/textures/melColorMask.dds \ + build/ba_data/textures/melIcon.dds \ + build/ba_data/textures/melIconColorMask.dds \ + build/ba_data/textures/menuBG.dds \ + build/ba_data/textures/menuButton.dds \ + build/ba_data/textures/menuIcon.dds \ + build/ba_data/textures/meter.dds \ + build/ba_data/textures/monkeyFaceLevelColor.dds \ + build/ba_data/textures/monkeyFacePreview.dds \ + build/ba_data/textures/multiplayerExamples.dds \ + build/ba_data/textures/natureBackgroundColor.dds \ + build/ba_data/textures/neoSpazColor.dds \ + build/ba_data/textures/neoSpazColorMask.dds \ + build/ba_data/textures/neoSpazIcon.dds \ + build/ba_data/textures/neoSpazIconColorMask.dds \ + build/ba_data/textures/nextLevelIcon.dds \ + build/ba_data/textures/ninjaColor.dds \ + build/ba_data/textures/ninjaColorMask.dds \ + build/ba_data/textures/ninjaIcon.dds \ + build/ba_data/textures/ninjaIconColorMask.dds \ + build/ba_data/textures/nub.dds \ + build/ba_data/textures/null.dds \ + build/ba_data/textures/oldLadyColor.dds \ + build/ba_data/textures/oldLadyColorMask.dds \ + build/ba_data/textures/oldLadyIcon.dds \ + build/ba_data/textures/oldLadyIconColorMask.dds \ + build/ba_data/textures/operaSingerColor.dds \ + build/ba_data/textures/operaSingerColorMask.dds \ + build/ba_data/textures/operaSingerIcon.dds \ + build/ba_data/textures/operaSingerIconColorMask.dds \ + build/ba_data/textures/ouyaAButton.dds \ + build/ba_data/textures/ouyaIcon.dds \ + build/ba_data/textures/ouyaOButton.dds \ + build/ba_data/textures/ouyaUButton.dds \ + build/ba_data/textures/ouyaYButton.dds \ + build/ba_data/textures/penguinColor.dds \ + build/ba_data/textures/penguinColorMask.dds \ + build/ba_data/textures/penguinIcon.dds \ + build/ba_data/textures/penguinIconColorMask.dds \ + build/ba_data/textures/pixieColor.dds \ + build/ba_data/textures/pixieColorMask.dds \ + build/ba_data/textures/pixieIcon.dds \ + build/ba_data/textures/pixieIconColorMask.dds \ + build/ba_data/textures/playerLineup.dds \ + build/ba_data/textures/powerupBomb.dds \ + build/ba_data/textures/powerupCurse.dds \ + build/ba_data/textures/powerupHealth.dds \ + build/ba_data/textures/powerupIceBombs.dds \ + build/ba_data/textures/powerupImpactBombs.dds \ + build/ba_data/textures/powerupLandMines.dds \ + build/ba_data/textures/powerupPunch.dds \ + build/ba_data/textures/powerupShield.dds \ + build/ba_data/textures/powerupSpeed.dds \ + build/ba_data/textures/powerupStickyBombs.dds \ + build/ba_data/textures/puckColor.dds \ + build/ba_data/textures/rampageBGColor.dds \ + build/ba_data/textures/rampageBGColor2.dds \ + build/ba_data/textures/rampageLevelColor.dds \ + build/ba_data/textures/rampagePreview.dds \ + build/ba_data/textures/reflectionChar_+x.dds \ + build/ba_data/textures/reflectionChar_+y.dds \ + build/ba_data/textures/reflectionChar_+z.dds \ + build/ba_data/textures/reflectionChar_-x.dds \ + build/ba_data/textures/reflectionChar_-y.dds \ + build/ba_data/textures/reflectionChar_-z.dds \ + build/ba_data/textures/reflectionPowerup_+x.dds \ + build/ba_data/textures/reflectionPowerup_+y.dds \ + build/ba_data/textures/reflectionPowerup_+z.dds \ + build/ba_data/textures/reflectionPowerup_-x.dds \ + build/ba_data/textures/reflectionPowerup_-y.dds \ + build/ba_data/textures/reflectionPowerup_-z.dds \ + build/ba_data/textures/reflectionSharp_+x.dds \ + build/ba_data/textures/reflectionSharp_+y.dds \ + build/ba_data/textures/reflectionSharp_+z.dds \ + build/ba_data/textures/reflectionSharp_-x.dds \ + build/ba_data/textures/reflectionSharp_-y.dds \ + build/ba_data/textures/reflectionSharp_-z.dds \ + build/ba_data/textures/reflectionSharper_+x.dds \ + build/ba_data/textures/reflectionSharper_+y.dds \ + build/ba_data/textures/reflectionSharper_+z.dds \ + build/ba_data/textures/reflectionSharper_-x.dds \ + build/ba_data/textures/reflectionSharper_-y.dds \ + build/ba_data/textures/reflectionSharper_-z.dds \ + build/ba_data/textures/reflectionSharpest_+x.dds \ + build/ba_data/textures/reflectionSharpest_+y.dds \ + build/ba_data/textures/reflectionSharpest_+z.dds \ + build/ba_data/textures/reflectionSharpest_-x.dds \ + build/ba_data/textures/reflectionSharpest_-y.dds \ + build/ba_data/textures/reflectionSharpest_-z.dds \ + build/ba_data/textures/reflectionSoft_+x.dds \ + build/ba_data/textures/reflectionSoft_+y.dds \ + build/ba_data/textures/reflectionSoft_+z.dds \ + build/ba_data/textures/reflectionSoft_-x.dds \ + build/ba_data/textures/reflectionSoft_-y.dds \ + build/ba_data/textures/reflectionSoft_-z.dds \ + build/ba_data/textures/replayIcon.dds \ + build/ba_data/textures/rgbStripes.dds \ + build/ba_data/textures/rightButton.dds \ + build/ba_data/textures/robotColor.dds \ + build/ba_data/textures/robotColorMask.dds \ + build/ba_data/textures/robotIcon.dds \ + build/ba_data/textures/robotIconColorMask.dds \ + build/ba_data/textures/roundaboutLevelColor.dds \ + build/ba_data/textures/roundaboutPreview.dds \ + build/ba_data/textures/santaColor.dds \ + build/ba_data/textures/santaColorMask.dds \ + build/ba_data/textures/santaIcon.dds \ + build/ba_data/textures/santaIconColorMask.dds \ + build/ba_data/textures/scorch.dds \ + build/ba_data/textures/scorchBig.dds \ + build/ba_data/textures/scrollWidget.dds \ + build/ba_data/textures/scrollWidgetGlow.dds \ + build/ba_data/textures/settingsIcon.dds \ + build/ba_data/textures/shadow.dds \ + build/ba_data/textures/shadowSharp.dds \ + build/ba_data/textures/shadowSoft.dds \ + build/ba_data/textures/shield.dds \ + build/ba_data/textures/shrapnel1Color.dds \ + build/ba_data/textures/slash.dds \ + build/ba_data/textures/smoke.dds \ + build/ba_data/textures/softRect.dds \ + build/ba_data/textures/softRect2.dds \ + build/ba_data/textures/softRectVertical.dds \ + build/ba_data/textures/sparks.dds \ + build/ba_data/textures/star.dds \ + build/ba_data/textures/startButton.dds \ + build/ba_data/textures/stepRightUpLevelColor.dds \ + build/ba_data/textures/stepRightUpPreview.dds \ + build/ba_data/textures/storeCharacter.dds \ + build/ba_data/textures/storeCharacterEaster.dds \ + build/ba_data/textures/storeCharacterXmas.dds \ + build/ba_data/textures/storeIcon.dds \ + build/ba_data/textures/superheroColor.dds \ + build/ba_data/textures/superheroColorMask.dds \ + build/ba_data/textures/superheroIcon.dds \ + build/ba_data/textures/superheroIconColorMask.dds \ + build/ba_data/textures/textClearButton.dds \ + build/ba_data/textures/thePadLevelColor.dds \ + build/ba_data/textures/thePadPreview.dds \ + build/ba_data/textures/ticketRoll.dds \ + build/ba_data/textures/ticketRollBig.dds \ + build/ba_data/textures/ticketRolls.dds \ + build/ba_data/textures/tickets.dds \ + build/ba_data/textures/ticketsMore.dds \ + build/ba_data/textures/tipTopBGColor.dds \ + build/ba_data/textures/tipTopLevelColor.dds \ + build/ba_data/textures/tipTopPreview.dds \ + build/ba_data/textures/tnt.dds \ + build/ba_data/textures/touchArrows.dds \ + build/ba_data/textures/touchArrowsActions.dds \ + build/ba_data/textures/towerDLevelColor.dds \ + build/ba_data/textures/towerDPreview.dds \ + build/ba_data/textures/treesColor.dds \ + build/ba_data/textures/trophy.dds \ + build/ba_data/textures/tv.dds \ + build/ba_data/textures/uiAtlas.dds \ + build/ba_data/textures/uiAtlas2.dds \ + build/ba_data/textures/upButton.dds \ + build/ba_data/textures/usersButton.dds \ + build/ba_data/textures/vrFillMound.dds \ + build/ba_data/textures/warriorColor.dds \ + build/ba_data/textures/warriorColorMask.dds \ + build/ba_data/textures/warriorIcon.dds \ + build/ba_data/textures/warriorIconColorMask.dds \ + build/ba_data/textures/white.dds \ + build/ba_data/textures/windowHSmallVMed.dds \ + build/ba_data/textures/windowHSmallVSmall.dds \ + build/ba_data/textures/wings.dds \ + build/ba_data/textures/witchColor.dds \ + build/ba_data/textures/witchColorMask.dds \ + build/ba_data/textures/witchIcon.dds \ + build/ba_data/textures/witchIconColorMask.dds \ + build/ba_data/textures/wizardColor.dds \ + build/ba_data/textures/wizardColorMask.dds \ + build/ba_data/textures/wizardIcon.dds \ + build/ba_data/textures/wizardIconColorMask.dds \ + build/ba_data/textures/wrestlerColor.dds \ + build/ba_data/textures/wrestlerColorMask.dds \ + build/ba_data/textures/wrestlerIcon.dds \ + build/ba_data/textures/wrestlerIconColorMask.dds \ + build/ba_data/textures/zigZagLevelColor.dds \ + build/ba_data/textures/zigzagPreview.dds \ + build/ba_data/textures/zoeColor.dds \ + build/ba_data/textures/zoeColorMask.dds \ + build/ba_data/textures/zoeIcon.dds \ + build/ba_data/textures/zoeIconColorMask.dds TEX2D_PVR_TARGETS = \ - build/ba_data/textures/cyborgIconColorMask.pvr \ - build/ba_data/textures/chestOpenIcon.pvr \ - build/ba_data/textures/analogStick.pvr \ - build/ba_data/textures/circleOutline.pvr \ - build/ba_data/textures/white.pvr \ - build/ba_data/textures/medalBronze.pvr \ - build/ba_data/textures/slash.pvr \ - build/ba_data/textures/arrow.pvr \ - build/ba_data/textures/ouyaIcon.pvr \ - build/ba_data/textures/eyeColor.pvr \ - build/ba_data/textures/achievementMedalLarge.pvr \ - build/ba_data/textures/cowboyIconColorMask.pvr \ - build/ba_data/textures/wings.pvr \ - build/ba_data/textures/roundaboutPreview.pvr \ - build/ba_data/textures/warriorIcon.pvr \ - build/ba_data/textures/windowHSmallVMed.pvr \ - build/ba_data/textures/ninjaIconColorMask.pvr \ - build/ba_data/textures/reflectionSharpest_+z.pvr \ - build/ba_data/textures/stepRightUpLevelColor.pvr \ - build/ba_data/textures/fontSmall5.pvr \ - build/ba_data/textures/bombButton.pvr \ - build/ba_data/textures/aliIconColorMask.pvr \ - build/ba_data/textures/chTitleChar2.pvr \ - build/ba_data/textures/achievementOnslaught.pvr \ - build/ba_data/textures/smoke.pvr \ - build/ba_data/textures/lakeFrigidReflections.pvr \ - build/ba_data/textures/bunnyColor.pvr \ - build/ba_data/textures/leftButton.pvr \ - build/ba_data/textures/hockeyStadium.pvr \ - build/ba_data/textures/cowboyIcon.pvr \ - build/ba_data/textures/lakeFrigid.pvr \ - build/ba_data/textures/startButton.pvr \ - build/ba_data/textures/footballStadium.pvr \ - build/ba_data/textures/crossOutMask.pvr \ - build/ba_data/textures/bonesIconColorMask.pvr \ - build/ba_data/textures/operaSingerIconColorMask.pvr \ - build/ba_data/textures/lakeFrigidPreview.pvr \ - build/ba_data/textures/alienIcon.pvr \ - build/ba_data/textures/oldLadyColor.pvr \ - build/ba_data/textures/ouyaAButton.pvr \ - build/ba_data/textures/eggTex3.pvr \ - build/ba_data/textures/cyborgIcon.pvr \ - build/ba_data/textures/actionHeroColor.pvr \ - build/ba_data/textures/achievementTeamPlayer.pvr \ - build/ba_data/textures/reflectionSoft_+x.pvr \ - build/ba_data/textures/fontExtras3.pvr \ - build/ba_data/textures/buttonBomb.pvr \ - build/ba_data/textures/star.pvr \ - build/ba_data/textures/reflectionSharpest_-y.pvr \ - build/ba_data/textures/achievementSharingIsCaring.pvr \ - build/ba_data/textures/fontSmall3.pvr \ - build/ba_data/textures/powerupSpeed.pvr \ - build/ba_data/textures/vrFillMound.pvr \ - build/ba_data/textures/agentIconColorMask.pvr \ - build/ba_data/textures/kronkIcon.pvr \ - build/ba_data/textures/oldLadyIcon.pvr \ - build/ba_data/textures/chTitleChar4.pvr \ - build/ba_data/textures/nextLevelIcon.pvr \ - build/ba_data/textures/gameCircleIcon.pvr \ - build/ba_data/textures/bonesIcon.pvr \ - build/ba_data/textures/bearIcon.pvr \ - build/ba_data/textures/towerDPreview.pvr \ - build/ba_data/textures/achievementTNT.pvr \ - build/ba_data/textures/medalGold.pvr \ - build/ba_data/textures/circleZigZag.pvr \ - build/ba_data/textures/bunnyColorMask.pvr \ - build/ba_data/textures/black.pvr \ - build/ba_data/textures/menuIcon.pvr \ - build/ba_data/textures/file.pvr \ - build/ba_data/textures/logIcon.pvr \ - build/ba_data/textures/controllerIcon.pvr \ - build/ba_data/textures/reflectionSharper_-y.pvr \ - build/ba_data/textures/operaSingerColorMask.pvr \ - build/ba_data/textures/achievementFootballShutout.pvr \ - build/ba_data/textures/reflectionPowerup_-x.pvr \ - build/ba_data/textures/achievementsIcon.pvr \ - build/ba_data/textures/cowboyColor.pvr \ - build/ba_data/textures/wrestlerIconColorMask.pvr \ - build/ba_data/textures/googlePlayAchievementsIcon.pvr \ - build/ba_data/textures/alienIconColorMask.pvr \ - build/ba_data/textures/ticketRollBig.pvr \ - build/ba_data/textures/wrestlerIcon.pvr \ - build/ba_data/textures/egg1.pvr \ - build/ba_data/textures/gameCenterIcon.pvr \ - build/ba_data/textures/landMineLit.pvr \ - build/ba_data/textures/achievementWall.pvr \ - build/ba_data/textures/achievementMedalMedium.pvr \ - build/ba_data/textures/reflectionChar_-x.pvr \ - build/ba_data/textures/softRectVertical.pvr \ - build/ba_data/textures/reflectionSharper_+z.pvr \ - build/ba_data/textures/wizardIcon.pvr \ - build/ba_data/textures/mapPreviewMask.pvr \ - build/ba_data/textures/nub.pvr \ - build/ba_data/textures/empty.pvr \ - build/ba_data/textures/frostyIconColorMask.pvr \ - build/ba_data/textures/reflectionSharp_-x.pvr \ - build/ba_data/textures/bombColorIce.pvr \ - build/ba_data/textures/jumpsuitIcon.pvr \ - build/ba_data/textures/footballStadiumPreview.pvr \ - build/ba_data/textures/pixieIconColorMask.pvr \ - build/ba_data/textures/achievementEmpty.pvr \ - build/ba_data/textures/wrestlerColor.pvr \ - build/ba_data/textures/shield.pvr \ - build/ba_data/textures/iconOnslaught.pvr \ - build/ba_data/textures/replayIcon.pvr \ - build/ba_data/textures/powerupHealth.pvr \ - build/ba_data/textures/bg.pvr \ - build/ba_data/textures/chTitleChar3.pvr \ - build/ba_data/textures/textClearButton.pvr \ - build/ba_data/textures/reflectionSoft_-z.pvr \ - build/ba_data/textures/fontSmall4.pvr \ - build/ba_data/textures/warriorColor.pvr \ - build/ba_data/textures/light.pvr \ - build/ba_data/textures/santaColor.pvr \ - build/ba_data/textures/jackColor.pvr \ - build/ba_data/textures/aliSplash.pvr \ - build/ba_data/textures/scorch.pvr \ - build/ba_data/textures/zoeIcon.pvr \ - build/ba_data/textures/bonesColorMask.pvr \ - build/ba_data/textures/pixieColor.pvr \ - build/ba_data/textures/actionHeroIconColorMask.pvr \ - build/ba_data/textures/treesColor.pvr \ - build/ba_data/textures/neoSpazColorMask.pvr \ - build/ba_data/textures/superheroIcon.pvr \ - build/ba_data/textures/achievementOffYouGo.pvr \ - build/ba_data/textures/tipTopBGColor.pvr \ - build/ba_data/textures/robotColor.pvr \ - build/ba_data/textures/reflectionSharpest_-x.pvr \ - build/ba_data/textures/menuButton.pvr \ - build/ba_data/textures/powerupStickyBombs.pvr \ - build/ba_data/textures/ninjaIcon.pvr \ - build/ba_data/textures/witchColorMask.pvr \ - build/ba_data/textures/cowboyColorMask.pvr \ - build/ba_data/textures/operaSingerIcon.pvr \ build/ba_data/textures/achievementBoxer.pvr \ - build/ba_data/textures/eggTex2.pvr \ - build/ba_data/textures/rampageBGColor.pvr \ - build/ba_data/textures/fontExtras2.pvr \ - build/ba_data/textures/rampageLevelColor.pvr \ - build/ba_data/textures/reflectionSoft_+y.pvr \ - build/ba_data/textures/ticketRolls.pvr \ - build/ba_data/textures/natureBackgroundColor.pvr \ - build/ba_data/textures/santaIconColorMask.pvr \ - build/ba_data/textures/reflectionPowerup_+z.pvr \ - build/ba_data/textures/characterIconMask.pvr \ - build/ba_data/textures/aliColor.pvr \ - build/ba_data/textures/ninjaColorMask.pvr \ - build/ba_data/textures/buttonPickUp.pvr \ - build/ba_data/textures/chTitleChar5.pvr \ - build/ba_data/textures/bigGPreview.pvr \ - build/ba_data/textures/hockeyStadiumPreview.pvr \ - build/ba_data/textures/achievementMedalSmall.pvr \ - build/ba_data/textures/fontSmall2.pvr \ - build/ba_data/textures/achievementOutline.pvr \ - build/ba_data/textures/levelIcon.pvr \ - build/ba_data/textures/googlePlayGamesIcon.pvr \ - build/ba_data/textures/gladiatorColorMask.pvr \ - build/ba_data/textures/boxingGlovesColor.pvr \ - build/ba_data/textures/ouyaOButton.pvr \ - build/ba_data/textures/leaderboardsIcon.pvr \ - build/ba_data/textures/puckColor.pvr \ - build/ba_data/textures/reflectionChar_+z.pvr \ - build/ba_data/textures/penguinColor.pvr \ - build/ba_data/textures/reflectionSharper_-x.pvr \ - build/ba_data/textures/googlePlayLeaderboardsIcon.pvr \ - build/ba_data/textures/scrollWidget.pvr \ - build/ba_data/textures/courtyardPreview.pvr \ - build/ba_data/textures/aliColorMask.pvr \ - build/ba_data/textures/penguinColorMask.pvr \ - build/ba_data/textures/witchIcon.pvr \ - build/ba_data/textures/reflectionSharp_+z.pvr \ - build/ba_data/textures/graphicsIcon.pvr \ - build/ba_data/textures/agentIcon.pvr \ - build/ba_data/textures/fontExtras4.pvr \ - build/ba_data/textures/reflectionPowerup_-y.pvr \ - build/ba_data/textures/storeIcon.pvr \ - build/ba_data/textures/doomShroomPreview.pvr \ - build/ba_data/textures/null.pvr \ - build/ba_data/textures/backIcon.pvr \ - build/ba_data/textures/cyborgColor.pvr \ - build/ba_data/textures/monkeyFaceLevelColor.pvr \ - build/ba_data/textures/santaIcon.pvr \ - build/ba_data/textures/alwaysLandBGColor.pvr \ - build/ba_data/textures/roundaboutLevelColor.pvr \ - build/ba_data/textures/robotIcon.pvr \ - build/ba_data/textures/reflectionSharp_-y.pvr \ - build/ba_data/textures/bunnyIcon.pvr \ - build/ba_data/textures/circleShadow.pvr \ - build/ba_data/textures/flagPoleColor.pvr \ - build/ba_data/textures/ouyaUButton.pvr \ - build/ba_data/textures/reflectionChar_-y.pvr \ - build/ba_data/textures/achievementInControl.pvr \ - build/ba_data/textures/wizardColorMask.pvr \ - build/ba_data/textures/reflectionSharpest_+x.pvr \ - build/ba_data/textures/neoSpazColor.pvr \ - build/ba_data/textures/zigZagLevelColor.pvr \ - build/ba_data/textures/thePadPreview.pvr \ - build/ba_data/textures/superheroIconColorMask.pvr \ - build/ba_data/textures/fontSmall7.pvr \ - build/ba_data/textures/ticketRoll.pvr \ - build/ba_data/textures/reflectionSoft_-y.pvr \ - build/ba_data/textures/playerLineup.pvr \ - build/ba_data/textures/storeCharacterEaster.pvr \ - build/ba_data/textures/coin.pvr \ - build/ba_data/textures/circleOutlineNoAlpha.pvr \ - build/ba_data/textures/scorchBig.pvr \ - build/ba_data/textures/logoEaster.pvr \ - build/ba_data/textures/warriorColorMask.pvr \ - build/ba_data/textures/assassinColor.pvr \ - build/ba_data/textures/bombStickyColor.pvr \ - build/ba_data/textures/eggTex1.pvr \ - build/ba_data/textures/gladiatorIconColorMask.pvr \ - build/ba_data/textures/melColorMask.pvr \ - build/ba_data/textures/thePadLevelColor.pvr \ - build/ba_data/textures/wizardIconColorMask.pvr \ - build/ba_data/textures/bar.pvr \ - build/ba_data/textures/zoeIconColorMask.pvr \ - build/ba_data/textures/windowHSmallVSmall.pvr \ - build/ba_data/textures/circleNoAlpha.pvr \ - build/ba_data/textures/gladiatorIcon.pvr \ - build/ba_data/textures/reflectionSoft_+z.pvr \ - build/ba_data/textures/achievementRunaround.pvr \ - build/ba_data/textures/wizardColor.pvr \ - build/ba_data/textures/touchArrowsActions.pvr \ - build/ba_data/textures/advancedIcon.pvr \ - build/ba_data/textures/softRect2.pvr \ - build/ba_data/textures/achievementMine.pvr \ - build/ba_data/textures/rightButton.pvr \ - build/ba_data/textures/touchArrows.pvr \ - build/ba_data/textures/cyborgColorMask.pvr \ - build/ba_data/textures/jumpsuitIconColorMask.pvr \ - build/ba_data/textures/bridgitPreview.pvr \ - build/ba_data/textures/ninjaColor.pvr \ - build/ba_data/textures/santaColorMask.pvr \ - build/ba_data/textures/storeCharacter.pvr \ - build/ba_data/textures/flagColor.pvr \ - build/ba_data/textures/cragCastlePreview.pvr \ - build/ba_data/textures/frameInset.pvr \ - build/ba_data/textures/lock.pvr \ - build/ba_data/textures/agentColor.pvr \ - build/ba_data/textures/achievementGotTheMoves.pvr \ - build/ba_data/textures/buttonPunch.pvr \ - build/ba_data/textures/settingsIcon.pvr \ - build/ba_data/textures/rgbStripes.pvr \ - build/ba_data/textures/reflectionSharp_+y.pvr \ - build/ba_data/textures/powerupImpactBombs.pvr \ - build/ba_data/textures/bigG.pvr \ - build/ba_data/textures/melIconColorMask.pvr \ - build/ba_data/textures/reflectionChar_+y.pvr \ - build/ba_data/textures/multiplayerExamples.pvr \ - build/ba_data/textures/actionButtons.pvr \ - build/ba_data/textures/melIcon.pvr \ - build/ba_data/textures/oldLadyIconColorMask.pvr \ - build/ba_data/textures/robotIconColorMask.pvr \ - build/ba_data/textures/monkeyFacePreview.pvr \ - build/ba_data/textures/achievementDualWielding.pvr \ - build/ba_data/textures/folder.pvr \ - build/ba_data/textures/frostyColorMask.pvr \ - build/ba_data/textures/kronkIconColorMask.pvr \ - build/ba_data/textures/fontBig.pvr \ - build/ba_data/textures/fontSmall1.pvr \ - build/ba_data/textures/shadowSoft.pvr \ - build/ba_data/textures/powerupLandMines.pvr \ - build/ba_data/textures/stepRightUpPreview.pvr \ - build/ba_data/textures/bearIconColorMask.pvr \ - build/ba_data/textures/kronk.pvr \ - build/ba_data/textures/downButton.pvr \ - build/ba_data/textures/bombColor.pvr \ - build/ba_data/textures/logo.pvr \ - build/ba_data/textures/reflectionPowerup_+y.pvr \ - build/ba_data/textures/zoeColorMask.pvr \ - build/ba_data/textures/jumpsuitColorMask.pvr \ - build/ba_data/textures/penguinIcon.pvr \ - build/ba_data/textures/powerupPunch.pvr \ - build/ba_data/textures/shadow.pvr \ - build/ba_data/textures/reflectionChar_-z.pvr \ - build/ba_data/textures/assassinIcon.pvr \ - build/ba_data/textures/impactBombColor.pvr \ - build/ba_data/textures/storeCharacterXmas.pvr \ - build/ba_data/textures/jackIcon.pvr \ - build/ba_data/textures/pixieIcon.pvr \ - build/ba_data/textures/jumpsuitColor.pvr \ - build/ba_data/textures/reflectionSharper_+x.pvr \ - build/ba_data/textures/jackColorMask.pvr \ - build/ba_data/textures/shrapnel1Color.pvr \ - build/ba_data/textures/witchColor.pvr \ - build/ba_data/textures/achievementFreeLoader.pvr \ - build/ba_data/textures/zoeColor.pvr \ - build/ba_data/textures/alienColor.pvr \ - build/ba_data/textures/inventoryIcon.pvr \ - build/ba_data/textures/reflectionSharp_-z.pvr \ - build/ba_data/textures/glow.pvr \ - build/ba_data/textures/usersButton.pvr \ - build/ba_data/textures/reflectionPowerup_-z.pvr \ - build/ba_data/textures/melColor.pvr \ - build/ba_data/textures/aliControllerQR.pvr \ - build/ba_data/textures/frostyIcon.pvr \ - build/ba_data/textures/achievementFootballVictory.pvr \ - build/ba_data/textures/tickets.pvr \ - build/ba_data/textures/cursor.pvr \ - build/ba_data/textures/egg3.pvr \ - build/ba_data/textures/crossOut.pvr \ - build/ba_data/textures/bonesColor.pvr \ build/ba_data/textures/achievementCrossHair.pvr \ + build/ba_data/textures/achievementDualWielding.pvr \ + build/ba_data/textures/achievementEmpty.pvr \ + build/ba_data/textures/achievementFlawlessVictory.pvr \ + build/ba_data/textures/achievementFootballShutout.pvr \ + build/ba_data/textures/achievementFootballVictory.pvr \ + build/ba_data/textures/achievementFreeLoader.pvr \ + build/ba_data/textures/achievementGotTheMoves.pvr \ + build/ba_data/textures/achievementInControl.pvr \ + build/ba_data/textures/achievementMedalLarge.pvr \ + build/ba_data/textures/achievementMedalMedium.pvr \ + build/ba_data/textures/achievementMedalSmall.pvr \ + build/ba_data/textures/achievementMine.pvr \ + build/ba_data/textures/achievementOffYouGo.pvr \ + build/ba_data/textures/achievementOnslaught.pvr \ + build/ba_data/textures/achievementOutline.pvr \ + build/ba_data/textures/achievementRunaround.pvr \ + build/ba_data/textures/achievementSharingIsCaring.pvr \ + build/ba_data/textures/achievementStayinAlive.pvr \ + build/ba_data/textures/achievementSuperPunch.pvr \ + build/ba_data/textures/achievementTNT.pvr \ + build/ba_data/textures/achievementTeamPlayer.pvr \ + build/ba_data/textures/achievementWall.pvr \ + build/ba_data/textures/achievementsIcon.pvr \ + build/ba_data/textures/actionButtons.pvr \ + build/ba_data/textures/actionHeroColor.pvr \ build/ba_data/textures/actionHeroColorMask.pvr \ - build/ba_data/textures/chTitleChar1.pvr \ - build/ba_data/textures/heart.pvr \ - build/ba_data/textures/fontExtras.pvr \ - build/ba_data/textures/penguinIconColorMask.pvr \ - build/ba_data/textures/eyeColorTintMask.pvr \ + build/ba_data/textures/actionHeroIcon.pvr \ + build/ba_data/textures/actionHeroIconColorMask.pvr \ + build/ba_data/textures/advancedIcon.pvr \ + build/ba_data/textures/agentColor.pvr \ + build/ba_data/textures/agentColorMask.pvr \ + build/ba_data/textures/agentIcon.pvr \ + build/ba_data/textures/agentIconColorMask.pvr \ + build/ba_data/textures/aliBSRemoteIOSQR.pvr \ + build/ba_data/textures/aliColor.pvr \ + build/ba_data/textures/aliColorMask.pvr \ + build/ba_data/textures/aliControllerQR.pvr \ build/ba_data/textures/aliIcon.pvr \ - build/ba_data/textures/chestIconMulti.pvr \ - build/ba_data/textures/reflectionSoft_-x.pvr \ - build/ba_data/textures/uiAtlas.pvr \ - build/ba_data/textures/reflectionSharpest_+y.pvr \ - build/ba_data/textures/cragCastleLevelColor.pvr \ - build/ba_data/textures/assassinColorMask.pvr \ - build/ba_data/textures/bridgitLevelColor.pvr \ - build/ba_data/textures/fontSmall6.pvr \ - build/ba_data/textures/towerDLevelColor.pvr \ - build/ba_data/textures/ouyaYButton.pvr \ - build/ba_data/textures/lightSharp.pvr \ - build/ba_data/textures/buttonSquare.pvr \ - build/ba_data/textures/softRect.pvr \ - build/ba_data/textures/powerupIceBombs.pvr \ - build/ba_data/textures/jackIconColorMask.pvr \ - build/ba_data/textures/audioIcon.pvr \ - build/ba_data/textures/tv.pvr \ - build/ba_data/textures/reflectionSharpest_-z.pvr \ - build/ba_data/textures/warriorIconColorMask.pvr \ - build/ba_data/textures/googlePlusSignInButton.pvr \ - build/ba_data/textures/circle.pvr \ - build/ba_data/textures/neoSpazIconColorMask.pvr \ - build/ba_data/textures/medalComplete.pvr \ + build/ba_data/textures/aliIconColorMask.pvr \ + build/ba_data/textures/aliSplash.pvr \ + build/ba_data/textures/alienColor.pvr \ + build/ba_data/textures/alienColorMask.pvr \ + build/ba_data/textures/alienIcon.pvr \ + build/ba_data/textures/alienIconColorMask.pvr \ + build/ba_data/textures/alwaysLandBGColor.pvr \ build/ba_data/textures/alwaysLandLevelColor.pvr \ build/ba_data/textures/alwaysLandPreview.pvr \ - build/ba_data/textures/egg4.pvr \ - build/ba_data/textures/wrestlerColorMask.pvr \ - build/ba_data/textures/superheroColorMask.pvr \ - build/ba_data/textures/gladiatorColor.pvr \ - build/ba_data/textures/aliBSRemoteIOSQR.pvr \ - build/ba_data/textures/bearColorMask.pvr \ - build/ba_data/textures/doomShroomLevelColor.pvr \ - build/ba_data/textures/powerupBomb.pvr \ - build/ba_data/textures/chestIcon.pvr \ - build/ba_data/textures/upButton.pvr \ - build/ba_data/textures/iconRunaround.pvr \ - build/ba_data/textures/doomShroomBGColor.pvr \ - build/ba_data/textures/superheroColor.pvr \ - build/ba_data/textures/landMine.pvr \ - build/ba_data/textures/buttonJump.pvr \ - build/ba_data/textures/sparks.pvr \ - build/ba_data/textures/explosion.pvr \ - build/ba_data/textures/tipTopLevelColor.pvr \ - build/ba_data/textures/bunnyIconColorMask.pvr \ - build/ba_data/textures/reflectionChar_+x.pvr \ - build/ba_data/textures/ticketsMore.pvr \ - build/ba_data/textures/pixieColorMask.pvr \ - build/ba_data/textures/medalSilver.pvr \ - build/ba_data/textures/neoSpazIcon.pvr \ - build/ba_data/textures/meter.pvr \ - build/ba_data/textures/scrollWidgetGlow.pvr \ - build/ba_data/textures/achievementFlawlessVictory.pvr \ - build/ba_data/textures/zigzagPreview.pvr \ - build/ba_data/textures/reflectionSharper_-z.pvr \ - build/ba_data/textures/alienColorMask.pvr \ - build/ba_data/textures/powerupShield.pvr \ - build/ba_data/textures/reflectionSharp_+x.pvr \ - build/ba_data/textures/chestIconEmpty.pvr \ - build/ba_data/textures/agentColorMask.pvr \ - build/ba_data/textures/reflectionPowerup_+x.pvr \ - build/ba_data/textures/witchIconColorMask.pvr \ - build/ba_data/textures/kronkColorMask.pvr \ - build/ba_data/textures/menuBG.pvr \ - build/ba_data/textures/fontSmall0.pvr \ + build/ba_data/textures/analogStick.pvr \ + build/ba_data/textures/arrow.pvr \ + build/ba_data/textures/assassinColor.pvr \ + build/ba_data/textures/assassinColorMask.pvr \ + build/ba_data/textures/assassinIcon.pvr \ build/ba_data/textures/assassinIconColorMask.pvr \ + build/ba_data/textures/audioIcon.pvr \ + build/ba_data/textures/backIcon.pvr \ + build/ba_data/textures/bar.pvr \ build/ba_data/textures/bearColor.pvr \ - build/ba_data/textures/operaSingerColor.pvr \ - build/ba_data/textures/rampageBGColor2.pvr \ - build/ba_data/textures/fuse.pvr \ - build/ba_data/textures/frostyColor.pvr \ - build/ba_data/textures/achievementSuperPunch.pvr \ - build/ba_data/textures/tipTopPreview.pvr \ - build/ba_data/textures/googlePlusIcon.pvr \ - build/ba_data/textures/powerupCurse.pvr \ - build/ba_data/textures/trophy.pvr \ + build/ba_data/textures/bearColorMask.pvr \ + build/ba_data/textures/bearIcon.pvr \ + build/ba_data/textures/bearIconColorMask.pvr \ + build/ba_data/textures/bg.pvr \ + build/ba_data/textures/bigG.pvr \ + build/ba_data/textures/bigGPreview.pvr \ + build/ba_data/textures/black.pvr \ + build/ba_data/textures/bombButton.pvr \ + build/ba_data/textures/bombColor.pvr \ + build/ba_data/textures/bombColorIce.pvr \ + build/ba_data/textures/bombStickyColor.pvr \ + build/ba_data/textures/bonesColor.pvr \ + build/ba_data/textures/bonesColorMask.pvr \ + build/ba_data/textures/bonesIcon.pvr \ + build/ba_data/textures/bonesIconColorMask.pvr \ + build/ba_data/textures/boxingGlovesColor.pvr \ + build/ba_data/textures/bridgitLevelColor.pvr \ + build/ba_data/textures/bridgitPreview.pvr \ + build/ba_data/textures/bunnyColor.pvr \ + build/ba_data/textures/bunnyColorMask.pvr \ + build/ba_data/textures/bunnyIcon.pvr \ + build/ba_data/textures/bunnyIconColorMask.pvr \ + build/ba_data/textures/buttonBomb.pvr \ + build/ba_data/textures/buttonJump.pvr \ + build/ba_data/textures/buttonPickUp.pvr \ + build/ba_data/textures/buttonPunch.pvr \ + build/ba_data/textures/buttonSquare.pvr \ + build/ba_data/textures/chTitleChar1.pvr \ + build/ba_data/textures/chTitleChar2.pvr \ + build/ba_data/textures/chTitleChar3.pvr \ + build/ba_data/textures/chTitleChar4.pvr \ + build/ba_data/textures/chTitleChar5.pvr \ + build/ba_data/textures/characterIconMask.pvr \ + build/ba_data/textures/chestIcon.pvr \ + build/ba_data/textures/chestIconEmpty.pvr \ + build/ba_data/textures/chestIconMulti.pvr \ + build/ba_data/textures/chestOpenIcon.pvr \ + build/ba_data/textures/circle.pvr \ + build/ba_data/textures/circleNoAlpha.pvr \ + build/ba_data/textures/circleOutline.pvr \ + build/ba_data/textures/circleOutlineNoAlpha.pvr \ + build/ba_data/textures/circleShadow.pvr \ + build/ba_data/textures/circleZigZag.pvr \ + build/ba_data/textures/coin.pvr \ + build/ba_data/textures/controllerIcon.pvr \ build/ba_data/textures/courtyardLevelColor.pvr \ - build/ba_data/textures/oldLadyColorMask.pvr \ - build/ba_data/textures/rampagePreview.pvr \ + build/ba_data/textures/courtyardPreview.pvr \ + build/ba_data/textures/cowboyColor.pvr \ + build/ba_data/textures/cowboyColorMask.pvr \ + build/ba_data/textures/cowboyIcon.pvr \ + build/ba_data/textures/cowboyIconColorMask.pvr \ + build/ba_data/textures/cragCastleLevelColor.pvr \ + build/ba_data/textures/cragCastlePreview.pvr \ + build/ba_data/textures/crossOut.pvr \ + build/ba_data/textures/crossOutMask.pvr \ + build/ba_data/textures/cursor.pvr \ build/ba_data/textures/cuteSpaz.pvr \ - build/ba_data/textures/lightSoft.pvr \ - build/ba_data/textures/reflectionSharper_+y.pvr \ - build/ba_data/textures/uiAtlas2.pvr \ + build/ba_data/textures/cyborgColor.pvr \ + build/ba_data/textures/cyborgColorMask.pvr \ + build/ba_data/textures/cyborgIcon.pvr \ + build/ba_data/textures/cyborgIconColorMask.pvr \ + build/ba_data/textures/doomShroomBGColor.pvr \ + build/ba_data/textures/doomShroomLevelColor.pvr \ + build/ba_data/textures/doomShroomPreview.pvr \ + build/ba_data/textures/downButton.pvr \ + build/ba_data/textures/egg1.pvr \ build/ba_data/textures/egg2.pvr \ - build/ba_data/textures/shadowSharp.pvr \ - build/ba_data/textures/tnt.pvr \ - build/ba_data/textures/actionHeroIcon.pvr \ - build/ba_data/textures/robotColorMask.pvr \ + build/ba_data/textures/egg3.pvr \ + build/ba_data/textures/egg4.pvr \ + build/ba_data/textures/eggTex1.pvr \ + build/ba_data/textures/eggTex2.pvr \ + build/ba_data/textures/eggTex3.pvr \ + build/ba_data/textures/empty.pvr \ + build/ba_data/textures/explosion.pvr \ + build/ba_data/textures/eyeColor.pvr \ + build/ba_data/textures/eyeColorTintMask.pvr \ + build/ba_data/textures/file.pvr \ + build/ba_data/textures/flagColor.pvr \ + build/ba_data/textures/flagPoleColor.pvr \ + build/ba_data/textures/folder.pvr \ + build/ba_data/textures/fontBig.pvr \ + build/ba_data/textures/fontExtras.pvr \ + build/ba_data/textures/fontExtras2.pvr \ + build/ba_data/textures/fontExtras3.pvr \ + build/ba_data/textures/fontExtras4.pvr \ + build/ba_data/textures/fontSmall0.pvr \ + build/ba_data/textures/fontSmall1.pvr \ + build/ba_data/textures/fontSmall2.pvr \ + build/ba_data/textures/fontSmall3.pvr \ + build/ba_data/textures/fontSmall4.pvr \ + build/ba_data/textures/fontSmall5.pvr \ + build/ba_data/textures/fontSmall6.pvr \ + build/ba_data/textures/fontSmall7.pvr \ + build/ba_data/textures/footballStadium.pvr \ + build/ba_data/textures/footballStadiumPreview.pvr \ + build/ba_data/textures/frameInset.pvr \ + build/ba_data/textures/frostyColor.pvr \ + build/ba_data/textures/frostyColorMask.pvr \ + build/ba_data/textures/frostyIcon.pvr \ + build/ba_data/textures/frostyIconColorMask.pvr \ + build/ba_data/textures/fuse.pvr \ + build/ba_data/textures/gameCenterIcon.pvr \ + build/ba_data/textures/gameCircleIcon.pvr \ + build/ba_data/textures/gladiatorColor.pvr \ + build/ba_data/textures/gladiatorColorMask.pvr \ + build/ba_data/textures/gladiatorIcon.pvr \ + build/ba_data/textures/gladiatorIconColorMask.pvr \ + build/ba_data/textures/glow.pvr \ + build/ba_data/textures/googlePlayAchievementsIcon.pvr \ + build/ba_data/textures/googlePlayGamesIcon.pvr \ + build/ba_data/textures/googlePlayLeaderboardsIcon.pvr \ + build/ba_data/textures/googlePlusIcon.pvr \ + build/ba_data/textures/googlePlusSignInButton.pvr \ + build/ba_data/textures/graphicsIcon.pvr \ + build/ba_data/textures/heart.pvr \ + build/ba_data/textures/hockeyStadium.pvr \ + build/ba_data/textures/hockeyStadiumPreview.pvr \ + build/ba_data/textures/iconOnslaught.pvr \ + build/ba_data/textures/iconRunaround.pvr \ + build/ba_data/textures/impactBombColor.pvr \ build/ba_data/textures/impactBombColorLit.pvr \ - build/ba_data/textures/achievementStayinAlive.pvr + build/ba_data/textures/inventoryIcon.pvr \ + build/ba_data/textures/jackColor.pvr \ + build/ba_data/textures/jackColorMask.pvr \ + build/ba_data/textures/jackIcon.pvr \ + build/ba_data/textures/jackIconColorMask.pvr \ + build/ba_data/textures/jumpsuitColor.pvr \ + build/ba_data/textures/jumpsuitColorMask.pvr \ + build/ba_data/textures/jumpsuitIcon.pvr \ + build/ba_data/textures/jumpsuitIconColorMask.pvr \ + build/ba_data/textures/kronk.pvr \ + build/ba_data/textures/kronkColorMask.pvr \ + build/ba_data/textures/kronkIcon.pvr \ + build/ba_data/textures/kronkIconColorMask.pvr \ + build/ba_data/textures/lakeFrigid.pvr \ + build/ba_data/textures/lakeFrigidPreview.pvr \ + build/ba_data/textures/lakeFrigidReflections.pvr \ + build/ba_data/textures/landMine.pvr \ + build/ba_data/textures/landMineLit.pvr \ + build/ba_data/textures/leaderboardsIcon.pvr \ + build/ba_data/textures/leftButton.pvr \ + build/ba_data/textures/levelIcon.pvr \ + build/ba_data/textures/light.pvr \ + build/ba_data/textures/lightSharp.pvr \ + build/ba_data/textures/lightSoft.pvr \ + build/ba_data/textures/lock.pvr \ + build/ba_data/textures/logIcon.pvr \ + build/ba_data/textures/logo.pvr \ + build/ba_data/textures/logoEaster.pvr \ + build/ba_data/textures/mapPreviewMask.pvr \ + build/ba_data/textures/medalBronze.pvr \ + build/ba_data/textures/medalComplete.pvr \ + build/ba_data/textures/medalGold.pvr \ + build/ba_data/textures/medalSilver.pvr \ + build/ba_data/textures/melColor.pvr \ + build/ba_data/textures/melColorMask.pvr \ + build/ba_data/textures/melIcon.pvr \ + build/ba_data/textures/melIconColorMask.pvr \ + build/ba_data/textures/menuBG.pvr \ + build/ba_data/textures/menuButton.pvr \ + build/ba_data/textures/menuIcon.pvr \ + build/ba_data/textures/meter.pvr \ + build/ba_data/textures/monkeyFaceLevelColor.pvr \ + build/ba_data/textures/monkeyFacePreview.pvr \ + build/ba_data/textures/multiplayerExamples.pvr \ + build/ba_data/textures/natureBackgroundColor.pvr \ + build/ba_data/textures/neoSpazColor.pvr \ + build/ba_data/textures/neoSpazColorMask.pvr \ + build/ba_data/textures/neoSpazIcon.pvr \ + build/ba_data/textures/neoSpazIconColorMask.pvr \ + build/ba_data/textures/nextLevelIcon.pvr \ + build/ba_data/textures/ninjaColor.pvr \ + build/ba_data/textures/ninjaColorMask.pvr \ + build/ba_data/textures/ninjaIcon.pvr \ + build/ba_data/textures/ninjaIconColorMask.pvr \ + build/ba_data/textures/nub.pvr \ + build/ba_data/textures/null.pvr \ + build/ba_data/textures/oldLadyColor.pvr \ + build/ba_data/textures/oldLadyColorMask.pvr \ + build/ba_data/textures/oldLadyIcon.pvr \ + build/ba_data/textures/oldLadyIconColorMask.pvr \ + build/ba_data/textures/operaSingerColor.pvr \ + build/ba_data/textures/operaSingerColorMask.pvr \ + build/ba_data/textures/operaSingerIcon.pvr \ + build/ba_data/textures/operaSingerIconColorMask.pvr \ + build/ba_data/textures/ouyaAButton.pvr \ + build/ba_data/textures/ouyaIcon.pvr \ + build/ba_data/textures/ouyaOButton.pvr \ + build/ba_data/textures/ouyaUButton.pvr \ + build/ba_data/textures/ouyaYButton.pvr \ + build/ba_data/textures/penguinColor.pvr \ + build/ba_data/textures/penguinColorMask.pvr \ + build/ba_data/textures/penguinIcon.pvr \ + build/ba_data/textures/penguinIconColorMask.pvr \ + build/ba_data/textures/pixieColor.pvr \ + build/ba_data/textures/pixieColorMask.pvr \ + build/ba_data/textures/pixieIcon.pvr \ + build/ba_data/textures/pixieIconColorMask.pvr \ + build/ba_data/textures/playerLineup.pvr \ + build/ba_data/textures/powerupBomb.pvr \ + build/ba_data/textures/powerupCurse.pvr \ + build/ba_data/textures/powerupHealth.pvr \ + build/ba_data/textures/powerupIceBombs.pvr \ + build/ba_data/textures/powerupImpactBombs.pvr \ + build/ba_data/textures/powerupLandMines.pvr \ + build/ba_data/textures/powerupPunch.pvr \ + build/ba_data/textures/powerupShield.pvr \ + build/ba_data/textures/powerupSpeed.pvr \ + build/ba_data/textures/powerupStickyBombs.pvr \ + build/ba_data/textures/puckColor.pvr \ + build/ba_data/textures/rampageBGColor.pvr \ + build/ba_data/textures/rampageBGColor2.pvr \ + build/ba_data/textures/rampageLevelColor.pvr \ + build/ba_data/textures/rampagePreview.pvr \ + build/ba_data/textures/reflectionChar_+x.pvr \ + build/ba_data/textures/reflectionChar_+y.pvr \ + build/ba_data/textures/reflectionChar_+z.pvr \ + build/ba_data/textures/reflectionChar_-x.pvr \ + build/ba_data/textures/reflectionChar_-y.pvr \ + build/ba_data/textures/reflectionChar_-z.pvr \ + build/ba_data/textures/reflectionPowerup_+x.pvr \ + build/ba_data/textures/reflectionPowerup_+y.pvr \ + build/ba_data/textures/reflectionPowerup_+z.pvr \ + build/ba_data/textures/reflectionPowerup_-x.pvr \ + build/ba_data/textures/reflectionPowerup_-y.pvr \ + build/ba_data/textures/reflectionPowerup_-z.pvr \ + build/ba_data/textures/reflectionSharp_+x.pvr \ + build/ba_data/textures/reflectionSharp_+y.pvr \ + build/ba_data/textures/reflectionSharp_+z.pvr \ + build/ba_data/textures/reflectionSharp_-x.pvr \ + build/ba_data/textures/reflectionSharp_-y.pvr \ + build/ba_data/textures/reflectionSharp_-z.pvr \ + build/ba_data/textures/reflectionSharper_+x.pvr \ + build/ba_data/textures/reflectionSharper_+y.pvr \ + build/ba_data/textures/reflectionSharper_+z.pvr \ + build/ba_data/textures/reflectionSharper_-x.pvr \ + build/ba_data/textures/reflectionSharper_-y.pvr \ + build/ba_data/textures/reflectionSharper_-z.pvr \ + build/ba_data/textures/reflectionSharpest_+x.pvr \ + build/ba_data/textures/reflectionSharpest_+y.pvr \ + build/ba_data/textures/reflectionSharpest_+z.pvr \ + build/ba_data/textures/reflectionSharpest_-x.pvr \ + build/ba_data/textures/reflectionSharpest_-y.pvr \ + build/ba_data/textures/reflectionSharpest_-z.pvr \ + build/ba_data/textures/reflectionSoft_+x.pvr \ + build/ba_data/textures/reflectionSoft_+y.pvr \ + build/ba_data/textures/reflectionSoft_+z.pvr \ + build/ba_data/textures/reflectionSoft_-x.pvr \ + build/ba_data/textures/reflectionSoft_-y.pvr \ + build/ba_data/textures/reflectionSoft_-z.pvr \ + build/ba_data/textures/replayIcon.pvr \ + build/ba_data/textures/rgbStripes.pvr \ + build/ba_data/textures/rightButton.pvr \ + build/ba_data/textures/robotColor.pvr \ + build/ba_data/textures/robotColorMask.pvr \ + build/ba_data/textures/robotIcon.pvr \ + build/ba_data/textures/robotIconColorMask.pvr \ + build/ba_data/textures/roundaboutLevelColor.pvr \ + build/ba_data/textures/roundaboutPreview.pvr \ + build/ba_data/textures/santaColor.pvr \ + build/ba_data/textures/santaColorMask.pvr \ + build/ba_data/textures/santaIcon.pvr \ + build/ba_data/textures/santaIconColorMask.pvr \ + build/ba_data/textures/scorch.pvr \ + build/ba_data/textures/scorchBig.pvr \ + build/ba_data/textures/scrollWidget.pvr \ + build/ba_data/textures/scrollWidgetGlow.pvr \ + build/ba_data/textures/settingsIcon.pvr \ + build/ba_data/textures/shadow.pvr \ + build/ba_data/textures/shadowSharp.pvr \ + build/ba_data/textures/shadowSoft.pvr \ + build/ba_data/textures/shield.pvr \ + build/ba_data/textures/shrapnel1Color.pvr \ + build/ba_data/textures/slash.pvr \ + build/ba_data/textures/smoke.pvr \ + build/ba_data/textures/softRect.pvr \ + build/ba_data/textures/softRect2.pvr \ + build/ba_data/textures/softRectVertical.pvr \ + build/ba_data/textures/sparks.pvr \ + build/ba_data/textures/star.pvr \ + build/ba_data/textures/startButton.pvr \ + build/ba_data/textures/stepRightUpLevelColor.pvr \ + build/ba_data/textures/stepRightUpPreview.pvr \ + build/ba_data/textures/storeCharacter.pvr \ + build/ba_data/textures/storeCharacterEaster.pvr \ + build/ba_data/textures/storeCharacterXmas.pvr \ + build/ba_data/textures/storeIcon.pvr \ + build/ba_data/textures/superheroColor.pvr \ + build/ba_data/textures/superheroColorMask.pvr \ + build/ba_data/textures/superheroIcon.pvr \ + build/ba_data/textures/superheroIconColorMask.pvr \ + build/ba_data/textures/textClearButton.pvr \ + build/ba_data/textures/thePadLevelColor.pvr \ + build/ba_data/textures/thePadPreview.pvr \ + build/ba_data/textures/ticketRoll.pvr \ + build/ba_data/textures/ticketRollBig.pvr \ + build/ba_data/textures/ticketRolls.pvr \ + build/ba_data/textures/tickets.pvr \ + build/ba_data/textures/ticketsMore.pvr \ + build/ba_data/textures/tipTopBGColor.pvr \ + build/ba_data/textures/tipTopLevelColor.pvr \ + build/ba_data/textures/tipTopPreview.pvr \ + build/ba_data/textures/tnt.pvr \ + build/ba_data/textures/touchArrows.pvr \ + build/ba_data/textures/touchArrowsActions.pvr \ + build/ba_data/textures/towerDLevelColor.pvr \ + build/ba_data/textures/towerDPreview.pvr \ + build/ba_data/textures/treesColor.pvr \ + build/ba_data/textures/trophy.pvr \ + build/ba_data/textures/tv.pvr \ + build/ba_data/textures/uiAtlas.pvr \ + build/ba_data/textures/uiAtlas2.pvr \ + build/ba_data/textures/upButton.pvr \ + build/ba_data/textures/usersButton.pvr \ + build/ba_data/textures/vrFillMound.pvr \ + build/ba_data/textures/warriorColor.pvr \ + build/ba_data/textures/warriorColorMask.pvr \ + build/ba_data/textures/warriorIcon.pvr \ + build/ba_data/textures/warriorIconColorMask.pvr \ + build/ba_data/textures/white.pvr \ + build/ba_data/textures/windowHSmallVMed.pvr \ + build/ba_data/textures/windowHSmallVSmall.pvr \ + build/ba_data/textures/wings.pvr \ + build/ba_data/textures/witchColor.pvr \ + build/ba_data/textures/witchColorMask.pvr \ + build/ba_data/textures/witchIcon.pvr \ + build/ba_data/textures/witchIconColorMask.pvr \ + build/ba_data/textures/wizardColor.pvr \ + build/ba_data/textures/wizardColorMask.pvr \ + build/ba_data/textures/wizardIcon.pvr \ + build/ba_data/textures/wizardIconColorMask.pvr \ + build/ba_data/textures/wrestlerColor.pvr \ + build/ba_data/textures/wrestlerColorMask.pvr \ + build/ba_data/textures/wrestlerIcon.pvr \ + build/ba_data/textures/wrestlerIconColorMask.pvr \ + build/ba_data/textures/zigZagLevelColor.pvr \ + build/ba_data/textures/zigzagPreview.pvr \ + build/ba_data/textures/zoeColor.pvr \ + build/ba_data/textures/zoeColorMask.pvr \ + build/ba_data/textures/zoeIcon.pvr \ + build/ba_data/textures/zoeIconColorMask.pvr TEX2D_KTX_TARGETS = \ - build/ba_data/textures/cyborgIconColorMask.ktx \ - build/ba_data/textures/chestOpenIcon.ktx \ - build/ba_data/textures/analogStick.ktx \ - build/ba_data/textures/circleOutline.ktx \ - build/ba_data/textures/white.ktx \ - build/ba_data/textures/medalBronze.ktx \ - build/ba_data/textures/slash.ktx \ - build/ba_data/textures/arrow.ktx \ - build/ba_data/textures/ouyaIcon.ktx \ - build/ba_data/textures/eyeColor.ktx \ - build/ba_data/textures/achievementMedalLarge.ktx \ - build/ba_data/textures/cowboyIconColorMask.ktx \ - build/ba_data/textures/wings.ktx \ - build/ba_data/textures/roundaboutPreview.ktx \ - build/ba_data/textures/warriorIcon.ktx \ - build/ba_data/textures/windowHSmallVMed.ktx \ - build/ba_data/textures/ninjaIconColorMask.ktx \ - build/ba_data/textures/reflectionSharpest_+z.ktx \ - build/ba_data/textures/stepRightUpLevelColor.ktx \ - build/ba_data/textures/fontSmall5.ktx \ - build/ba_data/textures/bombButton.ktx \ - build/ba_data/textures/aliIconColorMask.ktx \ - build/ba_data/textures/chTitleChar2.ktx \ - build/ba_data/textures/achievementOnslaught.ktx \ - build/ba_data/textures/smoke.ktx \ - build/ba_data/textures/lakeFrigidReflections.ktx \ - build/ba_data/textures/bunnyColor.ktx \ - build/ba_data/textures/leftButton.ktx \ - build/ba_data/textures/hockeyStadium.ktx \ - build/ba_data/textures/cowboyIcon.ktx \ - build/ba_data/textures/lakeFrigid.ktx \ - build/ba_data/textures/startButton.ktx \ - build/ba_data/textures/footballStadium.ktx \ - build/ba_data/textures/crossOutMask.ktx \ - build/ba_data/textures/bonesIconColorMask.ktx \ - build/ba_data/textures/operaSingerIconColorMask.ktx \ - build/ba_data/textures/lakeFrigidPreview.ktx \ - build/ba_data/textures/alienIcon.ktx \ - build/ba_data/textures/oldLadyColor.ktx \ - build/ba_data/textures/ouyaAButton.ktx \ - build/ba_data/textures/eggTex3.ktx \ - build/ba_data/textures/cyborgIcon.ktx \ - build/ba_data/textures/actionHeroColor.ktx \ - build/ba_data/textures/achievementTeamPlayer.ktx \ - build/ba_data/textures/reflectionSoft_+x.ktx \ - build/ba_data/textures/fontExtras3.ktx \ - build/ba_data/textures/buttonBomb.ktx \ - build/ba_data/textures/star.ktx \ - build/ba_data/textures/reflectionSharpest_-y.ktx \ - build/ba_data/textures/achievementSharingIsCaring.ktx \ - build/ba_data/textures/fontSmall3.ktx \ - build/ba_data/textures/powerupSpeed.ktx \ - build/ba_data/textures/vrFillMound.ktx \ - build/ba_data/textures/agentIconColorMask.ktx \ - build/ba_data/textures/kronkIcon.ktx \ - build/ba_data/textures/oldLadyIcon.ktx \ - build/ba_data/textures/chTitleChar4.ktx \ - build/ba_data/textures/nextLevelIcon.ktx \ - build/ba_data/textures/gameCircleIcon.ktx \ - build/ba_data/textures/bonesIcon.ktx \ - build/ba_data/textures/bearIcon.ktx \ - build/ba_data/textures/towerDPreview.ktx \ - build/ba_data/textures/achievementTNT.ktx \ - build/ba_data/textures/medalGold.ktx \ - build/ba_data/textures/circleZigZag.ktx \ - build/ba_data/textures/bunnyColorMask.ktx \ - build/ba_data/textures/black.ktx \ - build/ba_data/textures/menuIcon.ktx \ - build/ba_data/textures/file.ktx \ - build/ba_data/textures/logIcon.ktx \ - build/ba_data/textures/controllerIcon.ktx \ - build/ba_data/textures/reflectionSharper_-y.ktx \ - build/ba_data/textures/operaSingerColorMask.ktx \ - build/ba_data/textures/achievementFootballShutout.ktx \ - build/ba_data/textures/reflectionPowerup_-x.ktx \ - build/ba_data/textures/achievementsIcon.ktx \ - build/ba_data/textures/cowboyColor.ktx \ - build/ba_data/textures/wrestlerIconColorMask.ktx \ - build/ba_data/textures/googlePlayAchievementsIcon.ktx \ - build/ba_data/textures/alienIconColorMask.ktx \ - build/ba_data/textures/ticketRollBig.ktx \ - build/ba_data/textures/wrestlerIcon.ktx \ - build/ba_data/textures/egg1.ktx \ - build/ba_data/textures/gameCenterIcon.ktx \ - build/ba_data/textures/landMineLit.ktx \ - build/ba_data/textures/achievementWall.ktx \ - build/ba_data/textures/achievementMedalMedium.ktx \ - build/ba_data/textures/reflectionChar_-x.ktx \ - build/ba_data/textures/softRectVertical.ktx \ - build/ba_data/textures/reflectionSharper_+z.ktx \ - build/ba_data/textures/wizardIcon.ktx \ - build/ba_data/textures/mapPreviewMask.ktx \ - build/ba_data/textures/nub.ktx \ - build/ba_data/textures/empty.ktx \ - build/ba_data/textures/frostyIconColorMask.ktx \ - build/ba_data/textures/reflectionSharp_-x.ktx \ - build/ba_data/textures/bombColorIce.ktx \ - build/ba_data/textures/jumpsuitIcon.ktx \ - build/ba_data/textures/footballStadiumPreview.ktx \ - build/ba_data/textures/pixieIconColorMask.ktx \ - build/ba_data/textures/achievementEmpty.ktx \ - build/ba_data/textures/wrestlerColor.ktx \ - build/ba_data/textures/shield.ktx \ - build/ba_data/textures/iconOnslaught.ktx \ - build/ba_data/textures/replayIcon.ktx \ - build/ba_data/textures/powerupHealth.ktx \ - build/ba_data/textures/bg.ktx \ - build/ba_data/textures/chTitleChar3.ktx \ - build/ba_data/textures/textClearButton.ktx \ - build/ba_data/textures/reflectionSoft_-z.ktx \ - build/ba_data/textures/fontSmall4.ktx \ - build/ba_data/textures/warriorColor.ktx \ - build/ba_data/textures/light.ktx \ - build/ba_data/textures/santaColor.ktx \ - build/ba_data/textures/jackColor.ktx \ - build/ba_data/textures/aliSplash.ktx \ - build/ba_data/textures/scorch.ktx \ - build/ba_data/textures/zoeIcon.ktx \ - build/ba_data/textures/bonesColorMask.ktx \ - build/ba_data/textures/pixieColor.ktx \ - build/ba_data/textures/actionHeroIconColorMask.ktx \ - build/ba_data/textures/treesColor.ktx \ - build/ba_data/textures/neoSpazColorMask.ktx \ - build/ba_data/textures/superheroIcon.ktx \ - build/ba_data/textures/achievementOffYouGo.ktx \ - build/ba_data/textures/tipTopBGColor.ktx \ - build/ba_data/textures/robotColor.ktx \ - build/ba_data/textures/reflectionSharpest_-x.ktx \ - build/ba_data/textures/menuButton.ktx \ - build/ba_data/textures/powerupStickyBombs.ktx \ - build/ba_data/textures/ninjaIcon.ktx \ - build/ba_data/textures/witchColorMask.ktx \ - build/ba_data/textures/cowboyColorMask.ktx \ - build/ba_data/textures/operaSingerIcon.ktx \ build/ba_data/textures/achievementBoxer.ktx \ - build/ba_data/textures/eggTex2.ktx \ - build/ba_data/textures/rampageBGColor.ktx \ - build/ba_data/textures/fontExtras2.ktx \ - build/ba_data/textures/rampageLevelColor.ktx \ - build/ba_data/textures/reflectionSoft_+y.ktx \ - build/ba_data/textures/ticketRolls.ktx \ - build/ba_data/textures/natureBackgroundColor.ktx \ - build/ba_data/textures/santaIconColorMask.ktx \ - build/ba_data/textures/reflectionPowerup_+z.ktx \ - build/ba_data/textures/characterIconMask.ktx \ - build/ba_data/textures/aliColor.ktx \ - build/ba_data/textures/ninjaColorMask.ktx \ - build/ba_data/textures/buttonPickUp.ktx \ - build/ba_data/textures/chTitleChar5.ktx \ - build/ba_data/textures/bigGPreview.ktx \ - build/ba_data/textures/hockeyStadiumPreview.ktx \ - build/ba_data/textures/achievementMedalSmall.ktx \ - build/ba_data/textures/fontSmall2.ktx \ - build/ba_data/textures/achievementOutline.ktx \ - build/ba_data/textures/levelIcon.ktx \ - build/ba_data/textures/googlePlayGamesIcon.ktx \ - build/ba_data/textures/gladiatorColorMask.ktx \ - build/ba_data/textures/boxingGlovesColor.ktx \ - build/ba_data/textures/ouyaOButton.ktx \ - build/ba_data/textures/leaderboardsIcon.ktx \ - build/ba_data/textures/puckColor.ktx \ - build/ba_data/textures/reflectionChar_+z.ktx \ - build/ba_data/textures/penguinColor.ktx \ - build/ba_data/textures/reflectionSharper_-x.ktx \ - build/ba_data/textures/googlePlayLeaderboardsIcon.ktx \ - build/ba_data/textures/scrollWidget.ktx \ - build/ba_data/textures/courtyardPreview.ktx \ - build/ba_data/textures/aliColorMask.ktx \ - build/ba_data/textures/penguinColorMask.ktx \ - build/ba_data/textures/witchIcon.ktx \ - build/ba_data/textures/reflectionSharp_+z.ktx \ - build/ba_data/textures/graphicsIcon.ktx \ - build/ba_data/textures/agentIcon.ktx \ - build/ba_data/textures/fontExtras4.ktx \ - build/ba_data/textures/reflectionPowerup_-y.ktx \ - build/ba_data/textures/storeIcon.ktx \ - build/ba_data/textures/doomShroomPreview.ktx \ - build/ba_data/textures/null.ktx \ - build/ba_data/textures/backIcon.ktx \ - build/ba_data/textures/cyborgColor.ktx \ - build/ba_data/textures/monkeyFaceLevelColor.ktx \ - build/ba_data/textures/santaIcon.ktx \ - build/ba_data/textures/alwaysLandBGColor.ktx \ - build/ba_data/textures/roundaboutLevelColor.ktx \ - build/ba_data/textures/robotIcon.ktx \ - build/ba_data/textures/reflectionSharp_-y.ktx \ - build/ba_data/textures/bunnyIcon.ktx \ - build/ba_data/textures/circleShadow.ktx \ - build/ba_data/textures/flagPoleColor.ktx \ - build/ba_data/textures/ouyaUButton.ktx \ - build/ba_data/textures/reflectionChar_-y.ktx \ - build/ba_data/textures/achievementInControl.ktx \ - build/ba_data/textures/wizardColorMask.ktx \ - build/ba_data/textures/reflectionSharpest_+x.ktx \ - build/ba_data/textures/neoSpazColor.ktx \ - build/ba_data/textures/zigZagLevelColor.ktx \ - build/ba_data/textures/thePadPreview.ktx \ - build/ba_data/textures/superheroIconColorMask.ktx \ - build/ba_data/textures/fontSmall7.ktx \ - build/ba_data/textures/ticketRoll.ktx \ - build/ba_data/textures/reflectionSoft_-y.ktx \ - build/ba_data/textures/playerLineup.ktx \ - build/ba_data/textures/storeCharacterEaster.ktx \ - build/ba_data/textures/coin.ktx \ - build/ba_data/textures/circleOutlineNoAlpha.ktx \ - build/ba_data/textures/scorchBig.ktx \ - build/ba_data/textures/logoEaster.ktx \ - build/ba_data/textures/warriorColorMask.ktx \ - build/ba_data/textures/assassinColor.ktx \ - build/ba_data/textures/bombStickyColor.ktx \ - build/ba_data/textures/eggTex1.ktx \ - build/ba_data/textures/gladiatorIconColorMask.ktx \ - build/ba_data/textures/melColorMask.ktx \ - build/ba_data/textures/thePadLevelColor.ktx \ - build/ba_data/textures/wizardIconColorMask.ktx \ - build/ba_data/textures/bar.ktx \ - build/ba_data/textures/zoeIconColorMask.ktx \ - build/ba_data/textures/windowHSmallVSmall.ktx \ - build/ba_data/textures/circleNoAlpha.ktx \ - build/ba_data/textures/gladiatorIcon.ktx \ - build/ba_data/textures/reflectionSoft_+z.ktx \ - build/ba_data/textures/achievementRunaround.ktx \ - build/ba_data/textures/wizardColor.ktx \ - build/ba_data/textures/touchArrowsActions.ktx \ - build/ba_data/textures/advancedIcon.ktx \ - build/ba_data/textures/softRect2.ktx \ - build/ba_data/textures/achievementMine.ktx \ - build/ba_data/textures/rightButton.ktx \ - build/ba_data/textures/touchArrows.ktx \ - build/ba_data/textures/cyborgColorMask.ktx \ - build/ba_data/textures/jumpsuitIconColorMask.ktx \ - build/ba_data/textures/bridgitPreview.ktx \ - build/ba_data/textures/ninjaColor.ktx \ - build/ba_data/textures/santaColorMask.ktx \ - build/ba_data/textures/storeCharacter.ktx \ - build/ba_data/textures/flagColor.ktx \ - build/ba_data/textures/cragCastlePreview.ktx \ - build/ba_data/textures/frameInset.ktx \ - build/ba_data/textures/lock.ktx \ - build/ba_data/textures/agentColor.ktx \ - build/ba_data/textures/achievementGotTheMoves.ktx \ - build/ba_data/textures/buttonPunch.ktx \ - build/ba_data/textures/settingsIcon.ktx \ - build/ba_data/textures/rgbStripes.ktx \ - build/ba_data/textures/reflectionSharp_+y.ktx \ - build/ba_data/textures/powerupImpactBombs.ktx \ - build/ba_data/textures/bigG.ktx \ - build/ba_data/textures/melIconColorMask.ktx \ - build/ba_data/textures/reflectionChar_+y.ktx \ - build/ba_data/textures/multiplayerExamples.ktx \ - build/ba_data/textures/actionButtons.ktx \ - build/ba_data/textures/melIcon.ktx \ - build/ba_data/textures/oldLadyIconColorMask.ktx \ - build/ba_data/textures/robotIconColorMask.ktx \ - build/ba_data/textures/monkeyFacePreview.ktx \ - build/ba_data/textures/achievementDualWielding.ktx \ - build/ba_data/textures/folder.ktx \ - build/ba_data/textures/frostyColorMask.ktx \ - build/ba_data/textures/kronkIconColorMask.ktx \ - build/ba_data/textures/fontBig.ktx \ - build/ba_data/textures/fontSmall1.ktx \ - build/ba_data/textures/shadowSoft.ktx \ - build/ba_data/textures/powerupLandMines.ktx \ - build/ba_data/textures/stepRightUpPreview.ktx \ - build/ba_data/textures/bearIconColorMask.ktx \ - build/ba_data/textures/kronk.ktx \ - build/ba_data/textures/downButton.ktx \ - build/ba_data/textures/bombColor.ktx \ - build/ba_data/textures/logo.ktx \ - build/ba_data/textures/reflectionPowerup_+y.ktx \ - build/ba_data/textures/zoeColorMask.ktx \ - build/ba_data/textures/jumpsuitColorMask.ktx \ - build/ba_data/textures/penguinIcon.ktx \ - build/ba_data/textures/powerupPunch.ktx \ - build/ba_data/textures/shadow.ktx \ - build/ba_data/textures/reflectionChar_-z.ktx \ - build/ba_data/textures/assassinIcon.ktx \ - build/ba_data/textures/impactBombColor.ktx \ - build/ba_data/textures/storeCharacterXmas.ktx \ - build/ba_data/textures/jackIcon.ktx \ - build/ba_data/textures/pixieIcon.ktx \ - build/ba_data/textures/jumpsuitColor.ktx \ - build/ba_data/textures/reflectionSharper_+x.ktx \ - build/ba_data/textures/jackColorMask.ktx \ - build/ba_data/textures/shrapnel1Color.ktx \ - build/ba_data/textures/witchColor.ktx \ - build/ba_data/textures/achievementFreeLoader.ktx \ - build/ba_data/textures/zoeColor.ktx \ - build/ba_data/textures/alienColor.ktx \ - build/ba_data/textures/inventoryIcon.ktx \ - build/ba_data/textures/reflectionSharp_-z.ktx \ - build/ba_data/textures/glow.ktx \ - build/ba_data/textures/usersButton.ktx \ - build/ba_data/textures/reflectionPowerup_-z.ktx \ - build/ba_data/textures/melColor.ktx \ - build/ba_data/textures/aliControllerQR.ktx \ - build/ba_data/textures/frostyIcon.ktx \ - build/ba_data/textures/achievementFootballVictory.ktx \ - build/ba_data/textures/tickets.ktx \ - build/ba_data/textures/cursor.ktx \ - build/ba_data/textures/egg3.ktx \ - build/ba_data/textures/crossOut.ktx \ - build/ba_data/textures/bonesColor.ktx \ build/ba_data/textures/achievementCrossHair.ktx \ + build/ba_data/textures/achievementDualWielding.ktx \ + build/ba_data/textures/achievementEmpty.ktx \ + build/ba_data/textures/achievementFlawlessVictory.ktx \ + build/ba_data/textures/achievementFootballShutout.ktx \ + build/ba_data/textures/achievementFootballVictory.ktx \ + build/ba_data/textures/achievementFreeLoader.ktx \ + build/ba_data/textures/achievementGotTheMoves.ktx \ + build/ba_data/textures/achievementInControl.ktx \ + build/ba_data/textures/achievementMedalLarge.ktx \ + build/ba_data/textures/achievementMedalMedium.ktx \ + build/ba_data/textures/achievementMedalSmall.ktx \ + build/ba_data/textures/achievementMine.ktx \ + build/ba_data/textures/achievementOffYouGo.ktx \ + build/ba_data/textures/achievementOnslaught.ktx \ + build/ba_data/textures/achievementOutline.ktx \ + build/ba_data/textures/achievementRunaround.ktx \ + build/ba_data/textures/achievementSharingIsCaring.ktx \ + build/ba_data/textures/achievementStayinAlive.ktx \ + build/ba_data/textures/achievementSuperPunch.ktx \ + build/ba_data/textures/achievementTNT.ktx \ + build/ba_data/textures/achievementTeamPlayer.ktx \ + build/ba_data/textures/achievementWall.ktx \ + build/ba_data/textures/achievementsIcon.ktx \ + build/ba_data/textures/actionButtons.ktx \ + build/ba_data/textures/actionHeroColor.ktx \ build/ba_data/textures/actionHeroColorMask.ktx \ - build/ba_data/textures/chTitleChar1.ktx \ - build/ba_data/textures/heart.ktx \ - build/ba_data/textures/fontExtras.ktx \ - build/ba_data/textures/penguinIconColorMask.ktx \ - build/ba_data/textures/eyeColorTintMask.ktx \ + build/ba_data/textures/actionHeroIcon.ktx \ + build/ba_data/textures/actionHeroIconColorMask.ktx \ + build/ba_data/textures/advancedIcon.ktx \ + build/ba_data/textures/agentColor.ktx \ + build/ba_data/textures/agentColorMask.ktx \ + build/ba_data/textures/agentIcon.ktx \ + build/ba_data/textures/agentIconColorMask.ktx \ + build/ba_data/textures/aliBSRemoteIOSQR.ktx \ + build/ba_data/textures/aliColor.ktx \ + build/ba_data/textures/aliColorMask.ktx \ + build/ba_data/textures/aliControllerQR.ktx \ build/ba_data/textures/aliIcon.ktx \ - build/ba_data/textures/chestIconMulti.ktx \ - build/ba_data/textures/reflectionSoft_-x.ktx \ - build/ba_data/textures/uiAtlas.ktx \ - build/ba_data/textures/reflectionSharpest_+y.ktx \ - build/ba_data/textures/cragCastleLevelColor.ktx \ - build/ba_data/textures/assassinColorMask.ktx \ - build/ba_data/textures/bridgitLevelColor.ktx \ - build/ba_data/textures/fontSmall6.ktx \ - build/ba_data/textures/towerDLevelColor.ktx \ - build/ba_data/textures/ouyaYButton.ktx \ - build/ba_data/textures/lightSharp.ktx \ - build/ba_data/textures/buttonSquare.ktx \ - build/ba_data/textures/softRect.ktx \ - build/ba_data/textures/powerupIceBombs.ktx \ - build/ba_data/textures/jackIconColorMask.ktx \ - build/ba_data/textures/audioIcon.ktx \ - build/ba_data/textures/tv.ktx \ - build/ba_data/textures/reflectionSharpest_-z.ktx \ - build/ba_data/textures/warriorIconColorMask.ktx \ - build/ba_data/textures/googlePlusSignInButton.ktx \ - build/ba_data/textures/circle.ktx \ - build/ba_data/textures/neoSpazIconColorMask.ktx \ - build/ba_data/textures/medalComplete.ktx \ + build/ba_data/textures/aliIconColorMask.ktx \ + build/ba_data/textures/aliSplash.ktx \ + build/ba_data/textures/alienColor.ktx \ + build/ba_data/textures/alienColorMask.ktx \ + build/ba_data/textures/alienIcon.ktx \ + build/ba_data/textures/alienIconColorMask.ktx \ + build/ba_data/textures/alwaysLandBGColor.ktx \ build/ba_data/textures/alwaysLandLevelColor.ktx \ build/ba_data/textures/alwaysLandPreview.ktx \ - build/ba_data/textures/egg4.ktx \ - build/ba_data/textures/wrestlerColorMask.ktx \ - build/ba_data/textures/superheroColorMask.ktx \ - build/ba_data/textures/gladiatorColor.ktx \ - build/ba_data/textures/aliBSRemoteIOSQR.ktx \ - build/ba_data/textures/bearColorMask.ktx \ - build/ba_data/textures/doomShroomLevelColor.ktx \ - build/ba_data/textures/powerupBomb.ktx \ - build/ba_data/textures/chestIcon.ktx \ - build/ba_data/textures/upButton.ktx \ - build/ba_data/textures/iconRunaround.ktx \ - build/ba_data/textures/doomShroomBGColor.ktx \ - build/ba_data/textures/superheroColor.ktx \ - build/ba_data/textures/landMine.ktx \ - build/ba_data/textures/buttonJump.ktx \ - build/ba_data/textures/sparks.ktx \ - build/ba_data/textures/explosion.ktx \ - build/ba_data/textures/tipTopLevelColor.ktx \ - build/ba_data/textures/bunnyIconColorMask.ktx \ - build/ba_data/textures/reflectionChar_+x.ktx \ - build/ba_data/textures/ticketsMore.ktx \ - build/ba_data/textures/pixieColorMask.ktx \ - build/ba_data/textures/medalSilver.ktx \ - build/ba_data/textures/neoSpazIcon.ktx \ - build/ba_data/textures/meter.ktx \ - build/ba_data/textures/scrollWidgetGlow.ktx \ - build/ba_data/textures/achievementFlawlessVictory.ktx \ - build/ba_data/textures/zigzagPreview.ktx \ - build/ba_data/textures/reflectionSharper_-z.ktx \ - build/ba_data/textures/alienColorMask.ktx \ - build/ba_data/textures/powerupShield.ktx \ - build/ba_data/textures/reflectionSharp_+x.ktx \ - build/ba_data/textures/chestIconEmpty.ktx \ - build/ba_data/textures/agentColorMask.ktx \ - build/ba_data/textures/reflectionPowerup_+x.ktx \ - build/ba_data/textures/witchIconColorMask.ktx \ - build/ba_data/textures/kronkColorMask.ktx \ - build/ba_data/textures/menuBG.ktx \ - build/ba_data/textures/fontSmall0.ktx \ + build/ba_data/textures/analogStick.ktx \ + build/ba_data/textures/arrow.ktx \ + build/ba_data/textures/assassinColor.ktx \ + build/ba_data/textures/assassinColorMask.ktx \ + build/ba_data/textures/assassinIcon.ktx \ build/ba_data/textures/assassinIconColorMask.ktx \ + build/ba_data/textures/audioIcon.ktx \ + build/ba_data/textures/backIcon.ktx \ + build/ba_data/textures/bar.ktx \ build/ba_data/textures/bearColor.ktx \ - build/ba_data/textures/operaSingerColor.ktx \ - build/ba_data/textures/rampageBGColor2.ktx \ - build/ba_data/textures/fuse.ktx \ - build/ba_data/textures/frostyColor.ktx \ - build/ba_data/textures/achievementSuperPunch.ktx \ - build/ba_data/textures/tipTopPreview.ktx \ - build/ba_data/textures/googlePlusIcon.ktx \ - build/ba_data/textures/powerupCurse.ktx \ - build/ba_data/textures/trophy.ktx \ + build/ba_data/textures/bearColorMask.ktx \ + build/ba_data/textures/bearIcon.ktx \ + build/ba_data/textures/bearIconColorMask.ktx \ + build/ba_data/textures/bg.ktx \ + build/ba_data/textures/bigG.ktx \ + build/ba_data/textures/bigGPreview.ktx \ + build/ba_data/textures/black.ktx \ + build/ba_data/textures/bombButton.ktx \ + build/ba_data/textures/bombColor.ktx \ + build/ba_data/textures/bombColorIce.ktx \ + build/ba_data/textures/bombStickyColor.ktx \ + build/ba_data/textures/bonesColor.ktx \ + build/ba_data/textures/bonesColorMask.ktx \ + build/ba_data/textures/bonesIcon.ktx \ + build/ba_data/textures/bonesIconColorMask.ktx \ + build/ba_data/textures/boxingGlovesColor.ktx \ + build/ba_data/textures/bridgitLevelColor.ktx \ + build/ba_data/textures/bridgitPreview.ktx \ + build/ba_data/textures/bunnyColor.ktx \ + build/ba_data/textures/bunnyColorMask.ktx \ + build/ba_data/textures/bunnyIcon.ktx \ + build/ba_data/textures/bunnyIconColorMask.ktx \ + build/ba_data/textures/buttonBomb.ktx \ + build/ba_data/textures/buttonJump.ktx \ + build/ba_data/textures/buttonPickUp.ktx \ + build/ba_data/textures/buttonPunch.ktx \ + build/ba_data/textures/buttonSquare.ktx \ + build/ba_data/textures/chTitleChar1.ktx \ + build/ba_data/textures/chTitleChar2.ktx \ + build/ba_data/textures/chTitleChar3.ktx \ + build/ba_data/textures/chTitleChar4.ktx \ + build/ba_data/textures/chTitleChar5.ktx \ + build/ba_data/textures/characterIconMask.ktx \ + build/ba_data/textures/chestIcon.ktx \ + build/ba_data/textures/chestIconEmpty.ktx \ + build/ba_data/textures/chestIconMulti.ktx \ + build/ba_data/textures/chestOpenIcon.ktx \ + build/ba_data/textures/circle.ktx \ + build/ba_data/textures/circleNoAlpha.ktx \ + build/ba_data/textures/circleOutline.ktx \ + build/ba_data/textures/circleOutlineNoAlpha.ktx \ + build/ba_data/textures/circleShadow.ktx \ + build/ba_data/textures/circleZigZag.ktx \ + build/ba_data/textures/coin.ktx \ + build/ba_data/textures/controllerIcon.ktx \ build/ba_data/textures/courtyardLevelColor.ktx \ - build/ba_data/textures/oldLadyColorMask.ktx \ - build/ba_data/textures/rampagePreview.ktx \ + build/ba_data/textures/courtyardPreview.ktx \ + build/ba_data/textures/cowboyColor.ktx \ + build/ba_data/textures/cowboyColorMask.ktx \ + build/ba_data/textures/cowboyIcon.ktx \ + build/ba_data/textures/cowboyIconColorMask.ktx \ + build/ba_data/textures/cragCastleLevelColor.ktx \ + build/ba_data/textures/cragCastlePreview.ktx \ + build/ba_data/textures/crossOut.ktx \ + build/ba_data/textures/crossOutMask.ktx \ + build/ba_data/textures/cursor.ktx \ build/ba_data/textures/cuteSpaz.ktx \ - build/ba_data/textures/lightSoft.ktx \ - build/ba_data/textures/reflectionSharper_+y.ktx \ - build/ba_data/textures/uiAtlas2.ktx \ + build/ba_data/textures/cyborgColor.ktx \ + build/ba_data/textures/cyborgColorMask.ktx \ + build/ba_data/textures/cyborgIcon.ktx \ + build/ba_data/textures/cyborgIconColorMask.ktx \ + build/ba_data/textures/doomShroomBGColor.ktx \ + build/ba_data/textures/doomShroomLevelColor.ktx \ + build/ba_data/textures/doomShroomPreview.ktx \ + build/ba_data/textures/downButton.ktx \ + build/ba_data/textures/egg1.ktx \ build/ba_data/textures/egg2.ktx \ - build/ba_data/textures/shadowSharp.ktx \ - build/ba_data/textures/tnt.ktx \ - build/ba_data/textures/actionHeroIcon.ktx \ - build/ba_data/textures/robotColorMask.ktx \ + build/ba_data/textures/egg3.ktx \ + build/ba_data/textures/egg4.ktx \ + build/ba_data/textures/eggTex1.ktx \ + build/ba_data/textures/eggTex2.ktx \ + build/ba_data/textures/eggTex3.ktx \ + build/ba_data/textures/empty.ktx \ + build/ba_data/textures/explosion.ktx \ + build/ba_data/textures/eyeColor.ktx \ + build/ba_data/textures/eyeColorTintMask.ktx \ + build/ba_data/textures/file.ktx \ + build/ba_data/textures/flagColor.ktx \ + build/ba_data/textures/flagPoleColor.ktx \ + build/ba_data/textures/folder.ktx \ + build/ba_data/textures/fontBig.ktx \ + build/ba_data/textures/fontExtras.ktx \ + build/ba_data/textures/fontExtras2.ktx \ + build/ba_data/textures/fontExtras3.ktx \ + build/ba_data/textures/fontExtras4.ktx \ + build/ba_data/textures/fontSmall0.ktx \ + build/ba_data/textures/fontSmall1.ktx \ + build/ba_data/textures/fontSmall2.ktx \ + build/ba_data/textures/fontSmall3.ktx \ + build/ba_data/textures/fontSmall4.ktx \ + build/ba_data/textures/fontSmall5.ktx \ + build/ba_data/textures/fontSmall6.ktx \ + build/ba_data/textures/fontSmall7.ktx \ + build/ba_data/textures/footballStadium.ktx \ + build/ba_data/textures/footballStadiumPreview.ktx \ + build/ba_data/textures/frameInset.ktx \ + build/ba_data/textures/frostyColor.ktx \ + build/ba_data/textures/frostyColorMask.ktx \ + build/ba_data/textures/frostyIcon.ktx \ + build/ba_data/textures/frostyIconColorMask.ktx \ + build/ba_data/textures/fuse.ktx \ + build/ba_data/textures/gameCenterIcon.ktx \ + build/ba_data/textures/gameCircleIcon.ktx \ + build/ba_data/textures/gladiatorColor.ktx \ + build/ba_data/textures/gladiatorColorMask.ktx \ + build/ba_data/textures/gladiatorIcon.ktx \ + build/ba_data/textures/gladiatorIconColorMask.ktx \ + build/ba_data/textures/glow.ktx \ + build/ba_data/textures/googlePlayAchievementsIcon.ktx \ + build/ba_data/textures/googlePlayGamesIcon.ktx \ + build/ba_data/textures/googlePlayLeaderboardsIcon.ktx \ + build/ba_data/textures/googlePlusIcon.ktx \ + build/ba_data/textures/googlePlusSignInButton.ktx \ + build/ba_data/textures/graphicsIcon.ktx \ + build/ba_data/textures/heart.ktx \ + build/ba_data/textures/hockeyStadium.ktx \ + build/ba_data/textures/hockeyStadiumPreview.ktx \ + build/ba_data/textures/iconOnslaught.ktx \ + build/ba_data/textures/iconRunaround.ktx \ + build/ba_data/textures/impactBombColor.ktx \ build/ba_data/textures/impactBombColorLit.ktx \ - build/ba_data/textures/achievementStayinAlive.ktx + build/ba_data/textures/inventoryIcon.ktx \ + build/ba_data/textures/jackColor.ktx \ + build/ba_data/textures/jackColorMask.ktx \ + build/ba_data/textures/jackIcon.ktx \ + build/ba_data/textures/jackIconColorMask.ktx \ + build/ba_data/textures/jumpsuitColor.ktx \ + build/ba_data/textures/jumpsuitColorMask.ktx \ + build/ba_data/textures/jumpsuitIcon.ktx \ + build/ba_data/textures/jumpsuitIconColorMask.ktx \ + build/ba_data/textures/kronk.ktx \ + build/ba_data/textures/kronkColorMask.ktx \ + build/ba_data/textures/kronkIcon.ktx \ + build/ba_data/textures/kronkIconColorMask.ktx \ + build/ba_data/textures/lakeFrigid.ktx \ + build/ba_data/textures/lakeFrigidPreview.ktx \ + build/ba_data/textures/lakeFrigidReflections.ktx \ + build/ba_data/textures/landMine.ktx \ + build/ba_data/textures/landMineLit.ktx \ + build/ba_data/textures/leaderboardsIcon.ktx \ + build/ba_data/textures/leftButton.ktx \ + build/ba_data/textures/levelIcon.ktx \ + build/ba_data/textures/light.ktx \ + build/ba_data/textures/lightSharp.ktx \ + build/ba_data/textures/lightSoft.ktx \ + build/ba_data/textures/lock.ktx \ + build/ba_data/textures/logIcon.ktx \ + build/ba_data/textures/logo.ktx \ + build/ba_data/textures/logoEaster.ktx \ + build/ba_data/textures/mapPreviewMask.ktx \ + build/ba_data/textures/medalBronze.ktx \ + build/ba_data/textures/medalComplete.ktx \ + build/ba_data/textures/medalGold.ktx \ + build/ba_data/textures/medalSilver.ktx \ + build/ba_data/textures/melColor.ktx \ + build/ba_data/textures/melColorMask.ktx \ + build/ba_data/textures/melIcon.ktx \ + build/ba_data/textures/melIconColorMask.ktx \ + build/ba_data/textures/menuBG.ktx \ + build/ba_data/textures/menuButton.ktx \ + build/ba_data/textures/menuIcon.ktx \ + build/ba_data/textures/meter.ktx \ + build/ba_data/textures/monkeyFaceLevelColor.ktx \ + build/ba_data/textures/monkeyFacePreview.ktx \ + build/ba_data/textures/multiplayerExamples.ktx \ + build/ba_data/textures/natureBackgroundColor.ktx \ + build/ba_data/textures/neoSpazColor.ktx \ + build/ba_data/textures/neoSpazColorMask.ktx \ + build/ba_data/textures/neoSpazIcon.ktx \ + build/ba_data/textures/neoSpazIconColorMask.ktx \ + build/ba_data/textures/nextLevelIcon.ktx \ + build/ba_data/textures/ninjaColor.ktx \ + build/ba_data/textures/ninjaColorMask.ktx \ + build/ba_data/textures/ninjaIcon.ktx \ + build/ba_data/textures/ninjaIconColorMask.ktx \ + build/ba_data/textures/nub.ktx \ + build/ba_data/textures/null.ktx \ + build/ba_data/textures/oldLadyColor.ktx \ + build/ba_data/textures/oldLadyColorMask.ktx \ + build/ba_data/textures/oldLadyIcon.ktx \ + build/ba_data/textures/oldLadyIconColorMask.ktx \ + build/ba_data/textures/operaSingerColor.ktx \ + build/ba_data/textures/operaSingerColorMask.ktx \ + build/ba_data/textures/operaSingerIcon.ktx \ + build/ba_data/textures/operaSingerIconColorMask.ktx \ + build/ba_data/textures/ouyaAButton.ktx \ + build/ba_data/textures/ouyaIcon.ktx \ + build/ba_data/textures/ouyaOButton.ktx \ + build/ba_data/textures/ouyaUButton.ktx \ + build/ba_data/textures/ouyaYButton.ktx \ + build/ba_data/textures/penguinColor.ktx \ + build/ba_data/textures/penguinColorMask.ktx \ + build/ba_data/textures/penguinIcon.ktx \ + build/ba_data/textures/penguinIconColorMask.ktx \ + build/ba_data/textures/pixieColor.ktx \ + build/ba_data/textures/pixieColorMask.ktx \ + build/ba_data/textures/pixieIcon.ktx \ + build/ba_data/textures/pixieIconColorMask.ktx \ + build/ba_data/textures/playerLineup.ktx \ + build/ba_data/textures/powerupBomb.ktx \ + build/ba_data/textures/powerupCurse.ktx \ + build/ba_data/textures/powerupHealth.ktx \ + build/ba_data/textures/powerupIceBombs.ktx \ + build/ba_data/textures/powerupImpactBombs.ktx \ + build/ba_data/textures/powerupLandMines.ktx \ + build/ba_data/textures/powerupPunch.ktx \ + build/ba_data/textures/powerupShield.ktx \ + build/ba_data/textures/powerupSpeed.ktx \ + build/ba_data/textures/powerupStickyBombs.ktx \ + build/ba_data/textures/puckColor.ktx \ + build/ba_data/textures/rampageBGColor.ktx \ + build/ba_data/textures/rampageBGColor2.ktx \ + build/ba_data/textures/rampageLevelColor.ktx \ + build/ba_data/textures/rampagePreview.ktx \ + build/ba_data/textures/reflectionChar_+x.ktx \ + build/ba_data/textures/reflectionChar_+y.ktx \ + build/ba_data/textures/reflectionChar_+z.ktx \ + build/ba_data/textures/reflectionChar_-x.ktx \ + build/ba_data/textures/reflectionChar_-y.ktx \ + build/ba_data/textures/reflectionChar_-z.ktx \ + build/ba_data/textures/reflectionPowerup_+x.ktx \ + build/ba_data/textures/reflectionPowerup_+y.ktx \ + build/ba_data/textures/reflectionPowerup_+z.ktx \ + build/ba_data/textures/reflectionPowerup_-x.ktx \ + build/ba_data/textures/reflectionPowerup_-y.ktx \ + build/ba_data/textures/reflectionPowerup_-z.ktx \ + build/ba_data/textures/reflectionSharp_+x.ktx \ + build/ba_data/textures/reflectionSharp_+y.ktx \ + build/ba_data/textures/reflectionSharp_+z.ktx \ + build/ba_data/textures/reflectionSharp_-x.ktx \ + build/ba_data/textures/reflectionSharp_-y.ktx \ + build/ba_data/textures/reflectionSharp_-z.ktx \ + build/ba_data/textures/reflectionSharper_+x.ktx \ + build/ba_data/textures/reflectionSharper_+y.ktx \ + build/ba_data/textures/reflectionSharper_+z.ktx \ + build/ba_data/textures/reflectionSharper_-x.ktx \ + build/ba_data/textures/reflectionSharper_-y.ktx \ + build/ba_data/textures/reflectionSharper_-z.ktx \ + build/ba_data/textures/reflectionSharpest_+x.ktx \ + build/ba_data/textures/reflectionSharpest_+y.ktx \ + build/ba_data/textures/reflectionSharpest_+z.ktx \ + build/ba_data/textures/reflectionSharpest_-x.ktx \ + build/ba_data/textures/reflectionSharpest_-y.ktx \ + build/ba_data/textures/reflectionSharpest_-z.ktx \ + build/ba_data/textures/reflectionSoft_+x.ktx \ + build/ba_data/textures/reflectionSoft_+y.ktx \ + build/ba_data/textures/reflectionSoft_+z.ktx \ + build/ba_data/textures/reflectionSoft_-x.ktx \ + build/ba_data/textures/reflectionSoft_-y.ktx \ + build/ba_data/textures/reflectionSoft_-z.ktx \ + build/ba_data/textures/replayIcon.ktx \ + build/ba_data/textures/rgbStripes.ktx \ + build/ba_data/textures/rightButton.ktx \ + build/ba_data/textures/robotColor.ktx \ + build/ba_data/textures/robotColorMask.ktx \ + build/ba_data/textures/robotIcon.ktx \ + build/ba_data/textures/robotIconColorMask.ktx \ + build/ba_data/textures/roundaboutLevelColor.ktx \ + build/ba_data/textures/roundaboutPreview.ktx \ + build/ba_data/textures/santaColor.ktx \ + build/ba_data/textures/santaColorMask.ktx \ + build/ba_data/textures/santaIcon.ktx \ + build/ba_data/textures/santaIconColorMask.ktx \ + build/ba_data/textures/scorch.ktx \ + build/ba_data/textures/scorchBig.ktx \ + build/ba_data/textures/scrollWidget.ktx \ + build/ba_data/textures/scrollWidgetGlow.ktx \ + build/ba_data/textures/settingsIcon.ktx \ + build/ba_data/textures/shadow.ktx \ + build/ba_data/textures/shadowSharp.ktx \ + build/ba_data/textures/shadowSoft.ktx \ + build/ba_data/textures/shield.ktx \ + build/ba_data/textures/shrapnel1Color.ktx \ + build/ba_data/textures/slash.ktx \ + build/ba_data/textures/smoke.ktx \ + build/ba_data/textures/softRect.ktx \ + build/ba_data/textures/softRect2.ktx \ + build/ba_data/textures/softRectVertical.ktx \ + build/ba_data/textures/sparks.ktx \ + build/ba_data/textures/star.ktx \ + build/ba_data/textures/startButton.ktx \ + build/ba_data/textures/stepRightUpLevelColor.ktx \ + build/ba_data/textures/stepRightUpPreview.ktx \ + build/ba_data/textures/storeCharacter.ktx \ + build/ba_data/textures/storeCharacterEaster.ktx \ + build/ba_data/textures/storeCharacterXmas.ktx \ + build/ba_data/textures/storeIcon.ktx \ + build/ba_data/textures/superheroColor.ktx \ + build/ba_data/textures/superheroColorMask.ktx \ + build/ba_data/textures/superheroIcon.ktx \ + build/ba_data/textures/superheroIconColorMask.ktx \ + build/ba_data/textures/textClearButton.ktx \ + build/ba_data/textures/thePadLevelColor.ktx \ + build/ba_data/textures/thePadPreview.ktx \ + build/ba_data/textures/ticketRoll.ktx \ + build/ba_data/textures/ticketRollBig.ktx \ + build/ba_data/textures/ticketRolls.ktx \ + build/ba_data/textures/tickets.ktx \ + build/ba_data/textures/ticketsMore.ktx \ + build/ba_data/textures/tipTopBGColor.ktx \ + build/ba_data/textures/tipTopLevelColor.ktx \ + build/ba_data/textures/tipTopPreview.ktx \ + build/ba_data/textures/tnt.ktx \ + build/ba_data/textures/touchArrows.ktx \ + build/ba_data/textures/touchArrowsActions.ktx \ + build/ba_data/textures/towerDLevelColor.ktx \ + build/ba_data/textures/towerDPreview.ktx \ + build/ba_data/textures/treesColor.ktx \ + build/ba_data/textures/trophy.ktx \ + build/ba_data/textures/tv.ktx \ + build/ba_data/textures/uiAtlas.ktx \ + build/ba_data/textures/uiAtlas2.ktx \ + build/ba_data/textures/upButton.ktx \ + build/ba_data/textures/usersButton.ktx \ + build/ba_data/textures/vrFillMound.ktx \ + build/ba_data/textures/warriorColor.ktx \ + build/ba_data/textures/warriorColorMask.ktx \ + build/ba_data/textures/warriorIcon.ktx \ + build/ba_data/textures/warriorIconColorMask.ktx \ + build/ba_data/textures/white.ktx \ + build/ba_data/textures/windowHSmallVMed.ktx \ + build/ba_data/textures/windowHSmallVSmall.ktx \ + build/ba_data/textures/wings.ktx \ + build/ba_data/textures/witchColor.ktx \ + build/ba_data/textures/witchColorMask.ktx \ + build/ba_data/textures/witchIcon.ktx \ + build/ba_data/textures/witchIconColorMask.ktx \ + build/ba_data/textures/wizardColor.ktx \ + build/ba_data/textures/wizardColorMask.ktx \ + build/ba_data/textures/wizardIcon.ktx \ + build/ba_data/textures/wizardIconColorMask.ktx \ + build/ba_data/textures/wrestlerColor.ktx \ + build/ba_data/textures/wrestlerColorMask.ktx \ + build/ba_data/textures/wrestlerIcon.ktx \ + build/ba_data/textures/wrestlerIconColorMask.ktx \ + build/ba_data/textures/zigZagLevelColor.ktx \ + build/ba_data/textures/zigzagPreview.ktx \ + build/ba_data/textures/zoeColor.ktx \ + build/ba_data/textures/zoeColorMask.ktx \ + build/ba_data/textures/zoeIcon.ktx \ + build/ba_data/textures/zoeIconColorMask.ktx TEX2D_PREVIEW_PNG_TARGETS = \ - build/ba_data/textures/cyborgIconColorMask_preview.png \ - build/ba_data/textures/chestOpenIcon_preview.png \ - build/ba_data/textures/analogStick_preview.png \ - build/ba_data/textures/circleOutline_preview.png \ - build/ba_data/textures/white_preview.png \ - build/ba_data/textures/medalBronze_preview.png \ - build/ba_data/textures/slash_preview.png \ - build/ba_data/textures/arrow_preview.png \ - build/ba_data/textures/ouyaIcon_preview.png \ - build/ba_data/textures/eyeColor_preview.png \ - build/ba_data/textures/achievementMedalLarge_preview.png \ - build/ba_data/textures/cowboyIconColorMask_preview.png \ - build/ba_data/textures/wings_preview.png \ - build/ba_data/textures/roundaboutPreview_preview.png \ - build/ba_data/textures/warriorIcon_preview.png \ - build/ba_data/textures/windowHSmallVMed_preview.png \ - build/ba_data/textures/ninjaIconColorMask_preview.png \ - build/ba_data/textures/reflectionSharpest_+z_preview.png \ - build/ba_data/textures/stepRightUpLevelColor_preview.png \ - build/ba_data/textures/fontSmall5_preview.png \ - build/ba_data/textures/bombButton_preview.png \ - build/ba_data/textures/aliIconColorMask_preview.png \ - build/ba_data/textures/chTitleChar2_preview.png \ - build/ba_data/textures/achievementOnslaught_preview.png \ - build/ba_data/textures/smoke_preview.png \ - build/ba_data/textures/lakeFrigidReflections_preview.png \ - build/ba_data/textures/bunnyColor_preview.png \ - build/ba_data/textures/leftButton_preview.png \ - build/ba_data/textures/hockeyStadium_preview.png \ - build/ba_data/textures/cowboyIcon_preview.png \ - build/ba_data/textures/lakeFrigid_preview.png \ - build/ba_data/textures/startButton_preview.png \ - build/ba_data/textures/footballStadium_preview.png \ - build/ba_data/textures/crossOutMask_preview.png \ - build/ba_data/textures/bonesIconColorMask_preview.png \ - build/ba_data/textures/operaSingerIconColorMask_preview.png \ - build/ba_data/textures/lakeFrigidPreview_preview.png \ - build/ba_data/textures/alienIcon_preview.png \ - build/ba_data/textures/oldLadyColor_preview.png \ - build/ba_data/textures/ouyaAButton_preview.png \ - build/ba_data/textures/eggTex3_preview.png \ - build/ba_data/textures/cyborgIcon_preview.png \ - build/ba_data/textures/actionHeroColor_preview.png \ - build/ba_data/textures/achievementTeamPlayer_preview.png \ - build/ba_data/textures/reflectionSoft_+x_preview.png \ - build/ba_data/textures/fontExtras3_preview.png \ - build/ba_data/textures/buttonBomb_preview.png \ - build/ba_data/textures/star_preview.png \ - build/ba_data/textures/reflectionSharpest_-y_preview.png \ - build/ba_data/textures/achievementSharingIsCaring_preview.png \ - build/ba_data/textures/fontSmall3_preview.png \ - build/ba_data/textures/powerupSpeed_preview.png \ - build/ba_data/textures/vrFillMound_preview.png \ - build/ba_data/textures/agentIconColorMask_preview.png \ - build/ba_data/textures/kronkIcon_preview.png \ - build/ba_data/textures/oldLadyIcon_preview.png \ - build/ba_data/textures/chTitleChar4_preview.png \ - build/ba_data/textures/nextLevelIcon_preview.png \ - build/ba_data/textures/gameCircleIcon_preview.png \ - build/ba_data/textures/bonesIcon_preview.png \ - build/ba_data/textures/bearIcon_preview.png \ - build/ba_data/textures/towerDPreview_preview.png \ - build/ba_data/textures/achievementTNT_preview.png \ - build/ba_data/textures/medalGold_preview.png \ - build/ba_data/textures/circleZigZag_preview.png \ - build/ba_data/textures/bunnyColorMask_preview.png \ - build/ba_data/textures/black_preview.png \ - build/ba_data/textures/menuIcon_preview.png \ - build/ba_data/textures/file_preview.png \ - build/ba_data/textures/logIcon_preview.png \ - build/ba_data/textures/controllerIcon_preview.png \ - build/ba_data/textures/reflectionSharper_-y_preview.png \ - build/ba_data/textures/operaSingerColorMask_preview.png \ - build/ba_data/textures/achievementFootballShutout_preview.png \ - build/ba_data/textures/reflectionPowerup_-x_preview.png \ - build/ba_data/textures/achievementsIcon_preview.png \ - build/ba_data/textures/cowboyColor_preview.png \ - build/ba_data/textures/wrestlerIconColorMask_preview.png \ - build/ba_data/textures/googlePlayAchievementsIcon_preview.png \ - build/ba_data/textures/alienIconColorMask_preview.png \ - build/ba_data/textures/ticketRollBig_preview.png \ - build/ba_data/textures/wrestlerIcon_preview.png \ - build/ba_data/textures/egg1_preview.png \ - build/ba_data/textures/gameCenterIcon_preview.png \ - build/ba_data/textures/landMineLit_preview.png \ - build/ba_data/textures/achievementWall_preview.png \ - build/ba_data/textures/achievementMedalMedium_preview.png \ - build/ba_data/textures/reflectionChar_-x_preview.png \ - build/ba_data/textures/softRectVertical_preview.png \ - build/ba_data/textures/reflectionSharper_+z_preview.png \ - build/ba_data/textures/wizardIcon_preview.png \ - build/ba_data/textures/mapPreviewMask_preview.png \ - build/ba_data/textures/nub_preview.png \ - build/ba_data/textures/empty_preview.png \ - build/ba_data/textures/frostyIconColorMask_preview.png \ - build/ba_data/textures/reflectionSharp_-x_preview.png \ - build/ba_data/textures/bombColorIce_preview.png \ - build/ba_data/textures/jumpsuitIcon_preview.png \ - build/ba_data/textures/footballStadiumPreview_preview.png \ - build/ba_data/textures/pixieIconColorMask_preview.png \ - build/ba_data/textures/achievementEmpty_preview.png \ - build/ba_data/textures/wrestlerColor_preview.png \ - build/ba_data/textures/shield_preview.png \ - build/ba_data/textures/iconOnslaught_preview.png \ - build/ba_data/textures/replayIcon_preview.png \ - build/ba_data/textures/powerupHealth_preview.png \ - build/ba_data/textures/bg_preview.png \ - build/ba_data/textures/chTitleChar3_preview.png \ - build/ba_data/textures/textClearButton_preview.png \ - build/ba_data/textures/reflectionSoft_-z_preview.png \ - build/ba_data/textures/fontSmall4_preview.png \ - build/ba_data/textures/warriorColor_preview.png \ - build/ba_data/textures/light_preview.png \ - build/ba_data/textures/santaColor_preview.png \ - build/ba_data/textures/jackColor_preview.png \ - build/ba_data/textures/aliSplash_preview.png \ - build/ba_data/textures/scorch_preview.png \ - build/ba_data/textures/zoeIcon_preview.png \ - build/ba_data/textures/bonesColorMask_preview.png \ - build/ba_data/textures/pixieColor_preview.png \ - build/ba_data/textures/actionHeroIconColorMask_preview.png \ - build/ba_data/textures/treesColor_preview.png \ - build/ba_data/textures/neoSpazColorMask_preview.png \ - build/ba_data/textures/superheroIcon_preview.png \ - build/ba_data/textures/achievementOffYouGo_preview.png \ - build/ba_data/textures/tipTopBGColor_preview.png \ - build/ba_data/textures/robotColor_preview.png \ - build/ba_data/textures/reflectionSharpest_-x_preview.png \ - build/ba_data/textures/menuButton_preview.png \ - build/ba_data/textures/powerupStickyBombs_preview.png \ - build/ba_data/textures/ninjaIcon_preview.png \ - build/ba_data/textures/witchColorMask_preview.png \ - build/ba_data/textures/cowboyColorMask_preview.png \ - build/ba_data/textures/operaSingerIcon_preview.png \ build/ba_data/textures/achievementBoxer_preview.png \ - build/ba_data/textures/eggTex2_preview.png \ - build/ba_data/textures/rampageBGColor_preview.png \ - build/ba_data/textures/fontExtras2_preview.png \ - build/ba_data/textures/rampageLevelColor_preview.png \ - build/ba_data/textures/reflectionSoft_+y_preview.png \ - build/ba_data/textures/ticketRolls_preview.png \ - build/ba_data/textures/natureBackgroundColor_preview.png \ - build/ba_data/textures/santaIconColorMask_preview.png \ - build/ba_data/textures/reflectionPowerup_+z_preview.png \ - build/ba_data/textures/characterIconMask_preview.png \ - build/ba_data/textures/aliColor_preview.png \ - build/ba_data/textures/ninjaColorMask_preview.png \ - build/ba_data/textures/buttonPickUp_preview.png \ - build/ba_data/textures/chTitleChar5_preview.png \ - build/ba_data/textures/bigGPreview_preview.png \ - build/ba_data/textures/hockeyStadiumPreview_preview.png \ - build/ba_data/textures/achievementMedalSmall_preview.png \ - build/ba_data/textures/fontSmall2_preview.png \ - build/ba_data/textures/achievementOutline_preview.png \ - build/ba_data/textures/levelIcon_preview.png \ - build/ba_data/textures/googlePlayGamesIcon_preview.png \ - build/ba_data/textures/gladiatorColorMask_preview.png \ - build/ba_data/textures/boxingGlovesColor_preview.png \ - build/ba_data/textures/ouyaOButton_preview.png \ - build/ba_data/textures/leaderboardsIcon_preview.png \ - build/ba_data/textures/puckColor_preview.png \ - build/ba_data/textures/reflectionChar_+z_preview.png \ - build/ba_data/textures/penguinColor_preview.png \ - build/ba_data/textures/reflectionSharper_-x_preview.png \ - build/ba_data/textures/googlePlayLeaderboardsIcon_preview.png \ - build/ba_data/textures/scrollWidget_preview.png \ - build/ba_data/textures/courtyardPreview_preview.png \ - build/ba_data/textures/aliColorMask_preview.png \ - build/ba_data/textures/penguinColorMask_preview.png \ - build/ba_data/textures/witchIcon_preview.png \ - build/ba_data/textures/reflectionSharp_+z_preview.png \ - build/ba_data/textures/graphicsIcon_preview.png \ - build/ba_data/textures/agentIcon_preview.png \ - build/ba_data/textures/fontExtras4_preview.png \ - build/ba_data/textures/reflectionPowerup_-y_preview.png \ - build/ba_data/textures/storeIcon_preview.png \ - build/ba_data/textures/doomShroomPreview_preview.png \ - build/ba_data/textures/null_preview.png \ - build/ba_data/textures/backIcon_preview.png \ - build/ba_data/textures/cyborgColor_preview.png \ - build/ba_data/textures/monkeyFaceLevelColor_preview.png \ - build/ba_data/textures/santaIcon_preview.png \ - build/ba_data/textures/alwaysLandBGColor_preview.png \ - build/ba_data/textures/roundaboutLevelColor_preview.png \ - build/ba_data/textures/robotIcon_preview.png \ - build/ba_data/textures/reflectionSharp_-y_preview.png \ - build/ba_data/textures/bunnyIcon_preview.png \ - build/ba_data/textures/circleShadow_preview.png \ - build/ba_data/textures/flagPoleColor_preview.png \ - build/ba_data/textures/ouyaUButton_preview.png \ - build/ba_data/textures/reflectionChar_-y_preview.png \ - build/ba_data/textures/achievementInControl_preview.png \ - build/ba_data/textures/wizardColorMask_preview.png \ - build/ba_data/textures/reflectionSharpest_+x_preview.png \ - build/ba_data/textures/neoSpazColor_preview.png \ - build/ba_data/textures/zigZagLevelColor_preview.png \ - build/ba_data/textures/thePadPreview_preview.png \ - build/ba_data/textures/superheroIconColorMask_preview.png \ - build/ba_data/textures/fontSmall7_preview.png \ - build/ba_data/textures/ticketRoll_preview.png \ - build/ba_data/textures/reflectionSoft_-y_preview.png \ - build/ba_data/textures/playerLineup_preview.png \ - build/ba_data/textures/storeCharacterEaster_preview.png \ - build/ba_data/textures/coin_preview.png \ - build/ba_data/textures/circleOutlineNoAlpha_preview.png \ - build/ba_data/textures/scorchBig_preview.png \ - build/ba_data/textures/logoEaster_preview.png \ - build/ba_data/textures/warriorColorMask_preview.png \ - build/ba_data/textures/assassinColor_preview.png \ - build/ba_data/textures/bombStickyColor_preview.png \ - build/ba_data/textures/eggTex1_preview.png \ - build/ba_data/textures/gladiatorIconColorMask_preview.png \ - build/ba_data/textures/melColorMask_preview.png \ - build/ba_data/textures/thePadLevelColor_preview.png \ - build/ba_data/textures/wizardIconColorMask_preview.png \ - build/ba_data/textures/bar_preview.png \ - build/ba_data/textures/zoeIconColorMask_preview.png \ - build/ba_data/textures/windowHSmallVSmall_preview.png \ - build/ba_data/textures/circleNoAlpha_preview.png \ - build/ba_data/textures/gladiatorIcon_preview.png \ - build/ba_data/textures/reflectionSoft_+z_preview.png \ - build/ba_data/textures/achievementRunaround_preview.png \ - build/ba_data/textures/wizardColor_preview.png \ - build/ba_data/textures/touchArrowsActions_preview.png \ - build/ba_data/textures/advancedIcon_preview.png \ - build/ba_data/textures/softRect2_preview.png \ - build/ba_data/textures/achievementMine_preview.png \ - build/ba_data/textures/rightButton_preview.png \ - build/ba_data/textures/touchArrows_preview.png \ - build/ba_data/textures/cyborgColorMask_preview.png \ - build/ba_data/textures/jumpsuitIconColorMask_preview.png \ - build/ba_data/textures/bridgitPreview_preview.png \ - build/ba_data/textures/ninjaColor_preview.png \ - build/ba_data/textures/santaColorMask_preview.png \ - build/ba_data/textures/storeCharacter_preview.png \ - build/ba_data/textures/flagColor_preview.png \ - build/ba_data/textures/cragCastlePreview_preview.png \ - build/ba_data/textures/frameInset_preview.png \ - build/ba_data/textures/lock_preview.png \ - build/ba_data/textures/agentColor_preview.png \ - build/ba_data/textures/achievementGotTheMoves_preview.png \ - build/ba_data/textures/buttonPunch_preview.png \ - build/ba_data/textures/settingsIcon_preview.png \ - build/ba_data/textures/rgbStripes_preview.png \ - build/ba_data/textures/reflectionSharp_+y_preview.png \ - build/ba_data/textures/powerupImpactBombs_preview.png \ - build/ba_data/textures/bigG_preview.png \ - build/ba_data/textures/melIconColorMask_preview.png \ - build/ba_data/textures/reflectionChar_+y_preview.png \ - build/ba_data/textures/multiplayerExamples_preview.png \ - build/ba_data/textures/actionButtons_preview.png \ - build/ba_data/textures/melIcon_preview.png \ - build/ba_data/textures/oldLadyIconColorMask_preview.png \ - build/ba_data/textures/robotIconColorMask_preview.png \ - build/ba_data/textures/monkeyFacePreview_preview.png \ - build/ba_data/textures/achievementDualWielding_preview.png \ - build/ba_data/textures/folder_preview.png \ - build/ba_data/textures/frostyColorMask_preview.png \ - build/ba_data/textures/kronkIconColorMask_preview.png \ - build/ba_data/textures/fontBig_preview.png \ - build/ba_data/textures/fontSmall1_preview.png \ - build/ba_data/textures/shadowSoft_preview.png \ - build/ba_data/textures/powerupLandMines_preview.png \ - build/ba_data/textures/stepRightUpPreview_preview.png \ - build/ba_data/textures/bearIconColorMask_preview.png \ - build/ba_data/textures/kronk_preview.png \ - build/ba_data/textures/downButton_preview.png \ - build/ba_data/textures/bombColor_preview.png \ - build/ba_data/textures/logo_preview.png \ - build/ba_data/textures/reflectionPowerup_+y_preview.png \ - build/ba_data/textures/zoeColorMask_preview.png \ - build/ba_data/textures/jumpsuitColorMask_preview.png \ - build/ba_data/textures/penguinIcon_preview.png \ - build/ba_data/textures/powerupPunch_preview.png \ - build/ba_data/textures/shadow_preview.png \ - build/ba_data/textures/reflectionChar_-z_preview.png \ - build/ba_data/textures/assassinIcon_preview.png \ - build/ba_data/textures/impactBombColor_preview.png \ - build/ba_data/textures/storeCharacterXmas_preview.png \ - build/ba_data/textures/jackIcon_preview.png \ - build/ba_data/textures/pixieIcon_preview.png \ - build/ba_data/textures/jumpsuitColor_preview.png \ - build/ba_data/textures/reflectionSharper_+x_preview.png \ - build/ba_data/textures/jackColorMask_preview.png \ - build/ba_data/textures/shrapnel1Color_preview.png \ - build/ba_data/textures/witchColor_preview.png \ - build/ba_data/textures/achievementFreeLoader_preview.png \ - build/ba_data/textures/zoeColor_preview.png \ - build/ba_data/textures/alienColor_preview.png \ - build/ba_data/textures/inventoryIcon_preview.png \ - build/ba_data/textures/reflectionSharp_-z_preview.png \ - build/ba_data/textures/glow_preview.png \ - build/ba_data/textures/usersButton_preview.png \ - build/ba_data/textures/reflectionPowerup_-z_preview.png \ - build/ba_data/textures/melColor_preview.png \ - build/ba_data/textures/aliControllerQR_preview.png \ - build/ba_data/textures/frostyIcon_preview.png \ - build/ba_data/textures/achievementFootballVictory_preview.png \ - build/ba_data/textures/tickets_preview.png \ - build/ba_data/textures/cursor_preview.png \ - build/ba_data/textures/egg3_preview.png \ - build/ba_data/textures/crossOut_preview.png \ - build/ba_data/textures/bonesColor_preview.png \ build/ba_data/textures/achievementCrossHair_preview.png \ + build/ba_data/textures/achievementDualWielding_preview.png \ + build/ba_data/textures/achievementEmpty_preview.png \ + build/ba_data/textures/achievementFlawlessVictory_preview.png \ + build/ba_data/textures/achievementFootballShutout_preview.png \ + build/ba_data/textures/achievementFootballVictory_preview.png \ + build/ba_data/textures/achievementFreeLoader_preview.png \ + build/ba_data/textures/achievementGotTheMoves_preview.png \ + build/ba_data/textures/achievementInControl_preview.png \ + build/ba_data/textures/achievementMedalLarge_preview.png \ + build/ba_data/textures/achievementMedalMedium_preview.png \ + build/ba_data/textures/achievementMedalSmall_preview.png \ + build/ba_data/textures/achievementMine_preview.png \ + build/ba_data/textures/achievementOffYouGo_preview.png \ + build/ba_data/textures/achievementOnslaught_preview.png \ + build/ba_data/textures/achievementOutline_preview.png \ + build/ba_data/textures/achievementRunaround_preview.png \ + build/ba_data/textures/achievementSharingIsCaring_preview.png \ + build/ba_data/textures/achievementStayinAlive_preview.png \ + build/ba_data/textures/achievementSuperPunch_preview.png \ + build/ba_data/textures/achievementTNT_preview.png \ + build/ba_data/textures/achievementTeamPlayer_preview.png \ + build/ba_data/textures/achievementWall_preview.png \ + build/ba_data/textures/achievementsIcon_preview.png \ + build/ba_data/textures/actionButtons_preview.png \ build/ba_data/textures/actionHeroColorMask_preview.png \ - build/ba_data/textures/chTitleChar1_preview.png \ - build/ba_data/textures/heart_preview.png \ - build/ba_data/textures/fontExtras_preview.png \ - build/ba_data/textures/penguinIconColorMask_preview.png \ - build/ba_data/textures/eyeColorTintMask_preview.png \ + build/ba_data/textures/actionHeroColor_preview.png \ + build/ba_data/textures/actionHeroIconColorMask_preview.png \ + build/ba_data/textures/actionHeroIcon_preview.png \ + build/ba_data/textures/advancedIcon_preview.png \ + build/ba_data/textures/agentColorMask_preview.png \ + build/ba_data/textures/agentColor_preview.png \ + build/ba_data/textures/agentIconColorMask_preview.png \ + build/ba_data/textures/agentIcon_preview.png \ + build/ba_data/textures/aliBSRemoteIOSQR_preview.png \ + build/ba_data/textures/aliColorMask_preview.png \ + build/ba_data/textures/aliColor_preview.png \ + build/ba_data/textures/aliControllerQR_preview.png \ + build/ba_data/textures/aliIconColorMask_preview.png \ build/ba_data/textures/aliIcon_preview.png \ - build/ba_data/textures/chestIconMulti_preview.png \ - build/ba_data/textures/reflectionSoft_-x_preview.png \ - build/ba_data/textures/uiAtlas_preview.png \ - build/ba_data/textures/reflectionSharpest_+y_preview.png \ - build/ba_data/textures/cragCastleLevelColor_preview.png \ - build/ba_data/textures/assassinColorMask_preview.png \ - build/ba_data/textures/bridgitLevelColor_preview.png \ - build/ba_data/textures/fontSmall6_preview.png \ - build/ba_data/textures/towerDLevelColor_preview.png \ - build/ba_data/textures/ouyaYButton_preview.png \ - build/ba_data/textures/lightSharp_preview.png \ - build/ba_data/textures/buttonSquare_preview.png \ - build/ba_data/textures/softRect_preview.png \ - build/ba_data/textures/powerupIceBombs_preview.png \ - build/ba_data/textures/jackIconColorMask_preview.png \ - build/ba_data/textures/audioIcon_preview.png \ - build/ba_data/textures/tv_preview.png \ - build/ba_data/textures/reflectionSharpest_-z_preview.png \ - build/ba_data/textures/warriorIconColorMask_preview.png \ - build/ba_data/textures/googlePlusSignInButton_preview.png \ - build/ba_data/textures/circle_preview.png \ - build/ba_data/textures/neoSpazIconColorMask_preview.png \ - build/ba_data/textures/medalComplete_preview.png \ + build/ba_data/textures/aliSplash_preview.png \ + build/ba_data/textures/alienColorMask_preview.png \ + build/ba_data/textures/alienColor_preview.png \ + build/ba_data/textures/alienIconColorMask_preview.png \ + build/ba_data/textures/alienIcon_preview.png \ + build/ba_data/textures/alwaysLandBGColor_preview.png \ build/ba_data/textures/alwaysLandLevelColor_preview.png \ build/ba_data/textures/alwaysLandPreview_preview.png \ - build/ba_data/textures/egg4_preview.png \ - build/ba_data/textures/wrestlerColorMask_preview.png \ - build/ba_data/textures/superheroColorMask_preview.png \ - build/ba_data/textures/gladiatorColor_preview.png \ - build/ba_data/textures/aliBSRemoteIOSQR_preview.png \ - build/ba_data/textures/bearColorMask_preview.png \ - build/ba_data/textures/doomShroomLevelColor_preview.png \ - build/ba_data/textures/powerupBomb_preview.png \ - build/ba_data/textures/chestIcon_preview.png \ - build/ba_data/textures/upButton_preview.png \ - build/ba_data/textures/iconRunaround_preview.png \ - build/ba_data/textures/doomShroomBGColor_preview.png \ - build/ba_data/textures/superheroColor_preview.png \ - build/ba_data/textures/landMine_preview.png \ - build/ba_data/textures/buttonJump_preview.png \ - build/ba_data/textures/sparks_preview.png \ - build/ba_data/textures/explosion_preview.png \ - build/ba_data/textures/tipTopLevelColor_preview.png \ - build/ba_data/textures/bunnyIconColorMask_preview.png \ - build/ba_data/textures/reflectionChar_+x_preview.png \ - build/ba_data/textures/ticketsMore_preview.png \ - build/ba_data/textures/pixieColorMask_preview.png \ - build/ba_data/textures/medalSilver_preview.png \ - build/ba_data/textures/neoSpazIcon_preview.png \ - build/ba_data/textures/meter_preview.png \ - build/ba_data/textures/scrollWidgetGlow_preview.png \ - build/ba_data/textures/achievementFlawlessVictory_preview.png \ - build/ba_data/textures/zigzagPreview_preview.png \ - build/ba_data/textures/reflectionSharper_-z_preview.png \ - build/ba_data/textures/alienColorMask_preview.png \ - build/ba_data/textures/powerupShield_preview.png \ - build/ba_data/textures/reflectionSharp_+x_preview.png \ - build/ba_data/textures/chestIconEmpty_preview.png \ - build/ba_data/textures/agentColorMask_preview.png \ - build/ba_data/textures/reflectionPowerup_+x_preview.png \ - build/ba_data/textures/witchIconColorMask_preview.png \ - build/ba_data/textures/kronkColorMask_preview.png \ - build/ba_data/textures/menuBG_preview.png \ - build/ba_data/textures/fontSmall0_preview.png \ + build/ba_data/textures/analogStick_preview.png \ + build/ba_data/textures/arrow_preview.png \ + build/ba_data/textures/assassinColorMask_preview.png \ + build/ba_data/textures/assassinColor_preview.png \ build/ba_data/textures/assassinIconColorMask_preview.png \ + build/ba_data/textures/assassinIcon_preview.png \ + build/ba_data/textures/audioIcon_preview.png \ + build/ba_data/textures/backIcon_preview.png \ + build/ba_data/textures/bar_preview.png \ + build/ba_data/textures/bearColorMask_preview.png \ build/ba_data/textures/bearColor_preview.png \ - build/ba_data/textures/operaSingerColor_preview.png \ - build/ba_data/textures/rampageBGColor2_preview.png \ - build/ba_data/textures/fuse_preview.png \ - build/ba_data/textures/frostyColor_preview.png \ - build/ba_data/textures/achievementSuperPunch_preview.png \ - build/ba_data/textures/tipTopPreview_preview.png \ - build/ba_data/textures/googlePlusIcon_preview.png \ - build/ba_data/textures/powerupCurse_preview.png \ - build/ba_data/textures/trophy_preview.png \ + build/ba_data/textures/bearIconColorMask_preview.png \ + build/ba_data/textures/bearIcon_preview.png \ + build/ba_data/textures/bg_preview.png \ + build/ba_data/textures/bigGPreview_preview.png \ + build/ba_data/textures/bigG_preview.png \ + build/ba_data/textures/black_preview.png \ + build/ba_data/textures/bombButton_preview.png \ + build/ba_data/textures/bombColorIce_preview.png \ + build/ba_data/textures/bombColor_preview.png \ + build/ba_data/textures/bombStickyColor_preview.png \ + build/ba_data/textures/bonesColorMask_preview.png \ + build/ba_data/textures/bonesColor_preview.png \ + build/ba_data/textures/bonesIconColorMask_preview.png \ + build/ba_data/textures/bonesIcon_preview.png \ + build/ba_data/textures/boxingGlovesColor_preview.png \ + build/ba_data/textures/bridgitLevelColor_preview.png \ + build/ba_data/textures/bridgitPreview_preview.png \ + build/ba_data/textures/bunnyColorMask_preview.png \ + build/ba_data/textures/bunnyColor_preview.png \ + build/ba_data/textures/bunnyIconColorMask_preview.png \ + build/ba_data/textures/bunnyIcon_preview.png \ + build/ba_data/textures/buttonBomb_preview.png \ + build/ba_data/textures/buttonJump_preview.png \ + build/ba_data/textures/buttonPickUp_preview.png \ + build/ba_data/textures/buttonPunch_preview.png \ + build/ba_data/textures/buttonSquare_preview.png \ + build/ba_data/textures/chTitleChar1_preview.png \ + build/ba_data/textures/chTitleChar2_preview.png \ + build/ba_data/textures/chTitleChar3_preview.png \ + build/ba_data/textures/chTitleChar4_preview.png \ + build/ba_data/textures/chTitleChar5_preview.png \ + build/ba_data/textures/characterIconMask_preview.png \ + build/ba_data/textures/chestIconEmpty_preview.png \ + build/ba_data/textures/chestIconMulti_preview.png \ + build/ba_data/textures/chestIcon_preview.png \ + build/ba_data/textures/chestOpenIcon_preview.png \ + build/ba_data/textures/circleNoAlpha_preview.png \ + build/ba_data/textures/circleOutlineNoAlpha_preview.png \ + build/ba_data/textures/circleOutline_preview.png \ + build/ba_data/textures/circleShadow_preview.png \ + build/ba_data/textures/circleZigZag_preview.png \ + build/ba_data/textures/circle_preview.png \ + build/ba_data/textures/coin_preview.png \ + build/ba_data/textures/controllerIcon_preview.png \ build/ba_data/textures/courtyardLevelColor_preview.png \ - build/ba_data/textures/oldLadyColorMask_preview.png \ - build/ba_data/textures/rampagePreview_preview.png \ + build/ba_data/textures/courtyardPreview_preview.png \ + build/ba_data/textures/cowboyColorMask_preview.png \ + build/ba_data/textures/cowboyColor_preview.png \ + build/ba_data/textures/cowboyIconColorMask_preview.png \ + build/ba_data/textures/cowboyIcon_preview.png \ + build/ba_data/textures/cragCastleLevelColor_preview.png \ + build/ba_data/textures/cragCastlePreview_preview.png \ + build/ba_data/textures/crossOutMask_preview.png \ + build/ba_data/textures/crossOut_preview.png \ + build/ba_data/textures/cursor_preview.png \ build/ba_data/textures/cuteSpaz_preview.png \ - build/ba_data/textures/lightSoft_preview.png \ - build/ba_data/textures/reflectionSharper_+y_preview.png \ - build/ba_data/textures/uiAtlas2_preview.png \ + build/ba_data/textures/cyborgColorMask_preview.png \ + build/ba_data/textures/cyborgColor_preview.png \ + build/ba_data/textures/cyborgIconColorMask_preview.png \ + build/ba_data/textures/cyborgIcon_preview.png \ + build/ba_data/textures/doomShroomBGColor_preview.png \ + build/ba_data/textures/doomShroomLevelColor_preview.png \ + build/ba_data/textures/doomShroomPreview_preview.png \ + build/ba_data/textures/downButton_preview.png \ + build/ba_data/textures/egg1_preview.png \ build/ba_data/textures/egg2_preview.png \ - build/ba_data/textures/shadowSharp_preview.png \ - build/ba_data/textures/tnt_preview.png \ - build/ba_data/textures/actionHeroIcon_preview.png \ - build/ba_data/textures/robotColorMask_preview.png \ + build/ba_data/textures/egg3_preview.png \ + build/ba_data/textures/egg4_preview.png \ + build/ba_data/textures/eggTex1_preview.png \ + build/ba_data/textures/eggTex2_preview.png \ + build/ba_data/textures/eggTex3_preview.png \ + build/ba_data/textures/empty_preview.png \ + build/ba_data/textures/explosion_preview.png \ + build/ba_data/textures/eyeColorTintMask_preview.png \ + build/ba_data/textures/eyeColor_preview.png \ + build/ba_data/textures/file_preview.png \ + build/ba_data/textures/flagColor_preview.png \ + build/ba_data/textures/flagPoleColor_preview.png \ + build/ba_data/textures/folder_preview.png \ + build/ba_data/textures/fontBig_preview.png \ + build/ba_data/textures/fontExtras2_preview.png \ + build/ba_data/textures/fontExtras3_preview.png \ + build/ba_data/textures/fontExtras4_preview.png \ + build/ba_data/textures/fontExtras_preview.png \ + build/ba_data/textures/fontSmall0_preview.png \ + build/ba_data/textures/fontSmall1_preview.png \ + build/ba_data/textures/fontSmall2_preview.png \ + build/ba_data/textures/fontSmall3_preview.png \ + build/ba_data/textures/fontSmall4_preview.png \ + build/ba_data/textures/fontSmall5_preview.png \ + build/ba_data/textures/fontSmall6_preview.png \ + build/ba_data/textures/fontSmall7_preview.png \ + build/ba_data/textures/footballStadiumPreview_preview.png \ + build/ba_data/textures/footballStadium_preview.png \ + build/ba_data/textures/frameInset_preview.png \ + build/ba_data/textures/frostyColorMask_preview.png \ + build/ba_data/textures/frostyColor_preview.png \ + build/ba_data/textures/frostyIconColorMask_preview.png \ + build/ba_data/textures/frostyIcon_preview.png \ + build/ba_data/textures/fuse_preview.png \ + build/ba_data/textures/gameCenterIcon_preview.png \ + build/ba_data/textures/gameCircleIcon_preview.png \ + build/ba_data/textures/gladiatorColorMask_preview.png \ + build/ba_data/textures/gladiatorColor_preview.png \ + build/ba_data/textures/gladiatorIconColorMask_preview.png \ + build/ba_data/textures/gladiatorIcon_preview.png \ + build/ba_data/textures/glow_preview.png \ + build/ba_data/textures/googlePlayAchievementsIcon_preview.png \ + build/ba_data/textures/googlePlayGamesIcon_preview.png \ + build/ba_data/textures/googlePlayLeaderboardsIcon_preview.png \ + build/ba_data/textures/googlePlusIcon_preview.png \ + build/ba_data/textures/googlePlusSignInButton_preview.png \ + build/ba_data/textures/graphicsIcon_preview.png \ + build/ba_data/textures/heart_preview.png \ + build/ba_data/textures/hockeyStadiumPreview_preview.png \ + build/ba_data/textures/hockeyStadium_preview.png \ + build/ba_data/textures/iconOnslaught_preview.png \ + build/ba_data/textures/iconRunaround_preview.png \ build/ba_data/textures/impactBombColorLit_preview.png \ - build/ba_data/textures/achievementStayinAlive_preview.png + build/ba_data/textures/impactBombColor_preview.png \ + build/ba_data/textures/inventoryIcon_preview.png \ + build/ba_data/textures/jackColorMask_preview.png \ + build/ba_data/textures/jackColor_preview.png \ + build/ba_data/textures/jackIconColorMask_preview.png \ + build/ba_data/textures/jackIcon_preview.png \ + build/ba_data/textures/jumpsuitColorMask_preview.png \ + build/ba_data/textures/jumpsuitColor_preview.png \ + build/ba_data/textures/jumpsuitIconColorMask_preview.png \ + build/ba_data/textures/jumpsuitIcon_preview.png \ + build/ba_data/textures/kronkColorMask_preview.png \ + build/ba_data/textures/kronkIconColorMask_preview.png \ + build/ba_data/textures/kronkIcon_preview.png \ + build/ba_data/textures/kronk_preview.png \ + build/ba_data/textures/lakeFrigidPreview_preview.png \ + build/ba_data/textures/lakeFrigidReflections_preview.png \ + build/ba_data/textures/lakeFrigid_preview.png \ + build/ba_data/textures/landMineLit_preview.png \ + build/ba_data/textures/landMine_preview.png \ + build/ba_data/textures/leaderboardsIcon_preview.png \ + build/ba_data/textures/leftButton_preview.png \ + build/ba_data/textures/levelIcon_preview.png \ + build/ba_data/textures/lightSharp_preview.png \ + build/ba_data/textures/lightSoft_preview.png \ + build/ba_data/textures/light_preview.png \ + build/ba_data/textures/lock_preview.png \ + build/ba_data/textures/logIcon_preview.png \ + build/ba_data/textures/logoEaster_preview.png \ + build/ba_data/textures/logo_preview.png \ + build/ba_data/textures/mapPreviewMask_preview.png \ + build/ba_data/textures/medalBronze_preview.png \ + build/ba_data/textures/medalComplete_preview.png \ + build/ba_data/textures/medalGold_preview.png \ + build/ba_data/textures/medalSilver_preview.png \ + build/ba_data/textures/melColorMask_preview.png \ + build/ba_data/textures/melColor_preview.png \ + build/ba_data/textures/melIconColorMask_preview.png \ + build/ba_data/textures/melIcon_preview.png \ + build/ba_data/textures/menuBG_preview.png \ + build/ba_data/textures/menuButton_preview.png \ + build/ba_data/textures/menuIcon_preview.png \ + build/ba_data/textures/meter_preview.png \ + build/ba_data/textures/monkeyFaceLevelColor_preview.png \ + build/ba_data/textures/monkeyFacePreview_preview.png \ + build/ba_data/textures/multiplayerExamples_preview.png \ + build/ba_data/textures/natureBackgroundColor_preview.png \ + build/ba_data/textures/neoSpazColorMask_preview.png \ + build/ba_data/textures/neoSpazColor_preview.png \ + build/ba_data/textures/neoSpazIconColorMask_preview.png \ + build/ba_data/textures/neoSpazIcon_preview.png \ + build/ba_data/textures/nextLevelIcon_preview.png \ + build/ba_data/textures/ninjaColorMask_preview.png \ + build/ba_data/textures/ninjaColor_preview.png \ + build/ba_data/textures/ninjaIconColorMask_preview.png \ + build/ba_data/textures/ninjaIcon_preview.png \ + build/ba_data/textures/nub_preview.png \ + build/ba_data/textures/null_preview.png \ + build/ba_data/textures/oldLadyColorMask_preview.png \ + build/ba_data/textures/oldLadyColor_preview.png \ + build/ba_data/textures/oldLadyIconColorMask_preview.png \ + build/ba_data/textures/oldLadyIcon_preview.png \ + build/ba_data/textures/operaSingerColorMask_preview.png \ + build/ba_data/textures/operaSingerColor_preview.png \ + build/ba_data/textures/operaSingerIconColorMask_preview.png \ + build/ba_data/textures/operaSingerIcon_preview.png \ + build/ba_data/textures/ouyaAButton_preview.png \ + build/ba_data/textures/ouyaIcon_preview.png \ + build/ba_data/textures/ouyaOButton_preview.png \ + build/ba_data/textures/ouyaUButton_preview.png \ + build/ba_data/textures/ouyaYButton_preview.png \ + build/ba_data/textures/penguinColorMask_preview.png \ + build/ba_data/textures/penguinColor_preview.png \ + build/ba_data/textures/penguinIconColorMask_preview.png \ + build/ba_data/textures/penguinIcon_preview.png \ + build/ba_data/textures/pixieColorMask_preview.png \ + build/ba_data/textures/pixieColor_preview.png \ + build/ba_data/textures/pixieIconColorMask_preview.png \ + build/ba_data/textures/pixieIcon_preview.png \ + build/ba_data/textures/playerLineup_preview.png \ + build/ba_data/textures/powerupBomb_preview.png \ + build/ba_data/textures/powerupCurse_preview.png \ + build/ba_data/textures/powerupHealth_preview.png \ + build/ba_data/textures/powerupIceBombs_preview.png \ + build/ba_data/textures/powerupImpactBombs_preview.png \ + build/ba_data/textures/powerupLandMines_preview.png \ + build/ba_data/textures/powerupPunch_preview.png \ + build/ba_data/textures/powerupShield_preview.png \ + build/ba_data/textures/powerupSpeed_preview.png \ + build/ba_data/textures/powerupStickyBombs_preview.png \ + build/ba_data/textures/puckColor_preview.png \ + build/ba_data/textures/rampageBGColor2_preview.png \ + build/ba_data/textures/rampageBGColor_preview.png \ + build/ba_data/textures/rampageLevelColor_preview.png \ + build/ba_data/textures/rampagePreview_preview.png \ + build/ba_data/textures/reflectionChar_+x_preview.png \ + build/ba_data/textures/reflectionChar_+y_preview.png \ + build/ba_data/textures/reflectionChar_+z_preview.png \ + build/ba_data/textures/reflectionChar_-x_preview.png \ + build/ba_data/textures/reflectionChar_-y_preview.png \ + build/ba_data/textures/reflectionChar_-z_preview.png \ + build/ba_data/textures/reflectionPowerup_+x_preview.png \ + build/ba_data/textures/reflectionPowerup_+y_preview.png \ + build/ba_data/textures/reflectionPowerup_+z_preview.png \ + build/ba_data/textures/reflectionPowerup_-x_preview.png \ + build/ba_data/textures/reflectionPowerup_-y_preview.png \ + build/ba_data/textures/reflectionPowerup_-z_preview.png \ + build/ba_data/textures/reflectionSharp_+x_preview.png \ + build/ba_data/textures/reflectionSharp_+y_preview.png \ + build/ba_data/textures/reflectionSharp_+z_preview.png \ + build/ba_data/textures/reflectionSharp_-x_preview.png \ + build/ba_data/textures/reflectionSharp_-y_preview.png \ + build/ba_data/textures/reflectionSharp_-z_preview.png \ + build/ba_data/textures/reflectionSharper_+x_preview.png \ + build/ba_data/textures/reflectionSharper_+y_preview.png \ + build/ba_data/textures/reflectionSharper_+z_preview.png \ + build/ba_data/textures/reflectionSharper_-x_preview.png \ + build/ba_data/textures/reflectionSharper_-y_preview.png \ + build/ba_data/textures/reflectionSharper_-z_preview.png \ + build/ba_data/textures/reflectionSharpest_+x_preview.png \ + build/ba_data/textures/reflectionSharpest_+y_preview.png \ + build/ba_data/textures/reflectionSharpest_+z_preview.png \ + build/ba_data/textures/reflectionSharpest_-x_preview.png \ + build/ba_data/textures/reflectionSharpest_-y_preview.png \ + build/ba_data/textures/reflectionSharpest_-z_preview.png \ + build/ba_data/textures/reflectionSoft_+x_preview.png \ + build/ba_data/textures/reflectionSoft_+y_preview.png \ + build/ba_data/textures/reflectionSoft_+z_preview.png \ + build/ba_data/textures/reflectionSoft_-x_preview.png \ + build/ba_data/textures/reflectionSoft_-y_preview.png \ + build/ba_data/textures/reflectionSoft_-z_preview.png \ + build/ba_data/textures/replayIcon_preview.png \ + build/ba_data/textures/rgbStripes_preview.png \ + build/ba_data/textures/rightButton_preview.png \ + build/ba_data/textures/robotColorMask_preview.png \ + build/ba_data/textures/robotColor_preview.png \ + build/ba_data/textures/robotIconColorMask_preview.png \ + build/ba_data/textures/robotIcon_preview.png \ + build/ba_data/textures/roundaboutLevelColor_preview.png \ + build/ba_data/textures/roundaboutPreview_preview.png \ + build/ba_data/textures/santaColorMask_preview.png \ + build/ba_data/textures/santaColor_preview.png \ + build/ba_data/textures/santaIconColorMask_preview.png \ + build/ba_data/textures/santaIcon_preview.png \ + build/ba_data/textures/scorchBig_preview.png \ + build/ba_data/textures/scorch_preview.png \ + build/ba_data/textures/scrollWidgetGlow_preview.png \ + build/ba_data/textures/scrollWidget_preview.png \ + build/ba_data/textures/settingsIcon_preview.png \ + build/ba_data/textures/shadowSharp_preview.png \ + build/ba_data/textures/shadowSoft_preview.png \ + build/ba_data/textures/shadow_preview.png \ + build/ba_data/textures/shield_preview.png \ + build/ba_data/textures/shrapnel1Color_preview.png \ + build/ba_data/textures/slash_preview.png \ + build/ba_data/textures/smoke_preview.png \ + build/ba_data/textures/softRect2_preview.png \ + build/ba_data/textures/softRectVertical_preview.png \ + build/ba_data/textures/softRect_preview.png \ + build/ba_data/textures/sparks_preview.png \ + build/ba_data/textures/star_preview.png \ + build/ba_data/textures/startButton_preview.png \ + build/ba_data/textures/stepRightUpLevelColor_preview.png \ + build/ba_data/textures/stepRightUpPreview_preview.png \ + build/ba_data/textures/storeCharacterEaster_preview.png \ + build/ba_data/textures/storeCharacterXmas_preview.png \ + build/ba_data/textures/storeCharacter_preview.png \ + build/ba_data/textures/storeIcon_preview.png \ + build/ba_data/textures/superheroColorMask_preview.png \ + build/ba_data/textures/superheroColor_preview.png \ + build/ba_data/textures/superheroIconColorMask_preview.png \ + build/ba_data/textures/superheroIcon_preview.png \ + build/ba_data/textures/textClearButton_preview.png \ + build/ba_data/textures/thePadLevelColor_preview.png \ + build/ba_data/textures/thePadPreview_preview.png \ + build/ba_data/textures/ticketRollBig_preview.png \ + build/ba_data/textures/ticketRoll_preview.png \ + build/ba_data/textures/ticketRolls_preview.png \ + build/ba_data/textures/ticketsMore_preview.png \ + build/ba_data/textures/tickets_preview.png \ + build/ba_data/textures/tipTopBGColor_preview.png \ + build/ba_data/textures/tipTopLevelColor_preview.png \ + build/ba_data/textures/tipTopPreview_preview.png \ + build/ba_data/textures/tnt_preview.png \ + build/ba_data/textures/touchArrowsActions_preview.png \ + build/ba_data/textures/touchArrows_preview.png \ + build/ba_data/textures/towerDLevelColor_preview.png \ + build/ba_data/textures/towerDPreview_preview.png \ + build/ba_data/textures/treesColor_preview.png \ + build/ba_data/textures/trophy_preview.png \ + build/ba_data/textures/tv_preview.png \ + build/ba_data/textures/uiAtlas2_preview.png \ + build/ba_data/textures/uiAtlas_preview.png \ + build/ba_data/textures/upButton_preview.png \ + build/ba_data/textures/usersButton_preview.png \ + build/ba_data/textures/vrFillMound_preview.png \ + build/ba_data/textures/warriorColorMask_preview.png \ + build/ba_data/textures/warriorColor_preview.png \ + build/ba_data/textures/warriorIconColorMask_preview.png \ + build/ba_data/textures/warriorIcon_preview.png \ + build/ba_data/textures/white_preview.png \ + build/ba_data/textures/windowHSmallVMed_preview.png \ + build/ba_data/textures/windowHSmallVSmall_preview.png \ + build/ba_data/textures/wings_preview.png \ + build/ba_data/textures/witchColorMask_preview.png \ + build/ba_data/textures/witchColor_preview.png \ + build/ba_data/textures/witchIconColorMask_preview.png \ + build/ba_data/textures/witchIcon_preview.png \ + build/ba_data/textures/wizardColorMask_preview.png \ + build/ba_data/textures/wizardColor_preview.png \ + build/ba_data/textures/wizardIconColorMask_preview.png \ + build/ba_data/textures/wizardIcon_preview.png \ + build/ba_data/textures/wrestlerColorMask_preview.png \ + build/ba_data/textures/wrestlerColor_preview.png \ + build/ba_data/textures/wrestlerIconColorMask_preview.png \ + build/ba_data/textures/wrestlerIcon_preview.png \ + build/ba_data/textures/zigZagLevelColor_preview.png \ + build/ba_data/textures/zigzagPreview_preview.png \ + build/ba_data/textures/zoeColorMask_preview.png \ + build/ba_data/textures/zoeColor_preview.png \ + build/ba_data/textures/zoeIconColorMask_preview.png \ + build/ba_data/textures/zoeIcon_preview.png EXTRAS_TARGETS_WIN_WIN32 = \ - build/windows/Win32/VC_redist.x86.exe \ - build/windows/Win32/python37.dll \ - build/windows/Win32/pythonw.exe \ - build/windows/Win32/OpenAL32.dll \ - build/windows/Win32/libvorbis.dll \ - build/windows/Win32/python.exe \ - build/windows/Win32/libvorbisfile.dll \ - build/windows/Win32/SDL2.dll \ - build/windows/Win32/ogg.dll \ - build/windows/Win32/DLLs/python_tools.cat \ - build/windows/Win32/DLLs/_msi.pyd \ + build/windows/Win32/DLLs/_asyncio.pyd \ + build/windows/Win32/DLLs/_bz2.pyd \ + build/windows/Win32/DLLs/_ctypes.pyd \ + build/windows/Win32/DLLs/_decimal.pyd \ build/windows/Win32/DLLs/_elementtree.pyd \ build/windows/Win32/DLLs/_hashlib.pyd \ - build/windows/Win32/DLLs/python_lib.cat \ - build/windows/Win32/DLLs/winsound.pyd \ - build/windows/Win32/DLLs/_ssl.pyd \ - build/windows/Win32/DLLs/libssl-1_1.dll \ - build/windows/Win32/DLLs/sqlite3.dll \ - build/windows/Win32/DLLs/_overlapped.pyd \ - build/windows/Win32/DLLs/libcrypto-1_1.dll \ - build/windows/Win32/DLLs/_asyncio.pyd \ build/windows/Win32/DLLs/_lzma.pyd \ + build/windows/Win32/DLLs/_msi.pyd \ build/windows/Win32/DLLs/_multiprocessing.pyd \ - build/windows/Win32/DLLs/pyexpat.pyd \ - build/windows/Win32/DLLs/_sqlite3.pyd \ + build/windows/Win32/DLLs/_overlapped.pyd \ build/windows/Win32/DLLs/_queue.pyd \ build/windows/Win32/DLLs/_socket.pyd \ - build/windows/Win32/DLLs/pyd.ico \ + build/windows/Win32/DLLs/_sqlite3.pyd \ + build/windows/Win32/DLLs/_ssl.pyd \ + build/windows/Win32/DLLs/libcrypto-1_1.dll \ + build/windows/Win32/DLLs/libssl-1_1.dll \ build/windows/Win32/DLLs/py.ico \ - build/windows/Win32/DLLs/_ctypes.pyd \ build/windows/Win32/DLLs/pyc.ico \ - build/windows/Win32/DLLs/_bz2.pyd \ + build/windows/Win32/DLLs/pyd.ico \ + build/windows/Win32/DLLs/pyexpat.pyd \ + build/windows/Win32/DLLs/python_lib.cat \ + build/windows/Win32/DLLs/python_tools.cat \ build/windows/Win32/DLLs/select.pyd \ - build/windows/Win32/DLLs/_decimal.pyd \ + build/windows/Win32/DLLs/sqlite3.dll \ build/windows/Win32/DLLs/unicodedata.pyd \ - build/windows/Win32/Lib/distutils/README \ - build/windows/Win32/Lib/distutils/tests/includetest.rst \ - build/windows/Win32/Lib/distutils/tests/Setup.sample \ - build/windows/Win32/Lib/distutils/command/command_template \ - build/windows/Win32/Lib/ctypes/macholib/fetch_macholib \ + build/windows/Win32/DLLs/winsound.pyd \ build/windows/Win32/Lib/ctypes/macholib/README.ctypes \ + build/windows/Win32/Lib/ctypes/macholib/fetch_macholib \ build/windows/Win32/Lib/ctypes/macholib/fetch_macholib.bat \ - build/windows/Win32/Lib/site-packages/README.txt \ + build/windows/Win32/Lib/distutils/README \ + build/windows/Win32/Lib/distutils/command/command_template \ + build/windows/Win32/Lib/distutils/tests/Setup.sample \ + build/windows/Win32/Lib/distutils/tests/includetest.rst \ + build/windows/Win32/Lib/email/architecture.rst \ build/windows/Win32/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl \ build/windows/Win32/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl \ - build/windows/Win32/Lib/venv/scripts/posix/activate.fish \ - build/windows/Win32/Lib/venv/scripts/posix/activate.csh \ - build/windows/Win32/Lib/venv/scripts/nt/activate.bat \ - build/windows/Win32/Lib/venv/scripts/nt/Activate.ps1 \ - build/windows/Win32/Lib/venv/scripts/nt/pythonw.exe \ - build/windows/Win32/Lib/venv/scripts/nt/python.exe \ - build/windows/Win32/Lib/venv/scripts/nt/deactivate.bat \ - build/windows/Win32/Lib/venv/scripts/common/activate \ build/windows/Win32/Lib/pydoc_data/_pydoc.css \ - build/windows/Win32/Lib/email/architecture.rst + build/windows/Win32/Lib/site-packages/README.txt \ + build/windows/Win32/Lib/venv/scripts/common/activate \ + build/windows/Win32/Lib/venv/scripts/nt/Activate.ps1 \ + build/windows/Win32/Lib/venv/scripts/nt/activate.bat \ + build/windows/Win32/Lib/venv/scripts/nt/deactivate.bat \ + build/windows/Win32/Lib/venv/scripts/nt/python.exe \ + build/windows/Win32/Lib/venv/scripts/nt/pythonw.exe \ + build/windows/Win32/Lib/venv/scripts/posix/activate.csh \ + build/windows/Win32/Lib/venv/scripts/posix/activate.fish \ + build/windows/Win32/OpenAL32.dll \ + build/windows/Win32/SDL2.dll \ + build/windows/Win32/VC_redist.x86.exe \ + build/windows/Win32/libvorbis.dll \ + build/windows/Win32/libvorbisfile.dll \ + build/windows/Win32/ogg.dll \ + build/windows/Win32/python.exe \ + build/windows/Win32/python37.dll \ + build/windows/Win32/pythonw.exe # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_WIN32) : ../.efrocachemap @@ -20035,61 +20035,61 @@ $(EXTRAS_TARGETS_WIN_WIN32) : ../.efrocachemap EXTRAS_TARGETS_WIN_X64 = \ - build/windows/x64/python37.dll \ - build/windows/x64/pythonw.exe \ - build/windows/x64/OpenAL32.dll \ - build/windows/x64/libvorbis.dll \ - build/windows/x64/python.exe \ - build/windows/x64/libvorbisfile.dll \ - build/windows/x64/SDL2.dll \ - build/windows/x64/ogg.dll \ - build/windows/x64/VC_redist.x64.exe \ - build/windows/x64/DLLs/python_tools.cat \ - build/windows/x64/DLLs/_msi.pyd \ + build/windows/x64/DLLs/_asyncio.pyd \ + build/windows/x64/DLLs/_bz2.pyd \ + build/windows/x64/DLLs/_ctypes.pyd \ + build/windows/x64/DLLs/_decimal.pyd \ build/windows/x64/DLLs/_elementtree.pyd \ build/windows/x64/DLLs/_hashlib.pyd \ - build/windows/x64/DLLs/python_lib.cat \ - build/windows/x64/DLLs/winsound.pyd \ - build/windows/x64/DLLs/_ssl.pyd \ - build/windows/x64/DLLs/libssl-1_1.dll \ - build/windows/x64/DLLs/sqlite3.dll \ - build/windows/x64/DLLs/_overlapped.pyd \ - build/windows/x64/DLLs/libcrypto-1_1.dll \ - build/windows/x64/DLLs/_asyncio.pyd \ build/windows/x64/DLLs/_lzma.pyd \ + build/windows/x64/DLLs/_msi.pyd \ build/windows/x64/DLLs/_multiprocessing.pyd \ - build/windows/x64/DLLs/pyexpat.pyd \ - build/windows/x64/DLLs/_sqlite3.pyd \ + build/windows/x64/DLLs/_overlapped.pyd \ build/windows/x64/DLLs/_queue.pyd \ build/windows/x64/DLLs/_socket.pyd \ - build/windows/x64/DLLs/pyd.ico \ + build/windows/x64/DLLs/_sqlite3.pyd \ + build/windows/x64/DLLs/_ssl.pyd \ + build/windows/x64/DLLs/libcrypto-1_1.dll \ + build/windows/x64/DLLs/libssl-1_1.dll \ build/windows/x64/DLLs/py.ico \ - build/windows/x64/DLLs/_ctypes.pyd \ build/windows/x64/DLLs/pyc.ico \ - build/windows/x64/DLLs/_bz2.pyd \ + build/windows/x64/DLLs/pyd.ico \ + build/windows/x64/DLLs/pyexpat.pyd \ + build/windows/x64/DLLs/python_lib.cat \ + build/windows/x64/DLLs/python_tools.cat \ build/windows/x64/DLLs/select.pyd \ - build/windows/x64/DLLs/_decimal.pyd \ + build/windows/x64/DLLs/sqlite3.dll \ build/windows/x64/DLLs/unicodedata.pyd \ - build/windows/x64/Lib/distutils/README \ - build/windows/x64/Lib/distutils/tests/includetest.rst \ - build/windows/x64/Lib/distutils/tests/Setup.sample \ - build/windows/x64/Lib/distutils/command/command_template \ - build/windows/x64/Lib/ctypes/macholib/fetch_macholib \ + build/windows/x64/DLLs/winsound.pyd \ build/windows/x64/Lib/ctypes/macholib/README.ctypes \ + build/windows/x64/Lib/ctypes/macholib/fetch_macholib \ build/windows/x64/Lib/ctypes/macholib/fetch_macholib.bat \ - build/windows/x64/Lib/site-packages/README.txt \ + build/windows/x64/Lib/distutils/README \ + build/windows/x64/Lib/distutils/command/command_template \ + build/windows/x64/Lib/distutils/tests/Setup.sample \ + build/windows/x64/Lib/distutils/tests/includetest.rst \ + build/windows/x64/Lib/email/architecture.rst \ build/windows/x64/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl \ build/windows/x64/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl \ - build/windows/x64/Lib/venv/scripts/posix/activate.fish \ - build/windows/x64/Lib/venv/scripts/posix/activate.csh \ - build/windows/x64/Lib/venv/scripts/nt/activate.bat \ - build/windows/x64/Lib/venv/scripts/nt/Activate.ps1 \ - build/windows/x64/Lib/venv/scripts/nt/pythonw.exe \ - build/windows/x64/Lib/venv/scripts/nt/python.exe \ - build/windows/x64/Lib/venv/scripts/nt/deactivate.bat \ - build/windows/x64/Lib/venv/scripts/common/activate \ build/windows/x64/Lib/pydoc_data/_pydoc.css \ - build/windows/x64/Lib/email/architecture.rst + build/windows/x64/Lib/site-packages/README.txt \ + build/windows/x64/Lib/venv/scripts/common/activate \ + build/windows/x64/Lib/venv/scripts/nt/Activate.ps1 \ + build/windows/x64/Lib/venv/scripts/nt/activate.bat \ + build/windows/x64/Lib/venv/scripts/nt/deactivate.bat \ + build/windows/x64/Lib/venv/scripts/nt/python.exe \ + build/windows/x64/Lib/venv/scripts/nt/pythonw.exe \ + build/windows/x64/Lib/venv/scripts/posix/activate.csh \ + build/windows/x64/Lib/venv/scripts/posix/activate.fish \ + build/windows/x64/OpenAL32.dll \ + build/windows/x64/SDL2.dll \ + build/windows/x64/VC_redist.x64.exe \ + build/windows/x64/libvorbis.dll \ + build/windows/x64/libvorbisfile.dll \ + build/windows/x64/ogg.dll \ + build/windows/x64/python.exe \ + build/windows/x64/python37.dll \ + build/windows/x64/pythonw.exe # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_X64) : ../.efrocachemap From 67693dc639fd90a620629b36c409bdd10e889b0d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 14:48:55 -0700 Subject: [PATCH 069/417] Fixed sorting bug --- assets/Makefile | 5978 +++++++++++++++++----------------- tools/update_assets_makefile | 8 +- 2 files changed, 2995 insertions(+), 2991 deletions(-) diff --git a/assets/Makefile b/assets/Makefile index d817bcef..b5f37459 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -431,12 +431,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc \ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc \ @@ -467,6 +461,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc \ @@ -486,6 +481,8 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc \ @@ -504,8 +501,16 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc \ @@ -514,6 +519,10 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc \ @@ -524,41 +533,14 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc \ @@ -568,10 +550,19 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc \ @@ -595,10 +586,19 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc \ build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. @@ -909,372 +909,372 @@ build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/coopjoin.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/coopscore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/drawscore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/dualteamscore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/freeforallvictory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamjoin.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamscore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamvictory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/background.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/bomb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/controlsguide.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/flag.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/image.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/onscreencountdown.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/onscreentimer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/playerspaz.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/popuptext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/powerupbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/respawnicon.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/scoreboard.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spawner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spaz.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazappearance.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazbot.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazfactory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/tipstext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/zoomtext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/appdelegate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/assault.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/capturetheflag.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/chosenone.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/conquest.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/deathmatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/easteregghunt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/elimination.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/football.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/hockey.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/keepaway.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/kingofthehill.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/meteorshower.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/ninjafight.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/onslaught.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/race.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/runaround.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/targetpractice.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/thelaststand.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/gameutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mainmenu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/big_g.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/bridgit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/courtyard.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/crag_castle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/doom_shroom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/football_stadium.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/happy_thoughts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/hockey_stadium.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/lake_frigid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/monkey_face.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/rampage.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/roundabout.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/step_right_up.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/the_pad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/tip_top.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/tower_d.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/zig_zag.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/maps.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/session/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/stdmap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/tutorial.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -1284,467 +1284,467 @@ build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/link.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/settings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/unlink.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/viewer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/achievements.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/appinvite.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/characterpicker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/colorpicker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/configerror.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/confirm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/continues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/gamebutton.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/level.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/creditslist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/debug.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/feedback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/fileselector.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/gather.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/getcurrency.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/getremote.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/helpui.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/iconpicker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/kiosk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankbutton.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankwindow.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/mainmenu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/onscreenkeyboard.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/party.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/partyqueue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/play.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/addgame.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/customizebrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/edit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/editcontroller.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/editgame.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/mapselect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/share.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playoptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/popup.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/edit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/upgrade.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/promocode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/purchase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/qrcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/radiogroup.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/report.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/resourcetypeinfo.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/serverdialog.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/advanced.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/allsettings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/audio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/controls.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepadadvanced.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepadselect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/graphics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/keyboard.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/nettesting.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/ps3controller.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/remoteapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/testing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/touchscreen.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/vrtesting.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/wiimote.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/xbox360controller.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/edit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/specialoffer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/browser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/button.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/item.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tabs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/teamnamescolors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/telnet.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tournamententry.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tournamentscores.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/trophies.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/url.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ +build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/watch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -1783,17 +1783,17 @@ SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \ build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc \ build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc \ build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc \ build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc \ build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc \ build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc \ build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc + build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -1843,57 +1843,57 @@ build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_entity.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_field.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_value.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/json.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/terminal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ +build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -2353,153 +2353,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc \ build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc \ build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ @@ -2525,27 +2378,58 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc \ build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc \ build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc \ build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ @@ -2562,10 +2446,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc \ build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ @@ -2575,6 +2455,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ @@ -2700,6 +2584,23 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc \ build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc \ build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc \ @@ -2708,6 +2609,8 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc \ build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc \ build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ @@ -2715,23 +2618,118 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc \ build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc \ build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc \ build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc \ build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc \ build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc \ build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc \ build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc \ build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc \ build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc \ build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc \ build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc \ build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ @@ -2756,7 +2754,9 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc + build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -2877,2022 +2877,2022 @@ build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/coroutines.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/format_helpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/locks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/proactor_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/protocols.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/runners.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/selector_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/sslproto.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/streams.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/transports.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/unix_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/windows_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ +build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/windows_utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ build/pylib-apple/base64.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/pylib-apple/bdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/pylib-apple/binhex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/pylib-apple/bisect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/pylib-apple/bz2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/pylib-apple/cProfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/pylib-apple/calendar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/pylib-apple/cgi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/pylib-apple/cgitb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/pylib-apple/chunk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/pylib-apple/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ build/pylib-apple/code.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/pylib-apple/codecs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/pylib-apple/codeop.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ +build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/collections/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ +build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/collections/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/pylib-apple/colorsys.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/pylib-apple/compileall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ +build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ +build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ +build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ +build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/pylib-apple/configparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/pylib-apple/contextlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/pylib-apple/contextvars.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ build/pylib-apple/copy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/pylib-apple/copyreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/pylib-apple/crypt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ build/pylib-apple/csv.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_aix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_endian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dyld.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dylib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/framework.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ +build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ +build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ +build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ +build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ +build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ +build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/pylib-apple/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/pylib-apple/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/pylib-apple/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/pylib-apple/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ build/pylib-apple/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/pylib-apple/doctest.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/pylib-apple/dummy_threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/email/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_encoded_words.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_header_value_parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_parseaddr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_policybase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/pylib-apple/email/base64mime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/pylib-apple/email/charset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/pylib-apple/email/contentmanager.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/pylib-apple/email/encoders.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/pylib-apple/email/errors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/feedparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/pylib-apple/email/generator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/pylib-apple/email/header.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/pylib-apple/email/headerregistry.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/pylib-apple/email/iterators.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-apple/email/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/application.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/audio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/image.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/multipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/nonmultipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/pylib-apple/email/policy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/pylib-apple/email/quoprimime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ +build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/pylib-apple/email/utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/aliases.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/base64_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/big5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/big5hkscs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/bz2_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/charmap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp037.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1006.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1026.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1125.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1140.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1250.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1251.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1252.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1253.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1254.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1255.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1256.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1257.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1258.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp273.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp424.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp437.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp500.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp65001.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp720.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp737.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp775.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp850.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp852.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp855.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp856.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp857.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp858.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp860.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp861.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp862.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp863.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp864.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp865.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp866.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp869.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp874.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp875.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp932.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp949.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp950.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gb18030.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gb2312.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gbk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hex_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hp_roman8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hz.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/idna.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_10.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_11.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_14.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_15.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_4.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_6.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_9.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/johab.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_r.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_t.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_u.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/kz1048.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/latin_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_arabic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_centeuro.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_croatian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_cyrillic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_farsi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_greek.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_iceland.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_latin2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_roman.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_romanian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_turkish.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mbcs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/oem.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/palmos.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/ptcp154.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/punycode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/quopri_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/raw_unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/rot_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/tis_620.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/undefined.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/unicode_internal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_8_sig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/uu_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ +build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/zlib_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ build/pylib-apple/enum.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/pylib-apple/filecmp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/pylib-apple/fileinput.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/pylib-apple/fnmatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/pylib-apple/formatter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/pylib-apple/fractions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/pylib-apple/ftplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ build/pylib-apple/functools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/pylib-apple/genericpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/pylib-apple/getopt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/pylib-apple/getpass.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/pylib-apple/gettext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ build/pylib-apple/glob.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/pylib-apple/gzip.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/pylib-apple/hashlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/pylib-apple/heapq.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/pylib-apple/hmac.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ +build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/html/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ +build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/pylib-apple/html/entities.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ +build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-apple/html/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ +build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/http/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ +build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-apple/http/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ +build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/pylib-apple/http/cookiejar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ +build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/pylib-apple/http/cookies.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ +build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-apple/http/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/pylib-apple/imghdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ build/pylib-apple/imp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/_bootstrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/_bootstrap_external.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/machinery.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/resources.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ +build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/pylib-apple/inspect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ build/pylib-apple/io.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/pylib-apple/ipaddress.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ +build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/json/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ +build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/pylib-apple/json/decoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ +build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/pylib-apple/json/encoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ +build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/pylib-apple/json/scanner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ +build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/pylib-apple/json/tool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/pylib-apple/keyword.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/pylib-apple/linecache.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ build/pylib-apple/locale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ +build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ +build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ +build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/handlers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-apple/lzma.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/pylib-apple/macpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-apple/mailbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-apple/mailcap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/pylib-apple/mimetypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-apple/modulefinder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/pylib-apple/netrc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/pylib-apple/nntplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/pylib-apple/ntpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-apple/nturl2path.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/pylib-apple/numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-apple/opcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-apple/operator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/pylib-apple/optparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ build/pylib-apple/os.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/pylib-apple/pathlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/pylib-apple/pdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/pylib-apple/pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/pylib-apple/pickletools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/pylib-apple/pipes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/pylib-apple/pkgutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ build/pylib-apple/platform.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/pylib-apple/plistlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/pylib-apple/poplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/pylib-apple/posixpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/pylib-apple/pprint.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ build/pylib-apple/profile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/pylib-apple/pstats.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ build/pylib-apple/pty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/pylib-apple/py_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/pylib-apple/pyclbr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/pylib-apple/pydoc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ build/pylib-apple/queue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/pylib-apple/quopri.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ build/pylib-apple/random.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ build/pylib-apple/re.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/pylib-apple/reprlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/pylib-apple/rlcompleter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/pylib-apple/runpy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ build/pylib-apple/sched.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/pylib-apple/secrets.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/pylib-apple/selectors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/pylib-apple/shelve.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/pylib-apple/shlex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/pylib-apple/shutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ build/pylib-apple/signal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ build/pylib-apple/site.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/pylib-apple/smtpd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/pylib-apple/smtplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/pylib-apple/sndhdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ build/pylib-apple/socket.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/pylib-apple/socketserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ +build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ +build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/dbapi2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ +build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/pylib-apple/ssl.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ build/pylib-apple/stat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/pylib-apple/statistics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ build/pylib-apple/string.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/pylib-apple/stringprep.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ build/pylib-apple/struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/pylib-apple/sunau.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/pylib-apple/symbol.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/pylib-apple/symtable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/pylib-apple/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/pylib-apple/tabnanny.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/pylib-apple/tarfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/pylib-apple/telnetlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/pylib-apple/tempfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/pylib-apple/textwrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ build/pylib-apple/this.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ build/pylib-apple/threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/pylib-apple/timeit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ build/pylib-apple/token.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/pylib-apple/tokenize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ build/pylib-apple/trace.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/pylib-apple/traceback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/pylib-apple/tracemalloc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ build/pylib-apple/tty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ build/pylib-apple/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ build/pylib-apple/typing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ +build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ +build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ +build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/request.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ +build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/response.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ +build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/robotparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ build/pylib-apple/uu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/pylib-apple/uuid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/pylib-apple/warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ build/pylib-apple/wave.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/pylib-apple/weakref.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/pylib-apple/webbrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/pylib-apple/xdrlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minicompat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/pulldom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/xmlbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementInclude.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ +build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ +build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ +build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/pylib-apple/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ +build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/pylib-apple/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -5349,153 +5349,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc \ build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc \ build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ @@ -5521,27 +5374,58 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc \ build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc \ build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc \ build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ @@ -5558,10 +5442,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc \ build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ @@ -5571,6 +5451,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ @@ -5696,6 +5580,23 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc \ build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc \ build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc \ @@ -5704,6 +5605,8 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc \ build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc \ build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ @@ -5711,23 +5614,118 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc \ build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc \ build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc \ build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc \ build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc \ build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc \ build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc \ build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc \ build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc \ build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc \ build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc \ build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc \ build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ @@ -5752,7 +5750,9 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc + build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -5873,2022 +5873,2022 @@ build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/coroutines.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/format_helpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/locks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/proactor_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/protocols.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/runners.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/selector_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/sslproto.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/streams.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/transports.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/unix_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/windows_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ +build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/windows_utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/pylib-android/asyncore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ build/pylib-android/base64.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/pylib-android/bdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/pylib-android/binhex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/pylib-android/bisect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/pylib-android/bz2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/pylib-android/cProfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/pylib-android/calendar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/pylib-android/cgi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/pylib-android/cgitb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/pylib-android/chunk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/pylib-android/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ build/pylib-android/code.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/pylib-android/codecs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/pylib-android/codeop.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ +build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/collections/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ +build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/collections/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/pylib-android/colorsys.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/pylib-android/compileall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ +build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ +build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ +build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ +build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ +build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/pylib-android/configparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/pylib-android/contextlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/pylib-android/contextvars.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ build/pylib-android/copy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/pylib-android/copyreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/pylib-android/crypt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ build/pylib-android/csv.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_aix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_endian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dyld.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dylib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/framework.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ +build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ +build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ +build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-android/curses/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ +build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/pylib-android/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ +build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/pylib-android/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ +build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/pylib-android/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/pylib-android/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/pylib-android/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/pylib-android/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/pylib-android/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ build/pylib-android/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/pylib-android/doctest.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/pylib-android/dummy_threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/email/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/pylib-android/email/_encoded_words.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/pylib-android/email/_header_value_parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/pylib-android/email/_parseaddr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/pylib-android/email/_policybase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/pylib-android/email/base64mime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/pylib-android/email/charset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/pylib-android/email/contentmanager.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/pylib-android/email/encoders.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/pylib-android/email/errors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/pylib-android/email/feedparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/pylib-android/email/generator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/pylib-android/email/header.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/pylib-android/email/headerregistry.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/pylib-android/email/iterators.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-android/email/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/application.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/audio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/image.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/multipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/nonmultipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ +build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-android/email/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/pylib-android/email/policy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/pylib-android/email/quoprimime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ +build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/pylib-android/email/utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/aliases.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/base64_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/big5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/big5hkscs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/bz2_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/charmap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp037.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1006.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1026.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1125.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1140.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1250.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1251.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1252.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1253.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1254.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1255.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1256.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1257.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1258.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp273.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp424.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp437.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp500.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp65001.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp720.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp737.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp775.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp850.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp852.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp855.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp856.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp857.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp858.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp860.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp861.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp862.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp863.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp864.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp865.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp866.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp869.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp874.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp875.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp932.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp949.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp950.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gb18030.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gb2312.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gbk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hex_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hp_roman8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hz.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/idna.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_10.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_11.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_14.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_15.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_4.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_6.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_9.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/johab.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_r.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_t.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_u.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/kz1048.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/latin_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_arabic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_centeuro.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_croatian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_cyrillic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_farsi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_greek.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_iceland.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_latin2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_roman.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_romanian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_turkish.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mbcs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/oem.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/palmos.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/ptcp154.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/punycode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/quopri_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/raw_unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/rot_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/tis_620.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/undefined.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/unicode_internal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_8_sig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/uu_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ +build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/zlib_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ build/pylib-android/enum.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/pylib-android/filecmp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/pylib-android/fileinput.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/pylib-android/fnmatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/pylib-android/formatter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/pylib-android/fractions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/pylib-android/ftplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ build/pylib-android/functools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/pylib-android/genericpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/pylib-android/getopt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/pylib-android/getpass.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/pylib-android/gettext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ build/pylib-android/glob.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/pylib-android/gzip.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/pylib-android/hashlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/pylib-android/heapq.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/pylib-android/hmac.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ +build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/html/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ +build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/pylib-android/html/entities.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ +build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-android/html/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ +build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/http/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ +build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-android/http/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ +build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/pylib-android/http/cookiejar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ +build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/pylib-android/http/cookies.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ +build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-android/http/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/pylib-android/imghdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ build/pylib-android/imp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/_bootstrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/_bootstrap_external.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/machinery.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/resources.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ +build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/pylib-android/inspect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ build/pylib-android/io.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/pylib-android/ipaddress.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ +build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/json/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ +build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/pylib-android/json/decoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ +build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/pylib-android/json/encoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ +build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/pylib-android/json/scanner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ +build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/pylib-android/json/tool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/pylib-android/keyword.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/pylib-android/linecache.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ build/pylib-android/locale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ +build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/logging/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ +build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/pylib-android/logging/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ +build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/pylib-android/logging/handlers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-android/lzma.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/pylib-android/macpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-android/mailbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-android/mailcap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/pylib-android/mimetypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-android/modulefinder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/pylib-android/netrc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/pylib-android/nntplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/pylib-android/ntpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-android/nturl2path.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/pylib-android/numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-android/opcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-android/operator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/pylib-android/optparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ build/pylib-android/os.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/pylib-android/pathlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/pylib-android/pdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/pylib-android/pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/pylib-android/pickletools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/pylib-android/pipes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/pylib-android/pkgutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ build/pylib-android/platform.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/pylib-android/plistlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/pylib-android/poplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/pylib-android/posixpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/pylib-android/pprint.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ build/pylib-android/profile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/pylib-android/pstats.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ build/pylib-android/pty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/pylib-android/py_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/pylib-android/pyclbr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/pylib-android/pydoc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ build/pylib-android/queue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/pylib-android/quopri.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ build/pylib-android/random.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ build/pylib-android/re.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/pylib-android/reprlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/pylib-android/rlcompleter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/pylib-android/runpy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ build/pylib-android/sched.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/pylib-android/secrets.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/pylib-android/selectors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/pylib-android/shelve.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/pylib-android/shlex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/pylib-android/shutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ build/pylib-android/signal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ build/pylib-android/site.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/pylib-android/smtpd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/pylib-android/smtplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/pylib-android/sndhdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ build/pylib-android/socket.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/pylib-android/socketserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ +build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ +build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/dbapi2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ +build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/pylib-android/sre_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/pylib-android/sre_constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/pylib-android/sre_parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/pylib-android/ssl.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ build/pylib-android/stat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/pylib-android/statistics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ build/pylib-android/string.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/pylib-android/stringprep.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ build/pylib-android/struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/pylib-android/sunau.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/pylib-android/symbol.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/pylib-android/symtable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/pylib-android/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/pylib-android/tabnanny.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/pylib-android/tarfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/pylib-android/telnetlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/pylib-android/tempfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/pylib-android/textwrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ build/pylib-android/this.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ build/pylib-android/threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/pylib-android/timeit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ build/pylib-android/token.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/pylib-android/tokenize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ build/pylib-android/trace.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/pylib-android/traceback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/pylib-android/tracemalloc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ build/pylib-android/tty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ build/pylib-android/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ build/pylib-android/typing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ +build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ +build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ +build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/request.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ +build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/response.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ +build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/robotparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ build/pylib-android/uu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/pylib-android/uuid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/pylib-android/warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ build/pylib-android/wave.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/pylib-android/weakref.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/pylib-android/webbrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/pylib-android/xdrlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minicompat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/pulldom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/xmlbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementInclude.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/pylib-android/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ +build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ +build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ +build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/pylib-android/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ +build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/pylib-android/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -8727,155 +8727,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ @@ -8901,18 +8752,40 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ @@ -8970,43 +8843,28 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ @@ -9030,6 +8888,23 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ @@ -9074,6 +8949,13 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ @@ -9090,10 +8972,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ @@ -9103,6 +8981,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ @@ -9231,6 +9113,23 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ @@ -9239,6 +9138,9 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ @@ -9246,14 +9148,26 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ @@ -9261,6 +9175,8 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ @@ -9278,10 +9194,54 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ @@ -9295,6 +9255,37 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ @@ -9305,7 +9296,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ @@ -9334,20 +9324,28 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ @@ -9372,7 +9370,9 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc + build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -9493,3232 +9493,3232 @@ build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/coroutines.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/format_helpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/locks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/proactor_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/protocols.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/runners.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/selector_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/sslproto.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/streams.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/transports.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/unix_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/windows_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/windows_utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/base64.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/binhex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bisect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bz2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cProfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/calendar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cgi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cgitb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/chunk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/code.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/codecs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/codeop.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/collections/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/collections/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/colorsys.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/compileall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/configparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/contextlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/contextvars.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/copy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/copyreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/crypt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/csv.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/_aix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/_endian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/dyld.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/dylib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/framework.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_anon.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_arrays.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_as_parameter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_bitfields.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_buffers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_bytes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_byteswap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_callbacks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_cast.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_cfuncs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_checkretval.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_delattr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_errno.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_find.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_frombuffer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_funcptr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_functions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_incomplete.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_init.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_internals.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_keeprefs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_libc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_loading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_macholib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_memfunctions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_objects.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_parameters.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pep3118.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_values.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/gnu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/ndbm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/archive_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/ccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_clib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_py.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/check.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/clean.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_data.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_egg_info.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_headers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_lib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/register.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/sdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/upload.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/core.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/cygwinccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/debug.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dep_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dir_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/errors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/extension.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/fancy_getopt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/file_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/filelist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/msvc9compiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_archive_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_clib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_py.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_check.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_clean.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_config_cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_core.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dep_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dir_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_extension.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_file_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_filelist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_data.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_headers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_lib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_register.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_sdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_text_file.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_upload.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_version.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/text_file.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/unixccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/version.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/versionpredicate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/doctest.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dummy_threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_encoded_words.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_header_value_parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_parseaddr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_policybase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/base64mime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/charset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/contentmanager.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/encoders.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/errors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/feedparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/generator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/header.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/headerregistry.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/iterators.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/application.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/audio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/image.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/multipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/nonmultipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/policy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/quoprimime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/aliases.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/base64_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/big5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/big5hkscs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/bz2_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/charmap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp037.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1006.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1026.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1125.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1140.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1250.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1251.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1252.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1253.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1254.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1255.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1256.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1257.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1258.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp273.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp424.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp437.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp500.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp65001.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp720.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp737.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp775.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp850.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp852.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp855.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp856.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp857.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp858.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp860.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp861.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp862.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp863.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp864.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp865.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp866.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp869.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp874.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp875.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp932.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp949.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp950.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gb18030.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gb2312.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gbk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hex_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hp_roman8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hz.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/idna.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_10.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_11.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_14.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_15.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_4.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_6.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_9.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/johab.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_r.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_t.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_u.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/kz1048.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/latin_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_arabic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_centeuro.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_croatian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_cyrillic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_farsi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_greek.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_iceland.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_latin2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_roman.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_romanian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_turkish.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mbcs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/oem.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/palmos.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/ptcp154.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/punycode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/quopri_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/raw_unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/rot_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/tis_620.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/undefined.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/unicode_internal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/uu_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/zlib_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/_uninstall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/enum.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/filecmp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fileinput.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fnmatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/formatter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fractions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ftplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/functools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/genericpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/getopt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/getpass.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/gettext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/glob.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/gzip.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/hashlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/heapq.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/hmac.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/entities.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/cookiejar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/cookies.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imaplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imghdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/_bootstrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/_bootstrap_external.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/machinery.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/resources.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/inspect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/io.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ipaddress.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/decoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/encoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/scanner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/tool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/keyword.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/linecache.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/locale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/handlers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/lzma.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/macpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mailbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mailcap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mimetypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/modulefinder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/schema.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/sequence.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/context.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/heap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/managers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/pool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/reduction.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/netrc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/nntplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ntpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/nturl2path.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/opcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/operator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/optparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/os.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pathlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pickletools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pipes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pkgutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/platform.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/plistlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/poplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/posixpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pprint.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/profile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pstats.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/py_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pyclbr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc_data/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc_data/topics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/queue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/quopri.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/random.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/re.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/reprlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/rlcompleter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/runpy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sched.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/secrets.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/selectors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shelve.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shlex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/signal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/site.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/smtpd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/smtplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sndhdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/socket.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/socketserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/backup.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/factory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/regression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ssl.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/stat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/statistics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/string.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/stringprep.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sunau.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/symbol.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/symtable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tabnanny.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tarfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/telnetlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tempfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/textwrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/this.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/timeit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/token.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tokenize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/trace.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/traceback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tracemalloc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/turtle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/typing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/case.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/loader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/main.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/mock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/runner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/signals.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/suite.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/_test_warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/dummy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_break.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_case.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_discovery.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_loader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_program.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_runner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_setups.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_skipping.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_suite.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/request.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/response.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/robotparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/uu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/uuid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/venv/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/venv/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wave.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/weakref.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/webbrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/handlers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/headers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/simple_server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/validate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xdrlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/minicompat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/pulldom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ +build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ @@ -13417,155 +13417,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc \ build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ @@ -13591,18 +13442,40 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ @@ -13660,43 +13533,28 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc \ build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ @@ -13720,6 +13578,23 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ @@ -13764,6 +13639,13 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ @@ -13780,10 +13662,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ @@ -13793,6 +13671,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ @@ -13921,6 +13803,23 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ @@ -13929,6 +13828,9 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ @@ -13936,14 +13838,26 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc \ build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ @@ -13951,6 +13865,8 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ @@ -13968,10 +13884,54 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ @@ -13985,6 +13945,37 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ @@ -13995,7 +13986,6 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ @@ -14024,20 +14014,28 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ @@ -14062,7 +14060,9 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc + build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -14183,3232 +14183,3232 @@ build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/coroutines.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/format_helpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/futures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/locks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/proactor_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/protocols.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/runners.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/selector_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/sslproto.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/streams.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/tasks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/transports.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/unix_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/windows_events.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/windows_utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncore.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/base64.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/binhex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bisect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bz2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cProfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/calendar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cgi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cgitb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/chunk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/code.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/codecs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/codeop.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/collections/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/collections/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/colorsys.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/compileall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/_base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/thread.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/configparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/contextlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/contextvars.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/copy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/copyreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/crypt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/csv.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/_aix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/_endian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/dyld.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/dylib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/framework.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_anon.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_arrays.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_as_parameter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_bitfields.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_buffers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_bytes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_byteswap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_callbacks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_cast.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_cfuncs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_checkretval.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_delattr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_errno.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_find.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_frombuffer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_funcptr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_functions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_incomplete.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_init.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_internals.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_keeprefs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_libc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_loading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_macholib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_memfunctions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_objects.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_parameters.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pep3118.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_values.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/wintypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/has_key.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/panel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/textpad.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dataclasses.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/datetime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/gnu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/ndbm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/decimal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/difflib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/archive_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/ccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_clib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_py.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/check.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/clean.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_data.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_egg_info.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_headers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_lib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/register.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/sdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/upload.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/core.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/cygwinccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/debug.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dep_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dir_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/errors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/extension.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/fancy_getopt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/file_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/filelist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/msvc9compiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_archive_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_msi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_clib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_py.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_check.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_clean.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_config_cmd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_core.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dep_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dir_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_extension.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_file_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_filelist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_data.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_headers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_lib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_scripts.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_log.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_msvccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_register.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_sdist.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_text_file.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_unixccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_upload.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_version.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_versionpredicate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/text_file.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/unixccompiler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/version.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/versionpredicate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/doctest.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dummy_threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_encoded_words.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_header_value_parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_parseaddr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_policybase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/base64mime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/charset.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/contentmanager.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/encoders.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/errors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/feedparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/generator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/header.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/headerregistry.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/iterators.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/application.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/audio.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/base.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/image.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/message.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/multipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/nonmultipart.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/policy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/quoprimime.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/utils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/aliases.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/ascii.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/base64_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/big5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/big5hkscs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/bz2_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/charmap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp037.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1006.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1026.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1125.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1140.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1250.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1251.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1252.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1253.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1254.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1255.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1256.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1257.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1258.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp273.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp424.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp437.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp500.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp65001.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp720.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp737.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp775.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp850.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp852.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp855.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp856.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp857.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp858.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp860.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp861.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp862.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp863.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp864.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp865.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp866.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp869.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp874.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp875.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp932.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp949.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp950.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gb18030.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gb2312.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gbk.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hex_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hp_roman8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hz.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/idna.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_ext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_kr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_10.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_11.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_14.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_15.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_3.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_4.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_5.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_6.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_9.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/johab.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_r.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_t.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_u.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/kz1048.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/latin_1.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_arabic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_centeuro.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_croatian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_cyrillic.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_farsi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_greek.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_iceland.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_latin2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_roman.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_romanian.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_turkish.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mbcs.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/oem.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/palmos.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/ptcp154.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/punycode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/quopri_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/raw_unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/rot_13.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jis.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jis_2004.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jisx0213.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/tis_620.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/undefined.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/unicode_escape.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/unicode_internal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32_be.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32_le.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_7.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/uu_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/zlib_codec.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/_uninstall.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/enum.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/filecmp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fileinput.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fnmatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/formatter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fractions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ftplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/functools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/genericpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/getopt.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/getpass.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/gettext.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/glob.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/gzip.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/hashlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/heapq.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/hmac.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/entities.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/parser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/cookiejar.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/cookies.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imaplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imghdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/_bootstrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/_bootstrap_external.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/abc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/machinery.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/resources.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/inspect.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/io.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ipaddress.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/decoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/encoder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/scanner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/tool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/keyword.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/linecache.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/locale.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/config.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/handlers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/lzma.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/macpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mailbox.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mailcap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mimetypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/modulefinder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/schema.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/sequence.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/text.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/context.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/heap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/managers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/pool.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/process.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/queues.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/reduction.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/spawn.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/netrc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/nntplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ntpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/nturl2path.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/numbers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/opcode.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/operator.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/optparse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/os.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pathlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pdb.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pickle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pickletools.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pipes.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pkgutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/platform.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/plistlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/poplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/posixpath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pprint.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/profile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pstats.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/py_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pyclbr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc_data/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc_data/topics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/queue.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/quopri.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/random.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/re.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/reprlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/rlcompleter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/runpy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sched.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/secrets.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/selectors.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shelve.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shlex.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shutil.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/signal.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/site.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/smtpd.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/smtplib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sndhdr.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/socket.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/socketserver.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/backup.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/dump.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/factory.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/regression.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_compile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_constants.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ssl.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/stat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/statistics.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/string.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/stringprep.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/struct.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/subprocess.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sunau.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/symbol.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/symtable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sysconfig.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tabnanny.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tarfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/telnetlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tempfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/textwrap.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/this.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/threading.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/timeit.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/token.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tokenize.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/trace.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/traceback.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tracemalloc.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tty.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/turtle.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/types.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/typing.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/case.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/loader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/main.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/mock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/runner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/signals.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/suite.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/_test_warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/dummy.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_break.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_case.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_discovery.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_loader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_program.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_result.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_runner.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_setups.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_skipping.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_suite.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/error.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/parse.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/request.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/response.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/robotparser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/uu.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/uuid.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/venv/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/venv/__main__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/warnings.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wave.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/weakref.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/webbrowser.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/handlers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/headers.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/simple_server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/util.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/validate.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xdrlib.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/domreg.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/minicompat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/minidom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/pulldom.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/parsers/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/parsers/expat.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/expatreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/handler.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/saxutils.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/__init__.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/client.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/server.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/zipapp.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ +build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/zipfile.py @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile index ab9bcde3..0c1ef269 100755 --- a/tools/update_assets_makefile +++ b/tools/update_assets_makefile @@ -149,8 +149,12 @@ def _get_py_targets_subset(all_targets: Set[str], subset: str, all_targets, subset=subset) - py_targets.sort() - pyc_targets.sort() + # Need to sort these combined to keep pairs together. + combined_targets = [(py_targets[i], pyc_targets[i]) + for i in range(len(py_targets))] + combined_targets.sort() + py_targets = [t[0] for t in combined_targets] + pyc_targets = [t[1] for t in combined_targets] out = (f'\nSCRIPT_TARGETS_PY{suffix} = \\\n ' + ' \\\n '.join(py_targets) + '\n') From 546ad7848f63895300c06144a245f429a6c73a52 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 15:37:47 -0700 Subject: [PATCH 070/417] Tidying --- .efrocachemap | 24 ++-- .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 6 +- assets/src/ba_data/python/ba/__init__.py | 4 +- assets/src/ba_data/python/ba/_activity.py | 8 +- .../src/ba_data/python/ba/_activitytypes.py | 37 ++--- assets/src/ba_data/python/ba/_coopgame.py | 2 +- assets/src/ba_data/python/ba/_gameactivity.py | 4 +- assets/src/ba_data/python/ba/_level.py | 2 +- assets/src/ba_data/python/ba/_player.py | 17 +++ assets/src/ba_data/python/ba/_session.py | 2 +- assets/src/ba_data/python/ba/_stats.py | 6 +- assets/src/ba_data/python/ba/_team.py | 17 +++ assets/src/ba_data/python/ba/_teamgame.py | 2 +- .../ba_data/python/bastd/activity/coopjoin.py | 2 +- .../python/bastd/activity/coopscore.py | 2 +- .../python/bastd/activity/dualteamscore.py | 2 +- .../bastd/activity/freeforallvictory.py | 2 +- .../python/bastd/activity/multiteamjoin.py | 2 +- .../python/bastd/activity/multiteamscore.py | 2 +- .../python/bastd/activity/multiteamvictory.py | 2 +- .../src/ba_data/python/bastd/game/assault.py | 2 +- .../python/bastd/game/capturetheflag.py | 2 +- .../ba_data/python/bastd/game/chosenone.py | 2 +- .../src/ba_data/python/bastd/game/conquest.py | 2 +- .../ba_data/python/bastd/game/deathmatch.py | 2 +- .../python/bastd/game/easteregghunt.py | 2 +- .../ba_data/python/bastd/game/elimination.py | 2 +- .../src/ba_data/python/bastd/game/football.py | 8 +- .../src/ba_data/python/bastd/game/hockey.py | 2 +- .../src/ba_data/python/bastd/game/keepaway.py | 2 +- .../python/bastd/game/kingofthehill.py | 2 +- .../ba_data/python/bastd/game/meteorshower.py | 2 +- .../ba_data/python/bastd/game/ninjafight.py | 2 +- .../ba_data/python/bastd/game/onslaught.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 2 +- .../ba_data/python/bastd/game/runaround.py | 2 +- .../python/bastd/game/targetpractice.py | 2 +- .../ba_data/python/bastd/game/thelaststand.py | 2 +- assets/src/ba_data/python/bastd/tutorial.py | 2 +- .../python/bastd/ui/settings/gamepad.py | 2 +- .../python/bastd/ui/settings/keyboard.py | 2 +- docs/ba_module.md | 133 ++++++++++++++++-- 43 files changed, 230 insertions(+), 97 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index a3cd6b95..9959a6e0 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/15/7a/d4e39ad022b8365418ecee4d026b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ab/ad/7e371dfb7ed7b10d46f0bf9497d8", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/92/28/faa6501d779b381dec7fb9ac19c5", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/57/97d03c6230cfc4d9f0687249f408", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/ec/9a476535716a8798813506f502a5", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ae/78/7a6522e860506fe1046808ce7b0b", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fa/67/ec5ab3ace8d2e740e85f23ebfbb0", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/49/3c1d3c8a995df400e46df3470b02", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7c/6f/c04c002f3a92497f52ff56f62bd3", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/c7/91f468ff6714872fe4329a11b27d", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/85/ef/23050d0205b3449a8e4c74c35e62", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ef/a1/78572099ac9ef2d0734fb14ed164" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2e/aa/9bcdf166975aa5295669df48f641", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/44/091ec27299abfb3e4a12efbb4016", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1b/2f/99bcfa67fb5a77d9d80883fcc9a4", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f6/f5/fbd4514b7ca4663f917ee848acc5", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/3c/7f4895731a58ab99c8deb2caa563", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/d5/5a51c250695ce84b0cf2d59ef447", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/e9/33f406d3ff1a7a5ec5c0d7f185e6", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/53/55/1f3e23b7c6e975056854005de9aa", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c5/5d/56272619667b1fcd87b759d8688d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8b/d0/24e71e25ac40fbd513e21c318ba4", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8a/6a/ba53af1a84abfa764213f1791ea2", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d8/7b/b32727ec4d7e899d54ebe83e1203" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 1763add7..62472471 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -34,6 +34,7 @@ acnt actionhero activityname + activityplayer activitytypes activityutils actorclass diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index fb7554fd..cea20518 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=214847179904844500339904334878206016957 +# SOURCES_HASH=78832523659898286100096175148597852751 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -843,7 +843,7 @@ class SessionPlayer: character: str The character this player has selected in their profile. - gameplayer: Optional[ba.Player] + activityplayer: Optional[ba.Player] The current game-specific instance for this player. """ id: int @@ -853,7 +853,7 @@ class SessionPlayer: color: Sequence[float] highlight: Sequence[float] character: str - gameplayer: Optional[ba.Player] + activityplayer: Optional[ba.Player] def assigninput(self, type: Union[str, Tuple[str, ...]], call: Callable) -> None: diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 936cdef6..d3f41562 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -39,7 +39,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, open_url, widget) from ba._activity import Activity from ba._actor import Actor -from ba._player import PlayerInfo, Player, StandLocation +from ba._player import PlayerInfo, Player, EmptyPlayer, StandLocation from ba._nodeactor import NodeActor from ba._app import App from ba._coopgame import CoopGameActivity @@ -62,7 +62,7 @@ from ba._session import Session from ba._servermode import ServerController from ba._score import ScoreType, ScoreInfo from ba._stats import PlayerScoredMessage, PlayerRecord, Stats -from ba._team import SessionTeam, Team +from ba._team import SessionTeam, Team, EmptyTeam from ba._teamgame import TeamGameActivity from ba._dualteamsession import DualTeamSession from ba._achievement import Achievement diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 6c494c5f..0fa0d50e 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -140,7 +140,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # the next activity? can_show_ad_on_death = False - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): """Creates an Activity in the current ba.Session. The activity will not be actually run until ba.Session.setactivity() @@ -582,7 +582,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): assert team is not None sessionplayer.setactivity(self) with _ba.Context(self): - sessionplayer.gameplayer = player = self.create_player( + sessionplayer.activityplayer = player = self.create_player( sessionplayer) player.postinit(sessionplayer) @@ -606,7 +606,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): """ assert not self.expired - player: Any = sessionplayer.gameplayer + player: Any = sessionplayer.activityplayer assert isinstance(player, self._playertype) team: Any = sessionplayer.sessionteam.gameteam assert isinstance(team, self._teamtype) @@ -714,7 +714,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # These should never fail I think... sessionplayer.setactivity(None) - sessionplayer.gameplayer = None + sessionplayer.activityplayer = None def _setup_player_and_team_types(self) -> None: """Pull player and team types from our typing.Generic params.""" diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index cb03c75c..66bbc980 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -26,9 +26,9 @@ from typing import TYPE_CHECKING import _ba from ba._activity import Activity from ba._music import setmusic, MusicType -# False positive due to our class_generics_filter custom pylint filter. -from ba import _player -from ba import _team +# False-positive from pylint due to our class-generics-filter. +from ba._player import EmptyPlayer # pylint: disable=W0611 +from ba._team import EmptyTeam # pylint: disable=W0611 if TYPE_CHECKING: from typing import Any, Dict, Optional @@ -36,21 +36,10 @@ if TYPE_CHECKING: from ba._lobby import JoinInfo -# Even though we don't need custom Player/Team types, define empty ones -# so we don't have ba.Player[Any] and ba.Team[Any] as our types which -# reduces type safety. -class Player(_player.Player['Team']): - """Our player type for this game.""" - - -class Team(_team.Team[Player]): - """Our team type for this game.""" - - -class EndSessionActivity(Activity[Player, Team]): +class EndSessionActivity(Activity[EmptyPlayer, EmptyTeam]): """Special ba.Activity to fade out and end the current ba.Session.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) # Keeps prev activity alive while we fade out. @@ -75,13 +64,13 @@ class EndSessionActivity(Activity[Player, Team]): call_after_ad(Call(_ba.new_host_session, MainMenuSession)) -class JoinActivity(Activity[Player, Team]): +class JoinActivity(Activity[EmptyPlayer, EmptyTeam]): """Standard activity for waiting for players to join. It shows tips and other info and waits for all players to check ready. """ - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) # This activity is a special 'joiner' activity. @@ -112,13 +101,13 @@ class JoinActivity(Activity[Player, Team]): _ba.set_analytics_screen('Joining Screen') -class TransitionActivity(Activity[Player, Team]): +class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]): """A simple overlay fade out/in. Useful as a bare minimum transition between two level based activities. """ - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) # Keep prev activity alive while we fade in. @@ -145,13 +134,13 @@ class TransitionActivity(Activity[Player, Team]): _ba.timer(0.1, self.end) -class ScoreScreenActivity(Activity[Player, Team]): +class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): """A standard score screen that fades in and shows stuff for a while. After a specified delay, player input is assigned to end the activity. """ - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self.transition_time = 0.5 self.inherits_tint = True @@ -169,7 +158,7 @@ class ScoreScreenActivity(Activity[Player, Team]): self._custom_continue_message: Optional[ba.Lstr] = None self._server_transitioning: Optional[bool] = None - def on_player_join(self, player: Player) -> None: + def on_player_join(self, player: EmptyPlayer) -> None: from ba import _general super().on_player_join(player) time_till_assign = max( @@ -235,7 +224,7 @@ class ScoreScreenActivity(Activity[Player, Team]): # Otherwise end the activity normally. self.end() - def _safe_assign(self, player: Player) -> None: + def _safe_assign(self, player: EmptyPlayer) -> None: # Just to be extra careful, don't assign if we're transitioning out. # (though theoretically that would be ok). diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index 08c72572..6bba3296 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -50,7 +50,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): from ba._coopsession import CoopSession return issubclass(sessiontype, CoopSession) - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) # Cache these for efficiency. diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 370bc7a5..188d599d 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -278,7 +278,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # By default, games support any versus mode return issubclass(sessiontype, MultiTeamSession) - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): """Instantiate the Activity.""" super().__init__(settings) @@ -1224,7 +1224,7 @@ class GameActivity(Activity[PlayerType, TeamType]): trail=trail, color=color).autoretain() - def _calc_map_name(self, settings: Dict[str, Any]) -> str: + def _calc_map_name(self, settings: dict) -> str: map_name: str if 'map' in settings: map_name = settings['map'] diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py index 8f59099a..05d4f709 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -42,7 +42,7 @@ class Level: def __init__(self, name: str, gametype: Type[ba.GameActivity], - settings: Dict[str, Any], + settings: dict, preview_texture_name: str, displayname: str = None): """Initializes a Level object with the provided values.""" diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index b986d04c..3a1c38e1 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -299,6 +299,23 @@ class Player(Generic[TeamType]): return self.exists() +class EmptyPlayer(Player['ba.EmptyTeam']): + """An empty player for use by Activities that don't need to define one. + + Category: Gameplay Classes + + ba.Player and ba.Team are 'Generic' types, and so passing them as + type arguments when defining a ba.Activity reduces type safety. + For example, activity.teams[0].player will have type 'Any' in that case. + For that reason, it is better to pass EmptyPlayer and EmptyTeam when + defining a ba.Activity that does not need custom types of its own. + + Note that EmptyPlayer defines its team type as EmptyTeam and vice versa, + so if you want to define your own class for one of them you must do so + for both. + """ + + # NOTE: It seems we might not need these playercast() calls; have gone # the direction where things returning players generally take a type arg # and do this themselves; that way the user is 'forced' to deal with types diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 98b97728..a290efde 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -274,7 +274,7 @@ class Session: ' in on_player_leave.') # Grab their activity-specific player instance. - player = sessionplayer.gameplayer + player = sessionplayer.activityplayer assert isinstance(player, (Player, type(None))) # Remove them from any current Activity. diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index cdc0271d..b92dc374 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -206,9 +206,9 @@ class PlayerRecord: # a current position for them. our_pos: Optional[Sequence[float]] = None if self._player is not None: - if self._player.gameplayer is not None: - if self._player.gameplayer.node: - our_pos = self._player.gameplayer.node.position + if self._player.activityplayer is not None: + if self._player.activityplayer.node: + our_pos = self._player.activityplayer.node.position if our_pos is None: return diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index fa4be4d6..23326f82 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -211,3 +211,20 @@ class Team(Generic[PlayerType]): return sessionteam from ba import _error raise _error.SessionTeamNotFoundError() + + +class EmptyTeam(Team['ba.EmptyPlayer']): + """An empty player for use by Activities that don't need to define one. + + Category: Gameplay Classes + + ba.Player and ba.Team are 'Generic' types, and so passing them as + type arguments when defining a ba.Activity reduces type safety. + For example, activity.teams[0].player will have type 'Any' in that case. + For that reason, it is better to pass EmptyPlayer and EmptyTeam when + defining a ba.Activity that does not need custom types of its own. + + Note that EmptyPlayer defines its team type as EmptyTeam and vice versa, + so if you want to define your own class for one of them you must do so + for both. + """ diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index c34a67b4..b6cb3386 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -58,7 +58,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): return (issubclass(sessiontype, DualTeamSession) or issubclass(sessiontype, FreeForAllSession)) - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) # By default we don't show kill-points in free-for-all sessions. diff --git a/assets/src/ba_data/python/bastd/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py index 78addd43..54bd831f 100644 --- a/assets/src/ba_data/python/bastd/activity/coopjoin.py +++ b/assets/src/ba_data/python/bastd/activity/coopjoin.py @@ -38,7 +38,7 @@ class CoopJoinActivity(JoinActivity): # We can assume our session is a CoopSession. session: ba.CoopSession - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) session = self.session assert isinstance(session, ba.CoopSession) diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 45d4b0b2..e3092882 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -41,7 +41,7 @@ if TYPE_CHECKING: class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): """Score screen showing the results of a cooperative game.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): # pylint: disable=too-many-statements super().__init__(settings) diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index 5c7e28cd..8831d687 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -35,7 +35,7 @@ if TYPE_CHECKING: class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): """Scorescreen between rounds of a dual-team session.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings=settings) self._winner: ba.SessionTeam = settings['winner'] assert isinstance(self._winner, ba.SessionTeam) diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py index 9e0de4e8..3dd4232c 100644 --- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py +++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py @@ -34,7 +34,7 @@ if TYPE_CHECKING: class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): """Score screen shown at after free-for-all rounds.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings=settings) # Keep prev activity alive while we fade in. diff --git a/assets/src/ba_data/python/bastd/activity/multiteamjoin.py b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py index 08b10b71..56e344ae 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamjoin.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py @@ -35,7 +35,7 @@ if TYPE_CHECKING: class MultiTeamJoinActivity(JoinActivity): """Join screen for teams sessions.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._next_up_text: Optional[Text] = None diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index 77b2a5f9..909619b5 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -35,7 +35,7 @@ if TYPE_CHECKING: class MultiTeamScoreScreenActivity(ScoreScreenActivity): """Base class for score screens.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings=settings) self._score_display_sound = ba.getsound('scoreHit01') self._score_display_sound_small = ba.getsound('scoreHit02') diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 39f37f8c..ea2bd5ae 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -34,7 +34,7 @@ if TYPE_CHECKING: class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): """Final score screen for a team series.""" - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings=settings) self._min_view_time = 15.0 self._is_ffa = isinstance(self.session, ba.FreeForAllSession) diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index f58594af..3aa609fa 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -86,7 +86,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('team_flag') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._last_score_time = 0.0 diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 79528594..44ae5bb9 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -153,7 +153,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('team_flag') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._alarmsound = ba.getsound('alarm') diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 740631bc..dd6cb3dd 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -95,7 +95,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('keep_away') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._chosen_one_player: Optional[Player] = None diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 8ae90f0c..3a40e783 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -120,7 +120,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('conquest') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 2c2395d6..2ce26015 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -101,7 +101,7 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('melee') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._score_to_win: Optional[int] = None diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index bef86f60..9d1b98cb 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -77,7 +77,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): or issubclass(sessiontype, ba.DualTeamSession) or issubclass(sessiontype, ba.FreeForAllSession)) - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._last_player_death_time = None diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index a2acd319..b6bbae25 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -237,7 +237,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('melee') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._start_time: Optional[float] = None diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index e8c03711..3d8abc67 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -123,7 +123,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('football') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard: Optional[Scoreboard] = Scoreboard() @@ -329,9 +329,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): class FootballCoopGame(ba.CoopGameActivity[Player, Team]): - """ - Co-op variant of football - """ + """Co-op variant of football.""" name = 'Football' tips = ['Use the pick-up button to grab the flag < ${PICKUP} >'] @@ -356,7 +354,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): return 'score ${ARG1} touchdowns', touchdowns return 'score a touchdown' - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): settings['map'] = 'Football Stadium' super().__init__(settings) self._preset = settings.get('preset', 'rookie') diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 0f13c998..57a17ec0 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -153,7 +153,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('hockey') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 0dda4482..9ae4600a 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -94,7 +94,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('keep_away') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._swipsound = ba.getsound('swip') diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 56c04457..8d98b26e 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -96,7 +96,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('king_of_the_hill') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) shared = SharedObjects.get() self._scoreboard = Scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index c9887da8..7512a186 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -74,7 +74,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): or issubclass(sessiontype, ba.FreeForAllSession) or issubclass(sessiontype, ba.CoopSession)) - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._epic_mode = settings.get('Epic Mode', False) diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 72e15581..c2187f80 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -71,7 +71,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): # In the constructor we should load any media we need/etc. # ...but not actually create anything yet. - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._winsound = ba.getsound('score') self._won = False diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 430a7251..607ce182 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -155,7 +155,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): # Show messages when players die since it matters here. announce_player_deaths = True - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): self._preset = Preset(settings.get('preset', 'training')) if self._preset in { diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index cc90ff7a..be5d0ec5 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -144,7 +144,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: return ba.getmaps('race') - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): self._race_started = False super().__init__(settings) self._scoreboard = Scoreboard() diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index d4b1b6cb..cf27e920 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -86,7 +86,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): StickyBot: 0.5 } - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): settings['map'] = 'Tower D' super().__init__(settings) shared = SharedObjects.get() diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 7832b038..632ddc46 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -83,7 +83,7 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): return (issubclass(sessiontype, ba.CoopSession) or issubclass(sessiontype, ba.MultiTeamSession)) - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): super().__init__(settings) self._scoreboard = Scoreboard() self._targets: List[Target] = [] diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 77c74e81..047c8a29 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -77,7 +77,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): default_music = ba.MusicType.EPIC - def __init__(self, settings: Dict[str, Any]): + def __init__(self, settings: dict): settings['map'] = 'Rampage' super().__init__(settings) self._new_wave_sound = ba.getsound('scoreHit01') diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index 8e95c00e..95a65111 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -197,7 +197,7 @@ class Team(ba.Team[Player]): class TutorialActivity(ba.Activity[Player, Team]): - def __init__(self, settings: Dict[str, Any] = None): + def __init__(self, settings: dict = None): from bastd.maps import Rampage if settings is None: settings = {} diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index 758b432f..8faea5ad 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -39,7 +39,7 @@ class GamepadSettingsWindow(ba.Window): is_main_menu: bool = True, transition: str = 'in_right', transition_out: str = 'out_right', - settings: Dict[str, Any] = None): + settings: dict = None): self._input = gamepad # If this fails, our input device went away or something; diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index b7c04984..340a5446 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -262,7 +262,7 @@ class ConfigKeyboardWindow(ba.Window): class AwaitKeyboardInputWindow(ba.Window): """Window for capturing a keypress.""" - def __init__(self, button: str, ui: ba.Widget, settings: Dict[str, Any]): + def __init__(self, button: str, ui: ba.Widget, settings: dict): self._capture_button = button self._capture_key_ui = ui diff --git a/docs/ba_module.md b/docs/ba_module.md index af2783a2..12344a28 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -26,6 +26,9 @@

  • ba.Material
  • ba.Node
  • ba.Player
  • +
  • ba.PlayerInfo
  • ba.PlayerRecord
  • ba.ScoreInfo
  • @@ -43,6 +46,9 @@
  • ba.StandLocation
  • ba.Stats
  • ba.Team
  • +
  • ba.TeamGameResults
  • Gameplay Functions

    @@ -424,7 +430,7 @@ regardless of the player count).

    <constructor>, add_actor_weak_ref(), create_player(), create_team(), end(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_begin(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), retain_actor(), transition_out()

    <constructor>

    -

    ba.Activity(settings: Dict[str, Any])

    +

    ba.Activity(settings: dict)

    Creates an Activity in the current ba.Session.

    @@ -1616,7 +1622,7 @@ start_long_action(callback_when_done=ba.ContextC
    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()

    <constructor>

    -

    ba.CoopGameActivity(settings: Dict[str, Any])

    +

    ba.CoopGameActivity(settings: dict)

    Instantiate the Activity.

    @@ -2063,6 +2069,111 @@ its time with lingering corpses, sound effects, etc.


    +

    ba.EmptyPlayer

    +

    Inherits from: ba.Player, typing.Generic

    +

    An empty player for use by Activities that don't need to define one.

    + +

    Category: Gameplay Classes

    + +

    ba.Player and ba.Team are 'Generic' types, and so passing them as + type arguments when defining a ba.Activity reduces type safety. + For example, activity.teams[0].player will have type 'Any' in that case. + For that reason, it is better to pass EmptyPlayer and EmptyTeam when + defining a ba.Activity that does not need custom types of its own.

    + +

    Note that EmptyPlayer defines its team type as EmptyTeam and vice versa, + so if you want to define your own class for one of them you must do so + for both. +

    + +

    Attributes Inherited:

    +
    actor
    +

    Attributes Defined Here:

    +
    customdata, node, position, sessionplayer, team
    +
    +

    customdata

    +

    dict

    +

    Arbitrary values associated with the player. + Though it is encouraged that most player values be properly defined + on the ba.Player subclass, it may be useful for player-agnostic + objects to store values here. This dict is cleared when the player + leaves or expires so objects stored here will be disposed of at + the expected time, unlike the Player instance itself which may + continue to be referenced after it is no longer part of the game.

    + +
    +

    node

    +

    ba.Node

    +

    A ba.Node of type 'player' associated with this Player.

    + +

    This node can be used to get a generic player position/etc.

    + +
    +

    position

    +

    ba.Vec3

    +

    The position of the player, as defined by its current ba.Actor.

    + +

    This value is undefined when the player has no Actor.

    + +
    +

    sessionplayer

    +

    ba.SessionPlayer

    +

    Return the ba.SessionPlayer corresponding to this Player.

    + +

    Throws a ba.SessionPlayerNotFoundError if it does not exist.

    + +
    +

    team

    +

    TeamType

    +

    The ba.Team for this player.

    + +
    +
    +

    Methods:

    +

    <all methods inherited from ba.Player>

    +
    +

    ba.EmptyTeam

    +

    Inherits from: ba.Team, typing.Generic

    +

    An empty player for use by Activities that don't need to define one.

    + +

    Category: Gameplay Classes

    + +

    ba.Player and ba.Team are 'Generic' types, and so passing them as + type arguments when defining a ba.Activity reduces type safety. + For example, activity.teams[0].player will have type 'Any' in that case. + For that reason, it is better to pass EmptyPlayer and EmptyTeam when + defining a ba.Activity that does not need custom types of its own.

    + +

    Note that EmptyPlayer defines its team type as EmptyTeam and vice versa, + so if you want to define your own class for one of them you must do so + for both. +

    + +

    Attributes:

    +
    customdata, sessionteam
    +
    +

    customdata

    +

    dict

    +

    Arbitrary values associated with the team. + Though it is encouraged that most player values be properly defined + on the ba.Team subclass, it may be useful for player-agnostic + objects to store values here. This dict is cleared when the team + leaves or expires so objects stored here will be disposed of at + the expected time, unlike the Team instance itself which may + continue to be referenced after it is no longer part of the game.

    + +
    +

    sessionteam

    +

    SessionTeam

    +

    Return the ba.SessionTeam corresponding to this Team.

    + +

    Throws a ba.SessionTeamNotFoundError if there is none.

    + +
    +
    +

    Methods:

    +

    <all methods inherited from ba.Team>

    +

    ba.Existable

    Inherits from: typing_extensions.Protocol

    A Protocol for objects supporting an exists() method.

    @@ -2209,7 +2320,7 @@ its time with lingering corpses, sound effects, etc.

    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    -

    ba.GameActivity(settings: Dict[str, Any])

    +

    ba.GameActivity(settings: dict)

    Instantiate the Activity.

    @@ -2785,7 +2896,7 @@ prefs, etc.

    <constructor>, get_campaign(), get_high_scores(), get_preview_texture(), get_score_version_string(), get_settings(), set_complete(), set_high_scores(), set_rating()

    <constructor>

    -

    ba.Level(name: str, gametype: Type[ba.GameActivity], settings: Dict[str, Any], preview_texture_name: str, displayname: str = None)

    +

    ba.Level(name: str, gametype: Type[ba.GameActivity], settings: dict, preview_texture_name: str, displayname: str = None)

    Initializes a Level object with the provided values.

    @@ -4557,8 +4668,13 @@ that a SessionPlayer is still present if retaining references to one for any length of time.

    Attributes:

    -
    character, color, gameplayer, highlight, id, in_game, inputdevice, sessionteam
    +
    activityplayer, character, color, highlight, id, in_game, inputdevice, sessionteam
    +

    activityplayer

    +

    Optional[ba.Player]

    +

    The current game-specific instance for this player.

    + +

    character

    str

    The character this player has selected in their profile.

    @@ -4569,11 +4685,6 @@ for any length of time.

    The base color for this Player. In team games this will match the ba.SessionTeam's color.

    -
    -

    gameplayer

    -

    Optional[ba.Player]

    -

    The current game-specific instance for this player.

    -

    highlight

    Sequence[float]

    @@ -5124,7 +5235,7 @@ of the session.

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()

    <constructor>

    -

    ba.TeamGameActivity(settings: Dict[str, Any])

    +

    ba.TeamGameActivity(settings: dict)

    Instantiate the Activity.

    From 5b4282eb11d02b47e20735c50bdddca8cd0dba5a Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 18:46:38 -0700 Subject: [PATCH 071/417] Made game settings type safe --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 4 + assets/.asset_manifest_public.json | 2 + assets/Makefile | 7 + assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/__init__.py | 5 +- assets/src/ba_data/python/ba/_appdelegate.py | 5 +- assets/src/ba_data/python/ba/_coopgame.py | 2 +- assets/src/ba_data/python/ba/_coopsession.py | 16 +- assets/src/ba_data/python/ba/_gameactivity.py | 36 +-- assets/src/ba_data/python/ba/_gameresults.py | 10 +- assets/src/ba_data/python/ba/_gamesettings.py | 102 ++++++++ assets/src/ba_data/python/ba/_level.py | 2 +- assets/src/ba_data/python/ba/_playlist.py | 9 +- assets/src/ba_data/python/ba/_score.py | 4 +- .../src/ba_data/python/bastd/appdelegate.py | 5 +- .../src/ba_data/python/bastd/game/assault.py | 49 ++-- .../python/bastd/game/capturetheflag.py | 67 ++--- .../ba_data/python/bastd/game/chosenone.py | 61 +++-- .../src/ba_data/python/bastd/game/conquest.py | 40 +-- .../ba_data/python/bastd/game/deathmatch.py | 64 +++-- .../python/bastd/game/easteregghunt.py | 4 +- .../ba_data/python/bastd/game/elimination.py | 69 ++--- .../src/ba_data/python/bastd/game/football.py | 52 ++-- .../src/ba_data/python/bastd/game/hockey.py | 47 ++-- .../src/ba_data/python/bastd/game/keepaway.py | 49 ++-- .../python/bastd/game/kingofthehill.py | 49 ++-- .../ba_data/python/bastd/game/meteorshower.py | 8 +- .../ba_data/python/bastd/game/ninjafight.py | 6 +- assets/src/ba_data/python/bastd/game/race.py | 76 +++--- .../python/bastd/game/targetpractice.py | 15 +- .../python/bastd/ui/playlist/editgame.py | 60 ++--- docs/ba_module.md | 236 +++++++++++++----- 33 files changed, 764 insertions(+), 423 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_gamesettings.py diff --git a/.efrocachemap b/.efrocachemap index 9959a6e0..988b9239 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2e/aa/9bcdf166975aa5295669df48f641", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/44/091ec27299abfb3e4a12efbb4016", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1b/2f/99bcfa67fb5a77d9d80883fcc9a4", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f6/f5/fbd4514b7ca4663f917ee848acc5", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/3c/7f4895731a58ab99c8deb2caa563", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/d5/5a51c250695ce84b0cf2d59ef447", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/e9/33f406d3ff1a7a5ec5c0d7f185e6", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/53/55/1f3e23b7c6e975056854005de9aa", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c5/5d/56272619667b1fcd87b759d8688d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8b/d0/24e71e25ac40fbd513e21c318ba4", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8a/6a/ba53af1a84abfa764213f1791ea2", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d8/7b/b32727ec4d7e899d54ebe83e1203" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1f/1d/c3e431b8c9116fb76eb10c7c3351", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/b8/9cb66184745ef1d783af3f7d3f22", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/52/e8/4826278e2030d629a682a8de070f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/8a/9e07236256d006f0357d5d1aa887", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/81/38/985294f68973344e2f012fe93c45", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/57/2cdf16147cdd25263ba76aa40198", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/ec/1d64c0c31d58ef530b6894fabf2a", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/ea/c136ba4360d210842915c2f6c55e", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/35/06/d5ae11c90f89d1c10ca62a2b2f66", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a1/e9/960e434759c45b623fba34725e64", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dd/d0/f85582938a539d2d677d3e36b61b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/e9/3685ecf7b07f3e3568867da5536f" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 62472471..da52b07d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -746,6 +746,7 @@ gameplayer gameport gameresults + gamesettings gameteam gametype gametypes @@ -783,6 +784,7 @@ getpt getremote getscanresults + getscoreconfig getsession getsockname getsound @@ -1444,6 +1446,7 @@ prevstate priceraw printcolors + printf printnodes printobjects printpaths @@ -1640,6 +1643,7 @@ sched sclx scly + scoreconfig scorescreen scoreteam scoretxt diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index 24552382..df9ec086 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -24,6 +24,7 @@ "ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc", @@ -80,6 +81,7 @@ "ba_data/python/ba/_freeforallsession.py", "ba_data/python/ba/_gameactivity.py", "ba_data/python/ba/_gameresults.py", + "ba_data/python/ba/_gamesettings.py", "ba_data/python/ba/_gameutils.py", "ba_data/python/ba/_general.py", "ba_data/python/ba/_hooks.py", diff --git a/assets/Makefile b/assets/Makefile index b5f37459..1d120c97 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -166,6 +166,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_freeforallsession.py \ build/ba_data/python/ba/_gameactivity.py \ build/ba_data/python/ba/_gameresults.py \ + build/ba_data/python/ba/_gamesettings.py \ build/ba_data/python/ba/_gameutils.py \ build/ba_data/python/ba/_general.py \ build/ba_data/python/ba/_hooks.py \ @@ -396,6 +397,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc \ @@ -734,6 +736,11 @@ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_gamesettings.py + @echo Compiling script: $^ + @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameutils.py @echo Compiling script: $^ diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index cea20518..667f6921 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=78832523659898286100096175148597852751 +# SOURCES_HASH=48988468250135652281791058794704714718 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index d3f41562..9f1c38b3 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -56,11 +56,14 @@ from ba._error import ( from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity from ba._gameresults import TeamGameResults +from ba._gamesettings import (Setting, IntSetting, FloatSetting, ChoiceSetting, + BoolSetting, IntChoiceSetting, + FloatChoiceSetting) from ba._lang import Lstr, setlanguage, get_valid_languages from ba._map import Map, getmaps from ba._session import Session from ba._servermode import ServerController -from ba._score import ScoreType, ScoreInfo +from ba._score import ScoreType, ScoreConfig from ba._stats import PlayerScoredMessage, PlayerRecord, Stats from ba._team import SessionTeam, Team, EmptyTeam from ba._teamgame import TeamGameActivity diff --git a/assets/src/ba_data/python/ba/_appdelegate.py b/assets/src/ba_data/python/ba/_appdelegate.py index a1bcb9de..148b5587 100644 --- a/assets/src/ba_data/python/ba/_appdelegate.py +++ b/assets/src/ba_data/python/ba/_appdelegate.py @@ -36,9 +36,8 @@ class AppDelegate: def create_default_game_settings_ui( self, gameclass: Type[ba.GameActivity], - sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], - completion_call: Callable[[Optional[Dict[str, Any]]], - None]) -> None: + sessionclass: Type[ba.Session], config: Optional[dict], + completion_call: Callable[[Optional[dict]], None]) -> None: """Launch a UI to configure the given game config. It should manipulate the contents of config and call completion_call diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index 6bba3296..0895181d 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -121,7 +121,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): animate(txt.node, 'scale', {1.0: 0.0, 1.1: 0.7, 1.2: 0.6}) break - # FIXME: this is now redundant with activityutils.get_score_info(); + # FIXME: this is now redundant with activityutils.getscoreconfig(); # need to kill this. def get_score_type(self) -> str: """ diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 22456491..ac2b4add 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -121,10 +121,10 @@ class CoopSession(Session): settings = level.get_settings() # Make sure all settings the game expects are present. - neededsettings = gametype.get_game_settings(type(self)) - for settingname, setting in neededsettings: - if settingname not in settings: - settings[settingname] = setting['default'] + neededsettings = gametype.get_available_settings(type(self)) + for setting in neededsettings: + if setting.name not in settings: + settings[setting.name] = setting.default newactivity = _ba.new_activity(gametype, settings) assert isinstance(newactivity, GameActivity) @@ -144,10 +144,10 @@ class CoopSession(Session): settings = nextlevel.get_settings() # Make sure all settings the game expects are present. - neededsettings = gametype.get_game_settings(type(self)) - for settingname, setting in neededsettings: - if settingname not in settings: - settings[settingname] = setting['default'] + neededsettings = gametype.get_available_settings(type(self)) + for setting in neededsettings: + if setting.name not in settings: + settings[setting.name] = setting.default # We wanna be in the activity's context while taking it down. newactivity = _ba.new_activity(gametype, settings) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 188d599d..66f8d263 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -27,7 +27,7 @@ import random from typing import TYPE_CHECKING, TypeVar from ba._activity import Activity -from ba._score import ScoreInfo +from ba._score import ScoreConfig from ba._lang import Lstr from ba._messages import PlayerDiedMessage, StandMessage from ba._error import NotFoundError, print_error, print_exception @@ -62,11 +62,11 @@ class GameActivity(Activity[PlayerType, TeamType]): # Default get_description() will return this if not None. description: Optional[str] = None - # Default get_game_settings() will return this if not None. - game_settings: Optional[List[Tuple[str, Dict[str, Any]]]] = None + # Default get_available_settings() will return this if not None. + available_settings: Optional[List[ba.Setting]] = None - # Default get_score_info() will return this if not None. - score_info: Optional[ba.ScoreInfo] = None + # Default getscoreconfig() will return this if not None. + scoreconfig: Optional[ba.ScoreConfig] = None # Override some defaults. allow_pausing = True @@ -83,8 +83,8 @@ class GameActivity(Activity[PlayerType, TeamType]): def create_settings_ui( cls, sessionclass: Type[ba.Session], - settings: Optional[Dict[str, Any]], - completion_call: Callable[[Optional[Dict[str, Any]]], None], + settings: Optional[dict], + completion_call: Callable[[Optional[dict]], None], ) -> None: """Launch an in-game UI to configure settings for a game type. @@ -93,11 +93,11 @@ class GameActivity(Activity[PlayerType, TeamType]): 'config' should be an existing config dict (specifies 'edit' ui mode) or None (specifies 'add' ui mode). - 'completion_call' will be called with a filled-out config dict on + 'completion_call' will be called with a filled-out settings dict on success or None on cancel. Generally subclasses don't need to override this; if they override - ba.GameActivity.get_game_settings() and + ba.GameActivity.get_available_settings() and ba.GameActivity.get_supported_maps() they can just rely on the default implementation here which calls those methods. """ @@ -107,9 +107,10 @@ class GameActivity(Activity[PlayerType, TeamType]): completion_call) @classmethod - def get_score_info(cls) -> ba.ScoreInfo: + def getscoreconfig(cls) -> ba.ScoreConfig: """Return info about game scoring setup; can be overridden by games.""" - return cls.score_info if cls.score_info is not None else ScoreInfo() + return cls.scoreconfig if cls.scoreconfig is not None else ScoreConfig( + ) @classmethod def getname(cls) -> str: @@ -129,7 +130,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # A few substitutions for 'Epic', 'Solo' etc. modes. # FIXME: Should provide a way for game types to define filters of - # their own. + # their own and should not rely on hard-coded settings names. if settings is not None: if 'Solo Mode' in settings and settings['Solo Mode']: name = Lstr(resource='soloNameFilterText', @@ -167,9 +168,8 @@ class GameActivity(Activity[PlayerType, TeamType]): return Lstr(translate=('gameDescriptions', description)) @classmethod - def get_game_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: """ Called by the default ba.GameActivity.create_settings_ui() implementation; should return a dict of config options to be presented @@ -191,9 +191,9 @@ class GameActivity(Activity[PlayerType, TeamType]): 'increment': Value increment for int/float settings. - # example get_game_settings() for a capture-the-flag game: + # example get_available_settings() for a capture-the-flag game: @classmethod - def get_game_settings(cls, sessiontype): + def get_available_settings(cls, sessiontype): return [("Score to Win", { 'default': 3, 'min_value': 1 @@ -228,7 +228,7 @@ class GameActivity(Activity[PlayerType, TeamType]): })] """ del sessiontype # Unused arg. - return [] if cls.game_settings is None else cls.game_settings + return [] if cls.available_settings is None else cls.available_settings @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index c7009ff4..58e0a285 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -68,12 +68,12 @@ class TeamGameResults: raise RuntimeError('Game set twice for TeamGameResults.') self._game_set = True self._sessionteams = [weakref.ref(team) for team in game.teams] - score_info = game.get_score_info() + scoreconfig = game.getscoreconfig() self._playerinfos = copy.deepcopy(game.initialplayerinfos) - self._lower_is_better = score_info.lower_is_better - self._score_label = score_info.label - self._none_is_winner = score_info.none_is_winner - self._scoretype = score_info.scoretype + self._lower_is_better = scoreconfig.lower_is_better + self._score_label = scoreconfig.label + self._none_is_winner = scoreconfig.none_is_winner + self._scoretype = scoreconfig.scoretype def set_team_score(self, team: ba.Team, score: Optional[int]) -> None: """Set the score for a given ba.Team. diff --git a/assets/src/ba_data/python/ba/_gamesettings.py b/assets/src/ba_data/python/ba/_gamesettings.py new file mode 100644 index 00000000..260ad63f --- /dev/null +++ b/assets/src/ba_data/python/ba/_gamesettings.py @@ -0,0 +1,102 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Functionality for user-controllable settings.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING +from dataclasses import dataclass + +if TYPE_CHECKING: + from typing import Any, List, Tuple + + +@dataclass +class Setting: + """Defines a user-controllable setting for a game or other entity. + + Category: Gameplay Classes + """ + + name: str + default: Any + + +@dataclass +class BoolSetting(Setting): + """A boolean game setting. + + Category: Settings Classes + """ + default: bool + + +@dataclass +class IntSetting(Setting): + """An integer game setting. + + Category: Settings Classes + """ + default: int + min_value: int = 0 + max_value: int = 9999 + increment: int = 1 + + +@dataclass +class FloatSetting(Setting): + """A floating point game setting. + + Category: Settings Classes + """ + default: float + min_value: float = 0.0 + max_value: float = 9999.0 + increment: float = 1.0 + + +@dataclass +class ChoiceSetting(Setting): + """A setting with multiple choices. + + Category: Settings Classes + """ + choices: List[Tuple[str, Any]] + + +@dataclass +class IntChoiceSetting(ChoiceSetting): + """An int setting with multiple choices. + + Category: Settings Classes + """ + default: int + choices: List[Tuple[str, int]] + + +@dataclass +class FloatChoiceSetting(ChoiceSetting): + """A float setting with multiple choices. + + Category: Settings Classes + """ + default: float + choices: List[Tuple[str, float]] diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py index 05d4f709..ffe88bde 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -144,7 +144,7 @@ class Level: can be changed to separate its new high score lists/etc. from the old. """ if self._score_version_string is None: - scorever = self._gametype.get_score_info().version + scorever = self._gametype.getscoreconfig().version if scorever != '': scorever = ' ' + scorever self._score_version_string = scorever diff --git a/assets/src/ba_data/python/ba/_playlist.py b/assets/src/ba_data/python/ba/_playlist.py index 22c18c1b..29dc896f 100644 --- a/assets/src/ba_data/python/ba/_playlist.py +++ b/assets/src/ba_data/python/ba/_playlist.py @@ -151,11 +151,10 @@ def filter_playlist(playlist: PlaylistType, entry['is_unowned_game'] = True # Make sure all settings the game defines are present. - neededsettings = gameclass.get_game_settings(sessiontype) - for setting_name, setting in neededsettings: - if (setting_name not in entry['settings'] - and 'default' in setting): - entry['settings'][setting_name] = setting['default'] + neededsettings = gameclass.get_available_settings(sessiontype) + for setting in neededsettings: + if setting.name not in entry['settings']: + entry['settings'][setting.name] = setting.default goodlist.append(entry) except ImportError as exc: print(f'Import failed while scanning playlist: {exc}') diff --git a/assets/src/ba_data/python/ba/_score.py b/assets/src/ba_data/python/ba/_score.py index 83432b0f..79326f7c 100644 --- a/assets/src/ba_data/python/ba/_score.py +++ b/assets/src/ba_data/python/ba/_score.py @@ -42,8 +42,8 @@ class ScoreType(Enum): @dataclass -class ScoreInfo: - """Info about a game's scoring setup. +class ScoreConfig: + """Settings for how a game handles scores. Category: Gameplay Classes diff --git a/assets/src/ba_data/python/bastd/appdelegate.py b/assets/src/ba_data/python/bastd/appdelegate.py index 11b145d4..c3e19ee0 100644 --- a/assets/src/ba_data/python/bastd/appdelegate.py +++ b/assets/src/ba_data/python/bastd/appdelegate.py @@ -34,9 +34,8 @@ class AppDelegate(ba.AppDelegate): def create_default_game_settings_ui( self, gameclass: Type[ba.GameActivity], - sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], - completion_call: Callable[[Optional[Dict[str, Any]]], - Any]) -> None: + sessionclass: Type[ba.Session], config: Optional[dict], + completion_call: Callable[[Optional[dict]], Any]) -> None: """(internal)""" # Replace the main window once we come up successfully. diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 3aa609fa..d1226977 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -57,25 +57,36 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): name = 'Assault' description = 'Reach the enemy flag to score.' - game_settings = [ - ('Score to Win', { - 'min_value': 1, - 'default': 3 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=3, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), ] @classmethod diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 44ae5bb9..3f709d0b 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -114,35 +114,44 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): name = 'Capture the Flag' description = 'Return the enemy flag to score.' - game_settings = [ - ('Score to Win', { - 'min_value': 1, - 'default': 3 - }), - ('Flag Touch Return Time', { - 'min_value': 0, - 'default': 0, - 'increment': 1 - }), - ('Flag Idle Return Time', { - 'min_value': 5, - 'default': 30, - 'increment': 5 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), + available_settings = [ + ba.IntSetting('Score to Win', min_value=1, default=3), + ba.IntSetting( + 'Flag Touch Return Time', + min_value=0, + default=0, + increment=1, + ), + ba.IntSetting( + 'Flag Idle Return Time', + min_value=5, + default=30, + increment=5, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), ] @classmethod diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index dd6cb3dd..95fc6527 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -62,34 +62,41 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): name = 'Chosen One' description = ('Be the chosen one for a length of time to win.\n' 'Kill the chosen one to become it.') - game_settings = [ - ('Chosen One Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Chosen One Gets Gloves', { - 'default': True - }), - ('Chosen One Gets Shield', { - 'default': False - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), + available_settings = [ + ba.IntSetting( + 'Chosen One Time', + min_value=10, + default=30, + increment=10, + ), + ba.BoolSetting('Chosen One Gets Gloves', default=True), + ba.BoolSetting('Chosen One Gets Shield', default=False), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), ] - score_info = ba.ScoreInfo(label='Time Held') + scoreconfig = ba.ScoreConfig(label='Time Held') @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 3a40e783..7849910b 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -95,21 +95,31 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): name = 'Conquest' description = 'Secure all flags on the map to win.' - game_settings = [ - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), + available_settings = [ + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), ] @classmethod diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 2ce26015..0b29ef1f 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -57,29 +57,39 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): announce_player_deaths = True @classmethod - def get_game_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - settings: List[Tuple[str, Dict[str, Any]]] = [ - ('Kills to Win Per Player', { - 'min_value': 1, - 'default': 5, - 'increment': 1 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting( + 'Kills to Win Per Player', + min_value=1, + default=5, + increment=1, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), ] # In teams mode, a suicide gives a point to the other team, but in @@ -88,7 +98,8 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): # be able to go negative. (to avoid a strategy of just # suiciding until you get a good drop) if issubclass(sessiontype, ba.FreeForAllSession): - settings.append(('Allow Negative Scores', {'default': False})) + settings.append( + ba.BoolSetting('Allow Negative Scores', default=False)) return settings @@ -150,7 +161,7 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): killer = msg.getkillerplayer(Player) if killer is None: - return + return None # Handle team-kills. if killer.team is player.team: @@ -191,7 +202,8 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): ba.timer(0.5, self.end_game) else: - super().handlemessage(msg) + return super().handlemessage(msg) + return None def _update_scoreboard(self) -> None: for team in self.teams: diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 9d1b98cb..bc37fcca 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -62,8 +62,8 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): name = 'Easter Egg Hunt' description = 'Gather eggs!' - game_settings = [('Pro Mode', {'default': False})] - score_info = ba.ScoreInfo(label='Score', scoretype=ba.ScoreType.POINTS) + available_settings = [ba.BoolSetting('Pro Mode', default=False)] + scoreconfig = ba.ScoreConfig(label='Score', scoretype=ba.ScoreType.POINTS) # We're currently hard-coded for one map. @classmethod diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index b6bbae25..3ab82c96 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -191,41 +191,52 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): name = 'Elimination' description = 'Last remaining alive wins.' - score_info = ba.ScoreInfo(label='Survived', - scoretype=ba.ScoreType.SECONDS, - none_is_winner=True) + scoreconfig = ba.ScoreConfig(label='Survived', + scoretype=ba.ScoreType.SECONDS, + none_is_winner=True) # Show messages when players die since it's meaningful here. announce_player_deaths = True @classmethod - def get_game_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - settings: List[Tuple[str, Dict[str, Any]]] = [ - ('Lives Per Player', { - 'default': 1, - 'min_value': 1, - 'max_value': 10, - 'increment': 1 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), - ('Epic Mode', { - 'default': False - }), + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting( + 'Lives Per Player', + default=1, + min_value=1, + max_value=10, + increment=1, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), + ba.BoolSetting('Epic Mode', default=False), ] if issubclass(sessiontype, ba.DualTeamSession): - settings.append(('Solo Mode', {'default': False})) - settings.append(('Balance Total Lives', {'default': False})) + settings.append(ba.BoolSetting('Solo Mode', default=False)) + settings.append( + ba.BoolSetting('Balance Total Lives', default=False)) return settings @classmethod diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 3d8abc67..530ea8ef 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -94,23 +94,36 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): name = 'Football' description = 'Get the flag to the enemy end zone.' - game_settings = [ - ('Score to Win', { - 'min_value': 7, - 'default': 21, - 'increment': 7 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=7, + default=21, + increment=7, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), ] default_music = ba.MusicType.FOOTBALL @@ -333,10 +346,11 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): name = 'Football' tips = ['Use the pick-up button to grab the flag < ${PICKUP} >'] - score_info = ba.ScoreInfo(scoretype=ba.ScoreType.MILLISECONDS, version='B') + scoreconfig = ba.ScoreConfig(scoretype=ba.ScoreType.MILLISECONDS, + version='B') default_music = ba.MusicType.FOOTBALL - # FIXME: Need to update co-op games to use get_score_info. + # FIXME: Need to update co-op games to use getscoreconfig. def get_score_type(self) -> str: return 'time' diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 57a17ec0..30a64f2b 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -125,23 +125,36 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): name = 'Hockey' description = 'Score some goals.' - game_settings = [ - ('Score to Win', { - 'min_value': 1, - 'default': 1, - 'increment': 1 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), + available_settings = [ + ba.IntSetting( + 'Score to Win', + min_value=1, + default=1, + increment=1, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), ] default_music = ba.MusicType.HOCKEY diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 9ae4600a..79007e6d 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -64,25 +64,38 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): name = 'Keep Away' description = 'Carry the flag for a set length of time.' - game_settings = [ - ('Hold Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), + available_settings = [ + ba.IntSetting( + 'Hold Time', + min_value=10, + default=30, + increment=10, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), ] - score_info = ba.ScoreInfo(label='Time Held') + scoreconfig = ba.ScoreConfig(label='Time Held') default_music = ba.MusicType.KEEP_AWAY @classmethod diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 8d98b26e..5e44602e 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -68,25 +68,38 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): name = 'King of the Hill' description = 'Secure the flag for a set length of time.' - game_settings = [ - ('Hold Time', { - 'min_value': 10, - 'default': 30, - 'increment': 10 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Respawn Times', { - 'choices': [('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0)], - 'default': 1.0 - }), + available_settings = [ + ba.IntSetting( + 'Hold Time', + min_value=10, + default=30, + increment=10, + ), + ba.IntChoiceSetting( + 'Time Limit', + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + default=0, + ), + ba.FloatChoiceSetting( + 'Respawn Times', + choices=[ + ('Shorter', 0.25), + ('Short', 0.5), + ('Normal', 1.0), + ('Long', 2.0), + ('Longer', 4.0), + ], + default=1.0, + ), ] - score_info = ba.ScoreInfo(label='Time Held') + scoreconfig = ba.ScoreConfig(label='Time Held') @classmethod def supports_session_type(cls, sessiontype: Type[ba.Session]) -> bool: diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 7512a186..5f7df16f 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -54,10 +54,10 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): name = 'Meteor Shower' description = 'Dodge the falling bombs.' - game_settings = [('Epic Mode', {'default': False})] - score_info = ba.ScoreInfo(label='Survived', - scoretype=ba.ScoreType.MILLISECONDS, - version='B') + available_settings = [ba.BoolSetting('Epic Mode', default=False)] + scoreconfig = ba.ScoreConfig(label='Survived', + scoretype=ba.ScoreType.MILLISECONDS, + version='B') # Print messages when players die (since its meaningful in this game). announce_player_deaths = True diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index c2187f80..54e0a20d 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -53,9 +53,9 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): name = 'Ninja Fight' description = 'How fast can you defeat the ninjas?' - score_info = ba.ScoreInfo(label='Time', - scoretype=ba.ScoreType.MILLISECONDS, - lower_is_better=True) + scoreconfig = ba.ScoreConfig(label='Time', + scoretype=ba.ScoreType.MILLISECONDS, + lower_is_better=True) @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index be5d0ec5..9b050b96 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -95,45 +95,55 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): name = 'Race' description = 'Run real fast!' - score_info = ba.ScoreInfo(label='Time', - lower_is_better=True, - scoretype=ba.ScoreType.MILLISECONDS) + scoreconfig = ba.ScoreConfig(label='Time', + lower_is_better=True, + scoretype=ba.ScoreType.MILLISECONDS) @classmethod - def get_game_settings( - cls, - sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]: - settings: List[Tuple[str, Dict[str, Any]]] = [ - ('Laps', { - 'min_value': 1, - 'default': 3, - 'increment': 1 - }), - ('Time Limit', { - 'choices': [('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200)], - 'default': 0 - }), - ('Mine Spawning', { - 'choices': [('No Mines', 0), ('8 Seconds', 8000), - ('4 Seconds', 4000), ('2 Seconds', 2000)], - 'default': 4000 - }), - ('Bomb Spawning', { - 'choices': [('None', 0), ('8 Seconds', 8000), - ('4 Seconds', 4000), ('2 Seconds', 2000), - ('1 Second', 1000)], - 'default': 2000 - }), - ('Epic Mode', { - 'default': False - }), + def get_available_settings( + cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: + settings = [ + ba.IntSetting('Laps', min_value=1, default=3, increment=1), + ba.IntChoiceSetting( + 'Time Limit', + default=0, + choices=[ + ('None', 0), + ('1 Minute', 60), + ('2 Minutes', 120), + ('5 Minutes', 300), + ('10 Minutes', 600), + ('20 Minutes', 1200), + ], + ), + ba.IntChoiceSetting( + 'Mine Spawning', + default=4000, + choices=[ + ('No Mines', 0), + ('8 Seconds', 8000), + ('4 Seconds', 4000), + ('2 Seconds', 2000), + ], + ), + ba.IntChoiceSetting( + 'Bomb Spawning', + choices=[ + ('None', 0), + ('8 Seconds', 8000), + ('4 Seconds', 4000), + ('2 Seconds', 2000), + ('1 Second', 1000), + ], + default=2000, + ), + ba.BoolSetting('Epic Mode', default=False), ] # We have some specific settings in teams mode. if issubclass(sessiontype, ba.DualTeamSession): - settings.append(('Entire Team Must Finish', {'default': False})) + settings.append( + ba.BoolSetting('Entire Team Must Finish', default=False)) return settings @classmethod diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 632ddc46..c646a6af 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -59,17 +59,10 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): name = 'Target Practice' description = 'Bomb as many targets as you can.' - game_settings = [ - ('Target Count', { - 'min_value': 1, - 'default': 3 - }), - ('Enable Impact Bombs', { - 'default': True - }), - ('Enable Triple Bombs', { - 'default': True - }), + available_settings = [ + ba.IntSetting('Target Count', min_value=1, default=3), + ba.BoolSetting('Enable Impact Bombs', default=True), + ba.BoolSetting('Enable Triple Bombs', default=True) ] default_music = ba.MusicType.FORWARD_MARCH diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index cb0b84bb..6486be14 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -72,7 +72,7 @@ class PlaylistEditGameWindow(ba.Window): ba.screenmessage(ba.Lstr(resource='noValidMapsErrorText')) raise Exception('No valid maps') - self._settings_defs = gameclass.get_game_settings(sessiontype) + self._settings_defs = gameclass.get_available_settings(sessiontype) self._completion_call = completion_call # To start with, pick a random map out of the ones we own. @@ -239,30 +239,31 @@ class PlaylistEditGameWindow(ba.Window): v_align='center') v -= map_height - for setting_name, setting in self._settings_defs: - value = setting['default'] + for setting in self._settings_defs: + value = setting.default value_type = type(value) # Now, if there's an existing value for it in the config, # override with that. try: if (config is not None and 'settings' in config - and setting_name in config['settings']): - value = value_type(config['settings'][setting_name]) + and setting.name in config['settings']): + value = value_type(config['settings'][setting.name]) except Exception: ba.print_exception() # Shove the starting value in there to start. - self._settings[setting_name] = value + self._settings[setting.name] = value - name_translated = self._get_localized_setting_name(setting_name) + name_translated = self._get_localized_setting_name(setting.name) mw1 = 280 mw2 = 70 # Handle types with choices specially: - if 'choices' in setting: - for choice in setting['choices']: + if isinstance(setting, ba.ChoiceSetting): + # if 'choices' in setting: + for choice in setting.choices: if len(choice) != 2: raise ValueError( "Expected 2-member tuples for 'choices'; got: " + @@ -281,10 +282,10 @@ class PlaylistEditGameWindow(ba.Window): 'got: ' + repr(setting)) # Start at the choice corresponding to the default if possible. - self._choice_selections[setting_name] = 0 - for index, choice in enumerate(setting['choices']): + self._choice_selections[setting.name] = 0 + for index, choice in enumerate(setting.choices): if choice[1] == value: - self._choice_selections[setting_name] = index + self._choice_selections[setting.name] = index break v -= spacing @@ -300,8 +301,8 @@ class PlaylistEditGameWindow(ba.Window): parent=self._subcontainer, position=(h + 509 - 95, v), size=(0, 28), - text=self._get_localized_setting_name(setting['choices'][ - self._choice_selections[setting_name]][0]), + text=self._get_localized_setting_name(setting.choices[ + self._choice_selections[setting.name]][0]), editable=False, color=(0.6, 1.0, 0.6, 1.0), maxwidth=mw2, @@ -314,7 +315,7 @@ class PlaylistEditGameWindow(ba.Window): label='<', autoselect=True, on_activate_call=ba.Call( - self._choice_inc, setting_name, txt, + self._choice_inc, setting.name, txt, setting, -1), repeat=True) btn2 = ba.buttonwidget(parent=self._subcontainer, @@ -323,25 +324,16 @@ class PlaylistEditGameWindow(ba.Window): label='>', autoselect=True, on_activate_call=ba.Call( - self._choice_inc, setting_name, txt, + self._choice_inc, setting.name, txt, setting, 1), repeat=True) widget_column.append([btn1, btn2]) - elif value_type in [int, float]: + elif isinstance(setting, (ba.IntSetting, ba.FloatSetting)): v -= spacing - try: - min_value = setting['min_value'] - except Exception: - min_value = 0 - try: - max_value = setting['max_value'] - except Exception: - max_value = 9999 - try: - increment = setting['increment'] - except Exception: - increment = 1 + min_value = setting.min_value + max_value = setting.max_value + increment = setting.increment ba.textwidget(parent=self._subcontainer, position=(h + 50, v), size=(100, 30), @@ -368,7 +360,7 @@ class PlaylistEditGameWindow(ba.Window): on_activate_call=ba.Call( self._inc, txt, min_value, max_value, -increment, value_type, - setting_name), + setting.name), repeat=True) btn2 = ba.buttonwidget(parent=self._subcontainer, position=(h + 509 + 5, v), @@ -378,7 +370,7 @@ class PlaylistEditGameWindow(ba.Window): on_activate_call=ba.Call( self._inc, txt, min_value, max_value, increment, value_type, - setting_name), + setting.name), repeat=True) widget_column.append([btn1, btn2]) @@ -413,7 +405,7 @@ class PlaylistEditGameWindow(ba.Window): value=value, on_value_change_call=ba.Call( self._check_value_change, - setting_name, txt)) + setting.name, txt)) widget_column.append([cbw]) else: @@ -463,8 +455,8 @@ class PlaylistEditGameWindow(ba.Window): self._completion_call).get_root_widget() def _choice_inc(self, setting_name: str, widget: ba.Widget, - setting: Dict[str, Any], increment: int) -> None: - choices = setting['choices'] + setting: ba.ChoiceSetting, increment: int) -> None: + choices = setting.choices if increment > 0: self._choice_selections[setting_name] = min( len(choices) - 1, self._choice_selections[setting_name] + 1) diff --git a/docs/ba_module.md b/docs/ba_module.md index 12344a28..1ecb47b6 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-02 for Ballistica version 1.5.0 build 20041

    +

    last updated on 2020-06-02 for Ballistica version 1.5.0 build 20042

    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!


    @@ -31,7 +31,7 @@
  • ba.PlayerInfo
  • ba.PlayerRecord
  • -
  • ba.ScoreInfo
  • +
  • ba.ScoreConfig
  • ba.Session
  • ba.SessionPlayer
  • ba.SessionTeam
  • +
  • ba.Setting
  • ba.StandLocation
  • ba.Stats
  • ba.Team
  • @@ -220,6 +221,17 @@ +

    Settings Classes

    +

    ba.Achievement

    <top level class> @@ -1087,7 +1099,7 @@ manually.

    Methods:

    create_default_game_settings_ui()

    -

    create_default_game_settings_ui(self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None

    +

    create_default_game_settings_ui(self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None

    Launch a UI to configure the given game config.

    @@ -1161,6 +1173,21 @@ when done.

    Behavior is similar to ba.gettexture()

    +
    +
    +
    +

    ba.BoolSetting

    +

    Inherits from: ba.Setting

    +

    A boolean game setting.

    + +

    Category: Settings Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.BoolSetting(name: str, default: bool)

    +

    @@ -1291,6 +1318,21 @@ mycall()

    <constructor>

    ba.CelebrateMessage(duration: float = 10.0)

    +
    +
    +
    +

    ba.ChoiceSetting

    +

    Inherits from: ba.Setting

    +

    A setting with multiple choices.

    + +

    Category: Settings Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.ChoiceSetting(name: str, default: Any, choices: List[Tuple[str, Any]])

    +

    @@ -1617,7 +1659,7 @@ start_long_action(callback_when_done=ba.ContextC

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), end(), end_game(), expire(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), end(), end_game(), expire(), get_available_settings(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), getscoreconfig(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_in(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, celebrate(), fade_to_red(), get_score_type(), on_begin(), setup_low_life_warning_sound(), spawn_player_spaz(), supports_session_type()
    @@ -2188,6 +2230,36 @@ its time with lingering corpses, sound effects, etc.

    Whether this object exists.

    +
    +
    +
    +

    ba.FloatChoiceSetting

    +

    Inherits from: ba.ChoiceSetting, ba.Setting

    +

    A float setting with multiple choices.

    + +

    Category: Settings Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.FloatChoiceSetting(name: str, default: float, choices: List[Tuple[str, float]])

    + +
    +
    +
    +

    ba.FloatSetting

    +

    Inherits from: ba.Setting

    +

    A floating point game setting.

    + +

    Category: Settings Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.FloatSetting(name: str, default: float, min_value: float = 0.0, max_value: float = 9999.0, increment: float = 1.0)

    +

    @@ -2317,7 +2389,7 @@ its time with lingering corpses, sound effects, etc.

    Methods Inherited:

    add_actor_weak_ref(), add_player(), add_team(), begin(), create_player(), create_team(), dep_is_present(), expire(), get_dynamic_deps(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), on_expire(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), retain_actor(), set_has_ended(), transition_in(), transition_out()

    Methods Defined or Overridden:

    -
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_description(), get_description_display_string(), get_display_string(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()
    +
    <constructor>, continue_or_end_game(), create_settings_ui(), end(), end_game(), get_available_settings(), get_description(), get_description_display_string(), get_display_string(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), getscoreconfig(), handlemessage(), is_waiting_for_continue(), on_begin(), on_continue(), on_player_join(), on_transition_in(), respawn_player(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), spawn_player_spaz(), supports_session_type()

    <constructor>

    ba.GameActivity(settings: dict)

    @@ -2334,7 +2406,7 @@ and calls either end_game or continue_game depending on the result

    create_settings_ui()

    <class method>
    -

    create_settings_ui(sessionclass: Type[ba.Session], settings: Optional[Dict[str, Any]], completion_call: Callable[[Optional[Dict[str, Any]]], None]) -> None

    +

    create_settings_ui(sessionclass: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None

    Launch an in-game UI to configure settings for a game type.

    @@ -2343,11 +2415,11 @@ and calls either end_game or continue_game depending on the result

    'config' should be an existing config dict (specifies 'edit' ui mode) or None (specifies 'add' ui mode).

    -

    'completion_call' will be called with a filled-out config dict on +

    'completion_call' will be called with a filled-out settings dict on success or None on cancel.

    Generally subclasses don't need to override this; if they override -ba.GameActivity.get_game_settings() and +ba.GameActivity.get_available_settings() and ba.GameActivity.get_supported_maps() they can just rely on the default implementation here which calls those methods.

    @@ -2374,38 +2446,9 @@ there is no 'winner' yet; this way things like the standard time-limit (ba.GameActivity.setup_standard_time_limit()) will work with the game.

    -

    get_description()

    +

    get_available_settings()

    <class method>
    -

    get_description(sessiontype: Type[ba.Session]) -> str

    - -

    Get a str description of this game type.

    - -

    The default implementation simply returns the 'description' class var. -Classes which want to change their description depending on the session -can override this method.

    - -
    -

    get_description_display_string()

    -
    <class method>
    -

    get_description_display_string(sessiontype: Type[ba.Session]) -> ba.Lstr

    - -

    Return a translated version of get_description().

    - -

    Sub-classes should override get_description(); not this.

    - -
    -

    get_display_string()

    -
    <class method>
    -

    get_display_string(settings: Optional[Dict] = None) -> ba.Lstr

    - -

    Return a descriptive name for this game/settings combo.

    - -

    Subclasses should override getname(); not this.

    - -
    -

    get_game_settings()

    -
    <class method>
    -

    get_game_settings(sessiontype: Type[ba.Session]) -> List[Tuple[str, Dict[str, Any]]]

    +

    get_available_settings(sessiontype: Type[ba.Session]) -> List[ba.Setting]

    Called by the default ba.GameActivity.create_settings_ui() implementation; should return a dict of config options to be presented @@ -2427,9 +2470,9 @@ of a name and a dict of options.

    'increment': Value increment for int/float settings.

    -
    # example get_game_settings() for a capture-the-flag game:
    +
    # example get_available_settings() for a capture-the-flag game:
     @classmethod
    -def get_game_settings(cls, sessiontype):
    +def get_available_settings(cls, sessiontype):
         return [("Score to Win", {
                     'default': 3,
                     'min_value': 1
    @@ -2463,6 +2506,35 @@ def get_game_settings(cls, sessiontype):
                     'default': False
                 })]
    +
    +

    get_description()

    +
    <class method>
    +

    get_description(sessiontype: Type[ba.Session]) -> str

    + +

    Get a str description of this game type.

    + +

    The default implementation simply returns the 'description' class var. +Classes which want to change their description depending on the session +can override this method.

    + +
    +

    get_description_display_string()

    +
    <class method>
    +

    get_description_display_string(sessiontype: Type[ba.Session]) -> ba.Lstr

    + +

    Return a translated version of get_description().

    + +

    Sub-classes should override get_description(); not this.

    + +
    +

    get_display_string()

    +
    <class method>
    +

    get_display_string(settings: Optional[Dict] = None) -> ba.Lstr

    + +

    Return a descriptive name for this game/settings combo.

    + +

    Subclasses should override getname(); not this.

    +

    get_instance_description()

    get_instance_description(self) -> Union[str, Sequence]

    @@ -2532,13 +2604,6 @@ with the first value, ${ARG2} with the second, etc.

    This name is used above the game scoreboard in the corner of the screen, so it should be as concise as possible.

    -
    -

    get_score_info()

    -
    <class method>
    -

    get_score_info() -> ba.ScoreInfo

    - -

    Return info about game scoring setup; can be overridden by games.

    -

    get_settings_display_string()

    <class method>
    @@ -2574,6 +2639,13 @@ for this game-type for the given ba.Session type

    This default implementation simply returns the 'name' class attr.

    +
    +

    getscoreconfig()

    +
    <class method>
    +

    getscoreconfig() -> ba.ScoreConfig

    + +

    Return info about game scoring setup; can be overridden by games.

    +

    handlemessage()

    handlemessage(self, msg: Any) -> Any

    @@ -2842,6 +2914,36 @@ prefs, etc.

    Methods:

    <all methods inherited from ba.NotFoundError>


    +

    ba.IntChoiceSetting

    +

    Inherits from: ba.ChoiceSetting, ba.Setting

    +

    An int setting with multiple choices.

    + +

    Category: Settings Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.IntChoiceSetting(name: str, default: int, choices: List[Tuple[str, int]])

    + +
    +
    +
    +

    ba.IntSetting

    +

    Inherits from: ba.Setting

    +

    An integer game setting.

    + +

    Category: Settings Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.IntSetting(name: str, default: int, min_value: int = 0, max_value: int = 9999, increment: int = 1)

    + +
    +
    +

    ba.Level

    <top level class>

    @@ -4345,38 +4447,38 @@ cause the powerup box to make a sound and disappear or whatnot.


    -

    ba.ScoreInfo

    +

    ba.ScoreConfig

    <top level class>

    -

    Info about a game's scoring setup.

    +

    Settings for how a game handles scores.

    Category: Gameplay Classes

    Attributes:

    -
    label, lower_is_better, none_is_winner, scoretype, version
    +
    label, lower_is_better, none_is_winner, scoretype, version
    -

    label

    +

    label

    str

    A label show to the user for scores; 'Score', 'Time Survived', etc.

    -

    lower_is_better

    +

    lower_is_better

    bool

    Whether lower scores are preferable. Higher scores are by default.

    -

    none_is_winner

    +

    none_is_winner

    bool

    Whether a value of None is considered better than other scores. By default it is not.

    -

    scoretype

    +

    scoretype

    ba.ScoreType

    How the score value should be displayed.

    -

    version

    +

    version

    str

    To change high-score lists used by a game without renaming the game, change this. Defaults to an empty string.

    @@ -4385,8 +4487,8 @@ change this. Defaults to an empty string.

    Methods:

    -

    <constructor>

    -

    ba.ScoreInfo(label: 'str' = 'Score', scoretype: 'ba.ScoreType' = <ScoreType.POINTS: 'p'>, lower_is_better: 'bool' = False, none_is_winner: 'bool' = False, version: 'str' = '')

    +

    <constructor>

    +

    ba.ScoreConfig(label: 'str' = 'Score', scoretype: 'ba.ScoreType' = <ScoreType.POINTS: 'p'>, lower_is_better: 'bool' = False, none_is_winner: 'bool' = False, version: 'str' = '')

    @@ -4867,6 +4969,22 @@ of the session.

    Methods:

    <all methods inherited from ba.NotFoundError>


    +

    ba.Setting

    +

    <top level class> +

    +

    Defines a user-controllable setting for a game or other entity.

    + +

    Category: Gameplay Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.Setting(name: str, default: Any)

    + +
    +
    +

    ba.ShouldShatterMessage

    <top level class>

    @@ -5230,7 +5348,7 @@ of the session.

    Methods Inherited:

    -
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), end_game(), expire(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_game_settings(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_score_info(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()
    +
    add_actor_weak_ref(), add_player(), add_team(), begin(), continue_or_end_game(), create_player(), create_settings_ui(), create_team(), dep_is_present(), end_game(), expire(), get_available_settings(), get_description(), get_description_display_string(), get_display_string(), get_dynamic_deps(), get_instance_description(), get_instance_description_short(), get_instance_display_string(), get_instance_scoreboard_display_string(), get_settings_display_string(), get_supported_maps(), get_team_display_string(), getname(), getscoreconfig(), handlemessage(), has_begun(), has_ended(), has_transitioned_in(), is_transitioning_out(), is_waiting_for_continue(), on_continue(), on_expire(), on_player_join(), on_player_leave(), on_team_join(), on_team_leave(), on_transition_out(), remove_player(), remove_team(), respawn_player(), retain_actor(), set_has_ended(), setup_standard_powerup_drops(), setup_standard_time_limit(), show_zoom_message(), spawn_player(), spawn_player_if_exists(), transition_in(), transition_out()

    Methods Defined or Overridden:

    <constructor>, end(), on_begin(), on_transition_in(), spawn_player_spaz(), supports_session_type()
    From ed102842c58efad83bdd16905e42fd1eb90e4acc Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 20:11:10 -0700 Subject: [PATCH 072/417] Modernized runaround code --- .idea/dictionaries/ericf.xml | 1 + .../ba_data/python/bastd/game/runaround.py | 529 +++++++++--------- 2 files changed, 270 insertions(+), 260 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index da52b07d..563dcadb 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1752,6 +1752,7 @@ spazappearance spazbot spazfactory + spaztype spazzes spcall spcstr diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index cf27e920..acccd945 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -26,6 +26,8 @@ from __future__ import annotations import random +from dataclasses import dataclass +from enum import Enum from typing import TYPE_CHECKING import ba @@ -42,7 +44,46 @@ from bastd.actor.spazbot import ( BomberBotPro, BrawlerBotPro) if TYPE_CHECKING: - from typing import Type, Any, List, Dict, Tuple, Sequence, Optional + from typing import Type, Any, List, Dict, Tuple, Sequence, Optional, Union + + +class Preset(Enum): + """Play presets.""" + ENDLESS = 'endless' + ENDLESS_TOURNAMENT = 'endless_tournament' + PRO = 'pro' + PRO_EASY = 'pro_easy' + UBER = 'uber' + UBER_EASY = 'uber_easy' + TOURNAMENT = 'tournament' + TOURNAMENT_UBER = 'tournament_uber' + + +class Point(Enum): + """Where we can spawn stuff and the corresponding map attr name.""" + BOTTOM_LEFT = 'bot_spawn_bottom_left' + BOTTOM_RIGHT = 'bot_spawn_bottom_right' + START = 'bot_spawn_start' + + +@dataclass +class Spawn: + """Defines a bot spawn.""" + type: Type[SpazBot] + path: int = 0 + point: Optional[Point] = None + + +@dataclass +class Spacing: + """Defines spacing between spawns.""" + duration: float + + +@dataclass +class Wave: + """Defines a wave of enemies.""" + entries: List[Union[Spawn, Spacing, None]] class Player(ba.Player['Team']): @@ -90,7 +131,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): settings['map'] = 'Tower D' super().__init__(settings) shared = SharedObjects.get() - self._preset = str(settings.get('preset', 'pro')) + self._preset = Preset(settings.get('preset', 'pro')) self._player_death_sound = ba.getsound('playerDeath') self._new_wave_sound = ba.getsound('scoreHit01') @@ -112,9 +153,11 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._score_region_material = ba.Material() self._score_region_material.add_actions( conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'collide', - True), ('modify_part_collision', 'physical', False), - ('call', 'at_connect', self._handle_reached_end))) + actions=( + ('modify_part_collision', 'collide', True), + ('modify_part_collision', 'physical', False), + ('call', 'at_connect', self._handle_reached_end), + )) self._last_wave_end_time = ba.time() self._player_has_picked_up_powerup = False @@ -129,7 +172,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._dingsoundhigh = ba.getsound('dingSmallHigh') self._exclude_powerups: Optional[List[str]] = None self._have_tnt: Optional[bool] = None - self._waves: Optional[List[Dict[str, Any]]] = None + self._waves: Optional[List[Wave]] = None self._bots = SpazBotSet() self._tntspawner: Optional[TNTSpawner] = None self._lives_bg: Optional[ba.NodeActor] = None @@ -161,206 +204,186 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): def on_begin(self) -> None: super().on_begin() player_count = len(self.players) - hard = self._preset not in ['pro_easy', 'uber_easy'] + hard = self._preset not in {Preset.PRO_EASY, Preset.UBER_EASY} - if self._preset in ['pro', 'pro_easy', 'tournament']: + if self._preset in {Preset.PRO, Preset.PRO_EASY, Preset.TOURNAMENT}: self._exclude_powerups = ['curse'] self._have_tnt = True self._waves = [ - {'entries': [ - {'type': BomberBot, 'path': 3 if hard else 2}, - {'type': BomberBot, 'path': 2}, - {'type': BomberBot, 'path': 2} if hard else None, - {'type': BomberBot, 'path': 2} if player_count > 1 - else None, - {'type': BomberBot, 'path': 1} if hard else None, - {'type': BomberBot, 'path': 1} if player_count > 2 - else None, - {'type': BomberBot, 'path': 1} if player_count > 3 - else None, - ]}, - {'entries': [ - {'type': BomberBot, 'path': 1} if hard else None, - {'type': BomberBot, 'path': 2} if hard else None, - {'type': BomberBot, 'path': 2}, - {'type': BomberBot, 'path': 2}, - {'type': BomberBot, 'path': 2} if player_count > 3 - else None, - {'type': BrawlerBot, 'path': 3}, - {'type': BrawlerBot, 'path': 3}, - {'type': BrawlerBot, 'path': 3} if hard else None, - {'type': BrawlerBot, 'path': 3} if player_count > 1 - else None, - {'type': BrawlerBot, 'path': 3} if player_count > 2 - else None, - ]}, - {'entries': [ - {'type': ChargerBot, 'path': 2} if hard else None, - {'type': ChargerBot, 'path': 2} if player_count > 2 - else None, - {'type': TriggerBot, 'path': 2}, - {'type': TriggerBot, 'path': 2} if player_count > 1 - else None, - {'type': 'spacing', 'duration': 3.0}, - {'type': BomberBot, 'path': 2} if hard else None, - {'type': BomberBot, 'path': 2} if hard else None, - {'type': BomberBot, 'path': 2}, - {'type': BomberBot, 'path': 3} if hard else None, - {'type': BomberBot, 'path': 3}, - {'type': BomberBot, 'path': 3}, - {'type': BomberBot, 'path': 3} if player_count > 3 - else None, - ]}, - {'entries': [ - {'type': TriggerBot, 'path': 1} if hard else None, - {'type': 'spacing', 'duration': 1.0} if hard else None, - {'type': TriggerBot, 'path': 2}, - {'type': 'spacing', 'duration': 1.0}, - {'type': TriggerBot, 'path': 3}, - {'type': 'spacing', 'duration': 1.0}, - {'type': TriggerBot, 'path': 1} if hard else None, - {'type': 'spacing', 'duration': 1.0} if hard else None, - {'type': TriggerBot, 'path': 2}, - {'type': 'spacing', 'duration': 1.0}, - {'type': TriggerBot, 'path': 3}, - {'type': 'spacing', 'duration': 1.0}, - {'type': TriggerBot, 'path': 1} - if (player_count > 1 and hard) else None, - {'type': 'spacing', 'duration': 1.0}, - {'type': TriggerBot, 'path': 2} if player_count > 2 - else None, - {'type': 'spacing', 'duration': 1.0}, - {'type': TriggerBot, 'path': 3} if player_count > 3 - else None, - {'type': 'spacing', 'duration': 1.0}, - ]}, - {'entries': [ - {'type': ChargerBotProShielded if hard - else ChargerBot, 'path': 1}, - {'type': BrawlerBot, 'path': 2} if hard else None, - {'type': BrawlerBot, 'path': 2}, - {'type': BrawlerBot, 'path': 2}, - {'type': BrawlerBot, 'path': 3} if hard else None, - {'type': BrawlerBot, 'path': 3}, - {'type': BrawlerBot, 'path': 3}, - {'type': BrawlerBot, 'path': 3} if player_count > 1 - else None, - {'type': BrawlerBot, 'path': 3} if player_count > 2 - else None, - {'type': BrawlerBot, 'path': 3} if player_count > 3 - else None, - ]}, - {'entries': [ - {'type': BomberBotProShielded, 'path': 3}, - {'type': 'spacing', 'duration': 1.5}, - {'type': BomberBotProShielded, 'path': 2}, - {'type': 'spacing', 'duration': 1.5}, - {'type': BomberBotProShielded, 'path': 1} if hard - else None, - {'type': 'spacing', 'duration': 1.0} if hard else None, - {'type': BomberBotProShielded, 'path': 3}, - {'type': 'spacing', 'duration': 1.5}, - {'type': BomberBotProShielded, 'path': 2}, - {'type': 'spacing', 'duration': 1.5}, - {'type': BomberBotProShielded, 'path': 1} if hard - else None, - {'type': 'spacing', 'duration': 1.5} if hard else None, - {'type': BomberBotProShielded, 'path': 3} - if player_count > 1 else None, - {'type': 'spacing', 'duration': 1.5}, - {'type': BomberBotProShielded, 'path': 2} - if player_count > 2 else None, - {'type': 'spacing', 'duration': 1.5}, - {'type': BomberBotProShielded, 'path': 1} - if player_count > 3 else None, - ]}, - ] # yapf: disable - elif self._preset in ['uber_easy', 'uber', 'tournament_uber']: + Wave(entries=[ + Spawn(BomberBot, path=3 if hard else 2), + Spawn(BomberBot, path=2), + Spawn(BomberBot, path=2) if hard else None, + Spawn(BomberBot, path=2) if player_count > 1 else None, + Spawn(BomberBot, path=1) if hard else None, + Spawn(BomberBot, path=1) if player_count > 2 else None, + Spawn(BomberBot, path=1) if player_count > 3 else None, + ]), + Wave(entries=[ + Spawn(BomberBot, path=1) if hard else None, + Spawn(BomberBot, path=2) if hard else None, + Spawn(BomberBot, path=2), + Spawn(BomberBot, path=2), + Spawn(BomberBot, path=2) if player_count > 3 else None, + Spawn(BrawlerBot, path=3), + Spawn(BrawlerBot, path=3), + Spawn(BrawlerBot, path=3) if hard else None, + Spawn(BrawlerBot, path=3) if player_count > 1 else None, + Spawn(BrawlerBot, path=3) if player_count > 2 else None, + ]), + Wave(entries=[ + Spawn(ChargerBot, path=2) if hard else None, + Spawn(ChargerBot, path=2) if player_count > 2 else None, + Spawn(TriggerBot, path=2), + Spawn(TriggerBot, path=2) if player_count > 1 else None, + Spacing(duration=3.0), + Spawn(BomberBot, path=2) if hard else None, + Spawn(BomberBot, path=2) if hard else None, + Spawn(BomberBot, path=2), + Spawn(BomberBot, path=3) if hard else None, + Spawn(BomberBot, path=3), + Spawn(BomberBot, path=3), + Spawn(BomberBot, path=3) if player_count > 3 else None, + ]), + Wave(entries=[ + Spawn(TriggerBot, path=1) if hard else None, + Spacing(duration=1.0) if hard else None, + Spawn(TriggerBot, path=2), + Spacing(duration=1.0), + Spawn(TriggerBot, path=3), + Spacing(duration=1.0), + Spawn(TriggerBot, path=1) if hard else None, + Spacing(duration=1.0) if hard else None, + Spawn(TriggerBot, path=2), + Spacing(duration=1.0), + Spawn(TriggerBot, path=3), + Spacing(duration=1.0), + Spawn(TriggerBot, path=1) if ( + player_count > 1 and hard) else None, + Spacing(duration=1.0), + Spawn(TriggerBot, path=2) if player_count > 2 else None, + Spacing(duration=1.0), + Spawn(TriggerBot, path=3) if player_count > 3 else None, + Spacing(duration=1.0), + ]), + Wave(entries=[ + Spawn(ChargerBotProShielded if hard else ChargerBot, + path=1), + Spawn(BrawlerBot, path=2) if hard else None, + Spawn(BrawlerBot, path=2), + Spawn(BrawlerBot, path=2), + Spawn(BrawlerBot, path=3) if hard else None, + Spawn(BrawlerBot, path=3), + Spawn(BrawlerBot, path=3), + Spawn(BrawlerBot, path=3) if player_count > 1 else None, + Spawn(BrawlerBot, path=3) if player_count > 2 else None, + Spawn(BrawlerBot, path=3) if player_count > 3 else None, + ]), + Wave(entries=[ + Spawn(BomberBotProShielded, path=3), + Spacing(duration=1.5), + Spawn(BomberBotProShielded, path=2), + Spacing(duration=1.5), + Spawn(BomberBotProShielded, path=1) if hard else None, + Spacing(duration=1.0) if hard else None, + Spawn(BomberBotProShielded, path=3), + Spacing(duration=1.5), + Spawn(BomberBotProShielded, path=2), + Spacing(duration=1.5), + Spawn(BomberBotProShielded, path=1) if hard else None, + Spacing(duration=1.5) if hard else None, + Spawn(BomberBotProShielded, path=3 + ) if player_count > 1 else None, + Spacing(duration=1.5), + Spawn(BomberBotProShielded, path=2 + ) if player_count > 2 else None, + Spacing(duration=1.5), + Spawn(BomberBotProShielded, path=1 + ) if player_count > 3 else None, + ]), + ] + elif self._preset in { + Preset.UBER_EASY, Preset.UBER, Preset.TOURNAMENT_UBER + }: self._exclude_powerups = [] self._have_tnt = True self._waves = [ - {'entries': [ - {'type': TriggerBot, 'path': 1} if hard else None, - {'type': TriggerBot, 'path': 2}, - {'type': TriggerBot, 'path': 2}, - {'type': TriggerBot, 'path': 3}, - {'type': BrawlerBotPro if hard - else BrawlerBot, 'point': 'bottom_left'}, - {'type': BrawlerBotPro, 'point': 'bottom_right'} - if player_count > 2 else None, - ]}, - {'entries': [ - {'type': ChargerBot, 'path': 2}, - {'type': ChargerBot, 'path': 3}, - {'type': ChargerBot, 'path': 1} if hard else None, - {'type': ChargerBot, 'path': 2}, - {'type': ChargerBot, 'path': 3}, - {'type': ChargerBot, 'path': 1} if player_count > 2 - else None, - ]}, - {'entries': [ - {'type': BomberBotProShielded, 'path': 1} if hard - else None, - {'type': BomberBotProShielded, 'path': 2}, - {'type': BomberBotProShielded, 'path': 2}, - {'type': BomberBotProShielded, 'path': 3}, - {'type': BomberBotProShielded, 'path': 3}, - {'type': ChargerBot, 'point': 'bottom_right'}, - {'type': ChargerBot, 'point': 'bottom_left'} - if player_count > 2 else None, - ]}, - {'entries': [ - {'type': TriggerBotPro, 'path': 1} - if hard else None, - {'type': TriggerBotPro, 'path': 1 if hard else 2}, - {'type': TriggerBotPro, 'path': 1 if hard else 2}, - {'type': TriggerBotPro, 'path': 1 if hard else 2}, - {'type': TriggerBotPro, 'path': 1 if hard else 2}, - {'type': TriggerBotPro, 'path': 1 if hard else 2}, - {'type': TriggerBotPro, 'path': 1 if hard else 2} - if player_count > 1 else None, - {'type': TriggerBotPro, 'path': 1 if hard else 2} - if player_count > 3 else None, - ]}, - {'entries': [ - {'type': TriggerBotProShielded if hard - else TriggerBotPro, 'point': 'bottom_left'}, - {'type': TriggerBotProShielded, - 'point': 'bottom_right'} - if hard else None, - {'type': TriggerBotProShielded, - 'point': 'bottom_right'} - if player_count > 2 else None, - {'type': BomberBot, 'path': 3}, - {'type': BomberBot, 'path': 3}, - {'type': 'spacing', 'duration': 5.0}, - {'type': BrawlerBot, 'path': 2}, - {'type': BrawlerBot, 'path': 2}, - {'type': 'spacing', 'duration': 5.0}, - {'type': TriggerBot, 'path': 1} if hard else None, - {'type': TriggerBot, 'path': 1} if hard else None, - ]}, - {'entries': [ - {'type': BomberBotProShielded, 'path': 2}, - {'type': BomberBotProShielded, 'path': 2} if hard - else None, - {'type': StickyBot, 'point': 'bottom_right'}, - {'type': BomberBotProShielded, 'path': 2}, - {'type': BomberBotProShielded, 'path': 2}, - {'type': StickyBot, 'point': 'bottom_right'} - if player_count > 2 else None, - {'type': BomberBotProShielded, 'path': 2}, - {'type': ExplodeyBot, 'point': 'bottom_left'}, - {'type': BomberBotProShielded, 'path': 2}, - {'type': BomberBotProShielded, 'path': 2} - if player_count > 1 else None, - {'type': 'spacing', 'duration': 5.0}, - {'type': StickyBot, 'point': 'bottom_left'}, - {'type': 'spacing', 'duration': 2.0}, - {'type': ExplodeyBot, 'point': 'bottom_right'}, - ]}, - ] # yapf: disable - elif self._preset in ['endless', 'endless_tournament']: + Wave(entries=[ + Spawn(TriggerBot, path=1) if hard else None, + Spawn(TriggerBot, path=2), + Spawn(TriggerBot, path=2), + Spawn(TriggerBot, path=3), + Spawn(BrawlerBotPro if hard else BrawlerBot, + point=Point.BOTTOM_LEFT), + Spawn(BrawlerBotPro, point=Point.BOTTOM_RIGHT + ) if player_count > 2 else None, + ]), + Wave(entries=[ + Spawn(ChargerBot, path=2), + Spawn(ChargerBot, path=3), + Spawn(ChargerBot, path=1) if hard else None, + Spawn(ChargerBot, path=2), + Spawn(ChargerBot, path=3), + Spawn(ChargerBot, path=1) if player_count > 2 else None, + ]), + Wave(entries=[ + Spawn(BomberBotProShielded, path=1) if hard else None, + Spawn(BomberBotProShielded, path=2), + Spawn(BomberBotProShielded, path=2), + Spawn(BomberBotProShielded, path=3), + Spawn(BomberBotProShielded, path=3), + Spawn(ChargerBot, point=Point.BOTTOM_RIGHT), + Spawn(ChargerBot, point=Point.BOTTOM_LEFT + ) if player_count > 2 else None, + ]), + Wave(entries=[ + Spawn(TriggerBotPro, path=1) if hard else None, + Spawn(TriggerBotPro, path=1 if hard else 2), + Spawn(TriggerBotPro, path=1 if hard else 2), + Spawn(TriggerBotPro, path=1 if hard else 2), + Spawn(TriggerBotPro, path=1 if hard else 2), + Spawn(TriggerBotPro, path=1 if hard else 2), + Spawn(TriggerBotPro, path=1 if hard else 2 + ) if player_count > 1 else None, + Spawn(TriggerBotPro, path=1 if hard else 2 + ) if player_count > 3 else None, + ]), + Wave(entries=[ + Spawn(TriggerBotProShielded if hard else TriggerBotPro, + point=Point.BOTTOM_LEFT), + Spawn(TriggerBotProShielded, point=Point.BOTTOM_RIGHT + ) if hard else None, + Spawn(TriggerBotProShielded, point=Point.BOTTOM_RIGHT + ) if player_count > 2 else None, + Spawn(BomberBot, path=3), + Spawn(BomberBot, path=3), + Spacing(duration=5.0), + Spawn(BrawlerBot, path=2), + Spawn(BrawlerBot, path=2), + Spacing(duration=5.0), + Spawn(TriggerBot, path=1) if hard else None, + Spawn(TriggerBot, path=1) if hard else None, + ]), + Wave(entries=[ + Spawn(BomberBotProShielded, path=2), + Spawn(BomberBotProShielded, path=2) if hard else None, + Spawn(StickyBot, point=Point.BOTTOM_RIGHT), + Spawn(BomberBotProShielded, path=2), + Spawn(BomberBotProShielded, path=2), + Spawn(StickyBot, point=Point.BOTTOM_RIGHT + ) if player_count > 2 else None, + Spawn(BomberBotProShielded, path=2), + Spawn(ExplodeyBot, point=Point.BOTTOM_LEFT), + Spawn(BomberBotProShielded, path=2), + Spawn(BomberBotProShielded, path=2 + ) if player_count > 1 else None, + Spacing(duration=5.0), + Spawn(StickyBot, point=Point.BOTTOM_LEFT), + Spacing(duration=2.0), + Spawn(ExplodeyBot, point=Point.BOTTOM_RIGHT), + ]), + ] + elif self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: self._exclude_powerups = [] self._have_tnt = True @@ -480,7 +503,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._spawn_center[1], self._spawn_center[2] + random.uniform(-1.5, 1.5)) spaz = self.spawn_player_spaz(player, position=pos) - if self._preset in ['pro_easy', 'uber_easy']: + if self._preset in {Preset.PRO_EASY, Preset.UBER_EASY}: spaz.impact_scale = 0.25 # Add the material that causes us to hit the player-wall. @@ -580,7 +603,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._time_bonus_timer = None self._time_bonus_text = None - if self._preset in ['endless', 'endless_tournament']: + if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: won = False else: assert self._waves is not None @@ -604,7 +627,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): if won: # Completion achievements: - if self._preset in ['pro', 'pro_easy']: + if self._preset in {Preset.PRO, Preset.PRO_EASY}: self._award_achievement('Pro Runaround Victory', sound=False) if self._lives == self._start_lives: @@ -612,7 +635,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): if not self._player_has_picked_up_powerup: self._award_achievement('Precision Bombing', sound=False) - elif self._preset in ['uber', 'uber_easy']: + elif self._preset in {Preset.UBER, Preset.UBER_EASY}: self._award_achievement('Uber Runaround Victory', sound=False) if self._lives == self._start_lives: @@ -717,13 +740,13 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): t_sec = 0.0 base_delay = 0.5 delay = 0.0 - bot_types: List[Optional[Dict[str, Any]]] = [] + bot_types: List[Union[Spawn, Spacing, None]] = [] - if self._preset in ['endless', 'endless_tournament']: + if self._preset in {Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT}: level = self._wavenum target_points = (level + 1) * 8.0 group_count = random.randint(1, 3) - entries = [] + entries: List[Union[Spawn, Spacing, None]] = [] spaz_types: List[Tuple[Type[SpazBot], float]] = [] if level < 6: spaz_types += [(BomberBot, 5.0)] @@ -811,13 +834,11 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): this_target_point_s *= 0.7 def _add_defender(defender_type: Tuple[Type[SpazBot], float], - pnt: str) -> Tuple[float, Dict[str, Any]]: - # FIXME: should look into this warning + pnt: Point) -> Tuple[float, Spawn]: + # This is ok because we call it immediately. # pylint: disable=cell-var-from-loop - return this_target_point_s * defender_type[1], { - 'type': defender_type[0], - 'point': pnt - } + return this_target_point_s * defender_type[1], Spawn( + defender_type[0], point=pnt) # Add defenders. defender_type1 = defender_types[random.randrange( @@ -829,10 +850,10 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): or (group == 2 and level > 5)): if random.random() < min(0.75, (level - 1) * 0.11): this_target_point_s, defender1 = _add_defender( - defender_type1, 'bottom_left') + defender_type1, Point.BOTTOM_LEFT) if random.random() < min(0.75, (level - 1) * 0.04): this_target_point_s, defender2 = _add_defender( - defender_type2, 'bottom_right') + defender_type2, Point.BOTTOM_RIGHT) spaz_type = spaz_types[random.randrange(len(spaz_types))] member_count = max( @@ -846,12 +867,9 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): this_path = random.randint(1, 3) # Random. else: this_path = path - entries.append({'type': spaz_type[0], 'path': this_path}) + entries.append(Spawn(spaz_type[0], path=this_path)) if spacing != 0.0: - entries.append({ - 'type': 'spacing', - 'duration': spacing - }) + entries.append(Spacing(duration=spacing)) if defender1 is not None: entries.append(defender1) @@ -866,15 +884,15 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): spacing = 1.0 else: spacing = 1.0 - entries.append({'type': 'spacing', 'duration': spacing}) + entries.append(Spacing(duration=spacing)) - wave = {'entries': entries} + wave = Wave(entries=entries) else: assert self._waves is not None wave = self._waves[self._wavenum - 1] - bot_types += wave['entries'] + bot_types += wave.entries self._time_bonus_mult = 1.0 this_flawless_bonus = 0 non_runner_spawn_time = 1.0 @@ -882,36 +900,27 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): for info in bot_types: if info is None: continue - bot_type = info['type'] - path = -1 - if bot_type is not None: - if bot_type == 'non_runner_delay': - non_runner_spawn_time += info['duration'] - continue - if bot_type == 'spacing': - t_sec += info['duration'] - continue - try: - path = info['path'] - except Exception: - path = random.randint(1, 3) - self._time_bonus_mult += bot_type.points_mult * 0.02 - this_flawless_bonus += bot_type.points_mult * 5 + if isinstance(info, Spacing): + t_sec += info.duration + continue + bot_type = info.type + path = info.path + self._time_bonus_mult += bot_type.points_mult * 0.02 + this_flawless_bonus += bot_type.points_mult * 5 # If its got a position, use that. - try: - point = info['point'] - except Exception: - point = 'start' + if info.point is not None: + point = info.point + else: + point = Point.START # Space our our slower bots. delay = base_delay delay /= self._get_bot_speed(bot_type) t_sec += delay * 0.5 - tcall = ba.Call(self.add_bot_at_point, point, { - 'type': bot_type, - 'path': path - }, 0.1 if point == 'start' else non_runner_spawn_time) + tcall = ba.Call( + self.add_bot_at_point, point, bot_type, path, + 0.1 if point is Point.START else non_runner_spawn_time) ba.timer(t_sec, tcall) t_sec += delay * 0.5 @@ -954,12 +963,12 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): # player could fill the whole map with them) self._last_wave_end_time = ba.time() + t_sec totalwaves = str(len(self._waves)) if self._waves is not None else '??' - txtval = ba.Lstr( - value='${A} ${B}', - subs=[('${A}', ba.Lstr(resource='waveText')), - ('${B}', str(self._wavenum) + - ('' if self._preset in ['endless', 'endless_tournament'] - else f'/{totalwaves}'))]) + txtval = ba.Lstr(value='${A} ${B}', + subs=[('${A}', ba.Lstr(resource='waveText')), + ('${B}', + str(self._wavenum) + ('' if self._preset in { + Preset.ENDLESS, Preset.ENDLESS_TOURNAMENT + } else f'/{totalwaves}'))]) self._wave_text = ba.NodeActor( ba.newnode('text', attrs={ @@ -987,20 +996,20 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): setattr(spaz, 'r_walk_speed', self._get_bot_speed(spaz_type)) def add_bot_at_point(self, - point: str, - spaz_info: Dict[str, Any], + point: Point, + spaztype: Type[SpazBot], + path: int, spawn_time: float = 0.1) -> None: """Add the given type bot with the given delay (in seconds).""" # Don't add if the game has ended. if self._game_over: return - pos = self.map.defs.points['bot_spawn_' + point][:3] - self._bots.spawn_bot(spaz_info['type'], + pos = self.map.defs.points[point.value][:3] + self._bots.spawn_bot(spaztype, pos=pos, spawn_time=spawn_time, - on_spawn_call=ba.Call(self._on_bot_spawn, - spaz_info['path'])) + on_spawn_call=ba.Call(self._on_bot_spawn, path)) def _update_time_bonus(self) -> None: self._time_bonus = int(self._time_bonus * 0.91) @@ -1022,7 +1031,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): def _update_scores(self) -> None: score = self._score - if self._preset == 'endless': + if self._preset is Preset.ENDLESS: if score >= 500: self._award_achievement('Runaround Master') if score >= 1000: @@ -1148,8 +1157,8 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): ba.playsound(self._dingsound if importance == 1 else self._dingsoundhigh, volume=0.6) - except Exception as exc: - print('EXC in Runaround on SpazBotDiedMessage:', exc) + except Exception: + ba.print_exception('Error on SpazBotDiedMessage') # Normally we pull scores from the score-set, but if there's no # player lets be explicit. From 9c81450c9278ad3f6a8ca8f3a6792fb56c1e5fa2 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 2 Jun 2020 22:35:34 -0700 Subject: [PATCH 073/417] Added proper type for assigning input --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 44 ++- assets/src/ba_data/python/ba/__init__.py | 6 +- .../src/ba_data/python/ba/_activitytypes.py | 7 +- assets/src/ba_data/python/ba/_benchmark.py | 2 +- assets/src/ba_data/python/ba/_coopsession.py | 22 +- .../src/ba_data/python/ba/_dualteamsession.py | 21 +- assets/src/ba_data/python/ba/_enums.py | 33 +++ .../ba_data/python/ba/_freeforallsession.py | 13 +- assets/src/ba_data/python/ba/_gameactivity.py | 4 +- assets/src/ba_data/python/ba/_gameresults.py | 6 +- assets/src/ba_data/python/ba/_lobby.py | 28 +- .../ba_data/python/ba/_multiteamsession.py | 10 +- assets/src/ba_data/python/ba/_player.py | 11 +- assets/src/ba_data/python/ba/_session.py | 4 +- assets/src/ba_data/python/ba/_teamgame.py | 4 +- .../bastd/activity/freeforallvictory.py | 2 +- .../python/bastd/activity/multiteamscore.py | 8 +- .../ba_data/python/bastd/actor/playerspaz.py | 32 ++- .../src/ba_data/python/bastd/game/assault.py | 2 +- .../python/bastd/game/capturetheflag.py | 2 +- .../ba_data/python/bastd/game/chosenone.py | 2 +- .../src/ba_data/python/bastd/game/conquest.py | 8 +- .../ba_data/python/bastd/game/deathmatch.py | 2 +- .../python/bastd/game/easteregghunt.py | 2 +- .../ba_data/python/bastd/game/elimination.py | 2 +- .../src/ba_data/python/bastd/game/football.py | 2 +- .../src/ba_data/python/bastd/game/hockey.py | 2 +- .../src/ba_data/python/bastd/game/keepaway.py | 2 +- .../python/bastd/game/kingofthehill.py | 2 +- .../ba_data/python/bastd/game/meteorshower.py | 2 +- .../ba_data/python/bastd/game/ninjafight.py | 2 +- assets/src/ba_data/python/bastd/game/race.py | 2 +- .../ba_data/python/bastd/game/runaround.py | 2 +- .../python/bastd/game/targetpractice.py | 2 +- assets/src/ba_data/python/bastd/mainmenu.py | 4 +- assets/src/ba_data/python/bastd/tutorial.py | 3 +- docs/ba_module.md | 264 ++++++++++-------- tools/update_project | 19 +- 40 files changed, 335 insertions(+), 275 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 988b9239..9f34ff7b 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1f/1d/c3e431b8c9116fb76eb10c7c3351", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/b8/9cb66184745ef1d783af3f7d3f22", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/52/e8/4826278e2030d629a682a8de070f", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/8a/9e07236256d006f0357d5d1aa887", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/81/38/985294f68973344e2f012fe93c45", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/57/2cdf16147cdd25263ba76aa40198", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/ec/1d64c0c31d58ef530b6894fabf2a", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/ea/c136ba4360d210842915c2f6c55e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/35/06/d5ae11c90f89d1c10ca62a2b2f66", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a1/e9/960e434759c45b623fba34725e64", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dd/d0/f85582938a539d2d677d3e36b61b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/e9/3685ecf7b07f3e3568867da5536f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/a5/bc48ad0c1b5757913b8d354e4302", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/e0/cd115dbd1ce795e9b6a2878e8912", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/78/d3166e9e3f2f443c13838768b4ee", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/79/af/4d26abbac53e9fc396d1fc5660ae", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e0/85/8d8d8d74685d0823bc341942c31c", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/81/06f6dff6c5686d1b2ffb1b44bb46", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/34/96/f1d361405a41d118016a576ef517", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0c/7e/116fdd2bb269fd3c4c3826f526b9", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/75/a6/320d0a4b79a1e0c0cb8fecbc69e2", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8a/de/f35f0be58d20cc58cf1ba078013a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2b/23/849c8e6286a8de4f6140f249c59a", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ba/fd/49fe8a41b0448e2fd81a462618cb" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 563dcadb..ecf35539 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -934,6 +934,7 @@ instancer interstitials intex + intp introspectable ipaddress ipos diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 667f6921..e7c48f86 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=48988468250135652281791058794704714718 +# SOURCES_HASH=289441941088504861465847265420796017643 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -855,18 +855,12 @@ class SessionPlayer: character: str activityplayer: Optional[ba.Player] - def assigninput(self, type: Union[str, Tuple[str, ...]], + def assigninput(self, type: Union[ba.InputType, Tuple[ba.InputType, ...]], call: Callable) -> None: - """assigninput(type: Union[str, Tuple[str, ...]], + """assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]], call: Callable) -> None Set the python callable to be run for one or more types of input. - Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', - 'punchRelease','bombPress', 'bombRelease', 'pickUpPress', - 'pickUpRelease', 'upDown','leftRight','upPress', 'upRelease', - 'downPress', 'downRelease', 'leftPress','leftRelease','rightPress', - 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', - 'startRelease' """ return None @@ -2922,22 +2916,6 @@ def music_player_stop() -> None: return None -def new_activity(activity_type: Type[ba.Activity], - settings: dict = None) -> ba.Activity: - """new_activity(activity_type: Type[ba.Activity], - settings: dict = None) -> ba.Activity - - Instantiates a ba.Activity given a type object. - - Category: General Utility Functions - - Activities require special setup and thus cannot be directly - instantiated; You must go through this function. - """ - import ba # pylint: disable=cyclic-import - return ba.Activity(settings={}) - - def new_host_session(sessiontype: Type[ba.Session], benchmark_type: str = None) -> None: """new_host_session(sessiontype: Type[ba.Session], @@ -2956,6 +2934,22 @@ def new_replay_session(file_name: str) -> None: return None +def newactivity(activity_type: Type[ba.Activity], + settings: dict = None) -> ba.Activity: + """newactivity(activity_type: Type[ba.Activity], + settings: dict = None) -> ba.Activity + + Instantiates a ba.Activity given a type object. + + Category: General Utility Functions + + Activities require special setup and thus cannot be directly + instantiated; You must go through this function. + """ + import ba # pylint: disable=cyclic-import + return ba.Activity(settings={}) + + def newnode(type: str, owner: ba.Node = None, attrs: dict = None, diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 9f1c38b3..26bdf607 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -32,7 +32,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, Vec3, Widget, buttonwidget, camerashake, checkboxwidget, columnwidget, containerwidget, do_once, emitfx, getactivity, getcollidemodel, getmodel, getnodes, getsession, getsound, - gettexture, hscrollwidget, imagewidget, log, new_activity, + gettexture, hscrollwidget, imagewidget, log, newactivity, newnode, playsound, printnodes, printobjects, pushcall, quit, rowwidget, safecolor, screenmessage, scrollwidget, set_analytics_screen, charstr, textwidget, time, timer, @@ -46,7 +46,7 @@ from ba._coopgame import CoopGameActivity from ba._coopsession import CoopSession from ba._dependency import (Dependency, DependencyComponent, DependencySet, AssetPackage) -from ba._enums import TimeType, Permission, TimeFormat, SpecialChar +from ba._enums import TimeType, Permission, TimeFormat, SpecialChar, InputType from ba._error import ( print_exception, print_error, ContextError, NotFoundError, PlayerNotFoundError, SessionPlayerNotFoundError, NodeNotFoundError, @@ -55,7 +55,7 @@ from ba._error import ( SessionNotFoundError, DelegateNotFoundError, DependencyError) from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity -from ba._gameresults import TeamGameResults +from ba._gameresults import GameResults from ba._gamesettings import (Setting, IntSetting, FloatSetting, ChoiceSetting, BoolSetting, IntChoiceSetting, FloatChoiceSetting) diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index 66bbc980..01e3fc55 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -26,6 +26,7 @@ from typing import TYPE_CHECKING import _ba from ba._activity import Activity from ba._music import setmusic, MusicType +from ba._enums import InputType # False-positive from pylint due to our class-generics-filter. from ba._player import EmptyPlayer # pylint: disable=W0611 from ba._team import EmptyTeam # pylint: disable=W0611 @@ -229,6 +230,6 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): # Just to be extra careful, don't assign if we're transitioning out. # (though theoretically that would be ok). if not self.is_transitioning_out() and player: - player.assigninput( - ('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'), - self._player_press) + player.assigninput((InputType.JUMP_PRESS, InputType.PUNCH_PRESS, + InputType.BOMB_PRESS, InputType.PICK_UP_PRESS), + self._player_press) diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index 7646f03a..539cc31d 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -53,7 +53,7 @@ def run_cpu_benchmark() -> None: cfg['Graphics Quality'] = 'Low' cfg.apply() self.benchmark_type = 'cpu' - self.setactivity(_ba.new_activity(tutorial.TutorialActivity)) + self.setactivity(_ba.newactivity(tutorial.TutorialActivity)) def __del__(self) -> None: diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index ac2b4add..926d1cc9 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -98,7 +98,7 @@ class CoopSession(Session): self._custom_menu_ui: List[Dict[str, Any]] = [] # Start our joining screen. - self.setactivity(_ba.new_activity(CoopJoinActivity)) + self.setactivity(_ba.newactivity(CoopJoinActivity)) self._next_game_instance: Optional[ba.GameActivity] = None self._next_game_level_name: Optional[str] = None @@ -126,7 +126,7 @@ class CoopSession(Session): if setting.name not in settings: settings[setting.name] = setting.default - newactivity = _ba.new_activity(gametype, settings) + newactivity = _ba.newactivity(gametype, settings) assert isinstance(newactivity, GameActivity) self._current_game_instance: GameActivity = newactivity @@ -150,7 +150,7 @@ class CoopSession(Session): settings[setting.name] = setting.default # We wanna be in the activity's context while taking it down. - newactivity = _ba.new_activity(gametype, settings) + newactivity = _ba.newactivity(gametype, settings) assert isinstance(newactivity, GameActivity) self._next_game_instance = newactivity self._next_game_level_name = nextlevel.name @@ -165,7 +165,7 @@ class CoopSession(Session): and self._tutorial_activity is None and not self._ran_tutorial_activity): from bastd.tutorial import TutorialActivity - self._tutorial_activity = _ba.new_activity(TutorialActivity) + self._tutorial_activity = _ba.newactivity(TutorialActivity) def get_custom_menu_entries(self) -> List[Dict[str, Any]]: return self._custom_menu_ui @@ -250,7 +250,7 @@ class CoopSession(Session): from ba._lang import Lstr from ba._general import WeakCall from ba._coopgame import CoopGameActivity - from ba._gameresults import TeamGameResults + from ba._gameresults import GameResults from ba._score import ScoreType from ba._player import PlayerInfo from bastd.tutorial import TutorialActivity @@ -258,10 +258,10 @@ class CoopSession(Session): app = _ba.app - # If we're running a TeamGameActivity we'll have a TeamGameResults + # If we're running a TeamGameActivity we'll have a GameResults # as results. Otherwise its an old CoopGameActivity so its giving # us a dict of random stuff. - if isinstance(results, TeamGameResults): + if isinstance(results, GameResults): outcome = 'defeat' # This can't be 'beaten'. else: try: @@ -338,13 +338,13 @@ class CoopSession(Session): # If we were in a tutorial, just pop a transition to get to the # actual round. elif isinstance(activity, TutorialActivity): - self.setactivity(_ba.new_activity(TransitionActivity)) + self.setactivity(_ba.newactivity(TransitionActivity)) else: playerinfos: List[ba.PlayerInfo] # Generic team games. - if isinstance(results, TeamGameResults): + if isinstance(results, GameResults): playerinfos = results.playerinfos score = results.get_team_score(results.sessionteams[0]) fail_message = None @@ -390,10 +390,10 @@ class CoopSession(Session): if outcome == 'restart': # This will pop up back in the same round. - self.setactivity(_ba.new_activity(TransitionActivity)) + self.setactivity(_ba.newactivity(TransitionActivity)) else: self.setactivity( - _ba.new_activity( + _ba.newactivity( CoopScoreScreen, { 'playerinfos': playerinfos, 'score': score, diff --git a/assets/src/ba_data/python/ba/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py index c07e0451..b53eb62f 100644 --- a/assets/src/ba_data/python/ba/_dualteamsession.py +++ b/assets/src/ba_data/python/ba/_dualteamsession.py @@ -35,8 +35,11 @@ class DualTeamSession(MultiTeamSession): Category: Gameplay Classes """ + + # Base class overrides: use_teams = True use_team_colors = True + _playlist_selection_var = 'Team Tournament Playlist Selection' _playlist_randomize_var = 'Team Tournament Playlist Randomize' _playlists_var = 'Team Tournament Playlists' @@ -45,28 +48,28 @@ class DualTeamSession(MultiTeamSession): _ba.increment_analytics_count('Teams session start') super().__init__() - def _switch_to_score_screen(self, results: ba.TeamGameResults) -> None: + def _switch_to_score_screen(self, results: ba.GameResults) -> None: # pylint: disable=cyclic-import from bastd.activity.drawscore import DrawScoreScreenActivity from bastd.activity.dualteamscore import ( TeamVictoryScoreScreenActivity) from bastd.activity.multiteamvictory import ( TeamSeriesVictoryScoreScreenActivity) - winners = results.winnergroups + winnergroups = results.winnergroups # If everyone has the same score, call it a draw. - if len(winners) < 2: - self.setactivity(_ba.new_activity(DrawScoreScreenActivity)) + if len(winnergroups) < 2: + self.setactivity(_ba.newactivity(DrawScoreScreenActivity)) else: - winner = winners[0].teams[0] + winner = winnergroups[0].teams[0] winner.customdata['score'] += 1 # If a team has won, show final victory screen. if winner.customdata['score'] >= (self._series_length - 1) / 2 + 1: self.setactivity( - _ba.new_activity(TeamSeriesVictoryScoreScreenActivity, - {'winner': winner})) + _ba.newactivity(TeamSeriesVictoryScoreScreenActivity, + {'winner': winner})) else: self.setactivity( - _ba.new_activity(TeamVictoryScoreScreenActivity, - {'winner': winner})) + _ba.newactivity(TeamVictoryScoreScreenActivity, + {'winner': winner})) diff --git a/assets/src/ba_data/python/ba/_enums.py b/assets/src/ba_data/python/ba/_enums.py index 4d69467e..3d78425a 100644 --- a/assets/src/ba_data/python/ba/_enums.py +++ b/assets/src/ba_data/python/ba/_enums.py @@ -23,6 +23,39 @@ from enum import Enum +class InputType(Enum): + """Types of input a controller can send to the game. + + Category: Enums + + """ + UP_DOWN = 0 + LEFT_RIGHT = 1 + JUMP_PRESS = 2 + JUMP_RELEASE = 3 + PUNCH_PRESS = 4 + PUNCH_RELEASE = 5 + BOMB_PRESS = 6 + BOMB_RELEASE = 7 + PICK_UP_PRESS = 8 + PICK_UP_RELEASE = 9 + RUN = 10 + FLY_PRESS = 11 + FLY_RELEASE = 12 + START_PRESS = 13 + START_RELEASE = 14 + HOLD_POSITION_PRESS = 15 + HOLD_POSITION_RELEASE = 16 + LEFT_PRESS = 17 + LEFT_RELEASE = 18 + RIGHT_PRESS = 19 + RIGHT_RELEASE = 20 + UP_PRESS = 21 + UP_RELEASE = 22 + DOWN_PRESS = 23 + DOWN_RELEASE = 24 + + class TimeType(Enum): """Specifies the type of time for various operations to target/use. diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index 71ac1088..2f39ba5c 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -69,7 +69,7 @@ class FreeForAllSession(MultiTeamSession): _ba.increment_analytics_count('Free-for-all session start') super().__init__() - def _switch_to_score_screen(self, results: ba.TeamGameResults) -> None: + def _switch_to_score_screen(self, results: ba.GameResults) -> None: # pylint: disable=cyclic-import from bastd.activity.drawscore import DrawScoreScreenActivity from bastd.activity.multiteamvictory import ( @@ -82,8 +82,7 @@ class FreeForAllSession(MultiTeamSession): # call it a draw. if len(self.players) > 1 and len(winners) < 2: self.setactivity( - _ba.new_activity(DrawScoreScreenActivity, - {'results': results})) + _ba.newactivity(DrawScoreScreenActivity, {'results': results})) else: # Award different point amounts based on number of players. point_awards = self.get_ffa_point_awards() @@ -106,9 +105,9 @@ class FreeForAllSession(MultiTeamSession): and series_winners[0].customdata['score'] != series_winners[1].customdata['score'])): self.setactivity( - _ba.new_activity(TeamSeriesVictoryScoreScreenActivity, - {'winner': series_winners[0]})) + _ba.newactivity(TeamSeriesVictoryScoreScreenActivity, + {'winner': series_winners[0]})) else: self.setactivity( - _ba.new_activity(FreeForAllVictoryScoreScreenActivity, - {'results': results})) + _ba.newactivity(FreeForAllVictoryScoreScreenActivity, + {'results': results})) diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index 66f8d263..a6320fa8 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -820,11 +820,11 @@ class GameActivity(Activity[PlayerType, TeamType]): results: Any = None, delay: float = 0.0, force: bool = False) -> None: - from ba._gameresults import TeamGameResults + from ba._gameresults import GameResults # If results is a standard team-game-results, associate it with us # so it can grab our score prefs. - if isinstance(results, TeamGameResults): + if isinstance(results, GameResults): results.set_game(self) # If we had a standard time-limit that had not expired, stop it so diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 58e0a285..8b850f80 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -39,9 +39,9 @@ class WinnerGroup: teams: Sequence[ba.SessionTeam] -class TeamGameResults: +class GameResults: """ - Results for a completed ba.TeamGameActivity. + Results for a completed game. Category: Gameplay Classes @@ -65,7 +65,7 @@ class TeamGameResults: def set_game(self, game: ba.GameActivity) -> None: """Set the game instance these results are applying to.""" if self._game_set: - raise RuntimeError('Game set twice for TeamGameResults.') + raise RuntimeError('Game set twice for GameResults.') self._game_set = True self._sessionteams = [weakref.ref(team) for team in game.teams] scoreconfig = game.getscoreconfig() diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 10cfa563..c3564c81 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -30,7 +30,7 @@ import _ba from ba._error import print_exception, print_error, NotFoundError from ba._gameutils import animate, animate_array from ba._lang import Lstr -from ba._enums import SpecialChar +from ba._enums import SpecialChar, InputType from ba._profile import get_player_profile_colors if TYPE_CHECKING: @@ -515,32 +515,36 @@ class Chooser: if not ready: self._sessionplayer.assigninput( - 'leftPress', Call(self.handlemessage, - ChangeMessage('team', -1))) + InputType.LEFT_PRESS, + Call(self.handlemessage, ChangeMessage('team', -1))) self._sessionplayer.assigninput( - 'rightPress', Call(self.handlemessage, - ChangeMessage('team', 1))) + InputType.RIGHT_PRESS, + Call(self.handlemessage, ChangeMessage('team', 1))) self._sessionplayer.assigninput( - 'bombPress', + InputType.BOMB_PRESS, Call(self.handlemessage, ChangeMessage('character', 1))) self._sessionplayer.assigninput( - 'upPress', + InputType.UP_PRESS, Call(self.handlemessage, ChangeMessage('profileindex', -1))) self._sessionplayer.assigninput( - 'downPress', + InputType.DOWN_PRESS, Call(self.handlemessage, ChangeMessage('profileindex', 1))) self._sessionplayer.assigninput( - ('jumpPress', 'pickUpPress', 'punchPress'), + (InputType.JUMP_PRESS, InputType.PICK_UP_PRESS, + InputType.PUNCH_PRESS), Call(self.handlemessage, ChangeMessage('ready', 1))) self._ready = False self._update_text() self._sessionplayer.setname('untitled', real=False) else: self._sessionplayer.assigninput( - ('leftPress', 'rightPress', 'upPress', 'downPress', - 'jumpPress', 'bombPress', 'pickUpPress'), self._do_nothing) + (InputType.LEFT_PRESS, InputType.RIGHT_PRESS, + InputType.UP_PRESS, InputType.DOWN_PRESS, + InputType.JUMP_PRESS, InputType.BOMB_PRESS, + InputType.PICK_UP_PRESS), self._do_nothing) self._sessionplayer.assigninput( - ('jumpPress', 'bombPress', 'pickUpPress', 'punchPress'), + (InputType.JUMP_PRESS, InputType.BOMB_PRESS, + InputType.PICK_UP_PRESS, InputType.PUNCH_PRESS), Call(self.handlemessage, ChangeMessage('ready', 0))) # Store the last profile picked by this input for reuse. diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 91a17e5c..90bd4b1f 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -85,7 +85,7 @@ class MultiTeamSession(Session): from bastd.tutorial import TutorialActivity # Get this loading. - self._tutorial_activity_instance = _ba.new_activity( + self._tutorial_activity_instance = _ba.newactivity( TutorialActivity) else: self._tutorial_activity_instance = None @@ -133,7 +133,7 @@ class MultiTeamSession(Session): self._instantiate_next_game() # Start in our custom join screen. - self.setactivity(_ba.new_activity(MultiTeamJoinActivity)) + self.setactivity(_ba.newactivity(MultiTeamJoinActivity)) def get_ffa_series_length(self) -> int: """Return free-for-all series length.""" @@ -165,7 +165,7 @@ class MultiTeamSession(Session): return _ba.app.config.get('Free-for-All Max Players', 8) def _instantiate_next_game(self) -> None: - self._next_game_instance = _ba.new_activity( + self._next_game_instance = _ba.newactivity( self._next_game_spec['resolved_type'], self._next_game_spec['settings']) @@ -187,7 +187,7 @@ class MultiTeamSession(Session): # to transition us into a round gracefully (otherwise we'd snap from # one terrain to another instantly). elif isinstance(activity, TutorialActivity): - self.setactivity(_ba.new_activity(TransitionActivity)) + self.setactivity(_ba.newactivity(TransitionActivity)) # If we're in a between-round activity or a restart-activity, hop # into a round. @@ -241,7 +241,7 @@ class MultiTeamSession(Session): def announce_game_results(self, activity: ba.GameActivity, - results: ba.TeamGameResults, + results: ba.GameResults, delay: float, announce_winning_team: bool = True) -> None: """Show basic game result at the end of a game. diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 3a1c38e1..a07bc61d 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -269,18 +269,13 @@ class Player(Generic[TeamType]): assert not self._expired return self._sessionplayer.get_icon() - def assigninput(self, inputtype: Union[str, Tuple[str, ...]], + def assigninput(self, inputtype: Union[ba.InputType, Tuple[ba.InputType, + ...]], call: Callable) -> None: - """assigninput(type: Union[str, Tuple[str, ...]], + """assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]], call: Callable) -> None Set the python callable to be run for one or more types of input. - Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', - 'punchRelease','bombPress', 'bombRelease', 'pickUpPress', - 'pickUpRelease', 'upDown','leftRight','upPress', 'upRelease', - 'downPress', 'downRelease', 'leftPress','leftRelease','rightPress', - 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', - 'startRelease' """ assert self._postinited assert not self._expired diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index a290efde..2025cc42 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -177,7 +177,7 @@ class Session: self._ending = False self._activity_should_end_immediately = False self._activity_should_end_immediately_results: ( - Optional[ba.TeamGameResults]) = None + Optional[ba.GameResults]) = None self._activity_should_end_immediately_delay = 0.0 # Create static teams if we're using them. @@ -348,7 +348,7 @@ class Session: '_launch_end_session_activity called twice (since_last=' + str(since_last) + ')') self._launch_end_session_activity_time = curtime - self.setactivity(_ba.new_activity(EndSessionActivity)) + self.setactivity(_ba.newactivity(EndSessionActivity)) self._wants_to_end = False self._ending = True # Prevent further actions. diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index b6cb3386..0bd3736c 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -26,7 +26,7 @@ from typing import TYPE_CHECKING, TypeVar from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity -from ba._gameresults import TeamGameResults +from ba._gameresults import GameResults from ba._dualteamsession import DualTeamSession import _ba @@ -152,7 +152,7 @@ class TeamGameActivity(GameActivity[PlayerType, TeamType]): super().end(results, delay=2.0 + announce_delay, force=force) # Need to do this *after* end end call so that results is valid. - assert isinstance(results, TeamGameResults) + assert isinstance(results, GameResults) if do_announce and isinstance(session, MultiTeamSession): session.announce_game_results( self, diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py index 3dd4232c..d3147b32 100644 --- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py +++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py @@ -83,7 +83,7 @@ class FreeForAllVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): ba.timer(0.3, ba.Call(ba.playsound, self._score_display_sound)) results = self.settings_raw['results'] - assert isinstance(results, ba.TeamGameResults) + assert isinstance(results, ba.GameResults) self.show_player_scores(delay=0.001, results=results, scale=1.2, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index 909619b5..c95266d1 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -70,7 +70,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): def show_player_scores(self, delay: float = 2.5, - results: Optional[ba.TeamGameResults] = None, + results: Optional[ba.GameResults] = None, scale: float = 1.0, x_offset: float = 0.0, y_offset: float = 0.0) -> None: @@ -87,7 +87,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): def _get_prec_score(p_rec: ba.PlayerRecord) -> Optional[int]: if is_free_for_all and results is not None: - assert isinstance(results, ba.TeamGameResults) + assert isinstance(results, ba.GameResults) assert p_rec.team.gameteam is not None val = results.get_team_score(p_rec.team) return val @@ -95,7 +95,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): def _get_prec_score_str(p_rec: ba.PlayerRecord) -> Union[str, ba.Lstr]: if is_free_for_all and results is not None: - assert isinstance(results, ba.TeamGameResults) + assert isinstance(results, ba.GameResults) assert p_rec.team.gameteam is not None val = results.get_team_score_str(p_rec.team.gameteam) assert val is not None @@ -107,7 +107,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): # (since they're not in results and that's where we pull their # scores from) if results is not None: - assert isinstance(results, ba.TeamGameResults) + assert isinstance(results, ba.GameResults) player_records = [] assert self.stats valid_players = list(self.stats.get_records().items()) diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 7d8da8d5..48acc0aa 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -143,28 +143,30 @@ class PlayerSpaz(Spaz): else: player.resetinput() - player.assigninput('upDown', self.on_move_up_down) - player.assigninput('leftRight', self.on_move_left_right) - player.assigninput('holdPositionPress', self.on_hold_position_press) - player.assigninput('holdPositionRelease', + player.assigninput(ba.InputType.UP_DOWN, self.on_move_up_down) + player.assigninput(ba.InputType.LEFT_RIGHT, self.on_move_left_right) + player.assigninput(ba.InputType.HOLD_POSITION_PRESS, + self.on_hold_position_press) + player.assigninput(ba.InputType.HOLD_POSITION_RELEASE, self.on_hold_position_release) + intp = ba.InputType if enable_jump: - player.assigninput('jumpPress', self.on_jump_press) - player.assigninput('jumpRelease', self.on_jump_release) + player.assigninput(intp.JUMP_PRESS, self.on_jump_press) + player.assigninput(intp.JUMP_RELEASE, self.on_jump_release) if enable_pickup: - player.assigninput('pickUpPress', self.on_pickup_press) - player.assigninput('pickUpRelease', self.on_pickup_release) + player.assigninput(intp.PICK_UP_PRESS, self.on_pickup_press) + player.assigninput(intp.PICK_UP_RELEASE, self.on_pickup_release) if enable_punch: - player.assigninput('punchPress', self.on_punch_press) - player.assigninput('punchRelease', self.on_punch_release) + player.assigninput(intp.PUNCH_PRESS, self.on_punch_press) + player.assigninput(intp.PUNCH_RELEASE, self.on_punch_release) if enable_bomb: - player.assigninput('bombPress', self.on_bomb_press) - player.assigninput('bombRelease', self.on_bomb_release) + player.assigninput(intp.BOMB_PRESS, self.on_bomb_press) + player.assigninput(intp.BOMB_RELEASE, self.on_bomb_release) if enable_run: - player.assigninput('run', self.on_run) + player.assigninput(intp.RUN, self.on_run) if enable_fly: - player.assigninput('flyPress', self.on_fly_press) - player.assigninput('flyRelease', self.on_fly_release) + player.assigninput(intp.FLY_PRESS, self.on_fly_press) + player.assigninput(intp.FLY_RELEASE, self.on_fly_release) self._connected_to_player = player diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index d1226977..17d6fea2 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -261,7 +261,7 @@ class AssaultGame(ba.TeamGameActivity[Player, Team]): self.end_game() def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 3f709d0b..f12cdde8 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -388,7 +388,7 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): self.end_game() def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results, announce_delay=0.8) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index 95fc6527..b9d4463f 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -262,7 +262,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): self._set_chosen_one_player(None) def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, self._chosen_one_time - team.time_remaining) diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 7849910b..06ac4d21 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -149,8 +149,10 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): # We want flags to tell us they've been hit but not react physically. self._extraflagmat.add_actions( conditions=('they_have_material', shared.player_material), - actions=(('modify_part_collision', 'collide', True), - ('call', 'at_connect', self._handle_flag_player_collide))) + actions=( + ('modify_part_collision', 'collide', True), + ('call', 'at_connect', self._handle_flag_player_collide), + )) def get_instance_description(self) -> Union[str, Sequence]: return 'Secure all ${ARG1} flags.', len(self.map.flag_points) @@ -229,7 +231,7 @@ class ConquestGame(ba.TeamGameActivity[Player, Team]): len(self._flags)) def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.flags_held) self.end(results=results) diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 0b29ef1f..4a8c95c4 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -211,7 +211,7 @@ class DeathMatchGame(ba.TeamGameActivity[Player, Team]): self._score_to_win) def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index bc37fcca..aa0c99ea 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -230,7 +230,7 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]): self._scoreboard.set_team_value(team, team.score) def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results) diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 3ab82c96..14c428fc 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -575,7 +575,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): def end_game(self) -> None: if self.has_ended(): return - results = ba.TeamGameResults() + results = ba.GameResults() self._vs_text = None # Kill our 'vs' if its there. for team in self.teams: results.set_team_score(team, team.survival_seconds) diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 530ea8ef..c6b12473 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -266,7 +266,7 @@ class FootballTeamGame(ba.TeamGameActivity[Player, Team]): self._update_scoreboard() def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results, announce_delay=0.8) diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index 30a64f2b..bf09dff9 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -343,7 +343,7 @@ class HockeyGame(ba.TeamGameActivity[Player, Team]): self._update_scoreboard() def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results=results) diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 79007e6d..a15de541 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -190,7 +190,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]): self.end_game() def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, self._hold_time - team.timeremaining) self.end(results=results, announce_delay=0) diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 5e44602e..079a1f73 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -227,7 +227,7 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]): self.end_game() def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, self._hold_time - team.time_remaining) self.end(results=results, announce_delay=0) diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 5f7df16f..233894c6 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -263,7 +263,7 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): # Ok now calc game results: set a score for each team and then tell # the game to end. - results = ba.TeamGameResults() + results = ba.GameResults() # Remember that 'free-for-all' mode is simply a special form # of 'teams' mode where each player gets their own team, so we can diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 54e0a20d..1180dda6 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -172,7 +172,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): assert self._timer is not None self._timer.stop() - results = ba.TeamGameResults() + results = ba.GameResults() # If we won, set our score to the elapsed time in milliseconds. # (there should just be 1 team here since this is co-op). diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index 9b050b96..bbe8dc26 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -712,7 +712,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): endtime=None if self._last_team_time is None else ( self._timer.getstarttime() + self._last_team_time)) - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: if team.time is not None: diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index acccd945..34d6139d 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -68,7 +68,7 @@ class Point(Enum): @dataclass class Spawn: - """Defines a bot spawn.""" + """Defines a bot spawn event.""" type: Type[SpazBot] path: int = 0 point: Optional[Point] = None diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index c646a6af..2945551d 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -202,7 +202,7 @@ class TargetPracticeGame(ba.TeamGameActivity[Player, Team]): self._scoreboard.set_team_value(team, team.score) def end_game(self) -> None: - results = ba.TeamGameResults() + results = ba.GameResults() for team in self.teams: results.set_team_score(team, team.score) self.end(results) diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index e0e39deb..ae792fbb 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -920,14 +920,14 @@ class MainMenuSession(ba.Session): super().__init__([self._activity_deps]) self._locked = False - self.setactivity(ba.new_activity(MainMenuActivity)) + self.setactivity(ba.newactivity(MainMenuActivity)) def on_activity_end(self, activity: ba.Activity, results: Any) -> None: if self._locked: _ba.unlock_all_input() # Any ending activity leads us into the main menu one. - self.setactivity(ba.new_activity(MainMenuActivity)) + self.setactivity(ba.newactivity(MainMenuActivity)) def on_player_request(self, player: ba.SessionPlayer) -> bool: # Reject all player requests. diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index 95a65111..3aa0ca0d 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -2413,7 +2413,8 @@ class TutorialActivity(ba.Activity[Player, Team]): # We just wanna know if this player presses anything. player.assigninput( - ('jumpPress', 'punchPress', 'bombPress', 'pickUpPress'), + (ba.InputType.JUMP_PRESS, ba.InputType.PUNCH_PRESS, + ba.InputType.BOMB_PRESS, ba.InputType.PICK_UP_PRESS), ba.Call(self._player_pressed_button, player)) def on_player_leave(self, player: Player) -> None: diff --git a/docs/ba_module.md b/docs/ba_module.md index 1ecb47b6..c3fadfde 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-02 for Ballistica version 1.5.0 build 20042

    +

    last updated on 2020-06-02 for Ballistica version 1.5.0 build 20043

    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!


    @@ -20,6 +20,7 @@
  • ba.NodeActor
  • ba.Chooser
  • +
  • ba.GameResults
  • ba.InputDevice
  • ba.Level
  • ba.Lobby
  • @@ -50,7 +51,6 @@ -
  • ba.TeamGameResults
  • Gameplay Functions

    +
    +
    +

    ba.GameResults

    +

    <top level class> +

    +

    +Results for a completed game.

    + +

    Category: Gameplay Classes

    + +

    Upon completion, a game should fill one of these out and pass it to its +ba.Activity.end() call.

    + +

    Attributes:

    +
    lower_is_better, playerinfos, score_label, scoretype, sessionteams, winnergroups, winning_team
    +
    +

    lower_is_better

    +

    bool

    +

    Whether lower scores are better.

    + +
    +

    playerinfos

    +

    List[ba.PlayerInfo]

    +

    Get info about the players represented by the results.

    + +
    +

    score_label

    +

    str

    +

    The label associated with scores ('points', etc).

    + +
    +

    scoretype

    +

    ba.ScoreType

    +

    The type of score.

    + +
    +

    sessionteams

    +

    List[ba.SessionTeam]

    +

    Return all ba.SessionTeams in the results.

    + +
    +

    winnergroups

    +

    List[WinnerGroup]

    +

    Get an ordered list of winner groups.

    + +
    +

    winning_team

    +

    Optional[ba.SessionTeam]

    +

    The winning ba.SessionTeam if there is exactly one, or else None.

    + +
    +
    +

    Methods:

    +
    <constructor>, get_team_score(), get_team_score_str(), has_score_for_team(), set_game(), set_team_score()
    +
    +

    <constructor>

    +

    ba.GameResults()

    + +

    Instantiate a results instance.

    + +
    +

    get_team_score()

    +

    get_team_score(self, sessionteam: Union[ba.SessionTeam]) -> Optional[int]

    + +

    Return the score for a given ba.SessionTeam.

    + +
    +

    get_team_score_str()

    +

    get_team_score_str(self, team: ba.Team) -> ba.Lstr

    + +

    Return the score for the given ba.Team as an Lstr.

    + +

    (properly formatted for the score type.)

    + +
    +

    has_score_for_team()

    +

    has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool

    + +

    Return whether there is a score for a given team.

    + +
    +

    set_game()

    +

    set_game(self, game: ba.GameActivity) -> None

    + +

    Set the game instance these results are applying to.

    + +
    +

    set_team_score()

    +

    set_team_score(self, team: ba.Team, score: Optional[int]) -> None

    + +

    Set the score for a given ba.Team.

    + +

    This can be a number or None. +(see the none_is_winner arg in the constructor)

    +

    @@ -2914,6 +3011,43 @@ prefs, etc.

    Methods:

    <all methods inherited from ba.NotFoundError>


    +

    ba.InputType

    +

    Inherits from: enum.Enum

    +

    Types of input a controller can send to the game.

    + +

    Category: Enums

    + +

    + +

    Values:

    +
      +
    • UP_DOWN
    • +
    • LEFT_RIGHT
    • +
    • JUMP_PRESS
    • +
    • JUMP_RELEASE
    • +
    • PUNCH_PRESS
    • +
    • PUNCH_RELEASE
    • +
    • BOMB_PRESS
    • +
    • BOMB_RELEASE
    • +
    • PICK_UP_PRESS
    • +
    • PICK_UP_RELEASE
    • +
    • RUN
    • +
    • FLY_PRESS
    • +
    • FLY_RELEASE
    • +
    • START_PRESS
    • +
    • START_RELEASE
    • +
    • HOLD_POSITION_PRESS
    • +
    • HOLD_POSITION_RELEASE
    • +
    • LEFT_PRESS
    • +
    • LEFT_RELEASE
    • +
    • RIGHT_PRESS
    • +
    • RIGHT_RELEASE
    • +
    • UP_PRESS
    • +
    • UP_RELEASE
    • +
    • DOWN_PRESS
    • +
    • DOWN_RELEASE
    • +
    +

    ba.IntChoiceSetting

    Inherits from: ba.ChoiceSetting, ba.Setting

    An int setting with multiple choices.

    @@ -3615,7 +3749,7 @@ Use ba.getmodel() to instantiate one.

    announce_game_results()

    -

    announce_game_results(self, activity: ba.GameActivity, results: ba.TeamGameResults, delay: float, announce_winning_team: bool = True) -> None

    +

    announce_game_results(self, activity: ba.GameActivity, results: ba.GameResults, delay: float, announce_winning_team: bool = True) -> None

    Show basic game result at the end of a game.

    @@ -4134,18 +4268,12 @@ even if myactor is set to None.

    assigninput(), exists(), get_icon(), getname(), is_alive(), on_expire(), resetinput()

    assigninput()

    -

    assigninput(self, inputtype: Union[str, Tuple[str, ...]], call: Callable) -> None

    +

    assigninput(self, inputtype: Union[ba.InputType, Tuple[ba.InputType, ...]], call: Callable) -> None

    -

    assigninput(type: Union[str, Tuple[str, ...]], +

    assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]], call: Callable) -> None

    -

    Set the python callable to be run for one or more types of input. -Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', - 'punchRelease','bombPress', 'bombRelease', 'pickUpPress', - 'pickUpRelease', 'upDown','leftRight','upPress', 'upRelease', - 'downPress', 'downRelease', 'leftPress','leftRelease','rightPress', - 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', - 'startRelease'

    +

    Set the python callable to be run for one or more types of input.

    exists()

    @@ -4828,16 +4956,10 @@ is still in its lobby selecting a team/etc. then a
    assigninput(), exists(), get_account_id(), get_icon(), getname(), remove_from_game(), resetinput(), setname()

    assigninput()

    -

    assigninput(type: Union[str, Tuple[str, ...]], +

    assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]], call: Callable) -> None

    -

    Set the python callable to be run for one or more types of input. -Valid type values are: 'jumpPress', 'jumpRelease', 'punchPress', - 'punchRelease','bombPress', 'bombRelease', 'pickUpPress', - 'pickUpRelease', 'upDown','leftRight','upPress', 'upRelease', - 'downPress', 'downRelease', 'leftPress','leftRelease','rightPress', - 'rightRelease', 'run', 'flyPress', 'flyRelease', 'startPress', - 'startRelease'

    +

    Set the python callable to be run for one or more types of input.

    exists()

    @@ -5404,102 +5526,6 @@ on the ba.Player and their ba.DualTeamSessions and ba.FreeForAllSessions; False otherwise.

    -
    -
    -
    -

    ba.TeamGameResults

    -

    <top level class> -

    -

    -Results for a completed ba.TeamGameActivity.

    - -

    Category: Gameplay Classes

    - -

    Upon completion, a game should fill one of these out and pass it to its -ba.Activity.end() call.

    - -

    Attributes:

    -
    lower_is_better, playerinfos, score_label, scoretype, sessionteams, winnergroups, winning_team
    -
    -

    lower_is_better

    -

    bool

    -

    Whether lower scores are better.

    - -
    -

    playerinfos

    -

    List[ba.PlayerInfo]

    -

    Get info about the players represented by the results.

    - -
    -

    score_label

    -

    str

    -

    The label associated with scores ('points', etc).

    - -
    -

    scoretype

    -

    ba.ScoreType

    -

    The type of score.

    - -
    -

    sessionteams

    -

    List[ba.SessionTeam]

    -

    Return all ba.SessionTeams in the results.

    - -
    -

    winnergroups

    -

    List[WinnerGroup]

    -

    Get an ordered list of winner groups.

    - -
    -

    winning_team

    -

    Optional[ba.SessionTeam]

    -

    The winning ba.SessionTeam if there is exactly one, or else None.

    - -
    -
    -

    Methods:

    -
    <constructor>, get_team_score(), get_team_score_str(), has_score_for_team(), set_game(), set_team_score()
    -
    -

    <constructor>

    -

    ba.TeamGameResults()

    - -

    Instantiate a results instance.

    - -
    -

    get_team_score()

    -

    get_team_score(self, sessionteam: Union[ba.SessionTeam]) -> Optional[int]

    - -

    Return the score for a given ba.SessionTeam.

    - -
    -

    get_team_score_str()

    -

    get_team_score_str(self, team: ba.Team) -> ba.Lstr

    - -

    Return the score for the given ba.Team as an Lstr.

    - -

    (properly formatted for the score type.)

    - -
    -

    has_score_for_team()

    -

    has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool

    - -

    Return whether there is a score for a given team.

    - -
    -

    set_game()

    -

    set_game(self, game: ba.GameActivity) -> None

    - -

    Set the game instance these results are applying to.

    - -
    -

    set_team_score()

    -

    set_team_score(self, team: ba.Team, score: Optional[int]) -> None

    - -

    Set the score for a given ba.Team.

    - -

    This can be a number or None. -(see the none_is_winner arg in the constructor)

    -

    @@ -6375,8 +6401,8 @@ issues unless to_server is False.

    so in most cases you can just use that.


    -

    ba.new_activity()

    -

    new_activity(activity_type: Type[ba.Activity], +

    ba.newactivity()

    +

    newactivity(activity_type: Type[ba.Activity], settings: dict = None) -> ba.Activity

    Instantiates a ba.Activity given a type object.

    diff --git a/tools/update_project b/tools/update_project index 008ec748..f50d074b 100755 --- a/tools/update_project +++ b/tools/update_project @@ -145,7 +145,7 @@ class App: if os.path.exists('tools/gendummymodule.py'): if os.system('tools/gendummymodule.py' + self._checkarg) != 0: print( - f'{Clr.RED}Error checking/updating dummy module{Clr.RST}') + f'{Clr.RED}Error checking/updating dummy module.{Clr.RST}') sys.exit(255) def _update_docs_md(self) -> None: @@ -636,33 +636,32 @@ class App: def _update_assets_makefile(self) -> None: assert os.path.exists('tools/update_assets_makefile') if os.system('tools/update_assets_makefile' + self._checkarg) != 0: - print(Clr.RED + 'Error checking/updating assets Makefile' + - Clr.RST) + print( + f'{Clr.RED}Error checking/updating assets Makefile.f{Clr.RST}') sys.exit(255) def _update_generated_code_makefile(self) -> None: if os.path.exists('tools/update_generated_code_makefile'): if os.system('tools/update_generated_code_makefile' + self._checkarg) != 0: - print(Clr.RED + - 'Error checking/updating generated-code Makefile' + - Clr.RST) + print(f'{Clr.RED}Error checking/updating' + f' generated-code Makefile{Clr.RED}') sys.exit(255) def _update_resources_makefile(self) -> None: if os.path.exists('tools/update_resources_makefile'): if os.system('tools/update_resources_makefile' + self._checkarg) != 0: - print(Clr.RED + 'Error checking/updating resources Makefile' + - Clr.RST) + print(f'{Clr.RED}Error checking/updating' + f' resources Makefile.{Clr.RST}') sys.exit(255) def _update_python_enums_module(self) -> None: if os.path.exists('tools/update_python_enums_module'): if os.system('tools/update_python_enums_module' + self._checkarg) != 0: - print(Clr.RED + 'Error checking/updating python enums module' + - Clr.RST) + print(f'{Clr.RED}Error checking/updating' + f' python enums module.{Clr.RST}') sys.exit(255) From 9a48d6581aa93b6f2b9abed4b253a084ae25b728 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 3 Jun 2020 01:24:12 -0700 Subject: [PATCH 074/417] More general type cleanup --- .efrocachemap | 24 +-- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/__init__.py | 2 +- assets/src/ba_data/python/ba/_activity.py | 13 +- assets/src/ba_data/python/ba/_appdelegate.py | 4 +- assets/src/ba_data/python/ba/_coopsession.py | 2 +- assets/src/ba_data/python/ba/_gameactivity.py | 110 ++++---------- assets/src/ba_data/python/ba/_gameresults.py | 7 +- assets/src/ba_data/python/ba/_gameutils.py | 12 ++ assets/src/ba_data/python/ba/_general.py | 2 +- .../ba_data/python/ba/_multiteamsession.py | 2 +- assets/src/ba_data/python/ba/_player.py | 8 +- assets/src/ba_data/python/ba/_session.py | 8 +- assets/src/ba_data/python/ba/_stats.py | 55 +++---- .../python/bastd/activity/multiteamscore.py | 2 +- .../src/ba_data/python/bastd/appdelegate.py | 4 +- .../ba_data/python/bastd/game/onslaught.py | 54 +++---- docs/ba_module.md | 138 +++++++----------- 18 files changed, 187 insertions(+), 262 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 9f34ff7b..f420e66d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/a5/bc48ad0c1b5757913b8d354e4302", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/e0/cd115dbd1ce795e9b6a2878e8912", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/44/78/d3166e9e3f2f443c13838768b4ee", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/79/af/4d26abbac53e9fc396d1fc5660ae", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e0/85/8d8d8d74685d0823bc341942c31c", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/81/06f6dff6c5686d1b2ffb1b44bb46", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/34/96/f1d361405a41d118016a576ef517", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0c/7e/116fdd2bb269fd3c4c3826f526b9", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/75/a6/320d0a4b79a1e0c0cb8fecbc69e2", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8a/de/f35f0be58d20cc58cf1ba078013a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2b/23/849c8e6286a8de4f6140f249c59a", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ba/fd/49fe8a41b0448e2fd81a462618cb" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/7f/785a205dbe19ee4099f427dd9ca2", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/10/7ab16ca078a401bbbe2310660b85", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/f5/be729c0261c6326c3ef92330b764", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/9d/98bc183187af679fbc6531e3ac04", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/17/07/aed82d9bc9c5b4dd3457fcea9a8a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/71/5e/a837ebb98b829cd3bebf081e02b0", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/a0/3204f264abfd13f40f7f4f72aa65", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/ab/de21be17db5b93a7191c353dbce8", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/54/5a/e32b46e614ed37c7ebe42c73b03c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/09/2245bdaf317da30c7d63d8559c82", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f6/45/6972dd74de4fc822a28e995a4a0d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/34/74/e8ff832e808ceaa07a4015fb2a5f" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index e7c48f86..4fb9bba5 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=289441941088504861465847265420796017643 +# SOURCES_HASH=102801821147286215106809880997032542189 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 26bdf607..d257eca7 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -73,7 +73,7 @@ from ba._appconfig import AppConfig from ba._appdelegate import AppDelegate from ba._apputils import is_browser_likely_available from ba._campaign import Campaign -from ba._gameutils import (animate, animate_array, show_damage_count, +from ba._gameutils import (GameTip, animate, animate_array, show_damage_count, timestring, cameraflash) from ba._general import (WeakCall, Call, existing, Existable, verify_object_death, storagename) diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 0fa0d50e..08795ab9 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -169,12 +169,8 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # FIXME: Relocate or remove the need for this stuff. self.paused_text: Optional[ba.Actor] = None - self.spaz_respawn_icons_right: Dict[int, RespawnIcon] - session = _ba.getsession() - if session is None: - raise RuntimeError('No current session') - self._session = weakref.ref(session) + self._session = weakref.ref(_ba.getsession()) # Preloaded data for actors, maps, etc; indexed by type. self.preloads: Dict[Type, Any] = {} @@ -193,12 +189,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._delay_delete_teams: List[TeamType] = [] self._players_that_left: List[ReferenceType[PlayerType]] = [] self._teams_that_left: List[ReferenceType[TeamType]] = [] - - # This gets set once another activity has begun transitioning in but - # before this one is killed. The on_transition_out() method is also - # called at this time. Make sure to not assign player inputs, - # change music, or anything else with global implications once this - # happens. self._transitioning_out = False # A handy place to put most actors; this list is pruned of dead @@ -209,7 +199,6 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._last_prune_dead_actors_time = _ba.time() self._prune_dead_actors_timer: Optional[ba.Timer] = None - # This stuff gets filled in just before on_begin() is called. self.teams = [] self.players = [] diff --git a/assets/src/ba_data/python/ba/_appdelegate.py b/assets/src/ba_data/python/ba/_appdelegate.py index 148b5587..e1cf5431 100644 --- a/assets/src/ba_data/python/ba/_appdelegate.py +++ b/assets/src/ba_data/python/ba/_appdelegate.py @@ -36,14 +36,14 @@ class AppDelegate: def create_default_game_settings_ui( self, gameclass: Type[ba.GameActivity], - sessionclass: Type[ba.Session], config: Optional[dict], + sessiontype: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None: """Launch a UI to configure the given game config. It should manipulate the contents of config and call completion_call when done. """ - del gameclass, sessionclass, config, completion_call # unused + del gameclass, sessiontype, settings, completion_call # Unused. from ba import _error _error.print_error( "create_default_game_settings_ui needs to be overridden") diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 926d1cc9..8f57b9b8 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -312,7 +312,7 @@ class CoopSession(Session): # Skip players that are still choosing a team. if player.in_game: - self.stats.register_player(player) + self.stats.register_sessionplayer(player) self.stats.setactivity(next_game) # Now flip the current activity. diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index a6320fa8..c83e6ea6 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -54,7 +54,8 @@ class GameActivity(Activity[PlayerType, TeamType]): """ # pylint: disable=too-many-public-methods - tips: List[Union[str, Dict[str, Any]]] = [] + # Tips to be presented to the user at the start of the game. + tips: List[Union[str, ba.GameTip]] = [] # Default getname() will return this if not None. name: Optional[str] = None @@ -82,16 +83,16 @@ class GameActivity(Activity[PlayerType, TeamType]): @classmethod def create_settings_ui( cls, - sessionclass: Type[ba.Session], + sessiontype: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None], ) -> None: """Launch an in-game UI to configure settings for a game type. - 'sessionclass' should be the ba.Session class the game will be used in. + 'sessiontype' should be the ba.Session class the game will be used in. - 'config' should be an existing config dict (specifies 'edit' ui mode) - or None (specifies 'add' ui mode). + 'settings' should be an existing settings dict (implies 'edit' + ui mode) or None (implies 'add' ui mode). 'completion_call' will be called with a filled-out settings dict on success or None on cancel. @@ -103,14 +104,14 @@ class GameActivity(Activity[PlayerType, TeamType]): """ delegate = _ba.app.delegate assert delegate is not None - delegate.create_default_game_settings_ui(cls, sessionclass, settings, + delegate.create_default_game_settings_ui(cls, sessiontype, settings, completion_call) @classmethod def getscoreconfig(cls) -> ba.ScoreConfig: """Return info about game scoring setup; can be overridden by games.""" - return cls.scoreconfig if cls.scoreconfig is not None else ScoreConfig( - ) + return (cls.scoreconfig + if cls.scoreconfig is not None else ScoreConfig()) @classmethod def getname(cls) -> str: @@ -170,62 +171,8 @@ class GameActivity(Activity[PlayerType, TeamType]): @classmethod def get_available_settings( cls, sessiontype: Type[ba.Session]) -> List[ba.Setting]: - """ - Called by the default ba.GameActivity.create_settings_ui() - implementation; should return a dict of config options to be presented - to the user for the given ba.Session type. - - The format for settings is a list of 2-member tuples consisting - of a name and a dict of options. - - Available Setting Options: - - 'default': This determines the default value as well as the - type (int, float, or bool) - - 'min_value': Minimum value for int/float settings. - - 'max_value': Maximum value for int/float settings. - - 'choices': A list of name/value pairs the user can choose from by name. - - 'increment': Value increment for int/float settings. - - # example get_available_settings() for a capture-the-flag game: - @classmethod - def get_available_settings(cls, sessiontype): - return [("Score to Win", { - 'default': 3, - 'min_value': 1 - }), - ("Flag Touch Return Time", { - 'default': 0, - 'min_value': 0, - 'increment': 1 - }), - ("Flag Idle Return Time", { - 'default': 30, - 'min_value': 5, - 'increment': 5 - }), - ("Time Limit", { - 'default': 0, - 'choices': [ - ('None', 0), ('1 Minute', 60), ('2 Minutes', 120), - ('5 Minutes', 300), ('10 Minutes', 600), - ('20 Minutes', 1200) - ] - }), - ("Respawn Times", { - 'default': 1.0, - 'choices': [ - ('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0), - ('Long', 2.0), ('Longer', 4.0) - ] - }), - ("Epic Mode", { - 'default': False - })] + """Return a list of settings relevant to this game type when + running under the provided session type. """ del sessiontype # Unused arg. return [] if cls.available_settings is None else cls.available_settings @@ -403,7 +350,6 @@ class GameActivity(Activity[PlayerType, TeamType]): return '' def on_transition_in(self) -> None: - super().on_transition_in() # Make our map. @@ -575,8 +521,9 @@ class GameActivity(Activity[PlayerType, TeamType]): victim_player=player, importance=importance, showpoints=self.show_kill_points) - return None - return super().handlemessage(msg) + else: + return super().handlemessage(msg) + return None def _show_scoreboard_info(self) -> None: """Create the game info display. @@ -599,7 +546,7 @@ class GameActivity(Activity[PlayerType, TeamType]): else: sb_desc_l = sb_desc_in if not isinstance(sb_desc_l[0], str): - raise TypeError('Invalid format for instance description') + raise TypeError('Invalid format for instance description.') is_empty = (sb_desc_l[0] == '') subs = [] @@ -608,9 +555,7 @@ class GameActivity(Activity[PlayerType, TeamType]): translation = Lstr(translate=('gameDescriptions', sb_desc_l[0]), subs=subs) sb_desc = translation - vrmode = _ba.app.vr_mode - yval = -34 if is_empty else -20 yval -= 16 sbpos = ((15, yval) if isinstance(self.session, FreeForAllSession) else @@ -727,7 +672,7 @@ class GameActivity(Activity[PlayerType, TeamType]): def _show_tip(self) -> None: # pylint: disable=too-many-locals - from ba._gameutils import animate + from ba._gameutils import animate, GameTip from ba._enums import SpecialChar # If there's any tips left on the list, display one. @@ -735,14 +680,12 @@ class GameActivity(Activity[PlayerType, TeamType]): tip = self.tips.pop(random.randrange(len(self.tips))) tip_title = Lstr(value='${A}:', subs=[('${A}', Lstr(resource='tipText'))]) - icon = None - sound = None - if isinstance(tip, dict): - if 'icon' in tip: - icon = tip['icon'] - if 'sound' in tip: - sound = tip['sound'] - tip = tip['tip'] + icon: Optional[ba.Texture] = None + sound: Optional[ba.Sound] = None + if isinstance(tip, GameTip): + icon = tip.icon + sound = tip.sound + tip = tip.text assert isinstance(tip, str) # Do a few substitutions. @@ -844,12 +787,11 @@ class GameActivity(Activity[PlayerType, TeamType]): super().end(results, delay, force) def end_game(self) -> None: - """ - Tells the game to wrap itself up and call ba.Activity.end() - immediately. This method should be overridden by subclasses. + """Tell the game to wrap up and call ba.Activity.end() immediately. - A game should always be prepared to end and deliver results, even if - there is no 'winner' yet; this way things like the standard time-limit + This method should be overridden by subclasses. A game should always + be prepared to end and deliver results, even if there is no 'winner' + yet; this way things like the standard time-limit (ba.GameActivity.setup_standard_time_limit()) will work with the game. """ print('WARNING: default end_game() implementation called;' diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 8b850f80..1ffa78a8 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -84,8 +84,7 @@ class GameResults: sessionteam = team.sessionteam self._scores[sessionteam.id] = (weakref.ref(sessionteam), score) - def get_team_score(self, - sessionteam: Union[ba.SessionTeam]) -> Optional[int]: + def get_team_score(self, sessionteam: ba.SessionTeam) -> Optional[int]: """Return the score for a given ba.SessionTeam.""" for score in list(self._scores.values()): if score[0]() is sessionteam: @@ -111,7 +110,7 @@ class GameResults: """Return whether there is a score for a given team.""" return any(s[0]() is sessionteam for s in self._scores.values()) - def get_team_score_str(self, team: ba.Team) -> ba.Lstr: + def get_team_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr: """Return the score for the given ba.Team as an Lstr. (properly formatted for the score type.) @@ -123,7 +122,7 @@ class GameResults: if not self._game_set: raise RuntimeError("Can't get team-score-str until game is set.") for score in list(self._scores.values()): - if score[0]() is team.sessionteam: + if score[0]() is sessionteam: if score[1] is None: return Lstr(value='-') if self._scoretype is ScoreType.SECONDS: diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 8c48ce76..7f4588fb 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -22,6 +22,7 @@ from __future__ import annotations +from dataclasses import dataclass from typing import TYPE_CHECKING import _ba @@ -42,6 +43,17 @@ TROPHY_CHARS = { } +@dataclass +class GameTip: + """Defines a tip presentable to the user at the start of a game. + + Category: Gameplay Classes + """ + text: str + icon: Optional[ba.Texture] = None + sound: Optional[ba.Sound] = None + + def get_trophy_string(trophy_id: str) -> str: """Given a trophy id, returns a string to visualize it.""" if trophy_id in TROPHY_CHARS: diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index bb1f3bb5..43eff04b 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -123,7 +123,7 @@ def json_prep(data: Any) -> Any: def utf8_all(data: Any) -> Any: - """Convert any unicode data in provided sequence(s)to utf8 bytes.""" + """Convert any unicode data in provided sequence(s) to utf8 bytes.""" if isinstance(data, dict): return dict((utf8_all(key), utf8_all(value)) for key, value in list(data.items())) diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 90bd4b1f..9daedc9d 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -224,7 +224,7 @@ class MultiTeamSession(Session): except NotFoundError: has_team = False if has_team: - self.stats.register_player(player) + self.stats.register_sessionplayer(player) self.stats.setactivity(next_game) # Now flip the current activity. diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index a07bc61d..6dbd6969 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -26,7 +26,8 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, TypeVar, Generic, cast import _ba -from ba._error import SessionPlayerNotFoundError, print_exception +from ba._error import (SessionPlayerNotFoundError, print_exception, + ActorNotFoundError) from ba._messages import DeathType, DieMessage if TYPE_CHECKING: @@ -219,11 +220,12 @@ class Player(Generic[TeamType]): def position(self) -> ba.Vec3: """The position of the player, as defined by its current ba.Actor. - This value is undefined when the player has no Actor. + If the player currently has no actor, raises a ba.ActorNotFoundError. """ assert self._postinited assert not self._expired - assert self.actor is not None + if self.actor is None: + raise ActorNotFoundError return _ba.Vec3(self.node.position) def exists(self) -> bool: diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 2025cc42..72c56101 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -84,6 +84,10 @@ class Session: Whether players should be allowed to join in the middle of activities. + customdata + A shared dictionary for objects to use as storage on this session. + Ensure that keys here are unique to avoid collisions. + """ use_teams: bool = False use_team_colors: bool = True @@ -95,6 +99,7 @@ class Session: max_players: int min_players: int players: List[ba.SessionPlayer] + customdata: dict teams: List[ba.SessionTeam] def __init__(self, @@ -166,6 +171,7 @@ class Session: self.min_players = min_players self.max_players = max_players + self.customdata = {} self._in_set_activity = False self._next_team_id = 0 self._activity_retained: Optional[ba.Activity] = None @@ -695,7 +701,7 @@ class Session: color=chooser.get_color(), highlight=chooser.get_highlight()) - self.stats.register_player(sessionplayer) + self.stats.register_sessionplayer(sessionplayer) if pass_to_activity: activity.add_player(sessionplayer) return sessionplayer diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index b92dc374..317e8c83 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -28,7 +28,7 @@ from dataclasses import dataclass import _ba from ba._error import (print_exception, print_error, SessionTeamNotFoundError, - SessionPlayerNotFoundError) + SessionPlayerNotFoundError, NotFoundError) if TYPE_CHECKING: import ba @@ -61,8 +61,8 @@ class PlayerRecord: """ character: str - def __init__(self, name: str, name_full: str, player: ba.SessionPlayer, - stats: ba.Stats): + def __init__(self, name: str, name_full: str, + sessionplayer: ba.SessionPlayer, stats: ba.Stats): self.name = name self.name_full = name_full self.score = 0 @@ -75,10 +75,10 @@ class PlayerRecord: self._multi_kill_count = 0 self._stats = weakref.ref(stats) self._last_sessionplayer: Optional[ba.SessionPlayer] = None - self._player: Optional[ba.SessionPlayer] = None - self._team: Optional[ReferenceType[ba.SessionTeam]] = None + self._sessionplayer: Optional[ba.SessionPlayer] = None + self._sessionteam: Optional[ReferenceType[ba.SessionTeam]] = None self.streak = 0 - self.associate_with_player(player) + self.associate_with_sessionplayer(sessionplayer) @property def team(self) -> ba.SessionTeam: @@ -87,8 +87,8 @@ class PlayerRecord: This can still return a valid result even if the player is gone. Raises a ba.SessionTeamNotFoundError if the team no longer exists. """ - assert self._team is not None - team = self._team() + assert self._sessionteam is not None + team = self._sessionteam() if team is None: raise SessionTeamNotFoundError() return team @@ -100,9 +100,9 @@ class PlayerRecord: Raises a ba.SessionPlayerNotFoundError if the player no longer exists. """ - if not self._player: + if not self._sessionplayer: raise SessionPlayerNotFoundError() - return self._player + return self._sessionplayer def getname(self, full: bool = False) -> str: """Return the player entry's name.""" @@ -127,19 +127,20 @@ class PlayerRecord: return stats.getactivity() return None - def associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None: + def associate_with_sessionplayer(self, + sessionplayer: ba.SessionPlayer) -> None: """Associate this entry with a ba.SessionPlayer.""" - self._team = weakref.ref(sessionplayer.sessionteam) + self._sessionteam = weakref.ref(sessionplayer.sessionteam) self.character = sessionplayer.character self._last_sessionplayer = sessionplayer - self._player = sessionplayer + self._sessionplayer = sessionplayer self.streak = 0 def _end_multi_kill(self) -> None: self._multi_kill_timer = None self._multi_kill_count = 0 - def get_last_player(self) -> ba.SessionPlayer: + def get_last_sessionplayer(self) -> ba.SessionPlayer: """Return the last ba.Player we were associated with.""" assert self._last_sessionplayer is not None return self._last_sessionplayer @@ -204,18 +205,20 @@ class PlayerRecord: # Only award this if they're still alive and we can get # a current position for them. - our_pos: Optional[Sequence[float]] = None - if self._player is not None: - if self._player.activityplayer is not None: - if self._player.activityplayer.node: - our_pos = self._player.activityplayer.node.position + our_pos: Optional[ba.Vec3] = None + if self._sessionplayer is not None: + if self._sessionplayer.activityplayer is not None: + try: + our_pos = self._sessionplayer.activityplayer.position + except NotFoundError: + pass if our_pos is None: return # Jitter position a bit since these often come in clusters. - our_pos = (our_pos[0] + (random.random() - 0.5) * 2.0, - our_pos[1] + (random.random() - 0.5) * 2.0, - our_pos[2] + (random.random() - 0.5) * 2.0) + our_pos = _ba.Vec3(our_pos[0] + (random.random() - 0.5) * 2.0, + our_pos[1] + (random.random() - 0.5) * 2.0, + our_pos[2] + (random.random() - 0.5) * 2.0) activity = self.getactivity() if activity is not None: PopupText(Lstr( @@ -305,14 +308,14 @@ class Stats: s_player.accum_killed_count = 0 s_player.streak = 0 - def register_player(self, player: ba.SessionPlayer) -> None: - """Register a player with this score-set.""" + def register_sessionplayer(self, player: ba.SessionPlayer) -> None: + """Register a ba.SessionPlayer with this score-set.""" assert player.exists() # Invalid refs should never be passed to funcs. name = player.getname() if name in self._player_records: # If the player already exists, update his character and such as # it may have changed. - self._player_records[name].associate_with_player(player) + self._player_records[name].associate_with_sessionplayer(player) else: name_full = player.getname(full=True) self._player_records[name] = PlayerRecord(name, name_full, player, @@ -325,7 +328,7 @@ class Stats: # Go through our player records and return ones whose player id still # corresponds to a player with that name. for record_id, record in self._player_records.items(): - lastplayer = record.get_last_player() + lastplayer = record.get_last_sessionplayer() if lastplayer and lastplayer.getname() == record_id: records[record_id] = record return records diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index c95266d1..68a4c3d8 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -97,7 +97,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): if is_free_for_all and results is not None: assert isinstance(results, ba.GameResults) assert p_rec.team.gameteam is not None - val = results.get_team_score_str(p_rec.team.gameteam) + val = results.get_team_score_str(p_rec.team) assert val is not None return val return str(p_rec.accumscore) diff --git a/assets/src/ba_data/python/bastd/appdelegate.py b/assets/src/ba_data/python/bastd/appdelegate.py index c3e19ee0..351a1984 100644 --- a/assets/src/ba_data/python/bastd/appdelegate.py +++ b/assets/src/ba_data/python/bastd/appdelegate.py @@ -34,7 +34,7 @@ class AppDelegate(ba.AppDelegate): def create_default_game_settings_ui( self, gameclass: Type[ba.GameActivity], - sessionclass: Type[ba.Session], config: Optional[dict], + sessiontype: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], Any]) -> None: """(internal)""" @@ -42,6 +42,6 @@ class AppDelegate(ba.AppDelegate): from bastd.ui.playlist.editgame import PlaylistEditGameWindow prev_window = ba.app.main_menu_window ba.app.main_menu_window = (PlaylistEditGameWindow( - gameclass, sessionclass, config, + gameclass, sessiontype, settings, completion_call=completion_call).get_root_widget()) ba.containerwidget(edit=prev_window, transition='out_left') diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 607ce182..cbb03d17 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -141,7 +141,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): name = 'Onslaught' description = 'Defeat all enemies.' - tips: List[Union[str, Dict[str, Any]]] = [ + tips: List[Union[str, ba.GameTip]] = [ 'Hold any button to run.' ' (Trigger buttons work well if you have them)', 'Try tricking enemies into killing eachother or running off cliffs.', @@ -213,43 +213,45 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def on_transition_in(self) -> None: super().on_transition_in() - session = ba.getsession() + customdata = ba.getsession().customdata # Show special landmine tip on rookie preset. if self._preset in {Preset.ROOKIE, Preset.ROOKIE_EASY}: # Show once per session only (then we revert to regular tips). - if not getattr(session, '_g_showed_onslaught_landmine_tip', False): - setattr(session, '_g_showed_onslaught_landmine_tip', True) - self.tips = [{ - 'tip': 'Land-mines are a good way' - ' to stop speedy enemies.', - 'icon': ba.gettexture('powerupLandMines'), - 'sound': ba.getsound('ding') - }] + if not customdata.get('_showed_onslaught_landmine_tip', False): + customdata['_showed_onslaught_landmine_tip'] = True + self.tips = [ + ba.GameTip( + 'Land-mines are a good way to stop speedy enemies.', + icon=ba.gettexture('powerupLandMines'), + sound=ba.getsound('ding')) + ] # Show special tnt tip on pro preset. if self._preset in {Preset.PRO, Preset.PRO_EASY}: # Show once per session only (then we revert to regular tips). - if not getattr(session, '_g_showed_onslaught_tnt_tip', False): - setattr(session, '_g_showed_onslaught_tnt_tip', True) - self.tips = [{ - 'tip': 'Take out a group of enemies by\n' - 'setting off a bomb near a TNT box.', - 'icon': ba.gettexture('tnt'), - 'sound': ba.getsound('ding') - }] + if not customdata.get('_showed_onslaught_tnt_tip', False): + customdata['_showed_onslaught_tnt_tip'] = True + self.tips = [ + ba.GameTip( + 'Take out a group of enemies by\n' + 'setting off a bomb near a TNT box.', + icon=ba.gettexture('tnt'), + sound=ba.getsound('ding')) + ] # Show special curse tip on uber preset. if self._preset in {Preset.UBER, Preset.UBER_EASY}: # Show once per session only (then we revert to regular tips). - if not getattr(session, '_g_showed_onslaught_curse_tip', False): - setattr(session, '_g_showed_onslaught_curse_tip', True) - self.tips = [{ - 'tip': 'Curse boxes turn you into a ticking time bomb.\n' - 'The only cure is to quickly grab a health-pack.', - 'icon': ba.gettexture('powerupCurse'), - 'sound': ba.getsound('ding') - }] + if not customdata.get('_showed_onslaught_curse_tip', False): + customdata['_showed_onslaught_curse_tip'] = True + self.tips = [ + ba.GameTip( + 'Curse boxes turn you into a ticking time bomb.\n' + 'The only cure is to quickly grab a health-pack.', + icon=ba.gettexture('powerupCurse'), + sound=ba.getsound('ding')) + ] self._spawn_info_text = ba.NodeActor( ba.newnode('text', diff --git a/docs/ba_module.md b/docs/ba_module.md index c3fadfde..662e9975 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-02 for Ballistica version 1.5.0 build 20043

    +

    last updated on 2020-06-03 for Ballistica version 1.5.0 build 20044

    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!


    @@ -21,6 +21,7 @@
  • ba.Chooser
  • ba.GameResults
  • +
  • ba.GameTip
  • ba.InputDevice
  • ba.Level
  • ba.Lobby
  • @@ -1100,7 +1101,7 @@ manually.

    Methods:

    create_default_game_settings_ui()

    -

    create_default_game_settings_ui(self, gameclass: Type[ba.GameActivity], sessionclass: Type[ba.Session], config: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None

    +

    create_default_game_settings_ui(self, gameclass: Type[ba.GameActivity], sessiontype: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None

    Launch a UI to configure the given game config.

    @@ -1733,7 +1734,7 @@ and it should begin its actual game logic.

    high score lists.

    Attributes Inherited:

    -
    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Attributes Defined Here:

    campaign, sessionglobalsnode
    @@ -2091,7 +2092,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    -
    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Attributes Defined Here:

    sessionglobalsnode

    @@ -2156,7 +2157,7 @@ its time with lingering corpses, sound effects, etc.

    ba.Vec3

    The position of the player, as defined by its current ba.Actor.

    -

    This value is undefined when the player has no Actor.

    +

    If the player currently has no actor, raises a ba.ActorNotFoundError.

    sessionplayer

    @@ -2272,7 +2273,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    -
    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Attributes Defined Here:

    sessionglobalsnode

    @@ -2407,14 +2408,14 @@ and calls either end_game or continue_game depending on the result

    create_settings_ui()

    <class method>
    -

    create_settings_ui(sessionclass: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None

    +

    create_settings_ui(sessiontype: Type[ba.Session], settings: Optional[dict], completion_call: Callable[[Optional[dict]], None]) -> None

    Launch an in-game UI to configure settings for a game type.

    -

    'sessionclass' should be the ba.Session class the game will be used in.

    +

    'sessiontype' should be the ba.Session class the game will be used in.

    -

    'config' should be an existing config dict (specifies 'edit' ui mode) - or None (specifies 'add' ui mode).

    +

    'settings' should be an existing settings dict (implies 'edit' + ui mode) or None (implies 'add' ui mode).

    'completion_call' will be called with a filled-out settings dict on success or None on cancel.

    @@ -2439,11 +2440,11 @@ will replace the old.

    end_game()

    end_game(self) -> None

    -

    Tells the game to wrap itself up and call ba.Activity.end() -immediately. This method should be overridden by subclasses.

    +

    Tell the game to wrap up and call ba.Activity.end() immediately.

    -

    A game should always be prepared to end and deliver results, even if -there is no 'winner' yet; this way things like the standard time-limit +

    This method should be overridden by subclasses. A game should always +be prepared to end and deliver results, even if there is no 'winner' +yet; this way things like the standard time-limit (ba.GameActivity.setup_standard_time_limit()) will work with the game.

    @@ -2451,61 +2452,8 @@ there is no 'winner' yet; this way things like the standard time-limit
    <class method>

    get_available_settings(sessiontype: Type[ba.Session]) -> List[ba.Setting]

    -

    Called by the default ba.GameActivity.create_settings_ui() -implementation; should return a dict of config options to be presented -to the user for the given ba.Session type.

    - -

    The format for settings is a list of 2-member tuples consisting -of a name and a dict of options.

    - -

    Available Setting Options:

    - -

    'default': This determines the default value as well as the - type (int, float, or bool)

    - -

    'min_value': Minimum value for int/float settings.

    - -

    'max_value': Maximum value for int/float settings.

    - -

    'choices': A list of name/value pairs the user can choose from by name.

    - -

    'increment': Value increment for int/float settings.

    - -
    # example get_available_settings() for a capture-the-flag game:
    -@classmethod
    -def get_available_settings(cls, sessiontype):
    -    return [("Score to Win", {
    -                'default': 3,
    -                'min_value': 1
    -            }),
    -            ("Flag Touch Return Time", {
    -                'default': 0,
    -                'min_value': 0,
    -                'increment': 1
    -            }),
    -            ("Flag Idle Return Time", {
    -                'default': 30,
    -                'min_value': 5,
    -                'increment': 5
    -            }),
    -            ("Time Limit", {
    -                'default': 0,
    -                'choices': [
    -                    ('None', 0), ('1 Minute', 60), ('2 Minutes', 120),
    -                    ('5 Minutes', 300), ('10 Minutes', 600),
    -                    ('20 Minutes', 1200)
    -                ]
    -            }),
    -            ("Respawn Times", {
    -                'default': 1.0,
    -                'choices': [
    -                    ('Shorter', 0.25), ('Short', 0.5), ('Normal', 1.0),
    -                    ('Long', 2.0), ('Longer', 4.0)
    -                ]
    -            }),
    -            ("Epic Mode", {
    -                'default': False
    -            })]
    +

    Return a list of settings relevant to this game type when +running under the provided session type.

    get_description()

    @@ -2821,13 +2769,13 @@ Results for a completed game.

    get_team_score()

    -

    get_team_score(self, sessionteam: Union[ba.SessionTeam]) -> Optional[int]

    +

    get_team_score(self, sessionteam: ba.SessionTeam) -> Optional[int]

    Return the score for a given ba.SessionTeam.

    get_team_score_str()

    -

    get_team_score_str(self, team: ba.Team) -> ba.Lstr

    +

    get_team_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr

    Return the score for the given ba.Team as an Lstr.

    @@ -2854,6 +2802,22 @@ Results for a completed game.

    This can be a number or None. (see the none_is_winner arg in the constructor)

    +
    +
    +
    +

    ba.GameTip

    +

    <top level class> +

    +

    Defines a tip presentable to the user at the start of a game.

    + +

    Category: Gameplay Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.GameTip(text: str, icon: Optional[ba.Texture] = None, sound: Optional[ba.Sound] = None)

    +

    @@ -3728,7 +3692,7 @@ Use ba.getmodel() to instantiate one.

    Attributes Inherited:

    -
    allow_mid_activity_joins, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams

    Attributes Defined Here:

    sessionglobalsnode

    @@ -4248,7 +4212,7 @@ even if myactor is set to None.

    ba.Vec3

    The position of the player, as defined by its current ba.Actor.

    -

    This value is undefined when the player has no Actor.

    +

    If the player currently has no actor, raises a ba.ActorNotFoundError.

    sessionplayer

    @@ -4446,14 +4410,14 @@ the type-checker properly identifies the returned value as one.

    Methods:

    -
    <constructor>, associate_with_player(), cancel_multi_kill_timer(), get_icon(), get_last_player(), getactivity(), getname(), submit_kill()
    +
    <constructor>, associate_with_sessionplayer(), cancel_multi_kill_timer(), get_icon(), get_last_sessionplayer(), getactivity(), getname(), submit_kill()

    <constructor>

    -

    ba.PlayerRecord(name: str, name_full: str, player: ba.SessionPlayer, stats: ba.Stats)

    +

    ba.PlayerRecord(name: str, name_full: str, sessionplayer: ba.SessionPlayer, stats: ba.Stats)

    -

    associate_with_player()

    -

    associate_with_player(self, sessionplayer: ba.SessionPlayer) -> None

    +

    associate_with_sessionplayer()

    +

    associate_with_sessionplayer(self, sessionplayer: ba.SessionPlayer) -> None

    Associate this entry with a ba.SessionPlayer.

    @@ -4470,8 +4434,8 @@ the type-checker properly identifies the returned value as one.

    Get the icon for this instance's player.

    -

    get_last_player()

    -

    get_last_player(self) -> ba.SessionPlayer

    +

    get_last_sessionplayer()

    +

    get_last_sessionplayer(self) -> ba.SessionPlayer

    Return the last ba.Player we were associated with.

    @@ -4700,13 +4664,19 @@ Pass 0 or a negative number for no ban time.

    maintaining state between them (players, teams, score tallies, etc).

    Attributes:

    -
    allow_mid_activity_joins, lobby, max_players, min_players, players, sessionglobalsnode, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, sessionglobalsnode, teams, use_team_colors, use_teams

    allow_mid_activity_joins

    bool

    Whether players should be allowed to join in the middle of activities.

    +
    +

    customdata

    +

    dict

    +

    A shared dictionary for objects to use as storage on this session. +Ensure that keys here are unique to avoid collisions.

    +

    lobby

    ba.Lobby

    @@ -5290,7 +5260,7 @@ of the session.

    Methods:

    -
    <constructor>, get_records(), getactivity(), player_scored(), player_was_killed(), register_player(), reset(), reset_accum(), setactivity()
    +
    <constructor>, get_records(), getactivity(), player_scored(), player_was_killed(), register_sessionplayer(), reset(), reset_accum(), setactivity()

    <constructor>

    ba.Stats()

    @@ -5324,10 +5294,10 @@ of the session.

    Should be called when a player is killed.

    -

    register_player()

    -

    register_player(self, player: ba.SessionPlayer) -> None

    +

    register_sessionplayer()

    +

    register_sessionplayer(self, player: ba.SessionPlayer) -> None

    -

    Register a player with this score-set.

    +

    Register a ba.SessionPlayer with this score-set.

    reset()

    From 58766a8f6e28a311ff3fa198b8605a04953d8731 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 3 Jun 2020 12:06:40 -0700 Subject: [PATCH 075/417] Tidying and language updates --- .efrocachemap | 32 +++--- assets/src/ba_data/python/ba/_achievement.py | 4 +- assets/src/ba_data/python/ba/_activity.py | 51 ++++----- .../src/ba_data/python/ba/_activitytypes.py | 37 +++---- assets/src/ba_data/python/ba/_analytics.py | 2 +- assets/src/ba_data/python/ba/_app.py | 11 +- assets/src/ba_data/python/ba/_campaign.py | 100 +++++++++--------- assets/src/ba_data/python/ba/_coopgame.py | 2 +- assets/src/ba_data/python/ba/_coopsession.py | 10 +- assets/src/ba_data/python/ba/_gameactivity.py | 2 +- assets/src/ba_data/python/ba/_level.py | 23 ++-- assets/src/ba_data/python/ba/internal.py | 2 +- .../ba_data/python/bastd/activity/coopjoin.py | 4 +- .../python/bastd/activity/coopscore.py | 16 +-- .../python/bastd/activity/multiteamvictory.py | 8 +- .../ba_data/python/bastd/game/ninjafight.py | 7 +- .../python/bastd/ui/account/settings.py | 12 +-- .../ba_data/python/bastd/ui/coop/browser.py | 22 ++-- .../python/bastd/ui/coop/gamebutton.py | 18 ++-- docs/ba_module.md | 63 +++++------ tools/batools/build.py | 2 +- 21 files changed, 202 insertions(+), 226 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index f420e66d..250ee99d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -423,7 +423,7 @@ "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/98/6d/e6de20b119fd6a5914982cd468b6", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/15/1b/3e0690b975c7cafbfa65e3aafad3", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/80/b2/b24a9a8395580ef2dea714abf478", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/aa/91/2411c0728bae33619c21237a2689", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f2/90/62968ad28a2499a8d182a5740a85", @@ -444,14 +444,14 @@ "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a9/bc/ea61ebd23066c685fb779e23d10f", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", - "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/78/5e/d24967ddaa15e0a574bd274544db", + "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/56/f4/b76f1e862b29db5f642a67da67f3", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/90/d9/0f8f5b03bbe2dfebfb544cee6bd6", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/b6/c9/999c95ff8d917126352a306d89a3", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/30/70/ba6f57b2d865d0027a50c6e1dba5", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/e0/f7/f6daa488dc29e303dea69aae864b", - "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/53/fe/b06f46dfeb31fb29d47a9546c01a", + "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/5f/a8/7d563fe99b8d1d1eb9bea49dc5df", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", "assets/build/ba_data/data/maps/courtyard.json": "https://files.ballistica.net/cache/ba1/03/38/344dd05bfef7bbdf464035ec5aa2", @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/7f/785a205dbe19ee4099f427dd9ca2", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/10/7ab16ca078a401bbbe2310660b85", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/f5/be729c0261c6326c3ef92330b764", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/98/9d/98bc183187af679fbc6531e3ac04", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/17/07/aed82d9bc9c5b4dd3457fcea9a8a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/71/5e/a837ebb98b829cd3bebf081e02b0", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/a0/3204f264abfd13f40f7f4f72aa65", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/68/ab/de21be17db5b93a7191c353dbce8", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/54/5a/e32b46e614ed37c7ebe42c73b03c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/09/2245bdaf317da30c7d63d8559c82", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f6/45/6972dd74de4fc822a28e995a4a0d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/34/74/e8ff832e808ceaa07a4015fb2a5f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/ca/9fa8a48f38554ef676a900136ce9", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e3/2c/f3e52a261f8dabced7a41d925053", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/82/1c63fa091da3fb52bcecf87f8ea6", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/18/a60e9e2f6e37e2f36ca8c8f4f42c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/96/6a/cc35319fd83bca6ff578e4c8dad6", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/a2/b04d489862ae208c6b2b31697519", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/ca/89e007ea20b4f2a3dee09e1361c3", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/cd/f8ad50715cb46d5cae7bd87bb498", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/d1/67a51def178a07f99acc3cc2b11c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/4a/a7a5b56eda157fde6e58a90ab98a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cc/ec/d82c9ba9d587598f8183bc360326", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/2a/f24b48e15ef4fd5794c5e426081b" } \ No newline at end of file diff --git a/assets/src/ba_data/python/ba/_achievement.py b/assets/src/ba_data/python/ba/_achievement.py index 44292c28..73165ba8 100644 --- a/assets/src/ba_data/python/ba/_achievement.py +++ b/assets/src/ba_data/python/ba/_achievement.py @@ -291,9 +291,9 @@ class Achievement: name: Union[ba.Lstr, str] try: if self._level_name != '': - from ba._campaign import get_campaign + from ba._campaign import getcampaign campaignname, campaign_level = self._level_name.split(':') - name = get_campaign(campaignname).get_level( + name = getcampaign(campaignname).getlevel( campaign_level).displayname else: name = '' diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 08795ab9..d439d6db 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -326,14 +326,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): returns False for the Actor. The ba.Actor.autoretain() method is a convenient way to access this same functionality. """ - from ba import _actor as bsactor - if not isinstance(actor, bsactor.Actor): - raise TypeError('non-actor passed to retain_actor') - - # Make sure our pruning is happening... - assert (not self.has_transitioned_in() - or _ba.time() - self._last_prune_dead_actors_time < 10.0) - + if __debug__: + from ba._actor import Actor + assert isinstance(actor, Actor) self._actor_refs.append(actor) def add_actor_weak_ref(self, actor: ba.Actor) -> None: @@ -341,14 +336,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): (called by the ba.Actor base class) """ - from ba import _actor as bsactor - if not isinstance(actor, bsactor.Actor): - raise TypeError('non-actor passed to add_actor_weak_ref') - - # Make sure our pruning is happening... - assert (not self.has_transitioned_in() - or _ba.time() - self._last_prune_dead_actors_time < 10.0) - + if __debug__: + from ba._actor import Actor + assert isinstance(actor, Actor) self._actor_weak_refs.append(weakref.ref(actor)) @property @@ -476,7 +466,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_transition_in() except Exception: - print_exception(f'Error in on_transition_in for {self}') + print_exception(f'Error in on_transition_in for {self}.') # Tell the C++ layer that this activity is the main one, so it uses # settings from our globals, directs various events to us, etc. @@ -490,7 +480,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_transition_out() except Exception: - print_exception('Error in on_transition_out for', self) + print_exception(f'Error in on_transition_out for {self}.') def begin(self, session: ba.Session) -> None: """Begin the activity. @@ -586,7 +576,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_player_join(player) except Exception: - print_exception('Error in on_player_join for', self) + print_exception(f'Error in on_player_join for {self}.') def remove_player(self, sessionplayer: ba.SessionPlayer) -> None: """Remove a player from the Activity while it is running. @@ -616,11 +606,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_player_leave(player) except Exception: - print_exception(f'Error in on_player_leave for {self}') + print_exception(f'Error in on_player_leave for {self}.') try: player.leave() except Exception: - print_exception(f'Error on leave for {player} in {self}') + print_exception(f'Error on leave for {player} in {self}.') self._reset_session_player_for_no_activity(sessionplayer) @@ -645,7 +635,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_team_join(team) except Exception: - print_exception(f'Error in on_team_join for {self}') + print_exception(f'Error in on_team_join for {self}.') def remove_team(self, sessionteam: ba.SessionTeam) -> None: """Remove a team from a Running Activity @@ -667,11 +657,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self.on_team_leave(team) except Exception: - print_exception(f'Error in on_team_leave for {self}') + print_exception(f'Error in on_team_leave for {self}.') try: team.leave() except Exception: - print_exception(f'Error on leave for {team} in {self}') + print_exception(f'Error on leave for {team} in {self}.') sessionteam.gameteam = None @@ -693,13 +683,13 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): except Exception: print_exception( f'Error resetting SessionPlayer node on {sessionplayer}' - f' for {self}') + f' for {self}.') try: sessionplayer.resetinput() except Exception: print_exception( f'Error resetting SessionPlayer input on {sessionplayer}' - f' for {self}') + f' for {self}.') # These should never fail I think... sessionplayer.setactivity(None) @@ -767,7 +757,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): _ba.quit() except Exception: - print_exception('exception on _check_activity_death:') + print_exception('Error on _check_activity_death/') def _expire(self) -> None: """Put the activity in a state where it can be garbage-collected. @@ -801,8 +791,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: self._activity_data.expire() except Exception: - print_exception( - 'Error during ba.Activity._expire() destroying data:') + print_exception(f'Error expiring _activity_data for {self}.') def _expire_actors(self) -> None: # Expire all Actors. @@ -843,7 +832,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # until now whos underlying SessionPlayer left long ago... pass except Exception: - print_exception(f'Error expiring {player}') + print_exception(f'Error expiring {player}.') def _expire_teams(self) -> None: @@ -873,7 +862,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): # player/team has left the game) pass except Exception: - print_exception(f'Error expiring Team {team}') + print_exception(f'Error expiring Team {team}.') def _prune_delay_deletes(self) -> None: self._delay_delete_players.clear() diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index 01e3fc55..d17d391a 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -103,21 +103,21 @@ class JoinActivity(Activity[EmptyPlayer, EmptyTeam]): class TransitionActivity(Activity[EmptyPlayer, EmptyTeam]): - """A simple overlay fade out/in. + """A simple overlay to fade out/in. Useful as a bare minimum transition between two level based activities. """ + # Keep prev activity alive while we fade in. + transition_time = 0.5 + inherits_slow_motion = True # Don't change. + inherits_tint = True # Don't change. + inherits_vr_camera_offset = True # Don't change. + inherits_vr_overlay_center = True + use_fixed_vr_overlay = True + def __init__(self, settings: dict): super().__init__(settings) - - # Keep prev activity alive while we fade in. - self.transition_time = 0.5 - self.inherits_slow_motion = True # Don't change. - self.inherits_tint = True # Don't change. - self.inherits_vr_camera_offset = True # Don't change. - self.inherits_vr_overlay_center = True - self.use_fixed_vr_overlay = True self._background: Optional[ba.Actor] = None def on_transition_in(self) -> None: @@ -141,13 +141,15 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): After a specified delay, player input is assigned to end the activity. """ + transition_time = 0.5 + inherits_tint = True + inherits_vr_camera_offset = True + use_fixed_vr_overlay = True + + default_music: Optional[MusicType] = MusicType.SCORES + def __init__(self, settings: dict): super().__init__(settings) - self.transition_time = 0.5 - self.inherits_tint = True - self.inherits_vr_camera_offset = True - self.use_fixed_vr_overlay = True - self.default_music: Optional[MusicType] = MusicType.SCORES self._birth_time = _ba.time() self._min_view_time = 5.0 self._allow_server_transition = False @@ -160,15 +162,14 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): self._server_transitioning: Optional[bool] = None def on_player_join(self, player: EmptyPlayer) -> None: - from ba import _general + from ba._general import WeakCall super().on_player_join(player) time_till_assign = max( 0, self._birth_time + self._min_view_time - _ba.time()) # If we're still kicking at the end of our assign-delay, assign this # guy's input to trigger us. - _ba.timer(time_till_assign, _general.WeakCall(self._safe_assign, - player)) + _ba.timer(time_till_assign, WeakCall(self._safe_assign, player)) def on_transition_in(self) -> None: from bastd.actor.tipstext import TipsText @@ -228,7 +229,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): def _safe_assign(self, player: EmptyPlayer) -> None: # Just to be extra careful, don't assign if we're transitioning out. - # (though theoretically that would be ok). + # (though theoretically that should be ok). if not self.is_transitioning_out() and player: player.assigninput((InputType.JUMP_PRESS, InputType.PUNCH_PRESS, InputType.BOMB_PRESS, InputType.PICK_UP_PRESS), diff --git a/assets/src/ba_data/python/ba/_analytics.py b/assets/src/ba_data/python/ba/_analytics.py index 8448c963..f01853fd 100644 --- a/assets/src/ba_data/python/ba/_analytics.py +++ b/assets/src/ba_data/python/ba/_analytics.py @@ -50,7 +50,7 @@ def game_begin_analytics() -> None: assert campaign is not None _ba.set_analytics_screen( 'Coop Game: ' + campaign.name + ' ' + - campaign.get_level(_ba.app.coop_session_args['level']).name) + campaign.getlevel(_ba.app.coop_session_args['level']).name) _ba.increment_analytics_count('Co-op round start') if len(activity.players) == 1: _ba.increment_analytics_count('Co-op round start 1 human player') diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 8847c13c..946a8908 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -724,26 +724,25 @@ class App: args: Dict = None) -> bool: """High level way to launch a local co-op session.""" # pylint: disable=cyclic-import - from ba._campaign import get_campaign + from ba._campaign import getcampaign from bastd.ui.coop.level import CoopLevelLockedWindow if args is None: args = {} if game == '': raise ValueError('empty game name') campaignname, levelname = game.split(':') - campaign = get_campaign(campaignname) - levels = campaign.get_levels() + campaign = getcampaign(campaignname) # If this campaign is sequential, make sure we've completed the # one before this. if campaign.sequential and not force: - for level in levels: + for level in campaign.levels: if level.name == levelname: break if not level.complete: CoopLevelLockedWindow( - campaign.get_level(levelname).displayname, - campaign.get_level(level.name).displayname) + campaign.getlevel(levelname).displayname, + campaign.getlevel(level.name).displayname) return False # Ok, we're good to go. diff --git a/assets/src/ba_data/python/ba/_campaign.py b/assets/src/ba_data/python/ba/_campaign.py index b7112972..6fd832e6 100644 --- a/assets/src/ba_data/python/ba/_campaign.py +++ b/assets/src/ba_data/python/ba/_campaign.py @@ -35,7 +35,7 @@ def register_campaign(campaign: ba.Campaign) -> None: _ba.app.campaigns[campaign.name] = campaign -def get_campaign(name: str) -> ba.Campaign: +def getcampaign(name: str) -> ba.Campaign: """Return a campaign by name.""" return _ba.app.campaigns[name] @@ -61,18 +61,19 @@ class Campaign: """Whether this Campaign's levels must be played in sequence.""" return self._sequential - def add_level(self, level: ba.Level) -> None: + def addlevel(self, level: ba.Level) -> None: """Adds a ba.Level to the Campaign.""" - if level.get_campaign() is not None: - raise RuntimeError('level already belongs to a campaign') + if level.campaign is not None: + raise RuntimeError('Level already belongs to a campaign.') level.set_campaign(self, len(self._levels)) self._levels.append(level) - def get_levels(self) -> List[ba.Level]: - """Return the set of ba.Levels in the Campaign.""" + @property + def levels(self) -> List[ba.Level]: + """The list of ba.Levels in the Campaign.""" return self._levels - def get_level(self, name: str) -> ba.Level: + def getlevel(self, name: str) -> ba.Level: """Return a contained ba.Level by name.""" from ba import _error for level in self._levels: @@ -89,14 +90,15 @@ class Campaign: # FIXME should these give/take ba.Level instances instead of level names?.. def set_selected_level(self, levelname: str) -> None: """Set the Level currently selected in the UI (by name).""" - self.get_config_dict()['Selection'] = levelname + self.configdict['Selection'] = levelname _ba.app.config.commit() def get_selected_level(self) -> str: """Return the name of the Level currently selected in the UI.""" - return self.get_config_dict().get('Selection', self._levels[0].name) + return self.configdict.get('Selection', self._levels[0].name) - def get_config_dict(self) -> Dict[str, Any]: + @property + def configdict(self) -> Dict[str, Any]: """Return the live config dict for this campaign.""" val: Dict[str, Any] = (_ba.app.config.setdefault('Campaigns', {}).setdefault( @@ -123,47 +125,47 @@ def init_campaigns() -> None: # FIXME: Once translations catch up, we can convert these to use the # generic display-name '${GAME} Training' type stuff. campaign = Campaign('Easy') - campaign.add_level( + campaign.addlevel( _level.Level('Onslaught Training', gametype=OnslaughtGame, settings={'preset': 'training_easy'}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Rookie Onslaught', gametype=OnslaughtGame, settings={'preset': 'rookie_easy'}, preview_texture_name='courtyardPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Rookie Football', gametype=FootballCoopGame, settings={'preset': 'rookie_easy'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Onslaught', gametype=OnslaughtGame, settings={'preset': 'pro_easy'}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Football', gametype=FootballCoopGame, settings={'preset': 'pro_easy'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Runaround', gametype=RunaroundGame, settings={'preset': 'pro_easy'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Onslaught', gametype=OnslaughtGame, settings={'preset': 'uber_easy'}, preview_texture_name='courtyardPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Football', gametype=FootballCoopGame, settings={'preset': 'uber_easy'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Runaround', gametype=RunaroundGame, settings={'preset': 'uber_easy'}, @@ -172,52 +174,52 @@ def init_campaigns() -> None: # "hard" mode campaign = Campaign('Default') - campaign.add_level( + campaign.addlevel( _level.Level('Onslaught Training', gametype=OnslaughtGame, settings={'preset': 'training'}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Rookie Onslaught', gametype=OnslaughtGame, settings={'preset': 'rookie'}, preview_texture_name='courtyardPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Rookie Football', gametype=FootballCoopGame, settings={'preset': 'rookie'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Onslaught', gametype=OnslaughtGame, settings={'preset': 'pro'}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Football', gametype=FootballCoopGame, settings={'preset': 'pro'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Runaround', gametype=RunaroundGame, settings={'preset': 'pro'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Onslaught', gametype=OnslaughtGame, settings={'preset': 'uber'}, preview_texture_name='courtyardPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Football', gametype=FootballCoopGame, settings={'preset': 'uber'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Runaround', gametype=RunaroundGame, settings={'preset': 'uber'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('The Last Stand', gametype=TheLastStandGame, settings={}, @@ -226,17 +228,17 @@ def init_campaigns() -> None: # challenges: our 'official' random extra co-op levels campaign = Campaign('Challenges', sequential=False) - campaign.add_level( + campaign.addlevel( _level.Level('Infinite Onslaught', gametype=OnslaughtGame, settings={'preset': 'endless'}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Infinite Runaround', gametype=RunaroundGame, settings={'preset': 'endless'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Race', displayname='${GAME}', gametype=RaceGame, @@ -246,7 +248,7 @@ def init_campaigns() -> None: 'Bomb Spawning': 0 }, preview_texture_name='bigGPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Race', displayname='Pro ${GAME}', gametype=RaceGame, @@ -256,7 +258,7 @@ def init_campaigns() -> None: 'Bomb Spawning': 1000 }, preview_texture_name='bigGPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Lake Frigid Race', displayname='${GAME}', gametype=RaceGame, @@ -267,55 +269,55 @@ def init_campaigns() -> None: 'Bomb Spawning': 0 }, preview_texture_name='lakeFrigidPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Football', displayname='${GAME}', gametype=FootballCoopGame, settings={'preset': 'tournament'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Football', displayname='Pro ${GAME}', gametype=FootballCoopGame, settings={'preset': 'tournament_pro'}, preview_texture_name='footballStadiumPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Runaround', displayname='${GAME}', gametype=RunaroundGame, settings={'preset': 'tournament'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Uber Runaround', displayname='Uber ${GAME}', gametype=RunaroundGame, settings={'preset': 'tournament_uber'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('The Last Stand', displayname='${GAME}', gametype=TheLastStandGame, settings={'preset': 'tournament'}, preview_texture_name='rampagePreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Tournament Infinite Onslaught', displayname='Infinite Onslaught', gametype=OnslaughtGame, settings={'preset': 'endless_tournament'}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Tournament Infinite Runaround', displayname='Infinite Runaround', gametype=RunaroundGame, settings={'preset': 'endless_tournament'}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Target Practice', displayname='Pro ${GAME}', gametype=TargetPracticeGame, settings={}, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Target Practice B', displayname='${GAME}', gametype=TargetPracticeGame, @@ -325,38 +327,38 @@ def init_campaigns() -> None: 'Enable Triple Bombs': False }, preview_texture_name='doomShroomPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Meteor Shower', displayname='${GAME}', gametype=MeteorShowerGame, settings={}, preview_texture_name='rampagePreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Epic Meteor Shower', displayname='${GAME}', gametype=MeteorShowerGame, settings={'Epic Mode': True}, preview_texture_name='rampagePreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Easter Egg Hunt', displayname='${GAME}', gametype=EasterEggHuntGame, settings={}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level('Pro Easter Egg Hunt', displayname='Pro ${GAME}', gametype=EasterEggHuntGame, settings={'Pro Mode': True}, preview_texture_name='towerDPreview')) - campaign.add_level( + campaign.addlevel( _level.Level( name='Ninja Fight', # (unique id not seen by player) displayname='${GAME}', # (readable name seen by player) gametype=NinjaFightGame, settings={'preset': 'regular'}, preview_texture_name='courtyardPreview')) - campaign.add_level( + campaign.addlevel( _level.Level(name='Pro Ninja Fight', displayname='Pro ${GAME}', gametype=NinjaFightGame, diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index 0895181d..4e169f81 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -74,7 +74,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): levelname = self._get_coop_level_name() campaign = self.session.campaign assert campaign is not None - config_str = (str(len(self.players)) + 'p' + campaign.get_level( + config_str = (str(len(self.players)) + 'p' + campaign.getlevel( self.settings_raw['name']).get_score_version_string().replace( ' ', '_')) _ba.get_scores_to_beat(levelname, config_str, diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 8f57b9b8..90da45f8 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -60,7 +60,7 @@ class CoopSession(Session): def __init__(self) -> None: """Instantiate a co-op mode session.""" # pylint: disable=cyclic-import - from ba._campaign import get_campaign + from ba._campaign import getcampaign from bastd.activity.coopjoin import CoopJoinActivity _ba.increment_analytics_count('Co-op session start') @@ -90,7 +90,7 @@ class CoopSession(Session): self.tournament_id: Optional[str] = ( app.coop_session_args.get('tournament_id')) - self.campaign = get_campaign(app.coop_session_args['campaign']) + self.campaign = getcampaign(app.coop_session_args['campaign']) self.campaign_level_name: str = app.coop_session_args['level'] self._ran_tutorial_activity = False @@ -116,7 +116,7 @@ class CoopSession(Session): # Build an instance for the current level. assert self.campaign is not None - level = self.campaign.get_level(self.campaign_level_name) + level = self.campaign.getlevel(self.campaign_level_name) gametype = level.gametype settings = level.get_settings() @@ -131,8 +131,8 @@ class CoopSession(Session): self._current_game_instance: GameActivity = newactivity # Find the next level and build an instance for it too. - levels = self.campaign.get_levels() - level = self.campaign.get_level(self.campaign_level_name) + levels = self.campaign.levels + level = self.campaign.getlevel(self.campaign_level_name) nextlevel: Optional[ba.Level] if level.index < len(levels) - 1: diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index c83e6ea6..b7e7cb77 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -290,7 +290,7 @@ class GameActivity(Activity[PlayerType, TeamType]): if isinstance(self.session, CoopSession): campaign = self.session.campaign assert campaign is not None - return campaign.get_level( + return campaign.getlevel( self.session.campaign_level_name).displayname except Exception: print_error('error getting campaign level name') diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py index ffe88bde..42afa83a 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -45,7 +45,6 @@ class Level: settings: dict, preview_texture_name: str, displayname: str = None): - """Initializes a Level object with the provided values.""" self._name = name self._gametype = gametype self._settings = settings @@ -93,8 +92,9 @@ class Level: """The type of game used for this Level.""" return self._gametype - def get_campaign(self) -> Optional[ba.Campaign]: - """Return the ba.Campaign this Level is associated with, or None.""" + @property + def campaign(self) -> Optional[ba.Campaign]: + """The ba.Campaign this Level is associated with, or None.""" return None if self._campaign is None else self._campaign() @property @@ -123,7 +123,7 @@ class Level: config = self._get_config_dict() config['Complete'] = val - def get_high_scores(self) -> Dict: + def get_high_scores(self) -> dict: """Return the current high scores for this Level.""" config = self._get_config_dict() high_scores_key = 'High Scores' + self.get_score_version_string() @@ -167,15 +167,14 @@ class Level: The referenced dict exists under the game's config dict and can be modified in place.""" - campaign = self.get_campaign() + campaign = self.campaign if campaign is None: - raise TypeError('level is not in a campaign') - campaign_config = campaign.get_config_dict() - val: Dict[str, - Any] = campaign_config.setdefault(self._name, { - 'Rating': 0.0, - 'Complete': False - }) + raise RuntimeError('Level is not in a campaign.') + configdict = campaign.configdict + val: Dict[str, Any] = configdict.setdefault(self._name, { + 'Rating': 0.0, + 'Complete': False + }) assert isinstance(val, dict) return val diff --git a/assets/src/ba_data/python/ba/internal.py b/assets/src/ba_data/python/ba/internal.py index 4a9f5386..a33bee87 100644 --- a/assets/src/ba_data/python/ba/internal.py +++ b/assets/src/ba_data/python/ba/internal.py @@ -48,7 +48,7 @@ from ba._apputils import (is_browser_likely_available, get_remote_app_name, should_submit_debug_info, show_ad, show_ad_2) from ba._benchmark import (run_gpu_benchmark, run_cpu_benchmark, run_media_reload_benchmark, run_stress_test) -from ba._campaign import get_campaign +from ba._campaign import getcampaign from ba._messages import PlayerProfilesChangedMessage from ba._meta import get_game_types from ba._modutils import show_user_scripts diff --git a/assets/src/ba_data/python/bastd/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py index 54bd831f..e1f06dd0 100644 --- a/assets/src/ba_data/python/bastd/activity/coopjoin.py +++ b/assets/src/ba_data/python/bastd/activity/coopjoin.py @@ -47,7 +47,7 @@ class CoopJoinActivity(JoinActivity): assert session.campaign is not None level_name_full = (session.campaign.name + ':' + session.campaign_level_name) - config_str = ('1p' + session.campaign.get_level( + config_str = ('1p' + session.campaign.getlevel( session.campaign_level_name).get_score_version_string().replace( ' ', '_')) _ba.get_scores_to_beat(level_name_full, config_str, @@ -59,7 +59,7 @@ class CoopJoinActivity(JoinActivity): super().on_transition_in() assert isinstance(self.session, ba.CoopSession) assert self.session.campaign - Text(self.session.campaign.get_level( + Text(self.session.campaign.getlevel( self.session.campaign_level_name).displayname, scale=1.3, h_attach=Text.HAttach.CENTER, diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index e3092882..9f05dd18 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -174,7 +174,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._game_name_str = self._campaign.name + ':' + self._level_name self._game_config_str = str(len( - self._playerinfos)) + 'p' + self._campaign.get_level( + self._playerinfos)) + 'p' + self._campaign.getlevel( self._level_name).get_score_version_string().replace(' ', '_') # If game-center/etc scores are available we show our friends' @@ -183,7 +183,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._game_name_str, self._game_config_str) try: - self._old_best_rank = self._campaign.get_level( + self._old_best_rank = self._campaign.getlevel( self._level_name).rating except Exception: self._old_best_rank = 0.0 @@ -522,8 +522,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._begin_time = ba.time() # Calc whether the level is complete and other stuff. - levels = self._campaign.get_levels() - level = self._campaign.get_level(self._level_name) + levels = self._campaign.levels + level = self._campaign.getlevel(self._level_name) self._was_complete = level.complete self._is_complete = (self._was_complete or self._victory) self._newly_complete = (self._is_complete and not self._was_complete) @@ -591,7 +591,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): pstr = ba.Lstr(value='- ${A} -', subs=[('${A}', ba.Lstr(resource='singlePlayerCountText'))]) - ZoomText(self._campaign.get_level(self._level_name).displayname, + ZoomText(self._campaign.getlevel(self._level_name).displayname, maxwidth=800, flash=False, trail=False, @@ -659,7 +659,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): ba.timer(0.4, ba.WeakCall(self._play_drumroll)) # Add us to high scores, filter, and store. - our_high_scores_all = self._campaign.get_level( + our_high_scores_all = self._campaign.getlevel( self._level_name).get_high_scores() try: our_high_scores = our_high_scores_all[str(len(self._playerinfos)) + @@ -691,7 +691,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): del our_high_scores[10:] if self._score is not None: - sver = (self._campaign.get_level( + sver = (self._campaign.getlevel( self._level_name).get_score_version_string()) _ba.add_transaction({ 'type': 'SET_LEVEL_LOCAL_HIGH_SCORES', @@ -1391,7 +1391,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): dostar(2, 10 - 30, -112, '7.5') dostar(3, 77 - 30, -112, '9.5') try: - best_rank = self._campaign.get_level(self._level_name).rating + best_rank = self._campaign.getlevel(self._level_name).rating except Exception: best_rank = 0.0 diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index ea2bd5ae..eec98f82 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -34,18 +34,16 @@ if TYPE_CHECKING: class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): """Final score screen for a team series.""" + # Dont' play music by default; (we do manually after a delay). + default_music = None + def __init__(self, settings: dict): super().__init__(settings=settings) self._min_view_time = 15.0 self._is_ffa = isinstance(self.session, ba.FreeForAllSession) self._allow_server_transition = True self._tips_text = None - - def on_transition_in(self) -> None: - # We don't yet want music and whatnot... - self.default_music = None self._default_show_tips = False - super().on_transition_in() def on_begin(self) -> None: # pylint: disable=too-many-branches diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index 1180dda6..be60ecc2 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -56,6 +56,7 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): scoreconfig = ba.ScoreConfig(label='Time', scoretype=ba.ScoreType.MILLISECONDS, lower_is_better=True) + default_music = ba.MusicType.TO_THE_DEATH @classmethod def get_supported_maps(cls, sessiontype: Type[ba.Session]) -> List[str]: @@ -79,12 +80,6 @@ class NinjaFightGame(ba.TeamGameActivity[Player, Team]): self._bots = SpazBotSet() self._preset = str(settings['preset']) - # Called when our game is transitioning in but not ready to begin; - # we can go ahead and start creating stuff, playing music, etc. - def on_transition_in(self) -> None: - self.default_music = ba.MusicType.TO_THE_DEATH - super().on_transition_in() - # Called when our game actually begins. def on_begin(self) -> None: super().on_begin() diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py index 48b63361..4ece4879 100644 --- a/assets/src/ba_data/python/bastd/ui/account/settings.py +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py @@ -968,13 +968,13 @@ class AccountSettingsWindow(ba.Window): ('${A}', accounts_str)])) def _refresh_campaign_progress_text(self) -> None: - from ba.internal import get_campaign + from ba.internal import getcampaign if self._campaign_progress_text is None: return p_str: Union[str, ba.Lstr] try: - campaign = get_campaign('Default') - levels = campaign.get_levels() + campaign = getcampaign('Default') + levels = campaign.levels levels_complete = sum((1 if l.complete else 0) for l in levels) # Last level cant be completed; hence the -1; @@ -1071,14 +1071,14 @@ class AccountSettingsWindow(ba.Window): def _reset_progress(self) -> None: try: - from ba.internal import get_campaign + from ba.internal import getcampaign # FIXME: This would need to happen server-side these days. if self._can_reset_achievements: ba.app.config['Achievements'] = {} _ba.reset_achievements() - campaign = get_campaign('Default') + campaign = getcampaign('Default') campaign.reset() # also writes the config.. - campaign = get_campaign('Challenges') + campaign = getcampaign('Challenges') campaign.reset() # also writes the config.. except Exception: ba.print_exception('exception resetting co-op campaign progress') diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 721f4c6d..396dead6 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -343,7 +343,7 @@ class CoopBrowserWindow(ba.Window): # pylint: disable=too-many-statements # pylint: disable=too-many-locals # pylint: disable=too-many-branches - from ba.internal import get_campaign, get_tournament_prize_strings + from ba.internal import getcampaign, get_tournament_prize_strings # If the number of tournaments or challenges in the data differs from # our current arrangement, refresh with the new number. @@ -466,20 +466,20 @@ class CoopBrowserWindow(ba.Window): opacity=0.2) else: campaignname, levelname = game.split(':') - campaign = get_campaign(campaignname) + campaign = getcampaign(campaignname) max_players = ba.app.tournament_info[ tbtn['tournament_id']]['maxPlayers'] txt = ba.Lstr( value='${A} ${B}', - subs=[('${A}', campaign.get_level(levelname).displayname), + subs=[('${A}', campaign.getlevel(levelname).displayname), ('${B}', ba.Lstr(resource='playerCountAbbreviatedText', subs=[('${COUNT}', str(max_players))]))]) ba.textwidget(edit=tbtn['button_text'], text=txt) - ba.imagewidget(edit=tbtn['image'], - texture=campaign.get_level( - levelname).get_preview_texture(), - opacity=1.0 if enabled else 0.5) + ba.imagewidget( + edit=tbtn['image'], + texture=campaign.getlevel(levelname).get_preview_texture(), + opacity=1.0 if enabled else 0.5) fee = entry['fee'] @@ -615,7 +615,7 @@ class CoopBrowserWindow(ba.Window): def _refresh_campaign_row(self) -> None: # pylint: disable=too-many-locals # pylint: disable=cyclic-import - from ba.internal import get_campaign + from ba.internal import getcampaign from bastd.ui.coop.gamebutton import GameButton parent_widget = self._campaign_sub_container @@ -716,8 +716,8 @@ class CoopBrowserWindow(ba.Window): down_widget=next_widget_down) # Update our existing percent-complete text. - campaign = get_campaign(campaignname) - levels = campaign.get_levels() + campaign = getcampaign(campaignname) + levels = campaign.levels levels_complete = sum((1 if l.complete else 0) for l in levels) # Last level cant be completed; hence the -1. @@ -936,7 +936,7 @@ class CoopBrowserWindow(ba.Window): # add all custom user levels here.. # items += [ # 'User:' + l.getname() - # for l in get_campaign('User').get_levels() + # for l in getcampaign('User').getlevels() # ] self._custom_h_scroll = custom_h_scroll = h_scroll = ba.hscrollwidget( diff --git a/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py index f7bd8b87..3f7683cb 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py +++ b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py @@ -40,7 +40,7 @@ class GameButton: x: float, y: float, select: bool, row: str): # pylint: disable=too-many-statements # pylint: disable=too-many-locals - from ba.internal import (get_achievements_for_coop_level, get_campaign) + from ba.internal import (get_achievements_for_coop_level, getcampaign) self._game = game sclx = 195.0 scly = 195.0 @@ -54,8 +54,8 @@ class GameButton: campaignname = 'Default' rating: Optional[float] - campaign = get_campaign(campaignname) - rating = campaign.get_level(levelname).rating + campaign = getcampaign(campaignname) + rating = campaign.getlevel(levelname).rating if game == 'Easy:The Last Stand': rating = None @@ -95,10 +95,10 @@ class GameButton: size=(image_width, image_width * 0.5), model_transparent=window.lsbt, model_opaque=window.lsbo, - texture=campaign.get_level(levelname).get_preview_texture(), + texture=campaign.getlevel(levelname).get_preview_texture(), mask_texture=ba.gettexture('mapPreviewMask')) - translated = campaign.get_level(levelname).displayname + translated = campaign.getlevel(levelname).displayname self._achievements = (get_achievements_for_coop_level(game)) self._name_widget = ba.textwidget(parent=parent, @@ -182,7 +182,7 @@ class GameButton: def _update(self) -> None: # pylint: disable=too-many-boolean-expressions - from ba.internal import have_pro, get_campaign + from ba.internal import have_pro, getcampaign game = self._game campaignname, levelname = game.split(':') @@ -192,15 +192,13 @@ class GameButton: if game == 'Easy:The Last Stand': campaignname = 'Default' - campaign = get_campaign(campaignname) - - levels = campaign.get_levels() + campaign = getcampaign(campaignname) # If this campaign is sequential, make sure we've unlocked # everything up to here. unlocked = True if campaign.sequential: - for level in levels: + for level in campaign.levels: if level.name == levelname: break if not level.complete: diff --git a/docs/ba_module.md b/docs/ba_module.md index 662e9975..ed4fc6dc 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-03 for Ballistica version 1.5.0 build 20044

    +

    last updated on 2020-06-03 for Ballistica version 1.5.0 build 20045

    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!


    @@ -1236,8 +1236,18 @@ mycall()

    Attributes:

    -
    name, sequential
    +
    configdict, levels, name, sequential
    +

    configdict

    +

    Dict[str, Any]

    +

    Return the live config dict for this campaign.

    + +
    +

    levels

    +

    List[ba.Level]

    +

    The list of ba.Levels in the Campaign.

    + +

    name

    str

    The name of the Campaign.

    @@ -1250,41 +1260,29 @@ mycall()

    Methods:

    -
    <constructor>, add_level(), get_config_dict(), get_level(), get_levels(), get_selected_level(), reset(), set_selected_level()
    +
    <constructor>, addlevel(), get_selected_level(), getlevel(), reset(), set_selected_level()

    <constructor>

    ba.Campaign(name: str, sequential: bool = True)

    -

    add_level()

    -

    add_level(self, level: ba.Level) -> None

    +

    addlevel()

    +

    addlevel(self, level: ba.Level) -> None

    Adds a ba.Level to the Campaign.

    -
    -

    get_config_dict()

    -

    get_config_dict(self) -> Dict[str, Any]

    - -

    Return the live config dict for this campaign.

    - -
    -

    get_level()

    -

    get_level(self, name: str) -> ba.Level

    - -

    Return a contained ba.Level by name.

    - -
    -

    get_levels()

    -

    get_levels(self) -> List[ba.Level]

    - -

    Return the set of ba.Levels in the Campaign.

    -

    get_selected_level()

    get_selected_level(self) -> str

    Return the name of the Level currently selected in the UI.

    +
    +

    getlevel()

    +

    getlevel(self, name: str) -> ba.Level

    + +

    Return a contained ba.Level by name.

    +

    reset()

    reset(self) -> None

    @@ -3051,8 +3049,13 @@ prefs, etc.

    Attributes:

    -
    complete, displayname, gametype, index, name, preview_texture_name, rating
    +
    campaign, complete, displayname, gametype, index, name, preview_texture_name, rating
    +

    campaign

    +

    Optional[ba.Campaign]

    +

    The ba.Campaign this Level is associated with, or None.

    + +

    complete

    bool

    Whether this Level has been completed.

    @@ -3093,22 +3096,14 @@ prefs, etc.

    Methods:

    -
    <constructor>, get_campaign(), get_high_scores(), get_preview_texture(), get_score_version_string(), get_settings(), set_complete(), set_high_scores(), set_rating()
    +
    <constructor>, get_high_scores(), get_preview_texture(), get_score_version_string(), get_settings(), set_complete(), set_high_scores(), set_rating()

    <constructor>

    ba.Level(name: str, gametype: Type[ba.GameActivity], settings: dict, preview_texture_name: str, displayname: str = None)

    -

    Initializes a Level object with the provided values.

    - -
    -

    get_campaign()

    -

    get_campaign(self) -> Optional[ba.Campaign]

    - -

    Return the ba.Campaign this Level is associated with, or None.

    -

    get_high_scores()

    -

    get_high_scores(self) -> Dict

    +

    get_high_scores(self) -> dict

    Return the current high scores for this Level.

    diff --git a/tools/batools/build.py b/tools/batools/build.py index 524b3043..f36b2e8c 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -47,7 +47,7 @@ class PipRequirement: PIP_REQUIREMENTS = [ PipRequirement(modulename='pylint', minversion=[2, 5, 2]), - PipRequirement(modulename='mypy', minversion=[0, 770]), + PipRequirement(modulename='mypy', minversion=[0, 780]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), PipRequirement(modulename='cpplint', minversion=[1, 5, 0]), PipRequirement(modulename='typing_extensions'), From 8fd97b1ee9ce345b120619eedc40614a6ab46465 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 3 Jun 2020 16:55:52 -0700 Subject: [PATCH 076/417] Tidying --- .idea/dictionaries/ericf.xml | 6 ++++++ tests/test_efro/test_dataclasses.py | 1 + tests/test_efro/test_entity.py | 3 +++ tools/efro/entity/_entity.py | 1 + tools/efro/util.py | 3 ++- tools/efrotools/pybuild.py | 13 ++++++++----- 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index ecf35539..635c0d21 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -41,6 +41,7 @@ adbcfaca adbpath addgame + addlevel addr addrstr adisp @@ -344,6 +345,7 @@ compounddict compoundlist conditionalize + configdict configerror confighash configkey @@ -619,6 +621,7 @@ fdict fecfc feedparser + ffaeff ffap fhash fhashes @@ -761,6 +764,7 @@ genutils getaccountid getactivity + getcampaign getclass getcollide getcollidemodel @@ -772,7 +776,9 @@ getdata getinputdevice getkillerplayer + getlevel getlevelname + getlevels getlog getmaps getmodel diff --git a/tests/test_efro/test_dataclasses.py b/tests/test_efro/test_dataclasses.py index f00c4aa9..470bf01b 100644 --- a/tests/test_efro/test_dataclasses.py +++ b/tests/test_efro/test_dataclasses.py @@ -159,6 +159,7 @@ def test_assign() -> None: dataclass_assign(tclass, {'lfval': [1]}) +# noinspection PyTypeHints def test_validate() -> None: """Testing validation.""" diff --git a/tests/test_efro/test_entity.py b/tests/test_efro/test_entity.py index 97354d92..063ab689 100644 --- a/tests/test_efro/test_entity.py +++ b/tests/test_efro/test_entity.py @@ -80,6 +80,7 @@ class EntityTest(entity.Entity): fval2 = entity.Field('f2', entity.Float3Value()) +# noinspection PyTypeHints def test_entity_values() -> None: """Test various entity assigns for value and type correctness.""" ent = EntityTest() @@ -133,6 +134,7 @@ def test_entity_values() -> None: assert dict(ent.str_int_dict.items()) == {'foo': 123} +# noinspection PyTypeHints def test_entity_values_2() -> None: """Test various entity assigns for value and type correctness.""" @@ -189,6 +191,7 @@ def test_entity_values_2() -> None: assert static_type_equals(ent.grp.compoundlist[0].subval, bool) +# noinspection PyTypeHints def test_field_copies() -> None: """Test copying various values between fields.""" ent1 = EntityTest() diff --git a/tools/efro/entity/_entity.py b/tools/efro/entity/_entity.py index 9f66ab10..144fec0f 100644 --- a/tools/efro/entity/_entity.py +++ b/tools/efro/entity/_entity.py @@ -121,6 +121,7 @@ class EntityMixin: self.d_data = target.d_data # Make sure target blows up if someone tries to use it. + # noinspection PyTypeHints target.d_data = None # type: ignore def pruned_data(self) -> Dict[str, Any]: diff --git a/tools/efro/util.py b/tools/efro/util.py index c7a2b69a..5ce9a3c3 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -53,6 +53,7 @@ def utc_now() -> datetime.datetime: return datetime.datetime.now(datetime.timezone.utc) +# noinspection PyUnresolvedReferences def empty_weakref(objtype: Type[T]) -> ReferenceType[T]: """Return an invalidated weak-reference for the specified type.""" # At runtime, all weakrefs are the same; our type arg is just @@ -99,7 +100,7 @@ class DispatchMethodWrapper(Generic[TARG, TRET]): registry: Dict[Any, Callable] -# noinspection PyProtectedMember +# noinspection PyProtectedMember,PyTypeHints def dispatchmethod( func: Callable[[Any, TARG], TRET]) -> DispatchMethodWrapper[TARG, TRET]: diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index 0bd301c6..f8bd65f8 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -47,8 +47,11 @@ def build_apple(arch: str, debug: bool = False) -> None: os.chdir(builddir) # TEMP: Check out a particular commit while the branch head is broken. - # efrotools.run('git checkout 1a9c71dca298c03517e8236b81cf1d9c8c521cbf') - efrotools.run(f'git checkout {PYTHON_VERSION_MAJOR}') + # We can actually fix this to use the current one, but something + # broke in the underlying build even on old commits so keeping it + # locked for now... + efrotools.run('git checkout bf1ed73d0d5ff46862ba69dd5eb2ffaeff6f19b6') + # efrotools.run(f'git checkout {PYTHON_VERSION_MAJOR}') # On mac we currently have to add the _scproxy module or urllib will # fail. @@ -152,7 +155,7 @@ def build_apple(arch: str, debug: bool = False) -> None: # Turn doc strings on; looks like it only adds a few hundred k. txt = txt.replace('--without-doc-strings', '--with-doc-strings') - # We're currently aiming at 10.13+ on mac + # Set mac/ios version reqs # (see issue with utimensat and futimens). txt = efrotools.replace_one(txt, 'MACOSX_DEPLOYMENT_TARGET=10.8', 'MACOSX_DEPLOYMENT_TARGET=10.13') @@ -178,7 +181,7 @@ def build_apple(arch: str, debug: bool = False) -> None: dline = 'python$(PYTHON_VER)m' splitlen = len(txt.split(dline)) if splitlen != 14: - raise Exception('unexpected configure lines') + raise RuntimeError(f'Unexpected configure line count {splitlen}.') txt = txt.replace(dline, 'python$(PYTHON_VER)dm') efrotools.writefile('Makefile', txt) @@ -282,7 +285,7 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: efrotools.writefile('pybuild/packages/python.py', ftxt) # Set this to a particular cpython commit to target exact releases from git - commit = '43364a7ae01fbe4288ef42622259a0038ce1edcc' # 3.7.6 release + commit = 'd7c567b08f9d7d6aef21b881340a2b72731129db' # 3.7.7 release if commit is not None: ftxt = efrotools.readfile('pybuild/source.py') From 690ca375afd09456c7933f8347909656f0714a13 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 3 Jun 2020 22:59:00 -0700 Subject: [PATCH 077/417] Updated python build setup for 3.7.7 and latest site-packges --- .efrocachemap | 104 ++++++++++++++++++------------------- tools/efrotools/pybuild.py | 30 +++++++---- 2 files changed, 73 insertions(+), 61 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 250ee99d..b4a793fe 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -2567,7 +2567,7 @@ "assets/build/pylib-android/_markupbase.py": "https://files.ballistica.net/cache/ba1/a5/5e/6ad43bfbcd054529b852fa9d9919", "assets/build/pylib-android/_osx_support.py": "https://files.ballistica.net/cache/ba1/61/30/ac3f83f7567392218242dc1bd371", "assets/build/pylib-android/_py_abc.py": "https://files.ballistica.net/cache/ba1/63/57/80933fee0979574b2d3b1172cdc8", - "assets/build/pylib-android/_pydecimal.py": "https://files.ballistica.net/cache/ba1/3f/40/99f6dc63cecd617696a3c6fb2804", + "assets/build/pylib-android/_pydecimal.py": "https://files.ballistica.net/cache/ba1/78/1c/999595e074c71574c01ff521a6e0", "assets/build/pylib-android/_pyio.py": "https://files.ballistica.net/cache/ba1/e6/8e/da9cef09b9375b297ccc45cbedf7", "assets/build/pylib-android/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/6d/7a/d76775d8f9d27c45135ca654dfd0", "assets/build/pylib-android/_strptime.py": "https://files.ballistica.net/cache/ba1/59/74/f1350b09c0bd4924be716707ba93", @@ -2580,7 +2580,7 @@ "assets/build/pylib-android/ast.py": "https://files.ballistica.net/cache/ba1/4d/98/0c14a8fb30313b4f4d9650772599", "assets/build/pylib-android/asynchat.py": "https://files.ballistica.net/cache/ba1/5e/b1/f69db224de08b5e119f5c0f425a8", "assets/build/pylib-android/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/6d/27/61dd597138eea19aaf7d724ee691", - "assets/build/pylib-android/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/d5/95/d7a6113215758f48a5d775fb9123", + "assets/build/pylib-android/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/93/62/5ee3d4885bf7d85654964fb065e3", "assets/build/pylib-android/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/a7/f3/869a086bf784ae308d02e15d3c0b", "assets/build/pylib-android/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/38/b3/a183c0e04a18def5f39acb4ef3b5", "assets/build/pylib-android/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/28/a0/90a971561cc54a06d1c683cc1562", @@ -2605,8 +2605,8 @@ "assets/build/pylib-android/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/3d/20/87bd62ba23f5d9f81421eb287041", "assets/build/pylib-android/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/2e/f9/7642257a860d664f7242efecb3f7", "assets/build/pylib-android/asyncore.py": "https://files.ballistica.net/cache/ba1/25/1f/ccae9e6cdd0885f9d989a3902e9b", - "assets/build/pylib-android/base64.py": "https://files.ballistica.net/cache/ba1/ba/b9/bb8f6861712922c4ee7bbb6a9ed2", - "assets/build/pylib-android/bdb.py": "https://files.ballistica.net/cache/ba1/02/b7/17d359fd061e74e62d54bfb996d2", + "assets/build/pylib-android/base64.py": "https://files.ballistica.net/cache/ba1/4f/23/c5419203b2ccd1ae27fd49d2cc56", + "assets/build/pylib-android/bdb.py": "https://files.ballistica.net/cache/ba1/f6/27/ce7dcdf436e9b9b4f9b87568794d", "assets/build/pylib-android/binhex.py": "https://files.ballistica.net/cache/ba1/54/6a/c80667fe1186c14eda368148b7c3", "assets/build/pylib-android/bisect.py": "https://files.ballistica.net/cache/ba1/67/2a/ac7f3e408cbfe1d697e44a420aac", "assets/build/pylib-android/bz2.py": "https://files.ballistica.net/cache/ba1/84/cb/27cdd0e9186f848fe949c2a3bee7", @@ -2616,13 +2616,13 @@ "assets/build/pylib-android/cgitb.py": "https://files.ballistica.net/cache/ba1/45/67/f3f215ae81b670ba05d94706a2ab", "assets/build/pylib-android/chunk.py": "https://files.ballistica.net/cache/ba1/f6/fe/3c43d1dc84ee74b8a170c61271a3", "assets/build/pylib-android/cmd.py": "https://files.ballistica.net/cache/ba1/f0/d9/8cec4bcbbfd195d46c3ad637df71", - "assets/build/pylib-android/code.py": "https://files.ballistica.net/cache/ba1/e6/ec/de81e7e500b6aae41292320f3f02", - "assets/build/pylib-android/codecs.py": "https://files.ballistica.net/cache/ba1/75/0f/e06af8024b16ae3d6ad6406a622f", + "assets/build/pylib-android/code.py": "https://files.ballistica.net/cache/ba1/7a/a4/ee660f11ad995354a3b21efbfb1c", + "assets/build/pylib-android/codecs.py": "https://files.ballistica.net/cache/ba1/ed/16/584061843712bbb77342ee17c423", "assets/build/pylib-android/codeop.py": "https://files.ballistica.net/cache/ba1/19/1a/47fd0ef5269e708ad2faf50db559", "assets/build/pylib-android/collections/__init__.py": "https://files.ballistica.net/cache/ba1/96/31/74bf91d70ac53f56c651ea0b1c6f", "assets/build/pylib-android/collections/abc.py": "https://files.ballistica.net/cache/ba1/29/45/a03469c0f5eb61d823b277d547ce", "assets/build/pylib-android/colorsys.py": "https://files.ballistica.net/cache/ba1/d6/3b/b932055a535b017694e91296168c", - "assets/build/pylib-android/compileall.py": "https://files.ballistica.net/cache/ba1/63/dc/6feca206d0f5885ac8a0573f6fd0", + "assets/build/pylib-android/compileall.py": "https://files.ballistica.net/cache/ba1/1e/8e/a36de40dc3e6cca8103c8d3e762c", "assets/build/pylib-android/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/37/3e/87f9ab4111608e0442bc82ff572f", "assets/build/pylib-android/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/32/bd/77be7db5fed1029c0363bccf4456", "assets/build/pylib-android/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/7f/16/02e7e8e860f0648dbd22db4daebd", @@ -2631,7 +2631,7 @@ "assets/build/pylib-android/configparser.py": "https://files.ballistica.net/cache/ba1/af/7d/8334b15bad238a5e38a3af40b4f4", "assets/build/pylib-android/contextlib.py": "https://files.ballistica.net/cache/ba1/fd/9e/5ec1f12da2b8bcee39dabc218650", "assets/build/pylib-android/contextvars.py": "https://files.ballistica.net/cache/ba1/ed/ff/2f1089520caf4910564799a71d33", - "assets/build/pylib-android/copy.py": "https://files.ballistica.net/cache/ba1/f8/af/4ea2911df9313c7a7a4f34d6c9eb", + "assets/build/pylib-android/copy.py": "https://files.ballistica.net/cache/ba1/f7/ba/bbbc0523aa05bf7dc78f2ef3812a", "assets/build/pylib-android/copyreg.py": "https://files.ballistica.net/cache/ba1/df/0f/5d29c5993a73e81bdc4f2b4b9fb6", "assets/build/pylib-android/crypt.py": "https://files.ballistica.net/cache/ba1/ae/e1/e2f82225c1a189679f80c95c4476", "assets/build/pylib-android/csv.py": "https://files.ballistica.net/cache/ba1/eb/b9/8acd5724cdb94c8fb446e87e85da", @@ -2654,7 +2654,7 @@ "assets/build/pylib-android/decimal.py": "https://files.ballistica.net/cache/ba1/92/94/b8be378718b3ede8f05f07aa257b", "assets/build/pylib-android/difflib.py": "https://files.ballistica.net/cache/ba1/6c/c2/0e781f8333593d5cb5890f702476", "assets/build/pylib-android/dis.py": "https://files.ballistica.net/cache/ba1/a1/d1/7ccecfaa71f7cd43ce504eb53194", - "assets/build/pylib-android/doctest.py": "https://files.ballistica.net/cache/ba1/c2/a0/8cda971687fd0e88982b557d4d47", + "assets/build/pylib-android/doctest.py": "https://files.ballistica.net/cache/ba1/5b/27/a20fbc6e0c46230b9d02d0e016a5", "assets/build/pylib-android/dummy_threading.py": "https://files.ballistica.net/cache/ba1/20/2f/ec8e68634908312148b53a5dfd4c", "assets/build/pylib-android/email/__init__.py": "https://files.ballistica.net/cache/ba1/2b/f0/8c85ab15e7cdbdaa0e1705223012", "assets/build/pylib-android/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/08/fa/de22bc96e1e332bbe1cf76162a1c", @@ -2788,7 +2788,7 @@ "assets/build/pylib-android/encodings/oem.py": "https://files.ballistica.net/cache/ba1/89/7c/80a3ecd4520886dc361cfc656f3c", "assets/build/pylib-android/encodings/palmos.py": "https://files.ballistica.net/cache/ba1/78/a9/9ef953f611452d621d44ac394e79", "assets/build/pylib-android/encodings/ptcp154.py": "https://files.ballistica.net/cache/ba1/1c/c2/03b9c034f875cb7ec719396258d0", - "assets/build/pylib-android/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/a0/c1/870e6bfb76eb8fd60b0e42a648a5", + "assets/build/pylib-android/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/5c/08/5f08b470b9dfeca97acb5e500fab", "assets/build/pylib-android/encodings/quopri_codec.py": "https://files.ballistica.net/cache/ba1/75/d7/28a861eed016c9c3054a32732575", "assets/build/pylib-android/encodings/raw_unicode_escape.py": "https://files.ballistica.net/cache/ba1/20/0b/657a7fc32f133a16ddbe91ef0011", "assets/build/pylib-android/encodings/rot_13.py": "https://files.ballistica.net/cache/ba1/38/24/555e226e476d804d5f79ca0e65b8", @@ -2815,7 +2815,7 @@ "assets/build/pylib-android/fileinput.py": "https://files.ballistica.net/cache/ba1/00/79/91b5218d122a5ede37fb0c821b22", "assets/build/pylib-android/fnmatch.py": "https://files.ballistica.net/cache/ba1/d5/44/0a58d9161ae9d2409ae2477b5948", "assets/build/pylib-android/formatter.py": "https://files.ballistica.net/cache/ba1/8d/5e/9b9d7451083fbae7ee678ad8f51e", - "assets/build/pylib-android/fractions.py": "https://files.ballistica.net/cache/ba1/53/37/cf10d9be60223979783bd58eed99", + "assets/build/pylib-android/fractions.py": "https://files.ballistica.net/cache/ba1/36/80/23d5c7f0ea189309e0b7e10fa86e", "assets/build/pylib-android/ftplib.py": "https://files.ballistica.net/cache/ba1/3b/4f/055a7aa1c640ee3163992f99a4ba", "assets/build/pylib-android/functools.py": "https://files.ballistica.net/cache/ba1/7c/3f/5c9e15f26ce747d1a37890e18640", "assets/build/pylib-android/genericpath.py": "https://files.ballistica.net/cache/ba1/0e/6a/8fc3f6769f820b90d5b6c43e49df", @@ -2823,7 +2823,7 @@ "assets/build/pylib-android/getpass.py": "https://files.ballistica.net/cache/ba1/76/37/f0df6882db44ee701aea35e235bb", "assets/build/pylib-android/gettext.py": "https://files.ballistica.net/cache/ba1/76/6b/e08db748cbde1d300c69c3a844d2", "assets/build/pylib-android/glob.py": "https://files.ballistica.net/cache/ba1/92/ce/6d2048bd82599fb386c8a439de58", - "assets/build/pylib-android/gzip.py": "https://files.ballistica.net/cache/ba1/92/ee/ebce7cc0a8c7a8c49e03603f5f84", + "assets/build/pylib-android/gzip.py": "https://files.ballistica.net/cache/ba1/83/fa/8e6c94112337bfb2b405d81328d2", "assets/build/pylib-android/hashlib.py": "https://files.ballistica.net/cache/ba1/c6/5a/91b854e2bae475daed521a56319b", "assets/build/pylib-android/heapq.py": "https://files.ballistica.net/cache/ba1/17/a3/02bee5cf92dbd2a1937056dbcb9c", "assets/build/pylib-android/hmac.py": "https://files.ballistica.net/cache/ba1/08/7a/a9980f4c7dd15295192da2ff8033", @@ -2844,7 +2844,7 @@ "assets/build/pylib-android/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/a1/8f/18e6ff954af6e29a2c06701e426d", "assets/build/pylib-android/importlib/resources.py": "https://files.ballistica.net/cache/ba1/6f/5f/01901b3cc59aa8e5e91e78bf62e9", "assets/build/pylib-android/importlib/util.py": "https://files.ballistica.net/cache/ba1/74/6c/cf680cfd666f5e08fc17e1e02e21", - "assets/build/pylib-android/inspect.py": "https://files.ballistica.net/cache/ba1/8f/95/52b0949ceed253c834f3d683a26c", + "assets/build/pylib-android/inspect.py": "https://files.ballistica.net/cache/ba1/91/29/9a58f7871ce7d9f87586d2e105ef", "assets/build/pylib-android/io.py": "https://files.ballistica.net/cache/ba1/fa/0b/9a8c9ecdd79242fe6c5dd40f3784", "assets/build/pylib-android/ipaddress.py": "https://files.ballistica.net/cache/ba1/1e/73/43ed03804d0553b409f9452d6a7e", "assets/build/pylib-android/json/__init__.py": "https://files.ballistica.net/cache/ba1/8a/76/868c50cd60069c48f130f3a95fb7", @@ -2855,8 +2855,8 @@ "assets/build/pylib-android/keyword.py": "https://files.ballistica.net/cache/ba1/1d/8a/1cdb5840e8f561ec69407f898752", "assets/build/pylib-android/linecache.py": "https://files.ballistica.net/cache/ba1/60/c9/68f020023d9b6d0e7f1f7d6d6b50", "assets/build/pylib-android/locale.py": "https://files.ballistica.net/cache/ba1/ab/cf/da9a211a39662f631b6869e1c28b", - "assets/build/pylib-android/logging/__init__.py": "https://files.ballistica.net/cache/ba1/19/75/05927c752840da64b42ac594e944", - "assets/build/pylib-android/logging/config.py": "https://files.ballistica.net/cache/ba1/e7/17/c42b6051d993ba8292cf4d1746ac", + "assets/build/pylib-android/logging/__init__.py": "https://files.ballistica.net/cache/ba1/0d/d3/3460e7bd9309e2e09cbbac2c2f66", + "assets/build/pylib-android/logging/config.py": "https://files.ballistica.net/cache/ba1/14/a0/a315016fa0d6d748d204acde0c8d", "assets/build/pylib-android/logging/handlers.py": "https://files.ballistica.net/cache/ba1/34/92/8a7b95239e1d0751e49fd01c2a21", "assets/build/pylib-android/lzma.py": "https://files.ballistica.net/cache/ba1/9c/2e/978f3aa52af60fce9a819dc7de7c", "assets/build/pylib-android/macpath.py": "https://files.ballistica.net/cache/ba1/5c/d5/64f70a6aefd047187ab55eb0a239", @@ -2865,14 +2865,14 @@ "assets/build/pylib-android/mimetypes.py": "https://files.ballistica.net/cache/ba1/19/08/5481aa7dca208be033099bbba366", "assets/build/pylib-android/modulefinder.py": "https://files.ballistica.net/cache/ba1/0c/30/5e90e7723ca80176807ea7e41a95", "assets/build/pylib-android/netrc.py": "https://files.ballistica.net/cache/ba1/8f/80/36bb48bf9d57e4e5d2840bbc39ed", - "assets/build/pylib-android/nntplib.py": "https://files.ballistica.net/cache/ba1/ef/5c/151088e70abae8056339e146b943", + "assets/build/pylib-android/nntplib.py": "https://files.ballistica.net/cache/ba1/68/3f/b1b40b66ab19e7674529236a75de", "assets/build/pylib-android/ntpath.py": "https://files.ballistica.net/cache/ba1/69/86/c1b59b30cc6c61143e054fe4539c", "assets/build/pylib-android/nturl2path.py": "https://files.ballistica.net/cache/ba1/b4/46/c374747761328b745d54c20fb2d4", "assets/build/pylib-android/numbers.py": "https://files.ballistica.net/cache/ba1/b3/ec/5cbca4da9a176673ac3502dfe3ce", "assets/build/pylib-android/opcode.py": "https://files.ballistica.net/cache/ba1/a2/30/da96e8dba5f6b098839e1adb2e86", "assets/build/pylib-android/operator.py": "https://files.ballistica.net/cache/ba1/03/ac/fc74fa2a3146b00f9ee1921996c5", "assets/build/pylib-android/optparse.py": "https://files.ballistica.net/cache/ba1/56/b4/9ae8b02341d9b2b5c1a75d5f8729", - "assets/build/pylib-android/os.py": "https://files.ballistica.net/cache/ba1/dc/1f/590aefc42b2767560874eebd21ca", + "assets/build/pylib-android/os.py": "https://files.ballistica.net/cache/ba1/d0/78/d8693c3a2c5c4684faadf46ebed5", "assets/build/pylib-android/pathlib.py": "https://files.ballistica.net/cache/ba1/f6/90/a68b8e0dffc669ae7aec2c95010c", "assets/build/pylib-android/pdb.py": "https://files.ballistica.net/cache/ba1/84/4f/9fc933776560b7e45cb7ef3bcfa9", "assets/build/pylib-android/pickle.py": "https://files.ballistica.net/cache/ba1/81/cf/a94f6e8a45671c34c1d9d4efdc13", @@ -2889,7 +2889,7 @@ "assets/build/pylib-android/pty.py": "https://files.ballistica.net/cache/ba1/96/53/727538ed8a1ed56729d6732f4930", "assets/build/pylib-android/py_compile.py": "https://files.ballistica.net/cache/ba1/d3/c0/4464545ef3eb1a6d29ab57099b13", "assets/build/pylib-android/pyclbr.py": "https://files.ballistica.net/cache/ba1/ca/2d/70c81bfd320a52431b6e941198db", - "assets/build/pylib-android/pydoc.py": "https://files.ballistica.net/cache/ba1/9a/10/3c865fb4550ae8be364729806f6d", + "assets/build/pylib-android/pydoc.py": "https://files.ballistica.net/cache/ba1/15/f7/67affd41a830edfa22d087b213dd", "assets/build/pylib-android/queue.py": "https://files.ballistica.net/cache/ba1/8c/f8/37f30b7f7500462869580f7eb14c", "assets/build/pylib-android/quopri.py": "https://files.ballistica.net/cache/ba1/f3/08/1d7b3e0f7ce1ad649b1abf08f8ac", "assets/build/pylib-android/random.py": "https://files.ballistica.net/cache/ba1/f3/8e/b752b23583b23a38bb15cb176522", @@ -2922,13 +2922,13 @@ "assets/build/pylib-android/string.py": "https://files.ballistica.net/cache/ba1/b3/a4/ac5ce6361b4e350127bed3d9b66b", "assets/build/pylib-android/stringprep.py": "https://files.ballistica.net/cache/ba1/20/41/fcfc5f510286ead5f7f4678ac9ec", "assets/build/pylib-android/struct.py": "https://files.ballistica.net/cache/ba1/37/67/74dea8e8f3831e802c3b5288e901", - "assets/build/pylib-android/subprocess.py": "https://files.ballistica.net/cache/ba1/a0/56/4fa028b39079ffceaef1a683f2ff", + "assets/build/pylib-android/subprocess.py": "https://files.ballistica.net/cache/ba1/f6/bf/640ac9ceb0e3d7cfbe02bef64557", "assets/build/pylib-android/sunau.py": "https://files.ballistica.net/cache/ba1/ff/0e/1a6c5fd41803511cad28595dc248", "assets/build/pylib-android/symbol.py": "https://files.ballistica.net/cache/ba1/a5/26/eea6d483c82e7b4048937832889d", "assets/build/pylib-android/symtable.py": "https://files.ballistica.net/cache/ba1/46/92/4be884871052300c5e7b9a11164b", "assets/build/pylib-android/sysconfig.py": "https://files.ballistica.net/cache/ba1/9b/d7/6b01292e81749e4d3fd2bf762f7f", "assets/build/pylib-android/tabnanny.py": "https://files.ballistica.net/cache/ba1/f3/7e/b463d5f4ead23d34a36d0e559447", - "assets/build/pylib-android/tarfile.py": "https://files.ballistica.net/cache/ba1/ae/f0/6c4f055f0967dabbdd06d7566eac", + "assets/build/pylib-android/tarfile.py": "https://files.ballistica.net/cache/ba1/46/a6/9d1a46c06d7b5e787efbfeadec05", "assets/build/pylib-android/telnetlib.py": "https://files.ballistica.net/cache/ba1/60/28/4aab22dece4896a4d32694bbe282", "assets/build/pylib-android/tempfile.py": "https://files.ballistica.net/cache/ba1/69/88/1a506e6ee4ff144b2aecd4e98ad2", "assets/build/pylib-android/textwrap.py": "https://files.ballistica.net/cache/ba1/4c/4b/c743c5e7427b00f428c318a9673b", @@ -2937,24 +2937,24 @@ "assets/build/pylib-android/timeit.py": "https://files.ballistica.net/cache/ba1/b3/b7/a2c93ac110fde00eebcb74a7ced1", "assets/build/pylib-android/token.py": "https://files.ballistica.net/cache/ba1/2d/f8/943c252465b687a5bc367315432f", "assets/build/pylib-android/tokenize.py": "https://files.ballistica.net/cache/ba1/07/cc/13a7ec5c4d674ab025cb19186f7c", - "assets/build/pylib-android/trace.py": "https://files.ballistica.net/cache/ba1/66/df/150eca452f2b75d80a915656ceb1", + "assets/build/pylib-android/trace.py": "https://files.ballistica.net/cache/ba1/9b/9d/d6806d339c36bfc6a2b4769688e0", "assets/build/pylib-android/traceback.py": "https://files.ballistica.net/cache/ba1/8b/67/e189e176678255fe36a67f9cfe71", "assets/build/pylib-android/tracemalloc.py": "https://files.ballistica.net/cache/ba1/46/49/5683d0d9e0e342392361adb6e9a3", "assets/build/pylib-android/tty.py": "https://files.ballistica.net/cache/ba1/ad/19/a6ad29b8958fa9f5acc3cf71d3b2", "assets/build/pylib-android/types.py": "https://files.ballistica.net/cache/ba1/b9/5d/5467b37ac0f36b2ff4dd8ef458fd", - "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/70/c4/6cbac5be937c037fcc4a26d2e4b1", + "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/bf/f6/998b69740a766155dee2eabdf859", "assets/build/pylib-android/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/b0/56/87601ed47a5181d1e6a40eb4ea40", "assets/build/pylib-android/urllib/error.py": "https://files.ballistica.net/cache/ba1/07/8c/573897fc3bdc6d3e2e8d449f17c7", - "assets/build/pylib-android/urllib/parse.py": "https://files.ballistica.net/cache/ba1/79/d2/5d0e60d8d55efe5d786cdc13934d", - "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/6f/71/7040b124f0939959054c494c864c", + "assets/build/pylib-android/urllib/parse.py": "https://files.ballistica.net/cache/ba1/14/09/ffed6f45250b0b2dc1a86f3eb700", + "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/fd/2c/abd2d31e790eb1bf4c6e19eacfd8", "assets/build/pylib-android/urllib/response.py": "https://files.ballistica.net/cache/ba1/c4/d5/676a8e9fc4f7bd21ac2f555fc3fc", "assets/build/pylib-android/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/c7/a8/487a1aeccfbf4370fdb33b136b51", "assets/build/pylib-android/uu.py": "https://files.ballistica.net/cache/ba1/a1/89/070ed8553858a75fcafae4b7bd37", "assets/build/pylib-android/uuid.py": "https://files.ballistica.net/cache/ba1/6e/d5/cf315a28420c9f6bd5a95acd116d", - "assets/build/pylib-android/warnings.py": "https://files.ballistica.net/cache/ba1/8c/4a/f5bf646482975256f504c6543192", + "assets/build/pylib-android/warnings.py": "https://files.ballistica.net/cache/ba1/74/1f/097efcf5f38c0b41fcba3f60b44d", "assets/build/pylib-android/wave.py": "https://files.ballistica.net/cache/ba1/f8/72/9e060ca777991ea45d71eed336ca", "assets/build/pylib-android/weakref.py": "https://files.ballistica.net/cache/ba1/d2/48/f82fb97686199616e57417ee9e7a", - "assets/build/pylib-android/webbrowser.py": "https://files.ballistica.net/cache/ba1/0b/6d/0f525ade5e00c82e252347350d0d", + "assets/build/pylib-android/webbrowser.py": "https://files.ballistica.net/cache/ba1/c4/03/bd37d4bb045d5c20b78c518574fe", "assets/build/pylib-android/xdrlib.py": "https://files.ballistica.net/cache/ba1/ec/bf/84d830dca1231ec1a67d8ccbb21f", "assets/build/pylib-android/xml/__init__.py": "https://files.ballistica.net/cache/ba1/ba/67/bbd97e53f3db5ebc3abd3fef2275", "assets/build/pylib-android/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/36/76/2a47e7bc727db1c44d157b23d2c3", @@ -2993,7 +2993,7 @@ "assets/build/pylib-apple/_markupbase.py": "https://files.ballistica.net/cache/ba1/06/64/d7715998bc60bfd5235f96b1a779", "assets/build/pylib-apple/_osx_support.py": "https://files.ballistica.net/cache/ba1/0d/a6/91bbc7f4ec229327c92ab11b096d", "assets/build/pylib-apple/_py_abc.py": "https://files.ballistica.net/cache/ba1/1c/5c/a9fd7d6a37d72eacde407a919fd2", - "assets/build/pylib-apple/_pydecimal.py": "https://files.ballistica.net/cache/ba1/3e/7f/2bb850aa1eadc23656adf8fb4fbf", + "assets/build/pylib-apple/_pydecimal.py": "https://files.ballistica.net/cache/ba1/d9/61/6db82a7db9a9802eeb7186194014", "assets/build/pylib-apple/_pyio.py": "https://files.ballistica.net/cache/ba1/eb/50/29e2234098f0db705aad0f1d2ce5", "assets/build/pylib-apple/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/3b/91/55e882376c694fefc106067d0b3b", "assets/build/pylib-apple/_strptime.py": "https://files.ballistica.net/cache/ba1/d3/f5/e8851ba114168136272f4c5d142e", @@ -3006,7 +3006,7 @@ "assets/build/pylib-apple/ast.py": "https://files.ballistica.net/cache/ba1/60/dd/6fd420ffc9156f54fb4fc5f7b753", "assets/build/pylib-apple/asynchat.py": "https://files.ballistica.net/cache/ba1/af/53/8002843655550b707f97b0aef513", "assets/build/pylib-apple/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/67/54/3680c6d920cad0475d3f75f44688", - "assets/build/pylib-apple/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/f0/53/9c53a7f4251a321eebcf44e64578", + "assets/build/pylib-apple/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/3d/0b/e197b883f420b0f8f9ae89d68505", "assets/build/pylib-apple/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/1f/5e/13cd4e323a6a7468c048a0279d84", "assets/build/pylib-apple/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/21/8d/9cbca0cea8e700d27a09d120fcc1", "assets/build/pylib-apple/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/3a/dc/1214dddea378aa08daffdb7e786b", @@ -3031,8 +3031,8 @@ "assets/build/pylib-apple/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/47/6d/08eb442641ad579db371699d8247", "assets/build/pylib-apple/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/87/0a/f0cc4e03e7c3b8fb1b50fe6699fe", "assets/build/pylib-apple/asyncore.py": "https://files.ballistica.net/cache/ba1/2b/72/df815a3b340e40f3f1cac9e54f7c", - "assets/build/pylib-apple/base64.py": "https://files.ballistica.net/cache/ba1/53/54/290a4616d369c2c7302b294b3fa9", - "assets/build/pylib-apple/bdb.py": "https://files.ballistica.net/cache/ba1/d6/f3/69b2555c4a9e5c47e3541059b897", + "assets/build/pylib-apple/base64.py": "https://files.ballistica.net/cache/ba1/fc/aa/394cb22a0c927c575758eacd5d3c", + "assets/build/pylib-apple/bdb.py": "https://files.ballistica.net/cache/ba1/3f/5f/710f2f84bfda88f21b25ad5084f0", "assets/build/pylib-apple/binhex.py": "https://files.ballistica.net/cache/ba1/8a/1b/9e5f7d1c262ecbed4f2f1a127564", "assets/build/pylib-apple/bisect.py": "https://files.ballistica.net/cache/ba1/65/8d/7ee4b83ef17c4e12dbee3de0ed78", "assets/build/pylib-apple/bz2.py": "https://files.ballistica.net/cache/ba1/e2/fb/aebb1af1f3c9772be84d9907fefa", @@ -3042,13 +3042,13 @@ "assets/build/pylib-apple/cgitb.py": "https://files.ballistica.net/cache/ba1/2d/55/8d7d0ed1a9fce5117c8404567af9", "assets/build/pylib-apple/chunk.py": "https://files.ballistica.net/cache/ba1/e0/4d/8609a028d890841ff867e97f0869", "assets/build/pylib-apple/cmd.py": "https://files.ballistica.net/cache/ba1/33/25/43fd9394378dd3db266dd35af46e", - "assets/build/pylib-apple/code.py": "https://files.ballistica.net/cache/ba1/20/45/546d47fe7d97dea6e9913763b620", - "assets/build/pylib-apple/codecs.py": "https://files.ballistica.net/cache/ba1/19/1d/22a9ce945677366fbd99db8d84e2", + "assets/build/pylib-apple/code.py": "https://files.ballistica.net/cache/ba1/18/fc/d667016222e466707ec5d0991810", + "assets/build/pylib-apple/codecs.py": "https://files.ballistica.net/cache/ba1/59/5e/1db8ca057d9140fc441eddbba66a", "assets/build/pylib-apple/codeop.py": "https://files.ballistica.net/cache/ba1/53/e6/d9b2676f59dad4386c740ce4b551", "assets/build/pylib-apple/collections/__init__.py": "https://files.ballistica.net/cache/ba1/e9/19/524a6966561435000ebf610762b4", "assets/build/pylib-apple/collections/abc.py": "https://files.ballistica.net/cache/ba1/78/dd/38815f6fb41c45822afef8fb1b71", "assets/build/pylib-apple/colorsys.py": "https://files.ballistica.net/cache/ba1/ae/99/594631454b09ad4d5c34ec54a344", - "assets/build/pylib-apple/compileall.py": "https://files.ballistica.net/cache/ba1/d1/2c/f08c9cc11d79e1cfae3d347396d7", + "assets/build/pylib-apple/compileall.py": "https://files.ballistica.net/cache/ba1/03/97/c2f9709dc47ca3b1cba99aba338a", "assets/build/pylib-apple/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/f8/0b/346441ef94908fb806338d0510b6", "assets/build/pylib-apple/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/6e/57/3bbd8b7b6f315e106ad0d5653e38", "assets/build/pylib-apple/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/fe/10/4e0ed0d4f044863838e2980b7ab0", @@ -3057,7 +3057,7 @@ "assets/build/pylib-apple/configparser.py": "https://files.ballistica.net/cache/ba1/ad/48/0318a7ab517f1f3240e77ac0bdc5", "assets/build/pylib-apple/contextlib.py": "https://files.ballistica.net/cache/ba1/11/ad/4518abe76a5e3ab825d158f01172", "assets/build/pylib-apple/contextvars.py": "https://files.ballistica.net/cache/ba1/02/52/e520b59b10124c813468252fee2a", - "assets/build/pylib-apple/copy.py": "https://files.ballistica.net/cache/ba1/f6/46/146e39a5c6ad47cee4019027d60b", + "assets/build/pylib-apple/copy.py": "https://files.ballistica.net/cache/ba1/84/d0/d769d275a0fa46184eee8c534bc8", "assets/build/pylib-apple/copyreg.py": "https://files.ballistica.net/cache/ba1/a3/31/65d0b18e801caa2bef11d6ac93b4", "assets/build/pylib-apple/crypt.py": "https://files.ballistica.net/cache/ba1/54/c9/5286313c50d32918803c57359099", "assets/build/pylib-apple/csv.py": "https://files.ballistica.net/cache/ba1/9a/6f/e4a900981552c661cf8f1ce3a5ad", @@ -3080,7 +3080,7 @@ "assets/build/pylib-apple/decimal.py": "https://files.ballistica.net/cache/ba1/dd/5d/8d0f90ec4e20c613b6ce2a88bc60", "assets/build/pylib-apple/difflib.py": "https://files.ballistica.net/cache/ba1/81/ae/5c878b083eddc6db9624fe75c96a", "assets/build/pylib-apple/dis.py": "https://files.ballistica.net/cache/ba1/77/ac/6444908dfe3e74dd1041b41d2934", - "assets/build/pylib-apple/doctest.py": "https://files.ballistica.net/cache/ba1/61/33/15b14b81d37827fa9a64a97fca65", + "assets/build/pylib-apple/doctest.py": "https://files.ballistica.net/cache/ba1/9d/79/f582a06f080421d6ac02ad15909c", "assets/build/pylib-apple/dummy_threading.py": "https://files.ballistica.net/cache/ba1/5b/60/6a2a69960c1c982fa667f3fd8051", "assets/build/pylib-apple/email/__init__.py": "https://files.ballistica.net/cache/ba1/2f/8e/c14225900357ac302213f5b4d674", "assets/build/pylib-apple/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/c6/3d/d686aa9a7ddbee790ad558b25661", @@ -3214,7 +3214,7 @@ "assets/build/pylib-apple/encodings/oem.py": "https://files.ballistica.net/cache/ba1/95/72/044008306f724b5b7ed437b33345", "assets/build/pylib-apple/encodings/palmos.py": "https://files.ballistica.net/cache/ba1/6a/11/ea725dae02d1d9efe32deeddfa6f", "assets/build/pylib-apple/encodings/ptcp154.py": "https://files.ballistica.net/cache/ba1/64/3f/a54d9272029e4ea2c2c334eefe5e", - "assets/build/pylib-apple/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/98/d3/9989cfbc3a09b98b420a91bb0012", + "assets/build/pylib-apple/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/cf/31/c8cf7953762f98ac90c097a4b865", "assets/build/pylib-apple/encodings/quopri_codec.py": "https://files.ballistica.net/cache/ba1/7c/99/e1ba630b5466e0b9b1cd6ff779f7", "assets/build/pylib-apple/encodings/raw_unicode_escape.py": "https://files.ballistica.net/cache/ba1/ef/f7/9403c0484bd76983c3b23c1980e0", "assets/build/pylib-apple/encodings/rot_13.py": "https://files.ballistica.net/cache/ba1/ef/32/5aa7862c190b7246f8592bdeca9e", @@ -3241,7 +3241,7 @@ "assets/build/pylib-apple/fileinput.py": "https://files.ballistica.net/cache/ba1/08/d2/236f7a90d9c686581e6456e06229", "assets/build/pylib-apple/fnmatch.py": "https://files.ballistica.net/cache/ba1/00/11/7533d94880452cc0ab88f9373642", "assets/build/pylib-apple/formatter.py": "https://files.ballistica.net/cache/ba1/b3/5f/58445670edaf8bb748c745197fa7", - "assets/build/pylib-apple/fractions.py": "https://files.ballistica.net/cache/ba1/36/53/449e18911808fbb40428ad9d314d", + "assets/build/pylib-apple/fractions.py": "https://files.ballistica.net/cache/ba1/bb/20/945accff09d654218c4f4929f9b1", "assets/build/pylib-apple/ftplib.py": "https://files.ballistica.net/cache/ba1/a5/0f/4be26d989b3a1431da319d403f04", "assets/build/pylib-apple/functools.py": "https://files.ballistica.net/cache/ba1/82/f9/b13ce3b3135bad32a49fce297507", "assets/build/pylib-apple/genericpath.py": "https://files.ballistica.net/cache/ba1/e4/e1/3097bbebdff714b5ef8bb74759f9", @@ -3249,7 +3249,7 @@ "assets/build/pylib-apple/getpass.py": "https://files.ballistica.net/cache/ba1/02/a1/d4249edfdf76656945cda335490b", "assets/build/pylib-apple/gettext.py": "https://files.ballistica.net/cache/ba1/e1/68/e0f1837f5894efe656c47ae2fb37", "assets/build/pylib-apple/glob.py": "https://files.ballistica.net/cache/ba1/96/c2/9d910d21ac8886d2423287d0ef00", - "assets/build/pylib-apple/gzip.py": "https://files.ballistica.net/cache/ba1/38/c2/5a14bc48b9488c4d3a1552891035", + "assets/build/pylib-apple/gzip.py": "https://files.ballistica.net/cache/ba1/d9/fc/f621c55b5af86da312e264966efc", "assets/build/pylib-apple/hashlib.py": "https://files.ballistica.net/cache/ba1/ea/1c/7cef23322a343b2cb0dd0672a579", "assets/build/pylib-apple/heapq.py": "https://files.ballistica.net/cache/ba1/a5/e7/f4748c3884acf2e4e8ccc8034566", "assets/build/pylib-apple/hmac.py": "https://files.ballistica.net/cache/ba1/6e/dc/c724c3184b473c12632485fb1041", @@ -3270,7 +3270,7 @@ "assets/build/pylib-apple/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/1f/fe/2a27ae49f0c0db298c9eac2d6fa4", "assets/build/pylib-apple/importlib/resources.py": "https://files.ballistica.net/cache/ba1/ca/1a/f4d3e74466144c4852c53acf559c", "assets/build/pylib-apple/importlib/util.py": "https://files.ballistica.net/cache/ba1/28/14/519fd434e756d3e630d96cbc4d4f", - "assets/build/pylib-apple/inspect.py": "https://files.ballistica.net/cache/ba1/6a/be/1af85e9e3760a22210875ea1e66a", + "assets/build/pylib-apple/inspect.py": "https://files.ballistica.net/cache/ba1/c5/4d/ff30d22c573701958e1dc84c0d05", "assets/build/pylib-apple/io.py": "https://files.ballistica.net/cache/ba1/3b/5f/d80c2277bbb2e8be716d497d19c3", "assets/build/pylib-apple/ipaddress.py": "https://files.ballistica.net/cache/ba1/fe/be/a8b89725129a490eb4250a4c42dd", "assets/build/pylib-apple/json/__init__.py": "https://files.ballistica.net/cache/ba1/a7/14/b50d2bae12ae876dce4d674aa000", @@ -3281,8 +3281,8 @@ "assets/build/pylib-apple/keyword.py": "https://files.ballistica.net/cache/ba1/43/a9/76fa84b2f2a17fc06fbbf42e6a15", "assets/build/pylib-apple/linecache.py": "https://files.ballistica.net/cache/ba1/74/13/4df2fa7a9a0d1879e928afd1b3fa", "assets/build/pylib-apple/locale.py": "https://files.ballistica.net/cache/ba1/90/f9/938e5408764ae6a0fc378cc301bb", - "assets/build/pylib-apple/logging/__init__.py": "https://files.ballistica.net/cache/ba1/e1/88/9e5fca4749f8280fca94da8f5417", - "assets/build/pylib-apple/logging/config.py": "https://files.ballistica.net/cache/ba1/95/22/3cba6f6a0fb56dba5f6bb89df250", + "assets/build/pylib-apple/logging/__init__.py": "https://files.ballistica.net/cache/ba1/31/a7/d4a9cfdb9568e90c10cf674d2058", + "assets/build/pylib-apple/logging/config.py": "https://files.ballistica.net/cache/ba1/8c/0b/15a5fdbb610e26f973bf46ac4287", "assets/build/pylib-apple/logging/handlers.py": "https://files.ballistica.net/cache/ba1/58/a5/99e0d1cf6e9a35c11d349341f7c6", "assets/build/pylib-apple/lzma.py": "https://files.ballistica.net/cache/ba1/8d/4c/6289a712439521bf99a154d316ab", "assets/build/pylib-apple/macpath.py": "https://files.ballistica.net/cache/ba1/23/b7/d83ee2887e3ebdef21b5b592fd52", @@ -3291,14 +3291,14 @@ "assets/build/pylib-apple/mimetypes.py": "https://files.ballistica.net/cache/ba1/61/0f/15449b27ff2d27b50d55e387738a", "assets/build/pylib-apple/modulefinder.py": "https://files.ballistica.net/cache/ba1/44/03/57c041ddca84c7ba9986605820df", "assets/build/pylib-apple/netrc.py": "https://files.ballistica.net/cache/ba1/35/a9/0a1e1c8ecab734c09a5f8d64b51a", - "assets/build/pylib-apple/nntplib.py": "https://files.ballistica.net/cache/ba1/dc/56/f52a56f95fd67017773f6c0f5ed2", + "assets/build/pylib-apple/nntplib.py": "https://files.ballistica.net/cache/ba1/2b/92/a3a80b9a4e7730490198a548204c", "assets/build/pylib-apple/ntpath.py": "https://files.ballistica.net/cache/ba1/80/a7/462a2b4b0008f7dccd3c759f8857", "assets/build/pylib-apple/nturl2path.py": "https://files.ballistica.net/cache/ba1/d8/fa/0d625b59939d483cafa553790235", "assets/build/pylib-apple/numbers.py": "https://files.ballistica.net/cache/ba1/92/16/807de1550920d485c87f3d587d5d", "assets/build/pylib-apple/opcode.py": "https://files.ballistica.net/cache/ba1/d7/aa/1d37b642b89086fcc2d437d4adf8", "assets/build/pylib-apple/operator.py": "https://files.ballistica.net/cache/ba1/f0/07/a8b8b5f50e9abf13c9996e9b9434", "assets/build/pylib-apple/optparse.py": "https://files.ballistica.net/cache/ba1/7e/57/af779a7d4606910039060c7c9409", - "assets/build/pylib-apple/os.py": "https://files.ballistica.net/cache/ba1/34/9d/3198644aa260798e7d3279ada7e6", + "assets/build/pylib-apple/os.py": "https://files.ballistica.net/cache/ba1/c1/ab/b842eb67df94b7f66b20cf4e4fa9", "assets/build/pylib-apple/pathlib.py": "https://files.ballistica.net/cache/ba1/fc/c8/bd4616a80bfb3afcc77556e701a1", "assets/build/pylib-apple/pdb.py": "https://files.ballistica.net/cache/ba1/ca/29/76a70d0f97b46a7ac2fd3b26ef56", "assets/build/pylib-apple/pickle.py": "https://files.ballistica.net/cache/ba1/81/97/17747f0115fb9620c787b1c342d4", @@ -3315,7 +3315,7 @@ "assets/build/pylib-apple/pty.py": "https://files.ballistica.net/cache/ba1/26/71/f89485d103b2a80ec4198de7f3a6", "assets/build/pylib-apple/py_compile.py": "https://files.ballistica.net/cache/ba1/fe/6a/5b863bc38a0efa02e5a2e8df9758", "assets/build/pylib-apple/pyclbr.py": "https://files.ballistica.net/cache/ba1/44/3a/442c56a5f5f8b4c2c992cc12ed35", - "assets/build/pylib-apple/pydoc.py": "https://files.ballistica.net/cache/ba1/fe/32/9d910017079288d032c48a1c5739", + "assets/build/pylib-apple/pydoc.py": "https://files.ballistica.net/cache/ba1/be/f8/b7b3ffa4342672f71c578ac23d4a", "assets/build/pylib-apple/queue.py": "https://files.ballistica.net/cache/ba1/0b/69/f9e2c026824fe1d4602a6183b56c", "assets/build/pylib-apple/quopri.py": "https://files.ballistica.net/cache/ba1/34/a2/7e15c991e3a6ba75d988323117e8", "assets/build/pylib-apple/random.py": "https://files.ballistica.net/cache/ba1/07/b5/9ac8faa65ff3e80827b59fa931e4", @@ -3348,13 +3348,13 @@ "assets/build/pylib-apple/string.py": "https://files.ballistica.net/cache/ba1/87/20/f6260e9d53689af592a629332612", "assets/build/pylib-apple/stringprep.py": "https://files.ballistica.net/cache/ba1/f0/9b/77cc5580b139f527ee84fff812fc", "assets/build/pylib-apple/struct.py": "https://files.ballistica.net/cache/ba1/10/6d/7a6c0fbac83b2680bbeda8585f8f", - "assets/build/pylib-apple/subprocess.py": "https://files.ballistica.net/cache/ba1/0e/51/da9258c7d2f36f01a9e2af0c037e", + "assets/build/pylib-apple/subprocess.py": "https://files.ballistica.net/cache/ba1/d1/81/62496e6cd420342a1c254c31a461", "assets/build/pylib-apple/sunau.py": "https://files.ballistica.net/cache/ba1/99/de/eb56408801fec20de1d7c4a745c8", "assets/build/pylib-apple/symbol.py": "https://files.ballistica.net/cache/ba1/24/f5/3d4dc0c06af3af1051b792f63cdf", "assets/build/pylib-apple/symtable.py": "https://files.ballistica.net/cache/ba1/bb/be/5b97a512ed9e491ce7e8be113b61", "assets/build/pylib-apple/sysconfig.py": "https://files.ballistica.net/cache/ba1/31/09/41072e6015063a344086eca43827", "assets/build/pylib-apple/tabnanny.py": "https://files.ballistica.net/cache/ba1/f7/ba/da1e12d53ebdf326581c99c7d29b", - "assets/build/pylib-apple/tarfile.py": "https://files.ballistica.net/cache/ba1/9f/18/42078f0f0874ca3580d498740657", + "assets/build/pylib-apple/tarfile.py": "https://files.ballistica.net/cache/ba1/27/2c/ea8b64ffbe47c056fa5084893abd", "assets/build/pylib-apple/telnetlib.py": "https://files.ballistica.net/cache/ba1/12/a2/9022d2838d85ac4a84a5c9ef2e2c", "assets/build/pylib-apple/tempfile.py": "https://files.ballistica.net/cache/ba1/63/8a/6cce413f8da1bb559e542786db4f", "assets/build/pylib-apple/textwrap.py": "https://files.ballistica.net/cache/ba1/a9/d4/996c224bb06520a10b7bd86f8ee0", @@ -3363,24 +3363,24 @@ "assets/build/pylib-apple/timeit.py": "https://files.ballistica.net/cache/ba1/a5/a4/7e5f848d094fbf83e52dcd8f48c6", "assets/build/pylib-apple/token.py": "https://files.ballistica.net/cache/ba1/36/b9/9ae6aa89c0baadc5d80dd4127b7f", "assets/build/pylib-apple/tokenize.py": "https://files.ballistica.net/cache/ba1/73/b0/fd1563d114d63bdd21bceefa56be", - "assets/build/pylib-apple/trace.py": "https://files.ballistica.net/cache/ba1/7e/18/925baccd96ba96a79f03d91e762e", + "assets/build/pylib-apple/trace.py": "https://files.ballistica.net/cache/ba1/57/17/40229e4893d4eb9a5faaae113139", "assets/build/pylib-apple/traceback.py": "https://files.ballistica.net/cache/ba1/ac/cc/3f70a62f7cca00e4107df8cfa112", "assets/build/pylib-apple/tracemalloc.py": "https://files.ballistica.net/cache/ba1/b5/1e/62e69ad7c2181e30fac478d4f936", "assets/build/pylib-apple/tty.py": "https://files.ballistica.net/cache/ba1/ec/ea/2421fecb0e38e38d55cf0ce2b0e2", "assets/build/pylib-apple/types.py": "https://files.ballistica.net/cache/ba1/2f/7a/3bd0b56fdcddfc3e9edb6b556925", - "assets/build/pylib-apple/typing.py": "https://files.ballistica.net/cache/ba1/26/a2/14eb22ed632f5ba571783f4ca9f6", + "assets/build/pylib-apple/typing.py": "https://files.ballistica.net/cache/ba1/76/b3/0ae27201749a7b8e6ae9325d2a06", "assets/build/pylib-apple/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/a2/c9/6d1cda1b043897ad0b5b043e7112", "assets/build/pylib-apple/urllib/error.py": "https://files.ballistica.net/cache/ba1/09/dd/15e4e9e675bd3242b0d5fb0f2707", - "assets/build/pylib-apple/urllib/parse.py": "https://files.ballistica.net/cache/ba1/89/94/ce115dee299d7cc3bcb8b5f76907", - "assets/build/pylib-apple/urllib/request.py": "https://files.ballistica.net/cache/ba1/42/b4/b5823f8d3ffdbf333a756d9a21e7", + "assets/build/pylib-apple/urllib/parse.py": "https://files.ballistica.net/cache/ba1/0f/18/3bc3354a5520bc6e0f892404028f", + "assets/build/pylib-apple/urllib/request.py": "https://files.ballistica.net/cache/ba1/03/9e/0da6865195d8e69d43ff47c43efe", "assets/build/pylib-apple/urllib/response.py": "https://files.ballistica.net/cache/ba1/03/b2/ec9cd1798de4004d98d213362713", "assets/build/pylib-apple/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/23/40/c172a9879ccb2bd76adf0db29567", "assets/build/pylib-apple/uu.py": "https://files.ballistica.net/cache/ba1/02/7a/d6fed645dcff0d4aff84e3cea58e", "assets/build/pylib-apple/uuid.py": "https://files.ballistica.net/cache/ba1/fa/e3/1abf5dee0941c2d15cf45f9f95be", - "assets/build/pylib-apple/warnings.py": "https://files.ballistica.net/cache/ba1/8c/ad/2d445d2598c0f588db88e9780221", + "assets/build/pylib-apple/warnings.py": "https://files.ballistica.net/cache/ba1/08/9c/d3b49f9ffdf97270f336a4abb83b", "assets/build/pylib-apple/wave.py": "https://files.ballistica.net/cache/ba1/4d/a0/b093aa87d58ab11be45e1e8dd05a", "assets/build/pylib-apple/weakref.py": "https://files.ballistica.net/cache/ba1/19/e6/014589327dc84e8fd0e5fb180345", - "assets/build/pylib-apple/webbrowser.py": "https://files.ballistica.net/cache/ba1/29/57/574eac7a24d3fca5921287a4e42e", + "assets/build/pylib-apple/webbrowser.py": "https://files.ballistica.net/cache/ba1/66/26/d905690b0376e7ff4c36a5a5b31b", "assets/build/pylib-apple/xdrlib.py": "https://files.ballistica.net/cache/ba1/b7/83/ac6e63a15cead601475a09350849", "assets/build/pylib-apple/xml/__init__.py": "https://files.ballistica.net/cache/ba1/3f/bd/6072ff48fc04c3af1dcbb8005adf", "assets/build/pylib-apple/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/97/e8/e3ea178b500cab89a64c7e5d3d81", diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index f8bd65f8..865d270f 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -38,6 +38,18 @@ ENABLE_OPENSSL = True def build_apple(arch: str, debug: bool = False) -> None: """Run a build for the provided apple arch (mac, ios, or tvos).""" + import platform + import subprocess + from efro.error import CleanError + + # IMPORTANT; seems we currently wind up building against /usr/local gettext + # stuff. Hopefully the maintainer fixes this, but for now I need to + # remind myself to blow it away while building. + if 'MacBook-Fro' in platform.node(): + if (subprocess.run('which gettext', shell=True, + check=False).returncode == 0): + raise CleanError('NEED TO TEMP-KILL GETTEXT') + builddir = 'build/python_apple_' + arch + ('_debug' if debug else '') efrotools.run('rm -rf "' + builddir + '"') efrotools.run('mkdir -p build') @@ -50,8 +62,8 @@ def build_apple(arch: str, debug: bool = False) -> None: # We can actually fix this to use the current one, but something # broke in the underlying build even on old commits so keeping it # locked for now... - efrotools.run('git checkout bf1ed73d0d5ff46862ba69dd5eb2ffaeff6f19b6') - # efrotools.run(f'git checkout {PYTHON_VERSION_MAJOR}') + # efrotools.run('git checkout bf1ed73d0d5ff46862ba69dd5eb2ffaeff6f19b6') + efrotools.run(f'git checkout {PYTHON_VERSION_MAJOR}') # On mac we currently have to add the _scproxy module or urllib will # fail. @@ -146,10 +158,10 @@ def build_apple(arch: str, debug: bool = False) -> None: ('build/$2/Support/OpenSSL ' if ENABLE_OPENSSL else '') + 'build/$2/Support/XZ $$(PYTHON_DIR-$1)/Makefile\n#' + srctxt) srctxt = ('dist/Python-$(PYTHON_VER)-$1-support.' - 'b$(BUILD_NUMBER).tar.gz: ') + '$(BUILD_NUMBER).tar.gz: ') txt = efrotools.replace_one( txt, srctxt, - 'dist/Python-$(PYTHON_VER)-$1-support.b$(BUILD_NUMBER).tar.gz:' + 'dist/Python-$(PYTHON_VER)-$1-support.$(BUILD_NUMBER).tar.gz:' ' $$(PYTHON_FRAMEWORK-$1)\n#' + srctxt) # Turn doc strings on; looks like it only adds a few hundred k. @@ -158,13 +170,13 @@ def build_apple(arch: str, debug: bool = False) -> None: # Set mac/ios version reqs # (see issue with utimensat and futimens). txt = efrotools.replace_one(txt, 'MACOSX_DEPLOYMENT_TARGET=10.8', - 'MACOSX_DEPLOYMENT_TARGET=10.13') + 'MACOSX_DEPLOYMENT_TARGET=10.14') # And equivalent iOS (11+). txt = efrotools.replace_one(txt, 'CFLAGS-iOS=-mios-version-min=8.0', - 'CFLAGS-iOS=-mios-version-min=11.0') + 'CFLAGS-iOS=-mios-version-min=12.0') # Ditto for tvOS. txt = efrotools.replace_one(txt, 'CFLAGS-tvOS=-mtvos-version-min=9.0', - 'CFLAGS-tvOS=-mtvos-version-min=11.0') + 'CFLAGS-tvOS=-mtvos-version-min=12.0') if debug: @@ -177,10 +189,10 @@ def build_apple(arch: str, debug: bool = False) -> None: txt = txt.replace(dline, '--with-pydebug ' + dline) # Debug has a different name. - # (Currently expect to replace 13 instances of this). + # (Currently expect to replace 12 instances of this). dline = 'python$(PYTHON_VER)m' splitlen = len(txt.split(dline)) - if splitlen != 14: + if splitlen != 13: raise RuntimeError(f'Unexpected configure line count {splitlen}.') txt = txt.replace(dline, 'python$(PYTHON_VER)dm') From 431e6e80bf6ffcf03692d41aac5419fd91291966 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 4 Jun 2020 21:20:25 -0700 Subject: [PATCH 078/417] Tidying --- .idea/dictionaries/ericf.xml | 2 + assets/src/ba_data/python/ba/_activity.py | 14 +- assets/src/ba_data/python/ba/_coopsession.py | 2 +- assets/src/ba_data/python/ba/_gameresults.py | 17 +- .../ba_data/python/ba/_multiteamsession.py | 12 +- assets/src/ba_data/python/ba/_player.py | 3 +- assets/src/ba_data/python/ba/_session.py | 2 +- assets/src/ba_data/python/ba/_team.py | 2 +- assets/src/ba_data/python/ba/ui/__init__.py | 13 +- .../python/bastd/activity/multiteamscore.py | 26 +- .../python/bastd/activity/multiteamvictory.py | 4 +- .../ba_data/python/bastd/game/meteorshower.py | 3 +- assets/src/ba_data/python/bastd/game/race.py | 23 +- .../python/bastd/ui/playlist/__init__.py | 3 + .../python/bastd/ui/playlist/browser.py | 252 +++++++++--------- docs/ba_module.md | 28 +- 16 files changed, 210 insertions(+), 196 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 635c0d21..8ba8a5a1 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -35,6 +35,7 @@ actionhero activityname activityplayer + activityteam activitytypes activityutils actorclass @@ -2178,6 +2179,7 @@ yapf yapfconfig yinyang + yoffs ypos yres yscl diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index d439d6db..ae03193d 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -557,7 +557,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): sessionplayer.resetinput() sessionteam = sessionplayer.sessionteam assert sessionplayer in sessionteam.players - team = sessionteam.gameteam + team = sessionteam.activityteam assert team is not None sessionplayer.setactivity(self) with _ba.Context(self): @@ -587,7 +587,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): player: Any = sessionplayer.activityplayer assert isinstance(player, self._playertype) - team: Any = sessionplayer.sessionteam.gameteam + team: Any = sessionplayer.sessionteam.activityteam assert isinstance(team, self._teamtype) assert player in team.players @@ -629,7 +629,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): assert not self.expired with _ba.Context(self): - sessionteam.gameteam = team = self.create_team(sessionteam) + sessionteam.activityteam = team = self.create_team(sessionteam) team.postinit(sessionteam) self.teams.append(team) try: @@ -643,9 +643,9 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): (internal) """ assert not self.expired - assert sessionteam.gameteam is not None + assert sessionteam.activityteam is not None - team: Any = sessionteam.gameteam + team: Any = sessionteam.activityteam assert isinstance(team, self._teamtype) assert team in self.teams @@ -663,7 +663,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): except Exception: print_exception(f'Error on leave for {team} in {self}.') - sessionteam.gameteam = None + sessionteam.activityteam = None # Add the team to a list to keep it around for a while. This is # to discourage logic from firing on team object death, which @@ -854,7 +854,7 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): try: sessionteam = team.sessionteam - sessionteam.gameteam = None + sessionteam.activityteam = None except SessionTeamNotFoundError: # It is expected that Team objects may last longer than # the SessionTeam they came from (game objects may hold diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 90da45f8..2ee47cc9 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -346,7 +346,7 @@ class CoopSession(Session): # Generic team games. if isinstance(results, GameResults): playerinfos = results.playerinfos - score = results.get_team_score(results.sessionteams[0]) + score = results.get_sessionteam_score(results.sessionteams[0]) fail_message = None score_order = ('decreasing' if results.lower_is_better else 'increasing') diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 1ffa78a8..c58d9d2c 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -50,7 +50,6 @@ class GameResults: """ def __init__(self) -> None: - """Instantiate a results instance.""" self._game_set = False self._scores: Dict[int, Tuple[ReferenceType[ba.SessionTeam], Optional[int]]] = {} @@ -76,7 +75,7 @@ class GameResults: self._scoretype = scoreconfig.scoretype def set_team_score(self, team: ba.Team, score: Optional[int]) -> None: - """Set the score for a given ba.Team. + """Set the score for a given team. This can be a number or None. (see the none_is_winner arg in the constructor) @@ -84,7 +83,8 @@ class GameResults: sessionteam = team.sessionteam self._scores[sessionteam.id] = (weakref.ref(sessionteam), score) - def get_team_score(self, sessionteam: ba.SessionTeam) -> Optional[int]: + def get_sessionteam_score(self, + sessionteam: ba.SessionTeam) -> Optional[int]: """Return the score for a given ba.SessionTeam.""" for score in list(self._scores.values()): if score[0]() is sessionteam: @@ -106,12 +106,13 @@ class GameResults: teams.append(team) return teams - def has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool: - """Return whether there is a score for a given team.""" + def has_score_for_sessionteam(self, sessionteam: ba.SessionTeam) -> bool: + """Return whether there is a score for a given session-team.""" return any(s[0]() is sessionteam for s in self._scores.values()) - def get_team_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr: - """Return the score for the given ba.Team as an Lstr. + def get_sessionteam_score_str(self, + sessionteam: ba.SessionTeam) -> ba.Lstr: + """Return the score for the given session-team as an Lstr. (properly formatted for the score type.) """ @@ -169,7 +170,7 @@ class GameResults: return self._lower_is_better @property - def winning_team(self) -> Optional[ba.SessionTeam]: + def winning_sessionteam(self) -> Optional[ba.SessionTeam]: """The winning ba.SessionTeam if there is exactly one, or else None.""" if not self._game_set: raise RuntimeError("Can't get winners until game is set.") diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 9daedc9d..223c3930 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -262,12 +262,12 @@ class MultiTeamSession(Session): _ba.timer(delay, Call(_ba.playsound, _ba.getsound('boxingBell'))) if announce_winning_team: - winning_team = results.winning_team - if winning_team is not None: + winning_sessionteam = results.winning_sessionteam + if winning_sessionteam is not None: # Have all players celebrate. celebrate_msg = CelebrateMessage(duration=10.0) - assert winning_team.gameteam is not None - for player in winning_team.gameteam.players: + assert winning_sessionteam.activityteam is not None + for player in winning_sessionteam.activityteam.players: if player.actor: player.actor.handlemessage(celebrate_msg) cameraflash() @@ -278,11 +278,11 @@ class MultiTeamSession(Session): else: wins_resource = 'winsTeamText' wins_text = Lstr(resource=wins_resource, - subs=[('${NAME}', winning_team.name)]) + subs=[('${NAME}', winning_sessionteam.name)]) activity.show_zoom_message( wins_text, scale=0.85, - color=normalized_color(winning_team.color), + color=normalized_color(winning_sessionteam.color), ) diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 6dbd6969..16a53cc9 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -81,6 +81,7 @@ class Player(Generic[TeamType]): actor: Optional[ba.Actor] color: Sequence[float] highlight: Sequence[float] + _team: TeamType _sessionplayer: ba.SessionPlayer _nodeactor: Optional[ba.NodeActor] @@ -118,7 +119,7 @@ class Player(Generic[TeamType]): self.character = sessionplayer.character self.color = sessionplayer.color self.highlight = sessionplayer.highlight - self._team = cast(TeamType, sessionplayer.sessionteam.gameteam) + self._team = cast(TeamType, sessionplayer.sessionteam.activityteam) assert self._team is not None self._customdata = {} self._expired = False diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 72c56101..ecad97b2 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -306,7 +306,7 @@ class Session: # Remove their Team from the Activity. if activity is not None: - if sessionteam.gameteam in activity.teams: + if sessionteam.activityteam in activity.teams: activity.remove_team(sessionteam) else: print('Team not found in Activity in on_player_leave.') diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index 23326f82..f04c3178 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -85,7 +85,7 @@ class SessionTeam: self.color = tuple(color) self.players = [] self.customdata = {} - self.gameteam: Optional[Team] = None + self.activityteam: Optional[Team] = None def leave(self) -> None: """(internal)""" diff --git a/assets/src/ba_data/python/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py index 58e7a43e..02835ab6 100644 --- a/assets/src/ba_data/python/ba/ui/__init__.py +++ b/assets/src/ba_data/python/ba/ui/__init__.py @@ -194,12 +194,15 @@ def uicleanupcheck(obj: Any, widget: ba.Widget) -> None: if not isinstance(widget, _ba.Widget): raise TypeError('widget arg is not a ba.Widget') - def foobar() -> None: - """Just testing.""" - if DEBUG_UI_CLEANUP_CHECKS: - print('uicleanupcheck widget dying...') + if bool(False): + + def foobar() -> None: + """Just testing.""" + if DEBUG_UI_CLEANUP_CHECKS: + print('uicleanupcheck widget dying...') + + widget.add_delete_callback(foobar) - widget.add_delete_callback(foobar) _ba.app.uicleanupchecks.append( UICleanupCheck(obj=weakref.ref(obj), widget=widget, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index 68a4c3d8..f3c885f0 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -88,16 +88,16 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): def _get_prec_score(p_rec: ba.PlayerRecord) -> Optional[int]: if is_free_for_all and results is not None: assert isinstance(results, ba.GameResults) - assert p_rec.team.gameteam is not None - val = results.get_team_score(p_rec.team) + assert p_rec.team.activityteam is not None + val = results.get_sessionteam_score(p_rec.team) return val return p_rec.accumscore def _get_prec_score_str(p_rec: ba.PlayerRecord) -> Union[str, ba.Lstr]: if is_free_for_all and results is not None: assert isinstance(results, ba.GameResults) - assert p_rec.team.gameteam is not None - val = results.get_team_score_str(p_rec.team) + assert p_rec.team.activityteam is not None + val = results.get_sessionteam_score_str(p_rec.team) assert val is not None return val return str(p_rec.accumscore) @@ -139,18 +139,18 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): # Just want living player entries. player_records = [p[2] for p in player_records_scores if p[2]] - v_offs = -140.0 + spacing * len(player_records) * 0.5 + voffs = -140.0 + spacing * len(player_records) * 0.5 - def _txt(x_offs: float, - y_offs: float, + def _txt(xoffs: float, + yoffs: float, text: ba.Lstr, h_align: Text.HAlign = Text.HAlign.RIGHT, extrascale: float = 1.0, maxwidth: Optional[float] = 120.0) -> None: Text(text, color=(0.5, 0.5, 0.6, 0.5), - position=(ts_h_offs + x_offs * scale, - ts_v_offset + (v_offs + y_offs + 4.0) * scale), + position=(ts_h_offs + xoffs * scale, + ts_v_offset + (voffs + yoffs + 4.0) * scale), h_align=h_align, v_align=Text.VAlign.CENTER, scale=0.8 * scale * extrascale, @@ -193,7 +193,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): maxwidth: float = 70.0) -> None: Text(text, position=(ts_h_offs + x_offs * scale, - ts_v_offset + (v_offs + 15) * scale), + ts_v_offset + (voffs + 15) * scale), scale=scale, color=(1.0, 0.9, 0.5, 1.0) if highlight else (0.5, 0.5, 0.6, 0.5), @@ -205,10 +205,10 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): for playerrec in player_records: tdelay += 0.05 - v_offs -= spacing + voffs -= spacing Image(playerrec.get_icon(), position=(ts_h_offs - 12 * scale, - ts_v_offset + (v_offs + 15.0) * scale), + ts_v_offset + (voffs + 15.0) * scale), scale=(30.0 * scale, 30.0 * scale), transition=Image.Transition.IN_LEFT, transition_delay=tdelay).autoretain() @@ -216,7 +216,7 @@ class MultiTeamScoreScreenActivity(ScoreScreenActivity): maxwidth=160, scale=0.75 * scale, position=(ts_h_offs + 10.0 * scale, - ts_v_offset + (v_offs + 15) * scale), + ts_v_offset + (voffs + 15) * scale), h_align=Text.HAlign.LEFT, v_align=Text.VAlign.CENTER, color=ba.safecolor(playerrec.team.color + (1, )), diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index eec98f82..275e2911 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -61,7 +61,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): self._show_up_next = False self._custom_continue_message = sval super().on_begin() - winning_team = self.settings_raw['winner'] + winning_sessionteam = self.settings_raw['winner'] # Pause a moment before playing victory music. ba.timer(0.6, ba.WeakCall(self._play_victory_music)) @@ -171,7 +171,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): if not self._is_ffa: mvp, mvp_name = None, None for entry in player_entries: - if entry[2].team == winning_team: + if entry[2].team == winning_sessionteam: mvp = entry[2] mvp_name = entry[1] break diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 233894c6..9e41439c 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -177,7 +177,8 @@ class MeteorShowerGame(ba.TeamGameActivity[Player, Team]): else: # Default handler: - super().handlemessage(msg) + return super().handlemessage(msg) + return None def _check_end_game(self) -> None: living_team_count = 0 diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index bbe8dc26..adead4d7 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -532,16 +532,13 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): self._race_started = True def _update_player_order(self) -> None: - # FIXME: tidy this up # Calc all player distances. for player in self.players: pos: Optional[ba.Vec3] try: - assert isinstance(player.actor, PlayerSpaz) - assert player.actor.node - pos = ba.Vec3(player.actor.node.position) - except Exception: + pos = player.position + except ba.NotFoundError: pos = None if pos is not None: r_index = player.last_region @@ -560,14 +557,11 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): p_list.sort(reverse=True, key=lambda x: x[0]) for i, plr in enumerate(p_list): - try: - plr[1].rank = i - if plr[1].actor: - node = plr[1].distance_txt - if node: - node.text = str(i + 1) if plr[1].is_alive() else '' - except Exception: - ba.print_exception('error updating player orders') + plr[1].rank = i + if plr[1].actor: + node = plr[1].distance_txt + if node: + node.text = str(i + 1) if plr[1].is_alive() else '' def _spawn_bomb(self) -> None: if self._front_race_region is None: @@ -730,7 +724,8 @@ class RaceGame(ba.TeamGameActivity[Player, Team]): def handlemessage(self, msg: Any) -> Any: if isinstance(msg, ba.PlayerDiedMessage): - super().handlemessage(msg) # Augment default behavior. + # Augment default behavior. + super().handlemessage(msg) player = msg.getplayer(Player) if not player.finished: self.respawn_player(player, respawn_time=1) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/__init__.py b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py index aeabe2d1..46f37970 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py @@ -38,6 +38,7 @@ class PlaylistTypeVars: from ba.internal import (get_default_teams_playlist, get_default_free_for_all_playlist) self.sessiontype: Type[ba.Session] + if issubclass(sessiontype, ba.DualTeamSession): play_mode_name = ba.Lstr(resource='playModes.teamsText', fallback_resource='teamsText') @@ -47,6 +48,7 @@ class PlaylistTypeVars: self.window_title_name = ba.Lstr(resource='playModes.teamsText', fallback_resource='teamsText') self.sessiontype = ba.DualTeamSession + elif issubclass(sessiontype, ba.FreeForAllSession): play_mode_name = ba.Lstr(resource='playModes.freeForAllText', fallback_resource='freeForAllText') @@ -57,6 +59,7 @@ class PlaylistTypeVars: resource='playModes.freeForAllText', fallback_resource='freeForAllText') self.sessiontype = ba.FreeForAllSession + else: raise TypeError('playlist type vars undefined for session type: ' + str(sessiontype)) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index 2311eebd..bb03b07c 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -42,7 +42,7 @@ class PlaylistBrowserWindow(ba.Window): origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=cyclic-import - from bastd.ui import playlist + from bastd.ui.playlist import PlaylistTypeVars # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] @@ -62,8 +62,8 @@ class PlaylistBrowserWindow(ba.Window): ba.app.main_window = 'Free-for-All Game Select' ba.set_analytics_screen('FreeForAll Window') else: - raise TypeError(f'invalid sessiontype: {sessiontype}') - self._pvars = playlist.PlaylistTypeVars(sessiontype) + raise TypeError(f'Invalid sessiontype: {sessiontype}.') + self._pvars = PlaylistTypeVars(sessiontype) self._sessiontype = sessiontype @@ -74,39 +74,45 @@ class PlaylistBrowserWindow(ba.Window): # On new installations, go ahead and create a few playlists # besides the hard-coded default one: if not _ba.get_account_misc_val('madeStandardPlaylists', False): - # yapf: disable _ba.add_transaction({ - 'type': 'ADD_PLAYLIST', - 'playlistType': 'Free-for-All', + 'type': + 'ADD_PLAYLIST', + 'playlistType': + 'Free-for-All', 'playlistName': ba.Lstr(resource='singleGamePlaylistNameText' ).evaluate().replace( '${GAME}', - ba.Lstr( - translate=('gameNames', - 'Death Match')).evaluate()), + ba.Lstr(translate=('gameNames', + 'Death Match')).evaluate()), 'playlist': [ - {'type': 'bs_death_match.DeathMatchGame', - 'settings': { - 'Epic Mode': False, - 'Kills to Win Per Player': 10, - 'Respawn Times': 1.0, - 'Time Limit': 300, - 'map': 'Doom Shroom'} + { + 'type': 'bs_death_match.DeathMatchGame', + 'settings': { + 'Epic Mode': False, + 'Kills to Win Per Player': 10, + 'Respawn Times': 1.0, + 'Time Limit': 300, + 'map': 'Doom Shroom' + } + }, + { + 'type': 'bs_death_match.DeathMatchGame', + 'settings': { + 'Epic Mode': False, + 'Kills to Win Per Player': 10, + 'Respawn Times': 1.0, + 'Time Limit': 300, + 'map': 'Crag Castle' + } }, - {'type': 'bs_death_match.DeathMatchGame', - 'settings': { - 'Epic Mode': False, - 'Kills to Win Per Player': 10, - 'Respawn Times': 1.0, - 'Time Limit': 300, - 'map': 'Crag Castle'} - } ] }) _ba.add_transaction({ - 'type': 'ADD_PLAYLIST', - 'playlistType': 'Team Tournament', + 'type': + 'ADD_PLAYLIST', + 'playlistType': + 'Team Tournament', 'playlistName': ba.Lstr( resource='singleGamePlaylistNameText' @@ -115,92 +121,102 @@ class PlaylistBrowserWindow(ba.Window): ba.Lstr(translate=('gameNames', 'Capture the Flag')).evaluate()), 'playlist': [ - {'type': 'bs_capture_the_flag.CTFGame', - 'settings': { - 'map': 'Bridgit', - 'Score to Win': 3, - 'Flag Idle Return Time': 30, - 'Flag Touch Return Time': 0, - 'Respawn Times': 1.0, - 'Time Limit': 600, - 'Epic Mode': False} + { + 'type': 'bs_capture_the_flag.CTFGame', + 'settings': { + 'map': 'Bridgit', + 'Score to Win': 3, + 'Flag Idle Return Time': 30, + 'Flag Touch Return Time': 0, + 'Respawn Times': 1.0, + 'Time Limit': 600, + 'Epic Mode': False + } }, - {'type': 'bs_capture_the_flag.CTFGame', - 'settings': { - 'map': 'Roundabout', - 'Score to Win': 2, - 'Flag Idle Return Time': 30, - 'Flag Touch Return Time': 0, - 'Respawn Times': 1.0, - 'Time Limit': 600, - 'Epic Mode': False} + { + 'type': 'bs_capture_the_flag.CTFGame', + 'settings': { + 'map': 'Roundabout', + 'Score to Win': 2, + 'Flag Idle Return Time': 30, + 'Flag Touch Return Time': 0, + 'Respawn Times': 1.0, + 'Time Limit': 600, + 'Epic Mode': False + } + }, + { + 'type': 'bs_capture_the_flag.CTFGame', + 'settings': { + 'map': 'Tip Top', + 'Score to Win': 2, + 'Flag Idle Return Time': 30, + 'Flag Touch Return Time': 3, + 'Respawn Times': 1.0, + 'Time Limit': 300, + 'Epic Mode': False + } }, - {'type': 'bs_capture_the_flag.CTFGame', - 'settings': { - 'map': 'Tip Top', - 'Score to Win': 2, - 'Flag Idle Return Time': 30, - 'Flag Touch Return Time': 3, - 'Respawn Times': 1.0, - 'Time Limit': 300, - 'Epic Mode': False} - } ] }) _ba.add_transaction({ - 'type': 'ADD_PLAYLIST', - 'playlistType': 'Team Tournament', + 'type': + 'ADD_PLAYLIST', + 'playlistType': + 'Team Tournament', 'playlistName': - ba.Lstr(translate=('playlistNames', - 'Just Sports')).evaluate(), + ba.Lstr(translate=('playlistNames', 'Just Sports') + ).evaluate(), 'playlist': [ - {'type': 'bs_hockey.HockeyGame', - 'settings': { - 'Time Limit': 0, - 'map': 'Hockey Stadium', - 'Score to Win': 1, - 'Respawn Times': 1.0} + { + 'type': 'bs_hockey.HockeyGame', + 'settings': { + 'Time Limit': 0, + 'map': 'Hockey Stadium', + 'Score to Win': 1, + 'Respawn Times': 1.0 + } + }, + { + 'type': 'bs_football.FootballTeamGame', + 'settings': { + 'Time Limit': 0, + 'map': 'Football Stadium', + 'Score to Win': 21, + 'Respawn Times': 1.0 + } }, - {'type': 'bs_football.FootballTeamGame', - 'settings': { - 'Time Limit': 0, - 'map': 'Football Stadium', - 'Score to Win': 21, - 'Respawn Times': 1.0} - } ] }) _ba.add_transaction({ - 'type': 'ADD_PLAYLIST', - 'playlistType': 'Free-for-All', + 'type': + 'ADD_PLAYLIST', + 'playlistType': + 'Free-for-All', 'playlistName': - ba.Lstr(translate=('playlistNames', - 'Just Epic')).evaluate(), - 'playlist': [ - {'type': 'bs_elimination.EliminationGame', - 'settings': { - 'Time Limit': 120, - 'map': 'Tip Top', - 'Respawn Times': 1.0, - 'Lives Per Player': 1, - 'Epic Mode': 1} + ba.Lstr(translate=('playlistNames', 'Just Epic') + ).evaluate(), + 'playlist': [{ + 'type': 'bs_elimination.EliminationGame', + 'settings': { + 'Time Limit': 120, + 'map': 'Tip Top', + 'Respawn Times': 1.0, + 'Lives Per Player': 1, + 'Epic Mode': 1 } - ] + }] }) _ba.add_transaction({ 'type': 'SET_MISC_VAL', 'name': 'madeStandardPlaylists', 'value': True }) - # yapf: enable _ba.run_transactions() # Get the current selection (if any). - try: - self._selected_playlist = ba.app.config[self._pvars.config_name + - ' Playlist Selection'] - except Exception: - self._selected_playlist = None + self._selected_playlist = ba.app.config.get(self._pvars.config_name + + ' Playlist Selection') self._width = 900 if ba.app.small_ui else 800 x_inset = 50 if ba.app.small_ui else 0 @@ -270,12 +286,13 @@ class PlaylistBrowserWindow(ba.Window): self._config_name_full = self._pvars.config_name + ' Playlists' self._last_config = None - # update now and once per second.. (this should do our initial refresh) + # Update now and once per second. + # (this should do our initial refresh) + self._update() self._update_timer = ba.Timer(1.0, ba.WeakCall(self._update), timetype=ba.TimeType.REAL, repeat=True) - self._update() def _refresh(self) -> None: # FIXME: Should tidy this up. @@ -292,13 +309,13 @@ class PlaylistBrowserWindow(ba.Window): self._save_state() self._subcontainer.delete() - # make sure config exists + # Make sure config exists. if self._config_name_full not in ba.app.config: ba.app.config[self._config_name_full] = {} items = list(ba.app.config[self._config_name_full].items()) - # make sure everything is unicode + # Make sure everything is unicode. items = [(i[0].decode(), i[1]) if not isinstance(i[0], str) else i for i in items] @@ -507,7 +524,7 @@ class PlaylistBrowserWindow(ba.Window): v -= scl * 130.0 except Exception: - ba.print_exception('error listing playlist maps') + ba.print_exception('Error listing playlist maps.') if not map_images: ba.textwidget(parent=self._subcontainer, @@ -563,43 +580,39 @@ class PlaylistBrowserWindow(ba.Window): def _on_playlist_press(self, button: ba.Widget, playlist_name: str) -> None: # pylint: disable=cyclic-import - from bastd.ui import playoptions + from bastd.ui.playoptions import PlayOptionsWindow + # Make sure the target playlist still exists. - try: - exists = (playlist_name == '__default__' or playlist_name - in ba.app.config[self._config_name_full]) - except Exception: - exists = False + exists = (playlist_name == '__default__' + or playlist_name in ba.app.config.get( + self._config_name_full, {})) if not exists: return self._save_state() - playoptions.PlayOptionsWindow( - sessiontype=self._sessiontype, - scale_origin=button.get_screen_space_center(), - playlist=playlist_name, - delegate=self) + PlayOptionsWindow(sessiontype=self._sessiontype, + scale_origin=button.get_screen_space_center(), + playlist=playlist_name, + delegate=self) def _on_customize_press(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.playlist import customizebrowser as cb + from bastd.ui.playlist.customizebrowser import ( + PlaylistCustomizeBrowserWindow) self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (cb.PlaylistCustomizeBrowserWindow( + ba.app.main_menu_window = (PlaylistCustomizeBrowserWindow( origin_widget=self._customize_button, sessiontype=self._sessiontype).get_root_widget()) def _on_back_press(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import play + from bastd.ui.play import PlayWindow # Store our selected playlist if that's changed. if self._selected_playlist is not None: - try: - prev_sel = ba.app.config[self._pvars.config_name + - ' Playlist Selection'] - except Exception: - prev_sel = None + prev_sel = ba.app.config.get(self._pvars.config_name + + ' Playlist Selection') if self._selected_playlist != prev_sel: cfg = ba.app.config cfg[self._pvars.config_name + @@ -609,7 +622,7 @@ class PlaylistBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (play.PlayWindow( + ba.app.main_menu_window = (PlayWindow( transition='in_left').get_root_widget()) def _save_state(self) -> None: @@ -628,14 +641,11 @@ class PlaylistBrowserWindow(ba.Window): raise Exception('unrecognized selected widget') ba.app.window_states[self.__class__.__name__] = sel_name except Exception: - ba.print_exception('error saving state for', self.__class__) + ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: try: - try: - sel_name = ba.app.window_states[self.__class__.__name__] - except Exception: - sel_name = None + sel_name = ba.app.window_states.get(self.__class__.__name__) if sel_name == 'Back': sel = self._back_button elif sel_name == 'Scroll': @@ -649,4 +659,4 @@ class PlaylistBrowserWindow(ba.Window): sel = self._scrollwidget ba.containerwidget(edit=self._root_widget, selected_child=sel) except Exception: - ba.print_exception('error restoring state for', self.__class__) + ba.print_exception(f'Error restoring state for {self}.') diff --git a/docs/ba_module.md b/docs/ba_module.md index ed4fc6dc..181f67e7 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-03 for Ballistica version 1.5.0 build 20045

    +

    last updated on 2020-06-04 for Ballistica version 1.5.0 build 20045

    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!


    @@ -2719,7 +2719,7 @@ Results for a completed game.

    ba.Activity.end() call.

    Attributes:

    -
    lower_is_better, playerinfos, score_label, scoretype, sessionteams, winnergroups, winning_team
    +
    lower_is_better, playerinfos, score_label, scoretype, sessionteams, winnergroups, winning_sessionteam

    lower_is_better

    bool

    @@ -2751,39 +2751,37 @@ Results for a completed game.

    Get an ordered list of winner groups.

    -

    winning_team

    +

    winning_sessionteam

    Optional[ba.SessionTeam]

    The winning ba.SessionTeam if there is exactly one, or else None.

    Methods:

    -
    <constructor>, get_team_score(), get_team_score_str(), has_score_for_team(), set_game(), set_team_score()
    +
    <constructor>, get_sessionteam_score(), get_sessionteam_score_str(), has_score_for_sessionteam(), set_game(), set_team_score()

    <constructor>

    ba.GameResults()

    -

    Instantiate a results instance.

    -
    -

    get_team_score()

    -

    get_team_score(self, sessionteam: ba.SessionTeam) -> Optional[int]

    +

    get_sessionteam_score()

    +

    get_sessionteam_score(self, sessionteam: ba.SessionTeam) -> Optional[int]

    Return the score for a given ba.SessionTeam.

    -

    get_team_score_str()

    -

    get_team_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr

    +

    get_sessionteam_score_str()

    +

    get_sessionteam_score_str(self, sessionteam: ba.SessionTeam) -> ba.Lstr

    -

    Return the score for the given ba.Team as an Lstr.

    +

    Return the score for the given session-team as an Lstr.

    (properly formatted for the score type.)

    -

    has_score_for_team()

    -

    has_score_for_team(self, sessionteam: ba.SessionTeam) -> bool

    +

    has_score_for_sessionteam()

    +

    has_score_for_sessionteam(self, sessionteam: ba.SessionTeam) -> bool

    -

    Return whether there is a score for a given team.

    +

    Return whether there is a score for a given session-team.

    set_game()

    @@ -2795,7 +2793,7 @@ Results for a completed game.

    set_team_score()

    set_team_score(self, team: ba.Team, score: Optional[int]) -> None

    -

    Set the score for a given ba.Team.

    +

    Set the score for a given team.

    This can be a number or None. (see the none_is_winner arg in the constructor)

    From 5565b4bfa539e7f6b03dcd4f0a31058ac2e29b1c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 7 Jun 2020 23:17:48 -0700 Subject: [PATCH 079/417] Internal work related to tourney security --- .efrocachemap | 40 +- .idea/dictionaries/ericf.xml | 16 + assets/Makefile | 4908 ++++++++--------- assets/src/ba_data/python/_ba.py | 26 +- assets/src/ba_data/python/ba/_account.py | 2 +- assets/src/ba_data/python/ba/_app.py | 31 +- assets/src/ba_data/python/ba/_apputils.py | 68 +- assets/src/ba_data/python/ba/_campaign.py | 3 + assets/src/ba_data/python/ba/_coopsession.py | 7 +- assets/src/ba_data/python/ba/_gameresults.py | 8 +- assets/src/ba_data/python/ba/_general.py | 2 +- assets/src/ba_data/python/ba/_meta.py | 2 +- assets/src/ba_data/python/ba/_modutils.py | 4 +- assets/src/ba_data/python/ba/_servermode.py | 2 +- assets/src/ba_data/python/ba/osmusic.py | 2 +- assets/src/ba_data/python/bastd/__init__.py | 2 +- assets/src/ba_data/python/bastd/tutorial.py | 6 +- .../ba_data/python/bastd/ui/configerror.py | 2 +- .../ba_data/python/bastd/ui/coop/browser.py | 16 +- .../src/ba_data/python/bastd/ui/feedback.py | 6 +- .../python/bastd/ui/playlist/__init__.py | 4 +- assets/src/ba_data/python/bastd/ui/report.py | 4 +- docs/ba_module.md | 8 +- tools/bacommon/servermanager.py | 4 +- tools/batools/build.py | 2 +- tools/efrotools/__init__.py | 4 +- tools/efrotools/code.py | 16 +- tools/efrotools/ios.py | 6 +- tools/efrotools/snippets.py | 12 +- tools/efrotools/sync.py | 4 +- tools/snippets | 32 +- tools/update_assets_makefile | 12 +- tools/update_project | 6 +- 33 files changed, 2671 insertions(+), 2596 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index b4a793fe..a428af42 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,34 +420,34 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/98/6d/e6de20b119fd6a5914982cd468b6", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d4/df/3ab21c23dedf45ab454b0c4286b1", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/80/b2/b24a9a8395580ef2dea714abf478", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/aa/91/2411c0728bae33619c21237a2689", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f2/90/62968ad28a2499a8d182a5740a85", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", - "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/b4/fe/f33399347c16a13f17e920c7e33c", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/30/f3/4ef3bbaf1e5b7abe114c119ec106", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/95/9b/66e9080c82ef76387832dedee9b4", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/9d/00/a8c4ef9f0a25e789c046bd741203", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/e7/ff/638467708af1e2eea569e9225906", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8e/24/f070599beb7b09e1268569fa55b1", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/7a/64/04464dc6ee8a45632857fa436bff", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/8e/e7/38e093014a917418e6cf7aa9315d", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/05/fbdf4d90b85609e4fa258e1ce814", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/ef/b1935b3767692070f070847f40df", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/a9/bc/ea61ebd23066c685fb779e23d10f", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", - "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/56/f4/b76f1e862b29db5f642a67da67f3", + "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/90/d9/0f8f5b03bbe2dfebfb544cee6bd6", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a9/77/722faae6a695f19501bac76098db", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/30/70/ba6f57b2d865d0027a50c6e1dba5", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/e0/f7/f6daa488dc29e303dea69aae864b", @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/ca/9fa8a48f38554ef676a900136ce9", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e3/2c/f3e52a261f8dabced7a41d925053", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/82/1c63fa091da3fb52bcecf87f8ea6", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/18/a60e9e2f6e37e2f36ca8c8f4f42c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/96/6a/cc35319fd83bca6ff578e4c8dad6", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/a2/b04d489862ae208c6b2b31697519", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/ca/89e007ea20b4f2a3dee09e1361c3", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/cd/f8ad50715cb46d5cae7bd87bb498", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/d1/67a51def178a07f99acc3cc2b11c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/4a/a7a5b56eda157fde6e58a90ab98a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cc/ec/d82c9ba9d587598f8183bc360326", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/2a/f24b48e15ef4fd5794c5e426081b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/2c/09ca7e7ab982a04608a9cee6230b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/d6/25671c9f875c9eb1f25f09d1000f", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/ee/6989965b6929d55044156e41017b", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/e9/c7b41ca260cb04e539cc81fd79c4", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5b/ef/9d427caa8a691f225cbf3e0c649e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/61/63b817195328d360c02c8705405a", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/51/bf8fdbea96a0e76f9203bcd1c427", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/34/ad36c057f3d2c890617a25311cd8", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e3/00/d0cfc8d72ef8dd1567ca7e48a58e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cd/c0/56c8c49c60298727d7593f91928a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/24/d1/d73ae026e9797924e5257d87fe98", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8b/4f/112f32d713898abca7fa465779c1" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 8ba8a5a1..d4fe14f7 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -79,6 +79,8 @@ appkit applescript appletv + appname + appnameupper appstate appstore apputils @@ -155,6 +157,7 @@ basespaz basetime baseurl + baseval basew bastd batools @@ -184,6 +187,7 @@ blas blastos bldtp + blesspath blocksize bluetooth bmag @@ -222,8 +226,11 @@ btnh btnv btnx + buildblessing + buildblessingcheck builddir buildfile + buildnum buildtype bullseye bumpmap @@ -780,6 +787,7 @@ getlevel getlevelname getlevels + getlocalconfig getlog getmaps getmodel @@ -850,6 +858,7 @@ hasstarted hatmotion hattach + hcalc hdpi headercheckline headerregistry @@ -1051,6 +1060,7 @@ lineno linenum linenumber + linenums linetype linetypes linflav @@ -1127,6 +1137,7 @@ markupbase masktex masktexstorename + masterhash mathmodule mathnode mathutils @@ -1148,6 +1159,8 @@ meteorshower mfpath mhash + mhbegin + mhend mhsh microprotocols mikirog @@ -1326,6 +1339,7 @@ osval otherplayer otherspawn + ourhash ourself outdata outdelay @@ -1548,7 +1562,9 @@ pysources pytest pythondontwritebytecode + pythonhashseed pythonpath + pythonpaths pythonw pytree pytz diff --git a/assets/Makefile b/assets/Makefile index 1d120c97..56a530a5 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -619,1147 +619,1147 @@ $(SCRIPT_TARGETS_PY_PUBLIC) : build/%.py : src/%.py build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_account.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_achievement.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_activity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_activitytypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_actor.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_analytics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_app.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_appconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_appdelegate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_apputils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_assetmanager.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_benchmark.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_campaign.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_collision.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_coopgame.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_coopsession.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_dependency.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_dualteamsession.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_enums.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_freeforallsession.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameactivity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameresults.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gamesettings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_general.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_hooks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_input.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_lang.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_level.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_lobby.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_map.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_math.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_messages.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_meta.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_modutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_multiteamsession.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_music.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_netutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_nodeactor.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_player.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_playlist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_powerup.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_profile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_score.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_servermode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_session.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_stats.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_store.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_team.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_teamgame.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_tips.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_tournament.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/deprecated.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/internal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/macmusicapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/osmusic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/ui/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/coopjoin.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/coopscore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/drawscore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/dualteamscore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/freeforallvictory.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamjoin.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamscore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamvictory.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/background.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/bomb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/controlsguide.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/flag.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/image.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/onscreencountdown.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/onscreentimer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/playerspaz.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/popuptext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/powerupbox.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/respawnicon.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/scoreboard.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spawner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spaz.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazappearance.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazbot.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazfactory.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/tipstext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/zoomtext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/appdelegate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/assault.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/capturetheflag.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/chosenone.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/conquest.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/deathmatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/easteregghunt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/elimination.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/football.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/hockey.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/keepaway.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/kingofthehill.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/meteorshower.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/ninjafight.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/onslaught.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/race.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/runaround.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/targetpractice.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/thelaststand.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/gameutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mainmenu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/big_g.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/bridgit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/courtyard.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/crag_castle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/doom_shroom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/football_stadium.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/happy_thoughts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/hockey_stadium.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/lake_frigid.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/monkey_face.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/rampage.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/roundabout.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/step_right_up.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/the_pad.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/tip_top.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/tower_d.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/zig_zag.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/maps.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/session/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/stdmap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/tutorial.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/link.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/settings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/unlink.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/viewer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/achievements.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/appinvite.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/characterpicker.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/colorpicker.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/configerror.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/confirm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/continues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/browser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/gamebutton.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/level.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/creditslist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/debug.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/feedback.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/fileselector.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/gather.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/getcurrency.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/getremote.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/helpui.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/iconpicker.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/kiosk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankbutton.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankwindow.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/mainmenu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/onscreenkeyboard.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/party.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/partyqueue.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/play.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/addgame.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/browser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/customizebrowser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/edit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/editcontroller.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/editgame.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/mapselect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/share.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playoptions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/popup.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/browser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/edit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/upgrade.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/promocode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/purchase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/qrcode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/radiogroup.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/report.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/resourcetypeinfo.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/serverdialog.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/advanced.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/allsettings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/audio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/controls.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepad.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepadadvanced.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepadselect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/graphics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/keyboard.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/nettesting.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/ps3controller.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/remoteapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/testing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/touchscreen.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/vrtesting.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/wiimote.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/xbox360controller.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/browser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/edit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/specialoffer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/browser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/button.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/item.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tabs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/teamnamescolors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/telnet.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tournamententry.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tournamentscores.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/trophies.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/url.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/watch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc: \ build/server/ballisticacore_server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \ @@ -1818,92 +1818,92 @@ $(SCRIPT_TARGETS_PY_PUBLIC_TOOLS) : build/ba_data/python/%.py : ../tools/%.py build/ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bacommon/__pycache__/assets.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/assets.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/err.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/servermanager.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/call.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_entity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_field.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_value.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/json.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/terminal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ #AUTOGENERATED_END_PUBLIC @@ -2777,2132 +2777,2132 @@ $(SCRIPT_TARGETS_PY_PRIVATE_APPLE) : ../.efrocachemap build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/pylib-apple/__future__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/pylib-apple/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/pylib-apple/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/pylib-apple/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/pylib-apple/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/pylib-apple/_compression.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/pylib-apple/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/pylib-apple/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/pylib-apple/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/pylib-apple/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/pylib-apple/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/pylib-apple/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/pylib-apple/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/pylib-apple/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/pylib-apple/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/pylib-apple/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/pylib-apple/aifc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/pylib-apple/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/pylib-apple/argparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc: \ build/pylib-apple/ast.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/pylib-apple/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ build/pylib-apple/base64.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/pylib-apple/bdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/pylib-apple/binhex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/pylib-apple/bisect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/pylib-apple/bz2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/pylib-apple/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/pylib-apple/calendar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/pylib-apple/cgi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/pylib-apple/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/pylib-apple/chunk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/pylib-apple/cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ build/pylib-apple/code.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/pylib-apple/codecs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/pylib-apple/codeop.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/pylib-apple/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/pylib-apple/compileall.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/pylib-apple/configparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/pylib-apple/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/pylib-apple/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ build/pylib-apple/copy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/pylib-apple/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/pylib-apple/crypt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ build/pylib-apple/csv.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/pylib-apple/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/pylib-apple/datetime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/pylib-apple/decimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/pylib-apple/difflib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ build/pylib-apple/dis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/pylib-apple/doctest.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/pylib-apple/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/pylib-apple/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/pylib-apple/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/pylib-apple/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/pylib-apple/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/pylib-apple/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/pylib-apple/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/pylib-apple/email/header.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/pylib-apple/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/pylib-apple/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-apple/email/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/pylib-apple/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/pylib-apple/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/pylib-apple/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ build/pylib-apple/enum.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/pylib-apple/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/pylib-apple/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/pylib-apple/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/pylib-apple/formatter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/pylib-apple/fractions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/pylib-apple/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ build/pylib-apple/functools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/pylib-apple/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/pylib-apple/getopt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/pylib-apple/getpass.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/pylib-apple/gettext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ build/pylib-apple/glob.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/pylib-apple/gzip.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/pylib-apple/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/pylib-apple/heapq.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/pylib-apple/hmac.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/pylib-apple/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-apple/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-apple/http/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/pylib-apple/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/pylib-apple/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-apple/http/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/pylib-apple/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ build/pylib-apple/imp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/pylib-apple/inspect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ build/pylib-apple/io.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/pylib-apple/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/pylib-apple/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/pylib-apple/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/pylib-apple/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/pylib-apple/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/pylib-apple/keyword.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/pylib-apple/linecache.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ build/pylib-apple/locale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-apple/lzma.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/pylib-apple/macpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-apple/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-apple/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/pylib-apple/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-apple/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/pylib-apple/netrc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/pylib-apple/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/pylib-apple/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-apple/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/pylib-apple/numbers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-apple/opcode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-apple/operator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/pylib-apple/optparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ build/pylib-apple/os.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/pylib-apple/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/pylib-apple/pdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/pylib-apple/pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/pylib-apple/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/pylib-apple/pipes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/pylib-apple/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ build/pylib-apple/platform.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/pylib-apple/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/pylib-apple/poplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/pylib-apple/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/pylib-apple/pprint.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ build/pylib-apple/profile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/pylib-apple/pstats.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ build/pylib-apple/pty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/pylib-apple/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/pylib-apple/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/pylib-apple/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ build/pylib-apple/queue.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/pylib-apple/quopri.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ build/pylib-apple/random.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ build/pylib-apple/re.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/pylib-apple/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/pylib-apple/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/pylib-apple/runpy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ build/pylib-apple/sched.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/pylib-apple/secrets.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/pylib-apple/selectors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/pylib-apple/shelve.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/pylib-apple/shlex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/pylib-apple/shutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ build/pylib-apple/signal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ build/pylib-apple/site.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/pylib-apple/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/pylib-apple/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/pylib-apple/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ build/pylib-apple/socket.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/pylib-apple/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/pylib-apple/ssl.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ build/pylib-apple/stat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/pylib-apple/statistics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ build/pylib-apple/string.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/pylib-apple/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ build/pylib-apple/struct.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/pylib-apple/sunau.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/pylib-apple/symbol.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/pylib-apple/symtable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/pylib-apple/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/pylib-apple/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/pylib-apple/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/pylib-apple/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/pylib-apple/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/pylib-apple/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ build/pylib-apple/this.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ build/pylib-apple/threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/pylib-apple/timeit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ build/pylib-apple/token.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/pylib-apple/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ build/pylib-apple/trace.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/pylib-apple/traceback.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/pylib-apple/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ build/pylib-apple/tty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ build/pylib-apple/types.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ build/pylib-apple/typing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ build/pylib-apple/uu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/pylib-apple/uuid.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/pylib-apple/warnings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ build/pylib-apple/wave.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/pylib-apple/weakref.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/pylib-apple/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/pylib-apple/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/pylib-apple/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/pylib-apple/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ @@ -5773,2132 +5773,2132 @@ $(SCRIPT_TARGETS_PY_PRIVATE_ANDROID) : ../.efrocachemap build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/pylib-android/__future__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/pylib-android/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/pylib-android/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/pylib-android/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/pylib-android/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/pylib-android/_compression.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/pylib-android/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/pylib-android/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/pylib-android/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/pylib-android/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/pylib-android/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/pylib-android/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/pylib-android/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/pylib-android/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/pylib-android/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/pylib-android/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/pylib-android/aifc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/pylib-android/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/pylib-android/argparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc: \ build/pylib-android/ast.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/pylib-android/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/pylib-android/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ build/pylib-android/base64.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/pylib-android/bdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/pylib-android/binhex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/pylib-android/bisect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/pylib-android/bz2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/pylib-android/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/pylib-android/calendar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/pylib-android/cgi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/pylib-android/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/pylib-android/chunk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/pylib-android/cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ build/pylib-android/code.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/pylib-android/codecs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/pylib-android/codeop.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/pylib-android/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/pylib-android/compileall.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/pylib-android/configparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/pylib-android/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/pylib-android/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ build/pylib-android/copy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/pylib-android/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/pylib-android/crypt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ build/pylib-android/csv.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-android/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/pylib-android/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/pylib-android/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/pylib-android/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/pylib-android/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/pylib-android/datetime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/pylib-android/decimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/pylib-android/difflib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ build/pylib-android/dis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/pylib-android/doctest.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/pylib-android/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/pylib-android/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/pylib-android/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/pylib-android/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/pylib-android/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/pylib-android/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/pylib-android/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/pylib-android/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/pylib-android/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/pylib-android/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/pylib-android/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/pylib-android/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/pylib-android/email/header.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/pylib-android/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/pylib-android/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-android/email/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-android/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/pylib-android/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/pylib-android/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/pylib-android/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ build/pylib-android/enum.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/pylib-android/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/pylib-android/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/pylib-android/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/pylib-android/formatter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/pylib-android/fractions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/pylib-android/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ build/pylib-android/functools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/pylib-android/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/pylib-android/getopt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/pylib-android/getpass.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/pylib-android/gettext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ build/pylib-android/glob.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/pylib-android/gzip.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/pylib-android/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/pylib-android/heapq.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/pylib-android/hmac.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/pylib-android/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-android/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-android/http/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/pylib-android/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/pylib-android/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-android/http/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/pylib-android/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ build/pylib-android/imp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/pylib-android/inspect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ build/pylib-android/io.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/pylib-android/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/pylib-android/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/pylib-android/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/pylib-android/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/pylib-android/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/pylib-android/keyword.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/pylib-android/linecache.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ build/pylib-android/locale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/pylib-android/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/pylib-android/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-android/lzma.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/pylib-android/macpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-android/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-android/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/pylib-android/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-android/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/pylib-android/netrc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/pylib-android/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/pylib-android/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-android/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/pylib-android/numbers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-android/opcode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-android/operator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/pylib-android/optparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ build/pylib-android/os.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/pylib-android/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/pylib-android/pdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/pylib-android/pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/pylib-android/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/pylib-android/pipes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/pylib-android/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ build/pylib-android/platform.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/pylib-android/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/pylib-android/poplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/pylib-android/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/pylib-android/pprint.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ build/pylib-android/profile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/pylib-android/pstats.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ build/pylib-android/pty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/pylib-android/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/pylib-android/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/pylib-android/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ build/pylib-android/queue.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/pylib-android/quopri.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ build/pylib-android/random.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ build/pylib-android/re.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/pylib-android/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/pylib-android/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/pylib-android/runpy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ build/pylib-android/sched.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/pylib-android/secrets.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/pylib-android/selectors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/pylib-android/shelve.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/pylib-android/shlex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/pylib-android/shutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ build/pylib-android/signal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ build/pylib-android/site.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/pylib-android/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/pylib-android/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/pylib-android/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ build/pylib-android/socket.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/pylib-android/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/pylib-android/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/pylib-android/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/pylib-android/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/pylib-android/ssl.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ build/pylib-android/stat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/pylib-android/statistics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ build/pylib-android/string.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/pylib-android/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ build/pylib-android/struct.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/pylib-android/sunau.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/pylib-android/symbol.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/pylib-android/symtable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/pylib-android/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/pylib-android/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/pylib-android/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/pylib-android/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/pylib-android/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/pylib-android/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ build/pylib-android/this.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ build/pylib-android/threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/pylib-android/timeit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ build/pylib-android/token.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/pylib-android/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ build/pylib-android/trace.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/pylib-android/traceback.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/pylib-android/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ build/pylib-android/tty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ build/pylib-android/types.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ build/pylib-android/typing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ build/pylib-android/uu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/pylib-android/uuid.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/pylib-android/warnings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ build/pylib-android/wave.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/pylib-android/weakref.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/pylib-android/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/pylib-android/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/pylib-android/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/pylib-android/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/pylib-android/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_COMMON = \ @@ -7953,92 +7953,92 @@ $(SCRIPT_TARGETS_PY_PRIVATE_COMMON) : ../.efrocachemap build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/typing_extensions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/composer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/constructor.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/cyaml.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/dumper.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/emitter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/loader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/nodes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/parser.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/reader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/representer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/resolver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/scanner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/serializer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/tokens.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ @@ -9393,3342 +9393,3342 @@ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32) : ../.efrocachemap build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/__future__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_compression.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/aifc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/argparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ast.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/base64.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/binhex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bisect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bz2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/calendar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cgi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/chunk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/code.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/codecs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/codeop.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/compileall.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/configparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/copy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/crypt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/csv.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_anon.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_arrays.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_as_parameter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_bitfields.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_buffers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_bytes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_byteswap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_callbacks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_cast.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_cfuncs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_checkretval.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_delattr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_errno.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_find.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_frombuffer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_funcptr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_functions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_incomplete.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_init.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_internals.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_keeprefs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_libc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_loading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_macholib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_memfunctions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_numbers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_objects.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_parameters.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pep3118.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_values.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/datetime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/dumb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/gnu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/ndbm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/decimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/difflib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/archive_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/ccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_clib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_py.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/check.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/clean.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_data.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_egg_info.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_headers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_lib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/register.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/sdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/upload.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/core.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/debug.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dep_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dir_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/errors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/extension.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/fancy_getopt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/file_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/filelist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/spawn.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_archive_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_clib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_py.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_check.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_clean.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_config_cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_core.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dep_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dir_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_extension.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_file_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_filelist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_data.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_headers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_lib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_register.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_sdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_spawn.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_text_file.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_upload.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_version.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/text_file.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/version.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/doctest.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/header.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/_uninstall.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/enum.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/formatter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fractions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/functools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/getopt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/getpass.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/gettext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/glob.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/gzip.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/heapq.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/hmac.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imaplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/inspect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/io.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/keyword.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/linecache.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/locale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/lzma.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/macpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/schema.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/sequence.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/connection.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/context.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/heap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/managers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/pool.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/process.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/queues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/reduction.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/spawn.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/netrc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/numbers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/opcode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/operator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/optparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/os.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pipes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/platform.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/poplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pprint.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/profile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pstats.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc_data/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc_data/topics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/queue.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/quopri.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/random.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/re.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/runpy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sched.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/secrets.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/selectors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shelve.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shlex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/signal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/site.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/socket.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/backup.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/dump.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/factory.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/regression.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/types.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ssl.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/stat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/statistics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/string.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/struct.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sunau.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/symbol.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/symtable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/this.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/timeit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/token.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/trace.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/traceback.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/turtle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/types.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/typing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/case.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/loader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/main.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/mock.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/result.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/runner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/signals.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/suite.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/_test_warnings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/dummy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_break.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_case.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_discovery.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_loader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_program.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_result.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_runner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_setups.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_skipping.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_suite.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/uu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/uuid.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/venv/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/venv/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/warnings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wave.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/weakref.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/handlers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/headers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/simple_server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/validate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ @@ -14083,3342 +14083,3342 @@ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_X64) : ../.efrocachemap build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/__future__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_compression.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/aifc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/argparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ast.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/base64.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/binhex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bisect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bz2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/calendar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cgi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/chunk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/code.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/codecs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/codeop.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/compileall.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/configparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/copy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/crypt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/csv.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_anon.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_arrays.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_as_parameter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_bitfields.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_buffers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_bytes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_byteswap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_callbacks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_cast.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_cfuncs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_checkretval.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_delattr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_errno.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_find.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_frombuffer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_funcptr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_functions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_incomplete.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_init.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_internals.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_keeprefs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_libc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_loading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_macholib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_memfunctions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_numbers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_objects.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_parameters.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pep3118.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_values.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/datetime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/dumb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/gnu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/ndbm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/decimal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/difflib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/archive_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/ccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_clib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_py.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/check.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/clean.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_data.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_egg_info.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_headers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_lib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/register.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/sdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/upload.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/core.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/debug.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dep_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dir_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/errors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/extension.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/fancy_getopt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/file_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/filelist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/spawn.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_archive_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_clib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_py.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_check.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_clean.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_config_cmd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_core.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dep_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dir_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_extension.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_file_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_filelist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_data.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_headers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_lib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_log.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_register.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_sdist.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_spawn.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_text_file.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_upload.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_version.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/text_file.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/version.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/doctest.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/header.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/_uninstall.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/enum.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/formatter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fractions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/functools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/getopt.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/getpass.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/gettext.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/glob.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/gzip.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/heapq.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/hmac.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imaplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/inspect.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/io.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/keyword.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/linecache.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/locale.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/lzma.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/macpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/schema.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/sequence.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/text.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/connection.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/context.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/heap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/managers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/pool.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/process.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/queues.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/reduction.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/spawn.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/netrc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/numbers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/opcode.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/operator.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/optparse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/os.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pdb.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pickle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pipes.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/platform.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/poplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pprint.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/profile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pstats.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc_data/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc_data/topics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/queue.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/quopri.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/random.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/re.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/runpy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sched.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/secrets.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/selectors.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shelve.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shlex.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shutil.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/signal.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/site.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/socket.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/backup.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/dump.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/factory.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/regression.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/types.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ssl.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/stat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/statistics.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/string.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/struct.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sunau.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/symbol.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/symtable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/this.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/threading.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/timeit.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/token.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/trace.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/traceback.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tty.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/turtle.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/types.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/typing.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/case.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/loader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/main.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/mock.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/result.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/runner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/signals.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/suite.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/_test_warnings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/dummy.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_break.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_case.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_discovery.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_loader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_program.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_result.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_runner.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_setups.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_skipping.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_suite.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/uu.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/uuid.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/venv/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/venv/__main__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/warnings.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wave.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/weakref.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/handlers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/headers.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/simple_server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/util.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/validate.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ COB_TARGETS = \ @@ -20211,7 +20211,7 @@ scripts-android: $(SCRIPT_TARGETS_ANDROID) $(SCRIPT_TARGETS_COMMON) # Build scripts for all platforms scripts: scripts-cmake scripts-win scripts-mac scripts-ios scripts-android clean-scripts: - rm -rf build/ba_data/scripts + rm -rf build/ba_data/python # Build all required assets for a specific platform. assets-cmake: $(ASSET_TARGETS_CMAKE) $(ASSET_TARGETS_COMMON) diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 4fb9bba5..bb999180 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=102801821147286215106809880997032542189 +# SOURCES_HASH=197797300249336200681012613336602141418 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression @@ -1334,6 +1334,22 @@ def apply_config() -> None: return None +def appname() -> str: + """appname() -> str + + (internal) + """ + return str() + + +def appnameupper() -> str: + """appnameupper() -> str + + (internal) + """ + return str() + + def back_press() -> None: """back_press() -> None @@ -2708,6 +2724,14 @@ def invite_players() -> None: return None +def is_blessed() -> bool: + """is_blessed() -> bool + + (internal) + """ + return bool() + + def is_in_replay() -> bool: """is_in_replay() -> bool diff --git a/assets/src/ba_data/python/ba/_account.py b/assets/src/ba_data/python/ba/_account.py index 228fa8fb..a355ed54 100644 --- a/assets/src/ba_data/python/ba/_account.py +++ b/assets/src/ba_data/python/ba/_account.py @@ -163,7 +163,7 @@ def have_pro() -> bool: return bool( _ba.get_purchased('upgrades.pro') or _ba.get_purchased('static.pro') or _ba.get_purchased('static.pro_sale') - or 'ballistica' + 'core' == 'ballisticacore') + or 'ballistica' + 'core' == _ba.appname()) def have_pro_options() -> bool: diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 946a8908..9232a9ee 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -185,14 +185,14 @@ class App: return self._python_directory_user @property - def python_directory_ba(self) -> str: + def python_directory_app(self) -> str: """Path where the app looks for its bundled scripts.""" - return self._python_directory_ba + return self._python_directory_app @property - def python_directory_site(self) -> str: + def python_directory_app_site(self) -> str: """Path containing pip packages bundled with the app.""" - return self._python_directory_site + return self._python_directory_app_site @property def config(self) -> ba.AppConfig: @@ -297,10 +297,10 @@ class App: assert isinstance(self._test_build, bool) self._python_directory_user: str = env['python_directory_user'] assert isinstance(self._python_directory_user, str) - self._python_directory_ba: str = env['python_directory_ba'] - assert isinstance(self._python_directory_ba, str) - self._python_directory_site: str = env['python_directory_site'] - assert isinstance(self._python_directory_site, str) + self._python_directory_app: str = env['python_directory_app'] + assert isinstance(self._python_directory_app, str) + self._python_directory_app_site: str = env['python_directory_app_site'] + assert isinstance(self._python_directory_app_site, str) self._platform: str = env['platform'] assert isinstance(self._platform, str) self._subplatform: str = env['subplatform'] @@ -325,7 +325,6 @@ class App: self.metascan: Optional[_meta.ScanResults] = None self.tips: List[str] = [] self.stress_test_reset_timer: Optional[ba.Timer] = None - self.suppress_debug_reports = False self.last_ad_completion_time: Optional[float] = None self.last_ad_was_short = False self.did_weak_call_warning = False @@ -477,8 +476,11 @@ class App: ]: _map.register_map(maptype) - if self.debug_build: - _apputils.suppress_debug_reports() + # Non-test, non-debug builds should generally be blessed; warn if not. + # (so I don't accidentally release a build that can't play tourneys) + if (not self.debug_build and not self.test_build + and not _ba.is_blessed()): + _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0)) # IMPORTANT - if tweaking UI stuff, you need to make sure it behaves # for small, medium, and large UI modes. (doesn't run off screen, etc). @@ -526,7 +528,7 @@ class App: # Notify the user if we're using custom system scripts. # FIXME: This no longer works since sys-scripts is an absolute path; # need to just add a proper call to query this. - # if env['python_directory_ba'] != 'data/scripts': + # if env['python_directory_app'] != 'data/scripts': # ba.screenmessage("Using custom system scripts...", # color=(0, 1, 0)) @@ -795,8 +797,9 @@ class App: """Handle a deep link URL.""" from ba._lang import Lstr from ba._enums import TimeType - if url.startswith('ballisticacore://code/'): - code = url.replace('ballisticacore://code/', '') + appname = _ba.appname() + if url.startswith(f'{appname}://code/'): + code = url.replace(f'{appname}://code/', '') # If we're not signed in, queue up the code to run the next time we # are and issue a warning if we haven't signed in within the next diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index cf0f0137..a2ae13b1 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -67,15 +67,6 @@ def should_submit_debug_info() -> bool: return _ba.app.config.get('Submit Debug Info', True) -def suppress_debug_reports() -> None: - """Turn debug-reporting to the master server off. - - This should be called in devel/debug situations to avoid spamming - the master server with spurious logs. - """ - _ba.app.suppress_debug_reports = True - - def handle_log() -> None: """Called on debug log prints. @@ -89,37 +80,38 @@ def handle_log() -> None: if not app.log_upload_timer_started: def _put_log() -> None: - if not app.suppress_debug_reports: - try: - sessionname = str(_ba.get_foreground_host_session()) - except Exception: - sessionname = 'unavailable' - try: - activityname = str(_ba.get_foreground_host_activity()) - except Exception: - activityname = 'unavailable' - info = { - 'log': _ba.getlog(), - 'version': app.version, - 'build': app.build_number, - 'userAgentString': app.user_agent_string, - 'session': sessionname, - 'activity': activityname, - 'fatal': 0, - 'userRanCommands': _ba.has_user_run_commands(), - 'time': _ba.time(TimeType.REAL), - 'userModded': _ba.has_user_mods() - } + try: + sessionname = str(_ba.get_foreground_host_session()) + except Exception: + sessionname = 'unavailable' + try: + activityname = str(_ba.get_foreground_host_activity()) + except Exception: + activityname = 'unavailable' - def response(data: Any) -> None: - # A non-None response means success; lets - # take note that we don't need to report further - # log info this run - if data is not None: - app.log_have_new = False - _ba.mark_log_sent() + info = { + 'log': _ba.getlog(), + 'version': app.version, + 'build': app.build_number, + 'userAgentString': app.user_agent_string, + 'session': sessionname, + 'activity': activityname, + 'fatal': 0, + 'userRanCommands': _ba.has_user_run_commands(), + 'time': _ba.time(TimeType.REAL), + 'userModded': _ba.has_user_mods(), + 'newsShow': _ba.get_news_show(), + } - serverput('bsLog', info, response) + def response(data: Any) -> None: + # A non-None response means success; lets + # take note that we don't need to report further + # log info this run + if data is not None: + app.log_have_new = False + _ba.mark_log_sent() + + serverput('bsLog', info, response) app.log_upload_timer_started = True diff --git a/assets/src/ba_data/python/ba/_campaign.py b/assets/src/ba_data/python/ba/_campaign.py index 6fd832e6..30554edf 100644 --- a/assets/src/ba_data/python/ba/_campaign.py +++ b/assets/src/ba_data/python/ba/_campaign.py @@ -122,6 +122,9 @@ def init_campaigns() -> None: from bastd.game.easteregghunt import EasterEggHuntGame from bastd.game.ninjafight import NinjaFightGame + # TODO: Campaigns should be load-on-demand; not all imported at launch + # like this. + # FIXME: Once translations catch up, we can convert these to use the # generic display-name '${GAME} Training' type stuff. campaign = Campaign('Easy') diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 2ee47cc9..e6c9dcaf 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -264,10 +264,7 @@ class CoopSession(Session): if isinstance(results, GameResults): outcome = 'defeat' # This can't be 'beaten'. else: - try: - outcome = results['outcome'] - except Exception: - outcome = '' + outcome = '' if results is None else results.get('outcome', '') # If at any point we have no in-game players, quit out of the session # (this can happen if someone leaves in the tutorial for instance). @@ -315,7 +312,7 @@ class CoopSession(Session): self.stats.register_sessionplayer(player) self.stats.setactivity(next_game) - # Now flip the current activity. + # Now flip the current activity.. self.setactivity(next_game) if not app.kiosk_mode: diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index c58d9d2c..cce6f6b3 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -26,6 +26,8 @@ import weakref from dataclasses import dataclass from typing import TYPE_CHECKING +from ba._team import Team, SessionTeam + if TYPE_CHECKING: from weakref import ReferenceType from typing import Sequence, Tuple, Any, Optional, Dict, List, Union @@ -66,7 +68,9 @@ class GameResults: if self._game_set: raise RuntimeError('Game set twice for GameResults.') self._game_set = True - self._sessionteams = [weakref.ref(team) for team in game.teams] + self._sessionteams = [ + weakref.ref(team.sessionteam) for team in game.teams + ] scoreconfig = game.getscoreconfig() self._playerinfos = copy.deepcopy(game.initialplayerinfos) self._lower_is_better = scoreconfig.lower_is_better @@ -80,12 +84,14 @@ class GameResults: This can be a number or None. (see the none_is_winner arg in the constructor) """ + assert isinstance(team, Team) sessionteam = team.sessionteam self._scores[sessionteam.id] = (weakref.ref(sessionteam), score) def get_sessionteam_score(self, sessionteam: ba.SessionTeam) -> Optional[int]: """Return the score for a given ba.SessionTeam.""" + assert isinstance(sessionteam, SessionTeam) for score in list(self._scores.values()): if score[0]() is sessionteam: return score[1] diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 43eff04b..d1ebc5c5 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -89,7 +89,7 @@ def getclass(name: str, subclassof: Type[T]) -> Type[T]: cls: Type = getattr(module, classname) if not issubclass(cls, subclassof): - raise TypeError(name + ' is not a subclass of ' + str(subclassof)) + raise TypeError(f'{name} is not a subclass of {subclassof}.') return cls diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index 1de050db..14669765 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -56,7 +56,7 @@ def start_scan() -> None: app = _ba.app if app.metascan is not None: print('WARNING: meta scan run more than once.') - scriptdirs = [app.python_directory_ba, app.python_directory_user] + scriptdirs = [app.python_directory_app, app.python_directory_user] thread = ScanThread(scriptdirs) thread.start() diff --git a/assets/src/ba_data/python/ba/_modutils.py b/assets/src/ba_data/python/ba/_modutils.py index 11e33021..f7645821 100644 --- a/assets/src/ba_data/python/ba/_modutils.py +++ b/assets/src/ba_data/python/ba/_modutils.py @@ -119,9 +119,9 @@ def create_user_system_scripts() -> None: # 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_ba + src_dir = app.python_directory_app dst_dir = path + '_tmp' - filenames = os.listdir(app.python_directory_ba) + 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) diff --git a/assets/src/ba_data/python/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py index 882aa6ac..a8c75328 100644 --- a/assets/src/ba_data/python/ba/_servermode.py +++ b/assets/src/ba_data/python/ba/_servermode.py @@ -321,7 +321,7 @@ class ServerController: if self._first_run: curtimestr = time.strftime('%c') - print(f'{Clr.BLD}{Clr.BLU}BallisticaCore {app.version}' + print(f'{Clr.BLD}{Clr.BLU}{_ba.appnameupper()} {app.version}' f' ({app.build_number})' f' entering server-mode {curtimestr}{Clr.RST}') diff --git a/assets/src/ba_data/python/ba/osmusic.py b/assets/src/ba_data/python/ba/osmusic.py index 38a097c8..0b7c4a36 100644 --- a/assets/src/ba_data/python/ba/osmusic.py +++ b/assets/src/ba_data/python/ba/osmusic.py @@ -71,7 +71,7 @@ class OSMusicPlayer(MusicPlayer): elif entry_type == 'musicFolder': # Launch a thread to scan this folder and give us a random - # valid file within. + # valid file within it. self._want_to_play = True self._actually_playing = False _PickFolderSongThread(name, self.get_valid_music_file_extensions(), diff --git a/assets/src/ba_data/python/bastd/__init__.py b/assets/src/ba_data/python/bastd/__init__.py index ab76b753..e3ca3287 100644 --- a/assets/src/ba_data/python/bastd/__init__.py +++ b/assets/src/ba_data/python/bastd/__init__.py @@ -18,6 +18,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ----------------------------------------------------------------------------- -"""BallisticaCore standard library: games, UI, etc.""" +"""Ballistica standard library: games, UI, etc.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index 3aa0ca0d..9f66f8e4 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -239,7 +239,6 @@ class TutorialActivity(ba.Activity[Player, Team]): self.bomb_image_color = (1.0, 1.0, 1.0) self.pickup_image_color = (1.0, 1.0, 1.0) self.control_ui_nodes: List[ba.Node] = [] - self._test_file = '' self.spazzes: Dict[int, basespaz.Spaz] = {} self.jump_image_color = (1.0, 1.0, 1.0) self._entries: List[Any] = [] @@ -400,9 +399,6 @@ class TutorialActivity(ba.Activity[Player, Team]): ] for n in self.control_ui_nodes: n.opacity = 0.0 - self._test_file = ('/Users/ericf/Library/Containers/' - 'net.froemling.ballisticacore/Data/' - 'Library/Application Support/Ballisticacore/foo.py') self._read_entries() def set_stick_image_position(self, x: float, y: float) -> None: @@ -844,7 +840,7 @@ class TutorialActivity(ba.Activity[Player, Team]): ba.Lstr(resource=self._r + '.phrase02Text', subs=[ ('${APP_NAME}', ba.Lstr(resource='titleText')) - ])), # welcome to ballisticacore + ])), # welcome to DelayOld(80), Run(release=False), Jump(release=False), diff --git a/assets/src/ba_data/python/bastd/ui/configerror.py b/assets/src/ba_data/python/bastd/ui/configerror.py index 3d6bfc64..721dac05 100644 --- a/assets/src/ba_data/python/bastd/ui/configerror.py +++ b/assets/src/ba_data/python/bastd/ui/configerror.py @@ -47,7 +47,7 @@ class ConfigErrorWindow(ba.Window): h_align='center', v_align='top', scale=0.73, - text=('Error reading BallisticaCore config file' + text=(f'Error reading {_ba.appnameupper()} config file' ':\n\n\nCheck the console' ' (press ~ twice) for details.\n\nWould you like to quit and' ' try to fix it by hand\nor overwrite it with defaults?\n\n' diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 396dead6..ac12a22a 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -61,6 +61,16 @@ class CoopBrowserWindow(ba.Window): app = ba.app cfg = app.config + # Quick note to players that tourneys won't work if we're a non-blessed + # or a debug build... + if not _ba.is_blessed() or ba.app.debug_build: + ba.timer(1.0, + lambda: ba.screenmessage( + ba.Lstr(resource='noTournamentsInTestBuildText'), + color=(1, 1, 0), + ), + timetype=ba.TimeType.REAL) + # If they provided an origin-widget, scale up from that. scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: @@ -99,10 +109,8 @@ class CoopBrowserWindow(ba.Window): size=(self._width, self._height + top_extra), toolbar_visibility='menu_full', scale_origin_stack_offset=scale_origin, - stack_offset=(0, - -15) if app.small_ui else (0, - 0) if app.med_ui else (0, - 0), + stack_offset=((0, -15) if app.small_ui else ( + 0, 0) if app.med_ui else (0, 0)), transition=transition, scale=1.2 if app.small_ui else 0.8 if app.med_ui else 0.75)) diff --git a/assets/src/ba_data/python/bastd/ui/feedback.py b/assets/src/ba_data/python/bastd/ui/feedback.py index b762abd0..303b76a6 100644 --- a/assets/src/ba_data/python/bastd/ui/feedback.py +++ b/assets/src/ba_data/python/bastd/ui/feedback.py @@ -66,11 +66,13 @@ def ask_for_rating() -> Optional[ba.Widget]: v_align='center') def do_rating() -> None: + import _ba if platform == 'android': + appname = _ba.appname() if subplatform == 'google': - url = 'market://details?id=net.froemling.ballisticacore' + url = f'market://details?id=net.froemling.{appname}' else: - url = 'market://details?id=net.froemling.ballisticacorecb' + url = 'market://details?id=net.froemling.{appname}cb' else: url = 'macappstore://itunes.apple.com/app/id416482767?ls=1&mt=12' diff --git a/assets/src/ba_data/python/bastd/ui/playlist/__init__.py b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py index 46f37970..be0fa4c7 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py @@ -61,8 +61,8 @@ class PlaylistTypeVars: self.sessiontype = ba.FreeForAllSession else: - raise TypeError('playlist type vars undefined for session type: ' + - str(sessiontype)) + raise RuntimeError( + f'Playlist type vars undefined for sessiontype: {sessiontype}') self.default_list_name = ba.Lstr(resource='defaultGameListNameText', subs=[('${PLAYMODE}', play_mode_name) ]) diff --git a/assets/src/ba_data/python/bastd/ui/report.py b/assets/src/ba_data/python/bastd/ui/report.py index 01652805..a649b627 100644 --- a/assets/src/ba_data/python/bastd/ui/report.py +++ b/assets/src/ba_data/python/bastd/ui/report.py @@ -87,7 +87,7 @@ class ReportPlayerWindow(ba.Window): }) body = ba.Lstr(resource='reportPlayerExplanationText').evaluate() ba.open_url('mailto:support@froemling.net' - '?subject=BallisticaCore Player Report: ' + + f'?subject={_ba.appnameupper()} Player Report: ' + self._account_id + '&body=' + parse.quote(body)) self.close() @@ -100,7 +100,7 @@ class ReportPlayerWindow(ba.Window): }) body = ba.Lstr(resource='reportPlayerExplanationText').evaluate() ba.open_url('mailto:support@froemling.net' - '?subject=BallisticaCore Player Report: ' + + f'?subject={_ba.appnameupper()} Player Report: ' + self._account_id + '&body=' + parse.quote(body)) self.close() diff --git a/docs/ba_module.md b/docs/ba_module.md index 181f67e7..9df04a28 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-04 for Ballistica version 1.5.0 build 20045

    +

    last updated on 2020-06-07 for Ballistica version 1.5.0 build 20059

    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!


    @@ -805,7 +805,7 @@ likely result in errors.

    Attributes:

    -
    api_version, build_number, config, config_file_path, debug_build, interface_type, language, locale, on_tv, platform, python_directory_ba, python_directory_site, python_directory_user, subplatform, test_build, ui_bounds, user_agent_string, version, vr_mode
    +
    api_version, build_number, config, config_file_path, debug_build, interface_type, language, locale, on_tv, platform, python_directory_app, python_directory_app_site, python_directory_user, subplatform, test_build, ui_bounds, user_agent_string, version, vr_mode

    api_version

    int

    @@ -886,12 +886,12 @@ likely result in errors.

    Examples are: 'mac', 'windows', android'.

    -

    python_directory_ba

    +

    python_directory_app

    str

    Path where the app looks for its bundled scripts.

    -

    python_directory_site

    +

    python_directory_app_site

    str

    Path containing pip packages bundled with the app.

    diff --git a/tools/bacommon/servermanager.py b/tools/bacommon/servermanager.py index afa1d87d..732250ff 100644 --- a/tools/bacommon/servermanager.py +++ b/tools/bacommon/servermanager.py @@ -31,7 +31,7 @@ if TYPE_CHECKING: @dataclass class ServerConfig: - """Configuration for the server manager app (ballisticacore_server).""" + """Configuration for the server manager app (_server).""" # Name of our server in the public parties list. party_name: str = 'FFA' @@ -87,7 +87,7 @@ class ServerConfig: # Whether to enable telnet access. # IMPORTANT: This option is no longer available, as it was being used # for exploits. Live access to the running server is still possible through - # the mgr.cmd() function in ballisticacore_server. Run your server through + # the mgr.cmd() function in the server script. Run your server through # tools such as 'screen' or 'tmux' and you can reconnect to it remotely # over a secure ssh connection. enable_telnet: bool = False diff --git a/tools/batools/build.py b/tools/batools/build.py index f36b2e8c..f65643ba 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -158,7 +158,7 @@ def _lazybuild_check_paths(inpaths: List[str], category: SourceCategory, if _testpath(fpath): return True unchanged_count += 1 - print(f'{Clr.SBLU}Lazybuild: skipping "{tnamepretty}"' + print(f'{Clr.BLU}Lazybuild: skipping "{tnamepretty}"' f' ({unchanged_count} inputs unchanged).{Clr.RST}') return False diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index cbb2cf98..b89d640b 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -70,7 +70,7 @@ def explicit_bool(value: bool) -> bool: return value -def get_localconfig(projroot: Path) -> Dict[str, Any]: +def getlocalconfig(projroot: Path) -> Dict[str, Any]: """Return a project's localconfig contents (or default if missing).""" localconfig: Dict[str, Any] try: @@ -81,7 +81,7 @@ def get_localconfig(projroot: Path) -> Dict[str, Any]: return localconfig -def get_config(projroot: Path) -> Dict[str, Any]: +def getconfig(projroot: Path) -> Dict[str, Any]: """Return a project's config contents (or default if missing).""" config: Dict[str, Any] try: diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index aea849f8..72c46b63 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -86,7 +86,7 @@ def cpplint(projroot: Path, full: bool) -> None: import tempfile from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count - from efrotools import get_config + from efrotools import getconfig from efro.terminal import Clr from efro.error import CleanError @@ -97,7 +97,7 @@ def cpplint(projroot: Path, full: bool) -> None: raise Exception(f'Found space in path {fpath}; unexpected.') # Check the config for a list of ones to ignore. - code_blacklist: List[str] = get_config(projroot).get( + code_blacklist: List[str] = getconfig(projroot).get( 'cpplint_blacklist', []) # Just pretend blacklisted ones don't exist. @@ -170,9 +170,9 @@ def cpplint(projroot: Path, full: bool) -> None: def get_code_filenames(projroot: Path) -> List[str]: """Return the list of files to lint-check or auto-formatting.""" - from efrotools import get_config + from efrotools import getconfig exts = ('.h', '.c', '.cc', '.cpp', '.cxx', '.m', '.mm') - places = get_config(projroot).get('code_source_dirs', None) + places = getconfig(projroot).get('code_source_dirs', None) if places is None: raise RuntimeError('code_source_dirs not declared in config') codefilenames = [] @@ -249,9 +249,9 @@ def _should_include_script(fnamefull: str) -> bool: def get_script_filenames(projroot: Path) -> List[str]: """Return the Python filenames to lint-check or auto-format.""" - from efrotools import get_config + from efrotools import getconfig filenames = set() - places = get_config(projroot).get('python_source_dirs', None) + places = getconfig(projroot).get('python_source_dirs', None) if places is None: raise RuntimeError('python_source_dirs not declared in config') for place in places: @@ -436,7 +436,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], # pylint: disable=too-many-branches # pylint: disable=too-many-statements from astroid import modutils - from efrotools import get_config + from efrotools import getconfig from efro.error import CleanError # First off, build a map of dirtyfiles to module names @@ -484,7 +484,7 @@ def _apply_pylint_run_to_cache(projroot: Path, run: Any, dirtyfiles: List[str], else: untracked_deps.add(mname) - ignored_untracked_deps: List[str] = get_config(projroot).get( + ignored_untracked_deps: List[str] = getconfig(projroot).get( 'pylint_ignored_untracked_deps', []) # Add a few that this package itself triggers. diff --git a/tools/efrotools/ios.py b/tools/efrotools/ios.py index 0db9edea..9c4b1b8c 100644 --- a/tools/efrotools/ios.py +++ b/tools/efrotools/ios.py @@ -27,7 +27,7 @@ import subprocess import sys from dataclasses import dataclass -from efrotools import get_localconfig, get_config +from efrotools import getlocalconfig, getconfig MODES = { 'debug': { @@ -78,8 +78,8 @@ def push_ipa(root: pathlib.Path, modename: str) -> None: """ # Load both the local and project config data. - cfg = Config(**get_config(root)['push_ipa_config']) - lcfg = LocalConfig(**get_localconfig(root)['push_ipa_local_config']) + cfg = Config(**getconfig(root)['push_ipa_config']) + lcfg = LocalConfig(**getlocalconfig(root)['push_ipa_local_config']) if modename not in MODES: raise Exception('invalid mode: "' + str(modename) + '"') diff --git a/tools/efrotools/snippets.py b/tools/efrotools/snippets.py index 12e07cea..a68005c4 100644 --- a/tools/efrotools/snippets.py +++ b/tools/efrotools/snippets.py @@ -353,7 +353,7 @@ def tool_config_install() -> None: def _filter_tool_config(cfg: str) -> str: import textwrap - from efrotools import get_config + from efrotools import getconfig # Stick project-root wherever they want. cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(PROJROOT)) @@ -391,7 +391,7 @@ def _filter_tool_config(cfg: str) -> str: # Gen a pylint init to set up our python paths: pylint_init_tag = '__EFRO_PYLINT_INIT__' if pylint_init_tag in cfg: - pypaths = get_config(PROJROOT).get('python_paths') + pypaths = getconfig(PROJROOT).get('python_paths') if pypaths is None: raise RuntimeError('python_paths not set in project config') cstr = "init-hook='import sys;" @@ -460,13 +460,13 @@ def sync_all() -> None: def sync() -> None: """Runs standard syncs between this project and others.""" - from efrotools import get_config + from efrotools import getconfig from efrotools.sync import Mode, SyncItem, run_standard_syncs mode = Mode(sys.argv[2]) if len(sys.argv) > 2 else Mode.PULL # Load sync-items from project config and run them sync_items = [ - SyncItem(**i) for i in get_config(PROJROOT).get('sync_items', []) + SyncItem(**i) for i in getconfig(PROJROOT).get('sync_items', []) ] run_standard_syncs(PROJROOT, mode, sync_items) @@ -498,11 +498,11 @@ def pytest() -> None: import os import platform import subprocess - from efrotools import get_config, PYTHON_BIN + from efrotools import getconfig, PYTHON_BIN from efro.error import CleanError # Grab our python paths for the project and stuff them in PYTHONPATH. - pypaths = get_config(PROJROOT).get('python_paths') + pypaths = getconfig(PROJROOT).get('python_paths') if pypaths is None: raise CleanError('python_paths not found in project config.') diff --git a/tools/efrotools/sync.py b/tools/efrotools/sync.py index 2fbe32c0..860038d6 100644 --- a/tools/efrotools/sync.py +++ b/tools/efrotools/sync.py @@ -76,8 +76,8 @@ def run_standard_syncs(projectroot: Path, mode: Mode, Syncitems should be a list of tuples consisting of a src project name, a src subpath, and optionally a dst subpath (src will be used by default). """ - from efrotools import get_localconfig - localconfig = get_localconfig(projectroot) + from efrotools import getlocalconfig + localconfig = getlocalconfig(projectroot) for syncitem in syncitems: assert isinstance(syncitem, SyncItem) src_project = syncitem.src_project_id diff --git a/tools/snippets b/tools/snippets index 2a052e4b..43dd4ee6 100755 --- a/tools/snippets +++ b/tools/snippets @@ -41,14 +41,36 @@ from efrotools.snippets import ( PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile, cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install, sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, - makefile_target_list, spelling, spelling_all, compile_python_files, pytest, - echo) + makefile_target_list, spelling, spelling_all, pytest, echo) +from efrotools.snippets import compile_python_files as _orig_compile_py_files # pylint: enable=unused-import if TYPE_CHECKING: from typing import Optional +def compile_python_files() -> None: + """Override for compiling python files.""" + from pathlib import Path + import subprocess + import os + from efrotools import getlocalconfig + + # Run the standard command + _orig_compile_py_files() + + # Optionally also blow away blessing status to keep it clear that + # things need to be re-blessed. + blesspath = Path(PROJROOT, 'tools/bless') + if os.path.exists(blesspath) and getlocalconfig(PROJROOT).get( + 'auto_clear_blessing', False): + subprocess.run([blesspath, 'clear'], check=True, cwd=PROJROOT) + + +# Copy the original func's doc-string +compile_python_files.__doc__ = _orig_compile_py_files.__doc__ + + def archive_old_builds() -> None: """Stuff our old public builds into the 'old' dir. @@ -156,7 +178,7 @@ def get_master_asset_src_dir() -> None: if ('origin/master' in output.splitlines()[0] and 'ballistica' + 'core' == 'ballisticacore'): - # We seem to be in master in core repo.. lets do it. + # We seem to be in master in core repo; lets do it. print('/Users/ericf/Dropbox/ballisticacore_master_assets') else: # Still need to supply dummy path for makefile if not.. @@ -399,8 +421,8 @@ def warm_start_asset_build() -> None: import os import subprocess from pathlib import Path - from efrotools import get_config - public: bool = get_config(PROJROOT)['public'] + from efrotools import getconfig + public: bool = getconfig(PROJROOT)['public'] if public: from efrotools.efrocache import warm_start_cache diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile index 0c1ef269..dfe2b626 100755 --- a/tools/update_assets_makefile +++ b/tools/update_assets_makefile @@ -180,9 +180,15 @@ def _get_py_targets_subset(all_targets: Set[str], subset: str, ' instead, but perhaps listing these explicitly isn\'t so bad.\n') for i, target in enumerate(pyc_targets): + # Note: there's currently a bug which can cause python bytecode + # generation to be non-deterministic. This can break our blessing + # process since we bless in core but then regenerate bytecode in + # spinoffs. See https://bugs.python.org/issue34722 + # For now setting PYTHONHASHSEED=1 is a workaround. out += ('\n' + target + ': \\\n ' + py_targets[i] + '\n\t@echo Compiling script: $^\n' - '\t@rm -rf $@ && $(TOOLS_DIR)/snippets compile_python_files $^' + '\t@rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets' + ' compile_python_files $^' ' && chmod 444 $@\n') return out @@ -248,7 +254,7 @@ def _get_extras_targets_win(all_targets: Set[str], platform: str) -> str: def main() -> None: """Main script entry point.""" # pylint: disable=too-many-locals - from efrotools import get_config + from efrotools import getconfig from pathlib import Path # In 'check' mode we simply error on differences. @@ -257,7 +263,7 @@ def main() -> None: # Always operate out of dist root dir. os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..')) - public = get_config(Path('.'))['public'] + public = getconfig(Path('.'))['public'] assert isinstance(public, bool) fname = 'assets/Makefile' diff --git a/tools/update_project b/tools/update_project index f50d074b..2eea0210 100755 --- a/tools/update_project +++ b/tools/update_project @@ -67,14 +67,14 @@ class App: """Context for an app run.""" def __init__(self) -> None: - from efrotools import get_config, get_localconfig + from efrotools import getconfig, getlocalconfig from pathlib import Path self._check = ('--check' in sys.argv) self._fix = ('--fix' in sys.argv) self._checkarg = ' --check' if self._check else '' # We behave differently in the public repo - self._public = get_config(Path('.'))['public'] + self._public = getconfig(Path('.'))['public'] assert isinstance(self._public, bool) self._source_files: List[str] = [] @@ -84,7 +84,7 @@ class App: self._file_changes: Dict[str, str] = {} self._copyright_checks = bool( - get_localconfig(Path('.')).get('copyright_checks', True)) + getlocalconfig(Path('.')).get('copyright_checks', True)) def run(self) -> None: """Do the thing.""" From b53701085c7ea30968c99d4b4770b13cd39ea43e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 7 Jun 2020 23:54:24 -0700 Subject: [PATCH 080/417] Testing bless process --- tools/snippets | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/snippets b/tools/snippets index 43dd4ee6..efffcd61 100755 --- a/tools/snippets +++ b/tools/snippets @@ -595,9 +595,11 @@ def lazy_increment_build() -> None: lasthash = '' if codehash != lasthash: print(f'{Clr.SMAG}Source(s) changed; incrementing build...{Clr.RST}') - subprocess.run(['tools/version_utils', 'incrementbuild'], check=True) - # We just changed code, so we need to re-calc the current hash. + # Just go ahead and bless; this will increment the build as needed. + subprocess.run(['make', 'bless'], check=True) + + # We probably just changed code, so we need to re-calc the hash. codehash = get_files_hash(codefiles) os.makedirs(os.path.dirname(hashfilename), exist_ok=True) with open(hashfilename, 'w') as outfile: From 93f3900b99b457bca7a0749b30736fd93e1d2c9b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 8 Jun 2020 00:48:31 -0700 Subject: [PATCH 081/417] Tidying --- .efrocachemap | 16 ++++++++-------- assets/src/ba_data/python/_ba.py | 2 +- docs/ba_module.md | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index a428af42..d15b2a9f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1e/2c/09ca7e7ab982a04608a9cee6230b", + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/9e/32020e34ce5fdbadf629b33ed5f5", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/d6/25671c9f875c9eb1f25f09d1000f", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/ee/6989965b6929d55044156e41017b", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/b6/80b10adc9b2b98b8d05235d1cf52", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/e9/c7b41ca260cb04e539cc81fd79c4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5b/ef/9d427caa8a691f225cbf3e0c649e", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/46/99/b0a1e649204828f3371da6bf7aef", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/61/63b817195328d360c02c8705405a", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/51/bf8fdbea96a0e76f9203bcd1c427", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/3c/5e120a4ad559edfd8d068b85be67", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/34/ad36c057f3d2c890617a25311cd8", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e3/00/d0cfc8d72ef8dd1567ca7e48a58e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cd/c0/56c8c49c60298727d7593f91928a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/24/d1/d73ae026e9797924e5257d87fe98", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8b/4f/112f32d713898abca7fa465779c1" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1b/45/84ad79d8b17692ff684f2e8c9fe3", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/63/897899f41f282089fb752fd503b8", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/09/4f/940b3db9892ac20023c173e2c39d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/de/53/9b99e2dbf64622ccc95014ce598b" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index bb999180..a12c6430 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=197797300249336200681012613336602141418 +# SOURCES_HASH=188869443842417703663502065018427831709 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/docs/ba_module.md b/docs/ba_module.md index 9df04a28..15c8d134 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-07 for Ballistica version 1.5.0 build 20059

    +

    last updated on 2020-06-08 for Ballistica version 1.5.0 build 20060

    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!


    From 1e45d70d27337c418e62f594a3da8eebfe2f7c5b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 8 Jun 2020 13:58:36 -0700 Subject: [PATCH 082/417] Cleanup for BombSquad releases --- .efrocachemap | 26 ++++++------ .../ba_data/python/bastd/ui/coop/browser.py | 6 +-- tools/batools/build.py | 2 +- tools/snippets | 42 +++++++++---------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index d15b2a9f..923138b5 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d4/df/3ab21c23dedf45ab454b0c4286b1", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/1a/f1/5f137cf224ef00126e7bcbbcd6e7", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/9e/32020e34ce5fdbadf629b33ed5f5", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/d6/25671c9f875c9eb1f25f09d1000f", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/b6/80b10adc9b2b98b8d05235d1cf52", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/e9/c7b41ca260cb04e539cc81fd79c4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/46/99/b0a1e649204828f3371da6bf7aef", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/61/63b817195328d360c02c8705405a", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/3c/5e120a4ad559edfd8d068b85be67", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/34/ad36c057f3d2c890617a25311cd8", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1b/45/84ad79d8b17692ff684f2e8c9fe3", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/63/897899f41f282089fb752fd503b8", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/09/4f/940b3db9892ac20023c173e2c39d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/de/53/9b99e2dbf64622ccc95014ce598b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/e3/26df34acf7cada33af7f6f1d3431", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/b3/4b528db89a74e80a050274f22b6c", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e0/02/c987aa278b2439db5a148971d8ba", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a2/9b/15a7833af0c21bbb6308a691a292", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/9b/df93cfbca1c8feef57c3bf45b05a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/25/c4/3370a0713974510c049d9c2486aa", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/08/3e/9506fbb6603a33434df94e9f0680", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/20/b37a4700d2107b10f501b486a90e", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e0/5f/89ac5f7407bba4192d4ee0a85971", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/82/11/59011bd718f84ea698a1f8273d36", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/3b/b1dd633355c80357bc3ddfe18e4a", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/21/d5/099fafed1d613b666f1b7187eea4" } \ No newline at end of file diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index ac12a22a..cec83705 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -61,9 +61,9 @@ class CoopBrowserWindow(ba.Window): app = ba.app cfg = app.config - # Quick note to players that tourneys won't work if we're a non-blessed - # or a debug build... - if not _ba.is_blessed() or ba.app.debug_build: + # Quick note to players that tourneys won't work in ballistica + # core builds. (need to split the word so it won't get subbed out) + if 'ballistica' + 'core' == _ba.appname(): ba.timer(1.0, lambda: ba.screenmessage( ba.Lstr(resource='noTournamentsInTestBuildText'), diff --git a/tools/batools/build.py b/tools/batools/build.py index f65643ba..95d03e9a 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -46,7 +46,7 @@ class PipRequirement: PIP_REQUIREMENTS = [ - PipRequirement(modulename='pylint', minversion=[2, 5, 2]), + PipRequirement(modulename='pylint', minversion=[2, 5, 3]), PipRequirement(modulename='mypy', minversion=[0, 780]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), PipRequirement(modulename='cpplint', minversion=[1, 5, 0]), diff --git a/tools/snippets b/tools/snippets index efffcd61..86484dae 100755 --- a/tools/snippets +++ b/tools/snippets @@ -41,34 +41,33 @@ from efrotools.snippets import ( PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile, cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install, sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, - makefile_target_list, spelling, spelling_all, pytest, echo) -from efrotools.snippets import compile_python_files as _orig_compile_py_files + makefile_target_list, spelling, spelling_all, pytest, echo, + compile_python_files) +# from efrotools.snippets import compile_python_files as _orig_compile_py_files # pylint: enable=unused-import if TYPE_CHECKING: from typing import Optional +# def compile_python_files() -> None: +# """Override for compiling python files.""" +# from pathlib import Path +# import subprocess +# import os +# from efrotools import getlocalconfig -def compile_python_files() -> None: - """Override for compiling python files.""" - from pathlib import Path - import subprocess - import os - from efrotools import getlocalconfig +# # Run the standard command +# _orig_compile_py_files() - # Run the standard command - _orig_compile_py_files() +# # Optionally also blow away blessing status to keep it clear that +# # things need to be re-blessed. +# blesspath = Path(PROJROOT, 'tools/bless') +# if os.path.exists(blesspath) and getlocalconfig(PROJROOT).get( +# 'auto_clear_blessing', False): +# subprocess.run([blesspath, 'clear'], check=True, cwd=PROJROOT) - # Optionally also blow away blessing status to keep it clear that - # things need to be re-blessed. - blesspath = Path(PROJROOT, 'tools/bless') - if os.path.exists(blesspath) and getlocalconfig(PROJROOT).get( - 'auto_clear_blessing', False): - subprocess.run([blesspath, 'clear'], check=True, cwd=PROJROOT) - - -# Copy the original func's doc-string -compile_python_files.__doc__ = _orig_compile_py_files.__doc__ +# # Copy the original func's doc-string +# compile_python_files.__doc__ = _orig_compile_py_files.__doc__ def archive_old_builds() -> None: @@ -452,11 +451,12 @@ def install_pip_reqs() -> None: """Install Python Pip packages needed for this project.""" import subprocess from efrotools import PYTHON_BIN + from efro.terminal import Clr from batools.build import get_pip_reqs subprocess.run([PYTHON_BIN, '-m', 'pip', 'install', '--upgrade'] + get_pip_reqs(), check=True) - print('All pip requirements installed!') + print(f'{Clr.GRN}All pip requirements installed!{Clr.RST}') def checkenv() -> None: From 86f01e4be1f8f740fea5d3172c26f947bc4bcc55 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 8 Jun 2020 14:44:44 -0700 Subject: [PATCH 083/417] Some CTF code cleanup --- .efrocachemap | 24 +++++------ .../python/bastd/game/capturetheflag.py | 43 ++++++++----------- 2 files changed, 31 insertions(+), 36 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 923138b5..160b35c7 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/e3/26df34acf7cada33af7f6f1d3431", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/b3/4b528db89a74e80a050274f22b6c", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e0/02/c987aa278b2439db5a148971d8ba", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a2/9b/15a7833af0c21bbb6308a691a292", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/9b/df93cfbca1c8feef57c3bf45b05a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/25/c4/3370a0713974510c049d9c2486aa", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/08/3e/9506fbb6603a33434df94e9f0680", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/20/b37a4700d2107b10f501b486a90e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e0/5f/89ac5f7407bba4192d4ee0a85971", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/82/11/59011bd718f84ea698a1f8273d36", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/3b/b1dd633355c80357bc3ddfe18e4a", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/21/d5/099fafed1d613b666f1b7187eea4" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/9c/ea45597789b0b0ef00b3868dfd4b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/46/d99ad97bed02f7dbd8a22acfddea", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0b/22/78866aed7517959f4e340318cc7c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/87/2a6cbc9558ff7a8244b77419055b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/06/72/e400773b3e2765f764192acd67ac", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/c7/c9aafa0d4f9c83561f355495f50b", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/db/a1/a5c09c8ee119acd9276862726fb1", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ba/5f/4043991774fe98e496945c3c85fd", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a8/8f/953a7085c724a49ac8598819c09b", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/95/822b29da86c0f8b0196f18723fe3", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1f/9c/61ccc896b0c6f74910af629fc6ff", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d6/c2/0708d5b471ad22ccee64de7a61e3" } \ No newline at end of file diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index f12cdde8..e4b17421 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -68,14 +68,9 @@ class CTFFlag(Flag): @property def team(self) -> Team: - """return the flag's team.""" + """The flag's team.""" return self._team - @classmethod - def from_node(cls, node: Optional[ba.Node]) -> Optional[CTFFlag]: - """Attempt to get a CTFFlag from a flag node.""" - return node.getdelegate(CTFFlag) if node else None - class Player(ba.Player['Team']): """Our player type for this game.""" @@ -285,9 +280,11 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): ba.playsound(self._swipsound, position=team.flag.node.position) def _handle_flag_entered_base(self, team: Team) -> None: - flag = CTFFlag.from_node(ba.getcollision().opposingnode) - if not flag: - print('Unable to get flag in _handle_flag_entered_base') + try: + flag = ba.getcollision().opposingnode.getdelegate(CTFFlag, True) + except ba.NotFoundError: + # Don't think this should logically ever happen. + print('Error getting CTFFlag in entering-base callback.') return if flag.team is team: @@ -396,13 +393,12 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): def _handle_flag_left_base(self, team: Team) -> None: cur_time = ba.time() try: - flag = CTFFlag.from_node(ba.getcollision().opposingnode) - except ba.NodeNotFoundError: - # We still get this call even if the flag stopped touching us - # because it was deleted; that's ok. - flag = None - if not flag: + flag = ba.getcollision().opposingnode.getdelegate(CTFFlag, True) + except ba.NotFoundError: + # This can happen if the flag stops touching us due to being + # deleted; that's ok. return + if flag.team is team: # Check times here to prevent too much flashing. @@ -449,21 +445,20 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): return_score, screenmessage=False) - @staticmethod - def _player_from_node(node: Optional[ba.Node]) -> Optional[Player]: - """Return a player if given a node that is part of one's actor.""" - if not node: - return None - delegate = node.getdelegate(PlayerSpaz) - return None if delegate is None else delegate.getplayer(Player) - def _handle_touching_own_flag(self, team: Team, connecting: bool) -> None: """Called when a player touches or stops touching their own team flag. We keep track of when each player is touching their own flag so we can award points when returned. """ - player = self._player_from_node(ba.getcollision().sourcenode) + player: Optional[Player] + try: + player = ba.getcollision().sourcenode.getdelegate( + PlayerSpaz, True).getplayer(Player, True) + except ba.NotFoundError: + # This can happen if the player leaves but his corpse touches/etc. + player = None + if player: player.touching_own_flag += (1 if connecting else -1) From 57103caa31ee32a2abb1b38f5496cd98cfc0c084 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 9 Jun 2020 01:11:30 -0700 Subject: [PATCH 084/417] BombSquad 1.5.1 release --- .efrocachemap | 24 +++--- .idea/dictionaries/ericf.xml | 6 ++ CHANGELOG.md | 7 +- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/_servermode.py | 11 ++- assets/src/ba_data/python/bastd/ui/gather.py | 4 + assets/src/server/README.txt | 9 ++- .../server/launch_ballisticacore_server.bat | 6 +- docs/ba_module.md | 2 +- tools/efro/terminal.py | 74 ++++++++++++++++++- 10 files changed, 118 insertions(+), 27 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 160b35c7..bae283d1 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/9c/ea45597789b0b0ef00b3868dfd4b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/46/d99ad97bed02f7dbd8a22acfddea", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0b/22/78866aed7517959f4e340318cc7c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/87/2a6cbc9558ff7a8244b77419055b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/06/72/e400773b3e2765f764192acd67ac", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/c7/c9aafa0d4f9c83561f355495f50b", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/db/a1/a5c09c8ee119acd9276862726fb1", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ba/5f/4043991774fe98e496945c3c85fd", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a8/8f/953a7085c724a49ac8598819c09b", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/95/822b29da86c0f8b0196f18723fe3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1f/9c/61ccc896b0c6f74910af629fc6ff", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d6/c2/0708d5b471ad22ccee64de7a61e3" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c3/0a/88aac36a9fc3fd22655330620f94", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/24/292978d4c30e1ecd870eed435d28", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/f9/b7a3e4e3f4ff262804c14747ad11", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3c/55/c1005d5da5b7fc2fec10c4c5a5ba", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/4f/8a47768eaac63d56706489076fe9", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5f/15/231c0b5530fb193bf43d1d424c55", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/c6/de3932a656e27f7f21a54380f62c", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b6/d7/d00e68f088c6ff72963231730648", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/83/93/99e8eb67cdaa7f64ccb66ba7fa9e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d1/05/b7b47978e93db2f65cf172ff28b3", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/74/f2/a754439742dd96c00aa57b6b036c", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f2/91/7e1fd943727c3bd78e48f405b6c5" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index d4fe14f7..f2845589 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -89,6 +89,7 @@ archs argh argparse + argtypes argval armeabi arraymodule @@ -360,6 +361,7 @@ configparser configpath connectattr + conout containerwidget contentmanager contextlib @@ -627,6 +629,7 @@ fdata fdesc fdict + fdout fecfc feedparser ffaeff @@ -884,6 +887,7 @@ homebook homebrew hometest + hout howtoplay hpos hscrollwidget @@ -1100,6 +1104,7 @@ loofa loosey losecount + lpdword lpos lprop lsbo @@ -1360,6 +1365,7 @@ palmos pandoc pandroid + parallelized parsermodule partyqueue partyval diff --git a/CHANGELOG.md b/CHANGELOG.md index 424485c4..2c5bb2cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ +### 1.5.1 (20062) +- Windows server now properly displays color when run by double clicking the .bat file. +- Misc bug fixes. + ### 1.5.0 (20001) +- This build contains about 2 years worth of MAJOR internal refactoring to prepare for the future of BombSquad. As a player this should not (yet) look different from 1.4, but for modders there is a lot new. See the rest of these change entries or visit ballistica.net for more info. - Ported the entire scripting layer from Python 2 to to Python 3 (currently at 3.7, and I intend to keep this updated to the latest widely-available release). There's some significant changes going from python 2 to 3 (new print statement, string behavior, etc), but these are well documented online, so please read up as needed. This should provide us some nice benefits and future-proofs everything. (my janky 2.7 custom Python builds were getting a little long in the tooth). - Refactored all script code to be PEP8 compliant (Python coding standards). Basically, this means that stuff that was camel-case (fooBar) is now a single word or underscores (foobar / foo_bar). There are a few minor exceptions such as existing resource and media filenames, but in general old code can be ported by taking a pass through and killing the camel-case. I know this is a bit of a pain in the ass, but it'll let us use things like Pylint and just be more consistent with the rest of the Python world. - On a related note, I'm now using 'yapf' to keep my Python code formatted nicely (using pep8 style); I'd recommend checking it out if you're doing a lot of scripting as its a great time-saver. @@ -48,7 +53,7 @@ - bs.NodeActor is no more (it can simply be replaced with ba.Actor()) - bs.playMusic() is now ba.setmusic() which better fits its functionality (it sometimes just continues playing or stops playing). - The bs.Vector class is no more; in its place is a shiny new ba.Vec3 which is implemented internally in C++ so its nice and speedy. Will probably update certain things like vector node attrs to support this class in the future since it makes vector math nice and convenient. -- Ok you get the point.. +- Ok you get the point.. see ballistica.net for more info on these changes. ### 1.4.155 (14377) - Added protection against a repeated-input attack in lobbies. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index a12c6430..13993284 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=188869443842417703663502065018427831709 +# SOURCES_HASH=328357141536767746382612764132666300753 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py index a8c75328..47beb6c9 100644 --- a/assets/src/ba_data/python/ba/_servermode.py +++ b/assets/src/ba_data/python/ba/_servermode.py @@ -321,9 +321,11 @@ class ServerController: if self._first_run: curtimestr = time.strftime('%c') - print(f'{Clr.BLD}{Clr.BLU}{_ba.appnameupper()} {app.version}' - f' ({app.build_number})' - f' entering server-mode {curtimestr}{Clr.RST}') + _ba.log( + f'{Clr.BLD}{Clr.BLU}{_ba.appnameupper()} {app.version}' + f' ({app.build_number})' + f' entering server-mode {curtimestr}{Clr.RST}', + to_server=False) if sessiontype is FreeForAllSession: appcfg['Free-for-All Playlist Selection'] = self._playlist_name @@ -354,6 +356,7 @@ class ServerController: # And here we go. _ba.new_host_session(sessiontype) - if not self._ran_access_check: + # Run an access check if we're trying to make a public party. + if not self._ran_access_check and self._config.party_is_public: self._run_access_check() self._ran_access_check = True diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 288f3f62..98b122a0 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1720,6 +1720,10 @@ class GatherWindow(ba.Window): # Ignore harmless errors. if exc.errno == errno.EHOSTUNREACH: 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. diff --git a/assets/src/server/README.txt b/assets/src/server/README.txt index afc5f770..674c999a 100644 --- a/assets/src/server/README.txt +++ b/assets/src/server/README.txt @@ -2,8 +2,8 @@ To run this, simply cd into this directory and run ./ballisticacore_server (on mac or linux) or launch_ballisticacore_server.bat (on windows). You'll need to open a UDP port (43210 by default) so that the world can communicate with your server. -You can configure your server by creating a config.yaml file -(see config_template.yaml as a starting point) +You can configure your server by editing the config.yaml file. +(if you only see config_template.yaml, you can copy/rename that to config.yaml) Platform-Specific Notes: @@ -16,7 +16,7 @@ Mac: Linux (x86_64): - Server binaries are currently compiled against Ubuntu 18 LTS. They depend on Python 3.7, so you may need to install that. - This should just be something like "sudo apt install python3" + This should just be something like "sudo apt install python3.7" Raspberry Pi: - The server binary was compiled on a Raspberry Pi 4 running Raspbian Buster. @@ -25,7 +25,8 @@ Windows: - You may need to run dist/Vc_redist.x64.exe to install support libraries if the app quits with complaints of missing DLLs -Please give me a holler at support@froemling.net if you run into any problems. +Please give me a holler at support@froemling.net or check out +ballistica.net/wiki if you run into any problems. Enjoy! -Eric diff --git a/assets/src/server/launch_ballisticacore_server.bat b/assets/src/server/launch_ballisticacore_server.bat index 134ebd52..a5315816 100644 --- a/assets/src/server/launch_ballisticacore_server.bat +++ b/assets/src/server/launch_ballisticacore_server.bat @@ -1,2 +1,4 @@ -:: All this does is run the ballisticacore_server script with the included python interpreter -dist\\python.exe ballisticacore_server.py +:: Simply run the ballisticacore_server.py script with the bundled +:: python interpreter. Run in opt-mode so we pick up all the +:: bundled .opt-1.pyc files too. +dist\\python.exe -O ballisticacore_server.py diff --git a/docs/ba_module.md b/docs/ba_module.md index 15c8d134..aad68617 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-08 for Ballistica version 1.5.0 build 20060

    +

    last updated on 2020-06-09 for Ballistica version 1.5.1 build 20062

    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!


    diff --git a/tools/efro/terminal.py b/tools/efro/terminal.py index 727331f3..7f8acb8c 100644 --- a/tools/efro/terminal.py +++ b/tools/efro/terminal.py @@ -27,7 +27,7 @@ from enum import Enum, unique from typing import TYPE_CHECKING if TYPE_CHECKING: - pass + from typing import Any @unique @@ -85,6 +85,76 @@ class TerminalColor(Enum): STRONG_BG_WHITE = '\033[107m' +def _default_color_enabled() -> bool: + """Return whether we should enable ANSI color codes by default.""" + import platform + + # If we're not attached to a terminal, go with no-color. + if not sys.__stdout__.isatty(): + return False + + # On windows, try to enable ANSI color mode. + if platform.system() == 'Windows': + return _windows_enable_color() + + # We seem to be a terminal with color support; let's do it! + return True + + +# noinspection PyPep8Naming +def _windows_enable_color() -> bool: + """Attempt to enable ANSI color on windows terminal; return success.""" + # pylint: disable=invalid-name, import-error, undefined-variable + # Pulled from: https://bugs.python.org/issue30075 + import msvcrt + import ctypes + from ctypes import wintypes + kernel32 = ctypes.WinDLL('kernel32', use_last_error=True) # type: ignore + + ERROR_INVALID_PARAMETER = 0x0057 + ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004 + + def _check_bool(result: Any, _func: Any, args: Any) -> Any: + if not result: + raise ctypes.WinError(ctypes.get_last_error()) # type: ignore + return args + + LPDWORD = ctypes.POINTER(wintypes.DWORD) + kernel32.GetConsoleMode.errcheck = _check_bool + kernel32.GetConsoleMode.argtypes = (wintypes.HANDLE, LPDWORD) + kernel32.SetConsoleMode.errcheck = _check_bool + kernel32.SetConsoleMode.argtypes = (wintypes.HANDLE, wintypes.DWORD) + + def set_conout_mode(new_mode: int, mask: int = 0xffffffff) -> int: + # don't assume StandardOutput is a console. + # open CONOUT$ instead + fdout = os.open('CONOUT$', os.O_RDWR) + try: + hout = msvcrt.get_osfhandle(fdout) + old_mode = wintypes.DWORD() + kernel32.GetConsoleMode(hout, ctypes.byref(old_mode)) + mode = (new_mode & mask) | (old_mode.value & ~mask) + kernel32.SetConsoleMode(hout, mode) + return old_mode.value + finally: + os.close(fdout) + + def enable_vt_mode() -> int: + mode = mask = ENABLE_VIRTUAL_TERMINAL_PROCESSING + try: + return set_conout_mode(mode, mask) + except WindowsError as exc: + if exc.winerror == ERROR_INVALID_PARAMETER: + raise NotImplementedError + raise + + try: + enable_vt_mode() + return True + except NotImplementedError: + return False + + class Clr: """Convenience class for color terminal output. @@ -96,7 +166,7 @@ class Clr: """ _envval = os.environ.get('EFRO_TERMCOLORS') color_enabled = (True if _envval == '1' else - False if _envval == '0' else sys.__stdout__.isatty()) + False if _envval == '0' else _default_color_enabled()) if color_enabled: # Styles From 4601ce947385774be056a7ac01d3de3957b23e8b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 9 Jun 2020 16:15:11 -0700 Subject: [PATCH 085/417] 1.5.2 --- .efrocachemap | 24 +- CHANGELOG.md | 5 + assets/src/ba_data/python/ba/_benchmark.py | 2 +- assets/src/ba_data/python/ba/_enums.py | 50 +-- .../ba_data/python/bastd/game/onslaught.py | 342 +++++++++--------- docs/ba_module.md | 2 +- 6 files changed, 214 insertions(+), 211 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index bae283d1..991a8649 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c3/0a/88aac36a9fc3fd22655330620f94", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/24/292978d4c30e1ecd870eed435d28", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/f9/b7a3e4e3f4ff262804c14747ad11", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3c/55/c1005d5da5b7fc2fec10c4c5a5ba", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/4f/8a47768eaac63d56706489076fe9", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5f/15/231c0b5530fb193bf43d1d424c55", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/c6/de3932a656e27f7f21a54380f62c", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b6/d7/d00e68f088c6ff72963231730648", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/83/93/99e8eb67cdaa7f64ccb66ba7fa9e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d1/05/b7b47978e93db2f65cf172ff28b3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/74/f2/a754439742dd96c00aa57b6b036c", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f2/91/7e1fd943727c3bd78e48f405b6c5" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/cf/1799ab571bdc1942e58a99cc5c16", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/46/62/bc2a3dc03c8bd9bc034851cf5314", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ea/e8/d2b075dabe1e9f9358c198b8adff", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/cc/cd7704cb242e86535a688186240b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/00/cdf784fc736fcf7ec65fe6941bb3", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a8/da/466f2f0f4837069315adb4107573", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/14/f3795835f4b14e7b8c873bfdd936", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1b/c9/bb4b326efc4a125d01edb3ba6451", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e7/a0/5d8cfa3b7622468b6fff4d36a69b", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f6/05/599e4c7481031e8bfe5f901f422f", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b0/52/d3489ac0c0d25dcb2d81333f235e", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1b/b2/0169fdcb311e55fc9523ff6c53b8" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c5bb2cc..217c2f4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +### 1.5.2 (20063) +- Fixes an issue with controls not working correctly in net-play between 1.4.x and 1.5.x. +- Tidied up onslaught code a bit. +- Fixes various other minor bugs. + ### 1.5.1 (20062) - Windows server now properly displays color when run by double clicking the .bat file. - Misc bug fixes. diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index 539cc31d..fa47cde0 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -42,7 +42,7 @@ def run_cpu_benchmark() -> None: def __init__(self) -> None: - print('FIXME: BENCHMARK SESSION WOULD CALC DEPS.') + # print('FIXME: BENCHMARK SESSION WOULD CALC DEPS.') depsets: Sequence[ba.DependencySet] = [] super().__init__(depsets) diff --git a/assets/src/ba_data/python/ba/_enums.py b/assets/src/ba_data/python/ba/_enums.py index 3d78425a..1431686b 100644 --- a/assets/src/ba_data/python/ba/_enums.py +++ b/assets/src/ba_data/python/ba/_enums.py @@ -29,31 +29,31 @@ class InputType(Enum): Category: Enums """ - UP_DOWN = 0 - LEFT_RIGHT = 1 - JUMP_PRESS = 2 - JUMP_RELEASE = 3 - PUNCH_PRESS = 4 - PUNCH_RELEASE = 5 - BOMB_PRESS = 6 - BOMB_RELEASE = 7 - PICK_UP_PRESS = 8 - PICK_UP_RELEASE = 9 - RUN = 10 - FLY_PRESS = 11 - FLY_RELEASE = 12 - START_PRESS = 13 - START_RELEASE = 14 - HOLD_POSITION_PRESS = 15 - HOLD_POSITION_RELEASE = 16 - LEFT_PRESS = 17 - LEFT_RELEASE = 18 - RIGHT_PRESS = 19 - RIGHT_RELEASE = 20 - UP_PRESS = 21 - UP_RELEASE = 22 - DOWN_PRESS = 23 - DOWN_RELEASE = 24 + UP_DOWN = 2 + LEFT_RIGHT = 3 + JUMP_PRESS = 4 + JUMP_RELEASE = 5 + PUNCH_PRESS = 6 + PUNCH_RELEASE = 7 + BOMB_PRESS = 8 + BOMB_RELEASE = 9 + PICK_UP_PRESS = 10 + PICK_UP_RELEASE = 11 + RUN = 12 + FLY_PRESS = 13 + FLY_RELEASE = 14 + START_PRESS = 15 + START_RELEASE = 16 + HOLD_POSITION_PRESS = 17 + HOLD_POSITION_RELEASE = 18 + LEFT_PRESS = 19 + LEFT_RELEASE = 20 + RIGHT_PRESS = 21 + RIGHT_RELEASE = 22 + UP_PRESS = 23 + UP_RELEASE = 24 + DOWN_PRESS = 25 + DOWN_RELEASE = 26 class TimeType(Enum): diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index cbb03d17..c7b1971a 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -53,13 +53,13 @@ if TYPE_CHECKING: @dataclass class Wave: """A wave of enemies.""" - entries: List[Union[Bot, Spacing, Delay, None]] + entries: List[Union[Spawn, Spacing, Delay, None]] base_angle: float = 0.0 @dataclass -class Bot: - """A bot in a wave.""" +class Spawn: + """A bot spawn event in a wave.""" bottype: Union[Type[SpazBot], str] point: Optional[Point] = None spacing: float = 5.0 @@ -73,7 +73,7 @@ class Spacing: @dataclass class Delay: - """A delay in a wave.""" + """A delay between events in a wave.""" duration: float @@ -93,34 +93,34 @@ class Preset(Enum): @unique class Point(Enum): - """Points on the map to spawn at.""" - LEFT_UPPER_MORE = 'left_upper_more' - LEFT_UPPER = 'left_upper' - TURRET_TOP_RIGHT = 'turret_top_right' - RIGHT_UPPER = 'right_upper' - TURRET_TOP_MIDDLE_LEFT = 'turret_top_middle_left' - TURRET_TOP_MIDDLE_RIGHT = 'turret_top_middle_right' - TURRET_TOP_LEFT = 'turret_top_left' - TOP_RIGHT = 'top_right' - TOP_LEFT = 'top_left' - TOP = 'top' - BOTTOM = 'bottom' - LEFT = 'left' - RIGHT = 'right' - RIGHT_UPPER_MORE = 'right_upper_more' - RIGHT_LOWER = 'right_lower' - RIGHT_LOWER_MORE = 'right_lower_more' - BOTTOM_RIGHT = 'bottom_right' - BOTTOM_LEFT = 'bottom_left' - TURRET_BOTTOM_RIGHT = 'turret_bottom_right' - TURRET_BOTTOM_LEFT = 'turret_bottom_left' - LEFT_LOWER = 'left_lower' - LEFT_LOWER_MORE = 'left_lower_more' - TURRET_TOP_MIDDLE = 'turret_top_middle' - BOTTOM_HALF_RIGHT = 'bottom_half_right' - BOTTOM_HALF_LEFT = 'bottom_half_left' - TOP_HALF_RIGHT = 'top_half_right' - TOP_HALF_LEFT = 'top_half_left' + """Points on the map we can spawn at.""" + LEFT_UPPER_MORE = 'bot_spawn_left_upper_more' + LEFT_UPPER = 'bot_spawn_left_upper' + TURRET_TOP_RIGHT = 'bot_spawn_turret_top_right' + RIGHT_UPPER = 'bot_spawn_right_upper' + TURRET_TOP_MIDDLE_LEFT = 'bot_spawn_turret_top_middle_left' + TURRET_TOP_MIDDLE_RIGHT = 'bot_spawn_turret_top_middle_right' + TURRET_TOP_LEFT = 'bot_spawn_turret_top_left' + TOP_RIGHT = 'bot_spawn_top_right' + TOP_LEFT = 'bot_spawn_top_left' + TOP = 'bot_spawn_top' + BOTTOM = 'bot_spawn_bottom' + LEFT = 'bot_spawn_left' + RIGHT = 'bot_spawn_right' + RIGHT_UPPER_MORE = 'bot_spawn_right_upper_more' + RIGHT_LOWER = 'bot_spawn_right_lower' + RIGHT_LOWER_MORE = 'bot_spawn_right_lower_more' + BOTTOM_RIGHT = 'bot_spawn_bottom_right' + BOTTOM_LEFT = 'bot_spawn_bottom_left' + TURRET_BOTTOM_RIGHT = 'bot_spawn_turret_bottom_right' + TURRET_BOTTOM_LEFT = 'bot_spawn_turret_bottom_left' + LEFT_LOWER = 'bot_spawn_left_lower' + LEFT_LOWER_MORE = 'bot_spawn_left_lower_more' + TURRET_TOP_MIDDLE = 'bot_spawn_turret_top_middle' + BOTTOM_HALF_RIGHT = 'bot_spawn_bottom_half_right' + BOTTOM_HALF_LEFT = 'bot_spawn_bottom_half_left' + TOP_HALF_RIGHT = 'bot_spawn_top_half_right' + TOP_HALF_LEFT = 'bot_spawn_top_half_left' class Player(ba.Player['Team']): @@ -283,37 +283,37 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._waves = [ Wave(base_angle=195, entries=[ - Bot(BomberBotLite, spacing=5), + Spawn(BomberBotLite, spacing=5), ] * player_count), Wave(base_angle=130, entries=[ - Bot(BrawlerBotLite, spacing=5), + Spawn(BrawlerBotLite, spacing=5), ] * player_count), Wave(base_angle=195, - entries=[Bot(BomberBotLite, spacing=10)] * + entries=[Spawn(BomberBotLite, spacing=10)] * (player_count + 1)), Wave(base_angle=130, entries=[ - Bot(BrawlerBotLite, spacing=10), + Spawn(BrawlerBotLite, spacing=10), ] * (player_count + 1)), Wave(base_angle=130, entries=[ - Bot(BrawlerBotLite, spacing=5) + Spawn(BrawlerBotLite, spacing=5) if player_count > 1 else None, - Bot(BrawlerBotLite, spacing=5), + Spawn(BrawlerBotLite, spacing=5), Spacing(30), - Bot(BomberBotLite, spacing=5) + Spawn(BomberBotLite, spacing=5) if player_count > 3 else None, - Bot(BomberBotLite, spacing=5), + Spawn(BomberBotLite, spacing=5), Spacing(30), - Bot(BrawlerBotLite, spacing=5), - Bot(BrawlerBotLite, spacing=5) + Spawn(BrawlerBotLite, spacing=5), + Spawn(BrawlerBotLite, spacing=5) if player_count > 2 else None, ]), Wave(base_angle=195, entries=[ - Bot(TriggerBot, spacing=90), - Bot(TriggerBot, spacing=90) + Spawn(TriggerBot, spacing=90), + Spawn(TriggerBot, spacing=90) if player_count > 1 else None, ]), ] @@ -323,53 +323,53 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._excluded_powerups = ['curse'] self._waves = [ Wave(entries=[ - Bot(ChargerBot, Point.LEFT_UPPER_MORE - ) if player_count > 2 else None, - Bot(ChargerBot, Point.LEFT_UPPER), + Spawn(ChargerBot, Point.LEFT_UPPER_MORE + ) if player_count > 2 else None, + Spawn(ChargerBot, Point.LEFT_UPPER), ]), Wave(entries=[ - Bot(BomberBotStaticLite, Point.TURRET_TOP_RIGHT), - Bot(BrawlerBotLite, Point.RIGHT_UPPER), - Bot(BrawlerBotLite, Point.RIGHT_LOWER - ) if player_count > 1 else None, - Bot(BomberBotStaticLite, Point.TURRET_BOTTOM_RIGHT - ) if player_count > 2 else None, + Spawn(BomberBotStaticLite, Point.TURRET_TOP_RIGHT), + Spawn(BrawlerBotLite, Point.RIGHT_UPPER), + Spawn(BrawlerBotLite, Point.RIGHT_LOWER + ) if player_count > 1 else None, + Spawn(BomberBotStaticLite, Point.TURRET_BOTTOM_RIGHT + ) if player_count > 2 else None, ]), Wave(entries=[ - Bot(BomberBotStaticLite, Point.TURRET_BOTTOM_LEFT), - Bot(TriggerBot, Point.LEFT), - Bot(TriggerBot, Point.LEFT_LOWER - ) if player_count > 1 else None, - Bot(TriggerBot, Point.LEFT_UPPER - ) if player_count > 2 else None, + Spawn(BomberBotStaticLite, Point.TURRET_BOTTOM_LEFT), + Spawn(TriggerBot, Point.LEFT), + Spawn(TriggerBot, Point.LEFT_LOWER + ) if player_count > 1 else None, + Spawn(TriggerBot, Point.LEFT_UPPER + ) if player_count > 2 else None, ]), Wave(entries=[ - Bot(BrawlerBotLite, Point.TOP_RIGHT), - Bot(BrawlerBot, Point.TOP_HALF_RIGHT - ) if player_count > 1 else None, - Bot(BrawlerBotLite, Point.TOP_LEFT), - Bot(BrawlerBotLite, Point.TOP_HALF_LEFT - ) if player_count > 2 else None, - Bot(BrawlerBot, Point.TOP), - Bot(BomberBotStaticLite, Point.TURRET_TOP_MIDDLE), + Spawn(BrawlerBotLite, Point.TOP_RIGHT), + Spawn(BrawlerBot, Point.TOP_HALF_RIGHT + ) if player_count > 1 else None, + Spawn(BrawlerBotLite, Point.TOP_LEFT), + Spawn(BrawlerBotLite, Point.TOP_HALF_LEFT + ) if player_count > 2 else None, + Spawn(BrawlerBot, Point.TOP), + Spawn(BomberBotStaticLite, Point.TURRET_TOP_MIDDLE), ]), Wave(entries=[ - Bot(TriggerBotStatic, Point.TURRET_BOTTOM_LEFT), - Bot(TriggerBotStatic, Point.TURRET_BOTTOM_RIGHT), - Bot(TriggerBot, Point.BOTTOM), - Bot(TriggerBot, Point.BOTTOM_HALF_RIGHT - ) if player_count > 1 else None, - Bot(TriggerBot, Point.BOTTOM_HALF_LEFT - ) if player_count > 2 else None, + Spawn(TriggerBotStatic, Point.TURRET_BOTTOM_LEFT), + Spawn(TriggerBotStatic, Point.TURRET_BOTTOM_RIGHT), + Spawn(TriggerBot, Point.BOTTOM), + Spawn(TriggerBot, Point.BOTTOM_HALF_RIGHT + ) if player_count > 1 else None, + Spawn(TriggerBot, Point.BOTTOM_HALF_LEFT + ) if player_count > 2 else None, ]), Wave(entries=[ - Bot(BomberBotStaticLite, Point.TURRET_TOP_LEFT), - Bot(BomberBotStaticLite, Point.TURRET_TOP_RIGHT), - Bot(ChargerBot, Point.BOTTOM), - Bot(ChargerBot, Point.BOTTOM_HALF_LEFT - ) if player_count > 1 else None, - Bot(ChargerBot, Point.BOTTOM_HALF_RIGHT - ) if player_count > 2 else None, + Spawn(BomberBotStaticLite, Point.TURRET_TOP_LEFT), + Spawn(BomberBotStaticLite, Point.TURRET_TOP_RIGHT), + Spawn(ChargerBot, Point.BOTTOM), + Spawn(ChargerBot, Point.BOTTOM_HALF_LEFT + ) if player_count > 1 else None, + Spawn(ChargerBot, Point.BOTTOM_HALF_RIGHT + ) if player_count > 2 else None, ]), ] @@ -379,78 +379,78 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._waves = [ Wave(base_angle=-50, entries=[ - Bot(BrawlerBot, spacing=12) + Spawn(BrawlerBot, spacing=12) if player_count > 3 else None, - Bot(BrawlerBot, spacing=12), - Bot(BomberBot, spacing=6), - Bot(BomberBot, spacing=6) + Spawn(BrawlerBot, spacing=12), + Spawn(BomberBot, spacing=6), + Spawn(BomberBot, spacing=6) if self._preset is Preset.PRO else None, - Bot(BomberBot, spacing=6) + Spawn(BomberBot, spacing=6) if player_count > 1 else None, - Bot(BrawlerBot, spacing=12), - Bot(BrawlerBot, spacing=12) + Spawn(BrawlerBot, spacing=12), + Spawn(BrawlerBot, spacing=12) if player_count > 2 else None, ]), Wave(base_angle=180, entries=[ - Bot(BrawlerBot, spacing=6) + Spawn(BrawlerBot, spacing=6) if player_count > 3 else None, - Bot(BrawlerBot, spacing=6) + Spawn(BrawlerBot, spacing=6) if self._preset is Preset.PRO else None, - Bot(BrawlerBot, spacing=6), - Bot(ChargerBot, spacing=45), - Bot(ChargerBot, spacing=45) + Spawn(BrawlerBot, spacing=6), + Spawn(ChargerBot, spacing=45), + Spawn(ChargerBot, spacing=45) if player_count > 1 else None, - Bot(BrawlerBot, spacing=6), - Bot(BrawlerBot, spacing=6) + Spawn(BrawlerBot, spacing=6), + Spawn(BrawlerBot, spacing=6) if self._preset is Preset.PRO else None, - Bot(BrawlerBot, spacing=6) + Spawn(BrawlerBot, spacing=6) if player_count > 2 else None, ]), Wave(base_angle=0, entries=[ - Bot(ChargerBot, spacing=30), - Bot(TriggerBot, spacing=30), - Bot(TriggerBot, spacing=30), - Bot(TriggerBot, spacing=30) + Spawn(ChargerBot, spacing=30), + Spawn(TriggerBot, spacing=30), + Spawn(TriggerBot, spacing=30), + Spawn(TriggerBot, spacing=30) if self._preset is Preset.PRO else None, - Bot(TriggerBot, spacing=30) + Spawn(TriggerBot, spacing=30) if player_count > 1 else None, - Bot(TriggerBot, spacing=30) + Spawn(TriggerBot, spacing=30) if player_count > 3 else None, - Bot(ChargerBot, spacing=30), + Spawn(ChargerBot, spacing=30), ]), Wave(base_angle=90, entries=[ - Bot(StickyBot, spacing=50), - Bot(StickyBot, spacing=50) + Spawn(StickyBot, spacing=50), + Spawn(StickyBot, spacing=50) if self._preset is Preset.PRO else None, - Bot(StickyBot, spacing=50), - Bot(StickyBot, spacing=50) + Spawn(StickyBot, spacing=50), + Spawn(StickyBot, spacing=50) if player_count > 1 else None, - Bot(StickyBot, spacing=50) + Spawn(StickyBot, spacing=50) if player_count > 3 else None, ]), Wave(base_angle=0, entries=[ - Bot(TriggerBot, spacing=72), - Bot(TriggerBot, spacing=72), - Bot(TriggerBot, spacing=72) + Spawn(TriggerBot, spacing=72), + Spawn(TriggerBot, spacing=72), + Spawn(TriggerBot, spacing=72) if self._preset is Preset.PRO else None, - Bot(TriggerBot, spacing=72), - Bot(TriggerBot, spacing=72), - Bot(TriggerBot, spacing=36) + Spawn(TriggerBot, spacing=72), + Spawn(TriggerBot, spacing=72), + Spawn(TriggerBot, spacing=36) if player_count > 2 else None, ]), Wave(base_angle=30, entries=[ - Bot(ChargerBotProShielded, spacing=50), - Bot(ChargerBotProShielded, spacing=50), - Bot(ChargerBotProShielded, spacing=50) + Spawn(ChargerBotProShielded, spacing=50), + Spawn(ChargerBotProShielded, spacing=50), + Spawn(ChargerBotProShielded, spacing=50) if self._preset is Preset.PRO else None, - Bot(ChargerBotProShielded, spacing=50) + Spawn(ChargerBotProShielded, spacing=50) if player_count > 1 else None, - Bot(ChargerBotProShielded, spacing=50) + Spawn(ChargerBotProShielded, spacing=50) if player_count > 2 else None, ]) ] @@ -466,65 +466,65 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._excluded_powerups = [] self._waves = [ Wave(entries=[ - Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT - ) if hard else None, - Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT), - Bot(BomberBotProStatic, Point.TURRET_TOP_LEFT - ) if player_count > 2 else None, - Bot(ExplodeyBot, Point.TOP_RIGHT), + Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT + ) if hard else None, + Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT), + Spawn(BomberBotProStatic, Point.TURRET_TOP_LEFT + ) if player_count > 2 else None, + Spawn(ExplodeyBot, Point.TOP_RIGHT), Delay(4.0), - Bot(ExplodeyBot, Point.TOP_LEFT), + Spawn(ExplodeyBot, Point.TOP_LEFT), ]), Wave(entries=[ - Bot(ChargerBot, Point.LEFT), - Bot(ChargerBot, Point.RIGHT), - Bot(ChargerBot, Point.RIGHT_UPPER_MORE - ) if player_count > 2 else None, - Bot(BomberBotProStatic, Point.TURRET_TOP_LEFT), - Bot(BomberBotProStatic, Point.TURRET_TOP_RIGHT), + Spawn(ChargerBot, Point.LEFT), + Spawn(ChargerBot, Point.RIGHT), + Spawn(ChargerBot, Point.RIGHT_UPPER_MORE + ) if player_count > 2 else None, + Spawn(BomberBotProStatic, Point.TURRET_TOP_LEFT), + Spawn(BomberBotProStatic, Point.TURRET_TOP_RIGHT), ]), Wave(entries=[ - Bot(TriggerBotPro, Point.TOP_RIGHT), - Bot(TriggerBotPro, Point.RIGHT_UPPER_MORE - ) if player_count > 1 else None, - Bot(TriggerBotPro, Point.RIGHT_UPPER), - Bot(TriggerBotPro, Point.RIGHT_LOWER) if hard else None, - Bot(TriggerBotPro, Point.RIGHT_LOWER_MORE - ) if player_count > 2 else None, - Bot(TriggerBotPro, Point.BOTTOM_RIGHT), + Spawn(TriggerBotPro, Point.TOP_RIGHT), + Spawn(TriggerBotPro, Point.RIGHT_UPPER_MORE + ) if player_count > 1 else None, + Spawn(TriggerBotPro, Point.RIGHT_UPPER), + Spawn(TriggerBotPro, Point.RIGHT_LOWER) if hard else None, + Spawn(TriggerBotPro, Point.RIGHT_LOWER_MORE + ) if player_count > 2 else None, + Spawn(TriggerBotPro, Point.BOTTOM_RIGHT), ]), Wave(entries=[ - Bot(ChargerBotProShielded, Point.BOTTOM_RIGHT), - Bot(ChargerBotProShielded, Point.BOTTOM - ) if player_count > 2 else None, - Bot(ChargerBotProShielded, Point.BOTTOM_LEFT), - Bot(ChargerBotProShielded, Point.TOP) if hard else None, - Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE), + Spawn(ChargerBotProShielded, Point.BOTTOM_RIGHT), + Spawn(ChargerBotProShielded, Point.BOTTOM + ) if player_count > 2 else None, + Spawn(ChargerBotProShielded, Point.BOTTOM_LEFT), + Spawn(ChargerBotProShielded, Point.TOP) if hard else None, + Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE), ]), Wave(entries=[ - Bot(ExplodeyBot, Point.LEFT_UPPER), + Spawn(ExplodeyBot, Point.LEFT_UPPER), Delay(1.0), - Bot(BrawlerBotProShielded, Point.LEFT_LOWER), - Bot(BrawlerBotProShielded, Point.LEFT_LOWER_MORE), + Spawn(BrawlerBotProShielded, Point.LEFT_LOWER), + Spawn(BrawlerBotProShielded, Point.LEFT_LOWER_MORE), Delay(4.0), - Bot(ExplodeyBot, Point.RIGHT_UPPER), + Spawn(ExplodeyBot, Point.RIGHT_UPPER), Delay(1.0), - Bot(BrawlerBotProShielded, Point.RIGHT_LOWER), - Bot(BrawlerBotProShielded, Point.RIGHT_UPPER_MORE), + Spawn(BrawlerBotProShielded, Point.RIGHT_LOWER), + Spawn(BrawlerBotProShielded, Point.RIGHT_UPPER_MORE), Delay(4.0), - Bot(ExplodeyBot, Point.LEFT), + Spawn(ExplodeyBot, Point.LEFT), Delay(5.0), - Bot(ExplodeyBot, Point.RIGHT), + Spawn(ExplodeyBot, Point.RIGHT), ]), Wave(entries=[ - Bot(BomberBotProStatic, Point.TURRET_TOP_LEFT), - Bot(BomberBotProStatic, Point.TURRET_TOP_RIGHT), - Bot(BomberBotProStatic, Point.TURRET_BOTTOM_LEFT), - Bot(BomberBotProStatic, Point.TURRET_BOTTOM_RIGHT), - Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT - ) if hard else None, - Bot(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT - ) if hard else None, + Spawn(BomberBotProStatic, Point.TURRET_TOP_LEFT), + Spawn(BomberBotProStatic, Point.TURRET_TOP_RIGHT), + Spawn(BomberBotProStatic, Point.TURRET_BOTTOM_LEFT), + Spawn(BomberBotProStatic, Point.TURRET_BOTTOM_RIGHT), + Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_LEFT + ) if hard else None, + Spawn(BomberBotProStatic, Point.TURRET_TOP_MIDDLE_RIGHT + ) if hard else None, ]) ] @@ -535,7 +535,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self._waves = [] else: - raise Exception('Invalid preset: ' + str(self._preset)) + raise RuntimeError(f'Invalid preset: {self._preset}') # FIXME: Should migrate to use setup_standard_powerup_drops(). @@ -1088,8 +1088,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): def _add_entries_for_distribution_group( self, group: List[Tuple[int, int]], bot_levels: List[List[Type[SpazBot]]], - all_entries: List[Union[Bot, Spacing, Delay, None]]) -> None: - entries: List[Union[Bot, Spacing, Delay, None]] = [] + all_entries: List[Union[Spawn, Spacing, Delay, None]]) -> None: + entries: List[Union[Spawn, Spacing, Delay, None]] = [] for entry in group: bot_level = bot_levels[entry[0] - 1] bot_type = bot_level[random.randrange(len(bot_level))] @@ -1103,9 +1103,9 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): split = random.random() > 0.3 for i in range(entry[1]): if split and i % 2 == 0: - entries.insert(0, Bot(bot_type, spacing=spacing)) + entries.insert(0, Spawn(bot_type, spacing=spacing)) else: - entries.append(Bot(bot_type, spacing=spacing)) + entries.append(Spawn(bot_type, spacing=spacing)) if entries: all_entries += entries all_entries.append( @@ -1124,7 +1124,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): distribution = self._get_distribution(target_points, min_dudes, max_dudes, group_count, max_level) - all_entries: List[Union[Bot, Spacing, Delay, None]] = [] + all_entries: List[Union[Spawn, Spacing, Delay, None]] = [] for group in distribution: self._add_entries_for_distribution_group(group, bot_levels, all_entries) @@ -1149,7 +1149,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): if self._game_over: return assert isinstance(point.value, str) - pointpos = self.map.defs.points['bot_spawn_' + point.value] + pointpos = self.map.defs.points[point.value] assert self._bots is not None self._bots.spawn_bot(spaz_type, pos=pointpos, spawn_time=spawn_time) @@ -1322,9 +1322,7 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): self.spawn_player(player) def _checkroundover(self) -> None: - """ - see if the round is over in response to an event (player died, etc) - """ + """Potentially end the round based on the state of the game.""" if self.has_ended(): return if not any(player.is_alive() for player in self.teams[0].players): diff --git a/docs/ba_module.md b/docs/ba_module.md index aad68617..f8791bb1 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-09 for Ballistica version 1.5.1 build 20062

    +

    last updated on 2020-06-09 for Ballistica version 1.5.2 build 20064

    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!


    From 3aceb6ef66078872b06369ee728e95e525d69bc7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 11 Jun 2020 01:05:07 -0700 Subject: [PATCH 086/417] Improved windows support for unicode file paths --- CHANGELOG.md | 3 +++ assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/bastd/ui/gather.py | 5 ++++- docs/ba_module.md | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 217c2f4f..5d750f61 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.3 (20065) +- Improved handling of non-ascii characters in file paths on windows. + ### 1.5.2 (20063) - Fixes an issue with controls not working correctly in net-play between 1.4.x and 1.5.x. - Tidied up onslaught code a bit. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 13993284..1c3579ac 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=328357141536767746382612764132666300753 +# SOURCES_HASH=285571727710785006475742404303651213501 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 98b122a0..f2eba248 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -807,7 +807,10 @@ class GatherWindow(ba.Window): color=(1, 0, 0)) ba.playsound(ba.getsound('error')) return - port = int(cast(str, ba.textwidget(query=port_textwidget))) + try: + port = int(cast(str, ba.textwidget(query=port_textwidget))) + except ValueError: + port = -1 if port > 65535 or port < 0: ba.screenmessage( ba.Lstr(resource='internal.invalidPortErrorText'), diff --git a/docs/ba_module.md b/docs/ba_module.md index f8791bb1..cc401a8c 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-09 for Ballistica version 1.5.2 build 20064

    +

    last updated on 2020-06-11 for Ballistica version 1.5.3 build 20065

    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!


    From e8998190d9748d10f9da894d757bcba02f2e1c06 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 11 Jun 2020 01:35:29 -0700 Subject: [PATCH 087/417] Windows unicode file handling --- .efrocachemap | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 991a8649..628fa90e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/cf/1799ab571bdc1942e58a99cc5c16", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/46/62/bc2a3dc03c8bd9bc034851cf5314", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ea/e8/d2b075dabe1e9f9358c198b8adff", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/cc/cd7704cb242e86535a688186240b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/00/cdf784fc736fcf7ec65fe6941bb3", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a8/da/466f2f0f4837069315adb4107573", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/14/f3795835f4b14e7b8c873bfdd936", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1b/c9/bb4b326efc4a125d01edb3ba6451", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e7/a0/5d8cfa3b7622468b6fff4d36a69b", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f6/05/599e4c7481031e8bfe5f901f422f", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b0/52/d3489ac0c0d25dcb2d81333f235e", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1b/b2/0169fdcb311e55fc9523ff6c53b8" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/ae/aa4cae5e9309ce07cfc03ff2944f", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/c6/8a28188601251b2aef700afb10f9", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/8f/c63f246c18317efd538de4dfc05a", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/1a/a3ffb1ac0603cf30947ccce87dfa", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/aa/09256e27c814fb9f9b2f99e98cb5", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/24/a416a8a640bc93b2cda8b7bc63dd", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/58/ac/70c757e2a387b27c6488a6f1c02f", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/15/8b3092cfa6d1ac3741b2fc130d59", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/94/a8/3400acfd642e08552db4f0b835f3", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/20/63/52c7e6f5bbcfa40bbe3c89ea4e52", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3c/de/759cec622298b40fa014dde973fe", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/0f/7d/94a2599622da87b2f2afb32ccb6b" } \ No newline at end of file From e73aabe29ca08ac800e870e8fc00ff628ded67bd Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 11 Jun 2020 01:46:47 -0700 Subject: [PATCH 088/417] More work on windows unicode paths --- .efrocachemap | 24 ++++++++++++------------ assets/src/ba_data/python/_ba.py | 2 +- docs/ba_module.md | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 628fa90e..5974d2e5 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/ae/aa4cae5e9309ce07cfc03ff2944f", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/c6/8a28188601251b2aef700afb10f9", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/8f/c63f246c18317efd538de4dfc05a", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/1a/a3ffb1ac0603cf30947ccce87dfa", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/aa/09256e27c814fb9f9b2f99e98cb5", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8b/24/a416a8a640bc93b2cda8b7bc63dd", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/58/ac/70c757e2a387b27c6488a6f1c02f", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cc/15/8b3092cfa6d1ac3741b2fc130d59", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/94/a8/3400acfd642e08552db4f0b835f3", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/20/63/52c7e6f5bbcfa40bbe3c89ea4e52", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3c/de/759cec622298b40fa014dde973fe", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/0f/7d/94a2599622da87b2f2afb32ccb6b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/1e/68e550d4c35195ec0107eaa7c3cc", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/87/6061c0714efc233f3de960432a79", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/57/26/e1302c34ed190fdc459841ac4c0b", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/81/d41441701286993b888d679a6e1f", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/0e/4bbbc1fcb601fbe602ef8e823533", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9b/63/69be4efd49f53ba0243804eea2ee", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/00/a7/a83c42934ed3b6264e8ecfada36d", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ad/2e/ec4d892345bbe6bca5da1634650e", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b9/d2/54ab31ddba6bad9efa448bcf2bbf", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a6/2a/6dd220288e4c3fd5da7218c74772", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7e/84/41846d61dddad79eb58a8f1e275b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/14/a4/54763b4472c289d67f645ad55fc3" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 1c3579ac..bb3bf141 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=285571727710785006475742404303651213501 +# SOURCES_HASH=216354265308537648782207953147562280477 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/docs/ba_module.md b/docs/ba_module.md index cc401a8c..1424c823 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-11 for Ballistica version 1.5.3 build 20065

    +

    last updated on 2020-06-11 for Ballistica version 1.5.3 build 20066

    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!


    From c062111bf25cd2661436653e26dbfd4470e32f2b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 12 Jun 2020 00:09:18 -0700 Subject: [PATCH 089/417] More windows unicode path fixes --- .efrocachemap | 24 ++++++++++++------------ .idea/dictionaries/ericf.xml | 2 ++ CHANGELOG.md | 4 ++++ assets/src/ba_data/python/_ba.py | 2 +- config/toolconfigsrc/projectile | 1 + docs/ba_module.md | 2 +- tools/efrotools/code.py | 6 ++++++ 7 files changed, 27 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 5974d2e5..65d34a6f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/1e/68e550d4c35195ec0107eaa7c3cc", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/87/6061c0714efc233f3de960432a79", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/57/26/e1302c34ed190fdc459841ac4c0b", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/81/d41441701286993b888d679a6e1f", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/0e/4bbbc1fcb601fbe602ef8e823533", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9b/63/69be4efd49f53ba0243804eea2ee", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/00/a7/a83c42934ed3b6264e8ecfada36d", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ad/2e/ec4d892345bbe6bca5da1634650e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b9/d2/54ab31ddba6bad9efa448bcf2bbf", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a6/2a/6dd220288e4c3fd5da7218c74772", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7e/84/41846d61dddad79eb58a8f1e275b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/14/a4/54763b4472c289d67f645ad55fc3" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/7b/52228a39678578bfbf59708d8781", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c2/e9/448c88572519886ad50346d1e697", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/82/4c/78d3abe7f124ed1eb097d3de1b08", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/ae/f0f303927b49b6bf9619431fe52b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/95/ad7aacb2bbc9d81b43712e3c328a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/93/d99a5e660a739a15c8ddd36e23b4", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/82/c06b47fd0baa39a844292f0e92fd", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/48/66a3b1baf1d4b095b7c204f5fda8", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/47/fe/e6a8591b85e2ab02952920f87f1d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6c/60/28ed4dda33d29ef45d14f68b0d97", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/09/81/91fd4c5736515071cb28a3b5f520", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fc/c1/99b8e7db8426572427d3a901978d" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index f2845589..a32f3722 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1286,6 +1286,7 @@ nodpi nofiles noinspect + nondeterministic noninfringement nonmultipart noone @@ -2055,6 +2056,7 @@ uninited uniquify unixccompiler + unknownlintline unlinkable unlinking unlinks diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d750f61..aa5d6279 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.5.4 (20067) +- Should now work properly with non-ascii paths on Windows (for real this time). +- Misc cleanup and minor bug fixes. + ### 1.5.3 (20065) - Improved handling of non-ascii characters in file paths on windows. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index bb3bf141..074c725d 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=216354265308537648782207953147562280477 +# SOURCES_HASH=160088015161796037115905411263701036909 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/config/toolconfigsrc/projectile b/config/toolconfigsrc/projectile index e7af40de..11766487 100644 --- a/config/toolconfigsrc/projectile +++ b/config/toolconfigsrc/projectile @@ -1,2 +1,3 @@ +/tools +/assets/src/ba_data/python ++/ballisticacore-android/BallisticaCore/src diff --git a/docs/ba_module.md b/docs/ba_module.md index 1424c823..cc475203 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-11 for Ballistica version 1.5.3 build 20066

    +

    last updated on 2020-06-11 for Ballistica version 1.5.3 build 20067

    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!


    diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 72c46b63..a7518aa1 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -142,6 +142,12 @@ def cpplint(projroot: Path, full: bool) -> None: codelines[headercheckline] = ( " if False and include and include.group(1) in ('cfenv',") + # Don't complain about unknown NOLINT categories. + # (we use them for clang-tidy) + unknownlintline = codelines.index( + ' elif category not in _LEGACY_ERROR_CATEGORIES:') + codelines[unknownlintline] = ' elif False:' + def lint_file(filename: str) -> None: result = subprocess.call(['cpplint', '--root=src', filename], env=env) if result != 0: From 030eedc3829f07587bbeabb8103ca336d7a542f5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 12 Jun 2020 13:20:21 -0700 Subject: [PATCH 090/417] Language updates --- .efrocachemap | 36 ++++++++++++++++++------------------ tools/stage_assets | 16 +++++++++++----- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 65d34a6f..615253c2 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/1a/f1/5f137cf224ef00126e7bcbbcd6e7", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d7/12/16632915fdb57dc6e07fc04413cc", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", @@ -435,12 +435,12 @@ "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/9d/00/a8c4ef9f0a25e789c046bd741203", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8e/24/f070599beb7b09e1268569fa55b1", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", - "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/7a/64/04464dc6ee8a45632857fa436bff", + "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/ae/22/c1976a822db658e5aa732b21228e", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/8e/e7/38e093014a917418e6cf7aa9315d", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/6f/df2600b658a163f80077bd6c8d78", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/ef/b1935b3767692070f070847f40df", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/c2/fc/dd1c15cf9ecb411d9defbd000c06", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/ee/72/7c6705486a19856fb6587f6d03e7", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", @@ -449,9 +449,9 @@ "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a9/77/722faae6a695f19501bac76098db", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/30/70/ba6f57b2d865d0027a50c6e1dba5", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/ef/61/7dcdc48c7039bbad6cd01d3f9a1f", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/e0/f7/f6daa488dc29e303dea69aae864b", - "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/5f/a8/7d563fe99b8d1d1eb9bea49dc5df", + "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f1/00/c4ccd5969084505359e07f927b3a", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", "assets/build/ba_data/data/maps/courtyard.json": "https://files.ballistica.net/cache/ba1/03/38/344dd05bfef7bbdf464035ec5aa2", @@ -4132,16 +4132,16 @@ "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/7b/52228a39678578bfbf59708d8781", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c2/e9/448c88572519886ad50346d1e697", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/82/4c/78d3abe7f124ed1eb097d3de1b08", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d8/ae/f0f303927b49b6bf9619431fe52b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/95/ad7aacb2bbc9d81b43712e3c328a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/93/d99a5e660a739a15c8ddd36e23b4", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/82/c06b47fd0baa39a844292f0e92fd", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/48/66a3b1baf1d4b095b7c204f5fda8", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/47/fe/e6a8591b85e2ab02952920f87f1d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6c/60/28ed4dda33d29ef45d14f68b0d97", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/09/81/91fd4c5736515071cb28a3b5f520", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fc/c1/99b8e7db8426572427d3a901978d" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/79/a7/7ac018279a128aa32a5a416d3eff", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/4f/4a39906d3f891d93681e69b66d70", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8f/bd/cb7e2f48f7b17f89a5cd832c3554", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0b/b5/70ba3a3c723abde24ecef56a27d9", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ea/62/c659150da05f7ddf14bbbf5925a5", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/2a/1745f2848d2ccc39b22bf7bbacc5", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8a/00/f12aa5d62f2ba41a2f2f44bf8e67", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/03/eea3689c697343e58ee8c643ba38", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a7/24/2e46ae146cf830384c81679ee329", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/43/e3/b8b60b2cbff091a969a1ea6b8cea", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8b/72/798e5fb6c2b714c471a549aeb577", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/06/fc/5987010f8f24bd493fa78f9ca505" } \ No newline at end of file diff --git a/tools/stage_assets b/tools/stage_assets index 14b8d80c..6bdc48df 100755 --- a/tools/stage_assets +++ b/tools/stage_assets @@ -26,6 +26,7 @@ from __future__ import annotations import hashlib import os import sys +import subprocess from functools import partial from typing import TYPE_CHECKING @@ -203,22 +204,24 @@ def _write_payload_file(assets_root: str, full: bool) -> None: fpath = os.path.join(root, fname) fpathshort = fpath.replace(assets_root, '') if ' ' in fpathshort: - raise Exception("invalid filename found (contains spaces): '" + - fpathshort + "'") + raise RuntimeError( + f"Invalid filename (contains spaces): '{fpathshort}'") payload_str += fpathshort + ' ' + md5sum(fpath) + '\n' file_list.append(fpathshort) + payload_path = assets_root + '/payload_info' if file_list: # Write the file count, whether this is a 'full' payload, and finally # the file list. payload_str = (str(len(file_list)) + '\n' + ('1' if full else '0') + '\n' + payload_str) - payload_path = assets_root + '/payload_info' with open(payload_path, 'w') as outfile: outfile.write(payload_str) else: - # Hmm; do we need to build an empty payload in this case? - pass + # Remove the payload file; this will cause the game to completely + # skip the payload processing step. + if os.path.exists(payload_path): + os.unlink(payload_path) def _sync_windows_extras(cfg: Config) -> None: @@ -288,6 +291,9 @@ def main() -> None: # Do our stripped down pylib dir for platforms that use that. if cfg.include_pylib: _sync_pylib(cfg) + else: + if cfg.dst is not None and os.path.isdir(cfg.dst + '/pylib'): + subprocess.run(['rm', '-rf', cfg.dst + '/pylib'], check=True) # On windows we need to pull in some dlls and this and that # (we also include a non-stripped-down set of python libs). From d548da781ba4b4ca678a006e3c5a1f06951bf1e9 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 13 Jun 2020 19:13:39 -0700 Subject: [PATCH 091/417] Added windows debug dlls --- .efrocachemap | 33 +++-- .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 1 + Makefile | 18 +-- assets/.asset_manifest_private.json | 9 +- assets/Makefile | 11 +- assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/_meta.py | 18 ++- assets/src/ba_data/python/ba/_stats.py | 2 +- .../ba_data/python/bastd/ui/colorpicker.py | 53 ++++--- .../python/bastd/ui/settings/gamepad.py | 13 +- docs/ba_module.md | 2 +- tools/stage_assets | 130 ++++++++++++------ 13 files changed, 175 insertions(+), 118 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 615253c2..d337605a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/d7/12/16632915fdb57dc6e07fc04413cc", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/8d/3d/bcd72bb471b185102c2598cd2346", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", @@ -440,7 +440,7 @@ "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/6f/df2600b658a163f80077bd6c8d78", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/ef/b1935b3767692070f070847f40df", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/ee/72/7c6705486a19856fb6587f6d03e7", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/8e/3f/41e12b96fc07a623d89153b10c38", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", @@ -4125,23 +4125,26 @@ "assets/build/windows/x64/Lib/zipfile.py": "https://files.ballistica.net/cache/ba1/a6/3c/116c6602b0176d208f3e2a4813de", "assets/build/windows/x64/OpenAL32.dll": "https://files.ballistica.net/cache/ba1/a1/7f/e92ff76218c4b8cfce9bc72d5324", "assets/build/windows/x64/SDL2.dll": "https://files.ballistica.net/cache/ba1/b2/c1/0d3f95340344968b2aac3fc4a979", - "assets/build/windows/x64/VC_redist.x64.exe": "https://files.ballistica.net/cache/ba1/31/1b/07fbd2f6e9bf7eb8741ad9f7d811", "assets/build/windows/x64/libvorbis.dll": "https://files.ballistica.net/cache/ba1/2d/ec/f52561af5804abd5c646e364dea9", "assets/build/windows/x64/libvorbisfile.dll": "https://files.ballistica.net/cache/ba1/8c/2a/ef525f4ae1de3b46a23fbdd0dfde", + "assets/build/windows/x64/msvcp140d.dll": "https://files.ballistica.net/cache/ba1/25/73/87d96678583aabd18407963ac8b0", "assets/build/windows/x64/ogg.dll": "https://files.ballistica.net/cache/ba1/1b/3e/382012f9d092e45f211561e8b5ee", "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/79/a7/7ac018279a128aa32a5a416d3eff", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/4f/4a39906d3f891d93681e69b66d70", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8f/bd/cb7e2f48f7b17f89a5cd832c3554", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0b/b5/70ba3a3c723abde24ecef56a27d9", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ea/62/c659150da05f7ddf14bbbf5925a5", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/2a/1745f2848d2ccc39b22bf7bbacc5", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8a/00/f12aa5d62f2ba41a2f2f44bf8e67", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/03/eea3689c697343e58ee8c643ba38", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a7/24/2e46ae146cf830384c81679ee329", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/43/e3/b8b60b2cbff091a969a1ea6b8cea", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8b/72/798e5fb6c2b714c471a549aeb577", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/06/fc/5987010f8f24bd493fa78f9ca505" + "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/f1/3b/224ab441922e2cd0f95a042eca63", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/01/1382cb73f9a4484a49ba603429fc", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/dc/dcbe26dc38ac257f792cf10f0460", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/16/a4f73103c2db98225fb3c7763ea7", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/fd/969e660fbbd15177aeb5d79aaad3", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/dc/1b4b59fcf7e1b3a2fabfb6fa7762", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5f/80/3fc03f524c5ab0ca0f18bef1c994", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/72/c7/1b3960aeb864e2d69e7588c2fd70", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/13/25/c5ed7e41549396a2a376a547778d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0d/b7/144275e1c533a0b077d62610ff6b", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f5/80/08ff1c67de148ecd203892499a56", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d6/03/2fdba74ac6883ff5408b6a165f04" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index a32f3722..c9101d02 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1568,6 +1568,7 @@ pypaths pysources pytest + pythondirs pythondontwritebytecode pythonhashseed pythonpath diff --git a/CHANGELOG.md b/CHANGELOG.md index aa5d6279..c0737fb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.5.4 (20067) - Should now work properly with non-ascii paths on Windows (for real this time). +- Note that Windows game data is now stored under 'Local' appdata instead of 'Roaming'; if you have an old install with data you want to preserve, you may want to move it over manually. - Misc cleanup and minor bug fixes. ### 1.5.3 (20065) diff --git a/Makefile b/Makefile index 28aca96d..47257e12 100644 --- a/Makefile +++ b/Makefile @@ -185,7 +185,7 @@ prefab-mac-server-debug-build: prereqs assets-cmake \ build/prefab/mac-server/debug/ballisticacore_server \ build/prefab/mac-server/debug/config_template.yaml \ build/prefab/mac-server/debug/README.txt - @${STAGE_ASSETS} -cmake-server build/prefab/mac-server/debug/dist + @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/debug/dist build/prefab/mac-server/debug/ballisticacore_server: \ assets/src/server/ballisticacore_server.py @@ -216,7 +216,7 @@ prefab-mac-server-release-build: prereqs assets-cmake \ build/prefab/mac-server/release/ballisticacore_server \ build/prefab/mac-server/release/config_template.yaml \ build/prefab/mac-server/release/README.txt - @${STAGE_ASSETS} -cmake-server build/prefab/mac-server/release/dist + @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/release/dist build/prefab/mac-server/release/ballisticacore_server: \ assets/src/server/ballisticacore_server.py @@ -273,7 +273,7 @@ prefab-linux-server-debug-build: prereqs assets-cmake \ build/prefab/linux-server/debug/ballisticacore_server \ build/prefab/linux-server/debug/config_template.yaml \ build/prefab/linux-server/debug/README.txt - @${STAGE_ASSETS} -cmake-server build/prefab/linux-server/debug/dist + @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/debug/dist build/prefab/linux-server/debug/ballisticacore_server: \ assets/src/server/ballisticacore_server.py @@ -304,7 +304,7 @@ prefab-linux-server-release-build: prereqs assets-cmake \ build/prefab/linux-server/release/ballisticacore_server \ build/prefab/linux-server/release/config_template.yaml \ build/prefab/linux-server/release/README.txt - @${STAGE_ASSETS} -cmake-server build/prefab/linux-server/release/dist + @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/release/dist build/prefab/linux-server/release/ballisticacore_server: \ assets/src/server/ballisticacore_server.py @@ -333,7 +333,8 @@ prefab-windows-debug: prefab-windows-debug-build prefab-windows-debug-build: prereqs assets-windows-${PREFAB_WINDOWS_PLATFORM} \ build/prefab/windows/debug/BallisticaCore.exe - @${STAGE_ASSETS} -win-$(PREFAB_WINDOWS_PLATFORM) build/prefab/windows/debug + @${STAGE_ASSETS} -win-${PREFAB_WINDOWS_PLATFORM}-Debug \ +build/prefab/windows/debug build/prefab/windows/debug/BallisticaCore.exe: .efrocachemap @tools/snippets efrocache_get $@ @@ -348,7 +349,8 @@ prefab-windows-release: prefab-windows-release-build prefab-windows-release-build: prereqs \ assets-windows-${PREFAB_WINDOWS_PLATFORM} \ build/prefab/windows/release/BallisticaCore.exe - @${STAGE_ASSETS} -win-$(PREFAB_WINDOWS_PLATFORM) build/prefab/windows/release + @${STAGE_ASSETS} -win-${PREFAB_WINDOWS_PLATFORM}-Release \ +build/prefab/windows/release build/prefab/windows/release/BallisticaCore.exe: .efrocachemap @tools/snippets efrocache_get $@ @@ -367,7 +369,7 @@ prefab-windows-server-debug-build: prereqs \ build/prefab/windows-server/debug/ballisticacore_server.py \ build/prefab/windows-server/debug/config_template.yaml \ build/prefab/windows-server/debug/README.txt - @${STAGE_ASSETS} -win-$(PREFAB_WINDOWS_PLATFORM) \ + @${STAGE_ASSETS} -winserver-${PREFAB_WINDOWS_PLATFORM}-Debug \ build/prefab/windows-server/debug/dist build/prefab/windows-server/debug/dist/ballisticacore_headless.exe: .efrocachemap @@ -405,7 +407,7 @@ prefab-windows-server-release-build: prereqs \ build/prefab/windows-server/release/ballisticacore_server.py \ build/prefab/windows-server/release/config_template.yaml \ build/prefab/windows-server/release/README.txt - @${STAGE_ASSETS} -win-$(PREFAB_WINDOWS_PLATFORM) \ + @${STAGE_ASSETS} -winserver-${PREFAB_WINDOWS_PLATFORM}-Release \ build/prefab/windows-server/release/dist build/prefab/windows-server/release/dist/ballisticacore_headless.exe: .efrocachemap diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json index 8da5c579..d782cc5a 100644 --- a/assets/.asset_manifest_private.json +++ b/assets/.asset_manifest_private.json @@ -5663,13 +5663,13 @@ "windows/Win32/Lib/zipfile.py", "windows/Win32/OpenAL32.dll", "windows/Win32/SDL2.dll", - "windows/Win32/VC_redist.x86.exe", "windows/Win32/libvorbis.dll", "windows/Win32/libvorbisfile.dll", "windows/Win32/ogg.dll", "windows/Win32/python.exe", "windows/Win32/python37.dll", "windows/Win32/pythonw.exe", + "windows/Win32/vc_redist.x86.exe", "windows/x64/DLLs/_asyncio.pyd", "windows/x64/DLLs/_bz2.pyd", "windows/x64/DLLs/_ctypes.pyd", @@ -7054,11 +7054,14 @@ "windows/x64/Lib/zipfile.py", "windows/x64/OpenAL32.dll", "windows/x64/SDL2.dll", - "windows/x64/VC_redist.x64.exe", "windows/x64/libvorbis.dll", "windows/x64/libvorbisfile.dll", + "windows/x64/msvcp140d.dll", "windows/x64/ogg.dll", "windows/x64/python.exe", "windows/x64/python37.dll", - "windows/x64/pythonw.exe" + "windows/x64/pythonw.exe", + "windows/x64/vc_redist.x64.exe", + "windows/x64/vcruntime140_1d.dll", + "windows/x64/vcruntime140d.dll" ] \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 56a530a5..96829c3e 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -20028,13 +20028,13 @@ EXTRAS_TARGETS_WIN_WIN32 = \ build/windows/Win32/Lib/venv/scripts/posix/activate.fish \ build/windows/Win32/OpenAL32.dll \ build/windows/Win32/SDL2.dll \ - build/windows/Win32/VC_redist.x86.exe \ build/windows/Win32/libvorbis.dll \ build/windows/Win32/libvorbisfile.dll \ build/windows/Win32/ogg.dll \ build/windows/Win32/python.exe \ build/windows/Win32/python37.dll \ - build/windows/Win32/pythonw.exe + build/windows/Win32/pythonw.exe \ + build/windows/Win32/vc_redist.x86.exe # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_WIN32) : ../.efrocachemap @@ -20090,13 +20090,16 @@ EXTRAS_TARGETS_WIN_X64 = \ build/windows/x64/Lib/venv/scripts/posix/activate.fish \ build/windows/x64/OpenAL32.dll \ build/windows/x64/SDL2.dll \ - build/windows/x64/VC_redist.x64.exe \ build/windows/x64/libvorbis.dll \ build/windows/x64/libvorbisfile.dll \ + build/windows/x64/msvcp140d.dll \ build/windows/x64/ogg.dll \ build/windows/x64/python.exe \ build/windows/x64/python37.dll \ - build/windows/x64/pythonw.exe + build/windows/x64/pythonw.exe \ + build/windows/x64/vc_redist.x64.exe \ + build/windows/x64/vcruntime140_1d.dll \ + build/windows/x64/vcruntime140d.dll # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_X64) : ../.efrocachemap diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 074c725d..eba2eed8 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=160088015161796037115905411263701036909 +# SOURCES_HASH=30991209163728546136111726610486266810 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index 14669765..49a01a44 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -56,14 +56,13 @@ def start_scan() -> None: app = _ba.app if app.metascan is not None: print('WARNING: meta scan run more than once.') - scriptdirs = [app.python_directory_app, app.python_directory_user] - thread = ScanThread(scriptdirs) + pythondirs = [app.python_directory_app, app.python_directory_user] + thread = ScanThread(pythondirs) thread.start() def handle_scan_results(results: ScanResults) -> None: """Called in the game thread with results of a completed scan.""" - from ba import _lang # Warnings generally only get printed locally for users' benefit # (things like out-of-date scripts being ignored, etc.) @@ -71,13 +70,16 @@ def handle_scan_results(results: ScanResults) -> None: # warnings = results.get('warnings', '') # errors = results.get('errors', '') if results.warnings != '' or results.errors != '': - _ba.screenmessage(_lang.Lstr(resource='scanScriptsErrorText'), + import textwrap + from ba._lang import Lstr + _ba.screenmessage(Lstr(resource='scanScriptsErrorText'), color=(1, 0, 0)) _ba.playsound(_ba.getsound('error')) if results.warnings != '': - _ba.log(results.warnings, to_server=False) + _ba.log(textwrap.indent(results.warnings, 'Warning (meta-scan): '), + to_server=False) if results.errors != '': - _ba.log(results.errors) + _ba.log(textwrap.indent(results.errors, 'Error (meta-scan): ')) class ScanThread(threading.Thread): @@ -124,7 +126,9 @@ class DirectoryScan: 'warnings': warnings from scan; should be printed for local feedback 'errors': errors encountered during scan; should be fully logged """ - self.paths = [pathlib.Path(p) for p in paths] + + # Skip non-existent paths completely. + self.paths = [pathlib.Path(p) for p in paths if os.path.isdir(p)] self.results = ScanResults() def _get_path_module_entries( diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 317e8c83..5d94bbe6 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -206,7 +206,7 @@ class PlayerRecord: # Only award this if they're still alive and we can get # a current position for them. our_pos: Optional[ba.Vec3] = None - if self._sessionplayer is not None: + if self._sessionplayer: if self._sessionplayer.activityplayer is not None: try: our_pos = self._sessionplayer.activityplayer.position diff --git a/assets/src/ba_data/python/bastd/ui/colorpicker.py b/assets/src/ba_data/python/bastd/ui/colorpicker.py index c9133de0..8684c340 100644 --- a/assets/src/ba_data/python/bastd/ui/colorpicker.py +++ b/assets/src/ba_data/python/bastd/ui/colorpicker.py @@ -25,13 +25,13 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -from bastd.ui import popup +from bastd.ui.popup import PopupWindow if TYPE_CHECKING: from typing import Any, Tuple, Sequence, List, Optional -class ColorPicker(popup.PopupWindow): +class ColorPicker(PopupWindow): """A popup UI to select from a set of colors. Passes the color to the delegate's color_picker_selected_color() method. @@ -49,8 +49,7 @@ class ColorPicker(popup.PopupWindow): from ba.internal import have_pro, get_player_colors c_raw = get_player_colors() - if len(c_raw) != 16: - raise ValueError('expected 16 player colors') + assert len(c_raw) == 16 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] if scale is None: @@ -66,14 +65,14 @@ class ColorPicker(popup.PopupWindow): self._initial_color = initial_color # Create our _root_widget. - popup.PopupWindow.__init__(self, - position=position, - size=(210, 240), - scale=scale, - focus_position=(10, 10), - focus_size=(190, 220), - bg_color=(0.5, 0.5, 0.5), - offset=offset) + PopupWindow.__init__(self, + position=position, + size=(210, 240), + scale=scale, + focus_position=(10, 10), + focus_size=(190, 220), + bg_color=(0.5, 0.5, 0.5), + offset=offset) rows: List[List[ba.Widget]] = [] closest_dist = 9999.0 closest = (0, 0) @@ -172,7 +171,7 @@ class ColorPicker(popup.PopupWindow): self._transition_out() -class ColorPickerExact(popup.PopupWindow): +class ColorPickerExact(PopupWindow): """ pops up a ui to select from a set of colors. passes the color to the delegate's color_picker_selected_color() method """ @@ -185,11 +184,10 @@ class ColorPickerExact(popup.PopupWindow): offset: Tuple[float, float] = (0.0, 0.0), tag: Any = ''): # pylint: disable=too-many-locals - del parent # unused var + del parent # Unused var. from ba.internal import get_player_colors c_raw = get_player_colors() - if len(c_raw) != 16: - raise ValueError('expected 16 player colors') + assert len(c_raw) == 16 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] if scale is None: @@ -207,15 +205,15 @@ class ColorPickerExact(popup.PopupWindow): width = 180.0 height = 240.0 - # creates our _root_widget - popup.PopupWindow.__init__(self, - position=position, - size=(width, height), - scale=scale, - focus_position=(10, 10), - focus_size=(width - 20, height - 20), - bg_color=(0.5, 0.5, 0.5), - offset=offset) + # Creates our _root_widget. + PopupWindow.__init__(self, + position=position, + size=(width, height), + scale=scale, + focus_position=(10, 10), + focus_size=(width - 20, height - 20), + bg_color=(0.5, 0.5, 0.5), + offset=offset) self._swatch = ba.imagewidget(parent=self.root_widget, position=(width * 0.5 - 50, height - 70), size=(100, 70), @@ -264,14 +262,15 @@ class ColorPickerExact(popup.PopupWindow): autoselect=True) ba.containerwidget(edit=self.root_widget, start_button=btn) - # unlike the swatch picker, we stay open and constantly push our - # color to the delegate, so start doing that... + # Unlike the swatch picker, we stay open and constantly push our + # color to the delegate, so start doing that. self._update_for_color() def _update_for_color(self) -> None: if not self.root_widget: return ba.imagewidget(edit=self._swatch, color=self._color) + # We generate these procedurally, so pylint misses them. # FIXME: create static attrs instead. ba.textwidget(edit=self._label_r, text='%.2f' % self._color[0]) diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index 8faea5ad..f35abb36 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -42,13 +42,12 @@ class GamepadSettingsWindow(ba.Window): settings: dict = None): self._input = gamepad - # If this fails, our input device went away or something; - # just return an empty zombie then. - try: - self._name = self._input.name - except Exception: + # If our input-device went away, just return an empty zombie. + if not self._input: return + self._name = self._input.name + self._r = 'configGamepadWindow' self._settings = settings self._transition_out = transition_out @@ -776,8 +775,8 @@ class AwaitGamepadInputWindow(ba.Window): message2: ba.Lstr = None): if message is None: print('AwaitGamepadInputWindow message is None!') - message = ba.Lstr( - value='Press any button...') # Shouldn't get here. + # Shouldn't get here. + message = ba.Lstr(value='Press any button...') self._callback = callback self._input = gamepad self._capture_button = button diff --git a/docs/ba_module.md b/docs/ba_module.md index cc475203..d7a89752 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-11 for Ballistica version 1.5.3 build 20067

    +

    last updated on 2020-06-13 for Ballistica version 1.5.4 build 20067

    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!


    diff --git a/tools/stage_assets b/tools/stage_assets index 6bdc48df..bd893bb2 100755 --- a/tools/stage_assets +++ b/tools/stage_assets @@ -30,10 +30,11 @@ import subprocess from functools import partial from typing import TYPE_CHECKING +from efro.error import CleanError from efrotools.pybuild import PYTHON_VERSION_MAJOR if TYPE_CHECKING: - from typing import Optional + from typing import Optional, List # Suffix for the pyc files we include in stagings. # We're using deterministic opt pyc files; see PEP 552. @@ -53,6 +54,7 @@ class Config: os.path.dirname(sys.argv[0]) + '/../assets/build') self.dst: Optional[str] = None self.win_extras_src: Optional[str] = None + self.win_platform: Optional[str] = None self.include_audio = True self.include_models = True self.include_collide_models = True @@ -66,6 +68,7 @@ class Config: self.include_payload_file = False self.tex_suffix: Optional[str] = None self.is_payload_full = False + self.debug = False def _parse_android_args(self) -> None: # On Android we get nitpicky with what @@ -114,40 +117,53 @@ class Config: elif arg == '-audio': self.include_audio = True + def _parse_win_platform(self, platform: str) -> None: + """Parse sub-args in the windows platform string.""" + winempty, wintype, winplt, wincfg = platform.split('-') + self.win_platform = winplt + assert winempty == '' + self.dst = sys.argv[2] + self.tex_suffix = '.dds' + + if wintype == 'win': + pass + elif wintype == 'winserver': + self.include_textures = False + self.include_audio = False + self.include_models = False + else: + raise RuntimeError(f'Invalid wintype: "{wintype}"') + + if winplt == 'Win32': + self.win_extras_src = os.path.abspath( + os.path.dirname(sys.argv[0]) + + '/../assets/build/windows/Win32') + elif winplt == 'x64': + self.win_extras_src = os.path.abspath( + os.path.dirname(sys.argv[0]) + '/../assets/build/windows/x64') + else: + raise RuntimeError(f'Invalid winplt: "{winplt}"') + + if wincfg == 'Debug': + self.debug = True + elif wincfg == 'Release': + self.debug = False + else: + raise RuntimeError(f'Invalid wincfg: "{wincfg}"') + def parse_args(self) -> None: """Parse args and apply to the cfg.""" - if '-android' in sys.argv: + if len(sys.argv) < 2: + raise RuntimeError('Expected a platform argument.') + platform = sys.argv[1] + if platform == '-android': self._parse_android_args() - elif '-cmake' in sys.argv: + elif platform.startswith('-win'): + self._parse_win_platform(platform) + elif platform == '-cmake': self.dst = sys.argv[2] self.tex_suffix = '.dds' - elif '-win-Win32' in sys.argv: - self.dst = sys.argv[2] - self.tex_suffix = '.dds' - self.win_extras_src = os.path.abspath( - os.path.dirname(sys.argv[0]) + - '/../assets/build/windows/Win32') - elif '-win-x64' in sys.argv: - self.dst = sys.argv[2] - self.tex_suffix = '.dds' - self.win_extras_src = os.path.abspath( - os.path.dirname(sys.argv[0]) + '/../assets/build/windows/x64') - elif '-win-server-Win32' in sys.argv: - self.dst = sys.argv[2] - self.win_extras_src = os.path.abspath( - os.path.dirname(sys.argv[0]) + - '/../assets/build/windows/Win32') - self.include_textures = False - self.include_audio = False - self.include_models = False - elif '-win-server-x64' in sys.argv: - self.dst = sys.argv[2] - self.win_extras_src = os.path.abspath( - os.path.dirname(sys.argv[0]) + '/../assets/build/windows/x64') - self.include_textures = False - self.include_audio = False - self.include_models = False - elif '-cmake-server' in sys.argv: + elif '-cmakeserver' in sys.argv: self.dst = sys.argv[2] self.include_textures = False self.include_audio = False @@ -167,7 +183,7 @@ class Config: self.pylib_src_name = 'pylib-apple' self.tex_suffix = '.pvr' else: - raise Exception('no valid platform set') + raise RuntimeError('No valid platform arg provided.') def md5sum(filename: str) -> str: @@ -226,20 +242,18 @@ def _write_payload_file(assets_root: str, full: bool) -> None: def _sync_windows_extras(cfg: Config) -> None: assert cfg.win_extras_src is not None + assert cfg.win_platform is not None if not os.path.isdir(cfg.win_extras_src): raise Exception('win extras src dir not found: ' + cfg.win_extras_src) # Ok, lets do full syncs on each subdir we find so we # properly delete anything in dst that disappeared from src. # Lastly we'll sync over the remaining top level files. - # It'll technically be possible to orphaned top level - # files in dst, but we should be pulling those into dists - # individually by name anyway so it should be safe. + # Note: technically it'll be possible to leave orphaned top level + # files in dst, so when building packages/etc. we should always start + # from scratch. assert cfg.dst is not None for dirname in ('DLLs', 'Lib'): - # We also need to be more particular about which pyc files we pull - # over. The Python stuff in Extras is also used by some scripts - # so there may be arbitrary non-opt pycs hanging around. _run(f'mkdir -p "{cfg.dst}/{dirname}"') cmd = ('rsync --recursive --update --delete --delete-excluded ' ' --prune-empty-dirs' @@ -251,15 +265,39 @@ def _sync_windows_extras(cfg: Config) -> None: '"' + cfg.dst + '/' + dirname + '/"') _run(cmd) - # Now sync the top level individual files. - cmd = ('rsync --update ' + cfg.win_extras_src + '/*.dll ' + - cfg.win_extras_src + '/*.exe' - ' "' + cfg.dst + '/"') - _run(cmd) + # Now sync the top level individual files that we want. + # (we could technically copy everything over but this keeps staging + # dirs a bit tidier) + toplevelfiles: List[str] = [ + 'libvorbis.dll', 'libvorbisfile.dll', 'ogg.dll', 'OpenAL32.dll', + 'SDL2.dll' + ] + + # Include debug dlls for x64 so folks without msvc can run them. + # (seems win32 doesn't have the same set so ignoring that for now) + if cfg.debug and cfg.win_platform == 'x64': + toplevelfiles += [ + 'msvcp140d.dll', 'vcruntime140d.dll', 'vcruntime140_1d.dll' + ] + + # Include the runtime redistributables in release builds. + if not cfg.debug: + if cfg.win_platform == 'x64': + toplevelfiles.append('vc_redist.x64.exe') + elif cfg.win_platform == 'Win32': + toplevelfiles.append('vc_redist.x86.exe') + else: + raise RuntimeError(f'Invalid win_platform {cfg.win_platform}') + + cmd2 = (['rsync', '--update'] + + [os.path.join(cfg.win_extras_src, f) + for f in toplevelfiles] + [cfg.dst + '/']) + subprocess.run(cmd2, check=True) # If we're running under WSL we won't be able to launch these .exe files # unless they're marked executable, so do that here. - _run(f'chmod +x {cfg.dst}/*.exe') + # Update: gonna try simply setting this flag on the source side. + # _run(f'chmod +x {cfg.dst}/*.exe') def _sync_pylib(cfg: Config) -> None: @@ -339,4 +377,8 @@ def main() -> None: if __name__ == '__main__': - main() + try: + main() + except CleanError as exc: + exc.pretty_print() + sys.exit(1) From c749b99261740ac55ed10f010f14bc3c1b2cb51d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 13 Jun 2020 19:52:08 -0700 Subject: [PATCH 092/417] Cleaned up packaged files on windows --- .efrocachemap | 12 ++++++------ tools/stage_assets | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index d337605a..196e2bcd 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4139,12 +4139,12 @@ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/01/1382cb73f9a4484a49ba603429fc", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/dc/dcbe26dc38ac257f792cf10f0460", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/16/a4f73103c2db98225fb3c7763ea7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/fd/969e660fbbd15177aeb5d79aaad3", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/56/3e/c92b2d32d11f9adb59f80f040ed7", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/dc/1b4b59fcf7e1b3a2fabfb6fa7762", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5f/80/3fc03f524c5ab0ca0f18bef1c994", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/34/7a7d8aae625e6c871cdf8cc8607e", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/72/c7/1b3960aeb864e2d69e7588c2fd70", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/13/25/c5ed7e41549396a2a376a547778d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0d/b7/144275e1c533a0b077d62610ff6b", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f5/80/08ff1c67de148ecd203892499a56", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d6/03/2fdba74ac6883ff5408b6a165f04" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2b/50/6e2a0606fdd282de8b421d548bcd", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/29/d1/b98723d9348f444db169dc7e2ea4", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2f/ad/c921162d7f618ee39846618579f6", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f7/b5/797749be0b3dbcc8bab3e8f2fa17" } \ No newline at end of file diff --git a/tools/stage_assets b/tools/stage_assets index bd893bb2..e528135c 100755 --- a/tools/stage_assets +++ b/tools/stage_assets @@ -55,6 +55,7 @@ class Config: self.dst: Optional[str] = None self.win_extras_src: Optional[str] = None self.win_platform: Optional[str] = None + self.win_type: Optional[str] = None self.include_audio = True self.include_models = True self.include_collide_models = True @@ -121,6 +122,7 @@ class Config: """Parse sub-args in the windows platform string.""" winempty, wintype, winplt, wincfg = platform.split('-') self.win_platform = winplt + self.win_type = wintype assert winempty == '' self.dst = sys.argv[2] self.tex_suffix = '.dds' @@ -243,6 +245,7 @@ def _write_payload_file(assets_root: str, full: bool) -> None: def _sync_windows_extras(cfg: Config) -> None: assert cfg.win_extras_src is not None assert cfg.win_platform is not None + assert cfg.win_type is not None if not os.path.isdir(cfg.win_extras_src): raise Exception('win extras src dir not found: ' + cfg.win_extras_src) @@ -268,10 +271,15 @@ def _sync_windows_extras(cfg: Config) -> None: # Now sync the top level individual files that we want. # (we could technically copy everything over but this keeps staging # dirs a bit tidier) - toplevelfiles: List[str] = [ - 'libvorbis.dll', 'libvorbisfile.dll', 'ogg.dll', 'OpenAL32.dll', - 'SDL2.dll' - ] + toplevelfiles: List[str] = [] + + if cfg.win_type == 'win': + toplevelfiles += [ + 'libvorbis.dll', 'libvorbisfile.dll', 'ogg.dll', 'OpenAL32.dll', + 'SDL2.dll' + ] + elif cfg.win_type == 'winserver': + toplevelfiles += ['python.exe'] # Include debug dlls for x64 so folks without msvc can run them. # (seems win32 doesn't have the same set so ignoring that for now) From 2b75410a6be00aa399c2435e8be081b42a740844 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 13 Jun 2020 20:20:38 -0700 Subject: [PATCH 093/417] Fix win permission issue --- .efrocachemap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 196e2bcd..cad4929a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4139,12 +4139,12 @@ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/01/1382cb73f9a4484a49ba603429fc", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/dc/dcbe26dc38ac257f792cf10f0460", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/16/a4f73103c2db98225fb3c7763ea7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/56/3e/c92b2d32d11f9adb59f80f040ed7", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/c6/84709839bd04b9748b923a4f0835", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/dc/1b4b59fcf7e1b3a2fabfb6fa7762", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/34/7a7d8aae625e6c871cdf8cc8607e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/99/f1/c660885092c3a71294ce6da4dcdb", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/72/c7/1b3960aeb864e2d69e7588c2fd70", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2b/50/6e2a0606fdd282de8b421d548bcd", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/29/d1/b98723d9348f444db169dc7e2ea4", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2f/ad/c921162d7f618ee39846618579f6", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f7/b5/797749be0b3dbcc8bab3e8f2fa17" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e1/a8/a51c079fd89b97f7012a1d5073cf", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fd/92/e3a182bde513b4ecd1c9cdda72e3", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/12/cc/152f14e0b34dee25fe4fb6cbbe74", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d7/ae/b1d17450314143afac2411bc9c64" } \ No newline at end of file From 12e748ad8a9e1d04181241b89bcd9751c56d568d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 13 Jun 2020 20:21:49 -0700 Subject: [PATCH 094/417] Minor fix --- .efrocachemap | 12 ++++++------ assets/Makefile | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index cad4929a..5477a01c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4139,12 +4139,12 @@ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/01/1382cb73f9a4484a49ba603429fc", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/dc/dcbe26dc38ac257f792cf10f0460", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/16/a4f73103c2db98225fb3c7763ea7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/c6/84709839bd04b9748b923a4f0835", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/31/d7/a5fd6808a0f5031359e90d00f29b", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/dc/1b4b59fcf7e1b3a2fabfb6fa7762", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/99/f1/c660885092c3a71294ce6da4dcdb", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/e2/8b6983119d468b3f01f75ab377ab", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/72/c7/1b3960aeb864e2d69e7588c2fd70", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e1/a8/a51c079fd89b97f7012a1d5073cf", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fd/92/e3a182bde513b4ecd1c9cdda72e3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/12/cc/152f14e0b34dee25fe4fb6cbbe74", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d7/ae/b1d17450314143afac2411bc9c64" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f0/f4/0acbb407a70243e79ecd4f9c37a4", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/12/48/e5bd3c897ef27c733db9b0b97c73", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/37/b7/44fbb06655436c53351def23a7d2", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d8/bd/05c1f7b7991300ae8e339880b19a" } \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 96829c3e..0ed79f3d 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -20225,7 +20225,8 @@ assets-ios: $(ASSET_TARGETS_IOS) $(ASSET_TARGETS_COMMON) assets-android: $(ASSET_TARGETS_ANDROID) $(ASSET_TARGETS_COMMON) # Build all assets for all platforms. -assets: assets-cmake assets-win assets-mac assets-ios assets-android +assets: assets-cmake assets-win-Win32 assets-win-x64 assets-mac assets-ios \ + assets-android clean: @rm -rf build From 05f87d2d41bfda44af969b640e88de9ceeb61b6c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 13 Jun 2020 20:36:46 -0700 Subject: [PATCH 095/417] Even more windows fixes --- .efrocachemap | 24 ++++++++++++------------ assets/Makefile | 4 ++-- tools/snippets | 3 ++- tools/stage_assets | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 5477a01c..d0b4c525 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/f1/3b/224ab441922e2cd0f95a042eca63", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/01/1382cb73f9a4484a49ba603429fc", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/dc/dcbe26dc38ac257f792cf10f0460", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/16/a4f73103c2db98225fb3c7763ea7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/31/d7/a5fd6808a0f5031359e90d00f29b", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/dc/1b4b59fcf7e1b3a2fabfb6fa7762", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/e2/8b6983119d468b3f01f75ab377ab", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/72/c7/1b3960aeb864e2d69e7588c2fd70", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f0/f4/0acbb407a70243e79ecd4f9c37a4", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/12/48/e5bd3c897ef27c733db9b0b97c73", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/37/b7/44fbb06655436c53351def23a7d2", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d8/bd/05c1f7b7991300ae8e339880b19a" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ff/62/5125915d72879180babf3d26b2fc", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dd/0f/42f87cbaceb401bed5981f137d4a", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/99/58/5a2a52d0b9d3c0fc57b90246bdb2", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/86/07/e15c1708be88dc2069d16b654624", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/ba/33f8898f39a83ccf6e3965828bb3", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d7/07/cf5586ecebc8360c011fa7f268eb", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/87/4420eed6d8a61ba456bd958a22cb", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/00/97/dcb47fff319f0539fb65eb6d39c5", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/85/cc/001c4778eda9e1ee1ecea4c22bab", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f1/f4/35e9d455770501d48b89cd7d5a43", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e6/d0/b26b16a1e3abc54cf9d46c1d14bf", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/58/34/9577c9876162458e59f66e72c8e5" } \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 0ed79f3d..bdaacd03 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -20235,5 +20235,5 @@ clean: .PHONY: cmake win mac ios android audio clean-audio fonts clean-fonts \ data clean-data models clean-models \ clean-textures scripts clean-scripts \ - assets assets-cmake assets-win assets-mac assets-ios assets-android \ - asset_sources clean + assets assets-cmake assets-win-Win32 assets-win-x64 assets-mac \ + assets-ios assets-android asset_sources clean diff --git a/tools/snippets b/tools/snippets index 86484dae..95a8ada5 100755 --- a/tools/snippets +++ b/tools/snippets @@ -597,7 +597,8 @@ def lazy_increment_build() -> None: print(f'{Clr.SMAG}Source(s) changed; incrementing build...{Clr.RST}') # Just go ahead and bless; this will increment the build as needed. - subprocess.run(['make', 'bless'], check=True) + # subprocess.run(['make', 'bless'], check=True) + subprocess.run(['tools/version_utils', 'incrementbuild'], check=True) # We probably just changed code, so we need to re-calc the hash. codehash = get_files_hash(codefiles) diff --git a/tools/stage_assets b/tools/stage_assets index e528135c..8aed0567 100755 --- a/tools/stage_assets +++ b/tools/stage_assets @@ -271,7 +271,7 @@ def _sync_windows_extras(cfg: Config) -> None: # Now sync the top level individual files that we want. # (we could technically copy everything over but this keeps staging # dirs a bit tidier) - toplevelfiles: List[str] = [] + toplevelfiles: List[str] = ['python37.dll'] if cfg.win_type == 'win': toplevelfiles += [ From 823a12ac756da949708dc02f9e88d6bdfa6ac6ed Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 13 Jun 2020 21:01:09 -0700 Subject: [PATCH 096/417] 1.5.5 --- .idea/dictionaries/ericf.xml | 9 +++++++++ CHANGELOG.md | 4 ++++ tools/snippets | 12 +++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index c9101d02..e781fd39 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -327,6 +327,7 @@ clrhdr clrnames clrred + cmakeserver cmathmodule cmds cmembers @@ -1055,6 +1056,7 @@ libssl libvorbi libvorbis + libvorbisfile libxm libxmu libxz @@ -1207,6 +1209,7 @@ msbuild mshell msvccompiler + msvcp mtarget mtime mtrans @@ -1598,6 +1601,7 @@ realsies recache redist + redistributables relpath remainingchecks remoteapp @@ -1993,6 +1997,7 @@ topkillcount topkilledcount toplevel + toplevelfiles totaldudes totalpts totalwaves @@ -2100,6 +2105,7 @@ varname varsize vartype + vcruntime vcxproj venv verlines @@ -2148,14 +2154,17 @@ willeval wincfg wincount + winempty winnergroup winnergroups winplt winprj winref winscore + winserver winsound winstate + wintype wmsbe woooo workdir diff --git a/CHANGELOG.md b/CHANGELOG.md index c0737fb1..2696a3d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.5.5 (20069) +- Cleaned up Windows version packaging. +- More misc bug fixes. + ### 1.5.4 (20067) - Should now work properly with non-ascii paths on Windows (for real this time). - Note that Windows game data is now stored under 'Local' appdata instead of 'Roaming'; if you have an old install with data you want to preserve, you may want to move it over manually. diff --git a/tools/snippets b/tools/snippets index 95a8ada5..8e1fb344 100755 --- a/tools/snippets +++ b/tools/snippets @@ -583,8 +583,12 @@ def lazy_increment_build() -> None: import os import subprocess from efro.terminal import Clr + from efro.error import CleanError from efrotools import get_files_hash from efrotools.code import get_code_filenames + if sys.argv[2:] not in [[], ['--update-hash-only']]: + raise CleanError('Invalid arguments') + update_hash_only = '--update-hash-only' in sys.argv codefiles = get_code_filenames(PROJROOT) codehash = get_files_hash(codefiles) hashfilename = '.cache/lazy_increment_build' @@ -596,9 +600,11 @@ def lazy_increment_build() -> None: if codehash != lasthash: print(f'{Clr.SMAG}Source(s) changed; incrementing build...{Clr.RST}') - # Just go ahead and bless; this will increment the build as needed. - # subprocess.run(['make', 'bless'], check=True) - subprocess.run(['tools/version_utils', 'incrementbuild'], check=True) + if not update_hash_only: + # Just go ahead and bless; this will increment the build as needed. + # subprocess.run(['make', 'bless'], check=True) + subprocess.run(['tools/version_utils', 'incrementbuild'], + check=True) # We probably just changed code, so we need to re-calc the hash. codehash = get_files_hash(codefiles) From 9764e55f0a8699db1714256f037bf37230bdb0cb Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 16 Jun 2020 00:20:29 -0700 Subject: [PATCH 097/417] Lots of low level input cleanup for Android 1.5 --- .efrocachemap | 24 +++++++++---------- assets/src/ba_data/python/_ba.py | 2 +- .../python/bastd/ui/settings/testing.py | 24 +++++++++---------- config/toolconfigsrc/projectile | 1 - docs/ba_module.md | 2 +- tools/batools/build.py | 2 +- tools/snippets | 21 ---------------- 7 files changed, 27 insertions(+), 49 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index d0b4c525..ec6b11d7 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/ff/62/5125915d72879180babf3d26b2fc", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dd/0f/42f87cbaceb401bed5981f137d4a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/99/58/5a2a52d0b9d3c0fc57b90246bdb2", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/86/07/e15c1708be88dc2069d16b654624", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/ba/33f8898f39a83ccf6e3965828bb3", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d7/07/cf5586ecebc8360c011fa7f268eb", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/87/4420eed6d8a61ba456bd958a22cb", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/00/97/dcb47fff319f0539fb65eb6d39c5", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/85/cc/001c4778eda9e1ee1ecea4c22bab", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f1/f4/35e9d455770501d48b89cd7d5a43", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e6/d0/b26b16a1e3abc54cf9d46c1d14bf", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/58/34/9577c9876162458e59f66e72c8e5" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/89/4c/40cf1444b54cde1b8bf8596612ea", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/7b/ae898aca9e1000a7ceef18e7d90a", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/50/a8/139b0aab8e196efcdcabce873fb8", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/59/ab/fb77b5befd76e55b0ef287f09cc9", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/d9/f45a67d978cacfb1cf67d9f572b7", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9e/dc/496e106c69b04e6e287812fd513c", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/bc/b4e726affda0ccef4fbe18301f9d", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/03/42277cc689249139bbf713f100f9", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/78/189de5c70bcaa4a854b6075ec363", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/8d/7967bcd04e49a1b59905f1bd2a88", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/ff/949c3339724acb558b731eedb62d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/96/cd/d251d1699675f1741570fb7d2d93" } \ No newline at end of file diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index eba2eed8..afa2ece8 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -34,7 +34,7 @@ NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ # (hash we can use to see if this file is out of date) -# SOURCES_HASH=30991209163728546136111726610486266810 +# SOURCES_HASH=215440954657254583733032942455994403734 # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression diff --git a/assets/src/ba_data/python/bastd/ui/settings/testing.py b/assets/src/ba_data/python/bastd/ui/settings/testing.py index 3bdb2679..be3c17df 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/testing.py +++ b/assets/src/ba_data/python/bastd/ui/settings/testing.py @@ -106,7 +106,7 @@ class TestingWindow(ba.Window): entry_name = entry['name'] - # if we haven't yet, record the default value for this name so + # If we haven't yet, record the default value for this name so # we can reset if we want.. if entry_name not in ba.app.value_test_defaults: ba.app.value_test_defaults[entry_name] = ( @@ -132,14 +132,14 @@ class TestingWindow(ba.Window): if i == 0: ba.widget(edit=btn, up_widget=self._back_button) ba.widget(edit=btn, show_buffer_top=20, show_buffer_bottom=20) - entry['widget'] = ba.textwidget( - parent=self._subcontainer, - position=(h + 100, v), - size=(0, 0), - h_align='center', - v_align='center', - maxwidth=60, - text=str(round(_ba.value_test(entry_name), 4))) + entry['widget'] = ba.textwidget(parent=self._subcontainer, + position=(h + 100, v), + size=(0, 0), + h_align='center', + v_align='center', + maxwidth=60, + text='%.4g' % + _ba.value_test(entry_name)) btn = ba.buttonwidget(parent=self._subcontainer, position=(h + 140, v - 19), size=(40, 40), @@ -174,19 +174,19 @@ class TestingWindow(ba.Window): _ba.value_test(entry['name'], absolute=ba.app.value_test_defaults[entry['name']]) ba.textwidget(edit=entry['widget'], - text=str(round(_ba.value_test(entry['name']), 4))) + text='%.4g' % _ba.value_test(entry['name'])) def _on_minus_press(self, entry_name: str) -> None: entry = self._get_entry(entry_name) _ba.value_test(entry['name'], change=-entry['increment']) ba.textwidget(edit=entry['widget'], - text=str(round(_ba.value_test(entry['name']), 4))) + text='%.4g' % _ba.value_test(entry['name'])) def _on_plus_press(self, entry_name: str) -> None: entry = self._get_entry(entry_name) _ba.value_test(entry['name'], change=entry['increment']) ba.textwidget(edit=entry['widget'], - text=str(round(_ba.value_test(entry['name']), 4))) + text='%.4g' % _ba.value_test(entry['name'])) def _do_back(self) -> None: # pylint: disable=cyclic-import diff --git a/config/toolconfigsrc/projectile b/config/toolconfigsrc/projectile index 11766487..e7af40de 100644 --- a/config/toolconfigsrc/projectile +++ b/config/toolconfigsrc/projectile @@ -1,3 +1,2 @@ +/tools +/assets/src/ba_data/python -+/ballisticacore-android/BallisticaCore/src diff --git a/docs/ba_module.md b/docs/ba_module.md index d7a89752..c51a7a6f 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-13 for Ballistica version 1.5.4 build 20067

    +

    last updated on 2020-06-15 for Ballistica version 1.5.5 build 20069

    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!


    diff --git a/tools/batools/build.py b/tools/batools/build.py index 95d03e9a..0b88edde 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -399,7 +399,7 @@ def gen_fulltest_buildfile_apple() -> None: # (throw release build in the mix to hopefully catch opt-mode-only errors). lines.append('nice -n 18 make mac-appstore-release-build') lines.append('nice -n 18 make mac-new-build') - lines.append('nice -n 18 make mac-server-build') + lines.append('nice -n 18 make cmake-server-build') lines.append('nice -n 18 make cmake-build') if DO_SPARSE_TEST_BUILDS: extras = SPARSE_TEST_BUILDS[dayoffset % len(SPARSE_TEST_BUILDS)] diff --git a/tools/snippets b/tools/snippets index 8e1fb344..25bb7722 100755 --- a/tools/snippets +++ b/tools/snippets @@ -43,32 +43,11 @@ from efrotools.snippets import ( sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, makefile_target_list, spelling, spelling_all, pytest, echo, compile_python_files) -# from efrotools.snippets import compile_python_files as _orig_compile_py_files # pylint: enable=unused-import if TYPE_CHECKING: from typing import Optional -# def compile_python_files() -> None: -# """Override for compiling python files.""" -# from pathlib import Path -# import subprocess -# import os -# from efrotools import getlocalconfig - -# # Run the standard command -# _orig_compile_py_files() - -# # Optionally also blow away blessing status to keep it clear that -# # things need to be re-blessed. -# blesspath = Path(PROJROOT, 'tools/bless') -# if os.path.exists(blesspath) and getlocalconfig(PROJROOT).get( -# 'auto_clear_blessing', False): -# subprocess.run([blesspath, 'clear'], check=True, cwd=PROJROOT) - -# # Copy the original func's doc-string -# compile_python_files.__doc__ = _orig_compile_py_files.__doc__ - def archive_old_builds() -> None: """Stuff our old public builds into the 'old' dir. From 414afe598dbbcce6e57836e77890622c6d07bd50 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 16 Jun 2020 02:43:52 -0700 Subject: [PATCH 098/417] More internal android 1.5 event work --- .efrocachemap | 24 ++++++++++++------------ .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 22 ++++++++++------------ assets/src/ba_data/python/bastd/maps.py | 2 +- docs/ba_module.md | 10 +++++----- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index ec6b11d7..e0858e23 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/89/4c/40cf1444b54cde1b8bf8596612ea", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c8/7b/ae898aca9e1000a7ceef18e7d90a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/50/a8/139b0aab8e196efcdcabce873fb8", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/59/ab/fb77b5befd76e55b0ef287f09cc9", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/d9/f45a67d978cacfb1cf67d9f572b7", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9e/dc/496e106c69b04e6e287812fd513c", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/bc/b4e726affda0ccef4fbe18301f9d", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/03/42277cc689249139bbf713f100f9", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/78/189de5c70bcaa4a854b6075ec363", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/8d/7967bcd04e49a1b59905f1bd2a88", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/ff/949c3339724acb558b731eedb62d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/96/cd/d251d1699675f1741570fb7d2d93" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/6a/634ef384e18384fa78b7a2a624f8", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d6/1b/165df7c0c0c21761cba641640d4d", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e3/8b/b1770e7c2ade5a6f538260acae4d", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/c1/7ad792405a744d9f2fa4cf682d4b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a5/d5/d9ed741473501d1a1541d5c100df", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/10/e5/70bde6663088d44e126ec91cfaae", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6c/b4eb60746d994cddd19813faee85", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/17/31/dff0defb0cc64a80d5068ed97930", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/02/b0/83ec7dc92ec4e5b75a9d9a058cda", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/aa/1e/bfcf2f01ae72a897333a4e4137b5", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cc/ec/50508b196f190b4a4b137d4aaf9c", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/94/71/340f38cdbbcad105395733b9e556" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index e781fd39..fe1d1106 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1355,6 +1355,7 @@ outext outfilename outfilepath + outhashpath outname outpath ouya diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index afa2ece8..5d1584da 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -33,9 +33,6 @@ to make sure that it still works with all our tools NOTE: This file was autogenerated by gendummymodule; do not edit by hand. """ -# (hash we can use to see if this file is out of date) -# SOURCES_HASH=215440954657254583733032942455994403734 - # I'm sorry Pylint. I know this file saddens you. Be strong. # pylint: disable=useless-suppression # pylint: disable=unnecessary-pass @@ -149,11 +146,11 @@ class Context: Sets to the UI context. UI functions as well as loading of media to be used in said functions must happen in the UI context. - a ba.Activity instance: + A ba.Activity instance: Gives the context for the provided ba.Activity. Most all code run during a game happens in an Activity's Context. - a ba.Session instance: + A ba.Session instance: Gives the context for the provided ba.Session. Generally a user should not need to run anything here. @@ -210,13 +207,13 @@ class ContextCall: shutdown, whereas ba.WeakCall simply looks at whether the target object still exists. - # example A: code like this can inadvertently prevent our activity + # 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 + # 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. @@ -566,11 +563,12 @@ class Node: Node reference (sometimes used as attr values/etc). """ - # Adding attrs as needed. - # FIXME: These should be instance attrs. - # NOTE: Am just adding all possible node attrs here. - # It would be nicer to make a distinct class for each - # node type at some point so we get better type checks. + # Note attributes: + # NOTE: I'm just adding *all* possible node attrs here + # now now since we have a single ba.Node type; in the + # future I hope to create proper individual classes + # corresponding to different node types with correct + # attributes per node-type. color: Sequence[float] = (0.0, 0.0, 0.0) size: Sequence[float] = (0.0, 0.0, 0.0) position: Sequence[float] = (0.0, 0.0, 0.0) diff --git a/assets/src/ba_data/python/bastd/maps.py b/assets/src/ba_data/python/bastd/maps.py index 29de16eb..15b9290b 100644 --- a/assets/src/ba_data/python/bastd/maps.py +++ b/assets/src/ba_data/python/bastd/maps.py @@ -735,7 +735,7 @@ class ThePad(ba.Map): class DoomShroom(ba.Map): - """A giant mushroom. Of doom.""" + """A giant mushroom. Of doom!""" from bastd.mapdata import doom_shroom as defs diff --git a/docs/ba_module.md b/docs/ba_module.md index c51a7a6f..5b73dcce 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-15 for Ballistica version 1.5.5 build 20069

    +

    last updated on 2020-06-16 for Ballistica version 1.5.5 build 20070

    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!


    @@ -1514,11 +1514,11 @@ is passed, which can be one of the following strings/objects:

    Sets to the UI context. UI functions as well as loading of media to be used in said functions must happen in the UI context.

    -

    a ba.Activity instance: +

    A ba.Activity instance: Gives the context for the provided ba.Activity. Most all code run during a game happens in an Activity's Context.

    -

    a ba.Session instance: +

    A ba.Session instance: Gives the context for the provided ba.Session. Generally a user should not need to run anything here.

    @@ -1565,13 +1565,13 @@ ContextCall has the added bonus that it will not run during context shutdown, whereas ba.WeakCall simply looks at whether the target object still exists.

    -
    # example A: code like this can inadvertently prevent our activity
    +
    # 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
    +
    # 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.
    
    From 0fdc5f1fc438d854fb610cb1034bc9f1e7d73d0b Mon Sep 17 00:00:00 2001
    From: Eric Froemling 
    Date: Tue, 16 Jun 2020 20:29:03 -0700
    Subject: [PATCH 099/417] Exception handling cleanup
    
    ---
     .efrocachemap                                 | 24 +++++-----
     .idea/dictionaries/ericf.xml                  |  2 +
     assets/src/ba_data/python/ba/_dependency.py   |  4 +-
     assets/src/ba_data/python/ba/_general.py      |  8 ++--
     assets/src/ba_data/python/ba/_lang.py         |  7 +--
     assets/src/ba_data/python/ba/_map.py          |  4 +-
     .../python/bastd/activity/coopscore.py        | 29 ++++--------
     .../ba_data/python/bastd/actor/powerupbox.py  | 22 +++++----
     .../ba_data/python/bastd/actor/scoreboard.py  |  6 +--
     .../src/ba_data/python/bastd/actor/spazbot.py | 21 +++------
     .../python/bastd/game/easteregghunt.py        |  5 ++-
     .../src/ba_data/python/bastd/game/football.py |  2 +-
     .../src/ba_data/python/bastd/game/keepaway.py |  2 +-
     .../python/bastd/game/kingofthehill.py        |  8 ++--
     .../ba_data/python/bastd/game/onslaught.py    | 30 ++++++-------
     assets/src/ba_data/python/bastd/game/race.py  |  8 ++--
     .../ba_data/python/bastd/game/runaround.py    |  2 +-
     .../ba_data/python/bastd/game/thelaststand.py |  2 +-
     assets/src/ba_data/python/bastd/tutorial.py   |  6 +--
     .../python/bastd/ui/account/settings.py       | 13 +++---
     .../ba_data/python/bastd/ui/account/viewer.py |  6 +--
     .../ba_data/python/bastd/ui/coop/browser.py   | 21 ++++-----
     .../ba_data/python/bastd/ui/creditslist.py    |  2 +-
     .../ba_data/python/bastd/ui/fileselector.py   |  2 +-
     assets/src/ba_data/python/bastd/ui/gather.py  | 14 +++---
     assets/src/ba_data/python/bastd/ui/kiosk.py   |  5 +--
     .../python/bastd/ui/league/rankbutton.py      | 17 ++++---
     .../python/bastd/ui/league/rankwindow.py      |  4 +-
     .../src/ba_data/python/bastd/ui/mainmenu.py   | 13 +++---
     assets/src/ba_data/python/bastd/ui/party.py   |  2 +-
     .../src/ba_data/python/bastd/ui/partyqueue.py |  2 +-
     assets/src/ba_data/python/bastd/ui/play.py    |  9 ++--
     .../python/bastd/ui/playlist/browser.py       |  2 +-
     .../bastd/ui/playlist/customizebrowser.py     | 16 +++----
     .../python/bastd/ui/playlist/editgame.py      |  4 +-
     .../python/bastd/ui/playlist/mapselect.py     |  3 +-
     .../ba_data/python/bastd/ui/playoptions.py    | 13 ++----
     .../python/bastd/ui/profile/browser.py        | 14 ++----
     .../python/bastd/ui/settings/advanced.py      | 13 +++---
     .../python/bastd/ui/settings/allsettings.py   | 11 ++---
     .../ba_data/python/bastd/ui/settings/audio.py | 11 ++---
     .../python/bastd/ui/settings/controls.py      |  5 +--
     .../python/bastd/ui/settings/gamepad.py       |  2 +-
     .../bastd/ui/settings/gamepadadvanced.py      |  5 +--
     .../python/bastd/ui/soundtrack/browser.py     | 20 +++------
     .../python/bastd/ui/soundtrack/edit.py        |  5 +--
     .../ba_data/python/bastd/ui/specialoffer.py   |  3 +-
     .../ba_data/python/bastd/ui/store/browser.py  | 16 +++----
     .../ba_data/python/bastd/ui/store/button.py   |  2 +-
     .../python/bastd/ui/tournamententry.py        |  8 ++--
     assets/src/ba_data/python/bastd/ui/watch.py   | 45 +++++++++----------
     docs/ba_module.md                             |  4 +-
     tools/bacloud                                 |  4 +-
     tools/efro/entity/_value.py                   |  3 +-
     tools/efro/terminal.py                        |  2 +-
     55 files changed, 214 insertions(+), 299 deletions(-)
    
    diff --git a/.efrocachemap b/.efrocachemap
    index e0858e23..571dca2e 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/59/6a/634ef384e18384fa78b7a2a624f8",
    -  "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d6/1b/165df7c0c0c21761cba641640d4d",
    -  "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e3/8b/b1770e7c2ade5a6f538260acae4d",
    -  "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/c1/7ad792405a744d9f2fa4cf682d4b",
    -  "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a5/d5/d9ed741473501d1a1541d5c100df",
    -  "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/10/e5/70bde6663088d44e126ec91cfaae",
    -  "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6c/b4eb60746d994cddd19813faee85",
    -  "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/17/31/dff0defb0cc64a80d5068ed97930",
    -  "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/02/b0/83ec7dc92ec4e5b75a9d9a058cda",
    -  "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/aa/1e/bfcf2f01ae72a897333a4e4137b5",
    -  "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cc/ec/50508b196f190b4a4b137d4aaf9c",
    -  "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/94/71/340f38cdbbcad105395733b9e556"
    +  "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/29/9c/24a918c046b06f010d9948458a09",
    +  "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2e/1c/2285cc92d83ce3a32b26c020cb71",
    +  "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/b6/9410d8cf8be5aaf2ffad07964950",
    +  "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/48/c4/2bdd6802858b92c348df702c9dcd",
    +  "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/ca/0a1426dabc53a9f90a6beb011423",
    +  "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/ef/4186b927c2675c3e4dfa19ba180d",
    +  "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/29/59/60175945534d87709dfc29d1b180",
    +  "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5c/b8/16b868c1bbd8b1be2ebaf4da4d31",
    +  "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/6c/33b6b194062212beeae3043515a3",
    +  "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4b/24/c54be077112185f6a3d2c67641ea",
    +  "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ee/6e/a9d59e81b549b992673d20f84f11",
    +  "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5b/73/97159eb1d7dfb4018c5a1241f164"
     }
    \ No newline at end of file
    diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
    index fe1d1106..74ab5b89 100644
    --- a/.idea/dictionaries/ericf.xml
    +++ b/.idea/dictionaries/ericf.xml
    @@ -572,6 +572,7 @@
           ensurepip
           entitylist
           entrynew
    +      entrystorename
           entrytype
           entrytypeselect
           enumtype
    @@ -1306,6 +1307,7 @@
           ntriple
           nturl
           numedit
    +      numsound
           numstr
           nvcompress
           nvidia
    diff --git a/assets/src/ba_data/python/ba/_dependency.py b/assets/src/ba_data/python/ba/_dependency.py
    index 8ae536dd..b8817ad1 100644
    --- a/assets/src/ba_data/python/ba/_dependency.py
    +++ b/assets/src/ba_data/python/ba/_dependency.py
    @@ -422,8 +422,8 @@ def test_depset() -> None:
                         if dep.cls is AssetPackage:
                             print('MISSING ASSET PACKAGE', dep.config)
                         else:
    -                        raise Exception('unknown dependency error for ' +
    -                                        str(dep.cls))
    +                        raise RuntimeError(
    +                            f'Unknown dependency error for {dep.cls}') from exc
                 except Exception as exc:
                     print('DependencySet resolve failed with exc type:', type(exc))
                 if depset.resolved:
    diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py
    index d1ebc5c5..7b4b87c9 100644
    --- a/assets/src/ba_data/python/ba/_general.py
    +++ b/assets/src/ba_data/python/ba/_general.py
    @@ -337,7 +337,7 @@ def _verify_object_death(wref: ReferenceType) -> None:
             i += 1
     
     
    -def storagename(basename: str) -> str:
    +def storagename(suffix: str = None) -> str:
         """Generate a (hopefully) unique name for storing things in public places.
     
         Category: General Utility Functions
    @@ -371,7 +371,9 @@ def storagename(basename: str) -> str:
         qualname = fback.f_locals.get('__qualname__')
         if qualname is not None:
             assert isinstance(qualname, str)
    -        fullpath = f'_{modulepath}_{qualname.lower()}_{basename}'
    +        fullpath = f'_{modulepath}_{qualname.lower()}'
         else:
    -        fullpath = f'_{modulepath}_{basename}'
    +        fullpath = f'_{modulepath}'
    +    if suffix is not None:
    +        fullpath = f'{fullpath}_{suffix}'
         return fullpath.replace('.', '_')
    diff --git a/assets/src/ba_data/python/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py
    index 608f7579..fcef0708 100644
    --- a/assets/src/ba_data/python/ba/_lang.py
    +++ b/assets/src/ba_data/python/ba/_lang.py
    @@ -296,8 +296,8 @@ def _add_to_attr_dict(dst: AttrDict, src: Dict) -> None:
                 except Exception:
                     dst_dict = dst[key] = AttrDict()
                 if not isinstance(dst_dict, AttrDict):
    -                raise Exception("language key '" + key +
    -                                "' is defined both as a dict and value")
    +                raise RuntimeError("language key '" + key +
    +                                   "' is defined both as a dict and value")
                 _add_to_attr_dict(dst_dict, value)
             else:
                 if not isinstance(value, (float, int, bool, str, str, type(None))):
    @@ -404,7 +404,8 @@ def get_resource(resource: str,
             from ba import _error
             if fallback_value is not None:
                 return fallback_value
    -        raise _error.NotFoundError("resource not found: '" + resource + "'")
    +        raise _error.NotFoundError(
    +            f"Resource not found: '{resource}'") from None
     
     
     def translate(category: str,
    diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py
    index 005c236f..0dfbbf65 100644
    --- a/assets/src/ba_data/python/ba/_map.py
    +++ b/assets/src/ba_data/python/ba/_map.py
    @@ -143,9 +143,9 @@ def get_map_class(name: str) -> Type[ba.Map]:
         name = get_filtered_map_name(name)
         try:
             return _ba.app.maps[name]
    -    except Exception:
    +    except KeyError:
             from ba import _error
    -        raise _error.NotFoundError("Map not found: '" + name + "'")
    +        raise _error.NotFoundError(f"Map not found: '{name}'") from None
     
     
     class Map(Actor):
    diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py
    index 9f05dd18..2aa482b7 100644
    --- a/assets/src/ba_data/python/bastd/activity/coopscore.py
    +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py
    @@ -322,7 +322,6 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
         def show_ui(self) -> None:
             """Show the UI for restarting, playing the next Level, etc."""
             # pylint: disable=too-many-locals
    -        # pylint: disable=too-many-statements
             from bastd.ui.store.button import StoreButton
             from bastd.ui.league.rankbutton import LeagueRankButton
     
    @@ -330,15 +329,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
     
             # If there's no players left in the game, lets not show the UI
             # (that would allow restarting the game with zero players, etc).
    -
    -        # Hmmm shouldn't need this try/except here i don't think.
    -        try:
    -            players = self.players
    -        except Exception as exc:
    -            print(('EXC bs_coop_game show_ui cant get '
    -                   'self.players; shouldn\'t happen:'), exc)
    -            players = []
    -        if not players:
    +        if not self.players:
                 return
     
             rootc = self._root_ui = ba.containerwidget(size=(0, 0),
    @@ -513,7 +504,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
                 self._store_button_instance.set_position((pos_x + 100, pos_y))
     
         def on_begin(self) -> None:
    -        # FIXME: clean this up
    +        # FIXME: Clean this up.
             # pylint: disable=too-many-statements
             # pylint: disable=too-many-branches
             # pylint: disable=too-many-locals
    @@ -661,12 +652,9 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
             # Add us to high scores, filter, and store.
             our_high_scores_all = self._campaign.getlevel(
                 self._level_name).get_high_scores()
    -        try:
    -            our_high_scores = our_high_scores_all[str(len(self._playerinfos)) +
    -                                                  ' Player']
    -        except Exception:
    -            our_high_scores = our_high_scores_all[str(len(self._playerinfos)) +
    -                                                  ' Player'] = []
    +
    +        our_high_scores = our_high_scores_all.setdefault(
    +            str(len(self._playerinfos)) + ' Player', [])
     
             if self._score is not None:
                 our_score: Optional[list] = [
    @@ -685,8 +673,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
                 our_high_scores.sort(reverse=self._score_order == 'increasing',
                                      key=lambda x: x[0])
             except Exception:
    -            ba.print_exception('Error sorting scores')
    -            print('our_high_scores:', our_high_scores)
    +            ba.print_exception('Error sorting scores.')
    +            print(f'our_high_scores: {our_high_scores}')
     
             del our_high_scores[10:]
     
    @@ -809,6 +797,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
                         name_str = ', '.join(
                             [p['name'] for p in display_scores[i][1]['players']])
                     except Exception:
    +                    ba.print_exception('Error calcing name_str')
                         name_str = '-'
                     if display_scores[i] == our_score and not showed_ours:
                         flash = True
    @@ -1256,7 +1245,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]):
                                  transition_delay=2.0).autoretain()
                             vval -= 35
             except Exception:
    -            ba.print_exception('error showing prize ranges')
    +            ba.print_exception('Error showing prize ranges.')
     
             if self._do_new_rating:
                 if error:
    diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py
    index 0a4053e1..4717bdc3 100644
    --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py
    +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py
    @@ -98,6 +98,8 @@ class PowerupBoxFactory:
               that has this ba.Material applied.
         """
     
    +    _STORENAME = ba.storagename()
    +
         def __init__(self) -> None:
             """Instantiate a PowerupBoxFactory.
     
    @@ -187,21 +189,17 @@ class PowerupBoxFactory:
             self._lastpoweruptype = ptype
             return ptype
     
    -    @staticmethod
    -    def get() -> PowerupBoxFactory:
    +    @classmethod
    +    def get(cls) -> PowerupBoxFactory:
             """Return a shared ba.PowerupBoxFactory object, creating if needed."""
             activity = ba.getactivity()
             if activity is None:
    -            raise RuntimeError('no current activity')
    -        try:
    -            # FIXME: et better way to store stuff with activity
    -            # pylint: disable=protected-access
    -            # noinspection PyProtectedMember
    -            return activity._shared_powerup_factory  # type: ignore
    -        except Exception:
    -            factory = activity._shared_powerup_factory = (  # type: ignore
    -                PowerupBoxFactory())
    -            return factory
    +            raise ba.ContextError('No current activity.')
    +        factory = activity.customdata.get(cls._STORENAME)
    +        if factory is None:
    +            factory = activity.customdata[cls._STORENAME] = PowerupBoxFactory()
    +        assert isinstance(factory, PowerupBoxFactory)
    +        return factory
     
     
     class PowerupBox(ba.Actor):
    diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py
    index 448cd89a..31be59a7 100644
    --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py
    +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py
    @@ -343,7 +343,7 @@ class Scoreboard:
         category: Gameplay Classes
         """
     
    -    _STORENAME = ba.storagename('entry')
    +    _ENTRYSTORENAME = ba.storagename('entry')
     
         def __init__(self, label: ba.Lstr = None, score_split: float = 0.7):
             """Instantiate a scoreboard.
    @@ -384,8 +384,8 @@ class Scoreboard:
     
                 # Create a proxy in the team which will kill
                 # our entry when it dies (for convenience)
    -            assert self._STORENAME not in team.customdata
    -            team.customdata[self._STORENAME] = _EntryProxy(self, team)
    +            assert self._ENTRYSTORENAME not in team.customdata
    +            team.customdata[self._ENTRYSTORENAME] = _EntryProxy(self, team)
     
             # Now set the entry.
             self._entries[team.id].set_value(score=score,
    diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py
    index bd7ebc23..5a507563 100644
    --- a/assets/src/ba_data/python/bastd/actor/spazbot.py
    +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py
    @@ -235,11 +235,7 @@ class SpazBot(Spaz):
             # towards the flag and try to pick it up.
             if self.target_flag:
                 if self.node.hold_node:
    -                try:
    -                    holding_flag = (
    -                        self.node.hold_node.getnodetype() == 'flag')
    -                except Exception:
    -                    holding_flag = False
    +                holding_flag = (self.node.hold_node.getnodetype() == 'flag')
                 else:
                     holding_flag = False
     
    @@ -280,11 +276,8 @@ class SpazBot(Spaz):
     
             # Not a flag-bearer. If we're holding anything but a bomb, drop it.
             if self.node.hold_node:
    -            try:
    -                holding_bomb = (self.node.hold_node.getnodetype()
    -                                in ['bomb', 'prop'])
    -            except Exception:
    -                holding_bomb = False
    +            holding_bomb = (self.node.hold_node.getnodetype()
    +                            in ['bomb', 'prop'])
                 if not holding_bomb:
                     self.node.pickup_pressed = True
                     self.node.pickup_pressed = False
    @@ -532,8 +525,8 @@ class SpazBot(Spaz):
                         picked_up_by = msg.node.source_player
                     else:
                         picked_up_by = None
    -            except Exception as exc:
    -                print('EXC on SpazBot DroppedMessage:', exc)
    +            except Exception:
    +                ba.print_exception('Error on SpazBot DroppedMessage.')
                     picked_up_by = None
     
                 if picked_up_by:
    @@ -969,7 +962,7 @@ class SpazBotSet:
                 ])
             except Exception:
                 bot_list = []
    -            ba.print_exception('error updating bot list: ' +
    +            ba.print_exception('Error updating bot list: ' +
                                    str(self._bot_lists[self._bot_update_list]))
             self._bot_update_list = (self._bot_update_list +
                                      1) % self._bot_list_count
    @@ -988,7 +981,7 @@ class SpazBotSet:
                         player_pts.append((ba.Vec3(player.actor.node.position),
                                            ba.Vec3(player.actor.node.velocity)))
                 except Exception:
    -                ba.print_exception('error on bot-set _update')
    +                ba.print_exception('Error on bot-set _update.')
     
             for bot in bot_list:
                 bot.set_player_points(player_pts)
    diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py
    index aa0c99ea..13fe9177 100644
    --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py
    +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py
    @@ -139,12 +139,15 @@ class EasterEggHuntGame(ba.TeamGameActivity[Player, Team]):
             if self.has_ended():
                 return
             collision = ba.getcollision()
    +
    +        # Be defensive here; we could be hitting the corpse of a player
    +        # who just left/etc.
             try:
                 egg = collision.sourcenode.getdelegate(Egg, True)
                 player = collision.opposingnode.getdelegate(PlayerSpaz,
                                                             True).getplayer(
                                                                 Player, True)
    -        except Exception:
    +        except ba.NotFoundError:
                 return
     
             player.team.score += 1
    diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py
    index c6b12473..ac6d4925 100644
    --- a/assets/src/ba_data/python/bastd/game/football.py
    +++ b/assets/src/ba_data/python/bastd/game/football.py
    @@ -653,7 +653,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]):
                 assert self._flag is not None
                 self._flag.handlemessage(ba.DieMessage())
             except Exception:
    -            ba.print_exception('error in _kill_flag')
    +            ba.print_exception('Error in _kill_flag.')
     
         def _handle_score(self) -> None:
             """ a point has been scored """
    diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py
    index a15de541..5faaf19a 100644
    --- a/assets/src/ba_data/python/bastd/game/keepaway.py
    +++ b/assets/src/ba_data/python/bastd/game/keepaway.py
    @@ -208,7 +208,7 @@ class KeepAwayGame(ba.TeamGameActivity[Player, Team]):
                         holdingflag = (
                             player.actor.node.hold_node.getnodetype() == 'flag')
                 except Exception:
    -                ba.print_exception('exception checking hold flag')
    +                ba.print_exception('Error checking hold flag.')
                 if holdingflag:
                     self._holding_players.append(player)
                     player.team.holdingflag = True
    diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py
    index 079a1f73..1e8b3610 100644
    --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py
    +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py
    @@ -216,11 +216,9 @@ class KingOfTheHillGame(ba.TeamGameActivity[Player, Team]):
                     self._flag.set_score_text(str(scoring_team.time_remaining))
     
                 # Announce numbers we have sounds for.
    -            try:
    -                ba.playsound(
    -                    self._countdownsounds[scoring_team.time_remaining])
    -            except Exception:
    -                pass
    +            numsound = self._countdownsounds.get(scoring_team.time_remaining)
    +            if numsound is not None:
    +                ba.playsound(numsound)
     
                 # winner
                 if scoring_team.time_remaining <= 0:
    diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py
    index c7b1971a..97718328 100644
    --- a/assets/src/ba_data/python/bastd/game/onslaught.py
    +++ b/assets/src/ba_data/python/bastd/game/onslaught.py
    @@ -1225,25 +1225,21 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]):
                 if msg.killerplayer is not None:
                     self._handle_kill_achievements(msg)
                     target: Optional[Sequence[float]]
    -                try:
    -                    assert msg.spazbot.node
    +                if msg.spazbot.node:
                         target = msg.spazbot.node.position
    -                except Exception:
    -                    ba.print_exception()
    +                else:
                         target = None
    -                try:
    -                    killerplayer = msg.killerplayer
    -                    self.stats.player_scored(killerplayer,
    -                                             pts,
    -                                             target=target,
    -                                             kill=True,
    -                                             screenmessage=False,
    -                                             importance=importance)
    -                    ba.playsound(self._dingsound
    -                                 if importance == 1 else self._dingsoundhigh,
    -                                 volume=0.6)
    -                except Exception:
    -                    pass
    +
    +                killerplayer = msg.killerplayer
    +                self.stats.player_scored(killerplayer,
    +                                         pts,
    +                                         target=target,
    +                                         kill=True,
    +                                         screenmessage=False,
    +                                         importance=importance)
    +                ba.playsound(self._dingsound
    +                             if importance == 1 else self._dingsoundhigh,
    +                             volume=0.6)
     
                 # Normally we pull scores from the score-set, but if there's
                 # no player lets be explicit.
    diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py
    index adead4d7..f65626bf 100644
    --- a/assets/src/ba_data/python/bastd/game/race.py
    +++ b/assets/src/ba_data/python/bastd/game/race.py
    @@ -361,8 +361,8 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
                                     2.2: 0
                                 })
                                 ba.timer(2.3, mathnode.delete)
    -                        except Exception as exc:
    -                            print('Exception printing lap:', exc)
    +                        except Exception:
    +                            ba.print_exception('Error printing lap.')
     
         def on_team_join(self, team: Team) -> None:
             self._update_scoreboard()
    @@ -392,7 +392,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
                         if otherplayer.actor is not None:
                             otherplayer.actor.handlemessage(ba.DieMessage())
                     except Exception:
    -                    ba.print_exception('Error sending diemessages')
    +                    ba.print_exception('Error sending DieMessage.')
     
             # Defer so team/player lists will be updated.
             ba.pushcall(self._check_end_game)
    @@ -520,7 +520,7 @@ class RaceGame(ba.TeamGameActivity[Player, Team]):
                         assert isinstance(player.actor, PlayerSpaz)
                         player.actor.connect_controls_to_player()
                     except Exception:
    -                    ba.print_exception('Error in race player connects')
    +                    ba.print_exception('Error in race player connects.')
             assert self._timer is not None
             self._timer.start()
     
    diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py
    index 34d6139d..0cecb473 100644
    --- a/assets/src/ba_data/python/bastd/game/runaround.py
    +++ b/assets/src/ba_data/python/bastd/game/runaround.py
    @@ -1158,7 +1158,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]):
                                          self._dingsoundhigh,
                                          volume=0.6)
                     except Exception:
    -                    ba.print_exception('Error on SpazBotDiedMessage')
    +                    ba.print_exception('Error on SpazBotDiedMessage.')
     
                 # Normally we pull scores from the score-set, but if there's no
                 # player lets be explicit.
    diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py
    index 047c8a29..a0cf3c1e 100644
    --- a/assets/src/ba_data/python/bastd/game/thelaststand.py
    +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py
    @@ -216,7 +216,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]):
                         assert player.actor.node
                         playerpts.append(player.actor.node.position)
                 except Exception:
    -                ba.print_exception('Error updating bots')
    +                ba.print_exception('Error updating bots.')
             for i in range(3):
                 for playerpt in playerpts:
                     dists[i] += abs(playerpt[0] - botspawnpts[i][0])
    diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py
    index 9f66f8e4..bdd10671 100644
    --- a/assets/src/ba_data/python/bastd/tutorial.py
    +++ b/assets/src/ba_data/python/bastd/tutorial.py
    @@ -2305,8 +2305,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
                 ]
     
             except Exception:
    -            import traceback
    -            traceback.print_exc()
    +            ba.print_exception()
     
             # If we read some, exec them.
             if self._entries:
    @@ -2324,8 +2323,7 @@ class TutorialActivity(ba.Activity[Player, Team]):
                     result = entry.run(self)
                 except Exception:
                     result = None
    -                import traceback
    -                traceback.print_exc()
    +                ba.print_exception()
     
                 # If the entry returns an int value, set a timer;
                 # otherwise just keep going.
    diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py
    index 4ece4879..db786b1b 100644
    --- a/assets/src/ba_data/python/bastd/ui/account/settings.py
    +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py
    @@ -984,7 +984,7 @@ class AccountSettingsWindow(ba.Window):
                                        str(int(progress * 100.0)) + '%')])
             except Exception:
                 p_str = '?'
    -            ba.print_exception('error calculating co-op campaign progress')
    +            ba.print_exception('Error calculating co-op campaign progress.')
             ba.textwidget(edit=self._campaign_progress_text, text=p_str)
     
         def _refresh_tickets_text(self) -> None:
    @@ -1081,7 +1081,7 @@ class AccountSettingsWindow(ba.Window):
                 campaign = getcampaign('Challenges')
                 campaign.reset()  # also writes the config..
             except Exception:
    -            ba.print_exception('exception resetting co-op campaign progress')
    +            ba.print_exception('Error resetting co-op campaign progress.')
     
             ba.playsound(ba.getsound('shieldDown'))
             self._refresh()
    @@ -1108,14 +1108,11 @@ class AccountSettingsWindow(ba.Window):
                     raise ValueError('unrecognized selection')
                 ba.app.window_states[self.__class__.__name__] = sel_name
             except Exception:
    -            ba.print_exception('exception saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[self.__class__.__name__]
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__)
                 if sel_name == 'Back':
                     sel = self._back_button
                 elif sel_name == 'Scroll':
    @@ -1124,4 +1121,4 @@ class AccountSettingsWindow(ba.Window):
                     sel = self._back_button
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
    diff --git a/assets/src/ba_data/python/bastd/ui/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py
    index 5aaa952c..7bc137f9 100644
    --- a/assets/src/ba_data/python/bastd/ui/account/viewer.py
    +++ b/assets/src/ba_data/python/bastd/ui/account/viewer.py
    @@ -208,7 +208,7 @@ class AccountViewerWindow(popup.PopupWindow):
                         if trophystr == '':
                             trophystr = '-'
                     except Exception:
    -                    ba.print_exception('Error displaying trophies')
    +                    ba.print_exception('Error displaying trophies.')
                     account_name_spacing = 15
                     tscale = 0.65
                     ts_height = _ba.get_string_height(trophystr,
    @@ -255,7 +255,7 @@ class AccountViewerWindow(popup.PopupWindow):
                                         tint2_color=tint2_color)
                                     v -= 95
                         except Exception:
    -                        ba.print_exception('Error displaying character')
    +                        ba.print_exception('Error displaying character.')
                         ba.textwidget(
                             parent=self._subcontainer,
                             size=(0, 0),
    @@ -474,7 +474,7 @@ class AccountViewerWindow(popup.PopupWindow):
                                   text=trophystr)
     
                 except Exception:
    -                ba.print_exception('Error displaying account info')
    +                ba.print_exception('Error displaying account info.')
     
         def _on_cancel_press(self) -> None:
             self._transition_out()
    diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py
    index cec83705..eb96bf30 100644
    --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py
    +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py
    @@ -83,10 +83,8 @@ class CoopBrowserWindow(ba.Window):
     
             # Try to recreate the same number of buttons we had last time so our
             # re-selection code works.
    -        try:
    -            self._tournament_button_count = app.config['Tournament Rows']
    -        except Exception:
    -            self._tournament_button_count = 0
    +        self._tournament_button_count = app.config.get('Tournament Rows', 0)
    +        assert isinstance(self._tournament_button_count, int)
     
             self._easy_button: Optional[ba.Widget] = None
             self._hard_button: Optional[ba.Widget] = None
    @@ -345,7 +343,7 @@ class CoopBrowserWindow(ba.Window):
                 ba.imagewidget(edit=self._hard_button_lock_image,
                                opacity=0.0 if have_pro_options() else 1.0)
             except Exception:
    -            ba.print_exception('error updating campaign lock')
    +            ba.print_exception('Error updating campaign lock.')
     
         def _update_for_data(self, data: Optional[List[Dict[str, Any]]]) -> None:
             # pylint: disable=too-many-statements
    @@ -1006,7 +1004,7 @@ class CoopBrowserWindow(ba.Window):
                         up_widget=tournament_h_scroll if self._tournament_buttons
                         else self._tournament_info_button)
                 except Exception:
    -                ba.print_exception('Error wiring up custom buttons')
    +                ba.print_exception('Error wiring up custom buttons.')
     
             if self._back_button is not None:
                 ba.buttonwidget(edit=self._back_button,
    @@ -1531,11 +1529,8 @@ class CoopBrowserWindow(ba.Window):
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[
    -                    self.__class__.__name__]['sel_name']
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__,
    +                                                {}).get('sel_name')
                 if sel_name == 'Back':
                     sel = self._back_button
                 elif sel_name == 'Scroll':
    @@ -1548,7 +1543,7 @@ class CoopBrowserWindow(ba.Window):
                     sel = self._scrollwidget
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
     
         def _save_state(self) -> None:
             cfg = ba.app.config
    @@ -1568,7 +1563,7 @@ class CoopBrowserWindow(ba.Window):
                     'sel_name': sel_name
                 }
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
             cfg['Selected Coop Row'] = self._selected_row
             cfg['Selected Coop Custom Level'] = self._selected_custom_level
    diff --git a/assets/src/ba_data/python/bastd/ui/creditslist.py b/assets/src/ba_data/python/bastd/ui/creditslist.py
    index a69aa613..cb5ad694 100644
    --- a/assets/src/ba_data/python/bastd/ui/creditslist.py
    +++ b/assets/src/ba_data/python/bastd/ui/creditslist.py
    @@ -173,7 +173,7 @@ class CreditsListWindow(ba.Window):
                     translation_contributors = (json.loads(
                         infile.read())['translation_contributors'])
             except Exception:
    -            ba.print_exception('error reading translation contributors')
    +            ba.print_exception('Error reading translation contributors.')
                 translation_contributors = []
     
             translation_names = _format_names(translation_contributors, 60)
    diff --git a/assets/src/ba_data/python/bastd/ui/fileselector.py b/assets/src/ba_data/python/bastd/ui/fileselector.py
    index 27c34818..d397fb33 100644
    --- a/assets/src/ba_data/python/bastd/ui/fileselector.py
    +++ b/assets/src/ba_data/python/bastd/ui/fileselector.py
    @@ -181,7 +181,7 @@ class FileSelectorWindow(ba.Window):
                                test_path))
             except Exception:
                 ba.print_exception(
    -                'error on FileSelectorWindow._on_entry_activated')
    +                'Error in FileSelectorWindow._on_entry_activated().')
     
             if new_path is not None:
                 self._set_path(new_path)
    diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py
    index f2eba248..fecf8f6e 100644
    --- a/assets/src/ba_data/python/bastd/ui/gather.py
    +++ b/assets/src/ba_data/python/bastd/ui/gather.py
    @@ -828,14 +828,14 @@ class GatherWindow(ba.Window):
                             self._call = call
     
                         def run(self) -> None:
    +                        result: Optional[str]
                             try:
                                 import socket
    -                            addr2 = socket.gethostbyname(self._name)
    -                            ba.pushcall(ba.Call(self._call, addr2),
    -                                        from_other_thread=True)
    +                            result = socket.gethostbyname(self._name)
                             except Exception:
    -                            ba.pushcall(ba.Call(self._call, None),
    -                                        from_other_thread=True)
    +                            result = None
    +                        ba.pushcall(ba.Call(self._call, result),
    +                                    from_other_thread=True)
     
                     def do_it_2(addr2: Optional[str]) -> None:
                         if addr2 is None:
    @@ -1969,7 +1969,7 @@ class GatherWindow(ba.Window):
                     'internet_tab': self._internet_tab
                 }
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    @@ -1990,7 +1990,7 @@ class GatherWindow(ba.Window):
                     sel = self._tab_buttons[current_tab]
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
     
         def _back(self) -> None:
             from bastd.ui import mainmenu
    diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py
    index f1f7d88a..e344257d 100644
    --- a/assets/src/ba_data/python/bastd/ui/kiosk.py
    +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py
    @@ -336,10 +336,7 @@ class KioskWindow(ba.Window):
                                           repeat=True)
     
         def _restore_state(self) -> None:
    -        try:
    -            sel_name = ba.app.window_states[self.__class__.__name__]
    -        except Exception:
    -            sel_name = None
    +        sel_name = ba.app.window_states.get(self.__class__.__name__)
             sel: Optional[ba.Widget]
             if sel_name == 'b1':
                 sel = self._b1
    diff --git a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py
    index a1aecb5a..b64e9e10 100644
    --- a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py
    +++ b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py
    @@ -227,7 +227,7 @@ class LeagueRankButton:
                 ba.buttonwidget(edit=self._button, color=color_used)
     
             except Exception:
    -            ba.print_exception('error doing smooth update')
    +            ba.print_exception('Error doing smooth update.')
                 self._smooth_update_timer = None
     
         def _update_for_league_rank_data(self, data: Optional[Dict[str,
    @@ -285,7 +285,7 @@ class LeagueRankButton:
                         status_text = str(int(self._smooth_percent)) + '%'
     
                 except Exception:
    -                ba.print_exception('error updating power ranking')
    +                ba.print_exception('Error updating power ranking.')
                     self._percent = self._rank = None
                     status_text = '-'
     
    @@ -326,10 +326,15 @@ class LeagueRankButton:
             else:
                 try:
                     assert data is not None
    -                txt = ba.Lstr(resource='league.leagueFullText',
    -                              subs=[('${NAME}',
    -                                     ba.Lstr(translate=('leagueNames',
    -                                                        data['l']['n'])))])
    +                txt = ba.Lstr(
    +                    resource='league.leagueFullText',
    +                    subs=[
    +                        (
    +                            '${NAME}',
    +                            ba.Lstr(translate=('leagueNames', data['l']['n'])),
    +                        ),
    +                    ],
    +                )
                     t_color = data['l']['c']
                 except Exception:
                     txt = ba.Lstr(
    diff --git a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py
    index 066adfc7..c90f705f 100644
    --- a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py
    +++ b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py
    @@ -259,7 +259,7 @@ class LeagueRankWindow(ba.Window):
                         ba.textwidget(edit=self._season_ends_text, text='')
                         ba.textwidget(edit=self._trophy_counts_reset_text, text='')
                 except Exception:
    -                ba.print_exception('error showing updated rank info')
    +                ba.print_exception('Error showing updated rank info.')
     
                 self._last_power_ranking_query_time = cur_time
                 self._doing_power_ranking_query = True
    @@ -651,7 +651,7 @@ class LeagueRankWindow(ba.Window):
                                     '${REMAINING}', str(data['scores'][-1][1])))
                         do_percent = True
                 except Exception:
    -                ba.print_exception('error updating power ranking')
    +                ba.print_exception('Error updating power ranking.')
                     status_text = self._rdict.powerRankingNotInTopText.replace(
                         '${NUMBER}', str(data['listSize']))
                     extra_text = ''
    diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py
    index bbc4dd5c..113f86b7 100644
    --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py
    +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py
    @@ -109,8 +109,8 @@ class MainMenuWindow(ba.Window):
                         ba.timer(2.5,
                                  _check_show_bs_remote_window,
                                  timetype=ba.TimeType.REAL)
    -            except Exception as exc:
    -                print('EXC bs_remote_show', exc)
    +            except Exception:
    +                ba.print_exception('Error showing get-remote-app info')
     
         def _get_store_char_tex(self) -> str:
             return ('storeCharacterXmas' if _ba.get_account_misc_read_val(
    @@ -677,8 +677,8 @@ class MainMenuWindow(ba.Window):
                                              str(cme))
                 except Exception:
                     custom_menu_entries = []
    -                ba.print_exception('exception getting custom menu entries for',
    -                                   session)
    +                ba.print_exception(
    +                    f'Error getting custom menu entries for {session}')
             self._width = 250.0
             self._height = 250.0 if self._input_player else 180.0
             if self._is_kiosk and self._input_player:
    @@ -738,10 +738,7 @@ class MainMenuWindow(ba.Window):
     
                 # Ask the entry whether we should resume when we call
                 # it (defaults to true).
    -            try:
    -                resume = entry['resume_on_call']
    -            except Exception:
    -                resume = True
    +            resume = bool(entry.get('resume_on_call', True))
     
                 if resume:
                     call = ba.Call(self._resume_and_call, entry['call'])
    diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py
    index 9782d494..74c5e540 100644
    --- a/assets/src/ba_data/python/bastd/ui/party.py
    +++ b/assets/src/ba_data/python/bastd/ui/party.py
    @@ -284,7 +284,7 @@ class PartyWindow(ba.Window):
                                             'displayString']
                                 except Exception:
                                     ba.print_exception(
    -                                    'error calcing client name str')
    +                                    'Error calcing client name str.')
                                     p_str = '???'
     
                                 widget = ba.textwidget(parent=self._root_widget,
    diff --git a/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py
    index 582e9410..e29e5ec1 100644
    --- a/assets/src/ba_data/python/bastd/ui/partyqueue.py
    +++ b/assets/src/ba_data/python/bastd/ui/partyqueue.py
    @@ -279,7 +279,7 @@ class PartyQueueWindow(ba.Window):
                 })
                 _ba.run_transactions()
             except Exception:
    -            ba.print_exception('err removing self from party queue')
    +            ba.print_exception('Error removing self from party queue.')
     
         def get_line_left(self) -> float:
             """(internal)"""
    diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py
    index 1caee865..1fd43c5c 100644
    --- a/assets/src/ba_data/python/bastd/ui/play.py
    +++ b/assets/src/ba_data/python/bastd/ui/play.py
    @@ -541,14 +541,11 @@ class PlayWindow(ba.Window):
                     raise ValueError(f'unrecognized selection {sel}')
                 ba.app.window_states[self.__class__.__name__] = sel_name
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[self.__class__.__name__]
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__)
                 if sel_name == 'Team Games':
                     sel = self._teams_button
                 elif sel_name == 'Co-op Games':
    @@ -561,4 +558,4 @@ class PlayWindow(ba.Window):
                     sel = self._coop_button
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
    diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py
    index bb03b07c..85be719a 100644
    --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py
    +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py
    @@ -452,7 +452,7 @@ class PlaylistBrowserWindow(ba.Window):
                             maptype: Optional[Type[ba.Map]]
                             try:
                                 maptype = get_map_class(mapname)
    -                        except Exception:
    +                        except ba.NotFoundError:
                                 maptype = None
                             if maptype is not None:
                                 tex_name = maptype.get_preview_texture_name()
    diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py
    index dda12b80..c1beaac5 100644
    --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py
    +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py
    @@ -229,11 +229,8 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
     
             h = 145
     
    -        try:
    -            self._do_randomize_val = ba.app.config[self._pvars.config_name +
    -                                                   ' Playlist Randomize']
    -        except Exception:
    -            self._do_randomize_val = 0
    +        self._do_randomize_val = ba.app.config.get(
    +            self._pvars.config_name + ' Playlist Randomize', 0)
     
             h += 210
     
    @@ -300,7 +297,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
                 _ba.new_host_session(self._sessiontype)
             except Exception:
                 from bastd import mainmenu
    -            ba.print_exception('exception running session', self._sessiontype)
    +            ba.print_exception(f'Error running session {self._sessiontype}.')
     
                 # Drop back into a main menu session.
                 _ba.new_host_session(mainmenu.MainMenuSession)
    @@ -318,11 +315,8 @@ class PlaylistCustomizeBrowserWindow(ba.Window):
     
             # If there was no prev selection, look in prefs.
             if old_selection is None:
    -            try:
    -                old_selection = ba.app.config[self._pvars.config_name +
    -                                              ' Playlist Selection']
    -            except Exception:
    -                pass
    +            old_selection = ba.app.config.get(self._pvars.config_name +
    +                                              ' Playlist Selection')
     
             old_selection_index = self._selected_playlist_index
     
    diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py
    index 6486be14..07e590de 100644
    --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py
    +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py
    @@ -97,7 +97,7 @@ class PlaylistEditGameWindow(ba.Window):
                     if filtered_map_name in valid_maps:
                         self._map = filtered_map_name
             except Exception:
    -            ba.print_exception('exception getting map for editor')
    +            ba.print_exception('Error getting map for editor.')
     
             if config is not None and 'settings' in config:
                 self._settings = config['settings']
    @@ -427,7 +427,7 @@ class PlaylistEditGameWindow(ba.Window):
                     prev_widgets = cwdg
             except Exception:
                 ba.print_exception(
    -                'error wiring up game-settings-select widget column')
    +                'Error wiring up game-settings-select widget column.')
     
             ba.buttonwidget(edit=add_button, on_activate_call=ba.Call(self._add))
             ba.containerwidget(edit=self._root_widget,
    diff --git a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py
    index 757f622f..62311293 100644
    --- a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py
    +++ b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py
    @@ -135,8 +135,7 @@ class PlaylistMapSelectWindow(ba.Window):
                         map_tex = ba.gettexture(map_tex_name)
                         self._maps.append((mapname, map_tex))
                     except Exception:
    -                    print('invalid map preview texture: "' + map_tex_name +
    -                          '"')
    +                    print(f'Invalid map preview texture: "{map_tex_name}".')
                 else:
                     print('Error: no map preview texture for map:', mapname)
     
    diff --git a/assets/src/ba_data/python/bastd/ui/playoptions.py b/assets/src/ba_data/python/bastd/ui/playoptions.py
    index 3efe14c3..bc3b78a8 100644
    --- a/assets/src/ba_data/python/bastd/ui/playoptions.py
    +++ b/assets/src/ba_data/python/bastd/ui/playoptions.py
    @@ -117,7 +117,7 @@ class PlayOptionsWindow(popup.PopupWindow):
                     maptype: Optional[Type[ba.Map]]
                     try:
                         maptype = get_map_class(mapname)
    -                except Exception:
    +                except ba.NotFoundError:
                         maptype = None
                     if maptype is not None:
                         tex_name = maptype.get_preview_texture_name()
    @@ -141,7 +141,7 @@ class PlayOptionsWindow(popup.PopupWindow):
                     self._height += self._row_height * rows
     
             except Exception:
    -            ba.print_exception('error listing playlist maps')
    +            ba.print_exception('Error listing playlist maps.')
     
             show_shuffle_check_box = game_count > 1
     
    @@ -304,10 +304,7 @@ class PlayOptionsWindow(popup.PopupWindow):
                     on_value_change_call=_cb_callback)
     
             # Show tutorial.
    -        try:
    -            show_tutorial = ba.app.config['Show Tutorial']
    -        except Exception:
    -            show_tutorial = True
    +        show_tutorial = bool(ba.app.config.get('Show Tutorial', True))
     
             def _cb_callback_2(val: bool) -> None:
                 cfg = ba.app.config
    @@ -388,10 +385,8 @@ class PlayOptionsWindow(popup.PopupWindow):
         def _does_target_playlist_exist(self) -> bool:
             if self._playlist == '__default__':
                 return True
    -        val: bool = self._playlist in ba.app.config.get(
    +        return self._playlist in ba.app.config.get(
                 self._pvars.config_name + ' Playlists', {})
    -        assert isinstance(val, bool)
    -        return val
     
         def _update(self) -> None:
             # All we do here is make sure our targeted playlist still exists,
    diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py
    index 81f81b1c..1821ab2c 100644
    --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py
    +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py
    @@ -290,10 +290,7 @@ class ProfileBrowserWindow(ba.Window):
             # Delete old.
             while self._profile_widgets:
                 self._profile_widgets.pop().delete()
    -        try:
    -            self._profiles = ba.app.config['Player Profiles']
    -        except Exception:
    -            self._profiles = {}
    +        self._profiles = ba.app.config.get('Player Profiles', {})
             assert self._profiles is not None
             items = list(self._profiles.items())
             items.sort(key=lambda x: x[0].lower())
    @@ -365,14 +362,11 @@ class ProfileBrowserWindow(ba.Window):
                     sel_name = 'Back'
                 ba.app.window_states[self.__class__.__name__] = sel_name
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[self.__class__.__name__]
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__)
                 if sel_name == 'Scroll':
                     sel = self._scrollwidget
                 elif sel_name == 'New':
    @@ -392,4 +386,4 @@ class ProfileBrowserWindow(ba.Window):
                         sel = self._scrollwidget
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py
    index a76616b4..f996d38f 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py
    @@ -253,7 +253,7 @@ class AdvancedSettingsWindow(ba.Window):
                     lang_names_translated = (json.loads(
                         infile.read())['lang_names_translated'])
             except Exception:
    -            ba.print_exception('error reading lang data')
    +            ba.print_exception('Error reading lang data.')
                 lang_names_translated = {}
     
             langs_translated = {}
    @@ -605,16 +605,13 @@ class AdvancedSettingsWindow(ba.Window):
                     'sel_name': sel_name
                 }
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self.__class__}')
     
         def _restore_state(self) -> None:
             # pylint: disable=too-many-branches
             try:
    -            try:
    -                sel_name = ba.app.window_states[
    -                    self.__class__.__name__]['sel_name']
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__,
    +                                                {}).get('sel_name')
                 if sel_name == 'Back':
                     sel = self._back_button
                 else:
    @@ -654,7 +651,7 @@ class AdvancedSettingsWindow(ba.Window):
                                        selected_child=sel,
                                        visible_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self.__class__}')
     
         def _on_menu_open(self) -> None:
             self._menu_open = True
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py
    index 2a0d5994..7e45179b 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py
    @@ -257,15 +257,12 @@ class AllSettingsWindow(ba.Window):
                     'sel_name': sel_name
                 }
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[
    -                    self.__class__.__name__]['sel_name']
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__,
    +                                                {}).get('sel_name')
                 sel: Optional[ba.Widget]
                 if sel_name == 'Controllers':
                     sel = self._controllers_button
    @@ -282,4 +279,4 @@ class AllSettingsWindow(ba.Window):
                 if sel is not None:
                     ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/audio.py b/assets/src/ba_data/python/bastd/ui/settings/audio.py
    index bbe86a98..bf4c34ce 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/audio.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/audio.py
    @@ -210,7 +210,7 @@ class AudioSettingsWindow(ba.Window):
             try:
                 ba.widget(edit=back_button, down_widget=svne.minusbutton)
             except Exception:
    -            ba.print_exception('error wiring AudioSettingsWindow')
    +            ba.print_exception('Error wiring AudioSettingsWindow.')
     
             self._restore_state()
     
    @@ -269,14 +269,11 @@ class AudioSettingsWindow(ba.Window):
                     raise ValueError(f'unrecognized selection \'{sel}\'')
                 ba.app.window_states[self.__class__.__name__] = sel_name
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self.__class__}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[self.__class__.__name__]
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__)
                 sel: Optional[ba.Widget]
                 if sel_name == 'SoundMinus':
                     sel = self._sound_volume_numedit.minusbutton
    @@ -297,4 +294,4 @@ class AudioSettingsWindow(ba.Window):
                 if sel:
                     ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self.__class__}.')
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py
    index 9805557e..c90d11ff 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py
    @@ -474,10 +474,7 @@ class ControlsSettingsWindow(ba.Window):
             ba.app.window_states[self.__class__.__name__] = sel_name
     
         def _restore_state(self) -> None:
    -        try:
    -            sel_name = ba.app.window_states[self.__class__.__name__]
    -        except Exception:
    -            sel_name = None
    +        sel_name = ba.app.window_states.get(self.__class__.__name__)
             if sel_name == 'GamePads':
                 sel = self._gamepads_button
             elif sel_name == 'Touch':
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py
    index f35abb36..62545869 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py
    @@ -351,7 +351,7 @@ class GamepadSettingsWindow(ba.Window):
                     ba.widget(edit=cancel_button, right_widget=save_button)
                     ba.widget(edit=save_button, left_widget=cancel_button)
             except Exception:
    -            ba.print_exception('error wiring gamepad config window')
    +            ba.print_exception('Error wiring up gamepad config window.')
     
         def get_r(self) -> str:
             """(internal)"""
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py
    index cc8de99c..1b12cdfd 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py
    @@ -403,10 +403,7 @@ class GamepadAdvancedSettingsWindow(ba.Window):
     
         def _inc(self, control: str, min_val: float, max_val: float,
                  inc: float) -> None:
    -        try:
    -            val = self._parent_window.get_settings()[control]
    -        except Exception:
    -            val = 1.0
    +        val = self._parent_window.get_settings().get(control, 1.0)
             val = min(max_val, max(min_val, val + inc))
             if abs(1.0 - val) < 0.001:
                 if control in self._parent_window.get_settings():
    diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
    index 8340ceaa..b727122b 100644
    --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
    +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py
    @@ -379,19 +379,14 @@ class SoundtrackBrowserWindow(ba.Window):
     
             # If there was no prev selection, look in prefs.
             if old_selection is None:
    -            try:
    -                old_selection = ba.app.config['Soundtrack']
    -            except Exception:
    -                pass
    +            old_selection = ba.app.config.get('Soundtrack')
             old_selection_index = self._selected_soundtrack_index
     
             # Delete old.
             while self._soundtrack_widgets:
                 self._soundtrack_widgets.pop().delete()
    -        try:
    -            self._soundtracks = ba.app.config['Soundtracks']
    -        except Exception:
    -            self._soundtracks = {}
    +
    +        self._soundtracks = ba.app.config.get('Soundtracks', {})
             assert self._soundtracks is not None
             items = list(self._soundtracks.items())
             items.sort(key=lambda x: x[0].lower())
    @@ -488,14 +483,11 @@ class SoundtrackBrowserWindow(ba.Window):
                     raise ValueError(f'unrecognized selection \'{sel}\'')
                 ba.app.window_states[self.__class__.__name__] = sel_name
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[self.__class__.__name__]
    -            except Exception:
    -                sel_name = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__)
                 if sel_name == 'Scroll':
                     sel = self._scrollwidget
                 elif sel_name == 'New':
    @@ -510,4 +502,4 @@ class SoundtrackBrowserWindow(ba.Window):
                     sel = self._scrollwidget
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
    diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py
    index 7373bf18..0895cb83 100644
    --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py
    +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py
    @@ -213,10 +213,7 @@ class SoundtrackEditWindow(ba.Window):
                                    claims_left_right=True,
                                    claims_tab=True,
                                    selection_loop_to_parent=True)
    -            try:
    -                type_name = type_names_translated[song_type]
    -            except Exception:
    -                type_name = song_type
    +            type_name = type_names_translated.get(song_type, song_type)
                 ba.textwidget(parent=row,
                               size=(230, 25),
                               always_highlight=True,
    diff --git a/assets/src/ba_data/python/bastd/ui/specialoffer.py b/assets/src/ba_data/python/bastd/ui/specialoffer.py
    index f32432f0..6c9169e7 100644
    --- a/assets/src/ba_data/python/bastd/ui/specialoffer.py
    +++ b/assets/src/ba_data/python/bastd/ui/specialoffer.py
    @@ -119,6 +119,7 @@ class SpecialOfferWindow(ba.Window):
                         resource='store.salePercentText').evaluate().replace(
                             '${PERCENT}', str(percent_off))
             except Exception:
    +            ba.print_exception('Error setting up special-offer')
                 original_price_str = new_price_str = '?'
                 percent_off_text = ''
     
    @@ -462,6 +463,6 @@ def show_offer() -> bool:
                 app.special_offer = None
                 return True
         except Exception:
    -        ba.print_exception('Error showing offer')
    +        ba.print_exception('Error showing offer.')
     
         return False
    diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py
    index e6522e7c..59ad1d34 100644
    --- a/assets/src/ba_data/python/bastd/ui/store/browser.py
    +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py
    @@ -1008,20 +1008,14 @@ class StoreBrowserWindow(ba.Window):
                     'tab': self._current_tab
                 }
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
                 sel: Optional[ba.Widget]
    -            try:
    -                sel_name = (
    -                    ba.app.window_states[self.__class__.__name__]['sel_name'])
    -            except Exception:
    -                sel_name = None
    -            try:
    -                current_tab = ba.app.config['Store Tab']
    -            except Exception:
    -                current_tab = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__,
    +                                                {}).get('sel_name')
    +            current_tab = ba.app.config.get('Store Tab')
                 if self._show_tab is not None:
                     current_tab = self._show_tab
                 if current_tab is None or current_tab not in self._tab_buttons:
    @@ -1044,7 +1038,7 @@ class StoreBrowserWindow(ba.Window):
                 if sel is not None:
                     ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
     
         def _on_get_more_tickets_press(self) -> None:
             # pylint: disable=cyclic-import
    diff --git a/assets/src/ba_data/python/bastd/ui/store/button.py b/assets/src/ba_data/python/bastd/ui/store/button.py
    index 7807873d..17d73f0a 100644
    --- a/assets/src/ba_data/python/bastd/ui/store/button.py
    +++ b/assets/src/ba_data/python/bastd/ui/store/button.py
    @@ -259,7 +259,7 @@ class StoreButton:
                             if to_end > 0:
                                 sale_times.append(to_end)
                 except Exception:
    -                ba.print_exception('Error parsing sales')
    +                ba.print_exception('Error parsing sales.')
                 if sale_times:
                     sale_time = int(min(sale_times) * 1000)
     
    diff --git a/assets/src/ba_data/python/bastd/ui/tournamententry.py b/assets/src/ba_data/python/bastd/ui/tournamententry.py
    index 8c2171b4..6b53b2d9 100644
    --- a/assets/src/ba_data/python/bastd/ui/tournamententry.py
    +++ b/assets/src/ba_data/python/bastd/ui/tournamententry.py
    @@ -332,10 +332,7 @@ class TournamentEntryWindow(popup.PopupWindow):
             cfg.commit()
     
         def _restore_state(self) -> None:
    -        try:
    -            sel_name = ba.app.config['Tournament Pay Selection']
    -        except Exception:
    -            sel_name = 'Tickets'
    +        sel_name = ba.app.config.get('Tournament Pay Selection', 'Tickets')
             if sel_name == 'Ad' and self._pay_with_ad_btn is not None:
                 sel = self._pay_with_ad_btn
             else:
    @@ -457,13 +454,14 @@ class TournamentEntryWindow(popup.PopupWindow):
                     ba.screenmessage(ba.Lstr(translate=('serverResponses',
                                                         'Entering tournament...')),
                                      color=(0, 1, 0))
    +
                 # We can hit exceptions here if _tournament_activity ends before
                 # our restart attempt happens.
                 # In this case we'll fall back to launching a new session.
                 # This is not ideal since players will have to rejoin, etc.,
                 # but it works for now.
                 except Exception:
    -                pass
    +                print('Error restarting tournament activity.')
     
             # If we had no existing activity (or were unable to restart it)
             # launch a new session.
    diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py
    index dd8baf3e..f739c1ff 100644
    --- a/assets/src/ba_data/python/bastd/ui/watch.py
    +++ b/assets/src/ba_data/python/bastd/ui/watch.py
    @@ -286,16 +286,17 @@ class WatchWindow(ba.Window):
     
             def do_it() -> None:
                 try:
    -                # reset to normal speed
    +                # Reset to normal speed.
                     _ba.set_replay_speed_exponent(0)
                     _ba.fade_screen(True)
                     assert self._my_replay_selected is not None
                     _ba.new_replay_session(_ba.get_replays_dir() + '/' +
                                            self._my_replay_selected)
                 except Exception:
    -                ba.print_exception('exception running replay session')
    -                # drop back into a fresh main menu session
    -                # in case we half-launched or something..
    +                ba.print_exception('Error running replay session.')
    +
    +                # Drop back into a fresh main menu session
    +                # in case we half-launched or something.
                     from bastd import mainmenu
                     _ba.new_host_session(mainmenu.MainMenuSession)
     
    @@ -391,11 +392,12 @@ class WatchWindow(ba.Window):
                         ba.playsound(ba.getsound('gunCocking'))
             except Exception:
                 ba.print_exception(
    -                f"error renaming replay '{replay}' to '{new_name}'")
    +                f"Error renaming replay '{replay}' to '{new_name}'.")
                 ba.playsound(ba.getsound('error'))
    -            ba.screenmessage(ba.Lstr(resource=self._r +
    -                                     '.replayRenameErrorText'),
    -                             color=(1, 0, 0))
    +            ba.screenmessage(
    +                ba.Lstr(resource=self._r + '.replayRenameErrorText'),
    +                color=(1, 0, 0),
    +            )
     
             ba.containerwidget(edit=self._my_replays_rename_window,
                                transition='out_scale')
    @@ -428,11 +430,12 @@ class WatchWindow(ba.Window):
                 if replay == self._my_replay_selected:
                     self._my_replay_selected = None
             except Exception:
    -            ba.print_exception("exception deleting replay '" + replay + "'")
    +            ba.print_exception(f"Error deleting replay '{replay}'.")
                 ba.playsound(ba.getsound('error'))
    -            ba.screenmessage(ba.Lstr(resource=self._r +
    -                                     '.replayDeleteErrorText'),
    -                             color=(1, 0, 0))
    +            ba.screenmessage(
    +                ba.Lstr(resource=self._r + '.replayDeleteErrorText'),
    +                color=(1, 0, 0),
    +            )
     
         def _on_my_replay_select(self, replay: str) -> None:
             self._my_replay_selected = replay
    @@ -448,7 +451,7 @@ class WatchWindow(ba.Window):
                 names = [n for n in names if n.endswith('.brp')]
                 names.sort(key=lambda x: x.lower())
             except Exception:
    -            ba.print_exception('error listing replays dir')
    +            ba.print_exception('Error listing replays dir.')
                 names = []
     
             assert self._my_replays_scroll_width is not None
    @@ -488,19 +491,13 @@ class WatchWindow(ba.Window):
                     'tab': self._current_tab
                 }
             except Exception:
    -            ba.print_exception('error saving state for', self.__class__)
    +            ba.print_exception(f'Error saving state for {self}.')
     
         def _restore_state(self) -> None:
             try:
    -            try:
    -                sel_name = ba.app.window_states[
    -                    self.__class__.__name__]['sel_name']
    -            except Exception:
    -                sel_name = None
    -            try:
    -                current_tab = ba.app.config['Watch Tab']
    -            except Exception:
    -                current_tab = None
    +            sel_name = ba.app.window_states.get(self.__class__.__name__,
    +                                                {}).get('sel_name')
    +            current_tab = ba.app.config.get('Watch Tab')
                 if current_tab is None or current_tab not in self._tab_buttons:
                     current_tab = 'my_replays'
                 self._set_tab(current_tab)
    @@ -517,7 +514,7 @@ class WatchWindow(ba.Window):
                         sel = self._tab_buttons[current_tab]
                 ba.containerwidget(edit=self._root_widget, selected_child=sel)
             except Exception:
    -            ba.print_exception('error restoring state for', self.__class__)
    +            ba.print_exception(f'Error restoring state for {self}.')
     
         def _back(self) -> None:
             from bastd.ui import mainmenu
    diff --git a/docs/ba_module.md b/docs/ba_module.md
    index 5b73dcce..ea3a1495 100644
    --- a/docs/ba_module.md
    +++ b/docs/ba_module.md
    @@ -1,5 +1,5 @@
     
    -

    last updated on 2020-06-16 for Ballistica version 1.5.5 build 20070

    +

    last updated on 2020-06-16 for Ballistica version 1.5.5 build 20071

    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!


    @@ -6620,7 +6620,7 @@ playing, the playing track will not be restarted.


    ba.storagename()

    -

    storagename(basename: str) -> str

    +

    storagename(suffix: str = None) -> str

    Generate a (hopefully) unique name for storing things in public places.

    diff --git a/tools/bacloud b/tools/bacloud index 51c3b050..55da2960 100755 --- a/tools/bacloud +++ b/tools/bacloud @@ -438,7 +438,7 @@ if __name__ == '__main__': except KeyboardInterrupt: # Let's do a clean fail on keyboard interrupt. # Can make this optional if a backtrace is ever useful.. - sys.exit(-1) + sys.exit(1) except CleanError as exc: exc.pretty_print() - sys.exit(-1) + sys.exit(1) diff --git a/tools/efro/entity/_value.py b/tools/efro/entity/_value.py index 44bf4ec9..b85919d9 100644 --- a/tools/efro/entity/_value.py +++ b/tools/efro/entity/_value.py @@ -369,7 +369,8 @@ class BaseEnumValue(TypedValue[T]): except ValueError: if error: raise ValueError( - f'Invalid value for {self._enumtype}: {data}') + f'Invalid value for {self._enumtype}: {data}' + ) from None logging.error('Ignoring invalid value for %s: %s', self._enumtype, data) data = self._default_data diff --git a/tools/efro/terminal.py b/tools/efro/terminal.py index 7f8acb8c..3c852e82 100644 --- a/tools/efro/terminal.py +++ b/tools/efro/terminal.py @@ -145,7 +145,7 @@ def _windows_enable_color() -> bool: return set_conout_mode(mode, mask) except WindowsError as exc: if exc.winerror == ERROR_INVALID_PARAMETER: - raise NotImplementedError + raise NotImplementedError from exc raise try: From fc7b2fa4740dc6685b727b41f6e7434a0d77bb15 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Wed, 17 Jun 2020 23:05:24 +0300 Subject: [PATCH 100/417] Update CHANGELOG.md for better look in Markdown --- CHANGELOG.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2696a3d2..b15a4dbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,15 +20,15 @@ - Misc bug fixes. ### 1.5.0 (20001) -- This build contains about 2 years worth of MAJOR internal refactoring to prepare for the future of BombSquad. As a player this should not (yet) look different from 1.4, but for modders there is a lot new. See the rest of these change entries or visit ballistica.net for more info. +- This build contains about 2 years worth of MAJOR internal refactoring to prepare for the future of BombSquad. As a player this should not (yet) look different from 1.4, but for modders there is a lot new. See the rest of these change entries or visit [ballistica.net](https://ballistica.net) for more info. - Ported the entire scripting layer from Python 2 to to Python 3 (currently at 3.7, and I intend to keep this updated to the latest widely-available release). There's some significant changes going from python 2 to 3 (new print statement, string behavior, etc), but these are well documented online, so please read up as needed. This should provide us some nice benefits and future-proofs everything. (my janky 2.7 custom Python builds were getting a little long in the tooth). -- Refactored all script code to be PEP8 compliant (Python coding standards). Basically, this means that stuff that was camel-case (fooBar) is now a single word or underscores (foobar / foo_bar). There are a few minor exceptions such as existing resource and media filenames, but in general old code can be ported by taking a pass through and killing the camel-case. I know this is a bit of a pain in the ass, but it'll let us use things like Pylint and just be more consistent with the rest of the Python world. +- Refactored all script code to be PEP8 compliant (Python coding standards). Basically, this means that stuff that was camel-case (fooBar) is now a single word or underscores (foobar / foo\_bar). There are a few minor exceptions such as existing resource and media filenames, but in general old code can be ported by taking a pass through and killing the camel-case. I know this is a bit of a pain in the ass, but it'll let us use things like Pylint and just be more consistent with the rest of the Python world. - On a related note, I'm now using 'yapf' to keep my Python code formatted nicely (using pep8 style); I'd recommend checking it out if you're doing a lot of scripting as its a great time-saver. - On another related note, I'm trying to confirm to Google's recommendations for Python code (search 'Google Python Style Guide'). There are some good bits of wisdom in there so I recommend at least skimming through it. - And as one last related note, I'm now running Pylint on all my own Python code. Highly recommended if you are doing serious scripting, as it can make Python almost feel as type-safe as C++. - The minimum required android version will now be 5.0 (a requirement of the Python 3 builds I'm using) - Minimum required macOS version is now 10.13 (for similar reasons) -- 'bsInternal' module is now '_ba' (better lines up with standard Python practices) +- 'bsInternal' module is now '\_ba' (better lines up with standard Python practices) - bs.writeConfig() and bs.applySettings() are no more. There is now ba.app.config which is basically a fancy dict class with some methods added such as commit() and apply() - bs.getEnvironment() is no more; the values there are now available through ba.app (see notes down further) - Fixed the mac build so command line input works again when launched from a terminal @@ -38,7 +38,7 @@ - Various other minor name changes (bs.getUIBounds() -> ba.app.uibounds, etc). I'm keeping old and new Python API docs around for now so you can compare as needed. - Renamed bot classes based on their actions instead of their appearances (ie: PirateBot -> ExplodeyBot) - bs.getSharedObject() is now ba.stdobj() -- Removed bs.uni(), bs.utf8(), bs.uni_to_ints(), and bs.uni_from_ints() which are no longer needed due to Python 3's better string handling. +- Removed bs.uni(), bs.utf8(), bs.uni\_to\_ints(), and bs.uni\_from\_ints() which are no longer needed due to Python 3's better string handling. - Removed bs.SecureInt since it didn't do much to slow down hackers and hurts code readability. - Renamed 'finalize' to 'expire' for actors and activities. 'Finalize' sounds too much like a destructor, which is not really what that is. - bs.getMapsSupportingPlayType() is now simply ba.getmaps(). I might want to add more filter options to it besides just play-type, hence the rename. @@ -46,9 +46,9 @@ - I'm converting all scripting functions to operate on floating-point seconds by default instead of integer milliseconds. This will let us support more accurate simulations later and is just cleaner I feel. To keep existing calls working you should be able to add timeformat='ms' and you'll get the old behavior (or multiply your time values by 0.001). Specific notes listed below. - ba.Timer now takes its 'time' arg as seconds instead of milliseconds. To port old calls, add: timeformat='ms' to each call (or multiply your input by 0.001) - ba.animate() now takes times in seconds and its 'driver' arg is now 'timetype' for consistency with other time functions. To port existing code you can pass timeformat='ms' to keep the old milliseconds based behavior. -- ditto for ba.animate_array() +- ditto for ba.animate\_array() - ba.Activity.end() now takes seconds instead of milliseconds as its delay arg. -- TNTSpawner now also takes seconds instead of milliseconds for respawn_time. +- TNTSpawner now also takes seconds instead of milliseconds for respawn\_time. - There is a new ba.timer() function which is used for all one-off timer creation. It has the same args as the ba.Timer() class constructor. - bs.gameTimer() is no more. Pass timeformat='ms' to ba.timer() if you need to recreate its behavior. - bs.netTimer() is no more. Pass timetype='base' and timeformat='ms' to ba.timer() if you need to recreate its behavior. @@ -58,19 +58,19 @@ - bs.getNetTime() is no more. Pass timetype='base' and timeformat='ms' to ba.time() if you need to recreate its behavior. - bs.getRealTime() is no more. Pass timetype='real' and timeformat='ms' to ba.time() if you need to recreate its behavior. - bs.getTimeString() is now just ba.timestring(), and accepts seconds by default (pass timeformat='ms' to keep old calls working). -- bs.callInGameThread() has been replaced by an optional 'from_other_thread' arg for ba.pushcall() +- bs.callInGameThread() has been replaced by an optional 'from\_other\_thread' arg for ba.pushcall() - There is now a special ba.UNHANDLED value that handlemessage() calls should return any time they don't handle a passed message. This will allow fallback message types and other nice things in the future. - Wired the boolean operator up to ba.Actor's exists() method, so now a simple "if mynode" will do the right thing for both Actors and None values instead of having to explicitly check for both. - Ditto for ba.Node; you can now just do 'if mynode' which will do the right thing for both a dead Node or None. - Ditto for ba.InputDevice, ba.Widget, ba.Player - Added a bs.App class accessible via ba.app; will be migrating global app values there instead of littering python modules with globals. The only remaining module globals should be all-caps public 'constants' -- 'Internal' methods and classes living in _ba and elsewhere no longer start with underscores. They are now simply marked with '(internal)' in their docstrings. 'Internal' bits are likely to have janky interfaces and can change without warning, so be wary of using them. If you find yourself depending on some internal thing often, please let me know and I can try to clean it up and make it 'public'. +- 'Internal' methods and classes living in \_ba and elsewhere no longer start with underscores. They are now simply marked with '(internal)' in their docstrings. 'Internal' bits are likely to have janky interfaces and can change without warning, so be wary of using them. If you find yourself depending on some internal thing often, please let me know and I can try to clean it up and make it 'public'. - bs.getLanguage() is no more; that value is now accessible via ba.app.language - bs.Actor now accepts an optional 'node' arg which it will store as self.node if passed. Its default DieMessage() and exists() handlers will use self.node if it exists. This removes the need for a separate NodeActor() for simple cases. - bs.NodeActor is no more (it can simply be replaced with ba.Actor()) - bs.playMusic() is now ba.setmusic() which better fits its functionality (it sometimes just continues playing or stops playing). - The bs.Vector class is no more; in its place is a shiny new ba.Vec3 which is implemented internally in C++ so its nice and speedy. Will probably update certain things like vector node attrs to support this class in the future since it makes vector math nice and convenient. -- Ok you get the point.. see ballistica.net for more info on these changes. +- Ok you get the point.. see [ballistica.net](https://ballistica.net) for more info on these changes. ### 1.4.155 (14377) - Added protection against a repeated-input attack in lobbies. @@ -81,8 +81,8 @@ ### 1.4.150 (14369) - Telnet port can now be specified in the config - Telnet socket no longer opens on headless build when telnet access is off (reduces DoS attack potential) -- Added a filter_chat_message() call which can be used by servers to intercept/modify/block all chat messages. -- bsInternal._disconnectClient() now takes an optional banTime arg (in seconds, defaults to old value of 300). +- Added a filter\_chat\_message() call which can be used by servers to intercept/modify/block all chat messages. +- bsInternal.\_disconnectClient() now takes an optional banTime arg (in seconds, defaults to old value of 300). ### 1.4.148 (14365) - Added a password option for telnet access on server builds @@ -120,7 +120,7 @@ - Removed the language column from the server browser. This was more relevant back when all clients saw the game in the server's language, and is nowadays largely just hijacked for silly purposes. Holler if you miss it. - Server list now re-pings servers less often and averages ping results to reduce the amount of jumping around in the list. Please holler if this feels off. - Added some slick new client-verification tech. Going forward it should be pretty much impossible to fool a server into thinking you are using a different account than you really are. -- Added a 'get_account_id()' method to the bs.Player class. This will return a player's signed-in account-id (when it can be verified for certain) +- Added a 'get\_account\_id()' method to the bs.Player class. This will return a player's signed-in account-id (when it can be verified for certain) ### 1.4.138 (14336) - Removed SDL library from the server builds, so that's one less dependency that needs to be installed when setting up a linux server @@ -240,10 +240,10 @@ - fixed a bug that could cause the windows version to freeze randomly after a while ### 1.4.95 (14233) -- ballisticacore (both bs_headless and regular) now reads commands from standard input, making it easier to run commands via scripts or the terminal +- ballisticacore (both bs\_headless and regular) now reads commands from standard input, making it easier to run commands via scripts or the terminal - server now runs using a 'server' account-type instead of the local 'device' account. (avoids daily-ticket-reward messages and other stuff that's not relevant to servers) - the server script now passes args to the game as a json file instead of individual args; this should keep things cleaner and more expandable -- the ballisticacore_server script also now reads commands from stdin, allowing reconfiguring server settings on the fly +- the ballisticacore\_server script also now reads commands from stdin, allowing reconfiguring server settings on the fly - added more options such as the ability to set game series lengths and to host a non-public party ### 1.4.94 From be6a7b74374dedb923d4f9a7080dc5cd5bd9fc53 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Wed, 17 Jun 2020 23:09:19 +0300 Subject: [PATCH 101/417] Update CONTRIBUTORS.md --- CONTRIBUTORS.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 78e21e1b..b17b8450 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -9,9 +9,4 @@ - Fixed some game modes ### Roman Trapeznikov -###### Ballistica -- Bug fixes -###### beyond the project code -- Game servers developer -- Modder - +- Bug fixes and code cleanup From 97457e5bfdfa1fe779e976982c0386045a32ce93 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 17 Jun 2020 17:31:41 -0700 Subject: [PATCH 102/417] More work towards Android 1.5 --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 6 + Makefile | 52 +- assets/src/server/ballisticacore_server.py | 8 +- .../server/launch_ballisticacore_server.bat | 5 +- tools/batools/snippets.py | 618 ++++++++++++++++++ tools/snippets | 562 +--------------- 8 files changed, 689 insertions(+), 587 deletions(-) create mode 100644 tools/batools/snippets.py diff --git a/.efrocachemap b/.efrocachemap index 571dca2e..e76d1774 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/29/9c/24a918c046b06f010d9948458a09", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2e/1c/2285cc92d83ce3a32b26c020cb71", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/b6/9410d8cf8be5aaf2ffad07964950", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/48/c4/2bdd6802858b92c348df702c9dcd", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/ca/0a1426dabc53a9f90a6beb011423", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/ef/4186b927c2675c3e4dfa19ba180d", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/29/59/60175945534d87709dfc29d1b180", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5c/b8/16b868c1bbd8b1be2ebaf4da4d31", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/6c/33b6b194062212beeae3043515a3", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4b/24/c54be077112185f6a3d2c67641ea", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ee/6e/a9d59e81b549b992673d20f84f11", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5b/73/97159eb1d7dfb4018c5a1241f164" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fc/3d/ab2ccd1f76fec48d1d1f8cc07aa4", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e2/e1/672e2ccaceadf3b0867bf3b887a4", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5f/9d/90533da6e9d91dc6b932a2aa7f43", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/30/ea/6af215aa0cab66e46c7041a7b091", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/55/66/b8bc31f6818606e282eda887939f", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/52/e7/2419b41d3524735dc709338c4290", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/11/b5/5ee7f3ba18e2683d56b8a020b39f", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/24/5f/6953fd0f2b47e943ea734bc14911", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1b/fb/739c5d5dc13218efdeaaa020c9f9", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/15/75f7b94e3608435a4609a3992dbc", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9f/9d/cf77bfbd79aed7178d9674b3af14", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c9/b2/6863b197eac679f85a5414525aa9" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 74ab5b89..a631cdc7 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1196,6 +1196,7 @@ modder modders modename + modestr modpack modtimes moduledir diff --git a/CHANGELOG.md b/CHANGELOG.md index 2696a3d2..20550909 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 1.5.6 (20072) +- Mouse wheel now works in manual camera mode on more platforms. +- Lots of internal event-handling cleanup/reorganization in preparation for Android 1.5 update. +- Server scripts now run in opt mode in release builds so they can use bundled .opt-1.pyc files. +- More misc bug fixes and tidying. + ### 1.5.5 (20069) - Cleaned up Windows version packaging. - More misc bug fixes. diff --git a/Makefile b/Makefile index 47257e12..79ede417 100644 --- a/Makefile +++ b/Makefile @@ -188,14 +188,15 @@ prefab-mac-server-debug-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/debug/dist build/prefab/mac-server/debug/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py - @cp $< $@ + assets/src/server/ballisticacore_server.py tools/batools/snippets.py + @tools/snippets stage_server_file debug $< $@ build/prefab/mac-server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ + tools/batools/snippets.py \ tools/bacommon/servermanager.py - @tools/snippets filter_server_config $< $@ + @tools/snippets stage_server_file debug $< $@ build/prefab/mac-server/debug/README.txt: \ assets/src/server/README.txt @@ -219,14 +220,15 @@ prefab-mac-server-release-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/release/dist build/prefab/mac-server/release/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py - @cp $< $@ + assets/src/server/ballisticacore_server.py tools/batools/snippets.py + @tools/snippets stage_server_file release $< $@ build/prefab/mac-server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ + tools/batools/snippets.py \ tools/bacommon/servermanager.py - @tools/snippets filter_server_config $< $@ + @tools/snippets stage_server_file release $< $@ build/prefab/mac-server/release/README.txt: \ assets/src/server/README.txt @@ -276,14 +278,15 @@ prefab-linux-server-debug-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/debug/dist build/prefab/linux-server/debug/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py - @cp $< $@ + assets/src/server/ballisticacore_server.py tools/batools/snippets.py + @tools/snippets stage_server_file debug $< $@ build/prefab/linux-server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ + tools/batools/snippets.py \ tools/bacommon/servermanager.py - @tools/snippets filter_server_config $< $@ + @tools/snippets stage_server_file debug $< $@ build/prefab/linux-server/debug/README.txt: \ assets/src/server/README.txt @@ -307,14 +310,15 @@ prefab-linux-server-release-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/release/dist build/prefab/linux-server/release/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py - @cp $< $@ + assets/src/server/ballisticacore_server.py tools/batools/snippets.py + @tools/snippets stage_server_file release $< $@ build/prefab/linux-server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ + tools/batools/snippets.py \ tools/bacommon/servermanager.py - @tools/snippets filter_server_config $< $@ + @tools/snippets stage_server_file release $< $@ build/prefab/linux-server/release/README.txt: \ assets/src/server/README.txt @@ -376,25 +380,26 @@ build/prefab/windows-server/debug/dist/ballisticacore_headless.exe: .efrocachema @tools/snippets efrocache_get $@ build/prefab/windows-server/debug/ballisticacore_server.py: \ - assets/src/server/ballisticacore_server.py - @cp $< $@ + assets/src/server/ballisticacore_server.py tools/batools/snippets.py + @tools/snippets stage_server_file debug $< $@ build/prefab/windows-server/debug/launch_ballisticacore_server.bat: \ - assets/src/server/launch_ballisticacore_server.bat - @cp $< $@ + assets/src/server/launch_ballisticacore_server.bat tools/batools/snippets.py + @tools/snippets stage_server_file debug $< $@ build/prefab/windows-server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ + tools/batools/snippets.py \ tools/bacommon/servermanager.py - @tools/snippets filter_server_config $< $@ + @tools/snippets stage_server_file debug $< $@ build/prefab/windows-server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ RUN_PREFAB_WINDOWS_SERVER_RELEASE = cd build/prefab/windows-server/release \ - && dist/python.exe ballisticacore_server.py + && dist/python.exe -O ballisticacore_server.py prefab-windows-server-release: prefab-windows-server-release-build @tools/snippets ensure_prefab_platform windows @@ -414,18 +419,19 @@ build/prefab/windows-server/release/dist/ballisticacore_headless.exe: .efrocache @tools/snippets efrocache_get $@ build/prefab/windows-server/release/ballisticacore_server.py: \ - assets/src/server/ballisticacore_server.py - @cp $< $@ + assets/src/server/ballisticacore_server.py tools/batools/snippets.py + @tools/snippets stage_server_file release $< $@ build/prefab/windows-server/release/launch_ballisticacore_server.bat: \ - assets/src/server/launch_ballisticacore_server.bat - @cp $< $@ + assets/src/server/launch_ballisticacore_server.bat tools/batools/snippets.py + @tools/snippets stage_server_file release $< $@ build/prefab/windows-server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ + tools/batools/snippets.py \ tools/bacommon/servermanager.py - @tools/snippets filter_server_config $< $@ + @tools/snippets stage_server_file release $< $@ build/prefab/windows-server/release/README.txt: \ assets/src/server/README.txt diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index 969d5884..a0de2d87 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -51,7 +51,7 @@ if TYPE_CHECKING: # Not sure how much versioning we'll do with this, but this will get # printed at startup in case we need it. -VERSION_STR = '1.0.1' +VERSION_STR = '1.0.2' class ServerManagerApp: @@ -106,9 +106,13 @@ class ServerManagerApp: # Print basic usage info in interactive mode. if sys.stdin.isatty(): + if __debug__: + modestr = '(debug mode)' + else: + modestr = '(opt mode)' print(f'{Clr.CYN}{Clr.BLD}BallisticaCore server' f' manager {VERSION_STR}' - f' starting up...{Clr.RST}\n' + f' starting up {modestr}...{Clr.RST}\n' f'{Clr.CYN}Use the "mgr" object to make' f' live server adjustments.\n' f'Type "help(mgr)" for more information.{Clr.RST}') diff --git a/assets/src/server/launch_ballisticacore_server.bat b/assets/src/server/launch_ballisticacore_server.bat index a5315816..547324d6 100644 --- a/assets/src/server/launch_ballisticacore_server.bat +++ b/assets/src/server/launch_ballisticacore_server.bat @@ -1,4 +1,3 @@ :: Simply run the ballisticacore_server.py script with the bundled -:: python interpreter. Run in opt-mode so we pick up all the -:: bundled .opt-1.pyc files too. -dist\\python.exe -O ballisticacore_server.py +:: Python interpreter. +dist\\python.exe ballisticacore_server.py diff --git a/tools/batools/snippets.py b/tools/batools/snippets.py new file mode 100644 index 00000000..7324cc21 --- /dev/null +++ b/tools/batools/snippets.py @@ -0,0 +1,618 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Standard snippets that can be pulled into project snippets scripts. + +A snippet is a mini-program that directly takes input from stdin and does +some focused task. This module consists of ballistica-specific ones. +""" +from __future__ import annotations + +# Note: import as little as possible here at the module level to +# keep launch times fast for small snippets. +import sys +from typing import TYPE_CHECKING + +from efrotools.snippets import PROJROOT + +if TYPE_CHECKING: + from typing import Optional + + +def stage_server_file() -> None: + """Stage files for the server environment with some filtering.""" + import os + import subprocess + import batools.build + from efro.error import CleanError + from efrotools import replace_one + if len(sys.argv) != 5: + raise CleanError('Expected 3 args (mode, infile, outfile).') + mode, infilename, outfilename = sys.argv[2], sys.argv[3], sys.argv[4] + if mode not in ('debug', 'release'): + raise CleanError(f"Invalid mode '{mode}'; expected debug or release.") + + print(f'Building server file: {os.path.basename(outfilename)}') + + basename = os.path.basename(infilename) + if basename == 'config_template.yaml': + # Inject all available config values into the config file. + batools.build.filter_server_config(str(PROJROOT), infilename, + outfilename) + elif basename == 'ballisticacore_server.py': + # Run Python in opt mode for release builds. + with open(infilename) as infile: + lines = infile.read().splitlines() + if mode == 'release': + lines[0] = replace_one(lines[0], '#!/usr/bin/env python3.7', + '#!/usr/bin/env python3.7 -O') + with open(outfilename, 'w') as outfile: + outfile.write('\n'.join(lines) + '\n') + subprocess.run(['chmod', '+x', outfilename], check=True) + elif basename == 'launch_ballisticacore_server.bat': + # Run Python in opt mode for release builds. + with open(infilename) as infile: + lines = infile.read().splitlines() + if mode == 'release': + lines[1] = replace_one( + lines[1], ':: Python interpreter.', + ':: Python interpreter.' + ' (in opt mode so we use bundled .opt-1.pyc files)') + lines[2] = replace_one( + lines[2], 'dist\\\\python.exe ballisticacore_server.py', + 'dist\\\\python.exe -O ballisticacore_server.py') + with open(outfilename, 'w') as outfile: + outfile.write('\n'.join(lines) + '\n') + else: + raise CleanError(f"Unknown server file for staging: '{basename}'.") + + +def py_examine() -> None: + """Run a python examination at a given point in a given file.""" + import os + from pathlib import Path + import efrotools + if len(sys.argv) != 7: + print('ERROR: expected 7 args') + sys.exit(255) + filename = Path(sys.argv[2]) + line = int(sys.argv[3]) + column = int(sys.argv[4]) + selection: Optional[str] = (None if sys.argv[5] == '' else sys.argv[5]) + operation = sys.argv[6] + + # This stuff assumes it is being run from project root. + os.chdir(PROJROOT) + + # Set up pypaths so our main distro stuff works. + scriptsdir = os.path.abspath( + os.path.join(os.path.dirname(sys.argv[0]), + '../assets/src/ba_data/python')) + toolsdir = os.path.abspath( + os.path.join(os.path.dirname(sys.argv[0]), '../tools')) + if scriptsdir not in sys.path: + sys.path.append(scriptsdir) + if toolsdir not in sys.path: + sys.path.append(toolsdir) + efrotools.py_examine(PROJROOT, filename, line, column, selection, + operation) + + +def clean_orphaned_assets() -> None: + """Remove asset files that are no longer part of the build.""" + import os + import json + import efrotools + + # Operate from dist root.. + os.chdir(PROJROOT) + + # Our manifest is split into 2 files (public and private) + with open('assets/.asset_manifest_public.json') as infile: + manifest = set(json.loads(infile.read())) + with open('assets/.asset_manifest_private.json') as infile: + manifest.update(set(json.loads(infile.read()))) + for root, _dirs, fnames in os.walk('assets/build'): + for fname in fnames: + fpath = os.path.join(root, fname) + fpathrel = fpath[13:] # paths are relative to assets/build + if fpathrel not in manifest: + print(f'Removing orphaned asset file: {fpath}') + os.unlink(fpath) + + # Lastly, clear empty dirs. + efrotools.run('find assets/build -depth -empty -type d -delete') + + +def fix_mac_ssh() -> None: + """Turn off mac ssh password access. + + (This totally doesn't belong in this project btw..) + """ + configpath = '/etc/ssh/sshd_config' + with open(configpath) as infile: + lines = infile.readlines() + index = lines.index('#PasswordAuthentication yes\n') + lines[index] = 'PasswordAuthentication no\n' + index = lines.index('#ChallengeResponseAuthentication yes\n') + lines[index] = 'ChallengeResponseAuthentication no\n' + index = lines.index('UsePAM yes\n') + lines[index] = 'UsePAM no\n' + with open(configpath, 'w') as outfile: + outfile.write(''.join(lines)) + print('SSH config updated successfully!') + + +def check_mac_ssh() -> None: + """Make sure ssh password access is turned off. + + (This totally doesn't belong here, but I use it it to remind myself to + fix mac ssh after system updates which blow away ssh customizations). + """ + with open('/etc/ssh/sshd_config') as infile: + lines = infile.read().splitlines() + if ('UsePAM yes' in lines or '#PasswordAuthentication yes' in lines + or '#ChallengeResponseAuthentication yes' in lines): + print('ERROR: ssh config is allowing password access.\n' + 'To fix: sudo tools/snippets fix_mac_ssh') + sys.exit(255) + print('password ssh auth seems disabled; hooray!') + + +def resize_image() -> None: + """Resize an image and save it to a new location. + + args: xres, yres, src, dst + """ + import os + import efrotools + if len(sys.argv) != 6: + raise Exception('expected 5 args') + width = int(sys.argv[2]) + height = int(sys.argv[3]) + src = sys.argv[4] + dst = sys.argv[5] + if not dst.endswith('.png'): + raise RuntimeError(f'dst must be a png; got "{dst}"') + if not src.endswith('.png'): + raise RuntimeError(f'src must be a png; got "{src}"') + print('Creating: ' + os.path.basename(dst), file=sys.stderr) + efrotools.run(f'convert "{src}" -resize {width}x{height} "{dst}"') + + +def check_clean_safety() -> None: + """Ensure all files are are added to git or in gitignore. + + Use to avoid losing work if we accidentally do a clean without + adding something. + """ + import os + from efrotools.snippets import check_clean_safety as std_snippet + + # First do standard checks. + std_snippet() + + # Then also make sure there are no untracked changes to core files + # (since we may be blowing core away here). + spinoff_bin = os.path.join(str(PROJROOT), 'tools', 'spinoff') + if os.path.exists(spinoff_bin): + status = os.system(spinoff_bin + ' cleancheck') + if status != 0: + sys.exit(255) + + +def archive_old_builds() -> None: + """Stuff our old public builds into the 'old' dir. + + (called after we push newer ones) + """ + import batools.build + if len(sys.argv) < 3: + raise Exception('invalid arguments') + ssh_server = sys.argv[2] + builds_dir = sys.argv[3] + ssh_args = sys.argv[4:] + batools.build.archive_old_builds(ssh_server, builds_dir, ssh_args) + + +def lazy_increment_build() -> None: + """Increment build number only if C++ sources have changed. + + This is convenient to place in automatic commit/push scripts. + It could make sense to auto update build number when scripts/assets + change too, but a build number change requires rebuilding all binaries + so I'll leave that as an explicit choice to save work. + """ + import os + import subprocess + from efro.terminal import Clr + from efro.error import CleanError + from efrotools import get_files_hash + from efrotools.code import get_code_filenames + if sys.argv[2:] not in [[], ['--update-hash-only']]: + raise CleanError('Invalid arguments') + update_hash_only = '--update-hash-only' in sys.argv + codefiles = get_code_filenames(PROJROOT) + codehash = get_files_hash(codefiles) + hashfilename = '.cache/lazy_increment_build' + try: + with open(hashfilename) as infile: + lasthash = infile.read() + except FileNotFoundError: + lasthash = '' + if codehash != lasthash: + print(f'{Clr.SMAG}Source(s) changed; incrementing build...{Clr.RST}') + + if not update_hash_only: + # Just go ahead and bless; this will increment the build as needed. + # subprocess.run(['make', 'bless'], check=True) + subprocess.run(['tools/version_utils', 'incrementbuild'], + check=True) + + # We probably just changed code, so we need to re-calc the hash. + codehash = get_files_hash(codefiles) + os.makedirs(os.path.dirname(hashfilename), exist_ok=True) + with open(hashfilename, 'w') as outfile: + outfile.write(codehash) + + +def get_master_asset_src_dir() -> None: + """Print master-asset-source dir for this repo.""" + import subprocess + + # Ok, for now lets simply use our hard-coded master-src + # path if we're on master in and not otherwise. Should + # probably make this configurable. + output = subprocess.check_output( + ['git', 'status', '--branch', '--porcelain']).decode() + + # Also compare repo name to split version of itself to + # see if we're outside of core (filtering will cause mismatch if so). + if ('origin/master' in output.splitlines()[0] + and 'ballistica' + 'core' == 'ballisticacore'): + + # We seem to be in master in core repo; lets do it. + print('/Users/ericf/Dropbox/ballisticacore_master_assets') + else: + # Still need to supply dummy path for makefile if not.. + print('/__DUMMY_MASTER_SRC_DISABLED_PATH__') + + +def androidaddr() -> None: + """Return the source file location for an android program-counter. + + command line args: archive_dir architecture addr + """ + import batools.android + from efro.error import CleanError + if len(sys.argv) != 5: + raise CleanError(f'ERROR: expected 3 args; got {len(sys.argv) - 2}\n' + f'Usage: "tools/snippets android_addr' + f' "') + archive_dir = sys.argv[2] + arch = sys.argv[3] + addr = sys.argv[4] + batools.android.androidaddr(archive_dir=archive_dir, arch=arch, addr=addr) + + +def push_ipa() -> None: + """Construct and push ios IPA for testing.""" + from pathlib import Path + import efrotools.ios + root = Path(sys.argv[0], '../..').resolve() + if len(sys.argv) != 3: + raise Exception('expected 1 arg (debug or release)') + modename = sys.argv[2] + efrotools.ios.push_ipa(root, modename) + + +def printcolors() -> None: + """Print all colors available in efro.terminals.TerminalColor.""" + from efro.error import CleanError + from efro.terminal import TerminalColor, Clr + + if Clr.RED == '': + raise CleanError('Efro color terminal output is disabled.') + + clrnames = {getattr(Clr, s): s for s in dir(Clr) if s.isupper()} + + # Print everything in Clr (since that's what users should be using + # but do it in the order of TerminalColor (since Clr is just a class + # so is unordered) + for value in TerminalColor: + if value is TerminalColor.RESET: + continue + shortname = f'Clr.{clrnames[value.value]}' + longname = f'({value.name})' + print(f'{shortname:<12} {longname:<20} {value.value}' + f'The quick brown fox jumps over the lazy dog.' + f'{TerminalColor.RESET.value}') + + +def gen_fulltest_buildfile_android() -> None: + """Generate fulltest command list for jenkins. + + (so we see nice pretty split-up build trees) + """ + import batools.build + batools.build.gen_fulltest_buildfile_android() + + +def gen_fulltest_buildfile_windows() -> None: + """Generate fulltest command list for jenkins. + + (so we see nice pretty split-up build trees) + """ + import batools.build + batools.build.gen_fulltest_buildfile_windows() + + +def gen_fulltest_buildfile_apple() -> None: + """Generate fulltest command list for jenkins. + + (so we see nice pretty split-up build trees) + """ + import batools.build + batools.build.gen_fulltest_buildfile_apple() + + +def gen_fulltest_buildfile_linux() -> None: + """Generate fulltest command list for jenkins. + + (so we see nice pretty split-up build trees) + """ + import batools.build + batools.build.gen_fulltest_buildfile_linux() + + +def python_build_apple() -> None: + """Build an embeddable python for mac/ios/tvos.""" + _python_build_apple(debug=False) + + +def python_build_apple_debug() -> None: + """Build embeddable python for mac/ios/tvos (dbg ver).""" + _python_build_apple(debug=True) + + +def _python_build_apple(debug: bool) -> None: + """Build an embeddable python for macOS/iOS/tvOS.""" + import os + from efrotools import pybuild + os.chdir(PROJROOT) + archs = ('mac', 'ios', 'tvos') + if len(sys.argv) != 3: + print('ERROR: expected one arg: ' + ', '.join(archs)) + sys.exit(255) + arch = sys.argv[2] + if arch not in archs: + print('ERROR: invalid arch. valid values are: ' + ', '.join(archs)) + sys.exit(255) + pybuild.build_apple(arch, debug=debug) + + +def python_build_android() -> None: + """Build an embeddable Python lib for Android.""" + _python_build_android(debug=False) + + +def python_build_android_debug() -> None: + """Build embeddable Android Python lib (debug ver).""" + _python_build_android(debug=True) + + +def _python_build_android(debug: bool) -> None: + import os + from efrotools import pybuild + os.chdir(PROJROOT) + archs = ('arm', 'arm64', 'x86', 'x86_64') + if len(sys.argv) != 3: + print('ERROR: expected one arg: ' + ', '.join(archs)) + sys.exit(255) + arch = sys.argv[2] + if arch not in archs: + print('ERROR: invalid arch. valid values are: ' + ', '.join(archs)) + sys.exit(255) + pybuild.build_android(str(PROJROOT), arch, debug=debug) + + +def python_android_patch() -> None: + """Patches Python to prep for building for Android.""" + import os + from efrotools import pybuild + os.chdir(sys.argv[2]) + pybuild.android_patch() + + +def python_gather() -> None: + """Gather build python components into the project. + + This assumes all embeddable py builds have been run successfully. + """ + import os + from efrotools import pybuild + os.chdir(PROJROOT) + pybuild.gather() + + +def capitalize() -> None: + """Print args capitalized.""" + print(' '.join(w.capitalize() for w in sys.argv[2:])) + + +def efrocache_update() -> None: + """Build & push files to efrocache for public access.""" + from efrotools.efrocache import update_cache + makefile_dirs = ['', 'assets'] + update_cache(makefile_dirs) + + +def efrocache_get() -> None: + """Get a file from efrocache.""" + from efrotools.efrocache import get_target + if len(sys.argv) != 3: + raise RuntimeError('Expected exactly 1 arg') + get_target(sys.argv[2]) + + +def get_modern_make() -> None: + """Print name of a modern make command.""" + import platform + import subprocess + + # Mac gnu make is outdated (due to newer versions using GPL3 I believe). + # so let's return 'gmake' there which will point to homebrew make which + # should be up to date. + if platform.system() == 'Darwin': + if subprocess.run(['which', 'gmake'], check=False, + capture_output=True).returncode != 0: + print( + 'WARNING: this requires gmake (mac system make is too old).' + " Install it with 'brew install make'", + file=sys.stderr, + flush=True) + print('gmake') + else: + print('make') + + +def warm_start_asset_build() -> None: + """Prep asset builds to run faster.""" + import os + import subprocess + from pathlib import Path + from efrotools import getconfig + public: bool = getconfig(PROJROOT)['public'] + + if public: + from efrotools.efrocache import warm_start_cache + os.chdir(PROJROOT) + warm_start_cache() + else: + # For internal builds we don't use efrocache but we do use an + # internal build cache. Download an initial cache/etc. if need be. + subprocess.run( + [str(Path(PROJROOT, 'tools/convert_util')), '--init-asset-cache'], + check=True) + + +def update_docs_md() -> None: + """Updates docs markdown files if necessary.""" + import batools.build + batools.build.update_docs_md(check='--check' in sys.argv) + + +def list_pip_reqs() -> None: + """List Python Pip packages needed for this project.""" + from batools.build import get_pip_reqs + print(' '.join(get_pip_reqs())) + + +def install_pip_reqs() -> None: + """Install Python Pip packages needed for this project.""" + import subprocess + from efrotools import PYTHON_BIN + from efro.terminal import Clr + from batools.build import get_pip_reqs + subprocess.run([PYTHON_BIN, '-m', 'pip', 'install', '--upgrade'] + + get_pip_reqs(), + check=True) + print(f'{Clr.GRN}All pip requirements installed!{Clr.RST}') + + +def checkenv() -> None: + """Check for tools necessary to build and run the app.""" + import batools.build + from efro.error import CleanError + try: + batools.build.checkenv() + except RuntimeError as exc: + raise CleanError(exc) + + +def ensure_prefab_platform() -> None: + """Ensure we are running on a particular prefab platform.""" + import batools.build + from efro.error import CleanError + if len(sys.argv) != 3: + raise CleanError('Expected 1 platform name arg.') + needed = sys.argv[2] + current = batools.build.get_current_prefab_platform() + if current != needed: + raise CleanError( + f'Incorrect platform: we are {current}, this requires {needed}.') + + +def prefab_run_var() -> None: + """Print a var for running a prefab run for the current platform. + + We use this mechanism instead of just having a command recursively run + a make target so that ctrl-c can be handled cleanly and directly by the + command getting run instead of generating extra errors in the recursive + processes. + """ + import batools.build + if len(sys.argv) != 3: + raise RuntimeError('Expected 1 arg.') + base = sys.argv[2].replace('-', '_').upper() + platform = batools.build.get_current_prefab_platform().upper() + print(f'RUN_PREFAB_{platform}_{base}', end='') + + +def make_prefab() -> None: + """Run prefab builds for the current platform.""" + import subprocess + import batools.build + if len(sys.argv) != 3: + raise RuntimeError('Expected one argument') + target = batools.build.PrefabTarget(sys.argv[2]) + platform = batools.build.get_current_prefab_platform() + try: + subprocess.run(['make', f'prefab-{platform}-{target.value}-build'], + check=True) + except (Exception, KeyboardInterrupt) as exc: + if str(exc): + print(f'make_prefab failed with error: {exc}') + sys.exit(-1) + + +def update_makebob() -> None: + """Build fresh make_bob binaries for all relevant platforms.""" + import batools.build + batools.build.update_makebob() + + +def lazybuild() -> None: + """Run a build command only if an input has changed.""" + import subprocess + import batools.build + from efro.error import CleanError + if len(sys.argv) < 5: + raise CleanError('Expected at least 3 args') + try: + category = batools.build.SourceCategory(sys.argv[2]) + except ValueError as exc: + raise CleanError(exc) + target = sys.argv[3] + command = ' '.join(sys.argv[4:]) + try: + batools.build.lazybuild(target, category, command) + except subprocess.CalledProcessError as exc: + raise CleanError(exc) diff --git a/tools/snippets b/tools/snippets index 25bb7722..7a5d17eb 100755 --- a/tools/snippets +++ b/tools/snippets @@ -32,10 +32,10 @@ from __future__ import annotations # Note: import as little as possible here at the module level to # keep launch times fast for small snippets. -import sys from typing import TYPE_CHECKING -# Pull in some standard snippets we want to expose. +# Pull in the snippets we want to expose. Its more efficient to define them in +# modules rather than inline here because we'll be able to load them via pyc. # pylint: disable=unused-import from efrotools.snippets import ( PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile, @@ -43,554 +43,22 @@ from efrotools.snippets import ( sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, makefile_target_list, spelling, spelling_all, pytest, echo, compile_python_files) +from batools.snippets import ( + stage_server_file, py_examine, fix_mac_ssh, check_mac_ssh, resize_image, + check_clean_safety, clean_orphaned_assets, archive_old_builds, + lazy_increment_build, get_master_asset_src_dir, androidaddr, push_ipa, + printcolors, gen_fulltest_buildfile_android, + gen_fulltest_buildfile_windows, gen_fulltest_buildfile_apple, + gen_fulltest_buildfile_linux, python_build_apple, python_build_apple_debug, + python_build_android, python_build_android_debug, python_android_patch, + python_gather, capitalize, efrocache_update, efrocache_get, + get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, + install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, + make_prefab, update_makebob, lazybuild) # pylint: enable=unused-import if TYPE_CHECKING: - from typing import Optional - - -def archive_old_builds() -> None: - """Stuff our old public builds into the 'old' dir. - - (called after we push newer ones) - """ - import batools.build - if len(sys.argv) < 3: - raise Exception('invalid arguments') - ssh_server = sys.argv[2] - builds_dir = sys.argv[3] - ssh_args = sys.argv[4:] - batools.build.archive_old_builds(ssh_server, builds_dir, ssh_args) - - -def gen_fulltest_buildfile_android() -> None: - """Generate fulltest command list for jenkins. - - (so we see nice pretty split-up build trees) - """ - import batools.build - batools.build.gen_fulltest_buildfile_android() - - -def gen_fulltest_buildfile_windows() -> None: - """Generate fulltest command list for jenkins. - - (so we see nice pretty split-up build trees) - """ - import batools.build - batools.build.gen_fulltest_buildfile_windows() - - -def gen_fulltest_buildfile_apple() -> None: - """Generate fulltest command list for jenkins. - - (so we see nice pretty split-up build trees) - """ - import batools.build - batools.build.gen_fulltest_buildfile_apple() - - -def gen_fulltest_buildfile_linux() -> None: - """Generate fulltest command list for jenkins. - - (so we see nice pretty split-up build trees) - """ - import batools.build - batools.build.gen_fulltest_buildfile_linux() - - -def resize_image() -> None: - """Resize an image and save it to a new location. - - args: xres, yres, src, dst - """ - import os - import efrotools - if len(sys.argv) != 6: - raise Exception('expected 5 args') - width = int(sys.argv[2]) - height = int(sys.argv[3]) - src = sys.argv[4] - dst = sys.argv[5] - if not dst.endswith('.png'): - raise RuntimeError(f'dst must be a png; got "{dst}"') - if not src.endswith('.png'): - raise RuntimeError(f'src must be a png; got "{src}"') - print('Creating: ' + os.path.basename(dst), file=sys.stderr) - efrotools.run(f'convert "{src}" -resize {width}x{height} "{dst}"') - - -def check_clean_safety() -> None: - """Ensure all files are are added to git or in gitignore. - - Use to avoid losing work if we accidentally do a clean without - adding something. - """ - import os - from efrotools.snippets import check_clean_safety as std_snippet - - # First do standard checks. - std_snippet() - - # Then also make sure there are no untracked changes to core files - # (since we may be blowing core away here). - spinoff_bin = os.path.join(str(PROJROOT), 'tools', 'spinoff') - if os.path.exists(spinoff_bin): - status = os.system(spinoff_bin + ' cleancheck') - if status != 0: - sys.exit(255) - - -def get_master_asset_src_dir() -> None: - """Print master-asset-source dir for this repo.""" - import subprocess - - # Ok, for now lets simply use our hard-coded master-src - # path if we're on master in and not otherwise. Should - # probably make this configurable. - output = subprocess.check_output( - ['git', 'status', '--branch', '--porcelain']).decode() - - # Also compare repo name to split version of itself to - # see if we're outside of core (filtering will cause mismatch if so). - if ('origin/master' in output.splitlines()[0] - and 'ballistica' + 'core' == 'ballisticacore'): - - # We seem to be in master in core repo; lets do it. - print('/Users/ericf/Dropbox/ballisticacore_master_assets') - else: - # Still need to supply dummy path for makefile if not.. - print('/__DUMMY_MASTER_SRC_DISABLED_PATH__') - - -def androidaddr() -> None: - """Return the source file location for an android program-counter. - - command line args: archive_dir architecture addr - """ - import batools.android - from efro.error import CleanError - if len(sys.argv) != 5: - raise CleanError(f'ERROR: expected 3 args; got {len(sys.argv) - 2}\n' - f'Usage: "tools/snippets android_addr' - f' "') - archive_dir = sys.argv[2] - arch = sys.argv[3] - addr = sys.argv[4] - batools.android.androidaddr(archive_dir=archive_dir, arch=arch, addr=addr) - - -def python_build_apple() -> None: - """Build an embeddable python for mac/ios/tvos.""" - _python_build_apple(debug=False) - - -def python_build_apple_debug() -> None: - """Build embeddable python for mac/ios/tvos (dbg ver).""" - _python_build_apple(debug=True) - - -def _python_build_apple(debug: bool) -> None: - """Build an embeddable python for macOS/iOS/tvOS.""" - import os - from efrotools import pybuild - os.chdir(PROJROOT) - archs = ('mac', 'ios', 'tvos') - if len(sys.argv) != 3: - print('ERROR: expected one arg: ' + ', '.join(archs)) - sys.exit(255) - arch = sys.argv[2] - if arch not in archs: - print('ERROR: invalid arch. valid values are: ' + ', '.join(archs)) - sys.exit(255) - pybuild.build_apple(arch, debug=debug) - - -def python_build_android() -> None: - """Build an embeddable Python lib for Android.""" - _python_build_android(debug=False) - - -def python_build_android_debug() -> None: - """Build embeddable Android Python lib (debug ver).""" - _python_build_android(debug=True) - - -def _python_build_android(debug: bool) -> None: - import os - from efrotools import pybuild - os.chdir(PROJROOT) - archs = ('arm', 'arm64', 'x86', 'x86_64') - if len(sys.argv) != 3: - print('ERROR: expected one arg: ' + ', '.join(archs)) - sys.exit(255) - arch = sys.argv[2] - if arch not in archs: - print('ERROR: invalid arch. valid values are: ' + ', '.join(archs)) - sys.exit(255) - pybuild.build_android(str(PROJROOT), arch, debug=debug) - - -def python_android_patch() -> None: - """Patches Python to prep for building for Android.""" - import os - from efrotools import pybuild - os.chdir(sys.argv[2]) - pybuild.android_patch() - - -def python_gather() -> None: - """Gather build python components into the project. - - This assumes all embeddable py builds have been run successfully. - """ - import os - from efrotools import pybuild - os.chdir(PROJROOT) - pybuild.gather() - - -def clean_orphaned_assets() -> None: - """Remove asset files that are no longer part of the build.""" - import os - import json - import efrotools - - # Operate from dist root.. - os.chdir(PROJROOT) - - # Our manifest is split into 2 files (public and private) - with open('assets/.asset_manifest_public.json') as infile: - manifest = set(json.loads(infile.read())) - with open('assets/.asset_manifest_private.json') as infile: - manifest.update(set(json.loads(infile.read()))) - for root, _dirs, fnames in os.walk('assets/build'): - for fname in fnames: - fpath = os.path.join(root, fname) - fpathrel = fpath[13:] # paths are relative to assets/build - if fpathrel not in manifest: - print(f'Removing orphaned asset file: {fpath}') - os.unlink(fpath) - - # Lastly, clear empty dirs. - efrotools.run('find assets/build -depth -empty -type d -delete') - - -def py_examine() -> None: - """Run a python examination at a given point in a given file.""" - import os - from pathlib import Path - import efrotools - if len(sys.argv) != 7: - print('ERROR: expected 7 args') - sys.exit(255) - filename = Path(sys.argv[2]) - line = int(sys.argv[3]) - column = int(sys.argv[4]) - selection: Optional[str] = (None if sys.argv[5] == '' else sys.argv[5]) - operation = sys.argv[6] - - # This stuff assumes it is being run from project root. - os.chdir(PROJROOT) - - # Set up pypaths so our main distro stuff works. - scriptsdir = os.path.abspath( - os.path.join(os.path.dirname(sys.argv[0]), - '../assets/src/ba_data/python')) - toolsdir = os.path.abspath( - os.path.join(os.path.dirname(sys.argv[0]), '../tools')) - if scriptsdir not in sys.path: - sys.path.append(scriptsdir) - if toolsdir not in sys.path: - sys.path.append(toolsdir) - efrotools.py_examine(PROJROOT, filename, line, column, selection, - operation) - - -def push_ipa() -> None: - """Construct and push ios IPA for testing.""" - from pathlib import Path - import efrotools.ios - root = Path(sys.argv[0], '../..').resolve() - if len(sys.argv) != 3: - raise Exception('expected 1 arg (debug or release)') - modename = sys.argv[2] - efrotools.ios.push_ipa(root, modename) - - -def fix_mac_ssh() -> None: - """Turn off mac ssh password access. - - (This totally doesn't belong in this project btw..) - """ - configpath = '/etc/ssh/sshd_config' - with open(configpath) as infile: - lines = infile.readlines() - index = lines.index('#PasswordAuthentication yes\n') - lines[index] = 'PasswordAuthentication no\n' - index = lines.index('#ChallengeResponseAuthentication yes\n') - lines[index] = 'ChallengeResponseAuthentication no\n' - index = lines.index('UsePAM yes\n') - lines[index] = 'UsePAM no\n' - with open(configpath, 'w') as outfile: - outfile.write(''.join(lines)) - print('SSH config updated successfully!') - - -def check_mac_ssh() -> None: - """Make sure ssh password access is turned off. - - (This totally doesn't belong here, but I use it it to remind myself to - fix mac ssh after system updates which blow away ssh customizations). - """ - with open('/etc/ssh/sshd_config') as infile: - lines = infile.read().splitlines() - if ('UsePAM yes' in lines or '#PasswordAuthentication yes' in lines - or '#ChallengeResponseAuthentication yes' in lines): - print('ERROR: ssh config is allowing password access.\n' - 'To fix: sudo tools/snippets fix_mac_ssh') - sys.exit(255) - print('password ssh auth seems disabled; hooray!') - - -def capitalize() -> None: - """Print args capitalized.""" - print(' '.join(w.capitalize() for w in sys.argv[2:])) - - -def efrocache_update() -> None: - """Build & push files to efrocache for public access.""" - from efrotools.efrocache import update_cache - makefile_dirs = ['', 'assets'] - update_cache(makefile_dirs) - - -def efrocache_get() -> None: - """Get a file from efrocache.""" - from efrotools.efrocache import get_target - if len(sys.argv) != 3: - raise RuntimeError('Expected exactly 1 arg') - get_target(sys.argv[2]) - - -def get_modern_make() -> None: - """Print name of a modern make command.""" - import platform - import subprocess - - # Mac gnu make is outdated (due to newer versions using GPL3 I believe). - # so let's return 'gmake' there which will point to homebrew make which - # should be up to date. - if platform.system() == 'Darwin': - if subprocess.run(['which', 'gmake'], check=False, - capture_output=True).returncode != 0: - print( - 'WARNING: this requires gmake (mac system make is too old).' - " Install it with 'brew install make'", - file=sys.stderr, - flush=True) - print('gmake') - else: - print('make') - - -def warm_start_asset_build() -> None: - """Prep asset builds to run faster.""" - import os - import subprocess - from pathlib import Path - from efrotools import getconfig - public: bool = getconfig(PROJROOT)['public'] - - if public: - from efrotools.efrocache import warm_start_cache - os.chdir(PROJROOT) - warm_start_cache() - else: - # For internal builds we don't use efrocache but we do use an - # internal build cache. Download an initial cache/etc. if need be. - subprocess.run( - [str(Path(PROJROOT, 'tools/convert_util')), '--init-asset-cache'], - check=True) - - -def update_docs_md() -> None: - """Updates docs markdown files if necessary.""" - import batools.build - batools.build.update_docs_md(check='--check' in sys.argv) - - -def list_pip_reqs() -> None: - """List Python Pip packages needed for this project.""" - from batools.build import get_pip_reqs - print(' '.join(get_pip_reqs())) - - -def install_pip_reqs() -> None: - """Install Python Pip packages needed for this project.""" - import subprocess - from efrotools import PYTHON_BIN - from efro.terminal import Clr - from batools.build import get_pip_reqs - subprocess.run([PYTHON_BIN, '-m', 'pip', 'install', '--upgrade'] + - get_pip_reqs(), - check=True) - print(f'{Clr.GRN}All pip requirements installed!{Clr.RST}') - - -def checkenv() -> None: - """Check for tools necessary to build and run the app.""" - import batools.build - from efro.error import CleanError - try: - batools.build.checkenv() - except RuntimeError as exc: - raise CleanError(exc) - - -def ensure_prefab_platform() -> None: - """Ensure we are running on a particular prefab platform.""" - import batools.build - from efro.error import CleanError - if len(sys.argv) != 3: - raise CleanError('Expected 1 platform name arg.') - needed = sys.argv[2] - current = batools.build.get_current_prefab_platform() - if current != needed: - raise CleanError( - f'Incorrect platform: we are {current}, this requires {needed}.') - - -def prefab_run_var() -> None: - """Print a var for running a prefab run for the current platform. - - We use this mechanism instead of just having a command recursively run - a make target so that ctrl-c can be handled cleanly and directly by the - command getting run instead of generating extra errors in the recursive - processes. - """ - import batools.build - if len(sys.argv) != 3: - raise RuntimeError('Expected 1 arg.') - base = sys.argv[2].replace('-', '_').upper() - platform = batools.build.get_current_prefab_platform().upper() - print(f'RUN_PREFAB_{platform}_{base}', end='') - - -def make_prefab() -> None: - """Run prefab builds for the current platform.""" - import subprocess - import batools.build - if len(sys.argv) != 3: - raise RuntimeError('Expected one argument') - target = batools.build.PrefabTarget(sys.argv[2]) - platform = batools.build.get_current_prefab_platform() - try: - subprocess.run(['make', f'prefab-{platform}-{target.value}-build'], - check=True) - except (Exception, KeyboardInterrupt) as exc: - if str(exc): - print(f'make_prefab failed with error: {exc}') - sys.exit(-1) - - -def update_makebob() -> None: - """Build fresh make_bob binaries for all relevant platforms.""" - import batools.build - batools.build.update_makebob() - - -def lazybuild() -> None: - """Run a build command only if an input has changed.""" - import subprocess - import batools.build - from efro.error import CleanError - if len(sys.argv) < 5: - raise CleanError('Expected at least 3 args') - try: - category = batools.build.SourceCategory(sys.argv[2]) - except ValueError as exc: - raise CleanError(exc) - target = sys.argv[3] - command = ' '.join(sys.argv[4:]) - try: - batools.build.lazybuild(target, category, command) - except subprocess.CalledProcessError as exc: - raise CleanError(exc) - - -def filter_server_config() -> None: - """Add commented-out config options to a server config.""" - import batools.build - from efro.error import CleanError - if len(sys.argv) != 4: - raise CleanError('Expected 2 args (infile and outfile).') - batools.build.filter_server_config(str(PROJROOT), sys.argv[2], sys.argv[3]) - - -def printcolors() -> None: - """Print all colors available in efro.terminals.TerminalColor.""" - from efro.error import CleanError - from efro.terminal import TerminalColor, Clr - - if Clr.RED == '': - raise CleanError('Efro color terminal output is disabled.') - - clrnames = {getattr(Clr, s): s for s in dir(Clr) if s.isupper()} - - # Print everything in Clr (since that's what users should be using - # but do it in the order of TerminalColor (since Clr is just a class - # so is unordered) - for value in TerminalColor: - if value is TerminalColor.RESET: - continue - shortname = f'Clr.{clrnames[value.value]}' - longname = f'({value.name})' - print(f'{shortname:<12} {longname:<20} {value.value}' - f'The quick brown fox jumps over the lazy dog.' - f'{TerminalColor.RESET.value}') - - -def lazy_increment_build() -> None: - """Increment build number only if C++ sources have changed. - - This is convenient to place in automatic commit/push scripts. - It could make sense to auto update build number when scripts/assets - change too, but a build number change requires rebuilding all binaries - so I'll leave that as an explicit choice to save work. - """ - import os - import subprocess - from efro.terminal import Clr - from efro.error import CleanError - from efrotools import get_files_hash - from efrotools.code import get_code_filenames - if sys.argv[2:] not in [[], ['--update-hash-only']]: - raise CleanError('Invalid arguments') - update_hash_only = '--update-hash-only' in sys.argv - codefiles = get_code_filenames(PROJROOT) - codehash = get_files_hash(codefiles) - hashfilename = '.cache/lazy_increment_build' - try: - with open(hashfilename) as infile: - lasthash = infile.read() - except FileNotFoundError: - lasthash = '' - if codehash != lasthash: - print(f'{Clr.SMAG}Source(s) changed; incrementing build...{Clr.RST}') - - if not update_hash_only: - # Just go ahead and bless; this will increment the build as needed. - # subprocess.run(['make', 'bless'], check=True) - subprocess.run(['tools/version_utils', 'incrementbuild'], - check=True) - - # We probably just changed code, so we need to re-calc the hash. - codehash = get_files_hash(codefiles) - os.makedirs(os.path.dirname(hashfilename), exist_ok=True) - with open(hashfilename, 'w') as outfile: - outfile.write(codehash) - + pass if __name__ == '__main__': snippets_main(globals()) From baac8eb48946c9d5c47f1035947f24ee8c9f9c07 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 17 Jun 2020 21:40:24 -0700 Subject: [PATCH 103/417] Fix for potential crash in local network browser. --- .efrocachemap | 24 ++++++++++---------- CHANGELOG.md | 1 + assets/src/ba_data/python/bastd/ui/gather.py | 4 +++- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e76d1774..e1cbe804 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/fc/3d/ab2ccd1f76fec48d1d1f8cc07aa4", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e2/e1/672e2ccaceadf3b0867bf3b887a4", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5f/9d/90533da6e9d91dc6b932a2aa7f43", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/30/ea/6af215aa0cab66e46c7041a7b091", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/55/66/b8bc31f6818606e282eda887939f", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/52/e7/2419b41d3524735dc709338c4290", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/11/b5/5ee7f3ba18e2683d56b8a020b39f", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/24/5f/6953fd0f2b47e943ea734bc14911", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1b/fb/739c5d5dc13218efdeaaa020c9f9", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/15/75f7b94e3608435a4609a3992dbc", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9f/9d/cf77bfbd79aed7178d9674b3af14", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c9/b2/6863b197eac679f85a5414525aa9" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/79/8482459e849c4b75b16bb100266f", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/9c/ec1fbb2000b98ee3f435e5c513fe", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/76/5b/db956e121da63577f936e64f3494", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/3b/a57f68ff20e2b609e9e5206b95a5", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/e3/50b8b93f13e62224361adc25d349", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d1/1e/0a2b25787b8b8fb22bc98fd01deb", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cb/bb/283f8b7e32c525a18d8ff352a909", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cf/53/a41d9c765398f15c9e12fb09f901", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dc/ed/d8ede234c0a7088a4779034a0546", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/93/bcebb3578733d2d6cad663493221", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2c/15/5b57e11da90398f11e8e7c72a7ca", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/37/a4/7a81bd34c99b3f43e2e528dd28b9" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index e03e1290..cd613e6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - Mouse wheel now works in manual camera mode on more platforms. - Lots of internal event-handling cleanup/reorganization in preparation for Android 1.5 update. - Server scripts now run in opt mode in release builds so they can use bundled .opt-1.pyc files. +- Fixes a potential crash in the local network browser. - More misc bug fixes and tidying. ### 1.5.5 (20069) diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index fecf8f6e..2fdc1e18 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1721,7 +1721,9 @@ class GatherWindow(ba.Window): import errno # Ignore harmless errors. - if exc.errno == errno.EHOSTUNREACH: + if exc.errno in { + errno.EHOSTUNREACH, errno.ENETUNREACH + }: pass elif exc.errno == 10051: # Windows 'a socket operation was attempted From 113175218569626920ae4621a07355c0ddcfc489 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 17 Jun 2020 22:18:46 -0700 Subject: [PATCH 104/417] Fixed main menu return location (Issue #59) --- assets/src/ba_data/python/ba/_app.py | 7 +++++-- assets/src/ba_data/python/bastd/ui/mainmenu.py | 2 +- docs/ba_module.md | 4 ++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 9232a9ee..abe571f2 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -661,13 +661,16 @@ class App: # FIXME: This should not be an actor attr. activity.paused_text = None - def return_to_main_menu_session_gracefully(self) -> None: + def return_to_main_menu_session_gracefully(self, + reset_ui: bool = True) -> None: """Attempt to cleanly get back to the main menu.""" # pylint: disable=cyclic-import from ba import _benchmark from ba._general import Call from bastd.mainmenu import MainMenuSession - _ba.app.main_window = None + if reset_ui: + _ba.app.main_window = None + if isinstance(_ba.get_foreground_host_session(), MainMenuSession): # It may be possible we're on the main menu but the screen is faded # so fade back in. diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 113f86b7..95a3135c 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -874,7 +874,7 @@ class MainMenuWindow(ba.Window): if not self._root_widget: return ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.return_to_main_menu_session_gracefully() + ba.app.return_to_main_menu_session_gracefully(reset_ui=False) def _leave(self) -> None: if self._input_player: diff --git a/docs/ba_module.md b/docs/ba_module.md index ea3a1495..0f85eb2b 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-16 for Ballistica version 1.5.5 build 20071

    +

    last updated on 2020-06-17 for Ballistica version 1.5.6 build 20074

    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!


    @@ -990,7 +990,7 @@ to resume.

    return_to_main_menu_session_gracefully()

    -

    return_to_main_menu_session_gracefully(self) -> None

    +

    return_to_main_menu_session_gracefully(self, reset_ui: bool = True) -> None

    Attempt to cleanly get back to the main menu.

    From 334ac7aa5ea514b7b1c5992d289840d020f35f07 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 18 Jun 2020 02:41:25 -0700 Subject: [PATCH 105/417] Build system fix for WSL2 --- .efrocachemap | 24 ++++++++++++------------ tools/batools/build.py | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e1cbe804..06d8caf4 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/38/79/8482459e849c4b75b16bb100266f", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/9c/ec1fbb2000b98ee3f435e5c513fe", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/76/5b/db956e121da63577f936e64f3494", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/3b/a57f68ff20e2b609e9e5206b95a5", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/e3/50b8b93f13e62224361adc25d349", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d1/1e/0a2b25787b8b8fb22bc98fd01deb", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cb/bb/283f8b7e32c525a18d8ff352a909", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cf/53/a41d9c765398f15c9e12fb09f901", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dc/ed/d8ede234c0a7088a4779034a0546", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/93/bcebb3578733d2d6cad663493221", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2c/15/5b57e11da90398f11e8e7c72a7ca", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/37/a4/7a81bd34c99b3f43e2e528dd28b9" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/31/39/870b3da9d4e8bbb0dde02328cf72", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cc/28/fcf6593ea46a25253121a5c284a1", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/fc/1f85fd832931a4f29e3b7fe64acc", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/02/d4/fc4da9b7b56007556ed7bc7c02d4", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/ab/210ebb40458811c3eacc56c9838d", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/41/8be050199ee9b2bac816482677a6", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/36/14/e1746bb5df2b33edc429028b0536", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d0/67/4965f41035dbce0781cc144f9de3", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/86/75/88694137c6b97bcf467a77850d9a", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/d8/46a5d20ff31bac737441ef3140da", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1e/45/cfabbaf255c6084377381267dd15", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6c/25/473847d1de1bfcbd3781e65732bf" } \ No newline at end of file diff --git a/tools/batools/build.py b/tools/batools/build.py index 0b88edde..ca2abb97 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -465,7 +465,7 @@ def get_current_prefab_platform() -> str: if system == 'Linux': # If it looks like we're in Windows Subsystem for Linux, # go with the Windows version. - if 'microsoft' in platform.uname()[3].lower(): + if 'microsoft' in platform.uname().release.lower(): return 'windows' # We currently only support x86_64 linux. From c5b0d977e3fddd7f0e8e4fa2901710c0f53b96e5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 18 Jun 2020 11:54:53 -0700 Subject: [PATCH 106/417] Made efrocache extraction more robust --- tools/efrotools/efrocache.py | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index 3d037a73..896d9ae4 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -98,7 +98,7 @@ def get_target(path: str) -> None: # download it. if not os.path.exists(local_cache_path): os.makedirs(os.path.dirname(local_cache_path), exist_ok=True) - print(f'Downloading: {Clr.SBLU}{path}{Clr.RST}') + print(f'Downloading: {Clr.BLU}{path}{Clr.RST}') result = subprocess.run( f'curl --fail --silent {url} --output {local_cache_path_dl}', shell=True, @@ -118,8 +118,25 @@ def get_target(path: str) -> None: # Ok we should have a valid .tar.gz file in our cache dir at this point. # Just expand it and it get placed wherever it belongs. + + # Strangely, decompressing lots of these simultaneously leads to occasional + # "File does not exist" errors when running on Windows Subystem for Linux. + # There should be no overlap in files getting written, but perhaps + # something about how tar rebuilds the directory structure causes clashes. + # It seems that just explicitly creating necessary directories first + # prevents the problem. + os.makedirs(os.path.dirname(path), exist_ok=True) + print(f'Extracting: {path}') - run(f'tar -zxf {local_cache_path}') + try: + subprocess.run(['tar', '-zxf', local_cache_path], check=True) + except Exception: + # If something goes wrong, try to make sure we don't leave a half + # decompressed file lying around or whatnot. + print(f"Error expanding cache archive for '{local_cache_path}'.") + if os.path.exists(local_cache_path): + os.remove(local_cache_path) + raise # The file will wind up with the timestamp it was compressed with, # so let's update its timestamp or else it will still be considered From bc22359dcd06b1dea6a1c767ba350783f4fb53f5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 18 Jun 2020 12:41:30 -0700 Subject: [PATCH 107/417] Cleaning up factory classes --- assets/src/ba_data/python/bastd/actor/bomb.py | 14 ++--- assets/src/ba_data/python/bastd/actor/flag.py | 10 +-- assets/src/ba_data/python/bastd/actor/spaz.py | 61 ++++++++----------- .../ba_data/python/bastd/actor/spazfactory.py | 21 ++++++- .../ba_data/python/bastd/game/elimination.py | 4 +- assets/src/ba_data/python/bastd/gameutils.py | 16 +++-- assets/src/ba_data/python/bastd/mainmenu.py | 4 +- tools/efrotools/efrocache.py | 2 +- 8 files changed, 68 insertions(+), 64 deletions(-) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index f5a4b6cd..f5b7743b 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -34,10 +34,6 @@ from bastd.gameutils import SharedObjects if TYPE_CHECKING: from typing import Any, Sequence, Optional, Callable, List, Tuple, Type -# Attr we store these objects as on the current activity. -# (based on our module so hopefully avoids conflicts) -STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_bombfactory' - PlayerType = TypeVar('PlayerType', bound='ba.Player') @@ -150,14 +146,16 @@ class BombFactory: ba.Sound for a rolling bomb. """ - @staticmethod - def get() -> BombFactory: + _STORENAME = ba.storagename() + + @classmethod + def get(cls) -> BombFactory: """Get/create a shared bastd.actor.bomb.BombFactory object.""" activity = ba.getactivity() - factory = getattr(activity, STORAGE_ATTR_NAME, None) + factory = activity.customdata.get(cls._STORENAME) if factory is None: factory = BombFactory() - setattr(activity, STORAGE_ATTR_NAME, factory) + activity.customdata[cls._STORENAME] = factory assert isinstance(factory, BombFactory) return factory diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index b8cad76e..78cfb666 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -59,6 +59,8 @@ class FlagFactory: The ba.Texture for flags. """ + _STORENAME = ba.storagename() + def __init__(self) -> None: """Instantiate a FlagFactory. @@ -123,14 +125,14 @@ class FlagFactory: self.flag_texture = ba.gettexture('flagColor') - @staticmethod - def get() -> FlagFactory: + @classmethod + def get(cls) -> FlagFactory: """Get/create a shared FlagFactory instance.""" activity = ba.getactivity() - factory = getattr(activity, 'shared_flag_factory', None) + factory = activity.customdata.get(cls._STORENAME) if factory is None: factory = FlagFactory() - setattr(activity, 'shared_flag_factory', factory) + activity.customdata[cls._STORENAME] = factory assert isinstance(factory, FlagFactory) return factory diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index 8e13d6a4..2ae01b4b 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -29,6 +29,7 @@ from typing import TYPE_CHECKING import ba from bastd.actor import bomb as stdbomb from bastd.actor.powerupbox import PowerupBoxFactory +from bastd.actor.spazfactory import SpazFactory from bastd.gameutils import SharedObjects if TYPE_CHECKING: @@ -56,18 +57,6 @@ class BombDiedMessage: """A bomb has died and thus can be recycled.""" -def get_factory() -> SpazFactory: - """Return the shared ba.SpazFactory object, creating it if necessary.""" - # pylint: disable=cyclic-import - from bastd.actor.spazfactory import SpazFactory - activity = ba.getactivity() - factory = getattr(activity, 'shared_spaz_factory', None) - if factory is None: - factory = activity.shared_spaz_factory = SpazFactory() # type: ignore - assert isinstance(factory, SpazFactory) - return factory - - class Spaz(ba.Actor): """ Base class for various Spazzes. @@ -112,7 +101,7 @@ class Spaz(ba.Actor): shared = SharedObjects.get() activity = self.activity - factory = get_factory() + factory = SpazFactory.get() # we need to behave slightly different in the tutorial self._demo_mode = demo_mode @@ -466,7 +455,7 @@ class Spaz(ba.Actor): ba.timer( 0.1, ba.WeakCall(self._safe_play_sound, - get_factory().swish_sound, 0.8)) + SpazFactory.get().swish_sound, 0.8)) self._turbo_filter_add_press('punch') def _safe_play_sound(self, sound: ba.Sound, volume: float) -> None: @@ -605,7 +594,7 @@ class Spaz(ba.Actor): he will explode in 5 seconds. """ if not self._cursed: - factory = get_factory() + factory = SpazFactory.get() self._cursed = True # Add the curse material. @@ -637,7 +626,7 @@ class Spaz(ba.Actor): self._punch_power_scale = 1.7 self._punch_cooldown = 300 else: - factory = get_factory() + factory = SpazFactory.get() self._punch_power_scale = factory.punch_power_scale_gloves self._punch_cooldown = factory.punch_cooldown_gloves @@ -650,7 +639,7 @@ class Spaz(ba.Actor): ba.print_error('Can\'t equip shields; no node.') return - factory = get_factory() + factory = SpazFactory.get() if self.shield is None: self.shield = ba.newnode('shield', owner=self.node, @@ -685,7 +674,7 @@ class Spaz(ba.Actor): self.shield = None self.shield_decay_timer = None assert self.node - ba.playsound(get_factory().shield_down_sound, + ba.playsound(SpazFactory.get().shield_down_sound, 1.0, position=self.node.position) else: @@ -802,7 +791,7 @@ class Spaz(ba.Actor): ba.WeakCall(self._gloves_wear_off), timeformat=ba.TimeFormat.MILLISECONDS)) elif msg.poweruptype == 'shield': - factory = get_factory() + factory = SpazFactory.get() # Let's allow powerup-equipped shields to lose hp over time. self.equip_shields(decay=factory.shield_decay_rate > 0) @@ -832,7 +821,7 @@ class Spaz(ba.Actor): self._cursed = False # Remove cursed material. - factory = get_factory() + factory = SpazFactory.get() for attr in ['materials', 'roller_materials']: materials = getattr(self.node, attr) if factory.curse_material in materials: @@ -856,7 +845,7 @@ class Spaz(ba.Actor): if not self.node: return None if self.node.invincible: - ba.playsound(get_factory().block_sound, + ba.playsound(SpazFactory.get().block_sound, 1.0, position=self.node.position) return None @@ -881,7 +870,7 @@ class Spaz(ba.Actor): if not self.node: return None if self.node.invincible: - ba.playsound(get_factory().block_sound, + ba.playsound(SpazFactory.get().block_sound, 1.0, position=self.node.position) return True @@ -924,13 +913,13 @@ class Spaz(ba.Actor): # without damaging the player. # However, massive damage events should still be able to # damage the player. This hopefully gives us a happy medium. - max_spillover = get_factory().max_shield_spillover_damage + max_spillover = SpazFactory.get().max_shield_spillover_damage if self.shield_hitpoints <= 0: # FIXME: Transition out perhaps? self.shield.delete() self.shield = None - ba.playsound(get_factory().shield_down_sound, + ba.playsound(SpazFactory.get().shield_down_sound, 1.0, position=self.node.position) @@ -944,7 +933,7 @@ class Spaz(ba.Actor): chunk_type='spark') else: - ba.playsound(get_factory().shield_hit_sound, + ba.playsound(SpazFactory.get().shield_hit_sound, 0.5, position=self.node.position) @@ -1001,14 +990,14 @@ class Spaz(ba.Actor): # Let's always add in a super-punch sound with boxing # gloves just to differentiate them. if msg.hit_subtype == 'super_punch': - ba.playsound(get_factory().punch_sound_stronger, + ba.playsound(SpazFactory.get().punch_sound_stronger, 1.0, position=self.node.position) if damage > 500: - sounds = get_factory().punch_sound_strong + sounds = SpazFactory.get().punch_sound_strong sound = sounds[random.randrange(len(sounds))] else: - sound = get_factory().punch_sound + sound = SpazFactory.get().punch_sound ba.playsound(sound, 1.0, position=self.node.position) # Throw up some chunks. @@ -1118,7 +1107,7 @@ class Spaz(ba.Actor): elif self.node: self.node.hurt = 1.0 if self.play_big_death_sound and not wasdead: - ba.playsound(get_factory().single_player_death_sound) + ba.playsound(SpazFactory.get().single_player_death_sound) self.node.dead = True ba.timer(2.0, self.node.delete) @@ -1160,7 +1149,7 @@ class Spaz(ba.Actor): # If its something besides another spaz, just do a muffled # punch sound. if node.getnodetype() != 'spaz': - sounds = get_factory().impact_sounds_medium + sounds = SpazFactory.get().impact_sounds_medium sound = sounds[random.randrange(len(sounds))] ba.playsound(sound, 1.0, position=self.node.position) @@ -1347,11 +1336,11 @@ class Spaz(ba.Actor): scale=0.3, spread=0.2, chunk_type='ice') - ba.playsound(get_factory().shatter_sound, + ba.playsound(SpazFactory.get().shatter_sound, 1.0, position=self.node.position) else: - ba.playsound(get_factory().splatter_sound, + ba.playsound(SpazFactory.get().splatter_sound, 1.0, position=self.node.position) self.handlemessage(ba.DieMessage()) @@ -1369,11 +1358,11 @@ class Spaz(ba.Actor): self.node.handlemessage('knockout', max(0.0, 50.0 * intensity)) sounds: Sequence[ba.Sound] if intensity > 5.0: - sounds = get_factory().impact_sounds_harder + sounds = SpazFactory.get().impact_sounds_harder elif intensity > 3.0: - sounds = get_factory().impact_sounds_hard + sounds = SpazFactory.get().impact_sounds_hard else: - sounds = get_factory().impact_sounds_medium + sounds = SpazFactory.get().impact_sounds_medium sound = sounds[random.randrange(len(sounds))] ba.playsound(sound, position=pos, volume=5.0) @@ -1418,7 +1407,7 @@ class Spaz(ba.Actor): self._punch_power_scale = 1.2 self._punch_cooldown = BASE_PUNCH_COOLDOWN else: - factory = get_factory() + factory = SpazFactory.get() self._punch_power_scale = factory.punch_power_scale self._punch_cooldown = factory.punch_cooldown self._has_boxing_gloves = False diff --git a/assets/src/ba_data/python/bastd/actor/spazfactory.py b/assets/src/ba_data/python/bastd/actor/spazfactory.py index 6946088a..346723e2 100644 --- a/assets/src/ba_data/python/bastd/actor/spazfactory.py +++ b/assets/src/ba_data/python/bastd/actor/spazfactory.py @@ -26,8 +26,6 @@ from typing import TYPE_CHECKING import ba from bastd.gameutils import SharedObjects -from bastd.actor.spaz import (PickupMessage, PunchHitMessage, - CurseExplodeMessage) import _ba if TYPE_CHECKING: @@ -97,12 +95,20 @@ class SpazFactory: A ba.Material applied to a cursed ba.Spaz that triggers an explosion. """ + _STORENAME = ba.storagename() + def _preload(self, character: str) -> None: """Preload media needed for a given character.""" self.get_media(character) def __init__(self) -> None: """Instantiate a factory object.""" + # pylint: disable=cyclic-import + # FIXME: should probably put these somewhere common so we don't + # have to import them from a module that imports us. + from bastd.actor.spaz import (PickupMessage, PunchHitMessage, + CurseExplodeMessage) + shared = SharedObjects.get() self.impact_sounds_medium = (ba.getsound('impactMedium'), ba.getsound('impactMedium2')) @@ -265,3 +271,14 @@ class SpazFactory: else: media = self.spaz_media[character] return media + + @classmethod + def get(cls) -> SpazFactory: + """Return the shared ba.SpazFactory, creating it if necessary.""" + # pylint: disable=cyclic-import + activity = ba.getactivity() + factory = activity.customdata.get(cls._STORENAME) + if factory is None: + factory = activity.customdata[cls._STORENAME] = SpazFactory() + assert isinstance(factory, SpazFactory) + return factory diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 14c428fc..63c579ed 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -28,7 +28,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import ba -from bastd.actor.spaz import get_factory +from bastd.actor.spazfactory import SpazFactory from bastd.actor.scoreboard import Scoreboard if TYPE_CHECKING: @@ -525,7 +525,7 @@ class EliminationGame(ba.TeamGameActivity[Player, Team]): # Play big death sound on our last death # or for every one in solo mode. if self._solo_mode or player.lives == 0: - ba.playsound(get_factory().single_player_death_sound) + ba.playsound(SpazFactory.get().single_player_death_sound) # If we hit zero lives, we're dead (and our team might be too). if player.lives == 0: diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py index 4519e988..de34b2bd 100644 --- a/assets/src/ba_data/python/bastd/gameutils.py +++ b/assets/src/ba_data/python/bastd/gameutils.py @@ -29,10 +29,6 @@ import ba if TYPE_CHECKING: from typing import Sequence, Optional -# Attr we store these objects as on the current activity. -# (based on our module so hopefully avoids conflicts) -STORAGE_ATTR_NAME = '_' + __name__.replace('.', '_') + '_sharedobjs' - class SharedObjects: """Various common components for use in games. @@ -44,9 +40,11 @@ class SharedObjects: standard materials. """ + _STORENAME = ba.storagename() + def __init__(self) -> None: activity = ba.getactivity() - if hasattr(activity, STORAGE_ATTR_NAME): + if hasattr(activity, self._STORENAME): raise RuntimeError('Use SharedObjects.get() to fetch the' ' shared instance for this activity.') self._object_material: Optional[ba.Material] = None @@ -58,14 +56,14 @@ class SharedObjects: self._region_material: Optional[ba.Material] = None self._railing_material: Optional[ba.Material] = None - @staticmethod - def get() -> SharedObjects: + @classmethod + def get(cls) -> SharedObjects: """Fetch/create the instance of this class for the current activity.""" activity = ba.getactivity() - shobs = getattr(activity, STORAGE_ATTR_NAME, None) + shobs = activity.customdata.get(cls._STORENAME) if shobs is None: shobs = SharedObjects() - setattr(activity, STORAGE_ATTR_NAME, shobs) + activity.customdata[cls._STORENAME] = shobs assert isinstance(shobs, SharedObjects) return shobs diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index ae792fbb..4be9c553 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -28,7 +28,6 @@ import weakref from typing import TYPE_CHECKING import ba -from bastd.actor import spaz import _ba if TYPE_CHECKING: @@ -886,6 +885,7 @@ def _preload2() -> None: def _preload3() -> None: + from bastd.actor.spazfactory import SpazFactory for mname in ['bomb', 'bombSticky', 'impactBomb']: ba.getmodel(mname) for tname in [ @@ -895,7 +895,7 @@ def _preload3() -> None: ba.gettexture(tname) for sname in ['freeze', 'fuse01', 'activateBeep', 'warnBeep']: ba.getsound(sname) - spaz.get_factory() + SpazFactory.get() ba.timer(0.2, _preload4) diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index 896d9ae4..d6724e0a 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -120,7 +120,7 @@ def get_target(path: str) -> None: # Just expand it and it get placed wherever it belongs. # Strangely, decompressing lots of these simultaneously leads to occasional - # "File does not exist" errors when running on Windows Subystem for Linux. + # "File does not exist" errors when running on Windows Subsystem for Linux. # There should be no overlap in files getting written, but perhaps # something about how tar rebuilds the directory structure causes clashes. # It seems that just explicitly creating necessary directories first From a28b11ea1653b4d79e98c4f61736807aed998317 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 18 Jun 2020 19:33:14 -0700 Subject: [PATCH 108/417] 1.5.6 --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 6 ++++-- docs/ba_module.md | 2 +- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 06d8caf4..00514c8f 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/31/39/870b3da9d4e8bbb0dde02328cf72", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cc/28/fcf6593ea46a25253121a5c284a1", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/fc/1f85fd832931a4f29e3b7fe64acc", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/02/d4/fc4da9b7b56007556ed7bc7c02d4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/32/ab/210ebb40458811c3eacc56c9838d", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/41/8be050199ee9b2bac816482677a6", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/36/14/e1746bb5df2b33edc429028b0536", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d0/67/4965f41035dbce0781cc144f9de3", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/86/75/88694137c6b97bcf467a77850d9a", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/d8/46a5d20ff31bac737441ef3140da", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1e/45/cfabbaf255c6084377381267dd15", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6c/25/473847d1de1bfcbd3781e65732bf" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7e/4b/d425cee78e5be7c33eaa116958a0", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/28/927306fabceb4204f6362abbe6c1", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e4/75/e4d5bd0254174a6e0dd946e9436a", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/34/e9/53f7f898b38c0f3027cc2a3769ea", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/b4/026d24c65666eb55a881ca2aad12", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/1f/0fe528dbc9a91c2df1a3f9a85417", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/fb/1087df6e200a2c4401bf07a11a6d", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/10/8315e088429cdbcf228ee09da84a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3a/54/ae033a0ee11c1d6373878646bcb9", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/87/3adfdd60c639575750d90274ee47", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f7/98/24404678c0f890d234317648916b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/98/a4/1176b6af11ac9ac3faa5db145454" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index cd613e6d..2c8a1833 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,10 @@ -### 1.5.6 (20072) -- Mouse wheel now works in manual camera mode on more platforms. +### 1.5.6 (20075) - Lots of internal event-handling cleanup/reorganization in preparation for Android 1.5 update. +- Lots of low level input handling cleanup, also related to Android 1.5 version. Please holler if keyboard/game-controllers/etc. are behaving odd on any platforms. +- Mouse wheel now works in manual camera mode on more platforms. - Server scripts now run in opt mode in release builds so they can use bundled .opt-1.pyc files. - Fixes a potential crash in the local network browser. +- Fixes an issue where Hockey Pucks would not show up in network games. - More misc bug fixes and tidying. ### 1.5.5 (20069) diff --git a/docs/ba_module.md b/docs/ba_module.md index 0f85eb2b..b59a53fd 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-17 for Ballistica version 1.5.6 build 20074

    +

    last updated on 2020-06-18 for Ballistica version 1.5.6 build 20075

    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!


    From 366ad9266e19f1d6029a9a1d438378f47141a171 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 19 Jun 2020 15:35:10 -0700 Subject: [PATCH 109/417] v1.5.7 --- .efrocachemap | 24 +++++++++---------- CHANGELOG.md | 5 ++++ .../python/bastd/activity/coopscore.py | 17 ++++++++----- docs/ba_module.md | 2 +- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 00514c8f..dc426c5a 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/7e/4b/d425cee78e5be7c33eaa116958a0", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/28/927306fabceb4204f6362abbe6c1", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e4/75/e4d5bd0254174a6e0dd946e9436a", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/34/e9/53f7f898b38c0f3027cc2a3769ea", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/b4/026d24c65666eb55a881ca2aad12", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/1f/0fe528dbc9a91c2df1a3f9a85417", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/fb/1087df6e200a2c4401bf07a11a6d", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c1/10/8315e088429cdbcf228ee09da84a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3a/54/ae033a0ee11c1d6373878646bcb9", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/87/3adfdd60c639575750d90274ee47", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f7/98/24404678c0f890d234317648916b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/98/a4/1176b6af11ac9ac3faa5db145454" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e0/b0/f934d21ab92be82d8e5dbbf666a9", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/07/810564c043cbc370345b15191dd6", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/cd/530857c56f64c08d0f21f826cab1", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0f/ca/fd6a9f2f7e74ff2845fa5f700493", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/3d/17bf311a3a466f597cfa3ec2c008", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/89/d8b0e8fc16f095700dd67cb5811d", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e6/aa/8665c16eff6438e7333ccdd24efe", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b7/90/e90583e9397046ddc33bf596b7ab", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8c/e6/51abb2bff373041b3889ef4c742c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/04/24/2846a9ad74af186ae1aeed755a90", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/82/26/ca1bd2452e4734ada4377e67b37c", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1e/a0/61df379746c449f24e8a2cecb528" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c8a1833..394ceddf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,11 @@ +### 1.5.7 (20077) +- Fixed an issue where co-op score screen rating could look like '3.99999999999999' +- Other minor bug fixes. + ### 1.5.6 (20075) - Lots of internal event-handling cleanup/reorganization in preparation for Android 1.5 update. - Lots of low level input handling cleanup, also related to Android 1.5 version. Please holler if keyboard/game-controllers/etc. are behaving odd on any platforms. +- Now including Android test builds for the first time since 1.5. These have not been thoroughly tested yet so please holler with anything that is obviously broken. - Mouse wheel now works in manual camera mode on more platforms. - Server scripts now run in opt mode in release builds so they can use bundled .opt-1.pyc files. - Fixes a potential crash in the local network browser. diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 2aa482b7..42da9596 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -794,10 +794,15 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): (1.9 + i * 0.05, 2.3 + i * 0.05)) for i in range(display_count): try: - name_str = ', '.join( - [p['name'] for p in display_scores[i][1]['players']]) + if display_scores[i][1] is None: + name_str = '-' + else: + name_str = ', '.join([ + p['name'] for p in display_scores[i][1]['players'] + ]) except Exception: - ba.print_exception('Error calcing name_str') + ba.print_exception( + f'Error calcing name_str for {display_scores}') name_str = '-' if display_scores[i] == our_score and not showed_ours: flash = True @@ -1172,8 +1177,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): if 'error' in self._show_info['results'] else None) rank = self._show_info['results']['rank'] total = self._show_info['results']['total'] - rating = 10.0 if total == 1 else round( - 10.0 * (1.0 - (float(rank - 1) / (total - 1))), 1) + rating = (10.0 if total == 1 else 10.0 * (1.0 - (float(rank - 1) / + (total - 1)))) player_rank = self._show_info['results']['playerRank'] best_player_rank = self._show_info['results']['bestPlayerRank'] else: @@ -1298,7 +1303,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): scale=0.7, transition_delay=1.0).autoretain() else: - ZoomText((str(rating) if available else ba.Lstr( + ZoomText((f'{rating:.1f}' if available else ba.Lstr( resource='unavailableText')), flash=True, trail=True, diff --git a/docs/ba_module.md b/docs/ba_module.md index b59a53fd..ea629bcd 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-18 for Ballistica version 1.5.6 build 20075

    +

    last updated on 2020-06-19 for Ballistica version 1.5.6 build 20076

    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!


    From 1aadb77d8cce23fd0de4f469ccf32127989dfa4c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 20 Jun 2020 13:33:19 -0700 Subject: [PATCH 110/417] Language updates --- .efrocachemap | 34 +++++++++++++++++----------------- CHANGELOG.md | 2 +- assets/Makefile | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index dc426c5a..8b54820e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,19 +420,19 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/8d/3d/bcd72bb471b185102c2598cd2346", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/b6/af/5d10baf9fdb9b9a48ab0b1cd24bb", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", - "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/aa/91/2411c0728bae33619c21237a2689", + "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/21/38/7e50214f79088f55c6e059fd33d2", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", - "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/f2/90/62968ad28a2499a8d182a5740a85", + "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/30/f3/4ef3bbaf1e5b7abe114c119ec106", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/95/9b/66e9080c82ef76387832dedee9b4", - "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/9d/00/a8c4ef9f0a25e789c046bd741203", + "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8e/24/f070599beb7b09e1268569fa55b1", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/ae/22/c1976a822db658e5aa732b21228e", @@ -441,7 +441,7 @@ "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/ef/b1935b3767692070f070847f40df", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/8e/3f/41e12b96fc07a623d89153b10c38", - "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/db/eb/324f86a4b714240ae50ffeeed2f8", + "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/62/18/c2987e85c8ce48544cfa9c29d7bb", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74", @@ -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/e0/b0/f934d21ab92be82d8e5dbbf666a9", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/07/810564c043cbc370345b15191dd6", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/cd/530857c56f64c08d0f21f826cab1", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0f/ca/fd6a9f2f7e74ff2845fa5f700493", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/3d/17bf311a3a466f597cfa3ec2c008", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/89/d8b0e8fc16f095700dd67cb5811d", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e6/aa/8665c16eff6438e7333ccdd24efe", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b7/90/e90583e9397046ddc33bf596b7ab", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8c/e6/51abb2bff373041b3889ef4c742c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/04/24/2846a9ad74af186ae1aeed755a90", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/82/26/ca1bd2452e4734ada4377e67b37c", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1e/a0/61df379746c449f24e8a2cecb528" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/2f/e3b29f02f19fa7e8f2fc14b1fd7b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3c/f1/514a1c22aaf3e78b13c745ad4306", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/5b/6884ab37847e1cc7f849629dcec7", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2a/1a/6503edbce03557e4dc91509578f3", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c0/26/ad827bb61a7d6768092c0bcc3989", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/5c/d21d74a56e8e06dc2f7c8ad8916c", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6a/c2/4675f86966169552fa5712eaf182", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ee/d1/68f419fe8daea2c7bccf07f6bae1", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/39/c6/fff4fe2694e30a95675f0de5bcbd", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/59/98/f578939a40efe49320b7768d1df7", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/cd/a4e3ac5b10a081701c348c721d3d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/36/c6/6fb17e0267c5e40d2ed6f72aa134" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 394ceddf..3fdc7a93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ### 1.5.7 (20077) -- Fixed an issue where co-op score screen rating could look like '3.99999999999999' +- Fixed an issue where co-op score screen rating could look like '3.9999999999999' - Other minor bug fixes. ### 1.5.6 (20075) diff --git a/assets/Makefile b/assets/Makefile index bdaacd03..083a36da 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -20214,7 +20214,7 @@ scripts-android: $(SCRIPT_TARGETS_ANDROID) $(SCRIPT_TARGETS_COMMON) # Build scripts for all platforms scripts: scripts-cmake scripts-win scripts-mac scripts-ios scripts-android clean-scripts: - rm -rf build/ba_data/python + rm -rf build/ba_data/python build/ba_data/python-site-packages # Build all required assets for a specific platform. assets-cmake: $(ASSET_TARGETS_CMAKE) $(ASSET_TARGETS_COMMON) From 13937d47772f99fa3ec0ead281a0a24a8e086cc7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 21 Jun 2020 03:09:54 -0700 Subject: [PATCH 111/417] v1.5.8 --- .efrocachemap | 24 +++--- .idea/dictionaries/ericf.xml | 4 + CHANGELOG.md | 6 ++ assets/src/ba_data/python/ba/_app.py | 5 -- assets/src/ba_data/python/ba/_apputils.py | 44 +++++++---- assets/src/ba_data/python/bastd/ui/config.py | 16 ++-- assets/src/ba_data/python/bastd/ui/gather.py | 79 +++---------------- .../ba_data/python/bastd/ui/settings/audio.py | 2 +- docs/ba_module.md | 2 +- tools/batools/build.py | 4 +- 10 files changed, 74 insertions(+), 112 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 8b54820e..addd6d70 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/4f/2f/e3b29f02f19fa7e8f2fc14b1fd7b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3c/f1/514a1c22aaf3e78b13c745ad4306", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b4/5b/6884ab37847e1cc7f849629dcec7", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2a/1a/6503edbce03557e4dc91509578f3", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c0/26/ad827bb61a7d6768092c0bcc3989", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f8/5c/d21d74a56e8e06dc2f7c8ad8916c", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6a/c2/4675f86966169552fa5712eaf182", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ee/d1/68f419fe8daea2c7bccf07f6bae1", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/39/c6/fff4fe2694e30a95675f0de5bcbd", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/59/98/f578939a40efe49320b7768d1df7", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/cd/a4e3ac5b10a081701c348c721d3d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/36/c6/6fb17e0267c5e40d2ed6f72aa134" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/94/a726a87b0601df96b34e457f406f", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/f4/1de7a2a7b25e9797cdeb8fbdbd4a", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ed/6f/8d356c4b4aacb83ef227498a0c5c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/76/4bf599bdab77331350d0da8a5714", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/36/ebcc874f5b681e4fc22b0512f31b", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/5f/c2b1ff67661b855f93a201fe78fd", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/ea/bc68af318e0100d2d4cde351591b", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/da/08/6913f20d7c0a6f77369f3ade467a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/af/73e96b1008e2a34b43a482534c04", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/19/3b/ee02640ca173b63aa1805fe3b82b", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/15/d1/c79915d092932b4019ad086d93dc", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/83/c1/73811083cdfbd86f7365001a0ccb" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index a631cdc7..b97b270f 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -881,6 +881,7 @@ hmac hmmm hmmmm + hmph hoffs holdingflag holdingteam @@ -1622,6 +1623,7 @@ respawned respawnicon responsetype + resultstr returncode returnfuncptrs returnspc @@ -1900,6 +1902,8 @@ sysctl syslogmodule tabval + tagargs + tagversion taobao taobaomascot targ diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fdc7a93..57b0af09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +### 1.5.8 (20079) +- Fixed an issue where touch controls or sound settings values could look like 0.8999999999. Please holler if you see this anywhere else. +- Fixed a potential crash when tapping the screen before the game is fully inited. +- Restored the correct error message in the 'Google Play' connection tab from 1.4 (I am actively working on a replacement) +- Other minor bug fixes. + ### 1.5.7 (20077) - Fixed an issue where co-op score screen rating could look like '3.9999999999999' - Other minor bug fixes. diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index abe571f2..184da001 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -519,11 +519,6 @@ class App: # If there's a leftover log file, attempt to upload # it to the server and/or get rid of it. _apputils.handle_leftover_log_file() - try: - _apputils.handle_leftover_log_file() - except Exception: - from ba import _error - _error.print_exception('Error handling leftover log file') # Notify the user if we're using custom system scripts. # FIXME: This no longer works since sys-scripts is an absolute path; diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index a2ae13b1..dcecd42c 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -136,26 +136,36 @@ def handle_log() -> None: def handle_leftover_log_file() -> None: """Handle an un-uploaded log from a previous run.""" - import json - from ba._netutils import serverput + try: + import json + from ba._netutils import serverput - if os.path.exists(_ba.get_log_file_path()): - with open(_ba.get_log_file_path()) as infile: - info = json.loads(infile.read()) - infile.close() - do_send = should_submit_debug_info() - if do_send: + if os.path.exists(_ba.get_log_file_path()): + with open(_ba.get_log_file_path()) as infile: + info = json.loads(infile.read()) + infile.close() + do_send = should_submit_debug_info() + if do_send: - def response(data: Any) -> None: - # Non-None response means we were successful; - # lets kill it. - if data is not None: - os.remove(_ba.get_log_file_path()) + def response(data: Any) -> None: + # Non-None response means we were successful; + # lets kill it. + if data is not None: + try: + os.remove(_ba.get_log_file_path()) + except FileNotFoundError: + # Saw this in the wild. The file just existed + # a moment ago but I suppose something could have + # killed it since. ¯\_(ツ)_/¯ + pass - serverput('bsLog', info, response) - else: - # If they don't want logs uploaded just kill it. - os.remove(_ba.get_log_file_path()) + serverput('bsLog', info, response) + else: + # If they don't want logs uploaded just kill it. + os.remove(_ba.get_log_file_path()) + except Exception: + from ba import _error + _error.print_exception('Error handling leftover log file.') def garbage_collect(session_end: bool = True) -> None: diff --git a/assets/src/ba_data/python/bastd/ui/config.py b/assets/src/ba_data/python/bastd/ui/config.py index a55c5a95..8426de77 100644 --- a/assets/src/ba_data/python/bastd/ui/config.py +++ b/assets/src/ba_data/python/bastd/ui/config.py @@ -127,23 +127,23 @@ class ConfigNumberEdit: text=displayname, maxwidth=160 + xoffset, color=(0.8, 0.8, 0.8, 1.0), - h_align="left", - v_align="center", + h_align='left', + v_align='center', scale=textscale) self.valuetext = ba.textwidget(parent=parent, position=(246 + xoffset, position[1]), size=(60, 28), editable=False, color=(0.3, 1.0, 0.3, 1.0), - h_align="right", - v_align="center", + h_align='right', + v_align='center', text=str(self._value), padding=2) self.minusbutton = ba.buttonwidget( parent=parent, position=(330 + xoffset, position[1]), size=(28, 28), - label="-", + label='-', autoselect=True, on_activate_call=ba.Call(self._down), repeat=True, @@ -152,12 +152,12 @@ class ConfigNumberEdit: position=(380 + xoffset, position[1]), size=(28, 28), - label="+", + label='+', autoselect=True, on_activate_call=ba.Call(self._up), repeat=True, enable_sound=changesound) - # complain if we outlive our widgets + # Complain if we outlive our widgets. ba.uicleanupcheck(self, self.nametext) self._update_display() @@ -177,4 +177,4 @@ class ConfigNumberEdit: ba.app.config.apply_and_commit() def _update_display(self) -> None: - ba.textwidget(edit=self.valuetext, text=str(round(self._value, 2))) + ba.textwidget(edit=self.valuetext, text=f'{self._value:.1f}') diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 2fdc1e18..6d2da8c3 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -348,8 +348,6 @@ class GatherWindow(ba.Window): elif tab == 'google_play': c_width = self._scroll_width c_height = 380.0 - b_width = 250.0 - b_width2 = 230.0 self._tab_container = cnt = ba.containerwidget( parent=self._root_widget, position=(scroll_left, scroll_bottom + @@ -357,71 +355,17 @@ class GatherWindow(ba.Window): size=(c_width, c_height), background=False, selection_loop_to_parent=True) - img_size = 100 - v = c_height - 30 - ba.textwidget(parent=cnt, - position=(c_width * 0.5, v), - color=(0.6, 1.0, 0.6), - scale=1.3, - size=(0, 0), - maxwidth=c_width * 0.9, - h_align='center', - v_align='center', - text=ba.Lstr(resource=self._r + - '.googlePlayDescriptionText')) - v -= 35 - ba.textwidget(parent=cnt, - position=(c_width * 0.5, v), - color=(0.6, 1.0, 0.6), - scale=0.7, - size=(0, 0), - maxwidth=c_width * 0.9, - h_align='center', - v_align='center', - text=ba.Lstr(resource=self._r + - '.worksWithGooglePlayDevicesText')) - v -= 125 - btn = ba.buttonwidget( + v = c_height - 30.0 + ba.textwidget( parent=cnt, - label='', - position=(c_width * 0.5 - b_width * 0.5, v - b_width * 0.5), - size=(b_width, b_width * 0.9), - button_type='square', - on_activate_call=self._on_google_play_invite_press, - autoselect=True, - up_widget=self._tab_buttons[tab]) - ba.imagewidget(parent=cnt, - position=(c_width * 0.5 - img_size * 0.5, v - 35), - size=(img_size, img_size), - draw_controller=btn, - texture=ba.gettexture('googlePlayGamesIcon'), - color=(0, 1, 0)) - ba.textwidget(parent=cnt, - text=ba.Lstr(resource=self._r + - '.googlePlayInviteText'), - maxwidth=b_width * 0.8, - draw_controller=btn, - color=(0, 1, 0), - flatness=1.0, - position=(c_width * 0.5, v - 60), - scale=1.6, - size=(0, 0), - h_align='center', - v_align='center') - v -= 180 - ba.buttonwidget( - parent=cnt, - label=ba.Lstr(resource=self._r + '.googlePlaySeeInvitesText'), - color=(0.5, 0.5, 0.6), - textcolor=(0.75, 0.7, 0.8), - autoselect=True, - position=(c_width * 0.5 - b_width2 * 0.5, v), - size=(b_width2, 60), - on_activate_call=lambda: ba.timer( - 0.1, - self._on_google_play_show_invites_press, - timetype=ba.TimeType.REAL), - ) + position=(c_width * 0.5, v - 140.0), + color=(0.6, 1.0, 0.6), + scale=1.3, + size=(0.0, 0.0), + maxwidth=c_width * 0.9, + h_align='center', + v_align='center', + text=ba.Lstr(resource='googleMultiplayerDiscontinuedText')) elif tab == 'internet': c_width = self._scroll_width @@ -1717,6 +1661,9 @@ class GatherWindow(ba.Window): self._call, self._address, self._port, ping if accessible else None), from_other_thread=True) + except ConnectionRefusedError: + # Fine, server; sorry we pinged you. Hmph. + pass except OSError as exc: import errno diff --git a/assets/src/ba_data/python/bastd/ui/settings/audio.py b/assets/src/ba_data/python/bastd/ui/settings/audio.py index bf4c34ce..02c6b25d 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/audio.py +++ b/assets/src/ba_data/python/bastd/ui/settings/audio.py @@ -206,7 +206,7 @@ class AudioSettingsWindow(ba.Window): else: self._soundtrack_button = None - # tweak a few navigation bits + # Tweak a few navigation bits. try: ba.widget(edit=back_button, down_widget=svne.minusbutton) except Exception: diff --git a/docs/ba_module.md b/docs/ba_module.md index ea629bcd..7852b68e 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-19 for Ballistica version 1.5.6 build 20076

    +

    last updated on 2020-06-21 for Ballistica version 1.5.8 build 20079

    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!


    diff --git a/tools/batools/build.py b/tools/batools/build.py index ca2abb97..a918883f 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -47,9 +47,9 @@ class PipRequirement: PIP_REQUIREMENTS = [ PipRequirement(modulename='pylint', minversion=[2, 5, 3]), - PipRequirement(modulename='mypy', minversion=[0, 780]), + PipRequirement(modulename='mypy', minversion=[0, 781]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), - PipRequirement(modulename='cpplint', minversion=[1, 5, 0]), + PipRequirement(modulename='cpplint', minversion=[1, 5, 1]), PipRequirement(modulename='typing_extensions'), PipRequirement(modulename='pytz'), PipRequirement(modulename='yaml', pipname='PyYAML'), From fe8b030b214c105e2ce41ee0770181cb2dd4ba87 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 21 Jun 2020 17:15:30 -0700 Subject: [PATCH 112/417] Added ui module preloading to prevent hitches --- .efrocachemap | 24 ++--- CHANGELOG.md | 3 + .../ba_data/python/bastd/ui/coop/browser.py | 73 ++++++++------ .../python/bastd/ui/league/rankbutton.py | 5 +- .../src/ba_data/python/bastd/ui/mainmenu.py | 94 +++++++++++-------- assets/src/ba_data/python/bastd/ui/play.py | 34 +++++-- .../python/bastd/ui/settings/allsettings.py | 35 +++++-- .../ba_data/python/bastd/ui/store/button.py | 10 +- 8 files changed, 176 insertions(+), 102 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index addd6d70..5f75a607 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/48/94/a726a87b0601df96b34e457f406f", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/93/f4/1de7a2a7b25e9797cdeb8fbdbd4a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ed/6f/8d356c4b4aacb83ef227498a0c5c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/76/4bf599bdab77331350d0da8a5714", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3a/36/ebcc874f5b681e4fc22b0512f31b", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/5f/c2b1ff67661b855f93a201fe78fd", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/ea/bc68af318e0100d2d4cde351591b", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/da/08/6913f20d7c0a6f77369f3ade467a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/af/73e96b1008e2a34b43a482534c04", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/19/3b/ee02640ca173b63aa1805fe3b82b", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/15/d1/c79915d092932b4019ad086d93dc", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/83/c1/73811083cdfbd86f7365001a0ccb" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/10/8b0acfe18403ed5f7648cbd16304", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/60/d6/78971bf24839db03eb52df3d66fa", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6f/17/265584b464b9ed0dd32f5138513c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/47/42/4b10abcb0acd20c7a36d80283046", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ec/7c/0456f8a0371de22d65dfc50389b4", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/c8/d7c9071a85ddc33e395960af86e0", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/41/b6/aa543cfed5ef05b6b1aae26c33f0", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/50/dd/4be23bf45b013537a3970e457976", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/32/4c/aff483fae256674f9833946cd5f2", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/93/ff/d898d07ebebebfd225d6bb437488", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f1/c5/d56a83b4e32c1a2e566054cf58ad", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/44/9a/5cef4f8e575e210baac8857e265b" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 57b0af09..7945eb13 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.9 (20081) +- Reduced some hitches when clicking on certain buttons in the UI + ### 1.5.8 (20079) - Fixed an issue where touch controls or sound settings values could look like 0.8999999999. Please holler if you see this anywhere else. - Fixed a potential crash when tapping the screen before the game is fully inited. diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index eb96bf30..5284abed 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -29,6 +29,8 @@ from typing import TYPE_CHECKING import _ba import ba +from bastd.ui.store.button import StoreButton +from bastd.ui.league.rankbutton import LeagueRankButton if TYPE_CHECKING: from typing import Any, Optional, Tuple, Dict, List, Union @@ -54,8 +56,12 @@ class CoopBrowserWindow(ba.Window): # pylint: disable=cyclic-import # pylint: disable=too-many-statements # pylint: disable=cyclic-import - from bastd.ui.store.button import StoreButton - from bastd.ui.league.rankbutton import LeagueRankButton + import threading + + # Preload some modules we use in a background thread so we won't + # have a visual hitch when the user taps them. + threading.Thread(target=self._preload_modules).start() + ba.set_analytics_screen('Coop Window') app = ba.app @@ -271,6 +277,20 @@ class CoopBrowserWindow(ba.Window): repeat=True) self._update() + @staticmethod + def _preload_modules() -> None: + """For preloading modules we use in a bg thread to prevent hitches.""" + import bastd.ui.purchase as _unused1 + import bastd.ui.coop.gamebutton as _unused2 + import bastd.ui.confirm as _unused3 + import bastd.ui.account as _unused4 + import bastd.ui.league.rankwindow as _unused5 + import bastd.ui.store.browser as _unused6 + import bastd.ui.account.viewer as _unused7 + import bastd.ui.tournamentscores as _unused8 + import bastd.ui.tournamententry as _unused9 + import bastd.ui.play as _unused10 + def _update(self) -> None: cur_time = ba.time(ba.TimeType.REAL) @@ -739,13 +759,13 @@ class CoopBrowserWindow(ba.Window): def _on_tournament_info_press(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import confirm + from bastd.ui.confirm import ConfirmWindow txt = ba.Lstr(resource=self._r + '.tournamentInfoText') - confirm.ConfirmWindow(txt, - cancel_button=False, - width=550, - height=260, - origin_widget=self._tournament_info_button) + ConfirmWindow(txt, + cancel_button=False, + width=550, + height=260, + origin_widget=self._tournament_info_button) def _refresh(self) -> None: # pylint: disable=too-many-statements @@ -1335,10 +1355,10 @@ class CoopBrowserWindow(ba.Window): def _switch_to_league_rankings(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import account + from bastd.ui.account import show_sign_in_prompt from bastd.ui.league.rankwindow import LeagueRankWindow if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') @@ -1349,22 +1369,22 @@ class CoopBrowserWindow(ba.Window): def _switch_to_score(self, show_tab: Optional[str] = 'extras') -> None: # pylint: disable=cyclic-import - from bastd.ui import account - from bastd.ui.store import browser + from bastd.ui.account import show_sign_in_prompt + from bastd.ui.store.browser import StoreBrowserWindow if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') assert self._store_button is not None - ba.app.main_menu_window = (browser.StoreBrowserWindow( + ba.app.main_menu_window = (StoreBrowserWindow( origin_widget=self._store_button.get_button(), show_tab=show_tab, back_location='CoopBrowserWindow').get_root_widget()) def _show_leader(self, tournament_button: Dict[str, Any]) -> None: # pylint: disable=cyclic-import - from bastd.ui.account import viewer + from bastd.ui.account.viewer import AccountViewerWindow tournament_id = tournament_button['tournament_id'] # FIXME: This assumes a single player entry in leader; should expand @@ -1374,7 +1394,7 @@ class CoopBrowserWindow(ba.Window): ba.playsound(ba.getsound('error')) return ba.playsound(ba.getsound('swish')) - viewer.AccountViewerWindow( + AccountViewerWindow( account_id=tournament_button['leader'][2][0].get('a', None), profile_id=tournament_button['leader'][2][0].get('p', None), position=tournament_button['current_leader_name_text']. @@ -1382,13 +1402,13 @@ class CoopBrowserWindow(ba.Window): def _show_scores(self, tournament_button: Dict[str, Any]) -> None: # pylint: disable=cyclic-import - from bastd.ui import tournamentscores + from bastd.ui.tournamentscores import TournamentScoresWindow tournament_id = tournament_button['tournament_id'] if tournament_id is None: ba.playsound(ba.getsound('error')) return - tournamentscores.TournamentScoresWindow( + TournamentScoresWindow( tournament_id=tournament_id, position=tournament_button['more_scores_button']. get_screen_space_center()) @@ -1406,8 +1426,8 @@ class CoopBrowserWindow(ba.Window): # pylint: disable=too-many-return-statements # pylint: disable=cyclic-import from ba.internal import have_pro - from bastd.ui import confirm - from bastd.ui import tournamententry + from bastd.ui.confirm import ConfirmWindow + from bastd.ui.tournamententry import TournamentEntryWindow from bastd.ui.purchase import PurchaseWindow from bastd.ui.account import show_sign_in_prompt args: Dict[str, Any] = {} @@ -1457,12 +1477,11 @@ class CoopBrowserWindow(ba.Window): tournament_button['tournament_id']]['game'] if tournament_button is None and game == 'Easy:The Last Stand': - confirm.ConfirmWindow(ba.Lstr( - resource='difficultyHardUnlockOnlyText', - fallback_resource='difficultyHardOnlyText'), - cancel_button=False, - width=460, - height=130) + ConfirmWindow(ba.Lstr(resource='difficultyHardUnlockOnlyText', + fallback_resource='difficultyHardOnlyText'), + cancel_button=False, + width=460, + height=130) return # Infinite onslaught/runaround require pro; bring up a store link if @@ -1506,7 +1525,7 @@ class CoopBrowserWindow(ba.Window): # For tournaments, we pop up the entry window. if tournament_button is not None: - tournamententry.TournamentEntryWindow( + TournamentEntryWindow( tournament_id=tournament_button['tournament_id'], position=tournament_button['button'].get_screen_space_center()) else: diff --git a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py index b64e9e10..54868a5d 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py @@ -374,8 +374,9 @@ class LeagueRankButton: callback=ba.WeakCall(self._on_power_ranking_query_response)) def _default_on_activate_call(self) -> None: - from bastd.ui.league import rankwindow - rankwindow.LeagueRankWindow(modal=True, origin_widget=self._button) + # pylint: disable=cyclic-import + from bastd.ui.league.rankwindow import LeagueRankWindow + LeagueRankWindow(modal=True, origin_widget=self._button) def set_position(self, position: Tuple[float, float]) -> None: """Set the button's position.""" diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 95a3135c..1d908fb3 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -37,12 +37,17 @@ class MainMenuWindow(ba.Window): def __init__(self, transition: Optional[str] = 'in_right'): # pylint: disable=cyclic-import - from bastd import mainmenu + import threading + from bastd.mainmenu import MainMenuSession self._in_game = not isinstance(_ba.get_foreground_host_session(), - mainmenu.MainMenuSession) + MainMenuSession) + + # Preload some modules we use in a background thread so we won't + # have a visual hitch when the user taps them. + threading.Thread(target=self._preload_modules).start() + if not self._in_game: ba.set_analytics_screen('Main Menu') - self._show_remote_app_info_on_first_launch() # Make a vanilla container; we'll modify it to our needs in refresh. @@ -84,6 +89,22 @@ class MainMenuWindow(ba.Window): repeat=True, timetype=ba.TimeType.REAL) + @staticmethod + def _preload_modules() -> None: + """For preloading modules we use in a bg thread to prevent hitches.""" + import bastd.ui.getremote as _unused + import bastd.ui.confirm as _unused2 + import bastd.ui.store.button as _unused3 + import bastd.ui.kiosk as _unused4 + import bastd.ui.account.settings as _unused5 + import bastd.ui.store.browser as _unused6 + import bastd.ui.creditslist as _unused7 + import bastd.ui.helpui as _unused8 + import bastd.ui.settings.allsettings as _unused9 + import bastd.ui.gather as _unused10 + import bastd.ui.watch as _unused11 + import bastd.ui.play as _unused12 + def _show_remote_app_info_on_first_launch(self) -> None: # The first time the non-in-game menu pops up, we might wanna show # a 'get-remote-app' dialog in front of it. @@ -99,12 +120,12 @@ class MainMenuWindow(ba.Window): def _check_show_bs_remote_window() -> None: try: - from bastd.ui import getremote + from bastd.ui.getremote import GetBSRemoteWindow ba.playsound(ba.getsound('swish')) - getremote.GetBSRemoteWindow() + GetBSRemoteWindow() except Exception: ba.print_exception( - 'error showing ba-remote window') + 'Error showing get-remote window.') ba.timer(2.5, _check_show_bs_remote_window, @@ -149,7 +170,7 @@ class MainMenuWindow(ba.Window): # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-statements - from bastd.ui import confirm + from bastd.ui.confirm import QuitWindow from bastd.ui.store.button import StoreButton # Clear everything that was there. @@ -323,7 +344,7 @@ class MainMenuWindow(ba.Window): and ba.app.platform == 'android'): def _do_quit() -> None: - confirm.QuitWindow(swish=True, back=True) + QuitWindow(swish=True, back=True) ba.containerwidget(edit=self._root_widget, on_cancel_call=_do_quit) @@ -804,68 +825,67 @@ class MainMenuWindow(ba.Window): def _quit(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import confirm - confirm.QuitWindow(origin_widget=self._quit_button) + from bastd.ui.confirm import QuitWindow + QuitWindow(origin_widget=self._quit_button) def _demo_menu_press(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import kiosk + from bastd.ui.kiosk import KioskWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (kiosk.KioskWindow( + ba.app.main_menu_window = (KioskWindow( transition='in_left').get_root_widget()) def _show_account_window(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.account import settings + from bastd.ui.account.settings import AccountSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (settings.AccountSettingsWindow( + ba.app.main_menu_window = (AccountSettingsWindow( origin_widget=self._gc_button).get_root_widget()) def _on_store_pressed(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.store import browser - from bastd.ui import account + from bastd.ui.store.browser import StoreBrowserWindow + from bastd.ui.account import show_sign_in_prompt if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (browser.StoreBrowserWindow( + ba.app.main_menu_window = (StoreBrowserWindow( origin_widget=self._store_button).get_root_widget()) def _confirm_end_game(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import confirm + from bastd.ui.confirm import ConfirmWindow # FIXME: Currently we crash calling this on client-sessions. # Select cancel by default; this occasionally gets called by accident # in a fit of button mashing and this will help reduce damage. - confirm.ConfirmWindow(ba.Lstr(resource=self._r + '.exitToMenuText'), - self._end_game, - cancel_is_selected=True) + ConfirmWindow(ba.Lstr(resource=self._r + '.exitToMenuText'), + self._end_game, + cancel_is_selected=True) def _confirm_end_replay(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import confirm + from bastd.ui.confirm import ConfirmWindow # Select cancel by default; this occasionally gets called by accident # in a fit of button mashing and this will help reduce damage. - confirm.ConfirmWindow(ba.Lstr(resource=self._r + '.exitToMenuText'), - self._end_game, - cancel_is_selected=True) + ConfirmWindow(ba.Lstr(resource=self._r + '.exitToMenuText'), + self._end_game, + cancel_is_selected=True) def _confirm_leave_party(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import confirm + from bastd.ui.confirm import ConfirmWindow # Select cancel by default; this occasionally gets called by accident # in a fit of button mashing and this will help reduce damage. - confirm.ConfirmWindow(ba.Lstr(resource=self._r + - '.leavePartyConfirmText'), - self._leave_party, - cancel_is_selected=True) + ConfirmWindow(ba.Lstr(resource=self._r + '.leavePartyConfirmText'), + self._leave_party, + cancel_is_selected=True) def _leave_party(self) -> None: _ba.disconnect_from_host() @@ -886,27 +906,27 @@ class MainMenuWindow(ba.Window): def _credits(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import creditslist + from bastd.ui.creditslist import CreditsListWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (creditslist.CreditsListWindow( + ba.app.main_menu_window = (CreditsListWindow( origin_widget=self._credits_button).get_root_widget()) def _howtoplay(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import helpui + from bastd.ui.helpui import HelpWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (helpui.HelpWindow( + ba.app.main_menu_window = (HelpWindow( main_menu=True, origin_widget=self._how_to_play_button).get_root_widget()) def _settings(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import allsettings + from bastd.ui.settings.allsettings import AllSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (allsettings.AllSettingsWindow( + ba.app.main_menu_window = (AllSettingsWindow( origin_widget=self._settings_button).get_root_widget()) def _resume_and_call(self, call: Callable[[], Any]) -> None: diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py index 1fd43c5c..f8e7e6a2 100644 --- a/assets/src/ba_data/python/bastd/ui/play.py +++ b/assets/src/ba_data/python/bastd/ui/play.py @@ -39,6 +39,12 @@ class PlayWindow(ba.Window): origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals + import threading + + # Preload some modules we use in a background thread so we won't + # have a visual hitch when the user taps them. + threading.Thread(target=self._preload_modules).start() + new_style = True width = 1000 if ba.app.small_ui else 800 x_offs = 100 if ba.app.small_ui else 0 @@ -410,42 +416,50 @@ class PlayWindow(ba.Window): self._restore_state() + @staticmethod + def _preload_modules() -> None: + """For preloading modules we use in a bg thread to prevent hitches.""" + import bastd.ui.mainmenu as _unused1 + import bastd.ui.account as _unused2 + import bastd.ui.coop.browser as _unused3 + import bastd.ui.playlist.browser as _unused4 + def _back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow self._save_state() - ba.app.main_menu_window = (mainmenu.MainMenuWindow( + ba.app.main_menu_window = (MainMenuWindow( transition='in_left').get_root_widget()) ba.containerwidget(edit=self._root_widget, transition=self._transition_out) def _coop(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import account - from bastd.ui.coop import browser + from bastd.ui.account import show_sign_in_prompt + from bastd.ui.coop.browser import CoopBrowserWindow if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (browser.CoopBrowserWindow( + ba.app.main_menu_window = (CoopBrowserWindow( origin_widget=self._coop_button).get_root_widget()) def _team_tourney(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.playlist import browser + from bastd.ui.playlist.browser import PlaylistBrowserWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (browser.PlaylistBrowserWindow( + ba.app.main_menu_window = (PlaylistBrowserWindow( origin_widget=self._teams_button, sessiontype=ba.DualTeamSession).get_root_widget()) def _free_for_all(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.playlist import browser + from bastd.ui.playlist.browser import PlaylistBrowserWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (browser.PlaylistBrowserWindow( + ba.app.main_menu_window = (PlaylistBrowserWindow( origin_widget=self._free_for_all_button, sessiontype=ba.FreeForAllSession).get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index 7e45179b..cd7686c9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -39,6 +39,12 @@ class AllSettingsWindow(ba.Window): origin_widget: ba.Widget = None): # pylint: disable=too-many-statements # pylint: disable=too-many-locals + import threading + + # Preload some modules we use in a background thread so we won't + # have a visual hitch when the user taps them. + threading.Thread(target=self._preload_modules).start() + ba.set_analytics_screen('Settings Window') scale_origin: Optional[Tuple[float, float]] if origin_widget is not None: @@ -197,45 +203,54 @@ class AllSettingsWindow(ba.Window): texture=ba.gettexture('advancedIcon'), draw_controller=avb) + @staticmethod + def _preload_modules() -> None: + """For preloading modules we use in a bg thread to prevent hitches.""" + import bastd.ui.mainmenu as _unused1 + import bastd.ui.settings.controls as _unused2 + import bastd.ui.settings.graphics as _unused3 + import bastd.ui.settings.audio as _unused4 + import bastd.ui.settings.advanced as _unused5 + def _do_back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (mainmenu.MainMenuWindow( + ba.app.main_menu_window = (MainMenuWindow( transition='in_left').get_root_widget()) def _do_controllers(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import controls + from bastd.ui.settings.controls import ControlsSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( + ba.app.main_menu_window = (ControlsSettingsWindow( origin_widget=self._controllers_button).get_root_widget()) def _do_graphics(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import graphics + from bastd.ui.settings.graphics import GraphicsSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (graphics.GraphicsSettingsWindow( + ba.app.main_menu_window = (GraphicsSettingsWindow( origin_widget=self._graphics_button).get_root_widget()) def _do_audio(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import audio + from bastd.ui.settings.audio import AudioSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (audio.AudioSettingsWindow( + ba.app.main_menu_window = (AudioSettingsWindow( origin_widget=self._audio_button).get_root_widget()) def _do_advanced(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import advanced + from bastd.ui.settings.advanced import AdvancedSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (advanced.AdvancedSettingsWindow( + ba.app.main_menu_window = (AdvancedSettingsWindow( origin_widget=self._advanced_button).get_root_widget()) def _save_state(self) -> None: diff --git a/assets/src/ba_data/python/bastd/ui/store/button.py b/assets/src/ba_data/python/bastd/ui/store/button.py index 17d73f0a..4cacaabe 100644 --- a/assets/src/ba_data/python/bastd/ui/store/button.py +++ b/assets/src/ba_data/python/bastd/ui/store/button.py @@ -212,12 +212,13 @@ class StoreButton: self._sale_circle_rad * 0.3)) def _default_on_activate_call(self) -> None: - from bastd.ui import account - from bastd.ui.store import browser + # pylint: disable=cyclic-import + from bastd.ui.account import show_sign_in_prompt + from bastd.ui.store.browser import StoreBrowserWindow if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return - browser.StoreBrowserWindow(modal=True, origin_widget=self._button) + StoreBrowserWindow(modal=True, origin_widget=self._button) def get_button(self) -> ba.Widget: """Return the underlying button widget.""" @@ -225,6 +226,7 @@ class StoreButton: def _update(self) -> None: # pylint: disable=too-many-branches + # pylint: disable=cyclic-import from ba import SpecialChar, TimeFormat from ba.internal import (get_available_sale_time, get_available_purchase_count) From ae1b317af72956d80254f4c332fa738d8788bd87 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 22 Jun 2020 02:09:49 -0700 Subject: [PATCH 113/417] v1.5.9 --- .efrocachemap | 24 +++++++------- CHANGELOG.md | 6 +++- assets/.asset_manifest_public.json | 4 +-- assets/Makefile | 14 ++++---- assets/src/ba_data/python/ba/_benchmark.py | 4 +-- assets/src/ba_data/python/ba/_input.py | 7 ++-- assets/src/ba_data/python/ba/internal.py | 1 - .../python/ba/{_modutils.py => modutils.py} | 0 .../ba_data/python/bastd/ui/coop/browser.py | 1 - assets/src/ba_data/python/bastd/ui/gather.py | 32 ++++++++++++------- .../python/bastd/ui/settings/advanced.py | 2 +- docs/ba_module.md | 2 +- 12 files changed, 56 insertions(+), 41 deletions(-) rename assets/src/ba_data/python/ba/{_modutils.py => modutils.py} (100%) diff --git a/.efrocachemap b/.efrocachemap index 5f75a607..c0bdfcf3 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/0d/10/8b0acfe18403ed5f7648cbd16304", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/60/d6/78971bf24839db03eb52df3d66fa", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6f/17/265584b464b9ed0dd32f5138513c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/47/42/4b10abcb0acd20c7a36d80283046", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ec/7c/0456f8a0371de22d65dfc50389b4", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/c8/d7c9071a85ddc33e395960af86e0", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/41/b6/aa543cfed5ef05b6b1aae26c33f0", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/50/dd/4be23bf45b013537a3970e457976", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/32/4c/aff483fae256674f9833946cd5f2", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/93/ff/d898d07ebebebfd225d6bb437488", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f1/c5/d56a83b4e32c1a2e566054cf58ad", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/44/9a/5cef4f8e575e210baac8857e265b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/4a/c6ce1f7c93d71cd392f32f39346f", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/ef/371aaa27e0f4767cec5fe2117efe", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/59/5f/d25b830965dd26638c8e0cae6d8c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/99/f2/8a99c79e670fcdde746cfa0dd379", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/77/b3/e2af340577b93d3983550b351604", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/21/27/1633ac867e848b68324cae7c5838", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c6/37/5ad49f380196860b49b77b66bc39", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/01/73cb3ae73e00f64f2d8bde9ba3d3", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/85/8a/71b0356f1210a32e2314fdbda7f8", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/48/a7/96da0cf90e70d9e7a8661c01d5b9", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9c/5c/49340950cd68dce232fefa47fbaa", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/b6/d2dd933fc479d3c669a4be4cee77" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7945eb13..f8a5e2e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ -### 1.5.9 (20081) +### 1.5.9 (20082) - Reduced some hitches when clicking on certain buttons in the UI +- Fixed an issue where very early keyboard/controller connects/disconnects could get lost on android. +- ba._modutils is now ba.modutils since it is intended to be publicly accessible. +- drop-down console is now properly accessible again via android hardware keyboards (` key) +- Other minor bug fixes.. ### 1.5.8 (20079) - Fixed an issue where touch controls or sound settings values could look like 0.8999999999. Please holler if you see this anywhere else. diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index df9ec086..be327ba4 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -36,7 +36,6 @@ "ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc", @@ -57,6 +56,7 @@ "ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc", "ba_data/python/ba/_account.py", "ba_data/python/ba/_achievement.py", @@ -93,7 +93,6 @@ "ba_data/python/ba/_math.py", "ba_data/python/ba/_messages.py", "ba_data/python/ba/_meta.py", - "ba_data/python/ba/_modutils.py", "ba_data/python/ba/_multiteamsession.py", "ba_data/python/ba/_music.py", "ba_data/python/ba/_netutils.py", @@ -114,6 +113,7 @@ "ba_data/python/ba/deprecated.py", "ba_data/python/ba/internal.py", "ba_data/python/ba/macmusicapp.py", + "ba_data/python/ba/modutils.py", "ba_data/python/ba/osmusic.py", "ba_data/python/ba/ui/__init__.py", "ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc", diff --git a/assets/Makefile b/assets/Makefile index 083a36da..69839ee2 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -178,7 +178,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_math.py \ build/ba_data/python/ba/_messages.py \ build/ba_data/python/ba/_meta.py \ - build/ba_data/python/ba/_modutils.py \ build/ba_data/python/ba/_multiteamsession.py \ build/ba_data/python/ba/_music.py \ build/ba_data/python/ba/_netutils.py \ @@ -199,6 +198,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/deprecated.py \ build/ba_data/python/ba/internal.py \ build/ba_data/python/ba/macmusicapp.py \ + build/ba_data/python/ba/modutils.py \ build/ba_data/python/ba/osmusic.py \ build/ba_data/python/ba/ui/__init__.py \ build/ba_data/python/bastd/__init__.py \ @@ -409,7 +409,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc \ @@ -430,6 +429,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc \ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc \ @@ -796,11 +796,6 @@ build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/ba/__pycache__/_modutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_modutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_multiteamsession.py @echo Compiling script: $^ @@ -901,6 +896,11 @@ build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/modutils.py + @echo Compiling script: $^ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/osmusic.py @echo Compiling script: $^ diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index fa47cde0..2dedcdaa 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -73,7 +73,7 @@ def run_stress_test(playlist_type: str = 'Random', player_count: int = 8, round_duration: int = 30) -> None: """Run a stress test.""" - from ba import _modutils + from ba import modutils from ba._general import Call from ba._enums import TimeType _ba.screenmessage( @@ -90,7 +90,7 @@ def run_stress_test(playlist_type: str = 'Random', _ba.timer(7.0, Call(_ba.screenmessage, ('stats will be written to ' + - _modutils.get_human_readable_user_scripts_path() + + modutils.get_human_readable_user_scripts_path() + '/stress_test_stats.csv')), timetype=TimeType.REAL) diff --git a/assets/src/ba_data/python/ba/_input.py b/assets/src/ba_data/python/ba/_input.py index 403e0a13..c8267b6c 100644 --- a/assets/src/ba_data/python/ba/_input.py +++ b/assets/src/ba_data/python/ba/_input.py @@ -562,8 +562,11 @@ def _gen_android_input_hash() -> str: # (since it'll vary a lot across devices) if f_name == 'gpio-keys.kl': continue - with open(dirname + '/' + f_name, 'rb') as infile: - md5.update(infile.read()) + try: + with open(f'{dirname}/{f_name}', 'rb') as infile: + md5.update(infile.read()) + except PermissionError: + pass except Exception: from ba import _error _error.print_exception( diff --git a/assets/src/ba_data/python/ba/internal.py b/assets/src/ba_data/python/ba/internal.py index a33bee87..958a2580 100644 --- a/assets/src/ba_data/python/ba/internal.py +++ b/assets/src/ba_data/python/ba/internal.py @@ -51,7 +51,6 @@ from ba._benchmark import (run_gpu_benchmark, run_cpu_benchmark, from ba._campaign import getcampaign from ba._messages import PlayerProfilesChangedMessage from ba._meta import get_game_types -from ba._modutils import show_user_scripts from ba._multiteamsession import DEFAULT_TEAM_COLORS, DEFAULT_TEAM_NAMES from ba._music import do_play_music from ba._netutils import serverget, serverput, get_ip_address_type diff --git a/assets/src/ba_data/python/ba/_modutils.py b/assets/src/ba_data/python/ba/modutils.py similarity index 100% rename from assets/src/ba_data/python/ba/_modutils.py rename to assets/src/ba_data/python/ba/modutils.py diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 5284abed..2cbdc6c5 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -53,7 +53,6 @@ class CoopBrowserWindow(ba.Window): def __init__(self, transition: Optional[str] = 'in_right', origin_widget: ba.Widget = None): - # pylint: disable=cyclic-import # pylint: disable=too-many-statements # pylint: disable=cyclic-import import threading diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 6d2da8c3..464f27ee 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1626,6 +1626,7 @@ class GatherWindow(ba.Window): self._call = call def run(self) -> None: + # pylint: disable=too-many-branches ba.app.ping_thread_count += 1 try: import socket @@ -1669,9 +1670,13 @@ class GatherWindow(ba.Window): # Ignore harmless errors. if exc.errno in { - errno.EHOSTUNREACH, errno.ENETUNREACH + errno.EHOSTUNREACH, + errno.ENETUNREACH, }: 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. @@ -1686,8 +1691,10 @@ class GatherWindow(ba.Window): f' for addr {self._address}' f' port {self._port}.') else: - ba.print_exception('Error on gather ping.', - once=True) + ba.print_exception( + f'Error on gather ping ' + f'(errno={exc.errno})', + once=True) except Exception: ba.print_exception('Error on gather ping', once=True) @@ -1776,10 +1783,12 @@ class GatherWindow(ba.Window): text = self._internet_host_status_text if text: if data is None: - ba.textwidget(edit=text, - text=ba.Lstr(resource=self._r + - '.partyStatusNoConnectionText'), - color=(1, 0, 0)) + ba.textwidget( + edit=text, + text=ba.Lstr(resource=self._r + + '.partyStatusNoConnectionText'), + color=(1, 0, 0), + ) else: if not data.get('accessible', False): ex_line: Union[str, ba.Lstr] @@ -1822,10 +1831,11 @@ class GatherWindow(ba.Window): ba.playsound(ba.getsound('shieldDown')) text = self._internet_host_status_text if text: - ba.textwidget(edit=text, - text=ba.Lstr(resource=self._r + - '.partyStatusNotPublicText'), - color=(0.6, 0.6, 0.6)) + ba.textwidget( + edit=text, + text=ba.Lstr(resource=self._r + '.partyStatusNotPublicText'), + color=(0.6, 0.6, 0.6), + ) ba.buttonwidget( edit=self._internet_host_toggle_button, diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index f996d38f..da5c35f3 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -179,7 +179,7 @@ class AdvancedSettingsWindow(ba.Window): # pylint: disable=too-many-branches # pylint: disable=too-many-locals from bastd.ui.config import ConfigCheckBox - from ba.internal import show_user_scripts + from ba.modutils import show_user_scripts # Don't rebuild if the menu is open or if our language and # language-list hasn't changed. diff --git a/docs/ba_module.md b/docs/ba_module.md index 7852b68e..74d484c8 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-21 for Ballistica version 1.5.8 build 20079

    +

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

    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!


    From c18cfeaa29f0389b2c544a8c3876dbc146398c21 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Mon, 22 Jun 2020 15:38:20 +0300 Subject: [PATCH 114/417] add position_center attribute to ba.Node --- assets/src/ba_data/python/_ba.py | 1 + 1 file changed, 1 insertion(+) diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 5d1584da..e9948ae1 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -572,6 +572,7 @@ class Node: color: Sequence[float] = (0.0, 0.0, 0.0) size: Sequence[float] = (0.0, 0.0, 0.0) position: Sequence[float] = (0.0, 0.0, 0.0) + position_center: Sequence[float] = (0.0, 0.0, 0.0) position_forward: Sequence[float] = (0.0, 0.0, 0.0) punch_position: Sequence[float] = (0.0, 0.0, 0.0) punch_velocity: Sequence[float] = (0.0, 0.0, 0.0) From dbeb520a0e5f2a1fe78dfe44b9a7b4a6913ce69a Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Mon, 22 Jun 2020 15:52:47 +0300 Subject: [PATCH 115/417] add optional bomb_scale parameter --- assets/src/ba_data/python/bastd/actor/bomb.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index f5b7743b..9d2ff2a5 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -674,6 +674,7 @@ class Bomb(ba.Actor): velocity: Sequence[float] = (0.0, 0.0, 0.0), bomb_type: str = 'normal', blast_radius: float = 2.0, + bomb_scale: float = 1.0, source_player: ba.Player = None, owner: ba.Node = None): """Create a new Bomb. @@ -693,6 +694,7 @@ class Bomb(ba.Actor): self.bomb_type = bomb_type self._exploded = False + self.scale = bomb_scale self.texture_sequence: Optional[ba.Node] = None @@ -753,6 +755,7 @@ class Bomb(ba.Actor): 'model': factory.land_mine_model, 'light_model': factory.land_mine_model, 'body': 'landMine', + 'body_scale': self.scale, 'shadow_size': 0.44, 'color_texture': factory.land_mine_tex, 'reflection': 'powerup', @@ -770,6 +773,7 @@ class Bomb(ba.Actor): 'model': factory.tnt_model, 'light_model': factory.tnt_model, 'body': 'crate', + 'body_scale': self.scale, 'shadow_size': 0.5, 'color_texture': factory.tnt_tex, 'reflection': 'soft', @@ -785,6 +789,7 @@ class Bomb(ba.Actor): 'position': position, 'velocity': velocity, 'body': 'sphere', + 'body_scale': self.scale, 'model': factory.impact_bomb_model, 'shadow_size': 0.3, 'color_texture': factory.impact_tex, @@ -822,6 +827,7 @@ class Bomb(ba.Actor): 'position': position, 'velocity': velocity, 'model': model, + 'body_scale': self.scale, 'shadow_size': 0.3, 'color_texture': tex, 'sticky': sticky, @@ -846,7 +852,11 @@ class Bomb(ba.Actor): ba.timer(fuse_time, ba.WeakCall(self.handlemessage, ExplodeMessage())) - ba.animate(self.node, 'model_scale', {0: 0, 0.2: 1.3, 0.26: 1}) + ba.animate(self.node, 'model_scale', { + 0: 0, + 0.2: 1.3 * self.scale, + 0.26: self.scale + }) def get_source_player( self, playertype: Type[PlayerType]) -> Optional[PlayerType]: From f6d4a5c9a697448cd2a20786c56dce095f7de432 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 22 Jun 2020 16:00:20 -0700 Subject: [PATCH 116/417] Syncing latest changes between public/private. --- .efrocachemap | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index c0bdfcf3..61e2ef47 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4139,12 +4139,12 @@ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/ef/371aaa27e0f4767cec5fe2117efe", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/59/5f/d25b830965dd26638c8e0cae6d8c", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/99/f2/8a99c79e670fcdde746cfa0dd379", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/77/b3/e2af340577b93d3983550b351604", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/14/f8/fd613804b3b499e12508e9625801", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/21/27/1633ac867e848b68324cae7c5838", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c6/37/5ad49f380196860b49b77b66bc39", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/11/9c8cd8b9b05c00bddf95d9aaf1b3", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/01/73cb3ae73e00f64f2d8bde9ba3d3", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/85/8a/71b0356f1210a32e2314fdbda7f8", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/48/a7/96da0cf90e70d9e7a8661c01d5b9", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9c/5c/49340950cd68dce232fefa47fbaa", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/b6/d2dd933fc479d3c669a4be4cee77" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3d/95/b58293d15e155eef8b98c462c7d7", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/11/76/76e50c02b4f7f430c943cece93f1", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/47/ad/11789f7500317e014c0736ba17b9", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/61/ff/b018bc29b68eee07306ccb3bf1c2" } \ No newline at end of file From 1bbe987f154a73cd00ebed8fde608baeafaa5564 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 22 Jun 2020 18:17:32 -0700 Subject: [PATCH 117/417] Streamlined c++ layer bootstrapping --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 3 +++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 61e2ef47..9b742b51 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/87/4a/c6ce1f7c93d71cd392f32f39346f", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/68/ef/371aaa27e0f4767cec5fe2117efe", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/59/5f/d25b830965dd26638c8e0cae6d8c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/99/f2/8a99c79e670fcdde746cfa0dd379", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/14/f8/fd613804b3b499e12508e9625801", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/21/27/1633ac867e848b68324cae7c5838", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/11/9c8cd8b9b05c00bddf95d9aaf1b3", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/01/73cb3ae73e00f64f2d8bde9ba3d3", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3d/95/b58293d15e155eef8b98c462c7d7", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/11/76/76e50c02b4f7f430c943cece93f1", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/47/ad/11789f7500317e014c0736ba17b9", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/61/ff/b018bc29b68eee07306ccb3bf1c2" + "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" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index f8a5e2e4..c170868b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.10 (20083) +- Streamlined C++ layer bootstrapping process a bit. + ### 1.5.9 (20082) - Reduced some hitches when clicking on certain buttons in the UI - Fixed an issue where very early keyboard/controller connects/disconnects could get lost on android. From 4655cc7391557d2d4001aef7d9aec547d4c25dd0 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 23 Jun 2020 02:10:34 -0700 Subject: [PATCH 118/417] 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!


    From 5f5f07d0f61895f15fcffd73cf20f379209d45a6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 23 Jun 2020 12:42:46 -0700 Subject: [PATCH 119/417] Fixed a freeze in the local network browser --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 3 +++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index eb6aa543..d032547a 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/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" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9a/9a/dbc7632cc645ecf5c273d589a07e", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/7f/b201970d237f95d44199f5fdef71", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/02/81/0b3fe0d185a78f10c8ebfa769330", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/26/d3/a059a63707ec37900feb47754e1b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/cc/1420671159cd408b2e20c2477158", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3c/8e/8f300fccecc01e1f3f59b6cbec8a", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/9b/2e19466672f252b5cef09b69eb7d", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/68/717661df21d3d60d990f9130afb3", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b3/0b/f4457c5ca8f3504bc60fa4fa3eed", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f7/c8/d115c0bdb5caafe21a853917546c", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/6a/8c6c587b254e8450477d55bd4096", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/c9/77494e00a3509ad90581275600d0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ec5bcf28..03b82f89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.11 (20083) +- Fixed a freeze in the local network browser. + ### 1.5.10 (20083) - Streamlined C++ layer bootstrapping process a bit. - Creating sys scripts via ba.modutils now works properly. From e5c4c5ff371402d325b1450f16b6dee13ea4ef53 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 23 Jun 2020 13:04:53 -0700 Subject: [PATCH 120/417] v1.5.11 --- .efrocachemap | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index d032547a..b1f754da 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/9a/9a/dbc7632cc645ecf5c273d589a07e", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/7f/b201970d237f95d44199f5fdef71", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/02/81/0b3fe0d185a78f10c8ebfa769330", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/26/d3/a059a63707ec37900feb47754e1b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/cc/1420671159cd408b2e20c2477158", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3c/8e/8f300fccecc01e1f3f59b6cbec8a", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/9b/2e19466672f252b5cef09b69eb7d", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/87/68/717661df21d3d60d990f9130afb3", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b3/0b/f4457c5ca8f3504bc60fa4fa3eed", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f7/c8/d115c0bdb5caafe21a853917546c", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/6a/8c6c587b254e8450477d55bd4096", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/c9/77494e00a3509ad90581275600d0" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/25/53/7faeb52e734e393cf99fea8eccdc", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/6a/741bc0838174e53dea8af25d2f6e", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/49/18248eac92473bd3b961beadcda4", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/8a/ca68ced1f85746893def0bbe73c7", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1c/09/d8ee3fdc0b76d138174834efed2e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/02/97/fbf3c622030669bbea505987c248", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a9/ec/5f8354b927730c69fe5a681a2ce8", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/8a/b8ae2692dec40600576346298373", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/59/b6/425b5784fb985c2af8bdce7860d7", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4b/3f/6d5a31e33396bc71b5cbb86a8346", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d8/72/f20cfe9a9e6acc8f1f70ae30e64b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/56/aa/58e96b30c8fb93e456165be58ae2" } \ No newline at end of file From 9a12f02689e3cc1793dbe6fcfe679303822fec48 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 24 Jun 2020 16:14:43 -0700 Subject: [PATCH 121/417] Switched windows prefab builds to 32 bit --- .efrocachemap | 24 +++++++++---------- .idea/dictionaries/ericf.xml | 2 ++ CHANGELOG.md | 2 ++ Makefile | 2 +- assets/.asset_manifest_private.json | 2 ++ assets/.asset_manifest_public.json | 4 ++-- assets/Makefile | 18 +++++++------- assets/src/ba_data/python/ba/__init__.py | 5 ++-- assets/src/ba_data/python/ba/_general.py | 14 ++++++----- .../ba/{_gamesettings.py => _settings.py} | 0 docs/ba_module.md | 14 +++++++---- tools/efrotools/code.py | 8 +++++-- tools/stage_assets | 14 ++++++----- 13 files changed, 64 insertions(+), 45 deletions(-) rename assets/src/ba_data/python/ba/{_gamesettings.py => _settings.py} (100%) diff --git a/.efrocachemap b/.efrocachemap index b1f754da..719098f5 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/25/53/7faeb52e734e393cf99fea8eccdc", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/6a/741bc0838174e53dea8af25d2f6e", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/49/18248eac92473bd3b961beadcda4", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/8a/ca68ced1f85746893def0bbe73c7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1c/09/d8ee3fdc0b76d138174834efed2e", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/02/97/fbf3c622030669bbea505987c248", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a9/ec/5f8354b927730c69fe5a681a2ce8", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/74/8a/b8ae2692dec40600576346298373", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/59/b6/425b5784fb985c2af8bdce7860d7", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4b/3f/6d5a31e33396bc71b5cbb86a8346", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d8/72/f20cfe9a9e6acc8f1f70ae30e64b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/56/aa/58e96b30c8fb93e456165be58ae2" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4d/d2/45d06a8dfcde71da3200fd4d2821", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/87/34f9bf38be66b158c9a53536dc41", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/26/59/925cf3b362cde408b96f78fd7b54", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/ad/0650df6bd220bc24ace2817098e8", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/12/89/ec265516675eccf129704a350730", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/72/2afc2855b5f258849c7dc3fda768", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/02/3b/5c9c860eee9be52abe1991534470", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/24/e19eca2f233d1f368e19cd3aa2ff", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/db/fa/5c3fb5069c67a71808927e0bd09e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b3/32/09227cb81f307f0b30978c97b383", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ea/4d/df0cc0ef2649bd8e3fb8ffd658ba", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/23/69b46627e812ff279bf761daf309" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 9299712b..d50ebee8 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -419,6 +419,7 @@ cwdg cxxabi cyaml + cycledelay cygwinccompiler darwiin darwiinremote @@ -2145,6 +2146,7 @@ vtype vval waaah + waittime wanttype wasdead wavenum diff --git a/CHANGELOG.md b/CHANGELOG.md index 03b82f89..7a613136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +### 1.5.12 (20087) + ### 1.5.11 (20083) - Fixed a freeze in the local network browser. diff --git a/Makefile b/Makefile index 79ede417..6519cb8a 100644 --- a/Makefile +++ b/Makefile @@ -327,7 +327,7 @@ build/prefab/linux-server/release/README.txt: \ build/prefab/linux-server/release/dist/ballisticacore_headless: .efrocachemap @tools/snippets efrocache_get $@ -PREFAB_WINDOWS_PLATFORM = x64 +PREFAB_WINDOWS_PLATFORM = Win32 RUN_PREFAB_WINDOWS_DEBUG = cd build/prefab/windows/debug && ./BallisticaCore.exe diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json index d782cc5a..b2e11385 100644 --- a/assets/.asset_manifest_private.json +++ b/assets/.asset_manifest_private.json @@ -5665,11 +5665,13 @@ "windows/Win32/SDL2.dll", "windows/Win32/libvorbis.dll", "windows/Win32/libvorbisfile.dll", + "windows/Win32/msvcp140d.dll", "windows/Win32/ogg.dll", "windows/Win32/python.exe", "windows/Win32/python37.dll", "windows/Win32/pythonw.exe", "windows/Win32/vc_redist.x86.exe", + "windows/Win32/vcruntime140d.dll", "windows/x64/DLLs/_asyncio.pyd", "windows/x64/DLLs/_bz2.pyd", "windows/x64/DLLs/_ctypes.pyd", diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index be327ba4..87802e0c 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -24,7 +24,6 @@ "ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc", @@ -47,6 +46,7 @@ "ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc", @@ -81,7 +81,6 @@ "ba_data/python/ba/_freeforallsession.py", "ba_data/python/ba/_gameactivity.py", "ba_data/python/ba/_gameresults.py", - "ba_data/python/ba/_gamesettings.py", "ba_data/python/ba/_gameutils.py", "ba_data/python/ba/_general.py", "ba_data/python/ba/_hooks.py", @@ -104,6 +103,7 @@ "ba_data/python/ba/_score.py", "ba_data/python/ba/_servermode.py", "ba_data/python/ba/_session.py", + "ba_data/python/ba/_settings.py", "ba_data/python/ba/_stats.py", "ba_data/python/ba/_store.py", "ba_data/python/ba/_team.py", diff --git a/assets/Makefile b/assets/Makefile index 69839ee2..4d3ec9ce 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -166,7 +166,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_freeforallsession.py \ build/ba_data/python/ba/_gameactivity.py \ build/ba_data/python/ba/_gameresults.py \ - build/ba_data/python/ba/_gamesettings.py \ build/ba_data/python/ba/_gameutils.py \ build/ba_data/python/ba/_general.py \ build/ba_data/python/ba/_hooks.py \ @@ -189,6 +188,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_score.py \ build/ba_data/python/ba/_servermode.py \ build/ba_data/python/ba/_session.py \ + build/ba_data/python/ba/_settings.py \ build/ba_data/python/ba/_stats.py \ build/ba_data/python/ba/_store.py \ build/ba_data/python/ba/_team.py \ @@ -397,7 +397,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc \ @@ -420,6 +419,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc \ @@ -736,11 +736,6 @@ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ -build/ba_data/python/ba/__pycache__/_gamesettings.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gamesettings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ - build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameutils.py @echo Compiling script: $^ @@ -851,6 +846,11 @@ build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc: \ @echo Compiling script: $^ @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ +build/ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc: \ + build/ba_data/python/ba/_settings.py + @echo Compiling script: $^ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_stats.py @echo Compiling script: $^ @@ -20030,11 +20030,13 @@ EXTRAS_TARGETS_WIN_WIN32 = \ build/windows/Win32/SDL2.dll \ build/windows/Win32/libvorbis.dll \ build/windows/Win32/libvorbisfile.dll \ + build/windows/Win32/msvcp140d.dll \ build/windows/Win32/ogg.dll \ build/windows/Win32/python.exe \ build/windows/Win32/python37.dll \ build/windows/Win32/pythonw.exe \ - build/windows/Win32/vc_redist.x86.exe + build/windows/Win32/vc_redist.x86.exe \ + build/windows/Win32/vcruntime140d.dll # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_WIN32) : ../.efrocachemap diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index d257eca7..44ed439e 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -56,9 +56,8 @@ from ba._error import ( from ba._freeforallsession import FreeForAllSession from ba._gameactivity import GameActivity from ba._gameresults import GameResults -from ba._gamesettings import (Setting, IntSetting, FloatSetting, ChoiceSetting, - BoolSetting, IntChoiceSetting, - FloatChoiceSetting) +from ba._settings import (Setting, IntSetting, FloatSetting, ChoiceSetting, + BoolSetting, IntChoiceSetting, FloatChoiceSetting) from ba._lang import Lstr, setlanguage, get_valid_languages from ba._map import Map, getmaps from ba._session import Session diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 7b4b87c9..82cc917b 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -188,9 +188,10 @@ class _WeakCall: """ def __init__(self, *args: Any, **keywds: Any) -> None: - """ - Instantiate a WeakCall; pass a callable as the first - arg, followed by any number of arguments or keywords. + """Instantiate a WeakCall. + + Pass a callable as the first arg, followed by any number of + arguments or keywords. # Example: wrap a method call with some positional and # keyword args: @@ -240,9 +241,10 @@ class _Call: """ def __init__(self, *args: Any, **keywds: Any): - """ - Instantiate a Call; pass a callable as the first - arg, followed by any number of arguments or keywords. + """Instantiate a Call. + + Pass a callable as the first arg, followed by any number of + arguments or keywords. # Example: wrap a method call with 1 positional and 1 keyword arg: mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2) diff --git a/assets/src/ba_data/python/ba/_gamesettings.py b/assets/src/ba_data/python/ba/_settings.py similarity index 100% rename from assets/src/ba_data/python/ba/_gamesettings.py rename to assets/src/ba_data/python/ba/_settings.py diff --git a/docs/ba_module.md b/docs/ba_module.md index 488ff5a7..90607238 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

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

    +

    last updated on 2020-06-24 for Ballistica version 1.5.12 build 20088

    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!


    @@ -1214,8 +1214,10 @@ when done.

    <constructor>

    ba.Call(*args: Any, **keywds: Any)

    -

    Instantiate a Call; pass a callable as the first -arg, followed by any number of arguments or keywords.

    +

    Instantiate a Call.

    + +

    Pass a callable as the first arg, followed by any number of +arguments or keywords.

    # Example: wrap a method call with 1 positional and 1 keyword arg:
     mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2)
    @@ -5756,8 +5758,10 @@ self.t = ba.Timer(0.3, say_it, repeat=True)

    <constructor>

    ba.WeakCall(*args: Any, **keywds: Any)

    -

    Instantiate a WeakCall; pass a callable as the first -arg, followed by any number of arguments or keywords.

    +

    Instantiate a WeakCall.

    + +

    Pass a callable as the first arg, followed by any number of +arguments or keywords.

    # Example: wrap a method call with some positional and
     # keyword args:
    diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py
    index a7518aa1..ea3b4d53 100644
    --- a/tools/efrotools/code.py
    +++ b/tools/efrotools/code.py
    @@ -856,7 +856,7 @@ def clioncode(projroot: Path, full: bool, verbose: bool) -> None:
         # reason too.
         # So for now let's try blowing away caches, launching the gui
         # temporarily, and then kicking off inspections after that. Sigh.
    -    print('Clearing clion caches...', flush=True)
    +    print('Clearing CLion caches...', flush=True)
         subprocess.run('rm -rf ~/Library/Caches/CLion*', shell=True, check=True)
     
         # Note: I'm assuming this project needs to be open when the GUI
    @@ -866,7 +866,11 @@ def clioncode(projroot: Path, full: bool, verbose: bool) -> None:
         process = subprocess.Popen(str(clionbin))
     
         # Wait a moment and ask it nicely to die.
    -    time.sleep(120)
    +    waittime = 120
    +    while waittime > 0:
    +        print(f'Waiting for {waittime} more seconds.')
    +        time.sleep(10)
    +        waittime -= 10
     
         # Seems killing it via applescript is more likely to leave it
         # in a working state for offline inspections than TERM signal..
    diff --git a/tools/stage_assets b/tools/stage_assets
    index 8aed0567..d412ee20 100755
    --- a/tools/stage_assets
    +++ b/tools/stage_assets
    @@ -281,12 +281,14 @@ def _sync_windows_extras(cfg: Config) -> None:
         elif cfg.win_type == 'winserver':
             toplevelfiles += ['python.exe']
     
    -    # Include debug dlls for x64 so folks without msvc can run them.
    -    # (seems win32 doesn't have the same set so ignoring that for now)
    -    if cfg.debug and cfg.win_platform == 'x64':
    -        toplevelfiles += [
    -            'msvcp140d.dll', 'vcruntime140d.dll', 'vcruntime140_1d.dll'
    -        ]
    +    # Include debug dlls so folks without msvc can run them.
    +    if cfg.debug:
    +        if cfg.win_platform == 'x64':
    +            toplevelfiles += [
    +                'msvcp140d.dll', 'vcruntime140d.dll', 'vcruntime140_1d.dll'
    +            ]
    +        else:
    +            toplevelfiles += ['msvcp140d.dll', 'vcruntime140d.dll']
     
         # Include the runtime redistributables in release builds.
         if not cfg.debug:
    
    From 6301b8ed0cc021c508c2232a056f10536c3b5feb Mon Sep 17 00:00:00 2001
    From: Eric Froemling 
    Date: Thu, 25 Jun 2020 20:27:15 -0700
    Subject: [PATCH 122/417] Work on error/crash reporting
    
    ---
     .efrocachemap                                 | 24 +++++------
     .idea/dictionaries/ericf.xml                  |  4 ++
     assets/src/ba_data/python/ba/_apputils.py     |  8 ++--
     assets/src/ba_data/python/ba/_netutils.py     |  6 +--
     assets/src/ba_data/python/ba/_servermode.py   |  4 +-
     assets/src/ba_data/python/ba/internal.py      |  3 +-
     .../ba_data/python/bastd/ui/account/viewer.py |  6 +--
     assets/src/ba_data/python/bastd/ui/gather.py  | 15 +++----
     .../ba_data/python/bastd/ui/getcurrency.py    |  7 ++--
     .../python/bastd/ui/profile/upgrade.py        |  6 +--
     .../python/bastd/ui/settings/advanced.py      |  6 +--
     .../python/bastd/ui/settings/gamepad.py       |  4 +-
     .../python/bastd/ui/settings/keyboard.py      |  4 +-
     .../ba_data/python/bastd/ui/specialoffer.py   | 41 ++++++++++++-------
     .../ba_data/python/bastd/ui/store/browser.py  |  4 +-
     docs/ba_module.md                             |  2 +-
     tools/batools/snippets.py                     | 35 ++++++++++++++++
     tools/efrotools/snippets.py                   |  5 ++-
     tools/snippets                                |  2 +-
     19 files changed, 120 insertions(+), 66 deletions(-)
    
    diff --git a/.efrocachemap b/.efrocachemap
    index 719098f5..fbd821e4 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/4d/d2/45d06a8dfcde71da3200fd4d2821",
    -  "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/87/34f9bf38be66b158c9a53536dc41",
    -  "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/26/59/925cf3b362cde408b96f78fd7b54",
    -  "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/ad/0650df6bd220bc24ace2817098e8",
    -  "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/12/89/ec265516675eccf129704a350730",
    -  "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/72/2afc2855b5f258849c7dc3fda768",
    -  "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/02/3b/5c9c860eee9be52abe1991534470",
    -  "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/24/e19eca2f233d1f368e19cd3aa2ff",
    -  "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/db/fa/5c3fb5069c67a71808927e0bd09e",
    -  "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b3/32/09227cb81f307f0b30978c97b383",
    -  "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ea/4d/df0cc0ef2649bd8e3fb8ffd658ba",
    -  "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/69/23/69b46627e812ff279bf761daf309"
    +  "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/83/b0/c0963abb0e6f5628742e1de7b890",
    +  "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6a/63/fe355b556462b609f26cebc4a140",
    +  "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/0a/de33d78be9b5f7a31af4f5181d43",
    +  "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/4e/a08641d6e81bbca74c24bf364f59",
    +  "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/b1/8648ef7e0060d0b1b3716893d389",
    +  "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/b5/a5233e4efdf0420f43759e2c9f8e",
    +  "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f6/62/ac74aa6cb053cdd0486826d580f1",
    +  "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/21/817d17de9b85320710e57b3e8882",
    +  "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/d6/2ba38ece384d512820ef64c8e748",
    +  "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/06/44/6daa364334ae5f7ac23ad565cd79",
    +  "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b1/28/6ceb93f662ea36958b573ea6e761",
    +  "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b4/34/81b1bb50eece76cfa2163a9fdcba"
     }
    \ No newline at end of file
    diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml
    index d50ebee8..9d6534a6 100644
    --- a/.idea/dictionaries/ericf.xml
    +++ b/.idea/dictionaries/ericf.xml
    @@ -15,6 +15,7 @@
           aarch
           abcdefghijklmnopqrstuvwxyz
           abeb
    +      abishort
           abot
           abtn
           accesstime
    @@ -433,6 +434,7 @@
           daynum
           dayoffset
           dbapi
    +      dbase
           dbpath
           dcls
           dcmake
    @@ -1046,6 +1048,7 @@
           lfval
           libcrypto
           libegl
    +      libext
           libgen
           libinst
           liblzma
    @@ -2087,6 +2090,7 @@
           unranked
           unstaged
           unstripped
    +      unstrl
           unsubscriptable
           untracked
           upcase
    diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py
    index dcecd42c..d98cea00 100644
    --- a/assets/src/ba_data/python/ba/_apputils.py
    +++ b/assets/src/ba_data/python/ba/_apputils.py
    @@ -73,7 +73,7 @@ def handle_log() -> None:
         When this happens, we can upload our log to the server
         after a short bit if desired.
         """
    -    from ba._netutils import serverput
    +    from ba._netutils import master_server_post
         from ba._enums import TimeType
         app = _ba.app
         app.log_have_new = True
    @@ -111,7 +111,7 @@ def handle_log() -> None:
                         app.log_have_new = False
                         _ba.mark_log_sent()
     
    -            serverput('bsLog', info, response)
    +            master_server_post('bsLog', info, response)
     
             app.log_upload_timer_started = True
     
    @@ -138,7 +138,7 @@ def handle_leftover_log_file() -> None:
         """Handle an un-uploaded log from a previous run."""
         try:
             import json
    -        from ba._netutils import serverput
    +        from ba._netutils import master_server_post
     
             if os.path.exists(_ba.get_log_file_path()):
                 with open(_ba.get_log_file_path()) as infile:
    @@ -159,7 +159,7 @@ def handle_leftover_log_file() -> None:
                                 # killed it since. ¯\_(ツ)_/¯
                                 pass
     
    -                serverput('bsLog', info, response)
    +                master_server_post('bsLog', info, response)
                 else:
                     # If they don't want logs uploaded just kill it.
                     os.remove(_ba.get_log_file_path())
    diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py
    index 08a41f82..ea138d01 100644
    --- a/assets/src/ba_data/python/ba/_netutils.py
    +++ b/assets/src/ba_data/python/ba/_netutils.py
    @@ -114,8 +114,6 @@ class ServerCallThread(threading.Thread):
             try:
                 self._data = _general.utf8_all(self._data)
                 _ba.set_thread_name('BA_ServerCallThread')
    -
    -            # Seems pycharm doesn't know about urllib.parse.
                 parse = urllib.parse
                 if self._request_type == 'get':
                     response = urllib.request.urlopen(
    @@ -181,7 +179,7 @@ class ServerCallThread(threading.Thread):
                              from_other_thread=True)
     
     
    -def serverget(
    +def master_server_get(
             request: str,
             data: Dict[str, Any],
             callback: Optional[ServerCallbackType] = None,
    @@ -190,7 +188,7 @@ def serverget(
         ServerCallThread(request, 'get', data, callback, response_type).start()
     
     
    -def serverput(
    +def master_server_post(
             request: str,
             data: Dict[str, Any],
             callback: Optional[ServerCallbackType] = None,
    diff --git a/assets/src/ba_data/python/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py
    index 47beb6c9..653a1510 100644
    --- a/assets/src/ba_data/python/ba/_servermode.py
    +++ b/assets/src/ba_data/python/ba/_servermode.py
    @@ -204,8 +204,8 @@ class ServerController:
     
         def _run_access_check(self) -> None:
             """Check with the master server to see if we're likely joinable."""
    -        from ba._netutils import serverget
    -        serverget(
    +        from ba._netutils import master_server_get
    +        master_server_get(
                 'bsAccessCheck',
                 {
                     'port': _ba.get_game_port(),
    diff --git a/assets/src/ba_data/python/ba/internal.py b/assets/src/ba_data/python/ba/internal.py
    index 958a2580..4ac5d01b 100644
    --- a/assets/src/ba_data/python/ba/internal.py
    +++ b/assets/src/ba_data/python/ba/internal.py
    @@ -53,7 +53,8 @@ from ba._messages import PlayerProfilesChangedMessage
     from ba._meta import get_game_types
     from ba._multiteamsession import DEFAULT_TEAM_COLORS, DEFAULT_TEAM_NAMES
     from ba._music import do_play_music
    -from ba._netutils import serverget, serverput, get_ip_address_type
    +from ba._netutils import (master_server_get, master_server_post,
    +                          get_ip_address_type)
     from ba._powerup import get_default_powerup_distribution
     from ba._profile import (get_player_profile_colors, get_player_profile_icon,
                              get_player_colors)
    diff --git a/assets/src/ba_data/python/bastd/ui/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py
    index 7bc137f9..5a61b9db 100644
    --- a/assets/src/ba_data/python/bastd/ui/account/viewer.py
    +++ b/assets/src/ba_data/python/bastd/ui/account/viewer.py
    @@ -41,7 +41,7 @@ class AccountViewerWindow(popup.PopupWindow):
                      position: Tuple[float, float] = (0.0, 0.0),
                      scale: float = None,
                      offset: Tuple[float, float] = (0.0, 0.0)):
    -        from ba.internal import is_browser_likely_available, serverget
    +        from ba.internal import is_browser_likely_available, master_server_get
     
             self._account_id = account_id
             self._profile_id = profile_id
    @@ -124,12 +124,12 @@ class AccountViewerWindow(popup.PopupWindow):
             ba.containerwidget(edit=self.root_widget,
                                cancel_button=self._cancel_button)
     
    -        serverget('bsAccountInfo', {
    +        master_server_get('bsAccountInfo', {
                 'buildNumber': ba.app.build_number,
                 'accountID': self._account_id,
                 'profileID': self._profile_id
             },
    -                  callback=ba.WeakCall(self._on_query_response))
    +                          callback=ba.WeakCall(self._on_query_response))
     
         def popup_menu_selected_choice(self, window: popup.PopupMenu,
                                        choice: str) -> None:
    diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py
    index 8edcdd24..a9b93207 100644
    --- a/assets/src/ba_data/python/bastd/ui/gather.py
    +++ b/assets/src/ba_data/python/bastd/ui/gather.py
    @@ -1725,14 +1725,14 @@ class GatherWindow(ba.Window):
                     self._rebuild_public_party_list()
     
         def _do_internet_status_check(self) -> None:
    -        from ba.internal import serverget
    +        from ba.internal import master_server_get
             ba.textwidget(edit=self._internet_host_status_text,
                           color=(1, 1, 0),
                           text=ba.Lstr(resource=self._r +
                                        '.partyStatusCheckingText'))
    -        serverget('bsAccessCheck', {'b': ba.app.build_number},
    -                  callback=ba.WeakCall(
    -                      self._on_public_party_accessible_response))
    +        master_server_get('bsAccessCheck', {'b': ba.app.build_number},
    +                          callback=ba.WeakCall(
    +                              self._on_public_party_accessible_response))
     
         def _on_start_internet_advertizing_press(self) -> None:
             from bastd.ui import account
    @@ -1843,7 +1843,7 @@ class GatherWindow(ba.Window):
     
         def _access_check_update(self, t_addr: ba.Widget, t_accessible: ba.Widget,
                                  t_accessible_extra: ba.Widget) -> None:
    -        from ba.internal import serverget
    +        from ba.internal import master_server_get
     
             # If we don't have an outstanding query, start one..
             assert self._doing_access_check is not None
    @@ -1854,8 +1854,9 @@ class GatherWindow(ba.Window):
                 self._t_addr = t_addr
                 self._t_accessible = t_accessible
                 self._t_accessible_extra = t_accessible_extra
    -            serverget('bsAccessCheck', {'b': ba.app.build_number},
    -                      callback=ba.WeakCall(self._on_accessible_response))
    +            master_server_get('bsAccessCheck', {'b': ba.app.build_number},
    +                              callback=ba.WeakCall(
    +                                  self._on_accessible_response))
     
         def _on_accessible_response(self, data: Optional[Dict[str, Any]]) -> None:
             t_addr = self._t_addr
    diff --git a/assets/src/ba_data/python/bastd/ui/getcurrency.py b/assets/src/ba_data/python/bastd/ui/getcurrency.py
    index b25457cb..429cd52b 100644
    --- a/assets/src/ba_data/python/bastd/ui/getcurrency.py
    +++ b/assets/src/ba_data/python/bastd/ui/getcurrency.py
    @@ -523,7 +523,7 @@ class GetCurrencyWindow(ba.Window):
         def _purchase(self, item: str) -> None:
             from bastd.ui import account
             from bastd.ui import appinvite
    -        from ba.internal import serverget
    +        from ba.internal import master_server_get
             if item == 'app_invite':
                 if _ba.get_account_state() != 'signed_in':
                     account.show_sign_in_prompt()
    @@ -533,14 +533,15 @@ class GetCurrencyWindow(ba.Window):
             # here we ping the server to ask if it's valid for us to
             # purchase this.. (better to fail now than after we've paid locally)
             app = ba.app
    -        serverget('bsAccountPurchaseCheck', {
    +        master_server_get('bsAccountPurchaseCheck', {
                 'item': item,
                 'platform': app.platform,
                 'subplatform': app.subplatform,
                 'version': app.version,
                 'buildNumber': app.build_number
             },
    -                  callback=ba.WeakCall(self._purchase_check_result, item))
    +                          callback=ba.WeakCall(self._purchase_check_result,
    +                                               item))
     
         def _purchase_check_result(self, item: str,
                                    result: Optional[Dict[str, Any]]) -> None:
    diff --git a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py
    index 86ccaf07..62cebcf0 100644
    --- a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py
    +++ b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py
    @@ -40,7 +40,7 @@ class ProfileUpgradeWindow(ba.Window):
         def __init__(self,
                      edit_profile_window: EditProfileWindow,
                      transition: str = 'in_right'):
    -        from ba.internal import serverget
    +        from ba.internal import master_server_get
             self._r = 'editProfileWindow'
     
             self._width = 680
    @@ -138,11 +138,11 @@ class ProfileUpgradeWindow(ba.Window):
             else:
                 self._tickets_text = None
     
    -        serverget('bsGlobalProfileCheck', {
    +        master_server_get('bsGlobalProfileCheck', {
                 'name': self._name,
                 'b': ba.app.build_number
             },
    -                  callback=ba.WeakCall(self._profile_check_result))
    +                          callback=ba.WeakCall(self._profile_check_result))
             self._cost = _ba.get_account_misc_read_val('price.global_profile', 500)
             self._status: Optional[str] = 'waiting'
             self._update_timer = ba.Timer(1.0,
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py
    index da5c35f3..f9205206 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py
    @@ -39,7 +39,7 @@ class AdvancedSettingsWindow(ba.Window):
                      transition: str = 'in_right',
                      origin_widget: ba.Widget = None):
             # pylint: disable=too-many-statements
    -        from ba.internal import serverget
    +        from ba.internal import master_server_get
     
             app = ba.app
     
    @@ -151,8 +151,8 @@ class AdvancedSettingsWindow(ba.Window):
                                            timetype=ba.TimeType.REAL)
     
             # Fetch the list of completed languages.
    -        serverget('bsLangGetCompleted', {'b': app.build_number},
    -                  callback=ba.WeakCall(self._completed_langs_cb))
    +        master_server_get('bsLangGetCompleted', {'b': app.build_number},
    +                          callback=ba.WeakCall(self._completed_langs_cb))
     
         def _update_lang_status(self) -> None:
             if self._complete_langs_list is not None:
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py
    index 62545869..406bee3d 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py
    @@ -717,7 +717,7 @@ class GamepadSettingsWindow(ba.Window):
                     transition='in_left').get_root_widget())
     
         def _save(self) -> None:
    -        from ba.internal import (serverput, get_input_device_config,
    +        from ba.internal import (master_server_post, get_input_device_config,
                                      get_input_map_hash, should_submit_debug_info)
             ba.containerwidget(edit=self._root_widget,
                                transition=self._transition_out)
    @@ -742,7 +742,7 @@ class GamepadSettingsWindow(ba.Window):
                 # generate more defaults in the future.
                 inputhash = get_input_map_hash(self._input)
                 if should_submit_debug_info():
    -                serverput(
    +                master_server_post(
                         'controllerConfig', {
                             'ua': ba.app.user_agent_string,
                             'b': ba.app.build_number,
    diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py
    index 340a5446..407b4d56 100644
    --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py
    +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py
    @@ -230,7 +230,7 @@ class ConfigKeyboardWindow(ba.Window):
         def _save(self) -> None:
             from bastd.ui.settings.controls import ControlsSettingsWindow
             from ba.internal import (get_input_device_config,
    -                                 should_submit_debug_info, serverput)
    +                                 should_submit_debug_info, master_server_post)
     
             ba.containerwidget(edit=self._root_widget, transition='out_right')
             ba.playsound(ba.getsound('gunCocking'))
    @@ -246,7 +246,7 @@ class ConfigKeyboardWindow(ba.Window):
             # If we're allowed to phone home, send this config so we can generate
             # more defaults in the future.
             if should_submit_debug_info():
    -            serverput(
    +            master_server_post(
                     'controllerConfig', {
                         'ua': ba.app.user_agent_string,
                         'name': self._name,
    diff --git a/assets/src/ba_data/python/bastd/ui/specialoffer.py b/assets/src/ba_data/python/bastd/ui/specialoffer.py
    index 6c9169e7..80c6bf20 100644
    --- a/assets/src/ba_data/python/bastd/ui/specialoffer.py
    +++ b/assets/src/ba_data/python/bastd/ui/specialoffer.py
    @@ -56,11 +56,15 @@ class SpecialOfferWindow(ba.Window):
                 real_price = _ba.get_price('pro' if offer['item'] ==
                                            'pro_fullprice' else 'pro_sale')
                 if real_price is None and ba.app.debug_build:
    -                print('TEMP FAKING REAL PRICE')
    +                print('NOTE: Faking prices for debug build.')
                     real_price = '$1.23'
                 zombie = real_price is None
    -        elif isinstance(offer['price'], str):  # a string price implies IAP id
    +        elif isinstance(offer['price'], str):
    +            # (a string price implies IAP id)
                 real_price = _ba.get_price(offer['price'])
    +            if real_price is None and ba.app.debug_build:
    +                print('NOTE: Faking price for debug build.')
    +                real_price = '$1.23'
                 zombie = real_price is None
             else:
                 real_price = None
    @@ -109,16 +113,25 @@ class SpecialOfferWindow(ba.Window):
                         self._is_bundle_sale = True
                     original_price = _ba.get_account_misc_read_val(
                         'price.' + self._offer_item, 9999)
    -                new_price = offer['price']
    -                tchar = ba.charstr(SpecialChar.TICKET)
    -                original_price_str = tchar + str(original_price)
    -                new_price_str = tchar + str(new_price)
    -                percent_off = int(
    -                    round(100.0 - (float(new_price) / original_price) * 100.0))
    -                percent_off_text = ' ' + ba.Lstr(
    -                    resource='store.salePercentText').evaluate().replace(
    -                        '${PERCENT}', str(percent_off))
    +
    +                # For pure ticket prices we can show a percent-off.
    +                if isinstance(offer['price'], int):
    +                    new_price = offer['price']
    +                    tchar = ba.charstr(SpecialChar.TICKET)
    +                    original_price_str = tchar + str(original_price)
    +                    new_price_str = tchar + str(new_price)
    +                    percent_off = int(
    +                        round(100.0 -
    +                              (float(new_price) / original_price) * 100.0))
    +                    percent_off_text = ' ' + ba.Lstr(
    +                        resource='store.salePercentText').evaluate().replace(
    +                            '${PERCENT}', str(percent_off))
    +                else:
    +                    original_price_str = new_price_str = '?'
    +                    percent_off_text = ''
    +
             except Exception:
    +            print(f'Offer: {offer}')
                 ba.print_exception('Error setting up special-offer')
                 original_price_str = new_price_str = '?'
                 percent_off_text = ''
    @@ -211,8 +224,8 @@ class SpecialOfferWindow(ba.Window):
                 total_worth_item = offer.get('valueItem', None)
                 if total_worth_item is not None:
                     price = _ba.get_price(total_worth_item)
    -                assert price is not None
    -                total_worth_price = get_clean_price(price)
    +                total_worth_price = (get_clean_price(price)
    +                                     if price is not None else None)
                     if total_worth_price is not None:
                         total_worth_text = ba.Lstr(resource='store.totalWorthText',
                                                    subs=[('${TOTAL_WORTH}',
    @@ -246,7 +259,7 @@ class SpecialOfferWindow(ba.Window):
                               text=new_price_str)
     
             # Add ticket button only if this is ticket-purchasable.
    -        if offer['price'] is not None and isinstance(offer['price'], int):
    +        if isinstance(offer.get('price'), int):
                 self._get_tickets_button = ba.buttonwidget(
                     parent=self._root_widget,
                     position=(self._width - 125, self._height - 68),
    diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py
    index 59ad1d34..d8677e7b 100644
    --- a/assets/src/ba_data/python/bastd/ui/store/browser.py
    +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py
    @@ -449,13 +449,13 @@ class StoreBrowserWindow(ba.Window):
         def _do_purchase_check(self,
                                item: str,
                                is_ticket_purchase: bool = False) -> None:
    -        from ba.internal import serverget
    +        from ba.internal import master_server_get
     
             # Here we ping the server to ask if it's valid for us to
             # purchase this. Better to fail now than after we've
             # paid locally.
             app = ba.app
    -        serverget(
    +        master_server_get(
                 'bsAccountPurchaseCheck',
                 {
                     'item': item,
    diff --git a/docs/ba_module.md b/docs/ba_module.md
    index 90607238..4465d271 100644
    --- a/docs/ba_module.md
    +++ b/docs/ba_module.md
    @@ -1,5 +1,5 @@
     
    -

    last updated on 2020-06-24 for Ballistica version 1.5.12 build 20088

    +

    last updated on 2020-06-25 for Ballistica version 1.5.12 build 20089

    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!


    diff --git a/tools/batools/snippets.py b/tools/batools/snippets.py index 7324cc21..57e11240 100644 --- a/tools/batools/snippets.py +++ b/tools/batools/snippets.py @@ -616,3 +616,38 @@ def lazybuild() -> None: batools.build.lazybuild(target, category, command) except subprocess.CalledProcessError as exc: raise CleanError(exc) + + +def android_archive_unstripped_libs() -> None: + """Copy libs to a build archive.""" + import subprocess + from pathlib import Path + from efro.error import CleanError + from efro.terminal import Clr + if len(sys.argv) != 4: + raise CleanError('Expected 2 args; src-dir and dst-dir') + src = Path(sys.argv[2]) + dst = Path(sys.argv[3]) + if dst.exists(): + subprocess.run(['rm', '-rf', dst], check=True) + dst.mkdir(parents=True, exist_ok=True) + if not src.is_dir(): + raise CleanError(f"Source dir not found: '{src}'") + libname = 'libmain' + libext = '.so' + for abi, abishort in [ + ('armeabi-v7a', 'arm'), + ('arm64-v8a', 'arm64'), + ('x86', 'x86'), + ('x86_64', 'x86-64'), + ]: + srcpath = Path(src, abi, libname + libext) + dstname = f'{libname}_{abishort}{libext}' + dstpath = Path(dst, dstname) + if srcpath.exists(): + print(f'Archiving unstripped library: {Clr.BLD}{dstname}{Clr.RST}') + subprocess.run(['cp', srcpath, dstpath], check=True) + subprocess.run(['tar', '-zcf', dstname + '.tgz', dstname], + cwd=dst, + check=True) + subprocess.run(['rm', dstpath], check=True) diff --git a/tools/efrotools/snippets.py b/tools/efrotools/snippets.py index a68005c4..da95b003 100644 --- a/tools/efrotools/snippets.py +++ b/tools/efrotools/snippets.py @@ -79,8 +79,9 @@ def snippets_main(globs: Dict[str, Any]) -> None: exc.pretty_print() sys.exit(1) else: - print('Unknown snippets command: "' + sys.argv[1] + '"', - file=sys.stderr) + print( + f'{Clr.RED}Unknown snippets command: "{sys.argv[1]}"{Clr.RST}', + file=sys.stderr) retval = 255 if show_help: diff --git a/tools/snippets b/tools/snippets index 7a5d17eb..ebe46596 100755 --- a/tools/snippets +++ b/tools/snippets @@ -54,7 +54,7 @@ from batools.snippets import ( python_gather, capitalize, efrocache_update, efrocache_get, get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, - make_prefab, update_makebob, lazybuild) + make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs) # pylint: enable=unused-import if TYPE_CHECKING: From c38ae5c39b3cc7985be166a959245ca060d3bf31 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 26 Jun 2020 01:59:50 -0700 Subject: [PATCH 123/417] v1.5.13 --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 6 ++++++ tools/batools/android.py | 8 ++++++-- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index fbd821e4..40a6344f 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/83/b0/c0963abb0e6f5628742e1de7b890", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6a/63/fe355b556462b609f26cebc4a140", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/0a/de33d78be9b5f7a31af4f5181d43", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/4e/a08641d6e81bbca74c24bf364f59", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/b1/8648ef7e0060d0b1b3716893d389", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/b5/a5233e4efdf0420f43759e2c9f8e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f6/62/ac74aa6cb053cdd0486826d580f1", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/21/817d17de9b85320710e57b3e8882", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/d6/2ba38ece384d512820ef64c8e748", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/06/44/6daa364334ae5f7ac23ad565cd79", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b1/28/6ceb93f662ea36958b573ea6e761", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b4/34/81b1bb50eece76cfa2163a9fdcba" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/21/b9/84344d916a526f3144eda007f245", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/c1/8d69797934e136feb17a400fcf8d", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/06/98/94acb9d29ca85a01edf3ba935e99", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/e5/317de6a4ea73cb9c4fe895a5ed66", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/75/35/61423ae280cfab87ee73bf7e1c34", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/ab/08821599d02ec46e83814dcfbab3", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/de/77af3bf69b95e04d7a49d7d606a9", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/f8/7bafd47112eb99ede6c817f12704", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/41/ee/0dbd6c907c45ed6c27e26657fe5a", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cf/ac/4b84bdeaa0dfe5f9b2990c8094b6", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fc/bd/52a82497581428fc1fe6cb1f7db1", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9d/6c/714e999d02c4ea913159d62692c0" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a613136..86f79f5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,10 @@ +### 1.5.13 (20095) +- Hopefully fixed an elusive random crash on android that popped up recently. +- Misc bug fixes. + ### 1.5.12 (20087) +- Improved exception handling and crash reporting. +- Misc bug fixes. ### 1.5.11 (20083) - Fixed a freeze in the local network browser. diff --git a/tools/batools/android.py b/tools/batools/android.py index 8fe178d9..08396d90 100644 --- a/tools/batools/android.py +++ b/tools/batools/android.py @@ -74,9 +74,13 @@ def androidaddr(archive_dir: str, arch: str, addr: str) -> None: ['find', os.path.join(ndkpath, 'toolchains'), '-name', '*addr2line']).decode().strip().splitlines() - lines = [line for line in lines if archs[arch]['prefix'] in line] + # print('RAW LINES', lines) + lines = [ + line for line in lines + if archs[arch]['prefix'] in line and '/llvm/' in line + ] if len(lines) != 1: - print("ERROR: couldn't find addr2line binary") + print(f"ERROR: can't find addr2line binary ({len(lines)} options).") sys.exit(255) addr2line = lines[0] efrotools.run('mkdir -p "' + os.path.join(rootdir, 'android_addr_tmp') + From 3ffeff8ce401a00128363ff08b406471092adaa9 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 30 Jun 2020 22:43:13 -0700 Subject: [PATCH 124/417] v1.5.16 --- .efrocachemap | 32 ++++++++++++++++---------------- CHANGELOG.md | 7 +++++++ docs/ba_module.md | 2 +- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 40a6344f..8c3d924c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,8 +420,8 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/b6/af/5d10baf9fdb9b9a48ab0b1cd24bb", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/b8/ed/e18bec56ff1d094aae86517a7854", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/91/cc/22cdc1ce692de2cba974bd095d8b", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/4c/ca/1e38748da251895ca11dcdc87107", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/21/38/7e50214f79088f55c6e059fd33d2", @@ -438,7 +438,7 @@ "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/ae/22/c1976a822db658e5aa732b21228e", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/6f/df2600b658a163f80077bd6c8d78", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a5/ef/b1935b3767692070f070847f40df", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/70/d0/36b0d655839c60c2a763bbe52332", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/8e/3f/41e12b96fc07a623d89153b10c38", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/62/18/c2987e85c8ce48544cfa9c29d7bb", @@ -450,7 +450,7 @@ "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a9/77/722faae6a695f19501bac76098db", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/ef/61/7dcdc48c7039bbad6cd01d3f9a1f", - "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/e0/f7/f6daa488dc29e303dea69aae864b", + "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/71/ea/8dfd2a392713ead3f60a833b3a4e", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f1/00/c4ccd5969084505359e07f927b3a", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", @@ -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/21/b9/84344d916a526f3144eda007f245", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/c1/8d69797934e136feb17a400fcf8d", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/06/98/94acb9d29ca85a01edf3ba935e99", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/e5/317de6a4ea73cb9c4fe895a5ed66", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/75/35/61423ae280cfab87ee73bf7e1c34", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/ab/08821599d02ec46e83814dcfbab3", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/de/77af3bf69b95e04d7a49d7d606a9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/43/f8/7bafd47112eb99ede6c817f12704", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/41/ee/0dbd6c907c45ed6c27e26657fe5a", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cf/ac/4b84bdeaa0dfe5f9b2990c8094b6", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fc/bd/52a82497581428fc1fe6cb1f7db1", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9d/6c/714e999d02c4ea913159d62692c0" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/60/0ec966889ccd774e7e7c2bde2300", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/69/1a53798138120730e4b50553d3a6", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/b3/2c1e2e99161df7774dc15da7974d", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/3d/afc0c90ce7f78aefa0235eeafa0b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fb/42/2d6119d13bd4f4c3f6f82cd23e82", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/60/59/6c48f3172215908e6a14784e3f76", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/cc/5bc457d1a527fa8baccff1e4c5fa", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c2/98/471cb5f15f314c1ddae478d37a26", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cb/e8/d18b9d76c0223d65ff01a6641682", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4b/68/b21c4b91bda649f21a7ded0c6b55", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4f/27/029c90dc03cab7fb214c03b3c125", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7f/b9/a61816627b8f70c7b5741f49d7f3" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 86f79f5b..090d1719 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### 1.5.16 (20099) +- Hopefully finally fixed that pesky crash bug on score submissions. + +### 1.5.14 (20096) +- Fixed Android VR version failing to launch. +- More bug fixing and crash reporting improvements. + ### 1.5.13 (20095) - Hopefully fixed an elusive random crash on android that popped up recently. - Misc bug fixes. diff --git a/docs/ba_module.md b/docs/ba_module.md index 4465d271..0d5ec472 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-25 for Ballistica version 1.5.12 build 20089

    +

    last updated on 2020-06-30 for Ballistica version 1.5.15 build 20098

    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!


    From 7c508dcfe6546437bba61a09bc1fd8bdb6c82105 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 3 Jul 2020 02:51:12 -0700 Subject: [PATCH 125/417] v1.5.17 --- .efrocachemap | 32 ++++---- .idea/dictionaries/ericf.xml | 7 ++ CHANGELOG.md | 4 + assets/src/ba_data/python/_ba.py | 32 ++++++-- assets/src/ba_data/python/ba/_appconfig.py | 2 +- assets/src/ba_data/python/bastd/ui/gather.py | 4 +- docs/ba_module.md | 9 ++- tools/batools/android.py | 2 +- tools/batools/snippets.py | 36 ++++++++- tools/efrotools/android.py | 84 ++++++++++++++++++++ tools/snippets | 3 +- 11 files changed, 181 insertions(+), 34 deletions(-) create mode 100644 tools/efrotools/android.py diff --git a/.efrocachemap b/.efrocachemap index 8c3d924c..cf123ff0 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/91/cc/22cdc1ce692de2cba974bd095d8b", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/b5/5b/63af84997e9012c1917ea298ebbb", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/4c/ca/1e38748da251895ca11dcdc87107", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", @@ -431,11 +431,11 @@ "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/30/f3/4ef3bbaf1e5b7abe114c119ec106", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/95/9b/66e9080c82ef76387832dedee9b4", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/c7/63/f72f7f8b2004ff79b1606b040f8b", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8e/24/f070599beb7b09e1268569fa55b1", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", - "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/ae/22/c1976a822db658e5aa732b21228e", + "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/30/e7/d36b1b1eeb2ec10633281855a34c", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/6f/df2600b658a163f80077bd6c8d78", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/70/d0/36b0d655839c60c2a763bbe52332", @@ -450,7 +450,7 @@ "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a9/77/722faae6a695f19501bac76098db", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/ef/61/7dcdc48c7039bbad6cd01d3f9a1f", - "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/71/ea/8dfd2a392713ead3f60a833b3a4e", + "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/9d/fb/6c2feb78bdabbec049a71ba40d78", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f1/00/c4ccd5969084505359e07f927b3a", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", @@ -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/b6/60/0ec966889ccd774e7e7c2bde2300", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/69/1a53798138120730e4b50553d3a6", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/b3/2c1e2e99161df7774dc15da7974d", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/3d/afc0c90ce7f78aefa0235eeafa0b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fb/42/2d6119d13bd4f4c3f6f82cd23e82", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/60/59/6c48f3172215908e6a14784e3f76", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/cc/5bc457d1a527fa8baccff1e4c5fa", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c2/98/471cb5f15f314c1ddae478d37a26", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cb/e8/d18b9d76c0223d65ff01a6641682", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4b/68/b21c4b91bda649f21a7ded0c6b55", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4f/27/029c90dc03cab7fb214c03b3c125", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7f/b9/a61816627b8f70c7b5741f49d7f3" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/af/d70d326fe40d4ec40672c5d062ea", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/3c/d5c499426cf31f0bc75e56ba3294", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d3/f5/d97f3590bac4f4aa811d1de04222", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c4/35/f83dc6901dfb3d398fda301eb6b5", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/39/a79bf14a5a823e81dcfaaa846df5", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1a/39/cf3412e69777805f53f3d65a0cf1", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e7/b7/02b5a461b12f6f0ecae09e6efb45", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/00/77b425a357d8ea186e71611e20fa", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/75/f1214d30fc1e28d342fc35071098", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fc/d1/37903806d79ea619531731232aef", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/79/5a38fba6af60053de588c02b79c3", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/89/ab/4301d0fda22038089dab5c804bad" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 9d6534a6..459c3a5d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -232,6 +232,7 @@ buildblessingcheck builddir buildfile + buildfilename buildnum buildtype bullseye @@ -407,6 +408,7 @@ ctex ctuple ctype + cupcmd curdir curhash curhashes @@ -548,11 +550,13 @@ editcontroller editgame editorconfig + efgrd efile efro efrocache efrocachemap efroemling + efrogradle efrosync efrotool efrotools @@ -1068,6 +1072,7 @@ libxz lindex lindexorig + linebits lineheight lineno linenum @@ -1534,6 +1539,7 @@ pushdocs pushish pushlist + pushsymbols putasset putassetmanifest putassetpack @@ -1752,6 +1758,7 @@ shellapi shiftdelay shiftposition + shiplog shobs shortname shouldn diff --git a/CHANGELOG.md b/CHANGELOG.md index 090d1719..9ff993e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +### 1.5.17 (20102) +- More cleanup to logging and crash reporting system. +- Various other minor bug fixes.. + ### 1.5.16 (20099) - Hopefully finally fixed that pesky crash bug on score submissions. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index e9948ae1..c5078118 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -2803,12 +2803,9 @@ def lock_all_input() -> None: return None -def log(message: str, - to_console: bool = True, - newline: bool = True, - to_server: bool = True) -> None: - """log(message: str, to_console: bool = True, newline: bool = True, - to_server: bool = True) -> None +def log(message: str, to_stdout: bool = True, to_server: bool = True) -> None: + """log(message: str, to_stdout: bool = True, + to_server: bool = True) -> None Category: General Utility Functions @@ -3081,6 +3078,22 @@ def print_load_info() -> None: return None +def print_stderr(message: str) -> None: + """print_stderr(message: str) -> None + + (internal) + """ + return None + + +def print_stdout(message: str) -> None: + """print_stdout(message: str) -> None + + (internal) + """ + return None + + def printnodes() -> None: """printnodes() -> None @@ -3112,8 +3125,11 @@ def purchase(item: str) -> None: return None -def pushcall(call: Callable, from_other_thread: bool = False) -> None: - """pushcall(call: Callable, from_other_thread: bool = False) -> None +def pushcall(call: Callable, + from_other_thread: bool = False, + suppress_other_thread_warning: bool = False) -> None: + """pushcall(call: Callable, from_other_thread: bool = False, + suppress_other_thread_warning: bool = False ) -> None Pushes a call onto the event loop to be run during the next cycle. diff --git a/assets/src/ba_data/python/ba/_appconfig.py b/assets/src/ba_data/python/ba/_appconfig.py index 55f94943..d4d5b35b 100644 --- a/assets/src/ba_data/python/ba/_appconfig.py +++ b/assets/src/ba_data/python/ba/_appconfig.py @@ -149,7 +149,7 @@ def read_config() -> Tuple[AppConfig, bool]: try: _ba.log('broken config contents:\n' + config_contents.replace('\000', ''), - to_console=False) + to_stdout=False) except Exception as exc: print('EXC logging broken config contents:', exc) config = AppConfig() diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index a9b93207..6e45dd83 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1667,8 +1667,8 @@ class GatherWindow(ba.Window): # Ignore harmless errors. if exc.errno in { - errno.EHOSTUNREACH, - errno.ENETUNREACH, + errno.EHOSTUNREACH, errno.ENETUNREACH, + errno.EINVAL }: pass elif exc.errno == 10022: diff --git a/docs/ba_module.md b/docs/ba_module.md index 0d5ec472..5a38c794 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-06-30 for Ballistica version 1.5.15 build 20098

    +

    last updated on 2020-07-03 for Ballistica version 1.5.17 build 20102

    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!


    @@ -6352,8 +6352,8 @@ is only useful for simple URLs.)


    ba.log()

    -

    log(message: str, to_console: bool = True, newline: bool = True, - to_server: bool = True) -> None

    +

    log(message: str, to_stdout: bool = True, + to_server: bool = True) -> None

    Category: General Utility Functions

    @@ -6481,7 +6481,8 @@ It prints various info about the current object count, etc.


    ba.pushcall()

    -

    pushcall(call: Callable, from_other_thread: bool = False) -> None

    +

    pushcall(call: Callable, from_other_thread: bool = False, + suppress_other_thread_warning: bool = False ) -> None

    Pushes a call onto the event loop to be run during the next cycle.

    diff --git a/tools/batools/android.py b/tools/batools/android.py index 08396d90..23506a4d 100644 --- a/tools/batools/android.py +++ b/tools/batools/android.py @@ -30,7 +30,7 @@ from typing import TYPE_CHECKING import efrotools if TYPE_CHECKING: - pass + from typing import List, Optional, Set def androidaddr(archive_dir: str, arch: str, addr: str) -> None: diff --git a/tools/batools/snippets.py b/tools/batools/snippets.py index 57e11240..a17d84fb 100644 --- a/tools/batools/snippets.py +++ b/tools/batools/snippets.py @@ -33,7 +33,7 @@ from typing import TYPE_CHECKING from efrotools.snippets import PROJROOT if TYPE_CHECKING: - from typing import Optional + from typing import Optional, List, Set def stage_server_file() -> None: @@ -651,3 +651,37 @@ def android_archive_unstripped_libs() -> None: cwd=dst, check=True) subprocess.run(['rm', dstpath], check=True) + + +def _camel_case_split(string: str) -> List[str]: + words = [[string[0]]] + for char in string[1:]: + if words[-1][-1].islower() and char.isupper(): + words.append(list(char)) + else: + words[-1].append(char) + return [''.join(word) for word in words] + + +def efro_gradle() -> None: + """Calls ./gradlew with some extra magic.""" + import subprocess + from efrotools.android import filter_gradle_file + args = ['./gradlew'] + sys.argv[2:] + enabled_tags: Set[str] = set() + target_words = [w.lower() for w in _camel_case_split(args[-1])] + if 'google' in target_words: + enabled_tags = {'google', 'crashlytics'} + filter_gradle_file('BallisticaCore/build.gradle', enabled_tags) + + try: + subprocess.run(args, check=True) + errored = False + except BaseException: + errored = True + + # Put things back to default state. + filter_gradle_file('BallisticaCore/build.gradle', set()) + + if errored: + sys.exit(1) diff --git a/tools/efrotools/android.py b/tools/efrotools/android.py new file mode 100644 index 00000000..b5eb9412 --- /dev/null +++ b/tools/efrotools/android.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3.7 +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Functionality related to android builds.""" +from __future__ import annotations + +from typing import TYPE_CHECKING +from dataclasses import dataclass + +if TYPE_CHECKING: + from typing import List, Optional, Set + + +@dataclass +class GradleFilterSection: + """Filtered section of gradle file.""" + tag: str + firstline: int + lastline: int + + +def filter_gradle_file(buildfilename: str, enabled_tags: Set[str]) -> None: + """Filter 'EFRO_IF' sections in a gradle file.""" + + sections: List[GradleFilterSection] = [] + + with open(buildfilename) as infile: + original = infile.read() + lines = original.splitlines() + + current_section: Optional[GradleFilterSection] = None + for i, line in enumerate(lines): + if line.strip().startswith('// EFRO_IF'): + if current_section is not None: + raise RuntimeError('Malformed gradle file') + current_section = GradleFilterSection(tag=line.split()[2], + firstline=i, + lastline=i) + elif line.strip().startswith('// EFRO_ENDIF'): + if current_section is None: + raise RuntimeError('Malformed gradle file') + current_section.lastline = i + sections.append(current_section) + current_section = None + if current_section is not None: + raise RuntimeError('Malformed gradle file') + + for section in sections: + for lineno in range(section.firstline + 1, section.lastline): + enable = section.tag in enabled_tags + line = lines[lineno] + leading = '' + while line.startswith(' '): + leading += ' ' + line = line[1:] + if not enable and not line.startswith('// '): + line = '// ' + line + if enable and line.startswith('// '): + line = line[3:] + lines[lineno] = leading + line + + # Only write if its not changed (potentially avoid triggering builds). + out = '\n'.join(lines) + '\n' + if out != original: + with open(buildfilename, 'w') as outfile: + outfile.write(out) diff --git a/tools/snippets b/tools/snippets index ebe46596..1b862fc3 100755 --- a/tools/snippets +++ b/tools/snippets @@ -54,7 +54,8 @@ from batools.snippets import ( python_gather, capitalize, efrocache_update, efrocache_get, get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, - make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs) + make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, + efro_gradle) # pylint: enable=unused-import if TYPE_CHECKING: From ec2eceb0d5a31c8136d9be50e0d640b28ad3d06d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 3 Jul 2020 16:31:39 -0700 Subject: [PATCH 126/417] tools/snippets is now tools/pcommand --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 3 + Makefile | 190 +- assets/Makefile | 4974 ++++++++--------- .../python/bastd/ui/tournamententry.py | 2 +- config/toolconfigsrc/pycheckers | 2 +- docs/ba_module.md | 2 +- tools/batools/build.py | 32 +- tools/batools/{snippets.py => pcommand.py} | 10 +- tools/efrotools/efrocache.py | 4 +- tools/efrotools/{snippets.py => pcommand.py} | 18 +- tools/efrotools/pybuild.py | 2 +- tools/{snippets => pcommand} | 8 +- tools/update_assets_makefile | 2 +- tools/update_project | 4 +- 16 files changed, 2641 insertions(+), 2637 deletions(-) rename tools/batools/{snippets.py => pcommand.py} (98%) rename tools/efrotools/{snippets.py => pcommand.py} (97%) rename tools/{snippets => pcommand} (95%) diff --git a/.efrocachemap b/.efrocachemap index cf123ff0..0d885507 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/85/af/d70d326fe40d4ec40672c5d062ea", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/3c/d5c499426cf31f0bc75e56ba3294", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d3/f5/d97f3590bac4f4aa811d1de04222", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c4/35/f83dc6901dfb3d398fda301eb6b5", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/39/a79bf14a5a823e81dcfaaa846df5", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1a/39/cf3412e69777805f53f3d65a0cf1", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e7/b7/02b5a461b12f6f0ecae09e6efb45", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/00/77b425a357d8ea186e71611e20fa", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/36/75/f1214d30fc1e28d342fc35071098", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fc/d1/37903806d79ea619531731232aef", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/79/5a38fba6af60053de588c02b79c3", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/89/ab/4301d0fda22038089dab5c804bad" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f2/e4/3f66ba2b14096ab164364705b8a3", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/be/1f982df77f11cafb2d1e881b80ab", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3b/9f/f12a5696a599bffb5c7711235328", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c3/ee/8e71bc4ad318d4099a03c096d541", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/95/62eac97133aab925282cb97ab7e6", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3d/05/0d7b02cea3b7d26bea4b036f825a", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/87/faa3ba3c5d6613727aeb4072f78b", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/54/70/6bdb7d6ce26d636b66265bacf195", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3b/77/805cd6d6898e33e9fc8679664e87", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/65/33/8a7dcbe289fcb682e0997bf8f024", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/86/3c/eae5a2cae586dc732a909eebfea0", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ff/46/63b0a2c3969a0785aa109867b0f9" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 459c3a5d..98cf369f 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1402,6 +1402,7 @@ pbxproj pcall pchild + pcommand pcstr pedit peditui diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ff993e1..19efe74b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.18 (20106) +- A bit of project cleanup; tools/snippets is now tools/pcommand, etc. + ### 1.5.17 (20102) - More cleanup to logging and crash reporting system. - Various other minor bug fixes.. diff --git a/Makefile b/Makefile index 6519cb8a..84cc0ca3 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ DOCPREFIX = "ballisticacore_" # List targets in this Makefile and basic descriptions for them. help: - @tools/snippets makefile_target_list Makefile + @tools/pcommand makefile_target_list Makefile PREREQS = .cache/checkenv .dir-locals.el \ .mypy.ini .pycheckers .pylintrc .style.yapf .clang-format \ @@ -115,42 +115,42 @@ clean-list: # Assemble & run a debug build for this platform. prefab-debug: prefab-debug-build - ${${shell tools/snippets prefab_run_var debug}} + ${${shell tools/pcommand prefab_run_var debug}} # Assemble & run a release build for this platform. prefab-release: prefab-release-build - ${${shell tools/snippets prefab_run_var release}} + ${${shell tools/pcommand prefab_run_var release}} # Assemble a debug build for this platform. prefab-debug-build: - @tools/snippets make_prefab debug + @tools/pcommand make_prefab debug # Assemble a release build for this platform. prefab-release-build: - @tools/snippets make_prefab release + @tools/pcommand make_prefab release # Assemble & run a server debug build for this platform. prefab-server-debug: prefab-server-debug-build - ${${shell tools/snippets prefab_run_var server-debug}} + ${${shell tools/pcommand prefab_run_var server-debug}} # Assemble & run a server release build for this platform. prefab-server-release: prefab-server-release-build - ${${shell tools/snippets prefab_run_var server-release}} + ${${shell tools/pcommand prefab_run_var server-release}} # Assemble a server debug build for this platform. prefab-server-debug-build: - @tools/snippets make_prefab server-debug + @tools/pcommand make_prefab server-debug # Assemble a server release build for this platform. prefab-server-release-build: - @tools/snippets make_prefab server-release + @tools/pcommand make_prefab server-release # Specific platform prefab targets: RUN_PREFAB_MAC_DEBUG = cd build/prefab/mac/debug && ./ballisticacore prefab-mac-debug: prefab-mac-debug-build - @tools/snippets ensure_prefab_platform mac + @tools/pcommand ensure_prefab_platform mac @${RUN_PREFAB_MAC_DEBUG} prefab-mac-debug-build: prereqs assets-cmake \ @@ -158,12 +158,12 @@ prefab-mac-debug-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmake build/prefab/mac/debug build/prefab/mac/debug/ballisticacore: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_MAC_RELEASE = cd build/prefab/mac/release && ./ballisticacore prefab-mac-release: prefab-mac-release-build - @tools/snippets ensure_prefab_platform mac + @tools/pcommand ensure_prefab_platform mac @${RUN_PREFAB_MAC_RELEASE} prefab-mac-release-build: prereqs assets-cmake \ @@ -171,13 +171,13 @@ prefab-mac-release-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmake build/prefab/mac/release build/prefab/mac/release/ballisticacore: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_MAC_SERVER_DEBUG = cd build/prefab/mac-server/debug \ && ./ballisticacore_server prefab-mac-server-debug: prefab-mac-server-debug-build - @tools/snippets ensure_prefab_platform mac + @tools/pcommand ensure_prefab_platform mac @${RUN_PREFAB_MAC_SERVER_DEBUG} prefab-mac-server-debug-build: prereqs assets-cmake \ @@ -188,28 +188,28 @@ prefab-mac-server-debug-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/debug/dist build/prefab/mac-server/debug/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/snippets.py - @tools/snippets stage_server_file debug $< $@ + assets/src/server/ballisticacore_server.py tools/batools/pcommand.py + @tools/pcommand stage_server_file debug $< $@ build/prefab/mac-server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ - tools/batools/snippets.py \ + tools/batools/pcommand.py \ tools/bacommon/servermanager.py - @tools/snippets stage_server_file debug $< $@ + @tools/pcommand stage_server_file debug $< $@ build/prefab/mac-server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ build/prefab/mac-server/debug/dist/ballisticacore_headless: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_MAC_SERVER_RELEASE = cd build/prefab/mac-server/release \ && ./ballisticacore_server prefab-mac-server-release: prefab-mac-server-release-build - @tools/snippets ensure_prefab_platform mac + @tools/pcommand ensure_prefab_platform mac @${RUN_PREFAB_MAC_SERVER_RELEASE} prefab-mac-server-release-build: prereqs assets-cmake \ @@ -220,27 +220,27 @@ prefab-mac-server-release-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/release/dist build/prefab/mac-server/release/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/snippets.py - @tools/snippets stage_server_file release $< $@ + assets/src/server/ballisticacore_server.py tools/batools/pcommand.py + @tools/pcommand stage_server_file release $< $@ build/prefab/mac-server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ - tools/batools/snippets.py \ + tools/batools/pcommand.py \ tools/bacommon/servermanager.py - @tools/snippets stage_server_file release $< $@ + @tools/pcommand stage_server_file release $< $@ build/prefab/mac-server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ build/prefab/mac-server/release/dist/ballisticacore_headless: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_DEBUG = cd build/prefab/linux/debug && ./ballisticacore prefab-linux-debug: prefab-linux-debug-build - @tools/snippets ensure_prefab_platform linux + @tools/pcommand ensure_prefab_platform linux @${RUN_PREFAB_LINUX_DEBUG} prefab-linux-debug-build: prereqs assets-cmake \ @@ -248,12 +248,12 @@ prefab-linux-debug-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmake build/prefab/linux/debug build/prefab/linux/debug/ballisticacore: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_RELEASE = cd build/prefab/linux/release && ./ballisticacore prefab-linux-release: prefab-linux-release-build - @tools/snippets ensure_prefab_platform linux + @tools/pcommand ensure_prefab_platform linux @${RUN_PREFAB_LINUX_RELEASE} prefab-linux-release-build: prereqs assets-cmake \ @@ -261,13 +261,13 @@ prefab-linux-release-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmake build/prefab/linux/release build/prefab/linux/release/ballisticacore: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_SERVER_DEBUG = cd build/prefab/linux-server/debug \ && ./ballisticacore_server prefab-linux-server-debug: prefab-linux-server-debug-build - @tools/snippets ensure_prefab_platform linux + @tools/pcommand ensure_prefab_platform linux @${RUN_PREFAB_LINUX_SERVER_DEBUG} prefab-linux-server-debug-build: prereqs assets-cmake \ @@ -278,28 +278,28 @@ prefab-linux-server-debug-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/debug/dist build/prefab/linux-server/debug/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/snippets.py - @tools/snippets stage_server_file debug $< $@ + assets/src/server/ballisticacore_server.py tools/batools/pcommand.py + @tools/pcommand stage_server_file debug $< $@ build/prefab/linux-server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ - tools/batools/snippets.py \ + tools/batools/pcommand.py \ tools/bacommon/servermanager.py - @tools/snippets stage_server_file debug $< $@ + @tools/pcommand stage_server_file debug $< $@ build/prefab/linux-server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ build/prefab/linux-server/debug/dist/ballisticacore_headless: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_SERVER_RELEASE = cd build/prefab/linux-server/release \ && ./ballisticacore_server prefab-linux-server-release: prefab-linux-server-release-build - @tools/snippets ensure_prefab_platform linux + @tools/pcommand ensure_prefab_platform linux @${RUN_PREFAB_LINUX_SERVER_RELEASE} prefab-linux-server-release-build: prereqs assets-cmake \ @@ -310,29 +310,29 @@ prefab-linux-server-release-build: prereqs assets-cmake \ @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/release/dist build/prefab/linux-server/release/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/snippets.py - @tools/snippets stage_server_file release $< $@ + assets/src/server/ballisticacore_server.py tools/batools/pcommand.py + @tools/pcommand stage_server_file release $< $@ build/prefab/linux-server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ - tools/batools/snippets.py \ + tools/batools/pcommand.py \ tools/bacommon/servermanager.py - @tools/snippets stage_server_file release $< $@ + @tools/pcommand stage_server_file release $< $@ build/prefab/linux-server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ build/prefab/linux-server/release/dist/ballisticacore_headless: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ PREFAB_WINDOWS_PLATFORM = Win32 RUN_PREFAB_WINDOWS_DEBUG = cd build/prefab/windows/debug && ./BallisticaCore.exe prefab-windows-debug: prefab-windows-debug-build - @tools/snippets ensure_prefab_platform windows + @tools/pcommand ensure_prefab_platform windows @{RUN_PREFAB_WINDOWS_DEBUG} prefab-windows-debug-build: prereqs assets-windows-${PREFAB_WINDOWS_PLATFORM} \ @@ -341,13 +341,13 @@ prefab-windows-debug-build: prereqs assets-windows-${PREFAB_WINDOWS_PLATFORM} \ build/prefab/windows/debug build/prefab/windows/debug/BallisticaCore.exe: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_WINDOWS_RELEASE = cd build/prefab/windows/release \ && ./BallisticaCore.exe prefab-windows-release: prefab-windows-release-build - @tools/snippets ensure_prefab_platform windows + @tools/pcommand ensure_prefab_platform windows @{RUN_PREFAB_WINDOWS_RELEASE} prefab-windows-release-build: prereqs \ @@ -357,13 +357,13 @@ prefab-windows-release-build: prereqs \ build/prefab/windows/release build/prefab/windows/release/BallisticaCore.exe: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ RUN_PREFAB_WINDOWS_SERVER_DEBUG = cd build/prefab/windows-server/debug \ && dist/python.exe ballisticacore_server.py prefab-windows-server-debug: prefab-windows-server-debug-build - @tools/snippets ensure_prefab_platform windows + @tools/pcommand ensure_prefab_platform windows @{RUN_PREFAB_WINDOWS_SERVER_DEBUG} prefab-windows-server-debug-build: prereqs \ @@ -377,22 +377,22 @@ prefab-windows-server-debug-build: prereqs \ build/prefab/windows-server/debug/dist build/prefab/windows-server/debug/dist/ballisticacore_headless.exe: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ build/prefab/windows-server/debug/ballisticacore_server.py: \ - assets/src/server/ballisticacore_server.py tools/batools/snippets.py - @tools/snippets stage_server_file debug $< $@ + assets/src/server/ballisticacore_server.py tools/batools/pcommand.py + @tools/pcommand stage_server_file debug $< $@ build/prefab/windows-server/debug/launch_ballisticacore_server.bat: \ - assets/src/server/launch_ballisticacore_server.bat tools/batools/snippets.py - @tools/snippets stage_server_file debug $< $@ + assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py + @tools/pcommand stage_server_file debug $< $@ build/prefab/windows-server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ - tools/batools/snippets.py \ + tools/batools/pcommand.py \ tools/bacommon/servermanager.py - @tools/snippets stage_server_file debug $< $@ + @tools/pcommand stage_server_file debug $< $@ build/prefab/windows-server/debug/README.txt: \ assets/src/server/README.txt @@ -402,7 +402,7 @@ RUN_PREFAB_WINDOWS_SERVER_RELEASE = cd build/prefab/windows-server/release \ && dist/python.exe -O ballisticacore_server.py prefab-windows-server-release: prefab-windows-server-release-build - @tools/snippets ensure_prefab_platform windows + @tools/pcommand ensure_prefab_platform windows @{RUN_PREFAB_WINDOWS_SERVER_RELEASE} prefab-windows-server-release-build: prereqs \ @@ -416,22 +416,22 @@ prefab-windows-server-release-build: prereqs \ build/prefab/windows-server/release/dist build/prefab/windows-server/release/dist/ballisticacore_headless.exe: .efrocachemap - @tools/snippets efrocache_get $@ + @tools/pcommand efrocache_get $@ build/prefab/windows-server/release/ballisticacore_server.py: \ - assets/src/server/ballisticacore_server.py tools/batools/snippets.py - @tools/snippets stage_server_file release $< $@ + assets/src/server/ballisticacore_server.py tools/batools/pcommand.py + @tools/pcommand stage_server_file release $< $@ build/prefab/windows-server/release/launch_ballisticacore_server.bat: \ - assets/src/server/launch_ballisticacore_server.bat tools/batools/snippets.py - @tools/snippets stage_server_file release $< $@ + assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py + @tools/pcommand stage_server_file release $< $@ build/prefab/windows-server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ - tools/batools/snippets.py \ + tools/batools/pcommand.py \ tools/bacommon/servermanager.py - @tools/snippets stage_server_file release $< $@ + @tools/pcommand stage_server_file release $< $@ build/prefab/windows-server/release/README.txt: \ assets/src/server/README.txt @@ -483,32 +483,32 @@ update-check: prereqs # Run formatting on all files in the project considered 'dirty'. format: @${MAKE} -j3 format-code format-scripts format-makefile - @tools/snippets echo GRN Formatting complete! + @tools/pcommand echo GRN Formatting complete! # Same but always formats; ignores dirty state. format-full: @${MAKE} -j3 format-code-full format-scripts-full format-makefile - @tools/snippets echo GRN Formatting complete! + @tools/pcommand echo GRN Formatting complete! # Run formatting for compiled code sources (.cc, .h, etc.). format-code: prereqs - @tools/snippets formatcode + @tools/pcommand formatcode # Same but always formats; ignores dirty state. format-code-full: prereqs - @tools/snippets formatcode -full + @tools/pcommand formatcode -full # Runs formatting for scripts (.py, etc). format-scripts: prereqs - @tools/snippets formatscripts + @tools/pcommand formatscripts # Same but always formats; ignores dirty state. format-scripts-full: prereqs - @tools/snippets formatscripts -full + @tools/pcommand formatscripts -full # Runs formatting on the project Makefile. format-makefile: prereqs - @tools/snippets formatmakefile + @tools/pcommand formatmakefile .PHONY: format format-full format-code format-code-full format-scripts \ format-scripts-full @@ -523,62 +523,62 @@ format-makefile: prereqs # Run all project checks. (static analysis) check: update-check @${MAKE} -j3 cpplint pylint mypy - @tools/snippets echo GRN ALL CHECKS PASSED! + @tools/pcommand echo GRN ALL CHECKS PASSED! # Same as check but no caching (all files are checked). check-full: update-check @${MAKE} -j3 cpplint-full pylint-full mypy-full - @tools/snippets echo GRN ALL CHECKS PASSED! + @tools/pcommand echo GRN ALL CHECKS PASSED! # Same as 'check' plus optional/slow extra checks. check2: update-check @${MAKE} -j4 cpplint pylint mypy pycharm - @tools/snippets echo GRN ALL CHECKS PASSED! + @tools/pcommand echo GRN ALL CHECKS PASSED! # Same as check2 but no caching (all files are checked). check2-full: update-check @${MAKE} -j4 cpplint-full pylint-full mypy-full pycharm-full - @tools/snippets echo GRN ALL CHECKS PASSED! + @tools/pcommand echo GRN ALL CHECKS PASSED! # Run Cpplint checks on all C/C++ code. cpplint: prereqs - @tools/snippets cpplint + @tools/pcommand cpplint # Run Cpplint checks without caching (all files are checked). cpplint-full: prereqs - @tools/snippets cpplint -full + @tools/pcommand cpplint -full # Run Pylint checks on all Python Code. pylint: prereqs - @tools/snippets pylint + @tools/pcommand pylint # Run Pylint checks without caching (all files are checked). pylint-full: prereqs - @tools/snippets pylint -full + @tools/pcommand pylint -full # Run Mypy checks on all Python code. mypy: prereqs - @tools/snippets mypy + @tools/pcommand mypy # Run Mypy checks without caching (all files are checked). mypy-full: prereqs - @tools/snippets mypy -full + @tools/pcommand mypy -full # Run Mypy checks on all Python code using daemon mode. dmypy: prereqs - @tools/snippets dmypy + @tools/pcommand dmypy # Stop the mypy daemon dmypy-stop: prereqs - @tools/snippets dmypy -stop + @tools/pcommand dmypy -stop # Run PyCharm checks on all Python code. pycharm: prereqs - @tools/snippets pycharm + @tools/pcommand pycharm # Run PyCharm checks without caching (all files are checked). pycharm-full: prereqs - @tools/snippets pycharm -full + @tools/pcommand pycharm -full # Tell make which of these targets don't represent files. .PHONY: check check-full check2 check2-full \ @@ -594,19 +594,19 @@ pycharm-full: prereqs # Run all tests. (live execution verification) test: prereqs - @tools/snippets echo BLU Running all tests... - @tools/snippets pytest -v tests + @tools/pcommand echo BLU Running all tests... + @tools/pcommand pytest -v tests # Run tests with any caching disabled. test-full: test # Iterate on individual tests with extra debug output enabled. test-assetmanager: - @tools/snippets pytest -o log_cli=true -o log_cli_level=debug -s -v \ + @tools/pcommand pytest -o log_cli=true -o log_cli_level=debug -s -v \ tests/test_ba/test_assetmanager.py::test_assetmanager test-dataclasses: - @tools/snippets pytest -o log_cli=true -o log_cli_level=debug -s -v \ + @tools/pcommand pytest -o log_cli=true -o log_cli_level=debug -s -v \ tests/test_efro/test_dataclasses.py # Tell make which of these targets don't represent files. @@ -624,28 +624,28 @@ preflight: @${MAKE} format @${MAKE} update @${MAKE} -j4 cpplint pylint mypy test - @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! + @tools/pcommand echo SGRN BLD PREFLIGHT SUCCESSFUL! # Same as 'preflight' without caching (all files are visited). preflight-full: @${MAKE} format-full @${MAKE} update @${MAKE} -j4 cpplint-full pylint-full mypy-full test-full - @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! + @tools/pcommand echo SGRN BLD PREFLIGHT SUCCESSFUL! # Same as 'preflight' plus optional/slow extra checks. preflight2: @${MAKE} format @${MAKE} update @${MAKE} -j5 cpplint pylint mypy pycharm test - @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! + @tools/pcommand echo SGRN BLD PREFLIGHT SUCCESSFUL! # Same as 'preflight2' but without caching (all files visited). preflight2-full: @${MAKE} format-full @${MAKE} update @${MAKE} -j5 cpplint-full pylint-full mypy-full pycharm-full test-full - @tools/snippets echo SGRN BLD PREFLIGHT SUCCESSFUL! + @tools/pcommand echo SGRN BLD PREFLIGHT SUCCESSFUL! # Tell make which of these targets don't represent files. .PHONY: preflight preflight-full preflight2 preflight2-full @@ -672,16 +672,16 @@ ROOT_CLEAN_IGNORES = --exclude=assets/src_master \ --exclude=config/localconfig.json \ --exclude=.spinoffdata -CHECK_CLEAN_SAFETY = ${PROJ_DIR}/tools/snippets check_clean_safety +CHECK_CLEAN_SAFETY = ${PROJ_DIR}/tools/pcommand check_clean_safety # Some tool configs that need filtering (mainly injecting projroot path). -TOOL_CFG_INST = tools/snippets tool_config_install +TOOL_CFG_INST = tools/pcommand tool_config_install # Anything that affects tool-config generation. -TOOL_CFG_SRC = tools/efrotools/snippets.py config/config.json +TOOL_CFG_SRC = tools/efrotools/pcommand.py config/config.json # Anything that should trigger an environment-check when changed. -ENV_SRC = tools/snippets tools/batools/build.py +ENV_SRC = tools/pcommand tools/batools/build.py .clang-format: config/toolconfigsrc/clang-format ${TOOL_CFG_SRC} @${TOOL_CFG_INST} $< $@ @@ -709,7 +709,7 @@ ENV_SRC = tools/snippets tools/batools/build.py # Include anything as sources here that should require .cache/checkenv: ${ENV_SRC} - @tools/snippets checkenv + @tools/pcommand checkenv @mkdir -p .cache @touch .cache/checkenv diff --git a/assets/Makefile b/assets/Makefile index 4d3ec9ce..4f4f01d1 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -42,45 +42,45 @@ PROJ_DIR = .. # Build everything needed for all platforms. all: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets # Build everything needed for our cmake builds (linux, mac). cmake: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets-cmake - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets # Build everything needed for x86 windows builds. win-Win32: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets-win-Win32 - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets # Build everything needed for x86-64 windows builds. win-x64: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets-win-x64 - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets # Build everything needed for our mac xcode builds. mac: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets-mac - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets # Build everything needed for our ios/tvos builds. ios: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets-ios - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets # Build everything needed for android. android: - @${TOOLS_DIR}/snippets warm_start_asset_build + @${TOOLS_DIR}/pcommand warm_start_asset_build @$(MAKE) assets-android - @${TOOLS_DIR}/snippets clean_orphaned_assets + @${TOOLS_DIR}/pcommand clean_orphaned_assets MAKE_AUDIO = 1 MAKE_TEXTURES = 1 @@ -619,1147 +619,1147 @@ $(SCRIPT_TARGETS_PY_PUBLIC) : build/%.py : src/%.py build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_account.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_achievement.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_activity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_activitytypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_actor.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_analytics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_app.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_appconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_appdelegate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_apputils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_assetmanager.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_benchmark.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_campaign.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_collision.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_coopgame.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_coopsession.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_dependency.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_dualteamsession.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_enums.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_freeforallsession.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameactivity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameresults.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_gameutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_general.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_hooks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_input.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_lang.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_level.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_lobby.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_map.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_math.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_messages.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_meta.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_multiteamsession.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_music.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_netutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_nodeactor.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_player.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_playlist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_powerup.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_profile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_score.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_servermode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_session.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_settings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_stats.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_store.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_team.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_teamgame.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_tips.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/_tournament.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/deprecated.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/internal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/macmusicapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/modutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/osmusic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/ba/ui/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/coopjoin.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/coopscore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/drawscore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/dualteamscore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/freeforallvictory.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamjoin.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamscore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/activity/multiteamvictory.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/background.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/bomb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/controlsguide.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/flag.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/image.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/onscreencountdown.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/onscreentimer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/playerspaz.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/popuptext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/powerupbox.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/respawnicon.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/scoreboard.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spawner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spaz.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazappearance.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazbot.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/spazfactory.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/tipstext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/actor/zoomtext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/appdelegate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/assault.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/capturetheflag.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/chosenone.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/conquest.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/deathmatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/easteregghunt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/elimination.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/football.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/hockey.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/keepaway.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/kingofthehill.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/meteorshower.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/ninjafight.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/onslaught.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/race.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/runaround.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/targetpractice.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/game/thelaststand.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/gameutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mainmenu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/big_g.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/bridgit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/courtyard.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/crag_castle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/doom_shroom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/football_stadium.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/happy_thoughts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/hockey_stadium.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/lake_frigid.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/monkey_face.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/rampage.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/roundabout.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/step_right_up.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/the_pad.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/tip_top.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/tower_d.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/mapdata/zig_zag.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/maps.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/session/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/stdmap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/tutorial.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/link.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/settings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/unlink.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/account/viewer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/achievements.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/appinvite.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/characterpicker.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/colorpicker.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/configerror.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/confirm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/continues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/browser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/gamebutton.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/coop/level.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/creditslist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/debug.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/feedback.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/fileselector.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/gather.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/getcurrency.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/getremote.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/helpui.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/iconpicker.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/kiosk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankbutton.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/league/rankwindow.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/mainmenu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/onscreenkeyboard.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/party.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/partyqueue.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/play.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/addgame.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/browser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/customizebrowser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/edit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/editcontroller.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/editgame.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/mapselect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playlist/share.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/playoptions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/popup.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/browser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/edit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/profile/upgrade.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/promocode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/purchase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/qrcode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/radiogroup.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/report.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/resourcetypeinfo.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/serverdialog.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/advanced.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/allsettings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/audio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/controls.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepad.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepadadvanced.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/gamepadselect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/graphics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/keyboard.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/nettesting.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/ps3controller.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/remoteapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/testing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/touchscreen.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/vrtesting.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/wiimote.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/settings/xbox360controller.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/browser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/edit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/specialoffer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/browser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/button.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/store/item.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tabs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/teamnamescolors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/telnet.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tournamententry.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/tournamentscores.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/trophies.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/url.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ build/ba_data/python/bastd/ui/watch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc: \ build/server/ballisticacore_server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \ @@ -1818,92 +1818,92 @@ $(SCRIPT_TARGETS_PY_PUBLIC_TOOLS) : build/ba_data/python/%.py : ../tools/%.py build/ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bacommon/__pycache__/assets.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/assets.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/err.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc: \ build/ba_data/python/bacommon/servermanager.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/call.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_entity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_field.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/_value.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/entity/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/json.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/terminal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ build/ba_data/python/efro/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ #AUTOGENERATED_END_PUBLIC @@ -2768,7 +2768,7 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) $(SCRIPT_TARGETS_PY_PRIVATE_APPLE) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Looks like path mangling from py to pyc is too complex for pattern rules so # just generating explicit targets for each. Could perhaps look into using a @@ -2777,2132 +2777,2132 @@ $(SCRIPT_TARGETS_PY_PRIVATE_APPLE) : ../.efrocachemap build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/pylib-apple/__future__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/pylib-apple/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/pylib-apple/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/pylib-apple/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/pylib-apple/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/pylib-apple/_compression.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/pylib-apple/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/pylib-apple/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/pylib-apple/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/pylib-apple/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/pylib-apple/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/pylib-apple/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/pylib-apple/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/pylib-apple/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/pylib-apple/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/pylib-apple/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/pylib-apple/aifc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/pylib-apple/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/pylib-apple/argparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc: \ build/pylib-apple/ast.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/pylib-apple/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/pylib-apple/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ build/pylib-apple/base64.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/pylib-apple/bdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/pylib-apple/binhex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/pylib-apple/bisect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/pylib-apple/bz2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/pylib-apple/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/pylib-apple/calendar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/pylib-apple/cgi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/pylib-apple/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/pylib-apple/chunk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/pylib-apple/cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ build/pylib-apple/code.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/pylib-apple/codecs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/pylib-apple/codeop.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/pylib-apple/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/pylib-apple/compileall.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/pylib-apple/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/pylib-apple/configparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/pylib-apple/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/pylib-apple/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ build/pylib-apple/copy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/pylib-apple/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/pylib-apple/crypt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ build/pylib-apple/csv.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/pylib-apple/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/pylib-apple/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/pylib-apple/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/pylib-apple/datetime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/pylib-apple/decimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/pylib-apple/difflib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ build/pylib-apple/dis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/pylib-apple/doctest.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/pylib-apple/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/pylib-apple/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/pylib-apple/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/pylib-apple/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/pylib-apple/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/pylib-apple/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/pylib-apple/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/pylib-apple/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/pylib-apple/email/header.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/pylib-apple/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/pylib-apple/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-apple/email/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/pylib-apple/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-apple/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/pylib-apple/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/pylib-apple/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/pylib-apple/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/pylib-apple/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ build/pylib-apple/enum.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/pylib-apple/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/pylib-apple/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/pylib-apple/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/pylib-apple/formatter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/pylib-apple/fractions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/pylib-apple/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ build/pylib-apple/functools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/pylib-apple/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/pylib-apple/getopt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/pylib-apple/getpass.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/pylib-apple/gettext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ build/pylib-apple/glob.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/pylib-apple/gzip.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/pylib-apple/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/pylib-apple/heapq.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/pylib-apple/hmac.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/pylib-apple/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-apple/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-apple/http/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/pylib-apple/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/pylib-apple/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-apple/http/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/pylib-apple/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ build/pylib-apple/imp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-apple/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/pylib-apple/inspect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ build/pylib-apple/io.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/pylib-apple/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/pylib-apple/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/pylib-apple/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/pylib-apple/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/pylib-apple/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/pylib-apple/keyword.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/pylib-apple/linecache.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ build/pylib-apple/locale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/pylib-apple/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-apple/lzma.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/pylib-apple/macpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-apple/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-apple/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/pylib-apple/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-apple/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/pylib-apple/netrc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/pylib-apple/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/pylib-apple/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-apple/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/pylib-apple/numbers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-apple/opcode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-apple/operator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/pylib-apple/optparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ build/pylib-apple/os.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/pylib-apple/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/pylib-apple/pdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/pylib-apple/pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/pylib-apple/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/pylib-apple/pipes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/pylib-apple/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ build/pylib-apple/platform.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/pylib-apple/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/pylib-apple/poplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/pylib-apple/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/pylib-apple/pprint.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ build/pylib-apple/profile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/pylib-apple/pstats.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ build/pylib-apple/pty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/pylib-apple/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/pylib-apple/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/pylib-apple/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ build/pylib-apple/queue.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/pylib-apple/quopri.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ build/pylib-apple/random.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ build/pylib-apple/re.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/pylib-apple/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/pylib-apple/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/pylib-apple/runpy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ build/pylib-apple/sched.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/pylib-apple/secrets.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/pylib-apple/selectors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/pylib-apple/shelve.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/pylib-apple/shlex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/pylib-apple/shutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ build/pylib-apple/signal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ build/pylib-apple/site.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/pylib-apple/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/pylib-apple/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/pylib-apple/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ build/pylib-apple/socket.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/pylib-apple/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/pylib-apple/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/pylib-apple/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/pylib-apple/ssl.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ build/pylib-apple/stat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/pylib-apple/statistics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ build/pylib-apple/string.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/pylib-apple/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ build/pylib-apple/struct.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-apple/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/pylib-apple/sunau.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/pylib-apple/symbol.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/pylib-apple/symtable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/pylib-apple/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/pylib-apple/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/pylib-apple/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/pylib-apple/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/pylib-apple/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/pylib-apple/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ build/pylib-apple/this.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ build/pylib-apple/threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/pylib-apple/timeit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ build/pylib-apple/token.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/pylib-apple/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ build/pylib-apple/trace.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/pylib-apple/traceback.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/pylib-apple/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ build/pylib-apple/tty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ build/pylib-apple/types.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ build/pylib-apple/typing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/pylib-apple/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ build/pylib-apple/uu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/pylib-apple/uuid.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/pylib-apple/warnings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ build/pylib-apple/wave.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/pylib-apple/weakref.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/pylib-apple/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/pylib-apple/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-apple/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-apple/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/pylib-apple/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/pylib-apple/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ @@ -5764,7 +5764,7 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) $(SCRIPT_TARGETS_PY_PRIVATE_ANDROID) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Looks like path mangling from py to pyc is too complex for pattern rules so # just generating explicit targets for each. Could perhaps look into using a @@ -5773,2132 +5773,2132 @@ $(SCRIPT_TARGETS_PY_PRIVATE_ANDROID) : ../.efrocachemap build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/pylib-android/__future__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/pylib-android/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/pylib-android/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/pylib-android/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/pylib-android/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/pylib-android/_compression.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/pylib-android/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/pylib-android/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/pylib-android/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/pylib-android/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/pylib-android/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/pylib-android/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/pylib-android/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/pylib-android/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/pylib-android/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/pylib-android/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/pylib-android/aifc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/pylib-android/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/pylib-android/argparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc: \ build/pylib-android/ast.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/pylib-android/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/pylib-android/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/pylib-android/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ build/pylib-android/base64.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/pylib-android/bdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/pylib-android/binhex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/pylib-android/bisect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/pylib-android/bz2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/pylib-android/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/pylib-android/calendar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/pylib-android/cgi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/pylib-android/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/pylib-android/chunk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/pylib-android/cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ build/pylib-android/code.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/pylib-android/codecs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/pylib-android/codeop.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/pylib-android/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/pylib-android/compileall.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/pylib-android/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/pylib-android/configparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/pylib-android/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/pylib-android/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ build/pylib-android/copy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/pylib-android/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/pylib-android/crypt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ build/pylib-android/csv.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/pylib-android/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-android/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/pylib-android/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/pylib-android/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/pylib-android/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/pylib-android/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/pylib-android/datetime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/pylib-android/decimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/pylib-android/difflib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ build/pylib-android/dis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/pylib-android/doctest.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/pylib-android/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/pylib-android/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/pylib-android/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/pylib-android/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/pylib-android/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/pylib-android/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/pylib-android/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/pylib-android/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/pylib-android/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/pylib-android/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/pylib-android/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/pylib-android/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/pylib-android/email/header.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/pylib-android/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/pylib-android/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-android/email/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/pylib-android/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-android/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/pylib-android/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/pylib-android/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/pylib-android/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/pylib-android/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ build/pylib-android/enum.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/pylib-android/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/pylib-android/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/pylib-android/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/pylib-android/formatter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/pylib-android/fractions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/pylib-android/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ build/pylib-android/functools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/pylib-android/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/pylib-android/getopt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/pylib-android/getpass.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/pylib-android/gettext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ build/pylib-android/glob.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/pylib-android/gzip.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/pylib-android/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/pylib-android/heapq.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/pylib-android/hmac.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/pylib-android/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/pylib-android/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-android/http/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/pylib-android/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/pylib-android/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-android/http/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/pylib-android/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ build/pylib-android/imp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/pylib-android/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/pylib-android/inspect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ build/pylib-android/io.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/pylib-android/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/pylib-android/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/pylib-android/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/pylib-android/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/pylib-android/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/pylib-android/keyword.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/pylib-android/linecache.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ build/pylib-android/locale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/pylib-android/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/pylib-android/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/pylib-android/lzma.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/pylib-android/macpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/pylib-android/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/pylib-android/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/pylib-android/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/pylib-android/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/pylib-android/netrc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/pylib-android/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/pylib-android/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/pylib-android/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/pylib-android/numbers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/pylib-android/opcode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ build/pylib-android/operator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/pylib-android/optparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ build/pylib-android/os.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/pylib-android/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/pylib-android/pdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/pylib-android/pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/pylib-android/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/pylib-android/pipes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/pylib-android/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ build/pylib-android/platform.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/pylib-android/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/pylib-android/poplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/pylib-android/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/pylib-android/pprint.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ build/pylib-android/profile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/pylib-android/pstats.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ build/pylib-android/pty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/pylib-android/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/pylib-android/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/pylib-android/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ build/pylib-android/queue.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/pylib-android/quopri.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ build/pylib-android/random.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ build/pylib-android/re.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/pylib-android/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/pylib-android/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/pylib-android/runpy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ build/pylib-android/sched.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/pylib-android/secrets.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/pylib-android/selectors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/pylib-android/shelve.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/pylib-android/shlex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/pylib-android/shutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ build/pylib-android/signal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ build/pylib-android/site.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/pylib-android/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/pylib-android/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/pylib-android/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ build/pylib-android/socket.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/pylib-android/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/pylib-android/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/pylib-android/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/pylib-android/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/pylib-android/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/pylib-android/ssl.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ build/pylib-android/stat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/pylib-android/statistics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ build/pylib-android/string.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/pylib-android/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ build/pylib-android/struct.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/pylib-android/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/pylib-android/sunau.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/pylib-android/symbol.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/pylib-android/symtable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/pylib-android/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/pylib-android/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/pylib-android/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/pylib-android/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/pylib-android/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/pylib-android/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ build/pylib-android/this.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ build/pylib-android/threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/pylib-android/timeit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ build/pylib-android/token.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/pylib-android/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ build/pylib-android/trace.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/pylib-android/traceback.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/pylib-android/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ build/pylib-android/tty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ build/pylib-android/types.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ build/pylib-android/typing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/pylib-android/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ build/pylib-android/uu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/pylib-android/uuid.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/pylib-android/warnings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ build/pylib-android/wave.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/pylib-android/weakref.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/pylib-android/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/pylib-android/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/pylib-android/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/pylib-android/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/pylib-android/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/pylib-android/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/pylib-android/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/pylib-android/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/pylib-android/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_COMMON = \ @@ -7944,7 +7944,7 @@ SCRIPT_TARGETS_PYC_PRIVATE_COMMON = \ # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) $(SCRIPT_TARGETS_PY_PRIVATE_COMMON) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Looks like path mangling from py to pyc is too complex for pattern rules so # just generating explicit targets for each. Could perhaps look into using a @@ -7953,92 +7953,92 @@ $(SCRIPT_TARGETS_PY_PRIVATE_COMMON) : ../.efrocachemap build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/typing_extensions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/composer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/constructor.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/cyaml.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/dumper.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/emitter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/loader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/nodes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/parser.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/reader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/representer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/resolver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/scanner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/serializer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc: \ build/ba_data/python-site-packages/yaml/tokens.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ @@ -9384,7 +9384,7 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) $(SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Looks like path mangling from py to pyc is too complex for pattern rules so # just generating explicit targets for each. Could perhaps look into using a @@ -9393,3342 +9393,3342 @@ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32) : ../.efrocachemap build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/__future__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_compression.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/aifc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/argparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ast.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/base64.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/binhex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bisect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/bz2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/calendar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cgi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/chunk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/code.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/codecs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/codeop.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/compileall.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/configparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/copy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/crypt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/csv.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_anon.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_arrays.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_as_parameter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_bitfields.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_buffers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_bytes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_byteswap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_callbacks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_cast.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_cfuncs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_checkretval.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_delattr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_errno.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_find.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_frombuffer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_funcptr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_functions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_incomplete.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_init.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_internals.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_keeprefs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_libc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_loading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_macholib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_memfunctions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_numbers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_objects.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_parameters.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pep3118.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_values.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/datetime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/dumb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/gnu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dbm/ndbm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/decimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/difflib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/archive_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/ccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_clib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_py.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/check.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/clean.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_data.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_egg_info.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_headers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_lib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/register.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/sdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/command/upload.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/core.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/debug.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dep_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dir_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/dist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/errors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/extension.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/fancy_getopt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/file_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/filelist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/spawn.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_archive_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_clib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_py.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_check.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_clean.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_config_cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_core.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dep_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dir_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_dist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_extension.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_file_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_filelist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_data.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_headers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_lib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_register.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_sdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_spawn.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_text_file.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_upload.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_version.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/text_file.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/version.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/distutils/versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/doctest.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/header.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ensurepip/_uninstall.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/enum.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/formatter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/fractions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/functools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/getopt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/getpass.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/gettext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/glob.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/gzip.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/heapq.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/hmac.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/http/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imaplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/imp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/inspect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/io.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/keyword.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/linecache.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/locale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/lzma.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/macpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/schema.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/sequence.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/msilib/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/connection.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/context.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/heap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/managers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/pool.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/process.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/queues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/reduction.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/spawn.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/multiprocessing/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/netrc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/numbers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/opcode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/operator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/optparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/os.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pipes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/platform.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/poplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pprint.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/profile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pstats.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc_data/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/pydoc_data/topics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/queue.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/quopri.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/random.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/re.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/runpy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sched.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/secrets.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/selectors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shelve.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shlex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/shutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/signal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/site.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/socket.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/backup.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/dump.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/factory.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/regression.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/types.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/ssl.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/stat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/statistics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/string.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/struct.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sunau.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/symbol.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/symtable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/this.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/timeit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/token.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/trace.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/traceback.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/tty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/turtle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/types.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/typing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/case.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/loader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/main.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/mock.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/result.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/runner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/signals.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/suite.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/_test_warnings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/dummy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_break.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_case.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_discovery.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_loader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_program.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_result.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_runner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_setups.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_skipping.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/test_suite.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/unittest/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/uu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/uuid.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/venv/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/venv/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/warnings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wave.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/weakref.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/handlers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/headers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/simple_server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/wsgiref/validate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/windows/Win32/Lib/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ @@ -14074,7 +14074,7 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) $(SCRIPT_TARGETS_PY_PRIVATE_WIN_X64) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Looks like path mangling from py to pyc is too complex for pattern rules so # just generating explicit targets for each. Could perhaps look into using a @@ -14083,3342 +14083,3342 @@ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_X64) : ../.efrocachemap build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/__future__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/__phello__.foo.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_bootlocale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_collections_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_compat_pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_compression.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_dummy_thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_markupbase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_osx_support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_py_abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_pydecimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_pyio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_sitebuiltins.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_strptime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_threading_local.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/_weakrefset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/aifc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/antigravity.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/argparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ast.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asynchat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/base_tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/coroutines.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/format_helpers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/futures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/locks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/proactor_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/protocols.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/queues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/runners.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/selector_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/sslproto.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/streams.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/tasks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/transports.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/unix_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/windows_events.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncio/windows_utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/asyncore.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/base64.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/binhex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bisect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/bz2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cProfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/calendar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cgi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cgitb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/chunk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/code.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/codecs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/codeop.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/collections/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/collections/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/colorsys.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/compileall.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/_base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/process.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/concurrent/futures/thread.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/configparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/contextlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/contextvars.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/copy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/copyreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/crypt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/csv.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/_aix.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/_endian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/dyld.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/dylib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/macholib/framework.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_anon.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_arrays.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_as_parameter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_bitfields.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_buffers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_bytes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_byteswap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_callbacks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_cast.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_cfuncs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_checkretval.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_delattr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_errno.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_find.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_frombuffer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_funcptr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_functions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_incomplete.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_init.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_internals.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_keeprefs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_libc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_loading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_macholib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_memfunctions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_numbers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_objects.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_parameters.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pep3118.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pickling.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_pointers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_prototypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_python_api.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_random_things.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_refcounts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_repr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_sizes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_slicing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_stringptr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_strings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_struct_fields.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_structures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_unicode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_values.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_varsize_struct.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_win32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/test/test_wintypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ctypes/wintypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/has_key.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/panel.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/curses/textpad.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dataclasses.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/datetime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/dumb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/gnu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dbm/ndbm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/decimal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/difflib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/archive_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/bcppcompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/ccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_clib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_py.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/check.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/clean.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_data.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_egg_info.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_headers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_lib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/register.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/sdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/command/upload.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/core.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/debug.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dep_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dir_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/dist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/errors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/extension.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/fancy_getopt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/file_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/filelist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/spawn.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_archive_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_msi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_clib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_py.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_build_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_check.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_clean.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_config_cmd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_core.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dep_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dir_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_dist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_extension.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_file_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_filelist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_data.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_headers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_lib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_install_scripts.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_log.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_msvccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_register.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_sdist.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_spawn.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_text_file.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_upload.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_version.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/tests/test_versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/text_file.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/unixccompiler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/version.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/distutils/versionpredicate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/doctest.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/dummy_threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_encoded_words.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_header_value_parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_parseaddr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/_policybase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/base64mime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/charset.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/contentmanager.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/encoders.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/errors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/feedparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/generator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/header.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/headerregistry.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/iterators.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/application.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/audio.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/base.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/image.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/message.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/multipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/nonmultipart.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/mime/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/policy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/quoprimime.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/email/utils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/aliases.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/ascii.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/base64_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/big5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/big5hkscs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/bz2_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/charmap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp037.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1006.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1026.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1125.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1140.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1250.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1251.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1252.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1253.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1254.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1255.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1256.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1257.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp1258.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp273.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp424.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp437.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp500.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp65001.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp720.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp737.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp775.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp850.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp852.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp855.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp856.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp857.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp858.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp860.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp861.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp862.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp863.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp864.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp865.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp866.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp869.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp874.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp875.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp932.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp949.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/cp950.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/euc_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gb18030.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gb2312.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/gbk.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hex_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hp_roman8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/hz.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/idna.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_jp_ext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso2022_kr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_10.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_11.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_14.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_15.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_3.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_4.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_5.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_6.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/iso8859_9.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/johab.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_r.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_t.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/koi8_u.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/kz1048.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/latin_1.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_arabic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_centeuro.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_croatian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_cyrillic.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_farsi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_greek.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_iceland.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_latin2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_roman.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_romanian.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mac_turkish.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/mbcs.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/oem.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/palmos.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/ptcp154.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/punycode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/quopri_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/raw_unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/rot_13.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jis.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jis_2004.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/shift_jisx0213.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/tis_620.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/undefined.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/unicode_escape.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/unicode_internal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_16_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32_be.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_32_le.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_7.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/utf_8_sig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/uu_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/encodings/zlib_codec.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ensurepip/_uninstall.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/enum.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/filecmp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fileinput.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fnmatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/formatter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/fractions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ftplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/functools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/genericpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/getopt.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/getpass.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/gettext.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/glob.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/gzip.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/hashlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/heapq.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/hmac.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/entities.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/html/parser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/cookiejar.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/cookies.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/http/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imaplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imghdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/imp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/_bootstrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/_bootstrap_external.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/abc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/machinery.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/resources.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/importlib/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/inspect.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/io.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ipaddress.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/decoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/encoder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/scanner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/json/tool.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/keyword.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/linecache.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/locale.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/config.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/logging/handlers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/lzma.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/macpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mailbox.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mailcap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/mimetypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/modulefinder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/schema.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/sequence.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/msilib/text.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/connection.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/context.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/dummy/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/dummy/connection.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/forkserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/heap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/managers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/pool.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_fork.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_forkserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/process.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/queues.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/reduction.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/resource_sharer.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/semaphore_tracker.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/sharedctypes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/spawn.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/synchronize.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/multiprocessing/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/netrc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/nntplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ntpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/nturl2path.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/numbers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/opcode.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/operator.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/optparse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/os.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pathlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pdb.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pickle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pickletools.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pipes.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pkgutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/platform.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/plistlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/poplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/posixpath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pprint.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/profile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pstats.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/py_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pyclbr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc_data/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/pydoc_data/topics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/queue.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/quopri.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/random.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/re.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/reprlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/rlcompleter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/runpy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sched.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/secrets.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/selectors.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shelve.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shlex.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/shutil.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/signal.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/site.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/smtpd.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/smtplib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sndhdr.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/socket.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/socketserver.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/dbapi2.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/dump.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/backup.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/dbapi.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/dump.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/factory.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/hooks.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/regression.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/transactions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/types.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sqlite3/test/userfunctions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_compile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_constants.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sre_parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/ssl.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/stat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/statistics.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/string.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/stringprep.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/struct.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/subprocess.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sunau.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/symbol.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/symtable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/sysconfig.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tabnanny.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tarfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/telnetlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tempfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/textwrap.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/this.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/threading.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/timeit.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/token.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tokenize.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/trace.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/traceback.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tracemalloc.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/tty.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/turtle.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/types.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/typing.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/case.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/loader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/main.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/mock.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/result.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/runner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/signals.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/suite.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/_test_warnings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/dummy.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_assertions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_break.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_case.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_discovery.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_functiontestcase.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_loader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_program.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_result.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_runner.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_setups.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_skipping.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/test_suite.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/support.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testcallable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testhelpers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testmock.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testpatch.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testsealable.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testsentinel.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/test/testmock/testwith.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/unittest/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/error.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/parse.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/request.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/response.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/urllib/robotparser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/uu.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/uuid.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/venv/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/venv/__main__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/warnings.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wave.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/weakref.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/webbrowser.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/handlers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/headers.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/simple_server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/util.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/wsgiref/validate.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xdrlib.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/NodeFilter.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/domreg.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/expatbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/minicompat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/minidom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/pulldom.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/dom/xmlbuilder.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementInclude.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementPath.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/ElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/etree/cElementTree.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/parsers/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/parsers/expat.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/_exceptions.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/expatreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/handler.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/saxutils.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xml/sax/xmlreader.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/__init__.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/client.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/xmlrpc/server.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/zipapp.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ build/windows/x64/Lib/zipfile.py @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets compile_python_files $^ && chmod 444 $@ + @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ COB_TARGETS = \ @@ -20040,7 +20040,7 @@ EXTRAS_TARGETS_WIN_WIN32 = \ # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_WIN32) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ EXTRAS_TARGETS_WIN_X64 = \ @@ -20105,53 +20105,53 @@ EXTRAS_TARGETS_WIN_X64 = \ # Rule to copy src extras to build. $(EXTRAS_TARGETS_WIN_X64) : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ #AUTOGENERATED_END_PRIVATE ASSET_TARGETS_COMMON += $(MODEL_TARGETS) build/%.bob : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%.cob : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%.ogg : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%.fdata : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Langdata one-off json file. build/ba_data/data/langdata.json : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Languages json files. build/ba_data/data/languages/%.json : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ # Map json files. build/ba_data/data/maps/%.json : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ src/%.tex2d.png : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ src/%_+x.tex2d.png : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%_preview.png : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%.dds : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%.pvr : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ build/%.ktx : ../.efrocachemap - @cd .. && tools/snippets efrocache_get assets/$@ + @cd .. && tools/pcommand efrocache_get assets/$@ audio: $(AUDIO_TARGETS) clean-audio: diff --git a/assets/src/ba_data/python/bastd/ui/tournamententry.py b/assets/src/ba_data/python/bastd/ui/tournamententry.py index 6b53b2d9..3fe494a9 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamententry.py +++ b/assets/src/ba_data/python/bastd/ui/tournamententry.py @@ -461,7 +461,7 @@ class TournamentEntryWindow(popup.PopupWindow): # This is not ideal since players will have to rejoin, etc., # but it works for now. except Exception: - print('Error restarting tournament activity.') + ba.print_exception('Error restarting tournament activity.') # If we had no existing activity (or were unable to restart it) # launch a new session. diff --git a/config/toolconfigsrc/pycheckers b/config/toolconfigsrc/pycheckers index a5f89bb5..556740c8 100644 --- a/config/toolconfigsrc/pycheckers +++ b/config/toolconfigsrc/pycheckers @@ -2,4 +2,4 @@ checkers= pylint, mypy3 mypy_config_file=.mypy.ini mypy_use_daemon=true -mypy_daemon_files_command=tools/snippets scriptfiles -lines +mypy_daemon_files_command=tools/pcommand scriptfiles -lines diff --git a/docs/ba_module.md b/docs/ba_module.md index 5a38c794..d9f9e73f 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-03 for Ballistica version 1.5.17 build 20102

    +

    last updated on 2020-07-03 for Ballistica version 1.5.17 build 20104

    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!


    diff --git a/tools/batools/build.py b/tools/batools/build.py index a918883f..f7e62995 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -201,7 +201,7 @@ def lazybuild(target: str, category: SourceCategory, command: str) -> None: # Everything possibly affecting resource builds. elif category is SourceCategory.RESOURCES: paths = [ - 'Makefile', 'tools/snippets', 'resources/src', 'resources/Makefile' + 'Makefile', 'tools/pcommand', 'resources/src', 'resources/Makefile' ] else: raise ValueError(f'Invalid source category: {category}') @@ -284,22 +284,22 @@ def gen_fulltest_buildfile_android() -> None: extras = [e for e in extras if e.startswith('android.')] for extra in extras: if extra == 'android.pylibs.arm': - lines.append('tools/snippets python_build_android arm') + lines.append('tools/pcommand python_build_android arm') elif extra == 'android.pylibs.arm.debug': - lines.append('tools/snippets python_build_android_debug arm') + lines.append('tools/pcommand python_build_android_debug arm') elif extra == 'android.pylibs.arm64': - lines.append('tools/snippets python_build_android arm64') + lines.append('tools/pcommand python_build_android arm64') elif extra == 'android.pylibs.arm64.debug': - lines.append('tools/snippets python_build_android_debug arm64') + lines.append('tools/pcommand python_build_android_debug arm64') elif extra == 'android.pylibs.x86': - lines.append('tools/snippets python_build_android x86') + lines.append('tools/pcommand python_build_android x86') elif extra == 'android.pylibs.x86.debug': - lines.append('tools/snippets python_build_android_debug x86') + lines.append('tools/pcommand python_build_android_debug x86') elif extra == 'android.pylibs.x86_64': - lines.append('tools/snippets python_build_android x86_64') + lines.append('tools/pcommand python_build_android x86_64') elif extra == 'android.pylibs.x86_64.debug': lines.append( - 'tools/snippets python_build_android_debug x86_64') + 'tools/pcommand python_build_android_debug x86_64') elif extra == 'android.package': lines.append('make android-package') else: @@ -375,9 +375,9 @@ def gen_fulltest_buildfile_apple() -> None: extras = [e for e in extras if e.startswith('ios.')] for extra in extras: if extra == 'ios.pylibs': - lines.append('tools/snippets python_build_apple ios') + lines.append('tools/pcommand python_build_apple ios') elif extra == 'ios.pylibs.debug': - lines.append('tools/snippets python_build_apple_debug ios') + lines.append('tools/pcommand python_build_apple_debug ios') else: raise RuntimeError(f'Unknown extra: {extra}') @@ -388,9 +388,9 @@ def gen_fulltest_buildfile_apple() -> None: extras = [e for e in extras if e.startswith('tvos.')] for extra in extras: if extra == 'tvos.pylibs': - lines.append('tools/snippets python_build_apple tvos') + lines.append('tools/pcommand python_build_apple tvos') elif extra == 'tvos.pylibs.debug': - lines.append('tools/snippets python_build_apple_debug tvos') + lines.append('tools/pcommand python_build_apple_debug tvos') else: raise RuntimeError(f'Unknown extra: {extra}') @@ -410,9 +410,9 @@ def gen_fulltest_buildfile_apple() -> None: elif extra == 'mac.package.server': lines.append('make mac-server-package') elif extra == 'mac.pylibs': - lines.append('tools/snippets python_build_apple mac') + lines.append('tools/pcommand python_build_apple mac') elif extra == 'mac.pylibs.debug': - lines.append('tools/snippets python_build_apple_debug mac') + lines.append('tools/pcommand python_build_apple_debug mac') else: raise RuntimeError(f'Unknown extra: {extra}') @@ -540,7 +540,7 @@ def checkenv() -> None: f' found {_vstr(vnums)}.\n' f'To upgrade it, try: "{PYTHON_BIN}' f' -m pip install --upgrade {packagename}".\n' - 'Alternately, "tools/snippets install_pip_reqs"' + 'Alternately, "tools/pcommand install_pip_reqs"' ' will update all pip requirements.') print(f'{Clr.BLD}Environment ok.{Clr.RST}', flush=True) diff --git a/tools/batools/snippets.py b/tools/batools/pcommand.py similarity index 98% rename from tools/batools/snippets.py rename to tools/batools/pcommand.py index a17d84fb..fcc19735 100644 --- a/tools/batools/snippets.py +++ b/tools/batools/pcommand.py @@ -18,7 +18,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ----------------------------------------------------------------------------- -"""Standard snippets that can be pulled into project snippets scripts. +"""Standard snippets that can be pulled into project pcommand scripts. A snippet is a mini-program that directly takes input from stdin and does some focused task. This module consists of ballistica-specific ones. @@ -30,7 +30,7 @@ from __future__ import annotations import sys from typing import TYPE_CHECKING -from efrotools.snippets import PROJROOT +from efrotools.pcommand import PROJROOT if TYPE_CHECKING: from typing import Optional, List, Set @@ -171,7 +171,7 @@ def check_mac_ssh() -> None: if ('UsePAM yes' in lines or '#PasswordAuthentication yes' in lines or '#ChallengeResponseAuthentication yes' in lines): print('ERROR: ssh config is allowing password access.\n' - 'To fix: sudo tools/snippets fix_mac_ssh') + 'To fix: sudo tools/pcommand fix_mac_ssh') sys.exit(255) print('password ssh auth seems disabled; hooray!') @@ -204,7 +204,7 @@ def check_clean_safety() -> None: adding something. """ import os - from efrotools.snippets import check_clean_safety as std_snippet + from efrotools.pcommand import check_clean_safety as std_snippet # First do standard checks. std_snippet() @@ -304,7 +304,7 @@ def androidaddr() -> None: from efro.error import CleanError if len(sys.argv) != 5: raise CleanError(f'ERROR: expected 3 args; got {len(sys.argv) - 2}\n' - f'Usage: "tools/snippets android_addr' + f'Usage: "tools/pcommand android_addr' f' "') archive_dir = sys.argv[2] arch = sys.argv[3] diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index d6724e0a..f58dda6c 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -158,7 +158,7 @@ def filter_makefile(makefile_dir: str, contents: str) -> str: cachemap = os.path.join(to_proj_root, CACHE_MAP_NAME) lines = contents.splitlines() - snippets = 'tools/snippets' + pcommand = 'tools/pcommand' # Strip out parts they don't want. while STRIP_BEGIN_TAG in lines: @@ -184,7 +184,7 @@ def filter_makefile(makefile_dir: str, contents: str) -> str: lines.insert(index, tname + ': ' + cachemap) target = (makefile_dir + '/' + '$@') if makefile_dir else '$@' pre = f'cd {to_proj_root} && ' if makefile_dir else '' - lines.insert(index + 1, f'\t@{pre}{snippets} efrocache_get {target}') + lines.insert(index + 1, f'\t@{pre}{pcommand} efrocache_get {target}') return '\n'.join(lines) + '\n' diff --git a/tools/efrotools/snippets.py b/tools/efrotools/pcommand.py similarity index 97% rename from tools/efrotools/snippets.py rename to tools/efrotools/pcommand.py index da95b003..5609ec37 100644 --- a/tools/efrotools/snippets.py +++ b/tools/efrotools/pcommand.py @@ -18,11 +18,11 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ----------------------------------------------------------------------------- -"""Standard snippets that can be pulled into project snippets scripts. +"""Standard snippets that can be pulled into project pcommand scripts. A snippet is a mini-program that directly takes input from stdin and does some focused task. This module is a repository of common snippets that can -be imported into projects' snippets script for easy reuse. +be imported into projects' pcommand script for easy reuse. """ from __future__ import annotations @@ -39,8 +39,8 @@ if TYPE_CHECKING: PROJROOT = Path(__file__).resolve().parents[2] -def snippets_main(globs: Dict[str, Any]) -> None: - """Run a snippet contained in the snippets script. +def pcommand_main(globs: Dict[str, Any]) -> None: + """Run a snippet contained in the pcommand script. We simply look for all public functions and call the one corresponding to the first passed arg. @@ -49,7 +49,7 @@ def snippets_main(globs: Dict[str, Any]) -> None: from efro.error import CleanError from efro.terminal import Clr funcs = dict(((name, obj) for name, obj in globs.items() - if not name.startswith('_') and name != 'snippets_main' + if not name.startswith('_') and name != 'pcommand_main' and isinstance(obj, types.FunctionType))) show_help = False retval = 0 @@ -67,7 +67,7 @@ def snippets_main(globs: Dict[str, Any]) -> None: else: docs = _trim_docstring( getattr(funcs[sys.argv[2]], '__doc__', '')) - print(f'\n{Clr.MAG}{Clr.BLD}snippets {sys.argv[2]}:{Clr.RST}\n' + print(f'\n{Clr.MAG}{Clr.BLD}pcommand {sys.argv[2]}:{Clr.RST}\n' f'{Clr.MAG}{docs}{Clr.RST}\n') elif sys.argv[1] in funcs: try: @@ -80,14 +80,14 @@ def snippets_main(globs: Dict[str, Any]) -> None: sys.exit(1) else: print( - f'{Clr.RED}Unknown snippets command: "{sys.argv[1]}"{Clr.RST}', + f'{Clr.RED}Unknown pcommand command: "{sys.argv[1]}"{Clr.RST}', file=sys.stderr) retval = 255 if show_help: - print('Snippets contains project related commands too small' + print('Pcommand contains project related commands too small' ' to warrant full scripts.') - print(f"Run {Clr.MAG}'snippets help {Clr.BLD}'" + print(f"Run {Clr.MAG}'pcommand help {Clr.BLD}'" f'{Clr.RST} for full command documentation.') print('Available commands:') for func, obj in sorted(funcs.items()): diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index 865d270f..3d7f93a4 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -291,7 +291,7 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: ftxt, ' def build(self):', ' def build(self):\n import os\n' ' if os.system(\'"' + rootdir + - '/tools/snippets" python_android_patch "' + os.getcwd() + + '/tools/pcommand" python_android_patch "' + os.getcwd() + '"\') != 0: raise Exception("patch apply failed")') efrotools.writefile('pybuild/packages/python.py', ftxt) diff --git a/tools/snippets b/tools/pcommand similarity index 95% rename from tools/snippets rename to tools/pcommand index 1b862fc3..481e3366 100755 --- a/tools/snippets +++ b/tools/pcommand @@ -37,13 +37,13 @@ from typing import TYPE_CHECKING # Pull in the snippets we want to expose. Its more efficient to define them in # modules rather than inline here because we'll be able to load them via pyc. # pylint: disable=unused-import -from efrotools.snippets import ( - PROJROOT, snippets_main, formatcode, formatscripts, formatmakefile, +from efrotools.pcommand import ( + PROJROOT, pcommand_main, formatcode, formatscripts, formatmakefile, cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install, sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, makefile_target_list, spelling, spelling_all, pytest, echo, compile_python_files) -from batools.snippets import ( +from batools.pcommand import ( stage_server_file, py_examine, fix_mac_ssh, check_mac_ssh, resize_image, check_clean_safety, clean_orphaned_assets, archive_old_builds, lazy_increment_build, get_master_asset_src_dir, androidaddr, push_ipa, @@ -62,4 +62,4 @@ if TYPE_CHECKING: pass if __name__ == '__main__': - snippets_main(globals()) + pcommand_main(globals()) diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile index dfe2b626..139ac46c 100755 --- a/tools/update_assets_makefile +++ b/tools/update_assets_makefile @@ -187,7 +187,7 @@ def _get_py_targets_subset(all_targets: Set[str], subset: str, # For now setting PYTHONHASHSEED=1 is a workaround. out += ('\n' + target + ': \\\n ' + py_targets[i] + '\n\t@echo Compiling script: $^\n' - '\t@rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/snippets' + '\t@rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand' ' compile_python_files $^' ' && chmod 444 $@\n') diff --git a/tools/update_project b/tools/update_project index 2eea0210..5f5f49b2 100755 --- a/tools/update_project +++ b/tools/update_project @@ -155,7 +155,7 @@ class App: # been updated. # (only do this if gendocs is available) if os.path.exists('tools/gendocs.py'): - if os.system('tools/snippets update_docs_md' + + if os.system('tools/pcommand update_docs_md' + self._checkarg) != 0: print(f'{Clr.RED}Error checking/updating' f' docs markdown.{Clr.RST}') @@ -628,7 +628,7 @@ class App: def _check_sync_states(self) -> None: # Make sure none of our sync targets have been mucked with since # their last sync. - if os.system('tools/snippets sync check') != 0: + if os.system('tools/pcommand sync check') != 0: print(Clr.RED + 'Sync check failed; you may need to run "sync".' + Clr.RST) sys.exit(255) From 7987313e3cb77429d9b09f6e9051c0b8f5c2b971 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 3 Jul 2020 16:49:02 -0700 Subject: [PATCH 127/417] fixed github ci --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 704be58b..6caf140f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,7 @@ jobs: with: python-version: 3.7 - name: Install dependencies - run: tools/snippets install_pip_reqs + run: tools/pcommand install_pip_reqs - name: Run checks and tests run: make -j2 check test @@ -42,5 +42,5 @@ jobs: python -m pip install --upgrade pip pip install pytest typing_extensions - name: Run tests - run: python tools/snippets pytest -v tests + run: python tools/pcommand pytest -v tests From c20820c1061b511085d5827e82da118dc3650448 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 3 Jul 2020 18:27:35 -0700 Subject: [PATCH 128/417] Simplified asset makefile --- .idea/dictionaries/ericf.xml | 1 + assets/Makefile | 12335 +-------------------------------- tools/update_assets_makefile | 34 +- 3 files changed, 62 insertions(+), 12308 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 98cf369f..255c242b 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -572,6 +572,7 @@ encerr endcall endcommand + endef endindex endmessage endparen diff --git a/assets/Makefile b/assets/Makefile index 4f4f01d1..a9906ad4 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -139,6 +139,13 @@ endif ASSET_TARGETS_WIN_WIN32 += $(EXTRAS_TARGETS_WIN_WIN32) ASSET_TARGETS_WIN_X64 += $(EXTRAS_TARGETS_WIN_X64) +define make-opt-pyc-target +$1: $$(subst /__pycache__,,$$(subst .cpython-37.opt-1.pyc,.py,$1)) + @echo Compiling script: $$^ + @rm -rf $$@ && PYTHONHASHSEED=1 \ + $$(TOOLS_DIR)/pcommand compile_python_files $$^ && chmod 444 $$@ +endef + #AUTOGENERATED_BEGIN_PUBLIC (this section is managed by "update_project") SCRIPT_TARGETS_PY_PUBLIC = \ @@ -612,1155 +619,10 @@ $(SCRIPT_TARGETS_PY_PUBLIC) : build/%.py : src/%.py @cp $^ $@ @chmod 444 $@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_account.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_achievement.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_activity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_activitytypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_actor.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_analytics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_app.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_appconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_appdelegate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_apputils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_assetmanager.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_benchmark.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_campaign.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_collision.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_coopgame.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_coopsession.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_dependency.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_dualteamsession.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_enums.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_freeforallsession.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gameactivity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gameresults.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_gameutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_general.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_hooks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_input.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_lang.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_level.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_lobby.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_map.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_math.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_messages.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_meta.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_multiteamsession.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_music.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_netutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_nodeactor.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_player.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_playlist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_powerup.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_profile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_score.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_servermode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_session.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_settings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_stats.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_store.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_team.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_teamgame.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_tips.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/_tournament.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/deprecated.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/internal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/macmusicapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/modutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/osmusic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/ba/ui/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/coopjoin.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/coopscore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/drawscore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/dualteamscore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/freeforallvictory.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/multiteamjoin.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/multiteamscore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/activity/multiteamvictory.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/background.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/bomb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/controlsguide.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/flag.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/image.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/onscreencountdown.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/onscreentimer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/playerspaz.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/popuptext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/powerupbox.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/respawnicon.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/scoreboard.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spawner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spaz.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spazappearance.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spazbot.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/spazfactory.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/tipstext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/actor/zoomtext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/appdelegate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/assault.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/capturetheflag.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/chosenone.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/conquest.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/deathmatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/easteregghunt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/elimination.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/football.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/hockey.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/keepaway.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/kingofthehill.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/meteorshower.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/ninjafight.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/onslaught.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/race.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/runaround.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/targetpractice.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/game/thelaststand.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/gameutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mainmenu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/big_g.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/bridgit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/courtyard.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/crag_castle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/doom_shroom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/football_stadium.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/happy_thoughts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/hockey_stadium.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/lake_frigid.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/monkey_face.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/rampage.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/roundabout.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/step_right_up.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/the_pad.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/tip_top.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/tower_d.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/mapdata/zig_zag.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/maps.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/session/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/stdmap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/tutorial.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/link.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/settings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/unlink.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/account/viewer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/achievements.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/appinvite.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/characterpicker.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/colorpicker.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/configerror.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/confirm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/continues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/browser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/gamebutton.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/coop/level.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/creditslist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/debug.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/feedback.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/fileselector.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/gather.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/getcurrency.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/getremote.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/helpui.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/iconpicker.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/kiosk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/league/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/league/rankbutton.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/league/rankwindow.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/mainmenu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/onscreenkeyboard.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/party.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/partyqueue.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/play.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/addgame.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/browser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/customizebrowser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/edit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/editcontroller.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/editgame.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/mapselect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playlist/share.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/playoptions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/popup.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/browser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/edit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/profile/upgrade.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/promocode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/purchase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/qrcode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/radiogroup.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/report.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/resourcetypeinfo.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/serverdialog.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/advanced.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/allsettings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/audio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/controls.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/gamepad.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/gamepadadvanced.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/gamepadselect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/graphics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/keyboard.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/nettesting.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/ps3controller.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/remoteapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/testing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/touchscreen.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/vrtesting.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/wiimote.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/settings/xbox360controller.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/browser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/edit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/soundtrack/macmusicapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/specialoffer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/store/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/store/browser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/store/button.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/store/item.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/tabs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/teamnamescolors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/telnet.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/tournamententry.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/tournamentscores.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/trophies.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/url.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc: \ - build/ba_data/python/bastd/ui/watch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc: \ - build/server/ballisticacore_server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PUBLIC),\ +$(eval $(call make-opt-pyc-target,$(element)))) SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \ build/ba_data/python/bacommon/__init__.py \ @@ -1811,100 +673,10 @@ $(SCRIPT_TARGETS_PY_PUBLIC_TOOLS) : build/ba_data/python/%.py : ../tools/%.py @cp $^ $@ @chmod 444 $@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/bacommon/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bacommon/__pycache__/assets.cpython-37.opt-1.pyc: \ - build/ba_data/python/bacommon/assets.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc: \ - build/ba_data/python/bacommon/err.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc: \ - build/ba_data/python/bacommon/servermanager.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/call.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/dataclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_entity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_field.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/_value.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/entity/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/json.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/terminal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc: \ - build/ba_data/python/efro/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PUBLIC_TOOLS),\ +$(eval $(call make-opt-pyc-target,$(element)))) #AUTOGENERATED_END_PUBLIC #AUTOGENERATED_BEGIN_PRIVATE (this section is managed by "update_project") @@ -2770,2140 +1542,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ $(SCRIPT_TARGETS_PY_PRIVATE_APPLE) : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/pylib-apple/__future__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ - build/pylib-apple/__phello__.foo.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/pylib-apple/_bootlocale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/_collections_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/pylib-apple/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/pylib-apple/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/pylib-apple/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/pylib-apple/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/pylib-apple/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ - build/pylib-apple/_pydecimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/pylib-apple/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/pylib-apple/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/pylib-apple/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/pylib-apple/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/pylib-apple/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/pylib-apple/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/pylib-apple/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/pylib-apple/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/pylib-apple/ast.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/pylib-apple/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/pylib-apple/asyncore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/pylib-apple/base64.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/pylib-apple/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/pylib-apple/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/pylib-apple/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/pylib-apple/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/pylib-apple/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/pylib-apple/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/pylib-apple/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/pylib-apple/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/pylib-apple/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc: \ - build/pylib-apple/code.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/pylib-apple/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/pylib-apple/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/collections/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/pylib-apple/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/pylib-apple/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/pylib-apple/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/pylib-apple/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/pylib-apple/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/pylib-apple/copy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/pylib-apple/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/pylib-apple/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/pylib-apple/csv.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/_aix.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/_endian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/macholib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/macholib/dylib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/pylib-apple/ctypes/wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/has_key.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/panel.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/pylib-apple/curses/textpad.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/pylib-apple/dataclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/pylib-apple/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/pylib-apple/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/pylib-apple/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/pylib-apple/dis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/pylib-apple/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/pylib-apple/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/pylib-apple/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/base64_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/big5hkscs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/charmap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1026.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1125.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1140.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1252.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1253.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1256.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1257.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp1258.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp273.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp775.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp852.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp857.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp858.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp863.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp866.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp869.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp949.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/euc_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/gbk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/hp_roman8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/idna.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso2022_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_10.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_11.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_14.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_15.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_6.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/johab.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/koi8_r.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/koi8_t.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_arabic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_centeuro.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_croatian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_farsi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_greek.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_iceland.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_latin2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_roman.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_romanian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/oem.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/ptcp154.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/punycode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/raw_unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/rot_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/shift_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/unicode_internal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_16_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_32_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/utf_8_sig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/pylib-apple/encodings/zlib_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/pylib-apple/enum.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/pylib-apple/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/pylib-apple/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/pylib-apple/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/pylib-apple/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/pylib-apple/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/pylib-apple/functools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/pylib-apple/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/pylib-apple/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/pylib-apple/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/pylib-apple/glob.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/pylib-apple/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/pylib-apple/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/pylib-apple/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/html/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc: \ - build/pylib-apple/html/entities.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-apple/html/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/cookiejar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/cookies.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-apple/http/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/pylib-apple/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/pylib-apple/imp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-apple/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/pylib-apple/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc: \ - build/pylib-apple/io.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/pylib-apple/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/decoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/encoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/scanner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/pylib-apple/json/tool.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/pylib-apple/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/pylib-apple/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/pylib-apple/locale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/pylib-apple/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/pylib-apple/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/pylib-apple/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/pylib-apple/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/pylib-apple/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/pylib-apple/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/pylib-apple/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/pylib-apple/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/ntpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/pylib-apple/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/pylib-apple/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/pylib-apple/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/pylib-apple/operator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/pylib-apple/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc: \ - build/pylib-apple/os.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/pathlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/pylib-apple/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/pylib-apple/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/pylib-apple/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/pylib-apple/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/pylib-apple/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/pylib-apple/platform.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/pylib-apple/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/pylib-apple/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/pylib-apple/profile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/pylib-apple/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/pylib-apple/pty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/pylib-apple/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/pylib-apple/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/pylib-apple/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/pylib-apple/queue.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/pylib-apple/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc: \ - build/pylib-apple/random.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc: \ - build/pylib-apple/re.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/pylib-apple/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/pylib-apple/runpy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/pylib-apple/sched.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/pylib-apple/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/pylib-apple/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/pylib-apple/shelve.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/pylib-apple/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/pylib-apple/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/pylib-apple/signal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc: \ - build/pylib-apple/site.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/pylib-apple/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/pylib-apple/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/pylib-apple/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/pylib-apple/socket.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/pylib-apple/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/sqlite3/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/pylib-apple/sqlite3/dbapi2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/pylib-apple/sqlite3/dump.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/pylib-apple/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/pylib-apple/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/pylib-apple/sre_parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/pylib-apple/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/pylib-apple/stat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/pylib-apple/statistics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc: \ - build/pylib-apple/string.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/pylib-apple/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/pylib-apple/struct.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-apple/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/pylib-apple/sunau.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/pylib-apple/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/pylib-apple/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/pylib-apple/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/pylib-apple/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/pylib-apple/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc: \ - build/pylib-apple/this.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/pylib-apple/threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/pylib-apple/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc: \ - build/pylib-apple/token.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/pylib-apple/tokenize.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/pylib-apple/trace.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/pylib-apple/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/pylib-apple/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/pylib-apple/tty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc: \ - build/pylib-apple/types.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/pylib-apple/typing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/request.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/response.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/pylib-apple/urllib/robotparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/pylib-apple/uu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/pylib-apple/uuid.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/pylib-apple/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/pylib-apple/wave.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/pylib-apple/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/pylib-apple/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/pylib-apple/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/NodeFilter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/minidom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/dom/xmlbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/ElementInclude.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/ElementPath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/ElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/etree/cElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/parsers/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/parsers/expat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/expatreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/handler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/saxutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/pylib-apple/xml/sax/xmlreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-apple/xmlrpc/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ - build/pylib-apple/xmlrpc/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-apple/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/pylib-apple/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/pylib-apple/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PRIVATE_APPLE),\ +$(eval $(call make-opt-pyc-target,$(element)))) SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/__future__.py \ @@ -5766,2140 +2408,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ $(SCRIPT_TARGETS_PY_PRIVATE_ANDROID) : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/pylib-android/__future__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ - build/pylib-android/__phello__.foo.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/pylib-android/_bootlocale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ - build/pylib-android/_collections_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/pylib-android/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/pylib-android/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/pylib-android/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/pylib-android/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/pylib-android/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/pylib-android/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ - build/pylib-android/_pydecimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/pylib-android/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/pylib-android/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/pylib-android/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/pylib-android/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/pylib-android/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-android/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/pylib-android/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/pylib-android/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/pylib-android/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/pylib-android/ast.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/pylib-android/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/pylib-android/asyncore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/pylib-android/base64.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/pylib-android/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/pylib-android/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/pylib-android/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/pylib-android/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/pylib-android/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/pylib-android/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/pylib-android/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/pylib-android/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/pylib-android/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/pylib-android/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc: \ - build/pylib-android/code.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/pylib-android/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/pylib-android/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/collections/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-android/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/pylib-android/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/pylib-android/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/pylib-android/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/pylib-android/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/pylib-android/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/pylib-android/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/pylib-android/copy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/pylib-android/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/pylib-android/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/pylib-android/csv.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/_aix.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/_endian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/macholib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/macholib/dylib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/pylib-android/ctypes/wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/has_key.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/panel.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/pylib-android/curses/textpad.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/pylib-android/dataclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/pylib-android/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/pylib-android/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/pylib-android/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/pylib-android/dis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/pylib-android/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/pylib-android/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/pylib-android/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/pylib-android/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/pylib-android/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/pylib-android/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/pylib-android/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/pylib-android/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/pylib-android/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/pylib-android/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/pylib-android/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/pylib-android/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/pylib-android/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-android/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/pylib-android/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-android/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/pylib-android/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/pylib-android/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/pylib-android/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/base64_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/big5hkscs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/charmap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1026.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1125.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1140.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1252.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1253.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1256.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1257.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp1258.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp273.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp775.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp852.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp857.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp858.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp863.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp866.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp869.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp949.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/euc_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/gbk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/hp_roman8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/idna.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso2022_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_10.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_11.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_14.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_15.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_6.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/johab.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/koi8_r.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/koi8_t.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_arabic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_centeuro.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_croatian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_farsi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_greek.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_iceland.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_latin2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_roman.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_romanian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/oem.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/ptcp154.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/punycode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/raw_unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/rot_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/shift_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/unicode_internal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_16_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_32_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/utf_8_sig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/pylib-android/encodings/zlib_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/pylib-android/enum.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/pylib-android/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/pylib-android/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/pylib-android/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/pylib-android/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/pylib-android/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/pylib-android/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/pylib-android/functools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/pylib-android/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/pylib-android/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/pylib-android/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/pylib-android/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/pylib-android/glob.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/pylib-android/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/pylib-android/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/pylib-android/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/pylib-android/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/html/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc: \ - build/pylib-android/html/entities.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/pylib-android/html/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/http/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/pylib-android/http/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/pylib-android/http/cookiejar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/pylib-android/http/cookies.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-android/http/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/pylib-android/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/pylib-android/imp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/pylib-android/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/pylib-android/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc: \ - build/pylib-android/io.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/pylib-android/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/json/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/pylib-android/json/decoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/pylib-android/json/encoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/pylib-android/json/scanner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/pylib-android/json/tool.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/pylib-android/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/pylib-android/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/pylib-android/locale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/pylib-android/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/pylib-android/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/pylib-android/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/pylib-android/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/pylib-android/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/pylib-android/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/pylib-android/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/pylib-android/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/pylib-android/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/pylib-android/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/pylib-android/ntpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/pylib-android/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/pylib-android/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/pylib-android/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/pylib-android/operator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/pylib-android/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc: \ - build/pylib-android/os.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/pylib-android/pathlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/pylib-android/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/pylib-android/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/pylib-android/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/pylib-android/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/pylib-android/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/pylib-android/platform.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/pylib-android/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/pylib-android/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/pylib-android/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/pylib-android/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/pylib-android/profile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/pylib-android/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/pylib-android/pty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/pylib-android/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/pylib-android/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/pylib-android/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/pylib-android/queue.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/pylib-android/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc: \ - build/pylib-android/random.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc: \ - build/pylib-android/re.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/pylib-android/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/pylib-android/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/pylib-android/runpy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/pylib-android/sched.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/pylib-android/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/pylib-android/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/pylib-android/shelve.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/pylib-android/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/pylib-android/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/pylib-android/signal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc: \ - build/pylib-android/site.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/pylib-android/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/pylib-android/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/pylib-android/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/pylib-android/socket.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/pylib-android/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/sqlite3/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/pylib-android/sqlite3/dbapi2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/pylib-android/sqlite3/dump.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/pylib-android/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/pylib-android/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/pylib-android/sre_parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/pylib-android/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/pylib-android/stat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/pylib-android/statistics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc: \ - build/pylib-android/string.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/pylib-android/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/pylib-android/struct.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/pylib-android/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/pylib-android/sunau.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/pylib-android/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/pylib-android/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/pylib-android/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/pylib-android/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/pylib-android/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/pylib-android/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/pylib-android/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/pylib-android/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc: \ - build/pylib-android/this.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/pylib-android/threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/pylib-android/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc: \ - build/pylib-android/token.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/pylib-android/tokenize.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/pylib-android/trace.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/pylib-android/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/pylib-android/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/pylib-android/tty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc: \ - build/pylib-android/types.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/pylib-android/typing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/request.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/response.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/pylib-android/urllib/robotparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/pylib-android/uu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/pylib-android/uuid.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/pylib-android/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/pylib-android/wave.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/pylib-android/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/pylib-android/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/pylib-android/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/NodeFilter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/minidom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/dom/xmlbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/ElementInclude.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/ElementPath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/ElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/etree/cElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/parsers/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/parsers/expat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/expatreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/handler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/saxutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/pylib-android/xml/sax/xmlreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/pylib-android/xmlrpc/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ - build/pylib-android/xmlrpc/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/pylib-android/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/pylib-android/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/pylib-android/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PRIVATE_ANDROID),\ +$(eval $(call make-opt-pyc-target,$(element)))) SCRIPT_TARGETS_PY_PRIVATE_COMMON = \ build/ba_data/python-site-packages/typing_extensions.py \ @@ -7946,100 +2458,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_COMMON = \ $(SCRIPT_TARGETS_PY_PRIVATE_COMMON) : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/typing_extensions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/composer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/constructor.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/cyaml.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/dumper.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/emitter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/loader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/nodes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/reader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/representer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/resolver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/scanner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/serializer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc: \ - build/ba_data/python-site-packages/yaml/tokens.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PRIVATE_COMMON),\ +$(eval $(call make-opt-pyc-target,$(element)))) SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/__future__.py \ @@ -9386,3350 +3808,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32) : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/__future__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/__phello__.foo.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_bootlocale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_collections_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_pydecimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ast.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/asyncore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/base64.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/code.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/collections/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/copy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/csv.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/_aix.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/_endian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/dylib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_anon.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_arrays.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_as_parameter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_bitfields.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_buffers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_bytes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_byteswap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_callbacks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_cast.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_cfuncs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_checkretval.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_delattr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_errno.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_find.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_frombuffer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_funcptr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_functions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_incomplete.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_init.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_internals.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_keeprefs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_libc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_loading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_macholib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_memfunctions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_numbers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_objects.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_parameters.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_pep3118.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_pickling.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_pointers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_prototypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_python_api.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_random_things.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_refcounts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_repr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_sizes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_slicing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_stringptr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_strings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_struct_fields.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_structures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_unicode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_values.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_win32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/test/test_wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ctypes/wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/has_key.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/panel.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/curses/textpad.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dataclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/dumb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/gnu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dbm/ndbm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/_msvccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/archive_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/bcppcompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/ccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_dumb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_msi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_rpm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/bdist_wininst.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_clib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_py.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/build_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/check.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/clean.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_data.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_egg_info.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_headers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_lib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/install_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/register.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/sdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/command/upload.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/core.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/cygwinccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/debug.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/dep_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/dir_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/dist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/errors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/extension.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/fancy_getopt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/file_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/filelist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/msvc9compiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/msvccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/spawn.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_archive_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_clib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_py.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_build_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_check.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_clean.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_config_cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_core.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_dep_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_dir_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_dist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_extension.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_file_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_filelist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_data.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_headers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_lib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_install_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_register.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_sdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_spawn.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_text_file.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_upload.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_version.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/text_file.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/unixccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/version.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/distutils/versionpredicate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/base64_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/big5hkscs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/charmap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1026.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1125.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1140.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1252.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1253.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1256.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1257.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp1258.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp273.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp775.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp852.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp857.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp858.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp863.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp866.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp869.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp949.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/euc_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/gbk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/hp_roman8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/idna.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso2022_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_10.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_11.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_14.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_15.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_6.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/johab.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/koi8_r.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/koi8_t.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_arabic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_centeuro.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_croatian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_farsi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_greek.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_iceland.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_latin2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_roman.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_romanian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/oem.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/ptcp154.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/punycode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/raw_unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/rot_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/shift_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/unicode_internal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_16_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_32_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/utf_8_sig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/encodings/zlib_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ensurepip/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ensurepip/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ensurepip/_uninstall.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/enum.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/functools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/glob.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/html/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/html/entities.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/html/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/cookiejar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/cookies.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/http/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/imaplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/imp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/io.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/decoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/encoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/scanner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/json/tool.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/locale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/schema.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/sequence.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/msilib/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/connection.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/context.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/dummy/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/dummy/connection.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/heap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/managers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/pool.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_fork.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/process.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/queues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/reduction.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/resource_sharer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/sharedctypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/spawn.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/synchronize.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/multiprocessing/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ntpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/operator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/os.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pathlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/platform.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/profile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pydoc_data/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/pydoc_data/topics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/queue.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/random.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/re.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/runpy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sched.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/shelve.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/signal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/site.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/socket.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/dbapi2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/dump.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/backup.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/dbapi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/dump.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/factory.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/hooks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/regression.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/transactions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/types.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sqlite3/test/userfunctions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sre_parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/stat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/statistics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/string.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/struct.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sunau.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/this.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/token.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tokenize.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/trace.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/tty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/turtle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/types.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/typing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/case.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/loader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/main.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/mock.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/result.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/runner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/signals.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/suite.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/_test_warnings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/dummy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_assertions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_break.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_case.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_discovery.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_functiontestcase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_loader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_program.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_result.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_runner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_setups.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_skipping.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/test_suite.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testcallable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testmock.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testpatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testsealable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/test/testmock/testwith.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/unittest/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/request.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/response.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/urllib/robotparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/uu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/uuid.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/venv/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/venv/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wave.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/headers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/simple_server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/wsgiref/validate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/NodeFilter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/minidom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/dom/xmlbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/ElementInclude.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/ElementPath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/ElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/etree/cElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/parsers/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/parsers/expat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/expatreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/handler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/saxutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xml/sax/xmlreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xmlrpc/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xmlrpc/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/windows/Win32/Lib/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32),\ +$(eval $(call make-opt-pyc-target,$(element)))) SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/__future__.py \ @@ -14076,3350 +5158,10 @@ SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ $(SCRIPT_TARGETS_PY_PRIVATE_WIN_X64) : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -# Looks like path mangling from py to pyc is too complex for pattern rules so -# just generating explicit targets for each. Could perhaps look into using a -# fancy for-loop instead, but perhaps listing these explicitly isn't so bad. - -build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/__future__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/__phello__.foo.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_bootlocale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_collections_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_compat_pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_compression.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_dummy_thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_markupbase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_osx_support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_py_abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_pydecimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_pyio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_sitebuiltins.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_strptime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_threading_local.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/_weakrefset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/aifc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/antigravity.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/argparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ast.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asynchat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/base_tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/coroutines.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/format_helpers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/futures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/locks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/proactor_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/protocols.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/queues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/runners.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/selector_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/sslproto.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/streams.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/tasks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/transports.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/unix_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/windows_events.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncio/windows_utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/asyncore.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/base64.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/bdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/binhex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/bisect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/bz2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cProfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/calendar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cgi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cgitb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/chunk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/code.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/codecs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/codeop.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/collections/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/collections/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/colorsys.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/compileall.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/_base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/process.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/concurrent/futures/thread.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/configparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/contextlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/contextvars.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/copy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/copyreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/crypt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/csv.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/_aix.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/_endian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/dyld.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/dylib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/macholib/framework.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_anon.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_arrays.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_as_parameter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_bitfields.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_buffers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_bytes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_byteswap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_callbacks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_cast.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_cfuncs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_checkretval.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_delattr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_errno.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_find.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_frombuffer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_funcptr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_functions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_incomplete.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_init.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_internals.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_keeprefs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_libc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_loading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_macholib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_memfunctions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_numbers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_objects.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_parameters.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_pep3118.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_pickling.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_pointers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_prototypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_python_api.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_random_things.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_refcounts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_repr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_sizes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_slicing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_stringptr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_strings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_struct_fields.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_structures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_unicode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_values.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_varsize_struct.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_win32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/test/test_wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ctypes/wintypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/has_key.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/panel.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/curses/textpad.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dataclasses.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/datetime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/dumb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/gnu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dbm/ndbm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/decimal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/difflib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/_msvccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/archive_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/bcppcompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/ccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_dumb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_msi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_rpm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/bdist_wininst.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_clib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_py.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/build_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/check.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/clean.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_data.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_egg_info.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_headers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_lib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/install_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/register.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/sdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/command/upload.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/core.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/cygwinccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/debug.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/dep_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/dir_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/dist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/errors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/extension.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/fancy_getopt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/file_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/filelist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/msvc9compiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/msvccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/spawn.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_archive_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_msi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_clib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_py.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_build_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_check.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_clean.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_config_cmd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_core.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_dep_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_dir_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_dist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_extension.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_file_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_filelist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_data.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_headers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_lib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_install_scripts.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_log.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_msvccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_register.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_sdist.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_spawn.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_text_file.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_unixccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_upload.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_version.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/tests/test_versionpredicate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/text_file.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/unixccompiler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/version.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/distutils/versionpredicate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/doctest.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/dummy_threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_encoded_words.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_header_value_parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_parseaddr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/_policybase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/base64mime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/charset.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/contentmanager.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/encoders.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/errors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/feedparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/generator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/header.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/headerregistry.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/iterators.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/application.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/audio.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/base.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/image.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/message.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/multipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/nonmultipart.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/mime/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/policy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/quoprimime.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/email/utils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/aliases.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/ascii.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/base64_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/big5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/big5hkscs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/bz2_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/charmap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp037.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1006.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1026.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1125.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1140.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1250.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1251.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1252.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1253.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1254.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1255.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1256.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1257.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp1258.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp273.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp424.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp437.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp500.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp65001.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp720.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp737.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp775.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp850.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp852.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp855.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp856.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp857.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp858.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp860.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp861.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp862.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp863.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp864.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp865.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp866.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp869.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp874.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp875.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp932.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp949.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/cp950.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/euc_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/gb18030.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/gb2312.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/gbk.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/hex_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/hp_roman8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/hz.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/idna.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_jp_ext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso2022_kr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_10.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_11.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_14.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_15.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_3.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_4.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_5.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_6.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/iso8859_9.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/johab.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/koi8_r.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/koi8_t.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/koi8_u.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/kz1048.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/latin_1.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_arabic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_centeuro.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_croatian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_cyrillic.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_farsi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_greek.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_iceland.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_latin2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_roman.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_romanian.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mac_turkish.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/mbcs.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/oem.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/palmos.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/ptcp154.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/punycode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/quopri_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/raw_unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/rot_13.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/shift_jis.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/shift_jis_2004.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/shift_jisx0213.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/tis_620.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/undefined.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/unicode_escape.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/unicode_internal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_16.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_16_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_16_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_32_be.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_32_le.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_7.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_8.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/utf_8_sig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/uu_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/encodings/zlib_codec.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ensurepip/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ensurepip/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ensurepip/_uninstall.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/enum.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/filecmp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/fileinput.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/fnmatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/formatter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/fractions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ftplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/functools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/genericpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/getopt.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/getpass.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/gettext.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/glob.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/gzip.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/hashlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/heapq.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/hmac.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/html/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/html/entities.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/html/parser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/cookiejar.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/cookies.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/http/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/imaplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/imghdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/imp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/_bootstrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/_bootstrap_external.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/abc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/machinery.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/resources.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/importlib/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/inspect.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/io.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ipaddress.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/decoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/encoder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/scanner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/json/tool.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/keyword.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/linecache.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/locale.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/logging/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/logging/config.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/logging/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/lzma.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/macpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/mailbox.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/mailcap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/mimetypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/modulefinder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/schema.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/sequence.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/msilib/text.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/connection.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/context.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/dummy/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/dummy/connection.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/heap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/managers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/pool.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_fork.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_forkserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/process.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/queues.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/reduction.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/resource_sharer.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/semaphore_tracker.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/sharedctypes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/spawn.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/synchronize.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/multiprocessing/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/netrc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/nntplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ntpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/nturl2path.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/numbers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/opcode.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/operator.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/optparse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/os.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pathlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pdb.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pickle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pickletools.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pipes.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pkgutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/platform.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/plistlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/poplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/posixpath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pprint.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/profile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pstats.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/py_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pyclbr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pydoc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pydoc_data/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/pydoc_data/topics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/queue.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/quopri.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/random.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/re.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/reprlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/rlcompleter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/runpy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sched.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/secrets.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/selectors.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/shelve.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/shlex.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/shutil.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/signal.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/site.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/smtpd.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/smtplib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sndhdr.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/socket.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/socketserver.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/dbapi2.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/dump.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/backup.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/dbapi.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/dump.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/factory.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/hooks.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/regression.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/transactions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/types.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sqlite3/test/userfunctions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sre_compile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sre_constants.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sre_parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/ssl.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/stat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/statistics.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/string.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/stringprep.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/struct.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/subprocess.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sunau.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/symbol.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/symtable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/sysconfig.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tabnanny.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tarfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/telnetlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tempfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/textwrap.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/this.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/threading.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/timeit.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/token.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tokenize.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/trace.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/traceback.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tracemalloc.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/tty.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/turtle.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/types.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/typing.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/case.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/loader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/main.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/mock.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/result.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/runner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/signals.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/suite.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/_test_warnings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/dummy.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_assertions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_break.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_case.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_discovery.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_functiontestcase.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_loader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_program.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_result.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_runner.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_setups.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_skipping.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/test_suite.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/support.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testcallable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testhelpers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testmock.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testpatch.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testsealable.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testsentinel.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/test/testmock/testwith.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/unittest/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/error.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/parse.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/request.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/response.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/urllib/robotparser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/uu.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/uuid.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/venv/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/venv/__main__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/warnings.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wave.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/weakref.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/webbrowser.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/handlers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/headers.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/simple_server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/util.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/wsgiref/validate.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xdrlib.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/NodeFilter.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/domreg.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/expatbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/minicompat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/minidom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/pulldom.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/dom/xmlbuilder.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/ElementInclude.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/ElementPath.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/ElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/etree/cElementTree.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/parsers/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/parsers/expat.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/_exceptions.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/expatreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/handler.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/saxutils.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xml/sax/xmlreader.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xmlrpc/__init__.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xmlrpc/client.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/xmlrpc/server.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/zipapp.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - -build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc: \ - build/windows/x64/Lib/zipfile.py - @echo Compiling script: $^ - @rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand compile_python_files $^ && chmod 444 $@ - +# These are too complex to define in a pattern rule; +# Instead we generate individual targets in a loop. +$(foreach element,$(SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64),\ +$(eval $(call make-opt-pyc-target,$(element)))) COB_TARGETS = \ build/ba_data/models/alwaysLandLevelCollide.cob \ @@ -20214,9 +7956,12 @@ scripts-ios: $(SCRIPT_TARGETS_IOS) $(SCRIPT_TARGETS_COMMON) scripts-android: $(SCRIPT_TARGETS_ANDROID) $(SCRIPT_TARGETS_COMMON) # Build scripts for all platforms -scripts: scripts-cmake scripts-win scripts-mac scripts-ios scripts-android +scripts: scripts-cmake scripts-win-Win32 scripts-win-x64 scripts-mac \ + scripts-ios scripts-android clean-scripts: - rm -rf build/ba_data/python build/ba_data/python-site-packages + rm -rf build/ba_data/python build/ba_data/python-site-packages \ + build/pylib-android build/pylib-apple build/windows/Win32/Lib \ + build/windows/x64/Lib # Build all required assets for a specific platform. assets-cmake: $(ASSET_TARGETS_CMAKE) $(ASSET_TARGETS_COMMON) diff --git a/tools/update_assets_makefile b/tools/update_assets_makefile index 139ac46c..32e2f628 100755 --- a/tools/update_assets_makefile +++ b/tools/update_assets_makefile @@ -174,22 +174,30 @@ def _get_py_targets_subset(all_targets: Set[str], subset: str, '\t@cp $^ $@\n' '\t@chmod 444 $@\n') - out += ('\n# Looks like path mangling from py to pyc is too complex for' + # Fancy new simple loop-based target generation. + out += (f'\n# These are too complex to define in a pattern rule;\n' + f'# Instead we generate individual targets in a loop.\n' + f'$(foreach element,$(SCRIPT_TARGETS_PYC{suffix}),\\\n' + f'$(eval $(call make-opt-pyc-target,$(element))))') + + # Old code to explicitly emit individual targets. + if bool(False): + out += ( + '\n# Looks like path mangling from py to pyc is too complex for' ' pattern rules so\n# just generating explicit targets' ' for each. Could perhaps look into using a\n# fancy for-loop' ' instead, but perhaps listing these explicitly isn\'t so bad.\n') - - for i, target in enumerate(pyc_targets): - # Note: there's currently a bug which can cause python bytecode - # generation to be non-deterministic. This can break our blessing - # process since we bless in core but then regenerate bytecode in - # spinoffs. See https://bugs.python.org/issue34722 - # For now setting PYTHONHASHSEED=1 is a workaround. - out += ('\n' + target + ': \\\n ' + py_targets[i] + - '\n\t@echo Compiling script: $^\n' - '\t@rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand' - ' compile_python_files $^' - ' && chmod 444 $@\n') + for i, target in enumerate(pyc_targets): + # Note: there's currently a bug which can cause python bytecode + # generation to be non-deterministic. This can break our blessing + # process since we bless in core but then regenerate bytecode in + # spinoffs. See https://bugs.python.org/issue34722 + # For now setting PYTHONHASHSEED=1 is a workaround. + out += ('\n' + target + ': \\\n ' + py_targets[i] + + '\n\t@echo Compiling script: $^\n' + '\t@rm -rf $@ && PYTHONHASHSEED=1 $(TOOLS_DIR)/pcommand' + ' compile_python_files $^' + ' && chmod 444 $@\n') return out From 406fc2770d573f66a8f6a9c9948dac31c6e913e7 Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Sat, 4 Jul 2020 13:59:33 +0530 Subject: [PATCH 129/417] Update bomb.py This will lead to solving of issue #90 --- assets/src/ba_data/python/bastd/actor/bomb.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 9d2ff2a5..c5cb74a7 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -1005,11 +1005,11 @@ class Bomb(ba.Actor): ba.playsound(factory.activate_sound, 0.5, position=self.node.position) def _handle_hit(self, msg: ba.HitMessage) -> None: - ispunch = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') + ispunched = (msg.srcnode and msg.srcnode.getnodetype() == 'spaz') # Normal bombs are triggered by non-punch impacts; # impact-bombs by all impacts. - if (not self._exploded and not ispunch + if not ispunched and (not self._exploded or self.bomb_type in ['impact', 'land_mine']): # Also lets change the owner of the bomb to whoever is setting # us off. (this way points for big chain reactions go to the From 3044099832a88e6a7e1a0028b3403192713d2730 Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Sat, 4 Jul 2020 14:01:57 +0530 Subject: [PATCH 130/417] Added comment for changes --- assets/src/ba_data/python/bastd/actor/bomb.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index c5cb74a7..ae6d0666 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -1011,6 +1011,10 @@ class Bomb(ba.Actor): # impact-bombs by all impacts. if not ispunched and (not self._exploded or self.bomb_type in ['impact', 'land_mine']): + # We don't want to give the credit and points to player, + # who punched the bomb of other player in a chain reaction. + # And this will protect the bomb from getting hit_type 'punch'. + # Also lets change the owner of the bomb to whoever is setting # us off. (this way points for big chain reactions go to the # person causing them). From 229ed58c48d7423ea72bae5612d0e11af2ae5677 Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Sat, 4 Jul 2020 14:23:58 +0530 Subject: [PATCH 131/417] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 19efe74b..77942c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.5.18 (20106) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. +- More code improvement ### 1.5.17 (20102) - More cleanup to logging and crash reporting system. From 500ad1a52e11eb976f398c1012641a97168a7ae1 Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Sat, 4 Jul 2020 14:25:33 +0530 Subject: [PATCH 132/417] Adding myself to CONTRIBUTORS.md --- CONTRIBUTORS.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b17b8450..7a0a5ed2 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,3 +10,7 @@ ### Roman Trapeznikov - Bug fixes and code cleanup + +### Benefit-Zebra +- Unofficial BombSquad Bug Finder +- Code Cleanup From 5fdd12b535a9af0c85cc3c807dbcf973a3fffbba Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Sat, 4 Jul 2020 18:53:20 +0530 Subject: [PATCH 133/417] Update bomb.py Removed trailing whitespace --- assets/src/ba_data/python/bastd/actor/bomb.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index ae6d0666..47a7463d 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -1014,7 +1014,7 @@ class Bomb(ba.Actor): # We don't want to give the credit and points to player, # who punched the bomb of other player in a chain reaction. # And this will protect the bomb from getting hit_type 'punch'. - + # Also lets change the owner of the bomb to whoever is setting # us off. (this way points for big chain reactions go to the # person causing them). From b304452084782a0ca69abcca94d722088d24c70f Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 5 Jul 2020 16:18:21 -0700 Subject: [PATCH 134/417] v1.5.18 --- .efrocachemap | 24 +++++------ CHANGELOG.md | 3 +- assets/src/ba_data/python/ba/_session.py | 42 ++++++++++--------- .../python/bastd/game/capturetheflag.py | 18 ++++---- assets/src/ba_data/python/bastd/ui/gather.py | 2 +- docs/ba_module.md | 2 +- tools/batools/pcommand.py | 12 ++++-- 7 files changed, 57 insertions(+), 46 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 4ae50836..64d0393d 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/ce/31/b04472c4ec3f900d319b4522ab0d", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/81/6e/971bfc46e8d4f0e4ba685c60f121", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/9c/c6dffeceff4ce4e8e2f80c0bb3e2", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/83/ef6633a278dc7ecdb8be9f63591e", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4d/02/906eb5da3a0ec6ca227cf9ba4265", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/50/17/ddbde947f50be43aa94630188107", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/d0/d2370a7c96901b6a2af7eca8dbdb", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/0c/54/ae9513cdcb60d2c9e5845cde909e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/41/dd/b2d6cb0e1471b34d506072ff7785", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ef/fb/1c681f24e04862b1dcef345d7063", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a0/2c/65a719c19570f05428a5fc68bd76", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1f/db/b4c059aae0ef1d79c6dcaf521c62" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b8/7d/8fb23522c5431b80f43518d52bc1", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/1b/a7c5f57925c5af6c4af7fb144f03", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/84/e3/a6538c8ae4861d182eeb435d9918", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/18/7a/02301ecf6287c8103d72a18702a5", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ee/07/cf35aa850c673b3c505d62ec4435", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9e/5c/64299df2b8eb147cc19e1d3035a1", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f4/ed/216d2257dd2b421c4e4d060c0d33", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/07/6f/ec5b94e8089a56a01f97c90fb2f9", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f4/09/8c42bebbfb28b1ebb060a7e9f0c7", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ff/43/ec16a091f0b9cfb77e9f7bab1f25", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/42/1f9000faf46cb8de8db34aac2178", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b7/86/f2da432d7b177d9556c577fa6391" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 19efe74b..c3f847e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ -### 1.5.18 (20106) +### 1.5.18 (20108) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. +- More minor bug fixes and crash/bug-logging improvements.. ### 1.5.17 (20102) - More cleanup to logging and crash reporting system. diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index ecad97b2..ed79d753 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -591,28 +591,32 @@ class Session: lobby = chooser.lobby activity = self._activity_weak() + # It seems this can happen.. + if activity is None: + print('_on_player_ready called with no activity.') + return + # In joining-activities, we wait till all choosers are ready # and then create all players at once. - if activity is not None and activity.is_joining_activity: - if lobby.check_all_ready(): - choosers = lobby.get_choosers() - min_players = self.min_players - if len(choosers) >= min_players: - for lch in lobby.get_choosers(): - self._add_chosen_player(lch) - lobby.remove_all_choosers() - - # Get our next activity going. - self._complete_end_activity(activity, {}) - else: - _ba.screenmessage( - Lstr(resource='notEnoughPlayersText', - subs=[('${COUNT}', str(min_players))]), - color=(1, 1, 0), - ) - _ba.playsound(_ba.getsound('error')) - else: + if activity.is_joining_activity: + if not lobby.check_all_ready(): return + choosers = lobby.get_choosers() + min_players = self.min_players + if len(choosers) >= min_players: + for lch in lobby.get_choosers(): + self._add_chosen_player(lch) + lobby.remove_all_choosers() + + # Get our next activity going. + self._complete_end_activity(activity, {}) + else: + _ba.screenmessage( + Lstr(resource='notEnoughPlayersText', + subs=[('${COUNT}', str(min_players))]), + color=(1, 1, 0), + ) + _ba.playsound(_ba.getsound('error')) # Otherwise just add players on the fly. else: diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index e4b17421..999277cf 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -426,16 +426,16 @@ class CaptureTheFlagGame(ba.TeamGameActivity[Player, Team]): 'loop': True })) flag = team.flag - assert flag.touch_return_time is not None - flag.touch_return_time -= 0.1 - if flag.counter: - flag.counter.text = f'{flag.touch_return_time:.1f}' - flag.counter.color = (1, 1, 0, 1) - flag.counter.scale = 0.02 + if flag.touch_return_time is not None: + flag.touch_return_time -= 0.1 + if flag.counter: + flag.counter.text = f'{flag.touch_return_time:.1f}' + flag.counter.color = (1, 1, 0, 1) + flag.counter.scale = 0.02 - if flag.touch_return_time <= 0.0: - self._award_players_touching_own_flag(team) - flag.handlemessage(ba.DieMessage()) + if flag.touch_return_time <= 0.0: + self._award_players_touching_own_flag(team) + flag.handlemessage(ba.DieMessage()) def _award_players_touching_own_flag(self, team: Team) -> None: for player in team.players: diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 6e45dd83..5929297d 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1668,7 +1668,7 @@ class GatherWindow(ba.Window): # Ignore harmless errors. if exc.errno in { errno.EHOSTUNREACH, errno.ENETUNREACH, - errno.EINVAL + errno.EINVAL, errno.EPERM }: pass elif exc.errno == 10022: diff --git a/docs/ba_module.md b/docs/ba_module.md index d9f9e73f..fe520533 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-03 for Ballistica version 1.5.17 build 20104

    +

    last updated on 2020-07-05 for Ballistica version 1.5.18 build 20108

    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!


    diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index fcc19735..177a43d4 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -672,7 +672,13 @@ def efro_gradle() -> None: target_words = [w.lower() for w in _camel_case_split(args[-1])] if 'google' in target_words: enabled_tags = {'google', 'crashlytics'} - filter_gradle_file('BallisticaCore/build.gradle', enabled_tags) + + buildfilename = 'BallisticaCore/build.gradle' + # Backup the original file, preserving timestamps and whatnot so as to not + # trip modification tests. + subprocess.run(['cp', '-p', buildfilename, f'{buildfilename}.prev'], + check=True) + filter_gradle_file(buildfilename, enabled_tags) try: subprocess.run(args, check=True) @@ -680,8 +686,8 @@ def efro_gradle() -> None: except BaseException: errored = True - # Put things back to default state. - filter_gradle_file('BallisticaCore/build.gradle', set()) + # Restore the original. + subprocess.run(['mv', f'{buildfilename}.prev', buildfilename], check=True) if errored: sys.exit(1) From 19e78590424d51a9baf0f5158b1c5eb797f75159 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 6 Jul 2020 15:59:43 -0700 Subject: [PATCH 135/417] Bomb logic cleanup --- assets/src/ba_data/python/bastd/actor/bomb.py | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 47a7463d..fd4fa485 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -718,10 +718,16 @@ class Bomb(ba.Actor): # By default our hit type/subtype is our own, but we pick up types of # whoever sets us off so we know what caused a chain reaction. + # UPDATE (July 2020): not inheriting hit-types anymore; this causes + # weird effects such as land-mines inheriting 'punch' hit types and + # then not being able to destroy certain things they normally could, + # etc. Inheriting owner/source-node from things that set us off + # should be all we need I think... self.hit_type = 'explosion' self.hit_subtype = self.bomb_type # The node this came from. + # FIXME: can we unify this and source_player? self.owner = owner # Adding footing-materials to things can screw up jumping and flying @@ -1009,11 +1015,8 @@ class Bomb(ba.Actor): # Normal bombs are triggered by non-punch impacts; # impact-bombs by all impacts. - if not ispunched and (not self._exploded - or self.bomb_type in ['impact', 'land_mine']): - # We don't want to give the credit and points to player, - # who punched the bomb of other player in a chain reaction. - # And this will protect the bomb from getting hit_type 'punch'. + if (not self._exploded and + (not ispunched or self.bomb_type in ['impact', 'land_mine'])): # Also lets change the owner of the bomb to whoever is setting # us off. (this way points for big chain reactions go to the @@ -1025,13 +1028,15 @@ class Bomb(ba.Actor): # Also inherit the hit type (if a landmine sets off by a bomb, # the credit should go to the mine) # the exception is TNT. TNT always gets credit. - if self.bomb_type != 'tnt': - self.hit_type = msg.hit_type - self.hit_subtype = msg.hit_subtype + # UPDATE (July 2020): not doing this anymore. Causes too much + # weird logic such as bombs acting like punches. Holler if + # anything is noticeably broken due to this. + # if self.bomb_type != 'tnt': + # self.hit_type = msg.hit_type + # self.hit_subtype = msg.hit_subtype - ba.timer(100 + int(random.random() * 100), - ba.WeakCall(self.handlemessage, ExplodeMessage()), - timeformat=ba.TimeFormat.MILLISECONDS) + ba.timer(0.1 + random.random() * 0.1, + ba.WeakCall(self.handlemessage, ExplodeMessage())) assert self.node self.node.handlemessage('impulse', msg.pos[0], msg.pos[1], msg.pos[2], msg.velocity[0], msg.velocity[1], From c88a2d3217dbe2cc3d8e9b45d1d7db23ba043e72 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 6 Jul 2020 16:00:11 -0700 Subject: [PATCH 136/417] Syncing latest changes between public/private. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3f847e1..27c2b7a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ ### 1.5.18 (20108) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. -- More minor bug fixes and crash/bug-logging improvements.. +- More minor bug fixes and crash/bug-logging improvements. ### 1.5.17 (20102) - More cleanup to logging and crash reporting system. From 67810d769e4cf8ac2106d16abb6a69e0ff351ea4 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 6 Jul 2020 17:03:52 -0700 Subject: [PATCH 137/417] Added node gravity_scale attr --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 3 +++ assets/src/ba_data/python/_ba.py | 1 + tools/batools/pcommand.py | 9 +++++---- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 74d83a3e..057ab683 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/05/0d/bc658d9bcf94d07bde0812c3f4a7", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2f/ce/d2018415a449ad310a68970ac848", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4e/60/bbf2bf14e58835ea71897366674c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/7b/5c7d8989c1cf1a34c3b84390d26d", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d2/33/f26482f85d7e3fe349badc83fb38", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/24/30/0a93d6fb06eaf30e698900f7719f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/7f/d3d4952829448c53ad93c4a7a7f6", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/40/0e1838ce963ebc0ff5927d2ef096", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3b/3b/13e222119a4fae02a43ebca3a2e1", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/5b/90/2f7e0be10cf2e4681902b1dbfac5", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8e/76/6b1a723d85bc9fd81ca44f71c653", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/11/cd/8152982a3b7f9970cde209470f9c" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4e/53/7ec6327e532452541ad97ff927ab", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/70/7f/d853bede37c4b91d822cf853fc51", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/be/93c11fb8a237efcec5fe9e95b52f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a2/4a/cd3f8408329ac476450b14d961a4", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0f/6e/fb1fffbb11902f90edd5ea3ff257", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/f7/9cb910b949bab6ac8b4c82f8b03d", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/1e/483962e078392dafe3c47ab56ec8", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/70/1c30ceee55f2a89657507b7023d7", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/56/89/69526aeb40798e71afe19984b68f", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/93/d1/23e82bfbdfb38bf3e443939490be", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e5/a2/96201ceeefb90d6ebb4b81089b67", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/55/42/cfd614f84ade2658ba12dff258b6" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 27c2b7a5..18789952 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.19 (20114) +- Cleaned up some bomb chain-reaction logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by a punch. Holler if anything explosion-related looks broken. + ### 1.5.18 (20108) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. - More minor bug fixes and crash/bug-logging improvements. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index c5078118..1a03a0e9 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -613,6 +613,7 @@ class Node: model_opaque: Optional[ba.Model] = None model_transparent: Optional[ba.Model] = None damage_smoothed: float = 0.0 + gravity_scale: float = 1.0 punch_power: float = 0.0 punch_momentum_linear: Sequence[float] = (0.0, 0.0, 0.0) punch_momentum_angular: float = 0.0 diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 177a43d4..7e904c7e 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -674,10 +674,11 @@ def efro_gradle() -> None: enabled_tags = {'google', 'crashlytics'} buildfilename = 'BallisticaCore/build.gradle' - # Backup the original file, preserving timestamps and whatnot so as to not - # trip modification tests. - subprocess.run(['cp', '-p', buildfilename, f'{buildfilename}.prev'], - check=True) + + # Move the original file out of the way and operate on a copy of it. + subprocess.run(['mv', buildfilename, f'{buildfilename}.prev'], check=True) + subprocess.run(['cp', f'{buildfilename}.prev', buildfilename], check=True) + filter_gradle_file(buildfilename, enabled_tags) try: From bf6d02b5acf47d2ea9c2ecfbc6fc6aba471169b6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 8 Jul 2020 03:18:58 -0700 Subject: [PATCH 138/417] v1.5.19 --- .efrocachemap | 24 +++++++++++------------ .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 6 ++++-- assets/src/ba_data/python/ba/_app.py | 7 ------- assets/src/ba_data/python/ba/_netutils.py | 5 ++++- docs/ba_module.md | 2 +- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 057ab683..10931f64 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/4e/53/7ec6327e532452541ad97ff927ab", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/70/7f/d853bede37c4b91d822cf853fc51", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9f/be/93c11fb8a237efcec5fe9e95b52f", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a2/4a/cd3f8408329ac476450b14d961a4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0f/6e/fb1fffbb11902f90edd5ea3ff257", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/f7/9cb910b949bab6ac8b4c82f8b03d", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f2/1e/483962e078392dafe3c47ab56ec8", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/70/1c30ceee55f2a89657507b7023d7", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/56/89/69526aeb40798e71afe19984b68f", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/93/d1/23e82bfbdfb38bf3e443939490be", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e5/a2/96201ceeefb90d6ebb4b81089b67", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/55/42/cfd614f84ade2658ba12dff258b6" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/24/62/ba95f1a18d481f1cb6c154db5a1c", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d4/59/3e6553fa8d37f195a138d2464025", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/20/c0/0584548c8a8b198d44a31fcacc2d", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/71/28e1828d3a3b35372b260cfd8cf3", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/77/e7/f7dc1cb46460bcb19ba179407af4", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/74/d4/f583f9cf258c28966dbd55b9cb1f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f5/9d/a15377aa4b028dac302332be6e7a", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/2e/e69ef7d8ca7ed3bb2cd680fdb0a0", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/61/c7/01c3ecce17f17166c9b848b19bdc", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8d/de/f25b5905e1fb3a1e9ce01cf7b946", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/90/2f/f2244495552190f95b4de21b9538", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/60/42/2352f743f4b871106b5e92ffeebc" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 255c242b..6507a224 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -975,6 +975,7 @@ iserverget iserverput ispunch + ispunched isubval isysroot itms diff --git a/CHANGELOG.md b/CHANGELOG.md index 18789952..57f9ac4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ -### 1.5.19 (20114) -- Cleaned up some bomb chain-reaction logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by a punch. Holler if anything explosion-related looks broken. +### 1.5.19 (20123) +- Cleaned up some bomb logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by punches or bombs potentially resulting in multiple explosions when triggered by multiple other bombs simultaneously. Holler if anything explosion-related seems off now. +- Reactivated and cleaned up fatal-error message dialogs; they should now show up more consistently and on more platforms when something really bad happens instead of getting a silent crash. +- Certain hardware buttons on Android which stopped working in 1.5 should now be working again.. ### 1.5.18 (20108) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 184da001..fbb88a8a 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -520,13 +520,6 @@ class App: # it to the server and/or get rid of it. _apputils.handle_leftover_log_file() - # Notify the user if we're using custom system scripts. - # FIXME: This no longer works since sys-scripts is an absolute path; - # need to just add a proper call to query this. - # if env['python_directory_app'] != 'data/scripts': - # ba.screenmessage("Using custom system scripts...", - # color=(0, 1, 0)) - # Only do this stuff if our config file is healthy so we don't # overwrite a broken one or whatnot and wipe out data. if not self.config_file_healthy: diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index ea138d01..0fd9ed2e 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -158,10 +158,13 @@ class ServerCallThread(threading.Thread): elif isinstance(exc, OSError): if exc.errno == 10051: # Windows unreachable network error. pass - elif exc.errno in [errno.ETIMEDOUT]: + elif exc.errno in [errno.ETIMEDOUT, errno.EHOSTUNREACH]: pass else: do_print = True + elif (self._response_type == ServerResponseType.JSON + and isinstance(exc, json.decoder.JSONDecodeError)): + pass else: do_print = True diff --git a/docs/ba_module.md b/docs/ba_module.md index fe520533..e8f344b3 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-05 for Ballistica version 1.5.18 build 20108

    +

    last updated on 2020-07-08 for Ballistica version 1.5.19 build 20119

    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!


    From 61c7dad9c04b723ea6fbe9f94d57218a55d7006e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 8 Jul 2020 04:08:43 -0700 Subject: [PATCH 139/417] fixed debug log spewage --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 10931f64..ac54aafc 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/24/62/ba95f1a18d481f1cb6c154db5a1c", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d4/59/3e6553fa8d37f195a138d2464025", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/20/c0/0584548c8a8b198d44a31fcacc2d", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/71/28e1828d3a3b35372b260cfd8cf3", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/77/e7/f7dc1cb46460bcb19ba179407af4", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/74/d4/f583f9cf258c28966dbd55b9cb1f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f5/9d/a15377aa4b028dac302332be6e7a", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a8/2e/e69ef7d8ca7ed3bb2cd680fdb0a0", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/61/c7/01c3ecce17f17166c9b848b19bdc", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8d/de/f25b5905e1fb3a1e9ce01cf7b946", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/90/2f/f2244495552190f95b4de21b9538", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/60/42/2352f743f4b871106b5e92ffeebc" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/19/bb/f03a6517dc8fdfa02324a3059dbd", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/93/3b0a9a32dd7de1373a3f23c0db1c", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/84/c0/59d2d1755a6acd0087892cda1f2f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/c5/dccf038a6357df5f363e81f26f3c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/8d/56a2e40acf5dfa800475875b469e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9d/66/3c5ac59f38b141f58d0070180ec7", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/c5/f94df676b749a6c26dea2a650893", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/bc/8802a039ffc5f6d751afe42c8848", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ff/de/ef57afea5f6185b94e7b655cb6cf", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b5/ea/9b7604181d98cafe49cc2b7ceb2e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9e/fb/f81378d8e98f81dc54b097b132db", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/82/c9/72c92564a78169edf48a640b5e9a" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 57f9ac4f..ef1a558d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Reactivated and cleaned up fatal-error message dialogs; they should now show up more consistently and on more platforms when something really bad happens instead of getting a silent crash. - Certain hardware buttons on Android which stopped working in 1.5 should now be working again.. + ### 1.5.18 (20108) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. - More minor bug fixes and crash/bug-logging improvements. From 29742b69cb8bbbeb32e1195ec8958efb0bdd4946 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 9 Jul 2020 14:01:33 -0700 Subject: [PATCH 140/417] Minor bug fixes and build system improvements --- .efrocachemap | 24 +++++----- CHANGELOG.md | 6 ++- assets/src/ba_data/python/ba/_activity.py | 4 +- assets/src/ba_data/python/ba/_coopsession.py | 8 ++-- .../ba_data/python/ba/_freeforallsession.py | 16 +++---- assets/src/ba_data/python/ba/_lobby.py | 4 +- .../ba_data/python/ba/_multiteamsession.py | 4 +- assets/src/ba_data/python/ba/_netutils.py | 4 +- assets/src/ba_data/python/ba/_session.py | 45 ++++++++++--------- .../python/bastd/activity/dualteamscore.py | 2 +- .../python/bastd/activity/multiteamjoin.py | 5 ++- .../python/bastd/actor/controlsguide.py | 6 ++- docs/ba_module.md | 39 ++++++++-------- tools/efrotools/code.py | 6 ++- tools/update_project | 6 +-- 15 files changed, 97 insertions(+), 82 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index ac54aafc..3763543a 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/19/bb/f03a6517dc8fdfa02324a3059dbd", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/93/3b0a9a32dd7de1373a3f23c0db1c", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/84/c0/59d2d1755a6acd0087892cda1f2f", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1c/c5/dccf038a6357df5f363e81f26f3c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/8d/56a2e40acf5dfa800475875b469e", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9d/66/3c5ac59f38b141f58d0070180ec7", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/c5/f94df676b749a6c26dea2a650893", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/bc/8802a039ffc5f6d751afe42c8848", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ff/de/ef57afea5f6185b94e7b655cb6cf", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b5/ea/9b7604181d98cafe49cc2b7ceb2e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9e/fb/f81378d8e98f81dc54b097b132db", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/82/c9/72c92564a78169edf48a640b5e9a" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/57/f8/47526bddac42b974f4ce86d13166", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0a/a9/46cb3927b667d67d8dc936b744b6", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/f3/130eb5ddb320f11093ba92bfbe6a", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/53/a6/56310d64b07fb7aa1481e59a4d29", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/6a/1518d0ebde22f06a679edf04002a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/72/4f/f4d081f47a48ba940603a6825c1f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/1f/436439103f6ede3ec88f46b592a7", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/97/44/68715ff4f2208719f42e174db2e5", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/39/87/ce5cf695b6af229875b9c5ff757e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/db/f1/50f277827b1b070dd3b4c5c97553", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/f3/6fb608d305279d5d8663f6b8cee6", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/71/a0/00ae9e235e28b18def6847d69c75" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ef1a558d..ced1dff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,13 @@ +### 1.5.20 (20126) +- The ba.Session.teams and ba.Session.players lists are now ba.Session.sessionteams and ba.Session.sessionplayers. This is to help keep it clear that a Team/Player and a SessionTeam/SessionPlayer are different things now. +- Disconnecting an input-device now immediately removes the player instead of doing so in the next cycle; this prevents possible issues where code would try to access player.inputdevice before the removal happens which would lead to errors. +- Updated mac prefab builds to point at homebrew's python@3.7 package now that 3.8 has been made the default. + ### 1.5.19 (20123) - Cleaned up some bomb logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by punches or bombs potentially resulting in multiple explosions when triggered by multiple other bombs simultaneously. Holler if anything explosion-related seems off now. - Reactivated and cleaned up fatal-error message dialogs; they should now show up more consistently and on more platforms when something really bad happens instead of getting a silent crash. - Certain hardware buttons on Android which stopped working in 1.5 should now be working again.. - ### 1.5.18 (20108) - A bit of project cleanup; tools/snippets is now tools/pcommand, etc. - More minor bug fixes and crash/bug-logging improvements. diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index ae03193d..1eefd4b1 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -494,11 +494,11 @@ class Activity(DependencyComponent, Generic[PlayerType, TeamType]): self._stats = session.stats # Add session's teams in. - for team in session.teams: + for team in session.sessionteams: self.add_team(team) # Add session's players in. - for player in session.players: + for player in session.sessionplayers: self.add_player(player) self._has_begun = True diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index e6c9dcaf..b50365f1 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -189,7 +189,7 @@ class CoopSession(Session): # If there's *no* players left in the current activity but there *is* # in the session, restart the activity to pull them into the game # (or quit if they're just in the lobby). - if not activity.players and self.players: + if not activity.players and self.sessionplayers: # Special exception for tourney games; don't auto-restart these. if self.tournament_id is not None: @@ -226,7 +226,7 @@ class CoopSession(Session): # Make an exception if there's no players left. Otherwise this # can override the default session end that occurs in that case. - if not self.players: + if not self.sessionplayers: return # This method may get called from the UI context so make sure we @@ -268,7 +268,7 @@ class CoopSession(Session): # If at any point we have no in-game players, quit out of the session # (this can happen if someone leaves in the tutorial for instance). - active_players = [p for p in self.players if p.in_game] + active_players = [p for p in self.sessionplayers if p.in_game] if not active_players: self.end() return @@ -305,7 +305,7 @@ class CoopSession(Session): # Reset stats for the new activity. self.stats.reset() - for player in self.players: + for player in self.sessionplayers: # Skip players that are still choosing a team. if player.in_game: diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index 2f39ba5c..e88457f4 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -49,17 +49,17 @@ class FreeForAllSession(MultiTeamSession): This is based on the current number of players. """ point_awards: Dict[int, int] - if len(self.players) == 1: + if len(self.sessionplayers) == 1: point_awards = {} - elif len(self.players) == 2: + elif len(self.sessionplayers) == 2: point_awards = {0: 6} - elif len(self.players) == 3: + elif len(self.sessionplayers) == 3: point_awards = {0: 6, 1: 3} - elif len(self.players) == 4: + elif len(self.sessionplayers) == 4: point_awards = {0: 8, 1: 4, 2: 2} - elif len(self.players) == 5: + elif len(self.sessionplayers) == 5: point_awards = {0: 8, 1: 4, 2: 2} - elif len(self.players) == 6: + elif len(self.sessionplayers) == 6: point_awards = {0: 8, 1: 4, 2: 2} else: point_awards = {0: 8, 1: 4, 2: 2, 3: 1} @@ -80,7 +80,7 @@ class FreeForAllSession(MultiTeamSession): # If there's multiple players and everyone has the same score, # call it a draw. - if len(self.players) > 1 and len(winners) < 2: + if len(self.sessionplayers) > 1 and len(winners) < 2: self.setactivity( _ba.newactivity(DrawScoreScreenActivity, {'results': results})) else: @@ -95,7 +95,7 @@ class FreeForAllSession(MultiTeamSession): team.customdata['score'] += points series_winners = [ - team for team in self.teams + team for team in self.sessionteams if team.customdata['score'] >= self._ffa_series_length ] series_winners.sort(reverse=True, diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index c3564c81..82898aba 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -841,7 +841,9 @@ class Lobby: session = _ba.getsession() self._use_team_colors = session.use_team_colors if session.use_teams: - self._sessionteams = [weakref.ref(team) for team in session.teams] + self._sessionteams = [ + weakref.ref(team) for team in session.sessionteams + ] else: self._dummy_teams = SessionTeam() self._sessionteams = [weakref.ref(self._dummy_teams)] diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index 223c3930..ecf962d7 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -199,7 +199,7 @@ class MultiTeamSession(Session): if isinstance(activity, TeamSeriesVictoryScoreScreenActivity): self.stats.reset() self._game_number = 0 - for team in self.teams: + for team in self.sessionteams: team.customdata['score'] = 0 # Otherwise just set accum (per-game) scores. @@ -216,7 +216,7 @@ class MultiTeamSession(Session): self._instantiate_next_game() # (Re)register all players and wire stats to our next activity. - for player in self.players: + for player in self.sessionplayers: # ..but only ones who have been placed on a team # (ie: no longer sitting in the lobby). try: diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index 0fd9ed2e..c414d7a4 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -158,7 +158,9 @@ class ServerCallThread(threading.Thread): elif isinstance(exc, OSError): if exc.errno == 10051: # Windows unreachable network error. pass - elif exc.errno in [errno.ETIMEDOUT, errno.EHOSTUNREACH]: + elif exc.errno in [ + errno.ETIMEDOUT, errno.EHOSTUNREACH, errno.ENETUNREACH + ]: pass else: do_print = True diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index ed79d753..1aea000a 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -48,21 +48,22 @@ class Session: Attrs: - teams - All the ba.Teams in the Session. Most things should use the team - list in ba.Activity; not this. + sessionteams + All the ba.SessionTeams in the Session. Most things should use the + list of ba.Teams in ba.Activity; not this. - players - All ba.Players in the Session. Most things should use the player - list in ba.Activity; not this. Some players, such as those who have - not yet selected a character, will only appear on this list. + sessionplayers + All ba.SessionPlayers in the Session. Most things should use the + list of ba.Players in ba.Activity; not this. Some players, such as + those who have not yet selected a character, will only be + found on this list. min_players - The minimum number of Players who must be present for the Session + The minimum number of players who must be present for the Session to proceed past the initial joining screen. max_players - The maximum number of Players allowed in the Session. + The maximum number of players allowed in the Session. lobby The ba.Lobby instance where new ba.Players go to select a @@ -98,9 +99,9 @@ class Session: lobby: ba.Lobby max_players: int min_players: int - players: List[ba.SessionPlayer] + sessionplayers: List[ba.SessionPlayer] customdata: dict - teams: List[ba.SessionTeam] + sessionteams: List[ba.SessionTeam] def __init__(self, depsets: Sequence[ba.DependencySet], @@ -166,8 +167,8 @@ class Session: # Should remove this if possible. self.tournament_id: Optional[str] = None - self.teams = [] - self.players = [] + self.sessionteams = [] + self.sessionplayers = [] self.min_players = min_players self.max_players = max_players @@ -195,7 +196,7 @@ class Session: name=GameActivity.get_team_display_string( team_names[i]), color=color) - self.teams.append(team) + self.sessionteams.append(team) self._next_team_id += 1 try: with _ba.Context(self): @@ -226,7 +227,7 @@ class Session: # Limit player counts *unless* we're in a stress test. if _ba.app.stress_test_reset_timer is None: - if len(self.players) >= self.max_players: + if len(self.sessionplayers) >= self.max_players: # Print a rejection message *only* to the client trying to # join (prevents spamming everyone else in the game). @@ -245,7 +246,7 @@ class Session: def on_player_leave(self, sessionplayer: ba.SessionPlayer) -> None: """Called when a previously-accepted ba.SessionPlayer leaves.""" - if sessionplayer not in self.players: + if sessionplayer not in self.sessionplayers: print('ERROR: Session.on_player_leave called' ' for player not in our list.') return @@ -295,7 +296,7 @@ class Session: self._remove_player_team(sessionteam, activity) # Now remove them from the session list. - self.players.remove(sessionplayer) + self.sessionplayers.remove(sessionplayer) def _remove_player_team(self, sessionteam: ba.SessionTeam, activity: Optional[ba.Activity]) -> None: @@ -313,9 +314,9 @@ class Session: # And then from the Session. with _ba.Context(self): - if sessionteam in self.teams: + if sessionteam in self.sessionteams: try: - self.teams.remove(sessionteam) + self.sessionteams.remove(sessionteam) self.on_team_leave(sessionteam) except Exception: print_exception( @@ -535,7 +536,7 @@ class Session: # If they said yes, add the player to the lobby. if result: - self.players.append(sessionplayer) + self.sessionplayers.append(sessionplayer) with _ba.Context(self): try: self.lobby.add_chooser(sessionplayer) @@ -643,7 +644,7 @@ class Session: def _add_chosen_player(self, chooser: ba.Chooser) -> ba.SessionPlayer: from ba._team import SessionTeam sessionplayer = chooser.getplayer() - assert sessionplayer in self.players, ( + assert sessionplayer in self.sessionplayers, ( 'SessionPlayer not found in session ' 'player-list after chooser selection.') @@ -686,7 +687,7 @@ class Session: ) # Add player's team to the Session. - self.teams.append(sessionteam) + self.sessionteams.append(sessionteam) with _ba.Context(self): try: diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index 8831d687..6efa7ea5 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -75,7 +75,7 @@ class TeamVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): scale=0.25, color=(0.5, 0.5, 0.5, 1.0), jitter=3.0).autoretain() - for team in self.session.teams: + for team in self.session.sessionteams: ba.timer( i * 0.15 + 0.15, ba.WeakCall(self._show_team_name, vval - i * height, team, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamjoin.py b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py index 56e344ae..38fe9a7b 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamjoin.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py @@ -66,9 +66,10 @@ class MultiTeamJoinActivity(JoinActivity): # In teams mode, show our two team names. # FIXME: Lobby should handle this. if isinstance(ba.getsession(), DualTeamSession): - team_names = [team.name for team in ba.getsession().teams] + team_names = [team.name for team in ba.getsession().sessionteams] team_colors = [ - tuple(team.color) + (0.5, ) for team in ba.getsession().teams + tuple(team.color) + (0.5, ) + for team in ba.getsession().sessionteams ] if len(team_names) == 2: for i in range(2): diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py index bfb33de6..374bb7ef 100644 --- a/assets/src/ba_data/python/bastd/actor/controlsguide.py +++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py @@ -271,7 +271,9 @@ class ControlsGuide(ba.Actor): # We look at the session's players; not the activity's. # We want to get ones who are still in the process of # selecting a character, etc. - input_devices = [p.inputdevice for p in ba.getsession().players] + input_devices = [ + p.inputdevice for p in ba.getsession().sessionplayers + ] input_devices = [ i for i in input_devices if i and i is not touchscreen ] @@ -323,7 +325,7 @@ class ControlsGuide(ba.Actor): # We look at the session's players; not the activity's - we want to # get ones who are still in the process of selecting a character, etc. - input_devices = [p.inputdevice for p in ba.getsession().players] + input_devices = [p.inputdevice for p in ba.getsession().sessionplayers] input_devices = [i for i in input_devices if i] # If there's no players with input devices yet, try to default to diff --git a/docs/ba_module.md b/docs/ba_module.md index e8f344b3..8953ba8c 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-08 for Ballistica version 1.5.19 build 20119

    +

    last updated on 2020-07-09 for Ballistica version 1.5.20 build 20128

    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!


    @@ -1734,7 +1734,7 @@ and it should begin its actual game logic.

    high score lists.

    Attributes Inherited:

    -
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, sessionplayers, sessionteams, use_team_colors, use_teams

    Attributes Defined Here:

    campaign, sessionglobalsnode
    @@ -2092,7 +2092,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    -
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, sessionplayers, sessionteams, use_team_colors, use_teams

    Attributes Defined Here:

    sessionglobalsnode

    @@ -2219,7 +2219,7 @@ its time with lingering corpses, sound effects, etc.

    <all methods inherited from ba.Team>


    ba.Existable

    -

    Inherits from: typing_extensions.Protocol

    +

    Inherits from: typing.Protocol, typing.Generic

    A Protocol for objects supporting an exists() method.

    Category: Protocols @@ -2273,7 +2273,7 @@ its time with lingering corpses, sound effects, etc.

    Attributes Inherited:

    -
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, sessionplayers, sessionteams, use_team_colors, use_teams

    Attributes Defined Here:

    sessionglobalsnode

    @@ -3687,7 +3687,7 @@ Use ba.getmodel() to instantiate one.

    Attributes Inherited:

    -
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, sessionplayers, sessionteams, use_team_colors, use_teams

    Attributes Defined Here:

    sessionglobalsnode

    @@ -4659,7 +4659,7 @@ Pass 0 or a negative number for no ban time.

    maintaining state between them (players, teams, score tallies, etc).

    Attributes:

    -
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, players, sessionglobalsnode, teams, use_team_colors, use_teams
    +
    allow_mid_activity_joins, customdata, lobby, max_players, min_players, sessionglobalsnode, sessionplayers, sessionteams, use_team_colors, use_teams

    allow_mid_activity_joins

    bool

    @@ -4683,31 +4683,32 @@ any such selection.

    max_players

    int

    -

    The maximum number of Players allowed in the Session.

    +

    The maximum number of players allowed in the Session.

    min_players

    int

    -

    The minimum number of Players who must be present for the Session +

    The minimum number of players who must be present for the Session to proceed past the initial joining screen.

    -
    -

    players

    -

    List[ba.SessionPlayer]

    -

    All ba.Players in the Session. Most things should use the player -list in ba.Activity; not this. Some players, such as those who have -not yet selected a character, will only appear on this list.

    -

    sessionglobalsnode

    ba.Node

    The sessionglobals ba.Node for the session.

    -

    teams

    +

    sessionplayers

    +

    List[ba.SessionPlayer]

    +

    All ba.SessionPlayers in the Session. Most things should use the +list of ba.Players in ba.Activity; not this. Some players, such as +those who have not yet selected a character, will only be +found on this list.

    + +
    +

    sessionteams

    List[ba.SessionTeam]

    -

    All the ba.Teams in the Session. Most things should use the team -list in ba.Activity; not this.

    +

    All the ba.SessionTeams in the Session. Most things should use the +list of ba.Teams in ba.Activity; not this.

    use_team_colors

    diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index ea3b4d53..28dfd52b 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -149,7 +149,8 @@ def cpplint(projroot: Path, full: bool) -> None: codelines[unknownlintline] = ' elif False:' def lint_file(filename: str) -> None: - result = subprocess.call(['cpplint', '--root=src', filename], env=env) + result = subprocess.call( + ['python3.7', '-m', 'cpplint', '--root=src', filename], env=env) if result != 0: raise CleanError( f'{Clr.RED}Cpplint failed for {filename}.{Clr.RST}') @@ -213,7 +214,8 @@ def formatscripts(projroot: Path, full: bool) -> None: def format_file(filename: str) -> None: start_time = time.time() - result = subprocess.call(['yapf', '--in-place', filename]) + result = subprocess.call( + ['python3.7', '-m', 'yapf', '--in-place', filename]) if result != 0: raise Exception(f'Formatting failed for {filename}') duration = time.time() - start_time diff --git a/tools/update_project b/tools/update_project index 5f5f49b2..719c01f5 100755 --- a/tools/update_project +++ b/tools/update_project @@ -586,11 +586,11 @@ class App: with open(fname) as infile: lines = infile.read().splitlines() - auto_start = lines.index(' #AUTOGENERATED_BEGIN (this section' + auto_start = lines.index(' #AUTOGENERATED_BEGIN (this section' ' is managed by the "update_project" tool)') - auto_end = lines.index(' #AUTOGENERATED_END') + auto_end = lines.index(' #AUTOGENERATED_END') our_lines = [ - ' ${BA_SRC_ROOT}/ballistica' + f + ' ${BA_SRC_ROOT}/ballistica' + f for f in sorted(self._source_files + self._header_files) if not f.endswith('.mm') and not f.endswith('.m') ] From 0db957a4c369ca532990c326b49901583f7b85e6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 12 Jul 2020 02:47:27 -0700 Subject: [PATCH 141/417] Minor bug fixing and project cleanup --- .efrocachemap | 24 +++---- CHANGELOG.md | 1 + Makefile | 2 +- assets/src/ba_data/python/ba/_session.py | 4 +- .../src/ba_data/python/bastd/ui/partyqueue.py | 7 +++ docs/ba_module.md | 4 +- .../{stage_assets => batools/assetstaging.py} | 63 +++++++++---------- tools/batools/pcommand.py | 11 ++++ tools/pcommand | 2 +- 9 files changed, 69 insertions(+), 49 deletions(-) rename tools/{stage_assets => batools/assetstaging.py} (92%) diff --git a/.efrocachemap b/.efrocachemap index 3763543a..e206f443 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/57/f8/47526bddac42b974f4ce86d13166", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0a/a9/46cb3927b667d67d8dc936b744b6", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/f3/130eb5ddb320f11093ba92bfbe6a", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/53/a6/56310d64b07fb7aa1481e59a4d29", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cd/6a/1518d0ebde22f06a679edf04002a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/72/4f/f4d081f47a48ba940603a6825c1f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/1f/436439103f6ede3ec88f46b592a7", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/97/44/68715ff4f2208719f42e174db2e5", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/39/87/ce5cf695b6af229875b9c5ff757e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/db/f1/50f277827b1b070dd3b4c5c97553", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/f3/6fb608d305279d5d8663f6b8cee6", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/71/a0/00ae9e235e28b18def6847d69c75" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7c/92/8e0cbeffff273e5aa40fa584b602", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/4a/91a9073717d810d978101f035f75", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/cc/732f4cbdaa5ff318c7041b3cc46e", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/95/01/6e4e0ddd1b32d2a24267472811d9", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/ee/2230562fd122dbc68ace1959440a", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/0e/6aebdc438215b178618b209b3d38", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a6/6e/7041677d14ff3445e678e85ed509", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/78/7f/27a790f133b341a47e0d286631f6", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3f/7b/6548e30606ba52f274a72f123473", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/df/d8/b1bfd4a2de519276ae8b3498e64d", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/56/77/a0fcc90f8be8ac87b677ac0c983d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/45/1e/d1a5697069c1719b962140d4815b" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ced1dff9..c96b13a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - The ba.Session.teams and ba.Session.players lists are now ba.Session.sessionteams and ba.Session.sessionplayers. This is to help keep it clear that a Team/Player and a SessionTeam/SessionPlayer are different things now. - Disconnecting an input-device now immediately removes the player instead of doing so in the next cycle; this prevents possible issues where code would try to access player.inputdevice before the removal happens which would lead to errors. - Updated mac prefab builds to point at homebrew's python@3.7 package now that 3.8 has been made the default. +- Fixed an issue where adding/deleting UI widgets within certain callbacks could cause a crash. ### 1.5.19 (20123) - Cleaned up some bomb logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by punches or bombs potentially resulting in multiple explosions when triggered by multiple other bombs simultaneously. Holler if anything explosion-related seems off now. diff --git a/Makefile b/Makefile index 84cc0ca3..59dc4290 100644 --- a/Makefile +++ b/Makefile @@ -665,7 +665,7 @@ VERSION = $(shell tools/version_utils version) BUILD_NUMBER = $(shell tools/version_utils build) BUILD_DIR = ${PROJ_DIR}/build LAZYBUILDDIR = .cache/lazybuild -STAGE_ASSETS = ${PROJ_DIR}/tools/stage_assets +STAGE_ASSETS = ${PROJ_DIR}/tools/pcommand stage_assets # Things to ignore when doing root level cleans. ROOT_CLEAN_IGNORES = --exclude=assets/src_master \ diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 1aea000a..65f9610c 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -592,7 +592,9 @@ class Session: lobby = chooser.lobby activity = self._activity_weak() - # It seems this can happen.. + # This happens sometimes. That seems like it shouldn't be happening; + # when would we have a session and a chooser with players but no + # active activity? if activity is None: print('_on_player_ready called with no activity.') return diff --git a/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py index e29e5ec1..68e1dc73 100644 --- a/assets/src/ba_data/python/bastd/ui/partyqueue.py +++ b/assets/src/ba_data/python/bastd/ui/partyqueue.py @@ -374,8 +374,15 @@ class PartyQueueWindow(ba.Window): def on_update_response(self, response: Optional[Dict[str, Any]]) -> None: """We've received a response from an update to the server.""" + # pylint: disable=too-many-branches if not self._root_widget: return + + # Seeing this in logs; debugging... + if not self._title_text: + print('PartyQueueWindows update: Have root but no title_text.') + return + if response is not None: should_show_field = (response.get('d') is not None) self._smoothing = response['s'] diff --git a/docs/ba_module.md b/docs/ba_module.md index 8953ba8c..e25260c5 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-09 for Ballistica version 1.5.20 build 20128

    +

    last updated on 2020-07-11 for Ballistica version 1.5.20 build 20132

    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!


    @@ -2219,7 +2219,7 @@ its time with lingering corpses, sound effects, etc.

    <all methods inherited from ba.Team>


    ba.Existable

    -

    Inherits from: typing.Protocol, typing.Generic

    +

    Inherits from: typing_extensions.Protocol

    A Protocol for objects supporting an exists() method.

    Category: Protocols diff --git a/tools/stage_assets b/tools/batools/assetstaging.py similarity index 92% rename from tools/stage_assets rename to tools/batools/assetstaging.py index d412ee20..1fa0ed07 100755 --- a/tools/stage_assets +++ b/tools/batools/assetstaging.py @@ -30,7 +30,6 @@ import subprocess from functools import partial from typing import TYPE_CHECKING -from efro.error import CleanError from efrotools.pybuild import PYTHON_VERSION_MAJOR if TYPE_CHECKING: @@ -48,10 +47,10 @@ OPT_PYC_SUFFIX = ('cpython-' + PYTHON_VERSION_MAJOR.replace('.', '') + class Config: """Encapsulates command options.""" - def __init__(self) -> None: + def __init__(self, projroot: str) -> None: + self.projroot = projroot # We always calc src relative to this script. - self.src = os.path.abspath( - os.path.dirname(sys.argv[0]) + '/../assets/build') + self.src = self.projroot + '/assets/build' self.dst: Optional[str] = None self.win_extras_src: Optional[str] = None self.win_platform: Optional[str] = None @@ -71,7 +70,7 @@ class Config: self.is_payload_full = False self.debug = False - def _parse_android_args(self) -> None: + def _parse_android_args(self, args: List[str]) -> None: # On Android we get nitpicky with what # we want to copy in since we can speed up # iterations by installing stripped down @@ -89,7 +88,7 @@ class Config: self.include_fonts = False self.include_json = False self.include_pylib = False - for arg in sys.argv[1:]: + for arg in args: if arg == '-full': self.include_audio = True self.include_models = True @@ -118,13 +117,13 @@ class Config: elif arg == '-audio': self.include_audio = True - def _parse_win_platform(self, platform: str) -> None: + def _parse_win_platform(self, platform: str, args: List[str]) -> None: """Parse sub-args in the windows platform string.""" winempty, wintype, winplt, wincfg = platform.split('-') self.win_platform = winplt self.win_type = wintype assert winempty == '' - self.dst = sys.argv[2] + self.dst = args[1] self.tex_suffix = '.dds' if wintype == 'win': @@ -137,12 +136,9 @@ class Config: raise RuntimeError(f'Invalid wintype: "{wintype}"') if winplt == 'Win32': - self.win_extras_src = os.path.abspath( - os.path.dirname(sys.argv[0]) + - '/../assets/build/windows/Win32') + self.win_extras_src = self.projroot + '/assets/build/windows/Win32' elif winplt == 'x64': - self.win_extras_src = os.path.abspath( - os.path.dirname(sys.argv[0]) + '/../assets/build/windows/x64') + self.win_extras_src = self.projroot + '/assets/build/windows/x64' else: raise RuntimeError(f'Invalid winplt: "{winplt}"') @@ -153,31 +149,31 @@ class Config: else: raise RuntimeError(f'Invalid wincfg: "{wincfg}"') - def parse_args(self) -> None: + def parse_args(self, args: List[str]) -> None: """Parse args and apply to the cfg.""" - if len(sys.argv) < 2: + if len(args) < 1: raise RuntimeError('Expected a platform argument.') - platform = sys.argv[1] + platform = args[0] if platform == '-android': - self._parse_android_args() + self._parse_android_args(args) elif platform.startswith('-win'): - self._parse_win_platform(platform) + self._parse_win_platform(platform, args) elif platform == '-cmake': - self.dst = sys.argv[2] + self.dst = args[1] self.tex_suffix = '.dds' - elif '-cmakeserver' in sys.argv: - self.dst = sys.argv[2] + elif '-cmakeserver' in args: + self.dst = args[1] self.include_textures = False self.include_audio = False self.include_models = False - elif '-xcode-mac' in sys.argv: + elif '-xcode-mac' in args: self.src = os.environ['SOURCE_ROOT'] + '/assets/build' self.dst = (os.environ['TARGET_BUILD_DIR'] + '/' + os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']) self.include_pylib = True self.pylib_src_name = 'pylib-apple' self.tex_suffix = '.dds' - elif '-xcode-ios' in sys.argv: + elif '-xcode-ios' in args: self.src = os.environ['SOURCE_ROOT'] + '/assets/build' self.dst = (os.environ['TARGET_BUILD_DIR'] + '/' + os.environ['UNLOCALIZED_RESOURCES_FOLDER_PATH']) @@ -323,11 +319,14 @@ def _sync_pylib(cfg: Config) -> None: _run(cmd) -def main() -> None: +def main(projroot: str, args: Optional[List[str]] = None) -> None: """Stage assets for a build.""" - cfg = Config() - cfg.parse_args() + if args is None: + args = sys.argv + + cfg = Config(projroot) + cfg.parse_args(args) # Ok, now for every top level dir in src, come up with a nice single # command to sync the needed subset of it to dst. @@ -386,9 +385,9 @@ def main() -> None: _write_payload_file(cfg.dst, cfg.is_payload_full) -if __name__ == '__main__': - try: - main() - except CleanError as exc: - exc.pretty_print() - sys.exit(1) +# if __name__ == '__main__': +# try: +# main() +# except CleanError as exc: +# exc.pretty_print() +# sys.exit(1) diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 7e904c7e..196c31cf 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -692,3 +692,14 @@ def efro_gradle() -> None: if errored: sys.exit(1) + + +def stage_assets() -> None: + """Stage assets for a build.""" + from batools.assetstaging import main + from efro.error import CleanError + try: + main(projroot=str(PROJROOT), args=sys.argv[2:]) + except CleanError as exc: + exc.pretty_print() + sys.exit(1) diff --git a/tools/pcommand b/tools/pcommand index 481e3366..6351f9c6 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -55,7 +55,7 @@ from batools.pcommand import ( get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, - efro_gradle) + efro_gradle, stage_assets) # pylint: enable=unused-import if TYPE_CHECKING: From 09a3a300a296973e90b17ce287626e2b4b8d1854 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 12 Jul 2020 18:28:56 -0700 Subject: [PATCH 142/417] Added ba.app.uiscale with a proper enum type --- .efrocachemap | 24 ++--- .idea/dictionaries/ericf.xml | 2 + CHANGELOG.md | 3 + assets/src/ba_data/python/ba/__init__.py | 3 +- .../src/ba_data/python/ba/_activitytypes.py | 4 +- assets/src/ba_data/python/ba/_app.py | 95 +++++++++---------- assets/src/ba_data/python/ba/_enums.py | 25 +++++ assets/src/ba_data/python/ba/_gameutils.py | 4 +- .../python/bastd/activity/multiteamvictory.py | 2 +- .../ba_data/python/bastd/game/runaround.py | 6 +- assets/src/ba_data/python/bastd/mainmenu.py | 8 +- .../ba_data/python/bastd/ui/account/link.py | 11 ++- .../python/bastd/ui/account/settings.py | 18 ++-- .../ba_data/python/bastd/ui/account/unlink.py | 7 +- .../ba_data/python/bastd/ui/account/viewer.py | 12 ++- .../ba_data/python/bastd/ui/achievements.py | 9 +- .../src/ba_data/python/bastd/ui/appinvite.py | 8 +- .../python/bastd/ui/characterpicker.py | 8 +- .../ba_data/python/bastd/ui/colorpicker.py | 10 +- assets/src/ba_data/python/bastd/ui/confirm.py | 4 +- .../ba_data/python/bastd/ui/coop/browser.py | 69 ++++++++------ .../src/ba_data/python/bastd/ui/coop/level.py | 4 +- .../ba_data/python/bastd/ui/creditslist.py | 51 +++++----- assets/src/ba_data/python/bastd/ui/debug.py | 12 ++- .../src/ba_data/python/bastd/ui/feedback.py | 4 +- .../ba_data/python/bastd/ui/fileselector.py | 12 ++- assets/src/ba_data/python/bastd/ui/gather.py | 22 +++-- .../ba_data/python/bastd/ui/getcurrency.py | 12 ++- .../src/ba_data/python/bastd/ui/getremote.py | 4 +- assets/src/ba_data/python/bastd/ui/helpui.py | 35 +++---- .../src/ba_data/python/bastd/ui/iconpicker.py | 8 +- assets/src/ba_data/python/bastd/ui/kiosk.py | 5 +- .../python/bastd/ui/league/rankwindow.py | 26 ++--- .../src/ba_data/python/bastd/ui/mainmenu.py | 25 +++-- .../python/bastd/ui/onscreenkeyboard.py | 10 +- assets/src/ba_data/python/bastd/ui/party.py | 20 ++-- .../src/ba_data/python/bastd/ui/partyqueue.py | 4 +- assets/src/ba_data/python/bastd/ui/play.py | 19 ++-- .../python/bastd/ui/playlist/addgame.py | 16 ++-- .../python/bastd/ui/playlist/browser.py | 31 +++--- .../bastd/ui/playlist/customizebrowser.py | 19 ++-- .../ba_data/python/bastd/ui/playlist/edit.py | 19 ++-- .../python/bastd/ui/playlist/editgame.py | 16 ++-- .../python/bastd/ui/playlist/mapselect.py | 15 +-- .../ba_data/python/bastd/ui/playlist/share.py | 4 +- .../ba_data/python/bastd/ui/playoptions.py | 4 +- assets/src/ba_data/python/bastd/ui/popup.py | 6 +- .../python/bastd/ui/profile/browser.py | 19 ++-- .../ba_data/python/bastd/ui/profile/edit.py | 18 ++-- .../python/bastd/ui/profile/upgrade.py | 9 +- .../src/ba_data/python/bastd/ui/promocode.py | 4 +- .../src/ba_data/python/bastd/ui/purchase.py | 6 +- assets/src/ba_data/python/bastd/ui/qrcode.py | 4 +- assets/src/ba_data/python/bastd/ui/report.py | 5 +- .../python/bastd/ui/resourcetypeinfo.py | 4 +- .../ba_data/python/bastd/ui/serverdialog.py | 4 +- .../python/bastd/ui/settings/advanced.py | 18 ++-- .../python/bastd/ui/settings/allsettings.py | 22 +++-- .../ba_data/python/bastd/ui/settings/audio.py | 7 +- .../python/bastd/ui/settings/controls.py | 6 +- .../python/bastd/ui/settings/gamepad.py | 13 ++- .../bastd/ui/settings/gamepadadvanced.py | 19 ++-- .../python/bastd/ui/settings/gamepadselect.py | 11 ++- .../python/bastd/ui/settings/graphics.py | 11 ++- .../python/bastd/ui/settings/keyboard.py | 22 +++-- .../python/bastd/ui/settings/ps3controller.py | 4 +- .../python/bastd/ui/settings/remoteapp.py | 6 +- .../python/bastd/ui/settings/testing.py | 8 +- .../python/bastd/ui/settings/touchscreen.py | 4 +- .../bastd/ui/settings/xbox360controller.py | 4 +- .../python/bastd/ui/soundtrack/browser.py | 20 ++-- .../python/bastd/ui/soundtrack/edit.py | 16 ++-- .../bastd/ui/soundtrack/entrytypeselect.py | 4 +- .../ba_data/python/bastd/ui/specialoffer.py | 6 +- .../ba_data/python/bastd/ui/store/browser.py | 29 +++--- .../python/bastd/ui/teamnamescolors.py | 4 +- assets/src/ba_data/python/bastd/ui/telnet.py | 4 +- .../python/bastd/ui/tournamententry.py | 8 +- .../python/bastd/ui/tournamentscores.py | 9 +- .../src/ba_data/python/bastd/ui/trophies.py | 5 +- assets/src/ba_data/python/bastd/ui/url.py | 9 +- assets/src/ba_data/python/bastd/ui/watch.py | 52 +++++----- docs/ba_module.md | 51 +++++++--- 83 files changed, 700 insertions(+), 480 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e206f443..aca4202a 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/7c/92/8e0cbeffff273e5aa40fa584b602", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/4a/91a9073717d810d978101f035f75", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/13/cc/732f4cbdaa5ff318c7041b3cc46e", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/95/01/6e4e0ddd1b32d2a24267472811d9", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/63/ee/2230562fd122dbc68ace1959440a", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/0e/6aebdc438215b178618b209b3d38", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a6/6e/7041677d14ff3445e678e85ed509", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/78/7f/27a790f133b341a47e0d286631f6", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3f/7b/6548e30606ba52f274a72f123473", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/df/d8/b1bfd4a2de519276ae8b3498e64d", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/56/77/a0fcc90f8be8ac87b677ac0c983d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/45/1e/d1a5697069c1719b962140d4815b" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/eb/bc/4dd3903ea7c71defdfc204c6f888", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/36/19/3c6dcb2ee2cfc7f089355e9c81a1", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/33/ffe405cbec3b823592b8ebf06a59", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/18/8d125a287dae90ab4623a423443f", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2f/5d/f1fe725d479915bbe3d2e5f6b643", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a5/ae/f0e854f7cf68f8ffab4c3a94e403", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/0d/f8dbfe4faa05379b2330c9f91cab", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b9/c6/ac98c7aad5847fea5a37087d5aa0", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4e/59/c8cbb6d6909ab853bfa61a5160ce", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/26/cd/737e2615e116d110aac319a3e293", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/45/28/ff409cd1913fc71bf9b677b87df0", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a4/15/f823745542ea46f679552669b131" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 6507a224..a376cbb2 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -963,6 +963,7 @@ insta installdir instancer + interfacetype interstitials intex intp @@ -1779,6 +1780,7 @@ sline slval smag + smallscale smlh smtpd smtplib diff --git a/CHANGELOG.md b/CHANGELOG.md index c96b13a8..c31c523c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ - Disconnecting an input-device now immediately removes the player instead of doing so in the next cycle; this prevents possible issues where code would try to access player.inputdevice before the removal happens which would lead to errors. - Updated mac prefab builds to point at homebrew's python@3.7 package now that 3.8 has been made the default. - Fixed an issue where adding/deleting UI widgets within certain callbacks could cause a crash. +- Fixed a case where an early fatal error could lead to a hung app and no error dialog. +- Added environment variables which can override UI scale for testing. Set BA_FORCE_UI_SCALE to small, medium or large. +- Added a ba.UIScale enum. The value at ba.app.uiscale replaces the old ba.app.interface_type, ba.app.small_ui, and ba.app.med_ui values. ### 1.5.19 (20123) - Cleaned up some bomb logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by punches or bombs potentially resulting in multiple explosions when triggered by multiple other bombs simultaneously. Holler if anything explosion-related seems off now. diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 44ed439e..863ea29c 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -46,7 +46,8 @@ from ba._coopgame import CoopGameActivity from ba._coopsession import CoopSession from ba._dependency import (Dependency, DependencyComponent, DependencySet, AssetPackage) -from ba._enums import TimeType, Permission, TimeFormat, SpecialChar, InputType +from ba._enums import (TimeType, Permission, TimeFormat, SpecialChar, + InputType, UIScale) from ba._error import ( print_exception, print_error, ContextError, NotFoundError, PlayerNotFoundError, SessionPlayerNotFoundError, NodeNotFoundError, diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index d17d391a..065c47e2 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -26,7 +26,7 @@ from typing import TYPE_CHECKING import _ba from ba._activity import Activity from ba._music import setmusic, MusicType -from ba._enums import InputType +from ba._enums import InputType, UIScale # False-positive from pylint due to our class-generics-filter. from ba._player import EmptyPlayer # pylint: disable=W0611 from ba._team import EmptyTeam # pylint: disable=W0611 @@ -191,7 +191,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): # Pop up a 'press any button to continue' statement after our # min-view-time show a 'press any button to continue..' # thing after a bit. - if _ba.app.interface_type == 'large': + if _ba.app.uiscale is UIScale.LARGE: # FIXME: Need a better way to determine whether we've probably # got a keyboard. sval = _lang.Lstr(resource='pressAnyKeyButtonText') diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index fbb88a8a..4bd5e0ad 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -125,7 +125,7 @@ class App: 'hi': 'Hindi' } - # Special case Chinese: specific variations map to traditional. + # Special case for Chinese: specific variations map to traditional. # (otherwise will map to 'Chinese' which is simplified) if self.locale in ('zh_HANT', 'zh_TW'): language = 'ChineseTraditional' @@ -231,17 +231,9 @@ class App: return CURRENT_API_VERSION @property - def interface_type(self) -> str: - """Interface mode the game is in; can be 'large', 'medium', or 'small'. - - 'large' is used by system such as desktop PC where elements on screen - remain usable even at small sizes, allowing more to be shown. - 'small' is used by small devices such as phones, where elements on - screen must be larger to remain readable and usable. - 'medium' is used by tablets and other middle-of-the-road situations - such as VR or TV. - """ - return self._interface_type + def uiscale(self) -> ba.UIScale: + """Current ui scale for the app.""" + return self._uiscale @property def on_tv(self) -> bool: @@ -269,6 +261,7 @@ class App: """ # pylint: disable=too-many-statements from ba._music import MusicController + from ba._enums import UIScale # Config. self.config_file_healthy = False @@ -305,8 +298,16 @@ class App: assert isinstance(self._platform, str) self._subplatform: str = env['subplatform'] assert isinstance(self._subplatform, str) - self._interface_type: str = env['interface_type'] - assert isinstance(self._interface_type, str) + self._uiscale: ba.UIScale + interfacetype = env['interface_type'] + if interfacetype == 'large': + self._uiscale = UIScale.LARGE + elif interfacetype == 'medium': + self._uiscale = UIScale.MEDIUM + elif interfacetype == 'small': + self._uiscale = UIScale.SMALL + else: + raise RuntimeError('Invalid UIScale value: {interfacetype}') self._on_tv: bool = env['on_tv'] assert isinstance(self._on_tv, bool) self._vr_mode: bool = env['vr_mode'] @@ -427,15 +428,10 @@ class App: self.infotextcolor = (0.7, 0.9, 0.7) self.uicleanupchecks: List[UICleanupCheck] = [] self.uiupkeeptimer: Optional[ba.Timer] = None + self.toolbars = env.get('toolbar_test', True) self.delegate: Optional[ba.AppDelegate] = None - # A few shortcuts. - self.small_ui = env['interface_type'] == 'small' - self.med_ui = env['interface_type'] == 'medium' - self.large_ui = env['interface_type'] == 'large' - self.toolbars = env.get('toolbar_test', True) - def on_app_launch(self) -> None: """Runs after the app finishes bootstrapping. @@ -454,7 +450,7 @@ class App: from bastd import appdelegate from bastd import maps as stdmaps from bastd.actor import spazappearance - from ba._enums import TimeType + from ba._enums import TimeType, UIScale cfg = self.config @@ -482,12 +478,6 @@ class App: and not _ba.is_blessed()): _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0)) - # IMPORTANT - if tweaking UI stuff, you need to make sure it behaves - # for small, medium, and large UI modes. (doesn't run off screen, etc). - # Set these to 1 to test with different sizes. Generally small is used - # on phones, medium is used on tablets, and large is on desktops or - # large tablets. - # Kick off our periodic UI upkeep. # FIXME: Can probably kill this if we do immediate UI death checks. self.uiupkeeptimer = _ba.Timer(2.6543, @@ -495,29 +485,31 @@ class App: timetype=TimeType.REAL, repeat=True) - if bool(False): # force-test small UI - self.small_ui = True - self.med_ui = False - with _ba.Context('ui'): - _ba.pushcall(lambda: _ba.screenmessage( - 'FORCING SMALL UI FOR TESTING', color=(1, 0, 1), log=True)) + # IMPORTANT: If tweaking UI stuff, make sure it behaves for small, + # medium, and large UI modes. (doesn't run off screen, etc). + # The overrides below can be used to test with different sizes. + # Generally small is used on phones, medium is used on tablets/tvs, + # and large is on desktop computers or perhaps large tablets. When + # possible, run in windowed mode and resize the window to assure + # this holds true at all aspect ratios. - if bool(False): # force-test medium UI - self.small_ui = False - self.med_ui = True - with _ba.Context('ui'): - _ba.pushcall(lambda: _ba.screenmessage( - 'FORCING MEDIUM UI FOR TESTING', color=(1, 0, 1 - ), log=True)) - if bool(False): # force-test large UI - self.small_ui = False - self.med_ui = False - with _ba.Context('ui'): - _ba.pushcall(lambda: _ba.screenmessage( - 'FORCING LARGE UI FOR TESTING', color=(1, 0, 1), log=True)) + # UPDATE: A better way to test this is now by setting the environment + # variable BA_FORCE_UI_SCALE to "small", "medium", or "large". + # This will affect system UIs not covered by the values below such + # as screen-messages. The below values remain functional, however, + # for cases such as Android where environment variables can't be set + # easily. - # If there's a leftover log file, attempt to upload - # it to the server and/or get rid of it. + if bool(False): # force-test ui scale + self._uiscale = UIScale.SMALL + with _ba.Context('ui'): + _ba.pushcall(lambda: _ba.screenmessage( + f'FORCING UISCALE {self._uiscale.name} FOR TESTING', + color=(1, 0, 1), + log=True)) + + # If there's a leftover log file, attempt to upload it to the + # master-server and/or get rid of it. _apputils.handle_leftover_log_file() # Only do this stuff if our config file is healthy so we don't @@ -545,7 +537,7 @@ class App: # Debugging - make note if we're using the local test server so we # don't accidentally leave it on in a release. - # FIXME - move this to native layer. + # FIXME - should move this to the native layer. server_addr = _ba.get_master_server_address() if 'localhost' in server_addr: _ba.timer(2.0, @@ -582,9 +574,7 @@ class App: # Auto-sign-in to a local account in a moment if we're set to. def do_auto_sign_in() -> None: - if self.headless_build: - _ba.sign_in('Local') - elif cfg.get('Auto Account State') == 'Local': + if self.headless_build or cfg.get('Auto Account State') == 'Local': _ba.sign_in('Local') _ba.pushcall(do_auto_sign_in) @@ -610,6 +600,7 @@ class App: and not _ba.have_connected_clients()): from ba import _gameutils, _lang from ba._nodeactor import NodeActor + # FIXME: Shouldn't be touching scene stuff here; # should just pass the request on to the host-session. with _ba.Context(activity): diff --git a/assets/src/ba_data/python/ba/_enums.py b/assets/src/ba_data/python/ba/_enums.py index 1431686b..19aeed47 100644 --- a/assets/src/ba_data/python/ba/_enums.py +++ b/assets/src/ba_data/python/ba/_enums.py @@ -56,6 +56,31 @@ class InputType(Enum): DOWN_RELEASE = 26 +class UIScale(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. + + Category: Enums + + '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 = 0 + MEDIUM = 1 + SMALL = 2 + + class TimeType(Enum): """Specifies the type of time for various operations to target/use. diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 7f4588fb..dbe0c6d0 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -26,7 +26,7 @@ from dataclasses import dataclass from typing import TYPE_CHECKING import _ba -from ba._enums import TimeType, TimeFormat, SpecialChar +from ba._enums import TimeType, TimeFormat, SpecialChar, UIScale from ba._error import ActivityNotFoundError if TYPE_CHECKING: @@ -224,7 +224,7 @@ def show_damage_count(damage: str, position: Sequence[float], # FIXME: Should never vary game elements based on local config. # (connected clients may have differing configs so they won't # get the intended results). - do_big = app.interface_type == 'small' or app.vr_mode + do_big = app.uiscale is UIScale.SMALL or app.vr_mode txtnode = _ba.newnode('text', attrs={ 'text': damage, diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 275e2911..6f0bd926 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -54,7 +54,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): from ba.deprecated import get_resource ba.set_analytics_screen('FreeForAll Series Victory Screen' if self. _is_ffa else 'Teams Series Victory Screen') - if ba.app.interface_type == 'large': + if ba.app.uiscale is ba.UIScale.LARGE: sval = ba.Lstr(resource='pressAnyKeyButtonPlayAgainText') else: sval = ba.Lstr(resource='pressAnyButtonPlayAgainText') diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 0cecb473..66cd18b0 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -398,9 +398,9 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._tntspawner = TNTSpawner(position=self._tntspawnpos) # Make sure to stay out of the way of menu/party buttons in the corner. - interface_type = ba.app.interface_type - l_offs = (-80 if interface_type == 'small' else - -40 if interface_type == 'medium' else 0) + uiscale = ba.app.uiscale + l_offs = (-80 if uiscale is ba.UIScale.SMALL else + -40 if uiscale is ba.UIScale.MEDIUM else 0) self._lives_bg = ba.NodeActor( ba.newnode('image', diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 4be9c553..cbdb3003 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -65,7 +65,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): color = ((1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6)) # FIXME: Need a node attr for vr-specific-scale. scale = (0.9 if - (app.interface_type == 'small' or vr_mode) else 0.7) + (app.uiscale is ba.UIScale.SMALL or vr_mode) else 0.7) self.my_name = ba.NodeActor( ba.newnode('text', attrs={ @@ -104,7 +104,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): # Any differences need to happen at the engine level so everyone sees # things in their own optimal way. vr_mode = app.vr_mode - interface_type = app.interface_type + uiscale = app.uiscale # In cases where we're doing lots of dev work lets always show the # build number. @@ -127,7 +127,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): ]) else: text = ba.Lstr(value='${V}', subs=[('${V}', app.version)]) - scale = 0.9 if (interface_type == 'small' or vr_mode) else 0.7 + scale = 0.9 if (uiscale is ba.UIScale.SMALL or vr_mode) else 0.7 color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7) self.version = ba.NodeActor( ba.newnode( @@ -373,7 +373,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): ba.WeakCall(self._change_phrase), repeat=True) - scl = 1.2 if (ba.app.interface_type == 'small' + scl = 1.2 if (ba.app.uiscale is ba.UIScale.SMALL or ba.app.vr_mode) else 0.8 color2 = ((1, 1, 1, 1) if ba.app.vr_mode else diff --git a/assets/src/ba_data/python/bastd/ui/account/link.py b/assets/src/ba_data/python/bastd/ui/account/link.py index f25a3509..506ec979 100644 --- a/assets/src/ba_data/python/bastd/ui/account/link.py +++ b/assets/src/ba_data/python/bastd/ui/account/link.py @@ -49,14 +49,15 @@ class AccountLinkWindow(ba.Window): bg_color = (0.4, 0.4, 0.5) self._width = 560 self._height = 420 - base_scale = (1.65 - if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.1) + uiscale = ba.app.uiscale + base_scale = (1.65 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, - stack_offset=(0, -10) if ba.app.small_ui else (0, 0))) + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, position=(40, self._height - 45), size=(50, 50), @@ -131,11 +132,13 @@ class AccountLinkCodeWindow(ba.Window): def __init__(self, data: Dict[str, Any]): self._width = 350 self._height = 200 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), transition='in_scale', - scale=1.8 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0)) + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._data = copy.deepcopy(data) ba.playsound(ba.getsound('cashRegister')) ba.playsound(ba.getsound('swish')) diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py index db786b1b..56583eb7 100644 --- a/assets/src/ba_data/python/bastd/ui/account/settings.py +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py @@ -77,11 +77,12 @@ class AccountSettingsWindow(ba.Window): self._can_reset_achievements = (account_type == 'Game Center') app = ba.app + uiscale = app.uiscale - self._width = 760 if ba.app.small_ui else 660 - x_offs = 50 if ba.app.small_ui else 0 - self._height = (390 - if ba.app.small_ui else 430 if ba.app.med_ui else 490) + self._width = 760 if uiscale is ba.UIScale.SMALL else 660 + x_offs = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = (390 if uiscale is ba.UIScale.SMALL else + 430 if uiscale is ba.UIScale.MEDIUM else 490) self._sign_in_button = None self._sign_in_text = None @@ -103,15 +104,16 @@ class AccountSettingsWindow(ba.Window): # exceptions. self._show_sign_in_buttons.append('Local') - top_extra = 15 if ba.app.small_ui else 0 + top_extra = 15 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=(2.09 if ba.app.small_ui else 1.4 if ba.app.med_ui else 1.0), - stack_offset=(0, -19) if ba.app.small_ui else (0, 0))) - if ba.app.small_ui and ba.app.toolbars: + scale=(2.09 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -19) if uiscale is ba.UIScale.SMALL else (0, 0))) + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) diff --git a/assets/src/ba_data/python/bastd/ui/account/unlink.py b/assets/src/ba_data/python/bastd/ui/account/unlink.py index 7d20768a..c4b7ec78 100644 --- a/assets/src/ba_data/python/bastd/ui/account/unlink.py +++ b/assets/src/ba_data/python/bastd/ui/account/unlink.py @@ -50,14 +50,15 @@ class AccountUnlinkWindow(ba.Window): self._height = 350 self._scroll_width = 400 self._scroll_height = 200 - base_scale = (2.0 - if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.1) + uiscale = ba.app.uiscale + base_scale = (2.0 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, - stack_offset=(0, -10) if ba.app.small_ui else (0, 0))) + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, position=(30, self._height - 50), size=(50, 50), diff --git a/assets/src/ba_data/python/bastd/ui/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py index 5a61b9db..3c9022f5 100644 --- a/assets/src/ba_data/python/bastd/ui/account/viewer.py +++ b/assets/src/ba_data/python/bastd/ui/account/viewer.py @@ -46,13 +46,15 @@ class AccountViewerWindow(popup.PopupWindow): self._account_id = account_id self._profile_id = profile_id + uiscale = ba.app.uiscale if scale is None: - scale = (2.6 if ba.app.small_ui else 1.8 if ba.app.med_ui else 1.4) + scale = (2.6 if uiscale is ba.UIScale.SMALL else + 1.8 if uiscale is ba.UIScale.MEDIUM else 1.4) self._transitioning_out = False self._width = 400 - self._height = (300 - if ba.app.small_ui else 400 if ba.app.med_ui else 450) + self._height = (300 if uiscale is ba.UIScale.SMALL else + 400 if uiscale is ba.UIScale.MEDIUM else 450) self._subcontainer: Optional[ba.Widget] = None bg_color = (0.5, 0.4, 0.6) @@ -159,9 +161,11 @@ class AccountViewerWindow(popup.PopupWindow): choices.append('ban') choices_display.append(ba.Lstr(resource='banThisPlayerText')) + uiscale = ba.app.uiscale popup.PopupMenuWindow( position=self._extras_menu_button.get_screen_space_center(), - scale=2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), choices=choices, choices_display=choices_display, current_choice='more', diff --git a/assets/src/ba_data/python/bastd/ui/achievements.py b/assets/src/ba_data/python/bastd/ui/achievements.py index 2583a086..b63ce088 100644 --- a/assets/src/ba_data/python/bastd/ui/achievements.py +++ b/assets/src/ba_data/python/bastd/ui/achievements.py @@ -36,13 +36,14 @@ class AchievementsWindow(popup.PopupWindow): def __init__(self, position: Tuple[float, float], scale: float = None): # pylint: disable=too-many-locals + uiscale = ba.app.uiscale if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 450 - self._height = (300 - if ba.app.small_ui else 370 if ba.app.med_ui else 450) + self._height = (300 if uiscale is ba.UIScale.SMALL else + 370 if uiscale is ba.UIScale.MEDIUM else 450) bg_color = (0.5, 0.4, 0.6) # creates our _root_widget diff --git a/assets/src/ba_data/python/bastd/ui/appinvite.py b/assets/src/ba_data/python/bastd/ui/appinvite.py index a043192f..00eabdd8 100644 --- a/assets/src/ba_data/python/bastd/ui/appinvite.py +++ b/assets/src/ba_data/python/bastd/ui/appinvite.py @@ -42,10 +42,12 @@ class AppInviteWindow(ba.Window): self._width = 650 self._height = 400 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', - scale=1.8 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0)) + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=0.8, @@ -172,11 +174,13 @@ class ShowFriendCodeWindow(ba.Window): ba.set_analytics_screen('Friend Promo Code') self._width = 650 self._height = 400 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), transition='in_scale', - scale=1.7 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0)) + scale=(1.7 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._data = copy.deepcopy(data) ba.playsound(ba.getsound('cashRegister')) ba.playsound(ba.getsound('swish')) diff --git a/assets/src/ba_data/python/bastd/ui/characterpicker.py b/assets/src/ba_data/python/bastd/ui/characterpicker.py index 40cbe68d..4952988c 100644 --- a/assets/src/ba_data/python/bastd/ui/characterpicker.py +++ b/assets/src/ba_data/python/bastd/ui/characterpicker.py @@ -48,9 +48,10 @@ class CharacterPicker(popup.PopupWindow): # pylint: disable=too-many-locals from bastd.actor import spazappearance del parent # unused here + uiscale = ba.app.uiscale if scale is None: - scale = (1.85 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (1.85 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False @@ -79,7 +80,8 @@ class CharacterPicker(popup.PopupWindow): self._width = (10 + columns * (button_width + 2 * button_buffer_h) * (1.0 / 0.95) * (1.0 / 0.8)) - self._height = self._width * (0.8 if ba.app.small_ui else 1.06) + self._height = self._width * (0.8 + if uiscale is ba.UIScale.SMALL else 1.06) self._scroll_width = self._width * 0.8 self._scroll_height = self._height * 0.8 diff --git a/assets/src/ba_data/python/bastd/ui/colorpicker.py b/assets/src/ba_data/python/bastd/ui/colorpicker.py index 8684c340..21f4328e 100644 --- a/assets/src/ba_data/python/bastd/ui/colorpicker.py +++ b/assets/src/ba_data/python/bastd/ui/colorpicker.py @@ -52,9 +52,10 @@ class ColorPicker(PopupWindow): assert len(c_raw) == 16 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] + uiscale = ba.app.uiscale if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._parent = parent self._position = position self._scale = scale @@ -190,9 +191,10 @@ class ColorPickerExact(PopupWindow): assert len(c_raw) == 16 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] + uiscale = ba.app.uiscale if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False self._tag = tag diff --git a/assets/src/ba_data/python/bastd/ui/confirm.py b/assets/src/ba_data/python/bastd/ui/confirm.py index 9693b287..b15b1a6d 100644 --- a/assets/src/ba_data/python/bastd/ui/confirm.py +++ b/assets/src/ba_data/python/bastd/ui/confirm.py @@ -68,12 +68,14 @@ class ConfirmWindow: scale_origin = None transition = 'in_right' + uiscale = ba.app.uiscale self.root_widget = ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal_no_back', parent=_ba.get_special_widget('overlay_stack'), - scale=2.1 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0, + scale=(2.1 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), scale_origin_stack_offset=scale_origin) ba.textwidget(parent=self.root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 2cbdc6c5..629b782a 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -40,15 +40,17 @@ class CoopBrowserWindow(ba.Window): """Window for browsing co-op levels/games/etc.""" def _update_corner_button_positions(self) -> None: - offs = (-55 if ba.app.small_ui and _ba.is_party_icon_visible() else 0) + uiscale = ba.app.uiscale + offs = (-55 if uiscale is ba.UIScale.SMALL + and _ba.is_party_icon_visible() else 0) if self._league_rank_button is not None: self._league_rank_button.set_position( - (self._width - 282 + offs - self._x_inset, - self._height - 85 - (4 if ba.app.small_ui else 0))) + (self._width - 282 + offs - self._x_inset, self._height - 85 - + (4 if uiscale is ba.UIScale.SMALL else 0))) if self._store_button is not None: self._store_button.set_position( - (self._width - 170 + offs - self._x_inset, - self._height - 85 - (4 if ba.app.small_ui else 0))) + (self._width - 170 + offs - self._x_inset, self._height - 85 - + (4 if uiscale is ba.UIScale.SMALL else 0))) def __init__(self, transition: Optional[str] = 'in_right', @@ -96,12 +98,14 @@ class CoopBrowserWindow(ba.Window): self._hard_button_lock_image: Optional[ba.Widget] = None self._campaign_percent_text: Optional[ba.Widget] = None - self._width = 1320 if app.small_ui else 1120 - self._x_inset = x_inset = 100 if app.small_ui else 0 - self._height = (657 if app.small_ui else 730 if app.med_ui else 800) + uiscale = ba.app.uiscale + self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 + self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (657 if uiscale is ba.UIScale.SMALL else + 730 if uiscale is ba.UIScale.MEDIUM else 800) app.main_window = 'Coop Select' self._r = 'coopSelectWindow' - top_extra = 20 if app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 self._tourney_data_up_to_date = False @@ -112,18 +116,19 @@ class CoopBrowserWindow(ba.Window): size=(self._width, self._height + top_extra), toolbar_visibility='menu_full', scale_origin_stack_offset=scale_origin, - stack_offset=((0, -15) if app.small_ui else ( - 0, 0) if app.med_ui else (0, 0)), + stack_offset=((0, -15) if uiscale is ba.UIScale.SMALL else ( + 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0)), transition=transition, - scale=1.2 if app.small_ui else 0.8 if app.med_ui else 0.75)) + scale=(1.2 if uiscale is ba.UIScale.SMALL else + 0.8 if uiscale is ba.UIScale.MEDIUM else 0.75))) - if app.toolbars and app.small_ui: + if app.toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None else: self._back_button = ba.buttonwidget( parent=self._root_widget, - position=(75 + x_inset, - self._height - 87 - (4 if app.small_ui else 0)), + position=(75 + x_inset, self._height - 87 - + (4 if uiscale is ba.UIScale.SMALL else 0)), size=(120, 60), scale=1.2, autoselect=True, @@ -138,8 +143,8 @@ class CoopBrowserWindow(ba.Window): if not app.toolbars: prb = self._league_rank_button = LeagueRankButton( parent=self._root_widget, - position=(self._width - (282 + x_inset), - self._height - 85 - (4 if app.small_ui else 0)), + position=(self._width - (282 + x_inset), self._height - 85 - + (4 if uiscale is ba.UIScale.SMALL else 0)), size=(100, 60), color=(0.4, 0.4, 0.9), textcolor=(0.9, 0.9, 2.0), @@ -149,8 +154,8 @@ class CoopBrowserWindow(ba.Window): sbtn = self._store_button = StoreButton( parent=self._root_widget, - position=(self._width - (170 + x_inset), - self._height - 85 - (4 if app.small_ui else 0)), + position=(self._width - (170 + x_inset), self._height - 85 - + (4 if uiscale is ba.UIScale.SMALL else 0)), size=(100, 60), color=(0.6, 0.4, 0.7), show_tickets=True, @@ -195,7 +200,8 @@ class CoopBrowserWindow(ba.Window): v = self._height - 95 txt = ba.textwidget( parent=self._root_widget, - position=(self._width * 0.5, v + 40 - (0 if app.small_ui else 0)), + position=(self._width * 0.5, + v + 40 - (0 if uiscale is ba.UIScale.SMALL else 0)), size=(0, 0), text=ba.Lstr(resource='playModes.singlePlayerCoopText', fallback_resource='playModes.coopText'), @@ -205,16 +211,17 @@ class CoopBrowserWindow(ba.Window): maxwidth=500, v_align='center') - if app.toolbars and app.small_ui: + if app.toolbars and uiscale is ba.UIScale.SMALL: ba.textwidget(edit=txt, text='') if self._back_button is not None: - ba.buttonwidget(edit=self._back_button, - button_type='backSmall', - size=(60, 50), - position=(75 + x_inset, self._height - 87 - - (4 if app.small_ui else 0) + 6), - label=ba.charstr(ba.SpecialChar.BACK)) + ba.buttonwidget( + edit=self._back_button, + button_type='backSmall', + size=(60, 50), + position=(75 + x_inset, self._height - 87 - + (4 if uiscale is ba.UIScale.SMALL else 0) + 6), + label=ba.charstr(ba.SpecialChar.BACK)) self._selected_row = cfg.get('Selected Coop Row', None) @@ -225,8 +232,9 @@ class CoopBrowserWindow(ba.Window): self.a_outline_model = ba.getmodel('achievementOutline') self._scroll_width = self._width - (130 + 2 * x_inset) - self._scroll_height = self._height - (190 if app.small_ui - and app.toolbars else 160) + self._scroll_height = ( + self._height - + (190 if uiscale is ba.UIScale.SMALL and app.toolbars else 160)) self._subcontainerwidth = 800.0 self._subcontainerheight = 1400.0 @@ -234,7 +242,8 @@ class CoopBrowserWindow(ba.Window): self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, - position=(65 + x_inset, 120) if app.small_ui and app.toolbars else + position=(65 + x_inset, + 120) if uiscale is ba.UIScale.SMALL and app.toolbars else (65 + x_inset, 70), size=(self._scroll_width, self._scroll_height), simple_culling_v=10.0) diff --git a/assets/src/ba_data/python/bastd/ui/coop/level.py b/assets/src/ba_data/python/bastd/ui/coop/level.py index 8a8d60d6..113ca6fc 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/level.py +++ b/assets/src/ba_data/python/bastd/ui/coop/level.py @@ -32,10 +32,12 @@ class CoopLevelLockedWindow(ba.Window): width = 550.0 height = 250.0 lock_tex = ba.gettexture('lock') + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', - scale=1.7 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0)) + scale=(1.7 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0))) ba.textwidget(parent=self._root_widget, position=(150 - 20, height * 0.63), size=(0, 0), diff --git a/assets/src/ba_data/python/bastd/ui/creditslist.py b/assets/src/ba_data/python/bastd/ui/creditslist.py index cb5ad694..154337c1 100644 --- a/assets/src/ba_data/python/bastd/ui/creditslist.py +++ b/assets/src/ba_data/python/bastd/ui/creditslist.py @@ -51,9 +51,10 @@ class CreditsListWindow(ba.Window): scale_origin = None transition = 'in_right' - width = 870 if ba.app.small_ui else 670 - x_inset = 100 if ba.app.small_ui else 0 - height = 398 if ba.app.small_ui else 500 + uiscale = ba.app.uiscale + width = 870 if uiscale is ba.UIScale.SMALL else 670 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + height = 398 if uiscale is ba.UIScale.SMALL else 500 self._r = 'creditsWindow' super().__init__(root_widget=ba.containerwidget( @@ -61,33 +62,37 @@ class CreditsListWindow(ba.Window): transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=(2.0 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0), - stack_offset=(0, -8) if ba.app.small_ui else (0, 0))) + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -8) if uiscale is ba.UIScale.SMALL else (0, 0))) - if ba.app.toolbars and ba.app.small_ui: + if ba.app.toolbars and uiscale is ba.UIScale.SMALL: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) else: - btn = ba.buttonwidget(parent=self._root_widget, - position=(40 + x_inset, height - - (68 if ba.app.small_ui else 62)), - size=(140, 60), - scale=0.8, - label=ba.Lstr(resource='backText'), - button_type='back', - on_activate_call=self._back, - autoselect=True) + btn = ba.buttonwidget( + parent=self._root_widget, + position=(40 + x_inset, height - + (68 if uiscale is ba.UIScale.SMALL else 62)), + size=(140, 60), + scale=0.8, + label=ba.Lstr(resource='backText'), + button_type='back', + on_activate_call=self._back, + autoselect=True) ba.containerwidget(edit=self._root_widget, cancel_button=btn) - ba.buttonwidget(edit=btn, - button_type='backSmall', - position=(40 + x_inset, height - - (68 if ba.app.small_ui else 62) + 5), - size=(60, 48), - label=ba.charstr(ba.SpecialChar.BACK)) + ba.buttonwidget( + edit=btn, + button_type='backSmall', + position=(40 + x_inset, height - + (68 if uiscale is ba.UIScale.SMALL else 62) + 5), + size=(60, 48), + label=ba.charstr(ba.SpecialChar.BACK)) ba.textwidget(parent=self._root_widget, - position=(0, height - (59 if ba.app.small_ui else 54)), + position=(0, height - + (59 if uiscale is ba.UIScale.SMALL else 54)), size=(width, 30), text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', @@ -106,7 +111,7 @@ class CreditsListWindow(ba.Window): if ba.app.toolbars: ba.widget(edit=scroll, right_widget=_ba.get_special_widget('party_button')) - if ba.app.small_ui: + if uiscale is ba.UIScale.SMALL: ba.widget(edit=scroll, left_widget=_ba.get_special_widget('back_button')) diff --git a/assets/src/ba_data/python/bastd/ui/debug.py b/assets/src/ba_data/python/bastd/ui/debug.py index 50b8c670..41c864e6 100644 --- a/assets/src/ba_data/python/bastd/ui/debug.py +++ b/assets/src/ba_data/python/bastd/ui/debug.py @@ -38,9 +38,10 @@ class DebugWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui import popup + uiscale = ba.app.uiscale self._width = width = 580 - self._height = height = (350 if ba.app.small_ui else - 420 if ba.app.med_ui else 520) + self._height = height = (350 if uiscale is ba.UIScale.SMALL else + 420 if uiscale is ba.UIScale.MEDIUM else 520) self._scroll_width = self._width - 100 self._scroll_height = self._height - 120 @@ -54,12 +55,13 @@ class DebugWindow(ba.Window): self._stress_test_round_duration = 30 self._r = 'debugWindow' + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, - scale=( - 2.35 if ba.app.small_ui else 1.55 if ba.app.med_ui else 1.0), - stack_offset=(0, -30) if ba.app.small_ui else (0, 0))) + scale=(2.35 if uiscale is ba.UIScale.SMALL else + 1.55 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -30) if uiscale is ba.UIScale.SMALL else (0, 0))) self._done_button = btn = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/feedback.py b/assets/src/ba_data/python/bastd/ui/feedback.py index 303b76a6..d10d9f57 100644 --- a/assets/src/ba_data/python/bastd/ui/feedback.py +++ b/assets/src/ba_data/python/bastd/ui/feedback.py @@ -41,10 +41,12 @@ def ask_for_rating() -> Optional[ba.Widget]: width = 700 height = 400 spacing = 40 + uiscale = ba.app.uiscale dlg = ba.containerwidget( size=(width, height), transition='in_right', - scale=1.6 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0) + scale=(1.6 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0)) v = height - 50 v -= spacing v -= 140 diff --git a/assets/src/ba_data/python/bastd/ui/fileselector.py b/assets/src/ba_data/python/bastd/ui/fileselector.py index d397fb33..a65905a0 100644 --- a/assets/src/ba_data/python/bastd/ui/fileselector.py +++ b/assets/src/ba_data/python/bastd/ui/fileselector.py @@ -45,9 +45,10 @@ class FileSelectorWindow(ba.Window): allow_folders: bool = False): if valid_file_extensions is None: valid_file_extensions = [] - self._width = 700 if ba.app.small_ui else 600 - self._x_inset = x_inset = 50 if ba.app.small_ui else 0 - self._height = 365 if ba.app.small_ui else 418 + uiscale = ba.app.uiscale + self._width = 700 if uiscale is ba.UIScale.SMALL else 600 + self._x_inset = x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = 365 if uiscale is ba.UIScale.SMALL else 418 self._callback = callback self._base_path = path self._path: Optional[str] = None @@ -65,8 +66,9 @@ class FileSelectorWindow(ba.Window): super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_right', - scale=(2.23 if ba.app.small_ui else 1.4 if ba.app.med_ui else 1.0), - stack_offset=(0, -35) if ba.app.small_ui else (0, 0))) + scale=(2.23 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -35) if uiscale is ba.UIScale.SMALL else (0, 0))) ba.textwidget( parent=self._root_widget, position=(self._width * 0.5, self._height - 42), diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 5929297d..e4d3185f 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -58,12 +58,13 @@ class GatherWindow(ba.Window): ba.app.main_window = 'Gather' _ba.set_party_icon_always_visible(True) self._public_parties: Dict[str, Dict[str, Any]] = {} - self._width = 1240 if ba.app.small_ui else 1040 - x_offs = 100 if ba.app.small_ui else 0 - self._height = (582 - if ba.app.small_ui else 680 if ba.app.med_ui else 800) + uiscale = ba.app.uiscale + self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (582 if uiscale is ba.UIScale.SMALL else + 680 if uiscale is ba.UIScale.MEDIUM else 800) self._current_tab: Optional[str] = None - extra_top = 20 if ba.app.small_ui else 0 + extra_top = 20 if uiscale is ba.UIScale.SMALL else 0 self._r = 'gatherWindow' self._tab_data: Any = None self._internet_local_address: Optional[str] = None @@ -108,11 +109,12 @@ class GatherWindow(ba.Window): transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=(1.3 if ba.app.small_ui else 0.97 if ba.app.med_ui else 0.8), - stack_offset=(0, -11) if ba.app.small_ui else ( - 0, 0) if ba.app.med_ui else (0, 0))) + scale=(1.3 if uiscale is ba.UIScale.SMALL else + 0.97 if uiscale is ba.UIScale.MEDIUM else 0.8), + stack_offset=(0, -11) if uiscale is ba.UIScale.SMALL else ( + 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0))) - if ba.app.small_ui and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) self._back_button = None @@ -173,7 +175,7 @@ class GatherWindow(ba.Window): if ba.app.toolbars: ba.widget(edit=self._tab_buttons[tabs_def[-1][0]], right_widget=_ba.get_special_widget('party_button')) - if ba.app.small_ui: + if uiscale is ba.UIScale.SMALL: ba.widget(edit=self._tab_buttons[tabs_def[0][0]], left_widget=_ba.get_special_widget('back_button')) diff --git a/assets/src/ba_data/python/bastd/ui/getcurrency.py b/assets/src/ba_data/python/bastd/ui/getcurrency.py index 429cd52b..bfa0a96e 100644 --- a/assets/src/ba_data/python/bastd/ui/getcurrency.py +++ b/assets/src/ba_data/python/bastd/ui/getcurrency.py @@ -65,23 +65,25 @@ class GetCurrencyWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - self._width = 1000.0 if ba.app.small_ui else 800.0 - x_inset = 100.0 if ba.app.small_ui else 0.0 + uiscale = ba.app.uiscale + self._width = 1000.0 if uiscale is ba.UIScale.SMALL else 800.0 + x_inset = 100.0 if uiscale is ba.UIScale.SMALL else 0.0 self._height = 480.0 self._modal = modal self._from_modal_store = from_modal_store self._r = 'getTicketsWindow' - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, scale_origin_stack_offset=scale_origin, color=(0.4, 0.37, 0.55), - scale=(1.63 if ba.app.small_ui else 1.2 if ba.app.med_ui else 1.0), - stack_offset=(0, -3) if ba.app.small_ui else (0, 0))) + scale=(1.63 if uiscale is ba.UIScale.SMALL else + 1.2 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -3) if uiscale is ba.UIScale.SMALL else (0, 0))) btn = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/getremote.py b/assets/src/ba_data/python/bastd/ui/getremote.py index 4474afe1..4d7c6a84 100644 --- a/assets/src/ba_data/python/bastd/ui/getremote.py +++ b/assets/src/ba_data/python/bastd/ui/getremote.py @@ -36,7 +36,9 @@ class GetBSRemoteWindow(popup.PopupWindow): def __init__(self) -> None: position = (0.0, 0.0) - scale = (2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + uiscale = ba.app.uiscale + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 570 self._height = 350 diff --git a/assets/src/ba_data/python/bastd/ui/helpui.py b/assets/src/ba_data/python/bastd/ui/helpui.py index f9ecfb37..0d36502c 100644 --- a/assets/src/ba_data/python/bastd/ui/helpui.py +++ b/assets/src/ba_data/python/bastd/ui/helpui.py @@ -57,22 +57,25 @@ class HelpWindow(ba.Window): self._r = 'helpWindow' self._main_menu = main_menu - width = 950 if ba.app.small_ui else 750 - x_offs = 100 if ba.app.small_ui else 0 - height = 460 if ba.app.small_ui else 530 if ba.app.med_ui else 600 + uiscale = ba.app.uiscale + width = 950 if uiscale is ba.UIScale.SMALL else 750 + x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 + height = (460 if uiscale is ba.UIScale.SMALL else + 530 if uiscale is ba.UIScale.MEDIUM else 600) super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=( - 1.77 if ba.app.small_ui else 1.25 if ba.app.med_ui else 1.0), - stack_offset=(0, -30) if ba.app.small_ui else ( - 0, 15) if ba.app.med_ui else (0, 0))) + scale=(1.77 if uiscale is ba.UIScale.SMALL else + 1.25 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -30) if uiscale is ba.UIScale.SMALL else ( + 0, 15) if uiscale is ba.UIScale.MEDIUM else (0, 0))) ba.textwidget(parent=self._root_widget, - position=(0, height - (50 if ba.app.small_ui else 45)), + position=(0, height - + (50 if uiscale is ba.UIScale.SMALL else 45)), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', @@ -83,10 +86,10 @@ class HelpWindow(ba.Window): self._scrollwidget = ba.scrollwidget( parent=self._root_widget, - position=(44 + x_offs, 55 if ba.app.small_ui else 55), + position=(44 + x_offs, 55 if uiscale is ba.UIScale.SMALL else 55), simple_culling_v=100.0, size=(width - (88 + 2 * x_offs), - height - 120 + (5 if ba.app.small_ui else 0)), + height - 120 + (5 if uiscale is ba.UIScale.SMALL else 0)), capture_arrows=True) if ba.app.toolbars: @@ -97,7 +100,7 @@ class HelpWindow(ba.Window): # ugly: create this last so it gets first dibs at touch events (since # we have it close to the scroll widget) - if ba.app.small_ui and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._close) ba.widget(edit=self._scrollwidget, @@ -105,10 +108,12 @@ class HelpWindow(ba.Window): else: btn = ba.buttonwidget( parent=self._root_widget, - position=(x_offs + (40 + 0 if ba.app.small_ui else 70), - height - (59 if ba.app.small_ui else 50)), + position=(x_offs + + (40 + 0 if uiscale is ba.UIScale.SMALL else 70), + height - + (59 if uiscale is ba.UIScale.SMALL else 50)), size=(140, 60), - scale=0.7 if ba.app.small_ui else 0.8, + scale=0.7 if uiscale is ba.UIScale.SMALL else 0.8, label=ba.Lstr( resource='backText') if self._main_menu else 'Close', button_type='back' if self._main_menu else None, @@ -123,8 +128,6 @@ class HelpWindow(ba.Window): size=(60, 55), label=ba.charstr(ba.SpecialChar.BACK)) - # interface_type = ba.app.interface_type - self._sub_width = 660 self._sub_height = 1590 + get_resource( self._r + '.someDaysExtraSpace') + get_resource( diff --git a/assets/src/ba_data/python/bastd/ui/iconpicker.py b/assets/src/ba_data/python/bastd/ui/iconpicker.py index e80708bb..d2cc9794 100644 --- a/assets/src/ba_data/python/bastd/ui/iconpicker.py +++ b/assets/src/ba_data/python/bastd/ui/iconpicker.py @@ -50,9 +50,10 @@ class IconPicker(popup.PopupWindow): del parent # unused here del tint_color # unused_here del tint2_color # unused here + uiscale = ba.app.uiscale if scale is None: - scale = (1.85 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (1.85 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False @@ -69,7 +70,8 @@ class IconPicker(popup.PopupWindow): self._width = (10 + columns * (button_width + 2 * button_buffer_h) * (1.0 / 0.95) * (1.0 / 0.8)) - self._height = self._width * (0.8 if ba.app.small_ui else 1.06) + self._height = (self._width * + (0.8 if uiscale is ba.UIScale.SMALL else 1.06)) self._scroll_width = self._width * 0.8 self._scroll_height = self._height * 0.8 diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index e344257d..353867f5 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -311,6 +311,7 @@ class KioskWindow(ba.Window): self._b4 = self._b5 = self._b6 = None self._b7: Optional[ba.Widget] + uiscale = ba.app.uiscale if bool(False): self._b7 = ba.buttonwidget( parent=self._root_widget, @@ -321,8 +322,8 @@ class KioskWindow(ba.Window): scale=0.5, position=((self._width * 0.5 - 37.5, y_extra + 120) if not self._show_multiplayer else - (self._width + 100, - y_extra + (140 if ba.app.small_ui else 120))), + (self._width + 100, y_extra + + (140 if uiscale is ba.UIScale.SMALL else 120))), transition_delay=tdelay, label=ba.Lstr(resource=self._r + '.fullMenuText'), on_activate_call=self._do_full_menu) diff --git a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py index c90f705f..e4844ee2 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py @@ -40,6 +40,7 @@ class LeagueRankWindow(ba.Window): transition: str = 'in_right', modal: bool = False, origin_widget: ba.Widget = None): + # pylint: disable=too-many-statements from ba.internal import get_cached_league_rank_data from ba.deprecated import get_resource ba.set_analytics_screen('League Rank Window') @@ -57,13 +58,14 @@ class LeagueRankWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - self._width = 1320 if ba.app.small_ui else 1120 - x_inset = 100 if ba.app.small_ui else 0 - self._height = (657 - if ba.app.small_ui else 710 if ba.app.med_ui else 800) + uiscale = ba.app.uiscale + self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (657 if uiscale is ba.UIScale.SMALL else + 710 if uiscale is ba.UIScale.MEDIUM else 800) self._r = 'coopSelectWindow' self._rdict = get_resource(self._r) - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 self._league_url_arg = '' @@ -72,17 +74,17 @@ class LeagueRankWindow(ba.Window): super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), - stack_offset=(0, -15) if ba.app.small_ui else ( - 0, 10) if ba.app.med_ui else (0, 0), + stack_offset=(0, -15) if uiscale is ba.UIScale.SMALL else ( + 0, 10) if uiscale is ba.UIScale.MEDIUM else (0, 0), transition=transition, scale_origin_stack_offset=scale_origin, - scale=( - 1.2 if ba.app.small_ui else 0.93 if ba.app.med_ui else 0.8))) + scale=(1.2 if uiscale is ba.UIScale.SMALL else + 0.93 if uiscale is ba.UIScale.MEDIUM else 0.8))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, - position=(75 + x_inset, - self._height - 87 - (4 if ba.app.small_ui else 0)), + position=(75 + x_inset, self._height - 87 - + (4 if uiscale is ba.UIScale.SMALL else 0)), size=(120, 60), scale=1.2, autoselect=True, @@ -106,7 +108,7 @@ class LeagueRankWindow(ba.Window): ba.buttonwidget(edit=btn, button_type='backSmall', position=(75 + x_inset, self._height - 87 - - (2 if ba.app.small_ui else 0)), + (2 if uiscale is ba.UIScale.SMALL else 0)), size=(60, 55), label=ba.charstr(ba.SpecialChar.BACK)) diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 1d908fb3..3354bf3d 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -187,7 +187,7 @@ class MainMenuWindow(ba.Window): self._r = 'mainMenu' app = ba.app - self._have_quit_button = (app.interface_type == 'large' + self._have_quit_button = (app.uiscale is ba.UIScale.LARGE or (app.platform == 'windows' and app.subplatform == 'oculus')) @@ -288,8 +288,9 @@ class MainMenuWindow(ba.Window): sale_scale=1.3, transition_delay=self._tdelay) self._store_button = store_button = sbtn.get_button() - icon_size = (55 - if ba.app.small_ui else 55 if ba.app.med_ui else 70) + uiscale = ba.app.uiscale + icon_size = (55 if uiscale is ba.UIScale.SMALL else + 55 if uiscale is ba.UIScale.MEDIUM else 70) ba.imagewidget( parent=self._root_widget, position=(h - icon_size * 0.5, @@ -356,12 +357,13 @@ class MainMenuWindow(ba.Window): b_size = 50.0 b_buffer = 10.0 t_scale = 0.75 - if ba.app.small_ui: + uiscale = ba.app.uiscale + if uiscale is ba.UIScale.SMALL: b_size *= 0.6 b_buffer *= 1.0 v_offs = -40 t_scale = 0.5 - elif ba.app.med_ui: + elif uiscale is ba.UIScale.MEDIUM: v_offs = -70 else: v_offs = -100 @@ -457,7 +459,8 @@ class MainMenuWindow(ba.Window): b_count += 1 if self._have_store_button: b_count += 1 - if ba.app.small_ui: + uiscale = ba.app.uiscale + if uiscale is ba.UIScale.SMALL: root_widget_scale = 1.6 play_button_width = self._button_width * 0.65 play_button_height = self._button_height * 1.1 @@ -466,7 +469,7 @@ class MainMenuWindow(ba.Window): button_y_offs2 = -60.0 self._button_height *= 1.3 button_spacing = 1.04 - elif ba.app.med_ui: + elif uiscale is ba.UIScale.MEDIUM: root_widget_scale = 1.3 play_button_width = self._button_width * 0.65 play_button_height = self._button_height * 1.1 @@ -514,7 +517,9 @@ class MainMenuWindow(ba.Window): on_activate_call=self._demo_menu_press) else: self._demo_menu_button = None - foof = (-1 if ba.app.small_ui else 1 if ba.app.med_ui else 3) + uiscale = ba.app.uiscale + foof = (-1 if uiscale is ba.UIScale.SMALL else + 1 if uiscale is ba.UIScale.MEDIUM else 3) h, v, scale = positions[self._p_index] v = v + foof gather_delay = 0.0 if self._t_delay_play == 0.0 else max( @@ -710,10 +715,12 @@ class MainMenuWindow(ba.Window): # In this case we have a leave *and* a disconnect button. self._height += 50 self._height += 50 * (len(custom_menu_entries)) + uiscale = ba.app.uiscale ba.containerwidget( edit=self._root_widget, size=(self._width, self._height), - scale=2.15 if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.0) + scale=(2.15 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0)) h = 125.0 v = (self._height - 80.0 if self._input_player else self._height - 60) h_offset = 0 diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 431a123a..4e7cee12 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -39,16 +39,18 @@ class OnScreenKeyboardWindow(ba.Window): self._target_text = textwidget self._width = 700 self._height = 400 - top_extra = 20 if ba.app.small_ui else 0 + uiscale = ba.app.uiscale + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( parent=_ba.get_special_widget('overlay_stack'), size=(self._width, self._height + top_extra), transition='in_scale', scale_origin_stack_offset=self._target_text. get_screen_space_center(), - scale=(2.0 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0), - stack_offset=(0, 0) if ba.app.small_ui else ( - 0, 0) if ba.app.med_ui else (0, 0))) + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, 0) if uiscale is ba.UIScale.SMALL else ( + 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0))) self._done_button = ba.buttonwidget(parent=self._root_widget, position=(self._width - 200, 44), size=(140, 60), diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py index 74c5e540..74e6ad0e 100644 --- a/assets/src/ba_data/python/bastd/ui/party.py +++ b/assets/src/ba_data/python/bastd/ui/party.py @@ -47,8 +47,9 @@ class PartyWindow(ba.Window): self._popup_party_member_client_id: Optional[int] = None self._popup_party_member_is_host: Optional[bool] = None self._width = 500 - self._height = (365 - if ba.app.small_ui else 480 if ba.app.med_ui else 600) + uiscale = ba.app.uiscale + self._height = (365 if uiscale is ba.UIScale.SMALL else + 480 if uiscale is ba.UIScale.MEDIUM else 600) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', @@ -56,9 +57,10 @@ class PartyWindow(ba.Window): parent=_ba.get_special_widget('overlay_stack'), on_outside_click_call=self.close_with_sound, scale_origin_stack_offset=origin, - scale=(2.0 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0), - stack_offset=(0, -10) if ba.app.small_ui else ( - 240, 0) if ba.app.med_ui else (330, 20))) + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 240, 0) if uiscale is ba.UIScale.MEDIUM else (330, 20))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=0.7, @@ -198,9 +200,11 @@ class PartyWindow(ba.Window): def _on_menu_button_press(self) -> None: is_muted = ba.app.config.resolve('Chat Muted') + uiscale = ba.app.uiscale popup.PopupMenuWindow( position=self._menu_button.get_screen_space_center(), - scale=2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), choices=['unmute' if is_muted else 'mute'], choices_display=[ ba.Lstr( @@ -400,9 +404,11 @@ class PartyWindow(ba.Window): 14248): return kick_str = ba.Lstr(resource='kickVoteText') + uiscale = ba.app.uiscale popup.PopupMenuWindow( position=widget.get_screen_space_center(), - scale=2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23), choices=['kick'], choices_display=[kick_str], current_choice='kick', diff --git a/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py index 68e1dc73..a6d05cc5 100644 --- a/assets/src/ba_data/python/bastd/ui/partyqueue.py +++ b/assets/src/ba_data/python/bastd/ui/partyqueue.py @@ -223,11 +223,13 @@ class PartyQueueWindow(ba.Window): self._line_image: Optional[ba.Widget] = None self.eyes_model = ba.getmodel('plasticEyesTransparent') self._white_tex = ba.gettexture('white') + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), transition='in_scale', - scale=1.4 if ba.app.small_ui else 1.2 if ba.app.med_ui else 1.0)) + scale=(1.4 if uiscale is ba.UIScale.SMALL else + 1.2 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=1.0, diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py index f8e7e6a2..e1c84b25 100644 --- a/assets/src/ba_data/python/bastd/ui/play.py +++ b/assets/src/ba_data/python/bastd/ui/play.py @@ -46,8 +46,9 @@ class PlayWindow(ba.Window): threading.Thread(target=self._preload_modules).start() new_style = True - width = 1000 if ba.app.small_ui else 800 - x_offs = 100 if ba.app.small_ui else 0 + uiscale = ba.app.uiscale + width = 1000 if uiscale is ba.UIScale.SMALL else 800 + x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 height = 550 if new_style else 400 button_width = 400 @@ -67,10 +68,10 @@ class PlayWindow(ba.Window): transition=transition, toolbar_visibility='menu_full', scale_origin_stack_offset=scale_origin, - scale=(1.6 if new_style else 1.52 - ) if ba.app.small_ui else 0.9 if ba.app.med_ui else 0.8, + scale=((1.6 if new_style else 1.52) if uiscale is ba.UIScale.SMALL + else 0.9 if uiscale is ba.UIScale.MEDIUM else 0.8), stack_offset=((0, 0) if new_style else ( - 10, 7)) if ba.app.small_ui else (0, 0))) + 10, 7)) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(55 + x_offs, height - 132) if new_style else @@ -99,14 +100,14 @@ class PlayWindow(ba.Window): button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) - if ba.app.toolbars and ba.app.small_ui: + if ba.app.toolbars and uiscale is ba.UIScale.SMALL: ba.textwidget(edit=txt, text='') v = height - (110 if new_style else 60) v -= 100 clr = (0.6, 0.7, 0.6, 1.0) v -= 280 if new_style else 180 - v += 30 if ba.app.toolbars and ba.app.small_ui else 0 + v += 30 if ba.app.toolbars and uiscale is ba.UIScale.SMALL else 0 hoffs = x_offs + 80 if new_style else 0 scl = 1.13 if new_style else 0.68 @@ -134,7 +135,7 @@ class PlayWindow(ba.Window): text_scale=1.13, on_activate_call=self._coop) - if ba.app.toolbars and ba.app.small_ui: + if ba.app.toolbars and uiscale is ba.UIScale.SMALL: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) ba.widget(edit=btn, @@ -403,7 +404,7 @@ class PlayWindow(ba.Window): maxwidth=scl * button_width * 0.7, color=clr) - if ba.app.toolbars and ba.app.small_ui: + if ba.app.toolbars and uiscale is ba.UIScale.SMALL: back_button.delete() ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py index f60827ad..12e12cc0 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py @@ -40,18 +40,20 @@ class PlaylistAddGameWindow(ba.Window): transition: str = 'in_right'): self._editcontroller = editcontroller self._r = 'addGameWindow' - self._width = 750 if ba.app.small_ui else 650 - x_inset = 50 if ba.app.small_ui else 0 - self._height = (346 - if ba.app.small_ui else 380 if ba.app.med_ui else 440) - top_extra = 30 if ba.app.small_ui else 20 + uiscale = ba.app.uiscale + self._width = 750 if uiscale is ba.UIScale.SMALL else 650 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = (346 if uiscale is ba.UIScale.SMALL else + 380 if uiscale is ba.UIScale.MEDIUM else 440) + top_extra = 30 if uiscale is ba.UIScale.SMALL else 20 self._scroll_width = 210 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, - scale=(2.17 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0), - stack_offset=(0, 1) if ba.app.small_ui else (0, 0))) + scale=(2.17 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, 1) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = ba.buttonwidget(parent=self._root_widget, position=(58 + x_inset, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index 85be719a..01961c70 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -218,21 +218,22 @@ class PlaylistBrowserWindow(ba.Window): self._selected_playlist = ba.app.config.get(self._pvars.config_name + ' Playlist Selection') - self._width = 900 if ba.app.small_ui else 800 - x_inset = 50 if ba.app.small_ui else 0 - self._height = (480 - if ba.app.small_ui else 510 if ba.app.med_ui else 580) + uiscale = ba.app.uiscale + self._width = 900 if uiscale is ba.UIScale.SMALL else 800 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = (480 if uiscale is ba.UIScale.SMALL else + 510 if uiscale is ba.UIScale.MEDIUM else 580) - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility='menu_full', scale_origin_stack_offset=scale_origin, - scale=( - 1.69 if ba.app.small_ui else 1.05 if ba.app.med_ui else 0.9), - stack_offset=(0, -26) if ba.app.small_ui else (0, 0))) + scale=(1.69 if uiscale is ba.UIScale.SMALL else + 1.05 if uiscale is ba.UIScale.MEDIUM else 0.9), + stack_offset=(0, -26) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button: Optional[ba.Widget] = ba.buttonwidget( parent=self._root_widget, @@ -255,7 +256,7 @@ class PlaylistBrowserWindow(ba.Window): color=ba.app.heading_color, h_align='center', v_align='center') - if ba.app.small_ui and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: ba.textwidget(edit=txt, text='') ba.buttonwidget(edit=self._back_button, @@ -264,7 +265,7 @@ class PlaylistBrowserWindow(ba.Window): position=(59 + x_inset, self._height - 67), label=ba.charstr(ba.SpecialChar.BACK)) - if ba.app.small_ui and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: self._back_button.delete() self._back_button = None ba.containerwidget(edit=self._root_widget, @@ -273,8 +274,8 @@ class PlaylistBrowserWindow(ba.Window): else: scroll_offs = 0 self._scroll_width = self._width - (100 + 2 * x_inset) - self._scroll_height = self._height - (146 if ba.app.small_ui - and ba.app.toolbars else 136) + self._scroll_height = self._height - ( + 146 if uiscale is ba.UIScale.SMALL and ba.app.toolbars else 136) self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, @@ -364,6 +365,7 @@ class PlaylistBrowserWindow(ba.Window): h_offs = 225 if count == 1 else 115 if count == 2 else 0 h_offs_bottom = 0 + uiscale = ba.app.uiscale for y in range(rows): for x in range(columns): name = items[index][0] @@ -378,11 +380,12 @@ class PlaylistBrowserWindow(ba.Window): label='', position=pos) - if x == 0 and ba.app.toolbars and ba.app.small_ui: + if x == 0 and ba.app.toolbars and uiscale is ba.UIScale.SMALL: ba.widget( edit=btn, left_widget=_ba.get_special_widget('back_button')) - if x == columns - 1 and ba.app.toolbars and ba.app.small_ui: + if (x == columns - 1 and ba.app.toolbars + and uiscale is ba.UIScale.SMALL): ba.widget( edit=btn, right_widget=_ba.get_special_widget('party_button')) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py index c1beaac5..e72482f5 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -59,18 +59,20 @@ class PlaylistCustomizeBrowserWindow(ba.Window): self._pvars = playlist.PlaylistTypeVars(sessiontype) self._max_playlists = 30 self._r = 'gameListWindow' - self._width = 750.0 if ba.app.small_ui else 650.0 - x_inset = 50.0 if ba.app.small_ui else 0.0 - self._height = (380.0 if ba.app.small_ui else - 420.0 if ba.app.med_ui else 500.0) - top_extra = 20.0 if ba.app.small_ui else 0.0 + uiscale = ba.app.uiscale + self._width = 750.0 if uiscale is ba.UIScale.SMALL else 650.0 + x_inset = 50.0 if uiscale is ba.UIScale.SMALL else 0.0 + self._height = (380.0 if uiscale is ba.UIScale.SMALL else + 420.0 if uiscale is ba.UIScale.MEDIUM else 500.0) + top_extra = 20.0 if uiscale is ba.UIScale.SMALL else 0.0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, scale_origin_stack_offset=scale_origin, - scale=(2.05 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0), - stack_offset=(0, -10) if ba.app.small_ui else (0, 0))) + scale=(2.05 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = back_button = btn = ba.buttonwidget( parent=self._root_widget, @@ -105,7 +107,8 @@ class PlaylistCustomizeBrowserWindow(ba.Window): self._lock_images: List[ba.Widget] = [] lock_tex = ba.gettexture('lock') - scl = (1.1 if ba.app.small_ui else 1.27 if ba.app.med_ui else 1.57) + scl = (1.1 if uiscale is ba.UIScale.SMALL else + 1.27 if uiscale is ba.UIScale.MEDIUM else 1.57) scl *= 0.63 v -= 65.0 * scl new_button = btn = ba.buttonwidget( diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index 3603963b..610e8bc7 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -45,17 +45,19 @@ class PlaylistEditWindow(ba.Window): self._r = 'editGameListWindow' prev_selection = self._editcontroller.get_edit_ui_selection() - self._width = 770 if ba.app.small_ui else 670 - x_inset = 50 if ba.app.small_ui else 0 - self._height = (400 - if ba.app.small_ui else 470 if ba.app.med_ui else 540) + uiscale = ba.app.uiscale + self._width = 770 if uiscale is ba.UIScale.SMALL else 670 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + self._height = (400 if uiscale is ba.UIScale.SMALL else + 470 if uiscale is ba.UIScale.MEDIUM else 540) - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, - scale=(2.0 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0), - stack_offset=(0, -16) if ba.app.small_ui else (0, 0))) + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -16) if uiscale is ba.UIScale.SMALL else (0, 0))) cancel_button = ba.buttonwidget(parent=self._root_widget, position=(35 + x_inset, self._height - 60), @@ -133,7 +135,8 @@ class PlaylistEditWindow(ba.Window): v -= 2.0 v += 63 - scl = (1.03 if ba.app.small_ui else 1.36 if ba.app.med_ui else 1.74) + scl = (1.03 if uiscale is ba.UIScale.SMALL else + 1.36 if uiscale is ba.UIScale.MEDIUM else 1.74) v -= 63.0 * scl add_game_button = ba.buttonwidget( diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index 07e590de..bb029ff8 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -106,9 +106,11 @@ class PlaylistEditGameWindow(ba.Window): self._choice_selections: Dict[str, int] = {} - width = 720 if ba.app.small_ui else 620 - x_inset = 50 if ba.app.small_ui else 0 - height = (365 if ba.app.small_ui else 460 if ba.app.med_ui else 550) + uiscale = ba.app.uiscale + width = 720 if uiscale is ba.UIScale.SMALL else 620 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + height = (365 if uiscale is ba.UIScale.SMALL else + 460 if uiscale is ba.UIScale.MEDIUM else 550) spacing = 52 y_extra = 15 y_extra2 = 21 @@ -118,13 +120,13 @@ class PlaylistEditGameWindow(ba.Window): raise Exception('no map preview tex found for' + self._map) map_tex = ba.gettexture(map_tex_name) - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, - scale=( - 2.19 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0), - stack_offset=(0, -17) if ba.app.small_ui else (0, 0))) + scale=(2.19 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -17) if uiscale is ba.UIScale.SMALL else (0, 0))) btn = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py index 62311293..5b3917a1 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py @@ -55,16 +55,19 @@ class PlaylistMapSelectWindow(ba.Window): except Exception: self._previous_map = '' - width = 715 if ba.app.small_ui else 615 - x_inset = 50 if ba.app.small_ui else 0 - height = (400 if ba.app.small_ui else 480 if ba.app.med_ui else 600) + uiscale = ba.app.uiscale + width = 715 if uiscale is ba.UIScale.SMALL else 615 + x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 + height = (400 if uiscale is ba.UIScale.SMALL else + 480 if uiscale is ba.UIScale.MEDIUM else 600) - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, - scale=(2.17 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0), - stack_offset=(0, -27) if ba.app.small_ui else (0, 0))) + scale=(2.17 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -27) if uiscale is ba.UIScale.SMALL else (0, 0))) self._cancel_button = btn = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/playlist/share.py b/assets/src/ba_data/python/bastd/ui/playlist/share.py index a6aa7721..e5fcc4d0 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/share.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/share.py @@ -89,11 +89,13 @@ class SharePlaylistResultsWindow(ba.Window): del origin # unused arg self._width = 450 self._height = 300 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), transition='in_scale', - scale=1.8 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0)) + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) ba.playsound(ba.getsound('cashRegister')) ba.playsound(ba.getsound('swish')) diff --git a/assets/src/ba_data/python/bastd/ui/playoptions.py b/assets/src/ba_data/python/bastd/ui/playoptions.py index bc3b78a8..2e9267d4 100644 --- a/assets/src/ba_data/python/bastd/ui/playoptions.py +++ b/assets/src/ba_data/python/bastd/ui/playoptions.py @@ -149,7 +149,9 @@ class PlayOptionsWindow(popup.PopupWindow): self._height += 40 # Creates our _root_widget. - scale = (1.69 if ba.app.small_ui else 1.1 if ba.app.med_ui else 0.85) + uiscale = ba.app.uiscale + scale = (1.69 if uiscale is ba.UIScale.SMALL else + 1.1 if uiscale is ba.UIScale.MEDIUM else 0.85) super().__init__(position=scale_origin, size=(self._width, self._height), scale=scale) diff --git a/assets/src/ba_data/python/bastd/ui/popup.py b/assets/src/ba_data/python/bastd/ui/popup.py index 538b17e4..77dc2e11 100644 --- a/assets/src/ba_data/python/bastd/ui/popup.py +++ b/assets/src/ba_data/python/bastd/ui/popup.py @@ -291,13 +291,15 @@ class PopupMenu: choices_display: Sequence[ba.Lstr] = None, button_size: Tuple[float, float] = (160.0, 50.0), autoselect: bool = True): + # pylint: disable=too-many-locals if choices_disabled is None: choices_disabled = [] if choices_display is None: choices_display = [] + uiscale = ba.app.uiscale if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) if current_choice not in choices: current_choice = None self._choices = list(choices) diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py index 1821ab2c..6190f05e 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py @@ -47,10 +47,11 @@ class ProfileBrowserWindow(ba.Window): back_label = ba.Lstr(resource='backText') else: back_label = ba.Lstr(resource='doneText') - self._width = 700.0 if ba.app.small_ui else 600.0 - x_inset = 50.0 if ba.app.small_ui else 0.0 - self._height = (360.0 if ba.app.small_ui else - 385.0 if ba.app.med_ui else 410.0) + uiscale = ba.app.uiscale + self._width = 700.0 if uiscale is ba.UIScale.SMALL else 600.0 + x_inset = 50.0 if uiscale is ba.UIScale.SMALL else 0.0 + self._height = (360.0 if uiscale is ba.UIScale.SMALL else + 385.0 if uiscale is ba.UIScale.MEDIUM else 410.0) # If we're being called up standalone, handle pause/resume ourself. if not self._in_main_menu: @@ -71,14 +72,15 @@ class ProfileBrowserWindow(ba.Window): # Ensure we've got an account-profile in cases where we're signed in. ensure_have_account_player_profile() - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, scale_origin_stack_offset=scale_origin, - scale=(2.2 if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.0), - stack_offset=(0, -14) if ba.app.small_ui else (0, 0))) + scale=(2.2 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -14) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, @@ -113,7 +115,8 @@ class ProfileBrowserWindow(ba.Window): h = 50 + x_inset b_color = (0.6, 0.53, 0.63) - scl = (1.055 if ba.app.small_ui else 1.18 if ba.app.med_ui else 1.3) + scl = (1.055 if uiscale is ba.UIScale.SMALL else + 1.18 if uiscale is ba.UIScale.MEDIUM else 1.3) v -= 70.0 * scl self._new_button = ba.buttonwidget(parent=self._root_widget, position=(h, v), diff --git a/assets/src/ba_data/python/bastd/ui/profile/edit.py b/assets/src/ba_data/python/bastd/ui/profile/edit.py index d1c520b6..748219dd 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/edit.py +++ b/assets/src/ba_data/python/bastd/ui/profile/edit.py @@ -62,19 +62,21 @@ class EditProfileWindow(ba.Window): # Grab profile colors or pick random ones. self._color, self._highlight = get_player_profile_colors( existing_profile) - self._width = width = 780.0 if ba.app.small_ui else 680.0 - self._x_inset = x_inset = 50.0 if ba.app.small_ui else 0.0 - self._height = height = (350.0 if ba.app.small_ui else - 400.0 if ba.app.med_ui else 450.0) + uiscale = ba.app.uiscale + self._width = width = 780.0 if uiscale is ba.UIScale.SMALL else 680.0 + self._x_inset = x_inset = 50.0 if uiscale is ba.UIScale.SMALL else 0.0 + self._height = height = ( + 350.0 if uiscale is ba.UIScale.SMALL else + 400.0 if uiscale is ba.UIScale.MEDIUM else 450.0) spacing = 40 - self._base_scale = (2.05 if ba.app.small_ui else - 1.5 if ba.app.med_ui else 1.0) - top_extra = 15 if ba.app.small_ui else 15 + self._base_scale = (2.05 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) + top_extra = 15 if uiscale is ba.UIScale.SMALL else 15 super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, scale=self._base_scale, - stack_offset=(0, 15) if ba.app.small_ui else (0, 0))) + stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0))) cancel_button = btn = ba.buttonwidget( parent=self._root_widget, position=(52 + x_inset, height - 60), diff --git a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py index 62cebcf0..83876011 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py +++ b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py @@ -45,19 +45,20 @@ class ProfileUpgradeWindow(ba.Window): self._width = 680 self._height = 350 - self._base_scale = (2.05 if ba.app.small_ui else - 1.5 if ba.app.med_ui else 1.2) + uiscale = ba.app.uiscale + self._base_scale = (2.05 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.2) self._upgrade_start_time: Optional[float] = None self._name = edit_profile_window.getname() self._edit_profile_window = weakref.ref(edit_profile_window) - top_extra = 15 if ba.app.small_ui else 15 + top_extra = 15 if uiscale is ba.UIScale.SMALL else 15 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), toolbar_visibility='menu_currency', transition=transition, scale=self._base_scale, - stack_offset=(0, 15) if ba.app.small_ui else (0, 0))) + stack_offset=(0, 15) if uiscale is ba.UIScale.SMALL else (0, 0))) cancel_button = ba.buttonwidget(parent=self._root_widget, position=(52, 30), size=(155, 60), diff --git a/assets/src/ba_data/python/bastd/ui/promocode.py b/assets/src/ba_data/python/bastd/ui/promocode.py index af4aa198..5469dd5a 100644 --- a/assets/src/ba_data/python/bastd/ui/promocode.py +++ b/assets/src/ba_data/python/bastd/ui/promocode.py @@ -53,12 +53,14 @@ class PromoCodeWindow(ba.Window): self._modal = modal self._r = 'promoCodeWindow' + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, toolbar_visibility='menu_minimal_no_back', scale_origin_stack_offset=scale_origin, - scale=(2.0 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0))) + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0))) btn = ba.buttonwidget(parent=self._root_widget, scale=0.5, diff --git a/assets/src/ba_data/python/bastd/ui/purchase.py b/assets/src/ba_data/python/bastd/ui/purchase.py index e2dbee60..6189e937 100644 --- a/assets/src/ba_data/python/bastd/ui/purchase.py +++ b/assets/src/ba_data/python/bastd/ui/purchase.py @@ -48,12 +48,14 @@ class PurchaseWindow(ba.Window): self._items = list(items) self._width = 580 self._height = 520 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, toolbar_visibility='menu_currency', - scale=(1.2 if ba.app.small_ui else 1.1 if ba.app.med_ui else 1.0), - stack_offset=(0, -15) if ba.app.small_ui else (0, 0))) + scale=(1.2 if uiscale is ba.UIScale.SMALL else + 1.1 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -15) if uiscale is ba.UIScale.SMALL else (0, 0))) self._is_double = False self._title_text = ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, diff --git a/assets/src/ba_data/python/bastd/ui/qrcode.py b/assets/src/ba_data/python/bastd/ui/qrcode.py index c695103a..fbe234a1 100644 --- a/assets/src/ba_data/python/bastd/ui/qrcode.py +++ b/assets/src/ba_data/python/bastd/ui/qrcode.py @@ -31,7 +31,9 @@ class QRCodeWindow(popup.PopupWindow): def __init__(self, origin_widget: ba.Widget, qr_tex: ba.Texture): position = origin_widget.get_screen_space_center() - scale = (2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + uiscale = ba.app.uiscale + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 450 self._height = 400 diff --git a/assets/src/ba_data/python/bastd/ui/report.py b/assets/src/ba_data/python/bastd/ui/report.py index a649b627..afe54852 100644 --- a/assets/src/ba_data/python/bastd/ui/report.py +++ b/assets/src/ba_data/python/bastd/ui/report.py @@ -37,13 +37,14 @@ class ReportPlayerWindow(ba.Window): scale_origin = origin_widget.get_screen_space_center() overlay_stack = _ba.get_special_widget('overlay_stack') + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), parent=overlay_stack, transition='in_scale', scale_origin_stack_offset=scale_origin, - scale=( - 1.8 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0))) + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._cancel_button = ba.buttonwidget(parent=self._root_widget, scale=0.7, position=(40, self._height - 50), diff --git a/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py index eed95a9f..7b3d3cf3 100644 --- a/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py +++ b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py @@ -30,7 +30,9 @@ class ResourceTypeInfoWindow(popup.PopupWindow): """Popup window providing info about resource types.""" def __init__(self, origin_widget: ba.Widget): - scale = (2.3 if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + uiscale = ba.app.uiscale + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 570 self._height = 350 diff --git a/assets/src/ba_data/python/bastd/ui/serverdialog.py b/assets/src/ba_data/python/bastd/ui/serverdialog.py index f8fc48a0..8cdf820d 100644 --- a/assets/src/ba_data/python/bastd/ui/serverdialog.py +++ b/assets/src/ba_data/python/bastd/ui/serverdialog.py @@ -44,10 +44,12 @@ class ServerDialogWindow(ba.Window): txt_scale) self._width = 500 self._height = 130 + min(200, txt_height) + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', - scale=1.8 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0)) + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._starttime = ba.time(ba.TimeType.REAL, ba.TimeFormat.MILLISECONDS) ba.playsound(ba.getsound('swish')) diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index f9205206..dffa1274 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -53,20 +53,22 @@ class AdvancedSettingsWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - self._width = 870.0 if app.small_ui else 670.0 - x_inset = 100 if app.small_ui else 0 - self._height = (390.0 - if app.small_ui else 450.0 if app.med_ui else 520.0) + uiscale = ba.app.uiscale + self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (390.0 if uiscale is ba.UIScale.SMALL else + 450.0 if uiscale is ba.UIScale.MEDIUM else 520.0) self._spacing = 32 self._menu_open = False - top_extra = 10 if app.small_ui else 0 + top_extra = 10 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + top_extra), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=2.06 if app.small_ui else 1.4 if app.med_ui else 1.0, - stack_offset=(0, -25) if app.small_ui else (0, 0))) + scale=(2.06 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -25) if uiscale is ba.UIScale.SMALL else (0, 0))) self._prev_lang = '' self._prev_lang_list: List[str] = [] self._complete_langs_list: Optional[List] = None @@ -96,7 +98,7 @@ class AdvancedSettingsWindow(ba.Window): self._r = 'settingsWindowAdvanced' - if app.toolbars and app.small_ui: + if app.toolbars and uiscale is ba.UIScale.SMALL: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._do_back) self._back_button = None diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index cd7686c9..702e3e0a 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -54,23 +54,25 @@ class AllSettingsWindow(ba.Window): else: self._transition_out = 'out_right' scale_origin = None - width = 900 if ba.app.small_ui else 580 - x_inset = 75 if ba.app.small_ui else 0 + uiscale = ba.app.uiscale + width = 900 if uiscale is ba.UIScale.SMALL else 580 + x_inset = 75 if uiscale is ba.UIScale.SMALL else 0 height = 435 # button_height = 42 self._r = 'settingsWindow' - top_extra = 20 if ba.app.small_ui else 0 + top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=( - 1.75 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0), - stack_offset=(0, -8) if ba.app.small_ui else (0, 0))) + scale=(1.75 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -8) if uiscale is ba.UIScale.SMALL else (0, 0))) - if ba.app.toolbars and ba.app.small_ui: + if ba.app.toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._do_back) @@ -105,10 +107,10 @@ class AllSettingsWindow(ba.Window): v = height - 80 v -= 145 - basew = 280 if ba.app.small_ui else 230 + basew = 280 if uiscale is ba.UIScale.SMALL else 230 baseh = 170 - x_offs = x_inset + (105 - if ba.app.small_ui else 72) - basew # now unused + x_offs = x_inset + (105 if uiscale is ba.UIScale.SMALL else + 72) - basew # now unused x_offs2 = x_offs + basew - 7 x_offs3 = x_offs + 2 * (basew - 7) x_offs4 = x_offs2 diff --git a/assets/src/ba_data/python/bastd/ui/settings/audio.py b/assets/src/ba_data/python/bastd/ui/settings/audio.py index 02c6b25d..c7e8d970 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/audio.py +++ b/assets/src/ba_data/python/bastd/ui/settings/audio.py @@ -74,8 +74,9 @@ class AudioSettingsWindow(ba.Window): show_soundtracks = True height += spacing * 2.0 - base_scale = (2.05 - if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.0) + uiscale = ba.app.uiscale + base_scale = (2.05 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0) popup_menu_scale = base_scale * 1.2 super().__init__(root_widget=ba.containerwidget( @@ -83,7 +84,7 @@ class AudioSettingsWindow(ba.Window): transition=transition, scale=base_scale, scale_origin_stack_offset=scale_origin, - stack_offset=(0, -20) if ba.app.small_ui else (0, 0))) + stack_offset=(0, -20) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = back_button = btn = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index c90d11ff..283be4d3 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -144,12 +144,14 @@ class ControlsSettingsWindow(ba.Window): if show_xinput_toggle: height += spacing + uiscale = ba.app.uiscale + smallscale = (1.7 if show_keyboard else 2.2) super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, scale_origin_stack_offset=scale_origin, - scale=(1.7 if show_keyboard else 2.2 - ) if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0)) + scale=(smallscale if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, position=(35, height - 60), diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index 406bee3d..e27ba546 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -60,11 +60,12 @@ class GamepadSettingsWindow(ba.Window): self._width = 700 if self._is_secondary else 730 self._height = 440 if self._is_secondary else 450 self._spacing = 40 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), - scale=( - 1.63 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0), - stack_offset=(-20, -16) if ba.app.small_ui else (0, 0), + scale=(1.63 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(-20, -16) if uiscale is ba.UIScale.SMALL else (0, 0), transition=transition)) # Don't ask to config joysticks while we're in here. @@ -782,10 +783,12 @@ class AwaitGamepadInputWindow(ba.Window): self._capture_button = button width = 400 height = 150 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( - scale=2.0 if ba.app.small_ui else 1.9 if ba.app.med_ui else 1.0, + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.9 if uiscale is ba.UIScale.MEDIUM else 1.0), size=(width, height), - transition='in_scale')) + transition='in_scale'), ) ba.textwidget(parent=self._root_widget, position=(0, (height - 60) if message2 is None else (height - 50)), diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py index 1b12cdfd..d4631aed 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py @@ -41,22 +41,23 @@ class GamepadAdvancedSettingsWindow(ba.Window): app = ba.app self._r = parent_window.get_r() - self._width = 900 if ba.app.small_ui else 700 - self._x_inset = x_inset = 100 if ba.app.small_ui else 0 - self._height = 402 if ba.app.small_ui else 512 + uiscale = ba.app.uiscale + self._width = 900 if uiscale is ba.UIScale.SMALL else 700 + self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = 402 if uiscale is ba.UIScale.SMALL else 512 self._textwidgets: Dict[str, ba.Widget] = {} super().__init__(root_widget=ba.containerwidget( transition='in_scale', size=(self._width, self._height), - scale=1.06 * - (1.85 if ba.app.small_ui else 1.35 if ba.app.med_ui else 1.0), - stack_offset=(0, -25) if ba.app.small_ui else (0, 0), + scale=1.06 * (1.85 if uiscale is ba.UIScale.SMALL else + 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -25) if uiscale is ba.UIScale.SMALL else (0, 0), scale_origin_stack_offset=(parent_window.get_advanced_button(). get_screen_space_center()))) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - - (40 if ba.app.small_ui else 34)), + (40 if uiscale is ba.UIScale.SMALL else 34)), size=(0, 0), text=ba.Lstr(resource=self._r + '.advancedTitleText'), maxwidth=320, @@ -67,8 +68,8 @@ class GamepadAdvancedSettingsWindow(ba.Window): back_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, - position=(self._width - (176 + x_inset), - self._height - (60 if ba.app.small_ui else 55)), + position=(self._width - (176 + x_inset), self._height - + (60 if uiscale is ba.UIScale.SMALL else 55)), size=(120, 48), text_scale=0.8, label=ba.Lstr(resource='doneText'), diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py index daccdabf..9b063425 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py @@ -55,8 +55,10 @@ def gamepad_configure_callback(event: Dict[str, Any]) -> None: width = 700 height = 200 button_width = 100 + uiscale = ba.app.uiscale ba.app.main_menu_window = dlg = (ba.containerwidget( - scale=1.7 if ba.app.small_ui else 1.4 if ba.app.med_ui else 1.0, + scale=(1.7 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), size=(width, height), transition='in_right')) device_name = inputdevice.name @@ -97,10 +99,13 @@ class GamepadSelectWindow(ba.Window): spacing = 40 self._r = 'configGamepadSelectWindow' + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( - scale=2.3 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0, + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), size=(width, height), - transition='in_right')) + transition='in_right', + )) btn = ba.buttonwidget(parent=self._root_widget, position=(20, height - 60), diff --git a/assets/src/ba_data/python/bastd/ui/settings/graphics.py b/assets/src/ba_data/python/bastd/ui/settings/graphics.py index 6fe5477e..411b21a6 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/graphics.py +++ b/assets/src/ba_data/python/bastd/ui/settings/graphics.py @@ -57,14 +57,14 @@ class GraphicsSettingsWindow(ba.Window): spacing = 32 self._have_selected_child = False - interface_type = app.interface_type + uiscale = app.uiscale width = 450.0 height = 302.0 self._show_fullscreen = False fullscreen_spacing_top = spacing * 0.2 fullscreen_spacing = spacing * 1.2 - if interface_type == 'large' and app.platform != 'android': + if uiscale == ba.UIScale.LARGE and app.platform != 'android': self._show_fullscreen = True height += fullscreen_spacing + fullscreen_spacing_top @@ -83,8 +83,9 @@ class GraphicsSettingsWindow(ba.Window): show_resolution = (app.platform == 'android' and app.subplatform == 'cardboard') - base_scale = (2.4 - if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0) + uiscale = ba.app.uiscale + base_scale = (2.4 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) popup_menu_scale = base_scale * 1.2 v = height - 50 v -= spacing * 1.15 @@ -93,7 +94,7 @@ class GraphicsSettingsWindow(ba.Window): transition=transition, scale_origin_stack_offset=scale_origin, scale=base_scale, - stack_offset=(0, -30) if ba.app.small_ui else (0, 0))) + stack_offset=(0, -30) if uiscale is ba.UIScale.SMALL else (0, 0))) btn = ba.buttonwidget(parent=self._root_widget, position=(35, height - 50), diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index 407b4d56..61f02ae2 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -45,14 +45,16 @@ class ConfigKeyboardWindow(ba.Window): self._displayname = ba.Lstr(translate=('inputDeviceNames', dname_raw)) self._width = 700 if self._unique_id != '#1': - self._height = 450 + self._height = 480 else: - self._height = 345 + self._height = 375 self._spacing = 40 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), - scale=(1.6 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0), - stack_offset=(0, -10) if ba.app.small_ui else (0, 0), + scale=(1.6 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0), transition=transition)) self._rebuild_ui() @@ -73,7 +75,7 @@ class ConfigKeyboardWindow(ba.Window): cancel_button = ba.buttonwidget(parent=self._root_widget, autoselect=True, - position=(38, self._height - 65), + position=(38, self._height - 85), size=(170, 60), label=ba.Lstr(resource='cancelText'), scale=0.9, @@ -81,9 +83,9 @@ class ConfigKeyboardWindow(ba.Window): save_button = ba.buttonwidget(parent=self._root_widget, autoselect=True, position=(self._width - 190, - self._height - 65), + self._height - 85), size=(180, 60), - label=ba.Lstr(resource='makeItSoText'), + label=ba.Lstr(resource='saveText'), scale=0.9, text_scale=0.9, on_activate_call=self._save) @@ -94,7 +96,7 @@ class ConfigKeyboardWindow(ba.Window): ba.widget(edit=cancel_button, right_widget=save_button) ba.widget(edit=save_button, left_widget=cancel_button) - v = self._height - 54.0 + v = self._height - 74.0 ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, v + 15), size=(0, 0), @@ -270,10 +272,12 @@ class AwaitKeyboardInputWindow(ba.Window): width = 400 height = 150 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', - scale=2.0 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0)) + scale=(2.0 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0))) ba.textwidget(parent=self._root_widget, position=(0, height - 60), size=(width, 25), diff --git a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py index cc28369d..3598a39a 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py @@ -34,10 +34,12 @@ class PS3ControllerSettingsWindow(ba.Window): height = 330 if _ba.is_running_on_fire_tv() else 540 spacing = 40 self._r = 'ps3ControllersWindow' + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', - scale=1.35 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0)) + scale=(1.35 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0))) btn = ba.buttonwidget(parent=self._root_widget, position=(37, height - 73), diff --git a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py index 0db78e6e..d47f54fb 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py +++ b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py @@ -34,11 +34,13 @@ class RemoteAppSettingsWindow(ba.Window): width = 700 height = 390 spacing = 40 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', - scale=(1.85 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0), - stack_offset=(-10, 0) if ba.app.small_ui else (0, 0))) + scale=(1.85 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(-10, 0) if uiscale is ba.UIScale.SMALL else (0, 0))) btn = ba.buttonwidget(parent=self._root_widget, position=(40, height - 67), size=(140, 65), diff --git a/assets/src/ba_data/python/bastd/ui/settings/testing.py b/assets/src/ba_data/python/bastd/ui/settings/testing.py index be3c17df..63ca41d8 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/testing.py +++ b/assets/src/ba_data/python/bastd/ui/settings/testing.py @@ -39,14 +39,16 @@ class TestingWindow(ba.Window): title: ba.Lstr, entries: List[Dict[str, Any]], transition: str = 'in_right'): + uiscale = ba.app.uiscale self._width = 600 - self._height = 324 if ba.app.small_ui else 400 + self._height = 324 if uiscale is ba.UIScale.SMALL else 400 self._entries = copy.deepcopy(entries) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, - scale=(2.5 if ba.app.small_ui else 1.2 if ba.app.med_ui else 1.0), - stack_offset=(0, -28) if ba.app.small_ui else (0, 0))) + scale=(2.5 if uiscale is ba.UIScale.SMALL else + 1.2 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -28) if uiscale is ba.UIScale.SMALL else (0, 0))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, autoselect=True, diff --git a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py index 7dbc3d80..59faf44b 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py +++ b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py @@ -45,10 +45,12 @@ class TouchscreenSettingsWindow(ba.Window): _ba.set_touchscreen_editing(True) + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_right', - scale=1.9 if ba.app.small_ui else 1.55 if ba.app.med_ui else 1.2)) + scale=(1.9 if uiscale is ba.UIScale.SMALL else + 1.55 if uiscale is ba.UIScale.MEDIUM else 1.2))) btn = ba.buttonwidget(parent=self._root_widget, position=(55, self._height - 60), diff --git a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py index ac771431..b65b48ec 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py @@ -39,10 +39,12 @@ class XBox360ControllerSettingsWindow(ba.Window): width = 700 height = 300 if _ba.is_running_on_fire_tv() else 485 spacing = 40 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', - scale=1.4 if ba.app.small_ui else 1.4 if ba.app.med_ui else 1.0)) + scale=(1.4 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0))) btn = ba.buttonwidget(parent=self._root_widget, position=(35, height - 65), diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py index b727122b..a796229b 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py @@ -38,6 +38,7 @@ class SoundtrackBrowserWindow(ba.Window): def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): + # pylint: disable=too-many-locals # pylint: disable=too-many-statements # If they provided an origin-widget, scale up from that. @@ -51,10 +52,11 @@ class SoundtrackBrowserWindow(ba.Window): scale_origin = None self._r = 'editSoundtrackWindow' - self._width = 800 if ba.app.small_ui else 600 - x_inset = 100 if ba.app.small_ui else 0 - self._height = (340 - if ba.app.small_ui else 370 if ba.app.med_ui else 440) + uiscale = ba.app.uiscale + self._width = 800 if uiscale is ba.UIScale.SMALL else 600 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (340 if uiscale is ba.UIScale.SMALL else + 370 if uiscale is ba.UIScale.MEDIUM else 440) spacing = 40.0 v = self._height - 40.0 v -= spacing * 1.0 @@ -64,10 +66,11 @@ class SoundtrackBrowserWindow(ba.Window): transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=(2.3 if ba.app.small_ui else 1.6 if ba.app.med_ui else 1.0), - stack_offset=(0, -18) if ba.app.small_ui else (0, 0))) + scale=(2.3 if uiscale is ba.UIScale.SMALL else + 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -18) if uiscale is ba.UIScale.SMALL else (0, 0))) - if ba.app.toolbars and ba.app.small_ui: + if ba.app.toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None else: self._back_button = ba.buttonwidget( @@ -98,7 +101,8 @@ class SoundtrackBrowserWindow(ba.Window): lock_tex = ba.gettexture('lock') self._lock_images: List[ba.Widget] = [] - scl = (1.0 if ba.app.small_ui else 1.13 if ba.app.med_ui else 1.4) + scl = (1.0 if uiscale is ba.UIScale.SMALL else + 1.13 if uiscale is ba.UIScale.MEDIUM else 1.4) v -= 60.0 * scl self._new_button = btn = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py index 0895cb83..484757ff 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py @@ -43,16 +43,18 @@ class SoundtrackEditWindow(ba.Window): self._r = 'editSoundtrackWindow' self._folder_tex = ba.gettexture('folder') self._file_tex = ba.gettexture('file') - self._width = 848 if ba.app.small_ui else 648 - x_inset = 100 if ba.app.small_ui else 0 - self._height = (395 - if ba.app.small_ui else 450 if ba.app.med_ui else 560) + uiscale = ba.app.uiscale + self._width = 848 if uiscale is ba.UIScale.SMALL else 648 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (395 if uiscale is ba.UIScale.SMALL else + 450 if uiscale is ba.UIScale.MEDIUM else 560) super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, - scale=(2.08 if ba.app.small_ui else 1.5 if ba.app.med_ui else 1.0), - stack_offset=(0, -48) if ba.app.small_ui else ( - 0, 15) if ba.app.med_ui else (0, 0))) + scale=(2.08 if uiscale is ba.UIScale.SMALL else + 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -48) if uiscale is ba.UIScale.SMALL else ( + 0, 15) if uiscale is ba.UIScale.MEDIUM else (0, 0))) cancel_button = ba.buttonwidget(parent=self._root_widget, position=(38 + x_inset, self._height - 60), diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py index 22304ea8..b1652672 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @@ -64,10 +64,12 @@ class SoundtrackEntryTypeSelectWindow(ba.Window): if do_music_folder: self._height += spacing + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, - scale=1.7 if ba.app.small_ui else 1.4 if ba.app.med_ui else 1.0)) + scale=(1.7 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0))) btn = ba.buttonwidget(parent=self._root_widget, position=(35, self._height - 65), size=(160, 60), diff --git a/assets/src/ba_data/python/bastd/ui/specialoffer.py b/assets/src/ba_data/python/bastd/ui/specialoffer.py index 80c6bf20..8d7d2764 100644 --- a/assets/src/ba_data/python/bastd/ui/specialoffer.py +++ b/assets/src/ba_data/python/bastd/ui/specialoffer.py @@ -91,11 +91,13 @@ class SpecialOfferWindow(ba.Window): self._offer = copy.deepcopy(offer) self._width = 580 self._height = 590 + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, - scale=(1.2 if ba.app.small_ui else 1.15 if ba.app.med_ui else 1.0), - stack_offset=(0, -15) if ba.app.small_ui else (0, 0))) + scale=(1.2 if uiscale is ba.UIScale.SMALL else + 1.15 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -15) if uiscale is ba.UIScale.SMALL else (0, 0))) self._is_bundle_sale = False try: if offer['item'] in ['pro', 'pro_fullprice']: diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index d8677e7b..1bf05030 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -39,9 +39,10 @@ class StoreBrowserWindow(ba.Window): """Window for browsing the store.""" def _update_get_tickets_button_pos(self) -> None: + uiscale = ba.app.uiscale if self._get_tickets_button: pos = (self._width - 252 - - (self._x_inset + (47 if ba.app.small_ui + (self._x_inset + (47 if uiscale is ba.UIScale.SMALL and _ba.is_party_icon_visible() else 0)), self._height - 70) ba.buttonwidget(edit=self._get_tickets_button, position=pos) @@ -59,6 +60,7 @@ class StoreBrowserWindow(ba.Window): from ba import SpecialChar app = ba.app + uiscale = app.uiscale ba.set_analytics_screen('Store Window') @@ -81,11 +83,12 @@ class StoreBrowserWindow(ba.Window): self._on_close_call = on_close_call self._show_tab = show_tab self._modal = modal - self._width = 1240 if app.small_ui else 1040 - self._x_inset = x_inset = 100 if app.small_ui else 0 - self._height = (578 if app.small_ui else 645 if app.med_ui else 800) + self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (578 if uiscale is ba.UIScale.SMALL else + 645 if uiscale is ba.UIScale.MEDIUM else 800) self._current_tab: Optional[str] = None - extra_top = 30 if app.small_ui else 0 + extra_top = 30 if uiscale is ba.UIScale.SMALL else 0 self._request: Any = None self._r = 'store' @@ -95,12 +98,11 @@ class StoreBrowserWindow(ba.Window): size=(self._width, self._height + extra_top), transition=transition, toolbar_visibility='menu_full', - scale=1.3 if app.small_ui else 0.9 if app.med_ui else 0.8, + scale=(1.3 if uiscale is ba.UIScale.SMALL else + 0.9 if uiscale is ba.UIScale.MEDIUM else 0.8), scale_origin_stack_offset=scale_origin, - stack_offset=(0, - -5) if app.small_ui else (0, - 0) if app.med_ui else (0, - 0))) + stack_offset=((0, -5) if uiscale is ba.UIScale.SMALL else ( + 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0)))) self._back_button = btn = ba.buttonwidget( parent=self._root_widget, @@ -718,6 +720,8 @@ class StoreBrowserWindow(ba.Window): self._sections = copy.deepcopy(store_data[sdata['tab']]) self._height: Optional[float] = None + uiscale = ba.app.uiscale + # Pre-calc a few things and add them to store-data. for section in self._sections: if self._tab == 'characters': @@ -739,8 +743,9 @@ class StoreBrowserWindow(ba.Window): section['x_offs'] = (130 if self._tab == 'extras' else 270 if self._tab == 'maps' else 0) section['y_offs'] = ( - 55 if (self._tab == 'extras' and ba.app.small_ui) - else -20 if self._tab == 'icons' else 0) + 55 if (self._tab == 'extras' + and uiscale is ba.UIScale.SMALL) else + -20 if self._tab == 'icons' else 0) def instantiate(self, scrollwidget: ba.Widget, tab_button: ba.Widget) -> None: diff --git a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py index 543dce62..a49725f3 100644 --- a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py +++ b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py @@ -43,7 +43,9 @@ class TeamNamesColorsWindow(popup.PopupWindow): self._max_name_length = 16 # Creates our _root_widget. - scale = (1.69 if ba.app.small_ui else 1.1 if ba.app.med_ui else 0.85) + uiscale = ba.app.uiscale + scale = (1.69 if uiscale is ba.UIScale.SMALL else + 1.1 if uiscale is ba.UIScale.MEDIUM else 0.85) super().__init__(position=scale_origin, size=(self._width, self._height), scale=scale) diff --git a/assets/src/ba_data/python/bastd/ui/telnet.py b/assets/src/ba_data/python/bastd/ui/telnet.py index 2d412947..4b7f2737 100644 --- a/assets/src/ba_data/python/bastd/ui/telnet.py +++ b/assets/src/ba_data/python/bastd/ui/telnet.py @@ -34,10 +34,12 @@ class TelnetAccessRequestWindow(ba.Window): height = 100 text = ba.Lstr(resource='telnetAccessText') + uiscale = ba.app.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height + 40), transition='in_right', - scale=1.7 if ba.app.small_ui else 1.3 if ba.app.med_ui else 1.0)) + scale=(1.7 if uiscale is ba.UIScale.SMALL else + 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0))) padding = 20 ba.textwidget(parent=self._root_widget, position=(padding, padding + 33), diff --git a/assets/src/ba_data/python/bastd/ui/tournamententry.py b/assets/src/ba_data/python/bastd/ui/tournamententry.py index 3fe494a9..49ba780e 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamententry.py +++ b/assets/src/ba_data/python/bastd/ui/tournamententry.py @@ -43,8 +43,9 @@ class TournamentEntryWindow(popup.PopupWindow): scale: float = None, offset: Tuple[float, float] = (0.0, 0.0), on_close_call: Callable[[], Any] = None): - # needs some tidying + # Needs some tidying. # pylint: disable=too-many-branches + # pylint: disable=too-many-locals # pylint: disable=too-many-statements ba.set_analytics_screen('Tournament Entry Window') @@ -77,8 +78,9 @@ class TournamentEntryWindow(popup.PopupWindow): self._on_close_call = on_close_call if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + uiscale = ba.app.uiscale + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._delegate = delegate self._transitioning_out = False diff --git a/assets/src/ba_data/python/bastd/ui/tournamentscores.py b/assets/src/ba_data/python/bastd/ui/tournamentscores.py index e4e6f622..fc34f17a 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamentscores.py +++ b/assets/src/ba_data/python/bastd/ui/tournamentscores.py @@ -53,14 +53,15 @@ class TournamentScoresWindow(popup_ui.PopupWindow): self._tournament_id = tournament_id self._subcontainer: Optional[ba.Widget] = None self._on_close_call = on_close_call + uiscale = ba.app.uiscale if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 400 - self._height = (300 - if ba.app.small_ui else 370 if ba.app.med_ui else 450) + self._height = (300 if uiscale is ba.UIScale.SMALL else + 370 if uiscale is ba.UIScale.MEDIUM else 450) bg_color = (0.5, 0.4, 0.6) diff --git a/assets/src/ba_data/python/bastd/ui/trophies.py b/assets/src/ba_data/python/bastd/ui/trophies.py index 1bdfcea0..4009fc28 100644 --- a/assets/src/ba_data/python/bastd/ui/trophies.py +++ b/assets/src/ba_data/python/bastd/ui/trophies.py @@ -40,9 +40,10 @@ class TrophiesWindow(popup.PopupWindow): scale: float = None): from ba.deprecated import get_resource self._data = data + uiscale = ba.app.uiscale if scale is None: - scale = (2.3 - if ba.app.small_ui else 1.65 if ba.app.med_ui else 1.23) + scale = (2.3 if uiscale is ba.UIScale.SMALL else + 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False self._width = 300 self._height = 300 diff --git a/assets/src/ba_data/python/bastd/ui/url.py b/assets/src/ba_data/python/bastd/ui/url.py index 3f287dcc..510513fc 100644 --- a/assets/src/ba_data/python/bastd/ui/url.py +++ b/assets/src/ba_data/python/bastd/ui/url.py @@ -34,14 +34,15 @@ class ShowURLWindow(ba.Window): # in some cases we might want to show it as a qr code # (for long URLs especially) app = ba.app + uiscale = app.uiscale if app.platform == 'android' and app.subplatform == 'alibaba': self._width = 500 self._height = 500 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_right', - scale=(1.25 if ba.app.small_ui else 1.25 if ba.app. - med_ui else 1.25))) + scale=(1.25 if uiscale is ba.UIScale.SMALL else + 1.25 if uiscale is ba.UIScale.MEDIUM else 1.25))) self._cancel_button = ba.buttonwidget( parent=self._root_widget, position=(50, self._height - 30), @@ -68,8 +69,8 @@ class ShowURLWindow(ba.Window): self._root_widget = ba.containerwidget( size=(self._width, self._height + 40), transition='in_right', - scale=1.25 - if ba.app.small_ui else 1.25 if ba.app.med_ui else 1.25) + scale=(1.25 if uiscale is ba.UIScale.SMALL else + 1.25 if uiscale is ba.UIScale.MEDIUM else 1.25)) ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 10), size=(0, 0), diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py index f739c1ff..4cb1c0e6 100644 --- a/assets/src/ba_data/python/bastd/ui/watch.py +++ b/assets/src/ba_data/python/bastd/ui/watch.py @@ -60,23 +60,25 @@ class WatchWindow(ba.Window): self._my_replays_rename_window: Optional[ba.Widget] = None self._my_replay_rename_text: Optional[ba.Widget] = None self._r = 'watchWindow' - self._width = 1240 if ba.app.small_ui else 1040 - x_inset = 100 if ba.app.small_ui else 0 - self._height = (578 - if ba.app.small_ui else 670 if ba.app.med_ui else 800) + uiscale = ba.app.uiscale + self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (578 if uiscale is ba.UIScale.SMALL else + 670 if uiscale is ba.UIScale.MEDIUM else 800) self._current_tab: Optional[str] = None - extra_top = 20 if ba.app.small_ui else 0 + extra_top = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height + extra_top), transition=transition, toolbar_visibility='menu_minimal', scale_origin_stack_offset=scale_origin, - scale=(1.3 if ba.app.small_ui else 0.97 if ba.app.med_ui else 0.8), - stack_offset=(0, -10) if ba.app.small_ui else ( - 0, 15) if ba.app.med_ui else (0, 0))) + scale=(1.3 if uiscale is ba.UIScale.SMALL else + 0.97 if uiscale is ba.UIScale.MEDIUM else 0.8), + stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( + 0, 15) if uiscale is ba.UIScale.MEDIUM else (0, 0))) - if ba.app.small_ui and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) self._back_button = None @@ -122,7 +124,7 @@ class WatchWindow(ba.Window): if ba.app.toolbars: ba.widget(edit=self._tab_buttons[tabs_def[-1][0]], right_widget=_ba.get_special_widget('party_button')) - if ba.app.small_ui: + if uiscale is ba.UIScale.SMALL: bbtn = _ba.get_special_widget('back_button') ba.widget(edit=self._tab_buttons[tabs_def[0][0]], up_widget=bbtn, @@ -172,12 +174,13 @@ class WatchWindow(ba.Window): # switching to a different tab self._tab_data = {} + uiscale = ba.app.uiscale if tab == 'my_replays': c_width = self._scroll_width c_height = self._scroll_height - 20 sub_scroll_height = c_height - 63 self._my_replays_scroll_width = sub_scroll_width = ( - 680 if ba.app.small_ui else 640) + 680 if uiscale is ba.UIScale.SMALL else 640) self._tab_container = cnt = ba.containerwidget( parent=self._root_widget, @@ -202,19 +205,20 @@ class WatchWindow(ba.Window): ba.Lstr(resource='replayNameDefaultText')) ])) - b_width = 140 if ba.app.small_ui else 178 - b_height = (107 - if ba.app.small_ui else 142 if ba.app.med_ui else 190) - b_space_extra = (0 if ba.app.small_ui else - -2 if ba.app.med_ui else -5) + b_width = 140 if uiscale is ba.UIScale.SMALL else 178 + b_height = (107 if uiscale is ba.UIScale.SMALL else + 142 if uiscale is ba.UIScale.MEDIUM else 190) + b_space_extra = (0 if uiscale is ba.UIScale.SMALL else + -2 if uiscale is ba.UIScale.MEDIUM else -5) b_color = (0.6, 0.53, 0.63) b_textcolor = (0.75, 0.7, 0.8) - btnv = c_height - (48 if ba.app.small_ui else - 45 if ba.app.med_ui else 40) - b_height - btnh = 40 if ba.app.small_ui else 40 - smlh = 190 if ba.app.small_ui else 225 - tscl = 1.0 if ba.app.small_ui else 1.2 + btnv = (c_height - (48 if uiscale is ba.UIScale.SMALL else + 45 if uiscale is ba.UIScale.MEDIUM else 40) - + b_height) + btnh = 40 if uiscale is ba.UIScale.SMALL else 40 + smlh = 190 if uiscale is ba.UIScale.SMALL else 225 + tscl = 1.0 if uiscale is ba.UIScale.SMALL else 1.2 self._my_replays_watch_replay_button = btn1 = ba.buttonwidget( parent=cnt, size=(b_width, b_height), @@ -227,7 +231,7 @@ class WatchWindow(ba.Window): label=ba.Lstr(resource=self._r + '.watchReplayButtonText'), autoselect=True) ba.widget(edit=btn1, up_widget=self._tab_buttons[tab]) - if ba.app.small_ui and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.toolbars: ba.widget(edit=btn1, left_widget=_ba.get_special_widget('back_button')) btnv -= b_height + b_space_extra @@ -309,8 +313,10 @@ class WatchWindow(ba.Window): return c_width = 600 c_height = 250 + uiscale = ba.app.uiscale self._my_replays_rename_window = cnt = ba.containerwidget( - scale=1.8 if ba.app.small_ui else 1.55 if ba.app.med_ui else 1.0, + scale=(1.8 if uiscale is ba.UIScale.SMALL else + 1.55 if uiscale is ba.UIScale.MEDIUM else 1.0), size=(c_width, c_height), transition='in_scale') dname = self._get_replay_display_name(self._my_replay_selected) diff --git a/docs/ba_module.md b/docs/ba_module.md index e25260c5..20d09043 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-11 for Ballistica version 1.5.20 build 20132

    +

    last updated on 2020-07-12 for Ballistica version 1.5.20 build 20133

    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!


    @@ -191,6 +191,7 @@
  • ba.SpecialChar
  • ba.TimeFormat
  • ba.TimeType
  • +
  • ba.UIScale
  • Exception Classes

      @@ -805,7 +806,7 @@ likely result in errors.

      Attributes:

      -
      api_version, build_number, config, config_file_path, debug_build, interface_type, language, locale, on_tv, platform, python_directory_app, python_directory_app_site, python_directory_user, subplatform, test_build, ui_bounds, user_agent_string, version, vr_mode
      +
      api_version, build_number, config, config_file_path, debug_build, language, locale, on_tv, platform, python_directory_app, python_directory_app_site, python_directory_user, subplatform, test_build, ui_bounds, uiscale, user_agent_string, version, vr_mode

      api_version

      int

      @@ -844,18 +845,6 @@ likely result in errors.

      builds due to compiler optimizations being disabled and extra checks being run.

      -
      -

      interface_type

      -

      str

      -

      Interface mode the game is in; can be 'large', 'medium', or 'small'.

      - -

      'large' is used by system such as desktop PC where elements on screen - remain usable even at small sizes, allowing more to be shown. - 'small' is used by small devices such as phones, where elements on - screen must be larger to remain readable and usable. - 'medium' is used by tablets and other middle-of-the-road situations - such as VR or TV.

      -

      language

      str

      @@ -923,6 +912,11 @@ likely result in errors.

      This tuple contains: (x-min, x-max, y-min, y-max)

      +
      +

      uiscale

      +

      ba.UIScale

      +

      Current ui scale for the app.

      +

      user_agent_string

      str

      @@ -5658,6 +5652,35 @@ self.t = ba.Timer(0.3, say_it, repeat=True)

      +

      ba.UIScale

      +

      Inherits from: enum.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.

      + +

      Category: Enums

      + +

      '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. +

      + +

      Values:

      +
        +
      • LARGE
      • +
      • MEDIUM
      • +
      • SMALL
      • +
      +

      ba.Vec3

      <top level class>

      From 8f53e03cdb7a899bc84d3f7845d5bd3b40205aa7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 12 Jul 2020 19:15:18 -0700 Subject: [PATCH 143/417] Removing a few inactive UI elements on mac build --- .../python/bastd/ui/settings/controls.py | 18 +++++++++--------- .../python/bastd/ui/settings/keyboard.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index 283be4d3..a59e39ba 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -59,7 +59,7 @@ class ControlsSettingsWindow(ba.Window): self._r = 'configControllersWindow' app = ba.app - is_fire_tv = _ba.is_running_on_fire_tv() + # is_fire_tv = _ba.is_running_on_fire_tv() spacing = 50.0 button_width = 350.0 @@ -110,17 +110,17 @@ class ControlsSettingsWindow(ba.Window): show_remote = False show_ps3 = False - if platform == 'mac': - show_ps3 = True - height += spacing + # if platform == 'mac': + # show_ps3 = True + # height += spacing show360 = False - if platform == 'mac' or is_fire_tv: - show360 = True - height += spacing + # if platform == 'mac' or is_fire_tv: + # show360 = True + # height += spacing show_mac_wiimote = False - if platform == 'mac': + if platform == 'mac' and subplatform == 'appstore': show_mac_wiimote = True height += spacing @@ -135,7 +135,7 @@ class ControlsSettingsWindow(ba.Window): # (we can run into problems where devices register as one of each # type otherwise).. show_mac_controller_subsystem = False - if platform == 'mac': + if platform == 'mac' and subplatform == 'appstore': show_mac_controller_subsystem = True if show_mac_controller_subsystem: diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index 61f02ae2..8796bc4c 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -54,7 +54,7 @@ class ConfigKeyboardWindow(ba.Window): size=(self._width, self._height), scale=(1.6 if uiscale is ba.UIScale.SMALL else 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), - stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else (0, 0), + stack_offset=(0, 5) if uiscale is ba.UIScale.SMALL else (0, 0), transition=transition)) self._rebuild_ui() @@ -123,7 +123,7 @@ class ConfigKeyboardWindow(ba.Window): color=ba.app.infotextcolor, h_align='center', v_align='top') - v -= 45 + v -= 40 v -= 10 v -= self._spacing * 2.2 v += 25 From 057717598d490a88b3b235ae15445933f79154d8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 12 Jul 2020 22:11:00 -0700 Subject: [PATCH 144/417] Moved the update_assets_makefile script into the batools package --- .../assetsmakefile.py} | 11 ++--------- tools/batools/pcommand.py | 7 +++++++ tools/pcommand | 2 +- tools/update_project | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) rename tools/{update_assets_makefile => batools/assetsmakefile.py} (98%) diff --git a/tools/update_assets_makefile b/tools/batools/assetsmakefile.py similarity index 98% rename from tools/update_assets_makefile rename to tools/batools/assetsmakefile.py index 32e2f628..0e4663fb 100755 --- a/tools/update_assets_makefile +++ b/tools/batools/assetsmakefile.py @@ -259,17 +259,14 @@ def _get_extras_targets_win(all_targets: Set[str], platform: str) -> str: return out -def main() -> None: +def update_assets_makefile(projroot: str, check: bool) -> None: """Main script entry point.""" # pylint: disable=too-many-locals from efrotools import getconfig from pathlib import Path - # In 'check' mode we simply error on differences. - check = ('--check' in sys.argv) - # Always operate out of dist root dir. - os.chdir(os.path.join(os.path.dirname(sys.argv[0]), '..')) + os.chdir(projroot) public = getconfig(Path('.'))['public'] assert isinstance(public, bool) @@ -396,7 +393,3 @@ def _write_manifest(manifest_path: str, all_targets: Set[str], print(f'{Clr.SBLU}Updating: {manifest_path}{Clr.RST}') with open(manifest_path, 'w') as outfile: outfile.write(json.dumps(manifest, indent=1)) - - -if __name__ == '__main__': - main() diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 196c31cf..9e1e519a 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -703,3 +703,10 @@ def stage_assets() -> None: except CleanError as exc: exc.pretty_print() sys.exit(1) + + +def update_assets_makefile() -> None: + """Update the assets makefile.""" + from batools.assetsmakefile import update_assets_makefile as uam + check = ('--check' in sys.argv) + uam(projroot=str(PROJROOT), check=check) diff --git a/tools/pcommand b/tools/pcommand index 6351f9c6..1e349cf6 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -55,7 +55,7 @@ from batools.pcommand import ( get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, - efro_gradle, stage_assets) + efro_gradle, stage_assets, update_assets_makefile) # pylint: enable=unused-import if TYPE_CHECKING: diff --git a/tools/update_project b/tools/update_project index 719c01f5..ef2d15c1 100755 --- a/tools/update_project +++ b/tools/update_project @@ -634,8 +634,8 @@ class App: sys.exit(255) def _update_assets_makefile(self) -> None: - assert os.path.exists('tools/update_assets_makefile') - if os.system('tools/update_assets_makefile' + self._checkarg) != 0: + if os.system(f'tools/pcommand update_assets_makefile {self._checkarg}' + ) != 0: print( f'{Clr.RED}Error checking/updating assets Makefile.f{Clr.RST}') sys.exit(255) From 9e8b739282f68d4940bd9c1a40fc61dbd712151c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 12 Jul 2020 22:30:29 -0700 Subject: [PATCH 145/417] Moved the update_project script into the batools package --- .efrocachemap | 4 ++-- Makefile | 4 ++-- tools/batools/pcommand.py | 9 +++++++++ .../updateproject.py} | 19 +++++++++---------- tools/pcommand | 2 +- 5 files changed, 23 insertions(+), 15 deletions(-) rename tools/{update_project => batools/updateproject.py} (98%) diff --git a/.efrocachemap b/.efrocachemap index aca4202a..a1972ebf 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -4145,6 +4145,6 @@ "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b9/c6/ac98c7aad5847fea5a37087d5aa0", "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4e/59/c8cbb6d6909ab853bfa61a5160ce", "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/26/cd/737e2615e116d110aac319a3e293", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/45/28/ff409cd1913fc71bf9b677b87df0", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a4/15/f823745542ea46f679552669b131" + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/94/c1/efd04026c6a251c288511ce3b037", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b4/50/b5fe4c0946537354fdc80aec5bb9" } \ No newline at end of file diff --git a/Makefile b/Makefile index 59dc4290..8e682f73 100644 --- a/Makefile +++ b/Makefile @@ -464,11 +464,11 @@ prefab-clean: # Update any project files that need it (does NOT build projects). update: prereqs - @tools/update_project + @tools/pcommand update_project # Don't update but fail if anything needs it. update-check: prereqs - @tools/update_project --check + @tools/pcommand update_project --check # Tell make which of these targets don't represent files. .PHONY: update update-check diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 9e1e519a..9a848be5 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -710,3 +710,12 @@ def update_assets_makefile() -> None: from batools.assetsmakefile import update_assets_makefile as uam check = ('--check' in sys.argv) uam(projroot=str(PROJROOT), check=check) + + +def update_project() -> None: + """Update project files.""" + from batools.updateproject import Updater + check = '--check' in sys.argv + fix = '--fix' in sys.argv + + Updater(check=check, fix=fix).run() diff --git a/tools/update_project b/tools/batools/updateproject.py similarity index 98% rename from tools/update_project rename to tools/batools/updateproject.py index ef2d15c1..d1aede13 100755 --- a/tools/update_project +++ b/tools/batools/updateproject.py @@ -63,14 +63,14 @@ class LineChange: can_auto_update: bool -class App: +class Updater: """Context for an app run.""" - def __init__(self) -> None: + def __init__(self, check: bool, fix: bool) -> None: from efrotools import getconfig, getlocalconfig from pathlib import Path - self._check = ('--check' in sys.argv) - self._fix = ('--fix' in sys.argv) + self._check = check + self._fix = fix self._checkarg = ' --check' if self._check else '' # We behave differently in the public repo @@ -239,10 +239,9 @@ class App: lines = infile.read().splitlines() line = lines[change[1].line_number] print(f'{Clr.RED} Found "{line}"{Clr.RST}') - print(Clr.RED + - f'All {len(auto_changes)} errors are auto-fixable;' - ' run tools/update_project --fix to apply corrections.' + - Clr.RST) + print(f'{Clr.RED}All {len(auto_changes)} errors are' + f' auto-fixable; run tools/pcommand update_project' + f' --fix to apply corrections. {Clr.RST}') sys.exit(255) else: for i, change in enumerate(auto_changes): @@ -665,5 +664,5 @@ class App: sys.exit(255) -if __name__ == '__main__': - App().run() +# if __name__ == '__main__': +# App().run() diff --git a/tools/pcommand b/tools/pcommand index 1e349cf6..8019c1c5 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -55,7 +55,7 @@ from batools.pcommand import ( get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, - efro_gradle, stage_assets, update_assets_makefile) + efro_gradle, stage_assets, update_assets_makefile, update_project) # pylint: enable=unused-import if TYPE_CHECKING: From 98272fff4897a78e2b79869b738c75055a3dddd2 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 12 Jul 2020 23:43:56 -0700 Subject: [PATCH 146/417] Emoji no longer draw as faded --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 1 + 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index a1972ebf..a051f2a4 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/eb/bc/4dd3903ea7c71defdfc204c6f888", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/36/19/3c6dcb2ee2cfc7f089355e9c81a1", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7b/33/ffe405cbec3b823592b8ebf06a59", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/18/8d125a287dae90ab4623a423443f", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2f/5d/f1fe725d479915bbe3d2e5f6b643", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a5/ae/f0e854f7cf68f8ffab4c3a94e403", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/0d/f8dbfe4faa05379b2330c9f91cab", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b9/c6/ac98c7aad5847fea5a37087d5aa0", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4e/59/c8cbb6d6909ab853bfa61a5160ce", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/26/cd/737e2615e116d110aac319a3e293", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/94/c1/efd04026c6a251c288511ce3b037", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b4/50/b5fe4c0946537354fdc80aec5bb9" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f9/b8/7c7c7ad64d7325b193b870aa0633", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7d/04/d5dc7d084833227fc8d7c81d2a41", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/97/c9/d427faf63f2db1c472d2d19d2858", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/5c/1800421fa3603dbeaad09cce401e", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ec/48/6c83f2b8931114c2baad1d57a77f", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9f/52/0fd3a84f69aeaaa2057edc14ead1", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/55/e5/6360133eb2e30bcba373a3c779c1", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/33/3fdb8f82a0e1523fe1e863f715d0", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/46/72/eea6a1cfcab99efdfa0decbaa701", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6a/da/845cd6692482a31508db158944b3", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e1/45/67ff8bcdf72782925bf35f871946", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bf/c2/7423609789606dc09dfee1d6b95c" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c31c523c..752efbab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Fixed a case where an early fatal error could lead to a hung app and no error dialog. - Added environment variables which can override UI scale for testing. Set BA_FORCE_UI_SCALE to small, medium or large. - Added a ba.UIScale enum. The value at ba.app.uiscale replaces the old ba.app.interface_type, ba.app.small_ui, and ba.app.med_ui values. +- Emoji no longer display in-game with a washed-out appearance. If there are any places in-game where bright colored emoji become distracing, please holler. ### 1.5.19 (20123) - Cleaned up some bomb logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by punches or bombs potentially resulting in multiple explosions when triggered by multiple other bombs simultaneously. Holler if anything explosion-related seems off now. From 9b94e8e40b0f9ac323d3569bf501a2175611635a Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 13 Jul 2020 02:20:32 -0700 Subject: [PATCH 147/417] Added account_id to get_game_roster() --- .efrocachemap | 24 ++++++++++----------- CHANGELOG.md | 3 ++- assets/src/ba_data/python/ba/_servermode.py | 2 +- assets/src/ba_data/python/bastd/ui/party.py | 2 +- docs/ba_module.md | 2 +- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index a051f2a4..6ab1c512 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/f9/b8/7c7c7ad64d7325b193b870aa0633", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7d/04/d5dc7d084833227fc8d7c81d2a41", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/97/c9/d427faf63f2db1c472d2d19d2858", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/5c/1800421fa3603dbeaad09cce401e", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ec/48/6c83f2b8931114c2baad1d57a77f", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9f/52/0fd3a84f69aeaaa2057edc14ead1", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/55/e5/6360133eb2e30bcba373a3c779c1", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/33/3fdb8f82a0e1523fe1e863f715d0", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/46/72/eea6a1cfcab99efdfa0decbaa701", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6a/da/845cd6692482a31508db158944b3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e1/45/67ff8bcdf72782925bf35f871946", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bf/c2/7423609789606dc09dfee1d6b95c" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4d/52/c1c1011ac6286950129ecfe641c2", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/46/90e28db5c4a563bda000e2df2807", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/b5/c197989dd4e61498dda75f51759c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b8/24/1da2eb6ecdbac963dc31fc258a1d", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/63/a9c21960f84b2d7f40418e66d4c8", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a2/8e/e489beaf13382d65c6c4a39e77e3", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/80/c4/4b4f75b4ae6d887f19ef2ec0f4b5", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/22/ba/e61af862b2d2c138a848583f74a6", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d5/1a/7061d9ff66993841317369cce4dd", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a4/9f/5f3308d5dda1d6f8fb3b51389e05", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bc/0f/7fd42fceaa297e0e67ed18566d3e", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9b/c7/9756a8f6ef5237f1418cabfb6154" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 752efbab..87c63ca9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,8 @@ - Fixed a case where an early fatal error could lead to a hung app and no error dialog. - Added environment variables which can override UI scale for testing. Set BA_FORCE_UI_SCALE to small, medium or large. - Added a ba.UIScale enum. The value at ba.app.uiscale replaces the old ba.app.interface_type, ba.app.small_ui, and ba.app.med_ui values. -- Emoji no longer display in-game with a washed-out appearance. If there are any places in-game where bright colored emoji become distracing, please holler. +- Emoji no longer display in-game with a washed-out appearance. If there are any places in-game where bright colored emoji become distracting, please holler. +- _ba.get_game_roster() now includes 'account_id' which is the validated account id of all clients (will be None until completes). Also a few keys are renamed: specString->spec_string and displayString->display_string. ### 1.5.19 (20123) - Cleaned up some bomb logic to avoid weird corner-cases such as land-mine explosions behaving like punches when set off by punches or bombs potentially resulting in multiple explosions when triggered by multiple other bombs simultaneously. Holler if anything explosion-related seems off now. diff --git a/assets/src/ba_data/python/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py index 653a1510..237a4c7d 100644 --- a/assets/src/ba_data/python/ba/_servermode.py +++ b/assets/src/ba_data/python/ba/_servermode.py @@ -138,7 +138,7 @@ class ServerController: for client in roster: if client['client_id'] == -1: continue - spec = json.loads(client['specString']) + spec = json.loads(client['spec_string']) name = spec['n'] players = ', '.join(n['name'] for n in client['players']) clientid = client['client_id'] diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py index 74e6ad0e..6c46bf5e 100644 --- a/assets/src/ba_data/python/bastd/ui/party.py +++ b/assets/src/ba_data/python/bastd/ui/party.py @@ -285,7 +285,7 @@ class PartyWindow(ba.Window): p_str = p_str[:25] + '...' else: p_str = self._roster[index][ - 'displayString'] + 'display_string'] except Exception: ba.print_exception( 'Error calcing client name str.') diff --git a/docs/ba_module.md b/docs/ba_module.md index 20d09043..5a99e382 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

      last updated on 2020-07-12 for Ballistica version 1.5.20 build 20133

      +

      last updated on 2020-07-13 for Ballistica version 1.5.20 build 20135

      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!


      From 3891394831c04ec84fec9b87feaf49da0f9123d3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 13 Jul 2020 19:33:11 -0700 Subject: [PATCH 148/417] Added ba.app.ui subsystem to contain ui globals/functionality --- .efrocachemap | 24 ++-- .idea/dictionaries/ericf.xml | 4 + assets/.asset_manifest_public.json | 2 + assets/Makefile | 2 + assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/_app.py | 37 ++--- assets/src/ba_data/python/ba/_gameactivity.py | 3 +- assets/src/ba_data/python/ba/_hooks.py | 18 +-- assets/src/ba_data/python/ba/_ui.py | 133 ++++++++++++++++++ assets/src/ba_data/python/ba/ui/__init__.py | 8 +- .../src/ba_data/python/bastd/appdelegate.py | 12 +- assets/src/ba_data/python/bastd/mainmenu.py | 49 ++++--- .../ba_data/python/bastd/ui/account/link.py | 2 +- .../python/bastd/ui/account/settings.py | 42 +++--- .../ba_data/python/bastd/ui/account/unlink.py | 2 +- .../ba_data/python/bastd/ui/account/viewer.py | 8 +- .../src/ba_data/python/bastd/ui/appinvite.py | 4 +- assets/src/ba_data/python/bastd/ui/confirm.py | 9 +- .../src/ba_data/python/bastd/ui/continues.py | 2 +- .../ba_data/python/bastd/ui/coop/browser.py | 70 ++++----- .../src/ba_data/python/bastd/ui/coop/level.py | 2 +- .../ba_data/python/bastd/ui/creditslist.py | 12 +- assets/src/ba_data/python/bastd/ui/debug.py | 12 +- .../src/ba_data/python/bastd/ui/feedback.py | 2 +- .../ba_data/python/bastd/ui/fileselector.py | 4 +- assets/src/ba_data/python/bastd/ui/gather.py | 26 ++-- .../ba_data/python/bastd/ui/getcurrency.py | 4 +- assets/src/ba_data/python/bastd/ui/helpui.py | 12 +- assets/src/ba_data/python/bastd/ui/kiosk.py | 6 +- .../python/bastd/ui/league/rankbutton.py | 2 +- .../python/bastd/ui/league/rankwindow.py | 8 +- .../src/ba_data/python/bastd/ui/mainmenu.py | 69 ++++----- .../python/bastd/ui/onscreenkeyboard.py | 2 +- .../src/ba_data/python/bastd/ui/partyqueue.py | 4 +- assets/src/ba_data/python/bastd/ui/play.py | 40 +++--- .../python/bastd/ui/playlist/addgame.py | 4 +- .../python/bastd/ui/playlist/browser.py | 37 ++--- .../bastd/ui/playlist/customizebrowser.py | 11 +- .../ba_data/python/bastd/ui/playlist/edit.py | 30 ++-- .../bastd/ui/playlist/editcontroller.py | 60 ++++---- .../python/bastd/ui/playlist/editgame.py | 13 +- .../python/bastd/ui/playlist/mapselect.py | 42 +++--- .../ba_data/python/bastd/ui/playlist/share.py | 4 +- .../python/bastd/ui/profile/browser.py | 43 +++--- .../ba_data/python/bastd/ui/profile/edit.py | 43 +++--- .../python/bastd/ui/profile/upgrade.py | 6 +- .../src/ba_data/python/bastd/ui/promocode.py | 12 +- .../python/bastd/ui/settings/advanced.py | 49 +++---- .../python/bastd/ui/settings/allsettings.py | 38 ++--- .../ba_data/python/bastd/ui/settings/audio.py | 18 +-- .../python/bastd/ui/settings/controls.py | 82 +++++------ .../python/bastd/ui/settings/gamepad.py | 18 +-- .../bastd/ui/settings/gamepadadvanced.py | 2 +- .../python/bastd/ui/settings/gamepadselect.py | 21 +-- .../python/bastd/ui/settings/graphics.py | 19 +-- .../python/bastd/ui/settings/keyboard.py | 12 +- .../python/bastd/ui/settings/ps3controller.py | 7 +- .../python/bastd/ui/settings/remoteapp.py | 7 +- .../python/bastd/ui/settings/testing.py | 6 +- .../python/bastd/ui/settings/touchscreen.py | 7 +- .../python/bastd/ui/settings/wiimote.py | 13 +- .../bastd/ui/settings/xbox360controller.py | 7 +- .../python/bastd/ui/soundtrack/browser.py | 20 +-- .../python/bastd/ui/soundtrack/edit.py | 18 +-- .../bastd/ui/soundtrack/entrytypeselect.py | 39 ++--- .../python/bastd/ui/soundtrack/macmusicapp.py | 2 +- .../ba_data/python/bastd/ui/store/browser.py | 28 ++-- .../python/bastd/ui/tournamententry.py | 4 +- assets/src/ba_data/python/bastd/ui/url.py | 4 +- assets/src/ba_data/python/bastd/ui/watch.py | 22 +-- config/toolconfigsrc/pylintrc | 10 +- docs/ba_module.md | 4 +- 72 files changed, 788 insertions(+), 612 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_ui.py diff --git a/.efrocachemap b/.efrocachemap index 6ab1c512..6187936e 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/4d/52/c1c1011ac6286950129ecfe641c2", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/46/90e28db5c4a563bda000e2df2807", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/b5/c197989dd4e61498dda75f51759c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b8/24/1da2eb6ecdbac963dc31fc258a1d", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/63/a9c21960f84b2d7f40418e66d4c8", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a2/8e/e489beaf13382d65c6c4a39e77e3", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/80/c4/4b4f75b4ae6d887f19ef2ec0f4b5", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/22/ba/e61af862b2d2c138a848583f74a6", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d5/1a/7061d9ff66993841317369cce4dd", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a4/9f/5f3308d5dda1d6f8fb3b51389e05", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bc/0f/7fd42fceaa297e0e67ed18566d3e", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9b/c7/9756a8f6ef5237f1418cabfb6154" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6b/65/84b0f5e6f03ae3e281b3e7c84c33", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/4c/48a8d74829812edbe484a3a00647", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d1/e4/0a2390a2af7b50738e276214f7aa", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5e/33/7ce61884d65810d479d8a8f18845", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/de/aa7c8e010f8cba5559d7c2df953b", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ed/a1/75bbe8e63775056fb82fe4a3c5b9", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/65/64/f754cc64bdb97aae0ecfde4b14a9", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b6/ff/57211cac20b87dc6aec10fbb5e6d", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e0/9c/e781f97fe6b81e373e7524784d3b", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/dd/4747a402c2f635a31a70a305c48e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/26/de8bc04e6d4097583ea98df9eb35", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6f/b3/72fc80d493249f1a0085f29f5db4" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index a376cbb2..075831cb 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -316,6 +316,7 @@ classnames cleancheck cleanlist + cleanupchecks clientid clientlist clionbin @@ -715,6 +716,8 @@ fprint fproject fpsc + frameinfo + frameline framerate freefly freeforallendscreen @@ -2110,6 +2113,7 @@ updatethencheck updatethencheckfast updatethencheckfull + upkeeptimer uploadargs uploadcmd uptime diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index 87802e0c..d633bb80 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -53,6 +53,7 @@ "ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_ui.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc", @@ -110,6 +111,7 @@ "ba_data/python/ba/_teamgame.py", "ba_data/python/ba/_tips.py", "ba_data/python/ba/_tournament.py", + "ba_data/python/ba/_ui.py", "ba_data/python/ba/deprecated.py", "ba_data/python/ba/internal.py", "ba_data/python/ba/macmusicapp.py", diff --git a/assets/Makefile b/assets/Makefile index a9906ad4..86bcef7b 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -202,6 +202,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_teamgame.py \ build/ba_data/python/ba/_tips.py \ build/ba_data/python/ba/_tournament.py \ + build/ba_data/python/ba/_ui.py \ build/ba_data/python/ba/deprecated.py \ build/ba_data/python/ba/internal.py \ build/ba_data/python/ba/macmusicapp.py \ @@ -433,6 +434,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_ui.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 1a03a0e9..295c4763 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -2965,7 +2965,7 @@ def newactivity(activity_type: Type[ba.Activity], Category: General Utility Functions Activities require special setup and thus cannot be directly - instantiated; You must go through this function. + instantiated; you must go through this function. """ import ba # pylint: disable=cyclic-import return ba.Activity(settings={}) diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 4bd5e0ad..023f3957 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -262,6 +262,7 @@ class App: # pylint: disable=too-many-statements from ba._music import MusicController from ba._enums import UIScale + from ba._ui import UI # Config. self.config_file_healthy = False @@ -397,20 +398,12 @@ class App: self.coop_session_args: Dict = {} # UI. - self.uicontroller: Optional[ba.UIController] = None - self.main_menu_window: Optional[_ba.Widget] = None # FIXME: Kill this. - self.window_states: Dict = {} # FIXME: Kill this. - self.windows: Dict = {} # FIXME: Kill this. - self.main_window: Optional[str] = None # FIXME: Kill this. - self.main_menu_selection: Optional[str] = None # FIXME: Kill this. - self.have_party_queue_window = False - self.quit_window: Any = None - self.dismiss_wii_remotes_window_call: (Optional[Callable[[], - Any]]) = None + self.ui = UI() + self.value_test_defaults: dict = {} - self.main_menu_window_refresh_check_count = 0 self.first_main_menu = True # FIXME: Move to mainmenu class. self.did_menu_intro = False # FIXME: Move to mainmenu class. + self.main_menu_window_refresh_check_count = 0 # FIXME: Mv to mainmenu. self.main_menu_resume_callbacks: list = [] # Can probably go away. self.special_offer: Optional[Dict] = None self.league_rank_cache: Dict = {} @@ -422,13 +415,6 @@ class App: self.store_items: Optional[Dict[str, Dict]] = None self.pro_sale_start_time: Optional[int] = None self.pro_sale_start_val: Optional[int] = None - self.party_window: Any = None # FIXME: Don't use Any. - self.title_color = (0.72, 0.7, 0.75) - self.heading_color = (0.72, 0.7, 0.75) - self.infotextcolor = (0.7, 0.9, 0.7) - self.uicleanupchecks: List[UICleanupCheck] = [] - self.uiupkeeptimer: Optional[ba.Timer] = None - self.toolbars = env.get('toolbar_test', True) self.delegate: Optional[ba.AppDelegate] = None @@ -442,7 +428,6 @@ class App: # pylint: disable=cyclic-import from ba import _apputils from ba import _appconfig - from ba.ui import UIController, ui_upkeep from ba import _achievement from ba import _map from ba import _meta @@ -456,7 +441,8 @@ class App: self.delegate = appdelegate.AppDelegate() - self.uicontroller = UIController() + self.ui.on_app_launch() + _achievement.init_achievements() spazappearance.register_appearances() _campaign.init_campaigns() @@ -478,13 +464,6 @@ class App: and not _ba.is_blessed()): _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0)) - # Kick off our periodic UI upkeep. - # FIXME: Can probably kill this if we do immediate UI death checks. - self.uiupkeeptimer = _ba.Timer(2.6543, - ui_upkeep, - timetype=TimeType.REAL, - repeat=True) - # IMPORTANT: If tweaking UI stuff, make sure it behaves for small, # medium, and large UI modes. (doesn't run off screen, etc). # The overrides below can be used to test with different sizes. @@ -648,7 +627,7 @@ class App: from ba._general import Call from bastd.mainmenu import MainMenuSession if reset_ui: - _ba.app.main_window = None + _ba.app.ui.clear_main_menu_window() if isinstance(_ba.get_foreground_host_session(), MainMenuSession): # It may be possible we're on the main menu but the screen is faded @@ -681,7 +660,7 @@ class App: """(internal)""" # If there's no main menu up, just call immediately. - if not self.main_menu_window: + if not self.ui.has_main_menu_window(): with _ba.Context('ui'): call() else: diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index b7e7cb77..ee954fbf 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -423,8 +423,7 @@ class GameActivity(Activity[PlayerType, TeamType]): # Only attempt this if we're not currently paused # and there appears to be no UI. if (not gnode.paused - and _ba.app.main_menu_window is None - or not _ba.app.main_menu_window): + and not _ba.app.ui.has_main_menu_window()): self._is_waiting_for_continue = True with _ba.Context('ui'): _ba.timer( diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index a8718b6f..0c5e95c0 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -180,7 +180,7 @@ def purchases_restored_message() -> None: def dismiss_wii_remotes_window() -> None: - call = _ba.app.dismiss_wii_remotes_window_call + call = _ba.app.ui.dismiss_wii_remotes_window_call if call is not None: call() @@ -256,10 +256,10 @@ def party_icon_activate(origin: Sequence[float]) -> None: _ba.playsound(_ba.getsound('swish')) # If it exists, dismiss it; otherwise make a new one. - if app.party_window is not None and app.party_window() is not None: - app.party_window().close() + if app.ui.party_window is not None and app.ui.party_window() is not None: + app.ui.party_window().close() else: - app.party_window = weakref.ref(PartyWindow(origin=origin)) + app.ui.party_window = weakref.ref(PartyWindow(origin=origin)) def read_config() -> None: @@ -303,11 +303,11 @@ def gc_disable() -> None: def device_menu_press(device: ba.InputDevice) -> None: from bastd.ui.mainmenu import MainMenuWindow - in_main_menu = bool(_ba.app.main_menu_window) + in_main_menu = _ba.app.ui.has_main_menu_window() if not in_main_menu: _ba.set_ui_input_device(device) _ba.playsound(_ba.getsound('swish')) - _ba.app.main_menu_window = (MainMenuWindow().get_root_widget()) + _ba.app.ui.set_main_menu_window(MainMenuWindow().get_root_widget()) def show_url_window(address: str) -> None: @@ -338,9 +338,9 @@ def filter_chat_message(msg: str, client_id: int) -> Optional[str]: def local_chat_message(msg: str) -> None: - if (_ba.app.party_window is not None - and _ba.app.party_window() is not None): - _ba.app.party_window().on_chat_message(msg) + if (_ba.app.ui.party_window is not None + and _ba.app.ui.party_window() is not None): + _ba.app.ui.party_window().on_chat_message(msg) def handle_remote_achievement_list(completed_achievements: List[str]) -> None: diff --git a/assets/src/ba_data/python/ba/_ui.py b/assets/src/ba_data/python/ba/_ui.py new file mode 100644 index 00000000..ce4c5a99 --- /dev/null +++ b/assets/src/ba_data/python/ba/_ui.py @@ -0,0 +1,133 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""User interface functionality.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import _ba + +if TYPE_CHECKING: + from typing import Optional, Dict, Any, Callable, List + from ba.ui import UICleanupCheck + import ba + + +class UI: + """UI subsystem for the app.""" + + def __init__(self) -> None: + env = _ba.env() + + self.controller: Optional[ba.UIController] = None + + self._main_menu_window: Optional[ba.Widget] = None + self._main_menu_location: Optional[str] = None + + self.window_states: Dict = {} # FIXME: Kill this. + # self.windows: Dict = {} # FIXME: Kill this. + self.main_menu_selection: Optional[str] = None # FIXME: Kill this. + self.have_party_queue_window = False + self.quit_window: Any = None + self.dismiss_wii_remotes_window_call: (Optional[Callable[[], + Any]]) = None + self.cleanupchecks: List[UICleanupCheck] = [] + self.upkeeptimer: Optional[ba.Timer] = None + self.use_toolbars = env.get('toolbar_test', True) + self.party_window: Any = None # FIXME: Don't use Any. + self.title_color = (0.72, 0.7, 0.75) + self.heading_color = (0.72, 0.7, 0.75) + self.infotextcolor = (0.7, 0.9, 0.7) + + def on_app_launch(self) -> None: + """Should be run on app launch.""" + from ba.ui import UIController, ui_upkeep + from ba._enums import TimeType + + self.controller = UIController() + + # Kick off our periodic UI upkeep. + # FIXME: Can probably kill this if we do immediate UI death checks. + self.upkeeptimer = _ba.Timer(2.6543, + ui_upkeep, + timetype=TimeType.REAL, + repeat=True) + + def set_main_menu_window(self, window: ba.Widget) -> None: + """Set the current 'main' window, replacing any existing.""" + existing = self._main_menu_window + from ba._enums import TimeType + from inspect import currentframe, getframeinfo + + # Let's grab the location where we were called from to report + # if we have to force-kill the existing window (which normally + # should not happen). + frameline = None + try: + frame = currentframe() + if frame is not None: + frame = frame.f_back + if frame is not None: + frameinfo = getframeinfo(frame) + frameline = f'{frameinfo.filename} {frameinfo.lineno}' + except Exception: + from ba._error import print_exception + print_exception('Error calcing line for set_main_menu_window') + + # With our legacy main-menu system, the caller is responsible for + # clearing out the old main menu window when assigning the new. + # However there are corner cases where that doesn't happen and we get + # old windows stuck under the new main one. So let's guard against that + # However, we can't simply delete the existing main window when + # a new one is assigned because the user may transition the old out + # *after* the assignment. Sigh. So as a happy medium let's check in + # on the old after a short bit of time and kill it if its still alive. + # That will be a bit ugly on screen but at least will un-break things. + def _delay_kill() -> None: + if existing: + print(f'Killing old main_menu_window' + f' when called at: {frameline}') + existing.delete() + + _ba.timer(1.0, _delay_kill, timetype=TimeType.REAL) + self._main_menu_window = window + + def clear_main_menu_window(self, transition: str = None) -> None: + """Clear any existing 'main' window with the provided transition.""" + if self._main_menu_window: + if transition is not None: + _ba.containerwidget(edit=self._main_menu_window, + transition=transition) + else: + self._main_menu_window.delete() + + def has_main_menu_window(self) -> bool: + """Return whether a main menu window is present.""" + return bool(self._main_menu_window) + + def set_main_menu_location(self, location: str) -> None: + """Set the location represented by the current main menu window.""" + self._main_menu_location = location + + def get_main_menu_location(self) -> Optional[str]: + """Return the current named main menu location, if any.""" + return self._main_menu_location diff --git a/assets/src/ba_data/python/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py index 02835ab6..4a1a4cb0 100644 --- a/assets/src/ba_data/python/ba/ui/__init__.py +++ b/assets/src/ba_data/python/ba/ui/__init__.py @@ -203,7 +203,7 @@ def uicleanupcheck(obj: Any, widget: ba.Widget) -> None: widget.add_delete_callback(foobar) - _ba.app.uicleanupchecks.append( + _ba.app.ui.cleanupchecks.append( UICleanupCheck(obj=weakref.ref(obj), widget=widget, widget_death_time=None)) @@ -211,10 +211,10 @@ def uicleanupcheck(obj: Any, widget: ba.Widget) -> None: def ui_upkeep() -> None: """Run UI cleanup checks, etc. should be called periodically.""" - app = _ba.app + ui = _ba.app.ui remainingchecks = [] now = _ba.time(TimeType.REAL) - for check in app.uicleanupchecks: + for check in ui.cleanupchecks: obj = check.obj() # If the object has died, ignore and don't re-add. @@ -237,4 +237,4 @@ def ui_upkeep() -> None: ' you probably have a memory leak.') else: remainingchecks.append(check) - app.uicleanupchecks = remainingchecks + ui.cleanupchecks = remainingchecks diff --git a/assets/src/ba_data/python/bastd/appdelegate.py b/assets/src/ba_data/python/bastd/appdelegate.py index 351a1984..e650a2e0 100644 --- a/assets/src/ba_data/python/bastd/appdelegate.py +++ b/assets/src/ba_data/python/bastd/appdelegate.py @@ -40,8 +40,10 @@ class AppDelegate(ba.AppDelegate): # Replace the main window once we come up successfully. from bastd.ui.playlist.editgame import PlaylistEditGameWindow - prev_window = ba.app.main_menu_window - ba.app.main_menu_window = (PlaylistEditGameWindow( - gameclass, sessiontype, settings, - completion_call=completion_call).get_root_widget()) - ba.containerwidget(edit=prev_window, transition='out_left') + ba.app.ui.clear_main_menu_window(transition='out_left') + ba.app.ui.set_main_menu_window( + PlaylistEditGameWindow( + gameclass, + sessiontype, + settings, + completion_call=completion_call).get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index cbdb3003..6b275cd9 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -403,55 +403,58 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): with ba.Context('ui'): from bastd.ui import specialoffer if bool(False): - uicontroller = ba.app.uicontroller + uicontroller = ba.app.ui.controller assert uicontroller is not None uicontroller.show_main_menu() else: - main_window = ba.app.main_window + main_menu_location = ba.app.ui.get_main_menu_location() # When coming back from a kiosk-mode game, jump to # the kiosk start screen. if ba.app.kiosk_mode: # pylint: disable=cyclic-import from bastd.ui.kiosk import KioskWindow - ba.app.main_menu_window = KioskWindow().get_root_widget() + ba.app.ui.set_main_menu_window( + KioskWindow().get_root_widget()) # ..or in normal cases go back to the main menu else: - main_window = ba.app.main_window - if main_window == 'Gather': + if main_menu_location == 'Gather': # pylint: disable=cyclic-import from bastd.ui.gather import GatherWindow - ba.app.main_menu_window = (GatherWindow( - transition=None).get_root_widget()) - elif main_window == 'Watch': + ba.app.ui.set_main_menu_window( + GatherWindow(transition=None).get_root_widget()) + elif main_menu_location == 'Watch': # pylint: disable=cyclic-import from bastd.ui.watch import WatchWindow - ba.app.main_menu_window = WatchWindow( - transition=None).get_root_widget() - elif main_window == 'Team Game Select': + ba.app.ui.set_main_menu_window( + WatchWindow(transition=None).get_root_widget()) + elif main_menu_location == 'Team Game Select': # pylint: disable=cyclic-import from bastd.ui.playlist.browser import ( PlaylistBrowserWindow) - ba.app.main_menu_window = PlaylistBrowserWindow( - sessiontype=ba.DualTeamSession, - transition=None).get_root_widget() - elif main_window == 'Free-for-All Game Select': + ba.app.ui.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=ba.DualTeamSession, + transition=None).get_root_widget()) + elif main_menu_location == 'Free-for-All Game Select': # pylint: disable=cyclic-import from bastd.ui.playlist.browser import ( PlaylistBrowserWindow) - ba.app.main_menu_window = PlaylistBrowserWindow( - sessiontype=ba.FreeForAllSession, - transition=None).get_root_widget() - elif main_window == 'Coop Select': + ba.app.ui.set_main_menu_window( + PlaylistBrowserWindow( + sessiontype=ba.FreeForAllSession, + transition=None).get_root_widget()) + elif main_menu_location == 'Coop Select': # pylint: disable=cyclic-import from bastd.ui.coop.browser import CoopBrowserWindow - ba.app.main_menu_window = CoopBrowserWindow( - transition=None).get_root_widget() + ba.app.ui.set_main_menu_window( + CoopBrowserWindow( + transition=None).get_root_widget()) else: # pylint: disable=cyclic-import from bastd.ui.mainmenu import MainMenuWindow - ba.app.main_menu_window = MainMenuWindow( - transition=None).get_root_widget() + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition=None).get_root_widget()) # attempt to show any pending offers immediately. # If that doesn't work, try again in a few seconds diff --git a/assets/src/ba_data/python/bastd/ui/account/link.py b/assets/src/ba_data/python/bastd/ui/account/link.py index 506ec979..8f0c238d 100644 --- a/assets/src/ba_data/python/bastd/ui/account/link.py +++ b/assets/src/ba_data/python/bastd/ui/account/link.py @@ -77,7 +77,7 @@ class AccountLinkWindow(ba.Window): 'accountSettingsWindow.linkAccountsInstructionsNewText'), subs=[('${COUNT}', str(maxlinks))]), maxwidth=self._width * 0.9, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, max_height=self._height * 0.6, h_align='center', v_align='center') diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py index 56583eb7..6f178d7c 100644 --- a/assets/src/ba_data/python/bastd/ui/account/settings.py +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py @@ -113,7 +113,7 @@ class AccountSettingsWindow(ba.Window): scale=(2.09 if uiscale is ba.UIScale.SMALL else 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -19) if uiscale is ba.UIScale.SMALL else (0, 0))) - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) @@ -140,7 +140,7 @@ class AccountSettingsWindow(ba.Window): position=(self._width * 0.5, self._height - 41), size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=self._width - 340, h_align='center', v_align='center') @@ -363,7 +363,7 @@ class AccountSettingsWindow(ba.Window): size=(0, 0), text=txt, scale=0.9, - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=self._sub_width * 0.9, h_align='center', v_align='center') @@ -450,7 +450,7 @@ class AccountSettingsWindow(ba.Window): on_activate_call=lambda: self._sign_in_press('Google Play')) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -475,7 +475,7 @@ class AccountSettingsWindow(ba.Window): on_activate_call=lambda: self._sign_in_press('Game Circle')) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -499,7 +499,7 @@ class AccountSettingsWindow(ba.Window): on_activate_call=lambda: self._sign_in_press('Ali')) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -545,7 +545,7 @@ class AccountSettingsWindow(ba.Window): color=(0.55, 0.8, 0.5)) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -592,7 +592,7 @@ class AccountSettingsWindow(ba.Window): color=(0.55, 0.8, 0.5)) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -614,7 +614,7 @@ class AccountSettingsWindow(ba.Window): on_activate_call=self._player_profiles_press) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=0) @@ -642,7 +642,7 @@ class AccountSettingsWindow(ba.Window): label=account_type_name) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -684,7 +684,7 @@ class AccountSettingsWindow(ba.Window): label='') if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -712,7 +712,7 @@ class AccountSettingsWindow(ba.Window): label=ba.Lstr(resource='leaderboardsText')) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -782,7 +782,7 @@ class AccountSettingsWindow(ba.Window): action=self._reset_progress)) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn) @@ -837,7 +837,7 @@ class AccountSettingsWindow(ba.Window): color=(0.75, 0.7, 0.8)) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=50) @@ -865,7 +865,7 @@ class AccountSettingsWindow(ba.Window): color=(0.75, 0.7, 0.8)) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=50) @@ -886,7 +886,7 @@ class AccountSettingsWindow(ba.Window): on_activate_call=self._sign_out_press) if first_selectable is None: first_selectable = btn - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) ba.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15) @@ -1090,14 +1090,14 @@ class AccountSettingsWindow(ba.Window): def _back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if not self._modal: - ba.app.main_menu_window = (mainmenu.MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) def _save_state(self) -> None: try: @@ -1108,13 +1108,13 @@ class AccountSettingsWindow(ba.Window): sel_name = 'Scroll' else: raise ValueError('unrecognized selection') - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name except Exception: ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) if sel_name == 'Back': sel = self._back_button elif sel_name == 'Scroll': diff --git a/assets/src/ba_data/python/bastd/ui/account/unlink.py b/assets/src/ba_data/python/bastd/ui/account/unlink.py index c4b7ec78..53d52189 100644 --- a/assets/src/ba_data/python/bastd/ui/account/unlink.py +++ b/assets/src/ba_data/python/bastd/ui/account/unlink.py @@ -77,7 +77,7 @@ class AccountUnlinkWindow(ba.Window): resource='accountSettingsWindow.unlinkAccountsInstructionsText' ), maxwidth=self._width * 0.7, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, h_align='center', v_align='center') ba.containerwidget(edit=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py index 3c9022f5..044196c7 100644 --- a/assets/src/ba_data/python/bastd/ui/account/viewer.py +++ b/assets/src/ba_data/python/bastd/ui/account/viewer.py @@ -292,7 +292,7 @@ class AccountViewerWindow(popup.PopupWindow): h_align='center', v_align='center', scale=title_scale, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=account_title, maxwidth=sub_width * maxwidth_scale) draw_small = (showing_character @@ -319,7 +319,7 @@ class AccountViewerWindow(popup.PopupWindow): h_align='center', v_align='center', scale=title_scale, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=ba.Lstr(resource='rankText'), maxwidth=sub_width * maxwidth_scale) v -= 14 @@ -433,7 +433,7 @@ class AccountViewerWindow(popup.PopupWindow): h_align='center', v_align='center', scale=title_scale, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=ba.Lstr(resource='achievementsText'), maxwidth=sub_width * maxwidth_scale) v -= 14 @@ -462,7 +462,7 @@ class AccountViewerWindow(popup.PopupWindow): h_align='center', v_align='center', scale=title_scale, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, flatness=1.0, text=ba.Lstr(resource='trophiesThisSeasonText', fallback_resource='trophiesText'), diff --git a/assets/src/ba_data/python/bastd/ui/appinvite.py b/assets/src/ba_data/python/bastd/ui/appinvite.py index 00eabdd8..db1615c4 100644 --- a/assets/src/ba_data/python/bastd/ui/appinvite.py +++ b/assets/src/ba_data/python/bastd/ui/appinvite.py @@ -202,7 +202,7 @@ class ShowFriendCodeWindow(ba.Window): parent=self._root_widget, position=(self._width * 0.5, self._height * 0.8), size=(0, 0), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, scale=1.0, flatness=1.0, h_align='center', @@ -231,7 +231,7 @@ class ShowFriendCodeWindow(ba.Window): parent=self._root_widget, position=(self._width * 0.5, self._height * 0.37), size=(0, 0), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, scale=1.0, flatness=1.0, h_align='center', diff --git a/assets/src/ba_data/python/bastd/ui/confirm.py b/assets/src/ba_data/python/bastd/ui/confirm.py index b15b1a6d..5874d299 100644 --- a/assets/src/ba_data/python/bastd/ui/confirm.py +++ b/assets/src/ba_data/python/bastd/ui/confirm.py @@ -147,18 +147,19 @@ class QuitWindow: swish: bool = False, back: bool = False, origin_widget: ba.Widget = None): + ui = ba.app.ui app = ba.app self._back = back # If there's already one of us up somewhere, kill it. - if app.quit_window is not None: - app.quit_window.delete() - app.quit_window = None + if ui.quit_window is not None: + ui.quit_window.delete() + ui.quit_window = None if swish: ba.playsound(ba.getsound('swish')) quit_resource = ('quitGameText' if app.platform == 'mac' else 'exitGameText') - self._root_widget = app.quit_window = (ConfirmWindow( + self._root_widget = ui.quit_window = (ConfirmWindow( ba.Lstr(resource=quit_resource, subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), self._fade_and_quit, diff --git a/assets/src/ba_data/python/bastd/ui/continues.py b/assets/src/ba_data/python/bastd/ui/continues.py index 926d19a6..68d78047 100644 --- a/assets/src/ba_data/python/bastd/ui/continues.py +++ b/assets/src/ba_data/python/bastd/ui/continues.py @@ -94,7 +94,7 @@ class ContinuesWindow(ba.Window): self._tickets_text_base: Optional[str] self._tickets_text: Optional[ba.Widget] - if not ba.app.toolbars: + if not ba.app.ui.use_toolbars: self._tickets_text_base = ba.Lstr( resource='getTicketsWindow.youHaveShortText', fallback_resource='getTicketsWindow.youHaveText').evaluate() diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 629b782a..c61884b2 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -103,7 +103,7 @@ class CoopBrowserWindow(ba.Window): self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (657 if uiscale is ba.UIScale.SMALL else 730 if uiscale is ba.UIScale.MEDIUM else 800) - app.main_window = 'Coop Select' + app.ui.set_main_menu_location('Coop Select') self._r = 'coopSelectWindow' top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 @@ -122,7 +122,7 @@ class CoopBrowserWindow(ba.Window): scale=(1.2 if uiscale is ba.UIScale.SMALL else 0.8 if uiscale is ba.UIScale.MEDIUM else 0.75))) - if app.toolbars and uiscale is ba.UIScale.SMALL: + if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None else: self._back_button = ba.buttonwidget( @@ -140,7 +140,7 @@ class CoopBrowserWindow(ba.Window): self._store_button_widget: Optional[ba.Widget] self._league_rank_button_widget: Optional[ba.Widget] - if not app.toolbars: + if not app.ui.use_toolbars: prb = self._league_rank_button = LeagueRankButton( parent=self._root_widget, position=(self._width - (282 + x_inset), self._height - 85 - @@ -206,12 +206,12 @@ class CoopBrowserWindow(ba.Window): text=ba.Lstr(resource='playModes.singlePlayerCoopText', fallback_resource='playModes.coopText'), h_align='center', - color=app.title_color, + color=app.ui.title_color, scale=1.5, maxwidth=500, v_align='center') - if app.toolbars and uiscale is ba.UIScale.SMALL: + if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.textwidget(edit=txt, text='') if self._back_button is not None: @@ -232,9 +232,9 @@ class CoopBrowserWindow(ba.Window): self.a_outline_model = ba.getmodel('achievementOutline') self._scroll_width = self._width - (130 + 2 * x_inset) - self._scroll_height = ( - self._height - - (190 if uiscale is ba.UIScale.SMALL and app.toolbars else 160)) + self._scroll_height = (self._height - + (190 if uiscale is ba.UIScale.SMALL + and app.ui.use_toolbars else 160)) self._subcontainerwidth = 800.0 self._subcontainerheight = 1400.0 @@ -242,9 +242,8 @@ class CoopBrowserWindow(ba.Window): self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, - position=(65 + x_inset, - 120) if uiscale is ba.UIScale.SMALL and app.toolbars else - (65 + x_inset, 70), + position=(65 + x_inset, 120) if uiscale is ba.UIScale.SMALL + and app.ui.use_toolbars else (65 + x_inset, 70), size=(self._scroll_width, self._scroll_height), simple_culling_v=10.0) self._subcontainer: Optional[ba.Widget] = None @@ -815,15 +814,15 @@ class CoopBrowserWindow(ba.Window): v = self._subcontainerheight - 73 - self._campaign_percent_text = ba.textwidget(parent=w_parent, - position=(h_base + 27, - v + 30), - size=(0, 0), - text='', - h_align='left', - v_align='center', - color=ba.app.title_color, - scale=1.1) + self._campaign_percent_text = ba.textwidget( + parent=w_parent, + position=(h_base + 27, v + 30), + size=(0, 0), + text='', + h_align='left', + v_align='center', + color=ba.app.ui.title_color, + scale=1.1) row_v_show_buffer = 100 v -= 198 @@ -867,7 +866,7 @@ class CoopBrowserWindow(ba.Window): text=txt, h_align='left', v_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.1) self._tournament_info_button = ba.buttonwidget( parent=w_parent, @@ -901,7 +900,7 @@ class CoopBrowserWindow(ba.Window): text=unavailable_text, h_align='left', v_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=0.9) v -= 40 v -= 198 @@ -947,7 +946,7 @@ class CoopBrowserWindow(ba.Window): fallback_resource='coopSelectWindow.customText'), h_align='left', v_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.1) items = [ @@ -1371,9 +1370,9 @@ class CoopBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') assert self._league_rank_button is not None - ba.app.main_menu_window = (LeagueRankWindow( - origin_widget=self._league_rank_button.get_button()). - get_root_widget()) + ba.app.ui.set_main_menu_window( + LeagueRankWindow(origin_widget=self._league_rank_button.get_button( + )).get_root_widget()) def _switch_to_score(self, show_tab: Optional[str] = 'extras') -> None: # pylint: disable=cyclic-import @@ -1385,10 +1384,11 @@ class CoopBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') assert self._store_button is not None - ba.app.main_menu_window = (StoreBrowserWindow( - origin_widget=self._store_button.get_button(), - show_tab=show_tab, - back_location='CoopBrowserWindow').get_root_widget()) + ba.app.ui.set_main_menu_window( + StoreBrowserWindow( + origin_widget=self._store_button.get_button(), + show_tab=show_tab, + back_location='CoopBrowserWindow').get_root_widget()) def _show_leader(self, tournament_button: Dict[str, Any]) -> None: # pylint: disable=cyclic-import @@ -1551,13 +1551,13 @@ class CoopBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (PlayWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + PlayWindow(transition='in_left').get_root_widget()) def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__, - {}).get('sel_name') + sel_name = ba.app.ui.window_states.get(self.__class__.__name__, + {}).get('sel_name') if sel_name == 'Back': sel = self._back_button elif sel_name == 'Scroll': @@ -1586,7 +1586,7 @@ class CoopBrowserWindow(ba.Window): sel_name = 'Scroll' else: raise ValueError('unrecognized selection') - ba.app.window_states[self.__class__.__name__] = { + ba.app.ui.window_states[self.__class__.__name__] = { 'sel_name': sel_name } except Exception: diff --git a/assets/src/ba_data/python/bastd/ui/coop/level.py b/assets/src/ba_data/python/bastd/ui/coop/level.py index 113ca6fc..85271139 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/level.py +++ b/assets/src/ba_data/python/bastd/ui/coop/level.py @@ -56,7 +56,7 @@ class CoopLevelLockedWindow(ba.Window): text=ba.Lstr(resource='levelMustBeCompletedFirstText', subs=[('${LEVEL}', dep_name)]), maxwidth=400, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, scale=0.8) ba.imagewidget(parent=self._root_widget, position=(56 - 20, height * 0.39), diff --git a/assets/src/ba_data/python/bastd/ui/creditslist.py b/assets/src/ba_data/python/bastd/ui/creditslist.py index 154337c1..f2241f8a 100644 --- a/assets/src/ba_data/python/bastd/ui/creditslist.py +++ b/assets/src/ba_data/python/bastd/ui/creditslist.py @@ -66,7 +66,7 @@ class CreditsListWindow(ba.Window): 1.3 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -8) if uiscale is ba.UIScale.SMALL else (0, 0))) - if ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) else: @@ -98,7 +98,7 @@ class CreditsListWindow(ba.Window): subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), h_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=330, v_align='center') @@ -108,7 +108,7 @@ class CreditsListWindow(ba.Window): height - 100), capture_arrows=True) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=scroll, right_widget=_ba.get_special_widget('party_button')) if uiscale is ba.UIScale.SMALL: @@ -280,8 +280,8 @@ class CreditsListWindow(ba.Window): voffs -= line_height def _back(self) -> None: - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = mainmenu.MainMenuWindow( - transition='in_left').get_root_widget() + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/debug.py b/assets/src/ba_data/python/bastd/ui/debug.py index 41c864e6..8470d1df 100644 --- a/assets/src/ba_data/python/bastd/ui/debug.py +++ b/assets/src/ba_data/python/bastd/ui/debug.py @@ -77,7 +77,7 @@ class DebugWindow(ba.Window): size=(width, 30), text=ba.Lstr(resource=self._r + '.titleText'), h_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, v_align='center', maxwidth=260) @@ -130,7 +130,7 @@ class DebugWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.stressTestTitleText'), maxwidth=200, - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.85, h_align='center', v_align='center') @@ -143,7 +143,7 @@ class DebugWindow(ba.Window): text=ba.Lstr(resource=self._r + '.stressTestPlaylistTypeText'), maxwidth=130, - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.65, h_align='right', v_align='center') @@ -169,7 +169,7 @@ class DebugWindow(ba.Window): text=ba.Lstr(resource=self._r + '.stressTestPlaylistNameText'), maxwidth=130, - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.65, h_align='right', v_align='center') @@ -333,5 +333,5 @@ class DebugWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.settings.advanced import AdvancedSettingsWindow ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (AdvancedSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + AdvancedSettingsWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/feedback.py b/assets/src/ba_data/python/bastd/ui/feedback.py index d10d9f57..5f5fb37b 100644 --- a/assets/src/ba_data/python/bastd/ui/feedback.py +++ b/assets/src/ba_data/python/bastd/ui/feedback.py @@ -57,7 +57,7 @@ def ask_for_rating() -> Optional[ba.Widget]: ba.textwidget(parent=dlg, position=(15, v - 55), size=(width - 30, 30), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=ba.Lstr(resource='pleaseRateText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), diff --git a/assets/src/ba_data/python/bastd/ui/fileselector.py b/assets/src/ba_data/python/bastd/ui/fileselector.py index a65905a0..cc5badc3 100644 --- a/assets/src/ba_data/python/bastd/ui/fileselector.py +++ b/assets/src/ba_data/python/bastd/ui/fileselector.py @@ -73,7 +73,7 @@ class FileSelectorWindow(ba.Window): parent=self._root_widget, position=(self._width * 0.5, self._height - 42), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', text=ba.Lstr(resource=self._r + '.titleFolderText') if @@ -121,7 +121,7 @@ class FileSelectorWindow(ba.Window): position=(self._folder_center, self._height - 98), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', text=self._path, diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index e4d3185f..9f0bf8dd 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -55,7 +55,7 @@ class GatherWindow(ba.Window): else: self._transition_out = 'out_right' scale_origin = None - ba.app.main_window = 'Gather' + ba.app.ui.set_main_menu_location('Gather') _ba.set_party_icon_always_visible(True) self._public_parties: Dict[str, Dict[str, Any]] = {} uiscale = ba.app.uiscale @@ -114,7 +114,7 @@ class GatherWindow(ba.Window): stack_offset=(0, -11) if uiscale is ba.UIScale.SMALL else ( 0, 0) if uiscale is ba.UIScale.MEDIUM else (0, 0))) - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) self._back_button = None @@ -138,7 +138,7 @@ class GatherWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 42), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.5, h_align='center', v_align='center', @@ -172,7 +172,7 @@ class GatherWindow(ba.Window): size=(self._width - tab_buffer_h, 50), on_select_call=self._set_tab) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=self._tab_buttons[tabs_def[-1][0]], right_widget=_ba.get_special_widget('party_button')) if uiscale is ba.UIScale.SMALL: @@ -1147,7 +1147,7 @@ class GatherWindow(ba.Window): v_align='center', maxwidth=200, scale=0.8, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, position=(210, v - 9), text=party_name_text) self._internet_host_name_text = ba.textwidget( @@ -1172,7 +1172,7 @@ class GatherWindow(ba.Window): v_align='center', maxwidth=200, scale=0.8, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, position=(210, v - 9), text=ba.Lstr(resource='maxPartySizeText', fallback_resource='maxConnectionsText')) @@ -1251,7 +1251,7 @@ class GatherWindow(ba.Window): h_align='center', v_align='center', maxwidth=c_width * 0.9, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, position=(c_width * 0.5, v)) # If public sharing is already on, @@ -1561,7 +1561,7 @@ class GatherWindow(ba.Window): # Special case: if a party-queue window is up, don't do any of this # (keeps things smoother). - if ba.app.have_party_queue_window: + if ba.app.ui.have_party_queue_window: return # If we've got a party-name text widget, keep its value plugged @@ -1922,7 +1922,7 @@ class GatherWindow(ba.Window): sel_name = 'TabContainer' else: raise ValueError(f'unrecognized selection: \'{sel}\'') - ba.app.window_states[self.__class__.__name__] = { + ba.app.ui.window_states[self.__class__.__name__] = { 'sel_name': sel_name, 'tab': self._current_tab, 'internet_tab': self._internet_tab @@ -1932,7 +1932,7 @@ class GatherWindow(ba.Window): def _restore_state(self) -> None: try: - winstate = ba.app.window_states.get(self.__class__.__name__, {}) + winstate = ba.app.ui.window_states.get(self.__class__.__name__, {}) sel_name = winstate.get('sel_name', None) self._internet_tab = winstate.get('internet_tab', 'join') current_tab = ba.app.config.get('Gather Tab', None) @@ -1952,9 +1952,9 @@ class GatherWindow(ba.Window): ba.print_exception(f'Error restoring state for {self}.') def _back(self) -> None: - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (mainmenu.MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/getcurrency.py b/assets/src/ba_data/python/bastd/ui/getcurrency.py index bfa0a96e..b3524168 100644 --- a/assets/src/ba_data/python/bastd/ui/getcurrency.py +++ b/assets/src/ba_data/python/bastd/ui/getcurrency.py @@ -100,7 +100,7 @@ class GetCurrencyWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 55), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.2, h_align='center', v_align='center', @@ -602,7 +602,7 @@ class GetCurrencyWindow(ba.Window): modal=self._from_modal_store, back_location=self._store_back_location).get_root_widget() if not self._from_modal_store: - ba.app.main_menu_window = window + ba.app.ui.set_main_menu_window(window) self._transitioning_out = True diff --git a/assets/src/ba_data/python/bastd/ui/helpui.py b/assets/src/ba_data/python/bastd/ui/helpui.py index 0d36502c..e0a49083 100644 --- a/assets/src/ba_data/python/bastd/ui/helpui.py +++ b/assets/src/ba_data/python/bastd/ui/helpui.py @@ -80,7 +80,7 @@ class HelpWindow(ba.Window): text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='top') @@ -92,7 +92,7 @@ class HelpWindow(ba.Window): height - 120 + (5 if uiscale is ba.UIScale.SMALL else 0)), capture_arrows=True) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=self._scrollwidget, right_widget=_ba.get_special_widget('party_button')) ba.containerwidget(edit=self._root_widget, @@ -100,7 +100,7 @@ class HelpWindow(ba.Window): # ugly: create this last so it gets first dibs at touch events (since # we have it close to the scroll widget) - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._close) ba.widget(edit=self._scrollwidget, @@ -600,9 +600,9 @@ class HelpWindow(ba.Window): def _close(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if self._main_menu: - ba.app.main_menu_window = (mainmenu.MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index 353867f5..a0a95ddb 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -337,7 +337,7 @@ class KioskWindow(ba.Window): repeat=True) def _restore_state(self) -> None: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) sel: Optional[ba.Widget] if sel_name == 'b1': sel = self._b1 @@ -376,7 +376,7 @@ class KioskWindow(ba.Window): sel_name = 'b7' else: sel_name = 'b1' - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name def _update(self) -> None: # Kiosk-mode is designed to be used signed-out... try for force @@ -466,4 +466,4 @@ class KioskWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') ba.app.did_menu_intro = True # prevent delayed transition-in - ba.app.main_menu_window = (MainMenuWindow().get_root_widget()) + ba.app.ui.set_main_menu_window(MainMenuWindow().get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py index 54868a5d..9d48c8eb 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py @@ -340,7 +340,7 @@ class LeagueRankButton: txt = ba.Lstr( resource='league.leagueRankText', fallback_resource='coopSelectWindow.powerRankingText') - t_color = ba.app.title_color + t_color = ba.app.ui.title_color ba.textwidget(edit=self._title_text, text=txt, color=t_color) ba.textwidget(edit=self._value_text, text=status_text) diff --git a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py index e4844ee2..6bfc30b0 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py @@ -100,7 +100,7 @@ class LeagueRankWindow(ba.Window): resource='league.leagueRankText', fallback_resource='coopSelectWindow.powerRankingText'), h_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.4, maxwidth=600, v_align='center') @@ -931,10 +931,10 @@ class LeagueRankWindow(ba.Window): pass def _back(self) -> None: - from bastd.ui.coop import browser + from bastd.ui.coop.browser import CoopBrowserWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if not self._modal: - ba.app.main_menu_window = (browser.CoopBrowserWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + CoopBrowserWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 3354bf3d..f46c4b1f 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -840,16 +840,17 @@ class MainMenuWindow(ba.Window): from bastd.ui.kiosk import KioskWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (KioskWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + KioskWindow(transition='in_left').get_root_widget()) def _show_account_window(self) -> None: # pylint: disable=cyclic-import from bastd.ui.account.settings import AccountSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (AccountSettingsWindow( - origin_widget=self._gc_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + AccountSettingsWindow( + origin_widget=self._gc_button).get_root_widget()) def _on_store_pressed(self) -> None: # pylint: disable=cyclic-import @@ -860,8 +861,9 @@ class MainMenuWindow(ba.Window): return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (StoreBrowserWindow( - origin_widget=self._store_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + StoreBrowserWindow( + origin_widget=self._store_button).get_root_widget()) def _confirm_end_game(self) -> None: # pylint: disable=cyclic-import @@ -916,25 +918,28 @@ class MainMenuWindow(ba.Window): from bastd.ui.creditslist import CreditsListWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (CreditsListWindow( - origin_widget=self._credits_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + CreditsListWindow( + origin_widget=self._credits_button).get_root_widget()) def _howtoplay(self) -> None: # pylint: disable=cyclic-import from bastd.ui.helpui import HelpWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (HelpWindow( - main_menu=True, - origin_widget=self._how_to_play_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + HelpWindow( + main_menu=True, + origin_widget=self._how_to_play_button).get_root_widget()) def _settings(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.allsettings import AllSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (AllSettingsWindow( - origin_widget=self._settings_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + AllSettingsWindow( + origin_widget=self._settings_button).get_root_widget()) def _resume_and_call(self, call: Callable[[], Any]) -> None: self._resume() @@ -951,28 +956,28 @@ class MainMenuWindow(ba.Window): return sel = self._root_widget.get_selected_child() if sel == self._start_button: - ba.app.main_menu_selection = 'Start' + ba.app.ui.main_menu_selection = 'Start' elif sel == self._gather_button: - ba.app.main_menu_selection = 'Gather' + ba.app.ui.main_menu_selection = 'Gather' elif sel == self._watch_button: - ba.app.main_menu_selection = 'Watch' + ba.app.ui.main_menu_selection = 'Watch' elif sel == self._how_to_play_button: - ba.app.main_menu_selection = 'HowToPlay' + ba.app.ui.main_menu_selection = 'HowToPlay' elif sel == self._credits_button: - ba.app.main_menu_selection = 'Credits' + ba.app.ui.main_menu_selection = 'Credits' elif sel == self._settings_button: - ba.app.main_menu_selection = 'Settings' + ba.app.ui.main_menu_selection = 'Settings' elif sel == self._gc_button: - ba.app.main_menu_selection = 'GameService' + ba.app.ui.main_menu_selection = 'GameService' elif sel == self._store_button: - ba.app.main_menu_selection = 'Store' + ba.app.ui.main_menu_selection = 'Store' elif sel == self._quit_button: - ba.app.main_menu_selection = 'Quit' + ba.app.ui.main_menu_selection = 'Quit' elif sel == self._demo_menu_button: - ba.app.main_menu_selection = 'DemoMenu' + ba.app.ui.main_menu_selection = 'DemoMenu' else: print('unknown widget in main menu store selection:', sel) - ba.app.main_menu_selection = 'Start' + ba.app.ui.main_menu_selection = 'Start' def _restore_state(self) -> None: # pylint: disable=too-many-branches @@ -980,7 +985,7 @@ class MainMenuWindow(ba.Window): # Don't do this for the in-game menu. if self._in_game: return - sel_name = ba.app.main_menu_selection + sel_name = ba.app.ui.main_menu_selection sel: Optional[ba.Widget] if sel_name is None: sel_name = 'Start' @@ -1012,30 +1017,30 @@ class MainMenuWindow(ba.Window): from bastd.ui.gather import GatherWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (GatherWindow( - origin_widget=self._gather_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + GatherWindow(origin_widget=self._gather_button).get_root_widget()) def _watch_press(self) -> None: # pylint: disable=cyclic-import from bastd.ui.watch import WatchWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (WatchWindow( - origin_widget=self._watch_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + WatchWindow(origin_widget=self._watch_button).get_root_widget()) def _play_press(self) -> None: # pylint: disable=cyclic-import from bastd.ui.play import PlayWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (PlayWindow( - origin_widget=self._start_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlayWindow(origin_widget=self._start_button).get_root_widget()) def _resume(self) -> None: ba.app.resume() if self._root_widget: ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = None + ba.app.ui.clear_main_menu_window() # If there's callbacks waiting for this window to go away, call them. for call in ba.app.main_menu_resume_callbacks: diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 4e7cee12..d32a9ae5 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -67,7 +67,7 @@ class OnScreenKeyboardWindow(ba.Window): scale=0.95, text=label, maxwidth=self._width - 140, - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') diff --git a/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py index a6d05cc5..0a1e8dc6 100644 --- a/assets/src/ba_data/python/bastd/ui/partyqueue.py +++ b/assets/src/ba_data/python/bastd/ui/partyqueue.py @@ -187,7 +187,7 @@ class PartyQueueWindow(ba.Window): self._boost_brightness += 0.6 def __init__(self, queue_id: str, address: str, port: int): - ba.app.have_party_queue_window = True + ba.app.ui.have_party_queue_window = True self._address = address self._port = port self._queue_id = queue_id @@ -274,7 +274,7 @@ class PartyQueueWindow(ba.Window): def __del__(self) -> None: try: - ba.app.have_party_queue_window = False + ba.app.ui.have_party_queue_window = False _ba.add_transaction({ 'type': 'PARTY_QUEUE_REMOVE', 'q': self._queue_id diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py index e1c84b25..356e67a4 100644 --- a/assets/src/ba_data/python/bastd/ui/play.py +++ b/assets/src/ba_data/python/bastd/ui/play.py @@ -92,7 +92,7 @@ class PlayWindow(ba.Window): scale=1.7, res_scale=2.0, maxwidth=400, - color=ba.app.heading_color, + color=ba.app.ui.heading_color, h_align='center', v_align='center') @@ -100,14 +100,15 @@ class PlayWindow(ba.Window): button_type='backSmall', size=(60, 60), label=ba.charstr(ba.SpecialChar.BACK)) - if ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.textwidget(edit=txt, text='') v = height - (110 if new_style else 60) v -= 100 clr = (0.6, 0.7, 0.6, 1.0) v -= 280 if new_style else 180 - v += 30 if ba.app.toolbars and uiscale is ba.UIScale.SMALL else 0 + v += (30 + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL else 0) hoffs = x_offs + 80 if new_style else 0 scl = 1.13 if new_style else 0.68 @@ -135,7 +136,7 @@ class PlayWindow(ba.Window): text_scale=1.13, on_activate_call=self._coop) - if ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.widget(edit=btn, left_widget=_ba.get_special_widget('back_button')) ba.widget(edit=btn, @@ -218,7 +219,7 @@ class PlayWindow(ba.Window): text_scale=1.13, on_activate_call=self._team_tourney) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, up_widget=_ba.get_special_widget('tickets_plus_button'), right_widget=_ba.get_special_widget('party_button')) @@ -404,7 +405,7 @@ class PlayWindow(ba.Window): maxwidth=scl * button_width * 0.7, color=clr) - if ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: back_button.delete() ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back, @@ -429,8 +430,8 @@ class PlayWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui.mainmenu import MainMenuWindow self._save_state() - ba.app.main_menu_window = (MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) ba.containerwidget(edit=self._root_widget, transition=self._transition_out) @@ -443,26 +444,29 @@ class PlayWindow(ba.Window): return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (CoopBrowserWindow( - origin_widget=self._coop_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + CoopBrowserWindow( + origin_widget=self._coop_button).get_root_widget()) def _team_tourney(self) -> None: # pylint: disable=cyclic-import from bastd.ui.playlist.browser import PlaylistBrowserWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (PlaylistBrowserWindow( - origin_widget=self._teams_button, - sessiontype=ba.DualTeamSession).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistBrowserWindow( + origin_widget=self._teams_button, + sessiontype=ba.DualTeamSession).get_root_widget()) def _free_for_all(self) -> None: # pylint: disable=cyclic-import from bastd.ui.playlist.browser import PlaylistBrowserWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (PlaylistBrowserWindow( - origin_widget=self._free_for_all_button, - sessiontype=ba.FreeForAllSession).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistBrowserWindow( + origin_widget=self._free_for_all_button, + sessiontype=ba.FreeForAllSession).get_root_widget()) def _draw_dude(self, i: int, btn: ba.Widget, hoffs: float, v: float, scl: float, position: Tuple[float, float], @@ -554,13 +558,13 @@ class PlayWindow(ba.Window): sel_name = 'Back' else: raise ValueError(f'unrecognized selection {sel}') - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name except Exception: ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) if sel_name == 'Team Games': sel = self._teams_button elif sel_name == 'Co-op Games': diff --git a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py index 12e12cc0..b1bc9990 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py @@ -75,7 +75,7 @@ class PlaylistAddGameWindow(ba.Window): label=ba.Lstr(resource='selectText'), on_activate_call=self._add) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=select_button, right_widget=_ba.get_special_widget('party_button')) @@ -85,7 +85,7 @@ class PlaylistAddGameWindow(ba.Window): scale=1.0, text=ba.Lstr(resource=self._r + '.titleText'), h_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=250, v_align='center') v = self._height - 64 diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index 01961c70..abaf4ed1 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -56,10 +56,10 @@ class PlaylistBrowserWindow(ba.Window): # Store state for when we exit the next game. if issubclass(sessiontype, ba.DualTeamSession): - ba.app.main_window = 'Team Game Select' + ba.app.ui.set_main_menu_location('Team Game Select') ba.set_analytics_screen('Teams Window') elif issubclass(sessiontype, ba.FreeForAllSession): - ba.app.main_window = 'Free-for-All Game Select' + ba.app.ui.set_main_menu_location('Free-for-All Game Select') ba.set_analytics_screen('FreeForAll Window') else: raise TypeError(f'Invalid sessiontype: {sessiontype}.') @@ -253,10 +253,10 @@ class PlaylistBrowserWindow(ba.Window): text=self._pvars.window_title_name, scale=1.3, res_scale=1.5, - color=ba.app.heading_color, + color=ba.app.ui.heading_color, h_align='center', v_align='center') - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.textwidget(edit=txt, text='') ba.buttonwidget(edit=self._back_button, @@ -265,7 +265,7 @@ class PlaylistBrowserWindow(ba.Window): position=(59 + x_inset, self._height - 67), label=ba.charstr(ba.SpecialChar.BACK)) - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: self._back_button.delete() self._back_button = None ba.containerwidget(edit=self._root_widget, @@ -274,8 +274,9 @@ class PlaylistBrowserWindow(ba.Window): else: scroll_offs = 0 self._scroll_width = self._width - (100 + 2 * x_inset) - self._scroll_height = self._height - ( - 146 if uiscale is ba.UIScale.SMALL and ba.app.toolbars else 136) + self._scroll_height = (self._height - + (146 if uiscale is ba.UIScale.SMALL + and ba.app.ui.use_toolbars else 136)) self._scrollwidget = ba.scrollwidget( parent=self._root_widget, highlight=False, @@ -351,7 +352,7 @@ class PlaylistBrowserWindow(ba.Window): size=(0, 0), scale=1.0, maxwidth=400, - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='left', v_align='center') @@ -380,11 +381,12 @@ class PlaylistBrowserWindow(ba.Window): label='', position=pos) - if x == 0 and ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if (x == 0 and ba.app.ui.use_toolbars + and uiscale is ba.UIScale.SMALL): ba.widget( edit=btn, left_widget=_ba.get_special_widget('back_button')) - if (x == columns - 1 and ba.app.toolbars + if (x == columns - 1 and ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL): ba.widget( edit=btn, @@ -604,9 +606,10 @@ class PlaylistBrowserWindow(ba.Window): PlaylistCustomizeBrowserWindow) self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (PlaylistCustomizeBrowserWindow( - origin_widget=self._customize_button, - sessiontype=self._sessiontype).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistCustomizeBrowserWindow( + origin_widget=self._customize_button, + sessiontype=self._sessiontype).get_root_widget()) def _on_back_press(self) -> None: # pylint: disable=cyclic-import @@ -625,8 +628,8 @@ class PlaylistBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (PlayWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + PlayWindow(transition='in_left').get_root_widget()) def _save_state(self) -> None: try: @@ -642,13 +645,13 @@ class PlaylistBrowserWindow(ba.Window): sel_name = 'Scroll' else: raise Exception('unrecognized selected widget') - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name except Exception: ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) if sel_name == 'Back': sel = self._back_button elif sel_name == 'Scroll': diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py index e72482f5..e0bbb9a7 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -90,7 +90,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): text=ba.Lstr(resource=self._r + '.titleText', subs=[('${TYPE}', self._pvars.window_title_name)]), - color=ba.app.heading_color, + color=ba.app.ui.heading_color, maxwidth=290, h_align='center', v_align='center') @@ -242,7 +242,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): ba.widget(edit=scrollwidget, left_widget=new_button, right_widget=_ba.get_special_widget('party_button') - if ba.app.toolbars else None) + if ba.app.ui.use_toolbars else None) # make sure config exists self._config_name_full = self._pvars.config_name + ' Playlists' @@ -285,9 +285,10 @@ class PlaylistCustomizeBrowserWindow(ba.Window): ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (browser.PlaylistBrowserWindow( - transition='in_left', - sessiontype=self._sessiontype).get_root_widget()) + ba.app.ui.set_main_menu_window( + browser.PlaylistBrowserWindow( + transition='in_left', + sessiontype=self._sessiontype).get_root_widget()) def _select(self, name: str, index: int) -> None: self._selected_playlist_name = name diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index 610e8bc7..f4569fd2 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -76,7 +76,7 @@ class PlaylistEditWindow(ba.Window): label=ba.Lstr(resource='saveText'), text_scale=1.2) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) @@ -88,7 +88,7 @@ class PlaylistEditWindow(ba.Window): position=(-10, self._height - 50), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.05, h_align='center', v_align='center', @@ -246,14 +246,16 @@ class PlaylistEditWindow(ba.Window): self._editcontroller.set_edit_ui_selection(selection) def _cancel(self) -> None: - from bastd.ui.playlist import customizebrowser as cb + from bastd.ui.playlist.customizebrowser import ( + PlaylistCustomizeBrowserWindow) ba.playsound(ba.getsound('powerdown01')) ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (cb.PlaylistCustomizeBrowserWindow( - transition='in_left', - sessiontype=self._editcontroller.get_session_type(), - select_playlist=self._editcontroller.get_existing_playlist_name()). - get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistCustomizeBrowserWindow( + transition='in_left', + sessiontype=self._editcontroller.get_session_type(), + select_playlist=self._editcontroller. + get_existing_playlist_name()).get_root_widget()) def _add(self) -> None: # Store list name then tell the session to perform an add. @@ -268,7 +270,8 @@ class PlaylistEditWindow(ba.Window): self._editcontroller.edit_game_pressed() def _save_press(self) -> None: - from bastd.ui.playlist import customizebrowser as cb + from bastd.ui.playlist.customizebrowser import ( + PlaylistCustomizeBrowserWindow) new_name = cast(str, ba.textwidget(query=self._text_field)) if (new_name != self._editcontroller.get_existing_playlist_name() and new_name @@ -316,10 +319,11 @@ class PlaylistEditWindow(ba.Window): ba.containerwidget(edit=self._root_widget, transition='out_right') ba.playsound(ba.getsound('gunCocking')) - ba.app.main_menu_window = (cb.PlaylistCustomizeBrowserWindow( - transition='in_left', - sessiontype=self._editcontroller.get_session_type(), - select_playlist=new_name).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistCustomizeBrowserWindow( + transition='in_left', + sessiontype=self._editcontroller.get_session_type(), + select_playlist=new_name).get_root_widget()) def _save_press_with_sound(self) -> None: ba.playsound(ba.getsound('swish')) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py index 5828f643..ec5ddeec 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py @@ -41,8 +41,8 @@ class PlaylistEditController: playlist: List[Dict[str, Any]] = None, playlist_name: str = None): from ba.internal import preload_map_preview_media, filter_playlist - from bastd.ui import playlist as playlistui - from bastd.ui.playlist import edit as peditui + from bastd.ui.playlist import PlaylistTypeVars + from bastd.ui.playlist.edit import PlaylistEditWindow appconfig = ba.app.config @@ -53,7 +53,7 @@ class PlaylistEditController: self._editing_game = False self._editing_game_type: Optional[Type[ba.GameActivity]] = None - self._pvars = playlistui.PlaylistTypeVars(sessiontype) + self._pvars = PlaylistTypeVars(sessiontype) self._existing_playlist_name = existing_playlist_name self._config_name_full = self._pvars.config_name + ' Playlists' @@ -96,8 +96,9 @@ class PlaylistEditController: # and that's all they can do. self._edit_ui_selection = 'add_button' - ba.app.main_menu_window = (peditui.PlaylistEditWindow( - editcontroller=self, transition=transition).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistEditWindow(editcontroller=self, + transition=transition).get_root_widget()) def get_config_name(self) -> str: """(internal)""" @@ -149,10 +150,10 @@ class PlaylistEditController: def add_game_pressed(self) -> None: """(internal)""" - from bastd.ui.playlist import addgame - ba.containerwidget(edit=ba.app.main_menu_window, transition='out_left') - ba.app.main_menu_window = (addgame.PlaylistAddGameWindow( - editcontroller=self).get_root_widget()) + from bastd.ui.playlist.addgame import PlaylistAddGameWindow + ba.app.ui.clear_main_menu_window(transition='out_left') + ba.app.ui.set_main_menu_window( + PlaylistAddGameWindow(editcontroller=self).get_root_widget()) def edit_game_pressed(self) -> None: """Should be called by supplemental UIs when a game is to be edited.""" @@ -166,11 +167,11 @@ class PlaylistEditController: def add_game_cancelled(self) -> None: """(internal)""" - from bastd.ui.playlist import edit as pedit - ba.containerwidget(edit=ba.app.main_menu_window, - transition='out_right') - ba.app.main_menu_window = (pedit.PlaylistEditWindow( - editcontroller=self, transition='in_left').get_root_widget()) + from bastd.ui.playlist.edit import PlaylistEditWindow + ba.app.ui.clear_main_menu_window(transition='out_right') + ba.app.ui.set_main_menu_window( + PlaylistEditWindow(editcontroller=self, + transition='in_left').get_root_widget()) def _show_edit_ui(self, gametype: Type[ba.GameActivity], settings: Optional[Dict[str, Any]]) -> None: @@ -185,26 +186,25 @@ class PlaylistEditController: self._show_edit_ui(gametype=gametype, settings=None) def _edit_game_done(self, config: Optional[Dict[str, Any]]) -> None: - from bastd.ui.playlist import edit as pedit - from bastd.ui.playlist import addgame + from bastd.ui.playlist.edit import PlaylistEditWindow + from bastd.ui.playlist.addgame import PlaylistAddGameWindow from ba.internal import get_type_name if config is None: # If we were editing, go back to our list. if self._editing_game: ba.playsound(ba.getsound('powerdown01')) - ba.containerwidget(edit=ba.app.main_menu_window, - transition='out_right') - ba.app.main_menu_window = (pedit.PlaylistEditWindow( - editcontroller=self, - transition='in_left').get_root_widget()) + ba.app.ui.clear_main_menu_window(transition='out_right') + ba.app.ui.set_main_menu_window( + PlaylistEditWindow(editcontroller=self, + transition='in_left').get_root_widget()) # Otherwise we were adding; go back to the add type choice list. else: - ba.containerwidget(edit=ba.app.main_menu_window, - transition='out_right') - ba.app.main_menu_window = (addgame.PlaylistAddGameWindow( - editcontroller=self, - transition='in_left').get_root_widget()) + ba.app.ui.clear_main_menu_window(transition='out_right') + ba.app.ui.set_main_menu_window( + PlaylistAddGameWindow( + editcontroller=self, + transition='in_left').get_root_widget()) else: # Make sure type is in there. assert self._editing_game_type is not None @@ -220,7 +220,7 @@ class PlaylistEditController: self._selected_index = insert_index ba.playsound(ba.getsound('gunCocking')) - ba.containerwidget(edit=ba.app.main_menu_window, - transition='out_right') - ba.app.main_menu_window = (pedit.PlaylistEditWindow( - editcontroller=self, transition='in_left').get_root_widget()) + ba.app.ui.clear_main_menu_window(transition='out_right') + ba.app.ui.set_main_menu_window( + PlaylistEditWindow(editcontroller=self, + transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index bb029ff8..750cc8f1 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -151,7 +151,7 @@ class PlaylistEditGameWindow(ba.Window): '.addGameText') if is_add else ba.Lstr( resource='doneText')) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: pbtn = _ba.get_special_widget('party_button') ba.widget(edit=add_button, right_widget=pbtn, up_widget=pbtn) @@ -159,7 +159,7 @@ class PlaylistEditGameWindow(ba.Window): position=(-8, height - 70 + y_extra2), size=(width, 25), text=gameclass.get_display_string(), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=235, scale=1.1, h_align='center', @@ -451,10 +451,11 @@ class PlaylistEditGameWindow(ba.Window): # Replace ourself with the map-select UI. ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = PlaylistMapSelectWindow( - self._gameclass, self._sessiontype, - copy.deepcopy(self._getconfig()), self._edit_info, - self._completion_call).get_root_widget() + ba.app.ui.set_main_menu_window( + PlaylistMapSelectWindow(self._gameclass, self._sessiontype, + copy.deepcopy(self._getconfig()), + self._edit_info, + self._completion_call).get_root_widget()) def _choice_inc(self, setting_name: str, widget: ba.Widget, setting: ba.ChoiceSetting, increment: int) -> None: diff --git a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py index 5b3917a1..50adc5c9 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py @@ -89,7 +89,7 @@ class PlaylistMapSelectWindow(ba.Window): subs=[('${GAME}', self._gameclass.get_display_string()) ]), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') v = height - 70 @@ -182,7 +182,7 @@ class PlaylistMapSelectWindow(ba.Window): ba.widget(edit=btn, left_widget=self._cancel_button) if y == 0: ba.widget(edit=btn, up_widget=self._cancel_button) - if x == columns - 1 and ba.app.toolbars: + if x == columns - 1 and ba.app.ui.use_toolbars: ba.widget( edit=btn, right_widget=_ba.get_special_widget('party_button')) @@ -240,17 +240,18 @@ class PlaylistMapSelectWindow(ba.Window): self._refresh(select_get_more_maps_button=True) def _select(self, map_name: str) -> None: - from bastd.ui.playlist import editgame + from bastd.ui.playlist.editgame import PlaylistEditGameWindow self._config['settings']['map'] = map_name ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (editgame.PlaylistEditGameWindow( - self._gameclass, - self._sessiontype, - self._config, - self._completion_call, - default_selection='map', - transition='in_left', - edit_info=self._edit_info).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistEditGameWindow( + self._gameclass, + self._sessiontype, + self._config, + self._completion_call, + default_selection='map', + transition='in_left', + edit_info=self._edit_info).get_root_widget()) def _select_with_delay(self, map_name: str) -> None: _ba.lock_all_input() @@ -260,13 +261,14 @@ class PlaylistMapSelectWindow(ba.Window): timetype=ba.TimeType.REAL) def _cancel(self) -> None: - from bastd.ui.playlist import editgame + from bastd.ui.playlist.editgame import PlaylistEditGameWindow ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (editgame.PlaylistEditGameWindow( - self._gameclass, - self._sessiontype, - self._config, - self._completion_call, - default_selection='map', - transition='in_left', - edit_info=self._edit_info).get_root_widget()) + ba.app.ui.set_main_menu_window( + PlaylistEditGameWindow( + self._gameclass, + self._sessiontype, + self._config, + self._completion_call, + default_selection='map', + transition='in_left', + edit_info=self._edit_info).get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/share.py b/assets/src/ba_data/python/bastd/ui/playlist/share.py index e5fcc4d0..26b47daf 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/share.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/share.py @@ -115,7 +115,7 @@ class SharePlaylistResultsWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height * 0.745), size=(0, 0), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, scale=1.0, flatness=1.0, h_align='center', @@ -128,7 +128,7 @@ class SharePlaylistResultsWindow(ba.Window): parent=self._root_widget, position=(self._width * 0.5, self._height * 0.645), size=(0, 0), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, scale=0.6, flatness=1.0, h_align='center', diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py index 6190f05e..dd434ae0 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py @@ -98,7 +98,7 @@ class ProfileBrowserWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=300, - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=0.9, h_align='center', v_align='center') @@ -160,7 +160,7 @@ class ProfileBrowserWindow(ba.Window): position=(self._width * 0.5, self._height - 71), size=(0, 0), text=ba.Lstr(resource=self._r + '.explanationText'), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, maxwidth=self._width * 0.83, scale=0.6, h_align='center', @@ -188,19 +188,18 @@ class ProfileBrowserWindow(ba.Window): def _new_profile(self) -> None: # pylint: disable=cyclic-import from ba.internal import have_pro_options - from bastd.ui.profile import edit as pedit - from bastd.ui import purchase + from bastd.ui.profile.edit import EditProfileWindow + from bastd.ui.purchase import PurchaseWindow # Limit to a handful profiles if they don't have pro-options. max_non_pro_profiles = _ba.get_account_misc_read_val('mnpp', 5) assert self._profiles is not None if (not have_pro_options() and len(self._profiles) >= max_non_pro_profiles): - purchase.PurchaseWindow(items=['pro'], - header_text=ba.Lstr( - resource='unlockThisProfilesText', - subs=[('${NUM}', - str(max_non_pro_profiles))])) + PurchaseWindow(items=['pro'], + header_text=ba.Lstr( + resource='unlockThisProfilesText', + subs=[('${NUM}', str(max_non_pro_profiles))])) return # Clamp at 100 profiles (otherwise the server will and that's less @@ -215,9 +214,10 @@ class ProfileBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (pedit.EditProfileWindow( - existing_profile=None, - in_main_menu=self._in_main_menu).get_root_widget()) + ba.app.ui.set_main_menu_window( + EditProfileWindow( + existing_profile=None, + in_main_menu=self._in_main_menu).get_root_widget()) def _delete_profile(self) -> None: # pylint: disable=cyclic-import @@ -253,7 +253,7 @@ class ProfileBrowserWindow(ba.Window): def _edit_profile(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.profile import edit as pedit + from bastd.ui.profile.edit import EditProfileWindow if self._selected_profile is None: ba.playsound(ba.getsound('error')) ba.screenmessage(ba.Lstr(resource='nothingIsSelectedErrorText'), @@ -261,9 +261,10 @@ class ProfileBrowserWindow(ba.Window): return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (pedit.EditProfileWindow( - self._selected_profile, - in_main_menu=self._in_main_menu).get_root_widget()) + ba.app.ui.set_main_menu_window( + EditProfileWindow( + self._selected_profile, + in_main_menu=self._in_main_menu).get_root_widget()) def _select(self, name: str, index: int) -> None: del index # Unused. @@ -271,13 +272,13 @@ class ProfileBrowserWindow(ba.Window): def _back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.account import settings + from bastd.ui.account.settings import AccountSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if self._in_main_menu: - ba.app.main_menu_window = (settings.AccountSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + AccountSettingsWindow(transition='in_left').get_root_widget()) # If we're being called up standalone, handle pause/resume ourself. else: @@ -363,13 +364,13 @@ class ProfileBrowserWindow(ba.Window): sel_name = 'Scroll' else: sel_name = 'Back' - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name except Exception: ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) if sel_name == 'Scroll': sel = self._scrollwidget elif sel_name == 'New': diff --git a/assets/src/ba_data/python/bastd/ui/profile/edit.py b/assets/src/ba_data/python/bastd/ui/profile/edit.py index 748219dd..0577a769 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/edit.py +++ b/assets/src/ba_data/python/bastd/ui/profile/edit.py @@ -40,8 +40,9 @@ class EditProfileWindow(ba.Window): def reload_window(self) -> None: """Transitions out and recreates ourself.""" ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = EditProfileWindow( - self.getname(), self._in_main_menu).get_root_widget() + ba.app.ui.set_main_menu_window( + EditProfileWindow(self.getname(), + self._in_main_menu).get_root_widget()) def __init__(self, existing_profile: Optional[str], @@ -102,7 +103,7 @@ class EditProfileWindow(ba.Window): text=(ba.Lstr(resource=self._r + '.titleNewText') if existing_profile is None else ba.Lstr( resource=self._r + '.titleEditText')), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=290, scale=1.0, h_align='center', @@ -211,7 +212,7 @@ class EditProfileWindow(ba.Window): position=(self._width * 0.5, v - 39), size=(0, 0), scale=0.6, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=txtl, maxwidth=270, h_align='center', @@ -258,7 +259,7 @@ class EditProfileWindow(ba.Window): draw_controller=btn, text=ba.Lstr(resource=self._r + '.iconText'), scale=0.7, - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=120) self._update_icon() @@ -281,7 +282,7 @@ class EditProfileWindow(ba.Window): position=(self._width * 0.5, v - 39), size=(0, 0), scale=0.6, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=txtl, maxwidth=240, h_align='center', @@ -322,7 +323,7 @@ class EditProfileWindow(ba.Window): position=(self._width * 0.5, v - 43), size=(0, 0), scale=0.6, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, text=txtl, maxwidth=270, h_align='center', @@ -379,7 +380,7 @@ class EditProfileWindow(ba.Window): draw_controller=btn, text=ba.Lstr(resource=self._r + '.colorText'), scale=0.7, - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=120) self._character_button = btn = ba.buttonwidget( @@ -403,7 +404,7 @@ class EditProfileWindow(ba.Window): draw_controller=btn, text=ba.Lstr(resource=self._r + '.characterText'), scale=0.7, - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=130) self._highlight_button = btn = ba.buttonwidget( @@ -436,7 +437,7 @@ class EditProfileWindow(ba.Window): draw_controller=btn, text=ba.Lstr(resource=self._r + '.highlightText'), scale=0.7, - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=120) self._update_character() @@ -559,12 +560,13 @@ class EditProfileWindow(ba.Window): tag=picker_type) def _cancel(self) -> None: - from bastd.ui.profile import browser as pbrowser + from bastd.ui.profile.browser import ProfileBrowserWindow ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = pbrowser.ProfileBrowserWindow( - 'in_left', - selected_profile=self._existing_profile, - in_main_menu=self._in_main_menu).get_root_widget() + ba.app.ui.set_main_menu_window( + ProfileBrowserWindow( + 'in_left', + selected_profile=self._existing_profile, + in_main_menu=self._in_main_menu).get_root_widget()) def _set_color(self, color: Tuple[float, float, float]) -> None: self._color = color @@ -644,7 +646,7 @@ class EditProfileWindow(ba.Window): def save(self, transition_out: bool = True) -> bool: """Save has been selected.""" - from bastd.ui.profile import browser as pbrowser + from bastd.ui.profile.browser import ProfileBrowserWindow new_name = self.getname().strip() if not new_name: @@ -681,8 +683,9 @@ class EditProfileWindow(ba.Window): if transition_out: _ba.run_transactions() ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (pbrowser.ProfileBrowserWindow( - 'in_left', - selected_profile=new_name, - in_main_menu=self._in_main_menu).get_root_widget()) + ba.app.ui.set_main_menu_window( + ProfileBrowserWindow( + 'in_left', + selected_profile=new_name, + in_main_menu=self._in_main_menu).get_root_widget()) return True diff --git a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py index 83876011..a08de529 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py +++ b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py @@ -84,7 +84,7 @@ class ProfileUpgradeWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.upgradeToGlobalProfileText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=self._width * 0.45, scale=1.0, h_align='center', @@ -95,7 +95,7 @@ class ProfileUpgradeWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.upgradeProfileInfoText'), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, maxwidth=self._width * 0.8, scale=0.7, h_align='center', @@ -125,7 +125,7 @@ class ProfileUpgradeWindow(ba.Window): v_align='center') self._tickets_text: Optional[ba.Widget] - if not ba.app.toolbars: + if not ba.app.ui.use_toolbars: self._tickets_text = ba.textwidget( parent=self._root_widget, position=(self._width * 0.9 - 5, self._height - 30), diff --git a/assets/src/ba_data/python/bastd/ui/promocode.py b/assets/src/ba_data/python/bastd/ui/promocode.py index 5469dd5a..5959a411 100644 --- a/assets/src/ba_data/python/bastd/ui/promocode.py +++ b/assets/src/ba_data/python/bastd/ui/promocode.py @@ -110,24 +110,24 @@ class PromoCodeWindow(ba.Window): def _do_back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import advanced + from bastd.ui.settings.advanced import AdvancedSettingsWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if not self._modal: - ba.app.main_menu_window = (advanced.AdvancedSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + AdvancedSettingsWindow(transition='in_left').get_root_widget()) def _activate_enter_button(self) -> None: self._enter_button.activate() def _do_enter(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import advanced + from bastd.ui.settings.advanced import AdvancedSettingsWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if not self._modal: - ba.app.main_menu_window = (advanced.AdvancedSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + AdvancedSettingsWindow(transition='in_left').get_root_widget()) _ba.add_transaction({ 'type': 'PROMO_CODE', 'expire_time': time.time() + 5, diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index dffa1274..50c5d8f6 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -98,7 +98,7 @@ class AdvancedSettingsWindow(ba.Window): self._r = 'settingsWindowAdvanced' - if app.toolbars and uiscale is ba.UIScale.SMALL: + if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._do_back) self._back_button = None @@ -120,7 +120,7 @@ class AdvancedSettingsWindow(ba.Window): size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=app.title_color, + color=app.ui.title_color, h_align='center', v_align='top') @@ -238,7 +238,7 @@ class AdvancedSettingsWindow(ba.Window): text=ba.Lstr(resource=self._r + '.languageText'), maxwidth=150, scale=0.95, - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='right', v_align='center') @@ -500,7 +500,7 @@ class AdvancedSettingsWindow(ba.Window): for child in self._subcontainer.get_children(): ba.widget(edit=child, show_buffer_bottom=30, show_buffer_top=20) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: pbtn = _ba.get_special_widget('party_button') ba.widget(edit=self._scrollwidget, right_widget=pbtn) if self._back_button is None: @@ -523,18 +523,18 @@ class AdvancedSettingsWindow(ba.Window): _ba.run_transactions() def _on_vr_test_press(self) -> None: - from bastd.ui.settings import vrtesting + from bastd.ui.settings.vrtesting import VRTestingWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (vrtesting.VRTestingWindow( - transition='in_right').get_root_widget()) + ba.app.ui.set_main_menu_window( + VRTestingWindow(transition='in_right').get_root_widget()) def _on_net_test_press(self) -> None: - from bastd.ui.settings import nettesting + from bastd.ui.settings.nettesting import NetTestingWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (nettesting.NetTestingWindow( - transition='in_right').get_root_widget()) + ba.app.ui.set_main_menu_window( + NetTestingWindow(transition='in_right').get_root_widget()) def _on_friend_promo_code_press(self) -> None: from bastd.ui import appinvite @@ -545,24 +545,25 @@ class AdvancedSettingsWindow(ba.Window): appinvite.handle_app_invites_press() def _on_promo_code_press(self) -> None: - from bastd.ui import promocode - from bastd.ui import account + from bastd.ui.promocode import PromoCodeWindow + from bastd.ui.account import show_sign_in_prompt # We have to be logged in for promo-codes to work. if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (promocode.PromoCodeWindow( - origin_widget=self._promo_code_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + PromoCodeWindow( + origin_widget=self._promo_code_button).get_root_widget()) def _on_benchmark_press(self) -> None: - from bastd.ui import debug + from bastd.ui.debug import DebugWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (debug.DebugWindow( - transition='in_right').get_root_widget()) + ba.app.ui.set_main_menu_window( + DebugWindow(transition='in_right').get_root_widget()) def _save_state(self) -> None: # pylint: disable=too-many-branches @@ -603,7 +604,7 @@ class AdvancedSettingsWindow(ba.Window): sel_name = 'Back' else: raise ValueError(f'unrecognized selection \'{sel}\'') - ba.app.window_states[self.__class__.__name__] = { + ba.app.ui.window_states[self.__class__.__name__] = { 'sel_name': sel_name } except Exception: @@ -612,8 +613,8 @@ class AdvancedSettingsWindow(ba.Window): def _restore_state(self) -> None: # pylint: disable=too-many-branches try: - sel_name = ba.app.window_states.get(self.__class__.__name__, - {}).get('sel_name') + sel_name = ba.app.ui.window_states.get(self.__class__.__name__, + {}).get('sel_name') if sel_name == 'Back': sel = self._back_button else: @@ -678,9 +679,9 @@ class AdvancedSettingsWindow(ba.Window): timetype=ba.TimeType.REAL) def _do_back(self) -> None: - from bastd.ui.settings import allsettings + from bastd.ui.settings.allsettings import AllSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (allsettings.AllSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + AllSettingsWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index 702e3e0a..64f918c2 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -72,7 +72,7 @@ class AllSettingsWindow(ba.Window): 1.35 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -8) if uiscale is ba.UIScale.SMALL else (0, 0))) - if ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None ba.containerwidget(edit=self._root_widget, on_cancel_call=self._do_back) @@ -93,7 +93,7 @@ class AllSettingsWindow(ba.Window): position=(0, height - 44), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', maxwidth=130) @@ -136,7 +136,7 @@ class AllSettingsWindow(ba.Window): button_type='square', label='', on_activate_call=self._do_controllers) - if ba.app.toolbars and self._back_button is None: + if ba.app.ui.use_toolbars and self._back_button is None: bbtn = _ba.get_special_widget('back_button') ba.widget(edit=ctb, left_widget=bbtn) _b_title(x_offs2, v, ctb, @@ -156,7 +156,7 @@ class AllSettingsWindow(ba.Window): button_type='square', label='', on_activate_call=self._do_graphics) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: pbtn = _ba.get_special_widget('party_button') ba.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn) _b_title(x_offs3, v, gfxb, ba.Lstr(resource=self._r + '.graphicsText')) @@ -220,40 +220,44 @@ class AllSettingsWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) def _do_controllers(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.controls import ControlsSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (ControlsSettingsWindow( - origin_widget=self._controllers_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + ControlsSettingsWindow( + origin_widget=self._controllers_button).get_root_widget()) def _do_graphics(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.graphics import GraphicsSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (GraphicsSettingsWindow( - origin_widget=self._graphics_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + GraphicsSettingsWindow( + origin_widget=self._graphics_button).get_root_widget()) def _do_audio(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.audio import AudioSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (AudioSettingsWindow( - origin_widget=self._audio_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + AudioSettingsWindow( + origin_widget=self._audio_button).get_root_widget()) def _do_advanced(self) -> None: # pylint: disable=cyclic-import from bastd.ui.settings.advanced import AdvancedSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (AdvancedSettingsWindow( - origin_widget=self._advanced_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + AdvancedSettingsWindow( + origin_widget=self._advanced_button).get_root_widget()) def _save_state(self) -> None: try: @@ -270,7 +274,7 @@ class AllSettingsWindow(ba.Window): sel_name = 'Back' else: raise ValueError(f'unrecognized selection \'{sel}\'') - ba.app.window_states[self.__class__.__name__] = { + ba.app.ui.window_states[self.__class__.__name__] = { 'sel_name': sel_name } except Exception: @@ -278,8 +282,8 @@ class AllSettingsWindow(ba.Window): def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__, - {}).get('sel_name') + sel_name = ba.app.ui.window_states.get(self.__class__.__name__, + {}).get('sel_name') sel: Optional[ba.Widget] if sel_name == 'Controllers': sel = self._controllers_button diff --git a/assets/src/ba_data/python/bastd/ui/settings/audio.py b/assets/src/ba_data/python/bastd/ui/settings/audio.py index c7e8d970..185339c9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/audio.py +++ b/assets/src/ba_data/python/bastd/ui/settings/audio.py @@ -103,7 +103,7 @@ class AudioSettingsWindow(ba.Window): position=(width * 0.5, height - 32), size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=180, h_align='center', v_align='center') @@ -122,7 +122,7 @@ class AudioSettingsWindow(ba.Window): minval=0.0, maxval=1.0, increment=0.1) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=svne.plusbutton, right_widget=_ba.get_special_widget('party_button')) v -= spacing @@ -237,8 +237,9 @@ class AudioSettingsWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (stb.SoundtrackBrowserWindow( - origin_widget=self._soundtrack_button).get_root_widget()) + ba.app.ui.set_main_menu_window( + stb.SoundtrackBrowserWindow( + origin_widget=self._soundtrack_button).get_root_widget()) def _back(self) -> None: # pylint: disable=cyclic-import @@ -246,8 +247,9 @@ class AudioSettingsWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (allsettings.AllSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + allsettings.AllSettingsWindow( + transition='in_left').get_root_widget()) def _save_state(self) -> None: try: @@ -268,13 +270,13 @@ class AudioSettingsWindow(ba.Window): sel_name = 'VRHeadRelative' else: raise ValueError(f'unrecognized selection \'{sel}\'') - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name except Exception: ba.print_exception(f'Error saving state for {self.__class__}.') def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) sel: Optional[ba.Widget] if sel_name == 'SoundMinus': sel = self._sound_volume_numedit.minusbutton diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index a59e39ba..c20e448a 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -178,7 +178,7 @@ class ControlsSettingsWindow(ba.Window): position=(0, height - 49), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='top') ba.buttonwidget(edit=btn, @@ -197,7 +197,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.configureTouchText'), on_activate_call=self._do_touchscreen) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: @@ -216,7 +216,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.configureControllersText'), on_activate_call=self._do_gamepads) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: @@ -240,7 +240,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.configureKeyboardText'), on_activate_call=self._config_keyboard) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: @@ -269,7 +269,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.configureMobileText'), on_activate_call=self._do_mobile_devices) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: @@ -287,7 +287,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.ps3Text'), on_activate_call=self._do_ps3_controllers) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) v -= spacing @@ -299,7 +299,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.xbox360Text'), on_activate_call=self._do_360_controllers) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) v -= spacing @@ -311,7 +311,7 @@ class ControlsSettingsWindow(ba.Window): autoselect=True, label=ba.Lstr(resource=self._r + '.wiimotesText'), on_activate_call=self._do_wiimotes) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=btn, right_widget=_ba.get_special_widget('party_button')) v -= spacing @@ -342,7 +342,7 @@ class ControlsSettingsWindow(ba.Window): scale=0.5, h_align='center', v_align='center', - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, maxwidth=width * 0.8) v -= spacing if show_mac_controller_subsystem: @@ -369,7 +369,7 @@ class ControlsSettingsWindow(ba.Window): scale=1.0, h_align='right', v_align='center', - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, maxwidth=180) ba.textwidget( parent=self._root_widget, @@ -379,7 +379,7 @@ class ControlsSettingsWindow(ba.Window): scale=0.5, h_align='center', v_align='center', - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, maxwidth=width * 0.8) v -= spacing self._restore_state() @@ -391,67 +391,69 @@ class ControlsSettingsWindow(ba.Window): def _config_keyboard(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import keyboard + from bastd.ui.settings.keyboard import ConfigKeyboardWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (keyboard.ConfigKeyboardWindow( - _ba.getinputdevice('Keyboard', '#1')).get_root_widget()) + ba.app.ui.set_main_menu_window( + ConfigKeyboardWindow(_ba.getinputdevice('Keyboard', + '#1')).get_root_widget()) def _config_keyboard2(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import keyboard + from bastd.ui.settings.keyboard import ConfigKeyboardWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (keyboard.ConfigKeyboardWindow( - _ba.getinputdevice('Keyboard', '#2')).get_root_widget()) + ba.app.ui.set_main_menu_window( + ConfigKeyboardWindow(_ba.getinputdevice('Keyboard', + '#2')).get_root_widget()) def _do_mobile_devices(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import remoteapp + from bastd.ui.settings.remoteapp import RemoteAppSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = ( - remoteapp.RemoteAppSettingsWindow().get_root_widget()) + ba.app.ui.set_main_menu_window( + RemoteAppSettingsWindow().get_root_widget()) def _do_ps3_controllers(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import ps3controller + from bastd.ui.settings.ps3controller import PS3ControllerSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = ( - ps3controller.PS3ControllerSettingsWindow().get_root_widget()) + ba.app.ui.set_main_menu_window( + PS3ControllerSettingsWindow().get_root_widget()) def _do_360_controllers(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import xbox360controller as xbox + from bastd.ui.settings.xbox360controller import ( + XBox360ControllerSettingsWindow) self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = ( - xbox.XBox360ControllerSettingsWindow().get_root_widget()) + ba.app.ui.set_main_menu_window( + XBox360ControllerSettingsWindow().get_root_widget()) def _do_wiimotes(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import wiimote + from bastd.ui.settings.wiimote import WiimoteSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = ( - wiimote.WiimoteSettingsWindow().get_root_widget()) + ba.app.ui.set_main_menu_window( + WiimoteSettingsWindow().get_root_widget()) def _do_gamepads(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import gamepadselect + from bastd.ui.settings.gamepadselect import GamepadSelectWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = ( - gamepadselect.GamepadSelectWindow().get_root_widget()) + ba.app.ui.set_main_menu_window(GamepadSelectWindow().get_root_widget()) def _do_touchscreen(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import touchscreen + from bastd.ui.settings.touchscreen import TouchscreenSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = ( - touchscreen.TouchscreenSettingsWindow().get_root_widget()) + ba.app.ui.set_main_menu_window( + TouchscreenSettingsWindow().get_root_widget()) def _save_state(self) -> None: sel = self._root_widget.get_selected_child() @@ -473,10 +475,10 @@ class ControlsSettingsWindow(ba.Window): sel_name = 'Wiimotes' else: sel_name = 'Back' - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name def _restore_state(self) -> None: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) if sel_name == 'GamePads': sel = self._gamepads_button elif sel_name == 'Touch': @@ -502,9 +504,9 @@ class ControlsSettingsWindow(ba.Window): def _back(self) -> None: # pylint: disable=cyclic-import - from bastd.ui.settings import allsettings + from bastd.ui.settings.allsettings import AllSettingsWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = allsettings.AllSettingsWindow( - transition='in_left').get_root_widget() + ba.app.ui.set_main_menu_window( + AllSettingsWindow(transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index e27ba546..7305ccd1 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -202,7 +202,7 @@ class GamepadSettingsWindow(ba.Window): position=(0, v + 5), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=310, h_align='center', v_align='center') @@ -212,7 +212,7 @@ class GamepadSettingsWindow(ba.Window): position=(0, v + 3), size=(self._width, 25), text=self._name, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, maxwidth=self._width * 0.9, h_align='center', v_align='center') @@ -235,7 +235,7 @@ class GamepadSettingsWindow(ba.Window): position=(0, v + 5), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.secondaryText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=300, h_align='center', v_align='center') @@ -710,12 +710,12 @@ class GamepadSettingsWindow(ba.Window): return btn def _cancel(self) -> None: - from bastd.ui.settings import controls + from bastd.ui.settings.controls import ControlsSettingsWindow ba.containerwidget(edit=self._root_widget, transition=self._transition_out) if self._is_main_menu: - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + ControlsSettingsWindow(transition='in_left').get_root_widget()) def _save(self) -> None: from ba.internal import (master_server_post, get_input_device_config, @@ -758,9 +758,9 @@ class GamepadSettingsWindow(ba.Window): ba.playsound(ba.getsound('error')) if self._is_main_menu: - from bastd.ui.settings import controls - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + from bastd.ui.settings.controls import ControlsSettingsWindow + ba.app.ui.set_main_menu_window( + ControlsSettingsWindow(transition='in_left').get_root_widget()) class AwaitGamepadInputWindow(ba.Window): diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py index d4631aed..ad5ba704 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py @@ -61,7 +61,7 @@ class GamepadAdvancedSettingsWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.advancedTitleText'), maxwidth=320, - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py index 9b063425..e2b14c5e 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py @@ -41,7 +41,7 @@ def gamepad_configure_callback(event: Dict[str, Any]) -> None: return _ba.release_gamepad_input() try: - ba.containerwidget(edit=ba.app.main_menu_window, transition='out_left') + ba.app.ui.clear_main_menu_window(transition='out_left') except Exception: ba.print_exception('Error transitioning out main_menu_window.') ba.playsound(ba.getsound('activateBeep')) @@ -49,18 +49,19 @@ def gamepad_configure_callback(event: Dict[str, Any]) -> None: inputdevice = event['input_device'] assert isinstance(inputdevice, ba.InputDevice) if inputdevice.allows_configuring: - ba.app.main_menu_window = ( + ba.app.ui.set_main_menu_window( gamepad.GamepadSettingsWindow(inputdevice).get_root_widget()) else: width = 700 height = 200 button_width = 100 uiscale = ba.app.uiscale - ba.app.main_menu_window = dlg = (ba.containerwidget( + dlg = (ba.containerwidget( scale=(1.7 if uiscale is ba.UIScale.SMALL else 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), size=(width, height), transition='in_right')) + ba.app.ui.set_main_menu_window(dlg) device_name = inputdevice.name if device_name == 'iDevice': msg = ba.Lstr(resource='bsRemoteConfigureInAppText', @@ -79,8 +80,9 @@ def gamepad_configure_callback(event: Dict[str, Any]) -> None: def _ok() -> None: from bastd.ui.settings import controls ba.containerwidget(edit=dlg, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) ba.buttonwidget(parent=dlg, position=((width - button_width) / 2, 20), @@ -124,7 +126,7 @@ class GamepadSelectWindow(ba.Window): size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=250, - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') @@ -141,7 +143,7 @@ class GamepadSelectWindow(ba.Window): scale=0.8, text=ba.Lstr(resource=self._r + '.pressAnyButtonText'), maxwidth=width * 0.95, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, h_align='center', v_align='top') v -= spacing * 1.24 @@ -162,5 +164,6 @@ class GamepadSelectWindow(ba.Window): from bastd.ui.settings import controls _ba.release_gamepad_input() ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/graphics.py b/assets/src/ba_data/python/bastd/ui/settings/graphics.py index 411b21a6..3bda574b 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/graphics.py +++ b/assets/src/ba_data/python/bastd/ui/settings/graphics.py @@ -112,7 +112,7 @@ class GraphicsSettingsWindow(ba.Window): position=(0, height - 44), size=(width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='top') @@ -153,7 +153,7 @@ class GraphicsSettingsWindow(ba.Window): increment=0.1, xoffset=-70, textscale=0.85) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=gmc.plusbutton, right_widget=_ba.get_special_widget('party_button')) if not self._have_selected_child: @@ -172,7 +172,7 @@ class GraphicsSettingsWindow(ba.Window): position=(60, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.visualsText'), - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', @@ -200,7 +200,7 @@ class GraphicsSettingsWindow(ba.Window): position=(230, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.texturesText'), - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', @@ -219,7 +219,7 @@ class GraphicsSettingsWindow(ba.Window): ], current_choice=ba.app.config.resolve('Texture Quality'), on_value_change_call=self._set_textures) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=textures_popup.get_button(), right_widget=_ba.get_special_widget('party_button')) v -= 80 @@ -232,7 +232,7 @@ class GraphicsSettingsWindow(ba.Window): position=(h_offs + 60, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.resolutionText'), - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', @@ -306,7 +306,7 @@ class GraphicsSettingsWindow(ba.Window): position=(230, v), size=(160, 25), text=ba.Lstr(resource=self._r + '.verticalSyncText'), - color=ba.app.heading_color, + color=ba.app.ui.heading_color, scale=0.65, maxwidth=150, h_align='center', @@ -367,8 +367,9 @@ class GraphicsSettingsWindow(ba.Window): from bastd.ui.settings import allsettings ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (allsettings.AllSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + allsettings.AllSettingsWindow( + transition='in_left').get_root_widget()) def _set_quality(self, quality: str) -> None: cfg = ba.app.config diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index 8796bc4c..f030eba1 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -102,7 +102,7 @@ class ConfigKeyboardWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.configuringText', subs=[('${DEVICE}', self._displayname)]), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', maxwidth=270, @@ -120,7 +120,7 @@ class ConfigKeyboardWindow(ba.Window): scale=0.7, maxwidth=self._width * 0.75, max_height=110, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, h_align='center', v_align='top') v -= 40 @@ -226,8 +226,8 @@ class ConfigKeyboardWindow(ba.Window): def _cancel(self) -> None: from bastd.ui.settings.controls import ControlsSettingsWindow ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + ControlsSettingsWindow(transition='in_left').get_root_widget()) def _save(self) -> None: from bastd.ui.settings.controls import ControlsSettingsWindow @@ -257,8 +257,8 @@ class ConfigKeyboardWindow(ba.Window): 'v': 2 }) ba.app.config.apply_and_commit() - ba.app.main_menu_window = (ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + ControlsSettingsWindow(transition='in_left').get_root_widget()) class AwaitKeyboardInputWindow(ba.Window): diff --git a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py index 3598a39a..25b6eada 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py @@ -58,7 +58,7 @@ class PS3ControllerSettingsWindow(ba.Window): text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') @@ -120,5 +120,6 @@ class PS3ControllerSettingsWindow(ba.Window): def _back(self) -> None: from bastd.ui.settings import controls ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py index d47f54fb..8c4bf58f 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py +++ b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py @@ -57,7 +57,7 @@ class RemoteAppSettingsWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=370, - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=0.8, h_align='center', v_align='center') @@ -131,5 +131,6 @@ class RemoteAppSettingsWindow(ba.Window): def _back(self) -> None: from bastd.ui.settings import controls ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/testing.py b/assets/src/ba_data/python/bastd/ui/settings/testing.py index 63ca41d8..9619c000 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/testing.py +++ b/assets/src/ba_data/python/bastd/ui/settings/testing.py @@ -62,7 +62,7 @@ class TestingWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 35), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', maxwidth=245, @@ -77,7 +77,7 @@ class TestingWindow(ba.Window): parent=self._root_widget, position=(self._width * 0.5, self._height - 75), size=(0, 0), - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, h_align='center', v_align='center', maxwidth=self._width * 0.75, @@ -194,6 +194,6 @@ class TestingWindow(ba.Window): # pylint: disable=cyclic-import import bastd.ui.settings.advanced ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = ( + ba.app.ui.set_main_menu_window( bastd.ui.settings.advanced.AdvancedSettingsWindow( transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py index 59faf44b..be30d230 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py +++ b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py @@ -65,7 +65,7 @@ class TouchscreenSettingsWindow(ba.Window): position=(25, self._height - 50), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=280, h_align='center', v_align='center') @@ -251,6 +251,7 @@ class TouchscreenSettingsWindow(ba.Window): def _back(self) -> None: from bastd.ui.settings import controls ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) _ba.set_touchscreen_editing(False) diff --git a/assets/src/ba_data/python/bastd/ui/settings/wiimote.py b/assets/src/ba_data/python/bastd/ui/settings/wiimote.py index dfca0b33..4daf8440 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/wiimote.py +++ b/assets/src/ba_data/python/bastd/ui/settings/wiimote.py @@ -52,7 +52,7 @@ class WiimoteSettingsWindow(ba.Window): size=(0, 0), text=ba.Lstr(resource=self._r + '.titleText'), maxwidth=270, - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') @@ -108,8 +108,9 @@ class WiimoteSettingsWindow(ba.Window): def _back(self) -> None: from bastd.ui.settings import controls ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) class WiimoteListenWindow(ba.Window): @@ -131,12 +132,12 @@ class WiimoteListenWindow(ba.Window): ba.containerwidget(edit=self._root_widget, cancel_button=btn) _ba.start_listening_for_wii_remotes() self._wiimote_connect_counter = 15 - ba.app.dismiss_wii_remotes_window_call = ba.WeakCall(self._dismiss) + ba.app.ui.dismiss_wii_remotes_window_call = ba.WeakCall(self._dismiss) ba.textwidget(parent=self._root_widget, position=(15, height - 55), size=(width - 30, 30), text=ba.Lstr(resource=self._r + '.listeningText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=320, h_align='center', v_align='center') @@ -204,7 +205,7 @@ class WiimoteLicenseWindow(ba.Window): size=(width, 30), text=ba.Lstr(resource=self._r + '.titleText'), h_align='center', - color=ba.app.title_color, + color=ba.app.ui.title_color, v_align='center') license_text = ( 'Copyright (c) 2007, DarwiinRemote Team\n' diff --git a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py index b65b48ec..334431a9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py @@ -63,7 +63,7 @@ class XBox360ControllerSettingsWindow(ba.Window): text=ba.Lstr(resource=self._r + '.titleText', subs=[('${APP_NAME}', ba.Lstr(resource='titleText'))]), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=400, h_align='center', v_align='center') @@ -128,5 +128,6 @@ class XBox360ControllerSettingsWindow(ba.Window): def _back(self) -> None: from bastd.ui.settings import controls ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (controls.ControlsSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + controls.ControlsSettingsWindow( + transition='in_left').get_root_widget()) diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py index a796229b..38fe0817 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py @@ -70,7 +70,7 @@ class SoundtrackBrowserWindow(ba.Window): 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0), stack_offset=(0, -18) if uiscale is ba.UIScale.SMALL else (0, 0))) - if ba.app.toolbars and uiscale is ba.UIScale.SMALL: + if ba.app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: self._back_button = None else: self._back_button = ba.buttonwidget( @@ -90,7 +90,7 @@ class SoundtrackBrowserWindow(ba.Window): size=(0, 0), maxwidth=300, text=ba.Lstr(resource=self._r + '.titleText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center') @@ -210,7 +210,7 @@ class SoundtrackBrowserWindow(ba.Window): ba.widget(edit=self._scrollwidget, left_widget=self._new_button, right_widget=_ba.get_special_widget('party_button') - if ba.app.toolbars else self._scrollwidget) + if ba.app.ui.use_toolbars else self._scrollwidget) self._col = ba.columnwidget(parent=scrollwidget) self._soundtracks: Optional[Dict[str, Any]] = None @@ -337,8 +337,8 @@ class SoundtrackBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (audio.AudioSettingsWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + audio.AudioSettingsWindow(transition='in_left').get_root_widget()) def _edit_soundtrack_with_sound(self) -> None: # pylint: disable=cyclic-import @@ -369,8 +369,10 @@ class SoundtrackBrowserWindow(ba.Window): self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (stedit.SoundtrackEditWindow( - existing_soundtrack=self._selected_soundtrack).get_root_widget()) + ba.app.ui.set_main_menu_window( + stedit.SoundtrackEditWindow( + existing_soundtrack=self._selected_soundtrack).get_root_widget( + )) def _get_soundtrack_display_name(self, soundtrack: str) -> ba.Lstr: if soundtrack == '__default__': @@ -485,13 +487,13 @@ class SoundtrackBrowserWindow(ba.Window): sel_name = 'Back' else: raise ValueError(f'unrecognized selection \'{sel}\'') - ba.app.window_states[self.__class__.__name__] = sel_name + ba.app.ui.window_states[self.__class__.__name__] = sel_name except Exception: ba.print_exception(f'Error saving state for {self}.') def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__) + sel_name = ba.app.ui.window_states.get(self.__class__.__name__) if sel_name == 'Scroll': sel = self._scrollwidget elif sel_name == 'New': diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py index 484757ff..be5d754a 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py @@ -78,7 +78,7 @@ class SoundtrackEditWindow(ba.Window): text=ba.Lstr(resource=self._r + ('.editSoundtrackText' if existing_soundtrack is not None else '.newSoundtrackText')), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', maxwidth=280) @@ -310,8 +310,8 @@ class SoundtrackEditWindow(ba.Window): else: soundtrack[musictype] = entry - ba.app.main_menu_window = (cls(state, - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + cls(state, transition='in_left').get_root_widget()) def _get_entry(self, song_type: str, entry: Any, selection_target_name: str) -> None: @@ -325,7 +325,7 @@ class SoundtrackEditWindow(ba.Window): 'last_edited_song_type': song_type } ba.containerwidget(edit=self._root_widget, transition='out_left') - ba.app.main_menu_window = (music.get_music_player().select_entry( + ba.app.ui.set_main_menu_window(music.get_music_player().select_entry( ba.Call(self._restore_editor, state, song_type), entry, selection_target_name).get_root_widget()) @@ -372,8 +372,9 @@ class SoundtrackEditWindow(ba.Window): # Resets music back to normal. music.set_music_play_mode(ba.MusicPlayMode.REGULAR) ba.containerwidget(edit=self._root_widget, transition='out_right') - ba.app.main_menu_window = (stb.SoundtrackBrowserWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + stb.SoundtrackBrowserWindow( + transition='in_left').get_root_widget()) def _do_it(self) -> None: from bastd.ui.soundtrack import browser as stb @@ -414,8 +415,9 @@ class SoundtrackEditWindow(ba.Window): # Resets music back to normal. music.set_music_play_mode(ba.MusicPlayMode.REGULAR, force_restart=True) - ba.app.main_menu_window = (stb.SoundtrackBrowserWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + stb.SoundtrackBrowserWindow( + transition='in_left').get_root_widget()) def _do_it_with_sound(self) -> None: ba.playsound(ba.getsound('swish')) diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py index b1652672..6c105975 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @@ -82,7 +82,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window): position=(self._width * 0.5, self._height - 32), size=(0, 0), text=ba.Lstr(resource=self._r + '.selectASourceText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, maxwidth=230, h_align='center', v_align='center') @@ -91,7 +91,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window): position=(self._width * 0.5, self._height - 56), size=(0, 0), text=selection_target_name, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, scale=0.7, maxwidth=230, h_align='center', @@ -161,33 +161,36 @@ class SoundtrackEntryTypeSelectWindow(ba.Window): self._current_entry) else: current_playlist_entry = None - ba.app.main_menu_window = (macmusicapp.MacMusicAppPlaylistSelectWindow( - self._callback, current_playlist_entry, - self._current_entry).get_root_widget()) + ba.app.ui.set_main_menu_window( + macmusicapp.MacMusicAppPlaylistSelectWindow( + self._callback, current_playlist_entry, + self._current_entry).get_root_widget()) def _on_music_file_press(self) -> None: from ba.osmusic import OSMusicPlayer from bastd.ui import fileselector ba.containerwidget(edit=self._root_widget, transition='out_left') base_path = _ba.android_get_external_storage_path() - ba.app.main_menu_window = (fileselector.FileSelectorWindow( - base_path, - callback=self._music_file_selector_cb, - show_base_path=False, - valid_file_extensions=( - OSMusicPlayer.get_valid_music_file_extensions()), - allow_folders=False).get_root_widget()) + ba.app.ui.set_main_menu_window( + fileselector.FileSelectorWindow( + base_path, + callback=self._music_file_selector_cb, + show_base_path=False, + valid_file_extensions=( + OSMusicPlayer.get_valid_music_file_extensions()), + allow_folders=False).get_root_widget()) def _on_music_folder_press(self) -> None: from bastd.ui import fileselector ba.containerwidget(edit=self._root_widget, transition='out_left') base_path = _ba.android_get_external_storage_path() - ba.app.main_menu_window = (fileselector.FileSelectorWindow( - base_path, - callback=self._music_folder_selector_cb, - show_base_path=False, - valid_file_extensions=[], - allow_folders=True).get_root_widget()) + ba.app.ui.set_main_menu_window( + fileselector.FileSelectorWindow( + base_path, + callback=self._music_folder_selector_cb, + show_base_path=False, + valid_file_extensions=[], + allow_folders=True).get_root_widget()) def _music_file_selector_cb(self, result: Optional[str]) -> None: if result is None: diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py b/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py index 64bef0ae..8457e197 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py @@ -58,7 +58,7 @@ class MacMusicAppPlaylistSelectWindow(ba.Window): position=(20, self._height - 54), size=(self._width, 25), text=ba.Lstr(resource=self._r + '.selectAPlaylistText'), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', maxwidth=200) diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 1bf05030..97090b07 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -160,7 +160,7 @@ class StoreBrowserWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 44), size=(0, 0), - color=app.title_color, + color=app.ui.title_color, scale=1.5, h_align='center', v_align='center', @@ -1008,7 +1008,7 @@ class StoreBrowserWindow(ba.Window): self._tab_buttons.values()).index(sel)] else: raise ValueError(f'unrecognized selection \'{sel}\'') - ba.app.window_states[self.__class__.__name__] = { + ba.app.ui.window_states[self.__class__.__name__] = { 'sel_name': sel_name, 'tab': self._current_tab } @@ -1018,8 +1018,8 @@ class StoreBrowserWindow(ba.Window): def _restore_state(self) -> None: try: sel: Optional[ba.Widget] - sel_name = ba.app.window_states.get(self.__class__.__name__, - {}).get('sel_name') + sel_name = ba.app.ui.window_states.get(self.__class__.__name__, + {}).get('sel_name') current_tab = ba.app.config.get('Store Tab') if self._show_tab is not None: current_tab = self._show_tab @@ -1047,18 +1047,18 @@ class StoreBrowserWindow(ba.Window): def _on_get_more_tickets_press(self) -> None: # pylint: disable=cyclic-import - from bastd.ui import account - from bastd.ui import getcurrency + from bastd.ui.account import show_sign_in_prompt + from bastd.ui.getcurrency import GetCurrencyWindow if _ba.get_account_state() != 'signed_in': - account.show_sign_in_prompt() + show_sign_in_prompt() return self._save_state() ba.containerwidget(edit=self._root_widget, transition='out_left') - window = getcurrency.GetCurrencyWindow( + window = GetCurrencyWindow( from_modal_store=self._modal, store_back_location=self._back_location).get_root_widget() if not self._modal: - ba.app.main_menu_window = window + ba.app.ui.set_main_menu_window(window) def _back(self) -> None: # pylint: disable=cyclic-import @@ -1069,10 +1069,12 @@ class StoreBrowserWindow(ba.Window): transition=self._transition_out) if not self._modal: if self._back_location == 'CoopBrowserWindow': - ba.app.main_menu_window = (browser.CoopBrowserWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + browser.CoopBrowserWindow( + transition='in_left').get_root_widget()) else: - ba.app.main_menu_window = (mainmenu.MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + mainmenu.MainMenuWindow( + transition='in_left').get_root_widget()) if self._on_close_call is not None: self._on_close_call() diff --git a/assets/src/ba_data/python/bastd/ui/tournamententry.py b/assets/src/ba_data/python/bastd/ui/tournamententry.py index 49ba780e..6e255229 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamententry.py +++ b/assets/src/ba_data/python/bastd/ui/tournamententry.py @@ -233,7 +233,7 @@ class TournamentEntryWindow(popup.PopupWindow): self._pay_with_ad_btn = None self._get_tickets_button: Optional[ba.Widget] - if not ba.app.toolbars: + if not ba.app.ui.use_toolbars: self._get_tickets_button = ba.buttonwidget( parent=self.root_widget, position=(self._width - 190 + 110, 15), @@ -255,7 +255,7 @@ class TournamentEntryWindow(popup.PopupWindow): # Let's also ask the server for info about this tournament # (time remaining, etc) so we can show the user time remaining, # disallow entry if time has run out, etc. - xoffs = 104 if ba.app.toolbars else 0 + xoffs = 104 if ba.app.ui.use_toolbars else 0 self._time_remaining_text = ba.textwidget(parent=self.root_widget, position=(70 + xoffs, 23), size=(0, 0), diff --git a/assets/src/ba_data/python/bastd/ui/url.py b/assets/src/ba_data/python/bastd/ui/url.py index 510513fc..cb47c26c 100644 --- a/assets/src/ba_data/python/bastd/ui/url.py +++ b/assets/src/ba_data/python/bastd/ui/url.py @@ -74,7 +74,7 @@ class ShowURLWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 10), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, h_align='center', v_align='center', text=ba.Lstr(resource='directBrowserToURLText'), @@ -84,7 +84,7 @@ class ShowURLWindow(ba.Window): self._height * 0.5 + 29), size=(0, 0), scale=1.3, - color=ba.app.infotextcolor, + color=ba.app.ui.infotextcolor, h_align='center', v_align='center', text=address, diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py index 4cb1c0e6..3924ef7e 100644 --- a/assets/src/ba_data/python/bastd/ui/watch.py +++ b/assets/src/ba_data/python/bastd/ui/watch.py @@ -50,7 +50,7 @@ class WatchWindow(ba.Window): else: self._transition_out = 'out_right' scale_origin = None - ba.app.main_window = 'Watch' + ba.app.ui.set_main_menu_location('Watch') self._tab_data: Dict[str, Any] = {} self._my_replays_scroll_width: Optional[float] = None self._my_replays_watch_replay_button: Optional[ba.Widget] = None @@ -78,7 +78,7 @@ class WatchWindow(ba.Window): stack_offset=(0, -10) if uiscale is ba.UIScale.SMALL else ( 0, 15) if uiscale is ba.UIScale.MEDIUM else (0, 0))) - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.containerwidget(edit=self._root_widget, on_cancel_call=self._back) self._back_button = None @@ -101,7 +101,7 @@ class WatchWindow(ba.Window): ba.textwidget(parent=self._root_widget, position=(self._width * 0.5, self._height - 38), size=(0, 0), - color=ba.app.title_color, + color=ba.app.ui.title_color, scale=1.5, h_align='center', v_align='center', @@ -121,7 +121,7 @@ class WatchWindow(ba.Window): size=(self._width - tab_buffer_h, 50), on_select_call=self._set_tab) - if ba.app.toolbars: + if ba.app.ui.use_toolbars: ba.widget(edit=self._tab_buttons[tabs_def[-1][0]], right_widget=_ba.get_special_widget('party_button')) if uiscale is ba.UIScale.SMALL: @@ -231,7 +231,7 @@ class WatchWindow(ba.Window): label=ba.Lstr(resource=self._r + '.watchReplayButtonText'), autoselect=True) ba.widget(edit=btn1, up_widget=self._tab_buttons[tab]) - if uiscale is ba.UIScale.SMALL and ba.app.toolbars: + if uiscale is ba.UIScale.SMALL and ba.app.ui.use_toolbars: ba.widget(edit=btn1, left_widget=_ba.get_special_widget('back_button')) btnv -= b_height + b_space_extra @@ -492,7 +492,7 @@ class WatchWindow(ba.Window): sel_name = 'TabContainer' else: raise ValueError(f'unrecognized selection {sel}') - ba.app.window_states[self.__class__.__name__] = { + ba.app.ui.window_states[self.__class__.__name__] = { 'sel_name': sel_name, 'tab': self._current_tab } @@ -501,8 +501,8 @@ class WatchWindow(ba.Window): def _restore_state(self) -> None: try: - sel_name = ba.app.window_states.get(self.__class__.__name__, - {}).get('sel_name') + sel_name = ba.app.ui.window_states.get(self.__class__.__name__, + {}).get('sel_name') current_tab = ba.app.config.get('Watch Tab') if current_tab is None or current_tab not in self._tab_buttons: current_tab = 'my_replays' @@ -523,9 +523,9 @@ class WatchWindow(ba.Window): ba.print_exception(f'Error restoring state for {self}.') def _back(self) -> None: - from bastd.ui import mainmenu + from bastd.ui.mainmenu import MainMenuWindow self._save_state() ba.containerwidget(edit=self._root_widget, transition=self._transition_out) - ba.app.main_menu_window = (mainmenu.MainMenuWindow( - transition='in_left').get_root_widget()) + ba.app.ui.set_main_menu_window( + MainMenuWindow(transition='in_left').get_root_widget()) diff --git a/config/toolconfigsrc/pylintrc b/config/toolconfigsrc/pylintrc index 89e19ab4..154eac9f 100644 --- a/config/toolconfigsrc/pylintrc +++ b/config/toolconfigsrc/pylintrc @@ -62,26 +62,26 @@ disable=broad-except, enable=useless-suppression [BASIC] -# I use x, y, h, and v for graphical purposes often, where I feel like they are -# meaningful, so adding them to the allowed list. -# Also t, r, s for translate/rotate/scale -# (i found myself just changing them to xval and yval which doesnt help) +# Allowing a handfull of short names commonly understood to be iterators, +# math concepts, or temporary variables. good-names=i, j, k, x, y, + z, h, v, s, + ui, h2, v2, ex, Run, id, - T, S, + T, U, _ diff --git a/docs/ba_module.md b/docs/ba_module.md index 5a99e382..534d3504 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

      last updated on 2020-07-13 for Ballistica version 1.5.20 build 20135

      +

      last updated on 2020-07-13 for Ballistica version 1.5.20 build 20136

      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!


      @@ -6401,7 +6401,7 @@ so in most cases you can just use that.

      Category: General Utility Functions

      Activities require special setup and thus cannot be directly -instantiated; You must go through this function.

      +instantiated; you must go through this function.


      ba.newnode()

      From 94380b83fd85e6c1116aaa9acbc03e3750f7481d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 13 Jul 2020 19:46:57 -0700 Subject: [PATCH 149/417] Updated changelog --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 3 +++ 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 6187936e..c7bf42d8 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/6b/65/84b0f5e6f03ae3e281b3e7c84c33", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/4c/48a8d74829812edbe484a3a00647", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d1/e4/0a2390a2af7b50738e276214f7aa", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5e/33/7ce61884d65810d479d8a8f18845", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e5/de/aa7c8e010f8cba5559d7c2df953b", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ed/a1/75bbe8e63775056fb82fe4a3c5b9", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/65/64/f754cc64bdb97aae0ecfde4b14a9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b6/ff/57211cac20b87dc6aec10fbb5e6d", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e0/9c/e781f97fe6b81e373e7524784d3b", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/01/dd/4747a402c2f635a31a70a305c48e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/26/de8bc04e6d4097583ea98df9eb35", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6f/b3/72fc80d493249f1a0085f29f5db4" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/b3/8ce3edf7899253523ca4052d6822", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5e/3b/93d65e405633a271b532c8b0c41a", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/76/dc/51f5097955d8cf2fa7a90726ed94", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/92/90dd14d0476826f68b85979130c6", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9c/75/039bc1ef241286e04cae7cf7f741", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/72/18/bcddf334f1236a356d1387e545e6", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b8/9d/986c79244ce3563899917bbe6b80", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/f0/55696477ef4ec8844e2dac651e76", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/9d/bd9670b2e4f6955089544d8cbefc", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/de/a49454db24304ac508d193feac2d", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d1/6c/ad012a25d04940733b69c88da29e", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c4/0a/21e32e240ab6ee416c098cc7520f" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 87c63ca9..d249d9b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.21 (20136) +- Added a UI subsystem at ba.app.ui (containing globals/functionality that was previously directly under ba.app). And hopefully added a fix for rare state of two main menus appearing on-screen at once. + ### 1.5.20 (20126) - The ba.Session.teams and ba.Session.players lists are now ba.Session.sessionteams and ba.Session.sessionplayers. This is to help keep it clear that a Team/Player and a SessionTeam/SessionPlayer are different things now. - Disconnecting an input-device now immediately removes the player instead of doing so in the next cycle; this prevents possible issues where code would try to access player.inputdevice before the removal happens which would lead to errors. From 5fd7783b23240d64746aa8cece1e616270ebaf4b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 14 Jul 2020 01:10:25 -0700 Subject: [PATCH 150/417] Added advanced options to disable cam-shake or cam-gyro-motion --- .efrocachemap | 34 ++++---- CHANGELOG.md | 1 + .../python/bastd/ui/settings/advanced.py | 77 ++++++++++--------- 3 files changed, 57 insertions(+), 55 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index c7bf42d8..591bbe3e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/b5/5b/63af84997e9012c1917ea298ebbb", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/12/d8/86ab6418b837b98ccdd60695c3f7", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/4c/ca/1e38748da251895ca11dcdc87107", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", @@ -429,13 +429,13 @@ "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", - "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/30/f3/4ef3bbaf1e5b7abe114c119ec106", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/e7/8e/3553965def02a0b2362a0ed8aebe", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/c7/63/f72f7f8b2004ff79b1606b040f8b", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/8e/24/f070599beb7b09e1268569fa55b1", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/43/ee/42cf5ad52de3d4f567ec04018655", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", - "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/30/e7/d36b1b1eeb2ec10633281855a34c", + "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/6f/df2600b658a163f80077bd6c8d78", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/70/d0/36b0d655839c60c2a763bbe52332", @@ -443,7 +443,7 @@ "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/8e/3f/41e12b96fc07a623d89153b10c38", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/62/18/c2987e85c8ce48544cfa9c29d7bb", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9", - "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/f6/d0/335b952306d211d56172b5c72d8c", + "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", @@ -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/18/b3/8ce3edf7899253523ca4052d6822", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5e/3b/93d65e405633a271b532c8b0c41a", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/76/dc/51f5097955d8cf2fa7a90726ed94", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fb/92/90dd14d0476826f68b85979130c6", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9c/75/039bc1ef241286e04cae7cf7f741", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/72/18/bcddf334f1236a356d1387e545e6", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b8/9d/986c79244ce3563899917bbe6b80", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f0/f0/55696477ef4ec8844e2dac651e76", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/9d/bd9670b2e4f6955089544d8cbefc", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/de/a49454db24304ac508d193feac2d", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d1/6c/ad012a25d04940733b69c88da29e", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c4/0a/21e32e240ab6ee416c098cc7520f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/91/6f5f68ff311414a11f64291f5e5d", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/da/500d5bfe62ba1dfb46fed74f1885", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/ad/dbfe0a1a79c08774dbb62d651f44", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/5c/0448f94d859f0c9aff6ac746484c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/53/499bd0581788ace12577ffa4e563", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/09/5a/4e0aa4eee0945e6bcf03861ac74e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/03/81/48ac08db74f2593cc88ff75b1da9", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5d/a3/85b1ff72f83cef742b4eec6369c2", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1f/59/555b2d780d465032756e80f269ad", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c0/28/1ae99132dc301d9a57bf9dc73958", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/30/41/19c5adcfe23cea006d0d07cecdc0", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/41/ee/31a6d9e0a3dc5afdf9d94c726968" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index d249d9b4..1fcea28c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.5.21 (20136) - Added a UI subsystem at ba.app.ui (containing globals/functionality that was previously directly under ba.app). And hopefully added a fix for rare state of two main menus appearing on-screen at once. +- Added options in the 'Advanced' section to disable camera shake and camera gyroscope motion. ### 1.5.20 (20126) - The ba.Session.teams and ba.Session.players lists are now ba.Session.sessionteams and ba.Session.sessionplayers. This is to help keep it clear that a Team/Player and a SessionTeam/SessionPlayer are different things now. diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index 50c5d8f6..e3fefe7f 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -82,11 +82,15 @@ class AdvancedSettingsWindow(ba.Window): self._scroll_width = self._width - (100 + 2 * x_inset) self._scroll_height = self._height - 115.0 self._sub_width = self._scroll_width * 0.95 - self._sub_height = 740.0 + self._sub_height = 724.0 if self._show_always_use_internal_keyboard: self._sub_height += 62 + self._show_disable_gyro = app.platform in {'ios', 'android'} + if self._show_disable_gyro: + self._sub_height += 42 + self._do_vr_test_button = app.vr_mode self._do_net_test_button = True self._extra_button_spacing = self._spacing * 2.5 @@ -359,6 +363,29 @@ class AdvancedSettingsWindow(ba.Window): scale=1.0, maxwidth=430) + v -= 42 + self._disable_camera_shake_check_box = ConfigCheckBox( + parent=self._subcontainer, + position=(50, v), + size=(self._sub_width - 100, 30), + configkey='Disable Camera Shake', + displayname=ba.Lstr(resource=self._r + '.disableCameraShakeText'), + scale=1.0, + maxwidth=430) + + self._disable_gyro_check_box: Optional[ConfigCheckBox] = None + if self._show_disable_gyro: + v -= 42 + self._disable_gyro_check_box = ConfigCheckBox( + parent=self._subcontainer, + position=(50, v), + size=(self._sub_width - 100, 30), + configkey='Disable Camera Gyro', + displayname=ba.Lstr(resource=self._r + + '.disableCameraGyroscopeMotionText'), + scale=1.0, + maxwidth=430) + self._always_use_internal_keyboard_check_box: Optional[ConfigCheckBox] if self._show_always_use_internal_keyboard: v -= 42 @@ -414,7 +441,7 @@ class AdvancedSettingsWindow(ba.Window): v -= self._spacing * 2.0 - btn = self._modding_guide_button = ba.buttonwidget( + self._modding_guide_button = ba.buttonwidget( parent=self._subcontainer, position=(self._sub_width / 2 - this_button_width / 2, v - 10), size=(this_button_width, 60), @@ -425,33 +452,6 @@ class AdvancedSettingsWindow(ba.Window): ba.open_url, 'http://www.froemling.net/docs/bombsquad-modding-guide')) - v -= self._spacing * 1.8 - - self._enable_package_mods_checkbox = ConfigCheckBox( - parent=self._subcontainer, - position=(80, v), - size=(self._sub_width - 100, 30), - configkey='Enable Package Mods', - autoselect=True, - value_change_call=ba.WeakCall(self._show_restart_needed), - displayname=ba.Lstr(resource=self._r + '.enablePackageModsText'), - scale=1.0, - maxwidth=400) - ccb = self._enable_package_mods_checkbox.widget - ba.widget(edit=btn, down_widget=ccb) - ba.widget(edit=ccb, up_widget=btn) - ba.textwidget(parent=self._subcontainer, - position=(90, v - 10), - size=(0, 0), - text=ba.Lstr(resource=self._r + - '.enablePackageModsDescriptionText'), - maxwidth=400, - flatness=1.0, - scale=0.65, - color=(0.4, 0.9, 0.4, 0.8), - h_align='left', - v_align='center') - v -= self._spacing * 0.6 self._vr_test_button: Optional[ba.Widget] @@ -492,11 +492,6 @@ class AdvancedSettingsWindow(ba.Window): text_scale=1.0, on_activate_call=self._on_benchmark_press) - ba.widget(edit=self._vr_test_button if self._vr_test_button is not None - else self._net_test_button if self._net_test_button - is not None else self._benchmarks_button, - up_widget=cbw) - for child in self._subcontainer.get_children(): ba.widget(edit=child, show_buffer_bottom=30, show_buffer_top=20) @@ -581,10 +576,15 @@ class AdvancedSettingsWindow(ba.Window): sel_name = 'Benchmarks' elif sel == self._kick_idle_players_check_box.widget: sel_name = 'KickIdlePlayers' + elif sel == self._disable_camera_shake_check_box.widget: + sel_name = 'DisableCameraShake' elif (self._always_use_internal_keyboard_check_box is not None and sel == self._always_use_internal_keyboard_check_box.widget): sel_name = 'AlwaysUseInternalKeyboard' + elif (self._disable_gyro_check_box is not None + and sel == self._disable_gyro_check_box.widget): + sel_name = 'DisableGyro' elif (self._language_popup is not None and sel == self._language_popup.get_button()): sel_name = 'Languages' @@ -594,8 +594,6 @@ class AdvancedSettingsWindow(ba.Window): sel_name = 'ShowUserMods' elif sel == self._modding_guide_button: sel_name = 'ModdingGuide' - elif sel == self._enable_package_mods_checkbox.widget: - sel_name = 'PackageMods' elif sel == self._language_inform_checkbox: sel_name = 'LangInform' else: @@ -630,10 +628,15 @@ class AdvancedSettingsWindow(ba.Window): sel = self._benchmarks_button elif sel_name == 'KickIdlePlayers': sel = self._kick_idle_players_check_box.widget + elif sel_name == 'DisableCameraShake': + sel = self._disable_camera_shake_check_box.widget elif (sel_name == 'AlwaysUseInternalKeyboard' and self._always_use_internal_keyboard_check_box is not None): sel = self._always_use_internal_keyboard_check_box.widget + elif (sel_name == 'DisableGyro' + and self._disable_gyro_check_box is not None): + sel = self._disable_gyro_check_box.widget elif (sel_name == 'Languages' and self._language_popup is not None): sel = self._language_popup.get_button() @@ -643,8 +646,6 @@ class AdvancedSettingsWindow(ba.Window): sel = self._show_user_mods_button elif sel_name == 'ModdingGuide': sel = self._modding_guide_button - elif sel_name == 'PackageMods': - sel = self._enable_package_mods_checkbox.widget elif sel_name == 'LangInform': sel = self._language_inform_checkbox else: From 56525c5927233fee80c12638fc96c74aa8a4ff48 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 14 Jul 2020 02:37:40 -0700 Subject: [PATCH 151/417] v1.5.121 --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 2 +- docs/ba_module.md | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 591bbe3e..5784a7d3 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/a9/91/6f5f68ff311414a11f64291f5e5d", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/da/500d5bfe62ba1dfb46fed74f1885", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1a/ad/dbfe0a1a79c08774dbb62d651f44", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/2e/5c/0448f94d859f0c9aff6ac746484c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/53/499bd0581788ace12577ffa4e563", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/09/5a/4e0aa4eee0945e6bcf03861ac74e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/03/81/48ac08db74f2593cc88ff75b1da9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5d/a3/85b1ff72f83cef742b4eec6369c2", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1f/59/555b2d780d465032756e80f269ad", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c0/28/1ae99132dc301d9a57bf9dc73958", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/30/41/19c5adcfe23cea006d0d07cecdc0", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/41/ee/31a6d9e0a3dc5afdf9d94c726968" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/92/53/05b4398b8455d60509cecdf44644", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/a0/99ced6c0fd68c2d9970441224f89", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d7/73/dd9a11fd1d117f40bcc293843685", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/95/e83fbd81b2af177c00075f1b5913", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/c3/f2ba004c50dd2824e73b784660f8", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/24/e500652fe98f86efddf3e91346d5", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e6/9c/70b5506bae3b40c53491fff46880", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/58/2b80aaee31ac02e9f54b7cd01b0a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/02/ca/73f67fecbc059f269394801f0366", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/38/83/44de94717c85f74b1ceeac569050", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/72/ea/86d4a544578493712cbbf2244f09", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6c/72/63e5fb1ddb3ee938100a6dcce409" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fcea28c..167d4c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5.21 (20136) +### 1.5.21 (20138) - Added a UI subsystem at ba.app.ui (containing globals/functionality that was previously directly under ba.app). And hopefully added a fix for rare state of two main menus appearing on-screen at once. - Added options in the 'Advanced' section to disable camera shake and camera gyroscope motion. diff --git a/docs/ba_module.md b/docs/ba_module.md index 534d3504..04166443 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

      last updated on 2020-07-13 for Ballistica version 1.5.20 build 20136

      +

      last updated on 2020-07-14 for Ballistica version 1.5.21 build 20138

      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!


      From d6d7152ae3b2551d280c0120be1dca4b07309881 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 14 Jul 2020 13:22:55 -0700 Subject: [PATCH 152/417] Language updates --- .efrocachemap | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 5784a7d3..bdc22351 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,10 +420,10 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/12/d8/86ab6418b837b98ccdd60695c3f7", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/4c/ca/1e38748da251895ca11dcdc87107", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/78/70/98c37db0c28354adfe8fa03676a5", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/30/8e/38c5f21b9251ea1111bed554035f", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/bc/59/21bb0b4ef33c733022340c60aebf", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/97/4e/48ae80fb711a22559a311c49b358", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/21/38/7e50214f79088f55c6e059fd33d2", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", @@ -431,7 +431,7 @@ "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/e7/8e/3553965def02a0b2362a0ed8aebe", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/c7/63/f72f7f8b2004ff79b1606b040f8b", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/eb/94/449eceecc6b0a6c7e4a548ea3607", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/43/ee/42cf5ad52de3d4f567ec04018655", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", @@ -441,15 +441,15 @@ "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/70/d0/36b0d655839c60c2a763bbe52332", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/8e/3f/41e12b96fc07a623d89153b10c38", - "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/62/18/c2987e85c8ce48544cfa9c29d7bb", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/66/0b/df2cd57be4eb505876d209a673d9", + "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/8f/e6/675e5e41b5aea12d34b152f0f705", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/9c/e3/834faf6869f5cd175edd4a0244b9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a9/77/722faae6a695f19501bac76098db", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a0/89/d377dea2c8b1ec5f4cb47e4e61ae", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/ef/61/7dcdc48c7039bbad6cd01d3f9a1f", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/d7/bc/0d6cf14910b9cdec808e0accf5c7", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/9d/fb/6c2feb78bdabbec049a71ba40d78", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f1/00/c4ccd5969084505359e07f927b3a", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", @@ -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/92/53/05b4398b8455d60509cecdf44644", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/a0/99ced6c0fd68c2d9970441224f89", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d7/73/dd9a11fd1d117f40bcc293843685", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/95/e83fbd81b2af177c00075f1b5913", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/62/c3/f2ba004c50dd2824e73b784660f8", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/42/24/e500652fe98f86efddf3e91346d5", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e6/9c/70b5506bae3b40c53491fff46880", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/58/2b80aaee31ac02e9f54b7cd01b0a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/02/ca/73f67fecbc059f269394801f0366", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/38/83/44de94717c85f74b1ceeac569050", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/72/ea/86d4a544578493712cbbf2244f09", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/6c/72/63e5fb1ddb3ee938100a6dcce409" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/e8/cb2aca94bb37c54803235ca19a75", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d2/da/661e79f9cbe9446a073e685f240d", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/38/07/ed14ca1cdab132da23bfd1f69f5f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/6a/0e233fc907a8461d7641f4740530", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b0/4b/eaed2d4f9296da8950707cf64fff", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9c/37/835be7a8730d5b1acc009823a781", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/03/5e/d126371e7d1d32948e04f0c77d77", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c2/57/a7bb77e0dd051cc68d7e4c6d0bde", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/35/11f66fbd7cd142e40ad4cc94022b", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c9/cb/0879d2f7acbdd8165f5a7af56264", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a2/9f/e82dd87f76005a97ececdfb2a1b2", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/14/ca/9de4a3803d3ac23d24591a36e49f" } \ No newline at end of file From e752a7dbb32ed6178ca7bcdfe4cce129f8baaa36 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 15 Jul 2020 03:43:03 -0700 Subject: [PATCH 153/417] v1.5.22 --- .efrocachemap | 24 +++++++-------- CHANGELOG.md | 3 ++ assets/src/ba_data/python/_ba.py | 21 ++++++++++---- assets/src/ba_data/python/ba/_lang.py | 10 +++++++ assets/src/ba_data/python/ba/_ui.py | 3 +- .../python/bastd/actor/controlsguide.py | 27 ++++++++++------- .../python/bastd/ui/settings/controls.py | 2 +- .../python/bastd/ui/settings/gamepad.py | 2 +- docs/ba_module.md | 29 +++++++++++++++---- 9 files changed, 85 insertions(+), 36 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index bdc22351..82f2a475 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/66/e8/cb2aca94bb37c54803235ca19a75", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d2/da/661e79f9cbe9446a073e685f240d", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/38/07/ed14ca1cdab132da23bfd1f69f5f", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/6a/0e233fc907a8461d7641f4740530", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b0/4b/eaed2d4f9296da8950707cf64fff", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/9c/37/835be7a8730d5b1acc009823a781", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/03/5e/d126371e7d1d32948e04f0c77d77", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c2/57/a7bb77e0dd051cc68d7e4c6d0bde", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/35/11f66fbd7cd142e40ad4cc94022b", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c9/cb/0879d2f7acbdd8165f5a7af56264", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a2/9f/e82dd87f76005a97ececdfb2a1b2", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/14/ca/9de4a3803d3ac23d24591a36e49f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/44/c5/099debe438f2bca2c3dc8d9f048e", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/7a/f92d78baa6d8137a8150e37c40a8", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/35/8b/1d44da11d466aa8e49390048bd3c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/13/b2/6f0da477dd7d4f54fe48647ce44b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/11/e50c98eb60cfbe1c5268e33af8b8", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3b/e5/ce291661086203e424dce2dcd692", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/70/09/d12993418eade4f88e8290d92f2e", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/93/8c/8d7097c9b662b6583a145ad34f56", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/d4/96f341a77b48a1f4adcbc5ca1e40", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/af/79/c1be9d5908663f693dc67a24fd5e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9e/e6/2cc3bc3fe700d8750387032bf43d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/92/8f/99cddfd2549fadedbb6f483bb174" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 167d4c29..7a4cb989 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.22 (20139) +- Button and key names now display correctly again on Android (and are cleaned up on other platforms too). + ### 1.5.21 (20138) - Added a UI subsystem at ba.app.ui (containing globals/functionality that was previously directly under ba.app). And hopefully added a fix for rare state of two main menus appearing on-screen at once. - Added options in the 'Advanced' section to disable camera shake and camera gyroscope motion. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 295c4763..ca9209ab 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -256,6 +256,11 @@ class InputDevice: allows_configuring: bool Whether the input-device can be configured. + has_meaningful_button_names: bool + Whether button names returned by this instance match labels + on the actual device. (Can be used to determine whether to show + them in controls-overlays, etc.) + player: Optional[ba.SessionPlayer] The player associated with this input device. @@ -288,6 +293,7 @@ class InputDevice: """ allows_configuring: bool + has_meaningful_button_names: bool player: Optional[ba.SessionPlayer] client_id: int name: str @@ -316,16 +322,21 @@ class InputDevice: def get_axis_name(self, axis_id: int) -> str: """get_axis_name(axis_id: int) -> str - Given an axis ID, returns the name of the axis on this device. + Given an axis ID, return the name of the axis on this device. + + Can return an empty string if the value is not meaningful to humans. """ return str() - def get_button_name(self, button_id: int) -> str: - """get_button_name(button_id: int) -> str + def get_button_name(self, button_id: int) -> ba.Lstr: + """get_button_name(button_id: int) -> ba.Lstr - Given a button ID, returns the name of the key/button on this device. + Given a button ID, return a human-readable name for that key/button. + + Can return an empty string if the value is not meaningful to humans. """ - return str() + import ba # pylint: disable=cyclic-import + return ba.Lstr(value='') def get_default_player_name(self) -> str: """get_default_player_name() -> str diff --git a/assets/src/ba_data/python/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py index fcef0708..7afacfbb 100644 --- a/assets/src/ba_data/python/ba/_lang.py +++ b/assets/src/ba_data/python/ba/_lang.py @@ -28,6 +28,7 @@ from typing import TYPE_CHECKING, overload import _ba if TYPE_CHECKING: + import ba from typing import Any, Dict, List, Optional, Tuple, Union, Sequence @@ -192,6 +193,13 @@ class Lstr: def __repr__(self) -> str: return '' + @staticmethod + def from_json(json_string: str) -> ba.Lstr: + """Given a json string, returns a ba.Lstr. Does no data validation.""" + lstr = Lstr(value='') + lstr.args = json.loads(json_string) + return lstr + def setlanguage(language: Optional[str], print_change: bool = True, @@ -203,6 +211,7 @@ def setlanguage(language: Optional[str], Pass None to use OS default language. """ # pylint: disable=too-many-locals + # pylint: disable=too-many-statements # pylint: disable=too-many-branches cfg = _ba.app.config cur_language = cfg.get('Lang', None) @@ -273,6 +282,7 @@ def setlanguage(language: Optional[str], internal_vals.append((value, lfull[value])) internal_vals.append( ('axisText', lfull['configGamepadWindow']['axisText'])) + internal_vals.append(('buttonText', lfull['buttonText'])) lmerged = _ba.app.language_merged assert lmerged is not None random_names = [ diff --git a/assets/src/ba_data/python/ba/_ui.py b/assets/src/ba_data/python/ba/_ui.py index ce4c5a99..5c612bf2 100644 --- a/assets/src/ba_data/python/ba/_ui.py +++ b/assets/src/ba_data/python/ba/_ui.py @@ -103,9 +103,10 @@ class UI: # on the old after a short bit of time and kill it if its still alive. # That will be a bit ugly on screen but at least will un-break things. def _delay_kill() -> None: + import time if existing: print(f'Killing old main_menu_window' - f' when called at: {frameline}') + f' when called at: {frameline} t={time.time():.3f}') existing.delete() _ba.timer(1.0, _delay_kill, timetype=TimeType.REAL) diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py index 374bb7ef..a68a6d7c 100644 --- a/assets/src/ba_data/python/bastd/actor/controlsguide.py +++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py @@ -243,6 +243,13 @@ class ControlsGuide(ba.Actor): # Don't do anything until our delay has passed. ba.timer(delay, ba.WeakCall(self._start_updating)) + @staticmethod + def _meaningful_button_name(device: ba.InputDevice, button: int) -> str: + """Return a flattened string button name; empty for non-meaningful.""" + if not device.has_meaningful_button_names: + return '' + return device.get_button_name(button).evaluate() + def _start_updating(self) -> None: # Ok, our delay has passed. Now lets periodically see if we can fade @@ -284,8 +291,8 @@ class ControlsGuide(ba.Actor): for device in input_devices: for name in ('buttonPunch', 'buttonJump', 'buttonBomb', 'buttonPickUp'): - if device.get_button_name( - get_device_value(device, name)) != '': + if self._meaningful_button_name( + device, get_device_value(device, name)) != '': fade_in = True break if fade_in: @@ -368,20 +375,20 @@ class ControlsGuide(ba.Actor): # Ignore empty values; things like the remote app or # wiimotes can return these. - bname = device.get_button_name( - get_device_value(device, 'buttonPunch')) + bname = self._meaningful_button_name( + device, get_device_value(device, 'buttonPunch')) if bname != '': punch_button_names.add(bname) - bname = device.get_button_name( - get_device_value(device, 'buttonJump')) + bname = self._meaningful_button_name( + device, get_device_value(device, 'buttonJump')) if bname != '': jump_button_names.add(bname) - bname = device.get_button_name( - get_device_value(device, 'buttonBomb')) + bname = self._meaningful_button_name( + device, get_device_value(device, 'buttonBomb')) if bname != '': bomb_button_names.add(bname) - bname = device.get_button_name( - get_device_value(device, 'buttonPickUp')) + bname = self._meaningful_button_name( + device, get_device_value(device, 'buttonPickUp')) if bname != '': pickup_button_names.add(bname) diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index c20e448a..6337af17 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -64,7 +64,7 @@ class ControlsSettingsWindow(ba.Window): spacing = 50.0 button_width = 350.0 width = 460.0 - height = 135.0 + height = 85.0 space_height = spacing * 0.3 diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index 7305ccd1..680a20c1 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -188,7 +188,7 @@ class GamepadSettingsWindow(ba.Window): size=((160 if self._is_secondary else 180), 60), autoselect=True, label=ba.Lstr(resource='doneText') - if self._is_secondary else ba.Lstr(resource='makeItSoText'), + if self._is_secondary else ba.Lstr(resource='saveText'), scale=0.9, on_activate_call=self._save) ba.containerwidget(edit=self._root_widget, diff --git a/docs/ba_module.md b/docs/ba_module.md index 04166443..6173809a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

      last updated on 2020-07-14 for Ballistica version 1.5.21 build 20138

      +

      last updated on 2020-07-15 for Ballistica version 1.5.22 build 20140

      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!


      @@ -2872,7 +2872,7 @@ Results for a completed game.

      Category: Gameplay Classes

      Attributes:

      -
      allows_configuring, client_id, id, instance_number, is_controller_app, is_remote_client, name, player, unique_identifier
      +
      allows_configuring, client_id, has_meaningful_button_names, id, instance_number, is_controller_app, is_remote_client, name, player, unique_identifier

      allows_configuring

      bool

      @@ -2885,6 +2885,13 @@ Results for a completed game.

      This is only meaningful for remote client inputs; for all local devices this will be -1.

      +
      +

      has_meaningful_button_names

      +

      bool

      +

      Whether button names returned by this instance match labels +on the actual device. (Can be used to determine whether to show +them in controls-overlays, etc.)

      +

      id

      int

      @@ -2946,13 +2953,17 @@ prefs, etc.

      get_axis_name()

      get_axis_name(axis_id: int) -> str

      -

      Given an axis ID, returns the name of the axis on this device.

      +

      Given an axis ID, return the name of the axis on this device.

      + +

      Can return an empty string if the value is not meaningful to humans.

      get_button_name()

      -

      get_button_name(button_id: int) -> str

      +

      get_button_name(button_id: int) -> ba.Lstr

      -

      Given a button ID, returns the name of the key/button on this device.

      +

      Given a button ID, return a human-readable name for that key/button.

      + +

      Can return an empty string if the value is not meaningful to humans.

      @@ -3273,7 +3284,7 @@ needs a chooser.

    Methods:

    -
    <constructor>, evaluate(), is_flat_value()
    +
    <constructor>, evaluate(), from_json(), is_flat_value()

    <constructor>

    ba.Lstr(*args: Any, **keywds: Any)

    @@ -3300,6 +3311,12 @@ the resource nor the fallback resource is found ('resource' mode only).

    You should avoid doing this as much as possible and instead pass and store Lstr values.

    +
    +

    from_json()

    +

    from_json(json_string: str) -> ba.Lstr

    + +

    Given a json string, returns a ba.Lstr. Does no data validation.

    +

    is_flat_value()

    is_flat_value(self) -> bool

    From 3c97a6904fa30d38a2c9e69f69b3a0a612e0a318 Mon Sep 17 00:00:00 2001 From: Ali Borhani Date: Thu, 16 Jul 2020 12:45:30 +0430 Subject: [PATCH 154/417] Use -S flag for /usr/bin/env MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because of using `-O` flag for `python3.7` binary, it returns the below error: ``` $ ./bombsquad_server /usr/bin/env: ‘python3.7 -O’: No such file or directory /usr/bin/env: use -[v]S to pass options in shebang lines ``` --- tools/batools/pcommand.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 9a848be5..b9248d75 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -62,7 +62,7 @@ def stage_server_file() -> None: lines = infile.read().splitlines() if mode == 'release': lines[0] = replace_one(lines[0], '#!/usr/bin/env python3.7', - '#!/usr/bin/env python3.7 -O') + '#!/usr/bin/env -S python3.7 -O') with open(outfilename, 'w') as outfile: outfile.write('\n'.join(lines) + '\n') subprocess.run(['chmod', '+x', outfilename], check=True) From b8832e61ea0eb0d5e2aabe63132ed9adc12e589e Mon Sep 17 00:00:00 2001 From: Ali Borhani Date: Thu, 16 Jul 2020 12:56:01 +0430 Subject: [PATCH 155/417] Add myself to CONTRIBUTORS.md --- CONTRIBUTORS.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 7a0a5ed2..226a1795 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -14,3 +14,6 @@ ### Benefit-Zebra - Unofficial BombSquad Bug Finder - Code Cleanup + +### Ali Borhani +- Bug fixes From 208ff00a769b2832cf2c24ae82c642bb8e45834a Mon Sep 17 00:00:00 2001 From: Ali Borhani Date: Thu, 16 Jul 2020 12:59:21 +0430 Subject: [PATCH 156/417] Add new changelog entry for using `-S` flag --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a4cb989..04624cb2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### Unreleased +- Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. + ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). From d09ecae7123451559a1bed1065e01a5bfdbc225d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 16 Jul 2020 12:28:32 -0700 Subject: [PATCH 157/417] WIP on plugin system --- .efrocachemap | 44 +++--- assets/.asset_manifest_public.json | 2 + assets/Makefile | 2 + .../ba_data/python/bastd/ui/coop/browser.py | 2 +- .../src/ba_data/python/bastd/ui/mainmenu.py | 2 +- assets/src/ba_data/python/bastd/ui/play.py | 2 +- .../python/bastd/ui/settings/advanced.py | 43 ++++++ .../python/bastd/ui/settings/allsettings.py | 2 +- .../python/bastd/ui/settings/plugins.py | 133 ++++++++++++++++++ 9 files changed, 206 insertions(+), 26 deletions(-) create mode 100644 assets/src/ba_data/python/bastd/ui/settings/plugins.py diff --git a/.efrocachemap b/.efrocachemap index 82f2a475..0a2147eb 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,36 +420,36 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/78/70/98c37db0c28354adfe8fa03676a5", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/ad/82/41fe495cb2c7431379171fc5778e", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/30/8e/38c5f21b9251ea1111bed554035f", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/97/4e/48ae80fb711a22559a311c49b358", - "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/21/38/7e50214f79088f55c6e059fd33d2", + "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/a0/ca/b4e3c4ea2c76e462b7e657b2b1c2", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", - "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/5b/a3/a46a77f0cc498e1f1e369d772414", - "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/e7/8e/3553965def02a0b2362a0ed8aebe", + "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/bb/99/cf7307a78b9635cb0bf93e1647c9", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/8b/c6/3fbabe88f18df228f6f2984201a5", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/eb/94/449eceecc6b0a6c7e4a548ea3607", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/43/ee/42cf5ad52de3d4f567ec04018655", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/cb/10/5d94df639e3e0cb405711e1b907f", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/e3/6f/df2600b658a163f80077bd6c8d78", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/70/d0/36b0d655839c60c2a763bbe52332", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/7f/52/3d0b7e1955af24a1158a36c9a272", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/ff/3f/f1c11e1f22454ceceb7b4d277a2a", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/8e/3f/41e12b96fc07a623d89153b10c38", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/bd/45/ffb2d9d9ce9578ae11de9bb5123d", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/8f/e6/675e5e41b5aea12d34b152f0f705", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/9c/e3/834faf6869f5cd175edd4a0244b9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/a0/89/d377dea2c8b1ec5f4cb47e4e61ae", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/c9/6b/dadd4329de69d0b7bfe1aa5f31d6", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/d7/bc/0d6cf14910b9cdec808e0accf5c7", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/82/7c/5363de81ac6823935098df95dc66", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/9d/fb/6c2feb78bdabbec049a71ba40d78", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f1/00/c4ccd5969084505359e07f927b3a", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", @@ -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/44/c5/099debe438f2bca2c3dc8d9f048e", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/7a/f92d78baa6d8137a8150e37c40a8", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/35/8b/1d44da11d466aa8e49390048bd3c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/13/b2/6f0da477dd7d4f54fe48647ce44b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/11/e50c98eb60cfbe1c5268e33af8b8", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3b/e5/ce291661086203e424dce2dcd692", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/70/09/d12993418eade4f88e8290d92f2e", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/93/8c/8d7097c9b662b6583a145ad34f56", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/52/d4/96f341a77b48a1f4adcbc5ca1e40", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/af/79/c1be9d5908663f693dc67a24fd5e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9e/e6/2cc3bc3fe700d8750387032bf43d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/92/8f/99cddfd2549fadedbb6f483bb174" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2f/d2/729e7d4c7e884bcdc6749a52c069", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b8/45/60a8069130b52e85422236921806", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/80/84/06b8fd82adb7a10dfc2c5a6b622b", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/54/fa/b6d33c93285c9d686bf455374ce3", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/db/d010f67fb908315d89e7a0e38fb7", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6a/34/66068c15c8e349743d82be4b0e98", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/03/89949b43cdf17f571e549a85e439", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d1/a0/5ffc17a4b0c4c93ee3de59a1597b", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/87/17/e01ce11e3c4869da04e0a8824ee8", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8f/30/dc9361159cb9b1c735e8957a0a66", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/07/c2/fbed8e21c1b973f9b30267b49386", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a3/2f/04346dd3c73a959eef8d59c43991" } \ No newline at end of file diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index d633bb80..d675bd70 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -414,6 +414,7 @@ "ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc", "ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc", "ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/plugins.cpython-37.opt-1.pyc", "ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc", "ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc", "ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc", @@ -431,6 +432,7 @@ "ba_data/python/bastd/ui/settings/graphics.py", "ba_data/python/bastd/ui/settings/keyboard.py", "ba_data/python/bastd/ui/settings/nettesting.py", + "ba_data/python/bastd/ui/settings/plugins.py", "ba_data/python/bastd/ui/settings/ps3controller.py", "ba_data/python/bastd/ui/settings/remoteapp.py", "ba_data/python/bastd/ui/settings/testing.py", diff --git a/assets/Makefile b/assets/Makefile index 86bcef7b..76796b24 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -353,6 +353,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/bastd/ui/settings/graphics.py \ build/ba_data/python/bastd/ui/settings/keyboard.py \ build/ba_data/python/bastd/ui/settings/nettesting.py \ + build/ba_data/python/bastd/ui/settings/plugins.py \ build/ba_data/python/bastd/ui/settings/ps3controller.py \ build/ba_data/python/bastd/ui/settings/remoteapp.py \ build/ba_data/python/bastd/ui/settings/testing.py \ @@ -585,6 +586,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/plugins.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc \ build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc \ diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index c61884b2..ea0ad875 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -286,7 +286,7 @@ class CoopBrowserWindow(ba.Window): @staticmethod def _preload_modules() -> None: - """For preloading modules we use in a bg thread to prevent hitches.""" + """Preload modules we use (called in bg thread).""" import bastd.ui.purchase as _unused1 import bastd.ui.coop.gamebutton as _unused2 import bastd.ui.confirm as _unused3 diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index f46c4b1f..292b4171 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -91,7 +91,7 @@ class MainMenuWindow(ba.Window): @staticmethod def _preload_modules() -> None: - """For preloading modules we use in a bg thread to prevent hitches.""" + """Preload modules we use (called in bg thread).""" import bastd.ui.getremote as _unused import bastd.ui.confirm as _unused2 import bastd.ui.store.button as _unused3 diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py index 356e67a4..d097dfde 100644 --- a/assets/src/ba_data/python/bastd/ui/play.py +++ b/assets/src/ba_data/python/bastd/ui/play.py @@ -420,7 +420,7 @@ class PlayWindow(ba.Window): @staticmethod def _preload_modules() -> None: - """For preloading modules we use in a bg thread to prevent hitches.""" + """Preload modules we use (called in bg thread).""" import bastd.ui.mainmenu as _unused1 import bastd.ui.account as _unused2 import bastd.ui.coop.browser as _unused3 diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index e3fefe7f..963aea01 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -41,6 +41,12 @@ class AdvancedSettingsWindow(ba.Window): # pylint: disable=too-many-statements from ba.internal import master_server_get + import threading + + # Preload some modules we use in a background thread so we won't + # have a visual hitch when the user taps them. + threading.Thread(target=self._preload_modules).start() + app = ba.app # If they provided an origin-widget, scale up from that. @@ -99,6 +105,7 @@ class AdvancedSettingsWindow(ba.Window): self._sub_height += self._extra_button_spacing if self._do_net_test_button: self._sub_height += self._extra_button_spacing + self._sub_height += self._spacing * 2.0 # plugins self._r = 'settingsWindowAdvanced' @@ -160,6 +167,19 @@ class AdvancedSettingsWindow(ba.Window): master_server_get('bsLangGetCompleted', {'b': app.build_number}, callback=ba.WeakCall(self._completed_langs_cb)) + @staticmethod + def _preload_modules() -> None: + """Preload modules we use (called in bg thread).""" + from bastd.ui import config as _unused1 + from ba import modutils as _unused2 + from bastd.ui.settings import vrtesting as _unused3 + from bastd.ui.settings import nettesting as _unused4 + from bastd.ui import appinvite as _unused5 + from bastd.ui import account as _unused6 + from bastd.ui import promocode as _unused7 + from bastd.ui import debug as _unused8 + from bastd.ui.settings import plugins as _unused9 + def _update_lang_status(self) -> None: if self._complete_langs_list is not None: up_to_date = (ba.app.language in self._complete_langs_list) @@ -452,6 +472,17 @@ class AdvancedSettingsWindow(ba.Window): ba.open_url, 'http://www.froemling.net/docs/bombsquad-modding-guide')) + v -= self._spacing * 2.0 + + self._plugins_button = ba.buttonwidget( + parent=self._subcontainer, + position=(self._sub_width / 2 - this_button_width / 2, v - 10), + size=(this_button_width, 60), + autoselect=True, + label=ba.Lstr(resource='pluginsText'), + text_scale=1.0, + on_activate_call=self._on_plugins_button_press) + v -= self._spacing * 0.6 self._vr_test_button: Optional[ba.Widget] @@ -539,6 +570,14 @@ class AdvancedSettingsWindow(ba.Window): return appinvite.handle_app_invites_press() + def _on_plugins_button_press(self) -> None: + from bastd.ui.settings.plugins import PluginSettingsWindow + self._save_state() + ba.containerwidget(edit=self._root_widget, transition='out_left') + ba.app.ui.set_main_menu_window( + PluginSettingsWindow( + origin_widget=self._plugins_button).get_root_widget()) + def _on_promo_code_press(self) -> None: from bastd.ui.promocode import PromoCodeWindow from bastd.ui.account import show_sign_in_prompt @@ -592,6 +631,8 @@ class AdvancedSettingsWindow(ba.Window): sel_name = 'TranslationEditor' elif sel == self._show_user_mods_button: sel_name = 'ShowUserMods' + elif sel == self._plugins_button: + sel_name = 'Plugins' elif sel == self._modding_guide_button: sel_name = 'ModdingGuide' elif sel == self._language_inform_checkbox: @@ -644,6 +685,8 @@ class AdvancedSettingsWindow(ba.Window): sel = self._translation_editor_button elif sel_name == 'ShowUserMods': sel = self._show_user_mods_button + elif sel_name == 'Plugins': + sel = self._plugins_button elif sel_name == 'ModdingGuide': sel = self._modding_guide_button elif sel_name == 'LangInform': diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index 64f918c2..ab9476c9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -207,7 +207,7 @@ class AllSettingsWindow(ba.Window): @staticmethod def _preload_modules() -> None: - """For preloading modules we use in a bg thread to prevent hitches.""" + """Preload modules we use (called in bg thread).""" import bastd.ui.mainmenu as _unused1 import bastd.ui.settings.controls as _unused2 import bastd.ui.settings.graphics as _unused3 diff --git a/assets/src/ba_data/python/bastd/ui/settings/plugins.py b/assets/src/ba_data/python/bastd/ui/settings/plugins.py new file mode 100644 index 00000000..b918a56b --- /dev/null +++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py @@ -0,0 +1,133 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Plugin settings UI.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba + +if TYPE_CHECKING: + from typing import Tuple, Optional + + +class PluginSettingsWindow(ba.Window): + """Window for configuring plugins.""" + + def __init__(self, + transition: str = 'in_right', + origin_widget: ba.Widget = None): + + app = ba.app + + # If they provided an origin-widget, scale up from that. + scale_origin: Optional[Tuple[float, float]] + if origin_widget is not None: + self._transition_out = 'out_scale' + scale_origin = origin_widget.get_screen_space_center() + transition = 'in_scale' + else: + self._transition_out = 'out_right' + scale_origin = None + + uiscale = ba.app.uiscale + self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0 + x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 + self._height = (390.0 if uiscale is ba.UIScale.SMALL else + 450.0 if uiscale is ba.UIScale.MEDIUM else 520.0) + top_extra = 10 if uiscale is ba.UIScale.SMALL else 0 + super().__init__(root_widget=ba.containerwidget( + size=(self._width, self._height + top_extra), + transition=transition, + toolbar_visibility='menu_minimal', + scale_origin_stack_offset=scale_origin, + scale=(2.06 if uiscale is ba.UIScale.SMALL else + 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), + stack_offset=(0, -25) if uiscale is ba.UIScale.SMALL else (0, 0))) + + self._scroll_width = self._width - (100 + 2 * x_inset) + self._scroll_height = self._height - 115.0 + self._sub_width = self._scroll_width * 0.95 + self._sub_height = 724.0 + + if app.ui.use_toolbars and uiscale is ba.UIScale.SMALL: + ba.containerwidget(edit=self._root_widget, + on_cancel_call=self._do_back) + self._back_button = None + else: + self._back_button = ba.buttonwidget( + parent=self._root_widget, + position=(53 + x_inset, self._height - 60), + size=(140, 60), + scale=0.8, + autoselect=True, + label=ba.Lstr(resource='backText'), + button_type='back', + on_activate_call=self._do_back) + ba.containerwidget(edit=self._root_widget, + cancel_button=self._back_button) + + self._title_text = ba.textwidget(parent=self._root_widget, + position=(0, self._height - 52), + size=(self._width, 25), + text=ba.Lstr(resource='pluginsText'), + color=app.ui.title_color, + h_align='center', + v_align='top') + + if self._back_button is not None: + ba.buttonwidget(edit=self._back_button, + button_type='backSmall', + size=(60, 60), + label=ba.charstr(ba.SpecialChar.BACK)) + + self._scrollwidget = ba.scrollwidget(parent=self._root_widget, + position=(50 + x_inset, 50), + simple_culling_v=20.0, + highlight=False, + size=(self._scroll_width, + self._scroll_height)) + ba.containerwidget(edit=self._scrollwidget, + selection_loop_to_parent=True) + self._subcontainer = ba.containerwidget(parent=self._scrollwidget, + size=(self._sub_width, + self._sub_height), + background=False, + selection_loop_to_parent=True) + + ba.screenmessage('Work in progress...') + self._restore_state() + + def _save_state(self) -> None: + print('would save state') + + def _restore_state(self) -> None: + print('would restore state') + + def _do_back(self) -> None: + # pylint: disable=cyclic-import + from bastd.ui.settings.advanced import AdvancedSettingsWindow + self._save_state() + ba.containerwidget(edit=self._root_widget, + transition=self._transition_out) + ba.app.ui.set_main_menu_window( + AdvancedSettingsWindow(transition='in_left').get_root_widget()) From f928e80d7826a6a32027be8e9541f9ab2e1725bf Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 16 Jul 2020 16:05:26 -0700 Subject: [PATCH 158/417] Tidying --- .efrocachemap | 24 +++++++++---------- .idea/dictionaries/ericf.xml | 1 + assets/src/ba_data/python/_ba.py | 2 +- assets/src/ba_data/python/ba/_hooks.py | 9 ++++--- .../src/ba_data/python/bastd/ui/mainmenu.py | 4 ++++ docs/ba_module.md | 4 ++-- 6 files changed, 26 insertions(+), 18 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 0a2147eb..a52dc74f 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/2f/d2/729e7d4c7e884bcdc6749a52c069", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b8/45/60a8069130b52e85422236921806", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/80/84/06b8fd82adb7a10dfc2c5a6b622b", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/54/fa/b6d33c93285c9d686bf455374ce3", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/db/d010f67fb908315d89e7a0e38fb7", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6a/34/66068c15c8e349743d82be4b0e98", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/03/89949b43cdf17f571e549a85e439", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d1/a0/5ffc17a4b0c4c93ee3de59a1597b", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/87/17/e01ce11e3c4869da04e0a8824ee8", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8f/30/dc9361159cb9b1c735e8957a0a66", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/07/c2/fbed8e21c1b973f9b30267b49386", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a3/2f/04346dd3c73a959eef8d59c43991" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/82/fccd083509e35606a05e8f4be12b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2d/db/1ba0b8fda62bb9673ae9a2d72263", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f6/c5/1d925d0f72e30e745db0c69f3492", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/a3/c2a5a5ac6b9e0756d5acc7872cd2", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8d/68/1b60db385be21968a1e62c0d8909", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/02/9eeac67f0678cdab9ee567975d46", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/4d/fddd748467190c6a6b90f7c428ac", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/da/ab/18a3841614075e089a7c3fe1a352", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d8/70/4b2203294c25113fe81e316b63f2", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6c/d9/3d25b18546efcdafc10107b0c970", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/77/58/4cfb2e7779068f1d0edbaa521e8f", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4b/45/4ebd1210c99b29c76c73228c3406" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 075831cb..5b2a603d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -202,6 +202,7 @@ bombsquadgame bools bootlocale + borhani botdist botlist botpos diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index ca9209ab..45a72cb6 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -1761,7 +1761,7 @@ def disconnect_from_host() -> None: def do_once() -> bool: """do_once() -> bool - Register a call at a location and return whether one already happened. + Return whether this is the first time running a line of code. Category: General Utility Functions diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index 0c5e95c0..0f45ad13 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -269,9 +269,12 @@ def read_config() -> None: def ui_remote_press() -> None: """Handle a press by a remote device that is only usable for nav.""" from ba._lang import Lstr - _ba.screenmessage(Lstr(resource='internal.controllerForMenusOnlyText'), - color=(1, 0, 0)) - _ba.playsound(_ba.getsound('error')) + + # Can be called without a context; need a context for getsound. + with _ba.Context('ui'): + _ba.screenmessage(Lstr(resource='internal.controllerForMenusOnlyText'), + color=(1, 0, 0)) + _ba.playsound(_ba.getsound('error')) def quit_window() -> None: diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 292b4171..f021f9da 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -824,6 +824,10 @@ class MainMenuWindow(ba.Window): return h, v, scale def _change_replay_speed(self, offs: int) -> None: + if not self._replay_speed_text: + if ba.do_once(): + print('_change_replay_speed called without widget') + return _ba.set_replay_speed_exponent(_ba.get_replay_speed_exponent() + offs) actual_speed = pow(2.0, _ba.get_replay_speed_exponent()) ba.textwidget(edit=self._replay_speed_text, diff --git a/docs/ba_module.md b/docs/ba_module.md index 6173809a..50fa5e0b 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-15 for Ballistica version 1.5.22 build 20140

    +

    last updated on 2020-07-16 for Ballistica version 1.5.22 build 20144

    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!


    @@ -6127,7 +6127,7 @@ are applied to the Widget.

    ba.do_once()

    do_once() -> bool

    -

    Register a call at a location and return whether one already happened.

    +

    Return whether this is the first time running a line of code.

    Category: General Utility Functions

    From a17863961c1db47520cb2a07cd66651806e00d55 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 17 Jul 2020 01:51:17 -0700 Subject: [PATCH 159/417] Fixed hardware keyboards in android on the in-game terminal --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 4 +++- docs/ba_module.md | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index a52dc74f..c662f72c 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/99/82/fccd083509e35606a05e8f4be12b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2d/db/1ba0b8fda62bb9673ae9a2d72263", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/f6/c5/1d925d0f72e30e745db0c69f3492", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/a3/c2a5a5ac6b9e0756d5acc7872cd2", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/8d/68/1b60db385be21968a1e62c0d8909", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/02/9eeac67f0678cdab9ee567975d46", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/4d/fddd748467190c6a6b90f7c428ac", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/da/ab/18a3841614075e089a7c3fe1a352", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d8/70/4b2203294c25113fe81e316b63f2", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6c/d9/3d25b18546efcdafc10107b0c970", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/77/58/4cfb2e7779068f1d0edbaa521e8f", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4b/45/4ebd1210c99b29c76c73228c3406" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/e7/d9f1262e508f61108f0d98c230bc", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/b3/a1990b135a846f8ad3e96bbf8531", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/d9/e1ec28e6c1c786fc8a355ce87417", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/17/39ad7638d945655d4cd91c223bc4", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bb/be/aefa046a757d570dab1902bace07", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/64/f3/6731d935940dcc4880e618ec41d6", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/2b/05a05bfcb05557acb98e88e4debe", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6c/df/8413a93ea22a3f456a4455576fd8", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/76/7e44dac9293d8cc7d097bdcef9f2", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/da/eb/9f13cc430e1e00435ab7c8ef6a1a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b4/38/d1bc194d914fccab834816ee63e8", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e7/6b/3625cd76f20f4d1f165dfbeeaa24" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 04624cb2..6987a771 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ -### Unreleased +### 1.5.23 - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. +- Fixed a bug with hardware keyboards emitting extra characters in the in-game console (~ or F2) +- Added support for 'plugin' mods and user controls to configure them in settings->advanced->plugins. ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). diff --git a/docs/ba_module.md b/docs/ba_module.md index 50fa5e0b..c247911a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-16 for Ballistica version 1.5.22 build 20144

    +

    last updated on 2020-07-17 for Ballistica version 1.5.22 build 20144

    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!


    From 1ff2793c00f53b7980812dc395724a411a5dade0 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 17 Jul 2020 01:59:46 -0700 Subject: [PATCH 160/417] Corrected version --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index c662f72c..6308dead 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/c4/e7/d9f1262e508f61108f0d98c230bc", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/b3/a1990b135a846f8ad3e96bbf8531", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/d9/e1ec28e6c1c786fc8a355ce87417", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c9/17/39ad7638d945655d4cd91c223bc4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bb/be/aefa046a757d570dab1902bace07", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/64/f3/6731d935940dcc4880e618ec41d6", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/90/2b/05a05bfcb05557acb98e88e4debe", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6c/df/8413a93ea22a3f456a4455576fd8", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/76/7e44dac9293d8cc7d097bdcef9f2", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/da/eb/9f13cc430e1e00435ab7c8ef6a1a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b4/38/d1bc194d914fccab834816ee63e8", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e7/6b/3625cd76f20f4d1f165dfbeeaa24" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d4/c1/8271c57f122e0b573e8794f7cd5b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/75/9db6b288e2d175cf84f955dbf6bb", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/c0/45729931ae9b895cff96045e0fcd", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/df/82/d918dfc09d4eebb56d46bf9b5c87", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/f0/f9b9b7f9de47e96a83ac415802ab", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/72/bc/8a8e931021e9c5ad34dd4363b0db", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/20/b6/c0ec182a7d36823e401b445e86d6", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/42/7ff30ce0d325d9d5d6d3a7b5bd76", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/91/40/c29c43a8a01ec909e4743c68c664", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1f/46/b28c2c2856aa79cae5130da98752", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/df/df/a3f01417e4e3982e6e8964bd6b06", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cd/45/268e89bafe3d75129e4bc5a2acbe" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 6987a771..8dc32dac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5.23 +### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. - Fixed a bug with hardware keyboards emitting extra characters in the in-game console (~ or F2) - Added support for 'plugin' mods and user controls to configure them in settings->advanced->plugins. From 1e5ca85dc9da587a224f507dcffd0e7316a4273f Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 18 Jul 2020 00:06:21 -0700 Subject: [PATCH 161/417] Updated Android Python to 3.7.8 --- .efrocachemap | 70 ++++++++++++++++++------------------ .idea/dictionaries/ericf.xml | 2 ++ tools/efrotools/pybuild.py | 49 ++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 36 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 6308dead..9f3857dd 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -2565,7 +2565,7 @@ "assets/build/pylib-android/_compression.py": "https://files.ballistica.net/cache/ba1/93/7f/56c3fd789058399b898c5c527b92", "assets/build/pylib-android/_dummy_thread.py": "https://files.ballistica.net/cache/ba1/5b/a5/82c6ed2ef16974f8cfd5ee2e11f6", "assets/build/pylib-android/_markupbase.py": "https://files.ballistica.net/cache/ba1/a5/5e/6ad43bfbcd054529b852fa9d9919", - "assets/build/pylib-android/_osx_support.py": "https://files.ballistica.net/cache/ba1/61/30/ac3f83f7567392218242dc1bd371", + "assets/build/pylib-android/_osx_support.py": "https://files.ballistica.net/cache/ba1/1a/dd/18c02bae9dd4e2b651071dd0e606", "assets/build/pylib-android/_py_abc.py": "https://files.ballistica.net/cache/ba1/63/57/80933fee0979574b2d3b1172cdc8", "assets/build/pylib-android/_pydecimal.py": "https://files.ballistica.net/cache/ba1/78/1c/999595e074c71574c01ff521a6e0", "assets/build/pylib-android/_pyio.py": "https://files.ballistica.net/cache/ba1/e6/8e/da9cef09b9375b297ccc45cbedf7", @@ -2577,7 +2577,7 @@ "assets/build/pylib-android/aifc.py": "https://files.ballistica.net/cache/ba1/8a/d6/25bd39b0581236a85b096ba3fe9d", "assets/build/pylib-android/antigravity.py": "https://files.ballistica.net/cache/ba1/83/cf/9d1698d68e0e260e6bbefec5a516", "assets/build/pylib-android/argparse.py": "https://files.ballistica.net/cache/ba1/7d/a3/3c4997b2a8c0c3486ee6a88a1d11", - "assets/build/pylib-android/ast.py": "https://files.ballistica.net/cache/ba1/4d/98/0c14a8fb30313b4f4d9650772599", + "assets/build/pylib-android/ast.py": "https://files.ballistica.net/cache/ba1/b7/42/718de3a57faaca60e6107da1791d", "assets/build/pylib-android/asynchat.py": "https://files.ballistica.net/cache/ba1/5e/b1/f69db224de08b5e119f5c0f425a8", "assets/build/pylib-android/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/6d/27/61dd597138eea19aaf7d724ee691", "assets/build/pylib-android/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/93/62/5ee3d4885bf7d85654964fb065e3", @@ -2601,7 +2601,7 @@ "assets/build/pylib-android/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/c8/c4/e58d4c6d467aff6b79cda30f9b52", "assets/build/pylib-android/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/92/c3/5a2f6c0fe03583f3f1255456959e", "assets/build/pylib-android/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/55/a3/0f5d3365b3235c75b2ea80bd5563", - "assets/build/pylib-android/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/58/44/5520e46a45d5630e95dad27b66d7", + "assets/build/pylib-android/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/eb/86/58dff20a80672a8e4406668de361", "assets/build/pylib-android/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/3d/20/87bd62ba23f5d9f81421eb287041", "assets/build/pylib-android/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/2e/f9/7642257a860d664f7242efecb3f7", "assets/build/pylib-android/asyncore.py": "https://files.ballistica.net/cache/ba1/25/1f/ccae9e6cdd0885f9d989a3902e9b", @@ -2612,13 +2612,13 @@ "assets/build/pylib-android/bz2.py": "https://files.ballistica.net/cache/ba1/84/cb/27cdd0e9186f848fe949c2a3bee7", "assets/build/pylib-android/cProfile.py": "https://files.ballistica.net/cache/ba1/6e/44/33dbc763d5d1bf76678bdbe772f4", "assets/build/pylib-android/calendar.py": "https://files.ballistica.net/cache/ba1/74/31/64ce1c94d173a6226df81fbe2baf", - "assets/build/pylib-android/cgi.py": "https://files.ballistica.net/cache/ba1/ba/63/856b253fbd572d7b925b552354b8", + "assets/build/pylib-android/cgi.py": "https://files.ballistica.net/cache/ba1/84/f5/4581cafa1723aab9252016a9128d", "assets/build/pylib-android/cgitb.py": "https://files.ballistica.net/cache/ba1/45/67/f3f215ae81b670ba05d94706a2ab", "assets/build/pylib-android/chunk.py": "https://files.ballistica.net/cache/ba1/f6/fe/3c43d1dc84ee74b8a170c61271a3", "assets/build/pylib-android/cmd.py": "https://files.ballistica.net/cache/ba1/f0/d9/8cec4bcbbfd195d46c3ad637df71", "assets/build/pylib-android/code.py": "https://files.ballistica.net/cache/ba1/7a/a4/ee660f11ad995354a3b21efbfb1c", "assets/build/pylib-android/codecs.py": "https://files.ballistica.net/cache/ba1/ed/16/584061843712bbb77342ee17c423", - "assets/build/pylib-android/codeop.py": "https://files.ballistica.net/cache/ba1/19/1a/47fd0ef5269e708ad2faf50db559", + "assets/build/pylib-android/codeop.py": "https://files.ballistica.net/cache/ba1/9b/f7/a7fac5b57aa2aa74739f16d62515", "assets/build/pylib-android/collections/__init__.py": "https://files.ballistica.net/cache/ba1/96/31/74bf91d70ac53f56c651ea0b1c6f", "assets/build/pylib-android/collections/abc.py": "https://files.ballistica.net/cache/ba1/29/45/a03469c0f5eb61d823b277d547ce", "assets/build/pylib-android/colorsys.py": "https://files.ballistica.net/cache/ba1/d6/3b/b932055a535b017694e91296168c", @@ -2654,11 +2654,11 @@ "assets/build/pylib-android/decimal.py": "https://files.ballistica.net/cache/ba1/92/94/b8be378718b3ede8f05f07aa257b", "assets/build/pylib-android/difflib.py": "https://files.ballistica.net/cache/ba1/6c/c2/0e781f8333593d5cb5890f702476", "assets/build/pylib-android/dis.py": "https://files.ballistica.net/cache/ba1/a1/d1/7ccecfaa71f7cd43ce504eb53194", - "assets/build/pylib-android/doctest.py": "https://files.ballistica.net/cache/ba1/5b/27/a20fbc6e0c46230b9d02d0e016a5", + "assets/build/pylib-android/doctest.py": "https://files.ballistica.net/cache/ba1/88/94/4e162825868d974768473472df54", "assets/build/pylib-android/dummy_threading.py": "https://files.ballistica.net/cache/ba1/20/2f/ec8e68634908312148b53a5dfd4c", "assets/build/pylib-android/email/__init__.py": "https://files.ballistica.net/cache/ba1/2b/f0/8c85ab15e7cdbdaa0e1705223012", "assets/build/pylib-android/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/08/fa/de22bc96e1e332bbe1cf76162a1c", - "assets/build/pylib-android/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/d8/a5/2c5574aedbde0de48d72b06770ef", + "assets/build/pylib-android/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/9f/f5/17085d073d928ec6c0b8e37fcb95", "assets/build/pylib-android/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/e0/b3/b0167200b852c46e60116ba12740", "assets/build/pylib-android/email/_policybase.py": "https://files.ballistica.net/cache/ba1/19/f9/844a8a848bc5670a810d06f0a6de", "assets/build/pylib-android/email/base64mime.py": "https://files.ballistica.net/cache/ba1/6b/52/907171fcf7e3baf097a4d503d79c", @@ -2669,7 +2669,7 @@ "assets/build/pylib-android/email/feedparser.py": "https://files.ballistica.net/cache/ba1/98/6d/61c614d442ca8451320ca7fe4e86", "assets/build/pylib-android/email/generator.py": "https://files.ballistica.net/cache/ba1/c1/23/173f2e5fd02455bd2db0970c9ca0", "assets/build/pylib-android/email/header.py": "https://files.ballistica.net/cache/ba1/bb/cb/194570894c14063cd85ea2d8ab6a", - "assets/build/pylib-android/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/a7/c9/e8d4ab6d0b0a13c4c0330a9201e1", + "assets/build/pylib-android/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/4b/d3/0240bedc7e23ba3e3022f6d2b87c", "assets/build/pylib-android/email/iterators.py": "https://files.ballistica.net/cache/ba1/a5/02/2f56787a3fb91547c61284d7facd", "assets/build/pylib-android/email/message.py": "https://files.ballistica.net/cache/ba1/9e/50/f42dc086f8eedac768907140cf75", "assets/build/pylib-android/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/42/fb/835abe12a4e1e72a5d1711d12cde", @@ -2810,7 +2810,7 @@ "assets/build/pylib-android/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/c5/56/c3d98c0cb4cf569fb833ed919cc1", "assets/build/pylib-android/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/f9/64/0107520eca9130ca870cec675bf0", "assets/build/pylib-android/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/b4/3f/7369ee7aa1aa36b098c3b33ea31b", - "assets/build/pylib-android/enum.py": "https://files.ballistica.net/cache/ba1/b1/ee/e7435d4112cdaef0192c57f12531", + "assets/build/pylib-android/enum.py": "https://files.ballistica.net/cache/ba1/de/8f/09627b04f762c56e00c24cdd5c3f", "assets/build/pylib-android/filecmp.py": "https://files.ballistica.net/cache/ba1/54/d4/3d6d66bd7d4ee85407851fe986a0", "assets/build/pylib-android/fileinput.py": "https://files.ballistica.net/cache/ba1/00/79/91b5218d122a5ede37fb0c821b22", "assets/build/pylib-android/fnmatch.py": "https://files.ballistica.net/cache/ba1/d5/44/0a58d9161ae9d2409ae2477b5948", @@ -2831,7 +2831,7 @@ "assets/build/pylib-android/html/entities.py": "https://files.ballistica.net/cache/ba1/02/4d/e42a17593176e35ff5da8d720cf9", "assets/build/pylib-android/html/parser.py": "https://files.ballistica.net/cache/ba1/c7/87/628a5a87855afbac3ebbd858e9a1", "assets/build/pylib-android/http/__init__.py": "https://files.ballistica.net/cache/ba1/93/8e/37eb6e0c8e0e85fbc817d9b7a7ac", - "assets/build/pylib-android/http/client.py": "https://files.ballistica.net/cache/ba1/cb/64/465b1cf482df244287406c2d04d9", + "assets/build/pylib-android/http/client.py": "https://files.ballistica.net/cache/ba1/91/76/10a31e7d6260da3f5cc290b14441", "assets/build/pylib-android/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/79/72/6cb2162180eaec43445a53f3ee97", "assets/build/pylib-android/http/cookies.py": "https://files.ballistica.net/cache/ba1/31/12/7d40c2be1ef8456a4abeb613d633", "assets/build/pylib-android/http/server.py": "https://files.ballistica.net/cache/ba1/9e/b7/7c94874f5f3684a110923c113b65", @@ -2851,9 +2851,9 @@ "assets/build/pylib-android/json/decoder.py": "https://files.ballistica.net/cache/ba1/3f/bf/6fd2a01d31cd85e4c21cf2c0a5c8", "assets/build/pylib-android/json/encoder.py": "https://files.ballistica.net/cache/ba1/5f/36/b17803f0c2b18467b7d10e87e46d", "assets/build/pylib-android/json/scanner.py": "https://files.ballistica.net/cache/ba1/c8/4b/bcc458a5047e9ac8064a607ee231", - "assets/build/pylib-android/json/tool.py": "https://files.ballistica.net/cache/ba1/59/1f/a5883f250a5a8584a786531159eb", + "assets/build/pylib-android/json/tool.py": "https://files.ballistica.net/cache/ba1/20/ac/edbfd1cabc47b3f3d57b37c95116", "assets/build/pylib-android/keyword.py": "https://files.ballistica.net/cache/ba1/1d/8a/1cdb5840e8f561ec69407f898752", - "assets/build/pylib-android/linecache.py": "https://files.ballistica.net/cache/ba1/60/c9/68f020023d9b6d0e7f1f7d6d6b50", + "assets/build/pylib-android/linecache.py": "https://files.ballistica.net/cache/ba1/01/91/9aecf23d41972edd3bcb7927b1fe", "assets/build/pylib-android/locale.py": "https://files.ballistica.net/cache/ba1/ab/cf/da9a211a39662f631b6869e1c28b", "assets/build/pylib-android/logging/__init__.py": "https://files.ballistica.net/cache/ba1/0d/d3/3460e7bd9309e2e09cbbac2c2f66", "assets/build/pylib-android/logging/config.py": "https://files.ballistica.net/cache/ba1/14/a0/a315016fa0d6d748d204acde0c8d", @@ -2873,13 +2873,13 @@ "assets/build/pylib-android/operator.py": "https://files.ballistica.net/cache/ba1/03/ac/fc74fa2a3146b00f9ee1921996c5", "assets/build/pylib-android/optparse.py": "https://files.ballistica.net/cache/ba1/56/b4/9ae8b02341d9b2b5c1a75d5f8729", "assets/build/pylib-android/os.py": "https://files.ballistica.net/cache/ba1/d0/78/d8693c3a2c5c4684faadf46ebed5", - "assets/build/pylib-android/pathlib.py": "https://files.ballistica.net/cache/ba1/f6/90/a68b8e0dffc669ae7aec2c95010c", + "assets/build/pylib-android/pathlib.py": "https://files.ballistica.net/cache/ba1/ee/4c/ae4cf6fa2e0b54aa42e26cbc6295", "assets/build/pylib-android/pdb.py": "https://files.ballistica.net/cache/ba1/84/4f/9fc933776560b7e45cb7ef3bcfa9", "assets/build/pylib-android/pickle.py": "https://files.ballistica.net/cache/ba1/81/cf/a94f6e8a45671c34c1d9d4efdc13", "assets/build/pylib-android/pickletools.py": "https://files.ballistica.net/cache/ba1/c7/0a/1f89f5d71ccf1f9269cc5f8d3d72", "assets/build/pylib-android/pipes.py": "https://files.ballistica.net/cache/ba1/ed/d3/9e08e7ece839c58d885223c57adb", "assets/build/pylib-android/pkgutil.py": "https://files.ballistica.net/cache/ba1/3f/27/1c376bf997f3ee3a09c9ffdb58d6", - "assets/build/pylib-android/platform.py": "https://files.ballistica.net/cache/ba1/23/0a/090ebfcb1943ca88f9a524f05b6a", + "assets/build/pylib-android/platform.py": "https://files.ballistica.net/cache/ba1/99/72/0d5d720f5936836937633e4cc54e", "assets/build/pylib-android/plistlib.py": "https://files.ballistica.net/cache/ba1/ff/ca/c37a29df76785ad0bb6975627639", "assets/build/pylib-android/poplib.py": "https://files.ballistica.net/cache/ba1/62/c4/c9a5a81583fcd7e7767ea6392ef4", "assets/build/pylib-android/posixpath.py": "https://files.ballistica.net/cache/ba1/8c/52/9a1a9b00a9a4c12c8fd0bb840865", @@ -2893,7 +2893,7 @@ "assets/build/pylib-android/queue.py": "https://files.ballistica.net/cache/ba1/8c/f8/37f30b7f7500462869580f7eb14c", "assets/build/pylib-android/quopri.py": "https://files.ballistica.net/cache/ba1/f3/08/1d7b3e0f7ce1ad649b1abf08f8ac", "assets/build/pylib-android/random.py": "https://files.ballistica.net/cache/ba1/f3/8e/b752b23583b23a38bb15cb176522", - "assets/build/pylib-android/re.py": "https://files.ballistica.net/cache/ba1/31/52/f31201e7ade98dab88d2f36faee8", + "assets/build/pylib-android/re.py": "https://files.ballistica.net/cache/ba1/d2/41/e4c70d2365338a2c378f55920849", "assets/build/pylib-android/reprlib.py": "https://files.ballistica.net/cache/ba1/81/66/44ee9dceee6943006c4500ee3303", "assets/build/pylib-android/rlcompleter.py": "https://files.ballistica.net/cache/ba1/fe/06/6f06102f9f6c8c0e73a33714c25a", "assets/build/pylib-android/runpy.py": "https://files.ballistica.net/cache/ba1/6b/e1/0453f97c2fcc323bf89989a74974", @@ -2925,28 +2925,28 @@ "assets/build/pylib-android/subprocess.py": "https://files.ballistica.net/cache/ba1/f6/bf/640ac9ceb0e3d7cfbe02bef64557", "assets/build/pylib-android/sunau.py": "https://files.ballistica.net/cache/ba1/ff/0e/1a6c5fd41803511cad28595dc248", "assets/build/pylib-android/symbol.py": "https://files.ballistica.net/cache/ba1/a5/26/eea6d483c82e7b4048937832889d", - "assets/build/pylib-android/symtable.py": "https://files.ballistica.net/cache/ba1/46/92/4be884871052300c5e7b9a11164b", + "assets/build/pylib-android/symtable.py": "https://files.ballistica.net/cache/ba1/e0/43/5390cbe7195d9edcddbbd2aa1cfa", "assets/build/pylib-android/sysconfig.py": "https://files.ballistica.net/cache/ba1/9b/d7/6b01292e81749e4d3fd2bf762f7f", "assets/build/pylib-android/tabnanny.py": "https://files.ballistica.net/cache/ba1/f3/7e/b463d5f4ead23d34a36d0e559447", "assets/build/pylib-android/tarfile.py": "https://files.ballistica.net/cache/ba1/46/a6/9d1a46c06d7b5e787efbfeadec05", "assets/build/pylib-android/telnetlib.py": "https://files.ballistica.net/cache/ba1/60/28/4aab22dece4896a4d32694bbe282", - "assets/build/pylib-android/tempfile.py": "https://files.ballistica.net/cache/ba1/69/88/1a506e6ee4ff144b2aecd4e98ad2", + "assets/build/pylib-android/tempfile.py": "https://files.ballistica.net/cache/ba1/03/07/434e753d91b18bbbd9b1c7640ce8", "assets/build/pylib-android/textwrap.py": "https://files.ballistica.net/cache/ba1/4c/4b/c743c5e7427b00f428c318a9673b", "assets/build/pylib-android/this.py": "https://files.ballistica.net/cache/ba1/a8/fa/4d1152b689d75bc1a997ff34b799", - "assets/build/pylib-android/threading.py": "https://files.ballistica.net/cache/ba1/95/c1/7562cfde69149c713cd881cb4d56", - "assets/build/pylib-android/timeit.py": "https://files.ballistica.net/cache/ba1/b3/b7/a2c93ac110fde00eebcb74a7ced1", + "assets/build/pylib-android/threading.py": "https://files.ballistica.net/cache/ba1/11/3a/cdb3194846494446ed43bf6d0050", + "assets/build/pylib-android/timeit.py": "https://files.ballistica.net/cache/ba1/55/7b/f7ef83f08ac5cb36ddaff03ac6ab", "assets/build/pylib-android/token.py": "https://files.ballistica.net/cache/ba1/2d/f8/943c252465b687a5bc367315432f", "assets/build/pylib-android/tokenize.py": "https://files.ballistica.net/cache/ba1/07/cc/13a7ec5c4d674ab025cb19186f7c", "assets/build/pylib-android/trace.py": "https://files.ballistica.net/cache/ba1/9b/9d/d6806d339c36bfc6a2b4769688e0", - "assets/build/pylib-android/traceback.py": "https://files.ballistica.net/cache/ba1/8b/67/e189e176678255fe36a67f9cfe71", + "assets/build/pylib-android/traceback.py": "https://files.ballistica.net/cache/ba1/fe/d7/2f880598e52c5c28a46df0ba0555", "assets/build/pylib-android/tracemalloc.py": "https://files.ballistica.net/cache/ba1/46/49/5683d0d9e0e342392361adb6e9a3", "assets/build/pylib-android/tty.py": "https://files.ballistica.net/cache/ba1/ad/19/a6ad29b8958fa9f5acc3cf71d3b2", "assets/build/pylib-android/types.py": "https://files.ballistica.net/cache/ba1/b9/5d/5467b37ac0f36b2ff4dd8ef458fd", - "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/bf/f6/998b69740a766155dee2eabdf859", + "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/de/0e/4506f09141585ca5fa94c90cf678", "assets/build/pylib-android/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/b0/56/87601ed47a5181d1e6a40eb4ea40", "assets/build/pylib-android/urllib/error.py": "https://files.ballistica.net/cache/ba1/07/8c/573897fc3bdc6d3e2e8d449f17c7", "assets/build/pylib-android/urllib/parse.py": "https://files.ballistica.net/cache/ba1/14/09/ffed6f45250b0b2dc1a86f3eb700", - "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/fd/2c/abd2d31e790eb1bf4c6e19eacfd8", + "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/d7/3e/bba38f3fc5c737cef80f48f69184", "assets/build/pylib-android/urllib/response.py": "https://files.ballistica.net/cache/ba1/c4/d5/676a8e9fc4f7bd21ac2f555fc3fc", "assets/build/pylib-android/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/c7/a8/487a1aeccfbf4370fdb33b136b51", "assets/build/pylib-android/uu.py": "https://files.ballistica.net/cache/ba1/a1/89/070ed8553858a75fcafae4b7bd37", @@ -2954,7 +2954,7 @@ "assets/build/pylib-android/warnings.py": "https://files.ballistica.net/cache/ba1/74/1f/097efcf5f38c0b41fcba3f60b44d", "assets/build/pylib-android/wave.py": "https://files.ballistica.net/cache/ba1/f8/72/9e060ca777991ea45d71eed336ca", "assets/build/pylib-android/weakref.py": "https://files.ballistica.net/cache/ba1/d2/48/f82fb97686199616e57417ee9e7a", - "assets/build/pylib-android/webbrowser.py": "https://files.ballistica.net/cache/ba1/c4/03/bd37d4bb045d5c20b78c518574fe", + "assets/build/pylib-android/webbrowser.py": "https://files.ballistica.net/cache/ba1/26/4a/b0ee4c8655e2c8ea7389d3a2b329", "assets/build/pylib-android/xdrlib.py": "https://files.ballistica.net/cache/ba1/ec/bf/84d830dca1231ec1a67d8ccbb21f", "assets/build/pylib-android/xml/__init__.py": "https://files.ballistica.net/cache/ba1/ba/67/bbd97e53f3db5ebc3abd3fef2275", "assets/build/pylib-android/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/36/76/2a47e7bc727db1c44d157b23d2c3", @@ -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/d4/c1/8271c57f122e0b573e8794f7cd5b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/28/75/9db6b288e2d175cf84f955dbf6bb", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/c0/45729931ae9b895cff96045e0fcd", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/df/82/d918dfc09d4eebb56d46bf9b5c87", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/f0/f9b9b7f9de47e96a83ac415802ab", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/72/bc/8a8e931021e9c5ad34dd4363b0db", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/20/b6/c0ec182a7d36823e401b445e86d6", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/42/7ff30ce0d325d9d5d6d3a7b5bd76", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/91/40/c29c43a8a01ec909e4743c68c664", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1f/46/b28c2c2856aa79cae5130da98752", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/df/df/a3f01417e4e3982e6e8964bd6b06", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/cd/45/268e89bafe3d75129e4bc5a2acbe" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/51/d5/b58e2da2a9dd4dba968acbbaf2a4", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/71/74/ce3f41e66235e907aedbf609b3bf", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/92/6b/ecebeada2b7401f9401877863a21", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/07/18/c56004638b1ebd5234974ffe3644", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b8/2a/6726ae2d5f56bdc9b663adda0e2e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/0c/8604fbcf8979a024d16cf1ad3f38", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/00/75/f1d62f08e8b5f523270819bd1ad0", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b8/92/a15a90fe81687a2ef49ef5275617", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/f9/0ef6fa2ef75f77d3ebe357a060da", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/f6/eb48fccf54236e4016181b37fee6", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/bc/dd92fe8e0f5ec65356e973228d4d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/19/d1/e83d59e2deb988d6dc2d4032e202" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 5b2a603d..07924e3f 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1392,6 +1392,7 @@ pandroid parallelized parsermodule + parsetok partyqueue partyval passnode @@ -1415,6 +1416,7 @@ peditui pentry perma + perrdetail phasers phello photoshop diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index 3d7f93a4..e7362d69 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -297,7 +297,8 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: efrotools.writefile('pybuild/packages/python.py', ftxt) # Set this to a particular cpython commit to target exact releases from git - commit = 'd7c567b08f9d7d6aef21b881340a2b72731129db' # 3.7.7 release + # commit = 'd7c567b08f9d7d6aef21b881340a2b72731129db' # 3.7.7 release + commit = '4b47a5b6ba66b02df9392feb97b8ead916f8c1fa' # 3.7.8 release if commit is not None: ftxt = efrotools.readfile('pybuild/source.py') @@ -417,6 +418,52 @@ def android_patch() -> None: ' [A-Z]*=*) DEFS="$line$NL$DEFS"; continue;;') efrotools.writefile(fname, txt) + # Add custom callbacks to Python's PyParser_ParseFileObject + # and PyParser_ParseString calls to debug a crash. + fname = 'src/cpython/Parser/parsetok.c' + txt = efrotools.readfile(fname) + txt = efrotools.replace_one( + txt, 'node *\n' + 'PyParser_ParseFileObject(FILE *fp, PyObject *filename,\n' + ' const char *enc, grammar *g, int start,\n' + ' const char *ps1, const char *ps2,\n' + ' perrdetail *err_ret, int *flags)\n' + '{\n', 'void (*PyParser_ParseFileObject_EfroCB)' + '(FILE *fp, PyObject *filename,\n' + ' const char *enc, grammar *g, int start,\n' + ' const char *ps1, const char *ps2,\n' + ' perrdetail *err_ret, int *flags) = NULL;\n' + 'node *\n' + 'PyParser_ParseFileObject(FILE *fp, PyObject *filename,\n' + ' const char *enc, grammar *g, int start,\n' + ' const char *ps1, const char *ps2,\n' + ' perrdetail *err_ret, int *flags)\n' + '{\n' + ' if (PyParser_ParseFileObject_EfroCB != NULL) {\n' + ' PyParser_ParseFileObject_EfroCB(fp, filename, enc, g,\n' + ' start, ps1, ps2,\n' + ' err_ret, flags);\n' + ' }\n') + txt = efrotools.replace_one( + txt, 'node *\n' + 'PyParser_ParseStringObject(const char *s, PyObject *filename,\n' + ' grammar *g, int start,\n' + ' perrdetail *err_ret, int *flags)\n' + '{\n', 'void (*PyParser_ParseStringObject_EfroCB)' + '(const char *s, PyObject *filename,\n' + ' grammar *g, int start,\n' + ' perrdetail *err_ret, int *flags) = NULL;\n' + 'node *\n' + 'PyParser_ParseStringObject(const char *s, PyObject *filename,\n' + ' grammar *g, int start,\n' + ' perrdetail *err_ret, int *flags)\n' + '{\n' + ' if (PyParser_ParseStringObject_EfroCB != NULL) {\n' + ' PyParser_ParseStringObject_EfroCB(s, filename, g, start,\n' + ' err_ret, flags);\n' + ' }\n') + efrotools.writefile(fname, txt) + print('APPLIED EFROTOOLS ANDROID BUILD PATCHES.') From e0d0c1d3d4d43b577949c734c345ea0214d74df7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 19 Jul 2020 01:38:28 -0700 Subject: [PATCH 162/417] Language updates and more plugin work --- .efrocachemap | 38 +++++++++++++++++++------------------- docs/ba_module.md | 2 +- tools/efrotools/ios.py | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 9f3857dd..f8b3ca81 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,31 +420,31 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/ad/82/41fe495cb2c7431379171fc5778e", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/de/c0/7197e7658bef48309741dfaf86c7", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/30/8e/38c5f21b9251ea1111bed554035f", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/97/4e/48ae80fb711a22559a311c49b358", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/ea/14/6485c200c717f82cca7c01dee0b3", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/a0/ca/b4e3c4ea2c76e462b7e657b2b1c2", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", - "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/bb/99/cf7307a78b9635cb0bf93e1647c9", + "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/8b/c6/3fbabe88f18df228f6f2984201a5", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/eb/94/449eceecc6b0a6c7e4a548ea3607", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/0d/ae/d2df1bf3c2157b4b5302df54622f", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/cb/10/5d94df639e3e0cb405711e1b907f", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/7f/52/3d0b7e1955af24a1158a36c9a272", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a3/b6/8987b9fc6a7cb0f61364f567c901", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/ff/3f/f1c11e1f22454ceceb7b4d277a2a", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/bd/45/ffb2d9d9ce9578ae11de9bb5123d", - "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/8f/e6/675e5e41b5aea12d34b152f0f705", + "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/e1/cc/13a4ba409b7d6f113f703be1aa8a", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/9c/e3/834faf6869f5cd175edd4a0244b9", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", - "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/33/82/be19758f3563ba6617db4736de74", + "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/57/bb/33e8bd738c3ee97122186471be75", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/c9/6b/dadd4329de69d0b7bfe1aa5f31d6", @@ -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/51/d5/b58e2da2a9dd4dba968acbbaf2a4", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/71/74/ce3f41e66235e907aedbf609b3bf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/92/6b/ecebeada2b7401f9401877863a21", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/07/18/c56004638b1ebd5234974ffe3644", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b8/2a/6726ae2d5f56bdc9b663adda0e2e", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/0c/8604fbcf8979a024d16cf1ad3f38", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/00/75/f1d62f08e8b5f523270819bd1ad0", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b8/92/a15a90fe81687a2ef49ef5275617", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/f9/0ef6fa2ef75f77d3ebe357a060da", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/f6/eb48fccf54236e4016181b37fee6", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/bc/dd92fe8e0f5ec65356e973228d4d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/19/d1/e83d59e2deb988d6dc2d4032e202" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/94/36/dd75b60256df2a060729decce0f7", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c3/38/cce780c715451caaa5f6cf4516ae", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/35/ba/774fac4f532434c20d90debb24be", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/86/a2/b026c303f1da34dcdaeceb9bad24", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/78/a3/52f50bd0b158c8765ebfbd95fb7b", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/70/43/0ab510f023e0a571e481b1194a0a", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e7/d0/2a07066094977585b7adc266ef86", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a9/b4/e4d542e791e43e00d886c5a2cd72", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8c/9a/9374664002b627493acb68a58d0f", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/31/a0/2e3391873c37f223bcedb191d0f2", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/57/f3a7e9f9443f193aba02bba7c463", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/36/ba/6323c8132892fbc06ba5a0aa202c" } \ No newline at end of file diff --git a/docs/ba_module.md b/docs/ba_module.md index c247911a..27ef89fe 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-17 for Ballistica version 1.5.22 build 20144

    +

    last updated on 2020-07-19 for Ballistica version 1.5.23 build 20148

    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!


    diff --git a/tools/efrotools/ios.py b/tools/efrotools/ios.py index 9c4b1b8c..4115bdb3 100644 --- a/tools/efrotools/ios.py +++ b/tools/efrotools/ios.py @@ -140,7 +140,7 @@ def _add_build_to_xcarchive(workdir: pathlib.Path, xcprojpath: pathlib.Path, MODES['debug']['configuration'], '-archivePath', str(archivepathbase) ] - subprocess.run(args, check=True, capture_output=True) + subprocess.run(args, check=True, capture_output=False) # Now copy our just-built app into the archive. print('Copying build to archive...') From df048bdeecbeea6b0e8d58a89984f9f0acc3d2aa Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Mon, 20 Jul 2020 18:47:21 +0530 Subject: [PATCH 163/417] BombSquad now has Exclusive Emojis --- .../python/bastd/ui/onscreenkeyboard.py | 74 ++++++++++++++++++- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index d32a9ae5..5494e2ec 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -86,9 +86,12 @@ class OnScreenKeyboardWindow(ba.Window): always_show_carat=True) self._shift_button = None + self._double_press_shift = False self._num_mode_button = None + self._emoji_button = None self._char_keys: List[ba.Widget] = [] self._mode = 'normal' + self._last_mode = 'normal' v = self._height - 180 key_width = 46 @@ -176,6 +179,19 @@ class OnScreenKeyboardWindow(ba.Window): color=key_color_dark, label='', ) + if self._emoji_button is None: + self._emoji_button = ba.buttonwidget( + parent=self._root_widget, + position=(56, v - 8), + size=(key_width, key_height + 5), + autoselect=True, + enable_sound=False, + textcolor=key_textcolor, + color=key_color_dark, + label=ba.charstr(ba.SpecialChar.LOGO_FLAT), + extra_touch_border_scale=0.3, + button_type='square', + ) btn1 = self._num_mode_button btn2 = ba.buttonwidget(parent=self._root_widget, position=(210, v - 12), @@ -188,10 +204,12 @@ class OnScreenKeyboardWindow(ba.Window): label=ba.Lstr(resource='spaceKeyText'), on_activate_call=ba.Call( self._type_char, ' ')) + btn3 = self._emoji_button ba.widget(edit=btn1, right_widget=btn2) ba.widget(edit=btn2, left_widget=btn1, right_widget=self._done_button) + ba.widget(edit=btn3, left_widget=btn1) ba.widget(edit=self._done_button, left_widget=btn2) ba.containerwidget(edit=self._root_widget, @@ -201,7 +219,7 @@ class OnScreenKeyboardWindow(ba.Window): def _refresh(self) -> None: chars: Optional[List[str]] = None - if self._mode in ['normal', 'caps']: + if self._mode in ['normal', 'caps', 'emoji']: chars = [ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', @@ -217,6 +235,40 @@ class OnScreenKeyboardWindow(ba.Window): ba.buttonwidget(edit=self._num_mode_button, label='123#&*', on_activate_call=self._num_mode) + if self._mode == 'emoji': + chars = [ + ba.charstr( + ba.SpecialChar.LOGO_FLAT), ba.charstr( + ba.SpecialChar.UP_ARROW), ba.charstr( + ba.SpecialChar.DOWN_ARROW), ba.charstr( + ba.SpecialChar.LEFT_ARROW), ba.charstr( + ba.SpecialChar.RIGHT_ARROW), ba.charstr( + ba.SpecialChar.DELETE), ba.charstr( + ba.SpecialChar.BACK), ba.charstr( + ba.SpecialChar.TICKET), ba.charstr( + ba.SpecialChar.PARTY_ICON), ba.charstr( + ba.SpecialChar.LOCAL_ACCOUNT), ba.charstr( + ba.SpecialChar.FEDORA), ba.charstr( + ba.SpecialChar.HAL), ba.charstr( + ba.SpecialChar.CROWN), ba.charstr( + ba.SpecialChar.YIN_YANG), ba.charstr( + ba.SpecialChar.EYE_BALL), ba.charstr( + ba.SpecialChar.SKULL), ba.charstr( + ba.SpecialChar.HEART), ba.charstr( + ba.SpecialChar.DRAGON), ba.charstr( + ba.SpecialChar.HELMET), ba.charstr( + ba.SpecialChar.MUSHROOM), ba.charstr( + ba.SpecialChar.NINJA_STAR), ba.charstr( + ba.SpecialChar.VIKING_HELMET), ba.charstr( + ba.SpecialChar.MOON), ba.charstr( + ba.SpecialChar.SPIDER), ba.charstr( + ba.SpecialChar.FIREBALL), ba.charstr( + ba.SpecialChar.MIKIROG)] + ba.buttonwidget(edit=self._emoji_button, + color=self._key_color_lit + if self._mode == 'emoji' else self._key_color_dark, + label=ba.charstr(ba.SpecialChar.LOGO_FLAT), + on_activate_call=self._emoji_mode) elif self._mode == 'num': chars = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '/', @@ -251,12 +303,25 @@ class OnScreenKeyboardWindow(ba.Window): self._mode = 'num' self._refresh() + def _emoji_mode(self) -> None: + ba.playsound(self._click_sound) + if self._mode in ['normal', 'caps', 'num']: + self._last_mode = self._mode + self._mode = 'emoji' + elif self._mode == 'emoji': + self._mode = self._last_mode + self._refresh() + def _shift(self) -> None: ba.playsound(self._click_sound) if self._mode == 'normal': self._mode = 'caps' + self._double_press_shift = False elif self._mode == 'caps': - self._mode = 'normal' + if not self._double_press_shift: + self._double_press_shift = True + else: + self._mode = 'normal' self._refresh() def _del(self) -> None: @@ -273,8 +338,9 @@ class OnScreenKeyboardWindow(ba.Window): txt = cast(str, ba.textwidget(query=self._text_field)) txt += char ba.textwidget(edit=self._text_field, text=txt) - # if we were caps, go back - if self._mode == 'caps': + # if we were caps, + # go back only if not Shift is pressed twice + if self._mode == 'caps' and self._double_press_shift != True: self._mode = 'normal' self._refresh() From 910243cefe67e3085feaa2a8441bc60ac9a348db Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Mon, 20 Jul 2020 18:48:46 +0530 Subject: [PATCH 164/417] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc32dac..e134ce09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. - Fixed a bug with hardware keyboards emitting extra characters in the in-game console (~ or F2) - Added support for 'plugin' mods and user controls to configure them in settings->advanced->plugins. +- BombSquad now has its own Exclusive Emojis in the Internal Game Keyboard. +- Added continuos CAPITAL letters typing feature in the Internal Game Keyboard. ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). From f5b179395f59f824f8732a8e69d07c58a3b683f8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 21 Jul 2020 03:05:51 -0700 Subject: [PATCH 165/417] UI code cleanup --- .efrocachemap | 24 ++--- .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 8 ++ assets/src/ba_data/python/_ba.py | 48 +++++++--- .../python/bastd/ui/account/settings.py | 18 ++-- .../ba_data/python/bastd/ui/account/unlink.py | 2 + .../ba_data/python/bastd/ui/coop/browser.py | 19 ++-- assets/src/ba_data/python/bastd/ui/gather.py | 17 ++-- assets/src/ba_data/python/bastd/ui/kiosk.py | 4 +- .../src/ba_data/python/bastd/ui/mainmenu.py | 2 +- assets/src/ba_data/python/bastd/ui/party.py | 4 +- .../python/bastd/ui/playlist/addgame.py | 4 +- .../bastd/ui/playlist/customizebrowser.py | 4 +- .../ba_data/python/bastd/ui/playlist/edit.py | 4 +- .../python/bastd/ui/playlist/editgame.py | 27 +++--- assets/src/ba_data/python/bastd/ui/popup.py | 8 +- .../python/bastd/ui/profile/browser.py | 4 +- .../python/bastd/ui/settings/advanced.py | 16 ++-- .../bastd/ui/settings/gamepadadvanced.py | 18 ++-- .../python/bastd/ui/settings/plugins.py | 34 ++++--- .../python/bastd/ui/settings/testing.py | 4 +- .../python/bastd/ui/settings/touchscreen.py | 89 +++++++++---------- .../python/bastd/ui/soundtrack/browser.py | 2 +- .../python/bastd/ui/soundtrack/edit.py | 27 +++--- .../python/bastd/ui/soundtrack/macmusicapp.py | 28 +++--- .../ba_data/python/bastd/ui/store/browser.py | 29 +++--- assets/src/ba_data/python/bastd/ui/watch.py | 7 +- docs/ba_module.md | 27 ++++-- 28 files changed, 267 insertions(+), 212 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index f8b3ca81..b38e80e7 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/94/36/dd75b60256df2a060729decce0f7", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c3/38/cce780c715451caaa5f6cf4516ae", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/35/ba/774fac4f532434c20d90debb24be", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/86/a2/b026c303f1da34dcdaeceb9bad24", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/78/a3/52f50bd0b158c8765ebfbd95fb7b", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/70/43/0ab510f023e0a571e481b1194a0a", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e7/d0/2a07066094977585b7adc266ef86", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a9/b4/e4d542e791e43e00d886c5a2cd72", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8c/9a/9374664002b627493acb68a58d0f", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/31/a0/2e3391873c37f223bcedb191d0f2", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/57/f3a7e9f9443f193aba02bba7c463", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/36/ba/6323c8132892fbc06ba5a0aa202c" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b6/f3/a034a7393edf52eefe644e6aa642", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5d/e2/c45ee46dc39c32aa4bff0d50ef2c", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/25/3d/f3cce76ed1c66e39b6e07d199696", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cf/8b/5c09d999c0d6b160e34d69f1f710", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c7/b6/18b0280b4c99aaf48fb3bfcc4fac", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/65/dd50a2026be7df75e3d280a2efc3", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/4e/f6a184076ad4676ad6b4cf9d4d01", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/20/d9/f86cd5d9fb67183e0a2ceda0e897", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e4/da/0b43bb125048696f4514eaca1e56", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d6/46/d0e647509453bc2125ccbe7eba09", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c2/a8/fee89fe0a3d76489b5b26a2c5fac", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/70/d5/86c8bdb5cf1dd15d9b9a0c7490da" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 07924e3f..30c2303d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1451,6 +1451,7 @@ plistname plpt plst + pluglist plusbutton plvel pmats diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc32dac..5f6af66b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. - Fixed a bug with hardware keyboards emitting extra characters in the in-game console (~ or F2) - Added support for 'plugin' mods and user controls to configure them in settings->advanced->plugins. +- renamed selection_loop_to_parent to selection_loops_to_parent in widget calls. +- Added 'selection_loops_to_parent', 'border', 'margin', 'claims_left_right', and 'claims_tab' args to ba.columnwidget(). +- Column-widget now has a default 'border' of 0 (explicitly pass 2 to get the old look). +- Column-widget now has a default 'margin' of 10 (explicitly pass 0 to get the old look). +- Added 'selection_loops_to_parent', 'claims_left_right', and 'claims_tab' args to ba.scrollwidget. +- Added 'selection_loops_to_parent', 'claims_left_right', and 'claims_tab' args to ba.rowwidget. +- Added 'claims_left_right' and 'claims_tab' to ba.hscrollwidget(). +- Default widget 'show_buffer' is now 20 instead of 0 (causes scrolling to stay slightly ahead of widget selection). This can be overridden with the ba.widget() call if anything breaks. ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 45a72cb6..bbffcfcb 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -1598,7 +1598,12 @@ def columnwidget(edit: ba.Widget = None, print_list_exit_instructions: bool = None, left_border: float = None, top_border: float = None, - bottom_border: float = None) -> ba.Widget: + bottom_border: float = None, + selection_loops_to_parent: bool = None, + border: float = None, + margin: float = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget: """columnwidget(edit: ba.Widget = None, parent: ba.Widget = None, size: Sequence[float] = None, @@ -1610,7 +1615,12 @@ def columnwidget(edit: ba.Widget = None, print_list_exit_instructions: bool = None, left_border: float = None, top_border: float = None, - bottom_border: float = None) -> ba.Widget + bottom_border: float = None, + selection_loops_to_parent: bool = None, + border: float = None, + margin: float = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget Create or edit a column widget. @@ -1669,7 +1679,7 @@ def containerwidget(edit: ba.Widget = None, claims_left_right: bool = None, claims_tab: bool = None, selection_loops: bool = None, - selection_loop_to_parent: bool = None, + selection_loops_to_parent: bool = None, scale: float = None, on_outside_click_call: Callable[[], None] = None, single_depth: bool = None, @@ -1700,7 +1710,7 @@ def containerwidget(edit: ba.Widget = None, claims_left_right: bool = None, claims_tab: bool = None, selection_loops: bool = None, - selection_loop_to_parent: bool = None, + selection_loops_to_parent: bool = None, scale: float = None, on_outside_click_call: Callable[[], None] = None, single_depth: bool = None, @@ -2618,7 +2628,9 @@ def hscrollwidget(edit: ba.Widget = None, color: Sequence[float] = None, highlight: bool = None, border_opacity: float = None, - simple_culling_h: float = None) -> ba.Widget: + simple_culling_h: float = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget: """hscrollwidget(edit: ba.Widget = None, parent: ba.Widget = None, size: Sequence[float] = None, position: Sequence[float] = None, background: bool = None, selected_child: ba.Widget = None, @@ -2626,7 +2638,9 @@ def hscrollwidget(edit: ba.Widget = None, on_select_call: Callable[[], None] = None, center_small_content: bool = None, color: Sequence[float] = None, highlight: bool = None, border_opacity: float = None, - simple_culling_h: float = None) -> ba.Widget + simple_culling_h: float = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget Create or edit a horizontal scroll widget. @@ -3283,12 +3297,18 @@ def rowwidget(edit: Widget = None, position: Sequence[float] = None, background: bool = None, selected_child: Widget = None, - visible_child: Widget = None) -> Widget: - """rowwidget(edit: Widget =None, parent: Widget =None, + visible_child: Widget = None, + claims_left_right: bool = None, + claims_tab: bool = None, + selection_loops_to_parent: bool = None) -> Widget: + """rowwidget(edit: Widget = None, parent: Widget = None, size: Sequence[float] = None, position: Sequence[float] = None, background: bool = None, selected_child: Widget = None, - visible_child: Widget = None) -> Widget + visible_child: Widget = None, + claims_left_right: bool = None, + claims_tab: bool = None, + selection_loops_to_parent: bool = None) -> Widget Create or edit a row widget. @@ -3365,14 +3385,20 @@ def scrollwidget(edit: ba.Widget = None, color: Sequence[float] = None, highlight: bool = None, border_opacity: float = None, - simple_culling_v: float = None) -> ba.Widget: + simple_culling_v: float = None, + selection_loops_to_parent: bool = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget: """scrollwidget(edit: ba.Widget = None, parent: ba.Widget = None, size: Sequence[float] = None, position: Sequence[float] = None, background: bool = None, selected_child: ba.Widget = None, capture_arrows: bool = False, on_select_call: Callable = None, center_small_content: bool = None, color: Sequence[float] = None, highlight: bool = None, border_opacity: float = None, - simple_culling_v: float = None) -> ba.Widget + simple_culling_v: float = None, + selection_loops_to_parent: bool = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget Create or edit a scroll widget. diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py index 6f178d7c..3ec9adf8 100644 --- a/assets/src/ba_data/python/bastd/ui/account/settings.py +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py @@ -150,7 +150,10 @@ class AccountSettingsWindow(ba.Window): highlight=False, position=((self._width - self._scroll_width) * 0.5, self._height - 65 - self._scroll_height), - size=(self._scroll_width, self._scroll_height)) + size=(self._scroll_width, self._scroll_height), + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._subcontainer: Optional[ba.Widget] = None self._refresh() self._restore_state() @@ -322,15 +325,10 @@ class AccountSettingsWindow(ba.Window): self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), - background=False) - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=self._subcontainer, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) first_selectable = None v = self._sub_height - 10.0 diff --git a/assets/src/ba_data/python/bastd/ui/account/unlink.py b/assets/src/ba_data/python/bastd/ui/account/unlink.py index 53d52189..214d8f92 100644 --- a/assets/src/ba_data/python/bastd/ui/account/unlink.py +++ b/assets/src/ba_data/python/bastd/ui/account/unlink.py @@ -91,6 +91,8 @@ class AccountUnlinkWindow(ba.Window): size=(self._scroll_width, self._scroll_height)) ba.containerwidget(edit=self._scrollwidget, claims_left_right=True) self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0, left_border=10) our_login_id = _ba.get_public_login_id() diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index ea0ad875..840f4fc3 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -245,7 +245,10 @@ class CoopBrowserWindow(ba.Window): position=(65 + x_inset, 120) if uiscale is ba.UIScale.SMALL and app.ui.use_toolbars else (65 + x_inset, 70), size=(self._scroll_width, self._scroll_height), - simple_culling_v=10.0) + simple_culling_v=10.0, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._subcontainer: Optional[ba.Widget] = None # Take note of our account state; we'll refresh later if this changes. @@ -792,17 +795,11 @@ class CoopBrowserWindow(ba.Window): self._subcontainer = ba.containerwidget( parent=self._scrollwidget, size=(self._subcontainerwidth, self._subcontainerheight), - background=False) + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) - # So we can still select root level widgets with controllers. - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=self._subcontainer, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) if self._back_button is not None: diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 9f0bf8dd..2347e3af 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -356,7 +356,7 @@ class GatherWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 30.0 ba.textwidget( parent=cnt, @@ -378,7 +378,7 @@ class GatherWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 30 self._internet_join_text = txt = ba.textwidget( parent=cnt, @@ -479,7 +479,10 @@ class GatherWindow(ba.Window): self._scrollwidget = scrollwidget self._tab_button = tab_button self._columnwidget = ba.columnwidget( - parent=self._scrollwidget, left_border=10) + parent=self._scrollwidget, + border=2, + margin=0, + left_border=10) ba.widget(edit=self._columnwidget, up_widget=tab_button) self._width = width self._last_selected_host: Optional[Dict[str, Any]] = None @@ -540,7 +543,7 @@ class GatherWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 30 ba.textwidget(parent=cnt, position=(c_width * 0.5, v - 3), @@ -578,7 +581,7 @@ class GatherWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 30 ba.textwidget(parent=cnt, position=(c_width * 0.5, v), @@ -631,7 +634,7 @@ class GatherWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 80 ba.textwidget(parent=cnt, @@ -684,7 +687,7 @@ class GatherWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 30 ba.textwidget(parent=cnt, position=(c_width * 0.5, v), diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index a0a95ddb..1b6625aa 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -36,12 +36,12 @@ class KioskWindow(ba.Window): def __init__(self, transition: str = 'in_right'): # pylint: disable=too-many-locals, too-many-statements - from bastd.ui import confirm + from bastd.ui.confirm import QuitWindow self._width = 720.0 self._height = 340.0 def _do_cancel() -> None: - confirm.QuitWindow(swish=True, back=True) + QuitWindow(swish=True, back=True) super().__init__( root_widget=ba.containerwidget(size=(self._width, self._height), diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index f021f9da..99a36922 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -146,7 +146,7 @@ class MainMenuWindow(ba.Window): # Don't refresh for the first few seconds the game is up so we don't # interrupt the transition in. ba.app.main_menu_window_refresh_check_count += 1 - if ba.app.main_menu_window_refresh_check_count < 3: + if ba.app.main_menu_window_refresh_check_count < 4: return store_char_tex = self._get_store_char_tex() diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py index 6c46bf5e..52fcc10a 100644 --- a/assets/src/ba_data/python/bastd/ui/party.py +++ b/assets/src/ba_data/python/bastd/ui/party.py @@ -119,7 +119,9 @@ class PartyWindow(ba.Window): self._height - 200), position=(30, 80), color=(0.4, 0.6, 0.3)) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) ba.widget(edit=self._menu_button, down_widget=self._columnwidget) self._muted_text = ba.textwidget( diff --git a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py index b1bc9990..f93779ef 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py @@ -143,7 +143,9 @@ class PlaylistAddGameWindow(ba.Window): if self._column is not None: self._column.delete() - self._column = ba.columnwidget(parent=self._scrollwidget) + self._column = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) gametypes = [ gt for gt in get_game_types() if gt.supports_session_type( diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py index e0bbb9a7..640f73a6 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -228,7 +228,9 @@ class PlaylistCustomizeBrowserWindow(ba.Window): self._scroll_height + 10), highlight=False) ba.widget(edit=back_button, right_widget=scrollwidget) - self._columnwidget = ba.columnwidget(parent=scrollwidget) + self._columnwidget = ba.columnwidget(parent=scrollwidget, + border=2, + margin=0) h = 145 diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index f4569fd2..3b5dda02 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -214,7 +214,9 @@ class PlaylistEditWindow(ba.Window): ba.widget(edit=scrollwidget, left_widget=add_game_button, right_widget=scrollwidget) - self._columnwidget = ba.columnwidget(parent=scrollwidget) + self._columnwidget = ba.columnwidget(parent=scrollwidget, + border=2, + margin=0) ba.widget(edit=self._columnwidget, up_widget=self._text_field) for button in [add_game_button, edit_game_button, remove_game_button]: diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index 750cc8f1..78a67007 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -177,22 +177,17 @@ class PlaylistEditGameWindow(ba.Window): position=(44 + x_inset, 35 + y_extra), size=(scroll_width, height - 116), - highlight=False) - self._subcontainer = cnt = ba.containerwidget( - parent=self._scrollwidget, - size=(scroll_width, scroll_height), - background=False) - - # So selection loops through everything and doesn't get stuck in - # sub-containers. - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=cnt, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + highlight=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) + self._subcontainer = ba.containerwidget(parent=self._scrollwidget, + size=(scroll_width, + scroll_height), + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) v = scroll_height - 5 h = -40 diff --git a/assets/src/ba_data/python/bastd/ui/popup.py b/assets/src/ba_data/python/bastd/ui/popup.py index 77dc2e11..8386b821 100644 --- a/assets/src/ba_data/python/bastd/ui/popup.py +++ b/assets/src/ba_data/python/bastd/ui/popup.py @@ -199,14 +199,18 @@ class PopupMenuWindow(PopupWindow): color=(0.35, 0.55, 0.15), size=(self._width - 40, self._height - 40)) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) else: self._offset_widget = ba.containerwidget(parent=self.root_widget, position=(30, 15), size=(self._width - 40, self._height), background=False) - self._columnwidget = ba.columnwidget(parent=self._offset_widget) + self._columnwidget = ba.columnwidget(parent=self._offset_widget, + border=2, + margin=0) for index, choice in enumerate(choices): if len(choices_display_fin) == len(choices): choice_display_name = choices_display_fin[index] diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py index dd434ae0..4feefaf1 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py @@ -177,7 +177,9 @@ class ProfileBrowserWindow(ba.Window): left_widget=self._new_button) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) - self._columnwidget = ba.columnwidget(parent=self._scrollwidget) + self._columnwidget = ba.columnwidget(parent=self._scrollwidget, + border=2, + margin=0) v -= 255 self._profiles: Optional[Dict[str, Dict[str, Any]]] = None self._selected_profile = selected_profile diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index 963aea01..6afca8f3 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -146,14 +146,14 @@ class AdvancedSettingsWindow(ba.Window): simple_culling_v=20.0, highlight=False, size=(self._scroll_width, - self._scroll_height)) - ba.containerwidget(edit=self._scrollwidget, - selection_loop_to_parent=True) + self._scroll_height), + selection_loops_to_parent=True) + ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) self._rebuild() @@ -693,10 +693,10 @@ class AdvancedSettingsWindow(ba.Window): sel = self._language_inform_checkbox else: sel = None - if sel is not None: - ba.containerwidget(edit=self._subcontainer, - selected_child=sel, - visible_child=sel) + if sel is not None: + ba.containerwidget(edit=self._subcontainer, + selected_child=sel, + visible_child=sel) except Exception: ba.print_exception(f'Error restoring state for {self.__class__}') diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py index ad5ba704..35f3e336 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py @@ -89,19 +89,17 @@ class GamepadAdvancedSettingsWindow(ba.Window): parent=self._root_widget, position=((self._width - self._scroll_width) * 0.5, self._height - 65 - self._scroll_height), - size=(self._scroll_width, self._scroll_height)) + size=(self._scroll_width, self._scroll_height), + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), - background=False) - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=self._subcontainer, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) ba.containerwidget(edit=self._root_widget, selected_child=self._scrollwidget) diff --git a/assets/src/ba_data/python/bastd/ui/settings/plugins.py b/assets/src/ba_data/python/bastd/ui/settings/plugins.py index b918a56b..8a953054 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/plugins.py +++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py @@ -105,23 +105,35 @@ class PluginSettingsWindow(ba.Window): simple_culling_v=20.0, highlight=False, size=(self._scroll_width, - self._scroll_height)) - ba.containerwidget(edit=self._scrollwidget, - selection_loop_to_parent=True) - self._subcontainer = ba.containerwidget(parent=self._scrollwidget, - size=(self._sub_width, - self._sub_height), - background=False, - selection_loop_to_parent=True) + self._scroll_height), + selection_loops_to_parent=True) + ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + self._subcontainer = ba.columnwidget(parent=self._scrollwidget, + selection_loops_to_parent=True) + + pluglist = [f'Test {i}' for i in range(10)] + for i, plug in enumerate(pluglist): + check = ba.checkboxwidget(parent=self._subcontainer, + text=plug, + size=(self._scroll_width - 40, 50)) + + # Make sure we scroll all the way to the end when using + # keyboard/button nav. + ba.widget(edit=check, show_buffer_top=40, show_buffer_bottom=40) + + # Keep last from looping to back button when down is pressed. + if i == len(pluglist) - 1: + ba.widget(edit=check, down_widget=check) + ba.containerwidget(edit=self._root_widget, + selected_child=self._scrollwidget) - ba.screenmessage('Work in progress...') self._restore_state() def _save_state(self) -> None: - print('would save state') + pass def _restore_state(self) -> None: - print('would restore state') + pass def _do_back(self) -> None: # pylint: disable=cyclic-import diff --git a/assets/src/ba_data/python/bastd/ui/settings/testing.py b/assets/src/ba_data/python/bastd/ui/settings/testing.py index 9619c000..58c9427b 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/testing.py +++ b/assets/src/ba_data/python/bastd/ui/settings/testing.py @@ -133,7 +133,6 @@ class TestingWindow(ba.Window): self._on_minus_press, entry['name'])) if i == 0: ba.widget(edit=btn, up_widget=self._back_button) - ba.widget(edit=btn, show_buffer_top=20, show_buffer_bottom=20) entry['widget'] = ba.textwidget(parent=self._subcontainer, position=(h + 100, v), size=(0, 0), @@ -155,7 +154,7 @@ class TestingWindow(ba.Window): ba.widget(edit=btn, up_widget=self._back_button) v -= self._spacing v -= 35 - b_reset = ba.buttonwidget( + ba.buttonwidget( parent=self._subcontainer, autoselect=True, size=(200, 50), @@ -163,7 +162,6 @@ class TestingWindow(ba.Window): label=ba.Lstr(resource='settingsWindowAdvanced.resetText'), right_widget=btn, on_activate_call=self._on_reset_press) - ba.widget(edit=b_reset, show_buffer_top=20, show_buffer_bottom=20) def _get_entry(self, name: str) -> Dict[str, Any]: for entry in self._entries: diff --git a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py index be30d230..311e5be2 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py +++ b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py @@ -84,26 +84,24 @@ class TouchscreenSettingsWindow(ba.Window): parent=self._root_widget, position=((self._width - self._scroll_width) * 0.5, self._height - 65 - self._scroll_height), - size=(self._scroll_width, self._scroll_height)) + size=(self._scroll_width, self._scroll_height), + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._subcontainer = ba.containerwidget(parent=self._scrollwidget, size=(self._sub_width, self._sub_height), - background=False) - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=self._subcontainer, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._build_gui() def _build_gui(self) -> None: - from bastd.ui import config as cfgui - from bastd.ui import radiogroup - # clear anything already there + from bastd.ui.config import ConfigNumberEdit, ConfigCheckBox + from bastd.ui.radiogroup import make_radio_group + + # Clear anything already there. children = self._subcontainer.get_children() for child in children: child.delete() @@ -145,20 +143,19 @@ class TouchscreenSettingsWindow(ba.Window): textcolor=clr2, value=False, scale=0.9) - radiogroup.make_radio_group((cb1, cb2), ('joystick', 'swipe'), cur_val, - self._movement_changed) + make_radio_group((cb1, cb2), ('joystick', 'swipe'), cur_val, + self._movement_changed) v -= 50 - cfgui.ConfigNumberEdit( - parent=self._subcontainer, - position=(h, v), - xoffset=65, - configkey='Touch Controls Scale Movement', - displayname=ba.Lstr(resource=self._r + - '.movementControlScaleText'), - changesound=False, - minval=0.1, - maxval=4.0, - increment=0.1) + ConfigNumberEdit(parent=self._subcontainer, + position=(h, v), + xoffset=65, + configkey='Touch Controls Scale Movement', + displayname=ba.Lstr(resource=self._r + + '.movementControlScaleText'), + changesound=False, + minval=0.1, + maxval=4.0, + increment=0.1) v -= 50 cur_val = ba.app.config.get('Touch Action Control Type', 'buttons') ba.textwidget(parent=self._subcontainer, @@ -183,28 +180,28 @@ class TouchscreenSettingsWindow(ba.Window): maxwidth=100, textcolor=clr2, scale=0.9) - radiogroup.make_radio_group((cb1, cb2), ('buttons', 'swipe'), cur_val, - self._actions_changed) + make_radio_group((cb1, cb2), ('buttons', 'swipe'), cur_val, + self._actions_changed) v -= 50 - cfgui.ConfigNumberEdit(parent=self._subcontainer, - position=(h, v), - xoffset=65, - configkey='Touch Controls Scale Actions', - displayname=ba.Lstr(resource=self._r + - '.actionControlScaleText'), - changesound=False, - minval=0.1, - maxval=4.0, - increment=0.1) + ConfigNumberEdit(parent=self._subcontainer, + position=(h, v), + xoffset=65, + configkey='Touch Controls Scale Actions', + displayname=ba.Lstr(resource=self._r + + '.actionControlScaleText'), + changesound=False, + minval=0.1, + maxval=4.0, + increment=0.1) v -= 50 - cfgui.ConfigCheckBox(parent=self._subcontainer, - position=(h, v), - size=(400, 30), - maxwidth=400, - configkey='Touch Controls Swipe Hidden', - displayname=ba.Lstr(resource=self._r + - '.swipeControlsHiddenText')) + ConfigCheckBox(parent=self._subcontainer, + position=(h, v), + size=(400, 30), + maxwidth=400, + configkey='Touch Controls Swipe Hidden', + displayname=ba.Lstr(resource=self._r + + '.swipeControlsHiddenText')) v -= 65 ba.buttonwidget(parent=self._subcontainer, diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py index 38fe0817..3db1035e 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py @@ -211,7 +211,7 @@ class SoundtrackBrowserWindow(ba.Window): left_widget=self._new_button, right_widget=_ba.get_special_widget('party_button') if ba.app.ui.use_toolbars else self._scrollwidget) - self._col = ba.columnwidget(parent=scrollwidget) + self._col = ba.columnwidget(parent=scrollwidget, border=2, margin=0) self._soundtracks: Optional[Dict[str, Any]] = None self._selected_soundtrack: Optional[str] = None diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py index be5d754a..c31d9e66 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py @@ -155,18 +155,15 @@ class SoundtrackEditWindow(ba.Window): highlight=False, position=(40 + x_inset, v - (scroll_height + 10)), size=(self._width - (80 + 2 * x_inset), scroll_height), - simple_culling_v=10) + simple_culling_v=10, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) ba.widget(edit=self._text_field, down_widget=self._scrollwidget) - self._col = ba.columnwidget(parent=scrollwidget) - - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=self._col, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + self._col = ba.columnwidget(parent=scrollwidget, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._song_type_buttons: Dict[str, ba.Widget] = {} self._refresh() @@ -210,11 +207,11 @@ class SoundtrackEditWindow(ba.Window): prev_test_button: Optional[ba.Widget] = None for index, song_type in enumerate(types): - row = ba.rowwidget(parent=self._col, size=(self._width - 40, 40)) - ba.containerwidget(edit=row, + row = ba.rowwidget(parent=self._col, + size=(self._width - 40, 40), claims_left_right=True, claims_tab=True, - selection_loop_to_parent=True) + selection_loops_to_parent=True) type_name = type_names_translated.get(song_type, song_type) ba.textwidget(parent=row, size=(230, 25), @@ -231,7 +228,7 @@ class SoundtrackEditWindow(ba.Window): entry = None if entry is not None: - # make sure they don't muck with this after it gets to us + # Make sure they don't muck with this after it gets to us. entry = copy.deepcopy(entry) icon_type = self._get_entry_button_display_icon_type(entry) diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py b/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py index 8457e197..e26f274e 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py @@ -52,7 +52,8 @@ class MacMusicAppPlaylistSelectWindow(ba.Window): position=(35, self._height - 65), size=(130, 50), label=ba.Lstr(resource='cancelText'), - on_activate_call=self._back) + on_activate_call=self._back, + autoselect=True) ba.containerwidget(edit=self._root_widget, cancel_button=btn) ba.textwidget(parent=self._root_widget, position=(20, self._height - 54), @@ -64,19 +65,13 @@ class MacMusicAppPlaylistSelectWindow(ba.Window): maxwidth=200) self._scrollwidget = ba.scrollwidget(parent=self._root_widget, position=(40, v - 340), - size=(self._width - 80, 400)) - self._column = ba.columnwidget(parent=self._scrollwidget) - - # So selection loops through everything and doesn't get stuck - # in sub-containers. - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - ba.containerwidget(edit=self._column, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + size=(self._width - 80, 400), + claims_tab=True, + selection_loops_to_parent=True) + ba.widget(edit=self._scrollwidget, right_widget=self._scrollwidget) + self._column = ba.columnwidget(parent=self._scrollwidget, + claims_tab=True, + selection_loops_to_parent=True) ba.textwidget(parent=self._column, size=(self._width - 80, 22), @@ -93,7 +88,7 @@ class MacMusicAppPlaylistSelectWindow(ba.Window): if self._column: for widget in self._column.get_children(): widget.delete() - for playlist in playlists: + for i, playlist in enumerate(playlists): txt = ba.textwidget(parent=self._column, size=(self._width - 80, 30), text=playlist, @@ -103,10 +98,13 @@ class MacMusicAppPlaylistSelectWindow(ba.Window): on_activate_call=ba.Call( self._sel, playlist), click_activate=True) + ba.widget(edit=txt, show_buffer_top=40, show_buffer_bottom=40) if playlist == self._existing_playlist: ba.columnwidget(edit=self._column, selected_child=txt, visible_child=txt) + if i == len(playlists) - 1: + ba.widget(edit=txt, down_widget=txt) def _sel(self, selection: str) -> None: if self._root_widget: diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 97090b07..627308e4 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -353,19 +353,16 @@ class StoreBrowserWindow(ba.Window): highlight=False, position=((self._width - self._scroll_width) * 0.5, self._height - self._scroll_height - 79 - 48), - size=(self._scroll_width, self._scroll_height)) + size=(self._scroll_width, self._scroll_height), + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) # NOTE: this stuff is modified by the _Store class. # Should maybe clean that up. self.button_infos = {} self.update_buttons_timer = None - # So we can still select root level widgets with controllers. - ba.containerwidget(edit=self._scrollwidget, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) - # Show status over top. if self._status_textwidget: self._status_textwidget.delete() @@ -781,11 +778,10 @@ class StoreBrowserWindow(ba.Window): cnt2 = ba.containerwidget(parent=scrollwidget, scale=1.0, size=(self._width, self._height), - background=False) - ba.containerwidget(edit=cnt2, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) v = self._height - 20 if self._tab == 'characters': @@ -976,11 +972,10 @@ class StoreBrowserWindow(ba.Window): scale=1.0, size=(self._scroll_width, self._scroll_height * 0.95), - background=False) - ba.containerwidget(edit=cnt, - claims_left_right=True, - claims_tab=True, - selection_loop_to_parent=True) + background=False, + claims_left_right=True, + claims_tab=True, + selection_loops_to_parent=True) self._status_textwidget = ba.textwidget( parent=cnt, position=(self._scroll_width * 0.5, diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py index 3924ef7e..c99884d8 100644 --- a/assets/src/ba_data/python/bastd/ui/watch.py +++ b/assets/src/ba_data/python/bastd/ui/watch.py @@ -188,7 +188,7 @@ class WatchWindow(ba.Window): (self._scroll_height - c_height) * 0.5), size=(c_width, c_height), background=False, - selection_loop_to_parent=True) + selection_loops_to_parent=True) v = c_height - 30 ba.textwidget(parent=cnt, @@ -265,7 +265,10 @@ class WatchWindow(ba.Window): position=(smlh, v), size=(sub_scroll_width, sub_scroll_height)) ba.containerwidget(edit=cnt, selected_child=scrlw) - self._columnwidget = ba.columnwidget(parent=scrlw, left_border=10) + self._columnwidget = ba.columnwidget(parent=scrlw, + left_border=10, + border=2, + margin=0) ba.widget(edit=scrlw, autoselect=True, diff --git a/docs/ba_module.md b/docs/ba_module.md index 27ef89fe..29e8a007 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-19 for Ballistica version 1.5.23 build 20148

    +

    last updated on 2020-07-21 for Ballistica version 1.5.23 build 20149

    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!


    @@ -6071,7 +6071,12 @@ are applied to the Widget.

    print_list_exit_instructions: bool = None, left_border: float = None, top_border: float = None, - bottom_border: float = None) -> ba.Widget

    + bottom_border: float = None, + selection_loops_to_parent: bool = None, + border: float = None, + margin: float = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget

    Create or edit a column widget.

    @@ -6097,7 +6102,7 @@ are applied to the Widget.

    claims_left_right: bool = None, claims_tab: bool = None, selection_loops: bool = None, - selection_loop_to_parent: bool = None, + selection_loops_to_parent: bool = None, scale: float = None, on_outside_click_call: Callable[[], None] = None, single_depth: bool = None, @@ -6337,7 +6342,9 @@ in the background if necessary.

    on_select_call: Callable[[], None] = None, center_small_content: bool = None, color: Sequence[float] = None, highlight: bool = None, border_opacity: float = None, - simple_culling_h: float = None) -> ba.Widget

    + simple_culling_h: float = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget

    Create or edit a horizontal scroll widget.

    @@ -6552,11 +6559,14 @@ app running.


    ba.rowwidget()

    -

    rowwidget(edit: Widget =None, parent: Widget =None, +

    rowwidget(edit: Widget = None, parent: Widget = None, size: Sequence[float] = None, position: Sequence[float] = None, background: bool = None, selected_child: Widget = None, - visible_child: Widget = None) -> Widget

    + visible_child: Widget = None, + claims_left_right: bool = None, + claims_tab: bool = None, + selection_loops_to_parent: bool = None) -> Widget

    Create or edit a row widget.

    @@ -6607,7 +6617,10 @@ Currently the 'clients' option only works for transient messages.

    capture_arrows: bool = False, on_select_call: Callable = None, center_small_content: bool = None, color: Sequence[float] = None, highlight: bool = None, border_opacity: float = None, - simple_culling_v: float = None) -> ba.Widget

    + simple_culling_v: float = None, + selection_loops_to_parent: bool = None, + claims_left_right: bool = None, + claims_tab: bool = None) -> ba.Widget

    Create or edit a scroll widget.

    From 919d8501cad5489c3cfe468bf3ee1dd9a90f0d83 Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Tue, 21 Jul 2020 17:45:21 +0530 Subject: [PATCH 166/417] Added Classic Emojis --- .../python/bastd/ui/onscreenkeyboard.py | 106 +++++++++++------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 5494e2ec..9164c492 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -26,6 +26,8 @@ from typing import TYPE_CHECKING, cast import _ba import ba +from ba import charstr +from ba import SpecialChar as SpCh if TYPE_CHECKING: from typing import List, Tuple, Optional @@ -128,7 +130,7 @@ class OnScreenKeyboardWindow(ba.Window): autoselect=True, textcolor=key_textcolor, color=key_color_dark, - label=ba.charstr(ba.SpecialChar.SHIFT), + label=charstr(SpCh.SHIFT), enable_sound=False, extra_touch_border_scale=0.3, button_type='square', @@ -160,7 +162,7 @@ class OnScreenKeyboardWindow(ba.Window): repeat=True, textcolor=key_textcolor, color=key_color_dark, - label=ba.charstr(ba.SpecialChar.DELETE), + label=charstr(SpCh.DELETE), button_type='square', on_activate_call=self._del) v -= (key_height + 9) @@ -188,7 +190,7 @@ class OnScreenKeyboardWindow(ba.Window): enable_sound=False, textcolor=key_textcolor, color=key_color_dark, - label=ba.charstr(ba.SpecialChar.LOGO_FLAT), + label=charstr(SpCh.LOGO_FLAT), extra_touch_border_scale=0.3, button_type='square', ) @@ -205,7 +207,7 @@ class OnScreenKeyboardWindow(ba.Window): on_activate_call=ba.Call( self._type_char, ' ')) btn3 = self._emoji_button - ba.widget(edit=btn1, right_widget=btn2) + ba.widget(edit=btn1, right_widget=btn2, left_widget=btn3) ba.widget(edit=btn2, left_widget=btn1, right_widget=self._done_button) @@ -219,7 +221,7 @@ class OnScreenKeyboardWindow(ba.Window): def _refresh(self) -> None: chars: Optional[List[str]] = None - if self._mode in ['normal', 'caps', 'emoji']: + if self._mode in ['normal', 'caps']: chars = [ 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', @@ -230,44 +232,14 @@ class OnScreenKeyboardWindow(ba.Window): ba.buttonwidget(edit=self._shift_button, color=self._key_color_lit if self._mode == 'caps' else self._key_color_dark, - label=ba.charstr(ba.SpecialChar.SHIFT), + label=charstr(SpCh.SHIFT), on_activate_call=self._shift) ba.buttonwidget(edit=self._num_mode_button, label='123#&*', on_activate_call=self._num_mode) - if self._mode == 'emoji': - chars = [ - ba.charstr( - ba.SpecialChar.LOGO_FLAT), ba.charstr( - ba.SpecialChar.UP_ARROW), ba.charstr( - ba.SpecialChar.DOWN_ARROW), ba.charstr( - ba.SpecialChar.LEFT_ARROW), ba.charstr( - ba.SpecialChar.RIGHT_ARROW), ba.charstr( - ba.SpecialChar.DELETE), ba.charstr( - ba.SpecialChar.BACK), ba.charstr( - ba.SpecialChar.TICKET), ba.charstr( - ba.SpecialChar.PARTY_ICON), ba.charstr( - ba.SpecialChar.LOCAL_ACCOUNT), ba.charstr( - ba.SpecialChar.FEDORA), ba.charstr( - ba.SpecialChar.HAL), ba.charstr( - ba.SpecialChar.CROWN), ba.charstr( - ba.SpecialChar.YIN_YANG), ba.charstr( - ba.SpecialChar.EYE_BALL), ba.charstr( - ba.SpecialChar.SKULL), ba.charstr( - ba.SpecialChar.HEART), ba.charstr( - ba.SpecialChar.DRAGON), ba.charstr( - ba.SpecialChar.HELMET), ba.charstr( - ba.SpecialChar.MUSHROOM), ba.charstr( - ba.SpecialChar.NINJA_STAR), ba.charstr( - ba.SpecialChar.VIKING_HELMET), ba.charstr( - ba.SpecialChar.MOON), ba.charstr( - ba.SpecialChar.SPIDER), ba.charstr( - ba.SpecialChar.FIREBALL), ba.charstr( - ba.SpecialChar.MIKIROG)] ba.buttonwidget(edit=self._emoji_button, - color=self._key_color_lit - if self._mode == 'emoji' else self._key_color_dark, - label=ba.charstr(ba.SpecialChar.LOGO_FLAT), + color=self._key_color_dark, + label=charstr(SpCh.LOGO_FLAT), on_activate_call=self._emoji_mode) elif self._mode == 'num': chars = [ @@ -282,6 +254,54 @@ class OnScreenKeyboardWindow(ba.Window): ba.buttonwidget(edit=self._num_mode_button, label='abc', on_activate_call=self._abc_mode) + ba.buttonwidget(edit=self._emoji_button, + color=self._key_color_dark, + label=charstr(SpCh.LOGO_FLAT), + on_activate_call=self._emoji_mode) + + elif self._mode in ['emoji', 'emoji2']: + chars = [ + '🙂', '😄', '😆', '😅', '😂', '☺', '😀', '😉', '😇', 'ðŸ˜', '😘', '😎', + 'ðŸ˜', '😛', '😜', 'ðŸ˜', 'ðŸ˜', '😑', '😢', '😵', '😬', '😌', '😔', '😡', + '😴', '😷' + ] + if self._mode == 'emoji2': + chars = [ + charstr(SpCh.LOGO_FLAT), + charstr(SpCh.UP_ARROW), + charstr(SpCh.DOWN_ARROW), + charstr(SpCh.LEFT_ARROW), + charstr(SpCh.RIGHT_ARROW), + charstr(SpCh.DELETE), + charstr(SpCh.BACK), + charstr(SpCh.TICKET), + charstr(SpCh.PARTY_ICON), + charstr(SpCh.LOCAL_ACCOUNT), + charstr(SpCh.FEDORA), + charstr(SpCh.HAL), + charstr(SpCh.CROWN), + charstr(SpCh.YIN_YANG), + charstr(SpCh.EYE_BALL), + charstr(SpCh.SKULL), + charstr(SpCh.HEART), + charstr(SpCh.DRAGON), + charstr(SpCh.HELMET), + charstr(SpCh.MUSHROOM), + charstr(SpCh.NINJA_STAR), + charstr(SpCh.VIKING_HELMET), + charstr(SpCh.MOON), + charstr(SpCh.SPIDER), + charstr(SpCh.FIREBALL), + charstr(SpCh.MIKIROG)] + ba.buttonwidget(edit=self._shift_button, + color=self._key_color_lit + if self._mode == 'emoji2' else self._key_color_dark, + label=charstr(SpCh.SHIFT), + on_activate_call=self._emoji_mode_2) + ba.buttonwidget(edit=self._emoji_button, + color=self._key_color_lit, + label=charstr(SpCh.LOGO_FLAT), + on_activate_call=self._emoji_mode) for i, btn in enumerate(self._char_keys): assert chars is not None @@ -308,10 +328,18 @@ class OnScreenKeyboardWindow(ba.Window): if self._mode in ['normal', 'caps', 'num']: self._last_mode = self._mode self._mode = 'emoji' - elif self._mode == 'emoji': + elif self._mode == 'emoji' or self._mode == 'emoji2': self._mode = self._last_mode self._refresh() + def _emoji_mode_2(self) -> None: + ba.playsound(self._click_sound) + if self._mode == 'emoji': + self._mode = 'emoji2' + elif self._mode == 'emoji2': + self._mode = 'emoji' + self._refresh() + def _shift(self) -> None: ba.playsound(self._click_sound) if self._mode == 'normal': From 93b2d158406d5ac6f99072df718803d82b1b1dd3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 21 Jul 2020 13:09:59 -0700 Subject: [PATCH 167/417] moved ba.app.uiscale to ba.app.ui.uiscale --- CHANGELOG.md | 1 + .../src/ba_data/python/ba/_activitytypes.py | 2 +- assets/src/ba_data/python/ba/_app.py | 44 +------------------ assets/src/ba_data/python/ba/_gameutils.py | 2 +- assets/src/ba_data/python/ba/_ui.py | 42 +++++++++++++++++- .../python/bastd/activity/multiteamvictory.py | 2 +- .../ba_data/python/bastd/game/runaround.py | 2 +- assets/src/ba_data/python/bastd/mainmenu.py | 6 +-- .../ba_data/python/bastd/ui/account/link.py | 4 +- .../python/bastd/ui/account/settings.py | 2 +- .../ba_data/python/bastd/ui/account/unlink.py | 2 +- .../ba_data/python/bastd/ui/account/viewer.py | 4 +- .../ba_data/python/bastd/ui/achievements.py | 2 +- .../src/ba_data/python/bastd/ui/appinvite.py | 4 +- .../python/bastd/ui/characterpicker.py | 2 +- .../ba_data/python/bastd/ui/colorpicker.py | 4 +- assets/src/ba_data/python/bastd/ui/confirm.py | 2 +- .../ba_data/python/bastd/ui/coop/browser.py | 4 +- .../src/ba_data/python/bastd/ui/coop/level.py | 2 +- .../ba_data/python/bastd/ui/creditslist.py | 2 +- assets/src/ba_data/python/bastd/ui/debug.py | 4 +- .../src/ba_data/python/bastd/ui/feedback.py | 2 +- .../ba_data/python/bastd/ui/fileselector.py | 2 +- assets/src/ba_data/python/bastd/ui/gather.py | 2 +- .../ba_data/python/bastd/ui/getcurrency.py | 2 +- .../src/ba_data/python/bastd/ui/getremote.py | 2 +- assets/src/ba_data/python/bastd/ui/helpui.py | 2 +- .../src/ba_data/python/bastd/ui/iconpicker.py | 2 +- assets/src/ba_data/python/bastd/ui/kiosk.py | 2 +- .../python/bastd/ui/league/rankwindow.py | 2 +- .../src/ba_data/python/bastd/ui/mainmenu.py | 12 ++--- .../python/bastd/ui/onscreenkeyboard.py | 2 +- assets/src/ba_data/python/bastd/ui/party.py | 6 +-- .../src/ba_data/python/bastd/ui/partyqueue.py | 2 +- assets/src/ba_data/python/bastd/ui/play.py | 2 +- .../python/bastd/ui/playlist/addgame.py | 2 +- .../python/bastd/ui/playlist/browser.py | 4 +- .../bastd/ui/playlist/customizebrowser.py | 2 +- .../ba_data/python/bastd/ui/playlist/edit.py | 2 +- .../python/bastd/ui/playlist/editgame.py | 2 +- .../python/bastd/ui/playlist/mapselect.py | 2 +- .../ba_data/python/bastd/ui/playlist/share.py | 2 +- .../ba_data/python/bastd/ui/playoptions.py | 2 +- assets/src/ba_data/python/bastd/ui/popup.py | 2 +- .../python/bastd/ui/profile/browser.py | 2 +- .../ba_data/python/bastd/ui/profile/edit.py | 2 +- .../python/bastd/ui/profile/upgrade.py | 2 +- .../src/ba_data/python/bastd/ui/promocode.py | 2 +- .../src/ba_data/python/bastd/ui/purchase.py | 2 +- assets/src/ba_data/python/bastd/ui/qrcode.py | 2 +- assets/src/ba_data/python/bastd/ui/report.py | 2 +- .../python/bastd/ui/resourcetypeinfo.py | 2 +- .../ba_data/python/bastd/ui/serverdialog.py | 2 +- .../python/bastd/ui/settings/advanced.py | 2 +- .../python/bastd/ui/settings/allsettings.py | 4 +- .../ba_data/python/bastd/ui/settings/audio.py | 2 +- .../python/bastd/ui/settings/controls.py | 2 +- .../python/bastd/ui/settings/gamepad.py | 4 +- .../bastd/ui/settings/gamepadadvanced.py | 2 +- .../python/bastd/ui/settings/gamepadselect.py | 4 +- .../python/bastd/ui/settings/graphics.py | 4 +- .../python/bastd/ui/settings/keyboard.py | 4 +- .../python/bastd/ui/settings/plugins.py | 2 +- .../python/bastd/ui/settings/ps3controller.py | 2 +- .../python/bastd/ui/settings/remoteapp.py | 2 +- .../python/bastd/ui/settings/testing.py | 2 +- .../python/bastd/ui/settings/touchscreen.py | 2 +- .../bastd/ui/settings/xbox360controller.py | 2 +- .../python/bastd/ui/soundtrack/browser.py | 2 +- .../python/bastd/ui/soundtrack/edit.py | 2 +- .../bastd/ui/soundtrack/entrytypeselect.py | 2 +- .../ba_data/python/bastd/ui/specialoffer.py | 2 +- .../ba_data/python/bastd/ui/store/browser.py | 6 +-- .../python/bastd/ui/teamnamescolors.py | 2 +- assets/src/ba_data/python/bastd/ui/telnet.py | 2 +- .../python/bastd/ui/tournamententry.py | 2 +- .../python/bastd/ui/tournamentscores.py | 2 +- .../src/ba_data/python/bastd/ui/trophies.py | 2 +- assets/src/ba_data/python/bastd/ui/url.py | 2 +- assets/src/ba_data/python/bastd/ui/watch.py | 6 +-- docs/ba_module.md | 9 +--- 81 files changed, 147 insertions(+), 153 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5f6af66b..4f058c78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ - Added 'selection_loops_to_parent', 'claims_left_right', and 'claims_tab' args to ba.rowwidget. - Added 'claims_left_right' and 'claims_tab' to ba.hscrollwidget(). - Default widget 'show_buffer' is now 20 instead of 0 (causes scrolling to stay slightly ahead of widget selection). This can be overridden with the ba.widget() call if anything breaks. +- Relocated ba.app.uiscale to ba.app.ui.uiscale ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index 065c47e2..2d8b917e 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -191,7 +191,7 @@ class ScoreScreenActivity(Activity[EmptyPlayer, EmptyTeam]): # Pop up a 'press any button to continue' statement after our # min-view-time show a 'press any button to continue..' # thing after a bit. - if _ba.app.uiscale is UIScale.LARGE: + if _ba.app.ui.uiscale is UIScale.LARGE: # FIXME: Need a better way to determine whether we've probably # got a keyboard. sval = _lang.Lstr(resource='pressAnyKeyButtonText') diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 023f3957..4c136eeb 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -30,7 +30,6 @@ import _ba if TYPE_CHECKING: import ba from ba import _lang, _meta - from ba.ui import UICleanupCheck from bastd.actor import spazappearance from typing import Optional, Dict, Set, Any, Type, Tuple, Callable, List @@ -230,11 +229,6 @@ class App: from ba._meta import CURRENT_API_VERSION return CURRENT_API_VERSION - @property - def uiscale(self) -> ba.UIScale: - """Current ui scale for the app.""" - return self._uiscale - @property def on_tv(self) -> bool: """Bool value for if the game is running on a TV.""" @@ -261,7 +255,6 @@ class App: """ # pylint: disable=too-many-statements from ba._music import MusicController - from ba._enums import UIScale from ba._ui import UI # Config. @@ -299,16 +292,6 @@ class App: assert isinstance(self._platform, str) self._subplatform: str = env['subplatform'] assert isinstance(self._subplatform, str) - self._uiscale: ba.UIScale - interfacetype = env['interface_type'] - if interfacetype == 'large': - self._uiscale = UIScale.LARGE - elif interfacetype == 'medium': - self._uiscale = UIScale.MEDIUM - elif interfacetype == 'small': - self._uiscale = UIScale.SMALL - else: - raise RuntimeError('Invalid UIScale value: {interfacetype}') self._on_tv: bool = env['on_tv'] assert isinstance(self._on_tv, bool) self._vr_mode: bool = env['vr_mode'] @@ -422,8 +405,6 @@ class App: """Runs after the app finishes bootstrapping. (internal)""" - # FIXME: Break this up. - # pylint: disable=too-many-statements # pylint: disable=too-many-locals # pylint: disable=cyclic-import from ba import _apputils @@ -435,7 +416,7 @@ class App: from bastd import appdelegate from bastd import maps as stdmaps from bastd.actor import spazappearance - from ba._enums import TimeType, UIScale + from ba._enums import TimeType cfg = self.config @@ -464,29 +445,6 @@ class App: and not _ba.is_blessed()): _ba.screenmessage('WARNING: NON-BLESSED BUILD', color=(1, 0, 0)) - # IMPORTANT: If tweaking UI stuff, make sure it behaves for small, - # medium, and large UI modes. (doesn't run off screen, etc). - # The overrides below can be used to test with different sizes. - # Generally small is used on phones, medium is used on tablets/tvs, - # and large is on desktop computers or perhaps large tablets. When - # possible, run in windowed mode and resize the window to assure - # this holds true at all aspect ratios. - - # UPDATE: A better way to test this is now by setting the environment - # variable BA_FORCE_UI_SCALE to "small", "medium", or "large". - # This will affect system UIs not covered by the values below such - # as screen-messages. The below values remain functional, however, - # for cases such as Android where environment variables can't be set - # easily. - - if bool(False): # force-test ui scale - self._uiscale = UIScale.SMALL - with _ba.Context('ui'): - _ba.pushcall(lambda: _ba.screenmessage( - f'FORCING UISCALE {self._uiscale.name} FOR TESTING', - color=(1, 0, 1), - log=True)) - # If there's a leftover log file, attempt to upload it to the # master-server and/or get rid of it. _apputils.handle_leftover_log_file() diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index dbe0c6d0..6679b685 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -224,7 +224,7 @@ def show_damage_count(damage: str, position: Sequence[float], # FIXME: Should never vary game elements based on local config. # (connected clients may have differing configs so they won't # get the intended results). - do_big = app.uiscale is UIScale.SMALL or app.vr_mode + do_big = app.ui.uiscale is UIScale.SMALL or app.vr_mode txtnode = _ba.newnode('text', attrs={ 'text': damage, diff --git a/assets/src/ba_data/python/ba/_ui.py b/assets/src/ba_data/python/ba/_ui.py index 5c612bf2..f2a5537c 100644 --- a/assets/src/ba_data/python/ba/_ui.py +++ b/assets/src/ba_data/python/ba/_ui.py @@ -25,6 +25,7 @@ from __future__ import annotations from typing import TYPE_CHECKING import _ba +from ba._enums import UIScale if TYPE_CHECKING: from typing import Optional, Dict, Any, Callable, List @@ -43,8 +44,19 @@ class UI: self._main_menu_window: Optional[ba.Widget] = None self._main_menu_location: Optional[str] = None + self._uiscale: ba.UIScale + + interfacetype = env['interface_type'] + if interfacetype == 'large': + self._uiscale = UIScale.LARGE + elif interfacetype == 'medium': + self._uiscale = UIScale.MEDIUM + elif interfacetype == 'small': + self._uiscale = UIScale.SMALL + else: + raise RuntimeError('Invalid UIScale value: {interfacetype}') + self.window_states: Dict = {} # FIXME: Kill this. - # self.windows: Dict = {} # FIXME: Kill this. self.main_menu_selection: Optional[str] = None # FIXME: Kill this. self.have_party_queue_window = False self.quit_window: Any = None @@ -58,11 +70,39 @@ class UI: self.heading_color = (0.72, 0.7, 0.75) self.infotextcolor = (0.7, 0.9, 0.7) + @property + def uiscale(self) -> ba.UIScale: + """Current ui scale for the app.""" + return self._uiscale + def on_app_launch(self) -> None: """Should be run on app launch.""" from ba.ui import UIController, ui_upkeep from ba._enums import TimeType + # IMPORTANT: If tweaking UI stuff, make sure it behaves for small, + # medium, and large UI modes. (doesn't run off screen, etc). + # The overrides below can be used to test with different sizes. + # Generally small is used on phones, medium is used on tablets/tvs, + # and large is on desktop computers or perhaps large tablets. When + # possible, run in windowed mode and resize the window to assure + # this holds true at all aspect ratios. + + # UPDATE: A better way to test this is now by setting the environment + # variable BA_FORCE_UI_SCALE to "small", "medium", or "large". + # This will affect system UIs not covered by the values below such + # as screen-messages. The below values remain functional, however, + # for cases such as Android where environment variables can't be set + # easily. + + if bool(False): # force-test ui scale + self._uiscale = UIScale.SMALL + with _ba.Context('ui'): + _ba.pushcall(lambda: _ba.screenmessage( + f'FORCING UISCALE {self._uiscale.name} FOR TESTING', + color=(1, 0, 1), + log=True)) + self.controller = UIController() # Kick off our periodic UI upkeep. diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 6f0bd926..352febc7 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -54,7 +54,7 @@ class TeamSeriesVictoryScoreScreenActivity(MultiTeamScoreScreenActivity): from ba.deprecated import get_resource ba.set_analytics_screen('FreeForAll Series Victory Screen' if self. _is_ffa else 'Teams Series Victory Screen') - if ba.app.uiscale is ba.UIScale.LARGE: + if ba.app.ui.uiscale is ba.UIScale.LARGE: sval = ba.Lstr(resource='pressAnyKeyButtonPlayAgainText') else: sval = ba.Lstr(resource='pressAnyButtonPlayAgainText') diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 66cd18b0..0813b076 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -398,7 +398,7 @@ class RunaroundGame(ba.CoopGameActivity[Player, Team]): self._tntspawner = TNTSpawner(position=self._tntspawnpos) # Make sure to stay out of the way of menu/party buttons in the corner. - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale l_offs = (-80 if uiscale is ba.UIScale.SMALL else -40 if uiscale is ba.UIScale.MEDIUM else 0) diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 6b275cd9..99795e68 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -65,7 +65,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): color = ((1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6)) # FIXME: Need a node attr for vr-specific-scale. scale = (0.9 if - (app.uiscale is ba.UIScale.SMALL or vr_mode) else 0.7) + (app.ui.uiscale is ba.UIScale.SMALL or vr_mode) else 0.7) self.my_name = ba.NodeActor( ba.newnode('text', attrs={ @@ -104,7 +104,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): # Any differences need to happen at the engine level so everyone sees # things in their own optimal way. vr_mode = app.vr_mode - uiscale = app.uiscale + uiscale = app.ui.uiscale # In cases where we're doing lots of dev work lets always show the # build number. @@ -373,7 +373,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): ba.WeakCall(self._change_phrase), repeat=True) - scl = 1.2 if (ba.app.uiscale is ba.UIScale.SMALL + scl = 1.2 if (ba.app.ui.uiscale is ba.UIScale.SMALL or ba.app.vr_mode) else 0.8 color2 = ((1, 1, 1, 1) if ba.app.vr_mode else diff --git a/assets/src/ba_data/python/bastd/ui/account/link.py b/assets/src/ba_data/python/bastd/ui/account/link.py index 8f0c238d..261b358b 100644 --- a/assets/src/ba_data/python/bastd/ui/account/link.py +++ b/assets/src/ba_data/python/bastd/ui/account/link.py @@ -49,7 +49,7 @@ class AccountLinkWindow(ba.Window): bg_color = (0.4, 0.4, 0.5) self._width = 560 self._height = 420 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale base_scale = (1.65 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( @@ -132,7 +132,7 @@ class AccountLinkCodeWindow(ba.Window): def __init__(self, data: Dict[str, Any]): self._width = 350 self._height = 200 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py index 3ec9adf8..bf970745 100644 --- a/assets/src/ba_data/python/bastd/ui/account/settings.py +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py @@ -77,7 +77,7 @@ class AccountSettingsWindow(ba.Window): self._can_reset_achievements = (account_type == 'Game Center') app = ba.app - uiscale = app.uiscale + uiscale = app.ui.uiscale self._width = 760 if uiscale is ba.UIScale.SMALL else 660 x_offs = 50 if uiscale is ba.UIScale.SMALL else 0 diff --git a/assets/src/ba_data/python/bastd/ui/account/unlink.py b/assets/src/ba_data/python/bastd/ui/account/unlink.py index 214d8f92..83ed0b47 100644 --- a/assets/src/ba_data/python/bastd/ui/account/unlink.py +++ b/assets/src/ba_data/python/bastd/ui/account/unlink.py @@ -50,7 +50,7 @@ class AccountUnlinkWindow(ba.Window): self._height = 350 self._scroll_width = 400 self._scroll_height = 200 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale base_scale = (2.0 if uiscale is ba.UIScale.SMALL else 1.6 if uiscale is ba.UIScale.MEDIUM else 1.1) super().__init__(root_widget=ba.containerwidget( diff --git a/assets/src/ba_data/python/bastd/ui/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py index 044196c7..6560d908 100644 --- a/assets/src/ba_data/python/bastd/ui/account/viewer.py +++ b/assets/src/ba_data/python/bastd/ui/account/viewer.py @@ -46,7 +46,7 @@ class AccountViewerWindow(popup.PopupWindow): self._account_id = account_id self._profile_id = profile_id - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.6 if uiscale is ba.UIScale.SMALL else 1.8 if uiscale is ba.UIScale.MEDIUM else 1.4) @@ -161,7 +161,7 @@ class AccountViewerWindow(popup.PopupWindow): choices.append('ban') choices_display.append(ba.Lstr(resource='banThisPlayerText')) - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale popup.PopupMenuWindow( position=self._extras_menu_button.get_screen_space_center(), scale=(2.3 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/achievements.py b/assets/src/ba_data/python/bastd/ui/achievements.py index b63ce088..6c4685a8 100644 --- a/assets/src/ba_data/python/bastd/ui/achievements.py +++ b/assets/src/ba_data/python/bastd/ui/achievements.py @@ -36,7 +36,7 @@ class AchievementsWindow(popup.PopupWindow): def __init__(self, position: Tuple[float, float], scale: float = None): # pylint: disable=too-many-locals - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/appinvite.py b/assets/src/ba_data/python/bastd/ui/appinvite.py index db1615c4..3ce9270d 100644 --- a/assets/src/ba_data/python/bastd/ui/appinvite.py +++ b/assets/src/ba_data/python/bastd/ui/appinvite.py @@ -42,7 +42,7 @@ class AppInviteWindow(ba.Window): self._width = 650 self._height = 400 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', @@ -174,7 +174,7 @@ class ShowFriendCodeWindow(ba.Window): ba.set_analytics_screen('Friend Promo Code') self._width = 650 self._height = 400 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), diff --git a/assets/src/ba_data/python/bastd/ui/characterpicker.py b/assets/src/ba_data/python/bastd/ui/characterpicker.py index 4952988c..c18f4806 100644 --- a/assets/src/ba_data/python/bastd/ui/characterpicker.py +++ b/assets/src/ba_data/python/bastd/ui/characterpicker.py @@ -48,7 +48,7 @@ class CharacterPicker(popup.PopupWindow): # pylint: disable=too-many-locals from bastd.actor import spazappearance del parent # unused here - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (1.85 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/colorpicker.py b/assets/src/ba_data/python/bastd/ui/colorpicker.py index 21f4328e..336be37e 100644 --- a/assets/src/ba_data/python/bastd/ui/colorpicker.py +++ b/assets/src/ba_data/python/bastd/ui/colorpicker.py @@ -52,7 +52,7 @@ class ColorPicker(PopupWindow): assert len(c_raw) == 16 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) @@ -191,7 +191,7 @@ class ColorPickerExact(PopupWindow): assert len(c_raw) == 16 self.colors = [c_raw[0:4], c_raw[4:8], c_raw[8:12], c_raw[12:16]] - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/confirm.py b/assets/src/ba_data/python/bastd/ui/confirm.py index 5874d299..803b5231 100644 --- a/assets/src/ba_data/python/bastd/ui/confirm.py +++ b/assets/src/ba_data/python/bastd/ui/confirm.py @@ -68,7 +68,7 @@ class ConfirmWindow: scale_origin = None transition = 'in_right' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self.root_widget = ba.containerwidget( size=(width, height), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index 840f4fc3..ef313d00 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -40,7 +40,7 @@ class CoopBrowserWindow(ba.Window): """Window for browsing co-op levels/games/etc.""" def _update_corner_button_positions(self) -> None: - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale offs = (-55 if uiscale is ba.UIScale.SMALL and _ba.is_party_icon_visible() else 0) if self._league_rank_button is not None: @@ -98,7 +98,7 @@ class CoopBrowserWindow(ba.Window): self._hard_button_lock_image: Optional[ba.Widget] = None self._campaign_percent_text: Optional[ba.Widget] = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (657 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/coop/level.py b/assets/src/ba_data/python/bastd/ui/coop/level.py index 85271139..f5b656af 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/level.py +++ b/assets/src/ba_data/python/bastd/ui/coop/level.py @@ -32,7 +32,7 @@ class CoopLevelLockedWindow(ba.Window): width = 550.0 height = 250.0 lock_tex = ba.gettexture('lock') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/creditslist.py b/assets/src/ba_data/python/bastd/ui/creditslist.py index f2241f8a..84ffa9ea 100644 --- a/assets/src/ba_data/python/bastd/ui/creditslist.py +++ b/assets/src/ba_data/python/bastd/ui/creditslist.py @@ -51,7 +51,7 @@ class CreditsListWindow(ba.Window): scale_origin = None transition = 'in_right' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale width = 870 if uiscale is ba.UIScale.SMALL else 670 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 height = 398 if uiscale is ba.UIScale.SMALL else 500 diff --git a/assets/src/ba_data/python/bastd/ui/debug.py b/assets/src/ba_data/python/bastd/ui/debug.py index 8470d1df..c523047b 100644 --- a/assets/src/ba_data/python/bastd/ui/debug.py +++ b/assets/src/ba_data/python/bastd/ui/debug.py @@ -38,7 +38,7 @@ class DebugWindow(ba.Window): # pylint: disable=cyclic-import from bastd.ui import popup - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = width = 580 self._height = height = (350 if uiscale is ba.UIScale.SMALL else 420 if uiscale is ba.UIScale.MEDIUM else 520) @@ -55,7 +55,7 @@ class DebugWindow(ba.Window): self._stress_test_round_duration = 30 self._r = 'debugWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/feedback.py b/assets/src/ba_data/python/bastd/ui/feedback.py index 5f5fb37b..0ecfe985 100644 --- a/assets/src/ba_data/python/bastd/ui/feedback.py +++ b/assets/src/ba_data/python/bastd/ui/feedback.py @@ -41,7 +41,7 @@ def ask_for_rating() -> Optional[ba.Widget]: width = 700 height = 400 spacing = 40 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale dlg = ba.containerwidget( size=(width, height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/fileselector.py b/assets/src/ba_data/python/bastd/ui/fileselector.py index cc5badc3..00fb2fba 100644 --- a/assets/src/ba_data/python/bastd/ui/fileselector.py +++ b/assets/src/ba_data/python/bastd/ui/fileselector.py @@ -45,7 +45,7 @@ class FileSelectorWindow(ba.Window): allow_folders: bool = False): if valid_file_extensions is None: valid_file_extensions = [] - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 700 if uiscale is ba.UIScale.SMALL else 600 self._x_inset = x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = 365 if uiscale is ba.UIScale.SMALL else 418 diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 2347e3af..5df5bf23 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -58,7 +58,7 @@ class GatherWindow(ba.Window): ba.app.ui.set_main_menu_location('Gather') _ba.set_party_icon_always_visible(True) self._public_parties: Dict[str, Dict[str, Any]] = {} - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (582 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/getcurrency.py b/assets/src/ba_data/python/bastd/ui/getcurrency.py index b3524168..78f28a62 100644 --- a/assets/src/ba_data/python/bastd/ui/getcurrency.py +++ b/assets/src/ba_data/python/bastd/ui/getcurrency.py @@ -65,7 +65,7 @@ class GetCurrencyWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 1000.0 if uiscale is ba.UIScale.SMALL else 800.0 x_inset = 100.0 if uiscale is ba.UIScale.SMALL else 0.0 self._height = 480.0 diff --git a/assets/src/ba_data/python/bastd/ui/getremote.py b/assets/src/ba_data/python/bastd/ui/getremote.py index 4d7c6a84..3dcae3f3 100644 --- a/assets/src/ba_data/python/bastd/ui/getremote.py +++ b/assets/src/ba_data/python/bastd/ui/getremote.py @@ -36,7 +36,7 @@ class GetBSRemoteWindow(popup.PopupWindow): def __init__(self) -> None: position = (0.0, 0.0) - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False diff --git a/assets/src/ba_data/python/bastd/ui/helpui.py b/assets/src/ba_data/python/bastd/ui/helpui.py index e0a49083..259977d4 100644 --- a/assets/src/ba_data/python/bastd/ui/helpui.py +++ b/assets/src/ba_data/python/bastd/ui/helpui.py @@ -57,7 +57,7 @@ class HelpWindow(ba.Window): self._r = 'helpWindow' self._main_menu = main_menu - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale width = 950 if uiscale is ba.UIScale.SMALL else 750 x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 height = (460 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/iconpicker.py b/assets/src/ba_data/python/bastd/ui/iconpicker.py index d2cc9794..2633aba1 100644 --- a/assets/src/ba_data/python/bastd/ui/iconpicker.py +++ b/assets/src/ba_data/python/bastd/ui/iconpicker.py @@ -50,7 +50,7 @@ class IconPicker(popup.PopupWindow): del parent # unused here del tint_color # unused_here del tint2_color # unused here - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (1.85 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index 1b6625aa..3d21fae6 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -311,7 +311,7 @@ class KioskWindow(ba.Window): self._b4 = self._b5 = self._b6 = None self._b7: Optional[ba.Widget] - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if bool(False): self._b7 = ba.buttonwidget( parent=self._root_widget, diff --git a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py index 6bfc30b0..0c83c884 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py @@ -58,7 +58,7 @@ class LeagueRankWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 1320 if uiscale is ba.UIScale.SMALL else 1120 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (657 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 99a36922..070dc893 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -187,7 +187,7 @@ class MainMenuWindow(ba.Window): self._r = 'mainMenu' app = ba.app - self._have_quit_button = (app.uiscale is ba.UIScale.LARGE + self._have_quit_button = (app.ui.uiscale is ba.UIScale.LARGE or (app.platform == 'windows' and app.subplatform == 'oculus')) @@ -288,7 +288,7 @@ class MainMenuWindow(ba.Window): sale_scale=1.3, transition_delay=self._tdelay) self._store_button = store_button = sbtn.get_button() - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale icon_size = (55 if uiscale is ba.UIScale.SMALL else 55 if uiscale is ba.UIScale.MEDIUM else 70) ba.imagewidget( @@ -357,7 +357,7 @@ class MainMenuWindow(ba.Window): b_size = 50.0 b_buffer = 10.0 t_scale = 0.75 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if uiscale is ba.UIScale.SMALL: b_size *= 0.6 b_buffer *= 1.0 @@ -459,7 +459,7 @@ class MainMenuWindow(ba.Window): b_count += 1 if self._have_store_button: b_count += 1 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if uiscale is ba.UIScale.SMALL: root_widget_scale = 1.6 play_button_width = self._button_width * 0.65 @@ -517,7 +517,7 @@ class MainMenuWindow(ba.Window): on_activate_call=self._demo_menu_press) else: self._demo_menu_button = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale foof = (-1 if uiscale is ba.UIScale.SMALL else 1 if uiscale is ba.UIScale.MEDIUM else 3) h, v, scale = positions[self._p_index] @@ -715,7 +715,7 @@ class MainMenuWindow(ba.Window): # In this case we have a leave *and* a disconnect button. self._height += 50 self._height += 50 * (len(custom_menu_entries)) - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale ba.containerwidget( edit=self._root_widget, size=(self._width, self._height), diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index d32a9ae5..15660f86 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -39,7 +39,7 @@ class OnScreenKeyboardWindow(ba.Window): self._target_text = textwidget self._width = 700 self._height = 400 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 super().__init__(root_widget=ba.containerwidget( parent=_ba.get_special_widget('overlay_stack'), diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py index 52fcc10a..46dd70eb 100644 --- a/assets/src/ba_data/python/bastd/ui/party.py +++ b/assets/src/ba_data/python/bastd/ui/party.py @@ -47,7 +47,7 @@ class PartyWindow(ba.Window): self._popup_party_member_client_id: Optional[int] = None self._popup_party_member_is_host: Optional[bool] = None self._width = 500 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._height = (365 if uiscale is ba.UIScale.SMALL else 480 if uiscale is ba.UIScale.MEDIUM else 600) super().__init__(root_widget=ba.containerwidget( @@ -202,7 +202,7 @@ class PartyWindow(ba.Window): def _on_menu_button_press(self) -> None: is_muted = ba.app.config.resolve('Chat Muted') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale popup.PopupMenuWindow( position=self._menu_button.get_screen_space_center(), scale=(2.3 if uiscale is ba.UIScale.SMALL else @@ -406,7 +406,7 @@ class PartyWindow(ba.Window): 14248): return kick_str = ba.Lstr(resource='kickVoteText') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale popup.PopupMenuWindow( position=widget.get_screen_space_center(), scale=(2.3 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py index 0a1e8dc6..3d5c2df7 100644 --- a/assets/src/ba_data/python/bastd/ui/partyqueue.py +++ b/assets/src/ba_data/python/bastd/ui/partyqueue.py @@ -223,7 +223,7 @@ class PartyQueueWindow(ba.Window): self._line_image: Optional[ba.Widget] = None self.eyes_model = ba.getmodel('plasticEyesTransparent') self._white_tex = ba.gettexture('white') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py index d097dfde..82eabd59 100644 --- a/assets/src/ba_data/python/bastd/ui/play.py +++ b/assets/src/ba_data/python/bastd/ui/play.py @@ -46,7 +46,7 @@ class PlayWindow(ba.Window): threading.Thread(target=self._preload_modules).start() new_style = True - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale width = 1000 if uiscale is ba.UIScale.SMALL else 800 x_offs = 100 if uiscale is ba.UIScale.SMALL else 0 height = 550 if new_style else 400 diff --git a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py index f93779ef..e2902826 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py @@ -40,7 +40,7 @@ class PlaylistAddGameWindow(ba.Window): transition: str = 'in_right'): self._editcontroller = editcontroller self._r = 'addGameWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 750 if uiscale is ba.UIScale.SMALL else 650 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = (346 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index abaf4ed1..d9600955 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -218,7 +218,7 @@ class PlaylistBrowserWindow(ba.Window): self._selected_playlist = ba.app.config.get(self._pvars.config_name + ' Playlist Selection') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 900 if uiscale is ba.UIScale.SMALL else 800 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = (480 if uiscale is ba.UIScale.SMALL else @@ -366,7 +366,7 @@ class PlaylistBrowserWindow(ba.Window): h_offs = 225 if count == 1 else 115 if count == 2 else 0 h_offs_bottom = 0 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale for y in range(rows): for x in range(columns): name = items[index][0] diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py index 640f73a6..b71a7575 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -59,7 +59,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): self._pvars = playlist.PlaylistTypeVars(sessiontype) self._max_playlists = 30 self._r = 'gameListWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 750.0 if uiscale is ba.UIScale.SMALL else 650.0 x_inset = 50.0 if uiscale is ba.UIScale.SMALL else 0.0 self._height = (380.0 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index 3b5dda02..35739c28 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -45,7 +45,7 @@ class PlaylistEditWindow(ba.Window): self._r = 'editGameListWindow' prev_selection = self._editcontroller.get_edit_ui_selection() - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 770 if uiscale is ba.UIScale.SMALL else 670 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 self._height = (400 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index 78a67007..1241c9d5 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -106,7 +106,7 @@ class PlaylistEditGameWindow(ba.Window): self._choice_selections: Dict[str, int] = {} - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale width = 720 if uiscale is ba.UIScale.SMALL else 620 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 height = (365 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py index 50adc5c9..1bcc15d1 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py @@ -55,7 +55,7 @@ class PlaylistMapSelectWindow(ba.Window): except Exception: self._previous_map = '' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale width = 715 if uiscale is ba.UIScale.SMALL else 615 x_inset = 50 if uiscale is ba.UIScale.SMALL else 0 height = (400 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/playlist/share.py b/assets/src/ba_data/python/bastd/ui/playlist/share.py index 26b47daf..4c2c27e1 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/share.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/share.py @@ -89,7 +89,7 @@ class SharePlaylistResultsWindow(ba.Window): del origin # unused arg self._width = 450 self._height = 300 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), color=(0.45, 0.63, 0.15), diff --git a/assets/src/ba_data/python/bastd/ui/playoptions.py b/assets/src/ba_data/python/bastd/ui/playoptions.py index 2e9267d4..958c90be 100644 --- a/assets/src/ba_data/python/bastd/ui/playoptions.py +++ b/assets/src/ba_data/python/bastd/ui/playoptions.py @@ -149,7 +149,7 @@ class PlayOptionsWindow(popup.PopupWindow): self._height += 40 # Creates our _root_widget. - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale scale = (1.69 if uiscale is ba.UIScale.SMALL else 1.1 if uiscale is ba.UIScale.MEDIUM else 0.85) super().__init__(position=scale_origin, diff --git a/assets/src/ba_data/python/bastd/ui/popup.py b/assets/src/ba_data/python/bastd/ui/popup.py index 8386b821..517e3a05 100644 --- a/assets/src/ba_data/python/bastd/ui/popup.py +++ b/assets/src/ba_data/python/bastd/ui/popup.py @@ -300,7 +300,7 @@ class PopupMenu: choices_disabled = [] if choices_display is None: choices_display = [] - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py index 4feefaf1..3a471cb4 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py @@ -47,7 +47,7 @@ class ProfileBrowserWindow(ba.Window): back_label = ba.Lstr(resource='backText') else: back_label = ba.Lstr(resource='doneText') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 700.0 if uiscale is ba.UIScale.SMALL else 600.0 x_inset = 50.0 if uiscale is ba.UIScale.SMALL else 0.0 self._height = (360.0 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/profile/edit.py b/assets/src/ba_data/python/bastd/ui/profile/edit.py index 0577a769..36f62bb8 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/edit.py +++ b/assets/src/ba_data/python/bastd/ui/profile/edit.py @@ -63,7 +63,7 @@ class EditProfileWindow(ba.Window): # Grab profile colors or pick random ones. self._color, self._highlight = get_player_profile_colors( existing_profile) - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = width = 780.0 if uiscale is ba.UIScale.SMALL else 680.0 self._x_inset = x_inset = 50.0 if uiscale is ba.UIScale.SMALL else 0.0 self._height = height = ( diff --git a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py index a08de529..c46133c9 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py +++ b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py @@ -45,7 +45,7 @@ class ProfileUpgradeWindow(ba.Window): self._width = 680 self._height = 350 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._base_scale = (2.05 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.2) self._upgrade_start_time: Optional[float] = None diff --git a/assets/src/ba_data/python/bastd/ui/promocode.py b/assets/src/ba_data/python/bastd/ui/promocode.py index 5959a411..7d0d9a93 100644 --- a/assets/src/ba_data/python/bastd/ui/promocode.py +++ b/assets/src/ba_data/python/bastd/ui/promocode.py @@ -53,7 +53,7 @@ class PromoCodeWindow(ba.Window): self._modal = modal self._r = 'promoCodeWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/purchase.py b/assets/src/ba_data/python/bastd/ui/purchase.py index 6189e937..9fdd6279 100644 --- a/assets/src/ba_data/python/bastd/ui/purchase.py +++ b/assets/src/ba_data/python/bastd/ui/purchase.py @@ -48,7 +48,7 @@ class PurchaseWindow(ba.Window): self._items = list(items) self._width = 580 self._height = 520 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/qrcode.py b/assets/src/ba_data/python/bastd/ui/qrcode.py index fbe234a1..42ac8a7d 100644 --- a/assets/src/ba_data/python/bastd/ui/qrcode.py +++ b/assets/src/ba_data/python/bastd/ui/qrcode.py @@ -31,7 +31,7 @@ class QRCodeWindow(popup.PopupWindow): def __init__(self, origin_widget: ba.Widget, qr_tex: ba.Texture): position = origin_widget.get_screen_space_center() - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False diff --git a/assets/src/ba_data/python/bastd/ui/report.py b/assets/src/ba_data/python/bastd/ui/report.py index afe54852..88600e79 100644 --- a/assets/src/ba_data/python/bastd/ui/report.py +++ b/assets/src/ba_data/python/bastd/ui/report.py @@ -37,7 +37,7 @@ class ReportPlayerWindow(ba.Window): scale_origin = origin_widget.get_screen_space_center() overlay_stack = _ba.get_special_widget('overlay_stack') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), parent=overlay_stack, diff --git a/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py index 7b3d3cf3..2ebe9728 100644 --- a/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py +++ b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py @@ -30,7 +30,7 @@ class ResourceTypeInfoWindow(popup.PopupWindow): """Popup window providing info about resource types.""" def __init__(self, origin_widget: ba.Widget): - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._transitioning_out = False diff --git a/assets/src/ba_data/python/bastd/ui/serverdialog.py b/assets/src/ba_data/python/bastd/ui/serverdialog.py index 8cdf820d..4a803f3f 100644 --- a/assets/src/ba_data/python/bastd/ui/serverdialog.py +++ b/assets/src/ba_data/python/bastd/ui/serverdialog.py @@ -44,7 +44,7 @@ class ServerDialogWindow(ba.Window): txt_scale) self._width = 500 self._height = 130 + min(200, txt_height) - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_scale', diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index 6afca8f3..538f5f47 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -59,7 +59,7 @@ class AdvancedSettingsWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (390.0 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index ab9476c9..1097f6da 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -54,7 +54,7 @@ class AllSettingsWindow(ba.Window): else: self._transition_out = 'out_right' scale_origin = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale width = 900 if uiscale is ba.UIScale.SMALL else 580 x_inset = 75 if uiscale is ba.UIScale.SMALL else 0 height = 435 @@ -62,7 +62,7 @@ class AllSettingsWindow(ba.Window): self._r = 'settingsWindow' top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height + top_extra), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/settings/audio.py b/assets/src/ba_data/python/bastd/ui/settings/audio.py index 185339c9..2ef25547 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/audio.py +++ b/assets/src/ba_data/python/bastd/ui/settings/audio.py @@ -74,7 +74,7 @@ class AudioSettingsWindow(ba.Window): show_soundtracks = True height += spacing * 2.0 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale base_scale = (2.05 if uiscale is ba.UIScale.SMALL else 1.6 if uiscale is ba.UIScale.MEDIUM else 1.0) popup_menu_scale = base_scale * 1.2 diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index 6337af17..6fcc2e5b 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -144,7 +144,7 @@ class ControlsSettingsWindow(ba.Window): if show_xinput_toggle: height += spacing - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale smallscale = (1.7 if show_keyboard else 2.2) super().__init__(root_widget=ba.containerwidget( size=(width, height), diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index 680a20c1..bdc9d4d9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -60,7 +60,7 @@ class GamepadSettingsWindow(ba.Window): self._width = 700 if self._is_secondary else 730 self._height = 440 if self._is_secondary else 450 self._spacing = 40 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), scale=(1.63 if uiscale is ba.UIScale.SMALL else @@ -783,7 +783,7 @@ class AwaitGamepadInputWindow(ba.Window): self._capture_button = button width = 400 height = 150 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( scale=(2.0 if uiscale is ba.UIScale.SMALL else 1.9 if uiscale is ba.UIScale.MEDIUM else 1.0), diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py index 35f3e336..c9893141 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py @@ -41,7 +41,7 @@ class GamepadAdvancedSettingsWindow(ba.Window): app = ba.app self._r = parent_window.get_r() - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 900 if uiscale is ba.UIScale.SMALL else 700 self._x_inset = x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = 402 if uiscale is ba.UIScale.SMALL else 512 diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py index e2b14c5e..72c7864e 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py @@ -55,7 +55,7 @@ def gamepad_configure_callback(event: Dict[str, Any]) -> None: width = 700 height = 200 button_width = 100 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale dlg = (ba.containerwidget( scale=(1.7 if uiscale is ba.UIScale.SMALL else 1.4 if uiscale is ba.UIScale.MEDIUM else 1.0), @@ -101,7 +101,7 @@ class GamepadSelectWindow(ba.Window): spacing = 40 self._r = 'configGamepadSelectWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( scale=(2.3 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0), diff --git a/assets/src/ba_data/python/bastd/ui/settings/graphics.py b/assets/src/ba_data/python/bastd/ui/settings/graphics.py index 3bda574b..addcce11 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/graphics.py +++ b/assets/src/ba_data/python/bastd/ui/settings/graphics.py @@ -57,7 +57,7 @@ class GraphicsSettingsWindow(ba.Window): spacing = 32 self._have_selected_child = False - uiscale = app.uiscale + uiscale = app.ui.uiscale width = 450.0 height = 302.0 @@ -83,7 +83,7 @@ class GraphicsSettingsWindow(ba.Window): show_resolution = (app.platform == 'android' and app.subplatform == 'cardboard') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale base_scale = (2.4 if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0) popup_menu_scale = base_scale * 1.2 diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index f030eba1..8ed9fc65 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -49,7 +49,7 @@ class ConfigKeyboardWindow(ba.Window): else: self._height = 375 self._spacing = 40 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), scale=(1.6 if uiscale is ba.UIScale.SMALL else @@ -272,7 +272,7 @@ class AwaitKeyboardInputWindow(ba.Window): width = 400 height = 150 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/settings/plugins.py b/assets/src/ba_data/python/bastd/ui/settings/plugins.py index 8a953054..c550f6a6 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/plugins.py +++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py @@ -49,7 +49,7 @@ class PluginSettingsWindow(ba.Window): self._transition_out = 'out_right' scale_origin = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 870.0 if uiscale is ba.UIScale.SMALL else 670.0 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (390.0 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py index 25b6eada..f9898611 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py @@ -34,7 +34,7 @@ class PS3ControllerSettingsWindow(ba.Window): height = 330 if _ba.is_running_on_fire_tv() else 540 spacing = 40 self._r = 'ps3ControllersWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py index 8c4bf58f..81569f2b 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py +++ b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py @@ -34,7 +34,7 @@ class RemoteAppSettingsWindow(ba.Window): width = 700 height = 390 spacing = 40 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/settings/testing.py b/assets/src/ba_data/python/bastd/ui/settings/testing.py index 58c9427b..b413df62 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/testing.py +++ b/assets/src/ba_data/python/bastd/ui/settings/testing.py @@ -39,7 +39,7 @@ class TestingWindow(ba.Window): title: ba.Lstr, entries: List[Dict[str, Any]], transition: str = 'in_right'): - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 600 self._height = 324 if uiscale is ba.UIScale.SMALL else 400 self._entries = copy.deepcopy(entries) diff --git a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py index 311e5be2..6e6d75eb 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py +++ b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py @@ -45,7 +45,7 @@ class TouchscreenSettingsWindow(ba.Window): _ba.set_touchscreen_editing(True) - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py index 334431a9..a91037ca 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py @@ -39,7 +39,7 @@ class XBox360ControllerSettingsWindow(ba.Window): width = 700 height = 300 if _ba.is_running_on_fire_tv() else 485 spacing = 40 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py index 3db1035e..2e1c5d97 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py @@ -52,7 +52,7 @@ class SoundtrackBrowserWindow(ba.Window): scale_origin = None self._r = 'editSoundtrackWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 800 if uiscale is ba.UIScale.SMALL else 600 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (340 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py index c31d9e66..c6ce84b7 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py @@ -43,7 +43,7 @@ class SoundtrackEditWindow(ba.Window): self._r = 'editSoundtrackWindow' self._folder_tex = ba.gettexture('folder') self._file_tex = ba.gettexture('file') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 848 if uiscale is ba.UIScale.SMALL else 648 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (395 if uiscale is ba.UIScale.SMALL else diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py index 6c105975..839a0753 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @@ -64,7 +64,7 @@ class SoundtrackEntryTypeSelectWindow(ba.Window): if do_music_folder: self._height += spacing - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/specialoffer.py b/assets/src/ba_data/python/bastd/ui/specialoffer.py index 8d7d2764..6c7b2618 100644 --- a/assets/src/ba_data/python/bastd/ui/specialoffer.py +++ b/assets/src/ba_data/python/bastd/ui/specialoffer.py @@ -91,7 +91,7 @@ class SpecialOfferWindow(ba.Window): self._offer = copy.deepcopy(offer) self._width = 580 self._height = 590 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(self._width, self._height), transition=transition, diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 627308e4..1e6f110f 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -39,7 +39,7 @@ class StoreBrowserWindow(ba.Window): """Window for browsing the store.""" def _update_get_tickets_button_pos(self) -> None: - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if self._get_tickets_button: pos = (self._width - 252 - (self._x_inset + (47 if uiscale is ba.UIScale.SMALL @@ -60,7 +60,7 @@ class StoreBrowserWindow(ba.Window): from ba import SpecialChar app = ba.app - uiscale = app.uiscale + uiscale = app.ui.uiscale ba.set_analytics_screen('Store Window') @@ -717,7 +717,7 @@ class StoreBrowserWindow(ba.Window): self._sections = copy.deepcopy(store_data[sdata['tab']]) self._height: Optional[float] = None - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale # Pre-calc a few things and add them to store-data. for section in self._sections: diff --git a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py index a49725f3..8ebea612 100644 --- a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py +++ b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py @@ -43,7 +43,7 @@ class TeamNamesColorsWindow(popup.PopupWindow): self._max_name_length = 16 # Creates our _root_widget. - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale scale = (1.69 if uiscale is ba.UIScale.SMALL else 1.1 if uiscale is ba.UIScale.MEDIUM else 0.85) super().__init__(position=scale_origin, diff --git a/assets/src/ba_data/python/bastd/ui/telnet.py b/assets/src/ba_data/python/bastd/ui/telnet.py index 4b7f2737..869d60fb 100644 --- a/assets/src/ba_data/python/bastd/ui/telnet.py +++ b/assets/src/ba_data/python/bastd/ui/telnet.py @@ -34,7 +34,7 @@ class TelnetAccessRequestWindow(ba.Window): height = 100 text = ba.Lstr(resource='telnetAccessText') - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale super().__init__(root_widget=ba.containerwidget( size=(width, height + 40), transition='in_right', diff --git a/assets/src/ba_data/python/bastd/ui/tournamententry.py b/assets/src/ba_data/python/bastd/ui/tournamententry.py index 6e255229..7238a753 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamententry.py +++ b/assets/src/ba_data/python/bastd/ui/tournamententry.py @@ -78,7 +78,7 @@ class TournamentEntryWindow(popup.PopupWindow): self._on_close_call = on_close_call if scale is None: - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) self._delegate = delegate diff --git a/assets/src/ba_data/python/bastd/ui/tournamentscores.py b/assets/src/ba_data/python/bastd/ui/tournamentscores.py index fc34f17a..d5e65142 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamentscores.py +++ b/assets/src/ba_data/python/bastd/ui/tournamentscores.py @@ -53,7 +53,7 @@ class TournamentScoresWindow(popup_ui.PopupWindow): self._tournament_id = tournament_id self._subcontainer: Optional[ba.Widget] = None self._on_close_call = on_close_call - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/trophies.py b/assets/src/ba_data/python/bastd/ui/trophies.py index 4009fc28..aa7d52ac 100644 --- a/assets/src/ba_data/python/bastd/ui/trophies.py +++ b/assets/src/ba_data/python/bastd/ui/trophies.py @@ -40,7 +40,7 @@ class TrophiesWindow(popup.PopupWindow): scale: float = None): from ba.deprecated import get_resource self._data = data - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if scale is None: scale = (2.3 if uiscale is ba.UIScale.SMALL else 1.65 if uiscale is ba.UIScale.MEDIUM else 1.23) diff --git a/assets/src/ba_data/python/bastd/ui/url.py b/assets/src/ba_data/python/bastd/ui/url.py index cb47c26c..413b257a 100644 --- a/assets/src/ba_data/python/bastd/ui/url.py +++ b/assets/src/ba_data/python/bastd/ui/url.py @@ -34,7 +34,7 @@ class ShowURLWindow(ba.Window): # in some cases we might want to show it as a qr code # (for long URLs especially) app = ba.app - uiscale = app.uiscale + uiscale = app.ui.uiscale if app.platform == 'android' and app.subplatform == 'alibaba': self._width = 500 self._height = 500 diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py index c99884d8..d2ef27da 100644 --- a/assets/src/ba_data/python/bastd/ui/watch.py +++ b/assets/src/ba_data/python/bastd/ui/watch.py @@ -60,7 +60,7 @@ class WatchWindow(ba.Window): self._my_replays_rename_window: Optional[ba.Widget] = None self._my_replay_rename_text: Optional[ba.Widget] = None self._r = 'watchWindow' - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._width = 1240 if uiscale is ba.UIScale.SMALL else 1040 x_inset = 100 if uiscale is ba.UIScale.SMALL else 0 self._height = (578 if uiscale is ba.UIScale.SMALL else @@ -174,7 +174,7 @@ class WatchWindow(ba.Window): # switching to a different tab self._tab_data = {} - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale if tab == 'my_replays': c_width = self._scroll_width c_height = self._scroll_height - 20 @@ -316,7 +316,7 @@ class WatchWindow(ba.Window): return c_width = 600 c_height = 250 - uiscale = ba.app.uiscale + uiscale = ba.app.ui.uiscale self._my_replays_rename_window = cnt = ba.containerwidget( scale=(1.8 if uiscale is ba.UIScale.SMALL else 1.55 if uiscale is ba.UIScale.MEDIUM else 1.0), diff --git a/docs/ba_module.md b/docs/ba_module.md index 29e8a007..4d050df1 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-21 for Ballistica version 1.5.23 build 20149

    +

    last updated on 2020-07-21 for Ballistica version 1.5.23 build 20150

    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!


    @@ -806,7 +806,7 @@ likely result in errors.

    Attributes:

    -
    api_version, build_number, config, config_file_path, debug_build, language, locale, on_tv, platform, python_directory_app, python_directory_app_site, python_directory_user, subplatform, test_build, ui_bounds, uiscale, user_agent_string, version, vr_mode
    +
    api_version, build_number, config, config_file_path, debug_build, language, locale, on_tv, platform, python_directory_app, python_directory_app_site, python_directory_user, subplatform, test_build, ui_bounds, user_agent_string, version, vr_mode

    api_version

    int

    @@ -912,11 +912,6 @@ likely result in errors.

    This tuple contains: (x-min, x-max, y-min, y-max)

    -
    -

    uiscale

    -

    ba.UIScale

    -

    Current ui scale for the app.

    -

    user_agent_string

    str

    From 42c7bb17f53ee06f83f8c0bd1a2b562acee77f71 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 21 Jul 2020 17:05:51 -0700 Subject: [PATCH 168/417] Cleaning up controllers UI --- .efrocachemap | 24 ++++++++--------- CHANGELOG.md | 1 + assets/src/ba_data/python/_ba.py | 8 ++++++ .../python/bastd/ui/settings/allsettings.py | 2 +- .../python/bastd/ui/settings/controls.py | 26 +++++++++---------- 5 files changed, 35 insertions(+), 26 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index b38e80e7..12fe1448 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/b6/f3/a034a7393edf52eefe644e6aa642", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5d/e2/c45ee46dc39c32aa4bff0d50ef2c", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/25/3d/f3cce76ed1c66e39b6e07d199696", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cf/8b/5c09d999c0d6b160e34d69f1f710", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c7/b6/18b0280b4c99aaf48fb3bfcc4fac", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/65/dd50a2026be7df75e3d280a2efc3", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/4e/f6a184076ad4676ad6b4cf9d4d01", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/20/d9/f86cd5d9fb67183e0a2ceda0e897", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e4/da/0b43bb125048696f4514eaca1e56", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d6/46/d0e647509453bc2125ccbe7eba09", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c2/a8/fee89fe0a3d76489b5b26a2c5fac", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/70/d5/86c8bdb5cf1dd15d9b9a0c7490da" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ff/36/ca09cc3913ae40382d73340f62ab", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/30/613d0c5acf97d7eb7770c4138a3b", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cb/58/e668468c6ebe7b3b1bacc7079f16", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/93/215ba8579ffc8bc5fc67aa6d1bfc", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/c5/b0be277a5324eccf97218644f429", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7c/f3/f82f3a29652ed279447dc5b1c4a5", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/21/aa/312efa59677ebd9a97b8f7f48796", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/de/c926cf39c972f1084762c917bb9c", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/bb/bfb59d70d101eefd14987007225d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/df/d3/3e91ec5117fe359c2e94818b9788", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/c0/cad3a08df13d190bbeff26bb901f", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ea/28/efe665eddea710871da829ad2dce" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f058c78..228961d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Added 'claims_left_right' and 'claims_tab' to ba.hscrollwidget(). - Default widget 'show_buffer' is now 20 instead of 0 (causes scrolling to stay slightly ahead of widget selection). This can be overridden with the ba.widget() call if anything breaks. - Relocated ba.app.uiscale to ba.app.ui.uiscale +- Top level settings window now properly saves/restores its state again. ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index bbffcfcb..9ead9791 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -2819,6 +2819,14 @@ def is_running_on_ouya() -> bool: return bool() +def is_xcode_build() -> bool: + """is_xcode_build() -> bool + + (internal) + """ + return bool() + + def lock_all_input() -> None: """lock_all_input() -> None diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index 1097f6da..0488ce79 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -58,7 +58,6 @@ class AllSettingsWindow(ba.Window): width = 900 if uiscale is ba.UIScale.SMALL else 580 x_inset = 75 if uiscale is ba.UIScale.SMALL else 0 height = 435 - # button_height = 42 self._r = 'settingsWindow' top_extra = 20 if uiscale is ba.UIScale.SMALL else 0 @@ -204,6 +203,7 @@ class AllSettingsWindow(ba.Window): color=(0.8, 0.95, 1), texture=ba.gettexture('advancedIcon'), draw_controller=avb) + self._restore_state() @staticmethod def _preload_modules() -> None: diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index 6fcc2e5b..0e6d0fd9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -64,12 +64,12 @@ class ControlsSettingsWindow(ba.Window): spacing = 50.0 button_width = 350.0 width = 460.0 - height = 85.0 + height = 130.0 space_height = spacing * 0.3 # FIXME: should create vis settings in platform for these, - # not hard code them here.. + # not hard code them here. show_gamepads = False platform = app.platform @@ -93,7 +93,7 @@ class ControlsSettingsWindow(ba.Window): show_keyboard = False if _ba.getinputdevice('Keyboard', '#1', doraise=False) is not None: show_keyboard = True - height += spacing * 2 + height += spacing show_keyboard_p2 = False if app.vr_mode else show_keyboard if show_keyboard_p2: height += spacing @@ -120,26 +120,25 @@ class ControlsSettingsWindow(ba.Window): # height += spacing show_mac_wiimote = False - if platform == 'mac' and subplatform == 'appstore': - show_mac_wiimote = True - height += spacing + # if platform == 'mac' and _ba.is_xcode_build(): + # show_mac_wiimote = True + # height += spacing - # on non-oculus-vr windows, show an option to disable xinput + # On windows (outside of oculus/vr), show an option to disable xinput. show_xinput_toggle = False - if platform == 'windows' and (subplatform != 'oculus' - or not app.vr_mode): + if platform == 'windows' and not app.vr_mode: show_xinput_toggle = True - # on mac builds, show an option to switch between generic and + # On mac builds, show an option to switch between generic and # made-for-iOS/Mac systems # (we can run into problems where devices register as one of each # type otherwise).. show_mac_controller_subsystem = False - if platform == 'mac' and subplatform == 'appstore': + if platform == 'mac' and _ba.is_xcode_build(): show_mac_controller_subsystem = True if show_mac_controller_subsystem: - height += spacing + height += spacing * 1.5 if show_xinput_toggle: height += spacing @@ -150,6 +149,7 @@ class ControlsSettingsWindow(ba.Window): size=(width, height), transition=transition, scale_origin_stack_offset=scale_origin, + stack_offset=((0, -10) if uiscale is ba.UIScale.SMALL else (0, 0)), scale=(smallscale if uiscale is ba.UIScale.SMALL else 1.5 if uiscale is ba.UIScale.MEDIUM else 1.0))) self._back_button = btn = ba.buttonwidget( @@ -381,7 +381,7 @@ class ControlsSettingsWindow(ba.Window): v_align='center', color=ba.app.ui.infotextcolor, maxwidth=width * 0.8) - v -= spacing + v -= spacing * 1.5 self._restore_state() def _set_mac_controller_subsystem(self, val: str) -> None: From ac174e45a5781cce2df3faa097a695ba7805903a Mon Sep 17 00:00:00 2001 From: Benefit-Zebra <42458260+Benefit-Zebra@users.noreply.github.com> Date: Wed, 22 Jul 2020 11:46:00 +0530 Subject: [PATCH 169/417] Added Standard Emojis --- .../python/bastd/ui/onscreenkeyboard.py | 84 ++++++++++++------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 7f60ff3f..a5d0fec1 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -261,38 +261,60 @@ class OnScreenKeyboardWindow(ba.Window): elif self._mode in ['emoji', 'emoji2']: chars = [ - '🙂', '😄', '😆', '😅', '😂', '☺', '😀', '😉', '😇', 'ðŸ˜', '😘', '😎', - 'ðŸ˜', '😛', '😜', 'ðŸ˜', 'ðŸ˜', '😑', '😢', '😵', '😬', '😌', '😔', '😡', - '😴', '😷' - ] + '💣', + '💥', + '🙂', + '😄', + '😆', + '😅', + '😂', + '☺', + '😀', + '😉', + '😇', + '😎', + '😰', + '😠', + '😈', + '😨', + '😛', + '😜', + 'ðŸ˜', + 'ðŸ˜', + '😑', + '😵', + '😬', + '😡', + '😌', + 'ðŸ˜'] if self._mode == 'emoji2': chars = [ - charstr(SpCh.LOGO_FLAT), - charstr(SpCh.UP_ARROW), - charstr(SpCh.DOWN_ARROW), - charstr(SpCh.LEFT_ARROW), - charstr(SpCh.RIGHT_ARROW), - charstr(SpCh.DELETE), - charstr(SpCh.BACK), - charstr(SpCh.TICKET), - charstr(SpCh.PARTY_ICON), - charstr(SpCh.LOCAL_ACCOUNT), - charstr(SpCh.FEDORA), - charstr(SpCh.HAL), - charstr(SpCh.CROWN), - charstr(SpCh.YIN_YANG), - charstr(SpCh.EYE_BALL), - charstr(SpCh.SKULL), - charstr(SpCh.HEART), - charstr(SpCh.DRAGON), - charstr(SpCh.HELMET), - charstr(SpCh.MUSHROOM), - charstr(SpCh.NINJA_STAR), - charstr(SpCh.VIKING_HELMET), - charstr(SpCh.MOON), - charstr(SpCh.SPIDER), - charstr(SpCh.FIREBALL), - charstr(SpCh.MIKIROG)] + '😔', + '😥', + '😭', + '😖', + '😓', + '😉', + '😴', + '😷', + '👋', + '💯', + 'ðŸ™', + '💪', + '👀', + '💬', + '💀', + '☠', + '💩', + '👻', + '👽', + '👾', + 'â¤', + '💛', + '💚', + '💙', + '💜', + '💔'] ba.buttonwidget(edit=self._shift_button, color=self._key_color_lit if self._mode == 'emoji2' else self._key_color_dark, @@ -368,7 +390,7 @@ class OnScreenKeyboardWindow(ba.Window): ba.textwidget(edit=self._text_field, text=txt) # if we were caps, # go back only if not Shift is pressed twice - if self._mode == 'caps' and self._double_press_shift != True: + if self._mode == 'caps' and not self._double_press_shift: self._mode = 'normal' self._refresh() From 0356b0b0e08f54514417711f769c1c569bdb50ac Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 21 Jul 2020 23:27:41 -0700 Subject: [PATCH 170/417] More work on plugins --- .efrocachemap | 24 +++++----- .idea/dictionaries/ericf.xml | 3 ++ assets/.asset_manifest_public.json | 2 + assets/Makefile | 2 + assets/src/ba_data/python/ba/__init__.py | 1 + assets/src/ba_data/python/ba/_app.py | 6 ++- assets/src/ba_data/python/ba/_meta.py | 43 ++++++++++++----- assets/src/ba_data/python/ba/_plugin.py | 48 +++++++++++++++++++ assets/src/ba_data/python/bastd/gameutils.py | 10 ++++ .../python/bastd/ui/settings/controls.py | 2 +- .../python/bastd/ui/settings/plugins.py | 30 ++++++++++-- docs/ba_module.md | 29 ++++++++++- 12 files changed, 170 insertions(+), 30 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_plugin.py diff --git a/.efrocachemap b/.efrocachemap index 12fe1448..23462ceb 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/ff/36/ca09cc3913ae40382d73340f62ab", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ca/30/613d0c5acf97d7eb7770c4138a3b", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/cb/58/e668468c6ebe7b3b1bacc7079f16", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3a/93/215ba8579ffc8bc5fc67aa6d1bfc", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a1/c5/b0be277a5324eccf97218644f429", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7c/f3/f82f3a29652ed279447dc5b1c4a5", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/21/aa/312efa59677ebd9a97b8f7f48796", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7c/de/c926cf39c972f1084762c917bb9c", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bd/bb/bfb59d70d101eefd14987007225d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/df/d3/3e91ec5117fe359c2e94818b9788", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/20/c0/cad3a08df13d190bbeff26bb901f", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ea/28/efe665eddea710871da829ad2dce" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/e9/3cc27e1957894e2926093efaf419", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cc/6d/523557326436bb1f2c79b40db30f", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/59/b5/cd299564c2795a47f19253121289", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/90/15/400a238c241f4baaf593338c2f0e", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/17/9c657df88fcf1aa529a6d57c1c63", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2c/14/4af6ef9f9452c10d3dbc7b864045", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/11/05/2d5de66e04958be2440d10c96694", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/89/c8/2e9218badd4259e480c3b3315bf6", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/7b/173c424cd6548670163304241161", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/d9/52268ba89bf9e6821fd95d4b6852", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e3/49/f6b920cf41705a40f7c00ad2cd26", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d4/9f/365187c2ebdeffdfba74a35cf4f7" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 30c2303d..c1bf311e 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -137,6 +137,7 @@ autoretain autoselect autotools + availplug aval axismotion bacfg @@ -628,6 +629,7 @@ extrascale exts factoryclass + fakemodule fallbacks farthestpt fback @@ -1452,6 +1454,7 @@ plpt plst pluglist + plugstates plusbutton plvel pmats diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index d675bd70..969b9ca3 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -41,6 +41,7 @@ "ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/_plugin.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc", "ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc", @@ -99,6 +100,7 @@ "ba_data/python/ba/_nodeactor.py", "ba_data/python/ba/_player.py", "ba_data/python/ba/_playlist.py", + "ba_data/python/ba/_plugin.py", "ba_data/python/ba/_powerup.py", "ba_data/python/ba/_profile.py", "ba_data/python/ba/_score.py", diff --git a/assets/Makefile b/assets/Makefile index 76796b24..2cbf1ee8 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -190,6 +190,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_nodeactor.py \ build/ba_data/python/ba/_player.py \ build/ba_data/python/ba/_playlist.py \ + build/ba_data/python/ba/_plugin.py \ build/ba_data/python/ba/_powerup.py \ build/ba_data/python/ba/_profile.py \ build/ba_data/python/ba/_score.py \ @@ -423,6 +424,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_plugin.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 863ea29c..88e53a3e 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -38,6 +38,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, set_analytics_screen, charstr, textwidget, time, timer, open_url, widget) from ba._activity import Activity +from ba._plugin import AvailablePlugin, Plugin from ba._actor import Actor from ba._player import PlayerInfo, Player, EmptyPlayer, StandLocation from ba._nodeactor import NodeActor diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 4c136eeb..e06e3903 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -37,7 +37,7 @@ if TYPE_CHECKING: class App: """A class for high level app functionality and state. - category: App Classes + Category: App Classes Use ba.app to access the single shared instance of this class. @@ -305,6 +305,10 @@ class App: self.headless_build: bool = env['headless_build'] assert isinstance(self.headless_build, bool) + # Plugins. + self.loaded_plugins: List[ba.Plugin] = [] + self.available_plugins: List[ba.AvailablePlugin] = [] + # Misc. self.default_language = self._get_default_language() self.metascan: Optional[_meta.ScanResults] = None diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index 49a01a44..c67bcca9 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -45,6 +45,7 @@ CURRENT_API_VERSION = 6 class ScanResults: """Final results from a metadata scan.""" games: List[str] = field(default_factory=list) + plugins: List[str] = field(default_factory=list) errors: str = '' warnings: str = '' @@ -64,6 +65,8 @@ def start_scan() -> None: def handle_scan_results(results: ScanResults) -> None: """Called in the game thread with results of a completed scan.""" + from ba._lang import Lstr + # Warnings generally only get printed locally for users' benefit # (things like out-of-date scripts being ignored, etc.) # Errors are more serious and will get included in the regular log @@ -71,7 +74,6 @@ def handle_scan_results(results: ScanResults) -> None: # errors = results.get('errors', '') if results.warnings != '' or results.errors != '': import textwrap - from ba._lang import Lstr _ba.screenmessage(Lstr(resource='scanScriptsErrorText'), color=(1, 0, 0)) _ba.playsound(_ba.getsound('error')) @@ -81,6 +83,31 @@ def handle_scan_results(results: ScanResults) -> None: if results.errors != '': _ba.log(textwrap.indent(results.errors, 'Error (meta-scan): ')) + # Handle plugins. + config_changed = False + found_new = False + plugstates: Dict[str, Dict] = _ba.app.config.setdefault('Plugins', {}) + if not isinstance(plugstates, dict): + print('Warning; found non-dict for "Plugins" in config.') + plugstates = {} + config_changed = True + + for plug in results.plugins: + if plug not in plugstates: + print('found new plugin:', plug) + plugstates[plug] = {'enabled': False} + config_changed = True + found_new = True + + if found_new: + _ba.screenmessage(Lstr(resource='pluginsDetectedText'), + color=(0, 1, 0)) + _ba.playsound(_ba.getsound('ding')) + + if config_changed: + _ba.app.config.commit() + # print(f'would check {len(results.plugins)} plugs') + class ScanThread(threading.Thread): """Thread to scan script dirs for metadata.""" @@ -90,7 +117,7 @@ class ScanThread(threading.Thread): self._dirs = dirs def run(self) -> None: - from ba import _general + from ba._general import Call try: scan = DirectoryScan(self._dirs) scan.scan() @@ -100,7 +127,7 @@ class ScanThread(threading.Thread): # Push a call to the game thread to print warnings/errors # or otherwise deal with scan results. - _ba.pushcall(_general.Call(handle_scan_results, results), + _ba.pushcall(Call(handle_scan_results, results), from_other_thread=True) # We also, however, immediately make results available. @@ -117,14 +144,6 @@ class DirectoryScan: It is assumed that these paths are also in PYTHONPATH. It is also assumed that any subdirectories are Python packages. - The returned dict contains the following: - 'powerups': list of ba.Powerup classes found. - 'campaigns': list of ba.Campaign classes found. - 'modifiers': list of ba.Modifier classes found. - 'maps': list of ba.Map classes found. - 'games': list of ba.GameActivity classes found. - 'warnings': warnings from scan; should be printed for local feedback - 'errors': errors encountered during scan; should be fully logged """ # Skip non-existent paths completely. @@ -251,6 +270,8 @@ class DirectoryScan: classname = modulename + '.' + export_class_name if exporttype == 'game': self.results.games.append(classname) + elif exporttype == 'plugin': + self.results.plugins.append(classname) else: self.results.warnings += ( 'Warning: ' + str(subpath) + diff --git a/assets/src/ba_data/python/ba/_plugin.py b/assets/src/ba_data/python/ba/_plugin.py new file mode 100644 index 00000000..146d7a7f --- /dev/null +++ b/assets/src/ba_data/python/ba/_plugin.py @@ -0,0 +1,48 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Plugin related functionality.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING +from dataclasses import dataclass + +if TYPE_CHECKING: + pass + + +@dataclass +class AvailablePlugin: + """Defines a plugin which can potentially be loaded. + + Category: App Classes + """ + display_name: str + class_path: str + + +class Plugin: + """A plugin to alter app behavior in some way. + + Category: App Classes + """ + + name: str diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py index de34b2bd..d756995a 100644 --- a/assets/src/ba_data/python/bastd/gameutils.py +++ b/assets/src/ba_data/python/bastd/gameutils.py @@ -161,3 +161,13 @@ class SharedObjects: ), ) return self._railing_material + + +# ba _meta export plugin +class TestPlug1(ba.Plugin): + """Just Testing.""" + + +# ba _meta export plugin +class TestPlug2(ba.Plugin): + """Just Testing 2.""" diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index 0e6d0fd9..fab4c9bc 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -164,7 +164,7 @@ class ControlsSettingsWindow(ba.Window): on_activate_call=self._back) ba.containerwidget(edit=self._root_widget, cancel_button=btn) - # need these vars to exist even if the buttons don't + # We need these vars to exist even if the buttons don't. self._gamepads_button: Optional[ba.Widget] = None self._touch_button: Optional[ba.Widget] = None self._keyboard_button: Optional[ba.Widget] = None diff --git a/assets/src/ba_data/python/bastd/ui/settings/plugins.py b/assets/src/ba_data/python/bastd/ui/settings/plugins.py index c550f6a6..6e73646a 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/plugins.py +++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py @@ -33,9 +33,13 @@ if TYPE_CHECKING: class PluginSettingsWindow(ba.Window): """Window for configuring plugins.""" + def __del__(self) -> None: + print('~PluginSettingsWindow()') + def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): + print('PluginSettingsWindow()') app = ba.app @@ -111,11 +115,22 @@ class PluginSettingsWindow(ba.Window): self._subcontainer = ba.columnwidget(parent=self._scrollwidget, selection_loops_to_parent=True) - pluglist = [f'Test {i}' for i in range(10)] - for i, plug in enumerate(pluglist): + pluglist = [ + ba.AvailablePlugin(display_name=f'Test {i}', + class_path='fakemodule') for i in range(10) + ] + for i, availplug in enumerate(pluglist): + active = i % 3 < 2 check = ba.checkboxwidget(parent=self._subcontainer, - text=plug, - size=(self._scroll_width - 40, 50)) + text=availplug.display_name, + value=active, + maxwidth=self._scroll_width - 100, + size=(self._scroll_width - 40, 50), + on_value_change_call=ba.Call( + self._check_value_changed, + availplug), + textcolor=((0, 1, 0) if active else + (0.6, 0.6, 0.6))) # Make sure we scroll all the way to the end when using # keyboard/button nav. @@ -129,6 +144,13 @@ class PluginSettingsWindow(ba.Window): self._restore_state() + def _check_value_changed(self, plug: ba.AvailablePlugin, + value: bool) -> None: + ba.screenmessage( + ba.Lstr(resource='settingsWindowAdvanced.mustRestartText'), + color=(1.0, 0.5, 0.0)) + print(f'check value changed for {plug} to {value}') + def _save_state(self) -> None: pass diff --git a/docs/ba_module.md b/docs/ba_module.md index 4d050df1..6ff42acd 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-21 for Ballistica version 1.5.23 build 20150

    +

    last updated on 2020-07-21 for Ballistica version 1.5.23 build 20151

    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!


    @@ -150,8 +150,10 @@
  • ba.App
  • ba.AppConfig
  • ba.AppDelegate
  • +
  • ba.AvailablePlugin
  • ba.Campaign
  • ba.MusicPlayer
  • +
  • ba.Plugin
  • ba.ServerController
  • User Interface Classes

    @@ -1164,6 +1166,22 @@ when done.

    Behavior is similar to ba.gettexture()

    +
    +
    +
    +

    ba.AvailablePlugin

    +

    <top level class> +

    +

    Defines a plugin which can potentially be loaded.

    + +

    Category: App Classes +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.AvailablePlugin(display_name: str, class_path: str)

    +

    @@ -4485,6 +4503,15 @@ the type-checker properly identifies the returned value as one.

    +
    +

    ba.Plugin

    +

    <top level class> +

    +

    A plugin to alter app behavior in some way.

    + +

    Category: App Classes +

    +

    ba.PowerupAcceptMessage

    <top level class> From 78bfd1241c23e980b1b80d5959ff1ffa9a89e47c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 21 Jul 2020 23:50:10 -0700 Subject: [PATCH 171/417] lint and tidying --- CHANGELOG.md | 4 +- .../python/bastd/ui/onscreenkeyboard.py | 65 ++++--------------- 2 files changed, 13 insertions(+), 56 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index def8e616..63563696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,8 +12,8 @@ - Default widget 'show_buffer' is now 20 instead of 0 (causes scrolling to stay slightly ahead of widget selection). This can be overridden with the ba.widget() call if anything breaks. - Relocated ba.app.uiscale to ba.app.ui.uiscale - Top level settings window now properly saves/restores its state again. -- BombSquad now has its own Exclusive Emojis in the Internal Game Keyboard. -- Added continuos CAPITAL letters typing feature in the Internal Game Keyboard. +- Added Emojis to the Internal Game Keyboard. +- Added continuous CAPITAL letters typing feature in the Internal Game Keyboard. ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index a5d0fec1..a87af751 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -38,6 +38,7 @@ class OnScreenKeyboardWindow(ba.Window): def __init__(self, textwidget: ba.Widget, label: str, max_chars: int): # pylint: disable=too-many-locals + # pylint: disable=too-many-statements self._target_text = textwidget self._width = 700 self._height = 400 @@ -261,63 +262,19 @@ class OnScreenKeyboardWindow(ba.Window): elif self._mode in ['emoji', 'emoji2']: chars = [ - '💣', - '💥', - '🙂', - '😄', - '😆', - '😅', - '😂', - '☺', - '😀', - '😉', - '😇', - '😎', - '😰', - '😠', - '😈', - '😨', - '😛', - '😜', - 'ðŸ˜', - 'ðŸ˜', - '😑', - '😵', - '😬', - '😡', - '😌', - 'ðŸ˜'] + '💣', '💥', '🙂', '😄', '😆', '😅', '😂', '☺', '😀', '😉', '😇', '😎', + '😰', '😠', '😈', '😨', '😛', '😜', 'ðŸ˜', 'ðŸ˜', '😑', '😵', '😬', '😡', + '😌', 'ðŸ˜' + ] if self._mode == 'emoji2': chars = [ - '😔', - '😥', - '😭', - '😖', - '😓', - '😉', - '😴', - '😷', - '👋', - '💯', - 'ðŸ™', - '💪', - '👀', - '💬', - '💀', - '☠', - '💩', - '👻', - '👽', - '👾', - 'â¤', - '💛', - '💚', - '💙', - '💜', - '💔'] + '😔', '😥', '😭', '😖', '😓', '😉', '😴', '😷', '👋', '💯', 'ðŸ™', '💪', + '👀', '💬', '💀', '☠', '💩', '👻', '👽', '👾', 'â¤', '💛', '💚', '💙', + '💜', '💔' + ] ba.buttonwidget(edit=self._shift_button, - color=self._key_color_lit - if self._mode == 'emoji2' else self._key_color_dark, + color=self._key_color_lit if self._mode == 'emoji2' + else self._key_color_dark, label=charstr(SpCh.SHIFT), on_activate_call=self._emoji_mode_2) ba.buttonwidget(edit=self._emoji_button, From a25abc809f5790243032251590de7823968871a4 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 21 Jul 2020 23:54:11 -0700 Subject: [PATCH 172/417] Syncing latest changes between public/private. --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 228961d5..63563696 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ - Default widget 'show_buffer' is now 20 instead of 0 (causes scrolling to stay slightly ahead of widget selection). This can be overridden with the ba.widget() call if anything breaks. - Relocated ba.app.uiscale to ba.app.ui.uiscale - Top level settings window now properly saves/restores its state again. +- Added Emojis to the Internal Game Keyboard. +- Added continuous CAPITAL letters typing feature in the Internal Game Keyboard. ### 1.5.22 (20139) - Button and key names now display correctly again on Android (and are cleaned up on other platforms too). From 49e4da8b4fd571c19499a547efdbe1ddc2d07f79 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 22 Jul 2020 02:48:51 -0700 Subject: [PATCH 173/417] v1.5.23 --- .efrocachemap | 24 ++++---- .idea/dictionaries/ericf.xml | 4 ++ CHANGELOG.md | 4 +- assets/src/ba_data/python/ba/__init__.py | 2 +- assets/src/ba_data/python/ba/_app.py | 43 +++++++++++++- assets/src/ba_data/python/ba/_meta.py | 35 +++++++++--- assets/src/ba_data/python/ba/_plugin.py | 22 +++++-- assets/src/ba_data/python/bastd/gameutils.py | 10 ---- .../python/bastd/ui/settings/plugins.py | 53 +++++++++-------- docs/ba_module.md | 57 ++++++++++++------- 10 files changed, 171 insertions(+), 83 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 23462ceb..ae607fc4 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/26/e9/3cc27e1957894e2926093efaf419", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cc/6d/523557326436bb1f2c79b40db30f", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/59/b5/cd299564c2795a47f19253121289", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/90/15/400a238c241f4baaf593338c2f0e", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4a/17/9c657df88fcf1aa529a6d57c1c63", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2c/14/4af6ef9f9452c10d3dbc7b864045", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/11/05/2d5de66e04958be2440d10c96694", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/89/c8/2e9218badd4259e480c3b3315bf6", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/7e/7b/173c424cd6548670163304241161", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/bc/d9/52268ba89bf9e6821fd95d4b6852", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e3/49/f6b920cf41705a40f7c00ad2cd26", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d4/9f/365187c2ebdeffdfba74a35cf4f7" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b2/16/0414b009ce117f73bb2bc8991d3b", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/07/d82a3ec80ff3243321e373439210", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/5f/f87158c3281a2616897fdd2165cb", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/69/23/a2d029f81db60cf89ad5f6510ddb", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/e3/5aba369252ed1977be8950e5a1ce", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/ef/c28554f863485e9cd54f0d8d4e6f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/af/f060b3463bc31c202a830fb0b20a", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/96/46/a239821d00e782303077192817c5", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dc/15/fdd9195afe2bf299405ec49ed238", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/f9/c42b1f9b5af34cb371f80250e16b", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5d/9b/213c602a9aa9cbc28872d2753f51", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2f/a4/e6a6a6e0e2b64c5232cccddffdd3" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index c1bf311e..9bcbca70 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -570,6 +570,7 @@ elim emitfx emoji + emojis enablexinput ename encerr @@ -1453,7 +1454,10 @@ plistname plpt plst + plugkey + plugkeys pluglist + plugstate plugstates plusbutton plvel diff --git a/CHANGELOG.md b/CHANGELOG.md index 63563696..e7a1696f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. - Fixed a bug with hardware keyboards emitting extra characters in the in-game console (~ or F2) - Added support for 'plugin' mods and user controls to configure them in settings->advanced->plugins. -- renamed selection_loop_to_parent to selection_loops_to_parent in widget calls. +- Renamed selection_loop_to_parent to selection_loops_to_parent in widget calls. - Added 'selection_loops_to_parent', 'border', 'margin', 'claims_left_right', and 'claims_tab' args to ba.columnwidget(). - Column-widget now has a default 'border' of 0 (explicitly pass 2 to get the old look). - Column-widget now has a default 'margin' of 10 (explicitly pass 0 to get the old look). @@ -10,7 +10,7 @@ - Added 'selection_loops_to_parent', 'claims_left_right', and 'claims_tab' args to ba.rowwidget. - Added 'claims_left_right' and 'claims_tab' to ba.hscrollwidget(). - Default widget 'show_buffer' is now 20 instead of 0 (causes scrolling to stay slightly ahead of widget selection). This can be overridden with the ba.widget() call if anything breaks. -- Relocated ba.app.uiscale to ba.app.ui.uiscale +- Relocated ba.app.uiscale to ba.app.ui.uiscale. - Top level settings window now properly saves/restores its state again. - Added Emojis to the Internal Game Keyboard. - Added continuous CAPITAL letters typing feature in the Internal Game Keyboard. diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 88e53a3e..6fa61a4c 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -38,7 +38,7 @@ from _ba import (CollideModel, Context, ContextCall, Data, InputDevice, set_analytics_screen, charstr, textwidget, time, timer, open_url, widget) from ba._activity import Activity -from ba._plugin import AvailablePlugin, Plugin +from ba._plugin import PotentialPlugin, Plugin from ba._actor import Actor from ba._player import PlayerInfo, Player, EmptyPlayer, StandLocation from ba._nodeactor import NodeActor diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index e06e3903..d3265d40 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -306,8 +306,8 @@ class App: assert isinstance(self.headless_build, bool) # Plugins. - self.loaded_plugins: List[ba.Plugin] = [] - self.available_plugins: List[ba.AvailablePlugin] = [] + self.potential_plugins: List[ba.PotentialPlugin] = [] + self.active_plugins: Dict[str, ba.Plugin] = {} # Misc. self.default_language = self._get_default_language() @@ -411,6 +411,7 @@ class App: (internal)""" # pylint: disable=too-many-locals # pylint: disable=cyclic-import + # pylint: disable=too-many-statements from ba import _apputils from ba import _appconfig from ba import _achievement @@ -520,11 +521,49 @@ class App: _ba.pushcall(do_auto_sign_in) + # Load up our plugins and go ahead and call their on_app_launch calls. + self.load_plugins() + for plugin in self.active_plugins.values(): + try: + plugin.on_app_launch() + except Exception: + from ba import _error + _error.print_exception('Error in plugin on_app_launch()') + self.ran_on_app_launch = True # from ba._dependency import test_depset # test_depset() + def load_plugins(self) -> None: + """(internal)""" + from ba._general import getclass + from ba._plugin import Plugin + + # Note: the plugins we load is purely based on what's enabled + # in the app config. Our meta-scan gives us a list of available + # plugins, but that is only used to give the user a list of plugins + # that they can enable. (we wouldn't want to look at meta-scan here + # anyway because it may not be done yet at this point in the launch) + plugstates: Dict[str, Dict] = self.config.get('Plugins', {}) + assert isinstance(plugstates, dict) + plugkeys: List[str] = sorted(key for key, val in plugstates.items() + if val.get('enabled', False)) + for plugkey in plugkeys: + try: + cls = getclass(plugkey, Plugin) + except Exception as exc: + _ba.log(f"Error loading plugin class '{plugkey}': {exc}", + to_server=False) + continue + try: + plugin = cls() + assert plugkey not in self.active_plugins + self.active_plugins[plugkey] = plugin + except Exception: + from ba import _error + _error.print_exception(f'Error loading plugin: {plugkey}') + def read_config(self) -> None: """(internal)""" from ba import _appconfig diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index c67bcca9..ecc5d727 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -66,6 +66,7 @@ def handle_scan_results(results: ScanResults) -> None: """Called in the game thread with results of a completed scan.""" from ba._lang import Lstr + from ba._plugin import PotentialPlugin # Warnings generally only get printed locally for users' benefit # (things like out-of-date scripts being ignored, etc.) @@ -87,18 +88,32 @@ def handle_scan_results(results: ScanResults) -> None: config_changed = False found_new = False plugstates: Dict[str, Dict] = _ba.app.config.setdefault('Plugins', {}) - if not isinstance(plugstates, dict): - print('Warning; found non-dict for "Plugins" in config.') - plugstates = {} - config_changed = True + assert isinstance(plugstates, dict) - for plug in results.plugins: - if plug not in plugstates: - print('found new plugin:', plug) - plugstates[plug] = {'enabled': False} + # Create a potential-plugin for each class we found in the scan. + for class_path in results.plugins: + _ba.app.potential_plugins.append( + PotentialPlugin(display_name=Lstr(value=class_path), + class_path=class_path, + available=True)) + if class_path not in plugstates: + plugstates[class_path] = {'enabled': False} config_changed = True found_new = True + # Also add a special one for any plugins set to load but *not* found + # in the scan (this way they will show up in the UI so we can disable them) + for class_path, plugstate in plugstates.items(): + enabled = plugstate.get('enabled', False) + assert isinstance(enabled, bool) + if enabled and class_path not in results.plugins: + _ba.app.potential_plugins.append( + PotentialPlugin(display_name=Lstr(value=class_path), + class_path=class_path, + available=False)) + + _ba.app.potential_plugins.sort(key=lambda p: p.class_path) + if found_new: _ba.screenmessage(Lstr(resource='pluginsDetectedText'), color=(0, 1, 0)) @@ -106,7 +121,6 @@ def handle_scan_results(results: ScanResults) -> None: if config_changed: _ba.app.config.commit() - # print(f'would check {len(results.plugins)} plugs') class ScanThread(threading.Thread): @@ -189,6 +203,9 @@ class DirectoryScan: self.results.warnings += ("Error scanning '" + str(subpath) + "': " + traceback.format_exc() + '\n') + # Sort our results + self.results.games.sort() + self.results.plugins.sort() def scan_module(self, moduledir: pathlib.Path, subpath: pathlib.Path) -> None: diff --git a/assets/src/ba_data/python/ba/_plugin.py b/assets/src/ba_data/python/ba/_plugin.py index 146d7a7f..51b9b077 100644 --- a/assets/src/ba_data/python/ba/_plugin.py +++ b/assets/src/ba_data/python/ba/_plugin.py @@ -26,23 +26,35 @@ from typing import TYPE_CHECKING from dataclasses import dataclass if TYPE_CHECKING: - pass + import ba @dataclass -class AvailablePlugin: - """Defines a plugin which can potentially be loaded. +class PotentialPlugin: + """Represents a ba.Plugin which can potentially be loaded. Category: App Classes + + These generally represent plugins which were detected by the + meta-tag scan. However they may also represent plugins which + were previously set to be loaded but which were unable to be + for some reason. In that case, 'available' will be set to False. """ - display_name: str + display_name: ba.Lstr class_path: str + available: bool class Plugin: """A plugin to alter app behavior in some way. Category: App Classes + + Plugins are discoverable by the meta-tag system + and the user can select which ones they want to activate. + Active plugins are then called at specific times as the + app is running in order to modify its behavior in some way. """ - name: str + def on_app_launch(self) -> None: + """Called when the app is being launched.""" diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py index d756995a..de34b2bd 100644 --- a/assets/src/ba_data/python/bastd/gameutils.py +++ b/assets/src/ba_data/python/bastd/gameutils.py @@ -161,13 +161,3 @@ class SharedObjects: ), ) return self._railing_material - - -# ba _meta export plugin -class TestPlug1(ba.Plugin): - """Just Testing.""" - - -# ba _meta export plugin -class TestPlug2(ba.Plugin): - """Just Testing 2.""" diff --git a/assets/src/ba_data/python/bastd/ui/settings/plugins.py b/assets/src/ba_data/python/bastd/ui/settings/plugins.py index 6e73646a..7b1993b1 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/plugins.py +++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py @@ -27,20 +27,16 @@ from typing import TYPE_CHECKING import ba if TYPE_CHECKING: - from typing import Tuple, Optional + from typing import Tuple, Optional, Dict class PluginSettingsWindow(ba.Window): """Window for configuring plugins.""" - def __del__(self) -> None: - print('~PluginSettingsWindow()') - def __init__(self, transition: str = 'in_right', origin_widget: ba.Widget = None): - print('PluginSettingsWindow()') - + # pylint: disable=too-many-locals app = ba.app # If they provided an origin-widget, scale up from that. @@ -115,22 +111,29 @@ class PluginSettingsWindow(ba.Window): self._subcontainer = ba.columnwidget(parent=self._scrollwidget, selection_loops_to_parent=True) - pluglist = [ - ba.AvailablePlugin(display_name=f'Test {i}', - class_path='fakemodule') for i in range(10) - ] + if ba.app.metascan is None: + ba.screenmessage('Still scanning plugins; please try again.', + color=(1, 0, 0)) + ba.playsound(ba.getsound('error')) + pluglist = ba.app.potential_plugins + plugstates: Dict[str, Dict] = ba.app.config.setdefault('Plugins', {}) + assert isinstance(plugstates, dict) for i, availplug in enumerate(pluglist): - active = i % 3 < 2 - check = ba.checkboxwidget(parent=self._subcontainer, - text=availplug.display_name, - value=active, - maxwidth=self._scroll_width - 100, - size=(self._scroll_width - 40, 50), - on_value_change_call=ba.Call( - self._check_value_changed, - availplug), - textcolor=((0, 1, 0) if active else - (0.6, 0.6, 0.6))) + active = availplug.class_path in ba.app.active_plugins + + plugstate = plugstates.setdefault(availplug.class_path, {}) + checked = plugstate.get('enabled', False) + assert isinstance(checked, bool) + check = ba.checkboxwidget( + parent=self._subcontainer, + text=availplug.display_name, + value=checked, + maxwidth=self._scroll_width - 100, + size=(self._scroll_width - 40, 50), + on_value_change_call=ba.Call(self._check_value_changed, + availplug), + textcolor=((0.8, 0.3, 0.3) if not availplug.available else + (0, 1, 0) if active else (0.6, 0.6, 0.6))) # Make sure we scroll all the way to the end when using # keyboard/button nav. @@ -144,12 +147,16 @@ class PluginSettingsWindow(ba.Window): self._restore_state() - def _check_value_changed(self, plug: ba.AvailablePlugin, + def _check_value_changed(self, plug: ba.PotentialPlugin, value: bool) -> None: ba.screenmessage( ba.Lstr(resource='settingsWindowAdvanced.mustRestartText'), color=(1.0, 0.5, 0.0)) - print(f'check value changed for {plug} to {value}') + plugstates: Dict[str, Dict] = ba.app.config.setdefault('Plugins', {}) + assert isinstance(plugstates, dict) + plugstate = plugstates.setdefault(plug.class_path, {}) + plugstate['enabled'] = value + ba.app.config.commit() def _save_state(self) -> None: pass diff --git a/docs/ba_module.md b/docs/ba_module.md index 6ff42acd..2c401f48 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-21 for Ballistica version 1.5.23 build 20151

    +

    last updated on 2020-07-22 for Ballistica version 1.5.23 build 20152

    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!


    @@ -150,10 +150,10 @@
  • ba.App
  • ba.AppConfig
  • ba.AppDelegate
  • -
  • ba.AvailablePlugin
  • ba.Campaign
  • ba.MusicPlayer
  • ba.Plugin
  • +
  • ba.PotentialPlugin
  • ba.ServerController
  • User Interface Classes

    @@ -1166,22 +1166,6 @@ when done.

    Behavior is similar to ba.gettexture()

    -
    -
    -
    -

    ba.AvailablePlugin

    -

    <top level class> -

    -

    Defines a plugin which can potentially be loaded.

    - -

    Category: App Classes -

    - -

    Methods:

    -
    -

    <constructor>

    -

    ba.AvailablePlugin(display_name: str, class_path: str)

    -

    @@ -4509,9 +4493,44 @@ the type-checker properly identifies the returned value as one.

    A plugin to alter app behavior in some way.

    -

    Category: App Classes +

    Category: App Classes

    + +

    Plugins are discoverable by the meta-tag system + and the user can select which ones they want to activate. + Active plugins are then called at specific times as the + app is running in order to modify its behavior in some way.

    +

    Methods:

    +
    +

    on_app_launch()

    +

    on_app_launch(self) -> None

    + +

    Called when the app is being launched.

    + +
    +
    +
    +

    ba.PotentialPlugin

    +

    <top level class> +

    +

    Represents a ba.Plugin which can potentially be loaded.

    + +

    Category: App Classes

    + +

    These generally represent plugins which were detected by the + meta-tag scan. However they may also represent plugins which + were previously set to be loaded but which were unable to be + for some reason. In that case, 'available' will be set to False. +

    + +

    Methods:

    +
    +

    <constructor>

    +

    ba.PotentialPlugin(display_name: ba.Lstr, class_path: str, available: bool)

    + +
    +

    ba.PowerupAcceptMessage

    <top level class> From 147c8ec66b1b02c20107ed045328c0c7b10ef884 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 26 Jul 2020 00:57:25 -0700 Subject: [PATCH 174/417] Prep for Python version upgrade --- .efrocachemap | 36 +-- .idea/dictionaries/ericf.xml | 2 + CHANGELOG.md | 3 + assets/src/ba_data/python/ba/_netutils.py | 8 +- assets/src/ba_data/python/bastd/actor/bomb.py | 9 +- assets/src/ba_data/python/bastd/ui/gather.py | 2 +- .../python/bastd/ui/settings/gamepad.py | 3 +- .../python/bastd/ui/settings/keyboard.py | 5 + docs/ba_module.md | 2 +- tools/batools/assetstaging.py | 5 +- tools/batools/pcommand.py | 7 +- tools/batools/updateproject.py | 4 +- tools/efro/util.py | 3 +- tools/efrotools/__init__.py | 5 +- tools/efrotools/code.py | 9 +- tools/efrotools/pcommand.py | 6 + tools/efrotools/pybuild.py | 235 ++++++++---------- tools/pcommand | 2 +- 18 files changed, 178 insertions(+), 168 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index ae607fc4..72d22bcb 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,8 +420,8 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/de/c0/7197e7658bef48309741dfaf86c7", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/30/8e/38c5f21b9251ea1111bed554035f", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/cd/7a/dcf7f0f9436884167abdcb126716", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a9/3c/63857b3f5f943205d7a5d8f8e476", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/ea/14/6485c200c717f82cca7c01dee0b3", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/a0/ca/b4e3c4ea2c76e462b7e657b2b1c2", @@ -436,22 +436,22 @@ "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/cb/10/5d94df639e3e0cb405711e1b907f", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", - "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/4d/4b/0790110201c9adb1b521e9a55e63", + "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a3/b6/8987b9fc6a7cb0f61364f567c901", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/ff/3f/f1c11e1f22454ceceb7b4d277a2a", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/bd/45/ffb2d9d9ce9578ae11de9bb5123d", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/e1/cc/13a4ba409b7d6f113f703be1aa8a", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/9c/e3/834faf6869f5cd175edd4a0244b9", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/e5/0a/6ee92ae2cb50f12eeb21059c6659", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/57/bb/33e8bd738c3ee97122186471be75", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/c9/6b/dadd4329de69d0b7bfe1aa5f31d6", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/73/ef/624000057ce55f5a511ba18fd433", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/82/7c/5363de81ac6823935098df95dc66", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/9d/fb/6c2feb78bdabbec049a71ba40d78", - "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/f1/00/c4ccd5969084505359e07f927b3a", + "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/96/96/b2e468ceec8800b7b0f1e1c5977c", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", "assets/build/ba_data/data/maps/courtyard.json": "https://files.ballistica.net/cache/ba1/03/38/344dd05bfef7bbdf464035ec5aa2", @@ -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/b2/16/0414b009ce117f73bb2bc8991d3b", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/66/07/d82a3ec80ff3243321e373439210", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/5f/f87158c3281a2616897fdd2165cb", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/69/23/a2d029f81db60cf89ad5f6510ddb", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c4/e3/5aba369252ed1977be8950e5a1ce", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f7/ef/c28554f863485e9cd54f0d8d4e6f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/68/af/f060b3463bc31c202a830fb0b20a", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/96/46/a239821d00e782303077192817c5", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/dc/15/fdd9195afe2bf299405ec49ed238", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/f9/c42b1f9b5af34cb371f80250e16b", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5d/9b/213c602a9aa9cbc28872d2753f51", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2f/a4/e6a6a6e0e2b64c5232cccddffdd3" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/05/00/2dd9723909746d8039c6bdf8cddb", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/62/6c310233f4b2c224a46914a4b78e", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0c/f8/d381993bd58c1f50f0da6d8e2be3", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/b5/d2ec28b09124404731b7f08008c8", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cb/82/4520a3fec142215ed0673a1811d9", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/0b/060333370a987cee92bdd081a8ca", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/11/31/9f1bb364db47563a1d86f0165549", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/11/62/4d784f02705e438f9bd519ff53f4", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8a/ff/abcf2602dc64f718408efeaf4d3a", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/04/2d/1f8c7ea677bae4cc7be8e967c344", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/b8/f19e24bd0e43ed9661ca62c10e6c", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/02/0b/d2fab33376bc7ae1c8797cae5c0f" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 9bcbca70..d45094c3 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1613,6 +1613,7 @@ pythonw pytree pytz + pyver qrcode qrencode qual @@ -1788,6 +1789,7 @@ simplesubclasses sincelaunch singledispatch + singledispatchmethod sirplus sitebuiltins skey diff --git a/CHANGELOG.md b/CHANGELOG.md index e7a1696f..8289ca3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.24 (20159) +- Misc bug fixes.. + ### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. - Fixed a bug with hardware keyboards emitting extra characters in the in-game console (~ or F2) diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index c414d7a4..72cf8dfe 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -56,7 +56,7 @@ def get_ip_address_type(addr: str) -> socket.AddressFamily: except OSError: pass if socket_type is None: - raise ValueError('addr seems to be neither v4 or v6: ' + str(addr)) + raise ValueError(f'addr seems to be neither v4 or v6: {addr}') return socket_type @@ -152,8 +152,10 @@ class ServerCallThread(threading.Thread): response_data = None # Ignore common network errors; note unexpected ones. - if isinstance(exc, (urllib.error.URLError, ConnectionError, - http.client.IncompleteRead)): + if isinstance( + exc, + (urllib.error.URLError, ConnectionError, + http.client.IncompleteRead, http.client.BadStatusLine)): pass elif isinstance(exc, OSError): if exc.errno == 10051: # Windows unreachable network error. diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index fd4fa485..4218666a 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -887,10 +887,11 @@ class Bomb(ba.Actor): def _handle_impact(self) -> None: node = ba.getcollision().opposingnode - # If we're an impact bomb and we came from this node, don't explode... - # alternately if we're hitting another impact-bomb from the same - # source, don't explode... - # try: + # If we're an impact bomb and we came from this node, don't explode. + # (otherwise we blow up on our own head when jumping). + # Alternately if we're hitting another impact-bomb from the same + # source, don't explode. (can cause accidental explosions if rapidly + # throwing/etc.) node_delegate = node.getdelegate(object) if node: if (self.bomb_type == 'impact' and diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index 5df5bf23..e98d6e96 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1673,7 +1673,7 @@ class GatherWindow(ba.Window): # Ignore harmless errors. if exc.errno in { errno.EHOSTUNREACH, errno.ENETUNREACH, - errno.EINVAL, errno.EPERM + errno.EINVAL, errno.EPERM, errno.EACCES }: pass elif exc.errno == 10022: diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index bdc9d4d9..fdfe2514 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -838,7 +838,8 @@ class AwaitGamepadInputWindow(ba.Window): assert isinstance(input_device, ba.InputDevice) # Update - we now allow *any* input device of this type. - if input_device.exists() and input_device.name == self._input.name: + if (self._input and input_device + and input_device.name == self._input.name): self._callback(self._capture_button, event, self) def _decrement(self) -> None: diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index 8ed9fc65..c68e5e3c 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -236,6 +236,11 @@ class ConfigKeyboardWindow(ba.Window): ba.containerwidget(edit=self._root_widget, transition='out_right') ba.playsound(ba.getsound('gunCocking')) + + # There's a chance the device disappeared; handle that gracefully. + if not self._input: + return + dst = get_input_device_config(self._input, default=False) dst2: Dict[str, Any] = dst[0][dst[1]] dst2.clear() diff --git a/docs/ba_module.md b/docs/ba_module.md index 2c401f48..b8d91550 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-22 for Ballistica version 1.5.23 build 20152

    +

    last updated on 2020-07-26 for Ballistica version 1.5.24 build 20158

    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!


    diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 1fa0ed07..8a281d81 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -30,7 +30,7 @@ import subprocess from functools import partial from typing import TYPE_CHECKING -from efrotools.pybuild import PYTHON_VERSION_MAJOR +from efrotools import PYVER if TYPE_CHECKING: from typing import Optional, List @@ -40,8 +40,7 @@ if TYPE_CHECKING: # Note: this means anyone wanting to modify .py files in a build # will need to wipe out the existing .pyc files first or the changes # will be ignored. -OPT_PYC_SUFFIX = ('cpython-' + PYTHON_VERSION_MAJOR.replace('.', '') + - '.opt-1.pyc') +OPT_PYC_SUFFIX = ('cpython-' + PYVER.replace('.', '') + '.opt-1.pyc') class Config: diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index b9248d75..a6cc67a0 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -43,6 +43,7 @@ def stage_server_file() -> None: import batools.build from efro.error import CleanError from efrotools import replace_one + from efrotools import PYVER if len(sys.argv) != 5: raise CleanError('Expected 3 args (mode, infile, outfile).') mode, infilename, outfilename = sys.argv[2], sys.argv[3], sys.argv[4] @@ -56,13 +57,15 @@ def stage_server_file() -> None: # Inject all available config values into the config file. batools.build.filter_server_config(str(PROJROOT), infilename, outfilename) + elif basename == 'ballisticacore_server.py': # Run Python in opt mode for release builds. with open(infilename) as infile: lines = infile.read().splitlines() if mode == 'release': - lines[0] = replace_one(lines[0], '#!/usr/bin/env python3.7', - '#!/usr/bin/env -S python3.7 -O') + lines[0] = replace_one(lines[0], + f'#!/usr/bin/env python{PYVER}', + f'#!/usr/bin/env -S python{PYVER} -O') with open(outfilename, 'w') as outfile: outfile.write('\n'.join(lines) + '\n') subprocess.run(['chmod', '+x', outfilename], check=True) diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index d1aede13..8b6cdb39 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -377,7 +377,7 @@ class Updater: def _check_python_file(self, fname: str) -> None: # pylint: disable=too-many-branches - from efrotools import get_public_license + from efrotools import get_public_license, PYVER with open(fname) as infile: contents = infile.read() lines = contents.splitlines() @@ -390,7 +390,7 @@ class Updater: if fname not in [ 'tools/devtool', 'tools/version_utils', 'tools/vmshell' ]: - if not contents.startswith('#!/usr/bin/env python3.7'): + if not contents.startswith(f'#!/usr/bin/env python{PYVER}'): print(f'{Clr.RED}Incorrect shebang (first line) for ' f'{fname}.{Clr.RST}') sys.exit(255) diff --git a/tools/efro/util.py b/tools/efro/util.py index 5ce9a3c3..906f17d1 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -115,9 +115,10 @@ def dispatchmethod( # All we do here is recreate the end of functools.singledispatch # where it returns a wrapper except instead of the wrapper using the # first arg to the function ours uses the second (to skip 'self'). - # This was made with Python 3.7; we should probably check up on + # This was made against Python 3.7; we should probably check up on # this in later versions in case anything has changed. # (or hopefully they'll add this functionality to their version) + # NOTE: sounds like we can use functools singledispatchmethod in 3.8 def wrapper(*args: Any, **kw: Any) -> Any: if not args or len(args) < 2: raise TypeError(f'{funcname} requires at least ' diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index b89d640b..51c93b35 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -40,8 +40,11 @@ if TYPE_CHECKING: from typing import Dict, Union, Sequence, Optional, Any from typing_extensions import Literal +# Python major version we're using for all this stuff. +PYVER = '3.7' + # Python binary assumed by these tools. -PYTHON_BIN = 'python3.7' if platform.system() != 'Windows' else 'python' +PYTHON_BIN = f'python{PYVER}' if platform.system() != 'Windows' else 'python' MIT_LICENSE = """Copyright (c) 2011-2020 Eric Froemling diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 28dfd52b..11c999b1 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -86,7 +86,7 @@ def cpplint(projroot: Path, full: bool) -> None: import tempfile from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count - from efrotools import getconfig + from efrotools import getconfig, PYVER from efro.terminal import Clr from efro.error import CleanError @@ -150,7 +150,8 @@ def cpplint(projroot: Path, full: bool) -> None: def lint_file(filename: str) -> None: result = subprocess.call( - ['python3.7', '-m', 'cpplint', '--root=src', filename], env=env) + [f'python{PYVER}', '-m', 'cpplint', '--root=src', filename], + env=env) if result != 0: raise CleanError( f'{Clr.RED}Cpplint failed for {filename}.{Clr.RST}') @@ -197,7 +198,7 @@ def formatscripts(projroot: Path, full: bool) -> None: import time from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count - from efrotools import get_files_hash + from efrotools import get_files_hash, PYVER os.chdir(projroot) cachepath = Path(projroot, 'config/.cache-formatscripts') if full and cachepath.exists(): @@ -215,7 +216,7 @@ def formatscripts(projroot: Path, full: bool) -> None: def format_file(filename: str) -> None: start_time = time.time() result = subprocess.call( - ['python3.7', '-m', 'yapf', '--in-place', filename]) + [f'python{PYVER}', '-m', 'yapf', '--in-place', filename]) if result != 0: raise Exception(f'Formatting failed for {filename}') duration = time.time() - start_time diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index 5609ec37..6af449ec 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -174,6 +174,12 @@ def spelling() -> None: _spelling(sys.argv[2:]) +def pyver() -> None: + """Prints the Python version used by this project.""" + from efrotools import PYVER + print(PYVER, end='') + + def check_clean_safety() -> None: """Ensure all files are are added to git or in gitignore. diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index e7362d69..6f32f418 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -25,14 +25,11 @@ from __future__ import annotations import os from typing import TYPE_CHECKING -import efrotools +from efrotools import PYVER, run, readfile, writefile, replace_one if TYPE_CHECKING: from typing import List, Dict, Any -# Overall version we're using for the game currently. -PYTHON_VERSION_MAJOR = '3.7' - ENABLE_OPENSSL = True @@ -51,23 +48,22 @@ def build_apple(arch: str, debug: bool = False) -> None: raise CleanError('NEED TO TEMP-KILL GETTEXT') builddir = 'build/python_apple_' + arch + ('_debug' if debug else '') - efrotools.run('rm -rf "' + builddir + '"') - efrotools.run('mkdir -p build') - efrotools.run('git clone ' - 'git@github.com:pybee/Python-Apple-support.git "' + - builddir + '"') + run('rm -rf "' + builddir + '"') + run('mkdir -p build') + run('git clone ' + 'git@github.com:pybee/Python-Apple-support.git "' + builddir + '"') os.chdir(builddir) # TEMP: Check out a particular commit while the branch head is broken. # We can actually fix this to use the current one, but something # broke in the underlying build even on old commits so keeping it # locked for now... - # efrotools.run('git checkout bf1ed73d0d5ff46862ba69dd5eb2ffaeff6f19b6') - efrotools.run(f'git checkout {PYTHON_VERSION_MAJOR}') + # run('git checkout bf1ed73d0d5ff46862ba69dd5eb2ffaeff6f19b6') + run(f'git checkout {PYVER}') # On mac we currently have to add the _scproxy module or urllib will # fail. - txt = efrotools.readfile('patch/Python/Setup.embedded') + txt = readfile('patch/Python/Setup.embedded') if arch == 'mac': txt += ('\n' '# ericf added - mac urllib needs this\n' @@ -76,19 +72,19 @@ def build_apple(arch: str, debug: bool = False) -> None: '-framework CoreFoundation') # Turn off sqlite module. (scratch that; leaving it in.) - # txt = efrotools.replace_one(txt, '_sqlite3 -I$(', '#_sqlite3 -I$(') + # txt = replace_one(txt, '_sqlite3 -I$(', '#_sqlite3 -I$(') # txt = txt.replace(' _sqlite/', '# _sqlite/') # Turn off xz compression module. (scratch that; leaving it in.) - # txt = efrotools.replace_one(txt, '_lzma _', '#_lzma _') + # txt = replace_one(txt, '_lzma _', '#_lzma _') # Turn off bzip2 module. - txt = efrotools.replace_one(txt, '_bz2 _b', '#_bz2 _b') + txt = replace_one(txt, '_bz2 _b', '#_bz2 _b') # Turn off openssl module (only if not doing openssl). if not ENABLE_OPENSSL: - txt = efrotools.replace_one(txt, '_hashlib _hashopenssl.c', - '#_hashlib _hashopenssl.c') + txt = replace_one(txt, '_hashlib _hashopenssl.c', + '#_hashlib _hashopenssl.c') # Turn off various other stuff we don't use. for line in [ @@ -123,7 +119,7 @@ def build_apple(arch: str, debug: bool = False) -> None: '_testimportmultiple _testimportmultiple.c', '_crypt _cryptmodule.c', # not on android so disabling here too ]: - txt = efrotools.replace_one(txt, line, '#' + line) + txt = replace_one(txt, line, '#' + line) if ENABLE_OPENSSL: @@ -138,28 +134,28 @@ def build_apple(arch: str, debug: bool = False) -> None: '_sha256 sha256module.c', '_sha512 sha512module.c', ]: - txt = efrotools.replace_one(txt, line, '#' + line) + txt = replace_one(txt, line, '#' + line) else: - txt = efrotools.replace_one(txt, '_ssl _ssl.c', '#_ssl _ssl.c') - efrotools.writefile('patch/Python/Setup.embedded', txt) + txt = replace_one(txt, '_ssl _ssl.c', '#_ssl _ssl.c') + writefile('patch/Python/Setup.embedded', txt) - txt = efrotools.readfile('Makefile') + txt = readfile('Makefile') # Fix a bug where spaces in PATH cause errors (darn you vmware fusion!) - txt = efrotools.replace_one( + txt = replace_one( txt, '&& PATH=$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/dist/bin:$(PATH) .', '&& PATH="$(PROJECT_DIR)/$(PYTHON_DIR-macOS)/dist/bin:$(PATH)" .') # Remove makefile dependencies so we don't build the # libs we're not using. srctxt = '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER)m.a: ' - txt = efrotools.replace_one( + txt = replace_one( txt, srctxt, '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER)m.a: ' + ('build/$2/Support/OpenSSL ' if ENABLE_OPENSSL else '') + 'build/$2/Support/XZ $$(PYTHON_DIR-$1)/Makefile\n#' + srctxt) srctxt = ('dist/Python-$(PYTHON_VER)-$1-support.' '$(BUILD_NUMBER).tar.gz: ') - txt = efrotools.replace_one( + txt = replace_one( txt, srctxt, 'dist/Python-$(PYTHON_VER)-$1-support.$(BUILD_NUMBER).tar.gz:' ' $$(PYTHON_FRAMEWORK-$1)\n#' + srctxt) @@ -169,14 +165,14 @@ def build_apple(arch: str, debug: bool = False) -> None: # Set mac/ios version reqs # (see issue with utimensat and futimens). - txt = efrotools.replace_one(txt, 'MACOSX_DEPLOYMENT_TARGET=10.8', - 'MACOSX_DEPLOYMENT_TARGET=10.14') + txt = replace_one(txt, 'MACOSX_DEPLOYMENT_TARGET=10.8', + 'MACOSX_DEPLOYMENT_TARGET=10.14') # And equivalent iOS (11+). - txt = efrotools.replace_one(txt, 'CFLAGS-iOS=-mios-version-min=8.0', - 'CFLAGS-iOS=-mios-version-min=12.0') + txt = replace_one(txt, 'CFLAGS-iOS=-mios-version-min=8.0', + 'CFLAGS-iOS=-mios-version-min=12.0') # Ditto for tvOS. - txt = efrotools.replace_one(txt, 'CFLAGS-tvOS=-mtvos-version-min=9.0', - 'CFLAGS-tvOS=-mtvos-version-min=12.0') + txt = replace_one(txt, 'CFLAGS-tvOS=-mtvos-version-min=9.0', + 'CFLAGS-tvOS=-mtvos-version-min=12.0') if debug: @@ -196,13 +192,13 @@ def build_apple(arch: str, debug: bool = False) -> None: raise RuntimeError(f'Unexpected configure line count {splitlen}.') txt = txt.replace(dline, 'python$(PYTHON_VER)dm') - efrotools.writefile('Makefile', txt) + writefile('Makefile', txt) # Ok; let 'er rip. # (we run these in parallel so limit to 1 job a piece; # otherwise they inherit the -j12 or whatever from the top level) # (also this build seems to fail with multiple threads) - efrotools.run('make -j1 ' + { + run('make -j1 ' + { 'mac': 'Python-macOS', 'ios': 'Python-iOS', 'tvos': 'Python-tvOS' @@ -217,11 +213,10 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: """ import subprocess builddir = 'build/python_android_' + arch + ('_debug' if debug else '') - efrotools.run('rm -rf "' + builddir + '"') - efrotools.run('mkdir -p build') - efrotools.run('git clone ' - 'git@github.com:yan12125/python3-android.git "' + builddir + - '"') + run('rm -rf "' + builddir + '"') + run('mkdir -p build') + run('git clone ' + 'git@github.com:yan12125/python3-android.git "' + builddir + '"') os.chdir(builddir) # It seems we now need 'autopoint' as part of this build, but on mac it @@ -242,69 +237,69 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: # a a completely new minimal one which will take some work to update here. # Punting on that for now... if True: # pylint: disable=using-constant-test - efrotools.run('git checkout 9adbcfaca37f40b7a86381f83f0f6af4187233ae') - ftxt = efrotools.readfile('pybuild/env.py') + run('git checkout 9adbcfaca37f40b7a86381f83f0f6af4187233ae') + ftxt = readfile('pybuild/env.py') # Set the packages we build. - ftxt = efrotools.replace_one( + ftxt = replace_one( ftxt, 'packages = (', "packages = ('zlib', 'sqlite', 'xz'," + (" 'openssl'" if ENABLE_OPENSSL else '') + ')\n# packages = (') # Don't wanna bother with gpg signing stuff. - ftxt = efrotools.replace_one(ftxt, 'verify_source = True', - 'verify_source = False') + ftxt = replace_one(ftxt, 'verify_source = True', 'verify_source = False') # Sub in the min api level we're targeting. - ftxt = efrotools.replace_one(ftxt, 'android_api_level = 21', - 'android_api_level = 21') - ftxt = efrotools.replace_one(ftxt, "target_arch = 'arm'", - "target_arch = '" + arch + "'") - efrotools.writefile('pybuild/env.py', ftxt) - ftxt = efrotools.readfile('Makefile') + ftxt = replace_one(ftxt, 'android_api_level = 21', + 'android_api_level = 21') + ftxt = replace_one(ftxt, "target_arch = 'arm'", + "target_arch = '" + arch + "'") + writefile('pybuild/env.py', ftxt) + ftxt = readfile('Makefile') # This needs to be python3 for us. - ftxt = efrotools.replace_one(ftxt, 'PYTHON?=python\n', 'PYTHON?=python3\n') - efrotools.writefile('Makefile', ftxt) - ftxt = efrotools.readfile('pybuild/packages/python.py') + ftxt = replace_one(ftxt, 'PYTHON?=python\n', 'PYTHON?=python3\n') + writefile('Makefile', ftxt) + ftxt = readfile('pybuild/packages/python.py') # We currently build as a static lib. - ftxt = efrotools.replace_one(ftxt, " '--enable-shared',\n", '') - ftxt = efrotools.replace_one( + ftxt = replace_one(ftxt, " '--enable-shared',\n", '') + ftxt = replace_one( ftxt, "super().__init__('https://github.com/python/cpython/')", - "super().__init__('https://github.com/python/cpython/', branch='3.7')") + "super().__init__('https://github.com/python/cpython/'" + f", branch='{PYVER}')") # Turn ipv6 on (curious why its turned off here?...) # Also, turn on low level debugging features for our debug builds. - ftxt = efrotools.replace_one(ftxt, "'--disable-ipv6',", "'--enable-ipv6',") + ftxt = replace_one(ftxt, "'--disable-ipv6',", "'--enable-ipv6',") if debug: - ftxt = efrotools.replace_one(ftxt, "'./configure',", - "'./configure', '--with-pydebug',") + ftxt = replace_one(ftxt, "'./configure',", + "'./configure', '--with-pydebug',") # We don't use this stuff so lets strip it out to simplify. - ftxt = efrotools.replace_one(ftxt, "'--without-ensurepip',", '') + ftxt = replace_one(ftxt, "'--without-ensurepip',", '') # This builds all modules as dynamic libs, but we want to be consistent # with our other embedded builds and just static-build the ones we # need... so to change that we'll need to add a hook for ourself after # python is downloaded but before it is built so we can muck with it. - ftxt = efrotools.replace_one( + ftxt = replace_one( ftxt, ' def build(self):', ' def build(self):\n import os\n' ' if os.system(\'"' + rootdir + '/tools/pcommand" python_android_patch "' + os.getcwd() + '"\') != 0: raise Exception("patch apply failed")') - efrotools.writefile('pybuild/packages/python.py', ftxt) + writefile('pybuild/packages/python.py', ftxt) # Set this to a particular cpython commit to target exact releases from git # commit = 'd7c567b08f9d7d6aef21b881340a2b72731129db' # 3.7.7 release commit = '4b47a5b6ba66b02df9392feb97b8ead916f8c1fa' # 3.7.8 release if commit is not None: - ftxt = efrotools.readfile('pybuild/source.py') + ftxt = readfile('pybuild/source.py') # Check out a particular commit right after the clone. - ftxt = efrotools.replace_one( + ftxt = replace_one( ftxt, "'git', 'clone', '--single-branch', '-b'," ' self.branch, self.source_url, self.dest])', "'git', 'clone', '-b'," @@ -315,16 +310,16 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: "'https://github.com/python/cpython/':\n" " run_in_dir(['git', 'checkout', '" + commit + "'], self.source_dir)") - efrotools.writefile('pybuild/source.py', ftxt) - ftxt = efrotools.readfile('pybuild/util.py') + writefile('pybuild/source.py', ftxt) + ftxt = readfile('pybuild/util.py') # Still don't wanna bother with gpg signing stuff. - ftxt = efrotools.replace_one( + ftxt = replace_one( ftxt, 'def gpg_verify_file(sig_filename, filename, validpgpkeys):\n', 'def gpg_verify_file(sig_filename, filename, validpgpkeys):\n' ' print("gpg-verify disabled by ericf")\n' ' return\n') - efrotools.writefile('pybuild/util.py', ftxt) + writefile('pybuild/util.py', ftxt) # These builds require ANDROID_NDK to be set, so make sure that's # the case. @@ -335,18 +330,18 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: # Ok, let 'er rip # (we often run these builds in parallel so limit to 1 job a piece; # otherwise they each inherit the -j12 or whatever from the top level). - efrotools.run('make -j1') + run('make -j1') print('python build complete! (android/' + arch + ')') def android_patch() -> None: """Run necessary patches on an android archive before building.""" fname = 'src/cpython/Modules/Setup.dist' - txt = efrotools.readfile(fname) + txt = readfile(fname) # Need to switch some flags on this one. - txt = efrotools.replace_one(txt, '#zlib zlibmodule.c', - 'zlib zlibmodule.c -lz\n#zlib zlibmodule.c') + txt = replace_one(txt, '#zlib zlibmodule.c', + 'zlib zlibmodule.c -lz\n#zlib zlibmodule.c') # Just turn all these on. for enable in [ '#array arraymodule.c', '#cmath cmathmodule.c _math.c', @@ -362,10 +357,10 @@ def android_patch() -> None: '#binascii binascii.c', '#_posixsubprocess _posixsubprocess.c', '#_sha3 _sha3/sha3module.c' ]: - txt = efrotools.replace_one(txt, enable, enable[1:]) + txt = replace_one(txt, enable, enable[1:]) if ENABLE_OPENSSL: - txt = efrotools.replace_one(txt, '#_ssl _ssl.c \\', - '_ssl _ssl.c -DUSE_SSL -lssl -lcrypto') + txt = replace_one(txt, '#_ssl _ssl.c \\', + '_ssl _ssl.c -DUSE_SSL -lssl -lcrypto') else: # Note that the _md5 and _sha modules are normally only built if the # system does not have the OpenSSL libs containing an optimized @@ -374,11 +369,10 @@ def android_patch() -> None: '#_md5 md5module.c', '#_sha1 sha1module.c', '#_sha256 sha256module.c', '#_sha512 sha512module.c' ]: - txt = efrotools.replace_one(txt, enable, enable[1:]) + txt = replace_one(txt, enable, enable[1:]) # Turn this off (its just an example module). - txt = efrotools.replace_one(txt, 'xxsubtype xxsubtype.c', - '#xxsubtype xxsubtype.c') + txt = replace_one(txt, 'xxsubtype xxsubtype.c', '#xxsubtype xxsubtype.c') # For whatever reason this stuff isn't in there at all; add it. txt += '\n_json _json.c\n' @@ -403,7 +397,7 @@ def android_patch() -> None: txt += '\n\n*disabled*\n_ctypes _crypt grp' - efrotools.writefile(fname, txt) + writefile(fname, txt) # Ok, this is weird. # When applying the module Setup, python looks for any line containing *=* @@ -412,17 +406,16 @@ def android_patch() -> None: # The check used to look for [A-Z]*=* which didn't break, so let' just # change it back to that for now. fname = 'src/cpython/Modules/makesetup' - txt = efrotools.readfile(fname) - txt = efrotools.replace_one( - txt, ' *=*) DEFS="$line$NL$DEFS"; continue;;', - ' [A-Z]*=*) DEFS="$line$NL$DEFS"; continue;;') - efrotools.writefile(fname, txt) + txt = readfile(fname) + txt = replace_one(txt, ' *=*) DEFS="$line$NL$DEFS"; continue;;', + ' [A-Z]*=*) DEFS="$line$NL$DEFS"; continue;;') + writefile(fname, txt) # Add custom callbacks to Python's PyParser_ParseFileObject # and PyParser_ParseString calls to debug a crash. fname = 'src/cpython/Parser/parsetok.c' - txt = efrotools.readfile(fname) - txt = efrotools.replace_one( + txt = readfile(fname) + txt = replace_one( txt, 'node *\n' 'PyParser_ParseFileObject(FILE *fp, PyObject *filename,\n' ' const char *enc, grammar *g, int start,\n' @@ -444,7 +437,7 @@ def android_patch() -> None: ' start, ps1, ps2,\n' ' err_ret, flags);\n' ' }\n') - txt = efrotools.replace_one( + txt = replace_one( txt, 'node *\n' 'PyParser_ParseStringObject(const char *s, PyObject *filename,\n' ' grammar *g, int start,\n' @@ -462,7 +455,7 @@ def android_patch() -> None: ' PyParser_ParseStringObject_EfroCB(s, filename, g, start,\n' ' err_ret, flags);\n' ' }\n') - efrotools.writefile(fname, txt) + writefile(fname, txt) print('APPLIED EFROTOOLS ANDROID BUILD PATCHES.') @@ -485,14 +478,14 @@ def gather() -> None: if d.startswith('pylib-') ] for existing_dir in existing_dirs: - efrotools.run('rm -rf "' + existing_dir + '"') + run('rm -rf "' + existing_dir + '"') for buildtype in ['debug', 'release']: debug = buildtype == 'debug' bsuffix = '_debug' if buildtype == 'debug' else '' bsuffix2 = '-debug' if buildtype == 'debug' else '' - libname = 'python' + PYTHON_VERSION_MAJOR + ('dm' if debug else 'm') + libname = 'python' + PYVER + ('dm' if debug else 'm') bases = { 'mac': @@ -513,19 +506,15 @@ def gather() -> None: # Note: only need pylib for the first in each group. builds: List[Dict[str, Any]] = [{ - 'name': - 'macos', - 'group': - 'apple', - 'headers': - bases['mac'] + '/Support/Python/Headers', + 'name': 'macos', + 'group': 'apple', + 'headers': bases['mac'] + '/Support/Python/Headers', 'libs': [ bases['mac'] + '/Support/Python/libPython.a', bases['mac'] + '/Support/OpenSSL/libOpenSSL.a', bases['mac'] + '/Support/XZ/libxz.a' ], - 'pylib': - (bases['mac'] + '/python/lib/python' + PYTHON_VERSION_MAJOR), + 'pylib': (bases['mac'] + '/python/lib/python' + PYVER), }, { 'name': 'ios', @@ -551,12 +540,9 @@ def gather() -> None: bases['tvos'] + '/Support/XZ/libxz.a' ], }, { - 'name': - 'android_arm', - 'group': - 'android', - 'headers': - bases['android_arm'] + f'/usr/include/{libname}', + 'name': 'android_arm', + 'group': 'android', + 'headers': bases['android_arm'] + f'/usr/include/{libname}', 'libs': [ bases['android_arm'] + f'/usr/lib/lib{libname}.a', bases['android_arm'] + '/usr/lib/libssl.a', @@ -564,10 +550,8 @@ def gather() -> None: bases['android_arm'] + '/usr/lib/liblzma.a', bases['android_arm'] + '/usr/lib/libsqlite3.a' ], - 'libinst': - 'android_armeabi-v7a', - 'pylib': (bases['android_arm'] + '/usr/lib/python' + - PYTHON_VERSION_MAJOR), + 'libinst': 'android_armeabi-v7a', + 'pylib': (bases['android_arm'] + '/usr/lib/python' + PYVER), }, { 'name': 'android_arm64', 'group': 'android', @@ -616,16 +600,15 @@ def gather() -> None: # Do some setup only once per group. if not os.path.exists(builddir): - efrotools.run('mkdir -p "' + builddir + '"') - efrotools.run('mkdir -p "' + lib_dst + '"') + run('mkdir -p "' + builddir + '"') + run('mkdir -p "' + lib_dst + '"') # Only pull modules into game assets on release pass. if not debug: # Copy system modules into the src assets # dir for this group. - efrotools.run('mkdir -p "' + assets_src_dst + '"') - efrotools.run( - 'rsync --recursive --include "*.py"' + run('mkdir -p "' + assets_src_dst + '"') + run('rsync --recursive --include "*.py"' ' --exclude __pycache__ --include "*/" --exclude "*" "' + build['pylib'] + '/" "' + assets_src_dst + '"') @@ -639,30 +622,30 @@ def gather() -> None: 'unittest', 'dbm', 'venv', 'ctypes/test', 'imaplib.py', '_sysconfigdata_*' ] - efrotools.run('cd "' + assets_src_dst + '" && rm -rf ' + - ' '.join(prune)) + run('cd "' + assets_src_dst + '" && rm -rf ' + + ' '.join(prune)) # Some minor filtering to system scripts: # on iOS/tvOS, addusersitepackages() leads to a crash # due to _sysconfigdata_dm_ios_darwin module not existing, # so let's skip that. fname = f'{assets_src_dst}/site.py' - txt = efrotools.readfile(fname) - txt = efrotools.replace_one( + txt = readfile(fname) + txt = replace_one( txt, ' known_paths = addusersitepackages(known_paths)', ' # efro tweak: this craps out on ios/tvos.\n' ' # (and we don\'t use it anyway)\n' ' # known_paths = addusersitepackages(known_paths)') - efrotools.writefile(fname, txt) + writefile(fname, txt) # Copy in a base set of headers (everything in a group should # be using the same headers) - efrotools.run(f'cp -r "{build["headers"]}" "{header_dst}"') + run(f'cp -r "{build["headers"]}" "{header_dst}"') # Clear whatever pyconfigs came across; we'll build our own # universal one below. - efrotools.run('rm ' + header_dst + '/pyconfig*') + run('rm ' + header_dst + '/pyconfig*') # Write a master pyconfig header that reroutes to each # platform's actual header. @@ -701,21 +684,21 @@ def gather() -> None: # contents too (those headers can themselves include # others; ios for instance points to a arm64 and a # x86_64 variant). - contents = efrotools.readfile(build['headers'] + '/' + cfg) + contents = readfile(build['headers'] + '/' + cfg) contents = contents.replace('pyconfig', 'pyconfig-' + build['name']) - efrotools.writefile(header_dst + '/' + out, contents) + writefile(header_dst + '/' + out, contents) else: # other configs we just rename - efrotools.run('cp "' + build['headers'] + '/' + cfg + - '" "' + header_dst + '/' + out + '"') + run('cp "' + build['headers'] + '/' + cfg + '" "' + + header_dst + '/' + out + '"') # Copy in libs. If the lib gave a specific install name, # use that; otherwise use name. targetdir = lib_dst + '/' + build.get('libinst', build['name']) - efrotools.run('rm -rf "' + targetdir + '"') - efrotools.run('mkdir -p "' + targetdir + '"') + run('rm -rf "' + targetdir + '"') + run('mkdir -p "' + targetdir + '"') for lib in build['libs']: - efrotools.run('cp "' + lib + '" "' + targetdir + '"') + run('cp "' + lib + '" "' + targetdir + '"') print('Great success!') diff --git a/tools/pcommand b/tools/pcommand index 8019c1c5..db068958 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -42,7 +42,7 @@ from efrotools.pcommand import ( cpplint, pylint, runpylint, mypy, runmypy, dmypy, tool_config_install, sync, sync_all, scriptfiles, pycharm, clioncode, androidstudiocode, makefile_target_list, spelling, spelling_all, pytest, echo, - compile_python_files) + compile_python_files, pyver) from batools.pcommand import ( stage_server_file, py_examine, fix_mac_ssh, check_mac_ssh, resize_image, check_clean_safety, clean_orphaned_assets, archive_old_builds, From 2ec0bd17be1ecfddfcd6e550507467560dbba9b6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 26 Jul 2020 01:40:45 -0700 Subject: [PATCH 175/417] minor prereq fix --- CHANGELOG.md | 2 +- tools/batools/build.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8289ca3f..75a57e7b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ### 1.5.24 (20159) -- Misc bug fixes.. +- Misc bug fixes. ### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. diff --git a/tools/batools/build.py b/tools/batools/build.py index f7e62995..9668fc60 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -502,7 +502,7 @@ def checkenv() -> None: check=False, capture_output=True).returncode != 0: raise RuntimeError( - 'pip (for {PYTHON_BIN}) is required; please install it.') + f'pip (for {PYTHON_BIN}) is required; please install it.') # Check for some required python modules. for req in PIP_REQUIREMENTS: From 2c16c8c13b7545e207325b5930f1da41c2efcb00 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 31 Jul 2020 13:39:09 -0700 Subject: [PATCH 176/417] Upgraded Python from 3.7 to 3.8 --- .efrocachemap | 1076 ++-- .gitignore | 2 + .idea/ballisticacore.iml | 2 +- .idea/dictionaries/ericf.xml | 8 + .idea/inspectionProfiles/Default.xml | 1 + .idea/misc.xml | 2 +- CHANGELOG.md | 4 +- assets/.asset_manifest_private.json | 4582 ++++++--------- assets/.asset_manifest_public.json | 500 +- assets/Makefile | 5092 +++++++---------- .../ba_data/python/bastd/game/thelaststand.py | 3 +- assets/src/server/README.txt | 4 +- assets/src/server/ballisticacore_server.py | 2 +- docs/ba_module.md | 4 +- tools/bacloud | 2 +- tools/batools/android.py | 2 +- tools/batools/assetsmakefile.py | 6 +- tools/batools/assetstaging.py | 13 +- tools/batools/build.py | 4 +- tools/batools/pcommand.py | 8 + tools/batools/updateproject.py | 14 +- tools/efrotools/__init__.py | 2 +- tools/efrotools/android.py | 2 +- tools/efrotools/pybuild.py | 110 +- tools/pcommand | 13 +- 25 files changed, 4776 insertions(+), 6682 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 72d22bcb..fe765ae4 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -2557,85 +2557,89 @@ "assets/build/ba_data/textures/zoeIconColorMask.pvr": "https://files.ballistica.net/cache/ba1/2b/dc/22df1ef245a7f368060d2eecb839", "assets/build/ba_data/textures/zoeIconColorMask_preview.png": "https://files.ballistica.net/cache/ba1/d5/08/7d5e28abf51591fb4923892f43dd", "assets/build/ba_data/textures/zoeIcon_preview.png": "https://files.ballistica.net/cache/ba1/e2/af/ab381c9d7242aedf8535fc90252f", - "assets/build/pylib-android/__future__.py": "https://files.ballistica.net/cache/ba1/3e/26/bf19b6d9c3b377dab2400761e703", + "assets/build/pylib-android/__future__.py": "https://files.ballistica.net/cache/ba1/b0/17/65eaa999408c68e15524355351bb", "assets/build/pylib-android/__phello__.foo.py": "https://files.ballistica.net/cache/ba1/18/38/a9706423d7445928a1c07345b100", "assets/build/pylib-android/_bootlocale.py": "https://files.ballistica.net/cache/ba1/42/c3/38a2d6f5e2467c1cab04a024c2ca", - "assets/build/pylib-android/_collections_abc.py": "https://files.ballistica.net/cache/ba1/b5/f5/7cf20ebefd0cdc1b1a4242596e3b", + "assets/build/pylib-android/_collections_abc.py": "https://files.ballistica.net/cache/ba1/5d/e8/8af7f48ff8e0cf88e87339221869", "assets/build/pylib-android/_compat_pickle.py": "https://files.ballistica.net/cache/ba1/03/70/f2d2ed965337f8ed80f6fffb37e1", "assets/build/pylib-android/_compression.py": "https://files.ballistica.net/cache/ba1/93/7f/56c3fd789058399b898c5c527b92", "assets/build/pylib-android/_dummy_thread.py": "https://files.ballistica.net/cache/ba1/5b/a5/82c6ed2ef16974f8cfd5ee2e11f6", "assets/build/pylib-android/_markupbase.py": "https://files.ballistica.net/cache/ba1/a5/5e/6ad43bfbcd054529b852fa9d9919", "assets/build/pylib-android/_osx_support.py": "https://files.ballistica.net/cache/ba1/1a/dd/18c02bae9dd4e2b651071dd0e606", - "assets/build/pylib-android/_py_abc.py": "https://files.ballistica.net/cache/ba1/63/57/80933fee0979574b2d3b1172cdc8", - "assets/build/pylib-android/_pydecimal.py": "https://files.ballistica.net/cache/ba1/78/1c/999595e074c71574c01ff521a6e0", - "assets/build/pylib-android/_pyio.py": "https://files.ballistica.net/cache/ba1/e6/8e/da9cef09b9375b297ccc45cbedf7", + "assets/build/pylib-android/_py_abc.py": "https://files.ballistica.net/cache/ba1/5d/06/d6095f475b0d26f707d3d7484080", + "assets/build/pylib-android/_pydecimal.py": "https://files.ballistica.net/cache/ba1/a5/4c/6fb8db34dfeb6c44bf18d555970d", + "assets/build/pylib-android/_pyio.py": "https://files.ballistica.net/cache/ba1/30/f3/9c14ceae8041894ae6914467ba66", "assets/build/pylib-android/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/6d/7a/d76775d8f9d27c45135ca654dfd0", - "assets/build/pylib-android/_strptime.py": "https://files.ballistica.net/cache/ba1/59/74/f1350b09c0bd4924be716707ba93", - "assets/build/pylib-android/_threading_local.py": "https://files.ballistica.net/cache/ba1/b6/c3/bef9f784ac2c4d01f1ca84c6d841", - "assets/build/pylib-android/_weakrefset.py": "https://files.ballistica.net/cache/ba1/77/4d/3acfab111cd04092728329c1ac4e", - "assets/build/pylib-android/abc.py": "https://files.ballistica.net/cache/ba1/f9/b3/c917c0ae42e4d70207fb758a774f", + "assets/build/pylib-android/_strptime.py": "https://files.ballistica.net/cache/ba1/2d/6d/ec0a63b650f5c5fdaf7a1b65ae8f", + "assets/build/pylib-android/_threading_local.py": "https://files.ballistica.net/cache/ba1/da/4d/144f886b39ebc097fdcea22eecc8", + "assets/build/pylib-android/_weakrefset.py": "https://files.ballistica.net/cache/ba1/5a/9d/765a6159b6db54bbffc249e35833", + "assets/build/pylib-android/abc.py": "https://files.ballistica.net/cache/ba1/46/99/e17cba0561b17a01327a35cd1aa6", "assets/build/pylib-android/aifc.py": "https://files.ballistica.net/cache/ba1/8a/d6/25bd39b0581236a85b096ba3fe9d", "assets/build/pylib-android/antigravity.py": "https://files.ballistica.net/cache/ba1/83/cf/9d1698d68e0e260e6bbefec5a516", - "assets/build/pylib-android/argparse.py": "https://files.ballistica.net/cache/ba1/7d/a3/3c4997b2a8c0c3486ee6a88a1d11", - "assets/build/pylib-android/ast.py": "https://files.ballistica.net/cache/ba1/b7/42/718de3a57faaca60e6107da1791d", + "assets/build/pylib-android/argparse.py": "https://files.ballistica.net/cache/ba1/cd/3b/9fdf463eacafdba271d8fe1d9b2d", + "assets/build/pylib-android/ast.py": "https://files.ballistica.net/cache/ba1/7c/fb/5fb2ffea4e71747a3a03b59f06a8", "assets/build/pylib-android/asynchat.py": "https://files.ballistica.net/cache/ba1/5e/b1/f69db224de08b5e119f5c0f425a8", - "assets/build/pylib-android/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/6d/27/61dd597138eea19aaf7d724ee691", - "assets/build/pylib-android/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/93/62/5ee3d4885bf7d85654964fb065e3", - "assets/build/pylib-android/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/a7/f3/869a086bf784ae308d02e15d3c0b", - "assets/build/pylib-android/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/38/b3/a183c0e04a18def5f39acb4ef3b5", - "assets/build/pylib-android/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/28/a0/90a971561cc54a06d1c683cc1562", + "assets/build/pylib-android/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/37/de/1740d5e10a554f64af0a2ddc4659", + "assets/build/pylib-android/asyncio/__main__.py": "https://files.ballistica.net/cache/ba1/00/05/038811ebbd5ac847aaf99cd8f2f9", + "assets/build/pylib-android/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/80/d1/0975e5cb364d63f1f85136bc4d80", + "assets/build/pylib-android/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/6b/d0/0f707d26d6ac7f6f5410462456a6", + "assets/build/pylib-android/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/72/c7/ccf47dbfa076fdf5dd38474a18dc", + "assets/build/pylib-android/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/f0/b8/3f75f12f1851216b9a16772dfa63", "assets/build/pylib-android/asyncio/constants.py": "https://files.ballistica.net/cache/ba1/b6/63/66f781190cbd10a134616e67b516", - "assets/build/pylib-android/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/b7/9a/53b2e414ad31da913ae95402d0ac", - "assets/build/pylib-android/asyncio/events.py": "https://files.ballistica.net/cache/ba1/e0/81/2296ab7b2b3d6298d488cf9c8e78", + "assets/build/pylib-android/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/72/cd/f838323eebe2eeb8f5ea19e5cebe", + "assets/build/pylib-android/asyncio/events.py": "https://files.ballistica.net/cache/ba1/2d/74/47cba281af0ad7cb6476a523c100", + "assets/build/pylib-android/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/3a/30/d29bc046b5e725464724b282c701", "assets/build/pylib-android/asyncio/format_helpers.py": "https://files.ballistica.net/cache/ba1/ff/c2/2be0f7aa8dc71aa3a7cee83ed5c7", - "assets/build/pylib-android/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/e2/7a/f9e0b16c5f91aef79e4a807be751", - "assets/build/pylib-android/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/94/e8/3f7b4db2ec62e21d6e5af271ae1b", + "assets/build/pylib-android/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/f1/da/2eff642e6a966b374b29361dfbb2", + "assets/build/pylib-android/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/07/0b/a37203e779cbd3b3fdf825a36849", "assets/build/pylib-android/asyncio/log.py": "https://files.ballistica.net/cache/ba1/da/7f/235e1251f8838a239dd3ec9e78c3", - "assets/build/pylib-android/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/d0/da/c7005c6b99cdba8b1d4b8d7bfcc9", - "assets/build/pylib-android/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/24/6a/fcf160c9b55ef581850153a23a3b", - "assets/build/pylib-android/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/2e/32/9c951a49109188e5975d8e1ef59c", + "assets/build/pylib-android/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/ec/e4/99c3537e2344e469feaf6a116c0b", + "assets/build/pylib-android/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/0d/2f/e3e6c48d73836172a211a6c39e68", + "assets/build/pylib-android/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/1c/69/6d73ee2286d3dbce70990a8ff174", "assets/build/pylib-android/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/50/48/2e9be563bfd8e02e32e1e15802fa", - "assets/build/pylib-android/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/cf/1d/dc1e75b2c845a83181585d0f1298", - "assets/build/pylib-android/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/cb/77/a46c16d87791f73355a840ce27e3", - "assets/build/pylib-android/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/db/7c/dcee49facb7d7e0697748f3f2cf4", - "assets/build/pylib-android/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/c8/c4/e58d4c6d467aff6b79cda30f9b52", - "assets/build/pylib-android/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/92/c3/5a2f6c0fe03583f3f1255456959e", - "assets/build/pylib-android/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/55/a3/0f5d3365b3235c75b2ea80bd5563", - "assets/build/pylib-android/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/eb/86/58dff20a80672a8e4406668de361", - "assets/build/pylib-android/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/3d/20/87bd62ba23f5d9f81421eb287041", - "assets/build/pylib-android/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/2e/f9/7642257a860d664f7242efecb3f7", - "assets/build/pylib-android/asyncore.py": "https://files.ballistica.net/cache/ba1/25/1f/ccae9e6cdd0885f9d989a3902e9b", + "assets/build/pylib-android/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/de/a6/2d155835ed7ff246475ab467870a", + "assets/build/pylib-android/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/ce/51/b4dc2c5750d26233aabbbfec3946", + "assets/build/pylib-android/asyncio/staggered.py": "https://files.ballistica.net/cache/ba1/f5/44/45851798434a9265934b4bb83368", + "assets/build/pylib-android/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/92/0c/884950c0c3a32bc5d2b763ca0044", + "assets/build/pylib-android/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/5f/44/b98545e4c3c4c178f8e6d1615413", + "assets/build/pylib-android/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/98/86/5188b1962fc7f15a7a22b70c1ff6", + "assets/build/pylib-android/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/28/74/1a4066e5538ac236ddbbe8d9aea0", + "assets/build/pylib-android/asyncio/trsock.py": "https://files.ballistica.net/cache/ba1/52/c8/e4d2abe8aaccd35c8f79d5b77431", + "assets/build/pylib-android/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/d2/f2/9c3e1bdeaf20ae6bc7441de68759", + "assets/build/pylib-android/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/73/c7/45560664ebe2b962551de6cf2be0", + "assets/build/pylib-android/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/2d/e4/dbd2379dd123a69aae5aa15ae6c2", + "assets/build/pylib-android/asyncore.py": "https://files.ballistica.net/cache/ba1/a7/5c/f528090ab4472aff3c8798cf42c9", "assets/build/pylib-android/base64.py": "https://files.ballistica.net/cache/ba1/4f/23/c5419203b2ccd1ae27fd49d2cc56", - "assets/build/pylib-android/bdb.py": "https://files.ballistica.net/cache/ba1/f6/27/ce7dcdf436e9b9b4f9b87568794d", + "assets/build/pylib-android/bdb.py": "https://files.ballistica.net/cache/ba1/ae/3f/acdf9e655546d96a28c484506fe9", "assets/build/pylib-android/binhex.py": "https://files.ballistica.net/cache/ba1/54/6a/c80667fe1186c14eda368148b7c3", - "assets/build/pylib-android/bisect.py": "https://files.ballistica.net/cache/ba1/67/2a/ac7f3e408cbfe1d697e44a420aac", - "assets/build/pylib-android/bz2.py": "https://files.ballistica.net/cache/ba1/84/cb/27cdd0e9186f848fe949c2a3bee7", - "assets/build/pylib-android/cProfile.py": "https://files.ballistica.net/cache/ba1/6e/44/33dbc763d5d1bf76678bdbe772f4", - "assets/build/pylib-android/calendar.py": "https://files.ballistica.net/cache/ba1/74/31/64ce1c94d173a6226df81fbe2baf", - "assets/build/pylib-android/cgi.py": "https://files.ballistica.net/cache/ba1/84/f5/4581cafa1723aab9252016a9128d", - "assets/build/pylib-android/cgitb.py": "https://files.ballistica.net/cache/ba1/45/67/f3f215ae81b670ba05d94706a2ab", + "assets/build/pylib-android/bisect.py": "https://files.ballistica.net/cache/ba1/e3/4e/c40a30927372b6b745aec7954d0d", + "assets/build/pylib-android/bz2.py": "https://files.ballistica.net/cache/ba1/8d/d6/d0ff69f6690ab56e45f7277abec0", + "assets/build/pylib-android/cProfile.py": "https://files.ballistica.net/cache/ba1/ae/10/06198546dc473414504b35bb86c4", + "assets/build/pylib-android/calendar.py": "https://files.ballistica.net/cache/ba1/52/59/c3f74ff2b6e664611af5f319f125", + "assets/build/pylib-android/cgi.py": "https://files.ballistica.net/cache/ba1/61/ce/9797194be01655e63ab2bf04db74", + "assets/build/pylib-android/cgitb.py": "https://files.ballistica.net/cache/ba1/44/fd/df9a22db6689da108e526e794e62", "assets/build/pylib-android/chunk.py": "https://files.ballistica.net/cache/ba1/f6/fe/3c43d1dc84ee74b8a170c61271a3", "assets/build/pylib-android/cmd.py": "https://files.ballistica.net/cache/ba1/f0/d9/8cec4bcbbfd195d46c3ad637df71", "assets/build/pylib-android/code.py": "https://files.ballistica.net/cache/ba1/7a/a4/ee660f11ad995354a3b21efbfb1c", - "assets/build/pylib-android/codecs.py": "https://files.ballistica.net/cache/ba1/ed/16/584061843712bbb77342ee17c423", + "assets/build/pylib-android/codecs.py": "https://files.ballistica.net/cache/ba1/46/7d/c9abbb72640e0270d05373ca097d", "assets/build/pylib-android/codeop.py": "https://files.ballistica.net/cache/ba1/9b/f7/a7fac5b57aa2aa74739f16d62515", - "assets/build/pylib-android/collections/__init__.py": "https://files.ballistica.net/cache/ba1/96/31/74bf91d70ac53f56c651ea0b1c6f", + "assets/build/pylib-android/collections/__init__.py": "https://files.ballistica.net/cache/ba1/20/79/d937c7f2b0121cda43113792991b", "assets/build/pylib-android/collections/abc.py": "https://files.ballistica.net/cache/ba1/29/45/a03469c0f5eb61d823b277d547ce", "assets/build/pylib-android/colorsys.py": "https://files.ballistica.net/cache/ba1/d6/3b/b932055a535b017694e91296168c", - "assets/build/pylib-android/compileall.py": "https://files.ballistica.net/cache/ba1/1e/8e/a36de40dc3e6cca8103c8d3e762c", + "assets/build/pylib-android/compileall.py": "https://files.ballistica.net/cache/ba1/e5/57/2b92b857953e59824989ede82453", "assets/build/pylib-android/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/37/3e/87f9ab4111608e0442bc82ff572f", - "assets/build/pylib-android/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/32/bd/77be7db5fed1029c0363bccf4456", - "assets/build/pylib-android/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/7f/16/02e7e8e860f0648dbd22db4daebd", - "assets/build/pylib-android/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/ed/59/ca581421e6f9f018cf417da7d08b", - "assets/build/pylib-android/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/2d/b5/f16d1bab301084cd6e2e1f0c32da", - "assets/build/pylib-android/configparser.py": "https://files.ballistica.net/cache/ba1/af/7d/8334b15bad238a5e38a3af40b4f4", - "assets/build/pylib-android/contextlib.py": "https://files.ballistica.net/cache/ba1/fd/9e/5ec1f12da2b8bcee39dabc218650", + "assets/build/pylib-android/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/0a/eb/2954f0e71c4a1e71db5c13548aec", + "assets/build/pylib-android/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/fc/07/2434cb1efcfdb8e396d2673d87e3", + "assets/build/pylib-android/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/a7/6e/a824dd0ccc5c3358e146fa4a143e", + "assets/build/pylib-android/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/46/b3/8ff0e8ddfd8ef4c2b65789015c0d", + "assets/build/pylib-android/configparser.py": "https://files.ballistica.net/cache/ba1/a2/cb/c077f4497d47011a41fb761da7e6", + "assets/build/pylib-android/contextlib.py": "https://files.ballistica.net/cache/ba1/9b/d5/72f4ba522348c8680098a35fed99", "assets/build/pylib-android/contextvars.py": "https://files.ballistica.net/cache/ba1/ed/ff/2f1089520caf4910564799a71d33", - "assets/build/pylib-android/copy.py": "https://files.ballistica.net/cache/ba1/f7/ba/bbbc0523aa05bf7dc78f2ef3812a", - "assets/build/pylib-android/copyreg.py": "https://files.ballistica.net/cache/ba1/df/0f/5d29c5993a73e81bdc4f2b4b9fb6", - "assets/build/pylib-android/crypt.py": "https://files.ballistica.net/cache/ba1/ae/e1/e2f82225c1a189679f80c95c4476", - "assets/build/pylib-android/csv.py": "https://files.ballistica.net/cache/ba1/eb/b9/8acd5724cdb94c8fb446e87e85da", - "assets/build/pylib-android/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/39/e3/dc6ed34197e6804b3dca273052f1", + "assets/build/pylib-android/copy.py": "https://files.ballistica.net/cache/ba1/2a/08/2626c3ca9b69eeea292688b30d87", + "assets/build/pylib-android/copyreg.py": "https://files.ballistica.net/cache/ba1/51/04/65c5689a2508a440fac7c453d907", + "assets/build/pylib-android/crypt.py": "https://files.ballistica.net/cache/ba1/a0/da/1dbb9eefae96fdac2bf0f2aed3a9", + "assets/build/pylib-android/csv.py": "https://files.ballistica.net/cache/ba1/4e/8b/5ec41815afbc80e90562abf06b28", + "assets/build/pylib-android/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/e3/e2/3ef58f0ffbf1e44f2290e7afb507", "assets/build/pylib-android/ctypes/_aix.py": "https://files.ballistica.net/cache/ba1/7b/ab/15a8d673206dbd15b7803f83ff58", "assets/build/pylib-android/ctypes/_endian.py": "https://files.ballistica.net/cache/ba1/4c/82/46e7f99faf6d1fac55192c5d06e1", "assets/build/pylib-android/ctypes/macholib/__init__.py": "https://files.ballistica.net/cache/ba1/44/d7/a915d5da7e8ef1030b43bb9b51ab", @@ -2644,32 +2648,32 @@ "assets/build/pylib-android/ctypes/macholib/framework.py": "https://files.ballistica.net/cache/ba1/86/80/861e32730cec812366d7d06f6185", "assets/build/pylib-android/ctypes/util.py": "https://files.ballistica.net/cache/ba1/a0/40/a64c0d63ffe76f3e04a74c145bc7", "assets/build/pylib-android/ctypes/wintypes.py": "https://files.ballistica.net/cache/ba1/48/c4/069f51da9b065dad73b199acb71b", - "assets/build/pylib-android/curses/__init__.py": "https://files.ballistica.net/cache/ba1/bf/c9/90630bb074e2c88e41e73a394862", + "assets/build/pylib-android/curses/__init__.py": "https://files.ballistica.net/cache/ba1/8a/96/a0fc5582125f7ebd8f3df4c15ebb", "assets/build/pylib-android/curses/ascii.py": "https://files.ballistica.net/cache/ba1/d9/f8/0a6587dae44d1694145b0dc96bc1", "assets/build/pylib-android/curses/has_key.py": "https://files.ballistica.net/cache/ba1/a0/10/afbfbd5688090da7ea41e933174b", "assets/build/pylib-android/curses/panel.py": "https://files.ballistica.net/cache/ba1/42/0f/580d5d6de90a64ade37f0a8e4696", "assets/build/pylib-android/curses/textpad.py": "https://files.ballistica.net/cache/ba1/a9/3f/ac729e39c1c9fcecd8e3525c7079", - "assets/build/pylib-android/dataclasses.py": "https://files.ballistica.net/cache/ba1/49/90/13ef1f264c8752f0ed1f6bab90d6", - "assets/build/pylib-android/datetime.py": "https://files.ballistica.net/cache/ba1/77/31/3fcc075c9834b07688f7900ae2bf", + "assets/build/pylib-android/dataclasses.py": "https://files.ballistica.net/cache/ba1/97/c8/24628bf4207b0ee2e29c1cd63fcf", + "assets/build/pylib-android/datetime.py": "https://files.ballistica.net/cache/ba1/6f/4c/3c6c3b8b25da5c3c9fdcce9d405b", "assets/build/pylib-android/decimal.py": "https://files.ballistica.net/cache/ba1/92/94/b8be378718b3ede8f05f07aa257b", - "assets/build/pylib-android/difflib.py": "https://files.ballistica.net/cache/ba1/6c/c2/0e781f8333593d5cb5890f702476", - "assets/build/pylib-android/dis.py": "https://files.ballistica.net/cache/ba1/a1/d1/7ccecfaa71f7cd43ce504eb53194", - "assets/build/pylib-android/doctest.py": "https://files.ballistica.net/cache/ba1/88/94/4e162825868d974768473472df54", + "assets/build/pylib-android/difflib.py": "https://files.ballistica.net/cache/ba1/bb/cf/6db21f4ed1982a8ee1337e12a8c1", + "assets/build/pylib-android/dis.py": "https://files.ballistica.net/cache/ba1/e0/cf/740c08618eb6c2e7c8cce3851a51", + "assets/build/pylib-android/doctest.py": "https://files.ballistica.net/cache/ba1/f7/33/cce48fd34ce6f6054e40c338c3ca", "assets/build/pylib-android/dummy_threading.py": "https://files.ballistica.net/cache/ba1/20/2f/ec8e68634908312148b53a5dfd4c", "assets/build/pylib-android/email/__init__.py": "https://files.ballistica.net/cache/ba1/2b/f0/8c85ab15e7cdbdaa0e1705223012", "assets/build/pylib-android/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/08/fa/de22bc96e1e332bbe1cf76162a1c", - "assets/build/pylib-android/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/9f/f5/17085d073d928ec6c0b8e37fcb95", + "assets/build/pylib-android/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/2d/c8/cbec982a4900ba1c15ea815624d7", "assets/build/pylib-android/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/e0/b3/b0167200b852c46e60116ba12740", "assets/build/pylib-android/email/_policybase.py": "https://files.ballistica.net/cache/ba1/19/f9/844a8a848bc5670a810d06f0a6de", "assets/build/pylib-android/email/base64mime.py": "https://files.ballistica.net/cache/ba1/6b/52/907171fcf7e3baf097a4d503d79c", - "assets/build/pylib-android/email/charset.py": "https://files.ballistica.net/cache/ba1/99/8c/c3da2c2a0f4cd1052a4e67b3451b", - "assets/build/pylib-android/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/b0/fa/00eade6999fa1d79e25cf29c773e", + "assets/build/pylib-android/email/charset.py": "https://files.ballistica.net/cache/ba1/a0/ba/c0b3f8daa9769adb9ba291937736", + "assets/build/pylib-android/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/d6/da/4125ae899a328aa5a3ddccb81cde", "assets/build/pylib-android/email/encoders.py": "https://files.ballistica.net/cache/ba1/7a/9c/eca8d9e60fa733457fc32facd2fe", "assets/build/pylib-android/email/errors.py": "https://files.ballistica.net/cache/ba1/8c/69/09c2e89bad6d5619cd4758db6bdd", "assets/build/pylib-android/email/feedparser.py": "https://files.ballistica.net/cache/ba1/98/6d/61c614d442ca8451320ca7fe4e86", "assets/build/pylib-android/email/generator.py": "https://files.ballistica.net/cache/ba1/c1/23/173f2e5fd02455bd2db0970c9ca0", "assets/build/pylib-android/email/header.py": "https://files.ballistica.net/cache/ba1/bb/cb/194570894c14063cd85ea2d8ab6a", - "assets/build/pylib-android/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/4b/d3/0240bedc7e23ba3e3022f6d2b87c", + "assets/build/pylib-android/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/44/93/a6b7f9a32043296668473e21997e", "assets/build/pylib-android/email/iterators.py": "https://files.ballistica.net/cache/ba1/a5/02/2f56787a3fb91547c61284d7facd", "assets/build/pylib-android/email/message.py": "https://files.ballistica.net/cache/ba1/9e/50/f42dc086f8eedac768907140cf75", "assets/build/pylib-android/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/42/fb/835abe12a4e1e72a5d1711d12cde", @@ -2684,9 +2688,9 @@ "assets/build/pylib-android/email/parser.py": "https://files.ballistica.net/cache/ba1/56/8f/cfad8593bd540c4c2d1b9ab9e133", "assets/build/pylib-android/email/policy.py": "https://files.ballistica.net/cache/ba1/a9/f3/301e5f1e73bed7a7bfa4a113ab14", "assets/build/pylib-android/email/quoprimime.py": "https://files.ballistica.net/cache/ba1/aa/32/7c1d81e4b7b757020947292f4031", - "assets/build/pylib-android/email/utils.py": "https://files.ballistica.net/cache/ba1/ab/db/68c123656453858a13b36ee8368f", - "assets/build/pylib-android/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/67/43/72e3d180a286fd22e897767e45ed", - "assets/build/pylib-android/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/83/c9/df2949267d12589775468200df40", + "assets/build/pylib-android/email/utils.py": "https://files.ballistica.net/cache/ba1/c2/f9/e2479bbc1b5957383614e197daf3", + "assets/build/pylib-android/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/dc/1a/1120389aa62a70fd5a669cab1dfc", + "assets/build/pylib-android/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/4c/10/6d8dd88e91acce8b8ad99b2f3fdf", "assets/build/pylib-android/encodings/ascii.py": "https://files.ballistica.net/cache/ba1/f6/30/d35b4c5d478856f618208177d679", "assets/build/pylib-android/encodings/base64_codec.py": "https://files.ballistica.net/cache/ba1/7f/03/88c0997433cffad3d142857389b8", "assets/build/pylib-android/encodings/big5.py": "https://files.ballistica.net/cache/ba1/3c/a3/0310d813b4a6822b0affdec62f00", @@ -2711,7 +2715,6 @@ "assets/build/pylib-android/encodings/cp424.py": "https://files.ballistica.net/cache/ba1/01/ae/24924c4383da3eea407dd9a76ce6", "assets/build/pylib-android/encodings/cp437.py": "https://files.ballistica.net/cache/ba1/11/44/0a615f0e2c8dd60863f351c25493", "assets/build/pylib-android/encodings/cp500.py": "https://files.ballistica.net/cache/ba1/b5/69/54dcc4070d53074fc8912b290160", - "assets/build/pylib-android/encodings/cp65001.py": "https://files.ballistica.net/cache/ba1/ad/a6/109385797cf2751d15a38a0fe909", "assets/build/pylib-android/encodings/cp720.py": "https://files.ballistica.net/cache/ba1/5d/f1/fd1d890b59934c857cc3f7ca6a4c", "assets/build/pylib-android/encodings/cp737.py": "https://files.ballistica.net/cache/ba1/85/b5/a9c80dfd08a1e52ebff80411998a", "assets/build/pylib-android/encodings/cp775.py": "https://files.ballistica.net/cache/ba1/8d/8f/21ec77013920bcd41253555b5474", @@ -2798,7 +2801,6 @@ "assets/build/pylib-android/encodings/tis_620.py": "https://files.ballistica.net/cache/ba1/c3/b4/fd078646ff6494baaf0453092c79", "assets/build/pylib-android/encodings/undefined.py": "https://files.ballistica.net/cache/ba1/09/43/e8b79735ec6bdc629c2a45264e8e", "assets/build/pylib-android/encodings/unicode_escape.py": "https://files.ballistica.net/cache/ba1/e6/32/eaa27c218dc93fa713f6c01141d9", - "assets/build/pylib-android/encodings/unicode_internal.py": "https://files.ballistica.net/cache/ba1/03/1c/30460b4b4542ccc9f7bb678592bd", "assets/build/pylib-android/encodings/utf_16.py": "https://files.ballistica.net/cache/ba1/e8/96/2999d7838c6ed0f435e3910ca1ee", "assets/build/pylib-android/encodings/utf_16_be.py": "https://files.ballistica.net/cache/ba1/c4/ee/77e5c5cb580218e139226a79416e", "assets/build/pylib-android/encodings/utf_16_le.py": "https://files.ballistica.net/cache/ba1/fe/89/c8a5cf4f08828b14a9911e2534a7", @@ -2810,151 +2812,151 @@ "assets/build/pylib-android/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/c5/56/c3d98c0cb4cf569fb833ed919cc1", "assets/build/pylib-android/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/f9/64/0107520eca9130ca870cec675bf0", "assets/build/pylib-android/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/b4/3f/7369ee7aa1aa36b098c3b33ea31b", - "assets/build/pylib-android/enum.py": "https://files.ballistica.net/cache/ba1/de/8f/09627b04f762c56e00c24cdd5c3f", + "assets/build/pylib-android/enum.py": "https://files.ballistica.net/cache/ba1/4a/00/37d26511042dbcf593d59286328c", "assets/build/pylib-android/filecmp.py": "https://files.ballistica.net/cache/ba1/54/d4/3d6d66bd7d4ee85407851fe986a0", - "assets/build/pylib-android/fileinput.py": "https://files.ballistica.net/cache/ba1/00/79/91b5218d122a5ede37fb0c821b22", + "assets/build/pylib-android/fileinput.py": "https://files.ballistica.net/cache/ba1/87/63/37392fb7eece4f1b010117205438", "assets/build/pylib-android/fnmatch.py": "https://files.ballistica.net/cache/ba1/d5/44/0a58d9161ae9d2409ae2477b5948", "assets/build/pylib-android/formatter.py": "https://files.ballistica.net/cache/ba1/8d/5e/9b9d7451083fbae7ee678ad8f51e", - "assets/build/pylib-android/fractions.py": "https://files.ballistica.net/cache/ba1/36/80/23d5c7f0ea189309e0b7e10fa86e", - "assets/build/pylib-android/ftplib.py": "https://files.ballistica.net/cache/ba1/3b/4f/055a7aa1c640ee3163992f99a4ba", - "assets/build/pylib-android/functools.py": "https://files.ballistica.net/cache/ba1/7c/3f/5c9e15f26ce747d1a37890e18640", - "assets/build/pylib-android/genericpath.py": "https://files.ballistica.net/cache/ba1/0e/6a/8fc3f6769f820b90d5b6c43e49df", + "assets/build/pylib-android/fractions.py": "https://files.ballistica.net/cache/ba1/62/07/d18fee429386d6e1f3cfa42884e0", + "assets/build/pylib-android/ftplib.py": "https://files.ballistica.net/cache/ba1/ed/58/61631b6f7097f6e06531ba9c4f04", + "assets/build/pylib-android/functools.py": "https://files.ballistica.net/cache/ba1/e7/0b/2a93172c587fc0f2c71802885221", + "assets/build/pylib-android/genericpath.py": "https://files.ballistica.net/cache/ba1/a4/d1/a132fc4c20d49468d9aee1667a18", "assets/build/pylib-android/getopt.py": "https://files.ballistica.net/cache/ba1/5c/25/34e54811bd07a3b7a15e60c67094", "assets/build/pylib-android/getpass.py": "https://files.ballistica.net/cache/ba1/76/37/f0df6882db44ee701aea35e235bb", - "assets/build/pylib-android/gettext.py": "https://files.ballistica.net/cache/ba1/76/6b/e08db748cbde1d300c69c3a844d2", - "assets/build/pylib-android/glob.py": "https://files.ballistica.net/cache/ba1/92/ce/6d2048bd82599fb386c8a439de58", - "assets/build/pylib-android/gzip.py": "https://files.ballistica.net/cache/ba1/83/fa/8e6c94112337bfb2b405d81328d2", - "assets/build/pylib-android/hashlib.py": "https://files.ballistica.net/cache/ba1/c6/5a/91b854e2bae475daed521a56319b", - "assets/build/pylib-android/heapq.py": "https://files.ballistica.net/cache/ba1/17/a3/02bee5cf92dbd2a1937056dbcb9c", - "assets/build/pylib-android/hmac.py": "https://files.ballistica.net/cache/ba1/08/7a/a9980f4c7dd15295192da2ff8033", + "assets/build/pylib-android/gettext.py": "https://files.ballistica.net/cache/ba1/30/f6/0cbdec6984d8bb4de4b8c12d3917", + "assets/build/pylib-android/glob.py": "https://files.ballistica.net/cache/ba1/9f/bb/02378daab858e94498b995d90e58", + "assets/build/pylib-android/gzip.py": "https://files.ballistica.net/cache/ba1/7c/81/2b86114f572713719b00eebc4fe7", + "assets/build/pylib-android/hashlib.py": "https://files.ballistica.net/cache/ba1/ae/a3/4bffbb609e9da7c1dab02c9d1bc0", + "assets/build/pylib-android/heapq.py": "https://files.ballistica.net/cache/ba1/63/79/bb9abc2fb3665fffc59e588aba1f", + "assets/build/pylib-android/hmac.py": "https://files.ballistica.net/cache/ba1/ce/4e/595b1539b0a8ea65e8c79afa6506", "assets/build/pylib-android/html/__init__.py": "https://files.ballistica.net/cache/ba1/63/0b/9695269a02f0ec6d8b2b928d1f3f", "assets/build/pylib-android/html/entities.py": "https://files.ballistica.net/cache/ba1/02/4d/e42a17593176e35ff5da8d720cf9", "assets/build/pylib-android/html/parser.py": "https://files.ballistica.net/cache/ba1/c7/87/628a5a87855afbac3ebbd858e9a1", - "assets/build/pylib-android/http/__init__.py": "https://files.ballistica.net/cache/ba1/93/8e/37eb6e0c8e0e85fbc817d9b7a7ac", - "assets/build/pylib-android/http/client.py": "https://files.ballistica.net/cache/ba1/91/76/10a31e7d6260da3f5cc290b14441", - "assets/build/pylib-android/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/79/72/6cb2162180eaec43445a53f3ee97", - "assets/build/pylib-android/http/cookies.py": "https://files.ballistica.net/cache/ba1/31/12/7d40c2be1ef8456a4abeb613d633", - "assets/build/pylib-android/http/server.py": "https://files.ballistica.net/cache/ba1/9e/b7/7c94874f5f3684a110923c113b65", - "assets/build/pylib-android/imghdr.py": "https://files.ballistica.net/cache/ba1/75/c7/58ca3c6b7706ffdf24c8eec8aaec", + "assets/build/pylib-android/http/__init__.py": "https://files.ballistica.net/cache/ba1/04/78/a177368f7a363b832b7aa700a24e", + "assets/build/pylib-android/http/client.py": "https://files.ballistica.net/cache/ba1/3e/69/1cd8c405c537b8d523b14ab6affa", + "assets/build/pylib-android/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/b1/a9/bf2b9d50cca20d3929dcd69a193f", + "assets/build/pylib-android/http/cookies.py": "https://files.ballistica.net/cache/ba1/b8/30/39a0e0ea03150efeb9fdd0c4f0f1", + "assets/build/pylib-android/http/server.py": "https://files.ballistica.net/cache/ba1/04/68/05482a7906eb8a4537fb591f2df9", + "assets/build/pylib-android/imghdr.py": "https://files.ballistica.net/cache/ba1/3d/d0/4f7452be4865bbf2e54e67fff577", "assets/build/pylib-android/imp.py": "https://files.ballistica.net/cache/ba1/76/c5/f35c903e1dd97bf22c1085a8284e", - "assets/build/pylib-android/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/e8/d4/1669dcd3db8c8050afd02771ad74", - "assets/build/pylib-android/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/39/f4/bd6822ee1fb17c9478100f69dfd5", - "assets/build/pylib-android/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/56/b4/ad41e4fa96c40b5fe7ee9bc961f5", + "assets/build/pylib-android/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/5e/ae/5efb7ab469b5d17c2ea79c50fcdf", + "assets/build/pylib-android/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/58/27/ef34e53df05321778b4a1d64f233", + "assets/build/pylib-android/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/f0/7d/66c18cd0ead3730530d9b02ae718", "assets/build/pylib-android/importlib/abc.py": "https://files.ballistica.net/cache/ba1/35/91/138b805ba19131c83fb9fa8cd5ae", "assets/build/pylib-android/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/a1/8f/18e6ff954af6e29a2c06701e426d", - "assets/build/pylib-android/importlib/resources.py": "https://files.ballistica.net/cache/ba1/6f/5f/01901b3cc59aa8e5e91e78bf62e9", + "assets/build/pylib-android/importlib/metadata.py": "https://files.ballistica.net/cache/ba1/bc/09/454c1f148b9b9b679bfe7382e267", + "assets/build/pylib-android/importlib/resources.py": "https://files.ballistica.net/cache/ba1/15/8c/53a8c444a47e76dde81052a0c41d", "assets/build/pylib-android/importlib/util.py": "https://files.ballistica.net/cache/ba1/74/6c/cf680cfd666f5e08fc17e1e02e21", - "assets/build/pylib-android/inspect.py": "https://files.ballistica.net/cache/ba1/91/29/9a58f7871ce7d9f87586d2e105ef", - "assets/build/pylib-android/io.py": "https://files.ballistica.net/cache/ba1/fa/0b/9a8c9ecdd79242fe6c5dd40f3784", - "assets/build/pylib-android/ipaddress.py": "https://files.ballistica.net/cache/ba1/1e/73/43ed03804d0553b409f9452d6a7e", - "assets/build/pylib-android/json/__init__.py": "https://files.ballistica.net/cache/ba1/8a/76/868c50cd60069c48f130f3a95fb7", + "assets/build/pylib-android/inspect.py": "https://files.ballistica.net/cache/ba1/18/06/354b659d76a3013d76c52173b48f", + "assets/build/pylib-android/io.py": "https://files.ballistica.net/cache/ba1/04/bf/435c1cef465b5f9f8b3a0e58aac2", + "assets/build/pylib-android/ipaddress.py": "https://files.ballistica.net/cache/ba1/e7/31/0dfc13e405aab44f7c0657dae937", + "assets/build/pylib-android/json/__init__.py": "https://files.ballistica.net/cache/ba1/ab/61/7360b1e8e05eae96ecc2614bc666", "assets/build/pylib-android/json/decoder.py": "https://files.ballistica.net/cache/ba1/3f/bf/6fd2a01d31cd85e4c21cf2c0a5c8", - "assets/build/pylib-android/json/encoder.py": "https://files.ballistica.net/cache/ba1/5f/36/b17803f0c2b18467b7d10e87e46d", + "assets/build/pylib-android/json/encoder.py": "https://files.ballistica.net/cache/ba1/91/e6/28d5bc7693037562877ff0ea08c5", "assets/build/pylib-android/json/scanner.py": "https://files.ballistica.net/cache/ba1/c8/4b/bcc458a5047e9ac8064a607ee231", - "assets/build/pylib-android/json/tool.py": "https://files.ballistica.net/cache/ba1/20/ac/edbfd1cabc47b3f3d57b37c95116", - "assets/build/pylib-android/keyword.py": "https://files.ballistica.net/cache/ba1/1d/8a/1cdb5840e8f561ec69407f898752", + "assets/build/pylib-android/json/tool.py": "https://files.ballistica.net/cache/ba1/d6/38/c65fcd6b76a399d0fb209e9e1130", + "assets/build/pylib-android/keyword.py": "https://files.ballistica.net/cache/ba1/7b/0d/514f7c437ade5881b923228db78d", "assets/build/pylib-android/linecache.py": "https://files.ballistica.net/cache/ba1/01/91/9aecf23d41972edd3bcb7927b1fe", "assets/build/pylib-android/locale.py": "https://files.ballistica.net/cache/ba1/ab/cf/da9a211a39662f631b6869e1c28b", - "assets/build/pylib-android/logging/__init__.py": "https://files.ballistica.net/cache/ba1/0d/d3/3460e7bd9309e2e09cbbac2c2f66", - "assets/build/pylib-android/logging/config.py": "https://files.ballistica.net/cache/ba1/14/a0/a315016fa0d6d748d204acde0c8d", - "assets/build/pylib-android/logging/handlers.py": "https://files.ballistica.net/cache/ba1/34/92/8a7b95239e1d0751e49fd01c2a21", + "assets/build/pylib-android/logging/__init__.py": "https://files.ballistica.net/cache/ba1/d5/e7/183d3a2ec1d6cfb277fc4b3b5127", + "assets/build/pylib-android/logging/config.py": "https://files.ballistica.net/cache/ba1/59/8b/cf4357716a774981a06b369e2074", + "assets/build/pylib-android/logging/handlers.py": "https://files.ballistica.net/cache/ba1/39/1d/09b83d3d4c22b804eb9c708e6574", "assets/build/pylib-android/lzma.py": "https://files.ballistica.net/cache/ba1/9c/2e/978f3aa52af60fce9a819dc7de7c", - "assets/build/pylib-android/macpath.py": "https://files.ballistica.net/cache/ba1/5c/d5/64f70a6aefd047187ab55eb0a239", - "assets/build/pylib-android/mailbox.py": "https://files.ballistica.net/cache/ba1/0a/2d/6a97623b1ced2b46c5a8c423bcef", + "assets/build/pylib-android/mailbox.py": "https://files.ballistica.net/cache/ba1/c7/5e/f3325f2bd78dcbffbfea6d9770fd", "assets/build/pylib-android/mailcap.py": "https://files.ballistica.net/cache/ba1/50/16/e34e153745925b34ce9038e3ea7f", - "assets/build/pylib-android/mimetypes.py": "https://files.ballistica.net/cache/ba1/19/08/5481aa7dca208be033099bbba366", - "assets/build/pylib-android/modulefinder.py": "https://files.ballistica.net/cache/ba1/0c/30/5e90e7723ca80176807ea7e41a95", + "assets/build/pylib-android/mimetypes.py": "https://files.ballistica.net/cache/ba1/49/c3/d46e03dd6ba50e8e2282ab22839a", + "assets/build/pylib-android/modulefinder.py": "https://files.ballistica.net/cache/ba1/84/08/24b4e6c420fec10ec3c2ea8c47da", "assets/build/pylib-android/netrc.py": "https://files.ballistica.net/cache/ba1/8f/80/36bb48bf9d57e4e5d2840bbc39ed", - "assets/build/pylib-android/nntplib.py": "https://files.ballistica.net/cache/ba1/68/3f/b1b40b66ab19e7674529236a75de", - "assets/build/pylib-android/ntpath.py": "https://files.ballistica.net/cache/ba1/69/86/c1b59b30cc6c61143e054fe4539c", + "assets/build/pylib-android/nntplib.py": "https://files.ballistica.net/cache/ba1/ed/e9/4fdac3b585199c036ca9e89b7f90", + "assets/build/pylib-android/ntpath.py": "https://files.ballistica.net/cache/ba1/86/46/129e6c4c896c2a48abc5294f3fb4", "assets/build/pylib-android/nturl2path.py": "https://files.ballistica.net/cache/ba1/b4/46/c374747761328b745d54c20fb2d4", "assets/build/pylib-android/numbers.py": "https://files.ballistica.net/cache/ba1/b3/ec/5cbca4da9a176673ac3502dfe3ce", - "assets/build/pylib-android/opcode.py": "https://files.ballistica.net/cache/ba1/a2/30/da96e8dba5f6b098839e1adb2e86", - "assets/build/pylib-android/operator.py": "https://files.ballistica.net/cache/ba1/03/ac/fc74fa2a3146b00f9ee1921996c5", - "assets/build/pylib-android/optparse.py": "https://files.ballistica.net/cache/ba1/56/b4/9ae8b02341d9b2b5c1a75d5f8729", - "assets/build/pylib-android/os.py": "https://files.ballistica.net/cache/ba1/d0/78/d8693c3a2c5c4684faadf46ebed5", - "assets/build/pylib-android/pathlib.py": "https://files.ballistica.net/cache/ba1/ee/4c/ae4cf6fa2e0b54aa42e26cbc6295", - "assets/build/pylib-android/pdb.py": "https://files.ballistica.net/cache/ba1/84/4f/9fc933776560b7e45cb7ef3bcfa9", - "assets/build/pylib-android/pickle.py": "https://files.ballistica.net/cache/ba1/81/cf/a94f6e8a45671c34c1d9d4efdc13", - "assets/build/pylib-android/pickletools.py": "https://files.ballistica.net/cache/ba1/c7/0a/1f89f5d71ccf1f9269cc5f8d3d72", + "assets/build/pylib-android/opcode.py": "https://files.ballistica.net/cache/ba1/65/7b/65f902a9c4e4ba7713e2af3fde5e", + "assets/build/pylib-android/operator.py": "https://files.ballistica.net/cache/ba1/f4/ff/f544ac0872105e67239d869102f5", + "assets/build/pylib-android/optparse.py": "https://files.ballistica.net/cache/ba1/0f/08/ec8ce5e48392a3f9bdc3c07f49cc", + "assets/build/pylib-android/os.py": "https://files.ballistica.net/cache/ba1/ae/a6/b92e148a97c42f68600fd8f5ff0a", + "assets/build/pylib-android/pathlib.py": "https://files.ballistica.net/cache/ba1/83/ca/16bb215695c952a809e3bf895c6b", + "assets/build/pylib-android/pdb.py": "https://files.ballistica.net/cache/ba1/35/87/b01440238b050fb386cd40b12be7", + "assets/build/pylib-android/pickle.py": "https://files.ballistica.net/cache/ba1/47/d1/5f7b853040812d8d8dd10ee8172a", + "assets/build/pylib-android/pickletools.py": "https://files.ballistica.net/cache/ba1/72/c5/182517538ac4e0c1b7d25bde80e4", "assets/build/pylib-android/pipes.py": "https://files.ballistica.net/cache/ba1/ed/d3/9e08e7ece839c58d885223c57adb", "assets/build/pylib-android/pkgutil.py": "https://files.ballistica.net/cache/ba1/3f/27/1c376bf997f3ee3a09c9ffdb58d6", - "assets/build/pylib-android/platform.py": "https://files.ballistica.net/cache/ba1/99/72/0d5d720f5936836937633e4cc54e", - "assets/build/pylib-android/plistlib.py": "https://files.ballistica.net/cache/ba1/ff/ca/c37a29df76785ad0bb6975627639", - "assets/build/pylib-android/poplib.py": "https://files.ballistica.net/cache/ba1/62/c4/c9a5a81583fcd7e7767ea6392ef4", - "assets/build/pylib-android/posixpath.py": "https://files.ballistica.net/cache/ba1/8c/52/9a1a9b00a9a4c12c8fd0bb840865", - "assets/build/pylib-android/pprint.py": "https://files.ballistica.net/cache/ba1/a4/1b/80825e9ec828d359a6fa06432c73", - "assets/build/pylib-android/profile.py": "https://files.ballistica.net/cache/ba1/0f/38/80e5c1933735939545d2f2bd5c4b", - "assets/build/pylib-android/pstats.py": "https://files.ballistica.net/cache/ba1/0f/a0/91174ec1a4bf59cbccdbf0ab9de6", - "assets/build/pylib-android/pty.py": "https://files.ballistica.net/cache/ba1/96/53/727538ed8a1ed56729d6732f4930", - "assets/build/pylib-android/py_compile.py": "https://files.ballistica.net/cache/ba1/d3/c0/4464545ef3eb1a6d29ab57099b13", - "assets/build/pylib-android/pyclbr.py": "https://files.ballistica.net/cache/ba1/ca/2d/70c81bfd320a52431b6e941198db", - "assets/build/pylib-android/pydoc.py": "https://files.ballistica.net/cache/ba1/15/f7/67affd41a830edfa22d087b213dd", - "assets/build/pylib-android/queue.py": "https://files.ballistica.net/cache/ba1/8c/f8/37f30b7f7500462869580f7eb14c", + "assets/build/pylib-android/platform.py": "https://files.ballistica.net/cache/ba1/2a/65/f358d875e6356bab841348b2a2c1", + "assets/build/pylib-android/plistlib.py": "https://files.ballistica.net/cache/ba1/3a/06/e5b474da39d2cdacf408aeb58235", + "assets/build/pylib-android/poplib.py": "https://files.ballistica.net/cache/ba1/07/e9/bd3185ee7e11fae8a93350f3c8ef", + "assets/build/pylib-android/posixpath.py": "https://files.ballistica.net/cache/ba1/4e/e0/74802bfb4ce50bf23b1fe082476f", + "assets/build/pylib-android/pprint.py": "https://files.ballistica.net/cache/ba1/c7/3d/79915a2f9a52402ad0165749f8a1", + "assets/build/pylib-android/profile.py": "https://files.ballistica.net/cache/ba1/f0/d9/233736935162a122506fd035be83", + "assets/build/pylib-android/pstats.py": "https://files.ballistica.net/cache/ba1/b2/50/e30c565b911c493f7297b447df96", + "assets/build/pylib-android/pty.py": "https://files.ballistica.net/cache/ba1/24/e7/674146721384259bfbbc196a59e6", + "assets/build/pylib-android/py_compile.py": "https://files.ballistica.net/cache/ba1/54/5b/d7f8dde4e8b1fd84ac106d077fc1", + "assets/build/pylib-android/pyclbr.py": "https://files.ballistica.net/cache/ba1/8a/0e/2fc7f524cbc1101d488c1a0c570f", + "assets/build/pylib-android/pydoc.py": "https://files.ballistica.net/cache/ba1/9e/1d/1c472858412cfa24f33d5228154a", + "assets/build/pylib-android/queue.py": "https://files.ballistica.net/cache/ba1/12/26/24837026ac4db0a65d099dfefc69", "assets/build/pylib-android/quopri.py": "https://files.ballistica.net/cache/ba1/f3/08/1d7b3e0f7ce1ad649b1abf08f8ac", - "assets/build/pylib-android/random.py": "https://files.ballistica.net/cache/ba1/f3/8e/b752b23583b23a38bb15cb176522", - "assets/build/pylib-android/re.py": "https://files.ballistica.net/cache/ba1/d2/41/e4c70d2365338a2c378f55920849", + "assets/build/pylib-android/random.py": "https://files.ballistica.net/cache/ba1/64/96/9262809205b823d80a1d3200cb94", + "assets/build/pylib-android/re.py": "https://files.ballistica.net/cache/ba1/59/e4/9022fc5507d9f81c023489d12bea", "assets/build/pylib-android/reprlib.py": "https://files.ballistica.net/cache/ba1/81/66/44ee9dceee6943006c4500ee3303", "assets/build/pylib-android/rlcompleter.py": "https://files.ballistica.net/cache/ba1/fe/06/6f06102f9f6c8c0e73a33714c25a", - "assets/build/pylib-android/runpy.py": "https://files.ballistica.net/cache/ba1/6b/e1/0453f97c2fcc323bf89989a74974", + "assets/build/pylib-android/runpy.py": "https://files.ballistica.net/cache/ba1/b2/76/1bf2d61d8494da2aeb4280144b2f", "assets/build/pylib-android/sched.py": "https://files.ballistica.net/cache/ba1/c7/c2/12fe5b57f846e1c9d4c75ee89d91", "assets/build/pylib-android/secrets.py": "https://files.ballistica.net/cache/ba1/b2/b0/b1a5252c6b75183471c11a4dbfb6", "assets/build/pylib-android/selectors.py": "https://files.ballistica.net/cache/ba1/77/2d/f195a32136d7aee6e17169e88b50", "assets/build/pylib-android/shelve.py": "https://files.ballistica.net/cache/ba1/8b/de/eca086cf73d1c9c823472de06a4c", - "assets/build/pylib-android/shlex.py": "https://files.ballistica.net/cache/ba1/2d/61/e67671fd85fe708733abdb009f59", - "assets/build/pylib-android/shutil.py": "https://files.ballistica.net/cache/ba1/ad/40/773116c0f86e1d848907f98b094c", - "assets/build/pylib-android/signal.py": "https://files.ballistica.net/cache/ba1/7a/94/647bd60815c91a093c853697b24d", - "assets/build/pylib-android/site.py": "https://files.ballistica.net/cache/ba1/7f/83/ee02875f9e9b64d264e4da388f08", + "assets/build/pylib-android/shlex.py": "https://files.ballistica.net/cache/ba1/d1/90/427ebd18132790c4b80ca7f0062a", + "assets/build/pylib-android/shutil.py": "https://files.ballistica.net/cache/ba1/8a/eb/b7e522ec6ec54024720638311e9a", + "assets/build/pylib-android/signal.py": "https://files.ballistica.net/cache/ba1/c1/e6/42f7446c4290ebf789e9d5d572e9", + "assets/build/pylib-android/site.py": "https://files.ballistica.net/cache/ba1/99/99/9f9631f0dcbe462ea076f63ea87a", "assets/build/pylib-android/smtpd.py": "https://files.ballistica.net/cache/ba1/ca/b1/59cd5236b8614b142c1c30f3d826", - "assets/build/pylib-android/smtplib.py": "https://files.ballistica.net/cache/ba1/cd/0c/af75196d61997cfb156a22018486", - "assets/build/pylib-android/sndhdr.py": "https://files.ballistica.net/cache/ba1/05/f2/858cf19617b9c92ce695791f7959", - "assets/build/pylib-android/socket.py": "https://files.ballistica.net/cache/ba1/02/1d/32662398f0d7e60ec9f910e62db4", + "assets/build/pylib-android/smtplib.py": "https://files.ballistica.net/cache/ba1/22/08/1223659e5797590e0725558b530e", + "assets/build/pylib-android/sndhdr.py": "https://files.ballistica.net/cache/ba1/d8/db/7f9e8c520cd68d3cf3308e3a9923", + "assets/build/pylib-android/socket.py": "https://files.ballistica.net/cache/ba1/1a/9e/d4ab190486a0e5fde8c165d76537", "assets/build/pylib-android/socketserver.py": "https://files.ballistica.net/cache/ba1/ee/5d/ff8d1e8000d294430919d854bfd4", "assets/build/pylib-android/sqlite3/__init__.py": "https://files.ballistica.net/cache/ba1/59/0c/ad2f1115231791e81b99f42bde59", "assets/build/pylib-android/sqlite3/dbapi2.py": "https://files.ballistica.net/cache/ba1/ba/45/70cc4fba245a1394b832240cd706", "assets/build/pylib-android/sqlite3/dump.py": "https://files.ballistica.net/cache/ba1/1c/d8/dc3fb256cbb05c8fffb52c52404a", - "assets/build/pylib-android/sre_compile.py": "https://files.ballistica.net/cache/ba1/3c/25/d88e4e0441c6a1a3f834a69e206f", - "assets/build/pylib-android/sre_constants.py": "https://files.ballistica.net/cache/ba1/6e/ef/5edaf33455de288d0619bd86f843", - "assets/build/pylib-android/sre_parse.py": "https://files.ballistica.net/cache/ba1/6d/47/a07a9102eaf21db32c5b512c5481", - "assets/build/pylib-android/ssl.py": "https://files.ballistica.net/cache/ba1/6d/07/ae83994da76b3709d2089175f632", - "assets/build/pylib-android/stat.py": "https://files.ballistica.net/cache/ba1/05/d9/57b564b0b1bda696753790568e50", - "assets/build/pylib-android/statistics.py": "https://files.ballistica.net/cache/ba1/0e/86/79fd4e3236d78c9a3e3624efc49f", - "assets/build/pylib-android/string.py": "https://files.ballistica.net/cache/ba1/b3/a4/ac5ce6361b4e350127bed3d9b66b", + "assets/build/pylib-android/sre_compile.py": "https://files.ballistica.net/cache/ba1/96/3a/830deabdb104a1d219f88ad9c090", + "assets/build/pylib-android/sre_constants.py": "https://files.ballistica.net/cache/ba1/87/9d/78b7e287798d388ac700586308ce", + "assets/build/pylib-android/sre_parse.py": "https://files.ballistica.net/cache/ba1/43/8a/41140a5502c31bbf238181ccf581", + "assets/build/pylib-android/ssl.py": "https://files.ballistica.net/cache/ba1/b8/4f/0a8be5651fd60986028dc9e60215", + "assets/build/pylib-android/stat.py": "https://files.ballistica.net/cache/ba1/03/1d/acbfa83d8d94d8a483c6a884b589", + "assets/build/pylib-android/statistics.py": "https://files.ballistica.net/cache/ba1/75/f2/4ce33352d4242c35554604908f43", + "assets/build/pylib-android/string.py": "https://files.ballistica.net/cache/ba1/52/bb/04d8688ce0acb53fef74b1cedaa4", "assets/build/pylib-android/stringprep.py": "https://files.ballistica.net/cache/ba1/20/41/fcfc5f510286ead5f7f4678ac9ec", "assets/build/pylib-android/struct.py": "https://files.ballistica.net/cache/ba1/37/67/74dea8e8f3831e802c3b5288e901", - "assets/build/pylib-android/subprocess.py": "https://files.ballistica.net/cache/ba1/f6/bf/640ac9ceb0e3d7cfbe02bef64557", + "assets/build/pylib-android/subprocess.py": "https://files.ballistica.net/cache/ba1/39/92/11fe2953e9ae13120ebaebea19d1", "assets/build/pylib-android/sunau.py": "https://files.ballistica.net/cache/ba1/ff/0e/1a6c5fd41803511cad28595dc248", - "assets/build/pylib-android/symbol.py": "https://files.ballistica.net/cache/ba1/a5/26/eea6d483c82e7b4048937832889d", - "assets/build/pylib-android/symtable.py": "https://files.ballistica.net/cache/ba1/e0/43/5390cbe7195d9edcddbbd2aa1cfa", - "assets/build/pylib-android/sysconfig.py": "https://files.ballistica.net/cache/ba1/9b/d7/6b01292e81749e4d3fd2bf762f7f", + "assets/build/pylib-android/symbol.py": "https://files.ballistica.net/cache/ba1/47/71/61a7a88103ae16c177bf03953f5f", + "assets/build/pylib-android/symtable.py": "https://files.ballistica.net/cache/ba1/19/e4/42f6d4096c880e51bbe06790f846", + "assets/build/pylib-android/sysconfig.py": "https://files.ballistica.net/cache/ba1/dc/ff/69dda6b350888a7dc962a287f641", "assets/build/pylib-android/tabnanny.py": "https://files.ballistica.net/cache/ba1/f3/7e/b463d5f4ead23d34a36d0e559447", - "assets/build/pylib-android/tarfile.py": "https://files.ballistica.net/cache/ba1/46/a6/9d1a46c06d7b5e787efbfeadec05", - "assets/build/pylib-android/telnetlib.py": "https://files.ballistica.net/cache/ba1/60/28/4aab22dece4896a4d32694bbe282", - "assets/build/pylib-android/tempfile.py": "https://files.ballistica.net/cache/ba1/03/07/434e753d91b18bbbd9b1c7640ce8", + "assets/build/pylib-android/tarfile.py": "https://files.ballistica.net/cache/ba1/d5/18/6d68a7178542369d63954b2ed4fe", + "assets/build/pylib-android/telnetlib.py": "https://files.ballistica.net/cache/ba1/a5/81/6133a7707e3de363ddc642944e52", + "assets/build/pylib-android/tempfile.py": "https://files.ballistica.net/cache/ba1/f8/a0/35899db755f634fa201d2e33a181", "assets/build/pylib-android/textwrap.py": "https://files.ballistica.net/cache/ba1/4c/4b/c743c5e7427b00f428c318a9673b", "assets/build/pylib-android/this.py": "https://files.ballistica.net/cache/ba1/a8/fa/4d1152b689d75bc1a997ff34b799", - "assets/build/pylib-android/threading.py": "https://files.ballistica.net/cache/ba1/11/3a/cdb3194846494446ed43bf6d0050", + "assets/build/pylib-android/threading.py": "https://files.ballistica.net/cache/ba1/77/4f/e025ea812a09965cdc395e86ceb9", "assets/build/pylib-android/timeit.py": "https://files.ballistica.net/cache/ba1/55/7b/f7ef83f08ac5cb36ddaff03ac6ab", - "assets/build/pylib-android/token.py": "https://files.ballistica.net/cache/ba1/2d/f8/943c252465b687a5bc367315432f", - "assets/build/pylib-android/tokenize.py": "https://files.ballistica.net/cache/ba1/07/cc/13a7ec5c4d674ab025cb19186f7c", - "assets/build/pylib-android/trace.py": "https://files.ballistica.net/cache/ba1/9b/9d/d6806d339c36bfc6a2b4769688e0", - "assets/build/pylib-android/traceback.py": "https://files.ballistica.net/cache/ba1/fe/d7/2f880598e52c5c28a46df0ba0555", + "assets/build/pylib-android/token.py": "https://files.ballistica.net/cache/ba1/1e/2e/d0c88f9d6ae92bb1fae7167aaba7", + "assets/build/pylib-android/tokenize.py": "https://files.ballistica.net/cache/ba1/72/3b/51cb704606f892e099c2e350e346", + "assets/build/pylib-android/trace.py": "https://files.ballistica.net/cache/ba1/2f/da/847f827b3e048f2b96d6c657bbe4", + "assets/build/pylib-android/traceback.py": "https://files.ballistica.net/cache/ba1/d6/05/4c6b29b0c59ba1ed3e98a9a2eec3", "assets/build/pylib-android/tracemalloc.py": "https://files.ballistica.net/cache/ba1/46/49/5683d0d9e0e342392361adb6e9a3", "assets/build/pylib-android/tty.py": "https://files.ballistica.net/cache/ba1/ad/19/a6ad29b8958fa9f5acc3cf71d3b2", - "assets/build/pylib-android/types.py": "https://files.ballistica.net/cache/ba1/b9/5d/5467b37ac0f36b2ff4dd8ef458fd", - "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/de/0e/4506f09141585ca5fa94c90cf678", + "assets/build/pylib-android/types.py": "https://files.ballistica.net/cache/ba1/15/8d/824df2b7a8d28811d23ee5dcbc9f", + "assets/build/pylib-android/typing.py": "https://files.ballistica.net/cache/ba1/4b/fe/17a1c5c37ea805a5c725551ee3f1", "assets/build/pylib-android/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/b0/56/87601ed47a5181d1e6a40eb4ea40", "assets/build/pylib-android/urllib/error.py": "https://files.ballistica.net/cache/ba1/07/8c/573897fc3bdc6d3e2e8d449f17c7", - "assets/build/pylib-android/urllib/parse.py": "https://files.ballistica.net/cache/ba1/14/09/ffed6f45250b0b2dc1a86f3eb700", - "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/d7/3e/bba38f3fc5c737cef80f48f69184", + "assets/build/pylib-android/urllib/parse.py": "https://files.ballistica.net/cache/ba1/ee/70/230466b11df30aa2e2c8c75e5202", + "assets/build/pylib-android/urllib/request.py": "https://files.ballistica.net/cache/ba1/c2/54/ab2931f322777af8076824b913c1", "assets/build/pylib-android/urllib/response.py": "https://files.ballistica.net/cache/ba1/c4/d5/676a8e9fc4f7bd21ac2f555fc3fc", - "assets/build/pylib-android/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/c7/a8/487a1aeccfbf4370fdb33b136b51", + "assets/build/pylib-android/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/a4/52/f0d03835bb08e08195aeebd05e04", "assets/build/pylib-android/uu.py": "https://files.ballistica.net/cache/ba1/a1/89/070ed8553858a75fcafae4b7bd37", - "assets/build/pylib-android/uuid.py": "https://files.ballistica.net/cache/ba1/6e/d5/cf315a28420c9f6bd5a95acd116d", - "assets/build/pylib-android/warnings.py": "https://files.ballistica.net/cache/ba1/74/1f/097efcf5f38c0b41fcba3f60b44d", + "assets/build/pylib-android/uuid.py": "https://files.ballistica.net/cache/ba1/8b/e8/41a9b606c415fe9d49df108b8543", + "assets/build/pylib-android/warnings.py": "https://files.ballistica.net/cache/ba1/23/25/0ed7968cb91c285e031fa93614db", "assets/build/pylib-android/wave.py": "https://files.ballistica.net/cache/ba1/f8/72/9e060ca777991ea45d71eed336ca", - "assets/build/pylib-android/weakref.py": "https://files.ballistica.net/cache/ba1/d2/48/f82fb97686199616e57417ee9e7a", - "assets/build/pylib-android/webbrowser.py": "https://files.ballistica.net/cache/ba1/26/4a/b0ee4c8655e2c8ea7389d3a2b329", + "assets/build/pylib-android/weakref.py": "https://files.ballistica.net/cache/ba1/14/4e/fbb121e9cfb74cdb2084e1fbb8d5", + "assets/build/pylib-android/webbrowser.py": "https://files.ballistica.net/cache/ba1/98/42/67ccc4fa2b1a59b02ef3412c6eb2", "assets/build/pylib-android/xdrlib.py": "https://files.ballistica.net/cache/ba1/ec/bf/84d830dca1231ec1a67d8ccbb21f", "assets/build/pylib-android/xml/__init__.py": "https://files.ballistica.net/cache/ba1/ba/67/bbd97e53f3db5ebc3abd3fef2275", "assets/build/pylib-android/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/36/76/2a47e7bc727db1c44d157b23d2c3", @@ -2962,106 +2964,111 @@ "assets/build/pylib-android/xml/dom/domreg.py": "https://files.ballistica.net/cache/ba1/db/f3/81553e1167748f7d22152ac83eba", "assets/build/pylib-android/xml/dom/expatbuilder.py": "https://files.ballistica.net/cache/ba1/18/79/cd302655dc15d49e3617a71966dc", "assets/build/pylib-android/xml/dom/minicompat.py": "https://files.ballistica.net/cache/ba1/27/a6/6caea719e99063ca274ba3dd9883", - "assets/build/pylib-android/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/e7/37/3c51b8c3797c11f2322dcb9db747", - "assets/build/pylib-android/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/59/64/2d3ab8aaf26c30d388832022b333", + "assets/build/pylib-android/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/69/e1/4ca8a5cd1c35dc93873b5d7f89c5", + "assets/build/pylib-android/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/69/93/695baf453ca1030e7f6a62eb977b", "assets/build/pylib-android/xml/dom/xmlbuilder.py": "https://files.ballistica.net/cache/ba1/6a/80/e9447455e3df06a8dea4ca762c05", "assets/build/pylib-android/xml/etree/ElementInclude.py": "https://files.ballistica.net/cache/ba1/2d/1f/dfb4d40f1edca9a6c4547946258b", - "assets/build/pylib-android/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/06/c0/a1cee53843420f8e60179aca95de", - "assets/build/pylib-android/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/50/1a/ca752ab9a81e914c3176776ae809", + "assets/build/pylib-android/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/7f/ee/475112162331092c87710dde95ac", + "assets/build/pylib-android/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/4f/d9/72db97951ff40cdf3fa18a1a3f78", "assets/build/pylib-android/xml/etree/__init__.py": "https://files.ballistica.net/cache/ba1/98/0c/80c528bd3fe3e658da076d08071e", "assets/build/pylib-android/xml/etree/cElementTree.py": "https://files.ballistica.net/cache/ba1/6f/39/4c840e5eb0e09f709569154159ba", "assets/build/pylib-android/xml/parsers/__init__.py": "https://files.ballistica.net/cache/ba1/db/92/7283051e5e1c7426985835f506b9", "assets/build/pylib-android/xml/parsers/expat.py": "https://files.ballistica.net/cache/ba1/39/6c/fac98453c28f626916837c8a1e6b", - "assets/build/pylib-android/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/b0/ec/7773819ffec5390afd9c025198b3", + "assets/build/pylib-android/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/d5/5d/6631d2cabb6d5d3de794a1cf8f30", "assets/build/pylib-android/xml/sax/_exceptions.py": "https://files.ballistica.net/cache/ba1/2c/42/ba99070cafd736b165b825f1df53", "assets/build/pylib-android/xml/sax/expatreader.py": "https://files.ballistica.net/cache/ba1/8f/58/dce938bf4dcf1e240206c88e903e", "assets/build/pylib-android/xml/sax/handler.py": "https://files.ballistica.net/cache/ba1/3c/9a/d4295144949f697e57545aff741b", - "assets/build/pylib-android/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/b6/1f/08020c73bc0273890fa58b4852cc", + "assets/build/pylib-android/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/13/27/66fe0ad3aa764ba65643f5fcbc37", "assets/build/pylib-android/xml/sax/xmlreader.py": "https://files.ballistica.net/cache/ba1/0d/90/edc37e1a4f436d853c6d90263ae3", "assets/build/pylib-android/xmlrpc/__init__.py": "https://files.ballistica.net/cache/ba1/fd/fd/acc2dbaec2abc4a76071ce7ed7ab", - "assets/build/pylib-android/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/67/60/b274831b61da37a578d38addb1a9", + "assets/build/pylib-android/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/da/48/e65c0e5eb49e3e5087866339f7e3", "assets/build/pylib-android/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/bd/3d/3771b879aad270172509a740aa80", "assets/build/pylib-android/zipapp.py": "https://files.ballistica.net/cache/ba1/40/ae/178305c27d72cc46ad2220b504ec", - "assets/build/pylib-android/zipfile.py": "https://files.ballistica.net/cache/ba1/62/46/dda05f55a31402c8a1db3852a12c", - "assets/build/pylib-apple/__future__.py": "https://files.ballistica.net/cache/ba1/bb/90/4755b7f49a7ff19718d174b1f1ea", + "assets/build/pylib-android/zipfile.py": "https://files.ballistica.net/cache/ba1/b3/b7/72bfe20298162e5a7d84ba775713", + "assets/build/pylib-android/zipimport.py": "https://files.ballistica.net/cache/ba1/99/2a/462d3c6a266d9e4ebdb887a99ae6", + "assets/build/pylib-apple/__future__.py": "https://files.ballistica.net/cache/ba1/99/0b/6fc3ba5dd9d9dad46907077bb6ef", "assets/build/pylib-apple/__phello__.foo.py": "https://files.ballistica.net/cache/ba1/c1/42/8c4e5889af4acd69a6e866ea360f", "assets/build/pylib-apple/_bootlocale.py": "https://files.ballistica.net/cache/ba1/15/7e/07e0a6fcaf9fca6354453f7d09fa", - "assets/build/pylib-apple/_collections_abc.py": "https://files.ballistica.net/cache/ba1/fb/89/cb601480f97b0e7e90b4de9ea105", + "assets/build/pylib-apple/_collections_abc.py": "https://files.ballistica.net/cache/ba1/fc/ba/022abfd65bf601ad4094eb051c62", "assets/build/pylib-apple/_compat_pickle.py": "https://files.ballistica.net/cache/ba1/5a/19/9dbf1e881a6483e3a268e5f8ea7d", "assets/build/pylib-apple/_compression.py": "https://files.ballistica.net/cache/ba1/c6/06/a4e9cc0e17800d71f6536d27976d", "assets/build/pylib-apple/_dummy_thread.py": "https://files.ballistica.net/cache/ba1/ca/6b/94c4270a794a3dd9144eac36ba70", "assets/build/pylib-apple/_markupbase.py": "https://files.ballistica.net/cache/ba1/06/64/d7715998bc60bfd5235f96b1a779", - "assets/build/pylib-apple/_osx_support.py": "https://files.ballistica.net/cache/ba1/0d/a6/91bbc7f4ec229327c92ab11b096d", - "assets/build/pylib-apple/_py_abc.py": "https://files.ballistica.net/cache/ba1/1c/5c/a9fd7d6a37d72eacde407a919fd2", - "assets/build/pylib-apple/_pydecimal.py": "https://files.ballistica.net/cache/ba1/d9/61/6db82a7db9a9802eeb7186194014", - "assets/build/pylib-apple/_pyio.py": "https://files.ballistica.net/cache/ba1/eb/50/29e2234098f0db705aad0f1d2ce5", + "assets/build/pylib-apple/_osx_support.py": "https://files.ballistica.net/cache/ba1/4d/3c/5a86fa537a2101d34076a72d0460", + "assets/build/pylib-apple/_py_abc.py": "https://files.ballistica.net/cache/ba1/be/e3/d1030ff81e5440dc12c13a6730f7", + "assets/build/pylib-apple/_pydecimal.py": "https://files.ballistica.net/cache/ba1/c2/6b/9fb0fb2b25247a6d68939f5d6ed5", + "assets/build/pylib-apple/_pyio.py": "https://files.ballistica.net/cache/ba1/41/de/afbd4243267e690fe1588b49db4c", "assets/build/pylib-apple/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/3b/91/55e882376c694fefc106067d0b3b", - "assets/build/pylib-apple/_strptime.py": "https://files.ballistica.net/cache/ba1/d3/f5/e8851ba114168136272f4c5d142e", - "assets/build/pylib-apple/_threading_local.py": "https://files.ballistica.net/cache/ba1/7b/84/d75d00471052f6e251caf2fb8eb7", - "assets/build/pylib-apple/_weakrefset.py": "https://files.ballistica.net/cache/ba1/6e/76/8db5a64d1139a55923158d29229b", - "assets/build/pylib-apple/abc.py": "https://files.ballistica.net/cache/ba1/05/7f/90b81479761f633beb1751bad027", + "assets/build/pylib-apple/_strptime.py": "https://files.ballistica.net/cache/ba1/7f/b5/8867817306aea16b94f613a26b93", + "assets/build/pylib-apple/_threading_local.py": "https://files.ballistica.net/cache/ba1/94/a6/3e202c4309c356baf71a34e9325e", + "assets/build/pylib-apple/_weakrefset.py": "https://files.ballistica.net/cache/ba1/2a/9c/f9cca37dc1131dd602c5b96a2312", + "assets/build/pylib-apple/abc.py": "https://files.ballistica.net/cache/ba1/dd/25/65dc23811a08b2445492e9f9d8e3", "assets/build/pylib-apple/aifc.py": "https://files.ballistica.net/cache/ba1/a3/50/aab369de7f1c182e54878faabd6a", "assets/build/pylib-apple/antigravity.py": "https://files.ballistica.net/cache/ba1/72/dc/84c9bb5f53db3ffbb81fac16b5be", - "assets/build/pylib-apple/argparse.py": "https://files.ballistica.net/cache/ba1/29/b8/067047e0a33be200a6a515e138a8", - "assets/build/pylib-apple/ast.py": "https://files.ballistica.net/cache/ba1/60/dd/6fd420ffc9156f54fb4fc5f7b753", + "assets/build/pylib-apple/argparse.py": "https://files.ballistica.net/cache/ba1/0a/c2/5cdf93f738b653523e371e91013f", + "assets/build/pylib-apple/ast.py": "https://files.ballistica.net/cache/ba1/b5/19/eaaf8461fdfe76eaca65c00097e7", "assets/build/pylib-apple/asynchat.py": "https://files.ballistica.net/cache/ba1/af/53/8002843655550b707f97b0aef513", - "assets/build/pylib-apple/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/67/54/3680c6d920cad0475d3f75f44688", - "assets/build/pylib-apple/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/3d/0b/e197b883f420b0f8f9ae89d68505", - "assets/build/pylib-apple/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/1f/5e/13cd4e323a6a7468c048a0279d84", - "assets/build/pylib-apple/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/21/8d/9cbca0cea8e700d27a09d120fcc1", - "assets/build/pylib-apple/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/3a/dc/1214dddea378aa08daffdb7e786b", + "assets/build/pylib-apple/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/b1/da/6206890af9505a246cc7a20d5d66", + "assets/build/pylib-apple/asyncio/__main__.py": "https://files.ballistica.net/cache/ba1/10/db/493c9bfaae1f8953435bf7aed8d2", + "assets/build/pylib-apple/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/eb/d3/3a958257fa4133116c01aa1bfd6f", + "assets/build/pylib-apple/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/45/ef/3f273a6f9501a58529296c24fe9b", + "assets/build/pylib-apple/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/88/cc/f422549995be43e7b17d9830ee38", + "assets/build/pylib-apple/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/c5/8f/0a5cbd7b5a6f2c8531af87a09469", "assets/build/pylib-apple/asyncio/constants.py": "https://files.ballistica.net/cache/ba1/bc/0e/b8a63e47d3d3d73b198bf52019e5", - "assets/build/pylib-apple/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/be/a4/a2740c153d0159440ab3508416ba", - "assets/build/pylib-apple/asyncio/events.py": "https://files.ballistica.net/cache/ba1/61/48/2e31bf45d9d065f9b7b179fd6b06", + "assets/build/pylib-apple/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/c3/d7/e58784180e8e61785d455f7e3679", + "assets/build/pylib-apple/asyncio/events.py": "https://files.ballistica.net/cache/ba1/e9/f2/6b48f0f6bda10450e901ccd72f88", + "assets/build/pylib-apple/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/a0/84/30400eb95e74a2109a2e93f96c84", "assets/build/pylib-apple/asyncio/format_helpers.py": "https://files.ballistica.net/cache/ba1/2d/0c/03cf213d7bc7bcc0a6ee0e7310dc", - "assets/build/pylib-apple/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/c5/86/8e5295feb2ea5ed6ac89f1e7bc1b", - "assets/build/pylib-apple/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/b4/21/8e810b1fcb8f9c6d826d623a3ddd", + "assets/build/pylib-apple/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/ef/69/ab54b22da528d7146cab1a00c2c1", + "assets/build/pylib-apple/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/ea/3c/7ac33a578ac25ca376a60bb59603", "assets/build/pylib-apple/asyncio/log.py": "https://files.ballistica.net/cache/ba1/0f/5a/f419c17cbe08eddfa90f314b8a6c", - "assets/build/pylib-apple/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/af/57/876d9954115606b8c5691f6ac606", - "assets/build/pylib-apple/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/82/bb/ada2cdf128d95bb136b5dc42765f", - "assets/build/pylib-apple/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/f9/d1/9e79917b0753e0e5be304ff6882e", + "assets/build/pylib-apple/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/12/a7/0f2c2cfdba36781166836ac9f392", + "assets/build/pylib-apple/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/ea/73/2b77a852d18c2fe98e291552efca", + "assets/build/pylib-apple/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/c4/17/7336ec7c6b3c65724008ebd96b0a", "assets/build/pylib-apple/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/f3/c4/1562c4242e6beac4ded50d512ee4", - "assets/build/pylib-apple/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/76/2b/410a13efdcbae269342c2c26c1c0", - "assets/build/pylib-apple/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/03/1a/57c4fe04e2becc42f35140bcefc7", - "assets/build/pylib-apple/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/e9/8d/a22fb5db3f0837476273ba3099bd", - "assets/build/pylib-apple/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/c8/4e/f1e57ebfa8ddb3e5f57f3b5465cb", - "assets/build/pylib-apple/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/6f/fa/cc3af4a3bb5fc10a15f10220102b", - "assets/build/pylib-apple/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/4c/79/d4bd7bab30caf850673f700bb92e", - "assets/build/pylib-apple/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/b7/d5/3600caefd31f76cd812c77880812", - "assets/build/pylib-apple/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/47/6d/08eb442641ad579db371699d8247", - "assets/build/pylib-apple/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/87/0a/f0cc4e03e7c3b8fb1b50fe6699fe", - "assets/build/pylib-apple/asyncore.py": "https://files.ballistica.net/cache/ba1/2b/72/df815a3b340e40f3f1cac9e54f7c", + "assets/build/pylib-apple/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/c2/eb/f5ca6bba3915a5ed4de714b1c30a", + "assets/build/pylib-apple/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/2d/c1/29a029f52f3b8049eea1d3f86b35", + "assets/build/pylib-apple/asyncio/staggered.py": "https://files.ballistica.net/cache/ba1/92/3a/0de93c93afe7311a68a615fb2b97", + "assets/build/pylib-apple/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/0c/e6/e52c7358eaa4a30fd6d8bbde94b8", + "assets/build/pylib-apple/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/98/e4/5b002decc44112664cf6526da71a", + "assets/build/pylib-apple/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/2d/eb/5328cec55b04544de1e533ff493a", + "assets/build/pylib-apple/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/31/cc/5460085d8f6659a5c88114026688", + "assets/build/pylib-apple/asyncio/trsock.py": "https://files.ballistica.net/cache/ba1/19/74/be437ee7d795f7c6106ef8fbf2db", + "assets/build/pylib-apple/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/20/0a/68fafab7f6d7f30fc5af5274b55a", + "assets/build/pylib-apple/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/40/76/59e334068588234d5a33c2879d1c", + "assets/build/pylib-apple/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/c3/9a/4bc6c5e7ffe8c0298bbae63157c0", + "assets/build/pylib-apple/asyncore.py": "https://files.ballistica.net/cache/ba1/f0/6a/4573904ec9cac4fd3155e80d5959", "assets/build/pylib-apple/base64.py": "https://files.ballistica.net/cache/ba1/fc/aa/394cb22a0c927c575758eacd5d3c", - "assets/build/pylib-apple/bdb.py": "https://files.ballistica.net/cache/ba1/3f/5f/710f2f84bfda88f21b25ad5084f0", + "assets/build/pylib-apple/bdb.py": "https://files.ballistica.net/cache/ba1/51/50/2e05640cfc2c0a4b61ee3fa028d2", "assets/build/pylib-apple/binhex.py": "https://files.ballistica.net/cache/ba1/8a/1b/9e5f7d1c262ecbed4f2f1a127564", - "assets/build/pylib-apple/bisect.py": "https://files.ballistica.net/cache/ba1/65/8d/7ee4b83ef17c4e12dbee3de0ed78", - "assets/build/pylib-apple/bz2.py": "https://files.ballistica.net/cache/ba1/e2/fb/aebb1af1f3c9772be84d9907fefa", - "assets/build/pylib-apple/cProfile.py": "https://files.ballistica.net/cache/ba1/4c/a3/fb311d2400209b2fd255b18c89d1", - "assets/build/pylib-apple/calendar.py": "https://files.ballistica.net/cache/ba1/c3/ac/b03d4417bb0a29cc5e43afcee018", - "assets/build/pylib-apple/cgi.py": "https://files.ballistica.net/cache/ba1/28/fd/bb721e852af6fbf278ce1db51094", - "assets/build/pylib-apple/cgitb.py": "https://files.ballistica.net/cache/ba1/2d/55/8d7d0ed1a9fce5117c8404567af9", + "assets/build/pylib-apple/bisect.py": "https://files.ballistica.net/cache/ba1/61/e8/bbdb541d16a6fa002a0fd395c73b", + "assets/build/pylib-apple/bz2.py": "https://files.ballistica.net/cache/ba1/4c/3d/878a1e93876d64136fa253176b50", + "assets/build/pylib-apple/cProfile.py": "https://files.ballistica.net/cache/ba1/3c/12/8477e3d7df2cb190254625ddaf06", + "assets/build/pylib-apple/calendar.py": "https://files.ballistica.net/cache/ba1/59/9c/2b0a13658c958a9995ade122ae00", + "assets/build/pylib-apple/cgi.py": "https://files.ballistica.net/cache/ba1/c0/8b/3b0909bcb61ce7cac1684a1e1943", + "assets/build/pylib-apple/cgitb.py": "https://files.ballistica.net/cache/ba1/9a/2d/70325a99eeaff8701540d2304d80", "assets/build/pylib-apple/chunk.py": "https://files.ballistica.net/cache/ba1/e0/4d/8609a028d890841ff867e97f0869", "assets/build/pylib-apple/cmd.py": "https://files.ballistica.net/cache/ba1/33/25/43fd9394378dd3db266dd35af46e", "assets/build/pylib-apple/code.py": "https://files.ballistica.net/cache/ba1/18/fc/d667016222e466707ec5d0991810", - "assets/build/pylib-apple/codecs.py": "https://files.ballistica.net/cache/ba1/59/5e/1db8ca057d9140fc441eddbba66a", + "assets/build/pylib-apple/codecs.py": "https://files.ballistica.net/cache/ba1/34/82/17d21cdb1a3a8e740629b5720b5b", "assets/build/pylib-apple/codeop.py": "https://files.ballistica.net/cache/ba1/53/e6/d9b2676f59dad4386c740ce4b551", - "assets/build/pylib-apple/collections/__init__.py": "https://files.ballistica.net/cache/ba1/e9/19/524a6966561435000ebf610762b4", + "assets/build/pylib-apple/collections/__init__.py": "https://files.ballistica.net/cache/ba1/2f/ec/36668a1b0f8ffedd3a1fa1ddb276", "assets/build/pylib-apple/collections/abc.py": "https://files.ballistica.net/cache/ba1/78/dd/38815f6fb41c45822afef8fb1b71", "assets/build/pylib-apple/colorsys.py": "https://files.ballistica.net/cache/ba1/ae/99/594631454b09ad4d5c34ec54a344", - "assets/build/pylib-apple/compileall.py": "https://files.ballistica.net/cache/ba1/03/97/c2f9709dc47ca3b1cba99aba338a", + "assets/build/pylib-apple/compileall.py": "https://files.ballistica.net/cache/ba1/1f/d7/80c8a9cb297994b001f766f96ca7", "assets/build/pylib-apple/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/f8/0b/346441ef94908fb806338d0510b6", - "assets/build/pylib-apple/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/6e/57/3bbd8b7b6f315e106ad0d5653e38", - "assets/build/pylib-apple/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/fe/10/4e0ed0d4f044863838e2980b7ab0", - "assets/build/pylib-apple/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/a8/b8/0bc0e2fd1bf530189df904714395", - "assets/build/pylib-apple/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/4d/55/e48627e904c8d428bb1706cd676a", - "assets/build/pylib-apple/configparser.py": "https://files.ballistica.net/cache/ba1/ad/48/0318a7ab517f1f3240e77ac0bdc5", - "assets/build/pylib-apple/contextlib.py": "https://files.ballistica.net/cache/ba1/11/ad/4518abe76a5e3ab825d158f01172", + "assets/build/pylib-apple/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/6b/26/78ac686a2335efb18fa8ed0e5d6a", + "assets/build/pylib-apple/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/e4/da/c5f51a895dbd067d6571a8f1e979", + "assets/build/pylib-apple/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/34/ba/b02bf14621a6b888a29c1a3bb11f", + "assets/build/pylib-apple/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/46/10/e24a0ea083991df41a0301a22b94", + "assets/build/pylib-apple/configparser.py": "https://files.ballistica.net/cache/ba1/06/36/09b61a5e5de8234b37fd3f476493", + "assets/build/pylib-apple/contextlib.py": "https://files.ballistica.net/cache/ba1/e3/b7/1cfb5689e277e48c8c347f6ba36e", "assets/build/pylib-apple/contextvars.py": "https://files.ballistica.net/cache/ba1/02/52/e520b59b10124c813468252fee2a", - "assets/build/pylib-apple/copy.py": "https://files.ballistica.net/cache/ba1/84/d0/d769d275a0fa46184eee8c534bc8", - "assets/build/pylib-apple/copyreg.py": "https://files.ballistica.net/cache/ba1/a3/31/65d0b18e801caa2bef11d6ac93b4", - "assets/build/pylib-apple/crypt.py": "https://files.ballistica.net/cache/ba1/54/c9/5286313c50d32918803c57359099", - "assets/build/pylib-apple/csv.py": "https://files.ballistica.net/cache/ba1/9a/6f/e4a900981552c661cf8f1ce3a5ad", - "assets/build/pylib-apple/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/54/92/9b951b76a7dfb352cdf6b535d46d", + "assets/build/pylib-apple/copy.py": "https://files.ballistica.net/cache/ba1/d9/f7/6d68526a34fd56e358cc920f723c", + "assets/build/pylib-apple/copyreg.py": "https://files.ballistica.net/cache/ba1/0c/5a/c21a2c6000ad2947861fbd711834", + "assets/build/pylib-apple/crypt.py": "https://files.ballistica.net/cache/ba1/1e/e7/a5d7cc52a39b600ea554534a75de", + "assets/build/pylib-apple/csv.py": "https://files.ballistica.net/cache/ba1/02/21/503374208b50d8cffa21e5aad48a", + "assets/build/pylib-apple/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/1f/87/6aeddc887fcb3d346849b4dcab80", "assets/build/pylib-apple/ctypes/_aix.py": "https://files.ballistica.net/cache/ba1/f4/e3/d0d2b2809d80ad7cd813477be797", "assets/build/pylib-apple/ctypes/_endian.py": "https://files.ballistica.net/cache/ba1/f7/ff/297cd3308735876b3d7ac54172e0", "assets/build/pylib-apple/ctypes/macholib/__init__.py": "https://files.ballistica.net/cache/ba1/cd/67/df2ef87d5f3411077030882bcae3", @@ -3070,32 +3077,32 @@ "assets/build/pylib-apple/ctypes/macholib/framework.py": "https://files.ballistica.net/cache/ba1/97/8b/19a7d679d50c0983f9c4b2f37d5e", "assets/build/pylib-apple/ctypes/util.py": "https://files.ballistica.net/cache/ba1/c0/da/78c5a52e438182375e166fafc4c7", "assets/build/pylib-apple/ctypes/wintypes.py": "https://files.ballistica.net/cache/ba1/09/43/f7e315d732918308ea4e4c197c5a", - "assets/build/pylib-apple/curses/__init__.py": "https://files.ballistica.net/cache/ba1/78/da/6501ff362460c3b7be7c4eb554b9", + "assets/build/pylib-apple/curses/__init__.py": "https://files.ballistica.net/cache/ba1/43/5a/c242200e965ec30f3922cf9f73b5", "assets/build/pylib-apple/curses/ascii.py": "https://files.ballistica.net/cache/ba1/97/27/94584e1dcd1637dfdce80efa78eb", "assets/build/pylib-apple/curses/has_key.py": "https://files.ballistica.net/cache/ba1/60/17/fde8d2bfabfe53298f936ebdec88", "assets/build/pylib-apple/curses/panel.py": "https://files.ballistica.net/cache/ba1/41/42/ef63abf4b18669a22ab9141bcb88", "assets/build/pylib-apple/curses/textpad.py": "https://files.ballistica.net/cache/ba1/34/78/bc5c856e5f1d8439d4e191bc4f75", - "assets/build/pylib-apple/dataclasses.py": "https://files.ballistica.net/cache/ba1/17/9c/7b97973c754e5bd2b682d6c2f037", - "assets/build/pylib-apple/datetime.py": "https://files.ballistica.net/cache/ba1/03/03/8d28f028302b508bd1996401c692", + "assets/build/pylib-apple/dataclasses.py": "https://files.ballistica.net/cache/ba1/cf/70/fb38c9192ae6ecb85a2ec2867614", + "assets/build/pylib-apple/datetime.py": "https://files.ballistica.net/cache/ba1/3e/b9/b835ed2958103cba232e6e9e71df", "assets/build/pylib-apple/decimal.py": "https://files.ballistica.net/cache/ba1/dd/5d/8d0f90ec4e20c613b6ce2a88bc60", - "assets/build/pylib-apple/difflib.py": "https://files.ballistica.net/cache/ba1/81/ae/5c878b083eddc6db9624fe75c96a", - "assets/build/pylib-apple/dis.py": "https://files.ballistica.net/cache/ba1/77/ac/6444908dfe3e74dd1041b41d2934", - "assets/build/pylib-apple/doctest.py": "https://files.ballistica.net/cache/ba1/9d/79/f582a06f080421d6ac02ad15909c", + "assets/build/pylib-apple/difflib.py": "https://files.ballistica.net/cache/ba1/63/ca/23738df60b6b3ffe279a617df1bf", + "assets/build/pylib-apple/dis.py": "https://files.ballistica.net/cache/ba1/85/bb/0f5f5bf2f7ec42a406e484611210", + "assets/build/pylib-apple/doctest.py": "https://files.ballistica.net/cache/ba1/2e/e7/7821f5346e5e5f1b228d8a4a0d00", "assets/build/pylib-apple/dummy_threading.py": "https://files.ballistica.net/cache/ba1/5b/60/6a2a69960c1c982fa667f3fd8051", "assets/build/pylib-apple/email/__init__.py": "https://files.ballistica.net/cache/ba1/2f/8e/c14225900357ac302213f5b4d674", "assets/build/pylib-apple/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/c6/3d/d686aa9a7ddbee790ad558b25661", - "assets/build/pylib-apple/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/95/52/246e090b5fb1c81585caaec17af0", + "assets/build/pylib-apple/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/ba/64/b6210f67e3308e79768747219d78", "assets/build/pylib-apple/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/52/1a/df154303ce2a676fc3a9813077e2", "assets/build/pylib-apple/email/_policybase.py": "https://files.ballistica.net/cache/ba1/6c/38/90cc9fd748e60e442565a4a1d88a", "assets/build/pylib-apple/email/base64mime.py": "https://files.ballistica.net/cache/ba1/92/48/e5d879df31628e601de7b937e48b", - "assets/build/pylib-apple/email/charset.py": "https://files.ballistica.net/cache/ba1/82/59/253c97de69d02816f76af5f66c70", + "assets/build/pylib-apple/email/charset.py": "https://files.ballistica.net/cache/ba1/7e/a5/dd4804d6ab73949fc8b905377163", "assets/build/pylib-apple/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/8b/9e/f72ebcf455884622e5e06828f04a", "assets/build/pylib-apple/email/encoders.py": "https://files.ballistica.net/cache/ba1/93/57/13dcc149580825b133b08fbc6a87", "assets/build/pylib-apple/email/errors.py": "https://files.ballistica.net/cache/ba1/2f/8d/fff46c8695ee407131c4abbb9c42", "assets/build/pylib-apple/email/feedparser.py": "https://files.ballistica.net/cache/ba1/5e/34/32eb942596826dd2cb845e9d2a2e", "assets/build/pylib-apple/email/generator.py": "https://files.ballistica.net/cache/ba1/2d/93/9e6179a10d1bfca9c97fcdcaca04", "assets/build/pylib-apple/email/header.py": "https://files.ballistica.net/cache/ba1/21/e7/9bb3af5ad0b37941d9c73020cccf", - "assets/build/pylib-apple/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/da/74/f4e97e898bc06e65693f4adac7f3", + "assets/build/pylib-apple/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/3e/3a/b0d7b858017852a220b25faf7dbe", "assets/build/pylib-apple/email/iterators.py": "https://files.ballistica.net/cache/ba1/2f/8c/6a1dc186422beb8546721f22b72b", "assets/build/pylib-apple/email/message.py": "https://files.ballistica.net/cache/ba1/90/fb/7502f66e12de14e5d3f21d69c51d", "assets/build/pylib-apple/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/e0/cb/20c79c7faa724bdfeebae99795aa", @@ -3111,8 +3118,8 @@ "assets/build/pylib-apple/email/policy.py": "https://files.ballistica.net/cache/ba1/a5/64/8c59670fdf565988c72f21040ed5", "assets/build/pylib-apple/email/quoprimime.py": "https://files.ballistica.net/cache/ba1/4a/85/aa0a24ec3a4f407d18aadf357bad", "assets/build/pylib-apple/email/utils.py": "https://files.ballistica.net/cache/ba1/37/aa/b3da0e0b188192db3e863bce2b9f", - "assets/build/pylib-apple/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/1d/46/c7aed39eff195e88ed43f89c5aa1", - "assets/build/pylib-apple/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/25/ee/76ea9c6e8d493844a9bd577fa286", + "assets/build/pylib-apple/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/b8/61/d28f98d3527e5e7285265ef03f7f", + "assets/build/pylib-apple/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/3a/72/a855c1e63bc3510a87099b87770f", "assets/build/pylib-apple/encodings/ascii.py": "https://files.ballistica.net/cache/ba1/ae/eb/d4efe1172c154ed19f3ed9c3e0d8", "assets/build/pylib-apple/encodings/base64_codec.py": "https://files.ballistica.net/cache/ba1/ac/9d/63f89df311a1a5cfb3c0e8cedcce", "assets/build/pylib-apple/encodings/big5.py": "https://files.ballistica.net/cache/ba1/78/ea/960502c422e3c224c8ad449fd429", @@ -3137,7 +3144,6 @@ "assets/build/pylib-apple/encodings/cp424.py": "https://files.ballistica.net/cache/ba1/1a/2d/a446a54a2d76c587b34eb915f127", "assets/build/pylib-apple/encodings/cp437.py": "https://files.ballistica.net/cache/ba1/46/c2/29b4a8a21a9bb96be0e203ad6ec4", "assets/build/pylib-apple/encodings/cp500.py": "https://files.ballistica.net/cache/ba1/a9/11/e8f4418506106a071feef14b3382", - "assets/build/pylib-apple/encodings/cp65001.py": "https://files.ballistica.net/cache/ba1/f0/95/917dc1bc0a37c79d05ca9ecf4469", "assets/build/pylib-apple/encodings/cp720.py": "https://files.ballistica.net/cache/ba1/53/18/99c144337822c63b123971dd1779", "assets/build/pylib-apple/encodings/cp737.py": "https://files.ballistica.net/cache/ba1/08/a7/8eab04dab573b446dba438e51467", "assets/build/pylib-apple/encodings/cp775.py": "https://files.ballistica.net/cache/ba1/5d/a9/7de5f8fd96e66e4bd2caa6ff84b1", @@ -3224,7 +3230,6 @@ "assets/build/pylib-apple/encodings/tis_620.py": "https://files.ballistica.net/cache/ba1/f5/97/5265d287599954e9edc9d136c2eb", "assets/build/pylib-apple/encodings/undefined.py": "https://files.ballistica.net/cache/ba1/e0/30/aa4fc6031370f50a2c5b895f2bd8", "assets/build/pylib-apple/encodings/unicode_escape.py": "https://files.ballistica.net/cache/ba1/24/ce/4c2ebd04cb8f2e74ae8a801040ac", - "assets/build/pylib-apple/encodings/unicode_internal.py": "https://files.ballistica.net/cache/ba1/cf/c2/9d4c0aa684537365bb989084a8b0", "assets/build/pylib-apple/encodings/utf_16.py": "https://files.ballistica.net/cache/ba1/0f/27/bd0dcbe7be3cf0daf600f720c24a", "assets/build/pylib-apple/encodings/utf_16_be.py": "https://files.ballistica.net/cache/ba1/25/40/ffe71632b66c6d5a08b4ce945790", "assets/build/pylib-apple/encodings/utf_16_le.py": "https://files.ballistica.net/cache/ba1/64/28/e9b6c773570ea8510c2acf0b7cd8", @@ -3236,151 +3241,151 @@ "assets/build/pylib-apple/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/1b/c8/1ffa26b3c2a650efae206d27b6f3", "assets/build/pylib-apple/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/40/6c/279145a291f59642952ea9880b9d", "assets/build/pylib-apple/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/1f/c9/57406baceeabe0a0e201a81833d5", - "assets/build/pylib-apple/enum.py": "https://files.ballistica.net/cache/ba1/cc/99/692ac42e40800b235552b9b1b309", + "assets/build/pylib-apple/enum.py": "https://files.ballistica.net/cache/ba1/9a/86/715e4351d4062e4f24f3686bdea2", "assets/build/pylib-apple/filecmp.py": "https://files.ballistica.net/cache/ba1/4f/1a/2d6576fd5bc7722af46820164d58", - "assets/build/pylib-apple/fileinput.py": "https://files.ballistica.net/cache/ba1/08/d2/236f7a90d9c686581e6456e06229", + "assets/build/pylib-apple/fileinput.py": "https://files.ballistica.net/cache/ba1/6b/04/bdebb1257b328a98f109e23eadfc", "assets/build/pylib-apple/fnmatch.py": "https://files.ballistica.net/cache/ba1/00/11/7533d94880452cc0ab88f9373642", "assets/build/pylib-apple/formatter.py": "https://files.ballistica.net/cache/ba1/b3/5f/58445670edaf8bb748c745197fa7", - "assets/build/pylib-apple/fractions.py": "https://files.ballistica.net/cache/ba1/bb/20/945accff09d654218c4f4929f9b1", - "assets/build/pylib-apple/ftplib.py": "https://files.ballistica.net/cache/ba1/a5/0f/4be26d989b3a1431da319d403f04", - "assets/build/pylib-apple/functools.py": "https://files.ballistica.net/cache/ba1/82/f9/b13ce3b3135bad32a49fce297507", - "assets/build/pylib-apple/genericpath.py": "https://files.ballistica.net/cache/ba1/e4/e1/3097bbebdff714b5ef8bb74759f9", + "assets/build/pylib-apple/fractions.py": "https://files.ballistica.net/cache/ba1/df/db/61be6d9b79cbce6bb29fae2aa9fb", + "assets/build/pylib-apple/ftplib.py": "https://files.ballistica.net/cache/ba1/42/ef/b31f8d12adfe82836b95a930b26f", + "assets/build/pylib-apple/functools.py": "https://files.ballistica.net/cache/ba1/20/35/bec93f7b040908eb4b87f30d2fa0", + "assets/build/pylib-apple/genericpath.py": "https://files.ballistica.net/cache/ba1/b3/cd/0b7bb99d3aa5a41b69a4b62cd3cf", "assets/build/pylib-apple/getopt.py": "https://files.ballistica.net/cache/ba1/46/47/d33382d447d398923f4c0c0f87c1", "assets/build/pylib-apple/getpass.py": "https://files.ballistica.net/cache/ba1/02/a1/d4249edfdf76656945cda335490b", - "assets/build/pylib-apple/gettext.py": "https://files.ballistica.net/cache/ba1/e1/68/e0f1837f5894efe656c47ae2fb37", - "assets/build/pylib-apple/glob.py": "https://files.ballistica.net/cache/ba1/96/c2/9d910d21ac8886d2423287d0ef00", - "assets/build/pylib-apple/gzip.py": "https://files.ballistica.net/cache/ba1/d9/fc/f621c55b5af86da312e264966efc", - "assets/build/pylib-apple/hashlib.py": "https://files.ballistica.net/cache/ba1/ea/1c/7cef23322a343b2cb0dd0672a579", - "assets/build/pylib-apple/heapq.py": "https://files.ballistica.net/cache/ba1/a5/e7/f4748c3884acf2e4e8ccc8034566", - "assets/build/pylib-apple/hmac.py": "https://files.ballistica.net/cache/ba1/6e/dc/c724c3184b473c12632485fb1041", + "assets/build/pylib-apple/gettext.py": "https://files.ballistica.net/cache/ba1/f8/e0/8ad913d8eac5ad9d2f34973cbc77", + "assets/build/pylib-apple/glob.py": "https://files.ballistica.net/cache/ba1/9c/8c/5db3f5435168ff5270ae2dbd7977", + "assets/build/pylib-apple/gzip.py": "https://files.ballistica.net/cache/ba1/1e/e9/669c96cbbc701643459c26e0ce87", + "assets/build/pylib-apple/hashlib.py": "https://files.ballistica.net/cache/ba1/a1/51/6234b8612e60917ecea82b8a7f3a", + "assets/build/pylib-apple/heapq.py": "https://files.ballistica.net/cache/ba1/cf/ff/e3aa597a8669e6030a2b8ab06228", + "assets/build/pylib-apple/hmac.py": "https://files.ballistica.net/cache/ba1/b8/43/24176dd09b4a346c5d2fb23b2489", "assets/build/pylib-apple/html/__init__.py": "https://files.ballistica.net/cache/ba1/cd/32/56a082769e4cd6fb8de604e0a1aa", "assets/build/pylib-apple/html/entities.py": "https://files.ballistica.net/cache/ba1/98/95/6e96db7b66edc0178c1680bbd561", "assets/build/pylib-apple/html/parser.py": "https://files.ballistica.net/cache/ba1/53/49/7e66623bcf32ec74f3b91806e36e", - "assets/build/pylib-apple/http/__init__.py": "https://files.ballistica.net/cache/ba1/e4/23/ce5fcd5273aaaf6b3cd3c725ee8f", - "assets/build/pylib-apple/http/client.py": "https://files.ballistica.net/cache/ba1/6a/45/18c59a32b44d63d2822799481a62", - "assets/build/pylib-apple/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/ec/e0/ffdb9824a3eb14a5f9a4c1810db5", - "assets/build/pylib-apple/http/cookies.py": "https://files.ballistica.net/cache/ba1/fe/40/6e67e0c4d88761dd6db90d686d09", - "assets/build/pylib-apple/http/server.py": "https://files.ballistica.net/cache/ba1/9f/9c/a537bd834ef9e2b13d2ddcfeefe7", + "assets/build/pylib-apple/http/__init__.py": "https://files.ballistica.net/cache/ba1/0c/4b/fd4d41d4614d30fbbc8a29804306", + "assets/build/pylib-apple/http/client.py": "https://files.ballistica.net/cache/ba1/e7/2a/ed9bde31ce0079c6a68fe45ee9f9", + "assets/build/pylib-apple/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/ca/58/434a958d4f8372b96b4cfa87a4a2", + "assets/build/pylib-apple/http/cookies.py": "https://files.ballistica.net/cache/ba1/3f/7e/a86ac95ad155cd1e7469437ce570", + "assets/build/pylib-apple/http/server.py": "https://files.ballistica.net/cache/ba1/30/83/9001b9601fc4c335ba19384c7996", "assets/build/pylib-apple/imghdr.py": "https://files.ballistica.net/cache/ba1/c2/84/90721ae9e476f55c9f22e8f18b6b", "assets/build/pylib-apple/imp.py": "https://files.ballistica.net/cache/ba1/ee/bf/d6a2ec2413b54a6be3a02cfa00ba", - "assets/build/pylib-apple/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/04/61/5245aeb2ae3b513eabaea5b08d98", - "assets/build/pylib-apple/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/fa/79/a856ce33c1e82d8023f4b15afed3", - "assets/build/pylib-apple/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/6c/51/f0a1de570d6ed6b4bccf43e7b29f", + "assets/build/pylib-apple/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/4e/6f/8d7a262ab97963fdd5b9ce8efe8b", + "assets/build/pylib-apple/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/26/7f/65d2f08e6894232a4fcc3f070f8b", + "assets/build/pylib-apple/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/19/fe/c77419d8c6dd79a483b62652fe46", "assets/build/pylib-apple/importlib/abc.py": "https://files.ballistica.net/cache/ba1/3f/bf/f3caab2fcf18ed1ae3ba1e9adaad", "assets/build/pylib-apple/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/1f/fe/2a27ae49f0c0db298c9eac2d6fa4", - "assets/build/pylib-apple/importlib/resources.py": "https://files.ballistica.net/cache/ba1/ca/1a/f4d3e74466144c4852c53acf559c", + "assets/build/pylib-apple/importlib/metadata.py": "https://files.ballistica.net/cache/ba1/92/eb/97adf1b89a596f601a55a804aaf4", + "assets/build/pylib-apple/importlib/resources.py": "https://files.ballistica.net/cache/ba1/88/45/4484c3e601fb26761c9f300d2866", "assets/build/pylib-apple/importlib/util.py": "https://files.ballistica.net/cache/ba1/28/14/519fd434e756d3e630d96cbc4d4f", - "assets/build/pylib-apple/inspect.py": "https://files.ballistica.net/cache/ba1/c5/4d/ff30d22c573701958e1dc84c0d05", - "assets/build/pylib-apple/io.py": "https://files.ballistica.net/cache/ba1/3b/5f/d80c2277bbb2e8be716d497d19c3", - "assets/build/pylib-apple/ipaddress.py": "https://files.ballistica.net/cache/ba1/fe/be/a8b89725129a490eb4250a4c42dd", - "assets/build/pylib-apple/json/__init__.py": "https://files.ballistica.net/cache/ba1/a7/14/b50d2bae12ae876dce4d674aa000", + "assets/build/pylib-apple/inspect.py": "https://files.ballistica.net/cache/ba1/62/a0/37eb7e5f75e1985618cb287db2b3", + "assets/build/pylib-apple/io.py": "https://files.ballistica.net/cache/ba1/f9/ed/07dba0ecf1e81d4cd816bce9542b", + "assets/build/pylib-apple/ipaddress.py": "https://files.ballistica.net/cache/ba1/e7/6c/f436bddaf6833279c51233aa863d", + "assets/build/pylib-apple/json/__init__.py": "https://files.ballistica.net/cache/ba1/72/b2/49cbdedf6ad5c411bb444377ec4f", "assets/build/pylib-apple/json/decoder.py": "https://files.ballistica.net/cache/ba1/6f/c8/ddcd524fd23ec4c64a11c80905da", - "assets/build/pylib-apple/json/encoder.py": "https://files.ballistica.net/cache/ba1/4e/5d/79e3e477bca15fc477102a14f592", + "assets/build/pylib-apple/json/encoder.py": "https://files.ballistica.net/cache/ba1/ec/bd/e78407bc99409c0fd4a6ff25c112", "assets/build/pylib-apple/json/scanner.py": "https://files.ballistica.net/cache/ba1/81/7c/03b7f8d8f18de6a1b12debd594db", - "assets/build/pylib-apple/json/tool.py": "https://files.ballistica.net/cache/ba1/b8/4e/efe04d51a3a6eef1865859ba7729", - "assets/build/pylib-apple/keyword.py": "https://files.ballistica.net/cache/ba1/43/a9/76fa84b2f2a17fc06fbbf42e6a15", + "assets/build/pylib-apple/json/tool.py": "https://files.ballistica.net/cache/ba1/14/15/f9f6e36235068667cb79b18fae84", + "assets/build/pylib-apple/keyword.py": "https://files.ballistica.net/cache/ba1/58/77/7d22ba844f36174fcbf10e362d44", "assets/build/pylib-apple/linecache.py": "https://files.ballistica.net/cache/ba1/74/13/4df2fa7a9a0d1879e928afd1b3fa", "assets/build/pylib-apple/locale.py": "https://files.ballistica.net/cache/ba1/90/f9/938e5408764ae6a0fc378cc301bb", - "assets/build/pylib-apple/logging/__init__.py": "https://files.ballistica.net/cache/ba1/31/a7/d4a9cfdb9568e90c10cf674d2058", - "assets/build/pylib-apple/logging/config.py": "https://files.ballistica.net/cache/ba1/8c/0b/15a5fdbb610e26f973bf46ac4287", - "assets/build/pylib-apple/logging/handlers.py": "https://files.ballistica.net/cache/ba1/58/a5/99e0d1cf6e9a35c11d349341f7c6", + "assets/build/pylib-apple/logging/__init__.py": "https://files.ballistica.net/cache/ba1/bb/e3/ab7aff8ffcb95e8cbfd6b3a92625", + "assets/build/pylib-apple/logging/config.py": "https://files.ballistica.net/cache/ba1/47/7d/30abadf91ca12fe6e68fdc38b239", + "assets/build/pylib-apple/logging/handlers.py": "https://files.ballistica.net/cache/ba1/30/e1/e0083ff67f38c6ded3a7b0fed1ee", "assets/build/pylib-apple/lzma.py": "https://files.ballistica.net/cache/ba1/8d/4c/6289a712439521bf99a154d316ab", - "assets/build/pylib-apple/macpath.py": "https://files.ballistica.net/cache/ba1/23/b7/d83ee2887e3ebdef21b5b592fd52", - "assets/build/pylib-apple/mailbox.py": "https://files.ballistica.net/cache/ba1/6f/5d/b40c483784423e5324e693cbce36", + "assets/build/pylib-apple/mailbox.py": "https://files.ballistica.net/cache/ba1/bc/95/77de0c6aaad3819b09abe0eed612", "assets/build/pylib-apple/mailcap.py": "https://files.ballistica.net/cache/ba1/c8/fc/03aaee28a480c60b9465c8358df2", - "assets/build/pylib-apple/mimetypes.py": "https://files.ballistica.net/cache/ba1/61/0f/15449b27ff2d27b50d55e387738a", - "assets/build/pylib-apple/modulefinder.py": "https://files.ballistica.net/cache/ba1/44/03/57c041ddca84c7ba9986605820df", + "assets/build/pylib-apple/mimetypes.py": "https://files.ballistica.net/cache/ba1/e1/25/a6eba431a8eeca33ee7e74e88205", + "assets/build/pylib-apple/modulefinder.py": "https://files.ballistica.net/cache/ba1/f5/26/0d92ec3a03d7f933cf157572f375", "assets/build/pylib-apple/netrc.py": "https://files.ballistica.net/cache/ba1/35/a9/0a1e1c8ecab734c09a5f8d64b51a", - "assets/build/pylib-apple/nntplib.py": "https://files.ballistica.net/cache/ba1/2b/92/a3a80b9a4e7730490198a548204c", - "assets/build/pylib-apple/ntpath.py": "https://files.ballistica.net/cache/ba1/80/a7/462a2b4b0008f7dccd3c759f8857", + "assets/build/pylib-apple/nntplib.py": "https://files.ballistica.net/cache/ba1/37/d0/25c88f817de5a6705d1c227bbd0d", + "assets/build/pylib-apple/ntpath.py": "https://files.ballistica.net/cache/ba1/2c/fd/c8b71d3d5efdf44556c68df02d30", "assets/build/pylib-apple/nturl2path.py": "https://files.ballistica.net/cache/ba1/d8/fa/0d625b59939d483cafa553790235", "assets/build/pylib-apple/numbers.py": "https://files.ballistica.net/cache/ba1/92/16/807de1550920d485c87f3d587d5d", - "assets/build/pylib-apple/opcode.py": "https://files.ballistica.net/cache/ba1/d7/aa/1d37b642b89086fcc2d437d4adf8", - "assets/build/pylib-apple/operator.py": "https://files.ballistica.net/cache/ba1/f0/07/a8b8b5f50e9abf13c9996e9b9434", - "assets/build/pylib-apple/optparse.py": "https://files.ballistica.net/cache/ba1/7e/57/af779a7d4606910039060c7c9409", - "assets/build/pylib-apple/os.py": "https://files.ballistica.net/cache/ba1/c1/ab/b842eb67df94b7f66b20cf4e4fa9", - "assets/build/pylib-apple/pathlib.py": "https://files.ballistica.net/cache/ba1/fc/c8/bd4616a80bfb3afcc77556e701a1", - "assets/build/pylib-apple/pdb.py": "https://files.ballistica.net/cache/ba1/ca/29/76a70d0f97b46a7ac2fd3b26ef56", - "assets/build/pylib-apple/pickle.py": "https://files.ballistica.net/cache/ba1/81/97/17747f0115fb9620c787b1c342d4", - "assets/build/pylib-apple/pickletools.py": "https://files.ballistica.net/cache/ba1/47/df/5536fd28281907e203536e319166", + "assets/build/pylib-apple/opcode.py": "https://files.ballistica.net/cache/ba1/7a/a8/3be6796ad635043eee8ba6ee031e", + "assets/build/pylib-apple/operator.py": "https://files.ballistica.net/cache/ba1/c5/02/51e774eacc0e70d60420010749f4", + "assets/build/pylib-apple/optparse.py": "https://files.ballistica.net/cache/ba1/a0/0b/202b321b2eddb9b62f30d58fd1f6", + "assets/build/pylib-apple/os.py": "https://files.ballistica.net/cache/ba1/65/88/d7823716fea104e4e65665b35f27", + "assets/build/pylib-apple/pathlib.py": "https://files.ballistica.net/cache/ba1/69/d1/0438fdd277d7d1b9be8b2276cc51", + "assets/build/pylib-apple/pdb.py": "https://files.ballistica.net/cache/ba1/8c/a3/6b98b2b18dfde43d40e1805f2626", + "assets/build/pylib-apple/pickle.py": "https://files.ballistica.net/cache/ba1/a8/d8/9fe5eab9682175ab2ce57b1eceb7", + "assets/build/pylib-apple/pickletools.py": "https://files.ballistica.net/cache/ba1/b0/a2/0655f9bef1f950e8f678be867bec", "assets/build/pylib-apple/pipes.py": "https://files.ballistica.net/cache/ba1/95/86/92cb2b19dc776bd8d7dc459eccc3", "assets/build/pylib-apple/pkgutil.py": "https://files.ballistica.net/cache/ba1/38/b0/3e59ab18a07c9f4f6995b855a7c4", - "assets/build/pylib-apple/platform.py": "https://files.ballistica.net/cache/ba1/ba/2f/3af76d3d44bba18f10d489612f00", - "assets/build/pylib-apple/plistlib.py": "https://files.ballistica.net/cache/ba1/00/09/6c803c86d767518c4144259e84fe", - "assets/build/pylib-apple/poplib.py": "https://files.ballistica.net/cache/ba1/76/0e/d6eabd7112d63567c6795bc2617d", - "assets/build/pylib-apple/posixpath.py": "https://files.ballistica.net/cache/ba1/67/84/6ef638edfeb45b5b646baee5dfef", - "assets/build/pylib-apple/pprint.py": "https://files.ballistica.net/cache/ba1/22/63/e57d5c0472c3629ae72029f81b8c", - "assets/build/pylib-apple/profile.py": "https://files.ballistica.net/cache/ba1/b0/06/270fd09b36f9d9cc14dbdf84342e", - "assets/build/pylib-apple/pstats.py": "https://files.ballistica.net/cache/ba1/a8/37/1da31b0fbc9acaa9112c1d6317e5", - "assets/build/pylib-apple/pty.py": "https://files.ballistica.net/cache/ba1/26/71/f89485d103b2a80ec4198de7f3a6", - "assets/build/pylib-apple/py_compile.py": "https://files.ballistica.net/cache/ba1/fe/6a/5b863bc38a0efa02e5a2e8df9758", - "assets/build/pylib-apple/pyclbr.py": "https://files.ballistica.net/cache/ba1/44/3a/442c56a5f5f8b4c2c992cc12ed35", - "assets/build/pylib-apple/pydoc.py": "https://files.ballistica.net/cache/ba1/be/f8/b7b3ffa4342672f71c578ac23d4a", - "assets/build/pylib-apple/queue.py": "https://files.ballistica.net/cache/ba1/0b/69/f9e2c026824fe1d4602a6183b56c", + "assets/build/pylib-apple/platform.py": "https://files.ballistica.net/cache/ba1/bb/d4/06918fb7382d0f898f0f33bbd83c", + "assets/build/pylib-apple/plistlib.py": "https://files.ballistica.net/cache/ba1/09/4a/cad393669361a6c4e40ad1584544", + "assets/build/pylib-apple/poplib.py": "https://files.ballistica.net/cache/ba1/92/a9/b8f8a4449c41b913cd0471a29703", + "assets/build/pylib-apple/posixpath.py": "https://files.ballistica.net/cache/ba1/e1/06/e298802e053842f6d101326ae76c", + "assets/build/pylib-apple/pprint.py": "https://files.ballistica.net/cache/ba1/04/96/6c34676c08e631ded6416c14866d", + "assets/build/pylib-apple/profile.py": "https://files.ballistica.net/cache/ba1/ca/00/b1d963b1cc92bdd214cec940c1e2", + "assets/build/pylib-apple/pstats.py": "https://files.ballistica.net/cache/ba1/c5/20/767c110045725305b118e523084b", + "assets/build/pylib-apple/pty.py": "https://files.ballistica.net/cache/ba1/33/56/32146736331945537902f3771ffb", + "assets/build/pylib-apple/py_compile.py": "https://files.ballistica.net/cache/ba1/bc/1e/1c4cb404145808ae25ef599660f2", + "assets/build/pylib-apple/pyclbr.py": "https://files.ballistica.net/cache/ba1/1a/e2/76bb863e9c510078b5e0828caf56", + "assets/build/pylib-apple/pydoc.py": "https://files.ballistica.net/cache/ba1/c7/39/322ac2338f1737dfa217f3645609", + "assets/build/pylib-apple/queue.py": "https://files.ballistica.net/cache/ba1/b6/2a/db3c0a47ad2bf43b3df8a2b4ebac", "assets/build/pylib-apple/quopri.py": "https://files.ballistica.net/cache/ba1/34/a2/7e15c991e3a6ba75d988323117e8", - "assets/build/pylib-apple/random.py": "https://files.ballistica.net/cache/ba1/07/b5/9ac8faa65ff3e80827b59fa931e4", - "assets/build/pylib-apple/re.py": "https://files.ballistica.net/cache/ba1/31/16/e4186a051e3e0421854e35388141", + "assets/build/pylib-apple/random.py": "https://files.ballistica.net/cache/ba1/d1/55/4fddea355c8156b287408489b579", + "assets/build/pylib-apple/re.py": "https://files.ballistica.net/cache/ba1/49/00/196fc6e98b9c244526b2d773c71f", "assets/build/pylib-apple/reprlib.py": "https://files.ballistica.net/cache/ba1/25/3c/b07febf734908722d45da1ea6c57", "assets/build/pylib-apple/rlcompleter.py": "https://files.ballistica.net/cache/ba1/fd/6f/0d94c6ff1d295c4381fff0042842", - "assets/build/pylib-apple/runpy.py": "https://files.ballistica.net/cache/ba1/23/7b/6d9bf1ca3c786cbc4cfbc0b8caec", + "assets/build/pylib-apple/runpy.py": "https://files.ballistica.net/cache/ba1/a8/01/35faaa35a3f951aca147d1863f11", "assets/build/pylib-apple/sched.py": "https://files.ballistica.net/cache/ba1/6f/18/dd390ca79c5429626c7e4d3f52e8", "assets/build/pylib-apple/secrets.py": "https://files.ballistica.net/cache/ba1/5e/a5/be60578ed41fe83eb1cd9124a2c4", "assets/build/pylib-apple/selectors.py": "https://files.ballistica.net/cache/ba1/d0/d3/46fb0c3bd78b1a38c58f7823365a", "assets/build/pylib-apple/shelve.py": "https://files.ballistica.net/cache/ba1/9b/7b/ae49077c735a6347f0711d0ecbb9", - "assets/build/pylib-apple/shlex.py": "https://files.ballistica.net/cache/ba1/d2/23/641654cb1e04835567e6de95a3bd", - "assets/build/pylib-apple/shutil.py": "https://files.ballistica.net/cache/ba1/16/d2/f287144a36f73a6a85d9ae1934f0", - "assets/build/pylib-apple/signal.py": "https://files.ballistica.net/cache/ba1/96/d8/e2740cbbfb4f37f8e23e94cd6e2e", - "assets/build/pylib-apple/site.py": "https://files.ballistica.net/cache/ba1/ac/62/dffa5203e5366ce249fbeefff2e8", + "assets/build/pylib-apple/shlex.py": "https://files.ballistica.net/cache/ba1/7f/24/3dd0f393ff5d88dba1eef618e3cf", + "assets/build/pylib-apple/shutil.py": "https://files.ballistica.net/cache/ba1/7b/03/dab7dd73a6895b5c30f7916a2f4f", + "assets/build/pylib-apple/signal.py": "https://files.ballistica.net/cache/ba1/1d/94/28fcd21e46fd2df5d11fd36b8a16", + "assets/build/pylib-apple/site.py": "https://files.ballistica.net/cache/ba1/15/e0/9fa4b86ea9b7f018bf002971ffd8", "assets/build/pylib-apple/smtpd.py": "https://files.ballistica.net/cache/ba1/74/25/b2a885dc3ec86528497fa22b44d2", - "assets/build/pylib-apple/smtplib.py": "https://files.ballistica.net/cache/ba1/61/55/7c45f390f85d1bcd0848921d1d15", + "assets/build/pylib-apple/smtplib.py": "https://files.ballistica.net/cache/ba1/19/36/4918ee3dd909ad4be1757462bf62", "assets/build/pylib-apple/sndhdr.py": "https://files.ballistica.net/cache/ba1/c2/d5/474b0c8055dc400e8369efe4a865", - "assets/build/pylib-apple/socket.py": "https://files.ballistica.net/cache/ba1/32/d9/aa089c57ccbd3f74236f2f1c5b50", + "assets/build/pylib-apple/socket.py": "https://files.ballistica.net/cache/ba1/38/33/369517fa47cab8bf4bc020986108", "assets/build/pylib-apple/socketserver.py": "https://files.ballistica.net/cache/ba1/4b/d2/913b77ec0f800ec101e82e9e9721", "assets/build/pylib-apple/sqlite3/__init__.py": "https://files.ballistica.net/cache/ba1/3e/dc/91b84dad3702e9ae8d915e3bd379", "assets/build/pylib-apple/sqlite3/dbapi2.py": "https://files.ballistica.net/cache/ba1/cd/c9/8ba4cb1adcb533d433e96af9f624", "assets/build/pylib-apple/sqlite3/dump.py": "https://files.ballistica.net/cache/ba1/cb/c9/2ea904e0824aefc3d9524174fd29", - "assets/build/pylib-apple/sre_compile.py": "https://files.ballistica.net/cache/ba1/6d/f4/c104647f0834ea148a7372410910", - "assets/build/pylib-apple/sre_constants.py": "https://files.ballistica.net/cache/ba1/8d/07/611d2c92f55c11f5c32682bfb4ec", - "assets/build/pylib-apple/sre_parse.py": "https://files.ballistica.net/cache/ba1/df/ea/3fdc144e2c4ed192863e9efc01b9", - "assets/build/pylib-apple/ssl.py": "https://files.ballistica.net/cache/ba1/fe/8c/0f89c639a92f0500f817bc07bb20", - "assets/build/pylib-apple/stat.py": "https://files.ballistica.net/cache/ba1/d1/af/bbd60b3f48e79d24788dcb30e666", - "assets/build/pylib-apple/statistics.py": "https://files.ballistica.net/cache/ba1/cd/c1/ceb3b5bfbdfdf23b3b0040d67fd3", - "assets/build/pylib-apple/string.py": "https://files.ballistica.net/cache/ba1/87/20/f6260e9d53689af592a629332612", + "assets/build/pylib-apple/sre_compile.py": "https://files.ballistica.net/cache/ba1/7d/b1/e88453af530e58284561945056c4", + "assets/build/pylib-apple/sre_constants.py": "https://files.ballistica.net/cache/ba1/95/ef/a427cef2c7463b6906f53e8811b8", + "assets/build/pylib-apple/sre_parse.py": "https://files.ballistica.net/cache/ba1/f7/67/2db2e1e8de620039831f008beb29", + "assets/build/pylib-apple/ssl.py": "https://files.ballistica.net/cache/ba1/7c/4a/5a2cd77e1d3b56e280ab08d8a03d", + "assets/build/pylib-apple/stat.py": "https://files.ballistica.net/cache/ba1/9b/79/01acd372faf539e10c6f87803eae", + "assets/build/pylib-apple/statistics.py": "https://files.ballistica.net/cache/ba1/a3/f2/7578bd81bc4ae980c5caa022e17c", + "assets/build/pylib-apple/string.py": "https://files.ballistica.net/cache/ba1/47/17/7792b18e4d5862d9269c3f2901ef", "assets/build/pylib-apple/stringprep.py": "https://files.ballistica.net/cache/ba1/f0/9b/77cc5580b139f527ee84fff812fc", "assets/build/pylib-apple/struct.py": "https://files.ballistica.net/cache/ba1/10/6d/7a6c0fbac83b2680bbeda8585f8f", - "assets/build/pylib-apple/subprocess.py": "https://files.ballistica.net/cache/ba1/d1/81/62496e6cd420342a1c254c31a461", + "assets/build/pylib-apple/subprocess.py": "https://files.ballistica.net/cache/ba1/fc/86/c516d8f9c386967ae1c34998cb4c", "assets/build/pylib-apple/sunau.py": "https://files.ballistica.net/cache/ba1/99/de/eb56408801fec20de1d7c4a745c8", - "assets/build/pylib-apple/symbol.py": "https://files.ballistica.net/cache/ba1/24/f5/3d4dc0c06af3af1051b792f63cdf", - "assets/build/pylib-apple/symtable.py": "https://files.ballistica.net/cache/ba1/bb/be/5b97a512ed9e491ce7e8be113b61", - "assets/build/pylib-apple/sysconfig.py": "https://files.ballistica.net/cache/ba1/31/09/41072e6015063a344086eca43827", + "assets/build/pylib-apple/symbol.py": "https://files.ballistica.net/cache/ba1/39/4b/212a37298559a013d6cb6ff84516", + "assets/build/pylib-apple/symtable.py": "https://files.ballistica.net/cache/ba1/0a/4d/c31caf2461eaf5a1f3a43824fdbd", + "assets/build/pylib-apple/sysconfig.py": "https://files.ballistica.net/cache/ba1/9e/63/b72faafc1f996a53bbb2cb032797", "assets/build/pylib-apple/tabnanny.py": "https://files.ballistica.net/cache/ba1/f7/ba/da1e12d53ebdf326581c99c7d29b", - "assets/build/pylib-apple/tarfile.py": "https://files.ballistica.net/cache/ba1/27/2c/ea8b64ffbe47c056fa5084893abd", - "assets/build/pylib-apple/telnetlib.py": "https://files.ballistica.net/cache/ba1/12/a2/9022d2838d85ac4a84a5c9ef2e2c", - "assets/build/pylib-apple/tempfile.py": "https://files.ballistica.net/cache/ba1/63/8a/6cce413f8da1bb559e542786db4f", + "assets/build/pylib-apple/tarfile.py": "https://files.ballistica.net/cache/ba1/91/29/2f83e7825374c1b6bf7fb877c032", + "assets/build/pylib-apple/telnetlib.py": "https://files.ballistica.net/cache/ba1/48/28/786c9600155c60407fe91045d587", + "assets/build/pylib-apple/tempfile.py": "https://files.ballistica.net/cache/ba1/a9/30/fd674a8211170b919c31e01e75d4", "assets/build/pylib-apple/textwrap.py": "https://files.ballistica.net/cache/ba1/a9/d4/996c224bb06520a10b7bd86f8ee0", "assets/build/pylib-apple/this.py": "https://files.ballistica.net/cache/ba1/ae/6a/c4cfb10d365db8ca16afef89958e", - "assets/build/pylib-apple/threading.py": "https://files.ballistica.net/cache/ba1/ee/fc/42358b487177069d6fd43aec36e2", - "assets/build/pylib-apple/timeit.py": "https://files.ballistica.net/cache/ba1/a5/a4/7e5f848d094fbf83e52dcd8f48c6", - "assets/build/pylib-apple/token.py": "https://files.ballistica.net/cache/ba1/36/b9/9ae6aa89c0baadc5d80dd4127b7f", - "assets/build/pylib-apple/tokenize.py": "https://files.ballistica.net/cache/ba1/73/b0/fd1563d114d63bdd21bceefa56be", - "assets/build/pylib-apple/trace.py": "https://files.ballistica.net/cache/ba1/57/17/40229e4893d4eb9a5faaae113139", - "assets/build/pylib-apple/traceback.py": "https://files.ballistica.net/cache/ba1/ac/cc/3f70a62f7cca00e4107df8cfa112", + "assets/build/pylib-apple/threading.py": "https://files.ballistica.net/cache/ba1/ba/31/8a5be4b90aa2654e0c14fd8fe1ae", + "assets/build/pylib-apple/timeit.py": "https://files.ballistica.net/cache/ba1/70/2a/4dc25a032c4975b059f972c76e0f", + "assets/build/pylib-apple/token.py": "https://files.ballistica.net/cache/ba1/da/77/a96be5a40982cc622f9812ee96e1", + "assets/build/pylib-apple/tokenize.py": "https://files.ballistica.net/cache/ba1/49/2d/09c9c18b942346de0a1eb5932d39", + "assets/build/pylib-apple/trace.py": "https://files.ballistica.net/cache/ba1/50/a3/c49ac220158edc7a0ea93dc4a238", + "assets/build/pylib-apple/traceback.py": "https://files.ballistica.net/cache/ba1/e4/88/dccd9ddcb29a024b7a82d17646ae", "assets/build/pylib-apple/tracemalloc.py": "https://files.ballistica.net/cache/ba1/b5/1e/62e69ad7c2181e30fac478d4f936", "assets/build/pylib-apple/tty.py": "https://files.ballistica.net/cache/ba1/ec/ea/2421fecb0e38e38d55cf0ce2b0e2", - "assets/build/pylib-apple/types.py": "https://files.ballistica.net/cache/ba1/2f/7a/3bd0b56fdcddfc3e9edb6b556925", - "assets/build/pylib-apple/typing.py": "https://files.ballistica.net/cache/ba1/76/b3/0ae27201749a7b8e6ae9325d2a06", + "assets/build/pylib-apple/types.py": "https://files.ballistica.net/cache/ba1/21/89/94447b44682aa438ea205a7e4a06", + "assets/build/pylib-apple/typing.py": "https://files.ballistica.net/cache/ba1/02/aa/0d5b397d0080a207ad66de9495c2", "assets/build/pylib-apple/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/a2/c9/6d1cda1b043897ad0b5b043e7112", "assets/build/pylib-apple/urllib/error.py": "https://files.ballistica.net/cache/ba1/09/dd/15e4e9e675bd3242b0d5fb0f2707", - "assets/build/pylib-apple/urllib/parse.py": "https://files.ballistica.net/cache/ba1/0f/18/3bc3354a5520bc6e0f892404028f", - "assets/build/pylib-apple/urllib/request.py": "https://files.ballistica.net/cache/ba1/03/9e/0da6865195d8e69d43ff47c43efe", + "assets/build/pylib-apple/urllib/parse.py": "https://files.ballistica.net/cache/ba1/87/98/9274a8b8db5063efc3b8c5daa62f", + "assets/build/pylib-apple/urllib/request.py": "https://files.ballistica.net/cache/ba1/d7/67/a06cc8547482f03e23c312d571df", "assets/build/pylib-apple/urllib/response.py": "https://files.ballistica.net/cache/ba1/03/b2/ec9cd1798de4004d98d213362713", - "assets/build/pylib-apple/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/23/40/c172a9879ccb2bd76adf0db29567", + "assets/build/pylib-apple/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/ba/83/b9c99d5b11514b827d64f9fd6d33", "assets/build/pylib-apple/uu.py": "https://files.ballistica.net/cache/ba1/02/7a/d6fed645dcff0d4aff84e3cea58e", - "assets/build/pylib-apple/uuid.py": "https://files.ballistica.net/cache/ba1/fa/e3/1abf5dee0941c2d15cf45f9f95be", - "assets/build/pylib-apple/warnings.py": "https://files.ballistica.net/cache/ba1/08/9c/d3b49f9ffdf97270f336a4abb83b", + "assets/build/pylib-apple/uuid.py": "https://files.ballistica.net/cache/ba1/8b/9a/f94052f87759d248f7feb0742214", + "assets/build/pylib-apple/warnings.py": "https://files.ballistica.net/cache/ba1/65/5c/5e6cf7bf573f4fae2344c68bed04", "assets/build/pylib-apple/wave.py": "https://files.ballistica.net/cache/ba1/4d/a0/b093aa87d58ab11be45e1e8dd05a", - "assets/build/pylib-apple/weakref.py": "https://files.ballistica.net/cache/ba1/19/e6/014589327dc84e8fd0e5fb180345", - "assets/build/pylib-apple/webbrowser.py": "https://files.ballistica.net/cache/ba1/66/26/d905690b0376e7ff4c36a5a5b31b", + "assets/build/pylib-apple/weakref.py": "https://files.ballistica.net/cache/ba1/2a/74/9f4d631ef9a7e998ec9fa040fea9", + "assets/build/pylib-apple/webbrowser.py": "https://files.ballistica.net/cache/ba1/13/d9/5502f76e359f9321f54b77b93f27", "assets/build/pylib-apple/xdrlib.py": "https://files.ballistica.net/cache/ba1/b7/83/ac6e63a15cead601475a09350849", "assets/build/pylib-apple/xml/__init__.py": "https://files.ballistica.net/cache/ba1/3f/bd/6072ff48fc04c3af1dcbb8005adf", "assets/build/pylib-apple/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/97/e8/e3ea178b500cab89a64c7e5d3d81", @@ -3388,53 +3393,88 @@ "assets/build/pylib-apple/xml/dom/domreg.py": "https://files.ballistica.net/cache/ba1/7b/7d/a7cea1700813d14a0909085369b0", "assets/build/pylib-apple/xml/dom/expatbuilder.py": "https://files.ballistica.net/cache/ba1/a1/36/34d0eea18937a0e2ae01a817cb72", "assets/build/pylib-apple/xml/dom/minicompat.py": "https://files.ballistica.net/cache/ba1/97/0c/a28bca0a0bd221a70cb6377f1bef", - "assets/build/pylib-apple/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/5c/de/fab4f56822203219d619f4aa2979", - "assets/build/pylib-apple/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/88/24/6f3b6cb8d8f26cf25ff26f33f41a", + "assets/build/pylib-apple/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/15/c2/a7bb9dbeebf7e3082b9fc932b008", + "assets/build/pylib-apple/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/bc/df/46a7e10fac8b5dd6c0361aaef6a2", "assets/build/pylib-apple/xml/dom/xmlbuilder.py": "https://files.ballistica.net/cache/ba1/03/bc/e639a0fd394cf537f9c29993179b", "assets/build/pylib-apple/xml/etree/ElementInclude.py": "https://files.ballistica.net/cache/ba1/e9/83/50f2fae2edafbaacfd9e278d9d7b", - "assets/build/pylib-apple/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/cb/46/039760bc837ae820a6e762e325d4", - "assets/build/pylib-apple/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/df/14/c899fb50601282d3c01f77eec46f", + "assets/build/pylib-apple/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/73/a6/0633b38a4c9db85b021447c9457c", + "assets/build/pylib-apple/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/12/f9/5f273773b21dc0cd45cce009170e", "assets/build/pylib-apple/xml/etree/__init__.py": "https://files.ballistica.net/cache/ba1/87/76/e8e68d23559ff4b14e010dad2a32", "assets/build/pylib-apple/xml/etree/cElementTree.py": "https://files.ballistica.net/cache/ba1/50/ec/0cd835d512fa5ca9bcada07c27ab", "assets/build/pylib-apple/xml/parsers/__init__.py": "https://files.ballistica.net/cache/ba1/2c/3e/7f79fe325f250709ab2c01bedada", "assets/build/pylib-apple/xml/parsers/expat.py": "https://files.ballistica.net/cache/ba1/58/65/6ea61e8a28312897baa67deeac2e", - "assets/build/pylib-apple/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/11/5f/568e95e5ccd7b21ebdccdfb5f469", + "assets/build/pylib-apple/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/9c/f8/3660a1de69e4e8c18a99ee85ad07", "assets/build/pylib-apple/xml/sax/_exceptions.py": "https://files.ballistica.net/cache/ba1/82/3b/a63de9807fe5698ad1283e70e261", "assets/build/pylib-apple/xml/sax/expatreader.py": "https://files.ballistica.net/cache/ba1/1a/ac/411c7140a4dc1f075acad11a899f", "assets/build/pylib-apple/xml/sax/handler.py": "https://files.ballistica.net/cache/ba1/1c/69/1ebd1278f335c1f6283bded9e89b", - "assets/build/pylib-apple/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/27/a5/e7127b26654d00024604ccf03f2c", + "assets/build/pylib-apple/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/2f/a5/38f2998b6ed24c674aa04a32d899", "assets/build/pylib-apple/xml/sax/xmlreader.py": "https://files.ballistica.net/cache/ba1/41/e7/9fcf670b326880d5452a7cc4cc7c", "assets/build/pylib-apple/xmlrpc/__init__.py": "https://files.ballistica.net/cache/ba1/7a/ee/61deeb7b264890b54b1cbb894cf8", - "assets/build/pylib-apple/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/7a/42/f61bd8528d07476b5f6ed58fda79", + "assets/build/pylib-apple/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/64/07/7249de27571c45a051572d3e5f3d", "assets/build/pylib-apple/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/0b/6d/4d9c74b62db0068856f63ad0f29e", "assets/build/pylib-apple/zipapp.py": "https://files.ballistica.net/cache/ba1/bc/39/2d745b00133cddd197c3a4ee400e", - "assets/build/pylib-apple/zipfile.py": "https://files.ballistica.net/cache/ba1/46/cd/bcbeb2f687acdc08aa40b6415f54", - "assets/build/windows/x64/DLLs/_asyncio.pyd": "https://files.ballistica.net/cache/ba1/79/a2/d075d8d6ca603d4fbe36468d0398", - "assets/build/windows/x64/DLLs/_bz2.pyd": "https://files.ballistica.net/cache/ba1/5b/6f/0626264694abdbe32e548151baa9", - "assets/build/windows/x64/DLLs/_ctypes.pyd": "https://files.ballistica.net/cache/ba1/ed/4a/4bf0275f28895f6eac4efd1764d8", - "assets/build/windows/x64/DLLs/_decimal.pyd": "https://files.ballistica.net/cache/ba1/9f/42/3abb45baa0b99f7436a10007ea31", - "assets/build/windows/x64/DLLs/_elementtree.pyd": "https://files.ballistica.net/cache/ba1/e0/fe/fd068c1f9de65560504da907fd9e", - "assets/build/windows/x64/DLLs/_hashlib.pyd": "https://files.ballistica.net/cache/ba1/d3/99/9b38158a529d8593013c12d59f70", - "assets/build/windows/x64/DLLs/_lzma.pyd": "https://files.ballistica.net/cache/ba1/f2/f0/fe11670d2352dab0520659be6914", - "assets/build/windows/x64/DLLs/_msi.pyd": "https://files.ballistica.net/cache/ba1/c0/df/8fe1b49d349386ad46c1b7030e92", - "assets/build/windows/x64/DLLs/_multiprocessing.pyd": "https://files.ballistica.net/cache/ba1/4b/71/009d58cff50c84bf2e0bbf8a65f0", - "assets/build/windows/x64/DLLs/_overlapped.pyd": "https://files.ballistica.net/cache/ba1/84/97/ed72c62697c3b6e5780370630bc4", - "assets/build/windows/x64/DLLs/_queue.pyd": "https://files.ballistica.net/cache/ba1/7c/7c/50e784f2f5288f5fedb6b1638e26", - "assets/build/windows/x64/DLLs/_socket.pyd": "https://files.ballistica.net/cache/ba1/a1/dc/726c8725a5cfb5ad556c9d3847cb", - "assets/build/windows/x64/DLLs/_sqlite3.pyd": "https://files.ballistica.net/cache/ba1/96/fa/f1ff796cab899ce9573a9a73f62f", - "assets/build/windows/x64/DLLs/_ssl.pyd": "https://files.ballistica.net/cache/ba1/e9/72/05989648ab1f3fe647d2b6f8c91f", - "assets/build/windows/x64/DLLs/libcrypto-1_1.dll": "https://files.ballistica.net/cache/ba1/83/3c/c7d85957ad342f8e7ea87bf6adf5", - "assets/build/windows/x64/DLLs/libssl-1_1.dll": "https://files.ballistica.net/cache/ba1/54/a9/908cee00992affbd1d8c79f6c62a", - "assets/build/windows/x64/DLLs/py.ico": "https://files.ballistica.net/cache/ba1/79/bc/dc46595e078d8a621d1e6d407759", - "assets/build/windows/x64/DLLs/pyc.ico": "https://files.ballistica.net/cache/ba1/f3/ac/9ffa5b67cb8fb680f133f36e4a31", - "assets/build/windows/x64/DLLs/pyd.ico": "https://files.ballistica.net/cache/ba1/31/c3/e0e83e275f531d26b1068f414294", - "assets/build/windows/x64/DLLs/pyexpat.pyd": "https://files.ballistica.net/cache/ba1/69/4b/536c21f6c99f7f2b0d34c45a45ab", - "assets/build/windows/x64/DLLs/python_lib.cat": "https://files.ballistica.net/cache/ba1/bd/82/eb288997be445630a5a4b1b0fea3", - "assets/build/windows/x64/DLLs/python_tools.cat": "https://files.ballistica.net/cache/ba1/2e/12/4877dfe0d64e5aa23e7af03c864e", - "assets/build/windows/x64/DLLs/select.pyd": "https://files.ballistica.net/cache/ba1/e0/f5/c8f325617adc8044c08e82919510", - "assets/build/windows/x64/DLLs/sqlite3.dll": "https://files.ballistica.net/cache/ba1/86/07/bee4ff520d4a895606aa534c230d", - "assets/build/windows/x64/DLLs/unicodedata.pyd": "https://files.ballistica.net/cache/ba1/1d/28/50891bbc86694e97fe530bdf9f31", - "assets/build/windows/x64/DLLs/winsound.pyd": "https://files.ballistica.net/cache/ba1/29/db/65e591d3763eaf360268be688291", + "assets/build/pylib-apple/zipfile.py": "https://files.ballistica.net/cache/ba1/75/54/c1fa31473f6e09efacc3e1cc3464", + "assets/build/pylib-apple/zipimport.py": "https://files.ballistica.net/cache/ba1/1f/fa/e11a7b5e9b1191a74bb80f48dc9f", + "assets/build/windows/x64/DLLs/_asyncio.pyd": "https://files.ballistica.net/cache/ba1/6e/32/174cf735f812c3270165eaf98f4d", + "assets/build/windows/x64/DLLs/_asyncio_d.pyd": "https://files.ballistica.net/cache/ba1/29/b1/6217ac66d4497f085bfc939080da", + "assets/build/windows/x64/DLLs/_bz2.pyd": "https://files.ballistica.net/cache/ba1/d3/75/1580a4974ad6ce4d9606cf2bb1f6", + "assets/build/windows/x64/DLLs/_bz2_d.pyd": "https://files.ballistica.net/cache/ba1/05/aa/b54eaef3e0a4478de582a34e4aab", + "assets/build/windows/x64/DLLs/_ctypes.pyd": "https://files.ballistica.net/cache/ba1/3d/43/46782f4468dd494155787303ec54", + "assets/build/windows/x64/DLLs/_ctypes_d.pyd": "https://files.ballistica.net/cache/ba1/70/52/eb0fa1e4703cb379dc395604c071", + "assets/build/windows/x64/DLLs/_ctypes_test.pyd": "https://files.ballistica.net/cache/ba1/2c/80/1527727254f50408e703611236ee", + "assets/build/windows/x64/DLLs/_ctypes_test_d.pyd": "https://files.ballistica.net/cache/ba1/36/6a/d67179765b5d0bf98aa8dd8f5a9e", + "assets/build/windows/x64/DLLs/_decimal.pyd": "https://files.ballistica.net/cache/ba1/af/97/1a4d0c6a2e78a2550899c8e51b30", + "assets/build/windows/x64/DLLs/_decimal_d.pyd": "https://files.ballistica.net/cache/ba1/21/34/1c65855a52881339dc790e69e593", + "assets/build/windows/x64/DLLs/_elementtree.pyd": "https://files.ballistica.net/cache/ba1/45/57/6b2be729f3e100061b3de9e596a7", + "assets/build/windows/x64/DLLs/_elementtree_d.pyd": "https://files.ballistica.net/cache/ba1/87/4a/6a8f5483d1cbaaec4445a585ec40", + "assets/build/windows/x64/DLLs/_hashlib.pyd": "https://files.ballistica.net/cache/ba1/d0/77/82b2ef9642f18369bdc5b94b4e16", + "assets/build/windows/x64/DLLs/_hashlib_d.pyd": "https://files.ballistica.net/cache/ba1/5c/37/1d22f6797f5604318418171fb195", + "assets/build/windows/x64/DLLs/_lzma.pyd": "https://files.ballistica.net/cache/ba1/22/79/5ea4b7f8a42b2d3c7eb4f06c718f", + "assets/build/windows/x64/DLLs/_lzma_d.pyd": "https://files.ballistica.net/cache/ba1/32/5f/7adce0b4f2415637b98c4a8c1967", + "assets/build/windows/x64/DLLs/_msi.pyd": "https://files.ballistica.net/cache/ba1/41/1b/36233d6878deefd86a713af966c5", + "assets/build/windows/x64/DLLs/_msi_d.pyd": "https://files.ballistica.net/cache/ba1/42/7b/78e8442f1f9ea41ca8a5f8c8342a", + "assets/build/windows/x64/DLLs/_multiprocessing.pyd": "https://files.ballistica.net/cache/ba1/33/f2/46d4ff461db2d5d6262a69552c9e", + "assets/build/windows/x64/DLLs/_multiprocessing_d.pyd": "https://files.ballistica.net/cache/ba1/57/91/e4409ffc2937e7d9c83bc8da092e", + "assets/build/windows/x64/DLLs/_overlapped.pyd": "https://files.ballistica.net/cache/ba1/fd/19/b386647908b3d4c0a36626614143", + "assets/build/windows/x64/DLLs/_overlapped_d.pyd": "https://files.ballistica.net/cache/ba1/22/a6/4fc4c59c9c25ccfc66537f00e9b4", + "assets/build/windows/x64/DLLs/_queue.pyd": "https://files.ballistica.net/cache/ba1/55/42/dfca0122165e4ccd86d350650c24", + "assets/build/windows/x64/DLLs/_queue_d.pyd": "https://files.ballistica.net/cache/ba1/8d/8a/98771d0b0871060a55b7fa2819be", + "assets/build/windows/x64/DLLs/_socket.pyd": "https://files.ballistica.net/cache/ba1/d2/ee/d107aeb379ab74d7df38915115a0", + "assets/build/windows/x64/DLLs/_socket_d.pyd": "https://files.ballistica.net/cache/ba1/c1/59/0fe5112152e9409864bfab7c31bf", + "assets/build/windows/x64/DLLs/_sqlite3.pyd": "https://files.ballistica.net/cache/ba1/e0/96/760f86b97227e15a444e41384306", + "assets/build/windows/x64/DLLs/_sqlite3_d.pyd": "https://files.ballistica.net/cache/ba1/98/f5/5db272cba607a9af62c1056307d0", + "assets/build/windows/x64/DLLs/_ssl.pyd": "https://files.ballistica.net/cache/ba1/50/5f/2974db8e35d3f80a8d356f0bd21a", + "assets/build/windows/x64/DLLs/_ssl_d.pyd": "https://files.ballistica.net/cache/ba1/60/b5/976c8fa2633abe2bb9e977e55c61", + "assets/build/windows/x64/DLLs/_testbuffer.pyd": "https://files.ballistica.net/cache/ba1/ba/03/44c93316695f8c1f2325e102548c", + "assets/build/windows/x64/DLLs/_testbuffer_d.pyd": "https://files.ballistica.net/cache/ba1/7b/ea/369ddcdf1bc0a9584291ba36d7dd", + "assets/build/windows/x64/DLLs/_testcapi.pyd": "https://files.ballistica.net/cache/ba1/ef/22/ef19ccfd61c67c94f1fe567c29e2", + "assets/build/windows/x64/DLLs/_testcapi_d.pyd": "https://files.ballistica.net/cache/ba1/b3/46/d5456df3056beb0e2b16e44b3290", + "assets/build/windows/x64/DLLs/_testconsole.pyd": "https://files.ballistica.net/cache/ba1/40/e5/a4d9a8d1d7bc4c94b72b1c6472ad", + "assets/build/windows/x64/DLLs/_testconsole_d.pyd": "https://files.ballistica.net/cache/ba1/99/a4/f6e1219b8eeae1a324720befc2ea", + "assets/build/windows/x64/DLLs/_testimportmultiple.pyd": "https://files.ballistica.net/cache/ba1/38/7d/b04a08e4a09caeb48716aef84baf", + "assets/build/windows/x64/DLLs/_testimportmultiple_d.pyd": "https://files.ballistica.net/cache/ba1/7e/8a/6639d7089235d5ce46a33583afe5", + "assets/build/windows/x64/DLLs/_testmultiphase.pyd": "https://files.ballistica.net/cache/ba1/3c/e6/008a6b59889fffd3f6235e2e2747", + "assets/build/windows/x64/DLLs/_testmultiphase_d.pyd": "https://files.ballistica.net/cache/ba1/5a/29/0bf85c28e0e4c5a58962a3cf4621", + "assets/build/windows/x64/DLLs/_tkinter.pyd": "https://files.ballistica.net/cache/ba1/6a/48/7f70645bda43c2f21c419f3d20af", + "assets/build/windows/x64/DLLs/_tkinter_d.lib": "https://files.ballistica.net/cache/ba1/9d/de/ada57ac91b8397aae5ce63d5acb0", + "assets/build/windows/x64/DLLs/_tkinter_d.pyd": "https://files.ballistica.net/cache/ba1/ae/71/a9aec95391fb9748f98e350b9640", + "assets/build/windows/x64/DLLs/libcrypto-1_1.dll": "https://files.ballistica.net/cache/ba1/e7/2f/6d9ca3aaa9c7f1c18e695f3d592a", + "assets/build/windows/x64/DLLs/libffi-7.dll": "https://files.ballistica.net/cache/ba1/e7/11/bca2299d83f69402396f7e0c5955", + "assets/build/windows/x64/DLLs/libssl-1_1.dll": "https://files.ballistica.net/cache/ba1/62/7b/aa0021d12fd2c9ffe6f8f061339a", + "assets/build/windows/x64/DLLs/pyexpat.pyd": "https://files.ballistica.net/cache/ba1/e8/54/47734b608f3741116698f2eb2f9f", + "assets/build/windows/x64/DLLs/pyexpat_d.pyd": "https://files.ballistica.net/cache/ba1/ea/7d/16329ec77d562afc9ab29a190762", + "assets/build/windows/x64/DLLs/python_lib.cat": "https://files.ballistica.net/cache/ba1/7d/72/921b6c6ac45ca70da316976b7249", + "assets/build/windows/x64/DLLs/python_tools.cat": "https://files.ballistica.net/cache/ba1/fe/bc/74e00a162e3a410e94a071b23a26", + "assets/build/windows/x64/DLLs/select.pyd": "https://files.ballistica.net/cache/ba1/71/b9/c5271872b0daba597cb8f1a02ea4", + "assets/build/windows/x64/DLLs/select_d.pyd": "https://files.ballistica.net/cache/ba1/2f/1f/e51ccbb8579ffbba07b0f5001f54", + "assets/build/windows/x64/DLLs/sqlite3.dll": "https://files.ballistica.net/cache/ba1/17/dd/c3dccbbabea5e74a494ddd1347c2", + "assets/build/windows/x64/DLLs/sqlite3_d.dll": "https://files.ballistica.net/cache/ba1/90/a4/65ee31ae896e0db3b719483c762e", + "assets/build/windows/x64/DLLs/tcl86t.dll": "https://files.ballistica.net/cache/ba1/61/af/a7fc7edb673bb6e11ff19a45a5ca", + "assets/build/windows/x64/DLLs/tk86t.dll": "https://files.ballistica.net/cache/ba1/0f/9b/e9b784626f42d90a782d2a43565a", + "assets/build/windows/x64/DLLs/unicodedata.pyd": "https://files.ballistica.net/cache/ba1/12/49/f5a5183a382c23d5851be5a5a47d", + "assets/build/windows/x64/DLLs/unicodedata_d.pyd": "https://files.ballistica.net/cache/ba1/25/5c/61c65e5cbe0851107385b11bde79", + "assets/build/windows/x64/DLLs/winsound.pyd": "https://files.ballistica.net/cache/ba1/50/90/2958cc3ce6454971b608c12c1c20", + "assets/build/windows/x64/DLLs/winsound_d.pyd": "https://files.ballistica.net/cache/ba1/5b/c9/4c66575b45e7d6d34748d1650b37", "assets/build/windows/x64/Lib/__future__.py": "https://files.ballistica.net/cache/ba1/5c/55/fb518c9fb289a2ea4461ad6186f0", "assets/build/windows/x64/Lib/__phello__.foo.py": "https://files.ballistica.net/cache/ba1/16/80/d0e73186e8d0c1ea5fe40684e67d", "assets/build/windows/x64/Lib/_bootlocale.py": "https://files.ballistica.net/cache/ba1/6f/f1/7d40ba193553db1028a52ac39916", @@ -3458,6 +3498,7 @@ "assets/build/windows/x64/Lib/ast.py": "https://files.ballistica.net/cache/ba1/54/59/698ce41b1e9df6fb3771550bfdf5", "assets/build/windows/x64/Lib/asynchat.py": "https://files.ballistica.net/cache/ba1/08/55/857f80dcdf35425707336aa697cc", "assets/build/windows/x64/Lib/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/55/fc/23407700f89c81735e78e7da5d2d", + "assets/build/windows/x64/Lib/asyncio/__main__.py": "https://files.ballistica.net/cache/ba1/07/56/1b86818d0401001d9d067edc8ce4", "assets/build/windows/x64/Lib/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/6d/41/6e56c2ca5c8d92596572c3fc0589", "assets/build/windows/x64/Lib/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/c3/cf/b78c0bef4cb41bcb051486346a57", "assets/build/windows/x64/Lib/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/5e/a3/0a696cdaab8634630bd400f3c536", @@ -3465,6 +3506,7 @@ "assets/build/windows/x64/Lib/asyncio/constants.py": "https://files.ballistica.net/cache/ba1/01/9e/a596fa8ed4a3b9d761289fc85044", "assets/build/windows/x64/Lib/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/a5/e1/505f36fd73a0f4cc1a02bb928225", "assets/build/windows/x64/Lib/asyncio/events.py": "https://files.ballistica.net/cache/ba1/c5/18/716d6a29cdcf1d69152768297410", + "assets/build/windows/x64/Lib/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/ff/c9/1391005ad3c50204c126c3a5560c", "assets/build/windows/x64/Lib/asyncio/format_helpers.py": "https://files.ballistica.net/cache/ba1/5d/91/b2d0791872c4c17be0054212fbec", "assets/build/windows/x64/Lib/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/cc/a4/6255ad789aacb6d79a3e7bca1734", "assets/build/windows/x64/Lib/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/fc/77/0b6646e95186daa896a17a409731", @@ -3475,10 +3517,12 @@ "assets/build/windows/x64/Lib/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/10/af/851dd38ed2a0a185bfc2e9b635b1", "assets/build/windows/x64/Lib/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/17/da/6cdec425e892917a02d773808d36", "assets/build/windows/x64/Lib/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/2a/76/32626fe24c543b105de251421a41", + "assets/build/windows/x64/Lib/asyncio/staggered.py": "https://files.ballistica.net/cache/ba1/e0/2b/266b926832c6c643c3676a478fb3", "assets/build/windows/x64/Lib/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/74/21/df0f11c35eb1c4acd4343c59ccde", "assets/build/windows/x64/Lib/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/25/33/ea8b8b867b57b0260f1d774fe4a6", "assets/build/windows/x64/Lib/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/3c/69/224db8e9bd2861056d011192a61a", "assets/build/windows/x64/Lib/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/97/56/520378b4483798bcb697c4c1146c", + "assets/build/windows/x64/Lib/asyncio/trsock.py": "https://files.ballistica.net/cache/ba1/4e/55/52931f6a570db262f91cced96f32", "assets/build/windows/x64/Lib/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/1e/f2/973acec4a3265ac4f18509cde4d8", "assets/build/windows/x64/Lib/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/19/78/a85e6a62af3af13a0a48b8cc9a45", "assets/build/windows/x64/Lib/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/09/f9/55f789b125d19e29d9fd9a3e735a", @@ -3523,59 +3567,6 @@ "assets/build/windows/x64/Lib/ctypes/macholib/fetch_macholib": "https://files.ballistica.net/cache/ba1/56/a1/345fb67665a88971680632d1a87f", "assets/build/windows/x64/Lib/ctypes/macholib/fetch_macholib.bat": "https://files.ballistica.net/cache/ba1/b0/39/edd85cc39a69b6d64e594029ece9", "assets/build/windows/x64/Lib/ctypes/macholib/framework.py": "https://files.ballistica.net/cache/ba1/a5/1c/8beab7cc8af1c46f8d3e4809dadf", - "assets/build/windows/x64/Lib/ctypes/test/__init__.py": "https://files.ballistica.net/cache/ba1/11/fb/0da924e077bb9a1afafe1dc767be", - "assets/build/windows/x64/Lib/ctypes/test/__main__.py": "https://files.ballistica.net/cache/ba1/9a/da/6eaa6c0c56746af5cf4bdd771557", - "assets/build/windows/x64/Lib/ctypes/test/test_anon.py": "https://files.ballistica.net/cache/ba1/79/fa/bf6650ae19aa0ba505f7291bf4ab", - "assets/build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py": "https://files.ballistica.net/cache/ba1/f8/fc/bcaadf1046061102f59db3268425", - "assets/build/windows/x64/Lib/ctypes/test/test_arrays.py": "https://files.ballistica.net/cache/ba1/52/a7/a9d3c0f9863c0b341fbac462ecf3", - "assets/build/windows/x64/Lib/ctypes/test/test_as_parameter.py": "https://files.ballistica.net/cache/ba1/b8/c1/0bff09c49f3a654b925d3b3409f2", - "assets/build/windows/x64/Lib/ctypes/test/test_bitfields.py": "https://files.ballistica.net/cache/ba1/4b/e6/95f29c244114a91f79cfb11802e7", - "assets/build/windows/x64/Lib/ctypes/test/test_buffers.py": "https://files.ballistica.net/cache/ba1/a9/4a/036eb8ef12e300b8d4ae24bedd37", - "assets/build/windows/x64/Lib/ctypes/test/test_bytes.py": "https://files.ballistica.net/cache/ba1/91/89/7bbf461f94a3966a60de55b8ae2d", - "assets/build/windows/x64/Lib/ctypes/test/test_byteswap.py": "https://files.ballistica.net/cache/ba1/36/69/4798c06e3f86c279eb905febca99", - "assets/build/windows/x64/Lib/ctypes/test/test_callbacks.py": "https://files.ballistica.net/cache/ba1/57/5a/a6140a9f31ca07e7465ce393b09b", - "assets/build/windows/x64/Lib/ctypes/test/test_cast.py": "https://files.ballistica.net/cache/ba1/10/b6/c34ba4cf7a7604d7dc482f32a782", - "assets/build/windows/x64/Lib/ctypes/test/test_cfuncs.py": "https://files.ballistica.net/cache/ba1/74/68/d5e47a7aad991e8de34ceae19200", - "assets/build/windows/x64/Lib/ctypes/test/test_checkretval.py": "https://files.ballistica.net/cache/ba1/5f/8c/7fb102f7caeb5cab16d87d4c7f55", - "assets/build/windows/x64/Lib/ctypes/test/test_delattr.py": "https://files.ballistica.net/cache/ba1/b1/3d/b003d9e2810f5581514ca58a6308", - "assets/build/windows/x64/Lib/ctypes/test/test_errno.py": "https://files.ballistica.net/cache/ba1/75/8a/4131b2749d5dc42a86cc192f55fd", - "assets/build/windows/x64/Lib/ctypes/test/test_find.py": "https://files.ballistica.net/cache/ba1/6e/1d/213221972fa0fd4c1b88ba8afa71", - "assets/build/windows/x64/Lib/ctypes/test/test_frombuffer.py": "https://files.ballistica.net/cache/ba1/6b/df/a542fc7b4aa37a60f76e03f4d986", - "assets/build/windows/x64/Lib/ctypes/test/test_funcptr.py": "https://files.ballistica.net/cache/ba1/bc/46/ccf34b782f0acb63be140c11a260", - "assets/build/windows/x64/Lib/ctypes/test/test_functions.py": "https://files.ballistica.net/cache/ba1/58/c3/97d1aec72c9a939173f11d746842", - "assets/build/windows/x64/Lib/ctypes/test/test_incomplete.py": "https://files.ballistica.net/cache/ba1/bd/25/2bfeaab24cd8ff7626570036daf1", - "assets/build/windows/x64/Lib/ctypes/test/test_init.py": "https://files.ballistica.net/cache/ba1/49/54/6bf2fd523e037035bafa06118d0b", - "assets/build/windows/x64/Lib/ctypes/test/test_internals.py": "https://files.ballistica.net/cache/ba1/8e/9d/93275f2a392378c6276ec7c99015", - "assets/build/windows/x64/Lib/ctypes/test/test_keeprefs.py": "https://files.ballistica.net/cache/ba1/b7/41/2f70123df4abcf72f0a988cd7ce1", - "assets/build/windows/x64/Lib/ctypes/test/test_libc.py": "https://files.ballistica.net/cache/ba1/a7/7b/9c5b40b5cb9e2fadf02dbd6b0c13", - "assets/build/windows/x64/Lib/ctypes/test/test_loading.py": "https://files.ballistica.net/cache/ba1/14/58/e1cdf7a994be7f3c7f030bb2552e", - "assets/build/windows/x64/Lib/ctypes/test/test_macholib.py": "https://files.ballistica.net/cache/ba1/d1/aa/214f47b26bc8d0ae0964460de276", - "assets/build/windows/x64/Lib/ctypes/test/test_memfunctions.py": "https://files.ballistica.net/cache/ba1/3a/51/a10c752ad528a7f14505fdf5fab6", - "assets/build/windows/x64/Lib/ctypes/test/test_numbers.py": "https://files.ballistica.net/cache/ba1/1a/db/775ddcd37ee83d1f64108dcda505", - "assets/build/windows/x64/Lib/ctypes/test/test_objects.py": "https://files.ballistica.net/cache/ba1/6a/ef/85bb0a619557670502df3dbbd1a3", - "assets/build/windows/x64/Lib/ctypes/test/test_parameters.py": "https://files.ballistica.net/cache/ba1/f7/86/40e418ef4520322a6b3da1df353d", - "assets/build/windows/x64/Lib/ctypes/test/test_pep3118.py": "https://files.ballistica.net/cache/ba1/58/60/8f910fa979cd42bb3aaa7c4d00a7", - "assets/build/windows/x64/Lib/ctypes/test/test_pickling.py": "https://files.ballistica.net/cache/ba1/a4/f5/aeee374a1d9b611dfc0a3489edda", - "assets/build/windows/x64/Lib/ctypes/test/test_pointers.py": "https://files.ballistica.net/cache/ba1/fb/bc/7a08cc13c51054a0a72d3b9fe004", - "assets/build/windows/x64/Lib/ctypes/test/test_prototypes.py": "https://files.ballistica.net/cache/ba1/76/32/6c72fa8188c7025095457a11879a", - "assets/build/windows/x64/Lib/ctypes/test/test_python_api.py": "https://files.ballistica.net/cache/ba1/4b/f9/11e986c1a722e2e3db89ffe332dd", - "assets/build/windows/x64/Lib/ctypes/test/test_random_things.py": "https://files.ballistica.net/cache/ba1/a8/63/83071d7698501c489a236bb39c72", - "assets/build/windows/x64/Lib/ctypes/test/test_refcounts.py": "https://files.ballistica.net/cache/ba1/6a/b3/8a7230e880dd675b2ae0f2eaf5b4", - "assets/build/windows/x64/Lib/ctypes/test/test_repr.py": "https://files.ballistica.net/cache/ba1/0e/95/2b164f05e2f99e45a255d3ab3856", - "assets/build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py": "https://files.ballistica.net/cache/ba1/3b/c4/aa5ca297ce1e3eaca180259ede73", - "assets/build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py": "https://files.ballistica.net/cache/ba1/09/cf/3a026c8744d673816c8d626483b6", - "assets/build/windows/x64/Lib/ctypes/test/test_sizes.py": "https://files.ballistica.net/cache/ba1/dc/00/8f84ea533448de7d48f41b769819", - "assets/build/windows/x64/Lib/ctypes/test/test_slicing.py": "https://files.ballistica.net/cache/ba1/af/d0/f99e0ce00f665a23e4a1dcceef8c", - "assets/build/windows/x64/Lib/ctypes/test/test_stringptr.py": "https://files.ballistica.net/cache/ba1/c6/7a/e0867150d506ea63f4ae34c1cbc8", - "assets/build/windows/x64/Lib/ctypes/test/test_strings.py": "https://files.ballistica.net/cache/ba1/ea/1c/7174510870a5fff42266c97726ea", - "assets/build/windows/x64/Lib/ctypes/test/test_struct_fields.py": "https://files.ballistica.net/cache/ba1/01/aa/5292f85b33841f8ae947ca7a859b", - "assets/build/windows/x64/Lib/ctypes/test/test_structures.py": "https://files.ballistica.net/cache/ba1/9e/6f/de97b390ec7e2436db7567a32d96", - "assets/build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py": "https://files.ballistica.net/cache/ba1/01/cd/b80592a202108effcdd77f7a7a86", - "assets/build/windows/x64/Lib/ctypes/test/test_unicode.py": "https://files.ballistica.net/cache/ba1/ee/f9/96005b42d2283b7e3644f6de9b4c", - "assets/build/windows/x64/Lib/ctypes/test/test_values.py": "https://files.ballistica.net/cache/ba1/2d/60/8e6f663ff3b8c8234e4954233ab1", - "assets/build/windows/x64/Lib/ctypes/test/test_varsize_struct.py": "https://files.ballistica.net/cache/ba1/63/3b/616299d747282eff0b424b2a6eba", - "assets/build/windows/x64/Lib/ctypes/test/test_win32.py": "https://files.ballistica.net/cache/ba1/dc/f4/ec74f996e3fa899b54a8eba2f835", - "assets/build/windows/x64/Lib/ctypes/test/test_wintypes.py": "https://files.ballistica.net/cache/ba1/d6/37/628bd2ac11f27cd8713bf4352199", "assets/build/windows/x64/Lib/ctypes/util.py": "https://files.ballistica.net/cache/ba1/82/79/81af49438e21e3d39002ca6c3617", "assets/build/windows/x64/Lib/ctypes/wintypes.py": "https://files.ballistica.net/cache/ba1/e1/d8/9db42a69096b386fe19d79f02ae3", "assets/build/windows/x64/Lib/curses/__init__.py": "https://files.ballistica.net/cache/ba1/cc/03/e54839d211f04b55a4653b224866", @@ -3585,112 +3576,9 @@ "assets/build/windows/x64/Lib/curses/textpad.py": "https://files.ballistica.net/cache/ba1/96/68/9789e90ca14113193ff432c6dfaf", "assets/build/windows/x64/Lib/dataclasses.py": "https://files.ballistica.net/cache/ba1/74/77/fa765a8b72a6e38923a97a1a8c1c", "assets/build/windows/x64/Lib/datetime.py": "https://files.ballistica.net/cache/ba1/a1/2c/30df2101c2b3cbf916dcca4b58fe", - "assets/build/windows/x64/Lib/dbm/__init__.py": "https://files.ballistica.net/cache/ba1/74/7c/7cb409d93e4c870dc9cb055984a1", - "assets/build/windows/x64/Lib/dbm/dumb.py": "https://files.ballistica.net/cache/ba1/a2/85/5838d4126f3c6fd3423c28558410", - "assets/build/windows/x64/Lib/dbm/gnu.py": "https://files.ballistica.net/cache/ba1/75/66/8a02a73aa564afdb2e79f961b9d0", - "assets/build/windows/x64/Lib/dbm/ndbm.py": "https://files.ballistica.net/cache/ba1/78/76/021032ee7c66ae39df1638cf243f", "assets/build/windows/x64/Lib/decimal.py": "https://files.ballistica.net/cache/ba1/cd/b3/d87ac73b40a69014ba9f7b1d479e", "assets/build/windows/x64/Lib/difflib.py": "https://files.ballistica.net/cache/ba1/83/c1/5756b30a00196d72fb06f79ea8b9", "assets/build/windows/x64/Lib/dis.py": "https://files.ballistica.net/cache/ba1/aa/69/5b606951368d7e4d60394d4acf73", - "assets/build/windows/x64/Lib/distutils/README": "https://files.ballistica.net/cache/ba1/3f/d5/668bcd02177e8ccef5aeafa3a799", - "assets/build/windows/x64/Lib/distutils/__init__.py": "https://files.ballistica.net/cache/ba1/cd/3b/3d815658ccf511fc0c678d2b6baf", - "assets/build/windows/x64/Lib/distutils/_msvccompiler.py": "https://files.ballistica.net/cache/ba1/0d/12/b4aa6e6bf102a2910d1dc7b62f88", - "assets/build/windows/x64/Lib/distutils/archive_util.py": "https://files.ballistica.net/cache/ba1/bc/a5/c1a13599392462a2990f7725ed4b", - "assets/build/windows/x64/Lib/distutils/bcppcompiler.py": "https://files.ballistica.net/cache/ba1/3a/af/07ae11f6ae975313f189fad5e6b0", - "assets/build/windows/x64/Lib/distutils/ccompiler.py": "https://files.ballistica.net/cache/ba1/96/6d/9719107722f7cfd4f45b5c7111b8", - "assets/build/windows/x64/Lib/distutils/cmd.py": "https://files.ballistica.net/cache/ba1/eb/71/4fffeac7decd85a226bd4ed34e4e", - "assets/build/windows/x64/Lib/distutils/command/__init__.py": "https://files.ballistica.net/cache/ba1/a0/5f/74a2a36f8e84ea9cf2db355e638a", - "assets/build/windows/x64/Lib/distutils/command/bdist.py": "https://files.ballistica.net/cache/ba1/41/77/bf7b47c7094b87c187a848aba67f", - "assets/build/windows/x64/Lib/distutils/command/bdist_dumb.py": "https://files.ballistica.net/cache/ba1/f8/0c/4f60e6d10f9bc89a33fa1c1c541b", - "assets/build/windows/x64/Lib/distutils/command/bdist_msi.py": "https://files.ballistica.net/cache/ba1/fb/17/3435f93f251028fa948b0f824392", - "assets/build/windows/x64/Lib/distutils/command/bdist_rpm.py": "https://files.ballistica.net/cache/ba1/90/e5/27feb7083f60bc362c6d656aad14", - "assets/build/windows/x64/Lib/distutils/command/bdist_wininst.py": "https://files.ballistica.net/cache/ba1/6b/24/9fdac33fb9eeda3bda215802866b", - "assets/build/windows/x64/Lib/distutils/command/build.py": "https://files.ballistica.net/cache/ba1/57/16/e6c6e10be62c28bb7fcb4eef7185", - "assets/build/windows/x64/Lib/distutils/command/build_clib.py": "https://files.ballistica.net/cache/ba1/67/77/8d372f3cc2b2f5aaa63b3473c9cd", - "assets/build/windows/x64/Lib/distutils/command/build_ext.py": "https://files.ballistica.net/cache/ba1/c1/e4/9d238424bfd4d627844ca48c00eb", - "assets/build/windows/x64/Lib/distutils/command/build_py.py": "https://files.ballistica.net/cache/ba1/9a/45/630001b6e6db460ff961bd9d3ed6", - "assets/build/windows/x64/Lib/distutils/command/build_scripts.py": "https://files.ballistica.net/cache/ba1/5b/4d/39390f086345665daec8d8b4538a", - "assets/build/windows/x64/Lib/distutils/command/check.py": "https://files.ballistica.net/cache/ba1/91/45/bfb251cd89c18ff8376c1131106d", - "assets/build/windows/x64/Lib/distutils/command/clean.py": "https://files.ballistica.net/cache/ba1/dd/ca/8551b9282fb0c21b527a4963f4c3", - "assets/build/windows/x64/Lib/distutils/command/command_template": "https://files.ballistica.net/cache/ba1/78/3d/87ba3781a5c17cf8f69e2ff148c4", - "assets/build/windows/x64/Lib/distutils/command/config.py": "https://files.ballistica.net/cache/ba1/99/f1/e148b378746271e15b2cb1c90acc", - "assets/build/windows/x64/Lib/distutils/command/install.py": "https://files.ballistica.net/cache/ba1/d5/61/4ca2d37b78878dac26b534723a5d", - "assets/build/windows/x64/Lib/distutils/command/install_data.py": "https://files.ballistica.net/cache/ba1/f4/fa/5cd0bfa37769706095e29b812761", - "assets/build/windows/x64/Lib/distutils/command/install_egg_info.py": "https://files.ballistica.net/cache/ba1/4f/f2/aaa641460c8b9b95f89cda12bd86", - "assets/build/windows/x64/Lib/distutils/command/install_headers.py": "https://files.ballistica.net/cache/ba1/66/b5/e705930896fc550b7d5170e8b6bb", - "assets/build/windows/x64/Lib/distutils/command/install_lib.py": "https://files.ballistica.net/cache/ba1/88/73/332fe054ba5ff54de4f513b45255", - "assets/build/windows/x64/Lib/distutils/command/install_scripts.py": "https://files.ballistica.net/cache/ba1/20/ca/be9871b64aa5b75d367c865b33f0", - "assets/build/windows/x64/Lib/distutils/command/register.py": "https://files.ballistica.net/cache/ba1/4e/4e/781582de44026d337580db28a816", - "assets/build/windows/x64/Lib/distutils/command/sdist.py": "https://files.ballistica.net/cache/ba1/ed/4d/7528790f9dc1287e1e5706473dfa", - "assets/build/windows/x64/Lib/distutils/command/upload.py": "https://files.ballistica.net/cache/ba1/7c/78/4bf07fd05b3dfdda4c423b0e743e", - "assets/build/windows/x64/Lib/distutils/config.py": "https://files.ballistica.net/cache/ba1/9d/96/383d9babcaf7276f1834454d11ae", - "assets/build/windows/x64/Lib/distutils/core.py": "https://files.ballistica.net/cache/ba1/71/e7/b934936ad04fadc99eef6f4e606f", - "assets/build/windows/x64/Lib/distutils/cygwinccompiler.py": "https://files.ballistica.net/cache/ba1/66/0a/5cfa637d8bf9369a60d912d72dd1", - "assets/build/windows/x64/Lib/distutils/debug.py": "https://files.ballistica.net/cache/ba1/eb/89/d24ec9b3581c377b725a0d0d75d2", - "assets/build/windows/x64/Lib/distutils/dep_util.py": "https://files.ballistica.net/cache/ba1/91/b3/44379798e9a446fcb8f2b56bbc25", - "assets/build/windows/x64/Lib/distutils/dir_util.py": "https://files.ballistica.net/cache/ba1/82/c4/92bc4304571c931f4a137d9a52b8", - "assets/build/windows/x64/Lib/distutils/dist.py": "https://files.ballistica.net/cache/ba1/2d/f0/e1acddceb8b7537f55e062cf4d03", - "assets/build/windows/x64/Lib/distutils/errors.py": "https://files.ballistica.net/cache/ba1/36/d5/a38f03d933a742a6fa5c7ca8697e", - "assets/build/windows/x64/Lib/distutils/extension.py": "https://files.ballistica.net/cache/ba1/b2/5c/7c1e45a62ffa34941bd3ba46e7dc", - "assets/build/windows/x64/Lib/distutils/fancy_getopt.py": "https://files.ballistica.net/cache/ba1/c6/4d/3930e38f15565bf55fe6f28ca2fc", - "assets/build/windows/x64/Lib/distutils/file_util.py": "https://files.ballistica.net/cache/ba1/ea/7c/89cbf998f8d3a5aa072f53f11562", - "assets/build/windows/x64/Lib/distutils/filelist.py": "https://files.ballistica.net/cache/ba1/59/92/286b972eac2020c8aa878ca26635", - "assets/build/windows/x64/Lib/distutils/log.py": "https://files.ballistica.net/cache/ba1/48/d7/d1f37e0d124f3115ce96cba69e0c", - "assets/build/windows/x64/Lib/distutils/msvc9compiler.py": "https://files.ballistica.net/cache/ba1/8a/eb/71cd14babe686b5fa5fcb62c4bca", - "assets/build/windows/x64/Lib/distutils/msvccompiler.py": "https://files.ballistica.net/cache/ba1/31/36/7d577f9410a8b9ae45de5f3cc95b", - "assets/build/windows/x64/Lib/distutils/spawn.py": "https://files.ballistica.net/cache/ba1/39/c2/884b8d1b85ea5597b9e56cf30ffc", - "assets/build/windows/x64/Lib/distutils/sysconfig.py": "https://files.ballistica.net/cache/ba1/f8/58/af66f5ebf75f7f273a555079b588", - "assets/build/windows/x64/Lib/distutils/tests/Setup.sample": "https://files.ballistica.net/cache/ba1/ec/82/b53af8259f7b788f5de436576091", - "assets/build/windows/x64/Lib/distutils/tests/__init__.py": "https://files.ballistica.net/cache/ba1/8a/b2/42a305f99a53b341d7b0d9fa4225", - "assets/build/windows/x64/Lib/distutils/tests/includetest.rst": "https://files.ballistica.net/cache/ba1/14/12/81e0c1db48acc22f4d4857f877bc", - "assets/build/windows/x64/Lib/distutils/tests/support.py": "https://files.ballistica.net/cache/ba1/e6/93/ceb400adfa2566c2ea83add7dbcd", - "assets/build/windows/x64/Lib/distutils/tests/test_archive_util.py": "https://files.ballistica.net/cache/ba1/87/dd/40da594efda28feea0bed5c3cafe", - "assets/build/windows/x64/Lib/distutils/tests/test_bdist.py": "https://files.ballistica.net/cache/ba1/95/20/13db012740af5b5251556c9c8973", - "assets/build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py": "https://files.ballistica.net/cache/ba1/c2/63/28f3baaa07776c783885a9f3f081", - "assets/build/windows/x64/Lib/distutils/tests/test_bdist_msi.py": "https://files.ballistica.net/cache/ba1/83/82/34c16c1410b158b5197e1c368c0b", - "assets/build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py": "https://files.ballistica.net/cache/ba1/e6/b2/9e7a36c3ea75fcd2c630dfdc7ce5", - "assets/build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py": "https://files.ballistica.net/cache/ba1/80/0a/7018b6869eb12667b9b4c96a7c44", - "assets/build/windows/x64/Lib/distutils/tests/test_build.py": "https://files.ballistica.net/cache/ba1/64/90/c2bfd09fb75ecb64969fffc23076", - "assets/build/windows/x64/Lib/distutils/tests/test_build_clib.py": "https://files.ballistica.net/cache/ba1/f1/2e/090086054d812d6d2d52b026ef12", - "assets/build/windows/x64/Lib/distutils/tests/test_build_ext.py": "https://files.ballistica.net/cache/ba1/56/52/ef3a082563adc3753f7f34582598", - "assets/build/windows/x64/Lib/distutils/tests/test_build_py.py": "https://files.ballistica.net/cache/ba1/fe/f6/192bd1384f0b72cfab47aa8046cb", - "assets/build/windows/x64/Lib/distutils/tests/test_build_scripts.py": "https://files.ballistica.net/cache/ba1/eb/3e/da9ead2df6d42a47b74620e0d1f8", - "assets/build/windows/x64/Lib/distutils/tests/test_check.py": "https://files.ballistica.net/cache/ba1/72/c3/9c7fe226fdef6e0423446e321094", - "assets/build/windows/x64/Lib/distutils/tests/test_clean.py": "https://files.ballistica.net/cache/ba1/50/8d/2a17e4e202a8ebbdbea3f6c6c056", - "assets/build/windows/x64/Lib/distutils/tests/test_cmd.py": "https://files.ballistica.net/cache/ba1/bb/46/3897bd36620d4927232ef58588cb", - "assets/build/windows/x64/Lib/distutils/tests/test_config.py": "https://files.ballistica.net/cache/ba1/dd/e7/a698ca3d0b2bb164d5896be777ec", - "assets/build/windows/x64/Lib/distutils/tests/test_config_cmd.py": "https://files.ballistica.net/cache/ba1/13/58/bf83ba9ecb16a9f3c800044ddacc", - "assets/build/windows/x64/Lib/distutils/tests/test_core.py": "https://files.ballistica.net/cache/ba1/91/0f/f79972dc8e614da585b9ce10d4cb", - "assets/build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py": "https://files.ballistica.net/cache/ba1/e7/23/004dc34a927ee9fe8e1bf0194f5f", - "assets/build/windows/x64/Lib/distutils/tests/test_dep_util.py": "https://files.ballistica.net/cache/ba1/7c/3c/f724762951cc832af42545cc2d0f", - "assets/build/windows/x64/Lib/distutils/tests/test_dir_util.py": "https://files.ballistica.net/cache/ba1/f8/c8/55a6a205c7d925d74f88b28185b5", - "assets/build/windows/x64/Lib/distutils/tests/test_dist.py": "https://files.ballistica.net/cache/ba1/04/8b/ed9f6d8a46cdaf2bc1da28237d18", - "assets/build/windows/x64/Lib/distutils/tests/test_extension.py": "https://files.ballistica.net/cache/ba1/14/bb/a39fd5924866d686785a943c2206", - "assets/build/windows/x64/Lib/distutils/tests/test_file_util.py": "https://files.ballistica.net/cache/ba1/10/5f/27f9bb6a567eab8661825a5c1280", - "assets/build/windows/x64/Lib/distutils/tests/test_filelist.py": "https://files.ballistica.net/cache/ba1/62/97/01edc4249c0c6c7db8c702ea7e12", - "assets/build/windows/x64/Lib/distutils/tests/test_install.py": "https://files.ballistica.net/cache/ba1/5e/90/64e37cd11a8efca415231f046214", - "assets/build/windows/x64/Lib/distutils/tests/test_install_data.py": "https://files.ballistica.net/cache/ba1/4e/ff/2c1a4c6bdc0effd0748ebe61fac0", - "assets/build/windows/x64/Lib/distutils/tests/test_install_headers.py": "https://files.ballistica.net/cache/ba1/12/62/b4bec59907efeadefd33a468dde0", - "assets/build/windows/x64/Lib/distutils/tests/test_install_lib.py": "https://files.ballistica.net/cache/ba1/86/d5/b895a721de478e46ba6fae93dd85", - "assets/build/windows/x64/Lib/distutils/tests/test_install_scripts.py": "https://files.ballistica.net/cache/ba1/df/3a/e25baa333a9459e3dd6c3961103c", - "assets/build/windows/x64/Lib/distutils/tests/test_log.py": "https://files.ballistica.net/cache/ba1/29/47/7a4cbc00690ec78add6f22b97b01", - "assets/build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py": "https://files.ballistica.net/cache/ba1/c4/5c/e627a4b2dfa84804e546b074c24e", - "assets/build/windows/x64/Lib/distutils/tests/test_msvccompiler.py": "https://files.ballistica.net/cache/ba1/8e/f6/6aade4b09822946f4af580eb65a7", - "assets/build/windows/x64/Lib/distutils/tests/test_register.py": "https://files.ballistica.net/cache/ba1/f5/f0/06bebf7180caa098cc0a71b92f56", - "assets/build/windows/x64/Lib/distutils/tests/test_sdist.py": "https://files.ballistica.net/cache/ba1/0a/40/3ecf64d3d158638c26fe4a9d6d13", - "assets/build/windows/x64/Lib/distutils/tests/test_spawn.py": "https://files.ballistica.net/cache/ba1/04/0b/2e7ee99a453bef0cd6fa19300e24", - "assets/build/windows/x64/Lib/distutils/tests/test_sysconfig.py": "https://files.ballistica.net/cache/ba1/31/b3/4421f02b56aa378b88e431762bb6", - "assets/build/windows/x64/Lib/distutils/tests/test_text_file.py": "https://files.ballistica.net/cache/ba1/cf/40/397f59e3cf180a8784bc47b22f70", - "assets/build/windows/x64/Lib/distutils/tests/test_unixccompiler.py": "https://files.ballistica.net/cache/ba1/c5/de/538aee1845c02413045a7174e5f3", - "assets/build/windows/x64/Lib/distutils/tests/test_upload.py": "https://files.ballistica.net/cache/ba1/ef/4d/6fc03196fbb24c9d8954fc36055c", - "assets/build/windows/x64/Lib/distutils/tests/test_util.py": "https://files.ballistica.net/cache/ba1/90/6b/13a9de9d2cd7adeb992dfcbccbbd", - "assets/build/windows/x64/Lib/distutils/tests/test_version.py": "https://files.ballistica.net/cache/ba1/f0/80/b67795a782b07739f2d319c1a0c3", - "assets/build/windows/x64/Lib/distutils/tests/test_versionpredicate.py": "https://files.ballistica.net/cache/ba1/bf/f7/bbaec86fdc8909843edeaab50c7d", - "assets/build/windows/x64/Lib/distutils/text_file.py": "https://files.ballistica.net/cache/ba1/a7/82/30129c46393987fe8865120cac83", - "assets/build/windows/x64/Lib/distutils/unixccompiler.py": "https://files.ballistica.net/cache/ba1/80/28/534fba2e657b4032697e502c697e", - "assets/build/windows/x64/Lib/distutils/util.py": "https://files.ballistica.net/cache/ba1/5b/56/48ea76b94396735fb9bd2e49fd87", - "assets/build/windows/x64/Lib/distutils/version.py": "https://files.ballistica.net/cache/ba1/4f/81/1550f304deb3676ad4017413da0b", - "assets/build/windows/x64/Lib/distutils/versionpredicate.py": "https://files.ballistica.net/cache/ba1/c8/9f/d2e1d30625ea298d761ecebaadd8", "assets/build/windows/x64/Lib/doctest.py": "https://files.ballistica.net/cache/ba1/fa/ef/b982e21caf77052bae28f4a99183", "assets/build/windows/x64/Lib/dummy_threading.py": "https://files.ballistica.net/cache/ba1/60/8d/f2224386ddb9900ca3534c260a81", "assets/build/windows/x64/Lib/email/__init__.py": "https://files.ballistica.net/cache/ba1/76/c0/fcec9aab01633e97f3b5e18eb70c", @@ -3749,7 +3637,6 @@ "assets/build/windows/x64/Lib/encodings/cp424.py": "https://files.ballistica.net/cache/ba1/4d/e6/e2a8073bfa4d5c125385b022459a", "assets/build/windows/x64/Lib/encodings/cp437.py": "https://files.ballistica.net/cache/ba1/bd/bd/0cbd2e567df80430b105dd9adecc", "assets/build/windows/x64/Lib/encodings/cp500.py": "https://files.ballistica.net/cache/ba1/19/15/b9c0fd54cff79cfb2aa1db2824ad", - "assets/build/windows/x64/Lib/encodings/cp65001.py": "https://files.ballistica.net/cache/ba1/b7/d6/daf9b3004bddd8f7aad873d3a796", "assets/build/windows/x64/Lib/encodings/cp720.py": "https://files.ballistica.net/cache/ba1/81/8d/14e839762423c34b032437c9d279", "assets/build/windows/x64/Lib/encodings/cp737.py": "https://files.ballistica.net/cache/ba1/63/1d/07f779e2e29133ba288d177b7ced", "assets/build/windows/x64/Lib/encodings/cp775.py": "https://files.ballistica.net/cache/ba1/08/aa/a345f023eb827c1168810bf682ba", @@ -3836,7 +3723,6 @@ "assets/build/windows/x64/Lib/encodings/tis_620.py": "https://files.ballistica.net/cache/ba1/bd/ac/f8918a7ba3f37c3d28f6659e6857", "assets/build/windows/x64/Lib/encodings/undefined.py": "https://files.ballistica.net/cache/ba1/b9/70/c8c381111c2bda1323ee1a59725d", "assets/build/windows/x64/Lib/encodings/unicode_escape.py": "https://files.ballistica.net/cache/ba1/fc/2a/e77b877df6810138c462be13c460", - "assets/build/windows/x64/Lib/encodings/unicode_internal.py": "https://files.ballistica.net/cache/ba1/3e/a3/d5c28fdf9d7b272191e6de492b5c", "assets/build/windows/x64/Lib/encodings/utf_16.py": "https://files.ballistica.net/cache/ba1/7a/35/d824d6726d66465a51d498d9f63c", "assets/build/windows/x64/Lib/encodings/utf_16_be.py": "https://files.ballistica.net/cache/ba1/99/65/b107a1cd6467da965e61637e0d9e", "assets/build/windows/x64/Lib/encodings/utf_16_le.py": "https://files.ballistica.net/cache/ba1/03/3f/7a404e31d9b0570bb3e469f001d1", @@ -3848,11 +3734,6 @@ "assets/build/windows/x64/Lib/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/8f/30/772445e0fc95262a5c0feb8b16bc", "assets/build/windows/x64/Lib/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/97/67/1460fda7afd448affdc491454e36", "assets/build/windows/x64/Lib/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/8e/f8/222b06ec8c6d36447139238a12ad", - "assets/build/windows/x64/Lib/ensurepip/__init__.py": "https://files.ballistica.net/cache/ba1/dc/68/77710a4c8c7122b2f109a5f79852", - "assets/build/windows/x64/Lib/ensurepip/__main__.py": "https://files.ballistica.net/cache/ba1/33/c2/b9b77720260e45c0ffad5ad0a590", - "assets/build/windows/x64/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl": "https://files.ballistica.net/cache/ba1/60/5b/a636272093a818efec4a10cc5968", - "assets/build/windows/x64/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl": "https://files.ballistica.net/cache/ba1/4b/64/8944c8d9bd9e59727b72fd613ea1", - "assets/build/windows/x64/Lib/ensurepip/_uninstall.py": "https://files.ballistica.net/cache/ba1/c1/a0/474f0049dd6ce9d1592814336cec", "assets/build/windows/x64/Lib/enum.py": "https://files.ballistica.net/cache/ba1/69/d7/2217fa4093dcc7b61827ecbe6568", "assets/build/windows/x64/Lib/filecmp.py": "https://files.ballistica.net/cache/ba1/d4/c2/2d03a499807cbeef622dbc90c8aa", "assets/build/windows/x64/Lib/fileinput.py": "https://files.ballistica.net/cache/ba1/1b/67/3f7eefb165aaf371eb69554bf30f", @@ -3878,7 +3759,6 @@ "assets/build/windows/x64/Lib/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/14/a8/bff26313dca1f680c09ebbad55bf", "assets/build/windows/x64/Lib/http/cookies.py": "https://files.ballistica.net/cache/ba1/f3/96/4d0259ac762ed234d1446b4fb188", "assets/build/windows/x64/Lib/http/server.py": "https://files.ballistica.net/cache/ba1/02/f2/9c1e773c37661b9534af57fc5f83", - "assets/build/windows/x64/Lib/imaplib.py": "https://files.ballistica.net/cache/ba1/5a/76/b0ca097deb773d55a79eb3b5376d", "assets/build/windows/x64/Lib/imghdr.py": "https://files.ballistica.net/cache/ba1/19/ff/b4c40eb476e9f29b41bb22756e7f", "assets/build/windows/x64/Lib/imp.py": "https://files.ballistica.net/cache/ba1/fa/32/ad8700e45e4c5a6ce22c4aedd97c", "assets/build/windows/x64/Lib/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/15/64/dc87514a1792ebf90ab2c5abc53f", @@ -3886,6 +3766,7 @@ "assets/build/windows/x64/Lib/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/a8/1a/576b8b53f6fca8ce8c2955b13a56", "assets/build/windows/x64/Lib/importlib/abc.py": "https://files.ballistica.net/cache/ba1/6e/b7/64855bc53a8f6de314e2602ed40b", "assets/build/windows/x64/Lib/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/53/71/10f33e5f5f4bedc0df0763c7f12e", + "assets/build/windows/x64/Lib/importlib/metadata.py": "https://files.ballistica.net/cache/ba1/d7/42/14b3782e33617bd2e0fc22c5922f", "assets/build/windows/x64/Lib/importlib/resources.py": "https://files.ballistica.net/cache/ba1/5e/94/96b7fa6cc4872c973bd0a65e125b", "assets/build/windows/x64/Lib/importlib/util.py": "https://files.ballistica.net/cache/ba1/f0/14/010077784291bdda228db67e355d", "assets/build/windows/x64/Lib/inspect.py": "https://files.ballistica.net/cache/ba1/00/bf/b5a64080675fe2dde8a456c70123", @@ -3903,7 +3784,6 @@ "assets/build/windows/x64/Lib/logging/config.py": "https://files.ballistica.net/cache/ba1/96/9d/6c147ae66c933f11400ee8f1ac27", "assets/build/windows/x64/Lib/logging/handlers.py": "https://files.ballistica.net/cache/ba1/74/fc/d58cf79b4a8ba3c1ca5b2788845f", "assets/build/windows/x64/Lib/lzma.py": "https://files.ballistica.net/cache/ba1/a7/25/74061a41daca93e5d252b46f4af4", - "assets/build/windows/x64/Lib/macpath.py": "https://files.ballistica.net/cache/ba1/a4/2b/9013b12638c516409a3f64d3a29f", "assets/build/windows/x64/Lib/mailbox.py": "https://files.ballistica.net/cache/ba1/16/93/108f6da97cc2681b27d34092932b", "assets/build/windows/x64/Lib/mailcap.py": "https://files.ballistica.net/cache/ba1/09/9b/812cf9dc875f7413e271b789151b", "assets/build/windows/x64/Lib/mimetypes.py": "https://files.ballistica.net/cache/ba1/68/47/5675fa86fc23db64fe98eb243ce7", @@ -3912,28 +3792,6 @@ "assets/build/windows/x64/Lib/msilib/schema.py": "https://files.ballistica.net/cache/ba1/a1/fa/4eb816d49773250568cd3a3bc6e3", "assets/build/windows/x64/Lib/msilib/sequence.py": "https://files.ballistica.net/cache/ba1/97/47/ff4ab28db63fdea3349fe62754ec", "assets/build/windows/x64/Lib/msilib/text.py": "https://files.ballistica.net/cache/ba1/ce/a6/430d401c2fb15952f3760cc535ce", - "assets/build/windows/x64/Lib/multiprocessing/__init__.py": "https://files.ballistica.net/cache/ba1/d5/90/5d313b52e1477485417ca745d165", - "assets/build/windows/x64/Lib/multiprocessing/connection.py": "https://files.ballistica.net/cache/ba1/66/f0/f4d8f161674ef937a7bbe14a03d1", - "assets/build/windows/x64/Lib/multiprocessing/context.py": "https://files.ballistica.net/cache/ba1/4a/70/5cbf6180008011b56143a9e4bf4b", - "assets/build/windows/x64/Lib/multiprocessing/dummy/__init__.py": "https://files.ballistica.net/cache/ba1/89/ad/dede4afdca209a9485ad30054b66", - "assets/build/windows/x64/Lib/multiprocessing/dummy/connection.py": "https://files.ballistica.net/cache/ba1/f7/dc/eb8c4301ff978b44399dde84af9f", - "assets/build/windows/x64/Lib/multiprocessing/forkserver.py": "https://files.ballistica.net/cache/ba1/21/32/343ec2b45629d6b33e66fb09843f", - "assets/build/windows/x64/Lib/multiprocessing/heap.py": "https://files.ballistica.net/cache/ba1/ad/eb/cfa8779be7deebd561f109b086d2", - "assets/build/windows/x64/Lib/multiprocessing/managers.py": "https://files.ballistica.net/cache/ba1/a5/fa/dd7b225d138c96b8abc490db42de", - "assets/build/windows/x64/Lib/multiprocessing/pool.py": "https://files.ballistica.net/cache/ba1/0c/51/c4c3a8e3d23c7f29ca9dd6276eb1", - "assets/build/windows/x64/Lib/multiprocessing/popen_fork.py": "https://files.ballistica.net/cache/ba1/29/2e/630c2df5fc6cec005139b0cecac5", - "assets/build/windows/x64/Lib/multiprocessing/popen_forkserver.py": "https://files.ballistica.net/cache/ba1/67/10/3e029e61e88c6355d339fd70be84", - "assets/build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py": "https://files.ballistica.net/cache/ba1/92/a6/b8c653c5478ea6e2db50f20cf9aa", - "assets/build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py": "https://files.ballistica.net/cache/ba1/6c/51/708f9122ac591063cd7b8741a583", - "assets/build/windows/x64/Lib/multiprocessing/process.py": "https://files.ballistica.net/cache/ba1/a5/e6/fcc0f4efc6ec94fb372f5a673b5c", - "assets/build/windows/x64/Lib/multiprocessing/queues.py": "https://files.ballistica.net/cache/ba1/b4/22/503476981b2f0cf3622cecfb40b2", - "assets/build/windows/x64/Lib/multiprocessing/reduction.py": "https://files.ballistica.net/cache/ba1/2b/f0/ea906f328f9957a07df58ba56e38", - "assets/build/windows/x64/Lib/multiprocessing/resource_sharer.py": "https://files.ballistica.net/cache/ba1/ba/24/3a823ebb0a89e6f70a8b0fdb81a3", - "assets/build/windows/x64/Lib/multiprocessing/semaphore_tracker.py": "https://files.ballistica.net/cache/ba1/21/3e/74546eff3b96e73b8ca6e9668f21", - "assets/build/windows/x64/Lib/multiprocessing/sharedctypes.py": "https://files.ballistica.net/cache/ba1/fe/9c/54aa659ee696002121425d95d981", - "assets/build/windows/x64/Lib/multiprocessing/spawn.py": "https://files.ballistica.net/cache/ba1/e3/1a/da985776fe4f8c2afea9ff17513c", - "assets/build/windows/x64/Lib/multiprocessing/synchronize.py": "https://files.ballistica.net/cache/ba1/6d/f8/a37028b2432c1db40c0edcb2653f", - "assets/build/windows/x64/Lib/multiprocessing/util.py": "https://files.ballistica.net/cache/ba1/16/38/cad1f5199cd93d476e347adb6308", "assets/build/windows/x64/Lib/netrc.py": "https://files.ballistica.net/cache/ba1/8d/05/18f219a7009d31762b91810cb7d9", "assets/build/windows/x64/Lib/nntplib.py": "https://files.ballistica.net/cache/ba1/9b/2f/f5e0f428fc6c61b987dede618022", "assets/build/windows/x64/Lib/ntpath.py": "https://files.ballistica.net/cache/ba1/c0/57/845ba80c288e1b77de52d561fc5d", @@ -3960,9 +3818,6 @@ "assets/build/windows/x64/Lib/py_compile.py": "https://files.ballistica.net/cache/ba1/46/56/cde4c6e43bc4c957206432e9bcf4", "assets/build/windows/x64/Lib/pyclbr.py": "https://files.ballistica.net/cache/ba1/bb/f9/c214e77b8d0539adadc7f1b0f972", "assets/build/windows/x64/Lib/pydoc.py": "https://files.ballistica.net/cache/ba1/03/b3/d440729325bd0e69a39dcd155d63", - "assets/build/windows/x64/Lib/pydoc_data/__init__.py": "https://files.ballistica.net/cache/ba1/af/1e/8372ed8ec0d0fc5ffffb86b4e371", - "assets/build/windows/x64/Lib/pydoc_data/_pydoc.css": "https://files.ballistica.net/cache/ba1/e4/dc/6cb974e7dca13c23a13fce716874", - "assets/build/windows/x64/Lib/pydoc_data/topics.py": "https://files.ballistica.net/cache/ba1/14/3f/ac7bd42adfdcaab26e5ab4ce2e19", "assets/build/windows/x64/Lib/queue.py": "https://files.ballistica.net/cache/ba1/93/b5/aae979d9f1be9bd7d9e38f9d7a5a", "assets/build/windows/x64/Lib/quopri.py": "https://files.ballistica.net/cache/ba1/92/18/eddf3ab6e4f11ddba84528943ea0", "assets/build/windows/x64/Lib/random.py": "https://files.ballistica.net/cache/ba1/6a/84/44e516cf5d86034d0de7f51eb8b3", @@ -3977,7 +3832,6 @@ "assets/build/windows/x64/Lib/shlex.py": "https://files.ballistica.net/cache/ba1/1d/5a/e51f5175dcb456429c25a5eaabd1", "assets/build/windows/x64/Lib/shutil.py": "https://files.ballistica.net/cache/ba1/9b/e8/7465b5ade563707d0741857faaf3", "assets/build/windows/x64/Lib/signal.py": "https://files.ballistica.net/cache/ba1/73/a2/334554b75ca8437e13febeb91690", - "assets/build/windows/x64/Lib/site-packages/README.txt": "https://files.ballistica.net/cache/ba1/8d/8c/afaf8e2c9af7448b2e55df3996f5", "assets/build/windows/x64/Lib/site.py": "https://files.ballistica.net/cache/ba1/be/7b/d361cac759233fc2a80cb3b22835", "assets/build/windows/x64/Lib/smtpd.py": "https://files.ballistica.net/cache/ba1/50/dd/0c9e73b772631a76117adb2814dc", "assets/build/windows/x64/Lib/smtplib.py": "https://files.ballistica.net/cache/ba1/8b/92/d81f42a94563b205cd36f0c0c1d4", @@ -3987,16 +3841,6 @@ "assets/build/windows/x64/Lib/sqlite3/__init__.py": "https://files.ballistica.net/cache/ba1/bb/ba/b889c65254f48b4d5a47f483165c", "assets/build/windows/x64/Lib/sqlite3/dbapi2.py": "https://files.ballistica.net/cache/ba1/96/b5/ed3c8e8d17a64334e94f5be5f822", "assets/build/windows/x64/Lib/sqlite3/dump.py": "https://files.ballistica.net/cache/ba1/86/aa/a3f45a108dabc152ccc7362cd846", - "assets/build/windows/x64/Lib/sqlite3/test/__init__.py": "https://files.ballistica.net/cache/ba1/1f/a9/ed8ae8f4f4c5c28fd3b91da678d1", - "assets/build/windows/x64/Lib/sqlite3/test/backup.py": "https://files.ballistica.net/cache/ba1/17/20/d1b4d647d5ade48c1a5146d7f895", - "assets/build/windows/x64/Lib/sqlite3/test/dbapi.py": "https://files.ballistica.net/cache/ba1/cc/68/f9a7bbe588d4a3db6cbf58330c82", - "assets/build/windows/x64/Lib/sqlite3/test/dump.py": "https://files.ballistica.net/cache/ba1/5e/4f/7df79c684deadf8234b821f0b8fa", - "assets/build/windows/x64/Lib/sqlite3/test/factory.py": "https://files.ballistica.net/cache/ba1/36/bd/d0e2e50c827030c0f881f8b0f230", - "assets/build/windows/x64/Lib/sqlite3/test/hooks.py": "https://files.ballistica.net/cache/ba1/43/7e/b04f571ea4c36a15a6b2bc573b3d", - "assets/build/windows/x64/Lib/sqlite3/test/regression.py": "https://files.ballistica.net/cache/ba1/83/01/0b94dd0a5d02f870a7b112e2cd3a", - "assets/build/windows/x64/Lib/sqlite3/test/transactions.py": "https://files.ballistica.net/cache/ba1/ff/53/aae07e65f3e83fd4187d540a20a2", - "assets/build/windows/x64/Lib/sqlite3/test/types.py": "https://files.ballistica.net/cache/ba1/4a/14/a5e8ec552268a1018f7b5fc27be3", - "assets/build/windows/x64/Lib/sqlite3/test/userfunctions.py": "https://files.ballistica.net/cache/ba1/24/36/58b16c881a2b561140a09a1c2bdd", "assets/build/windows/x64/Lib/sre_compile.py": "https://files.ballistica.net/cache/ba1/c7/6d/c1e9803811d4d1d194bb17468ce3", "assets/build/windows/x64/Lib/sre_constants.py": "https://files.ballistica.net/cache/ba1/67/81/991a55cff77b529d9a3055c3b883", "assets/build/windows/x64/Lib/sre_parse.py": "https://files.ballistica.net/cache/ba1/5c/6b/a743c8b3434b1a110801a7c020fe", @@ -4025,48 +3869,8 @@ "assets/build/windows/x64/Lib/traceback.py": "https://files.ballistica.net/cache/ba1/54/a6/571ed5ba74306260c89a7937a4ea", "assets/build/windows/x64/Lib/tracemalloc.py": "https://files.ballistica.net/cache/ba1/d9/82/542bddb3196a3a38e13315af549e", "assets/build/windows/x64/Lib/tty.py": "https://files.ballistica.net/cache/ba1/26/15/c352a80614f63b248f48133db95f", - "assets/build/windows/x64/Lib/turtle.py": "https://files.ballistica.net/cache/ba1/df/25/a0e2d8cc8dadd9691331f24e5e85", "assets/build/windows/x64/Lib/types.py": "https://files.ballistica.net/cache/ba1/2c/10/e7c7c31d211467498b6fc888b06e", "assets/build/windows/x64/Lib/typing.py": "https://files.ballistica.net/cache/ba1/65/3f/2b0ca5bd513806e127b5ef91fb22", - "assets/build/windows/x64/Lib/unittest/__init__.py": "https://files.ballistica.net/cache/ba1/dc/66/443ca7972971181583fe78c6ed56", - "assets/build/windows/x64/Lib/unittest/__main__.py": "https://files.ballistica.net/cache/ba1/60/ab/7ee0544285bfef8ddfc78e0790d7", - "assets/build/windows/x64/Lib/unittest/case.py": "https://files.ballistica.net/cache/ba1/74/fa/5a7154db900dda7f16b303a4a158", - "assets/build/windows/x64/Lib/unittest/loader.py": "https://files.ballistica.net/cache/ba1/58/5f/95a31cb85537729ef49b4ab687dc", - "assets/build/windows/x64/Lib/unittest/main.py": "https://files.ballistica.net/cache/ba1/75/a5/40b764a0bf706047e86c4fa51092", - "assets/build/windows/x64/Lib/unittest/mock.py": "https://files.ballistica.net/cache/ba1/93/97/a003eeeac4eff9db28d807136c45", - "assets/build/windows/x64/Lib/unittest/result.py": "https://files.ballistica.net/cache/ba1/67/4f/1af6c5f4a91d7efb2eefe55a63be", - "assets/build/windows/x64/Lib/unittest/runner.py": "https://files.ballistica.net/cache/ba1/ef/f3/f94df43920a8ee95fc6cd98b9b6c", - "assets/build/windows/x64/Lib/unittest/signals.py": "https://files.ballistica.net/cache/ba1/b2/37/98a5a68985c79d14871911f0b48e", - "assets/build/windows/x64/Lib/unittest/suite.py": "https://files.ballistica.net/cache/ba1/ce/05/02dd6ed2517efdd70db1f8842e2a", - "assets/build/windows/x64/Lib/unittest/test/__init__.py": "https://files.ballistica.net/cache/ba1/de/ce/95932a0f3f89adebf9b7e6e40dce", - "assets/build/windows/x64/Lib/unittest/test/__main__.py": "https://files.ballistica.net/cache/ba1/b3/36/0f12e843314f6145e7a3fecd587d", - "assets/build/windows/x64/Lib/unittest/test/_test_warnings.py": "https://files.ballistica.net/cache/ba1/55/c2/d8f5965f2bd9fd50b8969c346a35", - "assets/build/windows/x64/Lib/unittest/test/dummy.py": "https://files.ballistica.net/cache/ba1/49/86/5145309ab169fc0aabbf2560b6a7", - "assets/build/windows/x64/Lib/unittest/test/support.py": "https://files.ballistica.net/cache/ba1/87/1f/6d13f9c36ec6b31538bd32d48884", - "assets/build/windows/x64/Lib/unittest/test/test_assertions.py": "https://files.ballistica.net/cache/ba1/a7/d0/2df4efdfaad8ef5af148f3b343a8", - "assets/build/windows/x64/Lib/unittest/test/test_break.py": "https://files.ballistica.net/cache/ba1/7a/37/ad1c851df468677f1538f9953706", - "assets/build/windows/x64/Lib/unittest/test/test_case.py": "https://files.ballistica.net/cache/ba1/d9/8b/374acb128b977f0ef1390bc9225c", - "assets/build/windows/x64/Lib/unittest/test/test_discovery.py": "https://files.ballistica.net/cache/ba1/5b/4b/39f0ba5a3d5445208b567cc08df9", - "assets/build/windows/x64/Lib/unittest/test/test_functiontestcase.py": "https://files.ballistica.net/cache/ba1/47/5d/f4a4cb71dbc41b807041491ec84a", - "assets/build/windows/x64/Lib/unittest/test/test_loader.py": "https://files.ballistica.net/cache/ba1/f3/59/7f2b75f18d9730dccc28a1209c44", - "assets/build/windows/x64/Lib/unittest/test/test_program.py": "https://files.ballistica.net/cache/ba1/68/f4/752f58f0157b3cd27e80a65fb781", - "assets/build/windows/x64/Lib/unittest/test/test_result.py": "https://files.ballistica.net/cache/ba1/53/ba/0f313e965263af075de9fce89f8b", - "assets/build/windows/x64/Lib/unittest/test/test_runner.py": "https://files.ballistica.net/cache/ba1/f0/e2/ef607b3ab2d8b678387015a00b64", - "assets/build/windows/x64/Lib/unittest/test/test_setups.py": "https://files.ballistica.net/cache/ba1/c4/20/c9299a1b356a49f6b1bfa2151986", - "assets/build/windows/x64/Lib/unittest/test/test_skipping.py": "https://files.ballistica.net/cache/ba1/66/2d/50f2f9b9ff7a42bb0df1c33ae140", - "assets/build/windows/x64/Lib/unittest/test/test_suite.py": "https://files.ballistica.net/cache/ba1/cf/31/23cbc2b57a0111f3d61dfa36ef9c", - "assets/build/windows/x64/Lib/unittest/test/testmock/__init__.py": "https://files.ballistica.net/cache/ba1/db/b4/b678c77f5d05ed019d011ad00d33", - "assets/build/windows/x64/Lib/unittest/test/testmock/__main__.py": "https://files.ballistica.net/cache/ba1/9d/ba/af9bcc63afa84c81f0facd2ec228", - "assets/build/windows/x64/Lib/unittest/test/testmock/support.py": "https://files.ballistica.net/cache/ba1/71/ba/8d4f9a2c4b96a04d49321e32c489", - "assets/build/windows/x64/Lib/unittest/test/testmock/testcallable.py": "https://files.ballistica.net/cache/ba1/e5/d9/93837b5503b162611dec88629e9a", - "assets/build/windows/x64/Lib/unittest/test/testmock/testhelpers.py": "https://files.ballistica.net/cache/ba1/66/d4/54d994d56cd167fed162db5f9f3c", - "assets/build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py": "https://files.ballistica.net/cache/ba1/4e/23/9ef6882b2eb69d62bf607835f531", - "assets/build/windows/x64/Lib/unittest/test/testmock/testmock.py": "https://files.ballistica.net/cache/ba1/bf/47/0f5e419a9fed1eab224b9e91563f", - "assets/build/windows/x64/Lib/unittest/test/testmock/testpatch.py": "https://files.ballistica.net/cache/ba1/38/c6/0d3694b2105947fe696d50c2df85", - "assets/build/windows/x64/Lib/unittest/test/testmock/testsealable.py": "https://files.ballistica.net/cache/ba1/80/f0/97648ce2226373199a632651a26b", - "assets/build/windows/x64/Lib/unittest/test/testmock/testsentinel.py": "https://files.ballistica.net/cache/ba1/08/c9/f61ca1cfde630a2ff29753fd78d8", - "assets/build/windows/x64/Lib/unittest/test/testmock/testwith.py": "https://files.ballistica.net/cache/ba1/75/d7/2f41dc94639598baccbc2b01f9db", - "assets/build/windows/x64/Lib/unittest/util.py": "https://files.ballistica.net/cache/ba1/74/c7/82e31d822c6e2c9db45b923bc22b", "assets/build/windows/x64/Lib/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/bf/df/014153f62b00e4b6ec077d679983", "assets/build/windows/x64/Lib/urllib/error.py": "https://files.ballistica.net/cache/ba1/7f/1c/7253af299d30189ea693f2c1e79d", "assets/build/windows/x64/Lib/urllib/parse.py": "https://files.ballistica.net/cache/ba1/04/7d/865ccdec846455a44f6b438ae0e3", @@ -4075,26 +3879,10 @@ "assets/build/windows/x64/Lib/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/b2/82/27c36f6dd9599898e45b2d1643ee", "assets/build/windows/x64/Lib/uu.py": "https://files.ballistica.net/cache/ba1/d2/3a/c7ea1f88d74983d073e29b8cdb9b", "assets/build/windows/x64/Lib/uuid.py": "https://files.ballistica.net/cache/ba1/ea/69/1fdbe28c74670ba8b7e123501b58", - "assets/build/windows/x64/Lib/venv/__init__.py": "https://files.ballistica.net/cache/ba1/88/ed/20f50fe17b579bdcfa9f4e7dca95", - "assets/build/windows/x64/Lib/venv/__main__.py": "https://files.ballistica.net/cache/ba1/20/93/8a7cc042c69b17a2d856a2a6c7dc", - "assets/build/windows/x64/Lib/venv/scripts/common/activate": "https://files.ballistica.net/cache/ba1/23/93/ca2f88a7b5e5511af91b34970615", - "assets/build/windows/x64/Lib/venv/scripts/nt/Activate.ps1": "https://files.ballistica.net/cache/ba1/09/4a/e8c1d000af2e880ff9ab5a243a95", - "assets/build/windows/x64/Lib/venv/scripts/nt/activate.bat": "https://files.ballistica.net/cache/ba1/0e/d8/f69fe15c696ff3e6071cc69f0732", - "assets/build/windows/x64/Lib/venv/scripts/nt/deactivate.bat": "https://files.ballistica.net/cache/ba1/46/fb/d7d894f7e1c1faeb9af092764d3b", - "assets/build/windows/x64/Lib/venv/scripts/nt/python.exe": "https://files.ballistica.net/cache/ba1/7a/92/5fbd1caa44cc4dfe17e81151158b", - "assets/build/windows/x64/Lib/venv/scripts/nt/pythonw.exe": "https://files.ballistica.net/cache/ba1/1d/7d/71050c34d86c6bb210c811a4d9bd", - "assets/build/windows/x64/Lib/venv/scripts/posix/activate.csh": "https://files.ballistica.net/cache/ba1/5b/5a/410118175065cc1d3cbfeb7784e0", - "assets/build/windows/x64/Lib/venv/scripts/posix/activate.fish": "https://files.ballistica.net/cache/ba1/6a/90/c7b0a2ee25fcf174c66093f59890", "assets/build/windows/x64/Lib/warnings.py": "https://files.ballistica.net/cache/ba1/22/85/dd1f78755f0a68cf1001a86aba03", "assets/build/windows/x64/Lib/wave.py": "https://files.ballistica.net/cache/ba1/6c/28/cd5ae263e65cdf5646377e9af59a", "assets/build/windows/x64/Lib/weakref.py": "https://files.ballistica.net/cache/ba1/2a/54/d31db6e0d3a793c4969d0443149f", "assets/build/windows/x64/Lib/webbrowser.py": "https://files.ballistica.net/cache/ba1/c0/34/9d7e2df26287900e40a6161914ea", - "assets/build/windows/x64/Lib/wsgiref/__init__.py": "https://files.ballistica.net/cache/ba1/cb/85/439762721022a4155dd89df18b6b", - "assets/build/windows/x64/Lib/wsgiref/handlers.py": "https://files.ballistica.net/cache/ba1/89/a4/b07f15edbb4bcac27455f0429f6b", - "assets/build/windows/x64/Lib/wsgiref/headers.py": "https://files.ballistica.net/cache/ba1/78/48/0a6462c5fb48815dff5fc7eb43c6", - "assets/build/windows/x64/Lib/wsgiref/simple_server.py": "https://files.ballistica.net/cache/ba1/b8/e4/2beaa6bfccba974b26d45ede9621", - "assets/build/windows/x64/Lib/wsgiref/util.py": "https://files.ballistica.net/cache/ba1/59/dc/9f04064fcb6c8060f5b011067f43", - "assets/build/windows/x64/Lib/wsgiref/validate.py": "https://files.ballistica.net/cache/ba1/a0/80/0c04726381d9efe9c0d253a87204", "assets/build/windows/x64/Lib/xdrlib.py": "https://files.ballistica.net/cache/ba1/d7/d2/73267fea9d72ed3f84cf38dd7ce9", "assets/build/windows/x64/Lib/xml/__init__.py": "https://files.ballistica.net/cache/ba1/90/da/3877c42a503e181ce6ee8dd27143", "assets/build/windows/x64/Lib/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/24/f7/3c8ac11160cb6c141d8ab77dde32", @@ -4123,28 +3911,32 @@ "assets/build/windows/x64/Lib/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/90/d6/d1931f1dc07779dae8923909804b", "assets/build/windows/x64/Lib/zipapp.py": "https://files.ballistica.net/cache/ba1/8f/3a/728796fd929420a912edda05d567", "assets/build/windows/x64/Lib/zipfile.py": "https://files.ballistica.net/cache/ba1/a6/3c/116c6602b0176d208f3e2a4813de", + "assets/build/windows/x64/Lib/zipimport.py": "https://files.ballistica.net/cache/ba1/d5/0e/9f08a3aa213e5792e068acdeb845", "assets/build/windows/x64/OpenAL32.dll": "https://files.ballistica.net/cache/ba1/a1/7f/e92ff76218c4b8cfce9bc72d5324", "assets/build/windows/x64/SDL2.dll": "https://files.ballistica.net/cache/ba1/b2/c1/0d3f95340344968b2aac3fc4a979", "assets/build/windows/x64/libvorbis.dll": "https://files.ballistica.net/cache/ba1/2d/ec/f52561af5804abd5c646e364dea9", "assets/build/windows/x64/libvorbisfile.dll": "https://files.ballistica.net/cache/ba1/8c/2a/ef525f4ae1de3b46a23fbdd0dfde", "assets/build/windows/x64/msvcp140d.dll": "https://files.ballistica.net/cache/ba1/25/73/87d96678583aabd18407963ac8b0", "assets/build/windows/x64/ogg.dll": "https://files.ballistica.net/cache/ba1/1b/3e/382012f9d092e45f211561e8b5ee", - "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/25/a7/dc87c1be41605eb6fefd0145144c", - "assets/build/windows/x64/python37.dll": "https://files.ballistica.net/cache/ba1/b9/e4/d912f56e42e9991bcbb4c804cfcb", - "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/6c/bb/b6f52c306aa4e88061510e96cefe", + "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/34/e3/4af33a85aa47ce568fbceadf94a6", + "assets/build/windows/x64/python38.dll": "https://files.ballistica.net/cache/ba1/be/0a/7db9069448fc85e490b3e33df8fb", + "assets/build/windows/x64/python38_d.dll": "https://files.ballistica.net/cache/ba1/ea/7d/a75abf72b027ddd09073c0e75c78", + "assets/build/windows/x64/python_d.exe": "https://files.ballistica.net/cache/ba1/8c/c4/bc34113dc8c017be1116f8507c81", + "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/4d/11/dd24f5e0b39f4b96e6b924f09534", + "assets/build/windows/x64/pythonw_d.exe": "https://files.ballistica.net/cache/ba1/0c/2d/d432fb479b8baf94fafd9d96707c", "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/05/00/2dd9723909746d8039c6bdf8cddb", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/62/6c310233f4b2c224a46914a4b78e", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/0c/f8/d381993bd58c1f50f0da6d8e2be3", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/b5/d2ec28b09124404731b7f08008c8", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cb/82/4520a3fec142215ed0673a1811d9", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/0b/060333370a987cee92bdd081a8ca", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/11/31/9f1bb364db47563a1d86f0165549", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/11/62/4d784f02705e438f9bd519ff53f4", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8a/ff/abcf2602dc64f718408efeaf4d3a", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/04/2d/1f8c7ea677bae4cc7be8e967c344", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/b8/f19e24bd0e43ed9661ca62c10e6c", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/02/0b/d2fab33376bc7ae1c8797cae5c0f" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/3c/4ec6e5319de5ea5e71c1b9ecb63e", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/40/5d8daec9ea222adba802201b8678", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/bd/1f/3018946be23cfd961f3a9d5d6a1a", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/f2/4faacc69b875c9beec185f3b1b43", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/9d/81553253408524ecc3fde73434e7", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/6a/1f1a1198f07ebfb01375eabd8785", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/9d/82af854c2e7dc71c4edf266ee981", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/62/7a/a2c68757d9e018c74cd68c428e42", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/da/04/c3b9db39e28cf7f4d3a47bb1d06e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/c6/9fe301a0639bca9ef0f36295f662", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c8/9c/3208fe8df1ca8c4cbbac2046256a", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/44/0b/3125d5d6f5568f75ea86a03b1371" } \ No newline at end of file diff --git a/.gitignore b/.gitignore index a7a23f24..3bb3ed9c 100644 --- a/.gitignore +++ b/.gitignore @@ -74,7 +74,9 @@ libs/ !vc_redist.x86.exe !vc_redist.x64.exe !python.exe +!python_d.exe !pythonw.exe +!pythonw_d.exe !**/OculusSDK/Tools/**/*.exe # Note: specifying exact Debug/Release dirs for now; we wind up ignoring diff --git a/.idea/ballisticacore.iml b/.idea/ballisticacore.iml index 2703aac5..7bcaed50 100644 --- a/.idea/ballisticacore.iml +++ b/.idea/ballisticacore.iml @@ -63,7 +63,7 @@ - + \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index d45094c3..352971d3 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -440,6 +440,7 @@ dayoffset dbapi dbase + dbgsfx dbpath dcls dcmake @@ -485,6 +486,7 @@ distroot distros dline + dlldir dlls dmitry dmodule @@ -1061,8 +1063,10 @@ lfull lfval libcrypto + libdir libegl libext + libffi libgen libinst liblzma @@ -1977,6 +1981,7 @@ testcapi testcapimodule testclass + testconsole testd testdl testfoo @@ -1987,6 +1992,7 @@ testm testmagicmethods testmock + testmultiphase testobj testpatch testpath @@ -2058,6 +2064,7 @@ tref tret trophystr + trsock tscale tscl tspc @@ -2203,6 +2210,7 @@ winnergroups winplt winprj + winprune winref winscore winserver diff --git a/.idea/inspectionProfiles/Default.xml b/.idea/inspectionProfiles/Default.xml index f6b77a63..d496ec49 100644 --- a/.idea/inspectionProfiles/Default.xml +++ b/.idea/inspectionProfiles/Default.xml @@ -42,6 +42,7 @@ + diff --git a/.idea/misc.xml b/.idea/misc.xml index b158bc45..2a75f480 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/CHANGELOG.md b/CHANGELOG.md index 75a57e7b..489c5ffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ### 1.5.24 (20159) -- Misc bug fixes. +- Upgraded Python from 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now. +- Windows debug builds now use Python debug libraries. This should hopefully catch more errors that would otherwise go undetected and potentially cause crashes. +- Switched windows builds to use 'fast' mode math instead of 'strict'. This should make the game run more efficiently (similar modes are already in use on other platforms) but holler if any odd breakage happens such as things falling through floors (more often than the occasional random fluke-y case that happens now). ### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json index b2e11385..f5e9ff9f 100644 --- a/assets/.asset_manifest_private.json +++ b/assets/.asset_manifest_private.json @@ -939,26 +939,26 @@ "ba_data/models/zoeTorso.bob", "ba_data/models/zoeUpperArm.bob", "ba_data/models/zoeUpperLeg.bob", - "ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt-1.pyc", + "ba_data/python-site-packages/__pycache__/typing_extensions.cpython-38.opt-1.pyc", "ba_data/python-site-packages/typing_extensions.py", "ba_data/python-site-packages/yaml/__init__.py", - "ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/parser.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc", - "ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/composer.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/error.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/events.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/loader.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/parser.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/reader.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/representer.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-38.opt-1.pyc", + "ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-38.opt-1.pyc", "ba_data/python-site-packages/yaml/composer.py", "ba_data/python-site-packages/yaml/constructor.py", "ba_data/python-site-packages/yaml/cyaml.py", @@ -2577,175 +2577,175 @@ "ba_data/textures/zoeIcon_preview.png", "pylib-android/__future__.py", "pylib-android/__phello__.foo.py", - "pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/abc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/ast.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/base64.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/code.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/copy.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/csv.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/dis.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/enum.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/functools.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/glob.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/imp.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/io.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/locale.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/operator.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/os.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/platform.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/profile.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pty.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/queue.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/random.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/re.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sched.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/signal.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/site.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/socket.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/stat.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/string.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/struct.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/this.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/threading.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/token.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/trace.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/tty.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/types.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/typing.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/uu.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/wave.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc", - "pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc", + "pylib-android/__pycache__/__future__.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/__phello__.foo.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_bootlocale.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_collections_abc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_compat_pickle.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_compression.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_dummy_thread.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_markupbase.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_osx_support.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_py_abc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_pydecimal.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_pyio.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_strptime.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_threading_local.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/_weakrefset.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/abc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/aifc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/antigravity.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/argparse.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/ast.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/asynchat.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/asyncore.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/base64.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/bdb.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/binhex.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/bisect.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/bz2.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/cProfile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/calendar.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/cgi.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/cgitb.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/chunk.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/cmd.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/code.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/codecs.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/codeop.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/colorsys.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/compileall.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/configparser.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/contextlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/contextvars.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/copy.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/copyreg.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/crypt.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/csv.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/dataclasses.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/datetime.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/decimal.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/difflib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/dis.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/doctest.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/dummy_threading.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/enum.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/filecmp.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/fileinput.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/fnmatch.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/formatter.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/fractions.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/ftplib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/functools.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/genericpath.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/getopt.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/getpass.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/gettext.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/glob.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/gzip.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/hashlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/heapq.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/hmac.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/imghdr.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/imp.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/inspect.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/io.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/ipaddress.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/keyword.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/linecache.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/locale.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/lzma.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/mailbox.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/mailcap.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/mimetypes.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/modulefinder.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/netrc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/nntplib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/ntpath.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/nturl2path.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/numbers.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/opcode.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/operator.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/optparse.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/os.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pathlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pdb.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pickle.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pickletools.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pipes.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pkgutil.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/platform.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/plistlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/poplib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/posixpath.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pprint.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/profile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pstats.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pty.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/py_compile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pyclbr.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/pydoc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/queue.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/quopri.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/random.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/re.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/reprlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/rlcompleter.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/runpy.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sched.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/secrets.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/selectors.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/shelve.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/shlex.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/shutil.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/signal.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/site.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/smtpd.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/smtplib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sndhdr.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/socket.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/socketserver.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sre_compile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sre_constants.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sre_parse.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/ssl.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/stat.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/statistics.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/string.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/stringprep.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/struct.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/subprocess.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sunau.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/symbol.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/symtable.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/sysconfig.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/tabnanny.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/tarfile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/telnetlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/tempfile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/textwrap.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/this.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/threading.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/timeit.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/token.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/tokenize.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/trace.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/traceback.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/tracemalloc.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/tty.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/types.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/typing.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/uu.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/uuid.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/warnings.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/wave.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/weakref.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/webbrowser.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/xdrlib.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/zipapp.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/zipfile.cpython-38.opt-1.pyc", + "pylib-android/__pycache__/zipimport.cpython-38.opt-1.pyc", "pylib-android/_bootlocale.py", "pylib-android/_collections_abc.py", "pylib-android/_compat_pickle.py", @@ -2767,31 +2767,36 @@ "pylib-android/ast.py", "pylib-android/asynchat.py", "pylib-android/asyncio/__init__.py", - "pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc", - "pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc", + "pylib-android/asyncio/__main__.py", + "pylib-android/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/constants.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/events.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/futures.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/locks.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/log.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/queues.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/runners.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/streams.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/transports.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc", + "pylib-android/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc", "pylib-android/asyncio/base_events.py", "pylib-android/asyncio/base_futures.py", "pylib-android/asyncio/base_subprocess.py", @@ -2799,6 +2804,7 @@ "pylib-android/asyncio/constants.py", "pylib-android/asyncio/coroutines.py", "pylib-android/asyncio/events.py", + "pylib-android/asyncio/exceptions.py", "pylib-android/asyncio/format_helpers.py", "pylib-android/asyncio/futures.py", "pylib-android/asyncio/locks.py", @@ -2809,10 +2815,12 @@ "pylib-android/asyncio/runners.py", "pylib-android/asyncio/selector_events.py", "pylib-android/asyncio/sslproto.py", + "pylib-android/asyncio/staggered.py", "pylib-android/asyncio/streams.py", "pylib-android/asyncio/subprocess.py", "pylib-android/asyncio/tasks.py", "pylib-android/asyncio/transports.py", + "pylib-android/asyncio/trsock.py", "pylib-android/asyncio/unix_events.py", "pylib-android/asyncio/windows_events.py", "pylib-android/asyncio/windows_utils.py", @@ -2832,18 +2840,18 @@ "pylib-android/codecs.py", "pylib-android/codeop.py", "pylib-android/collections/__init__.py", - "pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc", + "pylib-android/collections/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/collections/__pycache__/abc.cpython-38.opt-1.pyc", "pylib-android/collections/abc.py", "pylib-android/colorsys.py", "pylib-android/compileall.py", "pylib-android/concurrent/__init__.py", - "pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc", + "pylib-android/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc", "pylib-android/concurrent/futures/__init__.py", - "pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc", - "pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc", - "pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc", + "pylib-android/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc", + "pylib-android/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc", + "pylib-android/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc", "pylib-android/concurrent/futures/_base.py", "pylib-android/concurrent/futures/process.py", "pylib-android/concurrent/futures/thread.py", @@ -2855,29 +2863,29 @@ "pylib-android/crypt.py", "pylib-android/csv.py", "pylib-android/ctypes/__init__.py", - "pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc", - "pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc", - "pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc", - "pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc", + "pylib-android/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc", + "pylib-android/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc", + "pylib-android/ctypes/__pycache__/util.cpython-38.opt-1.pyc", + "pylib-android/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc", "pylib-android/ctypes/_aix.py", "pylib-android/ctypes/_endian.py", "pylib-android/ctypes/macholib/__init__.py", - "pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc", - "pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc", - "pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc", + "pylib-android/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc", + "pylib-android/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc", + "pylib-android/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc", "pylib-android/ctypes/macholib/dyld.py", "pylib-android/ctypes/macholib/dylib.py", "pylib-android/ctypes/macholib/framework.py", "pylib-android/ctypes/util.py", "pylib-android/ctypes/wintypes.py", "pylib-android/curses/__init__.py", - "pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc", - "pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc", - "pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc", - "pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc", + "pylib-android/curses/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/curses/__pycache__/ascii.cpython-38.opt-1.pyc", + "pylib-android/curses/__pycache__/has_key.cpython-38.opt-1.pyc", + "pylib-android/curses/__pycache__/panel.cpython-38.opt-1.pyc", + "pylib-android/curses/__pycache__/textpad.cpython-38.opt-1.pyc", "pylib-android/curses/ascii.py", "pylib-android/curses/has_key.py", "pylib-android/curses/panel.py", @@ -2890,26 +2898,26 @@ "pylib-android/doctest.py", "pylib-android/dummy_threading.py", "pylib-android/email/__init__.py", - "pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc", - "pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc", + "pylib-android/email/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/_policybase.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/base64mime.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/charset.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/contentmanager.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/encoders.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/errors.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/feedparser.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/generator.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/header.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/headerregistry.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/iterators.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/message.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/parser.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/policy.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/quoprimime.cpython-38.opt-1.pyc", + "pylib-android/email/__pycache__/utils.cpython-38.opt-1.pyc", "pylib-android/email/_encoded_words.py", "pylib-android/email/_header_value_parser.py", "pylib-android/email/_parseaddr.py", @@ -2926,15 +2934,15 @@ "pylib-android/email/iterators.py", "pylib-android/email/message.py", "pylib-android/email/mime/__init__.py", - "pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc", - "pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc", + "pylib-android/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/application.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/audio.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/base.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/image.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/message.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc", + "pylib-android/email/mime/__pycache__/text.cpython-38.opt-1.pyc", "pylib-android/email/mime/application.py", "pylib-android/email/mime/audio.py", "pylib-android/email/mime/base.py", @@ -2948,131 +2956,129 @@ "pylib-android/email/quoprimime.py", "pylib-android/email/utils.py", "pylib-android/encodings/__init__.py", - "pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc", - "pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc", + "pylib-android/encodings/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/aliases.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/ascii.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/big5.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/charmap.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp037.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp273.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp424.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp437.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp500.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp720.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp737.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp775.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp850.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp852.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp855.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp856.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp857.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp858.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp860.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp861.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp862.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp863.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp864.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp865.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp866.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp869.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp874.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp875.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp932.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp949.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/cp950.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/gbk.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/hz.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/idna.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/johab.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/oem.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/palmos.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/punycode.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/undefined.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc", + "pylib-android/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc", "pylib-android/encodings/aliases.py", "pylib-android/encodings/ascii.py", "pylib-android/encodings/base64_codec.py", @@ -3098,7 +3104,6 @@ "pylib-android/encodings/cp424.py", "pylib-android/encodings/cp437.py", "pylib-android/encodings/cp500.py", - "pylib-android/encodings/cp65001.py", "pylib-android/encodings/cp720.py", "pylib-android/encodings/cp737.py", "pylib-android/encodings/cp775.py", @@ -3185,7 +3190,6 @@ "pylib-android/encodings/tis_620.py", "pylib-android/encodings/undefined.py", "pylib-android/encodings/unicode_escape.py", - "pylib-android/encodings/unicode_internal.py", "pylib-android/encodings/utf_16.py", "pylib-android/encodings/utf_16_be.py", "pylib-android/encodings/utf_16_le.py", @@ -3215,17 +3219,17 @@ "pylib-android/heapq.py", "pylib-android/hmac.py", "pylib-android/html/__init__.py", - "pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc", - "pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc", + "pylib-android/html/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/html/__pycache__/entities.cpython-38.opt-1.pyc", + "pylib-android/html/__pycache__/parser.cpython-38.opt-1.pyc", "pylib-android/html/entities.py", "pylib-android/html/parser.py", "pylib-android/http/__init__.py", - "pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc", - "pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc", - "pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc", - "pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc", + "pylib-android/http/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/http/__pycache__/client.cpython-38.opt-1.pyc", + "pylib-android/http/__pycache__/cookiejar.cpython-38.opt-1.pyc", + "pylib-android/http/__pycache__/cookies.cpython-38.opt-1.pyc", + "pylib-android/http/__pycache__/server.cpython-38.opt-1.pyc", "pylib-android/http/client.py", "pylib-android/http/cookiejar.py", "pylib-android/http/cookies.py", @@ -3233,28 +3237,30 @@ "pylib-android/imghdr.py", "pylib-android/imp.py", "pylib-android/importlib/__init__.py", - "pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc", - "pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc", - "pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc", - "pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc", - "pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc", - "pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc", + "pylib-android/importlib/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/abc.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/machinery.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/metadata.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/resources.cpython-38.opt-1.pyc", + "pylib-android/importlib/__pycache__/util.cpython-38.opt-1.pyc", "pylib-android/importlib/_bootstrap.py", "pylib-android/importlib/_bootstrap_external.py", "pylib-android/importlib/abc.py", "pylib-android/importlib/machinery.py", + "pylib-android/importlib/metadata.py", "pylib-android/importlib/resources.py", "pylib-android/importlib/util.py", "pylib-android/inspect.py", "pylib-android/io.py", "pylib-android/ipaddress.py", "pylib-android/json/__init__.py", - "pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc", - "pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc", - "pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc", - "pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc", + "pylib-android/json/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/json/__pycache__/decoder.cpython-38.opt-1.pyc", + "pylib-android/json/__pycache__/encoder.cpython-38.opt-1.pyc", + "pylib-android/json/__pycache__/scanner.cpython-38.opt-1.pyc", + "pylib-android/json/__pycache__/tool.cpython-38.opt-1.pyc", "pylib-android/json/decoder.py", "pylib-android/json/encoder.py", "pylib-android/json/scanner.py", @@ -3263,13 +3269,12 @@ "pylib-android/linecache.py", "pylib-android/locale.py", "pylib-android/logging/__init__.py", - "pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc", - "pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc", + "pylib-android/logging/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/logging/__pycache__/config.cpython-38.opt-1.pyc", + "pylib-android/logging/__pycache__/handlers.cpython-38.opt-1.pyc", "pylib-android/logging/config.py", "pylib-android/logging/handlers.py", "pylib-android/lzma.py", - "pylib-android/macpath.py", "pylib-android/mailbox.py", "pylib-android/mailcap.py", "pylib-android/mimetypes.py", @@ -3321,9 +3326,9 @@ "pylib-android/socket.py", "pylib-android/socketserver.py", "pylib-android/sqlite3/__init__.py", - "pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc", - "pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc", + "pylib-android/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc", + "pylib-android/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc", "pylib-android/sqlite3/dbapi2.py", "pylib-android/sqlite3/dump.py", "pylib-android/sre_compile.py", @@ -3357,12 +3362,12 @@ "pylib-android/types.py", "pylib-android/typing.py", "pylib-android/urllib/__init__.py", - "pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc", - "pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc", - "pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc", - "pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc", - "pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc", + "pylib-android/urllib/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/urllib/__pycache__/error.cpython-38.opt-1.pyc", + "pylib-android/urllib/__pycache__/parse.cpython-38.opt-1.pyc", + "pylib-android/urllib/__pycache__/request.cpython-38.opt-1.pyc", + "pylib-android/urllib/__pycache__/response.cpython-38.opt-1.pyc", + "pylib-android/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc", "pylib-android/urllib/error.py", "pylib-android/urllib/parse.py", "pylib-android/urllib/request.py", @@ -3376,17 +3381,17 @@ "pylib-android/webbrowser.py", "pylib-android/xdrlib.py", "pylib-android/xml/__init__.py", - "pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc", + "pylib-android/xml/__pycache__/__init__.cpython-38.opt-1.pyc", "pylib-android/xml/dom/NodeFilter.py", "pylib-android/xml/dom/__init__.py", - "pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc", - "pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc", + "pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc", "pylib-android/xml/dom/domreg.py", "pylib-android/xml/dom/expatbuilder.py", "pylib-android/xml/dom/minicompat.py", @@ -3397,207 +3402,208 @@ "pylib-android/xml/etree/ElementPath.py", "pylib-android/xml/etree/ElementTree.py", "pylib-android/xml/etree/__init__.py", - "pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc", - "pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc", - "pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc", - "pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc", + "pylib-android/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc", + "pylib-android/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc", + "pylib-android/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc", + "pylib-android/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc", "pylib-android/xml/etree/cElementTree.py", "pylib-android/xml/parsers/__init__.py", - "pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc", + "pylib-android/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc", "pylib-android/xml/parsers/expat.py", "pylib-android/xml/sax/__init__.py", - "pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc", - "pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc", - "pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc", - "pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc", - "pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc", + "pylib-android/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc", + "pylib-android/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc", + "pylib-android/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc", + "pylib-android/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc", + "pylib-android/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc", "pylib-android/xml/sax/_exceptions.py", "pylib-android/xml/sax/expatreader.py", "pylib-android/xml/sax/handler.py", "pylib-android/xml/sax/saxutils.py", "pylib-android/xml/sax/xmlreader.py", "pylib-android/xmlrpc/__init__.py", - "pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc", - "pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc", + "pylib-android/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-android/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc", + "pylib-android/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc", "pylib-android/xmlrpc/client.py", "pylib-android/xmlrpc/server.py", "pylib-android/zipapp.py", "pylib-android/zipfile.py", + "pylib-android/zipimport.py", "pylib-apple/__future__.py", "pylib-apple/__phello__.foo.py", - "pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/code.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/io.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/os.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/random.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/re.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/site.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/string.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/this.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/token.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/types.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc", - "pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc", + "pylib-apple/__pycache__/__future__.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/__phello__.foo.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_bootlocale.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_collections_abc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_compat_pickle.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_compression.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_dummy_thread.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_markupbase.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_osx_support.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_py_abc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_pydecimal.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_pyio.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_strptime.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_threading_local.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/_weakrefset.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/abc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/aifc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/antigravity.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/argparse.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/ast.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/asynchat.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/asyncore.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/base64.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/bdb.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/binhex.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/bisect.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/bz2.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/cProfile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/calendar.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/cgi.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/cgitb.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/chunk.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/cmd.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/code.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/codecs.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/codeop.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/colorsys.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/compileall.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/configparser.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/contextlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/contextvars.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/copy.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/copyreg.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/crypt.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/csv.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/dataclasses.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/datetime.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/decimal.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/difflib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/dis.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/doctest.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/dummy_threading.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/enum.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/filecmp.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/fileinput.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/fnmatch.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/formatter.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/fractions.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/ftplib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/functools.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/genericpath.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/getopt.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/getpass.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/gettext.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/glob.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/gzip.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/hashlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/heapq.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/hmac.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/imghdr.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/imp.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/inspect.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/io.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/ipaddress.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/keyword.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/linecache.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/locale.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/lzma.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/mailbox.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/mailcap.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/mimetypes.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/modulefinder.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/netrc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/nntplib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/ntpath.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/nturl2path.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/numbers.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/opcode.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/operator.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/optparse.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/os.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pathlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pdb.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pickle.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pickletools.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pipes.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pkgutil.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/platform.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/plistlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/poplib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/posixpath.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pprint.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/profile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pstats.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pty.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/py_compile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pyclbr.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/pydoc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/queue.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/quopri.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/random.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/re.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/reprlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/rlcompleter.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/runpy.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sched.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/secrets.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/selectors.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/shelve.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/shlex.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/shutil.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/signal.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/site.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/smtpd.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/smtplib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sndhdr.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/socket.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/socketserver.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sre_compile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sre_constants.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sre_parse.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/ssl.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/stat.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/statistics.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/string.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/stringprep.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/struct.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/subprocess.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sunau.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/symbol.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/symtable.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/sysconfig.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/tabnanny.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/tarfile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/telnetlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/tempfile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/textwrap.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/this.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/threading.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/timeit.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/token.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/tokenize.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/trace.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/traceback.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/tracemalloc.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/tty.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/types.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/typing.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/uu.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/uuid.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/warnings.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/wave.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/weakref.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/webbrowser.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/xdrlib.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/zipapp.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/zipfile.cpython-38.opt-1.pyc", + "pylib-apple/__pycache__/zipimport.cpython-38.opt-1.pyc", "pylib-apple/_bootlocale.py", "pylib-apple/_collections_abc.py", "pylib-apple/_compat_pickle.py", @@ -3619,31 +3625,36 @@ "pylib-apple/ast.py", "pylib-apple/asynchat.py", "pylib-apple/asyncio/__init__.py", - "pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc", - "pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc", + "pylib-apple/asyncio/__main__.py", + "pylib-apple/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/constants.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/events.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/futures.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/locks.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/log.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/queues.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/runners.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/streams.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/transports.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc", + "pylib-apple/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc", "pylib-apple/asyncio/base_events.py", "pylib-apple/asyncio/base_futures.py", "pylib-apple/asyncio/base_subprocess.py", @@ -3651,6 +3662,7 @@ "pylib-apple/asyncio/constants.py", "pylib-apple/asyncio/coroutines.py", "pylib-apple/asyncio/events.py", + "pylib-apple/asyncio/exceptions.py", "pylib-apple/asyncio/format_helpers.py", "pylib-apple/asyncio/futures.py", "pylib-apple/asyncio/locks.py", @@ -3661,10 +3673,12 @@ "pylib-apple/asyncio/runners.py", "pylib-apple/asyncio/selector_events.py", "pylib-apple/asyncio/sslproto.py", + "pylib-apple/asyncio/staggered.py", "pylib-apple/asyncio/streams.py", "pylib-apple/asyncio/subprocess.py", "pylib-apple/asyncio/tasks.py", "pylib-apple/asyncio/transports.py", + "pylib-apple/asyncio/trsock.py", "pylib-apple/asyncio/unix_events.py", "pylib-apple/asyncio/windows_events.py", "pylib-apple/asyncio/windows_utils.py", @@ -3684,18 +3698,18 @@ "pylib-apple/codecs.py", "pylib-apple/codeop.py", "pylib-apple/collections/__init__.py", - "pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc", + "pylib-apple/collections/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/collections/__pycache__/abc.cpython-38.opt-1.pyc", "pylib-apple/collections/abc.py", "pylib-apple/colorsys.py", "pylib-apple/compileall.py", "pylib-apple/concurrent/__init__.py", - "pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc", + "pylib-apple/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc", "pylib-apple/concurrent/futures/__init__.py", - "pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc", - "pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc", - "pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc", + "pylib-apple/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc", + "pylib-apple/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc", + "pylib-apple/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc", "pylib-apple/concurrent/futures/_base.py", "pylib-apple/concurrent/futures/process.py", "pylib-apple/concurrent/futures/thread.py", @@ -3707,29 +3721,29 @@ "pylib-apple/crypt.py", "pylib-apple/csv.py", "pylib-apple/ctypes/__init__.py", - "pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc", + "pylib-apple/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/__pycache__/util.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc", "pylib-apple/ctypes/_aix.py", "pylib-apple/ctypes/_endian.py", "pylib-apple/ctypes/macholib/__init__.py", - "pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc", - "pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc", + "pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc", + "pylib-apple/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc", "pylib-apple/ctypes/macholib/dyld.py", "pylib-apple/ctypes/macholib/dylib.py", "pylib-apple/ctypes/macholib/framework.py", "pylib-apple/ctypes/util.py", "pylib-apple/ctypes/wintypes.py", "pylib-apple/curses/__init__.py", - "pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc", - "pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc", - "pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc", - "pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc", + "pylib-apple/curses/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/curses/__pycache__/ascii.cpython-38.opt-1.pyc", + "pylib-apple/curses/__pycache__/has_key.cpython-38.opt-1.pyc", + "pylib-apple/curses/__pycache__/panel.cpython-38.opt-1.pyc", + "pylib-apple/curses/__pycache__/textpad.cpython-38.opt-1.pyc", "pylib-apple/curses/ascii.py", "pylib-apple/curses/has_key.py", "pylib-apple/curses/panel.py", @@ -3742,26 +3756,26 @@ "pylib-apple/doctest.py", "pylib-apple/dummy_threading.py", "pylib-apple/email/__init__.py", - "pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc", - "pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc", + "pylib-apple/email/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/_policybase.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/base64mime.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/charset.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/contentmanager.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/encoders.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/errors.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/feedparser.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/generator.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/header.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/headerregistry.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/iterators.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/message.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/parser.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/policy.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/quoprimime.cpython-38.opt-1.pyc", + "pylib-apple/email/__pycache__/utils.cpython-38.opt-1.pyc", "pylib-apple/email/_encoded_words.py", "pylib-apple/email/_header_value_parser.py", "pylib-apple/email/_parseaddr.py", @@ -3778,15 +3792,15 @@ "pylib-apple/email/iterators.py", "pylib-apple/email/message.py", "pylib-apple/email/mime/__init__.py", - "pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc", - "pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/application.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/audio.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/base.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/image.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/message.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc", + "pylib-apple/email/mime/__pycache__/text.cpython-38.opt-1.pyc", "pylib-apple/email/mime/application.py", "pylib-apple/email/mime/audio.py", "pylib-apple/email/mime/base.py", @@ -3800,131 +3814,129 @@ "pylib-apple/email/quoprimime.py", "pylib-apple/email/utils.py", "pylib-apple/encodings/__init__.py", - "pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc", - "pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc", + "pylib-apple/encodings/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/aliases.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/ascii.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/big5.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/charmap.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp037.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp273.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp424.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp437.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp500.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp720.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp737.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp775.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp850.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp852.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp855.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp856.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp857.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp858.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp860.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp861.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp862.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp863.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp864.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp865.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp866.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp869.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp874.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp875.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp932.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp949.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/cp950.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/gbk.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/hz.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/idna.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/johab.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/oem.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/palmos.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/punycode.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/undefined.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc", + "pylib-apple/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc", "pylib-apple/encodings/aliases.py", "pylib-apple/encodings/ascii.py", "pylib-apple/encodings/base64_codec.py", @@ -3950,7 +3962,6 @@ "pylib-apple/encodings/cp424.py", "pylib-apple/encodings/cp437.py", "pylib-apple/encodings/cp500.py", - "pylib-apple/encodings/cp65001.py", "pylib-apple/encodings/cp720.py", "pylib-apple/encodings/cp737.py", "pylib-apple/encodings/cp775.py", @@ -4037,7 +4048,6 @@ "pylib-apple/encodings/tis_620.py", "pylib-apple/encodings/undefined.py", "pylib-apple/encodings/unicode_escape.py", - "pylib-apple/encodings/unicode_internal.py", "pylib-apple/encodings/utf_16.py", "pylib-apple/encodings/utf_16_be.py", "pylib-apple/encodings/utf_16_le.py", @@ -4067,17 +4077,17 @@ "pylib-apple/heapq.py", "pylib-apple/hmac.py", "pylib-apple/html/__init__.py", - "pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc", - "pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc", + "pylib-apple/html/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/html/__pycache__/entities.cpython-38.opt-1.pyc", + "pylib-apple/html/__pycache__/parser.cpython-38.opt-1.pyc", "pylib-apple/html/entities.py", "pylib-apple/html/parser.py", "pylib-apple/http/__init__.py", - "pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc", - "pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc", - "pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc", - "pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc", + "pylib-apple/http/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/http/__pycache__/client.cpython-38.opt-1.pyc", + "pylib-apple/http/__pycache__/cookiejar.cpython-38.opt-1.pyc", + "pylib-apple/http/__pycache__/cookies.cpython-38.opt-1.pyc", + "pylib-apple/http/__pycache__/server.cpython-38.opt-1.pyc", "pylib-apple/http/client.py", "pylib-apple/http/cookiejar.py", "pylib-apple/http/cookies.py", @@ -4085,28 +4095,30 @@ "pylib-apple/imghdr.py", "pylib-apple/imp.py", "pylib-apple/importlib/__init__.py", - "pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc", - "pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc", - "pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc", - "pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc", - "pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc", - "pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc", + "pylib-apple/importlib/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/abc.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/machinery.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/metadata.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/resources.cpython-38.opt-1.pyc", + "pylib-apple/importlib/__pycache__/util.cpython-38.opt-1.pyc", "pylib-apple/importlib/_bootstrap.py", "pylib-apple/importlib/_bootstrap_external.py", "pylib-apple/importlib/abc.py", "pylib-apple/importlib/machinery.py", + "pylib-apple/importlib/metadata.py", "pylib-apple/importlib/resources.py", "pylib-apple/importlib/util.py", "pylib-apple/inspect.py", "pylib-apple/io.py", "pylib-apple/ipaddress.py", "pylib-apple/json/__init__.py", - "pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc", - "pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc", - "pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc", - "pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc", + "pylib-apple/json/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/json/__pycache__/decoder.cpython-38.opt-1.pyc", + "pylib-apple/json/__pycache__/encoder.cpython-38.opt-1.pyc", + "pylib-apple/json/__pycache__/scanner.cpython-38.opt-1.pyc", + "pylib-apple/json/__pycache__/tool.cpython-38.opt-1.pyc", "pylib-apple/json/decoder.py", "pylib-apple/json/encoder.py", "pylib-apple/json/scanner.py", @@ -4115,13 +4127,12 @@ "pylib-apple/linecache.py", "pylib-apple/locale.py", "pylib-apple/logging/__init__.py", - "pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc", - "pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc", + "pylib-apple/logging/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/logging/__pycache__/config.cpython-38.opt-1.pyc", + "pylib-apple/logging/__pycache__/handlers.cpython-38.opt-1.pyc", "pylib-apple/logging/config.py", "pylib-apple/logging/handlers.py", "pylib-apple/lzma.py", - "pylib-apple/macpath.py", "pylib-apple/mailbox.py", "pylib-apple/mailcap.py", "pylib-apple/mimetypes.py", @@ -4173,9 +4184,9 @@ "pylib-apple/socket.py", "pylib-apple/socketserver.py", "pylib-apple/sqlite3/__init__.py", - "pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc", - "pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc", + "pylib-apple/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc", + "pylib-apple/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc", "pylib-apple/sqlite3/dbapi2.py", "pylib-apple/sqlite3/dump.py", "pylib-apple/sre_compile.py", @@ -4209,12 +4220,12 @@ "pylib-apple/types.py", "pylib-apple/typing.py", "pylib-apple/urllib/__init__.py", - "pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc", - "pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc", - "pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc", - "pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc", - "pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc", + "pylib-apple/urllib/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/urllib/__pycache__/error.cpython-38.opt-1.pyc", + "pylib-apple/urllib/__pycache__/parse.cpython-38.opt-1.pyc", + "pylib-apple/urllib/__pycache__/request.cpython-38.opt-1.pyc", + "pylib-apple/urllib/__pycache__/response.cpython-38.opt-1.pyc", + "pylib-apple/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc", "pylib-apple/urllib/error.py", "pylib-apple/urllib/parse.py", "pylib-apple/urllib/request.py", @@ -4228,17 +4239,17 @@ "pylib-apple/webbrowser.py", "pylib-apple/xdrlib.py", "pylib-apple/xml/__init__.py", - "pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc", + "pylib-apple/xml/__pycache__/__init__.cpython-38.opt-1.pyc", "pylib-apple/xml/dom/NodeFilter.py", "pylib-apple/xml/dom/__init__.py", - "pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc", - "pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc", + "pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc", "pylib-apple/xml/dom/domreg.py", "pylib-apple/xml/dom/expatbuilder.py", "pylib-apple/xml/dom/minicompat.py", @@ -4249,235 +4260,268 @@ "pylib-apple/xml/etree/ElementPath.py", "pylib-apple/xml/etree/ElementTree.py", "pylib-apple/xml/etree/__init__.py", - "pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc", - "pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc", - "pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc", - "pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc", + "pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc", + "pylib-apple/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc", + "pylib-apple/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc", + "pylib-apple/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc", "pylib-apple/xml/etree/cElementTree.py", "pylib-apple/xml/parsers/__init__.py", - "pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc", + "pylib-apple/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc", "pylib-apple/xml/parsers/expat.py", "pylib-apple/xml/sax/__init__.py", - "pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc", - "pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc", - "pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc", - "pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc", - "pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc", + "pylib-apple/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc", + "pylib-apple/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc", + "pylib-apple/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc", + "pylib-apple/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc", + "pylib-apple/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc", "pylib-apple/xml/sax/_exceptions.py", "pylib-apple/xml/sax/expatreader.py", "pylib-apple/xml/sax/handler.py", "pylib-apple/xml/sax/saxutils.py", "pylib-apple/xml/sax/xmlreader.py", "pylib-apple/xmlrpc/__init__.py", - "pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc", - "pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc", - "pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc", + "pylib-apple/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc", + "pylib-apple/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc", + "pylib-apple/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc", "pylib-apple/xmlrpc/client.py", "pylib-apple/xmlrpc/server.py", "pylib-apple/zipapp.py", "pylib-apple/zipfile.py", + "pylib-apple/zipimport.py", "windows/Win32/DLLs/_asyncio.pyd", + "windows/Win32/DLLs/_asyncio_d.pyd", "windows/Win32/DLLs/_bz2.pyd", + "windows/Win32/DLLs/_bz2_d.pyd", "windows/Win32/DLLs/_ctypes.pyd", + "windows/Win32/DLLs/_ctypes_d.pyd", + "windows/Win32/DLLs/_ctypes_test.pyd", + "windows/Win32/DLLs/_ctypes_test_d.pyd", "windows/Win32/DLLs/_decimal.pyd", + "windows/Win32/DLLs/_decimal_d.pyd", "windows/Win32/DLLs/_elementtree.pyd", + "windows/Win32/DLLs/_elementtree_d.pyd", "windows/Win32/DLLs/_hashlib.pyd", + "windows/Win32/DLLs/_hashlib_d.pyd", "windows/Win32/DLLs/_lzma.pyd", + "windows/Win32/DLLs/_lzma_d.pyd", "windows/Win32/DLLs/_msi.pyd", + "windows/Win32/DLLs/_msi_d.pyd", "windows/Win32/DLLs/_multiprocessing.pyd", + "windows/Win32/DLLs/_multiprocessing_d.pyd", "windows/Win32/DLLs/_overlapped.pyd", + "windows/Win32/DLLs/_overlapped_d.pyd", "windows/Win32/DLLs/_queue.pyd", + "windows/Win32/DLLs/_queue_d.pyd", "windows/Win32/DLLs/_socket.pyd", + "windows/Win32/DLLs/_socket_d.pyd", "windows/Win32/DLLs/_sqlite3.pyd", + "windows/Win32/DLLs/_sqlite3_d.pyd", "windows/Win32/DLLs/_ssl.pyd", + "windows/Win32/DLLs/_ssl_d.pyd", + "windows/Win32/DLLs/_testbuffer.pyd", + "windows/Win32/DLLs/_testbuffer_d.pyd", + "windows/Win32/DLLs/_testcapi.pyd", + "windows/Win32/DLLs/_testcapi_d.pyd", + "windows/Win32/DLLs/_testconsole.pyd", + "windows/Win32/DLLs/_testconsole_d.pyd", + "windows/Win32/DLLs/_testimportmultiple.pyd", + "windows/Win32/DLLs/_testimportmultiple_d.pyd", + "windows/Win32/DLLs/_testmultiphase.pyd", + "windows/Win32/DLLs/_testmultiphase_d.pyd", + "windows/Win32/DLLs/_tkinter.pyd", + "windows/Win32/DLLs/_tkinter_d.lib", + "windows/Win32/DLLs/_tkinter_d.pyd", "windows/Win32/DLLs/libcrypto-1_1.dll", + "windows/Win32/DLLs/libffi-7.dll", "windows/Win32/DLLs/libssl-1_1.dll", - "windows/Win32/DLLs/py.ico", - "windows/Win32/DLLs/pyc.ico", - "windows/Win32/DLLs/pyd.ico", "windows/Win32/DLLs/pyexpat.pyd", + "windows/Win32/DLLs/pyexpat_d.pyd", "windows/Win32/DLLs/python_lib.cat", "windows/Win32/DLLs/python_tools.cat", "windows/Win32/DLLs/select.pyd", + "windows/Win32/DLLs/select_d.pyd", "windows/Win32/DLLs/sqlite3.dll", + "windows/Win32/DLLs/sqlite3_d.dll", + "windows/Win32/DLLs/tcl86t.dll", + "windows/Win32/DLLs/tk86t.dll", "windows/Win32/DLLs/unicodedata.pyd", + "windows/Win32/DLLs/unicodedata_d.pyd", "windows/Win32/DLLs/winsound.pyd", + "windows/Win32/DLLs/winsound_d.pyd", "windows/Win32/Lib/__future__.py", "windows/Win32/Lib/__phello__.foo.py", - "windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc", - "windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc", + "windows/Win32/Lib/__pycache__/__future__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/__phello__.foo.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_bootlocale.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_collections_abc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_compat_pickle.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_compression.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_dummy_thread.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_markupbase.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_osx_support.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_py_abc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_pydecimal.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_pyio.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_strptime.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_threading_local.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/_weakrefset.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/abc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/aifc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/antigravity.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/argparse.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/ast.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/asynchat.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/asyncore.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/base64.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/bdb.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/binhex.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/bisect.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/bz2.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/cProfile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/calendar.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/cgi.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/cgitb.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/chunk.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/cmd.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/code.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/codecs.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/codeop.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/colorsys.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/compileall.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/configparser.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/contextlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/contextvars.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/copy.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/copyreg.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/crypt.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/csv.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/dataclasses.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/datetime.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/decimal.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/difflib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/dis.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/doctest.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/dummy_threading.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/enum.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/filecmp.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/fileinput.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/fnmatch.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/formatter.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/fractions.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/ftplib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/functools.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/genericpath.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/getopt.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/getpass.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/gettext.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/glob.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/gzip.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/hashlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/heapq.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/hmac.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/imghdr.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/imp.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/inspect.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/io.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/ipaddress.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/keyword.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/linecache.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/locale.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/lzma.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/mailbox.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/mailcap.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/mimetypes.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/modulefinder.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/netrc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/nntplib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/ntpath.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/nturl2path.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/numbers.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/opcode.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/operator.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/optparse.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/os.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pathlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pdb.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pickle.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pickletools.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pipes.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pkgutil.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/platform.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/plistlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/poplib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/posixpath.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pprint.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/profile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pstats.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pty.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/py_compile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pyclbr.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/pydoc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/queue.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/quopri.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/random.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/re.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/reprlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/rlcompleter.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/runpy.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sched.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/secrets.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/selectors.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/shelve.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/shlex.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/shutil.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/signal.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/site.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/smtpd.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/smtplib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sndhdr.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/socket.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/socketserver.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sre_compile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sre_constants.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sre_parse.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/ssl.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/stat.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/statistics.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/string.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/stringprep.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/struct.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/subprocess.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sunau.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/symbol.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/symtable.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/sysconfig.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/tabnanny.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/tarfile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/telnetlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/tempfile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/textwrap.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/this.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/threading.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/timeit.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/token.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/tokenize.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/trace.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/traceback.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/tracemalloc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/tty.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/types.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/typing.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/uu.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/uuid.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/warnings.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/wave.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/weakref.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/webbrowser.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/xdrlib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/zipapp.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/zipfile.cpython-38.opt-1.pyc", + "windows/Win32/Lib/__pycache__/zipimport.cpython-38.opt-1.pyc", "windows/Win32/Lib/_bootlocale.py", "windows/Win32/Lib/_collections_abc.py", "windows/Win32/Lib/_compat_pickle.py", @@ -4499,31 +4543,36 @@ "windows/Win32/Lib/ast.py", "windows/Win32/Lib/asynchat.py", "windows/Win32/Lib/asyncio/__init__.py", - "windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc", - "windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc", + "windows/Win32/Lib/asyncio/__main__.py", + "windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/constants.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/events.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/futures.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/locks.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/log.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/queues.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/runners.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/streams.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/transports.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc", + "windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc", "windows/Win32/Lib/asyncio/base_events.py", "windows/Win32/Lib/asyncio/base_futures.py", "windows/Win32/Lib/asyncio/base_subprocess.py", @@ -4531,6 +4580,7 @@ "windows/Win32/Lib/asyncio/constants.py", "windows/Win32/Lib/asyncio/coroutines.py", "windows/Win32/Lib/asyncio/events.py", + "windows/Win32/Lib/asyncio/exceptions.py", "windows/Win32/Lib/asyncio/format_helpers.py", "windows/Win32/Lib/asyncio/futures.py", "windows/Win32/Lib/asyncio/locks.py", @@ -4541,10 +4591,12 @@ "windows/Win32/Lib/asyncio/runners.py", "windows/Win32/Lib/asyncio/selector_events.py", "windows/Win32/Lib/asyncio/sslproto.py", + "windows/Win32/Lib/asyncio/staggered.py", "windows/Win32/Lib/asyncio/streams.py", "windows/Win32/Lib/asyncio/subprocess.py", "windows/Win32/Lib/asyncio/tasks.py", "windows/Win32/Lib/asyncio/transports.py", + "windows/Win32/Lib/asyncio/trsock.py", "windows/Win32/Lib/asyncio/unix_events.py", "windows/Win32/Lib/asyncio/windows_events.py", "windows/Win32/Lib/asyncio/windows_utils.py", @@ -4564,18 +4616,18 @@ "windows/Win32/Lib/codecs.py", "windows/Win32/Lib/codeop.py", "windows/Win32/Lib/collections/__init__.py", - "windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc", + "windows/Win32/Lib/collections/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/collections/__pycache__/abc.cpython-38.opt-1.pyc", "windows/Win32/Lib/collections/abc.py", "windows/Win32/Lib/colorsys.py", "windows/Win32/Lib/compileall.py", "windows/Win32/Lib/concurrent/__init__.py", - "windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc", + "windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc", "windows/Win32/Lib/concurrent/futures/__init__.py", - "windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc", - "windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc", - "windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc", + "windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc", + "windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc", + "windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc", "windows/Win32/Lib/concurrent/futures/_base.py", "windows/Win32/Lib/concurrent/futures/process.py", "windows/Win32/Lib/concurrent/futures/thread.py", @@ -4587,372 +4639,64 @@ "windows/Win32/Lib/crypt.py", "windows/Win32/Lib/csv.py", "windows/Win32/Lib/ctypes/__init__.py", - "windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc", + "windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/__pycache__/util.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc", "windows/Win32/Lib/ctypes/_aix.py", "windows/Win32/Lib/ctypes/_endian.py", "windows/Win32/Lib/ctypes/macholib/README.ctypes", "windows/Win32/Lib/ctypes/macholib/__init__.py", - "windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc", + "windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc", + "windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc", "windows/Win32/Lib/ctypes/macholib/dyld.py", "windows/Win32/Lib/ctypes/macholib/dylib.py", "windows/Win32/Lib/ctypes/macholib/fetch_macholib", "windows/Win32/Lib/ctypes/macholib/fetch_macholib.bat", "windows/Win32/Lib/ctypes/macholib/framework.py", - "windows/Win32/Lib/ctypes/test/__init__.py", - "windows/Win32/Lib/ctypes/test/__main__.py", - "windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ctypes/test/test_anon.py", - "windows/Win32/Lib/ctypes/test/test_array_in_pointer.py", - "windows/Win32/Lib/ctypes/test/test_arrays.py", - "windows/Win32/Lib/ctypes/test/test_as_parameter.py", - "windows/Win32/Lib/ctypes/test/test_bitfields.py", - "windows/Win32/Lib/ctypes/test/test_buffers.py", - "windows/Win32/Lib/ctypes/test/test_bytes.py", - "windows/Win32/Lib/ctypes/test/test_byteswap.py", - "windows/Win32/Lib/ctypes/test/test_callbacks.py", - "windows/Win32/Lib/ctypes/test/test_cast.py", - "windows/Win32/Lib/ctypes/test/test_cfuncs.py", - "windows/Win32/Lib/ctypes/test/test_checkretval.py", - "windows/Win32/Lib/ctypes/test/test_delattr.py", - "windows/Win32/Lib/ctypes/test/test_errno.py", - "windows/Win32/Lib/ctypes/test/test_find.py", - "windows/Win32/Lib/ctypes/test/test_frombuffer.py", - "windows/Win32/Lib/ctypes/test/test_funcptr.py", - "windows/Win32/Lib/ctypes/test/test_functions.py", - "windows/Win32/Lib/ctypes/test/test_incomplete.py", - "windows/Win32/Lib/ctypes/test/test_init.py", - "windows/Win32/Lib/ctypes/test/test_internals.py", - "windows/Win32/Lib/ctypes/test/test_keeprefs.py", - "windows/Win32/Lib/ctypes/test/test_libc.py", - "windows/Win32/Lib/ctypes/test/test_loading.py", - "windows/Win32/Lib/ctypes/test/test_macholib.py", - "windows/Win32/Lib/ctypes/test/test_memfunctions.py", - "windows/Win32/Lib/ctypes/test/test_numbers.py", - "windows/Win32/Lib/ctypes/test/test_objects.py", - "windows/Win32/Lib/ctypes/test/test_parameters.py", - "windows/Win32/Lib/ctypes/test/test_pep3118.py", - "windows/Win32/Lib/ctypes/test/test_pickling.py", - "windows/Win32/Lib/ctypes/test/test_pointers.py", - "windows/Win32/Lib/ctypes/test/test_prototypes.py", - "windows/Win32/Lib/ctypes/test/test_python_api.py", - "windows/Win32/Lib/ctypes/test/test_random_things.py", - "windows/Win32/Lib/ctypes/test/test_refcounts.py", - "windows/Win32/Lib/ctypes/test/test_repr.py", - "windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py", - "windows/Win32/Lib/ctypes/test/test_simplesubclasses.py", - "windows/Win32/Lib/ctypes/test/test_sizes.py", - "windows/Win32/Lib/ctypes/test/test_slicing.py", - "windows/Win32/Lib/ctypes/test/test_stringptr.py", - "windows/Win32/Lib/ctypes/test/test_strings.py", - "windows/Win32/Lib/ctypes/test/test_struct_fields.py", - "windows/Win32/Lib/ctypes/test/test_structures.py", - "windows/Win32/Lib/ctypes/test/test_unaligned_structures.py", - "windows/Win32/Lib/ctypes/test/test_unicode.py", - "windows/Win32/Lib/ctypes/test/test_values.py", - "windows/Win32/Lib/ctypes/test/test_varsize_struct.py", - "windows/Win32/Lib/ctypes/test/test_win32.py", - "windows/Win32/Lib/ctypes/test/test_wintypes.py", "windows/Win32/Lib/ctypes/util.py", "windows/Win32/Lib/ctypes/wintypes.py", "windows/Win32/Lib/curses/__init__.py", - "windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc", - "windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc", - "windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc", - "windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc", + "windows/Win32/Lib/curses/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/curses/__pycache__/ascii.cpython-38.opt-1.pyc", + "windows/Win32/Lib/curses/__pycache__/has_key.cpython-38.opt-1.pyc", + "windows/Win32/Lib/curses/__pycache__/panel.cpython-38.opt-1.pyc", + "windows/Win32/Lib/curses/__pycache__/textpad.cpython-38.opt-1.pyc", "windows/Win32/Lib/curses/ascii.py", "windows/Win32/Lib/curses/has_key.py", "windows/Win32/Lib/curses/panel.py", "windows/Win32/Lib/curses/textpad.py", "windows/Win32/Lib/dataclasses.py", "windows/Win32/Lib/datetime.py", - "windows/Win32/Lib/dbm/__init__.py", - "windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc", - "windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc", - "windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc", - "windows/Win32/Lib/dbm/dumb.py", - "windows/Win32/Lib/dbm/gnu.py", - "windows/Win32/Lib/dbm/ndbm.py", "windows/Win32/Lib/decimal.py", "windows/Win32/Lib/difflib.py", "windows/Win32/Lib/dis.py", - "windows/Win32/Lib/distutils/README", - "windows/Win32/Lib/distutils/__init__.py", - "windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/_msvccompiler.py", - "windows/Win32/Lib/distutils/archive_util.py", - "windows/Win32/Lib/distutils/bcppcompiler.py", - "windows/Win32/Lib/distutils/ccompiler.py", - "windows/Win32/Lib/distutils/cmd.py", - "windows/Win32/Lib/distutils/command/__init__.py", - "windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/command/bdist.py", - "windows/Win32/Lib/distutils/command/bdist_dumb.py", - "windows/Win32/Lib/distutils/command/bdist_msi.py", - "windows/Win32/Lib/distutils/command/bdist_rpm.py", - "windows/Win32/Lib/distutils/command/bdist_wininst.py", - "windows/Win32/Lib/distutils/command/build.py", - "windows/Win32/Lib/distutils/command/build_clib.py", - "windows/Win32/Lib/distutils/command/build_ext.py", - "windows/Win32/Lib/distutils/command/build_py.py", - "windows/Win32/Lib/distutils/command/build_scripts.py", - "windows/Win32/Lib/distutils/command/check.py", - "windows/Win32/Lib/distutils/command/clean.py", - "windows/Win32/Lib/distutils/command/command_template", - "windows/Win32/Lib/distutils/command/config.py", - "windows/Win32/Lib/distutils/command/install.py", - "windows/Win32/Lib/distutils/command/install_data.py", - "windows/Win32/Lib/distutils/command/install_egg_info.py", - "windows/Win32/Lib/distutils/command/install_headers.py", - "windows/Win32/Lib/distutils/command/install_lib.py", - "windows/Win32/Lib/distutils/command/install_scripts.py", - "windows/Win32/Lib/distutils/command/register.py", - "windows/Win32/Lib/distutils/command/sdist.py", - "windows/Win32/Lib/distutils/command/upload.py", - "windows/Win32/Lib/distutils/config.py", - "windows/Win32/Lib/distutils/core.py", - "windows/Win32/Lib/distutils/cygwinccompiler.py", - "windows/Win32/Lib/distutils/debug.py", - "windows/Win32/Lib/distutils/dep_util.py", - "windows/Win32/Lib/distutils/dir_util.py", - "windows/Win32/Lib/distutils/dist.py", - "windows/Win32/Lib/distutils/errors.py", - "windows/Win32/Lib/distutils/extension.py", - "windows/Win32/Lib/distutils/fancy_getopt.py", - "windows/Win32/Lib/distutils/file_util.py", - "windows/Win32/Lib/distutils/filelist.py", - "windows/Win32/Lib/distutils/log.py", - "windows/Win32/Lib/distutils/msvc9compiler.py", - "windows/Win32/Lib/distutils/msvccompiler.py", - "windows/Win32/Lib/distutils/spawn.py", - "windows/Win32/Lib/distutils/sysconfig.py", - "windows/Win32/Lib/distutils/tests/Setup.sample", - "windows/Win32/Lib/distutils/tests/__init__.py", - "windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc", - "windows/Win32/Lib/distutils/tests/includetest.rst", - "windows/Win32/Lib/distutils/tests/support.py", - "windows/Win32/Lib/distutils/tests/test_archive_util.py", - "windows/Win32/Lib/distutils/tests/test_bdist.py", - "windows/Win32/Lib/distutils/tests/test_bdist_dumb.py", - "windows/Win32/Lib/distutils/tests/test_bdist_msi.py", - "windows/Win32/Lib/distutils/tests/test_bdist_rpm.py", - "windows/Win32/Lib/distutils/tests/test_bdist_wininst.py", - "windows/Win32/Lib/distutils/tests/test_build.py", - "windows/Win32/Lib/distutils/tests/test_build_clib.py", - "windows/Win32/Lib/distutils/tests/test_build_ext.py", - "windows/Win32/Lib/distutils/tests/test_build_py.py", - "windows/Win32/Lib/distutils/tests/test_build_scripts.py", - "windows/Win32/Lib/distutils/tests/test_check.py", - "windows/Win32/Lib/distutils/tests/test_clean.py", - "windows/Win32/Lib/distutils/tests/test_cmd.py", - "windows/Win32/Lib/distutils/tests/test_config.py", - "windows/Win32/Lib/distutils/tests/test_config_cmd.py", - "windows/Win32/Lib/distutils/tests/test_core.py", - "windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py", - "windows/Win32/Lib/distutils/tests/test_dep_util.py", - "windows/Win32/Lib/distutils/tests/test_dir_util.py", - "windows/Win32/Lib/distutils/tests/test_dist.py", - "windows/Win32/Lib/distutils/tests/test_extension.py", - "windows/Win32/Lib/distutils/tests/test_file_util.py", - "windows/Win32/Lib/distutils/tests/test_filelist.py", - "windows/Win32/Lib/distutils/tests/test_install.py", - "windows/Win32/Lib/distutils/tests/test_install_data.py", - "windows/Win32/Lib/distutils/tests/test_install_headers.py", - "windows/Win32/Lib/distutils/tests/test_install_lib.py", - "windows/Win32/Lib/distutils/tests/test_install_scripts.py", - "windows/Win32/Lib/distutils/tests/test_log.py", - "windows/Win32/Lib/distutils/tests/test_msvc9compiler.py", - "windows/Win32/Lib/distutils/tests/test_msvccompiler.py", - "windows/Win32/Lib/distutils/tests/test_register.py", - "windows/Win32/Lib/distutils/tests/test_sdist.py", - "windows/Win32/Lib/distutils/tests/test_spawn.py", - "windows/Win32/Lib/distutils/tests/test_sysconfig.py", - "windows/Win32/Lib/distutils/tests/test_text_file.py", - "windows/Win32/Lib/distutils/tests/test_unixccompiler.py", - "windows/Win32/Lib/distutils/tests/test_upload.py", - "windows/Win32/Lib/distutils/tests/test_util.py", - "windows/Win32/Lib/distutils/tests/test_version.py", - "windows/Win32/Lib/distutils/tests/test_versionpredicate.py", - "windows/Win32/Lib/distutils/text_file.py", - "windows/Win32/Lib/distutils/unixccompiler.py", - "windows/Win32/Lib/distutils/util.py", - "windows/Win32/Lib/distutils/version.py", - "windows/Win32/Lib/distutils/versionpredicate.py", "windows/Win32/Lib/doctest.py", "windows/Win32/Lib/dummy_threading.py", "windows/Win32/Lib/email/__init__.py", - "windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/_policybase.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/base64mime.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/charset.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/contentmanager.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/encoders.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/errors.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/feedparser.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/generator.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/header.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/headerregistry.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/iterators.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/message.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/parser.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/policy.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/quoprimime.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/__pycache__/utils.cpython-38.opt-1.pyc", "windows/Win32/Lib/email/_encoded_words.py", "windows/Win32/Lib/email/_header_value_parser.py", "windows/Win32/Lib/email/_parseaddr.py", @@ -4970,15 +4714,15 @@ "windows/Win32/Lib/email/iterators.py", "windows/Win32/Lib/email/message.py", "windows/Win32/Lib/email/mime/__init__.py", - "windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc", - "windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/application.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/audio.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/base.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/image.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/message.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc", + "windows/Win32/Lib/email/mime/__pycache__/text.cpython-38.opt-1.pyc", "windows/Win32/Lib/email/mime/application.py", "windows/Win32/Lib/email/mime/audio.py", "windows/Win32/Lib/email/mime/base.py", @@ -4992,131 +4736,129 @@ "windows/Win32/Lib/email/quoprimime.py", "windows/Win32/Lib/email/utils.py", "windows/Win32/Lib/encodings/__init__.py", - "windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc", - "windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/aliases.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/ascii.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/big5.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/charmap.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp037.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp273.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp424.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp437.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp500.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp720.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp737.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp775.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp850.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp852.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp855.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp856.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp857.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp858.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp860.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp861.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp862.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp863.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp864.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp865.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp866.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp869.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp874.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp875.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp932.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp949.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/cp950.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/gbk.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/hz.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/idna.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/johab.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/oem.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/palmos.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/punycode.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/undefined.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc", + "windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc", "windows/Win32/Lib/encodings/aliases.py", "windows/Win32/Lib/encodings/ascii.py", "windows/Win32/Lib/encodings/base64_codec.py", @@ -5142,7 +4884,6 @@ "windows/Win32/Lib/encodings/cp424.py", "windows/Win32/Lib/encodings/cp437.py", "windows/Win32/Lib/encodings/cp500.py", - "windows/Win32/Lib/encodings/cp65001.py", "windows/Win32/Lib/encodings/cp720.py", "windows/Win32/Lib/encodings/cp737.py", "windows/Win32/Lib/encodings/cp775.py", @@ -5229,7 +4970,6 @@ "windows/Win32/Lib/encodings/tis_620.py", "windows/Win32/Lib/encodings/undefined.py", "windows/Win32/Lib/encodings/unicode_escape.py", - "windows/Win32/Lib/encodings/unicode_internal.py", "windows/Win32/Lib/encodings/utf_16.py", "windows/Win32/Lib/encodings/utf_16_be.py", "windows/Win32/Lib/encodings/utf_16_le.py", @@ -5241,14 +4981,6 @@ "windows/Win32/Lib/encodings/utf_8_sig.py", "windows/Win32/Lib/encodings/uu_codec.py", "windows/Win32/Lib/encodings/zlib_codec.py", - "windows/Win32/Lib/ensurepip/__init__.py", - "windows/Win32/Lib/ensurepip/__main__.py", - "windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc", - "windows/Win32/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl", - "windows/Win32/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl", - "windows/Win32/Lib/ensurepip/_uninstall.py", "windows/Win32/Lib/enum.py", "windows/Win32/Lib/filecmp.py", "windows/Win32/Lib/fileinput.py", @@ -5267,47 +4999,48 @@ "windows/Win32/Lib/heapq.py", "windows/Win32/Lib/hmac.py", "windows/Win32/Lib/html/__init__.py", - "windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc", - "windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc", + "windows/Win32/Lib/html/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/html/__pycache__/entities.cpython-38.opt-1.pyc", + "windows/Win32/Lib/html/__pycache__/parser.cpython-38.opt-1.pyc", "windows/Win32/Lib/html/entities.py", "windows/Win32/Lib/html/parser.py", "windows/Win32/Lib/http/__init__.py", - "windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc", - "windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc", - "windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc", - "windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc", + "windows/Win32/Lib/http/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/http/__pycache__/client.cpython-38.opt-1.pyc", + "windows/Win32/Lib/http/__pycache__/cookiejar.cpython-38.opt-1.pyc", + "windows/Win32/Lib/http/__pycache__/cookies.cpython-38.opt-1.pyc", + "windows/Win32/Lib/http/__pycache__/server.cpython-38.opt-1.pyc", "windows/Win32/Lib/http/client.py", "windows/Win32/Lib/http/cookiejar.py", "windows/Win32/Lib/http/cookies.py", "windows/Win32/Lib/http/server.py", - "windows/Win32/Lib/imaplib.py", "windows/Win32/Lib/imghdr.py", "windows/Win32/Lib/imp.py", "windows/Win32/Lib/importlib/__init__.py", - "windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc", - "windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc", - "windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc", - "windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc", - "windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc", - "windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/abc.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/machinery.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/metadata.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/resources.cpython-38.opt-1.pyc", + "windows/Win32/Lib/importlib/__pycache__/util.cpython-38.opt-1.pyc", "windows/Win32/Lib/importlib/_bootstrap.py", "windows/Win32/Lib/importlib/_bootstrap_external.py", "windows/Win32/Lib/importlib/abc.py", "windows/Win32/Lib/importlib/machinery.py", + "windows/Win32/Lib/importlib/metadata.py", "windows/Win32/Lib/importlib/resources.py", "windows/Win32/Lib/importlib/util.py", "windows/Win32/Lib/inspect.py", "windows/Win32/Lib/io.py", "windows/Win32/Lib/ipaddress.py", "windows/Win32/Lib/json/__init__.py", - "windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc", - "windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc", - "windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc", - "windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc", + "windows/Win32/Lib/json/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/json/__pycache__/decoder.cpython-38.opt-1.pyc", + "windows/Win32/Lib/json/__pycache__/encoder.cpython-38.opt-1.pyc", + "windows/Win32/Lib/json/__pycache__/scanner.cpython-38.opt-1.pyc", + "windows/Win32/Lib/json/__pycache__/tool.cpython-38.opt-1.pyc", "windows/Win32/Lib/json/decoder.py", "windows/Win32/Lib/json/encoder.py", "windows/Win32/Lib/json/scanner.py", @@ -5316,69 +5049,24 @@ "windows/Win32/Lib/linecache.py", "windows/Win32/Lib/locale.py", "windows/Win32/Lib/logging/__init__.py", - "windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc", - "windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc", + "windows/Win32/Lib/logging/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/logging/__pycache__/config.cpython-38.opt-1.pyc", + "windows/Win32/Lib/logging/__pycache__/handlers.cpython-38.opt-1.pyc", "windows/Win32/Lib/logging/config.py", "windows/Win32/Lib/logging/handlers.py", "windows/Win32/Lib/lzma.py", - "windows/Win32/Lib/macpath.py", "windows/Win32/Lib/mailbox.py", "windows/Win32/Lib/mailcap.py", "windows/Win32/Lib/mimetypes.py", "windows/Win32/Lib/modulefinder.py", "windows/Win32/Lib/msilib/__init__.py", - "windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc", - "windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc", - "windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc", + "windows/Win32/Lib/msilib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/msilib/__pycache__/schema.cpython-38.opt-1.pyc", + "windows/Win32/Lib/msilib/__pycache__/sequence.cpython-38.opt-1.pyc", + "windows/Win32/Lib/msilib/__pycache__/text.cpython-38.opt-1.pyc", "windows/Win32/Lib/msilib/schema.py", "windows/Win32/Lib/msilib/sequence.py", "windows/Win32/Lib/msilib/text.py", - "windows/Win32/Lib/multiprocessing/__init__.py", - "windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/connection.py", - "windows/Win32/Lib/multiprocessing/context.py", - "windows/Win32/Lib/multiprocessing/dummy/__init__.py", - "windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc", - "windows/Win32/Lib/multiprocessing/dummy/connection.py", - "windows/Win32/Lib/multiprocessing/forkserver.py", - "windows/Win32/Lib/multiprocessing/heap.py", - "windows/Win32/Lib/multiprocessing/managers.py", - "windows/Win32/Lib/multiprocessing/pool.py", - "windows/Win32/Lib/multiprocessing/popen_fork.py", - "windows/Win32/Lib/multiprocessing/popen_forkserver.py", - "windows/Win32/Lib/multiprocessing/popen_spawn_posix.py", - "windows/Win32/Lib/multiprocessing/popen_spawn_win32.py", - "windows/Win32/Lib/multiprocessing/process.py", - "windows/Win32/Lib/multiprocessing/queues.py", - "windows/Win32/Lib/multiprocessing/reduction.py", - "windows/Win32/Lib/multiprocessing/resource_sharer.py", - "windows/Win32/Lib/multiprocessing/semaphore_tracker.py", - "windows/Win32/Lib/multiprocessing/sharedctypes.py", - "windows/Win32/Lib/multiprocessing/spawn.py", - "windows/Win32/Lib/multiprocessing/synchronize.py", - "windows/Win32/Lib/multiprocessing/util.py", "windows/Win32/Lib/netrc.py", "windows/Win32/Lib/nntplib.py", "windows/Win32/Lib/ntpath.py", @@ -5405,11 +5093,6 @@ "windows/Win32/Lib/py_compile.py", "windows/Win32/Lib/pyclbr.py", "windows/Win32/Lib/pydoc.py", - "windows/Win32/Lib/pydoc_data/__init__.py", - "windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc", - "windows/Win32/Lib/pydoc_data/_pydoc.css", - "windows/Win32/Lib/pydoc_data/topics.py", "windows/Win32/Lib/queue.py", "windows/Win32/Lib/quopri.py", "windows/Win32/Lib/random.py", @@ -5424,7 +5107,6 @@ "windows/Win32/Lib/shlex.py", "windows/Win32/Lib/shutil.py", "windows/Win32/Lib/signal.py", - "windows/Win32/Lib/site-packages/README.txt", "windows/Win32/Lib/site.py", "windows/Win32/Lib/smtpd.py", "windows/Win32/Lib/smtplib.py", @@ -5432,31 +5114,11 @@ "windows/Win32/Lib/socket.py", "windows/Win32/Lib/socketserver.py", "windows/Win32/Lib/sqlite3/__init__.py", - "windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc", + "windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc", + "windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc", "windows/Win32/Lib/sqlite3/dbapi2.py", "windows/Win32/Lib/sqlite3/dump.py", - "windows/Win32/Lib/sqlite3/test/__init__.py", - "windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/sqlite3/test/backup.py", - "windows/Win32/Lib/sqlite3/test/dbapi.py", - "windows/Win32/Lib/sqlite3/test/dump.py", - "windows/Win32/Lib/sqlite3/test/factory.py", - "windows/Win32/Lib/sqlite3/test/hooks.py", - "windows/Win32/Lib/sqlite3/test/regression.py", - "windows/Win32/Lib/sqlite3/test/transactions.py", - "windows/Win32/Lib/sqlite3/test/types.py", - "windows/Win32/Lib/sqlite3/test/userfunctions.py", "windows/Win32/Lib/sre_compile.py", "windows/Win32/Lib/sre_constants.py", "windows/Win32/Lib/sre_parse.py", @@ -5485,94 +5147,15 @@ "windows/Win32/Lib/traceback.py", "windows/Win32/Lib/tracemalloc.py", "windows/Win32/Lib/tty.py", - "windows/Win32/Lib/turtle.py", "windows/Win32/Lib/types.py", "windows/Win32/Lib/typing.py", - "windows/Win32/Lib/unittest/__init__.py", - "windows/Win32/Lib/unittest/__main__.py", - "windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/case.py", - "windows/Win32/Lib/unittest/loader.py", - "windows/Win32/Lib/unittest/main.py", - "windows/Win32/Lib/unittest/mock.py", - "windows/Win32/Lib/unittest/result.py", - "windows/Win32/Lib/unittest/runner.py", - "windows/Win32/Lib/unittest/signals.py", - "windows/Win32/Lib/unittest/suite.py", - "windows/Win32/Lib/unittest/test/__init__.py", - "windows/Win32/Lib/unittest/test/__main__.py", - "windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/_test_warnings.py", - "windows/Win32/Lib/unittest/test/dummy.py", - "windows/Win32/Lib/unittest/test/support.py", - "windows/Win32/Lib/unittest/test/test_assertions.py", - "windows/Win32/Lib/unittest/test/test_break.py", - "windows/Win32/Lib/unittest/test/test_case.py", - "windows/Win32/Lib/unittest/test/test_discovery.py", - "windows/Win32/Lib/unittest/test/test_functiontestcase.py", - "windows/Win32/Lib/unittest/test/test_loader.py", - "windows/Win32/Lib/unittest/test/test_program.py", - "windows/Win32/Lib/unittest/test/test_result.py", - "windows/Win32/Lib/unittest/test/test_runner.py", - "windows/Win32/Lib/unittest/test/test_setups.py", - "windows/Win32/Lib/unittest/test/test_skipping.py", - "windows/Win32/Lib/unittest/test/test_suite.py", - "windows/Win32/Lib/unittest/test/testmock/__init__.py", - "windows/Win32/Lib/unittest/test/testmock/__main__.py", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc", - "windows/Win32/Lib/unittest/test/testmock/support.py", - "windows/Win32/Lib/unittest/test/testmock/testcallable.py", - "windows/Win32/Lib/unittest/test/testmock/testhelpers.py", - "windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py", - "windows/Win32/Lib/unittest/test/testmock/testmock.py", - "windows/Win32/Lib/unittest/test/testmock/testpatch.py", - "windows/Win32/Lib/unittest/test/testmock/testsealable.py", - "windows/Win32/Lib/unittest/test/testmock/testsentinel.py", - "windows/Win32/Lib/unittest/test/testmock/testwith.py", - "windows/Win32/Lib/unittest/util.py", "windows/Win32/Lib/urllib/__init__.py", - "windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc", - "windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc", - "windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc", - "windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc", - "windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc", + "windows/Win32/Lib/urllib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/urllib/__pycache__/error.cpython-38.opt-1.pyc", + "windows/Win32/Lib/urllib/__pycache__/parse.cpython-38.opt-1.pyc", + "windows/Win32/Lib/urllib/__pycache__/request.cpython-38.opt-1.pyc", + "windows/Win32/Lib/urllib/__pycache__/response.cpython-38.opt-1.pyc", + "windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc", "windows/Win32/Lib/urllib/error.py", "windows/Win32/Lib/urllib/parse.py", "windows/Win32/Lib/urllib/request.py", @@ -5580,47 +5163,23 @@ "windows/Win32/Lib/urllib/robotparser.py", "windows/Win32/Lib/uu.py", "windows/Win32/Lib/uuid.py", - "windows/Win32/Lib/venv/__init__.py", - "windows/Win32/Lib/venv/__main__.py", - "windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/venv/scripts/common/activate", - "windows/Win32/Lib/venv/scripts/nt/Activate.ps1", - "windows/Win32/Lib/venv/scripts/nt/activate.bat", - "windows/Win32/Lib/venv/scripts/nt/deactivate.bat", - "windows/Win32/Lib/venv/scripts/nt/python.exe", - "windows/Win32/Lib/venv/scripts/nt/pythonw.exe", - "windows/Win32/Lib/venv/scripts/posix/activate.csh", - "windows/Win32/Lib/venv/scripts/posix/activate.fish", "windows/Win32/Lib/warnings.py", "windows/Win32/Lib/wave.py", "windows/Win32/Lib/weakref.py", "windows/Win32/Lib/webbrowser.py", - "windows/Win32/Lib/wsgiref/__init__.py", - "windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc", - "windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc", - "windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc", - "windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc", - "windows/Win32/Lib/wsgiref/handlers.py", - "windows/Win32/Lib/wsgiref/headers.py", - "windows/Win32/Lib/wsgiref/simple_server.py", - "windows/Win32/Lib/wsgiref/util.py", - "windows/Win32/Lib/wsgiref/validate.py", "windows/Win32/Lib/xdrlib.py", "windows/Win32/Lib/xml/__init__.py", - "windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc", + "windows/Win32/Lib/xml/__pycache__/__init__.cpython-38.opt-1.pyc", "windows/Win32/Lib/xml/dom/NodeFilter.py", "windows/Win32/Lib/xml/dom/__init__.py", - "windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc", "windows/Win32/Lib/xml/dom/domreg.py", "windows/Win32/Lib/xml/dom/expatbuilder.py", "windows/Win32/Lib/xml/dom/minicompat.py", @@ -5631,36 +5190,37 @@ "windows/Win32/Lib/xml/etree/ElementPath.py", "windows/Win32/Lib/xml/etree/ElementTree.py", "windows/Win32/Lib/xml/etree/__init__.py", - "windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc", + "windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc", "windows/Win32/Lib/xml/etree/cElementTree.py", "windows/Win32/Lib/xml/parsers/__init__.py", - "windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc", + "windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc", "windows/Win32/Lib/xml/parsers/expat.py", "windows/Win32/Lib/xml/sax/__init__.py", - "windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc", + "windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc", "windows/Win32/Lib/xml/sax/_exceptions.py", "windows/Win32/Lib/xml/sax/expatreader.py", "windows/Win32/Lib/xml/sax/handler.py", "windows/Win32/Lib/xml/sax/saxutils.py", "windows/Win32/Lib/xml/sax/xmlreader.py", "windows/Win32/Lib/xmlrpc/__init__.py", - "windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc", - "windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc", + "windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc", + "windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc", "windows/Win32/Lib/xmlrpc/client.py", "windows/Win32/Lib/xmlrpc/server.py", "windows/Win32/Lib/zipapp.py", "windows/Win32/Lib/zipfile.py", + "windows/Win32/Lib/zipimport.py", "windows/Win32/OpenAL32.dll", "windows/Win32/SDL2.dll", "windows/Win32/libvorbis.dll", @@ -5668,209 +5228,244 @@ "windows/Win32/msvcp140d.dll", "windows/Win32/ogg.dll", "windows/Win32/python.exe", - "windows/Win32/python37.dll", + "windows/Win32/python38.dll", + "windows/Win32/python38_d.dll", + "windows/Win32/python_d.exe", "windows/Win32/pythonw.exe", + "windows/Win32/pythonw_d.exe", "windows/Win32/vc_redist.x86.exe", "windows/Win32/vcruntime140d.dll", "windows/x64/DLLs/_asyncio.pyd", + "windows/x64/DLLs/_asyncio_d.pyd", "windows/x64/DLLs/_bz2.pyd", + "windows/x64/DLLs/_bz2_d.pyd", "windows/x64/DLLs/_ctypes.pyd", + "windows/x64/DLLs/_ctypes_d.pyd", + "windows/x64/DLLs/_ctypes_test.pyd", + "windows/x64/DLLs/_ctypes_test_d.pyd", "windows/x64/DLLs/_decimal.pyd", + "windows/x64/DLLs/_decimal_d.pyd", "windows/x64/DLLs/_elementtree.pyd", + "windows/x64/DLLs/_elementtree_d.pyd", "windows/x64/DLLs/_hashlib.pyd", + "windows/x64/DLLs/_hashlib_d.pyd", "windows/x64/DLLs/_lzma.pyd", + "windows/x64/DLLs/_lzma_d.pyd", "windows/x64/DLLs/_msi.pyd", + "windows/x64/DLLs/_msi_d.pyd", "windows/x64/DLLs/_multiprocessing.pyd", + "windows/x64/DLLs/_multiprocessing_d.pyd", "windows/x64/DLLs/_overlapped.pyd", + "windows/x64/DLLs/_overlapped_d.pyd", "windows/x64/DLLs/_queue.pyd", + "windows/x64/DLLs/_queue_d.pyd", "windows/x64/DLLs/_socket.pyd", + "windows/x64/DLLs/_socket_d.pyd", "windows/x64/DLLs/_sqlite3.pyd", + "windows/x64/DLLs/_sqlite3_d.pyd", "windows/x64/DLLs/_ssl.pyd", + "windows/x64/DLLs/_ssl_d.pyd", + "windows/x64/DLLs/_testbuffer.pyd", + "windows/x64/DLLs/_testbuffer_d.pyd", + "windows/x64/DLLs/_testcapi.pyd", + "windows/x64/DLLs/_testcapi_d.pyd", + "windows/x64/DLLs/_testconsole.pyd", + "windows/x64/DLLs/_testconsole_d.pyd", + "windows/x64/DLLs/_testimportmultiple.pyd", + "windows/x64/DLLs/_testimportmultiple_d.pyd", + "windows/x64/DLLs/_testmultiphase.pyd", + "windows/x64/DLLs/_testmultiphase_d.pyd", + "windows/x64/DLLs/_tkinter.pyd", + "windows/x64/DLLs/_tkinter_d.lib", + "windows/x64/DLLs/_tkinter_d.pyd", "windows/x64/DLLs/libcrypto-1_1.dll", + "windows/x64/DLLs/libffi-7.dll", "windows/x64/DLLs/libssl-1_1.dll", - "windows/x64/DLLs/py.ico", - "windows/x64/DLLs/pyc.ico", - "windows/x64/DLLs/pyd.ico", "windows/x64/DLLs/pyexpat.pyd", + "windows/x64/DLLs/pyexpat_d.pyd", "windows/x64/DLLs/python_lib.cat", "windows/x64/DLLs/python_tools.cat", "windows/x64/DLLs/select.pyd", + "windows/x64/DLLs/select_d.pyd", "windows/x64/DLLs/sqlite3.dll", + "windows/x64/DLLs/sqlite3_d.dll", + "windows/x64/DLLs/tcl86t.dll", + "windows/x64/DLLs/tk86t.dll", "windows/x64/DLLs/unicodedata.pyd", + "windows/x64/DLLs/unicodedata_d.pyd", "windows/x64/DLLs/winsound.pyd", + "windows/x64/DLLs/winsound_d.pyd", "windows/x64/Lib/__future__.py", "windows/x64/Lib/__phello__.foo.py", - "windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc", - "windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc", + "windows/x64/Lib/__pycache__/__future__.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/__phello__.foo.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_bootlocale.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_collections_abc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_compat_pickle.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_compression.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_dummy_thread.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_markupbase.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_osx_support.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_py_abc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_pydecimal.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_pyio.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_strptime.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_threading_local.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/_weakrefset.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/abc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/aifc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/antigravity.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/argparse.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/ast.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/asynchat.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/asyncore.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/base64.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/bdb.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/binhex.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/bisect.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/bz2.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/cProfile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/calendar.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/cgi.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/cgitb.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/chunk.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/cmd.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/code.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/codecs.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/codeop.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/colorsys.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/compileall.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/configparser.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/contextlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/contextvars.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/copy.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/copyreg.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/crypt.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/csv.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/dataclasses.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/datetime.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/decimal.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/difflib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/dis.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/doctest.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/dummy_threading.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/enum.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/filecmp.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/fileinput.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/fnmatch.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/formatter.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/fractions.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/ftplib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/functools.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/genericpath.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/getopt.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/getpass.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/gettext.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/glob.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/gzip.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/hashlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/heapq.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/hmac.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/imghdr.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/imp.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/inspect.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/io.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/ipaddress.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/keyword.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/linecache.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/locale.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/lzma.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/mailbox.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/mailcap.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/mimetypes.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/modulefinder.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/netrc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/nntplib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/ntpath.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/nturl2path.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/numbers.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/opcode.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/operator.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/optparse.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/os.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pathlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pdb.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pickle.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pickletools.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pipes.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pkgutil.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/platform.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/plistlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/poplib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/posixpath.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pprint.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/profile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pstats.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pty.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/py_compile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pyclbr.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/pydoc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/queue.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/quopri.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/random.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/re.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/reprlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/rlcompleter.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/runpy.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sched.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/secrets.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/selectors.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/shelve.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/shlex.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/shutil.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/signal.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/site.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/smtpd.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/smtplib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sndhdr.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/socket.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/socketserver.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sre_compile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sre_constants.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sre_parse.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/ssl.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/stat.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/statistics.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/string.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/stringprep.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/struct.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/subprocess.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sunau.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/symbol.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/symtable.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/sysconfig.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/tabnanny.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/tarfile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/telnetlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/tempfile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/textwrap.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/this.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/threading.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/timeit.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/token.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/tokenize.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/trace.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/traceback.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/tracemalloc.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/tty.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/types.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/typing.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/uu.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/uuid.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/warnings.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/wave.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/weakref.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/webbrowser.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/xdrlib.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/zipapp.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/zipfile.cpython-38.opt-1.pyc", + "windows/x64/Lib/__pycache__/zipimport.cpython-38.opt-1.pyc", "windows/x64/Lib/_bootlocale.py", "windows/x64/Lib/_collections_abc.py", "windows/x64/Lib/_compat_pickle.py", @@ -5892,31 +5487,36 @@ "windows/x64/Lib/ast.py", "windows/x64/Lib/asynchat.py", "windows/x64/Lib/asyncio/__init__.py", - "windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc", - "windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc", + "windows/x64/Lib/asyncio/__main__.py", + "windows/x64/Lib/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/constants.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/events.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/futures.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/locks.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/log.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/queues.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/runners.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/streams.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/transports.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc", + "windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc", "windows/x64/Lib/asyncio/base_events.py", "windows/x64/Lib/asyncio/base_futures.py", "windows/x64/Lib/asyncio/base_subprocess.py", @@ -5924,6 +5524,7 @@ "windows/x64/Lib/asyncio/constants.py", "windows/x64/Lib/asyncio/coroutines.py", "windows/x64/Lib/asyncio/events.py", + "windows/x64/Lib/asyncio/exceptions.py", "windows/x64/Lib/asyncio/format_helpers.py", "windows/x64/Lib/asyncio/futures.py", "windows/x64/Lib/asyncio/locks.py", @@ -5934,10 +5535,12 @@ "windows/x64/Lib/asyncio/runners.py", "windows/x64/Lib/asyncio/selector_events.py", "windows/x64/Lib/asyncio/sslproto.py", + "windows/x64/Lib/asyncio/staggered.py", "windows/x64/Lib/asyncio/streams.py", "windows/x64/Lib/asyncio/subprocess.py", "windows/x64/Lib/asyncio/tasks.py", "windows/x64/Lib/asyncio/transports.py", + "windows/x64/Lib/asyncio/trsock.py", "windows/x64/Lib/asyncio/unix_events.py", "windows/x64/Lib/asyncio/windows_events.py", "windows/x64/Lib/asyncio/windows_utils.py", @@ -5957,18 +5560,18 @@ "windows/x64/Lib/codecs.py", "windows/x64/Lib/codeop.py", "windows/x64/Lib/collections/__init__.py", - "windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc", + "windows/x64/Lib/collections/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/collections/__pycache__/abc.cpython-38.opt-1.pyc", "windows/x64/Lib/collections/abc.py", "windows/x64/Lib/colorsys.py", "windows/x64/Lib/compileall.py", "windows/x64/Lib/concurrent/__init__.py", - "windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc", + "windows/x64/Lib/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc", "windows/x64/Lib/concurrent/futures/__init__.py", - "windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc", - "windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc", - "windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc", + "windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc", + "windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc", + "windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc", "windows/x64/Lib/concurrent/futures/_base.py", "windows/x64/Lib/concurrent/futures/process.py", "windows/x64/Lib/concurrent/futures/thread.py", @@ -5980,372 +5583,64 @@ "windows/x64/Lib/crypt.py", "windows/x64/Lib/csv.py", "windows/x64/Lib/ctypes/__init__.py", - "windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc", + "windows/x64/Lib/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/__pycache__/util.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc", "windows/x64/Lib/ctypes/_aix.py", "windows/x64/Lib/ctypes/_endian.py", "windows/x64/Lib/ctypes/macholib/README.ctypes", "windows/x64/Lib/ctypes/macholib/__init__.py", - "windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc", + "windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc", + "windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc", "windows/x64/Lib/ctypes/macholib/dyld.py", "windows/x64/Lib/ctypes/macholib/dylib.py", "windows/x64/Lib/ctypes/macholib/fetch_macholib", "windows/x64/Lib/ctypes/macholib/fetch_macholib.bat", "windows/x64/Lib/ctypes/macholib/framework.py", - "windows/x64/Lib/ctypes/test/__init__.py", - "windows/x64/Lib/ctypes/test/__main__.py", - "windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc", - "windows/x64/Lib/ctypes/test/test_anon.py", - "windows/x64/Lib/ctypes/test/test_array_in_pointer.py", - "windows/x64/Lib/ctypes/test/test_arrays.py", - "windows/x64/Lib/ctypes/test/test_as_parameter.py", - "windows/x64/Lib/ctypes/test/test_bitfields.py", - "windows/x64/Lib/ctypes/test/test_buffers.py", - "windows/x64/Lib/ctypes/test/test_bytes.py", - "windows/x64/Lib/ctypes/test/test_byteswap.py", - "windows/x64/Lib/ctypes/test/test_callbacks.py", - "windows/x64/Lib/ctypes/test/test_cast.py", - "windows/x64/Lib/ctypes/test/test_cfuncs.py", - "windows/x64/Lib/ctypes/test/test_checkretval.py", - "windows/x64/Lib/ctypes/test/test_delattr.py", - "windows/x64/Lib/ctypes/test/test_errno.py", - "windows/x64/Lib/ctypes/test/test_find.py", - "windows/x64/Lib/ctypes/test/test_frombuffer.py", - "windows/x64/Lib/ctypes/test/test_funcptr.py", - "windows/x64/Lib/ctypes/test/test_functions.py", - "windows/x64/Lib/ctypes/test/test_incomplete.py", - "windows/x64/Lib/ctypes/test/test_init.py", - "windows/x64/Lib/ctypes/test/test_internals.py", - "windows/x64/Lib/ctypes/test/test_keeprefs.py", - "windows/x64/Lib/ctypes/test/test_libc.py", - "windows/x64/Lib/ctypes/test/test_loading.py", - "windows/x64/Lib/ctypes/test/test_macholib.py", - "windows/x64/Lib/ctypes/test/test_memfunctions.py", - "windows/x64/Lib/ctypes/test/test_numbers.py", - "windows/x64/Lib/ctypes/test/test_objects.py", - "windows/x64/Lib/ctypes/test/test_parameters.py", - "windows/x64/Lib/ctypes/test/test_pep3118.py", - "windows/x64/Lib/ctypes/test/test_pickling.py", - "windows/x64/Lib/ctypes/test/test_pointers.py", - "windows/x64/Lib/ctypes/test/test_prototypes.py", - "windows/x64/Lib/ctypes/test/test_python_api.py", - "windows/x64/Lib/ctypes/test/test_random_things.py", - "windows/x64/Lib/ctypes/test/test_refcounts.py", - "windows/x64/Lib/ctypes/test/test_repr.py", - "windows/x64/Lib/ctypes/test/test_returnfuncptrs.py", - "windows/x64/Lib/ctypes/test/test_simplesubclasses.py", - "windows/x64/Lib/ctypes/test/test_sizes.py", - "windows/x64/Lib/ctypes/test/test_slicing.py", - "windows/x64/Lib/ctypes/test/test_stringptr.py", - "windows/x64/Lib/ctypes/test/test_strings.py", - "windows/x64/Lib/ctypes/test/test_struct_fields.py", - "windows/x64/Lib/ctypes/test/test_structures.py", - "windows/x64/Lib/ctypes/test/test_unaligned_structures.py", - "windows/x64/Lib/ctypes/test/test_unicode.py", - "windows/x64/Lib/ctypes/test/test_values.py", - "windows/x64/Lib/ctypes/test/test_varsize_struct.py", - "windows/x64/Lib/ctypes/test/test_win32.py", - "windows/x64/Lib/ctypes/test/test_wintypes.py", "windows/x64/Lib/ctypes/util.py", "windows/x64/Lib/ctypes/wintypes.py", "windows/x64/Lib/curses/__init__.py", - "windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc", - "windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc", - "windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc", - "windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc", + "windows/x64/Lib/curses/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/curses/__pycache__/ascii.cpython-38.opt-1.pyc", + "windows/x64/Lib/curses/__pycache__/has_key.cpython-38.opt-1.pyc", + "windows/x64/Lib/curses/__pycache__/panel.cpython-38.opt-1.pyc", + "windows/x64/Lib/curses/__pycache__/textpad.cpython-38.opt-1.pyc", "windows/x64/Lib/curses/ascii.py", "windows/x64/Lib/curses/has_key.py", "windows/x64/Lib/curses/panel.py", "windows/x64/Lib/curses/textpad.py", "windows/x64/Lib/dataclasses.py", "windows/x64/Lib/datetime.py", - "windows/x64/Lib/dbm/__init__.py", - "windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc", - "windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc", - "windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc", - "windows/x64/Lib/dbm/dumb.py", - "windows/x64/Lib/dbm/gnu.py", - "windows/x64/Lib/dbm/ndbm.py", "windows/x64/Lib/decimal.py", "windows/x64/Lib/difflib.py", "windows/x64/Lib/dis.py", - "windows/x64/Lib/distutils/README", - "windows/x64/Lib/distutils/__init__.py", - "windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/_msvccompiler.py", - "windows/x64/Lib/distutils/archive_util.py", - "windows/x64/Lib/distutils/bcppcompiler.py", - "windows/x64/Lib/distutils/ccompiler.py", - "windows/x64/Lib/distutils/cmd.py", - "windows/x64/Lib/distutils/command/__init__.py", - "windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/command/bdist.py", - "windows/x64/Lib/distutils/command/bdist_dumb.py", - "windows/x64/Lib/distutils/command/bdist_msi.py", - "windows/x64/Lib/distutils/command/bdist_rpm.py", - "windows/x64/Lib/distutils/command/bdist_wininst.py", - "windows/x64/Lib/distutils/command/build.py", - "windows/x64/Lib/distutils/command/build_clib.py", - "windows/x64/Lib/distutils/command/build_ext.py", - "windows/x64/Lib/distutils/command/build_py.py", - "windows/x64/Lib/distutils/command/build_scripts.py", - "windows/x64/Lib/distutils/command/check.py", - "windows/x64/Lib/distutils/command/clean.py", - "windows/x64/Lib/distutils/command/command_template", - "windows/x64/Lib/distutils/command/config.py", - "windows/x64/Lib/distutils/command/install.py", - "windows/x64/Lib/distutils/command/install_data.py", - "windows/x64/Lib/distutils/command/install_egg_info.py", - "windows/x64/Lib/distutils/command/install_headers.py", - "windows/x64/Lib/distutils/command/install_lib.py", - "windows/x64/Lib/distutils/command/install_scripts.py", - "windows/x64/Lib/distutils/command/register.py", - "windows/x64/Lib/distutils/command/sdist.py", - "windows/x64/Lib/distutils/command/upload.py", - "windows/x64/Lib/distutils/config.py", - "windows/x64/Lib/distutils/core.py", - "windows/x64/Lib/distutils/cygwinccompiler.py", - "windows/x64/Lib/distutils/debug.py", - "windows/x64/Lib/distutils/dep_util.py", - "windows/x64/Lib/distutils/dir_util.py", - "windows/x64/Lib/distutils/dist.py", - "windows/x64/Lib/distutils/errors.py", - "windows/x64/Lib/distutils/extension.py", - "windows/x64/Lib/distutils/fancy_getopt.py", - "windows/x64/Lib/distutils/file_util.py", - "windows/x64/Lib/distutils/filelist.py", - "windows/x64/Lib/distutils/log.py", - "windows/x64/Lib/distutils/msvc9compiler.py", - "windows/x64/Lib/distutils/msvccompiler.py", - "windows/x64/Lib/distutils/spawn.py", - "windows/x64/Lib/distutils/sysconfig.py", - "windows/x64/Lib/distutils/tests/Setup.sample", - "windows/x64/Lib/distutils/tests/__init__.py", - "windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc", - "windows/x64/Lib/distutils/tests/includetest.rst", - "windows/x64/Lib/distutils/tests/support.py", - "windows/x64/Lib/distutils/tests/test_archive_util.py", - "windows/x64/Lib/distutils/tests/test_bdist.py", - "windows/x64/Lib/distutils/tests/test_bdist_dumb.py", - "windows/x64/Lib/distutils/tests/test_bdist_msi.py", - "windows/x64/Lib/distutils/tests/test_bdist_rpm.py", - "windows/x64/Lib/distutils/tests/test_bdist_wininst.py", - "windows/x64/Lib/distutils/tests/test_build.py", - "windows/x64/Lib/distutils/tests/test_build_clib.py", - "windows/x64/Lib/distutils/tests/test_build_ext.py", - "windows/x64/Lib/distutils/tests/test_build_py.py", - "windows/x64/Lib/distutils/tests/test_build_scripts.py", - "windows/x64/Lib/distutils/tests/test_check.py", - "windows/x64/Lib/distutils/tests/test_clean.py", - "windows/x64/Lib/distutils/tests/test_cmd.py", - "windows/x64/Lib/distutils/tests/test_config.py", - "windows/x64/Lib/distutils/tests/test_config_cmd.py", - "windows/x64/Lib/distutils/tests/test_core.py", - "windows/x64/Lib/distutils/tests/test_cygwinccompiler.py", - "windows/x64/Lib/distutils/tests/test_dep_util.py", - "windows/x64/Lib/distutils/tests/test_dir_util.py", - "windows/x64/Lib/distutils/tests/test_dist.py", - "windows/x64/Lib/distutils/tests/test_extension.py", - "windows/x64/Lib/distutils/tests/test_file_util.py", - "windows/x64/Lib/distutils/tests/test_filelist.py", - "windows/x64/Lib/distutils/tests/test_install.py", - "windows/x64/Lib/distutils/tests/test_install_data.py", - "windows/x64/Lib/distutils/tests/test_install_headers.py", - "windows/x64/Lib/distutils/tests/test_install_lib.py", - "windows/x64/Lib/distutils/tests/test_install_scripts.py", - "windows/x64/Lib/distutils/tests/test_log.py", - "windows/x64/Lib/distutils/tests/test_msvc9compiler.py", - "windows/x64/Lib/distutils/tests/test_msvccompiler.py", - "windows/x64/Lib/distutils/tests/test_register.py", - "windows/x64/Lib/distutils/tests/test_sdist.py", - "windows/x64/Lib/distutils/tests/test_spawn.py", - "windows/x64/Lib/distutils/tests/test_sysconfig.py", - "windows/x64/Lib/distutils/tests/test_text_file.py", - "windows/x64/Lib/distutils/tests/test_unixccompiler.py", - "windows/x64/Lib/distutils/tests/test_upload.py", - "windows/x64/Lib/distutils/tests/test_util.py", - "windows/x64/Lib/distutils/tests/test_version.py", - "windows/x64/Lib/distutils/tests/test_versionpredicate.py", - "windows/x64/Lib/distutils/text_file.py", - "windows/x64/Lib/distutils/unixccompiler.py", - "windows/x64/Lib/distutils/util.py", - "windows/x64/Lib/distutils/version.py", - "windows/x64/Lib/distutils/versionpredicate.py", "windows/x64/Lib/doctest.py", "windows/x64/Lib/dummy_threading.py", "windows/x64/Lib/email/__init__.py", - "windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/_policybase.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/base64mime.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/charset.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/contentmanager.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/encoders.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/errors.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/feedparser.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/generator.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/header.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/headerregistry.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/iterators.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/message.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/parser.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/policy.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/quoprimime.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/__pycache__/utils.cpython-38.opt-1.pyc", "windows/x64/Lib/email/_encoded_words.py", "windows/x64/Lib/email/_header_value_parser.py", "windows/x64/Lib/email/_parseaddr.py", @@ -6363,15 +5658,15 @@ "windows/x64/Lib/email/iterators.py", "windows/x64/Lib/email/message.py", "windows/x64/Lib/email/mime/__init__.py", - "windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc", - "windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/application.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/audio.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/base.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/image.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/message.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc", + "windows/x64/Lib/email/mime/__pycache__/text.cpython-38.opt-1.pyc", "windows/x64/Lib/email/mime/application.py", "windows/x64/Lib/email/mime/audio.py", "windows/x64/Lib/email/mime/base.py", @@ -6385,131 +5680,129 @@ "windows/x64/Lib/email/quoprimime.py", "windows/x64/Lib/email/utils.py", "windows/x64/Lib/encodings/__init__.py", - "windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc", - "windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/aliases.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/ascii.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/big5.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/charmap.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp037.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp273.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp424.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp437.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp500.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp720.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp737.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp775.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp850.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp852.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp855.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp856.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp857.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp858.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp860.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp861.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp862.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp863.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp864.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp865.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp866.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp869.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp874.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp875.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp932.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp949.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/cp950.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/gbk.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/hz.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/idna.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/johab.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/oem.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/palmos.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/punycode.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/undefined.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc", + "windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc", "windows/x64/Lib/encodings/aliases.py", "windows/x64/Lib/encodings/ascii.py", "windows/x64/Lib/encodings/base64_codec.py", @@ -6535,7 +5828,6 @@ "windows/x64/Lib/encodings/cp424.py", "windows/x64/Lib/encodings/cp437.py", "windows/x64/Lib/encodings/cp500.py", - "windows/x64/Lib/encodings/cp65001.py", "windows/x64/Lib/encodings/cp720.py", "windows/x64/Lib/encodings/cp737.py", "windows/x64/Lib/encodings/cp775.py", @@ -6622,7 +5914,6 @@ "windows/x64/Lib/encodings/tis_620.py", "windows/x64/Lib/encodings/undefined.py", "windows/x64/Lib/encodings/unicode_escape.py", - "windows/x64/Lib/encodings/unicode_internal.py", "windows/x64/Lib/encodings/utf_16.py", "windows/x64/Lib/encodings/utf_16_be.py", "windows/x64/Lib/encodings/utf_16_le.py", @@ -6634,14 +5925,6 @@ "windows/x64/Lib/encodings/utf_8_sig.py", "windows/x64/Lib/encodings/uu_codec.py", "windows/x64/Lib/encodings/zlib_codec.py", - "windows/x64/Lib/ensurepip/__init__.py", - "windows/x64/Lib/ensurepip/__main__.py", - "windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc", - "windows/x64/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl", - "windows/x64/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl", - "windows/x64/Lib/ensurepip/_uninstall.py", "windows/x64/Lib/enum.py", "windows/x64/Lib/filecmp.py", "windows/x64/Lib/fileinput.py", @@ -6660,47 +5943,48 @@ "windows/x64/Lib/heapq.py", "windows/x64/Lib/hmac.py", "windows/x64/Lib/html/__init__.py", - "windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc", - "windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc", + "windows/x64/Lib/html/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/html/__pycache__/entities.cpython-38.opt-1.pyc", + "windows/x64/Lib/html/__pycache__/parser.cpython-38.opt-1.pyc", "windows/x64/Lib/html/entities.py", "windows/x64/Lib/html/parser.py", "windows/x64/Lib/http/__init__.py", - "windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc", - "windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc", - "windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc", - "windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc", + "windows/x64/Lib/http/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/http/__pycache__/client.cpython-38.opt-1.pyc", + "windows/x64/Lib/http/__pycache__/cookiejar.cpython-38.opt-1.pyc", + "windows/x64/Lib/http/__pycache__/cookies.cpython-38.opt-1.pyc", + "windows/x64/Lib/http/__pycache__/server.cpython-38.opt-1.pyc", "windows/x64/Lib/http/client.py", "windows/x64/Lib/http/cookiejar.py", "windows/x64/Lib/http/cookies.py", "windows/x64/Lib/http/server.py", - "windows/x64/Lib/imaplib.py", "windows/x64/Lib/imghdr.py", "windows/x64/Lib/imp.py", "windows/x64/Lib/importlib/__init__.py", - "windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc", - "windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc", - "windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc", - "windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc", - "windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc", - "windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/abc.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/machinery.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/metadata.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/resources.cpython-38.opt-1.pyc", + "windows/x64/Lib/importlib/__pycache__/util.cpython-38.opt-1.pyc", "windows/x64/Lib/importlib/_bootstrap.py", "windows/x64/Lib/importlib/_bootstrap_external.py", "windows/x64/Lib/importlib/abc.py", "windows/x64/Lib/importlib/machinery.py", + "windows/x64/Lib/importlib/metadata.py", "windows/x64/Lib/importlib/resources.py", "windows/x64/Lib/importlib/util.py", "windows/x64/Lib/inspect.py", "windows/x64/Lib/io.py", "windows/x64/Lib/ipaddress.py", "windows/x64/Lib/json/__init__.py", - "windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc", - "windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc", - "windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc", - "windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc", + "windows/x64/Lib/json/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/json/__pycache__/decoder.cpython-38.opt-1.pyc", + "windows/x64/Lib/json/__pycache__/encoder.cpython-38.opt-1.pyc", + "windows/x64/Lib/json/__pycache__/scanner.cpython-38.opt-1.pyc", + "windows/x64/Lib/json/__pycache__/tool.cpython-38.opt-1.pyc", "windows/x64/Lib/json/decoder.py", "windows/x64/Lib/json/encoder.py", "windows/x64/Lib/json/scanner.py", @@ -6709,69 +5993,24 @@ "windows/x64/Lib/linecache.py", "windows/x64/Lib/locale.py", "windows/x64/Lib/logging/__init__.py", - "windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc", - "windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc", + "windows/x64/Lib/logging/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/logging/__pycache__/config.cpython-38.opt-1.pyc", + "windows/x64/Lib/logging/__pycache__/handlers.cpython-38.opt-1.pyc", "windows/x64/Lib/logging/config.py", "windows/x64/Lib/logging/handlers.py", "windows/x64/Lib/lzma.py", - "windows/x64/Lib/macpath.py", "windows/x64/Lib/mailbox.py", "windows/x64/Lib/mailcap.py", "windows/x64/Lib/mimetypes.py", "windows/x64/Lib/modulefinder.py", "windows/x64/Lib/msilib/__init__.py", - "windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc", - "windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc", - "windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc", + "windows/x64/Lib/msilib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/msilib/__pycache__/schema.cpython-38.opt-1.pyc", + "windows/x64/Lib/msilib/__pycache__/sequence.cpython-38.opt-1.pyc", + "windows/x64/Lib/msilib/__pycache__/text.cpython-38.opt-1.pyc", "windows/x64/Lib/msilib/schema.py", "windows/x64/Lib/msilib/sequence.py", "windows/x64/Lib/msilib/text.py", - "windows/x64/Lib/multiprocessing/__init__.py", - "windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/connection.py", - "windows/x64/Lib/multiprocessing/context.py", - "windows/x64/Lib/multiprocessing/dummy/__init__.py", - "windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc", - "windows/x64/Lib/multiprocessing/dummy/connection.py", - "windows/x64/Lib/multiprocessing/forkserver.py", - "windows/x64/Lib/multiprocessing/heap.py", - "windows/x64/Lib/multiprocessing/managers.py", - "windows/x64/Lib/multiprocessing/pool.py", - "windows/x64/Lib/multiprocessing/popen_fork.py", - "windows/x64/Lib/multiprocessing/popen_forkserver.py", - "windows/x64/Lib/multiprocessing/popen_spawn_posix.py", - "windows/x64/Lib/multiprocessing/popen_spawn_win32.py", - "windows/x64/Lib/multiprocessing/process.py", - "windows/x64/Lib/multiprocessing/queues.py", - "windows/x64/Lib/multiprocessing/reduction.py", - "windows/x64/Lib/multiprocessing/resource_sharer.py", - "windows/x64/Lib/multiprocessing/semaphore_tracker.py", - "windows/x64/Lib/multiprocessing/sharedctypes.py", - "windows/x64/Lib/multiprocessing/spawn.py", - "windows/x64/Lib/multiprocessing/synchronize.py", - "windows/x64/Lib/multiprocessing/util.py", "windows/x64/Lib/netrc.py", "windows/x64/Lib/nntplib.py", "windows/x64/Lib/ntpath.py", @@ -6798,11 +6037,6 @@ "windows/x64/Lib/py_compile.py", "windows/x64/Lib/pyclbr.py", "windows/x64/Lib/pydoc.py", - "windows/x64/Lib/pydoc_data/__init__.py", - "windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc", - "windows/x64/Lib/pydoc_data/_pydoc.css", - "windows/x64/Lib/pydoc_data/topics.py", "windows/x64/Lib/queue.py", "windows/x64/Lib/quopri.py", "windows/x64/Lib/random.py", @@ -6817,7 +6051,6 @@ "windows/x64/Lib/shlex.py", "windows/x64/Lib/shutil.py", "windows/x64/Lib/signal.py", - "windows/x64/Lib/site-packages/README.txt", "windows/x64/Lib/site.py", "windows/x64/Lib/smtpd.py", "windows/x64/Lib/smtplib.py", @@ -6825,31 +6058,11 @@ "windows/x64/Lib/socket.py", "windows/x64/Lib/socketserver.py", "windows/x64/Lib/sqlite3/__init__.py", - "windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc", + "windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc", + "windows/x64/Lib/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc", "windows/x64/Lib/sqlite3/dbapi2.py", "windows/x64/Lib/sqlite3/dump.py", - "windows/x64/Lib/sqlite3/test/__init__.py", - "windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc", - "windows/x64/Lib/sqlite3/test/backup.py", - "windows/x64/Lib/sqlite3/test/dbapi.py", - "windows/x64/Lib/sqlite3/test/dump.py", - "windows/x64/Lib/sqlite3/test/factory.py", - "windows/x64/Lib/sqlite3/test/hooks.py", - "windows/x64/Lib/sqlite3/test/regression.py", - "windows/x64/Lib/sqlite3/test/transactions.py", - "windows/x64/Lib/sqlite3/test/types.py", - "windows/x64/Lib/sqlite3/test/userfunctions.py", "windows/x64/Lib/sre_compile.py", "windows/x64/Lib/sre_constants.py", "windows/x64/Lib/sre_parse.py", @@ -6878,94 +6091,15 @@ "windows/x64/Lib/traceback.py", "windows/x64/Lib/tracemalloc.py", "windows/x64/Lib/tty.py", - "windows/x64/Lib/turtle.py", "windows/x64/Lib/types.py", "windows/x64/Lib/typing.py", - "windows/x64/Lib/unittest/__init__.py", - "windows/x64/Lib/unittest/__main__.py", - "windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/case.py", - "windows/x64/Lib/unittest/loader.py", - "windows/x64/Lib/unittest/main.py", - "windows/x64/Lib/unittest/mock.py", - "windows/x64/Lib/unittest/result.py", - "windows/x64/Lib/unittest/runner.py", - "windows/x64/Lib/unittest/signals.py", - "windows/x64/Lib/unittest/suite.py", - "windows/x64/Lib/unittest/test/__init__.py", - "windows/x64/Lib/unittest/test/__main__.py", - "windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/_test_warnings.py", - "windows/x64/Lib/unittest/test/dummy.py", - "windows/x64/Lib/unittest/test/support.py", - "windows/x64/Lib/unittest/test/test_assertions.py", - "windows/x64/Lib/unittest/test/test_break.py", - "windows/x64/Lib/unittest/test/test_case.py", - "windows/x64/Lib/unittest/test/test_discovery.py", - "windows/x64/Lib/unittest/test/test_functiontestcase.py", - "windows/x64/Lib/unittest/test/test_loader.py", - "windows/x64/Lib/unittest/test/test_program.py", - "windows/x64/Lib/unittest/test/test_result.py", - "windows/x64/Lib/unittest/test/test_runner.py", - "windows/x64/Lib/unittest/test/test_setups.py", - "windows/x64/Lib/unittest/test/test_skipping.py", - "windows/x64/Lib/unittest/test/test_suite.py", - "windows/x64/Lib/unittest/test/testmock/__init__.py", - "windows/x64/Lib/unittest/test/testmock/__main__.py", - "windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc", - "windows/x64/Lib/unittest/test/testmock/support.py", - "windows/x64/Lib/unittest/test/testmock/testcallable.py", - "windows/x64/Lib/unittest/test/testmock/testhelpers.py", - "windows/x64/Lib/unittest/test/testmock/testmagicmethods.py", - "windows/x64/Lib/unittest/test/testmock/testmock.py", - "windows/x64/Lib/unittest/test/testmock/testpatch.py", - "windows/x64/Lib/unittest/test/testmock/testsealable.py", - "windows/x64/Lib/unittest/test/testmock/testsentinel.py", - "windows/x64/Lib/unittest/test/testmock/testwith.py", - "windows/x64/Lib/unittest/util.py", "windows/x64/Lib/urllib/__init__.py", - "windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc", - "windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc", - "windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc", - "windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc", - "windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc", + "windows/x64/Lib/urllib/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/urllib/__pycache__/error.cpython-38.opt-1.pyc", + "windows/x64/Lib/urllib/__pycache__/parse.cpython-38.opt-1.pyc", + "windows/x64/Lib/urllib/__pycache__/request.cpython-38.opt-1.pyc", + "windows/x64/Lib/urllib/__pycache__/response.cpython-38.opt-1.pyc", + "windows/x64/Lib/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc", "windows/x64/Lib/urllib/error.py", "windows/x64/Lib/urllib/parse.py", "windows/x64/Lib/urllib/request.py", @@ -6973,47 +6107,23 @@ "windows/x64/Lib/urllib/robotparser.py", "windows/x64/Lib/uu.py", "windows/x64/Lib/uuid.py", - "windows/x64/Lib/venv/__init__.py", - "windows/x64/Lib/venv/__main__.py", - "windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc", - "windows/x64/Lib/venv/scripts/common/activate", - "windows/x64/Lib/venv/scripts/nt/Activate.ps1", - "windows/x64/Lib/venv/scripts/nt/activate.bat", - "windows/x64/Lib/venv/scripts/nt/deactivate.bat", - "windows/x64/Lib/venv/scripts/nt/python.exe", - "windows/x64/Lib/venv/scripts/nt/pythonw.exe", - "windows/x64/Lib/venv/scripts/posix/activate.csh", - "windows/x64/Lib/venv/scripts/posix/activate.fish", "windows/x64/Lib/warnings.py", "windows/x64/Lib/wave.py", "windows/x64/Lib/weakref.py", "windows/x64/Lib/webbrowser.py", - "windows/x64/Lib/wsgiref/__init__.py", - "windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc", - "windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc", - "windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc", - "windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc", - "windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc", - "windows/x64/Lib/wsgiref/handlers.py", - "windows/x64/Lib/wsgiref/headers.py", - "windows/x64/Lib/wsgiref/simple_server.py", - "windows/x64/Lib/wsgiref/util.py", - "windows/x64/Lib/wsgiref/validate.py", "windows/x64/Lib/xdrlib.py", "windows/x64/Lib/xml/__init__.py", - "windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc", + "windows/x64/Lib/xml/__pycache__/__init__.cpython-38.opt-1.pyc", "windows/x64/Lib/xml/dom/NodeFilter.py", "windows/x64/Lib/xml/dom/__init__.py", - "windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc", "windows/x64/Lib/xml/dom/domreg.py", "windows/x64/Lib/xml/dom/expatbuilder.py", "windows/x64/Lib/xml/dom/minicompat.py", @@ -7024,36 +6134,37 @@ "windows/x64/Lib/xml/etree/ElementPath.py", "windows/x64/Lib/xml/etree/ElementTree.py", "windows/x64/Lib/xml/etree/__init__.py", - "windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc", + "windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc", "windows/x64/Lib/xml/etree/cElementTree.py", "windows/x64/Lib/xml/parsers/__init__.py", - "windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc", + "windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc", "windows/x64/Lib/xml/parsers/expat.py", "windows/x64/Lib/xml/sax/__init__.py", - "windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc", - "windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc", + "windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc", + "windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc", "windows/x64/Lib/xml/sax/_exceptions.py", "windows/x64/Lib/xml/sax/expatreader.py", "windows/x64/Lib/xml/sax/handler.py", "windows/x64/Lib/xml/sax/saxutils.py", "windows/x64/Lib/xml/sax/xmlreader.py", "windows/x64/Lib/xmlrpc/__init__.py", - "windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc", - "windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc", - "windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc", + "windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc", + "windows/x64/Lib/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc", + "windows/x64/Lib/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc", "windows/x64/Lib/xmlrpc/client.py", "windows/x64/Lib/xmlrpc/server.py", "windows/x64/Lib/zipapp.py", "windows/x64/Lib/zipfile.py", + "windows/x64/Lib/zipimport.py", "windows/x64/OpenAL32.dll", "windows/x64/SDL2.dll", "windows/x64/libvorbis.dll", @@ -7061,8 +6172,11 @@ "windows/x64/msvcp140d.dll", "windows/x64/ogg.dll", "windows/x64/python.exe", - "windows/x64/python37.dll", + "windows/x64/python38.dll", + "windows/x64/python38_d.dll", + "windows/x64/python_d.exe", "windows/x64/pythonw.exe", + "windows/x64/pythonw_d.exe", "windows/x64/vc_redist.x64.exe", "windows/x64/vcruntime140_1d.dll", "windows/x64/vcruntime140d.dll" diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index 969b9ca3..e6bc81ae 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -1,65 +1,65 @@ [ "ba_data/python/ba/__init__.py", - "ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_plugin.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/_ui.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc", - "ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc", + "ba_data/python/ba/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_account.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_achievement.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_activity.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_activitytypes.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_actor.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_analytics.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_app.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_appconfig.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_appdelegate.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_apputils.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_assetmanager.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_benchmark.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_campaign.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_collision.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_coopgame.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_coopsession.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_dependency.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_dualteamsession.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_enums.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_error.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_freeforallsession.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_gameactivity.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_gameresults.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_gameutils.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_general.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_hooks.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_input.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_lang.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_level.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_lobby.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_map.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_math.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_messages.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_meta.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_multiteamsession.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_music.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_netutils.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_nodeactor.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_player.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_playlist.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_plugin.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_powerup.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_profile.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_score.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_servermode.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_session.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_settings.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_stats.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_store.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_team.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_teamgame.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_tips.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_tournament.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_ui.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/deprecated.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/internal.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/macmusicapp.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/modutils.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/osmusic.cpython-38.opt-1.pyc", "ba_data/python/ba/_account.py", "ba_data/python/ba/_achievement.py", "ba_data/python/ba/_activity.py", @@ -120,33 +120,33 @@ "ba_data/python/ba/modutils.py", "ba_data/python/ba/osmusic.py", "ba_data/python/ba/ui/__init__.py", - "ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc", + "ba_data/python/ba/ui/__pycache__/__init__.cpython-38.opt-1.pyc", "ba_data/python/bacommon/__init__.py", - "ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bacommon/__pycache__/assets.cpython-37.opt-1.pyc", - "ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc", - "ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc", + "ba_data/python/bacommon/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bacommon/__pycache__/assets.cpython-38.opt-1.pyc", + "ba_data/python/bacommon/__pycache__/err.cpython-38.opt-1.pyc", + "ba_data/python/bacommon/__pycache__/servermanager.cpython-38.opt-1.pyc", "ba_data/python/bacommon/assets.py", "ba_data/python/bacommon/err.py", "ba_data/python/bacommon/servermanager.py", "ba_data/python/bastd/__init__.py", - "ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc", - "ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc", - "ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc", - "ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc", - "ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc", - "ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc", + "ba_data/python/bastd/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/__pycache__/appdelegate.cpython-38.opt-1.pyc", + "ba_data/python/bastd/__pycache__/gameutils.cpython-38.opt-1.pyc", + "ba_data/python/bastd/__pycache__/mainmenu.cpython-38.opt-1.pyc", + "ba_data/python/bastd/__pycache__/maps.cpython-38.opt-1.pyc", + "ba_data/python/bastd/__pycache__/stdmap.cpython-38.opt-1.pyc", + "ba_data/python/bastd/__pycache__/tutorial.cpython-38.opt-1.pyc", "ba_data/python/bastd/activity/__init__.py", - "ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc", - "ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/coopscore.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/drawscore.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-38.opt-1.pyc", + "ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-38.opt-1.pyc", "ba_data/python/bastd/activity/coopjoin.py", "ba_data/python/bastd/activity/coopscore.py", "ba_data/python/bastd/activity/drawscore.py", @@ -156,27 +156,27 @@ "ba_data/python/bastd/activity/multiteamscore.py", "ba_data/python/bastd/activity/multiteamvictory.py", "ba_data/python/bastd/actor/__init__.py", - "ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc", - "ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/background.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/bomb.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/flag.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/image.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/popuptext.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/spawner.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/spaz.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/spazbot.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/text.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/tipstext.cpython-38.opt-1.pyc", + "ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-38.opt-1.pyc", "ba_data/python/bastd/actor/background.py", "ba_data/python/bastd/actor/bomb.py", "ba_data/python/bastd/actor/controlsguide.py", @@ -199,25 +199,25 @@ "ba_data/python/bastd/actor/zoomtext.py", "ba_data/python/bastd/appdelegate.py", "ba_data/python/bastd/game/__init__.py", - "ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc", - "ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/assault.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/chosenone.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/conquest.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/deathmatch.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/elimination.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/football.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/hockey.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/keepaway.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/meteorshower.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/ninjafight.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/onslaught.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/race.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/runaround.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/targetpractice.cpython-38.opt-1.pyc", + "ba_data/python/bastd/game/__pycache__/thelaststand.cpython-38.opt-1.pyc", "ba_data/python/bastd/game/assault.py", "ba_data/python/bastd/game/capturetheflag.py", "ba_data/python/bastd/game/chosenone.py", @@ -239,24 +239,24 @@ "ba_data/python/bastd/gameutils.py", "ba_data/python/bastd/mainmenu.py", "ba_data/python/bastd/mapdata/__init__.py", - "ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc", - "ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-38.opt-1.pyc", + "ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-38.opt-1.pyc", "ba_data/python/bastd/mapdata/big_g.py", "ba_data/python/bastd/mapdata/bridgit.py", "ba_data/python/bastd/mapdata/courtyard.py", @@ -276,58 +276,58 @@ "ba_data/python/bastd/mapdata/zig_zag.py", "ba_data/python/bastd/maps.py", "ba_data/python/bastd/session/__init__.py", - "ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc", + "ba_data/python/bastd/session/__pycache__/__init__.cpython-38.opt-1.pyc", "ba_data/python/bastd/stdmap.py", "ba_data/python/bastd/tutorial.py", "ba_data/python/bastd/ui/__init__.py", - "ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/achievements.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/appinvite.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/config.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/configerror.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/confirm.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/continues.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/creditslist.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/debug.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/feedback.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/fileselector.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/gather.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/getremote.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/helpui.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/kiosk.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/party.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/play.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/playoptions.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/popup.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/promocode.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/purchase.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/qrcode.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/report.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/tabs.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/telnet.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/trophies.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/url.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/__pycache__/watch.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/account/__init__.py", - "ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/account/__pycache__/link.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/account/__pycache__/settings.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/account/link.py", "ba_data/python/bastd/ui/account/settings.py", "ba_data/python/bastd/ui/account/unlink.py", @@ -341,10 +341,10 @@ "ba_data/python/bastd/ui/confirm.py", "ba_data/python/bastd/ui/continues.py", "ba_data/python/bastd/ui/coop/__init__.py", - "ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/coop/__pycache__/level.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/coop/browser.py", "ba_data/python/bastd/ui/coop/gamebutton.py", "ba_data/python/bastd/ui/coop/level.py", @@ -359,9 +359,9 @@ "ba_data/python/bastd/ui/iconpicker.py", "ba_data/python/bastd/ui/kiosk.py", "ba_data/python/bastd/ui/league/__init__.py", - "ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/league/rankbutton.py", "ba_data/python/bastd/ui/league/rankwindow.py", "ba_data/python/bastd/ui/mainmenu.py", @@ -370,15 +370,15 @@ "ba_data/python/bastd/ui/partyqueue.py", "ba_data/python/bastd/ui/play.py", "ba_data/python/bastd/ui/playlist/__init__.py", - "ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/playlist/addgame.py", "ba_data/python/bastd/ui/playlist/browser.py", "ba_data/python/bastd/ui/playlist/customizebrowser.py", @@ -390,10 +390,10 @@ "ba_data/python/bastd/ui/playoptions.py", "ba_data/python/bastd/ui/popup.py", "ba_data/python/bastd/ui/profile/__init__.py", - "ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/profile/browser.py", "ba_data/python/bastd/ui/profile/edit.py", "ba_data/python/bastd/ui/profile/upgrade.py", @@ -405,25 +405,25 @@ "ba_data/python/bastd/ui/resourcetypeinfo.py", "ba_data/python/bastd/ui/serverdialog.py", "ba_data/python/bastd/ui/settings/__init__.py", - "ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/plugins.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/plugins.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/settings/advanced.py", "ba_data/python/bastd/ui/settings/allsettings.py", "ba_data/python/bastd/ui/settings/audio.py", @@ -443,21 +443,21 @@ "ba_data/python/bastd/ui/settings/wiimote.py", "ba_data/python/bastd/ui/settings/xbox360controller.py", "ba_data/python/bastd/ui/soundtrack/__init__.py", - "ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/soundtrack/browser.py", "ba_data/python/bastd/ui/soundtrack/edit.py", "ba_data/python/bastd/ui/soundtrack/entrytypeselect.py", "ba_data/python/bastd/ui/soundtrack/macmusicapp.py", "ba_data/python/bastd/ui/specialoffer.py", "ba_data/python/bastd/ui/store/__init__.py", - "ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc", - "ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc", + "ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/store/__pycache__/browser.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/store/__pycache__/button.cpython-38.opt-1.pyc", + "ba_data/python/bastd/ui/store/__pycache__/item.cpython-38.opt-1.pyc", "ba_data/python/bastd/ui/store/browser.py", "ba_data/python/bastd/ui/store/button.py", "ba_data/python/bastd/ui/store/item.py", @@ -470,23 +470,23 @@ "ba_data/python/bastd/ui/url.py", "ba_data/python/bastd/ui/watch.py", "ba_data/python/efro/__init__.py", - "ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc", - "ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc", - "ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc", - "ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc", - "ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc", - "ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc", + "ba_data/python/efro/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/efro/__pycache__/call.cpython-38.opt-1.pyc", + "ba_data/python/efro/__pycache__/dataclasses.cpython-38.opt-1.pyc", + "ba_data/python/efro/__pycache__/error.cpython-38.opt-1.pyc", + "ba_data/python/efro/__pycache__/json.cpython-38.opt-1.pyc", + "ba_data/python/efro/__pycache__/terminal.cpython-38.opt-1.pyc", + "ba_data/python/efro/__pycache__/util.cpython-38.opt-1.pyc", "ba_data/python/efro/call.py", "ba_data/python/efro/dataclasses.py", "ba_data/python/efro/entity/__init__.py", - "ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc", - "ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc", - "ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc", - "ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc", - "ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc", - "ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc", - "ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/_base.cpython-38.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/_entity.cpython-38.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/_field.cpython-38.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/_support.cpython-38.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/_value.cpython-38.opt-1.pyc", + "ba_data/python/efro/entity/__pycache__/util.cpython-38.opt-1.pyc", "ba_data/python/efro/entity/_base.py", "ba_data/python/efro/entity/_entity.py", "ba_data/python/efro/entity/_field.py", @@ -497,6 +497,6 @@ "ba_data/python/efro/json.py", "ba_data/python/efro/terminal.py", "ba_data/python/efro/util.py", - "server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc", + "server/__pycache__/ballisticacore_server.cpython-38.opt-1.pyc", "server/ballisticacore_server.py" ] \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 2cbf1ee8..31615346 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -140,7 +140,7 @@ ASSET_TARGETS_WIN_WIN32 += $(EXTRAS_TARGETS_WIN_WIN32) ASSET_TARGETS_WIN_X64 += $(EXTRAS_TARGETS_WIN_X64) define make-opt-pyc-target -$1: $$(subst /__pycache__,,$$(subst .cpython-37.opt-1.pyc,.py,$1)) +$1: $$(subst /__pycache__,,$$(subst .cpython-38.opt-1.pyc,.py,$1)) @echo Compiling script: $$^ @rm -rf $$@ && PYTHONHASHSEED=1 \ $$(TOOLS_DIR)/pcommand compile_python_files $$^ && chmod 444 $$@ @@ -383,238 +383,238 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/server/ballisticacore_server.py SCRIPT_TARGETS_PYC_PUBLIC = \ - build/ba_data/python/ba/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_account.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_achievement.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_activity.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_activitytypes.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_actor.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_analytics.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_app.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_appconfig.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_appdelegate.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_apputils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_assetmanager.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_benchmark.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_campaign.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_collision.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_coopgame.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_coopsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_dependency.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_enums.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_error.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gameactivity.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gameresults.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_gameutils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_general.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_hooks.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_input.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_lang.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_level.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_lobby.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_map.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_math.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_messages.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_meta.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_music.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_netutils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_nodeactor.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_player.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_playlist.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_plugin.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_powerup.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_profile.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_score.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_servermode.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_session.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_settings.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_stats.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_store.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_team.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_teamgame.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_tips.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_tournament.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/_ui.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/deprecated.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/internal.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/modutils.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/__pycache__/osmusic.cpython-37.opt-1.pyc \ - build/ba_data/python/ba/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/background.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/flag.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/image.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/text.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/appdelegate.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/assault.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/conquest.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/elimination.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/football.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/hockey.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/race.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/runaround.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/gameutils.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/mainmenu.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/maps.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/session/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/stdmap.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/__pycache__/tutorial.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/config.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/continues.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/debug.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/gather.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/party.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/play.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/popup.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/report.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/plugins.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/url.cpython-37.opt-1.pyc \ - build/ba_data/python/bastd/ui/__pycache__/watch.cpython-37.opt-1.pyc \ - build/server/__pycache__/ballisticacore_server.cpython-37.opt-1.pyc + build/ba_data/python/ba/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_account.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_achievement.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_activity.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_activitytypes.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_actor.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_analytics.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_app.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_appconfig.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_appdelegate.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_apputils.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_assetmanager.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_benchmark.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_campaign.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_collision.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_coopgame.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_coopsession.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_dependency.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_dualteamsession.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_enums.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_error.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_freeforallsession.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gameactivity.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gameresults.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_gameutils.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_general.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_hooks.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_input.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_lang.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_level.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_lobby.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_map.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_math.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_messages.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_meta.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_multiteamsession.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_music.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_netutils.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_nodeactor.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_player.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_playlist.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_plugin.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_powerup.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_profile.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_score.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_servermode.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_session.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_settings.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_stats.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_store.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_team.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_teamgame.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_tips.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_tournament.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_ui.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/deprecated.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/internal.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/macmusicapp.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/modutils.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/osmusic.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/ui/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/coopjoin.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/coopscore.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/drawscore.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/dualteamscore.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/freeforallvictory.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/multiteamjoin.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/multiteamscore.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/activity/__pycache__/multiteamvictory.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/background.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/bomb.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/controlsguide.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/flag.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/image.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/onscreencountdown.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/onscreentimer.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/playerspaz.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/popuptext.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/powerupbox.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/respawnicon.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/scoreboard.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spawner.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spaz.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spazappearance.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spazbot.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/spazfactory.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/text.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/tipstext.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/actor/__pycache__/zoomtext.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/appdelegate.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/assault.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/capturetheflag.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/chosenone.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/conquest.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/deathmatch.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/easteregghunt.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/elimination.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/football.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/hockey.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/keepaway.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/kingofthehill.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/meteorshower.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/ninjafight.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/onslaught.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/race.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/runaround.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/gameutils.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/mainmenu.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/bridgit.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/courtyard.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/crag_castle.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/doom_shroom.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/football_stadium.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/happy_thoughts.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/hockey_stadium.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/lake_frigid.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/monkey_face.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/rampage.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/roundabout.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/step_right_up.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/the_pad.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/tip_top.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/tower_d.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/mapdata/__pycache__/zig_zag.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/maps.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/session/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/stdmap.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/__pycache__/tutorial.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/link.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/settings.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/unlink.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/account/__pycache__/viewer.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/achievements.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/appinvite.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/characterpicker.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/colorpicker.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/config.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/configerror.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/confirm.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/continues.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/browser.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/gamebutton.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/coop/__pycache__/level.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/creditslist.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/debug.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/feedback.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/fileselector.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/gather.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/getcurrency.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/getremote.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/helpui.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/iconpicker.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/kiosk.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/league/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/league/__pycache__/rankbutton.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/league/__pycache__/rankwindow.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/mainmenu.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/onscreenkeyboard.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/party.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/partyqueue.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/play.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/addgame.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/browser.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/customizebrowser.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/edit.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/editcontroller.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/editgame.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/mapselect.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/playlist/__pycache__/share.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/playoptions.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/popup.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/profile/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/profile/__pycache__/browser.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/profile/__pycache__/edit.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/profile/__pycache__/upgrade.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/promocode.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/purchase.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/qrcode.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/radiogroup.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/report.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/resourcetypeinfo.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/serverdialog.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/advanced.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/allsettings.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/audio.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/controls.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/gamepad.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/gamepadadvanced.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/gamepadselect.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/graphics.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/keyboard.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/nettesting.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/plugins.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/ps3controller.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/remoteapp.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/testing.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/touchscreen.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/vrtesting.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/wiimote.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/settings/__pycache__/xbox360controller.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/browser.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/edit.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/entrytypeselect.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/soundtrack/__pycache__/macmusicapp.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/specialoffer.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/store/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/store/__pycache__/browser.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/store/__pycache__/button.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/store/__pycache__/item.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tabs.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/teamnamescolors.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/telnet.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tournamententry.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/tournamentscores.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/url.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/ui/__pycache__/watch.cpython-38.opt-1.pyc \ + build/server/__pycache__/ballisticacore_server.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -651,24 +651,24 @@ SCRIPT_TARGETS_PY_PUBLIC_TOOLS = \ build/ba_data/python/efro/util.py SCRIPT_TARGETS_PYC_PUBLIC_TOOLS = \ - build/ba_data/python/bacommon/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/bacommon/__pycache__/assets.cpython-37.opt-1.pyc \ - build/ba_data/python/bacommon/__pycache__/err.cpython-37.opt-1.pyc \ - build/ba_data/python/bacommon/__pycache__/servermanager.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/call.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_base.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_entity.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_field.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_support.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/_value.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/entity/__pycache__/util.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/error.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/json.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/terminal.cpython-37.opt-1.pyc \ - build/ba_data/python/efro/__pycache__/util.cpython-37.opt-1.pyc + build/ba_data/python/bacommon/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bacommon/__pycache__/assets.cpython-38.opt-1.pyc \ + build/ba_data/python/bacommon/__pycache__/err.cpython-38.opt-1.pyc \ + build/ba_data/python/bacommon/__pycache__/servermanager.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/call.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/dataclasses.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_base.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_entity.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_field.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_support.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/_value.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/entity/__pycache__/util.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/error.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/json.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/terminal.cpython-38.opt-1.pyc \ + build/ba_data/python/efro/__pycache__/util.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -711,6 +711,7 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/ast.py \ build/pylib-apple/asynchat.py \ build/pylib-apple/asyncio/__init__.py \ + build/pylib-apple/asyncio/__main__.py \ build/pylib-apple/asyncio/base_events.py \ build/pylib-apple/asyncio/base_futures.py \ build/pylib-apple/asyncio/base_subprocess.py \ @@ -718,6 +719,7 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/asyncio/constants.py \ build/pylib-apple/asyncio/coroutines.py \ build/pylib-apple/asyncio/events.py \ + build/pylib-apple/asyncio/exceptions.py \ build/pylib-apple/asyncio/format_helpers.py \ build/pylib-apple/asyncio/futures.py \ build/pylib-apple/asyncio/locks.py \ @@ -728,10 +730,12 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/asyncio/runners.py \ build/pylib-apple/asyncio/selector_events.py \ build/pylib-apple/asyncio/sslproto.py \ + build/pylib-apple/asyncio/staggered.py \ build/pylib-apple/asyncio/streams.py \ build/pylib-apple/asyncio/subprocess.py \ build/pylib-apple/asyncio/tasks.py \ build/pylib-apple/asyncio/transports.py \ + build/pylib-apple/asyncio/trsock.py \ build/pylib-apple/asyncio/unix_events.py \ build/pylib-apple/asyncio/windows_events.py \ build/pylib-apple/asyncio/windows_utils.py \ @@ -842,7 +846,6 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/encodings/cp424.py \ build/pylib-apple/encodings/cp437.py \ build/pylib-apple/encodings/cp500.py \ - build/pylib-apple/encodings/cp65001.py \ build/pylib-apple/encodings/cp720.py \ build/pylib-apple/encodings/cp737.py \ build/pylib-apple/encodings/cp775.py \ @@ -929,7 +932,6 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/encodings/tis_620.py \ build/pylib-apple/encodings/undefined.py \ build/pylib-apple/encodings/unicode_escape.py \ - build/pylib-apple/encodings/unicode_internal.py \ build/pylib-apple/encodings/utf_16.py \ build/pylib-apple/encodings/utf_16_be.py \ build/pylib-apple/encodings/utf_16_le.py \ @@ -973,6 +975,7 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/importlib/_bootstrap_external.py \ build/pylib-apple/importlib/abc.py \ build/pylib-apple/importlib/machinery.py \ + build/pylib-apple/importlib/metadata.py \ build/pylib-apple/importlib/resources.py \ build/pylib-apple/importlib/util.py \ build/pylib-apple/inspect.py \ @@ -990,7 +993,6 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/logging/config.py \ build/pylib-apple/logging/handlers.py \ build/pylib-apple/lzma.py \ - build/pylib-apple/macpath.py \ build/pylib-apple/mailbox.py \ build/pylib-apple/mailcap.py \ build/pylib-apple/mimetypes.py \ @@ -1113,435 +1115,439 @@ SCRIPT_TARGETS_PY_PRIVATE_APPLE = \ build/pylib-apple/xmlrpc/client.py \ build/pylib-apple/xmlrpc/server.py \ build/pylib-apple/zipapp.py \ - build/pylib-apple/zipfile.py + build/pylib-apple/zipfile.py \ + build/pylib-apple/zipimport.py SCRIPT_TARGETS_PYC_PRIVATE_APPLE = \ - build/pylib-apple/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ast.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/base64.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/code.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/pylib-apple/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/copy.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/csv.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-apple/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/pylib-apple/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dis.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/errors.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/header.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ - build/pylib-apple/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/pylib-apple/email/__pycache__/utils.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/enum.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/functools.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/glob.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/pylib-apple/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/pylib-apple/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/pylib-apple/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/imp.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/pylib-apple/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/io.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/pylib-apple/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/locale.cpython-37.opt-1.pyc \ - build/pylib-apple/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/logging/__pycache__/config.cpython-37.opt-1.pyc \ - build/pylib-apple/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/operator.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/os.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/platform.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/profile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pty.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/queue.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/random.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/re.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sched.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/signal.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/site.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/socket.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/pylib-apple/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/pylib-apple/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/stat.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/string.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/struct.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/this.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/threading.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/token.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/trace.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/tty.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/types.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/typing.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/pylib-apple/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/uu.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/wave.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-apple/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/pylib-apple/__pycache__/zipfile.cpython-37.opt-1.pyc + build/pylib-apple/__pycache__/__future__.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/__phello__.foo.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_bootlocale.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_collections_abc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_compat_pickle.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_compression.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_dummy_thread.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_markupbase.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_osx_support.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_py_abc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_pydecimal.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_pyio.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_strptime.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_threading_local.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/_weakrefset.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/abc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/aifc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/antigravity.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/argparse.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/ast.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/asynchat.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/constants.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/events.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/futures.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/locks.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/log.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/queues.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/runners.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/streams.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/transports.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc \ + build/pylib-apple/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/asyncore.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/base64.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/bdb.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/binhex.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/bisect.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/bz2.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/cProfile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/calendar.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/cgi.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/cgitb.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/chunk.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/cmd.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/code.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/codecs.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/codeop.cpython-38.opt-1.pyc \ + build/pylib-apple/collections/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/collections/__pycache__/abc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/colorsys.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/compileall.cpython-38.opt-1.pyc \ + build/pylib-apple/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc \ + build/pylib-apple/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/configparser.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/contextlib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/contextvars.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/copy.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/copyreg.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/crypt.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/csv.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/util.cpython-38.opt-1.pyc \ + build/pylib-apple/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/has_key.cpython-38.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/panel.cpython-38.opt-1.pyc \ + build/pylib-apple/curses/__pycache__/textpad.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/dataclasses.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/datetime.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/decimal.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/difflib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/dis.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/doctest.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/dummy_threading.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/_policybase.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/base64mime.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/charset.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/contentmanager.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/encoders.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/errors.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/feedparser.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/generator.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/header.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/headerregistry.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/iterators.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/message.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/application.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/audio.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/base.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/image.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/message.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc \ + build/pylib-apple/email/mime/__pycache__/text.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/parser.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/policy.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/quoprimime.cpython-38.opt-1.pyc \ + build/pylib-apple/email/__pycache__/utils.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/aliases.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/big5.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/charmap.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp037.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp273.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp424.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp437.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp500.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp720.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp737.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp775.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp850.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp852.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp855.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp856.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp857.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp858.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp860.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp861.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp862.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp863.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp864.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp865.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp866.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp869.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp874.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp875.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp932.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp949.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/cp950.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/gbk.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/hz.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/idna.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/johab.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/oem.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/palmos.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/punycode.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/undefined.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc \ + build/pylib-apple/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/enum.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/filecmp.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/fileinput.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/fnmatch.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/formatter.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/fractions.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/ftplib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/functools.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/genericpath.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/getopt.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/getpass.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/gettext.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/glob.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/gzip.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/hashlib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/heapq.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/hmac.cpython-38.opt-1.pyc \ + build/pylib-apple/html/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/html/__pycache__/entities.cpython-38.opt-1.pyc \ + build/pylib-apple/html/__pycache__/parser.cpython-38.opt-1.pyc \ + build/pylib-apple/http/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/http/__pycache__/client.cpython-38.opt-1.pyc \ + build/pylib-apple/http/__pycache__/cookiejar.cpython-38.opt-1.pyc \ + build/pylib-apple/http/__pycache__/cookies.cpython-38.opt-1.pyc \ + build/pylib-apple/http/__pycache__/server.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/imghdr.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/imp.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/abc.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/machinery.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/metadata.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/resources.cpython-38.opt-1.pyc \ + build/pylib-apple/importlib/__pycache__/util.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/inspect.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/io.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/ipaddress.cpython-38.opt-1.pyc \ + build/pylib-apple/json/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/json/__pycache__/decoder.cpython-38.opt-1.pyc \ + build/pylib-apple/json/__pycache__/encoder.cpython-38.opt-1.pyc \ + build/pylib-apple/json/__pycache__/scanner.cpython-38.opt-1.pyc \ + build/pylib-apple/json/__pycache__/tool.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/keyword.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/linecache.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/locale.cpython-38.opt-1.pyc \ + build/pylib-apple/logging/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/logging/__pycache__/config.cpython-38.opt-1.pyc \ + build/pylib-apple/logging/__pycache__/handlers.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/lzma.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/mailbox.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/mailcap.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/mimetypes.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/modulefinder.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/netrc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/nntplib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/ntpath.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/nturl2path.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/numbers.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/opcode.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/operator.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/optparse.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/os.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pathlib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pdb.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pickle.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pickletools.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pipes.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pkgutil.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/platform.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/plistlib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/poplib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/posixpath.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pprint.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/profile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pstats.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pty.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/py_compile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pyclbr.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/pydoc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/queue.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/quopri.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/random.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/re.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/reprlib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/rlcompleter.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/runpy.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sched.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/secrets.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/selectors.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/shelve.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/shlex.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/shutil.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/signal.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/site.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/smtpd.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/smtplib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sndhdr.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/socket.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/socketserver.cpython-38.opt-1.pyc \ + build/pylib-apple/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc \ + build/pylib-apple/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_compile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_constants.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sre_parse.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/ssl.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/stat.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/statistics.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/string.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/stringprep.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/struct.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sunau.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/symbol.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/symtable.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/sysconfig.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/tabnanny.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/tarfile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/telnetlib.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/tempfile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/textwrap.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/this.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/threading.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/timeit.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/token.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/tokenize.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/trace.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/traceback.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/tracemalloc.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/tty.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/types.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/typing.cpython-38.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/error.cpython-38.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/parse.cpython-38.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/request.cpython-38.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/response.cpython-38.opt-1.pyc \ + build/pylib-apple/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/uu.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/uuid.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/warnings.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/wave.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/weakref.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/webbrowser.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/xdrlib.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc \ + build/pylib-apple/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc \ + build/pylib-apple/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-apple/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc \ + build/pylib-apple/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/zipapp.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/zipfile.cpython-38.opt-1.pyc \ + build/pylib-apple/__pycache__/zipimport.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -1577,6 +1583,7 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/ast.py \ build/pylib-android/asynchat.py \ build/pylib-android/asyncio/__init__.py \ + build/pylib-android/asyncio/__main__.py \ build/pylib-android/asyncio/base_events.py \ build/pylib-android/asyncio/base_futures.py \ build/pylib-android/asyncio/base_subprocess.py \ @@ -1584,6 +1591,7 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/asyncio/constants.py \ build/pylib-android/asyncio/coroutines.py \ build/pylib-android/asyncio/events.py \ + build/pylib-android/asyncio/exceptions.py \ build/pylib-android/asyncio/format_helpers.py \ build/pylib-android/asyncio/futures.py \ build/pylib-android/asyncio/locks.py \ @@ -1594,10 +1602,12 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/asyncio/runners.py \ build/pylib-android/asyncio/selector_events.py \ build/pylib-android/asyncio/sslproto.py \ + build/pylib-android/asyncio/staggered.py \ build/pylib-android/asyncio/streams.py \ build/pylib-android/asyncio/subprocess.py \ build/pylib-android/asyncio/tasks.py \ build/pylib-android/asyncio/transports.py \ + build/pylib-android/asyncio/trsock.py \ build/pylib-android/asyncio/unix_events.py \ build/pylib-android/asyncio/windows_events.py \ build/pylib-android/asyncio/windows_utils.py \ @@ -1708,7 +1718,6 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/encodings/cp424.py \ build/pylib-android/encodings/cp437.py \ build/pylib-android/encodings/cp500.py \ - build/pylib-android/encodings/cp65001.py \ build/pylib-android/encodings/cp720.py \ build/pylib-android/encodings/cp737.py \ build/pylib-android/encodings/cp775.py \ @@ -1795,7 +1804,6 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/encodings/tis_620.py \ build/pylib-android/encodings/undefined.py \ build/pylib-android/encodings/unicode_escape.py \ - build/pylib-android/encodings/unicode_internal.py \ build/pylib-android/encodings/utf_16.py \ build/pylib-android/encodings/utf_16_be.py \ build/pylib-android/encodings/utf_16_le.py \ @@ -1839,6 +1847,7 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/importlib/_bootstrap_external.py \ build/pylib-android/importlib/abc.py \ build/pylib-android/importlib/machinery.py \ + build/pylib-android/importlib/metadata.py \ build/pylib-android/importlib/resources.py \ build/pylib-android/importlib/util.py \ build/pylib-android/inspect.py \ @@ -1856,7 +1865,6 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/logging/config.py \ build/pylib-android/logging/handlers.py \ build/pylib-android/lzma.py \ - build/pylib-android/macpath.py \ build/pylib-android/mailbox.py \ build/pylib-android/mailcap.py \ build/pylib-android/mimetypes.py \ @@ -1979,435 +1987,439 @@ SCRIPT_TARGETS_PY_PRIVATE_ANDROID = \ build/pylib-android/xmlrpc/client.py \ build/pylib-android/xmlrpc/server.py \ build/pylib-android/zipapp.py \ - build/pylib-android/zipfile.py + build/pylib-android/zipfile.py \ + build/pylib-android/zipimport.py SCRIPT_TARGETS_PYC_PRIVATE_ANDROID = \ - build/pylib-android/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ast.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/pylib-android/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/base64.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/code.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/pylib-android/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/pylib-android/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/copy.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/csv.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-android/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/pylib-android/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dis.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/errors.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/header.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ - build/pylib-android/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/pylib-android/email/__pycache__/utils.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/pylib-android/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/enum.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/functools.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/glob.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/pylib-android/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/pylib-android/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/pylib-android/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/imp.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/pylib-android/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/io.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/pylib-android/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/locale.cpython-37.opt-1.pyc \ - build/pylib-android/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/logging/__pycache__/config.cpython-37.opt-1.pyc \ - build/pylib-android/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/operator.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/os.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/platform.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/profile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pty.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/queue.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/random.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/re.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sched.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/signal.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/site.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/socket.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/pylib-android/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/pylib-android/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/stat.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/string.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/struct.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/this.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/threading.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/token.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/trace.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/tty.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/types.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/typing.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/pylib-android/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/uu.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/wave.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/pylib-android/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/pylib-android/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/pylib-android/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/pylib-android/__pycache__/zipfile.cpython-37.opt-1.pyc + build/pylib-android/__pycache__/__future__.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/__phello__.foo.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_bootlocale.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_collections_abc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_compat_pickle.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_compression.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_dummy_thread.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_markupbase.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_osx_support.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_py_abc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_pydecimal.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_pyio.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_strptime.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_threading_local.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/_weakrefset.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/abc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/aifc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/antigravity.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/argparse.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/ast.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/asynchat.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/constants.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/events.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/futures.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/locks.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/log.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/queues.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/runners.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/streams.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/transports.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc \ + build/pylib-android/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/asyncore.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/base64.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/bdb.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/binhex.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/bisect.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/bz2.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/cProfile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/calendar.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/cgi.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/cgitb.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/chunk.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/cmd.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/code.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/codecs.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/codeop.cpython-38.opt-1.pyc \ + build/pylib-android/collections/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/collections/__pycache__/abc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/colorsys.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/compileall.cpython-38.opt-1.pyc \ + build/pylib-android/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc \ + build/pylib-android/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/configparser.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/contextlib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/contextvars.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/copy.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/copyreg.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/crypt.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/csv.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/util.cpython-38.opt-1.pyc \ + build/pylib-android/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc \ + build/pylib-android/curses/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/curses/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/pylib-android/curses/__pycache__/has_key.cpython-38.opt-1.pyc \ + build/pylib-android/curses/__pycache__/panel.cpython-38.opt-1.pyc \ + build/pylib-android/curses/__pycache__/textpad.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/dataclasses.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/datetime.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/decimal.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/difflib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/dis.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/doctest.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/dummy_threading.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/_policybase.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/base64mime.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/charset.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/contentmanager.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/encoders.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/errors.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/feedparser.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/generator.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/header.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/headerregistry.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/iterators.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/message.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/application.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/audio.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/base.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/image.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/message.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc \ + build/pylib-android/email/mime/__pycache__/text.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/parser.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/policy.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/quoprimime.cpython-38.opt-1.pyc \ + build/pylib-android/email/__pycache__/utils.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/aliases.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/big5.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/charmap.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp037.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp273.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp424.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp437.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp500.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp720.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp737.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp775.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp850.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp852.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp855.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp856.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp857.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp858.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp860.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp861.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp862.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp863.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp864.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp865.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp866.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp869.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp874.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp875.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp932.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp949.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/cp950.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/gbk.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/hz.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/idna.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/johab.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/oem.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/palmos.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/punycode.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/undefined.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc \ + build/pylib-android/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/enum.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/filecmp.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/fileinput.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/fnmatch.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/formatter.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/fractions.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/ftplib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/functools.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/genericpath.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/getopt.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/getpass.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/gettext.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/glob.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/gzip.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/hashlib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/heapq.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/hmac.cpython-38.opt-1.pyc \ + build/pylib-android/html/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/html/__pycache__/entities.cpython-38.opt-1.pyc \ + build/pylib-android/html/__pycache__/parser.cpython-38.opt-1.pyc \ + build/pylib-android/http/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/http/__pycache__/client.cpython-38.opt-1.pyc \ + build/pylib-android/http/__pycache__/cookiejar.cpython-38.opt-1.pyc \ + build/pylib-android/http/__pycache__/cookies.cpython-38.opt-1.pyc \ + build/pylib-android/http/__pycache__/server.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/imghdr.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/imp.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/abc.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/machinery.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/metadata.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/resources.cpython-38.opt-1.pyc \ + build/pylib-android/importlib/__pycache__/util.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/inspect.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/io.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/ipaddress.cpython-38.opt-1.pyc \ + build/pylib-android/json/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/json/__pycache__/decoder.cpython-38.opt-1.pyc \ + build/pylib-android/json/__pycache__/encoder.cpython-38.opt-1.pyc \ + build/pylib-android/json/__pycache__/scanner.cpython-38.opt-1.pyc \ + build/pylib-android/json/__pycache__/tool.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/keyword.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/linecache.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/locale.cpython-38.opt-1.pyc \ + build/pylib-android/logging/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/logging/__pycache__/config.cpython-38.opt-1.pyc \ + build/pylib-android/logging/__pycache__/handlers.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/lzma.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/mailbox.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/mailcap.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/mimetypes.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/modulefinder.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/netrc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/nntplib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/ntpath.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/nturl2path.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/numbers.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/opcode.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/operator.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/optparse.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/os.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pathlib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pdb.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pickle.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pickletools.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pipes.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pkgutil.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/platform.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/plistlib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/poplib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/posixpath.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pprint.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/profile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pstats.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pty.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/py_compile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pyclbr.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/pydoc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/queue.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/quopri.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/random.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/re.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/reprlib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/rlcompleter.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/runpy.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sched.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/secrets.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/selectors.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/shelve.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/shlex.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/shutil.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/signal.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/site.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/smtpd.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/smtplib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sndhdr.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/socket.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/socketserver.cpython-38.opt-1.pyc \ + build/pylib-android/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc \ + build/pylib-android/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sre_compile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sre_constants.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sre_parse.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/ssl.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/stat.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/statistics.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/string.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/stringprep.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/struct.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sunau.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/symbol.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/symtable.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/sysconfig.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/tabnanny.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/tarfile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/telnetlib.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/tempfile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/textwrap.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/this.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/threading.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/timeit.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/token.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/tokenize.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/trace.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/traceback.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/tracemalloc.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/tty.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/types.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/typing.cpython-38.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/error.cpython-38.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/parse.cpython-38.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/request.cpython-38.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/response.cpython-38.opt-1.pyc \ + build/pylib-android/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/uu.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/uuid.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/warnings.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/wave.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/weakref.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/webbrowser.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/xdrlib.cpython-38.opt-1.pyc \ + build/pylib-android/xml/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc \ + build/pylib-android/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc \ + build/pylib-android/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc \ + build/pylib-android/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc \ + build/pylib-android/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/pylib-android/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc \ + build/pylib-android/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/zipapp.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/zipfile.cpython-38.opt-1.pyc \ + build/pylib-android/__pycache__/zipimport.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -2440,24 +2452,24 @@ SCRIPT_TARGETS_PY_PRIVATE_COMMON = \ build/ba_data/python-site-packages/yaml/tokens.py SCRIPT_TARGETS_PYC_PRIVATE_COMMON = \ - build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/parser.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-37.opt-1.pyc \ - build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-37.opt-1.pyc + build/ba_data/python-site-packages/__pycache__/typing_extensions.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/composer.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/constructor.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/cyaml.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/dumper.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/emitter.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/error.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/events.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/loader.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/nodes.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/parser.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/reader.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/representer.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/resolver.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/scanner.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/serializer.cpython-38.opt-1.pyc \ + build/ba_data/python-site-packages/yaml/__pycache__/tokens.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -2493,6 +2505,7 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/ast.py \ build/windows/Win32/Lib/asynchat.py \ build/windows/Win32/Lib/asyncio/__init__.py \ + build/windows/Win32/Lib/asyncio/__main__.py \ build/windows/Win32/Lib/asyncio/base_events.py \ build/windows/Win32/Lib/asyncio/base_futures.py \ build/windows/Win32/Lib/asyncio/base_subprocess.py \ @@ -2500,6 +2513,7 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/asyncio/constants.py \ build/windows/Win32/Lib/asyncio/coroutines.py \ build/windows/Win32/Lib/asyncio/events.py \ + build/windows/Win32/Lib/asyncio/exceptions.py \ build/windows/Win32/Lib/asyncio/format_helpers.py \ build/windows/Win32/Lib/asyncio/futures.py \ build/windows/Win32/Lib/asyncio/locks.py \ @@ -2510,10 +2524,12 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/asyncio/runners.py \ build/windows/Win32/Lib/asyncio/selector_events.py \ build/windows/Win32/Lib/asyncio/sslproto.py \ + build/windows/Win32/Lib/asyncio/staggered.py \ build/windows/Win32/Lib/asyncio/streams.py \ build/windows/Win32/Lib/asyncio/subprocess.py \ build/windows/Win32/Lib/asyncio/tasks.py \ build/windows/Win32/Lib/asyncio/transports.py \ + build/windows/Win32/Lib/asyncio/trsock.py \ build/windows/Win32/Lib/asyncio/unix_events.py \ build/windows/Win32/Lib/asyncio/windows_events.py \ build/windows/Win32/Lib/asyncio/windows_utils.py \ @@ -2555,59 +2571,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/ctypes/macholib/dyld.py \ build/windows/Win32/Lib/ctypes/macholib/dylib.py \ build/windows/Win32/Lib/ctypes/macholib/framework.py \ - build/windows/Win32/Lib/ctypes/test/__init__.py \ - build/windows/Win32/Lib/ctypes/test/__main__.py \ - build/windows/Win32/Lib/ctypes/test/test_anon.py \ - build/windows/Win32/Lib/ctypes/test/test_array_in_pointer.py \ - build/windows/Win32/Lib/ctypes/test/test_arrays.py \ - build/windows/Win32/Lib/ctypes/test/test_as_parameter.py \ - build/windows/Win32/Lib/ctypes/test/test_bitfields.py \ - build/windows/Win32/Lib/ctypes/test/test_buffers.py \ - build/windows/Win32/Lib/ctypes/test/test_bytes.py \ - build/windows/Win32/Lib/ctypes/test/test_byteswap.py \ - build/windows/Win32/Lib/ctypes/test/test_callbacks.py \ - build/windows/Win32/Lib/ctypes/test/test_cast.py \ - build/windows/Win32/Lib/ctypes/test/test_cfuncs.py \ - build/windows/Win32/Lib/ctypes/test/test_checkretval.py \ - build/windows/Win32/Lib/ctypes/test/test_delattr.py \ - build/windows/Win32/Lib/ctypes/test/test_errno.py \ - build/windows/Win32/Lib/ctypes/test/test_find.py \ - build/windows/Win32/Lib/ctypes/test/test_frombuffer.py \ - build/windows/Win32/Lib/ctypes/test/test_funcptr.py \ - build/windows/Win32/Lib/ctypes/test/test_functions.py \ - build/windows/Win32/Lib/ctypes/test/test_incomplete.py \ - build/windows/Win32/Lib/ctypes/test/test_init.py \ - build/windows/Win32/Lib/ctypes/test/test_internals.py \ - build/windows/Win32/Lib/ctypes/test/test_keeprefs.py \ - build/windows/Win32/Lib/ctypes/test/test_libc.py \ - build/windows/Win32/Lib/ctypes/test/test_loading.py \ - build/windows/Win32/Lib/ctypes/test/test_macholib.py \ - build/windows/Win32/Lib/ctypes/test/test_memfunctions.py \ - build/windows/Win32/Lib/ctypes/test/test_numbers.py \ - build/windows/Win32/Lib/ctypes/test/test_objects.py \ - build/windows/Win32/Lib/ctypes/test/test_parameters.py \ - build/windows/Win32/Lib/ctypes/test/test_pep3118.py \ - build/windows/Win32/Lib/ctypes/test/test_pickling.py \ - build/windows/Win32/Lib/ctypes/test/test_pointers.py \ - build/windows/Win32/Lib/ctypes/test/test_prototypes.py \ - build/windows/Win32/Lib/ctypes/test/test_python_api.py \ - build/windows/Win32/Lib/ctypes/test/test_random_things.py \ - build/windows/Win32/Lib/ctypes/test/test_refcounts.py \ - build/windows/Win32/Lib/ctypes/test/test_repr.py \ - build/windows/Win32/Lib/ctypes/test/test_returnfuncptrs.py \ - build/windows/Win32/Lib/ctypes/test/test_simplesubclasses.py \ - build/windows/Win32/Lib/ctypes/test/test_sizes.py \ - build/windows/Win32/Lib/ctypes/test/test_slicing.py \ - build/windows/Win32/Lib/ctypes/test/test_stringptr.py \ - build/windows/Win32/Lib/ctypes/test/test_strings.py \ - build/windows/Win32/Lib/ctypes/test/test_struct_fields.py \ - build/windows/Win32/Lib/ctypes/test/test_structures.py \ - build/windows/Win32/Lib/ctypes/test/test_unaligned_structures.py \ - build/windows/Win32/Lib/ctypes/test/test_unicode.py \ - build/windows/Win32/Lib/ctypes/test/test_values.py \ - build/windows/Win32/Lib/ctypes/test/test_varsize_struct.py \ - build/windows/Win32/Lib/ctypes/test/test_win32.py \ - build/windows/Win32/Lib/ctypes/test/test_wintypes.py \ build/windows/Win32/Lib/ctypes/util.py \ build/windows/Win32/Lib/ctypes/wintypes.py \ build/windows/Win32/Lib/curses/__init__.py \ @@ -2617,108 +2580,9 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/curses/textpad.py \ build/windows/Win32/Lib/dataclasses.py \ build/windows/Win32/Lib/datetime.py \ - build/windows/Win32/Lib/dbm/__init__.py \ - build/windows/Win32/Lib/dbm/dumb.py \ - build/windows/Win32/Lib/dbm/gnu.py \ - build/windows/Win32/Lib/dbm/ndbm.py \ build/windows/Win32/Lib/decimal.py \ build/windows/Win32/Lib/difflib.py \ build/windows/Win32/Lib/dis.py \ - build/windows/Win32/Lib/distutils/__init__.py \ - build/windows/Win32/Lib/distutils/_msvccompiler.py \ - build/windows/Win32/Lib/distutils/archive_util.py \ - build/windows/Win32/Lib/distutils/bcppcompiler.py \ - build/windows/Win32/Lib/distutils/ccompiler.py \ - build/windows/Win32/Lib/distutils/cmd.py \ - build/windows/Win32/Lib/distutils/command/__init__.py \ - build/windows/Win32/Lib/distutils/command/bdist.py \ - build/windows/Win32/Lib/distutils/command/bdist_dumb.py \ - build/windows/Win32/Lib/distutils/command/bdist_msi.py \ - build/windows/Win32/Lib/distutils/command/bdist_rpm.py \ - build/windows/Win32/Lib/distutils/command/bdist_wininst.py \ - build/windows/Win32/Lib/distutils/command/build.py \ - build/windows/Win32/Lib/distutils/command/build_clib.py \ - build/windows/Win32/Lib/distutils/command/build_ext.py \ - build/windows/Win32/Lib/distutils/command/build_py.py \ - build/windows/Win32/Lib/distutils/command/build_scripts.py \ - build/windows/Win32/Lib/distutils/command/check.py \ - build/windows/Win32/Lib/distutils/command/clean.py \ - build/windows/Win32/Lib/distutils/command/config.py \ - build/windows/Win32/Lib/distutils/command/install.py \ - build/windows/Win32/Lib/distutils/command/install_data.py \ - build/windows/Win32/Lib/distutils/command/install_egg_info.py \ - build/windows/Win32/Lib/distutils/command/install_headers.py \ - build/windows/Win32/Lib/distutils/command/install_lib.py \ - build/windows/Win32/Lib/distutils/command/install_scripts.py \ - build/windows/Win32/Lib/distutils/command/register.py \ - build/windows/Win32/Lib/distutils/command/sdist.py \ - build/windows/Win32/Lib/distutils/command/upload.py \ - build/windows/Win32/Lib/distutils/config.py \ - build/windows/Win32/Lib/distutils/core.py \ - build/windows/Win32/Lib/distutils/cygwinccompiler.py \ - build/windows/Win32/Lib/distutils/debug.py \ - build/windows/Win32/Lib/distutils/dep_util.py \ - build/windows/Win32/Lib/distutils/dir_util.py \ - build/windows/Win32/Lib/distutils/dist.py \ - build/windows/Win32/Lib/distutils/errors.py \ - build/windows/Win32/Lib/distutils/extension.py \ - build/windows/Win32/Lib/distutils/fancy_getopt.py \ - build/windows/Win32/Lib/distutils/file_util.py \ - build/windows/Win32/Lib/distutils/filelist.py \ - build/windows/Win32/Lib/distutils/log.py \ - build/windows/Win32/Lib/distutils/msvc9compiler.py \ - build/windows/Win32/Lib/distutils/msvccompiler.py \ - build/windows/Win32/Lib/distutils/spawn.py \ - build/windows/Win32/Lib/distutils/sysconfig.py \ - build/windows/Win32/Lib/distutils/tests/__init__.py \ - build/windows/Win32/Lib/distutils/tests/support.py \ - build/windows/Win32/Lib/distutils/tests/test_archive_util.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_dumb.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_msi.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_rpm.py \ - build/windows/Win32/Lib/distutils/tests/test_bdist_wininst.py \ - build/windows/Win32/Lib/distutils/tests/test_build.py \ - build/windows/Win32/Lib/distutils/tests/test_build_clib.py \ - build/windows/Win32/Lib/distutils/tests/test_build_ext.py \ - build/windows/Win32/Lib/distutils/tests/test_build_py.py \ - build/windows/Win32/Lib/distutils/tests/test_build_scripts.py \ - build/windows/Win32/Lib/distutils/tests/test_check.py \ - build/windows/Win32/Lib/distutils/tests/test_clean.py \ - build/windows/Win32/Lib/distutils/tests/test_cmd.py \ - build/windows/Win32/Lib/distutils/tests/test_config.py \ - build/windows/Win32/Lib/distutils/tests/test_config_cmd.py \ - build/windows/Win32/Lib/distutils/tests/test_core.py \ - build/windows/Win32/Lib/distutils/tests/test_cygwinccompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_dep_util.py \ - build/windows/Win32/Lib/distutils/tests/test_dir_util.py \ - build/windows/Win32/Lib/distutils/tests/test_dist.py \ - build/windows/Win32/Lib/distutils/tests/test_extension.py \ - build/windows/Win32/Lib/distutils/tests/test_file_util.py \ - build/windows/Win32/Lib/distutils/tests/test_filelist.py \ - build/windows/Win32/Lib/distutils/tests/test_install.py \ - build/windows/Win32/Lib/distutils/tests/test_install_data.py \ - build/windows/Win32/Lib/distutils/tests/test_install_headers.py \ - build/windows/Win32/Lib/distutils/tests/test_install_lib.py \ - build/windows/Win32/Lib/distutils/tests/test_install_scripts.py \ - build/windows/Win32/Lib/distutils/tests/test_log.py \ - build/windows/Win32/Lib/distutils/tests/test_msvc9compiler.py \ - build/windows/Win32/Lib/distutils/tests/test_msvccompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_register.py \ - build/windows/Win32/Lib/distutils/tests/test_sdist.py \ - build/windows/Win32/Lib/distutils/tests/test_spawn.py \ - build/windows/Win32/Lib/distutils/tests/test_sysconfig.py \ - build/windows/Win32/Lib/distutils/tests/test_text_file.py \ - build/windows/Win32/Lib/distutils/tests/test_unixccompiler.py \ - build/windows/Win32/Lib/distutils/tests/test_upload.py \ - build/windows/Win32/Lib/distutils/tests/test_util.py \ - build/windows/Win32/Lib/distutils/tests/test_version.py \ - build/windows/Win32/Lib/distutils/tests/test_versionpredicate.py \ - build/windows/Win32/Lib/distutils/text_file.py \ - build/windows/Win32/Lib/distutils/unixccompiler.py \ - build/windows/Win32/Lib/distutils/util.py \ - build/windows/Win32/Lib/distutils/version.py \ - build/windows/Win32/Lib/distutils/versionpredicate.py \ build/windows/Win32/Lib/doctest.py \ build/windows/Win32/Lib/dummy_threading.py \ build/windows/Win32/Lib/email/__init__.py \ @@ -2776,7 +2640,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/encodings/cp424.py \ build/windows/Win32/Lib/encodings/cp437.py \ build/windows/Win32/Lib/encodings/cp500.py \ - build/windows/Win32/Lib/encodings/cp65001.py \ build/windows/Win32/Lib/encodings/cp720.py \ build/windows/Win32/Lib/encodings/cp737.py \ build/windows/Win32/Lib/encodings/cp775.py \ @@ -2863,7 +2726,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/encodings/tis_620.py \ build/windows/Win32/Lib/encodings/undefined.py \ build/windows/Win32/Lib/encodings/unicode_escape.py \ - build/windows/Win32/Lib/encodings/unicode_internal.py \ build/windows/Win32/Lib/encodings/utf_16.py \ build/windows/Win32/Lib/encodings/utf_16_be.py \ build/windows/Win32/Lib/encodings/utf_16_le.py \ @@ -2875,9 +2737,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/encodings/utf_8_sig.py \ build/windows/Win32/Lib/encodings/uu_codec.py \ build/windows/Win32/Lib/encodings/zlib_codec.py \ - build/windows/Win32/Lib/ensurepip/__init__.py \ - build/windows/Win32/Lib/ensurepip/__main__.py \ - build/windows/Win32/Lib/ensurepip/_uninstall.py \ build/windows/Win32/Lib/enum.py \ build/windows/Win32/Lib/filecmp.py \ build/windows/Win32/Lib/fileinput.py \ @@ -2903,7 +2762,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/http/cookiejar.py \ build/windows/Win32/Lib/http/cookies.py \ build/windows/Win32/Lib/http/server.py \ - build/windows/Win32/Lib/imaplib.py \ build/windows/Win32/Lib/imghdr.py \ build/windows/Win32/Lib/imp.py \ build/windows/Win32/Lib/importlib/__init__.py \ @@ -2911,6 +2769,7 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/importlib/_bootstrap_external.py \ build/windows/Win32/Lib/importlib/abc.py \ build/windows/Win32/Lib/importlib/machinery.py \ + build/windows/Win32/Lib/importlib/metadata.py \ build/windows/Win32/Lib/importlib/resources.py \ build/windows/Win32/Lib/importlib/util.py \ build/windows/Win32/Lib/inspect.py \ @@ -2928,7 +2787,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/logging/config.py \ build/windows/Win32/Lib/logging/handlers.py \ build/windows/Win32/Lib/lzma.py \ - build/windows/Win32/Lib/macpath.py \ build/windows/Win32/Lib/mailbox.py \ build/windows/Win32/Lib/mailcap.py \ build/windows/Win32/Lib/mimetypes.py \ @@ -2937,28 +2795,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/msilib/schema.py \ build/windows/Win32/Lib/msilib/sequence.py \ build/windows/Win32/Lib/msilib/text.py \ - build/windows/Win32/Lib/multiprocessing/__init__.py \ - build/windows/Win32/Lib/multiprocessing/connection.py \ - build/windows/Win32/Lib/multiprocessing/context.py \ - build/windows/Win32/Lib/multiprocessing/dummy/__init__.py \ - build/windows/Win32/Lib/multiprocessing/dummy/connection.py \ - build/windows/Win32/Lib/multiprocessing/forkserver.py \ - build/windows/Win32/Lib/multiprocessing/heap.py \ - build/windows/Win32/Lib/multiprocessing/managers.py \ - build/windows/Win32/Lib/multiprocessing/pool.py \ - build/windows/Win32/Lib/multiprocessing/popen_fork.py \ - build/windows/Win32/Lib/multiprocessing/popen_forkserver.py \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_posix.py \ - build/windows/Win32/Lib/multiprocessing/popen_spawn_win32.py \ - build/windows/Win32/Lib/multiprocessing/process.py \ - build/windows/Win32/Lib/multiprocessing/queues.py \ - build/windows/Win32/Lib/multiprocessing/reduction.py \ - build/windows/Win32/Lib/multiprocessing/resource_sharer.py \ - build/windows/Win32/Lib/multiprocessing/semaphore_tracker.py \ - build/windows/Win32/Lib/multiprocessing/sharedctypes.py \ - build/windows/Win32/Lib/multiprocessing/spawn.py \ - build/windows/Win32/Lib/multiprocessing/synchronize.py \ - build/windows/Win32/Lib/multiprocessing/util.py \ build/windows/Win32/Lib/netrc.py \ build/windows/Win32/Lib/nntplib.py \ build/windows/Win32/Lib/ntpath.py \ @@ -2985,8 +2821,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/py_compile.py \ build/windows/Win32/Lib/pyclbr.py \ build/windows/Win32/Lib/pydoc.py \ - build/windows/Win32/Lib/pydoc_data/__init__.py \ - build/windows/Win32/Lib/pydoc_data/topics.py \ build/windows/Win32/Lib/queue.py \ build/windows/Win32/Lib/quopri.py \ build/windows/Win32/Lib/random.py \ @@ -3010,16 +2844,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/sqlite3/__init__.py \ build/windows/Win32/Lib/sqlite3/dbapi2.py \ build/windows/Win32/Lib/sqlite3/dump.py \ - build/windows/Win32/Lib/sqlite3/test/__init__.py \ - build/windows/Win32/Lib/sqlite3/test/backup.py \ - build/windows/Win32/Lib/sqlite3/test/dbapi.py \ - build/windows/Win32/Lib/sqlite3/test/dump.py \ - build/windows/Win32/Lib/sqlite3/test/factory.py \ - build/windows/Win32/Lib/sqlite3/test/hooks.py \ - build/windows/Win32/Lib/sqlite3/test/regression.py \ - build/windows/Win32/Lib/sqlite3/test/transactions.py \ - build/windows/Win32/Lib/sqlite3/test/types.py \ - build/windows/Win32/Lib/sqlite3/test/userfunctions.py \ build/windows/Win32/Lib/sre_compile.py \ build/windows/Win32/Lib/sre_constants.py \ build/windows/Win32/Lib/sre_parse.py \ @@ -3048,48 +2872,8 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/traceback.py \ build/windows/Win32/Lib/tracemalloc.py \ build/windows/Win32/Lib/tty.py \ - build/windows/Win32/Lib/turtle.py \ build/windows/Win32/Lib/types.py \ build/windows/Win32/Lib/typing.py \ - build/windows/Win32/Lib/unittest/__init__.py \ - build/windows/Win32/Lib/unittest/__main__.py \ - build/windows/Win32/Lib/unittest/case.py \ - build/windows/Win32/Lib/unittest/loader.py \ - build/windows/Win32/Lib/unittest/main.py \ - build/windows/Win32/Lib/unittest/mock.py \ - build/windows/Win32/Lib/unittest/result.py \ - build/windows/Win32/Lib/unittest/runner.py \ - build/windows/Win32/Lib/unittest/signals.py \ - build/windows/Win32/Lib/unittest/suite.py \ - build/windows/Win32/Lib/unittest/test/__init__.py \ - build/windows/Win32/Lib/unittest/test/__main__.py \ - build/windows/Win32/Lib/unittest/test/_test_warnings.py \ - build/windows/Win32/Lib/unittest/test/dummy.py \ - build/windows/Win32/Lib/unittest/test/support.py \ - build/windows/Win32/Lib/unittest/test/test_assertions.py \ - build/windows/Win32/Lib/unittest/test/test_break.py \ - build/windows/Win32/Lib/unittest/test/test_case.py \ - build/windows/Win32/Lib/unittest/test/test_discovery.py \ - build/windows/Win32/Lib/unittest/test/test_functiontestcase.py \ - build/windows/Win32/Lib/unittest/test/test_loader.py \ - build/windows/Win32/Lib/unittest/test/test_program.py \ - build/windows/Win32/Lib/unittest/test/test_result.py \ - build/windows/Win32/Lib/unittest/test/test_runner.py \ - build/windows/Win32/Lib/unittest/test/test_setups.py \ - build/windows/Win32/Lib/unittest/test/test_skipping.py \ - build/windows/Win32/Lib/unittest/test/test_suite.py \ - build/windows/Win32/Lib/unittest/test/testmock/__init__.py \ - build/windows/Win32/Lib/unittest/test/testmock/__main__.py \ - build/windows/Win32/Lib/unittest/test/testmock/support.py \ - build/windows/Win32/Lib/unittest/test/testmock/testcallable.py \ - build/windows/Win32/Lib/unittest/test/testmock/testhelpers.py \ - build/windows/Win32/Lib/unittest/test/testmock/testmagicmethods.py \ - build/windows/Win32/Lib/unittest/test/testmock/testmock.py \ - build/windows/Win32/Lib/unittest/test/testmock/testpatch.py \ - build/windows/Win32/Lib/unittest/test/testmock/testsealable.py \ - build/windows/Win32/Lib/unittest/test/testmock/testsentinel.py \ - build/windows/Win32/Lib/unittest/test/testmock/testwith.py \ - build/windows/Win32/Lib/unittest/util.py \ build/windows/Win32/Lib/urllib/__init__.py \ build/windows/Win32/Lib/urllib/error.py \ build/windows/Win32/Lib/urllib/parse.py \ @@ -3098,18 +2882,10 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/urllib/robotparser.py \ build/windows/Win32/Lib/uu.py \ build/windows/Win32/Lib/uuid.py \ - build/windows/Win32/Lib/venv/__init__.py \ - build/windows/Win32/Lib/venv/__main__.py \ build/windows/Win32/Lib/warnings.py \ build/windows/Win32/Lib/wave.py \ build/windows/Win32/Lib/weakref.py \ build/windows/Win32/Lib/webbrowser.py \ - build/windows/Win32/Lib/wsgiref/__init__.py \ - build/windows/Win32/Lib/wsgiref/handlers.py \ - build/windows/Win32/Lib/wsgiref/headers.py \ - build/windows/Win32/Lib/wsgiref/simple_server.py \ - build/windows/Win32/Lib/wsgiref/util.py \ - build/windows/Win32/Lib/wsgiref/validate.py \ build/windows/Win32/Lib/xdrlib.py \ build/windows/Win32/Lib/xml/__init__.py \ build/windows/Win32/Lib/xml/dom/NodeFilter.py \ @@ -3137,677 +2913,443 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_WIN32 = \ build/windows/Win32/Lib/xmlrpc/client.py \ build/windows/Win32/Lib/xmlrpc/server.py \ build/windows/Win32/Lib/zipapp.py \ - build/windows/Win32/Lib/zipfile.py + build/windows/Win32/Lib/zipfile.py \ + build/windows/Win32/Lib/zipimport.py SCRIPT_TARGETS_PYC_PRIVATE_WIN_WIN32 = \ - build/windows/Win32/Lib/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/code.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/header.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/io.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/os.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/random.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/re.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/site.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/string.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/this.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/token.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/windows/Win32/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc + build/windows/Win32/Lib/__pycache__/__future__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/__phello__.foo.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_bootlocale.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_collections_abc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_compat_pickle.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_compression.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_dummy_thread.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_markupbase.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_osx_support.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_py_abc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_pydecimal.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_pyio.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_strptime.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_threading_local.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/_weakrefset.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/abc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/aifc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/antigravity.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/argparse.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ast.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/asynchat.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/constants.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/events.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/futures.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/locks.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/log.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/queues.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/runners.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/streams.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/transports.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/asyncore.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/base64.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bdb.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/binhex.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bisect.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/bz2.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cProfile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/calendar.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cgi.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cgitb.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/chunk.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/cmd.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/code.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/codecs.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/codeop.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/collections/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/collections/__pycache__/abc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/colorsys.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/compileall.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/configparser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/contextlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/contextvars.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/copy.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/copyreg.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/crypt.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/csv.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/util.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/has_key.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/panel.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/curses/__pycache__/textpad.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dataclasses.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/datetime.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/decimal.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/difflib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dis.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/doctest.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/dummy_threading.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/_policybase.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/base64mime.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/charset.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/contentmanager.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/encoders.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/errors.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/feedparser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/generator.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/header.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/headerregistry.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/iterators.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/message.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/application.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/audio.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/base.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/image.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/message.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/mime/__pycache__/text.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/parser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/policy.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/quoprimime.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/email/__pycache__/utils.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/aliases.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/big5.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/charmap.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp037.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp273.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp424.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp437.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp500.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp720.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp737.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp775.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp850.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp852.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp855.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp856.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp857.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp858.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp860.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp861.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp862.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp863.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp864.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp865.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp866.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp869.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp874.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp875.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp932.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp949.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/cp950.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/gbk.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/hz.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/idna.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/johab.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/oem.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/palmos.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/punycode.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/undefined.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/enum.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/filecmp.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fileinput.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fnmatch.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/formatter.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/fractions.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ftplib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/functools.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/genericpath.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/getopt.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/getpass.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/gettext.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/glob.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/gzip.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/hashlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/heapq.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/hmac.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/html/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/html/__pycache__/entities.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/html/__pycache__/parser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/client.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/cookiejar.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/cookies.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/http/__pycache__/server.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imghdr.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/imp.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/abc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/machinery.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/metadata.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/resources.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/importlib/__pycache__/util.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/inspect.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/io.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ipaddress.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/decoder.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/encoder.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/scanner.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/json/__pycache__/tool.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/keyword.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/linecache.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/locale.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/logging/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/logging/__pycache__/config.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/logging/__pycache__/handlers.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/lzma.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mailbox.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mailcap.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/mimetypes.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/modulefinder.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/schema.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/sequence.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/msilib/__pycache__/text.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/netrc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/nntplib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ntpath.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/nturl2path.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/numbers.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/opcode.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/operator.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/optparse.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/os.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pathlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pdb.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pickle.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pickletools.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pipes.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pkgutil.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/platform.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/plistlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/poplib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/posixpath.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pprint.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/profile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pstats.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pty.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/py_compile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pyclbr.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/pydoc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/queue.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/quopri.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/random.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/re.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/reprlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/rlcompleter.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/runpy.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sched.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/secrets.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/selectors.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shelve.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shlex.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/shutil.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/signal.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/site.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/smtpd.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/smtplib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sndhdr.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/socket.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/socketserver.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_compile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_constants.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sre_parse.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/ssl.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/stat.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/statistics.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/string.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/stringprep.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/struct.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sunau.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/symbol.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/symtable.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/sysconfig.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tabnanny.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tarfile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/telnetlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tempfile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/textwrap.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/this.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/threading.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/timeit.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/token.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tokenize.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/trace.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/traceback.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tracemalloc.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/tty.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/types.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/typing.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/error.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/parse.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/request.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/response.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/uu.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/uuid.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/warnings.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/wave.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/weakref.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/webbrowser.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/xdrlib.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipapp.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipfile.cpython-38.opt-1.pyc \ + build/windows/Win32/Lib/__pycache__/zipimport.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -3843,6 +3385,7 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/ast.py \ build/windows/x64/Lib/asynchat.py \ build/windows/x64/Lib/asyncio/__init__.py \ + build/windows/x64/Lib/asyncio/__main__.py \ build/windows/x64/Lib/asyncio/base_events.py \ build/windows/x64/Lib/asyncio/base_futures.py \ build/windows/x64/Lib/asyncio/base_subprocess.py \ @@ -3850,6 +3393,7 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/asyncio/constants.py \ build/windows/x64/Lib/asyncio/coroutines.py \ build/windows/x64/Lib/asyncio/events.py \ + build/windows/x64/Lib/asyncio/exceptions.py \ build/windows/x64/Lib/asyncio/format_helpers.py \ build/windows/x64/Lib/asyncio/futures.py \ build/windows/x64/Lib/asyncio/locks.py \ @@ -3860,10 +3404,12 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/asyncio/runners.py \ build/windows/x64/Lib/asyncio/selector_events.py \ build/windows/x64/Lib/asyncio/sslproto.py \ + build/windows/x64/Lib/asyncio/staggered.py \ build/windows/x64/Lib/asyncio/streams.py \ build/windows/x64/Lib/asyncio/subprocess.py \ build/windows/x64/Lib/asyncio/tasks.py \ build/windows/x64/Lib/asyncio/transports.py \ + build/windows/x64/Lib/asyncio/trsock.py \ build/windows/x64/Lib/asyncio/unix_events.py \ build/windows/x64/Lib/asyncio/windows_events.py \ build/windows/x64/Lib/asyncio/windows_utils.py \ @@ -3905,59 +3451,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/ctypes/macholib/dyld.py \ build/windows/x64/Lib/ctypes/macholib/dylib.py \ build/windows/x64/Lib/ctypes/macholib/framework.py \ - build/windows/x64/Lib/ctypes/test/__init__.py \ - build/windows/x64/Lib/ctypes/test/__main__.py \ - build/windows/x64/Lib/ctypes/test/test_anon.py \ - build/windows/x64/Lib/ctypes/test/test_array_in_pointer.py \ - build/windows/x64/Lib/ctypes/test/test_arrays.py \ - build/windows/x64/Lib/ctypes/test/test_as_parameter.py \ - build/windows/x64/Lib/ctypes/test/test_bitfields.py \ - build/windows/x64/Lib/ctypes/test/test_buffers.py \ - build/windows/x64/Lib/ctypes/test/test_bytes.py \ - build/windows/x64/Lib/ctypes/test/test_byteswap.py \ - build/windows/x64/Lib/ctypes/test/test_callbacks.py \ - build/windows/x64/Lib/ctypes/test/test_cast.py \ - build/windows/x64/Lib/ctypes/test/test_cfuncs.py \ - build/windows/x64/Lib/ctypes/test/test_checkretval.py \ - build/windows/x64/Lib/ctypes/test/test_delattr.py \ - build/windows/x64/Lib/ctypes/test/test_errno.py \ - build/windows/x64/Lib/ctypes/test/test_find.py \ - build/windows/x64/Lib/ctypes/test/test_frombuffer.py \ - build/windows/x64/Lib/ctypes/test/test_funcptr.py \ - build/windows/x64/Lib/ctypes/test/test_functions.py \ - build/windows/x64/Lib/ctypes/test/test_incomplete.py \ - build/windows/x64/Lib/ctypes/test/test_init.py \ - build/windows/x64/Lib/ctypes/test/test_internals.py \ - build/windows/x64/Lib/ctypes/test/test_keeprefs.py \ - build/windows/x64/Lib/ctypes/test/test_libc.py \ - build/windows/x64/Lib/ctypes/test/test_loading.py \ - build/windows/x64/Lib/ctypes/test/test_macholib.py \ - build/windows/x64/Lib/ctypes/test/test_memfunctions.py \ - build/windows/x64/Lib/ctypes/test/test_numbers.py \ - build/windows/x64/Lib/ctypes/test/test_objects.py \ - build/windows/x64/Lib/ctypes/test/test_parameters.py \ - build/windows/x64/Lib/ctypes/test/test_pep3118.py \ - build/windows/x64/Lib/ctypes/test/test_pickling.py \ - build/windows/x64/Lib/ctypes/test/test_pointers.py \ - build/windows/x64/Lib/ctypes/test/test_prototypes.py \ - build/windows/x64/Lib/ctypes/test/test_python_api.py \ - build/windows/x64/Lib/ctypes/test/test_random_things.py \ - build/windows/x64/Lib/ctypes/test/test_refcounts.py \ - build/windows/x64/Lib/ctypes/test/test_repr.py \ - build/windows/x64/Lib/ctypes/test/test_returnfuncptrs.py \ - build/windows/x64/Lib/ctypes/test/test_simplesubclasses.py \ - build/windows/x64/Lib/ctypes/test/test_sizes.py \ - build/windows/x64/Lib/ctypes/test/test_slicing.py \ - build/windows/x64/Lib/ctypes/test/test_stringptr.py \ - build/windows/x64/Lib/ctypes/test/test_strings.py \ - build/windows/x64/Lib/ctypes/test/test_struct_fields.py \ - build/windows/x64/Lib/ctypes/test/test_structures.py \ - build/windows/x64/Lib/ctypes/test/test_unaligned_structures.py \ - build/windows/x64/Lib/ctypes/test/test_unicode.py \ - build/windows/x64/Lib/ctypes/test/test_values.py \ - build/windows/x64/Lib/ctypes/test/test_varsize_struct.py \ - build/windows/x64/Lib/ctypes/test/test_win32.py \ - build/windows/x64/Lib/ctypes/test/test_wintypes.py \ build/windows/x64/Lib/ctypes/util.py \ build/windows/x64/Lib/ctypes/wintypes.py \ build/windows/x64/Lib/curses/__init__.py \ @@ -3967,108 +3460,9 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/curses/textpad.py \ build/windows/x64/Lib/dataclasses.py \ build/windows/x64/Lib/datetime.py \ - build/windows/x64/Lib/dbm/__init__.py \ - build/windows/x64/Lib/dbm/dumb.py \ - build/windows/x64/Lib/dbm/gnu.py \ - build/windows/x64/Lib/dbm/ndbm.py \ build/windows/x64/Lib/decimal.py \ build/windows/x64/Lib/difflib.py \ build/windows/x64/Lib/dis.py \ - build/windows/x64/Lib/distutils/__init__.py \ - build/windows/x64/Lib/distutils/_msvccompiler.py \ - build/windows/x64/Lib/distutils/archive_util.py \ - build/windows/x64/Lib/distutils/bcppcompiler.py \ - build/windows/x64/Lib/distutils/ccompiler.py \ - build/windows/x64/Lib/distutils/cmd.py \ - build/windows/x64/Lib/distutils/command/__init__.py \ - build/windows/x64/Lib/distutils/command/bdist.py \ - build/windows/x64/Lib/distutils/command/bdist_dumb.py \ - build/windows/x64/Lib/distutils/command/bdist_msi.py \ - build/windows/x64/Lib/distutils/command/bdist_rpm.py \ - build/windows/x64/Lib/distutils/command/bdist_wininst.py \ - build/windows/x64/Lib/distutils/command/build.py \ - build/windows/x64/Lib/distutils/command/build_clib.py \ - build/windows/x64/Lib/distutils/command/build_ext.py \ - build/windows/x64/Lib/distutils/command/build_py.py \ - build/windows/x64/Lib/distutils/command/build_scripts.py \ - build/windows/x64/Lib/distutils/command/check.py \ - build/windows/x64/Lib/distutils/command/clean.py \ - build/windows/x64/Lib/distutils/command/config.py \ - build/windows/x64/Lib/distutils/command/install.py \ - build/windows/x64/Lib/distutils/command/install_data.py \ - build/windows/x64/Lib/distutils/command/install_egg_info.py \ - build/windows/x64/Lib/distutils/command/install_headers.py \ - build/windows/x64/Lib/distutils/command/install_lib.py \ - build/windows/x64/Lib/distutils/command/install_scripts.py \ - build/windows/x64/Lib/distutils/command/register.py \ - build/windows/x64/Lib/distutils/command/sdist.py \ - build/windows/x64/Lib/distutils/command/upload.py \ - build/windows/x64/Lib/distutils/config.py \ - build/windows/x64/Lib/distutils/core.py \ - build/windows/x64/Lib/distutils/cygwinccompiler.py \ - build/windows/x64/Lib/distutils/debug.py \ - build/windows/x64/Lib/distutils/dep_util.py \ - build/windows/x64/Lib/distutils/dir_util.py \ - build/windows/x64/Lib/distutils/dist.py \ - build/windows/x64/Lib/distutils/errors.py \ - build/windows/x64/Lib/distutils/extension.py \ - build/windows/x64/Lib/distutils/fancy_getopt.py \ - build/windows/x64/Lib/distutils/file_util.py \ - build/windows/x64/Lib/distutils/filelist.py \ - build/windows/x64/Lib/distutils/log.py \ - build/windows/x64/Lib/distutils/msvc9compiler.py \ - build/windows/x64/Lib/distutils/msvccompiler.py \ - build/windows/x64/Lib/distutils/spawn.py \ - build/windows/x64/Lib/distutils/sysconfig.py \ - build/windows/x64/Lib/distutils/tests/__init__.py \ - build/windows/x64/Lib/distutils/tests/support.py \ - build/windows/x64/Lib/distutils/tests/test_archive_util.py \ - build/windows/x64/Lib/distutils/tests/test_bdist.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_dumb.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_msi.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_rpm.py \ - build/windows/x64/Lib/distutils/tests/test_bdist_wininst.py \ - build/windows/x64/Lib/distutils/tests/test_build.py \ - build/windows/x64/Lib/distutils/tests/test_build_clib.py \ - build/windows/x64/Lib/distutils/tests/test_build_ext.py \ - build/windows/x64/Lib/distutils/tests/test_build_py.py \ - build/windows/x64/Lib/distutils/tests/test_build_scripts.py \ - build/windows/x64/Lib/distutils/tests/test_check.py \ - build/windows/x64/Lib/distutils/tests/test_clean.py \ - build/windows/x64/Lib/distutils/tests/test_cmd.py \ - build/windows/x64/Lib/distutils/tests/test_config.py \ - build/windows/x64/Lib/distutils/tests/test_config_cmd.py \ - build/windows/x64/Lib/distutils/tests/test_core.py \ - build/windows/x64/Lib/distutils/tests/test_cygwinccompiler.py \ - build/windows/x64/Lib/distutils/tests/test_dep_util.py \ - build/windows/x64/Lib/distutils/tests/test_dir_util.py \ - build/windows/x64/Lib/distutils/tests/test_dist.py \ - build/windows/x64/Lib/distutils/tests/test_extension.py \ - build/windows/x64/Lib/distutils/tests/test_file_util.py \ - build/windows/x64/Lib/distutils/tests/test_filelist.py \ - build/windows/x64/Lib/distutils/tests/test_install.py \ - build/windows/x64/Lib/distutils/tests/test_install_data.py \ - build/windows/x64/Lib/distutils/tests/test_install_headers.py \ - build/windows/x64/Lib/distutils/tests/test_install_lib.py \ - build/windows/x64/Lib/distutils/tests/test_install_scripts.py \ - build/windows/x64/Lib/distutils/tests/test_log.py \ - build/windows/x64/Lib/distutils/tests/test_msvc9compiler.py \ - build/windows/x64/Lib/distutils/tests/test_msvccompiler.py \ - build/windows/x64/Lib/distutils/tests/test_register.py \ - build/windows/x64/Lib/distutils/tests/test_sdist.py \ - build/windows/x64/Lib/distutils/tests/test_spawn.py \ - build/windows/x64/Lib/distutils/tests/test_sysconfig.py \ - build/windows/x64/Lib/distutils/tests/test_text_file.py \ - build/windows/x64/Lib/distutils/tests/test_unixccompiler.py \ - build/windows/x64/Lib/distutils/tests/test_upload.py \ - build/windows/x64/Lib/distutils/tests/test_util.py \ - build/windows/x64/Lib/distutils/tests/test_version.py \ - build/windows/x64/Lib/distutils/tests/test_versionpredicate.py \ - build/windows/x64/Lib/distutils/text_file.py \ - build/windows/x64/Lib/distutils/unixccompiler.py \ - build/windows/x64/Lib/distutils/util.py \ - build/windows/x64/Lib/distutils/version.py \ - build/windows/x64/Lib/distutils/versionpredicate.py \ build/windows/x64/Lib/doctest.py \ build/windows/x64/Lib/dummy_threading.py \ build/windows/x64/Lib/email/__init__.py \ @@ -4126,7 +3520,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/encodings/cp424.py \ build/windows/x64/Lib/encodings/cp437.py \ build/windows/x64/Lib/encodings/cp500.py \ - build/windows/x64/Lib/encodings/cp65001.py \ build/windows/x64/Lib/encodings/cp720.py \ build/windows/x64/Lib/encodings/cp737.py \ build/windows/x64/Lib/encodings/cp775.py \ @@ -4213,7 +3606,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/encodings/tis_620.py \ build/windows/x64/Lib/encodings/undefined.py \ build/windows/x64/Lib/encodings/unicode_escape.py \ - build/windows/x64/Lib/encodings/unicode_internal.py \ build/windows/x64/Lib/encodings/utf_16.py \ build/windows/x64/Lib/encodings/utf_16_be.py \ build/windows/x64/Lib/encodings/utf_16_le.py \ @@ -4225,9 +3617,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/encodings/utf_8_sig.py \ build/windows/x64/Lib/encodings/uu_codec.py \ build/windows/x64/Lib/encodings/zlib_codec.py \ - build/windows/x64/Lib/ensurepip/__init__.py \ - build/windows/x64/Lib/ensurepip/__main__.py \ - build/windows/x64/Lib/ensurepip/_uninstall.py \ build/windows/x64/Lib/enum.py \ build/windows/x64/Lib/filecmp.py \ build/windows/x64/Lib/fileinput.py \ @@ -4253,7 +3642,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/http/cookiejar.py \ build/windows/x64/Lib/http/cookies.py \ build/windows/x64/Lib/http/server.py \ - build/windows/x64/Lib/imaplib.py \ build/windows/x64/Lib/imghdr.py \ build/windows/x64/Lib/imp.py \ build/windows/x64/Lib/importlib/__init__.py \ @@ -4261,6 +3649,7 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/importlib/_bootstrap_external.py \ build/windows/x64/Lib/importlib/abc.py \ build/windows/x64/Lib/importlib/machinery.py \ + build/windows/x64/Lib/importlib/metadata.py \ build/windows/x64/Lib/importlib/resources.py \ build/windows/x64/Lib/importlib/util.py \ build/windows/x64/Lib/inspect.py \ @@ -4278,7 +3667,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/logging/config.py \ build/windows/x64/Lib/logging/handlers.py \ build/windows/x64/Lib/lzma.py \ - build/windows/x64/Lib/macpath.py \ build/windows/x64/Lib/mailbox.py \ build/windows/x64/Lib/mailcap.py \ build/windows/x64/Lib/mimetypes.py \ @@ -4287,28 +3675,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/msilib/schema.py \ build/windows/x64/Lib/msilib/sequence.py \ build/windows/x64/Lib/msilib/text.py \ - build/windows/x64/Lib/multiprocessing/__init__.py \ - build/windows/x64/Lib/multiprocessing/connection.py \ - build/windows/x64/Lib/multiprocessing/context.py \ - build/windows/x64/Lib/multiprocessing/dummy/__init__.py \ - build/windows/x64/Lib/multiprocessing/dummy/connection.py \ - build/windows/x64/Lib/multiprocessing/forkserver.py \ - build/windows/x64/Lib/multiprocessing/heap.py \ - build/windows/x64/Lib/multiprocessing/managers.py \ - build/windows/x64/Lib/multiprocessing/pool.py \ - build/windows/x64/Lib/multiprocessing/popen_fork.py \ - build/windows/x64/Lib/multiprocessing/popen_forkserver.py \ - build/windows/x64/Lib/multiprocessing/popen_spawn_posix.py \ - build/windows/x64/Lib/multiprocessing/popen_spawn_win32.py \ - build/windows/x64/Lib/multiprocessing/process.py \ - build/windows/x64/Lib/multiprocessing/queues.py \ - build/windows/x64/Lib/multiprocessing/reduction.py \ - build/windows/x64/Lib/multiprocessing/resource_sharer.py \ - build/windows/x64/Lib/multiprocessing/semaphore_tracker.py \ - build/windows/x64/Lib/multiprocessing/sharedctypes.py \ - build/windows/x64/Lib/multiprocessing/spawn.py \ - build/windows/x64/Lib/multiprocessing/synchronize.py \ - build/windows/x64/Lib/multiprocessing/util.py \ build/windows/x64/Lib/netrc.py \ build/windows/x64/Lib/nntplib.py \ build/windows/x64/Lib/ntpath.py \ @@ -4335,8 +3701,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/py_compile.py \ build/windows/x64/Lib/pyclbr.py \ build/windows/x64/Lib/pydoc.py \ - build/windows/x64/Lib/pydoc_data/__init__.py \ - build/windows/x64/Lib/pydoc_data/topics.py \ build/windows/x64/Lib/queue.py \ build/windows/x64/Lib/quopri.py \ build/windows/x64/Lib/random.py \ @@ -4360,16 +3724,6 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/sqlite3/__init__.py \ build/windows/x64/Lib/sqlite3/dbapi2.py \ build/windows/x64/Lib/sqlite3/dump.py \ - build/windows/x64/Lib/sqlite3/test/__init__.py \ - build/windows/x64/Lib/sqlite3/test/backup.py \ - build/windows/x64/Lib/sqlite3/test/dbapi.py \ - build/windows/x64/Lib/sqlite3/test/dump.py \ - build/windows/x64/Lib/sqlite3/test/factory.py \ - build/windows/x64/Lib/sqlite3/test/hooks.py \ - build/windows/x64/Lib/sqlite3/test/regression.py \ - build/windows/x64/Lib/sqlite3/test/transactions.py \ - build/windows/x64/Lib/sqlite3/test/types.py \ - build/windows/x64/Lib/sqlite3/test/userfunctions.py \ build/windows/x64/Lib/sre_compile.py \ build/windows/x64/Lib/sre_constants.py \ build/windows/x64/Lib/sre_parse.py \ @@ -4398,48 +3752,8 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/traceback.py \ build/windows/x64/Lib/tracemalloc.py \ build/windows/x64/Lib/tty.py \ - build/windows/x64/Lib/turtle.py \ build/windows/x64/Lib/types.py \ build/windows/x64/Lib/typing.py \ - build/windows/x64/Lib/unittest/__init__.py \ - build/windows/x64/Lib/unittest/__main__.py \ - build/windows/x64/Lib/unittest/case.py \ - build/windows/x64/Lib/unittest/loader.py \ - build/windows/x64/Lib/unittest/main.py \ - build/windows/x64/Lib/unittest/mock.py \ - build/windows/x64/Lib/unittest/result.py \ - build/windows/x64/Lib/unittest/runner.py \ - build/windows/x64/Lib/unittest/signals.py \ - build/windows/x64/Lib/unittest/suite.py \ - build/windows/x64/Lib/unittest/test/__init__.py \ - build/windows/x64/Lib/unittest/test/__main__.py \ - build/windows/x64/Lib/unittest/test/_test_warnings.py \ - build/windows/x64/Lib/unittest/test/dummy.py \ - build/windows/x64/Lib/unittest/test/support.py \ - build/windows/x64/Lib/unittest/test/test_assertions.py \ - build/windows/x64/Lib/unittest/test/test_break.py \ - build/windows/x64/Lib/unittest/test/test_case.py \ - build/windows/x64/Lib/unittest/test/test_discovery.py \ - build/windows/x64/Lib/unittest/test/test_functiontestcase.py \ - build/windows/x64/Lib/unittest/test/test_loader.py \ - build/windows/x64/Lib/unittest/test/test_program.py \ - build/windows/x64/Lib/unittest/test/test_result.py \ - build/windows/x64/Lib/unittest/test/test_runner.py \ - build/windows/x64/Lib/unittest/test/test_setups.py \ - build/windows/x64/Lib/unittest/test/test_skipping.py \ - build/windows/x64/Lib/unittest/test/test_suite.py \ - build/windows/x64/Lib/unittest/test/testmock/__init__.py \ - build/windows/x64/Lib/unittest/test/testmock/__main__.py \ - build/windows/x64/Lib/unittest/test/testmock/support.py \ - build/windows/x64/Lib/unittest/test/testmock/testcallable.py \ - build/windows/x64/Lib/unittest/test/testmock/testhelpers.py \ - build/windows/x64/Lib/unittest/test/testmock/testmagicmethods.py \ - build/windows/x64/Lib/unittest/test/testmock/testmock.py \ - build/windows/x64/Lib/unittest/test/testmock/testpatch.py \ - build/windows/x64/Lib/unittest/test/testmock/testsealable.py \ - build/windows/x64/Lib/unittest/test/testmock/testsentinel.py \ - build/windows/x64/Lib/unittest/test/testmock/testwith.py \ - build/windows/x64/Lib/unittest/util.py \ build/windows/x64/Lib/urllib/__init__.py \ build/windows/x64/Lib/urllib/error.py \ build/windows/x64/Lib/urllib/parse.py \ @@ -4448,18 +3762,10 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/urllib/robotparser.py \ build/windows/x64/Lib/uu.py \ build/windows/x64/Lib/uuid.py \ - build/windows/x64/Lib/venv/__init__.py \ - build/windows/x64/Lib/venv/__main__.py \ build/windows/x64/Lib/warnings.py \ build/windows/x64/Lib/wave.py \ build/windows/x64/Lib/weakref.py \ build/windows/x64/Lib/webbrowser.py \ - build/windows/x64/Lib/wsgiref/__init__.py \ - build/windows/x64/Lib/wsgiref/handlers.py \ - build/windows/x64/Lib/wsgiref/headers.py \ - build/windows/x64/Lib/wsgiref/simple_server.py \ - build/windows/x64/Lib/wsgiref/util.py \ - build/windows/x64/Lib/wsgiref/validate.py \ build/windows/x64/Lib/xdrlib.py \ build/windows/x64/Lib/xml/__init__.py \ build/windows/x64/Lib/xml/dom/NodeFilter.py \ @@ -4487,677 +3793,443 @@ SCRIPT_TARGETS_PY_PRIVATE_WIN_X64 = \ build/windows/x64/Lib/xmlrpc/client.py \ build/windows/x64/Lib/xmlrpc/server.py \ build/windows/x64/Lib/zipapp.py \ - build/windows/x64/Lib/zipfile.py + build/windows/x64/Lib/zipfile.py \ + build/windows/x64/Lib/zipimport.py SCRIPT_TARGETS_PYC_PRIVATE_WIN_X64 = \ - build/windows/x64/Lib/__pycache__/__future__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_bootlocale.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_collections_abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_compression.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_markupbase.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_osx_support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_py_abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_pydecimal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_pyio.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_strptime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_threading_local.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/_weakrefset.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/aifc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/antigravity.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/argparse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ast.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/asynchat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/asyncore.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/base64.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bdb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/binhex.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bisect.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/bz2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cProfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/calendar.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cgi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cgitb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/chunk.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/code.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/codecs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/codeop.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/collections/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/collections/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/colorsys.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/compileall.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/configparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/contextlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/contextvars.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/copy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/copyreg.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/crypt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/csv.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_anon.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_array_in_pointer.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_arrays.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_as_parameter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_bitfields.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_buffers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_bytes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_byteswap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_callbacks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_cast.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_cfuncs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_checkretval.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_delattr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_errno.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_find.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_frombuffer.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_funcptr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_functions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_incomplete.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_init.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_internals.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_keeprefs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_libc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_loading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_macholib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_memfunctions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_numbers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_objects.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_parameters.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_pep3118.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_pickling.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_pointers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_prototypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_python_api.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_random_things.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_refcounts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_repr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_returnfuncptrs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_simplesubclasses.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_sizes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_slicing.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_stringptr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_strings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_struct_fields.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_structures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_unaligned_structures.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_unicode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_values.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_varsize_struct.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_win32.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/test/__pycache__/test_wintypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/has_key.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/panel.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/curses/__pycache__/textpad.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dataclasses.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/datetime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/dumb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/gnu.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/dbm/__pycache__/ndbm.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/decimal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/difflib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dis.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/archive_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/bcppcompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/ccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_msi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_clib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_ext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_py.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/build_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/check.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/clean.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_data.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_egg_info.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_headers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_lib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/install_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/register.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/sdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/command/__pycache__/upload.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/core.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/debug.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dep_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dir_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/dist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/extension.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/fancy_getopt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/file_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/filelist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_archive_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_dumb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_msi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_rpm.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_bdist_wininst.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_clib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_ext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_py.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_build_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_check.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_clean.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_config_cmd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_core.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_cygwinccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_dep_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_dir_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_dist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_extension.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_file_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_filelist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_data.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_headers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_lib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_install_scripts.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_log.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_msvc9compiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_msvccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_register.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_sdist.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_text_file.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_unixccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_upload.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_version.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/tests/__pycache__/test_versionpredicate.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/text_file.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/unixccompiler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/version.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/distutils/__pycache__/versionpredicate.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/doctest.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/dummy_threading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/_policybase.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/base64mime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/charset.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/encoders.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/errors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/feedparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/generator.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/header.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/iterators.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/application.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/base.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/image.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/message.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/mime/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/policy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/email/__pycache__/utils.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/big5.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp65001.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/hz.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/idna.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/johab.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/oem.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/unicode_internal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ensurepip/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ensurepip/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/ensurepip/__pycache__/_uninstall.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/enum.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/filecmp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fileinput.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fnmatch.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/formatter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/fractions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ftplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/functools.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/genericpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/getopt.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/getpass.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/gettext.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/glob.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/gzip.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/hashlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/heapq.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/hmac.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/html/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/html/__pycache__/entities.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/html/__pycache__/parser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/cookies.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/http/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imaplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imghdr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/imp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/abc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/resources.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/importlib/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/inspect.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/io.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ipaddress.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/decoder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/encoder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/scanner.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/json/__pycache__/tool.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/keyword.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/linecache.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/locale.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/logging/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/logging/__pycache__/config.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/logging/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/lzma.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/macpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mailbox.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mailcap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/mimetypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/modulefinder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/schema.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/msilib/__pycache__/text.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/context.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/dummy/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/dummy/__pycache__/connection.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/forkserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/heap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/managers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/pool.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_fork.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_forkserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_posix.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/popen_spawn_win32.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/process.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/queues.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/reduction.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/resource_sharer.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/semaphore_tracker.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/sharedctypes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/spawn.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/synchronize.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/multiprocessing/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/netrc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/nntplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ntpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/nturl2path.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/numbers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/opcode.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/operator.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/optparse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/os.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pathlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pdb.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pickle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pickletools.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pipes.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pkgutil.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/platform.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/plistlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/poplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/posixpath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pprint.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/profile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pstats.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pty.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/py_compile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pyclbr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/pydoc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/pydoc_data/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/pydoc_data/__pycache__/topics.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/queue.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/quopri.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/random.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/re.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/reprlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/rlcompleter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/runpy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sched.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/secrets.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/selectors.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shelve.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shlex.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/shutil.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/signal.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/site.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/smtpd.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/smtplib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sndhdr.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/socket.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/socketserver.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/backup.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/dbapi.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/dump.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/factory.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/hooks.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/regression.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/transactions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/sqlite3/test/__pycache__/userfunctions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_compile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_constants.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sre_parse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/ssl.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/stat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/statistics.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/string.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/stringprep.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/struct.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/subprocess.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sunau.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/symbol.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/symtable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/sysconfig.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tabnanny.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tarfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/telnetlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tempfile.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/textwrap.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/this.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/threading.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/timeit.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/token.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tokenize.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/trace.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/traceback.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tracemalloc.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/tty.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/turtle.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/types.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/typing.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/case.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/loader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/main.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/mock.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/result.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/runner.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/signals.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/suite.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/_test_warnings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/dummy.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_assertions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_break.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_case.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_discovery.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_functiontestcase.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_loader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_program.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_result.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_runner.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_setups.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_skipping.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/__pycache__/test_suite.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/support.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testcallable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testhelpers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmagicmethods.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testmock.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testpatch.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsealable.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testsentinel.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/test/testmock/__pycache__/testwith.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/unittest/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/error.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/parse.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/request.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/response.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/uu.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/uuid.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/venv/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/venv/__pycache__/__main__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/warnings.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/wave.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/weakref.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/webbrowser.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/handlers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/headers.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/simple_server.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/util.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/wsgiref/__pycache__/validate.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/xdrlib.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/zipapp.cpython-37.opt-1.pyc \ - build/windows/x64/Lib/__pycache__/zipfile.cpython-37.opt-1.pyc + build/windows/x64/Lib/__pycache__/__future__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/__phello__.foo.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_bootlocale.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_collections_abc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_compat_pickle.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_compression.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_dummy_thread.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_markupbase.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_osx_support.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_py_abc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_pydecimal.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_pyio.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_sitebuiltins.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_strptime.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_threading_local.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/_weakrefset.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/abc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/aifc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/antigravity.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/argparse.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ast.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/asynchat.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/__main__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_events.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_futures.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_subprocess.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/base_tasks.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/constants.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/coroutines.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/events.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/exceptions.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/format_helpers.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/futures.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/locks.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/log.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/proactor_events.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/protocols.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/queues.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/runners.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/selector_events.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/sslproto.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/staggered.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/streams.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/tasks.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/transports.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/trsock.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/unix_events.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/windows_events.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/asyncio/__pycache__/windows_utils.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/asyncore.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/base64.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bdb.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/binhex.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bisect.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/bz2.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cProfile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/calendar.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cgi.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cgitb.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/chunk.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/cmd.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/code.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/codecs.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/codeop.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/collections/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/collections/__pycache__/abc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/colorsys.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/compileall.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/concurrent/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/_base.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/process.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/concurrent/futures/__pycache__/thread.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/configparser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/contextlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/contextvars.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/copy.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/copyreg.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/crypt.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/csv.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/_aix.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/_endian.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/dyld.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/dylib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/macholib/__pycache__/framework.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/util.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/ctypes/__pycache__/wintypes.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/has_key.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/panel.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/curses/__pycache__/textpad.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dataclasses.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/datetime.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/decimal.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/difflib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dis.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/doctest.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/dummy_threading.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_encoded_words.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_header_value_parser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_parseaddr.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/_policybase.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/base64mime.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/charset.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/contentmanager.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/encoders.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/errors.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/feedparser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/generator.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/header.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/headerregistry.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/iterators.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/message.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/application.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/audio.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/base.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/image.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/message.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/multipart.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/nonmultipart.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/mime/__pycache__/text.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/parser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/policy.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/quoprimime.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/email/__pycache__/utils.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/aliases.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/ascii.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/base64_codec.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/big5.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/big5hkscs.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/bz2_codec.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/charmap.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp037.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1006.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1026.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1125.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1140.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1250.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1251.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1252.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1253.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1254.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1255.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1256.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1257.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp1258.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp273.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp424.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp437.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp500.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp720.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp737.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp775.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp850.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp852.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp855.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp856.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp857.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp858.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp860.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp861.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp862.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp863.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp864.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp865.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp866.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp869.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp874.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp875.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp932.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp949.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/cp950.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_jis_2004.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_jisx0213.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_jp.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/euc_kr.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/gb18030.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/gb2312.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/gbk.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/hex_codec.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/hp_roman8.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/hz.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/idna.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_1.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_2004.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_3.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_jp_ext.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso2022_kr.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_1.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_10.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_11.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_13.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_14.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_15.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_16.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_2.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_3.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_4.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_5.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_6.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_7.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_8.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/iso8859_9.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/johab.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/koi8_r.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/koi8_t.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/koi8_u.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/kz1048.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/latin_1.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_arabic.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_centeuro.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_croatian.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_cyrillic.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_farsi.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_greek.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_iceland.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_latin2.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_roman.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_romanian.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mac_turkish.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/mbcs.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/oem.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/palmos.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/ptcp154.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/punycode.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/quopri_codec.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/raw_unicode_escape.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/rot_13.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/shift_jis.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/shift_jis_2004.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/shift_jisx0213.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/tis_620.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/undefined.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/unicode_escape.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_16.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_16_be.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_16_le.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_32.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_32_be.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_32_le.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_7.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_8.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/utf_8_sig.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/uu_codec.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/encodings/__pycache__/zlib_codec.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/enum.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/filecmp.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fileinput.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fnmatch.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/formatter.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/fractions.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ftplib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/functools.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/genericpath.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/getopt.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/getpass.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/gettext.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/glob.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/gzip.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/hashlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/heapq.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/hmac.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/html/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/html/__pycache__/entities.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/html/__pycache__/parser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/client.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/cookiejar.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/cookies.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/http/__pycache__/server.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imghdr.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/imp.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/_bootstrap.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/_bootstrap_external.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/abc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/machinery.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/metadata.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/resources.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/importlib/__pycache__/util.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/inspect.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/io.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ipaddress.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/decoder.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/encoder.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/scanner.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/json/__pycache__/tool.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/keyword.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/linecache.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/locale.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/logging/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/logging/__pycache__/config.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/logging/__pycache__/handlers.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/lzma.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mailbox.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mailcap.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/mimetypes.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/modulefinder.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/schema.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/sequence.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/msilib/__pycache__/text.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/netrc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/nntplib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ntpath.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/nturl2path.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/numbers.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/opcode.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/operator.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/optparse.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/os.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pathlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pdb.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pickle.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pickletools.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pipes.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pkgutil.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/platform.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/plistlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/poplib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/posixpath.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pprint.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/profile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pstats.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pty.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/py_compile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pyclbr.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/pydoc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/queue.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/quopri.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/random.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/re.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/reprlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/rlcompleter.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/runpy.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sched.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/secrets.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/selectors.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shelve.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shlex.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/shutil.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/signal.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/site.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/smtpd.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/smtplib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sndhdr.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/socket.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/socketserver.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/__pycache__/dbapi2.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/sqlite3/__pycache__/dump.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_compile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_constants.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sre_parse.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/ssl.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/stat.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/statistics.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/string.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/stringprep.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/struct.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/subprocess.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sunau.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/symbol.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/symtable.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/sysconfig.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tabnanny.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tarfile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/telnetlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tempfile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/textwrap.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/this.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/threading.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/timeit.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/token.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tokenize.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/trace.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/traceback.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tracemalloc.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/tty.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/types.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/typing.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/error.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/parse.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/request.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/response.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/urllib/__pycache__/robotparser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/uu.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/uuid.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/warnings.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/wave.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/weakref.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/webbrowser.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/xdrlib.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/NodeFilter.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/domreg.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/expatbuilder.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/minicompat.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/minidom.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/pulldom.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/dom/__pycache__/xmlbuilder.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/ElementInclude.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/ElementPath.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/ElementTree.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/etree/__pycache__/cElementTree.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/parsers/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/parsers/__pycache__/expat.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/_exceptions.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/expatreader.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/handler.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/saxutils.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xml/sax/__pycache__/xmlreader.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xmlrpc/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xmlrpc/__pycache__/client.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/xmlrpc/__pycache__/server.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipapp.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipfile.cpython-38.opt-1.pyc \ + build/windows/x64/Lib/__pycache__/zipimport.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. # (and make non-writable so I'm less likely to accidentally edit them there) @@ -7729,51 +6801,69 @@ TEX2D_PREVIEW_PNG_TARGETS = \ EXTRAS_TARGETS_WIN_WIN32 = \ build/windows/Win32/DLLs/_asyncio.pyd \ + build/windows/Win32/DLLs/_asyncio_d.pyd \ build/windows/Win32/DLLs/_bz2.pyd \ + build/windows/Win32/DLLs/_bz2_d.pyd \ build/windows/Win32/DLLs/_ctypes.pyd \ + build/windows/Win32/DLLs/_ctypes_d.pyd \ + build/windows/Win32/DLLs/_ctypes_test.pyd \ + build/windows/Win32/DLLs/_ctypes_test_d.pyd \ build/windows/Win32/DLLs/_decimal.pyd \ + build/windows/Win32/DLLs/_decimal_d.pyd \ build/windows/Win32/DLLs/_elementtree.pyd \ + build/windows/Win32/DLLs/_elementtree_d.pyd \ build/windows/Win32/DLLs/_hashlib.pyd \ + build/windows/Win32/DLLs/_hashlib_d.pyd \ build/windows/Win32/DLLs/_lzma.pyd \ + build/windows/Win32/DLLs/_lzma_d.pyd \ build/windows/Win32/DLLs/_msi.pyd \ + build/windows/Win32/DLLs/_msi_d.pyd \ build/windows/Win32/DLLs/_multiprocessing.pyd \ + build/windows/Win32/DLLs/_multiprocessing_d.pyd \ build/windows/Win32/DLLs/_overlapped.pyd \ + build/windows/Win32/DLLs/_overlapped_d.pyd \ build/windows/Win32/DLLs/_queue.pyd \ + build/windows/Win32/DLLs/_queue_d.pyd \ build/windows/Win32/DLLs/_socket.pyd \ + build/windows/Win32/DLLs/_socket_d.pyd \ build/windows/Win32/DLLs/_sqlite3.pyd \ + build/windows/Win32/DLLs/_sqlite3_d.pyd \ build/windows/Win32/DLLs/_ssl.pyd \ + build/windows/Win32/DLLs/_ssl_d.pyd \ + build/windows/Win32/DLLs/_testbuffer.pyd \ + build/windows/Win32/DLLs/_testbuffer_d.pyd \ + build/windows/Win32/DLLs/_testcapi.pyd \ + build/windows/Win32/DLLs/_testcapi_d.pyd \ + build/windows/Win32/DLLs/_testconsole.pyd \ + build/windows/Win32/DLLs/_testconsole_d.pyd \ + build/windows/Win32/DLLs/_testimportmultiple.pyd \ + build/windows/Win32/DLLs/_testimportmultiple_d.pyd \ + build/windows/Win32/DLLs/_testmultiphase.pyd \ + build/windows/Win32/DLLs/_testmultiphase_d.pyd \ + build/windows/Win32/DLLs/_tkinter.pyd \ + build/windows/Win32/DLLs/_tkinter_d.lib \ + build/windows/Win32/DLLs/_tkinter_d.pyd \ build/windows/Win32/DLLs/libcrypto-1_1.dll \ + build/windows/Win32/DLLs/libffi-7.dll \ build/windows/Win32/DLLs/libssl-1_1.dll \ - build/windows/Win32/DLLs/py.ico \ - build/windows/Win32/DLLs/pyc.ico \ - build/windows/Win32/DLLs/pyd.ico \ build/windows/Win32/DLLs/pyexpat.pyd \ + build/windows/Win32/DLLs/pyexpat_d.pyd \ build/windows/Win32/DLLs/python_lib.cat \ build/windows/Win32/DLLs/python_tools.cat \ build/windows/Win32/DLLs/select.pyd \ + build/windows/Win32/DLLs/select_d.pyd \ build/windows/Win32/DLLs/sqlite3.dll \ + build/windows/Win32/DLLs/sqlite3_d.dll \ + build/windows/Win32/DLLs/tcl86t.dll \ + build/windows/Win32/DLLs/tk86t.dll \ build/windows/Win32/DLLs/unicodedata.pyd \ + build/windows/Win32/DLLs/unicodedata_d.pyd \ build/windows/Win32/DLLs/winsound.pyd \ + build/windows/Win32/DLLs/winsound_d.pyd \ build/windows/Win32/Lib/ctypes/macholib/README.ctypes \ build/windows/Win32/Lib/ctypes/macholib/fetch_macholib \ build/windows/Win32/Lib/ctypes/macholib/fetch_macholib.bat \ - build/windows/Win32/Lib/distutils/README \ - build/windows/Win32/Lib/distutils/command/command_template \ - build/windows/Win32/Lib/distutils/tests/Setup.sample \ - build/windows/Win32/Lib/distutils/tests/includetest.rst \ build/windows/Win32/Lib/email/architecture.rst \ - build/windows/Win32/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl \ - build/windows/Win32/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl \ - build/windows/Win32/Lib/pydoc_data/_pydoc.css \ - build/windows/Win32/Lib/site-packages/README.txt \ - build/windows/Win32/Lib/venv/scripts/common/activate \ - build/windows/Win32/Lib/venv/scripts/nt/Activate.ps1 \ - build/windows/Win32/Lib/venv/scripts/nt/activate.bat \ - build/windows/Win32/Lib/venv/scripts/nt/deactivate.bat \ - build/windows/Win32/Lib/venv/scripts/nt/python.exe \ - build/windows/Win32/Lib/venv/scripts/nt/pythonw.exe \ - build/windows/Win32/Lib/venv/scripts/posix/activate.csh \ - build/windows/Win32/Lib/venv/scripts/posix/activate.fish \ build/windows/Win32/OpenAL32.dll \ build/windows/Win32/SDL2.dll \ build/windows/Win32/libvorbis.dll \ @@ -7781,8 +6871,11 @@ EXTRAS_TARGETS_WIN_WIN32 = \ build/windows/Win32/msvcp140d.dll \ build/windows/Win32/ogg.dll \ build/windows/Win32/python.exe \ - build/windows/Win32/python37.dll \ + build/windows/Win32/python38.dll \ + build/windows/Win32/python38_d.dll \ + build/windows/Win32/python_d.exe \ build/windows/Win32/pythonw.exe \ + build/windows/Win32/pythonw_d.exe \ build/windows/Win32/vc_redist.x86.exe \ build/windows/Win32/vcruntime140d.dll @@ -7793,51 +6886,69 @@ $(EXTRAS_TARGETS_WIN_WIN32) : ../.efrocachemap EXTRAS_TARGETS_WIN_X64 = \ build/windows/x64/DLLs/_asyncio.pyd \ + build/windows/x64/DLLs/_asyncio_d.pyd \ build/windows/x64/DLLs/_bz2.pyd \ + build/windows/x64/DLLs/_bz2_d.pyd \ build/windows/x64/DLLs/_ctypes.pyd \ + build/windows/x64/DLLs/_ctypes_d.pyd \ + build/windows/x64/DLLs/_ctypes_test.pyd \ + build/windows/x64/DLLs/_ctypes_test_d.pyd \ build/windows/x64/DLLs/_decimal.pyd \ + build/windows/x64/DLLs/_decimal_d.pyd \ build/windows/x64/DLLs/_elementtree.pyd \ + build/windows/x64/DLLs/_elementtree_d.pyd \ build/windows/x64/DLLs/_hashlib.pyd \ + build/windows/x64/DLLs/_hashlib_d.pyd \ build/windows/x64/DLLs/_lzma.pyd \ + build/windows/x64/DLLs/_lzma_d.pyd \ build/windows/x64/DLLs/_msi.pyd \ + build/windows/x64/DLLs/_msi_d.pyd \ build/windows/x64/DLLs/_multiprocessing.pyd \ + build/windows/x64/DLLs/_multiprocessing_d.pyd \ build/windows/x64/DLLs/_overlapped.pyd \ + build/windows/x64/DLLs/_overlapped_d.pyd \ build/windows/x64/DLLs/_queue.pyd \ + build/windows/x64/DLLs/_queue_d.pyd \ build/windows/x64/DLLs/_socket.pyd \ + build/windows/x64/DLLs/_socket_d.pyd \ build/windows/x64/DLLs/_sqlite3.pyd \ + build/windows/x64/DLLs/_sqlite3_d.pyd \ build/windows/x64/DLLs/_ssl.pyd \ + build/windows/x64/DLLs/_ssl_d.pyd \ + build/windows/x64/DLLs/_testbuffer.pyd \ + build/windows/x64/DLLs/_testbuffer_d.pyd \ + build/windows/x64/DLLs/_testcapi.pyd \ + build/windows/x64/DLLs/_testcapi_d.pyd \ + build/windows/x64/DLLs/_testconsole.pyd \ + build/windows/x64/DLLs/_testconsole_d.pyd \ + build/windows/x64/DLLs/_testimportmultiple.pyd \ + build/windows/x64/DLLs/_testimportmultiple_d.pyd \ + build/windows/x64/DLLs/_testmultiphase.pyd \ + build/windows/x64/DLLs/_testmultiphase_d.pyd \ + build/windows/x64/DLLs/_tkinter.pyd \ + build/windows/x64/DLLs/_tkinter_d.lib \ + build/windows/x64/DLLs/_tkinter_d.pyd \ build/windows/x64/DLLs/libcrypto-1_1.dll \ + build/windows/x64/DLLs/libffi-7.dll \ build/windows/x64/DLLs/libssl-1_1.dll \ - build/windows/x64/DLLs/py.ico \ - build/windows/x64/DLLs/pyc.ico \ - build/windows/x64/DLLs/pyd.ico \ build/windows/x64/DLLs/pyexpat.pyd \ + build/windows/x64/DLLs/pyexpat_d.pyd \ build/windows/x64/DLLs/python_lib.cat \ build/windows/x64/DLLs/python_tools.cat \ build/windows/x64/DLLs/select.pyd \ + build/windows/x64/DLLs/select_d.pyd \ build/windows/x64/DLLs/sqlite3.dll \ + build/windows/x64/DLLs/sqlite3_d.dll \ + build/windows/x64/DLLs/tcl86t.dll \ + build/windows/x64/DLLs/tk86t.dll \ build/windows/x64/DLLs/unicodedata.pyd \ + build/windows/x64/DLLs/unicodedata_d.pyd \ build/windows/x64/DLLs/winsound.pyd \ + build/windows/x64/DLLs/winsound_d.pyd \ build/windows/x64/Lib/ctypes/macholib/README.ctypes \ build/windows/x64/Lib/ctypes/macholib/fetch_macholib \ build/windows/x64/Lib/ctypes/macholib/fetch_macholib.bat \ - build/windows/x64/Lib/distutils/README \ - build/windows/x64/Lib/distutils/command/command_template \ - build/windows/x64/Lib/distutils/tests/Setup.sample \ - build/windows/x64/Lib/distutils/tests/includetest.rst \ build/windows/x64/Lib/email/architecture.rst \ - build/windows/x64/Lib/ensurepip/_bundled/pip-19.0.3-py2.py3-none-any.whl \ - build/windows/x64/Lib/ensurepip/_bundled/setuptools-40.8.0-py2.py3-none-any.whl \ - build/windows/x64/Lib/pydoc_data/_pydoc.css \ - build/windows/x64/Lib/site-packages/README.txt \ - build/windows/x64/Lib/venv/scripts/common/activate \ - build/windows/x64/Lib/venv/scripts/nt/Activate.ps1 \ - build/windows/x64/Lib/venv/scripts/nt/activate.bat \ - build/windows/x64/Lib/venv/scripts/nt/deactivate.bat \ - build/windows/x64/Lib/venv/scripts/nt/python.exe \ - build/windows/x64/Lib/venv/scripts/nt/pythonw.exe \ - build/windows/x64/Lib/venv/scripts/posix/activate.csh \ - build/windows/x64/Lib/venv/scripts/posix/activate.fish \ build/windows/x64/OpenAL32.dll \ build/windows/x64/SDL2.dll \ build/windows/x64/libvorbis.dll \ @@ -7845,8 +6956,11 @@ EXTRAS_TARGETS_WIN_X64 = \ build/windows/x64/msvcp140d.dll \ build/windows/x64/ogg.dll \ build/windows/x64/python.exe \ - build/windows/x64/python37.dll \ + build/windows/x64/python38.dll \ + build/windows/x64/python38_d.dll \ + build/windows/x64/python_d.exe \ build/windows/x64/pythonw.exe \ + build/windows/x64/pythonw_d.exe \ build/windows/x64/vc_redist.x64.exe \ build/windows/x64/vcruntime140_1d.dll \ build/windows/x64/vcruntime140d.dll diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index a0cf3c1e..17e6ba03 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -113,8 +113,7 @@ class TheLastStandGame(ba.CoopGameActivity[Player, Team]): ChargerBot: SpawnInfo(0.30, 0.05, 0.000), StickyBot: SpawnInfo(0.10, 0.03, 0.001), ExplodeyBot: SpawnInfo(0.05, 0.02, 0.002) - } # yapf: disable - + } # yapf: disable def on_transition_in(self) -> None: super().on_transition_in() diff --git a/assets/src/server/README.txt b/assets/src/server/README.txt index 674c999a..78a1237a 100644 --- a/assets/src/server/README.txt +++ b/assets/src/server/README.txt @@ -14,9 +14,7 @@ Mac: (brew install python3). Linux (x86_64): -- Server binaries are currently compiled against Ubuntu 18 LTS. They depend - on Python 3.7, so you may need to install that. - This should just be something like "sudo apt install python3.7" +- Server binaries are currently compiled against Ubuntu 20 LTS. Raspberry Pi: - The server binary was compiled on a Raspberry Pi 4 running Raspbian Buster. diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index a0de2d87..ef24f90f 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/docs/ba_module.md b/docs/ba_module.md index b8d91550..33ec1b98 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-26 for Ballistica version 1.5.24 build 20158

    +

    last updated on 2020-07-28 for Ballistica version 1.5.24 build 20159

    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!


    @@ -2210,7 +2210,7 @@ its time with lingering corpses, sound effects, etc.

    <all methods inherited from ba.Team>


    ba.Existable

    -

    Inherits from: typing_extensions.Protocol

    +

    Inherits from: typing.Protocol, typing.Generic

    A Protocol for objects supporting an exists() method.

    Category: Protocols diff --git a/tools/bacloud b/tools/bacloud index 55da2960..cb08dcff 100755 --- a/tools/bacloud +++ b/tools/bacloud @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/tools/batools/android.py b/tools/batools/android.py index 23506a4d..46e8dff1 100644 --- a/tools/batools/android.py +++ b/tools/batools/android.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/tools/batools/assetsmakefile.py b/tools/batools/assetsmakefile.py index 0e4663fb..a77164aa 100755 --- a/tools/batools/assetsmakefile.py +++ b/tools/batools/assetsmakefile.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -33,7 +33,7 @@ from efro.terminal import Clr if TYPE_CHECKING: from typing import List, Set -PYC_SUFFIX = '.cpython-37.opt-1.pyc' +PYC_SUFFIX = '.cpython-38.opt-1.pyc' def _get_targets(varname: str, @@ -228,7 +228,7 @@ def _get_extras_targets_win(all_targets: Set[str], platform: str) -> str: if ext in [ '.exe', '.dll', '.bat', '.txt', '.whl', '.ps1', '.css', '.sample', '.ico', '.pyd', '.ctypes', '.rst', '.fish', - '.csh', '.cat' + '.csh', '.cat', '.pdb', '.lib', '.html' ] or fname in [ 'activate', 'README', 'command_template', 'fetch_macholib' ]: diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 8a281d81..7c328b11 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -238,6 +238,7 @@ def _write_payload_file(assets_root: str, full: bool) -> None: def _sync_windows_extras(cfg: Config) -> None: + # pylint: disable=too-many-branches assert cfg.win_extras_src is not None assert cfg.win_platform is not None assert cfg.win_type is not None @@ -251,12 +252,17 @@ def _sync_windows_extras(cfg: Config) -> None: # files in dst, so when building packages/etc. we should always start # from scratch. assert cfg.dst is not None + if cfg.debug: + pyd_rules = "--include '*_d.pyd'" + else: + pyd_rules = "--exclude '*_d.pyd' --include '*.pyd'" + for dirname in ('DLLs', 'Lib'): _run(f'mkdir -p "{cfg.dst}/{dirname}"') cmd = ('rsync --recursive --update --delete --delete-excluded ' ' --prune-empty-dirs' " --include '*.ico' --include '*.cat'" - " --include '*.dll' --include '*.pyd'" + f" --include '*.dll' {pyd_rules}" " --include '*.py' --include '*." + OPT_PYC_SUFFIX + "'" " --include '*/' --exclude '*' \"" + os.path.join(cfg.win_extras_src, dirname) + '/" ' @@ -266,7 +272,8 @@ def _sync_windows_extras(cfg: Config) -> None: # Now sync the top level individual files that we want. # (we could technically copy everything over but this keeps staging # dirs a bit tidier) - toplevelfiles: List[str] = ['python37.dll'] + dbgsfx = '_d' if cfg.debug else '' + toplevelfiles: List[str] = [f'python38{dbgsfx}.dll'] if cfg.win_type == 'win': toplevelfiles += [ diff --git a/tools/batools/build.py b/tools/batools/build.py index 9668fc60..41f7c100 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -525,7 +525,9 @@ def checkenv() -> None: raise RuntimeError( f'{packagename} (for {PYTHON_BIN}) is required.\n' f'To install it, try: "{PYTHON_BIN}' - f' -m pip install {packagename}"') + f' -m pip install {packagename}"\n' + f'Alternately, "tools/pcommand install_pip_reqs"' + f' will update all pip requirements.') if minver is not None: verlines = results.stdout.decode().splitlines() if verlines[0].startswith('Cpplint fork'): diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index a6cc67a0..ee0b23f1 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -455,6 +455,14 @@ def python_gather() -> None: pybuild.gather() +def python_winprune() -> None: + """Prune unneeded files from windows python.""" + import os + from efrotools import pybuild + os.chdir(PROJROOT) + pybuild.winprune() + + def capitalize() -> None: """Print args capitalized.""" print(' '.join(w.capitalize() for w in sys.argv[2:])) diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index 8b6cdb39..7b7bfb3f 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -42,6 +42,7 @@ import subprocess from dataclasses import dataclass from typing import TYPE_CHECKING +from efro.error import CleanError from efro.terminal import Clr if TYPE_CHECKING: @@ -391,9 +392,10 @@ class Updater: 'tools/devtool', 'tools/version_utils', 'tools/vmshell' ]: if not contents.startswith(f'#!/usr/bin/env python{PYVER}'): - print(f'{Clr.RED}Incorrect shebang (first line) for ' - f'{fname}.{Clr.RST}') - sys.exit(255) + # TEMP: allow this until ballistica.net is updated + if fname != 'tools/staging_server_upkeep': + raise CleanError(f'Incorrect shebang (first line) for ' + f'{fname}.') else: copyrightline = 0 @@ -636,7 +638,7 @@ class Updater: if os.system(f'tools/pcommand update_assets_makefile {self._checkarg}' ) != 0: print( - f'{Clr.RED}Error checking/updating assets Makefile.f{Clr.RST}') + f'{Clr.RED}Error checking/updating assets Makefile.{Clr.RST}') sys.exit(255) def _update_generated_code_makefile(self) -> None: @@ -644,7 +646,7 @@ class Updater: if os.system('tools/update_generated_code_makefile' + self._checkarg) != 0: print(f'{Clr.RED}Error checking/updating' - f' generated-code Makefile{Clr.RED}') + f' generated-code Makefile.{Clr.RED}') sys.exit(255) def _update_resources_makefile(self) -> None: diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index 51c93b35..9423b213 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -41,7 +41,7 @@ if TYPE_CHECKING: from typing_extensions import Literal # Python major version we're using for all this stuff. -PYVER = '3.7' +PYVER = '3.8' # Python binary assumed by these tools. PYTHON_BIN = f'python{PYVER}' if platform.system() != 'Windows' else 'python' diff --git a/tools/efrotools/android.py b/tools/efrotools/android.py index b5eb9412..45294876 100644 --- a/tools/efrotools/android.py +++ b/tools/efrotools/android.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index 6f32f418..df623831 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -31,10 +31,24 @@ if TYPE_CHECKING: from typing import List, Dict, Any ENABLE_OPENSSL = True +PY38 = True + +# Filenames we prune from Python lib dirs in source repo to cut down on size. +PRUNE_LIB_NAMES = [ + 'config-*', 'idlelib', 'lib-dynload', 'lib2to3', 'multiprocessing', + 'pydoc_data', 'site-packages', 'ensurepip', 'tkinter', 'wsgiref', + 'distutils', 'turtle.py', 'turtledemo', 'test', 'sqlite3/test', 'unittest', + 'dbm', 'venv', 'ctypes/test', 'imaplib.py', '_sysconfigdata_*' +] + +# Same but for DLLs dir (windows only) +PRUNE_DLL_NAMES = ['*.ico'] def build_apple(arch: str, debug: bool = False) -> None: """Run a build for the provided apple arch (mac, ios, or tvos).""" + # pylint: disable=too-many-branches + # pylint: disable=too-many-statements import platform import subprocess from efro.error import CleanError @@ -42,6 +56,7 @@ def build_apple(arch: str, debug: bool = False) -> None: # IMPORTANT; seems we currently wind up building against /usr/local gettext # stuff. Hopefully the maintainer fixes this, but for now I need to # remind myself to blow it away while building. + # (via brew remove gettext --ignore-dependencies) if 'MacBook-Fro' in platform.node(): if (subprocess.run('which gettext', shell=True, check=False).returncode == 0): @@ -148,11 +163,19 @@ def build_apple(arch: str, debug: bool = False) -> None: # Remove makefile dependencies so we don't build the # libs we're not using. - srctxt = '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER)m.a: ' - txt = replace_one( - txt, srctxt, '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER)m.a: ' + - ('build/$2/Support/OpenSSL ' if ENABLE_OPENSSL else '') + - 'build/$2/Support/XZ $$(PYTHON_DIR-$1)/Makefile\n#' + srctxt) + srctxt = '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER).a: ' + if PY38: + txt = replace_one( + txt, srctxt, + '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER).a: ' + + ('build/$2/Support/OpenSSL ' if ENABLE_OPENSSL else '') + + 'build/$2/Support/XZ $$(PYTHON_DIR-$1)/Makefile\n#' + srctxt) + else: + txt = replace_one( + txt, srctxt, + '$$(PYTHON_DIR-$1)/dist/lib/libpython$(PYTHON_VER)m.a: ' + + ('build/$2/Support/OpenSSL ' if ENABLE_OPENSSL else '') + + 'build/$2/Support/XZ $$(PYTHON_DIR-$1)/Makefile\n#' + srctxt) srctxt = ('dist/Python-$(PYTHON_VER)-$1-support.' '$(BUILD_NUMBER).tar.gz: ') txt = replace_one( @@ -166,13 +189,13 @@ def build_apple(arch: str, debug: bool = False) -> None: # Set mac/ios version reqs # (see issue with utimensat and futimens). txt = replace_one(txt, 'MACOSX_DEPLOYMENT_TARGET=10.8', - 'MACOSX_DEPLOYMENT_TARGET=10.14') + 'MACOSX_DEPLOYMENT_TARGET=10.15') # And equivalent iOS (11+). txt = replace_one(txt, 'CFLAGS-iOS=-mios-version-min=8.0', - 'CFLAGS-iOS=-mios-version-min=12.0') + 'CFLAGS-iOS=-mios-version-min=13.0') # Ditto for tvOS. txt = replace_one(txt, 'CFLAGS-tvOS=-mtvos-version-min=9.0', - 'CFLAGS-tvOS=-mtvos-version-min=12.0') + 'CFLAGS-tvOS=-mtvos-version-min=13.0') if debug: @@ -186,11 +209,12 @@ def build_apple(arch: str, debug: bool = False) -> None: # Debug has a different name. # (Currently expect to replace 12 instances of this). - dline = 'python$(PYTHON_VER)m' + dline = 'python$(PYTHON_VER)' if PY38 else 'python$(PYTHON_VER)m' splitlen = len(txt.split(dline)) if splitlen != 13: raise RuntimeError(f'Unexpected configure line count {splitlen}.') - txt = txt.replace(dline, 'python$(PYTHON_VER)dm') + txt = txt.replace( + dline, 'python$(PYTHON_VER)d' if PY38 else 'python$(PYTHON_VER)dm') writefile('Makefile', txt) @@ -293,7 +317,8 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: # Set this to a particular cpython commit to target exact releases from git # commit = 'd7c567b08f9d7d6aef21b881340a2b72731129db' # 3.7.7 release - commit = '4b47a5b6ba66b02df9392feb97b8ead916f8c1fa' # 3.7.8 release + # commit = '4b47a5b6ba66b02df9392feb97b8ead916f8c1fa' # 3.7.8 release + commit = '580fbb018fd0844806119614d752b41fc69660f9' # 3.8.5 if commit is not None: ftxt = readfile('pybuild/source.py') @@ -336,7 +361,10 @@ def build_android(rootdir: str, arch: str, debug: bool = False) -> None: def android_patch() -> None: """Run necessary patches on an android archive before building.""" - fname = 'src/cpython/Modules/Setup.dist' + if PY38: + fname = 'src/cpython/Modules/Setup' + else: + fname = 'src/cpython/Modules/Setup.dist' txt = readfile(fname) # Need to switch some flags on this one. @@ -344,17 +372,28 @@ def android_patch() -> None: 'zlib zlibmodule.c -lz\n#zlib zlibmodule.c') # Just turn all these on. for enable in [ - '#array arraymodule.c', '#cmath cmathmodule.c _math.c', - '#math mathmodule.c', '#_contextvars _contextvarsmodule.c', - '#_struct _struct.c', '#_weakref _weakref.c', - '#_testcapi _testcapimodule.c', '#_random _randommodule.c', - '#_elementtree -I', '#_pickle _pickle.c', - '#_datetime _datetimemodule.c', '#_bisect _bisectmodule.c', - '#_heapq _heapqmodule.c', '#_asyncio _asynciomodule.c', - '#unicodedata unicodedata.c', '#fcntl fcntlmodule.c', - '#select selectmodule.c', '#_csv _csv.c', - '#_socket socketmodule.c', '#_blake2 _blake2/blake2module.c', - '#binascii binascii.c', '#_posixsubprocess _posixsubprocess.c', + '#array arraymodule.c', + '#cmath cmathmodule.c _math.c', + '#math mathmodule.c', + '#_contextvars _contextvarsmodule.c', + '#_struct _struct.c', + '#_weakref _weakref.c', + # '#_testcapi _testcapimodule.c', + '#_random _randommodule.c', + '#_elementtree -I', + '#_pickle _pickle.c', + '#_datetime _datetimemodule.c', + '#_bisect _bisectmodule.c', + '#_heapq _heapqmodule.c', + '#_asyncio _asynciomodule.c', + '#unicodedata unicodedata.c', + '#fcntl fcntlmodule.c', + '#select selectmodule.c', + '#_csv _csv.c', + '#_socket socketmodule.c', + '#_blake2 _blake2/blake2module.c', + '#binascii binascii.c', + '#_posixsubprocess _posixsubprocess.c', '#_sha3 _sha3/sha3module.c' ]: txt = replace_one(txt, enable, enable[1:]) @@ -460,6 +499,19 @@ def android_patch() -> None: print('APPLIED EFROTOOLS ANDROID BUILD PATCHES.') +def winprune() -> None: + """Prune unneeded files from windows python dists.""" + for libdir in ('assets/src/windows/Win32/Lib', + 'assets/src/windows/x64/Lib'): + assert os.path.isdir(libdir) + run('cd "' + libdir + '" && rm -rf ' + ' '.join(PRUNE_LIB_NAMES)) + for dlldir in ('assets/src/windows/Win32/DLLs', + 'assets/src/windows/x64/DLLs'): + assert os.path.isdir(dlldir) + run('cd "' + dlldir + '" && rm -rf ' + ' '.join(PRUNE_DLL_NAMES)) + print('Win-prune successful.') + + def gather() -> None: """Gather per-platform python headers, libs, and modules together. @@ -485,7 +537,7 @@ def gather() -> None: bsuffix = '_debug' if buildtype == 'debug' else '' bsuffix2 = '-debug' if buildtype == 'debug' else '' - libname = 'python' + PYVER + ('dm' if debug else 'm') + libname = 'python' + PYVER + ('d' if debug else '') bases = { 'mac': @@ -614,16 +666,8 @@ def gather() -> None: # Prune a bunch of modules we don't need to cut # down on size. - prune = [ - 'config-*', 'idlelib', 'lib-dynload', 'lib2to3', - 'multiprocessing', 'pydoc_data', 'site-packages', - 'ensurepip', 'tkinter', 'wsgiref', 'distutils', - 'turtle.py', 'turtledemo', 'test', 'sqlite3/test', - 'unittest', 'dbm', 'venv', 'ctypes/test', 'imaplib.py', - '_sysconfigdata_*' - ] run('cd "' + assets_src_dst + '" && rm -rf ' + - ' '.join(prune)) + ' '.join(PRUNE_LIB_NAMES)) # Some minor filtering to system scripts: # on iOS/tvOS, addusersitepackages() leads to a crash diff --git a/tools/pcommand b/tools/pcommand index db068958..3a244185 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.7 +#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -51,11 +51,12 @@ from batools.pcommand import ( gen_fulltest_buildfile_windows, gen_fulltest_buildfile_apple, gen_fulltest_buildfile_linux, python_build_apple, python_build_apple_debug, python_build_android, python_build_android_debug, python_android_patch, - python_gather, capitalize, efrocache_update, efrocache_get, - get_modern_make, warm_start_asset_build, update_docs_md, list_pip_reqs, - install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, - make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, - efro_gradle, stage_assets, update_assets_makefile, update_project) + python_gather, python_winprune, capitalize, efrocache_update, + efrocache_get, get_modern_make, warm_start_asset_build, update_docs_md, + list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, + prefab_run_var, make_prefab, update_makebob, lazybuild, + android_archive_unstripped_libs, efro_gradle, stage_assets, + update_assets_makefile, update_project) # pylint: enable=unused-import if TYPE_CHECKING: From 1a044b28a3516462233c1489c411746737c9bcd1 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 31 Jul 2020 14:10:18 -0700 Subject: [PATCH 177/417] Updating github ci for Python 3.8 --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6caf140f..95490cfa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,13 +14,13 @@ jobs: # We run most of our testing on linux but it should apply to mac too; # we can always add an explicit mac job if it seems worthwhile. ci_unix: - runs-on: ubuntu-18.04 + runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v1 - name: Set up Python uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.8 - name: Install dependencies run: tools/pcommand install_pip_reqs - name: Run checks and tests @@ -36,7 +36,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v1 with: - python-version: 3.7 + python-version: 3.8 - name: Install dependencies run: | python -m pip install --upgrade pip From b0de9f09c25032d3fa1c8401420fcd3c40fce2cd Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 31 Jul 2020 16:21:25 -0700 Subject: [PATCH 178/417] Fix missing cache files for win32 prefab builds --- .efrocachemap | 1023 ++++++++++++++++++++++++------------------------- 1 file changed, 511 insertions(+), 512 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index fe765ae4..97ac4fed 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3415,518 +3415,517 @@ "assets/build/pylib-apple/zipapp.py": "https://files.ballistica.net/cache/ba1/bc/39/2d745b00133cddd197c3a4ee400e", "assets/build/pylib-apple/zipfile.py": "https://files.ballistica.net/cache/ba1/75/54/c1fa31473f6e09efacc3e1cc3464", "assets/build/pylib-apple/zipimport.py": "https://files.ballistica.net/cache/ba1/1f/fa/e11a7b5e9b1191a74bb80f48dc9f", - "assets/build/windows/x64/DLLs/_asyncio.pyd": "https://files.ballistica.net/cache/ba1/6e/32/174cf735f812c3270165eaf98f4d", - "assets/build/windows/x64/DLLs/_asyncio_d.pyd": "https://files.ballistica.net/cache/ba1/29/b1/6217ac66d4497f085bfc939080da", - "assets/build/windows/x64/DLLs/_bz2.pyd": "https://files.ballistica.net/cache/ba1/d3/75/1580a4974ad6ce4d9606cf2bb1f6", - "assets/build/windows/x64/DLLs/_bz2_d.pyd": "https://files.ballistica.net/cache/ba1/05/aa/b54eaef3e0a4478de582a34e4aab", - "assets/build/windows/x64/DLLs/_ctypes.pyd": "https://files.ballistica.net/cache/ba1/3d/43/46782f4468dd494155787303ec54", - "assets/build/windows/x64/DLLs/_ctypes_d.pyd": "https://files.ballistica.net/cache/ba1/70/52/eb0fa1e4703cb379dc395604c071", - "assets/build/windows/x64/DLLs/_ctypes_test.pyd": "https://files.ballistica.net/cache/ba1/2c/80/1527727254f50408e703611236ee", - "assets/build/windows/x64/DLLs/_ctypes_test_d.pyd": "https://files.ballistica.net/cache/ba1/36/6a/d67179765b5d0bf98aa8dd8f5a9e", - "assets/build/windows/x64/DLLs/_decimal.pyd": "https://files.ballistica.net/cache/ba1/af/97/1a4d0c6a2e78a2550899c8e51b30", - "assets/build/windows/x64/DLLs/_decimal_d.pyd": "https://files.ballistica.net/cache/ba1/21/34/1c65855a52881339dc790e69e593", - "assets/build/windows/x64/DLLs/_elementtree.pyd": "https://files.ballistica.net/cache/ba1/45/57/6b2be729f3e100061b3de9e596a7", - "assets/build/windows/x64/DLLs/_elementtree_d.pyd": "https://files.ballistica.net/cache/ba1/87/4a/6a8f5483d1cbaaec4445a585ec40", - "assets/build/windows/x64/DLLs/_hashlib.pyd": "https://files.ballistica.net/cache/ba1/d0/77/82b2ef9642f18369bdc5b94b4e16", - "assets/build/windows/x64/DLLs/_hashlib_d.pyd": "https://files.ballistica.net/cache/ba1/5c/37/1d22f6797f5604318418171fb195", - "assets/build/windows/x64/DLLs/_lzma.pyd": "https://files.ballistica.net/cache/ba1/22/79/5ea4b7f8a42b2d3c7eb4f06c718f", - "assets/build/windows/x64/DLLs/_lzma_d.pyd": "https://files.ballistica.net/cache/ba1/32/5f/7adce0b4f2415637b98c4a8c1967", - "assets/build/windows/x64/DLLs/_msi.pyd": "https://files.ballistica.net/cache/ba1/41/1b/36233d6878deefd86a713af966c5", - "assets/build/windows/x64/DLLs/_msi_d.pyd": "https://files.ballistica.net/cache/ba1/42/7b/78e8442f1f9ea41ca8a5f8c8342a", - "assets/build/windows/x64/DLLs/_multiprocessing.pyd": "https://files.ballistica.net/cache/ba1/33/f2/46d4ff461db2d5d6262a69552c9e", - "assets/build/windows/x64/DLLs/_multiprocessing_d.pyd": "https://files.ballistica.net/cache/ba1/57/91/e4409ffc2937e7d9c83bc8da092e", - "assets/build/windows/x64/DLLs/_overlapped.pyd": "https://files.ballistica.net/cache/ba1/fd/19/b386647908b3d4c0a36626614143", - "assets/build/windows/x64/DLLs/_overlapped_d.pyd": "https://files.ballistica.net/cache/ba1/22/a6/4fc4c59c9c25ccfc66537f00e9b4", - "assets/build/windows/x64/DLLs/_queue.pyd": "https://files.ballistica.net/cache/ba1/55/42/dfca0122165e4ccd86d350650c24", - "assets/build/windows/x64/DLLs/_queue_d.pyd": "https://files.ballistica.net/cache/ba1/8d/8a/98771d0b0871060a55b7fa2819be", - "assets/build/windows/x64/DLLs/_socket.pyd": "https://files.ballistica.net/cache/ba1/d2/ee/d107aeb379ab74d7df38915115a0", - "assets/build/windows/x64/DLLs/_socket_d.pyd": "https://files.ballistica.net/cache/ba1/c1/59/0fe5112152e9409864bfab7c31bf", - "assets/build/windows/x64/DLLs/_sqlite3.pyd": "https://files.ballistica.net/cache/ba1/e0/96/760f86b97227e15a444e41384306", - "assets/build/windows/x64/DLLs/_sqlite3_d.pyd": "https://files.ballistica.net/cache/ba1/98/f5/5db272cba607a9af62c1056307d0", - "assets/build/windows/x64/DLLs/_ssl.pyd": "https://files.ballistica.net/cache/ba1/50/5f/2974db8e35d3f80a8d356f0bd21a", - "assets/build/windows/x64/DLLs/_ssl_d.pyd": "https://files.ballistica.net/cache/ba1/60/b5/976c8fa2633abe2bb9e977e55c61", - "assets/build/windows/x64/DLLs/_testbuffer.pyd": "https://files.ballistica.net/cache/ba1/ba/03/44c93316695f8c1f2325e102548c", - "assets/build/windows/x64/DLLs/_testbuffer_d.pyd": "https://files.ballistica.net/cache/ba1/7b/ea/369ddcdf1bc0a9584291ba36d7dd", - "assets/build/windows/x64/DLLs/_testcapi.pyd": "https://files.ballistica.net/cache/ba1/ef/22/ef19ccfd61c67c94f1fe567c29e2", - "assets/build/windows/x64/DLLs/_testcapi_d.pyd": "https://files.ballistica.net/cache/ba1/b3/46/d5456df3056beb0e2b16e44b3290", - "assets/build/windows/x64/DLLs/_testconsole.pyd": "https://files.ballistica.net/cache/ba1/40/e5/a4d9a8d1d7bc4c94b72b1c6472ad", - "assets/build/windows/x64/DLLs/_testconsole_d.pyd": "https://files.ballistica.net/cache/ba1/99/a4/f6e1219b8eeae1a324720befc2ea", - "assets/build/windows/x64/DLLs/_testimportmultiple.pyd": "https://files.ballistica.net/cache/ba1/38/7d/b04a08e4a09caeb48716aef84baf", - "assets/build/windows/x64/DLLs/_testimportmultiple_d.pyd": "https://files.ballistica.net/cache/ba1/7e/8a/6639d7089235d5ce46a33583afe5", - "assets/build/windows/x64/DLLs/_testmultiphase.pyd": "https://files.ballistica.net/cache/ba1/3c/e6/008a6b59889fffd3f6235e2e2747", - "assets/build/windows/x64/DLLs/_testmultiphase_d.pyd": "https://files.ballistica.net/cache/ba1/5a/29/0bf85c28e0e4c5a58962a3cf4621", - "assets/build/windows/x64/DLLs/_tkinter.pyd": "https://files.ballistica.net/cache/ba1/6a/48/7f70645bda43c2f21c419f3d20af", - "assets/build/windows/x64/DLLs/_tkinter_d.lib": "https://files.ballistica.net/cache/ba1/9d/de/ada57ac91b8397aae5ce63d5acb0", - "assets/build/windows/x64/DLLs/_tkinter_d.pyd": "https://files.ballistica.net/cache/ba1/ae/71/a9aec95391fb9748f98e350b9640", - "assets/build/windows/x64/DLLs/libcrypto-1_1.dll": "https://files.ballistica.net/cache/ba1/e7/2f/6d9ca3aaa9c7f1c18e695f3d592a", - "assets/build/windows/x64/DLLs/libffi-7.dll": "https://files.ballistica.net/cache/ba1/e7/11/bca2299d83f69402396f7e0c5955", - "assets/build/windows/x64/DLLs/libssl-1_1.dll": "https://files.ballistica.net/cache/ba1/62/7b/aa0021d12fd2c9ffe6f8f061339a", - "assets/build/windows/x64/DLLs/pyexpat.pyd": "https://files.ballistica.net/cache/ba1/e8/54/47734b608f3741116698f2eb2f9f", - "assets/build/windows/x64/DLLs/pyexpat_d.pyd": "https://files.ballistica.net/cache/ba1/ea/7d/16329ec77d562afc9ab29a190762", - "assets/build/windows/x64/DLLs/python_lib.cat": "https://files.ballistica.net/cache/ba1/7d/72/921b6c6ac45ca70da316976b7249", - "assets/build/windows/x64/DLLs/python_tools.cat": "https://files.ballistica.net/cache/ba1/fe/bc/74e00a162e3a410e94a071b23a26", - "assets/build/windows/x64/DLLs/select.pyd": "https://files.ballistica.net/cache/ba1/71/b9/c5271872b0daba597cb8f1a02ea4", - "assets/build/windows/x64/DLLs/select_d.pyd": "https://files.ballistica.net/cache/ba1/2f/1f/e51ccbb8579ffbba07b0f5001f54", - "assets/build/windows/x64/DLLs/sqlite3.dll": "https://files.ballistica.net/cache/ba1/17/dd/c3dccbbabea5e74a494ddd1347c2", - "assets/build/windows/x64/DLLs/sqlite3_d.dll": "https://files.ballistica.net/cache/ba1/90/a4/65ee31ae896e0db3b719483c762e", - "assets/build/windows/x64/DLLs/tcl86t.dll": "https://files.ballistica.net/cache/ba1/61/af/a7fc7edb673bb6e11ff19a45a5ca", - "assets/build/windows/x64/DLLs/tk86t.dll": "https://files.ballistica.net/cache/ba1/0f/9b/e9b784626f42d90a782d2a43565a", - "assets/build/windows/x64/DLLs/unicodedata.pyd": "https://files.ballistica.net/cache/ba1/12/49/f5a5183a382c23d5851be5a5a47d", - "assets/build/windows/x64/DLLs/unicodedata_d.pyd": "https://files.ballistica.net/cache/ba1/25/5c/61c65e5cbe0851107385b11bde79", - "assets/build/windows/x64/DLLs/winsound.pyd": "https://files.ballistica.net/cache/ba1/50/90/2958cc3ce6454971b608c12c1c20", - "assets/build/windows/x64/DLLs/winsound_d.pyd": "https://files.ballistica.net/cache/ba1/5b/c9/4c66575b45e7d6d34748d1650b37", - "assets/build/windows/x64/Lib/__future__.py": "https://files.ballistica.net/cache/ba1/5c/55/fb518c9fb289a2ea4461ad6186f0", - "assets/build/windows/x64/Lib/__phello__.foo.py": "https://files.ballistica.net/cache/ba1/16/80/d0e73186e8d0c1ea5fe40684e67d", - "assets/build/windows/x64/Lib/_bootlocale.py": "https://files.ballistica.net/cache/ba1/6f/f1/7d40ba193553db1028a52ac39916", - "assets/build/windows/x64/Lib/_collections_abc.py": "https://files.ballistica.net/cache/ba1/e6/62/90704b9fca8e02fc2ae58608f9a9", - "assets/build/windows/x64/Lib/_compat_pickle.py": "https://files.ballistica.net/cache/ba1/d4/2a/fec8bc99bd7aac05838ddca26f27", - "assets/build/windows/x64/Lib/_compression.py": "https://files.ballistica.net/cache/ba1/f9/ff/49bf6f803ec1b9a9a37db5c0ca11", - "assets/build/windows/x64/Lib/_dummy_thread.py": "https://files.ballistica.net/cache/ba1/eb/3e/ccad286f08dd9025057e6bd4b120", - "assets/build/windows/x64/Lib/_markupbase.py": "https://files.ballistica.net/cache/ba1/ac/f1/8040438f7869ec515bf48d9c45cf", - "assets/build/windows/x64/Lib/_osx_support.py": "https://files.ballistica.net/cache/ba1/d3/7a/eef03a4e6fa0ce18a1dba3bb2007", - "assets/build/windows/x64/Lib/_py_abc.py": "https://files.ballistica.net/cache/ba1/61/5b/6f1b3120c34d6055bc2cc213d74b", - "assets/build/windows/x64/Lib/_pydecimal.py": "https://files.ballistica.net/cache/ba1/be/b3/3b3d8255c568b050fa0d4bea5e8a", - "assets/build/windows/x64/Lib/_pyio.py": "https://files.ballistica.net/cache/ba1/aa/6d/e02cc7b4793303e3bbc44390224a", - "assets/build/windows/x64/Lib/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/21/69/80645211f3e7cb709b1b821ba151", - "assets/build/windows/x64/Lib/_strptime.py": "https://files.ballistica.net/cache/ba1/20/11/354333c2cb23a7e8c7fd2c506048", - "assets/build/windows/x64/Lib/_threading_local.py": "https://files.ballistica.net/cache/ba1/5e/67/db01fc21951f2d5b0c7d2ef6f0bc", - "assets/build/windows/x64/Lib/_weakrefset.py": "https://files.ballistica.net/cache/ba1/2f/37/853e2c10926f428f2792e5494af3", - "assets/build/windows/x64/Lib/abc.py": "https://files.ballistica.net/cache/ba1/5b/b5/31c74d1cff835ccaff4afb291438", - "assets/build/windows/x64/Lib/aifc.py": "https://files.ballistica.net/cache/ba1/6e/e8/6b67de9750d700928af66578a096", - "assets/build/windows/x64/Lib/antigravity.py": "https://files.ballistica.net/cache/ba1/05/72/afa3a7f14c8732d0fdf53dbae03c", - "assets/build/windows/x64/Lib/argparse.py": "https://files.ballistica.net/cache/ba1/cb/d2/265fca743230ab6b837b82c58e79", - "assets/build/windows/x64/Lib/ast.py": "https://files.ballistica.net/cache/ba1/54/59/698ce41b1e9df6fb3771550bfdf5", - "assets/build/windows/x64/Lib/asynchat.py": "https://files.ballistica.net/cache/ba1/08/55/857f80dcdf35425707336aa697cc", - "assets/build/windows/x64/Lib/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/55/fc/23407700f89c81735e78e7da5d2d", - "assets/build/windows/x64/Lib/asyncio/__main__.py": "https://files.ballistica.net/cache/ba1/07/56/1b86818d0401001d9d067edc8ce4", - "assets/build/windows/x64/Lib/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/6d/41/6e56c2ca5c8d92596572c3fc0589", - "assets/build/windows/x64/Lib/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/c3/cf/b78c0bef4cb41bcb051486346a57", - "assets/build/windows/x64/Lib/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/5e/a3/0a696cdaab8634630bd400f3c536", - "assets/build/windows/x64/Lib/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/19/8a/bfed0ab975bbe54354fb5066372f", - "assets/build/windows/x64/Lib/asyncio/constants.py": "https://files.ballistica.net/cache/ba1/01/9e/a596fa8ed4a3b9d761289fc85044", - "assets/build/windows/x64/Lib/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/a5/e1/505f36fd73a0f4cc1a02bb928225", - "assets/build/windows/x64/Lib/asyncio/events.py": "https://files.ballistica.net/cache/ba1/c5/18/716d6a29cdcf1d69152768297410", - "assets/build/windows/x64/Lib/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/ff/c9/1391005ad3c50204c126c3a5560c", - "assets/build/windows/x64/Lib/asyncio/format_helpers.py": "https://files.ballistica.net/cache/ba1/5d/91/b2d0791872c4c17be0054212fbec", - "assets/build/windows/x64/Lib/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/cc/a4/6255ad789aacb6d79a3e7bca1734", - "assets/build/windows/x64/Lib/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/fc/77/0b6646e95186daa896a17a409731", - "assets/build/windows/x64/Lib/asyncio/log.py": "https://files.ballistica.net/cache/ba1/99/92/87f78d772878982b0813e31cc180", - "assets/build/windows/x64/Lib/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/4c/ca/e75edfd9ff64a77a31a8150a05f4", - "assets/build/windows/x64/Lib/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/c6/56/e83afb54704e8dde201f67aeb560", - "assets/build/windows/x64/Lib/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/6f/66/f6ce1a84f757eb75184a35eb42fb", - "assets/build/windows/x64/Lib/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/10/af/851dd38ed2a0a185bfc2e9b635b1", - "assets/build/windows/x64/Lib/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/17/da/6cdec425e892917a02d773808d36", - "assets/build/windows/x64/Lib/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/2a/76/32626fe24c543b105de251421a41", - "assets/build/windows/x64/Lib/asyncio/staggered.py": "https://files.ballistica.net/cache/ba1/e0/2b/266b926832c6c643c3676a478fb3", - "assets/build/windows/x64/Lib/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/74/21/df0f11c35eb1c4acd4343c59ccde", - "assets/build/windows/x64/Lib/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/25/33/ea8b8b867b57b0260f1d774fe4a6", - "assets/build/windows/x64/Lib/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/3c/69/224db8e9bd2861056d011192a61a", - "assets/build/windows/x64/Lib/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/97/56/520378b4483798bcb697c4c1146c", - "assets/build/windows/x64/Lib/asyncio/trsock.py": "https://files.ballistica.net/cache/ba1/4e/55/52931f6a570db262f91cced96f32", - "assets/build/windows/x64/Lib/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/1e/f2/973acec4a3265ac4f18509cde4d8", - "assets/build/windows/x64/Lib/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/19/78/a85e6a62af3af13a0a48b8cc9a45", - "assets/build/windows/x64/Lib/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/09/f9/55f789b125d19e29d9fd9a3e735a", - "assets/build/windows/x64/Lib/asyncore.py": "https://files.ballistica.net/cache/ba1/86/00/da358c12981af11f290b2dec68bf", - "assets/build/windows/x64/Lib/base64.py": "https://files.ballistica.net/cache/ba1/78/5a/6a752bed254093e22da5654b75e1", - "assets/build/windows/x64/Lib/bdb.py": "https://files.ballistica.net/cache/ba1/1a/57/7b6aed3adfb18f24f909e1004099", - "assets/build/windows/x64/Lib/binhex.py": "https://files.ballistica.net/cache/ba1/ac/3e/05d7d2a0cdabdc171e05ca799aa0", - "assets/build/windows/x64/Lib/bisect.py": "https://files.ballistica.net/cache/ba1/c8/af/50484311ae2f04707a7b46d63703", - "assets/build/windows/x64/Lib/bz2.py": "https://files.ballistica.net/cache/ba1/43/2a/49c9a3d71e5d9738525d9c6ae568", - "assets/build/windows/x64/Lib/cProfile.py": "https://files.ballistica.net/cache/ba1/ad/f8/9c779f2bb5a5c7af229549ee8cea", - "assets/build/windows/x64/Lib/calendar.py": "https://files.ballistica.net/cache/ba1/b0/26/a4926e2bb09ce9b6c4d622c8386e", - "assets/build/windows/x64/Lib/cgi.py": "https://files.ballistica.net/cache/ba1/fb/30/f19afc29fc9d1dc4fb7589484e24", - "assets/build/windows/x64/Lib/cgitb.py": "https://files.ballistica.net/cache/ba1/82/65/2d797f3a65ae4729af4852a189c9", - "assets/build/windows/x64/Lib/chunk.py": "https://files.ballistica.net/cache/ba1/30/89/c1be3b598eb5289bf7ffd267e8ae", - "assets/build/windows/x64/Lib/cmd.py": "https://files.ballistica.net/cache/ba1/e1/cb/2970df64878f92627f8618378225", - "assets/build/windows/x64/Lib/code.py": "https://files.ballistica.net/cache/ba1/df/5b/f53e46904c488d5fc0821965ca7f", - "assets/build/windows/x64/Lib/codecs.py": "https://files.ballistica.net/cache/ba1/43/ba/c6be3efd78eca9df246d4dfe2216", - "assets/build/windows/x64/Lib/codeop.py": "https://files.ballistica.net/cache/ba1/52/f4/a63a6d598ecfe586d1d6662c3ce5", - "assets/build/windows/x64/Lib/collections/__init__.py": "https://files.ballistica.net/cache/ba1/07/07/0c7a7e3a4ab71da37c1304ae9267", - "assets/build/windows/x64/Lib/collections/abc.py": "https://files.ballistica.net/cache/ba1/0f/f1/19d3b9c402cc1c95495998c26924", - "assets/build/windows/x64/Lib/colorsys.py": "https://files.ballistica.net/cache/ba1/df/86/a0965ceea915c58b40e7660cf4ed", - "assets/build/windows/x64/Lib/compileall.py": "https://files.ballistica.net/cache/ba1/4a/c2/1cd5d36135192460665d9b815483", - "assets/build/windows/x64/Lib/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/7e/e3/0c08640f850e3a3670faa1c3c2f2", - "assets/build/windows/x64/Lib/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/c8/2f/6ba6d5befe6816fce216bff6db67", - "assets/build/windows/x64/Lib/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/e0/d8/d11edee79422ac4c1f40d302feaf", - "assets/build/windows/x64/Lib/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/18/fa/2ceaff087553a83f9761b440140d", - "assets/build/windows/x64/Lib/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/04/e2/ff123638db3ce5959ffedfd1c1b0", - "assets/build/windows/x64/Lib/configparser.py": "https://files.ballistica.net/cache/ba1/38/3e/c03b7de3c4a1822d3f7e0f697d39", - "assets/build/windows/x64/Lib/contextlib.py": "https://files.ballistica.net/cache/ba1/62/f7/adfc79f9f6d43f4135e586bc9a30", - "assets/build/windows/x64/Lib/contextvars.py": "https://files.ballistica.net/cache/ba1/d3/3a/4337a66a2e373df41950946c704f", - "assets/build/windows/x64/Lib/copy.py": "https://files.ballistica.net/cache/ba1/36/ac/5c3576a2e70a3f8426b4aeafd5b5", - "assets/build/windows/x64/Lib/copyreg.py": "https://files.ballistica.net/cache/ba1/ad/9b/f147cc8a837fd7c210d0c7b9e7fa", - "assets/build/windows/x64/Lib/crypt.py": "https://files.ballistica.net/cache/ba1/08/89/066722a5ca69ce6d830f73dc1e64", - "assets/build/windows/x64/Lib/csv.py": "https://files.ballistica.net/cache/ba1/f0/58/e8df46e6013f977ec3abf4729cd6", - "assets/build/windows/x64/Lib/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/27/37/28f9616edf9aa1daccbe6f6806be", - "assets/build/windows/x64/Lib/ctypes/_aix.py": "https://files.ballistica.net/cache/ba1/a4/93/bad8d165eb8f7f9f0785f8f9adfa", - "assets/build/windows/x64/Lib/ctypes/_endian.py": "https://files.ballistica.net/cache/ba1/d7/63/92709063a95b4d8d2ff06d56f880", - "assets/build/windows/x64/Lib/ctypes/macholib/README.ctypes": "https://files.ballistica.net/cache/ba1/86/99/48b23885b48718062a0fe82bce5b", - "assets/build/windows/x64/Lib/ctypes/macholib/__init__.py": "https://files.ballistica.net/cache/ba1/79/6c/8d8d18124bac2a906733c4876bf3", - "assets/build/windows/x64/Lib/ctypes/macholib/dyld.py": "https://files.ballistica.net/cache/ba1/c3/eb/e3c85051080652ec84c45f42dacd", - "assets/build/windows/x64/Lib/ctypes/macholib/dylib.py": "https://files.ballistica.net/cache/ba1/f2/b9/946c05d9b6051f9206cb7aeb0f3e", - "assets/build/windows/x64/Lib/ctypes/macholib/fetch_macholib": "https://files.ballistica.net/cache/ba1/56/a1/345fb67665a88971680632d1a87f", - "assets/build/windows/x64/Lib/ctypes/macholib/fetch_macholib.bat": "https://files.ballistica.net/cache/ba1/b0/39/edd85cc39a69b6d64e594029ece9", - "assets/build/windows/x64/Lib/ctypes/macholib/framework.py": "https://files.ballistica.net/cache/ba1/a5/1c/8beab7cc8af1c46f8d3e4809dadf", - "assets/build/windows/x64/Lib/ctypes/util.py": "https://files.ballistica.net/cache/ba1/82/79/81af49438e21e3d39002ca6c3617", - "assets/build/windows/x64/Lib/ctypes/wintypes.py": "https://files.ballistica.net/cache/ba1/e1/d8/9db42a69096b386fe19d79f02ae3", - "assets/build/windows/x64/Lib/curses/__init__.py": "https://files.ballistica.net/cache/ba1/cc/03/e54839d211f04b55a4653b224866", - "assets/build/windows/x64/Lib/curses/ascii.py": "https://files.ballistica.net/cache/ba1/3e/3c/e7525589d106aeb286aae4e9f454", - "assets/build/windows/x64/Lib/curses/has_key.py": "https://files.ballistica.net/cache/ba1/e2/bc/01bda2d3fe68d84361ec2007bdf8", - "assets/build/windows/x64/Lib/curses/panel.py": "https://files.ballistica.net/cache/ba1/7b/5c/cd382e03cd72ae14ce7d68918df5", - "assets/build/windows/x64/Lib/curses/textpad.py": "https://files.ballistica.net/cache/ba1/96/68/9789e90ca14113193ff432c6dfaf", - "assets/build/windows/x64/Lib/dataclasses.py": "https://files.ballistica.net/cache/ba1/74/77/fa765a8b72a6e38923a97a1a8c1c", - "assets/build/windows/x64/Lib/datetime.py": "https://files.ballistica.net/cache/ba1/a1/2c/30df2101c2b3cbf916dcca4b58fe", - "assets/build/windows/x64/Lib/decimal.py": "https://files.ballistica.net/cache/ba1/cd/b3/d87ac73b40a69014ba9f7b1d479e", - "assets/build/windows/x64/Lib/difflib.py": "https://files.ballistica.net/cache/ba1/83/c1/5756b30a00196d72fb06f79ea8b9", - "assets/build/windows/x64/Lib/dis.py": "https://files.ballistica.net/cache/ba1/aa/69/5b606951368d7e4d60394d4acf73", - "assets/build/windows/x64/Lib/doctest.py": "https://files.ballistica.net/cache/ba1/fa/ef/b982e21caf77052bae28f4a99183", - "assets/build/windows/x64/Lib/dummy_threading.py": "https://files.ballistica.net/cache/ba1/60/8d/f2224386ddb9900ca3534c260a81", - "assets/build/windows/x64/Lib/email/__init__.py": "https://files.ballistica.net/cache/ba1/76/c0/fcec9aab01633e97f3b5e18eb70c", - "assets/build/windows/x64/Lib/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/ee/26/8984a8b57b377dc88bc57d04caa1", - "assets/build/windows/x64/Lib/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/1d/89/300995d4041a79e8dd6c084b0001", - "assets/build/windows/x64/Lib/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/74/cb/41b13f5ce960eecf67a51ef9ed27", - "assets/build/windows/x64/Lib/email/_policybase.py": "https://files.ballistica.net/cache/ba1/5d/f0/a758cd99a544b954c30375561653", - "assets/build/windows/x64/Lib/email/architecture.rst": "https://files.ballistica.net/cache/ba1/db/81/f753186a4351bc3194f5f80bf16f", - "assets/build/windows/x64/Lib/email/base64mime.py": "https://files.ballistica.net/cache/ba1/9a/7d/eac3ad91106569013ef635a63b58", - "assets/build/windows/x64/Lib/email/charset.py": "https://files.ballistica.net/cache/ba1/01/44/acf857fb78c161aca2d5f1f98231", - "assets/build/windows/x64/Lib/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/25/8d/c4903ae1ca071a00a9187274f311", - "assets/build/windows/x64/Lib/email/encoders.py": "https://files.ballistica.net/cache/ba1/f6/1d/5811c8c3904d1ebb1f307bb72fc6", - "assets/build/windows/x64/Lib/email/errors.py": "https://files.ballistica.net/cache/ba1/d2/51/26d427538101480071bfa60b37cc", - "assets/build/windows/x64/Lib/email/feedparser.py": "https://files.ballistica.net/cache/ba1/a6/9e/e6b962e6d35f0660da18b211ed5f", - "assets/build/windows/x64/Lib/email/generator.py": "https://files.ballistica.net/cache/ba1/e5/f3/731ce81ca93f92a8e6cc9f1a3834", - "assets/build/windows/x64/Lib/email/header.py": "https://files.ballistica.net/cache/ba1/96/26/1eba1e74334d898c9c0f807c16e3", - "assets/build/windows/x64/Lib/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/b0/7e/6d5a0fb939fc216a270d9a8979a0", - "assets/build/windows/x64/Lib/email/iterators.py": "https://files.ballistica.net/cache/ba1/d9/fd/355ed578d932c41ae35739d00673", - "assets/build/windows/x64/Lib/email/message.py": "https://files.ballistica.net/cache/ba1/4d/f3/2e6c4d52d3add5bf0187953abb49", - "assets/build/windows/x64/Lib/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/e5/17/b8d8aab249e2015d72953fde6b27", - "assets/build/windows/x64/Lib/email/mime/application.py": "https://files.ballistica.net/cache/ba1/66/77/33cd47aa2283240842c5b0ccea94", - "assets/build/windows/x64/Lib/email/mime/audio.py": "https://files.ballistica.net/cache/ba1/d0/48/29ba57462e545088782acc1823b1", - "assets/build/windows/x64/Lib/email/mime/base.py": "https://files.ballistica.net/cache/ba1/6b/b5/9bab7a468f19919aad6f3e010e1b", - "assets/build/windows/x64/Lib/email/mime/image.py": "https://files.ballistica.net/cache/ba1/8b/78/e00df112d73998458cd383049f12", - "assets/build/windows/x64/Lib/email/mime/message.py": "https://files.ballistica.net/cache/ba1/2c/2b/b85dc8c95c928c3007c91f2fba60", - "assets/build/windows/x64/Lib/email/mime/multipart.py": "https://files.ballistica.net/cache/ba1/68/0c/aec5031829994315cc33ecf1d9e6", - "assets/build/windows/x64/Lib/email/mime/nonmultipart.py": "https://files.ballistica.net/cache/ba1/78/2d/a28be843bf203f38519263232dd9", - "assets/build/windows/x64/Lib/email/mime/text.py": "https://files.ballistica.net/cache/ba1/18/32/e5c33bc2798d166befe514a9a80b", - "assets/build/windows/x64/Lib/email/parser.py": "https://files.ballistica.net/cache/ba1/82/e1/855e071c9e6b4435c4c02833020a", - "assets/build/windows/x64/Lib/email/policy.py": "https://files.ballistica.net/cache/ba1/1b/92/a09b3ad9a6f1eee058995e74cbe3", - "assets/build/windows/x64/Lib/email/quoprimime.py": "https://files.ballistica.net/cache/ba1/b1/bf/11189d2e2a83a70dd2f2f5390173", - "assets/build/windows/x64/Lib/email/utils.py": "https://files.ballistica.net/cache/ba1/36/eb/3d8be5fb4fbd24e1b9cd8ca0724e", - "assets/build/windows/x64/Lib/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/74/24/9e2c34c95798e55af6c9b5820ac6", - "assets/build/windows/x64/Lib/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/a2/02/b8535973acb057b76ebf24118c89", - "assets/build/windows/x64/Lib/encodings/ascii.py": "https://files.ballistica.net/cache/ba1/e9/04/f56438472f157bb2985101772aff", - "assets/build/windows/x64/Lib/encodings/base64_codec.py": "https://files.ballistica.net/cache/ba1/fe/f8/367ac1625dab56ae969e2d7ac7a0", - "assets/build/windows/x64/Lib/encodings/big5.py": "https://files.ballistica.net/cache/ba1/14/ba/cb214feee1646484f200bfd6da9b", - "assets/build/windows/x64/Lib/encodings/big5hkscs.py": "https://files.ballistica.net/cache/ba1/60/9b/5e91cd3eb429dd40a1871209abd8", - "assets/build/windows/x64/Lib/encodings/bz2_codec.py": "https://files.ballistica.net/cache/ba1/b7/9e/95cf25855a324c4dc48d4b2b5a04", - "assets/build/windows/x64/Lib/encodings/charmap.py": "https://files.ballistica.net/cache/ba1/22/42/65768735400a629d813036305f50", - "assets/build/windows/x64/Lib/encodings/cp037.py": "https://files.ballistica.net/cache/ba1/ff/f4/847df84fc6b8ef05b127c60f9f62", - "assets/build/windows/x64/Lib/encodings/cp1006.py": "https://files.ballistica.net/cache/ba1/34/ed/2d4a926fae79f1ea30c6fec585ad", - "assets/build/windows/x64/Lib/encodings/cp1026.py": "https://files.ballistica.net/cache/ba1/43/55/7661a71c113583b6791f70c3f8d4", - "assets/build/windows/x64/Lib/encodings/cp1125.py": "https://files.ballistica.net/cache/ba1/b8/09/06201598822ce12630fc9d6b5b11", - "assets/build/windows/x64/Lib/encodings/cp1140.py": "https://files.ballistica.net/cache/ba1/37/cf/73b6d59a7ca1deddcafcf6e480c6", - "assets/build/windows/x64/Lib/encodings/cp1250.py": "https://files.ballistica.net/cache/ba1/d8/57/3758591d66ad8107fa8909aa8f0f", - "assets/build/windows/x64/Lib/encodings/cp1251.py": "https://files.ballistica.net/cache/ba1/63/5a/477a5a4aaf73a28d26561f677fba", - "assets/build/windows/x64/Lib/encodings/cp1252.py": "https://files.ballistica.net/cache/ba1/90/1b/68fef9f2c5b36b5dd0e7e0cdfc65", - "assets/build/windows/x64/Lib/encodings/cp1253.py": "https://files.ballistica.net/cache/ba1/b1/7f/305e11e3b81ff2803cd8ee281895", - "assets/build/windows/x64/Lib/encodings/cp1254.py": "https://files.ballistica.net/cache/ba1/7d/4d/96694ce1020c83179a643628ca37", - "assets/build/windows/x64/Lib/encodings/cp1255.py": "https://files.ballistica.net/cache/ba1/a1/c5/b3e62985c335180d0617007112af", - "assets/build/windows/x64/Lib/encodings/cp1256.py": "https://files.ballistica.net/cache/ba1/63/71/44fa70340988f01a36ef6ab5972f", - "assets/build/windows/x64/Lib/encodings/cp1257.py": "https://files.ballistica.net/cache/ba1/b1/37/1d8602208665a4924d45af2587b5", - "assets/build/windows/x64/Lib/encodings/cp1258.py": "https://files.ballistica.net/cache/ba1/cb/72/b0cf17240bb1c91062e58cfc1514", - "assets/build/windows/x64/Lib/encodings/cp273.py": "https://files.ballistica.net/cache/ba1/26/f4/d6cbc326c04d7b98b6bffbfbb13f", - "assets/build/windows/x64/Lib/encodings/cp424.py": "https://files.ballistica.net/cache/ba1/4d/e6/e2a8073bfa4d5c125385b022459a", - "assets/build/windows/x64/Lib/encodings/cp437.py": "https://files.ballistica.net/cache/ba1/bd/bd/0cbd2e567df80430b105dd9adecc", - "assets/build/windows/x64/Lib/encodings/cp500.py": "https://files.ballistica.net/cache/ba1/19/15/b9c0fd54cff79cfb2aa1db2824ad", - "assets/build/windows/x64/Lib/encodings/cp720.py": "https://files.ballistica.net/cache/ba1/81/8d/14e839762423c34b032437c9d279", - "assets/build/windows/x64/Lib/encodings/cp737.py": "https://files.ballistica.net/cache/ba1/63/1d/07f779e2e29133ba288d177b7ced", - "assets/build/windows/x64/Lib/encodings/cp775.py": "https://files.ballistica.net/cache/ba1/08/aa/a345f023eb827c1168810bf682ba", - "assets/build/windows/x64/Lib/encodings/cp850.py": "https://files.ballistica.net/cache/ba1/d1/2f/14263031f47e4eeb6c4363ae58f0", - "assets/build/windows/x64/Lib/encodings/cp852.py": "https://files.ballistica.net/cache/ba1/c1/70/12b97addf29afd9a8688ee5db772", - "assets/build/windows/x64/Lib/encodings/cp855.py": "https://files.ballistica.net/cache/ba1/4a/9f/172dbf723c0f49fbca5403993a5b", - "assets/build/windows/x64/Lib/encodings/cp856.py": "https://files.ballistica.net/cache/ba1/ef/01/d45a30729ee28d531726e136d17b", - "assets/build/windows/x64/Lib/encodings/cp857.py": "https://files.ballistica.net/cache/ba1/0c/0e/14ac0f8c99522e08553a8153d404", - "assets/build/windows/x64/Lib/encodings/cp858.py": "https://files.ballistica.net/cache/ba1/57/fe/bf5b254de37e49d5d9f6fc50931f", - "assets/build/windows/x64/Lib/encodings/cp860.py": "https://files.ballistica.net/cache/ba1/30/01/55f609ba1bb95b67d05300b5bf7e", - "assets/build/windows/x64/Lib/encodings/cp861.py": "https://files.ballistica.net/cache/ba1/1d/6a/6b15fab71c2dc9d9598c92cbfb31", - "assets/build/windows/x64/Lib/encodings/cp862.py": "https://files.ballistica.net/cache/ba1/07/f0/e38c5f25bbfd9d0b624a24764f65", - "assets/build/windows/x64/Lib/encodings/cp863.py": "https://files.ballistica.net/cache/ba1/36/18/35bf024051ec832167babbeabe71", - "assets/build/windows/x64/Lib/encodings/cp864.py": "https://files.ballistica.net/cache/ba1/fc/7e/8e178a881c00acccba7b9086ad7e", - "assets/build/windows/x64/Lib/encodings/cp865.py": "https://files.ballistica.net/cache/ba1/d8/3b/d15b9ff4fd51705a55b3b2307f87", - "assets/build/windows/x64/Lib/encodings/cp866.py": "https://files.ballistica.net/cache/ba1/da/0d/d0d37e80220ecf322435a7762a54", - "assets/build/windows/x64/Lib/encodings/cp869.py": "https://files.ballistica.net/cache/ba1/14/58/4576ebb1b0cbd19a270cc659c474", - "assets/build/windows/x64/Lib/encodings/cp874.py": "https://files.ballistica.net/cache/ba1/33/d4/753ac21d78abdc07a7b55ea30e57", - "assets/build/windows/x64/Lib/encodings/cp875.py": "https://files.ballistica.net/cache/ba1/ee/69/1a689ca8548ddbfb99624d20edad", - "assets/build/windows/x64/Lib/encodings/cp932.py": "https://files.ballistica.net/cache/ba1/ee/9e/e0dfd2b261725de249578b92c5b5", - "assets/build/windows/x64/Lib/encodings/cp949.py": "https://files.ballistica.net/cache/ba1/0a/44/1455d0da411e361fb6f4ae25fd9d", - "assets/build/windows/x64/Lib/encodings/cp950.py": "https://files.ballistica.net/cache/ba1/40/e7/70c2fdfad989999e3576495cb81f", - "assets/build/windows/x64/Lib/encodings/euc_jis_2004.py": "https://files.ballistica.net/cache/ba1/8c/a8/4614eb4f49bf4c49d687679658bb", - "assets/build/windows/x64/Lib/encodings/euc_jisx0213.py": "https://files.ballistica.net/cache/ba1/de/5c/e72d74ab9bff97ccc0e98ad460c6", - "assets/build/windows/x64/Lib/encodings/euc_jp.py": "https://files.ballistica.net/cache/ba1/32/da/dcdc77182af710c129742e8f401e", - "assets/build/windows/x64/Lib/encodings/euc_kr.py": "https://files.ballistica.net/cache/ba1/e8/67/ae53ca4b1b4f10f11a3df08e7a98", - "assets/build/windows/x64/Lib/encodings/gb18030.py": "https://files.ballistica.net/cache/ba1/06/63/9b9bf4a0604aa73c0d58db56e658", - "assets/build/windows/x64/Lib/encodings/gb2312.py": "https://files.ballistica.net/cache/ba1/38/f9/5e0f3a867f8a48d73a1494b35317", - "assets/build/windows/x64/Lib/encodings/gbk.py": "https://files.ballistica.net/cache/ba1/d4/a4/fa5a68d45f1b88e8bf1282f37352", - "assets/build/windows/x64/Lib/encodings/hex_codec.py": "https://files.ballistica.net/cache/ba1/45/d6/eb6ea020a637ab74eb828cdbfdb4", - "assets/build/windows/x64/Lib/encodings/hp_roman8.py": "https://files.ballistica.net/cache/ba1/2f/54/bebb0d3ba23807fd485e3291faae", - "assets/build/windows/x64/Lib/encodings/hz.py": "https://files.ballistica.net/cache/ba1/af/5f/7c953eb303cc29d6f61b460c29dc", - "assets/build/windows/x64/Lib/encodings/idna.py": "https://files.ballistica.net/cache/ba1/7d/bc/c58b601f14e60d20d7a1382c1aee", - "assets/build/windows/x64/Lib/encodings/iso2022_jp.py": "https://files.ballistica.net/cache/ba1/71/86/b6ae087569877dfdfd6e410207a6", - "assets/build/windows/x64/Lib/encodings/iso2022_jp_1.py": "https://files.ballistica.net/cache/ba1/c2/cf/10821ebba3bf669e01038da6e32d", - "assets/build/windows/x64/Lib/encodings/iso2022_jp_2.py": "https://files.ballistica.net/cache/ba1/af/74/b6e3f35fe03d05792e81c2b7a78a", - "assets/build/windows/x64/Lib/encodings/iso2022_jp_2004.py": "https://files.ballistica.net/cache/ba1/4f/78/0a01c3c2bda1d7b4b5efcba21231", - "assets/build/windows/x64/Lib/encodings/iso2022_jp_3.py": "https://files.ballistica.net/cache/ba1/27/47/69e040b7879700a5c7a192dd4d26", - "assets/build/windows/x64/Lib/encodings/iso2022_jp_ext.py": "https://files.ballistica.net/cache/ba1/5f/a0/3c018b1581cfb2f248d779aff95d", - "assets/build/windows/x64/Lib/encodings/iso2022_kr.py": "https://files.ballistica.net/cache/ba1/bb/39/7509322635848679c212f85049c3", - "assets/build/windows/x64/Lib/encodings/iso8859_1.py": "https://files.ballistica.net/cache/ba1/9e/c2/2d727e3a3b03e7277bdb8facc956", - "assets/build/windows/x64/Lib/encodings/iso8859_10.py": "https://files.ballistica.net/cache/ba1/a1/41/982790952b0dc75be11b2e45e0d8", - "assets/build/windows/x64/Lib/encodings/iso8859_11.py": "https://files.ballistica.net/cache/ba1/f7/a5/b5c37b303e4733492db9dbf4de18", - "assets/build/windows/x64/Lib/encodings/iso8859_13.py": "https://files.ballistica.net/cache/ba1/6c/a5/2b9644cb901b9360df7a3f94ac3f", - "assets/build/windows/x64/Lib/encodings/iso8859_14.py": "https://files.ballistica.net/cache/ba1/9b/d5/d0c7b6b92ec3f06d3904c875c38d", - "assets/build/windows/x64/Lib/encodings/iso8859_15.py": "https://files.ballistica.net/cache/ba1/21/89/1e22552bf97a8a051dd6c469cbbc", - "assets/build/windows/x64/Lib/encodings/iso8859_16.py": "https://files.ballistica.net/cache/ba1/e8/49/1568ad897656faf5f11814154db3", - "assets/build/windows/x64/Lib/encodings/iso8859_2.py": "https://files.ballistica.net/cache/ba1/f0/9d/9c20a2fbc408a75d80f299723b93", - "assets/build/windows/x64/Lib/encodings/iso8859_3.py": "https://files.ballistica.net/cache/ba1/1a/38/e2ebe1877af6f0a36b3b11a102a8", - "assets/build/windows/x64/Lib/encodings/iso8859_4.py": "https://files.ballistica.net/cache/ba1/5e/0f/da704f8a67735c0082aa88c99715", - "assets/build/windows/x64/Lib/encodings/iso8859_5.py": "https://files.ballistica.net/cache/ba1/fb/a2/8ac3377de529fa4e74283fb39013", - "assets/build/windows/x64/Lib/encodings/iso8859_6.py": "https://files.ballistica.net/cache/ba1/5d/09/f7bc719316bc7053b3bdb37c3aed", - "assets/build/windows/x64/Lib/encodings/iso8859_7.py": "https://files.ballistica.net/cache/ba1/26/42/22c7633ba021d4b6b2d135865b7a", - "assets/build/windows/x64/Lib/encodings/iso8859_8.py": "https://files.ballistica.net/cache/ba1/3f/0e/0ffb6d8062d1ca6bb4dac300351a", - "assets/build/windows/x64/Lib/encodings/iso8859_9.py": "https://files.ballistica.net/cache/ba1/db/64/5816d116b0c204859241972066bc", - "assets/build/windows/x64/Lib/encodings/johab.py": "https://files.ballistica.net/cache/ba1/5a/42/f0ecea534c770559334b18ee854b", - "assets/build/windows/x64/Lib/encodings/koi8_r.py": "https://files.ballistica.net/cache/ba1/c0/a2/922baa4c328691f35a5f4ddde784", - "assets/build/windows/x64/Lib/encodings/koi8_t.py": "https://files.ballistica.net/cache/ba1/fc/2b/413045a8ab61dc5e086800f620da", - "assets/build/windows/x64/Lib/encodings/koi8_u.py": "https://files.ballistica.net/cache/ba1/70/2a/50a6ec3042b9d51579b37ddf378f", - "assets/build/windows/x64/Lib/encodings/kz1048.py": "https://files.ballistica.net/cache/ba1/dc/17/3a92165c9e9d3838fa51a6eeda56", - "assets/build/windows/x64/Lib/encodings/latin_1.py": "https://files.ballistica.net/cache/ba1/7d/a6/6f4d725a6372270b96e155a7ef9d", - "assets/build/windows/x64/Lib/encodings/mac_arabic.py": "https://files.ballistica.net/cache/ba1/e8/1a/9b51a5af9791109cc1f09e46dfca", - "assets/build/windows/x64/Lib/encodings/mac_centeuro.py": "https://files.ballistica.net/cache/ba1/c5/35/563cf68aea8669dc12f7d767e05e", - "assets/build/windows/x64/Lib/encodings/mac_croatian.py": "https://files.ballistica.net/cache/ba1/03/f2/3da0eada5421700df463b539eca2", - "assets/build/windows/x64/Lib/encodings/mac_cyrillic.py": "https://files.ballistica.net/cache/ba1/0e/5e/7c53fe019663903400c0dd77a5e5", - "assets/build/windows/x64/Lib/encodings/mac_farsi.py": "https://files.ballistica.net/cache/ba1/d8/f1/5f8e645053317b8067b7e8a8829f", - "assets/build/windows/x64/Lib/encodings/mac_greek.py": "https://files.ballistica.net/cache/ba1/a0/ca/608bd7d22e0e6f8c64d853af407e", - "assets/build/windows/x64/Lib/encodings/mac_iceland.py": "https://files.ballistica.net/cache/ba1/7d/33/6098fc0d54d758b145e20bb62cd2", - "assets/build/windows/x64/Lib/encodings/mac_latin2.py": "https://files.ballistica.net/cache/ba1/78/e4/4cf017141613f7668b1a1bed6bd3", - "assets/build/windows/x64/Lib/encodings/mac_roman.py": "https://files.ballistica.net/cache/ba1/58/69/8aa0406b22b62dcadba328c021b1", - "assets/build/windows/x64/Lib/encodings/mac_romanian.py": "https://files.ballistica.net/cache/ba1/07/75/27d3bbcc212afef94402427584b2", - "assets/build/windows/x64/Lib/encodings/mac_turkish.py": "https://files.ballistica.net/cache/ba1/87/63/084595d41e714bfd8e6ed367d318", - "assets/build/windows/x64/Lib/encodings/mbcs.py": "https://files.ballistica.net/cache/ba1/6b/1a/d837711acc57ca743ae0ead7a07a", - "assets/build/windows/x64/Lib/encodings/oem.py": "https://files.ballistica.net/cache/ba1/3e/24/c7621ddab4f0358837532a46fe54", - "assets/build/windows/x64/Lib/encodings/palmos.py": "https://files.ballistica.net/cache/ba1/f9/71/576173dffa4f7123914261d1536c", - "assets/build/windows/x64/Lib/encodings/ptcp154.py": "https://files.ballistica.net/cache/ba1/c0/8d/7f25b7fdfff8aa1186a9de51070c", - "assets/build/windows/x64/Lib/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/58/50/48ca96feb7d0974aa7fc56f6215d", - "assets/build/windows/x64/Lib/encodings/quopri_codec.py": "https://files.ballistica.net/cache/ba1/26/8d/742de4739a7a75f3a43afb899d11", - "assets/build/windows/x64/Lib/encodings/raw_unicode_escape.py": "https://files.ballistica.net/cache/ba1/49/64/d67fb4b67044d023b54bb62f7d8a", - "assets/build/windows/x64/Lib/encodings/rot_13.py": "https://files.ballistica.net/cache/ba1/b9/cd/70fc18e0abfd13a0276c09648dde", - "assets/build/windows/x64/Lib/encodings/shift_jis.py": "https://files.ballistica.net/cache/ba1/33/2c/19a215489ce349555bb6068220e3", - "assets/build/windows/x64/Lib/encodings/shift_jis_2004.py": "https://files.ballistica.net/cache/ba1/99/fd/9dbd69ee5f7de4f954317e2cb12f", - "assets/build/windows/x64/Lib/encodings/shift_jisx0213.py": "https://files.ballistica.net/cache/ba1/b6/b6/9ed722e8552bf242ca668fd07969", - "assets/build/windows/x64/Lib/encodings/tis_620.py": "https://files.ballistica.net/cache/ba1/bd/ac/f8918a7ba3f37c3d28f6659e6857", - "assets/build/windows/x64/Lib/encodings/undefined.py": "https://files.ballistica.net/cache/ba1/b9/70/c8c381111c2bda1323ee1a59725d", - "assets/build/windows/x64/Lib/encodings/unicode_escape.py": "https://files.ballistica.net/cache/ba1/fc/2a/e77b877df6810138c462be13c460", - "assets/build/windows/x64/Lib/encodings/utf_16.py": "https://files.ballistica.net/cache/ba1/7a/35/d824d6726d66465a51d498d9f63c", - "assets/build/windows/x64/Lib/encodings/utf_16_be.py": "https://files.ballistica.net/cache/ba1/99/65/b107a1cd6467da965e61637e0d9e", - "assets/build/windows/x64/Lib/encodings/utf_16_le.py": "https://files.ballistica.net/cache/ba1/03/3f/7a404e31d9b0570bb3e469f001d1", - "assets/build/windows/x64/Lib/encodings/utf_32.py": "https://files.ballistica.net/cache/ba1/be/f7/6c6b2930dc010230f80b9b6ac262", - "assets/build/windows/x64/Lib/encodings/utf_32_be.py": "https://files.ballistica.net/cache/ba1/d1/5d/eb58404ae123e77aa14bc73c5b8d", - "assets/build/windows/x64/Lib/encodings/utf_32_le.py": "https://files.ballistica.net/cache/ba1/58/db/9f0d7e9ca21d2aceea9fe885a509", - "assets/build/windows/x64/Lib/encodings/utf_7.py": "https://files.ballistica.net/cache/ba1/d4/e0/1ea11f08827d2daf642ec5c6f13c", - "assets/build/windows/x64/Lib/encodings/utf_8.py": "https://files.ballistica.net/cache/ba1/80/40/af0b79e2f4c5aa87285243465943", - "assets/build/windows/x64/Lib/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/8f/30/772445e0fc95262a5c0feb8b16bc", - "assets/build/windows/x64/Lib/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/97/67/1460fda7afd448affdc491454e36", - "assets/build/windows/x64/Lib/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/8e/f8/222b06ec8c6d36447139238a12ad", - "assets/build/windows/x64/Lib/enum.py": "https://files.ballistica.net/cache/ba1/69/d7/2217fa4093dcc7b61827ecbe6568", - "assets/build/windows/x64/Lib/filecmp.py": "https://files.ballistica.net/cache/ba1/d4/c2/2d03a499807cbeef622dbc90c8aa", - "assets/build/windows/x64/Lib/fileinput.py": "https://files.ballistica.net/cache/ba1/1b/67/3f7eefb165aaf371eb69554bf30f", - "assets/build/windows/x64/Lib/fnmatch.py": "https://files.ballistica.net/cache/ba1/90/89/03ce1c09aed86f396c25b965a908", - "assets/build/windows/x64/Lib/formatter.py": "https://files.ballistica.net/cache/ba1/64/fe/a0a4e4a34f02b48b45653627c54e", - "assets/build/windows/x64/Lib/fractions.py": "https://files.ballistica.net/cache/ba1/7b/93/a318f45fe345bd504a9c9c6f9824", - "assets/build/windows/x64/Lib/ftplib.py": "https://files.ballistica.net/cache/ba1/66/6a/fd18de6eb957c0d1bc5f6d868e60", - "assets/build/windows/x64/Lib/functools.py": "https://files.ballistica.net/cache/ba1/00/df/4af502ac2fe7e69d28403681e2ee", - "assets/build/windows/x64/Lib/genericpath.py": "https://files.ballistica.net/cache/ba1/2a/2d/3d87913fa549b6d5eb8e36883fc0", - "assets/build/windows/x64/Lib/getopt.py": "https://files.ballistica.net/cache/ba1/fc/72/8542fbda8fa94a1b481e8de052da", - "assets/build/windows/x64/Lib/getpass.py": "https://files.ballistica.net/cache/ba1/21/75/a551b07bb802be363ddeb5870fb4", - "assets/build/windows/x64/Lib/gettext.py": "https://files.ballistica.net/cache/ba1/af/1f/bbd243ba2e201c5a5c371e27025a", - "assets/build/windows/x64/Lib/glob.py": "https://files.ballistica.net/cache/ba1/ee/6d/1d2818cfb5a6a05d70033caca122", - "assets/build/windows/x64/Lib/gzip.py": "https://files.ballistica.net/cache/ba1/43/98/3326f91d7b504772fafaa34ceec3", - "assets/build/windows/x64/Lib/hashlib.py": "https://files.ballistica.net/cache/ba1/7a/5b/2445cd21e226852a1bb90b67af2a", - "assets/build/windows/x64/Lib/heapq.py": "https://files.ballistica.net/cache/ba1/04/98/2a58b7e4af075ca522df1e5df3e4", - "assets/build/windows/x64/Lib/hmac.py": "https://files.ballistica.net/cache/ba1/7b/ed/fcd0f5a00ea8e0219af6eb254e40", - "assets/build/windows/x64/Lib/html/__init__.py": "https://files.ballistica.net/cache/ba1/26/0a/26e6ebd92c62d4bf0252aca1dd11", - "assets/build/windows/x64/Lib/html/entities.py": "https://files.ballistica.net/cache/ba1/b8/8b/e021c3e320bcb94d48fa2cc2cefb", - "assets/build/windows/x64/Lib/html/parser.py": "https://files.ballistica.net/cache/ba1/84/1f/d9dad67e386c39a0ae44bdef1620", - "assets/build/windows/x64/Lib/http/__init__.py": "https://files.ballistica.net/cache/ba1/db/c5/cd825edf1c39892d71359819a128", - "assets/build/windows/x64/Lib/http/client.py": "https://files.ballistica.net/cache/ba1/da/29/5baf2eccaa3ccb6e98a499c37164", - "assets/build/windows/x64/Lib/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/14/a8/bff26313dca1f680c09ebbad55bf", - "assets/build/windows/x64/Lib/http/cookies.py": "https://files.ballistica.net/cache/ba1/f3/96/4d0259ac762ed234d1446b4fb188", - "assets/build/windows/x64/Lib/http/server.py": "https://files.ballistica.net/cache/ba1/02/f2/9c1e773c37661b9534af57fc5f83", - "assets/build/windows/x64/Lib/imghdr.py": "https://files.ballistica.net/cache/ba1/19/ff/b4c40eb476e9f29b41bb22756e7f", - "assets/build/windows/x64/Lib/imp.py": "https://files.ballistica.net/cache/ba1/fa/32/ad8700e45e4c5a6ce22c4aedd97c", - "assets/build/windows/x64/Lib/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/15/64/dc87514a1792ebf90ab2c5abc53f", - "assets/build/windows/x64/Lib/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/90/56/cf1817ce313f35917798f5cced85", - "assets/build/windows/x64/Lib/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/a8/1a/576b8b53f6fca8ce8c2955b13a56", - "assets/build/windows/x64/Lib/importlib/abc.py": "https://files.ballistica.net/cache/ba1/6e/b7/64855bc53a8f6de314e2602ed40b", - "assets/build/windows/x64/Lib/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/53/71/10f33e5f5f4bedc0df0763c7f12e", - "assets/build/windows/x64/Lib/importlib/metadata.py": "https://files.ballistica.net/cache/ba1/d7/42/14b3782e33617bd2e0fc22c5922f", - "assets/build/windows/x64/Lib/importlib/resources.py": "https://files.ballistica.net/cache/ba1/5e/94/96b7fa6cc4872c973bd0a65e125b", - "assets/build/windows/x64/Lib/importlib/util.py": "https://files.ballistica.net/cache/ba1/f0/14/010077784291bdda228db67e355d", - "assets/build/windows/x64/Lib/inspect.py": "https://files.ballistica.net/cache/ba1/00/bf/b5a64080675fe2dde8a456c70123", - "assets/build/windows/x64/Lib/io.py": "https://files.ballistica.net/cache/ba1/b7/f0/8a08f888a453794178c257fdd4d5", - "assets/build/windows/x64/Lib/ipaddress.py": "https://files.ballistica.net/cache/ba1/aa/5e/1ce79259fbed823434e87bd529e1", - "assets/build/windows/x64/Lib/json/__init__.py": "https://files.ballistica.net/cache/ba1/20/7f/0b895b2216258157fe5fdf67766f", - "assets/build/windows/x64/Lib/json/decoder.py": "https://files.ballistica.net/cache/ba1/71/6a/99a1a845d121bd044ad6168fccb6", - "assets/build/windows/x64/Lib/json/encoder.py": "https://files.ballistica.net/cache/ba1/28/de/c21d9731f34d2a2db9584b127a61", - "assets/build/windows/x64/Lib/json/scanner.py": "https://files.ballistica.net/cache/ba1/43/5a/76e7e589ade90534214297166bdf", - "assets/build/windows/x64/Lib/json/tool.py": "https://files.ballistica.net/cache/ba1/82/b5/d815ef914cf29ce45a353c2d68e0", - "assets/build/windows/x64/Lib/keyword.py": "https://files.ballistica.net/cache/ba1/0a/ff/16f514a8f31666c0a78932743eba", - "assets/build/windows/x64/Lib/linecache.py": "https://files.ballistica.net/cache/ba1/07/e4/8c633db930c5370ed05c9de68cec", - "assets/build/windows/x64/Lib/locale.py": "https://files.ballistica.net/cache/ba1/07/b1/56bcbf707cf795c7f7d1dbcb3ea4", - "assets/build/windows/x64/Lib/logging/__init__.py": "https://files.ballistica.net/cache/ba1/f0/a8/76f72f08c46327c353ce9c12edb5", - "assets/build/windows/x64/Lib/logging/config.py": "https://files.ballistica.net/cache/ba1/96/9d/6c147ae66c933f11400ee8f1ac27", - "assets/build/windows/x64/Lib/logging/handlers.py": "https://files.ballistica.net/cache/ba1/74/fc/d58cf79b4a8ba3c1ca5b2788845f", - "assets/build/windows/x64/Lib/lzma.py": "https://files.ballistica.net/cache/ba1/a7/25/74061a41daca93e5d252b46f4af4", - "assets/build/windows/x64/Lib/mailbox.py": "https://files.ballistica.net/cache/ba1/16/93/108f6da97cc2681b27d34092932b", - "assets/build/windows/x64/Lib/mailcap.py": "https://files.ballistica.net/cache/ba1/09/9b/812cf9dc875f7413e271b789151b", - "assets/build/windows/x64/Lib/mimetypes.py": "https://files.ballistica.net/cache/ba1/68/47/5675fa86fc23db64fe98eb243ce7", - "assets/build/windows/x64/Lib/modulefinder.py": "https://files.ballistica.net/cache/ba1/51/2e/83f548bac9d321b39cb3a08a7d24", - "assets/build/windows/x64/Lib/msilib/__init__.py": "https://files.ballistica.net/cache/ba1/63/7d/cf053b80d922e61284681a7744b7", - "assets/build/windows/x64/Lib/msilib/schema.py": "https://files.ballistica.net/cache/ba1/a1/fa/4eb816d49773250568cd3a3bc6e3", - "assets/build/windows/x64/Lib/msilib/sequence.py": "https://files.ballistica.net/cache/ba1/97/47/ff4ab28db63fdea3349fe62754ec", - "assets/build/windows/x64/Lib/msilib/text.py": "https://files.ballistica.net/cache/ba1/ce/a6/430d401c2fb15952f3760cc535ce", - "assets/build/windows/x64/Lib/netrc.py": "https://files.ballistica.net/cache/ba1/8d/05/18f219a7009d31762b91810cb7d9", - "assets/build/windows/x64/Lib/nntplib.py": "https://files.ballistica.net/cache/ba1/9b/2f/f5e0f428fc6c61b987dede618022", - "assets/build/windows/x64/Lib/ntpath.py": "https://files.ballistica.net/cache/ba1/c0/57/845ba80c288e1b77de52d561fc5d", - "assets/build/windows/x64/Lib/nturl2path.py": "https://files.ballistica.net/cache/ba1/84/da/eb096f826b77d45b3fe0e27c6567", - "assets/build/windows/x64/Lib/numbers.py": "https://files.ballistica.net/cache/ba1/f7/d3/6213dc42631692cd5573a9689972", - "assets/build/windows/x64/Lib/opcode.py": "https://files.ballistica.net/cache/ba1/8f/0a/9a98907807bd42d2dbfad9f47a90", - "assets/build/windows/x64/Lib/operator.py": "https://files.ballistica.net/cache/ba1/37/29/8bbc3d94fc35fee150e924369d19", - "assets/build/windows/x64/Lib/optparse.py": "https://files.ballistica.net/cache/ba1/06/d2/2fd4710e95fd249b2661a666165a", - "assets/build/windows/x64/Lib/os.py": "https://files.ballistica.net/cache/ba1/22/58/6d82cac13dcb272d95f8f38322e0", - "assets/build/windows/x64/Lib/pathlib.py": "https://files.ballistica.net/cache/ba1/b4/b9/ecab5538bdc5778826a67d787d47", - "assets/build/windows/x64/Lib/pdb.py": "https://files.ballistica.net/cache/ba1/88/01/4478651f6cf4489f5fbc791254b5", - "assets/build/windows/x64/Lib/pickle.py": "https://files.ballistica.net/cache/ba1/8a/66/c79ea496babedcebb92a26d3bc81", - "assets/build/windows/x64/Lib/pickletools.py": "https://files.ballistica.net/cache/ba1/72/00/4d7329402a96bd7f62f77b899d01", - "assets/build/windows/x64/Lib/pipes.py": "https://files.ballistica.net/cache/ba1/85/2a/144db768fd683b88d678a4efc229", - "assets/build/windows/x64/Lib/pkgutil.py": "https://files.ballistica.net/cache/ba1/4c/72/f21ea4423a9b49d9405a82f627c5", - "assets/build/windows/x64/Lib/platform.py": "https://files.ballistica.net/cache/ba1/87/0c/6a898724eb254252bdc1a0a92c75", - "assets/build/windows/x64/Lib/plistlib.py": "https://files.ballistica.net/cache/ba1/71/73/62fa40edb28a89ca36d077fc7d73", - "assets/build/windows/x64/Lib/poplib.py": "https://files.ballistica.net/cache/ba1/1b/cb/5b697b9ad4c79e736cc95c96d1c1", - "assets/build/windows/x64/Lib/posixpath.py": "https://files.ballistica.net/cache/ba1/a9/34/7839f0290c9a8f9cf6acc4541c5a", - "assets/build/windows/x64/Lib/pprint.py": "https://files.ballistica.net/cache/ba1/4a/35/b8974e63bf5952ce8ff501bc6630", - "assets/build/windows/x64/Lib/profile.py": "https://files.ballistica.net/cache/ba1/b7/1d/01f843683a5758907f9b623a1da9", - "assets/build/windows/x64/Lib/pstats.py": "https://files.ballistica.net/cache/ba1/b7/40/1ee7090b409ff4f749e4c8d58a87", - "assets/build/windows/x64/Lib/pty.py": "https://files.ballistica.net/cache/ba1/4d/2a/83a5552bb415f0d73451fb0a0dcd", - "assets/build/windows/x64/Lib/py_compile.py": "https://files.ballistica.net/cache/ba1/46/56/cde4c6e43bc4c957206432e9bcf4", - "assets/build/windows/x64/Lib/pyclbr.py": "https://files.ballistica.net/cache/ba1/bb/f9/c214e77b8d0539adadc7f1b0f972", - "assets/build/windows/x64/Lib/pydoc.py": "https://files.ballistica.net/cache/ba1/03/b3/d440729325bd0e69a39dcd155d63", - "assets/build/windows/x64/Lib/queue.py": "https://files.ballistica.net/cache/ba1/93/b5/aae979d9f1be9bd7d9e38f9d7a5a", - "assets/build/windows/x64/Lib/quopri.py": "https://files.ballistica.net/cache/ba1/92/18/eddf3ab6e4f11ddba84528943ea0", - "assets/build/windows/x64/Lib/random.py": "https://files.ballistica.net/cache/ba1/6a/84/44e516cf5d86034d0de7f51eb8b3", - "assets/build/windows/x64/Lib/re.py": "https://files.ballistica.net/cache/ba1/ec/57/93399db0804fff00cc9e8b98a8a5", - "assets/build/windows/x64/Lib/reprlib.py": "https://files.ballistica.net/cache/ba1/5f/b0/f39f9b9b95ca731e101f7d3db656", - "assets/build/windows/x64/Lib/rlcompleter.py": "https://files.ballistica.net/cache/ba1/9d/49/378d9d71ec5c21da86794f397564", - "assets/build/windows/x64/Lib/runpy.py": "https://files.ballistica.net/cache/ba1/c6/10/76bb7d39ddb6ed5228902609fc8f", - "assets/build/windows/x64/Lib/sched.py": "https://files.ballistica.net/cache/ba1/20/ae/b93c0891cb9c4ef6d3c6ffefa49a", - "assets/build/windows/x64/Lib/secrets.py": "https://files.ballistica.net/cache/ba1/10/1a/70a38e3b387a02b644bf52b4953d", - "assets/build/windows/x64/Lib/selectors.py": "https://files.ballistica.net/cache/ba1/1c/48/87452200d3c67a5e3eafd37704ca", - "assets/build/windows/x64/Lib/shelve.py": "https://files.ballistica.net/cache/ba1/a8/d7/7c387a96dacbf81d4196ab941030", - "assets/build/windows/x64/Lib/shlex.py": "https://files.ballistica.net/cache/ba1/1d/5a/e51f5175dcb456429c25a5eaabd1", - "assets/build/windows/x64/Lib/shutil.py": "https://files.ballistica.net/cache/ba1/9b/e8/7465b5ade563707d0741857faaf3", - "assets/build/windows/x64/Lib/signal.py": "https://files.ballistica.net/cache/ba1/73/a2/334554b75ca8437e13febeb91690", - "assets/build/windows/x64/Lib/site.py": "https://files.ballistica.net/cache/ba1/be/7b/d361cac759233fc2a80cb3b22835", - "assets/build/windows/x64/Lib/smtpd.py": "https://files.ballistica.net/cache/ba1/50/dd/0c9e73b772631a76117adb2814dc", - "assets/build/windows/x64/Lib/smtplib.py": "https://files.ballistica.net/cache/ba1/8b/92/d81f42a94563b205cd36f0c0c1d4", - "assets/build/windows/x64/Lib/sndhdr.py": "https://files.ballistica.net/cache/ba1/f0/4e/2a09c11a3f56f88132b8a39c5d82", - "assets/build/windows/x64/Lib/socket.py": "https://files.ballistica.net/cache/ba1/b7/9d/b861a4dce1461b8dc598fb545142", - "assets/build/windows/x64/Lib/socketserver.py": "https://files.ballistica.net/cache/ba1/09/c6/582c5f988e0526165aeba1942b3b", - "assets/build/windows/x64/Lib/sqlite3/__init__.py": "https://files.ballistica.net/cache/ba1/bb/ba/b889c65254f48b4d5a47f483165c", - "assets/build/windows/x64/Lib/sqlite3/dbapi2.py": "https://files.ballistica.net/cache/ba1/96/b5/ed3c8e8d17a64334e94f5be5f822", - "assets/build/windows/x64/Lib/sqlite3/dump.py": "https://files.ballistica.net/cache/ba1/86/aa/a3f45a108dabc152ccc7362cd846", - "assets/build/windows/x64/Lib/sre_compile.py": "https://files.ballistica.net/cache/ba1/c7/6d/c1e9803811d4d1d194bb17468ce3", - "assets/build/windows/x64/Lib/sre_constants.py": "https://files.ballistica.net/cache/ba1/67/81/991a55cff77b529d9a3055c3b883", - "assets/build/windows/x64/Lib/sre_parse.py": "https://files.ballistica.net/cache/ba1/5c/6b/a743c8b3434b1a110801a7c020fe", - "assets/build/windows/x64/Lib/ssl.py": "https://files.ballistica.net/cache/ba1/9f/f6/edd715c99767b34bfec3faa1b561", - "assets/build/windows/x64/Lib/stat.py": "https://files.ballistica.net/cache/ba1/c2/22/7a3a214143cd87945a1e8ed28e0a", - "assets/build/windows/x64/Lib/statistics.py": "https://files.ballistica.net/cache/ba1/66/24/ce75b4374cced725ae7d9911b93b", - "assets/build/windows/x64/Lib/string.py": "https://files.ballistica.net/cache/ba1/c8/b4/bb43b2912668295d576c1f233885", - "assets/build/windows/x64/Lib/stringprep.py": "https://files.ballistica.net/cache/ba1/36/42/c4ba482ef154a56bdcf4655e0396", - "assets/build/windows/x64/Lib/struct.py": "https://files.ballistica.net/cache/ba1/45/1a/128c83b366fb3c147e1489ca18e4", - "assets/build/windows/x64/Lib/subprocess.py": "https://files.ballistica.net/cache/ba1/43/6c/d3bc4edb17f009d9e25f1483c96c", - "assets/build/windows/x64/Lib/sunau.py": "https://files.ballistica.net/cache/ba1/98/e9/e18caf1000c9f2bbd6e7197d1fbb", - "assets/build/windows/x64/Lib/symbol.py": "https://files.ballistica.net/cache/ba1/a6/20/cfcf373423f5cfca600df140fedd", - "assets/build/windows/x64/Lib/symtable.py": "https://files.ballistica.net/cache/ba1/1f/32/310dd561150a0fdbe5de05366a6b", - "assets/build/windows/x64/Lib/sysconfig.py": "https://files.ballistica.net/cache/ba1/cb/eb/ecdfbad3cf648f48189f83e3bb7c", - "assets/build/windows/x64/Lib/tabnanny.py": "https://files.ballistica.net/cache/ba1/e8/3e/41215ca0ccd43e9aaa0101f7456e", - "assets/build/windows/x64/Lib/tarfile.py": "https://files.ballistica.net/cache/ba1/17/c0/4d98b2afa666a876f625fa97ade3", - "assets/build/windows/x64/Lib/telnetlib.py": "https://files.ballistica.net/cache/ba1/b0/14/38caadf173bca104d6d556fc1bff", - "assets/build/windows/x64/Lib/tempfile.py": "https://files.ballistica.net/cache/ba1/2b/11/f39ae106b09193cccfbcca08c259", - "assets/build/windows/x64/Lib/textwrap.py": "https://files.ballistica.net/cache/ba1/dc/99/1836f263c2b8c4bedac35279284a", - "assets/build/windows/x64/Lib/this.py": "https://files.ballistica.net/cache/ba1/fe/92/4b73cb9b5e6014fe5ac02cf15187", - "assets/build/windows/x64/Lib/threading.py": "https://files.ballistica.net/cache/ba1/9b/c7/4beeb483781e96416b0ec5cab13e", - "assets/build/windows/x64/Lib/timeit.py": "https://files.ballistica.net/cache/ba1/eb/65/e8f7884724850f3c4c23a3043dce", - "assets/build/windows/x64/Lib/token.py": "https://files.ballistica.net/cache/ba1/55/1b/26bf3afa1cf18477015372f2d6a8", - "assets/build/windows/x64/Lib/tokenize.py": "https://files.ballistica.net/cache/ba1/ea/ce/b324e9d762ca9ddd621334308575", - "assets/build/windows/x64/Lib/trace.py": "https://files.ballistica.net/cache/ba1/d2/32/1e84b97bb335f7b3c739505b9d6f", - "assets/build/windows/x64/Lib/traceback.py": "https://files.ballistica.net/cache/ba1/54/a6/571ed5ba74306260c89a7937a4ea", - "assets/build/windows/x64/Lib/tracemalloc.py": "https://files.ballistica.net/cache/ba1/d9/82/542bddb3196a3a38e13315af549e", - "assets/build/windows/x64/Lib/tty.py": "https://files.ballistica.net/cache/ba1/26/15/c352a80614f63b248f48133db95f", - "assets/build/windows/x64/Lib/types.py": "https://files.ballistica.net/cache/ba1/2c/10/e7c7c31d211467498b6fc888b06e", - "assets/build/windows/x64/Lib/typing.py": "https://files.ballistica.net/cache/ba1/65/3f/2b0ca5bd513806e127b5ef91fb22", - "assets/build/windows/x64/Lib/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/bf/df/014153f62b00e4b6ec077d679983", - "assets/build/windows/x64/Lib/urllib/error.py": "https://files.ballistica.net/cache/ba1/7f/1c/7253af299d30189ea693f2c1e79d", - "assets/build/windows/x64/Lib/urllib/parse.py": "https://files.ballistica.net/cache/ba1/04/7d/865ccdec846455a44f6b438ae0e3", - "assets/build/windows/x64/Lib/urllib/request.py": "https://files.ballistica.net/cache/ba1/7c/5a/c7b0b1a9ff4eefa6a52dfe8495b4", - "assets/build/windows/x64/Lib/urllib/response.py": "https://files.ballistica.net/cache/ba1/6e/d7/e1977098f004e835db74ed2dbcb6", - "assets/build/windows/x64/Lib/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/b2/82/27c36f6dd9599898e45b2d1643ee", - "assets/build/windows/x64/Lib/uu.py": "https://files.ballistica.net/cache/ba1/d2/3a/c7ea1f88d74983d073e29b8cdb9b", - "assets/build/windows/x64/Lib/uuid.py": "https://files.ballistica.net/cache/ba1/ea/69/1fdbe28c74670ba8b7e123501b58", - "assets/build/windows/x64/Lib/warnings.py": "https://files.ballistica.net/cache/ba1/22/85/dd1f78755f0a68cf1001a86aba03", - "assets/build/windows/x64/Lib/wave.py": "https://files.ballistica.net/cache/ba1/6c/28/cd5ae263e65cdf5646377e9af59a", - "assets/build/windows/x64/Lib/weakref.py": "https://files.ballistica.net/cache/ba1/2a/54/d31db6e0d3a793c4969d0443149f", - "assets/build/windows/x64/Lib/webbrowser.py": "https://files.ballistica.net/cache/ba1/c0/34/9d7e2df26287900e40a6161914ea", - "assets/build/windows/x64/Lib/xdrlib.py": "https://files.ballistica.net/cache/ba1/d7/d2/73267fea9d72ed3f84cf38dd7ce9", - "assets/build/windows/x64/Lib/xml/__init__.py": "https://files.ballistica.net/cache/ba1/90/da/3877c42a503e181ce6ee8dd27143", - "assets/build/windows/x64/Lib/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/24/f7/3c8ac11160cb6c141d8ab77dde32", - "assets/build/windows/x64/Lib/xml/dom/__init__.py": "https://files.ballistica.net/cache/ba1/2d/58/546bb2e9633ffa367045824b1d35", - "assets/build/windows/x64/Lib/xml/dom/domreg.py": "https://files.ballistica.net/cache/ba1/45/8d/def0e9fcc7ddc0747e596f3f419d", - "assets/build/windows/x64/Lib/xml/dom/expatbuilder.py": "https://files.ballistica.net/cache/ba1/d4/28/43314fc3a711328729597907a710", - "assets/build/windows/x64/Lib/xml/dom/minicompat.py": "https://files.ballistica.net/cache/ba1/39/a7/953efe5a57e9d540311b2619ecfe", - "assets/build/windows/x64/Lib/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/b1/58/1ede69a31bf72ef5631f73cb5a9a", - "assets/build/windows/x64/Lib/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/8e/27/da82238e33e0d8d003187c3f132a", - "assets/build/windows/x64/Lib/xml/dom/xmlbuilder.py": "https://files.ballistica.net/cache/ba1/42/b5/0ad9833d578db17367ed08717d7a", - "assets/build/windows/x64/Lib/xml/etree/ElementInclude.py": "https://files.ballistica.net/cache/ba1/9c/63/746b54837fa143b146682ec5b768", - "assets/build/windows/x64/Lib/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/2a/45/a13fcd560646db7212ef83272f42", - "assets/build/windows/x64/Lib/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/2b/70/0317ccbe85a69ea5792ab886f31d", - "assets/build/windows/x64/Lib/xml/etree/__init__.py": "https://files.ballistica.net/cache/ba1/52/36/7110ffc28e11db782bc0a61eab38", - "assets/build/windows/x64/Lib/xml/etree/cElementTree.py": "https://files.ballistica.net/cache/ba1/50/c1/c0a3f2ea4057998a7205be4ce168", - "assets/build/windows/x64/Lib/xml/parsers/__init__.py": "https://files.ballistica.net/cache/ba1/84/e4/f146fd8909d74918358754dcea8d", - "assets/build/windows/x64/Lib/xml/parsers/expat.py": "https://files.ballistica.net/cache/ba1/fb/71/c080d60f55c9475df2102fefcfc1", - "assets/build/windows/x64/Lib/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/fa/18/5daa79fd3654bfef854e6a301367", - "assets/build/windows/x64/Lib/xml/sax/_exceptions.py": "https://files.ballistica.net/cache/ba1/bf/8a/e17b41b348b56948346b89578657", - "assets/build/windows/x64/Lib/xml/sax/expatreader.py": "https://files.ballistica.net/cache/ba1/6d/33/593f9045dc1c34223621883465ed", - "assets/build/windows/x64/Lib/xml/sax/handler.py": "https://files.ballistica.net/cache/ba1/84/eb/f86753dac9d7105ab95f41d6b0d4", - "assets/build/windows/x64/Lib/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/ef/a0/2791f50e142d521cbeecc57b06a7", - "assets/build/windows/x64/Lib/xml/sax/xmlreader.py": "https://files.ballistica.net/cache/ba1/26/5e/62c6e8fae016fa46020ceab0b99b", - "assets/build/windows/x64/Lib/xmlrpc/__init__.py": "https://files.ballistica.net/cache/ba1/73/b0/7970b505757699330316404086d1", - "assets/build/windows/x64/Lib/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/5b/11/3cad888bffed07ee86742b013d5f", - "assets/build/windows/x64/Lib/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/90/d6/d1931f1dc07779dae8923909804b", - "assets/build/windows/x64/Lib/zipapp.py": "https://files.ballistica.net/cache/ba1/8f/3a/728796fd929420a912edda05d567", - "assets/build/windows/x64/Lib/zipfile.py": "https://files.ballistica.net/cache/ba1/a6/3c/116c6602b0176d208f3e2a4813de", - "assets/build/windows/x64/Lib/zipimport.py": "https://files.ballistica.net/cache/ba1/d5/0e/9f08a3aa213e5792e068acdeb845", - "assets/build/windows/x64/OpenAL32.dll": "https://files.ballistica.net/cache/ba1/a1/7f/e92ff76218c4b8cfce9bc72d5324", - "assets/build/windows/x64/SDL2.dll": "https://files.ballistica.net/cache/ba1/b2/c1/0d3f95340344968b2aac3fc4a979", - "assets/build/windows/x64/libvorbis.dll": "https://files.ballistica.net/cache/ba1/2d/ec/f52561af5804abd5c646e364dea9", - "assets/build/windows/x64/libvorbisfile.dll": "https://files.ballistica.net/cache/ba1/8c/2a/ef525f4ae1de3b46a23fbdd0dfde", - "assets/build/windows/x64/msvcp140d.dll": "https://files.ballistica.net/cache/ba1/25/73/87d96678583aabd18407963ac8b0", - "assets/build/windows/x64/ogg.dll": "https://files.ballistica.net/cache/ba1/1b/3e/382012f9d092e45f211561e8b5ee", - "assets/build/windows/x64/python.exe": "https://files.ballistica.net/cache/ba1/34/e3/4af33a85aa47ce568fbceadf94a6", - "assets/build/windows/x64/python38.dll": "https://files.ballistica.net/cache/ba1/be/0a/7db9069448fc85e490b3e33df8fb", - "assets/build/windows/x64/python38_d.dll": "https://files.ballistica.net/cache/ba1/ea/7d/a75abf72b027ddd09073c0e75c78", - "assets/build/windows/x64/python_d.exe": "https://files.ballistica.net/cache/ba1/8c/c4/bc34113dc8c017be1116f8507c81", - "assets/build/windows/x64/pythonw.exe": "https://files.ballistica.net/cache/ba1/4d/11/dd24f5e0b39f4b96e6b924f09534", - "assets/build/windows/x64/pythonw_d.exe": "https://files.ballistica.net/cache/ba1/0c/2d/d432fb479b8baf94fafd9d96707c", - "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", + "assets/build/windows/Win32/DLLs/_asyncio.pyd": "https://files.ballistica.net/cache/ba1/8d/de/800e3c97af2ce219a02b684e477c", + "assets/build/windows/Win32/DLLs/_asyncio_d.pyd": "https://files.ballistica.net/cache/ba1/e3/4d/ef2b666ed2c1dce82f73407caf68", + "assets/build/windows/Win32/DLLs/_bz2.pyd": "https://files.ballistica.net/cache/ba1/19/76/d5f179d480b26ffe56308415d28b", + "assets/build/windows/Win32/DLLs/_bz2_d.pyd": "https://files.ballistica.net/cache/ba1/c8/84/01422f9047df7c561eb7478643bc", + "assets/build/windows/Win32/DLLs/_ctypes.pyd": "https://files.ballistica.net/cache/ba1/4e/b2/30cb4f1924fe6ae528d2757ddf32", + "assets/build/windows/Win32/DLLs/_ctypes_d.pyd": "https://files.ballistica.net/cache/ba1/4f/14/d3564fabfce0e2a079e5d911f35a", + "assets/build/windows/Win32/DLLs/_ctypes_test.pyd": "https://files.ballistica.net/cache/ba1/51/d8/730d55a2ce2e2a1b5a1b738a4472", + "assets/build/windows/Win32/DLLs/_ctypes_test_d.pyd": "https://files.ballistica.net/cache/ba1/95/17/04dee43b02b0a026d763cc07954b", + "assets/build/windows/Win32/DLLs/_decimal.pyd": "https://files.ballistica.net/cache/ba1/b4/c7/522ae34b6b5f22f92b4ad3b4ceb2", + "assets/build/windows/Win32/DLLs/_decimal_d.pyd": "https://files.ballistica.net/cache/ba1/38/9d/6d790cb3eb0b896b4821a0ff8e6f", + "assets/build/windows/Win32/DLLs/_elementtree.pyd": "https://files.ballistica.net/cache/ba1/b8/82/4ee93baae05d17c96d0ffc45430d", + "assets/build/windows/Win32/DLLs/_elementtree_d.pyd": "https://files.ballistica.net/cache/ba1/35/63/1ffc72d11aa065b98fa10f1a42e7", + "assets/build/windows/Win32/DLLs/_hashlib.pyd": "https://files.ballistica.net/cache/ba1/c8/80/83f110f0afd6cd6e8a856ca860b4", + "assets/build/windows/Win32/DLLs/_hashlib_d.pyd": "https://files.ballistica.net/cache/ba1/de/b9/666391fb24c5d179bd3950a89e73", + "assets/build/windows/Win32/DLLs/_lzma.pyd": "https://files.ballistica.net/cache/ba1/1b/85/a4d05514f2e04858415a4d38741f", + "assets/build/windows/Win32/DLLs/_lzma_d.pyd": "https://files.ballistica.net/cache/ba1/b3/9c/34a5681ae0f2f473003c41598145", + "assets/build/windows/Win32/DLLs/_msi.pyd": "https://files.ballistica.net/cache/ba1/c8/e4/b4652214320f087102b1a3419fd4", + "assets/build/windows/Win32/DLLs/_msi_d.pyd": "https://files.ballistica.net/cache/ba1/2e/90/98ac82df2ae5e46bec283f5d9a9b", + "assets/build/windows/Win32/DLLs/_multiprocessing.pyd": "https://files.ballistica.net/cache/ba1/8c/8f/316765421523e677d5941258c651", + "assets/build/windows/Win32/DLLs/_multiprocessing_d.pyd": "https://files.ballistica.net/cache/ba1/87/cf/4ea7db642edd5e03a46af41576aa", + "assets/build/windows/Win32/DLLs/_overlapped.pyd": "https://files.ballistica.net/cache/ba1/24/d8/f17662d3c56ff611683657ddd2c5", + "assets/build/windows/Win32/DLLs/_overlapped_d.pyd": "https://files.ballistica.net/cache/ba1/d7/68/2852343867a48ca04f2bbd0abed0", + "assets/build/windows/Win32/DLLs/_queue.pyd": "https://files.ballistica.net/cache/ba1/f7/e3/45f3091b672acccbf3578b4bfe39", + "assets/build/windows/Win32/DLLs/_queue_d.pyd": "https://files.ballistica.net/cache/ba1/4d/38/7ead86d7ccf1914bcfbb6582fb5e", + "assets/build/windows/Win32/DLLs/_socket.pyd": "https://files.ballistica.net/cache/ba1/ed/68/e8042e91668ad33eb36561c6b629", + "assets/build/windows/Win32/DLLs/_socket_d.pyd": "https://files.ballistica.net/cache/ba1/27/a0/49e56fe84dc098f72ff6b12f0408", + "assets/build/windows/Win32/DLLs/_sqlite3.pyd": "https://files.ballistica.net/cache/ba1/30/07/effc3f8a77e3938440146755f087", + "assets/build/windows/Win32/DLLs/_sqlite3_d.pyd": "https://files.ballistica.net/cache/ba1/c8/a2/ccdcef00ada2b993938928f29a66", + "assets/build/windows/Win32/DLLs/_ssl.pyd": "https://files.ballistica.net/cache/ba1/fd/a9/0564bf549953a848b725dcd1ec8a", + "assets/build/windows/Win32/DLLs/_ssl_d.pyd": "https://files.ballistica.net/cache/ba1/10/1f/985bb1cb8d65a055554bccd1ed7c", + "assets/build/windows/Win32/DLLs/_testbuffer.pyd": "https://files.ballistica.net/cache/ba1/33/11/5a33331b18e47f49acb46a14a02b", + "assets/build/windows/Win32/DLLs/_testbuffer_d.pyd": "https://files.ballistica.net/cache/ba1/85/8d/6b43a04ea1324aafb8c8306a7264", + "assets/build/windows/Win32/DLLs/_testcapi.pyd": "https://files.ballistica.net/cache/ba1/08/6a/8e74bff951fdf6f20f0e2feed891", + "assets/build/windows/Win32/DLLs/_testcapi_d.pyd": "https://files.ballistica.net/cache/ba1/a6/a1/c8375b852ec72779bcfc13ef1d3b", + "assets/build/windows/Win32/DLLs/_testconsole.pyd": "https://files.ballistica.net/cache/ba1/1e/d6/bfbbd4179c10779da86bce93db27", + "assets/build/windows/Win32/DLLs/_testconsole_d.pyd": "https://files.ballistica.net/cache/ba1/dd/52/1437c93c7ae7adec7dcd020a0a69", + "assets/build/windows/Win32/DLLs/_testimportmultiple.pyd": "https://files.ballistica.net/cache/ba1/be/93/d94a12ed9a2fb4a4fe30c7bc1d14", + "assets/build/windows/Win32/DLLs/_testimportmultiple_d.pyd": "https://files.ballistica.net/cache/ba1/d7/71/e781ddfbc40f9946bec4e587847f", + "assets/build/windows/Win32/DLLs/_testmultiphase.pyd": "https://files.ballistica.net/cache/ba1/27/e6/b72e931d1cc112bc6172509afe8b", + "assets/build/windows/Win32/DLLs/_testmultiphase_d.pyd": "https://files.ballistica.net/cache/ba1/c2/d6/482bda4e439a5d7cb339528c59fb", + "assets/build/windows/Win32/DLLs/_tkinter.pyd": "https://files.ballistica.net/cache/ba1/a2/ae/8f0117dacefaf1518a508e4f84f1", + "assets/build/windows/Win32/DLLs/_tkinter_d.lib": "https://files.ballistica.net/cache/ba1/91/b9/efde15bd959340cfe6235dd8aeb5", + "assets/build/windows/Win32/DLLs/_tkinter_d.pyd": "https://files.ballistica.net/cache/ba1/fb/4d/98a28fe2109ffc2373bc4071eed0", + "assets/build/windows/Win32/DLLs/libcrypto-1_1.dll": "https://files.ballistica.net/cache/ba1/22/74/724cad55596b66aca60c4a6722ea", + "assets/build/windows/Win32/DLLs/libffi-7.dll": "https://files.ballistica.net/cache/ba1/0a/62/9908b69e4aace0659b7ba62772bf", + "assets/build/windows/Win32/DLLs/libssl-1_1.dll": "https://files.ballistica.net/cache/ba1/51/de/d89dfbf61686f9f7c37f1bcba5ef", + "assets/build/windows/Win32/DLLs/pyexpat.pyd": "https://files.ballistica.net/cache/ba1/c0/f5/9724a4694a3c9ecc879408c115bc", + "assets/build/windows/Win32/DLLs/pyexpat_d.pyd": "https://files.ballistica.net/cache/ba1/c2/41/51027410073a6238a056263b5450", + "assets/build/windows/Win32/DLLs/python_lib.cat": "https://files.ballistica.net/cache/ba1/ca/22/1f7cddb73b48ffd50f08081c27c3", + "assets/build/windows/Win32/DLLs/python_tools.cat": "https://files.ballistica.net/cache/ba1/2b/33/f32faece43ae5a1b58951800355a", + "assets/build/windows/Win32/DLLs/select.pyd": "https://files.ballistica.net/cache/ba1/54/83/e80947d5ed0a46e68312773653fb", + "assets/build/windows/Win32/DLLs/select_d.pyd": "https://files.ballistica.net/cache/ba1/af/db/13085b111321d3a4fdd843ffcf54", + "assets/build/windows/Win32/DLLs/sqlite3.dll": "https://files.ballistica.net/cache/ba1/d2/23/82ec454973363b65f92440e4d967", + "assets/build/windows/Win32/DLLs/sqlite3_d.dll": "https://files.ballistica.net/cache/ba1/60/2f/ff01f24a6876e8f9e821c3851664", + "assets/build/windows/Win32/DLLs/tcl86t.dll": "https://files.ballistica.net/cache/ba1/45/33/a98580a5a3794c22b8d487a256db", + "assets/build/windows/Win32/DLLs/tk86t.dll": "https://files.ballistica.net/cache/ba1/84/35/2bfd12b142f4fe1ff277e9ce3940", + "assets/build/windows/Win32/DLLs/unicodedata.pyd": "https://files.ballistica.net/cache/ba1/5c/47/0d7b57ae78def60ca263f35b97ca", + "assets/build/windows/Win32/DLLs/unicodedata_d.pyd": "https://files.ballistica.net/cache/ba1/fe/20/1d7bde0812563ab4b585e03a698a", + "assets/build/windows/Win32/DLLs/winsound.pyd": "https://files.ballistica.net/cache/ba1/50/ea/951f98c6f187f25757dae10b8337", + "assets/build/windows/Win32/DLLs/winsound_d.pyd": "https://files.ballistica.net/cache/ba1/28/13/8857b36063d66e952434a3973853", + "assets/build/windows/Win32/Lib/__future__.py": "https://files.ballistica.net/cache/ba1/2e/cb/a6159f9f7d7c895efcf2c6620ece", + "assets/build/windows/Win32/Lib/__phello__.foo.py": "https://files.ballistica.net/cache/ba1/3b/8b/939d78ee0764fdf52f3098127d6c", + "assets/build/windows/Win32/Lib/_bootlocale.py": "https://files.ballistica.net/cache/ba1/09/0e/9293a47b0ed243fc7482ab56b330", + "assets/build/windows/Win32/Lib/_collections_abc.py": "https://files.ballistica.net/cache/ba1/50/4a/8d27b1c1b0b8556b075f86e9467e", + "assets/build/windows/Win32/Lib/_compat_pickle.py": "https://files.ballistica.net/cache/ba1/46/06/1015248f3c4416edb60e7830aecb", + "assets/build/windows/Win32/Lib/_compression.py": "https://files.ballistica.net/cache/ba1/db/90/20ab62fe1558d9ec656e5ed43d0f", + "assets/build/windows/Win32/Lib/_dummy_thread.py": "https://files.ballistica.net/cache/ba1/41/7b/e6e2723be021e2c4a5ca9de01ea5", + "assets/build/windows/Win32/Lib/_markupbase.py": "https://files.ballistica.net/cache/ba1/0b/b4/b2b374394442d3ceac5659174306", + "assets/build/windows/Win32/Lib/_osx_support.py": "https://files.ballistica.net/cache/ba1/e6/e0/856d31ed5bfa2669f8ec45aca20d", + "assets/build/windows/Win32/Lib/_py_abc.py": "https://files.ballistica.net/cache/ba1/9c/7d/305e09e987f9efdf1048f34e4313", + "assets/build/windows/Win32/Lib/_pydecimal.py": "https://files.ballistica.net/cache/ba1/6d/f3/5c7034a9fa84d1f0a67a27603be1", + "assets/build/windows/Win32/Lib/_pyio.py": "https://files.ballistica.net/cache/ba1/09/94/e9b179e5720f64bf5c75ac1964e8", + "assets/build/windows/Win32/Lib/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/f9/0d/fb8aa34c3c72f100ea0de27b6891", + "assets/build/windows/Win32/Lib/_strptime.py": "https://files.ballistica.net/cache/ba1/81/bd/b94083af169c69202421de573ef0", + "assets/build/windows/Win32/Lib/_threading_local.py": "https://files.ballistica.net/cache/ba1/a2/1b/a9e3518a7c011ddb443a5f2b95b9", + "assets/build/windows/Win32/Lib/_weakrefset.py": "https://files.ballistica.net/cache/ba1/aa/d8/d7cf0531211ae5a2a7578162045e", + "assets/build/windows/Win32/Lib/abc.py": "https://files.ballistica.net/cache/ba1/7f/a7/ea2b02ced37d0e4b3758fbd8766b", + "assets/build/windows/Win32/Lib/aifc.py": "https://files.ballistica.net/cache/ba1/f0/05/54f64f43dd8a1269b42495106a8b", + "assets/build/windows/Win32/Lib/antigravity.py": "https://files.ballistica.net/cache/ba1/fe/66/fc51a4ead5b55dbf09bad7dee9cf", + "assets/build/windows/Win32/Lib/argparse.py": "https://files.ballistica.net/cache/ba1/cf/e4/e717b919d9f23949ae1c67fc8990", + "assets/build/windows/Win32/Lib/ast.py": "https://files.ballistica.net/cache/ba1/0b/6a/723bc070d337fbd76364cf865693", + "assets/build/windows/Win32/Lib/asynchat.py": "https://files.ballistica.net/cache/ba1/6d/8d/403f343399d118de9e3c42bf15ae", + "assets/build/windows/Win32/Lib/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/9f/8a/035dd21bdf2203871dd85f309d75", + "assets/build/windows/Win32/Lib/asyncio/__main__.py": "https://files.ballistica.net/cache/ba1/fb/f0/a4fad40aea4845a907af269fa159", + "assets/build/windows/Win32/Lib/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/a7/c0/241f7864be2fc6a923553d5c902b", + "assets/build/windows/Win32/Lib/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/8a/d0/1ce3ff1f5f8426b036aa9b327d5b", + "assets/build/windows/Win32/Lib/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/6f/86/58e45d69507c0969fd57e77d8248", + "assets/build/windows/Win32/Lib/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/56/07/d89a76bfe000279932381f78b5bf", + "assets/build/windows/Win32/Lib/asyncio/constants.py": "https://files.ballistica.net/cache/ba1/28/3e/49ec61050acc59c2bb5761d5332e", + "assets/build/windows/Win32/Lib/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/ab/a1/bc99786756b3bf8d594bdd0464a0", + "assets/build/windows/Win32/Lib/asyncio/events.py": "https://files.ballistica.net/cache/ba1/ee/e7/d736c75249b38b0538dfda5f3b83", + "assets/build/windows/Win32/Lib/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/00/70/1a9e71b51410e1d7a674201c5956", + "assets/build/windows/Win32/Lib/asyncio/format_helpers.py": "https://files.ballistica.net/cache/ba1/40/98/952c80350fd35c81680c0d565aa1", + "assets/build/windows/Win32/Lib/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/fb/cc/0ce896defcfde6d026fc80038141", + "assets/build/windows/Win32/Lib/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/31/a6/b1ccfb0809f3815d0131a184f555", + "assets/build/windows/Win32/Lib/asyncio/log.py": "https://files.ballistica.net/cache/ba1/d6/d3/380f88b21d3b8ef14f758f283af0", + "assets/build/windows/Win32/Lib/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/09/63/72457348d02a8ed2ef06dd60b7d8", + "assets/build/windows/Win32/Lib/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/d7/af/899719170681a771fdee0b8b0e9f", + "assets/build/windows/Win32/Lib/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/f1/81/41501b6b63db432d8e492cfeae5f", + "assets/build/windows/Win32/Lib/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/b2/15/ef01670e10a144f916023f32a933", + "assets/build/windows/Win32/Lib/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/db/94/b7ce0fbe94e33ced7868378a3810", + "assets/build/windows/Win32/Lib/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/75/52/47f6f534d8f0bff38934a1e9d0ce", + "assets/build/windows/Win32/Lib/asyncio/staggered.py": "https://files.ballistica.net/cache/ba1/9f/52/01396863292b0b31dfbc92c03907", + "assets/build/windows/Win32/Lib/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/9f/79/e707dbf54c712cbeb6930134a805", + "assets/build/windows/Win32/Lib/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/5f/c3/1dcb82253f0e7fba1ccb0659851f", + "assets/build/windows/Win32/Lib/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/2f/24/2f1558585ddff3b619bbfe6a8ae3", + "assets/build/windows/Win32/Lib/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/79/71/a95c9ea4cd4b7a1c25bd916d251c", + "assets/build/windows/Win32/Lib/asyncio/trsock.py": "https://files.ballistica.net/cache/ba1/46/88/ab7c4a2f09e5a3b9f675d5f89b2e", + "assets/build/windows/Win32/Lib/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/48/74/f1a74c42563a46dd6368b426d252", + "assets/build/windows/Win32/Lib/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/4b/4d/1867fd29a770f95265821bdbe690", + "assets/build/windows/Win32/Lib/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/2e/12/253a4c70468ff978daee580c6de2", + "assets/build/windows/Win32/Lib/asyncore.py": "https://files.ballistica.net/cache/ba1/44/dc/aa53adeb954a3b75c96936d2075b", + "assets/build/windows/Win32/Lib/base64.py": "https://files.ballistica.net/cache/ba1/20/47/38248b035f4fac397979328ea7e3", + "assets/build/windows/Win32/Lib/bdb.py": "https://files.ballistica.net/cache/ba1/6e/c1/609478e1331276950f4c489ac963", + "assets/build/windows/Win32/Lib/binhex.py": "https://files.ballistica.net/cache/ba1/ff/de/25906a6ac05fb00f147442afb165", + "assets/build/windows/Win32/Lib/bisect.py": "https://files.ballistica.net/cache/ba1/aa/48/5dc566d252de1c32107c20f384dd", + "assets/build/windows/Win32/Lib/bz2.py": "https://files.ballistica.net/cache/ba1/84/ba/6926aad97895ebfd38184a85ad4f", + "assets/build/windows/Win32/Lib/cProfile.py": "https://files.ballistica.net/cache/ba1/76/50/2800f118a2fb8fb63e43d6e8af73", + "assets/build/windows/Win32/Lib/calendar.py": "https://files.ballistica.net/cache/ba1/c2/58/fa09e1ac00b0427f13d4923998e6", + "assets/build/windows/Win32/Lib/cgi.py": "https://files.ballistica.net/cache/ba1/b0/20/a3b7e2382c7ddde4638dec0f8183", + "assets/build/windows/Win32/Lib/cgitb.py": "https://files.ballistica.net/cache/ba1/ca/c4/1be248ca37283a283419ec8c5128", + "assets/build/windows/Win32/Lib/chunk.py": "https://files.ballistica.net/cache/ba1/16/08/2708ae495aab5e54fe27da06f633", + "assets/build/windows/Win32/Lib/cmd.py": "https://files.ballistica.net/cache/ba1/cc/83/f3046ec22ee06c45649da6add0c7", + "assets/build/windows/Win32/Lib/code.py": "https://files.ballistica.net/cache/ba1/9e/c8/709a57c45e0fd884680f4c38d821", + "assets/build/windows/Win32/Lib/codecs.py": "https://files.ballistica.net/cache/ba1/2e/94/1c5c72dc0cc2968c10ab5d992d6a", + "assets/build/windows/Win32/Lib/codeop.py": "https://files.ballistica.net/cache/ba1/74/3f/c87d2f4f8ba045663ae87bcc088c", + "assets/build/windows/Win32/Lib/collections/__init__.py": "https://files.ballistica.net/cache/ba1/5b/4e/84c23eee138635a9aed31de38b42", + "assets/build/windows/Win32/Lib/collections/abc.py": "https://files.ballistica.net/cache/ba1/ee/9e/1b14e35345f9208b897b8db40100", + "assets/build/windows/Win32/Lib/colorsys.py": "https://files.ballistica.net/cache/ba1/e8/1f/297a0b5e14be06d3f3f554c9725e", + "assets/build/windows/Win32/Lib/compileall.py": "https://files.ballistica.net/cache/ba1/1b/ac/04b84c5eb26e874e884f3bc6bc1b", + "assets/build/windows/Win32/Lib/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/5b/ec/08df2761a442b8ff6fe7d52fcc89", + "assets/build/windows/Win32/Lib/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/4e/19/4b53a12344e38c97b850810ce096", + "assets/build/windows/Win32/Lib/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/72/be/a07d687c1e04ab6451af0d2f945a", + "assets/build/windows/Win32/Lib/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/b1/90/810fe62b37fb06f366aabb785a24", + "assets/build/windows/Win32/Lib/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/f2/63/f484bbdc6c4e7880980b14a664b1", + "assets/build/windows/Win32/Lib/configparser.py": "https://files.ballistica.net/cache/ba1/33/1c/b64584b4e411f9709b913aaa74a0", + "assets/build/windows/Win32/Lib/contextlib.py": "https://files.ballistica.net/cache/ba1/fc/88/4c49645703136b7b60060937132d", + "assets/build/windows/Win32/Lib/contextvars.py": "https://files.ballistica.net/cache/ba1/97/a6/19610cddd01bb44cc6f9d3a21293", + "assets/build/windows/Win32/Lib/copy.py": "https://files.ballistica.net/cache/ba1/1a/bf/cf033225a41642c04ddfd0c88e1d", + "assets/build/windows/Win32/Lib/copyreg.py": "https://files.ballistica.net/cache/ba1/ea/da/ddf7bbefcecb86e240a68ec88543", + "assets/build/windows/Win32/Lib/crypt.py": "https://files.ballistica.net/cache/ba1/dc/72/7588bb74cb6b52d873332ce2213e", + "assets/build/windows/Win32/Lib/csv.py": "https://files.ballistica.net/cache/ba1/f6/0a/09d03e5dcdab8b818812f838158b", + "assets/build/windows/Win32/Lib/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/a2/6e/832983b9f60eae5dd7744bba8bd2", + "assets/build/windows/Win32/Lib/ctypes/_aix.py": "https://files.ballistica.net/cache/ba1/30/2d/3ad91a485f58eb3690c863e7a961", + "assets/build/windows/Win32/Lib/ctypes/_endian.py": "https://files.ballistica.net/cache/ba1/04/c7/1775ac390854c9015be8e834ff50", + "assets/build/windows/Win32/Lib/ctypes/macholib/README.ctypes": "https://files.ballistica.net/cache/ba1/90/bf/d7c620c1dec8a9219b27e1cfa6f4", + "assets/build/windows/Win32/Lib/ctypes/macholib/__init__.py": "https://files.ballistica.net/cache/ba1/a7/68/4d72c2a8db47c671575650daa0e6", + "assets/build/windows/Win32/Lib/ctypes/macholib/dyld.py": "https://files.ballistica.net/cache/ba1/ab/b8/fd08898e1ed54c9f472815946294", + "assets/build/windows/Win32/Lib/ctypes/macholib/dylib.py": "https://files.ballistica.net/cache/ba1/c2/c2/547efc609d150143701b892bc5ae", + "assets/build/windows/Win32/Lib/ctypes/macholib/fetch_macholib": "https://files.ballistica.net/cache/ba1/4d/fb/26d07e6522338f7fc233734f8807", + "assets/build/windows/Win32/Lib/ctypes/macholib/fetch_macholib.bat": "https://files.ballistica.net/cache/ba1/ab/58/c056f07d65b7abf4ac2fc3598947", + "assets/build/windows/Win32/Lib/ctypes/macholib/framework.py": "https://files.ballistica.net/cache/ba1/fb/23/90116831cb2f6d105bc3cd65559c", + "assets/build/windows/Win32/Lib/ctypes/util.py": "https://files.ballistica.net/cache/ba1/c9/92/b71e0b1afdffde4b91ce0ad71cc8", + "assets/build/windows/Win32/Lib/ctypes/wintypes.py": "https://files.ballistica.net/cache/ba1/25/1d/9a7dfb9d5c76744c30ffcde3b6eb", + "assets/build/windows/Win32/Lib/curses/__init__.py": "https://files.ballistica.net/cache/ba1/fd/0d/5b8dedef05db92edb03fd74fa9ea", + "assets/build/windows/Win32/Lib/curses/ascii.py": "https://files.ballistica.net/cache/ba1/fd/14/86316d73c170437831841f44f410", + "assets/build/windows/Win32/Lib/curses/has_key.py": "https://files.ballistica.net/cache/ba1/39/59/8a09c722d5a9c762fe51d6bf827a", + "assets/build/windows/Win32/Lib/curses/panel.py": "https://files.ballistica.net/cache/ba1/48/9c/133d9a244f62e3739cb392d1a096", + "assets/build/windows/Win32/Lib/curses/textpad.py": "https://files.ballistica.net/cache/ba1/ea/c0/e047229f762662427d6c64dd3c61", + "assets/build/windows/Win32/Lib/dataclasses.py": "https://files.ballistica.net/cache/ba1/e4/e4/f953de6ad9b40bfe3bbfc447745e", + "assets/build/windows/Win32/Lib/datetime.py": "https://files.ballistica.net/cache/ba1/4a/34/e1fa9d71c0f17fceb7f4e914608d", + "assets/build/windows/Win32/Lib/decimal.py": "https://files.ballistica.net/cache/ba1/d5/55/9ae7a36d41bfe37b2d67ce3599d0", + "assets/build/windows/Win32/Lib/difflib.py": "https://files.ballistica.net/cache/ba1/1f/07/0083f523b930a1d4429851226286", + "assets/build/windows/Win32/Lib/dis.py": "https://files.ballistica.net/cache/ba1/59/f7/003e25bb8586b1e3732fbb131c25", + "assets/build/windows/Win32/Lib/doctest.py": "https://files.ballistica.net/cache/ba1/f2/03/245b99dc0d8a069a8f47d24baeb3", + "assets/build/windows/Win32/Lib/dummy_threading.py": "https://files.ballistica.net/cache/ba1/08/5a/e7d834d6197d9b58a075b05c4be6", + "assets/build/windows/Win32/Lib/email/__init__.py": "https://files.ballistica.net/cache/ba1/ed/7d/64247a9b90f5c7b3f577b0e28ca0", + "assets/build/windows/Win32/Lib/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/05/81/408bbbd16a07d3c6473ff0ce523b", + "assets/build/windows/Win32/Lib/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/6d/41/06081cc1cdb1b39c516544312443", + "assets/build/windows/Win32/Lib/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/50/a0/805c08eb86fc7fa064685846f73c", + "assets/build/windows/Win32/Lib/email/_policybase.py": "https://files.ballistica.net/cache/ba1/06/37/302137642525762bee6ce4a09cf1", + "assets/build/windows/Win32/Lib/email/architecture.rst": "https://files.ballistica.net/cache/ba1/78/7c/c4274166d5aa06c20c2c0d391104", + "assets/build/windows/Win32/Lib/email/base64mime.py": "https://files.ballistica.net/cache/ba1/92/3c/d5b71a0457e0715462a700c52e78", + "assets/build/windows/Win32/Lib/email/charset.py": "https://files.ballistica.net/cache/ba1/59/ab/965bed051392a950daea1e4d1c02", + "assets/build/windows/Win32/Lib/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/7b/e8/b98e3081cbc9dda43f591ddb7ceb", + "assets/build/windows/Win32/Lib/email/encoders.py": "https://files.ballistica.net/cache/ba1/05/5e/1da72e6b33454bc00ccc75bae468", + "assets/build/windows/Win32/Lib/email/errors.py": "https://files.ballistica.net/cache/ba1/53/1a/246d8f67140256975ac7ae97d1e5", + "assets/build/windows/Win32/Lib/email/feedparser.py": "https://files.ballistica.net/cache/ba1/aa/d0/f54e9f077a1a3a69295932c21353", + "assets/build/windows/Win32/Lib/email/generator.py": "https://files.ballistica.net/cache/ba1/92/60/db86790637e373e2a198c89619a7", + "assets/build/windows/Win32/Lib/email/header.py": "https://files.ballistica.net/cache/ba1/d8/53/2ad4aea28a0f2fb1dcdbaca1d8e8", + "assets/build/windows/Win32/Lib/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/45/38/678e0b87bcd80e22d84702a4f22e", + "assets/build/windows/Win32/Lib/email/iterators.py": "https://files.ballistica.net/cache/ba1/90/09/e8c04371be81b7ab0a11be68784d", + "assets/build/windows/Win32/Lib/email/message.py": "https://files.ballistica.net/cache/ba1/0c/87/ce24e36aa6e728d1cd4a6cd6025f", + "assets/build/windows/Win32/Lib/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/b5/ea/80f195a1c0d100480897a83a4da4", + "assets/build/windows/Win32/Lib/email/mime/application.py": "https://files.ballistica.net/cache/ba1/a6/b1/f129c2517c74d85f48087f80824d", + "assets/build/windows/Win32/Lib/email/mime/audio.py": "https://files.ballistica.net/cache/ba1/29/39/306f35115c997946975ac7c0191b", + "assets/build/windows/Win32/Lib/email/mime/base.py": "https://files.ballistica.net/cache/ba1/2b/03/f95d91c9d3b4c9c90010e58d6502", + "assets/build/windows/Win32/Lib/email/mime/image.py": "https://files.ballistica.net/cache/ba1/4e/b4/f4ac0b2fa30f88de156e3969685e", + "assets/build/windows/Win32/Lib/email/mime/message.py": "https://files.ballistica.net/cache/ba1/2a/bd/1ee232c948a87e6f1ec58a8694d8", + "assets/build/windows/Win32/Lib/email/mime/multipart.py": "https://files.ballistica.net/cache/ba1/48/c9/3beb25ea74084fd2ab4b2c86c37b", + "assets/build/windows/Win32/Lib/email/mime/nonmultipart.py": "https://files.ballistica.net/cache/ba1/0b/e2/82ca4668d9286af8b2dcffa0b6bc", + "assets/build/windows/Win32/Lib/email/mime/text.py": "https://files.ballistica.net/cache/ba1/cb/bb/02e93c2f1c2cce4b255ae7b1e482", + "assets/build/windows/Win32/Lib/email/parser.py": "https://files.ballistica.net/cache/ba1/1f/47/7c3d22b86077f944dfc8ee7a49cc", + "assets/build/windows/Win32/Lib/email/policy.py": "https://files.ballistica.net/cache/ba1/77/b1/8a70ba209a24931675bff0a345cd", + "assets/build/windows/Win32/Lib/email/quoprimime.py": "https://files.ballistica.net/cache/ba1/76/74/92b4640edaa325ff338c5affb245", + "assets/build/windows/Win32/Lib/email/utils.py": "https://files.ballistica.net/cache/ba1/b0/ec/8c0e7e25fa8daa7eab0fe4f5c370", + "assets/build/windows/Win32/Lib/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/be/e6/fba13ffac3f685892d540a195bdc", + "assets/build/windows/Win32/Lib/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/00/7e/c2a22ddceced03816f4cb1b61e66", + "assets/build/windows/Win32/Lib/encodings/ascii.py": "https://files.ballistica.net/cache/ba1/41/44/3c51a65e96fdbbdfc71983863cf5", + "assets/build/windows/Win32/Lib/encodings/base64_codec.py": "https://files.ballistica.net/cache/ba1/f8/5d/78e448a54324be27c57960c3ef8f", + "assets/build/windows/Win32/Lib/encodings/big5.py": "https://files.ballistica.net/cache/ba1/59/23/27486e3ee84ed7e8f3dfcba5497d", + "assets/build/windows/Win32/Lib/encodings/big5hkscs.py": "https://files.ballistica.net/cache/ba1/af/6d/cc95b1377b36ea595a6e7856b257", + "assets/build/windows/Win32/Lib/encodings/bz2_codec.py": "https://files.ballistica.net/cache/ba1/a9/7a/81d7ce81b9963f1bac848daed4aa", + "assets/build/windows/Win32/Lib/encodings/charmap.py": "https://files.ballistica.net/cache/ba1/3a/c4/a547fd6bbfff9a192fcdaaf04572", + "assets/build/windows/Win32/Lib/encodings/cp037.py": "https://files.ballistica.net/cache/ba1/d0/04/e8657144c01a9e55127f528a446e", + "assets/build/windows/Win32/Lib/encodings/cp1006.py": "https://files.ballistica.net/cache/ba1/3f/da/b8d4ce156a61f2741d26467759f0", + "assets/build/windows/Win32/Lib/encodings/cp1026.py": "https://files.ballistica.net/cache/ba1/f1/5d/e4fc4dde67b14f08135293d54fa5", + "assets/build/windows/Win32/Lib/encodings/cp1125.py": "https://files.ballistica.net/cache/ba1/4d/b5/90438fa1429f755c665b3e070437", + "assets/build/windows/Win32/Lib/encodings/cp1140.py": "https://files.ballistica.net/cache/ba1/50/9f/9fb7e2a356d6ba5a1b3d149c1f19", + "assets/build/windows/Win32/Lib/encodings/cp1250.py": "https://files.ballistica.net/cache/ba1/95/ec/6f472fd71c04ac97eeec9a385096", + "assets/build/windows/Win32/Lib/encodings/cp1251.py": "https://files.ballistica.net/cache/ba1/f6/6c/742c74e44015474a31c5abce598a", + "assets/build/windows/Win32/Lib/encodings/cp1252.py": "https://files.ballistica.net/cache/ba1/f8/e1/9306eb6a5c391e481b696f09442a", + "assets/build/windows/Win32/Lib/encodings/cp1253.py": "https://files.ballistica.net/cache/ba1/fe/0e/742893c2dbfbb7ca205fbca56c68", + "assets/build/windows/Win32/Lib/encodings/cp1254.py": "https://files.ballistica.net/cache/ba1/ba/d3/0cdc819b2db190ca8d8c1243bbb1", + "assets/build/windows/Win32/Lib/encodings/cp1255.py": "https://files.ballistica.net/cache/ba1/f3/2e/93096169d97b764d23900e4c4036", + "assets/build/windows/Win32/Lib/encodings/cp1256.py": "https://files.ballistica.net/cache/ba1/b9/fe/a8d6e2a6e1e82123929122ae7bdf", + "assets/build/windows/Win32/Lib/encodings/cp1257.py": "https://files.ballistica.net/cache/ba1/11/13/1f6503b747032c8a09cb4fb52562", + "assets/build/windows/Win32/Lib/encodings/cp1258.py": "https://files.ballistica.net/cache/ba1/5c/0c/73e8f1da40cf731a0682b210f23f", + "assets/build/windows/Win32/Lib/encodings/cp273.py": "https://files.ballistica.net/cache/ba1/16/17/a651036f942e64c98c1e76237c98", + "assets/build/windows/Win32/Lib/encodings/cp424.py": "https://files.ballistica.net/cache/ba1/dd/f9/afd1ad2a6a709a2f6024854b6bf1", + "assets/build/windows/Win32/Lib/encodings/cp437.py": "https://files.ballistica.net/cache/ba1/39/01/ca310570ec583d62401b6468b6f5", + "assets/build/windows/Win32/Lib/encodings/cp500.py": "https://files.ballistica.net/cache/ba1/bb/19/e298405e000df436dee9331327cd", + "assets/build/windows/Win32/Lib/encodings/cp720.py": "https://files.ballistica.net/cache/ba1/54/06/8dbf13e0ba1e6ebb13249dfbe449", + "assets/build/windows/Win32/Lib/encodings/cp737.py": "https://files.ballistica.net/cache/ba1/56/c1/cf08397bfbac35ca9a26951af2e2", + "assets/build/windows/Win32/Lib/encodings/cp775.py": "https://files.ballistica.net/cache/ba1/d0/d4/e0a4547c5853e36e8496ebcca08f", + "assets/build/windows/Win32/Lib/encodings/cp850.py": "https://files.ballistica.net/cache/ba1/74/7d/482f2d10fd45b5481c6fd8e0d000", + "assets/build/windows/Win32/Lib/encodings/cp852.py": "https://files.ballistica.net/cache/ba1/be/ea/645638e25c84ab1eefe98a017c44", + "assets/build/windows/Win32/Lib/encodings/cp855.py": "https://files.ballistica.net/cache/ba1/be/ff/27d738b63cbdb0a088d61e469f2d", + "assets/build/windows/Win32/Lib/encodings/cp856.py": "https://files.ballistica.net/cache/ba1/70/a9/8039d96806c15cd41ee0cf3c129e", + "assets/build/windows/Win32/Lib/encodings/cp857.py": "https://files.ballistica.net/cache/ba1/e1/42/b6db24f7914142da06f25070763c", + "assets/build/windows/Win32/Lib/encodings/cp858.py": "https://files.ballistica.net/cache/ba1/2d/76/2fc64c375b5d044508f61d68f345", + "assets/build/windows/Win32/Lib/encodings/cp860.py": "https://files.ballistica.net/cache/ba1/56/46/f37d63fc3725291352dd942690af", + "assets/build/windows/Win32/Lib/encodings/cp861.py": "https://files.ballistica.net/cache/ba1/e0/78/71599103be5608aae7b418b7c1f4", + "assets/build/windows/Win32/Lib/encodings/cp862.py": "https://files.ballistica.net/cache/ba1/d7/bb/6ebbe8ad5bcbe6dccb7516b173bd", + "assets/build/windows/Win32/Lib/encodings/cp863.py": "https://files.ballistica.net/cache/ba1/61/bb/44577e96baeb76ee9634d7dd72e7", + "assets/build/windows/Win32/Lib/encodings/cp864.py": "https://files.ballistica.net/cache/ba1/1c/61/3fd4c19c2f079bb3f2f889f24214", + "assets/build/windows/Win32/Lib/encodings/cp865.py": "https://files.ballistica.net/cache/ba1/cb/1e/2808aa8d5dfeebbaa85ec6391028", + "assets/build/windows/Win32/Lib/encodings/cp866.py": "https://files.ballistica.net/cache/ba1/b5/fd/1fae6d351f9f56453af776aa3178", + "assets/build/windows/Win32/Lib/encodings/cp869.py": "https://files.ballistica.net/cache/ba1/59/1f/928020788fef916505477a1af38a", + "assets/build/windows/Win32/Lib/encodings/cp874.py": "https://files.ballistica.net/cache/ba1/c2/fb/4fb9e0253a0003f8ef3d06092c47", + "assets/build/windows/Win32/Lib/encodings/cp875.py": "https://files.ballistica.net/cache/ba1/c2/c2/5b98ded094a33895e936e51bef3c", + "assets/build/windows/Win32/Lib/encodings/cp932.py": "https://files.ballistica.net/cache/ba1/30/8a/b850c7131b835043070dd23cb448", + "assets/build/windows/Win32/Lib/encodings/cp949.py": "https://files.ballistica.net/cache/ba1/c1/f0/3125394eb5c65fd69a3727bf5d24", + "assets/build/windows/Win32/Lib/encodings/cp950.py": "https://files.ballistica.net/cache/ba1/fa/9e/18fad07c67b69a92de36307ea755", + "assets/build/windows/Win32/Lib/encodings/euc_jis_2004.py": "https://files.ballistica.net/cache/ba1/54/91/7bd52fc806dae474183e780ca737", + "assets/build/windows/Win32/Lib/encodings/euc_jisx0213.py": "https://files.ballistica.net/cache/ba1/0c/08/e3660d7e1c63519d844461bf6cc5", + "assets/build/windows/Win32/Lib/encodings/euc_jp.py": "https://files.ballistica.net/cache/ba1/cb/27/12fd7ed4f52ed310ecd698d4afa0", + "assets/build/windows/Win32/Lib/encodings/euc_kr.py": "https://files.ballistica.net/cache/ba1/27/e1/0791e94e9fbf1c775822db3203f5", + "assets/build/windows/Win32/Lib/encodings/gb18030.py": "https://files.ballistica.net/cache/ba1/55/a4/3a0baefee1510dab0a10ce7be07f", + "assets/build/windows/Win32/Lib/encodings/gb2312.py": "https://files.ballistica.net/cache/ba1/18/89/82f27a14c4e50438daf7a1b43c7a", + "assets/build/windows/Win32/Lib/encodings/gbk.py": "https://files.ballistica.net/cache/ba1/c2/e5/89158266cac7e905aec39b3a386d", + "assets/build/windows/Win32/Lib/encodings/hex_codec.py": "https://files.ballistica.net/cache/ba1/f9/f0/99096817ec50a43574f5b13324e9", + "assets/build/windows/Win32/Lib/encodings/hp_roman8.py": "https://files.ballistica.net/cache/ba1/c3/a5/f69c9ab78d48a231843c8f442ee2", + "assets/build/windows/Win32/Lib/encodings/hz.py": "https://files.ballistica.net/cache/ba1/18/42/04846c7ccfc6f1dd92bd738ef3c2", + "assets/build/windows/Win32/Lib/encodings/idna.py": "https://files.ballistica.net/cache/ba1/bb/5a/adf3a73d954cd499cda1cbaa4c8e", + "assets/build/windows/Win32/Lib/encodings/iso2022_jp.py": "https://files.ballistica.net/cache/ba1/52/d1/dfd6413d34e9a3d9828cac952498", + "assets/build/windows/Win32/Lib/encodings/iso2022_jp_1.py": "https://files.ballistica.net/cache/ba1/e3/bd/75f5029b160812d3467b1deb71a0", + "assets/build/windows/Win32/Lib/encodings/iso2022_jp_2.py": "https://files.ballistica.net/cache/ba1/86/49/e1b42c251a8a428d4d15c3582ded", + "assets/build/windows/Win32/Lib/encodings/iso2022_jp_2004.py": "https://files.ballistica.net/cache/ba1/b3/18/abab0add51e2735cae631192a108", + "assets/build/windows/Win32/Lib/encodings/iso2022_jp_3.py": "https://files.ballistica.net/cache/ba1/02/99/66ce9f543edc09ab9ee0dd365a5a", + "assets/build/windows/Win32/Lib/encodings/iso2022_jp_ext.py": "https://files.ballistica.net/cache/ba1/4a/fa/de3068d1b82201597129c96d2402", + "assets/build/windows/Win32/Lib/encodings/iso2022_kr.py": "https://files.ballistica.net/cache/ba1/c1/3f/0084a5f33f40ac249d7a7f42ba6c", + "assets/build/windows/Win32/Lib/encodings/iso8859_1.py": "https://files.ballistica.net/cache/ba1/05/cc/1be2d57d81b08ca7c45f37887990", + "assets/build/windows/Win32/Lib/encodings/iso8859_10.py": "https://files.ballistica.net/cache/ba1/53/de/825c0e81ca85801a4a487b59e649", + "assets/build/windows/Win32/Lib/encodings/iso8859_11.py": "https://files.ballistica.net/cache/ba1/3a/b7/fa02f87fcbfac1c857e6eea35be4", + "assets/build/windows/Win32/Lib/encodings/iso8859_13.py": "https://files.ballistica.net/cache/ba1/6e/67/1452d5cd3b5150504574bf82cc65", + "assets/build/windows/Win32/Lib/encodings/iso8859_14.py": "https://files.ballistica.net/cache/ba1/41/df/6d0aafe8f31df2477102ceb578c1", + "assets/build/windows/Win32/Lib/encodings/iso8859_15.py": "https://files.ballistica.net/cache/ba1/c0/32/d256cfe344d7bf1bcce4562383eb", + "assets/build/windows/Win32/Lib/encodings/iso8859_16.py": "https://files.ballistica.net/cache/ba1/21/3f/3ec08c7249fe62ea857671765761", + "assets/build/windows/Win32/Lib/encodings/iso8859_2.py": "https://files.ballistica.net/cache/ba1/13/7f/aa4831a981e2d24fc004e07c1f4b", + "assets/build/windows/Win32/Lib/encodings/iso8859_3.py": "https://files.ballistica.net/cache/ba1/d2/70/e9e11fc724bb7a5de274ba845ef5", + "assets/build/windows/Win32/Lib/encodings/iso8859_4.py": "https://files.ballistica.net/cache/ba1/36/76/8143407a078308fe11a93f08ae89", + "assets/build/windows/Win32/Lib/encodings/iso8859_5.py": "https://files.ballistica.net/cache/ba1/46/6f/563d5a496dfb2459bc5c7b08ebcd", + "assets/build/windows/Win32/Lib/encodings/iso8859_6.py": "https://files.ballistica.net/cache/ba1/71/ac/874b7e441d428cf5ae181bd5bb41", + "assets/build/windows/Win32/Lib/encodings/iso8859_7.py": "https://files.ballistica.net/cache/ba1/7c/16/8fa091513c28d0727576988ca2d1", + "assets/build/windows/Win32/Lib/encodings/iso8859_8.py": "https://files.ballistica.net/cache/ba1/70/60/c888d1f1d4347914bd689e75eb09", + "assets/build/windows/Win32/Lib/encodings/iso8859_9.py": "https://files.ballistica.net/cache/ba1/02/18/f5a7e43238cc3035d3a1fbc01fb1", + "assets/build/windows/Win32/Lib/encodings/johab.py": "https://files.ballistica.net/cache/ba1/cf/d4/034a613a3b12d7c1dbc97b439441", + "assets/build/windows/Win32/Lib/encodings/koi8_r.py": "https://files.ballistica.net/cache/ba1/72/5e/fd8aaa704c7902394cd521cad6eb", + "assets/build/windows/Win32/Lib/encodings/koi8_t.py": "https://files.ballistica.net/cache/ba1/d8/43/ec2e92a189a5c353fac8b1a016bd", + "assets/build/windows/Win32/Lib/encodings/koi8_u.py": "https://files.ballistica.net/cache/ba1/b3/59/47c7bd9e465176ba19587528a2ad", + "assets/build/windows/Win32/Lib/encodings/kz1048.py": "https://files.ballistica.net/cache/ba1/d3/5b/422fa8a73c17bb05fdff6f663827", + "assets/build/windows/Win32/Lib/encodings/latin_1.py": "https://files.ballistica.net/cache/ba1/41/45/1c7f9d33cc7a8febf0a0071808cc", + "assets/build/windows/Win32/Lib/encodings/mac_arabic.py": "https://files.ballistica.net/cache/ba1/0a/8a/ab8900ad1b09cd5faeeb6eb6b5c6", + "assets/build/windows/Win32/Lib/encodings/mac_centeuro.py": "https://files.ballistica.net/cache/ba1/6c/27/ad832c0664490a0783439df01a7f", + "assets/build/windows/Win32/Lib/encodings/mac_croatian.py": "https://files.ballistica.net/cache/ba1/a5/01/ae139e112718536de88fe63f5bbf", + "assets/build/windows/Win32/Lib/encodings/mac_cyrillic.py": "https://files.ballistica.net/cache/ba1/01/84/40472ce95eaf2c04d3387a021eeb", + "assets/build/windows/Win32/Lib/encodings/mac_farsi.py": "https://files.ballistica.net/cache/ba1/04/9c/0b1bfb3fa6b4580cbc0c95f05f3d", + "assets/build/windows/Win32/Lib/encodings/mac_greek.py": "https://files.ballistica.net/cache/ba1/9c/d0/840650e734e4b7bd55c5e8322714", + "assets/build/windows/Win32/Lib/encodings/mac_iceland.py": "https://files.ballistica.net/cache/ba1/79/94/22a1bfb52d879c48afb0d7fb3960", + "assets/build/windows/Win32/Lib/encodings/mac_latin2.py": "https://files.ballistica.net/cache/ba1/e4/14/bb21b2f80597573dde201a847e4f", + "assets/build/windows/Win32/Lib/encodings/mac_roman.py": "https://files.ballistica.net/cache/ba1/ca/7f/68b9a04e47c09881a88351a7a924", + "assets/build/windows/Win32/Lib/encodings/mac_romanian.py": "https://files.ballistica.net/cache/ba1/75/9a/f10a4f64f31715a9ab7320e982f4", + "assets/build/windows/Win32/Lib/encodings/mac_turkish.py": "https://files.ballistica.net/cache/ba1/bc/e1/fd00b935519743331f28cf142b30", + "assets/build/windows/Win32/Lib/encodings/mbcs.py": "https://files.ballistica.net/cache/ba1/7f/c3/d5b7c74f6b1a2f476c0ef640c987", + "assets/build/windows/Win32/Lib/encodings/oem.py": "https://files.ballistica.net/cache/ba1/fa/02/08370f780f841c23b7a8dd8f25aa", + "assets/build/windows/Win32/Lib/encodings/palmos.py": "https://files.ballistica.net/cache/ba1/7b/fd/8cd9337594e60b0feddcf25c368d", + "assets/build/windows/Win32/Lib/encodings/ptcp154.py": "https://files.ballistica.net/cache/ba1/20/3b/47719c175fdfe43538c5e9792d24", + "assets/build/windows/Win32/Lib/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/94/05/babf7961a3c24e2e90ea827d7031", + "assets/build/windows/Win32/Lib/encodings/quopri_codec.py": "https://files.ballistica.net/cache/ba1/73/b5/88317f8c11128b5797b6b282b22a", + "assets/build/windows/Win32/Lib/encodings/raw_unicode_escape.py": "https://files.ballistica.net/cache/ba1/6a/82/0df142d583fcad7deba60635eafa", + "assets/build/windows/Win32/Lib/encodings/rot_13.py": "https://files.ballistica.net/cache/ba1/a9/86/d0e282a103b6005c7eba393c2865", + "assets/build/windows/Win32/Lib/encodings/shift_jis.py": "https://files.ballistica.net/cache/ba1/ba/2c/2ef82e17969f3b47e0dfe36f8439", + "assets/build/windows/Win32/Lib/encodings/shift_jis_2004.py": "https://files.ballistica.net/cache/ba1/e4/7f/191f32888ecc24da183a30be5976", + "assets/build/windows/Win32/Lib/encodings/shift_jisx0213.py": "https://files.ballistica.net/cache/ba1/9d/3e/acee612d961a29508e4fc5405d9d", + "assets/build/windows/Win32/Lib/encodings/tis_620.py": "https://files.ballistica.net/cache/ba1/11/e1/d45a248d14f218f1f4b35b46f949", + "assets/build/windows/Win32/Lib/encodings/undefined.py": "https://files.ballistica.net/cache/ba1/31/c6/571a6f1a9c7aa0d26e721ba4fc65", + "assets/build/windows/Win32/Lib/encodings/unicode_escape.py": "https://files.ballistica.net/cache/ba1/3b/e4/ae4a2dae3bb7edf7532fc7cef81a", + "assets/build/windows/Win32/Lib/encodings/utf_16.py": "https://files.ballistica.net/cache/ba1/2c/d5/a7818c23518a9bb340183dd05c1d", + "assets/build/windows/Win32/Lib/encodings/utf_16_be.py": "https://files.ballistica.net/cache/ba1/7f/2c/d6f996bcb15cda0a566bd3517239", + "assets/build/windows/Win32/Lib/encodings/utf_16_le.py": "https://files.ballistica.net/cache/ba1/8b/92/2014625fc6fc4012468d4fcc1551", + "assets/build/windows/Win32/Lib/encodings/utf_32.py": "https://files.ballistica.net/cache/ba1/71/bb/dd68363e86733e927523d710ba8c", + "assets/build/windows/Win32/Lib/encodings/utf_32_be.py": "https://files.ballistica.net/cache/ba1/1c/87/c323363c9f47092c236783f2e0e3", + "assets/build/windows/Win32/Lib/encodings/utf_32_le.py": "https://files.ballistica.net/cache/ba1/38/df/5b501debcfe2f050060ffe14b70c", + "assets/build/windows/Win32/Lib/encodings/utf_7.py": "https://files.ballistica.net/cache/ba1/fe/2c/cc363eceaec22d46829d0b3748e5", + "assets/build/windows/Win32/Lib/encodings/utf_8.py": "https://files.ballistica.net/cache/ba1/82/0e/a8bd3ac0e209ec22903f36c7e743", + "assets/build/windows/Win32/Lib/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/02/57/abf1662be43acd806d712d09ad92", + "assets/build/windows/Win32/Lib/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/ac/6a/ef4e3dfe6cb0ca98be39de499609", + "assets/build/windows/Win32/Lib/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/ca/b7/a919c6be178102f90d97879e61ec", + "assets/build/windows/Win32/Lib/enum.py": "https://files.ballistica.net/cache/ba1/b5/48/1d1c8b714439cb31efc583187a62", + "assets/build/windows/Win32/Lib/filecmp.py": "https://files.ballistica.net/cache/ba1/20/32/e1aa0ebff27033ec554330288554", + "assets/build/windows/Win32/Lib/fileinput.py": "https://files.ballistica.net/cache/ba1/c5/77/3090267f0805b911112684459b56", + "assets/build/windows/Win32/Lib/fnmatch.py": "https://files.ballistica.net/cache/ba1/50/d8/be1bfccd23262714b368a87efcfe", + "assets/build/windows/Win32/Lib/formatter.py": "https://files.ballistica.net/cache/ba1/94/4e/c1f6b9a2f088571d5faa0f323dca", + "assets/build/windows/Win32/Lib/fractions.py": "https://files.ballistica.net/cache/ba1/95/71/912995f855291425d58862c2348a", + "assets/build/windows/Win32/Lib/ftplib.py": "https://files.ballistica.net/cache/ba1/03/95/cb1b32f050224f99450715112d7d", + "assets/build/windows/Win32/Lib/functools.py": "https://files.ballistica.net/cache/ba1/46/0f/ce08a76f27dd0a726af57a09e4e9", + "assets/build/windows/Win32/Lib/genericpath.py": "https://files.ballistica.net/cache/ba1/48/83/1d5fa6fd3806f0a0dc604f9ec2e1", + "assets/build/windows/Win32/Lib/getopt.py": "https://files.ballistica.net/cache/ba1/c8/63/dfdbb68d2e67c3bae4f9dcc3f0f5", + "assets/build/windows/Win32/Lib/getpass.py": "https://files.ballistica.net/cache/ba1/be/e6/71f0a41074219d94d7e5f4d4dd77", + "assets/build/windows/Win32/Lib/gettext.py": "https://files.ballistica.net/cache/ba1/68/ac/560154c6e471eca4839dc2a2f207", + "assets/build/windows/Win32/Lib/glob.py": "https://files.ballistica.net/cache/ba1/ca/2c/ae8a44614324e4f1b5fb1888b530", + "assets/build/windows/Win32/Lib/gzip.py": "https://files.ballistica.net/cache/ba1/14/0b/f5188d97584eab715d09d0c3e263", + "assets/build/windows/Win32/Lib/hashlib.py": "https://files.ballistica.net/cache/ba1/62/18/a22dd8c65174420d1bef002c7e4c", + "assets/build/windows/Win32/Lib/heapq.py": "https://files.ballistica.net/cache/ba1/d5/7d/ed2881850aeb9d3ecd56f38175b7", + "assets/build/windows/Win32/Lib/hmac.py": "https://files.ballistica.net/cache/ba1/39/d5/f16de28e25d8a4f482d7c4e00457", + "assets/build/windows/Win32/Lib/html/__init__.py": "https://files.ballistica.net/cache/ba1/8c/08/c638db74e5e5979dea109da1f68b", + "assets/build/windows/Win32/Lib/html/entities.py": "https://files.ballistica.net/cache/ba1/52/69/e7311caea2fbfdfef9c05515de4b", + "assets/build/windows/Win32/Lib/html/parser.py": "https://files.ballistica.net/cache/ba1/93/8c/7e6734f43521e484eff3265c3b2f", + "assets/build/windows/Win32/Lib/http/__init__.py": "https://files.ballistica.net/cache/ba1/c6/f1/db2ad2c4d17dcda4c7c908fd0594", + "assets/build/windows/Win32/Lib/http/client.py": "https://files.ballistica.net/cache/ba1/6a/9f/9fc4ae67187f07ee2ac8b35b7079", + "assets/build/windows/Win32/Lib/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/ce/d1/d948c21fe6cee0951134e1441762", + "assets/build/windows/Win32/Lib/http/cookies.py": "https://files.ballistica.net/cache/ba1/1c/44/3832b5763a5ca6d422a0b1dfb34a", + "assets/build/windows/Win32/Lib/http/server.py": "https://files.ballistica.net/cache/ba1/cf/30/e6488897f60e5d51f32d55a5e542", + "assets/build/windows/Win32/Lib/imghdr.py": "https://files.ballistica.net/cache/ba1/68/6a/6e1e60839584bc133ee001bbe810", + "assets/build/windows/Win32/Lib/imp.py": "https://files.ballistica.net/cache/ba1/27/49/796442c2ad99d661778789ccb6b9", + "assets/build/windows/Win32/Lib/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/9d/88/7fbbfcef32d68d60a7cf2d1c9f33", + "assets/build/windows/Win32/Lib/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/f0/1a/a3698578fdab450d3cb0d624524b", + "assets/build/windows/Win32/Lib/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/d4/8c/0ba35e65bab4befa47988b55fe52", + "assets/build/windows/Win32/Lib/importlib/abc.py": "https://files.ballistica.net/cache/ba1/e1/ce/cf8dfb21a116a8bf87f757ddb332", + "assets/build/windows/Win32/Lib/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/a1/ac/b97d16285d94f0b18406366d803b", + "assets/build/windows/Win32/Lib/importlib/metadata.py": "https://files.ballistica.net/cache/ba1/50/b7/1e091864ef2342eb9f7627a5ad85", + "assets/build/windows/Win32/Lib/importlib/resources.py": "https://files.ballistica.net/cache/ba1/4e/31/44caa392a8ff3ca4c72b95e499b7", + "assets/build/windows/Win32/Lib/importlib/util.py": "https://files.ballistica.net/cache/ba1/5e/96/a3d35aecec8ff9e6f2158f56c27c", + "assets/build/windows/Win32/Lib/inspect.py": "https://files.ballistica.net/cache/ba1/7b/e2/ac2e2c98758f67254c26403eb3ad", + "assets/build/windows/Win32/Lib/io.py": "https://files.ballistica.net/cache/ba1/f1/4f/e33a91472082f5ee05b0a352c36d", + "assets/build/windows/Win32/Lib/ipaddress.py": "https://files.ballistica.net/cache/ba1/1a/5f/d02ef4503e4d8b0f50efa3037cc7", + "assets/build/windows/Win32/Lib/json/__init__.py": "https://files.ballistica.net/cache/ba1/5e/b6/0e2a48ac4f7c1bd0646e260467c0", + "assets/build/windows/Win32/Lib/json/decoder.py": "https://files.ballistica.net/cache/ba1/f5/44/19f6e70ef50bed1f318027bbf9aa", + "assets/build/windows/Win32/Lib/json/encoder.py": "https://files.ballistica.net/cache/ba1/b3/1a/63e5bf127edf3000e7d276c6c5be", + "assets/build/windows/Win32/Lib/json/scanner.py": "https://files.ballistica.net/cache/ba1/a7/9e/0fdf34c72293733a58f0dd2677fa", + "assets/build/windows/Win32/Lib/json/tool.py": "https://files.ballistica.net/cache/ba1/bf/da/feeaf67e5b1d79e759e3e75f0b03", + "assets/build/windows/Win32/Lib/keyword.py": "https://files.ballistica.net/cache/ba1/38/d0/bbde6b4e54dcf437fca3aa869732", + "assets/build/windows/Win32/Lib/linecache.py": "https://files.ballistica.net/cache/ba1/fa/63/086a9b401b1c2e3cb7eccac17e41", + "assets/build/windows/Win32/Lib/locale.py": "https://files.ballistica.net/cache/ba1/e9/ab/2a915b79b3ba36becb4dbb59107d", + "assets/build/windows/Win32/Lib/logging/__init__.py": "https://files.ballistica.net/cache/ba1/03/4f/7818d4ed23340153e1dbb1993d90", + "assets/build/windows/Win32/Lib/logging/config.py": "https://files.ballistica.net/cache/ba1/56/55/6da1bbc4da532f4ad4a183baca07", + "assets/build/windows/Win32/Lib/logging/handlers.py": "https://files.ballistica.net/cache/ba1/e9/8c/e7dd81f83b123d9f343ddc1408fc", + "assets/build/windows/Win32/Lib/lzma.py": "https://files.ballistica.net/cache/ba1/88/58/5eb2ce7457b4084010d40fa35609", + "assets/build/windows/Win32/Lib/mailbox.py": "https://files.ballistica.net/cache/ba1/77/3a/8ee9e0108fb3be6daec90dce4b30", + "assets/build/windows/Win32/Lib/mailcap.py": "https://files.ballistica.net/cache/ba1/cd/ef/d43f7e1f692a91246149348186f8", + "assets/build/windows/Win32/Lib/mimetypes.py": "https://files.ballistica.net/cache/ba1/fb/64/9905e7bacf8b6a9b082267e8ff8c", + "assets/build/windows/Win32/Lib/modulefinder.py": "https://files.ballistica.net/cache/ba1/19/1b/b25e54572967128c0c2e3b53b457", + "assets/build/windows/Win32/Lib/msilib/__init__.py": "https://files.ballistica.net/cache/ba1/32/b4/3d542fb6efb60c95af4e1edbe102", + "assets/build/windows/Win32/Lib/msilib/schema.py": "https://files.ballistica.net/cache/ba1/65/dd/95b460cf2c95a6caf4bdbb1a3d51", + "assets/build/windows/Win32/Lib/msilib/sequence.py": "https://files.ballistica.net/cache/ba1/5e/c4/a7a6140c298325ee69a8958b40d6", + "assets/build/windows/Win32/Lib/msilib/text.py": "https://files.ballistica.net/cache/ba1/49/b2/15871bd0d47d347c9371490eb35f", + "assets/build/windows/Win32/Lib/netrc.py": "https://files.ballistica.net/cache/ba1/6e/c7/c912c856c06d61ce362403506c58", + "assets/build/windows/Win32/Lib/nntplib.py": "https://files.ballistica.net/cache/ba1/38/10/cf7944b2ea0b601f10961acf9338", + "assets/build/windows/Win32/Lib/ntpath.py": "https://files.ballistica.net/cache/ba1/48/9d/a2164b32a2d851aa5b1854e0b143", + "assets/build/windows/Win32/Lib/nturl2path.py": "https://files.ballistica.net/cache/ba1/05/77/b863ff2e727259dac90f77bdcbfb", + "assets/build/windows/Win32/Lib/numbers.py": "https://files.ballistica.net/cache/ba1/19/02/57245f310345adfc574565c19471", + "assets/build/windows/Win32/Lib/opcode.py": "https://files.ballistica.net/cache/ba1/58/a0/cd29e37289328e38f4092f32a2e9", + "assets/build/windows/Win32/Lib/operator.py": "https://files.ballistica.net/cache/ba1/d2/72/3e9422ccde5f840628c2dae8a3db", + "assets/build/windows/Win32/Lib/optparse.py": "https://files.ballistica.net/cache/ba1/a5/df/e3d1a9c843816d0b3f39db14e4de", + "assets/build/windows/Win32/Lib/os.py": "https://files.ballistica.net/cache/ba1/55/1f/30b9d9cfce387d484dbec2701dfa", + "assets/build/windows/Win32/Lib/pathlib.py": "https://files.ballistica.net/cache/ba1/a3/bf/5b9c1655bef8cf01ee0b19283126", + "assets/build/windows/Win32/Lib/pdb.py": "https://files.ballistica.net/cache/ba1/a2/78/7b8651a73017df6a8933373db028", + "assets/build/windows/Win32/Lib/pickle.py": "https://files.ballistica.net/cache/ba1/ee/a4/ba3b129ed355075e5f2aa03b4fd2", + "assets/build/windows/Win32/Lib/pickletools.py": "https://files.ballistica.net/cache/ba1/c5/21/87c5922f498939a39d5068416c01", + "assets/build/windows/Win32/Lib/pipes.py": "https://files.ballistica.net/cache/ba1/4f/e3/798b7a258f1747aa6c5abb437149", + "assets/build/windows/Win32/Lib/pkgutil.py": "https://files.ballistica.net/cache/ba1/71/ec/ef12b9e970cdd6519387ad7168bc", + "assets/build/windows/Win32/Lib/platform.py": "https://files.ballistica.net/cache/ba1/24/d8/2932e822b160837c78865f13ab3c", + "assets/build/windows/Win32/Lib/plistlib.py": "https://files.ballistica.net/cache/ba1/ce/8e/69f629d62bcd9fb7ae75e8ca559f", + "assets/build/windows/Win32/Lib/poplib.py": "https://files.ballistica.net/cache/ba1/a0/e5/88e0487f1a7af2ec9d122feb3087", + "assets/build/windows/Win32/Lib/posixpath.py": "https://files.ballistica.net/cache/ba1/e2/34/814d24130241fd67c143813a24c0", + "assets/build/windows/Win32/Lib/pprint.py": "https://files.ballistica.net/cache/ba1/3b/b7/54e56a08109e3477e8aa436f6244", + "assets/build/windows/Win32/Lib/profile.py": "https://files.ballistica.net/cache/ba1/6f/6a/21204d8262bb6ae0ec570185d14e", + "assets/build/windows/Win32/Lib/pstats.py": "https://files.ballistica.net/cache/ba1/a0/b3/5a3bb49ede314fb6eb91ce354a4a", + "assets/build/windows/Win32/Lib/pty.py": "https://files.ballistica.net/cache/ba1/5c/f5/48d694cc661d436af2c44371fd2a", + "assets/build/windows/Win32/Lib/py_compile.py": "https://files.ballistica.net/cache/ba1/37/e5/29d7a2ca1aa281015151eed79abe", + "assets/build/windows/Win32/Lib/pyclbr.py": "https://files.ballistica.net/cache/ba1/51/4e/7f73565177805a6f80a08c5c72de", + "assets/build/windows/Win32/Lib/pydoc.py": "https://files.ballistica.net/cache/ba1/77/33/1e952dd1e7c7a2e083a9774a3d26", + "assets/build/windows/Win32/Lib/queue.py": "https://files.ballistica.net/cache/ba1/2a/d7/fa97bd96b3e7b51160cb8afea22b", + "assets/build/windows/Win32/Lib/quopri.py": "https://files.ballistica.net/cache/ba1/2c/58/ad0d88ce4f54696b2e3b77229b6f", + "assets/build/windows/Win32/Lib/random.py": "https://files.ballistica.net/cache/ba1/d0/83/f1f367e044737bfcc55df64bfbdd", + "assets/build/windows/Win32/Lib/re.py": "https://files.ballistica.net/cache/ba1/91/62/5aab4405c5f6ae6209896fc7392e", + "assets/build/windows/Win32/Lib/reprlib.py": "https://files.ballistica.net/cache/ba1/a8/ba/d93d9b48a6c8e84421dc29a7a356", + "assets/build/windows/Win32/Lib/rlcompleter.py": "https://files.ballistica.net/cache/ba1/07/36/8d1de8a69e6b5b1cc73d0216948a", + "assets/build/windows/Win32/Lib/runpy.py": "https://files.ballistica.net/cache/ba1/61/aa/784e414b515e3868431f6b50c8d3", + "assets/build/windows/Win32/Lib/sched.py": "https://files.ballistica.net/cache/ba1/c6/60/916d287001a20a6a9b10edec7eab", + "assets/build/windows/Win32/Lib/secrets.py": "https://files.ballistica.net/cache/ba1/56/3e/95bb97b0783468cfc2d3334daa98", + "assets/build/windows/Win32/Lib/selectors.py": "https://files.ballistica.net/cache/ba1/af/9a/2ffd2e47c2bfd9318aaf126ee6af", + "assets/build/windows/Win32/Lib/shelve.py": "https://files.ballistica.net/cache/ba1/78/b5/9bc76a4facc8d27398b939bc074b", + "assets/build/windows/Win32/Lib/shlex.py": "https://files.ballistica.net/cache/ba1/7c/d3/d968a6d998135ef16d6940f7f995", + "assets/build/windows/Win32/Lib/shutil.py": "https://files.ballistica.net/cache/ba1/36/97/d5b05739b9db38ce9ff006235f19", + "assets/build/windows/Win32/Lib/signal.py": "https://files.ballistica.net/cache/ba1/bd/2a/c03beeb8d029363b4fc9711800d5", + "assets/build/windows/Win32/Lib/site.py": "https://files.ballistica.net/cache/ba1/f9/d0/f195220772908a353fc92d69f9f9", + "assets/build/windows/Win32/Lib/smtpd.py": "https://files.ballistica.net/cache/ba1/63/b6/77d11c42ae0775a49ed76818bffb", + "assets/build/windows/Win32/Lib/smtplib.py": "https://files.ballistica.net/cache/ba1/2d/2b/db11a6f8a062fad8d96cd930bb38", + "assets/build/windows/Win32/Lib/sndhdr.py": "https://files.ballistica.net/cache/ba1/42/b0/9e3b462c511a254446918db4aba8", + "assets/build/windows/Win32/Lib/socket.py": "https://files.ballistica.net/cache/ba1/f9/a8/dedb211f89a29b5bd52ccced646a", + "assets/build/windows/Win32/Lib/socketserver.py": "https://files.ballistica.net/cache/ba1/d9/d9/7c1012e7659b8cea54a356640bb6", + "assets/build/windows/Win32/Lib/sqlite3/__init__.py": "https://files.ballistica.net/cache/ba1/4b/1b/be86116df24d067bf7aaa9dc690b", + "assets/build/windows/Win32/Lib/sqlite3/dbapi2.py": "https://files.ballistica.net/cache/ba1/12/ce/e004498a9d51b893c10a613c7c56", + "assets/build/windows/Win32/Lib/sqlite3/dump.py": "https://files.ballistica.net/cache/ba1/25/0e/52f5b1972488978dae3361460bec", + "assets/build/windows/Win32/Lib/sre_compile.py": "https://files.ballistica.net/cache/ba1/4d/63/8f72f4d7971992ec557e85a2ee62", + "assets/build/windows/Win32/Lib/sre_constants.py": "https://files.ballistica.net/cache/ba1/98/73/9d378c6d7c544da40403d2239721", + "assets/build/windows/Win32/Lib/sre_parse.py": "https://files.ballistica.net/cache/ba1/71/e7/0573aa4c865148946654dc0d473f", + "assets/build/windows/Win32/Lib/ssl.py": "https://files.ballistica.net/cache/ba1/fa/c4/63a9bc96c87579ff68a90a7fa5c2", + "assets/build/windows/Win32/Lib/stat.py": "https://files.ballistica.net/cache/ba1/1c/49/d7af3700c37df3d672ebbc0dc6db", + "assets/build/windows/Win32/Lib/statistics.py": "https://files.ballistica.net/cache/ba1/9b/cf/f5eb6d591c37fcfb405f0d7b5834", + "assets/build/windows/Win32/Lib/string.py": "https://files.ballistica.net/cache/ba1/e7/fe/3438429367248c9d31ff9adebb32", + "assets/build/windows/Win32/Lib/stringprep.py": "https://files.ballistica.net/cache/ba1/5b/42/39b8e69a2979e4f553bb6908b545", + "assets/build/windows/Win32/Lib/struct.py": "https://files.ballistica.net/cache/ba1/8e/da/3a3bdc58e197050b1906c1c86266", + "assets/build/windows/Win32/Lib/subprocess.py": "https://files.ballistica.net/cache/ba1/2b/3d/4f73c118219b99930ff16ce7413e", + "assets/build/windows/Win32/Lib/sunau.py": "https://files.ballistica.net/cache/ba1/83/4a/58133fd86ce134568f30cfa21b9c", + "assets/build/windows/Win32/Lib/symbol.py": "https://files.ballistica.net/cache/ba1/c4/bc/0e4adc5bf818f8ad24c90563d33d", + "assets/build/windows/Win32/Lib/symtable.py": "https://files.ballistica.net/cache/ba1/5d/1b/0368eb2693de8b03cc741ab7b4ad", + "assets/build/windows/Win32/Lib/sysconfig.py": "https://files.ballistica.net/cache/ba1/94/2c/060345a8379488204c165600eb41", + "assets/build/windows/Win32/Lib/tabnanny.py": "https://files.ballistica.net/cache/ba1/f0/6a/00c300ad5404f3bbbe4fe723a466", + "assets/build/windows/Win32/Lib/tarfile.py": "https://files.ballistica.net/cache/ba1/f3/cc/c392e24006d4ca942b0979e1a402", + "assets/build/windows/Win32/Lib/telnetlib.py": "https://files.ballistica.net/cache/ba1/0a/4b/b81b510b87a106cf8f9715d26c66", + "assets/build/windows/Win32/Lib/tempfile.py": "https://files.ballistica.net/cache/ba1/3c/36/b61379137f68368efa37c551d9d7", + "assets/build/windows/Win32/Lib/textwrap.py": "https://files.ballistica.net/cache/ba1/37/f6/08ba64ff387303ae0a39b19a7ad2", + "assets/build/windows/Win32/Lib/this.py": "https://files.ballistica.net/cache/ba1/b0/f9/1eb227ba1d4d069da408b12e8312", + "assets/build/windows/Win32/Lib/threading.py": "https://files.ballistica.net/cache/ba1/3f/71/b7c287f4e49167f63fec0bb357d9", + "assets/build/windows/Win32/Lib/timeit.py": "https://files.ballistica.net/cache/ba1/4f/19/f07bc4e9a8033788216ddc172620", + "assets/build/windows/Win32/Lib/token.py": "https://files.ballistica.net/cache/ba1/ba/13/08f9eed6b214df36aeacb086eaa2", + "assets/build/windows/Win32/Lib/tokenize.py": "https://files.ballistica.net/cache/ba1/d4/03/b677823f75fb00c5553e79e1665d", + "assets/build/windows/Win32/Lib/trace.py": "https://files.ballistica.net/cache/ba1/58/6d/bad849ff6ada0d760ad9e5053816", + "assets/build/windows/Win32/Lib/traceback.py": "https://files.ballistica.net/cache/ba1/d5/56/ec68c9153c3ccf59571d203df771", + "assets/build/windows/Win32/Lib/tracemalloc.py": "https://files.ballistica.net/cache/ba1/91/0a/fcb0e16864c9ffe49e4eb9cc122c", + "assets/build/windows/Win32/Lib/tty.py": "https://files.ballistica.net/cache/ba1/66/b3/bb1684cec763502fdf418909eedc", + "assets/build/windows/Win32/Lib/types.py": "https://files.ballistica.net/cache/ba1/8e/43/16e0fb9fc221c5664760dcb34155", + "assets/build/windows/Win32/Lib/typing.py": "https://files.ballistica.net/cache/ba1/f1/bc/ed57ac1054de7131ac5d8123f0a7", + "assets/build/windows/Win32/Lib/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/48/ca/f840c02dd0e7222236a872a7f278", + "assets/build/windows/Win32/Lib/urllib/error.py": "https://files.ballistica.net/cache/ba1/c9/c8/9d133fc217803023dff6faed8681", + "assets/build/windows/Win32/Lib/urllib/parse.py": "https://files.ballistica.net/cache/ba1/f7/b5/4c33d0394bacab721858874c567e", + "assets/build/windows/Win32/Lib/urllib/request.py": "https://files.ballistica.net/cache/ba1/14/f1/d983ab18df1b11a5fb5037f0404a", + "assets/build/windows/Win32/Lib/urllib/response.py": "https://files.ballistica.net/cache/ba1/bb/87/38040a39e87e422ad8afe64bf2a7", + "assets/build/windows/Win32/Lib/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/7a/b7/3af41797a3ab4b7aca844da2a17f", + "assets/build/windows/Win32/Lib/uu.py": "https://files.ballistica.net/cache/ba1/79/56/361ba661d709ca4e4c187fcbc341", + "assets/build/windows/Win32/Lib/uuid.py": "https://files.ballistica.net/cache/ba1/ea/ef/83330d443458dbd624fe1f2468c5", + "assets/build/windows/Win32/Lib/warnings.py": "https://files.ballistica.net/cache/ba1/54/8b/0cccabedfd1919dfcfaaec80f740", + "assets/build/windows/Win32/Lib/wave.py": "https://files.ballistica.net/cache/ba1/c9/ae/0c817c04a0dd981f32812f72444b", + "assets/build/windows/Win32/Lib/weakref.py": "https://files.ballistica.net/cache/ba1/58/f9/5c6b50780bb277d13853f0c6cc3d", + "assets/build/windows/Win32/Lib/webbrowser.py": "https://files.ballistica.net/cache/ba1/0b/2d/ec8eb248bdc1e9b48e08a7f0bd95", + "assets/build/windows/Win32/Lib/xdrlib.py": "https://files.ballistica.net/cache/ba1/35/a6/f6e14e4fb6beae1f68ec2a4be852", + "assets/build/windows/Win32/Lib/xml/__init__.py": "https://files.ballistica.net/cache/ba1/02/9f/a002b4cb540d2e1c2b68edb44b3c", + "assets/build/windows/Win32/Lib/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/70/fb/e0e98f50e21c494e53869d4d7d32", + "assets/build/windows/Win32/Lib/xml/dom/__init__.py": "https://files.ballistica.net/cache/ba1/da/c6/e03fc8651c8453f97f28b59c39e6", + "assets/build/windows/Win32/Lib/xml/dom/domreg.py": "https://files.ballistica.net/cache/ba1/24/0b/7c0c234f022ab835c9de2ebeae0b", + "assets/build/windows/Win32/Lib/xml/dom/expatbuilder.py": "https://files.ballistica.net/cache/ba1/00/f0/624de9ff458a0086a9287a4eca60", + "assets/build/windows/Win32/Lib/xml/dom/minicompat.py": "https://files.ballistica.net/cache/ba1/00/0c/03191b6f36ce83e51030448fae74", + "assets/build/windows/Win32/Lib/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/25/39/aaab19272ce3158764bcdbf2e284", + "assets/build/windows/Win32/Lib/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/e6/ae/11f1d46033dbad001e32eaf946ff", + "assets/build/windows/Win32/Lib/xml/dom/xmlbuilder.py": "https://files.ballistica.net/cache/ba1/b6/5f/e121c4c15d59af737b1040acc649", + "assets/build/windows/Win32/Lib/xml/etree/ElementInclude.py": "https://files.ballistica.net/cache/ba1/b5/91/29e1f927a81c897f265ba6f4d070", + "assets/build/windows/Win32/Lib/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/66/e0/f9886fd9661a9dbf7369dc5b8eca", + "assets/build/windows/Win32/Lib/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/fa/c0/19b98d57a3f1507ea252e7a16cb2", + "assets/build/windows/Win32/Lib/xml/etree/__init__.py": "https://files.ballistica.net/cache/ba1/ad/6d/fa6c976589d990e355cce61c4c96", + "assets/build/windows/Win32/Lib/xml/etree/cElementTree.py": "https://files.ballistica.net/cache/ba1/50/3c/23d2072448e974423bb11e396ab6", + "assets/build/windows/Win32/Lib/xml/parsers/__init__.py": "https://files.ballistica.net/cache/ba1/19/bf/5493270c481d02ed233d2119653c", + "assets/build/windows/Win32/Lib/xml/parsers/expat.py": "https://files.ballistica.net/cache/ba1/6e/f1/a6aad9b9297dd20b5c24a224eb87", + "assets/build/windows/Win32/Lib/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/23/97/5f390ff406f46bdd6aa543375f93", + "assets/build/windows/Win32/Lib/xml/sax/_exceptions.py": "https://files.ballistica.net/cache/ba1/47/64/9b8c6da80774cf676c116c42c779", + "assets/build/windows/Win32/Lib/xml/sax/expatreader.py": "https://files.ballistica.net/cache/ba1/c7/16/42cb40d7afcde4ce825abf5bfbf3", + "assets/build/windows/Win32/Lib/xml/sax/handler.py": "https://files.ballistica.net/cache/ba1/84/cb/83d1e4735c125aee0b686c26f9d0", + "assets/build/windows/Win32/Lib/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/7c/4e/17f476d11ed38a69f301268f632a", + "assets/build/windows/Win32/Lib/xml/sax/xmlreader.py": "https://files.ballistica.net/cache/ba1/05/f9/eeb1c32818d63991e806451dad45", + "assets/build/windows/Win32/Lib/xmlrpc/__init__.py": "https://files.ballistica.net/cache/ba1/84/79/19c277eda21caa83389ff1c2258f", + "assets/build/windows/Win32/Lib/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/9f/4f/2b601d31b625f3ac9eadf4acf048", + "assets/build/windows/Win32/Lib/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/dd/33/3de3c357d21186eaad20201fe99f", + "assets/build/windows/Win32/Lib/zipapp.py": "https://files.ballistica.net/cache/ba1/92/65/287c3d27f14ea2956622e136f71b", + "assets/build/windows/Win32/Lib/zipfile.py": "https://files.ballistica.net/cache/ba1/ea/20/cd2e335ec716ea491d023c6695fc", + "assets/build/windows/Win32/Lib/zipimport.py": "https://files.ballistica.net/cache/ba1/73/9f/d089ac24f8277925d6938ab1fe1f", + "assets/build/windows/Win32/OpenAL32.dll": "https://files.ballistica.net/cache/ba1/7b/0f/4349781f2e7ea0ced321fd0b9c45", + "assets/build/windows/Win32/SDL2.dll": "https://files.ballistica.net/cache/ba1/c5/7d/e8943b5eda2472a308b63f938b1c", + "assets/build/windows/Win32/libvorbis.dll": "https://files.ballistica.net/cache/ba1/1b/d1/75cc9eb21373659c8baacbdeb080", + "assets/build/windows/Win32/libvorbisfile.dll": "https://files.ballistica.net/cache/ba1/c6/e1/f52f5d6c78f0ba497f0c8cd1c630", + "assets/build/windows/Win32/msvcp140d.dll": "https://files.ballistica.net/cache/ba1/4e/48/54d72587b4bd07abcad311523685", + "assets/build/windows/Win32/ogg.dll": "https://files.ballistica.net/cache/ba1/f2/0c/469bdc2148ad7d94232023da2cc6", + "assets/build/windows/Win32/python.exe": "https://files.ballistica.net/cache/ba1/61/1e/8b300ef4a3c46652ac1f7d01ed53", + "assets/build/windows/Win32/python38.dll": "https://files.ballistica.net/cache/ba1/1f/39/e314c3e7846ecddbd946c08aac04", + "assets/build/windows/Win32/python38_d.dll": "https://files.ballistica.net/cache/ba1/e1/1e/9dd3909f6a7d14ef3f5c95bceb73", + "assets/build/windows/Win32/python_d.exe": "https://files.ballistica.net/cache/ba1/57/2f/7cda5f442a832f8f92fc76e8370d", + "assets/build/windows/Win32/pythonw.exe": "https://files.ballistica.net/cache/ba1/3b/01/7819c084c81c84562a2dab70033e", + "assets/build/windows/Win32/pythonw_d.exe": "https://files.ballistica.net/cache/ba1/4b/df/7ebb1be3e018abc04660d932a7b2", + "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", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/3c/4ec6e5319de5ea5e71c1b9ecb63e", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/40/5d8daec9ea222adba802201b8678", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/bd/1f/3018946be23cfd961f3a9d5d6a1a", From e4f1702fffbc632b241831f2ad10eb79f5800249 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 31 Jul 2020 17:25:31 -0700 Subject: [PATCH 179/417] Fixed out of date windows python assets --- .efrocachemap | 1244 ++++++++++++++++++++++++------------------------- CHANGELOG.md | 4 +- 2 files changed, 624 insertions(+), 624 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 97ac4fed..2a7fce1c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -1,425 +1,425 @@ { - "assets/build/ba_data/audio/achievement.ogg": "https://files.ballistica.net/cache/ba1/92/ed/cc9fae7fa642366402aeb7388047", - "assets/build/ba_data/audio/actionHero1.ogg": "https://files.ballistica.net/cache/ba1/6c/3a/f572c024ad808f893899498b39ed", - "assets/build/ba_data/audio/actionHero2.ogg": "https://files.ballistica.net/cache/ba1/03/f2/fc0f5534275d44e3bbca9e47dcb4", - "assets/build/ba_data/audio/actionHero3.ogg": "https://files.ballistica.net/cache/ba1/e9/66/e54c93567bda9d51f50a5f44e712", - "assets/build/ba_data/audio/actionHero4.ogg": "https://files.ballistica.net/cache/ba1/1d/88/cb185c6bdc3074462b2341eecf13", - "assets/build/ba_data/audio/actionHeroDeath.ogg": "https://files.ballistica.net/cache/ba1/15/67/56eb360b466b83a7d13a37d4179a", - "assets/build/ba_data/audio/actionHeroFall.ogg": "https://files.ballistica.net/cache/ba1/a3/cd/dbd36283e98ae9f34c935875011e", - "assets/build/ba_data/audio/actionHeroHit1.ogg": "https://files.ballistica.net/cache/ba1/ce/1c/2b99311fe5acb7f9f604e583598e", - "assets/build/ba_data/audio/actionHeroHit2.ogg": "https://files.ballistica.net/cache/ba1/97/da/02ca84f151893b8c1243212a6cda", - "assets/build/ba_data/audio/activateBeep.ogg": "https://files.ballistica.net/cache/ba1/4c/76/f3d02055c3138e0c8e28824057dc", - "assets/build/ba_data/audio/agent1.ogg": "https://files.ballistica.net/cache/ba1/cf/15/1dd190effa5072bfb4ed161b6831", - "assets/build/ba_data/audio/agent2.ogg": "https://files.ballistica.net/cache/ba1/41/96/f44e6ce0a2f5cbd1dcc32a25f9bb", - "assets/build/ba_data/audio/agent3.ogg": "https://files.ballistica.net/cache/ba1/d0/71/3ae6fde009e9aa21f7d7afe8b749", - "assets/build/ba_data/audio/agent4.ogg": "https://files.ballistica.net/cache/ba1/c1/05/ac952c89bbf4800b55ca1bf3c217", - "assets/build/ba_data/audio/agentDeath.ogg": "https://files.ballistica.net/cache/ba1/41/6f/816fccfa08f189b0e1c77fb86254", - "assets/build/ba_data/audio/agentFall.ogg": "https://files.ballistica.net/cache/ba1/27/ff/87ab29497c8e44c9574ea45e9471", - "assets/build/ba_data/audio/agentHit1.ogg": "https://files.ballistica.net/cache/ba1/de/11/170c245f33cbf3a221b0b9788414", - "assets/build/ba_data/audio/agentHit2.ogg": "https://files.ballistica.net/cache/ba1/34/98/5aea10ff741ea87d47cbcd04a78d", - "assets/build/ba_data/audio/alarm.ogg": "https://files.ballistica.net/cache/ba1/c0/ec/fcb7be8bb3e80ac7ec8964cde78f", - "assets/build/ba_data/audio/ali1.ogg": "https://files.ballistica.net/cache/ba1/7d/ea/a76253e501dfbc8f1cd9b738e657", - "assets/build/ba_data/audio/ali2.ogg": "https://files.ballistica.net/cache/ba1/32/27/b9aff80e1ca8d4e68aceb18fdbba", - "assets/build/ba_data/audio/ali3.ogg": "https://files.ballistica.net/cache/ba1/5d/9d/0814f83402b15341c2675cc48d90", - "assets/build/ba_data/audio/ali4.ogg": "https://files.ballistica.net/cache/ba1/da/25/fee30218b2573e980bc0d8a4bc40", - "assets/build/ba_data/audio/aliDeath.ogg": "https://files.ballistica.net/cache/ba1/da/42/f78e1ef54d7e51064ac60ea158b7", - "assets/build/ba_data/audio/aliFall.ogg": "https://files.ballistica.net/cache/ba1/02/83/1de429cdb220a5a8003f520323b2", - "assets/build/ba_data/audio/aliHit1.ogg": "https://files.ballistica.net/cache/ba1/51/1a/eadb6c1c05ac4d048829db626367", - "assets/build/ba_data/audio/aliHit2.ogg": "https://files.ballistica.net/cache/ba1/34/2f/8f03ec8341a17c0ed6feb9b19344", - "assets/build/ba_data/audio/alien1.ogg": "https://files.ballistica.net/cache/ba1/5d/3b/91e5163ce21e412495123accc966", - "assets/build/ba_data/audio/alien2.ogg": "https://files.ballistica.net/cache/ba1/46/68/f5770cfba1a7e8f1ffa7046e639e", - "assets/build/ba_data/audio/alien3.ogg": "https://files.ballistica.net/cache/ba1/9f/07/c045b60c44e510848e97f5a92ba0", - "assets/build/ba_data/audio/alien4.ogg": "https://files.ballistica.net/cache/ba1/da/62/99fbfb2a5c9e65125240d574d9db", - "assets/build/ba_data/audio/alienDeath.ogg": "https://files.ballistica.net/cache/ba1/f7/71/c2ea1d3559b1abc3cf0b4738dad5", - "assets/build/ba_data/audio/alienFall.ogg": "https://files.ballistica.net/cache/ba1/e1/f0/7a8968b32f88e10fa8507874d54b", - "assets/build/ba_data/audio/alienHit1.ogg": "https://files.ballistica.net/cache/ba1/09/98/1ad8d580c3c91b2b96adec08eedb", - "assets/build/ba_data/audio/alienHit2.ogg": "https://files.ballistica.net/cache/ba1/82/0f/421855fad0eeb855299fc5aa7379", - "assets/build/ba_data/audio/announceEight.ogg": "https://files.ballistica.net/cache/ba1/fc/d0/0b0a24cee18a849f705429e5bc9c", - "assets/build/ba_data/audio/announceFive.ogg": "https://files.ballistica.net/cache/ba1/05/84/cc26f8f8703700bfb18ab4c8df41", - "assets/build/ba_data/audio/announceFour.ogg": "https://files.ballistica.net/cache/ba1/70/76/c9208af50e5a59bf8e734fdba291", - "assets/build/ba_data/audio/announceNine.ogg": "https://files.ballistica.net/cache/ba1/f8/43/08c7e9866768af6375d542b65528", - "assets/build/ba_data/audio/announceOne.ogg": "https://files.ballistica.net/cache/ba1/a5/3f/cb9f89a7a98d43f94de026f668c7", - "assets/build/ba_data/audio/announceSeven.ogg": "https://files.ballistica.net/cache/ba1/6f/0c/705eba5b81daf21c8c9bb596eedd", - "assets/build/ba_data/audio/announceSix.ogg": "https://files.ballistica.net/cache/ba1/67/85/cab51a9fb0d70c47cc50461155f3", - "assets/build/ba_data/audio/announceTen.ogg": "https://files.ballistica.net/cache/ba1/b1/c2/a95b7babb3f393ce0e131be636dc", - "assets/build/ba_data/audio/announceThree.ogg": "https://files.ballistica.net/cache/ba1/2f/53/30da4f103a416f105a31cce72f0a", - "assets/build/ba_data/audio/announceTwo.ogg": "https://files.ballistica.net/cache/ba1/ef/b5/0635385ad9e7256fed6d1b7e9879", - "assets/build/ba_data/audio/assassin1.ogg": "https://files.ballistica.net/cache/ba1/55/b4/d9134e8a2cd2792f91f6a44fdeb6", - "assets/build/ba_data/audio/assassin2.ogg": "https://files.ballistica.net/cache/ba1/03/fb/8006c134b3929fb909924b890769", - "assets/build/ba_data/audio/assassin3.ogg": "https://files.ballistica.net/cache/ba1/6c/23/4ff9174edba7687c83bed5e57cea", - "assets/build/ba_data/audio/assassin4.ogg": "https://files.ballistica.net/cache/ba1/8a/1f/dc0910fe1bb12f17b2dfac433e01", - "assets/build/ba_data/audio/assassinDeath.ogg": "https://files.ballistica.net/cache/ba1/74/12/ba26245ff96f02db5017e067db59", - "assets/build/ba_data/audio/assassinFall.ogg": "https://files.ballistica.net/cache/ba1/86/c7/696182005646054bbc7523b793c3", - "assets/build/ba_data/audio/assassinHit1.ogg": "https://files.ballistica.net/cache/ba1/18/54/b4573c62cc3b0d975a7299a743b2", - "assets/build/ba_data/audio/assassinHit2.ogg": "https://files.ballistica.net/cache/ba1/73/ee/95251fd750360cfeda12204217d2", - "assets/build/ba_data/audio/bear1.ogg": "https://files.ballistica.net/cache/ba1/19/ea/9ab01c06ed6f2121020a3d1cb9d5", - "assets/build/ba_data/audio/bear2.ogg": "https://files.ballistica.net/cache/ba1/e1/85/42be0ec8005abcc9708835547030", - "assets/build/ba_data/audio/bear3.ogg": "https://files.ballistica.net/cache/ba1/ca/91/24c41299290858d2f46417da6904", - "assets/build/ba_data/audio/bear4.ogg": "https://files.ballistica.net/cache/ba1/84/5a/8e45901b72625e2f9c21100efcdf", - "assets/build/ba_data/audio/bearDeath.ogg": "https://files.ballistica.net/cache/ba1/75/23/5164c398d9025fd16275a701d1a7", - "assets/build/ba_data/audio/bearFall.ogg": "https://files.ballistica.net/cache/ba1/04/d3/ef47e8b37a869914a08ccabff2c7", - "assets/build/ba_data/audio/bearHit1.ogg": "https://files.ballistica.net/cache/ba1/ca/09/3082e6eeb6e8009161032f2ec197", - "assets/build/ba_data/audio/bearHit2.ogg": "https://files.ballistica.net/cache/ba1/ee/ce/6ffb306fe39f37fdd6685fa18e18", - "assets/build/ba_data/audio/bellHigh.ogg": "https://files.ballistica.net/cache/ba1/7f/77/8fe344ee29b20c83ed1d83288d01", - "assets/build/ba_data/audio/bellLow.ogg": "https://files.ballistica.net/cache/ba1/7b/e5/23ac10744040a3b3b5eb6a4c1d48", - "assets/build/ba_data/audio/bellMed.ogg": "https://files.ballistica.net/cache/ba1/f0/50/7d76b3ffaab29899c51f69ccd3f5", - "assets/build/ba_data/audio/bigImpact.ogg": "https://files.ballistica.net/cache/ba1/2b/15/a11ef20e8abdfde27f0e369b6d46", - "assets/build/ba_data/audio/bigImpact2.ogg": "https://files.ballistica.net/cache/ba1/99/8b/e920f8d3fea62194b63f08c3c8a7", - "assets/build/ba_data/audio/blank.ogg": "https://files.ballistica.net/cache/ba1/83/62/1a40e63b15db759b831cdb83a2eb", - "assets/build/ba_data/audio/blip.ogg": "https://files.ballistica.net/cache/ba1/49/66/877659338c9705c25bfa10d41c1c", - "assets/build/ba_data/audio/block.ogg": "https://files.ballistica.net/cache/ba1/a6/0b/cccee4f66078106f7cccf59de958", - "assets/build/ba_data/audio/bombDrop01.ogg": "https://files.ballistica.net/cache/ba1/82/45/0152b3754b4a756104d38c3c0f70", - "assets/build/ba_data/audio/bombDrop02.ogg": "https://files.ballistica.net/cache/ba1/40/4b/b5aeed0388de8c6edaa8863eef9e", - "assets/build/ba_data/audio/bombRoll01.ogg": "https://files.ballistica.net/cache/ba1/ce/ea/14570f4edf89a7f3dcf767739870", - "assets/build/ba_data/audio/bones1.ogg": "https://files.ballistica.net/cache/ba1/6c/96/64d95fe6abc17405cd4ebe17ec0b", - "assets/build/ba_data/audio/bones2.ogg": "https://files.ballistica.net/cache/ba1/87/7f/b1d3c5697cce6fa56e45b84905d8", - "assets/build/ba_data/audio/bones3.ogg": "https://files.ballistica.net/cache/ba1/9f/2e/567588b8aef702f0731cd774d820", - "assets/build/ba_data/audio/bonesDeath.ogg": "https://files.ballistica.net/cache/ba1/e1/19/b38a336b8b8330285a9319311460", - "assets/build/ba_data/audio/bonesFall.ogg": "https://files.ballistica.net/cache/ba1/fd/0b/4f28acf1244768b9ed6004c1b007", - "assets/build/ba_data/audio/boo.ogg": "https://files.ballistica.net/cache/ba1/11/6d/59ce86b99fab15ab6b7908c2339d", - "assets/build/ba_data/audio/boxDrop.ogg": "https://files.ballistica.net/cache/ba1/59/7a/64db77b50e9292c9ab19a949b1f6", - "assets/build/ba_data/audio/boxingBell.ogg": "https://files.ballistica.net/cache/ba1/f2/62/fe584681376afb9f8d85107f36a4", - "assets/build/ba_data/audio/bunny1.ogg": "https://files.ballistica.net/cache/ba1/09/56/95765c553553b1248cbffac8fbe5", - "assets/build/ba_data/audio/bunny2.ogg": "https://files.ballistica.net/cache/ba1/f3/fb/dc0e78b9b5223280247b82890880", - "assets/build/ba_data/audio/bunny3.ogg": "https://files.ballistica.net/cache/ba1/26/6d/7b58a6d8e92c62378f625260f5b8", - "assets/build/ba_data/audio/bunny4.ogg": "https://files.ballistica.net/cache/ba1/db/e1/ab9fdac20d4da0bddef6d78d6fa7", - "assets/build/ba_data/audio/bunnyDeath.ogg": "https://files.ballistica.net/cache/ba1/80/92/3d0b1b0ad08b2586d7b73b23a278", - "assets/build/ba_data/audio/bunnyFall.ogg": "https://files.ballistica.net/cache/ba1/f7/3f/ff9960bb8f6721c5564242227d51", - "assets/build/ba_data/audio/bunnyHit1.ogg": "https://files.ballistica.net/cache/ba1/a5/5e/596e389d107407b396b3cd928cee", - "assets/build/ba_data/audio/bunnyHit2.ogg": "https://files.ballistica.net/cache/ba1/7b/0b/f48d58f2c9dab841dac93a2a4d2c", - "assets/build/ba_data/audio/bunnyJump.ogg": "https://files.ballistica.net/cache/ba1/6a/d2/dc28a8b3f3685487ac5aeb163ae7", - "assets/build/ba_data/audio/cashRegister.ogg": "https://files.ballistica.net/cache/ba1/95/40/f92a787d199c72acf4c40224c549", - "assets/build/ba_data/audio/cashRegister2.ogg": "https://files.ballistica.net/cache/ba1/e2/27/067de536d637f846663a3ce5c7f5", - "assets/build/ba_data/audio/charSelectMusic.ogg": "https://files.ballistica.net/cache/ba1/da/67/b1a4329b5dee8069b07136311aca", - "assets/build/ba_data/audio/cheer.ogg": "https://files.ballistica.net/cache/ba1/aa/12/2e2d50be5059b4e06f006125b3c0", - "assets/build/ba_data/audio/click01.ogg": "https://files.ballistica.net/cache/ba1/4f/d7/6b90a09fe5c9357722e684ed31c7", - "assets/build/ba_data/audio/corkPop.ogg": "https://files.ballistica.net/cache/ba1/44/51/4565fac8d1df2e91511805b631a9", - "assets/build/ba_data/audio/cowboy1.ogg": "https://files.ballistica.net/cache/ba1/92/ee/9b2c5f1e4da3818ab47f3890e81d", - "assets/build/ba_data/audio/cowboy2.ogg": "https://files.ballistica.net/cache/ba1/0e/75/a9e3736f103d32a20c23c05746e3", - "assets/build/ba_data/audio/cowboy3.ogg": "https://files.ballistica.net/cache/ba1/59/8d/a0d19476559cf5a5ab816f059af6", - "assets/build/ba_data/audio/cowboy4.ogg": "https://files.ballistica.net/cache/ba1/6b/e5/7d38ab6d6b825411dfab086ad5fa", - "assets/build/ba_data/audio/cowboyDeath.ogg": "https://files.ballistica.net/cache/ba1/5a/41/0b58d290714a50d8ee5b66061a54", - "assets/build/ba_data/audio/cowboyFall.ogg": "https://files.ballistica.net/cache/ba1/37/f9/3f288870991e9f4ad672178e043e", - "assets/build/ba_data/audio/cowboyHit1.ogg": "https://files.ballistica.net/cache/ba1/03/4b/d0eb3026261ffa1c875394c6ce32", - "assets/build/ba_data/audio/cowboyHit2.ogg": "https://files.ballistica.net/cache/ba1/1f/ec/e9b50deeba812861599907daf236", - "assets/build/ba_data/audio/crowdChant.ogg": "https://files.ballistica.net/cache/ba1/e8/e1/2768189afc2e23c2a35cb3a5d57a", - "assets/build/ba_data/audio/cyborg1.ogg": "https://files.ballistica.net/cache/ba1/ad/5a/e5bb9cc841111a0cd6f924927325", - "assets/build/ba_data/audio/cyborg2.ogg": "https://files.ballistica.net/cache/ba1/5b/45/c7d0ace365917752c14cdb446740", - "assets/build/ba_data/audio/cyborg3.ogg": "https://files.ballistica.net/cache/ba1/7a/5a/945350b28f4bf2cdbe9922839ca4", - "assets/build/ba_data/audio/cyborg4.ogg": "https://files.ballistica.net/cache/ba1/59/7a/20c6633dc92352ae3d758897d8b6", - "assets/build/ba_data/audio/cyborgDeath.ogg": "https://files.ballistica.net/cache/ba1/76/0a/f97e3808f69a309cc7e1200ff022", - "assets/build/ba_data/audio/cyborgFall.ogg": "https://files.ballistica.net/cache/ba1/35/07/389489ec21b3d60a164ca4ee00d8", - "assets/build/ba_data/audio/cyborgHit1.ogg": "https://files.ballistica.net/cache/ba1/0b/08/2caf6743941273615246b613bf5d", - "assets/build/ba_data/audio/cyborgHit2.ogg": "https://files.ballistica.net/cache/ba1/8c/9f/0313164bc851503a59bd5c90d487", - "assets/build/ba_data/audio/cymbal.ogg": "https://files.ballistica.net/cache/ba1/df/16/4aa8600c113306202e8e98a7ddd2", - "assets/build/ba_data/audio/debrisFall.ogg": "https://files.ballistica.net/cache/ba1/ec/9e/db47851e08c9988b34162966d1bd", - "assets/build/ba_data/audio/deek.ogg": "https://files.ballistica.net/cache/ba1/79/fb/bd26ed0c7c38db6104b9c5f926c3", - "assets/build/ba_data/audio/deek2.ogg": "https://files.ballistica.net/cache/ba1/10/77/355824964ecc9d8e7154078889f2", - "assets/build/ba_data/audio/ding.ogg": "https://files.ballistica.net/cache/ba1/03/0e/2b6045dbf621ef6a89ce9f2959d8", - "assets/build/ba_data/audio/dingSmall.ogg": "https://files.ballistica.net/cache/ba1/6d/0f/5b2fa30315d9d375f95ee848f343", - "assets/build/ba_data/audio/dingSmallHigh.ogg": "https://files.ballistica.net/cache/ba1/69/fb/cb5791623d2178aca0cd70314777", - "assets/build/ba_data/audio/dripity.ogg": "https://files.ballistica.net/cache/ba1/77/42/03312537cc2de8096770f83df9d9", - "assets/build/ba_data/audio/drumRoll.ogg": "https://files.ballistica.net/cache/ba1/a8/af/e9e584510ae6af08dc35fb8c13b4", - "assets/build/ba_data/audio/error.ogg": "https://files.ballistica.net/cache/ba1/40/55/f1f8018b3d1a2d2de4ae0abdab6d", - "assets/build/ba_data/audio/explosion01.ogg": "https://files.ballistica.net/cache/ba1/09/e7/26b309e1f51fdf3189fa0749598f", - "assets/build/ba_data/audio/explosion02.ogg": "https://files.ballistica.net/cache/ba1/33/0b/5deb8006700448ad5b2a8f2f2ef7", - "assets/build/ba_data/audio/explosion03.ogg": "https://files.ballistica.net/cache/ba1/6f/94/f4bcd79eca30e6ce326a754f3fa3", - "assets/build/ba_data/audio/explosion04.ogg": "https://files.ballistica.net/cache/ba1/01/9a/a68fce2725ec3e0cd37ede6d3de2", - "assets/build/ba_data/audio/explosion05.ogg": "https://files.ballistica.net/cache/ba1/8e/84/6d58e528ce246f2490d82d2bc9ae", - "assets/build/ba_data/audio/fanfare.ogg": "https://files.ballistica.net/cache/ba1/e0/2e/cc83f86a6aef66dd950233ffea30", - "assets/build/ba_data/audio/flagCatcherMusic.ogg": "https://files.ballistica.net/cache/ba1/f7/59/73299fc66208b48c27023483a184", - "assets/build/ba_data/audio/flyingMusic.ogg": "https://files.ballistica.net/cache/ba1/aa/d4/6c044226b8dce5e6003aa6f6ddf5", - "assets/build/ba_data/audio/foghorn.ogg": "https://files.ballistica.net/cache/ba1/d0/f8/d6e0fc4c5f14471d16a635344030", - "assets/build/ba_data/audio/footImpact01.ogg": "https://files.ballistica.net/cache/ba1/7a/0a/1a0f4d7f49a7c8a6c5d2bc5d737e", - "assets/build/ba_data/audio/footImpact02.ogg": "https://files.ballistica.net/cache/ba1/ad/7b/e3760a959e9fd5ce376b4ab77e3a", - "assets/build/ba_data/audio/footImpact03.ogg": "https://files.ballistica.net/cache/ba1/e2/c3/f17c7bc0518c308f5d2973d31f43", - "assets/build/ba_data/audio/forwardMarchMusic.ogg": "https://files.ballistica.net/cache/ba1/0c/cf/0ae49454aeb767792ce6114b529c", - "assets/build/ba_data/audio/freeze.ogg": "https://files.ballistica.net/cache/ba1/67/7b/07b1d381e0e36567298dcd5000e6", - "assets/build/ba_data/audio/frosty01.ogg": "https://files.ballistica.net/cache/ba1/5d/69/1c0a9afb2d75e2c858121ca41971", - "assets/build/ba_data/audio/frosty02.ogg": "https://files.ballistica.net/cache/ba1/53/a4/b375204285ad630121a759265de4", - "assets/build/ba_data/audio/frosty03.ogg": "https://files.ballistica.net/cache/ba1/39/f6/a7987b4706b997b500c2899b2183", - "assets/build/ba_data/audio/frosty04.ogg": "https://files.ballistica.net/cache/ba1/47/52/91f81bcf5178746d58d49e62af97", - "assets/build/ba_data/audio/frosty05.ogg": "https://files.ballistica.net/cache/ba1/e2/90/9deb39db68d237fff0bb382877d9", - "assets/build/ba_data/audio/frostyDeath.ogg": "https://files.ballistica.net/cache/ba1/0c/5b/f4a054a41a15e6e2d01c11c428e4", - "assets/build/ba_data/audio/frostyFall.ogg": "https://files.ballistica.net/cache/ba1/1e/ea/38784c809a8860e0c6b0ca2fa13b", - "assets/build/ba_data/audio/frostyHit01.ogg": "https://files.ballistica.net/cache/ba1/3f/08/86e8693ee225340532ea8f3b537b", - "assets/build/ba_data/audio/frostyHit02.ogg": "https://files.ballistica.net/cache/ba1/6e/26/0f6fab8443cc788d34304c25c5b1", - "assets/build/ba_data/audio/frostyHit03.ogg": "https://files.ballistica.net/cache/ba1/0b/d7/e14be38ad2068749e040a43495a0", - "assets/build/ba_data/audio/fuse01.ogg": "https://files.ballistica.net/cache/ba1/76/71/dd93dadf35a79bb119fc8fd9fedd", - "assets/build/ba_data/audio/gladiator1.ogg": "https://files.ballistica.net/cache/ba1/55/76/01a6352e1211bdfbe6754d7992a7", - "assets/build/ba_data/audio/gladiator2.ogg": "https://files.ballistica.net/cache/ba1/8b/d8/1c149a375f8475f5ff47369ab31d", - "assets/build/ba_data/audio/gladiator3.ogg": "https://files.ballistica.net/cache/ba1/90/24/c1d70be9ad9dc38d849ac6bb74d8", - "assets/build/ba_data/audio/gladiator4.ogg": "https://files.ballistica.net/cache/ba1/d0/44/ab541c574ad2b96fafb2b682f4c3", - "assets/build/ba_data/audio/gladiatorDeath.ogg": "https://files.ballistica.net/cache/ba1/3b/d1/083972e99d2b291b8a33e53ded2f", - "assets/build/ba_data/audio/gladiatorFall.ogg": "https://files.ballistica.net/cache/ba1/98/0e/eb276183ca9bbd2049fbd2f25a45", - "assets/build/ba_data/audio/gladiatorHit1.ogg": "https://files.ballistica.net/cache/ba1/18/cb/95ad14e1e4f017f0fc398f59ca89", - "assets/build/ba_data/audio/gladiatorHit2.ogg": "https://files.ballistica.net/cache/ba1/66/20/76a47fd92de3595d5959118db50f", - "assets/build/ba_data/audio/gong.ogg": "https://files.ballistica.net/cache/ba1/c6/12/eeac834b7835a3d9f82a615b6016", - "assets/build/ba_data/audio/grandRompMusic.ogg": "https://files.ballistica.net/cache/ba1/8f/ac/3f46fe9804c5d5f525f196194fdc", - "assets/build/ba_data/audio/gravelSkid.ogg": "https://files.ballistica.net/cache/ba1/cf/3d/f5a6f9c90e3f5c75ad65fdf59c14", - "assets/build/ba_data/audio/gunCocking.ogg": "https://files.ballistica.net/cache/ba1/21/11/a21348daf7c4149b4e3f3652e9a2", - "assets/build/ba_data/audio/healthPowerup.ogg": "https://files.ballistica.net/cache/ba1/3f/99/5b46e3a85ece9ebc4e89d281052d", - "assets/build/ba_data/audio/hiss.ogg": "https://files.ballistica.net/cache/ba1/53/d2/1fc43214569fde5b9c607b504cfa", - "assets/build/ba_data/audio/impactHard.ogg": "https://files.ballistica.net/cache/ba1/1f/fe/4aa29cc4b8a63e48d586dee20aab", - "assets/build/ba_data/audio/impactHard2.ogg": "https://files.ballistica.net/cache/ba1/e3/59/afebacd04496ca341eb795c91974", - "assets/build/ba_data/audio/impactHard3.ogg": "https://files.ballistica.net/cache/ba1/f0/c5/af0c8f8fe6d57734aba644173b2e", - "assets/build/ba_data/audio/impactMedium.ogg": "https://files.ballistica.net/cache/ba1/94/43/c27da721c9bf7c8f4e5979da4abe", - "assets/build/ba_data/audio/impactMedium2.ogg": "https://files.ballistica.net/cache/ba1/10/2c/afac9ee2452e37bd6589ad8d1265", - "assets/build/ba_data/audio/jack01.ogg": "https://files.ballistica.net/cache/ba1/81/f3/94a3b316ba9c69b6f6cbeeceb377", - "assets/build/ba_data/audio/jack02.ogg": "https://files.ballistica.net/cache/ba1/b0/97/0d7985084e70d6ed3f4d9bc161b8", - "assets/build/ba_data/audio/jack03.ogg": "https://files.ballistica.net/cache/ba1/21/da/dbf533753afe8e33daf88e94c224", - "assets/build/ba_data/audio/jack04.ogg": "https://files.ballistica.net/cache/ba1/22/25/d814ad6fee1180fcaca1f097df52", - "assets/build/ba_data/audio/jack05.ogg": "https://files.ballistica.net/cache/ba1/e2/97/b76d969ba79df49050d9c9072f36", - "assets/build/ba_data/audio/jack06.ogg": "https://files.ballistica.net/cache/ba1/2b/a9/1473f78c94979b16f077069b2db3", - "assets/build/ba_data/audio/jackDeath01.ogg": "https://files.ballistica.net/cache/ba1/a8/a6/e8e8c0527659393f3c6c4cf8a9fc", - "assets/build/ba_data/audio/jackFall01.ogg": "https://files.ballistica.net/cache/ba1/7d/e1/b7d31169ac345688226e00115fde", - "assets/build/ba_data/audio/jackHit01.ogg": "https://files.ballistica.net/cache/ba1/51/f1/9ac9b0e647b695d7047568333a1c", - "assets/build/ba_data/audio/jackHit02.ogg": "https://files.ballistica.net/cache/ba1/db/aa/4422ad43564258f677dd2272ab00", - "assets/build/ba_data/audio/jackHit03.ogg": "https://files.ballistica.net/cache/ba1/32/55/72dd6c74e333d301e2db3c779891", - "assets/build/ba_data/audio/jackHit04.ogg": "https://files.ballistica.net/cache/ba1/4f/a5/a81916e8131c95c59cde2d0cd12c", - "assets/build/ba_data/audio/jackHit05.ogg": "https://files.ballistica.net/cache/ba1/a3/53/26845859fcf3653de646e53d675e", - "assets/build/ba_data/audio/jackHit06.ogg": "https://files.ballistica.net/cache/ba1/c0/4f/f0f56def3559c40aa3814993c734", - "assets/build/ba_data/audio/jackHit07.ogg": "https://files.ballistica.net/cache/ba1/cd/9b/976d67fff6167afc1292f0f66c10", - "assets/build/ba_data/audio/jumpsuit1.ogg": "https://files.ballistica.net/cache/ba1/f5/35/42cff1be18701cfe653465645b55", - "assets/build/ba_data/audio/jumpsuit2.ogg": "https://files.ballistica.net/cache/ba1/c6/e2/b587d3340eab9f7d14fb5877e35e", - "assets/build/ba_data/audio/jumpsuit3.ogg": "https://files.ballistica.net/cache/ba1/66/4d/91215ebd6192fb01e91c7c69165a", - "assets/build/ba_data/audio/jumpsuit4.ogg": "https://files.ballistica.net/cache/ba1/bf/d9/7858d10dba4a83b57a3783657fdd", - "assets/build/ba_data/audio/jumpsuitDeath.ogg": "https://files.ballistica.net/cache/ba1/3f/8b/2a002194ee696068687a0a92e27f", - "assets/build/ba_data/audio/jumpsuitFall.ogg": "https://files.ballistica.net/cache/ba1/c6/7f/e0bf39b48669b4fec191e1fd485c", - "assets/build/ba_data/audio/jumpsuitHit1.ogg": "https://files.ballistica.net/cache/ba1/2e/32/fa0c008a28329773f833718bd63e", - "assets/build/ba_data/audio/jumpsuitHit2.ogg": "https://files.ballistica.net/cache/ba1/71/f4/e8ea5afe94ad6cf7274a188f455c", - "assets/build/ba_data/audio/kronk1.ogg": "https://files.ballistica.net/cache/ba1/bf/fa/674317e36662679e13986a7d04bd", - "assets/build/ba_data/audio/kronk10.ogg": "https://files.ballistica.net/cache/ba1/ee/d4/370a2b43d3a97a348bb920b894c4", - "assets/build/ba_data/audio/kronk2.ogg": "https://files.ballistica.net/cache/ba1/dc/ab/aae4aeb4f45901c6a71ea4ef0f73", - "assets/build/ba_data/audio/kronk3.ogg": "https://files.ballistica.net/cache/ba1/7c/44/464fd7208338ffdd64f08cc3a3c1", - "assets/build/ba_data/audio/kronk4.ogg": "https://files.ballistica.net/cache/ba1/b4/da/ea0f4e9e42b37dbfcfb272fbef2a", - "assets/build/ba_data/audio/kronk5.ogg": "https://files.ballistica.net/cache/ba1/2d/01/9e1683943b2710e39aa1d79c8b67", - "assets/build/ba_data/audio/kronk6.ogg": "https://files.ballistica.net/cache/ba1/7c/a2/7d7d75608a1bab096f80eb4fa421", - "assets/build/ba_data/audio/kronk7.ogg": "https://files.ballistica.net/cache/ba1/60/db/c2457706cb3571ddf17aa7744440", - "assets/build/ba_data/audio/kronk8.ogg": "https://files.ballistica.net/cache/ba1/a5/f0/10b095c164c79f88c232b5103f7f", - "assets/build/ba_data/audio/kronk9.ogg": "https://files.ballistica.net/cache/ba1/6d/8d/a4ca274adcb13e652b991cd07e8d", - "assets/build/ba_data/audio/kronkDeath.ogg": "https://files.ballistica.net/cache/ba1/ce/d3/cdc3343b51e2979980b52da3a816", - "assets/build/ba_data/audio/kronkFall.ogg": "https://files.ballistica.net/cache/ba1/87/1b/9928d990191436de1e8c21945a53", - "assets/build/ba_data/audio/laser.ogg": "https://files.ballistica.net/cache/ba1/2c/47/7d922a65a655a81553ef0533e33e", - "assets/build/ba_data/audio/laserReverse.ogg": "https://files.ballistica.net/cache/ba1/c3/7a/abe01b9cea503d97927679dfa315", - "assets/build/ba_data/audio/mel01.ogg": "https://files.ballistica.net/cache/ba1/f2/c0/ef79c31c5b5984f227bdb2445954", - "assets/build/ba_data/audio/mel02.ogg": "https://files.ballistica.net/cache/ba1/c2/22/66901e999f0cd648329aa1ef1a81", - "assets/build/ba_data/audio/mel03.ogg": "https://files.ballistica.net/cache/ba1/ce/ac/ef881592d77d19377e7300994d37", - "assets/build/ba_data/audio/mel04.ogg": "https://files.ballistica.net/cache/ba1/0f/c0/8aa388a1146d2441281bfe4e0165", - "assets/build/ba_data/audio/mel05.ogg": "https://files.ballistica.net/cache/ba1/b9/c7/ec8f514f5947d8826a9161d5d426", - "assets/build/ba_data/audio/mel06.ogg": "https://files.ballistica.net/cache/ba1/7b/30/de6e7d4b8aceff272c30dcc405be", - "assets/build/ba_data/audio/mel07.ogg": "https://files.ballistica.net/cache/ba1/6e/3b/c37b47ca4eef520bd8555a11fe17", - "assets/build/ba_data/audio/mel08.ogg": "https://files.ballistica.net/cache/ba1/f1/a4/3dd4b84fe88ced3aa0bdde8b5e56", - "assets/build/ba_data/audio/mel09.ogg": "https://files.ballistica.net/cache/ba1/9d/61/3f99f9b2a93ec1a669cfb65a2940", - "assets/build/ba_data/audio/mel10.ogg": "https://files.ballistica.net/cache/ba1/3f/73/8032dde4e0ab7f5b99c4a40f5b6d", - "assets/build/ba_data/audio/melDeath01.ogg": "https://files.ballistica.net/cache/ba1/be/87/57ce37b21c5db3341fb14a2b98aa", - "assets/build/ba_data/audio/melFall01.ogg": "https://files.ballistica.net/cache/ba1/8f/60/31d936c645357aefd4e670a70eb1", - "assets/build/ba_data/audio/menuMusic.ogg": "https://files.ballistica.net/cache/ba1/61/f3/0cba182dcdac5cf72bcc8b97774d", - "assets/build/ba_data/audio/metalHit.ogg": "https://files.ballistica.net/cache/ba1/00/77/6cb05c1786edb32713a6e1d64a7a", - "assets/build/ba_data/audio/metalSkid.ogg": "https://files.ballistica.net/cache/ba1/9f/4a/b64179bf83a9b6f0664d067598cc", - "assets/build/ba_data/audio/ninjaAttack1.ogg": "https://files.ballistica.net/cache/ba1/b7/0f/ed70785c73339502b54a7ae1748c", - "assets/build/ba_data/audio/ninjaAttack2.ogg": "https://files.ballistica.net/cache/ba1/8b/bd/aecee9bb2f2695d8196441de52bb", - "assets/build/ba_data/audio/ninjaAttack3.ogg": "https://files.ballistica.net/cache/ba1/af/0e/38018d3810cdbb25f8c52ebb0fca", - "assets/build/ba_data/audio/ninjaAttack4.ogg": "https://files.ballistica.net/cache/ba1/d2/07/d115b01c0b0321f7dadbb364b444", - "assets/build/ba_data/audio/ninjaAttack5.ogg": "https://files.ballistica.net/cache/ba1/e1/3a/28e67d23fdcae883fcf3272e8776", - "assets/build/ba_data/audio/ninjaAttack6.ogg": "https://files.ballistica.net/cache/ba1/e3/5a/9ea987f64038bb3758d79b1e2032", - "assets/build/ba_data/audio/ninjaAttack7.ogg": "https://files.ballistica.net/cache/ba1/c0/35/65c35bfadc7df312af40a0853e7f", - "assets/build/ba_data/audio/ninjaDeath1.ogg": "https://files.ballistica.net/cache/ba1/39/f5/9950db3409b0605e50555d4190d8", - "assets/build/ba_data/audio/ninjaFall1.ogg": "https://files.ballistica.net/cache/ba1/06/e4/b1abbd7be4819d6b6e71c8a2c284", - "assets/build/ba_data/audio/ninjaHit1.ogg": "https://files.ballistica.net/cache/ba1/db/6c/43cc9b3490a849c112f17e9bae23", - "assets/build/ba_data/audio/ninjaHit2.ogg": "https://files.ballistica.net/cache/ba1/c1/ba/21270f79da645897c3d956e9de13", - "assets/build/ba_data/audio/ninjaHit3.ogg": "https://files.ballistica.net/cache/ba1/a5/d5/6dc564fbd1ee87a9f9aa9d31c515", - "assets/build/ba_data/audio/ninjaHit4.ogg": "https://files.ballistica.net/cache/ba1/d0/9c/20286b49760b9cdfd53b9bbf8cb4", - "assets/build/ba_data/audio/ninjaHit5.ogg": "https://files.ballistica.net/cache/ba1/67/a0/dfdfd64c24baa053ab56098274b3", - "assets/build/ba_data/audio/ninjaHit6.ogg": "https://files.ballistica.net/cache/ba1/65/bd/c1e61d007100ff1f0d4de4d7e819", - "assets/build/ba_data/audio/ninjaHit7.ogg": "https://files.ballistica.net/cache/ba1/9c/6d/d084e3cf25bdff3165086c08323e", - "assets/build/ba_data/audio/ninjaHit8.ogg": "https://files.ballistica.net/cache/ba1/28/d1/2d787baf1006ece20e99b6ba5470", - "assets/build/ba_data/audio/oldLady1.ogg": "https://files.ballistica.net/cache/ba1/87/27/1d0527c7105e166d82eae9427fc8", - "assets/build/ba_data/audio/oldLady2.ogg": "https://files.ballistica.net/cache/ba1/20/c4/411b0a2eedc0247e4b1eba073fa8", - "assets/build/ba_data/audio/oldLady3.ogg": "https://files.ballistica.net/cache/ba1/f8/1d/e8eb32a88fd6e36a1c0f517924c8", - "assets/build/ba_data/audio/oldLady4.ogg": "https://files.ballistica.net/cache/ba1/36/19/afb63e6cb1fdfcbaad520c6da149", - "assets/build/ba_data/audio/oldLadyDeath.ogg": "https://files.ballistica.net/cache/ba1/f8/78/8e055e0b75a95cb2b2931176212a", - "assets/build/ba_data/audio/oldLadyFall.ogg": "https://files.ballistica.net/cache/ba1/fe/8a/081e6fa36a7d6748d64ee46ea1c7", - "assets/build/ba_data/audio/oldLadyHit1.ogg": "https://files.ballistica.net/cache/ba1/66/9a/c57c0e853aedfa6889e9421b99b2", - "assets/build/ba_data/audio/oldLadyHit2.ogg": "https://files.ballistica.net/cache/ba1/7c/e7/6470b1a196cdddcb5b12ab98c4bc", - "assets/build/ba_data/audio/ooh.ogg": "https://files.ballistica.net/cache/ba1/c3/a8/12d22a0f128ba42e2df8ddf0e99c", - "assets/build/ba_data/audio/operaSinger1.ogg": "https://files.ballistica.net/cache/ba1/dd/3b/62d496066a2dfa9ea7057a804803", - "assets/build/ba_data/audio/operaSinger2.ogg": "https://files.ballistica.net/cache/ba1/e2/2e/eab4183bc8f1e8e8bd69d2d71352", - "assets/build/ba_data/audio/operaSinger3.ogg": "https://files.ballistica.net/cache/ba1/24/66/ec7d07d97411e63fb14a8f9067ab", - "assets/build/ba_data/audio/operaSinger4.ogg": "https://files.ballistica.net/cache/ba1/24/e5/cff076a87c6fb3fa9c6d16452b07", - "assets/build/ba_data/audio/operaSingerDeath.ogg": "https://files.ballistica.net/cache/ba1/03/14/f5b2681820de74b05a9b56f1b7fc", - "assets/build/ba_data/audio/operaSingerFall.ogg": "https://files.ballistica.net/cache/ba1/a2/be/6a56a5790e231f9d3b226f70c2ad", - "assets/build/ba_data/audio/operaSingerHit1.ogg": "https://files.ballistica.net/cache/ba1/65/ed/afeda77cf37f1a4b63f6e08a352a", - "assets/build/ba_data/audio/operaSingerHit2.ogg": "https://files.ballistica.net/cache/ba1/44/8c/950622d12780e9f5fa250fd07a9f", - "assets/build/ba_data/audio/orchestraHit.ogg": "https://files.ballistica.net/cache/ba1/40/59/410ae08a6831f6c6a6d9083934bd", - "assets/build/ba_data/audio/orchestraHit2.ogg": "https://files.ballistica.net/cache/ba1/b0/a8/52fd0c973f013b21e4458fc890bf", - "assets/build/ba_data/audio/orchestraHit3.ogg": "https://files.ballistica.net/cache/ba1/4f/68/d274de3ff2673c74438e2432f5ca", - "assets/build/ba_data/audio/orchestraHit4.ogg": "https://files.ballistica.net/cache/ba1/42/d1/51e826d32f1c7dae45378bb7126f", - "assets/build/ba_data/audio/orchestraHitBig1.ogg": "https://files.ballistica.net/cache/ba1/ae/9e/3502ad7cf8d0fc2c146964d6513d", - "assets/build/ba_data/audio/orchestraHitBig2.ogg": "https://files.ballistica.net/cache/ba1/a9/21/1f783a910a4c568b562b4155f2de", - "assets/build/ba_data/audio/penguin1.ogg": "https://files.ballistica.net/cache/ba1/10/af/24efaf9261e7c510acfd59fd8e4d", - "assets/build/ba_data/audio/penguin2.ogg": "https://files.ballistica.net/cache/ba1/cb/a3/f46c21e251b2d2adc05148e846e6", - "assets/build/ba_data/audio/penguin3.ogg": "https://files.ballistica.net/cache/ba1/ef/40/a9e5c6b4e150d2c39ba3c41bccd7", - "assets/build/ba_data/audio/penguin4.ogg": "https://files.ballistica.net/cache/ba1/8a/6f/e2be7c0221e22876364e7cab3875", - "assets/build/ba_data/audio/penguinDeath.ogg": "https://files.ballistica.net/cache/ba1/b4/56/e2d947ab708f3b2a32e41bf24815", - "assets/build/ba_data/audio/penguinFall.ogg": "https://files.ballistica.net/cache/ba1/a3/97/8cebf0c49330557bf29389627ec7", - "assets/build/ba_data/audio/penguinHit1.ogg": "https://files.ballistica.net/cache/ba1/ac/41/b864dbfaac8bbc735e46e0b21df6", - "assets/build/ba_data/audio/penguinHit2.ogg": "https://files.ballistica.net/cache/ba1/05/68/a0ebf27936094e4a91bbc11c9d59", - "assets/build/ba_data/audio/pixie1.ogg": "https://files.ballistica.net/cache/ba1/cd/28/7e6e44bc1964f67ac8a459b37d85", - "assets/build/ba_data/audio/pixie2.ogg": "https://files.ballistica.net/cache/ba1/68/57/1f785b0a94c66002df3d43f0c5e8", - "assets/build/ba_data/audio/pixie3.ogg": "https://files.ballistica.net/cache/ba1/9b/39/2e2a3d6998b35639cacea59c5873", - "assets/build/ba_data/audio/pixie4.ogg": "https://files.ballistica.net/cache/ba1/4f/10/a09b0c82531ece86a6833250cc07", - "assets/build/ba_data/audio/pixieDeath.ogg": "https://files.ballistica.net/cache/ba1/a4/81/f110e658f0193d55ba69d9f04dfd", - "assets/build/ba_data/audio/pixieFall.ogg": "https://files.ballistica.net/cache/ba1/7f/67/79d42e80033ffa528babd4bffcd7", - "assets/build/ba_data/audio/pixieHit1.ogg": "https://files.ballistica.net/cache/ba1/44/6f/c1af25af6fcd8e3d7f199867beb8", - "assets/build/ba_data/audio/pixieHit2.ogg": "https://files.ballistica.net/cache/ba1/c4/a7/a25f2e007ba55bc06dc030f1b915", - "assets/build/ba_data/audio/playerDeath.ogg": "https://files.ballistica.net/cache/ba1/f3/69/5e3cdd084af31e9c650a7929a252", - "assets/build/ba_data/audio/playerLeft.ogg": "https://files.ballistica.net/cache/ba1/ed/a6/6f12dc461a79f78dcaca203a51b2", - "assets/build/ba_data/audio/pop01.ogg": "https://files.ballistica.net/cache/ba1/47/62/cfbab3f9a6fabc7c2d366669c833", - "assets/build/ba_data/audio/powerdown01.ogg": "https://files.ballistica.net/cache/ba1/0c/15/76b3a9ec0a05dc9daa99bf699df3", - "assets/build/ba_data/audio/powerup01.ogg": "https://files.ballistica.net/cache/ba1/b6/a1/4777176235da6718c58e51e68af3", - "assets/build/ba_data/audio/punch01.ogg": "https://files.ballistica.net/cache/ba1/1f/f1/300fcb77b3cbb8f9d6c0c6413554", - "assets/build/ba_data/audio/punchStrong01.ogg": "https://files.ballistica.net/cache/ba1/dd/f6/4840483e912106f06f0ecb40a038", - "assets/build/ba_data/audio/punchStrong02.ogg": "https://files.ballistica.net/cache/ba1/40/a1/dafb2d75c81771e5c37feaa6cc63", - "assets/build/ba_data/audio/punchSwish.ogg": "https://files.ballistica.net/cache/ba1/da/7c/4b693a873f9838895a25b7cfef7c", - "assets/build/ba_data/audio/punchWeak01.ogg": "https://files.ballistica.net/cache/ba1/99/9a/8aa5073d39f27ec51112a48c3ef5", - "assets/build/ba_data/audio/raceBeep1.ogg": "https://files.ballistica.net/cache/ba1/3b/a0/d9919d09bfc8c4d8747e3b49b1fb", - "assets/build/ba_data/audio/raceBeep2.ogg": "https://files.ballistica.net/cache/ba1/e8/13/d338ad14de7f8c907b7e40b9b7ff", - "assets/build/ba_data/audio/refWhistle.ogg": "https://files.ballistica.net/cache/ba1/84/ce/150aa18d067feb1606d735b6a2db", - "assets/build/ba_data/audio/robot1.ogg": "https://files.ballistica.net/cache/ba1/1c/d7/1728041327e820a2b32114b93dc5", - "assets/build/ba_data/audio/robot2.ogg": "https://files.ballistica.net/cache/ba1/99/f1/cce9f935c2b334031af54877f3e9", - "assets/build/ba_data/audio/robot3.ogg": "https://files.ballistica.net/cache/ba1/ef/79/6de0588796db1f9feadbebc1ebca", - "assets/build/ba_data/audio/robot4.ogg": "https://files.ballistica.net/cache/ba1/c0/f5/7b1112efa507ab0cfaa8b4e46baa", - "assets/build/ba_data/audio/robotDeath.ogg": "https://files.ballistica.net/cache/ba1/ac/de/f87dbe8ef37b6d4c79604dada7ee", - "assets/build/ba_data/audio/robotFall.ogg": "https://files.ballistica.net/cache/ba1/69/62/0d63f1eb193862905dc55143d612", - "assets/build/ba_data/audio/robotHit1.ogg": "https://files.ballistica.net/cache/ba1/67/94/2eb9f45b4831a702de2f185ee82e", - "assets/build/ba_data/audio/robotHit2.ogg": "https://files.ballistica.net/cache/ba1/27/5a/1157a91c3136ed6c29b50344961a", - "assets/build/ba_data/audio/runAwayMusic.ogg": "https://files.ballistica.net/cache/ba1/ff/9c/8ed2c70a3a932e37e599fa8ceda5", - "assets/build/ba_data/audio/santa01.ogg": "https://files.ballistica.net/cache/ba1/c3/81/43a7887f6c91b0eb5c2323a21a99", - "assets/build/ba_data/audio/santa02.ogg": "https://files.ballistica.net/cache/ba1/c0/27/cf893af8c5ee41c08c8df8958f37", - "assets/build/ba_data/audio/santa03.ogg": "https://files.ballistica.net/cache/ba1/15/b6/f5eef5f99d40806f375c02f428b3", - "assets/build/ba_data/audio/santa04.ogg": "https://files.ballistica.net/cache/ba1/cd/07/a31c9227b0ee86ccd849ccf9aa14", - "assets/build/ba_data/audio/santa05.ogg": "https://files.ballistica.net/cache/ba1/b3/f1/9d47469e34816c86174adeb42061", - "assets/build/ba_data/audio/santaDeath.ogg": "https://files.ballistica.net/cache/ba1/56/71/5eaf852db9c748b7229fd9e5d76e", - "assets/build/ba_data/audio/santaFall.ogg": "https://files.ballistica.net/cache/ba1/b6/86/9513ecdeeda6ce7ea9f51db997b7", - "assets/build/ba_data/audio/santaHit01.ogg": "https://files.ballistica.net/cache/ba1/9b/0f/183c7a2be8ff4853f1fe38dbaaf6", - "assets/build/ba_data/audio/santaHit02.ogg": "https://files.ballistica.net/cache/ba1/93/c5/1b3d72d681ac3eff776b2bf4c501", - "assets/build/ba_data/audio/santaHit03.ogg": "https://files.ballistica.net/cache/ba1/7d/2e/31294f776ffb40159d6d2e689cb9", - "assets/build/ba_data/audio/santaHit04.ogg": "https://files.ballistica.net/cache/ba1/e2/f6/a73bcaae16c40f7a22167c70bf73", - "assets/build/ba_data/audio/scamper01.ogg": "https://files.ballistica.net/cache/ba1/fd/42/78303af4865484502d148b0fbcfc", - "assets/build/ba_data/audio/scaryMusic.ogg": "https://files.ballistica.net/cache/ba1/14/08/3b386310707e76cf4c1fb557fd10", - "assets/build/ba_data/audio/score.ogg": "https://files.ballistica.net/cache/ba1/eb/85/506d2f0b18806df56404989430c8", - "assets/build/ba_data/audio/scoreHit01.ogg": "https://files.ballistica.net/cache/ba1/ca/01/28be47f34963c556815defd3e5db", - "assets/build/ba_data/audio/scoreHit02.ogg": "https://files.ballistica.net/cache/ba1/dd/8d/78f9a4459a1355e0ba0c5e6f40b1", - "assets/build/ba_data/audio/scoreIncrease.ogg": "https://files.ballistica.net/cache/ba1/39/df/8bcd5a71b0e52b6ed6a6e0fe77cf", - "assets/build/ba_data/audio/scoresEpicMusic.ogg": "https://files.ballistica.net/cache/ba1/81/12/d7b283c2f0b75b5d0bc4696a7fb6", - "assets/build/ba_data/audio/shatter.ogg": "https://files.ballistica.net/cache/ba1/ad/da/8ed18645f7d441ed220a99ed4cab", - "assets/build/ba_data/audio/shieldDown.ogg": "https://files.ballistica.net/cache/ba1/ff/5b/35b8e8c56a30b18bb85acdf76868", - "assets/build/ba_data/audio/shieldHit.ogg": "https://files.ballistica.net/cache/ba1/23/7c/2aea22b8435e2b73434520f2e82f", - "assets/build/ba_data/audio/shieldUp.ogg": "https://files.ballistica.net/cache/ba1/88/4c/e8c80155990a426bc4fe8fb21aa4", - "assets/build/ba_data/audio/skid01.ogg": "https://files.ballistica.net/cache/ba1/b5/0a/9cdfb3bb4304d2e3a51de04124d7", - "assets/build/ba_data/audio/slowEpicMusic.ogg": "https://files.ballistica.net/cache/ba1/96/69/b373c25393d9ca598e1dcbc8d163", - "assets/build/ba_data/audio/sparkle01.ogg": "https://files.ballistica.net/cache/ba1/ae/cd/cc5223d8143f3f0a3e1df0e4445f", - "assets/build/ba_data/audio/sparkle02.ogg": "https://files.ballistica.net/cache/ba1/bd/36/d5c268a1baee5942359fd6bd0728", - "assets/build/ba_data/audio/sparkle03.ogg": "https://files.ballistica.net/cache/ba1/94/e5/1b6b0c32b3072cd01f2f4777bd4f", - "assets/build/ba_data/audio/spawn.ogg": "https://files.ballistica.net/cache/ba1/16/04/31ca7050c98b231be2359e76e5c7", - "assets/build/ba_data/audio/spazAttack01.ogg": "https://files.ballistica.net/cache/ba1/89/85/2e0ca4b50dfe7297144be77c75ff", - "assets/build/ba_data/audio/spazAttack02.ogg": "https://files.ballistica.net/cache/ba1/45/c3/54520484f3cda316855581fd7e13", - "assets/build/ba_data/audio/spazAttack03.ogg": "https://files.ballistica.net/cache/ba1/d6/6f/325fe4bf87b2b3e360d80475604a", - "assets/build/ba_data/audio/spazAttack04.ogg": "https://files.ballistica.net/cache/ba1/e1/7f/dd10f87eab42a30c6acebc91fd5e", - "assets/build/ba_data/audio/spazDeath01.ogg": "https://files.ballistica.net/cache/ba1/c5/47/c96908f4cc1370a1afa2094a5f89", - "assets/build/ba_data/audio/spazEff.ogg": "https://files.ballistica.net/cache/ba1/8b/ad/c3ca1060f6432feaaa80d140ba1d", - "assets/build/ba_data/audio/spazFall01.ogg": "https://files.ballistica.net/cache/ba1/3e/f9/22da3d48f5bc597346998dcde75c", - "assets/build/ba_data/audio/spazImpact01.ogg": "https://files.ballistica.net/cache/ba1/ad/78/4322f9a002878bfcec94d4d421ad", - "assets/build/ba_data/audio/spazImpact02.ogg": "https://files.ballistica.net/cache/ba1/d8/fd/a2cca812b6ecfd4f661caeb0bbaa", - "assets/build/ba_data/audio/spazImpact03.ogg": "https://files.ballistica.net/cache/ba1/1e/5c/7a27ed5d73654dca8d5f43a36623", - "assets/build/ba_data/audio/spazImpact04.ogg": "https://files.ballistica.net/cache/ba1/7e/ca/a29315cdb161a8308f18731c55e4", - "assets/build/ba_data/audio/spazJump01.ogg": "https://files.ballistica.net/cache/ba1/76/e1/a50a0f979f4d24ca4d1dcf6e2ebc", - "assets/build/ba_data/audio/spazJump02.ogg": "https://files.ballistica.net/cache/ba1/0c/af/54d124107c14c7d735d422693b3d", - "assets/build/ba_data/audio/spazJump03.ogg": "https://files.ballistica.net/cache/ba1/5b/0c/c6a115910caf1667d9a5115c289c", - "assets/build/ba_data/audio/spazJump04.ogg": "https://files.ballistica.net/cache/ba1/3c/96/47c00e290f1295244669430d2cd6", - "assets/build/ba_data/audio/spazOw.ogg": "https://files.ballistica.net/cache/ba1/5b/87/061de855314245a9c3796974c5e1", - "assets/build/ba_data/audio/spazPickup01.ogg": "https://files.ballistica.net/cache/ba1/8f/6f/14e8ff5f4aa89d2411775a8d7dee", - "assets/build/ba_data/audio/spazScream01.ogg": "https://files.ballistica.net/cache/ba1/25/12/7034a215aa6e0d3c004e832dff78", - "assets/build/ba_data/audio/splatter.ogg": "https://files.ballistica.net/cache/ba1/25/05/d142ce96d709d7878dd58fa45eee", - "assets/build/ba_data/audio/sportsMusic.ogg": "https://files.ballistica.net/cache/ba1/77/39/cc2530de33a1e3d05a56b697df06", - "assets/build/ba_data/audio/stickyImpact.ogg": "https://files.ballistica.net/cache/ba1/14/ed/ed40b86591ca759b1eb8d97dae36", - "assets/build/ba_data/audio/superPunch.ogg": "https://files.ballistica.net/cache/ba1/52/4a/abca1e94230a2f5185936bedd606", - "assets/build/ba_data/audio/superhero1.ogg": "https://files.ballistica.net/cache/ba1/1c/7a/73f51c7d279341d02a4af81aa8a8", - "assets/build/ba_data/audio/superhero2.ogg": "https://files.ballistica.net/cache/ba1/eb/0e/df2479a8848813303c2675c0f51e", - "assets/build/ba_data/audio/superhero3.ogg": "https://files.ballistica.net/cache/ba1/11/4d/5f62f421509d101500ff72f5f294", - "assets/build/ba_data/audio/superhero4.ogg": "https://files.ballistica.net/cache/ba1/95/79/045053213f7ff4d7b159b83bc048", - "assets/build/ba_data/audio/superheroDeath.ogg": "https://files.ballistica.net/cache/ba1/35/16/592718bbc77e4ea80d649b3e886e", - "assets/build/ba_data/audio/superheroFall.ogg": "https://files.ballistica.net/cache/ba1/e3/65/a482f2a9870ab929a2ea8538acf1", - "assets/build/ba_data/audio/superheroHit1.ogg": "https://files.ballistica.net/cache/ba1/c4/b6/59b23fad481f4bb07ab9dafefd48", - "assets/build/ba_data/audio/superheroHit2.ogg": "https://files.ballistica.net/cache/ba1/f9/d6/16b43f9a7daf1bdc024aa9e76b41", - "assets/build/ba_data/audio/survivalMusic.ogg": "https://files.ballistica.net/cache/ba1/28/c4/be8e429011f6c182bb480a94e4fd", - "assets/build/ba_data/audio/swip.ogg": "https://files.ballistica.net/cache/ba1/b0/3d/bd9749c63374f73cd5837dd5218b", - "assets/build/ba_data/audio/swip2.ogg": "https://files.ballistica.net/cache/ba1/d3/87/affc6bef53b71d9c545a50d74fa9", - "assets/build/ba_data/audio/swish.ogg": "https://files.ballistica.net/cache/ba1/67/59/b1174d7ccfcaeacb953eadbc95b2", - "assets/build/ba_data/audio/swish2.ogg": "https://files.ballistica.net/cache/ba1/bc/9b/51d85b565e3df6e415454e9d9adc", - "assets/build/ba_data/audio/swish3.ogg": "https://files.ballistica.net/cache/ba1/4a/04/569ac265e4cfb47076227c107c25", - "assets/build/ba_data/audio/tap.ogg": "https://files.ballistica.net/cache/ba1/79/b1/81bbbb83f678249a548255bbda6e", - "assets/build/ba_data/audio/technoHit01.ogg": "https://files.ballistica.net/cache/ba1/04/eb/7aede78bf7ceaa8f6a89b02c8626", - "assets/build/ba_data/audio/tick.ogg": "https://files.ballistica.net/cache/ba1/88/45/0e9e552e93daad33984593dbf3f8", - "assets/build/ba_data/audio/ticking.ogg": "https://files.ballistica.net/cache/ba1/35/1f/d97274b378dd75c4d22af5fc1ef6", - "assets/build/ba_data/audio/tickingCrazy.ogg": "https://files.ballistica.net/cache/ba1/1c/f8/f24a05138cd79238de8e495d4f69", - "assets/build/ba_data/audio/toTheDeathMusic.ogg": "https://files.ballistica.net/cache/ba1/c3/4f/212e0079cba9ea182ec782aacabd", - "assets/build/ba_data/audio/trashRummage.ogg": "https://files.ballistica.net/cache/ba1/05/ec/b8629cfe95e107f90e5068ddc186", - "assets/build/ba_data/audio/victoryMusic.ogg": "https://files.ballistica.net/cache/ba1/ce/64/4fc64f3c835ecc0f3cd5dcb4ae9c", - "assets/build/ba_data/audio/warnBeep.ogg": "https://files.ballistica.net/cache/ba1/fa/0a/96879d9f7ee740f26969d0a14d84", - "assets/build/ba_data/audio/warnBeeps.ogg": "https://files.ballistica.net/cache/ba1/36/98/519ff651b3f5e8cf97f879e08dfc", - "assets/build/ba_data/audio/warrior1.ogg": "https://files.ballistica.net/cache/ba1/c3/a5/73b1ce8f1cfca46b3429ebccfa78", - "assets/build/ba_data/audio/warrior2.ogg": "https://files.ballistica.net/cache/ba1/ed/5f/336e7661db624b6093f724d281c9", - "assets/build/ba_data/audio/warrior3.ogg": "https://files.ballistica.net/cache/ba1/74/b3/58d475a1d2b226c769938283d529", - "assets/build/ba_data/audio/warrior4.ogg": "https://files.ballistica.net/cache/ba1/03/99/d18527a43ddc6a8549e6df0d2e50", - "assets/build/ba_data/audio/warriorDeath.ogg": "https://files.ballistica.net/cache/ba1/7e/4f/0d8c07a9438f8e6d61070c7528d6", - "assets/build/ba_data/audio/warriorFall.ogg": "https://files.ballistica.net/cache/ba1/89/5d/0fa65788af27d44f1bbc8a00d0bc", - "assets/build/ba_data/audio/warriorHit1.ogg": "https://files.ballistica.net/cache/ba1/91/bb/cba5baa65c8cfbe6fd3c20db09b8", - "assets/build/ba_data/audio/warriorHit2.ogg": "https://files.ballistica.net/cache/ba1/9c/27/3475bff6c25103362223b0ae0fb2", - "assets/build/ba_data/audio/whenJohnnyComesMarchingHomeMusic.ogg": "https://files.ballistica.net/cache/ba1/eb/f5/d9c9166b5600d9124f507e740850", - "assets/build/ba_data/audio/witch1.ogg": "https://files.ballistica.net/cache/ba1/85/8c/bb2725208bd330748c56b6bb9360", - "assets/build/ba_data/audio/witch2.ogg": "https://files.ballistica.net/cache/ba1/3c/cf/050e6bbe26edb61ec24ce744ba3e", - "assets/build/ba_data/audio/witch3.ogg": "https://files.ballistica.net/cache/ba1/c8/13/56534f0ce4426da09d3cf2a9ae02", - "assets/build/ba_data/audio/witch4.ogg": "https://files.ballistica.net/cache/ba1/cc/15/326316bab0c09a6851fa40a35652", - "assets/build/ba_data/audio/witchDeath.ogg": "https://files.ballistica.net/cache/ba1/41/8f/035722dcfe46403af4b91df10a59", - "assets/build/ba_data/audio/witchFall.ogg": "https://files.ballistica.net/cache/ba1/c1/51/0ad26beb9d366ae3f12474f2fdaa", - "assets/build/ba_data/audio/witchHit1.ogg": "https://files.ballistica.net/cache/ba1/a3/55/b77829242b74fe0f9df45cda31c5", - "assets/build/ba_data/audio/witchHit2.ogg": "https://files.ballistica.net/cache/ba1/71/08/1bf912229995268c9812e7a12a45", - "assets/build/ba_data/audio/wizard1.ogg": "https://files.ballistica.net/cache/ba1/9c/e7/41dd895a40c8a24aea6f6226957b", - "assets/build/ba_data/audio/wizard2.ogg": "https://files.ballistica.net/cache/ba1/45/e1/dbfe4199aaf66ddecc4b6a11d452", - "assets/build/ba_data/audio/wizard3.ogg": "https://files.ballistica.net/cache/ba1/37/f8/6bc5e11bbfa0c93cbf3a5ab1a522", - "assets/build/ba_data/audio/wizard4.ogg": "https://files.ballistica.net/cache/ba1/aa/b4/e2e79796e7c290b0efa8a90358e5", - "assets/build/ba_data/audio/wizardDeath.ogg": "https://files.ballistica.net/cache/ba1/f8/02/664691cffd8840e4f640286bb460", - "assets/build/ba_data/audio/wizardFall.ogg": "https://files.ballistica.net/cache/ba1/28/9e/52908a92061ad8bb8109d1691500", - "assets/build/ba_data/audio/wizardHit1.ogg": "https://files.ballistica.net/cache/ba1/07/a7/b1c9ccc23bdd135f08859990f7bc", - "assets/build/ba_data/audio/wizardHit2.ogg": "https://files.ballistica.net/cache/ba1/de/26/2e11aa9bcce552afde06f728782e", - "assets/build/ba_data/audio/woodDebrisFall.ogg": "https://files.ballistica.net/cache/ba1/4c/35/38c513942bafb10740a425a82061", - "assets/build/ba_data/audio/wrestler1.ogg": "https://files.ballistica.net/cache/ba1/e6/5c/7eddfcb397f1e46a889aa2ae6bf6", - "assets/build/ba_data/audio/wrestler2.ogg": "https://files.ballistica.net/cache/ba1/0c/b5/6044554526168c6948ebb673a4c7", - "assets/build/ba_data/audio/wrestler3.ogg": "https://files.ballistica.net/cache/ba1/ec/42/9b5ef49f73df83c2613d343ff27b", - "assets/build/ba_data/audio/wrestler4.ogg": "https://files.ballistica.net/cache/ba1/b9/28/72cc79a9312838c96f732b16d7e2", - "assets/build/ba_data/audio/wrestlerDeath.ogg": "https://files.ballistica.net/cache/ba1/e0/fe/89031f95dc70949b693c21413d95", - "assets/build/ba_data/audio/wrestlerFall.ogg": "https://files.ballistica.net/cache/ba1/7e/df/8867657077439af75ed0629e8fe5", - "assets/build/ba_data/audio/wrestlerHit1.ogg": "https://files.ballistica.net/cache/ba1/88/b3/3b5c3ab59f150fecdd556a67691c", - "assets/build/ba_data/audio/wrestlerHit2.ogg": "https://files.ballistica.net/cache/ba1/81/69/62a52ba66e2191219a7af561ff0f", - "assets/build/ba_data/audio/zoeAttack01.ogg": "https://files.ballistica.net/cache/ba1/3b/4e/bd6936ed2cd7dbe35850b13d7fec", - "assets/build/ba_data/audio/zoeAttack02.ogg": "https://files.ballistica.net/cache/ba1/d4/eb/0ccab1530ee7224ca692737ea838", - "assets/build/ba_data/audio/zoeAttack03.ogg": "https://files.ballistica.net/cache/ba1/34/b5/6a39f035ba348be43ebb91ff1181", - "assets/build/ba_data/audio/zoeAttack04.ogg": "https://files.ballistica.net/cache/ba1/83/71/f466dc083f5cd5953333a48f1b90", - "assets/build/ba_data/audio/zoeDeath01.ogg": "https://files.ballistica.net/cache/ba1/bc/bc/37581c5c5b6d5e0a32e691ab17d6", - "assets/build/ba_data/audio/zoeEff.ogg": "https://files.ballistica.net/cache/ba1/83/9e/da2b5e8916cff27a74d360954d9b", - "assets/build/ba_data/audio/zoeFall01.ogg": "https://files.ballistica.net/cache/ba1/66/d1/75048af216397941731148403316", - "assets/build/ba_data/audio/zoeImpact01.ogg": "https://files.ballistica.net/cache/ba1/ff/64/5061b3f3057df36bd44006731e4a", - "assets/build/ba_data/audio/zoeImpact02.ogg": "https://files.ballistica.net/cache/ba1/f4/1f/50b32e93653f2484fb58b4dec5aa", - "assets/build/ba_data/audio/zoeImpact03.ogg": "https://files.ballistica.net/cache/ba1/bc/92/9373da51e51e9d4126d17bd83ecf", - "assets/build/ba_data/audio/zoeImpact04.ogg": "https://files.ballistica.net/cache/ba1/99/49/a05360000bf074e458998fb28d7e", - "assets/build/ba_data/audio/zoeJump01.ogg": "https://files.ballistica.net/cache/ba1/6d/5e/94eaba8007850838896130695b73", - "assets/build/ba_data/audio/zoeJump02.ogg": "https://files.ballistica.net/cache/ba1/e6/af/3c5985e93b0eb0a6e54f1c77cb98", - "assets/build/ba_data/audio/zoeJump03.ogg": "https://files.ballistica.net/cache/ba1/7f/ae/40dea6e87e0b1f5662f5287837ed", - "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/75/1d/868bb04cf691736035c917d02762", - "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/44/2a/8535b446284235cb503947ece074", - "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/f5/d3/8e941851c4310465646c4167afc1", + "assets/build/ba_data/audio/achievement.ogg": "https://files.ballistica.net/cache/ba1/50/a9/56b45fb5f83985f5655ec91ebea2", + "assets/build/ba_data/audio/actionHero1.ogg": "https://files.ballistica.net/cache/ba1/30/d0/a5c058b3107cf7b76e824400d1db", + "assets/build/ba_data/audio/actionHero2.ogg": "https://files.ballistica.net/cache/ba1/33/15/4793e06c883c94f25df229245efe", + "assets/build/ba_data/audio/actionHero3.ogg": "https://files.ballistica.net/cache/ba1/e0/8a/c696b1e07c4bc332ba2ce7af1848", + "assets/build/ba_data/audio/actionHero4.ogg": "https://files.ballistica.net/cache/ba1/88/61/a038557dc03ba848fc05b884f9f3", + "assets/build/ba_data/audio/actionHeroDeath.ogg": "https://files.ballistica.net/cache/ba1/0c/a0/6145e8e18d604b9e4b24b50e322e", + "assets/build/ba_data/audio/actionHeroFall.ogg": "https://files.ballistica.net/cache/ba1/1c/b5/b784b153b5dd1a711017a2072023", + "assets/build/ba_data/audio/actionHeroHit1.ogg": "https://files.ballistica.net/cache/ba1/82/c2/8e67215391017a09bbf244a1b63e", + "assets/build/ba_data/audio/actionHeroHit2.ogg": "https://files.ballistica.net/cache/ba1/0b/7a/2189f17d706d5b82c66e521a9152", + "assets/build/ba_data/audio/activateBeep.ogg": "https://files.ballistica.net/cache/ba1/23/a2/a7f68eb6451f3a046bd5478c8b03", + "assets/build/ba_data/audio/agent1.ogg": "https://files.ballistica.net/cache/ba1/6c/35/3594cb58960d13f750282497a209", + "assets/build/ba_data/audio/agent2.ogg": "https://files.ballistica.net/cache/ba1/05/34/029e656a7f92043d6632e7e73e6b", + "assets/build/ba_data/audio/agent3.ogg": "https://files.ballistica.net/cache/ba1/0e/2b/7ee23a8239dc7b9cd365348bbeec", + "assets/build/ba_data/audio/agent4.ogg": "https://files.ballistica.net/cache/ba1/33/03/b0bb642e2f89d17ff44c9d4a60de", + "assets/build/ba_data/audio/agentDeath.ogg": "https://files.ballistica.net/cache/ba1/b6/21/24e67aadbd61847104ba8ffa0f68", + "assets/build/ba_data/audio/agentFall.ogg": "https://files.ballistica.net/cache/ba1/4c/14/3af3b1d0a8d89f53651437553fad", + "assets/build/ba_data/audio/agentHit1.ogg": "https://files.ballistica.net/cache/ba1/47/e6/e44fe406b26aa0f9d6be63dd4eb2", + "assets/build/ba_data/audio/agentHit2.ogg": "https://files.ballistica.net/cache/ba1/3f/2f/ff6ad92df4fceab4bd42911adbb5", + "assets/build/ba_data/audio/alarm.ogg": "https://files.ballistica.net/cache/ba1/8e/e8/5954d0a607b435985e0583036251", + "assets/build/ba_data/audio/ali1.ogg": "https://files.ballistica.net/cache/ba1/dd/d2/50e253495c3e9af6277f812f8cc2", + "assets/build/ba_data/audio/ali2.ogg": "https://files.ballistica.net/cache/ba1/6d/e5/1d80d2bd9f6538f40c710d87196a", + "assets/build/ba_data/audio/ali3.ogg": "https://files.ballistica.net/cache/ba1/94/a9/c0a9ce8b92319f99ae76d8783ac9", + "assets/build/ba_data/audio/ali4.ogg": "https://files.ballistica.net/cache/ba1/b5/bc/d3f492f5f8a23b9fae4e02cfb880", + "assets/build/ba_data/audio/aliDeath.ogg": "https://files.ballistica.net/cache/ba1/3c/b2/10a19c64ff4f563f390ce290fedd", + "assets/build/ba_data/audio/aliFall.ogg": "https://files.ballistica.net/cache/ba1/c6/91/3261e8395f8c2153568f5a329867", + "assets/build/ba_data/audio/aliHit1.ogg": "https://files.ballistica.net/cache/ba1/72/f5/3a3d4c983a518b0c694b686b851d", + "assets/build/ba_data/audio/aliHit2.ogg": "https://files.ballistica.net/cache/ba1/61/27/1a0a3300e8dc4de41f442df714f8", + "assets/build/ba_data/audio/alien1.ogg": "https://files.ballistica.net/cache/ba1/a9/df/bb717af140a367f72dbd04319cec", + "assets/build/ba_data/audio/alien2.ogg": "https://files.ballistica.net/cache/ba1/a7/2c/05628e1bed0bd241113112d2aa22", + "assets/build/ba_data/audio/alien3.ogg": "https://files.ballistica.net/cache/ba1/60/27/e9b73795d8bdf67e4d636f23a96a", + "assets/build/ba_data/audio/alien4.ogg": "https://files.ballistica.net/cache/ba1/4a/a0/0199a46f6439235e465884bb668b", + "assets/build/ba_data/audio/alienDeath.ogg": "https://files.ballistica.net/cache/ba1/dc/94/cf48af48e71cebed571a94109ba6", + "assets/build/ba_data/audio/alienFall.ogg": "https://files.ballistica.net/cache/ba1/c0/6f/eec2d286f32629d5333058d4c949", + "assets/build/ba_data/audio/alienHit1.ogg": "https://files.ballistica.net/cache/ba1/e5/6c/b61eb6b326b80d8be6918551d7b2", + "assets/build/ba_data/audio/alienHit2.ogg": "https://files.ballistica.net/cache/ba1/ac/6d/82d4204ccce77c56de98598654f4", + "assets/build/ba_data/audio/announceEight.ogg": "https://files.ballistica.net/cache/ba1/3b/eb/1a0616700981f67ce85fc7a1a3e5", + "assets/build/ba_data/audio/announceFive.ogg": "https://files.ballistica.net/cache/ba1/08/d9/0735217731f5145f500e2a971657", + "assets/build/ba_data/audio/announceFour.ogg": "https://files.ballistica.net/cache/ba1/39/2a/abf2f0e5a0e731efb52fef7d2164", + "assets/build/ba_data/audio/announceNine.ogg": "https://files.ballistica.net/cache/ba1/a7/ec/36d6f34c676973936fe5450fb861", + "assets/build/ba_data/audio/announceOne.ogg": "https://files.ballistica.net/cache/ba1/7d/3f/93abbbcd31353fb71c1927ad5fab", + "assets/build/ba_data/audio/announceSeven.ogg": "https://files.ballistica.net/cache/ba1/36/68/a1c1401398ae881c41c4f1a036e4", + "assets/build/ba_data/audio/announceSix.ogg": "https://files.ballistica.net/cache/ba1/80/34/8f7ebce4d74fc15d816bce9f69f6", + "assets/build/ba_data/audio/announceTen.ogg": "https://files.ballistica.net/cache/ba1/50/65/cf643755cd165ec6c2a2960cdf45", + "assets/build/ba_data/audio/announceThree.ogg": "https://files.ballistica.net/cache/ba1/c7/87/e05c82825a25390d0d063906e198", + "assets/build/ba_data/audio/announceTwo.ogg": "https://files.ballistica.net/cache/ba1/d3/12/33ffea93ece2581f3b8f6f4e5ecf", + "assets/build/ba_data/audio/assassin1.ogg": "https://files.ballistica.net/cache/ba1/e4/a9/7eb8dd29046c57aa8dbe6695f5ca", + "assets/build/ba_data/audio/assassin2.ogg": "https://files.ballistica.net/cache/ba1/0c/e2/00dd880a5c95908e05f12c4338ec", + "assets/build/ba_data/audio/assassin3.ogg": "https://files.ballistica.net/cache/ba1/02/74/557996d112aa6672022ed59ba64d", + "assets/build/ba_data/audio/assassin4.ogg": "https://files.ballistica.net/cache/ba1/31/e2/429083c2ced72ec5a75d4e9896d7", + "assets/build/ba_data/audio/assassinDeath.ogg": "https://files.ballistica.net/cache/ba1/0b/b8/1350a4fd2af334cbe3521b7b341e", + "assets/build/ba_data/audio/assassinFall.ogg": "https://files.ballistica.net/cache/ba1/d4/fd/540b0c02c35764c199e7ce9159f0", + "assets/build/ba_data/audio/assassinHit1.ogg": "https://files.ballistica.net/cache/ba1/1f/7d/de53cebfb771c2f8f84aacac969c", + "assets/build/ba_data/audio/assassinHit2.ogg": "https://files.ballistica.net/cache/ba1/1b/2e/3a51d3492fbb64562132c1f4655a", + "assets/build/ba_data/audio/bear1.ogg": "https://files.ballistica.net/cache/ba1/98/77/336d440291ae568e0d1e08c904f0", + "assets/build/ba_data/audio/bear2.ogg": "https://files.ballistica.net/cache/ba1/39/cd/efd6adc8211c46c75b72e7766c20", + "assets/build/ba_data/audio/bear3.ogg": "https://files.ballistica.net/cache/ba1/e1/27/4ba2a9579f262a0427719c46be2a", + "assets/build/ba_data/audio/bear4.ogg": "https://files.ballistica.net/cache/ba1/ae/d4/579fb7a26290f4fba626e2f4348a", + "assets/build/ba_data/audio/bearDeath.ogg": "https://files.ballistica.net/cache/ba1/dc/4a/eacdeb3fa2e14d9642cf8da5f302", + "assets/build/ba_data/audio/bearFall.ogg": "https://files.ballistica.net/cache/ba1/c8/7e/34615b7ae496b9a840dbd83e6c37", + "assets/build/ba_data/audio/bearHit1.ogg": "https://files.ballistica.net/cache/ba1/62/e6/88559a4fb97b49054a9292370c0a", + "assets/build/ba_data/audio/bearHit2.ogg": "https://files.ballistica.net/cache/ba1/79/02/402d8dbdbd9c8008b9967c7f6577", + "assets/build/ba_data/audio/bellHigh.ogg": "https://files.ballistica.net/cache/ba1/8b/c2/f6d4e1fa7fe35cfa392414ffab14", + "assets/build/ba_data/audio/bellLow.ogg": "https://files.ballistica.net/cache/ba1/85/53/be1fb03730f7f47a2cca7c7bd01b", + "assets/build/ba_data/audio/bellMed.ogg": "https://files.ballistica.net/cache/ba1/0a/47/aca308341bffb0d8e71b42f63eb9", + "assets/build/ba_data/audio/bigImpact.ogg": "https://files.ballistica.net/cache/ba1/aa/bd/0e835f818bddac8b3344614941ed", + "assets/build/ba_data/audio/bigImpact2.ogg": "https://files.ballistica.net/cache/ba1/58/b9/91a3922a95f5c41e90111f6a482e", + "assets/build/ba_data/audio/blank.ogg": "https://files.ballistica.net/cache/ba1/d8/9f/f09b8eb28637e7371ed746245e38", + "assets/build/ba_data/audio/blip.ogg": "https://files.ballistica.net/cache/ba1/c9/cc/433b1bd9414149c17fd63967e7a9", + "assets/build/ba_data/audio/block.ogg": "https://files.ballistica.net/cache/ba1/d6/13/7ac8c0ca9c66fed26d06fb06cbfa", + "assets/build/ba_data/audio/bombDrop01.ogg": "https://files.ballistica.net/cache/ba1/5f/71/3723b381503fb18cbf7602882490", + "assets/build/ba_data/audio/bombDrop02.ogg": "https://files.ballistica.net/cache/ba1/29/fe/2131cb71f993e5fdaced1ae344d0", + "assets/build/ba_data/audio/bombRoll01.ogg": "https://files.ballistica.net/cache/ba1/46/24/f94e3229938ceec4bc81c70b92bf", + "assets/build/ba_data/audio/bones1.ogg": "https://files.ballistica.net/cache/ba1/c4/ca/f481223b62cc47621a43d53c98d0", + "assets/build/ba_data/audio/bones2.ogg": "https://files.ballistica.net/cache/ba1/6c/90/21466f4bc9251a3619901b3b23a4", + "assets/build/ba_data/audio/bones3.ogg": "https://files.ballistica.net/cache/ba1/46/e8/bef77fe076dc05ce913cecde7bac", + "assets/build/ba_data/audio/bonesDeath.ogg": "https://files.ballistica.net/cache/ba1/f9/42/bb3834ac4aa6bbdd830f6754a31a", + "assets/build/ba_data/audio/bonesFall.ogg": "https://files.ballistica.net/cache/ba1/be/6e/a21349d4b48d598427f08d722751", + "assets/build/ba_data/audio/boo.ogg": "https://files.ballistica.net/cache/ba1/e0/48/efff2fce2324b9692c34b9f7d0e3", + "assets/build/ba_data/audio/boxDrop.ogg": "https://files.ballistica.net/cache/ba1/ef/7e/fe58d3f396846af32304aa7ffdaf", + "assets/build/ba_data/audio/boxingBell.ogg": "https://files.ballistica.net/cache/ba1/a1/33/4cca31700ec77f92463b4a2d59ba", + "assets/build/ba_data/audio/bunny1.ogg": "https://files.ballistica.net/cache/ba1/39/a6/4c87b4a9a2b4f024e040c507249e", + "assets/build/ba_data/audio/bunny2.ogg": "https://files.ballistica.net/cache/ba1/17/a2/7ad3dd657c242eb0fd9597c3b711", + "assets/build/ba_data/audio/bunny3.ogg": "https://files.ballistica.net/cache/ba1/51/3c/c2d568406738c2af114ae598d0c2", + "assets/build/ba_data/audio/bunny4.ogg": "https://files.ballistica.net/cache/ba1/12/04/e7227b27f9c4642e0ea759db5f0a", + "assets/build/ba_data/audio/bunnyDeath.ogg": "https://files.ballistica.net/cache/ba1/6d/8c/7d425a6fff1f31d65482be258725", + "assets/build/ba_data/audio/bunnyFall.ogg": "https://files.ballistica.net/cache/ba1/2b/ef/fc04cdf73f07f00e31f434e92467", + "assets/build/ba_data/audio/bunnyHit1.ogg": "https://files.ballistica.net/cache/ba1/d3/83/25ced5d362767762a2cbad4c6398", + "assets/build/ba_data/audio/bunnyHit2.ogg": "https://files.ballistica.net/cache/ba1/53/7a/c30b06d5eeaff52e85252b73335e", + "assets/build/ba_data/audio/bunnyJump.ogg": "https://files.ballistica.net/cache/ba1/b7/63/857bfb36969dcbe49e64f3fab114", + "assets/build/ba_data/audio/cashRegister.ogg": "https://files.ballistica.net/cache/ba1/79/fd/504073b758363f672e7d980e0bdb", + "assets/build/ba_data/audio/cashRegister2.ogg": "https://files.ballistica.net/cache/ba1/19/d8/51c692662191259537ffb4c06451", + "assets/build/ba_data/audio/charSelectMusic.ogg": "https://files.ballistica.net/cache/ba1/df/61/6d8295ad5d5d15ec214566edf232", + "assets/build/ba_data/audio/cheer.ogg": "https://files.ballistica.net/cache/ba1/58/e3/8ff9e3b4ff31b0253434e3573525", + "assets/build/ba_data/audio/click01.ogg": "https://files.ballistica.net/cache/ba1/73/67/f594fa27345bde2a53911ad53645", + "assets/build/ba_data/audio/corkPop.ogg": "https://files.ballistica.net/cache/ba1/5c/66/2d38e3e783cac8783859d54ad22e", + "assets/build/ba_data/audio/cowboy1.ogg": "https://files.ballistica.net/cache/ba1/dc/00/812fbcea9de111d95d625f80f8c9", + "assets/build/ba_data/audio/cowboy2.ogg": "https://files.ballistica.net/cache/ba1/7a/4f/3e508d10914604287789bfddcfc4", + "assets/build/ba_data/audio/cowboy3.ogg": "https://files.ballistica.net/cache/ba1/bb/3f/1cb99923597b3bdf292d5c0b08e7", + "assets/build/ba_data/audio/cowboy4.ogg": "https://files.ballistica.net/cache/ba1/88/8c/7a1f7db130a52df860e49bf76ff9", + "assets/build/ba_data/audio/cowboyDeath.ogg": "https://files.ballistica.net/cache/ba1/5a/c3/21f0dfe0a77b372747a979e33998", + "assets/build/ba_data/audio/cowboyFall.ogg": "https://files.ballistica.net/cache/ba1/0e/df/a4546112eb1c841e2c9fee194a70", + "assets/build/ba_data/audio/cowboyHit1.ogg": "https://files.ballistica.net/cache/ba1/10/8b/5b57b3c71cab970f36cfc6d0bac8", + "assets/build/ba_data/audio/cowboyHit2.ogg": "https://files.ballistica.net/cache/ba1/e6/c3/af4435a0fc1c1bf8c528355f4dff", + "assets/build/ba_data/audio/crowdChant.ogg": "https://files.ballistica.net/cache/ba1/e0/c9/e2a8d3df75add22257e3abad8922", + "assets/build/ba_data/audio/cyborg1.ogg": "https://files.ballistica.net/cache/ba1/3a/12/3656e65d308d0fbde98d313d3fde", + "assets/build/ba_data/audio/cyborg2.ogg": "https://files.ballistica.net/cache/ba1/8c/28/99ee4c948e9c217edf70fbd7bb0d", + "assets/build/ba_data/audio/cyborg3.ogg": "https://files.ballistica.net/cache/ba1/90/65/42d387ea506f74aa079ac8c585ea", + "assets/build/ba_data/audio/cyborg4.ogg": "https://files.ballistica.net/cache/ba1/8d/39/120d057ebf564c4f0513cf0b2aac", + "assets/build/ba_data/audio/cyborgDeath.ogg": "https://files.ballistica.net/cache/ba1/de/cf/5bcf43503ff733a85bf85f19b291", + "assets/build/ba_data/audio/cyborgFall.ogg": "https://files.ballistica.net/cache/ba1/3b/9f/0c255b77a12ddb4f0d2cd378f28d", + "assets/build/ba_data/audio/cyborgHit1.ogg": "https://files.ballistica.net/cache/ba1/c6/25/1410623e05707fad84714d9cc95e", + "assets/build/ba_data/audio/cyborgHit2.ogg": "https://files.ballistica.net/cache/ba1/db/1f/05e2ad336cfa4a872511887a2f2c", + "assets/build/ba_data/audio/cymbal.ogg": "https://files.ballistica.net/cache/ba1/d4/fc/131a8411247271e02d42335664e0", + "assets/build/ba_data/audio/debrisFall.ogg": "https://files.ballistica.net/cache/ba1/0e/45/1806965a4157a8a4a22165d5bf2d", + "assets/build/ba_data/audio/deek.ogg": "https://files.ballistica.net/cache/ba1/63/81/0a5fcf154a97a8aed545547dee31", + "assets/build/ba_data/audio/deek2.ogg": "https://files.ballistica.net/cache/ba1/28/17/4a7af5b167ffedf1fb84438dfce0", + "assets/build/ba_data/audio/ding.ogg": "https://files.ballistica.net/cache/ba1/16/88/bbb194e8ca80d2a03dec562e9d1f", + "assets/build/ba_data/audio/dingSmall.ogg": "https://files.ballistica.net/cache/ba1/4b/33/2ff11a985f1309874b219cd27bf9", + "assets/build/ba_data/audio/dingSmallHigh.ogg": "https://files.ballistica.net/cache/ba1/33/f6/74395c50b2b4a15887850397adf1", + "assets/build/ba_data/audio/dripity.ogg": "https://files.ballistica.net/cache/ba1/7b/ad/a0b56c34e00670d7e10755e585b9", + "assets/build/ba_data/audio/drumRoll.ogg": "https://files.ballistica.net/cache/ba1/f8/d2/d14a0f8240383882012347598148", + "assets/build/ba_data/audio/error.ogg": "https://files.ballistica.net/cache/ba1/ed/9c/f70d9b620abd6911ab767ba87983", + "assets/build/ba_data/audio/explosion01.ogg": "https://files.ballistica.net/cache/ba1/7e/b9/1498aef56d0cabf44d9750561b6a", + "assets/build/ba_data/audio/explosion02.ogg": "https://files.ballistica.net/cache/ba1/6e/eb/27f85984133e75b161e361d5f81e", + "assets/build/ba_data/audio/explosion03.ogg": "https://files.ballistica.net/cache/ba1/fe/43/11e0fb6e26f265cdf1ca7f2da745", + "assets/build/ba_data/audio/explosion04.ogg": "https://files.ballistica.net/cache/ba1/36/9e/3bd1ce90fbfae702e9dd72a9d48e", + "assets/build/ba_data/audio/explosion05.ogg": "https://files.ballistica.net/cache/ba1/1e/aa/f424b99fe507765a1870f6d5236b", + "assets/build/ba_data/audio/fanfare.ogg": "https://files.ballistica.net/cache/ba1/eb/29/d16f4a6a9ff6d8960823706f1ce7", + "assets/build/ba_data/audio/flagCatcherMusic.ogg": "https://files.ballistica.net/cache/ba1/d8/b8/a978be710eed77e94e070475dd13", + "assets/build/ba_data/audio/flyingMusic.ogg": "https://files.ballistica.net/cache/ba1/dc/12/a419f0ee7e007dd49b72c2c574d3", + "assets/build/ba_data/audio/foghorn.ogg": "https://files.ballistica.net/cache/ba1/cf/2b/2301a2b441ac864aa284e3022a2f", + "assets/build/ba_data/audio/footImpact01.ogg": "https://files.ballistica.net/cache/ba1/47/81/87c67f98a3adf3e7f0ddd7460dea", + "assets/build/ba_data/audio/footImpact02.ogg": "https://files.ballistica.net/cache/ba1/f9/70/3eb5274dfef080daa3c0d8c6c62b", + "assets/build/ba_data/audio/footImpact03.ogg": "https://files.ballistica.net/cache/ba1/ac/b7/12b82e1d01d73d5516260f15048c", + "assets/build/ba_data/audio/forwardMarchMusic.ogg": "https://files.ballistica.net/cache/ba1/6d/7a/79524b49cf44427a54c9e02a07fc", + "assets/build/ba_data/audio/freeze.ogg": "https://files.ballistica.net/cache/ba1/ef/ae/243ec63c7f43d2c8c8b27e2d6c5e", + "assets/build/ba_data/audio/frosty01.ogg": "https://files.ballistica.net/cache/ba1/78/54/50cc202f0c5c882eba69a1d0d4e0", + "assets/build/ba_data/audio/frosty02.ogg": "https://files.ballistica.net/cache/ba1/54/cb/db2a15e2603d695c762c167ec47e", + "assets/build/ba_data/audio/frosty03.ogg": "https://files.ballistica.net/cache/ba1/cb/2e/1cfe57cd40f8a4e93081750cd399", + "assets/build/ba_data/audio/frosty04.ogg": "https://files.ballistica.net/cache/ba1/b9/5e/70884a5fb4574dad0bf8c1fa3bef", + "assets/build/ba_data/audio/frosty05.ogg": "https://files.ballistica.net/cache/ba1/34/31/9d35a7e8b9033c12a7568edcdd36", + "assets/build/ba_data/audio/frostyDeath.ogg": "https://files.ballistica.net/cache/ba1/c7/d7/4a5ac1bf26f819ead60ab0fd94d9", + "assets/build/ba_data/audio/frostyFall.ogg": "https://files.ballistica.net/cache/ba1/4a/98/b22db7e70d6f3d6baff5991d8ad7", + "assets/build/ba_data/audio/frostyHit01.ogg": "https://files.ballistica.net/cache/ba1/0a/e1/06b5309853b9c3f572be2c293ee7", + "assets/build/ba_data/audio/frostyHit02.ogg": "https://files.ballistica.net/cache/ba1/1b/cd/0e8adb2a330a715665be2c8e3ba0", + "assets/build/ba_data/audio/frostyHit03.ogg": "https://files.ballistica.net/cache/ba1/02/71/967daf9f36809718fa1643c7d6d5", + "assets/build/ba_data/audio/fuse01.ogg": "https://files.ballistica.net/cache/ba1/41/f5/296bc578f709709f3aff84077cc3", + "assets/build/ba_data/audio/gladiator1.ogg": "https://files.ballistica.net/cache/ba1/c8/80/4b8c2db0a5beebe784bbe5a8b6a8", + "assets/build/ba_data/audio/gladiator2.ogg": "https://files.ballistica.net/cache/ba1/2e/49/54c1b9e9c742f56cbf54f13c4ee1", + "assets/build/ba_data/audio/gladiator3.ogg": "https://files.ballistica.net/cache/ba1/80/11/c9e896259f3308a280ca38d5c780", + "assets/build/ba_data/audio/gladiator4.ogg": "https://files.ballistica.net/cache/ba1/fc/66/36ac046a06518f604cdb0e005178", + "assets/build/ba_data/audio/gladiatorDeath.ogg": "https://files.ballistica.net/cache/ba1/c2/04/5cfc04b504bc34e9f04e867623e9", + "assets/build/ba_data/audio/gladiatorFall.ogg": "https://files.ballistica.net/cache/ba1/64/ba/ecf274ba07d2d222003a91aac1f0", + "assets/build/ba_data/audio/gladiatorHit1.ogg": "https://files.ballistica.net/cache/ba1/09/77/43243b32309432e490500bc65fec", + "assets/build/ba_data/audio/gladiatorHit2.ogg": "https://files.ballistica.net/cache/ba1/0f/e2/9db7131b3571e1f7536152f95a1b", + "assets/build/ba_data/audio/gong.ogg": "https://files.ballistica.net/cache/ba1/ad/61/9dfed5e89099bc1f6ea83c0f40ec", + "assets/build/ba_data/audio/grandRompMusic.ogg": "https://files.ballistica.net/cache/ba1/85/82/c111e007c297fc684ffadec5008a", + "assets/build/ba_data/audio/gravelSkid.ogg": "https://files.ballistica.net/cache/ba1/54/63/03294f2ef8a416c73267419ec2b2", + "assets/build/ba_data/audio/gunCocking.ogg": "https://files.ballistica.net/cache/ba1/26/4c/e6d7cdf8472d17ae4c6361514356", + "assets/build/ba_data/audio/healthPowerup.ogg": "https://files.ballistica.net/cache/ba1/bc/e5/fccfe9edbdbdf93fc7b1e075c943", + "assets/build/ba_data/audio/hiss.ogg": "https://files.ballistica.net/cache/ba1/89/c3/6c45ce2abdfce03da210ed8c0a56", + "assets/build/ba_data/audio/impactHard.ogg": "https://files.ballistica.net/cache/ba1/9d/6d/74fd1499949de4e06a048dc22c24", + "assets/build/ba_data/audio/impactHard2.ogg": "https://files.ballistica.net/cache/ba1/23/42/1c61b4fe3eeec854a1f20f49c396", + "assets/build/ba_data/audio/impactHard3.ogg": "https://files.ballistica.net/cache/ba1/7e/95/5d3ca7f094e96ec8e0fa2e6cfcf9", + "assets/build/ba_data/audio/impactMedium.ogg": "https://files.ballistica.net/cache/ba1/5e/d2/7ebdb51bf6a71868b6add769b116", + "assets/build/ba_data/audio/impactMedium2.ogg": "https://files.ballistica.net/cache/ba1/34/e6/c08c1cdf9de0f22fab54a77b0b9b", + "assets/build/ba_data/audio/jack01.ogg": "https://files.ballistica.net/cache/ba1/96/d5/53f8ecb5f29a49e26c5914491c84", + "assets/build/ba_data/audio/jack02.ogg": "https://files.ballistica.net/cache/ba1/cc/68/6fc4306e6a8aa7443e856e2aaa96", + "assets/build/ba_data/audio/jack03.ogg": "https://files.ballistica.net/cache/ba1/8a/52/8e60fcc02ebab532e1c425c0aadf", + "assets/build/ba_data/audio/jack04.ogg": "https://files.ballistica.net/cache/ba1/06/32/f32924a83fd81b688110b11412ad", + "assets/build/ba_data/audio/jack05.ogg": "https://files.ballistica.net/cache/ba1/15/19/c6d3b80e05ffff5a1650805b21a0", + "assets/build/ba_data/audio/jack06.ogg": "https://files.ballistica.net/cache/ba1/0d/88/0e7a1ac17d47841d647561dd34c9", + "assets/build/ba_data/audio/jackDeath01.ogg": "https://files.ballistica.net/cache/ba1/92/34/ea8bb19d84fe4d994af417ef8585", + "assets/build/ba_data/audio/jackFall01.ogg": "https://files.ballistica.net/cache/ba1/5f/b3/c6f18f19b7a0782b716462a2430c", + "assets/build/ba_data/audio/jackHit01.ogg": "https://files.ballistica.net/cache/ba1/eb/8a/1d43a95e86e685414c09f9924743", + "assets/build/ba_data/audio/jackHit02.ogg": "https://files.ballistica.net/cache/ba1/c0/48/7a07aa8fdfd49f81021b5203110b", + "assets/build/ba_data/audio/jackHit03.ogg": "https://files.ballistica.net/cache/ba1/12/ee/092007083ce10141735b173b3373", + "assets/build/ba_data/audio/jackHit04.ogg": "https://files.ballistica.net/cache/ba1/58/12/72aa832aff572bba5be892449340", + "assets/build/ba_data/audio/jackHit05.ogg": "https://files.ballistica.net/cache/ba1/d6/fd/18000b475bbd1653ea70ebfa2f0c", + "assets/build/ba_data/audio/jackHit06.ogg": "https://files.ballistica.net/cache/ba1/f6/32/8538633e8e8461284c20f050d7f7", + "assets/build/ba_data/audio/jackHit07.ogg": "https://files.ballistica.net/cache/ba1/18/1d/a762e6887e5a7ce63b0b364b27cd", + "assets/build/ba_data/audio/jumpsuit1.ogg": "https://files.ballistica.net/cache/ba1/97/50/0121d8d9f15f6d9324cd7207cd0b", + "assets/build/ba_data/audio/jumpsuit2.ogg": "https://files.ballistica.net/cache/ba1/eb/9b/4648fe0c9bc941dcb157b868b7d5", + "assets/build/ba_data/audio/jumpsuit3.ogg": "https://files.ballistica.net/cache/ba1/ab/5a/bc86ad2318b5ff5a2d3865acc8a0", + "assets/build/ba_data/audio/jumpsuit4.ogg": "https://files.ballistica.net/cache/ba1/fa/aa/5a0671c0e9cd36683661ccba6109", + "assets/build/ba_data/audio/jumpsuitDeath.ogg": "https://files.ballistica.net/cache/ba1/80/5a/2d7b77e4a0a4e74beb5213512c19", + "assets/build/ba_data/audio/jumpsuitFall.ogg": "https://files.ballistica.net/cache/ba1/a0/f5/b09d7a0643904b17abe57f5291bd", + "assets/build/ba_data/audio/jumpsuitHit1.ogg": "https://files.ballistica.net/cache/ba1/54/ea/17e320c2551d4632334bebafd94d", + "assets/build/ba_data/audio/jumpsuitHit2.ogg": "https://files.ballistica.net/cache/ba1/6b/0e/3e27df545c96ccb4d2f1b061d2ce", + "assets/build/ba_data/audio/kronk1.ogg": "https://files.ballistica.net/cache/ba1/fc/1a/194cfb91ec793a99fc4879b2573b", + "assets/build/ba_data/audio/kronk10.ogg": "https://files.ballistica.net/cache/ba1/ab/6a/2c0ded3ac98a111c5ab598c8db13", + "assets/build/ba_data/audio/kronk2.ogg": "https://files.ballistica.net/cache/ba1/e1/70/55d4e6a5197e43786c6b924a2d93", + "assets/build/ba_data/audio/kronk3.ogg": "https://files.ballistica.net/cache/ba1/34/c4/77692a4a87bee598049e46cb4c82", + "assets/build/ba_data/audio/kronk4.ogg": "https://files.ballistica.net/cache/ba1/b6/49/4a8bc3d7dabc34163b62fec0b6ad", + "assets/build/ba_data/audio/kronk5.ogg": "https://files.ballistica.net/cache/ba1/ae/aa/85c5bd2a3d4f7b9c737ad9785ae5", + "assets/build/ba_data/audio/kronk6.ogg": "https://files.ballistica.net/cache/ba1/fd/b5/32987dd992dfab8fc849a07697bb", + "assets/build/ba_data/audio/kronk7.ogg": "https://files.ballistica.net/cache/ba1/49/fb/57f27cb591580e150f3d8a42eb47", + "assets/build/ba_data/audio/kronk8.ogg": "https://files.ballistica.net/cache/ba1/a4/f5/3029a36ea83bddf21d927e6995f2", + "assets/build/ba_data/audio/kronk9.ogg": "https://files.ballistica.net/cache/ba1/8c/2f/66cb5d3c6c73c94bdc702a4fe17d", + "assets/build/ba_data/audio/kronkDeath.ogg": "https://files.ballistica.net/cache/ba1/05/35/609ce71b9a16d3de816c3c60b664", + "assets/build/ba_data/audio/kronkFall.ogg": "https://files.ballistica.net/cache/ba1/c2/eb/b031ad4546850a2119e406836a2d", + "assets/build/ba_data/audio/laser.ogg": "https://files.ballistica.net/cache/ba1/11/fe/b68a27770a0ee23e5b4aa0de32a1", + "assets/build/ba_data/audio/laserReverse.ogg": "https://files.ballistica.net/cache/ba1/c0/09/165efbc651137eaf2808bf22a521", + "assets/build/ba_data/audio/mel01.ogg": "https://files.ballistica.net/cache/ba1/ab/bb/92ed08f8b0664da263b64549377f", + "assets/build/ba_data/audio/mel02.ogg": "https://files.ballistica.net/cache/ba1/75/8b/72aeaaee1ae57248c9303a993345", + "assets/build/ba_data/audio/mel03.ogg": "https://files.ballistica.net/cache/ba1/15/c6/366ac3da0fd7fa589f19fdfea463", + "assets/build/ba_data/audio/mel04.ogg": "https://files.ballistica.net/cache/ba1/37/56/430e27a2bcc5d265454996b9a908", + "assets/build/ba_data/audio/mel05.ogg": "https://files.ballistica.net/cache/ba1/60/4b/119cb366dbd8524903d28193b4e3", + "assets/build/ba_data/audio/mel06.ogg": "https://files.ballistica.net/cache/ba1/44/b5/2dfad899e58487e9f1e8668046ad", + "assets/build/ba_data/audio/mel07.ogg": "https://files.ballistica.net/cache/ba1/00/16/1a628969cc1bdfd4e7691f4b2902", + "assets/build/ba_data/audio/mel08.ogg": "https://files.ballistica.net/cache/ba1/11/98/fc1a85f19321be5d3d93df199ab2", + "assets/build/ba_data/audio/mel09.ogg": "https://files.ballistica.net/cache/ba1/77/34/5eb4eda9f56179b32a8aa707fc9b", + "assets/build/ba_data/audio/mel10.ogg": "https://files.ballistica.net/cache/ba1/5c/14/7f06c944feedcf240332dc67b610", + "assets/build/ba_data/audio/melDeath01.ogg": "https://files.ballistica.net/cache/ba1/b6/63/2541553e0ca4dffb462d45600d86", + "assets/build/ba_data/audio/melFall01.ogg": "https://files.ballistica.net/cache/ba1/9e/1f/35804bbb5ad31d1aacfe1fe08dc4", + "assets/build/ba_data/audio/menuMusic.ogg": "https://files.ballistica.net/cache/ba1/f7/03/4a24ed6aa4d916a9df0b330e3541", + "assets/build/ba_data/audio/metalHit.ogg": "https://files.ballistica.net/cache/ba1/44/b0/16de55ee611e53cca4e7b09390e0", + "assets/build/ba_data/audio/metalSkid.ogg": "https://files.ballistica.net/cache/ba1/68/02/28668811516444c52e7b289be025", + "assets/build/ba_data/audio/ninjaAttack1.ogg": "https://files.ballistica.net/cache/ba1/b0/d4/c083ebbca9f07fe72df06d73b2ff", + "assets/build/ba_data/audio/ninjaAttack2.ogg": "https://files.ballistica.net/cache/ba1/37/56/9b04b3fd1920100f34078e6f1a6f", + "assets/build/ba_data/audio/ninjaAttack3.ogg": "https://files.ballistica.net/cache/ba1/85/05/6b2ed4d125769a1b07fdc9f2a602", + "assets/build/ba_data/audio/ninjaAttack4.ogg": "https://files.ballistica.net/cache/ba1/f9/f5/d380bf32d6365b8f5e4c7b4a18ed", + "assets/build/ba_data/audio/ninjaAttack5.ogg": "https://files.ballistica.net/cache/ba1/ed/5f/b08a4531e9f04936d9190ea9c76b", + "assets/build/ba_data/audio/ninjaAttack6.ogg": "https://files.ballistica.net/cache/ba1/bb/94/e1dba3355ab518d79a3a9c90e3af", + "assets/build/ba_data/audio/ninjaAttack7.ogg": "https://files.ballistica.net/cache/ba1/fe/1c/7aad8d309eb95a157d70d2f3fb99", + "assets/build/ba_data/audio/ninjaDeath1.ogg": "https://files.ballistica.net/cache/ba1/99/84/eeb03dd81dfe74cc12fc0a4d5146", + "assets/build/ba_data/audio/ninjaFall1.ogg": "https://files.ballistica.net/cache/ba1/25/f8/80c787da086852e2a238f000fbea", + "assets/build/ba_data/audio/ninjaHit1.ogg": "https://files.ballistica.net/cache/ba1/f3/4d/72e7df81aa5817b8e405d619fdb9", + "assets/build/ba_data/audio/ninjaHit2.ogg": "https://files.ballistica.net/cache/ba1/dc/c8/ab4747bfd316baffb75d4ffb1a8e", + "assets/build/ba_data/audio/ninjaHit3.ogg": "https://files.ballistica.net/cache/ba1/02/b0/f99869d96698356a52fd8babb2d5", + "assets/build/ba_data/audio/ninjaHit4.ogg": "https://files.ballistica.net/cache/ba1/bb/4f/683ecb1ffad9e80c54b520ebd4bf", + "assets/build/ba_data/audio/ninjaHit5.ogg": "https://files.ballistica.net/cache/ba1/62/2e/0fcdd8e9326d394cd5d0d4830f66", + "assets/build/ba_data/audio/ninjaHit6.ogg": "https://files.ballistica.net/cache/ba1/82/5d/77c5ecf4a4e7f05e807b2c6ae2f7", + "assets/build/ba_data/audio/ninjaHit7.ogg": "https://files.ballistica.net/cache/ba1/b1/26/67ac98f1cb3d05ad5ab9aed04f7c", + "assets/build/ba_data/audio/ninjaHit8.ogg": "https://files.ballistica.net/cache/ba1/57/0d/affc43fb3ad32cb99f43552e3539", + "assets/build/ba_data/audio/oldLady1.ogg": "https://files.ballistica.net/cache/ba1/89/9a/d977ef9b0b4c2f4da4e666c9f155", + "assets/build/ba_data/audio/oldLady2.ogg": "https://files.ballistica.net/cache/ba1/f3/d0/37383856445b94d6256a7594fabd", + "assets/build/ba_data/audio/oldLady3.ogg": "https://files.ballistica.net/cache/ba1/92/46/bd82fce5c5312d839a5581611b78", + "assets/build/ba_data/audio/oldLady4.ogg": "https://files.ballistica.net/cache/ba1/d7/b8/a006e5302fad91903ffcf3bb1e28", + "assets/build/ba_data/audio/oldLadyDeath.ogg": "https://files.ballistica.net/cache/ba1/ce/82/bd5efc26ae4f6ef7b93811fec82d", + "assets/build/ba_data/audio/oldLadyFall.ogg": "https://files.ballistica.net/cache/ba1/44/6f/f01ae6802200636164bfd7677d69", + "assets/build/ba_data/audio/oldLadyHit1.ogg": "https://files.ballistica.net/cache/ba1/bf/bd/d5cfdd70dac2d1cec098faa7bd26", + "assets/build/ba_data/audio/oldLadyHit2.ogg": "https://files.ballistica.net/cache/ba1/2e/33/888bc43ee9022a842a459273ea21", + "assets/build/ba_data/audio/ooh.ogg": "https://files.ballistica.net/cache/ba1/2b/74/959198956efaaaf776aa24944b8f", + "assets/build/ba_data/audio/operaSinger1.ogg": "https://files.ballistica.net/cache/ba1/80/c7/c015724a7015ef647a3ffb823c35", + "assets/build/ba_data/audio/operaSinger2.ogg": "https://files.ballistica.net/cache/ba1/f2/43/79e4b0022894a568d741663d5934", + "assets/build/ba_data/audio/operaSinger3.ogg": "https://files.ballistica.net/cache/ba1/9f/d8/75946b3b45ae8942204e826175b9", + "assets/build/ba_data/audio/operaSinger4.ogg": "https://files.ballistica.net/cache/ba1/34/f0/d3b204d76a2ffa33063eacb6c4fd", + "assets/build/ba_data/audio/operaSingerDeath.ogg": "https://files.ballistica.net/cache/ba1/3d/bd/59755221471fffc28dfc93d15d2e", + "assets/build/ba_data/audio/operaSingerFall.ogg": "https://files.ballistica.net/cache/ba1/5e/ec/c2d319569d8ffa19414c7bd9263c", + "assets/build/ba_data/audio/operaSingerHit1.ogg": "https://files.ballistica.net/cache/ba1/b8/18/96ad11d2b9504dd846bddd9f57a6", + "assets/build/ba_data/audio/operaSingerHit2.ogg": "https://files.ballistica.net/cache/ba1/d2/69/7660cd8d13ef7f1cc463ca480fbd", + "assets/build/ba_data/audio/orchestraHit.ogg": "https://files.ballistica.net/cache/ba1/fd/34/8dc7ed68ddc8802fe9fb1ad09bc6", + "assets/build/ba_data/audio/orchestraHit2.ogg": "https://files.ballistica.net/cache/ba1/01/4c/006e6feb4bd61fa548efe9e95573", + "assets/build/ba_data/audio/orchestraHit3.ogg": "https://files.ballistica.net/cache/ba1/1e/97/fffcf206cfb4ffe9f1b6e5e6ea90", + "assets/build/ba_data/audio/orchestraHit4.ogg": "https://files.ballistica.net/cache/ba1/bc/74/ab66f3ad2d55ee9a18a484de5aef", + "assets/build/ba_data/audio/orchestraHitBig1.ogg": "https://files.ballistica.net/cache/ba1/b5/21/f089746ffd5b412e5f5540280a12", + "assets/build/ba_data/audio/orchestraHitBig2.ogg": "https://files.ballistica.net/cache/ba1/19/e4/30eaac3a0e55e6e11c8e860cc568", + "assets/build/ba_data/audio/penguin1.ogg": "https://files.ballistica.net/cache/ba1/d2/f2/d515297a46b8b66db28a1d01ecd7", + "assets/build/ba_data/audio/penguin2.ogg": "https://files.ballistica.net/cache/ba1/d7/f2/e6018f4bf38aaa1d0a2878f3d635", + "assets/build/ba_data/audio/penguin3.ogg": "https://files.ballistica.net/cache/ba1/dc/a9/67c6bb4920e023f730ea54f72b8f", + "assets/build/ba_data/audio/penguin4.ogg": "https://files.ballistica.net/cache/ba1/db/b9/1fbf06641f6d5c350cbdbcb22ca5", + "assets/build/ba_data/audio/penguinDeath.ogg": "https://files.ballistica.net/cache/ba1/ea/c0/bf1376748440c618c5644845402f", + "assets/build/ba_data/audio/penguinFall.ogg": "https://files.ballistica.net/cache/ba1/e0/23/5daf51c16bdef312bb6c643a3bdd", + "assets/build/ba_data/audio/penguinHit1.ogg": "https://files.ballistica.net/cache/ba1/ce/d7/f7584e0b34fa4f557c6877413e66", + "assets/build/ba_data/audio/penguinHit2.ogg": "https://files.ballistica.net/cache/ba1/b5/87/d08142a2c30bc6c25236c3ea4904", + "assets/build/ba_data/audio/pixie1.ogg": "https://files.ballistica.net/cache/ba1/f3/e5/b4e8705a6b28d0931c36e2f50131", + "assets/build/ba_data/audio/pixie2.ogg": "https://files.ballistica.net/cache/ba1/83/31/b00bd8b0924c99fa10f276d16f76", + "assets/build/ba_data/audio/pixie3.ogg": "https://files.ballistica.net/cache/ba1/37/6b/ff168951b2b8ec9414eceaa684f8", + "assets/build/ba_data/audio/pixie4.ogg": "https://files.ballistica.net/cache/ba1/4e/30/4386b812997fa62a43d5d2ad6671", + "assets/build/ba_data/audio/pixieDeath.ogg": "https://files.ballistica.net/cache/ba1/e2/36/fa9bfccfe97c5e10eb32066d84db", + "assets/build/ba_data/audio/pixieFall.ogg": "https://files.ballistica.net/cache/ba1/d1/2d/88d73cd9212a22bbe56f67200cc0", + "assets/build/ba_data/audio/pixieHit1.ogg": "https://files.ballistica.net/cache/ba1/d3/d8/b4df93455633ecb310c821c64194", + "assets/build/ba_data/audio/pixieHit2.ogg": "https://files.ballistica.net/cache/ba1/ca/ef/3b10c93ac23f606c11f2e013e425", + "assets/build/ba_data/audio/playerDeath.ogg": "https://files.ballistica.net/cache/ba1/08/7d/b5edba071311a58c2978d0eccc15", + "assets/build/ba_data/audio/playerLeft.ogg": "https://files.ballistica.net/cache/ba1/7c/8c/b92e847755d33787f509710f1fdf", + "assets/build/ba_data/audio/pop01.ogg": "https://files.ballistica.net/cache/ba1/38/4b/c4419b1330a6563cc92d4de497ee", + "assets/build/ba_data/audio/powerdown01.ogg": "https://files.ballistica.net/cache/ba1/92/00/c983f3a43c7b65115cbb2a09db81", + "assets/build/ba_data/audio/powerup01.ogg": "https://files.ballistica.net/cache/ba1/f6/ac/aa47ef019ae21153f0559be99fd1", + "assets/build/ba_data/audio/punch01.ogg": "https://files.ballistica.net/cache/ba1/fd/7c/a9d0ce09a4f673b146092ca529f1", + "assets/build/ba_data/audio/punchStrong01.ogg": "https://files.ballistica.net/cache/ba1/a4/85/f0bc0bb825f6c9165a16bbb6c8da", + "assets/build/ba_data/audio/punchStrong02.ogg": "https://files.ballistica.net/cache/ba1/54/01/c703a12fa60d946cd029dc152580", + "assets/build/ba_data/audio/punchSwish.ogg": "https://files.ballistica.net/cache/ba1/da/13/4dcb1bf034c9949f71560bfa220b", + "assets/build/ba_data/audio/punchWeak01.ogg": "https://files.ballistica.net/cache/ba1/c1/4d/5e70a755a58c979f10c7a0450b85", + "assets/build/ba_data/audio/raceBeep1.ogg": "https://files.ballistica.net/cache/ba1/27/89/973816794f93a411ba5c4e39a40f", + "assets/build/ba_data/audio/raceBeep2.ogg": "https://files.ballistica.net/cache/ba1/08/21/2e0e878739351c7675b8f87ca427", + "assets/build/ba_data/audio/refWhistle.ogg": "https://files.ballistica.net/cache/ba1/4c/c6/a5e4cc5d0838c15a2b531f377ea6", + "assets/build/ba_data/audio/robot1.ogg": "https://files.ballistica.net/cache/ba1/7c/ce/6048a27152d969b861dc8f870d63", + "assets/build/ba_data/audio/robot2.ogg": "https://files.ballistica.net/cache/ba1/0c/6a/ea28b8b88096302ea8b77d18ec9a", + "assets/build/ba_data/audio/robot3.ogg": "https://files.ballistica.net/cache/ba1/fa/31/55165ae00ae09d815536f2f38d0b", + "assets/build/ba_data/audio/robot4.ogg": "https://files.ballistica.net/cache/ba1/78/67/d049001912689d8fd303582683d5", + "assets/build/ba_data/audio/robotDeath.ogg": "https://files.ballistica.net/cache/ba1/eb/c3/c0645bf885e4d23f162da1994f1e", + "assets/build/ba_data/audio/robotFall.ogg": "https://files.ballistica.net/cache/ba1/87/ef/125ef62b6a947b52368ec67e39a8", + "assets/build/ba_data/audio/robotHit1.ogg": "https://files.ballistica.net/cache/ba1/e9/a6/2042ba33cf03380c2be0c464b451", + "assets/build/ba_data/audio/robotHit2.ogg": "https://files.ballistica.net/cache/ba1/87/ff/3e049fd5aa277bab20833d71ca1b", + "assets/build/ba_data/audio/runAwayMusic.ogg": "https://files.ballistica.net/cache/ba1/0f/9c/ffb9376c552c1e9321f8ace5684d", + "assets/build/ba_data/audio/santa01.ogg": "https://files.ballistica.net/cache/ba1/88/e8/2bb5080d864343e4325b945acb8a", + "assets/build/ba_data/audio/santa02.ogg": "https://files.ballistica.net/cache/ba1/22/95/8165d7ba91bd0e6e5ca20a02f8b9", + "assets/build/ba_data/audio/santa03.ogg": "https://files.ballistica.net/cache/ba1/61/87/751d68b9673d9a01a16acdda6530", + "assets/build/ba_data/audio/santa04.ogg": "https://files.ballistica.net/cache/ba1/1b/5d/069b4234850f4fa5279ba08b30f4", + "assets/build/ba_data/audio/santa05.ogg": "https://files.ballistica.net/cache/ba1/fc/13/ca7aa171b26b872c4979b1196e44", + "assets/build/ba_data/audio/santaDeath.ogg": "https://files.ballistica.net/cache/ba1/12/a8/c62ec7ff68e1086e8e9d98083c23", + "assets/build/ba_data/audio/santaFall.ogg": "https://files.ballistica.net/cache/ba1/c9/19/371e31518fa67d7c0e00812447cb", + "assets/build/ba_data/audio/santaHit01.ogg": "https://files.ballistica.net/cache/ba1/d3/6e/1f5bcf6c03f114e259c41c9eb743", + "assets/build/ba_data/audio/santaHit02.ogg": "https://files.ballistica.net/cache/ba1/af/96/22abcf4bda30edccd1179eec9e63", + "assets/build/ba_data/audio/santaHit03.ogg": "https://files.ballistica.net/cache/ba1/d9/b1/4f5c7b8fb34464e2e8c32e026ca2", + "assets/build/ba_data/audio/santaHit04.ogg": "https://files.ballistica.net/cache/ba1/c1/95/ef5e5c35e57e5cb0f2f925e186dd", + "assets/build/ba_data/audio/scamper01.ogg": "https://files.ballistica.net/cache/ba1/cc/92/c89583b9806a7c6d32e4f9705b5a", + "assets/build/ba_data/audio/scaryMusic.ogg": "https://files.ballistica.net/cache/ba1/31/6f/384814d96f0aa7427def1fcff94f", + "assets/build/ba_data/audio/score.ogg": "https://files.ballistica.net/cache/ba1/88/c5/5ac51203a41e5dd6e2b3fb9202f5", + "assets/build/ba_data/audio/scoreHit01.ogg": "https://files.ballistica.net/cache/ba1/15/d3/cc9ec8bbb43df7d336183422aefc", + "assets/build/ba_data/audio/scoreHit02.ogg": "https://files.ballistica.net/cache/ba1/d9/6f/cb9b4d3648fe22eb20b7dfb07bd0", + "assets/build/ba_data/audio/scoreIncrease.ogg": "https://files.ballistica.net/cache/ba1/ef/4c/e22b0550c8174e4f961ad6a67d6e", + "assets/build/ba_data/audio/scoresEpicMusic.ogg": "https://files.ballistica.net/cache/ba1/04/18/516dc125801bd5618e949f81f879", + "assets/build/ba_data/audio/shatter.ogg": "https://files.ballistica.net/cache/ba1/26/41/f31b1482be43ed741ba8bb5f272c", + "assets/build/ba_data/audio/shieldDown.ogg": "https://files.ballistica.net/cache/ba1/d3/65/3e68c0c133954c9ba2812c478fa6", + "assets/build/ba_data/audio/shieldHit.ogg": "https://files.ballistica.net/cache/ba1/65/a1/332b37975672fa99f0116ff1bc6a", + "assets/build/ba_data/audio/shieldUp.ogg": "https://files.ballistica.net/cache/ba1/c8/a8/95fc380d29531679d3437c525b30", + "assets/build/ba_data/audio/skid01.ogg": "https://files.ballistica.net/cache/ba1/49/c5/a3eeb40ba7a053390ec5ac6611f0", + "assets/build/ba_data/audio/slowEpicMusic.ogg": "https://files.ballistica.net/cache/ba1/7d/84/76439a001db40260f02a651a3e6f", + "assets/build/ba_data/audio/sparkle01.ogg": "https://files.ballistica.net/cache/ba1/01/9a/23b4168821fa1668b2a592d4b1f7", + "assets/build/ba_data/audio/sparkle02.ogg": "https://files.ballistica.net/cache/ba1/07/9d/212568d6811a70e226d0efa7c77b", + "assets/build/ba_data/audio/sparkle03.ogg": "https://files.ballistica.net/cache/ba1/13/bd/71e6370053fd29a9640ed257d69c", + "assets/build/ba_data/audio/spawn.ogg": "https://files.ballistica.net/cache/ba1/e6/53/24f8937260866f7d76dc69f0e2f8", + "assets/build/ba_data/audio/spazAttack01.ogg": "https://files.ballistica.net/cache/ba1/e1/58/4a0fcff78bc3520734fe00e39de9", + "assets/build/ba_data/audio/spazAttack02.ogg": "https://files.ballistica.net/cache/ba1/4f/78/35e098535b5a01849e63416d70b4", + "assets/build/ba_data/audio/spazAttack03.ogg": "https://files.ballistica.net/cache/ba1/cf/6b/8c5eeefe06b894cb3f0c48dfe69b", + "assets/build/ba_data/audio/spazAttack04.ogg": "https://files.ballistica.net/cache/ba1/4e/a3/037fe4e28eab8070c3a8b06ab9a1", + "assets/build/ba_data/audio/spazDeath01.ogg": "https://files.ballistica.net/cache/ba1/85/08/5c47833f78765f5bdbf3cb357254", + "assets/build/ba_data/audio/spazEff.ogg": "https://files.ballistica.net/cache/ba1/72/47/376dafbde4511352717c04147936", + "assets/build/ba_data/audio/spazFall01.ogg": "https://files.ballistica.net/cache/ba1/9f/f7/40bb58c2a4ba795a57405928a4cf", + "assets/build/ba_data/audio/spazImpact01.ogg": "https://files.ballistica.net/cache/ba1/cd/6c/2e975108effef9326d1247822c18", + "assets/build/ba_data/audio/spazImpact02.ogg": "https://files.ballistica.net/cache/ba1/f2/d6/85adf8a5e75e0e13393c0249b148", + "assets/build/ba_data/audio/spazImpact03.ogg": "https://files.ballistica.net/cache/ba1/3c/c9/2a99db6a0032952521739c585f1c", + "assets/build/ba_data/audio/spazImpact04.ogg": "https://files.ballistica.net/cache/ba1/5f/70/d4c12e5117b12849583b2cffc20a", + "assets/build/ba_data/audio/spazJump01.ogg": "https://files.ballistica.net/cache/ba1/b9/23/166fb2824454d35e3c6bc0b470b3", + "assets/build/ba_data/audio/spazJump02.ogg": "https://files.ballistica.net/cache/ba1/96/a8/ef4f3bdb51bb552159588defc8d0", + "assets/build/ba_data/audio/spazJump03.ogg": "https://files.ballistica.net/cache/ba1/ae/89/46203c5e859f71fe49c78690b2fc", + "assets/build/ba_data/audio/spazJump04.ogg": "https://files.ballistica.net/cache/ba1/3b/de/e741ee83f92b59f1e166228c02ee", + "assets/build/ba_data/audio/spazOw.ogg": "https://files.ballistica.net/cache/ba1/fa/c2/21281e31cf3917df0d8f83818232", + "assets/build/ba_data/audio/spazPickup01.ogg": "https://files.ballistica.net/cache/ba1/28/11/f8b8ae3a2c870a7e7a9f92adc1d5", + "assets/build/ba_data/audio/spazScream01.ogg": "https://files.ballistica.net/cache/ba1/46/b9/7ccb14316a01ed035e8adc5c7452", + "assets/build/ba_data/audio/splatter.ogg": "https://files.ballistica.net/cache/ba1/2b/e9/56abf68b429cd0860fee036fb29f", + "assets/build/ba_data/audio/sportsMusic.ogg": "https://files.ballistica.net/cache/ba1/5f/1e/042c93f291732af22fb91759f17f", + "assets/build/ba_data/audio/stickyImpact.ogg": "https://files.ballistica.net/cache/ba1/a5/7a/fb1c848bd8cd5aae6a3e66526930", + "assets/build/ba_data/audio/superPunch.ogg": "https://files.ballistica.net/cache/ba1/d5/df/0d0bc20b846f515da323f750e1f0", + "assets/build/ba_data/audio/superhero1.ogg": "https://files.ballistica.net/cache/ba1/71/ef/5e040cfe76a44671118d16941f3a", + "assets/build/ba_data/audio/superhero2.ogg": "https://files.ballistica.net/cache/ba1/b0/9b/c0a302c934001aa33ce1806d59d5", + "assets/build/ba_data/audio/superhero3.ogg": "https://files.ballistica.net/cache/ba1/75/a7/9d403b5a54226ad841fd21263b98", + "assets/build/ba_data/audio/superhero4.ogg": "https://files.ballistica.net/cache/ba1/d6/d8/99026aab119259a9c4cde6e63fec", + "assets/build/ba_data/audio/superheroDeath.ogg": "https://files.ballistica.net/cache/ba1/d4/20/cbb06970b6291afd90b263e6fa75", + "assets/build/ba_data/audio/superheroFall.ogg": "https://files.ballistica.net/cache/ba1/57/39/73d83f504896264996e5ca4d1129", + "assets/build/ba_data/audio/superheroHit1.ogg": "https://files.ballistica.net/cache/ba1/4b/85/132d71a1272cfa3eca34e59ca774", + "assets/build/ba_data/audio/superheroHit2.ogg": "https://files.ballistica.net/cache/ba1/e0/06/72d8a764622f92cbaef5316bb28c", + "assets/build/ba_data/audio/survivalMusic.ogg": "https://files.ballistica.net/cache/ba1/b0/de/b043bace73760c87ead5454984fa", + "assets/build/ba_data/audio/swip.ogg": "https://files.ballistica.net/cache/ba1/44/bb/d9db0c555d53e9e2495c218d260a", + "assets/build/ba_data/audio/swip2.ogg": "https://files.ballistica.net/cache/ba1/d7/8f/1ae8e37f64849ff73e4ebca6587f", + "assets/build/ba_data/audio/swish.ogg": "https://files.ballistica.net/cache/ba1/3e/14/cf0c31e0b593e57a981cf6605f45", + "assets/build/ba_data/audio/swish2.ogg": "https://files.ballistica.net/cache/ba1/07/0c/f58b33989b7baacefd4b4bbad585", + "assets/build/ba_data/audio/swish3.ogg": "https://files.ballistica.net/cache/ba1/d6/43/3425e23550cc14b025571d4a74be", + "assets/build/ba_data/audio/tap.ogg": "https://files.ballistica.net/cache/ba1/3a/ee/c44f4e4b602e905b7f66edccf487", + "assets/build/ba_data/audio/technoHit01.ogg": "https://files.ballistica.net/cache/ba1/38/fc/c325606d4c41f48abdad10a2b025", + "assets/build/ba_data/audio/tick.ogg": "https://files.ballistica.net/cache/ba1/02/73/29e04d7fd39d19d165178456c59b", + "assets/build/ba_data/audio/ticking.ogg": "https://files.ballistica.net/cache/ba1/1a/af/565837e17cb0dfd723dcd234119a", + "assets/build/ba_data/audio/tickingCrazy.ogg": "https://files.ballistica.net/cache/ba1/8b/24/ffca3762c9cc33b335d585ddb0c4", + "assets/build/ba_data/audio/toTheDeathMusic.ogg": "https://files.ballistica.net/cache/ba1/e4/44/72db636219ed3e68f2f85b8851c8", + "assets/build/ba_data/audio/trashRummage.ogg": "https://files.ballistica.net/cache/ba1/ef/5b/ee78e77ca4b9ffe8660b25b0529d", + "assets/build/ba_data/audio/victoryMusic.ogg": "https://files.ballistica.net/cache/ba1/8a/8e/30c4f4ae561780aab11493d03ea5", + "assets/build/ba_data/audio/warnBeep.ogg": "https://files.ballistica.net/cache/ba1/f5/9a/896ee7a6ff7cd33ed864bd286e31", + "assets/build/ba_data/audio/warnBeeps.ogg": "https://files.ballistica.net/cache/ba1/d5/a2/63701e0d2ebbd7045847b9371e92", + "assets/build/ba_data/audio/warrior1.ogg": "https://files.ballistica.net/cache/ba1/54/7c/03a344b8541636e222433622155a", + "assets/build/ba_data/audio/warrior2.ogg": "https://files.ballistica.net/cache/ba1/3b/84/29da2f2ec34870dfb2b68bfbc85f", + "assets/build/ba_data/audio/warrior3.ogg": "https://files.ballistica.net/cache/ba1/e1/e8/9945decc1196e37a6fd34a1ebc82", + "assets/build/ba_data/audio/warrior4.ogg": "https://files.ballistica.net/cache/ba1/36/03/0bee6810d5d5a047fccba9e3ef75", + "assets/build/ba_data/audio/warriorDeath.ogg": "https://files.ballistica.net/cache/ba1/bf/ec/16b6f71e633fb7e27ea2d359e01d", + "assets/build/ba_data/audio/warriorFall.ogg": "https://files.ballistica.net/cache/ba1/14/75/4ee34865e88282397d3d043ed869", + "assets/build/ba_data/audio/warriorHit1.ogg": "https://files.ballistica.net/cache/ba1/24/45/60f9daf5323189d0f6ec0db5af00", + "assets/build/ba_data/audio/warriorHit2.ogg": "https://files.ballistica.net/cache/ba1/36/81/51d9c84a8299d405e5603339b4d2", + "assets/build/ba_data/audio/whenJohnnyComesMarchingHomeMusic.ogg": "https://files.ballistica.net/cache/ba1/d7/c1/4a1c20c6d7eac01b49d35f06bebd", + "assets/build/ba_data/audio/witch1.ogg": "https://files.ballistica.net/cache/ba1/b6/77/c3183deb4118d4d9dbe6fd6148b5", + "assets/build/ba_data/audio/witch2.ogg": "https://files.ballistica.net/cache/ba1/82/90/2a14efb1af7172ac92de75f7d14a", + "assets/build/ba_data/audio/witch3.ogg": "https://files.ballistica.net/cache/ba1/b6/ee/aa47bcf141ebc584e1747cbfc0ef", + "assets/build/ba_data/audio/witch4.ogg": "https://files.ballistica.net/cache/ba1/54/44/3fe7c0655296998c3e58d7f8a6c0", + "assets/build/ba_data/audio/witchDeath.ogg": "https://files.ballistica.net/cache/ba1/90/04/7869e49bdf84f82146c0df2a6988", + "assets/build/ba_data/audio/witchFall.ogg": "https://files.ballistica.net/cache/ba1/d7/27/87ce01a8f9d7e0171315412c9e12", + "assets/build/ba_data/audio/witchHit1.ogg": "https://files.ballistica.net/cache/ba1/63/98/6b5eae87548288f4813af43bf466", + "assets/build/ba_data/audio/witchHit2.ogg": "https://files.ballistica.net/cache/ba1/d1/3a/00b1cada3409c087256a085ebd82", + "assets/build/ba_data/audio/wizard1.ogg": "https://files.ballistica.net/cache/ba1/49/96/51d50903e69d73b0ae3a2ca0d62a", + "assets/build/ba_data/audio/wizard2.ogg": "https://files.ballistica.net/cache/ba1/2d/61/67667c74d7f8def3c4bfcef6c4cc", + "assets/build/ba_data/audio/wizard3.ogg": "https://files.ballistica.net/cache/ba1/4d/25/406e9569f506bf0b43c4df91e2d6", + "assets/build/ba_data/audio/wizard4.ogg": "https://files.ballistica.net/cache/ba1/41/c7/f501ec6569fab8ffc7ae7b5f77ef", + "assets/build/ba_data/audio/wizardDeath.ogg": "https://files.ballistica.net/cache/ba1/87/18/15be59d3732b3880c7fd3131f101", + "assets/build/ba_data/audio/wizardFall.ogg": "https://files.ballistica.net/cache/ba1/60/93/fb55f121e50489ded9f101c5715b", + "assets/build/ba_data/audio/wizardHit1.ogg": "https://files.ballistica.net/cache/ba1/25/99/abcdd530160b3058f120d956d3cc", + "assets/build/ba_data/audio/wizardHit2.ogg": "https://files.ballistica.net/cache/ba1/62/6a/1c38de7135e9858308dccf11aa54", + "assets/build/ba_data/audio/woodDebrisFall.ogg": "https://files.ballistica.net/cache/ba1/55/29/e97fa21a97c9ea723e3014c700f1", + "assets/build/ba_data/audio/wrestler1.ogg": "https://files.ballistica.net/cache/ba1/71/5e/221be8a8aaf1f10bb14a24737527", + "assets/build/ba_data/audio/wrestler2.ogg": "https://files.ballistica.net/cache/ba1/b6/a2/47acd1ccb7e607182c95a463c7b8", + "assets/build/ba_data/audio/wrestler3.ogg": "https://files.ballistica.net/cache/ba1/1e/33/00026eb8409f8f3a443e1bf30df9", + "assets/build/ba_data/audio/wrestler4.ogg": "https://files.ballistica.net/cache/ba1/24/e5/75bce1ed9d5b2a32016c29c9a735", + "assets/build/ba_data/audio/wrestlerDeath.ogg": "https://files.ballistica.net/cache/ba1/52/b5/cdde9dff2ffb0542bf5e62753826", + "assets/build/ba_data/audio/wrestlerFall.ogg": "https://files.ballistica.net/cache/ba1/56/23/7429b2127cd2d86a1f94bb0aea01", + "assets/build/ba_data/audio/wrestlerHit1.ogg": "https://files.ballistica.net/cache/ba1/8e/de/b0afeef3ba23961dac5a030236bb", + "assets/build/ba_data/audio/wrestlerHit2.ogg": "https://files.ballistica.net/cache/ba1/c8/3f/9541179e2df4b78e8017e8fe8d7e", + "assets/build/ba_data/audio/zoeAttack01.ogg": "https://files.ballistica.net/cache/ba1/e7/36/3aa67d0e53292be79bc6f8dd0bd6", + "assets/build/ba_data/audio/zoeAttack02.ogg": "https://files.ballistica.net/cache/ba1/43/ca/407e582c059b345d80d62d452538", + "assets/build/ba_data/audio/zoeAttack03.ogg": "https://files.ballistica.net/cache/ba1/44/75/4de7a8ea92401dd7763f81abc78e", + "assets/build/ba_data/audio/zoeAttack04.ogg": "https://files.ballistica.net/cache/ba1/d7/d5/c26da55d6d8613c22439c78aa59b", + "assets/build/ba_data/audio/zoeDeath01.ogg": "https://files.ballistica.net/cache/ba1/91/05/4476cf27b69ffcbe79dd928a1abc", + "assets/build/ba_data/audio/zoeEff.ogg": "https://files.ballistica.net/cache/ba1/c3/0e/8d7eebc3d085aad6762d17f1a026", + "assets/build/ba_data/audio/zoeFall01.ogg": "https://files.ballistica.net/cache/ba1/30/44/f48f2c8f49221b75e59395cd6fda", + "assets/build/ba_data/audio/zoeImpact01.ogg": "https://files.ballistica.net/cache/ba1/9b/18/dfb859feccfbb1f5fca8699b0ab3", + "assets/build/ba_data/audio/zoeImpact02.ogg": "https://files.ballistica.net/cache/ba1/24/ad/cdff8ff7921e0898b54524baae27", + "assets/build/ba_data/audio/zoeImpact03.ogg": "https://files.ballistica.net/cache/ba1/e5/a6/2b55218323f29708e0dcdfe21deb", + "assets/build/ba_data/audio/zoeImpact04.ogg": "https://files.ballistica.net/cache/ba1/47/e7/7144ed60fa226672534780f39fd3", + "assets/build/ba_data/audio/zoeJump01.ogg": "https://files.ballistica.net/cache/ba1/0e/15/41a4e8172b90682428e3ca333218", + "assets/build/ba_data/audio/zoeJump02.ogg": "https://files.ballistica.net/cache/ba1/00/87/f34e160ba454d6ab13c731f3127b", + "assets/build/ba_data/audio/zoeJump03.ogg": "https://files.ballistica.net/cache/ba1/67/02/ab19c921862c9178e3ef4b5bb067", + "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", + "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", + "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/cd/7a/dcf7f0f9436884167abdcb126716", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a9/3c/63857b3f5f943205d7a5d8f8e476", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", @@ -3475,129 +3475,129 @@ "assets/build/windows/Win32/DLLs/unicodedata_d.pyd": "https://files.ballistica.net/cache/ba1/fe/20/1d7bde0812563ab4b585e03a698a", "assets/build/windows/Win32/DLLs/winsound.pyd": "https://files.ballistica.net/cache/ba1/50/ea/951f98c6f187f25757dae10b8337", "assets/build/windows/Win32/DLLs/winsound_d.pyd": "https://files.ballistica.net/cache/ba1/28/13/8857b36063d66e952434a3973853", - "assets/build/windows/Win32/Lib/__future__.py": "https://files.ballistica.net/cache/ba1/2e/cb/a6159f9f7d7c895efcf2c6620ece", + "assets/build/windows/Win32/Lib/__future__.py": "https://files.ballistica.net/cache/ba1/3d/b8/861d93720bc3cbcfaaae4b83b244", "assets/build/windows/Win32/Lib/__phello__.foo.py": "https://files.ballistica.net/cache/ba1/3b/8b/939d78ee0764fdf52f3098127d6c", "assets/build/windows/Win32/Lib/_bootlocale.py": "https://files.ballistica.net/cache/ba1/09/0e/9293a47b0ed243fc7482ab56b330", - "assets/build/windows/Win32/Lib/_collections_abc.py": "https://files.ballistica.net/cache/ba1/50/4a/8d27b1c1b0b8556b075f86e9467e", + "assets/build/windows/Win32/Lib/_collections_abc.py": "https://files.ballistica.net/cache/ba1/00/3b/57aa68a37cfe29103b6c1f23d59b", "assets/build/windows/Win32/Lib/_compat_pickle.py": "https://files.ballistica.net/cache/ba1/46/06/1015248f3c4416edb60e7830aecb", "assets/build/windows/Win32/Lib/_compression.py": "https://files.ballistica.net/cache/ba1/db/90/20ab62fe1558d9ec656e5ed43d0f", "assets/build/windows/Win32/Lib/_dummy_thread.py": "https://files.ballistica.net/cache/ba1/41/7b/e6e2723be021e2c4a5ca9de01ea5", "assets/build/windows/Win32/Lib/_markupbase.py": "https://files.ballistica.net/cache/ba1/0b/b4/b2b374394442d3ceac5659174306", - "assets/build/windows/Win32/Lib/_osx_support.py": "https://files.ballistica.net/cache/ba1/e6/e0/856d31ed5bfa2669f8ec45aca20d", - "assets/build/windows/Win32/Lib/_py_abc.py": "https://files.ballistica.net/cache/ba1/9c/7d/305e09e987f9efdf1048f34e4313", - "assets/build/windows/Win32/Lib/_pydecimal.py": "https://files.ballistica.net/cache/ba1/6d/f3/5c7034a9fa84d1f0a67a27603be1", - "assets/build/windows/Win32/Lib/_pyio.py": "https://files.ballistica.net/cache/ba1/09/94/e9b179e5720f64bf5c75ac1964e8", + "assets/build/windows/Win32/Lib/_osx_support.py": "https://files.ballistica.net/cache/ba1/08/7d/966879d8875ca07403db2f0ccb6b", + "assets/build/windows/Win32/Lib/_py_abc.py": "https://files.ballistica.net/cache/ba1/ad/d8/684169061fcf843ea3541d4a27a6", + "assets/build/windows/Win32/Lib/_pydecimal.py": "https://files.ballistica.net/cache/ba1/1d/27/479bf918f1c1d21e41a793adfcf1", + "assets/build/windows/Win32/Lib/_pyio.py": "https://files.ballistica.net/cache/ba1/ad/1d/2c6c4bb1acb9184f47a50df117f1", "assets/build/windows/Win32/Lib/_sitebuiltins.py": "https://files.ballistica.net/cache/ba1/f9/0d/fb8aa34c3c72f100ea0de27b6891", - "assets/build/windows/Win32/Lib/_strptime.py": "https://files.ballistica.net/cache/ba1/81/bd/b94083af169c69202421de573ef0", - "assets/build/windows/Win32/Lib/_threading_local.py": "https://files.ballistica.net/cache/ba1/a2/1b/a9e3518a7c011ddb443a5f2b95b9", - "assets/build/windows/Win32/Lib/_weakrefset.py": "https://files.ballistica.net/cache/ba1/aa/d8/d7cf0531211ae5a2a7578162045e", - "assets/build/windows/Win32/Lib/abc.py": "https://files.ballistica.net/cache/ba1/7f/a7/ea2b02ced37d0e4b3758fbd8766b", + "assets/build/windows/Win32/Lib/_strptime.py": "https://files.ballistica.net/cache/ba1/bb/b0/9a4289fffa3a74dd5fdab6128bf0", + "assets/build/windows/Win32/Lib/_threading_local.py": "https://files.ballistica.net/cache/ba1/6c/8a/9ac70e582f8ec4da33694a8a2409", + "assets/build/windows/Win32/Lib/_weakrefset.py": "https://files.ballistica.net/cache/ba1/d3/e3/ff1d4002e752d1410a3167c00642", + "assets/build/windows/Win32/Lib/abc.py": "https://files.ballistica.net/cache/ba1/c1/db/33e9537d855bd8c0e34660099463", "assets/build/windows/Win32/Lib/aifc.py": "https://files.ballistica.net/cache/ba1/f0/05/54f64f43dd8a1269b42495106a8b", "assets/build/windows/Win32/Lib/antigravity.py": "https://files.ballistica.net/cache/ba1/fe/66/fc51a4ead5b55dbf09bad7dee9cf", - "assets/build/windows/Win32/Lib/argparse.py": "https://files.ballistica.net/cache/ba1/cf/e4/e717b919d9f23949ae1c67fc8990", - "assets/build/windows/Win32/Lib/ast.py": "https://files.ballistica.net/cache/ba1/0b/6a/723bc070d337fbd76364cf865693", + "assets/build/windows/Win32/Lib/argparse.py": "https://files.ballistica.net/cache/ba1/46/34/8dc5b7f13686ed4f3f996effeca1", + "assets/build/windows/Win32/Lib/ast.py": "https://files.ballistica.net/cache/ba1/86/d1/93d66a0c3eca891bcba343c6ed71", "assets/build/windows/Win32/Lib/asynchat.py": "https://files.ballistica.net/cache/ba1/6d/8d/403f343399d118de9e3c42bf15ae", - "assets/build/windows/Win32/Lib/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/9f/8a/035dd21bdf2203871dd85f309d75", + "assets/build/windows/Win32/Lib/asyncio/__init__.py": "https://files.ballistica.net/cache/ba1/23/99/3a675e89dbd967a1ae1f9b58df2b", "assets/build/windows/Win32/Lib/asyncio/__main__.py": "https://files.ballistica.net/cache/ba1/fb/f0/a4fad40aea4845a907af269fa159", - "assets/build/windows/Win32/Lib/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/a7/c0/241f7864be2fc6a923553d5c902b", - "assets/build/windows/Win32/Lib/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/8a/d0/1ce3ff1f5f8426b036aa9b327d5b", - "assets/build/windows/Win32/Lib/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/6f/86/58e45d69507c0969fd57e77d8248", - "assets/build/windows/Win32/Lib/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/56/07/d89a76bfe000279932381f78b5bf", + "assets/build/windows/Win32/Lib/asyncio/base_events.py": "https://files.ballistica.net/cache/ba1/8d/61/9aabcbec5e16b10b60d9816bf168", + "assets/build/windows/Win32/Lib/asyncio/base_futures.py": "https://files.ballistica.net/cache/ba1/11/55/a6611b2c4f69b7aec0256fac7c04", + "assets/build/windows/Win32/Lib/asyncio/base_subprocess.py": "https://files.ballistica.net/cache/ba1/0e/c0/3384fbba49486643e507a49770ee", + "assets/build/windows/Win32/Lib/asyncio/base_tasks.py": "https://files.ballistica.net/cache/ba1/28/9d/b3adf943122909eb73dd216ef179", "assets/build/windows/Win32/Lib/asyncio/constants.py": "https://files.ballistica.net/cache/ba1/28/3e/49ec61050acc59c2bb5761d5332e", - "assets/build/windows/Win32/Lib/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/ab/a1/bc99786756b3bf8d594bdd0464a0", - "assets/build/windows/Win32/Lib/asyncio/events.py": "https://files.ballistica.net/cache/ba1/ee/e7/d736c75249b38b0538dfda5f3b83", + "assets/build/windows/Win32/Lib/asyncio/coroutines.py": "https://files.ballistica.net/cache/ba1/22/0f/65ce7b4328dbdf3a300616755b5f", + "assets/build/windows/Win32/Lib/asyncio/events.py": "https://files.ballistica.net/cache/ba1/b1/05/2e1dd073cc595bcc07f6eb4a42dc", "assets/build/windows/Win32/Lib/asyncio/exceptions.py": "https://files.ballistica.net/cache/ba1/00/70/1a9e71b51410e1d7a674201c5956", "assets/build/windows/Win32/Lib/asyncio/format_helpers.py": "https://files.ballistica.net/cache/ba1/40/98/952c80350fd35c81680c0d565aa1", - "assets/build/windows/Win32/Lib/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/fb/cc/0ce896defcfde6d026fc80038141", - "assets/build/windows/Win32/Lib/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/31/a6/b1ccfb0809f3815d0131a184f555", + "assets/build/windows/Win32/Lib/asyncio/futures.py": "https://files.ballistica.net/cache/ba1/9f/f7/f1b103c12bfec7aff8fc17d2b730", + "assets/build/windows/Win32/Lib/asyncio/locks.py": "https://files.ballistica.net/cache/ba1/10/f8/b21927b7d94ce1db0643d50ef4a2", "assets/build/windows/Win32/Lib/asyncio/log.py": "https://files.ballistica.net/cache/ba1/d6/d3/380f88b21d3b8ef14f758f283af0", - "assets/build/windows/Win32/Lib/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/09/63/72457348d02a8ed2ef06dd60b7d8", - "assets/build/windows/Win32/Lib/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/d7/af/899719170681a771fdee0b8b0e9f", - "assets/build/windows/Win32/Lib/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/f1/81/41501b6b63db432d8e492cfeae5f", - "assets/build/windows/Win32/Lib/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/b2/15/ef01670e10a144f916023f32a933", - "assets/build/windows/Win32/Lib/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/db/94/b7ce0fbe94e33ced7868378a3810", - "assets/build/windows/Win32/Lib/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/75/52/47f6f534d8f0bff38934a1e9d0ce", + "assets/build/windows/Win32/Lib/asyncio/proactor_events.py": "https://files.ballistica.net/cache/ba1/c5/f7/4442452b93b5c09747219e6a2713", + "assets/build/windows/Win32/Lib/asyncio/protocols.py": "https://files.ballistica.net/cache/ba1/95/49/8df484a9d8a0fb3259f90ef5c96c", + "assets/build/windows/Win32/Lib/asyncio/queues.py": "https://files.ballistica.net/cache/ba1/61/ba/dbf2d71075f7a5bc7633261c9c3b", + "assets/build/windows/Win32/Lib/asyncio/runners.py": "https://files.ballistica.net/cache/ba1/7b/41/4f6c78ebc75f4ed41d97d9289554", + "assets/build/windows/Win32/Lib/asyncio/selector_events.py": "https://files.ballistica.net/cache/ba1/18/2a/70a2893571a2af3092fef753b57f", + "assets/build/windows/Win32/Lib/asyncio/sslproto.py": "https://files.ballistica.net/cache/ba1/47/7a/942926b07057203c2e7288f59815", "assets/build/windows/Win32/Lib/asyncio/staggered.py": "https://files.ballistica.net/cache/ba1/9f/52/01396863292b0b31dfbc92c03907", - "assets/build/windows/Win32/Lib/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/9f/79/e707dbf54c712cbeb6930134a805", - "assets/build/windows/Win32/Lib/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/5f/c3/1dcb82253f0e7fba1ccb0659851f", - "assets/build/windows/Win32/Lib/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/2f/24/2f1558585ddff3b619bbfe6a8ae3", - "assets/build/windows/Win32/Lib/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/79/71/a95c9ea4cd4b7a1c25bd916d251c", + "assets/build/windows/Win32/Lib/asyncio/streams.py": "https://files.ballistica.net/cache/ba1/23/a6/917ae117a4057839242a360c1fd5", + "assets/build/windows/Win32/Lib/asyncio/subprocess.py": "https://files.ballistica.net/cache/ba1/7d/47/eeed1a313027e5ee77acfaa0dc0a", + "assets/build/windows/Win32/Lib/asyncio/tasks.py": "https://files.ballistica.net/cache/ba1/ce/d2/5a2220b412f1942e7580bbf942de", + "assets/build/windows/Win32/Lib/asyncio/transports.py": "https://files.ballistica.net/cache/ba1/c4/85/42d04f243299aeb34e7df9aca184", "assets/build/windows/Win32/Lib/asyncio/trsock.py": "https://files.ballistica.net/cache/ba1/46/88/ab7c4a2f09e5a3b9f675d5f89b2e", - "assets/build/windows/Win32/Lib/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/48/74/f1a74c42563a46dd6368b426d252", - "assets/build/windows/Win32/Lib/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/4b/4d/1867fd29a770f95265821bdbe690", - "assets/build/windows/Win32/Lib/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/2e/12/253a4c70468ff978daee580c6de2", - "assets/build/windows/Win32/Lib/asyncore.py": "https://files.ballistica.net/cache/ba1/44/dc/aa53adeb954a3b75c96936d2075b", - "assets/build/windows/Win32/Lib/base64.py": "https://files.ballistica.net/cache/ba1/20/47/38248b035f4fac397979328ea7e3", - "assets/build/windows/Win32/Lib/bdb.py": "https://files.ballistica.net/cache/ba1/6e/c1/609478e1331276950f4c489ac963", + "assets/build/windows/Win32/Lib/asyncio/unix_events.py": "https://files.ballistica.net/cache/ba1/7d/a1/000d2bec4813db2295c888991800", + "assets/build/windows/Win32/Lib/asyncio/windows_events.py": "https://files.ballistica.net/cache/ba1/e2/32/e5093d00d060bf24a02335ba6d36", + "assets/build/windows/Win32/Lib/asyncio/windows_utils.py": "https://files.ballistica.net/cache/ba1/bd/ed/ddb1d357625e17352ed9928cb9e5", + "assets/build/windows/Win32/Lib/asyncore.py": "https://files.ballistica.net/cache/ba1/7c/9e/3da840852d4b2389cb7c286d016b", + "assets/build/windows/Win32/Lib/base64.py": "https://files.ballistica.net/cache/ba1/d2/54/a6f18991ae74f56b4779e881a199", + "assets/build/windows/Win32/Lib/bdb.py": "https://files.ballistica.net/cache/ba1/f1/db/04f5a5f69b53227b2cea2a9ed417", "assets/build/windows/Win32/Lib/binhex.py": "https://files.ballistica.net/cache/ba1/ff/de/25906a6ac05fb00f147442afb165", - "assets/build/windows/Win32/Lib/bisect.py": "https://files.ballistica.net/cache/ba1/aa/48/5dc566d252de1c32107c20f384dd", - "assets/build/windows/Win32/Lib/bz2.py": "https://files.ballistica.net/cache/ba1/84/ba/6926aad97895ebfd38184a85ad4f", - "assets/build/windows/Win32/Lib/cProfile.py": "https://files.ballistica.net/cache/ba1/76/50/2800f118a2fb8fb63e43d6e8af73", - "assets/build/windows/Win32/Lib/calendar.py": "https://files.ballistica.net/cache/ba1/c2/58/fa09e1ac00b0427f13d4923998e6", - "assets/build/windows/Win32/Lib/cgi.py": "https://files.ballistica.net/cache/ba1/b0/20/a3b7e2382c7ddde4638dec0f8183", - "assets/build/windows/Win32/Lib/cgitb.py": "https://files.ballistica.net/cache/ba1/ca/c4/1be248ca37283a283419ec8c5128", + "assets/build/windows/Win32/Lib/bisect.py": "https://files.ballistica.net/cache/ba1/ab/40/e561035a5c9d84d0346e2a1b4ba1", + "assets/build/windows/Win32/Lib/bz2.py": "https://files.ballistica.net/cache/ba1/61/15/adef78493f0e2509db7590ea293c", + "assets/build/windows/Win32/Lib/cProfile.py": "https://files.ballistica.net/cache/ba1/56/8e/02e250e073deb65c6c6d0c81fb4f", + "assets/build/windows/Win32/Lib/calendar.py": "https://files.ballistica.net/cache/ba1/19/df/5fcc786979f9697a113d8ba9363f", + "assets/build/windows/Win32/Lib/cgi.py": "https://files.ballistica.net/cache/ba1/13/3b/49301cdd99d04c2cb027dc8bf954", + "assets/build/windows/Win32/Lib/cgitb.py": "https://files.ballistica.net/cache/ba1/77/44/358b17a4fc4b06db2d69d51bb1ff", "assets/build/windows/Win32/Lib/chunk.py": "https://files.ballistica.net/cache/ba1/16/08/2708ae495aab5e54fe27da06f633", "assets/build/windows/Win32/Lib/cmd.py": "https://files.ballistica.net/cache/ba1/cc/83/f3046ec22ee06c45649da6add0c7", - "assets/build/windows/Win32/Lib/code.py": "https://files.ballistica.net/cache/ba1/9e/c8/709a57c45e0fd884680f4c38d821", - "assets/build/windows/Win32/Lib/codecs.py": "https://files.ballistica.net/cache/ba1/2e/94/1c5c72dc0cc2968c10ab5d992d6a", - "assets/build/windows/Win32/Lib/codeop.py": "https://files.ballistica.net/cache/ba1/74/3f/c87d2f4f8ba045663ae87bcc088c", - "assets/build/windows/Win32/Lib/collections/__init__.py": "https://files.ballistica.net/cache/ba1/5b/4e/84c23eee138635a9aed31de38b42", + "assets/build/windows/Win32/Lib/code.py": "https://files.ballistica.net/cache/ba1/61/31/f1ff9d938a5f29efe83838362b52", + "assets/build/windows/Win32/Lib/codecs.py": "https://files.ballistica.net/cache/ba1/1f/64/412ff1b173e741fec018e4013213", + "assets/build/windows/Win32/Lib/codeop.py": "https://files.ballistica.net/cache/ba1/07/8a/5015a1453f0645dd58f5befa8fbc", + "assets/build/windows/Win32/Lib/collections/__init__.py": "https://files.ballistica.net/cache/ba1/89/aa/c75b4a114fb7caf9554f7e0030ea", "assets/build/windows/Win32/Lib/collections/abc.py": "https://files.ballistica.net/cache/ba1/ee/9e/1b14e35345f9208b897b8db40100", "assets/build/windows/Win32/Lib/colorsys.py": "https://files.ballistica.net/cache/ba1/e8/1f/297a0b5e14be06d3f3f554c9725e", - "assets/build/windows/Win32/Lib/compileall.py": "https://files.ballistica.net/cache/ba1/1b/ac/04b84c5eb26e874e884f3bc6bc1b", + "assets/build/windows/Win32/Lib/compileall.py": "https://files.ballistica.net/cache/ba1/60/d6/1d1435455b13730345ed85a54cd3", "assets/build/windows/Win32/Lib/concurrent/__init__.py": "https://files.ballistica.net/cache/ba1/5b/ec/08df2761a442b8ff6fe7d52fcc89", - "assets/build/windows/Win32/Lib/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/4e/19/4b53a12344e38c97b850810ce096", - "assets/build/windows/Win32/Lib/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/72/be/a07d687c1e04ab6451af0d2f945a", - "assets/build/windows/Win32/Lib/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/b1/90/810fe62b37fb06f366aabb785a24", - "assets/build/windows/Win32/Lib/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/f2/63/f484bbdc6c4e7880980b14a664b1", - "assets/build/windows/Win32/Lib/configparser.py": "https://files.ballistica.net/cache/ba1/33/1c/b64584b4e411f9709b913aaa74a0", - "assets/build/windows/Win32/Lib/contextlib.py": "https://files.ballistica.net/cache/ba1/fc/88/4c49645703136b7b60060937132d", + "assets/build/windows/Win32/Lib/concurrent/futures/__init__.py": "https://files.ballistica.net/cache/ba1/c7/46/341d04b8d611753ebc06780081ea", + "assets/build/windows/Win32/Lib/concurrent/futures/_base.py": "https://files.ballistica.net/cache/ba1/85/fc/0d7d7cca61f766b4409d6fbe513f", + "assets/build/windows/Win32/Lib/concurrent/futures/process.py": "https://files.ballistica.net/cache/ba1/7b/d9/5cb645d05a0bfa6fc3c023c09884", + "assets/build/windows/Win32/Lib/concurrent/futures/thread.py": "https://files.ballistica.net/cache/ba1/ce/6c/1e79d68a25a3f0e69cf3433264cd", + "assets/build/windows/Win32/Lib/configparser.py": "https://files.ballistica.net/cache/ba1/d9/cf/771c2ae14dd33a948e16a784a48f", + "assets/build/windows/Win32/Lib/contextlib.py": "https://files.ballistica.net/cache/ba1/0a/d0/ee6f3432112f85ec1efd7253e728", "assets/build/windows/Win32/Lib/contextvars.py": "https://files.ballistica.net/cache/ba1/97/a6/19610cddd01bb44cc6f9d3a21293", - "assets/build/windows/Win32/Lib/copy.py": "https://files.ballistica.net/cache/ba1/1a/bf/cf033225a41642c04ddfd0c88e1d", - "assets/build/windows/Win32/Lib/copyreg.py": "https://files.ballistica.net/cache/ba1/ea/da/ddf7bbefcecb86e240a68ec88543", - "assets/build/windows/Win32/Lib/crypt.py": "https://files.ballistica.net/cache/ba1/dc/72/7588bb74cb6b52d873332ce2213e", - "assets/build/windows/Win32/Lib/csv.py": "https://files.ballistica.net/cache/ba1/f6/0a/09d03e5dcdab8b818812f838158b", - "assets/build/windows/Win32/Lib/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/a2/6e/832983b9f60eae5dd7744bba8bd2", + "assets/build/windows/Win32/Lib/copy.py": "https://files.ballistica.net/cache/ba1/28/95/d923a86e884501194d65f2646de8", + "assets/build/windows/Win32/Lib/copyreg.py": "https://files.ballistica.net/cache/ba1/98/b3/d832dad3f6c073d6efcb14da53ce", + "assets/build/windows/Win32/Lib/crypt.py": "https://files.ballistica.net/cache/ba1/ae/cc/e39c20e40e3388095e186b6aa3b9", + "assets/build/windows/Win32/Lib/csv.py": "https://files.ballistica.net/cache/ba1/61/84/ece8a5a1edd77dfd481a0029bcc8", + "assets/build/windows/Win32/Lib/ctypes/__init__.py": "https://files.ballistica.net/cache/ba1/b5/3d/9e5225131d6b60d12eda1f11e058", "assets/build/windows/Win32/Lib/ctypes/_aix.py": "https://files.ballistica.net/cache/ba1/30/2d/3ad91a485f58eb3690c863e7a961", "assets/build/windows/Win32/Lib/ctypes/_endian.py": "https://files.ballistica.net/cache/ba1/04/c7/1775ac390854c9015be8e834ff50", "assets/build/windows/Win32/Lib/ctypes/macholib/README.ctypes": "https://files.ballistica.net/cache/ba1/90/bf/d7c620c1dec8a9219b27e1cfa6f4", "assets/build/windows/Win32/Lib/ctypes/macholib/__init__.py": "https://files.ballistica.net/cache/ba1/a7/68/4d72c2a8db47c671575650daa0e6", - "assets/build/windows/Win32/Lib/ctypes/macholib/dyld.py": "https://files.ballistica.net/cache/ba1/ab/b8/fd08898e1ed54c9f472815946294", + "assets/build/windows/Win32/Lib/ctypes/macholib/dyld.py": "https://files.ballistica.net/cache/ba1/cc/29/9eb47bbb4519ff41fd593917a78b", "assets/build/windows/Win32/Lib/ctypes/macholib/dylib.py": "https://files.ballistica.net/cache/ba1/c2/c2/547efc609d150143701b892bc5ae", "assets/build/windows/Win32/Lib/ctypes/macholib/fetch_macholib": "https://files.ballistica.net/cache/ba1/4d/fb/26d07e6522338f7fc233734f8807", "assets/build/windows/Win32/Lib/ctypes/macholib/fetch_macholib.bat": "https://files.ballistica.net/cache/ba1/ab/58/c056f07d65b7abf4ac2fc3598947", "assets/build/windows/Win32/Lib/ctypes/macholib/framework.py": "https://files.ballistica.net/cache/ba1/fb/23/90116831cb2f6d105bc3cd65559c", "assets/build/windows/Win32/Lib/ctypes/util.py": "https://files.ballistica.net/cache/ba1/c9/92/b71e0b1afdffde4b91ce0ad71cc8", "assets/build/windows/Win32/Lib/ctypes/wintypes.py": "https://files.ballistica.net/cache/ba1/25/1d/9a7dfb9d5c76744c30ffcde3b6eb", - "assets/build/windows/Win32/Lib/curses/__init__.py": "https://files.ballistica.net/cache/ba1/fd/0d/5b8dedef05db92edb03fd74fa9ea", + "assets/build/windows/Win32/Lib/curses/__init__.py": "https://files.ballistica.net/cache/ba1/d4/7a/94f01cec089c4c7b3a058954d1a0", "assets/build/windows/Win32/Lib/curses/ascii.py": "https://files.ballistica.net/cache/ba1/fd/14/86316d73c170437831841f44f410", "assets/build/windows/Win32/Lib/curses/has_key.py": "https://files.ballistica.net/cache/ba1/39/59/8a09c722d5a9c762fe51d6bf827a", "assets/build/windows/Win32/Lib/curses/panel.py": "https://files.ballistica.net/cache/ba1/48/9c/133d9a244f62e3739cb392d1a096", "assets/build/windows/Win32/Lib/curses/textpad.py": "https://files.ballistica.net/cache/ba1/ea/c0/e047229f762662427d6c64dd3c61", - "assets/build/windows/Win32/Lib/dataclasses.py": "https://files.ballistica.net/cache/ba1/e4/e4/f953de6ad9b40bfe3bbfc447745e", - "assets/build/windows/Win32/Lib/datetime.py": "https://files.ballistica.net/cache/ba1/4a/34/e1fa9d71c0f17fceb7f4e914608d", + "assets/build/windows/Win32/Lib/dataclasses.py": "https://files.ballistica.net/cache/ba1/1d/0a/d2ae7b3e8d6db1a24afed5549455", + "assets/build/windows/Win32/Lib/datetime.py": "https://files.ballistica.net/cache/ba1/09/bd/bd6fd74b8cd885b5032ffe2d2718", "assets/build/windows/Win32/Lib/decimal.py": "https://files.ballistica.net/cache/ba1/d5/55/9ae7a36d41bfe37b2d67ce3599d0", - "assets/build/windows/Win32/Lib/difflib.py": "https://files.ballistica.net/cache/ba1/1f/07/0083f523b930a1d4429851226286", - "assets/build/windows/Win32/Lib/dis.py": "https://files.ballistica.net/cache/ba1/59/f7/003e25bb8586b1e3732fbb131c25", - "assets/build/windows/Win32/Lib/doctest.py": "https://files.ballistica.net/cache/ba1/f2/03/245b99dc0d8a069a8f47d24baeb3", + "assets/build/windows/Win32/Lib/difflib.py": "https://files.ballistica.net/cache/ba1/20/25/50f6e9a63e9660b451ccbd9f8d86", + "assets/build/windows/Win32/Lib/dis.py": "https://files.ballistica.net/cache/ba1/31/e7/b3775d40bca4e0b4810fbb312260", + "assets/build/windows/Win32/Lib/doctest.py": "https://files.ballistica.net/cache/ba1/35/31/60314b37cfc4ef8e06b9c512a129", "assets/build/windows/Win32/Lib/dummy_threading.py": "https://files.ballistica.net/cache/ba1/08/5a/e7d834d6197d9b58a075b05c4be6", "assets/build/windows/Win32/Lib/email/__init__.py": "https://files.ballistica.net/cache/ba1/ed/7d/64247a9b90f5c7b3f577b0e28ca0", "assets/build/windows/Win32/Lib/email/_encoded_words.py": "https://files.ballistica.net/cache/ba1/05/81/408bbbd16a07d3c6473ff0ce523b", - "assets/build/windows/Win32/Lib/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/6d/41/06081cc1cdb1b39c516544312443", - "assets/build/windows/Win32/Lib/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/50/a0/805c08eb86fc7fa064685846f73c", + "assets/build/windows/Win32/Lib/email/_header_value_parser.py": "https://files.ballistica.net/cache/ba1/79/74/8b39d9278c30a5113a6285f68c13", + "assets/build/windows/Win32/Lib/email/_parseaddr.py": "https://files.ballistica.net/cache/ba1/ed/d2/06c5127141292bc913caee80137b", "assets/build/windows/Win32/Lib/email/_policybase.py": "https://files.ballistica.net/cache/ba1/06/37/302137642525762bee6ce4a09cf1", "assets/build/windows/Win32/Lib/email/architecture.rst": "https://files.ballistica.net/cache/ba1/78/7c/c4274166d5aa06c20c2c0d391104", "assets/build/windows/Win32/Lib/email/base64mime.py": "https://files.ballistica.net/cache/ba1/92/3c/d5b71a0457e0715462a700c52e78", - "assets/build/windows/Win32/Lib/email/charset.py": "https://files.ballistica.net/cache/ba1/59/ab/965bed051392a950daea1e4d1c02", - "assets/build/windows/Win32/Lib/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/7b/e8/b98e3081cbc9dda43f591ddb7ceb", + "assets/build/windows/Win32/Lib/email/charset.py": "https://files.ballistica.net/cache/ba1/85/85/2e724aa519d670805839deb3415f", + "assets/build/windows/Win32/Lib/email/contentmanager.py": "https://files.ballistica.net/cache/ba1/32/ed/b0372aa11be4a30fbd1820b57bb1", "assets/build/windows/Win32/Lib/email/encoders.py": "https://files.ballistica.net/cache/ba1/05/5e/1da72e6b33454bc00ccc75bae468", "assets/build/windows/Win32/Lib/email/errors.py": "https://files.ballistica.net/cache/ba1/53/1a/246d8f67140256975ac7ae97d1e5", "assets/build/windows/Win32/Lib/email/feedparser.py": "https://files.ballistica.net/cache/ba1/aa/d0/f54e9f077a1a3a69295932c21353", "assets/build/windows/Win32/Lib/email/generator.py": "https://files.ballistica.net/cache/ba1/92/60/db86790637e373e2a198c89619a7", "assets/build/windows/Win32/Lib/email/header.py": "https://files.ballistica.net/cache/ba1/d8/53/2ad4aea28a0f2fb1dcdbaca1d8e8", - "assets/build/windows/Win32/Lib/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/45/38/678e0b87bcd80e22d84702a4f22e", + "assets/build/windows/Win32/Lib/email/headerregistry.py": "https://files.ballistica.net/cache/ba1/89/87/3e0601839389ab46421c1325608e", "assets/build/windows/Win32/Lib/email/iterators.py": "https://files.ballistica.net/cache/ba1/90/09/e8c04371be81b7ab0a11be68784d", - "assets/build/windows/Win32/Lib/email/message.py": "https://files.ballistica.net/cache/ba1/0c/87/ce24e36aa6e728d1cd4a6cd6025f", + "assets/build/windows/Win32/Lib/email/message.py": "https://files.ballistica.net/cache/ba1/13/eb/1359fed9fd0ba38797bcd98a45d9", "assets/build/windows/Win32/Lib/email/mime/__init__.py": "https://files.ballistica.net/cache/ba1/b5/ea/80f195a1c0d100480897a83a4da4", "assets/build/windows/Win32/Lib/email/mime/application.py": "https://files.ballistica.net/cache/ba1/a6/b1/f129c2517c74d85f48087f80824d", "assets/build/windows/Win32/Lib/email/mime/audio.py": "https://files.ballistica.net/cache/ba1/29/39/306f35115c997946975ac7c0191b", @@ -3607,12 +3607,12 @@ "assets/build/windows/Win32/Lib/email/mime/multipart.py": "https://files.ballistica.net/cache/ba1/48/c9/3beb25ea74084fd2ab4b2c86c37b", "assets/build/windows/Win32/Lib/email/mime/nonmultipart.py": "https://files.ballistica.net/cache/ba1/0b/e2/82ca4668d9286af8b2dcffa0b6bc", "assets/build/windows/Win32/Lib/email/mime/text.py": "https://files.ballistica.net/cache/ba1/cb/bb/02e93c2f1c2cce4b255ae7b1e482", - "assets/build/windows/Win32/Lib/email/parser.py": "https://files.ballistica.net/cache/ba1/1f/47/7c3d22b86077f944dfc8ee7a49cc", + "assets/build/windows/Win32/Lib/email/parser.py": "https://files.ballistica.net/cache/ba1/4f/06/6bf636bb70433a9a62c41bca8406", "assets/build/windows/Win32/Lib/email/policy.py": "https://files.ballistica.net/cache/ba1/77/b1/8a70ba209a24931675bff0a345cd", "assets/build/windows/Win32/Lib/email/quoprimime.py": "https://files.ballistica.net/cache/ba1/76/74/92b4640edaa325ff338c5affb245", - "assets/build/windows/Win32/Lib/email/utils.py": "https://files.ballistica.net/cache/ba1/b0/ec/8c0e7e25fa8daa7eab0fe4f5c370", - "assets/build/windows/Win32/Lib/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/be/e6/fba13ffac3f685892d540a195bdc", - "assets/build/windows/Win32/Lib/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/00/7e/c2a22ddceced03816f4cb1b61e66", + "assets/build/windows/Win32/Lib/email/utils.py": "https://files.ballistica.net/cache/ba1/eb/d6/bb1e792fc83161264525c914cc46", + "assets/build/windows/Win32/Lib/encodings/__init__.py": "https://files.ballistica.net/cache/ba1/6f/a4/bb19f2225934af92392ef32b5096", + "assets/build/windows/Win32/Lib/encodings/aliases.py": "https://files.ballistica.net/cache/ba1/7a/7b/9e1451e88044c5c16cf671d207b8", "assets/build/windows/Win32/Lib/encodings/ascii.py": "https://files.ballistica.net/cache/ba1/41/44/3c51a65e96fdbbdfc71983863cf5", "assets/build/windows/Win32/Lib/encodings/base64_codec.py": "https://files.ballistica.net/cache/ba1/f8/5d/78e448a54324be27c57960c3ef8f", "assets/build/windows/Win32/Lib/encodings/big5.py": "https://files.ballistica.net/cache/ba1/59/23/27486e3ee84ed7e8f3dfcba5497d", @@ -3713,7 +3713,7 @@ "assets/build/windows/Win32/Lib/encodings/oem.py": "https://files.ballistica.net/cache/ba1/fa/02/08370f780f841c23b7a8dd8f25aa", "assets/build/windows/Win32/Lib/encodings/palmos.py": "https://files.ballistica.net/cache/ba1/7b/fd/8cd9337594e60b0feddcf25c368d", "assets/build/windows/Win32/Lib/encodings/ptcp154.py": "https://files.ballistica.net/cache/ba1/20/3b/47719c175fdfe43538c5e9792d24", - "assets/build/windows/Win32/Lib/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/94/05/babf7961a3c24e2e90ea827d7031", + "assets/build/windows/Win32/Lib/encodings/punycode.py": "https://files.ballistica.net/cache/ba1/81/cf/8fe2dc639f26d7cb00ff0ce7e1ea", "assets/build/windows/Win32/Lib/encodings/quopri_codec.py": "https://files.ballistica.net/cache/ba1/73/b5/88317f8c11128b5797b6b282b22a", "assets/build/windows/Win32/Lib/encodings/raw_unicode_escape.py": "https://files.ballistica.net/cache/ba1/6a/82/0df142d583fcad7deba60635eafa", "assets/build/windows/Win32/Lib/encodings/rot_13.py": "https://files.ballistica.net/cache/ba1/a9/86/d0e282a103b6005c7eba393c2865", @@ -3732,157 +3732,157 @@ "assets/build/windows/Win32/Lib/encodings/utf_7.py": "https://files.ballistica.net/cache/ba1/fe/2c/cc363eceaec22d46829d0b3748e5", "assets/build/windows/Win32/Lib/encodings/utf_8.py": "https://files.ballistica.net/cache/ba1/82/0e/a8bd3ac0e209ec22903f36c7e743", "assets/build/windows/Win32/Lib/encodings/utf_8_sig.py": "https://files.ballistica.net/cache/ba1/02/57/abf1662be43acd806d712d09ad92", - "assets/build/windows/Win32/Lib/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/ac/6a/ef4e3dfe6cb0ca98be39de499609", + "assets/build/windows/Win32/Lib/encodings/uu_codec.py": "https://files.ballistica.net/cache/ba1/ca/1c/8b4574b02be8387d5b8818d1399d", "assets/build/windows/Win32/Lib/encodings/zlib_codec.py": "https://files.ballistica.net/cache/ba1/ca/b7/a919c6be178102f90d97879e61ec", - "assets/build/windows/Win32/Lib/enum.py": "https://files.ballistica.net/cache/ba1/b5/48/1d1c8b714439cb31efc583187a62", + "assets/build/windows/Win32/Lib/enum.py": "https://files.ballistica.net/cache/ba1/bb/c9/3118d618dc2c7a6c11e4336e7b2d", "assets/build/windows/Win32/Lib/filecmp.py": "https://files.ballistica.net/cache/ba1/20/32/e1aa0ebff27033ec554330288554", - "assets/build/windows/Win32/Lib/fileinput.py": "https://files.ballistica.net/cache/ba1/c5/77/3090267f0805b911112684459b56", + "assets/build/windows/Win32/Lib/fileinput.py": "https://files.ballistica.net/cache/ba1/9c/59/041f2cde1b129359ae61dfa9816c", "assets/build/windows/Win32/Lib/fnmatch.py": "https://files.ballistica.net/cache/ba1/50/d8/be1bfccd23262714b368a87efcfe", "assets/build/windows/Win32/Lib/formatter.py": "https://files.ballistica.net/cache/ba1/94/4e/c1f6b9a2f088571d5faa0f323dca", - "assets/build/windows/Win32/Lib/fractions.py": "https://files.ballistica.net/cache/ba1/95/71/912995f855291425d58862c2348a", - "assets/build/windows/Win32/Lib/ftplib.py": "https://files.ballistica.net/cache/ba1/03/95/cb1b32f050224f99450715112d7d", - "assets/build/windows/Win32/Lib/functools.py": "https://files.ballistica.net/cache/ba1/46/0f/ce08a76f27dd0a726af57a09e4e9", - "assets/build/windows/Win32/Lib/genericpath.py": "https://files.ballistica.net/cache/ba1/48/83/1d5fa6fd3806f0a0dc604f9ec2e1", + "assets/build/windows/Win32/Lib/fractions.py": "https://files.ballistica.net/cache/ba1/d3/66/5942f4e9b9ea2f05fb7de136f2f3", + "assets/build/windows/Win32/Lib/ftplib.py": "https://files.ballistica.net/cache/ba1/09/0e/05e3fa3fc16419c3f5be08c5d3fe", + "assets/build/windows/Win32/Lib/functools.py": "https://files.ballistica.net/cache/ba1/bb/24/12c61dcec09c98ad01b56801db9f", + "assets/build/windows/Win32/Lib/genericpath.py": "https://files.ballistica.net/cache/ba1/51/fc/1a323017e8b06cdc6327c524fe66", "assets/build/windows/Win32/Lib/getopt.py": "https://files.ballistica.net/cache/ba1/c8/63/dfdbb68d2e67c3bae4f9dcc3f0f5", "assets/build/windows/Win32/Lib/getpass.py": "https://files.ballistica.net/cache/ba1/be/e6/71f0a41074219d94d7e5f4d4dd77", - "assets/build/windows/Win32/Lib/gettext.py": "https://files.ballistica.net/cache/ba1/68/ac/560154c6e471eca4839dc2a2f207", - "assets/build/windows/Win32/Lib/glob.py": "https://files.ballistica.net/cache/ba1/ca/2c/ae8a44614324e4f1b5fb1888b530", - "assets/build/windows/Win32/Lib/gzip.py": "https://files.ballistica.net/cache/ba1/14/0b/f5188d97584eab715d09d0c3e263", - "assets/build/windows/Win32/Lib/hashlib.py": "https://files.ballistica.net/cache/ba1/62/18/a22dd8c65174420d1bef002c7e4c", - "assets/build/windows/Win32/Lib/heapq.py": "https://files.ballistica.net/cache/ba1/d5/7d/ed2881850aeb9d3ecd56f38175b7", - "assets/build/windows/Win32/Lib/hmac.py": "https://files.ballistica.net/cache/ba1/39/d5/f16de28e25d8a4f482d7c4e00457", + "assets/build/windows/Win32/Lib/gettext.py": "https://files.ballistica.net/cache/ba1/11/6b/c1e62ac780490c34659934a6ab38", + "assets/build/windows/Win32/Lib/glob.py": "https://files.ballistica.net/cache/ba1/36/6c/b8ce0cc27f4cb3b86db3c7d9347a", + "assets/build/windows/Win32/Lib/gzip.py": "https://files.ballistica.net/cache/ba1/b8/da/b458a9670a4fa0d99a4835489a95", + "assets/build/windows/Win32/Lib/hashlib.py": "https://files.ballistica.net/cache/ba1/58/22/5813b858f7b0c5f6bd3c08b5e270", + "assets/build/windows/Win32/Lib/heapq.py": "https://files.ballistica.net/cache/ba1/34/2f/f8ff15aedf39c36b2f6412af45fe", + "assets/build/windows/Win32/Lib/hmac.py": "https://files.ballistica.net/cache/ba1/30/f4/e91fda1efa524172eb6aac3d326d", "assets/build/windows/Win32/Lib/html/__init__.py": "https://files.ballistica.net/cache/ba1/8c/08/c638db74e5e5979dea109da1f68b", "assets/build/windows/Win32/Lib/html/entities.py": "https://files.ballistica.net/cache/ba1/52/69/e7311caea2fbfdfef9c05515de4b", "assets/build/windows/Win32/Lib/html/parser.py": "https://files.ballistica.net/cache/ba1/93/8c/7e6734f43521e484eff3265c3b2f", - "assets/build/windows/Win32/Lib/http/__init__.py": "https://files.ballistica.net/cache/ba1/c6/f1/db2ad2c4d17dcda4c7c908fd0594", - "assets/build/windows/Win32/Lib/http/client.py": "https://files.ballistica.net/cache/ba1/6a/9f/9fc4ae67187f07ee2ac8b35b7079", - "assets/build/windows/Win32/Lib/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/ce/d1/d948c21fe6cee0951134e1441762", - "assets/build/windows/Win32/Lib/http/cookies.py": "https://files.ballistica.net/cache/ba1/1c/44/3832b5763a5ca6d422a0b1dfb34a", - "assets/build/windows/Win32/Lib/http/server.py": "https://files.ballistica.net/cache/ba1/cf/30/e6488897f60e5d51f32d55a5e542", - "assets/build/windows/Win32/Lib/imghdr.py": "https://files.ballistica.net/cache/ba1/68/6a/6e1e60839584bc133ee001bbe810", + "assets/build/windows/Win32/Lib/http/__init__.py": "https://files.ballistica.net/cache/ba1/00/9a/8db3eba06a3e0e739cf2da0c8996", + "assets/build/windows/Win32/Lib/http/client.py": "https://files.ballistica.net/cache/ba1/9b/b3/823a9620582a4310880c99b9013b", + "assets/build/windows/Win32/Lib/http/cookiejar.py": "https://files.ballistica.net/cache/ba1/08/00/0b45e485fbbf70dc705d41216abd", + "assets/build/windows/Win32/Lib/http/cookies.py": "https://files.ballistica.net/cache/ba1/d1/96/f86c64ac27b1aec761087d1fc55a", + "assets/build/windows/Win32/Lib/http/server.py": "https://files.ballistica.net/cache/ba1/30/7e/5e90c701918e966c0a10fe2b3d88", + "assets/build/windows/Win32/Lib/imghdr.py": "https://files.ballistica.net/cache/ba1/a8/49/6afa9e88ee446fadd95254fc159d", "assets/build/windows/Win32/Lib/imp.py": "https://files.ballistica.net/cache/ba1/27/49/796442c2ad99d661778789ccb6b9", - "assets/build/windows/Win32/Lib/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/9d/88/7fbbfcef32d68d60a7cf2d1c9f33", - "assets/build/windows/Win32/Lib/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/f0/1a/a3698578fdab450d3cb0d624524b", - "assets/build/windows/Win32/Lib/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/d4/8c/0ba35e65bab4befa47988b55fe52", + "assets/build/windows/Win32/Lib/importlib/__init__.py": "https://files.ballistica.net/cache/ba1/34/ab/d855c97aa3f1707dc083d3812422", + "assets/build/windows/Win32/Lib/importlib/_bootstrap.py": "https://files.ballistica.net/cache/ba1/e0/b8/fd3a491af05bab27fffee4711b36", + "assets/build/windows/Win32/Lib/importlib/_bootstrap_external.py": "https://files.ballistica.net/cache/ba1/d6/44/8e9fecfa85afede694eb06298034", "assets/build/windows/Win32/Lib/importlib/abc.py": "https://files.ballistica.net/cache/ba1/e1/ce/cf8dfb21a116a8bf87f757ddb332", "assets/build/windows/Win32/Lib/importlib/machinery.py": "https://files.ballistica.net/cache/ba1/a1/ac/b97d16285d94f0b18406366d803b", "assets/build/windows/Win32/Lib/importlib/metadata.py": "https://files.ballistica.net/cache/ba1/50/b7/1e091864ef2342eb9f7627a5ad85", - "assets/build/windows/Win32/Lib/importlib/resources.py": "https://files.ballistica.net/cache/ba1/4e/31/44caa392a8ff3ca4c72b95e499b7", + "assets/build/windows/Win32/Lib/importlib/resources.py": "https://files.ballistica.net/cache/ba1/13/da/3bc2fe81fddcb89589d4f5129d2b", "assets/build/windows/Win32/Lib/importlib/util.py": "https://files.ballistica.net/cache/ba1/5e/96/a3d35aecec8ff9e6f2158f56c27c", - "assets/build/windows/Win32/Lib/inspect.py": "https://files.ballistica.net/cache/ba1/7b/e2/ac2e2c98758f67254c26403eb3ad", - "assets/build/windows/Win32/Lib/io.py": "https://files.ballistica.net/cache/ba1/f1/4f/e33a91472082f5ee05b0a352c36d", - "assets/build/windows/Win32/Lib/ipaddress.py": "https://files.ballistica.net/cache/ba1/1a/5f/d02ef4503e4d8b0f50efa3037cc7", - "assets/build/windows/Win32/Lib/json/__init__.py": "https://files.ballistica.net/cache/ba1/5e/b6/0e2a48ac4f7c1bd0646e260467c0", + "assets/build/windows/Win32/Lib/inspect.py": "https://files.ballistica.net/cache/ba1/3e/76/764dd66ccb9ad74292d6e07ee3ff", + "assets/build/windows/Win32/Lib/io.py": "https://files.ballistica.net/cache/ba1/ee/a7/27e33a9728a22a8228628782bfe7", + "assets/build/windows/Win32/Lib/ipaddress.py": "https://files.ballistica.net/cache/ba1/7d/3c/b71af3f7f5d381bfaa1e200eb2ac", + "assets/build/windows/Win32/Lib/json/__init__.py": "https://files.ballistica.net/cache/ba1/a0/b3/9179fcad487ca6edf2c5a96f2f5e", "assets/build/windows/Win32/Lib/json/decoder.py": "https://files.ballistica.net/cache/ba1/f5/44/19f6e70ef50bed1f318027bbf9aa", - "assets/build/windows/Win32/Lib/json/encoder.py": "https://files.ballistica.net/cache/ba1/b3/1a/63e5bf127edf3000e7d276c6c5be", + "assets/build/windows/Win32/Lib/json/encoder.py": "https://files.ballistica.net/cache/ba1/65/87/ea5c0cd241ce16750147c2b113da", "assets/build/windows/Win32/Lib/json/scanner.py": "https://files.ballistica.net/cache/ba1/a7/9e/0fdf34c72293733a58f0dd2677fa", - "assets/build/windows/Win32/Lib/json/tool.py": "https://files.ballistica.net/cache/ba1/bf/da/feeaf67e5b1d79e759e3e75f0b03", - "assets/build/windows/Win32/Lib/keyword.py": "https://files.ballistica.net/cache/ba1/38/d0/bbde6b4e54dcf437fca3aa869732", - "assets/build/windows/Win32/Lib/linecache.py": "https://files.ballistica.net/cache/ba1/fa/63/086a9b401b1c2e3cb7eccac17e41", - "assets/build/windows/Win32/Lib/locale.py": "https://files.ballistica.net/cache/ba1/e9/ab/2a915b79b3ba36becb4dbb59107d", - "assets/build/windows/Win32/Lib/logging/__init__.py": "https://files.ballistica.net/cache/ba1/03/4f/7818d4ed23340153e1dbb1993d90", - "assets/build/windows/Win32/Lib/logging/config.py": "https://files.ballistica.net/cache/ba1/56/55/6da1bbc4da532f4ad4a183baca07", - "assets/build/windows/Win32/Lib/logging/handlers.py": "https://files.ballistica.net/cache/ba1/e9/8c/e7dd81f83b123d9f343ddc1408fc", + "assets/build/windows/Win32/Lib/json/tool.py": "https://files.ballistica.net/cache/ba1/70/80/f06ec89a4cfe38fabfeae3a9b1e4", + "assets/build/windows/Win32/Lib/keyword.py": "https://files.ballistica.net/cache/ba1/b6/c9/6fe1ba0c2f3df0a7cff398a69c75", + "assets/build/windows/Win32/Lib/linecache.py": "https://files.ballistica.net/cache/ba1/a5/e9/a9af76d79b1d6295749ea12a9590", + "assets/build/windows/Win32/Lib/locale.py": "https://files.ballistica.net/cache/ba1/ff/49/64c2836f6f9a4a9b7613ae4bbe68", + "assets/build/windows/Win32/Lib/logging/__init__.py": "https://files.ballistica.net/cache/ba1/78/e7/c93caee9b78214381dff14d0a645", + "assets/build/windows/Win32/Lib/logging/config.py": "https://files.ballistica.net/cache/ba1/af/72/51a97504cd5fda5bdfe7c9f966f6", + "assets/build/windows/Win32/Lib/logging/handlers.py": "https://files.ballistica.net/cache/ba1/8a/b9/7a237a423b8377a2b76be0e80f8e", "assets/build/windows/Win32/Lib/lzma.py": "https://files.ballistica.net/cache/ba1/88/58/5eb2ce7457b4084010d40fa35609", - "assets/build/windows/Win32/Lib/mailbox.py": "https://files.ballistica.net/cache/ba1/77/3a/8ee9e0108fb3be6daec90dce4b30", + "assets/build/windows/Win32/Lib/mailbox.py": "https://files.ballistica.net/cache/ba1/c9/02/4033e7308dd093bfb8dd15d58ea0", "assets/build/windows/Win32/Lib/mailcap.py": "https://files.ballistica.net/cache/ba1/cd/ef/d43f7e1f692a91246149348186f8", - "assets/build/windows/Win32/Lib/mimetypes.py": "https://files.ballistica.net/cache/ba1/fb/64/9905e7bacf8b6a9b082267e8ff8c", - "assets/build/windows/Win32/Lib/modulefinder.py": "https://files.ballistica.net/cache/ba1/19/1b/b25e54572967128c0c2e3b53b457", + "assets/build/windows/Win32/Lib/mimetypes.py": "https://files.ballistica.net/cache/ba1/25/a2/01e55fef8b57f4fcf5c92eebef4a", + "assets/build/windows/Win32/Lib/modulefinder.py": "https://files.ballistica.net/cache/ba1/55/6d/bd1b7ea0bc6b584d15bdde04c210", "assets/build/windows/Win32/Lib/msilib/__init__.py": "https://files.ballistica.net/cache/ba1/32/b4/3d542fb6efb60c95af4e1edbe102", "assets/build/windows/Win32/Lib/msilib/schema.py": "https://files.ballistica.net/cache/ba1/65/dd/95b460cf2c95a6caf4bdbb1a3d51", "assets/build/windows/Win32/Lib/msilib/sequence.py": "https://files.ballistica.net/cache/ba1/5e/c4/a7a6140c298325ee69a8958b40d6", "assets/build/windows/Win32/Lib/msilib/text.py": "https://files.ballistica.net/cache/ba1/49/b2/15871bd0d47d347c9371490eb35f", "assets/build/windows/Win32/Lib/netrc.py": "https://files.ballistica.net/cache/ba1/6e/c7/c912c856c06d61ce362403506c58", - "assets/build/windows/Win32/Lib/nntplib.py": "https://files.ballistica.net/cache/ba1/38/10/cf7944b2ea0b601f10961acf9338", - "assets/build/windows/Win32/Lib/ntpath.py": "https://files.ballistica.net/cache/ba1/48/9d/a2164b32a2d851aa5b1854e0b143", + "assets/build/windows/Win32/Lib/nntplib.py": "https://files.ballistica.net/cache/ba1/3f/6c/124eb82ca929cdbcbb7c8cb4628a", + "assets/build/windows/Win32/Lib/ntpath.py": "https://files.ballistica.net/cache/ba1/d0/16/d4d8d088994e890714a11dc15434", "assets/build/windows/Win32/Lib/nturl2path.py": "https://files.ballistica.net/cache/ba1/05/77/b863ff2e727259dac90f77bdcbfb", "assets/build/windows/Win32/Lib/numbers.py": "https://files.ballistica.net/cache/ba1/19/02/57245f310345adfc574565c19471", - "assets/build/windows/Win32/Lib/opcode.py": "https://files.ballistica.net/cache/ba1/58/a0/cd29e37289328e38f4092f32a2e9", - "assets/build/windows/Win32/Lib/operator.py": "https://files.ballistica.net/cache/ba1/d2/72/3e9422ccde5f840628c2dae8a3db", - "assets/build/windows/Win32/Lib/optparse.py": "https://files.ballistica.net/cache/ba1/a5/df/e3d1a9c843816d0b3f39db14e4de", - "assets/build/windows/Win32/Lib/os.py": "https://files.ballistica.net/cache/ba1/55/1f/30b9d9cfce387d484dbec2701dfa", - "assets/build/windows/Win32/Lib/pathlib.py": "https://files.ballistica.net/cache/ba1/a3/bf/5b9c1655bef8cf01ee0b19283126", - "assets/build/windows/Win32/Lib/pdb.py": "https://files.ballistica.net/cache/ba1/a2/78/7b8651a73017df6a8933373db028", - "assets/build/windows/Win32/Lib/pickle.py": "https://files.ballistica.net/cache/ba1/ee/a4/ba3b129ed355075e5f2aa03b4fd2", - "assets/build/windows/Win32/Lib/pickletools.py": "https://files.ballistica.net/cache/ba1/c5/21/87c5922f498939a39d5068416c01", + "assets/build/windows/Win32/Lib/opcode.py": "https://files.ballistica.net/cache/ba1/ad/4a/0d449831129669c0b9f800754322", + "assets/build/windows/Win32/Lib/operator.py": "https://files.ballistica.net/cache/ba1/fe/a1/433be97456e193c9a2e600ff84aa", + "assets/build/windows/Win32/Lib/optparse.py": "https://files.ballistica.net/cache/ba1/08/d8/10bbc27b50836a1329ca9a8c76d9", + "assets/build/windows/Win32/Lib/os.py": "https://files.ballistica.net/cache/ba1/f7/b0/7795b8038c42d6c812be0b62d42c", + "assets/build/windows/Win32/Lib/pathlib.py": "https://files.ballistica.net/cache/ba1/f9/66/3f0aea2a0518289bc4286b4bda8d", + "assets/build/windows/Win32/Lib/pdb.py": "https://files.ballistica.net/cache/ba1/75/66/b6b61ea0471e82da55f7b95e47b1", + "assets/build/windows/Win32/Lib/pickle.py": "https://files.ballistica.net/cache/ba1/23/de/8cea763cb47bd1d8dcde05876c23", + "assets/build/windows/Win32/Lib/pickletools.py": "https://files.ballistica.net/cache/ba1/2e/45/eddff9ff648e35265541ce3296aa", "assets/build/windows/Win32/Lib/pipes.py": "https://files.ballistica.net/cache/ba1/4f/e3/798b7a258f1747aa6c5abb437149", "assets/build/windows/Win32/Lib/pkgutil.py": "https://files.ballistica.net/cache/ba1/71/ec/ef12b9e970cdd6519387ad7168bc", - "assets/build/windows/Win32/Lib/platform.py": "https://files.ballistica.net/cache/ba1/24/d8/2932e822b160837c78865f13ab3c", - "assets/build/windows/Win32/Lib/plistlib.py": "https://files.ballistica.net/cache/ba1/ce/8e/69f629d62bcd9fb7ae75e8ca559f", - "assets/build/windows/Win32/Lib/poplib.py": "https://files.ballistica.net/cache/ba1/a0/e5/88e0487f1a7af2ec9d122feb3087", - "assets/build/windows/Win32/Lib/posixpath.py": "https://files.ballistica.net/cache/ba1/e2/34/814d24130241fd67c143813a24c0", - "assets/build/windows/Win32/Lib/pprint.py": "https://files.ballistica.net/cache/ba1/3b/b7/54e56a08109e3477e8aa436f6244", - "assets/build/windows/Win32/Lib/profile.py": "https://files.ballistica.net/cache/ba1/6f/6a/21204d8262bb6ae0ec570185d14e", - "assets/build/windows/Win32/Lib/pstats.py": "https://files.ballistica.net/cache/ba1/a0/b3/5a3bb49ede314fb6eb91ce354a4a", - "assets/build/windows/Win32/Lib/pty.py": "https://files.ballistica.net/cache/ba1/5c/f5/48d694cc661d436af2c44371fd2a", - "assets/build/windows/Win32/Lib/py_compile.py": "https://files.ballistica.net/cache/ba1/37/e5/29d7a2ca1aa281015151eed79abe", - "assets/build/windows/Win32/Lib/pyclbr.py": "https://files.ballistica.net/cache/ba1/51/4e/7f73565177805a6f80a08c5c72de", - "assets/build/windows/Win32/Lib/pydoc.py": "https://files.ballistica.net/cache/ba1/77/33/1e952dd1e7c7a2e083a9774a3d26", - "assets/build/windows/Win32/Lib/queue.py": "https://files.ballistica.net/cache/ba1/2a/d7/fa97bd96b3e7b51160cb8afea22b", + "assets/build/windows/Win32/Lib/platform.py": "https://files.ballistica.net/cache/ba1/e4/ce/7ff2a305f977646d16e9bd3f8520", + "assets/build/windows/Win32/Lib/plistlib.py": "https://files.ballistica.net/cache/ba1/4a/5c/e2974e9a8d629f5bdea197989c4c", + "assets/build/windows/Win32/Lib/poplib.py": "https://files.ballistica.net/cache/ba1/0b/3f/ebe15eb5e0aed0f623fb371d1e6c", + "assets/build/windows/Win32/Lib/posixpath.py": "https://files.ballistica.net/cache/ba1/0e/d9/4afdfd1c5d247b2184c9da8ce58d", + "assets/build/windows/Win32/Lib/pprint.py": "https://files.ballistica.net/cache/ba1/d7/a9/1c512abc7fa9626b3d4b8032aceb", + "assets/build/windows/Win32/Lib/profile.py": "https://files.ballistica.net/cache/ba1/df/aa/5f646a01fbbf11278346627ad967", + "assets/build/windows/Win32/Lib/pstats.py": "https://files.ballistica.net/cache/ba1/d8/83/57c8604d5383e3a1a72730c5ccbe", + "assets/build/windows/Win32/Lib/pty.py": "https://files.ballistica.net/cache/ba1/01/fa/73d52f1e8ad3e8fba58a8fd67d60", + "assets/build/windows/Win32/Lib/py_compile.py": "https://files.ballistica.net/cache/ba1/b3/4a/825bf33162ad633f02c93f05fa3a", + "assets/build/windows/Win32/Lib/pyclbr.py": "https://files.ballistica.net/cache/ba1/15/53/68c8a9df2a80480b6fc458352687", + "assets/build/windows/Win32/Lib/pydoc.py": "https://files.ballistica.net/cache/ba1/e5/ff/e8d985a8dbd62f018c02f6651e5f", + "assets/build/windows/Win32/Lib/queue.py": "https://files.ballistica.net/cache/ba1/f9/33/4ae8645dcd0a9d8b73d14a1b71c7", "assets/build/windows/Win32/Lib/quopri.py": "https://files.ballistica.net/cache/ba1/2c/58/ad0d88ce4f54696b2e3b77229b6f", - "assets/build/windows/Win32/Lib/random.py": "https://files.ballistica.net/cache/ba1/d0/83/f1f367e044737bfcc55df64bfbdd", - "assets/build/windows/Win32/Lib/re.py": "https://files.ballistica.net/cache/ba1/91/62/5aab4405c5f6ae6209896fc7392e", + "assets/build/windows/Win32/Lib/random.py": "https://files.ballistica.net/cache/ba1/b6/d9/b95dd3d9250d459233f6b5315a3b", + "assets/build/windows/Win32/Lib/re.py": "https://files.ballistica.net/cache/ba1/92/ef/6bfc4cf4278e1d656a339af3a4fb", "assets/build/windows/Win32/Lib/reprlib.py": "https://files.ballistica.net/cache/ba1/a8/ba/d93d9b48a6c8e84421dc29a7a356", "assets/build/windows/Win32/Lib/rlcompleter.py": "https://files.ballistica.net/cache/ba1/07/36/8d1de8a69e6b5b1cc73d0216948a", - "assets/build/windows/Win32/Lib/runpy.py": "https://files.ballistica.net/cache/ba1/61/aa/784e414b515e3868431f6b50c8d3", + "assets/build/windows/Win32/Lib/runpy.py": "https://files.ballistica.net/cache/ba1/33/bb/94fdb22005971a029ec79aea277f", "assets/build/windows/Win32/Lib/sched.py": "https://files.ballistica.net/cache/ba1/c6/60/916d287001a20a6a9b10edec7eab", "assets/build/windows/Win32/Lib/secrets.py": "https://files.ballistica.net/cache/ba1/56/3e/95bb97b0783468cfc2d3334daa98", "assets/build/windows/Win32/Lib/selectors.py": "https://files.ballistica.net/cache/ba1/af/9a/2ffd2e47c2bfd9318aaf126ee6af", "assets/build/windows/Win32/Lib/shelve.py": "https://files.ballistica.net/cache/ba1/78/b5/9bc76a4facc8d27398b939bc074b", - "assets/build/windows/Win32/Lib/shlex.py": "https://files.ballistica.net/cache/ba1/7c/d3/d968a6d998135ef16d6940f7f995", - "assets/build/windows/Win32/Lib/shutil.py": "https://files.ballistica.net/cache/ba1/36/97/d5b05739b9db38ce9ff006235f19", - "assets/build/windows/Win32/Lib/signal.py": "https://files.ballistica.net/cache/ba1/bd/2a/c03beeb8d029363b4fc9711800d5", - "assets/build/windows/Win32/Lib/site.py": "https://files.ballistica.net/cache/ba1/f9/d0/f195220772908a353fc92d69f9f9", + "assets/build/windows/Win32/Lib/shlex.py": "https://files.ballistica.net/cache/ba1/ea/f0/c13f433acca4bee87831401e5846", + "assets/build/windows/Win32/Lib/shutil.py": "https://files.ballistica.net/cache/ba1/48/6c/ab9181bbd7675b275280defc0a25", + "assets/build/windows/Win32/Lib/signal.py": "https://files.ballistica.net/cache/ba1/01/09/a4a4e1ca8c41d84e831555752222", + "assets/build/windows/Win32/Lib/site.py": "https://files.ballistica.net/cache/ba1/f1/8c/e38cbf5f63a710111788414c07c6", "assets/build/windows/Win32/Lib/smtpd.py": "https://files.ballistica.net/cache/ba1/63/b6/77d11c42ae0775a49ed76818bffb", - "assets/build/windows/Win32/Lib/smtplib.py": "https://files.ballistica.net/cache/ba1/2d/2b/db11a6f8a062fad8d96cd930bb38", - "assets/build/windows/Win32/Lib/sndhdr.py": "https://files.ballistica.net/cache/ba1/42/b0/9e3b462c511a254446918db4aba8", - "assets/build/windows/Win32/Lib/socket.py": "https://files.ballistica.net/cache/ba1/f9/a8/dedb211f89a29b5bd52ccced646a", - "assets/build/windows/Win32/Lib/socketserver.py": "https://files.ballistica.net/cache/ba1/d9/d9/7c1012e7659b8cea54a356640bb6", + "assets/build/windows/Win32/Lib/smtplib.py": "https://files.ballistica.net/cache/ba1/ee/88/b917a2d5a11d3b3f4ac874fd5510", + "assets/build/windows/Win32/Lib/sndhdr.py": "https://files.ballistica.net/cache/ba1/48/bd/cf83c27bc7f72e2c5b5d5497aeb3", + "assets/build/windows/Win32/Lib/socket.py": "https://files.ballistica.net/cache/ba1/f4/f6/c4a07d6f6a135b22f9a5d0df4eb4", + "assets/build/windows/Win32/Lib/socketserver.py": "https://files.ballistica.net/cache/ba1/8e/6e/62997e4b94b1360849b5476014d5", "assets/build/windows/Win32/Lib/sqlite3/__init__.py": "https://files.ballistica.net/cache/ba1/4b/1b/be86116df24d067bf7aaa9dc690b", "assets/build/windows/Win32/Lib/sqlite3/dbapi2.py": "https://files.ballistica.net/cache/ba1/12/ce/e004498a9d51b893c10a613c7c56", "assets/build/windows/Win32/Lib/sqlite3/dump.py": "https://files.ballistica.net/cache/ba1/25/0e/52f5b1972488978dae3361460bec", - "assets/build/windows/Win32/Lib/sre_compile.py": "https://files.ballistica.net/cache/ba1/4d/63/8f72f4d7971992ec557e85a2ee62", - "assets/build/windows/Win32/Lib/sre_constants.py": "https://files.ballistica.net/cache/ba1/98/73/9d378c6d7c544da40403d2239721", - "assets/build/windows/Win32/Lib/sre_parse.py": "https://files.ballistica.net/cache/ba1/71/e7/0573aa4c865148946654dc0d473f", - "assets/build/windows/Win32/Lib/ssl.py": "https://files.ballistica.net/cache/ba1/fa/c4/63a9bc96c87579ff68a90a7fa5c2", - "assets/build/windows/Win32/Lib/stat.py": "https://files.ballistica.net/cache/ba1/1c/49/d7af3700c37df3d672ebbc0dc6db", - "assets/build/windows/Win32/Lib/statistics.py": "https://files.ballistica.net/cache/ba1/9b/cf/f5eb6d591c37fcfb405f0d7b5834", - "assets/build/windows/Win32/Lib/string.py": "https://files.ballistica.net/cache/ba1/e7/fe/3438429367248c9d31ff9adebb32", + "assets/build/windows/Win32/Lib/sre_compile.py": "https://files.ballistica.net/cache/ba1/ad/7b/8ab12949ef2e5f8da457fac53624", + "assets/build/windows/Win32/Lib/sre_constants.py": "https://files.ballistica.net/cache/ba1/5e/cd/1e06950ce526150b57e13943b117", + "assets/build/windows/Win32/Lib/sre_parse.py": "https://files.ballistica.net/cache/ba1/ff/9f/a8bbd40431420f03a24cbaa958c0", + "assets/build/windows/Win32/Lib/ssl.py": "https://files.ballistica.net/cache/ba1/66/fa/d4499fb567d9c2fd5ab28070773e", + "assets/build/windows/Win32/Lib/stat.py": "https://files.ballistica.net/cache/ba1/f5/ba/9a795715bfa80417f6b90fc4d5eb", + "assets/build/windows/Win32/Lib/statistics.py": "https://files.ballistica.net/cache/ba1/59/68/14bc90c9ca05a8c167f7e9361ea0", + "assets/build/windows/Win32/Lib/string.py": "https://files.ballistica.net/cache/ba1/55/cf/9b2286ef41a546b8e83dafb4c21f", "assets/build/windows/Win32/Lib/stringprep.py": "https://files.ballistica.net/cache/ba1/5b/42/39b8e69a2979e4f553bb6908b545", "assets/build/windows/Win32/Lib/struct.py": "https://files.ballistica.net/cache/ba1/8e/da/3a3bdc58e197050b1906c1c86266", - "assets/build/windows/Win32/Lib/subprocess.py": "https://files.ballistica.net/cache/ba1/2b/3d/4f73c118219b99930ff16ce7413e", + "assets/build/windows/Win32/Lib/subprocess.py": "https://files.ballistica.net/cache/ba1/92/51/d899b4d325e933590218fcfb81b3", "assets/build/windows/Win32/Lib/sunau.py": "https://files.ballistica.net/cache/ba1/83/4a/58133fd86ce134568f30cfa21b9c", - "assets/build/windows/Win32/Lib/symbol.py": "https://files.ballistica.net/cache/ba1/c4/bc/0e4adc5bf818f8ad24c90563d33d", - "assets/build/windows/Win32/Lib/symtable.py": "https://files.ballistica.net/cache/ba1/5d/1b/0368eb2693de8b03cc741ab7b4ad", - "assets/build/windows/Win32/Lib/sysconfig.py": "https://files.ballistica.net/cache/ba1/94/2c/060345a8379488204c165600eb41", + "assets/build/windows/Win32/Lib/symbol.py": "https://files.ballistica.net/cache/ba1/db/33/0e3b5b52110cacc345203fd9d328", + "assets/build/windows/Win32/Lib/symtable.py": "https://files.ballistica.net/cache/ba1/32/ab/b015cae4110d38b37cc64251d89f", + "assets/build/windows/Win32/Lib/sysconfig.py": "https://files.ballistica.net/cache/ba1/d5/84/72778fc541502325d17fbb1f7f07", "assets/build/windows/Win32/Lib/tabnanny.py": "https://files.ballistica.net/cache/ba1/f0/6a/00c300ad5404f3bbbe4fe723a466", - "assets/build/windows/Win32/Lib/tarfile.py": "https://files.ballistica.net/cache/ba1/f3/cc/c392e24006d4ca942b0979e1a402", - "assets/build/windows/Win32/Lib/telnetlib.py": "https://files.ballistica.net/cache/ba1/0a/4b/b81b510b87a106cf8f9715d26c66", - "assets/build/windows/Win32/Lib/tempfile.py": "https://files.ballistica.net/cache/ba1/3c/36/b61379137f68368efa37c551d9d7", - "assets/build/windows/Win32/Lib/textwrap.py": "https://files.ballistica.net/cache/ba1/37/f6/08ba64ff387303ae0a39b19a7ad2", + "assets/build/windows/Win32/Lib/tarfile.py": "https://files.ballistica.net/cache/ba1/01/d4/bddbb7c9d8fe0d28a5f11aa4da6b", + "assets/build/windows/Win32/Lib/telnetlib.py": "https://files.ballistica.net/cache/ba1/29/35/bdff1814c1cdba6b4ae5cb2f8675", + "assets/build/windows/Win32/Lib/tempfile.py": "https://files.ballistica.net/cache/ba1/b8/f2/59d8cc47a08868c5467a00c1d85c", + "assets/build/windows/Win32/Lib/textwrap.py": "https://files.ballistica.net/cache/ba1/c0/4a/3c5af4ba3f0440874cdb4dc61ecd", "assets/build/windows/Win32/Lib/this.py": "https://files.ballistica.net/cache/ba1/b0/f9/1eb227ba1d4d069da408b12e8312", - "assets/build/windows/Win32/Lib/threading.py": "https://files.ballistica.net/cache/ba1/3f/71/b7c287f4e49167f63fec0bb357d9", - "assets/build/windows/Win32/Lib/timeit.py": "https://files.ballistica.net/cache/ba1/4f/19/f07bc4e9a8033788216ddc172620", - "assets/build/windows/Win32/Lib/token.py": "https://files.ballistica.net/cache/ba1/ba/13/08f9eed6b214df36aeacb086eaa2", - "assets/build/windows/Win32/Lib/tokenize.py": "https://files.ballistica.net/cache/ba1/d4/03/b677823f75fb00c5553e79e1665d", - "assets/build/windows/Win32/Lib/trace.py": "https://files.ballistica.net/cache/ba1/58/6d/bad849ff6ada0d760ad9e5053816", - "assets/build/windows/Win32/Lib/traceback.py": "https://files.ballistica.net/cache/ba1/d5/56/ec68c9153c3ccf59571d203df771", + "assets/build/windows/Win32/Lib/threading.py": "https://files.ballistica.net/cache/ba1/5b/a8/61c3511e8e103bdfd7825958b540", + "assets/build/windows/Win32/Lib/timeit.py": "https://files.ballistica.net/cache/ba1/10/08/1e351bf532a328eb7e2e23a25b44", + "assets/build/windows/Win32/Lib/token.py": "https://files.ballistica.net/cache/ba1/64/7c/121b22af2f56ace6019d0e2b3819", + "assets/build/windows/Win32/Lib/tokenize.py": "https://files.ballistica.net/cache/ba1/9d/01/b7ddea4fbc9401b71734d68e7500", + "assets/build/windows/Win32/Lib/trace.py": "https://files.ballistica.net/cache/ba1/61/e2/4f8a48fa03a1f49dd363204db6ed", + "assets/build/windows/Win32/Lib/traceback.py": "https://files.ballistica.net/cache/ba1/58/fe/040d4b32aab47ce1bd5920739394", "assets/build/windows/Win32/Lib/tracemalloc.py": "https://files.ballistica.net/cache/ba1/91/0a/fcb0e16864c9ffe49e4eb9cc122c", "assets/build/windows/Win32/Lib/tty.py": "https://files.ballistica.net/cache/ba1/66/b3/bb1684cec763502fdf418909eedc", - "assets/build/windows/Win32/Lib/types.py": "https://files.ballistica.net/cache/ba1/8e/43/16e0fb9fc221c5664760dcb34155", - "assets/build/windows/Win32/Lib/typing.py": "https://files.ballistica.net/cache/ba1/f1/bc/ed57ac1054de7131ac5d8123f0a7", + "assets/build/windows/Win32/Lib/types.py": "https://files.ballistica.net/cache/ba1/e0/c8/31f459e0c2f7bac2d0ebbfa00a59", + "assets/build/windows/Win32/Lib/typing.py": "https://files.ballistica.net/cache/ba1/b6/e4/03cad30b8be21630d987122692a4", "assets/build/windows/Win32/Lib/urllib/__init__.py": "https://files.ballistica.net/cache/ba1/48/ca/f840c02dd0e7222236a872a7f278", "assets/build/windows/Win32/Lib/urllib/error.py": "https://files.ballistica.net/cache/ba1/c9/c8/9d133fc217803023dff6faed8681", - "assets/build/windows/Win32/Lib/urllib/parse.py": "https://files.ballistica.net/cache/ba1/f7/b5/4c33d0394bacab721858874c567e", - "assets/build/windows/Win32/Lib/urllib/request.py": "https://files.ballistica.net/cache/ba1/14/f1/d983ab18df1b11a5fb5037f0404a", + "assets/build/windows/Win32/Lib/urllib/parse.py": "https://files.ballistica.net/cache/ba1/d7/fc/813689937d353eb8274116634140", + "assets/build/windows/Win32/Lib/urllib/request.py": "https://files.ballistica.net/cache/ba1/18/bf/a212326081a46262ca47520401bd", "assets/build/windows/Win32/Lib/urllib/response.py": "https://files.ballistica.net/cache/ba1/bb/87/38040a39e87e422ad8afe64bf2a7", - "assets/build/windows/Win32/Lib/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/7a/b7/3af41797a3ab4b7aca844da2a17f", - "assets/build/windows/Win32/Lib/uu.py": "https://files.ballistica.net/cache/ba1/79/56/361ba661d709ca4e4c187fcbc341", - "assets/build/windows/Win32/Lib/uuid.py": "https://files.ballistica.net/cache/ba1/ea/ef/83330d443458dbd624fe1f2468c5", - "assets/build/windows/Win32/Lib/warnings.py": "https://files.ballistica.net/cache/ba1/54/8b/0cccabedfd1919dfcfaaec80f740", - "assets/build/windows/Win32/Lib/wave.py": "https://files.ballistica.net/cache/ba1/c9/ae/0c817c04a0dd981f32812f72444b", - "assets/build/windows/Win32/Lib/weakref.py": "https://files.ballistica.net/cache/ba1/58/f9/5c6b50780bb277d13853f0c6cc3d", - "assets/build/windows/Win32/Lib/webbrowser.py": "https://files.ballistica.net/cache/ba1/0b/2d/ec8eb248bdc1e9b48e08a7f0bd95", + "assets/build/windows/Win32/Lib/urllib/robotparser.py": "https://files.ballistica.net/cache/ba1/ef/f6/c7fd5ad82a88e56463f9d1c1b8d1", + "assets/build/windows/Win32/Lib/uu.py": "https://files.ballistica.net/cache/ba1/40/20/7ae03397a7bf1f182a9e5463047f", + "assets/build/windows/Win32/Lib/uuid.py": "https://files.ballistica.net/cache/ba1/80/65/da9c089c4ccf0cc172827fcd024d", + "assets/build/windows/Win32/Lib/warnings.py": "https://files.ballistica.net/cache/ba1/4f/c2/55e364e63a35cfada42a1c0b9504", + "assets/build/windows/Win32/Lib/wave.py": "https://files.ballistica.net/cache/ba1/95/6b/02b4ea1ee3a929a5c3e706b59e2f", + "assets/build/windows/Win32/Lib/weakref.py": "https://files.ballistica.net/cache/ba1/71/b9/26e68828f98cf71c5e9802a24709", + "assets/build/windows/Win32/Lib/webbrowser.py": "https://files.ballistica.net/cache/ba1/9b/7d/4c8e1c024746aaa32427db9d3e08", "assets/build/windows/Win32/Lib/xdrlib.py": "https://files.ballistica.net/cache/ba1/35/a6/f6e14e4fb6beae1f68ec2a4be852", "assets/build/windows/Win32/Lib/xml/__init__.py": "https://files.ballistica.net/cache/ba1/02/9f/a002b4cb540d2e1c2b68edb44b3c", "assets/build/windows/Win32/Lib/xml/dom/NodeFilter.py": "https://files.ballistica.net/cache/ba1/70/fb/e0e98f50e21c494e53869d4d7d32", @@ -3890,27 +3890,27 @@ "assets/build/windows/Win32/Lib/xml/dom/domreg.py": "https://files.ballistica.net/cache/ba1/24/0b/7c0c234f022ab835c9de2ebeae0b", "assets/build/windows/Win32/Lib/xml/dom/expatbuilder.py": "https://files.ballistica.net/cache/ba1/00/f0/624de9ff458a0086a9287a4eca60", "assets/build/windows/Win32/Lib/xml/dom/minicompat.py": "https://files.ballistica.net/cache/ba1/00/0c/03191b6f36ce83e51030448fae74", - "assets/build/windows/Win32/Lib/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/25/39/aaab19272ce3158764bcdbf2e284", - "assets/build/windows/Win32/Lib/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/e6/ae/11f1d46033dbad001e32eaf946ff", + "assets/build/windows/Win32/Lib/xml/dom/minidom.py": "https://files.ballistica.net/cache/ba1/85/60/e39fb6f48bb279485b37e5174ef0", + "assets/build/windows/Win32/Lib/xml/dom/pulldom.py": "https://files.ballistica.net/cache/ba1/de/17/036dd0486e71bd9257e4d083b21b", "assets/build/windows/Win32/Lib/xml/dom/xmlbuilder.py": "https://files.ballistica.net/cache/ba1/b6/5f/e121c4c15d59af737b1040acc649", "assets/build/windows/Win32/Lib/xml/etree/ElementInclude.py": "https://files.ballistica.net/cache/ba1/b5/91/29e1f927a81c897f265ba6f4d070", - "assets/build/windows/Win32/Lib/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/66/e0/f9886fd9661a9dbf7369dc5b8eca", - "assets/build/windows/Win32/Lib/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/fa/c0/19b98d57a3f1507ea252e7a16cb2", + "assets/build/windows/Win32/Lib/xml/etree/ElementPath.py": "https://files.ballistica.net/cache/ba1/e9/75/85145b2539056a6b666cf091339e", + "assets/build/windows/Win32/Lib/xml/etree/ElementTree.py": "https://files.ballistica.net/cache/ba1/d1/3b/0b4abfc25ad2245f7409b716570e", "assets/build/windows/Win32/Lib/xml/etree/__init__.py": "https://files.ballistica.net/cache/ba1/ad/6d/fa6c976589d990e355cce61c4c96", "assets/build/windows/Win32/Lib/xml/etree/cElementTree.py": "https://files.ballistica.net/cache/ba1/50/3c/23d2072448e974423bb11e396ab6", "assets/build/windows/Win32/Lib/xml/parsers/__init__.py": "https://files.ballistica.net/cache/ba1/19/bf/5493270c481d02ed233d2119653c", "assets/build/windows/Win32/Lib/xml/parsers/expat.py": "https://files.ballistica.net/cache/ba1/6e/f1/a6aad9b9297dd20b5c24a224eb87", - "assets/build/windows/Win32/Lib/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/23/97/5f390ff406f46bdd6aa543375f93", + "assets/build/windows/Win32/Lib/xml/sax/__init__.py": "https://files.ballistica.net/cache/ba1/12/eb/ce78b2effa256a82dcd1192db74f", "assets/build/windows/Win32/Lib/xml/sax/_exceptions.py": "https://files.ballistica.net/cache/ba1/47/64/9b8c6da80774cf676c116c42c779", "assets/build/windows/Win32/Lib/xml/sax/expatreader.py": "https://files.ballistica.net/cache/ba1/c7/16/42cb40d7afcde4ce825abf5bfbf3", "assets/build/windows/Win32/Lib/xml/sax/handler.py": "https://files.ballistica.net/cache/ba1/84/cb/83d1e4735c125aee0b686c26f9d0", - "assets/build/windows/Win32/Lib/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/7c/4e/17f476d11ed38a69f301268f632a", + "assets/build/windows/Win32/Lib/xml/sax/saxutils.py": "https://files.ballistica.net/cache/ba1/b8/1c/2ca4b0f80078729b5e76b6d0250b", "assets/build/windows/Win32/Lib/xml/sax/xmlreader.py": "https://files.ballistica.net/cache/ba1/05/f9/eeb1c32818d63991e806451dad45", "assets/build/windows/Win32/Lib/xmlrpc/__init__.py": "https://files.ballistica.net/cache/ba1/84/79/19c277eda21caa83389ff1c2258f", - "assets/build/windows/Win32/Lib/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/9f/4f/2b601d31b625f3ac9eadf4acf048", - "assets/build/windows/Win32/Lib/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/dd/33/3de3c357d21186eaad20201fe99f", + "assets/build/windows/Win32/Lib/xmlrpc/client.py": "https://files.ballistica.net/cache/ba1/1c/07/4679e4429a5da03ebb39b3c219cd", + "assets/build/windows/Win32/Lib/xmlrpc/server.py": "https://files.ballistica.net/cache/ba1/1f/03/3ec486442d39392933c7bab3d00d", "assets/build/windows/Win32/Lib/zipapp.py": "https://files.ballistica.net/cache/ba1/92/65/287c3d27f14ea2956622e136f71b", - "assets/build/windows/Win32/Lib/zipfile.py": "https://files.ballistica.net/cache/ba1/ea/20/cd2e335ec716ea491d023c6695fc", + "assets/build/windows/Win32/Lib/zipfile.py": "https://files.ballistica.net/cache/ba1/a4/5d/baf60589ec6877de04ded39e9993", "assets/build/windows/Win32/Lib/zipimport.py": "https://files.ballistica.net/cache/ba1/73/9f/d089ac24f8277925d6938ab1fe1f", "assets/build/windows/Win32/OpenAL32.dll": "https://files.ballistica.net/cache/ba1/7b/0f/4349781f2e7ea0ced321fd0b9c45", "assets/build/windows/Win32/SDL2.dll": "https://files.ballistica.net/cache/ba1/c5/7d/e8943b5eda2472a308b63f938b1c", @@ -3926,16 +3926,16 @@ "assets/build/windows/Win32/pythonw_d.exe": "https://files.ballistica.net/cache/ba1/4b/df/7ebb1be3e018abc04660d932a7b2", "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", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/3c/4ec6e5319de5ea5e71c1b9ecb63e", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/40/5d8daec9ea222adba802201b8678", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/bd/1f/3018946be23cfd961f3a9d5d6a1a", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9a/f2/4faacc69b875c9beec185f3b1b43", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5c/9d/81553253408524ecc3fde73434e7", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/6a/1f1a1198f07ebfb01375eabd8785", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/9d/82af854c2e7dc71c4edf266ee981", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/62/7a/a2c68757d9e018c74cd68c428e42", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/da/04/c3b9db39e28cf7f4d3a47bb1d06e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/c6/9fe301a0639bca9ef0f36295f662", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c8/9c/3208fe8df1ca8c4cbbac2046256a", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/44/0b/3125d5d6f5568f75ea86a03b1371" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/b6/9438d9e41b904ee9eae03cf75c6a", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/69/648eaa2307e930481d970a9a32db", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/46/f8/bc3c101d36d1bb1c47d938ca8d0b", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/00/8c/6d078695eab35493bd0cfd2d3523", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/77/88/8c0de232370da88bff994864423c", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b0/4a/4b393c9ebb03e57fbc9030d4a501", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/16/e1/6e24960e5d0bdccc103ec8f85f37", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/eb/77425b1f9f65f9aa081a5851ea24", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/81/8e/0a81b48a997ae8d2a928ee23b950", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/70/32/de7a5b3c0b1afceaf2e6bc1a3441", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/25/25/9abf87f1717182796a362b733ae3", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9d/fe/b6ae85178385d36d35aad37e584e" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 489c5ffb..96a2fbc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -### 1.5.24 (20159) -- Upgraded Python from 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now. +### 1.5.24 (20160) +- Upgraded Python from version 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now.. - Windows debug builds now use Python debug libraries. This should hopefully catch more errors that would otherwise go undetected and potentially cause crashes. - Switched windows builds to use 'fast' mode math instead of 'strict'. This should make the game run more efficiently (similar modes are already in use on other platforms) but holler if any odd breakage happens such as things falling through floors (more often than the occasional random fluke-y case that happens now). From 8c16c2b818a304d131e2e08444da48835d4f8cc5 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 1 Aug 2020 14:02:57 -0700 Subject: [PATCH 180/417] Added ucrtbased.dll for win debug prefab builds --- .efrocachemap | 1 + assets/.asset_manifest_private.json | 2 ++ assets/Makefile | 2 ++ tools/batools/assetstaging.py | 7 +++++-- 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 2a7fce1c..1192d95d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3924,6 +3924,7 @@ "assets/build/windows/Win32/python_d.exe": "https://files.ballistica.net/cache/ba1/57/2f/7cda5f442a832f8f92fc76e8370d", "assets/build/windows/Win32/pythonw.exe": "https://files.ballistica.net/cache/ba1/3b/01/7819c084c81c84562a2dab70033e", "assets/build/windows/Win32/pythonw_d.exe": "https://files.ballistica.net/cache/ba1/4b/df/7ebb1be3e018abc04660d932a7b2", + "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/b6/9438d9e41b904ee9eae03cf75c6a", diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json index f5e9ff9f..ed6eeb97 100644 --- a/assets/.asset_manifest_private.json +++ b/assets/.asset_manifest_private.json @@ -5233,6 +5233,7 @@ "windows/Win32/python_d.exe", "windows/Win32/pythonw.exe", "windows/Win32/pythonw_d.exe", + "windows/Win32/ucrtbased.dll", "windows/Win32/vc_redist.x86.exe", "windows/Win32/vcruntime140d.dll", "windows/x64/DLLs/_asyncio.pyd", @@ -6177,6 +6178,7 @@ "windows/x64/python_d.exe", "windows/x64/pythonw.exe", "windows/x64/pythonw_d.exe", + "windows/x64/ucrtbased.dll", "windows/x64/vc_redist.x64.exe", "windows/x64/vcruntime140_1d.dll", "windows/x64/vcruntime140d.dll" diff --git a/assets/Makefile b/assets/Makefile index 31615346..09fcfea4 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -6876,6 +6876,7 @@ EXTRAS_TARGETS_WIN_WIN32 = \ build/windows/Win32/python_d.exe \ build/windows/Win32/pythonw.exe \ build/windows/Win32/pythonw_d.exe \ + build/windows/Win32/ucrtbased.dll \ build/windows/Win32/vc_redist.x86.exe \ build/windows/Win32/vcruntime140d.dll @@ -6961,6 +6962,7 @@ EXTRAS_TARGETS_WIN_X64 = \ build/windows/x64/python_d.exe \ build/windows/x64/pythonw.exe \ build/windows/x64/pythonw_d.exe \ + build/windows/x64/ucrtbased.dll \ build/windows/x64/vc_redist.x64.exe \ build/windows/x64/vcruntime140_1d.dll \ build/windows/x64/vcruntime140d.dll diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 7c328b11..dbe76f1f 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -287,10 +287,13 @@ def _sync_windows_extras(cfg: Config) -> None: if cfg.debug: if cfg.win_platform == 'x64': toplevelfiles += [ - 'msvcp140d.dll', 'vcruntime140d.dll', 'vcruntime140_1d.dll' + 'msvcp140d.dll', 'vcruntime140d.dll', 'vcruntime140_1d.dll', + 'ucrtbased.dll' ] else: - toplevelfiles += ['msvcp140d.dll', 'vcruntime140d.dll'] + toplevelfiles += [ + 'msvcp140d.dll', 'vcruntime140d.dll', 'ucrtbased.dll' + ] # Include the runtime redistributables in release builds. if not cfg.debug: From 04480157c32ec2dec372d9b05e65f25e6f1607d0 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Sun, 2 Aug 2020 12:34:28 +0300 Subject: [PATCH 181/417] New meta-tag '# ba_meta export keyboard' --- .idea/dictionaries/roman.xml | 7 + assets/.asset_manifest_public.json | 4 + assets/Makefile | 4 + assets/src/ba_data/python/ba/__init__.py | 1 + assets/src/ba_data/python/ba/_keyboard.py | 50 +++++ assets/src/ba_data/python/ba/_meta.py | 3 + .../python/bastd/ui/onscreenkeyboard.py | 192 +++++++++--------- assets/src/ba_data/python/keyboards.py | 61 ++++++ 8 files changed, 230 insertions(+), 92 deletions(-) create mode 100644 .idea/dictionaries/roman.xml create mode 100644 assets/src/ba_data/python/ba/_keyboard.py create mode 100644 assets/src/ba_data/python/keyboards.py diff --git a/.idea/dictionaries/roman.xml b/.idea/dictionaries/roman.xml new file mode 100644 index 00000000..120dcfa0 --- /dev/null +++ b/.idea/dictionaries/roman.xml @@ -0,0 +1,7 @@ + + + + maxlen + + + \ No newline at end of file diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index e6bc81ae..ecfa5dee 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -1,4 +1,5 @@ [ + "ba_data/python/__pycache__/keyboards.cpython-38.opt-1.pyc", "ba_data/python/ba/__init__.py", "ba_data/python/ba/__pycache__/__init__.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_account.cpython-38.opt-1.pyc", @@ -28,6 +29,7 @@ "ba_data/python/ba/__pycache__/_general.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_hooks.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_input.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_keyboard.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_lang.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_level.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_lobby.cpython-38.opt-1.pyc", @@ -87,6 +89,7 @@ "ba_data/python/ba/_general.py", "ba_data/python/ba/_hooks.py", "ba_data/python/ba/_input.py", + "ba_data/python/ba/_keyboard.py", "ba_data/python/ba/_lang.py", "ba_data/python/ba/_level.py", "ba_data/python/ba/_lobby.py", @@ -497,6 +500,7 @@ "ba_data/python/efro/json.py", "ba_data/python/efro/terminal.py", "ba_data/python/efro/util.py", + "ba_data/python/keyboards.py", "server/__pycache__/ballisticacore_server.cpython-38.opt-1.pyc", "server/ballisticacore_server.py" ] \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 31615346..037d59b8 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -177,6 +177,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_general.py \ build/ba_data/python/ba/_hooks.py \ build/ba_data/python/ba/_input.py \ + build/ba_data/python/ba/_keyboard.py \ build/ba_data/python/ba/_lang.py \ build/ba_data/python/ba/_level.py \ build/ba_data/python/ba/_lobby.py \ @@ -380,6 +381,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/bastd/ui/trophies.py \ build/ba_data/python/bastd/ui/url.py \ build/ba_data/python/bastd/ui/watch.py \ + build/ba_data/python/keyboards.py \ build/server/ballisticacore_server.py SCRIPT_TARGETS_PYC_PUBLIC = \ @@ -411,6 +413,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_general.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_hooks.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_input.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_keyboard.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_lang.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_level.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_lobby.cpython-38.opt-1.pyc \ @@ -614,6 +617,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/url.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/watch.cpython-38.opt-1.pyc \ + build/ba_data/python/__pycache__/keyboards.cpython-38.opt-1.pyc \ build/server/__pycache__/ballisticacore_server.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 6fa61a4c..a511f9c1 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -78,6 +78,7 @@ from ba._gameutils import (GameTip, animate, animate_array, show_damage_count, timestring, cameraflash) from ba._general import (WeakCall, Call, existing, Existable, verify_object_death, storagename) +from ba._keyboard import Keyboard from ba._level import Level from ba._lobby import Lobby, Chooser from ba._math import normalized_color, is_point_in_box, vec3validate diff --git a/assets/src/ba_data/python/ba/_keyboard.py b/assets/src/ba_data/python/ba/_keyboard.py new file mode 100644 index 00000000..3b703a0d --- /dev/null +++ b/assets/src/ba_data/python/ba/_keyboard.py @@ -0,0 +1,50 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""On-screen Keyboard related functionality.""" + +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing import List, Tuple, Dict + + +class Keyboard: + """Chars definitions for on-screen keyboard. + + Category: App Classes + + Keyboards are discoverable by the meta-tag system + and the user can select which one they want to use. + On-screen keyboard uses chars from active ba.Keyboard. + Attributes: + chars + Used for row/column lengths. + pages + Extra chars like emojis. + nums + The 'num' page. + """ + + chars: List[Tuple[str, ...]] + pages: Dict[str, Tuple[str, ...]] + nums: Tuple[str, ...] diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index ecc5d727..684bf9e9 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -46,6 +46,7 @@ class ScanResults: """Final results from a metadata scan.""" games: List[str] = field(default_factory=list) plugins: List[str] = field(default_factory=list) + keyboards: List[str] = field(default_factory=list) errors: str = '' warnings: str = '' @@ -289,6 +290,8 @@ class DirectoryScan: self.results.games.append(classname) elif exporttype == 'plugin': self.results.plugins.append(classname) + elif exporttype == 'keyboard': + self.results.keyboards.append(classname) else: self.results.warnings += ( 'Warning: ' + str(subpath) + diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index a87af751..3e3d9990 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -37,8 +37,6 @@ class OnScreenKeyboardWindow(ba.Window): """Simple built-in on-screen keyboard.""" def __init__(self, textwidget: ba.Widget, label: str, max_chars: int): - # pylint: disable=too-many-locals - # pylint: disable=too-many-statements self._target_text = textwidget self._width = 700 self._height = 400 @@ -88,22 +86,44 @@ class OnScreenKeyboardWindow(ba.Window): force_internal_editing=True, always_show_carat=True) - self._shift_button = None - self._double_press_shift = False - self._num_mode_button = None - self._emoji_button = None - self._char_keys: List[ba.Widget] = [] - self._mode = 'normal' - self._last_mode = 'normal' - - v = self._height - 180 - key_width = 46 - key_height = 46 self._key_color_lit = (1.4, 1.2, 1.4) - self._key_color = key_color = (0.69, 0.6, 0.74) - self._key_color_dark = key_color_dark = (0.55, 0.55, 0.71) + self._key_color = (0.69, 0.6, 0.74) + self._key_color_dark = (0.55, 0.55, 0.71) + + self._shift_button: Optional[ba.Widget] = None + self._backspace_button: Optional[ba.Widget] = None + self._space_button: Optional[ba.Widget] = None + self._double_press_shift = False + self._num_mode_button: Optional[ba.Widget] = None + self._emoji_button: Optional[ba.Widget] = None + self._char_keys: List[ba.Widget] = [] + self._keyboard_index = 0 + self._last_space_press = 0.0 + self._double_space_interval = 0.3 + + self._keyboard: ba.Keyboard + self._chars: List[str] + self._modes: List[str] + self._mode: str + self._mode_index: int + self._load_keyboard() + + def _load_keyboard(self) -> None: + # pylint: disable=too-many-locals + self._keyboard = self._get_keyboard() + # We want to get just chars without column data, etc. + self._chars = [j for i in self._keyboard.chars for j in i] + self._modes = ['normal'] + list(self._keyboard.pages) + self._mode_index = 0 + self._mode = self._modes[self._mode_index] + + v = self._height - 180.0 + key_width = 46 * 10 / len(self._keyboard.chars[0]) + key_height = 46 * 3 / len(self._keyboard.chars) key_textcolor = (1, 1, 1) - row_starts = (69, 95, 151) + row_starts = (69.0, 95.0, 151.0) + key_color = self._key_color + key_color_dark = self._key_color_dark self._click_sound = ba.getsound('click01') @@ -114,16 +134,12 @@ class OnScreenKeyboardWindow(ba.Window): # dummy data just used for row/column lengths... we don't actually # set things until refresh - chars: List[Tuple[str, ...]] = [ - ('q', 'u', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'), - ('a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'), - ('z', 'x', 'c', 'v', 'b', 'n', 'm') - ] + chars: List[Tuple[str, ...]] = self._keyboard.chars for row_num, row in enumerate(chars): h = row_starts[row_num] # shift key before row 3 - if row_num == 2: + if row_num == 2 and self._shift_button is None: self._shift_button = ba.buttonwidget( parent=self._root_widget, position=(h - key_width * 2.0, v), @@ -155,17 +171,21 @@ class OnScreenKeyboardWindow(ba.Window): # Add delete key at end of third row. if row_num == 2: - ba.buttonwidget(parent=self._root_widget, - position=(h + 4, v), - size=(key_width * 1.8, key_height), - autoselect=True, - enable_sound=False, - repeat=True, - textcolor=key_textcolor, - color=key_color_dark, - label=charstr(SpCh.DELETE), - button_type='square', - on_activate_call=self._del) + if self._backspace_button is not None: + self._backspace_button.delete() + + self._backspace_button = ba.buttonwidget( + parent=self._root_widget, + position=(h + 4, v), + size=(key_width * 1.8, key_height), + autoselect=True, + enable_sound=False, + repeat=True, + textcolor=key_textcolor, + color=key_color_dark, + label=charstr(SpCh.DELETE), + button_type='square', + on_activate_call=self._del) v -= (key_height + 9) # Do space bar and stuff. if row_num == 2: @@ -196,17 +216,19 @@ class OnScreenKeyboardWindow(ba.Window): button_type='square', ) btn1 = self._num_mode_button - btn2 = ba.buttonwidget(parent=self._root_widget, - position=(210, v - 12), - size=(key_width * 6.1, key_height + 15), - extra_touch_border_scale=0.3, - enable_sound=False, - autoselect=True, - textcolor=key_textcolor, - color=key_color_dark, - label=ba.Lstr(resource='spaceKeyText'), - on_activate_call=ba.Call( - self._type_char, ' ')) + if self._space_button is None: + self._space_button = ba.buttonwidget( + parent=self._root_widget, + position=(210, v - 12), + size=(key_width * 6.1, key_height + 15), + extra_touch_border_scale=0.3, + enable_sound=False, + autoselect=True, + textcolor=key_textcolor, + color=key_color_dark, + label=ba.Lstr(resource='spaceKeyText'), + on_activate_call=ba.Call(self._type_char, ' ')) + btn2 = self._space_button btn3 = self._emoji_button ba.widget(edit=btn1, right_widget=btn2, left_widget=btn3) ba.widget(edit=btn2, @@ -220,14 +242,19 @@ class OnScreenKeyboardWindow(ba.Window): self._refresh() + def _get_keyboard(self) -> ba.Keyboard: + assert ba.app.metascan is not None + path = ba.app.metascan.keyboards[self._keyboard_index] + classname = path.split('.')[-1] + module = path[:-len(classname) - 1] + keyboard = getattr(__import__(module), classname) + assert isinstance(keyboard, ba.Keyboard) + return keyboard + def _refresh(self) -> None: chars: Optional[List[str]] = None if self._mode in ['normal', 'caps']: - chars = [ - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', - 'n', 'm' - ] + chars = list(self._chars) if self._mode == 'caps': chars = [c.upper() for c in chars] ba.buttonwidget(edit=self._shift_button, @@ -241,13 +268,12 @@ class OnScreenKeyboardWindow(ba.Window): ba.buttonwidget(edit=self._emoji_button, color=self._key_color_dark, label=charstr(SpCh.LOGO_FLAT), - on_activate_call=self._emoji_mode) - elif self._mode == 'num': - chars = [ - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '/', - ':', ';', '(', ')', '$', '&', '@', '"', '.', ',', '?', '!', - '\'', '_' - ] + on_activate_call=self._next_mode) + else: + if self._mode == 'num': + chars = list(self._keyboard.nums) + else: + chars = list(self._keyboard.pages[self._mode]) ba.buttonwidget(edit=self._shift_button, color=self._key_color_dark, label='', @@ -258,29 +284,7 @@ class OnScreenKeyboardWindow(ba.Window): ba.buttonwidget(edit=self._emoji_button, color=self._key_color_dark, label=charstr(SpCh.LOGO_FLAT), - on_activate_call=self._emoji_mode) - - elif self._mode in ['emoji', 'emoji2']: - chars = [ - '💣', '💥', '🙂', '😄', '😆', '😅', '😂', '☺', '😀', '😉', '😇', '😎', - '😰', '😠', '😈', '😨', '😛', '😜', 'ðŸ˜', 'ðŸ˜', '😑', '😵', '😬', '😡', - '😌', 'ðŸ˜' - ] - if self._mode == 'emoji2': - chars = [ - '😔', '😥', '😭', '😖', '😓', '😉', '😴', '😷', '👋', '💯', 'ðŸ™', '💪', - '👀', '💬', '💀', '☠', '💩', '👻', '👽', '👾', 'â¤', '💛', '💚', '💙', - '💜', '💔' - ] - ba.buttonwidget(edit=self._shift_button, - color=self._key_color_lit if self._mode == 'emoji2' - else self._key_color_dark, - label=charstr(SpCh.SHIFT), - on_activate_call=self._emoji_mode_2) - ba.buttonwidget(edit=self._emoji_button, - color=self._key_color_lit, - label=charstr(SpCh.LOGO_FLAT), - on_activate_call=self._emoji_mode) + on_activate_call=self._next_mode) for i, btn in enumerate(self._char_keys): assert chars is not None @@ -302,22 +306,17 @@ class OnScreenKeyboardWindow(ba.Window): self._mode = 'num' self._refresh() - def _emoji_mode(self) -> None: + def _next_mode(self) -> None: ba.playsound(self._click_sound) - if self._mode in ['normal', 'caps', 'num']: - self._last_mode = self._mode - self._mode = 'emoji' - elif self._mode == 'emoji' or self._mode == 'emoji2': - self._mode = self._last_mode + self._mode_index = (self._mode_index + 1) % len(self._modes) + self._mode = self._modes[self._mode_index] self._refresh() - def _emoji_mode_2(self) -> None: - ba.playsound(self._click_sound) - if self._mode == 'emoji': - self._mode = 'emoji2' - elif self._mode == 'emoji2': - self._mode = 'emoji' - self._refresh() + def _next_keyboard(self) -> None: + assert ba.app.metascan is not None + self._keyboard_index = (self._keyboard_index + 1) % len( + ba.app.metascan.keyboards) + self._load_keyboard() def _shift(self) -> None: ba.playsound(self._click_sound) @@ -340,6 +339,15 @@ class OnScreenKeyboardWindow(ba.Window): def _type_char(self, char: str) -> None: ba.playsound(self._click_sound) + if char.isspace(): + if (ba.time(ba.TimeType.REAL) - self._last_space_press < + self._double_space_interval): + self._last_space_press = 0 + self._next_keyboard() + self._del() # We typed unneeded space around 1s ago. + return + self._last_space_press = ba.time(ba.TimeType.REAL) + # operate in unicode so we don't do anything funky like chop utf-8 # chars in half txt = cast(str, ba.textwidget(query=self._text_field)) diff --git a/assets/src/ba_data/python/keyboards.py b/assets/src/ba_data/python/keyboards.py new file mode 100644 index 00000000..abcad17b --- /dev/null +++ b/assets/src/ba_data/python/keyboards.py @@ -0,0 +1,61 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- +"""Defines a default keyboards.""" + +# ba_meta require api 6 +# (see https://ballistica.net/wiki/meta-tag-system) + +from __future__ import annotations + +from typing import TYPE_CHECKING + +import ba + +if TYPE_CHECKING: + from typing import Iterable, List + + +def split(chars: Iterable[ba.SpecialChar], + maxlen: int) -> List[List[ba.SpecialChar]]: + """Returns ba.SpecialChar groups with a fixed number of elements""" + result = [] + shatter: List[ba.SpecialChar] = [] + for i in chars: + if len(shatter) < maxlen: + shatter.append(i) + else: + result.append(shatter) + shatter = [i] + return result + + +# ba_meta export keyboard +class EnglishKeyboard(ba.Keyboard): + """Default English keyboard.""" + chars = [('q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'), + ('a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'), + ('z', 'x', 'c', 'v', 'b', 'n', 'm')] + nums = ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '/', ':', + ';', '(', ')', '$', '&', '@', '"', '.', ',', '?', '!', '\'', '_') + pages = { + f'emoji{i}': tuple(ba.charstr(char) for char in page) + for i, page in enumerate(split(ba.SpecialChar, len(nums))) + } From 3919cfbe379e84ac7ec69fd963a6319705916287 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Sun, 2 Aug 2020 12:57:39 +0300 Subject: [PATCH 182/417] remove built-in special chars from keyboard --- assets/src/ba_data/python/keyboards.py | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/assets/src/ba_data/python/keyboards.py b/assets/src/ba_data/python/keyboards.py index abcad17b..79647195 100644 --- a/assets/src/ba_data/python/keyboards.py +++ b/assets/src/ba_data/python/keyboards.py @@ -30,21 +30,7 @@ from typing import TYPE_CHECKING import ba if TYPE_CHECKING: - from typing import Iterable, List - - -def split(chars: Iterable[ba.SpecialChar], - maxlen: int) -> List[List[ba.SpecialChar]]: - """Returns ba.SpecialChar groups with a fixed number of elements""" - result = [] - shatter: List[ba.SpecialChar] = [] - for i in chars: - if len(shatter) < maxlen: - shatter.append(i) - else: - result.append(shatter) - shatter = [i] - return result + from typing import Dict, Tuple # ba_meta export keyboard @@ -55,7 +41,4 @@ class EnglishKeyboard(ba.Keyboard): ('z', 'x', 'c', 'v', 'b', 'n', 'm')] nums = ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '/', ':', ';', '(', ')', '$', '&', '@', '"', '.', ',', '?', '!', '\'', '_') - pages = { - f'emoji{i}': tuple(ba.charstr(char) for char in page) - for i, page in enumerate(split(ba.SpecialChar, len(nums))) - } + pages: Dict[str, Tuple[str, ...]] = {} From 6a2471cf773d056829ef34a82c15e8f14ad6990e Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Sun, 2 Aug 2020 14:26:49 +0300 Subject: [PATCH 183/417] fix --- assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 3e3d9990..b5061621 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -30,7 +30,7 @@ from ba import charstr from ba import SpecialChar as SpCh if TYPE_CHECKING: - from typing import List, Tuple, Optional + from typing import List, Tuple, Optional, Type class OnScreenKeyboardWindow(ba.Window): @@ -242,13 +242,13 @@ class OnScreenKeyboardWindow(ba.Window): self._refresh() - def _get_keyboard(self) -> ba.Keyboard: + def _get_keyboard(self) -> Type[ba.Keyboard]: assert ba.app.metascan is not None path = ba.app.metascan.keyboards[self._keyboard_index] classname = path.split('.')[-1] module = path[:-len(classname) - 1] keyboard = getattr(__import__(module), classname) - assert isinstance(keyboard, ba.Keyboard) + assert issubclass(keyboard, ba.Keyboard) return keyboard def _refresh(self) -> None: From 448eafd13fc0efd7caa0729c6060ef3d4e43793c Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Sun, 2 Aug 2020 15:28:11 +0300 Subject: [PATCH 184/417] type-checking fix --- assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index b5061621..1ca2d0ba 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -30,7 +30,7 @@ from ba import charstr from ba import SpecialChar as SpCh if TYPE_CHECKING: - from typing import List, Tuple, Optional, Type + from typing import List, Tuple, Optional class OnScreenKeyboardWindow(ba.Window): @@ -242,13 +242,13 @@ class OnScreenKeyboardWindow(ba.Window): self._refresh() - def _get_keyboard(self) -> Type[ba.Keyboard]: + def _get_keyboard(self) -> ba.Keyboard: assert ba.app.metascan is not None path = ba.app.metascan.keyboards[self._keyboard_index] classname = path.split('.')[-1] module = path[:-len(classname) - 1] - keyboard = getattr(__import__(module), classname) - assert issubclass(keyboard, ba.Keyboard) + keyboard = getattr(__import__(module), classname)() + assert isinstance(keyboard, ba.Keyboard) return keyboard def _refresh(self) -> None: From 2552dd07679333d372170c054033cb5558abf3ad Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 2 Aug 2020 16:19:30 -0700 Subject: [PATCH 185/417] Added _ba.can_display_full_unicode() --- .efrocachemap | 24 ++++++++++++------------ .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 3 ++- assets/src/ba_data/python/_ba.py | 11 +++++++++++ assets/src/ba_data/python/ba/_app.py | 2 +- docs/ba_module.md | 2 +- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 1192d95d..ea216131 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3927,16 +3927,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/b6/9438d9e41b904ee9eae03cf75c6a", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fa/69/648eaa2307e930481d970a9a32db", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/46/f8/bc3c101d36d1bb1c47d938ca8d0b", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/00/8c/6d078695eab35493bd0cfd2d3523", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/77/88/8c0de232370da88bff994864423c", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b0/4a/4b393c9ebb03e57fbc9030d4a501", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/16/e1/6e24960e5d0bdccc103ec8f85f37", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/eb/77425b1f9f65f9aa081a5851ea24", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/81/8e/0a81b48a997ae8d2a928ee23b950", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/70/32/de7a5b3c0b1afceaf2e6bc1a3441", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/25/25/9abf87f1717182796a362b733ae3", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9d/fe/b6ae85178385d36d35aad37e584e" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/b4/93f8ac61e4b0fad27790b896a79c", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/fe/9e8a1711d318c8f446ce42e2c8b4", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/47/ca91d44facaca3201e8b82f487ed", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/bc/97857879f57276567e99db0351dc", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/55/54/9725e0bb80d6fbb67e8033eb36a6", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/86/aa9ca99515ffa5676c960245659f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/59/1a087718dbcdde6ffd17aa0b2bfa", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ce/aa/17c53dbb9513d5ef3b8c0ccde6cf", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b5/a5/762949cfbeed5695589f64935731", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8b/dd/649721def17a01fb687472104826", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/82/0c/0a18430efea41ac56987472aa8ec", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/78/5d/00a738e0c764f0cc2427c5efe2f0" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 352971d3..79fa7d9d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -2091,6 +2091,7 @@ tzinfos uadfc uber + ucrtbased ugrade uibounds uicleanup diff --git a/CHANGELOG.md b/CHANGELOG.md index 96a2fbc0..5a59c5d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ -### 1.5.24 (20160) +### 1.5.24 (20161) - Upgraded Python from version 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now.. - Windows debug builds now use Python debug libraries. This should hopefully catch more errors that would otherwise go undetected and potentially cause crashes. - Switched windows builds to use 'fast' mode math instead of 'strict'. This should make the game run more efficiently (similar modes are already in use on other platforms) but holler if any odd breakage happens such as things falling through floors (more often than the occasional random fluke-y case that happens now). +- Added _ba.can_display_full_unicode() for any code that wants to avoid printing things that won't show up locally. ### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 9ead9791..597b13fa 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -1357,6 +1357,9 @@ def appnameupper() -> str: """appnameupper() -> str (internal) + + Return whether this build of the game can display full unicode such as + Emoji, Asian languages, etc. """ return str() @@ -1478,6 +1481,14 @@ def camerashake(intensity: float = 1.0) -> None: return None +def can_display_full_unicode() -> bool: + """can_display_full_unicode() -> bool + + (internal) + """ + return bool() + + def can_show_ad() -> bool: """can_show_ad() -> bool diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index d3265d40..611189b3 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -88,7 +88,7 @@ class App: if (language in { 'Chinese', 'ChineseTraditional', 'Persian', 'Korean', 'Arabic', 'Hindi', 'Vietnamese' - } and self.platform in ('windows', 'linux')): + } and not _ba.can_display_full_unicode()): return False return True diff --git a/docs/ba_module.md b/docs/ba_module.md index 33ec1b98..e2ea8d1f 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-07-28 for Ballistica version 1.5.24 build 20159

    +

    last updated on 2020-08-02 for Ballistica version 1.5.24 build 20160

    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!


    From 9b041fe51afe76b5d256f33c50e8f2fc99dd9a32 Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Mon, 3 Aug 2020 11:11:29 +0300 Subject: [PATCH 186/417] add standard emojis and some screen messages --- assets/src/ba_data/python/ba/_keyboard.py | 3 ++ .../python/bastd/ui/onscreenkeyboard.py | 12 +++++++ assets/src/ba_data/python/keyboards.py | 33 +++++++++++++++++-- 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/assets/src/ba_data/python/ba/_keyboard.py b/assets/src/ba_data/python/ba/_keyboard.py index 3b703a0d..04d627f0 100644 --- a/assets/src/ba_data/python/ba/_keyboard.py +++ b/assets/src/ba_data/python/ba/_keyboard.py @@ -37,6 +37,8 @@ class Keyboard: and the user can select which one they want to use. On-screen keyboard uses chars from active ba.Keyboard. Attributes: + name + Displays when user selecting this keyboard. chars Used for row/column lengths. pages @@ -45,6 +47,7 @@ class Keyboard: The 'num' page. """ + name: str chars: List[Tuple[str, ...]] pages: Dict[str, Tuple[str, ...]] nums: Tuple[str, ...] diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 1ca2d0ba..53ab84c2 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -228,6 +228,12 @@ class OnScreenKeyboardWindow(ba.Window): color=key_color_dark, label=ba.Lstr(resource='spaceKeyText'), on_activate_call=ba.Call(self._type_char, ' ')) + ba.textwidget(parent=self._root_widget, + h_align='center', + position=(210, v - 70), + size=(key_width * 6.1, key_height + 15), + text='Double press space to change keyboard', + scale=0.75) btn2 = self._space_button btn3 = self._emoji_button ba.widget(edit=btn1, right_widget=btn2, left_widget=btn3) @@ -317,6 +323,12 @@ class OnScreenKeyboardWindow(ba.Window): self._keyboard_index = (self._keyboard_index + 1) % len( ba.app.metascan.keyboards) self._load_keyboard() + if len(ba.app.metascan.keyboards) < 2: + ba.playsound(ba.getsound('error')) + ba.screenmessage('No other keyboards available', color=(1, 0, 0)) + else: + ba.screenmessage(f'Switching keyboard to "{self._keyboard.name}"', + color=(0, 1, 0)) def _shift(self) -> None: ba.playsound(self._click_sound) diff --git a/assets/src/ba_data/python/keyboards.py b/assets/src/ba_data/python/keyboards.py index 79647195..12d49560 100644 --- a/assets/src/ba_data/python/keyboards.py +++ b/assets/src/ba_data/python/keyboards.py @@ -30,15 +30,44 @@ from typing import TYPE_CHECKING import ba if TYPE_CHECKING: - from typing import Dict, Tuple + from typing import Iterable, List, Tuple, Dict + + +def split(chars: Iterable[str], maxlen: int) -> List[List[str]]: + """Returns char groups with a fixed number of elements""" + result = [] + shatter: List[str] = [] + for i in chars: + if len(shatter) < maxlen: + shatter.append(i) + else: + result.append(shatter) + shatter = [i] + if shatter: + while len(shatter) < maxlen: + shatter.append('') + result.append(shatter) + return result + + +def generate_emojis(maxlen: int) -> List[List[str]]: + """Generates a lot of UTF8 emojis prepared for ba.Keyboard pages""" + all_emojis = split([chr(i) for i in range(0x1F601, 0x1F650)], maxlen) + all_emojis += split([chr(i) for i in range(0x2702, 0x27B1)], maxlen) + all_emojis += split([chr(i) for i in range(0x1F680, 0x1F6C1)], maxlen) + return all_emojis # ba_meta export keyboard class EnglishKeyboard(ba.Keyboard): """Default English keyboard.""" + name = 'English' chars = [('q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'), ('a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l'), ('z', 'x', 'c', 'v', 'b', 'n', 'm')] nums = ('1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '/', ':', ';', '(', ')', '$', '&', '@', '"', '.', ',', '?', '!', '\'', '_') - pages: Dict[str, Tuple[str, ...]] = {} + pages: Dict[str, Tuple[str, ...]] = { + f'emoji{i}': tuple(page) + for i, page in enumerate(generate_emojis(len(nums))) + } From 12f9762a14d17e0cadc70c360af26c9279c2aadf Mon Sep 17 00:00:00 2001 From: Roman Trapeznikov Date: Mon, 3 Aug 2020 12:42:09 +0300 Subject: [PATCH 187/417] fix #145 --- assets/src/ba_data/python/ba/_meta.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index ecc5d727..e9f3853b 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -246,7 +246,8 @@ class DirectoryScan: submodules: List[Tuple[pathlib.Path, pathlib.Path]] = [] self._get_path_module_entries(moduledir, subpath, submodules) for submodule in submodules: - self.scan_module(submodule[0], submodule[1]) + if submodule[1].name != '__init__.py': + self.scan_module(submodule[0], submodule[1]) except Exception: import traceback self.results.warnings += ( From e6143fc33c8904ef73f0933771baaa7a855bcf62 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 3 Aug 2020 11:24:38 -0700 Subject: [PATCH 188/417] Syncing latest changes between public/private. --- .idea/dictionaries/ericf.xml | 16 ++++++++++++++++ CHANGELOG.md | 1 + assets/src/ba_data/python/_ba.py | 3 +-- assets/src/ba_data/python/ba/_actor.py | 4 +--- assets/src/ba_data/python/ba/_general.py | 3 +-- .../ba_data/python/bastd/actor/onscreentimer.py | 3 +-- .../src/ba_data/python/bastd/actor/playerspaz.py | 3 +-- config/toolconfigsrc/pylintrc | 2 +- docs/ba_module.md | 2 +- tools/batools/build.py | 4 ++-- tools/efro/entity/util.py | 5 +++-- tools/efrotools/__init__.py | 3 +-- tools/efrotools/pcommand.py | 12 ++++++++---- 13 files changed, 38 insertions(+), 23 deletions(-) diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 79fa7d9d..f280d478 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -30,6 +30,7 @@ achs acinstance ack + ack'ed acked acks acnt @@ -149,6 +150,7 @@ badguy bafoundation ballistica + ballistica's ballisticacore ballisticacorecb bamaster @@ -204,6 +206,7 @@ bools bootlocale borhani + bot's botdist botlist botpos @@ -607,6 +610,7 @@ etsel etxt etype + eval'ed evalpydata evel eventid @@ -631,6 +635,10 @@ extrahash extrascale exts + f'baseval + f'chmod + f'final + f'fixme factoryclass fakemodule fallbacks @@ -772,6 +780,7 @@ gameinstance gamemap gamepad + gamepad's gamepadadvanced gamepads gamepadselect @@ -1141,6 +1150,7 @@ lssl lstart lstr + lstr's lstrs lsval ltex @@ -1337,6 +1347,7 @@ nvcompress nvidia nyko + obj's objname objs objt @@ -1578,6 +1589,7 @@ pybee pybuild pycache + pycharm's pycharmbin pycharmfull pycharmroot @@ -1760,6 +1772,7 @@ sessionplayer sessionplayers sessionteam + sessionteam's sessionteams sessiontype setactivity @@ -1906,6 +1919,7 @@ subpath subplatform subplatforms + subprocess's subprocesses subrepos subsel @@ -2016,6 +2030,7 @@ thelaststand themself thingie + this'll threadtype throwiness timedisplay @@ -2084,6 +2099,7 @@ typeargs typecheck typechecker + typechecker's typedval typeshed typestr diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a59c5d8..0be8533b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ - Windows debug builds now use Python debug libraries. This should hopefully catch more errors that would otherwise go undetected and potentially cause crashes. - Switched windows builds to use 'fast' mode math instead of 'strict'. This should make the game run more efficiently (similar modes are already in use on other platforms) but holler if any odd breakage happens such as things falling through floors (more often than the occasional random fluke-y case that happens now). - Added _ba.can_display_full_unicode() for any code that wants to avoid printing things that won't show up locally. +- Now pulling some classes such as Literal and Protocol from typing instead of typing_extensions (they were officially added to Python in 3.8) ### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 597b13fa..9a1493cc 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -54,8 +54,7 @@ from ba._enums import TimeFormat, TimeType if TYPE_CHECKING: from typing import (Any, Dict, Callable, Tuple, List, Optional, Union, - List, Type) - from typing_extensions import Literal + List, Type, Literal) from ba._app import App import ba diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index 6fa9ea57..f70dd780 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -30,9 +30,7 @@ from ba._error import print_exception, ActivityNotFoundError import _ba if TYPE_CHECKING: - from typing import Any, Optional - from typing_extensions import Literal - + from typing import Any, Optional, Literal import ba T = TypeVar('T', bound='Actor') diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 82cc917b..276deb0d 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -26,8 +26,7 @@ import types import weakref import random import inspect -from typing import TYPE_CHECKING, TypeVar -from typing_extensions import Protocol +from typing import TYPE_CHECKING, TypeVar, Protocol from efro.terminal import Clr from ba._error import print_error, print_exception diff --git a/assets/src/ba_data/python/bastd/actor/onscreentimer.py b/assets/src/ba_data/python/bastd/actor/onscreentimer.py index 3facd7e3..560b13be 100644 --- a/assets/src/ba_data/python/bastd/actor/onscreentimer.py +++ b/assets/src/ba_data/python/bastd/actor/onscreentimer.py @@ -26,8 +26,7 @@ from typing import TYPE_CHECKING, overload import ba if TYPE_CHECKING: - from typing import Optional, Union, Any - from typing_extensions import Literal + from typing import Optional, Union, Any, Literal class OnScreenTimer(ba.Actor): diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index 48acc0aa..fde1f1a4 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -28,8 +28,7 @@ import ba from bastd.actor.spaz import Spaz if TYPE_CHECKING: - from typing import Any, Sequence, Tuple, Optional, Type - from typing_extensions import Literal + from typing import Any, Sequence, Tuple, Optional, Type, Literal PlayerType = TypeVar('PlayerType', bound=ba.Player) TeamType = TypeVar('TeamType', bound=ba.Team) diff --git a/config/toolconfigsrc/pylintrc b/config/toolconfigsrc/pylintrc index 154eac9f..cbe6f4f0 100644 --- a/config/toolconfigsrc/pylintrc +++ b/config/toolconfigsrc/pylintrc @@ -62,7 +62,7 @@ disable=broad-except, enable=useless-suppression [BASIC] -# Allowing a handfull of short names commonly understood to be iterators, +# Allowing a handful of short names commonly understood to be iterators, # math concepts, or temporary variables. good-names=i, diff --git a/docs/ba_module.md b/docs/ba_module.md index e2ea8d1f..6cfe17e3 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-02 for Ballistica version 1.5.24 build 20160

    +

    last updated on 2020-08-02 for Ballistica version 1.5.24 build 20162

    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!


    diff --git a/tools/batools/build.py b/tools/batools/build.py index 41f7c100..01fea940 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -47,9 +47,9 @@ class PipRequirement: PIP_REQUIREMENTS = [ PipRequirement(modulename='pylint', minversion=[2, 5, 3]), - PipRequirement(modulename='mypy', minversion=[0, 781]), + PipRequirement(modulename='mypy', minversion=[0, 782]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), - PipRequirement(modulename='cpplint', minversion=[1, 5, 1]), + PipRequirement(modulename='cpplint', minversion=[1, 5, 3]), PipRequirement(modulename='typing_extensions'), PipRequirement(modulename='pytz'), PipRequirement(modulename='yaml', pipname='PyYAML'), diff --git a/tools/efro/entity/util.py b/tools/efro/entity/util.py index 54d18857..8f804b4b 100644 --- a/tools/efro/entity/util.py +++ b/tools/efro/entity/util.py @@ -101,10 +101,11 @@ def have_matching_fields(val1: CompoundValue, val2: CompoundValue) -> bool: Note this just refers to the field configuration; not data. """ - # quick-out: matching types will always have identical fields + # Quick-out: matching types will always have identical fields. if type(val1) is type(val2): return True - # otherwise do a full comparision + + # Otherwise do a full comparison. return val1.get_fields() == val2.get_fields() diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index 9423b213..86b68a57 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -37,8 +37,7 @@ from pathlib import Path from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Dict, Union, Sequence, Optional, Any - from typing_extensions import Literal + from typing import Dict, Union, Sequence, Optional, Any, Literal # Python major version we're using for all this stuff. PYVER = '3.8' diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index 6af449ec..8f7bc855 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -162,10 +162,14 @@ def spelling_all() -> None: capture_output=True).stdout.decode().splitlines() if 'Typo: In word' in line ] - words = [ - line.split('Typo: In word')[1].strip().replace("'", '') - for line in lines - ] + words = [line.split('Typo: In word')[1].strip() for line in lines] + + # Strip enclosing quotes but not internal ones. + for i, word in enumerate(words): + assert word[0] == "'" + assert word[-1] == "'" + words[i] = word[1:-1] + _spelling(words) From 65b6d510def03f00e01171e39c1747cbba22c532 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 3 Aug 2020 12:01:03 -0700 Subject: [PATCH 189/417] Docs update --- docs/ba_module.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/docs/ba_module.md b/docs/ba_module.md index 03663df2..d2f091d9 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -151,6 +151,7 @@
  • ba.AppConfig
  • ba.AppDelegate
  • ba.Campaign
  • +
  • ba.Keyboard
  • ba.MusicPlayer
  • ba.Plugin
  • ba.PotentialPlugin
  • @@ -3039,6 +3040,42 @@ prefs, etc.

    <constructor>

    ba.IntSetting(name: str, default: int, min_value: int = 0, max_value: int = 9999, increment: int = 1)

    +
    +
    +
    +

    ba.Keyboard

    +

    <top level class> +

    +

    Chars definitions for on-screen keyboard.

    + +

    Category: App Classes

    + +

    Keyboards are discoverable by the meta-tag system + and the user can select which one they want to use. + On-screen keyboard uses chars from active ba.Keyboard.

    + +

    Attributes:

    +
    chars, name, nums, pages
    +
    +

    chars

    +

    List[Tuple[str, ...]]

    +

    Used for row/column lengths.

    + +
    +

    name

    +

    str

    +

    Displays when user selecting this keyboard.

    + +
    +

    nums

    +

    Tuple[str, ...]

    +

    The 'num' page.

    + +
    +

    pages

    +

    Dict[str, Tuple[str, ...]]

    +

    Extra chars like emojis.

    +

    From 0a625831ae7d4897ebd326b1be3717f4687682ea Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 3 Aug 2020 13:35:04 -0700 Subject: [PATCH 190/417] Tidying up custom keyboard stuff --- .efrocachemap | 34 +++++++-------- .idea/dictionaries/ericf.xml | 14 ++++--- assets/.asset_manifest_public.json | 6 ++- assets/Makefile | 6 ++- assets/src/ba_data/python/ba/__init__.py | 2 +- assets/src/ba_data/python/ba/_meta.py | 6 +-- .../ba_data/python/bastd/keyboard/__init__.py | 20 +++++++++ .../keyboard/englishkeyboard.py} | 0 .../python/bastd/ui/onscreenkeyboard.py | 42 +++++++++++-------- docs/ba_module.md | 12 ++++++ 10 files changed, 93 insertions(+), 49 deletions(-) create mode 100644 assets/src/ba_data/python/bastd/keyboard/__init__.py rename assets/src/ba_data/python/{keyboards.py => bastd/keyboard/englishkeyboard.py} (100%) diff --git a/.efrocachemap b/.efrocachemap index a9052269..564cbb66 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,20 +420,20 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/cd/7a/dcf7f0f9436884167abdcb126716", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/f7/81/01515c4bef514f45bfe3b8e6566b", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a9/3c/63857b3f5f943205d7a5d8f8e476", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/ea/14/6485c200c717f82cca7c01dee0b3", - "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/a0/ca/b4e3c4ea2c76e462b7e657b2b1c2", + "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/1d/a0/c2b68a77207c0fed98d7cec3b22f", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212", - "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/8b/c6/3fbabe88f18df228f6f2984201a5", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/56/1f/fe2912d87b3af510469dc40bdf85", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/0d/ae/d2df1bf3c2157b4b5302df54622f", - "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/ef/92/4a602f11f6dd3d0310ce98cd5538", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/cb/10/5d94df639e3e0cb405711e1b907f", + "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/fe/33/cead18bf921903f8c6d922017892", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/57/7d/e79791913a06c9c15fec75138e6a", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", @@ -3927,16 +3927,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/b4/93f8ac61e4b0fad27790b896a79c", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/fe/9e8a1711d318c8f446ce42e2c8b4", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/47/ca91d44facaca3201e8b82f487ed", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/bc/97857879f57276567e99db0351dc", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d9/b4/0415d8af3e4904c640991ddd16f9", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d3/86/aa9ca99515ffa5676c960245659f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/22/1fdd6e64721676f8c40fdf8b3e16", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ce/aa/17c53dbb9513d5ef3b8c0ccde6cf", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d5/3b/4e1fc9281cad80d6cbb5aca74761", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3c/79/f6476677ef525451a18c18f120d3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/63/50/b120c428fc03a18adf24c0363985", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c8/1d/a5f65b32cd9a0fac2415b61d6875" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ee/45/cade5b2fd62b09a51257941c7533", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1b/8f/ff4979b5192a38ef1b2ef0ef0875", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5a/2a/ef6ffc7421f21c196872ffa43101", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/08/3b/c5cbdf8034bc872f1aa622a64b58", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/eb/44/cfded3124db547b6a99aa8d7a947", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/30/d6/5d712b546730fed241aa3f5e5498", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/69/d3/7af0c2b55abfa753dd148f7199d9", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/16/70cd1b7b50578910267f91d563aa", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d3/a8/1e79f6258790a886ef14d4df5dd5", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b8/a7/9cb20c8a6cb09880e2cfbbf427cf", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/14/6173a6f6b7588a335f96e8f1f240", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7e/38/cfc24fc3e5e53ffedde3b372eef8" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index f280d478..4d9e7d52 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack ack'ed + ack acked acks acnt @@ -149,8 +149,8 @@ bacommon badguy bafoundation - ballistica ballistica's + ballistica ballisticacore ballisticacorecb bamaster @@ -586,6 +586,7 @@ endmessage endparen endtime + englishkeyboard ensurepip entitylist entrynew @@ -779,8 +780,8 @@ gamedata gameinstance gamemap - gamepad gamepad's + gamepad gamepadadvanced gamepads gamepadselect @@ -1019,6 +1020,7 @@ jsonstrbase jsontools jsonutils + kbclass kbytecount keepaway keeprefs @@ -1149,8 +1151,8 @@ lsqlite lssl lstart - lstr lstr's + lstr lstrs lsval ltex @@ -1771,8 +1773,8 @@ sessionname sessionplayer sessionplayers - sessionteam sessionteam's + sessionteam sessionteams sessiontype setactivity @@ -2098,8 +2100,8 @@ txtw typeargs typecheck - typechecker typechecker's + typechecker typedval typeshed typestr diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index ecfa5dee..cb611882 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -1,5 +1,4 @@ [ - "ba_data/python/__pycache__/keyboards.cpython-38.opt-1.pyc", "ba_data/python/ba/__init__.py", "ba_data/python/ba/__pycache__/__init__.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_account.cpython-38.opt-1.pyc", @@ -240,6 +239,10 @@ "ba_data/python/bastd/game/targetpractice.py", "ba_data/python/bastd/game/thelaststand.py", "ba_data/python/bastd/gameutils.py", + "ba_data/python/bastd/keyboard/__init__.py", + "ba_data/python/bastd/keyboard/__pycache__/__init__.cpython-38.opt-1.pyc", + "ba_data/python/bastd/keyboard/__pycache__/englishkeyboard.cpython-38.opt-1.pyc", + "ba_data/python/bastd/keyboard/englishkeyboard.py", "ba_data/python/bastd/mainmenu.py", "ba_data/python/bastd/mapdata/__init__.py", "ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-38.opt-1.pyc", @@ -500,7 +503,6 @@ "ba_data/python/efro/json.py", "ba_data/python/efro/terminal.py", "ba_data/python/efro/util.py", - "ba_data/python/keyboards.py", "server/__pycache__/ballisticacore_server.cpython-38.opt-1.pyc", "server/ballisticacore_server.py" ] \ No newline at end of file diff --git a/assets/Makefile b/assets/Makefile index 31bfb63c..ab0997b1 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -263,6 +263,8 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/bastd/game/targetpractice.py \ build/ba_data/python/bastd/game/thelaststand.py \ build/ba_data/python/bastd/gameutils.py \ + build/ba_data/python/bastd/keyboard/__init__.py \ + build/ba_data/python/bastd/keyboard/englishkeyboard.py \ build/ba_data/python/bastd/mainmenu.py \ build/ba_data/python/bastd/mapdata/__init__.py \ build/ba_data/python/bastd/mapdata/big_g.py \ @@ -381,7 +383,6 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/bastd/ui/trophies.py \ build/ba_data/python/bastd/ui/url.py \ build/ba_data/python/bastd/ui/watch.py \ - build/ba_data/python/keyboards.py \ build/server/ballisticacore_server.py SCRIPT_TARGETS_PYC_PUBLIC = \ @@ -499,6 +500,8 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/game/__pycache__/targetpractice.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/game/__pycache__/thelaststand.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/gameutils.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/keyboard/__pycache__/__init__.cpython-38.opt-1.pyc \ + build/ba_data/python/bastd/keyboard/__pycache__/englishkeyboard.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/__pycache__/mainmenu.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/__init__.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/mapdata/__pycache__/big_g.cpython-38.opt-1.pyc \ @@ -617,7 +620,6 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/bastd/ui/__pycache__/trophies.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/url.cpython-38.opt-1.pyc \ build/ba_data/python/bastd/ui/__pycache__/watch.cpython-38.opt-1.pyc \ - build/ba_data/python/__pycache__/keyboards.cpython-38.opt-1.pyc \ build/server/__pycache__/ballisticacore_server.cpython-38.opt-1.pyc # Rule to copy src asset scripts to dst. diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index a511f9c1..808338ed 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -77,7 +77,7 @@ from ba._campaign import Campaign from ba._gameutils import (GameTip, animate, animate_array, show_damage_count, timestring, cameraflash) from ba._general import (WeakCall, Call, existing, Existable, - verify_object_death, storagename) + verify_object_death, storagename, getclass) from ba._keyboard import Keyboard from ba._level import Level from ba._lobby import Lobby, Chooser diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index 9e97ec9e..3e3a8055 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -379,13 +379,13 @@ def get_scan_results() -> ScanResults: def get_game_types() -> List[Type[ba.GameActivity]]: """Return available game types.""" - from ba import _general - from ba import _gameactivity + from ba._general import getclass + from ba._gameactivity import GameActivity gameclassnames = get_scan_results().games gameclasses = [] for gameclassname in gameclassnames: try: - cls = _general.getclass(gameclassname, _gameactivity.GameActivity) + cls = getclass(gameclassname, GameActivity) gameclasses.append(cls) except Exception: from ba import _error diff --git a/assets/src/ba_data/python/bastd/keyboard/__init__.py b/assets/src/ba_data/python/bastd/keyboard/__init__.py new file mode 100644 index 00000000..32622553 --- /dev/null +++ b/assets/src/ba_data/python/bastd/keyboard/__init__.py @@ -0,0 +1,20 @@ +# Copyright (c) 2011-2020 Eric Froemling +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# ----------------------------------------------------------------------------- diff --git a/assets/src/ba_data/python/keyboards.py b/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py similarity index 100% rename from assets/src/ba_data/python/keyboards.py rename to assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 53ab84c2..17a7899a 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -228,12 +228,19 @@ class OnScreenKeyboardWindow(ba.Window): color=key_color_dark, label=ba.Lstr(resource='spaceKeyText'), on_activate_call=ba.Call(self._type_char, ' ')) - ba.textwidget(parent=self._root_widget, - h_align='center', - position=(210, v - 70), - size=(key_width * 6.1, key_height + 15), - text='Double press space to change keyboard', - scale=0.75) + + # Show change instructions only if we have more than one + # keyboard option. + if (ba.app.metascan is not None + and len(ba.app.metascan.keyboards) > 1): + ba.textwidget( + parent=self._root_widget, + h_align='center', + position=(210, v - 70), + size=(key_width * 6.1, key_height + 15), + text=ba.Lstr( + resource='keyboardChangeInstructionsText'), + scale=0.75) btn2 = self._space_button btn3 = self._emoji_button ba.widget(edit=btn1, right_widget=btn2, left_widget=btn3) @@ -250,12 +257,9 @@ class OnScreenKeyboardWindow(ba.Window): def _get_keyboard(self) -> ba.Keyboard: assert ba.app.metascan is not None - path = ba.app.metascan.keyboards[self._keyboard_index] - classname = path.split('.')[-1] - module = path[:-len(classname) - 1] - keyboard = getattr(__import__(module), classname)() - assert isinstance(keyboard, ba.Keyboard) - return keyboard + classname = ba.app.metascan.keyboards[self._keyboard_index] + kbclass = ba.getclass(classname, ba.Keyboard) + return kbclass() def _refresh(self) -> None: chars: Optional[List[str]] = None @@ -325,9 +329,11 @@ class OnScreenKeyboardWindow(ba.Window): self._load_keyboard() if len(ba.app.metascan.keyboards) < 2: ba.playsound(ba.getsound('error')) - ba.screenmessage('No other keyboards available', color=(1, 0, 0)) + ba.screenmessage(ba.Lstr(resource='keyboardNoOthersAvailableText'), + color=(1, 0, 0)) else: - ba.screenmessage(f'Switching keyboard to "{self._keyboard.name}"', + ba.screenmessage(ba.Lstr(resource='keyboardSwitchText', + subs=[('${NAME}', self._keyboard.name)]), color=(0, 1, 0)) def _shift(self) -> None: @@ -360,13 +366,13 @@ class OnScreenKeyboardWindow(ba.Window): return self._last_space_press = ba.time(ba.TimeType.REAL) - # operate in unicode so we don't do anything funky like chop utf-8 - # chars in half + # Operate in unicode so we don't do anything funky like chop utf-8 + # chars in half. txt = cast(str, ba.textwidget(query=self._text_field)) txt += char ba.textwidget(edit=self._text_field, text=txt) - # if we were caps, - # go back only if not Shift is pressed twice + + # If we were caps, go back only if not Shift is pressed twice. if self._mode == 'caps' and not self._double_press_shift: self._mode = 'normal' self._refresh() diff --git a/docs/ba_module.md b/docs/ba_module.md index d2f091d9..0550db84 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -85,6 +85,7 @@
  • ba.charstr()
  • ba.do_once()
  • ba.get_valid_languages()
  • +
  • ba.getclass()
  • ba.is_browser_likely_available()
  • ba.is_point_in_box()
  • ba.log()
  • @@ -6283,6 +6284,17 @@ Activity has since been created or is transitioning in. If there is no current Activity, raises a ba.ActivityNotFoundError. If doraise is False, None will be returned instead in that case.

    +
    +

    ba.getclass()

    +

    getclass(name: str, subclassof: Type[T]) -> Type[T]

    + +

    Given a full class name such as foo.bar.MyClass, return the class.

    + +

    Category: General Utility Functions

    + +

    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.

    +

    ba.getcollidemodel()

    getcollidemodel(name: str) -> ba.CollideModel

    From f4a547f65eacf8e4de510c118e1e21bb4d5b8b3c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 3 Aug 2020 22:44:35 -0700 Subject: [PATCH 191/417] Double clicks now work on widgets under a scroll view on mobile (such as replay list) --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 3 ++- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 564cbb66..e3c62f48 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3927,16 +3927,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ee/45/cade5b2fd62b09a51257941c7533", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1b/8f/ff4979b5192a38ef1b2ef0ef0875", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5a/2a/ef6ffc7421f21c196872ffa43101", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/08/3b/c5cbdf8034bc872f1aa622a64b58", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/eb/44/cfded3124db547b6a99aa8d7a947", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/30/d6/5d712b546730fed241aa3f5e5498", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/69/d3/7af0c2b55abfa753dd148f7199d9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/16/70cd1b7b50578910267f91d563aa", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/d3/a8/1e79f6258790a886ef14d4df5dd5", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b8/a7/9cb20c8a6cb09880e2cfbbf427cf", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/14/6173a6f6b7588a335f96e8f1f240", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7e/38/cfc24fc3e5e53ffedde3b372eef8" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c1/bd/ada4f12eadaa33f3fcf4f1b70ede", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/85/c4389f7f89b870b1685e9eed5eec", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/26/962a1518a29fe8f1c1048b574c35", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6d/e6/2fb6f02fac2a8c7ffc1f3ebf4786", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/23/0a8a3bfafae095b36c48ef826d59", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/0b/755d9f57d38ce4de022d3909ed1c", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/d9/eb3090c2c4369d13ce6c1bff48f7", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5d/bd/70427b399c0f72820c7e9dbeafd2", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/4a/5d2a7076414166d9aae182b533bf", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6f/d0/efaab1edd0f58c4db8c7fcbe8a3d", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/ad/cb58f2d0d615be118112ffd2f9fd", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b7/42/ba5e352389b4069228d49089bdf2" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0be8533b..81b04c29 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ -### 1.5.24 (20161) +### 1.5.24 (20163) - Upgraded Python from version 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now.. - Windows debug builds now use Python debug libraries. This should hopefully catch more errors that would otherwise go undetected and potentially cause crashes. - Switched windows builds to use 'fast' mode math instead of 'strict'. This should make the game run more efficiently (similar modes are already in use on other platforms) but holler if any odd breakage happens such as things falling through floors (more often than the occasional random fluke-y case that happens now). - Added _ba.can_display_full_unicode() for any code that wants to avoid printing things that won't show up locally. - Now pulling some classes such as Literal and Protocol from typing instead of typing_extensions (they were officially added to Python in 3.8) +- Double taps/clicks now work properly on widgets nested under a scroll-widget on mobile (so, for example, replays can now be double-clicked to view them) ### 1.5.23 (20146) - Fixed the shebang line in `bombsquad_server` file by using `-S` flag for `/usr/bin/env`. From 3c55923f55402114e2ffb4df393264271fa96052 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 4 Aug 2020 14:34:37 -0700 Subject: [PATCH 192/417] Language Updates --- .efrocachemap | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e3c62f48..93c29242 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,37 +420,37 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/f7/81/01515c4bef514f45bfe3b8e6566b", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/90/18/f6865956be7b13e7b8cdc6a3f06c", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a9/3c/63857b3f5f943205d7a5d8f8e476", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/ea/14/6485c200c717f82cca7c01dee0b3", - "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/1d/a0/c2b68a77207c0fed98d7cec3b22f", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/45/68/29dd2936391a747f99227423675b", + "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/d1/96/688ec16a817f34509e69109a431d", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/56/1f/fe2912d87b3af510469dc40bdf85", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/0d/ae/d2df1bf3c2157b4b5302df54622f", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/97/cc/8afdb842dbf284fc8bc60c72e2de", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/fe/33/cead18bf921903f8c6d922017892", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/57/7d/e79791913a06c9c15fec75138e6a", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a3/b6/8987b9fc6a7cb0f61364f567c901", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/ff/3f/f1c11e1f22454ceceb7b4d277a2a", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/82/7b/fac54bd2911a93d3d50df3c25ee2", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/bd/45/ffb2d9d9ce9578ae11de9bb5123d", - "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/e1/cc/13a4ba409b7d6f113f703be1aa8a", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/e5/0a/6ee92ae2cb50f12eeb21059c6659", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/39/33/5aaa68496edca5b6d9c988b657cb", + "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/1d/55/f8a3d9c1d8132527b1f273bdf7f7", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/b7/d8/4713322c35511a50e00b0aaead5a", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", - "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/57/bb/33e8bd738c3ee97122186471be75", + "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/61/97/8f5273183a2a0a5425bc6f4c3070", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/73/ef/624000057ce55f5a511ba18fd433", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/c2/bc/a426b99c4fde5f1eeeac97cf3600", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/82/7c/5363de81ac6823935098df95dc66", - "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/9d/fb/6c2feb78bdabbec049a71ba40d78", + "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/b8/8c/ac972d1936acf2aaa1d06a4b5ce6", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/96/96/b2e468ceec8800b7b0f1e1c5977c", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", @@ -3931,12 +3931,12 @@ "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/85/c4389f7f89b870b1685e9eed5eec", "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/26/962a1518a29fe8f1c1048b574c35", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6d/e6/2fb6f02fac2a8c7ffc1f3ebf4786", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/23/0a8a3bfafae095b36c48ef826d59", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e9/94/aadedc02a13bb4eb697ce9d7f9a4", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/0b/755d9f57d38ce4de022d3909ed1c", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/d9/eb3090c2c4369d13ce6c1bff48f7", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/aa/188da0d5b891f43c417275d430d2", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5d/bd/70427b399c0f72820c7e9dbeafd2", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/4a/5d2a7076414166d9aae182b533bf", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/6f/d0/efaab1edd0f58c4db8c7fcbe8a3d", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/ad/cb58f2d0d615be118112ffd2f9fd", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b7/42/ba5e352389b4069228d49089bdf2" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/06/f4/de0f4e54f5ad6c0b6989adeaaafe", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b7/ea/80b27468b5fb287e5bff9e7a3085", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3c/d0/4244f654e02b5465ea397a7e8b61", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3a/65/529b2aa735e8a1c0b7f047cf5653" } \ No newline at end of file From 4b63f19a63238bb741649a0ae7e6faf6a7a76e10 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 9 Aug 2020 22:12:15 -0700 Subject: [PATCH 193/417] Added venetian translation --- .efrocachemap | 39 ++++++++++--------- CHANGELOG.md | 3 ++ assets/.asset_manifest_private.json | 1 + assets/Makefile | 1 + assets/src/ba_data/python/ba/_app.py | 1 + .../python/bastd/actor/controlsguide.py | 2 + docs/ba_module.md | 2 +- 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 93c29242..060f61fb 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,12 +420,12 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/90/18/f6865956be7b13e7b8cdc6a3f06c", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/a9/3c/63857b3f5f943205d7a5d8f8e476", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/af/5d/5475c7fa4b5899788c5b3e241e01", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/6a/11/c33066f52828a303d62613254148", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/45/68/29dd2936391a747f99227423675b", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/d1/96/688ec16a817f34509e69109a431d", - "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/bb/9c/360fc084e6254a087096993af219", + "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/c7/ea/7b4357666b328b991fe82ea9a3fb", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212", @@ -437,10 +437,10 @@ "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a3/b6/8987b9fc6a7cb0f61364f567c901", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a9/71/817446169ae436e6775f76cd5aec", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/82/7b/fac54bd2911a93d3d50df3c25ee2", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/39/33/5aaa68496edca5b6d9c988b657cb", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/86/bf/284e1d1c6f07720828754b1ad4c9", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/1d/55/f8a3d9c1d8132527b1f273bdf7f7", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/b7/d8/4713322c35511a50e00b0aaead5a", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", @@ -449,9 +449,10 @@ "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/c2/bc/a426b99c4fde5f1eeeac97cf3600", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/82/7c/5363de81ac6823935098df95dc66", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/fc/68/afb751f913d8ae75effebc95f4a0", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/b8/8c/ac972d1936acf2aaa1d06a4b5ce6", - "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/96/96/b2e468ceec8800b7b0f1e1c5977c", + "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/ae/ec/9335bf4749a979061be7b8e6d613", + "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/04/52/683a27aaf9aa7c63e7e595f80d08", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", "assets/build/ba_data/data/maps/courtyard.json": "https://files.ballistica.net/cache/ba1/03/38/344dd05bfef7bbdf464035ec5aa2", @@ -3927,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c1/bd/ada4f12eadaa33f3fcf4f1b70ede", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/85/c4389f7f89b870b1685e9eed5eec", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/df/26/962a1518a29fe8f1c1048b574c35", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/6d/e6/2fb6f02fac2a8c7ffc1f3ebf4786", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e9/94/aadedc02a13bb4eb697ce9d7f9a4", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/0b/755d9f57d38ce4de022d3909ed1c", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/1f/aa/188da0d5b891f43c417275d430d2", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5d/bd/70427b399c0f72820c7e9dbeafd2", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/06/f4/de0f4e54f5ad6c0b6989adeaaafe", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b7/ea/80b27468b5fb287e5bff9e7a3085", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3c/d0/4244f654e02b5465ea397a7e8b61", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3a/65/529b2aa735e8a1c0b7f047cf5653" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fc/51/42cfaaf8101f604adbf7bdcb7c34", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/b6/2a886ca52b15e3c1a4ac7ca327f3", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/e5/cf5c585713f11c691047580a1f0c", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/59/7e/0fd8ce8fb147026004e8a6a313f4", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ce/4b/75871cc1df9b1536818717a03714", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/94/bfb8f62d52af7a114e36f90a3f1c", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/77/3f/65c310bf29312f1fcb75f7d92fc9", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/20/11/51e2583fbb531888d79559a0ff92", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/20/f2/a60ad18026aaefb0261a595781d6", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b6/ac/54d5bb63ee411bb0cc10ce76e5bf", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/33/e7/4e471804132ec72ca1bf4229612b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b8/1f/09cc97502db36973d70a9bbb42c9" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b04c29..aefbbcbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.25 (20164) +- Added Venetian language (thanks Federico!) + ### 1.5.24 (20163) - Upgraded Python from version 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now.. - Windows debug builds now use Python debug libraries. This should hopefully catch more errors that would otherwise go undetected and potentially cause crashes. diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json index ed6eeb97..1bb8aa43 100644 --- a/assets/.asset_manifest_private.json +++ b/assets/.asset_manifest_private.json @@ -451,6 +451,7 @@ "ba_data/data/languages/swedish.json", "ba_data/data/languages/turkish.json", "ba_data/data/languages/ukrainian.json", + "ba_data/data/languages/venetian.json", "ba_data/data/languages/vietnamese.json", "ba_data/data/maps/big_g.json", "ba_data/data/maps/bridgit.json", diff --git a/assets/Makefile b/assets/Makefile index ab0997b1..4efd83ac 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -4755,6 +4755,7 @@ DATA_TARGETS = \ build/ba_data/data/languages/swedish.json \ build/ba_data/data/languages/turkish.json \ build/ba_data/data/languages/ukrainian.json \ + build/ba_data/data/languages/venetian.json \ build/ba_data/data/languages/vietnamese.json \ build/ba_data/data/maps/big_g.json \ build/ba_data/data/maps/bridgit.json \ diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 611189b3..c3fafecf 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -121,6 +121,7 @@ class App: 'sr': 'Serbian', 'uk': 'Ukrainian', 'vi': 'Vietnamese', + 'vec': 'Venetian', 'hi': 'Hindi' } diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py index a68a6d7c..7158bdc5 100644 --- a/assets/src/ba_data/python/bastd/actor/controlsguide.py +++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py @@ -271,6 +271,8 @@ class ControlsGuide(ba.Actor): # If we have a touchscreen, we only fade in if we have a player with # an input device that is *not* the touchscreen. + # (otherwise it is confusing to see the touchscreen buttons right + # next to our display buttons) touchscreen: Optional[ba.InputDevice] = _ba.getinputdevice( 'TouchScreen', '#1', doraise=False) diff --git a/docs/ba_module.md b/docs/ba_module.md index 0550db84..15986a93 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-03 for Ballistica version 1.5.24 build 20162

    +

    last updated on 2020-08-09 for Ballistica version 1.5.24 build 20164

    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!


    From d58ba2f0dc72aa79ac25b16b97e63091d8f80852 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 11 Aug 2020 08:30:38 -0700 Subject: [PATCH 194/417] Language updates --- .efrocachemap | 50 +++++++++---------- CHANGELOG.md | 2 +- assets/src/ba_data/python/ba/_app.py | 6 ++- assets/src/ba_data/python/ba/_coopgame.py | 2 +- assets/src/ba_data/python/ba/_coopsession.py | 4 +- assets/src/ba_data/python/ba/_lobby.py | 7 +-- assets/src/ba_data/python/ba/_profile.py | 2 +- .../ba_data/python/bastd/activity/coopjoin.py | 2 +- .../python/bastd/activity/coopscore.py | 9 ++-- .../src/ba_data/python/bastd/game/football.py | 2 +- .../ba_data/python/bastd/game/onslaught.py | 4 +- assets/src/ba_data/python/bastd/mainmenu.py | 13 ++--- assets/src/ba_data/python/bastd/ui/kiosk.py | 13 ++--- .../src/ba_data/python/bastd/ui/mainmenu.py | 19 ++++--- docs/ba_module.md | 2 +- 15 files changed, 71 insertions(+), 66 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 060f61fb..44690c2a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,36 +420,36 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/af/5d/5475c7fa4b5899788c5b3e241e01", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/06/dd/547243a95a0360ffb4b2ddcad13a", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/6a/11/c33066f52828a303d62613254148", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", - "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/45/68/29dd2936391a747f99227423675b", - "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/d1/96/688ec16a817f34509e69109a431d", + "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", + "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/5a/9e/e8cad6f08b2b19803ab20fdc80d0", "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/c7/ea/7b4357666b328b991fe82ea9a3fb", "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212", - "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/56/1f/fe2912d87b3af510469dc40bdf85", + "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/d4/5b/fbd64cf1846340db0606824568c2", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", - "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/97/cc/8afdb842dbf284fc8bc60c72e2de", + "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/e3/6d/63e78b12ae9d99e0929671f52c12", "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/fe/33/cead18bf921903f8c6d922017892", - "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/57/7d/e79791913a06c9c15fec75138e6a", + "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/97/3a/b6746b7f89af424584c794c4d11f", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", - "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/11/56/ed2b07866104596338f7ce582d64", + "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/d5/19/5e450e35b83fe68722330d03b896", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a9/71/817446169ae436e6775f76cd5aec", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/82/7b/fac54bd2911a93d3d50df3c25ee2", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a8/b9/070b8151df9a1664d6b1b425f0b3", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/86/bf/284e1d1c6f07720828754b1ad4c9", - "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/1d/55/f8a3d9c1d8132527b1f273bdf7f7", - "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/b7/d8/4713322c35511a50e00b0aaead5a", + "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/88/4b/6745a1a58220772e259f0de51196", + "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/42/b5/7612cce15fe4555889585108b3ef", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", - "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/61/97/8f5273183a2a0a5425bc6f4c3070", + "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/d4/bb/69c09648f60e36f35bd38be20cf8", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/c2/bc/a426b99c4fde5f1eeeac97cf3600", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/b9/6b/adf28849d42f4c195dacf4f53902", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", - "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/fc/68/afb751f913d8ae75effebc95f4a0", + "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/8a/f7b2521c1904ffc83262dff1e11b", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/b8/8c/ac972d1936acf2aaa1d06a4b5ce6", "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/ae/ec/9335bf4749a979061be7b8e6d613", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/04/52/683a27aaf9aa7c63e7e595f80d08", @@ -3928,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fc/51/42cfaaf8101f604adbf7bdcb7c34", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a9/b6/2a886ca52b15e3c1a4ac7ca327f3", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c7/e5/cf5c585713f11c691047580a1f0c", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/59/7e/0fd8ce8fb147026004e8a6a313f4", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ce/4b/75871cc1df9b1536818717a03714", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f0/94/bfb8f62d52af7a114e36f90a3f1c", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/77/3f/65c310bf29312f1fcb75f7d92fc9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/20/11/51e2583fbb531888d79559a0ff92", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/20/f2/a60ad18026aaefb0261a595781d6", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b6/ac/54d5bb63ee411bb0cc10ce76e5bf", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/33/e7/4e471804132ec72ca1bf4229612b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b8/1f/09cc97502db36973d70a9bbb42c9" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/f4/988128b2a38a8321ec354da5dcee", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/de/58/1aa87a7931c22de875911fd514d8", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/3b/70935fd69c8ee28b0e6a087b94fd", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/1b/5fc0ae2fc3fea72d1a44d76acced", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/3b/fbd18332d7c9eb9bb6d19dbfdcb6", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c3/d4/9253ba5d7f3e264333960a11821e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/1f/17c118919f6b7d519652cfbc285e", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/52/3c/0b153dc147c57263eb5e79c6f419", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/76/0c/1473b08573d227c76ebecd1248c6", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/89/b3/cf229fd1765296e8829cd7e877b7", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2f/06/64b2cc506e0f32082fe8280cd294", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/8b/812d044be955463754ee378173f6" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index aefbbcbb..b926cb28 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5.25 (20164) +### 1.5.25 (20165) - Added Venetian language (thanks Federico!) ### 1.5.24 (20163) diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index c3fafecf..e6d9d839 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -301,8 +301,10 @@ class App: assert isinstance(self.protocol_version, int) self.toolbar_test: bool = env['toolbar_test'] assert isinstance(self.toolbar_test, bool) - self.kiosk_mode: bool = env['kiosk_mode'] - assert isinstance(self.kiosk_mode, bool) + self.demo_mode: bool = env['demo_mode'] + assert isinstance(self.demo_mode, bool) + self.arcade_mode: bool = env['arcade_mode'] + assert isinstance(self.arcade_mode, bool) self.headless_build: bool = env['headless_build'] assert isinstance(self.headless_build, bool) diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index 4e169f81..7e686dd4 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -64,7 +64,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): super().on_begin() # Show achievements remaining. - if not _ba.app.kiosk_mode: + if not (_ba.app.demo_mode or _ba.app.arcade_mode): _ba.timer(3.8, WeakCall(self._show_remaining_achievements)) # Preload achievement images in case we get some. diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index b50365f1..113a5886 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -292,7 +292,7 @@ class CoopSession(Session): # tutorial first. if (isinstance(activity, JoinActivity) and self.campaign_level_name == 'Onslaught Training' - and not app.kiosk_mode): + and not (app.demo_mode or app.arcade_mode)): if self._tutorial_activity is None: raise RuntimeError('Tutorial not preloaded properly.') self.setactivity(self._tutorial_activity) @@ -315,7 +315,7 @@ class CoopSession(Session): # Now flip the current activity.. self.setactivity(next_game) - if not app.kiosk_mode: + if not (app.demo_mode or app.arcade_mode): if self.tournament_id is not None: self._custom_menu_ui = [{ 'label': diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index 82898aba..f540478e 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -77,7 +77,7 @@ class JoinInfo: 'text': self._joinmsg })) - if _ba.app.kiosk_mode: + if _ba.app.demo_mode or _ba.app.arcade_mode: self._messages = [self._joinmsg] else: msg1 = Lstr(resource='pressToSelectProfileText', @@ -406,13 +406,14 @@ class Chooser: self._profiles['_random'] = {} # In kiosk mode we disable account profiles to force random. - if app.kiosk_mode: + if app.demo_mode or app.arcade_mode: if '__account__' in self._profiles: del self._profiles['__account__'] # For local devices, add it an 'edit' option which will pop up # the profile window. - if not is_remote and not is_test_input and not app.kiosk_mode: + if not is_remote and not is_test_input and not (app.demo_mode + or app.arcade_mode): self._profiles['_edit'] = {} # Build a sorted name list we can iterate through. diff --git a/assets/src/ba_data/python/ba/_profile.py b/assets/src/ba_data/python/ba/_profile.py index 8448baae..c938c33c 100644 --- a/assets/src/ba_data/python/ba/_profile.py +++ b/assets/src/ba_data/python/ba/_profile.py @@ -77,7 +77,7 @@ def get_player_profile_colors( # Special case: when being asked for a random color in kiosk mode, # always return default purple. - if _ba.app.kiosk_mode and profilename is None: + if (_ba.app.demo_mode or _ba.app.arcade_mode) and profilename is None: color = (0.5, 0.4, 1.0) highlight = (0.4, 0.4, 0.5) else: diff --git a/assets/src/ba_data/python/bastd/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py index e1f06dd0..cf9f33ef 100644 --- a/assets/src/ba_data/python/bastd/activity/coopjoin.py +++ b/assets/src/ba_data/python/bastd/activity/coopjoin.py @@ -173,7 +173,7 @@ class CoopJoinActivity(JoinActivity): self.session.campaign_level_name) ts_h_offs = 60 - if not ba.app.kiosk_mode: + if not (ba.app.demo_mode or ba.app.arcade_mode): achievements = [ a for a in get_achievements_for_coop_level(levelname) if not a.complete diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 42da9596..24b0fc73 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -389,7 +389,8 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): else: pass - show_next_button = self._is_more_levels and not ba.app.kiosk_mode + show_next_button = self._is_more_levels and not (ba.app.demo_mode + or ba.app.arcade_mode) if not show_next_button: h_offs += 70 @@ -455,7 +456,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): self._corner_button_offs = (h_offs + 300.0 + 100.0 + x_offs_extra, v_offs + 560.0) - if ba.app.kiosk_mode: + if ba.app.demo_mode or ba.app.arcade_mode: self._league_rank_button = None self._store_button_instance = None else: @@ -542,7 +543,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): ba.timer(1.0, ba.WeakCall(self.request_ui)) if (self._is_complete and self._victory and self._is_more_levels - and not ba.app.kiosk_mode): + and not (ba.app.demo_mode or ba.app.arcade_mode)): Text(ba.Lstr(value='${A}:\n', subs=[('${A}', ba.Lstr(resource='levelUnlockedText')) ]) if self._newly_complete else @@ -690,7 +691,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): }) if _ba.get_account_state() != 'signed_in': # We expect this only in kiosk mode; complain otherwise. - if not ba.app.kiosk_mode: + if not (ba.app.demo_mode or ba.app.arcade_mode): print('got not-signed-in at score-submit; unexpected') if self._show_friend_scores: ba.pushcall(ba.WeakCall(self._got_friend_score_results, None)) diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index ac6d4925..1a0bb939 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -450,7 +450,7 @@ class FootballCoopGame(ba.CoopGameActivity[Player, Team]): super().on_begin() # Show controls help in kiosk mode. - if ba.app.kiosk_mode: + if ba.app.demo_mode or ba.app.arcade_mode: controlsguide.ControlsGuide(delay=3.0, lifespan=10.0, bright=True).autoretain() assert self.initialplayerinfos is not None diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 97718328..72484566 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -457,8 +457,8 @@ class OnslaughtGame(ba.CoopGameActivity[Player, Team]): elif self._preset in {Preset.UBER, Preset.UBER_EASY}: - # Show controls help in kiosk mode. - if ba.app.kiosk_mode: + # Show controls help in demo/arcade modes. + if ba.app.demo_mode or ba.app.arcade_mode: ControlsGuide(delay=3.0, lifespan=10.0, bright=True).autoretain() diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index 99795e68..e669875b 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -150,8 +150,9 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): # Throw in test build info. self.beta_info = self.beta_info_2 = None - if app.test_build and not app.kiosk_mode: - pos = (230, 125) if app.kiosk_mode else (230, 35) + if app.test_build and not (app.demo_mode or app.arcade_mode): + pos = ((230, 125) if (app.demo_mode or app.arcade_mode) else + (230, 35)) self.beta_info = ba.NodeActor( ba.newnode('text', attrs={ @@ -396,7 +397,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): })) self._change_phrase() - if not app.kiosk_mode and not app.toolbar_test: + if not (app.demo_mode or app.arcade_mode) and not app.toolbar_test: self._news = News(self) # Bring up the last place we were, or start at the main menu otherwise. @@ -411,7 +412,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): # When coming back from a kiosk-mode game, jump to # the kiosk start screen. - if ba.app.kiosk_mode: + if ba.app.demo_mode or ba.app.arcade_mode: # pylint: disable=cyclic-import from bastd.ui.kiosk import KioskWindow ba.app.ui.set_main_menu_window( @@ -514,7 +515,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): base_x = -270.0 x = base_x - 20.0 spacing = 85.0 * base_scale - y_extra = 0.0 if app.kiosk_mode else 0.0 + y_extra = 0.0 if (app.demo_mode or app.arcade_mode) else 0.0 self._make_logo(x - 110 + 50, 113 + y + 1.2 * y_extra, 0.34 * base_scale, @@ -567,7 +568,7 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): base_x = -170 x = base_x - 20 spacing = 55 * base_scale - y_extra = 0 if app.kiosk_mode else 0 + y_extra = 0 if (app.demo_mode or app.arcade_mode) else 0 xv1 = x delay1 = delay for shadow in (True, False): diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index 3d21fae6..949ebd6f 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -99,8 +99,9 @@ class KioskWindow(ba.Window): size=(0, 0), position=(self._width * 0.5, self._height + y_extra - 34), transition_delay=tdelay, - text=ba.Lstr(resource='demoText', - fallback_resource='mainMenu.demoMenuText'), + text=(ba.Lstr(resource='demoText', + fallback_resource='mainMenu.demoMenuText') + if ba.app.demo_mode else 'ARCADE'), flatness=1.0, scale=1.2, h_align='center', @@ -311,8 +312,7 @@ class KioskWindow(ba.Window): self._b4 = self._b5 = self._b6 = None self._b7: Optional[ba.Widget] - uiscale = ba.app.ui.uiscale - if bool(False): + if ba.app.arcade_mode: self._b7 = ba.buttonwidget( parent=self._root_widget, autoselect=True, @@ -320,10 +320,7 @@ class KioskWindow(ba.Window): color=(0.45, 0.55, 0.45), textcolor=(0.7, 0.8, 0.7), scale=0.5, - position=((self._width * 0.5 - 37.5, - y_extra + 120) if not self._show_multiplayer else - (self._width + 100, y_extra + - (140 if uiscale is ba.UIScale.SMALL else 120))), + position=(self._width * 0.5 - 60.0, b_v - 70.0), transition_delay=tdelay, label=ba.Lstr(resource=self._r + '.fullMenuText'), on_activate_call=self._do_full_menu) diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 070dc893..7e1459e6 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -56,7 +56,8 @@ class MainMenuWindow(ba.Window): toolbar_visibility='menu_minimal_no_back' if self. _in_game else 'menu_minimal_no_back')) - self._is_kiosk = ba.app.kiosk_mode + self._is_demo = ba.app.demo_mode + self._is_arcade = ba.app.arcade_mode self._tdelay = 0.0 self._t_delay_inc = 0.02 self._t_delay_play = 1.7 @@ -73,6 +74,7 @@ class MainMenuWindow(ba.Window): self._gc_button: Optional[ba.Widget] = None self._how_to_play_button: Optional[ba.Widget] = None self._credits_button: Optional[ba.Widget] = None + self._settings_button: Optional[ba.Widget] = None self._store_char_tex = self._get_store_char_tex() @@ -193,9 +195,9 @@ class MainMenuWindow(ba.Window): self._have_store_button = not self._in_game - self._have_settings_button = ((not self._in_game - or not app.toolbar_test) - and not self._is_kiosk) + self._have_settings_button = ( + (not self._in_game or not app.toolbar_test) + and not (self._is_demo or self._is_arcade)) self._input_device = input_device = _ba.get_ui_input_device() self._input_player = input_device.player if input_device else None @@ -500,7 +502,7 @@ class MainMenuWindow(ba.Window): (x_offs + spc * i - 1.0, button_y_offs + button_y_offs2, small_button_scale)) # In kiosk mode, provide a button to get back to the kiosk menu. - if ba.app.kiosk_mode: + if ba.app.demo_mode or ba.app.arcade_mode: h, v, scale = positions[self._p_index] this_b_width = self._button_width * 0.4 * scale demo_menu_delay = 0.0 if self._t_delay_play == 0.0 else max( @@ -512,7 +514,8 @@ class MainMenuWindow(ba.Window): autoselect=True, color=(0.45, 0.55, 0.45), textcolor=(0.7, 0.8, 0.7), - label=ba.Lstr(resource=self._r + '.demoMenuText'), + label=ba.Lstr(resource='modeArcadeText' if ba.app. + arcade_mode else 'modeDemoText'), transition_delay=demo_menu_delay, on_activate_call=self._demo_menu_press) else: @@ -707,7 +710,7 @@ class MainMenuWindow(ba.Window): f'Error getting custom menu entries for {session}') self._width = 250.0 self._height = 250.0 if self._input_player else 180.0 - if self._is_kiosk and self._input_player: + if (self._is_demo or self._is_arcade) and self._input_player: self._height -= 40 if not self._have_settings_button: self._height -= 50 @@ -782,7 +785,7 @@ class MainMenuWindow(ba.Window): autoselect=self._use_autoselect) # Add a 'leave' button if the menu-owner has a player. if ((self._input_player or self._connected_to_remote_player) - and not self._is_kiosk): + and not (self._is_demo or self._is_arcade)): h, v, scale = positions[self._p_index] self._p_index += 1 btn = ba.buttonwidget(parent=self._root_widget, diff --git a/docs/ba_module.md b/docs/ba_module.md index 15986a93..800da8f6 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-09 for Ballistica version 1.5.24 build 20164

    +

    last updated on 2020-08-09 for Ballistica version 1.5.25 build 20166

    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!


    From de506cb4a5b36001e40906692fe34cbbea44ab9c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 18 Aug 2020 16:12:42 -0500 Subject: [PATCH 195/417] Language updates --- .efrocachemap | 34 +++++++++++++++++----------------- .idea/dictionaries/ericf.xml | 12 ++++++------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 44690c2a..66c15b2b 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,8 +420,8 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/06/dd/547243a95a0360ffb4b2ddcad13a", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/6a/11/c33066f52828a303d62613254148", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/dd/76/4336a2d6094a2153984c22bf3713", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/29/69/ec6b8725aa7dfa41d0b59f1e9ec1", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/5a/9e/e8cad6f08b2b19803ab20fdc80d0", @@ -432,13 +432,13 @@ "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/d4/5b/fbd64cf1846340db0606824568c2", "assets/build/ba_data/data/languages/esperanto.json": "https://files.ballistica.net/cache/ba1/6e/fd/685a4e1da031474d47a1d9eb2731", "assets/build/ba_data/data/languages/french.json": "https://files.ballistica.net/cache/ba1/e3/6d/63e78b12ae9d99e0929671f52c12", - "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/fe/33/cead18bf921903f8c6d922017892", + "assets/build/ba_data/data/languages/german.json": "https://files.ballistica.net/cache/ba1/3f/62/4eedf8cfad2e5f7ff2136ec19277", "assets/build/ba_data/data/languages/gibberish.json": "https://files.ballistica.net/cache/ba1/97/3a/b6746b7f89af424584c794c4d11f", "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/d5/19/5e450e35b83fe68722330d03b896", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a9/71/817446169ae436e6775f76cd5aec", - "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/a8/b9/070b8151df9a1664d6b1b425f0b3", + "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/33/04/b1c54ce2b8979cc983aecc781228", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/86/bf/284e1d1c6f07720828754b1ad4c9", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/88/4b/6745a1a58220772e259f0de51196", @@ -451,7 +451,7 @@ "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/8a/f7b2521c1904ffc83262dff1e11b", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/b8/8c/ac972d1936acf2aaa1d06a4b5ce6", - "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/ae/ec/9335bf4749a979061be7b8e6d613", + "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/cb/ae/e4006b346df70380788f24fa2716", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/04/52/683a27aaf9aa7c63e7e595f80d08", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", @@ -3928,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6e/f4/988128b2a38a8321ec354da5dcee", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/de/58/1aa87a7931c22de875911fd514d8", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a1/3b/70935fd69c8ee28b0e6a087b94fd", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b3/1b/5fc0ae2fc3fea72d1a44d76acced", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/88/3b/fbd18332d7c9eb9bb6d19dbfdcb6", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c3/d4/9253ba5d7f3e264333960a11821e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/bc/1f/17c118919f6b7d519652cfbc285e", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/52/3c/0b153dc147c57263eb5e79c6f419", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/76/0c/1473b08573d227c76ebecd1248c6", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/89/b3/cf229fd1765296e8829cd7e877b7", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2f/06/64b2cc506e0f32082fe8280cd294", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/54/8b/812d044be955463754ee378173f6" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/84/5eb5628720ff75385cc13928a49e", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/9f/f37978a5ffe39ac6edc664f60174", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/72/41f71faf74598e73632cd337f614", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ad/cf/aa8d6f48de619d0bd19332eb5b2c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/84/f232bc8c631bf1390cfadd542bf3", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/5c/c05a51b3cf567e4068bc3855b75e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8c/ed/d94a3be4a30c6225eba48babaedf", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/67/30/6f428cfd113e4d29954d3fa83070", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/be/b2/0129c26e2aa3c928c400546c3882", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/72/02/444ad6235391423f3a54562cebcb", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8f/21/9043cbb8ca95ae560a8805a63975", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/89/67/6be3af6d18c98b227e4b20952705" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 4d9e7d52..39f956f8 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack'ed ack + ack'ed acked acks acnt @@ -149,8 +149,8 @@ bacommon badguy bafoundation - ballistica's ballistica + ballistica's ballisticacore ballisticacorecb bamaster @@ -780,8 +780,8 @@ gamedata gameinstance gamemap - gamepad's gamepad + gamepad's gamepadadvanced gamepads gamepadselect @@ -1151,8 +1151,8 @@ lsqlite lssl lstart - lstr's lstr + lstr's lstrs lsval ltex @@ -1773,8 +1773,8 @@ sessionname sessionplayer sessionplayers - sessionteam's sessionteam + sessionteam's sessionteams sessiontype setactivity @@ -2100,8 +2100,8 @@ txtw typeargs typecheck - typechecker's typechecker + typechecker's typedval typeshed typestr From b0907652e63fb247866e1817466d2b551669b932 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 18 Aug 2020 17:40:17 -0500 Subject: [PATCH 196/417] Delete light note in chosen one if player leaves --- assets/src/ba_data/python/bastd/game/chosenone.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index b9d4463f..e0ece71d 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -184,6 +184,7 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): }) def _get_chosen_one_player(self) -> Optional[Player]: + # Should never return invalid references; return None in that case. if self._chosen_one_player: return self._chosen_one_player return None @@ -269,8 +270,9 @@ class ChosenOneGame(ba.TeamGameActivity[Player, Team]): self.end(results=results, announce_delay=0) def _set_chosen_one_player(self, player: Optional[Player]) -> None: - for p_other in self.players: - p_other.chosen_light = None + existing = self._get_chosen_one_player() + if existing: + existing.chosen_light = None ba.playsound(self._swipsound) if not player: assert self._flag_spawn_pos is not None From fc7ee67246b86b2fa03dc9cbfb50906225987930 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 20 Aug 2020 15:24:31 -0500 Subject: [PATCH 197/417] tidying --- .efrocachemap | 24 ++++++++++++------------ CHANGELOG.md | 4 +++- tools/efrotools/android.py | 1 - tools/efrotools/pcommand.py | 10 ++++++---- tools/pcommand | 15 +++++++-------- 5 files changed, 28 insertions(+), 26 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 66c15b2b..802a2ec7 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3928,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/84/5eb5628720ff75385cc13928a49e", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a6/9f/f37978a5ffe39ac6edc664f60174", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/72/41f71faf74598e73632cd337f614", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ad/cf/aa8d6f48de619d0bd19332eb5b2c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/73/84/f232bc8c631bf1390cfadd542bf3", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d8/5c/c05a51b3cf567e4068bc3855b75e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8c/ed/d94a3be4a30c6225eba48babaedf", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/67/30/6f428cfd113e4d29954d3fa83070", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/be/b2/0129c26e2aa3c928c400546c3882", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/72/02/444ad6235391423f3a54562cebcb", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8f/21/9043cbb8ca95ae560a8805a63975", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/89/67/6be3af6d18c98b227e4b20952705" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/8a/9ebc5daa1524ab2c28f110594713", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/54/4afa32ce286c9fd1769d5974d806", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/f6/70e8021e7eecd0ac2780c5290e20", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5e/1c/1537e910399d1ff9f16597d9a687", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bb/6d/2d6e692c88f33c69bb2cf4346d41", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/e7/364c1ffda791abc63375d6fcbf24", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/5f/425c115720b7f176a9968b064aec", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9b/1e/14c166e8608beb01074606b58b6d", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/d1/91d2ba146c8c8cbb5a314321fe68", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f0/f7/1aa0a6b5a48bc91b48f8314f6091", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ac/22/f41a02837800ffdcd1ab00b8c860", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1d/4a/5c01f5243c5dcae456f8f2dbf63d" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index b926cb28..767aa154 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ -### 1.5.25 (20165) +### 1.5.25 (20171) - Added Venetian language (thanks Federico!) +- Fixed an issue where chosen-one flashes would remain if the player leaves the game +- Added android input-device detection log messages for debugging ### 1.5.24 (20163) - Upgraded Python from version 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now.. diff --git a/tools/efrotools/android.py b/tools/efrotools/android.py index 45294876..16ed82f7 100644 --- a/tools/efrotools/android.py +++ b/tools/efrotools/android.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3.8 # Copyright (c) 2011-2020 Eric Froemling # # Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index 8f7bc855..b7c22ff4 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -85,10 +85,12 @@ def pcommand_main(globs: Dict[str, Any]) -> None: retval = 255 if show_help: - print('Pcommand contains project related commands too small' - ' to warrant full scripts.') - print(f"Run {Clr.MAG}'pcommand help {Clr.BLD}'" - f'{Clr.RST} for full command documentation.') + print(f'The {Clr.MAG}{Clr.BLD}pcommand{Clr.RST} script encapsulates' + f' a collection of project-related commands.') + print(f"Run {Clr.MAG}{Clr.BLD}'pcommand [COMMAND] ...'" + f'{Clr.RST} to run a command.') + print(f"Run {Clr.MAG}{Clr.BLD}'pcommand help [COMMAND]'" + f'{Clr.RST} for full documentation for a command.') print('Available commands:') for func, obj in sorted(funcs.items()): doc = getattr(obj, '__doc__', '').splitlines()[0].strip() diff --git a/tools/pcommand b/tools/pcommand index 3a244185..bd1d6665 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -19,22 +19,21 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # ----------------------------------------------------------------------------- -"""Wee little snippets of functionality specific to this project. +"""A collection of commands for use with this project. All top level functions here can be run by passing them as the first argument on the command line. (or pass no arguments to get a list of them). - -Functions can be placed here when they're not complex enough to warrant -their own files. Often these functions act as user-facing entry points -to functionality contained in efrotools or other standalone tool modules. """ + +# Note: we import as little as possible here at the module level to +# keep launch times fast; most imports should happen within individual command +# functions. + from __future__ import annotations -# Note: import as little as possible here at the module level to -# keep launch times fast for small snippets. from typing import TYPE_CHECKING -# Pull in the snippets we want to expose. Its more efficient to define them in +# Pull in commands we want to expose. Its more efficient to define them in # modules rather than inline here because we'll be able to load them via pyc. # pylint: disable=unused-import from efrotools.pcommand import ( From 7c24de005f7e6428bbfc6a3c2512fa302f18d341 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 21 Aug 2020 11:38:38 -0500 Subject: [PATCH 198/417] Tidying and updates for pylint 2.6 --- .efrocachemap | 24 +++++------ .idea/dictionaries/ericf.xml | 13 +++--- assets/src/ba_data/python/ba/_map.py | 4 +- assets/src/ba_data/python/ba/_session.py | 3 +- assets/src/server/ballisticacore_server.py | 2 +- docs/ba_module.md | 2 +- tools/bacloud | 11 ++--- tools/batools/build.py | 24 +++++------ tools/batools/pcommand.py | 50 +++++++++++++++++++--- tools/efrotools/code.py | 12 +++--- tools/efrotools/jsontools.py | 6 +-- tools/efrotools/pcommand.py | 4 +- tools/pcommand | 2 +- 13 files changed, 98 insertions(+), 59 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 802a2ec7..95cc3ae3 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3928,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/8a/9ebc5daa1524ab2c28f110594713", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/47/54/4afa32ce286c9fd1769d5974d806", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a4/f6/70e8021e7eecd0ac2780c5290e20", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/5e/1c/1537e910399d1ff9f16597d9a687", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bb/6d/2d6e692c88f33c69bb2cf4346d41", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/e7/364c1ffda791abc63375d6fcbf24", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8d/5f/425c115720b7f176a9968b064aec", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9b/1e/14c166e8608beb01074606b58b6d", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/d1/91d2ba146c8c8cbb5a314321fe68", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/f0/f7/1aa0a6b5a48bc91b48f8314f6091", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ac/22/f41a02837800ffdcd1ab00b8c860", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/1d/4a/5c01f5243c5dcae456f8f2dbf63d" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/c6/dfcaf3da1e374c6b6a8cca85299d", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b2/40/1070559af08278c0b05d854c7e09", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/27/d1/36949ffb430b588fa40a12f7bcad", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/07/99/ce84901053a1515146805082f104", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/3f/9c5e6a8435d46f4318034552870e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/89/b4/c88b4b1ed9e843f6f008c6988d20", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/67/f5/ce7f8ba6786caf2e5953d330be22", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/30/d06da2a6a373905a997d8b54062e", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/31/b5c420f11b65a031649339df0015", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0d/e3/191eae14cf956088ed1bd635d744", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bb/3c/6e2ca3917b4120d42fab3777c2ae", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/32/9f/586ee4ca6c6068483defbf95c86d" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 39f956f8..b326b1a3 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack ack'ed + ack acked acks acnt @@ -149,8 +149,8 @@ bacommon badguy bafoundation - ballistica ballistica's + ballistica ballisticacore ballisticacorecb bamaster @@ -780,8 +780,8 @@ gamedata gameinstance gamemap - gamepad gamepad's + gamepad gamepadadvanced gamepads gamepadselect @@ -1151,8 +1151,8 @@ lsqlite lssl lstart - lstr lstr's + lstr lstrs lsval ltex @@ -1773,8 +1773,8 @@ sessionname sessionplayer sessionplayers - sessionteam sessionteam's + sessionteam sessionteams sessiontype setactivity @@ -2100,8 +2100,8 @@ txtw typeargs typecheck - typechecker typechecker's + typechecker typedval typeshed typestr @@ -2177,6 +2177,7 @@ vcruntime vcxproj venv + verfilename verlines versioning versionpredicate diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py index 0dfbbf65..8e47f11e 100644 --- a/assets/src/ba_data/python/ba/_map.py +++ b/assets/src/ba_data/python/ba/_map.py @@ -218,12 +218,12 @@ class Map(Actor): # (and instruct the user if we weren't preloaded properly). try: self.preloaddata = _ba.getactivity().preloads[type(self)] - except Exception: + except Exception as exc: from ba import _error raise _error.NotFoundError( 'Preload data not found for ' + str(type(self)) + '; make sure to call the type\'s preload()' - ' staticmethod in the activity constructor') + ' staticmethod in the activity constructor') from exc # Set various globals. gnode = _ba.getactivity().globalsnode diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 65f9610c..60c3deba 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -143,7 +143,8 @@ class Session: else: missing_info = [(d.cls, d.config) for d in exc.deps] raise RuntimeError( - f'Missing non-asset dependencies: {missing_info}') + f'Missing non-asset dependencies: {missing_info}' + ) from exc # Throw a combined exception if we found anything missing. if missing_asset_packages: diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index ef24f90f..b2fd25c1 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -65,7 +65,7 @@ class ServerManagerApp: try: self._config = self._load_config() except Exception as exc: - raise CleanError(f'Error loading config: {exc}') + raise CleanError(f'Error loading config: {exc}') from exc self._done = False self._process_commands: List[Union[str, ServerCommand]] = [] self._process_commands_lock = Lock() diff --git a/docs/ba_module.md b/docs/ba_module.md index 800da8f6..3ab90371 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-09 for Ballistica version 1.5.25 build 20166

    +

    last updated on 2020-08-21 for Ballistica version 1.5.25 build 20171

    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!


    diff --git a/tools/bacloud b/tools/bacloud index cb08dcff..2765688f 100755 --- a/tools/bacloud +++ b/tools/bacloud @@ -208,9 +208,10 @@ class App: subprocess.run(['make', '--quiet', 'prereqs'], check=True, cwd=self._project_root) - except subprocess.CalledProcessError: - raise CleanError('"make prereqs" check failed. ' - 'Install missing requirements and try again.') + except subprocess.CalledProcessError as exc: + raise CleanError( + '"make prereqs" check failed. ' + 'Install missing requirements and try again.') from exc self._load_state() @@ -439,6 +440,6 @@ if __name__ == '__main__': # Let's do a clean fail on keyboard interrupt. # Can make this optional if a backtrace is ever useful.. sys.exit(1) - except CleanError as exc: - exc.pretty_print() + except CleanError as clean_exc: + clean_exc.pretty_print() sys.exit(1) diff --git a/tools/batools/build.py b/tools/batools/build.py index 01fea940..5f181bf3 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -30,6 +30,7 @@ import subprocess from pathlib import Path from typing import TYPE_CHECKING +from efro.error import CleanError from efro.terminal import Clr if TYPE_CHECKING: @@ -46,10 +47,10 @@ class PipRequirement: PIP_REQUIREMENTS = [ - PipRequirement(modulename='pylint', minversion=[2, 5, 3]), + PipRequirement(modulename='pylint', minversion=[2, 6, 0]), PipRequirement(modulename='mypy', minversion=[0, 782]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), - PipRequirement(modulename='cpplint', minversion=[1, 5, 3]), + PipRequirement(modulename='cpplint', minversion=[1, 5, 4]), PipRequirement(modulename='typing_extensions'), PipRequirement(modulename='pytz'), PipRequirement(modulename='yaml', pipname='PyYAML'), @@ -489,19 +490,19 @@ def checkenv() -> None: # Make sure they've got curl. if subprocess.run(['which', 'curl'], check=False, capture_output=True).returncode != 0: - raise RuntimeError('curl is required; please install it.') + raise CleanError('curl is required; please install it.') # Make sure they've got our target python version. if subprocess.run(['which', PYTHON_BIN], check=False, capture_output=True).returncode != 0: - raise RuntimeError(f'{PYTHON_BIN} is required; please install it.') + raise CleanError(f'{PYTHON_BIN} is required; please install it.') # Make sure they've got pip for that python version. if subprocess.run(f'{PYTHON_BIN} -m pip --version', shell=True, check=False, capture_output=True).returncode != 0: - raise RuntimeError( + raise CleanError( f'pip (for {PYTHON_BIN}) is required; please install it.') # Check for some required python modules. @@ -522,12 +523,11 @@ def checkenv() -> None: check=False, capture_output=True) if results.returncode != 0: - raise RuntimeError( - f'{packagename} (for {PYTHON_BIN}) is required.\n' - f'To install it, try: "{PYTHON_BIN}' - f' -m pip install {packagename}"\n' - f'Alternately, "tools/pcommand install_pip_reqs"' - f' will update all pip requirements.') + raise CleanError(f'{packagename} (for {PYTHON_BIN}) is required.\n' + f'To install it, try: "{PYTHON_BIN}' + f' -m pip install {packagename}"\n' + f'Alternately, "tools/pcommand install_pip_reqs"' + f' will update all pip requirements.') if minver is not None: verlines = results.stdout.decode().splitlines() if verlines[0].startswith('Cpplint fork'): @@ -537,7 +537,7 @@ def checkenv() -> None: vnums = [int(x) for x in ver_line.split()[-1].split('.')] assert len(vnums) == len(minver) if vnums < minver: - raise RuntimeError( + raise CleanError( f'{packagename} ver. {_vstr(minver)} or newer is required;' f' found {_vstr(vnums)}.\n' f'To upgrade it, try: "{PYTHON_BIN}' diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index ee0b23f1..f2b94f37 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -551,11 +551,7 @@ def install_pip_reqs() -> None: def checkenv() -> None: """Check for tools necessary to build and run the app.""" import batools.build - from efro.error import CleanError - try: - batools.build.checkenv() - except RuntimeError as exc: - raise CleanError(exc) + batools.build.checkenv() def ensure_prefab_platform() -> None: @@ -620,13 +616,13 @@ def lazybuild() -> None: try: category = batools.build.SourceCategory(sys.argv[2]) except ValueError as exc: - raise CleanError(exc) + raise CleanError(exc) from exc target = sys.argv[3] command = ' '.join(sys.argv[4:]) try: batools.build.lazybuild(target, category, command) except subprocess.CalledProcessError as exc: - raise CleanError(exc) + raise CleanError(exc) from exc def android_archive_unstripped_libs() -> None: @@ -730,3 +726,43 @@ def update_project() -> None: fix = '--fix' in sys.argv Updater(check=check, fix=fix).run() + + +def cmake_prep_dir() -> None: + """Create a dir, recreating it when cmake version changes. + + Useful to prevent builds from breaking when cmake is updated. + """ + import os + import subprocess + from efro.error import CleanError + from efro.terminal import Clr + + if len(sys.argv) != 3: + raise CleanError('Expected 1 arg (dir name)') + dirname = sys.argv[2] + + # Look for cmake version associated with the dir. + verfilename = os.path.join(dirname, '.ba_cmake_version') + ver: Optional[str] + if os.path.isfile(verfilename): + with open(verfilename) as infile: + ver = infile.read() + else: + ver = None + + # Get version of installed cmake. + cmake_ver_output = subprocess.run(['cmake', '--version'], + check=True, + capture_output=True).stdout.decode() + cmake_ver = cmake_ver_output.splitlines()[0].split('cmake version ')[1] + + # If they don't match, blow away the dir and write the current version. + if ver != cmake_ver: + if ver is not None: + print(f'{Clr.BLU}CMake version changed from {ver} to {cmake_ver};' + f' clearing existing build at "{dirname}".{Clr.RST}') + subprocess.run(['rm', '-rf', dirname], check=True) + os.makedirs(dirname, exist_ok=True) + with open(verfilename, 'w') as outfile: + outfile.write(cmake_ver) diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 11c999b1..35f47d78 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -121,8 +121,8 @@ def cpplint(projroot: Path, full: bool) -> None: # We want to do a few custom modifications to the cpplint module... try: import cpplint as cpplintmodule - except Exception: - raise CleanError('Unable to import cpplint') + except Exception as exc: + raise CleanError('Unable to import cpplint.') from exc with open(cpplintmodule.__file__) as infile: codelines = infile.read().splitlines() cheadersline = codelines.index('_C_HEADERS = frozenset([') @@ -598,8 +598,8 @@ def mypy(projroot: Path, full: bool) -> None: starttime = time.time() try: runmypy(projroot, filenames, full) - except Exception: - raise CleanError('Mypy failed.') + except Exception as exc: + raise CleanError('Mypy failed.') from exc duration = time.time() - starttime print(f'{Clr.GRN}Mypy passed in {duration:.1f} seconds.{Clr.RST}', flush=True) @@ -625,8 +625,8 @@ def dmypy(projroot: Path) -> None: '.mypy.ini', '--follow-imports=error', '--pretty' ] + filenames subprocess.run(args, check=True) - except Exception: - raise CleanError('Mypy daemon: fail.') + except Exception as exc: + raise CleanError('Mypy daemon: fail.') from exc duration = time.time() - starttime print(f'{Clr.GRN}Mypy daemon passed in {duration:.1f} seconds.{Clr.RST}', flush=True) diff --git a/tools/efrotools/jsontools.py b/tools/efrotools/jsontools.py index e608cd44..d01ae53b 100644 --- a/tools/efrotools/jsontools.py +++ b/tools/efrotools/jsontools.py @@ -43,7 +43,7 @@ class NoIndentEncoder(json.JSONEncoder): """Our custom encoder implementing selective indentation.""" def __init__(self, *args: Any, **kwargs: Any): - super(NoIndentEncoder, self).__init__(*args, **kwargs) + super().__init__(*args, **kwargs) self.kwargs = dict(kwargs) del self.kwargs['indent'] self._replacement_map: Dict = {} @@ -55,10 +55,10 @@ class NoIndentEncoder(json.JSONEncoder): key = uuid.uuid4().hex self._replacement_map[key] = json.dumps(o.value, **self.kwargs) return '@@%s@@' % (key, ) - return super(NoIndentEncoder, self).default(o) + return super().default(o) def encode(self, o: Any) -> Any: - result = super(NoIndentEncoder, self).encode(o) + result = super().encode(o) for k, v in self._replacement_map.items(): result = result.replace('"@@%s@@"' % (k, ), v) return result diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index b7c22ff4..a75a656b 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -297,8 +297,8 @@ def runmypy() -> None: try: efrotools.code.runmypy(PROJROOT, filenames) print(f'{Clr.GRN}Mypy Passed.{Clr.RST}') - except Exception: - raise CleanError('Mypy Failed.') + except Exception as exc: + raise CleanError('Mypy Failed.') from exc def dmypy() -> None: diff --git a/tools/pcommand b/tools/pcommand index bd1d6665..4a9c5cc2 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -55,7 +55,7 @@ from batools.pcommand import ( list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, efro_gradle, stage_assets, - update_assets_makefile, update_project) + update_assets_makefile, update_project, cmake_prep_dir) # pylint: enable=unused-import if TYPE_CHECKING: From a9df2c5925542b8c8b600410aa64507d7a8eab52 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 23 Aug 2020 18:41:46 -0500 Subject: [PATCH 199/417] C++ Layer Cleanup --- .efrocachemap | 24 ++++++++++++------------ .idea/dictionaries/ericf.xml | 1 + CHANGELOG.md | 2 +- docs/ba_module.md | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 95cc3ae3..3ac2821f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3928,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/53/c6/dfcaf3da1e374c6b6a8cca85299d", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b2/40/1070559af08278c0b05d854c7e09", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/27/d1/36949ffb430b588fa40a12f7bcad", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/07/99/ce84901053a1515146805082f104", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/59/3f/9c5e6a8435d46f4318034552870e", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/89/b4/c88b4b1ed9e843f6f008c6988d20", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/67/f5/ce7f8ba6786caf2e5953d330be22", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ef/30/d06da2a6a373905a997d8b54062e", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/68/31/b5c420f11b65a031649339df0015", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0d/e3/191eae14cf956088ed1bd635d744", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/bb/3c/6e2ca3917b4120d42fab3777c2ae", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/32/9f/586ee4ca6c6068483defbf95c86d" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/30/1f0f29bf2082ba1491ec5f693e5a", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/a9/8cb926cd717fd8a1a777683bc7e0", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/48/13/22c0bb0c91cf41ab34ebda463562", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/62/e0/cc4ac50696743a8864ba4c793a37", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/8b/bda7c882274919de97200a73efe5", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/6a/1346ce95d3fceaf22b336a6fe697", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/1f/3099ca907a025537990c263a9cf8", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/49/fd6cda67307cacb8d7b8d654561d", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b7/a8/c401f564941805196e2e0abed89c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/80/3a/977fd3e5392e435660f12d467d4c", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/08/72/73a8a403b228498aad76d9c5ce79", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ae/4d/358c50a4e2cf4cd7b2d4c2b65b32" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index b326b1a3..59d1f046 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -327,6 +327,7 @@ clionbin clioncode clionroot + cloudshell cloudtool cloudtoolcmd clrblu diff --git a/CHANGELOG.md b/CHANGELOG.md index 767aa154..3cae4162 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5.25 (20171) +### 1.5.25 (20172) - Added Venetian language (thanks Federico!) - Fixed an issue where chosen-one flashes would remain if the player leaves the game - Added android input-device detection log messages for debugging diff --git a/docs/ba_module.md b/docs/ba_module.md index 3ab90371..988f71c3 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-21 for Ballistica version 1.5.25 build 20171

    +

    last updated on 2020-08-23 for Ballistica version 1.5.25 build 20172

    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!


    From 3eb07cca2ba78382878081ca2d8cfc2395c415e6 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 31 Aug 2020 15:15:20 -0500 Subject: [PATCH 200/417] Language updates and c++ layer fixes --- .efrocachemap | 36 ++--- .idea/dictionaries/ericf.xml | 12 ++ CHANGELOG.md | 2 +- docs/ba_module.md | 2 +- tests/test_efro/test_entity.py | 5 + tools/efro/terminal.py | 248 ++++++++++++++++++++------------- tools/efrotools/code.py | 2 +- tools/efrotools/filecache.py | 2 +- 8 files changed, 193 insertions(+), 116 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 3ac2821f..b970591a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,8 +420,8 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/dd/76/4336a2d6094a2153984c22bf3713", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/29/69/ec6b8725aa7dfa41d0b59f1e9ec1", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/69/87/5e3820d12fc53bd102f3dc1401dc", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/d0/7c/87e7c5b3685a64f0a3ecd9a16b99", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/5a/9e/e8cad6f08b2b19803ab20fdc80d0", @@ -437,10 +437,10 @@ "assets/build/ba_data/data/languages/greek.json": "https://files.ballistica.net/cache/ba1/17/78/3fd0dca40e632ce53d03a944e7fa", "assets/build/ba_data/data/languages/hindi.json": "https://files.ballistica.net/cache/ba1/d5/19/5e450e35b83fe68722330d03b896", "assets/build/ba_data/data/languages/hungarian.json": "https://files.ballistica.net/cache/ba1/87/2d/027aa239eb66ea8f496562f4fd83", - "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/a9/71/817446169ae436e6775f76cd5aec", + "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/9a/3d/9aff685d04d2e1cabb2f9ddafcf3", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/33/04/b1c54ce2b8979cc983aecc781228", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/86/bf/284e1d1c6f07720828754b1ad4c9", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/e4/1a/489284781f8d24b743de3c05da1a", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/88/4b/6745a1a58220772e259f0de51196", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/42/b5/7612cce15fe4555889585108b3ef", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", @@ -450,7 +450,7 @@ "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/b9/6b/adf28849d42f4c195dacf4f53902", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/8a/f7b2521c1904ffc83262dff1e11b", - "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/b8/8c/ac972d1936acf2aaa1d06a4b5ce6", + "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/26/62/a072404c02c576a5c3f09059b582", "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/cb/ae/e4006b346df70380788f24fa2716", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/04/52/683a27aaf9aa7c63e7e595f80d08", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", @@ -940,7 +940,7 @@ "assets/build/ba_data/models/zoeTorso.bob": "https://files.ballistica.net/cache/ba1/88/66/74a21f09ca6cfbfe7352219e43e6", "assets/build/ba_data/models/zoeUpperArm.bob": "https://files.ballistica.net/cache/ba1/99/38/b7694cae0804260eeb337aa1676a", "assets/build/ba_data/models/zoeUpperLeg.bob": "https://files.ballistica.net/cache/ba1/83/4f/28b2202d0109fa93272c0b09fa2d", - "assets/build/ba_data/python-site-packages/typing_extensions.py": "https://files.ballistica.net/cache/ba1/e2/34/5db33f5dc674461d7672a88bd999", + "assets/build/ba_data/python-site-packages/typing_extensions.py": "https://files.ballistica.net/cache/ba1/57/e0/d240d3e3163e12faa7274410aff1", "assets/build/ba_data/python-site-packages/yaml/__init__.py": "https://files.ballistica.net/cache/ba1/ad/6c/07ad575eb2b280b2d22c53c0938f", "assets/build/ba_data/python-site-packages/yaml/composer.py": "https://files.ballistica.net/cache/ba1/3e/aa/d7fcfc4707ad19a6964d72654b82", "assets/build/ba_data/python-site-packages/yaml/constructor.py": "https://files.ballistica.net/cache/ba1/ad/dc/d8a51b583ad1cc74917bb189f9f9", @@ -3928,16 +3928,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/34/30/1f0f29bf2082ba1491ec5f693e5a", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/a9/8cb926cd717fd8a1a777683bc7e0", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/48/13/22c0bb0c91cf41ab34ebda463562", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/62/e0/cc4ac50696743a8864ba4c793a37", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3e/8b/bda7c882274919de97200a73efe5", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/2b/6a/1346ce95d3fceaf22b336a6fe697", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d2/1f/3099ca907a025537990c263a9cf8", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/49/fd6cda67307cacb8d7b8d654561d", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/b7/a8/c401f564941805196e2e0abed89c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/80/3a/977fd3e5392e435660f12d467d4c", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/08/72/73a8a403b228498aad76d9c5ce79", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ae/4d/358c50a4e2cf4cd7b2d4c2b65b32" + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/07/c0bf82b57e34f20a58069edbf651", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/a7/0c55882b9794255f1c5dede196b7", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c5/56/b033099ea96d4113fc434519f2bb", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/58/45/c307135aeb9b0ff3f98778db9db9", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e1/c0/d4e431d897d7bed37f6af21a9c9f", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/60/1d/ed514d5f0e2d6c0d6ca7a9a4c059", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ae/93/1a312729ea081233baf8a5f36be3", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/74/c8/64608e7c5a716cc336fc6425edf2", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/39/db/0246df61ce4d65a8e805437aa3d7", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/4a/b0729f19eee793ddb1a2f7b73fb1" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 59d1f046..f78d0797 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -56,6 +56,7 @@ allsettings allteams aman + amazonaws aname anamorphosis andr @@ -597,6 +598,7 @@ enumtype enumval envhash + envname envval epath epicfail @@ -892,6 +894,7 @@ hatmotion hattach hcalc + hcfg hdpi headercheckline headerregistry @@ -918,11 +921,14 @@ homebook homebrew hometest + hostconfig + hostuser hout howtoplay hpos hscrollwidget hspacing + httprequest hurtiness hval iasset @@ -1096,6 +1102,7 @@ libxm libxmu libxz + linbeast lindex lindexorig linebits @@ -1130,6 +1137,7 @@ lnums loadpackage localconfig + localuser locationgroup locationgroups locationlist @@ -1512,6 +1520,7 @@ pragmas prch prec + precommand preexec preflightfast preflightfull @@ -1919,6 +1928,7 @@ subdeps subdirs subfolders + subname subpath subplatform subplatforms @@ -1946,7 +1956,9 @@ syncable syncall syncalllist + synccfg synccheck + syncconfig syncforce syncfull syncitem diff --git a/CHANGELOG.md b/CHANGELOG.md index 3cae4162..e146c484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5.25 (20172) +### 1.5.25 (20174) - Added Venetian language (thanks Federico!) - Fixed an issue where chosen-one flashes would remain if the player leaves the game - Added android input-device detection log messages for debugging diff --git a/docs/ba_module.md b/docs/ba_module.md index 988f71c3..2242f408 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-23 for Ballistica version 1.5.25 build 20172

    +

    last updated on 2020-08-31 for Ballistica version 1.5.25 build 20175

    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!


    diff --git a/tests/test_efro/test_entity.py b/tests/test_efro/test_entity.py index 063ab689..8af4cf0e 100644 --- a/tests/test_efro/test_entity.py +++ b/tests/test_efro/test_entity.py @@ -27,8 +27,13 @@ from enum import Enum, unique import pytest +# Seeming to get some non-deterministic behavior here as of pylint 2.6.0 +# Where sometimes pylint wants these in one order and sometimes another. +# pylint: disable=useless-suppression +# pylint: disable=wrong-import-order from efro import entity from efrotools.statictest import static_type_equals +# pylint: enable=useless-suppression if TYPE_CHECKING: pass diff --git a/tools/efro/terminal.py b/tools/efro/terminal.py index 3c852e82..3919de7b 100644 --- a/tools/efro/terminal.py +++ b/tools/efro/terminal.py @@ -27,7 +27,7 @@ from enum import Enum, unique from typing import TYPE_CHECKING if TYPE_CHECKING: - from typing import Any + from typing import Any, ClassVar, Type @unique @@ -155,109 +155,169 @@ def _windows_enable_color() -> bool: return False -class Clr: +class ClrBase: + """Base class for color convenience class.""" + RST: ClassVar[str] + BLD: ClassVar[str] + UND: ClassVar[str] + INV: ClassVar[str] + + # Normal foreground colors + BLK: ClassVar[str] + RED: ClassVar[str] + GRN: ClassVar[str] + YLW: ClassVar[str] + BLU: ClassVar[str] + MAG: ClassVar[str] + CYN: ClassVar[str] + WHT: ClassVar[str] + + # Normal background colors. + BBLK: ClassVar[str] + BRED: ClassVar[str] + BGRN: ClassVar[str] + BYLW: ClassVar[str] + BBLU: ClassVar[str] + BMAG: ClassVar[str] + BCYN: ClassVar[str] + BWHT: ClassVar[str] + + # Strong foreground colors + SBLK: ClassVar[str] + SRED: ClassVar[str] + SGRN: ClassVar[str] + SYLW: ClassVar[str] + SBLU: ClassVar[str] + SMAG: ClassVar[str] + SCYN: ClassVar[str] + SWHT: ClassVar[str] + + # Strong background colors. + SBBLK: ClassVar[str] + SBRED: ClassVar[str] + SBGRN: ClassVar[str] + SBYLW: ClassVar[str] + SBBLU: ClassVar[str] + SBMAG: ClassVar[str] + SBCYN: ClassVar[str] + SBWHT: ClassVar[str] + + +class Clr1(ClrBase): """Convenience class for color terminal output. - These will be set to ANSI color escape sequences if the current process - seems to be an interactive terminal (sys.__stdout__.isatty()), otherwise - they will be empty strings. - If the environment variable EFRO_TERMCOLORS is set to 0 or 1, that - value will be used instead. + This version has colors always enabled. Generally you should use Clr which + points to the correct enabled/disabled class depending on the environment. """ - _envval = os.environ.get('EFRO_TERMCOLORS') - color_enabled = (True if _envval == '1' else - False if _envval == '0' else _default_color_enabled()) - if color_enabled: + color_enabled = True - # Styles - RST = TerminalColor.RESET.value - BLD = TerminalColor.BOLD.value - UND = TerminalColor.UNDERLINE.value - INV = TerminalColor.INVERSE.value + # Styles + RST = TerminalColor.RESET.value + BLD = TerminalColor.BOLD.value + UND = TerminalColor.UNDERLINE.value + INV = TerminalColor.INVERSE.value - # Normal foreground colors - BLK = TerminalColor.BLACK.value - RED = TerminalColor.RED.value - GRN = TerminalColor.GREEN.value - YLW = TerminalColor.YELLOW.value - BLU = TerminalColor.BLUE.value - MAG = TerminalColor.MAGENTA.value - CYN = TerminalColor.CYAN.value - WHT = TerminalColor.WHITE.value + # Normal foreground colors + BLK = TerminalColor.BLACK.value + RED = TerminalColor.RED.value + GRN = TerminalColor.GREEN.value + YLW = TerminalColor.YELLOW.value + BLU = TerminalColor.BLUE.value + MAG = TerminalColor.MAGENTA.value + CYN = TerminalColor.CYAN.value + WHT = TerminalColor.WHITE.value - # Normal background colors. - BBLK = TerminalColor.BG_BLACK.value - BRED = TerminalColor.BG_RED.value - BGRN = TerminalColor.BG_GREEN.value - BYLW = TerminalColor.BG_YELLOW.value - BBLU = TerminalColor.BG_BLUE.value - BMAG = TerminalColor.BG_MAGENTA.value - BCYN = TerminalColor.BG_CYAN.value - BWHT = TerminalColor.BG_WHITE.value + # Normal background colors. + BBLK = TerminalColor.BG_BLACK.value + BRED = TerminalColor.BG_RED.value + BGRN = TerminalColor.BG_GREEN.value + BYLW = TerminalColor.BG_YELLOW.value + BBLU = TerminalColor.BG_BLUE.value + BMAG = TerminalColor.BG_MAGENTA.value + BCYN = TerminalColor.BG_CYAN.value + BWHT = TerminalColor.BG_WHITE.value - # Strong foreground colors - SBLK = TerminalColor.STRONG_BLACK.value - SRED = TerminalColor.STRONG_RED.value - SGRN = TerminalColor.STRONG_GREEN.value - SYLW = TerminalColor.STRONG_YELLOW.value - SBLU = TerminalColor.STRONG_BLUE.value - SMAG = TerminalColor.STRONG_MAGENTA.value - SCYN = TerminalColor.STRONG_CYAN.value - SWHT = TerminalColor.STRONG_WHITE.value + # Strong foreground colors + SBLK = TerminalColor.STRONG_BLACK.value + SRED = TerminalColor.STRONG_RED.value + SGRN = TerminalColor.STRONG_GREEN.value + SYLW = TerminalColor.STRONG_YELLOW.value + SBLU = TerminalColor.STRONG_BLUE.value + SMAG = TerminalColor.STRONG_MAGENTA.value + SCYN = TerminalColor.STRONG_CYAN.value + SWHT = TerminalColor.STRONG_WHITE.value - # Strong background colors. - SBBLK = TerminalColor.STRONG_BG_BLACK.value - SBRED = TerminalColor.STRONG_BG_RED.value - SBGRN = TerminalColor.STRONG_BG_GREEN.value - SBYLW = TerminalColor.STRONG_BG_YELLOW.value - SBBLU = TerminalColor.STRONG_BG_BLUE.value - SBMAG = TerminalColor.STRONG_BG_MAGENTA.value - SBCYN = TerminalColor.STRONG_BG_CYAN.value - SBWHT = TerminalColor.STRONG_BG_WHITE.value + # Strong background colors. + SBBLK = TerminalColor.STRONG_BG_BLACK.value + SBRED = TerminalColor.STRONG_BG_RED.value + SBGRN = TerminalColor.STRONG_BG_GREEN.value + SBYLW = TerminalColor.STRONG_BG_YELLOW.value + SBBLU = TerminalColor.STRONG_BG_BLUE.value + SBMAG = TerminalColor.STRONG_BG_MAGENTA.value + SBCYN = TerminalColor.STRONG_BG_CYAN.value + SBWHT = TerminalColor.STRONG_BG_WHITE.value - else: - # Styles - RST = '' - BLD = '' - UND = '' - INV = '' - # Normal foreground colors - BLK = '' - RED = '' - GRN = '' - YLW = '' - BLU = '' - MAG = '' - CYN = '' - WHT = '' +class Clr0(ClrBase): + """Convenience class for color terminal output. - # Normal background colors. - BBLK = '' - BRED = '' - BGRN = '' - BYLW = '' - BBLU = '' - BMAG = '' - BCYN = '' - BWHT = '' + This version has colors disabled. Generally you should use Clr which + points to the correct enabled/disabled class depending on the environment. + """ + color_enabled = False - # Strong foreground colors - SBLK = '' - SRED = '' - SGRN = '' - SYLW = '' - SBLU = '' - SMAG = '' - SCYN = '' - SWHT = '' + # Styles + RST = '' + BLD = '' + UND = '' + INV = '' - # Strong background colors. - SBBLK = '' - SBRED = '' - SBGRN = '' - SBYLW = '' - SBBLU = '' - SBMAG = '' - SBCYN = '' - SBWHT = '' + # Normal foreground colors + BLK = '' + RED = '' + GRN = '' + YLW = '' + BLU = '' + MAG = '' + CYN = '' + WHT = '' + + # Normal background colors. + BBLK = '' + BRED = '' + BGRN = '' + BYLW = '' + BBLU = '' + BMAG = '' + BCYN = '' + BWHT = '' + + # Strong foreground colors + SBLK = '' + SRED = '' + SGRN = '' + SYLW = '' + SBLU = '' + SMAG = '' + SCYN = '' + SWHT = '' + + # Strong background colors. + SBBLK = '' + SBRED = '' + SBGRN = '' + SBYLW = '' + SBBLU = '' + SBMAG = '' + SBCYN = '' + SBWHT = '' + + +_envval = os.environ.get('EFRO_TERMCOLORS') +_color_enabled: bool = (True if _envval == '1' else + False if _envval == '0' else _default_color_enabled()) +Clr: Type[ClrBase] +if _color_enabled: + Clr = Clr1 +else: + Clr = Clr0 diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 35f47d78..63ec4bc3 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -622,7 +622,7 @@ def dmypy(projroot: Path) -> None: try: args = [ 'dmypy', 'run', '--timeout', '3600', '--', '--config-file', - '.mypy.ini', '--follow-imports=error', '--pretty' + '.mypy.ini', '--pretty' ] + filenames subprocess.run(args, check=True) except Exception as exc: diff --git a/tools/efrotools/filecache.py b/tools/efrotools/filecache.py index 1d582e38..77539068 100644 --- a/tools/efrotools/filecache.py +++ b/tools/efrotools/filecache.py @@ -26,8 +26,8 @@ import json import os from typing import TYPE_CHECKING -from efro.terminal import Clr from efrotools import get_files_hash +from efro.terminal import Clr if TYPE_CHECKING: from typing import Dict, Optional, Sequence, Any From b0523ea5b161789b0a1815824ed2223de32c0700 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 2 Sep 2020 16:18:12 -0500 Subject: [PATCH 201/417] Added log output for android asset-sync phase --- CHANGELOG.md | 3 ++- tools/efrotools/pcommand.py | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e146c484..9649c48a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ -### 1.5.25 (20174) +### 1.5.25 (20175) - Added Venetian language (thanks Federico!) - Fixed an issue where chosen-one flashes would remain if the player leaves the game - Added android input-device detection log messages for debugging +- Android asset-sync phase (completing install...) now emits log output for debugging. ### 1.5.24 (20163) - Upgraded Python from version 3.7 to 3.8. This is a substantial change (though nothing like the previous update from 2.7 to 3.7) so please holler if anything is broken. These updates will happen once every year or two now.. diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index a75a656b..57849d74 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -372,7 +372,13 @@ def _filter_tool_config(cfg: str) -> str: cfg = cfg.replace('__EFRO_PROJECT_ROOT__', str(PROJROOT)) # Short project name. - short_names = {'ballistica-internal': 'ba-int', 'ballistica': 'ba'} + short_names = { + 'ballistica-internal': 'ba-int', + 'ballistica': 'ba', + 'ballistica-master-server-2.0': 'bamaster2', + 'ballistica-master-server': 'bamaster', + 'ballistica-server-node': 'baservnode', + } shortname = short_names.get(PROJROOT.name, PROJROOT.name) cfg = cfg.replace('__EFRO_PROJECT_SHORTNAME__', shortname) From ac2e748c51be1db39aac1fc039bf65152393c5ec Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 6 Sep 2020 13:17:38 -0500 Subject: [PATCH 202/417] Build system improvements --- .efrocachemap | 20 ++++++++++---------- .idea/dictionaries/ericf.xml | 10 ++++++++++ CHANGELOG.md | 2 +- tools/batools/build.py | 7 +++---- 4 files changed, 24 insertions(+), 15 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index b970591a..3ce9104a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3930,14 +3930,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/07/c0bf82b57e34f20a58069edbf651", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ca/a7/0c55882b9794255f1c5dede196b7", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c5/56/b033099ea96d4113fc434519f2bb", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/58/45/c307135aeb9b0ff3f98778db9db9", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e1/c0/d4e431d897d7bed37f6af21a9c9f", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/60/1d/ed514d5f0e2d6c0d6ca7a9a4c059", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ae/93/1a312729ea081233baf8a5f36be3", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/74/c8/64608e7c5a716cc336fc6425edf2", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/39/db/0246df61ce4d65a8e805437aa3d7", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/4a/b0729f19eee793ddb1a2f7b73fb1" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/25/c53d807027893a776c6ebacedba4", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/84/bc/afaf493d73932639a1df0d689158", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/38/1ac23b6476d4fe77d9a82be52eae", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/1a/4bec9010414391b6ece113b659ca", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/1f/6dfe3c5638b23e6524946ee0fd30", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/c1/915052e847075e26c14d309f8bb9", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0f/54/4b9c86bb0cfcfe728e1b339333d5", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/83/53/e6a28ed5caef6be78dc556f91e3b", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b7/7d/d2075b867fc7e1cd281d0f87fd66", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b6/29/f05e7a8507a4f0c1c20594b592a1" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index f78d0797..5fec9375 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -160,6 +160,7 @@ baseh basemult basepos + baservnode basespaz basetime baseurl @@ -240,6 +241,7 @@ buildfile buildfilename buildnum + buildserver buildtype bullseye bumpmap @@ -329,6 +331,7 @@ clioncode clionroot cloudshell + cloudshellbuild cloudtool cloudtoolcmd clrblu @@ -397,6 +400,8 @@ cornerpin coroutines countdownsounds + cpbd + cpnf cpplint cpplintcode cpplintcodefull @@ -409,6 +414,8 @@ creationflags creditslist cryptmodule + cspbd + cspnf cssclass cstr csum @@ -1029,6 +1036,8 @@ jsonutils kbclass kbytecount + keepalive + keepalives keepaway keeprefs keylayout @@ -1137,6 +1146,7 @@ lnums loadpackage localconfig + localdir localuser locationgroup locationgroups diff --git a/CHANGELOG.md b/CHANGELOG.md index 9649c48a..ee31f156 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.5.25 (20175) +### 1.5.25 (20176) - Added Venetian language (thanks Federico!) - Fixed an issue where chosen-one flashes would remain if the player leaves the game - Added android input-device detection log messages for debugging diff --git a/tools/batools/build.py b/tools/batools/build.py index 5f181bf3..a85d4b3d 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -430,19 +430,18 @@ def gen_fulltest_buildfile_linux() -> None: dayoffset = datetime.datetime.now().timetuple().tm_yday targets = ['build', 'server-build'] - linflav = 'LINUX_FLAVOR=u18s' lines = [] for target in targets: - lines.append(f'{linflav} make linux-{target}') + lines.append(f'make cmake-cloudshell-{target}') if DO_SPARSE_TEST_BUILDS: extras = SPARSE_TEST_BUILDS[dayoffset % len(SPARSE_TEST_BUILDS)] extras = [e for e in extras if e.startswith('linux.')] for extra in extras: if extra == 'linux.package': - lines.append(f'{linflav} make linux-package') + lines.append('make linux-package') elif extra == 'linux.package.server': - lines.append(f'{linflav} make linux-server-package') + lines.append('make linux-server-package') else: raise RuntimeError(f'Unknown extra: {extra}') From fc94a640bcd57218bce34bfd216f19f4a1e58558 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 9 Sep 2020 10:07:00 -0500 Subject: [PATCH 203/417] Language updates --- .efrocachemap | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 3ce9104a..08d69e93 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,13 +420,13 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/69/87/5e3820d12fc53bd102f3dc1401dc", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/9d/cd/25cfecf21ff50b3a25e5e7318dc0", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/d0/7c/87e7c5b3685a64f0a3ecd9a16b99", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/5a/9e/e8cad6f08b2b19803ab20fdc80d0", - "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/c7/ea/7b4357666b328b991fe82ea9a3fb", - "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/dd/5a/14ca3ebb92a802315921e2b2b215", + "assets/build/ba_data/data/languages/croatian.json": "https://files.ballistica.net/cache/ba1/56/02/c22deb7174aabdcbffe1da23e484", + "assets/build/ba_data/data/languages/czech.json": "https://files.ballistica.net/cache/ba1/97/6c/61de67c477c98b7c4fddd22e6ae0", "assets/build/ba_data/data/languages/danish.json": "https://files.ballistica.net/cache/ba1/3f/46/e4da3c1d2b0ebf916df55c608b28", "assets/build/ba_data/data/languages/dutch.json": "https://files.ballistica.net/cache/ba1/d1/07/37b7adc3dbec7328d26c5325f212", "assets/build/ba_data/data/languages/english.json": "https://files.ballistica.net/cache/ba1/d4/5b/fbd64cf1846340db0606824568c2", @@ -3930,14 +3930,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d5/25/c53d807027893a776c6ebacedba4", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/84/bc/afaf493d73932639a1df0d689158", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/7b/38/1ac23b6476d4fe77d9a82be52eae", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/18/1a/4bec9010414391b6ece113b659ca", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/1f/6dfe3c5638b23e6524946ee0fd30", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/aa/c1/915052e847075e26c14d309f8bb9", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0f/54/4b9c86bb0cfcfe728e1b339333d5", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/83/53/e6a28ed5caef6be78dc556f91e3b", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b7/7d/d2075b867fc7e1cd281d0f87fd66", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b6/29/f05e7a8507a4f0c1c20594b592a1" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c8/b7/be926cab5936af26d6937bbe6705", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/53/f1a8f16ce3e3ba70f28366b0841b", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5f/a4/b2f5e98421d6e9a1c82bbddd1d9c", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/a4/c266c177ebe02bb6d2f9ccd88008", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/54/01/1e357e967597f1c166b48a084db7", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/67/1c/10987ea2d968ddb87dbc13f2bb23", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0b/6f/b8436a005bd90b370045aedd64f7", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4d/39/6ff5437d7a7ac964d157520cebad", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/84/b7/c77ac0a82852ef112743365e0547", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2d/3a/8ad49990f669d8594599d816578c" } \ No newline at end of file From 2aec1cc1d306e344b17c12f00d9c4189e4374fab Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 11 Sep 2020 18:41:48 -0500 Subject: [PATCH 204/417] Simplified copyright headers --- .efrocachemap | 20 ++-- .idea/dictionaries/ericf.xml | 15 ++- CHANGELOG.md | 3 + assets/.asset_manifest_public.json | 2 + assets/Makefile | 2 + assets/src/ba_data/python/_ba.py | 20 +--- assets/src/ba_data/python/ba/__init__.py | 20 +--- assets/src/ba_data/python/ba/_account.py | 20 +--- assets/src/ba_data/python/ba/_achievement.py | 20 +--- assets/src/ba_data/python/ba/_activity.py | 20 +--- .../src/ba_data/python/ba/_activitytypes.py | 20 +--- assets/src/ba_data/python/ba/_actor.py | 20 +--- assets/src/ba_data/python/ba/_analytics.py | 20 +--- assets/src/ba_data/python/ba/_app.py | 20 +--- assets/src/ba_data/python/ba/_appconfig.py | 20 +--- assets/src/ba_data/python/ba/_appdelegate.py | 20 +--- assets/src/ba_data/python/ba/_appmode.py | 3 + assets/src/ba_data/python/ba/_apputils.py | 20 +--- assets/src/ba_data/python/ba/_assetmanager.py | 20 +--- assets/src/ba_data/python/ba/_benchmark.py | 20 +--- assets/src/ba_data/python/ba/_campaign.py | 20 +--- assets/src/ba_data/python/ba/_collision.py | 20 +--- assets/src/ba_data/python/ba/_coopgame.py | 20 +--- assets/src/ba_data/python/ba/_coopsession.py | 20 +--- assets/src/ba_data/python/ba/_dependency.py | 20 +--- .../src/ba_data/python/ba/_dualteamsession.py | 20 +--- assets/src/ba_data/python/ba/_enums.py | 21 +--- assets/src/ba_data/python/ba/_error.py | 20 +--- .../ba_data/python/ba/_freeforallsession.py | 20 +--- assets/src/ba_data/python/ba/_gameactivity.py | 20 +--- assets/src/ba_data/python/ba/_gameresults.py | 20 +--- assets/src/ba_data/python/ba/_gameutils.py | 20 +--- assets/src/ba_data/python/ba/_general.py | 20 +--- assets/src/ba_data/python/ba/_hooks.py | 20 +--- assets/src/ba_data/python/ba/_input.py | 20 +--- assets/src/ba_data/python/ba/_keyboard.py | 20 +--- assets/src/ba_data/python/ba/_lang.py | 20 +--- assets/src/ba_data/python/ba/_level.py | 20 +--- assets/src/ba_data/python/ba/_lobby.py | 20 +--- assets/src/ba_data/python/ba/_map.py | 20 +--- assets/src/ba_data/python/ba/_math.py | 20 +--- assets/src/ba_data/python/ba/_messages.py | 20 +--- assets/src/ba_data/python/ba/_meta.py | 20 +--- .../ba_data/python/ba/_multiteamsession.py | 20 +--- assets/src/ba_data/python/ba/_music.py | 20 +--- assets/src/ba_data/python/ba/_netutils.py | 20 +--- assets/src/ba_data/python/ba/_nodeactor.py | 20 +--- assets/src/ba_data/python/ba/_player.py | 20 +--- assets/src/ba_data/python/ba/_playlist.py | 20 +--- assets/src/ba_data/python/ba/_plugin.py | 20 +--- assets/src/ba_data/python/ba/_powerup.py | 20 +--- assets/src/ba_data/python/ba/_profile.py | 20 +--- assets/src/ba_data/python/ba/_score.py | 20 +--- assets/src/ba_data/python/ba/_servermode.py | 20 +--- assets/src/ba_data/python/ba/_session.py | 20 +--- assets/src/ba_data/python/ba/_settings.py | 20 +--- assets/src/ba_data/python/ba/_stats.py | 20 +--- assets/src/ba_data/python/ba/_store.py | 20 +--- assets/src/ba_data/python/ba/_team.py | 20 +--- assets/src/ba_data/python/ba/_teamgame.py | 20 +--- assets/src/ba_data/python/ba/_tips.py | 20 +--- assets/src/ba_data/python/ba/_tournament.py | 20 +--- assets/src/ba_data/python/ba/_ui.py | 20 +--- assets/src/ba_data/python/ba/deprecated.py | 20 +--- assets/src/ba_data/python/ba/internal.py | 20 +--- assets/src/ba_data/python/ba/macmusicapp.py | 20 +--- assets/src/ba_data/python/ba/modutils.py | 20 +--- assets/src/ba_data/python/ba/osmusic.py | 20 +--- assets/src/ba_data/python/ba/ui/__init__.py | 20 +--- assets/src/ba_data/python/bastd/__init__.py | 20 +--- .../ba_data/python/bastd/activity/coopjoin.py | 20 +--- .../python/bastd/activity/coopscore.py | 20 +--- .../python/bastd/activity/drawscore.py | 20 +--- .../python/bastd/activity/dualteamscore.py | 20 +--- .../bastd/activity/freeforallvictory.py | 20 +--- .../python/bastd/activity/multiteamjoin.py | 20 +--- .../python/bastd/activity/multiteamscore.py | 20 +--- .../python/bastd/activity/multiteamvictory.py | 20 +--- .../ba_data/python/bastd/actor/background.py | 20 +--- assets/src/ba_data/python/bastd/actor/bomb.py | 20 +--- .../python/bastd/actor/controlsguide.py | 20 +--- assets/src/ba_data/python/bastd/actor/flag.py | 20 +--- .../src/ba_data/python/bastd/actor/image.py | 20 +--- .../python/bastd/actor/onscreencountdown.py | 20 +--- .../python/bastd/actor/onscreentimer.py | 20 +--- .../ba_data/python/bastd/actor/playerspaz.py | 20 +--- .../ba_data/python/bastd/actor/popuptext.py | 20 +--- .../ba_data/python/bastd/actor/powerupbox.py | 20 +--- .../ba_data/python/bastd/actor/respawnicon.py | 20 +--- .../ba_data/python/bastd/actor/scoreboard.py | 20 +--- .../src/ba_data/python/bastd/actor/spawner.py | 20 +--- assets/src/ba_data/python/bastd/actor/spaz.py | 20 +--- .../python/bastd/actor/spazappearance.py | 20 +--- .../src/ba_data/python/bastd/actor/spazbot.py | 20 +--- .../ba_data/python/bastd/actor/spazfactory.py | 20 +--- assets/src/ba_data/python/bastd/actor/text.py | 20 +--- .../ba_data/python/bastd/actor/tipstext.py | 20 +--- .../ba_data/python/bastd/actor/zoomtext.py | 20 +--- .../src/ba_data/python/bastd/appdelegate.py | 20 +--- .../src/ba_data/python/bastd/game/assault.py | 20 +--- .../python/bastd/game/capturetheflag.py | 20 +--- .../ba_data/python/bastd/game/chosenone.py | 20 +--- .../src/ba_data/python/bastd/game/conquest.py | 20 +--- .../ba_data/python/bastd/game/deathmatch.py | 20 +--- .../python/bastd/game/easteregghunt.py | 20 +--- .../ba_data/python/bastd/game/elimination.py | 20 +--- .../src/ba_data/python/bastd/game/football.py | 20 +--- .../src/ba_data/python/bastd/game/hockey.py | 20 +--- .../src/ba_data/python/bastd/game/keepaway.py | 20 +--- .../python/bastd/game/kingofthehill.py | 20 +--- .../ba_data/python/bastd/game/meteorshower.py | 20 +--- .../ba_data/python/bastd/game/ninjafight.py | 20 +--- .../ba_data/python/bastd/game/onslaught.py | 20 +--- assets/src/ba_data/python/bastd/game/race.py | 20 +--- .../ba_data/python/bastd/game/runaround.py | 20 +--- .../python/bastd/game/targetpractice.py | 20 +--- .../ba_data/python/bastd/game/thelaststand.py | 20 +--- assets/src/ba_data/python/bastd/gameutils.py | 20 +--- .../python/bastd/keyboard/englishkeyboard.py | 20 +--- assets/src/ba_data/python/bastd/mainmenu.py | 20 +--- .../src/ba_data/python/bastd/mapdata/big_g.py | 21 +--- .../ba_data/python/bastd/mapdata/bridgit.py | 21 +--- .../ba_data/python/bastd/mapdata/courtyard.py | 21 +--- .../python/bastd/mapdata/crag_castle.py | 21 +--- .../python/bastd/mapdata/doom_shroom.py | 21 +--- .../python/bastd/mapdata/football_stadium.py | 21 +--- .../python/bastd/mapdata/happy_thoughts.py | 21 +--- .../python/bastd/mapdata/hockey_stadium.py | 21 +--- .../python/bastd/mapdata/lake_frigid.py | 21 +--- .../python/bastd/mapdata/monkey_face.py | 21 +--- .../ba_data/python/bastd/mapdata/rampage.py | 21 +--- .../python/bastd/mapdata/roundabout.py | 21 +--- .../python/bastd/mapdata/step_right_up.py | 21 +--- .../ba_data/python/bastd/mapdata/the_pad.py | 21 +--- .../ba_data/python/bastd/mapdata/tip_top.py | 21 +--- .../ba_data/python/bastd/mapdata/tower_d.py | 21 +--- .../ba_data/python/bastd/mapdata/zig_zag.py | 21 +--- assets/src/ba_data/python/bastd/maps.py | 20 +--- assets/src/ba_data/python/bastd/stdmap.py | 20 +--- assets/src/ba_data/python/bastd/tutorial.py | 20 +--- .../src/ba_data/python/bastd/ui/__init__.py | 20 +--- .../python/bastd/ui/account/__init__.py | 20 +--- .../ba_data/python/bastd/ui/account/link.py | 20 +--- .../python/bastd/ui/account/settings.py | 20 +--- .../ba_data/python/bastd/ui/account/unlink.py | 20 +--- .../ba_data/python/bastd/ui/account/viewer.py | 20 +--- .../ba_data/python/bastd/ui/achievements.py | 20 +--- .../src/ba_data/python/bastd/ui/appinvite.py | 20 +--- .../python/bastd/ui/characterpicker.py | 20 +--- .../ba_data/python/bastd/ui/colorpicker.py | 20 +--- assets/src/ba_data/python/bastd/ui/config.py | 20 +--- .../ba_data/python/bastd/ui/configerror.py | 20 +--- assets/src/ba_data/python/bastd/ui/confirm.py | 20 +--- .../src/ba_data/python/bastd/ui/continues.py | 20 +--- .../ba_data/python/bastd/ui/coop/browser.py | 20 +--- .../python/bastd/ui/coop/gamebutton.py | 20 +--- .../src/ba_data/python/bastd/ui/coop/level.py | 20 +--- .../ba_data/python/bastd/ui/creditslist.py | 20 +--- assets/src/ba_data/python/bastd/ui/debug.py | 20 +--- .../src/ba_data/python/bastd/ui/feedback.py | 20 +--- .../ba_data/python/bastd/ui/fileselector.py | 20 +--- assets/src/ba_data/python/bastd/ui/gather.py | 20 +--- .../ba_data/python/bastd/ui/getcurrency.py | 20 +--- .../src/ba_data/python/bastd/ui/getremote.py | 20 +--- assets/src/ba_data/python/bastd/ui/helpui.py | 20 +--- .../src/ba_data/python/bastd/ui/iconpicker.py | 20 +--- assets/src/ba_data/python/bastd/ui/kiosk.py | 20 +--- .../python/bastd/ui/league/__init__.py | 20 +--- .../python/bastd/ui/league/rankbutton.py | 20 +--- .../python/bastd/ui/league/rankwindow.py | 20 +--- .../src/ba_data/python/bastd/ui/mainmenu.py | 20 +--- .../python/bastd/ui/onscreenkeyboard.py | 20 +--- assets/src/ba_data/python/bastd/ui/party.py | 20 +--- .../src/ba_data/python/bastd/ui/partyqueue.py | 20 +--- assets/src/ba_data/python/bastd/ui/play.py | 20 +--- .../python/bastd/ui/playlist/__init__.py | 20 +--- .../python/bastd/ui/playlist/addgame.py | 20 +--- .../python/bastd/ui/playlist/browser.py | 20 +--- .../bastd/ui/playlist/customizebrowser.py | 20 +--- .../ba_data/python/bastd/ui/playlist/edit.py | 20 +--- .../bastd/ui/playlist/editcontroller.py | 20 +--- .../python/bastd/ui/playlist/editgame.py | 20 +--- .../python/bastd/ui/playlist/mapselect.py | 20 +--- .../ba_data/python/bastd/ui/playlist/share.py | 20 +--- .../ba_data/python/bastd/ui/playoptions.py | 20 +--- assets/src/ba_data/python/bastd/ui/popup.py | 20 +--- .../python/bastd/ui/profile/browser.py | 20 +--- .../ba_data/python/bastd/ui/profile/edit.py | 20 +--- .../python/bastd/ui/profile/upgrade.py | 20 +--- .../src/ba_data/python/bastd/ui/promocode.py | 20 +--- .../src/ba_data/python/bastd/ui/purchase.py | 20 +--- assets/src/ba_data/python/bastd/ui/qrcode.py | 20 +--- .../src/ba_data/python/bastd/ui/radiogroup.py | 20 +--- assets/src/ba_data/python/bastd/ui/report.py | 20 +--- .../python/bastd/ui/resourcetypeinfo.py | 20 +--- .../ba_data/python/bastd/ui/serverdialog.py | 20 +--- .../python/bastd/ui/settings/advanced.py | 20 +--- .../python/bastd/ui/settings/allsettings.py | 20 +--- .../ba_data/python/bastd/ui/settings/audio.py | 20 +--- .../python/bastd/ui/settings/controls.py | 20 +--- .../python/bastd/ui/settings/gamepad.py | 20 +--- .../bastd/ui/settings/gamepadadvanced.py | 20 +--- .../python/bastd/ui/settings/gamepadselect.py | 20 +--- .../python/bastd/ui/settings/graphics.py | 20 +--- .../python/bastd/ui/settings/keyboard.py | 20 +--- .../python/bastd/ui/settings/nettesting.py | 20 +--- .../python/bastd/ui/settings/plugins.py | 20 +--- .../python/bastd/ui/settings/ps3controller.py | 20 +--- .../python/bastd/ui/settings/remoteapp.py | 20 +--- .../python/bastd/ui/settings/testing.py | 20 +--- .../python/bastd/ui/settings/touchscreen.py | 20 +--- .../python/bastd/ui/settings/vrtesting.py | 20 +--- .../python/bastd/ui/settings/wiimote.py | 20 +--- .../bastd/ui/settings/xbox360controller.py | 20 +--- .../python/bastd/ui/soundtrack/browser.py | 20 +--- .../python/bastd/ui/soundtrack/edit.py | 20 +--- .../bastd/ui/soundtrack/entrytypeselect.py | 20 +--- .../python/bastd/ui/soundtrack/macmusicapp.py | 20 +--- .../ba_data/python/bastd/ui/specialoffer.py | 20 +--- .../ba_data/python/bastd/ui/store/browser.py | 20 +--- .../ba_data/python/bastd/ui/store/button.py | 20 +--- .../src/ba_data/python/bastd/ui/store/item.py | 20 +--- assets/src/ba_data/python/bastd/ui/tabs.py | 20 +--- .../python/bastd/ui/teamnamescolors.py | 20 +--- assets/src/ba_data/python/bastd/ui/telnet.py | 20 +--- .../python/bastd/ui/tournamententry.py | 20 +--- .../python/bastd/ui/tournamentscores.py | 20 +--- .../src/ba_data/python/bastd/ui/trophies.py | 20 +--- assets/src/ba_data/python/bastd/ui/url.py | 20 +--- assets/src/ba_data/python/bastd/ui/watch.py | 20 +--- assets/src/server/ballisticacore_server.py | 20 +--- docs/ba_module.md | 2 +- tests/test_ba/test_assetmanager.py | 20 +--- tests/test_efro/test_dataclasses.py | 20 +--- tests/test_efro/test_entity.py | 20 +--- tools/bacloud | 20 +--- tools/bacommon/__init__.py | 20 +--- tools/bacommon/assets.py | 20 +--- tools/bacommon/err.py | 20 +--- tools/bacommon/servermanager.py | 20 +--- tools/batools/__init__.py | 20 +--- tools/batools/android.py | 20 +--- tools/batools/assetsmakefile.py | 20 +--- tools/batools/assetstaging.py | 20 +--- tools/batools/build.py | 24 +--- tools/batools/pcommand.py | 58 ++++------ tools/batools/updateproject.py | 109 ++++++++---------- tools/efro/__init__.py | 20 +--- tools/efro/call.py | 20 +--- tools/efro/dataclasses.py | 20 +--- tools/efro/entity/__init__.py | 20 +--- tools/efro/entity/_base.py | 20 +--- tools/efro/entity/_entity.py | 20 +--- tools/efro/entity/_field.py | 20 +--- tools/efro/entity/_support.py | 20 +--- tools/efro/entity/_value.py | 20 +--- tools/efro/entity/util.py | 20 +--- tools/efro/error.py | 20 +--- tools/efro/json.py | 20 +--- tools/efro/terminal.py | 20 +--- tools/efro/util.py | 20 +--- tools/efrotools/__init__.py | 25 +--- tools/efrotools/android.py | 20 +--- tools/efrotools/code.py | 20 +--- tools/efrotools/efrocache.py | 22 +--- tools/efrotools/filecache.py | 20 +--- tools/efrotools/ios.py | 20 +--- tools/efrotools/jsontools.py | 20 +--- tools/efrotools/makefile.py | 20 +--- tools/efrotools/pcommand.py | 20 +--- tools/efrotools/pybuild.py | 20 +--- tools/efrotools/pylintplugins.py | 20 +--- tools/efrotools/statictest.py | 20 +--- tools/efrotools/sync.py | 20 +--- tools/pcommand | 20 +--- 275 files changed, 393 insertions(+), 5170 deletions(-) create mode 100644 assets/src/ba_data/python/ba/_appmode.py diff --git a/.efrocachemap b/.efrocachemap index 08d69e93..0027084b 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3930,14 +3930,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/c8/b7/be926cab5936af26d6937bbe6705", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/dd/53/f1a8f16ce3e3ba70f28366b0841b", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5f/a4/b2f5e98421d6e9a1c82bbddd1d9c", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/41/a4/c266c177ebe02bb6d2f9ccd88008", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/54/01/1e357e967597f1c166b48a084db7", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/67/1c/10987ea2d968ddb87dbc13f2bb23", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/0b/6f/b8436a005bd90b370045aedd64f7", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4d/39/6ff5437d7a7ac964d157520cebad", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/84/b7/c77ac0a82852ef112743365e0547", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2d/3a/8ad49990f669d8594599d816578c" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/33/9e/3106cd524bfe83e8ca3ba603a0a3", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/88/77db83b5fe1218a99392f88b7131", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/74/74dcfb32ee1d796230cfac867978", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/63/5067f6fae12feecaa181d4f13a4d", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/d7/2abece41eae6a109583d75300528", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/15/0ba36634e2d80e8bed3922a63b24", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a0/7f/587e6a6d3dece7669d09bd042701", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ad/4c/7b78e4c0a2e65a62fee7e38e34e7", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c4/f8/1f8eee280877672da222c3397429", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/74/c7/dc173d3207f3ff2912093d28de98" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 5fec9375..39f4e51a 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack'ed ack + ack'ed acked acks acnt @@ -150,8 +150,8 @@ bacommon badguy bafoundation - ballistica's ballistica + ballistica's ballisticacore ballisticacorecb bamaster @@ -607,6 +607,7 @@ envhash envname envval + envvar epath epicfail ericf @@ -790,8 +791,8 @@ gamedata gameinstance gamemap - gamepad's gamepad + gamepad's gamepadadvanced gamepads gamepadselect @@ -1098,6 +1099,7 @@ libinst liblzma libmain + libogg libopena libopenal libpython @@ -1170,8 +1172,8 @@ lsqlite lssl lstart - lstr's lstr + lstr's lstrs lsval ltex @@ -1793,8 +1795,8 @@ sessionname sessionplayer sessionplayers - sessionteam's sessionteam + sessionteam's sessionteams sessiontype setactivity @@ -2087,6 +2089,7 @@ toplevelfiles totaldudes totalpts + totaltime totalwaves totype touchpad @@ -2123,8 +2126,8 @@ txtw typeargs typecheck - typechecker's typechecker + typechecker's typedval typeshed typestr diff --git a/CHANGELOG.md b/CHANGELOG.md index ee31f156..37779695 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +### 1.5.26 (20178) +- Simplified licensing header on python scripts. + ### 1.5.25 (20176) - Added Venetian language (thanks Federico!) - Fixed an issue where chosen-one flashes would remain if the player leaves the game diff --git a/assets/.asset_manifest_public.json b/assets/.asset_manifest_public.json index cb611882..19bd2d97 100644 --- a/assets/.asset_manifest_public.json +++ b/assets/.asset_manifest_public.json @@ -10,6 +10,7 @@ "ba_data/python/ba/__pycache__/_app.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_appconfig.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_appdelegate.cpython-38.opt-1.pyc", + "ba_data/python/ba/__pycache__/_appmode.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_apputils.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_assetmanager.cpython-38.opt-1.pyc", "ba_data/python/ba/__pycache__/_benchmark.cpython-38.opt-1.pyc", @@ -70,6 +71,7 @@ "ba_data/python/ba/_app.py", "ba_data/python/ba/_appconfig.py", "ba_data/python/ba/_appdelegate.py", + "ba_data/python/ba/_appmode.py", "ba_data/python/ba/_apputils.py", "ba_data/python/ba/_assetmanager.py", "ba_data/python/ba/_benchmark.py", diff --git a/assets/Makefile b/assets/Makefile index 4efd83ac..e1bd6ec3 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -159,6 +159,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \ build/ba_data/python/ba/_app.py \ build/ba_data/python/ba/_appconfig.py \ build/ba_data/python/ba/_appdelegate.py \ + build/ba_data/python/ba/_appmode.py \ build/ba_data/python/ba/_apputils.py \ build/ba_data/python/ba/_assetmanager.py \ build/ba_data/python/ba/_benchmark.py \ @@ -396,6 +397,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \ build/ba_data/python/ba/__pycache__/_app.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_appconfig.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_appdelegate.cpython-38.opt-1.pyc \ + build/ba_data/python/ba/__pycache__/_appmode.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_apputils.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_assetmanager.cpython-38.opt-1.pyc \ build/ba_data/python/ba/__pycache__/_benchmark.cpython-38.opt-1.pyc \ diff --git a/assets/src/ba_data/python/_ba.py b/assets/src/ba_data/python/_ba.py index 9a1493cc..cb7afb6b 100644 --- a/assets/src/ba_data/python/_ba.py +++ b/assets/src/ba_data/python/_ba.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """A dummy stub module for the real _ba. The real _ba is a compiled extension module and only available diff --git a/assets/src/ba_data/python/ba/__init__.py b/assets/src/ba_data/python/ba/__init__.py index 808338ed..67440e76 100644 --- a/assets/src/ba_data/python/ba/__init__.py +++ b/assets/src/ba_data/python/ba/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """The public face of Ballistica. This top level module is a collection of most commonly used functionality. diff --git a/assets/src/ba_data/python/ba/_account.py b/assets/src/ba_data/python/ba/_account.py index a355ed54..ecdfbd6b 100644 --- a/assets/src/ba_data/python/ba/_account.py +++ b/assets/src/ba_data/python/ba/_account.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Account related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_achievement.py b/assets/src/ba_data/python/ba/_achievement.py index 73165ba8..7a616476 100644 --- a/assets/src/ba_data/python/ba/_achievement.py +++ b/assets/src/ba_data/python/ba/_achievement.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Various functionality related to achievements.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_activity.py b/assets/src/ba_data/python/ba/_activity.py index 1eefd4b1..4a17c1ae 100644 --- a/assets/src/ba_data/python/ba/_activity.py +++ b/assets/src/ba_data/python/ba/_activity.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Activity class.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_activitytypes.py b/assets/src/ba_data/python/ba/_activitytypes.py index 2d8b917e..d739ba86 100644 --- a/assets/src/ba_data/python/ba/_activitytypes.py +++ b/assets/src/ba_data/python/ba/_activitytypes.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Some handy base class and special purpose Activity types.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_actor.py b/assets/src/ba_data/python/ba/_actor.py index f70dd780..2751eb3c 100644 --- a/assets/src/ba_data/python/ba/_actor.py +++ b/assets/src/ba_data/python/ba/_actor.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines base Actor class.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_analytics.py b/assets/src/ba_data/python/ba/_analytics.py index f01853fd..27c89964 100644 --- a/assets/src/ba_data/python/ba/_analytics.py +++ b/assets/src/ba_data/python/ba/_analytics.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to analytics.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index e6d9d839..058fd1ac 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the high level state of the app.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_appconfig.py b/assets/src/ba_data/python/ba/_appconfig.py index d4d5b35b..3e9828a7 100644 --- a/assets/src/ba_data/python/ba/_appconfig.py +++ b/assets/src/ba_data/python/ba/_appconfig.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides the AppConfig class.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_appdelegate.py b/assets/src/ba_data/python/ba/_appdelegate.py index e1cf5431..f6282bec 100644 --- a/assets/src/ba_data/python/ba/_appdelegate.py +++ b/assets/src/ba_data/python/ba/_appdelegate.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines AppDelegate class for handling high level app functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_appmode.py b/assets/src/ba_data/python/ba/_appmode.py new file mode 100644 index 00000000..ccec7ab7 --- /dev/null +++ b/assets/src/ba_data/python/ba/_appmode.py @@ -0,0 +1,3 @@ +# Released under the MIT License. See LICENSE for details. +# +"""Functionality related to the high level state of the app.""" diff --git a/assets/src/ba_data/python/ba/_apputils.py b/assets/src/ba_data/python/ba/_apputils.py index d98cea00..ea2ba64d 100644 --- a/assets/src/ba_data/python/ba/_apputils.py +++ b/assets/src/ba_data/python/ba/_apputils.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Utility functionality related to the overall operation of the app.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_assetmanager.py b/assets/src/ba_data/python/ba/_assetmanager.py index dcf58d67..118f2306 100644 --- a/assets/src/ba_data/python/ba/_assetmanager.py +++ b/assets/src/ba_data/python/ba/_assetmanager.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to managing cloud based assets.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_benchmark.py b/assets/src/ba_data/python/ba/_benchmark.py index 2dedcdaa..c5b0618d 100644 --- a/assets/src/ba_data/python/ba/_benchmark.py +++ b/assets/src/ba_data/python/ba/_benchmark.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Benchmark/Stress-Test related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_campaign.py b/assets/src/ba_data/python/ba/_campaign.py index 30554edf..77f4ce92 100644 --- a/assets/src/ba_data/python/ba/_campaign.py +++ b/assets/src/ba_data/python/ba/_campaign.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to co-op campaigns.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_collision.py b/assets/src/ba_data/python/ba/_collision.py index 7d4261dd..1959c741 100644 --- a/assets/src/ba_data/python/ba/_collision.py +++ b/assets/src/ba_data/python/ba/_collision.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Collision related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index 7e686dd4..d04c2c69 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to co-op games.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 113a5886..3b4fc6b5 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to coop-mode sessions.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_dependency.py b/assets/src/ba_data/python/ba/_dependency.py index b8817ad1..6cb43e8b 100644 --- a/assets/src/ba_data/python/ba/_dependency.py +++ b/assets/src/ba_data/python/ba/_dependency.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to object/asset dependencies.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_dualteamsession.py b/assets/src/ba_data/python/ba/_dualteamsession.py index b53eb62f..427e7063 100644 --- a/assets/src/ba_data/python/ba/_dualteamsession.py +++ b/assets/src/ba_data/python/ba/_dualteamsession.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to teams sessions.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_enums.py b/assets/src/ba_data/python/ba/_enums.py index 19aeed47..7940bcfd 100644 --- a/assets/src/ba_data/python/ba/_enums.py +++ b/assets/src/ba_data/python/ba/_enums.py @@ -1,23 +1,4 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. """Enums generated by tools/update_python_enums_module in ba-internal.""" from enum import Enum diff --git a/assets/src/ba_data/python/ba/_error.py b/assets/src/ba_data/python/ba/_error.py index bf1db183..ea98f3f3 100644 --- a/assets/src/ba_data/python/ba/_error.py +++ b/assets/src/ba_data/python/ba/_error.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Error related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index e88457f4..73304cc5 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to free-for-all sessions.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_gameactivity.py b/assets/src/ba_data/python/ba/_gameactivity.py index ee954fbf..b4da7b35 100644 --- a/assets/src/ba_data/python/ba/_gameactivity.py +++ b/assets/src/ba_data/python/ba/_gameactivity.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides GameActivity class.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index cce6f6b3..65bd3ef8 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to game results.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_gameutils.py b/assets/src/ba_data/python/ba/_gameutils.py index 6679b685..cda5d083 100644 --- a/assets/src/ba_data/python/ba/_gameutils.py +++ b/assets/src/ba_data/python/ba/_gameutils.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Utility functionality pertaining to gameplay.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_general.py b/assets/src/ba_data/python/ba/_general.py index 276deb0d..45bdf886 100644 --- a/assets/src/ba_data/python/ba/_general.py +++ b/assets/src/ba_data/python/ba/_general.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Utility snippets applying to generic Python code.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index 0f45ad13..368d35ca 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Snippets of code for use by the internal C++ layer. History: originally I would dynamically compile/eval bits of Python text diff --git a/assets/src/ba_data/python/ba/_input.py b/assets/src/ba_data/python/ba/_input.py index c8267b6c..533ebe87 100644 --- a/assets/src/ba_data/python/ba/_input.py +++ b/assets/src/ba_data/python/ba/_input.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Input related functionality""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_keyboard.py b/assets/src/ba_data/python/ba/_keyboard.py index 04d627f0..258125f5 100644 --- a/assets/src/ba_data/python/ba/_keyboard.py +++ b/assets/src/ba_data/python/ba/_keyboard.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """On-screen Keyboard related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_lang.py b/assets/src/ba_data/python/ba/_lang.py index 7afacfbb..2e98ea26 100644 --- a/assets/src/ba_data/python/ba/_lang.py +++ b/assets/src/ba_data/python/ba/_lang.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Language related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_level.py b/assets/src/ba_data/python/ba/_level.py index 42afa83a..b9bd1675 100644 --- a/assets/src/ba_data/python/ba/_level.py +++ b/assets/src/ba_data/python/ba/_level.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to individual levels in a campaign.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_lobby.py b/assets/src/ba_data/python/ba/_lobby.py index f540478e..d96206c6 100644 --- a/assets/src/ba_data/python/ba/_lobby.py +++ b/assets/src/ba_data/python/ba/_lobby.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Implements lobby system for gathering before games, char select, etc.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py index 8e47f11e..1cacd8a4 100644 --- a/assets/src/ba_data/python/ba/_map.py +++ b/assets/src/ba_data/python/ba/_map.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Map related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_math.py b/assets/src/ba_data/python/ba/_math.py index 38232480..98834ee9 100644 --- a/assets/src/ba_data/python/ba/_math.py +++ b/assets/src/ba_data/python/ba/_math.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Math related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_messages.py b/assets/src/ba_data/python/ba/_messages.py index dba1bfd6..c57ea556 100644 --- a/assets/src/ba_data/python/ba/_messages.py +++ b/assets/src/ba_data/python/ba/_messages.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines some standard message objects for use with handlemessage() calls.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index 3e3a8055..a09e47a0 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to dynamic discoverability of classes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_multiteamsession.py b/assets/src/ba_data/python/ba/_multiteamsession.py index ecf962d7..7884faa7 100644 --- a/assets/src/ba_data/python/ba/_multiteamsession.py +++ b/assets/src/ba_data/python/ba/_multiteamsession.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to teams sessions.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py index 48bf5005..0e68de04 100644 --- a/assets/src/ba_data/python/ba/_music.py +++ b/assets/src/ba_data/python/ba/_music.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Music related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_netutils.py b/assets/src/ba_data/python/ba/_netutils.py index 72cf8dfe..5f5e0883 100644 --- a/assets/src/ba_data/python/ba/_netutils.py +++ b/assets/src/ba_data/python/ba/_netutils.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Networking related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_nodeactor.py b/assets/src/ba_data/python/ba/_nodeactor.py index 68f4dcf9..756a7fce 100644 --- a/assets/src/ba_data/python/ba/_nodeactor.py +++ b/assets/src/ba_data/python/ba/_nodeactor.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines NodeActor class.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_player.py b/assets/src/ba_data/python/ba/_player.py index 16a53cc9..e3fada9f 100644 --- a/assets/src/ba_data/python/ba/_player.py +++ b/assets/src/ba_data/python/ba/_player.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Player related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_playlist.py b/assets/src/ba_data/python/ba/_playlist.py index 29dc896f..58883a3e 100644 --- a/assets/src/ba_data/python/ba/_playlist.py +++ b/assets/src/ba_data/python/ba/_playlist.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Playlist related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_plugin.py b/assets/src/ba_data/python/ba/_plugin.py index 51b9b077..84658219 100644 --- a/assets/src/ba_data/python/ba/_plugin.py +++ b/assets/src/ba_data/python/ba/_plugin.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Plugin related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_powerup.py b/assets/src/ba_data/python/ba/_powerup.py index 950cc9ce..7dd895ce 100644 --- a/assets/src/ba_data/python/ba/_powerup.py +++ b/assets/src/ba_data/python/ba/_powerup.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Powerup related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_profile.py b/assets/src/ba_data/python/ba/_profile.py index c938c33c..a87e2024 100644 --- a/assets/src/ba_data/python/ba/_profile.py +++ b/assets/src/ba_data/python/ba/_profile.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to player profiles.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_score.py b/assets/src/ba_data/python/ba/_score.py index 79326f7c..be68a8e3 100644 --- a/assets/src/ba_data/python/ba/_score.py +++ b/assets/src/ba_data/python/ba/_score.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Score related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_servermode.py b/assets/src/ba_data/python/ba/_servermode.py index 237a4c7d..58798e9a 100644 --- a/assets/src/ba_data/python/ba/_servermode.py +++ b/assets/src/ba_data/python/ba/_servermode.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to running the game in server-mode.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 60c3deba..2a066f4f 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines base session class.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_settings.py b/assets/src/ba_data/python/ba/_settings.py index 260ad63f..1b3e4040 100644 --- a/assets/src/ba_data/python/ba/_settings.py +++ b/assets/src/ba_data/python/ba/_settings.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for user-controllable settings.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 5d94bbe6..089f7a5f 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to scores and statistics.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_store.py b/assets/src/ba_data/python/ba/_store.py index c68aa6f8..09252e47 100644 --- a/assets/src/ba_data/python/ba/_store.py +++ b/assets/src/ba_data/python/ba/_store.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Store related functionality for classic mode.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_team.py b/assets/src/ba_data/python/ba/_team.py index f04c3178..e4f74704 100644 --- a/assets/src/ba_data/python/ba/_team.py +++ b/assets/src/ba_data/python/ba/_team.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Team related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_teamgame.py b/assets/src/ba_data/python/ba/_teamgame.py index 0bd3736c..aa5563cf 100644 --- a/assets/src/ba_data/python/ba/_teamgame.py +++ b/assets/src/ba_data/python/ba/_teamgame.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to team games.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_tips.py b/assets/src/ba_data/python/ba/_tips.py index 8500c99f..a6c04c74 100644 --- a/assets/src/ba_data/python/ba/_tips.py +++ b/assets/src/ba_data/python/ba/_tips.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to game tips. These can be shown at opportune times such as between rounds.""" diff --git a/assets/src/ba_data/python/ba/_tournament.py b/assets/src/ba_data/python/ba/_tournament.py index 38b0768c..bb1cc1e8 100644 --- a/assets/src/ba_data/python/ba/_tournament.py +++ b/assets/src/ba_data/python/ba/_tournament.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to tournament play.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/_ui.py b/assets/src/ba_data/python/ba/_ui.py index f2a5537c..f6a16ccc 100644 --- a/assets/src/ba_data/python/ba/_ui.py +++ b/assets/src/ba_data/python/ba/_ui.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """User interface functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/deprecated.py b/assets/src/ba_data/python/ba/deprecated.py index fe800053..253c91f3 100644 --- a/assets/src/ba_data/python/ba/deprecated.py +++ b/assets/src/ba_data/python/ba/deprecated.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Deprecated functionality. Classes or functions can be relocated here when they are deprecated. diff --git a/assets/src/ba_data/python/ba/internal.py b/assets/src/ba_data/python/ba/internal.py index 4ac5d01b..dd354fb5 100644 --- a/assets/src/ba_data/python/ba/internal.py +++ b/assets/src/ba_data/python/ba/internal.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Exposed functionality not intended for full public use. Classes and functions contained here, while technically 'public', may change diff --git a/assets/src/ba_data/python/ba/macmusicapp.py b/assets/src/ba_data/python/ba/macmusicapp.py index 94a3b48f..68c6ebef 100644 --- a/assets/src/ba_data/python/ba/macmusicapp.py +++ b/assets/src/ba_data/python/ba/macmusicapp.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Music playback functionality using the Mac Music (formerly iTunes) app.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/modutils.py b/assets/src/ba_data/python/ba/modutils.py index a4ec3c0a..478d3df9 100644 --- a/assets/src/ba_data/python/ba/modutils.py +++ b/assets/src/ba_data/python/ba/modutils.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to modding.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/osmusic.py b/assets/src/ba_data/python/ba/osmusic.py index e188bebf..aaceba92 100644 --- a/assets/src/ba_data/python/ba/osmusic.py +++ b/assets/src/ba_data/python/ba/osmusic.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Music playback using OS functionality exposed through the C++ layer.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/ba/ui/__init__.py b/assets/src/ba_data/python/ba/ui/__init__.py index 4a1a4cb0..2907950c 100644 --- a/assets/src/ba_data/python/ba/ui/__init__.py +++ b/assets/src/ba_data/python/ba/ui/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provide top level UI related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/__init__.py b/assets/src/ba_data/python/bastd/__init__.py index e3ca3287..7a4ff44f 100644 --- a/assets/src/ba_data/python/bastd/__init__.py +++ b/assets/src/ba_data/python/bastd/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Ballistica standard library: games, UI, etc.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py index cf9f33ef..9e63747a 100644 --- a/assets/src/ba_data/python/bastd/activity/coopjoin.py +++ b/assets/src/ba_data/python/bastd/activity/coopjoin.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the co-op join screen.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 24b0fc73..15d1c9fe 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a score screen for coop games.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/activity/drawscore.py b/assets/src/ba_data/python/bastd/activity/drawscore.py index 9508325e..c12b82b7 100644 --- a/assets/src/ba_data/python/bastd/activity/drawscore.py +++ b/assets/src/ba_data/python/bastd/activity/drawscore.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the draw screen.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/activity/dualteamscore.py b/assets/src/ba_data/python/bastd/activity/dualteamscore.py index 6efa7ea5..88438bd3 100644 --- a/assets/src/ba_data/python/bastd/activity/dualteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/dualteamscore.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the end screen in dual-team mode.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py index d3147b32..10150580 100644 --- a/assets/src/ba_data/python/bastd/activity/freeforallvictory.py +++ b/assets/src/ba_data/python/bastd/activity/freeforallvictory.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the final screen in free-for-all games.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/activity/multiteamjoin.py b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py index 38fe9a7b..9c278590 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamjoin.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamjoin.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the join screen for multi-team sessions.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/activity/multiteamscore.py b/assets/src/ba_data/python/bastd/activity/multiteamscore.py index f3c885f0..ba87a616 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamscore.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamscore.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to teams mode score screen.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py index 352febc7..d8058806 100644 --- a/assets/src/ba_data/python/bastd/activity/multiteamvictory.py +++ b/assets/src/ba_data/python/bastd/activity/multiteamvictory.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the final screen in multi-teams sessions.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/background.py b/assets/src/ba_data/python/bastd/actor/background.py index 60f05f44..f9c486ba 100644 --- a/assets/src/ba_data/python/bastd/actor/background.py +++ b/assets/src/ba_data/python/bastd/actor/background.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/bomb.py b/assets/src/ba_data/python/bastd/actor/bomb.py index 4218666a..99d7dd12 100644 --- a/assets/src/ba_data/python/bastd/actor/bomb.py +++ b/assets/src/ba_data/python/bastd/actor/bomb.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Various classes for bombs, mines, tnt, etc.""" # FIXME diff --git a/assets/src/ba_data/python/bastd/actor/controlsguide.py b/assets/src/ba_data/python/bastd/actor/controlsguide.py index 7158bdc5..8f284a2d 100644 --- a/assets/src/ba_data/python/bastd/actor/controlsguide.py +++ b/assets/src/ba_data/python/bastd/actor/controlsguide.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actors related to controls guides.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index 78cfb666..f238b29c 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Implements a flag used for marking bases, capture-the-flag games, etc.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/image.py b/assets/src/ba_data/python/bastd/actor/image.py index 9ef97066..2db08a1e 100644 --- a/assets/src/ba_data/python/bastd/actor/image.py +++ b/assets/src/ba_data/python/bastd/actor/image.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/onscreencountdown.py b/assets/src/ba_data/python/bastd/actor/onscreencountdown.py index 6e767e54..a686cdf0 100644 --- a/assets/src/ba_data/python/bastd/actor/onscreencountdown.py +++ b/assets/src/ba_data/python/bastd/actor/onscreencountdown.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor Type(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/onscreentimer.py b/assets/src/ba_data/python/bastd/actor/onscreentimer.py index 560b13be..c58e87db 100644 --- a/assets/src/ba_data/python/bastd/actor/onscreentimer.py +++ b/assets/src/ba_data/python/bastd/actor/onscreentimer.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/playerspaz.py b/assets/src/ba_data/python/bastd/actor/playerspaz.py index fde1f1a4..b77aa8a4 100644 --- a/assets/src/ba_data/python/bastd/actor/playerspaz.py +++ b/assets/src/ba_data/python/bastd/actor/playerspaz.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to player-controlled Spazzes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/popuptext.py b/assets/src/ba_data/python/bastd/actor/popuptext.py index c3e23809..5ce8af9a 100644 --- a/assets/src/ba_data/python/bastd/actor/popuptext.py +++ b/assets/src/ba_data/python/bastd/actor/popuptext.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/powerupbox.py b/assets/src/ba_data/python/bastd/actor/powerupbox.py index 4717bdc3..aac89f07 100644 --- a/assets/src/ba_data/python/bastd/actor/powerupbox.py +++ b/assets/src/ba_data/python/bastd/actor/powerupbox.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/respawnicon.py b/assets/src/ba_data/python/bastd/actor/respawnicon.py index 6a7deb5e..504a8e66 100644 --- a/assets/src/ba_data/python/bastd/actor/respawnicon.py +++ b/assets/src/ba_data/python/bastd/actor/respawnicon.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Implements respawn icon actor.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/scoreboard.py b/assets/src/ba_data/python/bastd/actor/scoreboard.py index 31be59a7..7cce4253 100644 --- a/assets/src/ba_data/python/bastd/actor/scoreboard.py +++ b/assets/src/ba_data/python/bastd/actor/scoreboard.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines ScoreBoard Actor and related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/spawner.py b/assets/src/ba_data/python/bastd/actor/spawner.py index 02b89fde..e40d1866 100644 --- a/assets/src/ba_data/python/bastd/actor/spawner.py +++ b/assets/src/ba_data/python/bastd/actor/spawner.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines some lovely Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/spaz.py b/assets/src/ba_data/python/bastd/actor/spaz.py index 2ae01b4b..064b90b0 100644 --- a/assets/src/ba_data/python/bastd/actor/spaz.py +++ b/assets/src/ba_data/python/bastd/actor/spaz.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines the spaz actor.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/actor/spazappearance.py b/assets/src/ba_data/python/bastd/actor/spazappearance.py index 65e9dcdd..166b1f84 100644 --- a/assets/src/ba_data/python/bastd/actor/spazappearance.py +++ b/assets/src/ba_data/python/bastd/actor/spazappearance.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Appearance functionality for spazzes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/spazbot.py b/assets/src/ba_data/python/bastd/actor/spazbot.py index 5a507563..4e53ee67 100644 --- a/assets/src/ba_data/python/bastd/actor/spazbot.py +++ b/assets/src/ba_data/python/bastd/actor/spazbot.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Bot versions of Spaz.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/actor/spazfactory.py b/assets/src/ba_data/python/bastd/actor/spazfactory.py index 346723e2..7363ec43 100644 --- a/assets/src/ba_data/python/bastd/actor/spazfactory.py +++ b/assets/src/ba_data/python/bastd/actor/spazfactory.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a factory object from creating Spazzes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/text.py b/assets/src/ba_data/python/bastd/actor/text.py index 5864768f..96e3be58 100644 --- a/assets/src/ba_data/python/bastd/actor/text.py +++ b/assets/src/ba_data/python/bastd/actor/text.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/tipstext.py b/assets/src/ba_data/python/bastd/actor/tipstext.py index 33df2801..2cd5afd3 100644 --- a/assets/src/ba_data/python/bastd/actor/tipstext.py +++ b/assets/src/ba_data/python/bastd/actor/tipstext.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides tip related Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/actor/zoomtext.py b/assets/src/ba_data/python/bastd/actor/zoomtext.py index 192c6d18..4c0b2c9c 100644 --- a/assets/src/ba_data/python/bastd/actor/zoomtext.py +++ b/assets/src/ba_data/python/bastd/actor/zoomtext.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defined Actor(s).""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/appdelegate.py b/assets/src/ba_data/python/bastd/appdelegate.py index e650a2e0..9ae96c62 100644 --- a/assets/src/ba_data/python/bastd/appdelegate.py +++ b/assets/src/ba_data/python/bastd/appdelegate.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provide our delegate for high level app functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/game/assault.py b/assets/src/ba_data/python/bastd/game/assault.py index 17d6fea2..44dc8ca0 100644 --- a/assets/src/ba_data/python/bastd/game/assault.py +++ b/assets/src/ba_data/python/bastd/game/assault.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines assault minigame.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/capturetheflag.py b/assets/src/ba_data/python/bastd/game/capturetheflag.py index 999277cf..638d2d3b 100644 --- a/assets/src/ba_data/python/bastd/game/capturetheflag.py +++ b/assets/src/ba_data/python/bastd/game/capturetheflag.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines a capture-the-flag game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/chosenone.py b/assets/src/ba_data/python/bastd/game/chosenone.py index e0ece71d..465dec97 100644 --- a/assets/src/ba_data/python/bastd/game/chosenone.py +++ b/assets/src/ba_data/python/bastd/game/chosenone.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides the chosen-one mini-game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/conquest.py b/assets/src/ba_data/python/bastd/game/conquest.py index 06ac4d21..b2404b8e 100644 --- a/assets/src/ba_data/python/bastd/game/conquest.py +++ b/assets/src/ba_data/python/bastd/game/conquest.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides the Conquest game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/deathmatch.py b/assets/src/ba_data/python/bastd/game/deathmatch.py index 4a8c95c4..f91c7aff 100644 --- a/assets/src/ba_data/python/bastd/game/deathmatch.py +++ b/assets/src/ba_data/python/bastd/game/deathmatch.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """DeathMatch game and support classes.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/easteregghunt.py b/assets/src/ba_data/python/bastd/game/easteregghunt.py index 13fe9177..2c5b9b02 100644 --- a/assets/src/ba_data/python/bastd/game/easteregghunt.py +++ b/assets/src/ba_data/python/bastd/game/easteregghunt.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides an easter egg hunt game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/elimination.py b/assets/src/ba_data/python/bastd/game/elimination.py index 63c579ed..061ff0b4 100644 --- a/assets/src/ba_data/python/bastd/game/elimination.py +++ b/assets/src/ba_data/python/bastd/game/elimination.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Elimination mini-game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/football.py b/assets/src/ba_data/python/bastd/game/football.py index 1a0bb939..3531dfc5 100644 --- a/assets/src/ba_data/python/bastd/game/football.py +++ b/assets/src/ba_data/python/bastd/game/football.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Implements football games (both co-op and teams varieties).""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/hockey.py b/assets/src/ba_data/python/bastd/game/hockey.py index bf09dff9..3964ad7e 100644 --- a/assets/src/ba_data/python/bastd/game/hockey.py +++ b/assets/src/ba_data/python/bastd/game/hockey.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Hockey game and support classes.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/keepaway.py b/assets/src/ba_data/python/bastd/game/keepaway.py index 5faaf19a..7810b2e6 100644 --- a/assets/src/ba_data/python/bastd/game/keepaway.py +++ b/assets/src/ba_data/python/bastd/game/keepaway.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines a keep-away game type.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/kingofthehill.py b/assets/src/ba_data/python/bastd/game/kingofthehill.py index 1e8b3610..66726261 100644 --- a/assets/src/ba_data/python/bastd/game/kingofthehill.py +++ b/assets/src/ba_data/python/bastd/game/kingofthehill.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines the King of the Hill game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/meteorshower.py b/assets/src/ba_data/python/bastd/game/meteorshower.py index 9e41439c..9be79902 100644 --- a/assets/src/ba_data/python/bastd/game/meteorshower.py +++ b/assets/src/ba_data/python/bastd/game/meteorshower.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines a bomb-dodging mini-game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/ninjafight.py b/assets/src/ba_data/python/bastd/game/ninjafight.py index be60ecc2..37ba0215 100644 --- a/assets/src/ba_data/python/bastd/game/ninjafight.py +++ b/assets/src/ba_data/python/bastd/game/ninjafight.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides Ninja Fight mini-game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/onslaught.py b/assets/src/ba_data/python/bastd/game/onslaught.py index 72484566..9b8efe85 100644 --- a/assets/src/ba_data/python/bastd/game/onslaught.py +++ b/assets/src/ba_data/python/bastd/game/onslaught.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides Onslaught Co-op game.""" # Yes this is a long one.. diff --git a/assets/src/ba_data/python/bastd/game/race.py b/assets/src/ba_data/python/bastd/game/race.py index f65626bf..0a058ac4 100644 --- a/assets/src/ba_data/python/bastd/game/race.py +++ b/assets/src/ba_data/python/bastd/game/race.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines Race mini-game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/runaround.py b/assets/src/ba_data/python/bastd/game/runaround.py index 0813b076..711ee463 100644 --- a/assets/src/ba_data/python/bastd/game/runaround.py +++ b/assets/src/ba_data/python/bastd/game/runaround.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines the runaround co-op game.""" # We wear the cone of shame. diff --git a/assets/src/ba_data/python/bastd/game/targetpractice.py b/assets/src/ba_data/python/bastd/game/targetpractice.py index 2945551d..91d0e131 100644 --- a/assets/src/ba_data/python/bastd/game/targetpractice.py +++ b/assets/src/ba_data/python/bastd/game/targetpractice.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Implements Target Practice game.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/game/thelaststand.py b/assets/src/ba_data/python/bastd/game/thelaststand.py index 17e6ba03..5a24cc4d 100644 --- a/assets/src/ba_data/python/bastd/game/thelaststand.py +++ b/assets/src/ba_data/python/bastd/game/thelaststand.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines the last stand minigame.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/gameutils.py b/assets/src/ba_data/python/bastd/gameutils.py index de34b2bd..280e5742 100644 --- a/assets/src/ba_data/python/bastd/gameutils.py +++ b/assets/src/ba_data/python/bastd/gameutils.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Various utilities useful for gameplay.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py b/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py index 12d49560..a7e197d2 100644 --- a/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py +++ b/assets/src/ba_data/python/bastd/keyboard/englishkeyboard.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines a default keyboards.""" # ba_meta require api 6 diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index e669875b..d00ccdce 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Session and Activity for displaying the main menu bg.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/mapdata/big_g.py b/assets/src/ba_data/python/bastd/mapdata/big_g.py index dc1bc60d..207e93e0 100644 --- a/assets/src/ba_data/python/bastd/mapdata/big_g.py +++ b/assets/src/ba_data/python/bastd/mapdata/big_g.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "big_g.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/bridgit.py b/assets/src/ba_data/python/bastd/mapdata/bridgit.py index 9988ffd8..70cb3c78 100644 --- a/assets/src/ba_data/python/bastd/mapdata/bridgit.py +++ b/assets/src/ba_data/python/bastd/mapdata/bridgit.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "bridgit.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/courtyard.py b/assets/src/ba_data/python/bastd/mapdata/courtyard.py index 710e81c1..634cdb21 100644 --- a/assets/src/ba_data/python/bastd/mapdata/courtyard.py +++ b/assets/src/ba_data/python/bastd/mapdata/courtyard.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "courtyard.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/crag_castle.py b/assets/src/ba_data/python/bastd/mapdata/crag_castle.py index 9b7676a5..ca5d794d 100644 --- a/assets/src/ba_data/python/bastd/mapdata/crag_castle.py +++ b/assets/src/ba_data/python/bastd/mapdata/crag_castle.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "crag_castle.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/doom_shroom.py b/assets/src/ba_data/python/bastd/mapdata/doom_shroom.py index d62cc0ad..634a7308 100644 --- a/assets/src/ba_data/python/bastd/mapdata/doom_shroom.py +++ b/assets/src/ba_data/python/bastd/mapdata/doom_shroom.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "doom_shroom.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/football_stadium.py b/assets/src/ba_data/python/bastd/mapdata/football_stadium.py index 18fcd14f..b650238e 100644 --- a/assets/src/ba_data/python/bastd/mapdata/football_stadium.py +++ b/assets/src/ba_data/python/bastd/mapdata/football_stadium.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "football_stadium.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/happy_thoughts.py b/assets/src/ba_data/python/bastd/mapdata/happy_thoughts.py index 9a65ac43..c3e03ab3 100644 --- a/assets/src/ba_data/python/bastd/mapdata/happy_thoughts.py +++ b/assets/src/ba_data/python/bastd/mapdata/happy_thoughts.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "happy_thoughts.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/hockey_stadium.py b/assets/src/ba_data/python/bastd/mapdata/hockey_stadium.py index c049a601..722797f4 100644 --- a/assets/src/ba_data/python/bastd/mapdata/hockey_stadium.py +++ b/assets/src/ba_data/python/bastd/mapdata/hockey_stadium.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "hockey_stadium.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/lake_frigid.py b/assets/src/ba_data/python/bastd/mapdata/lake_frigid.py index 6b5356f9..a56b174f 100644 --- a/assets/src/ba_data/python/bastd/mapdata/lake_frigid.py +++ b/assets/src/ba_data/python/bastd/mapdata/lake_frigid.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "lake_frigid.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/monkey_face.py b/assets/src/ba_data/python/bastd/mapdata/monkey_face.py index a87abeb2..b0415091 100644 --- a/assets/src/ba_data/python/bastd/mapdata/monkey_face.py +++ b/assets/src/ba_data/python/bastd/mapdata/monkey_face.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "monkey_face.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/rampage.py b/assets/src/ba_data/python/bastd/mapdata/rampage.py index 101933ac..1daff2d7 100644 --- a/assets/src/ba_data/python/bastd/mapdata/rampage.py +++ b/assets/src/ba_data/python/bastd/mapdata/rampage.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "rampage.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/roundabout.py b/assets/src/ba_data/python/bastd/mapdata/roundabout.py index d41b9de6..e9f7bdbd 100644 --- a/assets/src/ba_data/python/bastd/mapdata/roundabout.py +++ b/assets/src/ba_data/python/bastd/mapdata/roundabout.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "roundabout.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/step_right_up.py b/assets/src/ba_data/python/bastd/mapdata/step_right_up.py index f30c3dd8..5d709bdd 100644 --- a/assets/src/ba_data/python/bastd/mapdata/step_right_up.py +++ b/assets/src/ba_data/python/bastd/mapdata/step_right_up.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "step_right_up.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/the_pad.py b/assets/src/ba_data/python/bastd/mapdata/the_pad.py index 3270d83a..7afe6298 100644 --- a/assets/src/ba_data/python/bastd/mapdata/the_pad.py +++ b/assets/src/ba_data/python/bastd/mapdata/the_pad.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "the_pad.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/tip_top.py b/assets/src/ba_data/python/bastd/mapdata/tip_top.py index 75e33267..7e8a17d6 100644 --- a/assets/src/ba_data/python/bastd/mapdata/tip_top.py +++ b/assets/src/ba_data/python/bastd/mapdata/tip_top.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "tip_top.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/tower_d.py b/assets/src/ba_data/python/bastd/mapdata/tower_d.py index 54043180..bc7b4350 100644 --- a/assets/src/ba_data/python/bastd/mapdata/tower_d.py +++ b/assets/src/ba_data/python/bastd/mapdata/tower_d.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "tower_d.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/mapdata/zig_zag.py b/assets/src/ba_data/python/bastd/mapdata/zig_zag.py index e425d549..701d9f82 100644 --- a/assets/src/ba_data/python/bastd/mapdata/zig_zag.py +++ b/assets/src/ba_data/python/bastd/mapdata/zig_zag.py @@ -1,23 +1,6 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- + # This file was automatically generated from "zig_zag.ma" # pylint: disable=all points = {} diff --git a/assets/src/ba_data/python/bastd/maps.py b/assets/src/ba_data/python/bastd/maps.py index 15b9290b..03f41255 100644 --- a/assets/src/ba_data/python/bastd/maps.py +++ b/assets/src/ba_data/python/bastd/maps.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Standard maps.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/stdmap.py b/assets/src/ba_data/python/bastd/stdmap.py index ed7bd335..237ea4a5 100644 --- a/assets/src/ba_data/python/bastd/stdmap.py +++ b/assets/src/ba_data/python/bastd/stdmap.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines standard map type.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/tutorial.py b/assets/src/ba_data/python/bastd/tutorial.py index bdd10671..39bad74d 100644 --- a/assets/src/ba_data/python/bastd/tutorial.py +++ b/assets/src/ba_data/python/bastd/tutorial.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Wrangles the game tutorial sequence.""" # Not too concerned with keeping this old module pretty; diff --git a/assets/src/ba_data/python/bastd/ui/__init__.py b/assets/src/ba_data/python/bastd/ui/__init__.py index 00093b29..15b7717f 100644 --- a/assets/src/ba_data/python/bastd/ui/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """ Provide top level UI related functionality. """ diff --git a/assets/src/ba_data/python/bastd/ui/account/__init__.py b/assets/src/ba_data/python/bastd/ui/account/__init__.py index cd1cd7f8..9b1c446b 100644 --- a/assets/src/ba_data/python/bastd/ui/account/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/account/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to accounts.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/account/link.py b/assets/src/ba_data/python/bastd/ui/account/link.py index 261b358b..f82985b2 100644 --- a/assets/src/ba_data/python/bastd/ui/account/link.py +++ b/assets/src/ba_data/python/bastd/ui/account/link.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for linking accounts.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/account/settings.py b/assets/src/ba_data/python/bastd/ui/account/settings.py index bf970745..30599418 100644 --- a/assets/src/ba_data/python/bastd/ui/account/settings.py +++ b/assets/src/ba_data/python/bastd/ui/account/settings.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for account functionality.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/ui/account/unlink.py b/assets/src/ba_data/python/bastd/ui/account/unlink.py index 83ed0b47..ef3b0114 100644 --- a/assets/src/ba_data/python/bastd/ui/account/unlink.py +++ b/assets/src/ba_data/python/bastd/ui/account/unlink.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for unlinking accounts.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/account/viewer.py b/assets/src/ba_data/python/bastd/ui/account/viewer.py index 6560d908..3b72aef0 100644 --- a/assets/src/ba_data/python/bastd/ui/account/viewer.py +++ b/assets/src/ba_data/python/bastd/ui/account/viewer.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a popup for displaying info about any account.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/achievements.py b/assets/src/ba_data/python/bastd/ui/achievements.py index 6c4685a8..66cb5b0b 100644 --- a/assets/src/ba_data/python/bastd/ui/achievements.py +++ b/assets/src/ba_data/python/bastd/ui/achievements.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a popup window to view achievements.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/appinvite.py b/assets/src/ba_data/python/bastd/ui/appinvite.py index 3ce9270d..c058f762 100644 --- a/assets/src/ba_data/python/bastd/ui/appinvite.py +++ b/assets/src/ba_data/python/bastd/ui/appinvite.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to inviting people to try the game.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/characterpicker.py b/assets/src/ba_data/python/bastd/ui/characterpicker.py index c18f4806..8b0dc502 100644 --- a/assets/src/ba_data/python/bastd/ui/characterpicker.py +++ b/assets/src/ba_data/python/bastd/ui/characterpicker.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a picker for characters.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/colorpicker.py b/assets/src/ba_data/python/bastd/ui/colorpicker.py index 336be37e..aac01dbe 100644 --- a/assets/src/ba_data/python/bastd/ui/colorpicker.py +++ b/assets/src/ba_data/python/bastd/ui/colorpicker.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides popup windows for choosing colors.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/config.py b/assets/src/ba_data/python/bastd/ui/config.py index 8426de77..0c11ff4e 100644 --- a/assets/src/ba_data/python/bastd/ui/config.py +++ b/assets/src/ba_data/python/bastd/ui/config.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for editing config values and applying them to the game.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/configerror.py b/assets/src/ba_data/python/bastd/ui/configerror.py index 721dac05..b94c5800 100644 --- a/assets/src/ba_data/python/bastd/ui/configerror.py +++ b/assets/src/ba_data/python/bastd/ui/configerror.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI for dealing with broken config files.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/confirm.py b/assets/src/ba_data/python/bastd/ui/confirm.py index 803b5231..fc65aaf6 100644 --- a/assets/src/ba_data/python/bastd/ui/confirm.py +++ b/assets/src/ba_data/python/bastd/ui/confirm.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides ConfirmWindow base class and commonly used derivatives.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/continues.py b/assets/src/ba_data/python/bastd/ui/continues.py index 68d78047..d5644a1a 100644 --- a/assets/src/ba_data/python/bastd/ui/continues.py +++ b/assets/src/ba_data/python/bastd/ui/continues.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a popup window to continue a game.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/coop/browser.py b/assets/src/ba_data/python/bastd/ui/coop/browser.py index ef313d00..0eaf88eb 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/browser.py +++ b/assets/src/ba_data/python/bastd/ui/coop/browser.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI for browsing available co-op levels/games/etc.""" # FIXME: Break this up. # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py index 3f7683cb..304d681e 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py +++ b/assets/src/ba_data/python/bastd/ui/coop/gamebutton.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines button for co-op games.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/coop/level.py b/assets/src/ba_data/python/bastd/ui/coop/level.py index f5b656af..c2444696 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/level.py +++ b/assets/src/ba_data/python/bastd/ui/coop/level.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Bits of utility functionality related to co-op levels.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/creditslist.py b/assets/src/ba_data/python/bastd/ui/creditslist.py index 84ffa9ea..b5caebc4 100644 --- a/assets/src/ba_data/python/bastd/ui/creditslist.py +++ b/assets/src/ba_data/python/bastd/ui/creditslist.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window to display game credits.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/debug.py b/assets/src/ba_data/python/bastd/ui/debug.py index c523047b..63f38784 100644 --- a/assets/src/ba_data/python/bastd/ui/debug.py +++ b/assets/src/ba_data/python/bastd/ui/debug.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UIs for debugging purposes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/feedback.py b/assets/src/ba_data/python/bastd/ui/feedback.py index 0ecfe985..4b688147 100644 --- a/assets/src/ba_data/python/bastd/ui/feedback.py +++ b/assets/src/ba_data/python/bastd/ui/feedback.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to users rating the game.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/fileselector.py b/assets/src/ba_data/python/bastd/ui/fileselector.py index 00fb2fba..da6e2b2f 100644 --- a/assets/src/ba_data/python/bastd/ui/fileselector.py +++ b/assets/src/ba_data/python/bastd/ui/fileselector.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for selecting files.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/gather.py b/assets/src/ba_data/python/bastd/ui/gather.py index e98d6e96..bb67b9a4 100644 --- a/assets/src/ba_data/python/bastd/ui/gather.py +++ b/assets/src/ba_data/python/bastd/ui/gather.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for inviting/joining friends.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/ui/getcurrency.py b/assets/src/ba_data/python/bastd/ui/getcurrency.py index 78f28a62..d879a8e5 100644 --- a/assets/src/ba_data/python/bastd/ui/getcurrency.py +++ b/assets/src/ba_data/python/bastd/ui/getcurrency.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for purchasing/acquiring currency.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/getremote.py b/assets/src/ba_data/python/bastd/ui/getremote.py index 3dcae3f3..4f8f401c 100644 --- a/assets/src/ba_data/python/bastd/ui/getremote.py +++ b/assets/src/ba_data/python/bastd/ui/getremote.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a popup telling the user about the BSRemote app.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/helpui.py b/assets/src/ba_data/python/bastd/ui/helpui.py index 259977d4..82b95d62 100644 --- a/assets/src/ba_data/python/bastd/ui/helpui.py +++ b/assets/src/ba_data/python/bastd/ui/helpui.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides help related ui.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/iconpicker.py b/assets/src/ba_data/python/bastd/ui/iconpicker.py index 2633aba1..fe6dfcc0 100644 --- a/assets/src/ba_data/python/bastd/ui/iconpicker.py +++ b/assets/src/ba_data/python/bastd/ui/iconpicker.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a picker for icons.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/kiosk.py b/assets/src/ba_data/python/bastd/ui/kiosk.py index 949ebd6f..d5db0f97 100644 --- a/assets/src/ba_data/python/bastd/ui/kiosk.py +++ b/assets/src/ba_data/python/bastd/ui/kiosk.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for running the game in kiosk mode.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/league/__init__.py b/assets/src/ba_data/python/bastd/ui/league/__init__.py index fcb92620..bb572664 100644 --- a/assets/src/ba_data/python/bastd/ui/league/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/league/__init__.py @@ -1,21 +1,3 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """League related UI functionality.""" diff --git a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py index 9d48c8eb..7f0e5cfd 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankbutton.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankbutton.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a button showing league rank.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py index 0c83c884..a998c71c 100644 --- a/assets/src/ba_data/python/bastd/ui/league/rankwindow.py +++ b/assets/src/ba_data/python/bastd/ui/league/rankwindow.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI related to league rank.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/mainmenu.py b/assets/src/ba_data/python/bastd/ui/mainmenu.py index 7e1459e6..3741acca 100644 --- a/assets/src/ba_data/python/bastd/ui/mainmenu.py +++ b/assets/src/ba_data/python/bastd/ui/mainmenu.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Implements the main menu window.""" # pylint: disable=too-many-lines diff --git a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py index 17a7899a..1df4aff6 100644 --- a/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py +++ b/assets/src/ba_data/python/bastd/ui/onscreenkeyboard.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides the built-in on screen keyboard UI.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/party.py b/assets/src/ba_data/python/bastd/ui/party.py index 46dd70eb..28330095 100644 --- a/assets/src/ba_data/python/bastd/ui/party.py +++ b/assets/src/ba_data/python/bastd/ui/party.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides party related UI.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/partyqueue.py b/assets/src/ba_data/python/bastd/ui/partyqueue.py index 3d5c2df7..fd8df48b 100644 --- a/assets/src/ba_data/python/bastd/ui/partyqueue.py +++ b/assets/src/ba_data/python/bastd/ui/partyqueue.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI related to waiting in line for a party.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/play.py b/assets/src/ba_data/python/bastd/ui/play.py index 82eabd59..deb9b8bf 100644 --- a/assets/src/ba_data/python/bastd/ui/play.py +++ b/assets/src/ba_data/python/bastd/ui/play.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides the top level play window.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/__init__.py b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py index be0fa4c7..483008c9 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Playlist ui functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py index e2902826..46cb3d70 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/addgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/addgame.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window for selecting a game type to add to a playlist.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index d9600955..af37ace9 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window for browsing and launching game playlists.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py index b71a7575..f743e412 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for viewing/creating/editing playlists.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/edit.py b/assets/src/ba_data/python/bastd/ui/playlist/edit.py index 35739c28..cb5388a2 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/edit.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/edit.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window for editing individual game playlists.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py index ec5ddeec..5c37c539 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editcontroller.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines a controller for wrangling playlist edit UIs.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py index 1241c9d5..1c0758c2 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/editgame.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/editgame.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for editing a game in a playlist.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py index 1bcc15d1..d7b5201c 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/mapselect.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for selecting maps in playlists.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playlist/share.py b/assets/src/ba_data/python/bastd/ui/playlist/share.py index 4c2c27e1..0cd1ea4b 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/share.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/share.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for importing shared playlists.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/playoptions.py b/assets/src/ba_data/python/bastd/ui/playoptions.py index 958c90be..e3341496 100644 --- a/assets/src/ba_data/python/bastd/ui/playoptions.py +++ b/assets/src/ba_data/python/bastd/ui/playoptions.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window for configuring play options.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/popup.py b/assets/src/ba_data/python/bastd/ui/popup.py index 517e3a05..500c3796 100644 --- a/assets/src/ba_data/python/bastd/ui/popup.py +++ b/assets/src/ba_data/python/bastd/ui/popup.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Popup window/menu related functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py index 3a471cb4..ca67d641 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to browsing player profiles.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/profile/edit.py b/assets/src/ba_data/python/bastd/ui/profile/edit.py index 36f62bb8..c63cd165 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/edit.py +++ b/assets/src/ba_data/python/bastd/ui/profile/edit.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI to edit a player profile.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py index c46133c9..c28777fd 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/upgrade.py +++ b/assets/src/ba_data/python/bastd/ui/profile/upgrade.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI for player profile upgrades.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/promocode.py b/assets/src/ba_data/python/bastd/ui/promocode.py index 7d0d9a93..dfd1fddd 100644 --- a/assets/src/ba_data/python/bastd/ui/promocode.py +++ b/assets/src/ba_data/python/bastd/ui/promocode.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for entering promo codes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/purchase.py b/assets/src/ba_data/python/bastd/ui/purchase.py index 9fdd6279..3450e780 100644 --- a/assets/src/ba_data/python/bastd/ui/purchase.py +++ b/assets/src/ba_data/python/bastd/ui/purchase.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI related to purchasing items.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/qrcode.py b/assets/src/ba_data/python/bastd/ui/qrcode.py index 42ac8a7d..16efd5db 100644 --- a/assets/src/ba_data/python/bastd/ui/qrcode.py +++ b/assets/src/ba_data/python/bastd/ui/qrcode.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides functionality for displaying QR codes.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/radiogroup.py b/assets/src/ba_data/python/bastd/ui/radiogroup.py index 38eb0fb7..20d3f9cc 100644 --- a/assets/src/ba_data/python/bastd/ui/radiogroup.py +++ b/assets/src/ba_data/python/bastd/ui/radiogroup.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for creating radio groups of buttons.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/report.py b/assets/src/ba_data/python/bastd/ui/report.py index 88600e79..1c761157 100644 --- a/assets/src/ba_data/python/bastd/ui/report.py +++ b/assets/src/ba_data/python/bastd/ui/report.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI related to reporting bad behavior/etc.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py index 2ebe9728..2013f5c4 100644 --- a/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py +++ b/assets/src/ba_data/python/bastd/ui/resourcetypeinfo.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window which shows info about resource types.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/serverdialog.py b/assets/src/ba_data/python/bastd/ui/serverdialog.py index 4a803f3f..17565036 100644 --- a/assets/src/ba_data/python/bastd/ui/serverdialog.py +++ b/assets/src/ba_data/python/bastd/ui/serverdialog.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Dialog window controlled by the master server.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/advanced.py b/assets/src/ba_data/python/bastd/ui/settings/advanced.py index 538f5f47..4294d56c 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/advanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/advanced.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for advanced settings.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py index 0488ce79..32c3e3e8 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/allsettings.py +++ b/assets/src/ba_data/python/bastd/ui/settings/allsettings.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI for top level settings categories.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/audio.py b/assets/src/ba_data/python/bastd/ui/settings/audio.py index 2ef25547..b84f0fd8 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/audio.py +++ b/assets/src/ba_data/python/bastd/ui/settings/audio.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides audio settings UI.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/controls.py b/assets/src/ba_data/python/bastd/ui/settings/controls.py index fab4c9bc..fd81b5e1 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/controls.py +++ b/assets/src/ba_data/python/bastd/ui/settings/controls.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a top level control settings window.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py index fdfe2514..4c345094 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepad.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepad.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Settings UI functionality related to gamepads.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py index c9893141..07c1074d 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadadvanced.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to advanced gamepad configuring.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py index 72c7864e..71b867c8 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py +++ b/assets/src/ba_data/python/bastd/ui/settings/gamepadselect.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Settings UI related to gamepad functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/graphics.py b/assets/src/ba_data/python/bastd/ui/settings/graphics.py index addcce11..df3e89ca 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/graphics.py +++ b/assets/src/ba_data/python/bastd/ui/settings/graphics.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for graphics settings.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py index c68e5e3c..7482381c 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/keyboard.py +++ b/assets/src/ba_data/python/bastd/ui/settings/keyboard.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Keyboard settings related UI functionality.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/nettesting.py b/assets/src/ba_data/python/bastd/ui/settings/nettesting.py index d7ec72b0..e8b645c5 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/nettesting.py +++ b/assets/src/ba_data/python/bastd/ui/settings/nettesting.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides ui for network related testing.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/plugins.py b/assets/src/ba_data/python/bastd/ui/settings/plugins.py index 7b1993b1..457eded9 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/plugins.py +++ b/assets/src/ba_data/python/bastd/ui/settings/plugins.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Plugin settings UI.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py index f9898611..6d588da0 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/ps3controller.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Settings UI related to PS3 controllers.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py index 81569f2b..dd81689f 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py +++ b/assets/src/ba_data/python/bastd/ui/settings/remoteapp.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Settings UI functionality related to the remote app.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/testing.py b/assets/src/ba_data/python/bastd/ui/settings/testing.py index b413df62..a96dd0d0 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/testing.py +++ b/assets/src/ba_data/python/bastd/ui/settings/testing.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for test settings.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py index 6e6d75eb..ddf43464 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py +++ b/assets/src/ba_data/python/bastd/ui/settings/touchscreen.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI settings functionality related to touchscreens.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/vrtesting.py b/assets/src/ba_data/python/bastd/ui/settings/vrtesting.py index b06afe7e..7065d463 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/vrtesting.py +++ b/assets/src/ba_data/python/bastd/ui/settings/vrtesting.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for testing vr settings.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/wiimote.py b/assets/src/ba_data/python/bastd/ui/settings/wiimote.py index 4daf8440..89dbadc7 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/wiimote.py +++ b/assets/src/ba_data/python/bastd/ui/settings/wiimote.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Settings UI functionality related to wiimote support.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py index a91037ca..0e145a70 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py +++ b/assets/src/ba_data/python/bastd/ui/settings/xbox360controller.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to using xbox360 controllers.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py index 2e1c5d97..3fcb5d89 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for browsing soundtracks.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py index c6ce84b7..238d3716 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/edit.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for editing a soundtrack.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py index 839a0753..53355ab1 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/entrytypeselect.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI for selecting soundtrack entry types.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py b/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py index e26f274e..1f149b02 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/macmusicapp.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to using the macOS Music app for soundtracks.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/specialoffer.py b/assets/src/ba_data/python/bastd/ui/specialoffer.py index 6c7b2618..35273224 100644 --- a/assets/src/ba_data/python/bastd/ui/specialoffer.py +++ b/assets/src/ba_data/python/bastd/ui/specialoffer.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI for presenting sales/etc.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/store/browser.py b/assets/src/ba_data/python/bastd/ui/store/browser.py index 1e6f110f..e7fe57f1 100644 --- a/assets/src/ba_data/python/bastd/ui/store/browser.py +++ b/assets/src/ba_data/python/bastd/ui/store/browser.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI for browsing the store.""" # pylint: disable=too-many-lines from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/store/button.py b/assets/src/ba_data/python/bastd/ui/store/button.py index 4cacaabe..5aec0506 100644 --- a/assets/src/ba_data/python/bastd/ui/store/button.py +++ b/assets/src/ba_data/python/bastd/ui/store/button.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for a button leading to the store.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/store/item.py b/assets/src/ba_data/python/bastd/ui/store/item.py index 1ff38c67..841ae1f2 100644 --- a/assets/src/ba_data/python/bastd/ui/store/item.py +++ b/assets/src/ba_data/python/bastd/ui/store/item.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to UI items.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/tabs.py b/assets/src/ba_data/python/bastd/ui/tabs.py index c5894891..c37fbdba 100644 --- a/assets/src/ba_data/python/bastd/ui/tabs.py +++ b/assets/src/ba_data/python/bastd/ui/tabs.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for creating tab style buttons.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py index 8ebea612..eecfc951 100644 --- a/assets/src/ba_data/python/bastd/ui/teamnamescolors.py +++ b/assets/src/ba_data/python/bastd/ui/teamnamescolors.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a window to customize team names and colors.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/telnet.py b/assets/src/ba_data/python/bastd/ui/telnet.py index 869d60fb..8ea63e4e 100644 --- a/assets/src/ba_data/python/bastd/ui/telnet.py +++ b/assets/src/ba_data/python/bastd/ui/telnet.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality for telnet access.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/tournamententry.py b/assets/src/ba_data/python/bastd/ui/tournamententry.py index 7238a753..62a4080f 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamententry.py +++ b/assets/src/ba_data/python/bastd/ui/tournamententry.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Defines a popup window for entering tournaments.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/tournamentscores.py b/assets/src/ba_data/python/bastd/ui/tournamentscores.py index d5e65142..e162b47b 100644 --- a/assets/src/ba_data/python/bastd/ui/tournamentscores.py +++ b/assets/src/ba_data/python/bastd/ui/tournamentscores.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a popup for viewing tournament scores.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/trophies.py b/assets/src/ba_data/python/bastd/ui/trophies.py index aa7d52ac..647912e2 100644 --- a/assets/src/ba_data/python/bastd/ui/trophies.py +++ b/assets/src/ba_data/python/bastd/ui/trophies.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a popup window for viewing trophies.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/url.py b/assets/src/ba_data/python/bastd/ui/url.py index 413b257a..00f3b30a 100644 --- a/assets/src/ba_data/python/bastd/ui/url.py +++ b/assets/src/ba_data/python/bastd/ui/url.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """UI functionality related to URLs.""" from __future__ import annotations diff --git a/assets/src/ba_data/python/bastd/ui/watch.py b/assets/src/ba_data/python/bastd/ui/watch.py index d2ef27da..f7c40c9e 100644 --- a/assets/src/ba_data/python/bastd/ui/watch.py +++ b/assets/src/ba_data/python/bastd/ui/watch.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides UI functionality for watching replays.""" from __future__ import annotations diff --git a/assets/src/server/ballisticacore_server.py b/assets/src/server/ballisticacore_server.py index b2fd25c1..89247ad7 100755 --- a/assets/src/server/ballisticacore_server.py +++ b/assets/src/server/ballisticacore_server.py @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """BallisticaCore server manager.""" from __future__ import annotations diff --git a/docs/ba_module.md b/docs/ba_module.md index 2242f408..5ad4eb1a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-08-31 for Ballistica version 1.5.25 build 20175

    +

    last updated on 2020-09-11 for Ballistica version 1.5.25 build 20179

    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!


    diff --git a/tests/test_ba/test_assetmanager.py b/tests/test_ba/test_assetmanager.py index 290291a1..06af5307 100644 --- a/tests/test_ba/test_assetmanager.py +++ b/tests/test_ba/test_assetmanager.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Testing asset manager functionality.""" from __future__ import annotations diff --git a/tests/test_efro/test_dataclasses.py b/tests/test_efro/test_dataclasses.py index 470bf01b..ecd71393 100644 --- a/tests/test_efro/test_dataclasses.py +++ b/tests/test_efro/test_dataclasses.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Testing dataclasses functionality.""" from __future__ import annotations diff --git a/tests/test_efro/test_entity.py b/tests/test_efro/test_entity.py index 8af4cf0e..e3e9ae12 100644 --- a/tests/test_efro/test_entity.py +++ b/tests/test_efro/test_entity.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Testing entity functionality.""" from __future__ import annotations diff --git a/tools/bacloud b/tools/bacloud index 2765688f..34e2c223 100755 --- a/tools/bacloud +++ b/tools/bacloud @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """A tool for interacting with ballistica's cloud services. This facilitates workflows such as creating asset-packages, etc. """ diff --git a/tools/bacommon/__init__.py b/tools/bacommon/__init__.py index 3a138b81..946ec27f 100644 --- a/tools/bacommon/__init__.py +++ b/tools/bacommon/__init__.py @@ -1,21 +1,3 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Bits of functionality common to ballistica client and server components.""" diff --git a/tools/bacommon/assets.py b/tools/bacommon/assets.py index fa789e89..60d1409c 100644 --- a/tools/bacommon/assets.py +++ b/tools/bacommon/assets.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to cloud based assets.""" from __future__ import annotations diff --git a/tools/bacommon/err.py b/tools/bacommon/err.py index aa77f4d4..b1403cbc 100644 --- a/tools/bacommon/err.py +++ b/tools/bacommon/err.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Error related functionality.""" from __future__ import annotations diff --git a/tools/bacommon/servermanager.py b/tools/bacommon/servermanager.py index 732250ff..5ff36eae 100644 --- a/tools/bacommon/servermanager.py +++ b/tools/bacommon/servermanager.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to the server manager script.""" from __future__ import annotations diff --git a/tools/batools/__init__.py b/tools/batools/__init__.py index 2d3bd7fb..583b42dd 100644 --- a/tools/batools/__init__.py +++ b/tools/batools/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Build/tool functionality specific to the Ballistica project. This stuff can be a bit more sloppy/loosey-goosey since it is not used by the diff --git a/tools/batools/android.py b/tools/batools/android.py index 46e8dff1..d286456b 100644 --- a/tools/batools/android.py +++ b/tools/batools/android.py @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to android builds.""" from __future__ import annotations diff --git a/tools/batools/assetsmakefile.py b/tools/batools/assetsmakefile.py index a77164aa..8c225c2b 100755 --- a/tools/batools/assetsmakefile.py +++ b/tools/batools/assetsmakefile.py @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Updates assets/Makefile based on source assets present.""" from __future__ import annotations diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index dbe76f1f..3137d602 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Stage assets for a build.""" from __future__ import annotations diff --git a/tools/batools/build.py b/tools/batools/build.py index a85d4b3d..0cdbea18 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """General functionality related to running builds.""" from __future__ import annotations @@ -277,7 +259,7 @@ def gen_fulltest_buildfile_android() -> None: continue mode = modes[(dayoffset + i) % len(modes)] lines.append('ANDROID_PLATFORM=' + flavor + ' ANDROID_MODE=' + mode + - ' nice -n 15 make android-build') + ' make android-cloud-build') # Now add sparse tests that land on today. if DO_SPARSE_TEST_BUILDS: @@ -432,7 +414,7 @@ def gen_fulltest_buildfile_linux() -> None: targets = ['build', 'server-build'] lines = [] for target in targets: - lines.append(f'make cmake-cloudshell-{target}') + lines.append(f'make cmake-cloud-{target}') if DO_SPARSE_TEST_BUILDS: extras = SPARSE_TEST_BUILDS[dayoffset % len(SPARSE_TEST_BUILDS)] diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index f2b94f37..ab802fdd 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Standard snippets that can be pulled into project pcommand scripts. A snippet is a mini-program that directly takes input from stdin and does @@ -279,23 +261,31 @@ def lazy_increment_build() -> None: def get_master_asset_src_dir() -> None: """Print master-asset-source dir for this repo.""" import subprocess + import os - # Ok, for now lets simply use our hard-coded master-src - # path if we're on master in and not otherwise. Should - # probably make this configurable. - output = subprocess.check_output( - ['git', 'status', '--branch', '--porcelain']).decode() + master_assets_dir = '/Users/ericf/Dropbox/ballisticacore_master_assets' + dummy_dir = '/__DUMMY_MASTER_SRC_DISABLED_PATH__' - # Also compare repo name to split version of itself to - # see if we're outside of core (filtering will cause mismatch if so). - if ('origin/master' in output.splitlines()[0] - and 'ballistica' + 'core' == 'ballisticacore'): + # Only apply this on my setup + if os.path.exists(master_assets_dir): - # We seem to be in master in core repo; lets do it. - print('/Users/ericf/Dropbox/ballisticacore_master_assets') - else: - # Still need to supply dummy path for makefile if not.. - print('/__DUMMY_MASTER_SRC_DISABLED_PATH__') + # Ok, for now lets simply use our hard-coded master-src + # path if we're on master in and not otherwise. Should + # probably make this configurable. + output = subprocess.check_output( + ['git', 'status', '--branch', '--porcelain']).decode() + + # Also compare repo name to split version of itself to + # see if we're outside of core (filtering will cause mismatch if so). + if ('origin/master' in output.splitlines()[0] + and 'ballistica' + 'core' == 'ballisticacore'): + + # We seem to be in master in core repo; lets do it. + print(master_assets_dir) + return + + # Still need to supply dummy path for makefile if not.. + print(dummy_dir) def androidaddr() -> None: @@ -673,8 +663,10 @@ def _camel_case_split(string: str) -> List[str]: def efro_gradle() -> None: """Calls ./gradlew with some extra magic.""" import subprocess + from efro.terminal import Clr from efrotools.android import filter_gradle_file args = ['./gradlew'] + sys.argv[2:] + print(f'{Clr.BLU}Running gradle with args:{Clr.RST} {args}.', flush=True) enabled_tags: Set[str] = set() target_words = [w.lower() for w in _camel_case_split(args[-1])] if 'google' in target_words: diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index 7b7bfb3f..93db6216 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """This script acts as a 'meta' Makefile for the project. It is in charge of generating Makefiles, IDE project files, procedurally generated source files, etc. based on the current structure of the project. @@ -84,8 +66,8 @@ class Updater: self._line_corrections: Dict[str, List[LineChange]] = {} self._file_changes: Dict[str, str] = {} - self._copyright_checks = bool( - getlocalconfig(Path('.')).get('copyright_checks', True)) + self._license_line_checks = bool( + getlocalconfig(Path('.')).get('license_line_checks', False)) def run(self) -> None: """Do the thing.""" @@ -222,7 +204,7 @@ class Updater: # Make a note on copyright lines that this can be disabled. if 'Copyright' in change[1].expected: print(f'{Clr.RED}NOTE: You can disable copyright' - f' checks by adding "copyright_checks": false\n' + f' checks by adding "license_line_checks": false\n' f'to the root dict in config/localconfig.json.\n' f'see https://ballistica.net/wiki' f'/Knowledge-Nuggets#' @@ -281,7 +263,7 @@ class Updater: lines = infile.read().splitlines() # Look for copyright/legal-notice line(s) - if self._copyright_checks: + if self._license_line_checks: legal_notice = '// ' + get_legal_notice_private() lnum = 0 if lines[lnum] != legal_notice: @@ -377,7 +359,6 @@ class Updater: raise RuntimeError(f'Pub license not found in {fname}') def _check_python_file(self, fname: str) -> None: - # pylint: disable=too-many-branches from efrotools import get_public_license, PYVER with open(fname) as infile: contents = infile.read() @@ -407,55 +388,63 @@ class Updater: # In all cases, look for our one-line legal notice. # In the public case, look for the rest of our public license too. - if self._copyright_checks: + if self._license_line_checks: public_license = get_public_license('python') - line = '# ' + get_legal_notice_private() + private_license = '# ' + get_legal_notice_private() # (Sanity check: public license's first line should be # same as priv) - if line != public_license.splitlines()[0]: - raise RuntimeError( - 'Public license first line should match priv.') + # if line != public_license.splitlines()[0]: + # raise RuntimeError( + # 'Public license first line should match priv.') lnum = copyrightline if len(lines) < lnum + 1: raise RuntimeError('Not enough lines in file:', fname) - if lines[lnum] != line: - # Allow auto-correcting if it looks close already - # (don't want to blow away an unrelated line) - allow_auto = 'Copyright' in lines[ - lnum] and 'Eric Froemling' in lines[lnum] - self._add_line_correction(fname, - line_number=lnum, - expected=line, - can_auto_update=allow_auto) - found_intact_private = False - else: - found_intact_private = True + # if lines[lnum] != private_license: + # # Allow auto-correcting if it looks close already + # # (don't want to blow away an unrelated line) + # # allow_auto = 'Copyright' in lines[ + # # lnum] and 'Eric Froemling' in lines[lnum] + # allow_auto = False + # self._add_line_correction(fname, + # line_number=lnum, + # expected=private_license, + # can_auto_update=allow_auto) + # found_intact_private = False + # else: + # found_intact_private = True if self._public: - # Check for the full license. - # If we can't find the full license but we found - # a private-license line, offer to replace it with the - # full one. Otherwise just complain and die. + # Check for public license only. + if lines[lnum] != public_license: + raise RuntimeError( + f'Found incorrect license text in {fname};' + f' please correct.') + else: + if (lines[lnum] != public_license + and lines[lnum] != private_license): + raise RuntimeError( + f'Found incorrect license text in {fname};' + f' please correct.') - # Try to be reasonably certain it's not in here... - definitely_have_full = public_license in contents - might_have_full = ('Permission is hereby granted' in contents - or 'THE SOFTWARE IS PROVIDED' in contents) + # # Try to be reasonably certain it's not in here... + # definitely_have_full = public_license in contents + # might_have_full = ('Permission is hereby granted' in contents + # or 'THE SOFTWARE IS PROVIDED' in contents) - # Only muck with it if we're not sure we've got it. - if not definitely_have_full: - if found_intact_private and not might_have_full: - self._add_line_correction(fname, - line_number=lnum, - expected=public_license, - can_auto_update=True) - else: - raise RuntimeError( - f'Found incorrect license text in {fname};' - f' please correct.') + # # Only muck with it if we're not sure we've got it. + # if not definitely_have_full: + # if found_intact_private and not might_have_full: + # self._add_line_correction(fname, + # line_number=lnum, + # expected=public_license, + # can_auto_update=True) + # else: + # raise RuntimeError( + # f'Found incorrect license text in {fname};' + # f' please correct.') def _check_python_files(self) -> None: from pathlib import Path diff --git a/tools/efro/__init__.py b/tools/efro/__init__.py index ec9d9060..1f50d614 100644 --- a/tools/efro/__init__.py +++ b/tools/efro/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Common bits of functionality shared between all efro projects. Things in here should be hardened, highly type-safe, and well-covered by unit diff --git a/tools/efro/call.py b/tools/efro/call.py index 62928c7a..f5bedfc2 100644 --- a/tools/efro/call.py +++ b/tools/efro/call.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Call related functionality shared between all efro components.""" from __future__ import annotations diff --git a/tools/efro/dataclasses.py b/tools/efro/dataclasses.py index 38edc2d2..4b20d74f 100644 --- a/tools/efro/dataclasses.py +++ b/tools/efro/dataclasses.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Custom functionality for dealing with dataclasses.""" from __future__ import annotations diff --git a/tools/efro/entity/__init__.py b/tools/efro/entity/__init__.py index 91e6d3af..6ecca973 100644 --- a/tools/efro/entity/__init__.py +++ b/tools/efro/entity/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Entity functionality. A system for defining complex data-containing types, supporting both static diff --git a/tools/efro/entity/_base.py b/tools/efro/entity/_base.py index 356d379e..08789c39 100644 --- a/tools/efro/entity/_base.py +++ b/tools/efro/entity/_base.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Base classes for the entity system.""" from __future__ import annotations diff --git a/tools/efro/entity/_entity.py b/tools/efro/entity/_entity.py index 144fec0f..220d243d 100644 --- a/tools/efro/entity/_entity.py +++ b/tools/efro/entity/_entity.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for the actual Entity types.""" from __future__ import annotations diff --git a/tools/efro/entity/_field.py b/tools/efro/entity/_field.py index f540141b..fbb1719a 100644 --- a/tools/efro/entity/_field.py +++ b/tools/efro/entity/_field.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Field types for the entity system.""" from __future__ import annotations diff --git a/tools/efro/entity/_support.py b/tools/efro/entity/_support.py index 961c6b0e..6d32ae39 100644 --- a/tools/efro/entity/_support.py +++ b/tools/efro/entity/_support.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Various support classes for accessing data and info on fields and values.""" from __future__ import annotations diff --git a/tools/efro/entity/_value.py b/tools/efro/entity/_value.py index b85919d9..57981796 100644 --- a/tools/efro/entity/_value.py +++ b/tools/efro/entity/_value.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Value types for the entity system.""" from __future__ import annotations diff --git a/tools/efro/entity/util.py b/tools/efro/entity/util.py index 8f804b4b..982ff6b9 100644 --- a/tools/efro/entity/util.py +++ b/tools/efro/entity/util.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Misc utility functionality related to the entity system.""" from __future__ import annotations diff --git a/tools/efro/error.py b/tools/efro/error.py index 88bfd7aa..80bd3ce7 100644 --- a/tools/efro/error.py +++ b/tools/efro/error.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for dealing with errors.""" from __future__ import annotations diff --git a/tools/efro/json.py b/tools/efro/json.py index 0ec2f492..f7775585 100644 --- a/tools/efro/json.py +++ b/tools/efro/json.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Custom json compressor/decompressor with support for more data times/etc.""" from __future__ import annotations diff --git a/tools/efro/terminal.py b/tools/efro/terminal.py index 3919de7b..f097a450 100644 --- a/tools/efro/terminal.py +++ b/tools/efro/terminal.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to terminal IO.""" from __future__ import annotations diff --git a/tools/efro/util.py b/tools/efro/util.py index 906f17d1..1140ba27 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Small handy bits of functionality.""" from __future__ import annotations diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index 86b68a57..daed12bd 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Build/tool functionality shared between all efro projects. This stuff can be a bit more sloppy/loosey-goosey since it is not used in @@ -113,8 +95,9 @@ def get_public_license(style: str) -> str: # Add a line at the bottom since our python-formatters tend to smush # our code up against the license; this keeps things a bit more # visually separated. - return ('\n'.join('#' + (' ' if l else '') + l - for l in raw.splitlines()) + '\n' + '# ' + '-' * 77) + return '# Released under the MIT License. See LICENSE for details.' + #return ('\n'.join('#' + (' ' if l else '') + l + # for l in raw.splitlines()) + '\n' + '# ' + '-' * 77) if style == 'makefile': # Basically same as python except without the last line. return ('\n'.join('#' + (' ' if l else '') + l diff --git a/tools/efrotools/android.py b/tools/efrotools/android.py index 16ed82f7..64738fbb 100644 --- a/tools/efrotools/android.py +++ b/tools/efrotools/android.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to android builds.""" from __future__ import annotations diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 63ec4bc3..2b8ba44e 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for formatting, linting, etc. code.""" from __future__ import annotations diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index f58dda6c..7b3a5296 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """A simple cloud caching system for making built binaries/assets available. The basic idea here is the ballistica-internal project can flag file targets @@ -289,7 +271,7 @@ def _upload_cache(fnames1: List[str], fnames2: List[str], hashes_str: str, # Sync all individual cache files to the staging server. print(f'{Clr.SBLU}Pushing cache to staging...{Clr.RST}', flush=True) - run('rsync --progress --recursive build/efrocache/' + run('rsync --progress --recursive --human-readable build/efrocache/' ' ubuntu@ballistica.net:files.ballistica.net/cache/ba1/') # Now generate the starter cache on the server.. diff --git a/tools/efrotools/filecache.py b/tools/efrotools/filecache.py index 77539068..188b4bf1 100644 --- a/tools/efrotools/filecache.py +++ b/tools/efrotools/filecache.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Provides a system for caching linting/formatting operations.""" from __future__ import annotations diff --git a/tools/efrotools/ios.py b/tools/efrotools/ios.py index 4115bdb3..3c342d5d 100644 --- a/tools/efrotools/ios.py +++ b/tools/efrotools/ios.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Tools related to ios development.""" from __future__ import annotations diff --git a/tools/efrotools/jsontools.py b/tools/efrotools/jsontools.py index d01ae53b..b1739704 100644 --- a/tools/efrotools/jsontools.py +++ b/tools/efrotools/jsontools.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Json related tools functionality.""" from __future__ import annotations diff --git a/tools/efrotools/makefile.py b/tools/efrotools/makefile.py index 1ebd0f5d..9412ada9 100644 --- a/tools/efrotools/makefile.py +++ b/tools/efrotools/makefile.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Tools for parsing/filtering makefiles.""" from __future__ import annotations diff --git a/tools/efrotools/pcommand.py b/tools/efrotools/pcommand.py index 57849d74..f9fa2ea6 100644 --- a/tools/efrotools/pcommand.py +++ b/tools/efrotools/pcommand.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Standard snippets that can be pulled into project pcommand scripts. A snippet is a mini-program that directly takes input from stdin and does diff --git a/tools/efrotools/pybuild.py b/tools/efrotools/pybuild.py index df623831..5b2a5267 100644 --- a/tools/efrotools/pybuild.py +++ b/tools/efrotools/pybuild.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality related to building python for ios, android, etc.""" from __future__ import annotations diff --git a/tools/efrotools/pylintplugins.py b/tools/efrotools/pylintplugins.py index 3db6760b..490df001 100644 --- a/tools/efrotools/pylintplugins.py +++ b/tools/efrotools/pylintplugins.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Plugins for pylint""" from __future__ import annotations diff --git a/tools/efrotools/statictest.py b/tools/efrotools/statictest.py index 2517662e..c2ed794b 100644 --- a/tools/efrotools/statictest.py +++ b/tools/efrotools/statictest.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for harnessing mypy for static type checking in unit tests.""" from __future__ import annotations diff --git a/tools/efrotools/sync.py b/tools/efrotools/sync.py index 860038d6..142ce815 100644 --- a/tools/efrotools/sync.py +++ b/tools/efrotools/sync.py @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """Functionality for syncing specific directories between different projects. This can be preferable vs using shared git subrepos for certain use cases. diff --git a/tools/pcommand b/tools/pcommand index 4a9c5cc2..9a582a34 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -1,24 +1,6 @@ #!/usr/bin/env python3.8 -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- """A collection of commands for use with this project. All top level functions here can be run by passing them as the first From 953d07406409017f3e3b4acd247e2ff7e0e1383e Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 12 Sep 2020 10:56:58 -0500 Subject: [PATCH 205/417] Tidying up license-line-checking --- .efrocachemap | 2 +- Makefile | 21 +----- assets/Makefile | 20 +---- .../ba_data/python/bastd/activity/__init__.py | 21 +----- .../ba_data/python/bastd/actor/__init__.py | 21 +----- .../src/ba_data/python/bastd/game/__init__.py | 21 +----- .../ba_data/python/bastd/keyboard/__init__.py | 21 +----- .../ba_data/python/bastd/mapdata/__init__.py | 21 +----- .../ba_data/python/bastd/session/__init__.py | 21 +----- .../ba_data/python/bastd/ui/coop/__init__.py | 21 +----- .../python/bastd/ui/profile/__init__.py | 21 +----- .../python/bastd/ui/settings/__init__.py | 21 +----- .../python/bastd/ui/soundtrack/__init__.py | 21 +----- .../ba_data/python/bastd/ui/store/__init__.py | 21 +----- tests/test_ba/__init__.py | 21 +----- tests/test_efro/__init__.py | 21 +----- tools/batools/updateproject.py | 74 +++++++------------ tools/efrotools/__init__.py | 13 +--- 18 files changed, 47 insertions(+), 356 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 0027084b..7308b3c3 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3939,5 +3939,5 @@ "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a0/7f/587e6a6d3dece7669d09bd042701", "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ad/4c/7b78e4c0a2e65a62fee7e38e34e7", "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c4/f8/1f8eee280877672da222c3397429", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/74/c7/dc173d3207f3ff2912093d28de98" + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/61/a7/7b8d223cef9f48fb58de41607009" } \ No newline at end of file diff --git a/Makefile b/Makefile index 8e682f73..a844f13b 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ------------------------------------------------------------------------------ - # This Makefile encompasses most high level functionality you should need when # working with Ballistica. These build rules are also handy as reference or a # starting point if you need specific funtionality beyond that exposed here. diff --git a/assets/Makefile b/assets/Makefile index e1bd6ec3..93161fbf 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -1,23 +1,5 @@ -# Copyright (c) 2011-2020 Eric Froemling +# Released under the MIT License. See LICENSE for details. # -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - ################################################################################ # # # Asset Generation # diff --git a/assets/src/ba_data/python/bastd/activity/__init__.py b/assets/src/ba_data/python/bastd/activity/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/activity/__init__.py +++ b/assets/src/ba_data/python/bastd/activity/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/actor/__init__.py b/assets/src/ba_data/python/bastd/actor/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/actor/__init__.py +++ b/assets/src/ba_data/python/bastd/actor/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/game/__init__.py b/assets/src/ba_data/python/bastd/game/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/game/__init__.py +++ b/assets/src/ba_data/python/bastd/game/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/keyboard/__init__.py b/assets/src/ba_data/python/bastd/keyboard/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/keyboard/__init__.py +++ b/assets/src/ba_data/python/bastd/keyboard/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/mapdata/__init__.py b/assets/src/ba_data/python/bastd/mapdata/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/mapdata/__init__.py +++ b/assets/src/ba_data/python/bastd/mapdata/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/session/__init__.py b/assets/src/ba_data/python/bastd/session/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/session/__init__.py +++ b/assets/src/ba_data/python/bastd/session/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/ui/coop/__init__.py b/assets/src/ba_data/python/bastd/ui/coop/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/ui/coop/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/coop/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/ui/profile/__init__.py b/assets/src/ba_data/python/bastd/ui/profile/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/profile/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/ui/settings/__init__.py b/assets/src/ba_data/python/bastd/ui/settings/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/ui/settings/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/settings/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/__init__.py b/assets/src/ba_data/python/bastd/ui/soundtrack/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/assets/src/ba_data/python/bastd/ui/store/__init__.py b/assets/src/ba_data/python/bastd/ui/store/__init__.py index 32622553..867b1714 100644 --- a/assets/src/ba_data/python/bastd/ui/store/__init__.py +++ b/assets/src/ba_data/python/bastd/ui/store/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/tests/test_ba/__init__.py b/tests/test_ba/__init__.py index 32622553..867b1714 100644 --- a/tests/test_ba/__init__.py +++ b/tests/test_ba/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/tests/test_efro/__init__.py b/tests/test_efro/__init__.py index 32622553..867b1714 100644 --- a/tests/test_efro/__init__.py +++ b/tests/test_efro/__init__.py @@ -1,20 +1 @@ -# Copyright (c) 2011-2020 Eric Froemling -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -# ----------------------------------------------------------------------------- +# Released under the MIT License. See LICENSE for details. diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index 93db6216..414739a1 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -67,7 +67,7 @@ class Updater: self._file_changes: Dict[str, str] = {} self._license_line_checks = bool( - getlocalconfig(Path('.')).get('license_line_checks', False)) + getlocalconfig(Path('.')).get('license_line_checks', True)) def run(self) -> None: """Do the thing.""" @@ -351,12 +351,15 @@ class Updater: for fname in fnames: with open(fname) as infile: makefile = infile.read() - if get_legal_notice_private() not in makefile: - raise RuntimeError(f'Priv legal not found in {fname}') if self._public: public_license = get_public_license('makefile') if public_license not in makefile: - raise RuntimeError(f'Pub license not found in {fname}') + raise CleanError(f'Pub license not found in {fname}.') + else: + if (get_legal_notice_private() not in makefile + and get_public_license('makefile') not in makefile): + raise CleanError( + f'Priv or pub legal not found in {fname}.') def _check_python_file(self, fname: str) -> None: from efrotools import get_public_license, PYVER @@ -391,60 +394,37 @@ class Updater: if self._license_line_checks: public_license = get_public_license('python') private_license = '# ' + get_legal_notice_private() - - # (Sanity check: public license's first line should be - # same as priv) - # if line != public_license.splitlines()[0]: - # raise RuntimeError( - # 'Public license first line should match priv.') - lnum = copyrightline if len(lines) < lnum + 1: raise RuntimeError('Not enough lines in file:', fname) - # if lines[lnum] != private_license: - # # Allow auto-correcting if it looks close already - # # (don't want to blow away an unrelated line) - # # allow_auto = 'Copyright' in lines[ - # # lnum] and 'Eric Froemling' in lines[lnum] - # allow_auto = False - # self._add_line_correction(fname, - # line_number=lnum, - # expected=private_license, - # can_auto_update=allow_auto) - # found_intact_private = False - # else: - # found_intact_private = True + disable_note = ('NOTE: You can disable license line' + ' checks by adding "license_line_checks": false\n' + 'to the root dict in config/localconfig.json.\n' + 'see https://ballistica.net/wiki' + '/Knowledge-Nuggets#' + 'hello-world-creating-a-new-game-type') if self._public: # Check for public license only. if lines[lnum] != public_license: - raise RuntimeError( - f'Found incorrect license text in {fname};' - f' please correct.') + raise CleanError(f'License text not found' + f" at '{fname}' line {lnum+1};" + f' please correct.\n' + f'Expected text is: {public_license}\n' + f'{disable_note}') else: + # Check for public or private license. if (lines[lnum] != public_license and lines[lnum] != private_license): - raise RuntimeError( - f'Found incorrect license text in {fname};' - f' please correct.') - - # # Try to be reasonably certain it's not in here... - # definitely_have_full = public_license in contents - # might_have_full = ('Permission is hereby granted' in contents - # or 'THE SOFTWARE IS PROVIDED' in contents) - - # # Only muck with it if we're not sure we've got it. - # if not definitely_have_full: - # if found_intact_private and not might_have_full: - # self._add_line_correction(fname, - # line_number=lnum, - # expected=public_license, - # can_auto_update=True) - # else: - # raise RuntimeError( - # f'Found incorrect license text in {fname};' - # f' please correct.') + raise CleanError(f'License text not found' + f" at '{fname}' line {lnum+1};" + f' please correct.\n' + f'Expected text (for public files):' + f' {public_license}\n' + f'Expected text (for private files):' + f' {private_license}\n' + f'{disable_note}') def _check_python_files(self) -> None: from pathlib import Path diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index daed12bd..6fac48dc 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -84,27 +84,22 @@ def set_config(projroot: Path, config: Dict[str, Any]) -> None: def get_public_license(style: str) -> str: - """Return the MIT license as used for our public facing stuff. + """Return the license notice as used for our public facing stuff. 'style' arg can be 'python', 'c++', or 'makefile, or 'raw'. """ - raw = MIT_LICENSE if style == 'raw': - return raw + return 'Released under the MIT License. See LICENSE for details.' if style == 'python': # Add a line at the bottom since our python-formatters tend to smush # our code up against the license; this keeps things a bit more # visually separated. return '# Released under the MIT License. See LICENSE for details.' - #return ('\n'.join('#' + (' ' if l else '') + l - # for l in raw.splitlines()) + '\n' + '# ' + '-' * 77) if style == 'makefile': # Basically same as python except without the last line. - return ('\n'.join('#' + (' ' if l else '') + l - for l in raw.splitlines())) + return '# Released under the MIT License. See LICENSE for details.' if style == 'c++': - return '\n'.join('//' + (' ' if l else '') + l - for l in raw.splitlines()) + return '// Released under the MIT License. See LICENSE for details.' raise RuntimeError(f'Invalid style: {style}') From c643145bfe3a7f1794902dfeebbb37202fc75e28 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 12 Sep 2020 11:25:33 -0500 Subject: [PATCH 206/417] Language updates --- .efrocachemap | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 7308b3c3..ff706cf7 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/9d/cd/25cfecf21ff50b3a25e5e7318dc0", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/cc/e6/27f02675b9adec5bd553ac43ee03", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/d0/7c/87e7c5b3685a64f0a3ecd9a16b99", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", @@ -451,7 +451,7 @@ "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/8a/f7b2521c1904ffc83262dff1e11b", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/26/62/a072404c02c576a5c3f09059b582", - "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/cb/ae/e4006b346df70380788f24fa2716", + "assets/build/ba_data/data/languages/venetian.json": "https://files.ballistica.net/cache/ba1/9e/1f/bfb90e9420a1528d9e2cfba315bc", "assets/build/ba_data/data/languages/vietnamese.json": "https://files.ballistica.net/cache/ba1/04/52/683a27aaf9aa7c63e7e595f80d08", "assets/build/ba_data/data/maps/big_g.json": "https://files.ballistica.net/cache/ba1/47/0a/a617cc85d927b576c4e6fc1091ed", "assets/build/ba_data/data/maps/bridgit.json": "https://files.ballistica.net/cache/ba1/03/4b/57ee9b42854b26f23f81bd8c58ef", @@ -3930,8 +3930,8 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/33/9e/3106cd524bfe83e8ca3ba603a0a3", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/64/88/77db83b5fe1218a99392f88b7131", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/46/36/ebf2770d091219bbccac73d18d96", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ea/78/2b6fa11738eefee4c65900543679", "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/74/74dcfb32ee1d796230cfac867978", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/63/5067f6fae12feecaa181d4f13a4d", "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/d7/2abece41eae6a109583d75300528", From cd259c65afe239be1882c3275203490801c920c8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 20 Sep 2020 14:44:11 -0500 Subject: [PATCH 207/417] build system rework --- .efrocachemap | 24 ++-- .idea/dictionaries/ericf.xml | 19 ++- CHANGELOG.md | 2 +- assets/.asset_manifest_private.json | 4 + assets/Makefile | 10 +- assets/src/ba_data/python/ba/_app.py | 114 ++++++++---------- assets/src/ba_data/python/ba/_coopsession.py | 2 +- assets/src/ba_data/python/ba/_map.py | 2 +- assets/src/ba_data/python/ba/_meta.py | 2 +- assets/src/ba_data/python/ba/_music.py | 4 +- assets/src/ba_data/python/ba/_score.py | 2 +- assets/src/ba_data/python/ba/_session.py | 2 +- assets/src/ba_data/python/ba/_stats.py | 2 +- assets/src/ba_data/python/ba/_ui.py | 6 +- assets/src/ba_data/python/bastd/actor/flag.py | 6 +- assets/src/ba_data/python/bastd/mainmenu.py | 18 +++ docs/ba_module.md | 16 +-- tools/bacloud | 2 +- tools/batools/build.py | 36 ++++-- tools/batools/updateproject.py | 13 +- 20 files changed, 160 insertions(+), 126 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index ff706cf7..e5cd40b8 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -1670,6 +1670,10 @@ "assets/build/ba_data/textures/iconRunaround.ktx": "https://files.ballistica.net/cache/ba1/6e/66/c5741e7805801c46c18df2f86c9a", "assets/build/ba_data/textures/iconRunaround.pvr": "https://files.ballistica.net/cache/ba1/54/e9/55a73bde307c0c7cb386c06837ac", "assets/build/ba_data/textures/iconRunaround_preview.png": "https://files.ballistica.net/cache/ba1/2b/09/82799554bb223e4ffba1aeb3dc81", + "assets/build/ba_data/textures/iircadeLogo.dds": "https://files.ballistica.net/cache/ba1/d1/e3/2f27a82cd5e5c69f78a3bac30ab5", + "assets/build/ba_data/textures/iircadeLogo.ktx": "https://files.ballistica.net/cache/ba1/58/b9/848fbac7a1c7ad6a9b2efd758ff1", + "assets/build/ba_data/textures/iircadeLogo.pvr": "https://files.ballistica.net/cache/ba1/19/ba/66f832c978d9cf46f991e4811401", + "assets/build/ba_data/textures/iircadeLogo_preview.png": "https://files.ballistica.net/cache/ba1/c7/d6/0740136951cbc17907f6192357b2", "assets/build/ba_data/textures/impactBombColor.dds": "https://files.ballistica.net/cache/ba1/70/54/c210c5ade9e3ba9a39b71631dc24", "assets/build/ba_data/textures/impactBombColor.ktx": "https://files.ballistica.net/cache/ba1/fc/3b/e1051061b1ed03bcbfdc6b9f8c79", "assets/build/ba_data/textures/impactBombColor.pvr": "https://files.ballistica.net/cache/ba1/d6/d9/0f81193db5aa44780ee8bb0943b9", @@ -3930,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/46/36/ebf2770d091219bbccac73d18d96", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ea/78/2b6fa11738eefee4c65900543679", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/11/74/74dcfb32ee1d796230cfac867978", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/63/5067f6fae12feecaa181d4f13a4d", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/d7/2abece41eae6a109583d75300528", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ab/15/0ba36634e2d80e8bed3922a63b24", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a0/7f/587e6a6d3dece7669d09bd042701", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ad/4c/7b78e4c0a2e65a62fee7e38e34e7", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c4/f8/1f8eee280877672da222c3397429", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/61/a7/7b8d223cef9f48fb58de41607009" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/95/36/1850f9eda27c27700a928a220d01", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/51/8117cff653fd3d3e5e4f2da28cfb", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/1b/dc4328caa59881f3c7a18f4b71cd", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/16/06/ce0ff5f88a22e9fd7daae113b229", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/63/af/656a2860f87943d534fdb69386bd", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6a/fc189088a19d5b12d624e5b9521a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c5/9b/597a1666729e0a9ad347f8aab67d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ba/03/4a8dd4bb42754cdd2bbd23949f25", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/b9/782ed1cea39bc38ae635dc21f4cd", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/1d/9fdaf892813430d8e9b3ef6628a4" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 39f4e51a..5ebd5934 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack ack'ed + ack acked acks acnt @@ -82,6 +82,7 @@ appkit applescript appletv + appmode appname appnameupper appstate @@ -150,8 +151,8 @@ bacommon badguy bafoundation - ballistica ballistica's + ballistica ballisticacore ballisticacorecb bamaster @@ -330,6 +331,7 @@ clionbin clioncode clionroot + cloudbuild cloudshell cloudshellbuild cloudtool @@ -791,8 +793,8 @@ gamedata gameinstance gamemap - gamepad gamepad's + gamepad gamepadadvanced gamepads gamepadselect @@ -949,6 +951,8 @@ idevices ifeq ifneq + iiarcade + iircade ilang ilck ilogput @@ -958,6 +962,7 @@ imagestacklayer imagewidget imaplib + imgdelay imgh imghdr imgw @@ -1172,8 +1177,8 @@ lsqlite lssl lstart - lstr lstr's + lstr lstrs lsval ltex @@ -1795,8 +1800,8 @@ sessionname sessionplayer sessionplayers - sessionteam sessionteam's + sessionteam sessionteams sessiontype setactivity @@ -2126,8 +2131,8 @@ txtw typeargs typecheck - typechecker typechecker's + typechecker typedval typeshed typestr @@ -2249,6 +2254,7 @@ wiimote wiimotes willeval + winbeast wincfg wincount winempty @@ -2271,6 +2277,7 @@ wref writeclasses writefuncs + wslpath wtcolor wtflib wttxt diff --git a/CHANGELOG.md b/CHANGELOG.md index 37779695..11717dfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ ### 1.5.26 (20178) -- Simplified licensing header on python scripts. +- Simplified licensing header on python scripts.. ### 1.5.25 (20176) - Added Venetian language (thanks Federico!) diff --git a/assets/.asset_manifest_private.json b/assets/.asset_manifest_private.json index 1bb8aa43..d96286e2 100644 --- a/assets/.asset_manifest_private.json +++ b/assets/.asset_manifest_private.json @@ -1688,6 +1688,10 @@ "ba_data/textures/iconRunaround.ktx", "ba_data/textures/iconRunaround.pvr", "ba_data/textures/iconRunaround_preview.png", + "ba_data/textures/iircadeLogo.dds", + "ba_data/textures/iircadeLogo.ktx", + "ba_data/textures/iircadeLogo.pvr", + "ba_data/textures/iircadeLogo_preview.png", "ba_data/textures/impactBombColor.dds", "ba_data/textures/impactBombColor.ktx", "ba_data/textures/impactBombColor.pvr", diff --git a/assets/Makefile b/assets/Makefile index 93161fbf..784b3207 100644 --- a/assets/Makefile +++ b/assets/Makefile @@ -5361,6 +5361,7 @@ TEX2D_DDS_TARGETS = \ build/ba_data/textures/hockeyStadiumPreview.dds \ build/ba_data/textures/iconOnslaught.dds \ build/ba_data/textures/iconRunaround.dds \ + build/ba_data/textures/iircadeLogo.dds \ build/ba_data/textures/impactBombColor.dds \ build/ba_data/textures/impactBombColorLit.dds \ build/ba_data/textures/inventoryIcon.dds \ @@ -5763,6 +5764,7 @@ TEX2D_PVR_TARGETS = \ build/ba_data/textures/hockeyStadiumPreview.pvr \ build/ba_data/textures/iconOnslaught.pvr \ build/ba_data/textures/iconRunaround.pvr \ + build/ba_data/textures/iircadeLogo.pvr \ build/ba_data/textures/impactBombColor.pvr \ build/ba_data/textures/impactBombColorLit.pvr \ build/ba_data/textures/inventoryIcon.pvr \ @@ -6165,6 +6167,7 @@ TEX2D_KTX_TARGETS = \ build/ba_data/textures/hockeyStadiumPreview.ktx \ build/ba_data/textures/iconOnslaught.ktx \ build/ba_data/textures/iconRunaround.ktx \ + build/ba_data/textures/iircadeLogo.ktx \ build/ba_data/textures/impactBombColor.ktx \ build/ba_data/textures/impactBombColorLit.ktx \ build/ba_data/textures/inventoryIcon.ktx \ @@ -6567,6 +6570,7 @@ TEX2D_PREVIEW_PNG_TARGETS = \ build/ba_data/textures/hockeyStadium_preview.png \ build/ba_data/textures/iconOnslaught_preview.png \ build/ba_data/textures/iconRunaround_preview.png \ + build/ba_data/textures/iircadeLogo_preview.png \ build/ba_data/textures/impactBombColorLit_preview.png \ build/ba_data/textures/impactBombColor_preview.png \ build/ba_data/textures/inventoryIcon_preview.png \ @@ -6990,13 +6994,13 @@ build/ba_data/data/languages/%.json : ../.efrocachemap build/ba_data/data/maps/%.json : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -src/%.tex2d.png : ../.efrocachemap +src/ba_data/%.tex2d.png : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -src/%_+x.tex2d.png : ../.efrocachemap +src/ba_data/%_+x.tex2d.png : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ -build/%_preview.png : ../.efrocachemap +build/ba_data/%_preview.png : ../.efrocachemap @cd .. && tools/pcommand efrocache_get assets/$@ build/%.dds : ../.efrocachemap diff --git a/assets/src/ba_data/python/ba/_app.py b/assets/src/ba_data/python/ba/_app.py index 058fd1ac..d3a9936e 100644 --- a/assets/src/ba_data/python/ba/_app.py +++ b/assets/src/ba_data/python/ba/_app.py @@ -40,12 +40,14 @@ class App: This value increases by at least 1 with each release of the game. It is independent of the human readable ba.App.version string. """ - return self._build_number + assert isinstance(self._env['build_number'], int) + return self._env['build_number'] @property def config_file_path(self) -> str: """Where the game's config file is stored on disk.""" - return self._config_file_path + assert isinstance(self._env['config_file_path'], str) + return self._env['config_file_path'] @property def locale(self) -> str: @@ -55,7 +57,8 @@ class App: ba.App.language, which is the language the game is using (which may differ from locale if the user sets a language, etc.) """ - return self._locale + assert isinstance(self._env['locale'], str) + return self._env['locale'] def can_display_language(self, language: str) -> bool: """Tell whether we can display a particular language. @@ -107,7 +110,7 @@ class App: 'hi': 'Hindi' } - # Special case for Chinese: specific variations map to traditional. + # Special case for Chinese: map specific variations to traditional. # (otherwise will map to 'Chinese' which is simplified) if self.locale in ('zh_HANT', 'zh_TW'): language = 'ChineseTraditional' @@ -130,7 +133,9 @@ class App: @property def user_agent_string(self) -> str: """String containing various bits of info about OS/device/etc.""" - return self._user_agent_string + # return self._user_agent_string + assert isinstance(self._env['user_agent_string'], str) + return self._env['user_agent_string'] @property def version(self) -> str: @@ -140,7 +145,8 @@ class App: string elements such as 'alpha', 'beta', 'test', etc. If a numeric version is needed, use 'ba.App.build_number'. """ - return self._version + assert isinstance(self._env['version'], str) + return self._env['version'] @property def debug_build(self) -> bool: @@ -150,7 +156,8 @@ class App: builds due to compiler optimizations being disabled and extra checks being run. """ - return self._debug_build + assert isinstance(self._env['debug_build'], bool) + return self._env['debug_build'] @property def test_build(self) -> bool: @@ -159,22 +166,27 @@ class App: Test mode enables extra checks and features that are useful for release testing but which do not slow the game down significantly. """ - return self._test_build + assert isinstance(self._env['test_build'], bool) + return self._env['test_build'] @property def python_directory_user(self) -> str: """Path where the app looks for custom user scripts.""" - return self._python_directory_user + assert isinstance(self._env['python_directory_user'], str) + return self._env['python_directory_user'] @property def python_directory_app(self) -> str: """Path where the app looks for its bundled scripts.""" - return self._python_directory_app + assert isinstance(self._env['python_directory_app'], str) + return self._env['python_directory_app'] + # return self._python_directory_app @property def python_directory_app_site(self) -> str: """Path containing pip packages bundled with the app.""" - return self._python_directory_app_site + assert isinstance(self._env['python_directory_app_site'], str) + return self._env['python_directory_app_site'] @property def config(self) -> ba.AppConfig: @@ -188,7 +200,8 @@ class App: Examples are: 'mac', 'windows', android'. """ - return self._platform + assert isinstance(self._env['platform'], str) + return self._env['platform'] @property def subplatform(self) -> str: @@ -197,30 +210,33 @@ class App: Can be empty. For the 'android' platform, subplatform may be 'google', 'amazon', etc. """ - return self._subplatform + assert isinstance(self._env['subplatform'], str) + return self._env['subplatform'] @property def api_version(self) -> int: """The game's api version. - Only python modules and packages associated with the current api - version will be detected by the game (see the ba_meta tag). This - value will change whenever backward-incompatible changes are - introduced to game apis; when that happens, scripts should be updated - accordingly and set to target the new api. + Only Python modules and packages associated with the current API + version number will be detected by the game (see the ba_meta tag). + This value will change whenever backward-incompatible changes are + introduced to game APIs. When that happens, scripts should be updated + accordingly and set to target the new API version number. """ from ba._meta import CURRENT_API_VERSION return CURRENT_API_VERSION @property def on_tv(self) -> bool: - """Bool value for if the game is running on a TV.""" - return self._on_tv + """Whether the game is currently running on a TV.""" + assert isinstance(self._env['on_tv'], bool) + return self._env['on_tv'] @property def vr_mode(self) -> bool: - """Bool value for if the game is running in VR.""" - return self._vr_mode + """Whether the game is currently running in VR.""" + assert isinstance(self._env['vr_mode'], bool) + return self._env['vr_mode'] @property def ui_bounds(self) -> Tuple[float, float, float, float]: @@ -237,7 +253,7 @@ class App: the single shared instance. """ # pylint: disable=too-many-statements - from ba._music import MusicController + from ba._music import MusicSubsystem from ba._ui import UI # Config. @@ -248,47 +264,19 @@ class App: # refreshed/etc. self.fg_state = 0 - # Environment stuff. - # (pulling these into attrs so we can type-check them and provide docs) - env = _ba.env() - self._build_number: int = env['build_number'] - assert isinstance(self._build_number, int) - self._config_file_path: str = env['config_file_path'] - assert isinstance(self._config_file_path, str) - self._locale: str = env['locale'] - assert isinstance(self._locale, str) - self._user_agent_string: str = env['user_agent_string'] - assert isinstance(self._user_agent_string, str) - self._version: str = env['version'] - assert isinstance(self._version, str) - self._debug_build: bool = env['debug_build'] - assert isinstance(self._debug_build, bool) - self._test_build: bool = env['test_build'] - assert isinstance(self._test_build, bool) - self._python_directory_user: str = env['python_directory_user'] - assert isinstance(self._python_directory_user, str) - self._python_directory_app: str = env['python_directory_app'] - assert isinstance(self._python_directory_app, str) - self._python_directory_app_site: str = env['python_directory_app_site'] - assert isinstance(self._python_directory_app_site, str) - self._platform: str = env['platform'] - assert isinstance(self._platform, str) - self._subplatform: str = env['subplatform'] - assert isinstance(self._subplatform, str) - self._on_tv: bool = env['on_tv'] - assert isinstance(self._on_tv, bool) - self._vr_mode: bool = env['vr_mode'] - assert isinstance(self._vr_mode, bool) - self.protocol_version: int = env['protocol_version'] + self._env = _ba.env() + self.protocol_version: int = self._env['protocol_version'] assert isinstance(self.protocol_version, int) - self.toolbar_test: bool = env['toolbar_test'] + self.toolbar_test: bool = self._env['toolbar_test'] assert isinstance(self.toolbar_test, bool) - self.demo_mode: bool = env['demo_mode'] + self.demo_mode: bool = self._env['demo_mode'] assert isinstance(self.demo_mode, bool) - self.arcade_mode: bool = env['arcade_mode'] + self.arcade_mode: bool = self._env['arcade_mode'] assert isinstance(self.arcade_mode, bool) - self.headless_build: bool = env['headless_build'] - assert isinstance(self.headless_build, bool) + self.headless_mode: bool = self._env['headless_mode'] + assert isinstance(self.headless_mode, bool) + self.iircade_mode: bool = self._env['iircade_mode'] + assert isinstance(self.headless_mode, bool) # Plugins. self.potential_plugins: List[ba.PotentialPlugin] = [] @@ -335,7 +323,7 @@ class App: self.attempted_first_ad = False # Music. - self.music = MusicController() + self.music = MusicSubsystem() # Language. self.language_target: Optional[_lang.AttrDict] = None @@ -493,7 +481,7 @@ class App: self.special_offer = config['pendingSpecialOffer']['o'] specialoffer.show_offer() - if not self.headless_build: + if not self.headless_mode: _ba.timer(3.0, check_special_offer, timetype=TimeType.REAL) # Start scanning for things exposed via ba_meta. @@ -501,7 +489,7 @@ class App: # Auto-sign-in to a local account in a moment if we're set to. def do_auto_sign_in() -> None: - if self.headless_build or cfg.get('Auto Account State') == 'Local': + if self.headless_mode or cfg.get('Auto Account State') == 'Local': _ba.sign_in('Local') _ba.pushcall(do_auto_sign_in) diff --git a/assets/src/ba_data/python/ba/_coopsession.py b/assets/src/ba_data/python/ba/_coopsession.py index 3b4fc6b5..5e351854 100644 --- a/assets/src/ba_data/python/ba/_coopsession.py +++ b/assets/src/ba_data/python/ba/_coopsession.py @@ -25,7 +25,7 @@ class CoopSession(Session): the computer and include functionality such as high score lists. - Attrs: + Attributes: campaign The ba.Campaign instance this Session represents, or None if diff --git a/assets/src/ba_data/python/ba/_map.py b/assets/src/ba_data/python/ba/_map.py index 1cacd8a4..bae3805b 100644 --- a/assets/src/ba_data/python/ba/_map.py +++ b/assets/src/ba_data/python/ba/_map.py @@ -108,7 +108,7 @@ def get_unowned_maps() -> List[str]: """ from ba import _store unowned_maps: Set[str] = set() - if not _ba.app.headless_build: + if not _ba.app.headless_mode: for map_section in _store.get_store_layout()['maps']: for mapitem in map_section['items']: if not _ba.get_purchased(mapitem): diff --git a/assets/src/ba_data/python/ba/_meta.py b/assets/src/ba_data/python/ba/_meta.py index a09e47a0..40c50187 100644 --- a/assets/src/ba_data/python/ba/_meta.py +++ b/assets/src/ba_data/python/ba/_meta.py @@ -381,7 +381,7 @@ def get_unowned_game_types() -> Set[Type[ba.GameActivity]]: try: from ba import _store unowned_games: Set[Type[ba.GameActivity]] = set() - if not _ba.app.headless_build: + if not _ba.app.headless_mode: for section in _store.get_store_layout()['minigames']: for mname in section['items']: if not _ba.get_purchased(mname): diff --git a/assets/src/ba_data/python/ba/_music.py b/assets/src/ba_data/python/ba/_music.py index 0e68de04..b60684a6 100644 --- a/assets/src/ba_data/python/ba/_music.py +++ b/assets/src/ba_data/python/ba/_music.py @@ -116,8 +116,8 @@ ASSET_SOUNDTRACK_ENTRIES: Dict[MusicType, AssetSoundtrackEntry] = { } -class MusicController: - """Controller for overall music playback in the app. +class MusicSubsystem: + """Subsystem for music playback in the app. Category: App Classes """ diff --git a/assets/src/ba_data/python/ba/_score.py b/assets/src/ba_data/python/ba/_score.py index be68a8e3..d1cbe52c 100644 --- a/assets/src/ba_data/python/ba/_score.py +++ b/assets/src/ba_data/python/ba/_score.py @@ -29,7 +29,7 @@ class ScoreConfig: Category: Gameplay Classes - Attrs: + Attributes: label A label show to the user for scores; 'Score', 'Time Survived', etc. diff --git a/assets/src/ba_data/python/ba/_session.py b/assets/src/ba_data/python/ba/_session.py index 2a066f4f..39cca9a7 100644 --- a/assets/src/ba_data/python/ba/_session.py +++ b/assets/src/ba_data/python/ba/_session.py @@ -28,7 +28,7 @@ class Session: ba.Activity instances such as mini-games and score-screens, and for maintaining state between them (players, teams, score tallies, etc). - Attrs: + Attributes: sessionteams All the ba.SessionTeams in the Session. Most things should use the diff --git a/assets/src/ba_data/python/ba/_stats.py b/assets/src/ba_data/python/ba/_stats.py index 089f7a5f..47a7ec79 100644 --- a/assets/src/ba_data/python/ba/_stats.py +++ b/assets/src/ba_data/python/ba/_stats.py @@ -24,7 +24,7 @@ class PlayerScoredMessage: Category: Message Classes - Attrs: + Attributes: score The score value. diff --git a/assets/src/ba_data/python/ba/_ui.py b/assets/src/ba_data/python/ba/_ui.py index f6a16ccc..ac7dfaeb 100644 --- a/assets/src/ba_data/python/ba/_ui.py +++ b/assets/src/ba_data/python/ba/_ui.py @@ -1,6 +1,6 @@ # Released under the MIT License. See LICENSE for details. # -"""User interface functionality.""" +"""User interface related functionality.""" from __future__ import annotations @@ -28,7 +28,7 @@ class UI: self._uiscale: ba.UIScale - interfacetype = env['interface_type'] + interfacetype = env['ui_scale'] if interfacetype == 'large': self._uiscale = UIScale.LARGE elif interfacetype == 'medium': @@ -36,7 +36,7 @@ class UI: elif interfacetype == 'small': self._uiscale = UIScale.SMALL else: - raise RuntimeError('Invalid UIScale value: {interfacetype}') + raise RuntimeError(f'Invalid UIScale value: {interfacetype}') self.window_states: Dict = {} # FIXME: Kill this. self.main_menu_selection: Optional[str] = None # FIXME: Kill this. diff --git a/assets/src/ba_data/python/bastd/actor/flag.py b/assets/src/ba_data/python/bastd/actor/flag.py index f238b29c..417a3d46 100644 --- a/assets/src/ba_data/python/bastd/actor/flag.py +++ b/assets/src/ba_data/python/bastd/actor/flag.py @@ -125,7 +125,7 @@ class FlagPickedUpMessage: category: Message Classes - Attrs: + Attributes: flag The ba.Flag that has been picked up. @@ -143,7 +143,7 @@ class FlagDiedMessage: category: Message Classes - Attrs: + Attributes: flag The ba.Flag that died. @@ -157,7 +157,7 @@ class FlagDroppedMessage: category: Message Classes - Attrs: + Attributes: flag The ba.Flag that was dropped. diff --git a/assets/src/ba_data/python/bastd/mainmenu.py b/assets/src/ba_data/python/bastd/mainmenu.py index d00ccdce..7a976816 100644 --- a/assets/src/ba_data/python/bastd/mainmenu.py +++ b/assets/src/ba_data/python/bastd/mainmenu.py @@ -130,6 +130,24 @@ class MainMenuActivity(ba.Activity[ba.Player, ba.Team]): assert self.version.node ba.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0}) + # Show the iircade logo on our iircade build. + if app.iircade_mode: + img = ba.NodeActor( + ba.newnode('image', + attrs={ + 'texture': ba.gettexture('iircadeLogo'), + 'attach': 'center', + 'scale': (250, 250), + 'position': (0, 0), + 'tilt_translate': 0.21, + 'absolute_scale': True + })).autoretain() + imgdelay = 0.0 if app.main_menu_did_initial_transition else 1.0 + ba.animate(img.node, 'opacity', { + imgdelay + 1.5: 0.0, + imgdelay + 2.5: 1.0 + }) + # Throw in test build info. self.beta_info = self.beta_info_2 = None if app.test_build and not (app.demo_mode or app.arcade_mode): diff --git a/docs/ba_module.md b/docs/ba_module.md index 5ad4eb1a..ff4e81d9 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-09-11 for Ballistica version 1.5.25 build 20179

    +

    last updated on 2020-09-17 for Ballistica version 1.5.26 build 20188

    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!


    @@ -816,11 +816,11 @@ likely result in errors.

    int

    The game's api version.

    -

    Only python modules and packages associated with the current api - version will be detected by the game (see the ba_meta tag). This - value will change whenever backward-incompatible changes are - introduced to game apis; when that happens, scripts should be updated - accordingly and set to target the new api.

    +

    Only Python modules and packages associated with the current API + version number will be detected by the game (see the ba_meta tag). + This value will change whenever backward-incompatible changes are + introduced to game APIs. When that happens, scripts should be updated + accordingly and set to target the new API version number.

    build_number

    @@ -869,7 +869,7 @@ likely result in errors.

    on_tv

    bool

    -

    Bool value for if the game is running on a TV.

    +

    Whether the game is currently running on a TV.

    platform

    @@ -933,7 +933,7 @@ likely result in errors.

    vr_mode

    bool

    -

    Bool value for if the game is running in VR.

    +

    Whether the game is currently running in VR.

    diff --git a/tools/bacloud b/tools/bacloud index 34e2c223..0b7ea780 100755 --- a/tools/bacloud +++ b/tools/bacloud @@ -48,7 +48,7 @@ class StateData: class Response: """Response sent from the bacloud server to the client. - Attrs: + Attributes: message: If present, client should print this message before any other response processing (including error handling) occurs. message_end: end arg for message print() call. diff --git a/tools/batools/build.py b/tools/batools/build.py index 0cdbea18..259df7f0 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -33,11 +33,11 @@ PIP_REQUIREMENTS = [ PipRequirement(modulename='mypy', minversion=[0, 782]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), PipRequirement(modulename='cpplint', minversion=[1, 5, 4]), + PipRequirement(modulename='pytest', minversion=[6, 0, 2]), PipRequirement(modulename='typing_extensions'), PipRequirement(modulename='pytz'), PipRequirement(modulename='yaml', pipname='PyYAML'), PipRequirement(modulename='requests'), - PipRequirement(modulename='pytest'), ] # Parts of full-tests suite we only run on particular days. @@ -225,7 +225,7 @@ def archive_old_builds(ssh_server: str, builds_dir: str, for old_file in [f for f in files if f.startswith(prefix)][1:]: files_to_archive.add(old_file) - # Would be faster to package this into a single command but + # Would be more efficient to package this into a single command but # this works. for fname in sorted(files_to_archive): print('Archiving ' + fname, file=sys.stderr) @@ -252,12 +252,27 @@ def gen_fulltest_buildfile_android() -> None: modes += modes modes.append('prod') + # By default we cycle through build architectures for each flavor. + # However, for minor flavor with low risk of platform-dependent breakage + # we stick to a single one to keep disk space costs lower. (build files + # amount to several gigs per mode per flavor) + # UPDATE: Now that we have CPU time to spare, we simply always do 'arm64' + # or 'prod' depending on build type; this results in 1 or 4 architectures + # worth of build files per flavor instead of 8 (prod + 4 singles) and + # keeps our daily runs identical. + lightweight_flavors = {'template', 'arcade', 'demo', 'iircade'} + lines = [] - for i, flavor in enumerate( + for _i, flavor in enumerate( sorted(os.listdir('ballisticacore-android/BallisticaCore/src'))): if flavor == 'main' or flavor.startswith('.'): continue - mode = modes[(dayoffset + i) % len(modes)] + + if flavor in lightweight_flavors: + mode = 'arm64' + else: + # mode = modes[(dayoffset + i) % len(modes)] + mode = 'prod' lines.append('ANDROID_PLATFORM=' + flavor + ' ANDROID_MODE=' + mode + ' make android-cloud-build') @@ -314,11 +329,11 @@ def gen_fulltest_buildfile_windows() -> None: cfg3 = 'Release' if (dayoffset + 2) % 7 == 0 else 'Debug' lines.append(f'WINDOWS_PROJECT= WINDOWS_PLATFORM={pval1} ' - f'WINDOWS_CONFIGURATION={cfg1} make windows-build') + f'WINDOWS_CONFIGURATION={cfg1} make windows-cloud-build') lines.append(f'WINDOWS_PROJECT=Headless WINDOWS_PLATFORM={pval2} ' - f'WINDOWS_CONFIGURATION={cfg2} make windows-build') + f'WINDOWS_CONFIGURATION={cfg2} make windows-cloud-build') lines.append(f'WINDOWS_PROJECT=Oculus WINDOWS_PLATFORM={pval3} ' - f'WINDOWS_CONFIGURATION={cfg3} make windows-build') + f'WINDOWS_CONFIGURATION={cfg3} make windows-cloud-build') # Now add sparse tests that land on today. if DO_SPARSE_TEST_BUILDS: @@ -391,7 +406,7 @@ def gen_fulltest_buildfile_apple() -> None: if extra == 'mac.package': lines.append('make mac-package') elif extra == 'mac.package.server': - lines.append('make mac-server-package') + lines.append('make mac-cloud-server-package') elif extra == 'mac.pylibs': lines.append('tools/pcommand python_build_apple mac') elif extra == 'mac.pylibs.debug': @@ -510,7 +525,9 @@ def checkenv() -> None: f'Alternately, "tools/pcommand install_pip_reqs"' f' will update all pip requirements.') if minver is not None: - verlines = results.stdout.decode().splitlines() + # Note: some modules such as pytest print their version to stderr, + # so grab both. + verlines = (results.stdout + results.stderr).decode().splitlines() if verlines[0].startswith('Cpplint fork'): verlines = verlines[1:] ver_line = verlines[0] @@ -664,6 +681,7 @@ def update_docs_md(check: bool) -> None: for fname in files: if any(fname.endswith(ext) for ext in exts): pysources.append(os.path.join(root, fname)) + pysources.sort() curhash = get_files_hash(pysources) # Extract the current embedded hash. diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index 414739a1..eb4907ca 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -179,7 +179,6 @@ class Updater: f'All {unchanged_project_count} project files are up to date.') def _apply_line_changes(self) -> None: - # pylint: disable=too-many-branches # Build a flat list of entries that can and can-not be auto applied. manual_changes: List[Tuple[str, LineChange]] = [] @@ -201,14 +200,6 @@ class Updater: f'{Clr.RED}{change[0]}:{change[1].line_number + 1}:' f' Expected line to be:\n {change[1].expected}{Clr.RST}') - # Make a note on copyright lines that this can be disabled. - if 'Copyright' in change[1].expected: - print(f'{Clr.RED}NOTE: You can disable copyright' - f' checks by adding "license_line_checks": false\n' - f'to the root dict in config/localconfig.json.\n' - f'see https://ballistica.net/wiki' - f'/Knowledge-Nuggets#' - f'hello-world-creating-a-new-game-type{Clr.RST}') sys.exit(-1) # Now, if we've got auto entries, either list or auto-correct them. @@ -262,7 +253,7 @@ class Updater: with open(fname) as infile: lines = infile.read().splitlines() - # Look for copyright/legal-notice line(s) + # Look for license line(s) if self._license_line_checks: legal_notice = '// ' + get_legal_notice_private() lnum = 0 @@ -301,7 +292,7 @@ class Updater: if self._public: raise RuntimeError('FIXME: Check for full license.') - # Look for copyright/legal-notice line(s) + # Look for copyright/legal-notice line(s). line = '// ' + get_legal_notice_private() lnum = 0 if lines[lnum] != line: From 9c02c0f54fb3d19482f011923d162378328dc19d Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 25 Sep 2020 16:46:41 -0500 Subject: [PATCH 208/417] tidying --- .efrocachemap | 24 ++++++++++++------------ .idea/dictionaries/ericf.xml | 12 ++++++------ Makefile | 3 +++ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index e5cd40b8..5596657a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/cc/e6/27f02675b9adec5bd553ac43ee03", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/9d/cd/25cfecf21ff50b3a25e5e7318dc0", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/d0/7c/87e7c5b3685a64f0a3ecd9a16b99", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", @@ -447,7 +447,7 @@ "assets/build/ba_data/data/languages/russian.json": "https://files.ballistica.net/cache/ba1/d4/bb/69c09648f60e36f35bd38be20cf8", "assets/build/ba_data/data/languages/serbian.json": "https://files.ballistica.net/cache/ba1/e7/d8/ace32888249fc8b8cca0e2edb48b", "assets/build/ba_data/data/languages/slovak.json": "https://files.ballistica.net/cache/ba1/b7/0a/fab820b96e7aa587ee56427ecdc2", - "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/b9/6b/adf28849d42f4c195dacf4f53902", + "assets/build/ba_data/data/languages/spanish.json": "https://files.ballistica.net/cache/ba1/32/0e/ac0b8dcef065d7934a6bc30d7560", "assets/build/ba_data/data/languages/swedish.json": "https://files.ballistica.net/cache/ba1/50/9f/be006ba19be6a69a57837eb6dca0", "assets/build/ba_data/data/languages/turkish.json": "https://files.ballistica.net/cache/ba1/9a/8a/f7b2521c1904ffc83262dff1e11b", "assets/build/ba_data/data/languages/ukrainian.json": "https://files.ballistica.net/cache/ba1/26/62/a072404c02c576a5c3f09059b582", @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/95/36/1850f9eda27c27700a928a220d01", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ec/51/8117cff653fd3d3e5e4f2da28cfb", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/1b/dc4328caa59881f3c7a18f4b71cd", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/16/06/ce0ff5f88a22e9fd7daae113b229", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/63/af/656a2860f87943d534fdb69386bd", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6a/fc189088a19d5b12d624e5b9521a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c5/9b/597a1666729e0a9ad347f8aab67d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ba/03/4a8dd4bb42754cdd2bbd23949f25", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/b9/782ed1cea39bc38ae635dc21f4cd", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/97/1d/9fdaf892813430d8e9b3ef6628a4" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6d/d27cadc6ba0745b031853f49fec5", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/c7/1a695160656a97fa8bc014ccfa4c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/b4/0714136fb2fe3a34f2954707e7de", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/80/50ddcc0240343e16517d9d065d18", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/f6/f5491c01ddc1c299869612928093", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/42/87a8426e9dd0d3842cd6f4dc9478", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/2c/3bc8f419c38188ad8bd3770814a0", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/12/63/73b0c2c2cac9f96e210220c9d338", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5b/e6/476c447cc5887f414b0a62e8851b", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b0/31/67ff1bb94408779ca359efcaf9c5" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 5ebd5934..5bde834d 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack'ed ack + ack'ed acked acks acnt @@ -151,8 +151,8 @@ bacommon badguy bafoundation - ballistica's ballistica + ballistica's ballisticacore ballisticacorecb bamaster @@ -793,8 +793,8 @@ gamedata gameinstance gamemap - gamepad's gamepad + gamepad's gamepadadvanced gamepads gamepadselect @@ -1177,8 +1177,8 @@ lsqlite lssl lstart - lstr's lstr + lstr's lstrs lsval ltex @@ -1800,8 +1800,8 @@ sessionname sessionplayer sessionplayers - sessionteam's sessionteam + sessionteam's sessionteams sessiontype setactivity @@ -2131,8 +2131,8 @@ txtw typeargs typecheck - typechecker's typechecker + typechecker's typedval typeshed typestr diff --git a/Makefile b/Makefile index a844f13b..a33ce896 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,9 @@ DOCPREFIX = "ballisticacore_" # # ################################################################################ +# Override this to 'localhost' to build cloud builds on a local Mac. +MAC_CLOUD_BUILD_HOST ?= homebook-fro + # List targets in this Makefile and basic descriptions for them. help: @tools/pcommand makefile_target_list Makefile From b51c57d0512b3218a6393ba985a79c6ad811fb0b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Tue, 29 Sep 2020 17:14:03 -0500 Subject: [PATCH 209/417] language updates --- .efrocachemap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 5596657a..d5245ea1 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/9d/cd/25cfecf21ff50b3a25e5e7318dc0", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/05/e9/af148b65bebed06c6574f60a6c34", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/d0/7c/87e7c5b3685a64f0a3ecd9a16b99", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", @@ -440,7 +440,7 @@ "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/9a/3d/9aff685d04d2e1cabb2f9ddafcf3", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/33/04/b1c54ce2b8979cc983aecc781228", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/e4/1a/489284781f8d24b743de3c05da1a", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/3e/cc/0da1886e43fa69a18a9ae5593648", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/88/4b/6745a1a58220772e259f0de51196", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/42/b5/7612cce15fe4555889585108b3ef", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", From 06428fec464c8d219f7860a189f16190d02574cd Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 30 Sep 2020 13:48:31 -0500 Subject: [PATCH 210/417] Initial work on c++ builds --- .efrocachemap | 16 +- ballisticacore-cmake/.idea/.gitignore | 3 + ballisticacore-cmake/.idea/.name | 1 + .../.idea/ballisticacore-cmake.iml | 2 + .../.idea/codeStyles/Project.xml | 8 + .../.idea/codeStyles/codeStyleConfig.xml | 5 + .../.idea/dictionaries/ericf.xml | 954 ++++++++++++++++++ .../inspectionProfiles/Project_Default.xml | 60 ++ ballisticacore-cmake/.idea/misc.xml | 30 + ballisticacore-cmake/.idea/modules.xml | 8 + ballisticacore-cmake/.idea/vcs.xml | 6 + ballisticacore-cmake/CMakeLists.txt | 199 ++++ ballisticacore-cmake/src | 1 + tools/batools/updateproject.py | 45 +- tools/efrotools/efrocache.py | 15 - 15 files changed, 1317 insertions(+), 36 deletions(-) create mode 100644 ballisticacore-cmake/.idea/.gitignore create mode 100644 ballisticacore-cmake/.idea/.name create mode 100644 ballisticacore-cmake/.idea/ballisticacore-cmake.iml create mode 100644 ballisticacore-cmake/.idea/codeStyles/Project.xml create mode 100644 ballisticacore-cmake/.idea/codeStyles/codeStyleConfig.xml create mode 100644 ballisticacore-cmake/.idea/dictionaries/ericf.xml create mode 100644 ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml create mode 100644 ballisticacore-cmake/.idea/misc.xml create mode 100644 ballisticacore-cmake/.idea/modules.xml create mode 100644 ballisticacore-cmake/.idea/vcs.xml create mode 100644 ballisticacore-cmake/CMakeLists.txt create mode 120000 ballisticacore-cmake/src diff --git a/.efrocachemap b/.efrocachemap index d5245ea1..4e10c4c6 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,14 +3932,14 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/3f/99/9b94f7d478142a08e02c769b64ba", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0d/f0/aed2b96addcc73e2de400aed2bdf", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6d/d27cadc6ba0745b031853f49fec5", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b0/c7/1a695160656a97fa8bc014ccfa4c", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/0b/b4/0714136fb2fe3a34f2954707e7de", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/99/80/50ddcc0240343e16517d9d065d18", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a5/f6/f5491c01ddc1c299869612928093", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fe/42/87a8426e9dd0d3842cd6f4dc9478", + "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", + "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/26/6c/76d9bd89859b444798fa5f150603", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/92/d3/dd71ceb73332e855a9e78edbae11", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e6/34/66b7c424a1481b7cff545f16f0f4", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d6/5e/9f3bb3103d0bd8e8b24f331820d4", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8c/7d/5c3af1223b81b267716d6697f3f6", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/58/7a/d60fbf3ec81b4083e75843824d63", "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/2c/3bc8f419c38188ad8bd3770814a0", "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/12/63/73b0c2c2cac9f96e210220c9d338", "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5b/e6/476c447cc5887f414b0a62e8851b", diff --git a/ballisticacore-cmake/.idea/.gitignore b/ballisticacore-cmake/.idea/.gitignore new file mode 100644 index 00000000..0e40fe8f --- /dev/null +++ b/ballisticacore-cmake/.idea/.gitignore @@ -0,0 +1,3 @@ + +# Default ignored files +/workspace.xml \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/.name b/ballisticacore-cmake/.idea/.name new file mode 100644 index 00000000..5aa978d3 --- /dev/null +++ b/ballisticacore-cmake/.idea/.name @@ -0,0 +1 @@ +BallisticaCore \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/ballisticacore-cmake.iml b/ballisticacore-cmake/.idea/ballisticacore-cmake.iml new file mode 100644 index 00000000..f08604bb --- /dev/null +++ b/ballisticacore-cmake/.idea/ballisticacore-cmake.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/codeStyles/Project.xml b/ballisticacore-cmake/.idea/codeStyles/Project.xml new file mode 100644 index 00000000..249efa28 --- /dev/null +++ b/ballisticacore-cmake/.idea/codeStyles/Project.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/codeStyles/codeStyleConfig.xml b/ballisticacore-cmake/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 00000000..79ee123c --- /dev/null +++ b/ballisticacore-cmake/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/dictionaries/ericf.xml b/ballisticacore-cmake/.idea/dictionaries/ericf.xml new file mode 100644 index 00000000..2467a179 --- /dev/null +++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml @@ -0,0 +1,954 @@ + + + + NOMINMAX + aabb + abcdefghijklmnopqrstuvwxyz + absval + accel + accountid + achs + acinstance + ack'ed + acked + acks + aclass + aclass's + activityplayer + addrs + adjoint + adminset + adreno + affx + affy + affz + aftx + afty + aftz + aint + airborn + alext + alibaba + allocs + alot + alphaimg + alphapixels + alsa + alsoft + animcurve + aniso + apientry + appconfig + appname + appnameupper + asci + assigninput + athome + attrobj + audiocache + automagically + autoselect + avel + avels + axismotion + backgrounded + backgrounding + backtraces + ballistica + ballisticacore + barebones + basetype + basicsize + bastd + bbbb + bbbbb + bbbbbb + bbbbbbb + bcfn + bezanson + bgra + bigendian + bilinear + binpow + bitcount + bitdepth + bitlength + bitmask + bitpos + bitval + blitters + blitting + blockadr + blockheight + blockwidth + bluetooth + blurscale + bname + bodyid + bodypart + bodyptr + bookmarkable + bools + boolval + boostrapping + bootconfig + bootstrappy + bouyancy + bppv + bresult + bridgit + broadcom + bsac + bscfg + bsgaps + bsgdps + bsivu + bsmhi + bsstd + bsuuid + bufs + buildconfig + buildnumber + buttondown + buttonmouse + buttonup + buttonwidget + bwst + calced + calcing + calcs + caled + callargs + callbackobj + camalign + camelback + camerashake + capitan + cargs + ccdd + ccontext + ccylinder + centiseconds + cfgdir + changeme + charn + charnum + charstr + chatmessage + checkboxwidget + chrono + cjief + classdict + clientid + clientinfo + cmath + cmds + cmdvals + codewarrior + codewarrior's + cofnodes + collapseable + collidable + collider + columnwidget + connectattr + containerwidget + controlfp + cooldown + coopscore + coreaudio + coulda + cout + cpel + cpplint + cptr + cpuid + crashenv + crashlytics + crom + crosswire + crvel + csize + cspr + cstdint + cstdlib + cstring + ctargetref + cubemap + curtime + cutef + cvar + data + datadata + dataout + datas + datav + datavec + dbias + dcol + ddcaps + ddpf + ddpixelformat + ddscaps + ddsd + ddsx + deadcode + deallocated + deallocation + deek + deinit + deltaval + demangle + demangled + demangling + denom + dernit + dets + dfba + dfff + dfmt + diffbit + dirslash + dlfcn + dlife + dllpath + dname + dncm + dobell + doneptr + doraise + dosomething + dout + downsample + dpad + dpads + drpt + dsize + dsound + dstattr + dstnode + dstpath + dstr + dtest + dummyvalid + dxgi + dynamicdata + echidna + edef + efro + elems + elevenbase + elevenbits + emitfx + emojis + enablexinput + endcall + endl + endline + endtime + entrypoint + envval + ericf + ericsson + erroring + etcdec + etcpack + evals + ewww + ewwww + ewwwww + exctype + execinfo + exhash + exhashstr + expbool + expl + extrahash + extrascale + exts + facepts + farval + fastdot + fastldlt + fastlsolve + fastltsolve + fbos + fdata + fdirx + fdiry + fdirz + fenv + fesetround + ffff + ffffff + fffffff + fffffffffifff + fgets + fifteenbits + finishedptr + fjco + fjcoiwef + flipbit + flopsy + fname + fnode + fnumc + focuswindow + fopen + fourcc + fovs + fovx + fovy + framebuffers + framedef + frameldefs + framerates + fread + freeform + freeifaddrs + freqs + froemling + frompos + frontmost + ftos + ftou + fullpath + funcname + fval + fvals + gamecenter + gamedata + gamepacket + gamepackets + gameplay + gameplayer + gapless + gasmsg + gbus + gcc's + gearvr + getactivity + getattro + getattrofunc + getbasetime + getbit + getbits + getbitshigh + getcollidemodel + getdata + getifaddrs + getinputdevice + getline + getlog + getmodel + getname + getnodes + getnodetype + getpackagecollidemodel + getpackagedata + getpackagemodel + getpackagesound + getpackagetexture + getpublicpartyenabled + getpublicpartymaxsize + getqrcodetexture + getsession + getsound + gettexture + gettotalrefcount + gles + glext + gpgs + gqualstr + grav + grisha + gstate + gthm + guiddef + gusl + gvrrts + hacky + haha + halign + handlemessage + hatmotion + haveint + havn't + havnt + healthcare + hexval + highp + highquality + hitchy + hmmm + homebrew + hostactivity + hostcmd + hostinfo + hotkeys + hotplug + hscrollwidget + htonf + htonl + htons + ibuf + icloud + iconscale + ieeefp + ifaddr + ifaddrs + ifdebug + iiarcade + iiiiisss + illum + ilock + imagewidget + incentivized + inet + inides + initguid + inittab + inputdevice + insta + intercollide + internalformat + interuptions + invote + iserverget + iserverput + isinst + isn' + isosplayingmusic + isutf + itemsize + itri + itsclass + itunes + ival + ivals + ized + jackmorgan + jacobian + janktastic + janky + jaxis + jcjwf + jmessage + keepalives + keycode + keysyms + keywds + khronos + kickable + kickee + killable + killcount + kmod + kronk + kwds + kxyz + lantinga + largeish + lasti + lastline + lastvalid + leaderboard + leaderboards + lgui + lhalf + libutf + lightshad + linearsize + listobj + llock + logmsg + logpath + logprefix + logput + logsuffix + lorient + lowp + lpos + lpsockaddr + lrintf + lscope + lstr + lsync + lvec + lvoid + macmusicappgetlibrarysource + macmusicappgetplaylists + macmusicappgetvolume + macmusicappinit + macmusicappplayplaylist + macmusicappsetvolume + macmusicappstop + macos + magoogan + magua + mainmenu + mallocs + maskhigh + maskuv + maximus + maxwidth + mediump + memalign + memchr + memcpy + meshdata + messagebox + meth + mhbegin + mhend + mikirog + millisecs + minelem + minsdl + mipmapcount + mipmaps + mmask + mmdevapi + modder + modelview + moduletype + momemtary + mqrspec + msaa + mult + multing + multipass + multisample + multitouch + multiway + musicplayerplay + musicplayersetvolume + musicplayershutdown + musicplayerstop + mutli + mybuf + mycallback + mynode + mystatspage + mywidget + ndebug + nearval + needwindow + negativex + negativey + negativez + nemanja + ness + netclient + netplay + newactivity + newchild + newimg + newitem + newname + newnode + nextchar + nitpicky + nlpos + nmemb + nodetype + nofilename + noglobs + nointhash + nominmax + noninfringement + nonlint + noone + nothin + nptr + nsize + ntoa + ntohl + numargs + numc + numentries + numlock + nvidia + nyffenegger + objexists + objid + obstack + obvs + oculus + oiffsss + oldname + oooo + ooooooo + ooooooooo + oooooooooo + oooooooooooo + ooooooooooooo + ooooooooooooooo + oooooooooooooooo + ooooooooooooooooo + oooooooooooooooooo + ooooooooooooooooooooooooooooooo + ooooooooooooooooooooooooooooooooooo + ooooooooooooooooooooooooooooooooooooo + opcode + openal + opengl + opensl + oper + opmode + opposingbody + opposingnode + optin + ortho + osis + osssssssssss + ostype + ourself + ourstanding + outval + ouya + parameteriv + passcode + pausable + pdst + persp + pflag + pflags + pgmout + pixelformat + playpause + playsound + plen + pname + podcast + podcasts + portaudio + positivex + positivey + positivez + postinit + powerup + precalc + predeclare + prefs + preloaded + preloads + premult + printf + printnodes + printobjects + priv + profilers + prog + proj + prolly + psmx + pspec + psps + psrc + pton + ptrs + ptype + pulseaudio + punchmomentumlinear + punchthrough + pushcall + putbits + putbitshigh + pval + pvrtc + pycommand + pyconfig + pycontext + pyexctype + pyhome + pylib + pyobj + pyobjs + pytype + qerr + qrcode + qrel + qrencode + qrinput + qrspec + quadtreespace + qual + qualcomm + radiusm + raii + raspbian + rasterizer + reaaaly + readset + realloc + reallocations + realtimers + recalc + recvfrom + redundants + refcounted + refl + rehel + reloadmedia + rendererdata + renormalize + rené + reprfunc + rerase + resends + resetinput + resync + retval + rezing + rgui + richcompare + rigth + rootwidget + rowwidget + rresize + rresult + rscode + rsgc + runnables + rvec + rvel + safecolor + samsung + sapspace + scancode + scenetime + screenmessage + scrollwidget + sdl's + sdlk + seqlen + serv + serverget + serverput + sessiondata + sessionglobals + sessionplayer + sessionteam + sessiontype + setactivity + setattro + setattrofunc + setdata + setname + setnode + setpublicpartyenabled + setpublicpartymaxsize + setpublicpartyname + setpublicpartystatsurl + setschedparam + setsockopt + sgis + sharedobj + shhh + shifthigh + shouldnt + shufflable + signsubscale + simd + sisssssssss + sixteenbits + smoothering + smoothstep + sndio + snorm + sockaddr + soffs + solaris + sourcenode + spaz + spead + sphrand + spivak + srcattr + srcpath + srcsz + sresult + sscanf + ssize + sssi + sssisisis + sssissss + ssss + sssss + sssssi + sssssss + sssssssd + sssssssi + ssssssssssss + standin + startedptr + startpos + starttime + startx + starty + staticdata + stdint + stepfast + stephane + stepnum + stepsize + strcasecmp + strchr + strcpy + strdup + stringi + strlen + strtof + subclsssing + subentities + subitems + subplatform + subscale + subscr + sval + symbolification + syscalls + talloc + tegra + telefonaktiebolaget + teleported + teleporting + tempvec + testint + testnode + texel + texqualstr + textcolor + textwidget + thang + thecommand + theres + threadname + threadtype + tiltage + timedisplay + timeformat + timerlist + timestep + timetype + timetypes + tmpmat + tomer + topos + touchpad + toucs + toutf + tracebacks + tracestr + trackpad + trackpads + tradeoff + trailcolor + transobj + treturn + trifunovic + trilinear + trimesh + trimeshes + tval + tvos + tweakage + twotimer + twst + typeobj + typestr + uber + uibounds + uiid + unblessed + uncas + unchecking + underrun + unformatted + unichar + unichars + uninited + unmanaged + unpaused + unplayed + unpremultiply + unsignaled + unstuff + unsynchronized + userspace + uther + uuids + uxxxx + uxxxxxxxx + valign + valobj + vals + valtab + valuedouble + valueint + valuestring + varyings + vbos + vbuf + vcache + vdynamic + vertout + verts + vidia + vmag + vorbis + vorbisfile + vparallel + vprintf + vsync + vsyncing + vtable + vtangential + vulkan + waaah + wack + wakeups + walisser + wasdebug + watte + wdeprecated + weakref + weakthis + welp + whaaaaaaa + wheee + wheeee + wiimote + wiimotes + windowshade + winmm + winsock + wofocj + wonkiness + worldspace + wunused + xclamped + xdiff + xdist + xinput + xmax + xmin + xmmintrin + xoffset + yclamped + ydiff + ydist + ymax + ymin + yoffs + yooooooo + zmax + zmin + zoffset + zomg + zoomable + zrot + + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml b/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..4db46f7f --- /dev/null +++ b/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,60 @@ + + + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/misc.xml b/ballisticacore-cmake/.idea/misc.xml new file mode 100644 index 00000000..acadce39 --- /dev/null +++ b/ballisticacore-cmake/.idea/misc.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/modules.xml b/ballisticacore-cmake/.idea/modules.xml new file mode 100644 index 00000000..5fb34ea8 --- /dev/null +++ b/ballisticacore-cmake/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/vcs.xml b/ballisticacore-cmake/.idea/vcs.xml new file mode 100644 index 00000000..6c0b8635 --- /dev/null +++ b/ballisticacore-cmake/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ballisticacore-cmake/CMakeLists.txt b/ballisticacore-cmake/CMakeLists.txt new file mode 100644 index 00000000..888fee8c --- /dev/null +++ b/ballisticacore-cmake/CMakeLists.txt @@ -0,0 +1,199 @@ +cmake_minimum_required(VERSION 3.12) +project(BallisticaCore) +include(CheckIncludeFile) + +option(HEADLESS "build headless server" OFF) +option(TEST_BUILD "include testing features" OFF) + +# Requiring minimum of C++17 currently. +set(CMAKE_CXX_STANDARD 17) + +if (APPLE) + # Seems as of Mojave we need to explicitly pull in /usr/local stuff. + include_directories("/usr/local/include") + link_directories("/usr/local/lib") + + # On Mac with homebrew it seems that Requesting 3.7 when we've got + # 3.8 installed will point us at the 3.8 framework but will attempt + # to load a 3.7 library from within it which doesn't exist. So we need + # to be a bit more explicit telling it where to look. This is no longer + # necessary since we're using 3.8 now but may be once 3.9 becomes available + # through homebrew. + execute_process(COMMAND "python3.8-config" "--prefix" + OUTPUT_VARIABLE Python_ROOT_DIR + OUTPUT_STRIP_TRAILING_WHITESPACE) + +endif () +find_package (Python 3.8 REQUIRED EXACT COMPONENTS Development) + + +if (HEADLESS) + add_definitions(-DBA_HEADLESS_BUILD=1) + else () + find_package(SDL2 QUIET) + if (SDL2_FOUND) + # Getting complaint about space at the end of this on ubuntu16. + string(STRIP ${SDL2_LIBRARIES} SDL2_LIBRARIES) + else () + message(FATAL_ERROR "SDL2 not found") + endif () + find_package(OpenGL REQUIRED) + find_package(OpenAL REQUIRED) + if (APPLE) + # On mac this sets an include path that we don't need since + # we're using the system framework... should clean this up. + set(OPENAL_INCLUDE_DIR "") + endif () + find_library(OGG_LIBRARY ogg) + find_library(VORBISFILE_LIBRARY vorbisfile) + if (NOT OGG_LIBRARY) + message(FATAL_ERROR "ogg library not found") + endif () + if (NOT VORBISFILE_LIBRARY) + message(FATAL_ERROR "vorbisfile library not found") + endif () + set(EXTRA_INCLUDE_DIRS ${OPENGL_INCLUDE_DIRS} + ${OPENAL_INCLUDE_DIR} ${SDL2_INCLUDE_DIRS}) + set(EXTRA_LIBRARIES ogg vorbisfile ${OPENGL_LIBRARIES} ${OPENAL_LIBRARY}) +endif () + +if (TEST_BUILD) + add_definitions(-DBA_TEST_BUILD=1) +endif () + +# Currently seeing warnings about parameter order changing in GCC 7.1 +# on Raspberry Pi builds. We never need to care about C++ abi compatibility +# so just silencing them for now. Can maybe remove this later if they stop. +if (CMAKE_COMPILER_IS_GNUCXX) + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -Wno-psabi") +endif() + +# message("GOT SDL INC ${SDL2_INCLUDE_DIRS}") +# message(FATAL_ERROR "SO FAR SO GOOD") + +set(BA_SRC_ROOT src) +include_directories(${BA_SRC_ROOT}) +add_compile_options(-include ballistica/config/config_cmake.h) + +if (CMAKE_BUILD_TYPE MATCHES Debug) + add_definitions(-DBA_DEBUG_BUILD=1) +endif () + +set(ODE_SRC_ROOT ${BA_SRC_ROOT}/external/open_dynamics_engine-ef) + +add_library(ode + ${ODE_SRC_ROOT}/ode/IceAABB.cpp + ${ODE_SRC_ROOT}/ode/IceContainer.cpp + ${ODE_SRC_ROOT}/ode/IceHPoint.cpp + ${ODE_SRC_ROOT}/ode/IceIndexedTriangle.cpp + ${ODE_SRC_ROOT}/ode/IceMatrix3x3.cpp + ${ODE_SRC_ROOT}/ode/IceMatrix4x4.cpp + ${ODE_SRC_ROOT}/ode/IceOBB.cpp + ${ODE_SRC_ROOT}/ode/IcePlane.cpp + ${ODE_SRC_ROOT}/ode/IcePoint.cpp + ${ODE_SRC_ROOT}/ode/IceRandom.cpp + ${ODE_SRC_ROOT}/ode/IceRay.cpp + ${ODE_SRC_ROOT}/ode/IceRevisitedRadix.cpp + ${ODE_SRC_ROOT}/ode/IceSegment.cpp + ${ODE_SRC_ROOT}/ode/IceTriangle.cpp + ${ODE_SRC_ROOT}/ode/IceUtils.cpp + ${ODE_SRC_ROOT}/ode/ode.cpp + ${ODE_SRC_ROOT}/ode/ode_array.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_cylinder_box.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_cylinder_plane.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_cylinder_sphere.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_cylinder_trimesh.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_kernel.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_quadtreespace.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_sapspace.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_space.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_std.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_transform.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_box.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_ccylinder.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_distance.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_plane.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_ray.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_sphere.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_trimesh_trimesh.cpp + ${ODE_SRC_ROOT}/ode/ode_collision_util.cpp + ${ODE_SRC_ROOT}/ode/ode_error.cpp + ${ODE_SRC_ROOT}/ode/ode_export-diff.cpp + ${ODE_SRC_ROOT}/ode/ode_fastdot.cpp + ${ODE_SRC_ROOT}/ode/ode_fastldlt.cpp + ${ODE_SRC_ROOT}/ode/ode_fastlsolve.cpp + ${ODE_SRC_ROOT}/ode/ode_fastltsolve.cpp + ${ODE_SRC_ROOT}/ode/ode_joint.cpp + ${ODE_SRC_ROOT}/ode/ode_lcp.cpp + ${ODE_SRC_ROOT}/ode/ode_mass.cpp + ${ODE_SRC_ROOT}/ode/ode_mat.cpp + ${ODE_SRC_ROOT}/ode/ode_math.cpp + ${ODE_SRC_ROOT}/ode/ode_matrix.cpp + ${ODE_SRC_ROOT}/ode/ode_memory.cpp + ${ODE_SRC_ROOT}/ode/ode_misc.cpp + ${ODE_SRC_ROOT}/ode/ode_obstack.cpp + ${ODE_SRC_ROOT}/ode/ode_quickstep.cpp + ${ODE_SRC_ROOT}/ode/ode_rotation.cpp + ${ODE_SRC_ROOT}/ode/ode_step.cpp + ${ODE_SRC_ROOT}/ode/ode_stepfast.cpp + ${ODE_SRC_ROOT}/ode/ode_timer.cpp + ${ODE_SRC_ROOT}/ode/ode_util.cpp + ${ODE_SRC_ROOT}/ode/OPC_AABBCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_AABBTree.cpp + ${ODE_SRC_ROOT}/ode/OPC_BaseModel.cpp + ${ODE_SRC_ROOT}/ode/OPC_BoxPruning.cpp + ${ODE_SRC_ROOT}/ode/OPC_Collider.cpp + ${ODE_SRC_ROOT}/ode/OPC_HybridModel.cpp + ${ODE_SRC_ROOT}/ode/OPC_LSSCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_MeshInterface.cpp + ${ODE_SRC_ROOT}/ode/OPC_Model.cpp + ${ODE_SRC_ROOT}/ode/OPC_OBBCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_OptimizedTree.cpp + ${ODE_SRC_ROOT}/ode/OPC_PlanesCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_RayCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_SphereCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_SweepAndPrune.cpp + ${ODE_SRC_ROOT}/ode/OPC_TreeBuilders.cpp + ${ODE_SRC_ROOT}/ode/OPC_TreeCollider.cpp + ${ODE_SRC_ROOT}/ode/OPC_VolumeCollider.cpp + ${ODE_SRC_ROOT}/ode/Opcode.cpp + ) +target_include_directories(ode PRIVATE ${ODE_SRC_ROOT}) + +# EWWW; GCC gives us bad mesh collisions with -O3 (and maybe -O2) +# need to finally get to the bottom of this but limiting to -01 for now. +# (-O2 might be safe??... or what about -Os? Should test again.) +if (CMAKE_BUILD_TYPE MATCHES Release) + target_compile_options(ode PRIVATE -O1) +endif () + +# BallisticaCore binary. +add_executable(ballisticacore + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/bitstream.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/mask.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/mmask.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/mqrspec.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/qrencode.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/qrinput.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/qrspec.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/rscode.c + ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/split.c + # AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool) + ${BA_SRC_ROOT}/ballistica/app/app.cc + # AUTOGENERATED_PUBLIC_END + ) + +target_include_directories(ballisticacore PRIVATE + ${Python_INCLUDE_DIRS} + ${BA_SRC_ROOT}/external/open_dynamics_engine-ef + ${BA_SRC_ROOT}/external/qrencode-3.4.4 + ${EXTRA_INCLUDE_DIRS} + ) + +# NOTE: seems we need to add 'dl' here for raspberry pi with manually +# built Python 3.8. Might be able to remove later. +target_link_libraries(ballisticacore PRIVATE + ballisticacore_private ode pthread ${Python_LIBRARIES} + ${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl) diff --git a/ballisticacore-cmake/src b/ballisticacore-cmake/src new file mode 120000 index 00000000..5cd551cf --- /dev/null +++ b/ballisticacore-cmake/src @@ -0,0 +1 @@ +../src \ No newline at end of file diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index eb4907ca..6ac8a2c1 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -145,6 +145,10 @@ class Updater: sys.exit(255) def _update_compile_commands_file(self) -> None: + # Only do this in private repo: + if self._public: + return + # Update our local compile-commands file based on any changes to # our cmake stuff. Do this at end so cmake changes already happened. if not self._check and os.path.exists('ballisticacore-cmake'): @@ -543,28 +547,43 @@ class Updater: if os.path.exists(fname): self._update_visual_studio_project(fname, '..\\..\\src') - def _update_cmake_file(self, fname: str) -> None: + def _is_public_source_file(self, filename: str) -> bool: + if filename == '/app/app.cc': + return True + return False + def _update_cmake_file(self, fname: str) -> None: with open(fname) as infile: lines = infile.read().splitlines() - auto_start = lines.index(' #AUTOGENERATED_BEGIN (this section' - ' is managed by the "update_project" tool)') - auto_end = lines.index(' #AUTOGENERATED_END') - our_lines = [ - ' ${BA_SRC_ROOT}/ballistica' + f - for f in sorted(self._source_files + self._header_files) - if not f.endswith('.mm') and not f.endswith('.m') - ] - filtered = lines[:auto_start + 1] + our_lines + lines[auto_end:] - self._file_changes[fname] = '\n'.join(filtered) + '\n' + + for section in ['PUBLIC', 'PRIVATE']: + # Public repo has no private section. + if self._public and section == 'PRIVATE': + continue + + auto_start = lines.index( + f' # AUTOGENERATED_{section}_BEGIN (this section' + f' is managed by the "update_project" tool)') + auto_end = lines.index(f' # AUTOGENERATED_{section}_END') + our_lines = [ + ' ${BA_SRC_ROOT}/ballistica' + f + for f in sorted(self._source_files + self._header_files) + if not f.endswith('.mm') and not f.endswith('.m') + and self._is_public_source_file(f) == (section == 'PUBLIC') + ] + lines = lines[:auto_start + 1] + our_lines + lines[auto_end:] + + self._file_changes[fname] = '\n'.join(lines) + '\n' def _update_cmake_files(self) -> None: + # Note: currently not updating cmake files at all in public builds; + # will need to get this working at some point... fname = 'ballisticacore-cmake/CMakeLists.txt' - if os.path.exists(fname): + if not self._public: self._update_cmake_file(fname) fname = ('ballisticacore-android/BallisticaCore' '/src/main/cpp/CMakeLists.txt') - if os.path.exists(fname): + if not self._public: self._update_cmake_file(fname) def _find_sources_and_headers(self, scan_dir: str) -> None: diff --git a/tools/efrotools/efrocache.py b/tools/efrotools/efrocache.py index 7b3a5296..01c4c404 100644 --- a/tools/efrotools/efrocache.py +++ b/tools/efrotools/efrocache.py @@ -25,8 +25,6 @@ if TYPE_CHECKING: BASE_URL = 'https://files.ballistica.net/cache/ba1/' TARGET_TAG = '#__EFROCACHE_TARGET__' -STRIP_BEGIN_TAG = '#__EFROCACHE_STRIP_BEGIN__' -STRIP_END_TAG = '#__EFROCACHE_STRIP_END__' CACHE_DIR_NAME = '.efrocache' CACHE_MAP_NAME = '.efrocachemap' @@ -142,19 +140,6 @@ def filter_makefile(makefile_dir: str, contents: str) -> str: lines = contents.splitlines() pcommand = 'tools/pcommand' - # Strip out parts they don't want. - while STRIP_BEGIN_TAG in lines: - index = lines.index(STRIP_BEGIN_TAG) - endindex = index - while lines[endindex] != STRIP_END_TAG: - endindex += 1 - - # If the line after us is blank, include it too to keep spacing clean. - if not lines[endindex + 1].strip(): - endindex += 1 - - del lines[index:endindex + 1] - # Replace cachable targets with cache lookups while TARGET_TAG in lines: index = lines.index(TARGET_TAG) From f28cf8c9acd5a752b5b9b6b5adaca5066e8146d8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Wed, 30 Sep 2020 17:33:18 -0500 Subject: [PATCH 211/417] More C++ layer prepping --- .efrocachemap | 20 ++++++++++---------- CHANGELOG.md | 3 ++- ballisticacore-cmake/CMakeLists.txt | 11 +---------- docs/ba_module.md | 2 +- 4 files changed, 14 insertions(+), 22 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 4e10c4c6..5d4fda8f 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/26/6c/76d9bd89859b444798fa5f150603", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/92/d3/dd71ceb73332e855a9e78edbae11", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e6/34/66b7c424a1481b7cff545f16f0f4", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d6/5e/9f3bb3103d0bd8e8b24f331820d4", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/8c/7d/5c3af1223b81b267716d6697f3f6", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/58/7a/d60fbf3ec81b4083e75843824d63", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/30/2c/3bc8f419c38188ad8bd3770814a0", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/12/63/73b0c2c2cac9f96e210220c9d338", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/5b/e6/476c447cc5887f414b0a62e8851b", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b0/31/67ff1bb94408779ca359efcaf9c5" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/72/55/dfa285b98b91dcf3b9a4959b2de7", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/93/f4/e4f6f62cf48e2b945a2e129debc2", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/37/a3cf70e0fcddeedded8a59ea83a1", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/27/d1b008386dab949c7a56e7d91f1f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/52/eb/cd526a92072fc57ceff9ead7be4c", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9d/6f/bdba4c9916b076076608e5c1b10a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1d/4e/1fefad2610732934ec9afacf15e4", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/74/81/60b8c9b55342697d3708827c2fb5", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/75/b7/d1c41081caeefeb6d367ea27d591", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9a/b6/4f2271173853f4e260c3d50488e6" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 11717dfc..23814529 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.5.26 (20178) -- Simplified licensing header on python scripts.. +- Simplified licensing header on python scripts. +- Project rework in prep for open-sourcing parts of c++ layer. ### 1.5.25 (20176) - Added Venetian language (thanks Federico!) diff --git a/ballisticacore-cmake/CMakeLists.txt b/ballisticacore-cmake/CMakeLists.txt index 888fee8c..81fd98a8 100644 --- a/ballisticacore-cmake/CMakeLists.txt +++ b/ballisticacore-cmake/CMakeLists.txt @@ -171,15 +171,7 @@ endif () # BallisticaCore binary. add_executable(ballisticacore - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/bitstream.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/mask.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/mmask.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/mqrspec.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/qrencode.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/qrinput.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/qrspec.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/rscode.c - ${BA_SRC_ROOT}/external/qrencode-3.4.4/qrencode/split.c + ${BA_SRC_ROOT}/external/qr_code_generator/QrCode.cpp # AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool) ${BA_SRC_ROOT}/ballistica/app/app.cc # AUTOGENERATED_PUBLIC_END @@ -188,7 +180,6 @@ add_executable(ballisticacore target_include_directories(ballisticacore PRIVATE ${Python_INCLUDE_DIRS} ${BA_SRC_ROOT}/external/open_dynamics_engine-ef - ${BA_SRC_ROOT}/external/qrencode-3.4.4 ${EXTRA_INCLUDE_DIRS} ) diff --git a/docs/ba_module.md b/docs/ba_module.md index ff4e81d9..a98f543a 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-09-17 for Ballistica version 1.5.26 build 20188

    +

    last updated on 2020-09-30 for Ballistica version 1.5.26 build 20190

    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!


    From 436d3f7f0f04c95eed8f3ad71d6d5985f4a1943c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 11:35:23 -0500 Subject: [PATCH 212/417] Adding some C++ external dependency code --- .../inspectionProfiles/Project_Default.xml | 2 + src/external/httprequest/httprequest.hpp | 689 ++++ .../open_dynamics_engine-ef/ode/IceAABB.cpp | 413 +++ .../open_dynamics_engine-ef/ode/IceAABB.h | 505 +++ .../open_dynamics_engine-ef/ode/IceAxes.h | 60 + .../ode/IceBoundingSphere.h | 142 + .../ode/IceContainer.cpp | 352 ++ .../ode/IceContainer.h | 212 ++ .../open_dynamics_engine-ef/ode/IceFPU.h | 337 ++ .../open_dynamics_engine-ef/ode/IceHPoint.cpp | 77 + .../open_dynamics_engine-ef/ode/IceHPoint.h | 161 + .../ode/IceIndexedTriangle.cpp | 556 +++ .../ode/IceIndexedTriangle.h | 72 + .../open_dynamics_engine-ef/ode/IceLSS.h | 75 + .../ode/IceMatrix3x3.cpp | 56 + .../ode/IceMatrix3x3.h | 496 +++ .../ode/IceMatrix4x4.cpp | 142 + .../ode/IceMatrix4x4.h | 455 +++ .../ode/IceMemoryMacros.h | 109 + .../open_dynamics_engine-ef/ode/IceOBB.cpp | 333 ++ .../open_dynamics_engine-ef/ode/IceOBB.h | 177 + .../open_dynamics_engine-ef/ode/IcePairs.h | 45 + .../open_dynamics_engine-ef/ode/IcePlane.cpp | 53 + .../open_dynamics_engine-ef/ode/IcePlane.h | 113 + .../open_dynamics_engine-ef/ode/IcePoint.cpp | 201 + .../open_dynamics_engine-ef/ode/IcePoint.h | 528 +++ .../ode/IcePreprocessor.h | 132 + .../open_dynamics_engine-ef/ode/IceRandom.cpp | 42 + .../open_dynamics_engine-ef/ode/IceRandom.h | 42 + .../open_dynamics_engine-ef/ode/IceRay.cpp | 92 + .../open_dynamics_engine-ef/ode/IceRay.h | 98 + .../ode/IceRevisitedRadix.cpp | 528 +++ .../ode/IceRevisitedRadix.h | 65 + .../ode/IceSegment.cpp | 65 + .../open_dynamics_engine-ef/ode/IceSegment.h | 55 + .../open_dynamics_engine-ef/ode/IceTriList.h | 61 + .../ode/IceTriangle.cpp | 295 ++ .../open_dynamics_engine-ef/ode/IceTriangle.h | 68 + .../open_dynamics_engine-ef/ode/IceTypes.h | 171 + .../open_dynamics_engine-ef/ode/IceUtils.cpp | 46 + .../open_dynamics_engine-ef/ode/IceUtils.h | 257 ++ .../ode/LICENSE_BSD.TXT | 34 + .../ode/OPC_AABBCollider.cpp | 706 ++++ .../ode/OPC_AABBCollider.h | 101 + .../ode/OPC_AABBTree.cpp | 581 +++ .../ode/OPC_AABBTree.h | 137 + .../ode/OPC_BaseModel.cpp | 146 + .../ode/OPC_BaseModel.h | 175 + .../ode/OPC_BoxBoxOverlap.h | 122 + .../ode/OPC_BoxPruning.cpp | 375 ++ .../ode/OPC_BoxPruning.h | 31 + .../ode/OPC_Collider.cpp | 62 + .../ode/OPC_Collider.h | 180 + .../ode/OPC_Common.cpp | 52 + .../open_dynamics_engine-ef/ode/OPC_Common.h | 101 + .../ode/OPC_HybridModel.cpp | 471 +++ .../ode/OPC_HybridModel.h | 106 + .../open_dynamics_engine-ef/ode/OPC_IceHook.h | 70 + .../ode/OPC_LSSAABBOverlap.h | 523 +++ .../ode/OPC_LSSCollider.cpp | 737 ++++ .../ode/OPC_LSSCollider.h | 103 + .../ode/OPC_LSSTriOverlap.h | 679 ++++ .../ode/OPC_MeshInterface.cpp | 316 ++ .../ode/OPC_MeshInterface.h | 205 ++ .../open_dynamics_engine-ef/ode/OPC_Model.cpp | 230 ++ .../open_dynamics_engine-ef/ode/OPC_Model.h | 65 + .../ode/OPC_OBBCollider.cpp | 779 ++++ .../ode/OPC_OBBCollider.h | 146 + .../ode/OPC_OptimizedTree.cpp | 798 ++++ .../ode/OPC_OptimizedTree.h | 209 ++ .../ode/OPC_Picking.cpp | 190 + .../open_dynamics_engine-ef/ode/OPC_Picking.h | 45 + .../ode/OPC_PlanesAABBOverlap.h | 50 + .../ode/OPC_PlanesCollider.cpp | 665 ++++ .../ode/OPC_PlanesCollider.h | 127 + .../ode/OPC_PlanesTriOverlap.h | 40 + .../ode/OPC_RayAABBOverlap.h | 63 + .../ode/OPC_RayCollider.cpp | 777 ++++ .../ode/OPC_RayCollider.h | 227 ++ .../ode/OPC_RayTriOverlap.h | 89 + .../ode/OPC_Settings.h | 49 + .../ode/OPC_SphereAABBOverlap.h | 128 + .../ode/OPC_SphereCollider.cpp | 738 ++++ .../ode/OPC_SphereCollider.h | 100 + .../ode/OPC_SphereTriOverlap.h | 187 + .../ode/OPC_Stdafx.cpp | 14 + .../open_dynamics_engine-ef/ode/OPC_Stdafx.h | 24 + .../ode/OPC_SweepAndPrune.cpp | 672 ++++ .../ode/OPC_SweepAndPrune.h | 86 + .../ode/OPC_TreeBuilders.cpp | 269 ++ .../ode/OPC_TreeBuilders.h | 183 + .../ode/OPC_TreeCollider.cpp | 951 +++++ .../ode/OPC_TreeCollider.h | 252 ++ .../ode/OPC_TriBoxOverlap.h | 339 ++ .../ode/OPC_TriTriOverlap.h | 279 ++ .../ode/OPC_VolumeCollider.cpp | 111 + .../ode/OPC_VolumeCollider.h | 138 + .../open_dynamics_engine-ef/ode/Opcode.cpp | 73 + .../open_dynamics_engine-ef/ode/ode.cpp | 1827 ++++++++++ .../open_dynamics_engine-ef/ode/ode.h | 47 + .../open_dynamics_engine-ef/ode/ode_Opcode.h | 113 + .../open_dynamics_engine-ef/ode/ode_array.cpp | 80 + .../open_dynamics_engine-ef/ode/ode_array.h | 135 + .../ode/ode_collision.h | 197 + .../ode/ode_collision_cylinder_box.cpp | 994 +++++ .../ode/ode_collision_cylinder_plane.cpp | 180 + .../ode/ode_collision_cylinder_sphere.cpp | 580 +++ .../ode/ode_collision_cylinder_trimesh.cpp | 1041 ++++++ .../ode/ode_collision_kernel.cpp | 653 ++++ .../ode/ode_collision_kernel.h | 202 + .../ode/ode_collision_quadtreespace.cpp | 583 +++ .../ode/ode_collision_sapspace.cpp | 487 +++ .../ode/ode_collision_space.cpp | 970 +++++ .../ode/ode_collision_space.h | 76 + .../ode/ode_collision_space_internal.h | 86 + .../ode/ode_collision_std.cpp | 2081 +++++++++++ .../ode/ode_collision_std.h | 79 + .../ode/ode_collision_transform.cpp | 235 ++ .../ode/ode_collision_transform.h | 40 + .../ode/ode_collision_trimesh.cpp | 547 +++ .../ode/ode_collision_trimesh.h | 191 + .../ode/ode_collision_trimesh_box.cpp | 1349 +++++++ .../ode/ode_collision_trimesh_ccylinder.cpp | 1005 +++++ .../ode/ode_collision_trimesh_distance.cpp | 1264 +++++++ .../ode/ode_collision_trimesh_internal.h | 364 ++ .../ode/ode_collision_trimesh_plane.cpp | 129 + .../ode/ode_collision_trimesh_ray.cpp | 134 + .../ode/ode_collision_trimesh_sphere.cpp | 502 +++ .../ode/ode_collision_trimesh_trimesh.cpp | 2162 +++++++++++ .../ode/ode_collision_util.cpp | 596 +++ .../ode/ode_collision_util.h | 344 ++ .../open_dynamics_engine-ef/ode/ode_common.h | 357 ++ .../ode/ode_compatibility.h | 40 + .../open_dynamics_engine-ef/ode/ode_config.h | 77 + .../open_dynamics_engine-ef/ode/ode_contact.h | 91 + .../ode/ode_drawstuff.h | 164 + .../ode/ode_drawstuff_version.h | 29 + .../open_dynamics_engine-ef/ode/ode_error.cpp | 175 + .../open_dynamics_engine-ef/ode/ode_error.h | 63 + .../ode/ode_export-dif.h | 32 + .../ode/ode_export-diff.cpp | 533 +++ .../ode/ode_fastdot.cpp | 30 + .../ode/ode_fastldlt.cpp | 383 ++ .../ode/ode_fastlsolve.cpp | 298 ++ .../ode/ode_fastltsolve.cpp | 199 + .../open_dynamics_engine-ef/ode/ode_joint.cpp | 3247 +++++++++++++++++ .../open_dynamics_engine-ef/ode/ode_joint.h | 295 ++ .../open_dynamics_engine-ef/ode/ode_lcp.cpp | 2020 ++++++++++ .../open_dynamics_engine-ef/ode/ode_lcp.h | 58 + .../open_dynamics_engine-ef/ode/ode_mass.cpp | 313 ++ .../open_dynamics_engine-ef/ode/ode_mass.h | 107 + .../open_dynamics_engine-ef/ode/ode_mat.cpp | 230 ++ .../open_dynamics_engine-ef/ode/ode_mat.h | 71 + .../open_dynamics_engine-ef/ode/ode_math.cpp | 165 + .../open_dynamics_engine-ef/ode/ode_math.h | 258 ++ .../ode/ode_matrix.cpp | 358 ++ .../open_dynamics_engine-ef/ode/ode_matrix.h | 194 + .../ode/ode_memory.cpp | 87 + .../open_dynamics_engine-ef/ode/ode_memory.h | 59 + .../open_dynamics_engine-ef/ode/ode_misc.cpp | 147 + .../open_dynamics_engine-ef/ode/ode_misc.h | 85 + .../open_dynamics_engine-ef/ode/ode_objects.h | 284 ++ .../ode/ode_objects_private.h | 125 + .../ode/ode_obstack.cpp | 138 + .../open_dynamics_engine-ef/ode/ode_obstack.h | 68 + .../ode/ode_quickstep.cpp | 1040 ++++++ .../ode/ode_quickstep.h | 33 + .../ode/ode_rotation.cpp | 304 ++ .../ode/ode_rotation.h | 70 + .../open_dynamics_engine-ef/ode/ode_step.cpp | 1786 +++++++++ .../open_dynamics_engine-ef/ode/ode_step.h | 36 + .../ode/ode_stepfast.cpp | 1136 ++++++ .../open_dynamics_engine-ef/ode/ode_timer.cpp | 427 +++ .../open_dynamics_engine-ef/ode/ode_timer.h | 76 + .../open_dynamics_engine-ef/ode/ode_util.cpp | 285 ++ .../open_dynamics_engine-ef/ode/ode_util.h | 56 + .../open_dynamics_engine-ef/ode/odecpp.h | 621 ++++ .../ode/odecpp_collision.h | 346 ++ src/external/qr_code_generator/QrCode.cpp | 862 +++++ src/external/qr_code_generator/QrCode.hpp | 556 +++ 180 files changed, 61171 insertions(+) create mode 100644 src/external/httprequest/httprequest.hpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceAABB.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceAABB.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceAxes.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceBoundingSphere.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceContainer.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceContainer.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceFPU.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceHPoint.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceHPoint.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceLSS.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceMemoryMacros.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceOBB.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceOBB.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IcePairs.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IcePlane.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IcePlane.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IcePoint.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IcePoint.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IcePreprocessor.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceRandom.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceRandom.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceRay.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceRay.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceRevisitedRadix.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceRevisitedRadix.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceSegment.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceSegment.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceTriList.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceTriangle.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceTriangle.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceTypes.h create mode 100644 src/external/open_dynamics_engine-ef/ode/IceUtils.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/IceUtils.h create mode 100644 src/external/open_dynamics_engine-ef/ode/LICENSE_BSD.TXT create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_BoxBoxOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Collider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Collider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Common.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Common.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_HybridModel.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_HybridModel.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_IceHook.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_LSSAABBOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_LSSCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_LSSCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_LSSTriOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_MeshInterface.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_MeshInterface.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Model.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Model.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Picking.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Picking.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_PlanesAABBOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_PlanesCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_PlanesCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_PlanesTriOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_RayAABBOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_RayTriOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Settings.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_SphereAABBOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_SphereTriOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_TreeBuilders.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_TreeBuilders.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_TreeCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_TreeCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_TriBoxOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_TriTriOverlap.h create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_VolumeCollider.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/OPC_VolumeCollider.h create mode 100644 src/external/open_dynamics_engine-ef/ode/Opcode.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_Opcode.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_array.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_array.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_box.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_plane.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_sphere.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_trimesh.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_quadtreespace.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_sapspace.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_space.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_space.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_space_internal.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_std.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_std.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_transform.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_transform.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_box.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ccylinder.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_distance.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_internal.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_plane.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ray.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_sphere.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_trimesh.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_util.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_collision_util.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_common.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_compatibility.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_config.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_contact.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_drawstuff.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_drawstuff_version.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_error.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_error.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_export-dif.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_export-diff.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_fastdot.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_fastldlt.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_fastlsolve.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_fastltsolve.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_joint.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_joint.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_lcp.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_lcp.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_mass.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_mass.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_mat.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_mat.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_math.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_math.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_matrix.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_matrix.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_memory.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_memory.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_misc.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_misc.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_objects.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_objects_private.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_obstack.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_obstack.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_quickstep.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_quickstep.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_rotation.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_rotation.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_step.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_step.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_stepfast.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_timer.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_timer.h create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_util.cpp create mode 100644 src/external/open_dynamics_engine-ef/ode/ode_util.h create mode 100644 src/external/open_dynamics_engine-ef/ode/odecpp.h create mode 100644 src/external/open_dynamics_engine-ef/ode/odecpp_collision.h create mode 100644 src/external/qr_code_generator/QrCode.cpp create mode 100644 src/external/qr_code_generator/QrCode.hpp diff --git a/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml b/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml index 4db46f7f..26034b2d 100644 --- a/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml +++ b/ballisticacore-cmake/.idea/inspectionProfiles/Project_Default.xml @@ -6,6 +6,7 @@ + @@ -51,6 +52,7 @@ + diff --git a/src/external/httprequest/httprequest.hpp b/src/external/httprequest/httprequest.hpp new file mode 100644 index 00000000..11869512 --- /dev/null +++ b/src/external/httprequest/httprequest.hpp @@ -0,0 +1,689 @@ +// +// https://github.com/elnormous/HTTPRequest +// + +#ifndef HTTPREQUEST_HPP +#define HTTPREQUEST_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef _WIN32 +# pragma push_macro("WIN32_LEAN_AND_MEAN") +# pragma push_macro("NOMINMAX") +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include +# if _WIN32_WINNT < _WIN32_WINNT_WINXP +char* strdup(const char* src) +{ + std::size_t length = 0; + while (src[length]) ++length; + char* result = static_cast(malloc(length + 1)); + char* p = result; + while (*src) *p++ = *src++; + *p = '\0'; + return result; +} +# include +# endif +# include +# pragma pop_macro("WIN32_LEAN_AND_MEAN") +# pragma pop_macro("NOMINMAX") +#else +# include +# include +# include +# include +# include +#endif + +namespace http +{ + class RequestError final: public std::logic_error + { + public: + explicit RequestError(const char* str): std::logic_error(str) {} + explicit RequestError(const std::string& str): std::logic_error(str) {} + }; + + class ResponseError final: public std::runtime_error + { + public: + explicit ResponseError(const char* str): std::runtime_error(str) {} + explicit ResponseError(const std::string& str): std::runtime_error(str) {} + }; + + enum class InternetProtocol: std::uint8_t + { + V4, + V6 + }; + + inline namespace detail + { +#ifdef _WIN32 + class WinSock final + { + public: + WinSock() + { + WSADATA wsaData; + const auto error = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (error != 0) + throw std::system_error(error, std::system_category(), "WSAStartup failed"); + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) + { + WSACleanup(); + throw std::runtime_error("Invalid WinSock version"); + } + + started = true; + } + + ~WinSock() + { + if (started) WSACleanup(); + } + + WinSock(WinSock&& other) noexcept: + started(other.started) + { + other.started = false; + } + + WinSock& operator=(WinSock&& other) noexcept + { + if (&other == this) return *this; + if (started) WSACleanup(); + started = other.started; + other.started = false; + return *this; + } + + private: + bool started = false; + }; +#endif + + inline int getLastError() noexcept + { +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif + } + + constexpr int getAddressFamily(InternetProtocol internetProtocol) + { + return (internetProtocol == InternetProtocol::V4) ? AF_INET : + (internetProtocol == InternetProtocol::V6) ? AF_INET6 : + throw RequestError("Unsupported protocol"); + } + +#ifdef _WIN32 + constexpr auto closeSocket = closesocket; +#else + constexpr auto closeSocket = close; +#endif + +#if defined(__APPLE__) || defined(_WIN32) + constexpr int noSignal = 0; +#else + constexpr int noSignal = MSG_NOSIGNAL; +#endif + + class Socket final + { + public: +#ifdef _WIN32 + using Type = SOCKET; + static constexpr Type invalid = INVALID_SOCKET; +#else + using Type = int; + static constexpr Type invalid = -1; +#endif + + explicit Socket(InternetProtocol internetProtocol): + endpoint(socket(getAddressFamily(internetProtocol), SOCK_STREAM, IPPROTO_TCP)) + { + if (endpoint == invalid) + throw std::system_error(getLastError(), std::system_category(), "Failed to create socket"); + +#if defined(__APPLE__) + const int value = 1; + if (setsockopt(endpoint, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value)) == -1) + throw std::system_error(getLastError(), std::system_category(), "Failed to set socket option"); +#endif + } + + ~Socket() + { + if (endpoint != invalid) closeSocket(endpoint); + } + + Socket(Socket&& other) noexcept: + endpoint(other.endpoint) + { + other.endpoint = invalid; + } + + Socket& operator=(Socket&& other) noexcept + { + if (&other == this) return *this; + if (endpoint != invalid) closeSocket(endpoint); + endpoint = other.endpoint; + other.endpoint = invalid; + return *this; + } + + void connect(const struct sockaddr* address, socklen_t addressSize) + { + auto result = ::connect(endpoint, address, addressSize); + +#ifdef _WIN32 + while (result == -1 && WSAGetLastError() == WSAEINTR) + result = ::connect(endpoint, address, addressSize); +#else + while (result == -1 && errno == EINTR) + result = ::connect(endpoint, address, addressSize); +#endif + + if (result == -1) + throw std::system_error(getLastError(), std::system_category(), "Failed to connect"); + } + + size_t send(const void* buffer, size_t length, int flags) + { +#ifdef _WIN32 + auto result = ::send(endpoint, reinterpret_cast(buffer), + static_cast(length), flags); + + while (result == -1 && WSAGetLastError() == WSAEINTR) + result = ::send(endpoint, reinterpret_cast(buffer), + static_cast(length), flags); + +#else + auto result = ::send(endpoint, reinterpret_cast(buffer), + length, flags); + + while (result == -1 && errno == EINTR) + result = ::send(endpoint, reinterpret_cast(buffer), + length, flags); +#endif + if (result == -1) + throw std::system_error(getLastError(), std::system_category(), "Failed to send data"); + + return static_cast(result); + } + + size_t recv(void* buffer, size_t length, int flags) + { +#ifdef _WIN32 + auto result = ::recv(endpoint, reinterpret_cast(buffer), + static_cast(length), flags); + + while (result == -1 && WSAGetLastError() == WSAEINTR) + result = ::recv(endpoint, reinterpret_cast(buffer), + static_cast(length), flags); +#else + auto result = ::recv(endpoint, reinterpret_cast(buffer), + length, flags); + + while (result == -1 && errno == EINTR) + result = ::recv(endpoint, reinterpret_cast(buffer), + length, flags); +#endif + if (result == -1) + throw std::system_error(getLastError(), std::system_category(), "Failed to read data"); + + return static_cast(result); + } + + operator Type() const noexcept { return endpoint; } + + private: + Type endpoint = invalid; + }; + } + + inline std::string urlEncode(const std::string& str) + { + constexpr char hexChars[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + std::string result; + + for (auto i = str.begin(); i != str.end(); ++i) + { + const std::uint8_t cp = *i & 0xFF; + + if ((cp >= 0x30 && cp <= 0x39) || // 0-9 + (cp >= 0x41 && cp <= 0x5A) || // A-Z + (cp >= 0x61 && cp <= 0x7A) || // a-z + cp == 0x2D || cp == 0x2E || cp == 0x5F) // - . _ + result += static_cast(cp); + else if (cp <= 0x7F) // length = 1 + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + else if ((cp >> 5) == 0x06) // length = 2 + { + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + if (++i == str.end()) break; + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + } + else if ((cp >> 4) == 0x0E) // length = 3 + { + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + if (++i == str.end()) break; + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + if (++i == str.end()) break; + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + } + else if ((cp >> 3) == 0x1E) // length = 4 + { + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + if (++i == str.end()) break; + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + if (++i == str.end()) break; + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + if (++i == str.end()) break; + result += std::string("%") + hexChars[(*i & 0xF0) >> 4] + hexChars[*i & 0x0F]; + } + } + + return result; + } + + struct Response final + { + enum Status + { + Continue = 100, + SwitchingProtocol = 101, + Processing = 102, + EarlyHints = 103, + + Ok = 200, + Created = 201, + Accepted = 202, + NonAuthoritativeInformation = 203, + NoContent = 204, + ResetContent = 205, + PartialContent = 206, + MultiStatus = 207, + AlreadyReported = 208, + ImUsed = 226, + + MultipleChoice = 300, + MovedPermanently = 301, + Found = 302, + SeeOther = 303, + NotModified = 304, + UseProxy = 305, + TemporaryRedirect = 307, + PermanentRedirect = 308, + + BadRequest = 400, + Unauthorized = 401, + PaymentRequired = 402, + Forbidden = 403, + NotFound = 404, + MethodNotAllowed = 405, + NotAcceptable = 406, + ProxyAuthenticationRequired = 407, + RequestTimeout = 408, + Conflict = 409, + Gone = 410, + LengthRequired = 411, + PreconditionFailed = 412, + PayloadTooLarge = 413, + UriTooLong = 414, + UnsupportedMediaType = 415, + RangeNotSatisfiable = 416, + ExpectationFailed = 417, + ImaTeapot = 418, + MisdirectedRequest = 421, + UnprocessableEntity = 422, + Locked = 423, + FailedDependency = 424, + TooEarly = 425, + UpgradeRequired = 426, + PreconditionRequired = 428, + TooManyRequests = 429, + RequestHeaderFieldsTooLarge = 431, + UnavailableForLegalReasons = 451, + + InternalServerError = 500, + NotImplemented = 501, + BadGateway = 502, + ServiceUnavailable = 503, + GatewayTimeout = 504, + HttpVersionNotSupported = 505, + VariantAlsoNegotiates = 506, + InsufficientStorage = 507, + LoopDetected = 508, + NotExtended = 510, + NetworkAuthenticationRequired = 511 + }; + + int status = 0; + std::vector headers; + std::vector body; + }; + + class Request final + { + public: + explicit Request(const std::string& url, + InternetProtocol protocol = InternetProtocol::V4): + internetProtocol(protocol) + { + const auto schemeEndPosition = url.find("://"); + + if (schemeEndPosition != std::string::npos) + { + scheme = url.substr(0, schemeEndPosition); + path = url.substr(schemeEndPosition + 3); + } + else + { + scheme = "http"; + path = url; + } + + const auto fragmentPosition = path.find('#'); + + // remove the fragment part + if (fragmentPosition != std::string::npos) + path.resize(fragmentPosition); + + const auto pathPosition = path.find('/'); + + if (pathPosition == std::string::npos) + { + domain = path; + path = "/"; + } + else + { + domain = path.substr(0, pathPosition); + path = path.substr(pathPosition); + } + + const auto portPosition = domain.find(':'); + + if (portPosition != std::string::npos) + { + port = domain.substr(portPosition + 1); + domain.resize(portPosition); + } + else + port = "80"; + } + + Response send(const std::string& method, + const std::map& parameters, + const std::vector& headers = {}) + { + std::string body; + bool first = true; + + for (const auto& parameter : parameters) + { + if (!first) body += "&"; + first = false; + + body += urlEncode(parameter.first) + "=" + urlEncode(parameter.second); + } + + return send(method, body, headers); + } + + Response send(const std::string& method = "GET", + const std::string& body = "", + const std::vector& headers = {}) + { + return send(method, + std::vector(body.begin(), body.end()), + headers); + } + + Response send(const std::string& method, + const std::vector& body, + const std::vector& headers) + { + if (scheme != "http") + throw RequestError("Only HTTP scheme is supported"); + + addrinfo hints = {}; + hints.ai_family = getAddressFamily(internetProtocol); + hints.ai_socktype = SOCK_STREAM; + + addrinfo* info; + if (getaddrinfo(domain.c_str(), port.c_str(), &hints, &info) != 0) + throw std::system_error(getLastError(), std::system_category(), "Failed to get address info of " + domain); + + std::unique_ptr addressInfo(info, freeaddrinfo); + + std::string headerData = method + " " + path + " HTTP/1.1\r\n"; + + for (const std::string& header : headers) + headerData += header + "\r\n"; + + headerData += "Host: " + domain + "\r\n" + "Content-Length: " + std::to_string(body.size()) + "\r\n" + "\r\n"; + + std::vector requestData(headerData.begin(), headerData.end()); + requestData.insert(requestData.end(), body.begin(), body.end()); + + Socket socket(internetProtocol); + + // take the first address from the list + socket.connect(addressInfo->ai_addr, static_cast(addressInfo->ai_addrlen)); + + auto remaining = requestData.size(); + auto sendData = requestData.data(); + + // send the request + while (remaining > 0) + { + const auto size = socket.send(sendData, remaining, noSignal); + remaining -= size; + sendData += size; + } + + std::uint8_t tempBuffer[4096]; + constexpr std::uint8_t crlf[] = {'\r', '\n'}; + Response response; + std::vector responseData; + bool firstLine = true; + bool parsedHeaders = false; + bool contentLengthReceived = false; + unsigned long contentLength = 0; + bool chunkedResponse = false; + std::size_t expectedChunkSize = 0; + bool removeCrlfAfterChunk = false; + + // read the response + for (;;) + { + const auto size = socket.recv(tempBuffer, sizeof(tempBuffer), noSignal); + + if (size == 0) + break; // disconnected + + responseData.insert(responseData.end(), tempBuffer, tempBuffer + size); + + if (!parsedHeaders) + for (;;) + { + const auto i = std::search(responseData.begin(), responseData.end(), std::begin(crlf), std::end(crlf)); + + // didn't find a newline + if (i == responseData.end()) break; + + const std::string line(responseData.begin(), i); + responseData.erase(responseData.begin(), i + 2); + + // empty line indicates the end of the header section + if (line.empty()) + { + parsedHeaders = true; + break; + } + else if (firstLine) // first line + { + firstLine = false; + + std::string::size_type lastPos = 0; + const auto length = line.length(); + std::vector parts; + + // tokenize first line + while (lastPos < length + 1) + { + auto pos = line.find(' ', lastPos); + if (pos == std::string::npos) pos = length; + + if (pos != lastPos) + parts.emplace_back(line.data() + lastPos, + static_cast::size_type>(pos) - lastPos); + + lastPos = pos + 1; + } + + if (parts.size() >= 2) + response.status = std::stoi(parts[1]); + } + else // headers + { + response.headers.push_back(line); + + const auto pos = line.find(':'); + + if (pos != std::string::npos) + { + std::string headerName = line.substr(0, pos); + std::string headerValue = line.substr(pos + 1); + + // ltrim + headerValue.erase(headerValue.begin(), + std::find_if(headerValue.begin(), headerValue.end(), + [](int c) {return !std::isspace(c);})); + + // rtrim + headerValue.erase(std::find_if(headerValue.rbegin(), headerValue.rend(), + [](int c) {return !std::isspace(c);}).base(), + headerValue.end()); + + if (headerName == "Content-Length") + { + contentLength = std::stoul(headerValue); + contentLengthReceived = true; + response.body.reserve(contentLength); + } + else if (headerName == "Transfer-Encoding") + { + if (headerValue == "chunked") + chunkedResponse = true; + else + throw ResponseError("Unsupported transfer encoding: " + headerValue); + } + } + } + } + + if (parsedHeaders) + { + // Content-Length must be ignored if Transfer-Encoding is received + if (chunkedResponse) + { + bool dataReceived = false; + for (;;) + { + if (expectedChunkSize > 0) + { + const auto toWrite = std::min(expectedChunkSize, responseData.size()); + response.body.insert(response.body.end(), responseData.begin(), responseData.begin() + static_cast(toWrite)); + responseData.erase(responseData.begin(), responseData.begin() + static_cast(toWrite)); + expectedChunkSize -= toWrite; + + if (expectedChunkSize == 0) removeCrlfAfterChunk = true; + if (responseData.empty()) break; + } + else + { + if (removeCrlfAfterChunk) + { + if (responseData.size() >= 2) + { + removeCrlfAfterChunk = false; + responseData.erase(responseData.begin(), responseData.begin() + 2); + } + else break; + } + + const auto i = std::search(responseData.begin(), responseData.end(), std::begin(crlf), std::end(crlf)); + + if (i == responseData.end()) break; + + const std::string line(responseData.begin(), i); + responseData.erase(responseData.begin(), i + 2); + + expectedChunkSize = std::stoul(line, nullptr, 16); + + if (expectedChunkSize == 0) + { + dataReceived = true; + break; + } + } + } + + if (dataReceived) + break; + } + else + { + response.body.insert(response.body.end(), responseData.begin(), responseData.end()); + responseData.clear(); + + // got the whole content + if (contentLengthReceived && response.body.size() >= contentLength) + break; + } + } + } + + return response; + } + + private: +#ifdef _WIN32 + WinSock winSock; +#endif + InternetProtocol internetProtocol; + std::string scheme; + std::string domain; + std::string port; + std::string path; + }; +} + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/IceAABB.cpp b/src/external/open_dynamics_engine-ef/ode/IceAABB.cpp new file mode 100644 index 00000000..5fce7cb8 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceAABB.cpp @@ -0,0 +1,413 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains AABB-related code. + * \file IceAABB.cpp + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * AABB class. + * \class AABB + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the sum of two AABBs. + * \param aabb [in] the other AABB + * \return Self-Reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABB& AABB::Add(const AABB& aabb) +{ + // Compute new min & max values + Point Min; GetMin(Min); + Point Tmp; aabb.GetMin(Tmp); + Min.Min(Tmp); + + Point Max; GetMax(Max); + aabb.GetMax(Tmp); + Max.Max(Tmp); + + // Update this + SetMinMax(Min, Max); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Makes a cube from the AABB. + * \param cube [out] the cube AABB + * \return cube edge length + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float AABB::MakeCube(AABB& cube) const +{ + Point Ext; GetExtents(Ext); + float Max = Ext.Max(); + + Point Cnt; GetCenter(Cnt); + cube.SetCenterExtents(Cnt, Point(Max, Max, Max)); + return Max; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Makes a sphere from the AABB. + * \param sphere [out] sphere containing the AABB + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABB::MakeSphere(Sphere& sphere) const +{ + GetExtents(sphere.mCenter); + sphere.mRadius = sphere.mCenter.Magnitude() * 1.00001f; // To make sure sphere::Contains(*this) succeeds + GetCenter(sphere.mCenter); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks a box is inside another box. + * \param box [in] the other AABB + * \return true if current box is inside input box + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABB::IsInside(const AABB& box) const +{ + if(box.GetMin(0)>GetMin(0)) return false; + if(box.GetMin(1)>GetMin(1)) return false; + if(box.GetMin(2)>GetMin(2)) return false; + if(box.GetMax(0) max.x) ? 2 : 0) // 2 = right + + ((local_eye.y < min.y) ? 4 : 0) // 4 = bottom + + ((local_eye.y > max.y) ? 8 : 0) // 8 = top + + ((local_eye.z < min.z) ? 16 : 0) // 16 = front + + ((local_eye.z > max.z) ? 32 : 0); // 32 = back + + // Look up number of vertices in outline + num = (sdword)gIndexList[pos][7]; + // Zero indicates invalid case + if(!num) return null; + + return &gIndexList[pos][0]; +} + +// calculateBoxArea: computes the screen-projected 2D area of an oriented 3D bounding box + +//const Point& eye, //eye point (in bbox object coordinates) +//const AABB& box, //3d bbox +//const Matrix4x4& mat, //free transformation for bbox +//float width, float height, int& num) +float AABB::ComputeBoxArea(const Point& eye, const Matrix4x4& mat, float width, float height, sdword& num) const +{ + const sbyte* Outline = ComputeOutline(eye, num); + if(!Outline) return -1.0f; + + // Compute box vertices + Point vertexBox[8], dst[8]; + ComputePoints(vertexBox); + + // Transform all outline corners into 2D screen space + for(sdword i=0;i GetMax(0) || p.x < GetMin(0)) return FALSE; \ + if(p.y > GetMax(1) || p.y < GetMin(1)) return FALSE; \ + if(p.z > GetMax(2) || p.z < GetMin(2)) return FALSE; \ + return TRUE; \ + } + + enum AABBType + { + AABB_RENDER = 0, //!< AABB used for rendering. Not visible == not rendered. + AABB_UPDATE = 1, //!< AABB used for dynamic updates. Not visible == not updated. + + AABB_FORCE_DWORD = 0x7fffffff, + }; + +#ifdef USE_MINMAX + + struct ICEMATHS_API ShadowAABB + { + Point mMin; + Point mMax; + }; + + class ICEMATHS_API AABB + { + public: + //! Constructor + inline_ AABB() {} + //! Destructor + inline_ ~AABB() {} + + //! Type-independent methods + AABB_COMMON_METHODS; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an AABB from min & max vectors. + * \param min [in] the min point + * \param max [in] the max point + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetMinMax(const Point& min, const Point& max) { mMin = min; mMax = max; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an AABB from center & extents vectors. + * \param c [in] the center point + * \param e [in] the extents vector + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetCenterExtents(const Point& c, const Point& e) { mMin = c - e; mMax = c + e; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an empty AABB. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetEmpty() { Point p(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); mMin = -p; mMax = p;} + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups a point AABB. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetPoint(const Point& pt) { mMin = mMax = pt; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the size of the AABB. The size is defined as the longest extent. + * \return the size of the AABB + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float GetSize() const { Point e; GetExtents(e); return e.Max(); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Extends the AABB. + * \param p [in] the next point + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Extend(const Point& p) + { + if(p.x > mMax.x) mMax.x = p.x; + if(p.x < mMin.x) mMin.x = p.x; + + if(p.y > mMax.y) mMax.y = p.y; + if(p.y < mMin.y) mMin.y = p.y; + + if(p.z > mMax.z) mMax.z = p.z; + if(p.z < mMin.z) mMin.z = p.z; + } + // Data access + + //! Get min point of the box + inline_ void GetMin(Point& min) const { min = mMin; } + //! Get max point of the box + inline_ void GetMax(Point& max) const { max = mMax; } + + //! Get component of the box's min point along a given axis + inline_ float GetMin(udword axis) const { return mMin[axis]; } + //! Get component of the box's max point along a given axis + inline_ float GetMax(udword axis) const { return mMax[axis]; } + + //! Get box center + inline_ void GetCenter(Point& center) const { center = (mMax + mMin)*0.5f; } + //! Get box extents + inline_ void GetExtents(Point& extents) const { extents = (mMax - mMin)*0.5f; } + + //! Get component of the box's center along a given axis + inline_ float GetCenter(udword axis) const { return (mMax[axis] + mMin[axis])*0.5f; } + //! Get component of the box's extents along a given axis + inline_ float GetExtents(udword axis) const { return (mMax[axis] - mMin[axis])*0.5f; } + + //! Get box diagonal + inline_ void GetDiagonal(Point& diagonal) const { diagonal = mMax - mMin; } + inline_ float GetWidth() const { return mMax.x - mMin.x; } + inline_ float GetHeight() const { return mMax.y - mMin.y; } + inline_ float GetDepth() const { return mMax.z - mMin.z; } + + //! Volume + inline_ float GetVolume() const { return GetWidth() * GetHeight() * GetDepth(); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes the intersection between two AABBs. + * \param a [in] the other AABB + * \return true on intersection + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL Intersect(const AABB& a) const + { + if(mMax.x < a.mMin.x + || a.mMax.x < mMin.x + || mMax.y < a.mMin.y + || a.mMax.y < mMin.y + || mMax.z < a.mMin.z + || a.mMax.z < mMin.z) return FALSE; + + return TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes the 1D-intersection between two AABBs, on a given axis. + * \param a [in] the other AABB + * \param axis [in] the axis (0, 1, 2) + * \return true on intersection + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL Intersect(const AABB& a, udword axis) const + { + if(mMax[axis] < a.mMin[axis] || a.mMax[axis] < mMin[axis]) return FALSE; + return TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Recomputes the AABB after an arbitrary transform by a 4x4 matrix. + * Original code by Charles Bloom on the GD-Algorithm list. (I slightly modified it) + * \param mtx [in] the transform matrix + * \param aabb [out] the transformed AABB [can be *this] + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const + { + // The three edges transformed: you can efficiently transform an X-only vector + // by just getting the "X" column of the matrix + Point vx,vy,vz; + mtx.GetRow(0, vx); vx *= (mMax.x - mMin.x); + mtx.GetRow(1, vy); vy *= (mMax.y - mMin.y); + mtx.GetRow(2, vz); vz *= (mMax.z - mMin.z); + + // Transform the min point + aabb.mMin = aabb.mMax = mMin * mtx; + + // Take the transformed min & axes and find new extents + // Using CPU code in the right place is faster... + if(IS_NEGATIVE_FLOAT(vx.x)) aabb.mMin.x += vx.x; else aabb.mMax.x += vx.x; + if(IS_NEGATIVE_FLOAT(vx.y)) aabb.mMin.y += vx.y; else aabb.mMax.y += vx.y; + if(IS_NEGATIVE_FLOAT(vx.z)) aabb.mMin.z += vx.z; else aabb.mMax.z += vx.z; + if(IS_NEGATIVE_FLOAT(vy.x)) aabb.mMin.x += vy.x; else aabb.mMax.x += vy.x; + if(IS_NEGATIVE_FLOAT(vy.y)) aabb.mMin.y += vy.y; else aabb.mMax.y += vy.y; + if(IS_NEGATIVE_FLOAT(vy.z)) aabb.mMin.z += vy.z; else aabb.mMax.z += vy.z; + if(IS_NEGATIVE_FLOAT(vz.x)) aabb.mMin.x += vz.x; else aabb.mMax.x += vz.x; + if(IS_NEGATIVE_FLOAT(vz.y)) aabb.mMin.y += vz.y; else aabb.mMax.y += vz.y; + if(IS_NEGATIVE_FLOAT(vz.z)) aabb.mMin.z += vz.z; else aabb.mMax.z += vz.z; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the AABB is valid. + * \return true if the box is valid + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL IsValid() const + { + // Consistency condition for (Min, Max) boxes: min < max + if(mMin.x > mMax.x) return FALSE; + if(mMin.y > mMax.y) return FALSE; + if(mMin.z > mMax.z) return FALSE; + return TRUE; + } + + //! Operator for AABB *= float. Scales the extents, keeps same center. + inline_ AABB& operator*=(float s) + { + Point Center; GetCenter(Center); + Point Extents; GetExtents(Extents); + SetCenterExtents(Center, Extents * s); + return *this; + } + + //! Operator for AABB /= float. Scales the extents, keeps same center. + inline_ AABB& operator/=(float s) + { + Point Center; GetCenter(Center); + Point Extents; GetExtents(Extents); + SetCenterExtents(Center, Extents / s); + return *this; + } + + //! Operator for AABB += Point. Translates the box. + inline_ AABB& operator+=(const Point& trans) + { + mMin+=trans; + mMax+=trans; + return *this; + } + private: + Point mMin; //!< Min point + Point mMax; //!< Max point + }; + +#else + + class ICEMATHS_API AABB + { + public: + //! Constructor + inline_ AABB() {} + //! Destructor + inline_ ~AABB() {} + + //! Type-independent methods + AABB_COMMON_METHODS; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an AABB from min & max vectors. + * \param min [in] the min point + * \param max [in] the max point + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an AABB from center & extents vectors. + * \param c [in] the center point + * \param e [in] the extents vector + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetCenterExtents(const Point& c, const Point& e) { mCenter = c; mExtents = e; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an empty AABB. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetEmpty() { mCenter.Zero(); mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT);} + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups a point AABB. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetPoint(const Point& pt) { mCenter = pt; mExtents.Zero(); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the size of the AABB. The size is defined as the longest extent. + * \return the size of the AABB + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + float GetSize() const { return mExtents.Max(); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Extends the AABB. + * \param p [in] the next point + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Extend(const Point& p) + { + Point Max = mCenter + mExtents; + Point Min = mCenter - mExtents; + + if(p.x > Max.x) Max.x = p.x; + if(p.x < Min.x) Min.x = p.x; + + if(p.y > Max.y) Max.y = p.y; + if(p.y < Min.y) Min.y = p.y; + + if(p.z > Max.z) Max.z = p.z; + if(p.z < Min.z) Min.z = p.z; + + SetMinMax(Min, Max); + } + // Data access + + //! Get min point of the box + inline_ void GetMin(Point& min) const { min = mCenter - mExtents; } + //! Get max point of the box + inline_ void GetMax(Point& max) const { max = mCenter + mExtents; } + + //! Get component of the box's min point along a given axis + inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; } + //! Get component of the box's max point along a given axis + inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; } + + //! Get box center + inline_ void GetCenter(Point& center) const { center = mCenter; } + //! Get box extents + inline_ void GetExtents(Point& extents) const { extents = mExtents; } + + //! Get component of the box's center along a given axis + inline_ float GetCenter(udword axis) const { return mCenter[axis]; } + //! Get component of the box's extents along a given axis + inline_ float GetExtents(udword axis) const { return mExtents[axis]; } + + //! Get box diagonal + inline_ void GetDiagonal(Point& diagonal) const { diagonal = mExtents * 2.0f; } + inline_ float GetWidth() const { return mExtents.x * 2.0f; } + inline_ float GetHeight() const { return mExtents.y * 2.0f; } + inline_ float GetDepth() const { return mExtents.z * 2.0f; } + + //! Volume + inline_ float GetVolume() const { return mExtents.x * mExtents.y * mExtents.z * 8.0f; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes the intersection between two AABBs. + * \param a [in] the other AABB + * \return true on intersection + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL Intersect(const AABB& a) const + { + float tx = mCenter.x - a.mCenter.x; float ex = a.mExtents.x + mExtents.x; if(AIR(tx) > IR(ex)) return FALSE; + float ty = mCenter.y - a.mCenter.y; float ey = a.mExtents.y + mExtents.y; if(AIR(ty) > IR(ey)) return FALSE; + float tz = mCenter.z - a.mCenter.z; float ez = a.mExtents.z + mExtents.z; if(AIR(tz) > IR(ez)) return FALSE; + return TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * The standard intersection method from Gamasutra. Just here to check its speed against the one above. + * \param a [in] the other AABB + * \return true on intersection + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool GomezIntersect(const AABB& a) + { + Point T = mCenter - a.mCenter; // Vector from A to B + return ((fabsf(T.x) <= (a.mExtents.x + mExtents.x)) + && (fabsf(T.y) <= (a.mExtents.y + mExtents.y)) + && (fabsf(T.z) <= (a.mExtents.z + mExtents.z))); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes the 1D-intersection between two AABBs, on a given axis. + * \param a [in] the other AABB + * \param axis [in] the axis (0, 1, 2) + * \return true on intersection + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL Intersect(const AABB& a, udword axis) const + { + float t = mCenter[axis] - a.mCenter[axis]; + float e = a.mExtents[axis] + mExtents[axis]; + if(AIR(t) > IR(e)) return FALSE; + return TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Recomputes the AABB after an arbitrary transform by a 4x4 matrix. + * \param mtx [in] the transform matrix + * \param aabb [out] the transformed AABB [can be *this] + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void Rotate(const Matrix4x4& mtx, AABB& aabb) const + { + // Compute new center + aabb.mCenter = mCenter * mtx; + + // Compute new extents. FPU code & CPU code have been interleaved for improved performance. + Point Ex(mtx.m[0][0] * mExtents.x, mtx.m[0][1] * mExtents.x, mtx.m[0][2] * mExtents.x); + IR(Ex.x)&=0x7fffffff; IR(Ex.y)&=0x7fffffff; IR(Ex.z)&=0x7fffffff; + + Point Ey(mtx.m[1][0] * mExtents.y, mtx.m[1][1] * mExtents.y, mtx.m[1][2] * mExtents.y); + IR(Ey.x)&=0x7fffffff; IR(Ey.y)&=0x7fffffff; IR(Ey.z)&=0x7fffffff; + + Point Ez(mtx.m[2][0] * mExtents.z, mtx.m[2][1] * mExtents.z, mtx.m[2][2] * mExtents.z); + IR(Ez.x)&=0x7fffffff; IR(Ez.y)&=0x7fffffff; IR(Ez.z)&=0x7fffffff; + + aabb.mExtents.x = Ex.x + Ey.x + Ez.x; + aabb.mExtents.y = Ex.y + Ey.y + Ez.y; + aabb.mExtents.z = Ex.z + Ey.z + Ez.z; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the AABB is valid. + * \return true if the box is valid + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL IsValid() const + { + // Consistency condition for (Center, Extents) boxes: Extents >= 0 + if(IS_NEGATIVE_FLOAT(mExtents.x)) return FALSE; + if(IS_NEGATIVE_FLOAT(mExtents.y)) return FALSE; + if(IS_NEGATIVE_FLOAT(mExtents.z)) return FALSE; + return TRUE; + } + + //! Operator for AABB *= float. Scales the extents, keeps same center. + inline_ AABB& operator*=(float s) { mExtents*=s; return *this; } + + //! Operator for AABB /= float. Scales the extents, keeps same center. + inline_ AABB& operator/=(float s) { mExtents/=s; return *this; } + + //! Operator for AABB += Point. Translates the box. + inline_ AABB& operator+=(const Point& trans) + { + mCenter+=trans; + return *this; + } + private: + Point mCenter; //!< AABB Center + Point mExtents; //!< x, y and z extents + }; + +#endif + + inline_ void ComputeMinMax(const Point& p, Point& min, Point& max) + { + if(p.x > max.x) max.x = p.x; + if(p.x < min.x) min.x = p.x; + + if(p.y > max.y) max.y = p.y; + if(p.y < min.y) min.y = p.y; + + if(p.z > max.z) max.z = p.z; + if(p.z < min.z) min.z = p.z; + } + + inline_ void ComputeAABB(AABB& aabb, const Point* list, udword nb_pts) + { + if(list) + { + Point Maxi(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); + Point Mini(MAX_FLOAT, MAX_FLOAT, MAX_FLOAT); + while(nb_pts--) + { +// _prefetch(list+1); // off by one ? + ComputeMinMax(*list++, Mini, Maxi); + } + aabb.SetMinMax(Mini, Maxi); + } + } + +#endif // __ICEAABB_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceAxes.h b/src/external/open_dynamics_engine-ef/ode/IceAxes.h new file mode 100644 index 00000000..1afe4cec --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceAxes.h @@ -0,0 +1,60 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains axes definition. + * \file IceAxes.h + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEAXES_H__ +#define __ICEAXES_H__ + + +// ericf added +#ifdef _X +#undef _X +#endif + + enum PointComponent + { + _X = 0, + _Y = 1, + _Z = 2, + _W = 3, + + _FORCE_DWORD = 0x7fffffff + }; + + enum AxisOrder + { + AXES_XYZ = (_X)|(_Y<<2)|(_Z<<4), + AXES_XZY = (_X)|(_Z<<2)|(_Y<<4), + AXES_YXZ = (_Y)|(_X<<2)|(_Z<<4), + AXES_YZX = (_Y)|(_Z<<2)|(_X<<4), + AXES_ZXY = (_Z)|(_X<<2)|(_Y<<4), + AXES_ZYX = (_Z)|(_Y<<2)|(_X<<4), + + AXES_FORCE_DWORD = 0x7fffffff + }; + + class ICEMATHS_API Axes + { + public: + + inline_ Axes(AxisOrder order) + { + mAxis0 = (order ) & 3; + mAxis1 = (order>>2) & 3; + mAxis2 = (order>>4) & 3; + } + inline_ ~Axes() {} + + udword mAxis0; + udword mAxis1; + udword mAxis2; + }; + +#endif // __ICEAXES_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceBoundingSphere.h b/src/external/open_dynamics_engine-ef/ode/IceBoundingSphere.h new file mode 100644 index 00000000..945d38cf --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceBoundingSphere.h @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code to compute the minimal bounding sphere. + * \file IceBoundingSphere.h + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEBOUNDINGSPHERE_H__ +#define __ICEBOUNDINGSPHERE_H__ + + enum BSphereMethod + { + BS_NONE, + BS_GEMS, + BS_MINIBALL, + + BS_FORCE_DWORD = 0x7fffffff + }; + + class ICEMATHS_API Sphere + { + public: + //! Constructor + inline_ Sphere() {} + //! Constructor + inline_ Sphere(const Point& center, float radius) : mCenter(center), mRadius(radius) {} + //! Constructor + Sphere(udword nb_verts, const Point* verts); + //! Copy constructor + inline_ Sphere(const Sphere& sphere) : mCenter(sphere.mCenter), mRadius(sphere.mRadius) {} + //! Destructor + inline_ ~Sphere() {} + + BSphereMethod Compute(udword nb_verts, const Point* verts); + bool FastCompute(udword nb_verts, const Point* verts); + + // Access methods + inline_ const Point& GetCenter() const { return mCenter; } + inline_ float GetRadius() const { return mRadius; } + + inline_ const Point& Center() const { return mCenter; } + inline_ float Radius() const { return mRadius; } + + inline_ Sphere& Set(const Point& center, float radius) { mCenter = center; mRadius = radius; return *this; } + inline_ Sphere& SetCenter(const Point& center) { mCenter = center; return *this; } + inline_ Sphere& SetRadius(float radius) { mRadius = radius; return *this; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if a point is contained within the sphere. + * \param p [in] the point to test + * \return true if inside the sphere + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool Contains(const Point& p) const + { + return mCenter.SquareDistance(p) <= mRadius*mRadius; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if a sphere is contained within the sphere. + * \param sphere [in] the sphere to test + * \return true if inside the sphere + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool Contains(const Sphere& sphere) const + { + // If our radius is the smallest, we can't possibly contain the other sphere + if(mRadius < sphere.mRadius) return false; + // So r is always positive or null now + float r = mRadius - sphere.mRadius; + return mCenter.SquareDistance(sphere.mCenter) <= r*r; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if a box is contained within the sphere. + * \param aabb [in] the box to test + * \return true if inside the sphere + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL Contains(const AABB& aabb) const + { + // I assume if all 8 box vertices are inside the sphere, so does the whole box. + // Sounds ok but maybe there's a better way? + float R2 = mRadius * mRadius; +#ifdef USE_MIN_MAX + const Point& Max = ((ShadowAABB&)&aabb).mMax; + const Point& Min = ((ShadowAABB&)&aabb).mMin; +#else + Point Max; aabb.GetMax(Max); + Point Min; aabb.GetMin(Min); +#endif + Point p; + p.x=Max.x; p.y=Max.y; p.z=Max.z; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Max.x; p.y=Max.y; p.z=Min.z; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Max.x; p.y=Min.y; if(mCenter.SquareDistance(p)>=R2) return FALSE; + p.x=Min.x; if(mCenter.SquareDistance(p)>=R2) return FALSE; + + return TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if the sphere intersects another sphere + * \param sphere [in] the other sphere + * \return true if spheres overlap + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool Intersect(const Sphere& sphere) const + { + float r = mRadius + sphere.mRadius; + return mCenter.SquareDistance(sphere.mCenter) <= r*r; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the sphere is valid. + * \return true if the box is valid + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL IsValid() const + { + // Consistency condition for spheres: Radius >= 0.0f + if(mRadius < 0.0f) return FALSE; + return TRUE; + } + public: + Point mCenter; //!< Sphere center + float mRadius; //!< Sphere radius + }; + +#endif // __ICEBOUNDINGSPHERE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceContainer.cpp b/src/external/open_dynamics_engine-ef/ode/IceContainer.cpp new file mode 100644 index 00000000..0599ba46 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceContainer.cpp @@ -0,0 +1,352 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a simple container class. + * \file IceContainer.cpp + * \author Pierre Terdiman + * \date February, 5, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a list of 32-bits values. + * Use this class when you need to store an unknown number of values. The list is automatically + * resized and can contains 32-bits entities (dwords or floats) + * + * \class Container + * \author Pierre Terdiman + * \version 1.0 + * \date 08.15.98 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceCore; + +// Static members +#ifdef CONTAINER_STATS +udword Container::mNbContainers = 0; +udword Container::mUsedRam = 0; +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. No entries allocated there. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Container::Container() : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f) +{ +#ifdef CONTAINER_STATS + mNbContainers++; + mUsedRam+=sizeof(Container); +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. Also allocates a given number of entries. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Container::Container(udword size, float growth_factor) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(growth_factor) +{ +#ifdef CONTAINER_STATS + mNbContainers++; + mUsedRam+=sizeof(Container); +#endif + SetSize(size); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Copy constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Container::Container(const Container& object) : mMaxNbEntries(0), mCurNbEntries(0), mEntries(null), mGrowthFactor(2.0f) +{ +#ifdef CONTAINER_STATS + mNbContainers++; + mUsedRam+=sizeof(Container); +#endif + *this = object; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. Frees everything and leaves. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Container::~Container() +{ + Empty(); +#ifdef CONTAINER_STATS + mNbContainers--; + mUsedRam-=GetUsedRam(); +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Clears the container. All stored values are deleted, and it frees used ram. + * \see Reset() + * \return Self-Reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Container& Container::Empty() +{ +#ifdef CONTAINER_STATS + mUsedRam-=mMaxNbEntries*sizeof(udword); +#endif + DELETEARRAY(mEntries); + mCurNbEntries = mMaxNbEntries = 0; + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Resizes the container. + * \param needed [in] assume the container can be added at least "needed" values + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Container::Resize(udword needed) +{ +#ifdef CONTAINER_STATS + // Subtract previous amount of bytes + mUsedRam-=mMaxNbEntries*sizeof(udword); +#endif + + // Get more entries + mMaxNbEntries = mMaxNbEntries ? udword(float(mMaxNbEntries)*mGrowthFactor) : 2; // Default nb Entries = 2 + if(mMaxNbEntriesmMaxNbEntries) Resize(nb); + + // Add new entry + CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(udword)); + mCurNbEntries+=nb; + return *this; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * A O(1) method to add a value in the container. The container is automatically resized if needed. + * The method is inline, not the resize. The call overhead happens on resizes only, which is not a problem since the resizing operation + * costs a lot more than the call overhead... + * + * \param entry [in] a float to store in the container + * \see Add(udword entry) + * \see Empty() + * \see Contains(udword entry) + * \return Self-Reference + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ Container& Add(float entry) + { + // Resize if needed + if(mCurNbEntries==mMaxNbEntries) Resize(); + + // Add new entry + mEntries[mCurNbEntries++] = IR(entry); + return *this; + } + + inline_ Container& Add(const float* entries, udword nb) + { + // Resize if needed + if(mCurNbEntries+nb>mMaxNbEntries) Resize(nb); + + // Add new entry + CopyMemory(&mEntries[mCurNbEntries], entries, nb*sizeof(float)); + mCurNbEntries+=nb; + return *this; + } + + //! Add unique [slow] + inline_ Container& AddUnique(udword entry) + { + if(!Contains(entry)) Add(entry); + return *this; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Clears the container. All stored values are deleted, and it frees used ram. + * \see Reset() + * \return Self-Reference + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + Container& Empty(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Resets the container. Stored values are discarded but the buffer is kept so that further calls don't need resizing again. + * That's a kind of temporal coherence. + * \see Empty() + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void Reset() + { + // Avoid the write if possible + // ### CMOV + if(mCurNbEntries) mCurNbEntries = 0; + } + + // HANDLE WITH CARE + inline_ void ForceSize(udword size) + { + mCurNbEntries = size; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Sets the initial size of the container. If it already contains something, it's discarded. + * \param nb [in] Number of entries + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool SetSize(udword nb); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Refits the container and get rid of unused bytes. + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool Refit(); + + // Checks whether the container already contains a given value. + bool Contains(udword entry, udword* location=null) const; + // Deletes an entry - doesn't preserve insertion order. + bool Delete(udword entry); + // Deletes an entry - does preserve insertion order. + bool DeleteKeepingOrder(udword entry); + //! Deletes the very last entry. + inline_ void DeleteLastEntry() { if(mCurNbEntries) mCurNbEntries--; } + //! Deletes the entry whose index is given + inline_ void DeleteIndex(udword index) { mEntries[index] = mEntries[--mCurNbEntries]; } + + // Helpers + Container& FindNext(udword& entry, FindMode find_mode=FIND_CLAMP); + Container& FindPrev(udword& entry, FindMode find_mode=FIND_CLAMP); + // Data access. + inline_ udword GetNbEntries() const { return mCurNbEntries; } //!< Returns the current number of entries. + inline_ udword GetEntry(udword i) const { return mEntries[i]; } //!< Returns ith entry + inline_ udword* GetEntries() const { return mEntries; } //!< Returns the list of entries. + + inline_ udword GetFirst() const { return mEntries[0]; } + inline_ udword GetLast() const { return mEntries[mCurNbEntries-1]; } + + // Growth control + inline_ float GetGrowthFactor() const { return mGrowthFactor; } //!< Returns the growth factor + inline_ void SetGrowthFactor(float growth) { mGrowthFactor = growth; } //!< Sets the growth factor + inline_ bool IsFull() const { return mCurNbEntries==mMaxNbEntries; } //!< Checks the container is full + inline_ BOOL IsNotEmpty() const { return mCurNbEntries; } //!< Checks the container is empty + + //! Read-access as an array + inline_ udword operator[](udword i) const { ASSERT(i>=0 && i=0 && i>31); + return (float&)y; + } + + //! Computes 1.0f / sqrtf(x). + inline_ float frsqrt(float f) + { + float x = f * 0.5f; + udword y = 0x5f3759df - ((udword&)f >> 1); + // Iteration... + (float&)y = (float&)y * ( 1.5f - ( x * (float&)y * (float&)y ) ); + // Result + return (float&)y; + } + + //! Computes 1.0f / sqrtf(x). Comes from NVIDIA. + inline_ float InvSqrt(const float& x) + { + udword tmp = (udword(IEEE_1_0 << 1) + IEEE_1_0 - *(udword*)&x) >> 1; + float y = *(float*)&tmp; + return y * (1.47f - 0.47f * x * y * y); + } + + //! Computes 1.0f / sqrtf(x). Comes from Quake3. Looks like the first one I had above. + //! See http://www.magic-software.com/3DGEDInvSqrt.html + inline_ float RSqrt(float number) + { + long i; + float x2, y; + const float threehalfs = 1.5f; + + x2 = number * 0.5f; + y = number; + i = * (long *) &y; + i = 0x5f3759df - (i >> 1); + y = * (float *) &i; + y = y * (threehalfs - (x2 * y * y)); + + return y; + } + + //! TO BE DOCUMENTED + inline_ float fsqrt(float f) + { + udword y = ( ( (sdword&)f - 0x3f800000 ) >> 1 ) + 0x3f800000; + // Iteration...? + // (float&)y = (3.0f - ((float&)y * (float&)y) / f) * (float&)y * 0.5f; + // Result + return (float&)y; + } + + //! Returns the float ranged espilon value. + inline_ float fepsilon(float f) + { + udword b = (udword&)f & 0xff800000; + udword a = b | 0x00000001; + (float&)a -= (float&)b; + // Result + return (float&)a; + } + + //! Is the float valid ? + inline_ bool IsNAN(float value) { return (IR(value)&0x7f800000) == 0x7f800000; } + inline_ bool IsIndeterminate(float value) { return IR(value) == 0xffc00000; } + inline_ bool IsPlusInf(float value) { return IR(value) == 0x7f800000; } + inline_ bool IsMinusInf(float value) { return IR(value) == 0xff800000; } + + inline_ bool IsValidFloat(float value) + { + if(IsNAN(value)) return false; + if(IsIndeterminate(value)) return false; + if(IsPlusInf(value)) return false; + if(IsMinusInf(value)) return false; + return true; + } + + #define CHECK_VALID_FLOAT(x) ASSERT(IsValidFloat(x)); + +/* + //! FPU precision setting function. + inline_ void SetFPU() + { + // This function evaluates whether the floating-point + // control word is set to single precision/round to nearest/ + // exceptions disabled. If these conditions don't hold, the + // function changes the control word to set them and returns + // TRUE, putting the old control word value in the passback + // location pointed to by pwOldCW. + { + uword wTemp, wSave; + + __asm fstcw wSave + if (wSave & 0x300 || // Not single mode + 0x3f != (wSave & 0x3f) || // Exceptions enabled + wSave & 0xC00) // Not round to nearest mode + { + __asm + { + mov ax, wSave + and ax, not 300h ;; single mode + or ax, 3fh ;; disable all exceptions + and ax, not 0xC00 ;; round to nearest mode + mov wTemp, ax + fldcw wTemp + } + } + } + } +*/ + //! This function computes the slowest possible floating-point value (you can also directly use FLT_EPSILON) + inline_ float ComputeFloatEpsilon() + { + float f = 1.0f; + ((udword&)f)^=1; + return f - 1.0f; // You can check it's the same as FLT_EPSILON + } + + inline_ bool IsFloatZero(float x, float epsilon=1e-6f) + { + return x*x < epsilon; + } + + #define FCOMI_ST0 _asm _emit 0xdb _asm _emit 0xf0 + #define FCOMIP_ST0 _asm _emit 0xdf _asm _emit 0xf0 + #define FCMOVB_ST0 _asm _emit 0xda _asm _emit 0xc0 + #define FCMOVNB_ST0 _asm _emit 0xdb _asm _emit 0xc0 + + #define FCOMI_ST1 _asm _emit 0xdb _asm _emit 0xf1 + #define FCOMIP_ST1 _asm _emit 0xdf _asm _emit 0xf1 + #define FCMOVB_ST1 _asm _emit 0xda _asm _emit 0xc1 + #define FCMOVNB_ST1 _asm _emit 0xdb _asm _emit 0xc1 + + #define FCOMI_ST2 _asm _emit 0xdb _asm _emit 0xf2 + #define FCOMIP_ST2 _asm _emit 0xdf _asm _emit 0xf2 + #define FCMOVB_ST2 _asm _emit 0xda _asm _emit 0xc2 + #define FCMOVNB_ST2 _asm _emit 0xdb _asm _emit 0xc2 + + #define FCOMI_ST3 _asm _emit 0xdb _asm _emit 0xf3 + #define FCOMIP_ST3 _asm _emit 0xdf _asm _emit 0xf3 + #define FCMOVB_ST3 _asm _emit 0xda _asm _emit 0xc3 + #define FCMOVNB_ST3 _asm _emit 0xdb _asm _emit 0xc3 + + #define FCOMI_ST4 _asm _emit 0xdb _asm _emit 0xf4 + #define FCOMIP_ST4 _asm _emit 0xdf _asm _emit 0xf4 + #define FCMOVB_ST4 _asm _emit 0xda _asm _emit 0xc4 + #define FCMOVNB_ST4 _asm _emit 0xdb _asm _emit 0xc4 + + #define FCOMI_ST5 _asm _emit 0xdb _asm _emit 0xf5 + #define FCOMIP_ST5 _asm _emit 0xdf _asm _emit 0xf5 + #define FCMOVB_ST5 _asm _emit 0xda _asm _emit 0xc5 + #define FCMOVNB_ST5 _asm _emit 0xdb _asm _emit 0xc5 + + #define FCOMI_ST6 _asm _emit 0xdb _asm _emit 0xf6 + #define FCOMIP_ST6 _asm _emit 0xdf _asm _emit 0xf6 + #define FCMOVB_ST6 _asm _emit 0xda _asm _emit 0xc6 + #define FCMOVNB_ST6 _asm _emit 0xdb _asm _emit 0xc6 + + #define FCOMI_ST7 _asm _emit 0xdb _asm _emit 0xf7 + #define FCOMIP_ST7 _asm _emit 0xdf _asm _emit 0xf7 + #define FCMOVB_ST7 _asm _emit 0xda _asm _emit 0xc7 + #define FCMOVNB_ST7 _asm _emit 0xdb _asm _emit 0xc7 + + //! A global function to find MAX(a,b) using FCOMI/FCMOV + inline_ float FCMax2(float a, float b) + { +#if defined(_MSC_VER) && 0 // ericf disabling + float Res; + _asm fld [a] + _asm fld [b] + FCOMI_ST1 + FCMOVB_ST1 + _asm fstp [Res] + _asm fcomp + return Res; +#else + return (a > b) ? a : b; +#endif + } + + //! A global function to find MIN(a,b) using FCOMI/FCMOV + inline_ float FCMin2(float a, float b) + { +#if defined(_MSC_VER) && 0 // ericf disabling + float Res; + _asm fld [a] + _asm fld [b] + FCOMI_ST1 + FCMOVNB_ST1 + _asm fstp [Res] + _asm fcomp + return Res; +#else + return (a < b) ? a : b; +#endif + } + + //! A global function to find MAX(a,b,c) using FCOMI/FCMOV + inline_ float FCMax3(float a, float b, float c) + { +#if defined(_MSC_VER) && 0 // ericf disabling + float Res; + _asm fld [a] + _asm fld [b] + _asm fld [c] + FCOMI_ST1 + FCMOVB_ST1 + FCOMI_ST2 + FCMOVB_ST2 + _asm fstp [Res] + _asm fcompp + return Res; +#else + return (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c); +#endif + } + + //! A global function to find MIN(a,b,c) using FCOMI/FCMOV + inline_ float FCMin3(float a, float b, float c) + { +#if defined(_MSC_VER) && 0 // ericf disabling + float Res; + _asm fld [a] + _asm fld [b] + _asm fld [c] + FCOMI_ST1 + FCMOVNB_ST1 + FCOMI_ST2 + FCMOVNB_ST2 + _asm fstp [Res] + _asm fcompp + return Res; +#else + return (a < b) ? ((a < c) ? a : c) : ((b < c) ? b : c); +#endif + } + + inline_ int ConvertToSortable(float f) + { + int& Fi = (int&)f; + int Fmask = (Fi>>31); + Fi ^= Fmask; + Fmask &= ~(1<<31); + Fi -= Fmask; + return Fi; + } + + enum FPUMode + { + FPU_FLOOR = 0, + FPU_CEIL = 1, + FPU_BEST = 2, + + FPU_FORCE_DWORD = 0x7fffffff + }; + + FUNCTION ICECORE_API FPUMode GetFPUMode(); + FUNCTION ICECORE_API void SaveFPU(); + FUNCTION ICECORE_API void RestoreFPU(); + FUNCTION ICECORE_API void SetFPUFloorMode(); + FUNCTION ICECORE_API void SetFPUCeilMode(); + FUNCTION ICECORE_API void SetFPUBestMode(); + + FUNCTION ICECORE_API void SetFPUPrecision24(); + FUNCTION ICECORE_API void SetFPUPrecision53(); + FUNCTION ICECORE_API void SetFPUPrecision64(); + FUNCTION ICECORE_API void SetFPURoundingChop(); + FUNCTION ICECORE_API void SetFPURoundingUp(); + FUNCTION ICECORE_API void SetFPURoundingDown(); + FUNCTION ICECORE_API void SetFPURoundingNear(); + + FUNCTION ICECORE_API int intChop(const float& f); + FUNCTION ICECORE_API int intFloor(const float& f); + FUNCTION ICECORE_API int intCeil(const float& f); + +#endif // __ICEFPU_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceHPoint.cpp b/src/external/open_dynamics_engine-ef/ode/IceHPoint.cpp new file mode 100644 index 00000000..79d60cf3 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceHPoint.cpp @@ -0,0 +1,77 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for homogeneous points. + * \file IceHPoint.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Homogeneous point. + * + * Use it: + * - for clipping in homogeneous space (standard way) + * - to differentiate between points (w=1) and vectors (w=0). + * - in some cases you can also use it instead of Point for padding reasons. + * + * \class HPoint + * \author Pierre Terdiman + * \version 1.0 + * \warning No cross-product in 4D. + * \warning HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Point Mul = HPoint * Matrix3x3; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Point HPoint::operator*(const Matrix3x3& mat) const +{ + return Point( + x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0], + x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1], + x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] ); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HPoint Mul = HPoint * Matrix4x4; +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HPoint HPoint::operator*(const Matrix4x4& mat) const +{ + return HPoint( + x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0], + x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1], + x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2], + x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3]); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// HPoint *= Matrix4x4 +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HPoint& HPoint::operator*=(const Matrix4x4& mat) +{ + float xp = x * mat.m[0][0] + y * mat.m[1][0] + z * mat.m[2][0] + w * mat.m[3][0]; + float yp = x * mat.m[0][1] + y * mat.m[1][1] + z * mat.m[2][1] + w * mat.m[3][1]; + float zp = x * mat.m[0][2] + y * mat.m[1][2] + z * mat.m[2][2] + w * mat.m[3][2]; + float wp = x * mat.m[0][3] + y * mat.m[1][3] + z * mat.m[2][3] + w * mat.m[3][3]; + + x = xp; y = yp; z = zp; w = wp; + + return *this; +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceHPoint.h b/src/external/open_dynamics_engine-ef/ode/IceHPoint.h new file mode 100644 index 00000000..c2248e07 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceHPoint.h @@ -0,0 +1,161 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for homogeneous points. + * \file IceHPoint.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEHPOINT_H__ +#define __ICEHPOINT_H__ + + class ICEMATHS_API HPoint : public Point + { + public: + + //! Empty constructor + inline_ HPoint() {} + //! Constructor from floats + inline_ HPoint(float _x, float _y, float _z, float _w=0.0f) : Point(_x, _y, _z), w(_w) {} + //! Constructor from array + inline_ HPoint(const float f[4]) : Point(f), w(f[3]) {} + //! Constructor from a Point + inline_ HPoint(const Point& p, float _w=0.0f) : Point(p), w(_w) {} + //! Destructor + inline_ ~HPoint() {} + + //! Clear the point + inline_ HPoint& Zero() { x = y = z = w = 0.0f; return *this; } + + //! Assignment from values + inline_ HPoint& Set(float _x, float _y, float _z, float _w ) { x = _x; y = _y; z = _z; w = _w; return *this; } + //! Assignment from array + inline_ HPoint& Set(const float f[4]) { x = f[_X]; y = f[_Y]; z = f[_Z]; w = f[_W]; return *this; } + //! Assignment from another h-point + inline_ HPoint& Set(const HPoint& src) { x = src.x; y = src.y; z = src.z; w = src.w; return *this; } + + //! Add a vector + inline_ HPoint& Add(float _x, float _y, float _z, float _w ) { x += _x; y += _y; z += _z; w += _w; return *this; } + //! Add a vector + inline_ HPoint& Add(const float f[4]) { x += f[_X]; y += f[_Y]; z += f[_Z]; w += f[_W]; return *this; } + + //! Subtract a vector + inline_ HPoint& Sub(float _x, float _y, float _z, float _w ) { x -= _x; y -= _y; z -= _z; w -= _w; return *this; } + //! Subtract a vector + inline_ HPoint& Sub(const float f[4]) { x -= f[_X]; y -= f[_Y]; z -= f[_Z]; w -= f[_W]; return *this; } + + //! Multiplies by a scalar + inline_ HPoint& Mul(float s) { x *= s; y *= s; z *= s; w *= s; return *this; } + + //! Returns MIN(x, y, z, w); + float Min() const { return MIN(x, MIN(y, MIN(z, w))); } + //! Returns MAX(x, y, z, w); + float Max() const { return MAX(x, MAX(y, MAX(z, w))); } + //! Sets each element to be componentwise minimum + HPoint& Min(const HPoint& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); w = MIN(w, p.w); return *this; } + //! Sets each element to be componentwise maximum + HPoint& Max(const HPoint& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); w = MAX(w, p.w); return *this; } + + //! Computes square magnitude + inline_ float SquareMagnitude() const { return x*x + y*y + z*z + w*w; } + //! Computes magnitude + inline_ float Magnitude() const { return sqrtf(x*x + y*y + z*z + w*w); } + + //! Normalize the vector + inline_ HPoint& Normalize() + { + float M = Magnitude(); + if(M) + { + M = 1.0f / M; + x *= M; + y *= M; + z *= M; + w *= M; + } + return *this; + } + + // Arithmetic operators + //! Operator for HPoint Negate = - HPoint; + inline_ HPoint operator-() const { return HPoint(-x, -y, -z, -w); } + + //! Operator for HPoint Plus = HPoint + HPoint; + inline_ HPoint operator+(const HPoint& p) const { return HPoint(x + p.x, y + p.y, z + p.z, w + p.w); } + //! Operator for HPoint Minus = HPoint - HPoint; + inline_ HPoint operator-(const HPoint& p) const { return HPoint(x - p.x, y - p.y, z - p.z, w - p.w); } + + //! Operator for HPoint Mul = HPoint * HPoint; + inline_ HPoint operator*(const HPoint& p) const { return HPoint(x * p.x, y * p.y, z * p.z, w * p.w); } + //! Operator for HPoint Scale = HPoint * float; + inline_ HPoint operator*(float s) const { return HPoint(x * s, y * s, z * s, w * s); } + //! Operator for HPoint Scale = float * HPoint; + inline_ friend HPoint operator*(float s, const HPoint& p) { return HPoint(s * p.x, s * p.y, s * p.z, s * p.w); } + + //! Operator for HPoint Div = HPoint / HPoint; + inline_ HPoint operator/(const HPoint& p) const { return HPoint(x / p.x, y / p.y, z / p.z, w / p.w); } + //! Operator for HPoint Scale = HPoint / float; + inline_ HPoint operator/(float s) const { s = 1.0f / s; return HPoint(x * s, y * s, z * s, w * s); } + //! Operator for HPoint Scale = float / HPoint; + inline_ friend HPoint operator/(float s, const HPoint& p) { return HPoint(s / p.x, s / p.y, s / p.z, s / p.w); } + + //! Operator for float DotProd = HPoint | HPoint; + inline_ float operator|(const HPoint& p) const { return x*p.x + y*p.y + z*p.z + w*p.w; } + // No cross-product in 4D + + //! Operator for HPoint += HPoint; + inline_ HPoint& operator+=(const HPoint& p) { x += p.x; y += p.y; z += p.z; w += p.w; return *this; } + //! Operator for HPoint += float; + inline_ HPoint& operator+=(float s) { x += s; y += s; z += s; w += s; return *this; } + + //! Operator for HPoint -= HPoint; + inline_ HPoint& operator-=(const HPoint& p) { x -= p.x; y -= p.y; z -= p.z; w -= p.w; return *this; } + //! Operator for HPoint -= float; + inline_ HPoint& operator-=(float s) { x -= s; y -= s; z -= s; w -= s; return *this; } + + //! Operator for HPoint *= HPoint; + inline_ HPoint& operator*=(const HPoint& p) { x *= p.x; y *= p.y; z *= p.z; w *= p.w; return *this; } + //! Operator for HPoint *= float; + inline_ HPoint& operator*=(float s) { x*=s; y*=s; z*=s; w*=s; return *this; } + + //! Operator for HPoint /= HPoint; + inline_ HPoint& operator/=(const HPoint& p) { x /= p.x; y /= p.y; z /= p.z; w /= p.w; return *this; } + //! Operator for HPoint /= float; + inline_ HPoint& operator/=(float s) { s = 1.0f / s; x*=s; y*=s; z*=s; w*=s; return *this; } + + // Arithmetic operators + + //! Operator for Point Mul = HPoint * Matrix3x3; + Point operator*(const Matrix3x3& mat) const; + //! Operator for HPoint Mul = HPoint * Matrix4x4; + HPoint operator*(const Matrix4x4& mat) const; + + // HPoint *= Matrix3x3 doesn't exist, the matrix is first casted to a 4x4 + //! Operator for HPoint *= Matrix4x4 + HPoint& operator*=(const Matrix4x4& mat); + + // Logical operators + + //! Operator for "if(HPoint==HPoint)" + inline_ bool operator==(const HPoint& p) const { return ( (x==p.x)&&(y==p.y)&&(z==p.z)&&(w==p.w)); } + //! Operator for "if(HPoint!=HPoint)" + inline_ bool operator!=(const HPoint& p) const { return ( (x!=p.x)||(y!=p.y)||(z!=p.z)||(w!=p.w)); } + + // Cast operators + + //! Cast a HPoint to a Point. w is discarded. +//#ifdef _MSC_VER + // ericf disabled + //inline_ operator Point() const { return Point(x, y, z); } + // gcc complains that conversion to a base class will never use a type conversion operator +//#endif + + public: + float w; + }; + +#endif // __ICEHPOINT_H__ + diff --git a/src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.cpp b/src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.cpp new file mode 100644 index 00000000..7e5012b7 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.cpp @@ -0,0 +1,556 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a handy indexed triangle class. + * \file IceIndexedTriangle.cpp + * \author Pierre Terdiman + * \date January, 17, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains an indexed triangle class. + * + * \class Triangle + * \author Pierre Terdiman + * \version 1.0 + * \date 08.15.98 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Flips the winding order. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::Flip() +{ + Swap(mVRef[1], mVRef[2]); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle area. + * \param verts [in] the list of indexed vertices + * \return the area + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::Area(const Point* verts) const +{ + if(!verts) return 0.0f; + const Point& p0 = verts[0]; + const Point& p1 = verts[1]; + const Point& p2 = verts[2]; + return ((p0-p1)^(p0-p2)).Magnitude() * 0.5f; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle perimeter. + * \param verts [in] the list of indexed vertices + * \return the perimeter + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::Perimeter(const Point* verts) const +{ + if(!verts) return 0.0f; + const Point& p0 = verts[0]; + const Point& p1 = verts[1]; + const Point& p2 = verts[2]; + return p0.Distance(p1) + + p0.Distance(p2) + + p1.Distance(p2); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle compacity. + * \param verts [in] the list of indexed vertices + * \return the compacity + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::Compacity(const Point* verts) const +{ + if(!verts) return 0.0f; + float P = Perimeter(verts); + if(P==0.0f) return 0.0f; + return (4.0f*PI*Area(verts)/(P*P)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle normal. + * \param verts [in] the list of indexed vertices + * \param normal [out] the computed normal + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::Normal(const Point* verts, Point& normal) const +{ + if(!verts) return; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + normal = ((p2-p1)^(p0-p1)).Normalize(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle denormalized normal. + * \param verts [in] the list of indexed vertices + * \param normal [out] the computed normal + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::DenormalizedNormal(const Point* verts, Point& normal) const +{ + if(!verts) return; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + normal = ((p2-p1)^(p0-p1)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle center. + * \param verts [in] the list of indexed vertices + * \param center [out] the computed center + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::Center(const Point* verts, Point& center) const +{ + if(!verts) return; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + center = (p0+p1+p2)*INV3; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the centered normal + * \param verts [in] the list of indexed vertices + * \param normal [out] the computed centered normal + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::CenteredNormal(const Point* verts, Point& normal) const +{ + if(!verts) return; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + Point Center = (p0+p1+p2)*INV3; + normal = Center + ((p2-p1)^(p0-p1)).Normalize(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes a random point within the triangle. + * \param verts [in] the list of indexed vertices + * param normal [out] the computed centered normal + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::RandomPoint(const Point* verts, Point& random) const +{ + if(!verts) return; + + // Random barycentric coords + float Alpha = UnitRandomFloat(); + float Beta = UnitRandomFloat(); + float Gamma = UnitRandomFloat(); + float OneOverTotal = 1.0f / (Alpha + Beta + Gamma); + Alpha *= OneOverTotal; + Beta *= OneOverTotal; + Gamma *= OneOverTotal; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + random = Alpha*p0 + Beta*p1 + Gamma*p2; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes backface culling. + * \param verts [in] the list of indexed vertices + * \param source [in] source point (in local space) from which culling must be computed + * \return true if the triangle is visible from the source point + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::IsVisible(const Point* verts, const Point& source) const +{ + // Checkings + if(!verts) return false; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + + // Compute denormalized normal + Point Normal = (p2 - p1)^(p0 - p1); + + // Backface culling + return (Normal | source) >= 0.0f; + +// Same as: +// Plane PL(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); +// return PL.Distance(source) > PL.d; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes backface culling. + * \param verts [in] the list of indexed vertices + * \param source [in] source point (in local space) from which culling must be computed + * \return true if the triangle is visible from the source point + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::BackfaceCulling(const Point* verts, const Point& source) const +{ + // Checkings + if(!verts) return false; + + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + + // Compute base +// Point Base = (p0 + p1 + p2)*INV3; + + // Compute denormalized normal + Point Normal = (p2 - p1)^(p0 - p1); + + // Backface culling +// return (Normal | (source - Base)) >= 0.0f; + return (Normal | (source - p0)) >= 0.0f; + +// Same as: (but a bit faster) +// Plane PL(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); +// return PL.Distance(source)>0.0f; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the occlusion potential of the triangle. + * \param verts [in] the list of indexed vertices + * param source [in] source point (in local space) from which occlusion potential must be computed + * \return the occlusion potential + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::ComputeOcclusionPotential(const Point* verts, const Point& view) const +{ + if(!verts) return 0.0f; + // Occlusion potential: -(A * (N|V) / d^2) + // A = polygon area + // N = polygon normal + // V = view vector + // d = distance viewpoint-center of polygon + + float A = Area(verts); + Point N; Normal(verts, N); + Point C; Center(verts, C); + float d = view.Distance(C); + return -(A*(N|view))/(d*d); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Replaces a vertex reference with another one. + * \param oldref [in] the vertex reference to replace + * \param newref [in] the new vertex reference + * \return true if success, else false if the input vertex reference doesn't belong to the triangle + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::ReplaceVertex(udword oldref, udword newref) +{ + if(mVRef[0]==oldref) { mVRef[0] = newref; return true; } + else if(mVRef[1]==oldref) { mVRef[1] = newref; return true; } + else if(mVRef[2]==oldref) { mVRef[2] = newref; return true; } + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks whether the triangle is degenerate or not. A degenerate triangle has two common vertex references. This is a zero-area triangle. + * \return true if the triangle is degenerate + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::IsDegenerate() const +{ + if(mVRef[0]==mVRef[1]) return true; + if(mVRef[1]==mVRef[2]) return true; + if(mVRef[2]==mVRef[0]) return true; + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks whether the input vertex reference belongs to the triangle or not. + * \param ref [in] the vertex reference to look for + * \return true if the triangle contains the vertex reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::HasVertex(udword ref) const +{ + if(mVRef[0]==ref) return true; + if(mVRef[1]==ref) return true; + if(mVRef[2]==ref) return true; + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks whether the input vertex reference belongs to the triangle or not. + * \param ref [in] the vertex reference to look for + * \param index [out] the corresponding index in the triangle + * \return true if the triangle contains the vertex reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::HasVertex(udword ref, udword* index) const +{ + if(mVRef[0]==ref) { *index = 0; return true; } + if(mVRef[1]==ref) { *index = 1; return true; } + if(mVRef[2]==ref) { *index = 2; return true; } + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Finds an edge in a tri, given two vertex references. + * \param vref0 [in] the edge's first vertex reference + * \param vref1 [in] the edge's second vertex reference + * \return the edge number between 0 and 2, or 0xff if input refs are wrong. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +ubyte IndexedTriangle::FindEdge(udword vref0, udword vref1) const +{ + if(mVRef[0]==vref0 && mVRef[1]==vref1) return 0; + else if(mVRef[0]==vref1 && mVRef[1]==vref0) return 0; + else if(mVRef[0]==vref0 && mVRef[2]==vref1) return 1; + else if(mVRef[0]==vref1 && mVRef[2]==vref0) return 1; + else if(mVRef[1]==vref0 && mVRef[2]==vref1) return 2; + else if(mVRef[1]==vref1 && mVRef[2]==vref0) return 2; + return 0xff; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets the last reference given the first two. + * \param vref0 [in] the first vertex reference + * \param vref1 [in] the second vertex reference + * \return the last reference, or INVALID_ID if input refs are wrong. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword IndexedTriangle::OppositeVertex(udword vref0, udword vref1) const +{ + if(mVRef[0]==vref0 && mVRef[1]==vref1) return mVRef[2]; + else if(mVRef[0]==vref1 && mVRef[1]==vref0) return mVRef[2]; + else if(mVRef[0]==vref0 && mVRef[2]==vref1) return mVRef[1]; + else if(mVRef[0]==vref1 && mVRef[2]==vref0) return mVRef[1]; + else if(mVRef[1]==vref0 && mVRef[2]==vref1) return mVRef[0]; + else if(mVRef[1]==vref1 && mVRef[2]==vref0) return mVRef[0]; + return INVALID_ID; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets the three sorted vertex references according to an edge number. + * edgenb = 0 => edge 0-1, returns references 0, 1, 2 + * edgenb = 1 => edge 0-2, returns references 0, 2, 1 + * edgenb = 2 => edge 1-2, returns references 1, 2, 0 + * + * \param edgenb [in] the edge number, 0, 1 or 2 + * \param vref0 [out] the returned first vertex reference + * \param vref1 [out] the returned second vertex reference + * \param vref2 [out] the returned third vertex reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::GetVRefs(ubyte edgenb, udword& vref0, udword& vref1, udword& vref2) const +{ + if(edgenb==0) + { + vref0 = mVRef[0]; + vref1 = mVRef[1]; + vref2 = mVRef[2]; + } + else if(edgenb==1) + { + vref0 = mVRef[0]; + vref1 = mVRef[2]; + vref2 = mVRef[1]; + } + else if(edgenb==2) + { + vref0 = mVRef[1]; + vref1 = mVRef[2]; + vref2 = mVRef[0]; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle's smallest edge length. + * \param verts [in] the list of indexed vertices + * \return the smallest edge length + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::MinEdgeLength(const Point* verts) const +{ + if(!verts) return 0.0f; + + float Min = MAX_FLOAT; + float Length01 = verts[0].Distance(verts[1]); + float Length02 = verts[0].Distance(verts[2]); + float Length12 = verts[1].Distance(verts[2]); + if(Length01 < Min) Min = Length01; + if(Length02 < Min) Min = Length02; + if(Length12 < Min) Min = Length12; + return Min; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle's largest edge length. + * \param verts [in] the list of indexed vertices + * \return the largest edge length + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::MaxEdgeLength(const Point* verts) const +{ + if(!verts) return 0.0f; + + float Max = MIN_FLOAT; + float Length01 = verts[0].Distance(verts[1]); + float Length02 = verts[0].Distance(verts[2]); + float Length12 = verts[1].Distance(verts[2]); + if(Length01 > Max) Max = Length01; + if(Length02 > Max) Max = Length02; + if(Length12 > Max) Max = Length12; + return Max; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes a point on the triangle according to the stabbing information. + * \param verts [in] the list of indexed vertices + * param u,v [in] point's barycentric coordinates + * \param pt [out] point on triangle + * \param nearvtx [out] index of nearest vertex + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void IndexedTriangle::ComputePoint(const Point* verts, float u, float v, Point& pt, udword* nearvtx) const +{ + // Checkings + if(!verts) return; + + // Get face in local or global space + const Point& p0 = verts[mVRef[0]]; + const Point& p1 = verts[mVRef[1]]; + const Point& p2 = verts[mVRef[2]]; + + // Compute point coordinates + pt = (1.0f - u - v)*p0 + u*p1 + v*p2; + + // Compute nearest vertex if needed + if(nearvtx) + { + // Compute distance vector + Point d(p0.SquareDistance(pt), // Distance^2 from vertex 0 to point on the face + p1.SquareDistance(pt), // Distance^2 from vertex 1 to point on the face + p2.SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face + + // Get smallest distance + *nearvtx = mVRef[d.SmallestAxis()]; + } +} + + //************************************** + // Angle between two vectors (in radians) + // we use this formula + // uv = |u||v| cos(u,v) + // u ^ v = w + // |w| = |u||v| |sin(u,v)| + //************************************** + float Angle(const Point& u, const Point& v) + { + float NormU = u.Magnitude(); // |u| + float NormV = v.Magnitude(); // |v| + float Product = NormU*NormV; // |u||v| + if(Product==0.0f) return 0.0f; + float OneOverProduct = 1.0f / Product; + + // Cosinus + float Cosinus = (u|v) * OneOverProduct; + + // Sinus + Point w = u^v; + float NormW = w.Magnitude(); + + float AbsSinus = NormW * OneOverProduct; + + // Remove degeneracy + if(AbsSinus > 1.0f) AbsSinus = 1.0f; + if(AbsSinus < -1.0f) AbsSinus = -1.0f; + + if(Cosinus>=0.0f) return asinf(AbsSinus); + else return (PI-asinf(AbsSinus)); + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the angle between two triangles. + * \param tri [in] the other triangle + * \param verts [in] the list of indexed vertices + * \return the angle in radians + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float IndexedTriangle::Angle(const IndexedTriangle& tri, const Point* verts) const +{ + // Checkings + if(!verts) return 0.0f; + + // Compute face normals + Point n0, n1; + Normal(verts, n0); + tri.Normal(verts, n1); + + // Compute angle + float dp = n0|n1; + if(dp>1.0f) return 0.0f; + if(dp<-1.0f) return PI; + return acosf(dp); + +// return ::Angle(n0,n1); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks a triangle is the same as another one. + * \param tri [in] the other triangle + * \return true if same triangle + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool IndexedTriangle::Equal(const IndexedTriangle& tri) const +{ + // Test all vertex references + return (HasVertex(tri.mVRef[0]) && + HasVertex(tri.mVRef[1]) && + HasVertex(tri.mVRef[2])); +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.h b/src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.h new file mode 100644 index 00000000..b34c485d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceIndexedTriangle.h @@ -0,0 +1,72 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a handy indexed triangle class. + * \file IceIndexedTriangle.h + * \author Pierre Terdiman + * \date January, 17, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEINDEXEDTRIANGLE_H__ +#define __ICEINDEXEDTRIANGLE_H__ + + // Forward declarations +#ifdef _MSC_VER + enum CubeIndex; +#else + typedef int CubeIndex; +#endif + + // An indexed triangle class. + class ICEMATHS_API IndexedTriangle + { + public: + //! Constructor + inline_ IndexedTriangle() {} + //! Constructor + inline_ IndexedTriangle(udword r0, udword r1, udword r2) { mVRef[0]=r0; mVRef[1]=r1; mVRef[2]=r2; } + //! Copy constructor + inline_ IndexedTriangle(const IndexedTriangle& triangle) + { + mVRef[0] = triangle.mVRef[0]; + mVRef[1] = triangle.mVRef[1]; + mVRef[2] = triangle.mVRef[2]; + } + //! Destructor + inline_ ~IndexedTriangle() {} + //! Vertex-references + udword mVRef[3]; + + // Methods + void Flip(); + float Area(const Point* verts) const; + float Perimeter(const Point* verts) const; + float Compacity(const Point* verts) const; + void Normal(const Point* verts, Point& normal) const; + void DenormalizedNormal(const Point* verts, Point& normal) const; + void Center(const Point* verts, Point& center) const; + void CenteredNormal(const Point* verts, Point& normal) const; + void RandomPoint(const Point* verts, Point& random) const; + bool IsVisible(const Point* verts, const Point& source) const; + bool BackfaceCulling(const Point* verts, const Point& source) const; + float ComputeOcclusionPotential(const Point* verts, const Point& view) const; + bool ReplaceVertex(udword oldref, udword newref); + bool IsDegenerate() const; + bool HasVertex(udword ref) const; + bool HasVertex(udword ref, udword* index) const; + ubyte FindEdge(udword vref0, udword vref1) const; + udword OppositeVertex(udword vref0, udword vref1) const; + inline_ udword OppositeVertex(ubyte edgenb) const { return mVRef[2-edgenb]; } + void GetVRefs(ubyte edgenb, udword& vref0, udword& vref1, udword& vref2) const; + float MinEdgeLength(const Point* verts) const; + float MaxEdgeLength(const Point* verts) const; + void ComputePoint(const Point* verts, float u, float v, Point& pt, udword* nearvtx=null) const; + float Angle(const IndexedTriangle& tri, const Point* verts) const; + inline_ Plane PlaneEquation(const Point* verts) const { return Plane(verts[mVRef[0]], verts[mVRef[1]], verts[mVRef[2]]); } + bool Equal(const IndexedTriangle& tri) const; + CubeIndex ComputeCubeIndex(const Point* verts) const; + }; + +#endif // __ICEINDEXEDTRIANGLE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceLSS.h b/src/external/open_dynamics_engine-ef/ode/IceLSS.h new file mode 100644 index 00000000..bd260c1e --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceLSS.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for line-swept spheres. + * \file IceLSS.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICELSS_H__ +#define __ICELSS_H__ + + class ICEMATHS_API LSS : public Segment + { + public: + //! Constructor + inline_ LSS() {} + //! Constructor + inline_ LSS(const Segment& seg, float radius) : Segment(seg), mRadius(radius) {} + //! Destructor + inline_ ~LSS() {} + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes an OBB surrounding the LSS. + * \param box [out] the OBB + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void ComputeOBB(OBB& box); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if a point is contained within the LSS. + * \param pt [in] the point to test + * \return true if inside the LSS + * \warning point and LSS must be in same space + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool Contains(const Point& pt) const { return SquareDistance(pt) <= mRadius*mRadius; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if a sphere is contained within the LSS. + * \param sphere [in] the sphere to test + * \return true if inside the LSS + * \warning sphere and LSS must be in same space + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool Contains(const Sphere& sphere) + { + float d = mRadius - sphere.mRadius; + if(d>=0.0f) return SquareDistance(sphere.mCenter) <= d*d; + else return false; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if an LSS is contained within the LSS. + * \param lss [in] the LSS to test + * \return true if inside the LSS + * \warning both LSS must be in same space + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ bool Contains(const LSS& lss) + { + // We check the LSS contains the two spheres at the start and end of the sweep + return Contains(Sphere(lss.mP0, lss.mRadius)) && Contains(Sphere(lss.mP0, lss.mRadius)); + } + + float mRadius; //!< Sphere radius + }; + +#endif // __ICELSS_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.cpp b/src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.cpp new file mode 100644 index 00000000..bd9ce41d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.cpp @@ -0,0 +1,56 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for 3x3 matrices. + * \file IceMatrix3x3.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 3x3 matrix. + * DirectX-compliant, ie row-column order, ie m[Row][Col]. + * Same as: + * m11 m12 m13 first row. + * m21 m22 m23 second row. + * m31 m32 m33 third row. + * Stored in memory as m11 m12 m13 m21... + * + * Multiplication rules: + * + * [x'y'z'] = [xyz][M] + * + * x' = x*m11 + y*m21 + z*m31 + * y' = x*m12 + y*m22 + z*m32 + * z' = x*m13 + y*m23 + z*m33 + * + * \class Matrix3x3 + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +// Cast operator +Matrix3x3::operator Matrix4x4() const +{ + return Matrix4x4( + m[0][0], m[0][1], m[0][2], 0.0f, + m[1][0], m[1][1], m[1][2], 0.0f, + m[2][0], m[2][1], m[2][2], 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.h b/src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.h new file mode 100644 index 00000000..a30680da --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceMatrix3x3.h @@ -0,0 +1,496 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for 3x3 matrices. + * \file IceMatrix3x3.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEMATRIX3X3_H__ +#define __ICEMATRIX3X3_H__ + + // Forward declarations + class Quat; + + #define MATRIX3X3_EPSILON (1.0e-7f) + + class ICEMATHS_API Matrix3x3 + { + public: + //! Empty constructor + inline_ Matrix3x3() {} + //! Constructor from 9 values + inline_ Matrix3x3(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) + { + m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; + m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; + m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; + } + //! Copy constructor + inline_ Matrix3x3(const Matrix3x3& mat) { CopyMemory(m, &mat.m, 9*sizeof(float)); } + //! Destructor + inline_ ~Matrix3x3() {} + + //! Assign values + inline_ void Set(float m00, float m01, float m02, float m10, float m11, float m12, float m20, float m21, float m22) + { + m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; + m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; + m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; + } + + //! Sets the scale from a Point. The point is put on the diagonal. + inline_ void SetScale(const Point& p) { m[0][0] = p.x; m[1][1] = p.y; m[2][2] = p.z; } + + //! Sets the scale from floats. Values are put on the diagonal. + inline_ void SetScale(float sx, float sy, float sz) { m[0][0] = sx; m[1][1] = sy; m[2][2] = sz; } + + //! Scales from a Point. Each row is multiplied by a component. + inline_ void Scale(const Point& p) + { + m[0][0] *= p.x; m[0][1] *= p.x; m[0][2] *= p.x; + m[1][0] *= p.y; m[1][1] *= p.y; m[1][2] *= p.y; + m[2][0] *= p.z; m[2][1] *= p.z; m[2][2] *= p.z; + } + + //! Scales from floats. Each row is multiplied by a value. + inline_ void Scale(float sx, float sy, float sz) + { + m[0][0] *= sx; m[0][1] *= sx; m[0][2] *= sx; + m[1][0] *= sy; m[1][1] *= sy; m[1][2] *= sy; + m[2][0] *= sz; m[2][1] *= sz; m[2][2] *= sz; + } + + //! Copy from a Matrix3x3 + inline_ void Copy(const Matrix3x3& source) { CopyMemory(m, source.m, 9*sizeof(float)); } + + // Row-column access + //! Returns a row. + inline_ void GetRow(const udword r, Point& p) const { p.x = m[r][0]; p.y = m[r][1]; p.z = m[r][2]; } + //! Returns a row. + inline_ const Point& GetRow(const udword r) const { return *(const Point*)&m[r][0]; } + //! Returns a row. + inline_ Point& GetRow(const udword r) { return *(Point*)&m[r][0]; } + //! Sets a row. + inline_ void SetRow(const udword r, const Point& p) { m[r][0] = p.x; m[r][1] = p.y; m[r][2] = p.z; } + //! Returns a column. + inline_ void GetCol(const udword c, Point& p) const { p.x = m[0][c]; p.y = m[1][c]; p.z = m[2][c]; } + //! Sets a column. + inline_ void SetCol(const udword c, const Point& p) { m[0][c] = p.x; m[1][c] = p.y; m[2][c] = p.z; } + + //! Computes the trace. The trace is the sum of the 3 diagonal components. + inline_ float Trace() const { return m[0][0] + m[1][1] + m[2][2]; } + //! Clears the matrix. + inline_ void Zero() { ZeroMemory(&m, sizeof(m)); } + //! Sets the identity matrix. + inline_ void Identity() { Zero(); m[0][0] = m[1][1] = m[2][2] = 1.0f; } + //! Checks for identity + inline_ bool IsIdentity() const + { + if(IR(m[0][0])!=IEEE_1_0) return false; + if(IR(m[0][1])!=0) return false; + if(IR(m[0][2])!=0) return false; + + if(IR(m[1][0])!=0) return false; + if(IR(m[1][1])!=IEEE_1_0) return false; + if(IR(m[1][2])!=0) return false; + + if(IR(m[2][0])!=0) return false; + if(IR(m[2][1])!=0) return false; + if(IR(m[2][2])!=IEEE_1_0) return false; + + return true; + } + + //! Checks matrix validity + inline_ BOOL IsValid() const + { + for(udword j=0;j<3;j++) + { + for(udword i=0;i<3;i++) + { + if(!IsValidFloat(m[j][i])) return FALSE; + } + } + return TRUE; + } + + //! Makes a skew-symmetric matrix (a.k.a. Star(*) Matrix) + //! [ 0.0 -a.z a.y ] + //! [ a.z 0.0 -a.x ] + //! [ -a.y a.x 0.0 ] + //! This is also called a "cross matrix" since for any vectors A and B, + //! A^B = Skew(A) * B = - B * Skew(A); + inline_ void SkewSymmetric(const Point& a) + { + m[0][0] = 0.0f; + m[0][1] = -a.z; + m[0][2] = a.y; + + m[1][0] = a.z; + m[1][1] = 0.0f; + m[1][2] = -a.x; + + m[2][0] = -a.y; + m[2][1] = a.x; + m[2][2] = 0.0f; + } + + //! Negates the matrix + inline_ void Neg() + { + m[0][0] = -m[0][0]; m[0][1] = -m[0][1]; m[0][2] = -m[0][2]; + m[1][0] = -m[1][0]; m[1][1] = -m[1][1]; m[1][2] = -m[1][2]; + m[2][0] = -m[2][0]; m[2][1] = -m[2][1]; m[2][2] = -m[2][2]; + } + + //! Neg from another matrix + inline_ void Neg(const Matrix3x3& mat) + { + m[0][0] = -mat.m[0][0]; m[0][1] = -mat.m[0][1]; m[0][2] = -mat.m[0][2]; + m[1][0] = -mat.m[1][0]; m[1][1] = -mat.m[1][1]; m[1][2] = -mat.m[1][2]; + m[2][0] = -mat.m[2][0]; m[2][1] = -mat.m[2][1]; m[2][2] = -mat.m[2][2]; + } + + //! Add another matrix + inline_ void Add(const Matrix3x3& mat) + { + m[0][0] += mat.m[0][0]; m[0][1] += mat.m[0][1]; m[0][2] += mat.m[0][2]; + m[1][0] += mat.m[1][0]; m[1][1] += mat.m[1][1]; m[1][2] += mat.m[1][2]; + m[2][0] += mat.m[2][0]; m[2][1] += mat.m[2][1]; m[2][2] += mat.m[2][2]; + } + + //! Sub another matrix + inline_ void Sub(const Matrix3x3& mat) + { + m[0][0] -= mat.m[0][0]; m[0][1] -= mat.m[0][1]; m[0][2] -= mat.m[0][2]; + m[1][0] -= mat.m[1][0]; m[1][1] -= mat.m[1][1]; m[1][2] -= mat.m[1][2]; + m[2][0] -= mat.m[2][0]; m[2][1] -= mat.m[2][1]; m[2][2] -= mat.m[2][2]; + } + //! Mac + inline_ void Mac(const Matrix3x3& a, const Matrix3x3& b, float s) + { + m[0][0] = a.m[0][0] + b.m[0][0] * s; + m[0][1] = a.m[0][1] + b.m[0][1] * s; + m[0][2] = a.m[0][2] + b.m[0][2] * s; + + m[1][0] = a.m[1][0] + b.m[1][0] * s; + m[1][1] = a.m[1][1] + b.m[1][1] * s; + m[1][2] = a.m[1][2] + b.m[1][2] * s; + + m[2][0] = a.m[2][0] + b.m[2][0] * s; + m[2][1] = a.m[2][1] + b.m[2][1] * s; + m[2][2] = a.m[2][2] + b.m[2][2] * s; + } + //! Mac + inline_ void Mac(const Matrix3x3& a, float s) + { + m[0][0] += a.m[0][0] * s; m[0][1] += a.m[0][1] * s; m[0][2] += a.m[0][2] * s; + m[1][0] += a.m[1][0] * s; m[1][1] += a.m[1][1] * s; m[1][2] += a.m[1][2] * s; + m[2][0] += a.m[2][0] * s; m[2][1] += a.m[2][1] * s; m[2][2] += a.m[2][2] * s; + } + + //! this = A * s + inline_ void Mult(const Matrix3x3& a, float s) + { + m[0][0] = a.m[0][0] * s; m[0][1] = a.m[0][1] * s; m[0][2] = a.m[0][2] * s; + m[1][0] = a.m[1][0] * s; m[1][1] = a.m[1][1] * s; m[1][2] = a.m[1][2] * s; + m[2][0] = a.m[2][0] * s; m[2][1] = a.m[2][1] * s; m[2][2] = a.m[2][2] * s; + } + + inline_ void Add(const Matrix3x3& a, const Matrix3x3& b) + { + m[0][0] = a.m[0][0] + b.m[0][0]; m[0][1] = a.m[0][1] + b.m[0][1]; m[0][2] = a.m[0][2] + b.m[0][2]; + m[1][0] = a.m[1][0] + b.m[1][0]; m[1][1] = a.m[1][1] + b.m[1][1]; m[1][2] = a.m[1][2] + b.m[1][2]; + m[2][0] = a.m[2][0] + b.m[2][0]; m[2][1] = a.m[2][1] + b.m[2][1]; m[2][2] = a.m[2][2] + b.m[2][2]; + } + + inline_ void Sub(const Matrix3x3& a, const Matrix3x3& b) + { + m[0][0] = a.m[0][0] - b.m[0][0]; m[0][1] = a.m[0][1] - b.m[0][1]; m[0][2] = a.m[0][2] - b.m[0][2]; + m[1][0] = a.m[1][0] - b.m[1][0]; m[1][1] = a.m[1][1] - b.m[1][1]; m[1][2] = a.m[1][2] - b.m[1][2]; + m[2][0] = a.m[2][0] - b.m[2][0]; m[2][1] = a.m[2][1] - b.m[2][1]; m[2][2] = a.m[2][2] - b.m[2][2]; + } + + //! this = a * b + inline_ void Mult(const Matrix3x3& a, const Matrix3x3& b) + { + m[0][0] = a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[1][0] + a.m[0][2] * b.m[2][0]; + m[0][1] = a.m[0][0] * b.m[0][1] + a.m[0][1] * b.m[1][1] + a.m[0][2] * b.m[2][1]; + m[0][2] = a.m[0][0] * b.m[0][2] + a.m[0][1] * b.m[1][2] + a.m[0][2] * b.m[2][2]; + m[1][0] = a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[1][0] + a.m[1][2] * b.m[2][0]; + m[1][1] = a.m[1][0] * b.m[0][1] + a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[2][1]; + m[1][2] = a.m[1][0] * b.m[0][2] + a.m[1][1] * b.m[1][2] + a.m[1][2] * b.m[2][2]; + m[2][0] = a.m[2][0] * b.m[0][0] + a.m[2][1] * b.m[1][0] + a.m[2][2] * b.m[2][0]; + m[2][1] = a.m[2][0] * b.m[0][1] + a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[2][1]; + m[2][2] = a.m[2][0] * b.m[0][2] + a.m[2][1] * b.m[1][2] + a.m[2][2] * b.m[2][2]; + } + + //! this = transpose(a) * b + inline_ void MultAtB(const Matrix3x3& a, const Matrix3x3& b) + { + m[0][0] = a.m[0][0] * b.m[0][0] + a.m[1][0] * b.m[1][0] + a.m[2][0] * b.m[2][0]; + m[0][1] = a.m[0][0] * b.m[0][1] + a.m[1][0] * b.m[1][1] + a.m[2][0] * b.m[2][1]; + m[0][2] = a.m[0][0] * b.m[0][2] + a.m[1][0] * b.m[1][2] + a.m[2][0] * b.m[2][2]; + m[1][0] = a.m[0][1] * b.m[0][0] + a.m[1][1] * b.m[1][0] + a.m[2][1] * b.m[2][0]; + m[1][1] = a.m[0][1] * b.m[0][1] + a.m[1][1] * b.m[1][1] + a.m[2][1] * b.m[2][1]; + m[1][2] = a.m[0][1] * b.m[0][2] + a.m[1][1] * b.m[1][2] + a.m[2][1] * b.m[2][2]; + m[2][0] = a.m[0][2] * b.m[0][0] + a.m[1][2] * b.m[1][0] + a.m[2][2] * b.m[2][0]; + m[2][1] = a.m[0][2] * b.m[0][1] + a.m[1][2] * b.m[1][1] + a.m[2][2] * b.m[2][1]; + m[2][2] = a.m[0][2] * b.m[0][2] + a.m[1][2] * b.m[1][2] + a.m[2][2] * b.m[2][2]; + } + + //! this = a * transpose(b) + inline_ void MultABt(const Matrix3x3& a, const Matrix3x3& b) + { + m[0][0] = a.m[0][0] * b.m[0][0] + a.m[0][1] * b.m[0][1] + a.m[0][2] * b.m[0][2]; + m[0][1] = a.m[0][0] * b.m[1][0] + a.m[0][1] * b.m[1][1] + a.m[0][2] * b.m[1][2]; + m[0][2] = a.m[0][0] * b.m[2][0] + a.m[0][1] * b.m[2][1] + a.m[0][2] * b.m[2][2]; + m[1][0] = a.m[1][0] * b.m[0][0] + a.m[1][1] * b.m[0][1] + a.m[1][2] * b.m[0][2]; + m[1][1] = a.m[1][0] * b.m[1][0] + a.m[1][1] * b.m[1][1] + a.m[1][2] * b.m[1][2]; + m[1][2] = a.m[1][0] * b.m[2][0] + a.m[1][1] * b.m[2][1] + a.m[1][2] * b.m[2][2]; + m[2][0] = a.m[2][0] * b.m[0][0] + a.m[2][1] * b.m[0][1] + a.m[2][2] * b.m[0][2]; + m[2][1] = a.m[2][0] * b.m[1][0] + a.m[2][1] * b.m[1][1] + a.m[2][2] * b.m[1][2]; + m[2][2] = a.m[2][0] * b.m[2][0] + a.m[2][1] * b.m[2][1] + a.m[2][2] * b.m[2][2]; + } + + //! Makes a rotation matrix mapping vector "from" to vector "to". + Matrix3x3& FromTo(const Point& from, const Point& to); + + //! Set a rotation matrix around the X axis. + //! 1 0 0 + //! RX = 0 cx sx + //! 0 -sx cx + void RotX(float angle); + //! Set a rotation matrix around the Y axis. + //! cy 0 -sy + //! RY = 0 1 0 + //! sy 0 cy + void RotY(float angle); + //! Set a rotation matrix around the Z axis. + //! cz sz 0 + //! RZ = -sz cz 0 + //! 0 0 1 + void RotZ(float angle); + //! cy sx.sy -sy.cx + //! RY.RX 0 cx sx + //! sy -sx.cy cx.cy + void RotYX(float y, float x); + + //! Make a rotation matrix about an arbitrary axis + Matrix3x3& Rot(float angle, const Point& axis); + + //! Transpose the matrix. + void Transpose() + { + IR(m[1][0]) ^= IR(m[0][1]); IR(m[0][1]) ^= IR(m[1][0]); IR(m[1][0]) ^= IR(m[0][1]); + IR(m[2][0]) ^= IR(m[0][2]); IR(m[0][2]) ^= IR(m[2][0]); IR(m[2][0]) ^= IR(m[0][2]); + IR(m[2][1]) ^= IR(m[1][2]); IR(m[1][2]) ^= IR(m[2][1]); IR(m[2][1]) ^= IR(m[1][2]); + } + + //! this = Transpose(a) + void Transpose(const Matrix3x3& a) + { + m[0][0] = a.m[0][0]; m[0][1] = a.m[1][0]; m[0][2] = a.m[2][0]; + m[1][0] = a.m[0][1]; m[1][1] = a.m[1][1]; m[1][2] = a.m[2][1]; + m[2][0] = a.m[0][2]; m[2][1] = a.m[1][2]; m[2][2] = a.m[2][2]; + } + + //! Compute the determinant of the matrix. We use the rule of Sarrus. + float Determinant() const + { + return (m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] + m[0][2]*m[1][0]*m[2][1]) + - (m[2][0]*m[1][1]*m[0][2] + m[2][1]*m[1][2]*m[0][0] + m[2][2]*m[1][0]*m[0][1]); + } +/* + //! Compute a cofactor. Used for matrix inversion. + float CoFactor(ubyte row, ubyte column) const + { + static sdword gIndex[3+2] = { 0, 1, 2, 0, 1 }; + return (m[gIndex[row+1]][gIndex[column+1]]*m[gIndex[row+2]][gIndex[column+2]] - m[gIndex[row+2]][gIndex[column+1]]*m[gIndex[row+1]][gIndex[column+2]]); + } +*/ + //! Invert the matrix. Determinant must be different from zero, else matrix can't be inverted. + Matrix3x3& Invert() + { + float Det = Determinant(); // Must be !=0 + float OneOverDet = 1.0f / Det; + + Matrix3x3 Temp; + Temp.m[0][0] = +(m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDet; + Temp.m[1][0] = -(m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDet; + Temp.m[2][0] = +(m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDet; + Temp.m[0][1] = -(m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDet; + Temp.m[1][1] = +(m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDet; + Temp.m[2][1] = -(m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDet; + Temp.m[0][2] = +(m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDet; + Temp.m[1][2] = -(m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDet; + Temp.m[2][2] = +(m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDet; + + *this = Temp; + + return *this; + } + + Matrix3x3& Normalize(); + + //! this = exp(a) + Matrix3x3& Exp(const Matrix3x3& a); + +void FromQuat(const Quat &q); +void FromQuatL2(const Quat &q, float l2); + + // Arithmetic operators + //! Operator for Matrix3x3 Plus = Matrix3x3 + Matrix3x3; + inline_ Matrix3x3 operator+(const Matrix3x3& mat) const + { + return Matrix3x3( + m[0][0] + mat.m[0][0], m[0][1] + mat.m[0][1], m[0][2] + mat.m[0][2], + m[1][0] + mat.m[1][0], m[1][1] + mat.m[1][1], m[1][2] + mat.m[1][2], + m[2][0] + mat.m[2][0], m[2][1] + mat.m[2][1], m[2][2] + mat.m[2][2]); + } + + //! Operator for Matrix3x3 Minus = Matrix3x3 - Matrix3x3; + inline_ Matrix3x3 operator-(const Matrix3x3& mat) const + { + return Matrix3x3( + m[0][0] - mat.m[0][0], m[0][1] - mat.m[0][1], m[0][2] - mat.m[0][2], + m[1][0] - mat.m[1][0], m[1][1] - mat.m[1][1], m[1][2] - mat.m[1][2], + m[2][0] - mat.m[2][0], m[2][1] - mat.m[2][1], m[2][2] - mat.m[2][2]); + } + + //! Operator for Matrix3x3 Mul = Matrix3x3 * Matrix3x3; + inline_ Matrix3x3 operator*(const Matrix3x3& mat) const + { + return Matrix3x3( + m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0], + m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1], + m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2], + + m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0], + m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1], + m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2], + + m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0], + m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1], + m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2]); + } + + //! Operator for Point Mul = Matrix3x3 * Point; + inline_ Point operator*(const Point& v) const { return Point(GetRow(0)|v, GetRow(1)|v, GetRow(2)|v); } + + //! Operator for Matrix3x3 Mul = Matrix3x3 * float; + inline_ Matrix3x3 operator*(float s) const + { + return Matrix3x3( + m[0][0]*s, m[0][1]*s, m[0][2]*s, + m[1][0]*s, m[1][1]*s, m[1][2]*s, + m[2][0]*s, m[2][1]*s, m[2][2]*s); + } + + //! Operator for Matrix3x3 Mul = float * Matrix3x3; + inline_ friend Matrix3x3 operator*(float s, const Matrix3x3& mat) + { + return Matrix3x3( + s*mat.m[0][0], s*mat.m[0][1], s*mat.m[0][2], + s*mat.m[1][0], s*mat.m[1][1], s*mat.m[1][2], + s*mat.m[2][0], s*mat.m[2][1], s*mat.m[2][2]); + } + + //! Operator for Matrix3x3 Div = Matrix3x3 / float; + inline_ Matrix3x3 operator/(float s) const + { + if (s) s = 1.0f / s; + return Matrix3x3( + m[0][0]*s, m[0][1]*s, m[0][2]*s, + m[1][0]*s, m[1][1]*s, m[1][2]*s, + m[2][0]*s, m[2][1]*s, m[2][2]*s); + } + + //! Operator for Matrix3x3 Div = float / Matrix3x3; + inline_ friend Matrix3x3 operator/(float s, const Matrix3x3& mat) + { + return Matrix3x3( + s/mat.m[0][0], s/mat.m[0][1], s/mat.m[0][2], + s/mat.m[1][0], s/mat.m[1][1], s/mat.m[1][2], + s/mat.m[2][0], s/mat.m[2][1], s/mat.m[2][2]); + } + + //! Operator for Matrix3x3 += Matrix3x3 + inline_ Matrix3x3& operator+=(const Matrix3x3& mat) + { + m[0][0] += mat.m[0][0]; m[0][1] += mat.m[0][1]; m[0][2] += mat.m[0][2]; + m[1][0] += mat.m[1][0]; m[1][1] += mat.m[1][1]; m[1][2] += mat.m[1][2]; + m[2][0] += mat.m[2][0]; m[2][1] += mat.m[2][1]; m[2][2] += mat.m[2][2]; + return *this; + } + + //! Operator for Matrix3x3 -= Matrix3x3 + inline_ Matrix3x3& operator-=(const Matrix3x3& mat) + { + m[0][0] -= mat.m[0][0]; m[0][1] -= mat.m[0][1]; m[0][2] -= mat.m[0][2]; + m[1][0] -= mat.m[1][0]; m[1][1] -= mat.m[1][1]; m[1][2] -= mat.m[1][2]; + m[2][0] -= mat.m[2][0]; m[2][1] -= mat.m[2][1]; m[2][2] -= mat.m[2][2]; + return *this; + } + + //! Operator for Matrix3x3 *= Matrix3x3 + inline_ Matrix3x3& operator*=(const Matrix3x3& mat) + { + Point TempRow; + + GetRow(0, TempRow); + m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0]; + m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1]; + m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2]; + + GetRow(1, TempRow); + m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0]; + m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1]; + m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2]; + + GetRow(2, TempRow); + m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0]; + m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1]; + m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2]; + return *this; + } + + //! Operator for Matrix3x3 *= float + inline_ Matrix3x3& operator*=(float s) + { + m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; + m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; + m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; + return *this; + } + + //! Operator for Matrix3x3 /= float + inline_ Matrix3x3& operator/=(float s) + { + if (s) s = 1.0f / s; + m[0][0] *= s; m[0][1] *= s; m[0][2] *= s; + m[1][0] *= s; m[1][1] *= s; m[1][2] *= s; + m[2][0] *= s; m[2][1] *= s; m[2][2] *= s; + return *this; + } + + // Cast operators + //! Cast a Matrix3x3 to a Matrix4x4. + operator Matrix4x4() const; + //! Cast a Matrix3x3 to a Quat. + operator Quat() const; + + inline_ const Point& operator[](int row) const { return *(const Point*)&m[row][0]; } + inline_ Point& operator[](int row) { return *(Point*)&m[row][0]; } + + public: + + float m[3][3]; + }; + +#endif // __ICEMATRIX3X3_H__ + diff --git a/src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.cpp b/src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.cpp new file mode 100644 index 00000000..f2b9e9e0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.cpp @@ -0,0 +1,142 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for 4x4 matrices. + * \file IceMatrix4x4.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 4x4 matrix. + * DirectX-compliant, ie row-column order, ie m[Row][Col]. + * Same as: + * m11 m12 m13 m14 first row. + * m21 m22 m23 m24 second row. + * m31 m32 m33 m34 third row. + * m41 m42 m43 m44 fourth row. + * Translation is (m41, m42, m43), (m14, m24, m34, m44) = (0, 0, 0, 1). + * Stored in memory as m11 m12 m13 m14 m21... + * + * Multiplication rules: + * + * [x'y'z'1] = [xyz1][M] + * + * x' = x*m11 + y*m21 + z*m31 + m41 + * y' = x*m12 + y*m22 + z*m32 + m42 + * z' = x*m13 + y*m23 + z*m33 + m43 + * 1' = 0 + 0 + 0 + m44 + * + * \class Matrix4x4 + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Inverts a PR matrix. (which only contains a rotation and a translation) + * This is faster and less subject to FPU errors than the generic inversion code. + * + * \relates Matrix4x4 + * \fn InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src) + * \param dest [out] destination matrix + * \param src [in] source matrix + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +ICEMATHS_API void IceMaths::InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src) +{ + dest.m[0][0] = src.m[0][0]; + dest.m[1][0] = src.m[0][1]; + dest.m[2][0] = src.m[0][2]; + dest.m[3][0] = -(src.m[3][0]*src.m[0][0] + src.m[3][1]*src.m[0][1] + src.m[3][2]*src.m[0][2]); + + dest.m[0][1] = src.m[1][0]; + dest.m[1][1] = src.m[1][1]; + dest.m[2][1] = src.m[1][2]; + dest.m[3][1] = -(src.m[3][0]*src.m[1][0] + src.m[3][1]*src.m[1][1] + src.m[3][2]*src.m[1][2]); + + dest.m[0][2] = src.m[2][0]; + dest.m[1][2] = src.m[2][1]; + dest.m[2][2] = src.m[2][2]; + dest.m[3][2] = -(src.m[3][0]*src.m[2][0] + src.m[3][1]*src.m[2][1] + src.m[3][2]*src.m[2][2]); + + dest.m[0][3] = 0.0f; + dest.m[1][3] = 0.0f; + dest.m[2][3] = 0.0f; + dest.m[3][3] = 1.0f; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Compute the cofactor of the Matrix at a specified location +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Matrix4x4::CoFactor(udword row, udword col) const +{ + return (( m[(row+1)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+3)&3][(col+3)&3] + + m[(row+1)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+3)&3][(col+1)&3] + + m[(row+1)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+3)&3][(col+2)&3]) + - (m[(row+3)&3][(col+1)&3]*m[(row+2)&3][(col+2)&3]*m[(row+1)&3][(col+3)&3] + + m[(row+3)&3][(col+2)&3]*m[(row+2)&3][(col+3)&3]*m[(row+1)&3][(col+1)&3] + + m[(row+3)&3][(col+3)&3]*m[(row+2)&3][(col+1)&3]*m[(row+1)&3][(col+2)&3])) * ((row + col) & 1 ? -1.0f : +1.0f); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Compute the determinant of the Matrix +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Matrix4x4::Determinant() const +{ + return m[0][0] * CoFactor(0, 0) + + m[0][1] * CoFactor(0, 1) + + m[0][2] * CoFactor(0, 2) + + m[0][3] * CoFactor(0, 3); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Compute the inverse of the matrix +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Matrix4x4& Matrix4x4::Invert() +{ + float Det = Determinant(); + Matrix4x4 Temp; + + if(fabsf(Det) < MATRIX4X4_EPSILON) + return *this; // The matrix is not invertible! Singular case! + + float IDet = 1.0f / Det; + + Temp.m[0][0] = CoFactor(0,0) * IDet; + Temp.m[1][0] = CoFactor(0,1) * IDet; + Temp.m[2][0] = CoFactor(0,2) * IDet; + Temp.m[3][0] = CoFactor(0,3) * IDet; + Temp.m[0][1] = CoFactor(1,0) * IDet; + Temp.m[1][1] = CoFactor(1,1) * IDet; + Temp.m[2][1] = CoFactor(1,2) * IDet; + Temp.m[3][1] = CoFactor(1,3) * IDet; + Temp.m[0][2] = CoFactor(2,0) * IDet; + Temp.m[1][2] = CoFactor(2,1) * IDet; + Temp.m[2][2] = CoFactor(2,2) * IDet; + Temp.m[3][2] = CoFactor(2,3) * IDet; + Temp.m[0][3] = CoFactor(3,0) * IDet; + Temp.m[1][3] = CoFactor(3,1) * IDet; + Temp.m[2][3] = CoFactor(3,2) * IDet; + Temp.m[3][3] = CoFactor(3,3) * IDet; + + *this = Temp; + + return *this; +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.h b/src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.h new file mode 100644 index 00000000..45919be7 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceMatrix4x4.h @@ -0,0 +1,455 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for 4x4 matrices. + * \file IceMatrix4x4.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEMATRIX4X4_H__ +#define __ICEMATRIX4X4_H__ + + // Forward declarations + class PRS; + class PR; + + #define MATRIX4X4_EPSILON (1.0e-7f) + + class ICEMATHS_API Matrix4x4 + { +// void LUBackwardSubstitution( sdword *indx, float* b ); +// void LUDecomposition( sdword* indx, float* d ); + + public: + //! Empty constructor. + inline_ Matrix4x4() {} + //! Constructor from 16 values + inline_ Matrix4x4( float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + { + m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; + m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; + m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; + m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; + } + //! Copy constructor + inline_ Matrix4x4(const Matrix4x4& mat) { CopyMemory(m, &mat.m, 16*sizeof(float)); } + //! Destructor. + inline_ ~Matrix4x4() {} + + //! Assign values (rotation only) + inline_ Matrix4x4& Set( float m00, float m01, float m02, + float m10, float m11, float m12, + float m20, float m21, float m22) + { + m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; + m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; + m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; + return *this; + } + //! Assign values + inline_ Matrix4x4& Set( float m00, float m01, float m02, float m03, + float m10, float m11, float m12, float m13, + float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + { + m[0][0] = m00; m[0][1] = m01; m[0][2] = m02; m[0][3] = m03; + m[1][0] = m10; m[1][1] = m11; m[1][2] = m12; m[1][3] = m13; + m[2][0] = m20; m[2][1] = m21; m[2][2] = m22; m[2][3] = m23; + m[3][0] = m30; m[3][1] = m31; m[3][2] = m32; m[3][3] = m33; + return *this; + } + + //! Copy from a Matrix4x4 + inline_ void Copy(const Matrix4x4& source) { CopyMemory(m, source.m, 16*sizeof(float)); } + + // Row-column access + //! Returns a row. + inline_ void GetRow(const udword r, HPoint& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; p.w=m[r][3]; } + //! Returns a row. + inline_ void GetRow(const udword r, Point& p) const { p.x=m[r][0]; p.y=m[r][1]; p.z=m[r][2]; } + //! Returns a row. + inline_ const HPoint& GetRow(const udword r) const { return *(const HPoint*)&m[r][0]; } + //! Returns a row. + inline_ HPoint& GetRow(const udword r) { return *(HPoint*)&m[r][0]; } + //! Sets a row. + inline_ void SetRow(const udword r, const HPoint& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]=p.w; } + //! Sets a row. + inline_ void SetRow(const udword r, const Point& p) { m[r][0]=p.x; m[r][1]=p.y; m[r][2]=p.z; m[r][3]= (r!=3) ? 0.0f : 1.0f; } + //! Returns a column. + inline_ void GetCol(const udword c, HPoint& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; p.w=m[3][c]; } + //! Returns a column. + inline_ void GetCol(const udword c, Point& p) const { p.x=m[0][c]; p.y=m[1][c]; p.z=m[2][c]; } + //! Sets a column. + inline_ void SetCol(const udword c, const HPoint& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]=p.w; } + //! Sets a column. + inline_ void SetCol(const udword c, const Point& p) { m[0][c]=p.x; m[1][c]=p.y; m[2][c]=p.z; m[3][c]= (c!=3) ? 0.0f : 1.0f; } + + // Translation + //! Returns the translation part of the matrix. + inline_ const HPoint& GetTrans() const { return GetRow(3); } + //! Gets the translation part of the matrix + inline_ void GetTrans(Point& p) const { p.x=m[3][0]; p.y=m[3][1]; p.z=m[3][2]; } + //! Sets the translation part of the matrix, from a Point. + inline_ void SetTrans(const Point& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; } + //! Sets the translation part of the matrix, from a HPoint. + inline_ void SetTrans(const HPoint& p) { m[3][0]=p.x; m[3][1]=p.y; m[3][2]=p.z; m[3][3]=p.w; } + //! Sets the translation part of the matrix, from floats. + inline_ void SetTrans(float tx, float ty, float tz) { m[3][0]=tx; m[3][1]=ty; m[3][2]=tz; } + + // Scale + //! Sets the scale from a Point. The point is put on the diagonal. + inline_ void SetScale(const Point& p) { m[0][0]=p.x; m[1][1]=p.y; m[2][2]=p.z; } + //! Sets the scale from floats. Values are put on the diagonal. + inline_ void SetScale(float sx, float sy, float sz) { m[0][0]=sx; m[1][1]=sy; m[2][2]=sz; } + //! Scales from a Point. Each row is multiplied by a component. + void Scale(const Point& p) + { + m[0][0] *= p.x; m[1][0] *= p.y; m[2][0] *= p.z; + m[0][1] *= p.x; m[1][1] *= p.y; m[2][1] *= p.z; + m[0][2] *= p.x; m[1][2] *= p.y; m[2][2] *= p.z; + } + //! Scales from floats. Each row is multiplied by a value. + void Scale(float sx, float sy, float sz) + { + m[0][0] *= sx; m[1][0] *= sy; m[2][0] *= sz; + m[0][1] *= sx; m[1][1] *= sy; m[2][1] *= sz; + m[0][2] *= sx; m[1][2] *= sy; m[2][2] *= sz; + } +/* + //! Returns a row. + inline_ HPoint GetRow(const udword row) const { return mRow[row]; } + //! Sets a row. + inline_ Matrix4x4& SetRow(const udword row, const HPoint& p) { mRow[row] = p; return *this; } + //! Sets a row. + Matrix4x4& SetRow(const udword row, const Point& p) + { + m[row][0] = p.x; + m[row][1] = p.y; + m[row][2] = p.z; + m[row][3] = (row != 3) ? 0.0f : 1.0f; + return *this; + } + //! Returns a column. + HPoint GetCol(const udword col) const + { + HPoint Res; + Res.x = m[0][col]; + Res.y = m[1][col]; + Res.z = m[2][col]; + Res.w = m[3][col]; + return Res; + } + //! Sets a column. + Matrix4x4& SetCol(const udword col, const HPoint& p) + { + m[0][col] = p.x; + m[1][col] = p.y; + m[2][col] = p.z; + m[3][col] = p.w; + return *this; + } + //! Sets a column. + Matrix4x4& SetCol(const udword col, const Point& p) + { + m[0][col] = p.x; + m[1][col] = p.y; + m[2][col] = p.z; + m[3][col] = (col != 3) ? 0.0f : 1.0f; + return *this; + } +*/ + //! Computes the trace. The trace is the sum of the 4 diagonal components. + inline_ float Trace() const { return m[0][0] + m[1][1] + m[2][2] + m[3][3]; } + //! Computes the trace of the upper 3x3 matrix. + inline_ float Trace3x3() const { return m[0][0] + m[1][1] + m[2][2]; } + //! Clears the matrix. + inline_ void Zero() { ZeroMemory(&m, sizeof(m)); } + //! Sets the identity matrix. + inline_ void Identity() { Zero(); m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f; } + //! Checks for identity + inline_ bool IsIdentity() const + { + if(IR(m[0][0])!=IEEE_1_0) return false; + if(IR(m[0][1])!=0) return false; + if(IR(m[0][2])!=0) return false; + if(IR(m[0][3])!=0) return false; + + if(IR(m[1][0])!=0) return false; + if(IR(m[1][1])!=IEEE_1_0) return false; + if(IR(m[1][2])!=0) return false; + if(IR(m[1][3])!=0) return false; + + if(IR(m[2][0])!=0) return false; + if(IR(m[2][1])!=0) return false; + if(IR(m[2][2])!=IEEE_1_0) return false; + if(IR(m[2][3])!=0) return false; + + if(IR(m[3][0])!=0) return false; + if(IR(m[3][1])!=0) return false; + if(IR(m[3][2])!=0) return false; + if(IR(m[3][3])!=IEEE_1_0) return false; + return true; + } + + //! Checks matrix validity + inline_ BOOL IsValid() const + { + for(udword j=0;j<4;j++) + { + for(udword i=0;i<4;i++) + { + if(!IsValidFloat(m[j][i])) return FALSE; + } + } + return TRUE; + } + + //! Sets a rotation matrix around the X axis. + void RotX(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[1][1] = m[2][2] = Cos; m[2][1] = -Sin; m[1][2] = Sin; } + //! Sets a rotation matrix around the Y axis. + void RotY(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[2][2] = Cos; m[2][0] = Sin; m[0][2] = -Sin; } + //! Sets a rotation matrix around the Z axis. + void RotZ(float angle) { float Cos = cosf(angle), Sin = sinf(angle); Identity(); m[0][0] = m[1][1] = Cos; m[1][0] = -Sin; m[0][1] = Sin; } + + //! Makes a rotation matrix about an arbitrary axis + Matrix4x4& Rot(float angle, Point& p1, Point& p2); + + //! Transposes the matrix. + void Transpose() + { + IR(m[1][0]) ^= IR(m[0][1]); IR(m[0][1]) ^= IR(m[1][0]); IR(m[1][0]) ^= IR(m[0][1]); + IR(m[2][0]) ^= IR(m[0][2]); IR(m[0][2]) ^= IR(m[2][0]); IR(m[2][0]) ^= IR(m[0][2]); + IR(m[3][0]) ^= IR(m[0][3]); IR(m[0][3]) ^= IR(m[3][0]); IR(m[3][0]) ^= IR(m[0][3]); + IR(m[1][2]) ^= IR(m[2][1]); IR(m[2][1]) ^= IR(m[1][2]); IR(m[1][2]) ^= IR(m[2][1]); + IR(m[1][3]) ^= IR(m[3][1]); IR(m[3][1]) ^= IR(m[1][3]); IR(m[1][3]) ^= IR(m[3][1]); + IR(m[2][3]) ^= IR(m[3][2]); IR(m[3][2]) ^= IR(m[2][3]); IR(m[2][3]) ^= IR(m[3][2]); + } + + //! Computes a cofactor. Used for matrix inversion. + float CoFactor(udword row, udword col) const; + //! Computes the determinant of the matrix. + float Determinant() const; + //! Inverts the matrix. Determinant must be different from zero, else matrix can't be inverted. + Matrix4x4& Invert(); +// Matrix& ComputeAxisMatrix(Point& axis, float angle); + + // Cast operators + //! Casts a Matrix4x4 to a Matrix3x3. + inline_ operator Matrix3x3() const + { + return Matrix3x3( + m[0][0], m[0][1], m[0][2], + m[1][0], m[1][1], m[1][2], + m[2][0], m[2][1], m[2][2]); + } + //! Casts a Matrix4x4 to a Quat. + operator Quat() const; + //! Casts a Matrix4x4 to a PR. + operator PR() const; + + // Arithmetic operators + //! Operator for Matrix4x4 Plus = Matrix4x4 + Matrix4x4; + inline_ Matrix4x4 operator+(const Matrix4x4& mat) const + { + return Matrix4x4( + m[0][0]+mat.m[0][0], m[0][1]+mat.m[0][1], m[0][2]+mat.m[0][2], m[0][3]+mat.m[0][3], + m[1][0]+mat.m[1][0], m[1][1]+mat.m[1][1], m[1][2]+mat.m[1][2], m[1][3]+mat.m[1][3], + m[2][0]+mat.m[2][0], m[2][1]+mat.m[2][1], m[2][2]+mat.m[2][2], m[2][3]+mat.m[2][3], + m[3][0]+mat.m[3][0], m[3][1]+mat.m[3][1], m[3][2]+mat.m[3][2], m[3][3]+mat.m[3][3]); + } + + //! Operator for Matrix4x4 Minus = Matrix4x4 - Matrix4x4; + inline_ Matrix4x4 operator-(const Matrix4x4& mat) const + { + return Matrix4x4( + m[0][0]-mat.m[0][0], m[0][1]-mat.m[0][1], m[0][2]-mat.m[0][2], m[0][3]-mat.m[0][3], + m[1][0]-mat.m[1][0], m[1][1]-mat.m[1][1], m[1][2]-mat.m[1][2], m[1][3]-mat.m[1][3], + m[2][0]-mat.m[2][0], m[2][1]-mat.m[2][1], m[2][2]-mat.m[2][2], m[2][3]-mat.m[2][3], + m[3][0]-mat.m[3][0], m[3][1]-mat.m[3][1], m[3][2]-mat.m[3][2], m[3][3]-mat.m[3][3]); + } + + //! Operator for Matrix4x4 Mul = Matrix4x4 * Matrix4x4; + inline_ Matrix4x4 operator*(const Matrix4x4& mat) const + { + return Matrix4x4( + m[0][0]*mat.m[0][0] + m[0][1]*mat.m[1][0] + m[0][2]*mat.m[2][0] + m[0][3]*mat.m[3][0], + m[0][0]*mat.m[0][1] + m[0][1]*mat.m[1][1] + m[0][2]*mat.m[2][1] + m[0][3]*mat.m[3][1], + m[0][0]*mat.m[0][2] + m[0][1]*mat.m[1][2] + m[0][2]*mat.m[2][2] + m[0][3]*mat.m[3][2], + m[0][0]*mat.m[0][3] + m[0][1]*mat.m[1][3] + m[0][2]*mat.m[2][3] + m[0][3]*mat.m[3][3], + + m[1][0]*mat.m[0][0] + m[1][1]*mat.m[1][0] + m[1][2]*mat.m[2][0] + m[1][3]*mat.m[3][0], + m[1][0]*mat.m[0][1] + m[1][1]*mat.m[1][1] + m[1][2]*mat.m[2][1] + m[1][3]*mat.m[3][1], + m[1][0]*mat.m[0][2] + m[1][1]*mat.m[1][2] + m[1][2]*mat.m[2][2] + m[1][3]*mat.m[3][2], + m[1][0]*mat.m[0][3] + m[1][1]*mat.m[1][3] + m[1][2]*mat.m[2][3] + m[1][3]*mat.m[3][3], + + m[2][0]*mat.m[0][0] + m[2][1]*mat.m[1][0] + m[2][2]*mat.m[2][0] + m[2][3]*mat.m[3][0], + m[2][0]*mat.m[0][1] + m[2][1]*mat.m[1][1] + m[2][2]*mat.m[2][1] + m[2][3]*mat.m[3][1], + m[2][0]*mat.m[0][2] + m[2][1]*mat.m[1][2] + m[2][2]*mat.m[2][2] + m[2][3]*mat.m[3][2], + m[2][0]*mat.m[0][3] + m[2][1]*mat.m[1][3] + m[2][2]*mat.m[2][3] + m[2][3]*mat.m[3][3], + + m[3][0]*mat.m[0][0] + m[3][1]*mat.m[1][0] + m[3][2]*mat.m[2][0] + m[3][3]*mat.m[3][0], + m[3][0]*mat.m[0][1] + m[3][1]*mat.m[1][1] + m[3][2]*mat.m[2][1] + m[3][3]*mat.m[3][1], + m[3][0]*mat.m[0][2] + m[3][1]*mat.m[1][2] + m[3][2]*mat.m[2][2] + m[3][3]*mat.m[3][2], + m[3][0]*mat.m[0][3] + m[3][1]*mat.m[1][3] + m[3][2]*mat.m[2][3] + m[3][3]*mat.m[3][3]); + } + + //! Operator for HPoint Mul = Matrix4x4 * HPoint; + inline_ HPoint operator*(const HPoint& v) const { return HPoint(GetRow(0)|v, GetRow(1)|v, GetRow(2)|v, GetRow(3)|v); } + + //! Operator for Point Mul = Matrix4x4 * Point; + inline_ Point operator*(const Point& v) const + { + return Point( m[0][0]*v.x + m[0][1]*v.y + m[0][2]*v.z + m[0][3], + m[1][0]*v.x + m[1][1]*v.y + m[1][2]*v.z + m[1][3], + m[2][0]*v.x + m[2][1]*v.y + m[2][2]*v.z + m[2][3] ); + } + + //! Operator for Matrix4x4 Scale = Matrix4x4 * float; + inline_ Matrix4x4 operator*(float s) const + { + return Matrix4x4( + m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s, + m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s, + m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s, + m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s); + } + + //! Operator for Matrix4x4 Scale = float * Matrix4x4; + inline_ friend Matrix4x4 operator*(float s, const Matrix4x4& mat) + { + return Matrix4x4( + s*mat.m[0][0], s*mat.m[0][1], s*mat.m[0][2], s*mat.m[0][3], + s*mat.m[1][0], s*mat.m[1][1], s*mat.m[1][2], s*mat.m[1][3], + s*mat.m[2][0], s*mat.m[2][1], s*mat.m[2][2], s*mat.m[2][3], + s*mat.m[3][0], s*mat.m[3][1], s*mat.m[3][2], s*mat.m[3][3]); + } + + //! Operator for Matrix4x4 Div = Matrix4x4 / float; + inline_ Matrix4x4 operator/(float s) const + { + if(s) s = 1.0f / s; + + return Matrix4x4( + m[0][0]*s, m[0][1]*s, m[0][2]*s, m[0][3]*s, + m[1][0]*s, m[1][1]*s, m[1][2]*s, m[1][3]*s, + m[2][0]*s, m[2][1]*s, m[2][2]*s, m[2][3]*s, + m[3][0]*s, m[3][1]*s, m[3][2]*s, m[3][3]*s); + } + + //! Operator for Matrix4x4 Div = float / Matrix4x4; + inline_ friend Matrix4x4 operator/(float s, const Matrix4x4& mat) + { + return Matrix4x4( + s/mat.m[0][0], s/mat.m[0][1], s/mat.m[0][2], s/mat.m[0][3], + s/mat.m[1][0], s/mat.m[1][1], s/mat.m[1][2], s/mat.m[1][3], + s/mat.m[2][0], s/mat.m[2][1], s/mat.m[2][2], s/mat.m[2][3], + s/mat.m[3][0], s/mat.m[3][1], s/mat.m[3][2], s/mat.m[3][3]); + } + + //! Operator for Matrix4x4 += Matrix4x4; + inline_ Matrix4x4& operator+=(const Matrix4x4& mat) + { + m[0][0]+=mat.m[0][0]; m[0][1]+=mat.m[0][1]; m[0][2]+=mat.m[0][2]; m[0][3]+=mat.m[0][3]; + m[1][0]+=mat.m[1][0]; m[1][1]+=mat.m[1][1]; m[1][2]+=mat.m[1][2]; m[1][3]+=mat.m[1][3]; + m[2][0]+=mat.m[2][0]; m[2][1]+=mat.m[2][1]; m[2][2]+=mat.m[2][2]; m[2][3]+=mat.m[2][3]; + m[3][0]+=mat.m[3][0]; m[3][1]+=mat.m[3][1]; m[3][2]+=mat.m[3][2]; m[3][3]+=mat.m[3][3]; + return *this; + } + + //! Operator for Matrix4x4 -= Matrix4x4; + inline_ Matrix4x4& operator-=(const Matrix4x4& mat) + { + m[0][0]-=mat.m[0][0]; m[0][1]-=mat.m[0][1]; m[0][2]-=mat.m[0][2]; m[0][3]-=mat.m[0][3]; + m[1][0]-=mat.m[1][0]; m[1][1]-=mat.m[1][1]; m[1][2]-=mat.m[1][2]; m[1][3]-=mat.m[1][3]; + m[2][0]-=mat.m[2][0]; m[2][1]-=mat.m[2][1]; m[2][2]-=mat.m[2][2]; m[2][3]-=mat.m[2][3]; + m[3][0]-=mat.m[3][0]; m[3][1]-=mat.m[3][1]; m[3][2]-=mat.m[3][2]; m[3][3]-=mat.m[3][3]; + return *this; + } + + //! Operator for Matrix4x4 *= Matrix4x4; + Matrix4x4& operator*=(const Matrix4x4& mat) + { + HPoint TempRow; + + GetRow(0, TempRow); + m[0][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; + m[0][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; + m[0][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; + m[0][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; + + GetRow(1, TempRow); + m[1][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; + m[1][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; + m[1][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; + m[1][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; + + GetRow(2, TempRow); + m[2][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; + m[2][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; + m[2][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; + m[2][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; + + GetRow(3, TempRow); + m[3][0] = TempRow.x*mat.m[0][0] + TempRow.y*mat.m[1][0] + TempRow.z*mat.m[2][0] + TempRow.w*mat.m[3][0]; + m[3][1] = TempRow.x*mat.m[0][1] + TempRow.y*mat.m[1][1] + TempRow.z*mat.m[2][1] + TempRow.w*mat.m[3][1]; + m[3][2] = TempRow.x*mat.m[0][2] + TempRow.y*mat.m[1][2] + TempRow.z*mat.m[2][2] + TempRow.w*mat.m[3][2]; + m[3][3] = TempRow.x*mat.m[0][3] + TempRow.y*mat.m[1][3] + TempRow.z*mat.m[2][3] + TempRow.w*mat.m[3][3]; + + return *this; + } + + //! Operator for Matrix4x4 *= float; + inline_ Matrix4x4& operator*=(float s) + { + m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s; + m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s; + m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s; + m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s; + return *this; + } + + //! Operator for Matrix4x4 /= float; + inline_ Matrix4x4& operator/=(float s) + { + if(s) s = 1.0f / s; + m[0][0]*=s; m[0][1]*=s; m[0][2]*=s; m[0][3]*=s; + m[1][0]*=s; m[1][1]*=s; m[1][2]*=s; m[1][3]*=s; + m[2][0]*=s; m[2][1]*=s; m[2][2]*=s; m[2][3]*=s; + m[3][0]*=s; m[3][1]*=s; m[3][2]*=s; m[3][3]*=s; + return *this; + } + + inline_ const HPoint& operator[](int row) const { return *(const HPoint*)&m[row][0]; } + inline_ HPoint& operator[](int row) { return *(HPoint*)&m[row][0]; } + + public: + + float m[4][4]; + }; + + //! Quickly rotates & translates a vector, using the 4x3 part of a 4x4 matrix + inline_ void TransformPoint4x3(Point& dest, const Point& source, const Matrix4x4& rot) + { + dest.x = rot.m[3][0] + source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0]; + dest.y = rot.m[3][1] + source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1]; + dest.z = rot.m[3][2] + source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2]; + } + + //! Quickly rotates a vector, using the 3x3 part of a 4x4 matrix + inline_ void TransformPoint3x3(Point& dest, const Point& source, const Matrix4x4& rot) + { + dest.x = source.x * rot.m[0][0] + source.y * rot.m[1][0] + source.z * rot.m[2][0]; + dest.y = source.x * rot.m[0][1] + source.y * rot.m[1][1] + source.z * rot.m[2][1]; + dest.z = source.x * rot.m[0][2] + source.y * rot.m[1][2] + source.z * rot.m[2][2]; + } + + ICEMATHS_API void InvertPRMatrix(Matrix4x4& dest, const Matrix4x4& src); + +#endif // __ICEMATRIX4X4_H__ + diff --git a/src/external/open_dynamics_engine-ef/ode/IceMemoryMacros.h b/src/external/open_dynamics_engine-ef/ode/IceMemoryMacros.h new file mode 100644 index 00000000..7ea8d4d0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceMemoryMacros.h @@ -0,0 +1,109 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains all memory macros. + * \file IceMemoryMacros.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEMEMORYMACROS_H__ +#define __ICEMEMORYMACROS_H__ + +#undef ZeroMemory +#undef CopyMemory +#undef MoveMemory +#undef FillMemory + + //! Clears a buffer. + //! \param addr [in] buffer address + //! \param size [in] buffer length + //! \see FillMemory + //! \see StoreDwords + //! \see CopyMemory + //! \see MoveMemory + inline_ void ZeroMemory(void* addr, udword size) { memset(addr, 0, size); } + + //! Fills a buffer with a given byte. + //! \param dest [in] buffer address + //! \param size [in] buffer length + //! \param val [in] the byte value + //! \see StoreDwords + //! \see ZeroMemory + //! \see CopyMemory + //! \see MoveMemory + inline_ void FillMemory(void* dest, udword size, ubyte val) { memset(dest, val, size); } + + //! Fills a buffer with a given dword. + //! \param dest [in] buffer address + //! \param nb [in] number of dwords to write + //! \param value [in] the dword value + //! \see FillMemory + //! \see ZeroMemory + //! \see CopyMemory + //! \see MoveMemory + //! \warning writes nb*4 bytes ! + inline_ void StoreDwords(udword* dest, udword nb, udword value) + { + // The asm code below **SHOULD** be equivalent to one of those C versions + // or the other if your compiled is good: (checked on VC++ 6.0) + // + // 1) while(nb--) *dest++ = value; + // + // 2) for(udword i=0;iRelease(); (x) = null; } //!< Safe D3D-style release + #define SAFE_DESTRUCT(x) if (x) { (x)->SelfDestruct(); (x) = null; } //!< Safe ICE-style release + +#ifdef __ICEERROR_H__ + #define CHECKALLOC(x) if(!x) return SetIceError("Out of memory.", EC_OUT_OF_MEMORY); //!< Standard alloc checking. HANDLE WITH CARE. +#else + #define CHECKALLOC(x) if(!x) return false; +#endif + + //! Standard allocation cycle + #define SAFE_ALLOC(ptr, type, count) DELETEARRAY(ptr); ptr = new type[count]; CHECKALLOC(ptr); + +#endif // __ICEMEMORYMACROS_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceOBB.cpp b/src/external/open_dynamics_engine-ef/ode/IceOBB.cpp new file mode 100644 index 00000000..d54fc902 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceOBB.cpp @@ -0,0 +1,333 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains OBB-related code. + * \file IceOBB.cpp + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * An Oriented Bounding Box (OBB). + * \class OBB + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Tests if a point is contained within the OBB. + * \param p [in] the world point to test + * \return true if inside the OBB + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool OBB::ContainsPoint(const Point& p) const +{ + // Point in OBB test using lazy evaluation and early exits + + // Translate to box space + Point RelPoint = p - mCenter; + + // Point * mRot maps from box space to world space + // mRot * Point maps from world space to box space (what we need here) + + float f = mRot.m[0][0] * RelPoint.x + mRot.m[0][1] * RelPoint.y + mRot.m[0][2] * RelPoint.z; + if(f >= mExtents.x || f <= -mExtents.x) return false; + + f = mRot.m[1][0] * RelPoint.x + mRot.m[1][1] * RelPoint.y + mRot.m[1][2] * RelPoint.z; + if(f >= mExtents.y || f <= -mExtents.y) return false; + + f = mRot.m[2][0] * RelPoint.x + mRot.m[2][1] * RelPoint.y + mRot.m[2][2] * RelPoint.z; + if(f >= mExtents.z || f <= -mExtents.z) return false; + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds an OBB from an AABB and a world transform. + * \param aabb [in] the aabb + * \param mat [in] the world transform + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBB::Create(const AABB& aabb, const Matrix4x4& mat) +{ + // Note: must be coherent with Rotate() + + aabb.GetCenter(mCenter); + aabb.GetExtents(mExtents); + // Here we have the same as OBB::Rotate(mat) where the obb is (mCenter, mExtents, Identity). + + // So following what's done in Rotate: + // - x-form the center + mCenter *= mat; + // - combine rotation with identity, i.e. just use given matrix + mRot = mat; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the obb planes. + * \param planes [out] 6 box planes + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool OBB::ComputePlanes(Plane* planes) const +{ + // Checkings + if(!planes) return false; + + Point Axis0 = mRot[0]; + Point Axis1 = mRot[1]; + Point Axis2 = mRot[2]; + + // Writes normals + planes[0].n = Axis0; + planes[1].n = -Axis0; + planes[2].n = Axis1; + planes[3].n = -Axis1; + planes[4].n = Axis2; + planes[5].n = -Axis2; + + // Compute a point on each plane + Point p0 = mCenter + Axis0 * mExtents.x; + Point p1 = mCenter - Axis0 * mExtents.x; + Point p2 = mCenter + Axis1 * mExtents.y; + Point p3 = mCenter - Axis1 * mExtents.y; + Point p4 = mCenter + Axis2 * mExtents.z; + Point p5 = mCenter - Axis2 * mExtents.z; + + // Compute d + planes[0].d = -(planes[0].n|p0); + planes[1].d = -(planes[1].n|p1); + planes[2].d = -(planes[2].n|p2); + planes[3].d = -(planes[3].n|p3); + planes[4].d = -(planes[4].n|p4); + planes[5].d = -(planes[5].n|p5); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the obb points. + * \param pts [out] 8 box points + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool OBB::ComputePoints(Point* pts) const +{ + // Checkings + if(!pts) return false; + + Point Axis0 = mRot[0]; + Point Axis1 = mRot[1]; + Point Axis2 = mRot[2]; + + Axis0 *= mExtents.x; + Axis1 *= mExtents.y; + Axis2 *= mExtents.z; + + // 7+------+6 0 = --- + // /| /| 1 = +-- + // / | / | 2 = ++- + // / 4+---/--+5 3 = -+- + // 3+------+2 / y z 4 = --+ + // | / | / | / 5 = +-+ + // |/ |/ |/ 6 = +++ + // 0+------+1 *---x 7 = -++ + + pts[0] = mCenter - Axis0 - Axis1 - Axis2; + pts[1] = mCenter + Axis0 - Axis1 - Axis2; + pts[2] = mCenter + Axis0 + Axis1 - Axis2; + pts[3] = mCenter - Axis0 + Axis1 - Axis2; + pts[4] = mCenter - Axis0 - Axis1 + Axis2; + pts[5] = mCenter + Axis0 - Axis1 + Axis2; + pts[6] = mCenter + Axis0 + Axis1 + Axis2; + pts[7] = mCenter - Axis0 + Axis1 + Axis2; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes vertex normals. + * \param pts [out] 8 box points + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool OBB::ComputeVertexNormals(Point* pts) const +{ + static float VertexNormals[] = + { + -INVSQRT3, -INVSQRT3, -INVSQRT3, + INVSQRT3, -INVSQRT3, -INVSQRT3, + INVSQRT3, INVSQRT3, -INVSQRT3, + -INVSQRT3, INVSQRT3, -INVSQRT3, + -INVSQRT3, -INVSQRT3, INVSQRT3, + INVSQRT3, -INVSQRT3, INVSQRT3, + INVSQRT3, INVSQRT3, INVSQRT3, + -INVSQRT3, INVSQRT3, INVSQRT3 + }; + + if(!pts) return false; + + const Point* VN = (const Point*)VertexNormals; + for(udword i=0;i<8;i++) + { + pts[i] = VN[i] * mRot; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Returns edges. + * \return 24 indices (12 edges) indexing the list returned by ComputePoints() + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const udword* OBB::GetEdges() const +{ + static udword Indices[] = { + 0, 1, 1, 2, 2, 3, 3, 0, + 7, 6, 6, 5, 5, 4, 4, 7, + 1, 5, 6, 2, + 3, 7, 4, 0 + }; + return Indices; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Returns local edge normals. + * \return edge normals in local space + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const Point* OBB::GetLocalEdgeNormals() const +{ + static float EdgeNormals[] = + { + 0, -INVSQRT2, -INVSQRT2, // 0-1 + INVSQRT2, 0, -INVSQRT2, // 1-2 + 0, INVSQRT2, -INVSQRT2, // 2-3 + -INVSQRT2, 0, -INVSQRT2, // 3-0 + + 0, INVSQRT2, INVSQRT2, // 7-6 + INVSQRT2, 0, INVSQRT2, // 6-5 + 0, -INVSQRT2, INVSQRT2, // 5-4 + -INVSQRT2, 0, INVSQRT2, // 4-7 + + INVSQRT2, -INVSQRT2, 0, // 1-5 + INVSQRT2, INVSQRT2, 0, // 6-2 + -INVSQRT2, INVSQRT2, 0, // 3-7 + -INVSQRT2, -INVSQRT2, 0 // 4-0 + }; + return (const Point*)EdgeNormals; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Returns world edge normal + * \param edge_index [in] 0 <= edge index < 12 + * \param world_normal [out] edge normal in world space + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBB::ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const +{ + ASSERT(edge_index<12); + world_normal = GetLocalEdgeNormals()[edge_index] * mRot; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes an LSS surrounding the OBB. + * \param lss [out] the LSS + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBB::ComputeLSS(LSS& lss) const +{ + Point Axis0 = mRot[0]; + Point Axis1 = mRot[1]; + Point Axis2 = mRot[2]; + + switch(mExtents.LargestAxis()) + { + case 0: + lss.mRadius = (mExtents.y + mExtents.z)*0.5f; + lss.mP0 = mCenter + Axis0 * (mExtents.x - lss.mRadius); + lss.mP1 = mCenter - Axis0 * (mExtents.x - lss.mRadius); + break; + case 1: + lss.mRadius = (mExtents.x + mExtents.z)*0.5f; + lss.mP0 = mCenter + Axis1 * (mExtents.y - lss.mRadius); + lss.mP1 = mCenter - Axis1 * (mExtents.y - lss.mRadius); + break; + case 2: + lss.mRadius = (mExtents.x + mExtents.y)*0.5f; + lss.mP0 = mCenter + Axis2 * (mExtents.z - lss.mRadius); + lss.mP1 = mCenter - Axis2 * (mExtents.z - lss.mRadius); + break; + default: + break; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the OBB is inside another OBB. + * \param box [in] the other OBB + * \return TRUE if we're inside the other box + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL OBB::IsInside(const OBB& box) const +{ + // Make a 4x4 from the box & inverse it + Matrix4x4 M0Inv; + { + Matrix4x4 M0 = box.mRot; + M0.SetTrans(box.mCenter); + InvertPRMatrix(M0Inv, M0); + } + + // With our inversed 4x4, create box1 in space of box0 + OBB _1in0; + Rotate(M0Inv, _1in0); + + // This should cancel out box0's rotation, i.e. it's now an AABB. + // => Center(0,0,0), Rot(identity) + + // The two boxes are in the same space so now we can compare them. + + // Create the AABB of (box1 in space of box0) + const Matrix3x3& mtx = _1in0.mRot; + + float f = fabsf(mtx.m[0][0] * mExtents.x) + fabsf(mtx.m[1][0] * mExtents.y) + fabsf(mtx.m[2][0] * mExtents.z) - box.mExtents.x; + if(f > _1in0.mCenter.x) return FALSE; + if(-f < _1in0.mCenter.x) return FALSE; + + f = fabsf(mtx.m[0][1] * mExtents.x) + fabsf(mtx.m[1][1] * mExtents.y) + fabsf(mtx.m[2][1] * mExtents.z) - box.mExtents.y; + if(f > _1in0.mCenter.y) return FALSE; + if(-f < _1in0.mCenter.y) return FALSE; + + f = fabsf(mtx.m[0][2] * mExtents.x) + fabsf(mtx.m[1][2] * mExtents.y) + fabsf(mtx.m[2][2] * mExtents.z) - box.mExtents.z; + if(f > _1in0.mCenter.z) return FALSE; + if(-f < _1in0.mCenter.z) return FALSE; + + return TRUE; +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceOBB.h b/src/external/open_dynamics_engine-ef/ode/IceOBB.h new file mode 100644 index 00000000..d6cf43e0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceOBB.h @@ -0,0 +1,177 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains OBB-related code. (oriented bounding box) + * \file IceOBB.h + * \author Pierre Terdiman + * \date January, 13, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEOBB_H__ +#define __ICEOBB_H__ + + // Forward declarations + class LSS; + + class ICEMATHS_API OBB + { + public: + //! Constructor + inline_ OBB() {} + //! Constructor + inline_ OBB(const Point& center, const Point& extents, const Matrix3x3& rot) : mCenter(center), mExtents(extents), mRot(rot) {} + //! Destructor + inline_ ~OBB() {} + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an empty OBB. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void SetEmpty() + { + mCenter.Zero(); + mExtents.Set(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); + mRot.Identity(); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Tests if a point is contained within the OBB. + * \param p [in] the world point to test + * \return true if inside the OBB + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool ContainsPoint(const Point& p) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Builds an OBB from an AABB and a world transform. + * \param aabb [in] the aabb + * \param mat [in] the world transform + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void Create(const AABB& aabb, const Matrix4x4& mat); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Recomputes the OBB after an arbitrary transform by a 4x4 matrix. + * \param mtx [in] the transform matrix + * \param obb [out] the transformed OBB + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void Rotate(const Matrix4x4& mtx, OBB& obb) const + { + // The extents remain constant + obb.mExtents = mExtents; + // The center gets x-formed + obb.mCenter = mCenter * mtx; + // Combine rotations + obb.mRot = mRot * Matrix3x3(mtx); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the OBB is valid. + * \return true if the box is valid + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL IsValid() const + { + // Consistency condition for (Center, Extents) boxes: Extents >= 0.0f + if(mExtents.x < 0.0f) return FALSE; + if(mExtents.y < 0.0f) return FALSE; + if(mExtents.z < 0.0f) return FALSE; + return TRUE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes the obb planes. + * \param planes [out] 6 box planes + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool ComputePlanes(Plane* planes) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes the obb points. + * \param pts [out] 8 box points + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool ComputePoints(Point* pts) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes vertex normals. + * \param pts [out] 8 box points + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool ComputeVertexNormals(Point* pts) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Returns edges. + * \return 24 indices (12 edges) indexing the list returned by ComputePoints() + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + const udword* GetEdges() const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Returns local edge normals. + * \return edge normals in local space + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + const Point* GetLocalEdgeNormals() const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Returns world edge normal + * \param edge_index [in] 0 <= edge index < 12 + * \param world_normal [out] edge normal in world space + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void ComputeWorldEdgeNormal(udword edge_index, Point& world_normal) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes an LSS surrounding the OBB. + * \param lss [out] the LSS + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + void ComputeLSS(LSS& lss) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the OBB is inside another OBB. + * \param box [in] the other OBB + * \return TRUE if we're inside the other box + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + BOOL IsInside(const OBB& box) const; + + inline_ const Point& GetCenter() const { return mCenter; } + inline_ const Point& GetExtents() const { return mExtents; } + inline_ const Matrix3x3& GetRot() const { return mRot; } + + inline_ void GetRotatedExtents(Matrix3x3& extents) const + { + extents = mRot; + extents.Scale(mExtents); + } + + Point mCenter; //!< B for Box + Point mExtents; //!< B for Bounding + Matrix3x3 mRot; //!< O for Oriented + + // Orientation is stored in row-major format, + // i.e. rows = eigen vectors of the covariance matrix + }; + +#endif // __ICEOBB_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IcePairs.h b/src/external/open_dynamics_engine-ef/ode/IcePairs.h new file mode 100644 index 00000000..2c09b929 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IcePairs.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a simple pair class. + * \file IcePairs.h + * \author Pierre Terdiman + * \date January, 13, 2003 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEPAIRS_H__ +#define __ICEPAIRS_H__ + + //! A generic couple structure + struct ICECORE_API Pair + { + inline_ Pair() {} + inline_ Pair(udword i0, udword i1) : id0(i0), id1(i1) {} + + udword id0; //!< First index of the pair + udword id1; //!< Second index of the pair + }; + + class ICECORE_API Pairs : private Container + { + public: + // Constructor / Destructor + Pairs() {} + ~Pairs() {} + + inline_ udword GetNbPairs() const { return GetNbEntries()>>1; } + inline_ const Pair* GetPairs() const { return (const Pair*)GetEntries(); } + inline_ const Pair* GetPair(udword i) const { return (const Pair*)&GetEntries()[i+i]; } + + inline_ BOOL HasPairs() const { return IsNotEmpty(); } + + inline_ void ResetPairs() { Reset(); } + inline_ void DeleteLastPair() { DeleteLastEntry(); DeleteLastEntry(); } + + inline_ void AddPair(const Pair& p) { Add(p.id0).Add(p.id1); } + inline_ void AddPair(udword id0, udword id1) { Add(id0).Add(id1); } + }; + +#endif // __ICEPAIRS_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IcePlane.cpp b/src/external/open_dynamics_engine-ef/ode/IcePlane.cpp new file mode 100644 index 00000000..6d1aad9f --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IcePlane.cpp @@ -0,0 +1,53 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for planes. + * \file IcePlane.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Plane class. + * \class Plane + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the plane equation from 3 points. + * \param p0 [in] first point + * \param p1 [in] second point + * \param p2 [in] third point + * \return Self-reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Plane& Plane::Set(const Point& p0, const Point& p1, const Point& p2) +{ + Point Edge0 = p1 - p0; + Point Edge1 = p2 - p0; + + n = Edge0 ^ Edge1; + n.Normalize(); + + d = -(p0 | n); + + return *this; +} diff --git a/src/external/open_dynamics_engine-ef/ode/IcePlane.h b/src/external/open_dynamics_engine-ef/ode/IcePlane.h new file mode 100644 index 00000000..4d470814 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IcePlane.h @@ -0,0 +1,113 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for planes. + * \file IcePlane.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEPLANE_H__ +#define __ICEPLANE_H__ + + #define PLANE_EPSILON (1.0e-7f) + + class ICEMATHS_API Plane + { + public: + //! Constructor + inline_ Plane() { } + //! Constructor from a normal and a distance + inline_ Plane(float nx, float ny, float nz, float d) { Set(nx, ny, nz, d); } + //! Constructor from a point on the plane and a normal + inline_ Plane(const Point& p, const Point& n) { Set(p, n); } + //! Constructor from three points + inline_ Plane(const Point& p0, const Point& p1, const Point& p2) { Set(p0, p1, p2); } + //! Constructor from a normal and a distance + inline_ Plane(const Point& _n, float _d) { n = _n; d = _d; } + //! Copy constructor + inline_ Plane(const Plane& plane) : n(plane.n), d(plane.d) { } + //! Destructor + inline_ ~Plane() { } + + inline_ Plane& Zero() { n.Zero(); d = 0.0f; return *this; } + inline_ Plane& Set(float nx, float ny, float nz, float _d) { n.Set(nx, ny, nz); d = _d; return *this; } + inline_ Plane& Set(const Point& p, const Point& _n) { n = _n; d = - p | _n; return *this; } + Plane& Set(const Point& p0, const Point& p1, const Point& p2); + + inline_ float Distance(const Point& p) const { return (p | n) + d; } + inline_ bool Belongs(const Point& p) const { return fabsf(Distance(p)) < PLANE_EPSILON; } + + inline_ void Normalize() + { + float Denom = 1.0f / n.Magnitude(); + n.x *= Denom; + n.y *= Denom; + n.z *= Denom; + d *= Denom; + } + public: + // Members + Point n; //!< The normal to the plane + float d; //!< The distance from the origin + + // Cast operators + inline_ operator Point() const { return n; } + inline_ operator HPoint() const { return HPoint(n, d); } + + // Arithmetic operators + inline_ Plane operator*(const Matrix4x4& m) const + { + // Old code from Irion. Kept for reference. + Plane Ret(*this); + return Ret *= m; + } + + inline_ Plane& operator*=(const Matrix4x4& m) + { + // Old code from Irion. Kept for reference. + Point n2 = HPoint(n, 0.0f) * m; + d = -((Point) (HPoint( -d*n, 1.0f ) * m) | n2); + n = n2; + return *this; + } + }; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster. + * \param transformed [out] transformed plane + * \param plane [in] source plane + * \param transform [in] transform matrix + * \warning the plane normal must be unit-length + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void TransformPlane(Plane& transformed, const Plane& plane, const Matrix4x4& transform) + { + // Rotate the normal using the rotation part of the 4x4 matrix + transformed.n = plane.n * Matrix3x3(transform); + + // Compute new d + transformed.d = plane.d - (Point(transform.GetTrans())|transformed.n); + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Transforms a plane by a 4x4 matrix. Same as Plane * Matrix4x4 operator, but faster. + * \param plane [in/out] source plane (transformed on return) + * \param transform [in] transform matrix + * \warning the plane normal must be unit-length + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void TransformPlane(Plane& plane, const Matrix4x4& transform) + { + // Rotate the normal using the rotation part of the 4x4 matrix + plane.n *= Matrix3x3(transform); + + // Compute new d + plane.d -= Point(transform.GetTrans())|plane.n; + } + +#endif // __ICEPLANE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IcePoint.cpp b/src/external/open_dynamics_engine-ef/ode/IcePoint.cpp new file mode 100644 index 00000000..25b4f4ad --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IcePoint.cpp @@ -0,0 +1,201 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for 3D vectors. + * \file IcePoint.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * 3D point. + * + * The name is "Point" instead of "Vector" since a vector is N-dimensional, whereas a point is an implicit "vector of dimension 3". + * So the choice was between "Point" and "Vector3", the first one looked better (IMHO). + * + * Some people, then, use a typedef to handle both points & vectors using the same class: typedef Point Vector3; + * This is bad since it opens the door to a lot of confusion while reading the code. I know it may sounds weird but check this out: + * + * \code + * Point P0,P1 = some 3D points; + * Point Delta = P1 - P0; + * \endcode + * + * This compiles fine, although you should have written: + * + * \code + * Point P0,P1 = some 3D points; + * Vector3 Delta = P1 - P0; + * \endcode + * + * Subtle things like this are not caught at compile-time, and when you find one in the code, you never know whether it's a mistake + * from the author or something you don't get. + * + * One way to handle it at compile-time would be to use different classes for Point & Vector3, only overloading operator "-" for vectors. + * But then, you get a lot of redundant code in thoses classes, and basically it's really a lot of useless work. + * + * Another way would be to use homogeneous points: w=1 for points, w=0 for vectors. That's why the HPoint class exists. Now, to store + * your model's vertices and in most cases, you really want to use Points to save ram. + * + * \class Point + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Creates a positive unit random vector. + * \return Self-reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Point& Point::PositiveUnitRandomVector() +{ + x = UnitRandomFloat(); + y = UnitRandomFloat(); + z = UnitRandomFloat(); + Normalize(); + return *this; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Creates a unit random vector. + * \return Self-reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Point& Point::UnitRandomVector() +{ + x = UnitRandomFloat() - 0.5f; + y = UnitRandomFloat() - 0.5f; + z = UnitRandomFloat() - 0.5f; + Normalize(); + return *this; +} + +// Cast operator +// WARNING: not inlined +Point::operator HPoint() const { return HPoint(x, y, z, 0.0f); } + +Point& Point::Refract(const Point& eye, const Point& n, float refractindex, Point& refracted) +{ + // Point EyePt = eye position + // Point p = current vertex + // Point n = vertex normal + // Point rv = refracted vector + // Eye vector - doesn't need to be normalized + Point Env; + Env.x = eye.x - x; + Env.y = eye.y - y; + Env.z = eye.z - z; + + float NDotE = n|Env; + float NDotN = n|n; + NDotE /= refractindex; + + // Refracted vector + refracted = n*NDotE - Env*NDotN; + + return *this; +} + +Point& Point::ProjectToPlane(const Plane& p) +{ + *this-= (p.d + (*this|p.n))*p.n; + return *this; +} + +void Point::ProjectToScreen(float halfrenderwidth, float halfrenderheight, const Matrix4x4& mat, HPoint& projected) const +{ + projected = HPoint(x, y, z, 1.0f) * mat; + projected.w = 1.0f / projected.w; + + projected.x*=projected.w; + projected.y*=projected.w; + projected.z*=projected.w; + + projected.x *= halfrenderwidth; projected.x += halfrenderwidth; + projected.y *= -halfrenderheight; projected.y += halfrenderheight; +} + +void Point::SetNotUsed() +{ + // We use a particular integer pattern : 0xffffffff everywhere. This is a NAN. + IR(x) = 0xffffffff; + IR(y) = 0xffffffff; + IR(z) = 0xffffffff; +} + +BOOL Point::IsNotUsed() const +{ + if(IR(x)!=0xffffffff) return FALSE; + if(IR(y)!=0xffffffff) return FALSE; + if(IR(z)!=0xffffffff) return FALSE; + return TRUE; +} + +Point& Point::Mult(const Matrix3x3& mat, const Point& a) +{ + x = a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2]; + y = a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2]; + z = a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2]; + return *this; +} + +Point& Point::Mult2(const Matrix3x3& mat1, const Point& a1, const Matrix3x3& mat2, const Point& a2) +{ + x = a1.x * mat1.m[0][0] + a1.y * mat1.m[0][1] + a1.z * mat1.m[0][2] + a2.x * mat2.m[0][0] + a2.y * mat2.m[0][1] + a2.z * mat2.m[0][2]; + y = a1.x * mat1.m[1][0] + a1.y * mat1.m[1][1] + a1.z * mat1.m[1][2] + a2.x * mat2.m[1][0] + a2.y * mat2.m[1][1] + a2.z * mat2.m[1][2]; + z = a1.x * mat1.m[2][0] + a1.y * mat1.m[2][1] + a1.z * mat1.m[2][2] + a2.x * mat2.m[2][0] + a2.y * mat2.m[2][1] + a2.z * mat2.m[2][2]; + return *this; +} + +Point& Point::Mac(const Matrix3x3& mat, const Point& a) +{ + x += a.x * mat.m[0][0] + a.y * mat.m[0][1] + a.z * mat.m[0][2]; + y += a.x * mat.m[1][0] + a.y * mat.m[1][1] + a.z * mat.m[1][2]; + z += a.x * mat.m[2][0] + a.y * mat.m[2][1] + a.z * mat.m[2][2]; + return *this; +} + +Point& Point::TransMult(const Matrix3x3& mat, const Point& a) +{ + x = a.x * mat.m[0][0] + a.y * mat.m[1][0] + a.z * mat.m[2][0]; + y = a.x * mat.m[0][1] + a.y * mat.m[1][1] + a.z * mat.m[2][1]; + z = a.x * mat.m[0][2] + a.y * mat.m[1][2] + a.z * mat.m[2][2]; + return *this; +} + +Point& Point::Transform(const Point& r, const Matrix3x3& rotpos, const Point& linpos) +{ + x = r.x * rotpos.m[0][0] + r.y * rotpos.m[0][1] + r.z * rotpos.m[0][2] + linpos.x; + y = r.x * rotpos.m[1][0] + r.y * rotpos.m[1][1] + r.z * rotpos.m[1][2] + linpos.y; + z = r.x * rotpos.m[2][0] + r.y * rotpos.m[2][1] + r.z * rotpos.m[2][2] + linpos.z; + return *this; +} + +Point& Point::InvTransform(const Point& r, const Matrix3x3& rotpos, const Point& linpos) +{ + float sx = r.x - linpos.x; + float sy = r.y - linpos.y; + float sz = r.z - linpos.z; + x = sx * rotpos.m[0][0] + sy * rotpos.m[1][0] + sz * rotpos.m[2][0]; + y = sx * rotpos.m[0][1] + sy * rotpos.m[1][1] + sz * rotpos.m[2][1]; + z = sx * rotpos.m[0][2] + sy * rotpos.m[1][2] + sz * rotpos.m[2][2]; + return *this; +} diff --git a/src/external/open_dynamics_engine-ef/ode/IcePoint.h b/src/external/open_dynamics_engine-ef/ode/IcePoint.h new file mode 100644 index 00000000..dd8d28ec --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IcePoint.h @@ -0,0 +1,528 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for 3D vectors. + * \file IcePoint.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEPOINT_H__ +#define __ICEPOINT_H__ + + // Forward declarations + class HPoint; + class Plane; + class Matrix3x3; + class Matrix4x4; + + #define CROSS2D(a, b) (a.x*b.y - b.x*a.y) + + const float EPSILON2 = 1.0e-20f; + + class ICEMATHS_API Point + { + public: + + //! Empty constructor + inline_ Point() {} + //! Constructor from a single float +// inline_ Point(float val) : x(val), y(val), z(val) {} +// Removed since it introduced the nasty "Point T = *Matrix4x4.GetTrans();" bug....... + //! Constructor from floats + inline_ Point(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {} + //! Constructor from array + inline_ Point(const float f[3]) : x(f[_X]), y(f[_Y]), z(f[_Z]) {} + //! Copy constructor + inline_ Point(const Point& p) : x(p.x), y(p.y), z(p.z) {} + //! Destructor + inline_ ~Point() {} + + //! Clears the vector + inline_ Point& Zero() { x = y = z = 0.0f; return *this; } + + //! + infinity + inline_ Point& SetPlusInfinity() { x = y = z = MAX_FLOAT; return *this; } + //! - infinity + inline_ Point& SetMinusInfinity() { x = y = z = MIN_FLOAT; return *this; } + + //! Sets positive unit random vector + Point& PositiveUnitRandomVector(); + //! Sets unit random vector + Point& UnitRandomVector(); + + //! Assignment from values + inline_ Point& Set(float _x, float _y, float _z) { x = _x; y = _y; z = _z; return *this; } + //! Assignment from array + inline_ Point& Set(const float f[3]) { x = f[_X]; y = f[_Y]; z = f[_Z]; return *this; } + //! Assignment from another point + inline_ Point& Set(const Point& src) { x = src.x; y = src.y; z = src.z; return *this; } + + //! Adds a vector + inline_ Point& Add(const Point& p) { x += p.x; y += p.y; z += p.z; return *this; } + //! Adds a vector + inline_ Point& Add(float _x, float _y, float _z) { x += _x; y += _y; z += _z; return *this; } + //! Adds a vector + inline_ Point& Add(const float f[3]) { x += f[_X]; y += f[_Y]; z += f[_Z]; return *this; } + //! Adds vectors + inline_ Point& Add(const Point& p, const Point& q) { x = p.x+q.x; y = p.y+q.y; z = p.z+q.z; return *this; } + + //! Subtracts a vector + inline_ Point& Sub(const Point& p) { x -= p.x; y -= p.y; z -= p.z; return *this; } + //! Subtracts a vector + inline_ Point& Sub(float _x, float _y, float _z) { x -= _x; y -= _y; z -= _z; return *this; } + //! Subtracts a vector + inline_ Point& Sub(const float f[3]) { x -= f[_X]; y -= f[_Y]; z -= f[_Z]; return *this; } + //! Subtracts vectors + inline_ Point& Sub(const Point& p, const Point& q) { x = p.x-q.x; y = p.y-q.y; z = p.z-q.z; return *this; } + + //! this = -this + inline_ Point& Neg() { x = -x; y = -y; z = -z; return *this; } + //! this = -a + inline_ Point& Neg(const Point& a) { x = -a.x; y = -a.y; z = -a.z; return *this; } + + //! Multiplies by a scalar + inline_ Point& Mult(float s) { x *= s; y *= s; z *= s; return *this; } + + //! this = a * scalar + inline_ Point& Mult(const Point& a, float scalar) + { + x = a.x * scalar; + y = a.y * scalar; + z = a.z * scalar; + return *this; + } + + //! this = a + b * scalar + inline_ Point& Mac(const Point& a, const Point& b, float scalar) + { + x = a.x + b.x * scalar; + y = a.y + b.y * scalar; + z = a.z + b.z * scalar; + return *this; + } + + //! this = this + a * scalar + inline_ Point& Mac(const Point& a, float scalar) + { + x += a.x * scalar; + y += a.y * scalar; + z += a.z * scalar; + return *this; + } + + //! this = a - b * scalar + inline_ Point& Msc(const Point& a, const Point& b, float scalar) + { + x = a.x - b.x * scalar; + y = a.y - b.y * scalar; + z = a.z - b.z * scalar; + return *this; + } + + //! this = this - a * scalar + inline_ Point& Msc(const Point& a, float scalar) + { + x -= a.x * scalar; + y -= a.y * scalar; + z -= a.z * scalar; + return *this; + } + + //! this = a + b * scalarb + c * scalarc + inline_ Point& Mac2(const Point& a, const Point& b, float scalarb, const Point& c, float scalarc) + { + x = a.x + b.x * scalarb + c.x * scalarc; + y = a.y + b.y * scalarb + c.y * scalarc; + z = a.z + b.z * scalarb + c.z * scalarc; + return *this; + } + + //! this = a - b * scalarb - c * scalarc + inline_ Point& Msc2(const Point& a, const Point& b, float scalarb, const Point& c, float scalarc) + { + x = a.x - b.x * scalarb - c.x * scalarc; + y = a.y - b.y * scalarb - c.y * scalarc; + z = a.z - b.z * scalarb - c.z * scalarc; + return *this; + } + + //! this = mat * a + inline_ Point& Mult(const Matrix3x3& mat, const Point& a); + + //! this = mat1 * a1 + mat2 * a2 + inline_ Point& Mult2(const Matrix3x3& mat1, const Point& a1, const Matrix3x3& mat2, const Point& a2); + + //! this = this + mat * a + inline_ Point& Mac(const Matrix3x3& mat, const Point& a); + + //! this = transpose(mat) * a + inline_ Point& TransMult(const Matrix3x3& mat, const Point& a); + + //! Linear interpolate between two vectors: this = a + t * (b - a) + inline_ Point& Lerp(const Point& a, const Point& b, float t) + { + x = a.x + t * (b.x - a.x); + y = a.y + t * (b.y - a.y); + z = a.z + t * (b.z - a.z); + return *this; + } + + //! Hermite interpolate between p1 and p2. p0 and p3 are used for finding gradient at p1 and p2. + //! this = p0 * (2t^2 - t^3 - t)/2 + //! + p1 * (3t^3 - 5t^2 + 2)/2 + //! + p2 * (4t^2 - 3t^3 + t)/2 + //! + p3 * (t^3 - t^2)/2 + inline_ Point& Herp(const Point& p0, const Point& p1, const Point& p2, const Point& p3, float t) + { + float t2 = t * t; + float t3 = t2 * t; + float kp0 = (2.0f * t2 - t3 - t) * 0.5f; + float kp1 = (3.0f * t3 - 5.0f * t2 + 2.0f) * 0.5f; + float kp2 = (4.0f * t2 - 3.0f * t3 + t) * 0.5f; + float kp3 = (t3 - t2) * 0.5f; + x = p0.x * kp0 + p1.x * kp1 + p2.x * kp2 + p3.x * kp3; + y = p0.y * kp0 + p1.y * kp1 + p2.y * kp2 + p3.y * kp3; + z = p0.z * kp0 + p1.z * kp1 + p2.z * kp2 + p3.z * kp3; + return *this; + } + + //! this = rotpos * r + linpos + inline_ Point& Transform(const Point& r, const Matrix3x3& rotpos, const Point& linpos); + + //! this = trans(rotpos) * (r - linpos) + inline_ Point& InvTransform(const Point& r, const Matrix3x3& rotpos, const Point& linpos); + + //! Returns MIN(x, y, z); + inline_ float Min() const { return MIN(x, MIN(y, z)); } + //! Returns MAX(x, y, z); + inline_ float Max() const { return MAX(x, MAX(y, z)); } + //! Sets each element to be componentwise minimum + inline_ Point& Min(const Point& p) { x = MIN(x, p.x); y = MIN(y, p.y); z = MIN(z, p.z); return *this; } + //! Sets each element to be componentwise maximum + inline_ Point& Max(const Point& p) { x = MAX(x, p.x); y = MAX(y, p.y); z = MAX(z, p.z); return *this; } + + //! Clamps each element + inline_ Point& Clamp(float min, float max) + { + if(xmax) x=max; + if(ymax) y=max; + if(zmax) z=max; + return *this; + } + + //! Computes square magnitude + inline_ float SquareMagnitude() const { return x*x + y*y + z*z; } + //! Computes magnitude + inline_ float Magnitude() const { return sqrtf(x*x + y*y + z*z); } + //! Computes volume + inline_ float Volume() const { return x * y * z; } + + //! Checks the point is near zero + inline_ bool ApproxZero() const { return SquareMagnitude() < EPSILON2; } + + //! Tests for exact zero vector + inline_ BOOL IsZero() const + { + if(IR(x) || IR(y) || IR(z)) return FALSE; + return TRUE; + } + + //! Checks point validity + inline_ BOOL IsValid() const + { + if(!IsValidFloat(x)) return FALSE; + if(!IsValidFloat(y)) return FALSE; + if(!IsValidFloat(z)) return FALSE; + return TRUE; + } + + //! Slighty moves the point + void Tweak(udword coord_mask, udword tweak_mask) + { + if(coord_mask&1) { udword Dummy = IR(x); Dummy^=tweak_mask; x = FR(Dummy); } + if(coord_mask&2) { udword Dummy = IR(y); Dummy^=tweak_mask; y = FR(Dummy); } + if(coord_mask&4) { udword Dummy = IR(z); Dummy^=tweak_mask; z = FR(Dummy); } + } + + #define TWEAKMASK 0x3fffff + #define TWEAKNOTMASK ~TWEAKMASK + //! Slighty moves the point out + inline_ void TweakBigger() + { + udword Dummy = (IR(x)&TWEAKNOTMASK); if(!IS_NEGATIVE_FLOAT(x)) Dummy+=TWEAKMASK+1; x = FR(Dummy); + Dummy = (IR(y)&TWEAKNOTMASK); if(!IS_NEGATIVE_FLOAT(y)) Dummy+=TWEAKMASK+1; y = FR(Dummy); + Dummy = (IR(z)&TWEAKNOTMASK); if(!IS_NEGATIVE_FLOAT(z)) Dummy+=TWEAKMASK+1; z = FR(Dummy); + } + + //! Slighty moves the point in + inline_ void TweakSmaller() + { + udword Dummy = (IR(x)&TWEAKNOTMASK); if(IS_NEGATIVE_FLOAT(x)) Dummy+=TWEAKMASK+1; x = FR(Dummy); + Dummy = (IR(y)&TWEAKNOTMASK); if(IS_NEGATIVE_FLOAT(y)) Dummy+=TWEAKMASK+1; y = FR(Dummy); + Dummy = (IR(z)&TWEAKNOTMASK); if(IS_NEGATIVE_FLOAT(z)) Dummy+=TWEAKMASK+1; z = FR(Dummy); + } + + //! Normalizes the vector + inline_ Point& Normalize() + { + float M = x*x + y*y + z*z; + if(M) + { + M = 1.0f / sqrtf(M); + x *= M; + y *= M; + z *= M; + } + return *this; + } + + //! Sets vector length + inline_ Point& SetLength(float length) + { + float NewLength = length / Magnitude(); + x *= NewLength; + y *= NewLength; + z *= NewLength; + return *this; + } + + //! Clamps vector length + inline_ Point& ClampLength(float limit_length) + { + if(limit_length>=0.0f) // Magnitude must be positive + { + float CurrentSquareLength = SquareMagnitude(); + + if(CurrentSquareLength > limit_length * limit_length) + { + float Coeff = limit_length / sqrtf(CurrentSquareLength); + x *= Coeff; + y *= Coeff; + z *= Coeff; + } + } + return *this; + } + + //! Computes distance to another point + inline_ float Distance(const Point& b) const + { + return sqrtf((x - b.x)*(x - b.x) + (y - b.y)*(y - b.y) + (z - b.z)*(z - b.z)); + } + + //! Computes square distance to another point + inline_ float SquareDistance(const Point& b) const + { + return ((x - b.x)*(x - b.x) + (y - b.y)*(y - b.y) + (z - b.z)*(z - b.z)); + } + + //! Dot product dp = this|a + inline_ float Dot(const Point& p) const { return p.x * x + p.y * y + p.z * z; } + + //! Cross product this = a x b + inline_ Point& Cross(const Point& a, const Point& b) + { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + return *this; + } + + //! Vector code ( bitmask = sign(z) | sign(y) | sign(x) ) + inline_ udword VectorCode() const + { + return (IR(x)>>31) | ((IR(y)&SIGN_BITMASK)>>30) | ((IR(z)&SIGN_BITMASK)>>29); + } + + //! Returns largest axis + inline_ PointComponent LargestAxis() const + { + const float* Vals = &x; + PointComponent m = _X; + if(Vals[_Y] > Vals[m]) m = _Y; + if(Vals[_Z] > Vals[m]) m = _Z; + return m; + } + + //! Returns closest axis + inline_ PointComponent ClosestAxis() const + { + const float* Vals = &x; + PointComponent m = _X; + if(AIR(Vals[_Y]) > AIR(Vals[m])) m = _Y; + if(AIR(Vals[_Z]) > AIR(Vals[m])) m = _Z; + return m; + } + + //! Returns smallest axis + inline_ PointComponent SmallestAxis() const + { + const float* Vals = &x; + PointComponent m = _X; + if(Vals[_Y] < Vals[m]) m = _Y; + if(Vals[_Z] < Vals[m]) m = _Z; + return m; + } + + //! Refracts the point + Point& Refract(const Point& eye, const Point& n, float refractindex, Point& refracted); + + //! Projects the point onto a plane + Point& ProjectToPlane(const Plane& p); + + //! Projects the point onto the screen + void ProjectToScreen(float halfrenderwidth, float halfrenderheight, const Matrix4x4& mat, HPoint& projected) const; + + //! Unfolds the point onto a plane according to edge(a,b) + Point& Unfold(Plane& p, Point& a, Point& b); + + //! Hash function from Ville Miettinen + inline_ udword GetHashValue() const + { + const udword* h = (const udword*)(this); + udword f = (h[0]+h[1]*11-(h[2]*17)) & 0x7fffffff; // avoid problems with +-0 + return (f>>22)^(f>>12)^(f); + } + + //! Stuff magic values in the point, marking it as explicitely not used. + void SetNotUsed(); + //! Checks the point is marked as not used + BOOL IsNotUsed() const; + + // Arithmetic operators + + //! Unary operator for Point Negate = - Point + inline_ Point operator-() const { return Point(-x, -y, -z); } + + //! Operator for Point Plus = Point + Point. + inline_ Point operator+(const Point& p) const { return Point(x + p.x, y + p.y, z + p.z); } + //! Operator for Point Minus = Point - Point. + inline_ Point operator-(const Point& p) const { return Point(x - p.x, y - p.y, z - p.z); } + + //! Operator for Point Mul = Point * Point. + inline_ Point operator*(const Point& p) const { return Point(x * p.x, y * p.y, z * p.z); } + //! Operator for Point Scale = Point * float. + inline_ Point operator*(float s) const { return Point(x * s, y * s, z * s ); } + //! Operator for Point Scale = float * Point. + inline_ friend Point operator*(float s, const Point& p) { return Point(s * p.x, s * p.y, s * p.z); } + + //! Operator for Point Div = Point / Point. + inline_ Point operator/(const Point& p) const { return Point(x / p.x, y / p.y, z / p.z); } + //! Operator for Point Scale = Point / float. + inline_ Point operator/(float s) const { s = 1.0f / s; return Point(x * s, y * s, z * s); } + //! Operator for Point Scale = float / Point. + inline_ friend Point operator/(float s, const Point& p) { return Point(s / p.x, s / p.y, s / p.z); } + + //! Operator for float DotProd = Point | Point. + inline_ float operator|(const Point& p) const { return x*p.x + y*p.y + z*p.z; } + //! Operator for Point VecProd = Point ^ Point. + inline_ Point operator^(const Point& p) const + { + return Point( + y * p.z - z * p.y, + z * p.x - x * p.z, + x * p.y - y * p.x ); + } + + //! Operator for Point += Point. + inline_ Point& operator+=(const Point& p) { x += p.x; y += p.y; z += p.z; return *this; } + //! Operator for Point += float. + inline_ Point& operator+=(float s) { x += s; y += s; z += s; return *this; } + + //! Operator for Point -= Point. + inline_ Point& operator-=(const Point& p) { x -= p.x; y -= p.y; z -= p.z; return *this; } + //! Operator for Point -= float. + inline_ Point& operator-=(float s) { x -= s; y -= s; z -= s; return *this; } + + //! Operator for Point *= Point. + inline_ Point& operator*=(const Point& p) { x *= p.x; y *= p.y; z *= p.z; return *this; } + //! Operator for Point *= float. + inline_ Point& operator*=(float s) { x *= s; y *= s; z *= s; return *this; } + + //! Operator for Point /= Point. + inline_ Point& operator/=(const Point& p) { x /= p.x; y /= p.y; z /= p.z; return *this; } + //! Operator for Point /= float. + inline_ Point& operator/=(float s) { s = 1.0f/s; x *= s; y *= s; z *= s; return *this; } + + // Logical operators + + //! Operator for "if(Point==Point)" + inline_ bool operator==(const Point& p) const { return ( (IR(x)==IR(p.x))&&(IR(y)==IR(p.y))&&(IR(z)==IR(p.z))); } + //! Operator for "if(Point!=Point)" + inline_ bool operator!=(const Point& p) const { return ( (IR(x)!=IR(p.x))||(IR(y)!=IR(p.y))||(IR(z)!=IR(p.z))); } + + // Arithmetic operators + + //! Operator for Point Mul = Point * Matrix3x3. + inline_ Point operator*(const Matrix3x3& mat) const + { + class ShadowMatrix3x3{ public: float m[3][3]; }; // To allow inlining + const ShadowMatrix3x3* Mat = (const ShadowMatrix3x3*)&mat; + + return Point( + x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0], + x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1], + x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2] ); + } + + //! Operator for Point Mul = Point * Matrix4x4. + inline_ Point operator*(const Matrix4x4& mat) const + { + class ShadowMatrix4x4{ public: float m[4][4]; }; // To allow inlining + const ShadowMatrix4x4* Mat = (const ShadowMatrix4x4*)&mat; + + return Point( + x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0] + Mat->m[3][0], + x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1] + Mat->m[3][1], + x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2] + Mat->m[3][2]); + } + + //! Operator for Point *= Matrix3x3. + inline_ Point& operator*=(const Matrix3x3& mat) + { + class ShadowMatrix3x3{ public: float m[3][3]; }; // To allow inlining + const ShadowMatrix3x3* Mat = (const ShadowMatrix3x3*)&mat; + + float xp = x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0]; + float yp = x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1]; + float zp = x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2]; + + x = xp; y = yp; z = zp; + + return *this; + } + + //! Operator for Point *= Matrix4x4. + inline_ Point& operator*=(const Matrix4x4& mat) + { + class ShadowMatrix4x4{ public: float m[4][4]; }; // To allow inlining + const ShadowMatrix4x4* Mat = (const ShadowMatrix4x4*)&mat; + + float xp = x * Mat->m[0][0] + y * Mat->m[1][0] + z * Mat->m[2][0] + Mat->m[3][0]; + float yp = x * Mat->m[0][1] + y * Mat->m[1][1] + z * Mat->m[2][1] + Mat->m[3][1]; + float zp = x * Mat->m[0][2] + y * Mat->m[1][2] + z * Mat->m[2][2] + Mat->m[3][2]; + + x = xp; y = yp; z = zp; + + return *this; + } + + // Cast operators + + //! Cast a Point to a HPoint. w is set to zero. + operator HPoint() const; + + inline_ operator const float*() const { return &x; } + inline_ operator float*() { return &x; } + + public: + float x, y, z; + }; + + FUNCTION ICEMATHS_API void Normalize1(Point& a); + FUNCTION ICEMATHS_API void Normalize2(Point& a); + +#endif //__ICEPOINT_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IcePreprocessor.h b/src/external/open_dynamics_engine-ef/ode/IcePreprocessor.h new file mode 100644 index 00000000..dbeca382 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IcePreprocessor.h @@ -0,0 +1,132 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains preprocessor stuff. This should be the first included header. + * \file IcePreprocessor.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICEPREPROCESSOR_H__ +#define __ICEPREPROCESSOR_H__ + + // Check platform + #if defined( _WIN32 ) || defined( WIN32 ) + // #pragma message("Compiling on Windows...") + #define PLATFORM_WINDOWS + #else + // don't issue pragmas on unknown platforms + // #pragma message("Compiling on unknown platform...") + #endif + + // Check compiler + #if defined(_MSC_VER) + // #pragma message("Compiling with VC++...") + #define COMPILER_VISUAL_CPP + #else + // don't issue pragmas on unknown platforms + // #pragma message("Compiling with unknown compiler...") + #endif + + // Check compiler options. If this file is included in user-apps, this + // shouldn't be needed, so that they can use what they like best. + #ifndef ICE_DONT_CHECK_COMPILER_OPTIONS + #ifdef COMPILER_VISUAL_CPP + #if defined(_CHAR_UNSIGNED) + #endif + + #if defined(_CPPRTTI) + #error Please disable RTTI... + #endif + + #if defined(_CPPUNWIND) + #error Please disable exceptions... + #endif + + #if defined(_MT) + // Multithreading + #endif + #endif + #endif + + // Check debug mode + #ifdef DEBUG // May be defined instead of _DEBUG. Let's fix it. + #ifndef _DEBUG + #define _DEBUG + #endif + #endif + + #ifdef _DEBUG + // Here you may define items for debug builds + #endif + + #ifndef THIS_FILE + #define THIS_FILE __FILE__ + #endif + + #ifndef ICE_NO_DLL + #ifdef ICECORE_EXPORTS + #define ICECORE_API __declspec(dllexport) + #else + #define ICECORE_API __declspec(dllimport) + #endif + #else + #define ICECORE_API + #endif + + // Don't override new/delete +// #define DEFAULT_NEWDELETE + #define DONT_TRACK_MEMORY_LEAKS + + #define FUNCTION extern "C" + + // Cosmetic stuff [mainly useful with multiple inheritance] + #define override(base_class) virtual + + // Our own inline keyword, so that: + // - we can switch to __forceinline to check it's really better or not + // - we can remove __forceinline if the compiler doesn't support it +// #define inline_ __forceinline +// #define inline_ inline + + // Contributed by Bruce Mitchener + #if defined(COMPILER_VISUAL_CPP) + #define inline_ __forceinline +// #define inline_ inline + #elif defined(__GNUC__) && __GNUC__ < 3 + #define inline_ inline + #elif defined(__GNUC__) + #define inline_ inline __attribute__ ((always_inline)) + #else + #define inline_ inline + #endif + + // Down the hatch +#ifdef _MSC_VER + #pragma inline_depth( 255 ) +#endif + + #ifdef COMPILER_VISUAL_CPP + #pragma intrinsic(memcmp) + #pragma intrinsic(memcpy) + #pragma intrinsic(memset) + #pragma intrinsic(strcat) + #pragma intrinsic(strcmp) + #pragma intrinsic(strcpy) + #pragma intrinsic(strlen) + #pragma intrinsic(abs) + #pragma intrinsic(labs) + #endif + + // ANSI compliance + #ifdef _DEBUG + // Remove painful warning in debug + inline_ bool __False__(){ return false; } + #define for if(__False__()){} else for + #else + #define for if(0){} else for + #endif + +#endif // __ICEPREPROCESSOR_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceRandom.cpp b/src/external/open_dynamics_engine-ef/ode/IceRandom.cpp new file mode 100644 index 00000000..ce85af8d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceRandom.cpp @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for random generators. + * \file IceRandom.cpp + * \author Pierre Terdiman + * \date August, 9, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceCore; + +void IceCore:: SRand(udword seed) +{ + srand(seed); +} + +udword IceCore::Rand() +{ + return rand(); +} + + +static BasicRandom gRandomGenerator(42); + +udword IceCore::GetRandomIndex(udword max_index) +{ + // We don't use rand() since it's limited to RAND_MAX + udword Index = gRandomGenerator.Randomize(); + return Index % max_index; +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceRandom.h b/src/external/open_dynamics_engine-ef/ode/IceRandom.h new file mode 100644 index 00000000..3170b33d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceRandom.h @@ -0,0 +1,42 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for random generators. + * \file IceRandom.h + * \author Pierre Terdiman + * \date August, 9, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICERANDOM_H__ +#define __ICERANDOM_H__ + + FUNCTION ICECORE_API void SRand(udword seed); + FUNCTION ICECORE_API udword Rand(); + + //! Returns a unit random floating-point value + inline_ float UnitRandomFloat() { return float(Rand()) * ONE_OVER_RAND_MAX; } + + //! Returns a random index so that 0<= index < max_index + ICECORE_API udword GetRandomIndex(udword max_index); + + class ICECORE_API BasicRandom + { + public: + + //! Constructor + inline_ BasicRandom(udword seed=0) : mRnd(seed) {} + //! Destructor + inline_ ~BasicRandom() {} + + inline_ void SetSeed(udword seed) { mRnd = seed; } + inline_ udword GetCurrentValue() const { return mRnd; } + inline_ udword Randomize() { mRnd = mRnd * 2147001325 + 715136305; return mRnd; } + + private: + udword mRnd; + }; + +#endif // __ICERANDOM_H__ + diff --git a/src/external/open_dynamics_engine-ef/ode/IceRay.cpp b/src/external/open_dynamics_engine-ef/ode/IceRay.cpp new file mode 100644 index 00000000..3288fe2b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceRay.cpp @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for rays. + * \file IceRay.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Ray class. + * A ray is a half-line P(t) = mOrig + mDir * t, with 0 <= t <= +infinity + * \class Ray + * \author Pierre Terdiman + * \version 1.0 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* + O = Origin = impact point + i = normalized vector along the x axis + j = normalized vector along the y axis = actually the normal vector in O + D = Direction vector, norm |D| = 1 + N = Projection of D on y axis, norm |N| = normal reaction + T = Projection of D on x axis, norm |T| = tangential reaction + R = Reflexion vector + + ^y + | + | + | + _ _ _| _ _ _ + * * *| + \ | / + \ |N / | + R\ | /D + \ | / | + \ | / + _________\|/______*_______>x + O T + + Let define theta = angle between D and N. Then cos(theta) = |N| / |D| = |N| since D is normalized. + + j|D = |j|*|D|*cos(theta) => |N| = j|D + + Then we simply have: + + D = N + T + + To compute tangential reaction : + + T = D - N + + To compute reflexion vector : + + R = N - T = N - (D-N) = 2*N - D +*/ + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +float Ray::SquareDistance(const Point& point, float* t) const +{ + Point Diff = point - mOrig; + float fT = Diff | mDir; + + if(fT<=0.0f) + { + fT = 0.0f; + } + else + { + fT /= mDir.SquareMagnitude(); + Diff -= fT*mDir; + } + + if(t) *t = fT; + + return Diff.SquareMagnitude(); +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceRay.h b/src/external/open_dynamics_engine-ef/ode/IceRay.h new file mode 100644 index 00000000..02682876 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceRay.h @@ -0,0 +1,98 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for rays. + * \file IceRay.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICERAY_H__ +#define __ICERAY_H__ + + class ICEMATHS_API Ray + { + public: + //! Constructor + inline_ Ray() {} + //! Constructor + inline_ Ray(const Point& orig, const Point& dir) : mOrig(orig), mDir(dir) {} + //! Copy constructor + inline_ Ray(const Ray& ray) : mOrig(ray.mOrig), mDir(ray.mDir) {} + //! Destructor + inline_ ~Ray() {} + + float SquareDistance(const Point& point, float* t=null) const; + inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); } + + Point mOrig; //!< Ray origin + Point mDir; //!< Normalized direction + }; + + inline_ void ComputeReflexionVector(Point& reflected, const Point& incoming_dir, const Point& outward_normal) + { + reflected = incoming_dir - outward_normal * 2.0f * (incoming_dir|outward_normal); + } + + inline_ void ComputeReflexionVector(Point& reflected, const Point& source, const Point& impact, const Point& normal) + { + Point V = impact - source; + reflected = V - normal * 2.0f * (V|normal); + } + + inline_ void DecomposeVector(Point& normal_compo, Point& tangent_compo, const Point& outward_dir, const Point& outward_normal) + { + normal_compo = outward_normal * (outward_dir|outward_normal); + tangent_compo = outward_dir - normal_compo; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Transforms a direction vector from world space to local space + * \param local_dir [out] direction vector in local space + * \param world_dir [in] direction vector in world space + * \param world [in] world transform + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void ComputeLocalDirection(Point& local_dir, const Point& world_dir, const Matrix4x4& world) + { + // Get world direction back in local space +// Matrix3x3 InvWorld = world; +// local_dir = InvWorld * world_dir; + local_dir = Matrix3x3(world) * world_dir; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Transforms a position vector from world space to local space + * \param local_pt [out] position vector in local space + * \param world_pt [in] position vector in world space + * \param world [in] world transform + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void ComputeLocalPoint(Point& local_pt, const Point& world_pt, const Matrix4x4& world) + { + // Get world vertex back in local space + Matrix4x4 InvWorld = world; + InvWorld.Invert(); + local_pt = world_pt * InvWorld; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Transforms a ray from world space to local space + * \param local_ray [out] ray in local space + * \param world_ray [in] ray in world space + * \param world [in] world transform + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void ComputeLocalRay(Ray& local_ray, const Ray& world_ray, const Matrix4x4& world) + { + // Get world ray back in local space + ComputeLocalDirection(local_ray.mDir, world_ray.mDir, world); + ComputeLocalPoint(local_ray.mOrig, world_ray.mOrig, world); + } + +#endif // __ICERAY_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceRevisitedRadix.cpp b/src/external/open_dynamics_engine-ef/ode/IceRevisitedRadix.cpp new file mode 100644 index 00000000..c31ed3f0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceRevisitedRadix.cpp @@ -0,0 +1,528 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains source code from the article "Radix Sort Revisited". + * \file IceRevisitedRadix.cpp + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Revisited Radix Sort. + * This is my new radix routine: + * - it uses indices and doesn't recopy the values anymore, hence wasting less ram + * - it creates all the histograms in one run instead of four + * - it sorts words faster than dwords and bytes faster than words + * - it correctly sorts negative floating-point values by patching the offsets + * - it automatically takes advantage of temporal coherence + * - multiple keys support is a side effect of temporal coherence + * - it may be worth recoding in asm... (mainly to use FCOMI, FCMOV, etc) [it's probably memory-bound anyway] + * + * History: + * - 08.15.98: very first version + * - 04.04.00: recoded for the radix article + * - 12.xx.00: code lifting + * - 09.18.01: faster CHECK_PASS_VALIDITY thanks to Mark D. Shattuck (who provided other tips, not included here) + * - 10.11.01: added local ram support + * - 01.20.02: bugfix! In very particular cases the last pass was skipped in the float code-path, leading to incorrect sorting...... + * - 01.02.02: - "mIndices" renamed => "mRanks". That's a rank sorter after all. + * - ranks are not "reset" anymore, but implicit on first calls + * - 07.05.02: - offsets rewritten with one less indirection. + * - 11.03.02: - "bool" replaced with RadixHint enum + * + * \class RadixSort + * \author Pierre Terdiman + * \version 1.4 + * \date August, 15, 1998 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* +To do: + - add an offset parameter between two input values (avoid some data recopy sometimes) + - unroll ? asm ? + - 11 bits trick & 3 passes as Michael did + - prefetch stuff the day I have a P3 + - make a version with 16-bits indices ? +*/ + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceCore; + +#define INVALIDATE_RANKS mCurrentSize|=0x80000000 +#define VALIDATE_RANKS mCurrentSize&=0x7fffffff +#define CURRENT_SIZE (mCurrentSize&0x7fffffff) +#define INVALID_RANKS (mCurrentSize&0x80000000) + +#define CHECK_RESIZE(n) \ + if(n!=mPreviousSize) \ + { \ + if(n>mCurrentSize) Resize(n); \ + else ResetRanks(); \ + mPreviousSize = n; \ + } + +#define CREATE_HISTOGRAMS(type, buffer) \ + /* Clear counters/histograms */ \ + ZeroMemory(mHistogram, 256*4*sizeof(udword)); \ + \ + /* Prepare to count */ \ + ubyte* p = (ubyte*)input; \ + ubyte* pe = &p[nb*4]; \ + udword* h0= &mHistogram[0]; /* Histogram for first pass (LSB) */ \ + udword* h1= &mHistogram[256]; /* Histogram for second pass */ \ + udword* h2= &mHistogram[512]; /* Histogram for third pass */ \ + udword* h3= &mHistogram[768]; /* Histogram for last pass (MSB) */ \ + \ + bool AlreadySorted = true; /* Optimism... */ \ + \ + if(INVALID_RANKS) \ + { \ + /* Prepare for temporal coherence */ \ + type* Running = (type*)buffer; \ + type PrevVal = *Running; \ + \ + while(p!=pe) \ + { \ + /* Read input buffer in previous sorted order */ \ + type Val = *Running++; \ + /* Check whether already sorted or not */ \ + if(ValCurSize) Resize(nb); + mCurrentSize = nb; + INVALIDATE_RANKS; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main sort routine. + * This one is for integer values. After the call, mRanks contains a list of indices in sorted order, i.e. in the order you may process your data. + * \param input [in] a list of integer values to sort + * \param nb [in] number of values to sort, must be < 2^31 + * \param hint [in] RADIX_SIGNED to handle negative values, RADIX_UNSIGNED if you know your input buffer only contains positive values + * \return Self-Reference + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RadixSort& RadixSort::Sort(const udword* input, udword nb, RadixHint hint) +{ + // Checkings + if(!input || !nb || nb&0x80000000) return *this; + + // Stats + mTotalCalls++; + + // Resize lists if needed + CheckResize(nb); + +#ifdef RADIX_LOCAL_RAM + // Allocate histograms & offsets on the stack + udword mHistogram[256*4]; +// udword mOffset[256]; + udword* mLink[256]; +#endif + + // Create histograms (counters). Counters for all passes are created in one run. + // Pros: read input buffer once instead of four times + // Cons: mHistogram is 4Kb instead of 1Kb + // We must take care of signed/unsigned values for temporal coherence.... I just + // have 2 code paths even if just a single opcode changes. Self-modifying code, someone? + if(hint==RADIX_UNSIGNED) { CREATE_HISTOGRAMS(udword, input); } + else { CREATE_HISTOGRAMS(sdword, input); } + + // Compute #negative values involved if needed + udword NbNegativeValues = 0; + if(hint==RADIX_SIGNED) + { + // An efficient way to compute the number of negatives values we'll have to deal with is simply to sum the 128 + // last values of the last histogram. Last histogram because that's the one for the Most Significant Byte, + // responsible for the sign. 128 last values because the 128 first ones are related to positive numbers. + udword* h3= &mHistogram[768]; + for(udword i=128;i<256;i++) NbNegativeValues += h3[i]; // 768 for last histogram, 128 for negative part + } + + // Radix sort, j is the pass number (0=LSB, 3=MSB) + for(udword j=0;j<4;j++) + { + CHECK_PASS_VALIDITY(j); + + // Sometimes the fourth (negative) pass is skipped because all numbers are negative and the MSB is 0xFF (for example). This is + // not a problem, numbers are correctly sorted anyway. + if(PerformPass) + { + // Should we care about negative values? + if(j!=3 || hint==RADIX_UNSIGNED) + { + // Here we deal with positive values only + + // Create offsets +// mOffset[0] = 0; +// for(udword i=1;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; + mLink[0] = mRanks2; + for(udword i=1;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; + } + else + { + // This is a special case to correctly handle negative integers. They're sorted in the right order but at the wrong place. + + // Create biased offsets, in order for negative numbers to be sorted as well +// mOffset[0] = NbNegativeValues; // First positive number takes place after the negative ones + mLink[0] = &mRanks2[NbNegativeValues]; // First positive number takes place after the negative ones +// for(udword i=1;i<128;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers + for(udword i=1;i<128;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; // 1 to 128 for positive numbers + + // Fixing the wrong place for negative values +// mOffset[128] = 0; + mLink[128] = mRanks2; +// for(i=129;i<256;i++) mOffset[i] = mOffset[i-1] + CurCount[i-1]; + for(udword i=129;i<256;i++) mLink[i] = mLink[i-1] + CurCount[i-1]; + } + + // Perform Radix Sort + ubyte* InputBytes = (ubyte*)input; + InputBytes += j; + if(INVALID_RANKS) + { +// for(udword i=0;i>24; // Radix byte, same as above. AND is useless here (udword). + // ### cmp to be killed. Not good. Later. +// if(Radix<128) mRanks2[mOffset[Radix]++] = i; // Number is positive, same as above +// else mRanks2[--mOffset[Radix]] = i; // Number is negative, flip the sorting order + if(Radix<128) *mLink[Radix]++ = i; // Number is positive, same as above + else *(--mLink[Radix]) = i; // Number is negative, flip the sorting order + } + VALIDATE_RANKS; + } + else + { + for(udword i=0;i>24; // Radix byte, same as above. AND is useless here (udword). + // ### cmp to be killed. Not good. Later. +// if(Radix<128) mRanks2[mOffset[Radix]++] = mRanks[i]; // Number is positive, same as above +// else mRanks2[--mOffset[Radix]] = mRanks[i]; // Number is negative, flip the sorting order + if(Radix<128) *mLink[Radix]++ = mRanks[i]; // Number is positive, same as above + else *(--mLink[Radix]) = mRanks[i]; // Number is negative, flip the sorting order + } + } + // Swap pointers for next pass. Valid indices - the most recent ones - are in mRanks after the swap. + udword* Tmp = mRanks; mRanks = mRanks2; mRanks2 = Tmp; + } + else + { + // The pass is useless, yet we still have to reverse the order of current list if all values are negative. + if(UniqueVal>=128) + { + if(INVALID_RANKS) + { + // ###Possible? + for(udword i=0;i=SqrLen) + { + fT = 1.0f; + Diff -= Dir; + } + else + { + fT /= SqrLen; + Diff -= fT*Dir; + } + } + + if(t) *t = fT; + + return Diff.SquareMagnitude(); +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceSegment.h b/src/external/open_dynamics_engine-ef/ode/IceSegment.h new file mode 100644 index 00000000..8d663226 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceSegment.h @@ -0,0 +1,55 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for segments. + * \file IceSegment.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICESEGMENT_H__ +#define __ICESEGMENT_H__ + + class ICEMATHS_API Segment + { + public: + //! Constructor + inline_ Segment() {} + //! Constructor + inline_ Segment(const Point& p0, const Point& p1) : mP0(p0), mP1(p1) {} + //! Copy constructor + inline_ Segment(const Segment& seg) : mP0(seg.mP0), mP1(seg.mP1) {} + //! Destructor + inline_ ~Segment() {} + + inline_ const Point& GetOrigin() const { return mP0; } + inline_ Point ComputeDirection() const { return mP1 - mP0; } + inline_ void ComputeDirection(Point& dir) const { dir = mP1 - mP0; } + inline_ float ComputeLength() const { return mP1.Distance(mP0); } + inline_ float ComputeSquareLength() const { return mP1.SquareDistance(mP0); } + + inline_ void SetOriginDirection(const Point& origin, const Point& direction) + { + mP0 = mP1 = origin; + mP1 += direction; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Computes a point on the segment + * \param pt [out] point on segment + * \param t [in] point's parameter [t=0 => pt = mP0, t=1 => pt = mP1] + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void ComputePoint(Point& pt, float t) const { pt = mP0 + t * (mP1 - mP0); } + + float SquareDistance(const Point& point, float* t=null) const; + inline_ float Distance(const Point& point, float* t=null) const { return sqrtf(SquareDistance(point, t)); } + + Point mP0; //!< Start of segment + Point mP1; //!< End of segment + }; + +#endif // __ICESEGMENT_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceTriList.h b/src/external/open_dynamics_engine-ef/ode/IceTriList.h new file mode 100644 index 00000000..d505459e --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceTriList.h @@ -0,0 +1,61 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a triangle container. + * \file IceTriList.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICETRILIST_H__ +#define __ICETRILIST_H__ + + class ICEMATHS_API TriList : public Container + { + public: + // Constructor / Destructor + TriList() {} + ~TriList() {} + + inline_ udword GetNbTriangles() const { return GetNbEntries()/9; } + inline_ Triangle* GetTriangles() const { return (Triangle*)GetEntries(); } + + void AddTri(const Triangle& tri) + { + Add(tri.mVerts[0].x).Add(tri.mVerts[0].y).Add(tri.mVerts[0].z); + Add(tri.mVerts[1].x).Add(tri.mVerts[1].y).Add(tri.mVerts[1].z); + Add(tri.mVerts[2].x).Add(tri.mVerts[2].y).Add(tri.mVerts[2].z); + } + + void AddTri(const Point& p0, const Point& p1, const Point& p2) + { + Add(p0.x).Add(p0.y).Add(p0.z); + Add(p1.x).Add(p1.y).Add(p1.z); + Add(p2.x).Add(p2.y).Add(p2.z); + } + }; + + class ICEMATHS_API TriangleList : public Container + { + public: + // Constructor / Destructor + TriangleList() {} + ~TriangleList() {} + + inline_ udword GetNbTriangles() const { return GetNbEntries()/3; } + inline_ IndexedTriangle* GetTriangles() const { return (IndexedTriangle*)GetEntries();} + + void AddTriangle(const IndexedTriangle& tri) + { + Add(tri.mVRef[0]).Add(tri.mVRef[1]).Add(tri.mVRef[2]); + } + + void AddTriangle(udword vref0, udword vref1, udword vref2) + { + Add(vref0).Add(vref1).Add(vref2); + } + }; + +#endif //__ICETRILIST_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceTriangle.cpp b/src/external/open_dynamics_engine-ef/ode/IceTriangle.cpp new file mode 100644 index 00000000..3d8ee96b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceTriangle.cpp @@ -0,0 +1,295 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a handy triangle class. + * \file IceTriangle.cpp + * \author Pierre Terdiman + * \date January, 17, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace IceMaths; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a triangle class. + * + * class Tri + * \author Pierre Terdiman + * \version 1.0 + * \date 08.15.98 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +static sdword VPlaneSideEps(const Point& v, const Plane& plane, float epsilon) +{ + // Compute distance from current vertex to the plane + float Dist = plane.Distance(v); + // Compute side: + // 1 = the vertex is on the positive side of the plane + // -1 = the vertex is on the negative side of the plane + // 0 = the vertex is on the plane (within epsilon) + return Dist > epsilon ? 1 : Dist < -epsilon ? -1 : 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Flips the winding order. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Triangle::Flip() +{ + Point Tmp = mVerts[1]; + mVerts[1] = mVerts[2]; + mVerts[2] = Tmp; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle area. + * \return the area + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Triangle::Area() const +{ + const Point& p0 = mVerts[0]; + const Point& p1 = mVerts[1]; + const Point& p2 = mVerts[2]; + return ((p0 - p1)^(p0 - p2)).Magnitude() * 0.5f; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle perimeter. + * \return the perimeter + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Triangle::Perimeter() const +{ + const Point& p0 = mVerts[0]; + const Point& p1 = mVerts[1]; + const Point& p2 = mVerts[2]; + return p0.Distance(p1) + + p0.Distance(p2) + + p1.Distance(p2); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle compacity. + * \return the compacity + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Triangle::Compacity() const +{ + float P = Perimeter(); + if(P==0.0f) return 0.0f; + return (4.0f*PI*Area()/(P*P)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle normal. + * \param normal [out] the computed normal + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Triangle::Normal(Point& normal) const +{ + const Point& p0 = mVerts[0]; + const Point& p1 = mVerts[1]; + const Point& p2 = mVerts[2]; + normal = ((p0 - p1)^(p0 - p2)).Normalize(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle denormalized normal. + * \param normal [out] the computed normal + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Triangle::DenormalizedNormal(Point& normal) const +{ + const Point& p0 = mVerts[0]; + const Point& p1 = mVerts[1]; + const Point& p2 = mVerts[2]; + normal = ((p0 - p1)^(p0 - p2)); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle center. + * \param center [out] the computed center + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Triangle::Center(Point& center) const +{ + const Point& p0 = mVerts[0]; + const Point& p1 = mVerts[1]; + const Point& p2 = mVerts[2]; + center = (p0 + p1 + p2)*INV3; +} + +PartVal Triangle::TestAgainstPlane(const Plane& plane, float epsilon) const +{ + bool Pos = false, Neg = false; + + // Loop through all vertices + for(udword i=0;i<3;i++) + { + // Compute side: + sdword Side = VPlaneSideEps(mVerts[i], plane, epsilon); + + if (Side < 0) Neg = true; + else if (Side > 0) Pos = true; + } + + if (!Pos && !Neg) return TRI_ON_PLANE; + else if (Pos && Neg) return TRI_INTERSECT; + else if (Pos && !Neg) return TRI_PLUS_SPACE; + else if (!Pos && Neg) return TRI_MINUS_SPACE; + + // What?! + return TRI_FORCEDWORD; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle moment. + * \param m [out] the moment + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* +void Triangle::ComputeMoment(Moment& m) +{ + // Compute the area of the triangle + m.mArea = Area(); + + // Compute the centroid + Center(m.mCentroid); + + // Second-order components. Handle zero-area faces. + Point& p = mVerts[0]; + Point& q = mVerts[1]; + Point& r = mVerts[2]; + if(m.mArea==0.0f) + { + // This triangle has zero area. The second order components would be eliminated with the usual formula, so, for the + // sake of robustness we use an alternative form. These are the centroid and second-order components of the triangle's vertices. + m.mCovariance.m[0][0] = (p.x*p.x + q.x*q.x + r.x*r.x); + m.mCovariance.m[0][1] = (p.x*p.y + q.x*q.y + r.x*r.y); + m.mCovariance.m[0][2] = (p.x*p.z + q.x*q.z + r.x*r.z); + m.mCovariance.m[1][1] = (p.y*p.y + q.y*q.y + r.y*r.y); + m.mCovariance.m[1][2] = (p.y*p.z + q.y*q.z + r.y*r.z); + m.mCovariance.m[2][2] = (p.z*p.z + q.z*q.z + r.z*r.z); + m.mCovariance.m[2][1] = m.mCovariance.m[1][2]; + m.mCovariance.m[1][0] = m.mCovariance.m[0][1]; + m.mCovariance.m[2][0] = m.mCovariance.m[0][2]; + } + else + { + const float OneOverTwelve = 1.0f / 12.0f; + m.mCovariance.m[0][0] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.x + p.x*p.x + q.x*q.x + r.x*r.x) * OneOverTwelve; + m.mCovariance.m[0][1] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.y + p.x*p.y + q.x*q.y + r.x*r.y) * OneOverTwelve; + m.mCovariance.m[1][1] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.y + p.y*p.y + q.y*q.y + r.y*r.y) * OneOverTwelve; + m.mCovariance.m[0][2] = m.mArea * (9.0f * m.mCentroid.x*m.mCentroid.z + p.x*p.z + q.x*q.z + r.x*r.z) * OneOverTwelve; + m.mCovariance.m[1][2] = m.mArea * (9.0f * m.mCentroid.y*m.mCentroid.z + p.y*p.z + q.y*q.z + r.y*r.z) * OneOverTwelve; + m.mCovariance.m[2][2] = m.mArea * (9.0f * m.mCentroid.z*m.mCentroid.z + p.z*p.z + q.z*q.z + r.z*r.z) * OneOverTwelve; + m.mCovariance.m[2][1] = m.mCovariance.m[1][2]; + m.mCovariance.m[1][0] = m.mCovariance.m[0][1]; + m.mCovariance.m[2][0] = m.mCovariance.m[0][2]; + } +} +*/ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle's smallest edge length. + * \return the smallest edge length + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Triangle::MinEdgeLength() const +{ + float Min = MAX_FLOAT; + float Length01 = mVerts[0].Distance(mVerts[1]); + float Length02 = mVerts[0].Distance(mVerts[2]); + float Length12 = mVerts[1].Distance(mVerts[2]); + if(Length01 < Min) Min = Length01; + if(Length02 < Min) Min = Length02; + if(Length12 < Min) Min = Length12; + return Min; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the triangle's largest edge length. + * \return the largest edge length + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float Triangle::MaxEdgeLength() const +{ + float Max = MIN_FLOAT; + float Length01 = mVerts[0].Distance(mVerts[1]); + float Length02 = mVerts[0].Distance(mVerts[2]); + float Length12 = mVerts[1].Distance(mVerts[2]); + if(Length01 > Max) Max = Length01; + if(Length02 > Max) Max = Length02; + if(Length12 > Max) Max = Length12; + return Max; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes a point on the triangle according to the stabbing information. + * \param u [in] point's barycentric coordinates + * \param v [in] point's barycentric coordinates + * \param pt [out] point on triangle + * \param nearvtx [out] index of nearest vertex + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Triangle::ComputePoint(float u, float v, Point& pt, udword* nearvtx) const +{ + // Compute point coordinates + pt = (1.0f - u - v)*mVerts[0] + u*mVerts[1] + v*mVerts[2]; + + // Compute nearest vertex if needed + if(nearvtx) + { + // Compute distance vector + Point d(mVerts[0].SquareDistance(pt), // Distance^2 from vertex 0 to point on the face + mVerts[1].SquareDistance(pt), // Distance^2 from vertex 1 to point on the face + mVerts[2].SquareDistance(pt)); // Distance^2 from vertex 2 to point on the face + + // Get smallest distance + *nearvtx = d.SmallestAxis(); + } +} + +void Triangle::Inflate(float fat_coeff, bool constant_border) +{ + // Compute triangle center + Point TriangleCenter; + Center(TriangleCenter); + + // Don't normalize? + // Normalize => add a constant border, regardless of triangle size + // Don't => add more to big triangles + for(udword i=0;i<3;i++) + { + Point v = mVerts[i] - TriangleCenter; + + if(constant_border) v.Normalize(); + + mVerts[i] += v * fat_coeff; + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/IceTriangle.h b/src/external/open_dynamics_engine-ef/ode/IceTriangle.h new file mode 100644 index 00000000..a984db83 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceTriangle.h @@ -0,0 +1,68 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a handy triangle class. + * \file IceTriangle.h + * \author Pierre Terdiman + * \date January, 17, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICETRIANGLE_H__ +#define __ICETRIANGLE_H__ + + // Forward declarations + class Moment; + + // Partitioning values + enum PartVal + { + TRI_MINUS_SPACE = 0, //!< Triangle is in the negative space + TRI_PLUS_SPACE = 1, //!< Triangle is in the positive space + TRI_INTERSECT = 2, //!< Triangle intersects plane + TRI_ON_PLANE = 3, //!< Triangle and plane are coplanar + + TRI_FORCEDWORD = 0x7fffffff + }; + + // A triangle class. + class ICEMATHS_API Triangle + { + public: + //! Constructor + inline_ Triangle() {} + //! Constructor + inline_ Triangle(const Point& p0, const Point& p1, const Point& p2) { mVerts[0]=p0; mVerts[1]=p1; mVerts[2]=p2; } + //! Copy constructor + inline_ Triangle(const Triangle& triangle) + { + mVerts[0] = triangle.mVerts[0]; + mVerts[1] = triangle.mVerts[1]; + mVerts[2] = triangle.mVerts[2]; + } + //! Destructor + inline_ ~Triangle() {} + //! Vertices + Point mVerts[3]; + + // Methods + void Flip(); + float Area() const; + float Perimeter() const; + float Compacity() const; + void Normal(Point& normal) const; + void DenormalizedNormal(Point& normal) const; + void Center(Point& center) const; + inline_ Plane PlaneEquation() const { return Plane(mVerts[0], mVerts[1], mVerts[2]); } + + PartVal TestAgainstPlane(const Plane& plane, float epsilon) const; +// float Distance(Point& cp, Point& cq, Tri& tri); + void ComputeMoment(Moment& m); + float MinEdgeLength() const; + float MaxEdgeLength() const; + void ComputePoint(float u, float v, Point& pt, udword* nearvtx=null) const; + void Inflate(float fat_coeff, bool constant_border); + }; + +#endif // __ICETRIANGLE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/IceTypes.h b/src/external/open_dynamics_engine-ef/ode/IceTypes.h new file mode 100644 index 00000000..4ff71b51 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/IceTypes.h @@ -0,0 +1,171 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains custom types. + * \file IceTypes.h + * \author Pierre Terdiman + * \date April, 4, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __ICETYPES_H__ +#define __ICETYPES_H__ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Things to help us compile on non-windows platforms + +#if defined(__MACOSX__) || defined(__APPLE__) +#undef bool +#define bool char +#undef true +#define true ((bool)-1) +#undef false +#define false ((bool)0) +#endif // mac stuff + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + #define USE_HANDLE_MANAGER + + // Constants + #define PI 3.1415926535897932384626433832795028841971693993751f //!< PI + #define HALFPI 1.57079632679489661923f //!< 0.5 * PI + #define TWOPI 6.28318530717958647692f //!< 2.0 * PI + #define INVPI 0.31830988618379067154f //!< 1.0 / PI + + #define RADTODEG 57.2957795130823208768f //!< 180.0 / PI, convert radians to degrees + #define DEGTORAD 0.01745329251994329577f //!< PI / 180.0, convert degrees to radians + + #define EXP 2.71828182845904523536f //!< e + #define INVLOG2 3.32192809488736234787f //!< 1.0 / log10(2) + #define LN2 0.693147180559945f //!< ln(2) + #define INVLN2 1.44269504089f //!< 1.0f / ln(2) + + #define INV3 0.33333333333333333333f //!< 1/3 + #define INV6 0.16666666666666666666f //!< 1/6 + #define INV7 0.14285714285714285714f //!< 1/7 + #define INV9 0.11111111111111111111f //!< 1/9 + #define INV255 0.00392156862745098039f //!< 1/255 + + #define SQRT2 1.41421356237f //!< sqrt(2) + #define INVSQRT2 0.707106781188f //!< 1 / sqrt(2) + + #define SQRT3 1.73205080757f //!< sqrt(3) + #define INVSQRT3 0.577350269189f //!< 1 / sqrt(3) + + #define null 0 //!< our own NULL pointer + + // Custom types used in ICE + typedef signed char sbyte; //!< sizeof(sbyte) must be 1 + typedef unsigned char ubyte; //!< sizeof(ubyte) must be 1 + typedef signed short sword; //!< sizeof(sword) must be 2 + typedef unsigned short uword; //!< sizeof(uword) must be 2 + typedef signed int sdword; //!< sizeof(sdword) must be 4 + typedef unsigned int udword; //!< sizeof(udword) must be 4 + typedef signed __int64 sqword; //!< sizeof(sqword) must be 8 + typedef unsigned __int64 uqword; //!< sizeof(uqword) must be 8 + typedef float float32; //!< sizeof(float32) must be 4 + typedef double float64; //!< sizeof(float64) must be 4 + + ICE_COMPILE_TIME_ASSERT(sizeof(bool)==1); // ...otherwise things might fail with VC++ 4.2 ! + ICE_COMPILE_TIME_ASSERT(sizeof(ubyte)==1); + ICE_COMPILE_TIME_ASSERT(sizeof(sbyte)==1); + ICE_COMPILE_TIME_ASSERT(sizeof(sword)==2); + ICE_COMPILE_TIME_ASSERT(sizeof(uword)==2); + ICE_COMPILE_TIME_ASSERT(sizeof(udword)==4); + ICE_COMPILE_TIME_ASSERT(sizeof(sdword)==4); + ICE_COMPILE_TIME_ASSERT(sizeof(uqword)==8); + ICE_COMPILE_TIME_ASSERT(sizeof(sqword)==8); + + //! TO BE DOCUMENTED + #define DECLARE_ICE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name + + typedef udword DynID; //!< Dynamic identifier +#ifdef USE_HANDLE_MANAGER + typedef udword KID; //!< Kernel ID +// DECLARE_ICE_HANDLE(KID); +#else + typedef uword KID; //!< Kernel ID +#endif + typedef udword RTYPE; //!< Relationship-type (!) between owners and references + #define INVALID_ID 0xffffffff //!< Invalid dword ID (counterpart of null pointers) +#ifdef USE_HANDLE_MANAGER + #define INVALID_KID 0xffffffff //!< Invalid Kernel ID +#else + #define INVALID_KID 0xffff //!< Invalid Kernel ID +#endif + #define INVALID_NUMBER 0xDEADBEEF //!< Standard junk value + + // Define BOOL if needed + #ifndef BOOL + typedef int BOOL; //!< Another boolean type. + #endif + + //! Union of a float and a sdword + typedef union { + float f; //!< The float + sdword d; //!< The integer + }scell; + + //! Union of a float and a udword + typedef union { + float f; //!< The float + udword d; //!< The integer + }ucell; + + // Type ranges + #define MAX_SBYTE 0x7f //!< max possible sbyte value + #define MIN_SBYTE 0x80 //!< min possible sbyte value + #define MAX_UBYTE 0xff //!< max possible ubyte value + #define MIN_UBYTE 0x00 //!< min possible ubyte value + #define MAX_SWORD 0x7fff //!< max possible sword value + #define MIN_SWORD 0x8000 //!< min possible sword value + #define MAX_UWORD 0xffff //!< max possible uword value + #define MIN_UWORD 0x0000 //!< min possible uword value + #define MAX_SDWORD 0x7fffffff //!< max possible sdword value + #define MIN_SDWORD 0x80000000 //!< min possible sdword value + #define MAX_UDWORD 0xffffffff //!< max possible udword value + #define MIN_UDWORD 0x00000000 //!< min possible udword value + #define MAX_FLOAT FLT_MAX //!< max possible float value + #define MIN_FLOAT (-FLT_MAX) //!< min possible loat value + #define IEEE_1_0 0x3f800000 //!< integer representation of 1.0 + #define IEEE_255_0 0x437f0000 //!< integer representation of 255.0 + #define IEEE_MAX_FLOAT 0x7f7fffff //!< integer representation of MAX_FLOAT + #define IEEE_MIN_FLOAT 0xff7fffff //!< integer representation of MIN_FLOAT + #define IEEE_UNDERFLOW_LIMIT 0x1a000000 + + #define ONE_OVER_RAND_MAX (1.0f / float(RAND_MAX)) //!< Inverse of the max possible value returned by rand() + + typedef int (__stdcall* PROC)(); //!< A standard procedure call. + typedef bool (*ENUMERATION)(udword value, udword param, udword context); //!< ICE standard enumeration call + typedef void** VTABLE; //!< A V-Table. + + #undef MIN + #undef MAX + #define MIN(a, b) ((a) < (b) ? (a) : (b)) //!< Returns the min value between a and b + #define MAX(a, b) ((a) > (b) ? (a) : (b)) //!< Returns the max value between a and b + #define MAXMAX(a,b,c) ((a) > (b) ? MAX (a,c) : MAX (b,c)) //!< Returns the max value between a, b and c + + template inline_ const T& TMin (const T& a, const T& b) { return b < a ? b : a; } + template inline_ const T& TMax (const T& a, const T& b) { return a < b ? b : a; } + template inline_ void TSetMin (T& a, const T& b) { if(a>b) a = b; } + template inline_ void TSetMax (T& a, const T& b) { if(a> 1) & 0x55555555) | ((n << 1) & 0xaaaaaaaa); + n = ((n >> 2) & 0x33333333) | ((n << 2) & 0xcccccccc); + n = ((n >> 4) & 0x0f0f0f0f) | ((n << 4) & 0xf0f0f0f0); + n = ((n >> 8) & 0x00ff00ff) | ((n << 8) & 0xff00ff00); + n = ((n >> 16) & 0x0000ffff) | ((n << 16) & 0xffff0000); + // Etc for larger intergers (64 bits in Java) + // NOTE: the >> operation must be unsigned! (>>> in java) + } + + //! Count the number of '1' bits in a 32 bit word (from Steve Baker's Cute Code Collection) + inline_ udword CountBits(udword n) + { + // This relies of the fact that the count of n bits can NOT overflow + // an n bit interger. EG: 1 bit count takes a 1 bit interger, 2 bit counts + // 2 bit interger, 3 bit count requires only a 2 bit interger. + // So we add all bit pairs, then each nible, then each byte etc... + n = (n & 0x55555555) + ((n & 0xaaaaaaaa) >> 1); + n = (n & 0x33333333) + ((n & 0xcccccccc) >> 2); + n = (n & 0x0f0f0f0f) + ((n & 0xf0f0f0f0) >> 4); + n = (n & 0x00ff00ff) + ((n & 0xff00ff00) >> 8); + n = (n & 0x0000ffff) + ((n & 0xffff0000) >> 16); + // Etc for larger intergers (64 bits in Java) + // NOTE: the >> operation must be unsigned! (>>> in java) + return n; + } + + //! Even faster? + inline_ udword CountBits2(udword bits) + { + bits = bits - ((bits >> 1) & 0x55555555); + bits = ((bits >> 2) & 0x33333333) + (bits & 0x33333333); + bits = ((bits >> 4) + bits) & 0x0F0F0F0F; + return (bits * 0x01010101) >> 24; + } + + //! Spread out bits. EG 00001111 -> 0101010101 + //! 00001010 -> 0100010000 + //! This is used to interleve to intergers to produce a `Morten Key' + //! used in Space Filling Curves (See DrDobbs Journal, July 1999) + //! Order is important. + inline_ void SpreadBits(udword& n) + { + n = ( n & 0x0000ffff) | (( n & 0xffff0000) << 16); + n = ( n & 0x000000ff) | (( n & 0x0000ff00) << 8); + n = ( n & 0x000f000f) | (( n & 0x00f000f0) << 4); + n = ( n & 0x03030303) | (( n & 0x0c0c0c0c) << 2); + n = ( n & 0x11111111) | (( n & 0x22222222) << 1); + } + + // Next Largest Power of 2 + // Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm + // that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with + // the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next + // largest power of 2. For a 32-bit value: + inline_ udword nlpo2(udword x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return x+1; + } + + //! Test to see if a number is an exact power of two (from Steve Baker's Cute Code Collection) + inline_ bool IsPowerOfTwo(udword n) { return ((n&(n-1))==0); } + + //! Zero the least significant '1' bit in a word. (from Steve Baker's Cute Code Collection) + inline_ void ZeroLeastSetBit(udword& n) { n&=(n-1); } + + //! Set the least significant N bits in a word. (from Steve Baker's Cute Code Collection) + inline_ void SetLeastNBits(udword& x, udword n) { x|=~(~0<> 31; return (x^y)-y; } + + //!< Alternative min function + inline_ sdword min_(sdword a, sdword b) { sdword delta = b-a; return a + (delta&(delta>>31)); } + + // Determine if one of the bytes in a 4 byte word is zero + inline_ BOOL HasNullByte(udword x) { return ((x + 0xfefefeff) & (~x) & 0x80808080); } + + // To find the smallest 1 bit in a word EG: ~~~~~~10---0 => 0----010---0 + inline_ udword LowestOneBit(udword w) { return ((w) & (~(w)+1)); } +// inline_ udword LowestOneBit_(udword w) { return ((w) & (-(w))); } + + // Most Significant 1 Bit + // Given a binary integer value x, the most significant 1 bit (highest numbered element of a bit set) + // can be computed using a SWAR algorithm that recursively "folds" the upper bits into the lower bits. + // This process yields a bit vector with the same most significant 1 as x, but all 1's below it. + // Bitwise AND of the original value with the complement of the "folded" value shifted down by one + // yields the most significant bit. For a 32-bit value: + inline_ udword msb32(udword x) + { + x |= (x >> 1); + x |= (x >> 2); + x |= (x >> 4); + x |= (x >> 8); + x |= (x >> 16); + return (x & ~(x >> 1)); + } + + /* + "Just call it repeatedly with various input values and always with the same variable as "memory". + The sharpness determines the degree of filtering, where 0 completely filters out the input, and 1 + does no filtering at all. + + I seem to recall from college that this is called an IIR (Infinite Impulse Response) filter. As opposed + to the more typical FIR (Finite Impulse Response). + + Also, I'd say that you can make more intelligent and interesting filters than this, for example filters + that remove wrong responses from the mouse because it's being moved too fast. You'd want such a filter + to be applied before this one, of course." + + (JCAB on Flipcode) + */ + inline_ float FeedbackFilter(float val, float& memory, float sharpness) + { + ASSERT(sharpness>=0.0f && sharpness<=1.0f && "Invalid sharpness value in feedback filter"); + if(sharpness<0.0f) sharpness = 0.0f; + else if(sharpness>1.0f) sharpness = 1.0f; + return memory = val * sharpness + memory * (1.0f - sharpness); + } + + //! If you can guarantee that your input domain (i.e. value of x) is slightly + //! limited (abs(x) must be < ((1<<31u)-32767)), then you can use the + //! following code to clamp the resulting value into [-32768,+32767] range: + inline_ int ClampToInt16(int x) + { +// ASSERT(abs(x) < (int)((1<<31u)-32767)); + + int delta = 32767 - x; + x += (delta>>31) & delta; + delta = x + 32768; + x -= (delta>>31) & delta; + return x; + } + + // Generic functions + template inline_ void TSwap(Type& a, Type& b) { const Type c = a; a = b; b = c; } + template inline_ Type TClamp(const Type& x, const Type& lo, const Type& hi) { return ((xhi) ? hi : x); } + + template inline_ void TSort(Type& a, Type& b) + { + if(a>b) TSwap(a, b); + } + + template inline_ void TSort(Type& a, Type& b, Type& c) + { + if(a>b) TSwap(a, b); + if(b>c) TSwap(b, c); + if(a>b) TSwap(a, b); + if(b>c) TSwap(b, c); + } + + // Prevent nasty user-manipulations (strategy borrowed from Charles Bloom) +// #define PREVENT_COPY(curclass) void operator = (const curclass& object) { ASSERT(!"Bad use of operator ="); } + // ... actually this is better ! + #define PREVENT_COPY(cur_class) private: cur_class(const cur_class& object); cur_class& operator=(const cur_class& object); + + //! TO BE DOCUMENTED + #define OFFSET_OF(Class, Member) (size_t)&(((Class*)0)->Member) + //! TO BE DOCUMENTED + #define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Returns the alignment of the input address. + * \fn Alignment(udword address) + * \param address [in] address to check + * \return the best alignment (e.g. 1 for odd addresses, etc) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + FUNCTION ICECORE_API udword Alignment(udword address); + + #define IS_ALIGNED_2(x) ((x&1)==0) + #define IS_ALIGNED_4(x) ((x&3)==0) + #define IS_ALIGNED_8(x) ((x&7)==0) + + // ericf commented out + //inline_ void _prefetch(void const* ptr) { (void)*(char const volatile *)ptr; } + + // Compute implicit coords from an index: + // The idea is to get back 2D coords from a 1D index. + // For example: + // + // 0 1 2 ... nbu-1 + // nbu nbu+1 i ... + // + // We have i, we're looking for the equivalent (u=2, v=1) location. + // i = u + v*nbu + // <=> i/nbu = u/nbu + v + // Since 0 <= u < nbu, u/nbu = 0 (integer) + // Hence: v = i/nbu + // Then we simply put it back in the original equation to compute u = i - v*nbu + inline_ void Compute2DCoords(udword& u, udword& v, udword i, udword nbu) + { + v = i / nbu; + u = i - (v * nbu); + } + + // In 3D: i = u + v*nbu + w*nbu*nbv + // <=> i/(nbu*nbv) = u/(nbu*nbv) + v/nbv + w + // u/(nbu*nbv) is null since u/nbu was null already. + // v/nbv is null as well for the same reason. + // Hence w = i/(nbu*nbv) + // Then we're left with a 2D problem: i' = i - w*nbu*nbv = u + v*nbu + inline_ void Compute3DCoords(udword& u, udword& v, udword& w, udword i, udword nbu, udword nbu_nbv) + { + w = i / (nbu_nbv); + Compute2DCoords(u, v, i - (w * nbu_nbv), nbu); + } + +#endif // __ICEUTILS_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/LICENSE_BSD.TXT b/src/external/open_dynamics_engine-ef/ode/LICENSE_BSD.TXT new file mode 100644 index 00000000..112f6a27 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/LICENSE_BSD.TXT @@ -0,0 +1,34 @@ + +This is the BSD-style license for the Open Dynamics Engine +---------------------------------------------------------- + +Open Dynamics Engine +Copyright (c) 2001-2007, Russell L. Smith. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +Neither the names of ODE's copyright owner nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.cpp new file mode 100644 index 00000000..dd665251 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.cpp @@ -0,0 +1,706 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for an AABB collider. + * \file OPC_AABBCollider.cpp + * \author Pierre Terdiman + * \date January, 1st, 2002 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains an AABB-vs-tree collider. + * + * \class AABBCollider + * \author Pierre Terdiman + * \version 1.3 + * \date January, 1st, 2002 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +#include "ode/OPC_BoxBoxOverlap.h" +#include "ode/OPC_TriBoxOverlap.h" + +#define SET_CONTACT(prim_index, flag) \ + /* Set contact status */ \ + mFlags |= flag; \ + mTouchedPrimitives->Add(prim_index); + +//! AABB-triangle test +#define AABB_PRIM(prim_index, flag) \ + /* Request vertices from the app */ \ + VertexPointers VP; mIMesh->GetTriangle(VP, prim_index);\ + mLeafVerts[0] = *VP.Vertex[0]; \ + mLeafVerts[1] = *VP.Vertex[1]; \ + mLeafVerts[2] = *VP.Vertex[2]; \ + /* Perform triangle-box overlap test */ \ + if(TriBoxOverlap()) \ + { \ + SET_CONTACT(prim_index, flag) \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBCollider::AABBCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBCollider::~AABBCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a box cache + * \param box [in] collision AABB in world space + * \param model [in] Opcode model to collide with + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, Model& model) +{ + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, box)) return true; + + if(!model.HasLeafNodes()) + { + if(model.IsQuantized()) + { + const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a collision query : + * - reset stats & contact status + * - check temporal coherence + * + * \param cache [in/out] a box cache + * \param box [in] AABB in world space + * \return TRUE if we can return immediately + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL AABBCollider::InitQuery(AABBCache& cache, const CollisionAABB& box) +{ + // 1) Call the base method + VolumeCollider::InitQuery(); + + // 2) Keep track of the query box + mBox = box; + + // 3) Setup destination pointer + mTouchedPrimitives = &cache.TouchedPrimitives; + + // 4) Special case: 1-triangle meshes [Opcode 1.3] + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + if(!SkipPrimitiveTests()) + { + // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. + mTouchedPrimitives->Reset(); + + // Perform overlap test between the unique triangle and the box (and set contact status if needed) + AABB_PRIM(udword(0), OPC_CONTACT) + + // Return immediately regardless of status + return TRUE; + } + } + + // 5) Check temporal coherence : + if(TemporalCoherenceEnabled()) + { + // Here we use temporal coherence + // => check results from previous frame before performing the collision query + if(FirstContactEnabled()) + { + // We're only interested in the first contact found => test the unique previously touched face + if(mTouchedPrimitives->GetNbEntries()) + { + // Get index of previously touched face = the first entry in the array + udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); + + // Then reset the array: + // - if the overlap test below is successful, the index we'll get added back anyway + // - if it isn't, then the array should be reset anyway for the normal query + mTouchedPrimitives->Reset(); + + // Perform overlap test between the cached triangle and the box (and set contact status if needed) + AABB_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) + + // Return immediately if possible + if(GetContactStatus()) return TRUE; + } + // else no face has been touched during previous query + // => we'll have to perform a normal query + } + else + { + // We're interested in all contacts =>test the new real box N(ew) against the previous fat box P(revious): + if(IsCacheValid(cache) && mBox.IsInside(cache.FatBox)) + { + // - if N is included in P, return previous list + // => we simply leave the list (mTouchedFaces) unchanged + + // Set contact status if needed + if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; + + // In any case we don't need to do a query + return TRUE; + } + else + { + // - else do the query using a fat N + + // Reset cache since we'll about to perform a real query + mTouchedPrimitives->Reset(); + + // Make a fat box so that coherence will work for subsequent frames + mBox.mExtents *= cache.FatCoeff; + + // Update cache with query data (signature for cached faces) + cache.FatBox = mBox; + } + } + } + else + { + // Here we don't use temporal coherence => do a normal query + mTouchedPrimitives->Reset(); + } + + // 5) Precompute min & max bounds if needed + mMin = box.mCenter - box.mExtents; + mMax = box.mCenter + box.mExtents; + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for vanilla AABB trees. + * \param cache [in/out] a box cache + * \param box [in] collision AABB in world space + * \param tree [in] AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree) +{ + // This is typically called for a scene tree, full of -AABBs-, not full of triangles. + // So we don't really have "primitives" to deal with. Hence it doesn't work with + // "FirstContact" + "TemporalCoherence". + ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); + + // Checkings + if(!tree) return false; + + // Init collision query + if(InitQuery(cache, box)) return true; + + // Perform collision query + _Collide(tree); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the AABB completely contains the box. In which case we can end the query sooner. + * \param bc [in] box center + * \param be [in] box extents + * \return true if the AABB contains the whole box + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL AABBCollider::AABBContainsBox(const Point& bc, const Point& be) +{ + if(mMin.x > bc.x - be.x) return FALSE; + if(mMin.y > bc.y - be.y) return FALSE; + if(mMin.z > bc.z - be.z) return FALSE; + + if(mMax.x < bc.x + be.x) return FALSE; + if(mMax.y < bc.y + be.y) return FALSE; + if(mMax.z < bc.z + be.z) return FALSE; + + return TRUE; +} + +#define TEST_BOX_IN_AABB(center, extents) \ + if(AABBContainsBox(center, extents)) \ + { \ + /* Set contact status */ \ + mFlags |= OPC_CONTACT; \ + _Dump(node); \ + return; \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_Collide(const AABBCollisionNode* node) +{ + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + AABB_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) +{ + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_Collide(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(Extents, Center)) return; + + TEST_BOX_IN_AABB(Center, Extents) + + if(node->IsLeaf()) + { + AABB_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(Extents, Center)) return; + + TEST_BOX_IN_AABB(Center, Extents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_Collide(const AABBNoLeafNode* node) +{ + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) +{ + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_AABB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_Collide(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(Extents, Center)) return; + + TEST_BOX_IN_AABB(Center, Extents) + + if(node->HasPosLeaf()) { AABB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { AABB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform AABB-AABB overlap test + if(!AABBAABBOverlap(Extents, Center)) return; + + TEST_BOX_IN_AABB(Center, Extents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for vanilla AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBCollider::_Collide(const AABBTreeNode* node) +{ + // Perform AABB-AABB overlap test + Point Center, Extents; + node->GetAABB()->GetCenter(Center); + node->GetAABB()->GetExtents(Extents); + if(!AABBAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf() || AABBContainsBox(Center, Extents)) + { + mFlags |= OPC_CONTACT; + mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives()); + } + else + { + _Collide(node->GetPos()); + _Collide(node->GetNeg()); + } +} + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridAABBCollider::HybridAABBCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridAABBCollider::~HybridAABBCollider() +{ +} + +//bool HybridAABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model) +// ericf change +bool HybridAABBCollider::Collide(AABBCache& cache, const CollisionAABB& box, HybridModel& model) +{ + // We don't want primitive tests here! + mFlags |= OPC_NO_PRIMITIVE_TESTS; + + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, box)) return true; + + // Special case for 1-leaf trees + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles + udword Nb = mIMesh->GetNbTriangles(); + + // Loop through all triangles + for(udword i=0;imCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + + // We only have a list of boxes so far + if(GetContactStatus()) + { + // Reset contact status, since it currently only reflects collisions with leaf boxes + Collider::InitQuery(); + + // Change dest container so that we can use built-in overlap tests and get collided primitives + cache.TouchedPrimitives.Reset(); + mTouchedPrimitives = &cache.TouchedPrimitives; + + // Read touched leaf boxes + udword Nb = mTouchedBoxes.GetNbEntries(); + const udword* Touched = mTouchedBoxes.GetEntries(); + + const LeafTriangles* LT = model.GetLeafTriangles(); + const udword* Indices = model.GetIndices(); + + // Loop through touched leaves + while(Nb--) + { + const LeafTriangles& CurrentLeaf = LT[*Touched++]; + + // Each leaf box has a set of triangles + udword NbTris = CurrentLeaf.GetNbTriangles(); + if(Indices) + { + const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = *T++; + AABB_PRIM(TriangleIndex, OPC_CONTACT) + } + } + else + { + udword BaseIndex = CurrentLeaf.GetTriangleIndex(); + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = BaseIndex++; + AABB_PRIM(TriangleIndex, OPC_CONTACT) + } + } + } + } + + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.h new file mode 100644 index 00000000..3911e957 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_AABBCollider.h @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for an AABB collider. + * \file OPC_AABBCollider.h + * \author Pierre Terdiman + * \date January, 1st, 2002 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_AABBCOLLIDER_H__ +#define __OPC_AABBCOLLIDER_H__ + + struct OPCODE_API AABBCache : VolumeCache + { + AABBCache() : FatCoeff(1.1f) + { + FatBox.mCenter.Zero(); + FatBox.mExtents.Zero(); + } + + // Cached faces signature + CollisionAABB FatBox; //!< Box used when performing the query resulting in cached faces + // User settings + float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere + }; + + class OPCODE_API AABBCollider : public VolumeCollider + { + public: + // Constructor / Destructor + AABBCollider(); + virtual ~AABBCollider(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a box cache + * \param box [in] collision AABB in world space + * \param model [in] Opcode model to collide with + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //bool Collide(AABBCache& cache, const CollisionAABB& box, const Model& model); + // ericf change + bool Collide(AABBCache& cache, const CollisionAABB& box, Model& model); + // + bool Collide(AABBCache& cache, const CollisionAABB& box, const AABBTree* tree); + protected: + CollisionAABB mBox; //!< Query box in (center, extents) form + Point mMin; //!< Query box min point + Point mMax; //!< Query box max point + // Leaf description + Point mLeafVerts[3]; //!< Triangle vertices + // Internal methods + void _Collide(const AABBCollisionNode* node); + void _Collide(const AABBNoLeafNode* node); + void _Collide(const AABBQuantizedNode* node); + void _Collide(const AABBQuantizedNoLeafNode* node); + void _Collide(const AABBTreeNode* node); + void _CollideNoPrimitiveTest(const AABBCollisionNode* node); + void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); + // Overlap tests + inline_ BOOL AABBContainsBox(const Point& bc, const Point& be); + inline_ BOOL AABBAABBOverlap(const Point& b, const Point& Pb); + inline_ BOOL TriBoxOverlap(); + // Init methods + BOOL InitQuery(AABBCache& cache, const CollisionAABB& box); + }; + + class OPCODE_API HybridAABBCollider : public AABBCollider + { + public: + // Constructor / Destructor + HybridAABBCollider(); + virtual ~HybridAABBCollider(); + + //bool Collide(AABBCache& cache, const CollisionAABB& box, const HybridModel& model); + // ericf change + bool Collide(AABBCache& cache, const CollisionAABB& box, HybridModel& model); + protected: + Container mTouchedBoxes; + }; + +#endif // __OPC_AABBCOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.cpp new file mode 100644 index 00000000..d8156595 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.cpp @@ -0,0 +1,581 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a versatile AABB tree. + * \file OPC_AABBTree.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a generic AABB tree node. + * + * \class AABBTreeNode + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a generic AABB tree. + * This is a vanilla AABB tree, without any particular optimization. It contains anonymous references to + * user-provided primitives, which can theoretically be anything - triangles, boxes, etc. Each primitive + * is surrounded by an AABB, regardless of the primitive's nature. When the primitive is a triangle, the + * resulting tree can be converted into an optimized tree. If the primitive is a box, the resulting tree + * can be used for culling - VFC or occlusion -, assuming you cull on a mesh-by-mesh basis (modern way). + * + * \class AABBTree + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBTreeNode::AABBTreeNode() : + mPos (null), +#ifndef OPC_NO_NEG_VANILLA_TREE + mNeg (null), +#endif + mNodePrimitives (null), + mNbPrimitives (0) +{ +#ifdef OPC_USE_TREE_COHERENCE + mBitmask = 0; +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBTreeNode::~AABBTreeNode() +{ + // Opcode 1.3: + const AABBTreeNode* Pos = GetPos(); +#ifndef OPC_NO_NEG_VANILLA_TREE + const AABBTreeNode* Neg = GetNeg(); + if(!(mPos&1)) DELETESINGLE(Pos); + if(!(mNeg&1)) DELETESINGLE(Neg); +#else + if(!(mPos&1)) DELETEARRAY(Pos); +#endif + mNodePrimitives = null; // This was just a shortcut to the global list => no release + mNbPrimitives = 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Splits the node along a given axis. + * The list of indices is reorganized according to the split values. + * \param axis [in] splitting axis index + * \param builder [in] the tree builder + * \return the number of primitives assigned to the first child + * \warning this method reorganizes the internal list of primitives + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword AABBTreeNode::Split(udword axis, AABBTreeBuilder* builder) +{ + // Get node split value + float SplitValue = builder->GetSplittingValue(mNodePrimitives, mNbPrimitives, mBV, axis); + + udword NbPos = 0; + // Loop through all node-related primitives. Their indices range from mNodePrimitives[0] to mNodePrimitives[mNbPrimitives-1]. + // Those indices map the global list in the tree builder. + for(udword i=0;iGetSplittingValue(Index, axis); + + // Reorganize the list of indices in this order: positive - negative. + if(PrimitiveValue > SplitValue) + { + // Swap entries + udword Tmp = mNodePrimitives[i]; + mNodePrimitives[i] = mNodePrimitives[NbPos]; + mNodePrimitives[NbPos] = Tmp; + // Count primitives assigned to positive space + NbPos++; + } + } + return NbPos; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Subdivides the node. + * + * N + * / \ + * / \ + * N/2 N/2 + * / \ / \ + * N/4 N/4 N/4 N/4 + * (etc) + * + * A well-balanced tree should have a O(log n) depth. + * A degenerate tree would have a O(n) depth. + * Note a perfectly-balanced tree is not well-suited to collision detection anyway. + * + * \param builder [in] the tree builder + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTreeNode::Subdivide(AABBTreeBuilder* builder) +{ + // Checkings + if(!builder) return false; + + // Stop subdividing if we reach a leaf node. This is always performed here, + // else we could end in trouble if user overrides this. + if(mNbPrimitives==1) return true; + + // Let the user validate the subdivision + if(!builder->ValidateSubdivision(mNodePrimitives, mNbPrimitives, mBV)) return true; + + bool ValidSplit = true; // Optimism... + udword NbPos = 0; + if(builder->mSettings.mRules & SPLIT_LARGEST_AXIS) + { + // Find the largest axis to split along + Point Extents; mBV.GetExtents(Extents); // Box extents + udword Axis = Extents.LargestAxis(); // Index of largest axis + + // Split along the axis + NbPos = Split(Axis, builder); + + // Check split validity + if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false; + } + else if(builder->mSettings.mRules & SPLIT_SPLATTER_POINTS) + { + // Compute the means + Point Means(0.0f, 0.0f, 0.0f); + for(udword i=0;iGetSplittingValue(Index, 0); + Means.y+=builder->GetSplittingValue(Index, 1); + Means.z+=builder->GetSplittingValue(Index, 2); + } + Means/=float(mNbPrimitives); + + // Compute variances + Point Vars(0.0f, 0.0f, 0.0f); + for(udword i=0;iGetSplittingValue(Index, 0); + float Cy = builder->GetSplittingValue(Index, 1); + float Cz = builder->GetSplittingValue(Index, 2); + Vars.x += (Cx - Means.x)*(Cx - Means.x); + Vars.y += (Cy - Means.y)*(Cy - Means.y); + Vars.z += (Cz - Means.z)*(Cz - Means.z); + } + Vars/=float(mNbPrimitives-1); + + // Choose axis with greatest variance + udword Axis = Vars.LargestAxis(); + + // Split along the axis + NbPos = Split(Axis, builder); + + // Check split validity + if(!NbPos || NbPos==mNbPrimitives) ValidSplit = false; + } + else if(builder->mSettings.mRules & SPLIT_BALANCED) + { + // Test 3 axis, take the best + float Results[3]; + NbPos = Split(0, builder); Results[0] = float(NbPos)/float(mNbPrimitives); + NbPos = Split(1, builder); Results[1] = float(NbPos)/float(mNbPrimitives); + NbPos = Split(2, builder); Results[2] = float(NbPos)/float(mNbPrimitives); + Results[0]-=0.5f; Results[0]*=Results[0]; + Results[1]-=0.5f; Results[1]*=Results[1]; + Results[2]-=0.5f; Results[2]*=Results[2]; + udword Min=0; + if(Results[1]mSettings.mRules & SPLIT_BEST_AXIS) + { + // Test largest, then middle, then smallest axis... + + // Sort axis + Point Extents; mBV.GetExtents(Extents); // Box extents + udword SortedAxis[] = { 0, 1, 2 }; + float* Keys = (float*)&Extents.x; + for(udword j=0;j<3;j++) + { + for(udword i=0;i<2;i++) + { + if(Keys[SortedAxis[i]]mSettings.mRules & SPLIT_FIFTY) + { + // Don't even bother splitting (mainly a performance test) + NbPos = mNbPrimitives>>1; + } + else return false; // Unknown splitting rules + + // Check the subdivision has been successful + if(!ValidSplit) + { + // Here, all boxes lie in the same sub-space. Two strategies: + // - if the tree *must* be complete, make an arbitrary 50-50 split + // - else stop subdividing +// if(builder->mSettings.mRules&SPLIT_COMPLETE) + if(builder->mSettings.mLimit==1) + { + builder->IncreaseNbInvalidSplits(); + NbPos = mNbPrimitives>>1; + } + else return true; + } + + // Now create children and assign their pointers. + if(builder->mNodeBase) + { + // We use a pre-allocated linear pool for complete trees [Opcode 1.3] + AABBTreeNode* Pool = (AABBTreeNode*)builder->mNodeBase; + udword Count = builder->GetCount() - 1; // Count begins to 1... + // Set last bit to tell it shouldn't be freed ### pretty ugly, find a better way. Maybe one bit in mNbPrimitives + ASSERT(!(udword(&Pool[Count+0])&1)); + ASSERT(!(udword(&Pool[Count+1])&1)); + mPos = size_t(&Pool[Count+0])|1; +#ifndef OPC_NO_NEG_VANILLA_TREE + mNeg = size_t(&Pool[Count+1])|1; +#endif + } + else + { + // Non-complete trees and/or Opcode 1.2 allocate nodes on-the-fly +#ifndef OPC_NO_NEG_VANILLA_TREE + mPos = (size_t)new AABBTreeNode; CHECKALLOC(mPos); + mNeg = (size_t)new AABBTreeNode; CHECKALLOC(mNeg); +#else + AABBTreeNode* PosNeg = new AABBTreeNode[2]; + CHECKALLOC(PosNeg); + mPos = (size_t)PosNeg; +#endif + } + + // Update stats + builder->IncreaseCount(2); + + // Assign children + AABBTreeNode* Pos = (AABBTreeNode*)GetPos(); + AABBTreeNode* Neg = (AABBTreeNode*)GetNeg(); + Pos->mNodePrimitives = &mNodePrimitives[0]; + Pos->mNbPrimitives = NbPos; + Neg->mNodePrimitives = &mNodePrimitives[NbPos]; + Neg->mNbPrimitives = mNbPrimitives - NbPos; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive hierarchy building in a top-down fashion. + * \param builder [in] the tree builder + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeNode::_BuildHierarchy(AABBTreeBuilder* builder) +{ + // 1) Compute the global box for current node. The box is stored in mBV. + builder->ComputeGlobalBox(mNodePrimitives, mNbPrimitives, mBV); + + // 2) Subdivide current node + Subdivide(builder); + + // 3) Recurse + AABBTreeNode* Pos = (AABBTreeNode*)GetPos(); + AABBTreeNode* Neg = (AABBTreeNode*)GetNeg(); + if(Pos) Pos->_BuildHierarchy(builder); + if(Neg) Neg->_BuildHierarchy(builder); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the tree (top-down). + * \param builder [in] the tree builder + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeNode::_Refit(AABBTreeBuilder* builder) +{ + // 1) Recompute the new global box for current node + builder->ComputeGlobalBox(mNodePrimitives, mNbPrimitives, mBV); + + // 2) Recurse + AABBTreeNode* Pos = (AABBTreeNode*)GetPos(); + AABBTreeNode* Neg = (AABBTreeNode*)GetNeg(); + if(Pos) Pos->_Refit(builder); + if(Neg) Neg->_Refit(builder); +} + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBTree::AABBTree() : mIndices(null), mPool(null),mTotalNbNodes(0) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBTree::~AABBTree() +{ + Release(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Releases the tree. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTree::Release() +{ + DELETEARRAY(mPool); + DELETEARRAY(mIndices); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds a generic AABB tree from a tree builder. + * \param builder [in] the tree builder + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTree::Build(AABBTreeBuilder* builder) +{ + // Checkings + if(!builder || !builder->mNbPrimitives) return false; + + // Release previous tree + Release(); + + // Init stats + builder->SetCount(1); + builder->SetNbInvalidSplits(0); + + // Initialize indices. This list will be modified during build. + mIndices = new udword[builder->mNbPrimitives]; + CHECKALLOC(mIndices); + // Identity permutation + for(udword i=0;imNbPrimitives;i++) mIndices[i] = i; + + // Setup initial node. Here we have a complete permutation of the app's primitives. + mNodePrimitives = mIndices; + mNbPrimitives = builder->mNbPrimitives; + + // Use a linear array for complete trees (since we can predict the final number of nodes) [Opcode 1.3] +// if(builder->mRules&SPLIT_COMPLETE) + if(builder->mSettings.mLimit==1) + { + // Allocate a pool of nodes + mPool = new AABBTreeNode[builder->mNbPrimitives*2 - 1]; + + builder->mNodeBase = mPool; // ### ugly ! + } + + // Build the hierarchy + _BuildHierarchy(builder); + + // Get back total number of nodes + mTotalNbNodes = builder->GetCount(); + + // For complete trees, check the correct number of nodes has been created [Opcode 1.3] + if(mPool) ASSERT(mTotalNbNodes==builder->mNbPrimitives*2 - 1); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the depth of the tree. + * A well-balanced tree should have a log(n) depth. A degenerate tree O(n) depth. + * \return depth of the tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword AABBTree::ComputeDepth() const +{ + return Walk(null, null); // Use the walking code without callback +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Walks the tree, calling the user back for each node. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword AABBTree::Walk(WalkingCallback callback, void* user_data) const +{ + // Call it without callback to compute max depth + udword MaxDepth = 0; + udword CurrentDepth = 0; + + struct Local + { + static void _Walk(const AABBTreeNode* current_node, udword& max_depth, udword& current_depth, WalkingCallback callback, void* user_data) + { + // Checkings + if(!current_node) return; + // Entering a new node => increase depth + current_depth++; + // Keep track of max depth + if(current_depth>max_depth) max_depth = current_depth; + + // Callback + if(callback && !(callback)(current_node, current_depth, user_data)) return; + + // Recurse + if(current_node->GetPos()) { _Walk(current_node->GetPos(), max_depth, current_depth, callback, user_data); current_depth--; } + if(current_node->GetNeg()) { _Walk(current_node->GetNeg(), max_depth, current_depth, callback, user_data); current_depth--; } + } + }; + Local::_Walk(this, MaxDepth, CurrentDepth, callback, user_data); + return MaxDepth; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the tree in a top-down way. + * \param builder [in] the tree builder + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTree::Refit(AABBTreeBuilder* builder) +{ + if(!builder) return false; + _Refit(builder); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the tree in a bottom-up way. + * \param builder [in] the tree builder + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTree::Refit2(AABBTreeBuilder* builder) +{ + // Checkings + if(!builder) return false; + + ASSERT(mPool); + + // Bottom-up update + Point Min,Max; + Point Min_,Max_; + udword Index = mTotalNbNodes; + while(Index--) + { + AABBTreeNode& Current = mPool[Index]; + + if(Current.IsLeaf()) + { + builder->ComputeGlobalBox(Current.GetPrimitives(), Current.GetNbPrimitives(), *(AABB*)Current.GetAABB()); + } + else + { + Current.GetPos()->GetAABB()->GetMin(Min); + Current.GetPos()->GetAABB()->GetMax(Max); + + Current.GetNeg()->GetAABB()->GetMin(Min_); + Current.GetNeg()->GetAABB()->GetMax(Max_); + + Min.Min(Min_); + Max.Max(Max_); + + ((AABB*)Current.GetAABB())->SetMinMax(Min, Max); + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the number of bytes used by the tree. + * \return number of bytes used + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword AABBTree::GetUsedBytes() const +{ + udword TotalSize = mTotalNbNodes*GetNodeSize(); + if(mIndices) TotalSize+=mNbPrimitives*sizeof(udword); + return TotalSize; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the tree is a complete tree or not. + * A complete tree is made of 2*N-1 nodes, where N is the number of primitives in the tree. + * \return true for complete trees + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTree::IsComplete() const +{ + return (GetNbNodes()==GetNbPrimitives()*2-1); +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.h b/src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.h new file mode 100644 index 00000000..ee2533db --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_AABBTree.h @@ -0,0 +1,137 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a versatile AABB tree. + * \file OPC_AABBTree.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_AABBTREE_H__ +#define __OPC_AABBTREE_H__ + +#ifdef OPC_NO_NEG_VANILLA_TREE + //! TO BE DOCUMENTED + #define IMPLEMENT_TREE(base_class, volume) \ + public: \ + /* Constructor / Destructor */ \ + base_class(); \ + ~base_class(); \ + /* Data access */ \ + inline_ const volume* Get##volume() const { return &mBV; } \ + /* Clear the last bit */ \ + inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \ + inline_ const base_class* GetNeg() const { const base_class* P = GetPos(); return P ? P+1 : null;} \ + \ + /* We don't need to test both nodes since we can't have one without the other */ \ + inline_ bool IsLeaf() const { return !GetPos(); } \ + \ + /* Stats */ \ + inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ + protected: \ + /* Tree-independent data */ \ + /* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \ + /* Whatever happens we need the two children and the enclosing volume.*/ \ + volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \ + size_t mPos; /* "Positive" & "Negative" children */ +#else + //! TO BE DOCUMENTED + #define IMPLEMENT_TREE(base_class, volume) \ + public: \ + /* Constructor / Destructor */ \ + base_class(); \ + ~base_class(); \ + /* Data access */ \ + inline_ const volume* Get##volume() const { return &mBV; } \ + /* Clear the last bit */ \ + inline_ const base_class* GetPos() const { return (const base_class*)(mPos&~1); } \ + inline_ const base_class* GetNeg() const { return (const base_class*)(mNeg&~1); } \ + \ +/* inline_ bool IsLeaf() const { return (!GetPos() && !GetNeg()); } */ \ + /* We don't need to test both nodes since we can't have one without the other */ \ + inline_ bool IsLeaf() const { return !GetPos(); } \ + \ + /* Stats */ \ + inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ + protected: \ + /* Tree-independent data */ \ + /* Following data always belong to the BV-tree, regardless of what the tree actually contains.*/ \ + /* Whatever happens we need the two children and the enclosing volume.*/ \ + volume mBV; /* Global bounding-volume enclosing all the node-related primitives */ \ + size_t mPos; /* "Positive" child */ \ + size_t mNeg; /* "Negative" child */ +#endif + + typedef void (*CullingCallback) (udword nb_primitives, udword* node_primitives, BOOL need_clipping, void* user_data); + + class OPCODE_API AABBTreeNode + { + IMPLEMENT_TREE(AABBTreeNode, AABB) + public: + // Data access + inline_ const udword* GetPrimitives() const { return mNodePrimitives; } + inline_ udword GetNbPrimitives() const { return mNbPrimitives; } + + protected: + // Tree-dependent data + udword* mNodePrimitives; //!< Node-related primitives (shortcut to a position in mIndices below) + udword mNbPrimitives; //!< Number of primitives for this node + // Internal methods + udword Split(udword axis, AABBTreeBuilder* builder); + bool Subdivide(AABBTreeBuilder* builder); + void _BuildHierarchy(AABBTreeBuilder* builder); + void _Refit(AABBTreeBuilder* builder); + }; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * User-callback, called for each node by the walking code. + * \param current [in] current node + * \param depth [in] current node's depth + * \param user_data [in] user-defined data + * \return true to recurse through children, else false to bypass them + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + typedef bool (*WalkingCallback) (const AABBTreeNode* current, udword depth, void* user_data); + + class OPCODE_API AABBTree : public AABBTreeNode + { + public: + // Constructor / Destructor + AABBTree(); + ~AABBTree(); + // Build + bool Build(AABBTreeBuilder* builder); + void Release(); + + // Data access + inline_ const udword* GetIndices() const { return mIndices; } //!< Catch the indices + inline_ udword GetNbNodes() const { return mTotalNbNodes; } //!< Catch the number of nodes + + // Infos + bool IsComplete() const; + // Stats + udword ComputeDepth() const; + udword GetUsedBytes() const; + udword Walk(WalkingCallback callback, void* user_data) const; + + bool Refit(AABBTreeBuilder* builder); + bool Refit2(AABBTreeBuilder* builder); + private: + udword* mIndices; //!< Indices in the app list. Indices are reorganized during build (permutation). + AABBTreeNode* mPool; //!< Linear pool of nodes for complete trees. Null otherwise. [Opcode 1.3] + // Stats + udword mTotalNbNodes; //!< Number of nodes in the tree. + }; + +#endif // __OPC_AABBTREE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.cpp new file mode 100644 index 00000000..24b5d16a --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.cpp @@ -0,0 +1,146 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains base model interface. + * \file OPC_BaseModel.cpp + * \author Pierre Terdiman + * \date May, 18, 2003 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * The base class for collision models. + * + * \class BaseModel + * \author Pierre Terdiman + * \version 1.3 + * \date May, 18, 2003 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OPCODECREATE::OPCODECREATE() +{ + mIMesh = null; + mSettings.mRules = SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER; + mSettings.mLimit = 1; // Mandatory for complete trees + mNoLeaf = true; + mQuantized = true; +#ifdef __MESHMERIZER_H__ + mCollisionHull = false; +#endif // __MESHMERIZER_H__ + mKeepOriginal = false; + mCanRemap = false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BaseModel::BaseModel() : mIMesh(null), mModelCode(0), mSource(null), mTree(null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BaseModel::~BaseModel() +{ + ReleaseBase(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Releases everything. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void BaseModel::ReleaseBase() +{ + DELETESINGLE(mSource); + DELETESINGLE(mTree); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Creates an optimized tree according to user-settings, and setups mModelCode. + * \param no_leaf [in] true for "no leaf" tree + * \param quantized [in] true for quantized tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool BaseModel::CreateTree(bool no_leaf, bool quantized) +{ + DELETESINGLE(mTree); + + // Setup model code + if(no_leaf) mModelCode |= OPC_NO_LEAF; + else mModelCode &= ~OPC_NO_LEAF; + + if(quantized) mModelCode |= OPC_QUANTIZED; + else mModelCode &= ~OPC_QUANTIZED; + + // Create the correct class + if(mModelCode & OPC_NO_LEAF) + { + if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedNoLeafTree; + else mTree = new AABBNoLeafTree; + } + else + { + if(mModelCode & OPC_QUANTIZED) mTree = new AABBQuantizedTree; + else mTree = new AABBCollisionTree; + } + CHECKALLOC(mTree); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the collision model. This can be used to handle dynamic meshes. Usage is: + * 1. modify your mesh vertices (keep the topology constant!) + * 2. refit the tree (call this method) + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool BaseModel::Refit() +{ + // Refit the optimized tree + return mTree->Refit(mIMesh); + +// Old code kept for reference : refit the source tree then rebuild ! +// if(!mSource) return false; +// // Ouch... +// mSource->Refit(&mTB); +// // Ouch... +// return mTree->Build(mSource); +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.h b/src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.h new file mode 100644 index 00000000..0057acdf --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_BaseModel.h @@ -0,0 +1,175 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains base model interface. + * \file OPC_BaseModel.h + * \author Pierre Terdiman + * \date May, 18, 2003 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_BASEMODEL_H__ +#define __OPC_BASEMODEL_H__ + + //! Model creation structure + struct OPCODE_API OPCODECREATE + { + //! Constructor + OPCODECREATE(); + + MeshInterface* mIMesh; //!< Mesh interface (access to triangles & vertices) (*) + BuildSettings mSettings; //!< Builder's settings + bool mNoLeaf; //!< true => discard leaf nodes (else use a normal tree) + bool mQuantized; //!< true => quantize the tree (else use a normal tree) +#ifdef __MESHMERIZER_H__ + bool mCollisionHull; //!< true => use convex hull + GJK +#endif // __MESHMERIZER_H__ + bool mKeepOriginal; //!< true => keep a copy of the original tree (debug purpose) + bool mCanRemap; //!< true => allows OPCODE to reorganize client arrays + + // (*) This pointer is saved internally and used by OPCODE until collision structures are released, + // so beware of the object's lifetime. + }; + + enum ModelFlag + { + OPC_QUANTIZED = (1<<0), //!< Compressed/uncompressed tree + OPC_NO_LEAF = (1<<1), //!< Leaf/NoLeaf tree + OPC_SINGLE_NODE = (1<<2) //!< Special case for 1-node models + }; + + class OPCODE_API BaseModel + { + public: + // Constructor/Destructor + BaseModel(); + virtual ~BaseModel(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Builds a collision model. + * \param create [in] model creation structure + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual bool Build(const OPCODECREATE& create) = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the number of bytes used by the tree. + * \return amount of bytes used + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual udword GetUsedBytes() const = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Refits the collision model. This can be used to handle dynamic meshes. Usage is: + * 1. modify your mesh vertices (keep the topology constant!) + * 2. refit the tree (call this method) + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual bool Refit(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the source tree. + * \return generic tree + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const AABBTree* GetSourceTree() const { return mSource; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the tree. + * \return the collision tree + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const AABBOptimizedTree* GetTree() const { return mTree; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the tree. + * \return the collision tree + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ AABBOptimizedTree* GetTree() { return mTree; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the number of nodes in the tree. + * Should be 2*N-1 for normal trees and N-1 for optimized ones. + * \return number of nodes + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbNodes() const { return mTree->GetNbNodes(); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks whether the tree has leaf nodes or not. + * \return true if the tree has leaf nodes (normal tree), else false (optimized tree) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL HasLeafNodes() const { return !(mModelCode & OPC_NO_LEAF); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks whether the tree is quantized or not. + * \return true if the tree is quantized + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL IsQuantized() const { return mModelCode & OPC_QUANTIZED; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks whether the model has a single node or not. This special case must be handled separately. + * \return true if the model has only 1 node + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL HasSingleNode() const { return mModelCode & OPC_SINGLE_NODE; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the model's code. + * \return model's code + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetModelCode() const { return mModelCode; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the mesh interface. + * \return mesh interface + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ MeshInterface* GetMeshInterface() { return mIMesh; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Sets the mesh interface. + * \param imesh [in] mesh interface + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetMeshInterface(MeshInterface* imesh) { mIMesh = imesh; } + + protected: + MeshInterface* mIMesh; //!< User-defined mesh interface + udword mModelCode; //!< Model code = combination of ModelFlag(s) + AABBTree* mSource; //!< Original source tree + AABBOptimizedTree* mTree; //!< Optimized tree owned by the model + // Internal methods + void ReleaseBase(); + bool CreateTree(bool no_leaf, bool quantized); + }; + +#endif //__OPC_BASEMODEL_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_BoxBoxOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_BoxBoxOverlap.h new file mode 100644 index 00000000..757a17dd --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_BoxBoxOverlap.h @@ -0,0 +1,122 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * OBB-OBB overlap test using the separating axis theorem. + * - original code by Gomez / Gamasutra (similar to Gottschalk's one in RAPID) + * - optimized for AABB trees by computing the rotation matrix once (SOLID-fashion) + * - the fabs matrix is precomputed as well and epsilon-tweaked (RAPID-style, we found this almost mandatory) + * - Class III axes can be disabled... (SOLID & Intel fashion) + * - ...or enabled to perform some profiling + * - CPU comparisons used when appropriate + * - lazy evaluation sometimes saves some work in case of early exits (unlike SOLID) + * + * \param ea [in] extents from box A + * \param ca [in] center from box A + * \param eb [in] extents from box B + * \param cb [in] center from box B + * \return true if boxes overlap + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL AABBTreeCollider::BoxBoxOverlap(const Point& ea, const Point& ca, const Point& eb, const Point& cb) +{ + // Stats + mNbBVBVTests++; + + float t,t2; + + // Class I : A's basis vectors + float Tx = (mR1to0.m[0][0]*cb.x + mR1to0.m[1][0]*cb.y + mR1to0.m[2][0]*cb.z) + mT1to0.x - ca.x; + t = ea.x + eb.x*mAR.m[0][0] + eb.y*mAR.m[1][0] + eb.z*mAR.m[2][0]; + if(GREATER(Tx, t)) return FALSE; + + float Ty = (mR1to0.m[0][1]*cb.x + mR1to0.m[1][1]*cb.y + mR1to0.m[2][1]*cb.z) + mT1to0.y - ca.y; + t = ea.y + eb.x*mAR.m[0][1] + eb.y*mAR.m[1][1] + eb.z*mAR.m[2][1]; + if(GREATER(Ty, t)) return FALSE; + + float Tz = (mR1to0.m[0][2]*cb.x + mR1to0.m[1][2]*cb.y + mR1to0.m[2][2]*cb.z) + mT1to0.z - ca.z; + t = ea.z + eb.x*mAR.m[0][2] + eb.y*mAR.m[1][2] + eb.z*mAR.m[2][2]; + if(GREATER(Tz, t)) return FALSE; + + // Class II : B's basis vectors + t = Tx*mR1to0.m[0][0] + Ty*mR1to0.m[0][1] + Tz*mR1to0.m[0][2]; t2 = ea.x*mAR.m[0][0] + ea.y*mAR.m[0][1] + ea.z*mAR.m[0][2] + eb.x; + if(GREATER(t, t2)) return FALSE; + + t = Tx*mR1to0.m[1][0] + Ty*mR1to0.m[1][1] + Tz*mR1to0.m[1][2]; t2 = ea.x*mAR.m[1][0] + ea.y*mAR.m[1][1] + ea.z*mAR.m[1][2] + eb.y; + if(GREATER(t, t2)) return FALSE; + + t = Tx*mR1to0.m[2][0] + Ty*mR1to0.m[2][1] + Tz*mR1to0.m[2][2]; t2 = ea.x*mAR.m[2][0] + ea.y*mAR.m[2][1] + ea.z*mAR.m[2][2] + eb.z; + if(GREATER(t, t2)) return FALSE; + + // Class III : 9 cross products + // Cool trick: always perform the full test for first level, regardless of settings. + // That way pathological cases (such as the pencils scene) are quickly rejected anyway ! + if(mFullBoxBoxTest || mNbBVBVTests==1) + { + t = Tz*mR1to0.m[0][1] - Ty*mR1to0.m[0][2]; t2 = ea.y*mAR.m[0][2] + ea.z*mAR.m[0][1] + eb.y*mAR.m[2][0] + eb.z*mAR.m[1][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B0 + t = Tz*mR1to0.m[1][1] - Ty*mR1to0.m[1][2]; t2 = ea.y*mAR.m[1][2] + ea.z*mAR.m[1][1] + eb.x*mAR.m[2][0] + eb.z*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B1 + t = Tz*mR1to0.m[2][1] - Ty*mR1to0.m[2][2]; t2 = ea.y*mAR.m[2][2] + ea.z*mAR.m[2][1] + eb.x*mAR.m[1][0] + eb.y*mAR.m[0][0]; if(GREATER(t, t2)) return FALSE; // L = A0 x B2 + t = Tx*mR1to0.m[0][2] - Tz*mR1to0.m[0][0]; t2 = ea.x*mAR.m[0][2] + ea.z*mAR.m[0][0] + eb.y*mAR.m[2][1] + eb.z*mAR.m[1][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B0 + t = Tx*mR1to0.m[1][2] - Tz*mR1to0.m[1][0]; t2 = ea.x*mAR.m[1][2] + ea.z*mAR.m[1][0] + eb.x*mAR.m[2][1] + eb.z*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B1 + t = Tx*mR1to0.m[2][2] - Tz*mR1to0.m[2][0]; t2 = ea.x*mAR.m[2][2] + ea.z*mAR.m[2][0] + eb.x*mAR.m[1][1] + eb.y*mAR.m[0][1]; if(GREATER(t, t2)) return FALSE; // L = A1 x B2 + t = Ty*mR1to0.m[0][0] - Tx*mR1to0.m[0][1]; t2 = ea.x*mAR.m[0][1] + ea.y*mAR.m[0][0] + eb.y*mAR.m[2][2] + eb.z*mAR.m[1][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B0 + t = Ty*mR1to0.m[1][0] - Tx*mR1to0.m[1][1]; t2 = ea.x*mAR.m[1][1] + ea.y*mAR.m[1][0] + eb.x*mAR.m[2][2] + eb.z*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B1 + t = Ty*mR1to0.m[2][0] - Tx*mR1to0.m[2][1]; t2 = ea.x*mAR.m[2][1] + ea.y*mAR.m[2][0] + eb.x*mAR.m[1][2] + eb.y*mAR.m[0][2]; if(GREATER(t, t2)) return FALSE; // L = A2 x B2 + } + return TRUE; +} + +//! A dedicated version when one box is constant +inline_ BOOL OBBCollider::BoxBoxOverlap(const Point& extents, const Point& center) +{ + // Stats + mNbVolumeBVTests++; + + float t,t2; + + // Class I : A's basis vectors + float Tx = mTBoxToModel.x - center.x; t = extents.x + mBBx1; if(GREATER(Tx, t)) return FALSE; + float Ty = mTBoxToModel.y - center.y; t = extents.y + mBBy1; if(GREATER(Ty, t)) return FALSE; + float Tz = mTBoxToModel.z - center.z; t = extents.z + mBBz1; if(GREATER(Tz, t)) return FALSE; + + // Class II : B's basis vectors + t = Tx*mRBoxToModel.m[0][0] + Ty*mRBoxToModel.m[0][1] + Tz*mRBoxToModel.m[0][2]; + t2 = extents.x*mAR.m[0][0] + extents.y*mAR.m[0][1] + extents.z*mAR.m[0][2] + mBoxExtents.x; + if(GREATER(t, t2)) return FALSE; + + t = Tx*mRBoxToModel.m[1][0] + Ty*mRBoxToModel.m[1][1] + Tz*mRBoxToModel.m[1][2]; + t2 = extents.x*mAR.m[1][0] + extents.y*mAR.m[1][1] + extents.z*mAR.m[1][2] + mBoxExtents.y; + if(GREATER(t, t2)) return FALSE; + + t = Tx*mRBoxToModel.m[2][0] + Ty*mRBoxToModel.m[2][1] + Tz*mRBoxToModel.m[2][2]; + t2 = extents.x*mAR.m[2][0] + extents.y*mAR.m[2][1] + extents.z*mAR.m[2][2] + mBoxExtents.z; + if(GREATER(t, t2)) return FALSE; + + // Class III : 9 cross products + // Cool trick: always perform the full test for first level, regardless of settings. + // That way pathological cases (such as the pencils scene) are quickly rejected anyway ! + if(mFullBoxBoxTest || mNbVolumeBVTests==1) + { + t = Tz*mRBoxToModel.m[0][1] - Ty*mRBoxToModel.m[0][2]; t2 = extents.y*mAR.m[0][2] + extents.z*mAR.m[0][1] + mBB_1; if(GREATER(t, t2)) return FALSE; // L = A0 x B0 + t = Tz*mRBoxToModel.m[1][1] - Ty*mRBoxToModel.m[1][2]; t2 = extents.y*mAR.m[1][2] + extents.z*mAR.m[1][1] + mBB_2; if(GREATER(t, t2)) return FALSE; // L = A0 x B1 + t = Tz*mRBoxToModel.m[2][1] - Ty*mRBoxToModel.m[2][2]; t2 = extents.y*mAR.m[2][2] + extents.z*mAR.m[2][1] + mBB_3; if(GREATER(t, t2)) return FALSE; // L = A0 x B2 + t = Tx*mRBoxToModel.m[0][2] - Tz*mRBoxToModel.m[0][0]; t2 = extents.x*mAR.m[0][2] + extents.z*mAR.m[0][0] + mBB_4; if(GREATER(t, t2)) return FALSE; // L = A1 x B0 + t = Tx*mRBoxToModel.m[1][2] - Tz*mRBoxToModel.m[1][0]; t2 = extents.x*mAR.m[1][2] + extents.z*mAR.m[1][0] + mBB_5; if(GREATER(t, t2)) return FALSE; // L = A1 x B1 + t = Tx*mRBoxToModel.m[2][2] - Tz*mRBoxToModel.m[2][0]; t2 = extents.x*mAR.m[2][2] + extents.z*mAR.m[2][0] + mBB_6; if(GREATER(t, t2)) return FALSE; // L = A1 x B2 + t = Ty*mRBoxToModel.m[0][0] - Tx*mRBoxToModel.m[0][1]; t2 = extents.x*mAR.m[0][1] + extents.y*mAR.m[0][0] + mBB_7; if(GREATER(t, t2)) return FALSE; // L = A2 x B0 + t = Ty*mRBoxToModel.m[1][0] - Tx*mRBoxToModel.m[1][1]; t2 = extents.x*mAR.m[1][1] + extents.y*mAR.m[1][0] + mBB_8; if(GREATER(t, t2)) return FALSE; // L = A2 x B1 + t = Ty*mRBoxToModel.m[2][0] - Tx*mRBoxToModel.m[2][1]; t2 = extents.x*mAR.m[2][1] + extents.y*mAR.m[2][0] + mBB_9; if(GREATER(t, t2)) return FALSE; // L = A2 x B2 + } + return TRUE; +} + +//! A special version for 2 axis-aligned boxes +inline_ BOOL AABBCollider::AABBAABBOverlap(const Point& extents, const Point& center) +{ + // Stats + mNbVolumeBVTests++; + + float tx = mBox.mCenter.x - center.x; float ex = extents.x + mBox.mExtents.x; if(GREATER(tx, ex)) return FALSE; + float ty = mBox.mCenter.y - center.y; float ey = extents.y + mBox.mExtents.y; if(GREATER(ty, ey)) return FALSE; + float tz = mBox.mCenter.z - center.z; float ez = extents.z + mBox.mExtents.z; if(GREATER(tz, ez)) return FALSE; + + return TRUE; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.cpp new file mode 100644 index 00000000..417e9165 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.cpp @@ -0,0 +1,375 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for box pruning. + * \file IceBoxPruning.cpp + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + You could use a complex sweep-and-prune as implemented in I-Collide. + You could use a complex hashing scheme as implemented in V-Clip or recently in ODE it seems. + You could use a "Recursive Dimensional Clustering" algorithm as implemented in GPG2. + + Or you could use this. + Faster ? I don't know. Probably not. It would be a shame. But who knows ? + Easier ? Definitely. Enjoy the sheer simplicity. +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +*/ + + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + + inline_ void FindRunningIndex(udword& index, float* array, udword* sorted, int last, float max) + { + int First=index; + while(First<=last) + { + index = (First+last)>>1; + + if(max>array[sorted[index]]) First = index+1; + else last = index-1; + } + } +// ### could be log(n) ! +// and maybe use cmp integers + +// InsertionSort has better coherence, RadixSort is better for one-shot queries. +#define PRUNING_SORTER RadixSort +//#define PRUNING_SORTER InsertionSort + +// Static for coherence +static PRUNING_SORTER* gCompletePruningSorter = null; +static PRUNING_SORTER* gBipartitePruningSorter0 = null; +static PRUNING_SORTER* gBipartitePruningSorter1 = null; +inline_ PRUNING_SORTER* GetCompletePruningSorter() +{ + if(!gCompletePruningSorter) gCompletePruningSorter = new PRUNING_SORTER; + return gCompletePruningSorter; +} +inline_ PRUNING_SORTER* GetBipartitePruningSorter0() +{ + if(!gBipartitePruningSorter0) gBipartitePruningSorter0 = new PRUNING_SORTER; + return gBipartitePruningSorter0; +} +inline_ PRUNING_SORTER* GetBipartitePruningSorter1() +{ + if(!gBipartitePruningSorter1) gBipartitePruningSorter1 = new PRUNING_SORTER; + return gBipartitePruningSorter1; +} +void ReleasePruningSorters() +{ + DELETESINGLE(gBipartitePruningSorter1); + DELETESINGLE(gBipartitePruningSorter0); + DELETESINGLE(gCompletePruningSorter); +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. + * \param nb0 [in] number of boxes in the first set + * \param array0 [in] array of boxes for the first set + * \param nb1 [in] number of boxes in the second set + * \param array1 [in] array of boxes for the second set + * \param pairs [out] array of overlapping pairs + * \param axes [in] projection order (0,2,1 is often best) + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Opcode::BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes) +{ + // Checkings + if(!nb0 || !array0 || !nb1 || !array1) return false; + + // Catch axes + udword Axis0 = axes.mAxis0; + udword Axis1 = axes.mAxis1; + udword Axis2 = axes.mAxis2; + + // Allocate some temporary data + float* MinPosList0 = new float[nb0]; + float* MinPosList1 = new float[nb1]; + + // 1) Build main lists using the primary axis + for(udword i=0;iGetMin(Axis0); + for(udword i=0;iGetMin(Axis0); + + // 2) Sort the lists + PRUNING_SORTER* RS0 = GetBipartitePruningSorter0(); + PRUNING_SORTER* RS1 = GetBipartitePruningSorter1(); + const udword* Sorted0 = RS0->Sort(MinPosList0, nb0).GetRanks(); + const udword* Sorted1 = RS1->Sort(MinPosList1, nb1).GetRanks(); + + // 3) Prune the lists + udword Index0, Index1; + + const udword* const LastSorted0 = &Sorted0[nb0]; + const udword* const LastSorted1 = &Sorted1[nb1]; + const udword* RunningAddress0 = Sorted0; + const udword* RunningAddress1 = Sorted1; + + while(RunningAddress1GetMax(Axis0)) + { + if(array0[Index0]->Intersect(*array1[Index1], Axis1)) + { + if(array0[Index0]->Intersect(*array1[Index1], Axis2)) + { + pairs.AddPair(Index0, Index1); + } + } + } + } + + //// + + while(RunningAddress0GetMax(Axis0)) + { + if(array0[Index1]->Intersect(*array1[Index0], Axis1)) + { + if(array0[Index1]->Intersect(*array1[Index0], Axis2)) + { + pairs.AddPair(Index1, Index0); + } + } + + } + } + + DELETEARRAY(MinPosList1); + DELETEARRAY(MinPosList0); + + return true; +} + +#define ORIGINAL_VERSION +//#define JOAKIM + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. + * \param nb [in] number of boxes + * \param array [in] array of boxes + * \param pairs [out] array of overlapping pairs + * \param axes [in] projection order (0,2,1 is often best) + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Opcode::CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes) +{ + // Checkings + if(!nb || !array) return false; + + // Catch axes + udword Axis0 = axes.mAxis0; + udword Axis1 = axes.mAxis1; + udword Axis2 = axes.mAxis2; + +#ifdef ORIGINAL_VERSION + // Allocate some temporary data +// float* PosList = new float[nb]; + float* PosList = new float[nb+1]; + + // 1) Build main list using the primary axis + for(udword i=0;iGetMin(Axis0); +PosList[nb++] = MAX_FLOAT; + + // 2) Sort the list + PRUNING_SORTER* RS = GetCompletePruningSorter(); + const udword* Sorted = RS->Sort(PosList, nb).GetRanks(); + + // 3) Prune the list + const udword* const LastSorted = &Sorted[nb]; + const udword* RunningAddress = Sorted; + udword Index0, Index1; + while(RunningAddressGetMax(Axis0)) + while(PosList[Index1 = *RunningAddress2++]<=array[Index0]->GetMax(Axis0)) + { +// if(Index0!=Index1) +// { + if(array[Index0]->Intersect(*array[Index1], Axis1)) + { + if(array[Index0]->Intersect(*array[Index1], Axis2)) + { + pairs.AddPair(Index0, Index1); + } + } +// } + } + } + } + + DELETEARRAY(PosList); +#endif + +#ifdef JOAKIM + // Allocate some temporary data +// float* PosList = new float[nb]; + float* MinList = new float[nb+1]; + + // 1) Build main list using the primary axis + for(udword i=0;iGetMin(Axis0); + MinList[nb] = MAX_FLOAT; + + // 2) Sort the list + PRUNING_SORTER* RS = GetCompletePruningSorter(); + udword* Sorted = RS->Sort(MinList, nb+1).GetRanks(); + + // 3) Prune the list +// const udword* const LastSorted = &Sorted[nb]; +// const udword* const LastSorted = &Sorted[nb-1]; + const udword* RunningAddress = Sorted; + udword Index0, Index1; + +// while(RunningAddressGetMax(Axis0)) + +// float CurrentMin = array[Index0]->GetMin(Axis0); + float CurrentMax = array[Index0]->GetMax(Axis0); + + while(MinList[Index1 = *RunningAddress2] <= CurrentMax) +// while(PosList[Index1 = *RunningAddress] <= CurrentMax) + { +// if(Index0!=Index1) +// { + if(array[Index0]->Intersect(*array[Index1], Axis1)) + { + if(array[Index0]->Intersect(*array[Index1], Axis2)) + { + pairs.AddPair(Index0, Index1); + } + } +// } + + RunningAddress2++; +// RunningAddress++; + } + } + } + + DELETEARRAY(MinList); +#endif + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Brute-force versions are kept: +// - to check the optimized versions return the correct list of intersections +// - to check the speed of the optimized code against the brute-force one +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Brute-force bipartite box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to a different set. + * \param nb0 [in] number of boxes in the first set + * \param array0 [in] array of boxes for the first set + * \param nb1 [in] number of boxes in the second set + * \param array1 [in] array of boxes for the second set + * \param pairs [out] array of overlapping pairs + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Opcode::BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs) +{ + // Checkings + if(!nb0 || !array0 || !nb1 || !array1) return false; + + // Brute-force nb0*nb1 overlap tests + for(udword i=0;iIntersect(*array1[j])) pairs.AddPair(i, j); + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Complete box pruning. Returns a list of overlapping pairs of boxes, each box of the pair belongs to the same set. + * \param nb [in] number of boxes + * \param array [in] array of boxes + * \param pairs [out] array of overlapping pairs + * \return true if success. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Opcode::BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs) +{ + // Checkings + if(!nb || !array) return false; + + // Brute-force n(n-1)/2 overlap tests + for(udword i=0;iIntersect(*array[j])) pairs.AddPair(i, j); + } + } + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.h b/src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.h new file mode 100644 index 00000000..460c5261 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_BoxPruning.h @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for box pruning. + * \file OPC_BoxPruning.h + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_BOXPRUNING_H__ +#define __OPC_BOXPRUNING_H__ + + // Optimized versions + FUNCTION OPCODE_API bool CompleteBoxPruning(udword nb, const AABB** array, Pairs& pairs, const Axes& axes); + FUNCTION OPCODE_API bool BipartiteBoxPruning(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs, const Axes& axes); + + // Brute-force versions + FUNCTION OPCODE_API bool BruteForceCompleteBoxTest(udword nb, const AABB** array, Pairs& pairs); + FUNCTION OPCODE_API bool BruteForceBipartiteBoxTest(udword nb0, const AABB** array0, udword nb1, const AABB** array1, Pairs& pairs); + +#endif //__OPC_BOXPRUNING_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Collider.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_Collider.cpp new file mode 100644 index 00000000..dd26e0d0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Collider.cpp @@ -0,0 +1,62 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains base collider class. + * \file OPC_Collider.cpp + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains the abstract class for colliders. + * + * \class Collider + * \author Pierre Terdiman + * \version 1.3 + * \date June, 2, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Collider::Collider() : + mFlags (0), + mCurrentModel (null), + mIMesh (null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Collider::~Collider() +{ +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Collider.h b/src/external/open_dynamics_engine-ef/ode/OPC_Collider.h new file mode 100644 index 00000000..678b5820 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Collider.h @@ -0,0 +1,180 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains base collider class. + * \file OPC_Collider.h + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_COLLIDER_H__ +#define __OPC_COLLIDER_H__ + + enum CollisionFlag + { + OPC_FIRST_CONTACT = (1<<0), //!< Report all contacts (false) or only first one (true) + OPC_TEMPORAL_COHERENCE = (1<<1), //!< Use temporal coherence or not + OPC_CONTACT = (1<<2), //!< Final contact status after a collision query + OPC_TEMPORAL_HIT = (1<<3), //!< There has been an early exit due to temporal coherence + OPC_NO_PRIMITIVE_TESTS = (1<<4), //!< Keep or discard primitive-bv tests in leaf nodes (volume-mesh queries) + + OPC_CONTACT_FOUND = OPC_FIRST_CONTACT | OPC_CONTACT, + OPC_TEMPORAL_CONTACT = OPC_TEMPORAL_HIT | OPC_CONTACT, + + OPC_FORCE_DWORD = 0x7fffffff + }; + + class OPCODE_API Collider + { + public: + // Constructor / Destructor + Collider(); + virtual ~Collider(); + + // Collision report + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the last collision status after a collision query. + * \return true if a collision occured + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL GetContactStatus() const { return mFlags & OPC_CONTACT; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the "first contact" mode. + * \return true if "first contact" mode is on + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL FirstContactEnabled() const { return mFlags & OPC_FIRST_CONTACT; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the temporal coherence mode. + * \return true if temporal coherence is on + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL TemporalCoherenceEnabled() const { return mFlags & OPC_TEMPORAL_COHERENCE; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks a first contact has already been found. + * \return true if a first contact has been found and we can stop a query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL ContactFound() const { return (mFlags&OPC_CONTACT_FOUND)==OPC_CONTACT_FOUND; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks there's been an early exit due to temporal coherence; + * \return true if a temporal hit has occured + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL TemporalHit() const { return mFlags & OPC_TEMPORAL_HIT; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks primitive tests are enabled; + * \return true if primitive tests must be skipped + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL SkipPrimitiveTests() const { return mFlags & OPC_NO_PRIMITIVE_TESTS; } + + // Settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Reports all contacts (false) or first contact only (true) + * \param flag [in] true for first contact, false for all contacts + * \see SetTemporalCoherence(bool flag) + * \see ValidateSettings() + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetFirstContact(bool flag) + { + if(flag) mFlags |= OPC_FIRST_CONTACT; + else mFlags &= ~OPC_FIRST_CONTACT; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Enable/disable temporal coherence. + * \param flag [in] true to enable temporal coherence, false to discard it + * \see SetFirstContact(bool flag) + * \see ValidateSettings() + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetTemporalCoherence(bool flag) + { + if(flag) mFlags |= OPC_TEMPORAL_COHERENCE; + else mFlags &= ~OPC_TEMPORAL_COHERENCE; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Enable/disable primitive tests. + * \param flag [in] true to enable primitive tests, false to discard them + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetPrimitiveTests(bool flag) + { + if(!flag) mFlags |= OPC_NO_PRIMITIVE_TESTS; + else mFlags &= ~OPC_NO_PRIMITIVE_TESTS; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider. + * \return null if everything is ok, else a string describing the problem + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual const char* ValidateSettings() = 0; + + protected: + udword mFlags; //!< Bit flags + const BaseModel* mCurrentModel; //!< Current model for collision query (owner of touched faces) + // User mesh interface + //const MeshInterface* mIMesh; //!< User-defined mesh interface + // ericf change + MeshInterface* mIMesh; //!< User-defined mesh interface + + // Internal methods + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups current collision model + * \param model [in] current collision model + * \return TRUE if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //inline_ BOOL Setup(const BaseModel* model) + // ericf change + inline_ BOOL Setup(BaseModel* model) + { + // Keep track of current model + mCurrentModel = model; + if(!mCurrentModel) return FALSE; + + mIMesh = model->GetMeshInterface(); + return mIMesh!=null; + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Initializes a query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual inline_ void InitQuery() { mFlags &= ~OPC_TEMPORAL_CONTACT; } + }; + +#endif // __OPC_COLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Common.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_Common.cpp new file mode 100644 index 00000000..4379eb34 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Common.cpp @@ -0,0 +1,52 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains common classes & defs used in OPCODE. + * \file OPC_Common.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * An AABB dedicated to collision detection. + * We don't use the generic AABB class included in ICE, since it can be a Min/Max or a Center/Extents one (depends + * on compilation flags). Since the Center/Extents model is more efficient in collision detection, it was worth + * using an extra special class. + * + * \class CollisionAABB + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A quantized AABB. + * Center/Extent model, using 16-bits integers. + * + * \class QuantizedAABB + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Common.h b/src/external/open_dynamics_engine-ef/ode/OPC_Common.h new file mode 100644 index 00000000..f1349903 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Common.h @@ -0,0 +1,101 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains common classes & defs used in OPCODE. + * \file OPC_Common.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_COMMON_H__ +#define __OPC_COMMON_H__ + +// [GOTTFRIED]: Just a small change for readability. +#ifdef OPC_CPU_COMPARE + #define GREATER(x, y) AIR(x) > IR(y) +#else + #define GREATER(x, y) fabsf(x) > (y) +#endif + + class OPCODE_API CollisionAABB + { + public: + //! Constructor + inline_ CollisionAABB() {} + //! Constructor + inline_ CollisionAABB(const AABB& b) { b.GetCenter(mCenter); b.GetExtents(mExtents); } + //! Destructor + inline_ ~CollisionAABB() {} + + //! Get min point of the box + inline_ void GetMin(Point& min) const { min = mCenter - mExtents; } + //! Get max point of the box + inline_ void GetMax(Point& max) const { max = mCenter + mExtents; } + + //! Get component of the box's min point along a given axis + inline_ float GetMin(udword axis) const { return mCenter[axis] - mExtents[axis]; } + //! Get component of the box's max point along a given axis + inline_ float GetMax(udword axis) const { return mCenter[axis] + mExtents[axis]; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Setups an AABB from min & max vectors. + * \param min [in] the min point + * \param max [in] the max point + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetMinMax(const Point& min, const Point& max) { mCenter = (max + min)*0.5f; mExtents = (max - min)*0.5f; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks a box is inside another box. + * \param box [in] the other box + * \return true if current box is inside input box + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ BOOL IsInside(const CollisionAABB& box) const + { + if(box.GetMin(0)>GetMin(0)) return FALSE; + if(box.GetMin(1)>GetMin(1)) return FALSE; + if(box.GetMin(2)>GetMin(2)) return FALSE; + if(box.GetMax(0)IsValid()) return false; + + // Look for degenerate faces. + udword NbDegenerate = create.mIMesh->CheckTopology(); + if(NbDegenerate) + Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate); + // We continue nonetheless.... + + Release(); // Make sure previous tree has been discarded + + // 1-1) Setup mesh interface automatically + SetMeshInterface(create.mIMesh); + + bool Status = false; + AABBTree* LeafTree = null; + Internal Data; + + // 2) Build a generic AABB Tree. + mSource = new AABBTree; + CHECKALLOC(mSource); + + // 2-1) Setup a builder. Our primitives here are triangles from input mesh, + // so we use an AABBTreeOfTrianglesBuilder..... + { + AABBTreeOfTrianglesBuilder TB; + TB.mIMesh = create.mIMesh; + TB.mNbPrimitives = create.mIMesh->GetNbTriangles(); + TB.mSettings = create.mSettings; + TB.mSettings.mLimit = 16; // ### Hardcoded, but maybe we could let the user choose 8 / 16 / 32 ... + if(!mSource->Build(&TB)) goto FreeAndExit; + } + + // 2-2) Here's the trick : create *another* AABB tree using the leaves of the first one (which are boxes, this time) + struct Local + { + // A callback to count leaf nodes + static bool CountLeaves(const AABBTreeNode* current, udword depth, void* user_data) + { + if(current->IsLeaf()) + { + Internal* Data = (Internal*)user_data; + Data->mNbLeaves++; + } + return true; + } + + // A callback to setup leaf nodes in our internal structures + static bool SetupLeafData(const AABBTreeNode* current, udword depth, void* user_data) + { + if(current->IsLeaf()) + { + Internal* Data = (Internal*)user_data; + + // Get current leaf's box + Data->mLeaves[Data->mNbLeaves] = *current->GetAABB(); + + // Setup leaf data + udword Index = (size_t(current->GetPrimitives()) - size_t(Data->mBase))/sizeof(size_t); + Data->mTriangles[Data->mNbLeaves].SetData(current->GetNbPrimitives(), Index); + + Data->mNbLeaves++; + } + return true; + } + }; + + // Walk the tree & count number of leaves + Data.mNbLeaves = 0; + mSource->Walk(Local::CountLeaves, &Data); + mNbLeaves = Data.mNbLeaves; // Keep track of it + + // Special case for 1-leaf meshes + if(mNbLeaves==1) + { + mModelCode |= OPC_SINGLE_NODE; + Status = true; + goto FreeAndExit; + } + + // Allocate our structures + Data.mLeaves = new AABB[Data.mNbLeaves]; CHECKALLOC(Data.mLeaves); + mTriangles = new LeafTriangles[Data.mNbLeaves]; CHECKALLOC(mTriangles); + + // Walk the tree again & setup leaf data + Data.mTriangles = mTriangles; + Data.mBase = mSource->GetIndices(); + Data.mNbLeaves = 0; // Reset for incoming walk + mSource->Walk(Local::SetupLeafData, &Data); + + // Handle source indices + { + bool MustKeepIndices = true; + if(create.mCanRemap) + { + // We try to get rid of source indices (saving more ram!) by reorganizing triangle arrays... + // Remap can fail when we use callbacks => keep track of indices in that case (it still + // works, only using more memory) + if(create.mIMesh->RemapClient(mSource->GetNbPrimitives(), mSource->GetIndices())) + { + MustKeepIndices = false; + } + } + + if(MustKeepIndices) + { + // Keep track of source indices (from vanilla tree) + mNbPrimitives = mSource->GetNbPrimitives(); + mIndices = new udword[mNbPrimitives]; + CopyMemory(mIndices, mSource->GetIndices(), mNbPrimitives*sizeof(udword)); + } + } + + // Now, create our optimized tree using previous leaf nodes + LeafTree = new AABBTree; + CHECKALLOC(LeafTree); + { + AABBTreeOfAABBsBuilder TB; // Now using boxes ! + TB.mSettings = create.mSettings; + TB.mSettings.mLimit = 1; // We now want a complete tree so that we can "optimize" it + TB.mNbPrimitives = Data.mNbLeaves; + TB.mAABBArray = Data.mLeaves; + if(!LeafTree->Build(&TB)) goto FreeAndExit; + } + + // 3) Create an optimized tree according to user-settings + if(!CreateTree(create.mNoLeaf, create.mQuantized)) goto FreeAndExit; + + // 3-2) Create optimized tree + if(!mTree->Build(LeafTree)) goto FreeAndExit; + + // Finally ok... + Status = true; + +FreeAndExit: // Allow me this one... + DELETESINGLE(LeafTree); + + // 3-3) Delete generic tree if needed + if(!create.mKeepOriginal) DELETESINGLE(mSource); + + return Status; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets the number of bytes used by the tree. + * \return amount of bytes used + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword HybridModel::GetUsedBytes() const +{ + udword UsedBytes = 0; + if(mTree) UsedBytes += mTree->GetUsedBytes(); + if(mIndices) UsedBytes += mNbPrimitives * sizeof(udword); // mIndices + if(mTriangles) UsedBytes += mNbLeaves * sizeof(LeafTriangles); // mTriangles + return UsedBytes; +} + +inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp) +{ + // Compute triangle's AABB = a leaf box +#ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much + min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); + max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); + + min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); + max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); + + min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); + max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); +#else + min = *vp.Vertex[0]; + max = *vp.Vertex[0]; + min.Min(*vp.Vertex[1]); + max.Max(*vp.Vertex[1]); + min.Min(*vp.Vertex[2]); + max.Max(*vp.Vertex[2]); +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the collision model. This can be used to handle dynamic meshes. Usage is: + * 1. modify your mesh vertices (keep the topology constant!) + * 2. refit the tree (call this method) + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool HybridModel::Refit() +{ + if(!mIMesh) return false; + if(!mTree) return false; + + if(IsQuantized()) return false; + if(HasLeafNodes()) return false; + + const LeafTriangles* LT = GetLeafTriangles(); + const udword* Indices = GetIndices(); + + // Bottom-up update + VertexPointers VP; + Point Min,Max; + Point Min_,Max_; + udword Index = mTree->GetNbNodes(); + AABBNoLeafNode* Nodes = (AABBNoLeafNode*)((AABBNoLeafTree*)mTree)->GetNodes(); + while(Index--) + { + AABBNoLeafNode& Current = Nodes[Index]; + + if(Current.HasPosLeaf()) + { + const LeafTriangles& CurrentLeaf = LT[Current.GetPosPrimitive()]; + + Min.SetPlusInfinity(); + Max.SetMinusInfinity(); + + Point TmpMin, TmpMax; + + // Each leaf box has a set of triangles + udword NbTris = CurrentLeaf.GetNbTriangles(); + if(Indices) + { + const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; + + // Loop through triangles and test each of them + while(NbTris--) + { + mIMesh->GetTriangle(VP, *T++); + ComputeMinMax(TmpMin, TmpMax, VP); + Min.Min(TmpMin); + Max.Max(TmpMax); + } + } + else + { + udword BaseIndex = CurrentLeaf.GetTriangleIndex(); + + // Loop through triangles and test each of them + while(NbTris--) + { + mIMesh->GetTriangle(VP, BaseIndex++); + ComputeMinMax(TmpMin, TmpMax, VP); + Min.Min(TmpMin); + Max.Max(TmpMax); + } + } + } + else + { + const CollisionAABB& CurrentBox = Current.GetPos()->mAABB; + CurrentBox.GetMin(Min); + CurrentBox.GetMax(Max); + } + + if(Current.HasNegLeaf()) + { + const LeafTriangles& CurrentLeaf = LT[Current.GetNegPrimitive()]; + + Min_.SetPlusInfinity(); + Max_.SetMinusInfinity(); + + Point TmpMin, TmpMax; + + // Each leaf box has a set of triangles + udword NbTris = CurrentLeaf.GetNbTriangles(); + if(Indices) + { + const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; + + // Loop through triangles and test each of them + while(NbTris--) + { + mIMesh->GetTriangle(VP, *T++); + ComputeMinMax(TmpMin, TmpMax, VP); + Min_.Min(TmpMin); + Max_.Max(TmpMax); + } + } + else + { + udword BaseIndex = CurrentLeaf.GetTriangleIndex(); + + // Loop through triangles and test each of them + while(NbTris--) + { + mIMesh->GetTriangle(VP, BaseIndex++); + ComputeMinMax(TmpMin, TmpMax, VP); + Min_.Min(TmpMin); + Max_.Max(TmpMax); + } + } + } + else + { + const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB; + CurrentBox.GetMin(Min_); + CurrentBox.GetMax(Max_); + } +#ifdef OPC_USE_FCOMI + Min.x = FCMin2(Min.x, Min_.x); + Max.x = FCMax2(Max.x, Max_.x); + Min.y = FCMin2(Min.y, Min_.y); + Max.y = FCMax2(Max.y, Max_.y); + Min.z = FCMin2(Min.z, Min_.z); + Max.z = FCMax2(Max.z, Max_.z); +#else + Min.Min(Min_); + Max.Max(Max_); +#endif + Current.mAABB.SetMinMax(Min, Max); + } + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_HybridModel.h b/src/external/open_dynamics_engine-ef/ode/OPC_HybridModel.h new file mode 100644 index 00000000..c7eb59d4 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_HybridModel.h @@ -0,0 +1,106 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for hybrid models. + * \file OPC_HybridModel.h + * \author Pierre Terdiman + * \date May, 18, 2003 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_HYBRIDMODEL_H__ +#define __OPC_HYBRIDMODEL_H__ + + //! Leaf descriptor + struct LeafTriangles + { + udword Data; //!< Packed data + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets number of triangles in the leaf. + * \return number of triangles N, with 0 < N <= 16 + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbTriangles() const { return (Data & 15)+1; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets triangle index for this leaf. Indexed model's array of indices retrieved with HybridModel::GetIndices() + * \return triangle index + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetTriangleIndex() const { return Data>>4; } + inline_ void SetData(udword nb, udword index) { ASSERT(nb>0 && nb<=16); nb--; Data = (index<<4)|(nb&15); } + }; + + class OPCODE_API HybridModel : public BaseModel + { + public: + // Constructor/Destructor + HybridModel(); + virtual ~HybridModel(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Builds a collision model. + * \param create [in] model creation structure + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(BaseModel) bool Build(const OPCODECREATE& create); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the number of bytes used by the tree. + * \return amount of bytes used + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(BaseModel) udword GetUsedBytes() const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Refits the collision model. This can be used to handle dynamic meshes. Usage is: + * 1. modify your mesh vertices (keep the topology constant!) + * 2. refit the tree (call this method) + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(BaseModel) bool Refit(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets array of triangles. + * \return array of triangles + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const LeafTriangles* GetLeafTriangles() const { return mTriangles; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets array of indices. + * \return array of indices + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const udword* GetIndices() const { return mIndices; } + + private: + udword mNbLeaves; //!< Number of leaf nodes in the model + LeafTriangles* mTriangles; //!< Array of mNbLeaves leaf descriptors + udword mNbPrimitives; //!< Number of primitives in the model + udword* mIndices; //!< Array of primitive indices + + // Internal methods + void Release(); + }; + +#endif // __OPC_HYBRIDMODEL_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_IceHook.h b/src/external/open_dynamics_engine-ef/ode/OPC_IceHook.h new file mode 100644 index 00000000..01d6e621 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_IceHook.h @@ -0,0 +1,70 @@ + +// Should be included by Opcode.h if needed + + #define ICE_DONT_CHECK_COMPILER_OPTIONS + + // From Windows... + typedef int BOOL; + #ifndef FALSE + #define FALSE 0 + #endif + + #ifndef TRUE + #define TRUE 1 + #endif + + #include + #include + #include + #include + #include + #include + + #ifndef ASSERT + #define ASSERT(exp) {} + #endif + #define ICE_COMPILE_TIME_ASSERT(exp) extern char ICE_Dummy[ (exp) ? 1 : -1 ] + + #define Log printf + #define SetIceError(a,b) false + #define EC_OUTOFMEMORY "Out of memory" + + #include "ode/IcePreprocessor.h" + + #undef ICECORE_API + #define ICECORE_API OPCODE_API + + #include "ode/IceTypes.h" + #include "ode/IceFPU.h" + #include "ode/IceMemoryMacros.h" + + namespace IceCore + { + #include "ode/IceUtils.h" + #include "ode/IceContainer.h" + #include "ode/IcePairs.h" + #include "ode/IceRevisitedRadix.h" + #include "ode/IceRandom.h" + } + using namespace IceCore; + + #define ICEMATHS_API OPCODE_API + namespace IceMaths + { + #include "ode/IceAxes.h" + #include "ode/IcePoint.h" + #include "ode/IceHPoint.h" + #include "ode/IceMatrix3x3.h" + #include "ode/IceMatrix4x4.h" + #include "ode/IcePlane.h" + #include "ode/IceRay.h" + #include "ode/IceIndexedTriangle.h" + #include "ode/IceTriangle.h" + #include "ode/IceTriList.h" + #include "ode/IceAABB.h" + #include "ode/IceOBB.h" + #include "ode/IceBoundingSphere.h" + #include "ode/IceSegment.h" + #include "ode/IceLSS.h" + } + using namespace IceMaths; diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_LSSAABBOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_LSSAABBOverlap.h new file mode 100644 index 00000000..5cc50b58 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_LSSAABBOverlap.h @@ -0,0 +1,523 @@ + +// Following code from Magic-Software (http://www.magic-software.com/) +// A bit modified for Opcode + +inline_ float OPC_PointAABBSqrDist(const Point& point, const Point& center, const Point& extents) +{ + // Compute coordinates of point in box coordinate system + Point Closest = point - center; + + float SqrDistance = 0.0f; + + if(Closest.x < -extents.x) + { + float Delta = Closest.x + extents.x; + SqrDistance += Delta*Delta; + } + else if(Closest.x > extents.x) + { + float Delta = Closest.x - extents.x; + SqrDistance += Delta*Delta; + } + + if(Closest.y < -extents.y) + { + float Delta = Closest.y + extents.y; + SqrDistance += Delta*Delta; + } + else if(Closest.y > extents.y) + { + float Delta = Closest.y - extents.y; + SqrDistance += Delta*Delta; + } + + if(Closest.z < -extents.z) + { + float Delta = Closest.z + extents.z; + SqrDistance += Delta*Delta; + } + else if(Closest.z > extents.z) + { + float Delta = Closest.z - extents.z; + SqrDistance += Delta*Delta; + } + return SqrDistance; +} + +static void Face(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, const Point& rkPmE, float* pfLParam, float& rfSqrDistance) +{ + Point kPpE; + float fLSqr, fInv, fTmp, fParam, fT, fDelta; + + kPpE[i1] = rkPnt[i1] + extents[i1]; + kPpE[i2] = rkPnt[i2] + extents[i2]; + if(rkDir[i0]*kPpE[i1] >= rkDir[i1]*rkPmE[i0]) + { + if(rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0]) + { + // v[i1] >= -e[i1], v[i2] >= -e[i2] (distance = 0) + if(pfLParam) + { + rkPnt[i0] = extents[i0]; + fInv = 1.0f/rkDir[i0]; + rkPnt[i1] -= rkDir[i1]*rkPmE[i0]*fInv; + rkPnt[i2] -= rkDir[i2]*rkPmE[i0]*fInv; + *pfLParam = -rkPmE[i0]*fInv; + } + } + else + { + // v[i1] >= -e[i1], v[i2] < -e[i2] + fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i2]*rkDir[i2]; + fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]); + if(fTmp <= 2.0f*fLSqr*extents[i1]) + { + fT = fTmp/fLSqr; + fLSqr += rkDir[i1]*rkDir[i1]; + fTmp = kPpE[i1] - fT; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = fT - extents[i1]; + rkPnt[i2] = -extents[i2]; + } + } + else + { + fLSqr += rkDir[i1]*rkDir[i1]; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = extents[i1]; + rkPnt[i2] = -extents[i2]; + } + } + } + } + else + { + if ( rkDir[i0]*kPpE[i2] >= rkDir[i2]*rkPmE[i0] ) + { + // v[i1] < -e[i1], v[i2] >= -e[i2] + fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]; + fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]); + if(fTmp <= 2.0f*fLSqr*extents[i2]) + { + fT = fTmp/fLSqr; + fLSqr += rkDir[i2]*rkDir[i2]; + fTmp = kPpE[i2] - fT; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = -extents[i1]; + rkPnt[i2] = fT - extents[i2]; + } + } + else + { + fLSqr += rkDir[i2]*rkDir[i2]; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = -extents[i1]; + rkPnt[i2] = extents[i2]; + } + } + } + else + { + // v[i1] < -e[i1], v[i2] < -e[i2] + fLSqr = rkDir[i0]*rkDir[i0]+rkDir[i2]*rkDir[i2]; + fTmp = fLSqr*kPpE[i1] - rkDir[i1]*(rkDir[i0]*rkPmE[i0] + rkDir[i2]*kPpE[i2]); + if(fTmp >= 0.0f) + { + // v[i1]-edge is closest + if ( fTmp <= 2.0f*fLSqr*extents[i1] ) + { + fT = fTmp/fLSqr; + fLSqr += rkDir[i1]*rkDir[i1]; + fTmp = kPpE[i1] - fT; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*fTmp + rkDir[i2]*kPpE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + fTmp*fTmp + kPpE[i2]*kPpE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = fT - extents[i1]; + rkPnt[i2] = -extents[i2]; + } + } + else + { + fLSqr += rkDir[i1]*rkDir[i1]; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*rkPmE[i1] + rkDir[i2]*kPpE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + rkPmE[i1]*rkPmE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = extents[i1]; + rkPnt[i2] = -extents[i2]; + } + } + return; + } + + fLSqr = rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]; + fTmp = fLSqr*kPpE[i2] - rkDir[i2]*(rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1]); + if(fTmp >= 0.0f) + { + // v[i2]-edge is closest + if(fTmp <= 2.0f*fLSqr*extents[i2]) + { + fT = fTmp/fLSqr; + fLSqr += rkDir[i2]*rkDir[i2]; + fTmp = kPpE[i2] - fT; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*fTmp; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + fTmp*fTmp + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = -extents[i1]; + rkPnt[i2] = fT - extents[i2]; + } + } + else + { + fLSqr += rkDir[i2]*rkDir[i2]; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*rkPmE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + rkPmE[i2]*rkPmE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = -extents[i1]; + rkPnt[i2] = extents[i2]; + } + } + return; + } + + // (v[i1],v[i2])-corner is closest + fLSqr += rkDir[i2]*rkDir[i2]; + fDelta = rkDir[i0]*rkPmE[i0] + rkDir[i1]*kPpE[i1] + rkDir[i2]*kPpE[i2]; + fParam = -fDelta/fLSqr; + rfSqrDistance += rkPmE[i0]*rkPmE[i0] + kPpE[i1]*kPpE[i1] + kPpE[i2]*kPpE[i2] + fDelta*fParam; + + if(pfLParam) + { + *pfLParam = fParam; + rkPnt[i0] = extents[i0]; + rkPnt[i1] = -extents[i1]; + rkPnt[i2] = -extents[i2]; + } + } + } +} + +static void CaseNoZeros(Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance) +{ + Point kPmE(rkPnt.x - extents.x, rkPnt.y - extents.y, rkPnt.z - extents.z); + + float fProdDxPy, fProdDyPx, fProdDzPx, fProdDxPz, fProdDzPy, fProdDyPz; + + fProdDxPy = rkDir.x*kPmE.y; + fProdDyPx = rkDir.y*kPmE.x; + if(fProdDyPx >= fProdDxPy) + { + fProdDzPx = rkDir.z*kPmE.x; + fProdDxPz = rkDir.x*kPmE.z; + if(fProdDzPx >= fProdDxPz) + { + // line intersects x = e0 + Face(0, 1, 2, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); + } + else + { + // line intersects z = e2 + Face(2, 0, 1, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); + } + } + else + { + fProdDzPy = rkDir.z*kPmE.y; + fProdDyPz = rkDir.y*kPmE.z; + if(fProdDzPy >= fProdDyPz) + { + // line intersects y = e1 + Face(1, 2, 0, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); + } + else + { + // line intersects z = e2 + Face(2, 0, 1, rkPnt, rkDir, extents, kPmE, pfLParam, rfSqrDistance); + } + } +} + +static void Case0(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance) +{ + float fPmE0 = rkPnt[i0] - extents[i0]; + float fPmE1 = rkPnt[i1] - extents[i1]; + float fProd0 = rkDir[i1]*fPmE0; + float fProd1 = rkDir[i0]*fPmE1; + float fDelta, fInvLSqr, fInv; + + if(fProd0 >= fProd1) + { + // line intersects P[i0] = e[i0] + rkPnt[i0] = extents[i0]; + + float fPpE1 = rkPnt[i1] + extents[i1]; + fDelta = fProd0 - rkDir[i0]*fPpE1; + if(fDelta >= 0.0f) + { + fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]); + rfSqrDistance += fDelta*fDelta*fInvLSqr; + if(pfLParam) + { + rkPnt[i1] = -extents[i1]; + *pfLParam = -(rkDir[i0]*fPmE0+rkDir[i1]*fPpE1)*fInvLSqr; + } + } + else + { + if(pfLParam) + { + fInv = 1.0f/rkDir[i0]; + rkPnt[i1] -= fProd0*fInv; + *pfLParam = -fPmE0*fInv; + } + } + } + else + { + // line intersects P[i1] = e[i1] + rkPnt[i1] = extents[i1]; + + float fPpE0 = rkPnt[i0] + extents[i0]; + fDelta = fProd1 - rkDir[i1]*fPpE0; + if(fDelta >= 0.0f) + { + fInvLSqr = 1.0f/(rkDir[i0]*rkDir[i0] + rkDir[i1]*rkDir[i1]); + rfSqrDistance += fDelta*fDelta*fInvLSqr; + if(pfLParam) + { + rkPnt[i0] = -extents[i0]; + *pfLParam = -(rkDir[i0]*fPpE0+rkDir[i1]*fPmE1)*fInvLSqr; + } + } + else + { + if(pfLParam) + { + fInv = 1.0f/rkDir[i1]; + rkPnt[i0] -= fProd1*fInv; + *pfLParam = -fPmE1*fInv; + } + } + } + + if(rkPnt[i2] < -extents[i2]) + { + fDelta = rkPnt[i2] + extents[i2]; + rfSqrDistance += fDelta*fDelta; + rkPnt[i2] = -extents[i2]; + } + else if ( rkPnt[i2] > extents[i2] ) + { + fDelta = rkPnt[i2] - extents[i2]; + rfSqrDistance += fDelta*fDelta; + rkPnt[i2] = extents[i2]; + } +} + +static void Case00(int i0, int i1, int i2, Point& rkPnt, const Point& rkDir, const Point& extents, float* pfLParam, float& rfSqrDistance) +{ + float fDelta; + + if(pfLParam) + *pfLParam = (extents[i0] - rkPnt[i0])/rkDir[i0]; + + rkPnt[i0] = extents[i0]; + + if(rkPnt[i1] < -extents[i1]) + { + fDelta = rkPnt[i1] + extents[i1]; + rfSqrDistance += fDelta*fDelta; + rkPnt[i1] = -extents[i1]; + } + else if(rkPnt[i1] > extents[i1]) + { + fDelta = rkPnt[i1] - extents[i1]; + rfSqrDistance += fDelta*fDelta; + rkPnt[i1] = extents[i1]; + } + + if(rkPnt[i2] < -extents[i2]) + { + fDelta = rkPnt[i2] + extents[i2]; + rfSqrDistance += fDelta*fDelta; + rkPnt[i1] = -extents[i2]; + } + else if(rkPnt[i2] > extents[i2]) + { + fDelta = rkPnt[i2] - extents[i2]; + rfSqrDistance += fDelta*fDelta; + rkPnt[i2] = extents[i2]; + } +} + +static void Case000(Point& rkPnt, const Point& extents, float& rfSqrDistance) +{ + float fDelta; + + if(rkPnt.x < -extents.x) + { + fDelta = rkPnt.x + extents.x; + rfSqrDistance += fDelta*fDelta; + rkPnt.x = -extents.x; + } + else if(rkPnt.x > extents.x) + { + fDelta = rkPnt.x - extents.x; + rfSqrDistance += fDelta*fDelta; + rkPnt.x = extents.x; + } + + if(rkPnt.y < -extents.y) + { + fDelta = rkPnt.y + extents.y; + rfSqrDistance += fDelta*fDelta; + rkPnt.y = -extents.y; + } + else if(rkPnt.y > extents.y) + { + fDelta = rkPnt.y - extents.y; + rfSqrDistance += fDelta*fDelta; + rkPnt.y = extents.y; + } + + if(rkPnt.z < -extents.z) + { + fDelta = rkPnt.z + extents.z; + rfSqrDistance += fDelta*fDelta; + rkPnt.z = -extents.z; + } + else if(rkPnt.z > extents.z) + { + fDelta = rkPnt.z - extents.z; + rfSqrDistance += fDelta*fDelta; + rkPnt.z = extents.z; + } +} + +static float SqrDistance(const Ray& rkLine, const Point& center, const Point& extents, float* pfLParam) +{ + // compute coordinates of line in box coordinate system + Point kDiff = rkLine.mOrig - center; + Point kPnt = kDiff; + Point kDir = rkLine.mDir; + + // Apply reflections so that direction vector has nonnegative components. + bool bReflect[3]; + for(int i=0;i<3;i++) + { + if(kDir[i]<0.0f) + { + kPnt[i] = -kPnt[i]; + kDir[i] = -kDir[i]; + bReflect[i] = true; + } + else + { + bReflect[i] = false; + } + } + + float fSqrDistance = 0.0f; + + if(kDir.x>0.0f) + { + if(kDir.y>0.0f) + { + if(kDir.z>0.0f) CaseNoZeros(kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,+,+) + else Case0(0, 1, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,+,0) + } + else + { + if(kDir.z>0.0f) Case0(0, 2, 1, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,0,+) + else Case00(0, 1, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (+,0,0) + } + } + else + { + if(kDir.y>0.0f) + { + if(kDir.z>0.0f) Case0(1, 2, 0, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,+,+) + else Case00(1, 0, 2, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,+,0) + } + else + { + if(kDir.z>0.0f) Case00(2, 0, 1, kPnt, kDir, extents, pfLParam, fSqrDistance); // (0,0,+) + else + { + Case000(kPnt, extents, fSqrDistance); // (0,0,0) + if(pfLParam) *pfLParam = 0.0f; + } + } + } + return fSqrDistance; +} + +inline_ float OPC_SegmentOBBSqrDist(const Segment& segment, const Point& c0, const Point& e0) +{ + float fLP; + float fSqrDistance = SqrDistance(Ray(segment.GetOrigin(), segment.ComputeDirection()), c0, e0, &fLP); + if(fLP>=0.0f) + { + if(fLP<=1.0f) return fSqrDistance; + else return OPC_PointAABBSqrDist(segment.mP1, c0, e0); + } + else return OPC_PointAABBSqrDist(segment.mP0, c0, e0); +} + +inline_ BOOL LSSCollider::LSSAABBOverlap(const Point& center, const Point& extents) +{ + // Stats + mNbVolumeBVTests++; + + float s2 = OPC_SegmentOBBSqrDist(mSeg, center, extents); + if(s2Add(prim_index); + +//! LSS-triangle overlap test +#define LSS_PRIM(prim_index, flag) \ + /* Request vertices from the app */ \ + VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \ + \ + /* Perform LSS-tri overlap test */ \ + if(LSSTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ + { \ + SET_CONTACT(prim_index, flag) \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +LSSCollider::LSSCollider() +{ +// mCenter.Zero(); +// mRadius2 = 0.0f; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +LSSCollider::~LSSCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] an lss cache + * \param lss [in] collision lss in local space + * \param model [in] Opcode model to collide with + * \param worldl [in] lss world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl, const Matrix4x4* worldm) +// ericf change +bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, Model& model, const Matrix4x4* worldl, const Matrix4x4* worldm) +{ + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, lss, worldl, worldm)) return true; + + if(!model.HasLeafNodes()) + { + if(model.IsQuantized()) + { + const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a collision query : + * - reset stats & contact status + * - setup matrices + * - check temporal coherence + * + * \param cache [in/out] an lss cache + * \param lss [in] lss in local space + * \param worldl [in] lss world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return TRUE if we can return immediately + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL LSSCollider::InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl, const Matrix4x4* worldm) +{ + // 1) Call the base method + VolumeCollider::InitQuery(); + + // 2) Compute LSS in model space: + // - Precompute R^2 + mRadius2 = lss.mRadius * lss.mRadius; + // - Compute segment + mSeg.mP0 = lss.mP0; + mSeg.mP1 = lss.mP1; + // -> to world space + if(worldl) + { + mSeg.mP0 *= *worldl; + mSeg.mP1 *= *worldl; + } + // -> to model space + if(worldm) + { + // Invert model matrix + Matrix4x4 InvWorldM; + InvertPRMatrix(InvWorldM, *worldm); + + mSeg.mP0 *= InvWorldM; + mSeg.mP1 *= InvWorldM; + } + + // 3) Setup destination pointer + mTouchedPrimitives = &cache.TouchedPrimitives; + + // 4) Special case: 1-triangle meshes [Opcode 1.3] + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + if(!SkipPrimitiveTests()) + { + // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. + mTouchedPrimitives->Reset(); + + // Perform overlap test between the unique triangle and the LSS (and set contact status if needed) + LSS_PRIM(udword(0), OPC_CONTACT) + + // Return immediately regardless of status + return TRUE; + } + } + + // 5) Check temporal coherence : + if(TemporalCoherenceEnabled()) + { + // Here we use temporal coherence + // => check results from previous frame before performing the collision query + if(FirstContactEnabled()) + { + // We're only interested in the first contact found => test the unique previously touched face + if(mTouchedPrimitives->GetNbEntries()) + { + // Get index of previously touched face = the first entry in the array + udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); + + // Then reset the array: + // - if the overlap test below is successful, the index we'll get added back anyway + // - if it isn't, then the array should be reset anyway for the normal query + mTouchedPrimitives->Reset(); + + // Perform overlap test between the cached triangle and the LSS (and set contact status if needed) + LSS_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) + + // Return immediately if possible + if(GetContactStatus()) return TRUE; + } + // else no face has been touched during previous query + // => we'll have to perform a normal query + } + else + { + // We're interested in all contacts =>test the new real LSS N(ew) against the previous fat LSS P(revious): + + // ### rewrite this + + LSS Test(mSeg, lss.mRadius); // in model space + LSS Previous(cache.Previous, sqrtf(cache.Previous.mRadius)); + +// if(cache.Previous.Contains(Test)) + if(IsCacheValid(cache) && Previous.Contains(Test)) + { + // - if N is included in P, return previous list + // => we simply leave the list (mTouchedFaces) unchanged + + // Set contact status if needed + if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; + + // In any case we don't need to do a query + return TRUE; + } + else + { + // - else do the query using a fat N + + // Reset cache since we'll about to perform a real query + mTouchedPrimitives->Reset(); + + // Make a fat sphere so that coherence will work for subsequent frames + mRadius2 *= cache.FatCoeff; +// mRadius2 = (lss.mRadius * cache.FatCoeff)*(lss.mRadius * cache.FatCoeff); + + + // Update cache with query data (signature for cached faces) + cache.Previous.mP0 = mSeg.mP0; + cache.Previous.mP1 = mSeg.mP1; + cache.Previous.mRadius = mRadius2; + } + } + } + else + { + // Here we don't use temporal coherence => do a normal query + mTouchedPrimitives->Reset(); + } + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for vanilla AABB trees. + * \param cache [in/out] an lss cache + * \param lss [in] collision lss in world space + * \param tree [in] AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool LSSCollider::Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree) +{ + // This is typically called for a scene tree, full of -AABBs-, not full of triangles. + // So we don't really have "primitives" to deal with. Hence it doesn't work with + // "FirstContact" + "TemporalCoherence". + ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); + + // Checkings + if(!tree) return false; + + // Init collision query + if(InitQuery(cache, lss)) return true; + + // Perform collision query + _Collide(tree); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the LSS completely contains the box. In which case we can end the query sooner. + * \param bc [in] box center + * \param be [in] box extents + * \return true if the LSS contains the whole box + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL LSSCollider::LSSContainsBox(const Point& bc, const Point& be) +{ + // Not implemented + return FALSE; +} + +#define TEST_BOX_IN_LSS(center, extents) \ + if(LSSContainsBox(center, extents)) \ + { \ + /* Set contact status */ \ + mFlags |= OPC_CONTACT; \ + _Dump(node); \ + return; \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_Collide(const AABBCollisionNode* node) +{ + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + LSS_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) +{ + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_Collide(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_LSS(Center, Extents) + + if(node->IsLeaf()) + { + LSS_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_LSS(Center, Extents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_Collide(const AABBNoLeafNode* node) +{ + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) +{ + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_LSS(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_Collide(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_LSS(Center, Extents) + + if(node->HasPosLeaf()) { LSS_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { LSS_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform LSS-AABB overlap test + if(!LSSAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_LSS(Center, Extents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for vanilla AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void LSSCollider::_Collide(const AABBTreeNode* node) +{ + // Perform LSS-AABB overlap test + Point Center, Extents; + node->GetAABB()->GetCenter(Center); + node->GetAABB()->GetExtents(Extents); + if(!LSSAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf() || LSSContainsBox(Center, Extents)) + { + mFlags |= OPC_CONTACT; + mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives()); + } + else + { + _Collide(node->GetPos()); + _Collide(node->GetNeg()); + } +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridLSSCollider::HybridLSSCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridLSSCollider::~HybridLSSCollider() +{ +} + +//bool HybridLSSCollider::Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl, const Matrix4x4* worldm) +// ericf change +bool HybridLSSCollider::Collide(LSSCache& cache, const LSS& lss, HybridModel& model, const Matrix4x4* worldl, const Matrix4x4* worldm) +{ + // We don't want primitive tests here! + mFlags |= OPC_NO_PRIMITIVE_TESTS; + + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, lss, worldl, worldm)) return true; + + // Special case for 1-leaf trees + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles + udword Nb = mIMesh->GetNbTriangles(); + + // Loop through all triangles + for(udword i=0;imCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + + // We only have a list of boxes so far + if(GetContactStatus()) + { + // Reset contact status, since it currently only reflects collisions with leaf boxes + Collider::InitQuery(); + + // Change dest container so that we can use built-in overlap tests and get collided primitives + cache.TouchedPrimitives.Reset(); + mTouchedPrimitives = &cache.TouchedPrimitives; + + // Read touched leaf boxes + udword Nb = mTouchedBoxes.GetNbEntries(); + const udword* Touched = mTouchedBoxes.GetEntries(); + + const LeafTriangles* LT = model.GetLeafTriangles(); + const udword* Indices = model.GetIndices(); + + // Loop through touched leaves + while(Nb--) + { + const LeafTriangles& CurrentLeaf = LT[*Touched++]; + + // Each leaf box has a set of triangles + udword NbTris = CurrentLeaf.GetNbTriangles(); + if(Indices) + { + const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = *T++; + LSS_PRIM(TriangleIndex, OPC_CONTACT) + } + } + else + { + udword BaseIndex = CurrentLeaf.GetTriangleIndex(); + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = BaseIndex++; + LSS_PRIM(TriangleIndex, OPC_CONTACT) + } + } + } + } + + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_LSSCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_LSSCollider.h new file mode 100644 index 00000000..8b1f1d29 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_LSSCollider.h @@ -0,0 +1,103 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for an LSS collider. + * \file OPC_LSSCollider.h + * \author Pierre Terdiman + * \date December, 28, 2002 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_LSSCOLLIDER_H__ +#define __OPC_LSSCOLLIDER_H__ + + struct OPCODE_API LSSCache : VolumeCache + { + LSSCache() + { + Previous.mP0 = Point(0.0f, 0.0f, 0.0f); + Previous.mP1 = Point(0.0f, 0.0f, 0.0f); + Previous.mRadius = 0.0f; + FatCoeff = 1.1f; + } + + // Cached faces signature + LSS Previous; //!< LSS used when performing the query resulting in cached faces + // User settings + float FatCoeff; //!< mRadius2 multiplier used to create a fat LSS + }; + + class OPCODE_API LSSCollider : public VolumeCollider + { + public: + // Constructor / Destructor + LSSCollider(); + virtual ~LSSCollider(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] an lss cache + * \param lss [in] collision lss in local space + * \param model [in] Opcode model to collide with + * \param worldl [in] lss world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //bool Collide(LSSCache& cache, const LSS& lss, const Model& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); + // ericf change + bool Collide(LSSCache& cache, const LSS& lss, Model& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); + // + bool Collide(LSSCache& cache, const LSS& lss, const AABBTree* tree); + protected: + // LSS in model space + Segment mSeg; //!< Segment + float mRadius2; //!< LSS radius squared + // Internal methods + void _Collide(const AABBCollisionNode* node); + void _Collide(const AABBNoLeafNode* node); + void _Collide(const AABBQuantizedNode* node); + void _Collide(const AABBQuantizedNoLeafNode* node); + void _Collide(const AABBTreeNode* node); + void _CollideNoPrimitiveTest(const AABBCollisionNode* node); + void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); + // Overlap tests + inline_ BOOL LSSContainsBox(const Point& bc, const Point& be); + inline_ BOOL LSSAABBOverlap(const Point& center, const Point& extents); + inline_ BOOL LSSTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2); + // Init methods + BOOL InitQuery(LSSCache& cache, const LSS& lss, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); + }; + + class OPCODE_API HybridLSSCollider : public LSSCollider + { + public: + // Constructor / Destructor + HybridLSSCollider(); + virtual ~HybridLSSCollider(); + + //bool Collide(LSSCache& cache, const LSS& lss, const HybridModel& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); + // ericf change + bool Collide(LSSCache& cache, const LSS& lss, HybridModel& model, const Matrix4x4* worldl=null, const Matrix4x4* worldm=null); + protected: + Container mTouchedBoxes; + }; + +#endif // __OPC_LSSCOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_LSSTriOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_LSSTriOverlap.h new file mode 100644 index 00000000..f1d17e4a --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_LSSTriOverlap.h @@ -0,0 +1,679 @@ +// Following code from Magic-Software (http://www.magic-software.com/) +// A bit modified for Opcode + +static const float gs_fTolerance = 1e-05f; + +static float OPC_PointTriangleSqrDist(const Point& point, const Point& p0, const Point& p1, const Point& p2) +{ + // Hook + Point TriEdge0 = p1 - p0; + Point TriEdge1 = p2 - p0; + + Point kDiff = p0 - point; + float fA00 = TriEdge0.SquareMagnitude(); + float fA01 = TriEdge0 | TriEdge1; + float fA11 = TriEdge1.SquareMagnitude(); + float fB0 = kDiff | TriEdge0; + float fB1 = kDiff | TriEdge1; + float fC = kDiff.SquareMagnitude(); + float fDet = fabsf(fA00*fA11 - fA01*fA01); + float fS = fA01*fB1-fA11*fB0; + float fT = fA01*fB0-fA00*fB1; + float fSqrDist; + + if(fS + fT <= fDet) + { + if(fS < 0.0f) + { + if(fT < 0.0f) // region 4 + { + if(fB0 < 0.0f) + { + if(-fB0 >= fA00) fSqrDist = fA00+2.0f*fB0+fC; + else fSqrDist = fB0*(-fB0/fA00)+fC; + } + else + { + if(fB1 >= 0.0f) fSqrDist = fC; + else if(-fB1 >= fA11) fSqrDist = fA11+2.0f*fB1+fC; + else fSqrDist = fB1*(-fB1/fA11)+fC; + } + } + else // region 3 + { + if(fB1 >= 0.0f) fSqrDist = fC; + else if(-fB1 >= fA11) fSqrDist = fA11+2.0f*fB1+fC; + else fSqrDist = fB1*(-fB1/fA11)+fC; + } + } + else if(fT < 0.0f) // region 5 + { + if(fB0 >= 0.0f) fSqrDist = fC; + else if(-fB0 >= fA00) fSqrDist = fA00+2.0f*fB0+fC; + else fSqrDist = fB0*(-fB0/fA00)+fC; + } + else // region 0 + { + // minimum at interior point + if(fDet==0.0f) + { + fSqrDist = MAX_FLOAT; + } + else + { + float fInvDet = 1.0f/fDet; + fS *= fInvDet; + fT *= fInvDet; + fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; + } + } + } + else + { + float fTmp0, fTmp1, fNumer, fDenom; + + if(fS < 0.0f) // region 2 + { + fTmp0 = fA01 + fB0; + fTmp1 = fA11 + fB1; + if(fTmp1 > fTmp0) + { + fNumer = fTmp1 - fTmp0; + fDenom = fA00-2.0f*fA01+fA11; + if(fNumer >= fDenom) + { + fSqrDist = fA00+2.0f*fB0+fC; + } + else + { + fS = fNumer/fDenom; + fT = 1.0f - fS; + fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; + } + } + else + { + if(fTmp1 <= 0.0f) fSqrDist = fA11+2.0f*fB1+fC; + else if(fB1 >= 0.0f) fSqrDist = fC; + else fSqrDist = fB1*(-fB1/fA11)+fC; + } + } + else if(fT < 0.0f) // region 6 + { + fTmp0 = fA01 + fB1; + fTmp1 = fA00 + fB0; + if(fTmp1 > fTmp0) + { + fNumer = fTmp1 - fTmp0; + fDenom = fA00-2.0f*fA01+fA11; + if(fNumer >= fDenom) + { + fSqrDist = fA11+2.0f*fB1+fC; + } + else + { + fT = fNumer/fDenom; + fS = 1.0f - fT; + fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; + } + } + else + { + if(fTmp1 <= 0.0f) fSqrDist = fA00+2.0f*fB0+fC; + else if(fB0 >= 0.0f) fSqrDist = fC; + else fSqrDist = fB0*(-fB0/fA00)+fC; + } + } + else // region 1 + { + fNumer = fA11 + fB1 - fA01 - fB0; + if(fNumer <= 0.0f) + { + fSqrDist = fA11+2.0f*fB1+fC; + } + else + { + fDenom = fA00-2.0f*fA01+fA11; + if(fNumer >= fDenom) + { + fSqrDist = fA00+2.0f*fB0+fC; + } + else + { + fS = fNumer/fDenom; + fT = 1.0f - fS; + fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; + } + } + } + } + return fabsf(fSqrDist); +} + +static float OPC_SegmentSegmentSqrDist(const Segment& rkSeg0, const Segment& rkSeg1) +{ + // Hook + Point rkSeg0Direction = rkSeg0.ComputeDirection(); + Point rkSeg1Direction = rkSeg1.ComputeDirection(); + + Point kDiff = rkSeg0.mP0 - rkSeg1.mP0; + float fA00 = rkSeg0Direction.SquareMagnitude(); + float fA01 = -rkSeg0Direction.Dot(rkSeg1Direction); + float fA11 = rkSeg1Direction.SquareMagnitude(); + float fB0 = kDiff.Dot(rkSeg0Direction); + float fC = kDiff.SquareMagnitude(); + float fDet = fabsf(fA00*fA11-fA01*fA01); + + float fB1, fS, fT, fSqrDist, fTmp; + + if(fDet>=gs_fTolerance) + { + // line segments are not parallel + fB1 = -kDiff.Dot(rkSeg1Direction); + fS = fA01*fB1-fA11*fB0; + fT = fA01*fB0-fA00*fB1; + + if(fS >= 0.0f) + { + if(fS <= fDet) + { + if(fT >= 0.0f) + { + if(fT <= fDet) // region 0 (interior) + { + // minimum at two interior points of 3D lines + float fInvDet = 1.0f/fDet; + fS *= fInvDet; + fT *= fInvDet; + fSqrDist = fS*(fA00*fS+fA01*fT+2.0f*fB0) + fT*(fA01*fS+fA11*fT+2.0f*fB1)+fC; + } + else // region 3 (side) + { + fTmp = fA01+fB0; + if(fTmp>=0.0f) fSqrDist = fA11+2.0f*fB1+fC; + else if(-fTmp>=fA00) fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp); + else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC; + } + } + else // region 7 (side) + { + if(fB0>=0.0f) fSqrDist = fC; + else if(-fB0>=fA00) fSqrDist = fA00+2.0f*fB0+fC; + else fSqrDist = fB0*(-fB0/fA00)+fC; + } + } + else + { + if ( fT >= 0.0 ) + { + if ( fT <= fDet ) // region 1 (side) + { + fTmp = fA01+fB1; + if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC; + else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp); + else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC; + } + else // region 2 (corner) + { + fTmp = fA01+fB0; + if ( -fTmp <= fA00 ) + { + if(fTmp>=0.0f) fSqrDist = fA11+2.0f*fB1+fC; + else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC; + } + else + { + fTmp = fA01+fB1; + if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC; + else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp); + else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC; + } + } + } + else // region 8 (corner) + { + if ( -fB0 < fA00 ) + { + if(fB0>=0.0f) fSqrDist = fC; + else fSqrDist = fB0*(-fB0/fA00)+fC; + } + else + { + fTmp = fA01+fB1; + if(fTmp>=0.0f) fSqrDist = fA00+2.0f*fB0+fC; + else if(-fTmp>=fA11) fSqrDist = fA00+fA11+fC+2.0f*(fB0+fTmp); + else fSqrDist = fTmp*(-fTmp/fA11)+fA00+2.0f*fB0+fC; + } + } + } + } + else + { + if ( fT >= 0.0f ) + { + if ( fT <= fDet ) // region 5 (side) + { + if(fB1>=0.0f) fSqrDist = fC; + else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC; + else fSqrDist = fB1*(-fB1/fA11)+fC; + } + else // region 4 (corner) + { + fTmp = fA01+fB0; + if ( fTmp < 0.0f ) + { + if(-fTmp>=fA00) fSqrDist = fA00+fA11+fC+2.0f*(fB1+fTmp); + else fSqrDist = fTmp*(-fTmp/fA00)+fA11+2.0f*fB1+fC; + } + else + { + if(fB1>=0.0f) fSqrDist = fC; + else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC; + else fSqrDist = fB1*(-fB1/fA11)+fC; + } + } + } + else // region 6 (corner) + { + if ( fB0 < 0.0f ) + { + if(-fB0>=fA00) fSqrDist = fA00+2.0f*fB0+fC; + else fSqrDist = fB0*(-fB0/fA00)+fC; + } + else + { + if(fB1>=0.0f) fSqrDist = fC; + else if(-fB1>=fA11) fSqrDist = fA11+2.0f*fB1+fC; + else fSqrDist = fB1*(-fB1/fA11)+fC; + } + } + } + } + else + { + // line segments are parallel + if ( fA01 > 0.0f ) + { + // direction vectors form an obtuse angle + if ( fB0 >= 0.0f ) + { + fSqrDist = fC; + } + else if ( -fB0 <= fA00 ) + { + fSqrDist = fB0*(-fB0/fA00)+fC; + } + else + { + fB1 = -kDiff.Dot(rkSeg1Direction); + fTmp = fA00+fB0; + if ( -fTmp >= fA01 ) + { + fSqrDist = fA00+fA11+fC+2.0f*(fA01+fB0+fB1); + } + else + { + fT = -fTmp/fA01; + fSqrDist = fA00+2.0f*fB0+fC+fT*(fA11*fT+2.0f*(fA01+fB1)); + } + } + } + else + { + // direction vectors form an acute angle + if ( -fB0 >= fA00 ) + { + fSqrDist = fA00+2.0f*fB0+fC; + } + else if ( fB0 <= 0.0f ) + { + fSqrDist = fB0*(-fB0/fA00)+fC; + } + else + { + fB1 = -kDiff.Dot(rkSeg1Direction); + if ( fB0 >= -fA01 ) + { + fSqrDist = fA11+2.0f*fB1+fC; + } + else + { + fT = -fB0/fA01; + fSqrDist = fC+fT*(2.0f*fB1+fA11*fT); + } + } + } + } + return fabsf(fSqrDist); +} + +inline_ float OPC_SegmentRaySqrDist(const Segment& rkSeg0, const Ray& rkSeg1) +{ + return OPC_SegmentSegmentSqrDist(rkSeg0, Segment(rkSeg1.mOrig, rkSeg1.mOrig + rkSeg1.mDir)); +} + +static float OPC_SegmentTriangleSqrDist(const Segment& segment, const Point& p0, const Point& p1, const Point& p2) +{ + // Hook + const Point TriEdge0 = p1 - p0; + const Point TriEdge1 = p2 - p0; + + const Point& rkSegOrigin = segment.GetOrigin(); + Point rkSegDirection = segment.ComputeDirection(); + + Point kDiff = p0 - rkSegOrigin; + float fA00 = rkSegDirection.SquareMagnitude(); + float fA01 = -rkSegDirection.Dot(TriEdge0); + float fA02 = -rkSegDirection.Dot(TriEdge1); + float fA11 = TriEdge0.SquareMagnitude(); + float fA12 = TriEdge0.Dot(TriEdge1); + float fA22 = TriEdge1.Dot(TriEdge1); + float fB0 = -kDiff.Dot(rkSegDirection); + float fB1 = kDiff.Dot(TriEdge0); + float fB2 = kDiff.Dot(TriEdge1); + float fCof00 = fA11*fA22-fA12*fA12; + float fCof01 = fA02*fA12-fA01*fA22; + float fCof02 = fA01*fA12-fA02*fA11; + float fDet = fA00*fCof00+fA01*fCof01+fA02*fCof02; + + Ray kTriSeg; + Point kPt; + float fSqrDist, fSqrDist0; + + if(fabsf(fDet)>=gs_fTolerance) + { + float fCof11 = fA00*fA22-fA02*fA02; + float fCof12 = fA02*fA01-fA00*fA12; + float fCof22 = fA00*fA11-fA01*fA01; + float fInvDet = 1.0f/fDet; + float fRhs0 = -fB0*fInvDet; + float fRhs1 = -fB1*fInvDet; + float fRhs2 = -fB2*fInvDet; + + float fR = fCof00*fRhs0+fCof01*fRhs1+fCof02*fRhs2; + float fS = fCof01*fRhs0+fCof11*fRhs1+fCof12*fRhs2; + float fT = fCof02*fRhs0+fCof12*fRhs1+fCof22*fRhs2; + + if ( fR < 0.0f ) + { + if ( fS+fT <= 1.0f ) + { + if ( fS < 0.0f ) + { + if ( fT < 0.0f ) // region 4m + { + // min on face s=0 or t=0 or r=0 + kTriSeg.mOrig = p0; + kTriSeg.mDir = TriEdge1; + fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg); + kTriSeg.mOrig = p0; + kTriSeg.mDir = TriEdge0; + fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg); + if(fSqrDist0 1 + { + if ( fS+fT <= 1.0f ) + { + if ( fS < 0.0f ) + { + if ( fT < 0.0f ) // region 4p + { + // min on face s=0 or t=0 or r=1 + kTriSeg.mOrig = p0; + kTriSeg.mDir = TriEdge1; + fSqrDist = OPC_SegmentRaySqrDist(segment, kTriSeg); + kTriSeg.mOrig = p0; + kTriSeg.mDir = TriEdge0; + fSqrDist0 = OPC_SegmentRaySqrDist(segment, kTriSeg); + if(fSqrDist0GetTriangle(triangle_index); + * // Setup pointers to vertices for the collision system + * triangle.Vertex[0] = MyMesh->GetVertex(Tri->mVRef[0]); + * triangle.Vertex[1] = MyMesh->GetVertex(Tri->mVRef[1]); + * triangle.Vertex[2] = MyMesh->GetVertex(Tri->mVRef[2]); + * } + * + * // Setup callbacks + * MeshInterface0->SetCallback(ColCallback, udword(Mesh0)); + * MeshInterface1->SetCallback(ColCallback, udword(Mesh1)); + * \endcode + * + * Of course, you should make this callback as fast as possible. And you're also not supposed + * to modify the geometry *after* the collision trees have been built. The alternative was to + * store the geometry & topology in the collision system as well (as in RAPID) but we have found + * this approach to waste a lot of ram in many cases. + * + * + * POINTERS: + * + * If you're internally using the following canonical structures: + * - a vertex made of three 32-bits floating point values + * - a triangle made of three 32-bits integer vertex references + * ...then you may want to use pointers instead of callbacks. This is the same, except OPCODE will directly + * use provided pointers to access the topology and geometry, without using a callback. It might be faster, + * but probably not as safe. Pointers have been introduced in OPCODE 1.2. + * + * Ex: + * + * \code + * // Setup pointers + * MeshInterface0->SetPointers(Mesh0->GetFaces(), Mesh0->GetVerts()); + * MeshInterface1->SetPointers(Mesh1->GetFaces(), Mesh1->GetVerts()); + * \endcode + * + * + * STRIDES: + * + * If your vertices are D3D-like entities interleaving a position, a normal and/or texture coordinates + * (i.e. if your vertices are FVFs), you might want to use a vertex stride to skip extra data OPCODE + * doesn't need. Using a stride shouldn't be notably slower than not using it, but it might increase + * cache misses. Please also note that you *shouldn't* read from AGP or video-memory buffers ! + * + * + * In any case, compilation flags are here to select callbacks/pointers/strides at compile time, so + * choose what's best for your application. All of this has been wrapped into this MeshInterface. + * + * \class MeshInterface + * \author Pierre Terdiman + * \version 1.3 + * \date November, 27, 2002 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +// ericf change +// Point MeshInterface::VertexCache[3]; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +MeshInterface::MeshInterface() : +#ifdef OPC_USE_CALLBACKS + mUserData (null), + mObjCallback (null), + mNbTris (0), + mNbVerts (0), +#else + mNbTris (0), + mNbVerts (0), + mTris (null), + mVerts (null), +# ifdef OPC_USE_STRIDE + mTriStride (sizeof(IndexedTriangle)), + mVertexStride (sizeof(Point)), +# endif +#endif + + Single(true) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +MeshInterface::~MeshInterface() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the mesh interface is valid, i.e. things have been setup correctly. + * \return true if valid + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool MeshInterface::IsValid() const +{ + if(!mNbTris || !mNbVerts) return false; +#ifdef OPC_USE_CALLBACKS + if(!mObjCallback) return false; +#else + if(!mTris || !mVerts) return false; +#endif + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the mesh itself is valid. + * Currently we only look for degenerate faces. + * \return number of degenerate faces + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//udword MeshInterface::CheckTopology() const +// ericf change +udword MeshInterface::CheckTopology() +{ + // Check topology. If the model contains degenerate faces, collision report can be wrong in some cases. + // e.g. it happens with the standard MAX teapot. So clean your meshes first... If you don't have a mesh cleaner + // you can try this: www.codercorner.com/Consolidation.zip + + udword NbDegenerate = 0; + + VertexPointers VP; + + // Using callbacks, we don't have access to vertex indices. Nevertheless we still can check for + // redundant vertex pointers, which cover all possibilities (callbacks/pointers/strides). + for(udword i=0;i= 0.0f; + } + }; + +#ifdef OPC_USE_CALLBACKS + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * User-callback, called by OPCODE to request vertices from the app. + * \param triangle_index [in] face index for which the system is requesting the vertices + * \param triangle [out] triangle's vertices (must be provided by the user) + * \param user_data [in] user-defined data from SetCallback() + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + typedef void (*RequestCallback) (udword triangle_index, VertexPointers& triangle, void* user_data); +#endif + + class OPCODE_API MeshInterface + { + public: + // Constructor / Destructor + MeshInterface(); + ~MeshInterface(); + // Common settings + inline_ udword GetNbTriangles() const { return mNbTris; } + inline_ udword GetNbVertices() const { return mNbVerts; } + inline_ void SetNbTriangles(udword nb) { mNbTris = nb; } + inline_ void SetNbVertices(udword nb) { mNbVerts = nb; } + +#ifdef OPC_USE_CALLBACKS + // Callback settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Callback control: setups object callback. Must provide triangle-vertices for a given triangle index. + * \param callback [in] user-defined callback + * \param user_data [in] user-defined data + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool SetCallback(RequestCallback callback, void* user_data); + inline_ void* GetUserData() const { return mUserData; } + inline_ RequestCallback GetCallback() const { return mObjCallback; } +#else + // Pointers settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Pointers control: setups object pointers. Must provide access to faces and vertices for a given object. + * \param tris [in] pointer to triangles + * \param verts [in] pointer to vertices + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool SetPointers(const IndexedTriangle* tris, const Point* verts); + inline_ const IndexedTriangle* GetTris() const { return mTris; } + inline_ const Point* GetVerts() const { return mVerts; } + + #ifdef OPC_USE_STRIDE + // Strides settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Strides control + * \param tri_stride [in] size of a triangle in bytes. The first sizeof(IndexedTriangle) bytes are used to get vertex indices. + * \param vertex_stride [in] size of a vertex in bytes. The first sizeof(Point) bytes are used to get vertex position. + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool SetStrides(udword tri_stride=sizeof(IndexedTriangle), udword vertex_stride=sizeof(Point)); + inline_ udword GetTriStride() const { return mTriStride; } + inline_ udword GetVertexStride() const { return mVertexStride; } + #endif +#endif + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Fetches a triangle given a triangle index. + * \param vp [out] required triangle's vertex pointers + * \param index [in] triangle index + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //inline_ void GetTriangle(VertexPointers& vp, udword index) const + inline_ void GetTriangle(VertexPointers& vp, udword index) + { +#ifdef OPC_USE_CALLBACKS + (mObjCallback)(index, vp, mUserData); +#else + #ifdef OPC_USE_STRIDE + const IndexedTriangle* T = (const IndexedTriangle*)(((ubyte*)mTris) + index * mTriStride); + + if (Single){ + vp.Vertex[0] = (const Point*)(((ubyte*)mVerts) + T->mVRef[0] * mVertexStride); + vp.Vertex[1] = (const Point*)(((ubyte*)mVerts) + T->mVRef[1] * mVertexStride); + vp.Vertex[2] = (const Point*)(((ubyte*)mVerts) + T->mVRef[2] * mVertexStride); + } + else{ + for (int i = 0; i < 3; i++){ + const double* v = (const double*)(((ubyte*)mVerts) + T->mVRef[i] * mVertexStride); + + VertexCache[i].x = (float)v[0]; + VertexCache[i].y = (float)v[1]; + VertexCache[i].z = (float)v[2]; + vp.Vertex[i] = &VertexCache[i]; + } + } + #else + const IndexedTriangle* T = &mTris[index]; + vp.Vertex[0] = &mVerts[T->mVRef[0]]; + vp.Vertex[1] = &mVerts[T->mVRef[1]]; + vp.Vertex[2] = &mVerts[T->mVRef[2]]; + #endif +#endif + } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Remaps client's mesh according to a permutation. + * \param nb_indices [in] number of indices in the permutation (will be checked against number of triangles) + * \param permutation [in] list of triangle indices + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool RemapClient(udword nb_indices, const udword* permutation) const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the mesh interface is valid, i.e. things have been setup correctly. + * \return true if valid + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool IsValid() const; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Checks the mesh itself is valid. + * Currently we only look for degenerate faces. + * \return number of degenerate faces + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // ericf change + udword CheckTopology(); + //udword CheckTopology() const; + private: + + udword mNbTris; //!< Number of triangles in the input model + udword mNbVerts; //!< Number of vertices in the input model +#ifdef OPC_USE_CALLBACKS + // User callback + void* mUserData; //!< User-defined data sent to callback + RequestCallback mObjCallback; //!< Object callback +#else + // User pointers + const IndexedTriangle* mTris; //!< Array of indexed triangles + const Point* mVerts; //!< Array of vertices +# ifdef OPC_USE_STRIDE + udword mTriStride; //!< Possible triangle stride in bytes [Opcode 1.3] + udword mVertexStride; //!< Possible vertex stride in bytes [Opcode 1.3] +# endif + public: + bool Single; //!< Use single or double precision vertices + private: + //static Point VertexCache[3]; + + // ericf change for multithreading + Point VertexCache[3]; +#endif + }; + +#endif //__OPC_MESHINTERFACE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Model.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_Model.cpp new file mode 100644 index 00000000..8fdec9e1 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Model.cpp @@ -0,0 +1,230 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for OPCODE models. + * \file OPC_Model.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * The main collision wrapper, for all trees. Supported trees are: + * - Normal trees (2*N-1 nodes, full size) + * - No-leaf trees (N-1 nodes, full size) + * - Quantized trees (2*N-1 nodes, half size) + * - Quantized no-leaf trees (N-1 nodes, half size) + * + * Usage: + * + * 1) Create a static mesh interface using callbacks or pointers. (see OPC_MeshInterface.cpp). + * Keep it around in your app, since a pointer to this interface is saved internally and + * used until you release the collision structures. + * + * 2) Build a Model using a creation structure: + * + * \code + * Model Sample; + * + * OPCODECREATE OPCC; + * OPCC.IMesh = ...; + * OPCC.Rules = ...; + * OPCC.NoLeaf = ...; + * OPCC.Quantized = ...; + * OPCC.KeepOriginal = ...; + * bool Status = Sample.Build(OPCC); + * \endcode + * + * 3) Create a tree collider and set it up: + * + * \code + * AABBTreeCollider TC; + * TC.SetFirstContact(...); + * TC.SetFullBoxBoxTest(...); + * TC.SetFullPrimBoxTest(...); + * TC.SetTemporalCoherence(...); + * \endcode + * + * 4) Perform a collision query + * + * \code + * // Setup cache + * static BVTCache ColCache; + * ColCache.Model0 = &Model0; + * ColCache.Model1 = &Model1; + * + * // Collision query + * bool IsOk = TC.Collide(ColCache, World0, World1); + * + * // Get collision status => if true, objects overlap + * BOOL Status = TC.GetContactStatus(); + * + * // Number of colliding pairs and list of pairs + * udword NbPairs = TC.GetNbPairs(); + * const Pair* p = TC.GetPairs() + * \endcode + * + * 5) Stats + * + * \code + * Model0.GetUsedBytes() = number of bytes used for this collision tree + * TC.GetNbBVBVTests() = number of BV-BV overlap tests performed during last query + * TC.GetNbPrimPrimTests() = number of Triangle-Triangle overlap tests performed during last query + * TC.GetNbBVPrimTests() = number of Triangle-BV overlap tests performed during last query + * \endcode + * + * \class Model + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Model::Model() +{ +#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! + mHull = null; +#endif // __MESHMERIZER_H__ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +Model::~Model() +{ + Release(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Releases the model. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void Model::Release() +{ + ReleaseBase(); +#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! + DELETESINGLE(mHull); +#endif // __MESHMERIZER_H__ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds a collision model. + * \param create [in] model creation structure + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool Model::Build(const OPCODECREATE& create) +{ + // 1) Checkings + if(!create.mIMesh || !create.mIMesh->IsValid()) return false; + + // For this model, we only support complete trees + if(create.mSettings.mLimit!=1) return SetIceError("OPCODE WARNING: supports complete trees only! Use mLimit = 1.\n", null); + + // Look for degenerate faces. + udword NbDegenerate = create.mIMesh->CheckTopology(); + if(NbDegenerate) Log("OPCODE WARNING: found %d degenerate faces in model! Collision might report wrong results!\n", NbDegenerate); + // We continue nonetheless.... + + Release(); // Make sure previous tree has been discarded [Opcode 1.3, thanks Adam] + + // 1-1) Setup mesh interface automatically [Opcode 1.3] + SetMeshInterface(create.mIMesh); + + // Special case for 1-triangle meshes [Opcode 1.3] + udword NbTris = create.mIMesh->GetNbTriangles(); + if(NbTris==1) + { + // We don't need to actually create a tree here, since we'll only have a single triangle to deal with anyway. + // It's a waste to use a "model" for this but at least it will work. + mModelCode |= OPC_SINGLE_NODE; + return true; + } + + // 2) Build a generic AABB Tree. + mSource = new AABBTree; + CHECKALLOC(mSource); + + // 2-1) Setup a builder. Our primitives here are triangles from input mesh, + // so we use an AABBTreeOfTrianglesBuilder..... + { + AABBTreeOfTrianglesBuilder TB; + TB.mIMesh = create.mIMesh; + TB.mSettings = create.mSettings; + TB.mNbPrimitives = NbTris; + if(!mSource->Build(&TB)) return false; + } + + // 3) Create an optimized tree according to user-settings + if(!CreateTree(create.mNoLeaf, create.mQuantized)) return false; + + // 3-2) Create optimized tree + if(!mTree->Build(mSource)) return false; + + // 3-3) Delete generic tree if needed + if(!create.mKeepOriginal) DELETESINGLE(mSource); + +#ifdef __MESHMERIZER_H__ + // 4) Convex hull + if(create.mCollisionHull) + { + // Create hull + mHull = new CollisionHull; + CHECKALLOC(mHull); + + CONVEXHULLCREATE CHC; + // ### doesn't work with strides + CHC.NbVerts = create.mIMesh->GetNbVertices(); + CHC.Vertices = create.mIMesh->GetVerts(); + CHC.UnifyNormals = true; + CHC.ReduceVertices = true; + CHC.WordFaces = false; + mHull->Compute(CHC); + } +#endif // __MESHMERIZER_H__ + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets the number of bytes used by the tree. + * \return amount of bytes used + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +udword Model::GetUsedBytes() const +{ + if(!mTree) return 0; + return mTree->GetUsedBytes(); +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Model.h b/src/external/open_dynamics_engine-ef/ode/OPC_Model.h new file mode 100644 index 00000000..98dee560 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Model.h @@ -0,0 +1,65 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for OPCODE models. + * \file OPC_Model.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_MODEL_H__ +#define __OPC_MODEL_H__ + + class OPCODE_API Model : public BaseModel + { + public: + // Constructor/Destructor + Model(); + virtual ~Model(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Builds a collision model. + * \param create [in] model creation structure + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(BaseModel) bool Build(const OPCODECREATE& create); + +#ifdef __MESHMERIZER_H__ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the collision hull. + * \return the collision hull if it exists + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const CollisionHull* GetHull() const { return mHull; } +#endif // __MESHMERIZER_H__ + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the number of bytes used by the tree. + * \return amount of bytes used + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(BaseModel) udword GetUsedBytes() const; + + private: +#ifdef __MESHMERIZER_H__ + CollisionHull* mHull; //!< Possible convex hull +#endif // __MESHMERIZER_H__ + // Internal methods + void Release(); + }; + +#endif //__OPC_MODEL_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.cpp new file mode 100644 index 00000000..d3bf19bc --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.cpp @@ -0,0 +1,779 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for an OBB collider. + * \file OPC_OBBCollider.cpp + * \author Pierre Terdiman + * \date January, 1st, 2002 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains an OBB-vs-tree collider. + * + * \class OBBCollider + * \author Pierre Terdiman + * \version 1.3 + * \date January, 1st, 2002 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +#include "ode/OPC_BoxBoxOverlap.h" +#include "ode/OPC_TriBoxOverlap.h" + +#define SET_CONTACT(prim_index, flag) \ + /* Set contact status */ \ + mFlags |= flag; \ + mTouchedPrimitives->Add(prim_index); + +//! OBB-triangle test +#define OBB_PRIM(prim_index, flag) \ + /* Request vertices from the app */ \ + VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \ + /* Transform them in a common space */ \ + TransformPoint(mLeafVerts[0], *VP.Vertex[0], mRModelToBox, mTModelToBox); \ + TransformPoint(mLeafVerts[1], *VP.Vertex[1], mRModelToBox, mTModelToBox); \ + TransformPoint(mLeafVerts[2], *VP.Vertex[2], mRModelToBox, mTModelToBox); \ + /* Perform triangle-box overlap test */ \ + if(TriBoxOverlap()) \ + { \ + SET_CONTACT(prim_index, flag) \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OBBCollider::OBBCollider() : mFullBoxBoxTest(true) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +OBBCollider::~OBBCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Validates current settings. You should call this method after all the settings and callbacks have been defined. + * \return null if everything is ok, else a string describing the problem + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const char* OBBCollider::ValidateSettings() +{ + if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; + + return VolumeCollider::ValidateSettings(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a box cache + * \param box [in] collision OBB in local space + * \param model [in] Opcode model to collide with + * \param worldb [in] OBB's world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool OBBCollider::Collide(OBBCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb, const Matrix4x4* worldm) +// ericf change +bool OBBCollider::Collide(OBBCache& cache, const OBB& box, Model& model, const Matrix4x4* worldb, const Matrix4x4* worldm) +{ + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, box, worldb, worldm)) return true; + + if(!model.HasLeafNodes()) + { + if(model.IsQuantized()) + { + const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a collision query : + * - reset stats & contact status + * - setup matrices + * - check temporal coherence + * + * \param cache [in/out] a box cache + * \param box [in] obb in local space + * \param worldb [in] obb's world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return TRUE if we can return immediately + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL OBBCollider::InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb, const Matrix4x4* worldm) +{ + // 1) Call the base method + VolumeCollider::InitQuery(); + + // 2) Compute obb in world space + mBoxExtents = box.mExtents; + + Matrix4x4 WorldB; + + if(worldb) + { + WorldB = Matrix4x4( box.mRot * Matrix3x3(*worldb) ); + WorldB.SetTrans(box.mCenter * *worldb); + } + else + { + WorldB = box.mRot; + WorldB.SetTrans(box.mCenter); + } + + // Setup matrices + Matrix4x4 InvWorldB; + InvertPRMatrix(InvWorldB, WorldB); + + if(worldm) + { + Matrix4x4 InvWorldM; + InvertPRMatrix(InvWorldM, *worldm); + + Matrix4x4 WorldBtoM = WorldB * InvWorldM; + Matrix4x4 WorldMtoB = *worldm * InvWorldB; + + mRModelToBox = WorldMtoB; WorldMtoB.GetTrans(mTModelToBox); + mRBoxToModel = WorldBtoM; WorldBtoM.GetTrans(mTBoxToModel); + } + else + { + mRModelToBox = InvWorldB; InvWorldB.GetTrans(mTModelToBox); + mRBoxToModel = WorldB; WorldB.GetTrans(mTBoxToModel); + } + + // 3) Setup destination pointer + mTouchedPrimitives = &cache.TouchedPrimitives; + + // 4) Special case: 1-triangle meshes [Opcode 1.3] + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + if(!SkipPrimitiveTests()) + { + // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. + mTouchedPrimitives->Reset(); + + // Perform overlap test between the unique triangle and the box (and set contact status if needed) + OBB_PRIM(udword(0), OPC_CONTACT) + + // Return immediately regardless of status + return TRUE; + } + } + + // 5) Check temporal coherence: + if(TemporalCoherenceEnabled()) + { + // Here we use temporal coherence + // => check results from previous frame before performing the collision query + if(FirstContactEnabled()) + { + // We're only interested in the first contact found => test the unique previously touched face + if(mTouchedPrimitives->GetNbEntries()) + { + // Get index of previously touched face = the first entry in the array + udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); + + // Then reset the array: + // - if the overlap test below is successful, the index we'll get added back anyway + // - if it isn't, then the array should be reset anyway for the normal query + mTouchedPrimitives->Reset(); + + // Perform overlap test between the cached triangle and the box (and set contact status if needed) + OBB_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) + + // Return immediately if possible + if(GetContactStatus()) return TRUE; + } + // else no face has been touched during previous query + // => we'll have to perform a normal query + } + else + { + // ### rewrite this + OBB TestBox(mTBoxToModel, mBoxExtents, mRBoxToModel); + + // We're interested in all contacts =>test the new real box N(ew) against the previous fat box P(revious): + if(IsCacheValid(cache) && TestBox.IsInside(cache.FatBox)) + { + // - if N is included in P, return previous list + // => we simply leave the list (mTouchedFaces) unchanged + + // Set contact status if needed + if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; + + // In any case we don't need to do a query + return TRUE; + } + else + { + // - else do the query using a fat N + + // Reset cache since we'll about to perform a real query + mTouchedPrimitives->Reset(); + + // Make a fat box so that coherence will work for subsequent frames + TestBox.mExtents *= cache.FatCoeff; + mBoxExtents *= cache.FatCoeff; + + // Update cache with query data (signature for cached faces) + cache.FatBox = TestBox; + } + } + } + else + { + // Here we don't use temporal coherence => do a normal query + mTouchedPrimitives->Reset(); + } + + // Now we can precompute box-box data + + // Precompute absolute box-to-model rotation matrix + for(udword i=0;i<3;i++) + { + for(udword j=0;j<3;j++) + { + // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID) + mAR.m[i][j] = 1e-6f + fabsf(mRBoxToModel.m[i][j]); + } + } + + // Precompute bounds for box-in-box test + mB0 = mBoxExtents - mTModelToBox; + mB1 = - mBoxExtents - mTModelToBox; + + // Precompute box-box data - Courtesy of Erwin de Vries + mBBx1 = mBoxExtents.x*mAR.m[0][0] + mBoxExtents.y*mAR.m[1][0] + mBoxExtents.z*mAR.m[2][0]; + mBBy1 = mBoxExtents.x*mAR.m[0][1] + mBoxExtents.y*mAR.m[1][1] + mBoxExtents.z*mAR.m[2][1]; + mBBz1 = mBoxExtents.x*mAR.m[0][2] + mBoxExtents.y*mAR.m[1][2] + mBoxExtents.z*mAR.m[2][2]; + + mBB_1 = mBoxExtents.y*mAR.m[2][0] + mBoxExtents.z*mAR.m[1][0]; + mBB_2 = mBoxExtents.x*mAR.m[2][0] + mBoxExtents.z*mAR.m[0][0]; + mBB_3 = mBoxExtents.x*mAR.m[1][0] + mBoxExtents.y*mAR.m[0][0]; + mBB_4 = mBoxExtents.y*mAR.m[2][1] + mBoxExtents.z*mAR.m[1][1]; + mBB_5 = mBoxExtents.x*mAR.m[2][1] + mBoxExtents.z*mAR.m[0][1]; + mBB_6 = mBoxExtents.x*mAR.m[1][1] + mBoxExtents.y*mAR.m[0][1]; + mBB_7 = mBoxExtents.y*mAR.m[2][2] + mBoxExtents.z*mAR.m[1][2]; + mBB_8 = mBoxExtents.x*mAR.m[2][2] + mBoxExtents.z*mAR.m[0][2]; + mBB_9 = mBoxExtents.x*mAR.m[1][2] + mBoxExtents.y*mAR.m[0][2]; + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the OBB completely contains the box. In which case we can end the query sooner. + * \param bc [in] box center + * \param be [in] box extents + * \return true if the OBB contains the whole box + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL OBBCollider::OBBContainsBox(const Point& bc, const Point& be) +{ + // I assume if all 8 box vertices are inside the OBB, so does the whole box. + // Sounds ok but maybe there's a better way? +/* +#define TEST_PT(a,b,c) \ + p.x=a; p.y=b; p.z=c; p+=bc; \ + f = p.x * mRModelToBox.m[0][0] + p.y * mRModelToBox.m[1][0] + p.z * mRModelToBox.m[2][0]; if(f>mB0.x || fmB0.y || fmB0.z || f NCx-NEx) return FALSE; + + float NCy = bc.x * mRModelToBox.m[0][1] + bc.y * mRModelToBox.m[1][1] + bc.z * mRModelToBox.m[2][1]; + float NEy = fabsf(mRModelToBox.m[0][1] * be.x) + fabsf(mRModelToBox.m[1][1] * be.y) + fabsf(mRModelToBox.m[2][1] * be.z); + + if(mB0.y < NCy+NEy) return FALSE; + if(mB1.y > NCy-NEy) return FALSE; + + float NCz = bc.x * mRModelToBox.m[0][2] + bc.y * mRModelToBox.m[1][2] + bc.z * mRModelToBox.m[2][2]; + float NEz = fabsf(mRModelToBox.m[0][2] * be.x) + fabsf(mRModelToBox.m[1][2] * be.y) + fabsf(mRModelToBox.m[2][2] * be.z); + + if(mB0.z < NCz+NEz) return FALSE; + if(mB1.z > NCz-NEz) return FALSE; + + return TRUE; +} + +#define TEST_BOX_IN_OBB(center, extents) \ + if(OBBContainsBox(center, extents)) \ + { \ + /* Set contact status */ \ + mFlags |= OPC_CONTACT; \ + _Dump(node); \ + return; \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_Collide(const AABBCollisionNode* node) +{ + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + OBB_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) +{ + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_Collide(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(Extents, Center)) return; + + TEST_BOX_IN_OBB(Center, Extents) + + if(node->IsLeaf()) + { + OBB_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(Extents, Center)) return; + + TEST_BOX_IN_OBB(Center, Extents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_Collide(const AABBNoLeafNode* node) +{ + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { OBB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { OBB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) +{ + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(node->mAABB.mExtents, node->mAABB.mCenter)) return; + + TEST_BOX_IN_OBB(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_Collide(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(Extents, Center)) return; + + TEST_BOX_IN_OBB(Center, Extents) + + if(node->HasPosLeaf()) { OBB_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { OBB_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void OBBCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform OBB-AABB overlap test + if(!BoxBoxOverlap(Extents, Center)) return; + + TEST_BOX_IN_OBB(Center, Extents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridOBBCollider::HybridOBBCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridOBBCollider::~HybridOBBCollider() +{ +} + +//bool HybridOBBCollider::Collide(OBBCache& cache, const OBB& box, const HybridModel& model, const Matrix4x4* worldb, const Matrix4x4* worldm) +// ericf change +bool HybridOBBCollider::Collide(OBBCache& cache, const OBB& box, HybridModel& model, const Matrix4x4* worldb, const Matrix4x4* worldm) +{ + // We don't want primitive tests here! + mFlags |= OPC_NO_PRIMITIVE_TESTS; + + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, box, worldb, worldm)) return true; + + // Special case for 1-leaf trees + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles + udword Nb = mIMesh->GetNbTriangles(); + + // Loop through all triangles + for(udword i=0;imCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + + // We only have a list of boxes so far + if(GetContactStatus()) + { + // Reset contact status, since it currently only reflects collisions with leaf boxes + Collider::InitQuery(); + + // Change dest container so that we can use built-in overlap tests and get collided primitives + cache.TouchedPrimitives.Reset(); + mTouchedPrimitives = &cache.TouchedPrimitives; + + // Read touched leaf boxes + udword Nb = mTouchedBoxes.GetNbEntries(); + const udword* Touched = mTouchedBoxes.GetEntries(); + + const LeafTriangles* LT = model.GetLeafTriangles(); + const udword* Indices = model.GetIndices(); + + // Loop through touched leaves + while(Nb--) + { + const LeafTriangles& CurrentLeaf = LT[*Touched++]; + + // Each leaf box has a set of triangles + udword NbTris = CurrentLeaf.GetNbTriangles(); + if(Indices) + { + const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = *T++; + OBB_PRIM(TriangleIndex, OPC_CONTACT) + } + } + else + { + udword BaseIndex = CurrentLeaf.GetTriangleIndex(); + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = BaseIndex++; + OBB_PRIM(TriangleIndex, OPC_CONTACT) + } + } + } + } + + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.h new file mode 100644 index 00000000..9ebd72cc --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_OBBCollider.h @@ -0,0 +1,146 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for an OBB collider. + * \file OPC_OBBCollider.h + * \author Pierre Terdiman + * \date January, 1st, 2002 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_OBBCOLLIDER_H__ +#define __OPC_OBBCOLLIDER_H__ + + struct OPCODE_API OBBCache : VolumeCache + { + OBBCache() : FatCoeff(1.1f) + { + FatBox.mCenter.Zero(); + FatBox.mExtents.Zero(); + FatBox.mRot.Identity(); + } + + // Cached faces signature + OBB FatBox; //!< Box used when performing the query resulting in cached faces + // User settings + float FatCoeff; //!< extents multiplier used to create a fat box + }; + + class OPCODE_API OBBCollider : public VolumeCollider + { + public: + // Constructor / Destructor + OBBCollider(); + virtual ~OBBCollider(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a box cache + * \param box [in] collision OBB in local space + * \param model [in] Opcode model to collide with + * \param worldb [in] OBB's world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //bool Collide(OBBCache& cache, const OBB& box, const Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); + // ericf change + bool Collide(OBBCache& cache, const OBB& box, Model& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); + + // Settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: select between full box-box tests or "SAT-lite" tests (where Class III axes are discarded) + * \param flag [in] true for full tests, false for coarse tests + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetFullBoxBoxTest(bool flag) { mFullBoxBoxTest = flag; } + + // Settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider. + * \return null if everything is ok, else a string describing the problem + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(Collider) const char* ValidateSettings(); + + protected: + // Precomputed data + Matrix3x3 mAR; //!< Absolute rotation matrix + Matrix3x3 mRModelToBox; //!< Rotation from model space to obb space + Matrix3x3 mRBoxToModel; //!< Rotation from obb space to model space + Point mTModelToBox; //!< Translation from model space to obb space + Point mTBoxToModel; //!< Translation from obb space to model space + + Point mBoxExtents; + Point mB0; //!< - mTModelToBox + mBoxExtents + Point mB1; //!< - mTModelToBox - mBoxExtents + + float mBBx1; + float mBBy1; + float mBBz1; + + float mBB_1; + float mBB_2; + float mBB_3; + float mBB_4; + float mBB_5; + float mBB_6; + float mBB_7; + float mBB_8; + float mBB_9; + + // Leaf description + Point mLeafVerts[3]; //!< Triangle vertices + // Settings + bool mFullBoxBoxTest; //!< Perform full BV-BV tests (true) or SAT-lite tests (false) + // Internal methods + void _Collide(const AABBCollisionNode* node); + void _Collide(const AABBNoLeafNode* node); + void _Collide(const AABBQuantizedNode* node); + void _Collide(const AABBQuantizedNoLeafNode* node); + void _CollideNoPrimitiveTest(const AABBCollisionNode* node); + void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); + // Overlap tests + inline_ BOOL OBBContainsBox(const Point& bc, const Point& be); + inline_ BOOL BoxBoxOverlap(const Point& extents, const Point& center); + inline_ BOOL TriBoxOverlap(); + // Init methods + BOOL InitQuery(OBBCache& cache, const OBB& box, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); + }; + + class OPCODE_API HybridOBBCollider : public OBBCollider + { + public: + // Constructor / Destructor + HybridOBBCollider(); + virtual ~HybridOBBCollider(); + + //bool Collide(OBBCache& cache, const OBB& box, const HybridModel& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); + // ericf change + bool Collide(OBBCache& cache, const OBB& box, HybridModel& model, const Matrix4x4* worldb=null, const Matrix4x4* worldm=null); + protected: + Container mTouchedBoxes; + }; + +#endif // __OPC_OBBCOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.cpp new file mode 100644 index 00000000..aa573e8d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.cpp @@ -0,0 +1,798 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for optimized trees. Implements 4 trees: + * - normal + * - no leaf + * - quantized + * - no leaf / quantized + * + * \file OPC_OptimizedTree.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A standard AABB tree. + * + * \class AABBCollisionTree + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A no-leaf AABB tree. + * + * \class AABBNoLeafTree + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A quantized AABB tree. + * + * \class AABBQuantizedTree + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A quantized no-leaf AABB tree. + * + * \class AABBQuantizedNoLeafTree + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +//! Compilation flag: +//! - true to fix quantized boxes (i.e. make sure they enclose the original ones) +//! - false to see the effects of quantization errors (faster, but wrong results in some cases) +static bool gFixQuantized = true; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds an implicit tree from a standard one. An implicit tree is a complete tree (2*N-1 nodes) whose negative + * box pointers and primitive pointers have been made implicit, hence packing 3 pointers in one. + * + * Layout for implicit trees: + * Node: + * - box + * - data (32-bits value) + * + * if data's LSB = 1 => remaining bits are a primitive pointer + * else remaining bits are a P-node pointer, and N = P + 1 + * + * \relates AABBCollisionNode + * \fn _BuildCollisionTree(AABBCollisionNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) + * \param linear [in] base address of destination nodes + * \param box_id [in] index of destination node + * \param current_id [in] current running index + * \param current_node [in] current node from input tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void _BuildCollisionTree(AABBCollisionNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) +{ + // Current node from input tree is "current_node". Must be flattened into "linear[boxid]". + + // Store the AABB + current_node->GetAABB()->GetCenter(linear[box_id].mAABB.mCenter); + current_node->GetAABB()->GetExtents(linear[box_id].mAABB.mExtents); + // Store remaining info + if(current_node->IsLeaf()) + { + // The input tree must be complete => i.e. one primitive/leaf + ASSERT(current_node->GetNbPrimitives()==1); + // Get the primitive index from the input tree + udword PrimitiveIndex = current_node->GetPrimitives()[0]; + // Setup box data as the primitive index, marked as leaf + linear[box_id].mData = (PrimitiveIndex<<1)|1; + } + else + { + // To make the negative one implicit, we must store P and N in successive order + udword PosID = current_id++; // Get a new id for positive child + udword NegID = current_id++; // Get a new id for negative child + // Setup box data as the forthcoming new P pointer + linear[box_id].mData = (size_t)&linear[PosID]; + // Make sure it's not marked as leaf + ASSERT(!(linear[box_id].mData&1)); + // Recurse with new IDs + _BuildCollisionTree(linear, PosID, current_id, current_node->GetPos()); + _BuildCollisionTree(linear, NegID, current_id, current_node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds a "no-leaf" tree from a standard one. This is a tree whose leaf nodes have been removed. + * + * Layout for no-leaf trees: + * + * Node: + * - box + * - P pointer => a node (LSB=0) or a primitive (LSB=1) + * - N pointer => a node (LSB=0) or a primitive (LSB=1) + * + * \relates AABBNoLeafNode + * \fn _BuildNoLeafTree(AABBNoLeafNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) + * \param linear [in] base address of destination nodes + * \param box_id [in] index of destination node + * \param current_id [in] current running index + * \param current_node [in] current node from input tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +static void _BuildNoLeafTree(AABBNoLeafNode* linear, const udword box_id, udword& current_id, const AABBTreeNode* current_node) +{ + const AABBTreeNode* P = current_node->GetPos(); + const AABBTreeNode* N = current_node->GetNeg(); + // Leaf nodes here?! + ASSERT(P); + ASSERT(N); + // Internal node => keep the box + current_node->GetAABB()->GetCenter(linear[box_id].mAABB.mCenter); + current_node->GetAABB()->GetExtents(linear[box_id].mAABB.mExtents); + + if(P->IsLeaf()) + { + // The input tree must be complete => i.e. one primitive/leaf + ASSERT(P->GetNbPrimitives()==1); + // Get the primitive index from the input tree + udword PrimitiveIndex = P->GetPrimitives()[0]; + // Setup prev box data as the primitive index, marked as leaf + linear[box_id].mPosData = (PrimitiveIndex<<1)|1; + } + else + { + // Get a new id for positive child + udword PosID = current_id++; + // Setup box data + linear[box_id].mPosData = (size_t)&linear[PosID]; + // Make sure it's not marked as leaf + ASSERT(!(linear[box_id].mPosData&1)); + // Recurse + _BuildNoLeafTree(linear, PosID, current_id, P); + } + + if(N->IsLeaf()) + { + // The input tree must be complete => i.e. one primitive/leaf + ASSERT(N->GetNbPrimitives()==1); + // Get the primitive index from the input tree + udword PrimitiveIndex = N->GetPrimitives()[0]; + // Setup prev box data as the primitive index, marked as leaf + linear[box_id].mNegData = (PrimitiveIndex<<1)|1; + } + else + { + // Get a new id for negative child + udword NegID = current_id++; + // Setup box data + linear[box_id].mNegData = (size_t)&linear[NegID]; + // Make sure it's not marked as leaf + ASSERT(!(linear[box_id].mNegData&1)); + // Recurse + _BuildNoLeafTree(linear, NegID, current_id, N); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBCollisionTree::AABBCollisionTree() : mNodes(null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBCollisionTree::~AABBCollisionTree() +{ + DELETEARRAY(mNodes); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds the collision tree from a generic AABB tree. + * \param tree [in] generic AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBCollisionTree::Build(AABBTree* tree) +{ + // Checkings + if(!tree) return false; + // Check the input tree is complete + udword NbTriangles = tree->GetNbPrimitives(); + udword NbNodes = tree->GetNbNodes(); + if(NbNodes!=NbTriangles*2-1) return false; + + // Get nodes + if(mNbNodes!=NbNodes) // Same number of nodes => keep moving + { + mNbNodes = NbNodes; + DELETEARRAY(mNodes); + mNodes = new AABBCollisionNode[mNbNodes]; + CHECKALLOC(mNodes); + } + + // Build the tree + udword CurID = 1; + _BuildCollisionTree(mNodes, 0, CurID, tree); + ASSERT(CurID==mNbNodes); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the collision tree after vertices have been modified. + * \param mesh_interface [in] mesh interface for current model + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool AABBCollisionTree::Refit(const MeshInterface* mesh_interface) +// ericf change +bool AABBCollisionTree::Refit(MeshInterface* mesh_interface) +{ + ASSERT(!"Not implemented since AABBCollisionTrees have twice as more nodes to refit as AABBNoLeafTrees!"); + return false; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Walks the tree and call the user back for each node. + * \param callback [in] walking callback + * \param user_data [in] callback's user data + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBCollisionTree::Walk(GenericWalkingCallback callback, void* user_data) const +{ + if(!callback) return false; + + struct Local + { + static void _Walk(const AABBCollisionNode* current_node, GenericWalkingCallback callback, void* user_data) + { + if(!current_node || !(callback)(current_node, user_data)) return; + + if(!current_node->IsLeaf()) + { + _Walk(current_node->GetPos(), callback, user_data); + _Walk(current_node->GetNeg(), callback, user_data); + } + } + }; + Local::_Walk(mNodes, callback, user_data); + return true; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBNoLeafTree::AABBNoLeafTree() : mNodes(null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBNoLeafTree::~AABBNoLeafTree() +{ + DELETEARRAY(mNodes); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds the collision tree from a generic AABB tree. + * \param tree [in] generic AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBNoLeafTree::Build(AABBTree* tree) +{ + // Checkings + if(!tree) return false; + // Check the input tree is complete + udword NbTriangles = tree->GetNbPrimitives(); + udword NbNodes = tree->GetNbNodes(); + if(NbNodes!=NbTriangles*2-1) return false; + + // Get nodes + if(mNbNodes!=NbTriangles-1) // Same number of nodes => keep moving + { + mNbNodes = NbTriangles-1; + DELETEARRAY(mNodes); + mNodes = new AABBNoLeafNode[mNbNodes]; + CHECKALLOC(mNodes); + } + + // Build the tree + udword CurID = 1; + _BuildNoLeafTree(mNodes, 0, CurID, tree); + ASSERT(CurID==mNbNodes); + + return true; +} + +inline_ void ComputeMinMax(Point& min, Point& max, const VertexPointers& vp) +{ + // Compute triangle's AABB = a leaf box +#ifdef OPC_USE_FCOMI // a 15% speedup on my machine, not much + min.x = FCMin3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); + max.x = FCMax3(vp.Vertex[0]->x, vp.Vertex[1]->x, vp.Vertex[2]->x); + + min.y = FCMin3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); + max.y = FCMax3(vp.Vertex[0]->y, vp.Vertex[1]->y, vp.Vertex[2]->y); + + min.z = FCMin3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); + max.z = FCMax3(vp.Vertex[0]->z, vp.Vertex[1]->z, vp.Vertex[2]->z); +#else + min = *vp.Vertex[0]; + max = *vp.Vertex[0]; + min.Min(*vp.Vertex[1]); + max.Max(*vp.Vertex[1]); + min.Min(*vp.Vertex[2]); + max.Max(*vp.Vertex[2]); +#endif +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Refits the collision tree after vertices have been modified. + * \param mesh_interface [in] mesh interface for current model + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool AABBNoLeafTree::Refit(const MeshInterface* mesh_interface) +// ericf change +bool AABBNoLeafTree::Refit(MeshInterface* mesh_interface) +{ + // Checkings + if(!mesh_interface) return false; + + // Bottom-up update + VertexPointers VP; + Point Min,Max; + Point Min_,Max_; + udword Index = mNbNodes; + while(Index--) + { + AABBNoLeafNode& Current = mNodes[Index]; + + if(Current.HasPosLeaf()) + { + mesh_interface->GetTriangle(VP, Current.GetPosPrimitive()); + ComputeMinMax(Min, Max, VP); + } + else + { + const CollisionAABB& CurrentBox = Current.GetPos()->mAABB; + CurrentBox.GetMin(Min); + CurrentBox.GetMax(Max); + } + + if(Current.HasNegLeaf()) + { + mesh_interface->GetTriangle(VP, Current.GetNegPrimitive()); + ComputeMinMax(Min_, Max_, VP); + } + else + { + const CollisionAABB& CurrentBox = Current.GetNeg()->mAABB; + CurrentBox.GetMin(Min_); + CurrentBox.GetMax(Max_); + } +#ifdef OPC_USE_FCOMI + Min.x = FCMin2(Min.x, Min_.x); + Max.x = FCMax2(Max.x, Max_.x); + Min.y = FCMin2(Min.y, Min_.y); + Max.y = FCMax2(Max.y, Max_.y); + Min.z = FCMin2(Min.z, Min_.z); + Max.z = FCMax2(Max.z, Max_.z); +#else + Min.Min(Min_); + Max.Max(Max_); +#endif + Current.mAABB.SetMinMax(Min, Max); + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Walks the tree and call the user back for each node. + * \param callback [in] walking callback + * \param user_data [in] callback's user data + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBNoLeafTree::Walk(GenericWalkingCallback callback, void* user_data) const +{ + if(!callback) return false; + + struct Local + { + static void _Walk(const AABBNoLeafNode* current_node, GenericWalkingCallback callback, void* user_data) + { + if(!current_node || !(callback)(current_node, user_data)) return; + + if(!current_node->HasPosLeaf()) _Walk(current_node->GetPos(), callback, user_data); + if(!current_node->HasNegLeaf()) _Walk(current_node->GetNeg(), callback, user_data); + } + }; + Local::_Walk(mNodes, callback, user_data); + return true; +} + +// Quantization notes: +// - We could use the highest bits of mData to store some more quantized bits. Dequantization code +// would be slightly more complex, but number of overlap tests would be reduced (and anyhow those +// bits are currently wasted). Of course it's not possible if we move to 16 bits mData. +// - Something like "16 bits floats" could be tested, to bypass the int-to-float conversion. +// - A dedicated BV-BV test could be used, dequantizing while testing for overlap. (i.e. it's some +// lazy-dequantization which may save some work in case of early exits). At the very least some +// muls could be saved by precomputing several more matrices. But maybe not worth the pain. +// - Do we need to dequantize anyway? Not doing the extents-related muls only implies the box has +// been scaled, for example. +// - The deeper we move into the hierarchy, the smaller the extents should be. May not need a fixed +// number of quantization bits. Even better, could probably be best delta-encoded. + + +// Find max values. Some people asked why I wasn't simply using the first node. Well, I can't. +// I'm not looking for (min, max) values like in a standard AABB, I'm looking for the extremal +// centers/extents in order to quantize them. The first node would only give a single center and +// a single extents. While extents would be the biggest, the center wouldn't. +#define FIND_MAX_VALUES \ + /* Get max values */ \ + Point CMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \ + Point EMax(MIN_FLOAT, MIN_FLOAT, MIN_FLOAT); \ + for(udword i=0;iCMax.x) CMax.x = fabsf(Nodes[i].mAABB.mCenter.x); \ + if(fabsf(Nodes[i].mAABB.mCenter.y)>CMax.y) CMax.y = fabsf(Nodes[i].mAABB.mCenter.y); \ + if(fabsf(Nodes[i].mAABB.mCenter.z)>CMax.z) CMax.z = fabsf(Nodes[i].mAABB.mCenter.z); \ + if(fabsf(Nodes[i].mAABB.mExtents.x)>EMax.x) EMax.x = fabsf(Nodes[i].mAABB.mExtents.x); \ + if(fabsf(Nodes[i].mAABB.mExtents.y)>EMax.y) EMax.y = fabsf(Nodes[i].mAABB.mExtents.y); \ + if(fabsf(Nodes[i].mAABB.mExtents.z)>EMax.z) EMax.z = fabsf(Nodes[i].mAABB.mExtents.z); \ + } + +#define INIT_QUANTIZATION \ + udword nbc=15; /* Keep one bit for sign */ \ + udword nbe=15; /* Keep one bit for fix */ \ + if(!gFixQuantized) nbe++; \ + \ + /* Compute quantization coeffs */ \ + Point CQuantCoeff, EQuantCoeff; \ + CQuantCoeff.x = CMax.x!=0.0f ? float((1<Min[j]) mNodes[i].mAABB.mExtents[j]++; \ + else FixMe=false; \ + /* Prevent wrapping */ \ + if(!mNodes[i].mAABB.mExtents[j]) \ + { \ + mNodes[i].mAABB.mExtents[j]=0xffff; \ + FixMe=false; \ + } \ + }while(FixMe); \ + } \ + } + +#define REMAP_DATA(member) \ + /* Fix data */ \ + Data = Nodes[i].member; \ + if(!(Data&1)) \ + { \ + /* Compute box number */ \ + udword Nb = (Data - size_t(Nodes))/Nodes[i].GetNodeSize(); \ + Data = (size_t) &mNodes[Nb] ; \ + } \ + /* ...remapped */ \ + mNodes[i].member = Data; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBQuantizedTree::AABBQuantizedTree() : mNodes(null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBQuantizedTree::~AABBQuantizedTree() +{ + DELETEARRAY(mNodes); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds the collision tree from a generic AABB tree. + * \param tree [in] generic AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBQuantizedTree::Build(AABBTree* tree) +{ + // Checkings + if(!tree) return false; + // Check the input tree is complete + udword NbTriangles = tree->GetNbPrimitives(); + udword NbNodes = tree->GetNbNodes(); + if(NbNodes!=NbTriangles*2-1) return false; + + // Get nodes + mNbNodes = NbNodes; + DELETEARRAY(mNodes); + AABBCollisionNode* Nodes = new AABBCollisionNode[mNbNodes]; + CHECKALLOC(Nodes); + + // Build the tree + udword CurID = 1; + _BuildCollisionTree(Nodes, 0, CurID, tree); + + // Quantize + { + mNodes = new AABBQuantizedNode[mNbNodes]; + CHECKALLOC(mNodes); + + // Get max values + FIND_MAX_VALUES + + // Quantization + INIT_QUANTIZATION + + // Quantize + size_t Data; + for(udword i=0;iIsLeaf()) + { + _Walk(current_node->GetPos(), callback, user_data); + _Walk(current_node->GetNeg(), callback, user_data); + } + } + }; + Local::_Walk(mNodes, callback, user_data); + return true; +} + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBQuantizedNoLeafTree::AABBQuantizedNoLeafTree() : mNodes(null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +AABBQuantizedNoLeafTree::~AABBQuantizedNoLeafTree() +{ + DELETEARRAY(mNodes); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Builds the collision tree from a generic AABB tree. + * \param tree [in] generic AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBQuantizedNoLeafTree::Build(AABBTree* tree) +{ + // Checkings + if(!tree) return false; + // Check the input tree is complete + udword NbTriangles = tree->GetNbPrimitives(); + udword NbNodes = tree->GetNbNodes(); + if(NbNodes!=NbTriangles*2-1) return false; + + // Get nodes + mNbNodes = NbTriangles-1; + DELETEARRAY(mNodes); + AABBNoLeafNode* Nodes = new AABBNoLeafNode[mNbNodes]; + CHECKALLOC(Nodes); + + // Build the tree + udword CurID = 1; + _BuildNoLeafTree(Nodes, 0, CurID, tree); + ASSERT(CurID==mNbNodes); + + // Quantize + { + mNodes = new AABBQuantizedNoLeafNode[mNbNodes]; + CHECKALLOC(mNodes); + + // Get max values + FIND_MAX_VALUES + + // Quantization + INIT_QUANTIZATION + + // Quantize + size_t Data; + for(udword i=0;iHasPosLeaf()) _Walk(current_node->GetPos(), callback, user_data); + if(!current_node->HasNegLeaf()) _Walk(current_node->GetNeg(), callback, user_data); + } + }; + Local::_Walk(mNodes, callback, user_data); + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.h b/src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.h new file mode 100644 index 00000000..f8e7498a --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_OptimizedTree.h @@ -0,0 +1,209 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for optimized trees. + * \file OPC_OptimizedTree.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_OPTIMIZEDTREE_H__ +#define __OPC_OPTIMIZEDTREE_H__ + + //! Common interface for a node of an implicit tree + #define IMPLEMENT_IMPLICIT_NODE(base_class, volume) \ + public: \ + /* Constructor / Destructor */ \ + inline_ base_class() : mData(0) {} \ + inline_ ~base_class() {} \ + /* Leaf test */ \ + inline_ BOOL IsLeaf() const { return mData&1; } \ + /* Data access */ \ + inline_ const base_class* GetPos() const { return (base_class*)mData; } \ + inline_ const base_class* GetNeg() const { return ((base_class*)mData)+1; } \ + inline_ udword GetPrimitive() const { return (mData>>1); } \ + /* Stats */ \ + inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ + \ + volume mAABB; \ + size_t mData; + + //! Common interface for a node of a no-leaf tree + #define IMPLEMENT_NOLEAF_NODE(base_class, volume) \ + public: \ + /* Constructor / Destructor */ \ + inline_ base_class() : mPosData(0), mNegData(0) {} \ + inline_ ~base_class() {} \ + /* Leaf tests */ \ + inline_ BOOL HasPosLeaf() const { return mPosData&1; } \ + inline_ BOOL HasNegLeaf() const { return mNegData&1; } \ + /* Data access */ \ + inline_ const base_class* GetPos() const { return (base_class*)mPosData; } \ + inline_ const base_class* GetNeg() const { return (base_class*)mNegData; } \ + inline_ udword GetPosPrimitive() const { return (mPosData>>1); } \ + inline_ udword GetNegPrimitive() const { return (mNegData>>1); } \ + /* Stats */ \ + inline_ udword GetNodeSize() const { return SIZEOFOBJECT; } \ + \ + volume mAABB; \ + size_t mPosData; \ + size_t mNegData; + + class OPCODE_API AABBCollisionNode + { + IMPLEMENT_IMPLICIT_NODE(AABBCollisionNode, CollisionAABB) + + inline_ float GetVolume() const { return mAABB.mExtents.x * mAABB.mExtents.y * mAABB.mExtents.z; } + inline_ float GetSize() const { return mAABB.mExtents.SquareMagnitude(); } + inline_ udword GetRadius() const + { + udword* Bits = (udword*)&mAABB.mExtents.x; + udword Max = Bits[0]; + if(Bits[1]>Max) Max = Bits[1]; + if(Bits[2]>Max) Max = Bits[2]; + return Max; + } + + // NB: using the square-magnitude or the true volume of the box, seems to yield better results + // (assuming UNC-like informed traversal methods). I borrowed this idea from PQP. The usual "size" + // otherwise, is the largest box extent. In SOLID that extent is computed on-the-fly each time it's + // needed (the best approach IMHO). In RAPID the rotation matrix is permuted so that Extent[0] is + // always the greatest, which saves looking for it at runtime. On the other hand, it yields matrices + // whose determinant is not 1, i.e. you can't encode them anymore as unit quaternions. Not a very + // good strategy. + }; + + class OPCODE_API AABBQuantizedNode + { + IMPLEMENT_IMPLICIT_NODE(AABBQuantizedNode, QuantizedAABB) + + inline_ uword GetSize() const + { + const uword* Bits = mAABB.mExtents; + uword Max = Bits[0]; + if(Bits[1]>Max) Max = Bits[1]; + if(Bits[2]>Max) Max = Bits[2]; + return Max; + } + // NB: for quantized nodes I don't feel like computing a square-magnitude with integers all + // over the place.......! + }; + + class OPCODE_API AABBNoLeafNode + { + IMPLEMENT_NOLEAF_NODE(AABBNoLeafNode, CollisionAABB) + }; + + class OPCODE_API AABBQuantizedNoLeafNode + { + IMPLEMENT_NOLEAF_NODE(AABBQuantizedNoLeafNode, QuantizedAABB) + }; + + //! Common interface for a collision tree + #define IMPLEMENT_COLLISION_TREE(base_class, node) \ + public: \ + /* Constructor / Destructor */ \ + base_class(); \ + virtual ~base_class(); \ + /* Builds from a standard tree */ \ + override(AABBOptimizedTree) bool Build(AABBTree* tree); \ + /* Refits the tree */ \ + /*ericf change override(AABBOptimizedTree) bool Refit(const MeshInterface* mesh_interface);*/ \ + override(AABBOptimizedTree) bool Refit(MeshInterface* mesh_interface); \ + /* Walks the tree */ \ + override(AABBOptimizedTree) bool Walk(GenericWalkingCallback callback, void* user_data) const; \ + /* Data access */ \ + inline_ const node* GetNodes() const { return mNodes; } \ + /* Stats */ \ + override(AABBOptimizedTree) udword GetUsedBytes() const { return mNbNodes*sizeof(node); } \ + private: \ + node* mNodes; + + typedef bool (*GenericWalkingCallback) (const void* current, void* user_data); + + class OPCODE_API AABBOptimizedTree + { + public: + // Constructor / Destructor + AABBOptimizedTree() : + mNbNodes (0) + {} + virtual ~AABBOptimizedTree() {} + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Builds the collision tree from a generic AABB tree. + * \param tree [in] generic AABB tree + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual bool Build(AABBTree* tree) = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Refits the collision tree after vertices have been modified. + * \param mesh_interface [in] mesh interface for current model + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //virtual bool Refit(const MeshInterface* mesh_interface) = 0; + // ericf change + virtual bool Refit(MeshInterface* mesh_interface) = 0; + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Walks the tree and call the user back for each node. + * \param callback [in] walking callback + * \param user_data [in] callback's user data + * \return true if success + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + virtual bool Walk(GenericWalkingCallback callback, void* user_data) const = 0; + + // Data access + virtual udword GetUsedBytes() const = 0; + inline_ udword GetNbNodes() const { return mNbNodes; } + + protected: + udword mNbNodes; + }; + + class OPCODE_API AABBCollisionTree : public AABBOptimizedTree + { + IMPLEMENT_COLLISION_TREE(AABBCollisionTree, AABBCollisionNode) + }; + + class OPCODE_API AABBNoLeafTree : public AABBOptimizedTree + { + IMPLEMENT_COLLISION_TREE(AABBNoLeafTree, AABBNoLeafNode) + }; + + class OPCODE_API AABBQuantizedTree : public AABBOptimizedTree + { + IMPLEMENT_COLLISION_TREE(AABBQuantizedTree, AABBQuantizedNode) + + public: + Point mCenterCoeff; + Point mExtentsCoeff; + }; + + class OPCODE_API AABBQuantizedNoLeafTree : public AABBOptimizedTree + { + IMPLEMENT_COLLISION_TREE(AABBQuantizedNoLeafTree, AABBQuantizedNoLeafNode) + + public: + Point mCenterCoeff; + Point mExtentsCoeff; + }; + +#endif // __OPC_OPTIMIZEDTREE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Picking.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_Picking.cpp new file mode 100644 index 00000000..6b6f82b1 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Picking.cpp @@ -0,0 +1,190 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code to perform "picking". + * \file OPC_Picking.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +#ifdef OPC_RAYHIT_CALLBACK + +/* + Possible RayCollider usages: + - boolean query (shadow feeler) + - closest hit + - all hits + - number of intersection (boolean) + +*/ + +bool Opcode::SetupAllHits(RayCollider& collider, CollisionFaces& contacts) +{ + struct Local + { + static void AllContacts(const CollisionFace& hit, void* user_data) + { + CollisionFaces* CF = (CollisionFaces*)user_data; + CF->AddFace(hit); + } + }; + + collider.SetFirstContact(false); + collider.SetHitCallback(Local::AllContacts); + collider.SetUserData(&contacts); + return true; +} + +bool Opcode::SetupClosestHit(RayCollider& collider, CollisionFace& closest_contact) +{ + struct Local + { + static void ClosestContact(const CollisionFace& hit, void* user_data) + { + CollisionFace* CF = (CollisionFace*)user_data; + if(hit.mDistancemDistance) *CF = hit; + } + }; + + collider.SetFirstContact(false); + collider.SetHitCallback(Local::ClosestContact); + collider.SetUserData(&closest_contact); + closest_contact.mDistance = MAX_FLOAT; + return true; +} + +bool Opcode::SetupShadowFeeler(RayCollider& collider) +{ + collider.SetFirstContact(true); + collider.SetHitCallback(null); + return true; +} + +bool Opcode::SetupInOutTest(RayCollider& collider) +{ + collider.SetFirstContact(false); + collider.SetHitCallback(null); + // Results with collider.GetNbIntersections() + return true; +} + +bool Opcode::Picking( +CollisionFace& picked_face, +const Ray& world_ray, const Model& model, const Matrix4x4* world, +float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data) +{ + struct Local + { + struct CullData + { + CollisionFace* Closest; + float MinLimit; + CullModeCallback Callback; + void* UserData; + Point ViewPoint; + const MeshInterface* IMesh; + }; + + // Called for each stabbed face + static void RenderCullingCallback(const CollisionFace& hit, void* user_data) + { + CullData* Data = (CullData*)user_data; + + // Discard face if we already have a closer hit + if(hit.mDistance>=Data->Closest->mDistance) return; + + // Discard face if hit point is smaller than min limit. This mainly happens when the face is in front + // of the near clip plane (or straddles it). If we keep the face nonetheless, the user can select an + // object that he may not even be able to see, which is very annoying. + if(hit.mDistance<=Data->MinLimit) return; + + // This is the index of currently stabbed triangle. + udword StabbedFaceIndex = hit.mFaceID; + + // We may keep it or not, depending on backface culling + bool KeepIt = true; + + // Catch *render* cull mode for this face + CullMode CM = (Data->Callback)(StabbedFaceIndex, Data->UserData); + + if(CM!=CULLMODE_NONE) // Don't even compute culling for double-sided triangles + { + // Compute backface culling for current face + + VertexPointers VP; + Data->IMesh->GetTriangle(VP, StabbedFaceIndex); + if(VP.BackfaceCulling(Data->ViewPoint)) + { + if(CM==CULLMODE_CW) KeepIt = false; + } + else + { + if(CM==CULLMODE_CCW) KeepIt = false; + } + } + + if(KeepIt) *Data->Closest = hit; + } + }; + + RayCollider RC; + RC.SetMaxDist(max_dist); + RC.SetTemporalCoherence(false); + RC.SetCulling(false); // We need all faces since some of them can be double-sided + RC.SetFirstContact(false); + RC.SetHitCallback(Local::RenderCullingCallback); + + picked_face.mFaceID = INVALID_ID; + picked_face.mDistance = MAX_FLOAT; + picked_face.mU = 0.0f; + picked_face.mV = 0.0f; + + Local::CullData Data; + Data.Closest = &picked_face; + Data.MinLimit = min_dist; + Data.Callback = callback; + Data.UserData = user_data; + Data.ViewPoint = view_point; + Data.IMesh = model.GetMeshInterface(); + + if(world) + { + // Get matrices + Matrix4x4 InvWorld; + InvertPRMatrix(InvWorld, *world); + + // Compute camera position in mesh space + Data.ViewPoint *= InvWorld; + } + + RC.SetUserData(&Data); + if(RC.Collide(world_ray, model, world)) + { + return picked_face.mFaceID!=INVALID_ID; + } + return false; +} + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Picking.h b/src/external/open_dynamics_engine-ef/ode/OPC_Picking.h new file mode 100644 index 00000000..d22fa38a --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Picking.h @@ -0,0 +1,45 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code to perform "picking". + * \file OPC_Picking.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_PICKING_H__ +#define __OPC_PICKING_H__ + +#ifdef OPC_RAYHIT_CALLBACK + + enum CullMode + { + CULLMODE_NONE = 0, + CULLMODE_CW = 1, + CULLMODE_CCW = 2 + }; + + typedef CullMode (*CullModeCallback)(udword triangle_index, void* user_data); + + OPCODE_API bool SetupAllHits (RayCollider& collider, CollisionFaces& contacts); + OPCODE_API bool SetupClosestHit (RayCollider& collider, CollisionFace& closest_contact); + OPCODE_API bool SetupShadowFeeler (RayCollider& collider); + OPCODE_API bool SetupInOutTest (RayCollider& collider); + + OPCODE_API bool Picking( + CollisionFace& picked_face, + const Ray& world_ray, const Model& model, const Matrix4x4* world, + float min_dist, float max_dist, const Point& view_point, CullModeCallback callback, void* user_data); +#endif + +#endif //__OPC_PICKING_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_PlanesAABBOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_PlanesAABBOverlap.h new file mode 100644 index 00000000..5d7576e5 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_PlanesAABBOverlap.h @@ -0,0 +1,50 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Planes-AABB overlap test. + * - original code by Ville Miettinen, from Umbra/dPVS (released on the GD-Algorithms mailing list) + * - almost used "as-is", I even left the comments (hence the frustum-related notes) + * + * \param center [in] box center + * \param extents [in] box extents + * \param out_clip_mask [out] bitmask for active planes + * \param in_clip_mask [in] bitmask for active planes + * \return TRUE if boxes overlap planes + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL PlanesCollider::PlanesAABBOverlap(const Point& center, const Point& extents, udword& out_clip_mask, udword in_clip_mask) +{ + // Stats + mNbVolumeBVTests++; + + const Plane* p = mPlanes; + + // Evaluate through all active frustum planes. We determine the relation + // between the AABB and a plane by using the concept of "near" and "far" + // vertices originally described by Zhang (and later by Möller). Our + // variant here uses 3 fabs ops, 6 muls, 7 adds and two floating point + // comparisons per plane. The routine early-exits if the AABB is found + // to be outside any of the planes. The loop also constructs a new output + // clip mask. Most FPUs have a native single-cycle fabsf() operation. + + udword Mask = 1; // current mask index (1,2,4,8,..) + udword TmpOutClipMask = 0; // initialize output clip mask into empty. + + while(Mask<=in_clip_mask) // keep looping while we have active planes left... + { + if(in_clip_mask & Mask) // if clip plane is active, process it.. + { + float NP = extents.x*fabsf(p->n.x) + extents.y*fabsf(p->n.y) + extents.z*fabsf(p->n.z); // ### fabsf could be precomputed + float MP = center.x*p->n.x + center.y*p->n.y + center.z*p->n.z + p->d; + + if(NP < MP) // near vertex behind the clip plane... + return FALSE; // .. so there is no intersection.. + if((-NP) < MP) // near and far vertices on different sides of plane.. + TmpOutClipMask |= Mask; // .. so update the clip mask... + } + Mask+=Mask; // mk = (1<Add(prim_index); + +//! Planes-triangle test +#define PLANES_PRIM(prim_index, flag) \ + /* Request vertices from the app */ \ + mIMesh->GetTriangle(mVP, prim_index); \ + /* Perform triangle-box overlap test */ \ + if(PlanesTriOverlap(clip_mask)) \ + { \ + SET_CONTACT(prim_index, flag) \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +PlanesCollider::PlanesCollider() : + mNbPlanes (0), + mPlanes (null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +PlanesCollider::~PlanesCollider() +{ + DELETEARRAY(mPlanes); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Validates current settings. You should call this method after all the settings and callbacks have been defined. + * \return null if everything is ok, else a string describing the problem + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const char* PlanesCollider::ValidateSettings() +{ + if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; + + return VolumeCollider::ValidateSettings(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a planes cache + * \param planes [in] list of planes in world space + * \param nb_planes [in] number of planes + * \param model [in] Opcode model to collide with + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool PlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const Model& model, const Matrix4x4* worldm) +// ericf change +bool PlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, Model& model, const Matrix4x4* worldm) +{ + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, planes, nb_planes, worldm)) return true; + + udword PlaneMask = (1<mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + else _Collide(Tree->GetNodes(), PlaneMask); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + else _Collide(Tree->GetNodes(), PlaneMask); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + else _Collide(Tree->GetNodes(), PlaneMask); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + else _Collide(Tree->GetNodes(), PlaneMask); + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a collision query : + * - reset stats & contact status + * - compute planes in model space + * - check temporal coherence + * + * \param cache [in/out] a planes cache + * \param planes [in] list of planes + * \param nb_planes [in] number of planes + * \param worldm [in] model's world matrix, or null + * \return TRUE if we can return immediately + * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL PlanesCollider::InitQuery(PlanesCache& cache, const Plane* planes, udword nb_planes, const Matrix4x4* worldm) +{ + // 1) Call the base method + VolumeCollider::InitQuery(); + + // 2) Compute planes in model space + if(nb_planes>mNbPlanes) + { + DELETEARRAY(mPlanes); + mPlanes = new Plane[nb_planes]; + } + mNbPlanes = nb_planes; + + if(worldm) + { + Matrix4x4 InvWorldM; + InvertPRMatrix(InvWorldM, *worldm); + +// for(udword i=0;iHasSingleNode()) + { + if(!SkipPrimitiveTests()) + { + // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. + mTouchedPrimitives->Reset(); + + // Perform overlap test between the unique triangle and the planes (and set contact status if needed) + udword clip_mask = (1< check results from previous frame before performing the collision query + if(FirstContactEnabled()) + { + // We're only interested in the first contact found => test the unique previously touched face + if(mTouchedPrimitives->GetNbEntries()) + { + // Get index of previously touched face = the first entry in the array + udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); + + // Then reset the array: + // - if the overlap test below is successful, the index we'll get added back anyway + // - if it isn't, then the array should be reset anyway for the normal query + mTouchedPrimitives->Reset(); + + // Perform overlap test between the cached triangle and the planes (and set contact status if needed) + udword clip_mask = (1< we'll have to perform a normal query + } + else mTouchedPrimitives->Reset(); + } + else + { + // Here we don't use temporal coherence => do a normal query + mTouchedPrimitives->Reset(); + } + + return FALSE; +} + +#define TEST_CLIP_MASK \ + /* If the box is completely included, so are its children. We don't need to do extra tests, we */ \ + /* can immediately output a list of visible children. Those ones won't need to be clipped. */ \ + if(!OutClipMask) \ + { \ + /* Set contact status */ \ + mFlags |= OPC_CONTACT; \ + _Dump(node); \ + return; \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_Collide(const AABBCollisionNode* node, udword clip_mask) +{ + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->IsLeaf()) + { + PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + _Collide(node->GetNeg(), OutClipMask); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node, udword clip_mask) +{ + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_Collide(const AABBQuantizedNode* node, udword clip_mask) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->IsLeaf()) + { + PLANES_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + _Collide(node->GetNeg(), OutClipMask); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node, udword clip_mask) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_Collide(const AABBNoLeafNode* node, udword clip_mask) +{ + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->HasPosLeaf()) { PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg(), OutClipMask); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node, udword clip_mask) +{ + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_Collide(const AABBQuantizedNoLeafNode* node, udword clip_mask) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->HasPosLeaf()) { PLANES_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { PLANES_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg(), OutClipMask); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void PlanesCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node, udword clip_mask) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Test the box against the planes. If the box is completely culled, so are its children, hence we exit. + udword OutClipMask; + if(!PlanesAABBOverlap(Center, Extents, OutClipMask, clip_mask)) return; + + TEST_CLIP_MASK + + // Else the box straddles one or several planes, so we need to recurse down the tree. + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos(), OutClipMask); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg(), OutClipMask); +} + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridPlanesCollider::HybridPlanesCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridPlanesCollider::~HybridPlanesCollider() +{ +} + +//bool HybridPlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, const HybridModel& model, const Matrix4x4* worldm) +// ericf change +bool HybridPlanesCollider::Collide(PlanesCache& cache, const Plane* planes, udword nb_planes, HybridModel& model, const Matrix4x4* worldm) +{ + // We don't want primitive tests here! + mFlags |= OPC_NO_PRIMITIVE_TESTS; + + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, planes, nb_planes, worldm)) return true; + + // Special case for 1-leaf trees + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles + udword Nb = mIMesh->GetNbTriangles(); + + // Loop through all triangles + udword clip_mask = (1<mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes(), PlaneMask); + } + } + + // We only have a list of boxes so far + if(GetContactStatus()) + { + // Reset contact status, since it currently only reflects collisions with leaf boxes + Collider::InitQuery(); + + // Change dest container so that we can use built-in overlap tests and get collided primitives + cache.TouchedPrimitives.Reset(); + mTouchedPrimitives = &cache.TouchedPrimitives; + + // Read touched leaf boxes + udword Nb = mTouchedBoxes.GetNbEntries(); + const udword* Touched = mTouchedBoxes.GetEntries(); + + const LeafTriangles* LT = model.GetLeafTriangles(); + const udword* Indices = model.GetIndices(); + + // Loop through touched leaves + udword clip_mask = (1<Distance(*mVP.Vertex[0]); + float d1 = p->Distance(*mVP.Vertex[1]); + float d2 = p->Distance(*mVP.Vertex[2]); + if(d0>0.0f && d1>0.0f && d2>0.0f) return FALSE; +// if(!(IR(d0)&SIGN_BITMASK) && !(IR(d1)&SIGN_BITMASK) && !(IR(d2)&SIGN_BITMASK)) return FALSE; + } + Mask+=Mask; + p++; + } +/* + for(udword i=0;i<6;i++) + { + float d0 = p[i].Distance(mLeafVerts[0]); + float d1 = p[i].Distance(mLeafVerts[1]); + float d2 = p[i].Distance(mLeafVerts[2]); + if(d0>0.0f && d1>0.0f && d2>0.0f) return false; + } +*/ + return TRUE; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_RayAABBOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_RayAABBOverlap.h new file mode 100644 index 00000000..a8162bf0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_RayAABBOverlap.h @@ -0,0 +1,63 @@ +// Opcode 1.1: ray-AABB overlap tests based on Woo's code +// Opcode 1.2: ray-AABB overlap tests based on the separating axis theorem +// +// The point of intersection is not computed anymore. The distance to impact is not needed anymore +// since we now have two different queries for segments or rays. + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes a segment-AABB overlap test using the separating axis theorem. Segment is cached within the class. + * \param center [in] AABB center + * \param extents [in] AABB extents + * \return true on overlap + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL RayCollider::SegmentAABBOverlap(const Point& center, const Point& extents) +{ + // Stats + mNbRayBVTests++; + + float Dx = mData2.x - center.x; if(fabsf(Dx) > extents.x + mFDir.x) return FALSE; + float Dy = mData2.y - center.y; if(fabsf(Dy) > extents.y + mFDir.y) return FALSE; + float Dz = mData2.z - center.z; if(fabsf(Dz) > extents.z + mFDir.z) return FALSE; + + float f; + f = mData.y * Dz - mData.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE; + f = mData.z * Dx - mData.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE; + f = mData.x * Dy - mData.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE; + + return TRUE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes a ray-AABB overlap test using the separating axis theorem. Ray is cached within the class. + * \param center [in] AABB center + * \param extents [in] AABB extents + * \return true on overlap + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL RayCollider::RayAABBOverlap(const Point& center, const Point& extents) +{ + // Stats + mNbRayBVTests++; + +// float Dx = mOrigin.x - center.x; if(fabsf(Dx) > extents.x && Dx*mDir.x>=0.0f) return FALSE; +// float Dy = mOrigin.y - center.y; if(fabsf(Dy) > extents.y && Dy*mDir.y>=0.0f) return FALSE; +// float Dz = mOrigin.z - center.z; if(fabsf(Dz) > extents.z && Dz*mDir.z>=0.0f) return FALSE; + + float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && Dx*mDir.x>=0.0f) return FALSE; + float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && Dy*mDir.y>=0.0f) return FALSE; + float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && Dz*mDir.z>=0.0f) return FALSE; + +// float Dx = mOrigin.x - center.x; if(GREATER(Dx, extents.x) && ((SIR(Dx)-1)^SIR(mDir.x))>=0.0f) return FALSE; +// float Dy = mOrigin.y - center.y; if(GREATER(Dy, extents.y) && ((SIR(Dy)-1)^SIR(mDir.y))>=0.0f) return FALSE; +// float Dz = mOrigin.z - center.z; if(GREATER(Dz, extents.z) && ((SIR(Dz)-1)^SIR(mDir.z))>=0.0f) return FALSE; + + float f; + f = mDir.y * Dz - mDir.z * Dy; if(fabsf(f) > extents.y*mFDir.z + extents.z*mFDir.y) return FALSE; + f = mDir.z * Dx - mDir.x * Dz; if(fabsf(f) > extents.x*mFDir.z + extents.z*mFDir.x) return FALSE; + f = mDir.x * Dy - mDir.y * Dx; if(fabsf(f) > extents.x*mFDir.y + extents.y*mFDir.x) return FALSE; + + return TRUE; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.cpp new file mode 100644 index 00000000..dc28b982 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.cpp @@ -0,0 +1,777 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a ray collider. + * \file OPC_RayCollider.cpp + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a ray-vs-tree collider. + * This class performs a stabbing query on an AABB tree, i.e. does a ray-mesh collision. + * + * HIGHER DISTANCE BOUND: + * + * If P0 and P1 are two 3D points, let's define: + * - d = distance between P0 and P1 + * - Origin = P0 + * - Direction = (P1 - P0) / d = normalized direction vector + * - A parameter t such as a point P on the line (P0,P1) is P = Origin + t * Direction + * - t = 0 --> P = P0 + * - t = d --> P = P1 + * + * Then we can define a general "ray" as: + * + * struct Ray + * { + * Point Origin; + * Point Direction; + * }; + * + * But it actually maps three different things: + * - a segment, when 0 <= t <= d + * - a half-line, when 0 <= t < +infinity, or -infinity < t <= d + * - a line, when -infinity < t < +infinity + * + * In Opcode, we support segment queries, which yield half-line queries by setting d = +infinity. + * We don't support line-queries. If you need them, shift the origin along the ray by an appropriate margin. + * + * In short, the lower bound is always 0, and you can setup the higher bound "d" with RayCollider::SetMaxDist(). + * + * Query |segment |half-line |line + * --------|-------------------|---------------|---------------- + * Usages |-shadow feelers |-raytracing |- + * |-sweep tests |-in/out tests | + * + * FIRST CONTACT: + * + * - You can setup "first contact" mode or "all contacts" mode with RayCollider::SetFirstContact(). + * - In "first contact" mode we return as soon as the ray hits one face. If can be useful e.g. for shadow feelers, where + * you want to know whether the path to the light is free or not (a boolean answer is enough). + * - In "all contacts" mode we return all faces hit by the ray. + * + * TEMPORAL COHERENCE: + * + * - You can enable or disable temporal coherence with RayCollider::SetTemporalCoherence(). + * - It currently only works in "first contact" mode. + * - If temporal coherence is enabled, the previously hit triangle is cached during the first query. Then, next queries + * start by colliding the ray against the cached triangle. If they still collide, we return immediately. + * + * CLOSEST HIT: + * + * - You can enable or disable "closest hit" with RayCollider::SetClosestHit(). + * - It currently only works in "all contacts" mode. + * - If closest hit is enabled, faces are sorted by distance on-the-fly and the closest one only is reported. + * + * BACKFACE CULLING: + * + * - You can enable or disable backface culling with RayCollider::SetCulling(). + * - If culling is enabled, ray will not hit back faces (only front faces). + * + * + * + * \class RayCollider + * \author Pierre Terdiman + * \version 1.3 + * \date June, 2, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * This class describes a face hit by a ray or segment. + * This is a particular class dedicated to stabbing queries. + * + * \class CollisionFace + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * This class is a dedicated collection of CollisionFace. + * + * \class CollisionFaces + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +#include "ode/OPC_RayAABBOverlap.h" +#include "ode/OPC_RayTriOverlap.h" + +#define SET_CONTACT(prim_index, flag) \ + mNbIntersections++; \ + /* Set contact status */ \ + mFlags |= flag; \ + /* In any case the contact has been found and recorded in mStabbedFace */ \ + mStabbedFace.mFaceID = prim_index; + +#ifdef OPC_RAYHIT_CALLBACK + + #define HANDLE_CONTACT(prim_index, flag) \ + SET_CONTACT(prim_index, flag) \ + \ + if(mHitCallback) (mHitCallback)(mStabbedFace, mUserData); + + #define UPDATE_CACHE \ + if(cache && GetContactStatus()) \ + { \ + *cache = mStabbedFace.mFaceID; \ + } +#else + + #define HANDLE_CONTACT(prim_index, flag) \ + SET_CONTACT(prim_index, flag) \ + \ + /* Now we can also record it in mStabbedFaces if available */ \ + if(mStabbedFaces) \ + { \ + /* If we want all faces or if that's the first one we hit */ \ + if(!mClosestHit || !mStabbedFaces->GetNbFaces()) \ + { \ + mStabbedFaces->AddFace(mStabbedFace); \ + } \ + else \ + { \ + /* We only keep closest hit */ \ + CollisionFace* Current = const_cast(mStabbedFaces->GetFaces()); \ + if(Current && mStabbedFace.mDistancemDistance) \ + { \ + *Current = mStabbedFace; \ + } \ + } \ + } + + #define UPDATE_CACHE \ + if(cache && GetContactStatus() && mStabbedFaces) \ + { \ + const CollisionFace* Current = mStabbedFaces->GetFaces(); \ + if(Current) *cache = Current->mFaceID; \ + else *cache = INVALID_ID; \ + } +#endif + +#define SEGMENT_PRIM(prim_index, flag) \ + /* Request vertices from the app */ \ + VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \ + \ + /* Perform ray-tri overlap test and return */ \ + if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ + { \ + /* Intersection point is valid if dist < segment's length */ \ + /* We know dist>0 so we can use integers */ \ + if(IR(mStabbedFace.mDistance)GetTriangle(VP, prim_index); \ + \ + /* Perform ray-tri overlap test and return */ \ + if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ + { \ + HANDLE_CONTACT(prim_index, flag) \ + } + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RayCollider::RayCollider() : + +#ifdef OPC_RAYHIT_CALLBACK + mNbRayBVTests (0), + mNbRayPrimTests (0), + mNbIntersections (0), + mMaxDist (MAX_FLOAT), + mHitCallback (null), + mUserData (0), +#else + mStabbedFaces (null), + mNbRayBVTests (0), + mNbRayPrimTests (0), + mNbIntersections (0), + mMaxDist (MAX_FLOAT), + mClosestHit (false), +#endif + mCulling (true) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +RayCollider::~RayCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Validates current settings. You should call this method after all the settings and callbacks have been defined. + * \return null if everything is ok, else a string describing the problem + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +const char* RayCollider::ValidateSettings() +{ + if(mMaxDist<0.0f) return "Higher distance bound must be positive!"; + if(TemporalCoherenceEnabled() && !FirstContactEnabled()) return "Temporal coherence only works with ""First contact"" mode!"; +#ifndef OPC_RAYHIT_CALLBACK + if(mClosestHit && FirstContactEnabled()) return "Closest hit doesn't work with ""First contact"" mode!"; + if(TemporalCoherenceEnabled() && mClosestHit) return "Temporal coherence can't guarantee to report closest hit!"; +#endif + if(SkipPrimitiveTests()) return "SkipPrimitiveTests not possible for RayCollider ! (not implemented)"; + return null; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Generic stabbing query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - in the user-provided destination array + * + * \param world_ray [in] stabbing ray in world space + * \param model [in] Opcode model to collide with + * \param world [in] model's world matrix, or null + * \param cache [in] a possibly cached face index, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool RayCollider::Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world, udword* cache) +// ericf change +bool RayCollider::Collide(const Ray& world_ray, Model& model, const Matrix4x4* world, udword* cache) +{ + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(world_ray, world, cache)) return true; + + if(!model.HasLeafNodes()) + { + if(model.IsQuantized()) + { + const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform stabbing query + if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); + else _RayStab(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform stabbing query + if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); + else _RayStab(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform stabbing query + if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); + else _RayStab(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform stabbing query + if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(Tree->GetNodes()); + else _RayStab(Tree->GetNodes()); + } + } + + // Update cache if needed + UPDATE_CACHE + return true; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a stabbing query : + * - reset stats & contact status + * - compute ray in local space + * - check temporal coherence + * + * \param world_ray [in] stabbing ray in world space + * \param world [in] object's world matrix, or null + * \param face_id [in] index of previously stabbed triangle + * \return TRUE if we can return immediately + * \warning SCALE NOT SUPPORTED. The matrix must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL RayCollider::InitQuery(const Ray& world_ray, const Matrix4x4* world, udword* face_id) +{ + // Reset stats & contact status + Collider::InitQuery(); + mNbRayBVTests = 0; + mNbRayPrimTests = 0; + mNbIntersections = 0; +#ifndef OPC_RAYHIT_CALLBACK + if(mStabbedFaces) mStabbedFaces->Reset(); +#endif + + // Compute ray in local space + // The (Origin/Dir) form is needed for the ray-triangle test anyway (even for segment tests) + if(world) + { + Matrix3x3 InvWorld = *world; + mDir = InvWorld * world_ray.mDir; + + Matrix4x4 World; + InvertPRMatrix(World, *world); + mOrigin = world_ray.mOrig * World; + } + else + { + mDir = world_ray.mDir; + mOrigin = world_ray.mOrig; + } + + // 4) Special case: 1-triangle meshes [Opcode 1.3] + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. + if(!SkipPrimitiveTests()) + { + // Perform overlap test between the unique triangle and the ray (and set contact status if needed) + SEGMENT_PRIM(udword(0), OPC_CONTACT) + + // Return immediately regardless of status + return TRUE; + } + } + + // Check temporal coherence : + + // Test previously colliding primitives first + if(TemporalCoherenceEnabled() && FirstContactEnabled() && face_id && *face_id!=INVALID_ID) + { +#ifdef OLD_CODE +#ifndef OPC_RAYHIT_CALLBACK + if(!mClosestHit) +#endif + { + // Request vertices from the app + VertexPointers VP; + mIMesh->GetTriangle(VP, *face_id); + // Perform ray-cached tri overlap test + if(RayTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) + { + // Intersection point is valid if: + // - distance is positive (else it can just be a face behind the orig point) + // - distance is smaller than a given max distance (useful for shadow feelers) +// if(mStabbedFace.mDistance>0.0f && mStabbedFace.mDistanceAddFace(mStabbedFace); +#endif + return TRUE; + } + } + } +#else + // New code + // We handle both Segment/ray queries with the same segment code, and a possible infinite limit + SEGMENT_PRIM(*face_id, OPC_TEMPORAL_CONTACT) + + // Return immediately if possible + if(GetContactStatus()) return TRUE; +#endif + } + + // Precompute data (moved after temporal coherence since only needed for ray-AABB) + if(IR(mMaxDist)!=IEEE_MAX_FLOAT) + { + // For Segment-AABB overlap + mData = 0.5f * mDir * mMaxDist; + mData2 = mOrigin + mData; + + // Precompute mFDir; + mFDir.x = fabsf(mData.x); + mFDir.y = fabsf(mData.y); + mFDir.z = fabsf(mData.z); + } + else + { + // For Ray-AABB overlap +// udword x = SIR(mDir.x)-1; +// udword y = SIR(mDir.y)-1; +// udword z = SIR(mDir.z)-1; +// mData.x = FR(x); +// mData.y = FR(y); +// mData.z = FR(z); + + // Precompute mFDir; + mFDir.x = fabsf(mDir.x); + mFDir.y = fabsf(mDir.y); + mFDir.z = fabsf(mDir.z); + } + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Stabbing query for vanilla AABB trees. + * \param world_ray [in] stabbing ray in world space + * \param tree [in] AABB tree + * \param box_indices [out] indices of stabbed boxes + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool RayCollider::Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices) +{ + // ### bad design here + + // This is typically called for a scene tree, full of -AABBs-, not full of triangles. + // So we don't really have "primitives" to deal with. Hence it doesn't work with + // "FirstContact" + "TemporalCoherence". + ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); + + // Checkings + if(!tree) return false; + + // Init collision query + // Basically this is only called to initialize precomputed data + if(InitQuery(world_ray)) return true; + + // Perform stabbing query + if(IR(mMaxDist)!=IEEE_MAX_FLOAT) _SegmentStab(tree, box_indices); + else _RayStab(tree, box_indices); + + return true; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_SegmentStab(const AABBCollisionNode* node) +{ + // Perform Segment-AABB overlap test + if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + if(node->IsLeaf()) + { + SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _SegmentStab(node->GetPos()); + + if(ContactFound()) return; + + _SegmentStab(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_SegmentStab(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Segment-AABB overlap test + if(!SegmentAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf()) + { + SEGMENT_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _SegmentStab(node->GetPos()); + + if(ContactFound()) return; + + _SegmentStab(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_SegmentStab(const AABBNoLeafNode* node) +{ + // Perform Segment-AABB overlap test + if(!SegmentAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + if(node->HasPosLeaf()) + { + SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT) + } + else _SegmentStab(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) + { + SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT) + } + else _SegmentStab(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_SegmentStab(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Segment-AABB overlap test + if(!SegmentAABBOverlap(Center, Extents)) return; + + if(node->HasPosLeaf()) + { + SEGMENT_PRIM(node->GetPosPrimitive(), OPC_CONTACT) + } + else _SegmentStab(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) + { + SEGMENT_PRIM(node->GetNegPrimitive(), OPC_CONTACT) + } + else _SegmentStab(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for vanilla AABB trees. + * \param node [in] current collision node + * \param box_indices [out] indices of stabbed boxes + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_SegmentStab(const AABBTreeNode* node, Container& box_indices) +{ + // Test the box against the segment + Point Center, Extents; + node->GetAABB()->GetCenter(Center); + node->GetAABB()->GetExtents(Extents); + if(!SegmentAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf()) + { + box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives()); + } + else + { + _SegmentStab(node->GetPos(), box_indices); + _SegmentStab(node->GetNeg(), box_indices); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_RayStab(const AABBCollisionNode* node) +{ + // Perform Ray-AABB overlap test + if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + if(node->IsLeaf()) + { + RAY_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _RayStab(node->GetPos()); + + if(ContactFound()) return; + + _RayStab(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_RayStab(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Ray-AABB overlap test + if(!RayAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf()) + { + RAY_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _RayStab(node->GetPos()); + + if(ContactFound()) return; + + _RayStab(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_RayStab(const AABBNoLeafNode* node) +{ + // Perform Ray-AABB overlap test + if(!RayAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + if(node->HasPosLeaf()) + { + RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT) + } + else _RayStab(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) + { + RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT) + } + else _RayStab(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_RayStab(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Ray-AABB overlap test + if(!RayAABBOverlap(Center, Extents)) return; + + if(node->HasPosLeaf()) + { + RAY_PRIM(node->GetPosPrimitive(), OPC_CONTACT) + } + else _RayStab(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) + { + RAY_PRIM(node->GetNegPrimitive(), OPC_CONTACT) + } + else _RayStab(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive stabbing query for vanilla AABB trees. + * \param node [in] current collision node + * \param box_indices [out] indices of stabbed boxes + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void RayCollider::_RayStab(const AABBTreeNode* node, Container& box_indices) +{ + // Test the box against the ray + Point Center, Extents; + node->GetAABB()->GetCenter(Center); + node->GetAABB()->GetExtents(Extents); + if(!RayAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf()) + { + mFlags |= OPC_CONTACT; + box_indices.Add(node->GetPrimitives(), node->GetNbPrimitives()); + } + else + { + _RayStab(node->GetPos(), box_indices); + _RayStab(node->GetNeg(), box_indices); + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.h new file mode 100644 index 00000000..fe65d77e --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_RayCollider.h @@ -0,0 +1,227 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a ray collider. + * \file OPC_RayCollider.h + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_RAYCOLLIDER_H__ +#define __OPC_RAYCOLLIDER_H__ + + class OPCODE_API CollisionFace + { + public: + //! Constructor + inline_ CollisionFace() {} + //! Destructor + inline_ ~CollisionFace() {} + + udword mFaceID; //!< Index of touched face + float mDistance; //!< Distance from collider to hitpoint + float mU, mV; //!< Impact barycentric coordinates + }; + + class OPCODE_API CollisionFaces : private Container + { + public: + //! Constructor + CollisionFaces() {} + //! Destructor + ~CollisionFaces() {} + + inline_ udword GetNbFaces() const { return GetNbEntries()>>2; } + inline_ const CollisionFace* GetFaces() const { return (const CollisionFace*)GetEntries(); } + + inline_ void Reset() { Container::Reset(); } + + inline_ void AddFace(const CollisionFace& face) { Add(face.mFaceID).Add(face.mDistance).Add(face.mU).Add(face.mV); } + }; + +#ifdef OPC_RAYHIT_CALLBACK + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * User-callback, called by OPCODE to record a hit. + * \param hit [in] current hit + * \param user_data [in] user-defined data from SetCallback() + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + typedef void (*HitCallback) (const CollisionFace& hit, void* user_data); +#endif + + class OPCODE_API RayCollider : public Collider + { + public: + // Constructor / Destructor + RayCollider(); + virtual ~RayCollider(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Generic stabbing query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - in the user-provided destination array + * + * \param world_ray [in] stabbing ray in world space + * \param model [in] Opcode model to collide with + * \param world [in] model's world matrix, or null + * \param cache [in] a possibly cached face index, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //bool Collide(const Ray& world_ray, const Model& model, const Matrix4x4* world=null, udword* cache=null); + // ericf + bool Collide(const Ray& world_ray, Model& model, const Matrix4x4* world=null, udword* cache=null); + // + bool Collide(const Ray& world_ray, const AABBTree* tree, Container& box_indices); + // Settings + +#ifndef OPC_RAYHIT_CALLBACK + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: enable or disable "closest hit" mode. + * \param flag [in] true to report closest hit only + * \see SetCulling(bool flag) + * \see SetMaxDist(float max_dist) + * \see SetDestination(StabbedFaces* sf) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetClosestHit(bool flag) { mClosestHit = flag; } +#endif + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: enable or disable backface culling. + * \param flag [in] true to enable backface culling + * \see SetClosestHit(bool flag) + * \see SetMaxDist(float max_dist) + * \see SetDestination(StabbedFaces* sf) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetCulling(bool flag) { mCulling = flag; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: sets the higher distance bound. + * \param max_dist [in] higher distance bound. Default = maximal value, for ray queries (else segment) + * \see SetClosestHit(bool flag) + * \see SetCulling(bool flag) + * \see SetDestination(StabbedFaces* sf) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetMaxDist(float max_dist=MAX_FLOAT) { mMaxDist = max_dist; } + +#ifdef OPC_RAYHIT_CALLBACK + inline_ void SetHitCallback(HitCallback cb) { mHitCallback = cb; } + inline_ void SetUserData(void* user_data) { mUserData = user_data; } +#else + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: sets the destination array for stabbed faces. + * \param cf [in] destination array, filled during queries + * \see SetClosestHit(bool flag) + * \see SetCulling(bool flag) + * \see SetMaxDist(float max_dist) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetDestination(CollisionFaces* cf) { mStabbedFaces = cf; } +#endif + // Stats + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of Ray-BV overlap tests after a collision query. + * \see GetNbRayPrimTests() + * \see GetNbIntersections() + * \return the number of Ray-BV tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbRayBVTests() const { return mNbRayBVTests; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of Ray-Triangle overlap tests after a collision query. + * \see GetNbRayBVTests() + * \see GetNbIntersections() + * \return the number of Ray-Triangle tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbRayPrimTests() const { return mNbRayPrimTests; } + + // In-out test + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of intersection found after a collision query. Can be used for in/out tests. + * \see GetNbRayBVTests() + * \see GetNbRayPrimTests() + * \return the number of valid intersections during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbIntersections() const { return mNbIntersections; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider. + * \return null if everything is ok, else a string describing the problem + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(Collider) const char* ValidateSettings(); + + protected: + // Ray in local space + Point mOrigin; //!< Ray origin + Point mDir; //!< Ray direction (normalized) + Point mFDir; //!< fabsf(mDir) + Point mData, mData2; + // Stabbed faces + CollisionFace mStabbedFace; //!< Current stabbed face +#ifdef OPC_RAYHIT_CALLBACK + HitCallback mHitCallback; //!< Callback used to record a hit + void* mUserData; //!< User-defined data +#else + CollisionFaces* mStabbedFaces; //!< List of stabbed faces +#endif + // Stats + udword mNbRayBVTests; //!< Number of Ray-BV tests + udword mNbRayPrimTests; //!< Number of Ray-Primitive tests + // In-out test + udword mNbIntersections; //!< Number of valid intersections + // Dequantization coeffs + Point mCenterCoeff; + Point mExtentsCoeff; + // Settings + float mMaxDist; //!< Valid segment on the ray +#ifndef OPC_RAYHIT_CALLBACK + bool mClosestHit; //!< Report closest hit only +#endif + bool mCulling; //!< Stab culled faces or not + // Internal methods + void _SegmentStab(const AABBCollisionNode* node); + void _SegmentStab(const AABBNoLeafNode* node); + void _SegmentStab(const AABBQuantizedNode* node); + void _SegmentStab(const AABBQuantizedNoLeafNode* node); + void _SegmentStab(const AABBTreeNode* node, Container& box_indices); + void _RayStab(const AABBCollisionNode* node); + void _RayStab(const AABBNoLeafNode* node); + void _RayStab(const AABBQuantizedNode* node); + void _RayStab(const AABBQuantizedNoLeafNode* node); + void _RayStab(const AABBTreeNode* node, Container& box_indices); + // Overlap tests + inline_ BOOL RayAABBOverlap(const Point& center, const Point& extents); + inline_ BOOL SegmentAABBOverlap(const Point& center, const Point& extents); + inline_ BOOL RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2); + // Init methods + BOOL InitQuery(const Ray& world_ray, const Matrix4x4* world=null, udword* face_id=null); + }; + +#endif // __OPC_RAYCOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_RayTriOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_RayTriOverlap.h new file mode 100644 index 00000000..7fe37c98 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_RayTriOverlap.h @@ -0,0 +1,89 @@ +#define LOCAL_EPSILON 0.000001f + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes a ray-triangle intersection test. + * Original code from Tomas Möller's "Fast Minimum Storage Ray-Triangle Intersection". + * It's been optimized a bit with integer code, and modified to return a non-intersection if distance from + * ray origin to triangle is negative. + * + * \param vert0 [in] triangle vertex + * \param vert1 [in] triangle vertex + * \param vert2 [in] triangle vertex + * \return true on overlap. mStabbedFace is filled with relevant info. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL RayCollider::RayTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2) +{ + // Stats + mNbRayPrimTests++; + + // Find vectors for two edges sharing vert0 + Point edge1 = vert1 - vert0; + Point edge2 = vert2 - vert0; + + // Begin calculating determinant - also used to calculate U parameter + Point pvec = mDir^edge2; + + // If determinant is near zero, ray lies in plane of triangle + float det = edge1|pvec; + + if(mCulling) + { + if(det 0. So we can use integer cmp. + + // Calculate distance from vert0 to ray origin + Point tvec = mOrigin - vert0; + + // Calculate U parameter and test bounds + mStabbedFace.mU = tvec|pvec; +// if(IR(u)&0x80000000 || u>det) return FALSE; + if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IR(det)) return FALSE; + + // Prepare to test V parameter + Point qvec = tvec^edge1; + + // Calculate V parameter and test bounds + mStabbedFace.mV = mDir|qvec; + if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>det) return FALSE; + + // Calculate t, scale parameters, ray intersects triangle + mStabbedFace.mDistance = edge2|qvec; + // Det > 0 so we can early exit here + // Intersection point is valid if distance is positive (else it can just be a face behind the orig point) + if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE; + // Else go on + float OneOverDet = 1.0f / det; + mStabbedFace.mDistance *= OneOverDet; + mStabbedFace.mU *= OneOverDet; + mStabbedFace.mV *= OneOverDet; + } + else + { + // the non-culling branch + if(det>-LOCAL_EPSILON && det1.0f) return FALSE; + if(IS_NEGATIVE_FLOAT(mStabbedFace.mU) || IR(mStabbedFace.mU)>IEEE_1_0) return FALSE; + + // prepare to test V parameter + Point qvec = tvec^edge1; + + // Calculate V parameter and test bounds + mStabbedFace.mV = (mDir|qvec) * OneOverDet; + if(IS_NEGATIVE_FLOAT(mStabbedFace.mV) || mStabbedFace.mU+mStabbedFace.mV>1.0f) return FALSE; + + // Calculate t, ray intersects triangle + mStabbedFace.mDistance = (edge2|qvec) * OneOverDet; + // Intersection point is valid if distance is positive (else it can just be a face behind the orig point) + if(IS_NEGATIVE_FLOAT(mStabbedFace.mDistance)) return FALSE; + } + return TRUE; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Settings.h b/src/external/open_dynamics_engine-ef/ode/OPC_Settings.h new file mode 100644 index 00000000..1841a2bc --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Settings.h @@ -0,0 +1,49 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains compilation flags. + * \file OPC_Settings.h + * \author Pierre Terdiman + * \date May, 12, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_SETTINGS_H__ +#define __OPC_SETTINGS_H__ + + //! Use CPU comparisons (comment that line to use standard FPU compares) + #define OPC_CPU_COMPARE + + //! Use FCOMI / FCMOV on Pentium-Pro based processors (comment that line to use plain C++) + #define OPC_USE_FCOMI + + //! Use epsilon value in tri-tri overlap test + #define OPC_TRITRI_EPSILON_TEST + + //! Use tree-coherence or not [not implemented yet] +// #define OPC_USE_TREE_COHERENCE + + //! Use callbacks or direct pointers. Using callbacks might be a bit slower (but probably not much) +// #define OPC_USE_CALLBACKS + + //! Support triangle and vertex strides or not. Using strides might be a bit slower (but probably not much) + #define OPC_USE_STRIDE + + //! Discard negative pointer in vanilla trees + #define OPC_NO_NEG_VANILLA_TREE + + //! Use a callback in the ray collider + //#define OPC_RAYHIT_CALLBACK + + // NB: no compilation flag to enable/disable stats since they're actually needed in the box/box overlap test + +#endif //__OPC_SETTINGS_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_SphereAABBOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_SphereAABBOverlap.h new file mode 100644 index 00000000..2278bc01 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_SphereAABBOverlap.h @@ -0,0 +1,128 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Sphere-AABB overlap test, based on Jim Arvo's code. + * \param center [in] box center + * \param extents [in] box extents + * \return TRUE on overlap + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL SphereCollider::SphereAABBOverlap(const Point& center, const Point& extents) +{ + // Stats + mNbVolumeBVTests++; + + float d = 0.0f; + + //find the square of the distance + //from the sphere to the box +#ifdef OLDIES + for(udword i=0;i<3;i++) + { + float tmp = mCenter[i] - center[i]; + float s = tmp + extents[i]; + + if(s<0.0f) d += s*s; + else + { + s = tmp - extents[i]; + if(s>0.0f) d += s*s; + } + } +#endif + +//#ifdef NEW_TEST + +// float tmp = mCenter.x - center.x; +// float s = tmp + extents.x; + + float tmp,s; + + tmp = mCenter.x - center.x; + s = tmp + extents.x; + + if(s<0.0f) + { + d += s*s; + if(d>mRadius2) return FALSE; + } + else + { + s = tmp - extents.x; + if(s>0.0f) + { + d += s*s; + if(d>mRadius2) return FALSE; + } + } + + tmp = mCenter.y - center.y; + s = tmp + extents.y; + + if(s<0.0f) + { + d += s*s; + if(d>mRadius2) return FALSE; + } + else + { + s = tmp - extents.y; + if(s>0.0f) + { + d += s*s; + if(d>mRadius2) return FALSE; + } + } + + tmp = mCenter.z - center.z; + s = tmp + extents.z; + + if(s<0.0f) + { + d += s*s; + if(d>mRadius2) return FALSE; + } + else + { + s = tmp - extents.z; + if(s>0.0f) + { + d += s*s; + if(d>mRadius2) return FALSE; + } + } +//#endif + +#ifdef OLDIES +// Point Min = center - extents; +// Point Max = center + extents; + + float d = 0.0f; + + //find the square of the distance + //from the sphere to the box + for(udword i=0;i<3;i++) + { +float Min = center[i] - extents[i]; + +// if(mCenter[i]Max[i]) + if(mCenter[i]>Max) + { + float s = mCenter[i] - Max; + d += s*s; + } + } + } +#endif + return d <= mRadius2; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.cpp new file mode 100644 index 00000000..39a4bfab --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.cpp @@ -0,0 +1,738 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a sphere collider. + * \file OPC_SphereCollider.cpp + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains a sphere-vs-tree collider. + * This class performs a collision test between a sphere and an AABB tree. You can use this to do a standard player vs world collision, + * in a Nettle/Telemachos way. It doesn't suffer from all reported bugs in those two classic codes - the "new" one by Paul Nettle is a + * debuggued version I think. Collision response can be driven by reported collision data - it works extremely well for me. In sake of + * efficiency, all meshes (that is, all AABB trees) should of course also be kept in an extra hierarchical structure (octree, whatever). + * + * \class SphereCollider + * \author Pierre Terdiman + * \version 1.3 + * \date June, 2, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +#include "ode/OPC_SphereAABBOverlap.h" +#include "ode/OPC_SphereTriOverlap.h" + +#define SET_CONTACT(prim_index, flag) \ + /* Set contact status */ \ + mFlags |= flag; \ + mTouchedPrimitives->Add(prim_index); + +//! Sphere-triangle overlap test +#define SPHERE_PRIM(prim_index, flag) \ + /* Request vertices from the app */ \ + VertexPointers VP; mIMesh->GetTriangle(VP, prim_index); \ + \ + /* Perform sphere-tri overlap test */ \ + if(SphereTriOverlap(*VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) \ + { \ + SET_CONTACT(prim_index, flag) \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SphereCollider::SphereCollider() +{ + mCenter.Zero(); + mRadius2 = 0.0f; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SphereCollider::~SphereCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a sphere cache + * \param sphere [in] collision sphere in local space + * \param model [in] Opcode model to collide with + * \param worlds [in] sphere's world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool SphereCollider::Collide(SphereCache& cache, const Sphere& sphere, const Model& model, const Matrix4x4* worlds, const Matrix4x4* worldm) +// ericf change +bool SphereCollider::Collide(SphereCache& cache, const Sphere& sphere, Model& model, const Matrix4x4* worlds, const Matrix4x4* worldm) +{ + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, sphere, worlds, worldm)) return true; + + if(!model.HasLeafNodes()) + { + if(model.IsQuantized()) + { + const AABBQuantizedNoLeafTree* Tree = (const AABBQuantizedNoLeafTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query + if(SkipPrimitiveTests()) _CollideNoPrimitiveTest(Tree->GetNodes()); + else _Collide(Tree->GetNodes()); + } + } + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a collision query : + * - reset stats & contact status + * - setup matrices + * - check temporal coherence + * + * \param cache [in/out] a sphere cache + * \param sphere [in] sphere in local space + * \param worlds [in] sphere's world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return TRUE if we can return immediately + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +BOOL SphereCollider::InitQuery(SphereCache& cache, const Sphere& sphere, const Matrix4x4* worlds, const Matrix4x4* worldm) +{ + // 1) Call the base method + VolumeCollider::InitQuery(); + + // 2) Compute sphere in model space: + // - Precompute R^2 + mRadius2 = sphere.mRadius * sphere.mRadius; + // - Compute center position + mCenter = sphere.mCenter; + // -> to world space + if(worlds) mCenter *= *worlds; + // -> to model space + if(worldm) + { + // Invert model matrix + Matrix4x4 InvWorldM; + InvertPRMatrix(InvWorldM, *worldm); + + mCenter *= InvWorldM; + } + + // 3) Setup destination pointer + mTouchedPrimitives = &cache.TouchedPrimitives; + + // 4) Special case: 1-triangle meshes [Opcode 1.3] + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + if(!SkipPrimitiveTests()) + { + // We simply perform the BV-Prim overlap test each time. We assume single triangle has index 0. + mTouchedPrimitives->Reset(); + + // Perform overlap test between the unique triangle and the sphere (and set contact status if needed) + SPHERE_PRIM(udword(0), OPC_CONTACT) + + // Return immediately regardless of status + return TRUE; + } + } + + // 5) Check temporal coherence : + if(TemporalCoherenceEnabled()) + { + // Here we use temporal coherence + // => check results from previous frame before performing the collision query + if(FirstContactEnabled()) + { + // We're only interested in the first contact found => test the unique previously touched face + if(mTouchedPrimitives->GetNbEntries()) + { + // Get index of previously touched face = the first entry in the array + udword PreviouslyTouchedFace = mTouchedPrimitives->GetEntry(0); + + // Then reset the array: + // - if the overlap test below is successful, the index we'll get added back anyway + // - if it isn't, then the array should be reset anyway for the normal query + mTouchedPrimitives->Reset(); + + // Perform overlap test between the cached triangle and the sphere (and set contact status if needed) + SPHERE_PRIM(PreviouslyTouchedFace, OPC_TEMPORAL_CONTACT) + + // Return immediately if possible + if(GetContactStatus()) return TRUE; + } + // else no face has been touched during previous query + // => we'll have to perform a normal query + } + else + { + // We're interested in all contacts =>test the new real sphere N(ew) against the previous fat sphere P(revious): + float r = sqrtf(cache.FatRadius2) - sphere.mRadius; + if(IsCacheValid(cache) && cache.Center.SquareDistance(mCenter) < r*r) + { + // - if N is included in P, return previous list + // => we simply leave the list (mTouchedFaces) unchanged + + // Set contact status if needed + if(mTouchedPrimitives->GetNbEntries()) mFlags |= OPC_TEMPORAL_CONTACT; + + // In any case we don't need to do a query + return TRUE; + } + else + { + // - else do the query using a fat N + + // Reset cache since we'll about to perform a real query + mTouchedPrimitives->Reset(); + + // Make a fat sphere so that coherence will work for subsequent frames + mRadius2 *= cache.FatCoeff; +// mRadius2 = (sphere.mRadius * cache.FatCoeff)*(sphere.mRadius * cache.FatCoeff); + + // Update cache with query data (signature for cached faces) + cache.Center = mCenter; + cache.FatRadius2 = mRadius2; + } + } + } + else + { + // Here we don't use temporal coherence => do a normal query + mTouchedPrimitives->Reset(); + } + + return FALSE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for vanilla AABB trees. + * \param cache [in/out] a sphere cache + * \param sphere [in] collision sphere in world space + * \param tree [in] AABB tree + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool SphereCollider::Collide(SphereCache& cache, const Sphere& sphere, const AABBTree* tree) +{ + // This is typically called for a scene tree, full of -AABBs-, not full of triangles. + // So we don't really have "primitives" to deal with. Hence it doesn't work with + // "FirstContact" + "TemporalCoherence". + ASSERT( !(FirstContactEnabled() && TemporalCoherenceEnabled()) ); + + // Checkings + if(!tree) return false; + + // Init collision query + if(InitQuery(cache, sphere)) return true; + + // Perform collision query + _Collide(tree); + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Checks the sphere completely contains the box. In which case we can end the query sooner. + * \param bc [in] box center + * \param be [in] box extents + * \return true if the sphere contains the whole box + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL SphereCollider::SphereContainsBox(const Point& bc, const Point& be) +{ + // I assume if all 8 box vertices are inside the sphere, so does the whole box. + // Sounds ok but maybe there's a better way? + Point p; + p.x=bc.x+be.x; p.y=bc.y+be.y; p.z=bc.z+be.z; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x+be.x; p.y=bc.y-be.y; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x+be.x; p.y=bc.y+be.y; p.z=bc.z-be.z; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x+be.x; p.y=bc.y-be.y; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + p.x=bc.x-be.x; if(mCenter.SquareDistance(p)>=mRadius2) return FALSE; + + return TRUE; +} + +#define TEST_BOX_IN_SPHERE(center, extents) \ + if(SphereContainsBox(center, extents)) \ + { \ + /* Set contact status */ \ + mFlags |= OPC_CONTACT; \ + _Dump(node); \ + return; \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_Collide(const AABBCollisionNode* node) +{ + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + SPHERE_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_CollideNoPrimitiveTest(const AABBCollisionNode* node) +{ + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_Collide(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_SPHERE(Center, Extents) + + if(node->IsLeaf()) + { + SPHERE_PRIM(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _Collide(node->GetPos()); + + if(ContactFound()) return; + + _Collide(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_CollideNoPrimitiveTest(const AABBQuantizedNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_SPHERE(Center, Extents) + + if(node->IsLeaf()) + { + SET_CONTACT(node->GetPrimitive(), OPC_CONTACT) + } + else + { + _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + _CollideNoPrimitiveTest(node->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_Collide(const AABBNoLeafNode* node) +{ + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { SPHERE_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SPHERE_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_CollideNoPrimitiveTest(const AABBNoLeafNode* node) +{ + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(node->mAABB.mCenter, node->mAABB.mExtents)) return; + + TEST_BOX_IN_SPHERE(node->mAABB.mCenter, node->mAABB.mExtents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_Collide(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_SPHERE(Center, Extents) + + if(node->HasPosLeaf()) { SPHERE_PRIM(node->GetPosPrimitive(), OPC_CONTACT) } + else _Collide(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SPHERE_PRIM(node->GetNegPrimitive(), OPC_CONTACT) } + else _Collide(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees, without primitive tests. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node) +{ + // Dequantize box + const QuantizedAABB& Box = node->mAABB; + const Point Center(float(Box.mCenter[0]) * mCenterCoeff.x, float(Box.mCenter[1]) * mCenterCoeff.y, float(Box.mCenter[2]) * mCenterCoeff.z); + const Point Extents(float(Box.mExtents[0]) * mExtentsCoeff.x, float(Box.mExtents[1]) * mExtentsCoeff.y, float(Box.mExtents[2]) * mExtentsCoeff.z); + + // Perform Sphere-AABB overlap test + if(!SphereAABBOverlap(Center, Extents)) return; + + TEST_BOX_IN_SPHERE(Center, Extents) + + if(node->HasPosLeaf()) { SET_CONTACT(node->GetPosPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetPos()); + + if(ContactFound()) return; + + if(node->HasNegLeaf()) { SET_CONTACT(node->GetNegPrimitive(), OPC_CONTACT) } + else _CollideNoPrimitiveTest(node->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for vanilla AABB trees. + * \param node [in] current collision node + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void SphereCollider::_Collide(const AABBTreeNode* node) +{ + // Perform Sphere-AABB overlap test + Point Center, Extents; + node->GetAABB()->GetCenter(Center); + node->GetAABB()->GetExtents(Extents); + if(!SphereAABBOverlap(Center, Extents)) return; + + if(node->IsLeaf() || SphereContainsBox(Center, Extents)) + { + mFlags |= OPC_CONTACT; + mTouchedPrimitives->Add(node->GetPrimitives(), node->GetNbPrimitives()); + } + else + { + _Collide(node->GetPos()); + _Collide(node->GetNeg()); + } +} + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridSphereCollider::HybridSphereCollider() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +HybridSphereCollider::~HybridSphereCollider() +{ +} + +//bool HybridSphereCollider::Collide(SphereCache& cache, const Sphere& sphere, const HybridModel& model, const Matrix4x4* worlds, const Matrix4x4* worldm) +// ericf change +bool HybridSphereCollider::Collide(SphereCache& cache, const Sphere& sphere, HybridModel& model, const Matrix4x4* worlds, const Matrix4x4* worldm) +{ + // We don't want primitive tests here! + mFlags |= OPC_NO_PRIMITIVE_TESTS; + + // Checkings + if(!Setup(&model)) return false; + + // Init collision query + if(InitQuery(cache, sphere, worlds, worldm)) return true; + + // Special case for 1-leaf trees + if(mCurrentModel && mCurrentModel->HasSingleNode()) + { + // Here we're supposed to perform a normal query, except our tree has a single node, i.e. just a few triangles + udword Nb = mIMesh->GetNbTriangles(); + + // Loop through all triangles + for(udword i=0;imCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBNoLeafTree* Tree = (const AABBNoLeafTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + else + { + if(model.IsQuantized()) + { + const AABBQuantizedTree* Tree = (const AABBQuantizedTree*)model.GetTree(); + + // Setup dequantization coeffs + mCenterCoeff = Tree->mCenterCoeff; + mExtentsCoeff = Tree->mExtentsCoeff; + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + else + { + const AABBCollisionTree* Tree = (const AABBCollisionTree*)model.GetTree(); + + // Perform collision query - we don't want primitive tests here! + _CollideNoPrimitiveTest(Tree->GetNodes()); + } + } + + // We only have a list of boxes so far + if(GetContactStatus()) + { + // Reset contact status, since it currently only reflects collisions with leaf boxes + Collider::InitQuery(); + + // Change dest container so that we can use built-in overlap tests and get collided primitives + cache.TouchedPrimitives.Reset(); + mTouchedPrimitives = &cache.TouchedPrimitives; + + // Read touched leaf boxes + udword Nb = mTouchedBoxes.GetNbEntries(); + const udword* Touched = mTouchedBoxes.GetEntries(); + + const LeafTriangles* LT = model.GetLeafTriangles(); + const udword* Indices = model.GetIndices(); + + // Loop through touched leaves + while(Nb--) + { + const LeafTriangles& CurrentLeaf = LT[*Touched++]; + + // Each leaf box has a set of triangles + udword NbTris = CurrentLeaf.GetNbTriangles(); + if(Indices) + { + const udword* T = &Indices[CurrentLeaf.GetTriangleIndex()]; + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = *T++; + SPHERE_PRIM(TriangleIndex, OPC_CONTACT) + } + } + else + { + udword BaseIndex = CurrentLeaf.GetTriangleIndex(); + + // Loop through triangles and test each of them + while(NbTris--) + { + udword TriangleIndex = BaseIndex++; + SPHERE_PRIM(TriangleIndex, OPC_CONTACT) + } + } + } + } + + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.h new file mode 100644 index 00000000..6a191d00 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_SphereCollider.h @@ -0,0 +1,100 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a sphere collider. + * \file OPC_SphereCollider.h + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_SPHERECOLLIDER_H__ +#define __OPC_SPHERECOLLIDER_H__ + + struct OPCODE_API SphereCache : VolumeCache + { + SphereCache() : Center(0.0f,0.0f,0.0f), FatRadius2(0.0f), FatCoeff(1.1f) {} + ~SphereCache() {} + + // Cached faces signature + Point Center; //!< Sphere used when performing the query resulting in cached faces + float FatRadius2; //!< Sphere used when performing the query resulting in cached faces + // User settings + float FatCoeff; //!< mRadius2 multiplier used to create a fat sphere + }; + + class OPCODE_API SphereCollider : public VolumeCollider + { + public: + // Constructor / Destructor + SphereCollider(); + virtual ~SphereCollider(); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Generic collision query for generic OPCODE models. After the call, access the results: + * - with GetContactStatus() + * - with GetNbTouchedPrimitives() + * - with GetTouchedPrimitives() + * + * \param cache [in/out] a sphere cache + * \param sphere [in] collision sphere in local space + * \param model [in] Opcode model to collide with + * \param worlds [in] sphere's world matrix, or null + * \param worldm [in] model's world matrix, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + //bool Collide(SphereCache& cache, const Sphere& sphere, const Model& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); + // ericf change + bool Collide(SphereCache& cache, const Sphere& sphere, Model& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); + + // + bool Collide(SphereCache& cache, const Sphere& sphere, const AABBTree* tree); + protected: + // Sphere in model space + Point mCenter; //!< Sphere center + float mRadius2; //!< Sphere radius squared + // Internal methods + void _Collide(const AABBCollisionNode* node); + void _Collide(const AABBNoLeafNode* node); + void _Collide(const AABBQuantizedNode* node); + void _Collide(const AABBQuantizedNoLeafNode* node); + void _Collide(const AABBTreeNode* node); + void _CollideNoPrimitiveTest(const AABBCollisionNode* node); + void _CollideNoPrimitiveTest(const AABBNoLeafNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNode* node); + void _CollideNoPrimitiveTest(const AABBQuantizedNoLeafNode* node); + // Overlap tests + inline_ BOOL SphereContainsBox(const Point& bc, const Point& be); + inline_ BOOL SphereAABBOverlap(const Point& center, const Point& extents); + BOOL SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2); + // Init methods + BOOL InitQuery(SphereCache& cache, const Sphere& sphere, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); + }; + + class OPCODE_API HybridSphereCollider : public SphereCollider + { + public: + // Constructor / Destructor + HybridSphereCollider(); + virtual ~HybridSphereCollider(); + + //bool Collide(SphereCache& cache, const Sphere& sphere, const HybridModel& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); + // ericf change + bool Collide(SphereCache& cache, const Sphere& sphere, HybridModel& model, const Matrix4x4* worlds=null, const Matrix4x4* worldm=null); + protected: + Container mTouchedBoxes; + }; + +#endif // __OPC_SPHERECOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_SphereTriOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_SphereTriOverlap.h new file mode 100644 index 00000000..77e59f37 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_SphereTriOverlap.h @@ -0,0 +1,187 @@ + +// This is collision detection. If you do another distance test for collision *response*, +// if might be useful to simply *skip* the test below completely, and report a collision. +// - if sphere-triangle overlap, result is ok +// - if they don't, we'll discard them during collision response with a similar test anyway +// Overall this approach should run faster. + +// Original code by David Eberly in Magic. +BOOL SphereCollider::SphereTriOverlap(const Point& vert0, const Point& vert1, const Point& vert2) +{ + // Stats + mNbVolumePrimTests++; + + // Early exit if one of the vertices is inside the sphere + Point kDiff = vert2 - mCenter; + float fC = kDiff.SquareMagnitude(); + if(fC <= mRadius2) return TRUE; + + kDiff = vert1 - mCenter; + fC = kDiff.SquareMagnitude(); + if(fC <= mRadius2) return TRUE; + + kDiff = vert0 - mCenter; + fC = kDiff.SquareMagnitude(); + if(fC <= mRadius2) return TRUE; + + // Else do the full distance test + Point TriEdge0 = vert1 - vert0; + Point TriEdge1 = vert2 - vert0; + +//Point kDiff = vert0 - mCenter; + float fA00 = TriEdge0.SquareMagnitude(); + float fA01 = TriEdge0 | TriEdge1; + float fA11 = TriEdge1.SquareMagnitude(); + float fB0 = kDiff | TriEdge0; + float fB1 = kDiff | TriEdge1; +//float fC = kDiff.SquareMagnitude(); + float fDet = fabsf(fA00*fA11 - fA01*fA01); + float u = fA01*fB1-fA11*fB0; + float v = fA01*fB0-fA00*fB1; + float SqrDist; + + if(u + v <= fDet) + { + if(u < 0.0f) + { + if(v < 0.0f) // region 4 + { + if(fB0 < 0.0f) + { +// v = 0.0f; + if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; } + else { u = -fB0/fA00; SqrDist = fB0*u+fC; } + } + else + { +// u = 0.0f; + if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; } + else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; } + else { v = -fB1/fA11; SqrDist = fB1*v+fC; } + } + } + else // region 3 + { +// u = 0.0f; + if(fB1>=0.0f) { /*v = 0.0f;*/ SqrDist = fC; } + else if(-fB1>=fA11) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; } + else { v = -fB1/fA11; SqrDist = fB1*v+fC; } + } + } + else if(v < 0.0f) // region 5 + { +// v = 0.0f; + if(fB0>=0.0f) { /*u = 0.0f;*/ SqrDist = fC; } + else if(-fB0>=fA00) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; } + else { u = -fB0/fA00; SqrDist = fB0*u+fC; } + } + else // region 0 + { + // minimum at interior point + if(fDet==0.0f) + { +// u = 0.0f; +// v = 0.0f; + SqrDist = MAX_FLOAT; + } + else + { + float fInvDet = 1.0f/fDet; + u *= fInvDet; + v *= fInvDet; + SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; + } + } + } + else + { + float fTmp0, fTmp1, fNumer, fDenom; + + if(u < 0.0f) // region 2 + { + fTmp0 = fA01 + fB0; + fTmp1 = fA11 + fB1; + if(fTmp1 > fTmp0) + { + fNumer = fTmp1 - fTmp0; + fDenom = fA00-2.0f*fA01+fA11; + if(fNumer >= fDenom) + { +// u = 1.0f; +// v = 0.0f; + SqrDist = fA00+2.0f*fB0+fC; + } + else + { + u = fNumer/fDenom; + v = 1.0f - u; + SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; + } + } + else + { +// u = 0.0f; + if(fTmp1 <= 0.0f) { /*v = 1.0f;*/ SqrDist = fA11+2.0f*fB1+fC; } + else if(fB1 >= 0.0f) { /*v = 0.0f;*/ SqrDist = fC; } + else { v = -fB1/fA11; SqrDist = fB1*v+fC; } + } + } + else if(v < 0.0f) // region 6 + { + fTmp0 = fA01 + fB1; + fTmp1 = fA00 + fB0; + if(fTmp1 > fTmp0) + { + fNumer = fTmp1 - fTmp0; + fDenom = fA00-2.0f*fA01+fA11; + if(fNumer >= fDenom) + { +// v = 1.0f; +// u = 0.0f; + SqrDist = fA11+2.0f*fB1+fC; + } + else + { + v = fNumer/fDenom; + u = 1.0f - v; + SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; + } + } + else + { +// v = 0.0f; + if(fTmp1 <= 0.0f) { /*u = 1.0f;*/ SqrDist = fA00+2.0f*fB0+fC; } + else if(fB0 >= 0.0f) { /*u = 0.0f;*/ SqrDist = fC; } + else { u = -fB0/fA00; SqrDist = fB0*u+fC; } + } + } + else // region 1 + { + fNumer = fA11 + fB1 - fA01 - fB0; + if(fNumer <= 0.0f) + { +// u = 0.0f; +// v = 1.0f; + SqrDist = fA11+2.0f*fB1+fC; + } + else + { + fDenom = fA00-2.0f*fA01+fA11; + if(fNumer >= fDenom) + { +// u = 1.0f; +// v = 0.0f; + SqrDist = fA00+2.0f*fB0+fC; + } + else + { + u = fNumer/fDenom; + v = 1.0f - u; + SqrDist = u*(fA00*u+fA01*v+2.0f*fB0) + v*(fA01*u+fA11*v+2.0f*fB1)+fC; + } + } + } + } + + return fabsf(SqrDist) < mRadius2; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.cpp new file mode 100644 index 00000000..a4e20edc --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.cpp @@ -0,0 +1,14 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif + +//#define ICE_MAIN +#include "OPC_Stdafx.h" diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.h b/src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.h new file mode 100644 index 00000000..f6468a61 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_Stdafx.h @@ -0,0 +1,24 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_STDAFX_H__EFB95044_1D31_11D5_8B0F_0050BAC83302__INCLUDED_) +#define AFX_STDAFX_H__EFB95044_1D31_11D5_8B0F_0050BAC83302__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// Insert your headers here +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#include "ode/ode_Opcode.h" + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__EFB95044_1D31_11D5_8B0F_0050BAC83302__INCLUDED_) diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.cpp new file mode 100644 index 00000000..89e3ffef --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.cpp @@ -0,0 +1,672 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains an implementation of the sweep-and-prune algorithm (moved from Z-Collide) + * \file OPC_SweepAndPrune.cpp + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +inline_ void Sort(udword& id0, udword& id1) +{ + if(id0>id1) Swap(id0, id1); +} + + class Opcode::SAP_Element + { + public: + inline_ SAP_Element() {} + inline_ SAP_Element(udword id, SAP_Element* next) : mID(id), mNext(next) {} + inline_ ~SAP_Element() {} + + udword mID; + SAP_Element* mNext; + }; + + class Opcode::SAP_Box + { + public: + SAP_EndPoint* Min[3]; + SAP_EndPoint* Max[3]; + }; + + class Opcode::SAP_EndPoint + { + public: + float Value; // Min or Max value + SAP_EndPoint* Previous; // Previous EndPoint whose Value is smaller than ours (or null) + SAP_EndPoint* Next; // Next EndPoint whose Value is greater than ours (or null) + udword Data; // Parent box ID *2 | MinMax flag + + inline_ void SetData(udword box_id, BOOL is_max) { Data = (box_id<<1)|is_max; } + inline_ BOOL IsMax() const { return Data & 1; } + inline_ udword GetBoxID() const { return Data>>1; } + + inline_ void InsertAfter(SAP_EndPoint* element) + { + if(this!=element && this!=element->Next) + { + // Remove + if(Previous) Previous->Next = Next; + if(Next) Next->Previous = Previous; + + // Insert + Next = element->Next; + if(Next) Next->Previous = this; + + element->Next = this; + Previous = element; + } + } + + inline_ void InsertBefore(SAP_EndPoint* element) + { + if(this!=element && this!=element->Previous) + { + // Remove + if(Previous) Previous->Next = Next; + if(Next) Next->Previous = Previous; + + // Insert + Previous = element->Previous; + element->Previous = this; + + Next = element; + if(Previous) Previous->Next = this; + } + } + }; + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SAP_PairData::SAP_PairData() : + mNbElements (0), + mNbUsedElements (0), + mElementPool (null), + mFirstFree (null), + mNbObjects (0), + mArray (null) +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SAP_PairData::~SAP_PairData() +{ + Release(); +} + +void SAP_PairData::Release() +{ + mNbElements = 0; + mNbUsedElements = 0; + mNbObjects = 0; + DELETEARRAY(mElementPool); + DELETEARRAY(mArray); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes. + * \param nb_objects [in] + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool SAP_PairData::Init(udword nb_objects) +{ + // Make sure everything has been released + Release(); + if(!nb_objects) return false; + + mArray = new SAP_Element*[nb_objects]; + CHECKALLOC(mArray); + ZeroMemory(mArray, nb_objects*sizeof(SAP_Element*)); + mNbObjects = nb_objects; + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Remaps a pointer when pool gets resized. + * \param element [in/out] remapped element + * \param delta [in] offset in bytes + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ void Remap(SAP_Element*& element, size_t delta) +{ + if(element) element = (SAP_Element*)(element + delta); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Gets a free element in the pool. + * \param id [in] element id + * \param next [in] next element + * \param remap [out] possible remapping offset + * \return the new element + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SAP_Element* SAP_PairData::GetFreeElem(udword id, SAP_Element* next, udword* remap) +{ + if(remap) *remap = 0; + + SAP_Element* FreeElem; + if(mFirstFree) + { + // Recycle + FreeElem = mFirstFree; + mFirstFree = mFirstFree->mNext; // First free = next free (or null) + } + else + { + if(mNbUsedElements==mNbElements) + { + // Resize + mNbElements = mNbElements ? (mNbElements<<1) : 2; + + SAP_Element* NewElems = new SAP_Element[mNbElements]; + + if(mNbUsedElements) CopyMemory(NewElems, mElementPool, mNbUsedElements*sizeof(SAP_Element)); + + // Remap everything + { + size_t Delta = size_t(NewElems) - size_t(mElementPool); + + for(udword i=0;imID = id; + FreeElem->mNext = next; + + return FreeElem; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Frees an element of the pool. + * \param elem [in] element to free/recycle + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ void SAP_PairData::FreeElem(SAP_Element* elem) +{ + elem->mNext = mFirstFree; // Next free + mFirstFree = elem; +} + +// Add a pair to the set. +void SAP_PairData::AddPair(udword id1, udword id2) +{ + // Order the ids + Sort(id1, id2); + + ASSERT(id1=mNbObjects) return; + + // Select the right list from "mArray". + SAP_Element* Current = mArray[id1]; + + if(!Current) + { + // Empty slot => create new element + mArray[id1] = GetFreeElem(id2, null); + } + else if(Current->mID>id2) + { + // The list is not empty but all elements are greater than id2 => insert id2 in the front. + mArray[id1] = GetFreeElem(id2, mArray[id1]); + } + else + { + // Else find the correct location in the sorted list (ascending order) and insert id2 there. + while(Current->mNext) + { + if(Current->mNext->mID > id2) break; + + Current = Current->mNext; + } + + if(Current->mID==id2) return; // The pair already exists + +// Current->mNext = GetFreeElem(id2, Current->mNext); + udword Delta; + SAP_Element* E = GetFreeElem(id2, Current->mNext, &Delta); + if(Delta) Remap(Current, Delta); + Current->mNext = E; + } +} + +// Delete a pair from the set. +void SAP_PairData::RemovePair(udword id1, udword id2) +{ + // Order the ids. + Sort(id1, id2); + + // Exit if the pair doesn't exist in the set + if(id1>=mNbObjects) return; + + // Otherwise, select the correct list. + SAP_Element* Current = mArray[id1]; + + // If this list is empty, the pair doesn't exist. + if(!Current) return; + + // Otherwise, if id2 is the first element, delete it. + if(Current->mID==id2) + { + mArray[id1] = Current->mNext; + FreeElem(Current); + } + else + { + // If id2 is not the first element, start traversing the sorted list. + while(Current->mNext) + { + // If we have moved too far away without hitting id2, then the pair doesn't exist + if(Current->mNext->mID > id2) return; + + // Otherwise, delete id2. + if(Current->mNext->mID == id2) + { + SAP_Element* Temp = Current->mNext; + Current->mNext = Temp->mNext; + FreeElem(Temp); + return; + } + Current = Current->mNext; + } + } +} + +void SAP_PairData::DumpPairs(Pairs& pairs) const +{ + // ### Ugly and slow + for(udword i=0;imIDmID); + Current = Current->mNext; + } + } +} + +void SAP_PairData::DumpPairs(PairCallback callback, void* user_data) const +{ + if(!callback) return; + + // ### Ugly and slow + for(udword i=0;imIDmID, user_data)) return; + Current = Current->mNext; + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Constructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SweepAndPrune::SweepAndPrune() +{ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Destructor. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +SweepAndPrune::~SweepAndPrune() +{ +} + +void SweepAndPrune::GetPairs(Pairs& pairs) const +{ + mPairs.DumpPairs(pairs); +} + +void SweepAndPrune::GetPairs(PairCallback callback, void* user_data) const +{ + mPairs.DumpPairs(callback, user_data); +} + +bool SweepAndPrune::Init(udword nb_objects, const AABB** boxes) +{ + // 1) Create sorted lists + mNbObjects = nb_objects; + + mBoxes = new SAP_Box[nb_objects]; +// for(udword i=0;iGetMin(Axis); + Data[i*2+1] = boxes[i]->GetMax(Axis); + } + RadixSort RS; + const udword* Sorted = RS.Sort(Data, nb_objects*2).GetRanks(); + + SAP_EndPoint* PreviousEndPoint = null; + + for(udword i=0;i>1; + + ASSERT(BoxIndexValue = SortedCoord; +// CurrentEndPoint->IsMax = SortedIndex&1; // ### could be implicit ? +// CurrentEndPoint->ID = BoxIndex; // ### could be implicit ? + CurrentEndPoint->SetData(BoxIndex, SortedIndex&1); // ### could be implicit ? + CurrentEndPoint->Previous = PreviousEndPoint; + CurrentEndPoint->Next = null; + if(PreviousEndPoint) PreviousEndPoint->Next = CurrentEndPoint; + + if(CurrentEndPoint->IsMax()) mBoxes[BoxIndex].Max[Axis] = CurrentEndPoint; + else mBoxes[BoxIndex].Min[Axis] = CurrentEndPoint; + + PreviousEndPoint = CurrentEndPoint; + } + } + + DELETEARRAY(Data); + + CheckListsIntegrity(); + + // 2) Quickly find starting pairs + + mPairs.Init(nb_objects); + + { + Pairs P; + CompleteBoxPruning(nb_objects, boxes, P, Axes(AXES_XZY)); + for(udword i=0;iid0; + udword id1 = PP->id1; + + if(id0!=id1 && boxes[id0]->Intersect(*boxes[id1])) + { + mPairs.AddPair(id0, id1); + } + else ASSERT(0); + } + } + + return true; +} + +bool SweepAndPrune::CheckListsIntegrity() +{ + for(udword Axis=0;Axis<3;Axis++) + { + // Find list head + SAP_EndPoint* Current = mList[Axis]; + while(Current->Previous) Current = Current->Previous; + + udword Nb = 0; + + SAP_EndPoint* Previous = null; + while(Current) + { + Nb++; + + if(Previous) + { + ASSERT(Previous->Value <= Current->Value); + if(Previous->Value > Current->Value) return false; + } + + ASSERT(Current->Previous==Previous); + if(Current->Previous!=Previous) return false; + + Previous = Current; + Current = Current->Next; + } + + ASSERT(Nb==mNbObjects*2); + } + return true; +} + +inline_ BOOL Intersect(const AABB& a, const SAP_Box& b) +{ + if(b.Max[0]->Value < a.GetMin(0) || a.GetMax(0) < b.Min[0]->Value + || b.Max[1]->Value < a.GetMin(1) || a.GetMax(1) < b.Min[1]->Value + || b.Max[2]->Value < a.GetMin(2) || a.GetMax(2) < b.Min[2]->Value) return FALSE; + + return TRUE; +} + + + +bool SweepAndPrune::UpdateObject(udword i, const AABB& box) +{ + for(udword Axis=0;Axis<3;Axis++) + { +// udword Base = (udword)&mList[Axis][0]; + + // Update min + { + SAP_EndPoint* const CurrentMin = mBoxes[i].Min[Axis]; + ASSERT(!CurrentMin->IsMax()); + + const float Limit = box.GetMin(Axis); + if(Limit == CurrentMin->Value) + { + } + else if(Limit < CurrentMin->Value) + { + CurrentMin->Value = Limit; + + // Min is moving left: + SAP_EndPoint* NewPos = CurrentMin; + ASSERT(NewPos); + + SAP_EndPoint* tmp; + while((tmp = NewPos->Previous) && tmp->Value > Limit) + { + NewPos = tmp; + + if(NewPos->IsMax()) + { + // Our min passed a max => start overlap + //udword SortedIndex = (udword(CurrentMin) - Base)/sizeof(NS_EndPoint); + const udword id0 = CurrentMin->GetBoxID(); + const udword id1 = NewPos->GetBoxID(); + + if(id0!=id1 && Intersect(box, mBoxes[id1])) mPairs.AddPair(id0, id1); + } + } + + CurrentMin->InsertBefore(NewPos); + } + else// if(Limit > CurrentMin->Value) + { + CurrentMin->Value = Limit; + + // Min is moving right: + SAP_EndPoint* NewPos = CurrentMin; + ASSERT(NewPos); + + SAP_EndPoint* tmp; + while((tmp = NewPos->Next) && tmp->Value < Limit) + { + NewPos = tmp; + + if(NewPos->IsMax()) + { + // Our min passed a max => stop overlap + const udword id0 = CurrentMin->GetBoxID(); + const udword id1 = NewPos->GetBoxID(); + + if(id0!=id1) mPairs.RemovePair(id0, id1); + } + } + + CurrentMin->InsertAfter(NewPos); + } + } + + // Update max + { + SAP_EndPoint* const CurrentMax = mBoxes[i].Max[Axis]; + ASSERT(CurrentMax->IsMax()); + + const float Limit = box.GetMax(Axis); + if(Limit == CurrentMax->Value) + { + } + else if(Limit > CurrentMax->Value) + { + CurrentMax->Value = Limit; + + // Max is moving right: + SAP_EndPoint* NewPos = CurrentMax; + ASSERT(NewPos); + + SAP_EndPoint* tmp; + while((tmp = NewPos->Next) && tmp->Value < Limit) + { + NewPos = tmp; + + if(!NewPos->IsMax()) + { + // Our max passed a min => start overlap + const udword id0 = CurrentMax->GetBoxID(); + const udword id1 = NewPos->GetBoxID(); + + if(id0!=id1 && Intersect(box, mBoxes[id1])) mPairs.AddPair(id0, id1); + } + } + + CurrentMax->InsertAfter(NewPos); + } + else// if(Limit < CurrentMax->Value) + { + CurrentMax->Value = Limit; + + // Max is moving left: + SAP_EndPoint* NewPos = CurrentMax; + ASSERT(NewPos); + + SAP_EndPoint* tmp; + while((tmp = NewPos->Previous) && tmp->Value > Limit) + { + NewPos = tmp; + + if(!NewPos->IsMax()) + { + // Our max passed a min => stop overlap + const udword id0 = CurrentMax->GetBoxID(); + const udword id1 = NewPos->GetBoxID(); + + if(id0!=id1) mPairs.RemovePair(id0, id1); + } + } + + CurrentMax->InsertBefore(NewPos); + } + } + } + + return true; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.h b/src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.h new file mode 100644 index 00000000..2cbbb7e6 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_SweepAndPrune.h @@ -0,0 +1,86 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains an implementation of the sweep-and-prune algorithm (moved from Z-Collide) + * \file OPC_SweepAndPrune.h + * \author Pierre Terdiman + * \date January, 29, 2000 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_SWEEPANDPRUNE_H__ +#define __OPC_SWEEPANDPRUNE_H__ + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * User-callback, called by OPCODE for each colliding pairs. + * \param id0 [in] id of colliding object + * \param id1 [in] id of colliding object + * \param user_data [in] user-defined data + * \return TRUE to continue enumeration + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + typedef BOOL (*PairCallback) (udword id0, udword id1, void* user_data); + + class SAP_Element; + class SAP_EndPoint; + class SAP_Box; + + class OPCODE_API SAP_PairData + { + public: + SAP_PairData(); + ~SAP_PairData(); + + bool Init(udword nb_objects); + + void AddPair(udword id1, udword id2); + void RemovePair(udword id1, udword id2); + + void DumpPairs(Pairs& pairs) const; + void DumpPairs(PairCallback callback, void* user_data) const; + private: + udword mNbElements; //!< Total number of elements in the pool + udword mNbUsedElements; //!< Number of used elements + SAP_Element* mElementPool; //!< Array of mNbElements elements + SAP_Element* mFirstFree; //!< First free element in the pool + + udword mNbObjects; //!< Max number of objects we can handle + SAP_Element** mArray; //!< Pointers to pool + // Internal methods + SAP_Element* GetFreeElem(udword id, SAP_Element* next, udword* remap=null); + inline_ void FreeElem(SAP_Element* elem); + void Release(); + }; + + class OPCODE_API SweepAndPrune + { + public: + SweepAndPrune(); + ~SweepAndPrune(); + + bool Init(udword nb_objects, const AABB** boxes); + bool UpdateObject(udword i, const AABB& box); + + void GetPairs(Pairs& pairs) const; + void GetPairs(PairCallback callback, void* user_data) const; + private: + SAP_PairData mPairs; + + udword mNbObjects; + SAP_Box* mBoxes; + SAP_EndPoint* mList[3]; + // Internal methods + bool CheckListsIntegrity(); + }; + +#endif //__OPC_SWEEPANDPRUNE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_TreeBuilders.cpp b/src/external/open_dynamics_engine-ef/ode/OPC_TreeBuilders.cpp new file mode 100644 index 00000000..f34a4b68 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_TreeBuilders.cpp @@ -0,0 +1,269 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for tree builders. + * \file OPC_TreeBuilders.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A builder for AABB-trees of vertices. + * + * \class AABBTreeOfVerticesBuilder + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A builder for AABB-trees of AABBs. + * + * \class AABBTreeOfAABBsBuilder + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * A builder for AABB-trees of triangles. + * + * \class AABBTreeOfTrianglesBuilder + * \author Pierre Terdiman + * \version 1.3 + * \date March, 20, 2001 +*/ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +using namespace Opcode; + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the AABB of a set of primitives. + * \param primitives [in] list of indices of primitives + * \param nb_prims [in] number of indices + * \param global_box [out] global AABB enclosing the set of input primitives + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool AABBTreeOfAABBsBuilder::ComputeGlobalBox(const udword* primitives, udword nb_prims, AABB& global_box) const +// ericf change +bool AABBTreeOfAABBsBuilder::ComputeGlobalBox(const udword* primitives, udword nb_prims, AABB& global_box) +{ + // Checkings + if(!primitives || !nb_prims) return false; + + // Initialize global box + global_box = mAABBArray[primitives[0]]; + + // Loop through boxes + for(udword i=1;iGetTriangle(VP, *primitives++); + // Update global box + Min.Min(*VP.Vertex[0]).Min(*VP.Vertex[1]).Min(*VP.Vertex[2]); + Max.Max(*VP.Vertex[0]).Max(*VP.Vertex[1]).Max(*VP.Vertex[2]); + } + global_box.SetMinMax(Min, Max); + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the splitting value along a given axis for a given primitive. + * \param index [in] index of the primitive to split + * \param axis [in] axis index (0,1,2) + * \return splitting value + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float AABBTreeOfTrianglesBuilder::GetSplittingValue(udword index, udword axis) const +{ +/* // Compute center of triangle + Point Center; + mTriList[index].Center(mVerts, Center); + // Return value + return Center[axis];*/ + + // Compute correct component from center of triangle +// return (mVerts[mTriList[index].mVRef[0]][axis] +// +mVerts[mTriList[index].mVRef[1]][axis] +// +mVerts[mTriList[index].mVRef[2]][axis])*INV3; + + VertexPointers VP; + mIMesh->GetTriangle(VP, index); + + // Compute correct component from center of triangle + return ((*VP.Vertex[0])[axis] + +(*VP.Vertex[1])[axis] + +(*VP.Vertex[2])[axis])*INV3; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the splitting value along a given axis for a given node. + * \param primitives [in] list of indices of primitives + * \param nb_prims [in] number of indices + * \param global_box [in] global AABB enclosing the set of input primitives + * \param axis [in] axis index (0,1,2) + * \return splitting value + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +float AABBTreeOfTrianglesBuilder::GetSplittingValue(const udword* primitives, udword nb_prims, const AABB& global_box, udword axis) const +{ + if(mSettings.mRules&SPLIT_GEOM_CENTER) + { + // Loop through triangles + float SplitValue = 0.0f; + VertexPointers VP; + for(udword i=0;iGetTriangle(VP, primitives[i]); + // Update split value + SplitValue += (*VP.Vertex[0])[axis]; + SplitValue += (*VP.Vertex[1])[axis]; + SplitValue += (*VP.Vertex[2])[axis]; + } + return SplitValue / float(nb_prims*3); + } + else return AABBTreeBuilder::GetSplittingValue(primitives, nb_prims, global_box, axis); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Computes the AABB of a set of primitives. + * \param primitives [in] list of indices of primitives + * \param nb_prims [in] number of indices + * \param global_box [out] global AABB enclosing the set of input primitives + * \return true if success + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//bool AABBTreeOfVerticesBuilder::ComputeGlobalBox(const udword* primitives, udword nb_prims, AABB& global_box) const +// ericf change +bool AABBTreeOfVerticesBuilder::ComputeGlobalBox(const udword* primitives, udword nb_prims, AABB& global_box) +{ + // Checkings + if(!primitives || !nb_prims) return false; + + // Initialize global box + global_box.SetEmpty(); + + // Loop through vertices + for(udword i=0;iHasLeafNodes()!=cache.Model1->HasLeafNodes()) return false; + if(cache.Model0->IsQuantized()!=cache.Model1->IsQuantized()) return false; + + /* + + Rules: + - perform hull test + - when hulls collide, disable hull test + - if meshes overlap, reset countdown + - if countdown reaches 0, enable hull test + + */ + +#ifdef __MESHMERIZER_H__ + // Handle hulls + if(cache.HullTest) + { + if(cache.Model0->GetHull() && cache.Model1->GetHull()) + { + struct Local + { + static Point* SVCallback(const Point& sv, udword& previndex, udword user_data) + { + CollisionHull* Hull = (CollisionHull*)user_data; + previndex = Hull->ComputeSupportingVertex(sv, previndex); + return (Point*)&Hull->GetVerts()[previndex]; + } + }; + + bool Collide; + + if(0) + { + static GJKEngine GJK; + static bool GJKInitDone=false; + if(!GJKInitDone) + { + GJK.Enable(GJK_BACKUP_PROCEDURE); + GJK.Enable(GJK_DEGENERATE); + GJK.Enable(GJK_HILLCLIMBING); + GJKInitDone = true; + } + GJK.SetCallbackObj0(Local::SVCallback); + GJK.SetCallbackObj1(Local::SVCallback); + GJK.SetUserData0(udword(cache.Model0->GetHull())); + GJK.SetUserData1(udword(cache.Model1->GetHull())); + Collide = GJK.Collide(*world0, *world1, &cache.SepVector); + } + else + { + static SVEngine SVE; + SVE.SetCallbackObj0(Local::SVCallback); + SVE.SetCallbackObj1(Local::SVCallback); + SVE.SetUserData0(udword(cache.Model0->GetHull())); + SVE.SetUserData1(udword(cache.Model1->GetHull())); + Collide = SVE.Collide(*world0, *world1, &cache.SepVector); + } + + if(!Collide) + { + // Reset stats & contact status + mFlags &= ~OPC_CONTACT; + mNbBVBVTests = 0; + mNbPrimPrimTests = 0; + mNbBVPrimTests = 0; + mPairs.Reset(); + return true; + } + } + } + + // Here, hulls collide + cache.HullTest = false; +#endif // __MESHMERIZER_H__ + + // Checkings + if(!Setup(cache.Model0->GetMeshInterface(), cache.Model1->GetMeshInterface())) return false; + + // Simple double-dispatch + bool Status; + if(!cache.Model0->HasLeafNodes()) + { + if(cache.Model0->IsQuantized()) + { + const AABBQuantizedNoLeafTree* T0 = (const AABBQuantizedNoLeafTree*)cache.Model0->GetTree(); + const AABBQuantizedNoLeafTree* T1 = (const AABBQuantizedNoLeafTree*)cache.Model1->GetTree(); + Status = Collide(T0, T1, world0, world1, &cache); + } + else + { + const AABBNoLeafTree* T0 = (const AABBNoLeafTree*)cache.Model0->GetTree(); + const AABBNoLeafTree* T1 = (const AABBNoLeafTree*)cache.Model1->GetTree(); + Status = Collide(T0, T1, world0, world1, &cache); + } + } + else + { + if(cache.Model0->IsQuantized()) + { + const AABBQuantizedTree* T0 = (const AABBQuantizedTree*)cache.Model0->GetTree(); + const AABBQuantizedTree* T1 = (const AABBQuantizedTree*)cache.Model1->GetTree(); + Status = Collide(T0, T1, world0, world1, &cache); + } + else + { + const AABBCollisionTree* T0 = (const AABBCollisionTree*)cache.Model0->GetTree(); + const AABBCollisionTree* T1 = (const AABBCollisionTree*)cache.Model1->GetTree(); + Status = Collide(T0, T1, world0, world1, &cache); + } + } + +#ifdef __MESHMERIZER_H__ + if(Status) + { + // Reset counter as long as overlap occurs + if(GetContactStatus()) cache.ResetCountDown(); + + // Enable hull test again when counter reaches zero + cache.CountDown--; + if(!cache.CountDown) + { + cache.ResetCountDown(); + cache.HullTest = true; + } + } +#endif + return Status; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Initializes a collision query : + * - reset stats & contact status + * - setup matrices + * + * \param world0 [in] world matrix for first object + * \param world1 [in] world matrix for second object + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::InitQuery(const Matrix4x4* world0, const Matrix4x4* world1) +{ + // Reset stats & contact status + Collider::InitQuery(); + mNbBVBVTests = 0; + mNbPrimPrimTests = 0; + mNbBVPrimTests = 0; + mPairs.Reset(); + + // Setup matrices + Matrix4x4 InvWorld0, InvWorld1; + if(world0) InvertPRMatrix(InvWorld0, *world0); + else InvWorld0.Identity(); + + if(world1) InvertPRMatrix(InvWorld1, *world1); + else InvWorld1.Identity(); + + Matrix4x4 World0to1 = world0 ? (*world0 * InvWorld1) : InvWorld1; + Matrix4x4 World1to0 = world1 ? (*world1 * InvWorld0) : InvWorld0; + + mR0to1 = World0to1; World0to1.GetTrans(mT0to1); + mR1to0 = World1to0; World1to0.GetTrans(mT1to0); + + // Precompute absolute 1-to-0 rotation matrix + for(udword i=0;i<3;i++) + { + for(udword j=0;j<3;j++) + { + // Epsilon value prevents floating-point inaccuracies (strategy borrowed from RAPID) + mAR.m[i][j] = 1e-6f + fabsf(mR1to0.m[i][j]); + } + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Takes advantage of temporal coherence. + * \param cache [in] cache for a pair of previously colliding primitives + * \return true if we can return immediately + * \warning only works for "First Contact" mode + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTreeCollider::CheckTemporalCoherence(Pair* cache) +{ + // Checkings + if(!cache) return false; + + // Test previously colliding primitives first + if(TemporalCoherenceEnabled() && FirstContactEnabled()) + { + PrimTest(cache->id0, cache->id1); + if(GetContactStatus()) return true; + } + return false; +} + +#define UPDATE_CACHE \ + if(cache && GetContactStatus()) \ + { \ + cache->id0 = mPairs.GetEntry(0); \ + cache->id1 = mPairs.GetEntry(1); \ + } + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for normal AABB trees. + * \param tree0 [in] AABB tree from first object + * \param tree1 [in] AABB tree from second object + * \param world0 [in] world matrix for first object + * \param world1 [in] world matrix for second object + * \param cache [in/out] cache for a pair of previously colliding primitives + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTreeCollider::Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) +{ + // Init collision query + InitQuery(world0, world1); + + // Check previous state + if(CheckTemporalCoherence(cache)) return true; + + // Perform collision query + _Collide(tree0->GetNodes(), tree1->GetNodes()); + + UPDATE_CACHE + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for no-leaf AABB trees. + * \param tree0 [in] AABB tree from first object + * \param tree1 [in] AABB tree from second object + * \param world0 [in] world matrix for first object + * \param world1 [in] world matrix for second object + * \param cache [in/out] cache for a pair of previously colliding primitives + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTreeCollider::Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) +{ + // Init collision query + InitQuery(world0, world1); + + // Check previous state + if(CheckTemporalCoherence(cache)) return true; + + // Perform collision query + _Collide(tree0->GetNodes(), tree1->GetNodes()); + + UPDATE_CACHE + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for quantized AABB trees. + * \param tree0 [in] AABB tree from first object + * \param tree1 [in] AABB tree from second object + * \param world0 [in] world matrix for first object + * \param world1 [in] world matrix for second object + * \param cache [in/out] cache for a pair of previously colliding primitives + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTreeCollider::Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) +{ + // Init collision query + InitQuery(world0, world1); + + // Check previous state + if(CheckTemporalCoherence(cache)) return true; + + // Setup dequantization coeffs + mCenterCoeff0 = tree0->mCenterCoeff; + mExtentsCoeff0 = tree0->mExtentsCoeff; + mCenterCoeff1 = tree1->mCenterCoeff; + mExtentsCoeff1 = tree1->mExtentsCoeff; + + // Dequantize box A + const AABBQuantizedNode* N0 = tree0->GetNodes(); + const Point a(float(N0->mAABB.mExtents[0]) * mExtentsCoeff0.x, float(N0->mAABB.mExtents[1]) * mExtentsCoeff0.y, float(N0->mAABB.mExtents[2]) * mExtentsCoeff0.z); + const Point Pa(float(N0->mAABB.mCenter[0]) * mCenterCoeff0.x, float(N0->mAABB.mCenter[1]) * mCenterCoeff0.y, float(N0->mAABB.mCenter[2]) * mCenterCoeff0.z); + // Dequantize box B + const AABBQuantizedNode* N1 = tree1->GetNodes(); + const Point b(float(N1->mAABB.mExtents[0]) * mExtentsCoeff1.x, float(N1->mAABB.mExtents[1]) * mExtentsCoeff1.y, float(N1->mAABB.mExtents[2]) * mExtentsCoeff1.z); + const Point Pb(float(N1->mAABB.mCenter[0]) * mCenterCoeff1.x, float(N1->mAABB.mCenter[1]) * mCenterCoeff1.y, float(N1->mAABB.mCenter[2]) * mCenterCoeff1.z); + + // Perform collision query + _Collide(N0, N1, a, Pa, b, Pb); + + UPDATE_CACHE + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Collision query for quantized no-leaf AABB trees. + * \param tree0 [in] AABB tree from first object + * \param tree1 [in] AABB tree from second object + * \param world0 [in] world matrix for first object + * \param world1 [in] world matrix for second object + * \param cache [in/out] cache for a pair of previously colliding primitives + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +bool AABBTreeCollider::Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const Matrix4x4* world0, const Matrix4x4* world1, Pair* cache) +{ + // Init collision query + InitQuery(world0, world1); + + // Check previous state + if(CheckTemporalCoherence(cache)) return true; + + // Setup dequantization coeffs + mCenterCoeff0 = tree0->mCenterCoeff; + mExtentsCoeff0 = tree0->mExtentsCoeff; + mCenterCoeff1 = tree1->mCenterCoeff; + mExtentsCoeff1 = tree1->mExtentsCoeff; + + // Perform collision query + _Collide(tree0->GetNodes(), tree1->GetNodes()); + + UPDATE_CACHE + + return true; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Standard trees +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +// The normal AABB tree can use 2 different descent rules (with different performances) +//#define ORIGINAL_CODE //!< UNC-like descent rules +#define ALTERNATIVE_CODE //!< Alternative descent rules + +#ifdef ORIGINAL_CODE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param b0 [in] collision node from first tree + * \param b1 [in] collision node from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1) +{ + // Perform BV-BV overlap test + if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter)) return; + + if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; } + + if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize()))) + { + _Collide(b0->GetNeg(), b1); + if(ContactFound()) return; + _Collide(b0->GetPos(), b1); + } + else + { + _Collide(b0, b1->GetNeg()); + if(ContactFound()) return; + _Collide(b0, b1->GetPos()); + } +} +#endif + +#ifdef ALTERNATIVE_CODE +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for normal AABB trees. + * \param b0 [in] collision node from first tree + * \param b1 [in] collision node from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1) +{ + // Perform BV-BV overlap test + if(!BoxBoxOverlap(b0->mAABB.mExtents, b0->mAABB.mCenter, b1->mAABB.mExtents, b1->mAABB.mCenter)) + { + return; + } + + if(b0->IsLeaf()) + { + if(b1->IsLeaf()) + { + PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); + } + else + { + _Collide(b0, b1->GetNeg()); + if(ContactFound()) return; + _Collide(b0, b1->GetPos()); + } + } + else if(b1->IsLeaf()) + { + _Collide(b0->GetNeg(), b1); + if(ContactFound()) return; + _Collide(b0->GetPos(), b1); + } + else + { + _Collide(b0->GetNeg(), b1->GetNeg()); + if(ContactFound()) return; + _Collide(b0->GetNeg(), b1->GetPos()); + if(ContactFound()) return; + _Collide(b0->GetPos(), b1->GetNeg()); + if(ContactFound()) return; + _Collide(b0->GetPos(), b1->GetPos()); + } +} +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// No-leaf trees +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Leaf-leaf test for two primitive indices. + * \param id0 [in] index from first leaf-triangle + * \param id1 [in] index from second leaf-triangle + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::PrimTest(udword id0, udword id1) +{ + // Request vertices from the app + VertexPointers VP0; + VertexPointers VP1; + mIMesh0->GetTriangle(VP0, id0); + mIMesh1->GetTriangle(VP1, id1); + + // Transform from space 1 to space 0 + Point u0,u1,u2; + TransformPoint(u0, *VP1.Vertex[0], mR1to0, mT1to0); + TransformPoint(u1, *VP1.Vertex[1], mR1to0, mT1to0); + TransformPoint(u2, *VP1.Vertex[2], mR1to0, mT1to0); + + // Perform triangle-triangle overlap test + if(TriTriOverlap(*VP0.Vertex[0], *VP0.Vertex[1], *VP0.Vertex[2], u0, u1, u2)) + { + // Keep track of colliding pairs + mPairs.Add(id0).Add(id1); + // Set contact status + mFlags |= OPC_CONTACT; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Leaf-leaf test for a previously fetched triangle from tree A (in B's space) and a new leaf from B. + * \param id1 [in] leaf-triangle index from tree B + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ void AABBTreeCollider::PrimTestTriIndex(udword id1) +{ + // Request vertices from the app + VertexPointers VP; + mIMesh1->GetTriangle(VP, id1); + + // Perform triangle-triangle overlap test + if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) + { + // Keep track of colliding pairs + mPairs.Add(mLeafIndex).Add(id1); + // Set contact status + mFlags |= OPC_CONTACT; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Leaf-leaf test for a previously fetched triangle from tree B (in A's space) and a new leaf from A. + * \param id0 [in] leaf-triangle index from tree A + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ void AABBTreeCollider::PrimTestIndexTri(udword id0) +{ + // Request vertices from the app + VertexPointers VP; + mIMesh0->GetTriangle(VP, id0); + + // Perform triangle-triangle overlap test + if(TriTriOverlap(mLeafVerts[0], mLeafVerts[1], mLeafVerts[2], *VP.Vertex[0], *VP.Vertex[1], *VP.Vertex[2])) + { + // Keep track of colliding pairs + mPairs.Add(id0).Add(mLeafIndex); + // Set contact status + mFlags |= OPC_CONTACT; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision of a leaf node from A and a branch from B. + * \param b [in] collision node from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_CollideTriBox(const AABBNoLeafNode* b) +{ + // Perform triangle-box overlap test + if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return; + + // Keep same triangle, deal with first child + if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive()); + else _CollideTriBox(b->GetPos()); + + if(ContactFound()) return; + + // Keep same triangle, deal with second child + if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive()); + else _CollideTriBox(b->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision of a leaf node from B and a branch from A. + * \param b [in] collision node from first tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_CollideBoxTri(const AABBNoLeafNode* b) +{ + // Perform triangle-box overlap test + if(!TriBoxOverlap(b->mAABB.mCenter, b->mAABB.mExtents)) return; + + // Keep same triangle, deal with first child + if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive()); + else _CollideBoxTri(b->GetPos()); + + if(ContactFound()) return; + + // Keep same triangle, deal with second child + if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive()); + else _CollideBoxTri(b->GetNeg()); +} + +//! Request triangle vertices from the app and transform them +#define FETCH_LEAF(prim_index, imesh, rot, trans) \ + mLeafIndex = prim_index; \ + /* Request vertices from the app */ \ + VertexPointers VP; imesh->GetTriangle(VP, prim_index); \ + /* Transform them in a common space */ \ + TransformPoint(mLeafVerts[0], *VP.Vertex[0], rot, trans); \ + TransformPoint(mLeafVerts[1], *VP.Vertex[1], rot, trans); \ + TransformPoint(mLeafVerts[2], *VP.Vertex[2], rot, trans); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for no-leaf AABB trees. + * \param a [in] collision node from first tree + * \param b [in] collision node from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_Collide(const AABBNoLeafNode* a, const AABBNoLeafNode* b) +{ + // Perform BV-BV overlap test + if(!BoxBoxOverlap(a->mAABB.mExtents, a->mAABB.mCenter, b->mAABB.mExtents, b->mAABB.mCenter)) return; + + // Catch leaf status + BOOL BHasPosLeaf = b->HasPosLeaf(); + BOOL BHasNegLeaf = b->HasNegLeaf(); + + if(a->HasPosLeaf()) + { + FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1) + + if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); + else _CollideTriBox(b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); + else _CollideTriBox(b->GetNeg()); + } + else + { + if(BHasPosLeaf) + { + FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetPos()); + } + else _Collide(a->GetPos(), b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) + { + FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetPos()); + } + else _Collide(a->GetPos(), b->GetNeg()); + } + + if(ContactFound()) return; + + if(a->HasNegLeaf()) + { + FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1) + + if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); + else _CollideTriBox(b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); + else _CollideTriBox(b->GetNeg()); + } + else + { + if(BHasPosLeaf) + { + // ### That leaf has possibly already been fetched + FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetNeg()); + } + else _Collide(a->GetNeg(), b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) + { + // ### That leaf has possibly already been fetched + FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetNeg()); + } + else _Collide(a->GetNeg(), b->GetNeg()); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantized trees +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized AABB trees. + * \param b0 [in] collision node from first tree + * \param b1 [in] collision node from second tree + * \param a [in] extent from box A + * \param Pa [in] center from box A + * \param b [in] extent from box B + * \param Pb [in] center from box B + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_Collide(const AABBQuantizedNode* b0, const AABBQuantizedNode* b1, const Point& a, const Point& Pa, const Point& b, const Point& Pb) +{ + // Perform BV-BV overlap test + if(!BoxBoxOverlap(a, Pa, b, Pb)) return; + + if(b0->IsLeaf() && b1->IsLeaf()) { PrimTest(b0->GetPrimitive(), b1->GetPrimitive()); return; } + + if(b1->IsLeaf() || (!b0->IsLeaf() && (b0->GetSize() > b1->GetSize()))) + { + // Dequantize box + const QuantizedAABB* Box = &b0->GetNeg()->mAABB; + const Point negPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z); + const Point nega(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z); + _Collide(b0->GetNeg(), b1, nega, negPa, b, Pb); + + if(ContactFound()) return; + + // Dequantize box + Box = &b0->GetPos()->mAABB; + const Point posPa(float(Box->mCenter[0]) * mCenterCoeff0.x, float(Box->mCenter[1]) * mCenterCoeff0.y, float(Box->mCenter[2]) * mCenterCoeff0.z); + const Point posa(float(Box->mExtents[0]) * mExtentsCoeff0.x, float(Box->mExtents[1]) * mExtentsCoeff0.y, float(Box->mExtents[2]) * mExtentsCoeff0.z); + _Collide(b0->GetPos(), b1, posa, posPa, b, Pb); + } + else + { + // Dequantize box + const QuantizedAABB* Box = &b1->GetNeg()->mAABB; + const Point negPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z); + const Point negb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z); + _Collide(b0, b1->GetNeg(), a, Pa, negb, negPb); + + if(ContactFound()) return; + + // Dequantize box + Box = &b1->GetPos()->mAABB; + const Point posPb(float(Box->mCenter[0]) * mCenterCoeff1.x, float(Box->mCenter[1]) * mCenterCoeff1.y, float(Box->mCenter[2]) * mCenterCoeff1.z); + const Point posb(float(Box->mExtents[0]) * mExtentsCoeff1.x, float(Box->mExtents[1]) * mExtentsCoeff1.y, float(Box->mExtents[2]) * mExtentsCoeff1.z); + _Collide(b0, b1->GetPos(), a, Pa, posb, posPb); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Quantized no-leaf trees +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision of a leaf node from A and a quantized branch from B. + * param leaf [in] leaf triangle from first tree + * \param b [in] collision node from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_CollideTriBox(const AABBQuantizedNoLeafNode* b) +{ + // Dequantize box + const QuantizedAABB* bb = &b->mAABB; + const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z); + const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z); + + // Perform triangle-box overlap test + if(!TriBoxOverlap(Pb, eb)) return; + + if(b->HasPosLeaf()) PrimTestTriIndex(b->GetPosPrimitive()); + else _CollideTriBox(b->GetPos()); + + if(ContactFound()) return; + + if(b->HasNegLeaf()) PrimTestTriIndex(b->GetNegPrimitive()); + else _CollideTriBox(b->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision of a leaf node from B and a quantized branch from A. + * \param b [in] collision node from first tree + * param leaf [in] leaf triangle from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_CollideBoxTri(const AABBQuantizedNoLeafNode* b) +{ + // Dequantize box + const QuantizedAABB* bb = &b->mAABB; + const Point Pa(float(bb->mCenter[0]) * mCenterCoeff0.x, float(bb->mCenter[1]) * mCenterCoeff0.y, float(bb->mCenter[2]) * mCenterCoeff0.z); + const Point ea(float(bb->mExtents[0]) * mExtentsCoeff0.x, float(bb->mExtents[1]) * mExtentsCoeff0.y, float(bb->mExtents[2]) * mExtentsCoeff0.z); + + // Perform triangle-box overlap test + if(!TriBoxOverlap(Pa, ea)) return; + + if(b->HasPosLeaf()) PrimTestIndexTri(b->GetPosPrimitive()); + else _CollideBoxTri(b->GetPos()); + + if(ContactFound()) return; + + if(b->HasNegLeaf()) PrimTestIndexTri(b->GetNegPrimitive()); + else _CollideBoxTri(b->GetNeg()); +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Recursive collision query for quantized no-leaf AABB trees. + * \param a [in] collision node from first tree + * \param b [in] collision node from second tree + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +void AABBTreeCollider::_Collide(const AABBQuantizedNoLeafNode* a, const AABBQuantizedNoLeafNode* b) +{ + // Dequantize box A + const QuantizedAABB* ab = &a->mAABB; + const Point Pa(float(ab->mCenter[0]) * mCenterCoeff0.x, float(ab->mCenter[1]) * mCenterCoeff0.y, float(ab->mCenter[2]) * mCenterCoeff0.z); + const Point ea(float(ab->mExtents[0]) * mExtentsCoeff0.x, float(ab->mExtents[1]) * mExtentsCoeff0.y, float(ab->mExtents[2]) * mExtentsCoeff0.z); + // Dequantize box B + const QuantizedAABB* bb = &b->mAABB; + const Point Pb(float(bb->mCenter[0]) * mCenterCoeff1.x, float(bb->mCenter[1]) * mCenterCoeff1.y, float(bb->mCenter[2]) * mCenterCoeff1.z); + const Point eb(float(bb->mExtents[0]) * mExtentsCoeff1.x, float(bb->mExtents[1]) * mExtentsCoeff1.y, float(bb->mExtents[2]) * mExtentsCoeff1.z); + + // Perform BV-BV overlap test + if(!BoxBoxOverlap(ea, Pa, eb, Pb)) return; + + // Catch leaf status + BOOL BHasPosLeaf = b->HasPosLeaf(); + BOOL BHasNegLeaf = b->HasNegLeaf(); + + if(a->HasPosLeaf()) + { + FETCH_LEAF(a->GetPosPrimitive(), mIMesh0, mR0to1, mT0to1) + + if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); + else _CollideTriBox(b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); + else _CollideTriBox(b->GetNeg()); + } + else + { + if(BHasPosLeaf) + { + FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetPos()); + } + else _Collide(a->GetPos(), b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) + { + FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetPos()); + } + else _Collide(a->GetPos(), b->GetNeg()); + } + + if(ContactFound()) return; + + if(a->HasNegLeaf()) + { + FETCH_LEAF(a->GetNegPrimitive(), mIMesh0, mR0to1, mT0to1) + + if(BHasPosLeaf) PrimTestTriIndex(b->GetPosPrimitive()); + else _CollideTriBox(b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) PrimTestTriIndex(b->GetNegPrimitive()); + else _CollideTriBox(b->GetNeg()); + } + else + { + if(BHasPosLeaf) + { + // ### That leaf has possibly already been fetched + FETCH_LEAF(b->GetPosPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetNeg()); + } + else _Collide(a->GetNeg(), b->GetPos()); + + if(ContactFound()) return; + + if(BHasNegLeaf) + { + // ### That leaf has possibly already been fetched + FETCH_LEAF(b->GetNegPrimitive(), mIMesh1, mR1to0, mT1to0) + + _CollideBoxTri(a->GetNeg()); + } + else _Collide(a->GetNeg(), b->GetNeg()); + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_TreeCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_TreeCollider.h new file mode 100644 index 00000000..31b8cc66 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_TreeCollider.h @@ -0,0 +1,252 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains code for a tree collider. + * \file OPC_TreeCollider.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_TREECOLLIDER_H__ +#define __OPC_TREECOLLIDER_H__ + + //! This structure holds cached information used by the algorithm. + //! Two model pointers and two colliding primitives are cached. Model pointers are assigned + //! to their respective meshes, and the pair of colliding primitives is used for temporal + //! coherence. That is, in case temporal coherence is enabled, those two primitives are + //! tested for overlap before everything else. If they still collide, we're done before + //! even entering the recursive collision code. + struct OPCODE_API BVTCache : Pair + { + //! Constructor + inline_ BVTCache() + { + ResetCache(); + ResetCountDown(); + } + + void ResetCache() + { + Model0 = null; + Model1 = null; + id0 = 0; + id1 = 1; +#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! + HullTest = true; + SepVector.pid = 0; + SepVector.qid = 0; + SepVector.SV = Point(1.0f, 0.0f, 0.0f); +#endif // __MESHMERIZER_H__ + } + + void ResetCountDown() + { +#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! + CountDown = 50; +#endif // __MESHMERIZER_H__ + } + + // ericf change + Model* Model0; //!< Model for first object + Model* Model1; //!< Model for second object + // const Model* Model0; //!< Model for first object + // const Model* Model1; //!< Model for second object + +#ifdef __MESHMERIZER_H__ // Collision hulls only supported within ICE ! + SVCache SepVector; + udword CountDown; + bool HullTest; +#endif // __MESHMERIZER_H__ + }; + + class OPCODE_API AABBTreeCollider : public Collider + { + public: + // Constructor / Destructor + AABBTreeCollider(); + virtual ~AABBTreeCollider(); + // Generic collision query + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Generic collision query for generic OPCODE models. After the call, access the results with: + * - GetContactStatus() + * - GetNbPairs() + * - GetPairs() + * + * \param cache [in] collision cache for model pointers and a colliding pair of primitives + * \param world0 [in] world matrix for first object, or null + * \param world1 [in] world matrix for second object, or null + * \return true if success + * \warning SCALE NOT SUPPORTED. The matrices must contain rotation & translation parts only. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + bool Collide(BVTCache& cache, const Matrix4x4* world0=null, const Matrix4x4* world1=null); + + // Collision queries + bool Collide(const AABBCollisionTree* tree0, const AABBCollisionTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); + bool Collide(const AABBNoLeafTree* tree0, const AABBNoLeafTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); + bool Collide(const AABBQuantizedTree* tree0, const AABBQuantizedTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); + bool Collide(const AABBQuantizedNoLeafTree* tree0, const AABBQuantizedNoLeafTree* tree1, const Matrix4x4* world0=null, const Matrix4x4* world1=null, Pair* cache=null); + // Settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: selects between full box-box tests or "SAT-lite" tests (where Class III axes are discarded) + * \param flag [in] true for full tests, false for coarse tests + * \see SetFullPrimBoxTest(bool flag) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetFullBoxBoxTest(bool flag) { mFullBoxBoxTest = flag; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Settings: selects between full triangle-box tests or "SAT-lite" tests (where Class III axes are discarded) + * \param flag [in] true for full tests, false for coarse tests + * \see SetFullBoxBoxTest(bool flag) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ void SetFullPrimBoxTest(bool flag) { mFullPrimBoxTest = flag; } + + // Stats + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of BV-BV overlap tests after a collision query. + * \see GetNbPrimPrimTests() + * \see GetNbBVPrimTests() + * \return the number of BV-BV tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbBVBVTests() const { return mNbBVBVTests; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of Triangle-Triangle overlap tests after a collision query. + * \see GetNbBVBVTests() + * \see GetNbBVPrimTests() + * \return the number of Triangle-Triangle tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbPrimPrimTests() const { return mNbPrimPrimTests; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of BV-Triangle overlap tests after a collision query. + * \see GetNbBVBVTests() + * \see GetNbPrimPrimTests() + * \return the number of BV-Triangle tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbBVPrimTests() const { return mNbBVPrimTests; } + + // Data access + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the number of contacts after a collision query. + * \see GetContactStatus() + * \see GetPairs() + * \return the number of contacts / colliding pairs. + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbPairs() const { return mPairs.GetNbEntries()>>1; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the pairs of colliding triangles after a collision query. + * \see GetContactStatus() + * \see GetNbPairs() + * \return the list of colliding pairs (triangle indices) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const Pair* GetPairs() const { return (const Pair*)mPairs.GetEntries(); } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Validates current settings. You should call this method after all the settings and callbacks have been defined for a collider. + * \return null if everything is ok, else a string describing the problem + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(Collider) const char* ValidateSettings(); + + protected: + // Colliding pairs + Container mPairs; //!< Pairs of colliding primitives + // User mesh interfaces + // ericf change + MeshInterface* mIMesh0; //!< User-defined mesh interface for object0 + MeshInterface* mIMesh1; //!< User-defined mesh interface for object1 + // const MeshInterface* mIMesh0; //!< User-defined mesh interface for object0 + // const MeshInterface* mIMesh1; //!< User-defined mesh interface for object1 + // Stats + udword mNbBVBVTests; //!< Number of BV-BV tests + udword mNbPrimPrimTests; //!< Number of Primitive-Primitive tests + udword mNbBVPrimTests; //!< Number of BV-Primitive tests + // Precomputed data + Matrix3x3 mAR; //!< Absolute rotation matrix + Matrix3x3 mR0to1; //!< Rotation from object0 to object1 + Matrix3x3 mR1to0; //!< Rotation from object1 to object0 + Point mT0to1; //!< Translation from object0 to object1 + Point mT1to0; //!< Translation from object1 to object0 + // Dequantization coeffs + Point mCenterCoeff0; + Point mExtentsCoeff0; + Point mCenterCoeff1; + Point mExtentsCoeff1; + // Leaf description + Point mLeafVerts[3]; //!< Triangle vertices + udword mLeafIndex; //!< Triangle index + // Settings + bool mFullBoxBoxTest; //!< Perform full BV-BV tests (true) or SAT-lite tests (false) + bool mFullPrimBoxTest; //!< Perform full Primitive-BV tests (true) or SAT-lite tests (false) + // Internal methods + + // Standard AABB trees + void _Collide(const AABBCollisionNode* b0, const AABBCollisionNode* b1); + // Quantized AABB trees + void _Collide(const AABBQuantizedNode* b0, const AABBQuantizedNode* b1, const Point& a, const Point& Pa, const Point& b, const Point& Pb); + // No-leaf AABB trees + void _CollideTriBox(const AABBNoLeafNode* b); + void _CollideBoxTri(const AABBNoLeafNode* b); + void _Collide(const AABBNoLeafNode* a, const AABBNoLeafNode* b); + // Quantized no-leaf AABB trees + void _CollideTriBox(const AABBQuantizedNoLeafNode* b); + void _CollideBoxTri(const AABBQuantizedNoLeafNode* b); + void _Collide(const AABBQuantizedNoLeafNode* a, const AABBQuantizedNoLeafNode* b); + // Overlap tests + void PrimTest(udword id0, udword id1); + inline_ void PrimTestTriIndex(udword id1); + inline_ void PrimTestIndexTri(udword id0); + + inline_ BOOL BoxBoxOverlap(const Point& ea, const Point& ca, const Point& eb, const Point& cb); + inline_ BOOL TriBoxOverlap(const Point& center, const Point& extents); + inline_ BOOL TriTriOverlap(const Point& V0, const Point& V1, const Point& V2, const Point& U0, const Point& U1, const Point& U2); + // Init methods + void InitQuery(const Matrix4x4* world0=null, const Matrix4x4* world1=null); + bool CheckTemporalCoherence(Pair* cache); + + //inline_ BOOL Setup(const MeshInterface* mi0, const MeshInterface* mi1) + // ericf change + inline_ BOOL Setup(MeshInterface* mi0, MeshInterface* mi1) + { + mIMesh0 = mi0; + mIMesh1 = mi1; + + if(!mIMesh0 || !mIMesh1) return FALSE; + + return TRUE; + } + }; + +#endif // __OPC_TREECOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_TriBoxOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_TriBoxOverlap.h new file mode 100644 index 00000000..b3a9bdee --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_TriBoxOverlap.h @@ -0,0 +1,339 @@ + +//! This macro quickly finds the min & max values among 3 variables +#define FINDMINMAX(x0, x1, x2, min, max) \ + min = max = x0; \ + if(x1max) max=x1; \ + if(x2max) max=x2; + +//! TO BE DOCUMENTED +inline_ BOOL planeBoxOverlap(const Point& normal, const float d, const Point& maxbox) +{ + Point vmin, vmax; + for(udword q=0;q<=2;q++) + { + if(normal[q]>0.0f) { vmin[q]=-maxbox[q]; vmax[q]=maxbox[q]; } + else { vmin[q]=maxbox[q]; vmax[q]=-maxbox[q]; } + } + if((normal|vmin)+d>0.0f) return FALSE; + if((normal|vmax)+d>=0.0f) return TRUE; + + return FALSE; +} + +//! TO BE DOCUMENTED +#define AXISTEST_X01(a, b, fa, fb) \ + min = a*v0.y - b*v0.z; \ + max = a*v2.y - b*v2.z; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.y + fb * extents.z; \ + if(min>rad || max<-rad) return FALSE; + +//! TO BE DOCUMENTED +#define AXISTEST_X2(a, b, fa, fb) \ + min = a*v0.y - b*v0.z; \ + max = a*v1.y - b*v1.z; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.y + fb * extents.z; \ + if(min>rad || max<-rad) return FALSE; + +//! TO BE DOCUMENTED +#define AXISTEST_Y02(a, b, fa, fb) \ + min = b*v0.z - a*v0.x; \ + max = b*v2.z - a*v2.x; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.z; \ + if(min>rad || max<-rad) return FALSE; + +//! TO BE DOCUMENTED +#define AXISTEST_Y1(a, b, fa, fb) \ + min = b*v0.z - a*v0.x; \ + max = b*v1.z - a*v1.x; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.z; \ + if(min>rad || max<-rad) return FALSE; + +//! TO BE DOCUMENTED +#define AXISTEST_Z12(a, b, fa, fb) \ + min = a*v1.x - b*v1.y; \ + max = a*v2.x - b*v2.y; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.y; \ + if(min>rad || max<-rad) return FALSE; + +//! TO BE DOCUMENTED +#define AXISTEST_Z0(a, b, fa, fb) \ + min = a*v0.x - b*v0.y; \ + max = a*v1.x - b*v1.y; \ + if(min>max) {const float tmp=max; max=min; min=tmp; } \ + rad = fa * extents.x + fb * extents.y; \ + if(min>rad || max<-rad) return FALSE; + +// compute triangle edges +// - edges lazy evaluated to take advantage of early exits +// - fabs precomputed (half less work, possible since extents are always >0) +// - customized macros to take advantage of the null component +// - axis vector discarded, possibly saves useless movs +#define IMPLEMENT_CLASS3_TESTS \ + float rad; \ + float min, max; \ + \ + const float fey0 = fabsf(e0.y); \ + const float fez0 = fabsf(e0.z); \ + AXISTEST_X01(e0.z, e0.y, fez0, fey0); \ + const float fex0 = fabsf(e0.x); \ + AXISTEST_Y02(e0.z, e0.x, fez0, fex0); \ + AXISTEST_Z12(e0.y, e0.x, fey0, fex0); \ + \ + const float fey1 = fabsf(e1.y); \ + const float fez1 = fabsf(e1.z); \ + AXISTEST_X01(e1.z, e1.y, fez1, fey1); \ + const float fex1 = fabsf(e1.x); \ + AXISTEST_Y02(e1.z, e1.x, fez1, fex1); \ + AXISTEST_Z0(e1.y, e1.x, fey1, fex1); \ + \ + const Point e2 = mLeafVerts[0] - mLeafVerts[2]; \ + const float fey2 = fabsf(e2.y); \ + const float fez2 = fabsf(e2.z); \ + AXISTEST_X2(e2.z, e2.y, fez2, fey2); \ + const float fex2 = fabsf(e2.x); \ + AXISTEST_Y1(e2.z, e2.x, fez2, fex2); \ + AXISTEST_Z12(e2.y, e2.x, fey2, fex2); + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Triangle-Box overlap test using the separating axis theorem. + * This is the code from Tomas Möller, a bit optimized: + * - with some more lazy evaluation (faster path on PC) + * - with a tiny bit of assembly + * - with "SAT-lite" applied if needed + * - and perhaps with some more minor modifs... + * + * \param center [in] box center + * \param extents [in] box extents + * \return true if triangle & box overlap + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL AABBTreeCollider::TriBoxOverlap(const Point& center, const Point& extents) +{ + // Stats + mNbBVPrimTests++; + + // use separating axis theorem to test overlap between triangle and box + // need to test for overlap in these directions: + // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle + // we do not even need to test these) + // 2) normal of the triangle + // 3) crossproduct(edge from tri, {x,y,z}-directin) + // this gives 3x3=9 more tests + + // move everything so that the boxcenter is in (0,0,0) + Point v0, v1, v2; + v0.x = mLeafVerts[0].x - center.x; + v1.x = mLeafVerts[1].x - center.x; + v2.x = mLeafVerts[2].x - center.x; + + // First, test overlap in the {x,y,z}-directions +#ifdef OPC_USE_FCOMI + // find min, max of the triangle in x-direction, and test for overlap in X + if(FCMin3(v0.x, v1.x, v2.x)>extents.x) return FALSE; + if(FCMax3(v0.x, v1.x, v2.x)<-extents.x) return FALSE; + + // same for Y + v0.y = mLeafVerts[0].y - center.y; + v1.y = mLeafVerts[1].y - center.y; + v2.y = mLeafVerts[2].y - center.y; + + if(FCMin3(v0.y, v1.y, v2.y)>extents.y) return FALSE; + if(FCMax3(v0.y, v1.y, v2.y)<-extents.y) return FALSE; + + // same for Z + v0.z = mLeafVerts[0].z - center.z; + v1.z = mLeafVerts[1].z - center.z; + v2.z = mLeafVerts[2].z - center.z; + + if(FCMin3(v0.z, v1.z, v2.z)>extents.z) return FALSE; + if(FCMax3(v0.z, v1.z, v2.z)<-extents.z) return FALSE; +#else + float min,max; + // Find min, max of the triangle in x-direction, and test for overlap in X + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if(min>extents.x || max<-extents.x) return FALSE; + + // Same for Y + v0.y = mLeafVerts[0].y - center.y; + v1.y = mLeafVerts[1].y - center.y; + v2.y = mLeafVerts[2].y - center.y; + + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if(min>extents.y || max<-extents.y) return FALSE; + + // Same for Z + v0.z = mLeafVerts[0].z - center.z; + v1.z = mLeafVerts[1].z - center.z; + v2.z = mLeafVerts[2].z - center.z; + + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if(min>extents.z || max<-extents.z) return FALSE; +#endif + // 2) Test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + // ### could be precomputed since we use the same leaf triangle several times + const Point e0 = v1 - v0; + const Point e1 = v2 - v1; + const Point normal = e0 ^ e1; + const float d = -normal|v0; + if(!planeBoxOverlap(normal, d, extents)) return FALSE; + + // 3) "Class III" tests + if(mFullPrimBoxTest) + { + IMPLEMENT_CLASS3_TESTS + } + return TRUE; +} + +//! A dedicated version where the box is constant +inline_ BOOL OBBCollider::TriBoxOverlap() +{ + // Stats + mNbVolumePrimTests++; + + // Hook + const Point& extents = mBoxExtents; + const Point& v0 = mLeafVerts[0]; + const Point& v1 = mLeafVerts[1]; + const Point& v2 = mLeafVerts[2]; + + // use separating axis theorem to test overlap between triangle and box + // need to test for overlap in these directions: + // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle + // we do not even need to test these) + // 2) normal of the triangle + // 3) crossproduct(edge from tri, {x,y,z}-directin) + // this gives 3x3=9 more tests + + // Box center is already in (0,0,0) + + // First, test overlap in the {x,y,z}-directions +#ifdef OPC_USE_FCOMI + // find min, max of the triangle in x-direction, and test for overlap in X + if(FCMin3(v0.x, v1.x, v2.x)>mBoxExtents.x) return FALSE; + if(FCMax3(v0.x, v1.x, v2.x)<-mBoxExtents.x) return FALSE; + + if(FCMin3(v0.y, v1.y, v2.y)>mBoxExtents.y) return FALSE; + if(FCMax3(v0.y, v1.y, v2.y)<-mBoxExtents.y) return FALSE; + + if(FCMin3(v0.z, v1.z, v2.z)>mBoxExtents.z) return FALSE; + if(FCMax3(v0.z, v1.z, v2.z)<-mBoxExtents.z) return FALSE; +#else + float min,max; + // Find min, max of the triangle in x-direction, and test for overlap in X + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if(min>mBoxExtents.x || max<-mBoxExtents.x) return FALSE; + + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if(min>mBoxExtents.y || max<-mBoxExtents.y) return FALSE; + + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if(min>mBoxExtents.z || max<-mBoxExtents.z) return FALSE; +#endif + // 2) Test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + // ### could be precomputed since we use the same leaf triangle several times + const Point e0 = v1 - v0; + const Point e1 = v2 - v1; + const Point normal = e0 ^ e1; + const float d = -normal|v0; + if(!planeBoxOverlap(normal, d, mBoxExtents)) return FALSE; + + // 3) "Class III" tests - here we always do full tests since the box is a primitive (not a BV) + { + IMPLEMENT_CLASS3_TESTS + } + return TRUE; +} + +//! ...and another one, jeez +inline_ BOOL AABBCollider::TriBoxOverlap() +{ + // Stats + mNbVolumePrimTests++; + + // Hook + const Point& center = mBox.mCenter; + const Point& extents = mBox.mExtents; + + // use separating axis theorem to test overlap between triangle and box + // need to test for overlap in these directions: + // 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle + // we do not even need to test these) + // 2) normal of the triangle + // 3) crossproduct(edge from tri, {x,y,z}-directin) + // this gives 3x3=9 more tests + + // move everything so that the boxcenter is in (0,0,0) + Point v0, v1, v2; + v0.x = mLeafVerts[0].x - center.x; + v1.x = mLeafVerts[1].x - center.x; + v2.x = mLeafVerts[2].x - center.x; + + // First, test overlap in the {x,y,z}-directions +#ifdef OPC_USE_FCOMI + // find min, max of the triangle in x-direction, and test for overlap in X + if(FCMin3(v0.x, v1.x, v2.x)>extents.x) return FALSE; + if(FCMax3(v0.x, v1.x, v2.x)<-extents.x) return FALSE; + + // same for Y + v0.y = mLeafVerts[0].y - center.y; + v1.y = mLeafVerts[1].y - center.y; + v2.y = mLeafVerts[2].y - center.y; + + if(FCMin3(v0.y, v1.y, v2.y)>extents.y) return FALSE; + if(FCMax3(v0.y, v1.y, v2.y)<-extents.y) return FALSE; + + // same for Z + v0.z = mLeafVerts[0].z - center.z; + v1.z = mLeafVerts[1].z - center.z; + v2.z = mLeafVerts[2].z - center.z; + + if(FCMin3(v0.z, v1.z, v2.z)>extents.z) return FALSE; + if(FCMax3(v0.z, v1.z, v2.z)<-extents.z) return FALSE; +#else + float min,max; + // Find min, max of the triangle in x-direction, and test for overlap in X + FINDMINMAX(v0.x, v1.x, v2.x, min, max); + if(min>extents.x || max<-extents.x) return FALSE; + + // Same for Y + v0.y = mLeafVerts[0].y - center.y; + v1.y = mLeafVerts[1].y - center.y; + v2.y = mLeafVerts[2].y - center.y; + + FINDMINMAX(v0.y, v1.y, v2.y, min, max); + if(min>extents.y || max<-extents.y) return FALSE; + + // Same for Z + v0.z = mLeafVerts[0].z - center.z; + v1.z = mLeafVerts[1].z - center.z; + v2.z = mLeafVerts[2].z - center.z; + + FINDMINMAX(v0.z, v1.z, v2.z, min, max); + if(min>extents.z || max<-extents.z) return FALSE; +#endif + // 2) Test if the box intersects the plane of the triangle + // compute plane equation of triangle: normal*x+d=0 + // ### could be precomputed since we use the same leaf triangle several times + const Point e0 = v1 - v0; + const Point e1 = v2 - v1; + const Point normal = e0 ^ e1; + const float d = -normal|v0; + if(!planeBoxOverlap(normal, d, extents)) return FALSE; + + // 3) "Class III" tests - here we always do full tests since the box is a primitive (not a BV) + { + IMPLEMENT_CLASS3_TESTS + } + return TRUE; +} diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_TriTriOverlap.h b/src/external/open_dynamics_engine-ef/ode/OPC_TriTriOverlap.h new file mode 100644 index 00000000..1c0b81a6 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_TriTriOverlap.h @@ -0,0 +1,279 @@ + +//! if OPC_TRITRI_EPSILON_TEST is true then we do a check (if |dv|b) \ + { \ + const float c=a; \ + a=b; \ + b=c; \ + } + +//! Edge to edge test based on Franlin Antonio's gem: "Faster Line Segment Intersection", in Graphics Gems III, pp. 199-202 +#define EDGE_EDGE_TEST(V0, U0, U1) \ + Bx = U0[i0] - U1[i0]; \ + By = U0[i1] - U1[i1]; \ + Cx = V0[i0] - U0[i0]; \ + Cy = V0[i1] - U0[i1]; \ + f = Ay*Bx - Ax*By; \ + d = By*Cx - Bx*Cy; \ + if((f>0.0f && d>=0.0f && d<=f) || (f<0.0f && d<=0.0f && d>=f)) \ + { \ + const float e=Ax*Cy - Ay*Cx; \ + if(f>0.0f) \ + { \ + if(e>=0.0f && e<=f) return TRUE; \ + } \ + else \ + { \ + if(e<=0.0f && e>=f) return TRUE; \ + } \ + } + +//! TO BE DOCUMENTED +#define EDGE_AGAINST_TRI_EDGES(V0, V1, U0, U1, U2) \ +{ \ + float Bx,By,Cx,Cy,d,f; \ + const float Ax = V1[i0] - V0[i0]; \ + const float Ay = V1[i1] - V0[i1]; \ + /* test edge U0,U1 against V0,V1 */ \ + EDGE_EDGE_TEST(V0, U0, U1); \ + /* test edge U1,U2 against V0,V1 */ \ + EDGE_EDGE_TEST(V0, U1, U2); \ + /* test edge U2,U1 against V0,V1 */ \ + EDGE_EDGE_TEST(V0, U2, U0); \ +} + +//! TO BE DOCUMENTED +#define POINT_IN_TRI(V0, U0, U1, U2) \ +{ \ + /* is T1 completly inside T2? */ \ + /* check if V0 is inside tri(U0,U1,U2) */ \ + float a = U1[i1] - U0[i1]; \ + float b = -(U1[i0] - U0[i0]); \ + float c = -a*U0[i0] - b*U0[i1]; \ + float d0 = a*V0[i0] + b*V0[i1] + c; \ + \ + a = U2[i1] - U1[i1]; \ + b = -(U2[i0] - U1[i0]); \ + c = -a*U1[i0] - b*U1[i1]; \ + const float d1 = a*V0[i0] + b*V0[i1] + c; \ + \ + a = U0[i1] - U2[i1]; \ + b = -(U0[i0] - U2[i0]); \ + c = -a*U2[i0] - b*U2[i1]; \ + const float d2 = a*V0[i0] + b*V0[i1] + c; \ + if(d0*d1>0.0f) \ + { \ + if(d0*d2>0.0f) return TRUE; \ + } \ +} + +//! TO BE DOCUMENTED +BOOL CoplanarTriTri(const Point& n, const Point& v0, const Point& v1, const Point& v2, const Point& u0, const Point& u1, const Point& u2) +{ + float A[3]; + short i0,i1; + /* first project onto an axis-aligned plane, that maximizes the area */ + /* of the triangles, compute indices: i0,i1. */ + A[0] = fabsf(n[0]); + A[1] = fabsf(n[1]); + A[2] = fabsf(n[2]); + if(A[0]>A[1]) + { + if(A[0]>A[2]) + { + i0=1; /* A[0] is greatest */ + i1=2; + } + else + { + i0=0; /* A[2] is greatest */ + i1=1; + } + } + else /* A[0]<=A[1] */ + { + if(A[2]>A[1]) + { + i0=0; /* A[2] is greatest */ + i1=1; + } + else + { + i0=0; /* A[1] is greatest */ + i1=2; + } + } + + /* test all edges of triangle 1 against the edges of triangle 2 */ + EDGE_AGAINST_TRI_EDGES(v0, v1, u0, u1, u2); + EDGE_AGAINST_TRI_EDGES(v1, v2, u0, u1, u2); + EDGE_AGAINST_TRI_EDGES(v2, v0, u0, u1, u2); + + /* finally, test if tri1 is totally contained in tri2 or vice versa */ + POINT_IN_TRI(v0, u0, u1, u2); + POINT_IN_TRI(u0, v0, v1, v2); + + return FALSE; +} + +//! TO BE DOCUMENTED +#define NEWCOMPUTE_INTERVALS(VV0, VV1, VV2, D0, D1, D2, D0D1, D0D2, A, B, C, X0, X1) \ +{ \ + if(D0D1>0.0f) \ + { \ + /* here we know that D0D2<=0.0 */ \ + /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ + A=VV2; B=(VV0 - VV2)*D2; C=(VV1 - VV2)*D2; X0=D2 - D0; X1=D2 - D1; \ + } \ + else if(D0D2>0.0f) \ + { \ + /* here we know that d0d1<=0.0 */ \ + A=VV1; B=(VV0 - VV1)*D1; C=(VV2 - VV1)*D1; X0=D1 - D0; X1=D1 - D2; \ + } \ + else if(D1*D2>0.0f || D0!=0.0f) \ + { \ + /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ + A=VV0; B=(VV1 - VV0)*D0; C=(VV2 - VV0)*D0; X0=D0 - D1; X1=D0 - D2; \ + } \ + else if(D1!=0.0f) \ + { \ + A=VV1; B=(VV0 - VV1)*D1; C=(VV2 - VV1)*D1; X0=D1 - D0; X1=D1 - D2; \ + } \ + else if(D2!=0.0f) \ + { \ + A=VV2; B=(VV0 - VV2)*D2; C=(VV1 - VV2)*D2; X0=D2 - D0; X1=D2 - D1; \ + } \ + else \ + { \ + /* triangles are coplanar */ \ + return CoplanarTriTri(N1, V0, V1, V2, U0, U1, U2); \ + } \ +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Triangle/triangle intersection test routine, + * by Tomas Moller, 1997. + * See article "A Fast Triangle-Triangle Intersection Test", + * Journal of Graphics Tools, 2(2), 1997 + * + * Updated June 1999: removed the divisions -- a little faster now! + * Updated October 1999: added {} to CROSS and SUB macros + * + * int NoDivTriTriIsect(float V0[3],float V1[3],float V2[3], + * float U0[3],float U1[3],float U2[3]) + * + * \param V0 [in] triangle 0, vertex 0 + * \param V1 [in] triangle 0, vertex 1 + * \param V2 [in] triangle 0, vertex 2 + * \param U0 [in] triangle 1, vertex 0 + * \param U1 [in] triangle 1, vertex 1 + * \param U2 [in] triangle 1, vertex 2 + * \return true if triangles overlap + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +inline_ BOOL AABBTreeCollider::TriTriOverlap(const Point& V0, const Point& V1, const Point& V2, const Point& U0, const Point& U1, const Point& U2) +{ + // Stats + mNbPrimPrimTests++; + + // Compute plane equation of triangle(V0,V1,V2) + Point E1 = V1 - V0; + Point E2 = V2 - V0; + const Point N1 = E1 ^ E2; + const float d1 =-N1 | V0; + // Plane equation 1: N1.X+d1=0 + + // Put U0,U1,U2 into plane equation 1 to compute signed distances to the plane + float du0 = (N1|U0) + d1; + float du1 = (N1|U1) + d1; + float du2 = (N1|U2) + d1; + + // Coplanarity robustness check +#ifdef OPC_TRITRI_EPSILON_TEST + if(fabsf(du0)0.0f && du0du2>0.0f) // same sign on all of them + not equal 0 ? + return FALSE; // no intersection occurs + + // Compute plane of triangle (U0,U1,U2) + E1 = U1 - U0; + E2 = U2 - U0; + const Point N2 = E1 ^ E2; + const float d2=-N2 | U0; + // plane equation 2: N2.X+d2=0 + + // put V0,V1,V2 into plane equation 2 + float dv0 = (N2|V0) + d2; + float dv1 = (N2|V1) + d2; + float dv2 = (N2|V2) + d2; + +#ifdef OPC_TRITRI_EPSILON_TEST + if(fabsf(dv0)0.0f && dv0dv2>0.0f) // same sign on all of them + not equal 0 ? + return FALSE; // no intersection occurs + + // Compute direction of intersection line + const Point D = N1^N2; + + // Compute and index to the largest component of D + float max=fabsf(D[0]); + short index=0; + float bb=fabsf(D[1]); + float cc=fabsf(D[2]); + if(bb>max) {max=bb;index=1;} + if(cc>max) {max=cc;index=2;} + + // This is the simplified projection onto L + const float vp0 = V0[index]; + const float vp1 = V1[index]; + const float vp2 = V2[index]; + + const float up0 = U0[index]; + const float up1 = U1[index]; + const float up2 = U2[index]; + + // Compute interval for triangle 1 + float a,b,c,x0,x1; + NEWCOMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,a,b,c,x0,x1); + + // Compute interval for triangle 2 + float d,e,f,y0,y1; + NEWCOMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,d,e,f,y0,y1); + + const float xx=x0*x1; + const float yy=y0*y1; + const float xxyy=xx*yy; + + float isect1[2], isect2[2]; + + float tmp=a*xxyy; + isect1[0]=tmp+b*x1*yy; + isect1[1]=tmp+c*x0*yy; + + tmp=d*xxyy; + isect2[0]=tmp+e*xx*y1; + isect2[1]=tmp+f*xx*y0; + + SORT(isect1[0],isect1[1]); + SORT(isect2[0],isect2[1]); + + if(isect1[1]HasPosLeaf()) mTouchedPrimitives->Add(node->GetPosPrimitive()); \ + else _Dump(node->GetPos()); \ + \ + if(ContactFound()) return; \ + \ + if(node->HasNegLeaf()) mTouchedPrimitives->Add(node->GetNegPrimitive()); \ + else _Dump(node->GetNeg()); \ +} + +#define IMPLEMENT_LEAFDUMP(type) \ +void VolumeCollider::_Dump(const type* node) \ +{ \ + if(node->IsLeaf()) \ + { \ + mTouchedPrimitives->Add(node->GetPrimitive()); \ + } \ + else \ + { \ + _Dump(node->GetPos()); \ + \ + if(ContactFound()) return; \ + \ + _Dump(node->GetNeg()); \ + } \ +} + +IMPLEMENT_NOLEAFDUMP(AABBNoLeafNode) +IMPLEMENT_NOLEAFDUMP(AABBQuantizedNoLeafNode) + +IMPLEMENT_LEAFDUMP(AABBCollisionNode) +IMPLEMENT_LEAFDUMP(AABBQuantizedNode) diff --git a/src/external/open_dynamics_engine-ef/ode/OPC_VolumeCollider.h b/src/external/open_dynamics_engine-ef/ode/OPC_VolumeCollider.h new file mode 100644 index 00000000..c0b812e7 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/OPC_VolumeCollider.h @@ -0,0 +1,138 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Contains base volume collider class. + * \file OPC_VolumeCollider.h + * \author Pierre Terdiman + * \date June, 2, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPC_VOLUMECOLLIDER_H__ +#define __OPC_VOLUMECOLLIDER_H__ + + struct OPCODE_API VolumeCache + { + VolumeCache() : Model(null) {} + ~VolumeCache() {} + + Container TouchedPrimitives; //!< Indices of touched primitives + const BaseModel* Model; //!< Owner + }; + + class OPCODE_API VolumeCollider : public Collider + { + public: + // Constructor / Destructor + VolumeCollider(); + virtual ~VolumeCollider() = 0; + + // Collision report + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the number of touched primitives after a collision query. + * \see GetContactStatus() + * \see GetTouchedPrimitives() + * \return the number of touched primitives + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbTouchedPrimitives() const { return mTouchedPrimitives ? mTouchedPrimitives->GetNbEntries() : 0; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Gets the list of touched primitives after a collision query. + * \see GetContactStatus() + * \see GetNbTouchedPrimitives() + * \return the list of touched primitives (primitive indices) + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ const udword* GetTouchedPrimitives() const { return mTouchedPrimitives ? mTouchedPrimitives->GetEntries() : null; } + + // Stats + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of Volume-BV overlap tests after a collision query. + * \see GetNbVolumePrimTests() + * \return the number of Volume-BV tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbVolumeBVTests() const { return mNbVolumeBVTests; } + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Stats: gets the number of Volume-Triangle overlap tests after a collision query. + * \see GetNbVolumeBVTests() + * \return the number of Volume-Triangle tests performed during last query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + inline_ udword GetNbVolumePrimTests() const { return mNbVolumePrimTests; } + + // Settings + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Validates current settings. You should call this method after all the settings / callbacks have been defined for a collider. + * \return null if everything is ok, else a string describing the problem + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(Collider) const char* ValidateSettings(); + + protected: + // Touched primitives + Container* mTouchedPrimitives; //!< List of touched primitives + + // Dequantization coeffs + Point mCenterCoeff; + Point mExtentsCoeff; + // Stats + udword mNbVolumeBVTests; //!< Number of Volume-BV tests + udword mNbVolumePrimTests; //!< Number of Volume-Primitive tests + // Internal methods + void _Dump(const AABBCollisionNode* node); + void _Dump(const AABBNoLeafNode* node); + void _Dump(const AABBQuantizedNode* node); + void _Dump(const AABBQuantizedNoLeafNode* node); + + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Initializes a query + */ + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + override(Collider) inline_ void InitQuery() + { + // Reset stats & contact status + mNbVolumeBVTests = 0; + mNbVolumePrimTests = 0; + Collider::InitQuery(); + } + + inline_ BOOL IsCacheValid(VolumeCache& cache) + { + // We're going to do a volume-vs-model query. + if(cache.Model!=mCurrentModel) + { + // Cached list was for another model so we can't keep it + // Keep track of new owner and reset cache + cache.Model = mCurrentModel; + return FALSE; + } + else + { + // Same models, no problem + return TRUE; + } + } + }; + +#endif // __OPC_VOLUMECOLLIDER_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/Opcode.cpp b/src/external/open_dynamics_engine-ef/ode/Opcode.cpp new file mode 100644 index 00000000..e52e4aae --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/Opcode.cpp @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main file for Opcode.dll. + * \file Opcode.cpp + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/* + Finding a good name is difficult! + Here's the draft for this lib.... Spooky, uh? + + VOID? Very Optimized Interference Detection + ZOID? Zappy's Optimized Interference Detection + CID? Custom/Clever Interference Detection + AID / ACID! Accurate Interference Detection + QUID? Quick Interference Detection + RIDE? Realtime Interference DEtection + WIDE? Wicked Interference DEtection (....) + GUID! + KID ! k-dop interference detection :) + OPCODE! OPtimized COllision DEtection +*/ + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Precompiled Header +#include "OPC_Stdafx.h" + +bool Opcode::InitOpcode() +{ + Log("// Initializing OPCODE\n\n"); +// LogAPIInfo(); + return true; +} + +void ReleasePruningSorters(); +bool Opcode::CloseOpcode() +{ + Log("// Closing OPCODE\n\n"); + + ReleasePruningSorters(); + + return true; +} + +#ifdef ICE_MAIN + +void ModuleAttach(HINSTANCE hinstance) +{ +} + +void ModuleDetach() +{ +} + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode.cpp b/src/external/open_dynamics_engine-ef/ode/ode.cpp new file mode 100644 index 00000000..848216d5 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode.cpp @@ -0,0 +1,1827 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifdef _MSC_VER +#pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" +#endif + +// this source file is mostly concerned with the data structures, not the +// numerics. + +#include "ode/ode_objects_private.h" +#include "ode/ode.h" +#include "ode/ode_joint.h" +#include "ode/ode_math.h" +#include "ode/ode_matrix.h" +#include "ode/ode_step.h" +#include "ode/ode_quickstep.h" +#include "ode/ode_util.h" +#include "ode/ode_memory.h" +#include "ode/ode_error.h" + +// misc defines +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// utility + + +//////////////////// ERIC TEST STUFFF + +#if VALUE_TESTING +FILE *f = NULL; + +bool testLogging = false; + +void odeTestEnableLogging() +{ + testLogging = true; + //fprintf(f,"log test\n"); +} + +void odeTestDisableLogging() +{ + testLogging = false; + //fprintf(f,"log test end\n"); +} + +#define PRINT_ARRAY(a,b) {for (int i = 0; i < b; i++) fprintf(f," %f",a[i]); fprintf(f,"\n");} + +//#define PRINT_DBL_HEX(x) {int *poo = (int*)&(x); fprintf(f,"0x%X%X\n",poo[0],poo[1]);} +void printBody(dxBody* b, int index) +{ + fprintf(f,"body %d\n", index); + fprintf(f," flags: %d\n",b->flags); + //fprintf(f," geomID: %x\n",b->geom); + fprintf(f," mass.mass: %x\n",b->mass.mass); //can check more + fprintf(f," mass.c: "); PRINT_ARRAY(b->mass.c,4); + fprintf(f," mass.I: "); PRINT_ARRAY(b->mass.I,12); + fprintf(f," invI: "); PRINT_ARRAY(b->invI,12); + fprintf(f," invMass: %f ",b->invMass); + fprintf(f," "); PRINT_DBL_HEX(b->invMass); + fprintf(f," pos: %f %f %f\n",b->pos[0],b->pos[1],b->pos[2]); + fprintf(f," p1"); PRINT_DBL_HEX(b->pos[0]); + fprintf(f," p2"); PRINT_DBL_HEX(b->pos[1]); + fprintf(f," p3"); PRINT_DBL_HEX(b->pos[2]); + fprintf(f," quat: %f %f %f %f\n",b->q[0],b->q[1],b->q[2],b->q[3]); + fprintf(f," q0"); PRINT_DBL_HEX(b->q[0]); + fprintf(f," q1"); PRINT_DBL_HEX(b->q[1]); + fprintf(f," q2"); PRINT_DBL_HEX(b->q[2]); + fprintf(f," q3"); PRINT_DBL_HEX(b->q[3]); + fprintf(f," rotMat: "); PRINT_ARRAY(b->R,12); + fprintf(f," lvel: %f %f %f\n",b->lvel[0],b->lvel[1],b->lvel[2]); + fprintf(f," lvel1"); PRINT_DBL_HEX(b->lvel[0]); + fprintf(f," lvel2"); PRINT_DBL_HEX(b->lvel[1]); + fprintf(f," lvel3"); PRINT_DBL_HEX(b->lvel[2]); + fprintf(f," avel: %f %f %f\n",b->avel[0],b->avel[1],b->avel[2]); + fprintf(f," avel1"); PRINT_DBL_HEX(b->avel[0]); + fprintf(f," avel2"); PRINT_DBL_HEX(b->avel[1]); + fprintf(f," avel3"); PRINT_DBL_HEX(b->avel[2]); + fprintf(f," facc: %f %f %f\n",b->facc[0],b->facc[1],b->facc[2]); + fprintf(f," facc1"); PRINT_DBL_HEX(b->facc[0]); + fprintf(f," facc2"); PRINT_DBL_HEX(b->facc[1]); + fprintf(f," facc3"); PRINT_DBL_HEX(b->facc[2]); + fprintf(f," tacc: %f %f %f\n",b->tacc[0],b->tacc[1],b->tacc[2]); + fprintf(f," tacc1"); PRINT_DBL_HEX(b->tacc[0]); + fprintf(f," tacc2"); PRINT_DBL_HEX(b->tacc[1]); + fprintf(f," tacc3"); PRINT_DBL_HEX(b->tacc[2]); + fprintf(f," finite_rot_axis: %f %f %f\n",b->finite_rot_axis[0], + b->finite_rot_axis[1], + b->finite_rot_axis[2]); +} + +void printJoint(dxJoint* j, int index) +{ + fprintf(f,"joint %d\n",index); + + //fprintf(f," fps: %d\n",j->fps); + + dxJoint::Info2 i2; + //dxJoint::Info1 i1; + + //fprintf(f," vtable: %x\n",j->vtable); + fprintf(f," vtable.size: %d\n",j->vtable->size); + //fprintf(f," vtable.getInfo1_fn %x\n",j->vtable->getInfo1); + //fprintf(f," vtable.getInfo2_fn %x\n",j->vtable->getInfo2); + +// j->lambda[0] = 0.0; +// j->lambda[1] = 0.0; +// j->lambda[2] = 0.0; +// j->lambda[3] = 0.0; +// j->lambda[4] = 0.0; +// j->lambda[5] = 0.0; + + fprintf(f," lambda: "); PRINT_ARRAY(j->lambda,6); + + //j->vtable->getInfo1(j,&i1); + //j->vtable->getInfo2(j,&i2); + + //fprintf(f," vtable: %x\n",j->vtable); + +} + +FILE *printODEState(dxWorld *w, int fileNum) +{ + + //double test = 1.0/24.563; + //int *t2 = (int*)&test; + + //printf("test is %f\n",test); + //printf("hex it is 0x%X%X\n",t2[0],t2[1]); + char fname[256]; + snprintf(fname,sizeof(fname),"/home/ecfroeml/Desktop/test%d.txt",fileNum); + + f = fopen(fname,"w"); + if (!f){ + printf("couldnt open file: %s\n", fname); + fflush(stdout); + // cout << "couldnt open file: " << fname << endl; + return NULL; + } + + dxBody *b; + dxJoint *j; + int n = 0; + for (b=w->firstbody; b; b=(dxBody*)b->next){ + n++; + printBody(b,n - 1); + } + if (w->nb != n) dDebug (0,"body count incorrect"); + //cout << "bodyCount: " << n << endl; + n = 0; + for (j=w->firstjoint; j; j=(dxJoint*)j->next){ + n++; + printJoint(j, n - 1); + } + + return f; +} +#endif + +/////////////////// END ERIC TEST STUFF + +static inline void initObject (dObject *obj, dxWorld *w) +{ + obj->world = w; + obj->next = 0; + obj->tome = 0; + obj->userdata = 0; + obj->tag = 0; +} + + +// add an object `obj' to the list who's head pointer is pointed to by `first'. + +static inline void addObjectToList (dObject *obj, dObject **first) +{ + obj->next = *first; + obj->tome = first; + if (*first) (*first)->tome = &obj->next; + (*first) = obj; +} + + +// remove the object from the linked list + +static inline void removeObjectFromList (dObject *obj) +{ + if (obj->next) obj->next->tome = obj->tome; + *(obj->tome) = obj->next; + // safeguard + obj->next = 0; + obj->tome = 0; +} + + +// remove the joint from neighbour lists of all connected bodies + +static void removeJointReferencesFromAttachedBodies (dxJoint *j) +{ + for (int i=0; i<2; i++) { + dxBody *body = j->node[i].body; + if (body) { + dxJointNode *n = body->firstjoint; + dxJointNode *last = 0; + while (n) { + if (n->joint == j) { + if (last) last->next = n->next; + else body->firstjoint = n->next; + break; + } + last = n; + n = n->next; + } + } + } + j->node[0].body = 0; + j->node[0].next = 0; + j->node[1].body = 0; + j->node[1].next = 0; +} + +//**************************************************************************** +// debugging + +// see if an object list loops on itself (if so, it's bad). + +static int listHasLoops (dObject *first) +{ + if (first==0 || first->next==0) return 0; + dObject *a=first,*b=first->next; + int skip=0; + while (b) { + if (a==b) return 1; + b = b->next; + if (skip) a = a->next; + skip ^= 1; + } + return 0; +} + + +// check the validity of the world data structures + +static void checkWorld (dxWorld *w) +{ + dxBody *b; + dxJoint *j; + + // check there are no loops + if (listHasLoops (w->firstbody)) dDebug (0,"body list has loops"); + if (listHasLoops (w->firstjoint)) dDebug (0,"joint list has loops"); + + // check lists are well formed (check `tome' pointers) + for (b=w->firstbody; b; b=(dxBody*)b->next) { + if (b->next && b->next->tome != &b->next) + dDebug (0,"bad tome pointer in body list"); + } + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->next && j->next->tome != &j->next) + dDebug (0,"bad tome pointer in joint list"); + } + + // check counts + int n = 0; + for (b=w->firstbody; b; b=(dxBody*)b->next){ + n++; + //printBody(b,n - 1); + } + if (w->nb != n) dDebug (0,"body count incorrect"); + //cout << "bodyCount: " << n << endl; + n = 0; + for (j=w->firstjoint; j; j=(dxJoint*)j->next){ + n++; + //printJoint(j, n - 1); + } + if (w->nj != n) dDebug (0,"joint count incorrect"); + //cout << "jointCount: " << n << endl; + + //fclose(f); + //} + + // set all tag values to a known value + static int count = 0; + count++; + for (b=w->firstbody; b; b=(dxBody*)b->next) b->tag = count; + for (j=w->firstjoint; j; j=(dxJoint*)j->next) j->tag = count; + + // check all body/joint world pointers are ok + for (b=w->firstbody; b; b=(dxBody*)b->next)if (b->world != w) + dDebug (0,"bad world pointer in body list"); + for (j=w->firstjoint; j; j=(dxJoint*)j->next) if (j->world != w) + dDebug (0,"bad world pointer in joint list"); + + /* + // check for half-connected joints - actually now these are valid + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->node[0].body || j->node[1].body) { + if (!(j->node[0].body && j->node[1].body)) + dDebug (0,"half connected joint found"); + } + } + */ + + // check that every joint node appears in the joint lists of both bodies it + // attaches + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + for (int i=0; i<2; i++) { + if (j->node[i].body) { + int ok = 0; + for (dxJointNode *n=j->node[i].body->firstjoint; n; n=n->next) { + if (n->joint == j) ok = 1; + } + if (ok==0) dDebug (0,"joint not in joint list of attached body"); + } + } + } + + // check all body joint lists (correct body ptrs) + for (b=w->firstbody; b; b=(dxBody*)b->next) { + for (dxJointNode *n=b->firstjoint; n; n=n->next) { + if (&n->joint->node[0] == n) { + if (n->joint->node[1].body != b) + dDebug (0,"bad body pointer in joint node of body list (1)"); + } + else { + if (n->joint->node[0].body != b) + dDebug (0,"bad body pointer in joint node of body list (2)"); + } + if (n->joint->tag != count) dDebug (0,"bad joint node pointer in body"); + } + } + + // check all body pointers in joints, check they are distinct + for (j=w->firstjoint; j; j=(dxJoint*)j->next) { + if (j->node[0].body && (j->node[0].body == j->node[1].body)) + dDebug (0,"non-distinct body pointers in joint"); + if ((j->node[0].body && j->node[0].body->tag != count) || + (j->node[1].body && j->node[1].body->tag != count)) + dDebug (0,"bad body pointer in joint"); + } +} + + +void dWorldCheck (dxWorld *w) +{ + checkWorld (w); +} + +//**************************************************************************** +// body + +dxBody *dBodyCreate (dxWorld *w) +{ + dAASSERT (w); + dxBody *b = new dxBody; + initObject (b,w); + b->firstjoint = 0; + b->flags = 0; + b->geom = 0; + dMassSetParameters (&b->mass,1,0,0,0,1,1,1,0,0,0); + dSetZero (b->invI,4*3); + b->invI[0] = 1; + b->invI[5] = 1; + b->invI[10] = 1; + b->invMass = 1; + dSetZero (b->pos,4); + dSetZero (b->q,4); + b->q[0] = 1; + dRSetIdentity (b->R); + dSetZero (b->lvel,4); + dSetZero (b->avel,4); + dSetZero (b->facc,4); + dSetZero (b->tacc,4); + dSetZero (b->finite_rot_axis,4); + addObjectToList (b,(dObject **) &w->firstbody); + w->nb++; + + // set auto-disable parameters + dBodySetAutoDisableDefaults (b); // must do this after adding to world + b->adis_stepsleft = b->adis.idle_steps; + b->adis_timeleft = b->adis.idle_time; + + return b; +} + + +void dBodyDestroy (dxBody *b) +{ + dAASSERT (b); + + // all geoms that link to this body must be notified that the body is about + // to disappear. note that the call to dGeomSetBody(geom,0) will result in + // dGeomGetBodyNext() returning 0 for the body, so we must get the next body + // before setting the body to 0. + dxGeom *next_geom = 0; + for (dxGeom *geom = b->geom; geom; geom = next_geom) { + next_geom = dGeomGetBodyNext (geom); + dGeomSetBody (geom,0); + } + + // detach all neighbouring joints, then delete this body. + dxJointNode *n = b->firstjoint; + while (n) { + // sneaky trick to speed up removal of joint references (black magic) + n->joint->node[(n == n->joint->node)].body = 0; + + dxJointNode *next = n->next; + n->next = 0; + removeJointReferencesFromAttachedBodies (n->joint); + n = next; + } + removeObjectFromList (b); + b->world->nb--; + delete b; +} + + +void dBodySetData (dBodyID b, void *data) +{ + dAASSERT (b); + b->userdata = data; +} + + +void *dBodyGetData (dBodyID b) +{ + dAASSERT (b); + return b->userdata; +} + + +void dBodySetPosition (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->pos[0] = x; + b->pos[1] = y; + b->pos[2] = z; + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + + +void dBodySetRotation (dBodyID b, const dMatrix3 R) +{ + dAASSERT (b && R); + dQuaternion q; + dRtoQ (R,q); + dNormalize4 (q); + b->q[0] = q[0]; + b->q[1] = q[1]; + b->q[2] = q[2]; + b->q[3] = q[3]; + dQtoR (b->q,b->R); + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + + +void dBodySetQuaternion (dBodyID b, const dQuaternion q) +{ + dAASSERT (b && q); + b->q[0] = q[0]; + b->q[1] = q[1]; + b->q[2] = q[2]; + b->q[3] = q[3]; + //dNormalize4 (b->q); + dQtoR (b->q,b->R); + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + + +void dBodySetLinearVel (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->lvel[0] = x; + b->lvel[1] = y; + b->lvel[2] = z; +} + + +void dBodySetAngularVel (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->avel[0] = x; + b->avel[1] = y; + b->avel[2] = z; +} + + +const dReal * dBodyGetPosition (dBodyID b) +{ + dAASSERT (b); + return b->pos; +} + + +const dReal * dBodyGetRotation (dBodyID b) +{ + dAASSERT (b); + return b->R; +} + + +const dReal * dBodyGetQuaternion (dBodyID b) +{ + dAASSERT (b); + return b->q; +} + + +const dReal * dBodyGetLinearVel (dBodyID b) +{ + dAASSERT (b); + return b->lvel; +} + + +const dReal * dBodyGetAngularVel (dBodyID b) +{ + dAASSERT (b); + return b->avel; +} + + +void dBodySetMass (dBodyID b, const dMass *mass) +{ + dAASSERT (b && mass); + memcpy (&b->mass,mass,sizeof(dMass)); + if (dInvertPDMatrix (b->mass.I,b->invI,3)==0) { + dDEBUGMSG ("inertia must be positive definite"); + dRSetIdentity (b->invI); + } + b->invMass = dRecip(b->mass.mass); +} + + +void dBodyGetMass (dBodyID b, dMass *mass) +{ + dAASSERT (b && mass); + memcpy (mass,&b->mass,sizeof(dMass)); +} + +#ifndef dNODEBUG +#define ERICF_MAX_FORCE_TEST 9999.0 +#define ERICF_MAX_TORQUE_TEST 9999.0 +static void printCrazyForce(float fx, float fy, float fz){ + printf("CRAAAZY FORCE BEING APPLIED!!!: %f %f %f\n",fx,fy,fz); +} +static void printCrazyTorque(float tx, float ty, float tz){ + printf("CRAAAZY TORQUE BEING APPLIED!!!: %f %f %f\n",tx,ty,tz); +} +#endif + +void dBodyAddForce (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_FORCE_TEST || dFabs(fy) > ERICF_MAX_FORCE_TEST || dFabs(fz) > ERICF_MAX_FORCE_TEST){ + printCrazyForce(fx,fy,fz); + } +# endif + + dAASSERT (b); + b->facc[0] += fx; + b->facc[1] += fy; + b->facc[2] += fz; +} + + +void dBodyAddTorque (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_TORQUE_TEST || dFabs(fy) > ERICF_MAX_TORQUE_TEST || dFabs(fz) > ERICF_MAX_TORQUE_TEST){ + printCrazyTorque(fx,fy,fz); + } +# endif + dAASSERT (b); + b->tacc[0] += fx; + b->tacc[1] += fy; + b->tacc[2] += fz; +} + + +void dBodyAddRelForce (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_FORCE_TEST || dFabs(fy) > ERICF_MAX_FORCE_TEST || dFabs(fz) > ERICF_MAX_FORCE_TEST){ + printCrazyForce(fx,fy,fz); + } +# endif + + dAASSERT (b); + dVector3 t1,t2; + t1[0] = fx; + t1[1] = fy; + t1[2] = fz; + t1[3] = 0; + dMULTIPLY0_331 (t2,b->R,t1); + b->facc[0] += t2[0]; + b->facc[1] += t2[1]; + b->facc[2] += t2[2]; +} + + +void dBodyAddRelTorque (dBodyID b, dReal fx, dReal fy, dReal fz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_TORQUE_TEST || dFabs(fy) > ERICF_MAX_TORQUE_TEST || dFabs(fz) > ERICF_MAX_TORQUE_TEST){ + printCrazyTorque(fx,fy,fz); + } +# endif + + dAASSERT (b); + dVector3 t1,t2; + t1[0] = fx; + t1[1] = fy; + t1[2] = fz; + t1[3] = 0; + dMULTIPLY0_331 (t2,b->R,t1); + b->tacc[0] += t2[0]; + b->tacc[1] += t2[1]; + b->tacc[2] += t2[2]; +} + + +void dBodyAddForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_FORCE_TEST || dFabs(fy) > ERICF_MAX_FORCE_TEST || dFabs(fz) > ERICF_MAX_FORCE_TEST){ + printCrazyForce(fx,fy,fz); + } +# endif + + dAASSERT (b); + b->facc[0] += fx; + b->facc[1] += fy; + b->facc[2] += fz; + dVector3 f,q; + f[0] = fx; + f[1] = fy; + f[2] = fz; + q[0] = px - b->pos[0]; + q[1] = py - b->pos[1]; + q[2] = pz - b->pos[2]; + dCROSS (b->tacc,+=,q,f); +} + + +void dBodyAddForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_FORCE_TEST || dFabs(fy) > ERICF_MAX_FORCE_TEST || dFabs(fz) > ERICF_MAX_FORCE_TEST){ + printCrazyForce(fx,fy,fz); + } +# endif + + dAASSERT (b); + dVector3 prel,f,p; + f[0] = fx; + f[1] = fy; + f[2] = fz; + f[3] = 0; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,b->R,prel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dCROSS (b->tacc,+=,p,f); +} + + +void dBodyAddRelForceAtPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_FORCE_TEST || dFabs(fy) > ERICF_MAX_FORCE_TEST || dFabs(fz) > ERICF_MAX_FORCE_TEST){ + printCrazyForce(fx,fy,fz); + } +# endif + + dAASSERT (b); + dVector3 frel,f; + frel[0] = fx; + frel[1] = fy; + frel[2] = fz; + frel[3] = 0; + dMULTIPLY0_331 (f,b->R,frel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dVector3 q; + q[0] = px - b->pos[0]; + q[1] = py - b->pos[1]; + q[2] = pz - b->pos[2]; + dCROSS (b->tacc,+=,q,f); +} + + +void dBodyAddRelForceAtRelPos (dBodyID b, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) +{ + // ericf tweak +# ifndef dNODEBUG + if (dFabs(fx) > ERICF_MAX_FORCE_TEST || dFabs(fy) > ERICF_MAX_FORCE_TEST || dFabs(fz) > ERICF_MAX_FORCE_TEST){ + printCrazyForce(fx,fy,fz); + } +# endif + + dAASSERT (b); + dVector3 frel,prel,f,p; + frel[0] = fx; + frel[1] = fy; + frel[2] = fz; + frel[3] = 0; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (f,b->R,frel); + dMULTIPLY0_331 (p,b->R,prel); + b->facc[0] += f[0]; + b->facc[1] += f[1]; + b->facc[2] += f[2]; + dCROSS (b->tacc,+=,p,f); +} + + +const dReal * dBodyGetForce (dBodyID b) +{ + dAASSERT (b); + return b->facc; +} + + +const dReal * dBodyGetTorque (dBodyID b) +{ + dAASSERT (b); + return b->tacc; +} + + +void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->facc[0] = x; + b->facc[1] = y; + b->facc[2] = z; +} + + +void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->tacc[0] = x; + b->tacc[1] = y; + b->tacc[2] = z; +} + + +void dBodyGetRelPointPos (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,b->R,prel); + result[0] = p[0] + b->pos[0]; + result[1] = p[1] + b->pos[1]; + result[2] = p[2] + b->pos[2]; +} + + +void dBodyGetRelPointVel (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,b->R,prel); + result[0] = b->lvel[0]; + result[1] = b->lvel[1]; + result[2] = b->lvel[2]; + dCROSS (result,+=,b->avel,p); +} + + +void dBodyGetPointVel (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px - b->pos[0]; + p[1] = py - b->pos[1]; + p[2] = pz - b->pos[2]; + p[3] = 0; + result[0] = b->lvel[0]; + result[1] = b->lvel[1]; + result[2] = b->lvel[2]; + dCROSS (result,+=,b->avel,p); +} + + +void dBodyGetPosRelPoint (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 prel; + prel[0] = px - b->pos[0]; + prel[1] = py - b->pos[1]; + prel[2] = pz - b->pos[2]; + prel[3] = 0; + dMULTIPLY1_331 (result,b->R,prel); +} + + +void dBodyVectorToWorld (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px; + p[1] = py; + p[2] = pz; + p[3] = 0; + dMULTIPLY0_331 (result,b->R,p); +} + + +void dBodyVectorFromWorld (dBodyID b, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (b); + dVector3 p; + p[0] = px; + p[1] = py; + p[2] = pz; + p[3] = 0; + dMULTIPLY1_331 (result,b->R,p); +} + + +void dBodySetFiniteRotationMode (dBodyID b, int mode) +{ + dAASSERT (b); + b->flags &= ~(dxBodyFlagFiniteRotation | dxBodyFlagFiniteRotationAxis); + if (mode) { + b->flags |= dxBodyFlagFiniteRotation; + if (b->finite_rot_axis[0] != 0 || b->finite_rot_axis[1] != 0 || + b->finite_rot_axis[2] != 0) { + b->flags |= dxBodyFlagFiniteRotationAxis; + } + } +} + + +void dBodySetFiniteRotationAxis (dBodyID b, dReal x, dReal y, dReal z) +{ + dAASSERT (b); + b->finite_rot_axis[0] = x; + b->finite_rot_axis[1] = y; + b->finite_rot_axis[2] = z; + if (x != 0 || y != 0 || z != 0) { + dNormalize3 (b->finite_rot_axis); + b->flags |= dxBodyFlagFiniteRotationAxis; + } + else { + b->flags &= ~dxBodyFlagFiniteRotationAxis; + } +} + + +int dBodyGetFiniteRotationMode (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyFlagFiniteRotation) != 0); +} + + +void dBodyGetFiniteRotationAxis (dBodyID b, dVector3 result) +{ + dAASSERT (b); + result[0] = b->finite_rot_axis[0]; + result[1] = b->finite_rot_axis[1]; + result[2] = b->finite_rot_axis[2]; +} + + +int dBodyGetNumJoints (dBodyID b) +{ + dAASSERT (b); + int count=0; + for (dxJointNode *n=b->firstjoint; n; n=n->next, count++); + return count; +} + + +dJointID dBodyGetJoint (dBodyID b, int index) +{ + dAASSERT (b); + int i=0; + for (dxJointNode *n=b->firstjoint; n; n=n->next, i++) { + if (i == index) return n->joint; + } + return 0; +} + + +void dBodyEnable (dBodyID b) +{ + dAASSERT (b); + b->flags &= ~dxBodyDisabled; + b->adis_stepsleft = b->adis.idle_steps; + b->adis_timeleft = b->adis.idle_time; +} + + +void dBodyDisable (dBodyID b) +{ + dAASSERT (b); + b->flags |= dxBodyDisabled; +} + + +int dBodyIsEnabled (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyDisabled) == 0); +} + + +void dBodySetGravityMode (dBodyID b, int mode) +{ + dAASSERT (b); + if (mode) b->flags &= ~dxBodyNoGravity; + else b->flags |= dxBodyNoGravity; +} + + +int dBodyGetGravityMode (dBodyID b) +{ + dAASSERT (b); + return ((b->flags & dxBodyNoGravity) == 0); +} + + +// body auto-disable functions + +dReal dBodyGetAutoDisableLinearThreshold (dBodyID b) +{ + dAASSERT(b); + return dSqrt (b->adis.linear_threshold); +} + + +void dBodySetAutoDisableLinearThreshold (dBodyID b, dReal linear_threshold) +{ + dAASSERT(b); + b->adis.linear_threshold = linear_threshold * linear_threshold; +} + + +dReal dBodyGetAutoDisableAngularThreshold (dBodyID b) +{ + dAASSERT(b); + return dSqrt (b->adis.angular_threshold); +} + + +void dBodySetAutoDisableAngularThreshold (dBodyID b, dReal angular_threshold) +{ + dAASSERT(b); + b->adis.angular_threshold = angular_threshold * angular_threshold; +} + + +int dBodyGetAutoDisableSteps (dBodyID b) +{ + dAASSERT(b); + return b->adis.idle_steps; +} + + +void dBodySetAutoDisableSteps (dBodyID b, int steps) +{ + dAASSERT(b); + b->adis.idle_steps = steps; +} + + +dReal dBodyGetAutoDisableTime (dBodyID b) +{ + dAASSERT(b); + return b->adis.idle_time; +} + + +void dBodySetAutoDisableTime (dBodyID b, dReal time) +{ + dAASSERT(b); + b->adis.idle_time = time; +} + + +int dBodyGetAutoDisableFlag (dBodyID b) +{ + dAASSERT(b); + return ((b->flags & dxBodyAutoDisable) != 0); +} + + +void dBodySetAutoDisableFlag (dBodyID b, int do_auto_disable) +{ + dAASSERT(b); + if (!do_auto_disable) b->flags &= ~dxBodyAutoDisable; + else b->flags |= dxBodyAutoDisable; +} + + +void dBodySetAutoDisableDefaults (dBodyID b) +{ + dAASSERT(b); + dWorldID w = b->world; + dAASSERT(w); + b->adis = w->adis; + dBodySetAutoDisableFlag (b, w->adis_flag); +} + +//**************************************************************************** +// joints + +static void dJointInit (dxWorld *w, dxJoint *j) +{ + dIASSERT (w && j); + initObject (j,w); + j->vtable = 0; + j->flags = 0; + j->node[0].joint = j; + j->node[0].body = 0; + j->node[0].next = 0; + j->node[1].joint = j; + j->node[1].body = 0; + j->node[1].next = 0; + dSetZero (j->lambda,6); + + // ericf temp + # ifndef dNODEBUG + j->jFixed = (dxJointFixed*)j; + j->jContact = (dxJointContact*)j; + j->jMotor = (dxJointAMotor*)j; + j->jFixedEricf = (JointFixedEF*)j; + #endif + + addObjectToList (j,(dObject **) &w->firstjoint); + w->nj++; +} + + +static dxJoint *createJoint (dWorldID w, dJointGroupID group, + dxJoint::Vtable *vtable) +{ + dIASSERT (w && vtable); + dxJoint *j; + if (group) { + j = (dxJoint*) group->stack.alloc (vtable->size); + group->num++; + } + else j = (dxJoint*) dAlloc (vtable->size); + dJointInit (w,j); + j->vtable = vtable; + if (group) j->flags |= dJOINT_INGROUP; + if (vtable->init) vtable->init (j); + j->feedback = 0; + return j; +} + + +dxJoint * dJointCreateBall (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dball_vtable); +} + + +dxJoint * dJointCreateHinge (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dhinge_vtable); +} + + +dxJoint * dJointCreateSlider (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dslider_vtable); +} + + +dxJoint * dJointCreateContact (dWorldID w, dJointGroupID group, + const dContact *c) +{ + dAASSERT (w && c); + dxJointContact *j = (dxJointContact *) + createJoint (w,group,&__dcontact_vtable); + j->contact = *c; + return j; +} + + +dxJoint * dJointCreateHinge2 (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dhinge2_vtable); +} + + +dxJoint * dJointCreateUniversal (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__duniversal_vtable); +} + + +dxJoint * dJointCreateFixed (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dfixed_vtable); +} + + +dxJoint * dJointCreateNull (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__dnull_vtable); +} + + +dxJoint * dJointCreateAMotor (dWorldID w, dJointGroupID group) +{ + dAASSERT (w); + return createJoint (w,group,&__damotor_vtable); +} + + +void dJointDestroy (dxJoint *j) +{ + dAASSERT (j); + if (j->flags & dJOINT_INGROUP) return; + removeJointReferencesFromAttachedBodies (j); + removeObjectFromList (j); + j->world->nj--; + dFree (j,j->vtable->size); +} + + +dJointGroupID dJointGroupCreate (int max_size) +{ + // not any more ... dUASSERT (max_size > 0,"max size must be > 0"); + dxJointGroup *group = new dxJointGroup; + group->num = 0; + return group; +} + + +void dJointGroupDestroy (dJointGroupID group) +{ + dAASSERT (group); + dJointGroupEmpty (group); + delete group; +} + + +void dJointGroupEmpty (dJointGroupID group) +{ + // the joints in this group are detached starting from the most recently + // added (at the top of the stack). this helps ensure that the various + // linked lists are not traversed too much, as the joints will hopefully + // be at the start of those lists. + // if any group joints have their world pointer set to 0, their world was + // previously destroyed. no special handling is required for these joints. + + dAASSERT (group); + int i; + dxJoint **jlist = (dxJoint**) ALLOCA (group->num * sizeof(dxJoint*)); + dxJoint *j = (dxJoint*) group->stack.rewind(); + for (i=0; i < group->num; i++) { + jlist[i] = j; + j = (dxJoint*) (group->stack.next (j->vtable->size)); + } + for (i=group->num-1; i >= 0; i--) { + if (jlist[i]->world) { + removeJointReferencesFromAttachedBodies (jlist[i]); + removeObjectFromList (jlist[i]); + jlist[i]->world->nj--; + } + } + group->num = 0; + group->stack.freeAll(); +} + + +void dJointAttach (dxJoint *joint, dxBody *body1, dxBody *body2) +{ + // check arguments + dUASSERT (joint,"bad joint argument"); + dUASSERT (body1 == 0 || body1 != body2,"can't have body1==body2"); + //dxWorld *world = joint->world; + dUASSERT ( (!body1 || body1->world == joint->world) && + (!body2 || body2->world == joint->world), + "joint and bodies must be in same world"); + + // check if the joint can not be attached to just one body + dUASSERT (!((joint->flags & dJOINT_TWOBODIES) && + ((body1 != 0) ^ (body2 != 0))), + "joint can not be attached to just one body"); + + // remove any existing body attachments + if (joint->node[0].body || joint->node[1].body) { + removeJointReferencesFromAttachedBodies (joint); + } + + // if a body is zero, make sure that it is body2, so 0 --> node[1].body + if (body1==0) { + body1 = body2; + body2 = 0; + joint->flags |= dJOINT_REVERSE; + } + else { + joint->flags &= (~dJOINT_REVERSE); + } + + // attach to new bodies + joint->node[0].body = body1; + joint->node[1].body = body2; + if (body1) { + joint->node[1].next = body1->firstjoint; + body1->firstjoint = &joint->node[1]; + } + else joint->node[1].next = 0; + if (body2) { + joint->node[0].next = body2->firstjoint; + body2->firstjoint = &joint->node[0]; + } + else { + joint->node[0].next = 0; + } +} + + +void dJointSetData (dxJoint *joint, void *data) +{ + dAASSERT (joint); + joint->userdata = data; +} + + +void *dJointGetData (dxJoint *joint) +{ + dAASSERT (joint); + return joint->userdata; +} + + +int dJointGetType (dxJoint *joint) +{ + dAASSERT (joint); + return joint->vtable->typenum; +} + + +dBodyID dJointGetBody (dxJoint *joint, int index) +{ + dAASSERT (joint); + if (index == 0 || index == 1) { + if (joint->flags & dJOINT_REVERSE) return joint->node[1-index].body; + else return joint->node[index].body; + } + else return 0; +} + + +void dJointSetFeedback (dxJoint *joint, dJointFeedback *f) +{ + dAASSERT (joint); + joint->feedback = f; +} + + +dJointFeedback *dJointGetFeedback (dxJoint *joint) +{ + dAASSERT (joint); + return joint->feedback; +} + + + +dJointID dConnectingJoint (dBodyID in_b1, dBodyID in_b2) +{ + dAASSERT (in_b1 || in_b2); + + dBodyID b1, b2; + + if (in_b1 == 0) { + b1 = in_b2; + b2 = in_b1; + } + else { + b1 = in_b1; + b2 = in_b2; + } + + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) return n->joint; + } + + return 0; +} + + + +int dConnectingJointList (dBodyID in_b1, dBodyID in_b2, dJointID* out_list) +{ + dAASSERT (in_b1 || in_b2); + + + dBodyID b1, b2; + + if (in_b1 == 0) { + b1 = in_b2; + b2 = in_b1; + } + else { + b1 = in_b1; + b2 = in_b2; + } + + // look through b1's neighbour list for b2 + int numConnectingJoints = 0; + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) + out_list[numConnectingJoints++] = n->joint; + } + + return numConnectingJoints; +} + + +int dAreConnected (dBodyID b1, dBodyID b2) +{ + dAASSERT (b1 && b2); + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (n->body == b2) return 1; + } + return 0; +} + + +int dAreConnectedExcluding (dBodyID b1, dBodyID b2, int joint_type) +{ + dAASSERT (b1 && b2); + // look through b1's neighbour list for b2 + for (dxJointNode *n=b1->firstjoint; n; n=n->next) { + if (dJointGetType (n->joint) != joint_type && n->body == b2) return 1; + } + return 0; +} + +int dWorldGetBodyCount(dxWorld *w) +{ + int count = 0; + dxBody *b = w->firstbody; + while (b) { + count++; + b = (dxBody*)b->next; + } + return count; +} + + +//**************************************************************************** +// world + +dxWorld * dWorldCreate() +{ + dxWorld *w = new dxWorld; + w->firstbody = 0; + w->firstjoint = 0; + w->nb = 0; + w->nj = 0; + dSetZero (w->gravity,4); + w->global_erp = REAL(0.2); +#if defined(dSINGLE) + w->global_cfm = 1e-5f; +#elif defined(dDOUBLE) + w->global_cfm = 1e-10; +#else + #error dSINGLE or dDOUBLE must be defined +#endif + + w->adis.linear_threshold = REAL(0.001)*REAL(0.001); // (magnitude squared) + w->adis.angular_threshold = REAL(0.001)*REAL(0.001); // (magnitude squared) + w->adis.idle_steps = 10; + w->adis.idle_time = 0; + w->adis_flag = 0; + + w->qs.num_iterations = 20; + w->qs.w = REAL(1.3); + + w->contactp.max_vel = dInfinity; + w->contactp.min_depth = 0; + + return w; +} + + +void dWorldDestroy (dxWorld *w) +{ + // delete all bodies and joints + dAASSERT (w); + dxBody *nextb, *b = w->firstbody; + while (b) { + nextb = (dxBody*) b->next; + delete b; + b = nextb; + } + dxJoint *nextj, *j = w->firstjoint; + while (j) { + nextj = (dxJoint*)j->next; + if (j->flags & dJOINT_INGROUP) { + // the joint is part of a group, so "deactivate" it instead + j->world = 0; + j->node[0].body = 0; + j->node[0].next = 0; + j->node[1].body = 0; + j->node[1].next = 0; + dMessage (0,"warning: destroying world containing grouped joints"); + } + else { + dFree (j,j->vtable->size); + } + j = nextj; + } + delete w; +} + + +void dWorldSetGravity (dWorldID w, dReal x, dReal y, dReal z) +{ + dAASSERT (w); + w->gravity[0] = x; + w->gravity[1] = y; + w->gravity[2] = z; +} + + +void dWorldGetGravity (dWorldID w, dVector3 g) +{ + dAASSERT (w); + g[0] = w->gravity[0]; + g[1] = w->gravity[1]; + g[2] = w->gravity[2]; +} + + +void dWorldSetERP (dWorldID w, dReal erp) +{ + dAASSERT (w); + w->global_erp = erp; +} + + +dReal dWorldGetERP (dWorldID w) +{ + dAASSERT (w); + return w->global_erp; +} + + +void dWorldSetCFM (dWorldID w, dReal cfm) +{ + dAASSERT (w); + w->global_cfm = cfm; +} + + +dReal dWorldGetCFM (dWorldID w) +{ + dAASSERT (w); + return w->global_cfm; +} + + +void dWorldStep (dWorldID w, dReal stepsize) +{ + dUASSERT (w,"bad world argument"); + dUASSERT (stepsize > 0,"stepsize must be > 0"); + dxProcessIslands (w,stepsize,&dInternalStepIsland); +} + +void dWorldQuickStep (dWorldID w, dReal stepsize) { + dUASSERT (w,"bad world argument"); + dUASSERT (stepsize > 0,"stepsize must be > 0"); + dxProcessIslands (w,stepsize,&dxQuickStepper); +} + +int dWorldGetQuickStepWarmStartingDataSize(dWorldID w) { + return 6 * w->nj; +} + +void dWorldGetQuickStepWarmStartingData(dWorldID w, dReal *data) { + dReal *a = data; + dxJoint *j; + for (j=w->firstjoint; j; j=(dxJoint*)j->next){ + for (int i = 0; i < 6; i++){ + *a = j->lambda[i]; + a++; + } + } +} + +void dWorldSetQuickStepWarmStartingData(dWorldID w, dReal *data) +{ + dReal *a = data; + dxJoint *j; + for (j=w->firstjoint; j; j=(dxJoint*)j->next){ + for (int i = 0; i < 6; i++){ + j->lambda[i] = *a; + a++; + } + } +} + + + + +void dWorldImpulseToForce (dWorldID w, dReal stepsize, + dReal ix, dReal iy, dReal iz, + dVector3 force) +{ + dAASSERT (w); + stepsize = dRecip(stepsize); + force[0] = stepsize * ix; + force[1] = stepsize * iy; + force[2] = stepsize * iz; + // @@@ force[3] = 0; +} + + +// world auto-disable functions + +dReal dWorldGetAutoDisableLinearThreshold (dWorldID w) +{ + dAASSERT(w); + return dSqrt (w->adis.linear_threshold); +} + + +void dWorldSetAutoDisableLinearThreshold (dWorldID w, dReal linear_threshold) +{ + dAASSERT(w); + w->adis.linear_threshold = linear_threshold * linear_threshold; +} + + +dReal dWorldGetAutoDisableAngularThreshold (dWorldID w) +{ + dAASSERT(w); + return dSqrt (w->adis.angular_threshold); +} + + +void dWorldSetAutoDisableAngularThreshold (dWorldID w, dReal angular_threshold) +{ + dAASSERT(w); + w->adis.angular_threshold = angular_threshold * angular_threshold; +} + + +int dWorldGetAutoDisableSteps (dWorldID w) +{ + dAASSERT(w); + return w->adis.idle_steps; +} + + +void dWorldSetAutoDisableSteps (dWorldID w, int steps) +{ + dAASSERT(w); + w->adis.idle_steps = steps; +} + + +dReal dWorldGetAutoDisableTime (dWorldID w) +{ + dAASSERT(w); + return w->adis.idle_time; +} + + +void dWorldSetAutoDisableTime (dWorldID w, dReal time) +{ + dAASSERT(w); + w->adis.idle_time = time; +} + + +int dWorldGetAutoDisableFlag (dWorldID w) +{ + dAASSERT(w); + return w->adis_flag; +} + + +void dWorldSetAutoDisableFlag (dWorldID w, int do_auto_disable) +{ + dAASSERT(w); + w->adis_flag = (do_auto_disable != 0); +} + + +void dWorldSetQuickStepNumIterations (dWorldID w, int num) +{ + dAASSERT(w); + w->qs.num_iterations = num; +} + + +int dWorldGetQuickStepNumIterations (dWorldID w) +{ + dAASSERT(w); + return w->qs.num_iterations; +} + + +void dWorldSetQuickStepW (dWorldID w, dReal param) +{ + dAASSERT(w); + w->qs.w = param; +} + + +dReal dWorldGetQuickStepW (dWorldID w) +{ + dAASSERT(w); + return w->qs.w; +} + + +void dWorldSetContactMaxCorrectingVel (dWorldID w, dReal vel) +{ + dAASSERT(w); + w->contactp.max_vel = vel; +} + + +dReal dWorldGetContactMaxCorrectingVel (dWorldID w) +{ + dAASSERT(w); + return w->contactp.max_vel; +} + + +void dWorldSetContactSurfaceLayer (dWorldID w, dReal depth) +{ + dAASSERT(w); + w->contactp.min_depth = depth; +} + + +dReal dWorldGetContactSurfaceLayer (dWorldID w) +{ + dAASSERT(w); + return w->contactp.min_depth; +} + +//**************************************************************************** +// testing + +#define NUM 100 + +#define DO(x) + + +extern "C" void dTestDataStructures() +{ + int i; + DO(printf ("testDynamicsStuff()\n")); + + dBodyID body [NUM]; + int nb = 0; + dJointID joint [NUM]; + int nj = 0; + + for (i=0; i 0.5) { + DO(printf ("creating body\n")); + body[nb] = dBodyCreate (w); + DO(printf ("\t--> %p\n",body[nb])); + nb++; + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + if (nj < NUM && nb > 2 && dRandReal() > 0.5) { + dBodyID b1 = body [dRand() % nb]; + dBodyID b2 = body [dRand() % nb]; + if (b1 != b2) { + DO(printf ("creating joint, attaching to %p,%p\n",b1,b2)); + joint[nj] = dJointCreateBall (w,0); + DO(printf ("\t-->%p\n",joint[nj])); + checkWorld (w); + dJointAttach (joint[nj],b1,b2); + nj++; + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + if (nj > 0 && nb > 2 && dRandReal() > 0.5) { + dBodyID b1 = body [dRand() % nb]; + dBodyID b2 = body [dRand() % nb]; + if (b1 != b2) { + int k = dRand() % nj; + DO(printf ("reattaching joint %p\n",joint[k])); + dJointAttach (joint[k],b1,b2); + checkWorld (w); + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + if (nb > 0 && dRandReal() > 0.5) { + int k = dRand() % nb; + DO(printf ("destroying body %p\n",body[k])); + dBodyDestroy (body[k]); + checkWorld (w); + for (; k < (NUM-1); k++) body[k] = body[k+1]; + nb--; + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + if (nj > 0 && dRandReal() > 0.5) { + int k = dRand() % nj; + DO(printf ("destroying joint %p\n",joint[k])); + dJointDestroy (joint[k]); + checkWorld (w); + for (; k < (NUM-1); k++) joint[k] = joint[k+1]; + nj--; + DO(printf ("%d BODIES, %d JOINTS\n",nb,nj)); + } + } + + /* + printf ("creating world\n"); + dWorldID w = dWorldCreate(); + checkWorld (w); + printf ("creating body\n"); + dBodyID b1 = dBodyCreate (w); + checkWorld (w); + printf ("creating body\n"); + dBodyID b2 = dBodyCreate (w); + checkWorld (w); + printf ("creating joint\n"); + dJointID j = dJointCreateBall (w); + checkWorld (w); + printf ("attaching joint\n"); + dJointAttach (j,b1,b2); + checkWorld (w); + printf ("destroying joint\n"); + dJointDestroy (j); + checkWorld (w); + printf ("destroying body\n"); + dBodyDestroy (b1); + checkWorld (w); + printf ("destroying body\n"); + dBodyDestroy (b2); + checkWorld (w); + printf ("destroying world\n"); + dWorldDestroy (w); + */ +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode.h b/src/external/open_dynamics_engine-ef/ode/ode.h new file mode 100644 index 00000000..a7257e1c --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode.h @@ -0,0 +1,47 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_ODE_H_ +#define _ODE_ODE_H_ + +/* include *everything* here */ + +#include "ode/ode_config.h" +#include "ode/ode_compatibility.h" +#include "ode/ode_common.h" +#include "ode/ode_contact.h" +#include "ode/ode_error.h" +#include "ode/ode_memory.h" +#include "ode/ode_math.h" +#include "ode/ode_matrix.h" +#include "ode/ode_timer.h" +#include "ode/ode_rotation.h" +#include "ode/ode_mass.h" +#include "ode/ode_misc.h" +#include "ode/ode_objects.h" +#include "ode/odecpp.h" +#include "ode/ode_collision_space.h" +#include "ode/ode_collision.h" +#include "ode/odecpp_collision.h" +#include "ode/ode_export-dif.h" + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_Opcode.h b/src/external/open_dynamics_engine-ef/ode/ode_Opcode.h new file mode 100644 index 00000000..3ac519e2 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_Opcode.h @@ -0,0 +1,113 @@ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/* + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +/** + * Main file for Opcode.dll. + * \file Opcode.h + * \author Pierre Terdiman + * \date March, 20, 2001 + */ +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Include Guard +#ifndef __OPCODE_H__ +#define __OPCODE_H__ + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Things to help us compile on non-windows platforms + +#if defined(__APPLE__) || defined(__MACOSX__) +#if __APPLE_CC__ < 1495 +#define sqrtf sqrt +#define sinf sin +#define cosf cos +#define acosf acos +#define asinf sinf +#endif +#endif + +#ifndef _MSC_VER + +#ifndef __int64 +#define __int64 long long int +#endif +#define __stdcall /* */ + +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Compilation messages +#ifdef _MSC_VER + #if defined(OPCODE_EXPORTS) + // #pragma message("Compiling OPCODE") + #elif !defined(OPCODE_EXPORTS) + // #pragma message("Using OPCODE") + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Automatic linking + #ifndef BAN_OPCODE_AUTOLINK + #ifdef _DEBUG + //#pragma comment(lib, "Opcode_D.lib") + #else + //#pragma comment(lib, "Opcode.lib") + #endif + #endif + #endif +#endif + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// Preprocessor +#ifndef ICE_NO_DLL + #ifdef OPCODE_EXPORTS + #define OPCODE_API// __declspec(dllexport) + #else + #define OPCODE_API// __declspec(dllimport) + #endif +#else + #define OPCODE_API +#endif + + #include "ode/OPC_IceHook.h" + + namespace Opcode + { + // Bulk-of-the-work + #include "ode/OPC_Settings.h" + #include "ode/OPC_Common.h" + #include "ode/OPC_MeshInterface.h" + // Builders + #include "ode/OPC_TreeBuilders.h" + // Trees + #include "ode/OPC_AABBTree.h" + #include "ode/OPC_OptimizedTree.h" + // Models + #include "ode/OPC_BaseModel.h" + #include "ode/OPC_Model.h" + #include "ode/OPC_HybridModel.h" + // Colliders + #include "ode/OPC_Collider.h" + #include "ode/OPC_VolumeCollider.h" + #include "ode/OPC_TreeCollider.h" + #include "ode/OPC_RayCollider.h" + #include "ode/OPC_SphereCollider.h" + #include "ode/OPC_OBBCollider.h" + #include "ode/OPC_AABBCollider.h" + #include "ode/OPC_LSSCollider.h" + #include "ode/OPC_PlanesCollider.h" + // Usages + #include "ode/OPC_Picking.h" + // Sweep-and-prune + #include "ode/OPC_BoxPruning.h" + #include "ode/OPC_SweepAndPrune.h" + + FUNCTION OPCODE_API bool InitOpcode(); + FUNCTION OPCODE_API bool CloseOpcode(); + } + +#endif // __OPCODE_H__ diff --git a/src/external/open_dynamics_engine-ef/ode/ode_array.cpp b/src/external/open_dynamics_engine-ef/ode/ode_array.cpp new file mode 100644 index 00000000..16dc9abf --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_array.cpp @@ -0,0 +1,80 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_config.h" +#include "ode/ode_memory.h" +#include "ode/ode_error.h" +#include "ode/ode_array.h" + + +static inline int roundUpToPowerOfTwo (int x) +{ + int i = 1; + while (i < x) i <<= 1; + return i; +} + + +void dArrayBase::_freeAll (int sizeofT) +{ + if (_data) { + if (_data == this+1) return; // if constructLocalArray() was called + dFree (_data,_anum * sizeofT); + } +} + + +void dArrayBase::_setSize (int newsize, int sizeofT) +{ + if (newsize < 0) return; + if (newsize > _anum) { + if (_data == this+1) { + // this is a no-no, because constructLocalArray() was called + dDebug (0,"setSize() out of space in LOCAL array"); + } + int newanum = roundUpToPowerOfTwo (newsize); + if (_data) _data = dRealloc (_data, _anum*sizeofT, newanum*sizeofT); + else _data = dAlloc (newanum*sizeofT); + _anum = newanum; + } + _size = newsize; +} + + +void * dArrayBase::operator new (size_t size) +{ + return dAlloc (size); +} + + +void dArrayBase::operator delete (void *ptr, size_t size) +{ + dFree (ptr,size); +} + + +void dArrayBase::constructLocalArray (int __anum) +{ + _size = 0; + _anum = __anum; + _data = this+1; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_array.h b/src/external/open_dynamics_engine-ef/ode/ode_array.h new file mode 100644 index 00000000..7835b631 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_array.h @@ -0,0 +1,135 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source. + * + * Variable sized array template. The array is always stored in a contiguous + * chunk. The array can be resized. A size increase will cause more memory + * to be allocated, and may result in relocation of the array memory. + * A size decrease has no effect on the memory allocation. + * + * Array elements with constructors or destructors are not supported! + * But if you must have such elements, here's what to know/do: + * - Bitwise copy is used when copying whole arrays. + * - When copying individual items (via push(), insert() etc) the `=' + * (equals) operator is used. Thus you should define this operator to do + * a bitwise copy. You should probably also define the copy constructor. + */ + + +#ifndef _ODE_ARRAY_H_ +#define _ODE_ARRAY_H_ + +#include "ode/ode_config.h" + + +// this base class has no constructors or destructor, for your convenience. + +class dArrayBase { +protected: + int _size; // number of elements in `data' + int _anum; // allocated number of elements in `data' + void *_data; // array data + + void _freeAll (int sizeofT); + void _setSize (int newsize, int sizeofT); + // set the array size to `newsize', allocating more memory if necessary. + // if newsize>_anum and is a power of two then this is guaranteed to + // set _size and _anum to newsize. + +public: + // not: dArrayBase () { _size=0; _anum=0; _data=0; } + + int size() const { return _size; } + int allocatedSize() const { return _anum; } + void * operator new (size_t size); + void operator delete (void *ptr, size_t size); + + void constructor() { _size=0; _anum=0; _data=0; } + // if this structure is allocated with malloc() instead of new, you can + // call this to set it up. + + void constructLocalArray (int __anum); + // this helper function allows non-reallocating arrays to be constructed + // on the stack (or in the heap if necessary). this is something of a + // kludge and should be used with extreme care. this function acts like + // a constructor - it is called on uninitialized memory that will hold the + // Array structure and the data. __anum is the number of elements that + // are allocated. the memory MUST be allocated with size: + // sizeof(ArrayBase) + __anum*sizeof(T) + // arrays allocated this way will never try to reallocate or free the + // memory - that's your job. +}; + + +template class dArray : public dArrayBase { +public: + void equals (const dArray &x) { + setSize (x.size()); + memcpy (_data,x._data,x._size * sizeof(T)); + } + + dArray () { constructor(); } + dArray (const dArray &x) { constructor(); equals (x); } + ~dArray () { _freeAll(sizeof(T)); } + void setSize (int newsize) { _setSize (newsize,sizeof(T)); } + T *data() const { return (T*) _data; } + T & operator[] (int i) const { return ((T*)_data)[i]; } + void operator = (const dArray &x) { equals (x); } + + void push (const T item) { + if (_size < _anum) _size++; else _setSize (_size+1,sizeof(T)); + memcpy (&(((T*)_data)[_size-1]), &item, sizeof(T)); + } + + void swap (dArray &x) { + int tmp1; + void *tmp2; + tmp1=_size; _size=x._size; x._size=tmp1; + tmp1=_anum; _anum=x._anum; x._anum=tmp1; + tmp2=_data; _data=x._data; x._data=tmp2; + } + + // insert the item at the position `i'. if i<0 then add the item to the + // start, if i >= size then add the item to the end of the array. + void insert (int i, const T item) { + if (_size < _anum) _size++; else _setSize (_size+1,sizeof(T)); + if (i >= (_size-1)) i = _size-1; // add to end + else { + if (i < 0) i=0; // add to start + int n = _size-1-i; + if (n>0) memmove (((T*)_data) + i+1, ((T*)_data) + i, n*sizeof(T)); + } + ((T*)_data)[i] = item; + } + + void remove (int i) { + if (i >= 0 && i < _size) { // passing this test guarantees size>0 + int n = _size-1-i; + if (n>0) memmove (((T*)_data) + i, ((T*)_data) + i+1, n*sizeof(T)); + _size--; + } + } +}; + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision.h b/src/external/open_dynamics_engine-ef/ode/ode_collision.h new file mode 100644 index 00000000..46b07161 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision.h @@ -0,0 +1,197 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_COLLISION_H_ +#define _ODE_COLLISION_H_ + +#include "ode/ode_common.h" +#include "ode/ode_collision_space.h" +#include "ode/ode_contact.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ************************************************************************ */ +/* general functions */ + +void dGeomDestroy (dGeomID); +void dGeomSetData (dGeomID, void *); +void *dGeomGetData (dGeomID); +void dGeomSetBody (dGeomID, dBodyID); +dBodyID dGeomGetBody (dGeomID); +void dGeomSetPosition (dGeomID, dReal x, dReal y, dReal z); +void dGeomSetRotation (dGeomID, const dMatrix3 R); +void dGeomSetQuaternion (dGeomID, const dQuaternion); +const dReal * dGeomGetPosition (dGeomID); +const dReal * dGeomGetRotation (dGeomID); +void dGeomGetRelPointPos (dGeomID g, dReal px, dReal py, dReal pz,dVector3 result); +void dGeomGetQuaternion (dGeomID, dQuaternion result); +void dGeomGetAABB (dGeomID, dReal aabb[6]); +int dGeomIsSpace (dGeomID); +dSpaceID dGeomGetSpace (dGeomID); +int dGeomGetClass (dGeomID); +void dGeomSetCategoryBits (dGeomID, unsigned long bits); +void dGeomSetCollideBits (dGeomID, unsigned long bits); +unsigned long dGeomGetCategoryBits (dGeomID); +unsigned long dGeomGetCollideBits (dGeomID); +void dGeomEnable (dGeomID); +void dGeomDisable (dGeomID); +int dGeomIsEnabled (dGeomID); + +/* ************************************************************************ */ +/* collision detection */ + +int dCollide (dGeomID o1, dGeomID o2, int flags, dContactGeom *contact, + int skip); +void dSpaceCollide (dSpaceID space, void *data, dNearCallback *callback); +void dSpaceCollide2 (dGeomID o1, dGeomID o2, void *data, + dNearCallback *callback); + +/* ************************************************************************ */ +/* standard classes */ + +/* the maximum number of user classes that are supported */ +enum { + dMaxUserClasses = 4 +}; + +/* class numbers - each geometry object needs a unique number */ +enum { + dSphereClass = 0, + dBoxClass, + dCCylinderClass, + dCylinderClass, + dPlaneClass, + dRayClass, + dGeomTransformClass, + dTriMeshClass, + + dFirstSpaceClass, + dSimpleSpaceClass = dFirstSpaceClass, + dHashSpaceClass, + dSweepAndPruneSpaceClass, // SAP + dQuadTreeSpaceClass, + dLastSpaceClass = dQuadTreeSpaceClass, + + dFirstUserClass, + dLastUserClass = dFirstUserClass + dMaxUserClasses - 1, + dGeomNumClasses +}; + + +dGeomID dCreateSphere (dSpaceID space, dReal radius); +void dGeomSphereSetRadius (dGeomID sphere, dReal radius); +dReal dGeomSphereGetRadius (dGeomID sphere); +dReal dGeomSpherePointDepth (dGeomID sphere, dReal x, dReal y, dReal z); + +dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz); +void dGeomBoxSetLengths (dGeomID box, dReal lx, dReal ly, dReal lz); +void dGeomBoxGetLengths (dGeomID box, dVector3 result); +dReal dGeomBoxPointDepth (dGeomID box, dReal x, dReal y, dReal z); + +dGeomID dCreatePlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); +void dGeomPlaneSetParams (dGeomID plane, dReal a, dReal b, dReal c, dReal d); +void dGeomPlaneGetParams (dGeomID plane, dVector4 result); +dReal dGeomPlanePointDepth (dGeomID plane, dReal x, dReal y, dReal z); + +dGeomID dCreateCCylinder (dSpaceID space, dReal radius, dReal length); +void dGeomCCylinderSetParams (dGeomID ccylinder, dReal radius, dReal length); +void dGeomCCylinderGetParams (dGeomID ccylinder, dReal *radius, dReal *length); +dReal dGeomCCylinderPointDepth (dGeomID ccylinder, dReal x, dReal y, dReal z); + +//new cylinder code +dGeomID dCreateCylinder (dSpaceID space, dReal radius, dReal length); +void dGeomCylinderSetParams (dGeomID cylinder, dReal radius, dReal length); +void dGeomCylinderGetParams (dGeomID cylinder, dReal *radius, dReal *length); +// end new cylinder code + +dGeomID dCreateRay (dSpaceID space, dReal length); +void dGeomRaySetLength (dGeomID ray, dReal length); +dReal dGeomRayGetLength (dGeomID ray); +void dGeomRaySet (dGeomID ray, dReal px, dReal py, dReal pz, + dReal dx, dReal dy, dReal dz); +void dGeomRayGet (dGeomID ray, dVector3 start, dVector3 dir); + +/* + * Set/get ray flags that influence ray collision detection. + * These flags are currently only noticed by the trimesh collider, because + * they can make a major differences there. + */ +void dGeomRaySetParams (dGeomID g, int FirstContact, int BackfaceCull); +void dGeomRayGetParams (dGeomID g, int *FirstContact, int *BackfaceCull); +void dGeomRaySetClosestHit (dGeomID g, int closestHit); +int dGeomRayGetClosestHit (dGeomID g); + +#include "ode/ode_collision_trimesh.h" + +dGeomID dCreateGeomTransform (dSpaceID space); +void dGeomTransformSetGeom (dGeomID g, dGeomID obj); +dGeomID dGeomTransformGetGeom (dGeomID g); +void dGeomTransformSetCleanup (dGeomID g, int mode); +int dGeomTransformGetCleanup (dGeomID g); +void dGeomTransformSetInfo (dGeomID g, int mode); +int dGeomTransformGetInfo (dGeomID g); + +/* ************************************************************************ */ +/* utility functions */ + +void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2, + const dVector3 b1, const dVector3 b2, + dVector3 cp1, dVector3 cp2); + +int dBoxTouchesBox (const dVector3 _p1, const dMatrix3 R1, + const dVector3 side1, const dVector3 _p2, + const dMatrix3 R2, const dVector3 side2); + +void dInfiniteAABB (dGeomID geom, dReal aabb[6]); +void dCloseODE(void); + +/* ************************************************************************ */ +/* custom classes */ + +typedef void dGetAABBFn (dGeomID, dReal aabb[6]); +typedef int dColliderFn (dGeomID o1, dGeomID o2, + int flags, dContactGeom *contact, int skip); +typedef dColliderFn * dGetColliderFnFn (int num); +typedef void dGeomDtorFn (dGeomID o); +typedef int dAABBTestFn (dGeomID o1, dGeomID o2, dReal aabb[6]); + +typedef struct dGeomClass { + int bytes; + dGetColliderFnFn *collider; + dGetAABBFn *aabb; + dAABBTestFn *aabb_test; + dGeomDtorFn *dtor; +} dGeomClass; + +int dCreateGeomClass (const dGeomClass *classptr); +void * dGeomGetClassData (dGeomID); +dGeomID dCreateGeom (int classnum); + +/* ************************************************************************ */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_box.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_box.cpp new file mode 100644 index 00000000..bf25bdfc --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_box.cpp @@ -0,0 +1,994 @@ +/************************************************************************* +* * +* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * +* All rights reserved. Email: russ@q12.org Web: www.q12.org * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of EITHER: * +* (1) The GNU Lesser General Public License as published by the Free * +* Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. The text of the GNU Lesser * +* General Public License is included with this library in the * +* file LICENSE.TXT. * +* (2) The BSD-style license that is included with this library in * +* the file LICENSE-BSD.TXT. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * +* LICENSE.TXT and LICENSE-BSD.TXT for more details. * +* * +*************************************************************************/ + +/* + * Cylinder-box collider by Alen Ladavac + * Ported to ODE by Nguyen Binh + */ + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" +#include "ode/ode_collision_kernel.h" + +static const int MAX_CYLBOX_CLIP_POINTS = 16; +static const int nCYLINDER_AXIS = 2; +// Number of segment of cylinder base circle. +// Must be divisible by 4. +static const int nCYLINDER_SEGMENT = 8; + +#define MAX_FLOAT dInfinity + +// Data that passed through the collider's functions +typedef struct _sCylinderBoxData +{ + // cylinder parameters + dMatrix3 mCylinderRot; + dVector3 vCylinderPos; + dVector3 vCylinderAxis; + dReal fCylinderRadius; + dReal fCylinderSize; + dVector3 avCylinderNormals[nCYLINDER_SEGMENT]; + + // box parameters + + dMatrix3 mBoxRot; + dVector3 vBoxPos; + dVector3 vBoxHalfSize; + // box vertices array : 8 vertices + dVector3 avBoxVertices[8]; + + // global collider data + dVector3 vDiff; + dVector3 vNormal; + dReal fBestDepth; + dReal fBestrb; + dReal fBestrc; + int iBestAxis; + + // contact data + dVector3 vEp0, vEp1; + dReal fDepth0, fDepth1; + + // ODE stuff + dGeomID gBox; + dGeomID gCylinder; + dContactGeom* gContact; + int iFlags; + int iSkip; + int nContacts; + +} sCylinderBoxData; + + +// initialize collision data +void _cldInitCylinderBox(sCylinderBoxData& cData) +{ + // get cylinder position, orientation + const dReal* pRotCyc = dGeomGetRotation(cData.gCylinder); + dMatrix3Copy(pRotCyc,cData.mCylinderRot); + + const dVector3* pPosCyc = (const dVector3*)dGeomGetPosition(cData.gCylinder); + dVector3Copy(*pPosCyc,cData.vCylinderPos); + + dMat3GetCol(cData.mCylinderRot,nCYLINDER_AXIS,cData.vCylinderAxis); + + // get cylinder radius and size + dGeomCylinderGetParams(cData.gCylinder,&cData.fCylinderRadius,&cData.fCylinderSize); + + // get box position, orientation, size + const dReal* pRotBox = dGeomGetRotation(cData.gBox); + dMatrix3Copy(pRotBox,cData.mBoxRot); + const dVector3* pPosBox = (const dVector3*)dGeomGetPosition(cData.gBox); + dVector3Copy(*pPosBox,cData.vBoxPos); + + dGeomBoxGetLengths(cData.gBox, cData.vBoxHalfSize); + cData.vBoxHalfSize[0] *= REAL(0.5); + cData.vBoxHalfSize[1] *= REAL(0.5); + cData.vBoxHalfSize[2] *= REAL(0.5); + + // vertex 0 + cData.avBoxVertices[0][0] = -cData.vBoxHalfSize[0]; + cData.avBoxVertices[0][1] = cData.vBoxHalfSize[1]; + cData.avBoxVertices[0][2] = -cData.vBoxHalfSize[2]; + + // vertex 1 + cData.avBoxVertices[1][0] = cData.vBoxHalfSize[0]; + cData.avBoxVertices[1][1] = cData.vBoxHalfSize[1]; + cData.avBoxVertices[1][2] = -cData.vBoxHalfSize[2]; + + // vertex 2 + cData.avBoxVertices[2][0] = -cData.vBoxHalfSize[0]; + cData.avBoxVertices[2][1] = -cData.vBoxHalfSize[1]; + cData.avBoxVertices[2][2] = -cData.vBoxHalfSize[2]; + + // vertex 3 + cData.avBoxVertices[3][0] = cData.vBoxHalfSize[0]; + cData.avBoxVertices[3][1] = -cData.vBoxHalfSize[1]; + cData.avBoxVertices[3][2] = -cData.vBoxHalfSize[2]; + + // vertex 4 + cData.avBoxVertices[4][0] = cData.vBoxHalfSize[0]; + cData.avBoxVertices[4][1] = cData.vBoxHalfSize[1]; + cData.avBoxVertices[4][2] = cData.vBoxHalfSize[2]; + + // vertex 5 + cData.avBoxVertices[5][0] = cData.vBoxHalfSize[0]; + cData.avBoxVertices[5][1] = -cData.vBoxHalfSize[1]; + cData.avBoxVertices[5][2] = cData.vBoxHalfSize[2]; + + // vertex 6 + cData.avBoxVertices[6][0] = -cData.vBoxHalfSize[0]; + cData.avBoxVertices[6][1] = -cData.vBoxHalfSize[1]; + cData.avBoxVertices[6][2] = cData.vBoxHalfSize[2]; + + // vertex 7 + cData.avBoxVertices[7][0] = -cData.vBoxHalfSize[0]; + cData.avBoxVertices[7][1] = cData.vBoxHalfSize[1]; + cData.avBoxVertices[7][2] = cData.vBoxHalfSize[2]; + + // temp index + int i = 0; + dVector3 vTempBoxVertices[8]; + // transform vertices in absolute space + for(i=0; i < 8; i++) + { + dMultiplyMat3Vec3(cData.mBoxRot,cData.avBoxVertices[i], vTempBoxVertices[i]); + dVector3Add(vTempBoxVertices[i], cData.vBoxPos, cData.avBoxVertices[i]); + } + + // find relative position + dVector3Subtract(cData.vCylinderPos,cData.vBoxPos,cData.vDiff); + cData.fBestDepth = MAX_FLOAT; + cData.vNormal[0] = REAL(0.0); + cData.vNormal[1] = REAL(0.0); + cData.vNormal[2] = REAL(0.0); + + // calculate basic angle for nCYLINDER_SEGMENT-gon + dReal fAngle = M_PI/nCYLINDER_SEGMENT; + + // calculate angle increment + dReal fAngleIncrement = fAngle * REAL(2.0); + + // calculate nCYLINDER_SEGMENT-gon points + for(i = 0; i < nCYLINDER_SEGMENT; i++) + { + cData.avCylinderNormals[i][0] = -dCos(fAngle); + cData.avCylinderNormals[i][1] = -dSin(fAngle); + cData.avCylinderNormals[i][2] = 0; + + fAngle += fAngleIncrement; + } + + cData.fBestrb = 0; + cData.fBestrc = 0; + cData.iBestAxis = 0; + cData.nContacts = 0; + +} + +// test for given separating axis +int _cldTestAxis(sCylinderBoxData& cData, dVector3& vInputNormal, int iAxis ) +{ + // check length of input normal + dReal fL = dVector3Length(vInputNormal); + // if not long enough + if ( fL < 1e-5f ) + { + // do nothing + return 1; + } + + // otherwise make it unit for sure + dNormalize3(vInputNormal); + + // project box and Cylinder on mAxis + dReal fdot1 = dVector3Dot(cData.vCylinderAxis, vInputNormal); + + dReal frc; + + if (fdot1 > REAL(1.0)) + { + fdot1 = REAL(1.0); + frc = dFabs(cData.fCylinderSize*REAL(0.5)); + } + + // project box and capsule on iAxis + frc = dFabs( fdot1 * (cData.fCylinderSize*REAL(0.5))) + cData.fCylinderRadius * dSqrt(REAL(1.0)-(fdot1*fdot1)); + + dVector3 vTemp1; + dReal frb = REAL(0.0); + + dMat3GetCol(cData.mBoxRot,0,vTemp1); + frb = dFabs(dVector3Dot(vTemp1,vInputNormal))*cData.vBoxHalfSize[0]; + + dMat3GetCol(cData.mBoxRot,1,vTemp1); + frb += dFabs(dVector3Dot(vTemp1,vInputNormal))*cData.vBoxHalfSize[1]; + + dMat3GetCol(cData.mBoxRot,2,vTemp1); + frb += dFabs(dVector3Dot(vTemp1,vInputNormal))*cData.vBoxHalfSize[2]; + + // project their distance on separating axis + dReal fd = dVector3Dot(cData.vDiff,vInputNormal); + + // if they do not overlap exit, we have no intersection + if ( dFabs(fd) > frc+frb ) + { + return 0; + } + + // get depth + dReal fDepth = - dFabs(fd) + (frc+frb); + + // get maximum depth + if ( fDepth < cData.fBestDepth ) + { + cData.fBestDepth = fDepth; + dVector3Copy(vInputNormal,cData.vNormal); + cData.iBestAxis = iAxis; + cData.fBestrb = frb; + cData.fBestrc = frc; + + // flip normal if interval is wrong faced + if (fd > 0) + { + dVector3Inv(cData.vNormal); + } + } + + return 1; +} + + +// check for separation between box edge and cylinder circle edge +int _cldTestEdgeCircleAxis( sCylinderBoxData& cData, + const dVector3 &vCenterPoint, + const dVector3 &vVx0, const dVector3 &vVx1, + int iAxis ) +{ + // calculate direction of edge + dVector3 vDirEdge; + dVector3Subtract(vVx1,vVx0,vDirEdge); + dNormalize3(vDirEdge); + // starting point of edge + dVector3 vEStart; + dVector3Copy(vVx0,vEStart);; + + // calculate angle cosine between cylinder axis and edge + dReal fdot2 = dVector3Dot (vDirEdge,cData.vCylinderAxis); + + // if edge is perpendicular to cylinder axis + if(dFabs(fdot2) < 1e-5f) + { + // this can't be separating axis, because edge is parallel to circle plane + return 1; + } + + // find point of intersection between edge line and circle plane + dVector3 vTemp1; + dVector3Subtract(vCenterPoint,vEStart,vTemp1); + dReal fdot1 = dVector3Dot(vTemp1,cData.vCylinderAxis); + dVector3 vpnt; + vpnt[0]= vEStart[0] + vDirEdge[0] * (fdot1/fdot2); + vpnt[1]= vEStart[1] + vDirEdge[1] * (fdot1/fdot2); + vpnt[2]= vEStart[2] + vDirEdge[2] * (fdot1/fdot2); + + // find tangent vector on circle with same center (vCenterPoint) that + // touches point of intersection (vpnt) + dVector3 vTangent; + dVector3Subtract(vCenterPoint,vpnt,vTemp1); + dVector3Cross(vTemp1,cData.vCylinderAxis,vTangent); + + // find vector orthogonal both to tangent and edge direction + dVector3 vAxis; + dVector3Cross(vTangent,vDirEdge,vAxis); + + // use that vector as separating axis + return _cldTestAxis( cData, vAxis, iAxis ); +} + +// Test separating axis for collision +int _cldTestSeparatingAxes(sCylinderBoxData& cData) +{ + // reset best axis + cData.fBestDepth = MAX_FLOAT; + cData.iBestAxis = 0; + cData.fBestrb = 0; + cData.fBestrc = 0; + cData.nContacts = 0; + + dVector3 vAxis = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)}; + + // Epsilon value for checking axis vector length + const dReal fEpsilon = 1e-6f; + + // axis A0 + dMat3GetCol(cData.mBoxRot, 0 , vAxis); + if (!_cldTestAxis( cData, vAxis, 1 )) + { + return 0; + } + + // axis A1 + dMat3GetCol(cData.mBoxRot, 1 , vAxis); + if (!_cldTestAxis( cData, vAxis, 2 )) + { + return 0; + } + + // axis A2 + dMat3GetCol(cData.mBoxRot, 2 , vAxis); + if (!_cldTestAxis( cData, vAxis, 3 )) + { + return 0; + } + + // axis C - Cylinder Axis + //vAxis = vCylinderAxis; + dVector3Copy(cData.vCylinderAxis , vAxis); + if (!_cldTestAxis( cData, vAxis, 4 )) + { + return 0; + } + + // axis CxA0 + //vAxis = ( vCylinderAxis cross mthGetColM33f( mBoxRot, 0 )); + dVector3CrossMat3Col(cData.mBoxRot, 0 ,cData.vCylinderAxis, vAxis); + if(dVector3Length2( vAxis ) > fEpsilon ) + { + if (!_cldTestAxis( cData, vAxis, 5 )) + { + return 0; + } + } + + // axis CxA1 + //vAxis = ( vCylinderAxis cross mthGetColM33f( mBoxRot, 1 )); + dVector3CrossMat3Col(cData.mBoxRot, 1 ,cData.vCylinderAxis, vAxis); + if(dVector3Length2( vAxis ) > fEpsilon ) + { + if (!_cldTestAxis( cData, vAxis, 6 )) + { + return 0; + } + } + + // axis CxA2 + //vAxis = ( vCylinderAxis cross mthGetColM33f( mBoxRot, 2 )); + dVector3CrossMat3Col(cData.mBoxRot, 2 ,cData.vCylinderAxis, vAxis); + if(dVector3Length2( vAxis ) > fEpsilon ) + { + if (!_cldTestAxis( cData, vAxis, 7 )) + { + return 0; + } + } + + int i = 0; + dVector3 vTemp1; + dVector3 vTemp2; + // here we check box's vertices axis + for(i=0; i< 8; i++) + { + //vAxis = ( vCylinderAxis cross (cData.avBoxVertices[i] - vCylinderPos)); + dVector3Subtract(cData.avBoxVertices[i],cData.vCylinderPos,vTemp1); + dVector3Cross(cData.vCylinderAxis,vTemp1,vTemp2); + //vAxis = ( vCylinderAxis cross vAxis ); + dVector3Cross(cData.vCylinderAxis,vTemp2,vAxis); + if(dVector3Length2( vAxis ) > fEpsilon ) + { + if (!_cldTestAxis( cData, vAxis, 8 + i )) + { + return 0; + } + } + } + + // ************************************ + // this is defined for first 12 axes + // normal of plane that contains top circle of cylinder + // center of top circle of cylinder + dVector3 vcc; + vcc[0] = (cData.vCylinderPos)[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + vcc[1] = (cData.vCylinderPos)[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + vcc[2] = (cData.vCylinderPos)[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + // ************************************ + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[0], 16)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[3], 17)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[3], 18)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[0], 19)) + { + return 0; + } + + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[1], 20)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[7], 21)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[0], cData.avBoxVertices[7], 22)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[3], 23)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[6], 24)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[6], 25)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[5], 26)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[6], cData.avBoxVertices[7], 27)) + { + return 0; + } + + // ************************************ + // this is defined for second 12 axes + // normal of plane that contains bottom circle of cylinder + // center of bottom circle of cylinder + // vcc = vCylinderPos - vCylinderAxis*(fCylinderSize*REAL(0.5)); + vcc[0] = (cData.vCylinderPos)[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + vcc[1] = (cData.vCylinderPos)[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + vcc[2] = (cData.vCylinderPos)[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + // ************************************ + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[0], 28)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[1], cData.avBoxVertices[3], 29)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[3], 30)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[0], 31)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[1], 32)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[7], 33)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[0], cData.avBoxVertices[7], 34)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[3], 35)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[5], cData.avBoxVertices[6], 36)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[2], cData.avBoxVertices[6], 37)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[4], cData.avBoxVertices[5], 38)) + { + return 0; + } + + if (!_cldTestEdgeCircleAxis( cData, vcc, cData.avBoxVertices[6], cData.avBoxVertices[7], 39)) + { + return 0; + } + + return 1; +} + +int _cldClipCylinderToBox(sCylinderBoxData& cData) +{ + + // calculate that vector perpendicular to cylinder axis which closes lowest angle with collision normal + dVector3 vN; + dReal fTemp1 = dVector3Dot(cData.vCylinderAxis,cData.vNormal); + vN[0] = cData.vNormal[0] - cData.vCylinderAxis[0]*fTemp1; + vN[1] = cData.vNormal[1] - cData.vCylinderAxis[1]*fTemp1; + vN[2] = cData.vNormal[2] - cData.vCylinderAxis[2]*fTemp1; + + // normalize that vector + dNormalize3(vN); + + // translate cylinder end points by the vector + dVector3 vCposTrans; + vCposTrans[0] = cData.vCylinderPos[0] + vN[0] * cData.fCylinderRadius; + vCposTrans[1] = cData.vCylinderPos[1] + vN[1] * cData.fCylinderRadius; + vCposTrans[2] = cData.vCylinderPos[2] + vN[2] * cData.fCylinderRadius; + + cData.vEp0[0] = vCposTrans[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + cData.vEp0[1] = vCposTrans[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + cData.vEp0[2] = vCposTrans[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + + cData.vEp1[0] = vCposTrans[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + cData.vEp1[1] = vCposTrans[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + cData.vEp1[2] = vCposTrans[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + + // transform edge points in box space + cData.vEp0[0] -= cData.vBoxPos[0]; + cData.vEp0[1] -= cData.vBoxPos[1]; + cData.vEp0[2] -= cData.vBoxPos[2]; + + cData.vEp1[0] -= cData.vBoxPos[0]; + cData.vEp1[1] -= cData.vBoxPos[1]; + cData.vEp1[2] -= cData.vBoxPos[2]; + + dVector3 vTemp1; + // clip the edge to box + dVector4 plPlane; + // plane 0 +x + dMat3GetCol(cData.mBoxRot,0,vTemp1); + dConstructPlane(vTemp1,cData.vBoxHalfSize[0],plPlane); + if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) + { + return 0; + } + + // plane 1 +y + dMat3GetCol(cData.mBoxRot,1,vTemp1); + dConstructPlane(vTemp1,cData.vBoxHalfSize[1],plPlane); + if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) + { + return 0; + } + + // plane 2 +z + dMat3GetCol(cData.mBoxRot,2,vTemp1); + dConstructPlane(vTemp1,cData.vBoxHalfSize[2],plPlane); + if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) + { + return 0; + } + + // plane 3 -x + dMat3GetCol(cData.mBoxRot,0,vTemp1); + dVector3Inv(vTemp1); + dConstructPlane(vTemp1,cData.vBoxHalfSize[0],plPlane); + if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) + { + return 0; + } + + // plane 4 -y + dMat3GetCol(cData.mBoxRot,1,vTemp1); + dVector3Inv(vTemp1); + dConstructPlane(vTemp1,cData.vBoxHalfSize[1],plPlane); + if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) + { + return 0; + } + + // plane 5 -z + dMat3GetCol(cData.mBoxRot,2,vTemp1); + dVector3Inv(vTemp1); + dConstructPlane(vTemp1,cData.vBoxHalfSize[2],plPlane); + if(!dClipEdgeToPlane( cData.vEp0, cData.vEp1, plPlane )) + { + return 0; + } + + // calculate depths for both contact points + cData.fDepth0 = cData.fBestrb + dVector3Dot(cData.vEp0, cData.vNormal); + cData.fDepth1 = cData.fBestrb + dVector3Dot(cData.vEp1, cData.vNormal); + + // clamp depths to 0 + if(cData.fDepth0<0) + { + cData.fDepth0 = REAL(0.0); + } + + if(cData.fDepth1<0) + { + cData.fDepth1 = REAL(0.0); + } + + // back transform edge points from box to absolute space + cData.vEp0[0] += cData.vBoxPos[0]; + cData.vEp0[1] += cData.vBoxPos[1]; + cData.vEp0[2] += cData.vBoxPos[2]; + + cData.vEp1[0] += cData.vBoxPos[0]; + cData.vEp1[1] += cData.vBoxPos[1]; + cData.vEp1[2] += cData.vBoxPos[2]; + + if (cData.nContacts < (cData.iFlags & NUMC_MASK)){ + dContactGeom* Contact0 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); + Contact0->depth = cData.fDepth0; + dVector3Copy(cData.vNormal,Contact0->normal); + dVector3Copy(cData.vEp0,Contact0->pos); + Contact0->g1 = cData.gCylinder; + Contact0->g2 = cData.gBox; + dVector3Inv(Contact0->normal); + cData.nContacts++; + } + + if (cData.nContacts < (cData.iFlags & NUMC_MASK)){ + dContactGeom* Contact1 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); + Contact1->depth = cData.fDepth1; + dVector3Copy(cData.vNormal,Contact1->normal); + dVector3Copy(cData.vEp1,Contact1->pos); + Contact1->g1 = cData.gCylinder; + Contact1->g2 = cData.gBox; + dVector3Inv(Contact1->normal); + cData.nContacts++; + } + + return 1; +} + + +void _cldClipBoxToCylinder(sCylinderBoxData& cData ) +{ + dVector3 vCylinderCirclePos, vCylinderCircleNormal_Rel; + // check which circle from cylinder we take for clipping + if ( dVector3Dot(cData.vCylinderAxis, cData.vNormal) > REAL(0.0) ) + { + // get top circle + vCylinderCirclePos[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + + vCylinderCircleNormal_Rel[0] = REAL(0.0); + vCylinderCircleNormal_Rel[1] = REAL(0.0); + vCylinderCircleNormal_Rel[2] = REAL(0.0); + vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(-1.0); + } + else + { + // get bottom circle + vCylinderCirclePos[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + + vCylinderCircleNormal_Rel[0] = REAL(0.0); + vCylinderCircleNormal_Rel[1] = REAL(0.0); + vCylinderCircleNormal_Rel[2] = REAL(0.0); + vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(1.0); + } + + // vNr is normal in Box frame, pointing from Cylinder to Box + dVector3 vNr; + dMatrix3 mBoxInv; + + // Find a way to use quaternion + dMatrix3Inv(cData.mBoxRot,mBoxInv); + dMultiplyMat3Vec3(mBoxInv,cData.vNormal,vNr); + + dVector3 vAbsNormal; + + vAbsNormal[0] = dFabs( vNr[0] ); + vAbsNormal[1] = dFabs( vNr[1] ); + vAbsNormal[2] = dFabs( vNr[2] ); + + // find which face in box is closest to cylinder + int iB0, iB1, iB2; + + // Different from Croteam's code + if (vAbsNormal[1] > vAbsNormal[0]) + { + // 1 > 0 + if (vAbsNormal[0]> vAbsNormal[2]) + { + // 0 > 2 -> 1 > 0 >2 + iB0 = 1; iB1 = 0; iB2 = 2; + } + else + { + // 2 > 0-> Must compare 1 and 2 + if (vAbsNormal[1] > vAbsNormal[2]) + { + // 1 > 2 -> 1 > 2 > 0 + iB0 = 1; iB1 = 2; iB2 = 0; + } + else + { + // 2 > 1 -> 2 > 1 > 0; + iB0 = 2; iB1 = 1; iB2 = 0; + } + } + } + else + { + // 0 > 1 + if (vAbsNormal[1] > vAbsNormal[2]) + { + // 1 > 2 -> 0 > 1 > 2 + iB0 = 0; iB1 = 1; iB2 = 2; + } + else + { + // 2 > 1 -> Must compare 0 and 2 + if (vAbsNormal[0] > vAbsNormal[2]) + { + // 0 > 2 -> 0 > 2 > 1; + iB0 = 0; iB1 = 2; iB2 = 1; + } + else + { + // 2 > 0 -> 2 > 0 > 1; + iB0 = 2; iB1 = 0; iB2 = 1; + } + } + } + + dVector3 vCenter; + // find center of box polygon + dVector3 vTemp; + if (vNr[iB0] > 0) + { + dMat3GetCol(cData.mBoxRot,iB0,vTemp); + vCenter[0] = cData.vBoxPos[0] - cData.vBoxHalfSize[iB0]*vTemp[0]; + vCenter[1] = cData.vBoxPos[1] - cData.vBoxHalfSize[iB0]*vTemp[1]; + vCenter[2] = cData.vBoxPos[2] - cData.vBoxHalfSize[iB0]*vTemp[2]; + } + else + { + dMat3GetCol(cData.mBoxRot,iB0,vTemp); + vCenter[0] = cData.vBoxPos[0] + cData.vBoxHalfSize[iB0]*vTemp[0]; + vCenter[1] = cData.vBoxPos[1] + cData.vBoxHalfSize[iB0]*vTemp[1]; + vCenter[2] = cData.vBoxPos[2] + cData.vBoxHalfSize[iB0]*vTemp[2]; + } + + // find the vertices of box polygon + dVector3 avPoints[4]; + dVector3 avTempArray1[MAX_CYLBOX_CLIP_POINTS]; + dVector3 avTempArray2[MAX_CYLBOX_CLIP_POINTS]; + + int i=0; + for(i=0; i= 0 && iTmpCounter1 <= MAX_CYLBOX_CLIP_POINTS ); + dIASSERT( iTmpCounter2 >= 0 && iTmpCounter2 <= MAX_CYLBOX_CLIP_POINTS ); + } + + // back transform clipped points to absolute space + dReal ftmpdot; + dReal fTempDepth; + dVector3 vPoint; + + if (nCircleSegment %2) + { + for( i=0; i REAL(0.0)) + { + // generate contacts + if (cData.nContacts < (cData.iFlags & NUMC_MASK)){ + dContactGeom* Contact0 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); + Contact0->depth = fTempDepth; + dVector3Copy(cData.vNormal,Contact0->normal); + dVector3Copy(vPoint,Contact0->pos); + Contact0->g1 = cData.gCylinder; + Contact0->g2 = cData.gBox; + dVector3Inv(Contact0->normal); + cData.nContacts++; + } + } + } + } + else + { + for( i=0; i REAL(0.0)) + { + // generate contacts + if (cData.nContacts < (cData.iFlags & NUMC_MASK)){ + dContactGeom* Contact0 = SAFECONTACT(cData.iFlags, cData.gContact, cData.nContacts, cData.iSkip); + Contact0->depth = fTempDepth; + dVector3Copy(cData.vNormal,Contact0->normal); + dVector3Copy(vPoint,Contact0->pos); + Contact0->g1 = cData.gCylinder; + Contact0->g2 = cData.gBox; + dVector3Inv(Contact0->normal); + cData.nContacts++; + } + } + } + } +} + + +// Cylinder - Box by CroTeam +// Ported by Nguyen Binh +int dCollideCylinderBox(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) +{ + sCylinderBoxData cData; + + // Assign ODE stuff + cData.gCylinder = o1; + cData.gBox = o2; + cData.iFlags = flags; + cData.iSkip = skip; + cData.gContact = contact; + + // initialize collider + _cldInitCylinderBox( cData ); + + // do intersection test and find best separating axis + if(!_cldTestSeparatingAxes( cData ) ) + { + // if not found do nothing + return 0; + } + + // if best separation axis is not found + if ( cData.iBestAxis == 0 ) + { + // this should not happen (we should already exit in that case) + dIASSERT(0); + // do nothing + return 0; + } + + dReal fdot = dVector3Dot(cData.vNormal,cData.vCylinderAxis); + // choose which clipping method are we going to apply + if (dFabs(fdot) < REAL(0.9) ) + { + // clip cylinder over box + if(!_cldClipCylinderToBox(cData)) + { + return 0; + } + } + else + { + _cldClipBoxToCylinder(cData); + } + + return cData.nContacts; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_plane.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_plane.cpp new file mode 100644 index 00000000..3a30cee7 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_plane.cpp @@ -0,0 +1,180 @@ +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define SQRT3_2 ((dReal)0.86602540378443864676) +#define dLENGTH(a) (dSqrt( ((a)[0])*((a)[0]) + ((a)[1])*((a)[1]) + ((a)[2])*((a)[2]) )); +#define dOPC(a,op,b,c) \ + (a)[0] = ((b)[0]) op (c); \ + (a)[1] = ((b)[1]) op (c); \ + (a)[2] = ((b)[2]) op (c); +#define dOPE(a,op,b) \ + (a)[0] op ((b)[0]); \ + (a)[1] op ((b)[1]); \ + (a)[2] op ((b)[2]); +#define dOP(a,op,b,c) \ + (a)[0] = ((b)[0]) op ((c)[0]); \ + (a)[1] = ((b)[1]) op ((c)[1]); \ + (a)[2] = ((b)[2]) op ((c)[2]); + + +/* + * There are five cases: no collision, one-point collision when one + edge + * circle intersects the plane, two-point collision when both edge + circles + * intersect the plane, three-point collision when the two edge + circles are + * on opposite sides of the plane, and deep collision when the center + of + * the cylinder has penetrated the plane (ugh). The contact normal is + * always perpendicular to the plane. + */ + +static void generatePlaneContact(dxGeom *geom, dxGeom *plane, + dContactGeom *contact, int skip, + dVector4 pparams, dVector3 point) { + dContactGeom *c = CONTACT(contact,skip); + dReal depth = -dDOT(pparams,point); + c->pos[0] = point[0] + depth*pparams[0]; + c->pos[1] = point[1] + depth*pparams[1]; + c->pos[2] = point[2] + depth*pparams[2]; + c->normal[0] = pparams[0]; + c->normal[1] = pparams[1]; + c->normal[2] = pparams[2]; + c->depth = depth; + c->g1 = geom; + c->g2 = plane; +} + +int dCollideCylinderPlane(dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + int maxContacts = flags&0xFFFF, numContacts = 0; + dReal radius, half_length; + dGeomCylinderGetParams( o1, &radius, &half_length ); + half_length /= 2; + const dReal *pos = dGeomGetPosition( o1 ); + const dReal *rot = dGeomGetRotation( o1 ); + + dVector4 pparams; + dGeomPlaneGetParams( o2, pparams ); + + // Early-out now by colliding against the cylinder's bounding + //sphere? + + dVector3 axis = { rot[2], rot[6], rot[10] }; + dVector3 ctop = { pos[0]+half_length*axis[0], + pos[1]+half_length*axis[1], + pos[2]+half_length*axis[2] }; + dVector3 cbot = { pos[0]-half_length*axis[0], + pos[1]-half_length*axis[1], + pos[2]-half_length*axis[2] }; + + dVector3 cross, rvec; + dCROSS(cross,=,pparams,axis); + dReal projectedRadius = radius * dLENGTH(cross); + dNormalize3(cross); + dCROSS(rvec,=,cross,axis); + dNormalize3(rvec); + dOPC(rvec,*,rvec,radius); + if( dDOT(pparams,rvec) > 0 ) { + dOPE(rvec,=-,rvec); + } + dReal dtop = dDOT(pparams,ctop); + dReal dbot = dDOT(pparams,cbot); + dVector3 point; + + // Has the center penetrated? + if( dDOT(pparams,pos) <= pparams[3] ) { + // Drat. Hopefully this will blast us out of the plane. + if( dtop < dbot ) { dOP(point,+,ctop,rvec); } + else { dOP(point,+,cbot,rvec); } + generatePlaneContact(o1,o2,contact,(numContacts++)*skip, + pparams,point); + } + else { + // Has the top face penetrated? + if( dtop - projectedRadius <= pparams[3] ) { + dOP(point,+,ctop,rvec); + generatePlaneContact(o1,o2,contact,(numContacts++)*skip, + pparams,point); + // Are we allowed to look for more contacts? + if( maxContacts >= 2 ) { + // Has the bottom face penetrated too? + if( dbot - projectedRadius <= pparams[3] ) { + dOP(point,+,cbot,rvec); + + generatePlaneContact(o1,o2,contact,(numContacts++)*skip, + pparams,point); + } + // Has the *whole* top face penetrated? + else if( dtop + projectedRadius <= pparams[3] ) { + if( maxContacts >= 3 ) { + dVector3 rvec2; + dCROSS(rvec2,=,axis,rvec); + dOPC(rvec,/,rvec,2); + dOPC(rvec2,*,rvec2,SQRT3_2); + point[0] = ctop[0]-rvec[0]+rvec2[0]; + point[1] = ctop[1]-rvec[1]+rvec2[1]; + point[2] = ctop[2]-rvec[2]+rvec2[2]; + generatePlaneContact(o1,o2,contact, + (numContacts++)*skip, + pparams,point); + point[0] = ctop[0]-rvec[0]-rvec2[0]; + point[1] = ctop[1]-rvec[1]-rvec2[1]; + point[2] = ctop[2]-rvec[2]-rvec2[2]; + generatePlaneContact(o1,o2,contact, + (numContacts++)*skip, + pparams,point); + } + else { + dOP(point,-,ctop,rvec); + generatePlaneContact(o1,o2,contact, + (numContacts++)*skip, + pparams,point); + } + } + } + } + // Has the bottom face penetrated? + else if( dbot - projectedRadius <= pparams[3] ) { + dOP(point,+,cbot,rvec); + generatePlaneContact(o1,o2,contact,(numContacts++)*skip, + pparams,point); + // Are we allowed to look for more contacts? + if( maxContacts >= 2 ) { + // Has the *whole* bottom face penetrated? + if( dbot + projectedRadius <= pparams[3] ) { + if( maxContacts >= 3 ) { + dVector3 rvec2; + dCROSS(rvec2,=,axis,rvec); + dOPC(rvec,/,rvec,2); + dOPC(rvec2,*,rvec2,SQRT3_2); + point[0] = cbot[0]-rvec[0]+rvec2[0]; + point[1] = cbot[1]-rvec[1]+rvec2[1]; + point[2] = cbot[2]-rvec[2]+rvec2[2]; + generatePlaneContact(o1,o2,contact, + (numContacts++)*skip, + pparams,point); + point[0] = cbot[0]-rvec[0]-rvec2[0]; + point[1] = cbot[1]-rvec[1]-rvec2[1]; + point[2] = cbot[2]-rvec[2]-rvec2[2]; + generatePlaneContact(o1,o2,contact, + (numContacts++)*skip, + pparams,point); + } + else { + dOP(point,-,cbot,rvec); + generatePlaneContact(o1,o2,contact, + (numContacts++)*skip, + pparams,point); + } + } + } + } + } + return numContacts; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_sphere.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_sphere.cpp new file mode 100644 index 00000000..1c55a592 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_sphere.cpp @@ -0,0 +1,580 @@ +/************************************************************************* +* * +* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * +* All rights reserved. Email: russ@q12.org Web: www.q12.org * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of EITHER: * +* (1) The GNU Lesser General Public License as published by the Free * +* Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. The text of the GNU Lesser * +* General Public License is included with this library in the * +* file LICENSE.TXT. * +* (2) The BSD-style license that is included with this library in * +* the file LICENSE-BSD.TXT. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * +* LICENSE.TXT and LICENSE-BSD.TXT for more details. * +* * +*************************************************************************/ + +/* + * Cylinder-sphere collider by Alen Ladavac (Croteam) + * Ported to ODE by Nguyen Binh ( www.coderfarm.com ) + */ + +// NOTES : +// I only try to solve some obvious problems on cylinder-sphere +// If you like to solve all problem when very large sphere drop over +// very small cylinder or vice versa, you will need to re-organize the code. +// I would eventually, try to do it later, when I have more time. +// On this version, I only try to solve the problem when a very large cylinder +// drop over very small sphere. + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" +#include "ode/ode_collision_kernel.h" +#include "ode/ode_objects.h" + +// Axis of Cylinder - ODE use axis Z. +static const int nCYLINDER_AXIS = 2; + +// Method to cure very deep penetration +// When two objects are in very deep penetration, we should exaggerate +// the depth value between them or numerical errors will make one object go +// through the other. +// 0 : do nothing - keep the calculated depth +// 1 : exaggerate calculated depth by multiple of fDepthRecoverRatio times. +// 2 : exaggerate calculated depth by multiple of log of ration between +// heavy object and light object. This method take a little more computing +// power but can be used to solved almost all "drop very large object over +// small object" problems. + +#define _DEPTH_RECOVER_METHOD_ 0 + +#if (_DEPTH_RECOVER_METHOD_ == 1) +static const dReal fDepthRecoverRatio = REAL(2.0); +#endif + +int dCollideCylinderSphere(dxGeom *gCylinder, dxGeom *gSphere, int flags, dContactGeom *contact, int skip) +{ + // get source hull position and orientation + // Number of contacts + int nContacts = 0; + + dQuaternion mQuatCylinder; + dGeomGetQuaternion(gCylinder,mQuatCylinder); + + dVector3 vCylinderPos; + dMatrix3 mCylinderRot; + const dReal* pRotCyc = dGeomGetRotation(gCylinder); + dMatrix3Copy(pRotCyc,mCylinderRot); + + const dVector3* pPosCyc = (const dVector3*)dGeomGetPosition(gCylinder); + dVector3Copy(*pPosCyc,vCylinderPos); + + // get capsule radius and size + dReal fCylinderRadius; + dReal fCylinderSize; + + dGeomCylinderGetParams(gCylinder,&fCylinderRadius,&fCylinderSize); + + // get destination hull position and radius + dMatrix3 mSphereRot; + dVector3 vSpherePos; + + dReal fSphereRadius = dGeomSphereGetRadius(gSphere); + + const dReal* pSphereRot = dGeomGetRotation(gSphere); + dMatrix3Copy(pSphereRot,mSphereRot); + + const dVector3* pSpherePos = (const dVector3*)dGeomGetPosition(gSphere); + dVector3Copy(*pSpherePos,vSpherePos); + + // transform sphere position in cylinder frame + dVector3 vSpherePosInCylinderFrame; + // temporary variables + dVector3 vTemp; + dVector3 vTemp2; + + // Sphere position relative to Cylinder + dVector3Subtract(vSpherePos,vCylinderPos,vTemp); + + dQuaternion mInvQuatCylinder; + dQuatInv(mQuatCylinder,mInvQuatCylinder); + dQuatTransform(mInvQuatCylinder,vTemp,vSpherePosInCylinderFrame); + + // cylinder boundaries along cylinder axis + dReal fHighCylinderBase = fCylinderSize*0.5f; + dReal fLowCylinderBase = -fCylinderSize*0.5f; + + dReal fDeltaHigh = (vSpherePosInCylinderFrame[nCYLINDER_AXIS] - fHighCylinderBase ); + dReal fDeltaLow = (fLowCylinderBase - vSpherePosInCylinderFrame[nCYLINDER_AXIS] ); + + // check if sphere intersecting with cylindrical part - side part + if( fDeltaHigh <= REAL(0.0) && fDeltaLow <= REAL(0.0)) + { + // This mean the center of sphere lies between high and low base along cylinder axis + // of the cylinder + + // calculate center of sphere on cylindrical axis which is referent for collision + // This circle of cylinder is in the same level with the center of sphere + dVector3 vBodyPoint = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vBodyPoint[nCYLINDER_AXIS] = vSpherePosInCylinderFrame[nCYLINDER_AXIS]; + + // calculate distance between two spheres + dVector3Subtract(vSpherePosInCylinderFrame,vBodyPoint,vTemp ); + dReal fDistance = dVector3Length( vTemp ); + + if ( fDistance <= (fCylinderRadius + fSphereRadius)) + { + dReal fTemp; + dReal fDepth; + dVector3 vPoint; + + // Axis dependent - Should change when you don't use cylinder along z axis + if (dFabs(vSpherePosInCylinderFrame[0]) <= fCylinderRadius + && dFabs(vSpherePosInCylinderFrame[1]) <= fCylinderRadius) + { + // Actually, not side penetrate but very deep top (or) bottom penetrate + // We have to use some trick to solve it. + + // First try to find top or bottom penetrate + dVector3 vCylinderLinearVel = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)}; + dVector3 vSphereLinearVel = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)}; + dBodyID CylinderBody = dGeomGetBody(gCylinder); + dBodyID SphereBody = dGeomGetBody(gSphere); + + // Get linear velocity + if (CylinderBody) + { + const dReal* pCylinderVel = dBodyGetLinearVel(CylinderBody); + vCylinderLinearVel[0] = pCylinderVel[0]; + vCylinderLinearVel[1] = pCylinderVel[1]; + vCylinderLinearVel[2] = pCylinderVel[2]; + } + + if (SphereBody) + { + const dReal* pSphereVel = dBodyGetLinearVel(SphereBody); + vSphereLinearVel[0] = pSphereVel[0]; + vSphereLinearVel[1] = pSphereVel[1]; + vSphereLinearVel[2] = pSphereVel[2]; + } + + dVector3 vSphereVelInCylinderFrame; + dVector3Subtract(vSphereLinearVel,vCylinderLinearVel,vSphereVelInCylinderFrame); + + #if (_DEPTH_RECOVER_METHOD_ == 2) + dReal fRelativeVel = dVector3Length(vSphereVelInCylinderFrame); + #endif + + dNormalize3(vSphereVelInCylinderFrame); + + dVector3 vCylinderAxis; + dMat3GetCol(mCylinderRot,nCYLINDER_AXIS,vCylinderAxis); + dNormalize3(vCylinderAxis); + + dReal fAngle = dVector3Dot(vSphereVelInCylinderFrame,vCylinderAxis); + + // Solve problem when drop very large cylinder over very small sphere + if (fAngle < 0 ) + { + // Top penetrate + // collision normal showing up from top cylinder plane + dVector3 vNormal = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vNormal[nCYLINDER_AXIS] = REAL(-1.0); + + // Transform to cylinder space + dQuatTransform(mQuatCylinder,vNormal,vTemp2); + dNormalize3(vTemp2); + + // set collision point in cylinder frame + dVector3Copy(vSpherePosInCylinderFrame,vPoint); + vPoint[nCYLINDER_AXIS] = fHighCylinderBase; + + // transform in absolute space + dQuatTransform(mQuatCylinder,vPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vPoint); + + // calculate collision depth + dReal fDepth = fSphereRadius - fDeltaHigh; + // Experiment show that we need to exaggerate depth ratio to + // keep the small object from being stuck in other + + #if (_DEPTH_RECOVER_METHOD_ == 1) + // Constant ratio + fDepth *= fDepthRecoverRatio; + #endif // (_DEPTH_RECOVER_METHOD_ == 1) + + // use log of ratio between large object and small object masses + #if (_DEPTH_RECOVER_METHOD_ == 2) + if (CylinderBody && SphereBody) + { + // No static geom -> need to exaggerate + dMass sphereMass; + dBodyGetMass(SphereBody,&sphereMass); + dMass cylinderMass; + dBodyGetMass(CylinderBody,&cylinderMass); + + dReal fRatio1 = cylinderMass.mass/sphereMass.mass; + + if (fRatio1 > REAL(1.0)) + { + fDepth *= fRelativeVel *dSqrt(fRatio1); + } + else + { + fDepth *= fRelativeVel * dSqrt( REAL(1.0) / fRatio1); + } + } + #endif // (_DEPTH_RECOVER_METHOD_ == 2) + + // generate contact + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vTemp2,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + } + + return nContacts; + } + else + { + // Near Bottom + dVector3 vNormal = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vNormal[nCYLINDER_AXIS] = REAL(1.0); + // Transform to cylinder space + dQuatTransform(mQuatCylinder,vNormal,vTemp2); + dNormalize3(vTemp2); + + // set collision point in cylinder frame + dVector3Copy(vSpherePosInCylinderFrame,vPoint); + vPoint[nCYLINDER_AXIS] = fLowCylinderBase; + + // transform in absolute space + dQuatTransform(mQuatCylinder,vPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vPoint); + + // calculate collision depth + dReal fDepth = fSphereRadius - fDeltaLow; + // Experiment show that we need to exaggerate depth ratio to + // keep the small sphere from being stuck + + #if (_DEPTH_RECOVER_METHOD_ == 1) + // Constant ratio + fDepth *= fDepthRecoverRatio; + #endif // (_DEPTH_RECOVER_METHOD_ == 1) + + // use log of ratio between large object and small object masses + #if (_DEPTH_RECOVER_METHOD_ == 2) + if (CylinderBody && SphereBody) + { + // No static geom -> need to exaggerate + dMass sphereMass; + dBodyGetMass(SphereBody,&sphereMass); + dMass cylinderMass; + dBodyGetMass(CylinderBody,&cylinderMass); + + dReal fRatio1 = cylinderMass.mass/sphereMass.mass; + + if (fRatio1 > REAL(1.0)) + { + fDepth *= fRelativeVel *dSqrt(fRatio1); + } + else + { + fDepth *= fRelativeVel * dSqrt( REAL(1.0) / fRatio1); + } + } + #endif // (_DEPTH_RECOVER_METHOD_ == 2) + + + // generate contact + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vTemp2,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + } + + return nContacts; + } + } + + // calculate collision normal + dVector3 vNormal; + dQuatTransform(mQuatCylinder,vBodyPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vTemp2); + dVector3Subtract(vSpherePos,vTemp2,vNormal); + dNormalize3(vNormal); + + // calculate collision point + fTemp = fCylinderRadius-fSphereRadius-fDistance; + + vPoint[0] = vSpherePos[0] + vNormal[0]* fTemp *REAL(0.5); + vPoint[1] = vSpherePos[1] + vNormal[1]* fTemp *REAL(0.5); + vPoint[2] = vSpherePos[2] + vNormal[2]* fTemp *REAL(0.5); + + // calculate penetration depth + fDepth = fCylinderRadius + fSphereRadius-fDistance; + + // generate contact + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vNormal,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + dVector3Inv(Contact->normal); + } + + return nContacts; + } + // check if sphere is intersecting with top or bottom circle of cylinder + } + else + { + // test sphere on top circle of cylinder + if ( fDeltaHigh > REAL(0.0)) + { + // check if sphere is intersecting top plane + if( fDeltaHigh < fSphereRadius ) + { + // calculate center of sphere on cylindrical axis which is referent for collision + dVector3 vBodyPoint = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vBodyPoint[nCYLINDER_AXIS] = vSpherePosInCylinderFrame[nCYLINDER_AXIS]; + + // distance between sphere and cylinder axis + dVector3Subtract(vSpherePosInCylinderFrame,vBodyPoint,vTemp); + dReal fDistance = dVector3Length(vTemp); + + // see if our intersection point is inside top circle + if( fDistance < fCylinderRadius) + { + // collision normal showing up from top cylinder plane + dVector3 vNormal = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vNormal[nCYLINDER_AXIS] = REAL(-1.0); + // Transform to cylinder space + dQuatTransform(mQuatCylinder,vNormal,vTemp2); + dNormalize3(vTemp2); + // set collision point in cylinder frame + dVector3 vPoint; + dVector3Copy(vSpherePosInCylinderFrame,vPoint); + vPoint[nCYLINDER_AXIS] = fHighCylinderBase; + + // transform in absolute space + dQuatTransform(mQuatCylinder,vPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vPoint); + + // calculate collision depth + dReal fDepth = fSphereRadius - fDeltaHigh; + + // generate contact + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vTemp2,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + } + + return nContacts; + } + + // if we got here then we are potentially intersecting the top ring + // of the cylinder + + // define top circle center point on cylinder axis + dVector3 vE0 = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vE0[nCYLINDER_AXIS] = fHighCylinderBase; + + // set direction vector from center to circle edge + dVector3 vDirVector; + dVector3Subtract(vSpherePosInCylinderFrame,vE0,vDirVector); + + // project it onto top plane + vDirVector[nCYLINDER_AXIS] = REAL(0.0); + + // and make it unit vector + dNormalize3(vDirVector); + + // define point on the top circle edge + dVector3 vPoint; + vPoint[0] = vE0[0] + vDirVector[0] * fCylinderRadius; + vPoint[1] = vE0[1] + vDirVector[1] * fCylinderRadius; + vPoint[2] = vE0[2] + vDirVector[2] * fCylinderRadius; + + // calculate distance from edge to sphere + dVector3Subtract(vPoint,vSpherePosInCylinderFrame,vTemp); + dReal fDistEdgeToSphere = dVector3Length(vTemp); + + // if edge/sphere are intersecting + if (fDistEdgeToSphere < fSphereRadius ) + { + // transform in absolute space + dQuatTransform(mQuatCylinder,vPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vPoint); + + // calculate collision normal + dVector3 vNormal; + dVector3Subtract(vPoint,vSpherePos,vNormal); + + // and make it unit vector + dNormalize3(vNormal); + // calculate penetration depth + dReal fDepth = fSphereRadius - fDistEdgeToSphere; + + // generate contact + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vNormal,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + } + + return nContacts; + } + } + + // test sphere on bottom circle of cylinder + } + else + if (vSpherePosInCylinderFrame[nCYLINDER_AXIS] < fLowCylinderBase) + { + + if( fDeltaLow < fSphereRadius ) + { + // calculate center of sphere on cylindrical axis which is referent for collision + dVector3 vBodyPoint = {REAL(0.0),REAL(0.0),REAL(0.0)}; + vBodyPoint[nCYLINDER_AXIS] = vSpherePosInCylinderFrame[nCYLINDER_AXIS]; + + // distance between sphere and cylinder axis + dVector3Subtract(vSpherePosInCylinderFrame,vBodyPoint,vTemp); + dReal fDistance = dVector3Length(vTemp); + + // see if our intersection point is inside bottom circle + if( fDistance < fCylinderRadius ) + { + // collision normal showing up from top cylinder plane + dVector3 vNormal = {REAL(0.0),REAL(0.0),REAL(0.0)};//(0,-1,0); + vNormal[nCYLINDER_AXIS] = REAL(1.0); + + dQuatTransform(mQuatCylinder,vNormal,vTemp2); + dNormalize3(vTemp2); + + // set collision point in cylinder frame + dVector3 vPoint; + dVector3Copy(vSpherePosInCylinderFrame,vPoint); + vPoint[nCYLINDER_AXIS] = fLowCylinderBase; + + // transform in absolute space + dQuatTransform(mQuatCylinder,vPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vPoint); + + // calculate collision depth + dReal fDepth = fSphereRadius - fDeltaLow; + + // generate contact + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vTemp2,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + } + + return nContacts; + } + + // if we got here then we are potentially intersecting the bottom ring + // of the cylinder + + // define top circle center point on cylinder axis + dVector3 vE0 = {REAL(0.0),REAL(0.0),REAL(0.0)};//(0,fLowCylinderBase,0); + vE0[nCYLINDER_AXIS] = fLowCylinderBase; + + // set direction vector from center to circle edge + dVector3 vDirVector; + dVector3Subtract(vSpherePosInCylinderFrame,vE0,vDirVector); + + // project it onto top plane + vDirVector[nCYLINDER_AXIS] = REAL(0.0); + + // and make it unit vector + dNormalize3(vDirVector); + + // define point on the top circle edge + dVector3 vPoint; + vPoint[0] = vE0[0] + vDirVector[0] * fCylinderRadius; + vPoint[1] = vE0[1] + vDirVector[1] * fCylinderRadius; + vPoint[2] = vE0[2] + vDirVector[2] * fCylinderRadius; + + dVector3Subtract(vPoint,vSpherePosInCylinderFrame,vTemp); + dReal fDistEdgeToSphere = dVector3Length(vTemp); + + // if edge/sphere are intersecting + if (fDistEdgeToSphere < fSphereRadius ) + { + // transform in absolute space + dQuatTransform(mQuatCylinder,vPoint,vTemp); + dVector3Add(vTemp,vCylinderPos,vPoint); + + // calculate collision normal + dVector3 vNormal;// = dVector3(vPoint - vSpherePos); + dVector3Subtract(vPoint,vSpherePos,vNormal); + + // and make it unit vector + dNormalize3(vNormal); + + // calculate penetration depth + dReal fDepth = fSphereRadius - fDistEdgeToSphere; + + if (nContacts < (flags & NUMC_MASK)) + { + dContactGeom* Contact = SAFECONTACT(flags, contact, nContacts, skip ); + Contact->depth = fDepth; + dVector3Copy(vNormal,Contact->normal); + dVector3Copy(vPoint,Contact->pos); + Contact->g1 = gCylinder; + Contact->g2 = gSphere; + nContacts++; + } + + return nContacts; + } + } + } + } + + return nContacts; +} + + diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_trimesh.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_trimesh.cpp new file mode 100644 index 00000000..66775d4b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_cylinder_trimesh.cpp @@ -0,0 +1,1041 @@ +/************************************************************************* +* * +* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * +* All rights reserved. Email: russ@q12.org Web: www.q12.org * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of EITHER: * +* (1) The GNU Lesser General Public License as published by the Free * +* Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. The text of the GNU Lesser * +* General Public License is included with this library in the * +* file LICENSE.TXT. * +* (2) The BSD-style license that is included with this library in * +* the file LICENSE-BSD.TXT. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * +* LICENSE.TXT and LICENSE-BSD.TXT for more details. * +* * +*************************************************************************/ + +/* + * Cylinder-trimesh collider by Alen Ladavac + * Ported to ODE by Nguyen Binh + */ + + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + + +#define MAX_REAL dInfinity +static const int nCYLINDER_AXIS = 2; +static const int nCYLINDER_CIRCLE_SEGMENTS = 8; +static const int nMAX_CYLINDER_TRIANGLE_CLIP_POINTS = 12; +static const int gMaxLocalContacts = 32; + +#define OPTIMIZE_CONTACTS 1 + +// Local contacts data +typedef struct _sLocalContactData +{ + dVector3 vPos; + dVector3 vNormal; + dReal fDepth; + int nFlags; // 0 = filtered out, 1 = OK +}sLocalContactData; + +typedef struct _sCylinderTrimeshColliderData +{ + // cylinder data + dMatrix3 mCylinderRot; + dQuaternion qCylinderRot; + dQuaternion qInvCylinderRot; + dVector3 vCylinderPos; + dVector3 vCylinderAxis; + dReal fCylinderRadius; + dReal fCylinderSize; + dVector3 avCylinderNormals[nCYLINDER_CIRCLE_SEGMENTS]; + + // mesh data + dQuaternion qTrimeshRot; + dQuaternion qInvTrimeshRot; + dMatrix3 mTrimeshRot; + dVector3 vTrimeshPos; + + // global collider data + dVector3 vBestPoint; + dReal fBestDepth; + dReal fBestCenter; + dReal fBestrt; + int iBestAxis; + dVector3 vContactNormal; + dVector3 vNormal; + dVector3 vE0; + dVector3 vE1; + dVector3 vE2; + + // ODE stuff + dGeomID gCylinder; + dxTriMesh* gTrimesh; + dContactGeom* gContact; + int iFlags; + int iSkip; + int nContacts;// = 0; + sLocalContactData gLocalContacts[gMaxLocalContacts]; +} sCylinderTrimeshColliderData; + +// Short type name +typedef sCylinderTrimeshColliderData sData; + +// Use to classify contacts to be "near" in position +static const dReal fSameContactPositionEpsilon = REAL(0.0001); // 1e-4 +// Use to classify contacts to be "near" in normal direction +static const dReal fSameContactNormalEpsilon = REAL(0.0001); // 1e-4 + +// If this two contact can be classified as "near" +inline int _IsNearContacts(sLocalContactData& c1,sLocalContactData& c2) +{ + int bPosNear = 0; + int bSameDir = 0; + dVector3 vDiff; + + // First check if they are "near" in position + dVector3Subtract(c1.vPos,c2.vPos,vDiff); + if ( (dFabs(vDiff[0]) < fSameContactPositionEpsilon) + &&(dFabs(vDiff[1]) < fSameContactPositionEpsilon) + &&(dFabs(vDiff[2]) < fSameContactPositionEpsilon)) + { + bPosNear = 1; + } + + // Second check if they are "near" in normal direction + dVector3Subtract(c1.vNormal,c2.vNormal,vDiff); + if ( (dFabs(vDiff[0]) < fSameContactNormalEpsilon) + &&(dFabs(vDiff[1]) < fSameContactNormalEpsilon) + &&(dFabs(vDiff[2]) < fSameContactNormalEpsilon) ) + { + bSameDir = 1; + } + + // Will be "near" if position and normal direction are "near" + return (bPosNear && bSameDir); +} + +inline int _IsBetter(sLocalContactData& c1,sLocalContactData& c2) +{ + // The not better will be throw away + // You can change the selection criteria here + return (c1.fDepth > c2.fDepth); +} + +// iterate through gLocalContacts and filtered out "near contact" +inline void _OptimizeLocalContacts(sData& cData) +{ + int nContacts = cData.nContacts; + + for (int i = 0; i < nContacts-1; i++) + { + for (int j = i+1; j < nContacts; j++) + { + if (_IsNearContacts(cData.gLocalContacts[i],cData.gLocalContacts[j])) + { + // If they are seem to be the samed then filtered + // out the least penetrate one + if (_IsBetter(cData.gLocalContacts[j],cData.gLocalContacts[i])) + { + cData.gLocalContacts[i].nFlags = 0; // filtered 1st contact + } + else + { + cData.gLocalContacts[j].nFlags = 0; // filtered 2nd contact + } + + // NOTE + // There is other way is to add two depth together but + // it not work so well. Why??? + } + } + } +} + +inline int _ProcessLocalContacts(sData& cData) +{ + if (cData.nContacts == 0) + { + return 0; + } + +#ifdef OPTIMIZE_CONTACTS + if (cData.nContacts > 1) + { + // Can be optimized... + _OptimizeLocalContacts(cData); + } +#endif + + int iContact = 0; + dContactGeom* Contact = 0; + + int nFinalContact = 0; + + for (iContact = 0; iContact < cData.nContacts; iContact ++) + { + if (1 == cData.gLocalContacts[iContact].nFlags) + { + // eric added - dont go over our contact limit + if (iContact >= (cData.iFlags & 0x0ffff)) + break; + Contact = SAFECONTACT(cData.iFlags, cData.gContact, nFinalContact, cData.iSkip); + Contact->depth = cData.gLocalContacts[iContact].fDepth; + dVector3Copy(cData.gLocalContacts[iContact].vNormal,Contact->normal); + dVector3Copy(cData.gLocalContacts[iContact].vPos,Contact->pos); + Contact->g1 = cData.gCylinder; + Contact->g2 = cData.gTrimesh; + dVector3Inv(Contact->normal); + + nFinalContact++; + } + } + // debug + //if (nFinalContact != cData.nContacts) + //{ + // printf("[Info] %d contacts generated,%d filtered.\n",cData.nContacts,cData.nContacts-nFinalContact); + //} + + return nFinalContact; +} + + +bool _cldTestAxis(sData& cData, + const dVector3 &v0, + const dVector3 &v1, + const dVector3 &v2, + dVector3& vAxis, + int iAxis, + bool bNoFlip = false) +{ + + // calculate length of separating axis vector + dReal fL = dVector3Length(vAxis); + // if not long enough + if ( fL < 1e-5f ) + { + // do nothing + return true; + } + + // otherwise normalize it + vAxis[0] /= fL; + vAxis[1] /= fL; + vAxis[2] /= fL; + + dReal fdot1 = dVector3Dot(cData.vCylinderAxis,vAxis); + // project capsule on vAxis + dReal frc; + + if (fdot1 > REAL(1.0) ) + { + fdot1 = REAL(1.0); + frc = dFabs(cData.fCylinderSize* REAL(0.5)); + } + else + { + frc = dFabs((cData.fCylinderSize* REAL(0.5)) * fdot1) + + cData.fCylinderRadius * dFabs(REAL(1.0)-(fdot1*fdot1)); + } + + dVector3 vV0; + dVector3Subtract(v0,cData.vCylinderPos,vV0); + dVector3 vV1; + dVector3Subtract(v1,cData.vCylinderPos,vV1); + dVector3 vV2; + dVector3Subtract(v2,cData.vCylinderPos,vV2); + + // project triangle on vAxis + dReal afv[3]; + afv[0] = dVector3Dot( vV0 , vAxis ); + afv[1] = dVector3Dot( vV1 , vAxis ); + afv[2] = dVector3Dot( vV2 , vAxis ); + + dReal fMin = MAX_REAL; + dReal fMax = -MAX_REAL; + + // for each vertex + for(int i = 0; i < 3; i++) + { + // find minimum + if (afv[i]fMax) + { + fMax = afv[i]; + } + } + + // find capsule's center of interval on axis + dReal fCenter = (fMin+fMax)* REAL(0.5); + // calculate triangles halfinterval + dReal fTriangleRadius = (fMax-fMin)*REAL(0.5); + + // if they do not overlap, + if( dFabs(fCenter) > (frc+fTriangleRadius) ) + { + // exit, we have no intersection + return false; + } + + // calculate depth + dReal fDepth = -(dFabs(fCenter) - (frc + fTriangleRadius ) ); + + // if greater then best found so far + if ( fDepth < cData.fBestDepth ) + { + // remember depth + cData.fBestDepth = fDepth; + cData.fBestCenter = fCenter; + cData.fBestrt = frc; + dVector3Copy(vAxis,cData.vContactNormal); + cData.iBestAxis = iAxis; + + // flip normal if interval is wrong faced + if ( fCenter< REAL(0.0) && !bNoFlip) + { + dVector3Inv(cData.vContactNormal); + cData.fBestCenter = -fCenter; + } + } + + return true; +} + +// intersection test between edge and circle +bool _cldTestCircleToEdgeAxis(sData& cData, + const dVector3 &v0, const dVector3 &v1, const dVector3 &v2, + const dVector3 &vCenterPoint, const dVector3 &vCylinderAxis1, + const dVector3 &vVx0, const dVector3 &vVx1, int iAxis) +{ + // calculate direction of edge + dVector3 vkl; + dVector3Subtract( vVx1 , vVx0 , vkl); + dNormalize3(vkl); + // starting point of edge + dVector3 vol; + dVector3Copy(vVx0,vol); + + // calculate angle cosine between cylinder axis and edge + dReal fdot2 = dVector3Dot(vkl , vCylinderAxis1); + + // if edge is perpendicular to cylinder axis + if(dFabs(fdot2)<1e-5f) + { + // this can't be separating axis, because edge is parallel to circle plane + return true; + } + + // find point of intersection between edge line and circle plane + dVector3 vTemp; + dVector3Subtract(vCenterPoint,vol,vTemp); + dReal fdot1 = dVector3Dot(vTemp,vCylinderAxis1); + dVector3 vpnt;// = vol + vkl * (fdot1/fdot2); + vpnt[0] = vol[0] + vkl[0] * fdot1/fdot2; + vpnt[1] = vol[1] + vkl[1] * fdot1/fdot2; + vpnt[2] = vol[2] + vkl[2] * fdot1/fdot2; + + // find tangent vector on circle with same center (vCenterPoint) that touches point of intersection (vpnt) + dVector3 vTangent; + dVector3Subtract(vCenterPoint,vpnt,vTemp); + dVector3Cross(vTemp,vCylinderAxis1,vTangent); + + // find vector orthogonal both to tangent and edge direction + dVector3 vAxis; + dVector3Cross(vTangent,vkl,vAxis); + + // use that vector as separating axis + return _cldTestAxis( cData ,v0, v1, v2, vAxis, iAxis ); +} + +// helper for less key strokes +// r = ( (v1 - v2) cross v3 ) cross v3 +inline void _CalculateAxis(const dVector3& v1, + const dVector3& v2, + const dVector3& v3, + dVector3& r) +{ + dVector3 t1; + dVector3 t2; + + dVector3Subtract(v1,v2,t1); + dVector3Cross(t1,v3,t2); + dVector3Cross(t2,v3,r); +} + +bool _cldTestSeparatingAxes(sData& cData, + const dVector3 &v0, + const dVector3 &v1, + const dVector3 &v2) +{ + + // calculate edge vectors + dVector3Subtract(v1 ,v0 , cData.vE0); + // cData.vE1 has been calculated before -> so save some cycles here + dVector3Subtract(v0 ,v2 , cData.vE2); + + // calculate caps centers in absolute space + dVector3 vCp0; + vCp0[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize* REAL(0.5)); + vCp0[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize* REAL(0.5)); + vCp0[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize* REAL(0.5)); + + dVector3 vCp1; + vCp1[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize* REAL(0.5)); + vCp1[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize* REAL(0.5)); + vCp1[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize* REAL(0.5)); + + // reset best axis + cData.iBestAxis = 0; + dVector3 vAxis; + + // axis cData.vNormal + //vAxis = -cData.vNormal; + vAxis[0] = -cData.vNormal[0]; + vAxis[1] = -cData.vNormal[1]; + vAxis[2] = -cData.vNormal[2]; + if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 1, true)) + { + return false; + } + + // axis CxE0 + // vAxis = ( cData.vCylinderAxis cross cData.vE0 ); + dVector3Cross(cData.vCylinderAxis, cData.vE0,vAxis); + if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 2)) + { + return false; + } + + // axis CxE1 + // vAxis = ( cData.vCylinderAxis cross cData.vE1 ); + dVector3Cross(cData.vCylinderAxis, cData.vE1,vAxis); + if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 3)) + { + return false; + } + + // axis CxE2 + // vAxis = ( cData.vCylinderAxis cross cData.vE2 ); + dVector3Cross(cData.vCylinderAxis, cData.vE2,vAxis); + if (!_cldTestAxis( cData ,v0, v1, v2, vAxis, 4)) + { + return false; + } + + // first vertex on triangle + // axis ((V0-Cp0) x C) x C + //vAxis = ( ( v0-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; + _CalculateAxis(v0 , vCp0 , cData.vCylinderAxis , vAxis); + if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 11)) + { + return false; + } + + // second vertex on triangle + // axis ((V1-Cp0) x C) x C + // vAxis = ( ( v1-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; + _CalculateAxis(v1 , vCp0 , cData.vCylinderAxis , vAxis); + if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 12)) + { + return false; + } + + // third vertex on triangle + // axis ((V2-Cp0) x C) x C + //vAxis = ( ( v2-vCp0 ) cross cData.vCylinderAxis ) cross cData.vCylinderAxis; + _CalculateAxis(v2 , vCp0 , cData.vCylinderAxis , vAxis); + if (!_cldTestAxis(cData, v0, v1, v2, vAxis, 13)) + { + return FALSE; + } + + // test cylinder axis + // vAxis = cData.vCylinderAxis; + dVector3Copy(cData.vCylinderAxis , vAxis); + if (!_cldTestAxis(cData , v0, v1, v2, vAxis, 14)) + { + return false; + } + + // Test top and bottom circle ring of cylinder for separation + dVector3 vccATop; + vccATop[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize * REAL(0.5)); + vccATop[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize * REAL(0.5)); + vccATop[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize * REAL(0.5)); + + dVector3 vccABottom; + vccABottom[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize * REAL(0.5)); + vccABottom[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize * REAL(0.5)); + vccABottom[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize * REAL(0.5)); + + + if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v0, v1, 15)) + { + return false; + } + + if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v1, v2, 16)) + { + return false; + } + + if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccATop, cData.vCylinderAxis, v0, v2, 17)) + { + return false; + } + + if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v0, v1, 18)) + { + return false; + } + + if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v1, v2, 19)) + { + return false; + } + + if (!_cldTestCircleToEdgeAxis(cData, v0, v1, v2, vccABottom, cData.vCylinderAxis, v0, v2, 20)) + { + return false; + } + + return true; +} + +bool _cldClipCylinderEdgeToTriangle(sData& cData, const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) +{ + // translate cylinder + dReal fTemp = dVector3Dot(cData.vCylinderAxis , cData.vContactNormal); + dVector3 vN2; + vN2[0] = cData.vContactNormal[0] - cData.vCylinderAxis[0]*fTemp; + vN2[1] = cData.vContactNormal[1] - cData.vCylinderAxis[1]*fTemp; + vN2[2] = cData.vContactNormal[2] - cData.vCylinderAxis[2]*fTemp; + + fTemp = dVector3Length(vN2); + if (fTemp < 1e-5) + { + return false; + } + + // Normalize it + vN2[0] /= fTemp; + vN2[1] /= fTemp; + vN2[2] /= fTemp; + + // calculate caps centers in absolute space + dVector3 vCposTrans; + vCposTrans[0] = cData.vCylinderPos[0] + vN2[0]*cData.fCylinderRadius; + vCposTrans[1] = cData.vCylinderPos[1] + vN2[1]*cData.fCylinderRadius; + vCposTrans[2] = cData.vCylinderPos[2] + vN2[2]*cData.fCylinderRadius; + + dVector3 vCEdgePoint0; + vCEdgePoint0[0] = vCposTrans[0] + cData.vCylinderAxis[0] * (cData.fCylinderSize* REAL(0.5)); + vCEdgePoint0[1] = vCposTrans[1] + cData.vCylinderAxis[1] * (cData.fCylinderSize* REAL(0.5)); + vCEdgePoint0[2] = vCposTrans[2] + cData.vCylinderAxis[2] * (cData.fCylinderSize* REAL(0.5)); + + dVector3 vCEdgePoint1; + vCEdgePoint1[0] = vCposTrans[0] - cData.vCylinderAxis[0] * (cData.fCylinderSize* REAL(0.5)); + vCEdgePoint1[1] = vCposTrans[1] - cData.vCylinderAxis[1] * (cData.fCylinderSize* REAL(0.5)); + vCEdgePoint1[2] = vCposTrans[2] - cData.vCylinderAxis[2] * (cData.fCylinderSize* REAL(0.5)); + + // transform cylinder edge points into triangle space + vCEdgePoint0[0] -= v0[0]; + vCEdgePoint0[1] -= v0[1]; + vCEdgePoint0[2] -= v0[2]; + + vCEdgePoint1[0] -= v0[0]; + vCEdgePoint1[1] -= v0[1]; + vCEdgePoint1[2] -= v0[2]; + + dVector4 plPlane; + dVector3 vPlaneNormal; + + // triangle plane + //plPlane = Plane4f( -cData.vNormal, 0); + vPlaneNormal[0] = -cData.vNormal[0]; + vPlaneNormal[1] = -cData.vNormal[1]; + vPlaneNormal[2] = -cData.vNormal[2]; + dConstructPlane(vPlaneNormal,REAL(0.0),plPlane); + if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return false; + } + + // plane with edge 0 + //plPlane = Plane4f( ( cData.vNormal cross cData.vE0 ), 1e-5f); + dVector3Cross(cData.vNormal,cData.vE0,vPlaneNormal); + dConstructPlane(vPlaneNormal,1e-5f,plPlane); + if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return false; + } + + // plane with edge 1 + //dVector3 vTemp = ( cData.vNormal cross cData.vE1 ); + dVector3Cross(cData.vNormal,cData.vE1,vPlaneNormal); + fTemp = dVector3Dot(cData.vE0 , vPlaneNormal) - 1e-5; + //plPlane = Plane4f( vTemp, -(( cData.vE0 dot vTemp )-1e-5f)); + dConstructPlane(vPlaneNormal,-fTemp,plPlane); + if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return false; + } + + // plane with edge 2 + // plPlane = Plane4f( ( cData.vNormal cross cData.vE2 ), 1e-5f); + dVector3Cross(cData.vNormal,cData.vE2,vPlaneNormal); + dConstructPlane(vPlaneNormal,1e-5f,plPlane); + if(!dClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return false; + } + + // return capsule edge points into absolute space + vCEdgePoint0[0] += v0[0]; + vCEdgePoint0[1] += v0[1]; + vCEdgePoint0[2] += v0[2]; + + vCEdgePoint1[0] += v0[0]; + vCEdgePoint1[1] += v0[1]; + vCEdgePoint1[2] += v0[2]; + + // calculate depths for both contact points + dVector3 vTemp; + dVector3Subtract(vCEdgePoint0,cData.vCylinderPos, vTemp); + dReal fRestDepth0 = -dVector3Dot(vTemp,cData.vContactNormal) + cData.fBestrt; + dVector3Subtract(vCEdgePoint1,cData.vCylinderPos, vTemp); + dReal fRestDepth1 = -dVector3Dot(vTemp,cData.vContactNormal) + cData.fBestrt; + + dReal fDepth0 = cData.fBestDepth - (fRestDepth0); + dReal fDepth1 = cData.fBestDepth - (fRestDepth1); + + // clamp depths to zero + if(fDepth0 < REAL(0.0) ) + { + fDepth0 = REAL(0.0); + } + + if(fDepth1 REAL(0.0)) + { + // get top circle + vCylinderCirclePos[0] = cData.vCylinderPos[0] + cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[1] = cData.vCylinderPos[1] + cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[2] = cData.vCylinderPos[2] + cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + + vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(-1.0); + } + else + { + // get bottom circle + vCylinderCirclePos[0] = cData.vCylinderPos[0] - cData.vCylinderAxis[0]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[1] = cData.vCylinderPos[1] - cData.vCylinderAxis[1]*(cData.fCylinderSize*REAL(0.5)); + vCylinderCirclePos[2] = cData.vCylinderPos[2] - cData.vCylinderAxis[2]*(cData.fCylinderSize*REAL(0.5)); + + vCylinderCircleNormal_Rel[nCYLINDER_AXIS] = REAL(1.0); + } + + dVector3 vTemp; + dQuatInv(cData.qCylinderRot , cData.qInvCylinderRot); + // transform triangle points to space of cylinder circle + for(int i=0; i<3; i++) + { + dVector3Subtract(avPoints[i] , vCylinderCirclePos , vTemp); + dQuatTransform(cData.qInvCylinderRot,vTemp,avPoints[i]); + } + + int iTmpCounter1 = 0; + int iTmpCounter2 = 0; + dVector4 plPlane; + + // plane of cylinder that contains circle for intersection + //plPlane = Plane4f( vCylinderCircleNormal_Rel, 0.0f ); + dConstructPlane(vCylinderCircleNormal_Rel,REAL(0.0),plPlane); + dClipPolyToPlane(avPoints, 3, avTempArray1, iTmpCounter1, plPlane); + + // Body of base circle of Cylinder + int nCircleSegment = 0; + for (nCircleSegment = 0; nCircleSegment < nCYLINDER_CIRCLE_SEGMENTS; nCircleSegment++) + { + dConstructPlane(cData.avCylinderNormals[nCircleSegment],cData.fCylinderRadius,plPlane); + + if (0 == (nCircleSegment % 2)) + { + dClipPolyToPlane( avTempArray1 , iTmpCounter1 , avTempArray2, iTmpCounter2, plPlane); + } + else + { + dClipPolyToPlane( avTempArray2, iTmpCounter2, avTempArray1 , iTmpCounter1 , plPlane ); + } + + dIASSERT( iTmpCounter1 >= 0 && iTmpCounter1 <= nMAX_CYLINDER_TRIANGLE_CLIP_POINTS ); + dIASSERT( iTmpCounter2 >= 0 && iTmpCounter2 <= nMAX_CYLINDER_TRIANGLE_CLIP_POINTS ); + } + + // back transform clipped points to absolute space + dReal ftmpdot; + dReal fTempDepth; + dVector3 vPoint; + + int i = 0; + if (nCircleSegment %2) + { + for( i=0; i REAL(0.0)) + { + cData.gLocalContacts[cData.nContacts].fDepth = fTempDepth; + dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); + dVector3Copy(vPoint,cData.gLocalContacts[cData.nContacts].vPos); + cData.gLocalContacts[cData.nContacts].nFlags = 1; + cData.nContacts++; + } + } + } + else + { + for( i=0; i REAL(0.0)) + { + cData.gLocalContacts[cData.nContacts].fDepth = fTempDepth; + dVector3Copy(cData.vContactNormal,cData.gLocalContacts[cData.nContacts].vNormal); + dVector3Copy(vPoint,cData.gLocalContacts[cData.nContacts].vPos); + cData.gLocalContacts[cData.nContacts].nFlags = 1; + cData.nContacts++; + } + } + } +} + +void TestOneTriangleVsCylinder( sData& cData, + const dVector3 &v0, + const dVector3 &v1, + const dVector3 &v2, + const bool bDoubleSided) +{ + + // calculate triangle normal + dVector3Subtract( v2 , v1 ,cData.vE1); + dVector3 vTemp; + dVector3Subtract( v0 , v1 ,vTemp); + dVector3Cross(cData.vE1 , vTemp , cData.vNormal ); + + dNormalize3( cData.vNormal); + + // create plane from triangle + //Plane4f plTrianglePlane = Plane4f( vPolyNormal, v0 ); + dReal plDistance = -dVector3Dot(v0, cData.vNormal); + dVector4 plTrianglePlane; + dConstructPlane( cData.vNormal,plDistance,plTrianglePlane); + + // calculate sphere distance to plane + dReal fDistanceCylinderCenterToPlane = dPointPlaneDistance(cData.vCylinderPos , plTrianglePlane); + + // Sphere must be over positive side of triangle + if(fDistanceCylinderCenterToPlane < 0 && !bDoubleSided) + { + // if not don't generate contacts + return; + } + + dVector3 vPnt0; + dVector3 vPnt1; + dVector3 vPnt2; + + if (fDistanceCylinderCenterToPlane < REAL(0.0) ) + { + // flip it + dVector3Copy(v0 , vPnt0); + dVector3Copy(v1 , vPnt2); + dVector3Copy(v2 , vPnt1); + } + else + { + dVector3Copy(v0 , vPnt0); + dVector3Copy(v1 , vPnt1); + dVector3Copy(v2 , vPnt2); + } + + cData.fBestDepth = MAX_REAL; + + // do intersection test and find best separating axis + if(!_cldTestSeparatingAxes(cData , vPnt0, vPnt1, vPnt2) ) + { + // if not found do nothing + return; + } + + // if best separation axis is not found + if ( cData.iBestAxis == 0 ) + { + // this should not happen (we should already exit in that case) + dIASSERT(false); + // do nothing + return; + } + + dReal fdot = dVector3Dot( cData.vContactNormal , cData.vCylinderAxis ); + + // choose which clipping method are we going to apply + if (dFabs(fdot) < REAL(0.9) ) + { + if (!_cldClipCylinderEdgeToTriangle(cData ,vPnt0, vPnt1, vPnt2)) + { + return; + } + } + else + { + _cldClipCylinderToTriangle(cData ,vPnt0, vPnt1, vPnt2); + } + +} + +void _InitCylinderTrimeshData(sData& cData) +{ + // get cylinder information + // Rotation + const dReal* pRotCyc = dGeomGetRotation(cData.gCylinder); + dMatrix3Copy(pRotCyc,cData.mCylinderRot); + dGeomGetQuaternion(cData.gCylinder,cData.qCylinderRot); + + // Position + const dVector3* pPosCyc = (const dVector3*)dGeomGetPosition(cData.gCylinder); + dVector3Copy(*pPosCyc,cData.vCylinderPos); + // Cylinder axis + dMat3GetCol(cData.mCylinderRot,nCYLINDER_AXIS,cData.vCylinderAxis); + // get cylinder radius and size + dGeomCylinderGetParams(cData.gCylinder,&cData.fCylinderRadius,&cData.fCylinderSize); + + // get trimesh position and orientation + const dReal* pRotTris = dGeomGetRotation(cData.gTrimesh); + dMatrix3Copy(pRotTris,cData.mTrimeshRot); + dGeomGetQuaternion(cData.gTrimesh,cData.qTrimeshRot); + + // Position + const dVector3* pPosTris = (const dVector3*)dGeomGetPosition(cData.gTrimesh); + dVector3Copy(*pPosTris,cData.vTrimeshPos); + + + // calculate basic angle for 8-gon + dReal fAngle = M_PI / nCYLINDER_CIRCLE_SEGMENTS; + // calculate angle increment + dReal fAngleIncrement = fAngle*REAL(2.0); + + // calculate plane normals + // axis dependant code + for(int i=0; i_OBBCollider; + + Point cCenter(cData.vCylinderPos[0],cData.vCylinderPos[1],cData.vCylinderPos[2]); + + Point cExtents(cData.fCylinderRadius,cData.fCylinderRadius,cData.fCylinderRadius); + cExtents[nCYLINDER_AXIS] = cData.fCylinderSize * REAL(0.5); + + Matrix3x3 obbRot; + + obbRot[0][0] = cData.mCylinderRot[0]; + obbRot[1][0] = cData.mCylinderRot[1]; + obbRot[2][0] = cData.mCylinderRot[2]; + + obbRot[0][1] = cData.mCylinderRot[4]; + obbRot[1][1] = cData.mCylinderRot[5]; + obbRot[2][1] = cData.mCylinderRot[6]; + + obbRot[0][2] = cData.mCylinderRot[8]; + obbRot[1][2] = cData.mCylinderRot[9]; + obbRot[2][2] = cData.mCylinderRot[10]; + + OBB obbCCylinder(cCenter,cExtents,obbRot); + + Matrix4x4 CCylinderMatrix; + MakeMatrix(cData.vCylinderPos, cData.mCylinderRot, CCylinderMatrix); + + Matrix4x4 MeshMatrix; + MakeMatrix(cData.vTrimeshPos, cData.mTrimeshRot, MeshMatrix); + + // TC results + if (cData.gTrimesh->doBoxTC) + { + dxTriMesh::BoxTC* BoxTC = 0; + for (int i = 0; i < cData.gTrimesh->BoxTCCache.size(); i++) + { + if (cData.gTrimesh->BoxTCCache[i].Geom == cData.gCylinder) + { + BoxTC = &cData.gTrimesh->BoxTCCache[i]; + break; + } + } + if (!BoxTC) + { + cData.gTrimesh->BoxTCCache.push(dxTriMesh::BoxTC()); + + BoxTC = &cData.gTrimesh->BoxTCCache[cData.gTrimesh->BoxTCCache.size() - 1]; + BoxTC->Geom = cData.gCylinder; + BoxTC->FatCoeff = REAL(1.0); + } + + // Intersect + Collider.SetTemporalCoherence(true); + Collider.Collide(*BoxTC, obbCCylinder, cData.gTrimesh->Data->BVTree, null, &MeshMatrix); + } + else + { + Collider.SetTemporalCoherence(false); + //Collider.Collide(dxTriMesh::defaultBoxCache, obbCCylinder, cData.gTrimesh->Data->BVTree, null,&MeshMatrix); + Collider.Collide(cData.gTrimesh->boxCache, obbCCylinder, cData.gTrimesh->Data->BVTree, null,&MeshMatrix); + } + + // Retrieve data + int TriCount = Collider.GetNbTouchedPrimitives(); + const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); + + + if (TriCount != 0) + { + if (cData.gTrimesh->ArrayCallback != null) + { + cData.gTrimesh->ArrayCallback(cData.gTrimesh, cData.gCylinder, Triangles, TriCount); + } + + //int OutTriCount = 0; + + // loop through all intersecting triangles + for (int i = 0; i < TriCount; i++) + { + if(cData.nContacts >= (cData.iFlags & NUMC_MASK)) + { + break; + } + + const int& Triint = Triangles[i]; + if (!Callback(cData.gTrimesh, cData.gCylinder, Triint)) continue; + + + dVector3 dv[3]; + FetchTriangle(cData.gTrimesh, Triint, cData.vTrimeshPos, cData.mTrimeshRot, dv); + + // test this triangle + TestOneTriangleVsCylinder(cData , dv[0],dv[1],dv[2], false); + } + } + + return _ProcessLocalContacts(cData); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.cpp new file mode 100644 index 00000000..b16d4d81 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.cpp @@ -0,0 +1,653 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +core collision functions and data structures, plus part of the public API +for geometry objects + +*/ + +#include "ode/ode_common.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_objects.h" +#include "ode/ode_collision_kernel.h" +#include "ode/ode_collision_util.h" +#include "ode/ode_collision_std.h" +#include "ode/ode_collision_transform.h" +#include "ode/ode_collision_trimesh_internal.h" + +#ifdef _MSC_VER +#pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" +#endif + +//**************************************************************************** +// helper functions for dCollide()ing a space with another geom + +// this struct records the parameters passed to dCollideSpaceGeom() + +struct SpaceGeomColliderData { + int flags; // space left in contacts array + dContactGeom *contact; + int skip; +}; + + +static void space_geom_collider (void *data, dxGeom *o1, dxGeom *o2) +{ + SpaceGeomColliderData *d = (SpaceGeomColliderData*) data; + if (d->flags & NUMC_MASK) { + int n = dCollide (o1,o2,d->flags,d->contact,d->skip); + d->contact = CONTACT (d->contact,d->skip*n); + d->flags -= n; + } +} + + +static int dCollideSpaceGeom (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + SpaceGeomColliderData data; + data.flags = flags; + data.contact = contact; + data.skip = skip; + dSpaceCollide2 (o1,o2,&data,&space_geom_collider); + return (flags & NUMC_MASK) - (data.flags & NUMC_MASK); +} + +//**************************************************************************** +// dispatcher for the N^2 collider functions + +// function pointers and modes for n^2 class collider functions + +struct dColliderEntry { + dColliderFn *fn; // collider function, 0 = no function available + int reverse; // 1 = reverse o1 and o2 +}; +static dColliderEntry colliders[dGeomNumClasses][dGeomNumClasses]; +static int colliders_initialized = 0; + + +// setCollider() will refuse to write over a collider entry once it has +// been written. + +static void setCollider (int i, int j, dColliderFn *fn) +{ + if (colliders[i][j].fn == 0) { + colliders[i][j].fn = fn; + colliders[i][j].reverse = 0; + } + if (colliders[j][i].fn == 0) { + colliders[j][i].fn = fn; + colliders[j][i].reverse = 1; + } +} + + +static void setAllColliders (int i, dColliderFn *fn) +{ + for (int j=0; jtype >= 0 && o1->type < dGeomNumClasses,"bad o1 class number"); + dUASSERT(o2->type >= 0 && o2->type < dGeomNumClasses,"bad o2 class number"); + + // no contacts if both geoms are the same + if (o1 == o2) return 0; + + // no contacts if both geoms on the same body, and the body is not 0 + if (o1->body == o2->body && o1->body) return 0; + + dColliderEntry *ce = &colliders[o1->type][o2->type]; + int count = 0; + if (ce->fn) { + if (ce->reverse) { + count = (*ce->fn) (o2,o1,flags,contact,skip); + for (int i=0; inormal[0] = -c->normal[0]; + c->normal[1] = -c->normal[1]; + c->normal[2] = -c->normal[2]; + dxGeom *tmp = c->g1; + c->g1 = c->g2; + c->g2 = tmp; + } + } + else { + count = (*ce->fn) (o1,o2,flags,contact,skip); + } + } + return count; +} + +//**************************************************************************** +// dxGeom + +dxGeom::dxGeom (dSpaceID _space, int is_placeable) +{ + initColliders(); + + // setup body vars. invalid type of -1 must be changed by the constructor. + type = -1; + gflags = GEOM_DIRTY | GEOM_AABB_BAD | GEOM_ENABLED; + if (is_placeable) gflags |= GEOM_PLACEABLE; + data = 0; + body = 0; + body_next = 0; + if (is_placeable) { + dxPosR *pr = (dxPosR*) dAlloc (sizeof(dxPosR)); + pos = pr->pos; + R = pr->R; + dSetZero (pos,4); + dRSetIdentity (R); + } + else { + pos = 0; + R = 0; + } + + // setup space vars + next = 0; + tome = 0; + parent_space = 0; + dSetZero (aabb,6); + category_bits = ~0; + collide_bits = ~0; + + // put this geom in a space if required + if (_space) dSpaceAdd (_space,this); +} + + +dxGeom::~dxGeom() +{ + if (parent_space) dSpaceRemove (parent_space,this); + if ((gflags & GEOM_PLACEABLE) && !body) dFree (pos,sizeof(dxPosR)); + bodyRemove(); +} + + +int dxGeom::AABBTest (dxGeom *o, dReal aabb[6]) +{ + return 1; +} + + +void dxGeom::bodyRemove() +{ + if (body) { + // delete this geom from body list + dxGeom **last = &body->geom, *g = body->geom; + while (g) { + if (g == this) { + *last = g->body_next; + break; + } + last = &g->body_next; + g = g->body_next; + } + body = 0; + body_next = 0; + } +} + +//**************************************************************************** +// misc + +dxGeom *dGeomGetBodyNext (dxGeom *geom) +{ + return geom->body_next; +} + +//**************************************************************************** +// public API for geometry objects + +#define CHECK_NOT_LOCKED(space) \ + dUASSERT (!(space && space->lock_count), \ + "invalid operation for geom in locked space"); + + +void dGeomDestroy (dxGeom *g) +{ + dAASSERT (g); + delete g; +} + + +void dGeomSetData (dxGeom *g, void *data) +{ + dAASSERT (g); + g->data = data; +} + + +void *dGeomGetData (dxGeom *g) +{ + dAASSERT (g); + return g->data; +} + + +void dGeomSetBody (dxGeom *g, dxBody *b) +{ + dAASSERT (g); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + CHECK_NOT_LOCKED (g->parent_space); + + if (b) { + if (!g->body) dFree (g->pos,sizeof(dxPosR)); + g->pos = b->pos; + g->R = b->R; + dGeomMoved (g); + if (g->body != b) { + g->bodyRemove(); + g->bodyAdd (b); + } + } + else { + if (g->body) { + dxPosR *pr = (dxPosR*) dAlloc (sizeof(dxPosR)); + g->pos = pr->pos; + g->R = pr->R; + memcpy (g->pos,g->body->pos,sizeof(dVector3)); + memcpy (g->R,g->body->R,sizeof(dMatrix3)); + g->bodyRemove(); + } + // dGeomMoved() should not be called if the body is being set to 0, as the + // new position of the geom is set to the old position of the body, so the + // effective position of the geom remains unchanged. + } +} + + +dBodyID dGeomGetBody (dxGeom *g) +{ + dAASSERT (g); + return g->body; +} + + +void dGeomSetPosition (dxGeom *g, dReal x, dReal y, dReal z) +{ + dAASSERT (g); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + CHECK_NOT_LOCKED (g->parent_space); + if (g->body) { + // this will call dGeomMoved (g), so we don't have to + dBodySetPosition (g->body,x,y,z); + } + else { + g->pos[0] = x; + g->pos[1] = y; + g->pos[2] = z; + dGeomMoved (g); + } +} + + +void dGeomSetRotation (dxGeom *g, const dMatrix3 R) +{ + dAASSERT (g && R); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + CHECK_NOT_LOCKED (g->parent_space); + if (g->body) { + // this will call dGeomMoved (g), so we don't have to + dBodySetRotation (g->body,R); + } + else { + memcpy (g->R,R,sizeof(dMatrix3)); + dGeomMoved (g); + } +} + + +void dGeomSetQuaternion (dxGeom *g, const dQuaternion quat) +{ + dAASSERT (g && quat); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + CHECK_NOT_LOCKED (g->parent_space); + if (g->body) { + // this will call dGeomMoved (g), so we don't have to + dBodySetQuaternion (g->body,quat); + } + else { + dQtoR (quat, g->R); + dGeomMoved (g); + } +} + + +const dReal * dGeomGetPosition (dxGeom *g) +{ + dAASSERT (g); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + return g->pos; +} + +void dGeomGetRelPointPos (dGeomID g, dReal px, dReal py, dReal pz, + dVector3 result) +{ + dAASSERT (g); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + dVector3 prel,p; + prel[0] = px; + prel[1] = py; + prel[2] = pz; + prel[3] = 0; + dMULTIPLY0_331 (p,g->R,prel); + result[0] = p[0] + g->pos[0]; + result[1] = p[1] + g->pos[1]; + result[2] = p[2] + g->pos[2]; +} + + +const dReal * dGeomGetRotation (dxGeom *g) +{ + dAASSERT (g); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + return g->R; +} + + +void dGeomGetQuaternion (dxGeom *g, dQuaternion quat) +{ + dAASSERT (g); + dUASSERT (g->gflags & GEOM_PLACEABLE,"geom must be placeable"); + if (g->body) { + const dReal * body_quat = dBodyGetQuaternion (g->body); + quat[0] = body_quat[0]; + quat[1] = body_quat[1]; + quat[2] = body_quat[2]; + quat[3] = body_quat[3]; + } + else { + dRtoQ (g->R, quat); + } +} + + +void dGeomGetAABB (dxGeom *g, dReal aabb[6]) +{ + dAASSERT (g); + dAASSERT (aabb); + g->recomputeAABB(); + memcpy (aabb,g->aabb,6 * sizeof(dReal)); +} + + +int dGeomIsSpace (dxGeom *g) +{ + dAASSERT (g); + return IS_SPACE(g); +} + + +dSpaceID dGeomGetSpace (dxGeom *g) +{ + dAASSERT (g); + return g->parent_space; +} + + +int dGeomGetClass (dxGeom *g) +{ + dAASSERT (g); + return g->type; +} + + +void dGeomSetCategoryBits (dxGeom *g, unsigned long bits) +{ + dAASSERT (g); + CHECK_NOT_LOCKED (g->parent_space); + g->category_bits = bits; +} + + +void dGeomSetCollideBits (dxGeom *g, unsigned long bits) +{ + dAASSERT (g); + CHECK_NOT_LOCKED (g->parent_space); + g->collide_bits = bits; +} + + +unsigned long dGeomGetCategoryBits (dxGeom *g) +{ + dAASSERT (g); + return g->category_bits; +} + + +unsigned long dGeomGetCollideBits (dxGeom *g) +{ + dAASSERT (g); + return g->collide_bits; +} + + +void dGeomEnable (dxGeom *g) +{ + dAASSERT (g); + g->gflags |= GEOM_ENABLED; +} + +void dGeomDisable (dxGeom *g) +{ + dAASSERT (g); + g->gflags &= ~GEOM_ENABLED; +} + +int dGeomIsEnabled (dxGeom *g) +{ + dAASSERT (g); + return (g->gflags & GEOM_ENABLED) != 0; +} + + +//**************************************************************************** +// C interface that lets the user make new classes. this interface is a lot +// more cumbersome than C++ subclassing, which is what is used internally +// in ODE. this API is mainly to support legacy code. + +static int num_user_classes = 0; +static dGeomClass user_classes [dMaxUserClasses]; + + +struct dxUserGeom : public dxGeom { + void *user_data; + + dxUserGeom (int class_num); + ~dxUserGeom(); + void computeAABB(); + int AABBTest (dxGeom *o, dReal aabb[6]); +}; + + +dxUserGeom::dxUserGeom (int class_num) : dxGeom (0,1) +{ + type = class_num; + int size = user_classes[type-dFirstUserClass].bytes; + user_data = dAlloc (size); + memset (user_data,0,size); +} + + +dxUserGeom::~dxUserGeom() +{ + dGeomClass *c = &user_classes[type-dFirstUserClass]; + if (c->dtor) c->dtor (this); + dFree (user_data,c->bytes); +} + + +void dxUserGeom::computeAABB() +{ + user_classes[type-dFirstUserClass].aabb (this,aabb); +} + + +int dxUserGeom::AABBTest (dxGeom *o, dReal aabb[6]) +{ + dGeomClass *c = &user_classes[type-dFirstUserClass]; + if (c->aabb_test) return c->aabb_test (this,o,aabb); + else return 1; +} + + +static int dCollideUserGeomWithGeom (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + // this generic collider function is called the first time that a user class + // tries to collide against something. it will find out the correct collider + // function and then set the colliders array so that the correct function is + // called directly the next time around. + + int t1 = o1->type; // note that o1 is a user geom + int t2 = o2->type; // o2 *may* be a user geom + + // find the collider function to use. if o1 does not know how to collide with + // o2, then o2 might know how to collide with o1 (provided that it is a user + // geom). + dColliderFn *fn = user_classes[t1-dFirstUserClass].collider (t2); + int reverse = 0; + if (!fn && t2 >= dFirstUserClass && t2 <= dLastUserClass) { + fn = user_classes[t2-dFirstUserClass].collider (t1); + reverse = 1; + } + + // set the colliders array so that the correct function is called directly + // the next time around. note that fn can be 0 here if no collider was found, + // which means that dCollide() will always return 0 for this case. + colliders[t1][t2].fn = fn; + colliders[t1][t2].reverse = reverse; + colliders[t2][t1].fn = fn; + colliders[t2][t1].reverse = !reverse; + + // now call the collider function indirectly through dCollide(), so that + // contact reversing is properly handled. + return dCollide (o1,o2,flags,contact,skip); +} + + +int dCreateGeomClass (const dGeomClass *c) +{ + dUASSERT(c && c->bytes >= 0 && c->collider && c->aabb,"bad geom class"); + + if (num_user_classes >= dMaxUserClasses) { + dDebug (0,"too many user classes, you must increase the limit and " + "recompile ODE"); + } + user_classes[num_user_classes] = *c; + int class_number = num_user_classes + dFirstUserClass; + initColliders(); + setAllColliders (class_number,&dCollideUserGeomWithGeom); + + num_user_classes++; + return class_number; +} + + +void * dGeomGetClassData (dxGeom *g) +{ + dUASSERT (g && g->type >= dFirstUserClass && + g->type <= dLastUserClass,"not a custom class"); + dxUserGeom *user = (dxUserGeom*) g; + return user->user_data; +} + + +dGeomID dCreateGeom (int classnum) +{ + dUASSERT (classnum >= dFirstUserClass && + classnum <= dLastUserClass,"not a custom class"); + return new dxUserGeom (classnum); +} + +//**************************************************************************** +// here is where we deallocate any memory that has been globally +// allocated, or free other global resources. + +void dCloseODE() +{ + colliders_initialized = 0; + num_user_classes = 0; +} + + diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.h new file mode 100644 index 00000000..d52f28e8 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_kernel.h @@ -0,0 +1,202 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +internal data structures and functions for collision detection. + +*/ + +#ifndef _ODE_COLLISION_KERNEL_H_ +#define _ODE_COLLISION_KERNEL_H_ + +#include "ode/ode_common.h" +#include "ode/ode_contact.h" +#include "ode/ode_collision.h" +#include "ode/ode_objects_private.h" + +//**************************************************************************** +// constants and macros + +// mask for the number-of-contacts field in the dCollide() flags parameter +#define NUMC_MASK (0xffff) + +#define IS_SPACE(geom) \ + ((geom)->type >= dFirstSpaceClass && (geom)->type <= dLastSpaceClass) + +//**************************************************************************** +// geometry object base class + +// position vector and rotation matrix for geometry objects that are not +// connected to bodies. + +struct dxPosR { + dVector3 pos; + dMatrix3 R; +}; + + +// geom flags. +// +// GEOM_DIRTY means that the space data structures for this geom are +// potentially not up to date. NOTE THAT all space parents of a dirty geom +// are themselves dirty. this is an invariant that must be enforced. +// +// GEOM_AABB_BAD means that the cached AABB for this geom is not up to date. +// note that GEOM_DIRTY does not imply GEOM_AABB_BAD, as the geom might +// recalculate its own AABB but does not know how to update the space data +// structures for the space it is in. but GEOM_AABB_BAD implies GEOM_DIRTY. +// the valid combinations are: 0, GEOM_DIRTY, GEOM_DIRTY|GEOM_AABB_BAD. + +enum { + GEOM_DIRTY = 1, // geom is 'dirty', i.e. position unknown + GEOM_AABB_BAD = 2, // geom's AABB is not valid + GEOM_PLACEABLE = 4, // geom is placeable + GEOM_ENABLED = 8, // geom is enabled + + // Ray specific + RAY_FIRSTCONTACT = 0x10000, + RAY_BACKFACECULL = 0x20000, + RAY_CLOSEST_HIT = 0x40000 +}; + + +// geometry object base class. pos and R will either point to a separately +// allocated buffer (if body is 0 - pos points to the dxPosR object) or to +// the pos and R of the body (if body nonzero). +// a dGeomID is a pointer to this object. + +struct dxGeom : public dBase { + int type; // geom type number, set by subclass constructor + int gflags; // flags used by geom and space + void *data; // user-defined data pointer + dBodyID body; // dynamics body associated with this object (if any) + dxGeom *body_next; // next geom in body's linked list of associated geoms + dReal *pos; // pointer to object's position vector + dReal *R; // pointer to object's rotation matrix + + // information used by spaces + dxGeom *next; // next geom in linked list of geoms + dxGeom **tome; // linked list backpointer + dxSpace *parent_space;// the space this geom is contained in, 0 if none + dReal aabb[6]; // cached AABB for this space + unsigned long category_bits,collide_bits; + + dxGeom (dSpaceID _space, int is_placeable); + virtual ~dxGeom(); + + virtual void computeAABB()=0; + // compute the AABB for this object and put it in aabb. this function + // always performs a fresh computation, it does not inspect the + // GEOM_AABB_BAD flag. + + virtual int AABBTest (dxGeom *o, dReal aabb[6]); + // test whether the given AABB object intersects with this object, return + // 1=yes, 0=no. this is used as an early-exit test in the space collision + // functions. the default implementation returns 1, which is the correct + // behavior if no more detailed implementation can be provided. + + // utility functions + + // compute the AABB only if it is not current. this function manipulates + // the GEOM_AABB_BAD flag. + + void recomputeAABB() { + if (gflags & GEOM_AABB_BAD) { + computeAABB(); + gflags &= ~GEOM_AABB_BAD; + } + } + + // add and remove this geom from a linked list maintained by a space. + + void spaceAdd (dxGeom **first_ptr) { + next = *first_ptr; + tome = first_ptr; + if (*first_ptr) (*first_ptr)->tome = &next; + *first_ptr = this; + } + void spaceRemove() { + if (next) next->tome = tome; + *tome = next; + } + + // add and remove this geom from a linked list maintained by a body. + + void bodyAdd (dxBody *b) { + body = b; + body_next = b->geom; + b->geom = this; + } + void bodyRemove(); +}; + +//**************************************************************************** +// the base space class +// +// the contained geoms are divided into two kinds: clean and dirty. +// the clean geoms have not moved since they were put in the list, +// and their AABBs are valid. the dirty geoms have changed position, and +// their AABBs are may not be valid. the two types are distinguished by the +// GEOM_DIRTY flag. all dirty geoms come *before* all clean geoms in the list. + +struct dxSpace : public dxGeom { + int count; // number of geoms in this space + dxGeom *first; // first geom in list + int cleanup; // cleanup mode, 1=destroy geoms on exit + + // cached state for getGeom() + int current_index; // only valid if current_geom != 0 + dxGeom *current_geom; // if 0 then there is no information + + // locking stuff. the space is locked when it is currently traversing its + // internal data structures, e.g. in collide() and collide2(). operations + // that modify the contents of the space are not permitted when the space + // is locked. + int lock_count; + + dxSpace (dSpaceID _space); + ~dxSpace(); + + void computeAABB(); + + void setCleanup (int mode); + int getCleanup(); + int query (dxGeom *geom); + int getNumGeoms(); + virtual dxGeom *getGeom (int i); + + virtual void add (dxGeom *); + virtual void remove (dxGeom *); + virtual void dirty (dxGeom *); + + virtual void cleanGeoms()=0; + // turn all dirty geoms into clean geoms by computing their AABBs and any + // other space data structures that are required. this should clear the + // GEOM_DIRTY and GEOM_AABB_BAD flags of all geoms. + + virtual void collide (void *data, dNearCallback *callback)=0; + virtual void collide2 (void *data, dxGeom *geom, dNearCallback *callback)=0; +}; + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_quadtreespace.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_quadtreespace.cpp new file mode 100644 index 00000000..435406e0 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_quadtreespace.cpp @@ -0,0 +1,583 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// QuadTreeSpace by Erwin de Vries. + +#include "ode/ode_common.h" +#include "ode/ode_matrix.h" +#include "ode/ode_collision_space.h" +#include "ode/ode_collision.h" +#include "ode/ode_collision_kernel.h" + +#include "ode/ode_collision_space_internal.h" + + +#define AXIS0 0 +#define AXIS1 1 +#define UP 2 + +//#define DRAWBLOCKS + +const int SPLITAXIS = 2; +const int SPLITS = SPLITAXIS * SPLITAXIS; + +#define GEOM_ENABLED(g) (g)->gflags & GEOM_ENABLED + +class Block{ +public: + dReal MinX, MaxX; + dReal MinZ, MaxZ; + + dGeomID First; + int GeomCount; + + Block* Parent; + Block* Children; + + void Create(const dVector3 Center, const dVector3 Extents, Block* Parent, int Depth, Block*& Blocks); + + void Collide(void* UserData, dNearCallback* Callback); + void Collide(dGeomID Object, dGeomID g, void* UserData, dNearCallback* Callback); + + void CollideLocal(dGeomID Object, void* UserData, dNearCallback* Callback); + + void AddObject(dGeomID Object); + void DelObject(dGeomID Object); + void Traverse(dGeomID Object); + + bool Inside(const dReal* AABB); + + Block* GetBlock(const dReal* AABB); + Block* GetBlockChild(const dReal* AABB); +}; + + +#ifdef DRAWBLOCKS +#include "ode/ode_drawstuff.h" + +static void DrawBlock(Block* Block){ + dVector3 v[8]; + v[0][AXIS0] = Block->MinX; + v[0][UP] = REAL(-1.0); + v[0][AXIS1] = Block->MinZ; + + v[1][AXIS0] = Block->MinX; + v[1][UP] = REAL(-1.0); + v[1][AXIS1] = Block->MaxZ; + + v[2][AXIS0] = Block->MaxX; + v[2][UP] = REAL(-1.0); + v[2][AXIS1] = Block->MinZ; + + v[3][AXIS0] = Block->MaxX; + v[3][UP] = REAL(-1.0); + v[3][AXIS1] = Block->MaxZ; + + v[4][AXIS0] = Block->MinX; + v[4][UP] = REAL(1.0); + v[4][AXIS1] = Block->MinZ; + + v[5][AXIS0] = Block->MinX; + v[5][UP] = REAL(1.0); + v[5][AXIS1] = Block->MaxZ; + + v[6][AXIS0] = Block->MaxX; + v[6][UP] = REAL(1.0); + v[6][AXIS1] = Block->MinZ; + + v[7][AXIS0] = Block->MaxX; + v[7][UP] = REAL(1.0); + v[7][AXIS1] = Block->MaxZ; + + // Bottom + dsDrawLine(v[0], v[1]); + dsDrawLine(v[1], v[3]); + dsDrawLine(v[3], v[2]); + dsDrawLine(v[2], v[0]); + + // Top + dsDrawLine(v[4], v[5]); + dsDrawLine(v[5], v[7]); + dsDrawLine(v[7], v[6]); + dsDrawLine(v[6], v[4]); + + // Sides + dsDrawLine(v[0], v[4]); + dsDrawLine(v[1], v[5]); + dsDrawLine(v[2], v[6]); + dsDrawLine(v[3], v[7]); +} +#endif //DRAWBLOCKS + + +void Block::Create(const dVector3 Center, const dVector3 Extents, Block* Parent, int Depth, Block*& Blocks){ + GeomCount = 0; + First = 0; + + MinX = Center[AXIS0] - Extents[AXIS0]; + MaxX = Center[AXIS0] + Extents[AXIS0]; + + MinZ = Center[AXIS1] - Extents[AXIS1]; + MaxZ = Center[AXIS1] + Extents[AXIS1]; + + this->Parent = Parent; + if (Depth > 0){ + Children = Blocks; + Blocks += SPLITS; + + dVector3 ChildExtents; + ChildExtents[AXIS0] = Extents[AXIS0] / SPLITAXIS; + ChildExtents[AXIS1] = Extents[AXIS1] / SPLITAXIS; + ChildExtents[UP] = Extents[UP]; + + for (int i = 0; i < SPLITAXIS; i++){ + for (int j = 0; j < SPLITAXIS; j++){ + int Index = i * SPLITAXIS + j; + + dVector3 ChildCenter; + ChildCenter[AXIS0] = Center[AXIS0] - Extents[AXIS0] + ChildExtents[AXIS0] + i * (ChildExtents[AXIS0] * 2); + ChildCenter[AXIS1] = Center[AXIS1] - Extents[AXIS1] + ChildExtents[AXIS1] + j * (ChildExtents[AXIS1] * 2); + ChildCenter[UP] = Center[UP]; + + Children[Index].Create(ChildCenter, ChildExtents, this, Depth - 1, Blocks); + } + } + } + else Children = 0; +} + +void Block::Collide(void* UserData, dNearCallback* Callback){ +#ifdef DRAWBLOCKS + DrawBlock(this); +#endif + // Collide the local list + dxGeom* g = First; + while (g){ + if (GEOM_ENABLED(g)){ + Collide(g, g->next, UserData, Callback); + } + g = g->next; + } + + // Recurse for children + if (Children){ + for (int i = 0; i < SPLITS; i++){ + if (Children[i].GeomCount <= 1){ // Early out + continue; + } + Children[i].Collide(UserData, Callback); + } + } +} + +void Block::Collide(dxGeom* g1, dxGeom* g2, void* UserData, dNearCallback* Callback){ +#ifdef DRAWBLOCKS + DrawBlock(this); +#endif + // Collide against local list + while (g2){ + if (GEOM_ENABLED(g2)){ + collideAABBs (g1, g2, UserData, Callback); + } + g2 = g2->next; + } + + // Collide against children + if (Children){ + for (int i = 0; i < SPLITS; i++){ + // Early out for empty blocks + if (Children[i].GeomCount == 0){ + continue; + } + + // Does the geom's AABB collide with the block? + // Dont do AABB tests for single geom blocks. + if (Children[i].GeomCount == 1 && Children[i].First){ + // + } + else if (true){ + if (g1->aabb[AXIS0 * 2 + 0] > Children[i].MaxX || + g1->aabb[AXIS0 * 2 + 1] < Children[i].MinX || + g1->aabb[AXIS1 * 2 + 0] > Children[i].MaxZ || + g1->aabb[AXIS1 * 2 + 1] < Children[i].MinZ) continue; + } + Children[i].Collide(g1, Children[i].First, UserData, Callback); + } + } +} + +void Block::CollideLocal(dxGeom* g1, void* UserData, dNearCallback* Callback){ + // Collide against local list + dxGeom* g2 = First; + while (g2){ + if (GEOM_ENABLED(g2)){ + collideAABBs (g1, g2, UserData, Callback); + } + g2 = g2->next; + } +} + +void Block::AddObject(dGeomID Object){ + // Add the geom + Object->next = First; + First = Object; + Object->tome = (dxGeom**)this; + + // Now traverse upwards to tell that we have a geom + Block* Block = this; + do{ + Block->GeomCount++; + Block = Block->Parent; + } + while (Block); +} + +void Block::DelObject(dGeomID Object){ + // Del the geom + dxGeom* g = First; + dxGeom* Last = 0; + while (g){ + if (g == Object){ + if (Last){ + Last->next = g->next; + } + else First = g->next; + + break; + } + Last = g; + g = g->next; + } + + Object->tome = 0; + + // Now traverse upwards to tell that we have lost a geom + Block* Block = this; + do{ + Block->GeomCount--; + Block = Block->Parent; + } + while (Block); +} + +void Block::Traverse(dGeomID Object){ + Block* NewBlock = GetBlock(Object->aabb); + + if (NewBlock != this){ + // Remove the geom from the old block and add it to the new block. + // This could be more optimal, but the loss should be very small. + DelObject(Object); + NewBlock->AddObject(Object); + } +} + +bool Block::Inside(const dReal* AABB){ + return AABB[AXIS0 * 2 + 0] >= MinX && AABB[AXIS0 * 2 + 1] <= MaxX && AABB[AXIS1 * 2 + 0] >= MinZ && AABB[AXIS1 * 2 + 1] <= MaxZ; +} + +Block* Block::GetBlock(const dReal* AABB){ + if (Inside(AABB)){ + return GetBlockChild(AABB); // Child or this will have a good block + } + else if (Parent){ + return Parent->GetBlock(AABB); // Parent has a good block + } + else return this; // We are at the root, so we have little choice +} + +Block* Block::GetBlockChild(const dReal* AABB){ + if (Children){ + for (int i = 0; i < SPLITS; i++){ + if (Children[i].Inside(AABB)){ + return Children[i].GetBlockChild(AABB); // Child will have good block + } + } + } + return this; // This is the best block +} + +//**************************************************************************** +// quadtree space + +struct dxQuadTreeSpace : public dxSpace{ + Block* Blocks; // Blocks[0] is the root + + dArray DirtyList; + + dxQuadTreeSpace(dSpaceID _space, dVector3 Center, dVector3 Extents, int Depth); + ~dxQuadTreeSpace(); + + dxGeom* getGeom(int i); + + void add(dxGeom* g); + void remove(dxGeom* g); + void dirty(dxGeom* g); + + void computeAABB(); + + void cleanGeoms(); + void collide(void* UserData, dNearCallback* Callback); + void collide2(void* UserData, dxGeom* g1, dNearCallback* Callback); + + // Temp data + Block* CurrentBlock; // Only used while enumerating + int* CurrentChild; // Only used while enumerating + int CurrentLevel; // Only used while enumerating + dxGeom* CurrentObject; // Only used while enumerating + int CurrentIndex; +}; + +dxQuadTreeSpace::dxQuadTreeSpace(dSpaceID _space, dVector3 Center, dVector3 Extents, int Depth) : dxSpace(_space){ + type = dQuadTreeSpaceClass; + + int BlockCount = 0; + for (int i = 0; i <= Depth; i++){ + BlockCount += (int)pow(dReal(SPLITS), i); + } + + Blocks = (Block*)dAlloc(BlockCount * sizeof(Block)); + Block* Blocks = this->Blocks + 1; // This pointer gets modified! + + this->Blocks[0].Create(Center, Extents, 0, Depth, Blocks); + + CurrentBlock = 0; + CurrentChild = (int*)dAlloc((Depth + 1) * sizeof(int)); + CurrentLevel = 0; + CurrentObject = 0; + CurrentIndex = -1; + + // Init AABB. We initialize to infinity because it is not illegal for an object to be outside of the tree. Its simply inserted in the root block + aabb[0] = -dInfinity; + aabb[1] = dInfinity; + aabb[2] = -dInfinity; + aabb[3] = dInfinity; + aabb[4] = -dInfinity; + aabb[5] = dInfinity; +} + +dxQuadTreeSpace::~dxQuadTreeSpace(){ + int Depth = 0; + Block* Current = &Blocks[0]; + while (Current){ + Depth++; + Current = Current->Children; + } + + int BlockCount = 0; + for (int i = 0; i < Depth; i++){ + BlockCount += (int)pow(dReal(SPLITS), i); + } + + dFree(Blocks, BlockCount * sizeof(Block)); + dFree(CurrentChild, (Depth + 1) * sizeof(int)); +} + +dxGeom* dxQuadTreeSpace::getGeom(int Index){ + dUASSERT(Index >= 0 && Index < count, "index out of range"); + + //@@@ + dDebug (0,"dxQuadTreeSpace::getGeom() not yet implemented"); + + return 0; + + // This doesnt work + + /*if (CurrentIndex == Index){ + // Loop through all objects in the local list +CHILDRECURSE: + if (CurrentObject){ + dGeomID g = CurrentObject; + CurrentObject = CurrentObject->next; + CurrentIndex++; + +#ifdef DRAWBLOCKS + DrawBlock(CurrentBlock); +#endif //DRAWBLOCKS + return g; + } + else{ + // Now lets loop through our children. Starting at index 0. + if (CurrentBlock->Children){ + CurrentChild[CurrentLevel] = 0; +PARENTRECURSE: + for (int& i = CurrentChild[CurrentLevel]; i < SPLITS; i++){ + if (CurrentBlock->Children[i].GeomCount == 0){ + continue; + } + CurrentBlock = &CurrentBlock->Children[i]; + CurrentObject = CurrentBlock->First; + + i++; + + CurrentLevel++; + goto CHILDRECURSE; + } + } + } + + // Now lets go back to the parent so it can continue processing its other children. + if (CurrentBlock->Parent){ + CurrentBlock = CurrentBlock->Parent; + CurrentLevel--; + goto PARENTRECURSE; + } + } + else{ + CurrentBlock = &Blocks[0]; + CurrentLevel = 0; + CurrentObject = CurrentObject; + CurrentIndex = 0; + + // Other states are already set + CurrentObject = CurrentBlock->First; + } + + + if (current_geom && current_index == Index - 1){ + //current_geom = current_geom->next; // next + current_index = Index; + return current_geom; + } + else for (int i = 0; i < Index; i++){ // this will be verrrrrrry slow + getGeom(i); + }*/ + + return 0; +} + +void dxQuadTreeSpace::add(dxGeom* g){ + CHECK_NOT_LOCKED (this); + dAASSERT(g); + dUASSERT(g->parent_space == 0 && g->next == 0, "geom is already in a space"); + + g->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; + DirtyList.push(g); + + // add + g->parent_space = this; + Blocks[0].GetBlock(g->aabb)->AddObject(g); // Add to best block + count++; + + // enumerator has been invalidated + current_geom = 0; + + dGeomMoved(this); +} + +void dxQuadTreeSpace::remove(dxGeom* g){ + CHECK_NOT_LOCKED(this); + dAASSERT(g); + dUASSERT(g->parent_space == this,"object is not in this space"); + + // remove + ((Block*)g->tome)->DelObject(g); + count--; + + for (int i = 0; i < DirtyList.size(); i++){ + if (DirtyList[i] == g){ + DirtyList.remove(i); + break; + } + } + + // safeguard + g->next = 0; + g->tome = 0; + g->parent_space = 0; + + // enumerator has been invalidated + current_geom = 0; + + // the bounding box of this space (and that of all the parents) may have + // changed as a consequence of the removal. + dGeomMoved(this); +} + +void dxQuadTreeSpace::dirty(dxGeom* g){ + DirtyList.push(g); +} + +void dxQuadTreeSpace::computeAABB(){ + // +} + +void dxQuadTreeSpace::cleanGeoms(){ + // compute the AABBs of all dirty geoms, and clear the dirty flags + lock_count++; + + for (int i = 0; i < DirtyList.size(); i++){ + dxGeom* g = DirtyList[i]; + if (IS_SPACE(g)){ + ((dxSpace*)g)->cleanGeoms(); + } + g->recomputeAABB(); + g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); + + ((Block*)g->tome)->Traverse(g); + } + DirtyList.setSize(0); + + lock_count--; +} + +void dxQuadTreeSpace::collide(void* UserData, dNearCallback* Callback){ + dAASSERT(Callback); + + lock_count++; + cleanGeoms(); + + Blocks[0].Collide(UserData, Callback); + + lock_count--; +} + +void dxQuadTreeSpace::collide2(void* UserData, dxGeom* g1, dNearCallback* Callback){ + dAASSERT(g1 && Callback); + + lock_count++; + cleanGeoms(); + g1->recomputeAABB(); + + if (g1->parent_space == this){ + // The block the geom is in + Block* CurrentBlock = (Block*)g1->tome; + + // Collide against block and its children + CurrentBlock->Collide(g1, CurrentBlock->First, UserData, Callback); + + // Collide against parents + while (true){ + CurrentBlock = CurrentBlock->Parent; + if (!CurrentBlock){ + break; + } + CurrentBlock->CollideLocal(g1, UserData, Callback); + } + } + else Blocks[0].Collide(g1, Blocks[0].First, UserData, Callback); + + lock_count--; +} + +dSpaceID dQuadTreeSpaceCreate(dxSpace* space, dVector3 Center, dVector3 Extents, int Depth){ + return new dxQuadTreeSpace(space, Center, Extents, Depth); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_sapspace.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_sapspace.cpp new file mode 100644 index 00000000..9e0081f3 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_sapspace.cpp @@ -0,0 +1,487 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + * Sweep and Prune adaptation/tweaks for ODE by Aras Pranckevicius. + * Original code: + * OPCODE - Optimized Collision Detection + * Copyright (C) 2001 Pierre Terdiman + * Homepage: http://www.codercorner.com/Opcode.htm + * + * This version does complete radix sort, not "classical" SAP. So, we + * have no temporal coherence, but are able to handle any movement + * velocities equally well. + */ + + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +#include "ode/ode_common.h" +#include "ode/ode_matrix.h" +#include "ode/ode_collision_space.h" +#include "ode/ode_collision.h" +#include "ode/ode_collision_kernel.h" + +#include "ode/ode_collision_space_internal.h" + +#include "ode/ode_Opcode.h" + + +// -------------------------------------------------------------------------- +// Box pruning code +// -------------------------------------------------------------------------- + +// InsertionSort has better coherence, RadixSort is better for one-shot queries. +#define PRUNING_SORTER RadixSort +//#define PRUNING_SORTER InsertionSort + +// Global pruning sorter for coherence +static PRUNING_SORTER* gCompletePruningSorter = 0; + +static inline PRUNING_SORTER* get_pruning_sorter() +{ + if( !gCompletePruningSorter ) + gCompletePruningSorter = new PRUNING_SORTER; + return gCompletePruningSorter; +} +// TBD: who should call this? +void release_pruning_sorters() +{ + if( gCompletePruningSorter ) { + delete gCompletePruningSorter; + gCompletePruningSorter = 0; + } +} + +/** + * Complete box pruning. + * Returns a list of overlapping pairs of boxes, each box of the pair + * belongs to the same set. + * NOTE: code uses floats instead of dReals because Opcode's radix sort + * is optimized for floats :) + * + * @param count [in] number of boxes. + * @param geoms [in] geoms of boxes. + * @param pairs [out] array of overlapping pairs. + * @param axes [in] projection order (0,2,1 is often best). + * @return true If success. + */ +static bool complete_box_pruning( int count, const dxGeom** geoms, Pairs& pairs, const Axes& axes ) +{ + // Checks + if (!count || !geoms) + return false; + + // Catch axes + udword Axis0 = axes.mAxis0; + udword Axis1 = axes.mAxis1; + udword Axis2 = axes.mAxis2; + + // Axis indices into geom's aabb are: min=idx, max=idx+1 + udword ax0idx = Axis0*2; + udword ax1idx = Axis1*2; + udword ax2idx = Axis2*2; + + // Allocate some temporary data + // TBD: persistent allocation between queries? + float* PosList = new float[count+1]; + + // 1) Build main list using the primary axis + for( int i = 0; i < count; ++i ) + PosList[i] = (float)geoms[i]->aabb[ax0idx]; + PosList[count++] = MAX_FLOAT; + + // 2) Sort the list + PRUNING_SORTER* RS = get_pruning_sorter(); + const udword* Sorted = RS->Sort(PosList, count).GetRanks(); + + // 3) Prune the list + const udword* const LastSorted = &Sorted[count]; + const udword* RunningAddress = Sorted; + udword Index0, Index1; + while( RunningAddress < LastSorted && Sorted < LastSorted ) { + Index0 = *Sorted++; + + while( PosList[*RunningAddress++] < PosList[Index0] ) { + // empty, the loop just advances RunningAddress + } + + if( RunningAddress < LastSorted ) { + const udword* RunningAddress2 = RunningAddress; + + float idx0ax0max = (float)geoms[Index0]->aabb[ax0idx+1]; + float idx0ax1max = (float)geoms[Index0]->aabb[ax1idx+1]; + float idx0ax2max = (float)geoms[Index0]->aabb[ax2idx+1]; + while( PosList[Index1 = *RunningAddress2++] <= idx0ax0max ) { +// if(Index0!=Index1) +// { + const dReal* aabb0 = geoms[Index0]->aabb; + const dReal* aabb1 = geoms[Index1]->aabb; + if( idx0ax1max < (float)aabb1[ax1idx] || (float)aabb1[ax1idx+1] < (float)aabb0[ax1idx] ) { + // no intersection + } else { + if( idx0ax2max < (float)aabb1[ax2idx] || (float)aabb1[ax2idx+1] < (float)aabb0[ax2idx] ) { + // no intersection + } else { + // yes! :) + pairs.AddPair( Index0, Index1 ); + } + } +// } + } + } + } + DELETEARRAY(PosList); + return true; +} + + +// -------------------------------------------------------------------------- +// SAP space code +// -------------------------------------------------------------------------- + +#define GEOM_ENABLED(g) ((g)->gflags & GEOM_ENABLED) + +/* + * A bit of repetitive work - similar to collideAABBs, but doesn't check + * if AABBs intersect (because SAP returns pairs with overlapping AABBs). + */ +static void collideGeomsNoAABBs( dxGeom *g1, dxGeom *g2, void *data, dNearCallback *callback ) +{ + dIASSERT( (g1->gflags & GEOM_AABB_BAD)==0 ); + dIASSERT( (g2->gflags & GEOM_AABB_BAD)==0 ); + + // no contacts if both geoms on the same body, and the body is not 0 + if (g1->body == g2->body && g1->body) return; + + // test if the category and collide bitfields match + if ( ((g1->category_bits & g2->collide_bits) || + (g2->category_bits & g1->collide_bits)) == 0) { + return; + } + + dReal *bounds1 = g1->aabb; + dReal *bounds2 = g2->aabb; + + // check if either object is able to prove that it doesn't intersect the + // AABB of the other + if (g1->AABBTest (g2,bounds2) == 0) return; + if (g2->AABBTest (g1,bounds1) == 0) return; + + // the objects might actually intersect - call the space callback function + callback (data,g1,g2); +}; + + +// -------------------------------------------------------------------------- +// SAP space + +// Kind of HACK: +// We abuse 'next' and 'tome' members of dxGeom to store indices +// into dirty/geom lists. +#define GEOM_SET_DIRTY_IDX(g,idx) { g->next = (dxGeom*)(size_t)(idx); } +#define GEOM_SET_GEOM_IDX(g,idx) { g->tome = (dxGeom**)(size_t)(idx); } +#define GEOM_GET_DIRTY_IDX(g) ((size_t)g->next) +#define GEOM_GET_GEOM_IDX(g) ((size_t)g->tome) +#define GEOM_INVALID_IDX (-1) + + +struct dxSAPSpace : public dxSpace { + typedef dArray TGeomPtrArray; + + // We have two lists (arrays of pointers) to dirty and clean + // geoms. Each geom knows it's index into the corresponding list + // (see macros above). + TGeomPtrArray DirtyList; // dirty geoms + TGeomPtrArray GeomList; // clean geoms + + // For SAP, we ultimately separate "normal" geoms and the ones that have + // infinite AABBs. No point doing SAP on infinite ones (and it doesn't handle + // infinite geoms anyway). + TGeomPtrArray TmpGeomList; // temporary for normal geoms + TGeomPtrArray TmpInfGeomList; // temporary for geoms with infinite AABBs + + // Our sorting axes. + Axes SortAxes; + + + dxSAPSpace( dSpaceID _space, AxisOrder sortAxes ); + virtual ~dxSAPSpace(); + + // dxSpace + virtual dxGeom* getGeom(int i); + virtual void add(dxGeom* g); + virtual void remove(dxGeom* g); + virtual void dirty(dxGeom* g); + virtual void computeAABB(); + virtual void cleanGeoms(); + virtual void collide (void *data, dNearCallback *callback); + // TBD: not implemented yet + virtual void collide2 (void *data, dxGeom *geom, dNearCallback *callback); +}; + + + +dxSAPSpace::dxSAPSpace( dSpaceID _space, AxisOrder sortAxes ) +: dxSpace( _space ), + SortAxes( sortAxes ) +{ + type = dSweepAndPruneSpaceClass; + + // Init AABB to infinity + aabb[0] = -dInfinity; + aabb[1] = dInfinity; + aabb[2] = -dInfinity; + aabb[3] = dInfinity; + aabb[4] = -dInfinity; + aabb[5] = dInfinity; +} + +dxSAPSpace::~dxSAPSpace() +{ +} + +dxGeom* dxSAPSpace::getGeom( int i ) +{ + dUASSERT( i >= 0 && i < count, "index out of range" ); + int dirtySize = DirtyList.size(); + if( i < dirtySize ) + return DirtyList[i]; + else + return GeomList[i-dirtySize]; +} + +void dxSAPSpace::add( dxGeom* g ) +{ + CHECK_NOT_LOCKED (this); + dAASSERT(g); + dUASSERT(g->parent_space == 0 && g->next == 0, "geom is already in a space"); + + g->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; + + // add to dirty list + GEOM_SET_DIRTY_IDX( g, DirtyList.size() ); + GEOM_SET_GEOM_IDX( g, GEOM_INVALID_IDX ); + DirtyList.push( g ); + + g->parent_space = this; + this->count++; + + dGeomMoved(this); +} + + +void dxSAPSpace::remove( dxGeom* g ) +{ + CHECK_NOT_LOCKED(this); + dAASSERT(g); + dUASSERT(g->parent_space == this,"object is not in this space"); + + // remove + int dirtyIdx = GEOM_GET_DIRTY_IDX(g); + int geomIdx = GEOM_GET_GEOM_IDX(g); + // must be in one list, not in both + dUASSERT( + dirtyIdx==GEOM_INVALID_IDX && geomIdx>=0 && geomIdx=0 && dirtyIdxparent_space = 0; + + // the bounding box of this space (and that of all the parents) may have + // changed as a consequence of the removal. + dGeomMoved(this); +} + +void dxSAPSpace::dirty( dxGeom* g ) +{ + dAASSERT(g); + dUASSERT(g->parent_space == this,"object is not in this space"); + + // check if already dirtied + int dirtyIdx = GEOM_GET_DIRTY_IDX(g); + if( dirtyIdx != GEOM_INVALID_IDX ) + return; + + int geomIdx = GEOM_GET_GEOM_IDX(g); + dUASSERT( geomIdx>=0 && geomIdxcleanGeoms(); + } + g->recomputeAABB(); + g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); + // remove from dirty list, add to geom list + GEOM_SET_DIRTY_IDX( g, GEOM_INVALID_IDX ); + GEOM_SET_GEOM_IDX( g, geomSize + i ); + GeomList[geomSize+i] = g; + } + // clear dirty list + DirtyList.setSize( 0 ); + + lock_count--; +} + + +void dxSAPSpace::collide (void *data, dNearCallback *callback) +{ + dAASSERT (callback); + + lock_count++; + + cleanGeoms(); + + // by now all geoms are in GeomList, and DirtyList must be empty + int geomSize = GeomList.size(); + dUASSERT( geomSize == count, "geom counts messed up" ); + + // separate all geoms into infinite AABBs and normal AABBs + TmpGeomList.setSize(0); + TmpInfGeomList.setSize(0); + int axis0max = SortAxes.mAxis0*2+1; + for( int i = 0; i < geomSize; ++i ) { + dxGeom* g =GeomList[i]; + if( !GEOM_ENABLED(g) ) // skip disabled ones + continue; + const dReal& amax = g->aabb[axis0max]; + if( amax == dInfinity ) // HACK? probably not... + TmpInfGeomList.push( g ); + else + TmpGeomList.push( g ); + } + + // do SAP on normal AABBs + Pairs overlapBoxes; + //bool isok = complete_box_pruning( TmpGeomList.size(), (const dxGeom**)TmpGeomList.data(), overlapBoxes, SortAxes ); + complete_box_pruning( TmpGeomList.size(), (const dxGeom**)TmpGeomList.data(), overlapBoxes, SortAxes ); + + // collide overlapping + udword overlapCount = overlapBoxes.GetNbPairs(); + for( udword j = 0; j < overlapCount; ++j ) { + const Pair* pair = overlapBoxes.GetPair(j); + dxGeom* g1 = TmpGeomList[pair->id0]; + dxGeom* g2 = TmpGeomList[pair->id1]; + collideGeomsNoAABBs( g1, g2, data, callback ); + } + + int infSize = TmpInfGeomList.size(); + int normSize = TmpGeomList.size(); + int m, n; + for( m = 0; m < infSize; ++m ) { + dxGeom* g1 = TmpInfGeomList[m]; + // collide infinite ones + for( n = m+1; n < infSize; ++n ) { + dxGeom* g2 = TmpInfGeomList[n]; + collideGeomsNoAABBs( g1, g2, data, callback ); + } + // collide infinite ones with normal ones + for( n = 0; n < normSize; ++n ) { + dxGeom* g2 = TmpGeomList[n]; + collideGeomsNoAABBs( g1, g2, data, callback ); + } + } + + lock_count--; +} + + +void dxSAPSpace::collide2( void *data, dxGeom *geom, dNearCallback *callback ) +{ + // TBD + /* + dAASSERT (geom && callback); + + lock_count++; + cleanGeoms(); + geom->recomputeAABB(); + + // intersect bounding boxes + for (dxGeom *g=first; g; g=g->next) { + if (GEOM_ENABLED(g)){ + collideAABBs (g,geom,data,callback); + } + } + + lock_count--; + */ +} + +dSpaceID dSweepAndPruneSpaceCreate(dxSpace* space,int sortAxes) { + return new dxSAPSpace( space, (AxisOrder)sortAxes ); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_space.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_space.cpp new file mode 100644 index 00000000..e37f29e4 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_space.cpp @@ -0,0 +1,970 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +spaces + +*/ + +#include "ode/ode_common.h" +#include "ode/ode_matrix.h" +#include "ode/ode_collision_space.h" +#include "ode/ode_collision.h" +#include "ode/ode_collision_kernel.h" +#include +#include "ode/ode_util.h" +#include "ballistica/ballistica.h" + +#include "ode/ode_collision_space_internal.h" + +// in my current setup, ldexp seems to be messed up +// when we compile with hardware floats.. +#if BA_OSTYPE_ANDROID +#define ldexp __builtin_ldexpf +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4291) // for VC++, no complaints about "no matching operator delete found" +#endif + + +// ericf addition - super simple memory buffer +// class _Buffer{ +// public: +// void allocate(unsigned long size){ +// if (_allocated and _ptr) free(_ptr); +// _ptr = malloc(size); +// dIASSERT(_ptr); +// _allocated = true; +// } +// ~_Buffer(){ +// if (_allocated and _ptr) free(_ptr); +// _ptr = NULL; +// } +// void* getPtr() const {return _ptr;} +// private: +// void* _ptr = nullptr; +// bool _allocated = false; +// }; + +// ericf addition +// #define TRIXY_ALLOCA(name, type, n) _Buffer name ## BUF; \ +// if (n > 1000) { \ +// name ## BUF.allocate((n)); \ +// name = (type*)name ## BUF.getPtr();\ +// } else { \ +// name = (type*)ALLOCA((n)); \ +// dIASSERT(name); \ +// } + + + +using namespace std; + +void collideAABBs (dxGeom *g1, dxGeom *g2, void *data, dNearCallback *callback) +{ + dIASSERT((g1->gflags & GEOM_AABB_BAD)==0); + dIASSERT((g2->gflags & GEOM_AABB_BAD)==0); + + // no contacts if both geoms on the same body, and the body is not 0 + if (g1->body == g2->body && g1->body) return; + + // test if the category and collide bitfields match + if ( ((g1->category_bits & g2->collide_bits) || + (g2->category_bits & g1->collide_bits)) == 0) { + return; + } + + // if the bounding boxes are disjoint then don't do anything + dReal *bounds1 = g1->aabb; + dReal *bounds2 = g2->aabb; + if (bounds1[0] > bounds2[1] || + bounds1[1] < bounds2[0] || + bounds1[2] > bounds2[3] || + bounds1[3] < bounds2[2] || + bounds1[4] > bounds2[5] || + bounds1[5] < bounds2[4]) { + return; + } + + // check if either object is able to prove that it doesn't intersect the + // AABB of the other + if (g1->AABBTest (g2,bounds2) == 0) return; + if (g2->AABBTest (g1,bounds1) == 0) return; + + // the objects might actually intersect - call the space callback function + callback (data,g1,g2); +} + + +//**************************************************************************** +// make the geom dirty by setting the GEOM_DIRTY and GEOM_BAD_AABB flags +// and moving it to the front of the space's list. all the parents of a +// dirty geom also become dirty. + +void dGeomMoved (dxGeom *geom) +{ + dAASSERT (geom); + + // from the bottom of the space heirarchy up, process all clean geoms + // turning them into dirty geoms. + dxSpace *parent = geom->parent_space; + + while (parent && (geom->gflags & GEOM_DIRTY)==0) { + CHECK_NOT_LOCKED (parent); + geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; + parent->dirty (geom); + geom = parent; + parent = parent->parent_space; + } + + // all the remaining dirty geoms must have their AABB_BAD flags set, to + // ensure that their AABBs get recomputed + while (geom) { + geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; + CHECK_NOT_LOCKED (geom->parent_space); + geom = geom->parent_space; + } +} + +// ericf tweak - we don't use this functionality +//#define GEOM_ENABLED(g) ((g)->gflags & GEOM_ENABLED) +#define GEOM_ENABLED(g) (true) + +//**************************************************************************** +// dxSpace + +dxSpace::dxSpace (dSpaceID _space) : dxGeom (_space,0) +{ + count = 0; + first = 0; + cleanup = 1; + current_index = 0; + current_geom = 0; + lock_count = 0; +} + + +dxSpace::~dxSpace() +{ + CHECK_NOT_LOCKED (this); + if (cleanup) { + // note that destroying each geom will call remove() + dxGeom *g,*n; + for (g = first; g; g=n) { + n = g->next; + dGeomDestroy (g); + } + } + else { + dxGeom *g,*n; + for (g = first; g; g=n) { + n = g->next; + remove (g); + } + } +} + + +void dxSpace::computeAABB() +{ + if (first) { + int i; + dReal a[6]; + a[0] = dInfinity; + a[1] = -dInfinity; + a[2] = dInfinity; + a[3] = -dInfinity; + a[4] = dInfinity; + a[5] = -dInfinity; + for (dxGeom *g=first; g; g=g->next) { + g->recomputeAABB(); + for (i=0; i<6; i += 2) if (g->aabb[i] < a[i]) a[i] = g->aabb[i]; + for (i=1; i<6; i += 2) if (g->aabb[i] > a[i]) a[i] = g->aabb[i]; + } + memcpy(aabb,a,6*sizeof(dReal)); + } + else { + dSetZero (aabb,6); + } +} + + +void dxSpace::setCleanup (int mode) +{ + cleanup = (mode != 0); +} + + +int dxSpace::getCleanup() +{ + return cleanup; +} + + +int dxSpace::query (dxGeom *geom) +{ + dAASSERT (geom); + return (geom->parent_space == this); +} + + +int dxSpace::getNumGeoms() +{ + return count; +} + + +// the dirty geoms are numbered 0..k, the clean geoms are numbered k+1..count-1 + +dxGeom *dxSpace::getGeom (int i) +{ + dUASSERT (i >= 0 && i < count,"index out of range"); + if (current_geom && current_index == i-1) { + current_geom = current_geom->next; + current_index = i; + return current_geom; + } + else { + dxGeom *g=first; + for (int j=0; jnext; else return 0; + } + current_geom = g; + current_index = i; + return g; + } +} + + +void dxSpace::add (dxGeom *geom) +{ + CHECK_NOT_LOCKED (this); + dAASSERT (geom); + dUASSERT (geom->parent_space == 0 && geom->next == 0, + "geom is already in a space"); + + // add + geom->parent_space = this; + geom->spaceAdd (&first); + count++; + + // enumerator has been invalidated + current_geom = 0; + + // new geoms are added to the front of the list and are always + // considered to be dirty. as a consequence, this space and all its + // parents are dirty too. + geom->gflags |= GEOM_DIRTY | GEOM_AABB_BAD; + dGeomMoved (this); +} + + +void dxSpace::remove (dxGeom *geom) +{ + CHECK_NOT_LOCKED (this); + dAASSERT (geom); + dUASSERT (geom->parent_space == this,"object is not in this space"); + + // remove + geom->spaceRemove(); + count--; + + // safeguard + geom->next = 0; + geom->tome = 0; + geom->parent_space = 0; + + // enumerator has been invalidated + current_geom = 0; + + // the bounding box of this space (and that of all the parents) may have + // changed as a consequence of the removal. + dGeomMoved (this); +} + + +void dxSpace::dirty (dxGeom *geom) +{ +// geom->spaceRemove(); +// geom->spaceAdd (&first); +} + +//**************************************************************************** +// simple space - reports all n^2 object intersections + +struct dxSimpleSpace : public dxSpace { + dxSimpleSpace (dSpaceID _space); + void cleanGeoms(); + void collide (void *data, dNearCallback *callback); + void collide2 (void *data, dxGeom *geom, dNearCallback *callback); +}; + + +dxSimpleSpace::dxSimpleSpace (dSpaceID _space) : dxSpace (_space) +{ + type = dSimpleSpaceClass; +} + + +void dxSimpleSpace::cleanGeoms() +{ + // compute the AABBs of all dirty geoms, and clear the dirty flags + lock_count++; +// for (dxGeom *g=first; g && (g->gflags & GEOM_DIRTY); g=g->next) { + for (dxGeom *g=first; g; g=g->next) { + if (g->gflags & GEOM_DIRTY){ + if (IS_SPACE(g)) { + ((dxSpace*)g)->cleanGeoms(); + } + g->recomputeAABB(); + g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); + } + } + lock_count--; +} + + +void dxSimpleSpace::collide (void *data, dNearCallback *callback) +{ +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"simplespace colliding\n"); + } +#endif + + dAASSERT (callback); + + lock_count++; + cleanGeoms(); + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"listing space geoms:\n"); + for (dxGeom *g1=first; g1; g1=g1->next) { + fprintf(f," space geomID: %d\n",g1->indexTest); + } + } +#endif + + // intersect all bounding boxes + for (dxGeom *g1=first; g1; g1=g1->next) { + //if (GEOM_ENABLED(g1)){ + for (dxGeom *g2=g1->next; g2; g2=g2->next) { + // if (GEOM_ENABLED(g2)){ + collideAABBs (g1,g2,data,callback); + // } + } + // } + } + + lock_count--; +} + + +void dxSimpleSpace::collide2 (void *data, dxGeom *geom, + dNearCallback *callback) +{ + dAASSERT (geom && callback); + + lock_count++; + cleanGeoms(); + geom->recomputeAABB(); + + // intersect bounding boxes + for (dxGeom *g=first; g; g=g->next) { + if (GEOM_ENABLED(g)){ + collideAABBs (g,geom,data,callback); + } + } + + lock_count--; +} + +//**************************************************************************** +// utility stuff for hash table space + +// kind of silly, but oh well... +#ifndef MAXINT +#define MAXINT ((int)((((unsigned int)(-1)) << 1) >> 1)) +#endif + + +// prime[i] is the largest prime smaller than 2^i +#define NUM_PRIMES 31 +static long int prime[NUM_PRIMES] = {1L,2L,3L,7L,13L,31L,61L,127L,251L,509L, + 1021L,2039L,4093L,8191L,16381L,32749L,65521L,131071L,262139L, + 524287L,1048573L,2097143L,4194301L,8388593L,16777213L,33554393L, + 67108859L,134217689L,268435399L,536870909L,1073741789L}; + + +// an axis aligned bounding box in the hash table +struct dxAABB { + dxAABB *next; // next in the list of all AABBs + int level; // the level this is stored in (cell size = 2^level) + int dbounds[6]; // AABB bounds, discretized to cell size + dxGeom *geom; // corresponding geometry object (AABB stored here) + int index; // index of this AABB, starting from 0 +}; + + +// a hash table node that represents an AABB that intersects a particular cell +// at a particular level +struct Node { + Node *next; // next node in hash table collision list, 0 if none + int x,y,z; // cell position in space, discretized to cell size + dxAABB *aabb; // axis aligned bounding box that intersects this cell +}; + + +// return the `level' of an AABB. the AABB will be put into cells at this +// level - the cell size will be 2^level. the level is chosen to be the +// smallest value such that the AABB occupies no more than 8 cells, regardless +// of its placement. this means that: +// size/2 < q <= size +// where q is the maximum AABB dimension. + +static int findLevel (dReal bounds[6]) +{ + if (bounds[0] <= -dInfinity || bounds[1] >= dInfinity || + bounds[2] <= -dInfinity || bounds[3] >= dInfinity || + bounds[4] <= -dInfinity || bounds[5] >= dInfinity) { + return MAXINT; + } + + // compute q + dReal q,q2; + q = bounds[1] - bounds[0]; // x bounds + q2 = bounds[3] - bounds[2]; // y bounds + if (q2 > q) q = q2; + q2 = bounds[5] - bounds[4]; // z bounds + if (q2 > q) q = q2; + + // find level such that 0.5 * 2^level < q <= 2^level + int level; + frexp (q,&level); // q = (0.5 .. 1.0) * 2^level (definition of frexp) + return level; +} + + +// find a virtual memory address for a cell at the given level and x,y,z +// position. +// @@@ currently this is not very sophisticated, e.g. the scaling +// factors could be better designed to avoid collisions, and they should +// probably depend on the hash table physical size. + +static unsigned long getVirtualAddress (int level, int x, int y, int z) +{ + return level*1000 + x*100 + y*10 + z; +} + +//**************************************************************************** +// hash space + +struct dxHashSpace : public dxSpace { + int global_minlevel; // smallest hash table level to put AABBs in + int global_maxlevel; // objects that need a level larger than this will be + // put in a "big objects" list instead of a hash table + + dxHashSpace (dSpaceID _space); + void setLevels (int minlevel, int maxlevel); + void getLevels (int *minlevel, int *maxlevel); + void cleanGeoms(); + void collide (void *data, dNearCallback *callback); + void collide2 (void *data, dxGeom *geom, dNearCallback *callback); +}; + + +dxHashSpace::dxHashSpace (dSpaceID _space) : dxSpace (_space) +{ + type = dHashSpaceClass; + global_minlevel = -3; + global_maxlevel = 10; +} + + +void dxHashSpace::setLevels (int minlevel, int maxlevel) +{ + dAASSERT (minlevel <= maxlevel); + global_minlevel = minlevel; + global_maxlevel = maxlevel; +} + + +void dxHashSpace::getLevels (int *minlevel, int *maxlevel) +{ + if (minlevel) *minlevel = global_minlevel; + if (maxlevel) *maxlevel = global_maxlevel; +} + + +void dxHashSpace::cleanGeoms() +{ + // compute the AABBs of all dirty geoms, and clear the dirty flags + lock_count++; + for (dxGeom *g=first; g; g=g->next) { + if (g->gflags & GEOM_DIRTY) + { + if (IS_SPACE(g)) { + ((dxSpace*)g)->cleanGeoms(); + } + g->recomputeAABB(); + g->gflags &= (~(GEOM_DIRTY|GEOM_AABB_BAD)); + } + } + lock_count--; +} + +//extern double ldexp(double, int) __NDK_FPABI_MATH__; +//extern double ldexp(double x, int exponent); + +void dxHashSpace::collide (void *data, dNearCallback *callback) +{ + + unsigned char *allocated1 = NULL; + unsigned char *allocated2 = NULL; + + dAASSERT(callback); + dxGeom *geom; + dxAABB *aabb; + + // ericf tweak - i was overflowing. + // FIXME: isn't long still 32 bit in some/all cases?.... + //int i,maxlevel; + long i, maxlevel; + + // 0 or 1 geoms can't collide with anything + if (count < 2) return; + + lock_count++; + cleanGeoms(); + + // create a list of auxiliary information for all geom axis aligned bounding + // boxes. set the level for all AABBs. put AABBs larger than the space's + // global_maxlevel in the big_boxes list, check everything else against + // that list at the end. for AABBs that are not too big, record the maximum + // level that we need. + + int n = 0; // number of AABBs in main list + dxAABB *first_aabb = 0; // list of AABBs in hash table + dxAABB *big_boxes = 0; // list of AABBs too big for hash table + maxlevel = global_minlevel - 1; + for (geom = first; geom; geom=geom->next) { + // if (!GEOM_ENABLED(geom)){ + // continue; + // } + // ericf note: TRIXY_ALLOCA will never actually allocate because + // this is always a small bit of memory; right?.. should test. + // TRIXY_ALLOCA(aabb, dxAABB, sizeof(dxAABB)); + dxAABB *aabb = (dxAABB*) ALLOCA (sizeof(dxAABB)); + aabb->geom = geom; + // compute level, but prevent cells from getting too small + int level = findLevel (geom->aabb); + if (level < global_minlevel) level = global_minlevel; + if (level <= global_maxlevel) { + // aabb goes in main list + aabb->next = first_aabb; + first_aabb = aabb; + aabb->level = level; + if (level > maxlevel) maxlevel = level; + // cellsize = 2^level + dReal cellsize = (dReal) ldexp (1.0,level); + // discretize AABB position to cell size + for (i=0; i < 6; i++) aabb->dbounds[i] = (int) + floor (geom->aabb[i]/cellsize); + // set AABB index + aabb->index = n; + n++; + } else { + // aabb is too big, put it in the big_boxes list. we don't care + // about setting level, dbounds, index, or the maxlevel + aabb->next = big_boxes; + big_boxes = aabb; + } + } + + // for `n' objects, an n*n array of bits is used to record if those objects + // have been intersection-tested against each other yet. this array can + // grow large with high n, but oh well... + long tested_rowsize = (n+7) >> 3; // number of bytes needed for n bits + unsigned char *tested; + + // dont allocate on the stack for substantial sizes... + if (n*tested_rowsize < 5000){ + tested = (unsigned char *) alloca (n * tested_rowsize); + } else { + tested = (unsigned char *) malloc (n * tested_rowsize); + allocated1 = tested; + } + memset (tested,0,n * tested_rowsize); + + // create a hash table to store all AABBs. each AABB may take up to 8 cells. + // we use chaining to resolve collisions, but we use a relatively large + // table to reduce the chance of collisions. + + // compute hash table size sz to be a prime > 8*n + for (i=0; i= (8*n)) break; + } + if (i >= NUM_PRIMES) i = NUM_PRIMES-1; // probably pointless + long sz = prime[i]; + + // allocate and initialize hash table node pointers + Node **table; + if (sizeof(Node*)*sz < 8000){ + table = (Node **) ALLOCA (sizeof(Node*) * sz); + } else { + table = (Node **) malloc(sizeof(Node*) * sz); + allocated2 = (unsigned char*)table; + } + dIASSERT (table != NULL); + + for (i=0; i 500){ + int need = 0; + // tally up what we'll need.. perhaps there's a way to determine this + // without iterating?.. + for (aabb=first_aabb; aabb; aabb=aabb->next) { + int *dbounds = aabb->dbounds; + for (int xi = dbounds[0]; xi <= dbounds[1]; xi++) { + for (int yi = dbounds[2]; yi <= dbounds[3]; yi++) { + for (int zi = dbounds[4]; zi <= dbounds[5]; zi++) { + need++; + } + } + } + } + nodeBuffer = (Node*)malloc(need*sizeof(Node)); + dIASSERT(nodeBuffer); + Node *ni = nodeBuffer; + + // add each AABB to the hash table (may need to add it to up to 8 cells) + for (aabb=first_aabb; aabb; aabb=aabb->next) { + int *dbounds = aabb->dbounds; + for (int xi = dbounds[0]; xi <= dbounds[1]; xi++) { + for (int yi = dbounds[2]; yi <= dbounds[3]; yi++) { + for (int zi = dbounds[4]; zi <= dbounds[5]; zi++) { + // get the hash index + unsigned long hi = getVirtualAddress (aabb->level,xi,yi,zi) % sz; + // add a new node to the hash table + Node *node = ni++; + node->x = xi; + node->y = yi; + node->z = zi; + node->aabb = aabb; + node->next = table[hi]; + table[hi] = node; + } + } + } + } + } else { + // old alloca-usin' code: + // add each AABB to the hash table (may need to add it to up to 8 cells) + for (aabb=first_aabb; aabb; aabb=aabb->next) { + int *dbounds = aabb->dbounds; + for (int xi = dbounds[0]; xi <= dbounds[1]; xi++) { + for (int yi = dbounds[2]; yi <= dbounds[3]; yi++) { + for (int zi = dbounds[4]; zi <= dbounds[5]; zi++) { + // get the hash index + unsigned long hi = getVirtualAddress (aabb->level,xi,yi,zi) % sz; + // add a new node to the hash table + Node *node = (Node*) alloca (sizeof (Node)); + node->x = xi; + node->y = yi; + node->z = zi; + node->aabb = aabb; + node->next = table[hi]; + table[hi] = node; + } + } + } + } + } + + // now that all AABBs are loaded into the hash table, we do the actual + // collision detection. for all AABBs, check for other AABBs in the + // same cells for collisions, and then check for other AABBs in all + // intersecting higher level cells. + + int db[6]; // discrete bounds at current level + for (aabb=first_aabb; aabb; aabb=aabb->next) { + // we are searching for collisions with aabb + for (i=0; i<6; i++) db[i] = aabb->dbounds[i]; + for (int level = aabb->level; level <= maxlevel; level++) { + for (int xi = db[0]; xi <= db[1]; xi++) { + for (int yi = db[2]; yi <= db[3]; yi++) { + for (int zi = db[4]; zi <= db[5]; zi++) { + // get the hash index + unsigned long hi = getVirtualAddress (level,xi,yi,zi) % sz; + // search all nodes at this index + Node *node; + for (node = table[hi]; node; node=node->next) { + // node points to an AABB that may intersect aabb + if (node->aabb == aabb) continue; + if (node->aabb->level == level && + node->x == xi && node->y == yi && node->z == zi) { + // see if aabb and node->aabb have already been tested + // against each other + unsigned char mask; + if (aabb->index <= node->aabb->index) { + i = ((long)aabb->index * tested_rowsize)+(node->aabb->index >> 3); + mask = 1 << (node->aabb->index & 7); + } else { + i = ((long)node->aabb->index * tested_rowsize)+(aabb->index >> 3); + mask = 1 << (aabb->index & 7); + } + dIASSERT (i >= 0 && i < (tested_rowsize*n)); + if ((tested[i] & mask)==0) { + collideAABBs (aabb->geom,node->aabb->geom,data,callback); + } + tested[i] |= mask; + } + } + } + } + } + // get the discrete bounds for the next level up + for (i=0; i<6; i++) db[i] >>= 1; + } + } + + // every AABB in the normal list must now be intersected against every + // AABB in the big_boxes list. so let's hope there are not too many objects + // in the big_boxes list. + for (aabb=first_aabb; aabb; aabb=aabb->next) { + for (dxAABB *aabb2=big_boxes; aabb2; aabb2=aabb2->next) { + collideAABBs (aabb->geom,aabb2->geom,data,callback); + } + } + + // intersected all AABBs in the big_boxes list together + for (aabb=big_boxes; aabb; aabb=aabb->next) { + for (dxAABB *aabb2=aabb->next; aabb2; aabb2=aabb2->next) { + collideAABBs (aabb->geom,aabb2->geom,data,callback); + } + } + + lock_count--; + + // ericf addition: if we allocated using malloc instead of alloca + // (to avoid overflowing the stack), free it here.. + if (allocated1) { + free(allocated1); + } + if (allocated2) { + free(allocated2); + } + if (nodeBuffer) { + free(nodeBuffer); + } +} + + +void dxHashSpace::collide2 (void *data, dxGeom *geom, + dNearCallback *callback) +{ + dAASSERT (geom && callback); + + // this could take advantage of the hash structure to avoid + // O(n2) complexity, but it does not yet. + + lock_count++; + cleanGeoms(); + geom->recomputeAABB(); + + // intersect bounding boxes + for (dxGeom *g=first; g; g=g->next) { + collideAABBs (g,geom,data,callback); + } + + lock_count--; +} + +//**************************************************************************** +// space functions + +dxSpace *dSimpleSpaceCreate (dxSpace *space) +{ + return new dxSimpleSpace (space); +} + + +dxSpace *dHashSpaceCreate (dxSpace *space) +{ + return new dxHashSpace (space); +} + + +void dHashSpaceSetLevels (dxSpace *space, int minlevel, int maxlevel) +{ + dAASSERT (space); + dUASSERT (minlevel <= maxlevel,"must have minlevel <= maxlevel"); + dUASSERT (space->type == dHashSpaceClass,"argument must be a hash space"); + dxHashSpace *hspace = (dxHashSpace*) space; + hspace->setLevels (minlevel,maxlevel); +} + + +void dHashSpaceGetLevels (dxSpace *space, int *minlevel, int *maxlevel) +{ + dAASSERT (space); + dUASSERT (space->type == dHashSpaceClass,"argument must be a hash space"); + dxHashSpace *hspace = (dxHashSpace*) space; + hspace->getLevels (minlevel,maxlevel); +} + + +void dSpaceDestroy (dxSpace *space) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + dGeomDestroy (space); +} + + +void dSpaceSetCleanup (dxSpace *space, int mode) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + space->setCleanup (mode); +} + + +int dSpaceGetCleanup (dxSpace *space) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + return space->getCleanup(); +} + + +void dSpaceAdd (dxSpace *space, dxGeom *g) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + CHECK_NOT_LOCKED (space); + space->add (g); +} + + +void dSpaceRemove (dxSpace *space, dxGeom *g) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + CHECK_NOT_LOCKED (space); + space->remove (g); +} + + +int dSpaceQuery (dxSpace *space, dxGeom *g) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + return space->query (g); +} + +void dSpaceClean (dxSpace *space){ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + + space->cleanGeoms(); +} + +int dSpaceGetNumGeoms (dxSpace *space) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + return space->getNumGeoms(); +} + + +dGeomID dSpaceGetGeom (dxSpace *space, int i) +{ + dAASSERT (space); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + return space->getGeom (i); +} + + +void dSpaceCollide (dxSpace *space, void *data, dNearCallback *callback) +{ + dAASSERT (space && callback); + dUASSERT (dGeomIsSpace(space),"argument not a space"); + space->collide (data,callback); +} + + +void dSpaceCollide2 (dxGeom *g1, dxGeom *g2, void *data, + dNearCallback *callback) +{ + dAASSERT (g1 && g2 && callback); + dxSpace *s1,*s2; + + // see if either geom is a space + if (IS_SPACE(g1)) s1 = (dxSpace*) g1; else s1 = 0; + if (IS_SPACE(g2)) s2 = (dxSpace*) g2; else s2 = 0; + + // handle the four space/geom cases + if (s1) { + if (s2) { + // g1 and g2 are spaces. + if (s1==s2) { + // collide a space with itself --> interior collision + s1->collide (data,callback); + } + else { + // iterate through the space that has the fewest geoms, calling + // collide2 in the other space for each one. + if (s1->count < s2->count) { + for (dxGeom *g = s1->first; g; g=g->next) { + s2->collide2 (data,g,callback); + } + } + else { + for (dxGeom *g = s2->first; g; g=g->next) { + s1->collide2 (data,g,callback); + } + } + } + } + else { + // g1 is a space, g2 is a geom + s1->collide2 (data,g2,callback); + } + } + else { + if (s2) { + // g1 is a geom, g2 is a space + s2->collide2 (data,g1,callback); + } + else { + // g1 and g2 are geoms, call the callback directly + callback (data,g1,g2); + } + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_space.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_space.h new file mode 100644 index 00000000..a71f30af --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_space.h @@ -0,0 +1,76 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_COLLISION_SPACE_H_ +#define _ODE_COLLISION_SPACE_H_ + +#include "ode/ode_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct dContactGeom; + +typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); + + +dSpaceID dSimpleSpaceCreate (dSpaceID space); +dSpaceID dHashSpaceCreate (dSpaceID space); +dSpaceID dQuadTreeSpaceCreate (dSpaceID space, dVector3 Center, dVector3 Extents, int Depth); + + +// SAP +// Order XZY or ZXY usually works best, if your Y is up. +// Don't know how to express axis orders... defines are ok? +// must match PointComponent/AxisOrder from Opcode/Ice/IceAxes.h! +#define dSAP_AXES_XYZ ((0)|(1<<2)|(2<<4)) +#define dSAP_AXES_XZY ((0)|(2<<2)|(1<<4)) +#define dSAP_AXES_YXZ ((1)|(0<<2)|(2<<4)) +#define dSAP_AXES_YZX ((1)|(2<<2)|(0<<4)) +#define dSAP_AXES_ZXY ((2)|(0<<2)|(1<<4)) +#define dSAP_AXES_ZYX ((2)|(1<<2)|(0<<4)) +dSpaceID dSweepAndPruneSpaceCreate (dSpaceID space, int axisorder); + + + +void dSpaceDestroy (dSpaceID); + +void dHashSpaceSetLevels (dSpaceID space, int minlevel, int maxlevel); +void dHashSpaceGetLevels (dSpaceID space, int *minlevel, int *maxlevel); + +void dSpaceSetCleanup (dSpaceID space, int mode); +int dSpaceGetCleanup (dSpaceID space); + +void dSpaceAdd (dSpaceID, dGeomID); +void dSpaceRemove (dSpaceID, dGeomID); +int dSpaceQuery (dSpaceID, dGeomID); +void dSpaceClean (dSpaceID); +int dSpaceGetNumGeoms (dSpaceID); +dGeomID dSpaceGetGeom (dSpaceID, int i); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_space_internal.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_space_internal.h new file mode 100644 index 00000000..a5f3c4c2 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_space_internal.h @@ -0,0 +1,86 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +stuff common to all spaces + +*/ + +#ifndef _ODE_COLLISION_SPACE_INTERNAL_H_ +#define _ODE_COLLISION_SPACE_INTERNAL_H_ + +#define ALLOCA(x) dALLOCA16(x) + +#define CHECK_NOT_LOCKED(space) \ + dUASSERT ((space)==0 || (space)->lock_count==0, \ + "invalid operation for locked space"); + + +// collide two geoms together. for the hash table space, this is +// called if the two AABBs inhabit the same hash table cells. +// this only calls the callback function if the AABBs actually +// intersect. if a geom has an AABB test function, that is called to +// provide a further refinement of the intersection. +// +// NOTE: this assumes that the geom AABBs are valid on entry +// and that both geoms are enabled. + +void collideAABBs (dxGeom *g1, dxGeom *g2, + void *data, dNearCallback *callback); + +//moved this to collision_space.cpp so we dont get unused warnings +/* { */ +/* dIASSERT((g1->gflags & GEOM_AABB_BAD)==0); */ +/* dIASSERT((g2->gflags & GEOM_AABB_BAD)==0); */ + +/* // no contacts if both geoms on the same body, and the body is not 0 */ +/* if (g1->body == g2->body && g1->body) return; */ + +/* // test if the category and collide bitfields match */ +/* if ( ((g1->category_bits & g2->collide_bits) || */ +/* (g2->category_bits & g1->collide_bits)) == 0) { */ +/* return; */ +/* } */ + +/* // if the bounding boxes are disjoint then don't do anything */ +/* dReal *bounds1 = g1->aabb; */ +/* dReal *bounds2 = g2->aabb; */ +/* if (bounds1[0] > bounds2[1] || */ +/* bounds1[1] < bounds2[0] || */ +/* bounds1[2] > bounds2[3] || */ +/* bounds1[3] < bounds2[2] || */ +/* bounds1[4] > bounds2[5] || */ +/* bounds1[5] < bounds2[4]) { */ +/* return; */ +/* } */ + +/* // check if either object is able to prove that it doesn't intersect the */ +/* // AABB of the other */ +/* if (g1->AABBTest (g2,bounds2) == 0) return; */ +/* if (g2->AABBTest (g1,bounds1) == 0) return; */ + +/* // the objects might actually intersect - call the space callback function */ +/* callback (data,g1,g2); */ +/* } */ + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_std.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_std.cpp new file mode 100644 index 00000000..62673f66 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_std.cpp @@ -0,0 +1,2081 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +standard ODE geometry primitives: public API and pairwise collision functions. + +the rule is that only the low level primitive collision functions should set +dContactGeom::g1 and dContactGeom::g2. + +*/ + +#include "ode/ode_common.h" +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_kernel.h" +#include "ode/ode_collision_std.h" +#include "ode/ode_collision_util.h" + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +//**************************************************************************** +// the basic geometry objects + +struct dxSphere : public dxGeom { + dReal radius; // sphere radius + dxSphere (dSpaceID space, dReal _radius); + void computeAABB(); +}; + + +struct dxBox : public dxGeom { + dVector3 side; // side lengths (x,y,z) + dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz); + void computeAABB(); +}; + + +struct dxCCylinder : public dxGeom { + dReal radius,lz; // radius, length along z axis + dxCCylinder (dSpaceID space, dReal _radius, dReal _length); + void computeAABB(); +}; + +struct dxCylinder : public dxGeom { + dReal radius,lz; // radius, length along z axis + dxCylinder (dSpaceID space, dReal _radius, dReal _length); + void computeAABB(); +}; + +struct dxPlane : public dxGeom { + dReal p[4]; + dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d); + void computeAABB(); +}; + + +struct dxRay : public dxGeom { + dReal length; + dxRay (dSpaceID space, dReal _length); + void computeAABB(); +}; + +//**************************************************************************** +// sphere public API + +dxSphere::dxSphere (dSpaceID space, dReal _radius) : dxGeom (space,1) +{ + dAASSERT (_radius > 0); + type = dSphereClass; + radius = _radius; +} + + +void dxSphere::computeAABB() +{ + aabb[0] = pos[0] - radius; + aabb[1] = pos[0] + radius; + aabb[2] = pos[1] - radius; + aabb[3] = pos[1] + radius; + aabb[4] = pos[2] - radius; + aabb[5] = pos[2] + radius; +} + + +dGeomID dCreateSphere (dSpaceID space, dReal radius) +{ + return new dxSphere (space,radius); +} + + +void dGeomSphereSetRadius (dGeomID g, dReal radius) +{ + dUASSERT (g && g->type == dSphereClass,"argument not a sphere"); + dAASSERT (radius > 0); + dxSphere *s = (dxSphere*) g; + s->radius = radius; + dGeomMoved (g); +} + + +dReal dGeomSphereGetRadius (dGeomID g) +{ + dUASSERT (g && g->type == dSphereClass,"argument not a sphere"); + dxSphere *s = (dxSphere*) g; + return s->radius; +} + + +dReal dGeomSpherePointDepth (dGeomID g, dReal x, dReal y, dReal z) +{ + dUASSERT (g && g->type == dSphereClass,"argument not a sphere"); + dxSphere *s = (dxSphere*) g; + return s->radius - dSqrt ((x-s->pos[0])*(x-s->pos[0]) + + (y-s->pos[1])*(y-s->pos[1]) + + (z-s->pos[2])*(z-s->pos[2])); +} + +//**************************************************************************** +// box public API + +dxBox::dxBox (dSpaceID space, dReal lx, dReal ly, dReal lz) : dxGeom (space,1) +{ + dAASSERT (lx >= 0 && ly >= 0 && lz >= 0); + type = dBoxClass; + side[0] = lx; + side[1] = ly; + side[2] = lz; +} + + +void dxBox::computeAABB() +{ + dReal xrange = REAL(0.5) * (dFabs (R[0] * side[0]) + + dFabs (R[1] * side[1]) + dFabs (R[2] * side[2])); + dReal yrange = REAL(0.5) * (dFabs (R[4] * side[0]) + + dFabs (R[5] * side[1]) + dFabs (R[6] * side[2])); + dReal zrange = REAL(0.5) * (dFabs (R[8] * side[0]) + + dFabs (R[9] * side[1]) + dFabs (R[10] * side[2])); + aabb[0] = pos[0] - xrange; + aabb[1] = pos[0] + xrange; + aabb[2] = pos[1] - yrange; + aabb[3] = pos[1] + yrange; + aabb[4] = pos[2] - zrange; + aabb[5] = pos[2] + zrange; +} + + +dGeomID dCreateBox (dSpaceID space, dReal lx, dReal ly, dReal lz) +{ + return new dxBox (space,lx,ly,lz); +} + + +void dGeomBoxSetLengths (dGeomID g, dReal lx, dReal ly, dReal lz) +{ + dUASSERT (g && g->type == dBoxClass,"argument not a box"); + dAASSERT (lx > 0 && ly > 0 && lz > 0); + dxBox *b = (dxBox*) g; + b->side[0] = lx; + b->side[1] = ly; + b->side[2] = lz; + dGeomMoved (g); +} + + +void dGeomBoxGetLengths (dGeomID g, dVector3 result) +{ + dUASSERT (g && g->type == dBoxClass,"argument not a box"); + dxBox *b = (dxBox*) g; + result[0] = b->side[0]; + result[1] = b->side[1]; + result[2] = b->side[2]; +} + + +dReal dGeomBoxPointDepth (dGeomID g, dReal x, dReal y, dReal z) +{ + dUASSERT (g && g->type == dBoxClass,"argument not a box"); + dxBox *b = (dxBox*) g; + + // Set p = (x,y,z) relative to box center + // + // This will be (0,0,0) if the point is at (side[0]/2,side[1]/2,side[2]/2) + + dVector3 p,q; + + p[0] = x - b->pos[0]; + p[1] = y - b->pos[1]; + p[2] = z - b->pos[2]; + + // Rotate p into box's coordinate frame, so we can + // treat the OBB as an AABB + + dMULTIPLY1_331 (q,b->R,p); + + // Record distance from point to each successive box side, and see + // if the point is inside all six sides + + dReal dist[6]; + int i; + + bool inside = true; + + for (i=0; i < 3; i++) { + dReal side = b->side[i] * REAL(0.5); + + dist[i ] = side - q[i]; + dist[i+3] = side + q[i]; + + if ((dist[i] < 0) || (dist[i+3] < 0)) { + inside = false; + } + } + + // If point is inside the box, the depth is the smallest positive distance + // to any side + + if (inside) { + dReal smallest_dist = (dReal) (unsigned) -1; + + for (i=0; i < 6; i++) { + if (dist[i] < smallest_dist) smallest_dist = dist[i]; + } + + return smallest_dist; + } + + // Otherwise, if point is outside the box, the depth is the largest + // distance to any side. This is an approximation to the 'proper' + // solution (the proper solution may be larger in some cases). + + dReal largest_dist = 0; + + for (i=0; i < 6; i++) { + if (dist[i] > largest_dist) largest_dist = dist[i]; + } + + return -largest_dist; +} + +//**************************************************************************** +// capped cylinder public API + +dxCCylinder::dxCCylinder (dSpaceID space, dReal _radius, dReal _length) : + dxGeom (space,1) +{ + dAASSERT (_radius > 0 && _length > 0); + type = dCCylinderClass; + radius = _radius; + lz = _length; +} + + +void dxCCylinder::computeAABB() +{ + dReal xrange = dFabs(R[2] * lz) * REAL(0.5) + radius; + dReal yrange = dFabs(R[6] * lz) * REAL(0.5) + radius; + dReal zrange = dFabs(R[10] * lz) * REAL(0.5) + radius; + aabb[0] = pos[0] - xrange; + aabb[1] = pos[0] + xrange; + aabb[2] = pos[1] - yrange; + aabb[3] = pos[1] + yrange; + aabb[4] = pos[2] - zrange; + aabb[5] = pos[2] + zrange; +} + + +dGeomID dCreateCCylinder (dSpaceID space, dReal radius, dReal length) +{ + return new dxCCylinder (space,radius,length); +} + + +void dGeomCCylinderSetParams (dGeomID g, dReal radius, dReal length) +{ + dUASSERT (g && g->type == dCCylinderClass,"argument not a ccylinder"); + dAASSERT (radius > 0 && length > 0); + dxCCylinder *c = (dxCCylinder*) g; + c->radius = radius; + c->lz = length; + dGeomMoved (g); +} + + +void dGeomCCylinderGetParams (dGeomID g, dReal *radius, dReal *length) +{ + dUASSERT (g && g->type == dCCylinderClass,"argument not a ccylinder"); + dxCCylinder *c = (dxCCylinder*) g; + *radius = c->radius; + *length = c->lz; +} + + +dReal dGeomCCylinderPointDepth (dGeomID g, dReal x, dReal y, dReal z) +{ + dUASSERT (g && g->type == dCCylinderClass,"argument not a ccylinder"); + dxCCylinder *c = (dxCCylinder*) g; + dVector3 a; + a[0] = x - c->pos[0]; + a[1] = y - c->pos[1]; + a[2] = z - c->pos[2]; + dReal beta = dDOT14(a,c->R+2); + dReal lz2 = c->lz*REAL(0.5); + if (beta < -lz2) beta = -lz2; + else if (beta > lz2) beta = lz2; + a[0] = c->pos[0] + beta*c->R[0*4+2]; + a[1] = c->pos[1] + beta*c->R[1*4+2]; + a[2] = c->pos[2] + beta*c->R[2*4+2]; + return c->radius - + dSqrt ((x-a[0])*(x-a[0]) + (y-a[1])*(y-a[1]) + (z-a[2])*(z-a[2])); +} + +//**************************************************************************** +// plane public API + +static void make_sure_plane_normal_has_unit_length (dxPlane *g) +{ + dReal l = g->p[0]*g->p[0] + g->p[1]*g->p[1] + g->p[2]*g->p[2]; + if (l > 0) { + l = dRecipSqrt(l); + g->p[0] *= l; + g->p[1] *= l; + g->p[2] *= l; + g->p[3] *= l; + } + else { + g->p[0] = 1; + g->p[1] = 0; + g->p[2] = 0; + g->p[3] = 0; + } +} + + +dxPlane::dxPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) : + dxGeom (space,0) +{ + type = dPlaneClass; + p[0] = a; + p[1] = b; + p[2] = c; + p[3] = d; + make_sure_plane_normal_has_unit_length (this); +} + + +void dxPlane::computeAABB() +{ + // @@@ planes that have normal vectors aligned along an axis can use a + // @@@ less comprehensive (half space) bounding box. + aabb[0] = -dInfinity; + aabb[1] = dInfinity; + aabb[2] = -dInfinity; + aabb[3] = dInfinity; + aabb[4] = -dInfinity; + aabb[5] = dInfinity; +} + + +dGeomID dCreatePlane (dSpaceID space, + dReal a, dReal b, dReal c, dReal d) +{ + return new dxPlane (space,a,b,c,d); +} + + +void dGeomPlaneSetParams (dGeomID g, dReal a, dReal b, dReal c, dReal d) +{ + dUASSERT (g && g->type == dPlaneClass,"argument not a plane"); + dxPlane *p = (dxPlane*) g; + p->p[0] = a; + p->p[1] = b; + p->p[2] = c; + p->p[3] = d; + make_sure_plane_normal_has_unit_length (p); + dGeomMoved (g); +} + + +void dGeomPlaneGetParams (dGeomID g, dVector4 result) +{ + dUASSERT (g && g->type == dPlaneClass,"argument not a plane"); + dxPlane *p = (dxPlane*) g; + result[0] = p->p[0]; + result[1] = p->p[1]; + result[2] = p->p[2]; + result[3] = p->p[3]; +} + + +dReal dGeomPlanePointDepth (dGeomID g, dReal x, dReal y, dReal z) +{ + dUASSERT (g && g->type == dPlaneClass,"argument not a plane"); + dxPlane *p = (dxPlane*) g; + return p->p[3] - p->p[0]*x - p->p[1]*y - p->p[2]*z; +} + +//**************************************************************************** +// ray public API + +dxRay::dxRay (dSpaceID space, dReal _length) : dxGeom (space,1) +{ + type = dRayClass; + length = _length; +} + + +void dxRay::computeAABB() +{ + dVector3 e; + e[0] = pos[0] + R[0*4+2]*length; + e[1] = pos[1] + R[1*4+2]*length; + e[2] = pos[2] + R[2*4+2]*length; + + if (pos[0] < e[0]){ + aabb[0] = pos[0]; + aabb[1] = e[0]; + } + else{ + aabb[0] = e[0]; + aabb[1] = pos[0]; + } + + if (pos[1] < e[1]){ + aabb[2] = pos[1]; + aabb[3] = e[1]; + } + else{ + aabb[2] = e[1]; + aabb[3] = pos[1]; + } + + if (pos[2] < e[2]){ + aabb[4] = pos[2]; + aabb[5] = e[2]; + } + else{ + aabb[4] = e[2]; + aabb[5] = pos[2]; + } +} + + +dGeomID dCreateRay (dSpaceID space, dReal length) +{ + return new dxRay (space,length); +} + + +void dGeomRaySetLength (dGeomID g, dReal length) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + dxRay *r = (dxRay*) g; + r->length = length; + dGeomMoved (g); +} + + +dReal dGeomRayGetLength (dGeomID g) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + dxRay *r = (dxRay*) g; + return r->length; +} + + +void dGeomRaySet (dGeomID g, dReal px, dReal py, dReal pz, + dReal dx, dReal dy, dReal dz) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + dReal* rot = g->R; + dReal* pos = g->pos; + dVector3 n; + pos[0] = px; + pos[1] = py; + pos[2] = pz; + + n[0] = dx; + n[1] = dy; + n[2] = dz; + dNormalize3(n); + rot[0*4+2] = n[0]; + rot[1*4+2] = n[1]; + rot[2*4+2] = n[2]; + dGeomMoved (g); +} + + +void dGeomRayGet (dGeomID g, dVector3 start, dVector3 dir) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + start[0] = g->pos[0]; + start[1] = g->pos[1]; + start[2] = g->pos[2]; + dir[0] = g->R[0*4+2]; + dir[1] = g->R[1*4+2]; + dir[2] = g->R[2*4+2]; +} + + +void dGeomRaySetParams (dxGeom *g, int FirstContact, int BackfaceCull) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + + if (FirstContact){ + g->gflags |= RAY_FIRSTCONTACT; + } + else g->gflags &= ~RAY_FIRSTCONTACT; + + if (BackfaceCull){ + g->gflags |= RAY_BACKFACECULL; + } + else g->gflags &= ~RAY_BACKFACECULL; +} + + +void dGeomRayGetParams (dxGeom *g, int *FirstContact, int *BackfaceCull) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + + (*FirstContact) = ((g->gflags & RAY_FIRSTCONTACT) != 0); + (*BackfaceCull) = ((g->gflags & RAY_BACKFACECULL) != 0); +} + + +void dGeomRaySetClosestHit (dxGeom *g, int closestHit) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + if (closestHit){ + g->gflags |= RAY_CLOSEST_HIT; + } + else g->gflags &= ~RAY_CLOSEST_HIT; +} + + +int dGeomRayGetClosestHit (dxGeom *g) +{ + dUASSERT (g && g->type == dRayClass,"argument not a ray"); + return ((g->gflags & RAY_CLOSEST_HIT) != 0); +} + +//**************************************************************************** +// box-box collision utility + + +// find all the intersection points between the 2D rectangle with vertices +// at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]), +// (p[2],p[3]),(p[4],p[5]),(p[6],p[7]). +// +// the intersection points are returned as x,y pairs in the 'ret' array. +// the number of intersection points is returned by the function (this will +// be in the range 0 to 8). + +static int intersectRectQuad (dReal h[2], dReal p[8], dReal ret[16]) +{ + // q (and r) contain nq (and nr) coordinate points for the current (and + // chopped) polygons + int nq=4,nr=0; + dReal buffer[16]; + dReal *q = p; + dReal *r = ret; + for (int dir=0; dir <= 1; dir++) { + // direction notation: xy[0] = x axis, xy[1] = y axis + for (int sign=-1; sign <= 1; sign += 2) { + // chop q along the line xy[dir] = sign*h[dir] + dReal *pq = q; + dReal *pr = r; + nr = 0; + for (int i=nq; i > 0; i--) { + // go through all points in q and all lines between adjacent points + if (sign*pq[dir] < h[dir]) { + // this point is inside the chopping line + pr[0] = pq[0]; + pr[1] = pq[1]; + pr += 2; + nr++; + if (nr & 8) { + q = r; + goto done; + } + } + dReal *nextq = (i > 1) ? pq+2 : q; + if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) { + // this line crosses the chopping line + pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) / + (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]); + pr[dir] = sign*h[dir]; + pr += 2; + nr++; + if (nr & 8) { + q = r; + goto done; + } + } + pq += 2; + } + q = r; + r = (q==ret) ? buffer : ret; + nq = nr; + } + } + done: + if (q != ret) memcpy (ret,q,nr*2*sizeof(dReal)); + return nr; +} + + +// given n points in the plane (array p, of size 2*n), generate m points that +// best represent the whole set. the definition of 'best' here is not +// predetermined - the idea is to select points that give good box-box +// collision detection behavior. the chosen point indexes are returned in the +// array iret (of size m). 'i0' is always the first entry in the array. +// n must be in the range [1..8]. m must be in the range [1..n]. i0 must be +// in the range [0..n-1]. + +void cullPoints (int n, dReal p[], int m, int i0, int iret[]) +{ + // compute the centroid of the polygon in cx,cy + int i,j; + dReal a,cx,cy,q; + if (n==1) { + cx = p[0]; + cy = p[1]; + } + else if (n==2) { + cx = REAL(0.5)*(p[0] + p[2]); + cy = REAL(0.5)*(p[1] + p[3]); + } + else { + a = 0; + cx = 0; + cy = 0; + for (i=0; i<(n-1); i++) { + q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1]; + a += q; + cx += q*(p[i*2]+p[i*2+2]); + cy += q*(p[i*2+1]+p[i*2+3]); + } + q = p[n*2-2]*p[1] - p[0]*p[n*2-1]; + a = dRecip(REAL(3.0)*(a+q)); + cx = a*(cx + q*(p[n*2-2]+p[0])); + cy = a*(cy + q*(p[n*2-1]+p[1])); + } + + // compute the angle of each point w.r.t. the centroid + dReal A[8]; + for (i=0; i M_PI) a -= 2*M_PI; + dReal maxdiff=1e9,diff; +#ifndef dNODEBUG + *iret = i0; // iret is not allowed to keep this value +#endif + for (i=0; i M_PI) diff = 2*M_PI - diff; + if (diff < maxdiff) { + maxdiff = diff; + *iret = i; + } + } + } +#ifndef dNODEBUG + dIASSERT (*iret != i0); // ensure iret got set +#endif + avail[*iret] = 0; + iret++; + } +} + + +// given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and +// generate contact points. this returns 0 if there is no contact otherwise +// it returns the number of contacts generated. +// `normal' returns the contact normal. +// `depth' returns the maximum penetration depth along that normal. +// `return_code' returns a number indicating the type of contact that was +// detected: +// 1,2,3 = box 2 intersects with a face of box 1 +// 4,5,6 = box 1 intersects with a face of box 2 +// 7..15 = edge-edge contact +// `maxc' is the maximum number of contacts allowed to be generated, i.e. +// the size of the `contact' array. +// `contact' and `skip' are the contact array information provided to the +// collision functions. this function only fills in the position and depth +// fields. + +int dBoxBox (const dVector3 p1, const dMatrix3 R1, + const dVector3 side1, const dVector3 p2, + const dMatrix3 R2, const dVector3 side2, + dVector3 normal, dReal *depth, int *return_code, + int maxc, dContactGeom *contact, int skip) +{ + const dReal fudge_factor = REAL(1.05); + dVector3 p,pp,normalC; + const dReal *normalR = 0; + dReal A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33, + Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l; + int i,j,invert_normal,code; + + // get vector from centers of box 1 to box 2, relative to box 1 + p[0] = p2[0] - p1[0]; + p[1] = p2[1] - p1[1]; + p[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 + + // get side lengths / 2 + A[0] = side1[0]*REAL(0.5); + A[1] = side1[1]*REAL(0.5); + A[2] = side1[2]*REAL(0.5); + B[0] = side2[0]*REAL(0.5); + B[1] = side2[1]*REAL(0.5); + B[2] = side2[2]*REAL(0.5); + + // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 + R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); + R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); + R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); + + Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); + Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); + Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); + + // for all 15 possible separating axes: + // * see if the axis separates the boxes. if so, return 0. + // * find the depth of the penetration along the separating axis (s2) + // * if this is the largest depth so far, record it. + // the normal vector will be set to the separating axis with the smallest + // depth. note: normalR is set to point to a column of R1 or R2 if that is + // the smallest depth normal so far. otherwise normalR is 0 and normalC is + // set to a vector relative to body 1. invert_normal is 1 if the sign of + // the normal should be flipped. + +#define TST(expr1,expr2,norm,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + if (s2 > s) { \ + s = s2; \ + normalR = norm; \ + invert_normal = ((expr1) < 0); \ + code = (cc); \ + } + + s = -dInfinity; + invert_normal = 0; + code = 0; + + // separating axis = u1,u2,u3 + TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1); + TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2); + TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3); + + // separating axis = v1,v2,v3 + TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4); + TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5); + TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6); + + // note: cross product axes need to be scaled when s is computed. + // normal (n1,n2,n3) is relative to box 1. +#undef TST +#define TST(expr1,expr2,n1,n2,n3,cc) \ + s2 = dFabs(expr1) - (expr2); \ + if (s2 > 0) return 0; \ + l = dSqrt ((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ + if (l > 0) { \ + s2 /= l; \ + if (s2*fudge_factor > s) { \ + s = s2; \ + normalR = 0; \ + normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ + invert_normal = ((expr1) < 0); \ + code = (cc); \ + } \ + } + + // separating axis = u1 x (v1,v2,v3) + TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7); + TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8); + TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9); + + // separating axis = u2 x (v1,v2,v3) + TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10); + TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11); + TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12); + + // separating axis = u3 x (v1,v2,v3) + TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13); + TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14); + TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15); + +#undef TST + + if (!code) return 0; + + // if we get to this point, the boxes interpenetrate. compute the normal + // in global coordinates. + if (normalR) { + normal[0] = normalR[0]; + normal[1] = normalR[4]; + normal[2] = normalR[8]; + } + else { + dMULTIPLY0_331 (normal,R1,normalC); + } + if (invert_normal) { + normal[0] = -normal[0]; + normal[1] = -normal[1]; + normal[2] = -normal[2]; + } + *depth = -s; + + // compute contact point(s) + + if (code > 6) { + // an edge from box 1 touches an edge from box 2. + // find a point pa on the intersecting edge of box 1 + dVector3 pa; + dReal sign; + for (i=0; i<3; i++) pa[i] = p1[i]; + for (j=0; j<3; j++) { + sign = (dDOT14(normal,R1+j) > 0) ? REAL(1.0) : REAL(-1.0); + for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j]; + } + + // find a point pb on the intersecting edge of box 2 + dVector3 pb; + for (i=0; i<3; i++) pb[i] = p2[i]; + for (j=0; j<3; j++) { + sign = (dDOT14(normal,R2+j) > 0) ? REAL(-1.0) : REAL(1.0); + for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j]; + } + + dReal alpha,beta; + dVector3 ua,ub; + for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4]; + for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4]; + + dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta); + for (i=0; i<3; i++) pa[i] += ua[i]*alpha; + for (i=0; i<3; i++) pb[i] += ub[i]*beta; + + for (i=0; i<3; i++) contact[0].pos[i] = REAL(0.5)*(pa[i]+pb[i]); + contact[0].depth = *depth; + *return_code = code; + return 1; + } + + // okay, we have a face-something intersection (because the separating + // axis is perpendicular to a face). define face 'a' to be the reference + // face (i.e. the normal vector is perpendicular to this) and face 'b' to be + // the incident face (the closest face of the other box). + + const dReal *Ra,*Rb,*pa,*pb,*Sa,*Sb; + if (code <= 3) { + Ra = R1; + Rb = R2; + pa = p1; + pb = p2; + Sa = A; + Sb = B; + } + else { + Ra = R2; + Rb = R1; + pa = p2; + pb = p1; + Sa = B; + Sb = A; + } + + // nr = normal vector of reference face dotted with axes of incident box. + // anr = absolute values of nr. + dVector3 normal2,nr,anr; + if (code <= 3) { + normal2[0] = normal[0]; + normal2[1] = normal[1]; + normal2[2] = normal[2]; + } + else { + normal2[0] = -normal[0]; + normal2[1] = -normal[1]; + normal2[2] = -normal[2]; + } + dMULTIPLY1_331 (nr,Rb,normal2); + anr[0] = dFabs (nr[0]); + anr[1] = dFabs (nr[1]); + anr[2] = dFabs (nr[2]); + + // find the largest compontent of anr: this corresponds to the normal + // for the indident face. the other axis numbers of the indicent face + // are stored in a1,a2. + int lanr,a1,a2; + if (anr[1] > anr[0]) { + if (anr[1] > anr[2]) { + a1 = 0; + lanr = 1; + a2 = 2; + } + else { + a1 = 0; + a2 = 1; + lanr = 2; + } + } + else { + if (anr[0] > anr[2]) { + lanr = 0; + a1 = 1; + a2 = 2; + } + else { + a1 = 0; + a2 = 1; + lanr = 2; + } + } + + // compute center point of incident face, in reference-face coordinates + dVector3 center; + if (nr[lanr] < 0) { + for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr]; + } + else { + for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr]; + } + + // find the normal and non-normal axis numbers of the reference box + int codeN,code1,code2; + if (code <= 3) codeN = code-1; else codeN = code-4; + if (codeN==0) { + code1 = 1; + code2 = 2; + } + else if (codeN==1) { + code1 = 0; + code2 = 2; + } + else { + code1 = 0; + code2 = 1; + } + + // find the four corners of the incident face, in reference-face coordinates + dReal quad[8]; // 2D coordinate of incident face (x,y pairs) + dReal c1,c2,m11,m12,m21,m22; + c1 = dDOT14 (center,Ra+code1); + c2 = dDOT14 (center,Ra+code2); + // optimize this? - we have already computed this data above, but it is not + // stored in an easy-to-index format. for now it's quicker just to recompute + // the four dot products. + m11 = dDOT44 (Ra+code1,Rb+a1); + m12 = dDOT44 (Ra+code1,Rb+a2); + m21 = dDOT44 (Ra+code2,Rb+a1); + m22 = dDOT44 (Ra+code2,Rb+a2); + { + dReal k1 = m11*Sb[a1]; + dReal k2 = m21*Sb[a1]; + dReal k3 = m12*Sb[a2]; + dReal k4 = m22*Sb[a2]; + quad[0] = c1 - k1 - k3; + quad[1] = c2 - k2 - k4; + quad[2] = c1 - k1 + k3; + quad[3] = c2 - k2 + k4; + quad[4] = c1 + k1 + k3; + quad[5] = c2 + k2 + k4; + quad[6] = c1 + k1 - k3; + quad[7] = c2 + k2 - k4; + } + + // find the size of the reference face + dReal rect[2]; + rect[0] = Sa[code1]; + rect[1] = Sa[code2]; + + // intersect the incident and reference faces + dReal ret[16]; + int n = intersectRectQuad (rect,quad,ret); + if (n < 1) return 0; // this should never happen + + // convert the intersection points into reference-face coordinates, + // and compute the contact position and depth for each point. only keep + // those points that have a positive (penetrating) depth. delete points in + // the 'ret' array as necessary so that 'point' and 'ret' correspond. + dReal point[3*8]; // penetrating contact points + dReal dep[8]; // depths for those points + dReal det1 = dRecip(m11*m22 - m12*m21); + m11 *= det1; + m12 *= det1; + m21 *= det1; + m22 *= det1; + int cnum = 0; // number of penetrating contact points found + for (j=0; j < n; j++) { + dReal k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2); + dReal k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2); + for (i=0; i<3; i++) point[cnum*3+i] = + center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2]; + dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3); + if (dep[cnum] >= 0) { + ret[cnum*2] = ret[j*2]; + ret[cnum*2+1] = ret[j*2+1]; + cnum++; + } + } + if (cnum < 1) return 0; // this should never happen + + // we can't generate more contacts than we actually have + if (maxc > cnum) maxc = cnum; + if (maxc < 1) maxc = 1; + + if (cnum <= maxc) { + // we have less contacts than we need, so we use them all + for (j=0; j < cnum; j++) { + dContactGeom *con = CONTACT(contact,skip*j); + for (i=0; i<3; i++) con->pos[i] = point[j*3+i] + pa[i]; + con->depth = dep[j]; + } + } + else { + // we have more contacts than are wanted, some of them must be culled. + // find the deepest point, it is always the first contact. + int i1 = 0; + dReal maxdepth = dep[0]; + for (i=1; i maxdepth) { + maxdepth = dep[i]; + i1 = i; + } + } + + int iret[8]; + cullPoints (cnum,ret,maxc,i1,iret); + + for (j=0; j < maxc; j++) { + dContactGeom *con = CONTACT(contact,skip*j); + for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i]; + con->depth = dep[iret[j]]; + } + cnum = maxc; + } + + *return_code = code; + return cnum; +} + +//**************************************************************************** +// pairwise collision functions for standard geom types + +int dCollideSphereSphere (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dSphereClass); + dIASSERT (o2->type == dSphereClass); + dxSphere *sphere1 = (dxSphere*) o1; + dxSphere *sphere2 = (dxSphere*) o2; + + contact->g1 = o1; + contact->g2 = o2; + + return dCollideSpheres (o1->pos,sphere1->radius, + o2->pos,sphere2->radius,contact); +} + + +int dCollideSphereBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + // this is easy. get the sphere center `p' relative to the box, and then clip + // that to the boundary of the box (call that point `q'). if q is on the + // boundary of the box and |p-q| is <= sphere radius, they touch. + // if q is inside the box, the sphere is inside the box, so set a contact + // normal to push the sphere to the closest box face. + + dVector3 l,t,p,q,r; + dReal depth; + int onborder = 0; + + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dSphereClass); + dIASSERT (o2->type == dBoxClass); + dxSphere *sphere = (dxSphere*) o1; + dxBox *box = (dxBox*) o2; + + contact->g1 = o1; + contact->g2 = o2; + + p[0] = o1->pos[0] - o2->pos[0]; + p[1] = o1->pos[1] - o2->pos[1]; + p[2] = o1->pos[2] - o2->pos[2]; + + l[0] = box->side[0]*REAL(0.5); + t[0] = dDOT14(p,o2->R); + if (t[0] < -l[0]) { t[0] = -l[0]; onborder = 1; } + if (t[0] > l[0]) { t[0] = l[0]; onborder = 1; } + + l[1] = box->side[1]*REAL(0.5); + t[1] = dDOT14(p,o2->R+1); + if (t[1] < -l[1]) { t[1] = -l[1]; onborder = 1; } + if (t[1] > l[1]) { t[1] = l[1]; onborder = 1; } + + t[2] = dDOT14(p,o2->R+2); + l[2] = box->side[2]*REAL(0.5); + if (t[2] < -l[2]) { t[2] = -l[2]; onborder = 1; } + if (t[2] > l[2]) { t[2] = l[2]; onborder = 1; } + + if (!onborder) { + // sphere center inside box. find closest face to `t' + dReal min_distance = l[0] - dFabs(t[0]); + int mini = 0; + for (int i=1; i<3; i++) { + dReal face_distance = l[i] - dFabs(t[i]); + if (face_distance < min_distance) { + min_distance = face_distance; + mini = i; + } + } + // contact position = sphere center + contact->pos[0] = o1->pos[0]; + contact->pos[1] = o1->pos[1]; + contact->pos[2] = o1->pos[2]; + // contact normal points to closest face + dVector3 tmp; + tmp[0] = 0; + tmp[1] = 0; + tmp[2] = 0; + tmp[mini] = (t[mini] > 0) ? REAL(1.0) : REAL(-1.0); + dMULTIPLY0_331 (contact->normal,o2->R,tmp); + // contact depth = distance to wall along normal plus radius + contact->depth = min_distance + sphere->radius; + return 1; + } + + t[3] = 0; //@@@ hmmm + dMULTIPLY0_331 (q,o2->R,t); + r[0] = p[0] - q[0]; + r[1] = p[1] - q[1]; + r[2] = p[2] - q[2]; + depth = sphere->radius - dSqrt(dDOT(r,r)); + if (depth < 0) return 0; + contact->pos[0] = q[0] + o2->pos[0]; + contact->pos[1] = q[1] + o2->pos[1]; + contact->pos[2] = q[2] + o2->pos[2]; + contact->normal[0] = r[0]; + contact->normal[1] = r[1]; + contact->normal[2] = r[2]; + dNormalize3 (contact->normal); + contact->depth = depth; + return 1; +} + + +int dCollideSpherePlane (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dSphereClass); + dIASSERT (o2->type == dPlaneClass); + dxSphere *sphere = (dxSphere*) o1; + dxPlane *plane = (dxPlane*) o2; + + contact->g1 = o1; + contact->g2 = o2; + dReal k = dDOT (o1->pos,plane->p); + dReal depth = plane->p[3] - k + sphere->radius; + if (depth >= 0) { + contact->normal[0] = plane->p[0]; + contact->normal[1] = plane->p[1]; + contact->normal[2] = plane->p[2]; + contact->pos[0] = o1->pos[0] - plane->p[0] * sphere->radius; + contact->pos[1] = o1->pos[1] - plane->p[1] * sphere->radius; + contact->pos[2] = o1->pos[2] - plane->p[2] * sphere->radius; + contact->depth = depth; + return 1; + } + else return 0; +} + + +int dCollideBoxBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dBoxClass); + dIASSERT (o2->type == dBoxClass); + dVector3 normal; + dReal depth; + int code; + dxBox *b1 = (dxBox*) o1; + dxBox *b2 = (dxBox*) o2; + int num = dBoxBox (o1->pos,o1->R,b1->side, o2->pos,o2->R,b2->side, + normal,&depth,&code,flags & NUMC_MASK,contact,skip); + for (int i=0; inormal[0] = -normal[0]; + CONTACT(contact,i*skip)->normal[1] = -normal[1]; + CONTACT(contact,i*skip)->normal[2] = -normal[2]; + CONTACT(contact,i*skip)->g1 = o1; + CONTACT(contact,i*skip)->g2 = o2; + } + return num; +} + + +int dCollideBoxPlane (dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dBoxClass); + dIASSERT (o2->type == dPlaneClass); + dxBox *box = (dxBox*) o1; + dxPlane *plane = (dxPlane*) o2; + + contact->g1 = o1; + contact->g2 = o2; + int ret = 0; + + //@@@ problem: using 4-vector (plane->p) as 3-vector (normal). + const dReal *R = o1->R; // rotation of box + const dReal *n = plane->p; // normal vector + + // project sides lengths along normal vector, get absolute values + dReal Q1 = dDOT14(n,R+0); + dReal Q2 = dDOT14(n,R+1); + dReal Q3 = dDOT14(n,R+2); + dReal A1 = box->side[0] * Q1; + dReal A2 = box->side[1] * Q2; + dReal A3 = box->side[2] * Q3; + dReal B1 = dFabs(A1); + dReal B2 = dFabs(A2); + dReal B3 = dFabs(A3); + + // early exit test + dReal depth = plane->p[3] + REAL(0.5)*(B1+B2+B3) - dDOT(n,o1->pos); + if (depth < 0) return 0; + + // find number of contacts requested + int maxc = flags & NUMC_MASK; + if (maxc < 1) maxc = 1; + if (maxc > 3) maxc = 3; // no more than 3 contacts per box allowed + + // find deepest point + dVector3 p; + p[0] = o1->pos[0]; + p[1] = o1->pos[1]; + p[2] = o1->pos[2]; +#define FOO(i,op) \ + p[0] op REAL(0.5)*box->side[i] * R[0+i]; \ + p[1] op REAL(0.5)*box->side[i] * R[4+i]; \ + p[2] op REAL(0.5)*box->side[i] * R[8+i]; +#define BAR(i,iinc) if (A ## iinc > 0) { FOO(i,-=) } else { FOO(i,+=) } + BAR(0,1); + BAR(1,2); + BAR(2,3); +#undef FOO +#undef BAR + + // the deepest point is the first contact point + contact->pos[0] = p[0]; + contact->pos[1] = p[1]; + contact->pos[2] = p[2]; + contact->normal[0] = n[0]; + contact->normal[1] = n[1]; + contact->normal[2] = n[2]; + contact->depth = depth; + ret = 1; // ret is number of contact points found so far + if (maxc == 1) goto done; + + // get the second and third contact points by starting from `p' and going + // along the two sides with the smallest projected length. + +#define FOO(i,j,op) \ + CONTACT(contact,i*skip)->pos[0] = p[0] op box->side[j] * R[0+j]; \ + CONTACT(contact,i*skip)->pos[1] = p[1] op box->side[j] * R[4+j]; \ + CONTACT(contact,i*skip)->pos[2] = p[2] op box->side[j] * R[8+j]; +#define BAR(ctact,side,sideinc) \ + depth -= B ## sideinc; \ + if (depth < 0) goto done; \ + if (A ## sideinc > 0) { FOO(ctact,side,+) } else { FOO(ctact,side,-) } \ + CONTACT(contact,ctact*skip)->depth = depth; \ + ret++; + + CONTACT(contact,skip)->normal[0] = n[0]; + CONTACT(contact,skip)->normal[1] = n[1]; + CONTACT(contact,skip)->normal[2] = n[2]; + if (maxc == 3) { + CONTACT(contact,2*skip)->normal[0] = n[0]; + CONTACT(contact,2*skip)->normal[1] = n[1]; + CONTACT(contact,2*skip)->normal[2] = n[2]; + } + + if (B1 < B2) { + if (B3 < B1) goto use_side_3; else { + BAR(1,0,1); // use side 1 + if (maxc == 2) goto done; + if (B2 < B3) goto contact2_2; else goto contact2_3; + } + } + else { + if (B3 < B2) { + use_side_3: // use side 3 + BAR(1,2,3); + if (maxc == 2) goto done; + if (B1 < B2) goto contact2_1; else goto contact2_2; + } + else { + BAR(1,1,2); // use side 2 + if (maxc == 2) goto done; + if (B1 < B3) goto contact2_1; else goto contact2_3; + } + } + + contact2_1: BAR(2,0,1); goto done; + contact2_2: BAR(2,1,2); goto done; + contact2_3: BAR(2,2,3); goto done; +#undef FOO +#undef BAR + + done: + for (int i=0; ig1 = o1; + CONTACT(contact,i*skip)->g2 = o2; + } + return ret; +} + + +int dCollideCCylinderSphere (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dCCylinderClass); + dIASSERT (o2->type == dSphereClass); + dxCCylinder *ccyl = (dxCCylinder*) o1; + dxSphere *sphere = (dxSphere*) o2; + + contact->g1 = o1; + contact->g2 = o2; + + // find the point on the cylinder axis that is closest to the sphere + dReal alpha = + o1->R[2] * (o2->pos[0] - o1->pos[0]) + + o1->R[6] * (o2->pos[1] - o1->pos[1]) + + o1->R[10] * (o2->pos[2] - o1->pos[2]); + dReal lz2 = ccyl->lz * REAL(0.5); + if (alpha > lz2) alpha = lz2; + if (alpha < -lz2) alpha = -lz2; + + // collide the spheres + dVector3 p; + p[0] = o1->pos[0] + alpha * o1->R[2]; + p[1] = o1->pos[1] + alpha * o1->R[6]; + p[2] = o1->pos[2] + alpha * o1->R[10]; + return dCollideSpheres (p,ccyl->radius,o2->pos,sphere->radius,contact); +} + + +int dCollideCCylinderBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dCCylinderClass); + dIASSERT (o2->type == dBoxClass); + dxCCylinder *cyl = (dxCCylinder*) o1; + dxBox *box = (dxBox*) o2; + + contact->g1 = o1; + contact->g2 = o2; + + // get p1,p2 = cylinder axis endpoints, get radius + dVector3 p1,p2; + dReal clen = cyl->lz * REAL(0.5); + p1[0] = o1->pos[0] + clen * o1->R[2]; + p1[1] = o1->pos[1] + clen * o1->R[6]; + p1[2] = o1->pos[2] + clen * o1->R[10]; + p2[0] = o1->pos[0] - clen * o1->R[2]; + p2[1] = o1->pos[1] - clen * o1->R[6]; + p2[2] = o1->pos[2] - clen * o1->R[10]; + dReal radius = cyl->radius; + + // copy out box center, rotation matrix, and side array + dReal *c = o2->pos; + dReal *R = o2->R; + const dReal *side = box->side; + + // get the closest point between the cylinder axis and the box + dVector3 pl,pb; + dClosestLineBoxPoints (p1,p2,c,R,side,pl,pb); + + // generate contact point + return dCollideSpheres (pl,radius,pb,0,contact); +} + + +int dCollideCCylinderCCylinder (dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip) +{ + int i; + const dReal tolerance = REAL(1e-5); + + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dCCylinderClass); + dIASSERT (o2->type == dCCylinderClass); + dxCCylinder *cyl1 = (dxCCylinder*) o1; + dxCCylinder *cyl2 = (dxCCylinder*) o2; + + contact->g1 = o1; + contact->g2 = o2; + + // copy out some variables, for convenience + dReal lz1 = cyl1->lz * REAL(0.5); + dReal lz2 = cyl2->lz * REAL(0.5); + dReal *pos1 = o1->pos; + dReal *pos2 = o2->pos; + dReal axis1[3],axis2[3]; + axis1[0] = o1->R[2]; + axis1[1] = o1->R[6]; + axis1[2] = o1->R[10]; + axis2[0] = o2->R[2]; + axis2[1] = o2->R[6]; + axis2[2] = o2->R[10]; + + // if the cylinder axes are close to parallel, we'll try to detect up to + // two contact points along the body of the cylinder. if we can't find any + // points then we'll fall back to the closest-points algorithm. note that + // we are not treating this special case for reasons of degeneracy, but + // because we want two contact points in some situations. the closet-points + // algorithm is robust in all casts, but it can return only one contact. + + dVector3 sphere1,sphere2; + dReal a1a2 = dDOT (axis1,axis2); + dReal det = REAL(1.0)-a1a2*a1a2; + if (det < tolerance) { + // the cylinder axes (almost) parallel, so we will generate up to two + // contacts. alpha1 and alpha2 (line position parameters) are related by: + // alpha2 = alpha1 + (pos1-pos2)'*axis1 (if axis1==axis2) + // or alpha2 = -(alpha1 + (pos1-pos2)'*axis1) (if axis1==-axis2) + // first compute where the two cylinders overlap in alpha1 space: + if (a1a2 < 0) { + axis2[0] = -axis2[0]; + axis2[1] = -axis2[1]; + axis2[2] = -axis2[2]; + } + dReal q[3]; + for (i=0; i<3; i++) q[i] = pos1[i]-pos2[i]; + dReal k = dDOT (axis1,q); + dReal a1lo = -lz1; + dReal a1hi = lz1; + dReal a2lo = -lz2 - k; + dReal a2hi = lz2 - k; + dReal lo = (a1lo > a2lo) ? a1lo : a2lo; + dReal hi = (a1hi < a2hi) ? a1hi : a2hi; + if (lo <= hi) { + int num_contacts = flags & NUMC_MASK; + if (num_contacts >= 2 && lo < hi) { + // generate up to two contacts. if one of those contacts is + // not made, fall back on the one-contact strategy. + for (i=0; i<3; i++) sphere1[i] = pos1[i] + lo*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + (lo+k)*axis2[i]; + int n1 = dCollideSpheres (sphere1,cyl1->radius, + sphere2,cyl2->radius,contact); + if (n1) { + for (i=0; i<3; i++) sphere1[i] = pos1[i] + hi*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + (hi+k)*axis2[i]; + dContactGeom *c2 = CONTACT(contact,skip); + int n2 = dCollideSpheres (sphere1,cyl1->radius, + sphere2,cyl2->radius, c2); + if (n2) { + c2->g1 = o1; + c2->g2 = o2; + return 2; + } + } + } + + // just one contact to generate, so put it in the middle of + // the range + dReal alpha1 = (lo + hi) * REAL(0.5); + dReal alpha2 = alpha1 + k; + for (i=0; i<3; i++) sphere1[i] = pos1[i] + alpha1*axis1[i]; + for (i=0; i<3; i++) sphere2[i] = pos2[i] + alpha2*axis2[i]; + return dCollideSpheres (sphere1,cyl1->radius, + sphere2,cyl2->radius,contact); + } + } + + // use the closest point algorithm + dVector3 a1,a2,b1,b2; + a1[0] = o1->pos[0] + axis1[0]*lz1; + a1[1] = o1->pos[1] + axis1[1]*lz1; + a1[2] = o1->pos[2] + axis1[2]*lz1; + a2[0] = o1->pos[0] - axis1[0]*lz1; + a2[1] = o1->pos[1] - axis1[1]*lz1; + a2[2] = o1->pos[2] - axis1[2]*lz1; + b1[0] = o2->pos[0] + axis2[0]*lz2; + b1[1] = o2->pos[1] + axis2[1]*lz2; + b1[2] = o2->pos[2] + axis2[2]*lz2; + b2[0] = o2->pos[0] - axis2[0]*lz2; + b2[1] = o2->pos[1] - axis2[1]*lz2; + b2[2] = o2->pos[2] - axis2[2]*lz2; + + dClosestLineSegmentPoints (a1,a2,b1,b2,sphere1,sphere2); + return dCollideSpheres (sphere1,cyl1->radius,sphere2,cyl2->radius,contact); +} + + +int dCollideCCylinderPlane (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dCCylinderClass); + dIASSERT (o2->type == dPlaneClass); + dxCCylinder *ccyl = (dxCCylinder*) o1; + dxPlane *plane = (dxPlane*) o2; + + // collide the deepest capping sphere with the plane + dReal sign = (dDOT14 (plane->p,o1->R+2) > 0) ? REAL(-1.0) : REAL(1.0); + dVector3 p; + p[0] = o1->pos[0] + o1->R[2] * ccyl->lz * REAL(0.5) * sign; + p[1] = o1->pos[1] + o1->R[6] * ccyl->lz * REAL(0.5) * sign; + p[2] = o1->pos[2] + o1->R[10] * ccyl->lz * REAL(0.5) * sign; + + dReal k = dDOT (p,plane->p); + dReal depth = plane->p[3] - k + ccyl->radius; + if (depth < 0) return 0; + contact->normal[0] = plane->p[0]; + contact->normal[1] = plane->p[1]; + contact->normal[2] = plane->p[2]; + contact->pos[0] = p[0] - plane->p[0] * ccyl->radius; + contact->pos[1] = p[1] - plane->p[1] * ccyl->radius; + contact->pos[2] = p[2] - plane->p[2] * ccyl->radius; + contact->depth = depth; + + int ncontacts = 1; + if ((flags & NUMC_MASK) >= 2) { + // collide the other capping sphere with the plane + p[0] = o1->pos[0] - o1->R[2] * ccyl->lz * REAL(0.5) * sign; + p[1] = o1->pos[1] - o1->R[6] * ccyl->lz * REAL(0.5) * sign; + p[2] = o1->pos[2] - o1->R[10] * ccyl->lz * REAL(0.5) * sign; + + k = dDOT (p,plane->p); + depth = plane->p[3] - k + ccyl->radius; + if (depth >= 0) { + dContactGeom *c2 = CONTACT(contact,skip); + c2->normal[0] = plane->p[0]; + c2->normal[1] = plane->p[1]; + c2->normal[2] = plane->p[2]; + c2->pos[0] = p[0] - plane->p[0] * ccyl->radius; + c2->pos[1] = p[1] - plane->p[1] * ccyl->radius; + c2->pos[2] = p[2] - plane->p[2] * ccyl->radius; + c2->depth = depth; + ncontacts = 2; + } + } + + for (int i=0; i < ncontacts; i++) { + CONTACT(contact,i*skip)->g1 = o1; + CONTACT(contact,i*skip)->g2 = o2; + } + return ncontacts; +} + + +// if mode==1 then use the sphere exit contact, not the entry contact + +static int ray_sphere_helper (dxRay *ray, dVector3 sphere_pos, dReal radius, + dContactGeom *contact, int mode) +{ + dVector3 q; + q[0] = ray->pos[0] - sphere_pos[0]; + q[1] = ray->pos[1] - sphere_pos[1]; + q[2] = ray->pos[2] - sphere_pos[2]; + dReal B = dDOT14(q,ray->R+2); + dReal C = dDOT(q,q) - radius*radius; + // note: if C <= 0 then the start of the ray is inside the sphere + dReal k = B*B - C; + if (k < 0) return 0; + k = dSqrt(k); + dReal alpha; + if (mode && C >= 0) { + alpha = -B + k; + if (alpha < 0) return 0; + } + else { + alpha = -B - k; + if (alpha < 0) { + alpha = -B + k; + if (alpha < 0) return 0; + } + } + if (alpha > ray->length) return 0; + contact->pos[0] = ray->pos[0] + alpha*ray->R[0*4+2]; + contact->pos[1] = ray->pos[1] + alpha*ray->R[1*4+2]; + contact->pos[2] = ray->pos[2] + alpha*ray->R[2*4+2]; + dReal nsign = (C < 0 || mode) ? REAL(-1.0) : REAL(1.0); + contact->normal[0] = nsign*(contact->pos[0] - sphere_pos[0]); + contact->normal[1] = nsign*(contact->pos[1] - sphere_pos[1]); + contact->normal[2] = nsign*(contact->pos[2] - sphere_pos[2]); + dNormalize3 (contact->normal); + contact->depth = alpha; + return 1; +} + + +int dCollideRaySphere (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dRayClass); + dIASSERT (o2->type == dSphereClass); + dxRay *ray = (dxRay*) o1; + dxSphere *sphere = (dxSphere*) o2; + contact->g1 = ray; + contact->g2 = sphere; + return ray_sphere_helper (ray,sphere->pos,sphere->radius,contact,0); +} + + +int dCollideRayBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dRayClass); + dIASSERT (o2->type == dBoxClass); + dxRay *ray = (dxRay*) o1; + dxBox *box = (dxBox*) o2; + + contact->g1 = ray; + contact->g2 = box; + + int i; + + // compute the start and delta of the ray relative to the box. + // we will do all subsequent computations in this box-relative coordinate + // system. we have to do a translation and rotation for each point. + dVector3 tmp,s,v; + tmp[0] = ray->pos[0] - box->pos[0]; + tmp[1] = ray->pos[1] - box->pos[1]; + tmp[2] = ray->pos[2] - box->pos[2]; + dMULTIPLY1_331 (s,box->R,tmp); + tmp[0] = ray->R[0*4+2]; + tmp[1] = ray->R[1*4+2]; + tmp[2] = ray->R[2*4+2]; + dMULTIPLY1_331 (v,box->R,tmp); + + // mirror the line so that v has all components >= 0 + dVector3 sign; + for (i=0; i<3; i++) { + if (v[i] < 0) { + s[i] = -s[i]; + v[i] = -v[i]; + sign[i] = 1; + } + else sign[i] = -1; + } + + // compute the half-sides of the box + dReal h[3]; + h[0] = REAL(0.5) * box->side[0]; + h[1] = REAL(0.5) * box->side[1]; + h[2] = REAL(0.5) * box->side[2]; + + // do a few early exit tests + if ((s[0] < -h[0] && v[0] <= 0) || s[0] > h[0] || + (s[1] < -h[1] && v[1] <= 0) || s[1] > h[1] || + (s[2] < -h[2] && v[2] <= 0) || s[2] > h[2] || + (v[0] == 0 && v[1] == 0 && v[2] == 0)) { + return 0; + } + + // compute the t=[lo..hi] range for where s+v*t intersects the box + dReal lo = -dInfinity; + dReal hi = dInfinity; + int nlo = 0, nhi = 0; + for (i=0; i<3; i++) { + if (v[i] != 0) { + dReal k = (-h[i] - s[i])/v[i]; + if (k > lo) { + lo = k; + nlo = i; + } + k = (h[i] - s[i])/v[i]; + if (k < hi) { + hi = k; + nhi = i; + } + } + } + + // check if the ray intersects + if (lo > hi) return 0; + dReal alpha; + int n; + if (lo >= 0) { + alpha = lo; + n = nlo; + } + else { + alpha = hi; + n = nhi; + } + if (alpha < 0 || alpha > ray->length) return 0; + contact->pos[0] = ray->pos[0] + alpha*ray->R[0*4+2]; + contact->pos[1] = ray->pos[1] + alpha*ray->R[1*4+2]; + contact->pos[2] = ray->pos[2] + alpha*ray->R[2*4+2]; + contact->normal[0] = box->R[0*4+n] * sign[n]; + contact->normal[1] = box->R[1*4+n] * sign[n]; + contact->normal[2] = box->R[2*4+n] * sign[n]; + contact->depth = alpha; + return 1; +} + + +int dCollideRayCCylinder (dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dRayClass); + dIASSERT (o2->type == dCCylinderClass); + dxRay *ray = (dxRay*) o1; + dxCCylinder *ccyl = (dxCCylinder*) o2; + + contact->g1 = ray; + contact->g2 = ccyl; + dReal lz2 = ccyl->lz * REAL(0.5); + + // compute some useful info + dVector3 cs,q,r; + dReal C,k; + cs[0] = ray->pos[0] - ccyl->pos[0]; + cs[1] = ray->pos[1] - ccyl->pos[1]; + cs[2] = ray->pos[2] - ccyl->pos[2]; + k = dDOT41(ccyl->R+2,cs); // position of ray start along ccyl axis + q[0] = k*ccyl->R[0*4+2] - cs[0]; + q[1] = k*ccyl->R[1*4+2] - cs[1]; + q[2] = k*ccyl->R[2*4+2] - cs[2]; + C = dDOT(q,q) - ccyl->radius*ccyl->radius; + // if C < 0 then ray start position within infinite extension of cylinder + + // see if ray start position is inside the capped cylinder + int inside_ccyl = 0; + if (C < 0) { + if (k < -lz2) k = -lz2; + else if (k > lz2) k = lz2; + r[0] = ccyl->pos[0] + k*ccyl->R[0*4+2]; + r[1] = ccyl->pos[1] + k*ccyl->R[1*4+2]; + r[2] = ccyl->pos[2] + k*ccyl->R[2*4+2]; + if ((ray->pos[0]-r[0])*(ray->pos[0]-r[0]) + + (ray->pos[1]-r[1])*(ray->pos[1]-r[1]) + + (ray->pos[2]-r[2])*(ray->pos[2]-r[2]) < ccyl->radius*ccyl->radius) { + inside_ccyl = 1; + } + } + + // compute ray collision with infinite cylinder, except for the case where + // the ray is outside the capped cylinder but within the infinite cylinder + // (it that case the ray can only hit endcaps) + if (!inside_ccyl && C < 0) { + // set k to cap position to check + if (k < 0) k = -lz2; else k = lz2; + } + else { + dReal uv = dDOT44(ccyl->R+2,ray->R+2); + r[0] = uv*ccyl->R[0*4+2] - ray->R[0*4+2]; + r[1] = uv*ccyl->R[1*4+2] - ray->R[1*4+2]; + r[2] = uv*ccyl->R[2*4+2] - ray->R[2*4+2]; + dReal A = dDOT(r,r); + dReal B = 2*dDOT(q,r); + k = B*B-4*A*C; + if (k < 0) { + // the ray does not intersect the infinite cylinder, but if the ray is + // inside and parallel to the cylinder axis it may intersect the end + // caps. set k to cap position to check. + if (!inside_ccyl) return 0; + if (uv < 0) k = -lz2; else k = lz2; + } + else { + k = dSqrt(k); + A = dRecip (2*A); + dReal alpha = (-B-k)*A; + if (alpha < 0) { + alpha = (-B+k)*A; + if (alpha < 0) return 0; + } + if (alpha > ray->length) return 0; + + // the ray intersects the infinite cylinder. check to see if the + // intersection point is between the caps + contact->pos[0] = ray->pos[0] + alpha*ray->R[0*4+2]; + contact->pos[1] = ray->pos[1] + alpha*ray->R[1*4+2]; + contact->pos[2] = ray->pos[2] + alpha*ray->R[2*4+2]; + q[0] = contact->pos[0] - ccyl->pos[0]; + q[1] = contact->pos[1] - ccyl->pos[1]; + q[2] = contact->pos[2] - ccyl->pos[2]; + k = dDOT14(q,ccyl->R+2); + dReal nsign = inside_ccyl ? REAL(-1.0) : REAL(1.0); + if (k >= -lz2 && k <= lz2) { + contact->normal[0] = nsign * (contact->pos[0] - + (ccyl->pos[0] + k*ccyl->R[0*4+2])); + contact->normal[1] = nsign * (contact->pos[1] - + (ccyl->pos[1] + k*ccyl->R[1*4+2])); + contact->normal[2] = nsign * (contact->pos[2] - + (ccyl->pos[2] + k*ccyl->R[2*4+2])); + dNormalize3 (contact->normal); + contact->depth = alpha; + return 1; + } + + // the infinite cylinder intersection point is not between the caps. + // set k to cap position to check. + if (k < 0) k = -lz2; else k = lz2; + } + } + + // check for ray intersection with the caps. k must indicate the cap + // position to check + q[0] = ccyl->pos[0] + k*ccyl->R[0*4+2]; + q[1] = ccyl->pos[1] + k*ccyl->R[1*4+2]; + q[2] = ccyl->pos[2] + k*ccyl->R[2*4+2]; + return ray_sphere_helper (ray,q,ccyl->radius,contact, inside_ccyl); +} + + +int dCollideRayPlane (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dRayClass); + dIASSERT (o2->type == dPlaneClass); + dxRay *ray = (dxRay*) o1; + dxPlane *plane = (dxPlane*) o2; + + dReal alpha = plane->p[3] - dDOT (plane->p,ray->pos); + // note: if alpha > 0 the starting point is below the plane + dReal nsign = (alpha > 0) ? REAL(-1.0) : REAL(1.0); + dReal k = dDOT14(plane->p,ray->R+2); + if (k==0) return 0; // ray parallel to plane + alpha /= k; + if (alpha < 0 || alpha > ray->length) return 0; + contact->pos[0] = ray->pos[0] + alpha*ray->R[0*4+2]; + contact->pos[1] = ray->pos[1] + alpha*ray->R[1*4+2]; + contact->pos[2] = ray->pos[2] + alpha*ray->R[2*4+2]; + contact->normal[0] = nsign*plane->p[0]; + contact->normal[1] = nsign*plane->p[1]; + contact->normal[2] = nsign*plane->p[2]; + contact->depth = alpha; + contact->g1 = ray; + contact->g2 = plane; + return 1; +} + +//// CYLINDER CODE ADDED +//**************************************************************************** +// flat cylinder public API + +dxCylinder::dxCylinder (dSpaceID space, dReal _radius, dReal _length) : +dxGeom (space,1) +{ + dAASSERT (_radius > 0 && _length > 0); + type = dCylinderClass; + radius = _radius; + lz = _length; +} + + +void dxCylinder::computeAABB() +{ + dReal xrange = dFabs (R[0] * radius) + dFabs (R[1] * radius) + REAL(0.5)* dFabs (R[2] * + lz); + dReal yrange = dFabs (R[4] * radius) + dFabs (R[5] * radius) + REAL(0.5)* dFabs (R[6] * + lz); + dReal zrange = dFabs (R[8] * radius) + dFabs (R[9] * radius) + REAL(0.5)* dFabs (R[10] * + lz); + aabb[0] = pos[0] - xrange; + aabb[1] = pos[0] + xrange; + aabb[2] = pos[1] - yrange; + aabb[3] = pos[1] + yrange; + aabb[4] = pos[2] - zrange; + aabb[5] = pos[2] + zrange; +} + + +dGeomID dCreateCylinder (dSpaceID space, dReal radius, dReal length) +{ + return new dxCylinder (space,radius,length); +} + +void dGeomCylinderSetParams (dGeomID cylinder, dReal radius, dReal length) +{ + dUASSERT (cylinder && cylinder->type == dCylinderClass,"argument not a ccylinder"); + dAASSERT (radius > 0 && length > 0); + dxCylinder *c = (dxCylinder*) cylinder; + c->radius = radius; + c->lz = length; + dGeomMoved (cylinder); +} + +void dGeomCylinderGetParams (dGeomID cylinder, dReal *radius, dReal *length) +{ + dUASSERT (cylinder && cylinder->type == dCylinderClass,"argument not a ccylinder"); + dxCylinder *c = (dxCylinder*) cylinder; + *radius = c->radius; + *length = c->lz; +} + +// int dCollideCylinderPlane(dxGeom *o1, dxGeom *o2, int flags,dContactGeom *contact, int skip) +// { +// dIASSERT (skip >= (int)sizeof(dContactGeom)); +// dIASSERT (dGeomGetClass(o1) == dCylinderClass); +// dIASSERT (dGeomGetClass(o2) == dPlaneClass); +// contact->g1 = const_cast (o1); +// contact->g2 = const_cast (o2); + +// int ret = 0; + +// dReal radius; +// dReal hlz; +// dGeomCylinderGetParams(o1,&radius,&hlz); +// hlz /= 2; + +// const dReal *R2 = dGeomGetRotation(o1);// rotation of cylinder +// dMatrix3 R; +// for (int j = 0; j < 12;j++) +// R[j] = R2[j]; + +// //rotate R about its own axis +// //dMatrix3 R3; +// //dRFromAxisAndAngle (R3,R2[0],R2[1],R2[2],180); +// //dRFromAxisAndAngle (R3,0,0,1,0); +// //dMultiply0 (R,R2,R3,3,3,3); + + +// //to make this cylinder code work here we just rotate it 90 degrees +// dReal tmp[3]; +// tmp[0] = R[4]; +// tmp[1] = R[5]; +// tmp[2] = R[6]; +// R[4] = R[8]; +// R[5] = R[9]; +// R[6] = R[10]; +// R[8] = tmp[0]; +// R[9] = tmp[1]; +// R[10] = tmp[2]; +// // R[0] *= -1; +// // R[1] *= -1; +// // R[2] *= -1; + +// const dReal* p = dGeomGetPosition(o1); +// dVector4 n; // normal vector +// dReal pp; +// dGeomPlaneGetParams (o2, n); +// pp=n[3]; +// dReal cos1,sin1; +// cos1=dFabs(dDOT14(n,R+1)); + +// cos1=cos10 ? hlz*R[1]:-hlz*R[1]; +// pos[1]-= A2>0 ? hlz*R[5]:-hlz*R[5]; +// pos[2]-= A2>0 ? hlz*R[9]:-hlz*R[9]; + +// contact->pos[0] = pos[0]; +// contact->pos[1] = pos[1]; +// contact->pos[2] = pos[2]; +// contact->depth = outDepth; +// ret=1; + +// if(dFabs(Q2)>M_SQRT1_2){ + +// if (ret <= (flags & NUMC_MASK)){ + +// CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A1*R[0]; +// CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A1*R[4]; +// CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A1*R[8]; +// CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q1*2.f*A1); + +// if(CONTACT(contact,ret*skip)->depth>0.f) +// ret++; +// } + +// if (ret <= (flags & NUMC_MASK)){ + +// CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*A3*R[2]; +// CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*A3*R[6]; +// CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*A3*R[10]; +// CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q3*2.f*A3); + +// if(CONTACT(contact,ret*skip)->depth>0.f) ret++; +// } + +// } else { + +// if (ret <= (flags & NUMC_MASK)){ + +// CONTACT(contact,ret*skip)->pos[0]=pos[0]+2.f*(A2>0 ? hlz*R[1]:-hlz*R[1]); +// CONTACT(contact,ret*skip)->pos[1]=pos[1]+2.f*(A2>0 ? hlz*R[5]:-hlz*R[5]); +// CONTACT(contact,ret*skip)->pos[2]=pos[2]+2.f*(A2>0 ? hlz*R[9]:-hlz*R[9]); +// CONTACT(contact,ret*skip)->depth=outDepth-dFabs(Q2*2.f*A2); + +// if(CONTACT(contact,ret*skip)->depth>0.f) ret++; +// } + +// } +// for (int i=0; ig1 = const_cast (o1); +// CONTACT(contact,i*skip)->g2 = const_cast (o2); +// CONTACT(contact,i*skip)->normal[0] =n[0]; +// CONTACT(contact,i*skip)->normal[1] =n[1]; +// CONTACT(contact,i*skip)->normal[2] =n[2]; +// } +// return ret; +// } diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_std.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_std.h new file mode 100644 index 00000000..fef64e76 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_std.h @@ -0,0 +1,79 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +the standard ODE geometry primitives. + +*/ + +#ifndef _ODE_COLLISION_STD_H_ +#define _ODE_COLLISION_STD_H_ + +#include "ode/ode_common.h" +#include "ode/ode_collision_kernel.h" + + +// primitive collision functions - these have the dColliderFn interface, i.e. +// the same interface as dCollide(). the first and second geom arguments must +// have the specified types. + +int dCollideSphereSphere (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideSphereBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideSpherePlane (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideBoxBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideBoxPlane (dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip); +int dCollideCCylinderSphere (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideCCylinderBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideCCylinderCCylinder (dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip); +int dCollideCCylinderPlane (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideRaySphere (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideRayBox (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); +int dCollideRayCCylinder (dxGeom *o1, dxGeom *o2, + int flags, dContactGeom *contact, int skip); +int dCollideRayPlane (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); + +// Cylinder - Box by (C) CroTeam +// Ported by Nguyen Binh +int dCollideCylinderBox(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); + +// Cylinder - Sphere (C) by CroTeam +// Ported by Nguyen Binh +int dCollideCylinderSphere(dxGeom *gCylinder, dxGeom *gSphere, int flags, dContactGeom + *contact, int skip); + +int dCollideCylinderPlane(dxGeom *gCylinder, dxGeom *gSphere, int flags, dContactGeom + *contact, int skip); + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_transform.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_transform.cpp new file mode 100644 index 00000000..2853e3db --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_transform.cpp @@ -0,0 +1,235 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +geom transform + +*/ + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_transform.h" +#include "ode/ode_collision_util.h" + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +//**************************************************************************** +// dxGeomTransform class + +struct dxGeomTransform : public dxGeom { + dxGeom *obj; // object that is being transformed + int cleanup; // 1 to destroy obj when destroyed + int infomode; // 1 to put Tx geom in dContactGeom g1 + + // cached final object transform (body tx + relative tx). this is set by + // computeAABB(), and it is valid while the AABB is valid. + dVector3 final_pos; + dMatrix3 final_R; + + dxGeomTransform (dSpaceID space); + ~dxGeomTransform(); + void computeAABB(); + void computeFinalTx(); +}; + + +dxGeomTransform::dxGeomTransform (dSpaceID space) : dxGeom (space,1) +{ + type = dGeomTransformClass; + obj = 0; + cleanup = 0; + infomode = 0; + dSetZero (final_pos,4); + dRSetIdentity (final_R); +} + + +dxGeomTransform::~dxGeomTransform() +{ + if (obj && cleanup) delete obj; +} + + +void dxGeomTransform::computeAABB() +{ + if (!obj) { + dSetZero (aabb,6); + return; + } + + // backup the relative pos and R pointers of the encapsulated geom object + dReal *posbak = obj->pos; + dReal *Rbak = obj->R; + + // compute temporary pos and R for the encapsulated geom object + computeFinalTx(); + obj->pos = final_pos; + obj->R = final_R; + + // compute the AABB + obj->computeAABB(); + memcpy (aabb,obj->aabb,6*sizeof(dReal)); + + // restore the pos and R + obj->pos = posbak; + obj->R = Rbak; +} + + +// utility function for dCollideTransform() : compute final pos and R +// for the encapsulated geom object + +void dxGeomTransform::computeFinalTx() +{ + dMULTIPLY0_331 (final_pos,R,obj->pos); + final_pos[0] += pos[0]; + final_pos[1] += pos[1]; + final_pos[2] += pos[2]; + dMULTIPLY0_333 (final_R,R,obj->R); +} + +//**************************************************************************** +// collider function: +// this collides a transformed geom with another geom. the other geom can +// also be a transformed geom, but this case is not handled specially. + +int dCollideTransform (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip) +{ + dIASSERT (skip >= (int)sizeof(dContactGeom)); + dIASSERT (o1->type == dGeomTransformClass); + + dxGeomTransform *tr = (dxGeomTransform*) o1; + if (!tr->obj) return 0; + dUASSERT (tr->obj->parent_space==0, + "GeomTransform encapsulated object must not be in a space"); + dUASSERT (tr->obj->body==0, + "GeomTransform encapsulated object must not be attached " + "to a body"); + + // backup the relative pos and R pointers of the encapsulated geom object, + // and the body pointer + dReal *posbak = tr->obj->pos; + dReal *Rbak = tr->obj->R; + dxBody *bodybak = tr->obj->body; + + // compute temporary pos and R for the encapsulated geom object. + // note that final_pos and final_R are valid if no GEOM_AABB_BAD flag, + // because computeFinalTx() will have already been called in + // dxGeomTransform::computeAABB() + + if (tr->gflags & GEOM_AABB_BAD) tr->computeFinalTx(); + tr->obj->pos = tr->final_pos; + tr->obj->R = tr->final_R; + tr->obj->body = o1->body; + + // do the collision + int n = dCollide (tr->obj,o2,flags,contact,skip); + + // if required, adjust the 'g1' values in the generated contacts so that + // thay indicated the GeomTransform object instead of the encapsulated + // object. + if (tr->infomode) { + for (int i=0; ig1 = o1; + } + } + + // restore the pos, R and body + tr->obj->pos = posbak; + tr->obj->R = Rbak; + tr->obj->body = bodybak; + return n; +} + +//**************************************************************************** +// public API + +dGeomID dCreateGeomTransform (dSpaceID space) +{ + return new dxGeomTransform (space); +} + + +void dGeomTransformSetGeom (dGeomID g, dGeomID obj) +{ + dUASSERT (g && g->type == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) g; + if (tr->obj && tr->cleanup) delete tr->obj; + tr->obj = obj; +} + + +dGeomID dGeomTransformGetGeom (dGeomID g) +{ + dUASSERT (g && g->type == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) g; + return tr->obj; +} + + +void dGeomTransformSetCleanup (dGeomID g, int mode) +{ + dUASSERT (g && g->type == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) g; + tr->cleanup = mode; +} + + +int dGeomTransformGetCleanup (dGeomID g) +{ + dUASSERT (g && g->type == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) g; + return tr->cleanup; +} + + +void dGeomTransformSetInfo (dGeomID g, int mode) +{ + dUASSERT (g && g->type == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) g; + tr->infomode = mode; +} + + +int dGeomTransformGetInfo (dGeomID g) +{ + dUASSERT (g && g->type == dGeomTransformClass, + "argument not a geom transform"); + dxGeomTransform *tr = (dxGeomTransform*) g; + return tr->infomode; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_transform.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_transform.h new file mode 100644 index 00000000..0c65b0f7 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_transform.h @@ -0,0 +1,40 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +geom transform + +*/ + +#ifndef _ODE_COLLISION_TRANSFORM_H_ +#define _ODE_COLLISION_TRANSFORM_H_ + +#include "ode/ode_common.h" +#include "ode/ode_collision_kernel.h" + + +int dCollideTransform (dxGeom *o1, dxGeom *o2, int flags, + dContactGeom *contact, int skip); + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.cpp new file mode 100644 index 00000000..161f3dac --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.cpp @@ -0,0 +1,547 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +// TriMesh code by Erwin de Vries. + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +// Trimesh data +dxTriMeshData::dxTriMeshData(){ +#ifndef dTRIMESH_ENABLED + dUASSERT(g, "dTRIMESH_ENABLED is not defined. Trimesh geoms will not work"); +#endif +} + +dxTriMeshData::~dxTriMeshData(){ + // +} + +void +dxTriMeshData::Build(const void* Vertices, int VertexStide, int VertexCount, + const void* Indices, int IndexCount, int TriStride, + const void* in_Normals, + bool Single){ + Mesh.SetNbTriangles(IndexCount / 3); + Mesh.SetNbVertices(VertexCount); + Mesh.SetPointers((IndexedTriangle*)Indices, (Point*)Vertices); + Mesh.SetStrides(TriStride, VertexStide); + Mesh.Single = Single; + + // Build tree + BuildSettings Settings; + // recommended in Opcode User Manual + //Settings.mRules = SPLIT_COMPLETE | SPLIT_SPLATTERPOINTS | SPLIT_GEOMCENTER; + // used in ODE, why? + //Settings.mRules = SPLIT_BEST_AXIS; + + // best compromise? + Settings.mRules = SPLIT_BEST_AXIS | SPLIT_SPLATTER_POINTS | SPLIT_GEOM_CENTER; + + + OPCODECREATE TreeBuilder; + TreeBuilder.mIMesh = &Mesh; + + TreeBuilder.mSettings = Settings; + TreeBuilder.mNoLeaf = true; + TreeBuilder.mQuantized = false; + + TreeBuilder.mKeepOriginal = false; + TreeBuilder.mCanRemap = false; + + + + BVTree.Build(TreeBuilder); + + // compute model space AABB + dVector3 AABBMax, AABBMin; + AABBMax[0] = AABBMax[1] = AABBMax[2] = (dReal) -dInfinity; + AABBMin[0] = AABBMin[1] = AABBMin[2] = (dReal) dInfinity; + if( Single ) { + const char* verts = (const char*)Vertices; + for( int i = 0; i < VertexCount; ++i ) { + const float* v = (const float*)verts; + if( v[0] > AABBMax[0] ) AABBMax[0] = v[0]; + if( v[1] > AABBMax[1] ) AABBMax[1] = v[1]; + if( v[2] > AABBMax[2] ) AABBMax[2] = v[2]; + if( v[0] < AABBMin[0] ) AABBMin[0] = v[0]; + if( v[1] < AABBMin[1] ) AABBMin[1] = v[1]; + if( v[2] < AABBMin[2] ) AABBMin[2] = v[2]; + verts += VertexStide; + } + } else { + const char* verts = (const char*)Vertices; + for( int i = 0; i < VertexCount; ++i ) { + const double* v = (const double*)verts; + if( v[0] > AABBMax[0] ) AABBMax[0] = (dReal) v[0]; + if( v[1] > AABBMax[1] ) AABBMax[1] = (dReal) v[1]; + if( v[2] > AABBMax[2] ) AABBMax[2] = (dReal) v[2]; + if( v[0] < AABBMin[0] ) AABBMin[0] = (dReal) v[0]; + if( v[1] < AABBMin[1] ) AABBMin[1] = (dReal) v[1]; + if( v[2] < AABBMin[2] ) AABBMin[2] = (dReal) v[2]; + verts += VertexStide; + } + } + AABBCenter[0] = (AABBMin[0] + AABBMax[0]) * REAL(0.5); + AABBCenter[1] = (AABBMin[1] + AABBMax[1]) * REAL(0.5); + AABBCenter[2] = (AABBMin[2] + AABBMax[2]) * REAL(0.5); + AABBExtents[0] = AABBMax[0] - AABBCenter[0]; + AABBExtents[1] = AABBMax[1] - AABBCenter[1]; + AABBExtents[2] = AABBMax[2] - AABBCenter[2]; + + // user data (not used by OPCODE) + for (int i=0; i<16; i++) + last_trans[i] = 0.0; + + Normals = (dReal *) in_Normals; +} + +dTriMeshDataID dGeomTriMeshDataCreate(){ + return new dxTriMeshData(); +} + +void dGeomTriMeshDataDestroy(dTriMeshDataID g){ + delete g; +} + +void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data) +{ + dUASSERT(g, "argument not trimesh data"); + + double *elem; + + switch (data_id) { + case TRIMESH_FACE_NORMALS: + g->Normals = (dReal *) in_data; + break; + + case TRIMESH_LAST_TRANSFORMATION: + elem = (double *) in_data; + for (int i=0; i<16; i++) + g->last_trans[i] = (dReal) elem[i]; + + break; + default: + dUASSERT(data_id, "invalid data type"); + break; + } + + return; +} + + + +void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id) +{ + dUASSERT(g, "argument not trimesh data"); + + switch (data_id) { + case TRIMESH_FACE_NORMALS: + return (void *) g->Normals; + break; + + case TRIMESH_LAST_TRANSFORMATION: + return (void *) g->last_trans; + break; + default: + dUASSERT(data_id, "invalid data type"); + break; +} + + return NULL; +} + + +void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride, + const void* Normals) +{ + dUASSERT(g, "argument not trimesh data"); + + g->Build(Vertices, VertexStride, VertexCount, + Indices, IndexCount, TriStride, + Normals, + true); +} + + +void dGeomTriMeshDataBuildSingle(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride) +{ + dGeomTriMeshDataBuildSingle1(g, Vertices, VertexStride, VertexCount, + Indices, IndexCount, TriStride, (void*)NULL); +} + + +void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride, + const void* Normals){ + dUASSERT(g, "argument not trimesh data"); + + g->Build(Vertices, VertexStride, VertexCount, + Indices, IndexCount, TriStride, + Normals, + false); +} + + +void dGeomTriMeshDataBuildDouble(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride) { + dGeomTriMeshDataBuildDouble1(g, Vertices, VertexStride, VertexCount, + Indices, IndexCount, TriStride, NULL); +} + + +void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g, + const dReal* Vertices, int VertexCount, + const int* Indices, int IndexCount, + const int* Normals){ +#ifdef dSINGLE + dGeomTriMeshDataBuildSingle1(g, + Vertices, 4 * sizeof(dReal), VertexCount, + Indices, IndexCount, 3 * sizeof(unsigned int), + Normals); +#else + dGeomTriMeshDataBuildDouble1(g, Vertices, 4 * sizeof(dReal), VertexCount, + Indices, IndexCount, 3 * sizeof(unsigned int), + Normals); +#endif +} + + +void dGeomTriMeshDataBuildSimple(dTriMeshDataID g, + const dReal* Vertices, int VertexCount, + const int* Indices, int IndexCount) { + dGeomTriMeshDataBuildSimple1(g, + Vertices, VertexCount, Indices, IndexCount, + (const int*)NULL); +} + + +// Trimesh +PlanesCollider dxTriMesh::_PlanesCollider; +SphereCollider dxTriMesh::_SphereCollider; +//OBBCollider dxTriMesh::_OBBCollider; +RayCollider dxTriMesh::_RayCollider; +AABBTreeCollider dxTriMesh::_AABBTreeCollider; +LSSCollider dxTriMesh::_LSSCollider; + +SphereCache dxTriMesh::defaultSphereCache; +//OBBCache dxTriMesh::defaultBoxCache; +LSSCache dxTriMesh::defaultCCylinderCache; + +CollisionFaces dxTriMesh::Faces; + +dxTriMesh::dxTriMesh(dSpaceID Space, dTriMeshDataID Data) : dxGeom(Space, 1){ + type = dTriMeshClass; + + this->Data = Data; + + _RayCollider.SetDestination(&Faces); + + _PlanesCollider.SetTemporalCoherence(true); + + _SphereCollider.SetTemporalCoherence(true); + _SphereCollider.SetPrimitiveTests(false); + + + _OBBCollider.SetTemporalCoherence(true); + + // no first-contact test (i.e. return full contact info) + _AABBTreeCollider.SetFirstContact( false ); + // temporal coherence only works with "first conact" tests + _AABBTreeCollider.SetTemporalCoherence(false); + // Perform full BV-BV tests (true) or SAT-lite tests (false) + _AABBTreeCollider.SetFullBoxBoxTest( true ); + // Perform full Primitive-BV tests (true) or SAT-lite tests (false) + _AABBTreeCollider.SetFullPrimBoxTest( true ); + _LSSCollider.SetTemporalCoherence(false); + + /* TC has speed/space 'issues' that don't make it a clear + win by default on spheres/boxes. */ + this->doSphereTC = false; + this->doBoxTC = false; + this->doCCylinderTC = false; + + + this->forceNormalMode = false; + + const char* msg; + if ((msg =_AABBTreeCollider.ValidateSettings())) + dDebug (d_ERR_UASSERT, msg, " (%s:%d)", __FILE__,__LINE__); + _LSSCollider.SetPrimitiveTests(false); + _LSSCollider.SetFirstContact(false); +} + +dxTriMesh::~dxTriMesh(){ + // +} + + +void dxTriMesh::ClearTCCache(){ + /* dxTriMesh::ClearTCCache uses dArray's setSize(0) to clear the caches - + but the destructor isn't called when doing this, so we would leak. + So, call the previous caches' containers' destructors by hand first. */ + int i, n; + n = SphereTCCache.size(); + for( i = 0; i < n; ++i ) { + SphereTCCache[i].~SphereTC(); + } + SphereTCCache.setSize(0); + n = BoxTCCache.size(); + for( i = 0; i < n; ++i ) { + BoxTCCache[i].~BoxTC(); + } + BoxTCCache.setSize(0); + n = CCylinderTCCache.size(); + for( i = 0; i < n; ++i ) { + CCylinderTCCache[i].~CCylinderTC(); + } + CCylinderTCCache.setSize(0); +} + + +int dxTriMesh::AABBTest(dxGeom* g, dReal aabb[6]){ + return 1; +} + + +void dxTriMesh::computeAABB() { + const dxTriMeshData* d = Data; + dVector3 c; + + dMULTIPLY0_331( c, R, d->AABBCenter ); + + dReal xrange = dFabs(R[0] * Data->AABBExtents[0]) + + dFabs(R[1] * Data->AABBExtents[1]) + + dFabs(R[2] * Data->AABBExtents[2]); + dReal yrange = dFabs(R[4] * Data->AABBExtents[0]) + + dFabs(R[5] * Data->AABBExtents[1]) + + dFabs(R[6] * Data->AABBExtents[2]); + dReal zrange = dFabs(R[8] * Data->AABBExtents[0]) + + dFabs(R[9] * Data->AABBExtents[1]) + + dFabs(R[10] * Data->AABBExtents[2]); + + aabb[0] = c[0] + pos[0] - xrange; + aabb[1] = c[0] + pos[0] + xrange; + aabb[2] = c[1] + pos[1] - yrange; + aabb[3] = c[1] + pos[1] + yrange; + aabb[4] = c[2] + pos[2] - zrange; + aabb[5] = c[2] + pos[2] + zrange; +} + +dGeomID dCreateTriMesh(dSpaceID space, + dTriMeshDataID Data, + dTriCallback* Callback, + dTriArrayCallback* ArrayCallback, + dTriRayCallback* RayCallback) +{ + dxTriMesh* Geom = new dxTriMesh(space, Data); + Geom->Callback = Callback; + Geom->ArrayCallback = ArrayCallback; + Geom->RayCallback = RayCallback; + + return Geom; +} + +void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + ((dxTriMesh*)g)->Callback = Callback; +} + +dTriCallback* dGeomTriMeshGetCallback(dGeomID g) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + return ((dxTriMesh*)g)->Callback; +} + +void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + ((dxTriMesh*)g)->ArrayCallback = ArrayCallback; +} + +dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + return ((dxTriMesh*)g)->ArrayCallback; +} + +void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + ((dxTriMesh*)g)->RayCallback = Callback; +} + +dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + return ((dxTriMesh*)g)->RayCallback; +} + +void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + ((dxTriMesh*)g)->Data = Data; +} + +dTriMeshDataID dGeomTriMeshGetData(dGeomID g) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + return ((dxTriMesh*)g)->Data; +} + + + +void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + + switch (geomClass) + { + case dSphereClass: + ((dxTriMesh*)g)->doSphereTC = (1 == enable); + break; + case dBoxClass: + ((dxTriMesh*)g)->doBoxTC = (1 == enable); + break; + case dCCylinderClass: + ((dxTriMesh*)g)->doCCylinderTC = (1 == enable); + break; + } +} + +int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass) +{ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + + switch (geomClass) + { + case dSphereClass: + if (((dxTriMesh*)g)->doSphereTC) + return 1; + break; + case dBoxClass: + if (((dxTriMesh*)g)->doBoxTC) + return 1; + break; + case dCCylinderClass: + if (((dxTriMesh*)g)->doCCylinderTC) + return 1; + break; + } + return 0; +} + +void dGeomTriMeshClearTCCache(dGeomID g){ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + + dxTriMesh* Geom = (dxTriMesh*)g; + Geom->ClearTCCache(); +} + +void dGeomTriMeshSetForceNormalMode(dGeomID g, int enable){ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + + dxTriMesh* Geom = (dxTriMesh*)g; + Geom->setForceNormalMode(enable); +} + +/* + * returns the TriMeshDataID + */ +dTriMeshDataID +dGeomTriMeshGetTriMeshDataID(dGeomID g) +{ + dxTriMesh* Geom = (dxTriMesh*) g; + return Geom->Data; +} + +// Getting data +void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2){ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + + dxTriMesh* Geom = (dxTriMesh*)g; + + const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); + const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); + + dVector3 v[3]; + FetchTriangle(Geom, Index, Position, Rotation, v); + + if (v0){ + (*v0)[0] = v[0][0]; + (*v0)[1] = v[0][1]; + (*v0)[2] = v[0][2]; + (*v0)[3] = v[0][3]; + } + if (v1){ + (*v1)[0] = v[1][0]; + (*v1)[1] = v[1][1]; + (*v1)[2] = v[1][2]; + (*v1)[3] = v[1][3]; + } + if (v2){ + (*v2)[0] = v[2][0]; + (*v2)[1] = v[2][1]; + (*v2)[2] = v[2][2]; + (*v2)[3] = v[2][3]; + } +} + +void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out){ + dUASSERT(g && g->type == dTriMeshClass, "argument not a trimesh"); + + dxTriMesh* Geom = (dxTriMesh*)g; + + const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); + const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); + + dVector3 dv[3]; + FetchTriangle(Geom, Index, Position, Rotation, dv); + + GetPointFromBarycentric(dv, u, v, Out); +} + +int dGeomTriMeshGetTriangleCount (dGeomID g) +{ + dxTriMesh* Geom = (dxTriMesh*)g; + return Geom->Data->Mesh.GetNbTriangles(); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.h new file mode 100644 index 00000000..cf61aa55 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh.h @@ -0,0 +1,191 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + * TriMesh code by Erwin de Vries. + * + * Trimesh data. + * This is where the actual vertexdata (pointers), and BV tree is stored. + * Vertices should be single precision! + * This should be more sophisticated, so that the user can easyly implement + * another collision library, but this is a lot of work, and also costs some + * performance because some data has to be copied. + */ + +#ifndef _ODE_COLLISION_TRIMESH_H_ +#define _ODE_COLLISION_TRIMESH_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Data storage for triangle meshes. + */ +struct dxTriMeshData; +typedef struct dxTriMeshData* dTriMeshDataID; + +/* + * These dont make much sense now, but they will later when we add more + * features. + */ +dTriMeshDataID dGeomTriMeshDataCreate(void); +void dGeomTriMeshDataDestroy(dTriMeshDataID g); + +enum { TRIMESH_FACE_NORMALS, TRIMESH_LAST_TRANSFORMATION }; +void dGeomTriMeshDataSet(dTriMeshDataID g, int data_id, void* in_data); +void* dGeomTriMeshDataGet(dTriMeshDataID g, int data_id); + +/* + * Build TriMesh data with single pricision used in vertex data . + */ +void dGeomTriMeshDataBuildSingle(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride); +/* same again with a normals array (used as trimesh-trimesh optimization) */ +void dGeomTriMeshDataBuildSingle1(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride, + const void* Normals); +/* +* Build TriMesh data with double pricision used in vertex data . +*/ +void dGeomTriMeshDataBuildDouble(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride); +/* same again with a normals array (used as trimesh-trimesh optimization) */ +void dGeomTriMeshDataBuildDouble1(dTriMeshDataID g, + const void* Vertices, int VertexStride, int VertexCount, + const void* Indices, int IndexCount, int TriStride, + const void* Normals); + +/* + * Simple build. Single/double precision based on dSINGLE/dDOUBLE! + */ +void dGeomTriMeshDataBuildSimple(dTriMeshDataID g, + const dReal* Vertices, int VertexCount, + const int* Indices, int IndexCount); +/* same again with a normals array (used as trimesh-trimesh optimization) */ +void dGeomTriMeshDataBuildSimple1(dTriMeshDataID g, + const dReal* Vertices, int VertexCount, + const int* Indices, int IndexCount, + const int* Normals); +/* + * Per triangle callback. Allows the user to say if he wants a collision with + * a particular triangle. + */ +typedef int dTriCallback(dGeomID TriMesh, dGeomID RefObject, int TriangleIndex); +void dGeomTriMeshSetCallback(dGeomID g, dTriCallback* Callback); +dTriCallback* dGeomTriMeshGetCallback(dGeomID g); + +/* + * Per object callback. Allows the user to get the list of triangles in 1 + * shot. Maybe we should remove this one. + */ +typedef void dTriArrayCallback(dGeomID TriMesh, dGeomID RefObject, const int* TriIndices, int TriCount); +void dGeomTriMeshSetArrayCallback(dGeomID g, dTriArrayCallback* ArrayCallback); +dTriArrayCallback* dGeomTriMeshGetArrayCallback(dGeomID g); + +/* + * Ray callback. + * Allows the user to say if a ray collides with a triangle on barycentric + * coords. The user can for example sample a texture with alpha transparency + * to determine if a collision should occur. + */ +typedef int dTriRayCallback(dGeomID TriMesh, dGeomID Ray, int TriangleIndex, dReal u, dReal v); +void dGeomTriMeshSetRayCallback(dGeomID g, dTriRayCallback* Callback); +dTriRayCallback* dGeomTriMeshGetRayCallback(dGeomID g); + +/* + * Trimesh class + * Construction. Callbacks are optional. + */ +dGeomID dCreateTriMesh(dSpaceID space, dTriMeshDataID Data, dTriCallback* Callback, dTriArrayCallback* ArrayCallback, dTriRayCallback* RayCallback); + +void dGeomTriMeshSetData(dGeomID g, dTriMeshDataID Data); +dTriMeshDataID dGeomTriMeshGetData(dGeomID g); + + +// enable/disable/check temporal coherence +void dGeomTriMeshEnableTC(dGeomID g, int geomClass, int enable); +int dGeomTriMeshIsTCEnabled(dGeomID g, int geomClass); + +/* + * Clears the internal temporal coherence caches. When a geom has its + * collision checked with a trimesh once, data is stored inside the trimesh. + * With large worlds with lots of seperate objects this list could get huge. + * We should be able to do this automagically. + */ +void dGeomTriMeshClearTCCache(dGeomID g); + + +/* + * sets the trimesh to "force-normal" mode in which its normals are always used + * for tri-on-tri collisions with a non-force-normal geom + */ + void dGeomTriMeshSetForceNormalMode(dGeomID g,int enable); + + +/* + * returns the TriMeshDataID + */ +dTriMeshDataID dGeomTriMeshGetTriMeshDataID(dGeomID g); + +/* + * Gets a triangle. + */ +void dGeomTriMeshGetTriangle(dGeomID g, int Index, dVector3* v0, dVector3* v1, dVector3* v2); + +/* + * Gets the point on the requested triangle and the given barycentric + * coordinates. + */ +void dGeomTriMeshGetPoint(dGeomID g, int Index, dReal u, dReal v, dVector3 Out); + +/* + +This is how the strided data works: + +struct StridedVertex{ + dVector3 Vertex; + // Userdata +}; +int VertexStride = sizeof(StridedVertex); + +struct StridedTri{ + int Indices[3]; + // Userdata +}; +int TriStride = sizeof(StridedTri); + +*/ + + +int dGeomTriMeshGetTriangleCount (dGeomID g); + + +#ifdef __cplusplus +} +#endif + +#endif /* _ODE_COLLISION_TRIMESH_H_ */ + diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_box.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_box.cpp new file mode 100644 index 00000000..bad0cd62 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_box.cpp @@ -0,0 +1,1349 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + + +/************************************************************************* + * * + * Triangle-box collider by Alen Ladavac and Vedran Klanac. * + * Ported to ODE by Oskari Nyman. * + * * + *************************************************************************/ + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +static void +GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, + dxGeom* in_g1, dxGeom* in_g2, + const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, + int& OutTriCount); + + +// largest number, double or float +#if defined(dSINGLE) + #define MAXVALUE FLT_MAX +#else + #define MAXVALUE DBL_MAX +#endif + + +// dVector3 +// r=a-b +#define SUBTRACT(a,b,r) do{ \ + (r)[0]=(a)[0] - (b)[0]; \ + (r)[1]=(a)[1] - (b)[1]; \ + (r)[2]=(a)[2] - (b)[2]; }while(0) + + +// dVector3 +// a=b +#define SET(a,b) do{ \ + (a)[0]=(b)[0]; \ + (a)[1]=(b)[1]; \ + (a)[2]=(b)[2]; }while(0) + + +// dMatrix3 +// a=b +#define SETM(a,b) do{ \ + (a)[0]=(b)[0]; \ + (a)[1]=(b)[1]; \ + (a)[2]=(b)[2]; \ + (a)[3]=(b)[3]; \ + (a)[4]=(b)[4]; \ + (a)[5]=(b)[5]; \ + (a)[6]=(b)[6]; \ + (a)[7]=(b)[7]; \ + (a)[8]=(b)[8]; \ + (a)[9]=(b)[9]; \ + (a)[10]=(b)[10]; \ + (a)[11]=(b)[11]; }while(0) + + +// dVector3 +// r=a+b +#define ADD(a,b,r) do{ \ + (r)[0]=(a)[0] + (b)[0]; \ + (r)[1]=(a)[1] + (b)[1]; \ + (r)[2]=(a)[2] + (b)[2]; }while(0) + + +// dMatrix3, int, dVector3 +// v=column a from m +#define GETCOL(m,a,v) do{ \ + (v)[0]=(m)[(a)+0]; \ + (v)[1]=(m)[(a)+4]; \ + (v)[2]=(m)[(a)+8]; }while(0) + + +// dVector4, dVector3 +// distance between plane p and point v +#define POINTDISTANCE(p,v) \ + ( p[0]*v[0] + p[1]*v[1] + p[2]*v[2] + p[3] ) + + +// dVector4, dVector3, dReal +// construct plane from normal and d +#define CONSTRUCTPLANE(plane,normal,d) do{ \ + plane[0]=normal[0];\ + plane[1]=normal[1];\ + plane[2]=normal[2];\ + plane[3]=d; }while(0) + + +// dVector3 +// length of vector a +#define LENGTHOF(a) \ + dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]) + + +struct _Context{ + + dMatrix3 mHullBoxRot; + dVector3 vHullBoxPos; + dVector3 vBoxHalfSize; + + // mesh data + dVector3 vHullDstPos; + + // global collider data + dVector3 vBestNormal; + dReal fBestDepth; + int iBestAxis; + int iExitAxis; + dVector3 vE0, vE1, vE2, vN; + + // global info for contact creation + int iFlags; + dContactGeom *ContactGeoms; + int iStride; + dxGeom *Geom1; + dxGeom *Geom2; + int ctContacts; + + _Context():ctContacts(0), + iBestAxis(0), + iExitAxis(0){} +}; + +// box data +//static dMatrix3 mHullBoxRot; +//static dVector3 vHullBoxPos; +//static dVector3 vBoxHalfSize; + +// mesh data +//static dVector3 vHullDstPos; + +// global collider data +//static dVector3 vBestNormal; +//static dReal fBestDepth; +//static int iBestAxis = 0; +//static int iExitAxis = 0; +//static dVector3 vE0; +//static dVector3 vE1; +//static dVector3 vE2; +//static dVector3 vN; + +// global info for contact creation +//static int iFlags; +//static dContactGeom *ContactGeoms; +//static int iStride; +//static dxGeom *Geom1; +//static dxGeom *Geom2; +//static int ctContacts = 0; + + + +// Test normal of mesh face as separating axis for intersection +static BOOL _cldTestNormal(_Context &ctx, dReal fp0, dReal fR, dVector3 vNormal, int iAxis ) +{ + // calculate overlapping interval of box and triangle + dReal fDepth = fR+fp0; + + // if we do not overlap + if ( fDepth<0 ) { + // do nothing + return FALSE; + } + + // calculate normal's length + dReal fLength = LENGTHOF(vNormal); + // if long enough + if ( fLength > 0.0f ) { + + dReal fOneOverLength = 1.0f/fLength; + // normalize depth + fDepth = fDepth*fOneOverLength; + + // get minimum depth + if (fDepth=0); + ctx.fBestDepth = fDepth; + } + + } + + return TRUE; +} + + + + +// Test box axis as separating axis +static BOOL _cldTestFace(_Context &ctx, dReal fp0, dReal fp1, dReal fp2, dReal fR, dReal fD, + dVector3 vNormal, int iAxis ) +{ + dReal fMin, fMax; + + // find min of triangle interval + if ( fp0 < fp1 ) { + if ( fp0 < fp2 ) { + fMin = fp0; + } else { + fMin = fp2; + } + } else { + if( fp1 < fp2 ) { + fMin = fp1; + } else { + fMin = fp2; + } + } + + // find max of triangle interval + if ( fp0 > fp1 ) { + if ( fp0 > fp2 ) { + fMax = fp0; + } else { + fMax = fp2; + } + } else { + if( fp1 > fp2 ) { + fMax = fp1; + } else { + fMax = fp2; + } + } + + // calculate minimum and maximum depth + dReal fDepthMin = fR - fMin; + dReal fDepthMax = fMax + fR; + + // if we dont't have overlapping interval + if ( fDepthMin < 0 || fDepthMax < 0 ) { + // do nothing + return FALSE; + } + + dReal fDepth = 0; + + // if greater depth is on negative side + if ( fDepthMin > fDepthMax ) { + // use smaller depth (one from positive side) + fDepth = fDepthMax; + // flip normal direction + vNormal[0] = -vNormal[0]; + vNormal[1] = -vNormal[1]; + vNormal[2] = -vNormal[2]; + fD = -fD; + // if greater depth is on positive side + } else { + // use smaller depth (one from negative side) + fDepth = fDepthMin; + } + + + // if lower depth than best found so far + if (fDepth=0); + ctx.fBestDepth = fDepth; + } + + return TRUE; +} + + + + + +// Test cross products of box axis and triangle edges as separating axis +static BOOL _cldTestEdge(_Context &ctx, dReal fp0, dReal fp1, dReal fR, dReal fD, + dVector3 vNormal, int iAxis ) +{ + dReal fMin, fMax; + + // calculate min and max interval values + if ( fp0 < fp1 ) { + fMin = fp0; + fMax = fp1; + } else { + fMin = fp1; + fMax = fp0; + } + + // check if we overlapp + dReal fDepthMin = fR - fMin; + dReal fDepthMax = fMax + fR; + + // if we don't overlapp + if ( fDepthMin < 0 || fDepthMax < 0 ) { + // do nothing + return FALSE; + } + + dReal fDepth; + + + // if greater depth is on negative side + if ( fDepthMin > fDepthMax ) { + // use smaller depth (one from positive side) + fDepth = fDepthMax; + // flip normal direction + vNormal[0] = -vNormal[0]; + vNormal[1] = -vNormal[1]; + vNormal[2] = -vNormal[2]; + fD = -fD; + // if greater depth is on positive side + } else { + // use smaller depth (one from negative side) + fDepth = fDepthMin; + } + + // calculate normal's length + dReal fLength = LENGTHOF(vNormal); + + // if long enough + if ( fLength > 0.0f ) { + + // normalize depth + dReal fOneOverLength = 1.0f/fLength; + fDepth = fDepth*fOneOverLength; + fD*=fOneOverLength; + + + // if lower depth than best found so far (favor face over edges) + if (fDepth*1.5f=0); + ctx.fBestDepth = fDepth; + } + } + + return TRUE; +} + + + + + +// clip polygon with plane and generate new polygon points +static void _cldClipPolyToPlane( dVector3 avArrayIn[], int ctIn, + dVector3 avArrayOut[], int &ctOut, + const dVector4 &plPlane ) +{ + // start with no output points + ctOut = 0; + + int i0 = ctIn-1; + + // for each edge in input polygon + for (int i1=0; i1= 0 ) { + // emit point + avArrayOut[ctOut][0] = avArrayIn[i0][0]; + avArrayOut[ctOut][1] = avArrayIn[i0][1]; + avArrayOut[ctOut][2] = avArrayIn[i0][2]; + ctOut++; + } + + // if points are on different sides + if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) { + + // find intersection point of edge and plane + dVector3 vIntersectionPoint; + vIntersectionPoint[0]= avArrayIn[i0][0] - (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[1]= avArrayIn[i0][1] - (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[2]= avArrayIn[i0][2] - (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1); + + // emit intersection point + avArrayOut[ctOut][0] = vIntersectionPoint[0]; + avArrayOut[ctOut][1] = vIntersectionPoint[1]; + avArrayOut[ctOut][2] = vIntersectionPoint[2]; + ctOut++; + } + } + +} + + + + +static BOOL _cldTestSeparatingAxes(_Context &ctx, const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) { + // reset best axis + ctx.iBestAxis = 0; + ctx.iExitAxis = -1; + ctx.fBestDepth = MAXVALUE; + + // calculate edges + SUBTRACT(v1,v0,ctx.vE0); + SUBTRACT(v2,v0,ctx.vE1); + SUBTRACT(ctx.vE1,ctx.vE0,ctx.vE2); + + // calculate poly normal + dCROSS(ctx.vN,=,ctx.vE0,ctx.vE1); + + // extract box axes as vectors + dVector3 vA0,vA1,vA2; + GETCOL(ctx.mHullBoxRot,0,vA0); + GETCOL(ctx.mHullBoxRot,1,vA1); + GETCOL(ctx.mHullBoxRot,2,vA2); + + // box halfsizes + dReal fa0 = ctx.vBoxHalfSize[0]; + dReal fa1 = ctx.vBoxHalfSize[1]; + dReal fa2 = ctx.vBoxHalfSize[2]; + + // calculate relative position between box and triangle + dVector3 vD; + SUBTRACT(v0,ctx.vHullBoxPos,vD); + + // calculate length of face normal + dReal fNLen = LENGTHOF( ctx.vN ); + + dVector3 vL; + dReal fp0, fp1, fp2, fR, fD; + + // Test separating axes for intersection + // ************************************************ + // Axis 1 - Triangle Normal + SET(vL,ctx.vN); + fp0 = dDOT(vL,vD); + fp1 = fp0; + fp2 = fp0; + fR=fa0*dFabs( dDOT(ctx.vN,vA0) ) + fa1 * dFabs( dDOT(ctx.vN,vA1) ) + fa2 * dFabs( dDOT(ctx.vN,vA2) ); + + + if( !_cldTestNormal(ctx, fp0, fR, vL, 1) ) { + ctx.iExitAxis=1; + return FALSE; + } + + // ************************************************ + + // Test Faces + // ************************************************ + // Axis 2 - Box X-Axis + SET(vL,vA0); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 + dDOT(vA0,ctx.vE0); + fp2 = fp0 + dDOT(vA0,ctx.vE1); + fR = fa0; + + + if( !_cldTestFace(ctx, fp0, fp1, fp2, fR, fD, vL, 2) ) { + ctx.iExitAxis=2; + return FALSE; + } + // ************************************************ + + // ************************************************ + // Axis 3 - Box Y-Axis + SET(vL,vA1); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 + dDOT(vA1,ctx.vE0); + fp2 = fp0 + dDOT(vA1,ctx.vE1); + fR = fa1; + + + if( !_cldTestFace(ctx, fp0, fp1, fp2, fR, fD, vL, 3) ) { + ctx.iExitAxis=3; + return FALSE; + } + + // ************************************************ + + // ************************************************ + // Axis 4 - Box Z-Axis + SET(vL,vA2); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 + dDOT(vA2,ctx.vE0); + fp2 = fp0 + dDOT(vA2,ctx.vE1); + fR = fa2; + + + if( !_cldTestFace(ctx, fp0, fp1, fp2, fR, fD, vL, 4) ) { + ctx.iExitAxis=4; + return FALSE; + } + + // ************************************************ + + // Test Edges + // ************************************************ + // Axis 5 - Box X-Axis cross Edge0 + dCROSS(vL,=,vA0,ctx.vE0); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0; + fp2 = fp0 + dDOT(vA0,ctx.vN); + fR = fa1 * dFabs(dDOT(vA2,ctx.vE0)) + fa2 * dFabs(dDOT(vA1,ctx.vE0)); + + + if( !_cldTestEdge(ctx, fp1, fp2, fR, fD, vL, 5) ) { + ctx.iExitAxis=5; + return FALSE; + } + // ************************************************ + + // ************************************************ + // Axis 6 - Box X-Axis cross Edge1 + dCROSS(vL,=,vA0,ctx.vE1); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 - dDOT(vA0,ctx.vN); + fp2 = fp0; + fR = fa1 * dFabs(dDOT(vA2,ctx.vE1)) + fa2 * dFabs(dDOT(vA1,ctx.vE1)); + + + if( !_cldTestEdge(ctx, fp0, fp1, fR, fD, vL, 6) ) { + ctx.iExitAxis=6; + return FALSE; + } + // ************************************************ + + // ************************************************ + // Axis 7 - Box X-Axis cross Edge2 + dCROSS(vL,=,vA0,ctx.vE2); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 - dDOT(vA0,ctx.vN); + fp2 = fp0 - dDOT(vA0,ctx.vN); + fR = fa1 * dFabs(dDOT(vA2,ctx.vE2)) + fa2 * dFabs(dDOT(vA1,ctx.vE2)); + + + if( !_cldTestEdge(ctx, fp0, fp1, fR, fD, vL, 7) ) { + ctx.iExitAxis=7; + return FALSE; + } + + // ************************************************ + + // ************************************************ + // Axis 8 - Box Y-Axis cross Edge0 + dCROSS(vL,=,vA1,ctx.vE0); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0; + fp2 = fp0 + dDOT(vA1,ctx.vN); + fR = fa0 * dFabs(dDOT(vA2,ctx.vE0)) + fa2 * dFabs(dDOT(vA0,ctx.vE0)); + + + if( !_cldTestEdge(ctx, fp0, fp2, fR, fD, vL, 8) ) { + ctx.iExitAxis=8; + return FALSE; + } + + // ************************************************ + + // ************************************************ + // Axis 9 - Box Y-Axis cross Edge1 + dCROSS(vL,=,vA1,ctx.vE1); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 - dDOT(vA1,ctx.vN); + fp2 = fp0; + fR = fa0 * dFabs(dDOT(vA2,ctx.vE1)) + fa2 * dFabs(dDOT(vA0,ctx.vE1)); + + + if( !_cldTestEdge(ctx, fp0, fp1, fR, fD, vL, 9) ) { + ctx.iExitAxis=9; + return FALSE; + } + + // ************************************************ + + // ************************************************ + // Axis 10 - Box Y-Axis cross Edge2 + dCROSS(vL,=,vA1,ctx.vE2); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 - dDOT(vA1,ctx.vN); + fp2 = fp0 - dDOT(vA1,ctx.vN); + fR = fa0 * dFabs(dDOT(vA2,ctx.vE2)) + fa2 * dFabs(dDOT(vA0,ctx.vE2)); + + + if( !_cldTestEdge(ctx, fp0, fp1, fR, fD, vL, 10) ) { + ctx.iExitAxis=10; + return FALSE; + } + + // ************************************************ + + // ************************************************ + // Axis 11 - Box Z-Axis cross Edge0 + dCROSS(vL,=,vA2,ctx.vE0); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0; + fp2 = fp0 + dDOT(vA2,ctx.vN); + fR = fa0 * dFabs(dDOT(vA1,ctx.vE0)) + fa1 * dFabs(dDOT(vA0,ctx.vE0)); + + + if( !_cldTestEdge(ctx, fp0, fp2, fR, fD, vL, 11) ) { + ctx.iExitAxis=11; + return FALSE; + } + // ************************************************ + + // ************************************************ + // Axis 12 - Box Z-Axis cross Edge1 + dCROSS(vL,=,vA2,ctx.vE1); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 - dDOT(vA2,ctx.vN); + fp2 = fp0; + fR = fa0 * dFabs(dDOT(vA1,ctx.vE1)) + fa1 * dFabs(dDOT(vA0,ctx.vE1)); + + + if( !_cldTestEdge(ctx, fp0, fp1, fR, fD, vL, 12) ) { + ctx.iExitAxis=12; + return FALSE; + } + // ************************************************ + + // ************************************************ + // Axis 13 - Box Z-Axis cross Edge2 + dCROSS(vL,=,vA2,ctx.vE2); + fD = dDOT(vL,ctx.vN)/fNLen; + fp0 = dDOT(vL,vD); + fp1 = fp0 - dDOT(vA2,ctx.vN); + fp2 = fp0 - dDOT(vA2,ctx.vN); + fR = fa0 * dFabs(dDOT(vA1,ctx.vE2)) + fa1 * dFabs(dDOT(vA0,ctx.vE2)); + + + if( !_cldTestEdge(ctx, fp0, fp1, fR, fD, vL, 13) ) { + ctx.iExitAxis=13; + return FALSE; + } + + // ************************************************ + return TRUE; +} + + + + + +// find two closest points on two lines +static BOOL _cldClosestPointOnTwoLines( dVector3 vPoint1, dVector3 vLenVec1, + dVector3 vPoint2, dVector3 vLenVec2, + dReal &fvalue1, dReal &fvalue2) +{ + // calulate denominator + dVector3 vp; + SUBTRACT(vPoint2,vPoint1,vp); + dReal fuaub = dDOT(vLenVec1,vLenVec2); + dReal fq1 = dDOT(vLenVec1,vp); + dReal fq2 = -dDOT(vLenVec2,vp); + dReal fd = 1.0f - fuaub * fuaub; + + // if denominator is positive + if (fd > 0.0f) { + // calculate points of closest approach + fd = 1.0f/fd; + fvalue1 = (fq1 + fuaub*fq2)*fd; + fvalue2 = (fuaub*fq1 + fq2)*fd; + return TRUE; + // otherwise + } else { + // lines are parallel + fvalue1 = 0.0f; + fvalue2 = 0.0f; + return FALSE; + } + +} + + + + + +// clip and generate contacts +static void _cldClipping(_Context &ctx, const dVector3 &v0, const dVector3 &v1, const dVector3 &v2) { + + // if we have edge/edge intersection + if ( ctx.iBestAxis > 4 ) { + + dVector3 vub,vPb,vPa; + + SET(vPa,ctx.vHullBoxPos); + + // calculate point on box edge + for( int i=0; i<3; i++) { + dVector3 vRotCol; + GETCOL(ctx.mHullBoxRot,i,vRotCol); + dReal fSign = dDOT(ctx.vBestNormal,vRotCol) > 0 ? 1.0f : -1.0f; + + vPa[0] += fSign * ctx.vBoxHalfSize[i] * vRotCol[0]; + vPa[1] += fSign * ctx.vBoxHalfSize[i] * vRotCol[1]; + vPa[2] += fSign * ctx.vBoxHalfSize[i] * vRotCol[2]; + } + + int iEdge = (ctx.iBestAxis-5)%3; + + // decide which edge is on triangle + if ( iEdge == 0 ) { + SET(vPb,v0); + SET(vub,ctx.vE0); + } else if ( iEdge == 1) { + SET(vPb,v2); + SET(vub,ctx.vE1); + } else { + SET(vPb,v1); + SET(vub,ctx.vE2); + } + + + // setup direction parameter for face edge + dNormalize3(vub); + + dReal fParam1, fParam2; + + // setup direction parameter for box edge + dVector3 vua; + int col=(ctx.iBestAxis-5)/3; + GETCOL(ctx.mHullBoxRot,col,vua); + + // find two closest points on both edges + _cldClosestPointOnTwoLines( vPa, vua, vPb, vub, fParam1, fParam2 ); + vPa[0] += vua[0]*fParam1; + vPa[1] += vua[1]*fParam1; + vPa[2] += vua[2]*fParam1; + + vPb[0] += vub[0]*fParam2; + vPb[1] += vub[1]*fParam2; + vPb[2] += vub[2]*fParam2; + + // calculate collision point + dVector3 vPntTmp; + ADD(vPa,vPb,vPntTmp); + + vPntTmp[0]*=0.5f; + vPntTmp[1]*=0.5f; + vPntTmp[2]*=0.5f; + + // generate contact point between two closest points +#ifdef ORIG + if (ctx.ctContacts < (ctx.iFlags & 0x0ffff)) { + dContactGeom* Contact = SAFECONTACT(ctx.iFlags, ctx.ContactGeoms, ctx.ctContacts, ctx.iStride); + Contact->depth = ctx.fBestDepth; + SET(Contact->normal,ctx.vBestNormal); + SET(Contact->pos,vPntTmp); + Contact->g1 = ctx.Geom1; + Contact->g2 = ctx.Geom2; + ctx.ctContacts++; + } +#endif + GenerateContact(ctx.iFlags, ctx.ContactGeoms, ctx.iStride, ctx.Geom1, ctx.Geom2, + vPntTmp, ctx.vBestNormal, ctx.fBestDepth, ctx.ctContacts); + + + + // if triangle is the referent face then clip box to triangle face + } else if ( ctx.iBestAxis == 1 ) { + + + dVector3 vNormal2; + vNormal2[0]=-ctx.vBestNormal[0]; + vNormal2[1]=-ctx.vBestNormal[1]; + vNormal2[2]=-ctx.vBestNormal[2]; + + + // vNr is normal in box frame, pointing from triangle to box + dMatrix3 mTransposed; + mTransposed[0*4+0]=ctx.mHullBoxRot[0*4+0]; + mTransposed[0*4+1]=ctx.mHullBoxRot[1*4+0]; + mTransposed[0*4+2]=ctx.mHullBoxRot[2*4+0]; + + mTransposed[1*4+0]=ctx.mHullBoxRot[0*4+1]; + mTransposed[1*4+1]=ctx.mHullBoxRot[1*4+1]; + mTransposed[1*4+2]=ctx.mHullBoxRot[2*4+1]; + + mTransposed[2*4+0]=ctx.mHullBoxRot[0*4+2]; + mTransposed[2*4+1]=ctx.mHullBoxRot[1*4+2]; + mTransposed[2*4+2]=ctx.mHullBoxRot[2*4+2]; + + dVector3 vNr; + vNr[0]=mTransposed[0*4+0]*vNormal2[0]+ mTransposed[0*4+1]*vNormal2[1]+ mTransposed[0*4+2]*vNormal2[2]; + vNr[1]=mTransposed[1*4+0]*vNormal2[0]+ mTransposed[1*4+1]*vNormal2[1]+ mTransposed[1*4+2]*vNormal2[2]; + vNr[2]=mTransposed[2*4+0]*vNormal2[0]+ mTransposed[2*4+1]*vNormal2[1]+ mTransposed[2*4+2]*vNormal2[2]; + + + dVector3 vAbsNormal; + vAbsNormal[0] = dFabs( vNr[0] ); + vAbsNormal[1] = dFabs( vNr[1] ); + vAbsNormal[2] = dFabs( vNr[2] ); + + // get closest face from box + int iB0, iB1, iB2; + if (vAbsNormal[1] > vAbsNormal[0]) { + if (vAbsNormal[1] > vAbsNormal[2]) { + iB1 = 0; iB0 = 1; iB2 = 2; + } else { + iB1 = 0; iB2 = 1; iB0 = 2; + } + } else { + + if (vAbsNormal[0] > vAbsNormal[2]) { + iB0 = 0; iB1 = 1; iB2 = 2; + } else { + iB1 = 0; iB2 = 1; iB0 = 2; + } + } + + // Here find center of box face we are going to project + dVector3 vCenter; + dVector3 vRotCol; + GETCOL(ctx.mHullBoxRot,iB0,vRotCol); + + if (vNr[iB0] > 0) { + vCenter[0] = ctx.vHullBoxPos[0] - v0[0] - ctx.vBoxHalfSize[iB0] * vRotCol[0]; + vCenter[1] = ctx.vHullBoxPos[1] - v0[1] - ctx.vBoxHalfSize[iB0] * vRotCol[1]; + vCenter[2] = ctx.vHullBoxPos[2] - v0[2] - ctx.vBoxHalfSize[iB0] * vRotCol[2]; + } else { + vCenter[0] = ctx.vHullBoxPos[0] - v0[0] + ctx.vBoxHalfSize[iB0] * vRotCol[0]; + vCenter[1] = ctx.vHullBoxPos[1] - v0[1] + ctx.vBoxHalfSize[iB0] * vRotCol[1]; + vCenter[2] = ctx.vHullBoxPos[2] - v0[2] + ctx.vBoxHalfSize[iB0] * vRotCol[2]; + } + + // Here find 4 corner points of box + dVector3 avPoints[4]; + + dVector3 vRotCol2; + GETCOL(ctx.mHullBoxRot,iB1,vRotCol); + GETCOL(ctx.mHullBoxRot,iB2,vRotCol2); + + for(int x=0;x<3;x++) { + avPoints[0][x] = vCenter[x] + (ctx.vBoxHalfSize[iB1] * vRotCol[x]) - (ctx.vBoxHalfSize[iB2] * vRotCol2[x]); + avPoints[1][x] = vCenter[x] - (ctx.vBoxHalfSize[iB1] * vRotCol[x]) - (ctx.vBoxHalfSize[iB2] * vRotCol2[x]); + avPoints[2][x] = vCenter[x] - (ctx.vBoxHalfSize[iB1] * vRotCol[x]) + (ctx.vBoxHalfSize[iB2] * vRotCol2[x]); + avPoints[3][x] = vCenter[x] + (ctx.vBoxHalfSize[iB1] * vRotCol[x]) + (ctx.vBoxHalfSize[iB2] * vRotCol2[x]); + } + + + // clip Box face with 4 planes of triangle (1 face plane, 3 egde planes) + dVector3 avTempArray1[9]; + dVector3 avTempArray2[9]; + dVector4 plPlane; + + int iTempCnt1=0; + int iTempCnt2=0; + + // zeroify vectors - necessary? + for(int i=0; i<9; i++) { + avTempArray1[i][0]=0; + avTempArray1[i][1]=0; + avTempArray1[i][2]=0; + + avTempArray2[i][0]=0; + avTempArray2[i][1]=0; + avTempArray2[i][2]=0; + } + + + // Normal plane + dVector3 vTemp; + vTemp[0]=-ctx.vN[0]; + vTemp[1]=-ctx.vN[1]; + vTemp[2]=-ctx.vN[2]; + dNormalize3(vTemp); + CONSTRUCTPLANE(plPlane,vTemp,0); + + _cldClipPolyToPlane( avPoints, 4, avTempArray1, iTempCnt1, plPlane ); + + + // Plane p0 + dVector3 vTemp2; + SUBTRACT(v1,v0,vTemp2); + dCROSS(vTemp,=,ctx.vN,vTemp2); + dNormalize3(vTemp); + CONSTRUCTPLANE(plPlane,vTemp,0); + + _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); + + + // Plane p1 + SUBTRACT(v2,v1,vTemp2); + dCROSS(vTemp,=,ctx.vN,vTemp2); + dNormalize3(vTemp); + SUBTRACT(v0,v2,vTemp2); + CONSTRUCTPLANE(plPlane,vTemp,dDOT(vTemp2,vTemp)); + + _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane ); + + + // Plane p2 + SUBTRACT(v0,v2,vTemp2); + dCROSS(vTemp,=,ctx.vN,vTemp2); + dNormalize3(vTemp); + CONSTRUCTPLANE(plPlane,vTemp,0); + + _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); + + + // END of clipping polygons + + + + // for each generated contact point + for ( int i=0; i 0) { + fTempDepth = 0; + } + + dVector3 vPntTmp; + ADD(avTempArray2[i],v0,vPntTmp); + +#ifdef ORIG + if (ctx.ctContacts < (ctx.iFlags & 0x0ffff)) { + dContactGeom* Contact = SAFECONTACT(ctx.iFlags, ctx.ContactGeoms, ctx.ctContacts, ctx.iStride); + + Contact->depth = -fTempDepth; + SET(Contact->normal,ctx.vBestNormal); + SET(Contact->pos,vPntTmp); + Contact->g1 = ctx.Geom1; + Contact->g2 = ctx.Geom2; + ctx.ctContacts++; + } +#endif + GenerateContact(ctx.iFlags, ctx.ContactGeoms, ctx.iStride, ctx.Geom1, ctx.Geom2, + vPntTmp, ctx.vBestNormal, -fTempDepth, ctx.ctContacts); + } + + //dAASSERT(ctx.ctContacts>0); + + // if box face is the referent face, then clip triangle on box face + } else { // 2 <= if ctx.iBestAxis <= 4 + + // get normal of box face + dVector3 vNormal2; + SET(vNormal2,ctx.vBestNormal); + + // get indices of box axes in correct order + int iA0,iA1,iA2; + iA0 = ctx.iBestAxis-2; + if ( iA0 == 0 ) { + iA1 = 1; iA2 = 2; + } else if ( iA0 == 1 ) { + iA1 = 0; iA2 = 2; + } else { + iA1 = 0; iA2 = 1; + } + + dVector3 avPoints[3]; + // calculate triangle vertices in box frame + SUBTRACT(v0,ctx.vHullBoxPos,avPoints[0]); + SUBTRACT(v1,ctx.vHullBoxPos,avPoints[1]); + SUBTRACT(v2,ctx.vHullBoxPos,avPoints[2]); + + // CLIP Polygons + // define temp data for clipping + dVector3 avTempArray1[9]; + dVector3 avTempArray2[9]; + + int iTempCnt1, iTempCnt2; + + // zeroify vectors - necessary? + for(int i=0; i<9; i++) { + avTempArray1[i][0]=0; + avTempArray1[i][1]=0; + avTempArray1[i][2]=0; + + avTempArray2[i][0]=0; + avTempArray2[i][1]=0; + avTempArray2[i][2]=0; + } + + // clip triangle with 5 box planes (1 face plane, 4 edge planes) + + dVector4 plPlane; + + // Normal plane + dVector3 vTemp; + vTemp[0]=-vNormal2[0]; + vTemp[1]=-vNormal2[1]; + vTemp[2]=-vNormal2[2]; + CONSTRUCTPLANE(plPlane,vTemp,ctx.vBoxHalfSize[iA0]); + + _cldClipPolyToPlane( avPoints, 3, avTempArray1, iTempCnt1, plPlane ); + + + // Plane p0 + GETCOL(ctx.mHullBoxRot,iA1,vTemp); + CONSTRUCTPLANE(plPlane,vTemp,ctx.vBoxHalfSize[iA1]); + + _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); + + + // Plane p1 + GETCOL(ctx.mHullBoxRot,iA1,vTemp); + vTemp[0]=-vTemp[0]; + vTemp[1]=-vTemp[1]; + vTemp[2]=-vTemp[2]; + CONSTRUCTPLANE(plPlane,vTemp,ctx.vBoxHalfSize[iA1]); + + _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane ); + + + // Plane p2 + GETCOL(ctx.mHullBoxRot,iA2,vTemp); + CONSTRUCTPLANE(plPlane,vTemp,ctx.vBoxHalfSize[iA2]); + + _cldClipPolyToPlane( avTempArray1, iTempCnt1, avTempArray2, iTempCnt2, plPlane ); + + + // Plane p3 + GETCOL(ctx.mHullBoxRot,iA2,vTemp); + vTemp[0]=-vTemp[0]; + vTemp[1]=-vTemp[1]; + vTemp[2]=-vTemp[2]; + CONSTRUCTPLANE(plPlane,vTemp,ctx.vBoxHalfSize[iA2]); + + _cldClipPolyToPlane( avTempArray2, iTempCnt2, avTempArray1, iTempCnt1, plPlane ); + + + // for each generated contact point + for ( int i=0; i 0) { + fTempDepth = 0; + } + + // generate contact data + dVector3 vPntTmp; + ADD(avTempArray1[i],ctx.vHullBoxPos,vPntTmp); + +#ifdef ORIG + if (ctx.ctContacts < (ctx.iFlags & 0x0ffff)) { + dContactGeom* Contact = SAFECONTACT(ctx.iFlags, ctx.ContactGeoms, ctx.ctContacts, ctx.iStride); + + Contact->depth = -fTempDepth; + SET(Contact->normal,ctx.vBestNormal); + SET(Contact->pos,vPntTmp); + Contact->g1 = ctx.Geom1; + Contact->g2 = ctx.Geom2; + ctx.ctContacts++; + } +#endif + GenerateContact(ctx.iFlags, ctx.ContactGeoms, ctx.iStride, ctx.Geom1, ctx.Geom2, + vPntTmp, ctx.vBestNormal, -fTempDepth, ctx.ctContacts); + } + + //dAASSERT(ctx.ctContacts>0); + } + +} + + + + + +// test one mesh triangle on intersection with given box +static void _cldTestOneTriangle(_Context &ctx, const dVector3 &v0, const dVector3 &v1, const dVector3 &v2)//, void *pvUser) +{ + // do intersection test and find best separating axis + if(!_cldTestSeparatingAxes(ctx, v0, v1, v2) ) { + // if not found do nothing + return; + } + + // if best separation axis is not found + if ( ctx.iBestAxis == 0 ) { + // this should not happen (we should already exit in that case) + //dMessage (0, "best separation axis not found"); + // do nothing + return; + } + + _cldClipping(ctx, v0, v1, v2); +} + + + + + +// box to mesh collider +int dCollideBTL(dxGeom* g1, dxGeom* BoxGeom, int Flags, dContactGeom* Contacts, int Stride){ + + dxTriMesh* TriMesh = (dxTriMesh*)g1; + + + // get source hull position, orientation and half size + const dMatrix3& mRotBox=*(const dMatrix3*)dGeomGetRotation(BoxGeom); + const dVector3& vPosBox=*(const dVector3*)dGeomGetPosition(BoxGeom); + + // ericf fix.. slot this in in place of ugly global vars so we dont die multithreaded + _Context ctx; + + // to global + //SETM(mHullBoxRot,mRotBox); + SETM(ctx.mHullBoxRot,mRotBox); + SET(ctx.vHullBoxPos,vPosBox); + + dGeomBoxGetLengths(BoxGeom, ctx.vBoxHalfSize); + ctx.vBoxHalfSize[0] *= 0.5f; + ctx.vBoxHalfSize[1] *= 0.5f; + ctx.vBoxHalfSize[2] *= 0.5f; + + + + // get destination hull position and orientation + const dMatrix3& mRotMesh=*(const dMatrix3*)dGeomGetRotation(TriMesh); + const dVector3& vPosMesh=*(const dVector3*)dGeomGetPosition(TriMesh); + + // to global + SET(ctx.vHullDstPos,vPosMesh); + + + + // global info for contact creation + ctx.ctContacts = 0; + ctx.iStride=Stride; + ctx.iFlags=Flags; + ctx.ContactGeoms=Contacts; + ctx.Geom1=TriMesh; + ctx.Geom2=BoxGeom; + + + + // reset stuff + ctx.fBestDepth = MAXVALUE; + ctx.vBestNormal[0]=0; + ctx.vBestNormal[1]=0; + ctx.vBestNormal[2]=0; + + OBBCollider& Collider = TriMesh->_OBBCollider; + + + + + // Make OBB + OBB Box; + Box.mCenter.x = vPosBox[0]; + Box.mCenter.y = vPosBox[1]; + Box.mCenter.z = vPosBox[2]; + + + Box.mExtents.x = ctx.vBoxHalfSize[0]; + Box.mExtents.y = ctx.vBoxHalfSize[1]; + Box.mExtents.z = ctx.vBoxHalfSize[2]; + + Box.mRot.m[0][0] = mRotBox[0]; + Box.mRot.m[1][0] = mRotBox[1]; + Box.mRot.m[2][0] = mRotBox[2]; + + Box.mRot.m[0][1] = mRotBox[4]; + Box.mRot.m[1][1] = mRotBox[5]; + Box.mRot.m[2][1] = mRotBox[6]; + + Box.mRot.m[0][2] = mRotBox[8]; + Box.mRot.m[1][2] = mRotBox[9]; + Box.mRot.m[2][2] = mRotBox[10]; + + Matrix4x4 amatrix; + Matrix4x4 BoxMatrix = MakeMatrix(vPosBox, mRotBox, amatrix); + + Matrix4x4 InvBoxMatrix; + InvertPRMatrix(InvBoxMatrix, BoxMatrix); + + // TC results + if (TriMesh->doBoxTC) { + dxTriMesh::BoxTC* BoxTC = 0; + for (int i = 0; i < TriMesh->BoxTCCache.size(); i++){ + if (TriMesh->BoxTCCache[i].Geom == BoxGeom){ + BoxTC = &TriMesh->BoxTCCache[i]; + break; + } + } + if (!BoxTC){ + TriMesh->BoxTCCache.push(dxTriMesh::BoxTC()); + + BoxTC = &TriMesh->BoxTCCache[TriMesh->BoxTCCache.size() - 1]; + BoxTC->Geom = BoxGeom; + BoxTC->FatCoeff = 1.1f; // Pierre recommends this, instead of 1.0 + } + + // Intersect + Collider.SetTemporalCoherence(true); + Collider.Collide(*BoxTC, Box, TriMesh->Data->BVTree, null, &MakeMatrix(vPosMesh, mRotMesh, amatrix)); + } + else { + Collider.SetTemporalCoherence(false); + Collider.Collide(TriMesh->boxCache, Box, TriMesh->Data->BVTree, null, + &MakeMatrix(vPosMesh, mRotMesh, amatrix)); + // Collider.Collide(dxTriMesh::defaultBoxCache, Box, TriMesh->Data->BVTree, null, + // &MakeMatrix(vPosMesh, mRotMesh, amatrix)); + } + + // Retrieve data + int TriCount = Collider.GetNbTouchedPrimitives(); + const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); + + if (TriCount != 0){ + if (TriMesh->ArrayCallback != null){ + TriMesh->ArrayCallback(TriMesh, BoxGeom, Triangles, TriCount); + } + + //int OutTriCount = 0; + + // loop through all intersecting triangles + for (int i = 0; i < TriCount; i++){ + + + const int& Triint = Triangles[i]; + if (!Callback(TriMesh, BoxGeom, Triint)) continue; + + + dVector3 dv[3]; + FetchTriangle(TriMesh, Triint, vPosMesh, mRotMesh, dv); + + + // test this triangle + _cldTestOneTriangle(ctx,dv[0],dv[1],dv[2]); + } + } + + + return ctx.ctContacts; +} + + + + +// GenerateContact - Written by Jeff Smith (jeff@burri.to) +// Generate a "unique" contact. A unique contact has a unique +// position or normal. If the potential contact has the same +// position and normal as an existing contact, but a larger +// penetration depth, this new depth is used instead +// +static void +GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, + dxGeom* in_g1, dxGeom* in_g2, + const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, + int& OutTriCount) +{ + //if (in_Depth < 0.0) + //return; + + if (OutTriCount == (in_Flags & 0x0ffff)) + return; // contacts are full! + + dContactGeom* Contact; + dVector3 diff; + bool duplicate = false; + for (int i=0; ipos[j]; + if (dDOT(diff, diff) < ODE_EPSILON) + { + // same normal? + if (fabs(dDOT(in_Normal, Contact->normal)) > ((dReal)1)-ODE_EPSILON) + { + if (in_Depth > Contact->depth) + Contact->depth = in_Depth; + duplicate = true; + } + } + } + + if (!duplicate) + { + // Add a new contact + Contact = SAFECONTACT(in_Flags, in_Contacts, OutTriCount, in_Stride); + + Contact->pos[0] = in_ContactPos[0]; + Contact->pos[1] = in_ContactPos[1]; + Contact->pos[2] = in_ContactPos[2]; + Contact->pos[3] = 0.0; + + Contact->normal[0] = in_Normal[0]; + Contact->normal[1] = in_Normal[1]; + Contact->normal[2] = in_Normal[2]; + Contact->normal[3] = 0.0; + + Contact->depth = in_Depth; + + Contact->g1 = in_g1; + Contact->g2 = in_g2; + + OutTriCount++; + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ccylinder.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ccylinder.cpp new file mode 100644 index 00000000..8d99bff9 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ccylinder.cpp @@ -0,0 +1,1005 @@ +/************************************************************************* +* * +* Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * +* All rights reserved. Email: russ@q12.org Web: www.q12.org * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of EITHER: * +* (1) The GNU Lesser General Public License as published by the Free * +* Software Foundation; either version 2.1 of the License, or (at * +* your option) any later version. The text of the GNU Lesser * +* General Public License is included with this library in the * +* file LICENSE.TXT. * +* (2) The BSD-style license that is included with this library in * +* the file LICENSE-BSD.TXT. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * +* LICENSE.TXT and LICENSE-BSD.TXT for more details. * +* * +*************************************************************************/ + +/* + * Triangle-CCylinder(Capsule) collider by Alen Ladavac + * Ported to ODE by Nguyen Binh + */ + +// NOTES from Nguyen Binh +// 14 Apr : Seem to be robust +// There is a problem when you use original Step and set contact friction +// surface.mu = dInfinity; +// More description : +// When I dropped CCylinder over the bunny ears, it seems to stuck +// there for a while. I think the cause is when you set surface.mu = dInfinity; +// the friction force is too high so it just hang the capsule there. +// So the good cure for this is to set mu = around 1.5 (in my case) +// For StepFast1, this become as solid as rock : StepFast1 just approximate +// friction force. + +// NOTES from Croteam's Alen +//As a side note... there are some extra contacts that can be generated +//on the edge between two triangles, and if the capsule penetrates deeply into +//the triangle (usually happens with large mass or low FPS), some such +//contacts can in some cases push the capsule away from the edge instead of +//away from the two triangles. This shows up as capsule slowing down a bit +//when hitting an edge while sliding along a flat tesselated grid of +//triangles. This is only if capsule is standing upwards. + +//Same thing can appear whenever a smooth object (e.g sphere) hits such an +//edge, and it needs to be solved as a special case probably. This is a +//problem we are looking forward to address soon. + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +// largest number, double or float +#if defined(dSINGLE) +#define MAX_REAL FLT_MAX +#define MIN_REAL (-FLT_MAX) +#else +#define MAX_REAL DBL_MAX +#define MIN_REAL (-DBL_MAX) +#endif + +// To optimize before send contacts to dynamic part +#define OPTIMIZE_CONTACTS + +// dVector3 +// r=a-b +#define SUBTRACT(a,b,r) \ + (r)[0]=(a)[0] - (b)[0]; \ + (r)[1]=(a)[1] - (b)[1]; \ + (r)[2]=(a)[2] - (b)[2]; + + +// dVector3 +// a=b +#define SET(a,b) \ + (a)[0]=(b)[0]; \ + (a)[1]=(b)[1]; \ + (a)[2]=(b)[2]; + + +// dMatrix3 +// a=b +#define SETM(a,b) \ + (a)[0]=(b)[0]; \ + (a)[1]=(b)[1]; \ + (a)[2]=(b)[2]; \ + (a)[3]=(b)[3]; \ + (a)[4]=(b)[4]; \ + (a)[5]=(b)[5]; \ + (a)[6]=(b)[6]; \ + (a)[7]=(b)[7]; \ + (a)[8]=(b)[8]; \ + (a)[9]=(b)[9]; \ + (a)[10]=(b)[10]; \ + (a)[11]=(b)[11]; + + +// dVector3 +// r=a+b +#define ADD(a,b,r) \ + (r)[0]=(a)[0] + (b)[0]; \ + (r)[1]=(a)[1] + (b)[1]; \ + (r)[2]=(a)[2] + (b)[2]; + + +// dMatrix3, int, dVector3 +// v=column a from m +#define GETCOL(m,a,v) \ + (v)[0]=(m)[(a)+0]; \ + (v)[1]=(m)[(a)+4]; \ + (v)[2]=(m)[(a)+8]; + + +// dVector4, dVector3 +// distance between plane p and point v +#define POINTDISTANCE(p,v) \ + ( p[0]*v[0] + p[1]*v[1] + p[2]*v[2] + p[3] ); \ + + +// dVector4, dVector3, dReal +// construct plane from normal and d +#define CONSTRUCTPLANE(plane,normal,d) \ + plane[0]=normal[0];\ + plane[1]=normal[1];\ + plane[2]=normal[2];\ + plane[3]=d; + + +// dVector3 +// length of vector a +#define LENGTHOF(a) \ + dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);\ + +inline dReal _length2OfVector3(dVector3 v) +{ + return (v[0] * v[0] + v[1] * v[1] + v[2] * v[2] ); +} + + +// Local contacts data +typedef struct _sLocalContactData +{ + dVector3 vPos; + dVector3 vNormal; + dReal fDepth; + int nFlags; // 0 = filtered out, 1 = OK +}sLocalContactData; + +static sLocalContactData *gLocalContacts; +static unsigned int ctContacts = 0; + +// capsule data +// real time data +static dMatrix3 mCapsuleRotation; +static dVector3 vCapsulePosition; +static dVector3 vCapsuleAxis; +// static data +static dReal vCapsuleRadius; +static dReal fCapsuleSize; + +// mesh data +//static dMatrix4 mHullDstPl; +static dMatrix3 mTriMeshRot; +static dVector3 mTriMeshPos; +static dVector3 vE0, vE1, vE2; + +// Two geom +dxGeom* gCylinder; +dxGeom* gTriMesh; + +// global collider data +static dVector3 vNormal; +static dReal fBestDepth; +static dReal fBestCenter; +static dReal fBestrt; +static int iBestAxis; +static dVector3 vN = {0,0,0,0}; + +static dVector3 vV0; +static dVector3 vV1; +static dVector3 vV2; + +// ODE contact's specific +static int iFlags; +static dContactGeom *ContactGeoms; +static int iStride; + +// Capsule lie on axis number 3 = (Z axis) +static const int nCAPSULE_AXIS = 2; + +// Use to classify contacts to be "near" in position +static const dReal fSameContactPositionEpsilon = REAL(0.0001); // 1e-4 +// Use to classify contacts to be "near" in normal direction +static const dReal fSameContactNormalEpsilon = REAL(0.0001); // 1e-4 + + +// If this two contact can be classified as "near" +inline int _IsNearContacts(sLocalContactData& c1,sLocalContactData& c2) +{ + int bPosNear = 0; + int bSameDir = 0; + dVector3 vDiff; + + // First check if they are "near" in position + SUBTRACT(c1.vPos,c2.vPos,vDiff); + if ( (dFabs(vDiff[0]) < fSameContactPositionEpsilon) + &&(dFabs(vDiff[1]) < fSameContactPositionEpsilon) + &&(dFabs(vDiff[2]) < fSameContactPositionEpsilon)) + { + bPosNear = 1; + } + + // Second check if they are "near" in normal direction + SUBTRACT(c1.vNormal,c2.vNormal,vDiff); + if ( (dFabs(vDiff[0]) < fSameContactNormalEpsilon) + &&(dFabs(vDiff[1]) < fSameContactNormalEpsilon) + &&(dFabs(vDiff[2]) < fSameContactNormalEpsilon) ) + { + bSameDir = 1; + } + + // Will be "near" if position and normal direction are "near" + return (bPosNear && bSameDir); +} + +inline int _IsBetter(sLocalContactData& c1,sLocalContactData& c2) +{ + // The not better will be throw away + // You can change the selection criteria here + return (c1.fDepth > c2.fDepth); +} + +// iterate through gLocalContacts and filtered out "near contact" +inline void _OptimizeLocalContacts() +{ + int nContacts = ctContacts; + + for (int i = 0; i < nContacts-1; i++) + { + for (int j = i+1; j < nContacts; j++) + { + if (_IsNearContacts(gLocalContacts[i],gLocalContacts[j])) + { + // If they are seem to be the samed then filtered + // out the least penetrate one + if (_IsBetter(gLocalContacts[j],gLocalContacts[i])) + { + gLocalContacts[i].nFlags = 0; // filtered 1st contact + } + else + { + gLocalContacts[j].nFlags = 0; // filtered 2nd contact + } + + // NOTE + // There is other way is to add two depth together but + // it not work so well. Why??? + } + } + } +} + +inline int _ProcessLocalContacts() +{ + if (ctContacts == 0) + { + delete[] gLocalContacts; + return 0; + } + +#ifdef OPTIMIZE_CONTACTS + if (ctContacts > 1) + { + // Can be optimized... + _OptimizeLocalContacts(); + } +#endif + + unsigned int iContact = 0; + dContactGeom* Contact = 0; + + int nFinalContact = 0; + + for (iContact = 0; iContact < ctContacts; iContact ++) + { + // Ensure that we haven't created too many contacts + if( nFinalContact >= (iFlags & NUMC_MASK)) + { + break; + } + + if (1 == gLocalContacts[iContact].nFlags) + { + Contact = SAFECONTACT(iFlags, ContactGeoms, nFinalContact, iStride); + Contact->depth = gLocalContacts[iContact].fDepth; + SET(Contact->normal,gLocalContacts[iContact].vNormal); + SET(Contact->pos,gLocalContacts[iContact].vPos); + Contact->g1 = gCylinder; + Contact->g2 = gTriMesh; + + nFinalContact++; + } + } + // debug + //if (nFinalContact != ctContacts) + //{ + // printf("[Info] %d contacts generated,%d filtered.\n",ctContacts,ctContacts-nFinalContact); + //} + + delete[] gLocalContacts; + return nFinalContact; +} + +BOOL _cldClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane) +{ + // calculate distance of edge points to plane + dReal fDistance0 = POINTDISTANCE( plPlane, vEpnt0 ); + dReal fDistance1 = POINTDISTANCE( plPlane, vEpnt1 ); + + // if both points are behind the plane + if ( fDistance0 < 0 && fDistance1 < 0 ) + { + // do nothing + return FALSE; + // if both points in front of the plane + } else if ( fDistance0 > 0 && fDistance1 > 0 ) + { + // accept them + return TRUE; + // if we have edge/plane intersection + } else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0)) + { + + // find intersection point of edge and plane + dVector3 vIntersectionPoint; + vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1); + + // clamp correct edge to intersection point + if ( fDistance0 < 0 ) + { + SET(vEpnt0,vIntersectionPoint); + } else + { + SET(vEpnt1,vIntersectionPoint); + } + return TRUE; + } + return TRUE; +} + +static BOOL _cldTestAxis(const dVector3 &v0, + const dVector3 &v1, + const dVector3 &v2, + dVector3 vAxis, + int iAxis, + BOOL bNoFlip = FALSE) +{ + + // calculate length of separating axis vector + dReal fL = LENGTHOF(vAxis); + // if not long enough + // TODO : dReal epsilon please + if ( fL < 1e-5f ) + { + // do nothing + //iLastOutAxis = 0; + return TRUE; + } + + // otherwise normalize it + dNormalize3(vAxis); + + // project capsule on vAxis + dReal frc = dFabs(dDOT(vCapsuleAxis,vAxis))*(fCapsuleSize*REAL(0.5)-vCapsuleRadius) + vCapsuleRadius; + + // project triangle on vAxis + dReal afv[3]; + afv[0] = dDOT( vV0 , vAxis ); + afv[1] = dDOT( vV1 , vAxis ); + afv[2] = dDOT( vV2 , vAxis ); + + dReal fMin = MAX_REAL; + dReal fMax = MIN_REAL; + + // for each vertex + for(int i=0; i<3; i++) + { + // find minimum + if (afv[i]fMax) + { + fMax = afv[i]; + } + } + + // find triangle's center of interval on axis + dReal fCenter = (fMin+fMax)*REAL(0.5); + // calculate triangles half interval + dReal fTriangleRadius = (fMax-fMin)*REAL(0.5); + + // if they do not overlap, + if( dFabs(fCenter) > ( frc + fTriangleRadius ) ) + { + // exit, we have no intersection + return FALSE; + } + + // calculate depth + dReal fDepth = dFabs(fCenter) - (frc+fTriangleRadius); + + // if greater then best found so far + if ( fDepth > fBestDepth ) + { + // remember depth + fBestDepth = fDepth; + fBestCenter = fCenter; + fBestrt = fTriangleRadius; + + vNormal[0] = vAxis[0]; + vNormal[1] = vAxis[1]; + vNormal[2] = vAxis[2]; + + iBestAxis = iAxis; + + // flip normal if interval is wrong faced + if (fCenter<0 && !bNoFlip) + { + vNormal[0] = -vNormal[0]; + vNormal[1] = -vNormal[1]; + vNormal[2] = -vNormal[2]; + + fBestCenter = -fCenter; + } + } + + return TRUE; +} + +// helper for less key strokes +inline void _CalculateAxis(const dVector3& v1, + const dVector3& v2, + const dVector3& v3, + const dVector3& v4, + dVector3& r) +{ + dVector3 t1; + dVector3 t2; + + SUBTRACT(v1,v2,t1); + dCROSS(t2,=,t1,v3); + dCROSS(r,=,t2,v4); +} + +static BOOL _cldTestSeparatingAxesOfCapsule(const dVector3 &v0, + const dVector3 &v1, + const dVector3 &v2) +{ + // calculate caps centers in absolute space + dVector3 vCp0; + vCp0[0] = vCapsulePosition[0] + vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCp0[1] = vCapsulePosition[1] + vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCp0[2] = vCapsulePosition[2] + vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + + dVector3 vCp1; + vCp1[0] = vCapsulePosition[0] - vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCp1[1] = vCapsulePosition[1] - vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCp1[2] = vCapsulePosition[2] - vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + + // reset best axis + iBestAxis = 0; + // reset best depth + fBestDepth = -MAX_REAL; + // reset separating axis vector + dVector3 vAxis = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)}; + + // Epsilon value for checking axis vector length + const dReal fEpsilon = 1e-6f; + + // Translate triangle to Cc cord. + SUBTRACT(v0 , vCapsulePosition, vV0); + SUBTRACT(v1 , vCapsulePosition, vV1); + SUBTRACT(v2 , vCapsulePosition, vV2); + + // We begin to test for 19 separating axis now + // I wonder does it help if we employ the method like ISA-GJK??? + // Or at least we should do experiment and find what axis will + // be most likely to be separating axis to check it first. + + // Original + // axis vN + //vAxis = -vN; + vAxis[0] = - vN[0]; + vAxis[1] = - vN[1]; + vAxis[2] = - vN[2]; + if (!_cldTestAxis( v0, v1, v2, vAxis, 1, TRUE)) + { + return FALSE; + } + + // axis CxE0 - Edge 0 + dCROSS(vAxis,=,vCapsuleAxis,vE0); + //vAxis = dCROSS( vCapsuleAxis cross vE0 ); + if( _length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 2)) { + return FALSE; + } + } + + // axis CxE1 - Edge 1 + dCROSS(vAxis,=,vCapsuleAxis,vE1); + //vAxis = ( vCapsuleAxis cross vE1 ); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 3)) { + return FALSE; + } + } + + // axis CxE2 - Edge 2 + //vAxis = ( vCapsuleAxis cross vE2 ); + dCROSS(vAxis,=,vCapsuleAxis,vE2); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 4)) { + return FALSE; + } + } + + // first capsule point + // axis ((Cp0-V0) x E0) x E0 + _CalculateAxis(vCp0,v0,vE0,vE0,vAxis); +// vAxis = ( ( vCp0-v0) cross vE0 ) cross vE0; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 5)) { + return FALSE; + } + } + + // axis ((Cp0-V1) x E1) x E1 + _CalculateAxis(vCp0,v1,vE1,vE1,vAxis); + //vAxis = ( ( vCp0-v1) cross vE1 ) cross vE1; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 6)) { + return FALSE; + } + } + + // axis ((Cp0-V2) x E2) x E2 + _CalculateAxis(vCp0,v2,vE2,vE2,vAxis); + //vAxis = ( ( vCp0-v2) cross vE2 ) cross vE2; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 7)) { + return FALSE; + } + } + + // second capsule point + // axis ((Cp1-V0) x E0) x E0 + _CalculateAxis(vCp1,v0,vE0,vE0,vAxis); + //vAxis = ( ( vCp1-v0 ) cross vE0 ) cross vE0; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 8)) { + return FALSE; + } + } + + // axis ((Cp1-V1) x E1) x E1 + _CalculateAxis(vCp1,v1,vE1,vE1,vAxis); + //vAxis = ( ( vCp1-v1 ) cross vE1 ) cross vE1; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 9)) { + return FALSE; + } + } + + // axis ((Cp1-V2) x E2) x E2 + _CalculateAxis(vCp1,v2,vE2,vE2,vAxis); + //vAxis = ( ( vCp1-v2 ) cross vE2 ) cross vE2; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 10)) { + return FALSE; + } + } + + // first vertex on triangle + // axis ((V0-Cp0) x C) x C + _CalculateAxis(v0,vCp0,vCapsuleAxis,vCapsuleAxis,vAxis); + //vAxis = ( ( v0-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 11)) { + return FALSE; + } + } + + // second vertex on triangle + // axis ((V1-Cp0) x C) x C + _CalculateAxis(v1,vCp0,vCapsuleAxis,vCapsuleAxis,vAxis); + //vAxis = ( ( v1-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 12)) { + return FALSE; + } + } + + // third vertex on triangle + // axis ((V2-Cp0) x C) x C + _CalculateAxis(v2,vCp0,vCapsuleAxis,vCapsuleAxis,vAxis); + //vAxis = ( ( v2-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis; + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 13)) { + return FALSE; + } + } + + // Test as separating axes direction vectors between each triangle + // edge and each capsule's cap center + + // first triangle vertex and first capsule point + //vAxis = v0 - vCp0; + SUBTRACT(v0,vCp0,vAxis); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 14)) { + return FALSE; + } + } + + // second triangle vertex and first capsule point + //vAxis = v1 - vCp0; + SUBTRACT(v1,vCp0,vAxis); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 15)) { + return FALSE; + } + } + + // third triangle vertex and first capsule point + //vAxis = v2 - vCp0; + SUBTRACT(v2,vCp0,vAxis); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 16)) { + return FALSE; + } + } + + // first triangle vertex and second capsule point + //vAxis = v0 - vCp1; + SUBTRACT(v0,vCp1,vAxis); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 17)) { + return FALSE; + } + } + + // second triangle vertex and second capsule point + //vAxis = v1 - vCp1; + SUBTRACT(v1,vCp1,vAxis); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 18)) { + return FALSE; + } + } + + // third triangle vertex and second capsule point + //vAxis = v2 - vCp1; + SUBTRACT(v2,vCp1,vAxis); + if(_length2OfVector3( vAxis ) > fEpsilon ) { + if (!_cldTestAxis( v0, v1, v2, vAxis, 19)) { + return FALSE; + } + } + + return TRUE; +} + +// test one mesh triangle on intersection with capsule +static void _cldTestOneTriangleVSCCylinder( const dVector3 &v0, + const dVector3 &v1, + const dVector3 &v2 ) +{ + + // calculate edges + SUBTRACT(v1,v0,vE0); + SUBTRACT(v2,v1,vE1); + SUBTRACT(v0,v2,vE2); + + dVector3 _minus_vE0; + SUBTRACT(v0,v1,_minus_vE0); + + // calculate poly normal + dCROSS(vN,=,vE1,_minus_vE0); + dNormalize3(vN); + + // create plane from triangle + dReal plDistance = -dDOT(v0,vN); + dVector4 plTrianglePlane; + CONSTRUCTPLANE(plTrianglePlane,vN,plDistance); + + // calculate capsule distance to plane + dReal fDistanceCapsuleCenterToPlane = POINTDISTANCE(plTrianglePlane,vCapsulePosition); + + // Capsule must be over positive side of triangle + if(fDistanceCapsuleCenterToPlane < 0 /* && !bDoubleSided*/) + { + // if not don't generate contacts + return; + } + + dVector3 vPnt0; + SET (vPnt0,v0); + dVector3 vPnt1; + SET (vPnt1,v1); + dVector3 vPnt2; + SET (vPnt2,v2); + + if (fDistanceCapsuleCenterToPlane < 0 ) + { + SET (vPnt0,v0); + SET (vPnt1,v2); + SET (vPnt2,v1); + } + + // do intersection test and find best separating axis + if(!_cldTestSeparatingAxesOfCapsule(vPnt0, vPnt1, vPnt2) ) + { + // if not found do nothing + return; + } + + // if best separation axis is not found + if ( iBestAxis == 0 ) + { + // this should not happen (we should already exit in that case) + ASSERT(FALSE); + // do nothing + return; + } + + // calculate caps centers in absolute space + dVector3 vCposTrans; + vCposTrans[0] = vCapsulePosition[0] + vNormal[0]*vCapsuleRadius; + vCposTrans[1] = vCapsulePosition[1] + vNormal[1]*vCapsuleRadius; + vCposTrans[2] = vCapsulePosition[2] + vNormal[2]*vCapsuleRadius; + + dVector3 vCEdgePoint0; + vCEdgePoint0[0] = vCposTrans[0] + vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCEdgePoint0[1] = vCposTrans[1] + vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCEdgePoint0[2] = vCposTrans[2] + vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + + dVector3 vCEdgePoint1; + vCEdgePoint1[0] = vCposTrans[0] - vCapsuleAxis[0]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCEdgePoint1[1] = vCposTrans[1] - vCapsuleAxis[1]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + vCEdgePoint1[2] = vCposTrans[2] - vCapsuleAxis[2]*(fCapsuleSize*REAL(0.5)-vCapsuleRadius); + + // transform capsule edge points into triangle space + vCEdgePoint0[0] -= vPnt0[0]; + vCEdgePoint0[1] -= vPnt0[1]; + vCEdgePoint0[2] -= vPnt0[2]; + + vCEdgePoint1[0] -= vPnt0[0]; + vCEdgePoint1[1] -= vPnt0[1]; + vCEdgePoint1[2] -= vPnt0[2]; + + dVector4 plPlane; + dVector3 _minus_vN; + _minus_vN[0] = -vN[0]; + _minus_vN[1] = -vN[1]; + _minus_vN[2] = -vN[2]; + // triangle plane + CONSTRUCTPLANE(plPlane,_minus_vN,0); + //plPlane = Plane4f( -vN, 0); + + if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return; + } + + // plane with edge 0 + dVector3 vTemp; + dCROSS(vTemp,=,vN,vE0); + CONSTRUCTPLANE(plPlane, vTemp, 1e-5f); + if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return; + } + + dCROSS(vTemp,=,vN,vE1); + CONSTRUCTPLANE(plPlane, vTemp, -(dDOT(vE0,vTemp)-1e-5f)); + if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) + { + return; + } + + dCROSS(vTemp,=,vN,vE2); + CONSTRUCTPLANE(plPlane, vTemp, 1e-5f); + if(!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) { + return; + } + + // return capsule edge points into absolute space + vCEdgePoint0[0] += vPnt0[0]; + vCEdgePoint0[1] += vPnt0[1]; + vCEdgePoint0[2] += vPnt0[2]; + + vCEdgePoint1[0] += vPnt0[0]; + vCEdgePoint1[1] += vPnt0[1]; + vCEdgePoint1[2] += vPnt0[2]; + + // calculate depths for both contact points + SUBTRACT(vCEdgePoint0,vCapsulePosition,vTemp); + dReal fDepth0 = dDOT(vTemp,vNormal) - (fBestCenter-fBestrt); + SUBTRACT(vCEdgePoint1,vCapsulePosition,vTemp); + dReal fDepth1 = dDOT(vTemp,vNormal) - (fBestCenter-fBestrt); + + // clamp depths to zero + if(fDepth0 < 0) + { + fDepth0 = 0.0f; + } + + if(fDepth1 < 0 ) + { + fDepth1 = 0.0f; + } + + // Cached contacts's data + // contact 0 + if ((int)ctContacts < (iFlags & NUMC_MASK)) { + gLocalContacts[ctContacts].fDepth = fDepth0; + SET(gLocalContacts[ctContacts].vNormal,vNormal); + SET(gLocalContacts[ctContacts].vPos,vCEdgePoint0); + gLocalContacts[ctContacts].nFlags = 1; + ctContacts++; + + if ((int)ctContacts < (iFlags & NUMC_MASK)) { + // contact 1 + gLocalContacts[ctContacts].fDepth = fDepth1; + SET(gLocalContacts[ctContacts].vNormal,vNormal); + SET(gLocalContacts[ctContacts].vPos,vCEdgePoint1); + gLocalContacts[ctContacts].nFlags = 1; + ctContacts++; + } + } + +} + +// capsule - trimesh by CroTeam +// Ported by Nguyem Binh +int dCollideCCTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip) +{ + dxTriMesh* TriMesh = (dxTriMesh*)o1; + gCylinder = o2; + gTriMesh = o1; + + const dMatrix3* pRot = (const dMatrix3*) dGeomGetRotation(gCylinder); + memcpy(mCapsuleRotation,pRot,sizeof(dMatrix3)); + + const dVector3* pDst = (const dVector3*)dGeomGetPosition(gCylinder); + memcpy(vCapsulePosition,pDst,sizeof(dVector3)); + + vCapsuleAxis[0] = mCapsuleRotation[0*4 + nCAPSULE_AXIS]; + vCapsuleAxis[1] = mCapsuleRotation[1*4 + nCAPSULE_AXIS]; + vCapsuleAxis[2] = mCapsuleRotation[2*4 + nCAPSULE_AXIS]; + + // Get size of CCylinder + dGeomCCylinderGetParams(gCylinder,&vCapsuleRadius,&fCapsuleSize); + fCapsuleSize += 2*vCapsuleRadius; + + const dMatrix3* pTriRot = (const dMatrix3*)dGeomGetRotation(TriMesh); + memcpy(mTriMeshRot,pTriRot,sizeof(dMatrix3)); + + const dVector3* pTriPos = (const dVector3*)dGeomGetPosition(TriMesh); + memcpy(mTriMeshPos,pTriPos,sizeof(dVector3)); + + // global info for contact creation + iStride =skip; + iFlags =flags; + ContactGeoms =contact; + + // reset contact counter + ctContacts = 0; + // allocat local contact workspace + gLocalContacts = new sLocalContactData[(iFlags & NUMC_MASK)]; + + // reset best depth + fBestDepth = - MAX_REAL; + fBestCenter = 0; + fBestrt = 0; + + // reset collision normal + vNormal[0] = REAL(0.0); + vNormal[1] = REAL(0.0); + vNormal[2] = REAL(0.0); + + // Will it better to use LSS here? -> confirm Pierre. + OBBCollider& Collider = TriMesh->_OBBCollider; + + Point cCenter((float) vCapsulePosition[0],(float) vCapsulePosition[1],(float) vCapsulePosition[2]); + Point cExtents((float) vCapsuleRadius,(float) vCapsuleRadius,(float) fCapsuleSize/2); + + Matrix3x3 obbRot; + + obbRot[0][0] = (float) mCapsuleRotation[0]; + obbRot[1][0] = (float) mCapsuleRotation[1]; + obbRot[2][0] = (float) mCapsuleRotation[2]; + + obbRot[0][1] = (float) mCapsuleRotation[4]; + obbRot[1][1] = (float) mCapsuleRotation[5]; + obbRot[2][1] = (float) mCapsuleRotation[6]; + + obbRot[0][2] = (float) mCapsuleRotation[8]; + obbRot[1][2] = (float) mCapsuleRotation[9]; + obbRot[2][2] = (float) mCapsuleRotation[10]; + + OBB obbCCylinder(cCenter,cExtents,obbRot); + + Matrix4x4 CCylinderMatrix; + MakeMatrix(vCapsulePosition, mCapsuleRotation, CCylinderMatrix); + + Matrix4x4 MeshMatrix; + MakeMatrix(mTriMeshPos, mTriMeshRot, MeshMatrix); + + // TC results + if (TriMesh->doBoxTC) { + dxTriMesh::BoxTC* BoxTC = 0; + for (int i = 0; i < TriMesh->BoxTCCache.size(); i++){ + if (TriMesh->BoxTCCache[i].Geom == gCylinder){ + BoxTC = &TriMesh->BoxTCCache[i]; + break; + } + } + if (!BoxTC){ + TriMesh->BoxTCCache.push(dxTriMesh::BoxTC()); + + BoxTC = &TriMesh->BoxTCCache[TriMesh->BoxTCCache.size() - 1]; + BoxTC->Geom = gCylinder; + BoxTC->FatCoeff = 1.0f; + } + + // Intersect + Collider.SetTemporalCoherence(true); + Collider.Collide(*BoxTC, obbCCylinder, TriMesh->Data->BVTree, null, &MeshMatrix); + } + else { + Collider.SetTemporalCoherence(false); + //Collider.Collide(dxTriMesh::defaultBoxCache, obbCCylinder, TriMesh->Data->BVTree, null,&MeshMatrix); + Collider.Collide(TriMesh->boxCache, obbCCylinder, TriMesh->Data->BVTree, null,&MeshMatrix); + } + + // Retrieve data + int TriCount = Collider.GetNbTouchedPrimitives(); + const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); + + if (TriCount != 0) + { + if (TriMesh->ArrayCallback != null) + { + TriMesh->ArrayCallback(TriMesh, gCylinder, Triangles, TriCount); + } + + //int OutTriCount = 0; + + // loop through all intersecting triangles + for (int i = 0; i < TriCount; i++) + { + if((int)ctContacts>=(iFlags & NUMC_MASK)) + { + break; + } + + const int& Triint = Triangles[i]; + if (!Callback(TriMesh, gCylinder, Triint)) continue; + + + dVector3 dv[3]; + FetchTriangle(TriMesh, Triint, mTriMeshPos, mTriMeshRot, dv); + + // test this triangle + _cldTestOneTriangleVSCCylinder(dv[0],dv[1],dv[2]); + + } + } + + return _ProcessLocalContacts(); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_distance.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_distance.cpp new file mode 100644 index 00000000..8246775c --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_distance.cpp @@ -0,0 +1,1264 @@ +// This file contains some code based on the code from Magic Software. +// That code is available under a Free Source License Agreement +// that can be found at http://www.magic-software.com/License/free.pdf + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +#include "ode/ode_common.h" +#include "ode/ode_math.h" +#include "ode/ode_collision.h" +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + + +//------------------------------------------------------------------------------ +/** + @brief Finds the shortest distance squared between a point and a triangle. + + @param pfSParam Barycentric coordinate of triangle at point closest to p (u) + @param pfTParam Barycentric coordinate of triangle at point closest to p (v) + @return Shortest distance squared. + + The third Barycentric coordinate is implicit, ie. w = 1.0 - u - v + + Taken from: + Magic Software, Inc. + http://www.magic-software.com +*/ +dReal SqrDistancePointTri( const dVector3 p, const dVector3 triOrigin, + const dVector3 triEdge0, const dVector3 triEdge1, + dReal* pfSParam, dReal* pfTParam ) +{ + dVector3 kDiff; + Vector3Subtract( triOrigin, p, kDiff ); + dReal fA00 = dDOT( triEdge0, triEdge0 ); + dReal fA01 = dDOT( triEdge0, triEdge1 ); + dReal fA11 = dDOT( triEdge1, triEdge1 ); + dReal fB0 = dDOT( kDiff, triEdge0 ); + dReal fB1 = dDOT( kDiff, triEdge1 ); + dReal fC = dDOT( kDiff, kDiff ); + dReal fDet = dReal(fabs(fA00*fA11-fA01*fA01)); + dReal fS = fA01*fB1-fA11*fB0; + dReal fT = fA01*fB0-fA00*fB1; + dReal fSqrDist; + + if ( fS + fT <= fDet ) + { + if ( fS < REAL(0.0) ) + { + if ( fT < REAL(0.0) ) // region 4 + { + if ( fB0 < REAL(0.0) ) + { + fT = REAL(0.0); + if ( -fB0 >= fA00 ) + { + fS = REAL(1.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else + { + fS = -fB0/fA00; + fSqrDist = fB0*fS+fC; + } + } + else + { + fS = REAL(0.0); + if ( fB1 >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB1 >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = -fB1/fA11; + fSqrDist = fB1*fT+fC; + } + } + } + else // region 3 + { + fS = REAL(0.0); + if ( fB1 >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB1 >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = -fB1/fA11; + fSqrDist = fB1*fT+fC; + } + } + } + else if ( fT < REAL(0.0) ) // region 5 + { + fT = REAL(0.0); + if ( fB0 >= REAL(0.0) ) + { + fS = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB0 >= fA00 ) + { + fS = REAL(1.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else + { + fS = -fB0/fA00; + fSqrDist = fB0*fS+fC; + } + } + else // region 0 + { + // minimum at interior point + if ( fDet == REAL(0.0) ) + { + fS = REAL(0.0); + fT = REAL(0.0); + fSqrDist = dInfinity; + } + else + { + float fInvDet = REAL(1.0)/fDet; + fS *= fInvDet; + fT *= fInvDet; + fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + + fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; + } + } + } + else + { + float fTmp0, fTmp1, fNumer, fDenom; + + if ( fS < REAL(0.0) ) // region 2 + { + fTmp0 = fA01 + fB0; + fTmp1 = fA11 + fB1; + if ( fTmp1 > fTmp0 ) + { + fNumer = fTmp1 - fTmp0; + fDenom = fA00-REAL(2.0)*fA01+fA11; + if ( fNumer >= fDenom ) + { + fS = REAL(1.0); + fT = REAL(0.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else + { + fS = fNumer/fDenom; + fT = REAL(1.0) - fS; + fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + + fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; + } + } + else + { + fS = REAL(0.0); + if ( fTmp1 <= REAL(0.0) ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else if ( fB1 >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fC; + } + else + { + fT = -fB1/fA11; + fSqrDist = fB1*fT+fC; + } + } + } + else if ( fT < REAL(0.0) ) // region 6 + { + fTmp0 = fA01 + fB1; + fTmp1 = fA00 + fB0; + if ( fTmp1 > fTmp0 ) + { + fNumer = fTmp1 - fTmp0; + fDenom = fA00-REAL(2.0)*fA01+fA11; + if ( fNumer >= fDenom ) + { + fT = REAL(1.0); + fS = REAL(0.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = fNumer/fDenom; + fS = REAL(1.0) - fT; + fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + + fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; + } + } + else + { + fT = REAL(0.0); + if ( fTmp1 <= REAL(0.0) ) + { + fS = REAL(1.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else if ( fB0 >= REAL(0.0) ) + { + fS = REAL(0.0); + fSqrDist = fC; + } + else + { + fS = -fB0/fA00; + fSqrDist = fB0*fS+fC; + } + } + } + else // region 1 + { + fNumer = fA11 + fB1 - fA01 - fB0; + if ( fNumer <= REAL(0.0) ) + { + fS = REAL(0.0); + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fDenom = fA00-REAL(2.0)*fA01+fA11; + if ( fNumer >= fDenom ) + { + fS = REAL(1.0); + fT = REAL(0.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else + { + fS = fNumer/fDenom; + fT = REAL(1.0) - fS; + fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + + fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; + } + } + } + } + + if ( pfSParam ) + *pfSParam = (float)fS; + + if ( pfTParam ) + *pfTParam = (float)fT; + + return dReal(fabs(fSqrDist)); +} + +//------------------------------------------------------------------------------ +/** + @brief Finds the shortest distance squared between two line segments. + @param pfSegP0 t value for seg1 where the shortest distance between + the segments exists. + param pfSegP0 t value for seg2 where the shortest distance between + the segments exists. + @return Shortest distance squared. + + Taken from: + Magic Software, Inc. + http://www.magic-software.com +*/ +dReal SqrDistanceSegments( const dVector3 seg1Origin, const dVector3 seg1Direction, + const dVector3 seg2Origin, const dVector3 seg2Direction, + dReal* pfSegP0, dReal* pfSegP1 ) +{ + const dReal gs_fTolerance = 1e-05f; + dVector3 kDiff, kNegDiff, seg1NegDirection; + Vector3Subtract( seg1Origin, seg2Origin, kDiff ); + Vector3Negate( kDiff, kNegDiff ); + dReal fA00 = dDOT( seg1Direction, seg1Direction ); + Vector3Negate( seg1Direction, seg1NegDirection ); + dReal fA01 = dDOT( seg1NegDirection, seg2Direction ); + dReal fA11 = dDOT( seg2Direction, seg2Direction ); + dReal fB0 = dDOT( kDiff, seg1Direction ); + dReal fC = dDOT( kDiff, kDiff ); + dReal fDet = dReal(fabs(fA00*fA11-fA01*fA01)); + dReal fB1, fS, fT, fSqrDist, fTmp; + + if ( fDet >= gs_fTolerance ) + { + // line segments are not parallel + fB1 = dDOT( kNegDiff, seg2Direction ); + fS = fA01*fB1-fA11*fB0; + fT = fA01*fB0-fA00*fB1; + + if ( fS >= REAL(0.0) ) + { + if ( fS <= fDet ) + { + if ( fT >= REAL(0.0) ) + { + if ( fT <= fDet ) // region 0 (interior) + { + // minimum at two interior points of 3D lines + dReal fInvDet = REAL(1.0)/fDet; + fS *= fInvDet; + fT *= fInvDet; + fSqrDist = fS*(fA00*fS+fA01*fT+REAL(2.0)*fB0) + + fT*(fA01*fS+fA11*fT+REAL(2.0)*fB1)+fC; + } + else // region 3 (side) + { + fT = REAL(1.0); + fTmp = fA01+fB0; + if ( fTmp >= REAL(0.0) ) + { + fS = REAL(0.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else if ( -fTmp >= fA00 ) + { + fS = REAL(1.0); + fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB1+fTmp); + } + else + { + fS = -fTmp/fA00; + fSqrDist = fTmp*fS+fA11+REAL(2.0)*fB1+fC; + } + } + } + else // region 7 (side) + { + fT = REAL(0.0); + if ( fB0 >= REAL(0.0) ) + { + fS = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB0 >= fA00 ) + { + fS = REAL(1.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else + { + fS = -fB0/fA00; + fSqrDist = fB0*fS+fC; + } + } + } + else + { + if ( fT >= REAL(0.0) ) + { + if ( fT <= fDet ) // region 1 (side) + { + fS = REAL(1.0); + fTmp = fA01+fB1; + if ( fTmp >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else if ( -fTmp >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB0+fTmp); + } + else + { + fT = -fTmp/fA11; + fSqrDist = fTmp*fT+fA00+REAL(2.0)*fB0+fC; + } + } + else // region 2 (corner) + { + fTmp = fA01+fB0; + if ( -fTmp <= fA00 ) + { + fT = REAL(1.0); + if ( fTmp >= REAL(0.0) ) + { + fS = REAL(0.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fS = -fTmp/fA00; + fSqrDist = fTmp*fS+fA11+REAL(2.0)*fB1+fC; + } + } + else + { + fS = REAL(1.0); + fTmp = fA01+fB1; + if ( fTmp >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else if ( -fTmp >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB0+fTmp); + } + else + { + fT = -fTmp/fA11; + fSqrDist = fTmp*fT+fA00+REAL(2.0)*fB0+fC; + } + } + } + } + else // region 8 (corner) + { + if ( -fB0 < fA00 ) + { + fT = REAL(0.0); + if ( fB0 >= REAL(0.0) ) + { + fS = REAL(0.0); + fSqrDist = fC; + } + else + { + fS = -fB0/fA00; + fSqrDist = fB0*fS+fC; + } + } + else + { + fS = REAL(1.0); + fTmp = fA01+fB1; + if ( fTmp >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else if ( -fTmp >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB0+fTmp); + } + else + { + fT = -fTmp/fA11; + fSqrDist = fTmp*fT+fA00+REAL(2.0)*fB0+fC; + } + } + } + } + } + else + { + if ( fT >= REAL(0.0) ) + { + if ( fT <= fDet ) // region 5 (side) + { + fS = REAL(0.0); + if ( fB1 >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB1 >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = -fB1/fA11; + fSqrDist = fB1*fT+fC; + } + } + else // region 4 (corner) + { + fTmp = fA01+fB0; + if ( fTmp < REAL(0.0) ) + { + fT = REAL(1.0); + if ( -fTmp >= fA00 ) + { + fS = REAL(1.0); + fSqrDist = fA00+fA11+fC+REAL(2.0)*(fB1+fTmp); + } + else + { + fS = -fTmp/fA00; + fSqrDist = fTmp*fS+fA11+REAL(2.0)*fB1+fC; + } + } + else + { + fS = REAL(0.0); + if ( fB1 >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB1 >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = -fB1/fA11; + fSqrDist = fB1*fT+fC; + } + } + } + } + else // region 6 (corner) + { + if ( fB0 < REAL(0.0) ) + { + fT = REAL(0.0); + if ( -fB0 >= fA00 ) + { + fS = REAL(1.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else + { + fS = -fB0/fA00; + fSqrDist = fB0*fS+fC; + } + } + else + { + fS = REAL(0.0); + if ( fB1 >= REAL(0.0) ) + { + fT = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB1 >= fA11 ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = -fB1/fA11; + fSqrDist = fB1*fT+fC; + } + } + } + } + } + else + { + // line segments are parallel + if ( fA01 > REAL(0.0) ) + { + // direction vectors form an obtuse angle + if ( fB0 >= REAL(0.0) ) + { + fS = REAL(0.0); + fT = REAL(0.0); + fSqrDist = fC; + } + else if ( -fB0 <= fA00 ) + { + fS = -fB0/fA00; + fT = REAL(0.0); + fSqrDist = fB0*fS+fC; + } + else + { + //fB1 = -kDiff % seg2.m; + fB1 = dDOT( kNegDiff, seg2Direction ); + fS = REAL(1.0); + fTmp = fA00+fB0; + if ( -fTmp >= fA01 ) + { + fT = REAL(1.0); + fSqrDist = fA00+fA11+fC+REAL(2.0)*(fA01+fB0+fB1); + } + else + { + fT = -fTmp/fA01; + fSqrDist = fA00+REAL(2.0)*fB0+fC+fT*(fA11*fT+REAL(2.0)*(fA01+fB1)); + } + } + } + else + { + // direction vectors form an acute angle + if ( -fB0 >= fA00 ) + { + fS = REAL(1.0); + fT = REAL(0.0); + fSqrDist = fA00+REAL(2.0)*fB0+fC; + } + else if ( fB0 <= REAL(0.0) ) + { + fS = -fB0/fA00; + fT = REAL(0.0); + fSqrDist = fB0*fS+fC; + } + else + { + fB1 = dDOT( kNegDiff, seg2Direction ); + fS = REAL(0.0); + if ( fB0 >= -fA01 ) + { + fT = REAL(1.0); + fSqrDist = fA11+REAL(2.0)*fB1+fC; + } + else + { + fT = -fB0/fA01; + fSqrDist = fC+fT*(REAL(2.0)*fB1+fA11*fT); + } + } + } + } + + if ( pfSegP0 ) + *pfSegP0 = fS; + + if ( pfSegP1 ) + *pfSegP1 = fT; + + return dReal(fabs(fSqrDist)); +} + +//------------------------------------------------------------------------------ +/** + @brief Finds the shortest distance squared between a line segment and + a triangle. + + @param pfSegP t value for the line segment where the shortest distance between + the segment and the triangle occurs. + So the point along the segment that is the shortest distance + away from the triangle can be obtained by (seg.end - seg.start) * t. + @param pfTriP0 Barycentric coordinate of triangle at point closest to seg (u) + @param pfTriP1 Barycentric coordinate of triangle at point closest to seg (v) + @return Shortest distance squared. + + The third Barycentric coordinate is implicit, ie. w = 1.0 - u - v + + Taken from: + Magic Software, Inc. + http://www.magic-software.com +*/ +dReal SqrDistanceSegTri( const dVector3 segOrigin, const dVector3 segEnd, + const dVector3 triOrigin, + const dVector3 triEdge0, const dVector3 triEdge1, + dReal* pfSegP, dReal* pfTriP0, dReal* pfTriP1 ) +{ + const dReal gs_fTolerance = 1e-06f; + dVector3 segDirection, segNegDirection, kDiff, kNegDiff; + Vector3Subtract( segEnd, segOrigin, segDirection ); + Vector3Negate( segDirection, segNegDirection ); + Vector3Subtract( triOrigin, segOrigin, kDiff ); + Vector3Negate( kDiff, kNegDiff ); + dReal fA00 = dDOT( segDirection, segDirection ); + dReal fA01 = dDOT( segNegDirection, triEdge0 ); + dReal fA02 = dDOT( segNegDirection, triEdge1 ); + dReal fA11 = dDOT( triEdge0, triEdge0 ); + dReal fA12 = dDOT( triEdge0, triEdge1 ); + dReal fA22 = dDOT( triEdge1, triEdge1 ); + dReal fB0 = dDOT( kNegDiff, segDirection ); + dReal fB1 = dDOT( kDiff, triEdge0 ); + dReal fB2 = dDOT( kDiff, triEdge1 ); + + dVector3 kTriSegOrigin, kTriSegDirection, kPt; + dReal fSqrDist, fSqrDist0, fR, fS, fT, fR0, fS0, fT0; + + // Set up for a relative error test on the angle between ray direction + // and triangle normal to determine parallel/nonparallel status. + dVector3 kN; + dCROSS( kN, =, triEdge0, triEdge1 ); + dReal fNSqrLen = dDOT( kN, kN ); + dReal fDot = dDOT( segDirection, kN ); + bool bNotParallel = (fDot*fDot >= gs_fTolerance*fA00*fNSqrLen); + + if ( bNotParallel ) + { + dReal fCof00 = fA11*fA22-fA12*fA12; + dReal fCof01 = fA02*fA12-fA01*fA22; + dReal fCof02 = fA01*fA12-fA02*fA11; + dReal fCof11 = fA00*fA22-fA02*fA02; + dReal fCof12 = fA02*fA01-fA00*fA12; + dReal fCof22 = fA00*fA11-fA01*fA01; + dReal fInvDet = REAL(1.0)/(fA00*fCof00+fA01*fCof01+fA02*fCof02); + dReal fRhs0 = -fB0*fInvDet; + dReal fRhs1 = -fB1*fInvDet; + dReal fRhs2 = -fB2*fInvDet; + + fR = fCof00*fRhs0+fCof01*fRhs1+fCof02*fRhs2; + fS = fCof01*fRhs0+fCof11*fRhs1+fCof12*fRhs2; + fT = fCof02*fRhs0+fCof12*fRhs1+fCof22*fRhs2; + + if ( fR < REAL(0.0) ) + { + if ( fS+fT <= REAL(1.0) ) + { + if ( fS < REAL(0.0) ) + { + if ( fT < REAL(0.0) ) // region 4m + { + // min on face s=0 or t=0 or r=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fS0 ); + fT0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 3m + { + // min on face s=0 or r=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR,&fT ); + fS = REAL(0.0); + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + } + else if ( fT < REAL(0.0) ) // region 5m + { + // min on face t=0 or r=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fS ); + fT = REAL(0.0); + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 0m + { + // min on face r=0 + fSqrDist = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS, &fT ); + fR = REAL(0.0); + } + } + else + { + if ( fS < REAL(0.0) ) // region 2m + { + // min on face s=0 or s+t=1 or r=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else if ( fT < REAL(0.0) ) // region 6m + { + // min on face t=0 or s+t=1 or r=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fS ); + fT = REAL(0.0); + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 1m + { + // min on face s+t=1 or r=0 + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(1.0) - fT; + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + } + } + else if ( fR <= REAL(1.0) ) + { + if ( fS+fT <= REAL(1.0) ) + { + if ( fS < REAL(0.0) ) + { + if ( fT < REAL(0.0) ) // region 4 + { + // min on face s=0 or t=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fS0 ); + fT0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 3 + { + // min on face s=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + } + } + else if ( fT < REAL(0.0) ) // region 5 + { + // min on face t=0 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fS ); + fT = REAL(0.0); + } + else // region 0 + { + // global minimum is interior, done + fSqrDist = REAL(0.0); + } + } + else + { + if ( fS < REAL(0.0) ) // region 2 + { + // min on face s=0 or s+t=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else if ( fT < REAL(0.0) ) // region 6 + { + // min on face t=0 or s+t=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fS ); + fT = REAL(0.0); + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 1 + { + // min on face s+t=1 + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(1.0) - fT; + } + } + } + else // fR > 1 + { + if ( fS+fT <= REAL(1.0) ) + { + if ( fS < REAL(0.0) ) + { + if ( fT < REAL(0.0) ) // region 4p + { + // min on face s=0 or t=0 or r=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fS0 ); + fT0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 3p + { + // min on face s=0 or r=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + } + else if ( fT < REAL(0.0) ) // region 5p + { + // min on face t=0 or r=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fS ); + fT = REAL(0.0); + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 0p + { + // min face on r=1 + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS, &fT ); + fR = REAL(1.0); + } + } + else + { + if ( fS < REAL(0.0) ) // region 2p + { + // min on face s=0 or s+t=1 or r=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(0.0); + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else if ( fT < REAL(0.0) ) // region 6p + { + // min on face t=0 or s+t=1 or r=1 + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fS ); + fT = REAL(0.0); + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + else // region 1p + { + // min on face s+t=1 or r=1 + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR, &fT ); + fS = REAL(1.0) - fT; + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + } + } + } + else + { + // segment and triangle are parallel + Vector3Copy( triOrigin, kTriSegOrigin ); + Vector3Copy( triEdge0, kTriSegDirection ); + fSqrDist = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, &fR, &fS ); + fT = REAL(0.0); + + Vector3Copy( triEdge1, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, + &fR0, &fT0 ); + fS0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + + Vector3Add( triOrigin, triEdge0, kTriSegOrigin ); + Vector3Subtract( triEdge1, triEdge0, kTriSegDirection ); + fSqrDist0 = SqrDistanceSegments( segOrigin, segDirection, + kTriSegOrigin, kTriSegDirection, &fR0, &fT0 ); + fS0 = REAL(1.0) - fT0; + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + + fSqrDist0 = SqrDistancePointTri( segOrigin, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(0.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + + Vector3Add( segOrigin, segDirection, kPt ); + fSqrDist0 = SqrDistancePointTri( kPt, triOrigin, triEdge0, triEdge1, + &fS0, &fT0 ); + fR0 = REAL(1.0); + if ( fSqrDist0 < fSqrDist ) + { + fSqrDist = fSqrDist0; + fR = fR0; + fS = fS0; + fT = fT0; + } + } + + if ( pfSegP ) + *pfSegP = fR; + + if ( pfTriP0 ) + *pfTriP0 = fS; + + if ( pfTriP1 ) + *pfTriP1 = fT; + + return fSqrDist; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_internal.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_internal.h new file mode 100644 index 00000000..ba0ee380 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_internal.h @@ -0,0 +1,364 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// TriMesh code by Erwin de Vries. + +#ifndef _ODE_COLLISION_TRIMESH_INTERNAL_H_ +#define _ODE_COLLISION_TRIMESH_INTERNAL_H_ + +// cylinder - trimesh +int dCollideCylinderTrimesh(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); + +int dCollideSTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); +int dCollideBTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); +int dCollideRTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); +int dCollideTTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); +int dCollideCCTL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); +int dCollideTPL(dxGeom *o1, dxGeom *o2, int flags, dContactGeom *contact, int skip); + +//**************************************************************************** +// dxTriMesh class + +#ifdef TRIMESH_INTERNAL + +#include "ode/ode_collision_kernel.h" +#include "ode/ode_collision_trimesh.h" + +#define BAN_OPCODE_AUTOLINK +#include "ode/ode_Opcode.h" +using namespace Opcode; + +struct dxTriMeshData : public dBase { + Model BVTree; + MeshInterface Mesh; + + dxTriMeshData(); + ~dxTriMeshData(); + + void Build(const void* Vertices, int VertexStide, int VertexCount, + const void* Indices, int IndexCount, int TriStride, + const void* Normals, + bool Single); + + /* aabb in model space */ + dVector3 AABBCenter; + dVector3 AABBExtents; + + /* data for use in collison resolution */ + const void* Normals; + //Matrix4x4 last_trans; + dMatrix4 last_trans; +}; + + +struct dxTriMesh : public dxGeom{ + // Callbacks + dTriCallback* Callback; + dTriArrayCallback* ArrayCallback; + dTriRayCallback* RayCallback; + + // Data types + dxTriMeshData* Data; + + + // Colliders + static PlanesCollider _PlanesCollider; + static SphereCollider _SphereCollider; + + + // ericf change.. keep one of these per mesh now for multithreading + + //static OBBCollider _OBBCollider; + OBBCollider _OBBCollider; + + + static RayCollider _RayCollider; + static AABBTreeCollider _AABBTreeCollider; + static LSSCollider _LSSCollider; + + // Some constants + static CollisionFaces Faces; + + // Temporal coherence + struct SphereTC : public SphereCache{ + dxGeom* Geom; + }; + dArray SphereTCCache; + static SphereCache defaultSphereCache; + + struct BoxTC : public OBBCache{ + dxGeom* Geom; + }; + dArray BoxTCCache; + + // ericf change - we keep one of these per trimesh + // so we can multithread.. + //static OBBCache defaultBoxCache; + OBBCache boxCache; + + struct CCylinderTC : public LSSCache{ + dxGeom* Geom; + }; + dArray CCylinderTCCache; + static LSSCache defaultCCylinderCache; + + bool doSphereTC; + bool doBoxTC; + bool doCCylinderTC; + + bool forceNormalMode; + // Functions + dxTriMesh(dSpaceID Space, dTriMeshDataID Data); + ~dxTriMesh(); + + void ClearTCCache(); + + void setForceNormalMode(int f) {forceNormalMode=f;} + + int AABBTest(dxGeom* g, dReal aabb[6]); + void computeAABB(); +}; + +/* // Fetches a contact */ +/* inline dContactGeom* SAFECONTACT(int Flags, dContactGeom* Contacts, int Index, int Stride){ */ +/* dIASSERT(Index >= 0 && Index < (Flags & 0x0ffff)); */ +/* return ((dContactGeom*)(((char*)Contacts) + (Index * Stride))); */ +/* } */ + +// Fetches a triangle +inline void FetchTriangle(dxTriMesh* TriMesh, int Index, dVector3 Out[3]){ + VertexPointers VP; + TriMesh->Data->Mesh.GetTriangle(VP, Index); + for (int i = 0; i < 3; i++){ + Out[i][0] = VP.Vertex[i]->x; + Out[i][1] = VP.Vertex[i]->y; + Out[i][2] = VP.Vertex[i]->z; + Out[i][3] = 0; + } +} + +// Fetches a triangle +inline void FetchTriangle(dxTriMesh* TriMesh, int Index, const dVector3 Position, const dMatrix3 Rotation, dVector3 Out[3]){ + VertexPointers VP; + TriMesh->Data->Mesh.GetTriangle(VP, Index); + for (int i = 0; i < 3; i++){ + dVector3 v; + v[0] = VP.Vertex[i]->x; + v[1] = VP.Vertex[i]->y; + v[2] = VP.Vertex[i]->z; + v[3] = 0; + + dMULTIPLY0_331(Out[i], Rotation, v); + Out[i][0] += Position[0]; + Out[i][1] += Position[1]; + Out[i][2] += Position[2]; + Out[i][3] = 0; + } +} + +// Creates an OPCODE matrix from an ODE matrix +inline Matrix4x4& MakeMatrix(const dVector3 Position, const dMatrix3 Rotation, Matrix4x4& Out){ + Out.m[0][0] = (float) Rotation[0]; + Out.m[1][0] = (float) Rotation[1]; + Out.m[2][0] = (float) Rotation[2]; + + Out.m[0][1] = (float) Rotation[4]; + Out.m[1][1] = (float) Rotation[5]; + Out.m[2][1] = (float) Rotation[6]; + + Out.m[0][2] = (float) Rotation[8]; + Out.m[1][2] = (float) Rotation[9]; + Out.m[2][2] = (float) Rotation[10]; + + Out.m[3][0] = (float) Position[0]; + Out.m[3][1] = (float) Position[1]; + Out.m[3][2] = (float) Position[2]; + + Out.m[0][3] = 0.0f; + Out.m[1][3] = 0.0f; + Out.m[2][3] = 0.0f; + Out.m[3][3] = 1.0f; + + return Out; +} + +// Outputs a matrix to 3 vectors +inline void Decompose(const dMatrix3 Matrix, dVector3 Right, dVector3 Up, dVector3 Direction){ + Right[0] = Matrix[0 * 4 + 0]; + Right[1] = Matrix[1 * 4 + 0]; + Right[2] = Matrix[2 * 4 + 0]; + Right[3] = REAL(0.0); + Up[0] = Matrix[0 * 4 + 1]; + Up[1] = Matrix[1 * 4 + 1]; + Up[2] = Matrix[2 * 4 + 1]; + Up[3] = REAL(0.0); + Direction[0] = Matrix[0 * 4 + 2]; + Direction[1] = Matrix[1 * 4 + 2]; + Direction[2] = Matrix[2 * 4 + 2]; + Direction[3] = REAL(0.0); +} + +// Outputs a matrix to 3 vectors +inline void Decompose(const dMatrix3 Matrix, dVector3 Vectors[3]){ + Decompose(Matrix, Vectors[0], Vectors[1], Vectors[2]); +} + +// Creates an OPCODE matrix from an ODE matrix +inline Matrix4x4& MakeMatrix(dxGeom* g, Matrix4x4& Out){ + const dVector3& Position = *(const dVector3*)dGeomGetPosition(g); + const dMatrix3& Rotation = *(const dMatrix3*)dGeomGetRotation(g); + return MakeMatrix(Position, Rotation, Out); +} + +// Finds barycentric +inline void GetPointFromBarycentric(const dVector3 dv[3], dReal u, dReal v, dVector3 Out){ + dReal w = REAL(1.0) - u - v; + + Out[0] = (dv[0][0] * w) + (dv[1][0] * u) + (dv[2][0] * v); + Out[1] = (dv[0][1] * w) + (dv[1][1] * u) + (dv[2][1] * v); + Out[2] = (dv[0][2] * w) + (dv[1][2] * u) + (dv[2][2] * v); + Out[3] = (dv[0][3] * w) + (dv[1][3] * u) + (dv[2][3] * v); +} + +// Performs a callback +inline bool Callback(dxTriMesh* TriMesh, dxGeom* Object, int TriIndex){ + if (TriMesh->Callback != null){ + return TriMesh->Callback(TriMesh, Object, TriIndex); + } + else return true; +} + +// Some utilities +template const T& dcMAX(const T& x, const T& y){ + return x > y ? x : y; +} + +template const T& dcMIN(const T& x, const T& y){ + return x < y ? x : y; +} + +dReal SqrDistancePointTri( const dVector3 p, const dVector3 triOrigin, + const dVector3 triEdge1, const dVector3 triEdge2, + dReal* pfSParam = 0, dReal* pfTParam = 0 ); + +dReal SqrDistanceSegments( const dVector3 seg1Origin, const dVector3 seg1Direction, + const dVector3 seg2Origin, const dVector3 seg2Direction, + dReal* pfSegP0 = 0, dReal* pfSegP1 = 0 ); + +dReal SqrDistanceSegTri( const dVector3 segOrigin, const dVector3 segEnd, + const dVector3 triOrigin, + const dVector3 triEdge1, const dVector3 triEdge2, + dReal* t = 0, dReal* u = 0, dReal* v = 0 ); + +inline +void Vector3Subtract( const dVector3 left, const dVector3 right, dVector3 result ) +{ + result[0] = left[0] - right[0]; + result[1] = left[1] - right[1]; + result[2] = left[2] - right[2]; + result[3] = REAL(0.0); +} + +inline +void Vector3Add( const dVector3 left, const dVector3 right, dVector3 result ) +{ + result[0] = left[0] + right[0]; + result[1] = left[1] + right[1]; + result[2] = left[2] + right[2]; + result[3] = REAL(0.0); +} + +inline +void Vector3Negate( const dVector3 in, dVector3 out ) +{ + out[0] = -in[0]; + out[1] = -in[1]; + out[2] = -in[2]; + out[3] = REAL(0.0); +} + +inline +void Vector3Copy( const dVector3 in, dVector3 out ) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + out[3] = REAL(0.0); +} + +inline +void Vector3Multiply( const dVector3 in, dReal scalar, dVector3 out ) +{ + out[0] = in[0] * scalar; + out[1] = in[1] * scalar; + out[2] = in[2] * scalar; + out[3] = REAL(0.0); +} + +inline +void TransformVector3( const dVector3 in, + const dMatrix3 orientation, const dVector3 position, + dVector3 out ) +{ + dMULTIPLY0_331( out, orientation, in ); + out[0] += position[0]; + out[1] += position[1]; + out[2] += position[2]; +} + +//------------------------------------------------------------------------------ +/** + @brief Check for intersection between triangle and capsule. + + @param dist [out] Shortest distance squared between the triangle and + the capsule segment (central axis). + @param t [out] t value of point on segment that's the shortest distance + away from the triangle, the coordinates of this point + can be found by (cap.seg.end - cap.seg.start) * t, + or cap.seg.ipol(t). + @param u [out] Barycentric coord on triangle. + @param v [out] Barycentric coord on triangle. + @return True if intersection exists. + + The third Barycentric coord is implicit, ie. w = 1.0 - u - v + The Barycentric coords give the location of the point on the triangle + closest to the capsule (where the distance between the two shapes + is the shortest). +*/ +inline +bool IntersectCapsuleTri( const dVector3 segOrigin, const dVector3 segEnd, + const dReal radius, const dVector3 triOrigin, + const dVector3 triEdge0, const dVector3 triEdge1, + dReal* dist, dReal* t, dReal* u, dReal* v ) +{ + dReal sqrDist = SqrDistanceSegTri( segOrigin, segEnd, triOrigin, triEdge0, triEdge1, + t, u, v ); + + if ( dist ) + *dist = sqrDist; + + return ( sqrDist <= (radius * radius) ); +} + +#endif //TRIMESH_INTERNAL + +#endif //_ODE_COLLISION_TRIMESH_INTERNAL_H_ diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_plane.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_plane.cpp new file mode 100644 index 00000000..5ff9a9d4 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_plane.cpp @@ -0,0 +1,129 @@ +// TriMesh vs Plane. +// +// CURRENT STATE: +// - Meshes collide with planes, but require a large number of contacts. +// - Have simple contact reduction (basically takes the contacts with the greatest depth). +// TODO LIST: +// - Reduce the number of contacts better. +// +//-James Dolan. + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +#define REDUCE_CONTACTS 1 + +int dCollideTPL(dxGeom* gmesh, dxGeom* gplane, int Flags, dContactGeom* Contacts, int Stride) +{ + //printf("eep\n"); + int ret = 0; + dxTriMesh *pTriMesh = (dxTriMesh *) gmesh; + dReal planeEq[4]; + Matrix4x4 WMat; + const dVector3 &TLPosition = *(const dVector3*)dGeomGetPosition(pTriMesh); + const dMatrix3 &TLRotation = *(const dMatrix3*)dGeomGetRotation(pTriMesh); + PlanesCache planeCache; + dxBody *pTriMeshBody = pTriMesh->body; + + if(!pTriMeshBody) + return ret; + + PlanesCollider &planeCollider = pTriMesh->_PlanesCollider; + + dGeomPlaneGetParams(gplane, planeEq); + + planeCollider.Collide(planeCache, (Plane *)planeEq, 1, pTriMesh->Data->BVTree, &MakeMatrix(TLPosition, TLRotation, WMat)); + + int iTriCount = planeCollider.GetNbTouchedPrimitives(); + + if(iTriCount > 0) + { + const int *pIndices = (const int*)planeCollider.GetTouchedPrimitives(); + if(pTriMesh->ArrayCallback) + { + pTriMesh->ArrayCallback(pTriMesh, gplane, pIndices, iTriCount); + } + int iOutContactCount = 0; + int iMaxContactCount = (Flags & 0xffff); + for(int i=0; i 0) + { + if(iOutContactCount < iMaxContactCount) + { + // Just add the contact. + dContactGeom *pContact = SAFECONTACT(Flags, Contacts, iOutContactCount, Stride); + *pContact = tNewContact; + iOutContactCount++; + } + else + { + #if REDUCE_CONTACTS + // Replace the contact with the shortest depth + // assuming our depth is greater. + dContactGeom *pContact = SAFECONTACT(Flags, Contacts, 0, Stride); + for(int j=1; jdepth < pContact->depth) + { + pContact = pTemp; + } + } + if(pContact->depth < tNewContact.depth) + { + *pContact = tNewContact; + } + #else + break; + #endif + } + } + } + ret = iOutContactCount; + } + + return ret; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ray.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ray.cpp new file mode 100644 index 00000000..d539c944 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_ray.cpp @@ -0,0 +1,134 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +// TriMesh code by Erwin de Vries. + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +int dCollideRTL(dxGeom* g1, dxGeom* RayGeom, int Flags, dContactGeom* Contacts, int Stride){ + dxTriMesh* TriMesh = (dxTriMesh*)g1; + + const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh); + const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh); + + RayCollider& Collider = TriMesh->_RayCollider; + + dReal Length = dGeomRayGetLength(RayGeom); + + int FirstContact, BackfaceCull; + dGeomRayGetParams(RayGeom, &FirstContact, &BackfaceCull); + int ClosestHit = dGeomRayGetClosestHit(RayGeom); + + Collider.SetFirstContact(FirstContact != 0); + Collider.SetClosestHit(ClosestHit != 0); + Collider.SetCulling(BackfaceCull != 0); + Collider.SetMaxDist(Length); + + dVector3 Origin, Direction; + dGeomRayGet(RayGeom, Origin, Direction); + + /* Make Ray */ + Ray WorldRay; + WorldRay.mOrig.x = Origin[0]; + WorldRay.mOrig.y = Origin[1]; + WorldRay.mOrig.z = Origin[2]; + WorldRay.mDir.x = Direction[0]; + WorldRay.mDir.y = Direction[1]; + WorldRay.mDir.z = Direction[2]; + + /* Intersect */ + Matrix4x4 amatrix; + int TriCount = 0; + if (Collider.Collide(WorldRay, TriMesh->Data->BVTree, &MakeMatrix(TLPosition, TLRotation, amatrix))) { + TriCount = TriMesh->Faces.GetNbFaces(); + } + + if (TriCount == 0) { + return 0; + } + + const CollisionFace* Faces = TriMesh->Faces.GetFaces(); + + int OutTriCount = 0; + for (int i = 0; i < TriCount; i++) { + if (OutTriCount == (Flags & 0xffff)) { + break; + } + if (TriMesh->RayCallback == null || + TriMesh->RayCallback(TriMesh, RayGeom, Faces[i].mFaceID, + Faces[i].mU, Faces[i].mV)) { + const int& TriIndex = Faces[i].mFaceID; + if (!Callback(TriMesh, RayGeom, TriIndex)) { + continue; + } + + dContactGeom* Contact = SAFECONTACT(Flags, Contacts, OutTriCount, Stride); + + dVector3 dv[3]; + FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv); + + float T = Faces[i].mDistance; + Contact->pos[0] = Origin[0] + (Direction[0] * T); + Contact->pos[1] = Origin[1] + (Direction[1] * T); + Contact->pos[2] = Origin[2] + (Direction[2] * T); + Contact->pos[3] = REAL(0.0); + + dVector3 vu; + vu[0] = dv[1][0] - dv[0][0]; + vu[1] = dv[1][1] - dv[0][1]; + vu[2] = dv[1][2] - dv[0][2]; + vu[3] = REAL(0.0); + + dVector3 vv; + vv[0] = dv[2][0] - dv[0][0]; + vv[1] = dv[2][1] - dv[0][1]; + vv[2] = dv[2][2] - dv[0][2]; + vv[3] = REAL(0.0); + + dCROSS(Contact->normal, =, vv, vu); // Reversed + + dNormalize3(Contact->normal); + + Contact->depth = T; + Contact->g1 = TriMesh; + Contact->g2 = RayGeom; + + OutTriCount++; + } + } + return OutTriCount; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_sphere.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_sphere.cpp new file mode 100644 index 00000000..ed2bb560 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_sphere.cpp @@ -0,0 +1,502 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +// TriMesh code by Erwin de Vries. + +#include + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +#define MERGECONTACTS + +// Ripped from Opcode 1.1. +static bool GetContactData(const dVector3& Center, dReal Radius, const dVector3 Origin, const dVector3 Edge0, const dVector3 Edge1, dReal& Dist, float& u, float& v){ + //calculate plane of triangle + dVector4 Plane; + dCROSS(Plane, =, Edge0, Edge1); + Plane[3] = dDOT(Plane, Origin); + + double min = 0.00000001; + + if ((std::abs(Plane[0]) <= min) && (std::abs(Plane[1]) <= min) + && (std::abs(Plane[2]) <= min) && (std::abs(Plane[3]) <= min)){ + printf("ode_collision_trimesh_sphere.cpp: Plane vector has zero length..\n"); + printf("vals: %f %f %f %f\n", std::abs(Plane[0]), std::abs(Plane[1]), std::abs(Plane[2]), std::abs(Plane[3])); + return 0; + } + //normalize + dNormalize4(Plane); + + /* If the center of the sphere is within the positive halfspace of the + * triangle's plane, allow a contact to be generated. + * If the center of the sphere made it into the positive halfspace of a + * back-facing triangle, then the physics update and/or velocity needs + * to be adjusted (penetration has occured anyway). + */ + + float side = dDOT(Plane,Center) - Plane[3]; + + if(side < 0.0f) { + return false; + } + + // now onto the bulk of the collision... + + dVector3 Diff; + Diff[0] = Origin[0] - Center[0]; + Diff[1] = Origin[1] - Center[1]; + Diff[2] = Origin[2] - Center[2]; + Diff[3] = Origin[3] - Center[3]; + + float A00 = dDOT(Edge0, Edge0); + float A01 = dDOT(Edge0, Edge1); + float A11 = dDOT(Edge1, Edge1); + + float B0 = dDOT(Diff, Edge0); + float B1 = dDOT(Diff, Edge1); + + float C = dDOT(Diff, Diff); + + float Det = dFabs(A00 * A11 - A01 * A01); + u = A01 * B1 - A11 * B0; + v = A01 * B0 - A00 * B1; + + float DistSq; + + if (u + v <= Det){ + if(u < REAL(0.0)){ + if(v < REAL(0.0)){ // region 4 + if(B0 < REAL(0.0)){ + v = REAL(0.0); + if (-B0 >= A00){ + u = REAL(1.0); + DistSq = A00 + REAL(2.0) * B0 + C; + } + else{ + u = -B0 / A00; + DistSq = B0 * u + C; + } + } + else{ + u = REAL(0.0); + if(B1 >= REAL(0.0)){ + v = REAL(0.0); + DistSq = C; + } + else if(-B1 >= A11){ + v = REAL(1.0); + DistSq = A11 + REAL(2.0) * B1 + C; + } + else{ + v = -B1 / A11; + DistSq = B1 * v + C; + } + } + } + else{ // region 3 + u = REAL(0.0); + if(B1 >= REAL(0.0)){ + v = REAL(0.0); + DistSq = C; + } + else if(-B1 >= A11){ + v = REAL(1.0); + DistSq = A11 + REAL(2.0) * B1 + C; + } + else{ + v = -B1 / A11; + DistSq = B1 * v + C; + } + } + } + else if(v < REAL(0.0)){ // region 5 + v = REAL(0.0); + if (B0 >= REAL(0.0)){ + u = REAL(0.0); + DistSq = C; + } + else if (-B0 >= A00){ + u = REAL(1.0); + DistSq = A00 + REAL(2.0) * B0 + C; + } + else{ + u = -B0 / A00; + DistSq = B0 * u + C; + } + } + else{ // region 0 + // minimum at interior point + if (Det == REAL(0.0)){ + u = REAL(0.0); + v = REAL(0.0); + DistSq = FLT_MAX; + } + else{ + float InvDet = REAL(1.0) / Det; + u *= InvDet; + v *= InvDet; + DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; + } + } + } + else{ + float Tmp0, Tmp1, Numer, Denom; + + if(u < REAL(0.0)){ // region 2 + Tmp0 = A01 + B0; + Tmp1 = A11 + B1; + if (Tmp1 > Tmp0){ + Numer = Tmp1 - Tmp0; + Denom = A00 - REAL(2.0) * A01 + A11; + if (Numer >= Denom){ + u = REAL(1.0); + v = REAL(0.0); + DistSq = A00 + REAL(2.0) * B0 + C; + } + else{ + u = Numer / Denom; + v = REAL(1.0) - u; + DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; + } + } + else{ + u = REAL(0.0); + if(Tmp1 <= REAL(0.0)){ + v = REAL(1.0); + DistSq = A11 + REAL(2.0) * B1 + C; + } + else if(B1 >= REAL(0.0)){ + v = REAL(0.0); + DistSq = C; + } + else{ + v = -B1 / A11; + DistSq = B1 * v + C; + } + } + } + else if(v < REAL(0.0)){ // region 6 + Tmp0 = A01 + B1; + Tmp1 = A00 + B0; + if (Tmp1 > Tmp0){ + Numer = Tmp1 - Tmp0; + Denom = A00 - REAL(2.0) * A01 + A11; + if (Numer >= Denom){ + v = REAL(1.0); + u = REAL(0.0); + DistSq = A11 + REAL(2.0) * B1 + C; + } + else{ + v = Numer / Denom; + u = REAL(1.0) - v; + DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; + } + } + else{ + v = REAL(0.0); + if (Tmp1 <= REAL(0.0)){ + u = REAL(1.0); + DistSq = A00 + REAL(2.0) * B0 + C; + } + else if(B0 >= REAL(0.0)){ + u = REAL(0.0); + DistSq = C; + } + else{ + u = -B0 / A00; + DistSq = B0 * u + C; + } + } + } + else{ // region 1 + Numer = A11 + B1 - A01 - B0; + if (Numer <= REAL(0.0)){ + u = REAL(0.0); + v = REAL(1.0); + DistSq = A11 + REAL(2.0) * B1 + C; + } + else{ + Denom = A00 - REAL(2.0) * A01 + A11; + if (Numer >= Denom){ + u = REAL(1.0); + v = REAL(0.0); + DistSq = A00 + REAL(2.0) * B0 + C; + } + else{ + u = Numer / Denom; + v = REAL(1.0) - u; + DistSq = u * (A00 * u + A01 * v + REAL(2.0) * B0) + v * (A01 * u + A11 * v + REAL(2.0) * B1) + C; + } + } + } + } + + Dist = dSqrt(dFabs(DistSq)); + + if (Dist <= Radius){ + Dist = Radius - Dist; + return true; + } + else return false; +} + +int dCollideSTL(dxGeom* g1, dxGeom* SphereGeom, int Flags, dContactGeom* Contacts, int Stride){ + dxTriMesh* TriMesh = (dxTriMesh*)g1; + + // Init + const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh); + const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh); + + SphereCollider& Collider = TriMesh->_SphereCollider; + + const dVector3& Position = *(const dVector3*)dGeomGetPosition(SphereGeom); + dReal Radius = dGeomSphereGetRadius(SphereGeom); + + // Sphere + Sphere Sphere; + Sphere.mCenter.x = Position[0]; + Sphere.mCenter.y = Position[1]; + Sphere.mCenter.z = Position[2]; + Sphere.mRadius = Radius; + + Matrix4x4 amatrix; + + // TC results + if (TriMesh->doSphereTC) { + dxTriMesh::SphereTC* sphereTC = 0; + for (int i = 0; i < TriMesh->SphereTCCache.size(); i++){ + if (TriMesh->SphereTCCache[i].Geom == SphereGeom){ + sphereTC = &TriMesh->SphereTCCache[i]; + break; + } + } + + if (!sphereTC){ + TriMesh->SphereTCCache.push(dxTriMesh::SphereTC()); + + sphereTC = &TriMesh->SphereTCCache[TriMesh->SphereTCCache.size() - 1]; + sphereTC->Geom = SphereGeom; + } + + // Intersect + Collider.SetTemporalCoherence(true); + Collider.Collide(*sphereTC, Sphere, TriMesh->Data->BVTree, null, + &MakeMatrix(TLPosition, TLRotation, amatrix)); + } + else { + Collider.SetTemporalCoherence(false); + Collider.Collide(dxTriMesh::defaultSphereCache, Sphere, TriMesh->Data->BVTree, null, + &MakeMatrix(TLPosition, TLRotation, amatrix)); + } + + // get results + int TriCount = Collider.GetNbTouchedPrimitives(); + const int* Triangles = (const int*)Collider.GetTouchedPrimitives(); + + if (TriCount != 0){ + if (TriMesh->ArrayCallback != null){ + TriMesh->ArrayCallback(TriMesh, SphereGeom, Triangles, TriCount); + } + + int OutTriCount = 0; + for (int i = 0; i < TriCount; i++){ + if (OutTriCount == (Flags & 0xffff)){ + break; + } + + const int& TriIndex = Triangles[i]; + + dVector3 dv[3]; + FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv); + + dVector3& v0 = dv[0]; + dVector3& v1 = dv[1]; + dVector3& v2 = dv[2]; + + dVector3 vu; + vu[0] = v1[0] - v0[0]; + vu[1] = v1[1] - v0[1]; + vu[2] = v1[2] - v0[2]; + vu[3] = REAL(0.0); + + dVector3 vv; + vv[0] = v2[0] - v0[0]; + vv[1] = v2[1] - v0[1]; + vv[2] = v2[2] - v0[2]; + vv[3] = REAL(0.0); + + dReal Depth; + float u, v; + if (!GetContactData(Position, Radius, v0, vu, vv, Depth, u, v)){ + continue; // Sphere doesnt hit triangle + } + dReal w = REAL(1.0) - u - v; + + if (Depth < REAL(0.0)){ + Depth = REAL(0.0); + } + + dContactGeom* Contact = SAFECONTACT(Flags, Contacts, OutTriCount, Stride); + + Contact->pos[0] = (v0[0] * w) + (v1[0] * u) + (v2[0] * v); + Contact->pos[1] = (v0[1] * w) + (v1[1] * u) + (v2[1] * v); + Contact->pos[2] = (v0[2] * w) + (v1[2] * u) + (v2[2] * v); + Contact->pos[3] = REAL(0.0); + + dVector4 Plane; + dCROSS(Plane, =, vv, vu); // Reversed + Plane[3] = dDOT(Plane, v0); // Using normal as plane. + + dReal Area = dSqrt(dDOT(Plane, Plane)); // We can use this later + Plane[0] /= Area; + Plane[1] /= Area; + Plane[2] /= Area; + Plane[3] /= Area; + + Contact->normal[0] = Plane[0]; + Contact->normal[1] = Plane[1]; + Contact->normal[2] = Plane[2]; + Contact->normal[3] = REAL(0.0); + + Contact->depth = Depth; + + //Contact->g1 = TriMesh; + //Contact->g2 = SphereGeom; + + OutTriCount++; + } + +#ifdef MERGECONTACTS // Merge all contacts into 1 + if (OutTriCount != 0){ + dContactGeom* Contact = SAFECONTACT(Flags, Contacts, 0, Stride); + + if (OutTriCount != 1){ + Contact->normal[0] *= Contact->depth; + Contact->normal[1] *= Contact->depth; + Contact->normal[2] *= Contact->depth; + Contact->normal[3] *= Contact->depth; + + for (int i = 1; i < OutTriCount; i++){ + dContactGeom* TempContact = SAFECONTACT(Flags, Contacts, i, Stride); + + Contact->pos[0] += TempContact->pos[0]; + Contact->pos[1] += TempContact->pos[1]; + Contact->pos[2] += TempContact->pos[2]; + Contact->pos[3] += TempContact->pos[3]; + + Contact->normal[0] += TempContact->normal[0] * TempContact->depth; + Contact->normal[1] += TempContact->normal[1] * TempContact->depth; + Contact->normal[2] += TempContact->normal[2] * TempContact->depth; + Contact->normal[3] += TempContact->normal[3] * TempContact->depth; + } + + Contact->pos[0] /= OutTriCount; + Contact->pos[1] /= OutTriCount; + Contact->pos[2] /= OutTriCount; + Contact->pos[3] /= OutTriCount; + + // Remember to divide in square space. + Contact->depth = dSqrt(dDOT(Contact->normal, Contact->normal) / OutTriCount); + + dNormalize3(Contact->normal); + } + + Contact->g1 = TriMesh; + Contact->g2 = SphereGeom; + + return 1; + } + else return 0; +#elif defined MERGECONTACTNORMALS // Merge all normals, and distribute between all contacts + if (OutTriCount != 0){ + if (OutTriCount != 1){ + dVector3& Normal = SAFECONTACT(Flags, Contacts, 0, Stride)->normal; + Normal[0] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; + Normal[1] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; + Normal[2] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; + Normal[3] *= SAFECONTACT(Flags, Contacts, 0, Stride)->depth; + + for (int i = 1; i < OutTriCount; i++){ + dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride); + + Normal[0] += Contact->normal[0] * Contact->depth; + Normal[1] += Contact->normal[1] * Contact->depth; + Normal[2] += Contact->normal[2] * Contact->depth; + Normal[3] += Contact->normal[3] * Contact->depth; + } + dNormalize3(Normal); + + for (int i = 1; i < OutTriCount; i++){ + dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride); + + Contact->normal[0] = Normal[0]; + Contact->normal[1] = Normal[1]; + Contact->normal[2] = Normal[2]; + Contact->normal[3] = Normal[3]; + + Contact->g1 = TriMesh; + Contact->g2 = SphereGeom; + } + } + else{ + SAFECONTACT(Flags, Contacts, 0, Stride)->g1 = TriMesh; + SAFECONTACT(Flags, Contacts, 0, Stride)->g2 = SphereGeom; + } + + return OutTriCount; + } + else return 0; +#else //MERGECONTACTNORMALS // Just gather penetration depths and return + for (int i = 0; i < OutTriCount; i++){ + dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride); + + //Contact->depth = dSqrt(dDOT(Contact->normal, Contact->normal)); + + /*Contact->normal[0] /= Contact->depth; + Contact->normal[1] /= Contact->depth; + Contact->normal[2] /= Contact->depth; + Contact->normal[3] /= Contact->depth;*/ + + Contact->g1 = TriMesh; + Contact->g2 = SphereGeom; + } + + return OutTriCount; +#endif // MERGECONTACTS + } + else return 0; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_trimesh.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_trimesh.cpp new file mode 100644 index 00000000..581baea2 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_trimesh_trimesh.cpp @@ -0,0 +1,2162 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + + // Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +// TriMesh/TriMesh collision code by Jeff Smith (c) 2004 +// + +#ifdef _MSC_VER +#include +#pragma warning(disable:4244 4305) // for VC++, no precision loss complaints +//static inline double round(double x){return x >= 0.0 ? floor(x + 0.5) : ceil(x - 0.5);} +#endif + +#include "ode/ode_collision.h" +#include "ode/ode_matrix.h" +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" +#include + + +#define TRIMESH_INTERNAL +#include "ode/ode_collision_trimesh_internal.h" + +#define SMALL_ELT 2.5e-4 +#define EXPANDED_ELT_THRESH 1.0e-3 +#define DISTANCE_EPSILON 1.0e-8 +#define VELOCITY_EPSILON 1.0e-5 +#define TINY_PENETRATION 5.0e-6 + +// new method for tri on tri intersection by Eric Froemling +// it is pretty much a stripped out version of the original +// which no longer uses body velocity information (we want resting contacts to somewhat work) +// it basically assigns the contact normal to be one of the two face normals in a random-ish fashion +// and the penetration depth is the co-normal distance between any two vertices A and B, +// i.e. d = DOT(n, (A-B)) - this can erroneously return huge penetration depths +// so we rely somewhat on contact filtering, penetration depth limiting, etc outside of the ode lib + +// another improvement over the original is that if fewer contacts are requested than we find, +// the contacts we return are sampled evenly across the list of contacts - in the old code +// just the first n contacts would be returned, which would usually be clustered to one side of a +// collision area thus creating incorrect collisionss + +#define ERICF_METHOD 1 + +struct LineContactSet +{ + dVector3 Points[8]; + int Count; +}; + + +//static void GetTriangleGeometryCallback(udword, VertexPointers&, udword); +static void GenerateContact(int, dContactGeom*, int, dxTriMesh*, dxTriMesh*, + const dVector3, const dVector3, dReal, int&); +static int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], + dReal U0[3],dReal U1[3],dReal U2[3],int *coplanar, + dReal isectpt1[3],dReal isectpt2[3]); +inline void dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B); +static void dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ); +//static int IntersectLineSegmentRay(dVector3, dVector3, dVector3, dVector3, dVector3); +#ifndef ERICF_METHOD +static bool FindTriSolidIntrsection(const dVector3 Tri[3], + const dVector4 Planes[6], int numSides, + LineContactSet& ClippedPolygon ); +static bool SimpleUnclippedTest(dVector3 in_CoplanarPt, dVector3 in_v, dVector3 in_elt, + dVector3 in_n, dVector3* in_col_v, dReal &out_depth); +static void ClipConvexPolygonAgainstPlane( const dVector3, dReal, LineContactSet& ); +static int ExamineContactPoint(dVector3* v_col, dVector3 in_n, dVector3 in_point); +static int RayTriangleIntersect(const dVector3 orig, const dVector3 dir, + const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, + dReal *t,dReal *u,dReal *v); +#endif + + + + +/* some math macros */ +#define CROSS(dest,v1,v2) { dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \ + dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \ + dest[2]=v1[0]*v2[1]-v1[1]*v2[0]; } + +#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2]) + +#define SUB(dest,v1,v2) { dest[0]=v1[0]-v2[0]; dest[1]=v1[1]-v2[1]; dest[2]=v1[2]-v2[2]; } + +#define ADD(dest,v1,v2) { dest[0]=v1[0]+v2[0]; dest[1]=v1[1]+v2[1]; dest[2]=v1[2]+v2[2]; } + +#define MULT(dest,v,factor) { dest[0]=factor*v[0]; dest[1]=factor*v[1]; dest[2]=factor*v[2]; } + +#define SET(dest,src) { dest[0]=src[0]; dest[1]=src[1]; dest[2]=src[2]; } + +#define SMULT(p,q,s) { p[0]=q[0]*s; p[1]=q[1]*s; p[2]=q[2]*s; } + +#define COMBO(combo,p,t,q) { combo[0]=p[0]+t*q[0]; combo[1]=p[1]+t*q[1]; combo[2]=p[2]+t*q[2]; } + +#define LENGTH(x) ((dReal) dSqrt(dDOT(x, x))) + +#define DEPTH(d, p, q, n) d = (p[0] - q[0])*n[0] + (p[1] - q[1])*n[1] + (p[2] - q[2])*n[2]; + +inline const dReal dMin(const dReal x, const dReal y) +{ + return x < y ? x : y; +} + + +inline void +SwapNormals(dVector3 *&pen_v, dVector3 *&col_v, dVector3* v1, dVector3* v2, + dVector3 *&pen_elt, dVector3 *elt_f1, dVector3 *elt_f2, + dVector3 n, dVector3 n1, dVector3 n2) +{ + if (pen_v == v1) { + pen_v = v2; + pen_elt = elt_f2; + col_v = v1; + SET(n, n1); + } + else { + pen_v = v1; + pen_elt = elt_f1; + col_v = v2; + SET(n, n2); + } +} + + + + +int +dCollideTTL(dxGeom* g1, dxGeom* g2, int Flags, dContactGeom* Contacts, int Stride) +{ + dxTriMesh* TriMesh1 = (dxTriMesh*) g1; + dxTriMesh* TriMesh2 = (dxTriMesh*) g2; + + dReal * TriNormals1 = (dReal *) TriMesh1->Data->Normals; + dReal * TriNormals2 = (dReal *) TriMesh2->Data->Normals; + + const dVector3& TLPosition1 = *(const dVector3*) dGeomGetPosition(TriMesh1); + // TLRotation1 = column-major order + const dMatrix3& TLRotation1 = *(const dMatrix3*) dGeomGetRotation(TriMesh1); + + const dVector3& TLPosition2 = *(const dVector3*) dGeomGetPosition(TriMesh2); + // TLRotation2 = column-major order + const dMatrix3& TLRotation2 = *(const dMatrix3*) dGeomGetRotation(TriMesh2); + + AABBTreeCollider& Collider = TriMesh1->_AABBTreeCollider; + + static BVTCache ColCache; + ColCache.Model0 = &TriMesh1->Data->BVTree; + ColCache.Model1 = &TriMesh2->Data->BVTree; + + // Collision query + Matrix4x4 amatrix, bmatrix; + BOOL IsOk = Collider.Collide(ColCache, + &MakeMatrix(TLPosition1, TLRotation1, amatrix), + &MakeMatrix(TLPosition2, TLRotation2, bmatrix) ); + + + // Make "double" versions of these matrices, if appropriate + dMatrix4 A, B; + dMakeMatrix4(TLPosition1, TLRotation1, A); + dMakeMatrix4(TLPosition2, TLRotation2, B); + + + if (IsOk) { + // Get collision status => if true, objects overlap + if ( Collider.GetContactStatus() ) { + // Number of colliding pairs and list of pairs + int TriCount = Collider.GetNbPairs(); + int requestedCount = Flags & 0xffff; + const Pair* CollidingPairs = Collider.GetPairs(); + +#if ERICF_METHOD + if (TriCount > 0){ + int OutTriCount = 0; + int id1, id2; + dVector3 v1[3], v2[3], CoplanarPt; + dVector3 e1, e2, n1, n2, n; + dReal depth; + + // only do these expensive inversions once + dMatrix4 InvMatrix1, InvMatrix2; + dInvertMatrix4(A, InvMatrix1); + dInvertMatrix4(B, InvMatrix2); + + bool forceNormal1 = false; + bool forceNormal2 = false; + if (TriMesh1->forceNormalMode) + forceNormal1 = true; + if (TriMesh2->forceNormalMode) + forceNormal2 = true; + if (forceNormal1 && forceNormal2){ + forceNormal1 = false; + forceNormal2 = false; + } + + //if they want less than we have, we skip around so as not to return only one side, etc + float triInterval = (float)TriCount/requestedCount; + if (triInterval < 1) triInterval = 1; + //cout << "they want " << requestedCount << " we have " << TriCount << " using interval " << triInterval << endl; + int i; + int iteration = 0; + for (float iFloat = 0; iFloat < TriCount; iFloat += triInterval){ + iteration++; + i = (int)round(iFloat); + if (i >= TriCount) + break; + if (OutTriCount < requestedCount) { + + int IsCoplanar = 0; + dReal IsectPt1[3], IsectPt2[3]; + + id1 = CollidingPairs[i].id0; + id2 = CollidingPairs[i].id1; + + // grab the colliding triangles + FetchTriangle((dxTriMesh*) g1, id1, TLPosition1, TLRotation1, v1); + FetchTriangle((dxTriMesh*) g2, id2, TLPosition2, TLRotation2, v2); + // Since we'll be doing matrix transfomrations, we need to + // make sure that all vertices have four elements + for (int j=0; j<3; j++) { + v1[j][3] = 1.0; + v2[j][3] = 1.0; + } + + if (TriTriIntersectWithIsectLine( v1[0], v1[1], v1[2], v2[0], v2[1], v2[2],&IsCoplanar, + IsectPt1, IsectPt2) ){ + + //cout << "got contact " << i << endl; + + // Compute the normals of the colliding faces + if (TriNormals1 == NULL) { + SUB( e1, v1[1], v1[0] ); + SUB( e2, v1[2], v1[0] ); + CROSS( n1, e1, e2 ); + dNormalize3(n1); + } + else { + // If we were passed normals, we need to adjust them to take into + // account the objects' current rotations + e1[0] = TriNormals1[id1*3]; + e1[1] = TriNormals1[id1*3 + 1]; + e1[2] = TriNormals1[id1*3 + 2]; + e1[3] = 0.0; + + //dMultiply1(n1, TLRotation1, e1, 3, 3, 1); + dMultiply0(n1, TLRotation1, e1, 3, 3, 1); + n1[3] = 1.0; + } + + if (TriNormals2 == NULL) { + SUB( e1, v2[1], v2[0] ); + SUB( e2, v2[2], v2[0] ); + CROSS( n2, e1, e2); + dNormalize3(n2); + } + else { + // If we were passed normals, we need to adjust them to take into + // account the objects' current rotations + e2[0] = TriNormals2[id2*3]; + e2[1] = TriNormals2[id2*3 + 1]; + e2[2] = TriNormals2[id2*3 + 2]; + e2[3] = 0.0; + + //dMultiply1(n2, TLRotation2, e2, 3, 3, 1); + dMultiply0(n2, TLRotation2, e2, 3, 3, 1); + n2[3] = 1.0; + } + + if (IsCoplanar) { + // We can reach this case if the faces are coplanar, OR + // if they don't actually intersect. (OPCODE can make + // mistakes) + if (fabs(dDOT(n1, n2)) > 0.999) { + // If the faces are coplanar, we declare that the point of + // contact is at the average location of the vertices of + // both faces + dVector3 ContactPt; + for (int j=0; j<3; j++) { + ContactPt[j] = 0.0; + for (int k=0; k<3; k++) + ContactPt[j] += v1[k][j] + v2[k][j]; + ContactPt[j] /= 6.0; + } + ContactPt[3] = 1.0; + + // and the contact normal is the normal of face 2 + // (could be face 1, because they are the same) + SET(n, n2); + + // and the penetration depth is the co-normal + // distance between any two vertices A and B, + // i.e. d = DOT(n, (A-B)) + DEPTH(depth, v1[1], v2[1], n); + if (depth < 0) + depth *= -1.0; + + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + ContactPt, n, depth, OutTriCount); + } + } + else{ + for (int j=0; j<3; j++) + CoplanarPt[j] = (dReal) ( (IsectPt1[j] + IsectPt2[j]) / 2.0 ); + CoplanarPt[3] = 1.0; + + dVector3 ContactPt; + for (int j=0; j<3; j++) + ContactPt[j] = CoplanarPt[j]; + + if (((iteration%2==0) || forceNormal2) && (!forceNormal1)){ + //if (i%2==0){ + SET(n,n2); + for (int j = 0;j<3;j++) + n[j]*=-1; + } + else{ + SET(n, n1); + } + + depth = 0.01; + + // and the penetration depth is the co-normal + // distance between any two vertices A and B, + // i.e. d = DOT(n, (A-B)) + DEPTH(depth, v1[1], v2[1], n); + if (depth < 0) + depth *= -1.0; + + GenerateContact(Flags,Contacts,Stride,TriMesh1,TriMesh2, + ContactPt, n, depth, OutTriCount); + } + + } + } + else + break; + } + return OutTriCount; + } +#else + + if (TriCount > 0) { + // step through the pairs, adding contacts + int id1, id2; + int OutTriCount = 0; + dVector3 v1[3], v2[3], CoplanarPt; + dVector3 e1, e2, e3, n1, n2, n, ContactNormal; + dReal depth; + dVector3 orig_pos, old_pos1, old_pos2, elt1, elt2, elt_sum; + dVector3 elt_f1[3], elt_f2[3]; + dReal contact_elt_length = SMALL_ELT; + LineContactSet firstClippedTri, secondClippedTri; + dVector3 *firstClippedElt = NULL; + dVector3 *secondClippedElt = NULL; + + + // only do these expensive inversions once + dMatrix4 InvMatrix1, InvMatrix2; + dInvertMatrix4(A, InvMatrix1); + dInvertMatrix4(B, InvMatrix2); + + + for (int i = 0; i < TriCount; i++){ + if (OutTriCount < (Flags & 0xffff)) { + + id1 = CollidingPairs[i].id0; + id2 = CollidingPairs[i].id1; + + // grab the colliding triangles + FetchTriangle((dxTriMesh*) g1, id1, TLPosition1, TLRotation1, v1); + FetchTriangle((dxTriMesh*) g2, id2, TLPosition2, TLRotation2, v2); + // Since we'll be doing matrix transfomrations, we need to + // make sure that all vertices have four elements + for (int j=0; j<3; j++) { + v1[j][3] = 1.0; + v2[j][3] = 1.0; + } + + + int IsCoplanar = 0; + dReal IsectPt1[3], IsectPt2[3]; + + // Sometimes OPCODE makes mistakes, so we look at the return + // value for TriTriIntersectWithIsectLine. A retcode of "0" + // means no intersection took place + if ( TriTriIntersectWithIsectLine( v1[0], v1[1], v1[2], v2[0], v2[1], v2[2], + &IsCoplanar, + IsectPt1, IsectPt2) ) { + + // Compute the normals of the colliding faces + // + if (TriNormals1 == NULL) { + SUB( e1, v1[1], v1[0] ); + SUB( e2, v1[2], v1[0] ); + CROSS( n1, e1, e2 ); + dNormalize3(n1); + } + else { + // If we were passed normals, we need to adjust them to take into + // account the objects' current rotations + e1[0] = TriNormals1[id1*3]; + e1[1] = TriNormals1[id1*3 + 1]; + e1[2] = TriNormals1[id1*3 + 2]; + e1[3] = 0.0; + + //dMultiply1(n1, TLRotation1, e1, 3, 3, 1); + dMultiply0(n1, TLRotation1, e1, 3, 3, 1); + n1[3] = 1.0; + } + + if (TriNormals2 == NULL) { + SUB( e1, v2[1], v2[0] ); + SUB( e2, v2[2], v2[0] ); + CROSS( n2, e1, e2); + dNormalize3(n2); + } + else { + // If we were passed normals, we need to adjust them to take into + // account the objects' current rotations + e2[0] = TriNormals2[id2*3]; + e2[1] = TriNormals2[id2*3 + 1]; + e2[2] = TriNormals2[id2*3 + 2]; + e2[3] = 0.0; + + //dMultiply1(n2, TLRotation2, e2, 3, 3, 1); + dMultiply0(n2, TLRotation2, e2, 3, 3, 1); + n2[3] = 1.0; + } + + + if (IsCoplanar) { + // We can reach this case if the faces are coplanar, OR + // if they don't actually intersect. (OPCODE can make + // mistakes) + if (fabs(dDOT(n1, n2)) > 0.999) { + // If the faces are coplanar, we declare that the point of + // contact is at the average location of the vertices of + // both faces + dVector3 ContactPt; + for (int j=0; j<3; j++) { + ContactPt[j] = 0.0; + for (int k=0; k<3; k++) + ContactPt[j] += v1[k][j] + v2[k][j]; + ContactPt[j] /= 6.0; + } + ContactPt[3] = 1.0; + + // and the contact normal is the normal of face 2 + // (could be face 1, because they are the same) + SET(n, n2); + + // and the penetration depth is the co-normal + // distance between any two vertices A and B, + // i.e. d = DOT(n, (A-B)) + DEPTH(depth, v1[1], v2[1], n); + if (depth < 0) + depth *= -1.0; + + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + ContactPt, n, depth, OutTriCount); + } + } + else { + // Otherwise (in non-co-planar cases), we create a coplanar + // point -- the middle of the line of intersection -- that + // will be used for various computations down the road + for (int j=0; j<3; j++) + CoplanarPt[j] = (dReal) ( (IsectPt1[j] + IsectPt2[j]) / 2.0 ); + CoplanarPt[3] = 1.0; + + // Find the ELT of the coplanar point + // + dMultiply1(orig_pos, InvMatrix1, CoplanarPt, 4, 4, 1); + dMultiply1(old_pos1, TriMesh1->Data->last_trans, orig_pos, 4, 4, 1); + SUB(elt1, CoplanarPt, old_pos1); + + dMultiply1(orig_pos, InvMatrix2, CoplanarPt, 4, 4, 1); + dMultiply1(old_pos2, TriMesh2->Data->last_trans, orig_pos, 4, 4, 1); + SUB(elt2, CoplanarPt, old_pos2); + + SUB(elt_sum, elt1, elt2); // net motion of the coplanar point + + + // Calculate how much the vertices of each face moved in the + // direction of the opposite face's normal + // + dReal total_dp1, total_dp2; + total_dp1 = 0.0; + total_dp2 = 0.0; + + for (int ii=0; ii<3; ii++) { + // find the estimated linear translation (ELT) of the vertices + // on face 1, wrt to the center of face 2. + + // un-transform this vertex by the current transform + dMultiply1(orig_pos, InvMatrix1, v1[ii], 4, 4, 1 ); + + // re-transform this vertex by last_trans (to get its old + // position) + dMultiply1(old_pos1, TriMesh1->Data->last_trans, orig_pos, 4, 4, 1); + + // Then subtract this position from our current one to find + // the elapsed linear translation (ELT) + for (int k=0; k<3; k++) { + elt_f1[ii][k] = (v1[ii][k] - old_pos1[k]) - elt2[k]; + } + + // Take the dot product of the ELT for each vertex (wrt the + // center of face2) + total_dp1 += fabs( dDOT(elt_f1[ii], n2) ); + } + + for (int ii=0; ii<3; ii++) { + // find the estimated linear translation (ELT) of the vertices + // on face 2, wrt to the center of face 1. + dMultiply1(orig_pos, InvMatrix2, v2[ii], 4, 4, 1); + dMultiply1(old_pos2, TriMesh2->Data->last_trans, orig_pos, 4, 4, 1); + for (int k=0; k<3; k++) { + elt_f2[ii][k] = (v2[ii][k] - old_pos2[k]) - elt1[k]; + } + + // Take the dot product of the ELT for each vertex (wrt the + // center of face2) and add them + total_dp2 += fabs( dDOT(elt_f2[ii], n1) ); + } + + + //////// + // Estimate the penetration depth. + // + dReal dp; + BOOL badPen = true; + dVector3 *pen_v; // the "penetrating vertices" + dVector3 *pen_elt; // the elt_f of the penetrating face + dVector3 *col_v; // the "collision vertices" (the penetrated face) + + + depth = 0.0; + if ((total_dp1 > DISTANCE_EPSILON) || (total_dp2 > DISTANCE_EPSILON)) { + //////// + // Find the collision normal, by finding the face + // that is pointed "most" in the direction of travel + // of the two triangles + // + if (total_dp2 > total_dp1) { + pen_v = v2; + pen_elt = elt_f2; + col_v = v1; + SET(n, n1); + } + else { + pen_v = v1; + pen_elt = elt_f1; + col_v = v2; + SET(n, n2); + } + } + else { + // the total_dp is very small, so let's fall back + // to a different test + if (LENGTH(elt2) > LENGTH(elt1)) { + pen_v = v2; + pen_elt = elt_f2; + col_v = v1; + SET(n, n1); + } + else { + pen_v = v1; + pen_elt = elt_f1; + col_v = v2; + SET(n, n2); + } + } + + + for (int j=0; j<3; j++) + if (SimpleUnclippedTest(CoplanarPt, pen_v[j], pen_elt[j], n, col_v, depth)) { + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + pen_v[j], n, depth, OutTriCount); + badPen = false; + } + + + if (badPen) { + // try the other normal + SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); + + for (int j=0; j<3; j++) + if (SimpleUnclippedTest(CoplanarPt, pen_v[j], pen_elt[j], n, col_v, depth)) { + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + pen_v[j], n, depth, OutTriCount); + badPen = false; + } + } + + + + //////////////////////////////////////// + // + // If we haven't found a good penetration, then we're probably straddling + // the edge of one of the objects, or the penetraing face is big + // enough that all of its vertices are outside the bounds of the + // penetrated face. + // In these cases, we do a more expensive test. We clip the penetrating + // triangle with a solid defined by the penetrated triangle, and repeat + // the tests above on this new polygon + if (badPen) { + + // Switch pen_v and n back again + SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); + + + // Find the three sides (no top or bottom) of the solid defined by + // the edges of the penetrated triangle. + + // The dVector4 "plane" structures contain the following information: + // [0]-[2]: The normal of the face, pointing INWARDS (i.e. + // the inverse normal + // [3]: The distance between the face and the center of the + // solid, along the normal + dVector4 SolidPlanes[3]; + dVector3 tmp1; + dVector3 sn; + + for (int j=0; j<3; j++) { + e1[j] = col_v[1][j] - col_v[0][j]; + e2[j] = col_v[0][j] - col_v[2][j]; + e3[j] = col_v[2][j] - col_v[1][j]; + } + + // side 1 + CROSS(sn, e1, n); + dNormalize3(sn); + SMULT( SolidPlanes[0], sn, -1.0 ); + + ADD(tmp1, col_v[0], col_v[1]); + SMULT(tmp1, tmp1, 0.5); // center of edge + // distance from center to edge along normal + SolidPlanes[0][3] = dDOT(tmp1, SolidPlanes[0]); + + + // side 2 + CROSS(sn, e2, n); + dNormalize3(sn); + SMULT( SolidPlanes[1], sn, -1.0 ); + + ADD(tmp1, col_v[0], col_v[2]); + SMULT(tmp1, tmp1, 0.5); // center of edge + // distance from center to edge along normal + SolidPlanes[1][3] = dDOT(tmp1, SolidPlanes[1]); + + + // side 3 + CROSS(sn, e3, n); + dNormalize3(sn); + SMULT( SolidPlanes[2], sn, -1.0 ); + + ADD(tmp1, col_v[2], col_v[1]); + SMULT(tmp1, tmp1, 0.5); // center of edge + // distance from center to edge along normal + SolidPlanes[2][3] = dDOT(tmp1, SolidPlanes[2]); + + + FindTriSolidIntrsection(pen_v, SolidPlanes, 3, firstClippedTri); + + firstClippedElt = new dVector3[firstClippedTri.Count]; + + for (int j=0; jData->last_trans, orig_pos, 4, 4, 1); + for (int k=0; k<3; k++) { + firstClippedElt[j][k] = (firstClippedTri.Points[j][k] - old_pos1[k]) - elt2[k]; + } + } + else { + dMultiply1(orig_pos, InvMatrix2, firstClippedTri.Points[j], 4, 4, 1); + dMultiply1(old_pos2, TriMesh2->Data->last_trans, orig_pos, 4, 4, 1); + for (int k=0; k<3; k++) { + firstClippedElt[j][k] = (firstClippedTri.Points[j][k] - old_pos2[k]) - elt1[k]; + } + } + + contact_elt_length = fabs(dDOT(firstClippedElt[j], n)); + + if (dp >= 0.0) { + depth = dp; + if (depth == 0.0) + depth = dMin(DISTANCE_EPSILON, contact_elt_length); + + if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) + depth = contact_elt_length; + + if (depth <= contact_elt_length) { + // Add a contact + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + firstClippedTri.Points[j], n, depth, OutTriCount); + badPen = false; + } + } + + } + } + + if (badPen) { + // Switch pen_v and n (again!) + SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); + + + // Find the three sides (no top or bottom) of the solid created by + // the penetrated triangle. + // The dVector4 "plane" structures contain the following information: + // [0]-[2]: The normal of the face, pointing INWARDS (i.e. + // the inverse normal + // [3]: The distance between the face and the center of the + // solid, along the normal + dVector4 SolidPlanes[3]; + dVector3 tmp1; + + dVector3 sn; + for (int j=0; j<3; j++) { + e1[j] = col_v[1][j] - col_v[0][j]; + e2[j] = col_v[0][j] - col_v[2][j]; + e3[j] = col_v[2][j] - col_v[1][j]; + } + + // side 1 + CROSS(sn, e1, n); + dNormalize3(sn); + SMULT( SolidPlanes[0], sn, -1.0 ); + + ADD(tmp1, col_v[0], col_v[1]); + SMULT(tmp1, tmp1, 0.5); // center of edge + // distance from center to edge along normal + SolidPlanes[0][3] = dDOT(tmp1, SolidPlanes[0]); + + + // side 2 + CROSS(sn, e2, n); + dNormalize3(sn); + SMULT( SolidPlanes[1], sn, -1.0 ); + + ADD(tmp1, col_v[0], col_v[2]); + SMULT(tmp1, tmp1, 0.5); // center of edge + // distance from center to edge along normal + SolidPlanes[1][3] = dDOT(tmp1, SolidPlanes[1]); + + + // side 3 + CROSS(sn, e3, n); + dNormalize3(sn); + SMULT( SolidPlanes[2], sn, -1.0 ); + + ADD(tmp1, col_v[2], col_v[1]); + SMULT(tmp1, tmp1, 0.5); // center of edge + // distance from center to edge along normal + SolidPlanes[2][3] = dDOT(tmp1, SolidPlanes[2]); + + FindTriSolidIntrsection(pen_v, SolidPlanes, 3, secondClippedTri); + + secondClippedElt = new dVector3[secondClippedTri.Count]; + + for (int j=0; jData->last_trans, orig_pos, 4, 4, 1); + for (int k=0; k<3; k++) { + secondClippedElt[j][k] = (secondClippedTri.Points[j][k] - old_pos1[k]) - elt2[k]; + } + } + else { + dMultiply1(orig_pos, InvMatrix2, secondClippedTri.Points[j], 4, 4, 1); + dMultiply1(old_pos2, TriMesh2->Data->last_trans, orig_pos, 4, 4, 1); + for (int k=0; k<3; k++) { + secondClippedElt[j][k] = (secondClippedTri.Points[j][k] - old_pos2[k]) - elt1[k]; + } + } + + + contact_elt_length = fabs(dDOT(secondClippedElt[j],n)); + + if (dp >= 0.0) { + depth = dp; + if (depth == 0.0) + depth = dMin(DISTANCE_EPSILON, contact_elt_length); + + if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) + depth = contact_elt_length; + + if (depth <= contact_elt_length) { + // Add a contact + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + secondClippedTri.Points[j], n, depth, OutTriCount); + badPen = false; + } + } + + + } + } + + + + ///////////////// + // All conventional tests have failed at this point, so now we deal with + // cases on a more "heuristic" basis + // + + if (badPen) { + // Switch pen_v and n (for the fourth time, so they're + // what my original guess said they were) + SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); + + if (fabs(dDOT(n1, n2)) < 0.01) { + // If we reach this point, we have (close to) perpindicular + // faces, either resting on each other or sliding in a + // direction orthogonal to both surface normals. + if (LENGTH(elt_sum) < DISTANCE_EPSILON) { + depth = (dReal) fabs(dDOT(n, elt_sum)); + + if (depth > 1e-12) { + dNormalize3(n); + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + CoplanarPt, n, depth, OutTriCount); + badPen = false; + } + else { + // If the two faces are (nearly) perfectly at rest with + // respect to each other, then we ignore the contact, + // allowing the objects to slip a little in the hopes + // that next frame, they'll give us something to work + // with. + badPen = false; + } + } + else { + // The faces are perpindicular, but moving significantly + // This can be sliding, or an unusual edge-straddling + // penetration. + dVector3 cn; + + CROSS(cn, n1, n2); + dNormalize3(cn); + SET(n, cn); + + // The shallowest ineterpenetration of the faces + // is the depth + dVector3 ContactPt; + dVector3 dvTmp; + dReal rTmp; + depth = dInfinity; + for (int j=0; j<3; j++) { + for (int k=0; k<3; k++) { + SUB(dvTmp, col_v[k], pen_v[j]); + + rTmp = dDOT(dvTmp, n); + if ( fabs(rTmp) < fabs(depth) ) { + depth = rTmp; + SET( ContactPt, pen_v[j] ); + contact_elt_length = fabs(dDOT(pen_elt[j], n)); + } + } + } + if (depth < 0.0) { + SMULT(n, n, -1.0); + depth *= -1.0; + } + + if ((depth > 0.0) && (depth <= contact_elt_length)) { + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + ContactPt, n, depth, OutTriCount); + badPen = false; + } + + } + } + } + + + if (badPen) { + // Use as the normal the direction of travel, rather than any particular + // face normal + // + dVector3 esn; + + if (pen_v == v1) { + SMULT(esn, elt_sum, -1.0); + } + else { + SET(esn, elt_sum); + } + dNormalize3(esn); + + + // The shallowest ineterpenetration of the faces + // is the depth + dVector3 ContactPt; + depth = dInfinity; + for (int j=0; j<3; j++) { + for (int k=0; k<3; k++) { + DEPTH(dp, col_v[k], pen_v[j], esn); + if ( (ExamineContactPoint(col_v, esn, pen_v[j])) && + ( fabs(dp) < fabs(depth)) ) { + depth = dp; + SET( ContactPt, pen_v[j] ); + contact_elt_length = fabs(dDOT(pen_elt[j], esn)); + } + } + } + + if ((depth > 0.0) && (depth <= contact_elt_length)) { + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + ContactPt, esn, depth, OutTriCount); + badPen = false; + } + } + + + if (badPen) { + // If the direction of motion is perpindicular to both normals + if ( (fabs(dDOT(n1, elt_sum)) < 0.01) && (fabs(dDOT(n2, elt_sum)) < 0.01) ) { + dVector3 esn; + if (pen_v == v1) { + SMULT(esn, elt_sum, -1.0); + } + else { + SET(esn, elt_sum); + } + + dNormalize3(esn); + + + // Look at the clipped points again, checking them against this + // new normal + for (int j=0; j= 0.0) { + contact_elt_length = fabs(dDOT(firstClippedElt[j], esn)); + + depth = dp; + //if (depth == 0.0) + //depth = dMin(DISTANCE_EPSILON, contact_elt_length); + + if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) + depth = contact_elt_length; + + if (depth <= contact_elt_length) { + // Add a contact + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + firstClippedTri.Points[j], esn, depth, OutTriCount); + badPen = false; + } + } + } + + if (badPen) { + // If this test failed, try it with the second set of clipped faces + for (int j=0; j= 0.0) { + contact_elt_length = fabs(dDOT(secondClippedElt[j], esn)); + + depth = dp; + //if (depth == 0.0) + //depth = dMin(DISTANCE_EPSILON, contact_elt_length); + + if ((contact_elt_length < SMALL_ELT) && (depth < EXPANDED_ELT_THRESH)) + depth = contact_elt_length; + + if (depth <= contact_elt_length) { + // Add a contact + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + secondClippedTri.Points[j], esn, depth, OutTriCount); + badPen = false; + } + } + } + } + } + } + + + + if (badPen) { + // if we have very little motion, we're dealing with resting contact + // and shouldn't reference the ELTs at all + // + if (LENGTH(elt_sum) < VELOCITY_EPSILON) { + + // instead of a "contact_elt_length" threshhold, we'll use an + // arbitrary, small one + for (int j=0; j<3; j++) { + DEPTH(dp, CoplanarPt, pen_v[j], n); + + if (dp == 0.0) + dp = TINY_PENETRATION; + + if ( (dp > 0.0) && (dp <= SMALL_ELT)) { + // Add a contact + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + pen_v[j], n, (dReal) dp, OutTriCount); + badPen = false; + } + } + + + if (badPen) { + // try the other normal + SwapNormals(pen_v, col_v, v1, v2, pen_elt, elt_f1, elt_f2, n, n1, n2); + + for (int j=0; j<3; j++) { + DEPTH(dp, CoplanarPt, pen_v[j], n); + + if (dp == 0.0) + dp = TINY_PENETRATION; + + if ( (dp > 0.0) && (dp <= SMALL_ELT)) { + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + pen_v[j], n, (dReal) dp, OutTriCount); + badPen = false; + } + } + } + + + + } + } + + if (badPen) { + // find the nearest existing contact, and replicate it's + // normal and depth + // + dContactGeom* Contact; + dVector3 pos_diff; + dReal min_dist, dist; + + min_dist = dInfinity; + depth = 0.0; + for (int j=0; jpos, CoplanarPt); + + dist = dDOT(pos_diff, pos_diff); + if (dist < min_dist) { + min_dist = dist; + depth = Contact->depth; + SMULT(ContactNormal, Contact->normal, -1.0); + } + } + + if (depth > 0.0) { + // Add a tiny contact at the coplanar point + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + CoplanarPt, ContactNormal, depth, OutTriCount); + badPen = false; + } + } + + + if (badPen) { + // Add a tiny contact at the coplanar point + if (-dDOT(elt_sum, n1) > -dDOT(elt_sum, n2)) { + SET(ContactNormal, n1); + } + else { + SET(ContactNormal, n2); + } + + GenerateContact(Flags, Contacts, Stride, TriMesh1, TriMesh2, + CoplanarPt, ContactNormal, TINY_PENETRATION, OutTriCount); + badPen = false; + } + + + } // not coplanar (main loop) + } // TriTriIntersectWithIsectLine + + // Free memory + delete[] firstClippedElt; + firstClippedElt = NULL; + delete[] secondClippedElt; + secondClippedElt = NULL; + + } // if (OutTriCount < (Flags & 0xffff)) + } + // Return the number of contacts + return OutTriCount; + + } +#endif //eric method + + } + } + + + // There was some kind of failure during the Collide call or + // there are no faces overlapping + return 0; +} + + + +// static void +// GetTriangleGeometryCallback(udword triangleindex, VertexPointers& triangle, udword user_data) +// { +// dVector3 Out[3]; + +// FetchTriangle((dxTriMesh*) user_data, (int) triangleindex, Out); + +// for (int i = 0; i < 3; i++) +// triangle.Vertex[i] = (const Point*) ((dReal*) Out[i]); +// } + + +// +// +// +#define B11 B[0] +#define B12 B[1] +#define B13 B[2] +#define B14 B[3] +#define B21 B[4] +#define B22 B[5] +#define B23 B[6] +#define B24 B[7] +#define B31 B[8] +#define B32 B[9] +#define B33 B[10] +#define B34 B[11] +#define B41 B[12] +#define B42 B[13] +#define B43 B[14] +#define B44 B[15] + +#define Binv11 Binv[0] +#define Binv12 Binv[1] +#define Binv13 Binv[2] +#define Binv14 Binv[3] +#define Binv21 Binv[4] +#define Binv22 Binv[5] +#define Binv23 Binv[6] +#define Binv24 Binv[7] +#define Binv31 Binv[8] +#define Binv32 Binv[9] +#define Binv33 Binv[10] +#define Binv34 Binv[11] +#define Binv41 Binv[12] +#define Binv42 Binv[13] +#define Binv43 Binv[14] +#define Binv44 Binv[15] + +inline void +dMakeMatrix4(const dVector3 Position, const dMatrix3 Rotation, dMatrix4 &B) +{ + B11 = Rotation[0]; B21 = Rotation[1]; B31 = Rotation[2]; B41 = Position[0]; + B12 = Rotation[4]; B22 = Rotation[5]; B32 = Rotation[6]; B42 = Position[1]; + B13 = Rotation[8]; B23 = Rotation[9]; B33 = Rotation[10]; B43 = Position[2]; + + B14 = 0.0; B24 = 0.0; B34 = 0.0; B44 = 1.0; +} + + +static void +dInvertMatrix4( dMatrix4& B, dMatrix4& Binv ) +{ + dReal det = (B11 * B22 - B12 * B21) * (B33 * B44 - B34 * B43) + -(B11 * B23 - B13 * B21) * (B32 * B44 - B34 * B42) + +(B11 * B24 - B14 * B21) * (B32 * B43 - B33 * B42) + +(B12 * B23 - B13 * B22) * (B31 * B44 - B34 * B41) + -(B12 * B24 - B14 * B22) * (B31 * B43 - B33 * B41) + +(B13 * B24 - B14 * B23) * (B31 * B42 - B32 * B41); + + dAASSERT (det != 0.0); + + det = 1.0 / det; + + Binv11 = (dReal) (det * ((B22 * B33) - (B23 * B32))); + Binv12 = (dReal) (det * ((B32 * B13) - (B33 * B12))); + Binv13 = (dReal) (det * ((B12 * B23) - (B13 * B22))); + Binv14 = 0.0f; + Binv21 = (dReal) (det * ((B23 * B31) - (B21 * B33))); + Binv22 = (dReal) (det * ((B33 * B11) - (B31 * B13))); + Binv23 = (dReal) (det * ((B13 * B21) - (B11 * B23))); + Binv24 = 0.0f; + Binv31 = (dReal) (det * ((B21 * B32) - (B22 * B31))); + Binv32 = (dReal) (det * ((B31 * B12) - (B32 * B11))); + Binv33 = (dReal) (det * ((B11 * B22) - (B12 * B21))); + Binv34 = 0.0f; + Binv41 = (dReal) (det * (B21*(B33*B42 - B32*B43) + B22*(B31*B43 - B33*B41) + B23*(B32*B41 - B31*B42))); + Binv42 = (dReal) (det * (B31*(B13*B42 - B12*B43) + B32*(B11*B43 - B13*B41) + B33*(B12*B41 - B11*B42))); + Binv43 = (dReal) (det * (B41*(B13*B22 - B12*B23) + B42*(B11*B23 - B13*B21) + B43*(B12*B21 - B11*B22))); + Binv44 = 1.0f; +} + + + +///////////////////////////////////////////////// +// +// Triangle/Triangle intersection utilities +// +// From the article "A Fast Triangle-Triangle Intersection Test", +// Journal of Graphics Tools, 2(2), 1997 +// +// Some of this functionality is duplicated in OPCODE (see +// OPC_TriTriOverlap.h) but we have replicated it here so we don't +// have to mess with the internals of OPCODE, as well as so we can +// further optimize some of the functions. +// +// This version computes the line of intersection as well (if they +// are not coplanar): +// int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], +// dReal U0[3],dReal U1[3],dReal U2[3], +// int *coplanar, +// dReal isectpt1[3],dReal isectpt2[3]); +// +// parameters: vertices of triangle 1: V0,V1,V2 +// vertices of triangle 2: U0,U1,U2 +// +// result : returns 1 if the triangles intersect, otherwise 0 +// "coplanar" returns whether the tris are coplanar +// isectpt1, isectpt2 are the endpoints of the line of +// intersection +// + + + +#define FABS(x) ((dReal)fabs(x)) /* implement as is fastest on your machine */ + +/* if USE_EPSILON_TEST is true then we do a check: + if |dv|b) \ + { \ + dReal c; \ + c=a; \ + a=b; \ + b=c; \ + } + +#define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \ + isect0=VV0+(VV1-VV0)*D0/(D0-D1); \ + isect1=VV0+(VV2-VV0)*D0/(D0-D2); + + +#define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \ + if(D0D1>0.0f) \ + { \ + /* here we know that D0D2<=0.0 */ \ + /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ + ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \ + } \ + else if(D0D2>0.0f) \ + { \ + /* here we know that d0d1<=0.0 */ \ + ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \ + } \ + else if(D1*D2>0.0f || D0!=0.0f) \ + { \ + /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ + ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1); \ + } \ + else if(D1!=0.0f) \ + { \ + ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \ + } \ + else if(D2!=0.0f) \ + { \ + ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \ + } \ + else \ + { \ + /* triangles are coplanar */ \ + return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ + } + + + +/* this edge to edge test is based on Franlin Antonio's gem: + "Faster Line Segment Intersection", in Graphics Gems III, + pp. 199-202 */ +#define EDGE_EDGE_TEST(V0,U0,U1) \ + Bx=U0[i0]-U1[i0]; \ + By=U0[i1]-U1[i1]; \ + Cx=V0[i0]-U0[i0]; \ + Cy=V0[i1]-U0[i1]; \ + f=Ay*Bx-Ax*By; \ + d=By*Cx-Bx*Cy; \ + if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) \ + { \ + e=Ax*Cy-Ay*Cx; \ + if(f>0) \ + { \ + if(e>=0 && e<=f) return 1; \ + } \ + else \ + { \ + if(e<=0 && e>=f) return 1; \ + } \ + } + +#define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \ +{ \ + dReal Ax,Ay,Bx,By,Cx,Cy,e,d,f; \ + Ax=V1[i0]-V0[i0]; \ + Ay=V1[i1]-V0[i1]; \ + /* test edge U0,U1 against V0,V1 */ \ + EDGE_EDGE_TEST(V0,U0,U1); \ + /* test edge U1,U2 against V0,V1 */ \ + EDGE_EDGE_TEST(V0,U1,U2); \ + /* test edge U2,U1 against V0,V1 */ \ + EDGE_EDGE_TEST(V0,U2,U0); \ +} + +#define POINT_IN_TRI(V0,U0,U1,U2) \ +{ \ + dReal a,b,c,d0,d1,d2; \ + /* is T1 completly inside T2? */ \ + /* check if V0 is inside tri(U0,U1,U2) */ \ + a=U1[i1]-U0[i1]; \ + b=-(U1[i0]-U0[i0]); \ + c=-a*U0[i0]-b*U0[i1]; \ + d0=a*V0[i0]+b*V0[i1]+c; \ + \ + a=U2[i1]-U1[i1]; \ + b=-(U2[i0]-U1[i0]); \ + c=-a*U1[i0]-b*U1[i1]; \ + d1=a*V0[i0]+b*V0[i1]+c; \ + \ + a=U0[i1]-U2[i1]; \ + b=-(U0[i0]-U2[i0]); \ + c=-a*U2[i0]-b*U2[i1]; \ + d2=a*V0[i0]+b*V0[i1]+c; \ + if(d0*d1>0.0) \ + { \ + if(d0*d2>0.0) return 1; \ + } \ +} + +int coplanar_tri_tri(dReal N[3],dReal V0[3],dReal V1[3],dReal V2[3], + dReal U0[3],dReal U1[3],dReal U2[3]) +{ + dReal A[3]; + short i0,i1; + /* first project onto an axis-aligned plane, that maximizes the area */ + /* of the triangles, compute indices: i0,i1. */ + A[0]= (dReal) fabs(N[0]); + A[1]= (dReal) fabs(N[1]); + A[2]= (dReal) fabs(N[2]); + if(A[0]>A[1]) + { + if(A[0]>A[2]) + { + i0=1; /* A[0] is greatest */ + i1=2; + } + else + { + i0=0; /* A[2] is greatest */ + i1=1; + } + } + else /* A[0]<=A[1] */ + { + if(A[2]>A[1]) + { + i0=0; /* A[2] is greatest */ + i1=1; + } + else + { + i0=0; /* A[1] is greatest */ + i1=2; + } + } + + /* test all edges of triangle 1 against the edges of triangle 2 */ + EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2); + EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2); + EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2); + + /* finally, test if tri1 is totally contained in tri2 or vice versa */ + POINT_IN_TRI(V0,U0,U1,U2); + POINT_IN_TRI(U0,V0,V1,V2); + + return 0; +} + + + +#define NEWCOMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,A,B,C,X0,X1) \ +{ \ + if(D0D1>0.0f) \ + { \ + /* here we know that D0D2<=0.0 */ \ + /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ + A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ + } \ + else if(D0D2>0.0f)\ + { \ + /* here we know that d0d1<=0.0 */ \ + A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ + } \ + else if(D1*D2>0.0f || D0!=0.0f) \ + { \ + /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ + A=VV0; B=(VV1-VV0)*D0; C=(VV2-VV0)*D0; X0=D0-D1; X1=D0-D2; \ + } \ + else if(D1!=0.0f) \ + { \ + A=VV1; B=(VV0-VV1)*D1; C=(VV2-VV1)*D1; X0=D1-D0; X1=D1-D2; \ + } \ + else if(D2!=0.0f) \ + { \ + A=VV2; B=(VV0-VV2)*D2; C=(VV1-VV2)*D2; X0=D2-D0; X1=D2-D1; \ + } \ + else \ + { \ + /* triangles are coplanar */ \ + return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ + } \ +} + + + + +/* sort so that a<=b */ +#define SORT2(a,b,smallest) \ + if(a>b) \ + { \ + dReal c; \ + c=a; \ + a=b; \ + b=c; \ + smallest=1; \ + } \ + else smallest=0; + + +inline void isect2(dReal VTX0[3],dReal VTX1[3],dReal VTX2[3],dReal VV0,dReal VV1,dReal VV2, + dReal D0,dReal D1,dReal D2,dReal *isect0,dReal *isect1,dReal isectpoint0[3],dReal isectpoint1[3]) +{ + dReal tmp=D0/(D0-D1); + dReal diff[3]; + *isect0=VV0+(VV1-VV0)*tmp; + SUB(diff,VTX1,VTX0); + MULT(diff,diff,tmp); + ADD(isectpoint0,diff,VTX0); + tmp=D0/(D0-D2); + *isect1=VV0+(VV2-VV0)*tmp; + SUB(diff,VTX2,VTX0); + MULT(diff,diff,tmp); + ADD(isectpoint1,VTX0,diff); +} + + +#if 0 +#define ISECT2(VTX0,VTX1,VTX2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1) \ + tmp=D0/(D0-D1); \ + isect0=VV0+(VV1-VV0)*tmp; \ + SUB(diff,VTX1,VTX0); \ + MULT(diff,diff,tmp); \ + ADD(isectpoint0,diff,VTX0); \ + tmp=D0/(D0-D2); +/* isect1=VV0+(VV2-VV0)*tmp; \ */ +/* SUB(diff,VTX2,VTX0); \ */ +/* MULT(diff,diff,tmp); \ */ +/* ADD(isectpoint1,VTX0,diff); */ +#endif + +inline int compute_intervals_isectline(dReal VERT0[3],dReal VERT1[3],dReal VERT2[3], + dReal VV0,dReal VV1,dReal VV2,dReal D0,dReal D1,dReal D2, + dReal D0D1,dReal D0D2,dReal *isect0,dReal *isect1, + dReal isectpoint0[3],dReal isectpoint1[3]) +{ + if(D0D1>0.0f) + { + /* here we know that D0D2<=0.0 */ + /* that is D0, D1 are on the same side, D2 on the other or on the plane */ + isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1); + } + else if(D0D2>0.0f) + { + /* here we know that d0d1<=0.0 */ + isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); + } + else if(D1*D2>0.0f || D0!=0.0f) + { + /* here we know that d0d1<=0.0 or that D0!=0.0 */ + isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,isect0,isect1,isectpoint0,isectpoint1); + } + else if(D1!=0.0f) + { + isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,isect0,isect1,isectpoint0,isectpoint1); + } + else if(D2!=0.0f) + { + isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,isect0,isect1,isectpoint0,isectpoint1); + } + else + { + /* triangles are coplanar */ + return 1; + } + return 0; +} + +#define COMPUTE_INTERVALS_ISECTLINE(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1,isectpoint0,isectpoint1) \ + if(D0D1>0.0f) \ + { \ + /* here we know that D0D2<=0.0 */ \ + /* that is D0, D1 are on the same side, D2 on the other or on the plane */ \ + isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \ + } +#if 0 + else if(D0D2>0.0f) \ + { \ + /* here we know that d0d1<=0.0 */ \ + isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ + } \ + else if(D1*D2>0.0f || D0!=0.0f) \ + { \ + /* here we know that d0d1<=0.0 or that D0!=0.0 */ \ + isect2(VERT0,VERT1,VERT2,VV0,VV1,VV2,D0,D1,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ + } \ + else if(D1!=0.0f) \ + { \ + isect2(VERT1,VERT0,VERT2,VV1,VV0,VV2,D1,D0,D2,&isect0,&isect1,isectpoint0,isectpoint1); \ + } \ + else if(D2!=0.0f) \ + { \ + isect2(VERT2,VERT0,VERT1,VV2,VV0,VV1,D2,D0,D1,&isect0,&isect1,isectpoint0,isectpoint1); \ + } \ + else \ + { \ + /* triangles are coplanar */ \ + coplanar=1; \ + return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \ + } +#endif + + +static int TriTriIntersectWithIsectLine(dReal V0[3],dReal V1[3],dReal V2[3], + dReal U0[3],dReal U1[3],dReal U2[3],int *coplanar, + dReal isectpt1[3],dReal isectpt2[3]) +{ + dReal E1[3],E2[3]; + dReal N1[3],N2[3],d1,d2; + dReal du0,du1,du2,dv0,dv1,dv2; + dReal D[3]; + dReal isect1[2], isect2[2]; + dReal isectpointA1[3],isectpointA2[3]; + dReal isectpointB1[3],isectpointB2[3]; + dReal du0du1,du0du2,dv0dv1,dv0dv2; + short index; + dReal vp0,vp1,vp2; + dReal up0,up1,up2; + dReal b,c,max; + int smallest1,smallest2; + + /* compute plane equation of triangle(V0,V1,V2) */ + SUB(E1,V1,V0); + SUB(E2,V2,V0); + CROSS(N1,E1,E2); + d1=-DOT(N1,V0); + /* plane equation 1: N1.X+d1=0 */ + + /* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/ + du0=DOT(N1,U0)+d1; + du1=DOT(N1,U1)+d1; + du2=DOT(N1,U2)+d1; + + /* coplanarity robustness check */ +#if USE_EPSILON_TEST==TRUE + if(fabs(du0)0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */ + return 0; /* no intersection occurs */ + + /* compute plane of triangle (U0,U1,U2) */ + SUB(E1,U1,U0); + SUB(E2,U2,U0); + CROSS(N2,E1,E2); + d2=-DOT(N2,U0); + /* plane equation 2: N2.X+d2=0 */ + + /* put V0,V1,V2 into plane equation 2 */ + dv0=DOT(N2,V0)+d2; + dv1=DOT(N2,V1)+d2; + dv2=DOT(N2,V2)+d2; + +#if USE_EPSILON_TEST==TRUE + if(fabs(dv0)0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */ + return 0; /* no intersection occurs */ + + /* compute direction of intersection line */ + CROSS(D,N1,N2); + + /* compute and index to the largest component of D */ + max= (dReal) fabs(D[0]); + index=0; + b= (dReal) fabs(D[1]); + c= (dReal) fabs(D[2]); + if(b>max) {max=b;index=1;} + if(c>max) {max=c;index=2;} + + /* this is the simplified projection onto L*/ + vp0=V0[index]; + vp1=V1[index]; + vp2=V2[index]; + + up0=U0[index]; + up1=U1[index]; + up2=U2[index]; + + /* compute interval for triangle 1 */ + *coplanar=compute_intervals_isectline(V0,V1,V2,vp0,vp1,vp2,dv0,dv1,dv2, + dv0dv1,dv0dv2,&isect1[0],&isect1[1],isectpointA1,isectpointA2); + if(*coplanar) return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); + + + /* compute interval for triangle 2 */ + compute_intervals_isectline(U0,U1,U2,up0,up1,up2,du0,du1,du2, + du0du1,du0du2,&isect2[0],&isect2[1],isectpointB1,isectpointB2); + + SORT2(isect1[0],isect1[1],smallest1); + SORT2(isect2[0],isect2[1],smallest2); + + if(isect1[1]isect1[1]) + { + if(smallest1==0) { SET(isectpt2,isectpointA2); } + else { SET(isectpt2,isectpointA1); } + } + else + { + if(smallest2==0) { SET(isectpt2,isectpointB2); } + else { SET(isectpt2,isectpointB1); } + } + } + return 1; +} + + + + + +// Find the intersectiojn point between a coplanar line segement, +// defined by X1 and X2, and a ray defined by X3 and direction N. +// +// This forumla for this calculation is: +// (c x b) . (a x b) +// Q = x1 + a ------------------- +// | a x b | ^2 +// +// where a = x2 - x1 +// b = x4 - x3 +// c = x3 - x1 +// x1 and x2 are the edges of the triangle, and x3 is CoplanarPt +// and x4 is (CoplanarPt - n) +#if 0 +static int +IntersectLineSegmentRay(dVector3 x1, dVector3 x2, dVector3 x3, dVector3 n, + dVector3 out_pt) +{ + dVector3 a, b, c, x4; + + ADD(x4, x3, n); // x4 = x3 + n + + SUB(a, x2, x1); // a = x2 - x1 + SUB(b, x4, x3); + SUB(c, x3, x1); + + dVector3 tmp1, tmp2; + CROSS(tmp1, c, b); + CROSS(tmp2, a, b); + + dReal num, denom; + num = dDOT(tmp1, tmp2); + denom = LENGTH( tmp2 ); + + dReal s; + s = num /(denom*denom); + + for (int i=0; i<3; i++) + out_pt[i] = x1[i] + a[i]*s; + + // Test if this intersection is "behind" x3, w.r.t. n + SUB(a, x3, out_pt); + if (dDOT(a, n) > 0.0) + return 0; + + // Test if this intersection point is outside the edge limits, + // if (dot( (out_pt-x1), (out_pt-x2) ) < 0) it's inside + // else outside + SUB(a, out_pt, x1); + SUB(b, out_pt, x2); + if (dDOT(a,b) < 0.0) + return 1; + else + return 0; +} +#endif //0 + +// FindTriSolidIntersection - Clips the input trinagle TRI with the +// sides of a convex bounding solid, described by PLANES, returning +// the (convex) clipped polygon in CLIPPEDPOLYGON +// +#ifndef ERICF_METHOD +static bool +FindTriSolidIntrsection(const dVector3 Tri[3], + const dVector4 Planes[6], int numSides, + LineContactSet& ClippedPolygon ) +{ + // Set up the LineContactSet structure + for (int k=0; k<3; k++) { + SET(ClippedPolygon.Points[k], Tri[k]); + } + ClippedPolygon.Count = 3; + + // Clip wrt the sides + for ( int i = 0; i < numSides; i++ ) + ClipConvexPolygonAgainstPlane( Planes[i], Planes[i][3], ClippedPolygon ); + + return (ClippedPolygon.Count > 0); +} +#endif + + + +// ClipConvexPolygonAgainstPlane - Clip a a convex polygon, described by +// CONTACTS, with a plane (described by N and C). Note: the input +// vertices are assumed to be in counterclockwise order. +// +// This code is taken from The Nebula Device: +// http://nebuladevice.sourceforge.net/cgi-bin/twiki/view/Nebula/WebHome +// and is licensed under the following license: +// http://nebuladevice.sourceforge.net/doc/source/license.txt +// +#ifndef ERICF_METHOD +static void +ClipConvexPolygonAgainstPlane( const dVector3 N, dReal C, + LineContactSet& Contacts ) +{ + // test on which side of line are the vertices + int Positive = 0, Negative = 0, PIndex = -1; + int Quantity = Contacts.Count; + + dReal Test[8]; + for ( int i = 0; i < Contacts.Count; i++ ) { + // An epsilon is used here because it is possible for the dot product + // and C to be exactly equal to each other (in theory), but differ + // slightly because of floating point problems. Thus, add a little + // to the test number to push actually equal numbers over the edge + // towards the positive. This should probably be somehow a relative + // tolerance, and I don't think multiplying by the constant is the best + // way to do this. + Test[i] = dDOT(N, Contacts.Points[i]) - C + dFabs(C)*1e-08; + + if (Test[i] >= REAL(0.0)) { + Positive++; + if (PIndex < 0) { + PIndex = i; + } + } + else Negative++; + } + + if (Positive > 0) { + if (Negative > 0) { + // plane transversely intersects polygon + dVector3 CV[8]; + int CQuantity = 0, Cur, Prv; + dReal T; + + if (PIndex > 0) { + // first clip vertex on line + Cur = PIndex; + Prv = Cur - 1; + T = Test[Cur] / (Test[Cur] - Test[Prv]); + CV[CQuantity][0] = Contacts.Points[Cur][0] + + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); + CV[CQuantity][1] = Contacts.Points[Cur][1] + + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); + CV[CQuantity][2] = Contacts.Points[Cur][2] + + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); + CV[CQuantity][3] = Contacts.Points[Cur][3] + + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); + CQuantity++; + + // vertices on positive side of line + while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { + CV[CQuantity][0] = Contacts.Points[Cur][0]; + CV[CQuantity][1] = Contacts.Points[Cur][1]; + CV[CQuantity][2] = Contacts.Points[Cur][2]; + CV[CQuantity][3] = Contacts.Points[Cur][3]; + CQuantity++; + Cur++; + } + + // last clip vertex on line + if (Cur < Quantity) { + Prv = Cur - 1; + } + else { + Cur = 0; + Prv = Quantity - 1; + } + + T = Test[Cur] / (Test[Cur] - Test[Prv]); + CV[CQuantity][0] = Contacts.Points[Cur][0] + + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); + CV[CQuantity][1] = Contacts.Points[Cur][1] + + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); + CV[CQuantity][2] = Contacts.Points[Cur][2] + + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); + CV[CQuantity][3] = Contacts.Points[Cur][3] + + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); + CQuantity++; + } + else { + // iPIndex is 0 + // vertices on positive side of line + Cur = 0; + while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { + CV[CQuantity][0] = Contacts.Points[Cur][0]; + CV[CQuantity][1] = Contacts.Points[Cur][1]; + CV[CQuantity][2] = Contacts.Points[Cur][2]; + CV[CQuantity][3] = Contacts.Points[Cur][3]; + CQuantity++; + Cur++; + } + + // last clip vertex on line + Prv = Cur - 1; + T = Test[Cur] / (Test[Cur] - Test[Prv]); + CV[CQuantity][0] = Contacts.Points[Cur][0] + + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); + CV[CQuantity][1] = Contacts.Points[Cur][1] + + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); + CV[CQuantity][2] = Contacts.Points[Cur][2] + + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); + CV[CQuantity][3] = Contacts.Points[Cur][3] + + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); + CQuantity++; + + // skip vertices on negative side + while (Cur < Quantity && Test[Cur] < REAL(0.0)) { + Cur++; + } + + // first clip vertex on line + if (Cur < Quantity) { + Prv = Cur - 1; + T = Test[Cur] / (Test[Cur] - Test[Prv]); + CV[CQuantity][0] = Contacts.Points[Cur][0] + + T * (Contacts.Points[Prv][0] - Contacts.Points[Cur][0]); + CV[CQuantity][1] = Contacts.Points[Cur][1] + + T * (Contacts.Points[Prv][1] - Contacts.Points[Cur][1]); + CV[CQuantity][2] = Contacts.Points[Cur][2] + + T * (Contacts.Points[Prv][2] - Contacts.Points[Cur][2]); + CV[CQuantity][3] = Contacts.Points[Cur][3] + + T * (Contacts.Points[Prv][3] - Contacts.Points[Cur][3]); + CQuantity++; + + // vertices on positive side of line + while (Cur < Quantity && Test[Cur] >= REAL(0.0)) { + CV[CQuantity][0] = Contacts.Points[Cur][0]; + CV[CQuantity][1] = Contacts.Points[Cur][1]; + CV[CQuantity][2] = Contacts.Points[Cur][2]; + CV[CQuantity][3] = Contacts.Points[Cur][3]; + CQuantity++; + Cur++; + } + } + else { + // iCur = 0 + Prv = Quantity - 1; + T = Test[0] / (Test[0] - Test[Prv]); + CV[CQuantity][0] = Contacts.Points[0][0] + + T * (Contacts.Points[Prv][0] - Contacts.Points[0][0]); + CV[CQuantity][1] = Contacts.Points[0][1] + + T * (Contacts.Points[Prv][1] - Contacts.Points[0][1]); + CV[CQuantity][2] = Contacts.Points[0][2] + + T * (Contacts.Points[Prv][2] - Contacts.Points[0][2]); + CV[CQuantity][3] = Contacts.Points[0][3] + + T * (Contacts.Points[Prv][3] - Contacts.Points[0][3]); + CQuantity++; + } + } + Quantity = CQuantity; + memcpy( Contacts.Points, CV, CQuantity * sizeof(dVector3) ); + } + // else polygon fully on positive side of plane, nothing to do + Contacts.Count = Quantity; + } + else { + Contacts.Count = 0; // This should not happen, but for safety + } + +} +#endif + + +// Determine if a potential collision point is +// +// + +#ifndef ERICF_METHOD +static int +ExamineContactPoint(dVector3* v_col, dVector3 in_n, dVector3 in_point) +{ + // Cast a ray from in_point, along the collison normal. Does it intersect the + // collision face. + dReal t, u, v; + + if (!RayTriangleIntersect(in_point, in_n, v_col[0], v_col[1], v_col[2], + &t, &u, &v)) + return 0; + else + return 1; +} +#endif + + +// RayTriangleIntersect - If an intersection is found, t contains the +// distance along the ray (dir) and u/v contain u/v coordinates into +// the triangle. Returns 0 if no hit is found +// From "Real-Time Rendering," page 305 +// +#ifndef ERICF_METHOD +static int +RayTriangleIntersect(const dVector3 orig, const dVector3 dir, + const dVector3 vert0, const dVector3 vert1,const dVector3 vert2, + dReal *t,dReal *u,dReal *v) + +{ + dReal edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + dReal det,inv_det; + + // find vectors for two edges sharing vert0 + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + + // begin calculating determinant - also used to calculate U parameter + CROSS(pvec, dir, edge2); + + // if determinant is near zero, ray lies in plane of triangle + det = DOT(edge1, pvec); + + if ((det > -0.001) && (det < 0.001)) + return 0; + inv_det = 1.0 / det; + + // calculate distance from vert0 to ray origin + SUB(tvec, orig, vert0); + + // calculate U parameter and test bounds + *u = DOT(tvec, pvec) * inv_det; + if ((*u < 0.0) || (*u > 1.0)) + return 0; + + // prepare to test V parameter + CROSS(qvec, tvec, edge1); + + // calculate V parameter and test bounds + *v = DOT(dir, qvec) * inv_det; + if ((*v < 0.0) || ((*u + *v) > 1.0)) + return 0; + + // calculate t, ray intersects triangle + *t = DOT(edge2, qvec) * inv_det; + + return 1; +} + +static bool +SimpleUnclippedTest(dVector3 in_CoplanarPt, dVector3 in_v, dVector3 in_elt, + dVector3 in_n, dVector3* in_col_v, dReal &out_depth) +{ + dReal dp = 0.0; + dReal contact_elt_length; + + DEPTH(dp, in_CoplanarPt, in_v, in_n); + + if (dp >= 0.0) { + // if the penetration depth (calculated above) is more than + // the contact point's ELT, then we've chosen the wrong face + // and should switch faces + contact_elt_length = fabs(dDOT(in_elt, in_n)); + + if (dp == 0.0) + dp = dMin(DISTANCE_EPSILON, contact_elt_length); + + if ((contact_elt_length < SMALL_ELT) && (dp < EXPANDED_ELT_THRESH)) + dp = contact_elt_length; + + if ( (dp > 0.0) && (dp <= contact_elt_length)) { + // Add a contact + + if ( ExamineContactPoint(in_col_v, in_n, in_v) ) { + out_depth = dp; + return true; + } + } + } + + return false; +} +#endif + + + +// Generate a "unique" contact. A unique contact has a unique +// position or normal. If the potential contact has the same +// position and normal as an existing contact, but a larger +// penetration depth, this new depth is used instead +// +static void +GenerateContact(int in_Flags, dContactGeom* in_Contacts, int in_Stride, + dxTriMesh* in_TriMesh1, dxTriMesh* in_TriMesh2, + const dVector3 in_ContactPos, const dVector3 in_Normal, dReal in_Depth, + int& OutTriCount) +{ + if (in_Depth < 0.0) + return; + + if (OutTriCount == (in_Flags & 0x0ffff)) + return; // contacts are full! + + + dContactGeom* Contact; + dVector3 diff; + bool duplicate = false; + + for (int i=0; ipos); + if (dDOT(diff, diff) < ODE_EPSILON) + { + // same normal? + if (fabs(dDOT(in_Normal, Contact->normal)) > ((dReal)1) - ODE_EPSILON ) + { + if (in_Depth > Contact->depth) { + Contact->depth = in_Depth; + SMULT( Contact->normal, in_Normal, -1.0); + Contact->normal[3] = 0.0; + } + duplicate = true; + } + } + } + + + if (!duplicate) + { + // Add a new contact + Contact = SAFECONTACT(in_Flags, in_Contacts, OutTriCount, in_Stride); + + SET( Contact->pos, in_ContactPos ); + Contact->pos[3] = 0.0; + + SMULT( Contact->normal, in_Normal, -1.0); + Contact->normal[3] = 0.0; + + Contact->depth = in_Depth; + + Contact->g1 = in_TriMesh1; + Contact->g2 = in_TriMesh2; + + OutTriCount++; + } + + +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_util.cpp b/src/external/open_dynamics_engine-ef/ode/ode_collision_util.cpp new file mode 100644 index 00000000..17a22c27 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_util.cpp @@ -0,0 +1,596 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +some useful collision utility stuff. this includes some API utility +functions that are defined in the public header files. + +*/ + +#include "ode/ode_common.h" +#include "ode/ode_collision.h" +#include "ode/ode_math.h" +#include "ode/ode_collision_util.h" + +//**************************************************************************** + +int dCollideSpheres (dVector3 p1, dReal r1, + dVector3 p2, dReal r2, dContactGeom *c) +{ + // printf ("d=%.2f (%.2f %.2f %.2f) (%.2f %.2f %.2f) r1=%.2f r2=%.2f\n", + // d,p1[0],p1[1],p1[2],p2[0],p2[1],p2[2],r1,r2); + + dReal d = dDISTANCE (p1,p2); + if (d > (r1 + r2)) return 0; + if (d <= 0) { + c->pos[0] = p1[0]; + c->pos[1] = p1[1]; + c->pos[2] = p1[2]; + c->normal[0] = 1; + c->normal[1] = 0; + c->normal[2] = 0; + c->depth = r1 + r2; + } + else { + dReal d1 = dRecip (d); + c->normal[0] = (p1[0]-p2[0])*d1; + c->normal[1] = (p1[1]-p2[1])*d1; + c->normal[2] = (p1[2]-p2[2])*d1; + dReal k = REAL(0.5) * (r2 - r1 - d); + c->pos[0] = p1[0] + c->normal[0]*k; + c->pos[1] = p1[1] + c->normal[1]*k; + c->pos[2] = p1[2] + c->normal[2]*k; + c->depth = r1 + r2 - d; + } + return 1; +} + + +void dLineClosestApproach (const dVector3 pa, const dVector3 ua, + const dVector3 pb, const dVector3 ub, + dReal *alpha, dReal *beta) +{ + dVector3 p; + p[0] = pb[0] - pa[0]; + p[1] = pb[1] - pa[1]; + p[2] = pb[2] - pa[2]; + dReal uaub = dDOT(ua,ub); + dReal q1 = dDOT(ua,p); + dReal q2 = -dDOT(ub,p); + dReal d = 1-uaub*uaub; + if (d <= REAL(0.0001)) { + // @@@ this needs to be made more robust + *alpha = 0; + *beta = 0; + } + else { + d = dRecip(d); + *alpha = (q1 + uaub*q2)*d; + *beta = (uaub*q1 + q2)*d; + } +} + + +// given two line segments A and B with endpoints a1-a2 and b1-b2, return the +// points on A and B that are closest to each other (in cp1 and cp2). +// in the case of parallel lines where there are multiple solutions, a +// solution involving the endpoint of at least one line will be returned. +// this will work correctly for zero length lines, e.g. if a1==a2 and/or +// b1==b2. +// +// the algorithm works by applying the voronoi clipping rule to the features +// of the line segments. the three features of each line segment are the two +// endpoints and the line between them. the voronoi clipping rule states that, +// for feature X on line A and feature Y on line B, the closest points PA and +// PB between X and Y are globally the closest points if PA is in V(Y) and +// PB is in V(X), where V(X) is the voronoi region of X. + +void dClosestLineSegmentPoints (const dVector3 a1, const dVector3 a2, + const dVector3 b1, const dVector3 b2, + dVector3 cp1, dVector3 cp2) +{ + dVector3 a1a2,b1b2,a1b1,a1b2,a2b1,a2b2,n; + dReal la,lb,k,da1,da2,da3,da4,db1,db2,db3,db4,det; + +#define SET2(a,b) a[0]=b[0]; a[1]=b[1]; a[2]=b[2]; +#define SET3(a,b,op,c) a[0]=b[0] op c[0]; a[1]=b[1] op c[1]; a[2]=b[2] op c[2]; + + // check vertex-vertex features + + SET3 (a1a2,a2,-,a1); + SET3 (b1b2,b2,-,b1); + SET3 (a1b1,b1,-,a1); + da1 = dDOT(a1a2,a1b1); + db1 = dDOT(b1b2,a1b1); + if (da1 <= 0 && db1 >= 0) { + SET2 (cp1,a1); + SET2 (cp2,b1); + return; + } + + SET3 (a1b2,b2,-,a1); + da2 = dDOT(a1a2,a1b2); + db2 = dDOT(b1b2,a1b2); + if (da2 <= 0 && db2 <= 0) { + SET2 (cp1,a1); + SET2 (cp2,b2); + return; + } + + SET3 (a2b1,b1,-,a2); + da3 = dDOT(a1a2,a2b1); + db3 = dDOT(b1b2,a2b1); + if (da3 >= 0 && db3 >= 0) { + SET2 (cp1,a2); + SET2 (cp2,b1); + return; + } + + SET3 (a2b2,b2,-,a2); + da4 = dDOT(a1a2,a2b2); + db4 = dDOT(b1b2,a2b2); + if (da4 >= 0 && db4 <= 0) { + SET2 (cp1,a2); + SET2 (cp2,b2); + return; + } + + // check edge-vertex features. + // if one or both of the lines has zero length, we will never get to here, + // so we do not have to worry about the following divisions by zero. + + la = dDOT(a1a2,a1a2); + if (da1 >= 0 && da3 <= 0) { + k = da1 / la; + SET3 (n,a1b1,-,k*a1a2); + if (dDOT(b1b2,n) >= 0) { + SET3 (cp1,a1,+,k*a1a2); + SET2 (cp2,b1); + return; + } + } + + if (da2 >= 0 && da4 <= 0) { + k = da2 / la; + SET3 (n,a1b2,-,k*a1a2); + if (dDOT(b1b2,n) <= 0) { + SET3 (cp1,a1,+,k*a1a2); + SET2 (cp2,b2); + return; + } + } + + lb = dDOT(b1b2,b1b2); + if (db1 <= 0 && db2 >= 0) { + k = -db1 / lb; + SET3 (n,-a1b1,-,k*b1b2); + if (dDOT(a1a2,n) >= 0) { + SET2 (cp1,a1); + SET3 (cp2,b1,+,k*b1b2); + return; + } + } + + if (db3 <= 0 && db4 >= 0) { + k = -db3 / lb; + SET3 (n,-a2b1,-,k*b1b2); + if (dDOT(a1a2,n) <= 0) { + SET2 (cp1,a2); + SET3 (cp2,b1,+,k*b1b2); + return; + } + } + + // it must be edge-edge + + k = dDOT(a1a2,b1b2); + det = la*lb - k*k; + if (det <= 0) { + // this should never happen, but just in case... + SET2(cp1,a1); + SET2(cp2,b1); + return; + } + det = dRecip (det); + dReal alpha = (lb*da1 - k*db1) * det; + dReal beta = ( k*da1 - la*db1) * det; + SET3 (cp1,a1,+,alpha*a1a2); + SET3 (cp2,b1,+,beta*b1b2); + +# undef SET2 +# undef SET3 +} + + +// a simple root finding algorithm is used to find the value of 't' that +// satisfies: +// d|D(t)|^2/dt = 0 +// where: +// |D(t)| = |p(t)-b(t)| +// where p(t) is a point on the line parameterized by t: +// p(t) = p1 + t*(p2-p1) +// and b(t) is that same point clipped to the boundary of the box. in box- +// relative coordinates d|D(t)|^2/dt is the sum of three x,y,z components +// each of which looks like this: +// +// t_lo / +// ______/ -->t +// / t_hi +// / +// +// t_lo and t_hi are the t values where the line passes through the planes +// corresponding to the sides of the box. the algorithm computes d|D(t)|^2/dt +// in a piecewise fashion from t=0 to t=1, stopping at the point where +// d|D(t)|^2/dt crosses from negative to positive. + +void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2, + const dVector3 c, const dMatrix3 R, + const dVector3 side, + dVector3 lret, dVector3 bret) +{ + int i; + + // compute the start and delta of the line p1-p2 relative to the box. + // we will do all subsequent computations in this box-relative coordinate + // system. we have to do a translation and rotation for each point. + dVector3 tmp,s,v; + tmp[0] = p1[0] - c[0]; + tmp[1] = p1[1] - c[1]; + tmp[2] = p1[2] - c[2]; + dMULTIPLY1_331 (s,R,tmp); + tmp[0] = p2[0] - p1[0]; + tmp[1] = p2[1] - p1[1]; + tmp[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (v,R,tmp); + + // mirror the line so that v has all components >= 0 + dVector3 sign; + for (i=0; i<3; i++) { + if (v[i] < 0) { + s[i] = -s[i]; + v[i] = -v[i]; + sign[i] = -1; + } + else sign[i] = 1; + } + + // compute v^2 + dVector3 v2; + v2[0] = v[0]*v[0]; + v2[1] = v[1]*v[1]; + v2[2] = v[2]*v[2]; + + // compute the half-sides of the box + dReal h[3]; + h[0] = REAL(0.5) * side[0]; + h[1] = REAL(0.5) * side[1]; + h[2] = REAL(0.5) * side[2]; + + // region is -1,0,+1 depending on which side of the box planes each + // coordinate is on. tanchor is the next t value at which there is a + // transition, or the last one if there are no more. + int region[3]; + dReal tanchor[3]; + + // find the region and tanchor values for p1 + for (i=0; i<3; i++) { + if (v[i] > 0) { + if (s[i] < -h[i]) { + region[i] = -1; + tanchor[i] = (-h[i]-s[i])/v[i]; + } + else { + region[i] = (s[i] > h[i]); + tanchor[i] = (h[i]-s[i])/v[i]; + } + } + else { + region[i] = 0; + tanchor[i] = 2; // this will never be a valid tanchor + } + } + + // compute d|d|^2/dt for t=0. if it's >= 0 then p1 is the closest point + dReal t=0; + dReal dd2dt = 0; + for (i=0; i<3; i++) dd2dt -= (region[i] ? v2[i] : 0) * tanchor[i]; + if (dd2dt >= 0) goto got_answer; + + do { + // find the point on the line that is at the next clip plane boundary + dReal next_t = 1; + for (i=0; i<3; i++) { + if (tanchor[i] > t && tanchor[i] < 1 && tanchor[i] < next_t) + next_t = tanchor[i]; + } + + // compute d|d|^2/dt for the next t + dReal next_dd2dt = 0; + for (i=0; i<3; i++) { + next_dd2dt += (region[i] ? v2[i] : 0) * (next_t - tanchor[i]); + } + + // if the sign of d|d|^2/dt has changed, solution = the crossover point + if (next_dd2dt >= 0) { + dReal m = (next_dd2dt-dd2dt)/(next_t - t); + t -= dd2dt/m; + goto got_answer; + } + + // advance to the next anchor point / region + for (i=0; i<3; i++) { + if (tanchor[i] == next_t) { + tanchor[i] = (h[i]-s[i])/v[i]; + region[i]++; + } + } + t = next_t; + dd2dt = next_dd2dt; + } + while (t < 1); + t = 1; + + got_answer: + + // compute closest point on the line + for (i=0; i<3; i++) lret[i] = p1[i] + t*tmp[i]; // note: tmp=p2-p1 + + // compute closest point on the box + for (i=0; i<3; i++) { + tmp[i] = sign[i] * (s[i] + t*v[i]); + if (tmp[i] < -h[i]) tmp[i] = -h[i]; + else if (tmp[i] > h[i]) tmp[i] = h[i]; + } + dMULTIPLY0_331 (s,R,tmp); + for (i=0; i<3; i++) bret[i] = s[i] + c[i]; +} + + +// given boxes (p1,R1,side1) and (p1,R1,side1), return 1 if they intersect +// or 0 if not. + +int dBoxTouchesBox (const dVector3 p1, const dMatrix3 R1, + const dVector3 side1, const dVector3 p2, + const dMatrix3 R2, const dVector3 side2) +{ + // two boxes are disjoint if (and only if) there is a separating axis + // perpendicular to a face from one box or perpendicular to an edge from + // either box. the following tests are derived from: + // "OBB Tree: A Hierarchical Structure for Rapid Interference Detection", + // S.Gottschalk, M.C.Lin, D.Manocha., Proc of ACM Siggraph 1996. + + // Rij is R1'*R2, i.e. the relative rotation between R1 and R2. + // Qij is abs(Rij) + dVector3 p,pp; + dReal A1,A2,A3,B1,B2,B3,R11,R12,R13,R21,R22,R23,R31,R32,R33, + Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33; + + // get vector from centers of box 1 to box 2, relative to box 1 + p[0] = p2[0] - p1[0]; + p[1] = p2[1] - p1[1]; + p[2] = p2[2] - p1[2]; + dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 + + // get side lengths / 2 + A1 = side1[0]*REAL(0.5); A2 = side1[1]*REAL(0.5); A3 = side1[2]*REAL(0.5); + B1 = side2[0]*REAL(0.5); B2 = side2[1]*REAL(0.5); B3 = side2[2]*REAL(0.5); + + // for the following tests, excluding computation of Rij, in the worst case, + // 15 compares, 60 adds, 81 multiplies, and 24 absolutes. + // notation: R1=[u1 u2 u3], R2=[v1 v2 v3] + + // separating axis = u1,u2,u3 + R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); + Q11 = dFabs(R11); Q12 = dFabs(R12); Q13 = dFabs(R13); + if (dFabs(pp[0]) > (A1 + B1*Q11 + B2*Q12 + B3*Q13)) return 0; + R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); + Q21 = dFabs(R21); Q22 = dFabs(R22); Q23 = dFabs(R23); + if (dFabs(pp[1]) > (A2 + B1*Q21 + B2*Q22 + B3*Q23)) return 0; + R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); + Q31 = dFabs(R31); Q32 = dFabs(R32); Q33 = dFabs(R33); + if (dFabs(pp[2]) > (A3 + B1*Q31 + B2*Q32 + B3*Q33)) return 0; + + // separating axis = v1,v2,v3 + if (dFabs(dDOT41(R2+0,p)) > (A1*Q11 + A2*Q21 + A3*Q31 + B1)) return 0; + if (dFabs(dDOT41(R2+1,p)) > (A1*Q12 + A2*Q22 + A3*Q32 + B2)) return 0; + if (dFabs(dDOT41(R2+2,p)) > (A1*Q13 + A2*Q23 + A3*Q33 + B3)) return 0; + + // separating axis = u1 x (v1,v2,v3) + if (dFabs(pp[2]*R21-pp[1]*R31) > A2*Q31 + A3*Q21 + B2*Q13 + B3*Q12) return 0; + if (dFabs(pp[2]*R22-pp[1]*R32) > A2*Q32 + A3*Q22 + B1*Q13 + B3*Q11) return 0; + if (dFabs(pp[2]*R23-pp[1]*R33) > A2*Q33 + A3*Q23 + B1*Q12 + B2*Q11) return 0; + + // separating axis = u2 x (v1,v2,v3) + if (dFabs(pp[0]*R31-pp[2]*R11) > A1*Q31 + A3*Q11 + B2*Q23 + B3*Q22) return 0; + if (dFabs(pp[0]*R32-pp[2]*R12) > A1*Q32 + A3*Q12 + B1*Q23 + B3*Q21) return 0; + if (dFabs(pp[0]*R33-pp[2]*R13) > A1*Q33 + A3*Q13 + B1*Q22 + B2*Q21) return 0; + + // separating axis = u3 x (v1,v2,v3) + if (dFabs(pp[1]*R11-pp[0]*R21) > A1*Q21 + A2*Q11 + B2*Q33 + B3*Q32) return 0; + if (dFabs(pp[1]*R12-pp[0]*R22) > A1*Q22 + A2*Q12 + B1*Q33 + B3*Q31) return 0; + if (dFabs(pp[1]*R13-pp[0]*R23) > A1*Q23 + A2*Q13 + B1*Q32 + B2*Q31) return 0; + + return 1; +} + +//**************************************************************************** +// other utility functions + +void dInfiniteAABB (dxGeom *geom, dReal aabb[6]) +{ + aabb[0] = -dInfinity; + aabb[1] = dInfinity; + aabb[2] = -dInfinity; + aabb[3] = dInfinity; + aabb[4] = -dInfinity; + aabb[5] = dInfinity; +} + + +//////////// ADDED CYLINDER CODE +// clip polygon with plane and generate new polygon points + +//**************************************************************************** +// Helpers for Croteam's collider - by Nguyen Binh + +int dClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane) +{ + // calculate distance of edge points to plane + dReal fDistance0 = dPointPlaneDistance( vEpnt0 ,plPlane ); + dReal fDistance1 = dPointPlaneDistance( vEpnt1 ,plPlane ); + + // if both points are behind the plane + if ( fDistance0 < 0 && fDistance1 < 0 ) + { + // do nothing + return 0; + // if both points in front of the plane + } + else if ( fDistance0 > 0 && fDistance1 > 0 ) + { + // accept them + return 1; + // if we have edge/plane intersection + } else if ((fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0)) + { + + // find intersection point of edge and plane + dVector3 vIntersectionPoint; + vIntersectionPoint[0]= vEpnt0[0]-(vEpnt0[0]-vEpnt1[0])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[1]= vEpnt0[1]-(vEpnt0[1]-vEpnt1[1])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[2]= vEpnt0[2]-(vEpnt0[2]-vEpnt1[2])*fDistance0/(fDistance0-fDistance1); + + // clamp correct edge to intersection point + if ( fDistance0 < 0 ) + { + dVector3Copy(vIntersectionPoint,vEpnt0); + } else + { + dVector3Copy(vIntersectionPoint,vEpnt1); + } + return 1; + } + return 1; +} + +void dClipPolyToPlane( const dVector3 avArrayIn[], const int ctIn, + dVector3 avArrayOut[], int &ctOut, + const dVector4 &plPlane ) +{ + // start with no output points + ctOut = 0; + + int i0 = ctIn-1; + + // for each edge in input polygon + for (int i1=0; i1= 0 ) { + // emit point + avArrayOut[ctOut][0] = avArrayIn[i0][0]; + avArrayOut[ctOut][1] = avArrayIn[i0][1]; + avArrayOut[ctOut][2] = avArrayIn[i0][2]; + ctOut++; + } + + // if points are on different sides + if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) { + + // find intersection point of edge and plane + dVector3 vIntersectionPoint; + vIntersectionPoint[0]= avArrayIn[i0][0] - + (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[1]= avArrayIn[i0][1] - + (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[2]= avArrayIn[i0][2] - + (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1); + + // emit intersection point + avArrayOut[ctOut][0] = vIntersectionPoint[0]; + avArrayOut[ctOut][1] = vIntersectionPoint[1]; + avArrayOut[ctOut][2] = vIntersectionPoint[2]; + ctOut++; + } + } + +} + +void dClipPolyToCircle(const dVector3 avArrayIn[], const int ctIn, + dVector3 avArrayOut[], int &ctOut, + const dVector4 &plPlane ,dReal fRadius) +{ + // start with no output points + ctOut = 0; + + int i0 = ctIn-1; + + // for each edge in input polygon + for (int i1=0; i1= 0 ) + { + // emit point + if (dVector3Length2(avArrayIn[i0]) <= fRadius*fRadius) + { + avArrayOut[ctOut][0] = avArrayIn[i0][0]; + avArrayOut[ctOut][1] = avArrayIn[i0][1]; + avArrayOut[ctOut][2] = avArrayIn[i0][2]; + ctOut++; + } + } + + // if points are on different sides + if( (fDistance0 > 0 && fDistance1 < 0) || ( fDistance0 < 0 && fDistance1 > 0) ) + { + + // find intersection point of edge and plane + dVector3 vIntersectionPoint; + vIntersectionPoint[0]= avArrayIn[i0][0] - + (avArrayIn[i0][0]-avArrayIn[i1][0])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[1]= avArrayIn[i0][1] - + (avArrayIn[i0][1]-avArrayIn[i1][1])*fDistance0/(fDistance0-fDistance1); + vIntersectionPoint[2]= avArrayIn[i0][2] - + (avArrayIn[i0][2]-avArrayIn[i1][2])*fDistance0/(fDistance0-fDistance1); + + // emit intersection point + if (dVector3Length2(avArrayIn[i0]) <= fRadius*fRadius) + { + avArrayOut[ctOut][0] = vIntersectionPoint[0]; + avArrayOut[ctOut][1] = vIntersectionPoint[1]; + avArrayOut[ctOut][2] = vIntersectionPoint[2]; + ctOut++; + } + } + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_collision_util.h b/src/external/open_dynamics_engine-ef/ode/ode_collision_util.h new file mode 100644 index 00000000..ee8d7895 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_collision_util.h @@ -0,0 +1,344 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +some useful collision utility stuff. + +*/ + +#ifndef _ODE_COLLISION_UTIL_H_ +#define _ODE_COLLISION_UTIL_H_ + +#include "ode/ode_common.h" +#include "ode/ode_contact.h" +#include "ode/ode_math.h" +#include "ode/ode_rotation.h" + +// given a pointer `p' to a dContactGeom, return the dContactGeom at +// p + skip bytes. +#define CONTACT(p,skip) ((dContactGeom*) (((char*)p) + (skip))) + + +// if the spheres (p1,r1) and (p2,r2) collide, set the contact `c' and +// return 1, else return 0. + +int dCollideSpheres (dVector3 p1, dReal r1, + dVector3 p2, dReal r2, dContactGeom *c); + + +// given two lines +// qa = pa + alpha* ua +// qb = pb + beta * ub +// where pa,pb are two points, ua,ub are two unit length vectors, and alpha, +// beta go from [-inf,inf], return alpha and beta such that qa and qb are +// as close as possible + +void dLineClosestApproach (const dVector3 pa, const dVector3 ua, + const dVector3 pb, const dVector3 ub, + dReal *alpha, dReal *beta); + + +// given a line segment p1-p2 and a box (center 'c', rotation 'R', side length +// vector 'side'), compute the points of closest approach between the box +// and the line. return these points in 'lret' (the point on the line) and +// 'bret' (the point on the box). if the line actually penetrates the box +// then the solution is not unique, but only one solution will be returned. +// in this case the solution points will coincide. + +void dClosestLineBoxPoints (const dVector3 p1, const dVector3 p2, + const dVector3 c, const dMatrix3 R, + const dVector3 side, + dVector3 lret, dVector3 bret); + + +/// CYLINDER ADDITION +// 20 Apr 2004 +// Start code by Nguyen Binh +int dClipEdgeToPlane( dVector3 &vEpnt0, dVector3 &vEpnt1, const dVector4& plPlane); +// clip polygon with plane and generate new polygon points +void dClipPolyToPlane(const dVector3 avArrayIn[], const int ctIn, + dVector3 avArrayOut[], int &ctOut, + const dVector4 &plPlane ); + +void dClipPolyToCircle(const dVector3 avArrayIn[], const int ctIn, + dVector3 avArrayOut[], int &ctOut, + const dVector4 &plPlane ,dReal fRadius); + + +// Some vector math +inline void dVector3Subtract(const dVector3& a,const dVector3& b,dVector3& c) +{ + c[0] = a[0] - b[0]; + c[1] = a[1] - b[1]; + c[2] = a[2] - b[2]; +} + +// Some vector math +inline void dVector3Scale(dVector3& a,dReal nScale) +{ + a[0] *= nScale ; + a[1] *= nScale ; + a[2] *= nScale ; +} + +inline void dVector3Add(const dVector3& a,const dVector3& b,dVector3& c) +{ + c[0] = a[0] + b[0]; + c[1] = a[1] + b[1]; + c[2] = a[2] + b[2]; +} + +inline void dVector3Copy(const dVector3& a,dVector3& c) +{ + c[0] = a[0]; + c[1] = a[1]; + c[2] = a[2]; +} + +inline void dVector3Cross(const dVector3& a,const dVector3& b,dVector3& c) +{ + dCROSS(c,=,a,b); +} + +inline dReal dVector3Length(const dVector3& a) +{ + return dSqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); +} + +inline dReal dVector3Dot(const dVector3& a,const dVector3& b) +{ + return dDOT(a,b); +} + +inline void dVector3Inv(dVector3& a) +{ + a[0] = -a[0]; + a[1] = -a[1]; + a[2] = -a[2]; +} + +inline dReal dVector3Length2(const dVector3& a) +{ + return (a[0]*a[0]+a[1]*a[1]+a[2]*a[2]); +} + +inline void dMat3GetCol(const dMatrix3& m,const int col, dVector3& v) +{ + v[0] = m[col + 0]; + v[1] = m[col + 4]; + v[2] = m[col + 8]; +} + +inline void dVector3CrossMat3Col(const dMatrix3& m,const int col,const dVector3& v,dVector3& r) +{ + r[0] = v[1] * m[2*4 + col] - v[2] * m[1*4 + col]; + r[1] = v[2] * m[0*4 + col] - v[0] * m[2*4 + col]; + r[2] = v[0] * m[1*4 + col] - v[1] * m[0*4 + col]; +} + +inline void dMat3ColCrossVector3(const dMatrix3& m,const int col,const dVector3& v,dVector3& r) +{ + r[0] = v[2] * m[1*4 + col] - v[1] * m[2*4 + col]; + r[1] = v[0] * m[2*4 + col] - v[2] * m[0*4 + col]; + r[2] = v[1] * m[0*4 + col] - v[0] * m[1*4 + col]; +} + +inline void dMultiplyMat3Vec3(const dMatrix3& m,const dVector3& v, dVector3& r) +{ + dMULTIPLY0_331(r,m,v); +} + +inline dReal dPointPlaneDistance(const dVector3& point,const dVector4& plane) +{ + return (plane[0]*point[0] + plane[1]*point[1] + plane[2]*point[2] + plane[3]); +} + +inline void dConstructPlane(const dVector3& normal,const dReal& distance, dVector4& plane) +{ + plane[0] = normal[0]; + plane[1] = normal[1]; + plane[2] = normal[2]; + plane[3] = distance; +} + +inline void dMatrix3Copy(const dReal* source,dMatrix3& dest) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + + dest[4] = source[4]; + dest[5] = source[5]; + dest[6] = source[6]; + + dest[8] = source[8]; + dest[9] = source[9]; + dest[10]= source[10]; +} + +inline dReal dMatrix3Det( const dMatrix3& mat ) +{ + dReal det; + + det = mat[0] * ( mat[5]*mat[10] - mat[9]*mat[6] ) + - mat[1] * ( mat[4]*mat[10] - mat[8]*mat[6] ) + + mat[2] * ( mat[4]*mat[9] - mat[8]*mat[5] ); + + return( det ); +} + + +inline void dMatrix3Inv( const dMatrix3& ma, dMatrix3& dst ) +{ + dReal det = dMatrix3Det( ma ); + + if ( dFabs( det ) < REAL(0.0005) ) + { + dRSetIdentity( dst ); + return; + } + + dst[0] = ma[5]*ma[10] - ma[6]*ma[9] / det; + dst[1] = -( ma[1]*ma[10] - ma[9]*ma[2] ) / det; + dst[2] = ma[1]*ma[6] - ma[5]*ma[2] / det; + + dst[4] = -( ma[4]*ma[10] - ma[6]*ma[8] ) / det; + dst[5] = ma[0]*ma[10] - ma[8]*ma[2] / det; + dst[6] = -( ma[0]*ma[6] - ma[4]*ma[2] ) / det; + + dst[8] = ma[4]*ma[9] - ma[8]*ma[5] / det; + dst[9] = -( ma[0]*ma[9] - ma[8]*ma[1] ) / det; + dst[10] = ma[0]*ma[5] - ma[1]*ma[4] / det; +} + +inline void dQuatTransform(const dQuaternion& quat,const dVector3& source,dVector3& dest) +{ + + // Nguyen Binh : this code seem to be the fastest. + dReal x0 = source[0] * quat[0] + source[2] * quat[2] - source[1] * quat[3]; + dReal x1 = source[1] * quat[0] + source[0] * quat[3] - source[2] * quat[1]; + dReal x2 = source[2] * quat[0] + source[1] * quat[1] - source[0] * quat[2]; + dReal x3 = source[0] * quat[1] + source[1] * quat[2] + source[2] * quat[3]; + + dest[0] = quat[0] * x0 + quat[1] * x3 + quat[2] * x2 - quat[3] * x1; + dest[1] = quat[0] * x1 + quat[2] * x3 + quat[3] * x0 - quat[1] * x2; + dest[2] = quat[0] * x2 + quat[3] * x3 + quat[1] * x1 - quat[2] * x0; + + /* + // nVidia SDK implementation + dVector3 uv, uuv; + dVector3 qvec; + qvec[0] = quat[1]; + qvec[1] = quat[2]; + qvec[2] = quat[3]; + + dVector3Cross(qvec,source,uv); + dVector3Cross(qvec,uv,uuv); + + dVector3Scale(uv,REAL(2.0)*quat[0]); + dVector3Scale(uuv,REAL(2.0)); + + dest[0] = source[0] + uv[0] + uuv[0]; + dest[1] = source[1] + uv[1] + uuv[1]; + dest[2] = source[2] + uv[2] + uuv[2]; + */ +} + +inline void dQuatInvTransform(const dQuaternion& quat,const dVector3& source,dVector3& dest) +{ + + dReal norm = quat[0]*quat[0] + quat[1]*quat[1] + quat[2]*quat[2] + quat[3]*quat[3]; + + if (norm > REAL(0.0)) + { + dQuaternion invQuat; + invQuat[0] = quat[0] / norm; + invQuat[1] = -quat[1] / norm; + invQuat[2] = -quat[2] / norm; + invQuat[3] = -quat[3] / norm; + + dQuatTransform(invQuat,source,dest); + + } + else + { + // Singular -> return identity + dVector3Copy(source,dest); + } +} + +inline void dGetEulerAngleFromRot(const dMatrix3& mRot,dReal& rX,dReal& rY,dReal& rZ) +{ + rY = asin(mRot[0 * 4 + 2]); + if (rY < M_PI /2) + { + if (rY > -M_PI /2) + { + rX = atan2(-mRot[1*4 + 2], mRot[2*4 + 2]); + rZ = atan2(-mRot[0*4 + 1], mRot[0*4 + 0]); + } + else + { + // not unique + rX = -atan2(mRot[1*4 + 0], mRot[1*4 + 1]); + rZ = REAL(0.0); + } + } + else + { + // not unique + rX = atan2(mRot[1*4 + 0], mRot[1*4 + 1]); + rZ = REAL(0.0); + } +} + +inline void dQuatInv(const dQuaternion& source, dQuaternion& dest) +{ + dReal norm = source[0]*source[0] + source[1]*source[1] + source[2]*source[2] + source[3]*source[3]; + + if (norm > 0.0f) + { + dest[0] = source[0] / norm; + dest[1] = -source[1] / norm; + dest[2] = -source[2] / norm; + dest[3] = -source[3] / norm; + } + else + { + // Singular -> return identity + dest[0] = REAL(1.0); + dest[1] = REAL(0.0); + dest[2] = REAL(0.0); + dest[3] = REAL(0.0); + } +} + +// Fetches a contact +inline dContactGeom* SAFECONTACT(int Flags, dContactGeom* Contacts, int Index, int Stride){ + dIASSERT(Index >= 0 && Index < (Flags & 0x0ffff)); + return ((dContactGeom*)(((char*)Contacts) + (Index * Stride))); +} + + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_common.h b/src/external/open_dynamics_engine-ef/ode/ode_common.h new file mode 100644 index 00000000..ef33df2f --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_common.h @@ -0,0 +1,357 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_COMMON_H_ +#define _ODE_COMMON_H_ + +#include "ode/ode_config.h" +#include "ode/ode_error.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +/* configuration stuff */ + +/* the efficient alignment. most platforms align data structures to some + * number of bytes, but this is not always the most efficient alignment. + * for example, many x86 compilers align to 4 bytes, but on a pentium it + * is important to align doubles to 8 byte boundaries (for speed), and + * the 4 floats in a SIMD register to 16 byte boundaries. many other + * platforms have similar behavior. setting a larger alignment can waste + * a (very) small amount of memory. NOTE: this number must be a power of + * two. this is set to 16 by default. + */ +#define EFFICIENT_ALIGNMENT 16 + + +/* constants */ + +/* pi and 1/sqrt(2) are defined here if necessary because they don't get + * defined in on some platforms (like MS-Windows) + */ + +#ifndef M_PI +#define M_PI REAL(3.1415926535897932384626433832795029) +#endif +#ifndef M_SQRT1_2 +#define M_SQRT1_2 REAL(0.7071067811865475244008443621048490) +#endif + + +/* debugging: + * IASSERT is an internal assertion, i.e. a consistency check. if it fails + * we want to know where. + * UASSERT is a user assertion, i.e. if it fails a nice error message + * should be printed for the user. + * AASSERT is an arguments assertion, i.e. if it fails "bad argument(s)" + * is printed. + * DEBUGMSG just prints out a message + */ + +#ifndef dNODEBUG +#ifdef __GNUC__ +#define dIASSERT(a) if (!(a)) dDebug (d_ERR_IASSERT, \ + "assertion \"" #a "\" failed in %s() [%s]",__FUNCTION__,__FILE__) +#define dUASSERT(a,msg) if (!(a)) dDebug (d_ERR_UASSERT, \ + msg " in %s()", __FUNCTION__) +#define dDEBUGMSG(msg) dMessage (d_ERR_UASSERT, \ + msg " in %s()", __FUNCTION__) +#else +#define dIASSERT(a) if (!(a)) dDebug (d_ERR_IASSERT, \ + "assertion \"" #a "\" failed in %s:%d",__FILE__,__LINE__); +#define dUASSERT(a,msg) if (!(a)) dDebug (d_ERR_UASSERT, \ + msg " (%s:%d)", __FILE__,__LINE__); +#define dDEBUGMSG(msg) dMessage (d_ERR_UASSERT, \ + msg " (%s:%d)", __FILE__,__LINE__); +#endif +#else +#define dIASSERT(a) ; +#define dUASSERT(a,msg) ; +#define dDEBUGMSG(msg) ; +#endif +#define dAASSERT(a) dUASSERT(a,"Bad argument(s)") + +/* floating point data type, vector, matrix and quaternion types */ + +#if defined(dSINGLE) +typedef float dReal; +#elif defined(dDOUBLE) +typedef double dReal; +#else +#error You must #define dSINGLE or dDOUBLE +#endif + +//epsilon +#if defined(dSINGLE) + #define ODE_EPSILON FLT_EPSILON +#else + #define ODE_EPSILON DBL_EPSILON +#endif + + +/* round an integer up to a multiple of 4, except that 0 and 1 are unmodified + * (used to compute matrix leading dimensions) + */ +#define dPAD(a) (((a) > 1) ? ((((a)-1)|3)+1) : (a)) + +/* these types are mainly just used in headers */ +typedef dReal dVector3[4]; +typedef dReal dVector4[4]; +typedef dReal dMatrix3[4*3]; +typedef dReal dMatrix4[4*4]; +typedef dReal dMatrix6[8*6]; +typedef dReal dQuaternion[4]; + + +/* precision dependent scalar math functions */ + +#if defined(dSINGLE) + +#define REAL(x) (x ## f) /* form a constant */ +#define dRecip(x) ((float)(1.0f/(x))) /* reciprocal */ +#define dSqrt(x) ((float)sqrtf(float(x))) /* square root */ +#define dRecipSqrt(x) ((float)(1.0f/sqrtf(float(x)))) /* reciprocal square root */ +#define dSin(x) ((float)sinf(float(x))) /* sine */ +#define dCos(x) ((float)cosf(float(x))) /* cosine */ +#define dFabs(x) ((float)fabsf(float(x))) /* absolute value */ +#define dAtan2(y,x) ((float)atan2f(float(y),float(x))) /* arc tangent with 2 args */ +#define dFMod(a,b) ((float)fmodf(float(a),float(b))) /* modulo */ +// #ifdef WIN32 // ericf added +#if 0 +#define dCopySign(a,b) ((float)copysign(float(a),float(b))) +#else +#define dCopySign(a,b) ((float)copysignf(float(a),float(b))) +#endif + +#elif defined(dDOUBLE) + +#define REAL(x) (x) +#define dRecip(x) (1.0/(x)) +#define dSqrt(x) sqrt(x) +#define dRecipSqrt(x) (1.0/sqrt(x)) +#define dSin(x) sin(x) +#define dCos(x) cos(x) +#define dFabs(x) fabs(x) +#define dAtan2(y,x) atan2((y),(x)) +#define dFMod(a,b) (fmod((a),(b))) +#define dCopySign(a,b) (copysign((a),(b))) + +#else +#error You must #define dSINGLE or dDOUBLE +#endif + + +/* utility */ + + +/* round something up to be a multiple of the EFFICIENT_ALIGNMENT */ + +#define dEFFICIENT_SIZE(x) ((((x)-1)|(EFFICIENT_ALIGNMENT-1))+1) + + +/* alloca aligned to the EFFICIENT_ALIGNMENT. note that this can waste + * up to 15 bytes per allocation, depending on what alloca() returns. + */ + +#define dALLOCA16(n) \ + ((char*)dEFFICIENT_SIZE(((size_t)(alloca((n)+(EFFICIENT_ALIGNMENT-1)))))) + + +// Use the error-checking memory allocation system. Becuase this system uses heap +// (malloc) instead of stack (alloca), it is slower. However, it allows you to +// simulate larger scenes, as well as handle out-of-memory errors in a somewhat +// graceful manner + +// #define dUSE_MALLOC_FOR_ALLOCA + +#ifdef dUSE_MALLOC_FOR_ALLOCA +enum { + d_MEMORY_OK = 0, /* no memory errors */ + d_MEMORY_OUT_OF_MEMORY /* malloc failed due to out of memory error */ +}; + +#endif + + + +/* internal object types (all prefixed with `dx') */ + +struct dxWorld; /* dynamics world */ +struct dxSpace; /* collision space */ +struct dxBody; /* rigid body (dynamics object) */ +struct dxGeom; /* geometry (collision object) */ +struct dxJoint; +struct dxJointNode; +struct dxJointGroup; + +typedef struct dxWorld *dWorldID; +typedef struct dxSpace *dSpaceID; +typedef struct dxBody *dBodyID; +typedef struct dxGeom *dGeomID; +typedef struct dxJoint *dJointID; +typedef struct dxJointGroup *dJointGroupID; + + +/* error numbers */ + +enum { + d_ERR_UNKNOWN = 0, /* unknown error */ + d_ERR_IASSERT, /* internal assertion failed */ + d_ERR_UASSERT, /* user assertion failed */ + d_ERR_LCP /* user assertion failed */ +}; + + +/* joint type numbers */ + +enum { + dJointTypeNone = 0, /* or "unknown" */ + dJointTypeBall, + dJointTypeHinge, + dJointTypeSlider, + dJointTypeContact, + dJointTypeUniversal, + dJointTypeHinge2, + dJointTypeFixed, + dJointTypeNull, + dJointTypeAMotor +}; + + +/* an alternative way of setting joint parameters, using joint parameter + * structures and member constants. we don't actually do this yet. + */ + +/* +typedef struct dLimot { + int mode; + dReal lostop, histop; + dReal vel, fmax; + dReal fudge_factor; + dReal bounce, soft; + dReal suspension_erp, suspension_cfm; +} dLimot; + +enum { + dLimotLoStop = 0x0001, + dLimotHiStop = 0x0002, + dLimotVel = 0x0004, + dLimotFMax = 0x0008, + dLimotFudgeFactor = 0x0010, + dLimotBounce = 0x0020, + dLimotSoft = 0x0040 +}; +*/ + + +/* standard joint parameter names. why are these here? - because we don't want + * to include all the joint function definitions in joint.cpp. hmmmm. + * MSVC complains if we call D_ALL_PARAM_NAMES_X with a blank second argument, + * which is why we have the D_ALL_PARAM_NAMES macro as well. please copy and + * paste between these two. + */ + +#define D_ALL_PARAM_NAMES(start) \ + /* parameters for limits and motors */ \ + dParamLoStop = start, \ + dParamHiStop, \ + dParamVel, \ + dParamFMax, \ + dParamFudgeFactor, \ + dParamBounce, \ + dParamCFM, \ + dParamStopERP, \ + dParamStopCFM, \ + /* parameters for suspension */ \ + dParamSuspensionERP, \ + dParamSuspensionCFM, \ + dParamStiffness, \ + dParamDamping, \ + dParamActive, \ + dParamLinearStiffness, \ + dParamLinearDamping, \ + dParamAngularStiffness, \ + dParamAngularDamping, + +#define D_ALL_PARAM_NAMES_X(start,x) \ + /* parameters for limits and motors */ \ + dParamLoStop ## x = start, \ + dParamHiStop ## x, \ + dParamVel ## x, \ + dParamFMax ## x, \ + dParamFudgeFactor ## x, \ + dParamBounce ## x, \ + dParamCFM ## x, \ + dParamStopERP ## x, \ + dParamStopCFM ## x, \ + /* parameters for suspension */ \ + dParamSuspensionERP ## x, \ + dParamSuspensionCFM ## x, + +enum { + D_ALL_PARAM_NAMES(0) + D_ALL_PARAM_NAMES_X(0x100,2) + D_ALL_PARAM_NAMES_X(0x200,3) + + /* add a multiple of this constant to the basic parameter numbers to get + * the parameters for the second, third etc axes. + */ + dParamGroup=0x100 +}; + + +/* angular motor mode numbers */ + +enum{ + dAMotorUser = 0, + dAMotorEuler = 1 +}; + + +/* joint force feedback information */ + +typedef struct dJointFeedback { + dVector3 f1; /* force applied to body 1 */ + dVector3 t1; /* torque applied to body 1 */ + dVector3 f2; /* force applied to body 2 */ + dVector3 t2; /* torque applied to body 2 */ +} dJointFeedback; + + +/* private functions that must be implemented by the collision library: + * (1) indicate that a geom has moved, (2) get the next geom in a body list. + * these functions are called whenever the position of geoms connected to a + * body have changed, e.g. with dBodySetPosition(), dBodySetRotation(), or + * when the ODE step function updates the body state. + */ + +void dGeomMoved (dGeomID); +dGeomID dGeomGetBodyNext (dGeomID); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_compatibility.h b/src/external/open_dynamics_engine-ef/ode/ode_compatibility.h new file mode 100644 index 00000000..b3709866 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_compatibility.h @@ -0,0 +1,40 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_COMPATIBILITY_H_ +#define _ODE_COMPATIBILITY_H_ + +/* + * ODE's backward compatibility system ensures that as ODE's API + * evolves, user code will not break. + */ + +/* + * These new rotation function names are more consistent with the + * rest of the API. + */ +#define dQtoR(q,R) dRfromQ((R),(q)) +#define dRtoQ(R,q) dQfromR((q),(R)) +#define dWtoDQ(w,q,dq) dDQfromW((dq),(w),(q)) + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_config.h b/src/external/open_dynamics_engine-ef/ode/ode_config.h new file mode 100644 index 00000000..adce621d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_config.h @@ -0,0 +1,77 @@ +/* per-machine configuration. this file is automatically generated. */ + +#ifndef _ODE_CONFIG_H_ +#define _ODE_CONFIG_H_ + +#if HAVE_CONFIG_H +# include +#endif + +/* standard system headers */ +#include +#include +#include +#include +#include +#include + +#if BA_OSTYPE_WINDOWS +//#include +#else +#include +#endif + +//#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* is this a pentium on a gcc-based platform? */ +// moved to makefile +//#define PENTIUM 1 + +/* #if BA_PROCTYPE_X86 */ +// moved to makefile +/* # define PENTIUM 1 */ +/* #endif */ + +/* #if BA_PROCTYPE_X86_64 */ +/* # define PENTIUM 1 */ +/* # define SYS64bits 1 */ +/* #endif */ + +/* #if !BA_DEBUG_BUILD */ +/* #endif */ + +/* is this a 64bit system on a gcc-based platform? */ +// #define SYS64bits 1 + +/* integer types (we assume int >= 32 bits) */ +typedef int8_t int8; +typedef uint8_t uint8; +typedef int16_t int16; +typedef uint16_t uint16; +typedef int32_t int32; +typedef uint32_t uint32; + +/* an integer type that we can safely cast a pointer to and + * from without loss of bits. + */ +typedef uintptr_t intP; + +/* select the base floating point type */ +//#define dDOUBLE 1 +#define dSINGLE 1 + +/* the floating point infinity */ +//#define dInfinity DBL_MAX +#define dInfinity FLT_MAX + +/* available functions */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_contact.h b/src/external/open_dynamics_engine-ef/ode/ode_contact.h new file mode 100644 index 00000000..3561a41b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_contact.h @@ -0,0 +1,91 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_CONTACT_H_ +#define _ODE_CONTACT_H_ + +#include "ode/ode_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +enum { + dContactMu2 = 0x001, + dContactFDir1 = 0x002, + dContactBounce = 0x004, + dContactSoftERP = 0x008, + dContactSoftCFM = 0x010, + dContactMotion1 = 0x020, + dContactMotion2 = 0x040, + dContactSlip1 = 0x080, + dContactSlip2 = 0x100, + dContactMotionN = 0x200, + + dContactApprox0 = 0x0000, + dContactApprox1_1 = 0x1000, + dContactApprox1_2 = 0x2000, + dContactApprox1 = 0x3000 +}; + + +typedef struct dSurfaceParameters { + /* must always be defined */ + int mode; + dReal mu; + + /* only defined if the corresponding flag is set in mode */ + dReal mu2; + dReal bounce; + dReal bounce_vel; + dReal soft_erp; + dReal soft_cfm; + dReal motion1,motion2,motionN; + dReal slip1,slip2; +} dSurfaceParameters; + + +/* contact info set by collision functions */ + +typedef struct dContactGeom { + dVector3 pos; + dVector3 normal; + dReal depth; + dGeomID g1,g2; +} dContactGeom; + + +/* contact info used by contact joint */ + +typedef struct dContact { + dSurfaceParameters surface; + dContactGeom geom; + dVector3 fdir1; +} dContact; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_drawstuff.h b/src/external/open_dynamics_engine-ef/ode/ode_drawstuff.h new file mode 100644 index 00000000..2d28263d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_drawstuff.h @@ -0,0 +1,164 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +Draw Stuff +---------- + +this is a library for rendering simple 3D objects in a virtual environment. + +NOTES +----- + +in the virtual world, the z axis is "up" and z=0 is the floor. + +the user is able to click+drag in the main window to move the camera: + * left button - pan and tilt. + * right button - forward and sideways. + * left + right button (or middle button) - sideways and up. + +*/ + + +#ifndef __DRAWSTUFF_H__ +#define __DRAWSTUFF_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "ode/ode_drawstuff_version.h" + + +/* texture numbers */ +#define DS_NONE 0 /* uses the current color instead of a texture */ +#define DS_WOOD 1 + + +typedef struct dsFunctions { + int version; /* put DS_VERSION here */ + /* version 1 data */ + void (*start)(); /* called before sim loop starts */ + void (*step) (int pause); /* called before every frame */ + void (*command) (int cmd); /* called if a command key is pressed */ + void (*stop)(); /* called after sim loop exits */ + /* version 2 data */ + char *path_to_textures; /* if nonzero, path to texture files */ +} dsFunctions; + + +/* the main() function should fill in the dsFunctions structure then + * call this. + */ +void dsSimulationLoop (int argc, char **argv, + int window_width, int window_height, + struct dsFunctions *fn); + +/* these functions display an error message then exit. they take arguments + * in the same way as printf(), except you do not have to add a terminating + * '\n'. Debug() tries to dump core or start the debugger. + */ +void dsError (char *msg, ...); +void dsDebug (char *msg, ...); + +/* dsPrint() prints out a message. it takes arguments in the same way as + * printf() (i.e. you must add a '\n' at the end of every line). + */ +void dsPrint (char *msg, ...); + +/* set and get the camera position. xyz is the cameria position (x,y,z). + * hpr contains heading, pitch and roll numbers in degrees. heading=0 + * points along the x axis, pitch=0 is looking towards the horizon, and + * roll 0 is "unrotated". + */ +void dsSetViewpoint (float xyz[3], float hpr[3]); +void dsGetViewpoint (float xyz[3], float hpr[3]); + +/* stop the simulation loop. calling this from within dsSimulationLoop() + * will cause it to exit and return to the caller. it is the same as if the + * user used the exit command. using this outside the loop will have no + * effect. + */ +void dsStop(); + +/* change the way objects are drawn. these changes will apply to all further + * dsDrawXXX() functions. the texture number must be a DS_xxx texture + * constant. the red, green, and blue number are between 0 and 1. + * alpha is between 0 and 1 - if alpha is not specified it's assubed to be 1. + * the current texture is colored according to the current color. + * at the start of each frame, the texture is reset to none and the color is + * reset to white. + */ +void dsSetTexture (int texture_number); +void dsSetColor (float red, float green, float blue); +void dsSetColorAlpha (float red, float green, float blue, float alpha); + +/* draw objects. + * - pos[] is the x,y,z of the center of the object. + * - R[] is a 3x3 rotation matrix for the object, stored by row like this: + * [ R11 R12 R13 0 ] + * [ R21 R22 R23 0 ] + * [ R31 R32 R33 0 ] + * - sides[] is an array of x,y,z side lengths. + * - all cylinders are aligned along the z axis. + */ +void dsDrawBox (const float pos[3], const float R[12], const float sides[3]); +void dsDrawSphere (const float pos[3], const float R[12], float radius); +void dsDrawTriangle (const float pos[3], const float R[12], + const float *v0, const float *v1, const float *v2, int solid); +void dsDrawCylinder (const float pos[3], const float R[12], + float length, float radius); +void dsDrawCappedCylinder (const float pos[3], const float R[12], + float length, float radius); +void dsDrawLine (const float pos1[3], const float pos2[3]); + +/* these drawing functions are identical to the ones above, except they take + * double arrays for `pos' and `R'. + */ +void dsDrawBoxD (const double pos[3], const double R[12], + const double sides[3]); +void dsDrawSphereD (const double pos[3], const double R[12], + const float radius); +void dsDrawTriangleD (const double pos[3], const double R[12], + const double *v0, const double *v1, const double *v2, int solid); +void dsDrawCylinderD (const double pos[3], const double R[12], + float length, float radius); +void dsDrawCappedCylinderD (const double pos[3], const double R[12], + float length, float radius); +void dsDrawLineD (const double pos1[3], const double pos2[3]); + +/* Set the drawn quality of the objects. Higher numbers are higher quality, + * but slower to draw. This must be set before the first objects are drawn to + * be effective. + */ +void dsSetSphereQuality (int n); /* default = 1 */ +void dsSetCappedCylinderQuality (int n); /* default = 3 */ + + +/* closing bracket for extern "C" */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_drawstuff_version.h b/src/external/open_dynamics_engine-ef/ode/ode_drawstuff_version.h new file mode 100644 index 00000000..71d95f46 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_drawstuff_version.h @@ -0,0 +1,29 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef __VERSION_H +#define __VERSION_H + +/* high byte is major version, low byte is minor version */ +#define DS_VERSION 0x0002 + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_error.cpp b/src/external/open_dynamics_engine-ef/ode/ode_error.cpp new file mode 100644 index 00000000..4fa3b98b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_error.cpp @@ -0,0 +1,175 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_config.h" +#include "ode/ode_error.h" + + +static dMessageFunction *error_function = 0; +static dMessageFunction *debug_function = 0; +static dMessageFunction *message_function = 0; + + +extern "C" void dSetErrorHandler (dMessageFunction *fn) +{ + error_function = fn; +} + + +extern "C" void dSetDebugHandler (dMessageFunction *fn) +{ + debug_function = fn; +} + + +extern "C" void dSetMessageHandler (dMessageFunction *fn) +{ + message_function = fn; +} + + +extern "C" dMessageFunction *dGetErrorHandler() +{ + return error_function; +} + + +extern "C" dMessageFunction *dGetDebugHandler() +{ + return debug_function; +} + + +extern "C" dMessageFunction *dGetMessageHandler() +{ + return message_function; +} + + +static void printMessage (int num, const char *msg1, const char *msg2, + va_list ap) +{ + fflush (stderr); + fflush (stdout); + if (num) fprintf (stderr,"\n%s %d: ",msg1,num); + else fprintf (stderr,"\n%s: ",msg1); + vfprintf (stderr,msg2,ap); + fprintf (stderr,"\n"); + fflush (stderr); +} + +//**************************************************************************** +// unix + +#ifndef WIN32 + +extern "C" void dError (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (error_function) error_function (num,msg,ap); + else printMessage (num,"ODE Error",msg,ap); + exit (1); +} + + +extern "C" void dDebug (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (debug_function) debug_function (num,msg,ap); + else printMessage (num,"ODE INTERNAL ERROR",msg,ap); + // *((char *)0) = 0; ... commit SEGVicide + abort(); +} + + +extern "C" void dMessage (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (message_function) message_function (num,msg,ap); + else printMessage (num,"ODE Message",msg,ap); +} + +#endif + +//**************************************************************************** +// windows + +#ifdef WIN32 + +// isn't cygwin annoying! +#ifdef CYGWIN +#define _snprintf snprintf +#define _vsnprintf vsnprintf +#endif + + +#include "windows.h" + + +extern "C" void dError (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (error_function) error_function (num,msg,ap); + else { + char s[1000],title[100]; + _snprintf (title,sizeof(title),"ODE Error %d",num); + _vsnprintf (s,sizeof(s),msg,ap); + s[sizeof(s)-1] = 0; + //printf("FIXME dError NEEDS UPDATING\n"); + //cout << "FIXME DERROR BROKEN" << endl; + //MessageBox(0,s,title,MB_OK | MB_ICONWARNING); + } + exit (1); +} + + +extern "C" void dDebug (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (debug_function) debug_function (num,msg,ap); + else { + char s[1000],title[100]; + _snprintf (title,sizeof(title),"ODE INTERNAL ERROR %d",num); + _vsnprintf (s,sizeof(s),msg,ap); + s[sizeof(s)-1] = 0; + printf("FIXME dDebug NEEDS UPDATING\n"); + //MessageBox(0,s,title,MB_OK | MB_ICONSTOP); + } + abort(); +} + + +extern "C" void dMessage (int num, const char *msg, ...) +{ + va_list ap; + va_start (ap,msg); + if (message_function) message_function (num,msg,ap); + else printMessage (num,"ODE Message",msg,ap); +} + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_error.h b/src/external/open_dynamics_engine-ef/ode/ode_error.h new file mode 100644 index 00000000..dd8e604a --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_error.h @@ -0,0 +1,63 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source */ + +#ifndef _ODE_ERROR_H_ +#define _ODE_ERROR_H_ + +#include "ode/ode_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* all user defined error functions have this type. error and debug functions + * should not return. + */ +typedef void dMessageFunction (int errnum, const char *msg, va_list ap); + +/* set a new error, debug or warning handler. if fn is 0, the default handlers + * are used. + */ +void dSetErrorHandler (dMessageFunction *fn); +void dSetDebugHandler (dMessageFunction *fn); +void dSetMessageHandler (dMessageFunction *fn); + +/* return the current error, debug or warning handler. if the return value is + * 0, the default handlers are in place. + */ +dMessageFunction *dGetErrorHandler(void); +dMessageFunction *dGetDebugHandler(void); +dMessageFunction *dGetMessageHandler(void); + +/* generate a fatal error, debug trap or a message. */ +void dError (int num, const char *msg, ...); +void dDebug (int num, const char *msg, ...); +void dMessage (int num, const char *msg, ...); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_export-dif.h b/src/external/open_dynamics_engine-ef/ode/ode_export-dif.h new file mode 100644 index 00000000..313d8727 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_export-dif.h @@ -0,0 +1,32 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_EXPORT_DIF_ +#define _ODE_EXPORT_DIF_ + +#include "ode/ode_common.h" + + +void dWorldExportDIF (dWorldID w, FILE *file, const char *world_name); + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_export-diff.cpp b/src/external/open_dynamics_engine-ef/ode/ode_export-diff.cpp new file mode 100644 index 00000000..935bcee8 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_export-diff.cpp @@ -0,0 +1,533 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + * Export a DIF (Dynamics Interchange Format) file. + */ + + +// @@@ TODO: +// * export all spaces, and geoms in spaces, not just ones attached to bodies +// (separate export function?) +// * say the space each geom is in, so reader can construct space heirarchy +// * limot --> separate out into limits and motors? +// * make sure ODE-specific parameters divided out + + +#include "ode/ode.h" +#include "ode/ode_objects_private.h" +#include "ode/ode_joint.h" +#include "ode/ode_collision_kernel.h" + +//*************************************************************************** +// utility + +struct PrintingContext { + FILE *file; // file to write to + int precision; // digits of precision to print + int indent; // number of levels of indent + + void printIndent(); + void printReal (dReal x); + void print (const char *name, int x); + void print (const char *name, dReal x); + void print (const char *name, const dReal *x, int n=3); + void print (const char *name, const char *x=0); + void printNonzero (const char *name, dReal x); + void printNonzero (const char *name, const dReal x[3]); +}; + + +void PrintingContext::printIndent() +{ + for (int i=0; i= 0) { + c.printIndent(); + fprintf (c.file,"limit%d = {\n",num); + } + else { + c.print ("limit = {"); + } + c.indent++; + c.print ("low_stop",limot.lostop); + c.print ("high_stop",limot.histop); + c.printNonzero ("bounce",limot.bounce); + c.print ("ODE = {"); + c.indent++; + c.printNonzero ("stop_erp",limot.stop_erp); + c.printNonzero ("stop_cfm",limot.stop_cfm); + c.indent--; + c.print ("},"); + c.indent--; + c.print ("},"); + + if (num >= 0) { + c.printIndent(); + fprintf (c.file,"motor%d = {\n",num); + } + else { + c.print ("motor = {"); + } + c.indent++; + c.printNonzero ("vel",limot.vel); + c.printNonzero ("fmax",limot.fmax); + c.print ("ODE = {"); + c.indent++; + c.printNonzero ("fudge_factor",limot.fudge_factor); + c.printNonzero ("normal_cfm",limot.normal_cfm); + c.indent--; + c.print ("},"); + c.indent--; + c.print ("},"); +} + + +static const char *getJointName (dxJoint *j) +{ + switch (j->vtable->typenum) { + case dJointTypeBall: return "ball"; + case dJointTypeHinge: return "hinge"; + case dJointTypeSlider: return "slider"; + case dJointTypeContact: return "contact"; + case dJointTypeUniversal: return "universal"; + case dJointTypeHinge2: return "ODE_hinge2"; + case dJointTypeFixed: return "fixed"; + case dJointTypeNull: return "null"; + case dJointTypeAMotor: return "ODE_angular_motor"; + } + return "unknown"; +} + + +static void printBall (PrintingContext &c, dxJoint *j) +{ + dxJointBall *b = (dxJointBall*) j; + c.print ("anchor1",b->anchor1); + c.print ("anchor2",b->anchor2); +} + + +static void printHinge (PrintingContext &c, dxJoint *j) +{ + dxJointHinge *h = (dxJointHinge*) j; + c.print ("anchor1",h->anchor1); + c.print ("anchor2",h->anchor2); + c.print ("axis1",h->axis1); + c.print ("axis2",h->axis2); + c.print ("qrel",h->qrel,4); + printLimot (c,h->limot,-1); +} + + +static void printSlider (PrintingContext &c, dxJoint *j) +{ + dxJointSlider *s = (dxJointSlider*) j; + c.print ("axis1",s->axis1); + c.print ("qrel",s->qrel,4); + c.print ("offset",s->offset); + printLimot (c,s->limot,-1); +} + + +static void printContact (PrintingContext &c, dxJoint *j) +{ + dxJointContact *ct = (dxJointContact*) j; + int mode = ct->contact.surface.mode; + c.print ("pos",ct->contact.geom.pos); + c.print ("normal",ct->contact.geom.normal); + c.print ("depth",ct->contact.geom.depth); + //@@@ may want to write the geoms g1 and g2 that are involved, for debugging. + // to do this we must have written out all geoms in all spaces, not just + // geoms that are attached to bodies. + c.print ("mu",ct->contact.surface.mu); + if (mode & dContactMu2) c.print ("mu2",ct->contact.surface.mu2); + if (mode & dContactBounce) c.print ("bounce",ct->contact.surface.bounce); + if (mode & dContactBounce) c.print ("bounce_vel",ct->contact.surface.bounce_vel); + if (mode & dContactSoftERP) c.print ("soft_ERP",ct->contact.surface.soft_erp); + if (mode & dContactSoftCFM) c.print ("soft_CFM",ct->contact.surface.soft_cfm); + if (mode & dContactMotion1) c.print ("motion1",ct->contact.surface.motion1); + if (mode & dContactMotion2) c.print ("motion2",ct->contact.surface.motion2); + if (mode & dContactSlip1) c.print ("slip1",ct->contact.surface.slip1); + if (mode & dContactSlip2) c.print ("slip2",ct->contact.surface.slip2); + int fa = 0; // friction approximation code + if (mode & dContactApprox1_1) fa |= 1; + if (mode & dContactApprox1_2) fa |= 2; + if (fa) c.print ("friction_approximation",fa); + if (mode & dContactFDir1) c.print ("fdir1",ct->contact.fdir1); +} + + +static void printUniversal (PrintingContext &c, dxJoint *j) +{ + dxJointUniversal *u = (dxJointUniversal*) j; + c.print ("anchor1",u->anchor1); + c.print ("anchor2",u->anchor2); + c.print ("axis1",u->axis1); + c.print ("axis2",u->axis2); + c.print ("qrel1",u->qrel1,4); + c.print ("qrel2",u->qrel2,4); + printLimot (c,u->limot1,1); + printLimot (c,u->limot2,2); +} + + +static void printHinge2 (PrintingContext &c, dxJoint *j) +{ + dxJointHinge2 *h = (dxJointHinge2*) j; + c.print ("anchor1",h->anchor1); + c.print ("anchor2",h->anchor2); + c.print ("axis1",h->axis1); + c.print ("axis2",h->axis2); + c.print ("v1",h->v1); //@@@ much better to write out 'qrel' here, if it's available + c.print ("v2",h->v2); + c.print ("susp_erp",h->susp_erp); + c.print ("susp_cfm",h->susp_cfm); + printLimot (c,h->limot1,1); + printLimot (c,h->limot2,2); +} + + +static void printFixed (PrintingContext &c, dxJoint *j) +{ + dxJointFixed *f = (dxJointFixed*) j; + c.print ("qrel",f->qrel); + c.print ("offset",f->offset); +} + + +static void printAMotor (PrintingContext &c, dxJoint *j) +{ + dxJointAMotor *a = (dxJointAMotor*) j; + c.print ("num",a->num); + c.print ("mode",a->mode); + c.printIndent(); + fprintf (c.file,"rel = {%d,%d,%d},\n",a->rel[0],a->rel[1],a->rel[2]); + c.print ("axis1",a->axis[0]); + c.print ("axis2",a->axis[1]); + c.print ("axis3",a->axis[2]); + for (int i=0; i<3; i++) printLimot (c,a->limot[i],i+1); + c.print ("angle1",a->angle[0]); + c.print ("angle2",a->angle[1]); + c.print ("angle3",a->angle[2]); +} + +//*************************************************************************** +// geometry + +static void printGeom (PrintingContext &c, dxGeom *g); + +static void printSphere (PrintingContext &c, dxGeom *g) +{ + c.print ("type","sphere"); + c.print ("radius",dGeomSphereGetRadius (g)); +} + + +static void printBox (PrintingContext &c, dxGeom *g) +{ + dVector3 sides; + dGeomBoxGetLengths (g,sides); + c.print ("type","box"); + c.print ("sides",sides); +} + + + +static void printCCylinder (PrintingContext &c, dxGeom *g) +{ + dReal radius,length; + dGeomCCylinderGetParams (g,&radius,&length); + c.print ("type","capsule"); + c.print ("radius",radius); + c.print ("length",length); +} + + +static void printPlane (PrintingContext &c, dxGeom *g) +{ + dVector4 e; + dGeomPlaneGetParams (g,e); + c.print ("type","plane"); + c.print ("normal",e); + c.print ("d",e[3]); +} + + + +static void printRay (PrintingContext &c, dxGeom *g) +{ + dReal length = dGeomRayGetLength (g); + c.print ("type","ray"); + c.print ("length",length); +} + + + +static void printGeomTransform (PrintingContext &c, dxGeom *g) +{ + dxGeom *g2 = dGeomTransformGetGeom (g); + const dReal *pos = dGeomGetPosition (g2); + dQuaternion q; + dGeomGetQuaternion (g2,q); + c.print ("type","transform"); + c.print ("pos",pos); + c.print ("q",q,4); + c.print ("geometry = {"); + c.indent++; + printGeom (c,g2); + c.indent--; + c.print ("}"); +} + + + +static void printTriMesh (PrintingContext &c, dxGeom *g) +{ + c.print ("type","trimesh"); + //@@@ i don't think that the trimesh accessor functions are really + // sufficient to read out all the triangle data, and anyway we + // should have a method of not duplicating trimesh data that is + // shared. +} + + +static void printGeom (PrintingContext &c, dxGeom *g) +{ + unsigned long category = dGeomGetCategoryBits (g); + if (category != (unsigned long)(~0)) { + c.printIndent(); + fprintf (c.file,"category_bits = %lu\n",category); + } + unsigned long collide = dGeomGetCollideBits (g); + if (collide != (unsigned long)(~0)) { + c.printIndent(); + fprintf (c.file,"collide_bits = %lu\n",collide); + } + if (!dGeomIsEnabled (g)) { + c.print ("disabled",1); + } + switch (g->type) { + case dSphereClass: printSphere (c,g); break; + case dBoxClass: printBox (c,g); break; + case dCCylinderClass: printCCylinder (c,g); break; + case dPlaneClass: printPlane (c,g); break; + case dRayClass: printRay (c,g); break; + case dGeomTransformClass: printGeomTransform (c,g); break; + case dTriMeshClass: printTriMesh (c,g); break; + } +} + +//*************************************************************************** +// world + +void dWorldExportDIF (dWorldID w, FILE *file, const char *prefix) +{ + PrintingContext c; + c.file = file; +#if defined(dSINGLE) + c.precision = 7; +#else + c.precision = 15; +#endif + c.indent = 1; + + fprintf (file,"-- Dynamics Interchange Format v0.1\n\n%sworld = dynamics.world {\n",prefix); + c.print ("gravity",w->gravity); + c.print ("ODE = {"); + c.indent++; + c.print ("ERP",w->global_erp); + c.print ("CFM",w->global_cfm); + c.print ("auto_disable = {"); + c.indent++; + c.print ("linear_threshold",w->adis.linear_threshold); + c.print ("angular_threshold",w->adis.angular_threshold); + c.print ("idle_time",w->adis.idle_time); + c.print ("idle_steps",w->adis.idle_steps); + fprintf (file,"\t\t},\n\t},\n}\n"); + c.indent -= 3; + + // bodies + int num = 0; + fprintf (file,"%sbody = {}\n",prefix); + for (dxBody *b=w->firstbody; b; b=(dxBody*)b->next) { + b->tag = num; + fprintf (file,"%sbody[%d] = dynamics.body {\n\tworld = %sworld,\n",prefix,num,prefix); + c.indent++; + c.print ("pos",b->pos); + c.print ("q",b->q,4); + c.print ("lvel",b->lvel); + c.print ("avel",b->avel); + c.print ("mass",b->mass.mass); + fprintf (file,"\tI = {{"); + for (int i=0; i<3; i++) { + for (int j=0; j<3; j++) { + c.printReal (b->mass.I[i*4+j]); + if (j < 2) fputc (',',file); + } + if (i < 2) fprintf (file,"},{"); + } + fprintf (file,"}},\n"); + c.printNonzero ("com",b->mass.c); + c.print ("ODE = {"); + c.indent++; + if (b->flags & dxBodyFlagFiniteRotation) c.print ("finite_rotation",1); + if (b->flags & dxBodyDisabled) c.print ("disabled",1); + if (b->flags & dxBodyNoGravity) c.print ("no_gravity",1); + if (b->flags & dxBodyAutoDisable) { + c.print ("auto_disable = {"); + c.indent++; + c.print ("linear_threshold",b->adis.linear_threshold); + c.print ("angular_threshold",b->adis.angular_threshold); + c.print ("idle_time",b->adis.idle_time); + c.print ("idle_steps",b->adis.idle_steps); + c.print ("time_left",b->adis_timeleft); + c.print ("steps_left",b->adis_stepsleft); + c.indent--; + c.print ("},"); + } + c.printNonzero ("facc",b->facc); + c.printNonzero ("tacc",b->tacc); + if (b->flags & dxBodyFlagFiniteRotationAxis) { + c.print ("finite_rotation_axis",b->finite_rot_axis); + } + c.indent--; + c.print ("},"); + if (b->geom) { + c.print ("geometry = {"); + c.indent++; + for (dxGeom *g=b->geom; g; g=g->body_next) { + c.print ("{"); + c.indent++; + printGeom (c,g); + c.indent--; + c.print ("},"); + } + c.indent--; + c.print ("},"); + } + c.indent--; + c.print ("}"); + num++; + } + + // joints + num = 0; + fprintf (file,"%sjoint = {}\n",prefix); + for (dxJoint *j=w->firstjoint; j; j=(dxJoint*)j->next) { + c.indent++; + const char *name = getJointName (j); + fprintf (file, + "%sjoint[%d] = dynamics.%s_joint {\n" + "\tworld = %sworld,\n" + "\tbody = {%sbody[%d]" + ,prefix,num,name,prefix,prefix,j->node[0].body->tag); + if (j->node[1].body) fprintf (file,",%sbody[%d]",prefix,j->node[1].body->tag); + fprintf (file,"},\n"); + switch (j->vtable->typenum) { + case dJointTypeBall: printBall (c,j); break; + case dJointTypeHinge: printHinge (c,j); break; + case dJointTypeSlider: printSlider (c,j); break; + case dJointTypeContact: printContact (c,j); break; + case dJointTypeUniversal: printUniversal (c,j); break; + case dJointTypeHinge2: printHinge2 (c,j); break; + case dJointTypeFixed: printFixed (c,j); break; + case dJointTypeAMotor: printAMotor (c,j); break; + } + c.indent--; + c.print ("}"); + num++; + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_fastdot.cpp b/src/external/open_dynamics_engine-ef/ode/ode_fastdot.cpp new file mode 100644 index 00000000..8fa792eb --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_fastdot.cpp @@ -0,0 +1,30 @@ +/* generated code, do not edit. */ + +#include "ode/ode_matrix.h" + + +dReal dDot (const dReal *a, const dReal *b, int n) +{ + dReal p0,q0,m0,p1,q1,m1,sum; + sum = 0; + n -= 2; + while (n >= 0) { + p0 = a[0]; q0 = b[0]; + m0 = p0 * q0; + p1 = a[1]; q1 = b[1]; + m1 = p1 * q1; + sum += m0; + sum += m1; + a += 2; + b += 2; + n -= 2; + } + n += 2; + while (n > 0) { + sum += (*a) * (*b); + a++; + b++; + n--; + } + return sum; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_fastldlt.cpp b/src/external/open_dynamics_engine-ef/ode/ode_fastldlt.cpp new file mode 100644 index 00000000..895d125b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_fastldlt.cpp @@ -0,0 +1,383 @@ +/* generated code, do not edit. */ + +#include "ode/ode_matrix.h" + +/* solve L*X=B, with B containing 1 right hand sides. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * B is an n*1 matrix that contains the right hand sides. + * B is stored by columns and its leading dimension is also lskip. + * B is overwritten with X. + * this processes blocks of 2*2. + * if this is in the factorizer source file, n must be a multiple of 2. + */ + +static void dSolveL1_1 (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,m11,Z21,m21,p1,q1,p2,*ex; + const dReal *ell; + int i,j; + /* compute all 2 x 1 blocks of X */ + for (i=0; i < n; i+=2) { + /* compute all 2 x 1 block of X, from rows i..i+2-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z21=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-2; j >= 0; j -= 2) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + p2=ell[lskip1]; + m21 = p2 * q1; + Z11 += m11; + Z21 += m21; + /* compute outer product and add it to the Z matrix */ + p1=ell[1]; + q1=ex[1]; + m11 = p1 * q1; + p2=ell[1+lskip1]; + m21 = p2 * q1; + /* advance pointers */ + ell += 2; + ex += 2; + Z11 += m11; + Z21 += m21; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 2; + for (; j > 0; j--) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + p2=ell[lskip1]; + m21 = p2 * q1; + /* advance pointers */ + ell += 1; + ex += 1; + Z11 += m11; + Z21 += m21; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + p1 = ell[lskip1]; + Z21 = ex[1] - Z21 - p1*Z11; + ex[1] = Z21; + /* end of outer loop */ + } +} + +/* solve L*X=B, with B containing 2 right hand sides. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * B is an n*2 matrix that contains the right hand sides. + * B is stored by columns and its leading dimension is also lskip. + * B is overwritten with X. + * this processes blocks of 2*2. + * if this is in the factorizer source file, n must be a multiple of 2. + */ + +static void dSolveL1_2 (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,m11,Z12,m12,Z21,m21,Z22,m22,p1,q1,p2,q2,*ex; + const dReal *ell; + int i,j; + /* compute all 2 x 2 blocks of X */ + for (i=0; i < n; i+=2) { + /* compute all 2 x 2 block of X, from rows i..i+2-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z12=0; + Z21=0; + Z22=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-2; j >= 0; j -= 2) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + q2=ex[lskip1]; + m12 = p1 * q2; + p2=ell[lskip1]; + m21 = p2 * q1; + m22 = p2 * q2; + Z11 += m11; + Z12 += m12; + Z21 += m21; + Z22 += m22; + /* compute outer product and add it to the Z matrix */ + p1=ell[1]; + q1=ex[1]; + m11 = p1 * q1; + q2=ex[1+lskip1]; + m12 = p1 * q2; + p2=ell[1+lskip1]; + m21 = p2 * q1; + m22 = p2 * q2; + /* advance pointers */ + ell += 2; + ex += 2; + Z11 += m11; + Z12 += m12; + Z21 += m21; + Z22 += m22; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 2; + for (; j > 0; j--) { + /* compute outer product and add it to the Z matrix */ + p1=ell[0]; + q1=ex[0]; + m11 = p1 * q1; + q2=ex[lskip1]; + m12 = p1 * q2; + p2=ell[lskip1]; + m21 = p2 * q1; + m22 = p2 * q2; + /* advance pointers */ + ell += 1; + ex += 1; + Z11 += m11; + Z12 += m12; + Z21 += m21; + Z22 += m22; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + Z12 = ex[lskip1] - Z12; + ex[lskip1] = Z12; + p1 = ell[lskip1]; + Z21 = ex[1] - Z21 - p1*Z11; + ex[1] = Z21; + Z22 = ex[1+lskip1] - Z22 - p1*Z12; + ex[1+lskip1] = Z22; + /* end of outer loop */ + } +} + + +void dFactorLDLT (dReal *A, dReal *d, int n, int nskip1) +{ + int i,j; + dReal sum,*ell,*dee,dd,p1,p2,q1,q2,Z11,m11,Z21,m21,Z22,m22; + if (n < 1) return; + + for (i=0; i<=n-2; i += 2) { + /* solve L*(D*l)=a, l is scaled elements in 2 x i block at A(i,0) */ + dSolveL1_2 (A,A+i*nskip1,i,nskip1); + /* scale the elements in a 2 x i block at A(i,0), and also */ + /* compute Z = the outer product matrix that we'll need. */ + Z11 = 0; + Z21 = 0; + Z22 = 0; + ell = A+i*nskip1; + dee = d; + for (j=i-6; j >= 0; j -= 6) { + p1 = ell[0]; + p2 = ell[nskip1]; + dd = dee[0]; + q1 = p1*dd; + q2 = p2*dd; + ell[0] = q1; + ell[nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[1]; + p2 = ell[1+nskip1]; + dd = dee[1]; + q1 = p1*dd; + q2 = p2*dd; + ell[1] = q1; + ell[1+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[2]; + p2 = ell[2+nskip1]; + dd = dee[2]; + q1 = p1*dd; + q2 = p2*dd; + ell[2] = q1; + ell[2+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[3]; + p2 = ell[3+nskip1]; + dd = dee[3]; + q1 = p1*dd; + q2 = p2*dd; + ell[3] = q1; + ell[3+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[4]; + p2 = ell[4+nskip1]; + dd = dee[4]; + q1 = p1*dd; + q2 = p2*dd; + ell[4] = q1; + ell[4+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + p1 = ell[5]; + p2 = ell[5+nskip1]; + dd = dee[5]; + q1 = p1*dd; + q2 = p2*dd; + ell[5] = q1; + ell[5+nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + ell += 6; + dee += 6; + } + /* compute left-over iterations */ + j += 6; + for (; j > 0; j--) { + p1 = ell[0]; + p2 = ell[nskip1]; + dd = dee[0]; + q1 = p1*dd; + q2 = p2*dd; + ell[0] = q1; + ell[nskip1] = q2; + m11 = p1*q1; + m21 = p2*q1; + m22 = p2*q2; + Z11 += m11; + Z21 += m21; + Z22 += m22; + ell++; + dee++; + } + /* solve for diagonal 2 x 2 block at A(i,i) */ + Z11 = ell[0] - Z11; + Z21 = ell[nskip1] - Z21; + Z22 = ell[1+nskip1] - Z22; + dee = d + i; + /* factorize 2 x 2 block Z,dee */ + /* factorize row 1 */ + dee[0] = dRecip(Z11); + /* factorize row 2 */ + sum = 0; + q1 = Z21; + q2 = q1 * dee[0]; + Z21 = q2; + sum += q1*q2; + dee[1] = dRecip(Z22 - sum); + /* done factorizing 2 x 2 block */ + ell[nskip1] = Z21; + } + /* compute the (less than 2) rows at the bottom */ + switch (n-i) { + case 0: + break; + + case 1: + dSolveL1_1 (A,A+i*nskip1,i,nskip1); + /* scale the elements in a 1 x i block at A(i,0), and also */ + /* compute Z = the outer product matrix that we'll need. */ + Z11 = 0; + ell = A+i*nskip1; + dee = d; + for (j=i-6; j >= 0; j -= 6) { + p1 = ell[0]; + dd = dee[0]; + q1 = p1*dd; + ell[0] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[1]; + dd = dee[1]; + q1 = p1*dd; + ell[1] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[2]; + dd = dee[2]; + q1 = p1*dd; + ell[2] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[3]; + dd = dee[3]; + q1 = p1*dd; + ell[3] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[4]; + dd = dee[4]; + q1 = p1*dd; + ell[4] = q1; + m11 = p1*q1; + Z11 += m11; + p1 = ell[5]; + dd = dee[5]; + q1 = p1*dd; + ell[5] = q1; + m11 = p1*q1; + Z11 += m11; + ell += 6; + dee += 6; + } + /* compute left-over iterations */ + j += 6; + for (; j > 0; j--) { + p1 = ell[0]; + dd = dee[0]; + q1 = p1*dd; + ell[0] = q1; + m11 = p1*q1; + Z11 += m11; + ell++; + dee++; + } + /* solve for diagonal 1 x 1 block at A(i,i) */ + Z11 = ell[0] - Z11; + dee = d + i; + /* factorize 1 x 1 block Z,dee */ + /* factorize row 1 */ + dee[0] = dRecip(Z11); + /* done factorizing 1 x 1 block */ + break; + + default: + abort(); + //*((char*)0)=0; /* this should never happen! */ + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_fastlsolve.cpp b/src/external/open_dynamics_engine-ef/ode/ode_fastlsolve.cpp new file mode 100644 index 00000000..6ab348b5 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_fastlsolve.cpp @@ -0,0 +1,298 @@ +/* generated code, do not edit. */ + +#include "ode/ode_matrix.h" + +/* solve L*X=B, with B containing 1 right hand sides. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * B is an n*1 matrix that contains the right hand sides. + * B is stored by columns and its leading dimension is also lskip. + * B is overwritten with X. + * this processes blocks of 4*4. + * if this is in the factorizer source file, n must be a multiple of 4. + */ + +void dSolveL1 (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,Z21,Z31,Z41,p1,q1,p2,p3,p4,*ex; + const dReal *ell; + int lskip2,lskip3,i,j; + /* compute lskip values */ + lskip2 = 2*lskip1; + lskip3 = 3*lskip1; + /* compute all 4 x 1 blocks of X */ + for (i=0; i <= n-4; i+=4) { + /* compute all 4 x 1 block of X, from rows i..i+4-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z21=0; + Z31=0; + Z41=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-12; j >= 0; j -= 12) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[lskip1]; + p3=ell[lskip2]; + p4=ell[lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[1]; + q1=ex[1]; + p2=ell[1+lskip1]; + p3=ell[1+lskip2]; + p4=ell[1+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[2]; + q1=ex[2]; + p2=ell[2+lskip1]; + p3=ell[2+lskip2]; + p4=ell[2+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[3]; + q1=ex[3]; + p2=ell[3+lskip1]; + p3=ell[3+lskip2]; + p4=ell[3+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[4]; + q1=ex[4]; + p2=ell[4+lskip1]; + p3=ell[4+lskip2]; + p4=ell[4+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[5]; + q1=ex[5]; + p2=ell[5+lskip1]; + p3=ell[5+lskip2]; + p4=ell[5+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[6]; + q1=ex[6]; + p2=ell[6+lskip1]; + p3=ell[6+lskip2]; + p4=ell[6+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[7]; + q1=ex[7]; + p2=ell[7+lskip1]; + p3=ell[7+lskip2]; + p4=ell[7+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[8]; + q1=ex[8]; + p2=ell[8+lskip1]; + p3=ell[8+lskip2]; + p4=ell[8+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[9]; + q1=ex[9]; + p2=ell[9+lskip1]; + p3=ell[9+lskip2]; + p4=ell[9+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[10]; + q1=ex[10]; + p2=ell[10+lskip1]; + p3=ell[10+lskip2]; + p4=ell[10+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* load p and q values */ + p1=ell[11]; + q1=ex[11]; + p2=ell[11+lskip1]; + p3=ell[11+lskip2]; + p4=ell[11+lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* advance pointers */ + ell += 12; + ex += 12; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 12; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[lskip1]; + p3=ell[lskip2]; + p4=ell[lskip3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + Z21 += p2 * q1; + Z31 += p3 * q1; + Z41 += p4 * q1; + /* advance pointers */ + ell += 1; + ex += 1; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + p1 = ell[lskip1]; + Z21 = ex[1] - Z21 - p1*Z11; + ex[1] = Z21; + p1 = ell[lskip2]; + p2 = ell[1+lskip2]; + Z31 = ex[2] - Z31 - p1*Z11 - p2*Z21; + ex[2] = Z31; + p1 = ell[lskip3]; + p2 = ell[1+lskip3]; + p3 = ell[2+lskip3]; + Z41 = ex[3] - Z41 - p1*Z11 - p2*Z21 - p3*Z31; + ex[3] = Z41; + /* end of outer loop */ + } + /* compute rows at end that are not a multiple of block size */ + for (; i < n; i++) { + /* compute all 1 x 1 block of X, from rows i..i+1-1 */ + /* set the Z matrix to 0 */ + Z11=0; + ell = L + i*lskip1; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-12; j >= 0; j -= 12) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[1]; + q1=ex[1]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[2]; + q1=ex[2]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[3]; + q1=ex[3]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[4]; + q1=ex[4]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[5]; + q1=ex[5]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[6]; + q1=ex[6]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[7]; + q1=ex[7]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[8]; + q1=ex[8]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[9]; + q1=ex[9]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[10]; + q1=ex[10]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* load p and q values */ + p1=ell[11]; + q1=ex[11]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* advance pointers */ + ell += 12; + ex += 12; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 12; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + Z11 += p1 * q1; + /* advance pointers */ + ell += 1; + ex += 1; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_fastltsolve.cpp b/src/external/open_dynamics_engine-ef/ode/ode_fastltsolve.cpp new file mode 100644 index 00000000..43d93565 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_fastltsolve.cpp @@ -0,0 +1,199 @@ +/* generated code, do not edit. */ + +#include "ode/ode_matrix.h" + +/* solve L^T * x=b, with b containing 1 right hand side. + * L is an n*n lower triangular matrix with ones on the diagonal. + * L is stored by rows and its leading dimension is lskip. + * b is an n*1 matrix that contains the right hand side. + * b is overwritten with x. + * this processes blocks of 4. + */ + +void dSolveL1T (const dReal *L, dReal *B, int n, int lskip1) +{ + /* declare variables - Z matrix, p and q vectors, etc */ + dReal Z11,m11,Z21,m21,Z31,m31,Z41,m41,p1,q1,p2,p3,p4,*ex; + const dReal *ell; + int lskip2,lskip3,i,j; + /* special handling for L and B because we're solving L1 *transpose* */ + L = L + (n-1)*(lskip1+1); + B = B + n-1; + lskip1 = -lskip1; + /* compute lskip values */ + lskip2 = 2*lskip1; + lskip3 = 3*lskip1; + /* compute all 4 x 1 blocks of X */ + for (i=0; i <= n-4; i+=4) { + /* compute all 4 x 1 block of X, from rows i..i+4-1 */ + /* set the Z matrix to 0 */ + Z11=0; + Z21=0; + Z31=0; + Z41=0; + ell = L - i; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-4; j >= 0; j -= 4) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* load p and q values */ + p1=ell[0]; + q1=ex[-1]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* load p and q values */ + p1=ell[0]; + q1=ex[-2]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* load p and q values */ + p1=ell[0]; + q1=ex[-3]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + ex -= 4; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 4; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + p2=ell[-1]; + p3=ell[-2]; + p4=ell[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + m21 = p2 * q1; + m31 = p3 * q1; + m41 = p4 * q1; + ell += lskip1; + ex -= 1; + Z11 += m11; + Z21 += m21; + Z31 += m31; + Z41 += m41; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + p1 = ell[-1]; + Z21 = ex[-1] - Z21 - p1*Z11; + ex[-1] = Z21; + p1 = ell[-2]; + p2 = ell[-2+lskip1]; + Z31 = ex[-2] - Z31 - p1*Z11 - p2*Z21; + ex[-2] = Z31; + p1 = ell[-3]; + p2 = ell[-3+lskip1]; + p3 = ell[-3+lskip2]; + Z41 = ex[-3] - Z41 - p1*Z11 - p2*Z21 - p3*Z31; + ex[-3] = Z41; + /* end of outer loop */ + } + /* compute rows at end that are not a multiple of block size */ + for (; i < n; i++) { + /* compute all 1 x 1 block of X, from rows i..i+1-1 */ + /* set the Z matrix to 0 */ + Z11=0; + ell = L - i; + ex = B; + /* the inner loop that computes outer products and adds them to Z */ + for (j=i-4; j >= 0; j -= 4) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + Z11 += m11; + /* load p and q values */ + p1=ell[0]; + q1=ex[-1]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + Z11 += m11; + /* load p and q values */ + p1=ell[0]; + q1=ex[-2]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + Z11 += m11; + /* load p and q values */ + p1=ell[0]; + q1=ex[-3]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + ex -= 4; + Z11 += m11; + /* end of inner loop */ + } + /* compute left-over iterations */ + j += 4; + for (; j > 0; j--) { + /* load p and q values */ + p1=ell[0]; + q1=ex[0]; + /* compute outer product and add it to the Z matrix */ + m11 = p1 * q1; + ell += lskip1; + ex -= 1; + Z11 += m11; + } + /* finish computing the X(i) block */ + Z11 = ex[0] - Z11; + ex[0] = Z11; + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_joint.cpp b/src/external/open_dynamics_engine-ef/ode/ode_joint.cpp new file mode 100644 index 00000000..193f5a20 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_joint.cpp @@ -0,0 +1,3247 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +design note: the general principle for giving a joint the option of connecting +to the static environment (i.e. the absolute frame) is to check the second +body (joint->node[1].body), and if it is zero then behave as if its body +transform is the identity. + +*/ + +#include "ode/ode_math.h" +#include "ode/ode_rotation.h" +#include "ode/ode_matrix.h" +#include "ode/ode_joint.h" +#include "ode/ode_util.h" + +// #include + +//**************************************************************************** +// externs + +extern "C" void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); +extern "C" void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); + +//**************************************************************************** +// utility + +// set three "ball-and-socket" rows in the constraint equation, and the +// corresponding right hand side. + +static inline void setBall (dxJoint *joint, dxJoint::Info2 *info, + dVector3 anchor1, dVector3 anchor2) +{ + // anchor points in global coordinates with respect to body PORs. + dVector3 a1,a2; + + int s = info->rowskip; + +#if VALUE_TESTING + if (testLogging) + fprintf(f,"rowskip %d\n",s); +#endif + + // set jacobian + info->J1l[0] = 1; + info->J1l[s+1] = 1; + info->J1l[2*s+2] = 1; + dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1); + dCROSSMAT (info->J1a,a1,s,-,+); + + if (joint->node[1].body) { + info->J2l[0] = -1; + info->J2l[s+1] = -1; + info->J2l[2*s+2] = -1; + dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2); + dCROSSMAT (info->J2a,a2,s,+,-); + + +#if VALUE_TESTING + if (testLogging){ + fprintf(f," %f ",info->J1a[1]); PRINT_DBL_HEX(info->J1a[1]); + fprintf(f," %f ",info->J1a[2]); PRINT_DBL_HEX(info->J1a[2]); + fprintf(f," %f ",info->J1a[s+0]); PRINT_DBL_HEX(info->J1a[s+0]); + fprintf(f," %f ",info->J1a[s+2]); PRINT_DBL_HEX(info->J1a[s+2]); + fprintf(f," %f ",info->J1a[2*s+0]); PRINT_DBL_HEX(info->J1a[2*s+0]); + fprintf(f," %f ",info->J1a[2*s+1]); PRINT_DBL_HEX(info->J1a[2*s+1]); + } +#endif + + +#if VALUE_TESTING + if (testLogging){ + fprintf(f," %f ",info->J2a[1]); PRINT_DBL_HEX(info->J2a[1]); + fprintf(f," %f ",info->J2a[2]); PRINT_DBL_HEX(info->J2a[2]); + fprintf(f," %f ",info->J2a[s+0]); PRINT_DBL_HEX(info->J2a[s+0]); + fprintf(f," %f ",info->J2a[s+2]); PRINT_DBL_HEX(info->J2a[s+2]); + fprintf(f," %f ",info->J2a[2*s+0]); PRINT_DBL_HEX(info->J2a[2*s+0]); + fprintf(f," %f ",info->J2a[2*s+1]); PRINT_DBL_HEX(info->J2a[2*s+1]); + } +#endif + + + } + + // set right hand side + dReal k = info->fps * info->erp; + if (joint->node[1].body) { + for (int j=0; j<3; j++) { + info->c[j] = k * (a2[j] + joint->node[1].body->pos[j] - + a1[j] - joint->node[0].body->pos[j]); + } + } + else { + for (int j=0; j<3; j++) { + info->c[j] = k * (anchor2[j] - a1[j] - + joint->node[0].body->pos[j]); + } + } +} + + +// this is like setBall(), except that `axis' is a unit length vector +// (in global coordinates) that should be used for the first jacobian +// position row (the other two row vectors will be derived from this). +// `erp1' is the erp value to use along the axis. + +static inline void setBall2 (dxJoint *joint, dxJoint::Info2 *info, + dVector3 anchor1, dVector3 anchor2, + dVector3 axis, dReal erp1) +{ + // anchor points in global coordinates with respect to body PORs. + dVector3 a1,a2; + + int i,s = info->rowskip; + + // get vectors normal to the axis. in setBall() axis,q1,q2 is [1 0 0], + // [0 1 0] and [0 0 1], which makes everything much easier. + dVector3 q1,q2; + dPlaneSpace (axis,q1,q2); + + // set jacobian + for (i=0; i<3; i++) info->J1l[i] = axis[i]; + for (i=0; i<3; i++) info->J1l[s+i] = q1[i]; + for (i=0; i<3; i++) info->J1l[2*s+i] = q2[i]; + dMULTIPLY0_331 (a1,joint->node[0].body->R,anchor1); + dCROSS (info->J1a,=,a1,axis); + dCROSS (info->J1a+s,=,a1,q1); + dCROSS (info->J1a+2*s,=,a1,q2); + if (joint->node[1].body) { + for (i=0; i<3; i++) info->J2l[i] = -axis[i]; + for (i=0; i<3; i++) info->J2l[s+i] = -q1[i]; + for (i=0; i<3; i++) info->J2l[2*s+i] = -q2[i]; + dMULTIPLY0_331 (a2,joint->node[1].body->R,anchor2); + dCROSS (info->J2a,= -,a2,axis); + dCROSS (info->J2a+s,= -,a2,q1); + dCROSS (info->J2a+2*s,= -,a2,q2); + } + + // set right hand side - measure error along (axis,q1,q2) + dReal k1 = info->fps * erp1; + dReal k = info->fps * info->erp; + + for (i=0; i<3; i++) a1[i] += joint->node[0].body->pos[i]; + if (joint->node[1].body) { + for (i=0; i<3; i++) a2[i] += joint->node[1].body->pos[i]; + info->c[0] = k1 * (dDOT(axis,a2) - dDOT(axis,a1)); + info->c[1] = k * (dDOT(q1,a2) - dDOT(q1,a1)); + info->c[2] = k * (dDOT(q2,a2) - dDOT(q2,a1)); + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[0] %f ",info->c[0]); PRINT_DBL_HEX(info->c[0]); + fprintf(f,"c[1] %f ",info->c[1]); PRINT_DBL_HEX(info->c[1]); + fprintf(f,"c[2] %f ",info->c[2]); PRINT_DBL_HEX(info->c[2]); + } +#endif + + } + else { + info->c[0] = k1 * (dDOT(axis,anchor2) - dDOT(axis,a1)); + info->c[1] = k * (dDOT(q1,anchor2) - dDOT(q1,a1)); + info->c[2] = k * (dDOT(q2,anchor2) - dDOT(q2,a1)); + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[0] %f ",info->c[0]); PRINT_DBL_HEX(info->c[0]); + fprintf(f,"c[1] %f ",info->c[1]); PRINT_DBL_HEX(info->c[1]); + fprintf(f,"c[2] %f ",info->c[2]); PRINT_DBL_HEX(info->c[2]); + } +#endif + + } +} + + +// set three orientation rows in the constraint equation, and the +// corresponding right hand side. + +static void setFixedOrientation(dxJoint *joint, dxJoint::Info2 *info, dQuaternion qrel, int start_row) +{ + int s = info->rowskip; + int start_index = start_row * s; + + // 3 rows to make body rotations equal + info->J1a[start_index] = 1; + info->J1a[start_index + s + 1] = 1; + info->J1a[start_index + s*2+2] = 1; + if (joint->node[1].body) { + info->J2a[start_index] = -1; + info->J2a[start_index + s+1] = -1; + info->J2a[start_index + s*2+2] = -1; + } + + // compute the right hand side. the first three elements will result in + // relative angular velocity of the two bodies - this is set to bring them + // back into alignment. the correcting angular velocity is + // |angular_velocity| = angle/time = erp*theta / stepsize + // = (erp*fps) * theta + // angular_velocity = |angular_velocity| * u + // = (erp*fps) * theta * u + // where rotation along unit length axis u by theta brings body 2's frame + // to qrel with respect to body 1's frame. using a small angle approximation + // for sin(), this gives + // angular_velocity = (erp*fps) * 2 * v + // where the quaternion of the relative rotation between the two bodies is + // q = [cos(theta/2) sin(theta/2)*u] = [s v] + + // get qerr = relative rotation (rotation error) between two bodies + dQuaternion qerr,e; + if (joint->node[1].body) { + dQuaternion qq; + dQMultiply1 (qq,joint->node[0].body->q,joint->node[1].body->q); + dQMultiply2 (qerr,qq,qrel); + } + else { + dQMultiply3 (qerr,joint->node[0].body->q,qrel); + } + if (qerr[0] < 0) { + qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small + qerr[2] = -qerr[2]; + qerr[3] = -qerr[3]; + } + dMULTIPLY0_331 (e,joint->node[0].body->R,qerr+1); // @@@ bad SIMD padding! + dReal k = info->fps * info->erp; + info->c[start_row] = 2*k * e[0]; + info->c[start_row+1] = 2*k * e[1]; + info->c[start_row+2] = 2*k * e[2]; + +} + + + +// compute anchor points relative to bodies + +static void setAnchors (dxJoint *j, dReal x, dReal y, dReal z, + dVector3 anchor1, dVector3 anchor2) +{ + if (j->node[0].body) { + dReal q[4]; + q[0] = x - j->node[0].body->pos[0]; + q[1] = y - j->node[0].body->pos[1]; + q[2] = z - j->node[0].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331 (anchor1,j->node[0].body->R,q); + if (j->node[1].body) { + q[0] = x - j->node[1].body->pos[0]; + q[1] = y - j->node[1].body->pos[1]; + q[2] = z - j->node[1].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331 (anchor2,j->node[1].body->R,q); + } + else { + anchor2[0] = x; + anchor2[1] = y; + anchor2[2] = z; + } + } + anchor1[3] = 0; + anchor2[3] = 0; +} + +// added by Eric Froemling - sets anchor 2 in absolute position +// for manually moving the target point for a single-body fixed constraint +static void setAnchorsAbs (dxJoint *j, dReal x, dReal y, dReal z, + dVector3 anchor1, dVector3 anchor2) +{ + if (j->node[0].body) { +// dReal q[4]; +// q[0] = x - j->node[0].body->pos[0]; +// q[1] = y - j->node[0].body->pos[1]; +// q[2] = z - j->node[0].body->pos[2]; +// q[3] = 0; +// dMULTIPLY1_331 (anchor1,j->node[0].body->R,q); +// if (j->node[1].body) { +// q[0] = x - j->node[1].body->pos[0]; +// q[1] = y - j->node[1].body->pos[1]; +// q[2] = z - j->node[1].body->pos[2]; +// q[3] = 0; +// dMULTIPLY1_331 (anchor2,j->node[1].body->R,q); +// } +// else { +// dReal q[4]; +// q[0] = x; +// q[1] = y; +// q[2] = z; +// q[3] = 0; +// dMULTIPLY1_331 (anchor1,j->node[0].body->R,q); + anchor2[0] = x; + anchor2[1] = y; + anchor2[2] = z; +// } + } +// anchor1[3] = 0; +// anchor2[3] = 0; +} + + +// compute axes relative to bodies. either axis1 or axis2 can be 0. + +static void setAxes (dxJoint *j, dReal x, dReal y, dReal z, + dVector3 axis1, dVector3 axis2) +{ + if (j->node[0].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + if (axis1) { + dMULTIPLY1_331 (axis1,j->node[0].body->R,q); + axis1[3] = 0; + } + if (axis2) { + if (j->node[1].body) { + dMULTIPLY1_331 (axis2,j->node[1].body->R,q); + } + else { + axis2[0] = x; + axis2[1] = y; + axis2[2] = z; + } + axis2[3] = 0; + } + } +} + + +static void getAnchor (dxJoint *j, dVector3 result, dVector3 anchor1) +{ + if (j->node[0].body) { + dMULTIPLY0_331 (result,j->node[0].body->R,anchor1); + result[0] += j->node[0].body->pos[0]; + result[1] += j->node[0].body->pos[1]; + result[2] += j->node[0].body->pos[2]; + } +} + + +static void getAnchor2 (dxJoint *j, dVector3 result, dVector3 anchor2) +{ + if (j->node[1].body) { + dMULTIPLY0_331 (result,j->node[1].body->R,anchor2); + result[0] += j->node[1].body->pos[0]; + result[1] += j->node[1].body->pos[1]; + result[2] += j->node[1].body->pos[2]; + } + else { + result[0] = anchor2[0]; + result[1] = anchor2[1]; + result[2] = anchor2[2]; + } +} + + +static void getAxis (dxJoint *j, dVector3 result, dVector3 axis1) +{ + if (j->node[0].body) { + dMULTIPLY0_331 (result,j->node[0].body->R,axis1); + } +} + + +static void getAxis2 (dxJoint *j, dVector3 result, dVector3 axis2) +{ + if (j->node[1].body) { + dMULTIPLY0_331 (result,j->node[1].body->R,axis2); + } + else { + result[0] = axis2[0]; + result[1] = axis2[1]; + result[2] = axis2[2]; + } +} + + +static dReal getHingeAngleFromRelativeQuat (dQuaternion qrel, dVector3 axis) +{ + // the angle between the two bodies is extracted from the quaternion that + // represents the relative rotation between them. recall that a quaternion + // q is: + // [s,v] = [ cos(theta/2) , sin(theta/2) * u ] + // where s is a scalar and v is a 3-vector. u is a unit length axis and + // theta is a rotation along that axis. we can get theta/2 by: + // theta/2 = atan2 ( sin(theta/2) , cos(theta/2) ) + // but we can't get sin(theta/2) directly, only its absolute value, i.e.: + // |v| = |sin(theta/2)| * |u| + // = |sin(theta/2)| + // using this value will have a strange effect. recall that there are two + // quaternion representations of a given rotation, q and -q. typically as + // a body rotates along the axis it will go through a complete cycle using + // one representation and then the next cycle will use the other + // representation. this corresponds to u pointing in the direction of the + // hinge axis and then in the opposite direction. the result is that theta + // will appear to go "backwards" every other cycle. here is a fix: if u + // points "away" from the direction of the hinge (motor) axis (i.e. more + // than 90 degrees) then use -q instead of q. this represents the same + // rotation, but results in the cos(theta/2) value being sign inverted. + + // extract the angle from the quaternion. cost2 = cos(theta/2), + // sint2 = |sin(theta/2)| + dReal cost2 = qrel[0]; + dReal sint2 = dSqrt (qrel[1]*qrel[1]+qrel[2]*qrel[2]+qrel[3]*qrel[3]); + dReal theta = (dDOT(qrel+1,axis) >= 0) ? // @@@ padding assumptions + (2 * dAtan2(sint2,cost2)) : // if u points in direction of axis + (2 * dAtan2(sint2,-cost2)); // if u points in opposite direction + + // the angle we get will be between 0..2*pi, but we want to return angles + // between -pi..pi + if (theta > M_PI) theta -= 2*M_PI; + + // the angle we've just extracted has the wrong sign + theta = -theta; + + return theta; +} + + +// given two bodies (body1,body2), the hinge axis that they are connected by +// w.r.t. body1 (axis), and the initial relative orientation between them +// (q_initial), return the relative rotation angle. the initial relative +// orientation corresponds to an angle of zero. if body2 is 0 then measure the +// angle between body1 and the static frame. +// +// this will not return the correct angle if the bodies rotate along any axis +// other than the given hinge axis. + +static dReal getHingeAngle (dxBody *body1, dxBody *body2, dVector3 axis, + dQuaternion q_initial) +{ + // get qrel = relative rotation between the two bodies + dQuaternion qrel; + if (body2) { + dQuaternion qq; + dQMultiply1 (qq,body1->q,body2->q); + dQMultiply2 (qrel,qq,q_initial); + } + else { + // pretend body2->q is the identity + dQMultiply3 (qrel,body1->q,q_initial); + } + + return getHingeAngleFromRelativeQuat (qrel,axis); +} + +//**************************************************************************** +// dxJointLimitMotor + +void dxJointLimitMotor::init (dxWorld *world) +{ + vel = 0; + fmax = 0; + lostop = -dInfinity; + histop = dInfinity; + fudge_factor = 1; + normal_cfm = world->global_cfm; + stop_erp = world->global_erp; + stop_cfm = world->global_cfm; + bounce = 0; + limit = 0; + limit_err = 0; +} + + +void dxJointLimitMotor::set (int num, dReal value) +{ + switch (num) { + case dParamLoStop: + if (value <= histop) lostop = value; + break; + case dParamHiStop: + if (value >= lostop) histop = value; + break; + case dParamVel: + //if (testLogging){ + //printf("dParamVel value %f ",value); PRINT_DBL_HEX_STDOUT(value); + //} + vel = value; + //if (testLogging){ + //printf("dParamVel valueb %f ",vel); PRINT_DBL_HEX_STDOUT(vel); + //} + break; + case dParamFMax: + if (value >= 0) fmax = value; + break; + case dParamFudgeFactor: + if (value >= 0 && value <= 1) fudge_factor = value; + break; + case dParamBounce: + bounce = value; + break; + case dParamCFM: + normal_cfm = value; + break; + case dParamStopERP: + stop_erp = value; + break; + case dParamStopCFM: + stop_cfm = value; + break; + } +} + + +dReal dxJointLimitMotor::get (int num) +{ + switch (num) { + case dParamLoStop: return lostop; + case dParamHiStop: return histop; + case dParamVel: return vel; + case dParamFMax: return fmax; + case dParamFudgeFactor: return fudge_factor; + case dParamBounce: return bounce; + case dParamCFM: return normal_cfm; + case dParamStopERP: return stop_erp; + case dParamStopCFM: return stop_cfm; + default: return 0; + } +} + + +int dxJointLimitMotor::testRotationalLimit (dReal angle) +{ + if (angle <= lostop) { + limit = 1; + limit_err = angle - lostop; + return 1; + } + else if (angle >= histop) { + limit = 2; + limit_err = angle - histop; + return 1; + } + else { + limit = 0; + return 0; + } +} + + +int dxJointLimitMotor::addLimot (dxJoint *joint, + dxJoint::Info2 *info, int row, + dVector3 ax1, int rotational) +{ + int srow = row * info->rowskip; + + // if the joint is powered, or has joint limits, add in the extra row + int powered = fmax > 0; + if (powered || limit) { + dReal *J1 = rotational ? info->J1a : info->J1l; + dReal *J2 = rotational ? info->J2a : info->J2l; + + J1[srow+0] = ax1[0]; + J1[srow+1] = ax1[1]; + J1[srow+2] = ax1[2]; + if (joint->node[1].body) { + J2[srow+0] = -ax1[0]; + J2[srow+1] = -ax1[1]; + J2[srow+2] = -ax1[2]; + } +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"J1[srow+0] %f ",J1[srow+0]); PRINT_DBL_HEX(J1[srow+0]); + fprintf(f,"J1[srow+1] %f ",J1[srow+1]); PRINT_DBL_HEX(J1[srow+1]); + fprintf(f,"J1[srow+2] %f ",J1[srow+2]); PRINT_DBL_HEX(J1[srow+2]); + + fprintf(f,"J2[srow+0] %f ",J2[srow+0]); PRINT_DBL_HEX(J2[srow+0]); + fprintf(f,"J2[srow+1] %f ",J2[srow+1]); PRINT_DBL_HEX(J2[srow+1]); + fprintf(f,"J2[srow+2] %f ",J2[srow+2]); PRINT_DBL_HEX(J2[srow+2]); + } +#endif + // linear limot torque decoupling step: + // + // if this is a linear limot (e.g. from a slider), we have to be careful + // that the linear constraint forces (+/- ax1) applied to the two bodies + // do not create a torque couple. in other words, the points that the + // constraint force is applied at must lie along the same ax1 axis. + // a torque couple will result in powered or limited slider-jointed free + // bodies from gaining angular momentum. + // the solution used here is to apply the constraint forces at the point + // halfway between the body centers. there is no penalty (other than an + // extra tiny bit of computation) in doing this adjustment. note that we + // only need to do this if the constraint connects two bodies. + + dVector3 ltd; // Linear Torque Decoupling vector (a torque) + if (!rotational && joint->node[1].body) { + dVector3 c; + c[0]=REAL(0.5)*(joint->node[1].body->pos[0]-joint->node[0].body->pos[0]); + c[1]=REAL(0.5)*(joint->node[1].body->pos[1]-joint->node[0].body->pos[1]); + c[2]=REAL(0.5)*(joint->node[1].body->pos[2]-joint->node[0].body->pos[2]); + dCROSS (ltd,=,c,ax1); + info->J1a[srow+0] = ltd[0]; + info->J1a[srow+1] = ltd[1]; + info->J1a[srow+2] = ltd[2]; + info->J2a[srow+0] = ltd[0]; + info->J2a[srow+1] = ltd[1]; + info->J2a[srow+2] = ltd[2]; + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"info->J1a[srow+0] %f ",info->J1a[srow+0]); PRINT_DBL_HEX(info->J1a[srow+0]); + fprintf(f,"info->J1a[srow+1] %f ",info->J1a[srow+1]); PRINT_DBL_HEX(info->J1a[srow+1]); + fprintf(f,"info->J1a[srow+2] %f ",info->J1a[srow+2]); PRINT_DBL_HEX(info->J1a[srow+2]); + + fprintf(f,"info->J2a[srow+0] %f ",info->J2a[srow+0]); PRINT_DBL_HEX(info->J2a[srow+0]); + fprintf(f,"info->J2a[srow+1] %f ",info->J2a[srow+1]); PRINT_DBL_HEX(info->J2a[srow+1]); + fprintf(f,"info->J2a[srow+2] %f ",info->J2a[srow+2]); PRINT_DBL_HEX(info->J2a[srow+2]); + } +#endif + + + } + + // if we're limited low and high simultaneously, the joint motor is + // ineffective + if (limit && (lostop == histop)) powered = 0; + + if (powered) { + info->cfm[row] = normal_cfm; + + if (! limit) { + info->c[row] = vel; +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"vel %f ",vel); PRINT_DBL_HEX(vel); + //fprintf(f,"c[row] 1 %f ",info->c[row]); PRINT_DBL_HEX(info->c[row]); + } +#endif + + info->lo[row] = -fmax; + info->hi[row] = fmax; + } + else { + // the joint is at a limit, AND is being powered. if the joint is + // being powered into the limit then we apply the maximum motor force + // in that direction, because the motor is working against the + // immovable limit. if the joint is being powered away from the limit + // then we have problems because actually we need *two* lcp + // constraints to handle this case. so we fake it and apply some + // fraction of the maximum force. the fraction to use can be set as + // a fudge factor. + + dReal fm = fmax; + if (vel > 0) fm = -fm; + + // if we're powering away from the limit, apply the fudge factor + if ((limit==1 && vel > 0) || (limit==2 && vel < 0)) fm *= fudge_factor; + + if (rotational) { + dBodyAddTorque (joint->node[0].body,-fm*ax1[0],-fm*ax1[1], + -fm*ax1[2]); + if (joint->node[1].body) + dBodyAddTorque (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); + } + else { + dBodyAddForce (joint->node[0].body,-fm*ax1[0],-fm*ax1[1],-fm*ax1[2]); + if (joint->node[1].body) { + dBodyAddForce (joint->node[1].body,fm*ax1[0],fm*ax1[1],fm*ax1[2]); + + // linear limot torque decoupling step: refer to above discussion + dBodyAddTorque (joint->node[0].body,-fm*ltd[0],-fm*ltd[1], + -fm*ltd[2]); + dBodyAddTorque (joint->node[1].body,-fm*ltd[0],-fm*ltd[1], + -fm*ltd[2]); + } + } + } + } + + if (limit) { + dReal k = info->fps * stop_erp; + info->c[row] = -k * limit_err; +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[row] 2 %f ",info->c[row]); PRINT_DBL_HEX(info->c[row]); + } +#endif + info->cfm[row] = stop_cfm; + + if (lostop == histop) { + // limited low and high simultaneously + info->lo[row] = -dInfinity; + info->hi[row] = dInfinity; + } + else { + if (limit == 1) { + // low limit + info->lo[row] = 0; + info->hi[row] = dInfinity; + } + else { + // high limit + info->lo[row] = -dInfinity; + info->hi[row] = 0; + } + + // deal with bounce + if (bounce > 0) { + // calculate joint velocity + dReal vel; + if (rotational) { + vel = dDOT(joint->node[0].body->avel,ax1); + if (joint->node[1].body) + vel -= dDOT(joint->node[1].body->avel,ax1); + } + else { + vel = dDOT(joint->node[0].body->lvel,ax1); + if (joint->node[1].body) + vel -= dDOT(joint->node[1].body->lvel,ax1); + } + + // only apply bounce if the velocity is incoming, and if the + // resulting c[] exceeds what we already have. + if (limit == 1) { + // low limit + if (vel < 0) { + dReal newc = -bounce * vel; + if (newc > info->c[row]){ + info->c[row] = newc; +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[row] 3 %f ",info->c[row]); PRINT_DBL_HEX(info->c[row]); + } +#endif + } + } + } + else { + // high limit - all those computations are reversed + if (vel > 0) { + dReal newc = -bounce * vel; + if (newc < info->c[row]){ + info->c[row] = newc; +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[row] 4 %f ",info->c[row]); PRINT_DBL_HEX(info->c[row]); + } +#endif + } + } + } + } + } + } + return 1; + } + else return 0; +} + +//**************************************************************************** +// ball and socket + +static void ballInit (dxJointBall *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + j->damping = 0; + j->stiffness = 0; + j->springMode = false; +} + + +static void ballGetInfo1 (dxJointBall *j, dxJoint::Info1 *info) +{ + info->m = 3; + info->nub = 3; +} + +static void ballGetInfo2 (dxJointBall *joint, dxJoint::Info2 *info) +{ + dReal origERP = info->erp; + + + dReal linearERP = 0; + dReal linearCFM = 0; + + if (joint->springMode){ + dReal linearStiffness = joint->stiffness; + dReal linearDamping = joint->damping; + + dReal stepSize = 1.0/info->fps; + if ((linearStiffness < 0.00001) && (linearDamping < 0.00001)){ + linearDamping = 0.00001; + } + linearERP = (linearStiffness * stepSize)/((linearStiffness * stepSize) + linearDamping); + linearCFM = 1.0/(stepSize*linearStiffness + linearDamping); + info->erp = linearERP; + } + + setBall (joint,info,joint->anchor1,joint->anchor2); + + if (joint->springMode){ + info->cfm[0] = linearCFM; + info->cfm[1] = linearCFM; + info->cfm[2] = linearCFM; + } + info->erp = origERP; +} + +extern "C" void dJointSetBallSpringMode (dxJointBall *joint, + int enable) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + joint->springMode = enable; +} +extern "C" void dJointSetBallParam (dxJointBall *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + switch (parameter) { + case dParamStiffness: + joint->stiffness = value; + break; + case dParamDamping: + joint->damping = value; + break; + } + +} + +extern "C" void dJointSetBallAnchor (dxJointBall *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); +} + + +extern "C" void dJointGetBallAnchor (dxJointBall *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + if (joint->flags & dJOINT_REVERSE) + getAnchor2 (joint,result,joint->anchor2); + else + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetBallAnchor2 (dxJointBall *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dball_vtable,"joint is not a ball"); + if (joint->flags & dJOINT_REVERSE) + getAnchor (joint,result,joint->anchor1); + else + getAnchor2 (joint,result,joint->anchor2); +} + + +dxJoint::Vtable __dball_vtable = { + sizeof(dxJointBall), + (dxJoint::init_fn*) ballInit, + (dxJoint::getInfo1_fn*) ballGetInfo1, + (dxJoint::getInfo2_fn*) ballGetInfo2, + dJointTypeBall}; + +//**************************************************************************** +// hinge + +static void hingeInit (dxJointHinge *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->axis2,4); + j->axis2[0] = 1; + dSetZero (j->qrel,4); + j->limot.init (j->world); +} + + +static void hingeGetInfo1 (dxJointHinge *j, dxJoint::Info1 *info) +{ + info->nub = 5; + + // see if joint is powered + if (j->limot.fmax > 0) + info->m = 6; // powered hinge needs an extra constraint row + else info->m = 5; + + // see if we're at a joint limit. + if ((j->limot.lostop >= -M_PI || j->limot.histop <= M_PI) && + j->limot.lostop <= j->limot.histop) { + dReal angle = getHingeAngle (j->node[0].body,j->node[1].body,j->axis1, + j->qrel); + if (j->limot.testRotationalLimit (angle)) info->m = 6; + } +} + + +static void hingeGetInfo2 (dxJointHinge *joint, dxJoint::Info2 *info) +{ + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"(hinge joint)\n"); + } +#endif + + + // set the three ball-and-socket rows + setBall (joint,info,joint->anchor1,joint->anchor2); + + // set the two hinge rows. the hinge axis should be the only unconstrained + // rotational axis, the angular velocity of the two bodies perpendicular to + // the hinge axis should be equal. thus the constraint equations are + // p*w1 - p*w2 = 0 + // q*w1 - q*w2 = 0 + // where p and q are unit vectors normal to the hinge axis, and w1 and w2 + // are the angular velocity vectors of the two bodies. + + dVector3 ax1; // length 1 joint axis in global coordinates, from 1st body + dVector3 p,q; // plane space vectors for ax1 + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + dPlaneSpace (ax1,p,q); + + int s3=3*info->rowskip; + int s4=4*info->rowskip; + + info->J1a[s3+0] = p[0]; + info->J1a[s3+1] = p[1]; + info->J1a[s3+2] = p[2]; + info->J1a[s4+0] = q[0]; + info->J1a[s4+1] = q[1]; + info->J1a[s4+2] = q[2]; + + if (joint->node[1].body) { + info->J2a[s3+0] = -p[0]; + info->J2a[s3+1] = -p[1]; + info->J2a[s3+2] = -p[2]; + info->J2a[s4+0] = -q[0]; + info->J2a[s4+1] = -q[1]; + info->J2a[s4+2] = -q[2]; + } + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"info->J1a[s3+0] %f ",info->J1a[s3+0]); PRINT_DBL_HEX(info->J1a[s3+0]); + fprintf(f,"info->J1a[s3+1] %f ",info->J1a[s3+1]); PRINT_DBL_HEX(info->J1a[s3+1]); + fprintf(f,"info->J1a[s3+2] %f ",info->J1a[s3+2]); PRINT_DBL_HEX(info->J1a[s3+2]); + fprintf(f,"info->J1a[s4+0] %f ",info->J1a[s4+0]); PRINT_DBL_HEX(info->J1a[s4+0]); + fprintf(f,"info->J1a[s4+1] %f ",info->J1a[s4+1]); PRINT_DBL_HEX(info->J1a[s4+1]); + fprintf(f,"info->J1a[s4+2] %f ",info->J1a[s4+2]); PRINT_DBL_HEX(info->J1a[s4+2]); + + fprintf(f,"info->J2a[s3+0] %f ",info->J2a[s3+0]); PRINT_DBL_HEX(info->J2a[s3+0]); + fprintf(f,"info->J2a[s3+1] %f ",info->J2a[s3+1]); PRINT_DBL_HEX(info->J2a[s3+1]); + fprintf(f,"info->J2a[s3+2] %f ",info->J2a[s3+2]); PRINT_DBL_HEX(info->J2a[s3+2]); + fprintf(f,"info->J2a[s4+0] %f ",info->J2a[s4+0]); PRINT_DBL_HEX(info->J2a[s4+0]); + fprintf(f,"info->J2a[s4+1] %f ",info->J2a[s4+1]); PRINT_DBL_HEX(info->J2a[s4+1]); + fprintf(f,"info->J2a[s4+2] %f ",info->J2a[s4+2]); PRINT_DBL_HEX(info->J2a[s4+2]); + //fprintf(f,"J2a[] %f ",i,J[i]); PRINT_DBL_HEX(J[i]);m + } +#endif + + + // compute the right hand side of the constraint equation. set relative + // body velocities along p and q to bring the hinge back into alignment. + // if ax1,ax2 are the unit length hinge axes as computed from body1 and + // body2, we need to rotate both bodies along the axis u = (ax1 x ax2). + // if `theta' is the angle between ax1 and ax2, we need an angular velocity + // along u to cover angle erp*theta in one step : + // |angular_velocity| = angle/time = erp*theta / stepsize + // = (erp*fps) * theta + // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| + // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) + // ...as ax1 and ax2 are unit length. if theta is smallish, + // theta ~= sin(theta), so + // angular_velocity = (erp*fps) * (ax1 x ax2) + // ax1 x ax2 is in the plane space of ax1, so we project the angular + // velocity to p and q to find the right hand side. + + dVector3 ax2,b; + if (joint->node[1].body) { + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); + } + else { + ax2[0] = joint->axis2[0]; + ax2[1] = joint->axis2[1]; + ax2[2] = joint->axis2[2]; + } + dCROSS (b,=,ax1,ax2); + dReal k = info->fps * info->erp; + info->c[3] = k * dDOT(b,p); + info->c[4] = k * dDOT(b,q); +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[3] %f ",info->c[3]); PRINT_DBL_HEX(info->c[3]); + fprintf(f,"c[4] %f ",info->c[4]); PRINT_DBL_HEX(info->c[4]); + } +#endif + + // if the hinge is powered, or has joint limits, add in the stuff + joint->limot.addLimot (joint,info,5,ax1,1); +} + + +// compute initial relative rotation body1 -> body2, or env -> body1 + +static void hingeComputeInitialRelativeRotation (dxJointHinge *joint) +{ + if (joint->node[0].body) { + if (joint->node[1].body) { + dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); + } + else { + // set joint->qrel to the transpose of the first body q + joint->qrel[0] = joint->node[0].body->q[0]; + for (int i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; + } + } +} + + +extern "C" void dJointSetHingeAnchor (dxJointHinge *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); + hingeComputeInitialRelativeRotation (joint); +} + + +extern "C" void dJointSetHingeAnchorDelta (dxJointHinge *joint, + dReal x, dReal y, dReal z, + dReal dx, dReal dy, dReal dz) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + + if (joint->node[0].body) { + dReal q[4]; + q[0] = x - joint->node[0].body->pos[0]; + q[1] = y - joint->node[0].body->pos[1]; + q[2] = z - joint->node[0].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331 (joint->anchor1,joint->node[0].body->R,q); + + if (joint->node[1].body) { + q[0] = x - joint->node[1].body->pos[0]; + q[1] = y - joint->node[1].body->pos[1]; + q[2] = z - joint->node[1].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331 (joint->anchor2,joint->node[1].body->R,q); + } + else { + // Move the relative displacement between the passive body and the + // anchor in the same direction as the passive body has just moved + joint->anchor2[0] = x + dx; + joint->anchor2[1] = y + dy; + joint->anchor2[2] = z + dz; + } + } + joint->anchor1[3] = 0; + joint->anchor2[3] = 0; + + hingeComputeInitialRelativeRotation (joint); +} + + +extern "C" void dJointSetHingeAxis (dxJointHinge *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + setAxes (joint,x,y,z,joint->axis1,joint->axis2); + hingeComputeInitialRelativeRotation (joint); +} + + +extern "C" void dJointGetHingeAnchor (dxJointHinge *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + if (joint->flags & dJOINT_REVERSE) + getAnchor2 (joint,result,joint->anchor2); + else + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetHingeAnchor2 (dxJointHinge *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + if (joint->flags & dJOINT_REVERSE) + getAnchor (joint,result,joint->anchor1); + else + getAnchor2 (joint,result,joint->anchor2); +} + + +extern "C" void dJointGetHingeAxis (dxJointHinge *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + getAxis (joint,result,joint->axis1); +} + + +extern "C" void dJointSetHingeParam (dxJointHinge *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + joint->limot.set (parameter,value); +} + + +extern "C" dReal dJointGetHingeParam (dxJointHinge *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + return joint->limot.get (parameter); +} + + +extern "C" dReal dJointGetHingeAngle (dxJointHinge *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a hinge"); + if (joint->node[0].body) { + dReal ang = getHingeAngle (joint->node[0].body,joint->node[1].body,joint->axis1, + joint->qrel); + if (joint->flags & dJOINT_REVERSE) + return -ang; + else + return ang; + } + else return 0; +} + + +extern "C" dReal dJointGetHingeAngleRate (dxJointHinge *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); + if (joint->node[0].body) { + dVector3 axis; + dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1); + dReal rate = dDOT(axis,joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); + if (joint->flags & dJOINT_REVERSE) rate = - rate; + return rate; + } + else return 0; +} + + +extern "C" void dJointAddHingeTorque (dxJointHinge *joint, dReal torque) +{ + dVector3 axis; + dAASSERT(joint); + dUASSERT(joint->vtable == &__dhinge_vtable,"joint is not a Hinge"); + + if (joint->flags & dJOINT_REVERSE) + torque = -torque; + + getAxis (joint,axis,joint->axis1); + axis[0] *= torque; + axis[1] *= torque; + axis[2] *= torque; + + if (joint->node[0].body != 0) + dBodyAddTorque (joint->node[0].body, axis[0], axis[1], axis[2]); + if (joint->node[1].body != 0) + dBodyAddTorque(joint->node[1].body, -axis[0], -axis[1], -axis[2]); +} + + +dxJoint::Vtable __dhinge_vtable = { + sizeof(dxJointHinge), + (dxJoint::init_fn*) hingeInit, + (dxJoint::getInfo1_fn*) hingeGetInfo1, + (dxJoint::getInfo2_fn*) hingeGetInfo2, + dJointTypeHinge}; + +//**************************************************************************** +// slider + +static void sliderInit (dxJointSlider *j) +{ + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->qrel,4); + dSetZero (j->offset,4); + j->limot.init (j->world); +} + + +extern "C" dReal dJointGetSliderPosition (dxJointSlider *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + + // get axis1 in global coordinates + dVector3 ax1,q; + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + + if (joint->node[1].body) { + // get body2 + offset point in global coordinates + dMULTIPLY0_331 (q,joint->node[1].body->R,joint->offset); + for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - q[i] - + joint->node[1].body->pos[i]; + } + else { + for (int i=0; i<3; i++) q[i] = joint->node[0].body->pos[i] - + joint->offset[i]; + + } + return dDOT(ax1,q); +} + + +extern "C" dReal dJointGetSliderPositionRate (dxJointSlider *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + + // get axis1 in global coordinates + dVector3 ax1; + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + + if (joint->node[1].body) { + return dDOT(ax1,joint->node[0].body->lvel) - + dDOT(ax1,joint->node[1].body->lvel); + } + else { + return dDOT(ax1,joint->node[0].body->lvel); + } +} + + +static void sliderGetInfo1 (dxJointSlider *j, dxJoint::Info1 *info) +{ + info->nub = 5; + + // see if joint is powered + if (j->limot.fmax > 0) + info->m = 6; // powered slider needs an extra constraint row + else info->m = 5; + + // see if we're at a joint limit. + j->limot.limit = 0; + if ((j->limot.lostop > -dInfinity || j->limot.histop < dInfinity) && + j->limot.lostop <= j->limot.histop) { + // measure joint position + dReal pos = dJointGetSliderPosition (j); + if (pos <= j->limot.lostop) { + j->limot.limit = 1; + j->limot.limit_err = pos - j->limot.lostop; + info->m = 6; + } + else if (pos >= j->limot.histop) { + j->limot.limit = 2; + j->limot.limit_err = pos - j->limot.histop; + info->m = 6; + } + } +} + + +static void sliderGetInfo2 (dxJointSlider *joint, dxJoint::Info2 *info) +{ + int i,s = info->rowskip; + int s3=3*s,s4=4*s; + + // pull out pos and R for both bodies. also get the `connection' + // vector pos2-pos1. + + dReal *pos1,*pos2,*R1,*R2; + dVector3 c; + pos1 = joint->node[0].body->pos; + R1 = joint->node[0].body->R; + if (joint->node[1].body) { + pos2 = joint->node[1].body->pos; + R2 = joint->node[1].body->R; + for (i=0; i<3; i++) c[i] = pos2[i] - pos1[i]; + } + else { + pos2 = 0; + R2 = 0; + } + + // 3 rows to make body rotations equal + setFixedOrientation(joint, info, joint->qrel, 0); + + // remaining two rows. we want: vel2 = vel1 + w1 x c ... but this would + // result in three equations, so we project along the planespace vectors + // so that sliding along the slider axis is disregarded. for symmetry we + // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2. + + dVector3 ax1; // joint axis in global coordinates (unit length) + dVector3 p,q; // plane space of ax1 + dMULTIPLY0_331 (ax1,R1,joint->axis1); + dPlaneSpace (ax1,p,q); + if (joint->node[1].body) { + dVector3 tmp; + dCROSS (tmp, = REAL(0.5) * ,c,p); + for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; + for (i=0; i<3; i++) info->J2a[s3+i] = tmp[i]; + dCROSS (tmp, = REAL(0.5) * ,c,q); + for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; + for (i=0; i<3; i++) info->J2a[s4+i] = tmp[i]; + for (i=0; i<3; i++) info->J2l[s3+i] = -p[i]; + for (i=0; i<3; i++) info->J2l[s4+i] = -q[i]; + } + for (i=0; i<3; i++) info->J1l[s3+i] = p[i]; + for (i=0; i<3; i++) info->J1l[s4+i] = q[i]; + + // compute last two elements of right hand side. we want to align the offset + // point (in body 2's frame) with the center of body 1. + dReal k = info->fps * info->erp; + if (joint->node[1].body) { + dVector3 ofs; // offset point in global coordinates + dMULTIPLY0_331 (ofs,R2,joint->offset); + for (i=0; i<3; i++) c[i] += ofs[i]; + info->c[3] = k * dDOT(p,c); + info->c[4] = k * dDOT(q,c); +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[3] %f ",info->c[3]); PRINT_DBL_HEX(info->c[3]); + fprintf(f,"c[4] %f ",info->c[4]); PRINT_DBL_HEX(info->c[4]); + } +#endif + + } + else { + dVector3 ofs; // offset point in global coordinates + for (i=0; i<3; i++) ofs[i] = joint->offset[i] - pos1[i]; + info->c[3] = k * dDOT(p,ofs); + info->c[4] = k * dDOT(q,ofs); +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[3] %f ",info->c[3]); PRINT_DBL_HEX(info->c[3]); + fprintf(f,"c[4] %f ",info->c[4]); PRINT_DBL_HEX(info->c[4]); + } +#endif + } + + // if the slider is powered, or has joint limits, add in the extra row + joint->limot.addLimot (joint,info,5,ax1,0); +} + + +extern "C" void dJointSetSliderAxis (dxJointSlider *joint, + dReal x, dReal y, dReal z) +{ + int i; + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + setAxes (joint,x,y,z,joint->axis1,0); + + // compute initial relative rotation body1 -> body2, or env -> body1 + // also compute center of body1 w.r.t body 2 + if (joint->node[1].body) { + dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); + dVector3 c; + for (i=0; i<3; i++) + c[i] = joint->node[0].body->pos[i] - joint->node[1].body->pos[i]; + dMULTIPLY1_331 (joint->offset,joint->node[1].body->R,c); + } + else { + // set joint->qrel to the transpose of the first body's q + joint->qrel[0] = joint->node[0].body->q[0]; + for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; + for (i=0; i<3; i++) joint->offset[i] = joint->node[0].body->pos[i]; + } +} + + +extern "C" void dJointSetSliderAxisDelta (dxJointSlider *joint, + dReal x, dReal y, dReal z, + dReal dx, dReal dy, dReal dz) +{ + int i; + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + setAxes (joint,x,y,z,joint->axis1,0); + + // compute initial relative rotation body1 -> body2, or env -> body1 + // also compute center of body1 w.r.t body 2 + if (joint->node[1].body) { + dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); + dVector3 c; + for (i=0; i<3; i++) + c[i] = joint->node[0].body->pos[i] - joint->node[1].body->pos[i]; + dMULTIPLY1_331 (joint->offset,joint->node[1].body->R,c); + } + else { + // set joint->qrel to the transpose of the first body's q + joint->qrel[0] = joint->node[0].body->q[0]; + + for (i=1; i<4; i++) + joint->qrel[i] = -joint->node[0].body->q[i]; + + joint->offset[0] = joint->node[0].body->pos[0] + dx; + joint->offset[1] = joint->node[0].body->pos[1] + dy; + joint->offset[2] = joint->node[0].body->pos[2] + dz; + } +} + + + +extern "C" void dJointGetSliderAxis (dxJointSlider *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + getAxis (joint,result,joint->axis1); +} + + +extern "C" void dJointSetSliderParam (dxJointSlider *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + joint->limot.set (parameter,value); +} + + +extern "C" dReal dJointGetSliderParam (dxJointSlider *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + return joint->limot.get (parameter); +} + + +extern "C" void dJointAddSliderForce (dxJointSlider *joint, dReal force) +{ + dVector3 axis; + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dslider_vtable,"joint is not a slider"); + + if (joint->flags & dJOINT_REVERSE) + force -= force; + + getAxis (joint,axis,joint->axis1); + axis[0] *= force; + axis[1] *= force; + axis[2] *= force; + + if (joint->node[0].body != 0) + dBodyAddForce (joint->node[0].body,axis[0],axis[1],axis[2]); + if (joint->node[1].body != 0) + dBodyAddForce(joint->node[1].body, -axis[0], -axis[1], -axis[2]); +} + + +dxJoint::Vtable __dslider_vtable = { + sizeof(dxJointSlider), + (dxJoint::init_fn*) sliderInit, + (dxJoint::getInfo1_fn*) sliderGetInfo1, + (dxJoint::getInfo2_fn*) sliderGetInfo2, + dJointTypeSlider}; + +//**************************************************************************** +// contact + +static void contactInit (dxJointContact *j) +{ + // default frictionless contact. hmmm, this info gets overwritten straight + // away anyway, so why bother? +#if 0 /* so don't bother ;) */ + j->contact.surface.mode = 0; + j->contact.surface.mu = 0; + dSetZero (j->contact.geom.pos,4); + dSetZero (j->contact.geom.normal,4); + j->contact.geom.depth = 0; +#endif +} + + +static void contactGetInfo1 (dxJointContact *j, dxJoint::Info1 *info) +{ + // make sure mu's >= 0, then calculate number of constraint rows and number + // of unbounded rows. + int m = 1, nub=0; + if (j->contact.surface.mu < 0) j->contact.surface.mu = 0; + if (j->contact.surface.mode & dContactMu2) { + if (j->contact.surface.mu > 0) m++; + if (j->contact.surface.mu2 < 0) j->contact.surface.mu2 = 0; + if (j->contact.surface.mu2 > 0) m++; + if (j->contact.surface.mu == dInfinity) nub ++; + if (j->contact.surface.mu2 == dInfinity) nub ++; + } + else { + if (j->contact.surface.mu > 0) m += 2; + if (j->contact.surface.mu == dInfinity) nub += 2; + } + + j->the_m = m; + info->m = m; + info->nub = nub; +} + + +static void contactGetInfo2 (dxJointContact *j, dxJoint::Info2 *info) +{ + int i,s = info->rowskip; + int s2 = 2*s; + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"(contact joint)\n"); + } +#endif + + + // get normal, with sign adjusted for body1/body2 polarity + dVector3 normal; + if (j->flags & dJOINT_REVERSE) { + normal[0] = - j->contact.geom.normal[0]; + normal[1] = - j->contact.geom.normal[1]; + normal[2] = - j->contact.geom.normal[2]; + } + else { + normal[0] = j->contact.geom.normal[0]; + normal[1] = j->contact.geom.normal[1]; + normal[2] = j->contact.geom.normal[2]; + } + normal[3] = 0; // @@@ hmmm + + // c1,c2 = contact points with respect to body PORs + dVector3 c1,c2; + for (i=0; i<3; i++){ + c1[i] = j->contact.geom.pos[i] - j->node[0].body->pos[i]; + + } + + // set jacobian for normal + info->J1l[0] = normal[0]; + info->J1l[1] = normal[1]; + info->J1l[2] = normal[2]; + dCROSS (info->J1a,=,c1,normal); + + if (j->node[1].body) { + for (i=0; i<3; i++) c2[i] = j->contact.geom.pos[i] - + j->node[1].body->pos[i]; + info->J2l[0] = -normal[0]; + info->J2l[1] = -normal[1]; + info->J2l[2] = -normal[2]; + dCROSS (info->J2a,= -,c2,normal); + } + + // set right hand side and cfm value for normal + dReal erp = info->erp; + if (j->contact.surface.mode & dContactSoftERP) + erp = j->contact.surface.soft_erp; + dReal k = info->fps * erp; + dReal depth = j->contact.geom.depth - j->world->contactp.min_depth; + if (depth < 0) depth = 0; + dReal maxvel = j->world->contactp.max_vel; + + // added by ericf - motion along normal - for simulating moving bodies' velocity along + // the normal using static geoms and such + dReal motionN = 0; + if (j->contact.surface.mode & dContactMotionN){ + motionN = j->contact.surface.motionN; + } + dReal pushout = k*depth + motionN; + if (pushout > maxvel) + info->c[0] = maxvel; + else + info->c[0] = pushout; + +// if (k*depth > maxvel){ +// info->c[0] = maxvel; +// } +// else{ +// info->c[0] = k*depth; +// } + + if (j->contact.surface.mode & dContactSoftCFM) + info->cfm[0] = j->contact.surface.soft_cfm; + + + + + // deal with bounce + if (j->contact.surface.mode & dContactBounce) { + // calculate outgoing velocity (-ve for incoming contact) + dReal outgoing = dDOT(info->J1l,j->node[0].body->lvel) + + dDOT(info->J1a,j->node[0].body->avel); + if (j->node[1].body) { + outgoing += dDOT(info->J2l,j->node[1].body->lvel) + + dDOT(info->J2a,j->node[1].body->avel); + } + // only apply bounce if the outgoing velocity is greater than the + // threshold, and if the resulting c[0] exceeds what we already have. + if (j->contact.surface.bounce_vel >= 0 && + (-outgoing) > j->contact.surface.bounce_vel) { + //motionN added by ericf + dReal newc = - j->contact.surface.bounce * outgoing + motionN; + if (newc > info->c[0]){ + info->c[0] = newc; + } + } + } + + // set LCP limits for normal + info->lo[0] = 0; + info->hi[0] = dInfinity; + + // now do jacobian for tangential forces + dVector3 t1,t2; // two vectors tangential to normal + + // first friction direction + if (j->the_m >= 2) { + if (j->contact.surface.mode & dContactFDir1) { // use fdir1 ? + t1[0] = j->contact.fdir1[0]; + t1[1] = j->contact.fdir1[1]; + t1[2] = j->contact.fdir1[2]; + dCROSS (t2,=,normal,t1); + } + else { + dPlaneSpace (normal,t1,t2); + } + info->J1l[s+0] = t1[0]; + info->J1l[s+1] = t1[1]; + info->J1l[s+2] = t1[2]; + dCROSS (info->J1a+s,=,c1,t1); + + if (j->node[1].body) { + info->J2l[s+0] = -t1[0]; + info->J2l[s+1] = -t1[1]; + info->J2l[s+2] = -t1[2]; + dCROSS (info->J2a+s,= -,c2,t1); + } + // set right hand side + if (j->contact.surface.mode & dContactMotion1) { + info->c[1] = j->contact.surface.motion1; + } + + // set LCP bounds and friction index. this depends on the approximation + // mode + info->lo[1] = -j->contact.surface.mu; + info->hi[1] = j->contact.surface.mu; + if (j->contact.surface.mode & dContactApprox1_1) info->findex[1] = 0; + + // set slip (constraint force mixing) + if (j->contact.surface.mode & dContactSlip1){ + info->cfm[1] = j->contact.surface.slip1; + } + } + + // second friction direction + if (j->the_m >= 3) { + info->J1l[s2+0] = t2[0]; + info->J1l[s2+1] = t2[1]; + info->J1l[s2+2] = t2[2]; + dCROSS (info->J1a+s2,=,c1,t2); + if (j->node[1].body) { + info->J2l[s2+0] = -t2[0]; + info->J2l[s2+1] = -t2[1]; + info->J2l[s2+2] = -t2[2]; + dCROSS (info->J2a+s2,= -,c2,t2); + } + // set right hand side + if (j->contact.surface.mode & dContactMotion2) { + info->c[2] = j->contact.surface.motion2; + } + // set LCP bounds and friction index. this depends on the approximation + // mode + if (j->contact.surface.mode & dContactMu2) { + info->lo[2] = -j->contact.surface.mu2; + info->hi[2] = j->contact.surface.mu2; + } + else { + info->lo[2] = -j->contact.surface.mu; + info->hi[2] = j->contact.surface.mu; + } + if (j->contact.surface.mode & dContactApprox1_2) info->findex[2] = 0; + + // set slip (constraint force mixing) + if (j->contact.surface.mode & dContactSlip2){ + info->cfm[2] = j->contact.surface.slip2; + } + } + +} + +dxJoint::Vtable __dcontact_vtable = { + sizeof(dxJointContact), + (dxJoint::init_fn*) contactInit, + (dxJoint::getInfo1_fn*) contactGetInfo1, + (dxJoint::getInfo2_fn*) contactGetInfo2, + dJointTypeContact}; + +//**************************************************************************** +// hinge 2. note that this joint must be attached to two bodies for it to work + +static dReal measureHinge2Angle (dxJointHinge2 *joint) +{ + dVector3 a1,a2; + dMULTIPLY0_331 (a1,joint->node[1].body->R,joint->axis2); + dMULTIPLY1_331 (a2,joint->node[0].body->R,a1); + dReal x = dDOT(joint->v1,a2); + dReal y = dDOT(joint->v2,a2); + return -dAtan2 (y,x); +} + + +static void hinge2Init (dxJointHinge2 *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->axis2,4); + j->axis2[1] = 1; + j->c0 = 0; + j->s0 = 0; + + dSetZero (j->v1,4); + j->v1[0] = 1; + dSetZero (j->v2,4); + j->v2[1] = 1; + + j->limot1.init (j->world); + j->limot2.init (j->world); + + j->susp_erp = j->world->global_erp; + j->susp_cfm = j->world->global_cfm; + + j->flags |= dJOINT_TWOBODIES; +} + + +static void hinge2GetInfo1 (dxJointHinge2 *j, dxJoint::Info1 *info) +{ + info->m = 4; + info->nub = 4; + + // see if we're powered or at a joint limit for axis 1 + int atlimit=0; + if ((j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && + j->limot1.lostop <= j->limot1.histop) { + dReal angle = measureHinge2Angle (j); + if (j->limot1.testRotationalLimit (angle)) atlimit = 1; + } + if (atlimit || j->limot1.fmax > 0) info->m++; + + // see if we're powering axis 2 (we currently never limit this axis) + j->limot2.limit = 0; + if (j->limot2.fmax > 0) info->m++; +} + + +// macro that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are +// relative to body 1 and 2 initially) and then computes the constrained +// rotational axis as the cross product of ax1 and ax2. +// the sin and cos of the angle between axis 1 and 2 is computed, this comes +// from dot and cross product rules. + +#define HINGE2_GET_AXIS_INFO(axis,sin_angle,cos_angle) \ + dVector3 ax1,ax2; \ + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); \ + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); \ + dCROSS (axis,=,ax1,ax2); \ + sin_angle = dSqrt (axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]); \ + cos_angle = dDOT (ax1,ax2); + + +static void hinge2GetInfo2 (dxJointHinge2 *joint, dxJoint::Info2 *info) +{ + // get information we need to set the hinge row + dReal s,c; + dVector3 q; + HINGE2_GET_AXIS_INFO (q,s,c); + dNormalize3 (q); // @@@ quicker: divide q by s ? + + // set the three ball-and-socket rows (aligned to the suspension axis ax1) + setBall2 (joint,info,joint->anchor1,joint->anchor2,ax1,joint->susp_erp); + + // set the hinge row + int s3=3*info->rowskip; + info->J1a[s3+0] = q[0]; + info->J1a[s3+1] = q[1]; + info->J1a[s3+2] = q[2]; + if (joint->node[1].body) { + info->J2a[s3+0] = -q[0]; + info->J2a[s3+1] = -q[1]; + info->J2a[s3+2] = -q[2]; + } + + // compute the right hand side for the constrained rotational DOF. + // axis 1 and axis 2 are separated by an angle `theta'. the desired + // separation angle is theta0. sin(theta0) and cos(theta0) are recorded + // in the joint structure. the correcting angular velocity is: + // |angular_velocity| = angle/time = erp*(theta0-theta) / stepsize + // = (erp*fps) * (theta0-theta) + // (theta0-theta) can be computed using the following small-angle-difference + // approximation: + // theta0-theta ~= tan(theta0-theta) + // = sin(theta0-theta)/cos(theta0-theta) + // = (c*s0 - s*c0) / (c*c0 + s*s0) + // = c*s0 - s*c0 assuming c*c0 + s*s0 ~= 1 + // where c = cos(theta), s = sin(theta) + // c0 = cos(theta0), s0 = sin(theta0) + + dReal k = info->fps * info->erp; + info->c[3] = k * (joint->c0 * s - joint->s0 * c); + + // if the axis1 hinge is powered, or has joint limits, add in more stuff + int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); + + // if the axis2 hinge is powered, add in more stuff + joint->limot2.addLimot (joint,info,row,ax2,1); + + // set parameter for the suspension + info->cfm[0] = joint->susp_cfm; +} + + +// compute vectors v1 and v2 (embedded in body1), used to measure angle +// between body 1 and body 2 + +static void makeHinge2V1andV2 (dxJointHinge2 *joint) +{ + if (joint->node[0].body) { + // get axis 1 and 2 in global coords + dVector3 ax1,ax2,v; + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); + + // don't do anything if the axis1 or axis2 vectors are zero or the same + if ((ax1[0]==0 && ax1[1]==0 && ax1[2]==0) || + (ax2[0]==0 && ax2[1]==0 && ax2[2]==0) || + (ax1[0]==ax2[0] && ax1[1]==ax2[1] && ax1[2]==ax2[2])) return; + + // modify axis 2 so it's perpendicular to axis 1 + dReal k = dDOT(ax1,ax2); + for (int i=0; i<3; i++) ax2[i] -= k*ax1[i]; + dNormalize3 (ax2); + + // make v1 = modified axis2, v2 = axis1 x (modified axis2) + dCROSS (v,=,ax1,ax2); + dMULTIPLY1_331 (joint->v1,joint->node[0].body->R,ax2); + dMULTIPLY1_331 (joint->v2,joint->node[0].body->R,v); + } +} + + +extern "C" void dJointSetHinge2Anchor (dxJointHinge2 *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); + makeHinge2V1andV2 (joint); +} + + +extern "C" void dJointSetHinge2Axis1 (dxJointHinge2 *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (joint->axis1,joint->node[0].body->R,q); + joint->axis1[3] = 0; + + // compute the sin and cos of the angle between axis 1 and axis 2 + dVector3 ax; + HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); + } + makeHinge2V1andV2 (joint); +} + + +extern "C" void dJointSetHinge2Axis2 (dxJointHinge2 *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[1].body) { + dReal q[4]; + q[0] = x; + q[1] = y; + q[2] = z; + q[3] = 0; + dNormalize3 (q); + dMULTIPLY1_331 (joint->axis2,joint->node[1].body->R,q); + joint->axis1[3] = 0; + + // compute the sin and cos of the angle between axis 1 and axis 2 + dVector3 ax; + HINGE2_GET_AXIS_INFO(ax,joint->s0,joint->c0); + } + makeHinge2V1andV2 (joint); +} + + +extern "C" void dJointSetHinge2Param (dxJointHinge2 *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if ((parameter & 0xff00) == 0x100) { + joint->limot2.set (parameter & 0xff,value); + } + else { + if (parameter == dParamSuspensionERP) joint->susp_erp = value; + else if (parameter == dParamSuspensionCFM) joint->susp_cfm = value; + else joint->limot1.set (parameter,value); + } +} + + +extern "C" void dJointGetHinge2Anchor (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->flags & dJOINT_REVERSE) + getAnchor2 (joint,result,joint->anchor2); + else + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetHinge2Anchor2 (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->flags & dJOINT_REVERSE) + getAnchor (joint,result,joint->anchor1); + else + getAnchor2 (joint,result,joint->anchor2); +} + + +extern "C" void dJointGetHinge2Axis1 (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) { + dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis1); + } +} + + +extern "C" void dJointGetHinge2Axis2 (dxJointHinge2 *joint, dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[1].body) { + dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis2); + } +} + + +extern "C" dReal dJointGetHinge2Param (dxJointHinge2 *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if ((parameter & 0xff00) == 0x100) { + return joint->limot2.get (parameter & 0xff); + } + else { + if (parameter == dParamSuspensionERP) return joint->susp_erp; + else if (parameter == dParamSuspensionCFM) return joint->susp_cfm; + else return joint->limot1.get (parameter); + } +} + + +extern "C" dReal dJointGetHinge2Angle1 (dxJointHinge2 *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) return measureHinge2Angle (joint); + else return 0; +} + + +extern "C" dReal dJointGetHinge2Angle1Rate (dxJointHinge2 *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body) { + dVector3 axis; + dMULTIPLY0_331 (axis,joint->node[0].body->R,joint->axis1); + dReal rate = dDOT(axis,joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); + return rate; + } + else return 0; +} + + +extern "C" dReal dJointGetHinge2Angle2Rate (dxJointHinge2 *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + if (joint->node[0].body && joint->node[1].body) { + dVector3 axis; + dMULTIPLY0_331 (axis,joint->node[1].body->R,joint->axis2); + dReal rate = dDOT(axis,joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis,joint->node[1].body->avel); + return rate; + } + else return 0; +} + + +extern "C" void dJointAddHinge2Torques (dxJointHinge2 *joint, dReal torque1, dReal torque2) +{ + dVector3 axis1, axis2; + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dhinge2_vtable,"joint is not a hinge2"); + + if (joint->node[0].body && joint->node[1].body) { + dMULTIPLY0_331 (axis1,joint->node[0].body->R,joint->axis1); + dMULTIPLY0_331 (axis2,joint->node[1].body->R,joint->axis2); + axis1[0] = axis1[0] * torque1 + axis2[0] * torque2; + axis1[1] = axis1[1] * torque1 + axis2[1] * torque2; + axis1[2] = axis1[2] * torque1 + axis2[2] * torque2; + dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]); + dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]); + } +} + + +dxJoint::Vtable __dhinge2_vtable = { + sizeof(dxJointHinge2), + (dxJoint::init_fn*) hinge2Init, + (dxJoint::getInfo1_fn*) hinge2GetInfo1, + (dxJoint::getInfo2_fn*) hinge2GetInfo2, + dJointTypeHinge2}; + +//**************************************************************************** +// universal + +// I just realized that the universal joint is equivalent to a hinge 2 joint with +// perfectly stiff suspension. By comparing the hinge 2 implementation to +// the universal implementation, you may be able to improve this +// implementation (or, less likely, the hinge2 implementation). + +static void universalInit (dxJointUniversal *j) +{ + dSetZero (j->anchor1,4); + dSetZero (j->anchor2,4); + dSetZero (j->axis1,4); + j->axis1[0] = 1; + dSetZero (j->axis2,4); + j->axis2[1] = 1; + dSetZero(j->qrel1,4); + dSetZero(j->qrel2,4); + j->limot1.init (j->world); + j->limot2.init (j->world); +} + + +static void getUniversalAxes(dxJointUniversal *joint, dVector3 ax1, dVector3 ax2) +{ + // This says "ax1 = joint->node[0].body->R * joint->axis1" + dMULTIPLY0_331 (ax1,joint->node[0].body->R,joint->axis1); + + if (joint->node[1].body) { + dMULTIPLY0_331 (ax2,joint->node[1].body->R,joint->axis2); + } + else { + ax2[0] = joint->axis2[0]; + ax2[1] = joint->axis2[1]; + ax2[2] = joint->axis2[2]; + } +} + + +static dReal getUniversalAngle1(dxJointUniversal *joint) +{ + if (joint->node[0].body) { + // length 1 joint axis in global coordinates, from each body + dVector3 ax1, ax2; + dMatrix3 R; + dQuaternion qcross, qq, qrel; + + getUniversalAxes (joint,ax1,ax2); + + // It should be possible to get both angles without explicitly + // constructing the rotation matrix of the cross. Basically, + // orientation of the cross about axis1 comes from body 2, + // about axis 2 comes from body 1, and the perpendicular + // axis can come from the two bodies somehow. (We don't really + // want to assume it's 90 degrees, because in general the + // constraints won't be perfectly satisfied, or even very well + // satisfied.) + // + // However, we'd need a version of getHingeAngleFromRElativeQuat() + // that CAN handle when its relative quat is rotated along a direction + // other than the given axis. What I have here works, + // although it's probably much slower than need be. + + dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); + dRtoQ (R,qcross); + + // This code is essential the same as getHingeAngle(), see the comments + // there for details. + + // get qrel = relative rotation between node[0] and the cross + dQMultiply1 (qq,joint->node[0].body->q,qcross); + dQMultiply2 (qrel,qq,joint->qrel1); + + return getHingeAngleFromRelativeQuat(qrel, joint->axis1); + } + return 0; +} + + +static dReal getUniversalAngle2(dxJointUniversal *joint) +{ + if (joint->node[0].body) { + // length 1 joint axis in global coordinates, from each body + dVector3 ax1, ax2; + dMatrix3 R; + dQuaternion qcross, qq, qrel; + + getUniversalAxes (joint,ax1,ax2); + + // It should be possible to get both angles without explicitly + // constructing the rotation matrix of the cross. Basically, + // orientation of the cross about axis1 comes from body 2, + // about axis 2 comes from body 1, and the perpendicular + // axis can come from the two bodies somehow. (We don't really + // want to assume it's 90 degrees, because in general the + // constraints won't be perfectly satisfied, or even very well + // satisfied.) + // + // However, we'd need a version of getHingeAngleFromRElativeQuat() + // that CAN handle when its relative quat is rotated along a direction + // other than the given axis. What I have here works, + // although it's probably much slower than need be. + + dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); + dRtoQ(R, qcross); + + if (joint->node[1].body) { + dQMultiply1 (qq, joint->node[1].body->q, qcross); + dQMultiply2 (qrel,qq,joint->qrel2); + } + else { + // pretend joint->node[1].body->q is the identity + dQMultiply2 (qrel,qcross, joint->qrel2); + } + + return - getHingeAngleFromRelativeQuat(qrel, joint->axis2); + } + return 0; +} + + +static void universalGetInfo1 (dxJointUniversal *j, dxJoint::Info1 *info) +{ + info->nub = 4; + info->m = 4; + + // see if we're powered or at a joint limit. + bool constraint1 = j->limot1.fmax > 0; + bool constraint2 = j->limot2.fmax > 0; + + bool limiting1 = (j->limot1.lostop >= -M_PI || j->limot1.histop <= M_PI) && + j->limot1.lostop <= j->limot1.histop; + bool limiting2 = (j->limot2.lostop >= -M_PI || j->limot2.histop <= M_PI) && + j->limot2.lostop <= j->limot2.histop; + + // We need to call testRotationLimit() even if we're motored, since it + // records the result. + if (limiting1 || limiting2) { + dReal angle1, angle2; + angle1 = getUniversalAngle1(j); + angle2 = getUniversalAngle2(j); + if (limiting1 && j->limot1.testRotationalLimit (angle1)) constraint1 = true; + if (limiting2 && j->limot2.testRotationalLimit (angle2)) constraint2 = true; + } + if (constraint1) + info->m++; + if (constraint2) + info->m++; +} + + +static void universalGetInfo2 (dxJointUniversal *joint, dxJoint::Info2 *info) +{ +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"(universal joint)\n"); + } +#endif + + // set the three ball-and-socket rows + setBall (joint,info,joint->anchor1,joint->anchor2); + + + // set the universal joint row. the angular velocity about an axis + // perpendicular to both joint axes should be equal. thus the constraint + // equation is + // p*w1 - p*w2 = 0 + // where p is a vector normal to both joint axes, and w1 and w2 + // are the angular velocity vectors of the two bodies. + + // length 1 joint axis in global coordinates, from each body + dVector3 ax1, ax2; + dVector3 ax2_temp; + // length 1 vector perpendicular to ax1 and ax2. Neither body can rotate + // about this. + dVector3 p; + dReal k; + + getUniversalAxes(joint, ax1, ax2); + k = dDOT(ax1, ax2); + ax2_temp[0] = ax2[0] - k*ax1[0]; + ax2_temp[1] = ax2[1] - k*ax1[1]; + ax2_temp[2] = ax2[2] - k*ax1[2]; + dCROSS(p, =, ax1, ax2_temp); + dNormalize3(p); + + int s3=3*info->rowskip; + + info->J1a[s3+0] = p[0]; + info->J1a[s3+1] = p[1]; + info->J1a[s3+2] = p[2]; + + if (joint->node[1].body) { + info->J2a[s3+0] = -p[0]; + info->J2a[s3+1] = -p[1]; + info->J2a[s3+2] = -p[2]; + } + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"info->J1a[s3+0] %f ",info->J1a[s3+0]); PRINT_DBL_HEX(info->J1a[s3+0]); + fprintf(f,"info->J1a[s3+1] %f ",info->J1a[s3+1]); PRINT_DBL_HEX(info->J1a[s3+1]); + fprintf(f,"info->J1a[s3+2] %f ",info->J1a[s3+2]); PRINT_DBL_HEX(info->J1a[s3+2]); + + fprintf(f,"info->J2a[s3+0] %f ",info->J2a[s3+0]); PRINT_DBL_HEX(info->J2a[s3+0]); + fprintf(f,"info->J2a[s3+1] %f ",info->J2a[s3+1]); PRINT_DBL_HEX(info->J2a[s3+1]); + fprintf(f,"info->J2a[s3+2] %f ",info->J2a[s3+2]); PRINT_DBL_HEX(info->J2a[s3+2]); + } +#endif + // compute the right hand side of the constraint equation. set relative + // body velocities along p to bring the axes back to perpendicular. + // If ax1, ax2 are unit length joint axes as computed from body1 and + // body2, we need to rotate both bodies along the axis p. If theta + // is the angle between ax1 and ax2, we need an angular velocity + // along p to cover the angle erp * (theta - Pi/2) in one step: + // + // |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize + // = (erp*fps) * (theta - Pi/2) + // + // if theta is close to Pi/2, + // theta - Pi/2 ~= cos(theta), so + // |angular_velocity| ~= (erp*fps) * (ax1 dot ax2) + + info->c[3] = info->fps * info->erp * - dDOT(ax1, ax2); +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"c[3] %f ",info->c[3]); PRINT_DBL_HEX(info->c[3]); + } +#endif + + + // if the first angle is powered, or has joint limits, add in the stuff + int row = 4 + joint->limot1.addLimot (joint,info,4,ax1,1); + + // if the second angle is powered, or has joint limits, add in more stuff + joint->limot2.addLimot (joint,info,row,ax2,1); +} + + +static void universalComputeInitialRelativeRotations (dxJointUniversal *joint) +{ + if (joint->node[0].body) { + dVector3 ax1, ax2; + dMatrix3 R; + dQuaternion qcross; + + getUniversalAxes(joint, ax1, ax2); + + // Axis 1. + dRFrom2Axes(R, ax1[0], ax1[1], ax1[2], ax2[0], ax2[1], ax2[2]); + dRtoQ(R, qcross); + dQMultiply1 (joint->qrel1, joint->node[0].body->q, qcross); + + // Axis 2. + dRFrom2Axes(R, ax2[0], ax2[1], ax2[2], ax1[0], ax1[1], ax1[2]); + dRtoQ(R, qcross); + if (joint->node[1].body) { + dQMultiply1 (joint->qrel2, joint->node[1].body->q, qcross); + } + else { + // set joint->qrel to qcross + for (int i=0; i<4; i++) joint->qrel2[i] = qcross[i]; + } + } +} + + +extern "C" void dJointSetUniversalAnchor (dxJointUniversal *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); + universalComputeInitialRelativeRotations(joint); +} + + +extern "C" void dJointSetUniversalAxis1 (dxJointUniversal *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + setAxes (joint,x,y,z,NULL,joint->axis2); + else + setAxes (joint,x,y,z,joint->axis1,NULL); + universalComputeInitialRelativeRotations(joint); +} + + +extern "C" void dJointSetUniversalAxis2 (dxJointUniversal *joint, + dReal x, dReal y, dReal z) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + setAxes (joint,x,y,z,joint->axis1,NULL); + else + setAxes (joint,x,y,z,NULL,joint->axis2); + universalComputeInitialRelativeRotations(joint); +} + + +extern "C" void dJointGetUniversalAnchor (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + getAnchor2 (joint,result,joint->anchor2); + else + getAnchor (joint,result,joint->anchor1); +} + + +extern "C" void dJointGetUniversalAnchor2 (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + getAnchor (joint,result,joint->anchor1); + else + getAnchor2 (joint,result,joint->anchor2); +} + + +extern "C" void dJointGetUniversalAxis1 (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + getAxis2 (joint,result,joint->axis2); + else + getAxis (joint,result,joint->axis1); +} + + +extern "C" void dJointGetUniversalAxis2 (dxJointUniversal *joint, + dVector3 result) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(result,"bad result argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + getAxis (joint,result,joint->axis1); + else + getAxis2 (joint,result,joint->axis2); +} + + +extern "C" void dJointSetUniversalParam (dxJointUniversal *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if ((parameter & 0xff00) == 0x100) { + joint->limot2.set (parameter & 0xff,value); + } + else { + joint->limot1.set (parameter,value); + } +} + + +extern "C" dReal dJointGetUniversalParam (dxJointUniversal *joint, int parameter) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if ((parameter & 0xff00) == 0x100) { + return joint->limot2.get (parameter & 0xff); + } + else { + return joint->limot1.get (parameter); + } +} + + +extern "C" dReal dJointGetUniversalAngle1 (dxJointUniversal *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + return getUniversalAngle2 (joint); + else + return getUniversalAngle1 (joint); +} + + +extern "C" dReal dJointGetUniversalAngle2 (dxJointUniversal *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + if (joint->flags & dJOINT_REVERSE) + return getUniversalAngle1 (joint); + else + return getUniversalAngle2 (joint); +} + + +extern "C" dReal dJointGetUniversalAngle1Rate (dxJointUniversal *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + + if (joint->node[0].body) { + dVector3 axis; + + if (joint->flags & dJOINT_REVERSE) + getAxis2 (joint,axis,joint->axis2); + else + getAxis (joint,axis,joint->axis1); + + dReal rate = dDOT(axis, joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel); + return rate; + } + return 0; +} + + +extern "C" dReal dJointGetUniversalAngle2Rate (dxJointUniversal *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + + if (joint->node[0].body) { + dVector3 axis; + + if (joint->flags & dJOINT_REVERSE) + getAxis (joint,axis,joint->axis1); + else + getAxis2 (joint,axis,joint->axis2); + + dReal rate = dDOT(axis, joint->node[0].body->avel); + if (joint->node[1].body) rate -= dDOT(axis, joint->node[1].body->avel); + return rate; + } + return 0; +} + + +extern "C" void dJointAddUniversalTorques (dxJointUniversal *joint, dReal torque1, dReal torque2) +{ + dVector3 axis1, axis2; + dAASSERT(joint); + dUASSERT(joint->vtable == &__duniversal_vtable,"joint is not a universal"); + + if (joint->flags & dJOINT_REVERSE) { + dReal temp = torque1; + torque1 = - torque2; + torque2 = - temp; + } + + getAxis (joint,axis1,joint->axis1); + getAxis2 (joint,axis2,joint->axis2); + axis1[0] = axis1[0] * torque1 + axis2[0] * torque2; + axis1[1] = axis1[1] * torque1 + axis2[1] * torque2; + axis1[2] = axis1[2] * torque1 + axis2[2] * torque2; + + if (joint->node[0].body != 0) + dBodyAddTorque (joint->node[0].body,axis1[0],axis1[1],axis1[2]); + if (joint->node[1].body != 0) + dBodyAddTorque(joint->node[1].body, -axis1[0], -axis1[1], -axis1[2]); +} + + + + + +dxJoint::Vtable __duniversal_vtable = { + sizeof(dxJointUniversal), + (dxJoint::init_fn*) universalInit, + (dxJoint::getInfo1_fn*) universalGetInfo1, + (dxJoint::getInfo2_fn*) universalGetInfo2, + dJointTypeUniversal}; + +//**************************************************************************** +// angular motor + +static void amotorInit (dxJointAMotor *j) +{ + int i; + j->num = 0; + j->mode = dAMotorUser; + for (i=0; i<3; i++) { + j->rel[i] = 0; + dSetZero (j->axis[i],4); + j->limot[i].init (j->world); + j->angle[i] = 0; + } + dSetZero (j->reference1,4); + dSetZero (j->reference2,4); +} + + +// compute the 3 axes in global coordinates + +static void amotorComputeGlobalAxes (dxJointAMotor *joint, dVector3 ax[3]) +{ + if (joint->mode == dAMotorEuler) { + // special handling for euler mode + dMULTIPLY0_331 (ax[0],joint->node[0].body->R,joint->axis[0]); + if (joint->node[1].body) { + dMULTIPLY0_331 (ax[2],joint->node[1].body->R,joint->axis[2]); + } + else { + ax[2][0] = joint->axis[2][0]; + ax[2][1] = joint->axis[2][1]; + ax[2][2] = joint->axis[2][2]; + } + dCROSS (ax[1],=,ax[2],ax[0]); + dNormalize3 (ax[1]); + } + else { + for (int i=0; i < joint->num; i++) { + if (joint->rel[i] == 1) { + // relative to b1 + dMULTIPLY0_331 (ax[i],joint->node[0].body->R,joint->axis[i]); + } + else if (joint->rel[i] == 2) { + // relative to b2 + if (joint->node[1].body) { // jds: don't assert, just ignore + dMULTIPLY0_331 (ax[i],joint->node[1].body->R,joint->axis[i]); + } + } + else { + // global - just copy it + ax[i][0] = joint->axis[i][0]; + ax[i][1] = joint->axis[i][1]; + ax[i][2] = joint->axis[i][2]; + } + } + } +} + + +static void amotorComputeEulerAngles (dxJointAMotor *joint, dVector3 ax[3]) +{ + // assumptions: + // global axes already calculated --> ax + // axis[0] is relative to body 1 --> global ax[0] + // axis[2] is relative to body 2 --> global ax[2] + // ax[1] = ax[2] x ax[0] + // original ax[0] and ax[2] are perpendicular + // reference1 is perpendicular to ax[0] (in body 1 frame) + // reference2 is perpendicular to ax[2] (in body 2 frame) + // all ax[] and reference vectors are unit length + + // calculate references in global frame + dVector3 ref1,ref2; + dMULTIPLY0_331 (ref1,joint->node[0].body->R,joint->reference1); + if (joint->node[1].body) { + dMULTIPLY0_331 (ref2,joint->node[1].body->R,joint->reference2); + } + else { + ref2[0] = joint->reference2[0]; + ref2[1] = joint->reference2[1]; + ref2[2] = joint->reference2[2]; + } + + // get q perpendicular to both ax[0] and ref1, get first euler angle + dVector3 q; + dCROSS (q,=,ax[0],ref1); + joint->angle[0] = -dAtan2 (dDOT(ax[2],q),dDOT(ax[2],ref1)); + + // get q perpendicular to both ax[0] and ax[1], get second euler angle + dCROSS (q,=,ax[0],ax[1]); + joint->angle[1] = -dAtan2 (dDOT(ax[2],ax[0]),dDOT(ax[2],q)); + + // get q perpendicular to both ax[1] and ax[2], get third euler angle + dCROSS (q,=,ax[1],ax[2]); + joint->angle[2] = -dAtan2 (dDOT(ref2,ax[1]), dDOT(ref2,q)); +} + + +// set the reference vectors as follows: +// * reference1 = current axis[2] relative to body 1 +// * reference2 = current axis[0] relative to body 2 +// this assumes that: +// * axis[0] is relative to body 1 +// * axis[2] is relative to body 2 + +static void amotorSetEulerReferenceVectors (dxJointAMotor *j) +{ + if (j->node[0].body && j->node[1].body) { + dVector3 r; // axis[2] and axis[0] in global coordinates + dMULTIPLY0_331 (r,j->node[1].body->R,j->axis[2]); + dMULTIPLY1_331 (j->reference1,j->node[0].body->R,r); + dMULTIPLY0_331 (r,j->node[0].body->R,j->axis[0]); + dMULTIPLY1_331 (j->reference2,j->node[1].body->R,r); + } + + else { // jds + // else if (j->node[0].body) { + // dMULTIPLY1_331 (j->reference1,j->node[0].body->R,j->axis[2]); + // dMULTIPLY0_331 (j->reference2,j->node[0].body->R,j->axis[0]); + + // We want to handle angular motors attached to passive geoms + dVector3 r; // axis[2] and axis[0] in global coordinates + r[0] = j->axis[2][0]; r[1] = j->axis[2][1]; r[2] = j->axis[2][2]; r[3] = j->axis[2][3]; + dMULTIPLY1_331 (j->reference1,j->node[0].body->R,r); + dMULTIPLY0_331 (r,j->node[0].body->R,j->axis[0]); + j->reference2[0] += r[0]; j->reference2[1] += r[1]; + j->reference2[2] += r[2]; j->reference2[3] += r[3]; + } +} + + +static void amotorGetInfo1 (dxJointAMotor *j, dxJoint::Info1 *info) +{ + info->m = 0; + info->nub = 0; + + // compute the axes and angles, if in euler mode + if (j->mode == dAMotorEuler) { + dVector3 ax[3]; + amotorComputeGlobalAxes (j,ax); + amotorComputeEulerAngles (j,ax); + } + + // see if we're powered or at a joint limit for each axis + for (int i=0; i < j->num; i++) { + if (j->limot[i].testRotationalLimit (j->angle[i]) || + j->limot[i].fmax > 0) { + info->m++; + } + } +} + + +static void amotorGetInfo2 (dxJointAMotor *joint, dxJoint::Info2 *info) +{ + int i; + +#if VALUE_TESTING + if (testLogging){ + fprintf(f,"(amotor joint)\n"); + } +#endif + + + // compute the axes (if not global) + dVector3 ax[3]; + amotorComputeGlobalAxes (joint,ax); + + // in euler angle mode we do not actually constrain the angular velocity + // along the axes axis[0] and axis[2] (although we do use axis[1]) : + // + // to get constrain w2-w1 along ...not + // ------ --------------------- ------ + // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0] + // d(angle[1])/dt = 0 ax[1] + // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2] + // + // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0. + // to prove the result for angle[0], write the expression for angle[0] from + // GetInfo1 then take the derivative. to prove this for angle[2] it is + // easier to take the euler rate expression for d(angle[2])/dt with respect + // to the components of w and set that to 0. + + dVector3 *axptr[3]; + axptr[0] = &ax[0]; + axptr[1] = &ax[1]; + axptr[2] = &ax[2]; + + dVector3 ax0_cross_ax1; + dVector3 ax1_cross_ax2; + if (joint->mode == dAMotorEuler) { + dCROSS (ax0_cross_ax1,=,ax[0],ax[1]); + axptr[2] = &ax0_cross_ax1; + dCROSS (ax1_cross_ax2,=,ax[1],ax[2]); + axptr[0] = &ax1_cross_ax2; + } + + int row=0; + for (i=0; i < joint->num; i++) { + row += joint->limot[i].addLimot (joint,info,row,*(axptr[i]),1); + } +} + + +extern "C" void dJointSetAMotorNumAxes (dxJointAMotor *joint, int num) +{ + dAASSERT(joint && num >= 0 && num <= 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (joint->mode == dAMotorEuler) { + joint->num = 3; + } + else { + if (num < 0) num = 0; + if (num > 3) num = 3; + joint->num = num; + } +} + + +extern "C" void dJointSetAMotorAxis (dxJointAMotor *joint, int anum, int rel, + dReal x, dReal y, dReal z) +{ + dAASSERT(joint && anum >= 0 && anum <= 2 && rel >= 0 && rel <= 2); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + dUASSERT(!(!joint->node[1].body && (joint->flags & dJOINT_REVERSE) && rel == 1),"no first body, can't set axis rel=1"); + dUASSERT(!(!joint->node[1].body && !(joint->flags & dJOINT_REVERSE) && rel == 2),"no second body, can't set axis rel=2"); + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + + // adjust rel to match the internal body order + if (!joint->node[1].body && rel==2) rel = 1; + + joint->rel[anum] = rel; + + // x,y,z is always in global coordinates regardless of rel, so we may have + // to convert it to be relative to a body + dVector3 r; + r[0] = x; + r[1] = y; + r[2] = z; + r[3] = 0; + if (rel > 0) { + if (rel==1) { + dMULTIPLY1_331 (joint->axis[anum],joint->node[0].body->R,r); + } + else { + // don't assert; handle the case of attachment to a bodiless geom + if (joint->node[1].body) { // jds + dMULTIPLY1_331 (joint->axis[anum],joint->node[1].body->R,r); + } + else { + joint->axis[anum][0] = r[0]; joint->axis[anum][1] = r[1]; + joint->axis[anum][2] = r[2]; joint->axis[anum][3] = r[3]; + } + } + } + else { + joint->axis[anum][0] = r[0]; + joint->axis[anum][1] = r[1]; + joint->axis[anum][2] = r[2]; + } + dNormalize3 (joint->axis[anum]); + if (joint->mode == dAMotorEuler) amotorSetEulerReferenceVectors (joint); +} + + +extern "C" void dJointSetAMotorAngle (dxJointAMotor *joint, int anum, + dReal angle) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (joint->mode == dAMotorUser) { + if (anum < 0) anum = 0; + if (anum > 3) anum = 3; + joint->angle[anum] = angle; + } +} + + +extern "C" void dJointSetAMotorParam (dxJointAMotor *joint, int parameter, + dReal value) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + int anum = parameter >> 8; + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + parameter &= 0xff; + joint->limot[anum].set (parameter, value); +} + + +extern "C" void dJointSetAMotorMode (dxJointAMotor *joint, int mode) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + joint->mode = mode; + if (joint->mode == dAMotorEuler) { + joint->num = 3; + amotorSetEulerReferenceVectors (joint); + } +} + + +extern "C" int dJointGetAMotorNumAxes (dxJointAMotor *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + return joint->num; +} + + +extern "C" void dJointGetAMotorAxis (dxJointAMotor *joint, int anum, + dVector3 result) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + if (joint->rel[anum] > 0) { + if (joint->rel[anum]==1) { + dMULTIPLY0_331 (result,joint->node[0].body->R,joint->axis[anum]); + } + else { + if (joint->node[1].body) { // jds + dMULTIPLY0_331 (result,joint->node[1].body->R,joint->axis[anum]); + } + else { + result[0] = joint->axis[anum][0]; result[1] = joint->axis[anum][1]; + result[2] = joint->axis[anum][2]; result[3] = joint->axis[anum][3]; + } + } + } + else { + result[0] = joint->axis[anum][0]; + result[1] = joint->axis[anum][1]; + result[2] = joint->axis[anum][2]; + } +} + + +extern "C" int dJointGetAMotorAxisRel (dxJointAMotor *joint, int anum) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + return joint->rel[anum]; +} + + +extern "C" dReal dJointGetAMotorAngle (dxJointAMotor *joint, int anum) +{ + dAASSERT(joint && anum >= 0 && anum < 3); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + if (anum < 0) anum = 0; + if (anum > 3) anum = 3; + + // compute the axes and angles, if in euler mode + if (joint->mode == dAMotorEuler) { + dVector3 ax[3]; + amotorComputeGlobalAxes (joint,ax); + amotorComputeEulerAngles (joint,ax); + } + + return joint->angle[anum]; +} + + +extern "C" dReal dJointGetAMotorAngleRate (dxJointAMotor *joint, int anum) +{ + // @@@ + dDebug (0,"not yet implemented"); + return 0; +} + + +extern "C" dReal dJointGetAMotorParam (dxJointAMotor *joint, int parameter) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + int anum = parameter >> 8; + if (anum < 0) anum = 0; + if (anum > 2) anum = 2; + parameter &= 0xff; + return joint->limot[anum].get (parameter); +} + + +extern "C" int dJointGetAMotorMode (dxJointAMotor *joint) +{ + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + return joint->mode; +} + + +extern "C" void dJointAddAMotorTorques (dxJointAMotor *joint, dReal torque1, dReal torque2, dReal torque3) +{ + dVector3 axes[3]; + dAASSERT(joint); + dUASSERT(joint->vtable == &__damotor_vtable,"joint is not an amotor"); + + if (joint->num == 0) + return; + dUASSERT((joint->flags & dJOINT_REVERSE) == 0, "dJointAddAMotorTorques not yet implemented for reverse AMotor joints"); + + amotorComputeGlobalAxes (joint,axes); + axes[0][0] *= torque1; + axes[0][1] *= torque1; + axes[0][2] *= torque1; + if (joint->num >= 2) { + axes[0][0] += axes[1][0] * torque2; + axes[0][1] += axes[1][0] * torque2; + axes[0][2] += axes[1][0] * torque2; + if (joint->num >= 3) { + axes[0][0] += axes[2][0] * torque3; + axes[0][1] += axes[2][0] * torque3; + axes[0][2] += axes[2][0] * torque3; + } + } + + if (joint->node[0].body != 0) + dBodyAddTorque (joint->node[0].body,axes[0][0],axes[0][1],axes[0][2]); + if (joint->node[1].body != 0) + dBodyAddTorque(joint->node[1].body, -axes[0][0], -axes[0][1], -axes[0][2]); +} + + +dxJoint::Vtable __damotor_vtable = { + sizeof(dxJointAMotor), + (dxJoint::init_fn*) amotorInit, + (dxJoint::getInfo1_fn*) amotorGetInfo1, + (dxJoint::getInfo2_fn*) amotorGetInfo2, + dJointTypeAMotor}; + +//**************************************************************************** +// fixed joint + +static void fixedInit (dxJointFixed *j) +{ + dSetZero (j->offset,4); + dSetZero (j->qrel,4); + dSetZero (j->anchor1,3); + dSetZero (j->anchor2,3); + j->linearStiffness = 0.0; + j->linearDamping = 0.0; + j->angularStiffness = 0.0; + j->angularDamping = 0.0; + j->active = true; + j->linearSpringMode = false; + j->angularSpringMode = false; + j->customAnchorPoint = false; +} + + +static void fixedGetInfo1 (dxJointFixed *j, dxJoint::Info1 *info) +{ + if (j->active){ + info->m = 6; + info->nub = 6; + } + else{ + info->m = 0; + info->nub = 0; + } +} + + +static void fixedGetInfo2 (dxJointFixed *joint, dxJoint::Info2 *info) +{ + if (!joint->active) + return; + + dReal origERP = info->erp; + + int s = info->rowskip; + + dReal linearStiffness = joint->linearStiffness; + dReal linearDamping = joint->linearDamping; + + dReal rotateStiffness = joint->angularStiffness; + dReal rotateDamping = joint->angularDamping; + + dReal stepSize = 1.0/info->fps; + + dReal linearERP = 0; + dReal linearCFM = 0; + dReal rotateERP = 0; + dReal rotateCFM = 0; + + if (joint->linearSpringMode){ + //printf("LSP %f %f\n",linearStiffness,linearDamping); + if ((linearStiffness < 0.00001) && (linearDamping < 0.00001)){ + linearDamping = 0.00001; + } + linearERP = (linearStiffness * stepSize)/((linearStiffness * stepSize) + linearDamping); + linearCFM = 1.0/(stepSize*linearStiffness + linearDamping); + } + if (joint->angularSpringMode){ + //printf("ASP %f %f\n",rotateStiffness,rotateDamping); + if ((rotateStiffness < 0.00001) && (rotateDamping < 0.00001)){ + rotateDamping = 0.00001; + } + rotateERP = (rotateStiffness * stepSize)/((rotateStiffness * stepSize) + rotateDamping); + rotateCFM = 1.0/(stepSize*rotateStiffness + rotateDamping); + info->erp = rotateERP; + } + + // Three rows for orientation + setFixedOrientation(joint, info, joint->qrel, 3); + + if (joint->linearSpringMode){ + info->erp = linearERP; + } + + + // we worry about our anchor point + if (joint->customAnchorPoint){ + setBall(joint,info,joint->anchor1,joint->anchor2); + } + //original fixed code - just use the offset between the two + // (the anchor is effectively at one of the bodies) + else{ + // Three rows for position. + // set jacobian + info->J1l[0] = 1; + info->J1l[s+1] = 1; + info->J1l[2*s+2] = 1; + + dVector3 ofs; + dMULTIPLY0_331 (ofs,joint->node[0].body->R,joint->offset); + if (joint->node[1].body) { + dCROSSMAT (info->J1a,ofs,s,+,-); + info->J2l[0] = -1; + info->J2l[s+1] = -1; + info->J2l[2*s+2] = -1; + } + + // set right hand side for the first three rows (linear) + dReal k = info->fps * info->erp; + if (joint->node[1].body) { + for (int j=0; j<3; j++) + info->c[j] = k * (joint->node[1].body->pos[j] - + joint->node[0].body->pos[j] + ofs[j]); + } + else { + for (int j=0; j<3; j++) + info->c[j] = k * (joint->offset[j] - joint->node[0].body->pos[j]); + } + } + + if (joint->linearSpringMode){ + info->cfm[0] = linearCFM; + info->cfm[1] = linearCFM; + info->cfm[2] = linearCFM; + } + if (joint->angularSpringMode){ + info->cfm[3] = rotateCFM; + info->cfm[4] = rotateCFM; + info->cfm[5] = rotateCFM; + } + + info->erp = origERP; +} + + +extern "C" void dJointSetFixed (dxJointFixed *joint) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not fixed"); + int i; + + // This code is taken from sJointSetSliderAxis(), we should really put the + // common code in its own function. + // compute the offset between the bodies + if (joint->node[0].body) { + if (joint->node[1].body) { + dQMultiply1 (joint->qrel,joint->node[0].body->q,joint->node[1].body->q); + dReal ofs[4]; + for (i=0; i<4; i++) ofs[i] = joint->node[0].body->pos[i]; + for (i=0; i<4; i++) ofs[i] -= joint->node[1].body->pos[i]; + dMULTIPLY1_331 (joint->offset,joint->node[0].body->R,ofs); + } + else { + // set joint->qrel to the transpose of the first body's q + joint->qrel[0] = joint->node[0].body->q[0]; + for (i=1; i<4; i++) joint->qrel[i] = -joint->node[0].body->q[i]; + for (i=0; i<4; i++) joint->offset[i] = joint->node[0].body->pos[i]; + } + for (i=0; i<4; i++) joint->qrelOrig[i] = joint->qrel[i]; + } +} + + +//if abs is true, the second anchor is set to abs coords +extern "C" void dJointSetFixedAnchor (dxJointFixed *joint, + dReal x, dReal y, dReal z, int abs) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not a fixed"); + if (abs) + setAnchorsAbs(joint,x,y,z,joint->anchor1,joint->anchor2); + else + setAnchors (joint,x,y,z,joint->anchor1,joint->anchor2); +} + +extern "C" void dJointSetFixedAnchorRotation (dxJointFixed *joint, const dQuaternion q) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not a fixed"); + //cout << "would set rot" << endl; +// dQuaternion q; +// dRtoQ(R,q); + +// for (int i=1; i<4; i++) q[i] = -q[i]; + //dQMultiply0(joint->qrel,joint->qrelOrig,q); + //dQuaternion q2; + //for (int i = 0; i < 4; i++) q2[i] = joint->qrelOrig[i]; + //dQMultiply0 (q2,joint->qrelOrig,joint->node[0].body->q); + dQMultiply0 (joint->qrel,joint->qrelOrig,q); + //for (int i = 0; i < 4; i++)joint->qrel[i] = q2[i]; +} + + +extern "C" void dJointSetFixedSpringMode (dxJointFixed *joint, + int linearEnable, + int angularEnable, + int customAnchorPointEnable) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not a fixed"); + joint->linearSpringMode = linearEnable; + joint->angularSpringMode = angularEnable; + joint->customAnchorPoint = customAnchorPointEnable; +} + +extern "C" void dJointSetFixedParam (dxJointFixed *joint, + int parameter, dReal value) +{ + dUASSERT(joint,"bad joint argument"); + dUASSERT(joint->vtable == &__dfixed_vtable,"joint is not fixed"); + switch (parameter) { + case dParamActive: + joint->active = value; + break; + case dParamLinearStiffness: + joint->linearStiffness = value; + break; + case dParamLinearDamping: + joint->linearDamping = value; + break; + case dParamAngularStiffness: + joint->angularStiffness = value; + break; + case dParamAngularDamping: + joint->angularDamping = value; + break; + } +} + + +dxJoint::Vtable __dfixed_vtable = { + sizeof(dxJointFixed), + (dxJoint::init_fn*) fixedInit, + (dxJoint::getInfo1_fn*) fixedGetInfo1, + (dxJoint::getInfo2_fn*) fixedGetInfo2, + dJointTypeFixed}; + +//**************************************************************************** +// null joint + +static void nullGetInfo1 (dxJointNull *j, dxJoint::Info1 *info) +{ + info->m = 0; + info->nub = 0; +} + + +static void nullGetInfo2 (dxJointNull *joint, dxJoint::Info2 *info) +{ + dDebug (0,"this should never get called"); +} + + +dxJoint::Vtable __dnull_vtable = { + sizeof(dxJointNull), + (dxJoint::init_fn*) 0, + (dxJoint::getInfo1_fn*) nullGetInfo1, + (dxJoint::getInfo2_fn*) nullGetInfo2, + dJointTypeNull}; diff --git a/src/external/open_dynamics_engine-ef/ode/ode_joint.h b/src/external/open_dynamics_engine-ef/ode/ode_joint.h new file mode 100644 index 00000000..9eec9a84 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_joint.h @@ -0,0 +1,295 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_JOINT_H_ +#define _ODE_JOINT_H_ + + +#include "ode/ode_objects_private.h" +#include "ode/ode_contact.h" +#include "ode/ode_obstack.h" + + +// joint flags +enum { + // if this flag is set, the joint was allocated in a joint group + dJOINT_INGROUP = 1, + + // if this flag is set, the joint was attached with arguments (0,body). + // our convention is to treat all attaches as (body,0), i.e. so node[0].body + // is always nonzero, so this flag records the fact that the arguments were + // swapped. + dJOINT_REVERSE = 2, + + // if this flag is set, the joint can not have just one body attached to it, + // it must have either zero or two bodies attached. + dJOINT_TWOBODIES = 4 +}; + + +// there are two of these nodes in the joint, one for each connection to a +// body. these are node of a linked list kept by each body of it's connecting +// joints. but note that the body pointer in each node points to the body that +// makes use of the *other* node, not this node. this trick makes it a bit +// easier to traverse the body/joint graph. + +struct dxJointNode { + dxJoint *joint; // pointer to enclosing dxJoint object + dxBody *body; // *other* body this joint is connected to + dxJointNode *next; // next node in body's list of connected joints +}; + + +// ericf temp +struct dxJointFixed; +struct dxJointContact; +struct dxJointAMotor; +struct JointFixedEF; + +struct dxJoint : public dObject { + // naming convention: the "first" body this is connected to is node[0].body, + // and the "second" body is node[1].body. if this joint is only connected + // to one body then the second body is 0. + + // info returned by getInfo1 function. the constraint dimension is m (<=6). + // i.e. that is the total number of rows in the jacobian. `nub' is the + // number of unbounded variables (which have lo,hi = -/+ infinity). + + struct Info1 { + int m,nub; + }; + + // info returned by getInfo2 function + + struct Info2 { + // integrator parameters: frames per second (1/stepsize), default error + // reduction parameter (0..1). + dReal fps,erp; + + // for the first and second body, pointers to two (linear and angular) + // n*3 jacobian sub matrices, stored by rows. these matrices will have + // been initialized to 0 on entry. if the second body is zero then the + // J2xx pointers may be 0. + dReal *J1l,*J1a,*J2l,*J2a; + + // elements to jump from one row to the next in J's + int rowskip; + + // right hand sides of the equation J*v = c + cfm * lambda. cfm is the + // "constraint force mixing" vector. c is set to zero on entry, cfm is + // set to a constant value (typically very small or zero) value on entry. + dReal *c,*cfm; + + // lo and hi limits for variables (set to -/+ infinity on entry). + dReal *lo,*hi; + + // findex vector for variables. see the LCP solver interface for a + // description of what this does. this is set to -1 on entry. + // note that the returned indexes are relative to the first index of + // the constraint. + int *findex; + }; + + // virtual function table: size of the joint structure, function pointers. + // we do it this way instead of using C++ virtual functions because + // sometimes we need to allocate joints ourself within a memory pool. + + typedef void init_fn (dxJoint *joint); + typedef void getInfo1_fn (dxJoint *joint, Info1 *info); + typedef void getInfo2_fn (dxJoint *joint, Info2 *info); + struct Vtable { + int size; + init_fn *init; + getInfo1_fn *getInfo1; + getInfo2_fn *getInfo2; + int typenum; // a dJointTypeXXX type number + }; + + Vtable *vtable; // virtual function table + int flags; // dJOINT_xxx flags + dxJointNode node[2]; // connections to bodies. node[1].body can be 0 + dJointFeedback *feedback; // optional feedback structure + dReal lambda[6]; // lambda generated by last step + + // TEMP ericf + #ifndef dNODEBUG + dxJointFixed *jFixed; + dxJointContact *jContact; + dxJointAMotor *jMotor; + JointFixedEF *jFixedEricf; + #endif +}; + + +// joint group. NOTE: any joints in the group that have their world destroyed +// will have their world pointer set to 0. + +struct dxJointGroup : public dBase { + int num; // number of joints on the stack + dObStack stack; // a stack of (possibly differently sized) dxJoint +}; // objects. + + +// common limit and motor information for a single joint axis of movement +struct dxJointLimitMotor { + dReal vel,fmax; // powered joint: velocity, max force + dReal lostop,histop; // joint limits, relative to initial position + dReal fudge_factor; // when powering away from joint limits + dReal normal_cfm; // cfm to use when not at a stop + dReal stop_erp,stop_cfm; // erp and cfm for when at joint limit + dReal bounce; // restitution factor + // variables used between getInfo1() and getInfo2() + int limit; // 0=free, 1=at lo limit, 2=at hi limit + dReal limit_err; // if at limit, amount over limit + + void init (dxWorld *); + void set (int num, dReal value); + dReal get (int num); + int testRotationalLimit (dReal angle); + int addLimot (dxJoint *joint, dxJoint::Info2 *info, int row, + dVector3 ax1, int rotational); +}; + + +// ball and socket + +struct dxJointBall : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dReal stiffness; + dReal damping; + int springMode; +}; +extern struct dxJoint::Vtable __dball_vtable; + + +// hinge + +struct dxJointHinge : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dVector3 axis1; // axis w.r.t first body + dVector3 axis2; // axis w.r.t second body + dQuaternion qrel; // initial relative rotation body1 -> body2 + dxJointLimitMotor limot; // limit and motor information +}; +extern struct dxJoint::Vtable __dhinge_vtable; + + +// universal + +struct dxJointUniversal : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dVector3 axis1; // axis w.r.t first body + dVector3 axis2; // axis w.r.t second body + dQuaternion qrel1; // initial relative rotation body1 -> virtual cross piece + dQuaternion qrel2; // initial relative rotation virtual cross piece -> body2 + dxJointLimitMotor limot1; // limit and motor information for axis1 + dxJointLimitMotor limot2; // limit and motor information for axis2 +}; +extern struct dxJoint::Vtable __duniversal_vtable; + + +// slider. if body2 is 0 then qrel is the absolute rotation of body1 and +// offset is the position of body1 center along axis1. + +struct dxJointSlider : public dxJoint { + dVector3 axis1; // axis w.r.t first body + dQuaternion qrel; // initial relative rotation body1 -> body2 + dVector3 offset; // point relative to body2 that should be + // aligned with body1 center along axis1 + dxJointLimitMotor limot; // limit and motor information +}; +extern struct dxJoint::Vtable __dslider_vtable; + + +// contact + +struct dxJointContact : public dxJoint { + int the_m; // number of rows computed by getInfo1 + dContact contact; +}; +extern struct dxJoint::Vtable __dcontact_vtable; + + +// hinge 2 + +struct dxJointHinge2 : public dxJoint { + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dVector3 axis1; // axis 1 w.r.t first body + dVector3 axis2; // axis 2 w.r.t second body + dReal c0,s0; // cos,sin of desired angle between axis 1,2 + dVector3 v1,v2; // angle ref vectors embedded in first body + dxJointLimitMotor limot1; // limit+motor info for axis 1 + dxJointLimitMotor limot2; // limit+motor info for axis 2 + dReal susp_erp,susp_cfm; // suspension parameters (erp,cfm) +}; +extern struct dxJoint::Vtable __dhinge2_vtable; + + +// angular motor + +struct dxJointAMotor : public dxJoint { + int num; // number of axes (0..3) + int mode; // a dAMotorXXX constant + int rel[3]; // what the axes are relative to (global,b1,b2) + dVector3 axis[3]; // three axes + dxJointLimitMotor limot[3]; // limit+motor info for axes + dReal angle[3]; // user-supplied angles for axes + // these vectors are used for calculating euler angles + dVector3 reference1; // original axis[2], relative to body 1 + dVector3 reference2; // original axis[0], relative to body 2 +}; +extern struct dxJoint::Vtable __damotor_vtable; + + +// fixed + +struct dxJointFixed : public dxJoint { + dQuaternion qrel; // relative rotation body1 -> body2 + dQuaternion qrelOrig; // initial relative rotation used for single body constrains that get modified + dVector3 offset; // relative offset between the bodies + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + dReal linearStiffness; //stiffness when in spring mode + dReal linearDamping; //damping when in spring mode + dReal angularStiffness; //stiffness when in spring mode + dReal angularDamping; //damping when in spring mode + bool active; //whether the joint works at all + bool linearSpringMode; + bool angularSpringMode; + bool customAnchorPoint; +}; +extern struct dxJoint::Vtable __dfixed_vtable; + + +// null joint, for testing only + +struct dxJointNull : public dxJoint { +}; +extern struct dxJoint::Vtable __dnull_vtable; + + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_lcp.cpp b/src/external/open_dynamics_engine-ef/ode/ode_lcp.cpp new file mode 100644 index 00000000..798f473b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_lcp.cpp @@ -0,0 +1,2020 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + + +THE ALGORITHM +------------- + +solve A*x = b+w, with x and w subject to certain LCP conditions. +each x(i),w(i) must lie on one of the three line segments in the following +diagram. each line segment corresponds to one index set : + + w(i) + /|\ | : + | | : + | |i in N : + w>0 | |state[i]=0 : + | | : + | | : i in C + w=0 + +-----------------------+ + | : | + | : | + w<0 | : |i in N + | : |state[i]=1 + | : | + | : | + +-------|-----------|-----------|----------> x(i) + lo 0 hi + +the Dantzig algorithm proceeds as follows: + for i=1:n + * if (x(i),w(i)) is not on the line, push x(i) and w(i) positive or + negative towards the line. as this is done, the other (x(j),w(j)) + for j= 0. this makes the algorithm a bit +simpler, because the starting point for x(i),w(i) is always on the dotted +line x=0 and x will only ever increase in one direction, so it can only hit +two out of the three line segments. + + +NOTES +----- + +this is an implementation of "lcp_dantzig2_ldlt.m" and "lcp_dantzig_lohi.m". +the implementation is split into an LCP problem object (dLCP) and an LCP +driver function. most optimization occurs in the dLCP object. + +a naive implementation of the algorithm requires either a lot of data motion +or a lot of permutation-array lookup, because we are constantly re-ordering +rows and columns. to avoid this and make a more optimized algorithm, a +non-trivial data structure is used to represent the matrix A (this is +implemented in the fast version of the dLCP object). + +during execution of this algorithm, some indexes in A are clamped (set C), +some are non-clamped (set N), and some are "don't care" (where x=0). +A,x,b,w (and other problem vectors) are permuted such that the clamped +indexes are first, the unclamped indexes are next, and the don't-care +indexes are last. this permutation is recorded in the array `p'. +initially p = 0..n-1, and as the rows and columns of A,x,b,w are swapped, +the corresponding elements of p are swapped. + +because the C and N elements are grouped together in the rows of A, we can do +lots of work with a fast dot product function. if A,x,etc were not permuted +and we only had a permutation array, then those dot products would be much +slower as we would have a permutation array lookup in some inner loops. + +A is accessed through an array of row pointers, so that element (i,j) of the +permuted matrix is A[i][j]. this makes row swapping fast. for column swapping +we still have to actually move the data. + +during execution of this algorithm we maintain an L*D*L' factorization of +the clamped submatrix of A (call it `AC') which is the top left nC*nC +submatrix of A. there are two ways we could arrange the rows/columns in AC. + +(1) AC is always permuted such that L*D*L' = AC. this causes a problem + when a row/column is removed from C, because then all the rows/columns of A + between the deleted index and the end of C need to be rotated downward. + this results in a lot of data motion and slows things down. +(2) L*D*L' is actually a factorization of a *permutation* of AC (which is + itself a permutation of the underlying A). this is what we do - the + permutation is recorded in the vector C. call this permutation A[C,C]. + when a row/column is removed from C, all we have to do is swap two + rows/columns and manipulate C. + +*/ + +#include "ode/ode_common.h" +#include "ode/ode_lcp.h" +#include "ode/ode_matrix.h" +#include "ode/ode_misc.h" +#include "ode/ode_mat.h" // for testing +#include "ode/ode_timer.h" // for testing + +//*************************************************************************** +// code generation parameters + +// LCP debugging (mosty for fast dLCP) - this slows things down a lot +//#define DEBUG_LCP + +//#define dLCP_SLOW // use slow dLCP object +#define dLCP_FAST // use fast dLCP object + +// option 1 : matrix row pointers (less data copying) +#define ROWPTRS +#define ATYPE dReal ** +#define AROW(i) (A[i]) + +// option 2 : no matrix row pointers (slightly faster inner loops) +//#define NOROWPTRS +//#define ATYPE dReal * +//#define AROW(i) (A+(i)*nskip) + +// use protected, non-stack memory allocation system + +#ifdef dUSE_MALLOC_FOR_ALLOCA +extern unsigned int dMemoryFlag; + +#define ALLOCA(t,v,s) t* v = (t*) malloc(s) +#define UNALLOCA(t) free(t) + +#else + +#define ALLOCA(t,v,s) t* v =(t*)dALLOCA16(s) +#define UNALLOCA(t) /* nothing */ + +#endif + +//#define dDot myDot +#define NUB_OPTIMIZATIONS + +//*************************************************************************** + +// an alternative inline dot product, for speed comparisons + +#if 0 +static inline dReal myDot (dReal *a, dReal *b, int n) +{ + dReal sum=0; + while (n > 0) { + sum += (*a) * (*b); + a++; + b++; + n--; + } + return sum; +} +#endif // 0 + + +// swap row/column i1 with i2 in the n*n matrix A. the leading dimension of +// A is nskip. this only references and swaps the lower triangle. +// if `do_fast_row_swaps' is nonzero and row pointers are being used, then +// rows will be swapped by exchanging row pointers. otherwise the data will +// be copied. + +static void swapRowsAndCols (ATYPE A, int n, int i1, int i2, int nskip, + int do_fast_row_swaps) +{ + int i; + dAASSERT (A && n > 0 && i1 >= 0 && i2 >= 0 && i1 < n && i2 < n && + nskip >= n && i1 < i2); + +# ifdef ROWPTRS + for (i=i1+1; i 0) { + memcpy (tmprow,A+i1*nskip,i1*sizeof(dReal)); + memcpy (A+i1*nskip,A+i2*nskip,i1*sizeof(dReal)); + memcpy (A+i2*nskip,tmprow,i1*sizeof(dReal)); + } + for (i=i1+1; i0 && i1 >=0 && i2 >= 0 && i1 < n && i2 < n && nskip >= n && + i1 <= i2); + if (i1==i2) return; + swapRowsAndCols (A,n,i1,i2,nskip,do_fast_row_swaps); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) + return; +#endif + tmp = x[i1]; + x[i1] = x[i2]; + x[i2] = tmp; + tmp = b[i1]; + b[i1] = b[i2]; + b[i2] = tmp; + tmp = w[i1]; + w[i1] = w[i2]; + w[i2] = tmp; + tmp = lo[i1]; + lo[i1] = lo[i2]; + lo[i2] = tmp; + tmp = hi[i1]; + hi[i1] = hi[i2]; + hi[i2] = tmp; + tmpi = p[i1]; + p[i1] = p[i2]; + p[i2] = tmpi; + tmpi = state[i1]; + state[i1] = state[i2]; + state[i2] = tmpi; + if (findex) { + tmpi = findex[i1]; + findex[i1] = findex[i2]; + findex[i2] = tmpi; + } +} + + +// for debugging - check that L,d is the factorization of A[C,C]. +// A[C,C] has size nC*nC and leading dimension nskip. +// L has size nC*nC and leading dimension nskip. +// d has size nC. + +#ifdef DEBUG_LCP + +static void checkFactorization (ATYPE A, dReal *_L, dReal *_d, + int nC, int *C, int nskip) +{ + int i,j; + if (nC==0) return; + + // get A1=A, copy the lower triangle to the upper triangle, get A2=A[C,C] + dMatrix A1 (nC,nC); + for (i=0; i 1e-8) + dDebug (0,"L*D*L' check, maximum difference = %.6e\n",diff); +} + +#endif + + +// for debugging + +#ifdef DEBUG_LCP + +static void checkPermutations (int i, int n, int nC, int nN, int *p, int *C) +{ + int j,k; + dIASSERT (nC>=0 && nN>=0 && (nC+nN)==i && i < n); + for (k=0; k= 0 && p[k] < i); + for (k=i; k C,N; // index sets + int last_i_for_solve1; // last i value given to solve1 + + dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, + dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, + dReal *_Dell, dReal *_ell, dReal *_tmp, + int *_state, int *_findex, int *_p, int *_C, dReal **Arows); + // the constructor is given an initial problem description (A,x,b,w) and + // space for other working data (which the caller may allocate on the stack). + // some of this data is specific to the fast dLCP implementation. + // the matrices A and L have size n*n, vectors have size n*1. + // A represents a symmetric matrix but only the lower triangle is valid. + // `nub' is the number of unbounded indexes at the start. all the indexes + // 0..nub-1 will be put into C. + + ~dLCP(); + + int getNub() { return nub; } + // return the value of `nub'. the constructor may want to change it, + // so the caller should find out its new value. + + // transfer functions: transfer index i to the given set (C or N). indexes + // less than `nub' can never be given. A,x,b,w,etc may be permuted by these + // functions, the caller must be robust to this. + + void transfer_i_to_C (int i); + // this assumes C and N span 1:i-1. this also assumes that solve1() has + // been recently called for the same i without any other transfer + // functions in between (thereby allowing some data reuse for the fast + // implementation). + void transfer_i_to_N (int i); + // this assumes C and N span 1:i-1. + void transfer_i_from_N_to_C (int i); + void transfer_i_from_C_to_N (int i); + + int numC(); + int numN(); + // return the number of indexes in set C/N + + int indexC (int i); + int indexN (int i); + // return index i in set C/N. + + // accessor and arithmetic functions. Aij translates as A(i,j), etc. + // make sure that only the lower triangle of A is ever referenced. + + dReal Aii (int i); + dReal AiC_times_qC (int i, dReal *q); + dReal AiN_times_qN (int i, dReal *q); // for all Nj + void pN_equals_ANC_times_qC (dReal *p, dReal *q); // for all Nj + void pN_plusequals_ANi (dReal *p, int i, int sign=1); + // for all Nj. sign = +1,-1. assumes i > maximum index in N. + void pC_plusequals_s_times_qC (dReal *p, dReal s, dReal *q); + void pN_plusequals_s_times_qN (dReal *p, dReal s, dReal *q); // for all Nj + void solve1 (dReal *a, int i, int dir=1, int only_transfer=0); + // get a(C) = - dir * A(C,C) \ A(C,i). dir must be +/- 1. + // the fast version of this function computes some data that is needed by + // transfer_i_to_C(). if only_transfer is nonzero then this function + // *only* computes that data, it does not set a(C). + + void unpermute(); + // call this at the end of the LCP function. if the x/w values have been + // permuted then this will unscramble them. +}; + + +dLCP::dLCP (int _n, int _nub, dReal *_Adata, dReal *_x, dReal *_b, dReal *_w, + dReal *_lo, dReal *_hi, dReal *_L, dReal *_d, + dReal *_Dell, dReal *_ell, dReal *_tmp, + int *_state, int *_findex, int *_p, int *_C, dReal **Arows) +{ + dUASSERT (_findex==0,"slow dLCP object does not support findex array"); + + n = _n; + nub = _nub; + Adata = _Adata; + A = 0; + x = _x; + b = _b; + w = _w; + lo = _lo; + hi = _hi; + nskip = dPAD(n); + dSetZero (x,n); + last_i_for_solve1 = -1; + + int i,j; + C.setSize (n); + N.setSize (n); + for (int i=0; i0, put all indexes 0..nub-1 into C and solve for x + if (nub > 0) { + for (i=0; i= i) dDebug (0,"N assumption violated"); + if (sign > 0) { + for (k=0; k 0) { + for (ii=0; ii nub + if (nub < n) { + for (k=0; k<100; k++) { + int i1,i2; + do { + i1 = dRandInt(n-nub)+nub; + i2 = dRandInt(n-nub)+nub; + } + while (i1 > i2); + //printf ("--> %d %d\n",i1,i2); + swapProblem (A,x,b,w,lo,hi,p,state,findex,n,i1,i2,nskip,0); + } + } + */ + + // permute the problem so that *all* the unbounded variables are at the + // start, i.e. look for unbounded variables not included in `nub'. we can + // potentially push up `nub' this way and get a bigger initial factorization. + // note that when we swap rows/cols here we must not just swap row pointers, + // as the initial factorization relies on the data being all in one chunk. + // variables that have findex >= 0 are *not* considered to be unbounded even + // if lo=-inf and hi=inf - this is because these limits may change during the + // solution process. + + for (k=nub; k= 0) continue; + if (lo[k]==-dInfinity && hi[k]==dInfinity) { + swapProblem (A,x,b,w,lo,hi,p,state,findex,n,nub,k,nskip,0); + nub++; + } + } + + // if there are unbounded variables at the start, factorize A up to that + // point and solve for x. this puts all indexes 0..nub-1 into C. + if (nub > 0) { + for (k=0; k nub such that all findex variables are at the end + if (findex) { + int num_at_end = 0; + for (k=n-1; k >= nub; k--) { + if (findex[k] >= 0) { + swapProblem (A,x,b,w,lo,hi,p,state,findex,n,k,n-1-num_at_end,nskip,1); + num_at_end++; + } + } + } + + // print info about indexes + /* + for (k=0; k 0) { + // ell,Dell were computed by solve1(). note, ell = D \ L1solve (L,A(i,C)) + for (j=0; j 0) { + dReal *aptr = AROW(i); +# ifdef NUB_OPTIMIZATIONS + // if nub>0, initial part of aptr unpermuted + for (j=0; j 0) { + for (int i=0; i 0) { + dReal *aptr = AROW(i); +# ifdef NUB_OPTIMIZATIONS + // if nub>0, initial part of aptr[] is guaranteed unpermuted + for (j=0; j 0) { + for (j=0; j0 && A && x && b && w && nub == 0); + + int i,k; + int nskip = dPAD(n); + ALLOCA (dReal,L,n*nskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (L == NULL) { + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,d,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (d == NULL) { + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,delta_x,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (delta_x == NULL) { + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,delta_w,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (delta_w == NULL) { + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,Dell,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (Dell == NULL) { + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,ell,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (ell == NULL) { + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,tmp,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (tmp == NULL) { + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal*,Arows,n*sizeof(dReal*)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (Arows == NULL) { + UNALLOCA(tmp); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (int,p,n*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (p == NULL) { + UNALLOCA(Arows); + UNALLOCA(tmp); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (int,C,n*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (C == NULL) { + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(tmp); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (int,dummy,n*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (dummy == NULL) { + UNALLOCA(C); + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(tmp); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + + dLCP lcp (n,0,A,x,b,w,tmp,tmp,L,d,Dell,ell,tmp,dummy,dummy,p,C,Arows); + nub = lcp.getNub(); + + for (i=0; i= 0) { + lcp.transfer_i_to_N (i); + } + else { + for (;;) { + // compute: delta_x(C) = -A(C,C)\A(C,i) + dSetZero (delta_x,n); + lcp.solve1 (delta_x,i); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { + UNALLOCA(dummy); + UNALLOCA(C); + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(tmp); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + return; + } +#endif + delta_x[i] = 1; + + // compute: delta_w = A*delta_x + dSetZero (delta_w,n); + lcp.pN_equals_ANC_times_qC (delta_w,delta_x); + lcp.pN_plusequals_ANi (delta_w,i); + delta_w[i] = lcp.AiC_times_qC (i,delta_x) + lcp.Aii(i); + + // find index to switch + int si = i; // si = switch index + int si_in_N = 0; // set to 1 if si in N + dReal s = -w[i]/delta_w[i]; + + if (s <= 0) { + dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s); + if (i < (n-1)) { + dSetZero (x+i,n-i); + dSetZero (w+i,n-i); + } + goto done; + } + + for (k=0; k < lcp.numN(); k++) { + if (delta_w[lcp.indexN(k)] < 0) { + dReal s2 = -w[lcp.indexN(k)] / delta_w[lcp.indexN(k)]; + if (s2 < s) { + s = s2; + si = lcp.indexN(k); + si_in_N = 1; + } + } + } + for (k=0; k < lcp.numC(); k++) { + if (delta_x[lcp.indexC(k)] < 0) { + dReal s2 = -x[lcp.indexC(k)] / delta_x[lcp.indexC(k)]; + if (s2 < s) { + s = s2; + si = lcp.indexC(k); + si_in_N = 0; + } + } + } + + // apply x = x + s * delta_x + lcp.pC_plusequals_s_times_qC (x,s,delta_x); + x[i] += s; + lcp.pN_plusequals_s_times_qN (w,s,delta_w); + w[i] += s * delta_w[i]; + + // switch indexes between sets if necessary + if (si==i) { + w[i] = 0; + lcp.transfer_i_to_C (i); + break; + } + if (si_in_N) { + w[si] = 0; + lcp.transfer_i_from_N_to_C (si); + } + else { + x[si] = 0; + lcp.transfer_i_from_C_to_N (si); + } + } + } + } + + done: + lcp.unpermute(); + + UNALLOCA (L); + UNALLOCA (d); + UNALLOCA (delta_x); + UNALLOCA (delta_w); + UNALLOCA (Dell); + UNALLOCA (ell); + UNALLOCA (tmp); + UNALLOCA (Arows); + UNALLOCA (p); + UNALLOCA (C); + UNALLOCA (dummy); +} + +//*************************************************************************** +// an optimized Dantzig LCP driver routine for the lo-hi LCP problem. + +void dSolveLCP (int n, dReal *A, dReal *x, dReal *b, + dReal *w, int nub, dReal *lo, dReal *hi, int *findex) +{ + dAASSERT (n>0 && A && x && b && w && lo && hi && nub >= 0 && nub <= n); + + int i,k,hit_first_friction_index = 0; + int nskip = dPAD(n); + + // if all the variables are unbounded then we can just factor, solve, + // and return + if (nub >= n) { + dFactorLDLT (A,w,n,nskip); // use w for d + dSolveLDLT (A,w,b,n,nskip); + memcpy (x,b,n*sizeof(dReal)); + dSetZero (w,n); + + return; + } +# ifndef dNODEBUG + // check restrictions on lo and hi + for (k=0; k= 0); +# endif + ALLOCA (dReal,L,n*nskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (L == NULL) { + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,d,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (d == NULL) { + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,delta_x,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (delta_x == NULL) { + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,delta_w,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (delta_w == NULL) { + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,Dell,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (Dell == NULL) { + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,ell,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (ell == NULL) { + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal*,Arows,n*sizeof(dReal*)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (Arows == NULL) { + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (int,p,n*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (p == NULL) { + UNALLOCA(Arows); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (int,C,n*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (C == NULL) { + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + int dir; + dReal dirf; + + // for i in N, state[i] is 0 if x(i)==lo(i) or 1 if x(i)==hi(i) + ALLOCA (int,state,n*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (state == NULL) { + UNALLOCA(C); + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + // create LCP object. note that tmp is set to delta_w to save space, this + // optimization relies on knowledge of how tmp is used, so be careful! + dLCP *lcp=new dLCP(n,nub,A,x,b,w,lo,hi,L,d,Dell,ell,delta_w,state,findex,p,C,Arows); + nub = lcp->getNub(); + + // loop over all indexes nub..n-1. for index i, if x(i),w(i) satisfy the + // LCP conditions then i is added to the appropriate index set. otherwise + // x(i),w(i) is driven either +ve or -ve to force it to the valid region. + // as we drive x(i), x(C) is also adjusted to keep w(C) at zero. + // while driving x(i) we maintain the LCP conditions on the other variables + // 0..i-1. we do this by watching out for other x(i),w(i) values going + // outside the valid region, and then switching them between index sets + // when that happens. + + for (i=nub; i= 0) { + // un-permute x into delta_w, which is not being used at the moment + for (k=0; kAiC_times_qC (i,x) + lcp->AiN_times_qN (i,x) - b[i]; + + // if lo=hi=0 (which can happen for tangential friction when normals are + // 0) then the index will be assigned to set N with some state. however, + // set C's line has zero size, so the index will always remain in set N. + // with the "normal" switching logic, if w changed sign then the index + // would have to switch to set C and then back to set N with an inverted + // state. this is pointless, and also computationally expensive. to + // prevent this from happening, we use the rule that indexes with lo=hi=0 + // will never be checked for set changes. this means that the state for + // these indexes may be incorrect, but that doesn't matter. + + // see if x(i),w(i) is in a valid region + if (lo[i]==0 && w[i] >= 0) { + lcp->transfer_i_to_N (i); + state[i] = 0; + } + else if (hi[i]==0 && w[i] <= 0) { + lcp->transfer_i_to_N (i); + state[i] = 1; + } + else if (w[i]==0) { + // this is a degenerate case. by the time we get to this test we know + // that lo != 0, which means that lo < 0 as lo is not allowed to be +ve, + // and similarly that hi > 0. this means that the line segment + // corresponding to set C is at least finite in extent, and we are on it. + // NOTE: we must call lcp->solve1() before lcp->transfer_i_to_C() + lcp->solve1 (delta_x,i,0,1); + +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { + UNALLOCA(state); + UNALLOCA(C); + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + return; + } +#endif + + lcp->transfer_i_to_C (i); + } + else { + // we must push x(i) and w(i) + for (;;) { + // find direction to push on x(i) + if (w[i] <= 0) { + dir = 1; + dirf = REAL(1.0); + } + else { + dir = -1; + dirf = REAL(-1.0); + } + + // compute: delta_x(C) = -dir*A(C,C)\A(C,i) + lcp->solve1 (delta_x,i,dir); + +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { + UNALLOCA(state); + UNALLOCA(C); + UNALLOCA(p); + UNALLOCA(Arows); + UNALLOCA(ell); + UNALLOCA(Dell); + UNALLOCA(delta_w); + UNALLOCA(delta_x); + UNALLOCA(d); + UNALLOCA(L); + return; + } +#endif + + // note that delta_x[i] = dirf, but we wont bother to set it + + // compute: delta_w = A*delta_x ... note we only care about + // delta_w(N) and delta_w(i), the rest is ignored + lcp->pN_equals_ANC_times_qC (delta_w,delta_x); + lcp->pN_plusequals_ANi (delta_w,i,dir); + delta_w[i] = lcp->AiC_times_qC (i,delta_x) + lcp->Aii(i)*dirf; + + // find largest step we can take (size=s), either to drive x(i),w(i) + // to the valid LCP region or to drive an already-valid variable + // outside the valid region. + + int cmd = 1; // index switching command + int si = 0; // si = index to switch if cmd>3 + dReal s = -w[i]/delta_w[i]; + if (dir > 0) { + if (hi[i] < dInfinity) { + dReal s2 = (hi[i]-x[i])/dirf; // step to x(i)=hi(i) + if (s2 < s) { + s = s2; + cmd = 3; + } + } + } + else { + if (lo[i] > -dInfinity) { + dReal s2 = (lo[i]-x[i])/dirf; // step to x(i)=lo(i) + if (s2 < s) { + s = s2; + cmd = 2; + } + } + } + + for (k=0; k < lcp->numN(); k++) { + if ((state[lcp->indexN(k)]==0 && delta_w[lcp->indexN(k)] < 0) || + (state[lcp->indexN(k)]!=0 && delta_w[lcp->indexN(k)] > 0)) { + // don't bother checking if lo=hi=0 + if (lo[lcp->indexN(k)] == 0 && hi[lcp->indexN(k)] == 0) continue; + dReal s2 = -w[lcp->indexN(k)] / delta_w[lcp->indexN(k)]; + if (s2 < s) { + s = s2; + cmd = 4; + si = lcp->indexN(k); + } + } + } + + for (k=nub; k < lcp->numC(); k++) { + if (delta_x[lcp->indexC(k)] < 0 && lo[lcp->indexC(k)] > -dInfinity) { + dReal s2 = (lo[lcp->indexC(k)]-x[lcp->indexC(k)]) / + delta_x[lcp->indexC(k)]; + if (s2 < s) { + s = s2; + cmd = 5; + si = lcp->indexC(k); + } + } + if (delta_x[lcp->indexC(k)] > 0 && hi[lcp->indexC(k)] < dInfinity) { + dReal s2 = (hi[lcp->indexC(k)]-x[lcp->indexC(k)]) / + delta_x[lcp->indexC(k)]; + if (s2 < s) { + s = s2; + cmd = 6; + si = lcp->indexC(k); + } + } + } + + //static char* cmdstring[8] = {0,"->C","->NL","->NH","N->C", + // "C->NL","C->NH"}; + //printf ("cmd=%d (%s), si=%d\n",cmd,cmdstring[cmd],(cmd>3) ? si : i); + + // if s <= 0 then we've got a problem. if we just keep going then + // we're going to get stuck in an infinite loop. instead, just cross + // our fingers and exit with the current solution. + if (s <= 0) { + dMessage (d_ERR_LCP, "LCP internal error, s <= 0 (s=%.4e)",s); + if (i < (n-1)) { + dSetZero (x+i,n-i); + dSetZero (w+i,n-i); + } + goto done; + } + + // apply x = x + s * delta_x + lcp->pC_plusequals_s_times_qC (x,s,delta_x); + x[i] += s * dirf; + + // apply w = w + s * delta_w + lcp->pN_plusequals_s_times_qN (w,s,delta_w); + w[i] += s * delta_w[i]; + + // switch indexes between sets if necessary + switch (cmd) { + case 1: // done + w[i] = 0; + lcp->transfer_i_to_C (i); + break; + case 2: // done + x[i] = lo[i]; + state[i] = 0; + lcp->transfer_i_to_N (i); + break; + case 3: // done + x[i] = hi[i]; + state[i] = 1; + lcp->transfer_i_to_N (i); + break; + case 4: // keep going + w[si] = 0; + lcp->transfer_i_from_N_to_C (si); + break; + case 5: // keep going + x[si] = lo[si]; + state[si] = 0; + lcp->transfer_i_from_C_to_N (si); + break; + case 6: // keep going + x[si] = hi[si]; + state[si] = 1; + lcp->transfer_i_from_C_to_N (si); + break; + } + + if (cmd <= 3) break; + } + } + } + + done: + lcp->unpermute(); + delete lcp; + + UNALLOCA (L); + UNALLOCA (d); + UNALLOCA (delta_x); + UNALLOCA (delta_w); + UNALLOCA (Dell); + UNALLOCA (ell); + UNALLOCA (Arows); + UNALLOCA (p); + UNALLOCA (C); + UNALLOCA (state); +} + +//*************************************************************************** +// accuracy and timing test + +extern "C" void dTestSolveLCP() +{ + int n = 100; + int i,nskip = dPAD(n); + const dReal tol = REAL(1e-9); + printf ("dTestSolveLCP()\n"); + + ALLOCA (dReal,A,n*nskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (A == NULL) { + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,x,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (x == NULL) { + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,b,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (b == NULL) { + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,w,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (w == NULL) { + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,lo,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (lo == NULL) { + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,hi,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (hi == NULL) { + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + ALLOCA (dReal,A2,n*nskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (A2 == NULL) { + UNALLOCA (hi); + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,b2,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (b2 == NULL) { + UNALLOCA (A2); + UNALLOCA (hi); + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,lo2,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (lo2 == NULL) { + UNALLOCA (b2); + UNALLOCA (A2); + UNALLOCA (hi); + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,hi2,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (hi2 == NULL) { + UNALLOCA (lo2); + UNALLOCA (b2); + UNALLOCA (A2); + UNALLOCA (hi); + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,tmp1,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (tmp1 == NULL) { + UNALLOCA (hi2); + UNALLOCA (lo2); + UNALLOCA (b2); + UNALLOCA (A2); + UNALLOCA (hi); + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA (dReal,tmp2,n*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (tmp2 == NULL) { + UNALLOCA (tmp1); + UNALLOCA (hi2); + UNALLOCA (lo2); + UNALLOCA (b2); + UNALLOCA (A2); + UNALLOCA (hi); + UNALLOCA (lo); + UNALLOCA (w); + UNALLOCA (b); + UNALLOCA (x); + UNALLOCA (A); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + double total_time = 0; + for (int count=0; count < 1000; count++) { + + // form (A,b) = a random positive definite LCP problem + dMakeRandomMatrix (A2,n,n,1.0); + dMultiply2 (A,A2,A2,n,n,n); + dMakeRandomMatrix (x,n,1,1.0); + dMultiply0 (b,A,x,n,n,1); + for (i=0; i tol ? "FAILED" : "passed"); + if (diff > tol) dDebug (0,"A*x = b+w, maximum difference = %.6e",diff); + int n1=0,n2=0,n3=0; + for (i=0; i= 0) { + n1++; // ok + } + else if (x[i]==hi[i] && w[i] <= 0) { + n2++; // ok + } + else if (x[i] >= lo[i] && x[i] <= hi[i] && w[i] == 0) { + n3++; // ok + } + else { + dDebug (0,"FAILED: i=%d x=%.4e w=%.4e lo=%.4e hi=%.4e",i, + x[i],w[i],lo[i],hi[i]); + } + } + + // pacifier + printf ("passed: NL=%3d NH=%3d C=%3d ",n1,n2,n3); + printf ("time=%10.3f ms avg=%10.4f\n",time * 1000.0,average); + } + + UNALLOCA (A); + UNALLOCA (x); + UNALLOCA (b); + UNALLOCA (w); + UNALLOCA (lo); + UNALLOCA (hi); + UNALLOCA (A2); + UNALLOCA (b2); + UNALLOCA (lo2); + UNALLOCA (hi2); + UNALLOCA (tmp1); + UNALLOCA (tmp2); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_lcp.h b/src/external/open_dynamics_engine-ef/ode/ode_lcp.h new file mode 100644 index 00000000..484902c1 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_lcp.h @@ -0,0 +1,58 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +given (A,b,lo,hi), solve the LCP problem: A*x = b+w, where each x(i),w(i) +satisfies one of + (1) x = lo, w >= 0 + (2) x = hi, w <= 0 + (3) lo < x < hi, w = 0 +A is a matrix of dimension n*n, everything else is a vector of size n*1. +lo and hi can be +/- dInfinity as needed. the first `nub' variables are +unbounded, i.e. hi and lo are assumed to be +/- dInfinity. + +we restrict lo(i) <= 0 and hi(i) >= 0. + +the original data (A,b) may be modified by this function. + +if the `findex' (friction index) parameter is nonzero, it points to an array +of index values. in this case constraints that have findex[i] >= 0 are +special. all non-special constraints are solved for, then the lo and hi values +for the special constraints are set: + hi[i] = abs( hi[i] * x[findex[i]] ) + lo[i] = -hi[i] +and the solution continues. this mechanism allows a friction approximation +to be implemented. the first `nub' variables are assumed to have findex < 0. + +*/ + + +#ifndef _ODE_LCP_H_ +#define _ODE_LCP_H_ + + +void dSolveLCP (int n, dReal *A, dReal *x, dReal *b, dReal *w, + int nub, dReal *lo, dReal *hi, int *findex); + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_mass.cpp b/src/external/open_dynamics_engine-ef/ode/ode_mass.cpp new file mode 100644 index 00000000..36508b24 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_mass.cpp @@ -0,0 +1,313 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_config.h" +#include "ode/ode_mass.h" +#include "ode/ode_math.h" +#include "ode/ode_matrix.h" + + +#define _I(i,j) I[(i)*4+(j)] + + +// return 1 if ok, 0 if bad + +static int checkMass (dMass *m) +{ + int i; + + if (m->mass <= 0) { + dDEBUGMSG ("mass must be > 0"); + return 0; + } + if (!dIsPositiveDefinite (m->I,3)) { + dDEBUGMSG ("inertia must be positive definite"); + return 0; + } + + // verify that the center of mass position is consistent with the mass + // and inertia matrix. this is done by checking that the inertia around + // the center of mass is also positive definite. from the comment in + // dMassTranslate(), if the body is translated so that its center of mass + // is at the point of reference, then the new inertia is: + // I + mass*crossmat(c)^2 + // note that requiring this to be positive definite is exactly equivalent + // to requiring that the spatial inertia matrix + // [ mass*eye(3,3) M*crossmat(c)^T ] + // [ M*crossmat(c) I ] + // is positive definite, given that I is PD and mass>0. see the theorem + // about partitioned PD matrices for proof. + + dMatrix3 I2,chat; + dSetZero (chat,12); + dCROSSMAT (chat,m->c,4,+,-); + dMULTIPLY0_333 (I2,chat,chat); + for (i=0; i<3; i++) I2[i] = m->I[i] + m->mass*I2[i]; + for (i=4; i<7; i++) I2[i] = m->I[i] + m->mass*I2[i]; + for (i=8; i<11; i++) I2[i] = m->I[i] + m->mass*I2[i]; + if (!dIsPositiveDefinite (I2,3)) { + dDEBUGMSG ("center of mass inconsistent with mass parameters"); + return 0; + } + return 1; +} + + +void dMassSetZero (dMass *m) +{ + dAASSERT (m); + m->mass = REAL(0.0); + dSetZero (m->c,sizeof(m->c) / sizeof(dReal)); + dSetZero (m->I,sizeof(m->I) / sizeof(dReal)); +} + + +void dMassSetParameters (dMass *m, dReal themass, + dReal cgx, dReal cgy, dReal cgz, + dReal I11, dReal I22, dReal I33, + dReal I12, dReal I13, dReal I23) +{ + dAASSERT (m); + dMassSetZero (m); + m->mass = themass; + m->c[0] = cgx; + m->c[1] = cgy; + m->c[2] = cgz; + m->_I(0,0) = I11; + m->_I(1,1) = I22; + m->_I(2,2) = I33; + m->_I(0,1) = I12; + m->_I(0,2) = I13; + m->_I(1,2) = I23; + m->_I(1,0) = I12; + m->_I(2,0) = I13; + m->_I(2,1) = I23; + checkMass (m); +} + + +void dMassSetSphere (dMass *m, dReal density, dReal radius) +{ + dMassSetSphereTotal (m, (REAL(4.0)/REAL(3.0)) * M_PI * + radius*radius*radius * density, radius); +} + + +void dMassSetSphereTotal (dMass *m, dReal total_mass, dReal radius) +{ + dAASSERT (m); + dMassSetZero (m); + m->mass = total_mass; + dReal II = REAL(0.4) * total_mass * radius*radius; + m->_I(0,0) = II; + m->_I(1,1) = II; + m->_I(2,2) = II; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassSetCappedCylinder (dMass *m, dReal density, int direction, + dReal radius, dReal length) +{ + dReal M1,M2,Ia,Ib; + dAASSERT (m); + dUASSERT (direction >= 1 && direction <= 3,"bad direction number"); + dMassSetZero (m); + M1 = M_PI*radius*radius*length*density; // cylinder mass + M2 = (REAL(4.0)/REAL(3.0))*M_PI*radius*radius*radius*density; // total cap mass + m->mass = M1+M2; + Ia = M1*(REAL(0.25)*radius*radius + (REAL(1.0)/REAL(12.0))*length*length) + + M2*(REAL(0.4)*radius*radius + REAL(0.375)*radius*length + REAL(0.25)*length*length); + Ib = (M1*REAL(0.5) + M2*REAL(0.4))*radius*radius; + m->_I(0,0) = Ia; + m->_I(1,1) = Ia; + m->_I(2,2) = Ia; + m->_I(direction-1,direction-1) = Ib; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassSetCappedCylinderTotal (dMass *m, dReal total_mass, int direction, + dReal a, dReal b) +{ + dMassSetCappedCylinder (m, 1.0, direction, a, b); + dMassAdjust (m, total_mass); +} + + +void dMassSetCylinder (dMass *m, dReal density, int direction, + dReal radius, dReal length) +{ + dMassSetCylinderTotal (m, M_PI*radius*radius*length*density, + direction, radius, length); +} + +void dMassSetCylinderTotal (dMass *m, dReal total_mass, int direction, + dReal radius, dReal length) +{ + dReal r2,I; + dAASSERT (m); + dMassSetZero (m); + r2 = radius*radius; + m->mass = total_mass; + I = total_mass*(REAL(0.25)*r2 + (REAL(1.0)/REAL(12.0))*length*length); + m->_I(0,0) = I; + m->_I(1,1) = I; + m->_I(2,2) = I; + m->_I(direction-1,direction-1) = total_mass*REAL(0.5)*r2; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassSetBox (dMass *m, dReal density, + dReal lx, dReal ly, dReal lz) +{ + dMassSetBoxTotal (m, lx*ly*lz*density, lx, ly, lz); +} + + +void dMassSetBoxTotal (dMass *m, dReal total_mass, + dReal lx, dReal ly, dReal lz) +{ + dAASSERT (m); + dMassSetZero (m); + m->mass = total_mass; + m->_I(0,0) = total_mass/REAL(12.0) * (ly*ly + lz*lz); + m->_I(1,1) = total_mass/REAL(12.0) * (lx*lx + lz*lz); + m->_I(2,2) = total_mass/REAL(12.0) * (lx*lx + ly*ly); + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassAdjust (dMass *m, dReal newmass) +{ + dAASSERT (m); + dReal scale = newmass / m->mass; + m->mass = newmass; + for (int i=0; i<3; i++) for (int j=0; j<3; j++) m->_I(i,j) *= scale; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassTranslate (dMass *m, dReal x, dReal y, dReal z) +{ + // if the body is translated by `a' relative to its point of reference, + // the new inertia about the point of reference is: + // + // I + mass*(crossmat(c)^2 - crossmat(c+a)^2) + // + // where c is the existing center of mass and I is the old inertia. + + int i,j; + dMatrix3 ahat,chat,t1,t2; + dReal a[3]; + + dAASSERT (m); + + // adjust inertia matrix + dSetZero (chat,12); + dCROSSMAT (chat,m->c,4,+,-); + a[0] = x + m->c[0]; + a[1] = y + m->c[1]; + a[2] = z + m->c[2]; + dSetZero (ahat,12); + dCROSSMAT (ahat,a,4,+,-); + dMULTIPLY0_333 (t1,ahat,ahat); + dMULTIPLY0_333 (t2,chat,chat); + for (i=0; i<3; i++) for (j=0; j<3; j++) + m->_I(i,j) += m->mass * (t2[i*4+j]-t1[i*4+j]); + + // ensure perfect symmetry + m->_I(1,0) = m->_I(0,1); + m->_I(2,0) = m->_I(0,2); + m->_I(2,1) = m->_I(1,2); + + // adjust center of mass + m->c[0] += x; + m->c[1] += y; + m->c[2] += z; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassRotate (dMass *m, const dMatrix3 R) +{ + // if the body is rotated by `R' relative to its point of reference, + // the new inertia about the point of reference is: + // + // R * I * R' + // + // where I is the old inertia. + + dMatrix3 t1; + dReal t2[3]; + + dAASSERT (m); + + // rotate inertia matrix + dMULTIPLY2_333 (t1,m->I,R); + dMULTIPLY0_333 (m->I,R,t1); + + // ensure perfect symmetry + m->_I(1,0) = m->_I(0,1); + m->_I(2,0) = m->_I(0,2); + m->_I(2,1) = m->_I(1,2); + + // rotate center of mass + dMULTIPLY0_331 (t2,R,m->c); + m->c[0] = t2[0]; + m->c[1] = t2[1]; + m->c[2] = t2[2]; + +# ifndef dNODEBUG + checkMass (m); +# endif +} + + +void dMassAdd (dMass *a, const dMass *b) +{ + int i; + dAASSERT (a && b); + dReal denom = dRecip (a->mass + b->mass); + for (i=0; i<3; i++) a->c[i] = (a->c[i]*a->mass + b->c[i]*b->mass)*denom; + a->mass += b->mass; + for (i=0; i<12; i++) a->I[i] += b->I[i]; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_mass.h b/src/external/open_dynamics_engine-ef/ode/ode_mass.h new file mode 100644 index 00000000..e2dfd184 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_mass.h @@ -0,0 +1,107 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_MASS_H_ +#define _ODE_MASS_H_ + +#include "ode/ode_common.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct dMass; +typedef struct dMass dMass; + + +void dMassSetZero (dMass *); + +void dMassSetParameters (dMass *, dReal themass, + dReal cgx, dReal cgy, dReal cgz, + dReal I11, dReal I22, dReal I33, + dReal I12, dReal I13, dReal I23); + +void dMassSetSphere (dMass *, dReal density, dReal radius); +void dMassSetSphereTotal (dMass *, dReal total_mass, dReal radius); + +void dMassSetCappedCylinder (dMass *, dReal density, int direction, + dReal radius, dReal length); +void dMassSetCappedCylinderTotal (dMass *, dReal total_mass, int direction, + dReal radius, dReal length); + +void dMassSetCylinder (dMass *, dReal density, int direction, + dReal radius, dReal length); +void dMassSetCylinderTotal (dMass *, dReal total_mass, int direction, + dReal radius, dReal length); + +void dMassSetBox (dMass *, dReal density, + dReal lx, dReal ly, dReal lz); +void dMassSetBoxTotal (dMass *, dReal total_mass, + dReal lx, dReal ly, dReal lz); + +void dMassAdjust (dMass *, dReal newmass); + +void dMassTranslate (dMass *, dReal x, dReal y, dReal z); + +void dMassRotate (dMass *, const dMatrix3 R); + +void dMassAdd (dMass *a, const dMass *b); + + + +struct dMass { + dReal mass; + dVector4 c; + dMatrix3 I; + +#ifdef __cplusplus + dMass() + { dMassSetZero (this); } + void setZero() + { dMassSetZero (this); } + void setParameters (dReal themass, dReal cgx, dReal cgy, dReal cgz, + dReal I11, dReal I22, dReal I33, + dReal I12, dReal I13, dReal I23) + { dMassSetParameters (this,themass,cgx,cgy,cgz,I11,I22,I33,I12,I13,I23); } + void setSphere (dReal density, dReal radius) + { dMassSetSphere (this,density,radius); } + void setCappedCylinder (dReal density, int direction, dReal a, dReal b) + { dMassSetCappedCylinder (this,density,direction,a,b); } + void setBox (dReal density, dReal lx, dReal ly, dReal lz) + { dMassSetBox (this,density,lx,ly,lz); } + void adjust (dReal newmass) + { dMassAdjust (this,newmass); } + void translate (dReal x, dReal y, dReal z) + { dMassTranslate (this,x,y,z); } + void rotate (const dMatrix3 R) + { dMassRotate (this,R); } + void add (const dMass *b) + { dMassAdd (this,b); } +#endif +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_mat.cpp b/src/external/open_dynamics_engine-ef/ode/ode_mat.cpp new file mode 100644 index 00000000..13c19f3b --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_mat.cpp @@ -0,0 +1,230 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_config.h" +#include "ode/ode_misc.h" +#include "ode/ode_matrix.h" +#include "ode/ode_error.h" +#include "ode/ode_memory.h" +#include "ode/ode_mat.h" + + +dMatrix::dMatrix() +{ + n = 0; + m = 0; + data = 0; +} + + +dMatrix::dMatrix (int rows, int cols) +{ + if (rows < 1 || cols < 1) dDebug (0,"bad matrix size"); + n = rows; + m = cols; + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + dSetZero (data,n*m); +} + + +dMatrix::dMatrix (const dMatrix &a) +{ + n = a.n; + m = a.m; + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + memcpy (data,a.data,n*m*sizeof(dReal)); +} + + +dMatrix::dMatrix (int rows, int cols, + dReal *_data, int rowskip, int colskip) +{ + if (rows < 1 || cols < 1) dDebug (0,"bad matrix size"); + n = rows; + m = cols; + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + for (int i=0; i= n || j < 0 || j >= m) dDebug (0,"bad matrix (i,j)"); + return data [i*m+j]; +} + + +void dMatrix::operator= (const dMatrix &a) +{ + if (data) dFree (data,n*m*sizeof(dReal)); + n = a.n; + m = a.m; + if (n > 0 && m > 0) { + data = (dReal*) dAlloc (n*m*sizeof(dReal)); + memcpy (data,a.data,n*m*sizeof(dReal)); + } + else data = 0; +} + + +void dMatrix::operator= (dReal a) +{ + for (int i=0; i= n || q[i] < 0 || q[i] >= m) + dDebug (0,"Matrix select, bad index arrays"); + r.data[i*nq+j] = data[p[i]*m+q[j]]; + } + } + return r; +} + + +dMatrix dMatrix::operator + (const dMatrix &a) +{ + if (n != a.n || m != a.m) dDebug (0,"matrix +, mismatched sizes"); + dMatrix r (n,m); + for (int i=0; i max) max = diff; + } + } + return max; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_mat.h b/src/external/open_dynamics_engine-ef/ode/ode_mat.h new file mode 100644 index 00000000..0b5a07fd --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_mat.h @@ -0,0 +1,71 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// matrix class. this is mostly for convenience in the testing code, it is +// not optimized at all. correctness is much more importance here. + +#ifndef _ODE_MAT_H_ +#define _ODE_MAT_H_ + +#include "ode/ode_common.h" + + +class dMatrix { + int n,m; // matrix dimension, n,m >= 0 + dReal *data; // if nonzero, n*m elements allocated on the heap + +public: + // constructors, destructors + dMatrix(); // make default 0x0 matrix + dMatrix (int rows, int cols); // construct zero matrix of given size + dMatrix (const dMatrix &); // construct copy of given matrix + // create copy of given data - element (i,j) is data[i*rowskip+j*colskip] + dMatrix (int rows, int cols, dReal *_data, int rowskip, int colskip); + ~dMatrix(); // destructor + + // data movement + dReal & operator () (int i, int j); // reference an element + void operator= (const dMatrix &); // matrix = matrix + void operator= (dReal); // matrix = scalar + dMatrix transpose(); // return transposed matrix + // return a permuted submatrix of this matrix, made up of the rows in p + // and the columns in q. p has np elements, q has nq elements. + dMatrix select (int np, int *p, int nq, int *q); + + // operators + dMatrix operator + (const dMatrix &); + dMatrix operator - (const dMatrix &); + dMatrix operator - (); + dMatrix operator * (const dMatrix &); + void operator += (const dMatrix &); + void operator -= (const dMatrix &); + + // utility + void clearUpperTriangle(); + void clearLowerTriangle(); + void makeRandom (dReal range); + void print (const char *fmt = "%10.4f ", FILE *f=stdout); + dReal maxDifference (const dMatrix &); +}; + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_math.cpp b/src/external/open_dynamics_engine-ef/ode/ode_math.cpp new file mode 100644 index 00000000..7ef06d0c --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_math.cpp @@ -0,0 +1,165 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_common.h" +#include "ode/ode_math.h" + +// get some math functions under windows +#ifdef WIN32 +#include +#ifndef CYGWIN // added by andy for cygwin +//messes up codewarrior +#define copysign(a,b) ((dReal)_copysign(a,b)) +#endif // added by andy for cygwin +#endif + + +// this may be called for vectors `a' with extremely small magnitude, for +// example the result of a cross product on two nearly perpendicular vectors. +// we must be robust to these small vectors. to prevent numerical error, +// first find the component a[i] with the largest magnitude and then scale +// all the components by 1/a[i]. then we can compute the length of `a' and +// scale the components by 1/l. this has been verified to work with vectors +// containing the smallest representable numbers. + +void dNormalize3 (dVector3 a) +{ + dReal a0,a1,a2,aa0,aa1,aa2,l; + dAASSERT (a); + a0 = a[0]; + a1 = a[1]; + a2 = a[2]; + aa0 = dFabs(a0); + aa1 = dFabs(a1); + aa2 = dFabs(a2); + if (aa1 > aa0) { + if (aa2 > aa1) { + goto aa2_largest; + } + else { // aa1 is largest + a0 /= aa1; + a2 /= aa1; + l = dRecipSqrt (a0*a0 + a2*a2 + 1); + a[0] = a0*l; + a[1] = dCopySign(l,a1); + a[2] = a2*l; + } + } + else { + if (aa2 > aa0) { + aa2_largest: // aa2 is largest + a0 /= aa2; + a1 /= aa2; + l = dRecipSqrt (a0*a0 + a1*a1 + 1); + a[0] = a0*l; + a[1] = a1*l; + a[2] = dCopySign(l,a2); + } + else { // aa0 is largest + if (aa0 <= 0) { + // dDEBUGMSG ("vector has zero size"); ... this messace is annoying + a[0] = 1; // if all a's are zero, this is where we'll end up. + a[1] = 0; // return a default unit length vector. + a[2] = 0; + return; + } + a1 /= aa0; + a2 /= aa0; + l = dRecipSqrt (a1*a1 + a2*a2 + 1); + a[0] = dCopySign(l,a0); + a[1] = a1*l; + a[2] = a2*l; + } + } +} + + +/* OLD VERSION */ +/* +void dNormalize3 (dVector3 a) +{ + dASSERT (a); + dReal l = dDOT(a,a); + if (l > 0) { + l = dRecipSqrt(l); + a[0] *= l; + a[1] *= l; + a[2] *= l; + } + else { + a[0] = 1; + a[1] = 0; + a[2] = 0; + } +} +*/ + + +void dNormalize4 (dVector4 a) +{ + dAASSERT (a); + dReal l = dDOT(a,a)+a[3]*a[3]; + if (l > 0) { + l = dRecipSqrt(l); + a[0] *= l; + a[1] *= l; + a[2] *= l; + a[3] *= l; + } + else { + dDEBUGMSG ("vector has zero size"); + a[0] = 1; + a[1] = 0; + a[2] = 0; + a[3] = 0; + } +} + + +void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q) +{ + dAASSERT (n && p && q); + if (dFabs(n[2]) > M_SQRT1_2) { + // choose p in y-z plane + dReal a = n[1]*n[1] + n[2]*n[2]; + dReal k = dRecipSqrt (a); + p[0] = 0; + p[1] = -n[2]*k; + p[2] = n[1]*k; + // set q = n x p + q[0] = a*k; + q[1] = -n[0]*p[2]; + q[2] = n[0]*p[1]; + } + else { + // choose p in x-y plane + dReal a = n[0]*n[0] + n[1]*n[1]; + dReal k = dRecipSqrt (a); + p[0] = -n[1]*k; + p[1] = n[0]*k; + p[2] = 0; + // set q = n x p + q[0] = -n[2]*p[1]; + q[1] = n[2]*p[0]; + q[2] = a*k; + } +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_math.h b/src/external/open_dynamics_engine-ef/ode/ode_math.h new file mode 100644 index 00000000..624b3cfd --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_math.h @@ -0,0 +1,258 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_ODEMATH_H_ +#define _ODE_ODEMATH_H_ + +#include "ode/ode_common.h" + +#ifdef __GNUC__ +#define PURE_INLINE extern inline +#else +#define PURE_INLINE inline +#endif + +/* + * macro to access elements i,j in an NxM matrix A, independent of the + * matrix storage convention. + */ +#define dACCESS33(A,i,j) ((A)[(i)*4+(j)]) + + +/* + * 3-way dot product. dDOTpq means that elements of `a' and `b' are spaced + * p and q indexes apart respectively. dDOT() means dDOT11. + * in C++ we could use function templates to get all the versions of these + * functions - but on some compilers this will result in sub-optimal code. + */ + +#define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)]) + +#ifdef __cplusplus + +PURE_INLINE dReal dDOT (const dReal *a, const dReal *b) { return dDOTpq(a,b,1,1); } +PURE_INLINE dReal dDOT13 (const dReal *a, const dReal *b) { return dDOTpq(a,b,1,3); } +PURE_INLINE dReal dDOT31 (const dReal *a, const dReal *b) { return dDOTpq(a,b,3,1); } +PURE_INLINE dReal dDOT33 (const dReal *a, const dReal *b) { return dDOTpq(a,b,3,3); } +PURE_INLINE dReal dDOT14 (const dReal *a, const dReal *b) { return dDOTpq(a,b,1,4); } +PURE_INLINE dReal dDOT41 (const dReal *a, const dReal *b) { return dDOTpq(a,b,4,1); } +PURE_INLINE dReal dDOT44 (const dReal *a, const dReal *b) { return dDOTpq(a,b,4,4); } + +#else + +#define dDOT(a,b) dDOTpq(a,b,1,1) +#define dDOT13(a,b) dDOTpq(a,b,1,3) +#define dDOT31(a,b) dDOTpq(a,b,3,1) +#define dDOT33(a,b) dDOTpq(a,b,3,3) +#define dDOT14(a,b) dDOTpq(a,b,1,4) +#define dDOT41(a,b) dDOTpq(a,b,4,1) +#define dDOT44(a,b) dDOTpq(a,b,4,4) + +#endif /* __cplusplus */ + + +/* + * cross product, set a = b x c. dCROSSpqr means that elements of `a', `b' + * and `c' are spaced p, q and r indexes apart respectively. + * dCROSS() means dCROSS111. `op' is normally `=', but you can set it to + * +=, -= etc to get other effects. + */ + +#define dCROSS(a,op,b,c) \ +do { \ + (a)[0] op ((b)[1]*(c)[2] - (b)[2]*(c)[1]); \ + (a)[1] op ((b)[2]*(c)[0] - (b)[0]*(c)[2]); \ + (a)[2] op ((b)[0]*(c)[1] - (b)[1]*(c)[0]); \ +} while(0) +#define dCROSSpqr(a,op,b,c,p,q,r) \ +do { \ + (a)[ 0] op ((b)[ q]*(c)[2*r] - (b)[2*q]*(c)[ r]); \ + (a)[ p] op ((b)[2*q]*(c)[ 0] - (b)[ 0]*(c)[2*r]); \ + (a)[2*p] op ((b)[ 0]*(c)[ r] - (b)[ q]*(c)[ 0]); \ +} while(0) +#define dCROSS114(a,op,b,c) dCROSSpqr(a,op,b,c,1,1,4) +#define dCROSS141(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,1) +#define dCROSS144(a,op,b,c) dCROSSpqr(a,op,b,c,1,4,4) +#define dCROSS411(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,1) +#define dCROSS414(a,op,b,c) dCROSSpqr(a,op,b,c,4,1,4) +#define dCROSS441(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,1) +#define dCROSS444(a,op,b,c) dCROSSpqr(a,op,b,c,4,4,4) + + +/* + * set a 3x3 submatrix of A to a matrix such that submatrix(A)*b = a x b. + * A is stored by rows, and has `skip' elements per row. the matrix is + * assumed to be already zero, so this does not write zero elements! + * if (plus,minus) is (+,-) then a positive version will be written. + * if (plus,minus) is (-,+) then a negative version will be written. + */ + +#define dCROSSMAT(A,a,skip,plus,minus) \ +do { \ + (A)[1] = minus (a)[2]; \ + (A)[2] = plus (a)[1]; \ + (A)[(skip)+0] = plus (a)[2]; \ + (A)[(skip)+2] = minus (a)[0]; \ + (A)[2*(skip)+0] = minus (a)[1]; \ + (A)[2*(skip)+1] = plus (a)[0]; \ +} while(0) + + +/* + * compute the distance between two 3-vectors + */ + +#ifdef __cplusplus +PURE_INLINE float dDISTANCE (const float a[3], const float b[3]) + { return (float) dSqrt( (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]) ); } +PURE_INLINE double dDISTANCE (const double a[3], const double b[3]) + { return dSqrt( (a[0]-b[0])*(a[0]-b[0]) + (a[1]-b[1])*(a[1]-b[1]) + (a[2]-b[2])*(a[2]-b[2]) ); } +#else +#define dDISTANCE(a,b) \ + (dSqrt( ((a)[0]-(b)[0])*((a)[0]-(b)[0]) + ((a)[1]-(b)[1])*((a)[1]-(b)[1]) + ((a)[2]-(b)[2])*((a)[2]-(b)[2]) )) +#endif + + +/* + * special case matrix multipication, with operator selection + */ + +#define dMULTIPLYOP0_331(A,op,B,C) \ +do { \ + (A)[0] op dDOT((B),(C)); \ + (A)[1] op dDOT((B+4),(C)); \ + (A)[2] op dDOT((B+8),(C)); \ +} while(0) +#define dMULTIPLYOP1_331(A,op,B,C) \ +do { \ + (A)[0] op dDOT41((B),(C)); \ + (A)[1] op dDOT41((B+1),(C)); \ + (A)[2] op dDOT41((B+2),(C)); \ +} while(0) +#define dMULTIPLYOP0_133(A,op,B,C) \ +do { \ + (A)[0] op dDOT14((B),(C)); \ + (A)[1] op dDOT14((B),(C+1)); \ + (A)[2] op dDOT14((B),(C+2)); \ +} while(0) +#define dMULTIPLYOP0_333(A,op,B,C) \ +do { \ + (A)[0] op dDOT14((B),(C)); \ + (A)[1] op dDOT14((B),(C+1)); \ + (A)[2] op dDOT14((B),(C+2)); \ + (A)[4] op dDOT14((B+4),(C)); \ + (A)[5] op dDOT14((B+4),(C+1)); \ + (A)[6] op dDOT14((B+4),(C+2)); \ + (A)[8] op dDOT14((B+8),(C)); \ + (A)[9] op dDOT14((B+8),(C+1)); \ + (A)[10] op dDOT14((B+8),(C+2)); \ +} while(0) +#define dMULTIPLYOP1_333(A,op,B,C) \ +do { \ + (A)[0] op dDOT44((B),(C)); \ + (A)[1] op dDOT44((B),(C+1)); \ + (A)[2] op dDOT44((B),(C+2)); \ + (A)[4] op dDOT44((B+1),(C)); \ + (A)[5] op dDOT44((B+1),(C+1)); \ + (A)[6] op dDOT44((B+1),(C+2)); \ + (A)[8] op dDOT44((B+2),(C)); \ + (A)[9] op dDOT44((B+2),(C+1)); \ + (A)[10] op dDOT44((B+2),(C+2)); \ +} while(0) +#define dMULTIPLYOP2_333(A,op,B,C) \ +do { \ + (A)[0] op dDOT((B),(C)); \ + (A)[1] op dDOT((B),(C+4)); \ + (A)[2] op dDOT((B),(C+8)); \ + (A)[4] op dDOT((B+4),(C)); \ + (A)[5] op dDOT((B+4),(C+4)); \ + (A)[6] op dDOT((B+4),(C+8)); \ + (A)[8] op dDOT((B+8),(C)); \ + (A)[9] op dDOT((B+8),(C+4)); \ + (A)[10] op dDOT((B+8),(C+8)); \ +} while(0) + +#ifdef __cplusplus + +#define DECL template PURE_INLINE void + +DECL dMULTIPLY0_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_331(A,=,B,C); } +DECL dMULTIPLY1_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_331(A,=,B,C); } +DECL dMULTIPLY0_133(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_133(A,=,B,C); } +DECL dMULTIPLY0_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_333(A,=,B,C); } +DECL dMULTIPLY1_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_333(A,=,B,C); } +DECL dMULTIPLY2_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP2_333(A,=,B,C); } + +DECL dMULTIPLYADD0_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_331(A,+=,B,C); } +DECL dMULTIPLYADD1_331(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_331(A,+=,B,C); } +DECL dMULTIPLYADD0_133(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_133(A,+=,B,C); } +DECL dMULTIPLYADD0_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP0_333(A,+=,B,C); } +DECL dMULTIPLYADD1_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP1_333(A,+=,B,C); } +DECL dMULTIPLYADD2_333(TA *A, const TB *B, const TC *C) { dMULTIPLYOP2_333(A,+=,B,C); } + +#undef DECL + +#else + +#define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C) +#define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C) +#define dMULTIPLY0_133(A,B,C) dMULTIPLYOP0_133(A,=,B,C) +#define dMULTIPLY0_333(A,B,C) dMULTIPLYOP0_333(A,=,B,C) +#define dMULTIPLY1_333(A,B,C) dMULTIPLYOP1_333(A,=,B,C) +#define dMULTIPLY2_333(A,B,C) dMULTIPLYOP2_333(A,=,B,C) + +#define dMULTIPLYADD0_331(A,B,C) dMULTIPLYOP0_331(A,+=,B,C) +#define dMULTIPLYADD1_331(A,B,C) dMULTIPLYOP1_331(A,+=,B,C) +#define dMULTIPLYADD0_133(A,B,C) dMULTIPLYOP0_133(A,+=,B,C) +#define dMULTIPLYADD0_333(A,B,C) dMULTIPLYOP0_333(A,+=,B,C) +#define dMULTIPLYADD1_333(A,B,C) dMULTIPLYOP1_333(A,+=,B,C) +#define dMULTIPLYADD2_333(A,B,C) dMULTIPLYOP2_333(A,+=,B,C) + +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * normalize 3x1 and 4x1 vectors (i.e. scale them to unit length) + */ +void dNormalize3 (dVector3 a); +void dNormalize4 (dVector4 a); + + +/* + * given a unit length "normal" vector n, generate vectors p and q vectors + * that are an orthonormal basis for the plane space perpendicular to n. + * i.e. this makes p,q such that n,p,q are all perpendicular to each other. + * q will equal n x p. if n is not unit length then p will be unit length but + * q wont be. + */ + +void dPlaneSpace (const dVector3 n, dVector3 p, dVector3 q); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_matrix.cpp b/src/external/open_dynamics_engine-ef/ode/ode_matrix.cpp new file mode 100644 index 00000000..10c01227 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_matrix.cpp @@ -0,0 +1,358 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_common.h" +#include "ode/ode_matrix.h" + +// misc defines +#define ALLOCA dALLOCA16 + + +void dSetZero (dReal *a, int n) +{ + dAASSERT (a && n >= 0); + while (n > 0) { + *(a++) = 0; + n--; + } +} + + +void dSetValue (dReal *a, int n, dReal value) +{ + dAASSERT (a && n >= 0); + while (n > 0) { + *(a++) = value; + n--; + } +} + + +void dMultiply0 (dReal *A, const dReal *B, const dReal *C, int p, int q, int r) +{ + int i,j,k,qskip,rskip,rpad; + dAASSERT (A && B && C && p>0 && q>0 && r>0); + qskip = dPAD(q); + rskip = dPAD(r); + rpad = rskip - r; + dReal sum; + const dReal *b,*c,*bb; + bb = B; + for (i=p; i; i--) { + for (j=0 ; j0 && q>0 && r>0); + pskip = dPAD(p); + rskip = dPAD(r); + for (i=0; i0 && q>0 && r>0); + rpad = dPAD(r) - r; + qskip = dPAD(q); + bb = B; + for (i=p; i; i--) { + cc = C; + for (j=r; j; j--) { + z = 0; + sum = 0; + for (k=q; k; k--,z++) sum += bb[z] * cc[z]; + *(A++) = sum; + cc += qskip; + } + A += rpad; + bb += qskip; + } +} + + +int dFactorCholesky (dReal *A, int n) +{ + int i,j,k,nskip; + dReal sum,*a,*b,*aa,*bb,*cc,*recip; + dAASSERT (n > 0 && A); + nskip = dPAD (n); + recip = (dReal*) ALLOCA (n * sizeof(dReal)); + aa = A; + for (i=0; i 0 && L && b); + nskip = dPAD (n); + y = (dReal*) ALLOCA (n*sizeof(dReal)); + for (i=0; i= 0; i--) { + sum = 0; + for (k=i+1; k < n; k++) sum += L[k*nskip+i]*b[k]; + b[i] = (y[i]-sum)/L[i*nskip+i]; + } +} + + +int dInvertPDMatrix (const dReal *A, dReal *Ainv, int n) +{ + int i,j,nskip; + dReal *L,*x; + dAASSERT (n > 0 && A && Ainv); + nskip = dPAD (n); + L = (dReal*) ALLOCA (nskip*n*sizeof(dReal)); + memcpy (L,A,nskip*n*sizeof(dReal)); + x = (dReal*) ALLOCA (n*sizeof(dReal)); + if (dFactorCholesky (L,n)==0) return 0; + dSetZero (Ainv,n*nskip); // make sure all padding elements set to 0 + for (i=0; i 0 && A); + int nskip = dPAD (n); + Acopy = (dReal*) ALLOCA (nskip*n * sizeof(dReal)); + memcpy (Acopy,A,nskip*n * sizeof(dReal)); + return dFactorCholesky (Acopy,n); +} + + +/***** this has been replaced by a faster version +void dSolveL1T (const dReal *L, dReal *b, int n, int nskip) +{ + int i,j; + dAASSERT (L && b && n >= 0 && nskip >= n); + dReal sum; + for (i=n-2; i>=0; i--) { + sum = 0; + for (j=i+1; j= 0); + for (int i=0; i 0 && nskip >= n); + dSolveL1 (L,b,n,nskip); + dVectorScale (b,d,n); + dSolveL1T (L,b,n,nskip); +} + + +void dLDLTAddTL (dReal *L, dReal *d, const dReal *a, int n, int nskip) +{ + int j,p; + dReal *W1,*W2,W11,W21,alpha1,alpha2,alphanew,gamma1,gamma2,k1,k2,Wp,ell,dee; + dAASSERT (L && d && a && n > 0 && nskip >= n); + + if (n < 2) return; + W1 = (dReal*) ALLOCA (n*sizeof(dReal)); + W2 = (dReal*) ALLOCA (n*sizeof(dReal)); + + W1[0] = 0; + W2[0] = 0; + for (j=1; j j) ? _GETA(i,j) : _GETA(j,i)) + + +void dLDLTRemove (dReal **A, const int *p, dReal *L, dReal *d, + int n1, int n2, int r, int nskip) +{ + int i; + dAASSERT(A && p && L && d && n1 > 0 && n2 > 0 && r >= 0 && r < n2 && + n1 >= n2 && nskip >= n1); + #ifndef dNODEBUG + for (i=0; i= 0 && p[i] < n1); + #endif + + if (r==n2-1) { + return; // deleting last row/col is easy + } + else if (r==0) { + dReal *a = (dReal*) ALLOCA (n2 * sizeof(dReal)); + for (i=0; i 0 && nskip >= n && r >= 0 && r < n); + if (r >= n-1) return; + if (r > 0) { + for (i=0; i 0 for any x. this performs a + * cholesky decomposition of A. if the decomposition fails then the matrix + * is not positive definite. A is stored by rows. A is not altered. + */ + +int dIsPositiveDefinite (const dReal *A, int n); + + +/* factorize a matrix A into L*D*L', where L is lower triangular with ones on + * the diagonal, and D is diagonal. + * A is an n*n matrix stored by rows, with a leading dimension of n rounded + * up to 4. L is written into the strict lower triangle of A (the ones are not + * written) and the reciprocal of the diagonal elements of D are written into + * d. + */ +void dFactorLDLT (dReal *A, dReal *d, int n, int nskip); + + +/* solve L*x=b, where L is n*n lower triangular with ones on the diagonal, + * and x,b are n*1. b is overwritten with x. + * the leading dimension of L is `nskip'. + */ +void dSolveL1 (const dReal *L, dReal *b, int n, int nskip); + + +/* solve L'*x=b, where L is n*n lower triangular with ones on the diagonal, + * and x,b are n*1. b is overwritten with x. + * the leading dimension of L is `nskip'. + */ +void dSolveL1T (const dReal *L, dReal *b, int n, int nskip); + + +/* in matlab syntax: a(1:n) = a(1:n) .* d(1:n) */ + +void dVectorScale (dReal *a, const dReal *d, int n); + + +/* given `L', a n*n lower triangular matrix with ones on the diagonal, + * and `d', a n*1 vector of the reciprocal diagonal elements of an n*n matrix + * D, solve L*D*L'*x=b where x,b are n*1. x overwrites b. + * the leading dimension of L is `nskip'. + */ + +void dSolveLDLT (const dReal *L, const dReal *d, dReal *b, int n, int nskip); + + +/* given an L*D*L' factorization of an n*n matrix A, return the updated + * factorization L2*D2*L2' of A plus the following "top left" matrix: + * + * [ b a' ] <-- b is a[0] + * [ a 0 ] <-- a is a[1..n-1] + * + * - L has size n*n, its leading dimension is nskip. L is lower triangular + * with ones on the diagonal. only the lower triangle of L is referenced. + * - d has size n. d contains the reciprocal diagonal elements of D. + * - a has size n. + * the result is written into L, except that the left column of L and d[0] + * are not actually modified. see ldltaddTL.m for further comments. + */ +void dLDLTAddTL (dReal *L, dReal *d, const dReal *a, int n, int nskip); + + +/* given an L*D*L' factorization of a permuted matrix A, produce a new + * factorization for row and column `r' removed. + * - A has size n1*n1, its leading dimension in nskip. A is symmetric and + * positive definite. only the lower triangle of A is referenced. + * A itself may actually be an array of row pointers. + * - L has size n2*n2, its leading dimension in nskip. L is lower triangular + * with ones on the diagonal. only the lower triangle of L is referenced. + * - d has size n2. d contains the reciprocal diagonal elements of D. + * - p is a permutation vector. it contains n2 indexes into A. each index + * must be in the range 0..n1-1. + * - r is the row/column of L to remove. + * the new L will be written within the old L, i.e. will have the same leading + * dimension. the last row and column of L, and the last element of d, are + * undefined on exit. + * + * a fast O(n^2) algorithm is used. see ldltremove.m for further comments. + */ +void dLDLTRemove (dReal **A, const int *p, dReal *L, dReal *d, + int n1, int n2, int r, int nskip); + + +/* given an n*n matrix A (with leading dimension nskip), remove the r'th row + * and column by moving elements. the new matrix will have the same leading + * dimension. the last row and column of A are untouched on exit. + */ +void dRemoveRowCol (dReal *A, int n, int nskip, int r); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_memory.cpp b/src/external/open_dynamics_engine-ef/ode/ode_memory.cpp new file mode 100644 index 00000000..d627b398 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_memory.cpp @@ -0,0 +1,87 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_config.h" +#include "ode/ode_memory.h" +#include "ode/ode_error.h" + + +static dAllocFunction *allocfn = 0; +static dReallocFunction *reallocfn = 0; +static dFreeFunction *freefn = 0; + + + +void dSetAllocHandler (dAllocFunction *fn) +{ + allocfn = fn; +} + + +void dSetReallocHandler (dReallocFunction *fn) +{ + reallocfn = fn; +} + + +void dSetFreeHandler (dFreeFunction *fn) +{ + freefn = fn; +} + + +dAllocFunction *dGetAllocHandler() +{ + return allocfn; +} + + +dReallocFunction *dGetReallocHandler() +{ + return reallocfn; +} + + +dFreeFunction *dGetFreeHandler() +{ + return freefn; +} + + +void * dAlloc (size_t size) +{ + if (allocfn) return allocfn (size); else return malloc (size); +} + + +void * dRealloc (void *ptr, size_t oldsize, size_t newsize) +{ + if (reallocfn) return reallocfn (ptr,oldsize,newsize); + else return realloc (ptr,newsize); +} + + +void dFree (void *ptr, size_t size) +{ + if (!ptr) return; + if (freefn) freefn (ptr,size); else free (ptr); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_memory.h b/src/external/open_dynamics_engine-ef/ode/ode_memory.h new file mode 100644 index 00000000..bc0679ad --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_memory.h @@ -0,0 +1,59 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* this comes from the `reuse' library. copy any changes back to the source */ + +#ifndef _ODE_MEMORY_H_ +#define _ODE_MEMORY_H_ + +#include "ode/ode_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* function types to allocate and free memory */ +typedef void * dAllocFunction (size_t size); +typedef void * dReallocFunction (void *ptr, size_t oldsize, size_t newsize); +typedef void dFreeFunction (void *ptr, size_t size); + +/* set new memory management functions. if fn is 0, the default handlers are + * used. */ +void dSetAllocHandler (dAllocFunction *fn); +void dSetReallocHandler (dReallocFunction *fn); +void dSetFreeHandler (dFreeFunction *fn); + +/* get current memory management functions */ +dAllocFunction *dGetAllocHandler (void); +dReallocFunction *dGetReallocHandler (void); +dFreeFunction *dGetFreeHandler (void); + +/* allocate and free memory. */ +void * dAlloc (size_t size); +void * dRealloc (void *ptr, size_t oldsize, size_t newsize); +void dFree (void *ptr, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_misc.cpp b/src/external/open_dynamics_engine-ef/ode/ode_misc.cpp new file mode 100644 index 00000000..18fabac4 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_misc.cpp @@ -0,0 +1,147 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_config.h" +#include "ode/ode_misc.h" +#include "ode/ode_matrix.h" + +//**************************************************************************** +// random numbers + +static unsigned long seed = 0; + +unsigned long dRand() +{ + seed = (1664525L*seed + 1013904223L) & 0xffffffff; + return seed; +} + + +unsigned long dRandGetSeed() +{ + return seed; +} + + +void dRandSetSeed (unsigned long s) +{ + seed = s; +} + + +int dTestRand() +{ + unsigned long oldseed = seed; + int ret = 1; + seed = 0; + if (dRand() != 0x3c6ef35f || dRand() != 0x47502932 || + dRand() != 0xd1ccf6e9 || dRand() != 0xaaf95334 || + dRand() != 0x6252e503) ret = 0; + seed = oldseed; + return ret; +} + + +int dRandInt (int n) +{ + double a = double(n) / 4294967296.0; + return (int) (double(dRand()) * a); +} + + +dReal dRandReal() +{ + return ((dReal) dRand()) / ((dReal) 0xffffffff); +} + +//**************************************************************************** +// matrix utility stuff + +void dPrintMatrix (const dReal *A, int n, int m, char *fmt, FILE *f) +{ + int i,j; + int skip = dPAD(m); + for (i=0; i max) max = diff; + } + } + return max; +} + + +dReal dMaxDifferenceLowerTriangle (const dReal *A, const dReal *B, int n) +{ + int i,j; + int skip = dPAD(n); + dReal diff,max; + max = 0; + for (i=0; i max) max = diff; + } + } + return max; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_misc.h b/src/external/open_dynamics_engine-ef/ode/ode_misc.h new file mode 100644 index 00000000..d7174e59 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_misc.h @@ -0,0 +1,85 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* miscellaneous math functions. these are mostly useful for testing */ + +#ifndef _ODE_MISC_H_ +#define _ODE_MISC_H_ + +#include "ode/ode_common.h" + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* return 1 if the random number generator is working. */ +int dTestRand(void); + +/* return next 32 bit random number. this uses a not-very-random linear + * congruential method. + */ +unsigned long dRand(void); + +/* get and set the current random number seed. */ +unsigned long dRandGetSeed(void); +void dRandSetSeed (unsigned long s); + +/* return a random integer between 0..n-1. the distribution will get worse + * as n approaches 2^32. + */ +int dRandInt (int n); + +/* return a random real number between 0..1 */ +dReal dRandReal(void); + +/* print out a matrix */ +#ifdef __cplusplus +void dPrintMatrix (const dReal *A, int n, int m, const char *fmt = "%10.4f ", + FILE *f=stdout); +#else +void dPrintMatrix (const dReal *A, int n, int m, char *fmt, FILE *f); +#endif + +/* make a random vector with entries between +/- range. A has n elements. */ +void dMakeRandomVector (dReal *A, int n, dReal range); + +/* make a random matrix with entries between +/- range. A has size n*m. */ +void dMakeRandomMatrix (dReal *A, int n, int m, dReal range); + +/* clear the upper triangle of a square matrix */ +void dClearUpperTriangle (dReal *A, int n); + +/* return the maximum element difference between the two n*m matrices */ +dReal dMaxDifference (const dReal *A, const dReal *B, int n, int m); + +/* return the maximum element difference between the lower triangle of two + * n*n matrices */ +dReal dMaxDifferenceLowerTriangle (const dReal *A, const dReal *B, int n); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_objects.h b/src/external/open_dynamics_engine-ef/ode/ode_objects.h new file mode 100644 index 00000000..7e50683d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_objects.h @@ -0,0 +1,284 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_OBJECTS_H_ +#define _ODE_OBJECTS_H_ + +#include "ode/ode_common.h" +#include "ode/ode_mass.h" +#include "ode/ode_contact.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* world */ + +dWorldID dWorldCreate(void); +void dWorldDestroy (dWorldID); + + int dWorldGetBodyCount(dWorldID); + +void dWorldSetGravity (dWorldID, dReal x, dReal y, dReal z); +void dWorldGetGravity (dWorldID, dVector3 gravity); +void dWorldSetERP (dWorldID, dReal erp); +dReal dWorldGetERP (dWorldID); +void dWorldSetCFM (dWorldID, dReal cfm); +dReal dWorldGetCFM (dWorldID); +void dWorldStep (dWorldID, dReal stepsize); +void dWorldImpulseToForce (dWorldID, dReal stepsize, + dReal ix, dReal iy, dReal iz, dVector3 force); + +/* World QuickStep functions */ + +void dWorldQuickStep (dWorldID w, dReal stepsize); +void dWorldSetQuickStepNumIterations (dWorldID, int num); +int dWorldGetQuickStepNumIterations (dWorldID); +void dWorldSetQuickStepW (dWorldID, dReal param); +dReal dWorldGetQuickStepW (dWorldID); + + int dWorldGetQuickStepWarmStartingDataSize(dWorldID w); + void dWorldGetQuickStepWarmStartingData(dWorldID w, dReal *array); + void dWorldSetQuickStepWarmStartingData(dWorldID w, dReal *array); + +/* World contact parameter functions */ + +void dWorldSetContactMaxCorrectingVel (dWorldID, dReal vel); +dReal dWorldGetContactMaxCorrectingVel (dWorldID); +void dWorldSetContactSurfaceLayer (dWorldID, dReal depth); +dReal dWorldGetContactSurfaceLayer (dWorldID); + +/* StepFast1 functions */ + +void dWorldStepFast1(dWorldID, dReal stepsize, int maxiterations); +void dWorldSetAutoEnableDepthSF1(dWorldID, int autoEnableDepth); +int dWorldGetAutoEnableDepthSF1(dWorldID); + +/* Auto-disable functions */ + +dReal dWorldGetAutoDisableLinearThreshold (dWorldID); +void dWorldSetAutoDisableLinearThreshold (dWorldID, dReal linear_threshold); +dReal dWorldGetAutoDisableAngularThreshold (dWorldID); +void dWorldSetAutoDisableAngularThreshold (dWorldID, dReal angular_threshold); +int dWorldGetAutoDisableSteps (dWorldID); +void dWorldSetAutoDisableSteps (dWorldID, int steps); +dReal dWorldGetAutoDisableTime (dWorldID); +void dWorldSetAutoDisableTime (dWorldID, dReal time); +int dWorldGetAutoDisableFlag (dWorldID); +void dWorldSetAutoDisableFlag (dWorldID, int do_auto_disable); + +dReal dBodyGetAutoDisableLinearThreshold (dBodyID); +void dBodySetAutoDisableLinearThreshold (dBodyID, dReal linear_threshold); +dReal dBodyGetAutoDisableAngularThreshold (dBodyID); +void dBodySetAutoDisableAngularThreshold (dBodyID, dReal angular_threshold); +int dBodyGetAutoDisableSteps (dBodyID); +void dBodySetAutoDisableSteps (dBodyID, int steps); +dReal dBodyGetAutoDisableTime (dBodyID); +void dBodySetAutoDisableTime (dBodyID, dReal time); +int dBodyGetAutoDisableFlag (dBodyID); +void dBodySetAutoDisableFlag (dBodyID, int do_auto_disable); +void dBodySetAutoDisableDefaults (dBodyID); + +/* bodies */ + +dBodyID dBodyCreate (dWorldID); +void dBodyDestroy (dBodyID); + +void dBodySetData (dBodyID, void *data); +void *dBodyGetData (dBodyID); + +void dBodySetPosition (dBodyID, dReal x, dReal y, dReal z); +void dBodySetRotation (dBodyID, const dMatrix3 R); +void dBodySetQuaternion (dBodyID, const dQuaternion q); +void dBodySetLinearVel (dBodyID, dReal x, dReal y, dReal z); +void dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z); +const dReal * dBodyGetPosition (dBodyID); +const dReal * dBodyGetRotation (dBodyID); /* ptr to 4x3 rot matrix */ +const dReal * dBodyGetQuaternion (dBodyID); +const dReal * dBodyGetLinearVel (dBodyID); +const dReal * dBodyGetAngularVel (dBodyID); + +void dBodySetMass (dBodyID, const dMass *mass); +void dBodyGetMass (dBodyID, dMass *mass); + +void dBodyAddForce (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddTorque (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddRelForce (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddRelTorque (dBodyID, dReal fx, dReal fy, dReal fz); +void dBodyAddForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); +void dBodyAddForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); +void dBodyAddRelForceAtPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); +void dBodyAddRelForceAtRelPos (dBodyID, dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz); + +const dReal * dBodyGetForce (dBodyID); +const dReal * dBodyGetTorque (dBodyID); +void dBodySetForce (dBodyID b, dReal x, dReal y, dReal z); +void dBodySetTorque (dBodyID b, dReal x, dReal y, dReal z); + +void dBodyGetRelPointPos (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyGetRelPointVel (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyGetPointVel (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyGetPosRelPoint (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyVectorToWorld (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); +void dBodyVectorFromWorld (dBodyID, dReal px, dReal py, dReal pz, + dVector3 result); + +void dBodySetFiniteRotationMode (dBodyID, int mode); +void dBodySetFiniteRotationAxis (dBodyID, dReal x, dReal y, dReal z); + +int dBodyGetFiniteRotationMode (dBodyID); +void dBodyGetFiniteRotationAxis (dBodyID, dVector3 result); + +int dBodyGetNumJoints (dBodyID b); +dJointID dBodyGetJoint (dBodyID, int index); + +void dBodyEnable (dBodyID); +void dBodyDisable (dBodyID); +int dBodyIsEnabled (dBodyID); + +void dBodySetGravityMode (dBodyID b, int mode); +int dBodyGetGravityMode (dBodyID b); + + +/* joints */ + +dJointID dJointCreateBall (dWorldID, dJointGroupID); +dJointID dJointCreateHinge (dWorldID, dJointGroupID); +dJointID dJointCreateSlider (dWorldID, dJointGroupID); +dJointID dJointCreateContact (dWorldID, dJointGroupID, const dContact *); +dJointID dJointCreateHinge2 (dWorldID, dJointGroupID); +dJointID dJointCreateUniversal (dWorldID, dJointGroupID); +dJointID dJointCreateFixed (dWorldID, dJointGroupID); +dJointID dJointCreateNull (dWorldID, dJointGroupID); +dJointID dJointCreateAMotor (dWorldID, dJointGroupID); + +void dJointDestroy (dJointID); + +dJointGroupID dJointGroupCreate (int max_size); +void dJointGroupDestroy (dJointGroupID); +void dJointGroupEmpty (dJointGroupID); + +void dJointAttach (dJointID, dBodyID body1, dBodyID body2); +void dJointSetData (dJointID, void *data); +void *dJointGetData (dJointID); +int dJointGetType (dJointID); +dBodyID dJointGetBody (dJointID, int index); + +void dJointSetFeedback (dJointID, dJointFeedback *); +dJointFeedback *dJointGetFeedback (dJointID); + +void dJointSetBallParam (dJointID, int parameter, dReal value); + void dJointSetBallSpringMode(dJointID,int enable); +void dJointSetBallAnchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetBallAnchor2 (dJointID, dReal x, dReal y, dReal z); +void dJointSetHingeAnchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetHingeAnchorDelta (dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); +void dJointSetHingeAxis (dJointID, dReal x, dReal y, dReal z); +void dJointSetHingeParam (dJointID, int parameter, dReal value); +void dJointAddHingeTorque(dJointID joint, dReal torque); +void dJointSetSliderAxis (dJointID, dReal x, dReal y, dReal z); +void dJointSetSliderAxisDelta (dJointID, dReal x, dReal y, dReal z, dReal ax, dReal ay, dReal az); +void dJointSetSliderParam (dJointID, int parameter, dReal value); +void dJointAddSliderForce(dJointID joint, dReal force); +void dJointSetHinge2Anchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetHinge2Axis1 (dJointID, dReal x, dReal y, dReal z); +void dJointSetHinge2Axis2 (dJointID, dReal x, dReal y, dReal z); +void dJointSetHinge2Param (dJointID, int parameter, dReal value); +void dJointAddHinge2Torques(dJointID joint, dReal torque1, dReal torque2); +void dJointSetUniversalAnchor (dJointID, dReal x, dReal y, dReal z); +void dJointSetUniversalAxis1 (dJointID, dReal x, dReal y, dReal z); +void dJointSetUniversalAxis2 (dJointID, dReal x, dReal y, dReal z); +void dJointSetUniversalParam (dJointID, int parameter, dReal value); +void dJointAddUniversalTorques(dJointID joint, dReal torque1, dReal torque2); +void dJointSetFixed (dJointID); +void dJointSetFixedAnchor (dJointID, dReal x, dReal y, dReal z, int abs); + void dJointSetFixedParam (dJointID,int parameter, dReal value); + void dJointSetFixedSpringMode(dJointID,int linearEnable, int angularEnable, + int customAnchorPointEnable); + + //added by Eric Froemling - for joints with only one body connection + void dJointSetFixedAnchorRotation(dJointID, const dQuaternion q); +void dJointSetAMotorNumAxes (dJointID, int num); +void dJointSetAMotorAxis (dJointID, int anum, int rel, + dReal x, dReal y, dReal z); +void dJointSetAMotorAngle (dJointID, int anum, dReal angle); +void dJointSetAMotorParam (dJointID, int parameter, dReal value); +void dJointSetAMotorMode (dJointID, int mode); +void dJointAddAMotorTorques (dJointID, dReal torque1, dReal torque2, dReal torque3); + +void dJointGetBallAnchor (dJointID, dVector3 result); +void dJointGetBallAnchor2 (dJointID, dVector3 result); +void dJointGetHingeAnchor (dJointID, dVector3 result); +void dJointGetHingeAnchor2 (dJointID, dVector3 result); +void dJointGetHingeAxis (dJointID, dVector3 result); +dReal dJointGetHingeParam (dJointID, int parameter); +dReal dJointGetHingeAngle (dJointID); +dReal dJointGetHingeAngleRate (dJointID); +dReal dJointGetSliderPosition (dJointID); +dReal dJointGetSliderPositionRate (dJointID); +void dJointGetSliderAxis (dJointID, dVector3 result); +dReal dJointGetSliderParam (dJointID, int parameter); +void dJointGetHinge2Anchor (dJointID, dVector3 result); +void dJointGetHinge2Anchor2 (dJointID, dVector3 result); +void dJointGetHinge2Axis1 (dJointID, dVector3 result); +void dJointGetHinge2Axis2 (dJointID, dVector3 result); +dReal dJointGetHinge2Param (dJointID, int parameter); +dReal dJointGetHinge2Angle1 (dJointID); +dReal dJointGetHinge2Angle1Rate (dJointID); +dReal dJointGetHinge2Angle2Rate (dJointID); +void dJointGetUniversalAnchor (dJointID, dVector3 result); +void dJointGetUniversalAnchor2 (dJointID, dVector3 result); +void dJointGetUniversalAxis1 (dJointID, dVector3 result); +void dJointGetUniversalAxis2 (dJointID, dVector3 result); +dReal dJointGetUniversalParam (dJointID, int parameter); +dReal dJointGetUniversalAngle1 (dJointID); +dReal dJointGetUniversalAngle2 (dJointID); +dReal dJointGetUniversalAngle1Rate (dJointID); +dReal dJointGetUniversalAngle2Rate (dJointID); +int dJointGetAMotorNumAxes (dJointID); +void dJointGetAMotorAxis (dJointID, int anum, dVector3 result); +int dJointGetAMotorAxisRel (dJointID, int anum); +dReal dJointGetAMotorAngle (dJointID, int anum); +dReal dJointGetAMotorAngleRate (dJointID, int anum); +dReal dJointGetAMotorParam (dJointID, int parameter); +int dJointGetAMotorMode (dJointID); + +dJointID dConnectingJoint (dBodyID, dBodyID); +int dConnectingJointList (dBodyID, dBodyID, dJointID*); +int dAreConnected (dBodyID, dBodyID); +int dAreConnectedExcluding (dBodyID, dBodyID, int joint_type); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_objects_private.h b/src/external/open_dynamics_engine-ef/ode/ode_objects_private.h new file mode 100644 index 00000000..a118a4d6 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_objects_private.h @@ -0,0 +1,125 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// object, body, and world structs. + + +#ifndef _ODE_OBJECT_H_ +#define _ODE_OBJECT_H_ + +#include "ode/ode_common.h" +#include "ode/ode_memory.h" +#include "ode/ode_mass.h" +#include "ode/ode_array.h" + + +// some body flags + +enum { + dxBodyFlagFiniteRotation = 1, // use finite rotations + dxBodyFlagFiniteRotationAxis = 2, // use finite rotations only along axis + dxBodyDisabled = 4, // body is disabled + dxBodyNoGravity = 8, // body is not influenced by gravity + dxBodyAutoDisable = 16 // enable auto-disable on body +}; + + +// base class that does correct object allocation / deallocation + +struct dBase { + void *operator new (size_t size) { return dAlloc (size); } + void operator delete (void *ptr, size_t size) { dFree (ptr,size); } + void *operator new[] (size_t size) { return dAlloc (size); } + void operator delete[] (void *ptr, size_t size) { dFree (ptr,size); } +}; + + +// base class for bodies and joints + +struct dObject : public dBase { + dxWorld *world; // world this object is in + dObject *next; // next object of this type in list + dObject **tome; // pointer to previous object's next ptr + void *userdata; // user settable data + int tag; // used by dynamics algorithms +}; + + +// auto disable parameters +struct dxAutoDisable { + dReal linear_threshold; // linear (squared) velocity treshold + dReal angular_threshold; // angular (squared) velocity treshold + dReal idle_time; // time the body needs to be idle to auto-disable it + int idle_steps; // steps the body needs to be idle to auto-disable it +}; + + +// quick-step parameters +struct dxQuickStepParameters { + int num_iterations; // number of SOR iterations to perform + dReal w; // the SOR over-relaxation parameter +}; + + +// contact generation parameters +struct dxContactParameters { + dReal max_vel; // maximum correcting velocity + dReal min_depth; // thickness of 'surface layer' +}; + + +struct dxBody : public dObject { + dxJointNode *firstjoint; // list of attached joints + int flags; // some dxBodyFlagXXX flags + dGeomID geom; // first collision geom associated with body + dMass mass; // mass parameters about POR + dMatrix3 invI; // inverse of mass.I + dReal invMass; // 1 / mass.mass + dVector3 pos; // position of POR (point of reference) + dQuaternion q; // orientation quaternion + dMatrix3 R; // rotation matrix, always corresponds to q + dVector3 lvel,avel; // linear and angular velocity of POR + dVector3 facc,tacc; // force and torque accumulators + dVector3 finite_rot_axis; // finite rotation axis, unit length or 0=none + + // auto-disable information + dxAutoDisable adis; // auto-disable parameters + dReal adis_timeleft; // time left to be idle + int adis_stepsleft; // steps left to be idle +}; + + +struct dxWorld : public dBase { + dxBody *firstbody; // body linked list + dxJoint *firstjoint; // joint linked list + int nb,nj; // number of bodies and joints in lists + dVector3 gravity; // gravity vector (m/s/s) + dReal global_erp; // global error reduction parameter + dReal global_cfm; // global costraint force mixing parameter + dxAutoDisable adis; // auto-disable parameters + int adis_flag; // auto-disable flag for new bodies + dxQuickStepParameters qs; + dxContactParameters contactp; +}; + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_obstack.cpp b/src/external/open_dynamics_engine-ef/ode/ode_obstack.cpp new file mode 100644 index 00000000..fb13c674 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_obstack.cpp @@ -0,0 +1,138 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +// Silence warnings about shortening 64 vit values into 32 bit containers +#if __clang__ +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#endif +#ifdef _MSC_VER +#pragma warning( disable: 4267) +#endif + +#include "ode/ode_common.h" +#include "ode/ode_error.h" +#include "ode/ode_memory.h" +#include "ode/ode_obstack.h" + +//**************************************************************************** +// macros and constants + +#define ROUND_UP_OFFSET_TO_EFFICIENT_SIZE(arena,ofs) \ + ofs = (size_t) (dEFFICIENT_SIZE( ((intP)(arena)) + ofs ) - ((intP)(arena)) ); + +#define MAX_ALLOC_SIZE \ + ((size_t)(dOBSTACK_ARENA_SIZE - sizeof (Arena) - EFFICIENT_ALIGNMENT + 1)) + +//**************************************************************************** +// dObStack + +dObStack::dObStack() +{ + first = 0; + last = 0; + current_arena = 0; + current_ofs = 0; +} + + +dObStack::~dObStack() +{ + // free all arenas + Arena *a,*nexta; + a = first; + while (a) { + nexta = a->next; + dFree (a,dOBSTACK_ARENA_SIZE); + a = nexta; + } +} + + +void *dObStack::alloc (int num_bytes) +{ + if ((size_t)num_bytes > MAX_ALLOC_SIZE) dDebug (0,"num_bytes too large"); + + // allocate or move to a new arena if necessary + if (!first) { + // allocate the first arena if necessary + first = last = (Arena *) dAlloc (dOBSTACK_ARENA_SIZE); + first->next = 0; + first->used = sizeof (Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (first,first->used); + } + else { + // we already have one or more arenas, see if a new arena must be used + if ((last->used + num_bytes) > dOBSTACK_ARENA_SIZE) { + if (!last->next) { + last->next = (Arena *) dAlloc (dOBSTACK_ARENA_SIZE); + last->next->next = 0; + } + last = last->next; + last->used = sizeof (Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (last,last->used); + } + } + + // allocate an area in the arena + char *c = ((char*) last) + last->used; + last->used += num_bytes; + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (last,last->used); + return c; +} + + +void dObStack::freeAll() +{ + last = first; + if (first) { + first->used = sizeof(Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (first,first->used); + } +} + + +void *dObStack::rewind() +{ + current_arena = first; + current_ofs = sizeof (Arena); + if (current_arena) { + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs) + return ((char*) current_arena) + current_ofs; + } + else return 0; +} + + +void *dObStack::next (int num_bytes) +{ + // this functions like alloc, except that no new storage is ever allocated + if (!current_arena) return 0; + current_ofs += num_bytes; + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs); + if (current_ofs >= current_arena->used) { + current_arena = current_arena->next; + if (!current_arena) return 0; + current_ofs = sizeof (Arena); + ROUND_UP_OFFSET_TO_EFFICIENT_SIZE (current_arena,current_ofs); + } + return ((char*) current_arena) + current_ofs; +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_obstack.h b/src/external/open_dynamics_engine-ef/ode/ode_obstack.h new file mode 100644 index 00000000..8fb4ba42 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_obstack.h @@ -0,0 +1,68 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_OBSTACK_H_ +#define _ODE_OBSTACK_H_ + +#include "ode/ode_objects_private.h" + +// each obstack Arena pointer points to a block of this many bytes +#define dOBSTACK_ARENA_SIZE 16384 + + +struct dObStack : public dBase { + struct Arena { + Arena *next; // next arena in linked list + int used; // total number of bytes used in this arena, counting + }; // this header + + Arena *first; // head of the arena linked list. 0 if no arenas yet + Arena *last; // arena where blocks are currently being allocated + + // used for iterator + Arena *current_arena; + int current_ofs; + + dObStack(); + ~dObStack(); + + void *alloc (int num_bytes); + // allocate a block in the last arena, allocating a new arena if necessary. + // it is a runtime error if num_bytes is larger than the arena size. + + void freeAll(); + // free all blocks in all arenas. this does not deallocate the arenas + // themselves, so future alloc()s will reuse them. + + void *rewind(); + // rewind the obstack iterator, and return the address of the first + // allocated block. return 0 if there are no allocated blocks. + + void *next (int num_bytes); + // return the address of the next allocated block. 'num_bytes' is the size + // of the previous block. this returns null if there are no more arenas. + // the sequence of 'num_bytes' parameters passed to next() during a + // traversal of the list must exactly match the parameters passed to alloc(). +}; + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_quickstep.cpp b/src/external/open_dynamics_engine-ef/ode/ode_quickstep.cpp new file mode 100644 index 00000000..dabd486e --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_quickstep.cpp @@ -0,0 +1,1040 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001-2003 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_objects_private.h" +#include "ode/ode_joint.h" +#include "ode/ode_config.h" +#include "ode/ode_math.h" +#include "ode/ode_rotation.h" +#include "ode/ode_timer.h" +#include "ode/ode_error.h" +#include "ode/ode_matrix.h" +#include "ode/ode_misc.h" +#include "ode/ode_lcp.h" +#include "ode/ode_util.h" +#include "ode/ode_misc.h" + +#define ALLOCA dALLOCA16 + +typedef const dReal *dRealPtr; +typedef dReal *dRealMutablePtr; +#define dRealArray(name,n) dReal name[n]; + +// ericf addition - a simple memory buffer +class _Buffer{ +public: + _Buffer():_ptr(NULL),_allocated(false){ + } + void allocate(unsigned long size){ + if (_allocated && _ptr) free(_ptr); + //dIASSERT(size > 0); + _ptr = malloc(size); + dIASSERT(_ptr); + _allocated = true; + } + ~_Buffer(){ + if (_allocated && _ptr) free(_ptr); + _ptr = NULL; + } + void* getPtr() const {return _ptr;} +private: + void* _ptr; + bool _allocated; +}; + + +// ...ericf update - we can shave a bit of time off by using our own bare-bones buffer class... +#define TRIXY_ALLOCA(name,type,n) _Buffer name ## BUF; if (n > 6000){name ## BUF.allocate((n)); name = (type*)name ## BUF.getPtr();} else {name = (type*)ALLOCA((n)); dIASSERT(name);} + +#define dRealAllocaArray(name,n) dReal *name; TRIXY_ALLOCA(name,dReal,n*sizeof(dReal)) +//#define dRealAllocaArray(name,n) dReal *name = (dReal*) ALLOCA ((n)*sizeof(dReal)); + + +// whether to use quickstep feedback patch submitted to the ode mailing +// list by Jaroslav Sinecky in June '05 +#define JUNE_05_PATCH 1 + +//*************************************************************************** +// configuration + +// for the SOR and CG methods: +// uncomment the following line to use warm starting. this definitely +// help for motor-driven joints. unfortunately it appears to hurt +// with high-friction contacts using the SOR method. use with care + +#define WARM_STARTING 0 + + +// for the SOR method: +// uncomment the following line to determine a new constraint-solving +// order for each iteration. however, the qsort per iteration is expensive, +// and the optimal order is somewhat problem dependent. +// @@@ try the leaf->root ordering. + +//#define REORDER_CONSTRAINTS 1 + + +// for the SOR method: +// uncomment the following line to randomly reorder constraint rows +// during the solution. depending on the situation, this can help a lot +// or hardly at all, but it doesn't seem to hurt. + +// ericf note: this was on for original release; trying it off to save processing.. +#define RANDOMLY_REORDER_CONSTRAINTS 0 + +#if JUNE_05_PATCH + +//**************************************************************************** +// special matrix multipliers + +// multiply block of B matrix (q x 6) with 12 dReal per row with C vektor (q) +static void Multiply1_12q1 (dReal *A, dReal *B, dReal *C, int q) +{ + int k; + dReal sum; + dIASSERT (q>0 && A && B && C); + sum = 0; + for (k=0; kinvMass; + for (j=0; j<3; j++) iMJ_ptr[j] = k*J_ptr[j]; + dMULTIPLY0_331 (iMJ_ptr + 3, invI + 12*b1, J_ptr + 3); + if (b2 >= 0) { + k = body[b2]->invMass; + for (j=0; j<3; j++) iMJ_ptr[j+6] = k*J_ptr[j+6]; + dMULTIPLY0_331 (iMJ_ptr + 9, invI + 12*b2, J_ptr + 9); + } + J_ptr += 12; + iMJ_ptr += 12; + } +} + + +// compute out = inv(M)*J'*in. + +static void multiply_invM_JT (int m, int nb, dRealMutablePtr iMJ, int *jb, + dRealMutablePtr in, dRealMutablePtr out) +{ + int i,j; + dSetZero (out,6*nb); + dRealPtr iMJ_ptr = iMJ; + for (i=0; i= 0) { + out_ptr = out + b2*6; + for (j=0; j<6; j++) out_ptr[j] += iMJ_ptr[j] * in[i]; + } + iMJ_ptr += 6; + } +} + + +// compute out = J*in. + +static void multiply_J (int m, dRealMutablePtr J, int *jb, + dRealMutablePtr in, dRealMutablePtr out) +{ + int i,j; + dRealPtr J_ptr = J; + for (i=0; i= 0) { + in_ptr = in + b2*6; + for (j=0; j<6; j++) sum += J_ptr[j] * in_ptr[j]; + } + J_ptr += 6; + out[i] = sum; + } +} + + +// compute out = (J*inv(M)*J' + cfm)*in. +// use z as an nb*6 temporary. + +#if 0 +static void multiply_J_invM_JT (int m, int nb, dRealMutablePtr J, dRealMutablePtr iMJ, int *jb, + dRealPtr cfm, dRealMutablePtr z, dRealMutablePtr in, dRealMutablePtr out) +{ + multiply_invM_JT (m,nb,iMJ,jb,in,z); + multiply_J (m,J,jb,z,out); + + // add cfm + for (int i=0; inum_iterations; + + // precompute iMJ = inv(M)*J' + dRealAllocaArray (iMJ,m*12); + compute_invM_JT (m,J,iMJ,jb,body,invI); + + dReal last_rho = 0; + dRealAllocaArray (r,m); + dRealAllocaArray (z,m); + dRealAllocaArray (p,m); + dRealAllocaArray (q,m); + + // precompute 1 / diagonals of A + dRealAllocaArray (Ad,m); + dRealPtr iMJ_ptr = iMJ; + dRealPtr J_ptr = J; + for (i=0; i= 0) { + for (j=6; j<12; j++) sum += iMJ_ptr[j] * J_ptr[j]; + } + iMJ_ptr += 12; + J_ptr += 12; + Ad[i] = REAL(1.0) / (sum + cfm[i]); + } + +#ifdef WARM_STARTING + // compute residual r = b - A*lambda + multiply_J_invM_JT (m,nb,J,iMJ,jb,cfm,fc,lambda,r); + for (i=0; ifindex < 0 && i2->findex >= 0) return -1; + if (i1->findex >= 0 && i2->findex < 0) return 1; + if (i1->error < i2->error) return -1; + if (i1->error > i2->error) return 1; + return 0; +} + +#endif + + +static void SOR_LCP (int m, int nb, dRealMutablePtr J, int *jb, dxBody * const *body, + dRealPtr invI, dRealMutablePtr lambda, dRealMutablePtr fc, dRealMutablePtr b, + dRealMutablePtr lo, dRealMutablePtr hi, dRealPtr cfm, int *findex, + dxQuickStepParameters *qs) +{ + const int num_iterations = qs->num_iterations; + const dReal sor_w = qs->w; // SOR over-relaxation parameter + + int i,j; + +#ifdef WARM_STARTING + // for warm starting, this seems to be necessary to prevent + // jerkiness in motor-driven joints. i have no idea why this works. + for (i=0; i= 0) { + for (j=6; j<12; j++) sum += iMJ_ptr[j] * J_ptr[j]; + } + iMJ_ptr += 12; + J_ptr += 12; + Ad[i] = sor_w / (sum + cfm[i]); + } + + // scale J and b by Ad + J_ptr = J; + for (i=0; i= 0) order[j++].index = i; + dIASSERT (j==m); +#endif + + for (int iteration=0; iteration < num_iterations; iteration++) { + +#ifdef REORDER_CONSTRAINTS + // constraints with findex < 0 always come first. + if (iteration < 2) { + // for the first two iterations, solve the constraints in + // the given order + for (i=0; i v2) ? v1 : v2; + if (max > 0) { + //@@@ relative error: order[i].error = dFabs(lambda[i]-last_lambda[i])/max; + order[i].error = dFabs(lambda[i]-last_lambda[i]); + } + else { + order[i].error = dInfinity; + } + order[i].findex = findex[i]; + order[i].index = i; + } + } + qsort (order,m,sizeof(IndexError),&compare_index_error); +#endif + +//ericf: we save and restore the random seed here so each island is not affected by the +//existance of other islands +#ifdef RANDOMLY_REORDER_CONSTRAINTS + unsigned long oldSeed = dRandGetSeed(); + if ((iteration & 7) == 0) { + for (i=1; i= 0) { + hi[index] = dFabs (hicopy[index] * lambda[findex[index]]); + lo[index] = -hi[index]; + } + + int b1 = jb[index*2]; + int b2 = jb[index*2+1]; + dReal delta = b[index] - lambda[index]*Ad[index]; + dRealMutablePtr fc_ptr = fc + 6*b1; + + //DIFF HERE + + // @@@ potential optimization: SIMD-ize this and the b2 >= 0 case + delta -=fc_ptr[0] * J_ptr[0] + fc_ptr[1] * J_ptr[1] + + fc_ptr[2] * J_ptr[2] + fc_ptr[3] * J_ptr[3] + + fc_ptr[4] * J_ptr[4] + fc_ptr[5] * J_ptr[5]; + // @@@ potential optimization: handle 1-body constraints in a separate + // loop to avoid the cost of test & jump? + if (b2 >= 0) { + fc_ptr = fc + 6*b2; + delta -=fc_ptr[0] * J_ptr[6] + fc_ptr[1] * J_ptr[7] + + fc_ptr[2] * J_ptr[8] + fc_ptr[3] * J_ptr[9] + + fc_ptr[4] * J_ptr[10] + fc_ptr[5] * J_ptr[11]; + } + + // compute lambda and clamp it to [lo,hi]. + // @@@ potential optimization: does SSE have clamping instructions + // to save test+jump penalties here? + dReal new_lambda = lambda[index] + delta; + if (new_lambda < lo[index]) { + delta = lo[index]-lambda[index]; + lambda[index] = lo[index]; + } + else if (new_lambda > hi[index]) { + delta = hi[index]-lambda[index]; + lambda[index] = hi[index]; + } + else { + lambda[index] = new_lambda; + } + + //@@@ a trick that may or may not help + //dReal ramp = (1-((dReal)(iteration+1)/(dReal)num_iterations)); + //delta *= ramp; + + + // update fc. + // @@@ potential optimization: SIMD for this and the b2 >= 0 case + fc_ptr = fc + 6*b1; + fc_ptr[0] += delta * iMJ_ptr[0]; + fc_ptr[1] += delta * iMJ_ptr[1]; + fc_ptr[2] += delta * iMJ_ptr[2]; + fc_ptr[3] += delta * iMJ_ptr[3]; + fc_ptr[4] += delta * iMJ_ptr[4]; + fc_ptr[5] += delta * iMJ_ptr[5]; + // @@@ potential optimization: handle 1-body constraints in a separate + // loop to avoid the cost of test & jump? + if (b2 >= 0) { + fc_ptr = fc + 6*b2; + fc_ptr[0] += delta * iMJ_ptr[6]; + fc_ptr[1] += delta * iMJ_ptr[7]; + fc_ptr[2] += delta * iMJ_ptr[8]; + fc_ptr[3] += delta * iMJ_ptr[9]; + fc_ptr[4] += delta * iMJ_ptr[10]; + fc_ptr[5] += delta * iMJ_ptr[11]; + } + } + } +} + + +void dxQuickStepper (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *_joint, int nj, dReal stepsize) +{ + int i,j; + IFTIMING(dTimerStart("preprocessing");) + + dReal stepsize1 = dRecip(stepsize); + + // number all bodies in the body list - set their tag values + for (i=0; itag = i; + + // make a local copy of the joint array, because we might want to modify it. + // (the "dxJoint *const*" declaration says we're allowed to modify the joints + // but not the joint array, because the caller might need it unchanged). + //@@@ do we really need to do this? we'll be sorting constraint rows individually, not joints + dxJoint **joint = (dxJoint**) alloca (nj * sizeof(dxJoint*)); + memcpy (joint,_joint,nj * sizeof(dxJoint*)); + + // for all bodies, compute the inertia tensor and its inverse in the global + // frame, and compute the rotational force and add it to the torque + // accumulator. I and invI are a vertical stack of 3x4 matrices, one per body. +#if !JUNE_05_PATCH + dRealAllocaArray (I,3*4*nb); // need to remember all I's for feedback purposes only +#endif + dRealAllocaArray (invI,3*4*nb); + for (i=0; imass.I,body[i]->R); +#if !JUNE_05_PATCH + dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); +#else + dMULTIPLY0_333 (I,body[i]->R,tmp); +#endif + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); + dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); + // compute rotational force + + // ERICF TEST +// #ifndef dNODEBUG +// { +// dReal testVal = (nb > 0)?dFabs(body[0]->lvel[0]):0.0; +// if (isnan(testVal) || isinf(testVal) || testVal > 9999.0f){ +// printf("ARGGGGG3!\n"); +// } +// } +// #endif + + +#define SIMPLE_ROTATION 1 + + +#if !SIMPLE_ROTATION + +#if !JUNE_05_PATCH + dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); +#else + dMULTIPLY0_331 (tmp,I,body[i]->avel); +#endif + dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); +#endif // SIMPLE_ROTATION + + } + + // { + // dReal testVal = (nb > 0)?dFabs(body[0]->facc[0]):0.0; + // if (isnan(testVal) || isinf(testVal) || testVal > 9999.0f){ + // printf("WHOOOOOAAAAAA!\n"); + // } + // } + + // add the gravity force to all bodies + for (i=0; iflags & dxBodyNoGravity)==0) { + body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; + body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; + body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; + } + // else{ + // body[i]->facc[0] = 0; + // body[i]->facc[1] = 0; + // body[i]->facc[2] = 0; + // body[i]->lvel[0] = 0; + // body[i]->lvel[1] = 0; + // body[i]->lvel[2] = 0; + // body[i]->avel[0] = 0; + // body[i]->avel[1] = 0; + // body[i]->avel[2] = 0; + // } + } + + // get joint information (m = total constraint dimension, nub = number of unbounded variables). + // joints with m=0 are inactive and are removed from the joints array + // entirely, so that the code that follows does not consider them. + //@@@ do we really need to save all the info1's + //printf("SIZE IS %d coutn is %d\n",sizeof(dxJoint::Info1),nj); + dxJoint::Info1 *info = (dxJoint::Info1*) alloca (nj*sizeof(dxJoint::Info1)); + for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); + dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); + if (info[i].m > 0) { + joint[i] = joint[j]; + i++; + } + } + nj = i; + + // create the row offset array + int m = 0; + int *ofs = (int*) alloca (nj*sizeof(int)); + for (i=0; i 0) { + // create a constraint equation right hand side vector `c', a constraint + // force mixing vector `cfm', and LCP low and high bound vectors, and an + // 'findex' vector. + dRealAllocaArray (c,m); + dRealAllocaArray (cfm,m); + dRealAllocaArray (lo,m); + dRealAllocaArray (hi,m); + int *findex = (int*) alloca (m*sizeof(int)); + dSetZero (c,m); + dSetValue (cfm,m,world->global_cfm); + dSetValue (lo,m,-dInfinity); + dSetValue (hi,m, dInfinity); + for (i=0; iglobal_erp; + + + for (i=0; ivtable->getInfo2 (joint[i],&Jinfo); + // adjust returned findex values for global index numbering + for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; + } + + } + +#if JUNE_05_PATCH + // we need a copy of Jacobian for joint feedbacks + // because it gets destroyed by SOR solver + // instead of saving all Jacobian, we can save just rows + // for joints, that requested feedback (which is normaly much less) + int mfb = 0; // number of rows we will have to save + for (i=0; ifeedback) + mfb += info[i].m; + dRealAllocaArray (Jcopy,mfb*12); + if (mfb > 0) { + mfb = 0; + for (i=0; ifeedback) { + memcpy(Jcopy+mfb*12, J+ofs[i]*12, info[i].m*12*sizeof(dReal)); + mfb += info[i].m; + } + } + + +#endif + + // create an array of body numbers for each joint row + int *jb_ptr = jb; + for (i=0; inode[0].body) ? (joint[i]->node[0].body->tag) : -1; + int b2 = (joint[i]->node[1].body) ? (joint[i]->node[1].body->tag) : -1; + for (j=0; jinvMass; + for (j=0; j<3; j++) tmp1[i*6+j] = body[i]->facc[j] * body_invMass + body[i]->lvel[j] * stepsize1; + dMULTIPLY0_331 (tmp1 + i*6 + 3,invI + i*12,body[i]->tacc); + for (j=0; j<3; j++) tmp1[i*6+3+j] += body[i]->avel[j] * stepsize1; + + } + + // put J*tmp1 into rhs + dRealAllocaArray (rhs,m); + multiply_J (m,J,jb,tmp1,rhs); + + // complete rhs + for (i=0; ilambda,info[i].m * sizeof(dReal)); + } +#endif + + + //check the stuff going into SOR_LCP + + // solve the LCP problem and get lambda and invM*constraint_force + IFTIMING (dTimerNow ("solving LCP problem");) + dRealAllocaArray (cforce,nb*6); + SOR_LCP (m,nb,J,jb,body,invI,lambda,cforce,rhs,lo,hi,cfm,findex,&world->qs); + + // ERICF TEST + { +// dReal testVal = (nb > 0)?dFabs(cforce[0]):0.0; +// if (isnan(testVal) || isinf(testVal) || testVal > 9999.0f){ +// printf("ARGGGGG1!\n"); +// for (i=0; ilambda[0]); +// } +// printf("dn\n"); + +// } +// else{ + +// # ifdef WARM_STARTING +// // save lambda for the next iteration +// //@@@ note that this doesn't work for contact joints yet, as they are +// // recreated every iteration +// for (i=0; ilambda,lambda+ofs[i],info[i].m * sizeof(dReal)); +// } +// # endif + + // note that the SOR method overwrites rhs and J at this point, so + // they should not be used again. + + // add stepsize * cforce to the body velocity + for (i=0; ilvel[j] += stepsize * cforce[i*6+j]; + } + for (j=0; j<3; j++){ + body[i]->avel[j] += stepsize * cforce[i*6+3+j]; + } + } + // } + + // ERICF TEST +// #ifndef dNODEBUG +// { +// dReal testVal = (nb > 0)?dFabs(body[0]->lvel[0]):0.0; +// if (isnan(testVal) || isinf(testVal) || testVal > 9999.0f){ +// printf("ARGGGGGffff1! %f\n",cforce[0]); +// } +// } +// #endif + + + +#if !JUNE_05_PATCH + // if joint feedback is requested, compute the constraint force. + // BUT: cforce is inv(M)*J'*lambda, whereas we want just J'*lambda, + // so we must compute M*cforce. + // @@@ if any joint has a feedback request we compute the entire + // adjusted cforce, which is not the most efficient way to do it. + for (j=0; jfeedback) { + // compute adjusted cforce + for (i=0; imass.mass; + cforce [i*6+0] *= k; + cforce [i*6+1] *= k; + cforce [i*6+2] *= k; + dVector3 tmp; + dMULTIPLY0_331 (tmp, I + 12*i, cforce + i*6 + 3); + cforce [i*6+3] = tmp[0]; + cforce [i*6+4] = tmp[1]; + cforce [i*6+5] = tmp[2]; + } + // compute feedback for this and all remaining joints + for (; jfeedback; + if (fb) { + int b1 = joint[j]->node[0].body->tag; + memcpy (fb->f1,cforce+b1*6,3*sizeof(dReal)); + memcpy (fb->t1,cforce+b1*6+3,3*sizeof(dReal)); + if (joint[j]->node[1].body) { + int b2 = joint[j]->node[1].body->tag; + memcpy (fb->f2,cforce+b2*6,3*sizeof(dReal)); + memcpy (fb->t2,cforce+b2*6+3,3*sizeof(dReal)); + } + } + } + } + } +#else + if (mfb > 0) { + // straightforward computation of joint contraint forces: + // multiply related lambdas with respective J' block for joints + // where feedback was requested + mfb = 0; + for (i=0; ifeedback) { + dJointFeedback *fb = joint[i]->feedback; + dReal data[6]; + Multiply1_12q1 (data, Jcopy+mfb*12, lambda+ofs[i], info[i].m); + fb->f1[0] = data[0]; + fb->f1[1] = data[1]; + fb->f1[2] = data[2]; + fb->t1[0] = data[3]; + fb->t1[1] = data[4]; + fb->t1[2] = data[5]; + if (joint[i]->node[1].body) + { + Multiply1_12q1 (data, Jcopy+mfb*12+6, lambda+ofs[i], info[i].m); + fb->f2[0] = data[0]; + fb->f2[1] = data[1]; + fb->f2[2] = data[2]; + fb->t2[0] = data[3]; + fb->t2[1] = data[4]; + fb->t2[2] = data[5]; + } + mfb += info[i].m; + } + } + } +#endif + } + + } + + // compute the velocity update: + // add stepsize * invM * fe to the body velocity + + IFTIMING (dTimerNow ("compute velocity update");) + + // ERICF CHANGE - take a look at the velocity on our first body - if it looks like it exploded, + // ignore this entire update. + { + // dReal testVal = (nb > 0)?dFabs(body[0]->lvel[0] + (stepsize * body[0]->invMass * body[0]->facc[0])):0.0; + // if (isnan(testVal) || isinf(testVal) || testVal > 9999.0f){ + // printf("SKIPPPPPPPING!\n"); + // } + // else{ + for (i=0; iinvMass; + for (j=0; j<3; j++) body[i]->lvel[j] += stepsize * body_invMass * body[i]->facc[j]; + for (j=0; j<3; j++) body[i]->tacc[j] *= stepsize; + dMULTIPLYADD0_331 (body[i]->avel,invI + i*12,body[i]->tacc); +// #ifndef dNODEBUG +// for (j=0; j<3; j++){ +// if ((dFabs(body[i]->lvel[j]) > 9999.0f) || (dFabs(body[i]->avel[j]) > 9999.0f)){ +// printf("WTFFFFFFF!!!!\n"); +// } +// } +// #endif + } + // } + } + +#if 0 + // check that the updated velocity obeys the constraint (this check needs unmodified J) + dRealAllocaArray (vel,nb*6); + for (i=0; ilvel[j]; + for (j=0; j<3; j++) vel[i*6+3+j] = body[i]->avel[j]; + } + dRealAllocaArray (tmp,m); + multiply_J (m,J,jb,vel,tmp); + dReal error = 0; + for (i=0; ifacc,3); + dSetZero (body[i]->tacc,3); + } + + IFTIMING (dTimerEnd();) + IFTIMING (if (m > 0) dTimerReport (stdout,1);) +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_quickstep.h b/src/external/open_dynamics_engine-ef/ode/ode_quickstep.h new file mode 100644 index 00000000..c46cef53 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_quickstep.h @@ -0,0 +1,33 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_QUICK_STEP_H_ +#define _ODE_QUICK_STEP_H_ + +#include "ode/ode_common.h" + + +void dxQuickStepper (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *_joint, int nj, dReal stepsize); + + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_rotation.cpp b/src/external/open_dynamics_engine-ef/ode/ode_rotation.cpp new file mode 100644 index 00000000..ed9eae9f --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_rotation.cpp @@ -0,0 +1,304 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +quaternions have the format: (s,vx,vy,vz) where (vx,vy,vz) is the +"rotation axis" and s is the "rotation angle". + +*/ + +#include "ode/ode_rotation.h" +#include "ode/ode_math.h" + + +#define _R(i,j) R[(i)*4+(j)] + +#define SET_3x3_IDENTITY \ + _R(0,0) = REAL(1.0); \ + _R(0,1) = REAL(0.0); \ + _R(0,2) = REAL(0.0); \ + _R(0,3) = REAL(0.0); \ + _R(1,0) = REAL(0.0); \ + _R(1,1) = REAL(1.0); \ + _R(1,2) = REAL(0.0); \ + _R(1,3) = REAL(0.0); \ + _R(2,0) = REAL(0.0); \ + _R(2,1) = REAL(0.0); \ + _R(2,2) = REAL(1.0); \ + _R(2,3) = REAL(0.0); + + +void dRSetIdentity (dMatrix3 R) +{ + dAASSERT (R); + SET_3x3_IDENTITY; +} + + +void dRFromAxisAndAngle (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal angle) +{ + dAASSERT (R); + dQuaternion q; + dQFromAxisAndAngle (q,ax,ay,az,angle); + dQtoR (q,R); +} + + +void dRFromEulerAngles (dMatrix3 R, dReal phi, dReal theta, dReal psi) +{ + dReal sphi,cphi,stheta,ctheta,spsi,cpsi; + dAASSERT (R); + sphi = dSin(phi); + cphi = dCos(phi); + stheta = dSin(theta); + ctheta = dCos(theta); + spsi = dSin(psi); + cpsi = dCos(psi); + _R(0,0) = cpsi*ctheta; + _R(0,1) = spsi*ctheta; + _R(0,2) =-stheta; + _R(1,0) = cpsi*stheta*sphi - spsi*cphi; + _R(1,1) = spsi*stheta*sphi + cpsi*cphi; + _R(1,2) = ctheta*sphi; + _R(2,0) = cpsi*stheta*cphi + spsi*sphi; + _R(2,1) = spsi*stheta*cphi - cpsi*sphi; + _R(2,2) = ctheta*cphi; +} + + +void dRFrom2Axes (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal bx, dReal by, dReal bz) +{ + dReal l,k; + dAASSERT (R); + l = dSqrt (ax*ax + ay*ay + az*az); + if (l <= REAL(0.0)) { + dDEBUGMSG ("zero length vector"); + return; + } + l = dRecip(l); + ax *= l; + ay *= l; + az *= l; + k = ax*bx + ay*by + az*bz; + bx -= k*ax; + by -= k*ay; + bz -= k*az; + l = dSqrt (bx*bx + by*by + bz*bz); + if (l <= REAL(0.0)) { + dDEBUGMSG ("zero length vector"); + return; + } + l = dRecip(l); + bx *= l; + by *= l; + bz *= l; + _R(0,0) = ax; + _R(1,0) = ay; + _R(2,0) = az; + _R(0,1) = bx; + _R(1,1) = by; + _R(2,1) = bz; + _R(0,2) = - by*az + ay*bz; + _R(1,2) = - bz*ax + az*bx; + _R(2,2) = - bx*ay + ax*by; +} + + +void dRFromZAxis (dMatrix3 R, dReal ax, dReal ay, dReal az) +{ + dVector3 n,p,q; + n[0] = ax; + n[1] = ay; + n[2] = az; + dNormalize3 (n); + dPlaneSpace (n,p,q); + _R(0,0) = p[0]; + _R(1,0) = p[1]; + _R(2,0) = p[2]; + _R(0,1) = q[0]; + _R(1,1) = q[1]; + _R(2,1) = q[2]; + _R(0,2) = n[0]; + _R(1,2) = n[1]; + _R(2,2) = n[2]; +} + + +void dQSetIdentity (dQuaternion q) +{ + dAASSERT (q); + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; +} + + +void dQFromAxisAndAngle (dQuaternion q, dReal ax, dReal ay, dReal az, + dReal angle) +{ + dAASSERT (q); + dReal l = ax*ax + ay*ay + az*az; + if (l > REAL(0.0)) { + angle *= REAL(0.5); + q[0] = dCos (angle); + l = dSin(angle) * dRecipSqrt(l); + q[1] = ax*l; + q[2] = ay*l; + q[3] = az*l; + } + else { + q[0] = 1; + q[1] = 0; + q[2] = 0; + q[3] = 0; + } +} + + +void dQMultiply0 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] - qb[1]*qc[1] - qb[2]*qc[2] - qb[3]*qc[3]; + qa[1] = qb[0]*qc[1] + qb[1]*qc[0] + qb[2]*qc[3] - qb[3]*qc[2]; + qa[2] = qb[0]*qc[2] + qb[2]*qc[0] + qb[3]*qc[1] - qb[1]*qc[3]; + qa[3] = qb[0]*qc[3] + qb[3]*qc[0] + qb[1]*qc[2] - qb[2]*qc[1]; +} + + +void dQMultiply1 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] + qb[1]*qc[1] + qb[2]*qc[2] + qb[3]*qc[3]; + qa[1] = qb[0]*qc[1] - qb[1]*qc[0] - qb[2]*qc[3] + qb[3]*qc[2]; + qa[2] = qb[0]*qc[2] - qb[2]*qc[0] - qb[3]*qc[1] + qb[1]*qc[3]; + qa[3] = qb[0]*qc[3] - qb[3]*qc[0] - qb[1]*qc[2] + qb[2]*qc[1]; +} + + +void dQMultiply2 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] + qb[1]*qc[1] + qb[2]*qc[2] + qb[3]*qc[3]; + qa[1] = -qb[0]*qc[1] + qb[1]*qc[0] - qb[2]*qc[3] + qb[3]*qc[2]; + qa[2] = -qb[0]*qc[2] + qb[2]*qc[0] - qb[3]*qc[1] + qb[1]*qc[3]; + qa[3] = -qb[0]*qc[3] + qb[3]*qc[0] - qb[1]*qc[2] + qb[2]*qc[1]; +} + + +void dQMultiply3 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc) +{ + dAASSERT (qa && qb && qc); + qa[0] = qb[0]*qc[0] - qb[1]*qc[1] - qb[2]*qc[2] - qb[3]*qc[3]; + qa[1] = -qb[0]*qc[1] - qb[1]*qc[0] + qb[2]*qc[3] - qb[3]*qc[2]; + qa[2] = -qb[0]*qc[2] - qb[2]*qc[0] + qb[3]*qc[1] - qb[1]*qc[3]; + qa[3] = -qb[0]*qc[3] - qb[3]*qc[0] + qb[1]*qc[2] - qb[2]*qc[1]; +} + + +// dRfromQ(), dQfromR() and dDQfromW() are derived from equations in "An Introduction +// to Physically Based Modeling: Rigid Body Simulation - 1: Unconstrained +// Rigid Body Dynamics" by David Baraff, Robotics Institute, Carnegie Mellon +// University, 1997. + +void dRfromQ (dMatrix3 R, const dQuaternion q) +{ + dAASSERT (q && R); + // q = (s,vx,vy,vz) + dReal qq1 = 2*q[1]*q[1]; + dReal qq2 = 2*q[2]*q[2]; + dReal qq3 = 2*q[3]*q[3]; + _R(0,0) = 1 - qq2 - qq3; + _R(0,1) = 2*(q[1]*q[2] - q[0]*q[3]); + _R(0,2) = 2*(q[1]*q[3] + q[0]*q[2]); + _R(1,0) = 2*(q[1]*q[2] + q[0]*q[3]); + _R(1,1) = 1 - qq1 - qq3; + _R(1,2) = 2*(q[2]*q[3] - q[0]*q[1]); + _R(2,0) = 2*(q[1]*q[3] - q[0]*q[2]); + _R(2,1) = 2*(q[2]*q[3] + q[0]*q[1]); + _R(2,2) = 1 - qq1 - qq2; +} + + +void dQfromR (dQuaternion q, const dMatrix3 R) +{ + dAASSERT (q && R); + dReal tr,s; + tr = _R(0,0) + _R(1,1) + _R(2,2); + if (tr >= 0) { + s = dSqrt (tr + 1); + q[0] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[1] = (_R(2,1) - _R(1,2)) * s; + q[2] = (_R(0,2) - _R(2,0)) * s; + q[3] = (_R(1,0) - _R(0,1)) * s; + } + else { + // find the largest diagonal element and jump to the appropriate case + if (_R(1,1) > _R(0,0)) { + if (_R(2,2) > _R(1,1)) goto case_2; + goto case_1; + } + if (_R(2,2) > _R(0,0)) goto case_2; + goto case_0; + + case_0: + s = dSqrt((_R(0,0) - (_R(1,1) + _R(2,2))) + 1); + q[1] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[2] = (_R(0,1) + _R(1,0)) * s; + q[3] = (_R(2,0) + _R(0,2)) * s; + q[0] = (_R(2,1) - _R(1,2)) * s; + return; + + case_1: + s = dSqrt((_R(1,1) - (_R(2,2) + _R(0,0))) + 1); + q[2] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[3] = (_R(1,2) + _R(2,1)) * s; + q[1] = (_R(0,1) + _R(1,0)) * s; + q[0] = (_R(0,2) - _R(2,0)) * s; + return; + + case_2: + s = dSqrt((_R(2,2) - (_R(0,0) + _R(1,1))) + 1); + q[3] = REAL(0.5) * s; + s = REAL(0.5) * dRecip(s); + q[1] = (_R(2,0) + _R(0,2)) * s; + q[2] = (_R(1,2) + _R(2,1)) * s; + q[0] = (_R(1,0) - _R(0,1)) * s; + return; + } +} + + +void dDQfromW (dReal dq[4], const dVector3 w, const dQuaternion q) +{ + dAASSERT (w && q && dq); + dq[0] = REAL(0.5)*(- w[0]*q[1] - w[1]*q[2] - w[2]*q[3]); + dq[1] = REAL(0.5)*( w[0]*q[0] + w[1]*q[3] - w[2]*q[2]); + dq[2] = REAL(0.5)*(- w[0]*q[3] + w[1]*q[0] + w[2]*q[1]); + dq[3] = REAL(0.5)*( w[0]*q[2] - w[1]*q[1] + w[2]*q[0]); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_rotation.h b/src/external/open_dynamics_engine-ef/ode/ode_rotation.h new file mode 100644 index 00000000..b8879dfe --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_rotation.h @@ -0,0 +1,70 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_ROTATION_H_ +#define _ODE_ROTATION_H_ + +#include "ode/ode_common.h" +#include "ode/ode_compatibility.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +void dRSetIdentity (dMatrix3 R); + +void dRFromAxisAndAngle (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal angle); + +void dRFromEulerAngles (dMatrix3 R, dReal phi, dReal theta, dReal psi); + +void dRFrom2Axes (dMatrix3 R, dReal ax, dReal ay, dReal az, + dReal bx, dReal by, dReal bz); + +void dRFromZAxis (dMatrix3 R, dReal ax, dReal ay, dReal az); + +void dQSetIdentity (dQuaternion q); + +void dQFromAxisAndAngle (dQuaternion q, dReal ax, dReal ay, dReal az, + dReal angle); + +/* Quaternion multiplication, analogous to the matrix multiplication routines. */ +/* qa = rotate by qc, then qb */ +void dQMultiply0 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); +/* qa = rotate by qc, then by inverse of qb */ +void dQMultiply1 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); +/* qa = rotate by inverse of qc, then by qb */ +void dQMultiply2 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); +/* qa = rotate by inverse of qc, then by inverse of qb */ +void dQMultiply3 (dQuaternion qa, const dQuaternion qb, const dQuaternion qc); + +void dRfromQ (dMatrix3 R, const dQuaternion q); +void dQfromR (dQuaternion q, const dMatrix3 R); +void dDQfromW (dReal dq[4], const dVector3 w, const dQuaternion q); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/ode_step.cpp b/src/external/open_dynamics_engine-ef/ode/ode_step.cpp new file mode 100644 index 00000000..61803d2c --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_step.cpp @@ -0,0 +1,1786 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#include "ode/ode_objects_private.h" +#include "ode/ode_joint.h" +#include "ode/ode_config.h" +#include "ode/ode_math.h" +#include "ode/ode_rotation.h" +#include "ode/ode_timer.h" +#include "ode/ode_error.h" +#include "ode/ode_matrix.h" +#include "ode/ode_lcp.h" +#include "ode/ode_util.h" + +//**************************************************************************** +// misc defines + +#define FAST_FACTOR +//#define TIMING + +// memory allocation system +#ifdef dUSE_MALLOC_FOR_ALLOCA +unsigned int dMemoryFlag; +#define REPORT_OUT_OF_MEMORY fprintf(stderr, "Insufficient memory to complete rigid body simulation. Results will not be accurate.\n") + +#define ALLOCA(t,v,s) t* v=(t*)malloc(s) +#define UNALLOCA(t) free(t) + +#else +#define ALLOCA(t,v,s) t* v=(t*)dALLOCA16(s) +#define UNALLOCA(t) /* nothing */ +#endif + + +//**************************************************************************** +// debugging - comparison of various vectors and matrices produced by the +// slow and fast versions of the stepper. + +//#define COMPARE_METHODS + +#ifdef COMPARE_METHODS +#include "ode/ode_testing.h" +dMatrixComparison comparator; +#endif + +// undef to use the fast decomposition +#define DIRECT_CHOLESKY +#undef REPORT_ERROR + +//**************************************************************************** +// special matrix multipliers + +// this assumes the 4th and 8th rows of B and C are zero. + +static void Multiply2_p8r (dReal *A, dReal *B, dReal *C, + int p, int r, int Askip) +{ + int i,j; + dReal sum,*bb,*cc; + dIASSERT (p>0 && r>0 && A && B && C); + bb = B; + for (i=p; i; i--) { + cc = C; + for (j=r; j; j--) { + sum = bb[0]*cc[0]; + sum += bb[1]*cc[1]; + sum += bb[2]*cc[2]; + sum += bb[4]*cc[4]; + sum += bb[5]*cc[5]; + sum += bb[6]*cc[6]; + *(A++) = sum; + cc += 8; + } + A += Askip - r; + bb += 8; + } +} + + +// this assumes the 4th and 8th rows of B and C are zero. + +static void MultiplyAdd2_p8r (dReal *A, dReal *B, dReal *C, + int p, int r, int Askip) +{ + int i,j; + dReal sum,*bb,*cc; + dIASSERT (p>0 && r>0 && A && B && C); + bb = B; + for (i=p; i; i--) { + cc = C; + for (j=r; j; j--) { + sum = bb[0]*cc[0]; + sum += bb[1]*cc[1]; + sum += bb[2]*cc[2]; + sum += bb[4]*cc[4]; + sum += bb[5]*cc[5]; + sum += bb[6]*cc[6]; + *(A++) += sum; + cc += 8; + } + A += Askip - r; + bb += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void Multiply0_p81 (dReal *A, dReal *B, dReal *C, int p) +{ + int i; + dIASSERT (p>0 && A && B && C); + dReal sum; + for (i=p; i; i--) { + sum = B[0]*C[0]; + sum += B[1]*C[1]; + sum += B[2]*C[2]; + sum += B[4]*C[4]; + sum += B[5]*C[5]; + sum += B[6]*C[6]; + *(A++) = sum; + B += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void MultiplyAdd0_p81 (dReal *A, dReal *B, dReal *C, int p) +{ + int i; + dIASSERT (p>0 && A && B && C); + dReal sum; + for (i=p; i; i--) { + sum = B[0]*C[0]; + sum += B[1]*C[1]; + sum += B[2]*C[2]; + sum += B[4]*C[4]; + sum += B[5]*C[5]; + sum += B[6]*C[6]; + *(A++) += sum; + B += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void MultiplyAdd1_8q1 (dReal *A, dReal *B, dReal *C, int q) +{ + int k; + dReal sum; + dIASSERT (q>0 && A && B && C); + sum = 0; + for (k=0; k0 && A && B && C); + sum = 0; + for (k=0; ktag = i; + + // make a local copy of the joint array, because we might want to modify it. + // (the "dxJoint *const*" declaration says we're allowed to modify the joints + // but not the joint array, because the caller might need it unchanged). + ALLOCA(dxJoint*,joint,nj*sizeof(dxJoint*)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (joint == NULL) { + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + memcpy (joint,_joint,nj * sizeof(dxJoint*)); + + // for all bodies, compute the inertia tensor and its inverse in the global + // frame, and compute the rotational force and add it to the torque + // accumulator. + // @@@ check computation of rotational force. + ALLOCA(dReal,I,3*nb*4*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (I == NULL) { + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,invI,3*nb*4*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (invI == NULL) { + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + //dSetZero (I,3*nb*4); + //dSetZero (invI,3*nb*4); + for (i=0; imass.I,body[i]->R); + dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); + dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); + // compute rotational force + dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); + dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); + } + + // add the gravity force to all bodies + for (i=0; iflags & dxBodyNoGravity)==0) { + body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; + body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; + body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; + } + } + + // get m = total constraint dimension, nub = number of unbounded variables. + // create constraint offset array and number-of-rows array for all joints. + // the constraints are re-ordered as follows: the purely unbounded + // constraints, the mixed unbounded + LCP constraints, and last the purely + // LCP constraints. + // + // joints with m=0 are inactive and are removed from the joints array + // entirely, so that the code that follows does not consider them. + int m = 0; + ALLOCA(dxJoint::Info1,info,nj*sizeof(dxJoint::Info1)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (info == NULL) { + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + ALLOCA(int,ofs,nj*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (ofs == NULL) { + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); + dIASSERT (info[i].m >= 0 && info[i].m <= 6 && + info[i].nub >= 0 && info[i].nub <= info[i].m); + if (info[i].m > 0) { + joint[i] = joint[j]; + i++; + } + } + nj = i; + + // the purely unbounded constraints + for (i=0; i 0 && info[i].nub < info[i].m) { + ofs[i] = m; + m += info[i].m; + } + // the purely LCP constraints + for (i=0; iinvMass; + MM[nskip+1] = body[i]->invMass; + MM[2*nskip+2] = body[i]->invMass; + MM += 3*nskip+3; + for (j=0; j<3; j++) for (k=0; k<3; k++) { + MM[j*nskip+k] = invI[i*12+j*4+k]; + } + } + + // assemble some body vectors: fe = external forces, v = velocities + ALLOCA(dReal,fe,n6*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (fe == NULL) { + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + ALLOCA(dReal,v,n6*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (v == NULL) { + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + //dSetZero (fe,n6); + //dSetZero (v,n6); + for (i=0; ifacc[j]; + for (j=0; j<3; j++) fe[i*6+3+j] = body[i]->tacc[j]; + for (j=0; j<3; j++) v[i*6+j] = body[i]->lvel[j]; + for (j=0; j<3; j++) v[i*6+3+j] = body[i]->avel[j]; + } + + // this will be set to the velocity update + ALLOCA(dReal,vnew,n6*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (vnew == NULL) { + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + dSetZero (vnew,n6); + + // if there are constraints, compute cforce + if (m > 0) { + // create a constraint equation right hand side vector `c', a constraint + // force mixing vector `cfm', and LCP low and high bound vectors, and an + // 'findex' vector. + ALLOCA(dReal,c,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (c == NULL) { + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,cfm,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (cfm == NULL) { + UNALLOCA(c); + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,lo,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (lo == NULL) { + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,hi,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (hi == NULL) { + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(int,findex,m*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (findex == NULL) { + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + dSetZero (c,m); + dSetValue (cfm,m,world->global_cfm); + dSetValue (lo,m,-dInfinity); + dSetValue (hi,m, dInfinity); + for (i=0; iglobal_erp; + for (i=0; inode[0].body->tag; + Jinfo.J1a = Jinfo.J1l + 3; + if (joint[i]->node[1].body) { + Jinfo.J2l = J + nskip*ofs[i] + 6*joint[i]->node[1].body->tag; + Jinfo.J2a = Jinfo.J2l + 3; + } + else { + Jinfo.J2l = 0; + Jinfo.J2a = 0; + } + Jinfo.c = c + ofs[i]; + Jinfo.cfm = cfm + ofs[i]; + Jinfo.lo = lo + ofs[i]; + Jinfo.hi = hi + ofs[i]; + Jinfo.findex = findex + ofs[i]; + joint[i]->vtable->getInfo2 (joint[i],&Jinfo); + // adjust returned findex values for global index numbering + for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; + } + } + + // compute A = J*invM*J' +# ifdef TIMING + dTimerNow ("compute A"); +# endif + ALLOCA(dReal,JinvM,m*nskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (JinvM == NULL) { + UNALLOCA(J); + UNALLOCA(findex); + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + //dSetZero (JinvM,m*nskip); + dMultiply0 (JinvM,J,invM,m,n6,n6); + int mskip = dPAD(m); + ALLOCA(dReal,A,m*mskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (A == NULL) { + UNALLOCA(JinvM); + UNALLOCA(J); + UNALLOCA(findex); + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(vnew); + UNALLOCA(v); + UNALLOCA(fe); + UNALLOCA(invM); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + //dSetZero (A,m*mskip); + dMultiply2 (A,JinvM,J,m,n6,m); + + // add cfm to the diagonal of A + for (i=0; ilvel[j] = vnew[i*6+j]; + for (j=0; j<3; j++) body[i]->avel[j] = vnew[i*6+3+j]; + } + + // update the position and orientation from the new linear/angular velocity + // (over the given timestep) +#ifdef TIMING + dTimerNow ("update position"); +#endif + for (i=0; ifacc[0] = 0; + body[i]->facc[1] = 0; + body[i]->facc[2] = 0; + body[i]->facc[3] = 0; + body[i]->tacc[0] = 0; + body[i]->tacc[1] = 0; + body[i]->tacc[2] = 0; + body[i]->tacc[3] = 0; + } + +#ifdef TIMING + dTimerEnd(); + if (m > 0) dTimerReport (stdout,1); +#endif + + UNALLOCA(joint); + UNALLOCA(I); + UNALLOCA(invI); + UNALLOCA(info); + UNALLOCA(ofs); + UNALLOCA(invM); + UNALLOCA(fe); + UNALLOCA(v); + UNALLOCA(vnew); +} + +//**************************************************************************** +// an optimized version of dInternalStepIsland1() + +void dInternalStepIsland_x2 (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *_joint, int nj, dReal stepsize) +{ + int i,j,k; +#ifdef TIMING + dTimerStart("preprocessing"); +#endif + + dReal stepsize1 = dRecip(stepsize); + + // number all bodies in the body list - set their tag values + for (i=0; itag = i; + + // make a local copy of the joint array, because we might want to modify it. + // (the "dxJoint *const*" declaration says we're allowed to modify the joints + // but not the joint array, because the caller might need it unchanged). + ALLOCA(dxJoint*,joint,nj*sizeof(dxJoint*)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (joint == NULL) { + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + memcpy (joint,_joint,nj * sizeof(dxJoint*)); + + // for all bodies, compute the inertia tensor and its inverse in the global + // frame, and compute the rotational force and add it to the torque + // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. + // @@@ check computation of rotational force. + ALLOCA(dReal,I,3*nb*4*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (I == NULL) { + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,invI,3*nb*4*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (invI == NULL) { + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + + //dSetZero (I,3*nb*4); + //dSetZero (invI,3*nb*4); + for (i=0; imass.I,body[i]->R); + dMULTIPLY0_333 (I+i*12,body[i]->R,tmp); + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp,body[i]->invI,body[i]->R); + dMULTIPLY0_333 (invI+i*12,body[i]->R,tmp); + // compute rotational force + dMULTIPLY0_331 (tmp,I+i*12,body[i]->avel); + dCROSS (body[i]->tacc,-=,body[i]->avel,tmp); + } + + // add the gravity force to all bodies + for (i=0; iflags & dxBodyNoGravity)==0) { + body[i]->facc[0] += body[i]->mass.mass * world->gravity[0]; + body[i]->facc[1] += body[i]->mass.mass * world->gravity[1]; + body[i]->facc[2] += body[i]->mass.mass * world->gravity[2]; + } + } + + // get m = total constraint dimension, nub = number of unbounded variables. + // create constraint offset array and number-of-rows array for all joints. + // the constraints are re-ordered as follows: the purely unbounded + // constraints, the mixed unbounded + LCP constraints, and last the purely + // LCP constraints. this assists the LCP solver to put all unbounded + // variables at the start for a quick factorization. + // + // joints with m=0 are inactive and are removed from the joints array + // entirely, so that the code that follows does not consider them. + // also number all active joints in the joint list (set their tag values). + // inactive joints receive a tag value of -1. + + int m = 0; + ALLOCA(dxJoint::Info1,info,nj*sizeof(dxJoint::Info1)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (info == NULL) { + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(int,ofs,nj*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (ofs == NULL) { + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + for (i=0, j=0; jvtable->getInfo1 (joint[j],info+i); + dIASSERT (info[i].m >= 0 && info[i].m <= 6 && + info[i].nub >= 0 && info[i].nub <= info[i].m); + if (info[i].m > 0) { + joint[i] = joint[j]; + joint[i]->tag = i; + i++; + } + else { + joint[j]->tag = -1; + } + } + nj = i; + + // the purely unbounded constraints + for (i=0; i 0 && info[i].nub < info[i].m) { + ofs[i] = m; + m += info[i].m; + } + // the purely LCP constraints + for (i=0; i 0) { + // create a constraint equation right hand side vector `c', a constraint + // force mixing vector `cfm', and LCP low and high bound vectors, and an + // 'findex' vector. + ALLOCA(dReal,c,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (c == NULL) { + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,cfm,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (cfm == NULL) { + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,lo,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (lo == NULL) { + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(dReal,hi,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (hi == NULL) { + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + ALLOCA(int,findex,m*sizeof(int)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (findex == NULL) { + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + dSetZero (c,m); + dSetValue (cfm,m,world->global_cfm); + dSetValue (lo,m,-dInfinity); + dSetValue (hi,m, dInfinity); + for (i=0; iglobal_erp; + for (i=0; ivtable->getInfo2 (joint[i],&Jinfo); + // adjust returned findex values for global index numbering + for (j=0; j= 0) findex[ofs[i] + j] += ofs[i]; + } + } + + // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same + // format as J so we just go through the constraints in J multiplying by + // the appropriate scalars and matrices. +# ifdef TIMING + dTimerNow ("compute A"); +# endif + ALLOCA(dReal,JinvM,2*m*8*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (JinvM == NULL) { + UNALLOCA(J); + UNALLOCA(findex); + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + dSetZero (JinvM,2*m*8); + for (i=0; inode[0].body->tag; + dReal body_invMass = body[b]->invMass; + dReal *body_invI = invI + b*12; + dReal *Jsrc = J + 2*8*ofs[i]; + dReal *Jdst = JinvM + 2*8*ofs[i]; + for (j=info[i].m-1; j>=0; j--) { + for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; + dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); + Jsrc += 8; + Jdst += 8; + } + if (joint[i]->node[1].body) { + b = joint[i]->node[1].body->tag; + body_invMass = body[b]->invMass; + body_invI = invI + b*12; + for (j=info[i].m-1; j>=0; j--) { + for (k=0; k<3; k++) Jdst[k] = Jsrc[k] * body_invMass; + dMULTIPLY0_133 (Jdst+4,Jsrc+4,body_invI); + Jsrc += 8; + Jdst += 8; + } + } + } + + // now compute A = JinvM * J'. A's rows and columns are grouped by joint, + // i.e. in the same way as the rows of J. block (i,j) of A is only nonzero + // if joints i and j have at least one body in common. this fact suggests + // the algorithm used to fill A: + // + // for b = all bodies + // n = number of joints attached to body b + // for i = 1..n + // for j = i+1..n + // ii = actual joint number for i + // jj = actual joint number for j + // // (ii,jj) will be set to all pairs of joints around body b + // compute blockwise: A(ii,jj) += JinvM(ii) * J(jj)' + // + // this algorithm catches all pairs of joints that have at least one body + // in common. it does not compute the diagonal blocks of A however - + // another similar algorithm does that. + + int mskip = dPAD(m); + ALLOCA(dReal,A,m*mskip*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (A == NULL) { + UNALLOCA(JinvM); + UNALLOCA(J); + UNALLOCA(findex); + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + dSetZero (A,m*mskip); + for (i=0; ifirstjoint; n1; n1=n1->next) { + for (dxJointNode *n2=n1->next; n2; n2=n2->next) { + // get joint numbers and ensure ofs[j1] >= ofs[j2] + int j1 = n1->joint->tag; + int j2 = n2->joint->tag; + if (ofs[j1] < ofs[j2]) { + int tmp = j1; + j1 = j2; + j2 = tmp; + } + + // if either joint was tagged as -1 then it is an inactive (m=0) + // joint that should not be considered + if (j1==-1 || j2==-1) continue; + + // determine if body i is the 1st or 2nd body of joints j1 and j2 + int jb1 = (joint[j1]->node[1].body == body[i]); + int jb2 = (joint[j2]->node[1].body == body[i]); + // jb1/jb2 must be 0 for joints with only one body + dIASSERT(joint[j1]->node[1].body || jb1==0); + dIASSERT(joint[j2]->node[1].body || jb2==0); + + // set block of A + MultiplyAdd2_p8r (A + ofs[j1]*mskip + ofs[j2], + JinvM + 2*8*ofs[j1] + jb1*8*info[j1].m, + J + 2*8*ofs[j2] + jb2*8*info[j2].m, + info[j1].m,info[j2].m, mskip); + } + } + } + // compute diagonal blocks of A + for (i=0; inode[1].body) { + MultiplyAdd2_p8r (A + ofs[i]*(mskip+1), + JinvM + 2*8*ofs[i] + 8*info[i].m, + J + 2*8*ofs[i] + 8*info[i].m, + info[i].m,info[i].m, mskip); + } + } + + // add cfm to the diagonal of A + for (i=0; iinvMass; + dReal *body_invI = invI + i*12; + for (j=0; j<3; j++) tmp1[i*8+j] = body[i]->facc[j] * body_invMass + + body[i]->lvel[j] * stepsize1; + dMULTIPLY0_331 (tmp1 + i*8 + 4,body_invI,body[i]->tacc); + for (j=0; j<3; j++) tmp1[i*8+4+j] += body[i]->avel[j] * stepsize1; + } + // put J*tmp1 into rhs + ALLOCA(dReal,rhs,m*sizeof(dReal)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (rhs == NULL) { + UNALLOCA(tmp1); + UNALLOCA(A); + UNALLOCA(JinvM); + UNALLOCA(J); + UNALLOCA(findex); + UNALLOCA(hi); + UNALLOCA(lo); + UNALLOCA(cfm); + UNALLOCA(c); + UNALLOCA(cforce); + UNALLOCA(ofs); + UNALLOCA(info); + UNALLOCA(invI); + UNALLOCA(I); + UNALLOCA(joint); + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + return; + } +#endif + //dSetZero (rhs,m); + for (i=0; inode[0].body->tag, info[i].m); + if (joint[i]->node[1].body) { + MultiplyAdd0_p81 (rhs+ofs[i],JJ + 8*info[i].m, + tmp1 + 8*joint[i]->node[1].body->tag, info[i].m); + } + } + // complete rhs + for (i=0; inode[0].body; + dxBody* b2 = joint[i]->node[1].body; + dJointFeedback *fb = joint[i]->feedback; + + if (fb) { + // the user has requested feedback on the amount of force that this + // joint is applying to the bodies. we use a slightly slower + // computation that splits out the force components and puts them + // in the feedback structure. + dReal data1[8],data2[8]; + Multiply1_8q1 (data1, JJ, lambda+ofs[i], info[i].m); + dReal *cf1 = cforce + 8*b1->tag; + cf1[0] += (fb->f1[0] = data1[0]); + cf1[1] += (fb->f1[1] = data1[1]); + cf1[2] += (fb->f1[2] = data1[2]); + cf1[4] += (fb->t1[0] = data1[4]); + cf1[5] += (fb->t1[1] = data1[5]); + cf1[6] += (fb->t1[2] = data1[6]); + if (b2){ + Multiply1_8q1 (data2, JJ + 8*info[i].m, lambda+ofs[i], info[i].m); + dReal *cf2 = cforce + 8*b2->tag; + cf2[0] += (fb->f2[0] = data2[0]); + cf2[1] += (fb->f2[1] = data2[1]); + cf2[2] += (fb->f2[2] = data2[2]); + cf2[4] += (fb->t2[0] = data2[4]); + cf2[5] += (fb->t2[1] = data2[5]); + cf2[6] += (fb->t2[2] = data2[6]); + } + } + else { + // no feedback is required, let's compute cforce the faster way + MultiplyAdd1_8q1 (cforce + 8*b1->tag,JJ, lambda+ofs[i], info[i].m); + if (b2) { + MultiplyAdd1_8q1 (cforce + 8*b2->tag, + JJ + 8*info[i].m, lambda+ofs[i], info[i].m); + } + } + } + UNALLOCA(c); + UNALLOCA(cfm); + UNALLOCA(lo); + UNALLOCA(hi); + UNALLOCA(findex); + UNALLOCA(J); + UNALLOCA(JinvM); + UNALLOCA(A); + UNALLOCA(tmp1); + UNALLOCA(rhs); + UNALLOCA(lambda); + UNALLOCA(residual); + } + + // compute the velocity update +#ifdef TIMING + dTimerNow ("compute velocity update"); +#endif + + // add fe to cforce + for (i=0; ifacc[j]; + for (j=0; j<3; j++) cforce[i*8+4+j] += body[i]->tacc[j]; + } + // multiply cforce by stepsize + for (i=0; i < nb*8; i++) cforce[i] *= stepsize; + // add invM * cforce to the body velocity + for (i=0; iinvMass; + dReal *body_invI = invI + i*12; + for (j=0; j<3; j++) body[i]->lvel[j] += body_invMass * cforce[i*8+j]; + dMULTIPLYADD0_331 (body[i]->avel,body_invI,cforce+i*8+4); + } + + // update the position and orientation from the new linear/angular velocity + // (over the given timestep) +# ifdef TIMING + dTimerNow ("update position"); +# endif + for (i=0; ilvel[j]; + for (j=0; j<3; j++) tmp_vnew[i*6+3+j] = body[i]->avel[j]; + } + comparator.nextMatrix (tmp_vnew,nb*6,1,0,"vnew"); + UNALLOCA(tmp); +#endif + +#ifdef TIMING + dTimerNow ("tidy up"); +#endif + + // zero all force accumulators + for (i=0; ifacc[0] = 0; + body[i]->facc[1] = 0; + body[i]->facc[2] = 0; + body[i]->facc[3] = 0; + body[i]->tacc[0] = 0; + body[i]->tacc[1] = 0; + body[i]->tacc[2] = 0; + body[i]->tacc[3] = 0; + } + +#ifdef TIMING + dTimerEnd(); + if (m > 0) dTimerReport (stdout,1); +#endif + + UNALLOCA(joint); + UNALLOCA(I); + UNALLOCA(invI); + UNALLOCA(info); + UNALLOCA(ofs); + UNALLOCA(cforce); +} + +//**************************************************************************** + +void dInternalStepIsland (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *joint, int nj, dReal stepsize) +{ + +#ifdef dUSE_MALLOC_FOR_ALLOCA + dMemoryFlag = d_MEMORY_OK; +#endif + +#ifndef COMPARE_METHODS + dInternalStepIsland_x2 (world,body,nb,joint,nj,stepsize); + +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (dMemoryFlag == d_MEMORY_OUT_OF_MEMORY) { + REPORT_OUT_OF_MEMORY; + return; + } +#endif + +#endif + +#ifdef COMPARE_METHODS + int i; + + // save body state + ALLOCA(dxBody,state,nb*sizeof(dxBody)); +#ifdef dUSE_MALLOC_FOR_ALLOCA + if (state == NULL) { + dMemoryFlag = d_MEMORY_OUT_OF_MEMORY; + REPORT_OUT_OF_MEMORY; + return; + } +#endif + for (i=0; i 0) + autoEnableDepth = autodepth; + else + autoEnableDepth = 0; +} + +int dWorldGetAutoEnableDepthSF1 (dxWorld *world) +{ + return autoEnableDepth; +} + +//little bit of math.... the _sym_ functions assume the return matrix will be symmetric +static void +Multiply2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) +{ + int i, j; + dReal sum, *aa, *ad, *bb, *cc; + dIASSERT (p > 0 && A && B && C); + bb = B; + for (i = 0; i < p; i++) + { + //aa is going accross the matrix, ad down + aa = ad = A; + cc = C; + for (j = i; j < p; j++) + { + sum = bb[0] * cc[0]; + sum += bb[1] * cc[1]; + sum += bb[2] * cc[2]; + sum += bb[4] * cc[4]; + sum += bb[5] * cc[5]; + sum += bb[6] * cc[6]; + *(aa++) = *ad = sum; + ad += Askip; + cc += 8; + } + bb += 8; + A += Askip + 1; + C += 8; + } +} + +static void +MultiplyAdd2_sym_p8p (dReal * A, dReal * B, dReal * C, int p, int Askip) +{ + int i, j; + dReal sum, *aa, *ad, *bb, *cc; + dIASSERT (p > 0 && A && B && C); + bb = B; + for (i = 0; i < p; i++) + { + //aa is going accross the matrix, ad down + aa = ad = A; + cc = C; + for (j = i; j < p; j++) + { + sum = bb[0] * cc[0]; + sum += bb[1] * cc[1]; + sum += bb[2] * cc[2]; + sum += bb[4] * cc[4]; + sum += bb[5] * cc[5]; + sum += bb[6] * cc[6]; + *(aa++) += sum; + *ad += sum; + ad += Askip; + cc += 8; + } + bb += 8; + A += Askip + 1; + C += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void +Multiply0_p81 (dReal * A, dReal * B, dReal * C, int p) +{ + int i; + dIASSERT (p > 0 && A && B && C); + dReal sum; + for (i = p; i; i--) + { + sum = B[0] * C[0]; + sum += B[1] * C[1]; + sum += B[2] * C[2]; + sum += B[4] * C[4]; + sum += B[5] * C[5]; + sum += B[6] * C[6]; + *(A++) = sum; + B += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void +MultiplyAdd0_p81 (dReal * A, dReal * B, dReal * C, int p) +{ + int i; + dIASSERT (p > 0 && A && B && C); + dReal sum; + for (i = p; i; i--) + { + sum = B[0] * C[0]; + sum += B[1] * C[1]; + sum += B[2] * C[2]; + sum += B[4] * C[4]; + sum += B[5] * C[5]; + sum += B[6] * C[6]; + *(A++) += sum; + B += 8; + } +} + + +// this assumes the 4th and 8th rows of B are zero. + +static void +Multiply1_8q1 (dReal * A, dReal * B, dReal * C, int q) +{ + int k; + dReal sum; + dIASSERT (q > 0 && A && B && C); + sum = 0; + for (k = 0; k < q; k++) + sum += B[k * 8] * C[k]; + A[0] = sum; + sum = 0; + for (k = 0; k < q; k++) + sum += B[1 + k * 8] * C[k]; + A[1] = sum; + sum = 0; + for (k = 0; k < q; k++) + sum += B[2 + k * 8] * C[k]; + A[2] = sum; + sum = 0; + for (k = 0; k < q; k++) + sum += B[4 + k * 8] * C[k]; + A[4] = sum; + sum = 0; + for (k = 0; k < q; k++) + sum += B[5 + k * 8] * C[k]; + A[5] = sum; + sum = 0; + for (k = 0; k < q; k++) + sum += B[6 + k * 8] * C[k]; + A[6] = sum; +} + +//**************************************************************************** +// body rotation + +// return sin(x)/x. this has a singularity at 0 so special handling is needed +// for small arguments. + +static inline dReal +sinc (dReal x) +{ + // if |x| < 1e-4 then use a taylor series expansion. this two term expansion + // is actually accurate to one LS bit within this range if double precision + // is being used - so don't worry! + if (dFabs (x) < 1.0e-4) + return REAL (1.0) - x * x * REAL (0.166666666666666666667); + else + return dSin (x) / x; +} + + +// given a body b, apply its linear and angular rotation over the time +// interval h, thereby adjusting its position and orientation. + +static inline void +moveAndRotateBody (dxBody * b, dReal h) +{ + int j; + + // handle linear velocity + for (j = 0; j < 3; j++) + b->pos[j] += h * b->lvel[j]; + + if (b->flags & dxBodyFlagFiniteRotation) + { + dVector3 irv; // infitesimal rotation vector + dQuaternion q; // quaternion for finite rotation + + if (b->flags & dxBodyFlagFiniteRotationAxis) + { + // split the angular velocity vector into a component along the finite + // rotation axis, and a component orthogonal to it. + dVector3 frv, irv; // finite rotation vector + dReal k = dDOT (b->finite_rot_axis, b->avel); + frv[0] = b->finite_rot_axis[0] * k; + frv[1] = b->finite_rot_axis[1] * k; + frv[2] = b->finite_rot_axis[2] * k; + irv[0] = b->avel[0] - frv[0]; + irv[1] = b->avel[1] - frv[1]; + irv[2] = b->avel[2] - frv[2]; + + // make a rotation quaternion q that corresponds to frv * h. + // compare this with the full-finite-rotation case below. + h *= REAL (0.5); + dReal theta = k * h; + q[0] = dCos (theta); + dReal s = sinc (theta) * h; + q[1] = frv[0] * s; + q[2] = frv[1] * s; + q[3] = frv[2] * s; + } + else + { + // make a rotation quaternion q that corresponds to w * h + dReal wlen = dSqrt (b->avel[0] * b->avel[0] + b->avel[1] * b->avel[1] + b->avel[2] * b->avel[2]); + h *= REAL (0.5); + dReal theta = wlen * h; + q[0] = dCos (theta); + dReal s = sinc (theta) * h; + q[1] = b->avel[0] * s; + q[2] = b->avel[1] * s; + q[3] = b->avel[2] * s; + } + + // do the finite rotation + dQuaternion q2; + dQMultiply0 (q2, q, b->q); + for (j = 0; j < 4; j++) + b->q[j] = q2[j]; + + // do the infitesimal rotation if required + if (b->flags & dxBodyFlagFiniteRotationAxis) + { + dReal dq[4]; + dWtoDQ (irv, b->q, dq); + for (j = 0; j < 4; j++) + b->q[j] += h * dq[j]; + } + } + else + { + // the normal way - do an infitesimal rotation + dReal dq[4]; + dWtoDQ (b->avel, b->q, dq); + for (j = 0; j < 4; j++) + b->q[j] += h * dq[j]; + } + + // normalize the quaternion and convert it to a rotation matrix + dNormalize4 (b->q); + dQtoR (b->q, b->R); + + // notify all attached geoms that this body has moved + for (dxGeom * geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + +//**************************************************************************** +//This is an implementation of the iterated/relaxation algorithm. +//Here is a quick overview of the algorithm per Sergi Valverde's posts to the +//mailing list: +// +// for i=0..N-1 do +// for c = 0..C-1 do +// Solve constraint c-th +// Apply forces to constraint bodies +// next +// next +// Integrate bodies + +void +dInternalStepFast (dxWorld * world, dxBody * body[2], dReal * GI[2], dReal * GinvI[2], dxJoint * joint, dxJoint::Info1 info, dxJoint::Info2 Jinfo, dReal stepsize) +{ + int i, j, k; +# ifdef TIMING + dTimerNow ("constraint preprocessing"); +# endif + + dReal stepsize1 = dRecip (stepsize); + + int m = info.m; + // nothing to do if no constraints. + if (m <= 0) + return; + + int nub = 0; + if (info.nub == info.m) + nub = m; + + // compute A = J*invM*J'. first compute JinvM = J*invM. this has the same + // format as J so we just go through the constraints in J multiplying by + // the appropriate scalars and matrices. +# ifdef TIMING + dTimerNow ("compute A"); +# endif + dReal JinvM[2 * 6 * 8]; + //dSetZero (JinvM, 2 * m * 8); + + dReal *Jsrc = Jinfo.J1l; + dReal *Jdst = JinvM; + if (body[0]) + { + for (j = m - 1; j >= 0; j--) + { + for (k = 0; k < 3; k++) + Jdst[k] = Jsrc[k] * body[0]->invMass; + dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[0]); + Jsrc += 8; + Jdst += 8; + } + } + if (body[1]) + { + Jsrc = Jinfo.J2l; + Jdst = JinvM + 8 * m; + for (j = m - 1; j >= 0; j--) + { + for (k = 0; k < 3; k++) + Jdst[k] = Jsrc[k] * body[1]->invMass; + dMULTIPLY0_133 (Jdst + 4, Jsrc + 4, GinvI[1]); + Jsrc += 8; + Jdst += 8; + } + } + + + // now compute A = JinvM * J'. + int mskip = dPAD (m); + dReal A[6 * 8]; + //dSetZero (A, 6 * 8); + + if (body[0]) { + Multiply2_sym_p8p (A, JinvM, Jinfo.J1l, m, mskip); + if (body[1]) + MultiplyAdd2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, + m, mskip); + } else { + if (body[1]) + Multiply2_sym_p8p (A, JinvM + 8 * m, Jinfo.J2l, + m, mskip); + } + + // add cfm to the diagonal of A + for (i = 0; i < m; i++) + A[i * mskip + i] += Jinfo.cfm[i] * stepsize1; + + // compute the right hand side `rhs' +# ifdef TIMING + dTimerNow ("compute rhs"); +# endif + dReal tmp1[16]; + //dSetZero (tmp1, 16); + // put v/h + invM*fe into tmp1 + for (i = 0; i < 2; i++) + { + if (!body[i]) + continue; + for (j = 0; j < 3; j++) + tmp1[i * 8 + j] = body[i]->facc[j] * body[i]->invMass + body[i]->lvel[j] * stepsize1; + dMULTIPLY0_331 (tmp1 + i * 8 + 4, GinvI[i], body[i]->tacc); + for (j = 0; j < 3; j++) + tmp1[i * 8 + 4 + j] += body[i]->avel[j] * stepsize1; + } + // put J*tmp1 into rhs + dReal rhs[6]; + //dSetZero (rhs, 6); + + if (body[0]) { + Multiply0_p81 (rhs, Jinfo.J1l, tmp1, m); + if (body[1]) + MultiplyAdd0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); + } else { + if (body[1]) + Multiply0_p81 (rhs, Jinfo.J2l, tmp1 + 8, m); + } + + // complete rhs + for (i = 0; i < m; i++) + rhs[i] = Jinfo.c[i] * stepsize1 - rhs[i]; + +#ifdef SLOW_LCP + // solve the LCP problem and get lambda. + // this will destroy A but that's okay +# ifdef TIMING + dTimerNow ("solving LCP problem"); +# endif + dReal *lambda = (dReal *) ALLOCA (m * sizeof (dReal)); + dReal *residual = (dReal *) ALLOCA (m * sizeof (dReal)); + dReal lo[6], hi[6]; + memcpy (lo, Jinfo.lo, m * sizeof (dReal)); + memcpy (hi, Jinfo.hi, m * sizeof (dReal)); + dSolveLCP (m, A, lambda, rhs, residual, nub, lo, hi, Jinfo.findex); +#endif + + // LCP Solver replacement: + // This algorithm goes like this: + // Do a straightforward LDLT factorization of the matrix A, solving for + // A*x = rhs + // For each x[i] that is outside of the bounds of lo[i] and hi[i], + // clamp x[i] into that range. + // Substitute into A the now known x's + // subtract the residual away from the rhs. + // Remove row and column i from L, updating the factorization + // place the known x's at the end of the array, keeping up with location in p + // Repeat until all constraints have been clamped or all are within bounds + // + // This is probably only faster in the single joint case where only one repeat is + // the norm. + +#ifdef FAST_FACTOR + // factorize A (L*D*L'=A) +# ifdef TIMING + dTimerNow ("factorize A"); +# endif + dReal d[6]; + dReal L[6 * 8]; + memcpy (L, A, m * mskip * sizeof (dReal)); + dFactorLDLT (L, d, m, mskip); + + // compute lambda +# ifdef TIMING + dTimerNow ("compute lambda"); +# endif + + int left = m; //constraints left to solve. + int remove[6]; + dReal lambda[6]; + dReal x[6]; + int p[6]; + for (i = 0; i < 6; i++) + p[i] = i; + while (true) + { + memcpy (x, rhs, left * sizeof (dReal)); + dSolveLDLT (L, d, x, left, mskip); + + int fixed = 0; + for (i = 0; i < left; i++) + { + j = p[i]; + remove[i] = false; + // This isn't the exact same use of findex as dSolveLCP.... since x[findex] + // may change after I've already clamped x[i], but it should be close + if (Jinfo.findex[j] > -1) + { + dReal f = fabs (Jinfo.hi[j] * x[p[Jinfo.findex[j]]]); + if (x[i] > f) + x[i] = f; + else if (x[i] < -f) + x[i] = -f; + else + continue; + } + else + { + if (x[i] > Jinfo.hi[j]) + x[i] = Jinfo.hi[j]; + else if (x[i] < Jinfo.lo[j]) + x[i] = Jinfo.lo[j]; + else + continue; + } + remove[i] = true; + fixed++; + } + if (fixed == 0 || fixed == left) //no change or all constraints solved + break; + + for (i = 0; i < left; i++) //sub in to right hand side. + if (remove[i]) + for (j = 0; j < left; j++) + if (!remove[j]) + rhs[j] -= A[j * mskip + i] * x[i]; + + for (int r = left - 1; r >= 0; r--) //eliminate row/col for fixed variables + { + if (remove[r]) + { + //dRemoveLDLT adapted for use without row pointers. + if (r == left - 1) + { + left--; + continue; // deleting last row/col is easy + } + else if (r == 0) + { + dReal a[6]; + for (i = 0; i < left; i++) + a[i] = -A[i * mskip]; + a[0] += REAL (1.0); + dLDLTAddTL (L, d, a, left, mskip); + } + else + { + dReal t[6]; + dReal a[6]; + for (i = 0; i < r; i++) + t[i] = L[r * mskip + i] / d[i]; + for (i = 0; i < left - r; i++) + a[i] = dDot (L + (r + i) * mskip, t, r) - A[(r + i) * mskip + r]; + a[0] += REAL (1.0); + dLDLTAddTL (L + r * mskip + r, d + r, a, left - r, mskip); + } + + dRemoveRowCol (L, left, mskip, r); + //end dRemoveLDLT + + left--; + if (r < (left - 1)) + { + dReal tx = x[r]; + memmove (d + r, d + r + 1, (left - r) * sizeof (dReal)); + memmove (rhs + r, rhs + r + 1, (left - r) * sizeof (dReal)); + //x will get written over by rhs anyway, no need to move it around + //just store the fixed value we just discovered in it. + x[left] = tx; + for (i = 0; i < m; i++) + if (p[i] > r && p[i] <= left) + p[i]--; + p[r] = left; + } + } + } + } + + for (i = 0; i < m; i++) + lambda[i] = x[p[i]]; +# endif + // compute the constraint force `cforce' +# ifdef TIMING + dTimerNow ("compute constraint force"); +#endif + + // compute cforce = J'*lambda + dJointFeedback *fb = joint->feedback; + dReal cforce[16]; + //dSetZero (cforce, 16); + + if (fb) + { + // the user has requested feedback on the amount of force that this + // joint is applying to the bodies. we use a slightly slower + // computation that splits out the force components and puts them + // in the feedback structure. + dReal data1[8], data2[8]; + if (body[0]) + { + Multiply1_8q1 (data1, Jinfo.J1l, lambda, m); + dReal *cf1 = cforce; + cf1[0] = (fb->f1[0] = data1[0]); + cf1[1] = (fb->f1[1] = data1[1]); + cf1[2] = (fb->f1[2] = data1[2]); + cf1[4] = (fb->t1[0] = data1[4]); + cf1[5] = (fb->t1[1] = data1[5]); + cf1[6] = (fb->t1[2] = data1[6]); + } + if (body[1]) + { + Multiply1_8q1 (data2, Jinfo.J2l, lambda, m); + dReal *cf2 = cforce + 8; + cf2[0] = (fb->f2[0] = data2[0]); + cf2[1] = (fb->f2[1] = data2[1]); + cf2[2] = (fb->f2[2] = data2[2]); + cf2[4] = (fb->t2[0] = data2[4]); + cf2[5] = (fb->t2[1] = data2[5]); + cf2[6] = (fb->t2[2] = data2[6]); + } + } + else + { + // no feedback is required, let's compute cforce the faster way + if (body[0]) + Multiply1_8q1 (cforce, Jinfo.J1l, lambda, m); + if (body[1]) + Multiply1_8q1 (cforce + 8, Jinfo.J2l, lambda, m); + } + + for (i = 0; i < 2; i++) + { + if (!body[i]) + continue; + for (j = 0; j < 3; j++) + { + body[i]->facc[j] += cforce[i * 8 + j]; + body[i]->tacc[j] += cforce[i * 8 + 4 + j]; + } + } +} + +void +dInternalStepIslandFast (dxWorld * world, dxBody * const *bodies, int nb, dxJoint * const *_joints, int nj, dReal stepsize, int maxiterations) +{ +# ifdef TIMING + dTimerNow ("preprocessing"); +# endif + dxBody *bodyPair[2], *body; + dReal *GIPair[2], *GinvIPair[2]; + dxJoint *joint; + int iter, b, j, i; + dReal ministep = stepsize / maxiterations; + + // make a local copy of the joint array, because we might want to modify it. + // (the "dxJoint *const*" declaration says we're allowed to modify the joints + // but not the joint array, because the caller might need it unchanged). + dxJoint **joints = (dxJoint **) ALLOCA (nj * sizeof (dxJoint *)); + memcpy (joints, _joints, nj * sizeof (dxJoint *)); + + // get m = total constraint dimension, nub = number of unbounded variables. + // create constraint offset array and number-of-rows array for all joints. + // the constraints are re-ordered as follows: the purely unbounded + // constraints, the mixed unbounded + LCP constraints, and last the purely + // LCP constraints. this assists the LCP solver to put all unbounded + // variables at the start for a quick factorization. + // + // joints with m=0 are inactive and are removed from the joints array + // entirely, so that the code that follows does not consider them. + // also number all active joints in the joint list (set their tag values). + // inactive joints receive a tag value of -1. + + int m = 0; + dxJoint::Info1 * info = (dxJoint::Info1 *) ALLOCA (nj * sizeof (dxJoint::Info1)); + int *ofs = (int *) ALLOCA (nj * sizeof (int)); + for (i = 0, j = 0; j < nj; j++) + { // i=dest, j=src + joints[j]->vtable->getInfo1 (joints[j], info + i); + dIASSERT (info[i].m >= 0 && info[i].m <= 6 && info[i].nub >= 0 && info[i].nub <= info[i].m); + if (info[i].m > 0) + { + joints[i] = joints[j]; + joints[i]->tag = i; + i++; + } + else + { + joints[j]->tag = -1; + } + } + nj = i; + + // the purely unbounded constraints + for (i = 0; i < nj; i++) + { + ofs[i] = m; + m += info[i].m; + } + dReal *c = NULL; + dReal *cfm = NULL; + dReal *lo = NULL; + dReal *hi = NULL; + int *findex = NULL; + + dReal *J = NULL; + dxJoint::Info2 * Jinfo = NULL; + + if (m) + { + // create a constraint equation right hand side vector `c', a constraint + // force mixing vector `cfm', and LCP low and high bound vectors, and an + // 'findex' vector. + c = (dReal *) ALLOCA (m * sizeof (dReal)); + cfm = (dReal *) ALLOCA (m * sizeof (dReal)); + lo = (dReal *) ALLOCA (m * sizeof (dReal)); + hi = (dReal *) ALLOCA (m * sizeof (dReal)); + findex = (int *) ALLOCA (m * sizeof (int)); + dSetZero (c, m); + dSetValue (cfm, m, world->global_cfm); + dSetValue (lo, m, -dInfinity); + dSetValue (hi, m, dInfinity); + for (i = 0; i < m; i++) + findex[i] = -1; + + // get jacobian data from constraints. a (2*m)x8 matrix will be created + // to store the two jacobian blocks from each constraint. it has this + // format: + // + // l l l 0 a a a 0 \ . + // l l l 0 a a a 0 }-- jacobian body 1 block for joint 0 (3 rows) + // l l l 0 a a a 0 / + // l l l 0 a a a 0 \ . + // l l l 0 a a a 0 }-- jacobian body 2 block for joint 0 (3 rows) + // l l l 0 a a a 0 / + // l l l 0 a a a 0 }--- jacobian body 1 block for joint 1 (1 row) + // l l l 0 a a a 0 }--- jacobian body 2 block for joint 1 (1 row) + // etc... + // + // (lll) = linear jacobian data + // (aaa) = angular jacobian data + // +# ifdef TIMING + dTimerNow ("create J"); +# endif + J = (dReal *) ALLOCA (2 * m * 8 * sizeof (dReal)); + dSetZero (J, 2 * m * 8); + Jinfo = (dxJoint::Info2 *) ALLOCA (nj * sizeof (dxJoint::Info2)); + for (i = 0; i < nj; i++) + { + Jinfo[i].rowskip = 8; + Jinfo[i].fps = dRecip (stepsize); + Jinfo[i].erp = world->global_erp; + Jinfo[i].J1l = J + 2 * 8 * ofs[i]; + Jinfo[i].J1a = Jinfo[i].J1l + 4; + Jinfo[i].J2l = Jinfo[i].J1l + 8 * info[i].m; + Jinfo[i].J2a = Jinfo[i].J2l + 4; + Jinfo[i].c = c + ofs[i]; + Jinfo[i].cfm = cfm + ofs[i]; + Jinfo[i].lo = lo + ofs[i]; + Jinfo[i].hi = hi + ofs[i]; + Jinfo[i].findex = findex + ofs[i]; + //joints[i]->vtable->getInfo2 (joints[i], Jinfo+i); + } + + } + + dReal *saveFacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); + dReal *saveTacc = (dReal *) ALLOCA (nb * 4 * sizeof (dReal)); + dReal *globalI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); + dReal *globalInvI = (dReal *) ALLOCA (nb * 12 * sizeof (dReal)); + for (b = 0; b < nb; b++) + { + for (i = 0; i < 4; i++) + { + saveFacc[b * 4 + i] = bodies[b]->facc[i]; + saveTacc[b * 4 + i] = bodies[b]->tacc[i]; + } + bodies[b]->tag = b; + } + + for (iter = 0; iter < maxiterations; iter++) + { +# ifdef TIMING + dTimerNow ("applying inertia and gravity"); +# endif + dReal tmp[12] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + for (b = 0; b < nb; b++) + { + body = bodies[b]; + + // for all bodies, compute the inertia tensor and its inverse in the global + // frame, and compute the rotational force and add it to the torque + // accumulator. I and invI are vertically stacked 3x4 matrices, one per body. + // @@@ check computation of rotational force. + + // compute inertia tensor in global frame + dMULTIPLY2_333 (tmp, body->mass.I, body->R); + dMULTIPLY0_333 (globalI + b * 12, body->R, tmp); + // compute inverse inertia tensor in global frame + dMULTIPLY2_333 (tmp, body->invI, body->R); + dMULTIPLY0_333 (globalInvI + b * 12, body->R, tmp); + + for (i = 0; i < 4; i++) + body->tacc[i] = saveTacc[b * 4 + i]; + // compute rotational force + dMULTIPLY0_331 (tmp, globalI + b * 12, body->avel); + dCROSS (body->tacc, -=, body->avel, tmp); + + // add the gravity force to all bodies + if ((body->flags & dxBodyNoGravity) == 0) + { + body->facc[0] = saveFacc[b * 4 + 0] + body->mass.mass * world->gravity[0]; + body->facc[1] = saveFacc[b * 4 + 1] + body->mass.mass * world->gravity[1]; + body->facc[2] = saveFacc[b * 4 + 2] + body->mass.mass * world->gravity[2]; + body->facc[3] = 0; + } else { + body->facc[0] = saveFacc[b * 4 + 0]; + body->facc[1] = saveFacc[b * 4 + 1]; + body->facc[2] = saveFacc[b * 4 + 2]; + body->facc[3] = 0; + } + + } + +#ifdef RANDOM_JOINT_ORDER +#ifdef TIMING + dTimerNow ("randomizing joint order"); +#endif + //randomize the order of the joints by looping through the array + //and swapping the current joint pointer with a random one before it. + for (j = 0; j < nj; j++) + { + joint = joints[j]; + dxJoint::Info1 i1 = info[j]; + dxJoint::Info2 i2 = Jinfo[j]; + const int r = dRandInt(j+1); + joints[j] = joints[r]; + info[j] = info[r]; + Jinfo[j] = Jinfo[r]; + joints[r] = joint; + info[r] = i1; + Jinfo[r] = i2; + } +#endif + + //now iterate through the random ordered joint array we created. + for (j = 0; j < nj; j++) + { +#ifdef TIMING + dTimerNow ("setting up joint"); +#endif + joint = joints[j]; + bodyPair[0] = joint->node[0].body; + bodyPair[1] = joint->node[1].body; + + if (bodyPair[0] && (bodyPair[0]->flags & dxBodyDisabled)) + bodyPair[0] = 0; + if (bodyPair[1] && (bodyPair[1]->flags & dxBodyDisabled)) + bodyPair[1] = 0; + + //if this joint is not connected to any enabled bodies, skip it. + if (!bodyPair[0] && !bodyPair[1]) + continue; + + if (bodyPair[0]) + { + GIPair[0] = globalI + bodyPair[0]->tag * 12; + GinvIPair[0] = globalInvI + bodyPair[0]->tag * 12; + } + if (bodyPair[1]) + { + GIPair[1] = globalI + bodyPair[1]->tag * 12; + GinvIPair[1] = globalInvI + bodyPair[1]->tag * 12; + } + + joints[j]->vtable->getInfo2 (joints[j], Jinfo + j); + + //dInternalStepIslandFast is an exact copy of the old routine with one + //modification: the calculated forces are added back to the facc and tacc + //vectors instead of applying them to the bodies and moving them. + if (info[j].m > 0) + { + dInternalStepFast (world, bodyPair, GIPair, GinvIPair, joint, info[j], Jinfo[j], ministep); + } + } + // } +# ifdef TIMING + dTimerNow ("moving bodies"); +# endif + //Now we can simulate all the free floating bodies, and move them. + for (b = 0; b < nb; b++) + { + body = bodies[b]; + + for (i = 0; i < 4; i++) + { + body->facc[i] *= ministep; + body->tacc[i] *= ministep; + } + + //apply torque + dMULTIPLYADD0_331 (body->avel, globalInvI + b * 12, body->tacc); + + //apply force + for (i = 0; i < 3; i++) + body->lvel[i] += body->invMass * body->facc[i]; + + //move It! + moveAndRotateBody (body, ministep); + } + } + for (b = 0; b < nb; b++) + for (j = 0; j < 4; j++) + bodies[b]->facc[j] = bodies[b]->tacc[j] = 0; +} + + +#ifdef NO_ISLANDS + +// Since the iterative algorithm doesn't care about islands of bodies, this is a +// faster algorithm that just sends it all the joints and bodies in one array. +// It's downfall is it's inability to handle disabled bodies as well as the old one. +static void +processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) +{ + // nothing to do if no bodies + if (world->nb <= 0) + return; + + dInternalHandleAutoDisabling (world,stepsize); + +# ifdef TIMING + dTimerStart ("creating joint and body arrays"); +# endif + dxBody **bodies, *body; + dxJoint **joints, *joint; + joints = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); + bodies = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); + + int nj = 0; + for (joint = world->firstjoint; joint; joint = (dxJoint *) joint->next) + joints[nj++] = joint; + + int nb = 0; + for (body = world->firstbody; body; body = (dxBody *) body->next) + bodies[nb++] = body; + + dInternalStepIslandFast (world, bodies, nb, joints, nj, stepsize, maxiterations); +# ifdef TIMING + dTimerEnd (); + dTimerReport (stdout, 1); +# endif +} + +#else + +//**************************************************************************** +// island processing + +// this groups all joints and bodies in a world into islands. all objects +// in an island are reachable by going through connected bodies and joints. +// each island can be simulated separately. +// note that joints that are not attached to anything will not be included +// in any island, an so they do not affect the simulation. +// +// this function starts new island from unvisited bodies. however, it will +// never start a new islands from a disabled body. thus islands of disabled +// bodies will not be included in the simulation. disabled bodies are +// re-enabled if they are found to be part of an active island. + +static void +processIslandsFast (dxWorld * world, dReal stepsize, int maxiterations) +{ +#ifdef TIMING + dTimerStart ("Island Setup"); +#endif + dxBody *b, *bb, **body; + dxJoint *j, **joint; + + // nothing to do if no bodies + if (world->nb <= 0) + return; + + dInternalHandleAutoDisabling (world,stepsize); + + // make arrays for body and joint lists (for a single island) to go into + body = (dxBody **) ALLOCA (world->nb * sizeof (dxBody *)); + joint = (dxJoint **) ALLOCA (world->nj * sizeof (dxJoint *)); + int bcount = 0; // number of bodies in `body' + int jcount = 0; // number of joints in `joint' + int tbcount = 0; + int tjcount = 0; + + // set all body/joint tags to 0 + for (b = world->firstbody; b; b = (dxBody *) b->next) + b->tag = 0; + for (j = world->firstjoint; j; j = (dxJoint *) j->next) + j->tag = 0; + + // allocate a stack of unvisited bodies in the island. the maximum size of + // the stack can be the lesser of the number of bodies or joints, because + // new bodies are only ever added to the stack by going through untagged + // joints. all the bodies in the stack must be tagged! + int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; + dxBody **stack = (dxBody **) ALLOCA (stackalloc * sizeof (dxBody *)); + int *autostack = (int *) ALLOCA (stackalloc * sizeof (int)); + + for (bb = world->firstbody; bb; bb = (dxBody *) bb->next) + { +#ifdef TIMING + dTimerNow ("Island Processing"); +#endif + // get bb = the next enabled, untagged body, and tag it + if (bb->tag || (bb->flags & dxBodyDisabled)) + continue; + bb->tag = 1; + + // tag all bodies and joints starting from bb. + int stacksize = 0; + int autoDepth = autoEnableDepth; + b = bb; + body[0] = bb; + bcount = 1; + jcount = 0; + goto quickstart; + while (stacksize > 0) + { + b = stack[--stacksize]; // pop body off stack + autoDepth = autostack[stacksize]; + body[bcount++] = b; // put body on body list + quickstart: + + // traverse and tag all body's joints, add untagged connected bodies + // to stack + for (dxJointNode * n = b->firstjoint; n; n = n->next) + { + if (!n->joint->tag) + { + int thisDepth = autoEnableDepth; + n->joint->tag = 1; + joint[jcount++] = n->joint; + if (n->body && !n->body->tag) + { + if (n->body->flags & dxBodyDisabled) + thisDepth = autoDepth - 1; + if (thisDepth < 0) + continue; + n->body->flags &= ~dxBodyDisabled; + n->body->tag = 1; + autostack[stacksize] = thisDepth; + stack[stacksize++] = n->body; + } + } + } + dIASSERT (stacksize <= world->nb); + dIASSERT (stacksize <= world->nj); + } + + // now do something with body and joint lists + dInternalStepIslandFast (world, body, bcount, joint, jcount, stepsize, maxiterations); + + // what we've just done may have altered the body/joint tag values. + // we must make sure that these tags are nonzero. + // also make sure all bodies are in the enabled state. + int i; + for (i = 0; i < bcount; i++) + { + body[i]->tag = 1; + body[i]->flags &= ~dxBodyDisabled; + } + for (i = 0; i < jcount; i++) + joint[i]->tag = 1; + + tbcount += bcount; + tjcount += jcount; + } + +#ifdef TIMING + dMessage(0, "Total joints processed: %i, bodies: %i", tjcount, tbcount); +#endif + + // if debugging, check that all objects (except for disabled bodies, + // unconnected joints, and joints that are connected to disabled bodies) + // were tagged. +# ifndef dNODEBUG + for (b = world->firstbody; b; b = (dxBody *) b->next) + { + if (b->flags & dxBodyDisabled) + { + if (b->tag) + dDebug (0, "disabled body tagged"); + } + else + { + if (!b->tag) + dDebug (0, "enabled body not tagged"); + } + } + for (j = world->firstjoint; j; j = (dxJoint *) j->next) + { + if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled) == 0) || (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled) == 0)) + { + if (!j->tag) + dDebug (0, "attached enabled joint not tagged"); + } + else + { + if (j->tag) + dDebug (0, "unattached or disabled joint tagged"); + } + } +# endif + +# ifdef TIMING + dTimerEnd (); + dTimerReport (stdout, 1); +# endif +} + +#endif + + +void dWorldStepFast1 (dWorldID w, dReal stepsize, int maxiterations) +{ + dUASSERT (w, "bad world argument"); + dUASSERT (stepsize > 0, "stepsize must be > 0"); + processIslandsFast (w, stepsize, maxiterations); +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_timer.cpp b/src/external/open_dynamics_engine-ef/ode/ode_timer.cpp new file mode 100644 index 00000000..38997392 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_timer.cpp @@ -0,0 +1,427 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* + +TODO +---- + +* gettimeofday() and the pentium time stamp counter return the real time, + not the process time. fix this somehow! + +*/ + +#include "ode/ode_common.h" +#include "ode/ode_timer.h" + +// misc defines +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// implementation for windows based on the multimedia performance counter. + +// #ifdef WIN32 +#if _WIN32 || _WIN64 + + +#include "windows.h" + +static inline void getClockCount (unsigned long cc[2]) +{ + LARGE_INTEGER a; + QueryPerformanceCounter (&a); + cc[0] = a.LowPart; + cc[1] = a.HighPart; +} + + +static inline void serialize() +{ +} + + +static inline double loadClockCount (unsigned long cc[2]) +{ + LARGE_INTEGER a; + a.LowPart = cc[0]; + a.HighPart = cc[1]; + return double(a.QuadPart); +} + + +double dTimerResolution() +{ + return 1.0/dTimerTicksPerSecond(); +} + + +double dTimerTicksPerSecond() +{ + static int query=0; + static double hz=0.0; + if (!query) { + LARGE_INTEGER a; + QueryPerformanceFrequency (&a); + hz = double(a.QuadPart); + query = 1; + } + return hz; +} + + +// Gonna go ahead and deactivate this funky assembly business since we get by +// fine without it on arm and elsewhere elsewhere. + +// //**************************************************************************** +// // implementation based on the pentium time stamp counter. the timer functions +// // can be serializing or non-serializing. serializing will ensure that all +// // instructions have executed and data has been written back before the cpu +// // time stamp counter is read. the CPUID instruction is used to serialize. + +// #if defined(PENTIUM) && !defined(WIN32) + +// // we need to know the clock rate so that the timing function can report +// // accurate times. this number only needs to be set accurately if we're +// // doing performance tests and care about real-world time numbers - otherwise, +// // just ignore this. i have not worked out how to determine this number +// // automatically yet. + +// #define PENTIUM_HZ (500e6) + +// static inline void getClockCount (unsigned long cc[2]) +// { +// #ifndef SYS64bits +// asm volatile ( +// "rdtsc\n" +// "movl %%eax,(%%esi)\n" +// "movl %%edx,4(%%esi)\n" +// : : "S" (cc) : "%eax","%edx","cc","memory"); +// #else +// asm volatile ( +// "rdtsc\n" +// "movl %%eax,(%%rsi)\n" +// "movl %%edx,4(%%rsi)\n" +// : : "S" (cc) : "%eax","%edx","cc","memory"); +// #endif +// } + + +// static inline void serialize() +// { +// #ifndef SYS64bits +// asm volatile ( + +// // PATCH TO GET WORKING ON INTEL MAC +// //"mov $0,%%eax\n" +// "mov %%ebx,%%edi\n" +// "cpuid\n" +// //: : : "%eax","%ebx","%ecx","%edx","cc","memory"); +// : : : "%eax","%edi","%ecx","%edx","cc","memory"); +// #else +// asm volatile ( +// "mov $0,%%rax\n" +// "cpuid\n" +// : : : "%rax","%rbx","%rcx","%rdx","cc","memory"); +// #endif +// } + + +// static inline double loadClockCount (unsigned long a[2]) +// { +// double ret; +// #ifndef SYS64bits +// asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : +// "cc","memory"); +// #else +// asm volatile ("fildll %1; fstpl %0" : "=m" (ret) : "m" (a[0]) : +// "cc","memory"); +// #endif +// return ret; +// } + + +// double dTimerResolution() +// { +// return 1.0/PENTIUM_HZ; +// } + + +// double dTimerTicksPerSecond() +// { +// return PENTIUM_HZ; +// } + +// #endif + +// //**************************************************************************** +// // otherwise, do the implementation based on gettimeofday(). + +// #if !defined(PENTIUM) && !defined(WIN32) + +#else + +#ifndef macintosh + +#include +#include + + +static inline void getClockCount (unsigned long cc[2]) +{ + struct timeval tv; + gettimeofday (&tv,0); + cc[0] = tv.tv_usec; + cc[1] = tv.tv_sec; +} + +#else // macintosh + +#include +#include + +static inline void getClockCount (unsigned long cc[2]) +{ + UnsignedWide ms; + Microseconds (&ms); + cc[1] = ms.lo / 1000000; + cc[0] = ms.lo - ( cc[1] * 1000000 ); +} + +#endif + + +static inline void serialize() +{ +} + + +static inline double loadClockCount (unsigned long a[2]) +{ + return a[1]*1.0e6 + a[0]; +} + + +double dTimerResolution() +{ + unsigned long cc1[2],cc2[2]; + getClockCount (cc1); + do { + getClockCount (cc2); + } + while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); + do { + getClockCount (cc1); + } + while (cc1[0]==cc2[0] && cc1[1]==cc2[1]); + double t1 = loadClockCount (cc1); + double t2 = loadClockCount (cc2); + return (t1-t2) / dTimerTicksPerSecond(); +} + + +double dTimerTicksPerSecond() +{ + return 1000000; +} + +#endif + +//**************************************************************************** +// stop watches + +void dStopwatchReset (dStopwatch *s) +{ + s->time = 0; + s->cc[0] = 0; + s->cc[1] = 0; +} + + +void dStopwatchStart (dStopwatch *s) +{ + serialize(); + getClockCount (s->cc); +} + + +void dStopwatchStop (dStopwatch *s) +{ + unsigned long cc[2]; + serialize(); + getClockCount (cc); + double t1 = loadClockCount (s->cc); + double t2 = loadClockCount (cc); + s->time += t2-t1; +} + + +double dStopwatchTime (dStopwatch *s) +{ + return s->time / dTimerTicksPerSecond(); +} + +//**************************************************************************** +// code timers + +// maximum number of events to record +#define MAXNUM 100 + +static int num = 0; // number of entries used in event array +static struct { + unsigned long cc[2]; // clock counts + double total_t; // total clocks used in this slot. + double total_p; // total percentage points used in this slot. + int count; // number of times this slot has been updated. + const char *description; // pointer to static string +} event[MAXNUM]; + + +// make sure all slot totals and counts reset to 0 at start + +static void initSlots() +{ + static int initialized=0; + if (!initialized) { + for (int i=0; i (description); + num = 1; + serialize(); + getClockCount (event[0].cc); +} + + +void dTimerNow (const char *description) +{ + if (num < MAXNUM) { + // do not serialize + getClockCount (event[num].cc); + event[num].description = const_cast (description); + num++; + } +} + + +void dTimerEnd() +{ + if (num < MAXNUM) { + serialize(); + getClockCount (event[num].cc); + event[num].description = "TOTAL"; + num++; + } +} + +//**************************************************************************** +// print report + +static void fprintDoubleWithPrefix (FILE *f, double a, const char *fmt) +{ + if (a >= 0.999999) { + fprintf (f,fmt,a); + return; + } + a *= 1000.0; + if (a >= 0.999999) { + fprintf (f,fmt,a); + fprintf (f,"m"); + return; + } + a *= 1000.0; + if (a >= 0.999999) { + fprintf (f,fmt,a); + fprintf (f,"u"); + return; + } + a *= 1000.0; + fprintf (f,fmt,a); + fprintf (f,"n"); +} + + +void dTimerReport (FILE *fout, int average) +{ + int i; + size_t maxl; + double ccunit = 1.0/dTimerTicksPerSecond(); + fprintf (fout,"\nTimer Report ("); + fprintDoubleWithPrefix (fout,ccunit,"%.2f "); + fprintf (fout,"s resolution)\n------------\n"); + if (num < 1) return; + + // get maximum description length + maxl = 0; + for (i=0; i maxl) maxl = l; + } + + // calculate total time + double t1 = loadClockCount (event[0].cc); + double t2 = loadClockCount (event[num-1].cc); + double total = t2 - t1; + if (total <= 0) total = 1; + + // compute time difference for all slots except the last one. update totals + double *times = (double*) ALLOCA (num * sizeof(double)); + for (i=0; i < (num-1); i++) { + double t1 = loadClockCount (event[i].cc); + double t2 = loadClockCount (event[i+1].cc); + times[i] = t2 - t1; + event[i].count++; + event[i].total_t += times[i]; + event[i].total_p += times[i]/total * 100.0; + } + + // print report (with optional averages) + for (i=0; i + +#define ALLOCA dALLOCA16 + +//**************************************************************************** +// Auto disabling + +void dInternalHandleAutoDisabling (dxWorld *world, dReal stepsize) +{ + dxBody *bb; + for (bb=world->firstbody; bb; bb=(dxBody*)bb->next) { + // nothing to do unless this body is currently enabled and has + // the auto-disable flag set + if ((bb->flags & (dxBodyAutoDisable|dxBodyDisabled)) != dxBodyAutoDisable) continue; + + // see if the body is idle + int idle = 1; // initial assumption + dReal lspeed2 = dDOT(bb->lvel,bb->lvel); + if (lspeed2 > bb->adis.linear_threshold) { + idle = 0; // moving fast - not idle + } + else { + dReal aspeed = dDOT(bb->avel,bb->avel); + if (aspeed > bb->adis.angular_threshold) { + idle = 0; // turning fast - not idle + } + } + + // if it's idle, accumulate steps and time. + // these counters won't overflow because this code doesn't run for disabled bodies. + if (idle) { + bb->adis_stepsleft--; + bb->adis_timeleft -= stepsize; + } + else { + bb->adis_stepsleft = bb->adis.idle_steps; + bb->adis_timeleft = bb->adis.idle_time; + } + + // disable the body if it's idle for a long enough time + if (bb->adis_stepsleft < 0 && bb->adis_timeleft < 0) { + bb->flags |= dxBodyDisabled; + + // ericf tweak - kill force and motion + // bb->lvel[0] = bb->lvel[1] = bb->lvel[2] = bb->avel[0] = bb->avel[1] = bb->avel[2] = 0.0; + // bb->facc[0] = bb->facc[1] = bb->facc[2] = 0.0; + } + } +} + + +//**************************************************************************** +// body rotation + +// return sin(x)/x. this has a singularity at 0 so special handling is needed +// for small arguments. + +static inline dReal sinc (dReal x) +{ + // if |x| < 1e-4 then use a taylor series expansion. this two term expansion + // is actually accurate to one LS bit within this range if double precision + // is being used - so don't worry! + if (dFabs(x) < 1.0e-4) return REAL(1.0) - x*x*REAL(0.166666666666666666667); + else return dSin(x)/x; +} + + +// given a body b, apply its linear and angular rotation over the time +// interval h, thereby adjusting its position and orientation. + +void dxStepBody (dxBody *b, dReal h) +{ + int j; + + // handle linear velocity + for (j=0; j<3; j++) b->pos[j] += h * b->lvel[j]; + + if (b->flags & dxBodyFlagFiniteRotation) { + dVector3 irv; // infitesimal rotation vector + dQuaternion q; // quaternion for finite rotation + + if (b->flags & dxBodyFlagFiniteRotationAxis) { + // split the angular velocity vector into a component along the finite + // rotation axis, and a component orthogonal to it. + dVector3 frv; // finite rotation vector + dReal k = dDOT (b->finite_rot_axis,b->avel); + frv[0] = b->finite_rot_axis[0] * k; + frv[1] = b->finite_rot_axis[1] * k; + frv[2] = b->finite_rot_axis[2] * k; + irv[0] = b->avel[0] - frv[0]; + irv[1] = b->avel[1] - frv[1]; + irv[2] = b->avel[2] - frv[2]; + + // make a rotation quaternion q that corresponds to frv * h. + // compare this with the full-finite-rotation case below. + h *= REAL(0.5); + dReal theta = k * h; + q[0] = dCos(theta); + dReal s = sinc(theta) * h; + q[1] = frv[0] * s; + q[2] = frv[1] * s; + q[3] = frv[2] * s; + } + else { + + // make a rotation quaternion q that corresponds to w * h + dReal wlen = dSqrt (b->avel[0]*b->avel[0] + b->avel[1]*b->avel[1] + + b->avel[2]*b->avel[2]); + h *= REAL(0.5); + dReal theta = wlen * h; + q[0] = dCos(theta); + dReal s = sinc(theta) * h; + q[1] = b->avel[0] * s; + q[2] = b->avel[1] * s; + q[3] = b->avel[2] * s; + } + + // do the finite rotation + dQuaternion q2; + dQMultiply0 (q2,q,b->q); + for (j=0; j<4; j++) b->q[j] = q2[j]; + + // do the infitesimal rotation if required + if (b->flags & dxBodyFlagFiniteRotationAxis) { + dReal dq[4]; + dWtoDQ (irv,b->q,dq); + for (j=0; j<4; j++) b->q[j] += h * dq[j]; + } + } + else { + + // the normal way - do an infitesimal rotation + dReal dq[4]; + dWtoDQ (b->avel,b->q,dq); + for (j=0; j<4; j++) b->q[j] += h * dq[j]; + + } + + // normalize the quaternion and convert it to a rotation matrix + dNormalize4 (b->q); + dQtoR (b->q,b->R); + + // notify all attached geoms that this body has moved + for (dxGeom *geom = b->geom; geom; geom = dGeomGetBodyNext (geom)) + dGeomMoved (geom); +} + +//**************************************************************************** +// island processing + +// this groups all joints and bodies in a world into islands. all objects +// in an island are reachable by going through connected bodies and joints. +// each island can be simulated separately. +// note that joints that are not attached to anything will not be included +// in any island, an so they do not affect the simulation. +// +// this function starts new island from unvisited bodies. however, it will +// never start a new islands from a disabled body. thus islands of disabled +// bodies will not be included in the simulation. disabled bodies are +// re-enabled if they are found to be part of an active island. + +void dxProcessIslands (dxWorld *world, dReal stepsize, dstepper_fn_t stepper) +{ + dxBody *b,*bb,**body; + dxJoint *j,**joint; + + // nothing to do if no bodies + if (world->nb <= 0) return; + + // handle auto-disabling of bodies + dInternalHandleAutoDisabling (world,stepsize); + + // make arrays for body and joint lists (for a single island) to go into + body = (dxBody**) ALLOCA (world->nb * sizeof(dxBody*)); + joint = (dxJoint**) ALLOCA (world->nj * sizeof(dxJoint*)); + int bcount = 0; // number of bodies in `body' + int jcount = 0; // number of joints in `joint' + + // set all body/joint tags to 0 + for (b=world->firstbody; b; b=(dxBody*)b->next) b->tag = 0; + for (j=world->firstjoint; j; j=(dxJoint*)j->next) j->tag = 0; + + // allocate a stack of unvisited bodies in the island. the maximum size of + // the stack can be the lesser of the number of bodies or joints, because + // new bodies are only ever added to the stack by going through untagged + // joints. all the bodies in the stack must be tagged! + int stackalloc = (world->nj < world->nb) ? world->nj : world->nb; + dxBody **stack = (dxBody**) ALLOCA (stackalloc * sizeof(dxBody*)); + + for (bb=world->firstbody; bb; bb=(dxBody*)bb->next) { + // get bb = the next enabled, untagged body, and tag it + if (bb->tag || (bb->flags & dxBodyDisabled)) continue; + bb->tag = 1; + + // tag all bodies and joints starting from bb. + int stacksize = 0; + b = bb; + body[0] = bb; + bcount = 1; + jcount = 0; + goto quickstart; + while (stacksize > 0) { + b = stack[--stacksize]; // pop body off stack + body[bcount++] = b; // put body on body list + quickstart: + + // traverse and tag all body's joints, add untagged connected bodies + // to stack + for (dxJointNode *n=b->firstjoint; n; n=n->next) { + if (!n->joint->tag) { + n->joint->tag = 1; + joint[jcount++] = n->joint; + if (n->body && !n->body->tag) { + n->body->tag = 1; + stack[stacksize++] = n->body; + } + } + } + dIASSERT(stacksize <= world->nb); + dIASSERT(stacksize <= world->nj); + } + + // now do something with body and joint lists + stepper (world,body,bcount,joint,jcount,stepsize); + + // what we've just done may have altered the body/joint tag values. + // we must make sure that these tags are nonzero. + // also make sure all bodies are in the enabled state. + int i; + for (i=0; itag = 1; + body[i]->flags &= ~dxBodyDisabled; + } + for (i=0; itag = 1; + } + + // if debugging, check that all objects (except for disabled bodies, + // unconnected joints, and joints that are connected to disabled bodies) + // were tagged. +# ifndef dNODEBUG + for (b=world->firstbody; b; b=(dxBody*)b->next) { + if (b->flags & dxBodyDisabled) { + if (b->tag) dDebug (0,"disabled body tagged"); + } + else { + if (!b->tag) dDebug (0,"enabled body not tagged"); + } + } + for (j=world->firstjoint; j; j=(dxJoint*)j->next) { + if ((j->node[0].body && (j->node[0].body->flags & dxBodyDisabled)==0) || + (j->node[1].body && (j->node[1].body->flags & dxBodyDisabled)==0)) { + if (!j->tag) dDebug (0,"attached enabled joint not tagged"); + } + else { + if (j->tag) dDebug (0,"unattached or disabled joint tagged"); + } + } +# endif +} diff --git a/src/external/open_dynamics_engine-ef/ode/ode_util.h b/src/external/open_dynamics_engine-ef/ode/ode_util.h new file mode 100644 index 00000000..a950bb9d --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/ode_util.h @@ -0,0 +1,56 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +#ifndef _ODE_UTIL_H_ +#define _ODE_UTIL_H_ + +#include "ode/ode_objects_private.h" + + +void dInternalHandleAutoDisabling (dxWorld *world, dReal stepsize); +void dxStepBody (dxBody *b, dReal h); + +typedef void (*dstepper_fn_t) (dxWorld *world, dxBody * const *body, int nb, + dxJoint * const *_joint, int nj, dReal stepsize); + +void dxProcessIslands (dxWorld *world, dReal stepsize, dstepper_fn_t stepper); + + + +/////////ERIC ADDED STUFF////////////////////// +#define VALUE_TESTING 0 + +#if VALUE_TESTING +extern FILE *f; +extern bool testLogging; +void odeTestEnableLogging(); +void odeTestDisableLogging(); + +#define PRINT_DBL_HEX(x) {int *poo = (int*)&(x); fprintf(f,"0x%X%X\n",poo[0],poo[1]);} +#define PRINT_DBL_HEX_STDOUT(x) {int *poo = (int*)&(x); printf("0x%X%X\n",poo[0],poo[1]);} +void printBody(dxBody* b, int index); +void printJoint(dxJoint* j, int index); +#endif + +////////////////////////////////////////////// + +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/odecpp.h b/src/external/open_dynamics_engine-ef/ode/odecpp.h new file mode 100644 index 00000000..a694caf7 --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/odecpp.h @@ -0,0 +1,621 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* C++ interface for non-collision stuff */ + + +#ifndef _ODE_ODECPP_H_ +#define _ODE_ODECPP_H_ +#ifdef __cplusplus + +#include "ode/ode_error.h" + + +class dWorld { + dWorldID _id; + + // intentionally undefined, don't use these + dWorld (const dWorld &); + void operator= (const dWorld &); + +public: + dWorld() + { _id = dWorldCreate(); } + ~dWorld() + { dWorldDestroy (_id); } + + dWorldID id() const + { return _id; } + operator dWorldID() const + { return _id; } + + void setGravity (dReal x, dReal y, dReal z) + { dWorldSetGravity (_id,x,y,z); } + void getGravity (dVector3 g) const + { dWorldGetGravity (_id,g); } + + void setERP (dReal erp) + { dWorldSetERP(_id, erp); } + dReal getERP() const + { return dWorldGetERP(_id); } + + void setCFM (dReal cfm) + { dWorldSetCFM(_id, cfm); } + dReal getCFM() const + { return dWorldGetCFM(_id); } + + void step (dReal stepsize) + { dWorldStep (_id,stepsize); } + + void stepFast1 (dReal stepsize, int maxiterations) + { dWorldStepFast1 (_id,stepsize,maxiterations); } + void setAutoEnableDepthSF1(dWorldID, int depth) + { dWorldSetAutoEnableDepthSF1 (_id, depth); } + int getAutoEnableDepthSF1(dWorldID) + { return dWorldGetAutoEnableDepthSF1 (_id); } + + void setAutoDisableLinearThreshold (dReal threshold) + { dWorldSetAutoDisableLinearThreshold (_id,threshold); } + dReal getAutoDisableLinearThreshold() + { return dWorldGetAutoDisableLinearThreshold (_id); } + void setAutoDisableAngularThreshold (dReal threshold) + { dWorldSetAutoDisableAngularThreshold (_id,threshold); } + dReal getAutoDisableAngularThreshold() + { return dWorldGetAutoDisableAngularThreshold (_id); } + void setAutoDisableSteps (int steps) + { dWorldSetAutoDisableSteps (_id,steps); } + int getAutoDisableSteps() + { return dWorldGetAutoDisableSteps (_id); } + void setAutoDisableTime (dReal time) + { dWorldSetAutoDisableTime (_id,time); } + dReal getAutoDisableTime() + { return dWorldGetAutoDisableTime (_id); } + void setAutoDisableFlag (int do_auto_disable) + { dWorldSetAutoDisableFlag (_id,do_auto_disable); } + int getAutoDisableFlag() + { return dWorldGetAutoDisableFlag (_id); } + + void impulseToForce (dReal stepsize, dReal ix, dReal iy, dReal iz, + dVector3 force) + { dWorldImpulseToForce (_id,stepsize,ix,iy,iz,force); } +}; + + +class dBody { + dBodyID _id; + + // intentionally undefined, don't use these + dBody (const dBody &); + void operator= (const dBody &); + +public: + dBody() + { _id = 0; } + dBody (dWorldID world) + { _id = dBodyCreate (world); } + ~dBody() + { if (_id) dBodyDestroy (_id); } + + void create (dWorldID world) { + if (_id) dBodyDestroy (_id); + _id = dBodyCreate (world); + } + + dBodyID id() const + { return _id; } + operator dBodyID() const + { return _id; } + + void setData (void *data) + { dBodySetData (_id,data); } + void *getData() const + { return dBodyGetData (_id); } + + void setPosition (dReal x, dReal y, dReal z) + { dBodySetPosition (_id,x,y,z); } + void setRotation (const dMatrix3 R) + { dBodySetRotation (_id,R); } + void setQuaternion (const dQuaternion q) + { dBodySetQuaternion (_id,q); } + void setLinearVel (dReal x, dReal y, dReal z) + { dBodySetLinearVel (_id,x,y,z); } + void setAngularVel (dReal x, dReal y, dReal z) + { dBodySetAngularVel (_id,x,y,z); } + + const dReal * getPosition() const + { return dBodyGetPosition (_id); } + const dReal * getRotation() const + { return dBodyGetRotation (_id); } + const dReal * getQuaternion() const + { return dBodyGetQuaternion (_id); } + const dReal * getLinearVel() const + { return dBodyGetLinearVel (_id); } + const dReal * getAngularVel() const + { return dBodyGetAngularVel (_id); } + + void setMass (const dMass *mass) + { dBodySetMass (_id,mass); } + void getMass (dMass *mass) const + { dBodyGetMass (_id,mass); } + + void addForce (dReal fx, dReal fy, dReal fz) + { dBodyAddForce (_id, fx, fy, fz); } + void addTorque (dReal fx, dReal fy, dReal fz) + { dBodyAddTorque (_id, fx, fy, fz); } + void addRelForce (dReal fx, dReal fy, dReal fz) + { dBodyAddRelForce (_id, fx, fy, fz); } + void addRelTorque (dReal fx, dReal fy, dReal fz) + { dBodyAddRelTorque (_id, fx, fy, fz); } + void addForceAtPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddForceAtPos (_id, fx, fy, fz, px, py, pz); } + void addForceAtRelPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddForceAtRelPos (_id, fx, fy, fz, px, py, pz); } + void addRelForceAtPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddRelForceAtPos (_id, fx, fy, fz, px, py, pz); } + void addRelForceAtRelPos (dReal fx, dReal fy, dReal fz, + dReal px, dReal py, dReal pz) + { dBodyAddRelForceAtRelPos (_id, fx, fy, fz, px, py, pz); } + + const dReal * getForce() const + { return dBodyGetForce(_id); } + const dReal * getTorque() const + { return dBodyGetTorque(_id); } + void setForce (dReal x, dReal y, dReal z) + { dBodySetForce (_id,x,y,z); } + void setTorque (dReal x, dReal y, dReal z) + { dBodySetTorque (_id,x,y,z); } + + void enable() + { dBodyEnable (_id); } + void disable() + { dBodyDisable (_id); } + int isEnabled() const + { return dBodyIsEnabled (_id); } + + void getRelPointPos (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetRelPointPos (_id, px, py, pz, result); } + void getRelPointVel (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetRelPointVel (_id, px, py, pz, result); } + void getPointVel (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetPointVel (_id,px,py,pz,result); } + void getPosRelPoint (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyGetPosRelPoint (_id,px,py,pz,result); } + void vectorToWorld (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyVectorToWorld (_id,px,py,pz,result); } + void vectorFromWorld (dReal px, dReal py, dReal pz, dVector3 result) const + { dBodyVectorFromWorld (_id,px,py,pz,result); } + + void setFiniteRotationMode (int mode) + { dBodySetFiniteRotationMode (_id, mode); } + void setFiniteRotationAxis (dReal x, dReal y, dReal z) + { dBodySetFiniteRotationAxis (_id, x, y, z); } + + int getFiniteRotationMode() const + { return dBodyGetFiniteRotationMode (_id); } + void getFiniteRotationAxis (dVector3 result) const + { dBodyGetFiniteRotationAxis (_id, result); } + + int getNumJoints() const + { return dBodyGetNumJoints (_id); } + dJointID getJoint (int index) const + { return dBodyGetJoint (_id, index); } + + void setGravityMode (int mode) + { dBodySetGravityMode (_id,mode); } + int getGravityMode() const + { return dBodyGetGravityMode (_id); } + + int isConnectedTo (dBodyID body) const + { return dAreConnected (_id, body); } + + void setAutoDisableLinearThreshold (dReal threshold) + { dBodySetAutoDisableLinearThreshold (_id,threshold); } + dReal getAutoDisableLinearThreshold() + { return dBodyGetAutoDisableLinearThreshold (_id); } + void setAutoDisableAngularThreshold (dReal threshold) + { dBodySetAutoDisableAngularThreshold (_id,threshold); } + dReal getAutoDisableAngularThreshold() + { return dBodyGetAutoDisableAngularThreshold (_id); } + void setAutoDisableSteps (int steps) + { dBodySetAutoDisableSteps (_id,steps); } + int getAutoDisableSteps() + { return dBodyGetAutoDisableSteps (_id); } + void setAutoDisableTime (dReal time) + { dBodySetAutoDisableTime (_id,time); } + dReal getAutoDisableTime() + { return dBodyGetAutoDisableTime (_id); } + void setAutoDisableFlag (int do_auto_disable) + { dBodySetAutoDisableFlag (_id,do_auto_disable); } + int getAutoDisableFlag() + { return dBodyGetAutoDisableFlag (_id); } +}; + + +class dJointGroup { + dJointGroupID _id; + + // intentionally undefined, don't use these + dJointGroup (const dJointGroup &); + void operator= (const dJointGroup &); + +public: + dJointGroup (int dummy_arg=0) + { _id = dJointGroupCreate (0); } + ~dJointGroup() + { dJointGroupDestroy (_id); } + void create (int dummy_arg=0) { + if (_id) dJointGroupDestroy (_id); + _id = dJointGroupCreate (0); + } + + dJointGroupID id() const + { return _id; } + operator dJointGroupID() const + { return _id; } + + void empty() + { dJointGroupEmpty (_id); } +}; + + +class dJoint { +private: + // intentionally undefined, don't use these + dJoint (const dJoint &) ; + void operator= (const dJoint &); + +protected: + dJointID _id; + +public: + dJoint() + { _id = 0; } + ~dJoint() + { if (_id) dJointDestroy (_id); } + + dJointID id() const + { return _id; } + operator dJointID() const + { return _id; } + + void attach (dBodyID body1, dBodyID body2) + { dJointAttach (_id, body1, body2); } + + void setData (void *data) + { dJointSetData (_id, data); } + void *getData() const + { return dJointGetData (_id); } + + int getType() const + { return dJointGetType (_id); } + + dBodyID getBody (int index) const + { return dJointGetBody (_id, index); } +}; + + +class dBallJoint : public dJoint { +private: + // intentionally undefined, don't use these + dBallJoint (const dBallJoint &); + void operator= (const dBallJoint &); + +public: + dBallJoint() { } + dBallJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateBall (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateBall (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetBallAnchor (_id, x, y, z); } + void getAnchor (dVector3 result) const + { dJointGetBallAnchor (_id, result); } + void getAnchor2 (dVector3 result) const + { dJointGetBallAnchor2 (_id, result); } +} ; + + +class dHingeJoint : public dJoint { + // intentionally undefined, don't use these + dHingeJoint (const dHingeJoint &); + void operator = (const dHingeJoint &); + +public: + dHingeJoint() { } + dHingeJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateHinge (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateHinge (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetHingeAnchor (_id, x, y, z); } + void getAnchor (dVector3 result) const + { dJointGetHingeAnchor (_id, result); } + void getAnchor2 (dVector3 result) const + { dJointGetHingeAnchor2 (_id, result); } + + void setAxis (dReal x, dReal y, dReal z) + { dJointSetHingeAxis (_id, x, y, z); } + void getAxis (dVector3 result) const + { dJointGetHingeAxis (_id, result); } + + dReal getAngle() const + { return dJointGetHingeAngle (_id); } + dReal getAngleRate() const + { return dJointGetHingeAngleRate (_id); } + + void setParam (int parameter, dReal value) + { dJointSetHingeParam (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetHingeParam (_id, parameter); } + + void addTorque (dReal torque) + { dJointAddHingeTorque(_id, torque); } +}; + + +class dSliderJoint : public dJoint { + // intentionally undefined, don't use these + dSliderJoint (const dSliderJoint &); + void operator = (const dSliderJoint &); + +public: + dSliderJoint() { } + dSliderJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateSlider (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateSlider (world, group); + } + + void setAxis (dReal x, dReal y, dReal z) + { dJointSetSliderAxis (_id, x, y, z); } + void getAxis (dVector3 result) const + { dJointGetSliderAxis (_id, result); } + + dReal getPosition() const + { return dJointGetSliderPosition (_id); } + dReal getPositionRate() const + { return dJointGetSliderPositionRate (_id); } + + void setParam (int parameter, dReal value) + { dJointSetSliderParam (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetSliderParam (_id, parameter); } + + void addForce (dReal force) + { dJointAddSliderForce(_id, force); } +}; + + +class dUniversalJoint : public dJoint { + // intentionally undefined, don't use these + dUniversalJoint (const dUniversalJoint &); + void operator = (const dUniversalJoint &); + +public: + dUniversalJoint() { } + dUniversalJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateUniversal (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateUniversal (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetUniversalAnchor (_id, x, y, z); } + void setAxis1 (dReal x, dReal y, dReal z) + { dJointSetUniversalAxis1 (_id, x, y, z); } + void setAxis2 (dReal x, dReal y, dReal z) + { dJointSetUniversalAxis2 (_id, x, y, z); } + void setParam (int parameter, dReal value) + { dJointSetUniversalParam (_id, parameter, value); } + + void getAnchor (dVector3 result) const + { dJointGetUniversalAnchor (_id, result); } + void getAnchor2 (dVector3 result) const + { dJointGetUniversalAnchor2 (_id, result); } + void getAxis1 (dVector3 result) const + { dJointGetUniversalAxis1 (_id, result); } + void getAxis2 (dVector3 result) const + { dJointGetUniversalAxis2 (_id, result); } + dReal getParam (int parameter) const + { return dJointGetUniversalParam (_id, parameter); } + dReal getAngle1() const + { return dJointGetUniversalAngle1 (_id); } + dReal getAngle1Rate() const + { return dJointGetUniversalAngle1Rate (_id); } + dReal getAngle2() const + { return dJointGetUniversalAngle2 (_id); } + dReal getAngle2Rate() const + { return dJointGetUniversalAngle2Rate (_id); } + + void addTorques (dReal torque1, dReal torque2) + { dJointAddUniversalTorques(_id, torque1, torque2); } +}; + + +class dHinge2Joint : public dJoint { + // intentionally undefined, don't use these + dHinge2Joint (const dHinge2Joint &); + void operator = (const dHinge2Joint &); + +public: + dHinge2Joint() { } + dHinge2Joint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateHinge2 (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateHinge2 (world, group); + } + + void setAnchor (dReal x, dReal y, dReal z) + { dJointSetHinge2Anchor (_id, x, y, z); } + void setAxis1 (dReal x, dReal y, dReal z) + { dJointSetHinge2Axis1 (_id, x, y, z); } + void setAxis2 (dReal x, dReal y, dReal z) + { dJointSetHinge2Axis2 (_id, x, y, z); } + + void getAnchor (dVector3 result) const + { dJointGetHinge2Anchor (_id, result); } + void getAnchor2 (dVector3 result) const + { dJointGetHinge2Anchor2 (_id, result); } + void getAxis1 (dVector3 result) const + { dJointGetHinge2Axis1 (_id, result); } + void getAxis2 (dVector3 result) const + { dJointGetHinge2Axis2 (_id, result); } + + dReal getAngle1() const + { return dJointGetHinge2Angle1 (_id); } + dReal getAngle1Rate() const + { return dJointGetHinge2Angle1Rate (_id); } + dReal getAngle2Rate() const + { return dJointGetHinge2Angle2Rate (_id); } + + void setParam (int parameter, dReal value) + { dJointSetHinge2Param (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetHinge2Param (_id, parameter); } + + void addTorques(dReal torque1, dReal torque2) + { dJointAddHinge2Torques(_id, torque1, torque2); } +}; + + +class dFixedJoint : public dJoint { + // intentionally undefined, don't use these + dFixedJoint (const dFixedJoint &); + void operator = (const dFixedJoint &); + +public: + dFixedJoint() { } + dFixedJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateFixed (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateFixed (world, group); + } + + void set() + { dJointSetFixed (_id); } +}; + + +class dContactJoint : public dJoint { + // intentionally undefined, don't use these + dContactJoint (const dContactJoint &); + void operator = (const dContactJoint &); + +public: + dContactJoint() { } + dContactJoint (dWorldID world, dJointGroupID group, dContact *contact) + { _id = dJointCreateContact (world, group, contact); } + + void create (dWorldID world, dJointGroupID group, dContact *contact) { + if (_id) dJointDestroy (_id); + _id = dJointCreateContact (world, group, contact); + } +}; + + +class dNullJoint : public dJoint { + // intentionally undefined, don't use these + dNullJoint (const dNullJoint &); + void operator = (const dNullJoint &); + +public: + dNullJoint() { } + dNullJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateNull (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateNull (world, group); + } +}; + + +class dAMotorJoint : public dJoint { + // intentionally undefined, don't use these + dAMotorJoint (const dAMotorJoint &); + void operator = (const dAMotorJoint &); + +public: + dAMotorJoint() { } + dAMotorJoint (dWorldID world, dJointGroupID group=0) + { _id = dJointCreateAMotor (world, group); } + + void create (dWorldID world, dJointGroupID group=0) { + if (_id) dJointDestroy (_id); + _id = dJointCreateAMotor (world, group); + } + + void setMode (int mode) + { dJointSetAMotorMode (_id, mode); } + int getMode() const + { return dJointGetAMotorMode (_id); } + + void setNumAxes (int num) + { dJointSetAMotorNumAxes (_id, num); } + int getNumAxes() const + { return dJointGetAMotorNumAxes (_id); } + + void setAxis (int anum, int rel, dReal x, dReal y, dReal z) + { dJointSetAMotorAxis (_id, anum, rel, x, y, z); } + void getAxis (int anum, dVector3 result) const + { dJointGetAMotorAxis (_id, anum, result); } + int getAxisRel (int anum) const + { return dJointGetAMotorAxisRel (_id, anum); } + + void setAngle (int anum, dReal angle) + { dJointSetAMotorAngle (_id, anum, angle); } + dReal getAngle (int anum) const + { return dJointGetAMotorAngle (_id, anum); } + dReal getAngleRate (int anum) + { return dJointGetAMotorAngleRate (_id,anum); } + + void setParam (int parameter, dReal value) + { dJointSetAMotorParam (_id, parameter, value); } + dReal getParam (int parameter) const + { return dJointGetAMotorParam (_id, parameter); } + + void addTorques(dReal torque1, dReal torque2, dReal torque3) + { dJointAddAMotorTorques(_id, torque1, torque2, torque3); } +}; + + +#endif +#endif diff --git a/src/external/open_dynamics_engine-ef/ode/odecpp_collision.h b/src/external/open_dynamics_engine-ef/ode/odecpp_collision.h new file mode 100644 index 00000000..36a6db3f --- /dev/null +++ b/src/external/open_dynamics_engine-ef/ode/odecpp_collision.h @@ -0,0 +1,346 @@ +/************************************************************************* + * * + * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * + * All rights reserved. Email: russ@q12.org Web: www.q12.org * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of EITHER: * + * (1) The GNU Lesser General Public License as published by the Free * + * Software Foundation; either version 2.1 of the License, or (at * + * your option) any later version. The text of the GNU Lesser * + * General Public License is included with this library in the * + * file LICENSE.TXT. * + * (2) The BSD-style license that is included with this library in * + * the file LICENSE-BSD.TXT. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * + * LICENSE.TXT and LICENSE-BSD.TXT for more details. * + * * + *************************************************************************/ + +/* C++ interface for new collision API */ + + +#ifndef _ODE_ODECPP_COLLISION_H_ +#define _ODE_ODECPP_COLLISION_H_ +#ifdef __cplusplus + +#include "ode/ode_error.h" + + +class dGeom { + // intentionally undefined, don't use these + dGeom (dGeom &); + void operator= (dGeom &); + +protected: + dGeomID _id; + +public: + dGeom() + { _id = 0; } + ~dGeom() + { if (_id) dGeomDestroy (_id); } + + dGeomID id() const + { return _id; } + operator dGeomID() const + { return _id; } + + void destroy() { + if (_id) dGeomDestroy (_id); + _id = 0; + } + + int getClass() const + { return dGeomGetClass (_id); } + + dSpaceID getSpace() const + { return dGeomGetSpace (_id); } + + void setData (void *data) + { dGeomSetData (_id,data); } + void *getData() const + { return dGeomGetData (_id); } + + void setBody (dBodyID b) + { dGeomSetBody (_id,b); } + dBodyID body() const + { return dGeomGetBody (_id); } + + void setPosition (dReal x, dReal y, dReal z) + { dGeomSetPosition (_id,x,y,z); } + const dReal * getPosition() const + { return dGeomGetPosition (_id); } + + void setRotation (const dMatrix3 R) + { dGeomSetRotation (_id,R); } + const dReal * getRotation() const + { return dGeomGetRotation (_id); } + + void setQuaternion (const dQuaternion quat) + { dGeomSetQuaternion (_id,quat); } + void getQuaternion (dQuaternion quat) const + { dGeomGetQuaternion (_id,quat); } + + void getAABB (dReal aabb[6]) const + { dGeomGetAABB (_id, aabb); } + + int isSpace() + { return dGeomIsSpace (_id); } + + void setCategoryBits (unsigned long bits) + { dGeomSetCategoryBits (_id, bits); } + void setCollideBits (unsigned long bits) + { dGeomSetCollideBits (_id, bits); } + unsigned long getCategoryBits() + { return dGeomGetCategoryBits (_id); } + unsigned long getCollideBits() + { return dGeomGetCollideBits (_id); } + + void enable() + { dGeomEnable (_id); } + void disable() + { dGeomDisable (_id); } + int isEnabled() + { return dGeomIsEnabled (_id); } + + void collide2 (dGeomID g, void *data, dNearCallback *callback) + { dSpaceCollide2 (_id,g,data,callback); } +}; + + +class dSpace : public dGeom { + // intentionally undefined, don't use these + dSpace (dSpace &); + void operator= (dSpace &); + +protected: + // the default constructor is protected so that you + // can't instance this class. you must instance one + // of its subclasses instead. + dSpace () { _id = 0; } + +public: + dSpaceID id() const + { return (dSpaceID) _id; } + operator dSpaceID() const + { return (dSpaceID) _id; } + + void setCleanup (int mode) + { dSpaceSetCleanup (id(), mode); } + int getCleanup() + { return dSpaceGetCleanup (id()); } + + void add (dGeomID x) + { dSpaceAdd (id(), x); } + void remove (dGeomID x) + { dSpaceRemove (id(), x); } + int query (dGeomID x) + { return dSpaceQuery (id(),x); } + + int getNumGeoms() + { return dSpaceGetNumGeoms (id()); } + dGeomID getGeom (int i) + { return dSpaceGetGeom (id(),i); } + + void collide (void *data, dNearCallback *callback) + { dSpaceCollide (id(),data,callback); } +}; + + +class dSimpleSpace : public dSpace { + // intentionally undefined, don't use these + dSimpleSpace (dSimpleSpace &); + void operator= (dSimpleSpace &); + +public: + dSimpleSpace (dSpaceID space) + { _id = (dGeomID) dSimpleSpaceCreate (space); } +}; + + +class dHashSpace : public dSpace { + // intentionally undefined, don't use these + dHashSpace (dHashSpace &); + void operator= (dHashSpace &); + +public: + dHashSpace (dSpaceID space) + { _id = (dGeomID) dHashSpaceCreate (space); } + void setLevels (int minlevel, int maxlevel) + { dHashSpaceSetLevels (id(),minlevel,maxlevel); } +}; + + +class dQuadTreeSpace : public dSpace { + // intentionally undefined, don't use these + dQuadTreeSpace (dQuadTreeSpace &); + void operator= (dQuadTreeSpace &); + +public: + dQuadTreeSpace (dSpaceID space, dVector3 center, dVector3 extents, int depth) + { _id = (dGeomID) dQuadTreeSpaceCreate (space,center,extents,depth); } +}; + + +class dSphere : public dGeom { + // intentionally undefined, don't use these + dSphere (dSphere &); + void operator= (dSphere &); + +public: + dSphere () { } + dSphere (dSpaceID space, dReal radius) + { _id = dCreateSphere (space, radius); } + + void create (dSpaceID space, dReal radius) { + if (_id) dGeomDestroy (_id); + _id = dCreateSphere (space, radius); + } + + void setRadius (dReal radius) + { dGeomSphereSetRadius (_id, radius); } + dReal getRadius() const + { return dGeomSphereGetRadius (_id); } +}; + + +class dBox : public dGeom { + // intentionally undefined, don't use these + dBox (dBox &); + void operator= (dBox &); + +public: + dBox () { } + dBox (dSpaceID space, dReal lx, dReal ly, dReal lz) + { _id = dCreateBox (space,lx,ly,lz); } + + void create (dSpaceID space, dReal lx, dReal ly, dReal lz) { + if (_id) dGeomDestroy (_id); + _id = dCreateBox (space,lx,ly,lz); + } + + void setLengths (dReal lx, dReal ly, dReal lz) + { dGeomBoxSetLengths (_id, lx, ly, lz); } + void getLengths (dVector3 result) const + { dGeomBoxGetLengths (_id,result); } +}; + + +class dPlane : public dGeom { + // intentionally undefined, don't use these + dPlane (dPlane &); + void operator= (dPlane &); + +public: + dPlane() { } + dPlane (dSpaceID space, dReal a, dReal b, dReal c, dReal d) + { _id = dCreatePlane (space,a,b,c,d); } + + void create (dSpaceID space, dReal a, dReal b, dReal c, dReal d) { + if (_id) dGeomDestroy (_id); + _id = dCreatePlane (space,a,b,c,d); + } + + void setParams (dReal a, dReal b, dReal c, dReal d) + { dGeomPlaneSetParams (_id, a, b, c, d); } + void getParams (dVector4 result) const + { dGeomPlaneGetParams (_id,result); } +}; + + +class dCCylinder : public dGeom { + // intentionally undefined, don't use these + dCCylinder (dCCylinder &); + void operator= (dCCylinder &); + +public: + dCCylinder() { } + dCCylinder (dSpaceID space, dReal radius, dReal length) + { _id = dCreateCCylinder (space,radius,length); } + + void create (dSpaceID space, dReal radius, dReal length) { + if (_id) dGeomDestroy (_id); + _id = dCreateCCylinder (space,radius,length); + } + + void setParams (dReal radius, dReal length) + { dGeomCCylinderSetParams (_id, radius, length); } + void getParams (dReal *radius, dReal *length) const + { dGeomCCylinderGetParams (_id,radius,length); } +}; + + +class dRay : public dGeom { + // intentionally undefined, don't use these + dRay (dRay &); + void operator= (dRay &); + +public: + dRay() { } + dRay (dSpaceID space, dReal length) + { _id = dCreateRay (space,length); } + + void create (dSpaceID space, dReal length) { + if (_id) dGeomDestroy (_id); + _id = dCreateRay (space,length); + } + + void setLength (dReal length) + { dGeomRaySetLength (_id, length); } + dReal getLength() + { return dGeomRayGetLength (_id); } + + void set (dReal px, dReal py, dReal pz, dReal dx, dReal dy, dReal dz) + { dGeomRaySet (_id, px, py, pz, dx, dy, dz); } + void get (dVector3 start, dVector3 dir) + { dGeomRayGet (_id, start, dir); } + + void setParams (int firstContact, int backfaceCull) + { dGeomRaySetParams (_id, firstContact, backfaceCull); } + void getParams (int *firstContact, int *backfaceCull) + { dGeomRayGetParams (_id, firstContact, backfaceCull); } + void setClosestHit (int closestHit) + { dGeomRaySetClosestHit (_id, closestHit); } + int getClosestHit() + { return dGeomRayGetClosestHit (_id); } +}; + + +class dGeomTransform : public dGeom { + // intentionally undefined, don't use these + dGeomTransform (dGeomTransform &); + void operator= (dGeomTransform &); + +public: + dGeomTransform() { } + dGeomTransform (dSpaceID space) + { _id = dCreateGeomTransform (space); } + + void create (dSpaceID space=0) { + if (_id) dGeomDestroy (_id); + _id = dCreateGeomTransform (space); + } + + void setGeom (dGeomID geom) + { dGeomTransformSetGeom (_id, geom); } + dGeomID geom() const + { return dGeomTransformGetGeom (_id); } + + void setCleanup (int mode) + { dGeomTransformSetCleanup (_id,mode); } + int getCleanup () + { return dGeomTransformGetCleanup (_id); } + + void setInfo (int mode) + { dGeomTransformSetInfo (_id,mode); } + int getInfo() + { return dGeomTransformGetInfo (_id); } +}; + + +#endif +#endif diff --git a/src/external/qr_code_generator/QrCode.cpp b/src/external/qr_code_generator/QrCode.cpp new file mode 100644 index 00000000..b9de8621 --- /dev/null +++ b/src/external/qr_code_generator/QrCode.cpp @@ -0,0 +1,862 @@ +/* + * QR Code generator library (C++) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "QrCode.hpp" + +using std::int8_t; +using std::uint8_t; +using std::size_t; +using std::vector; + + +namespace qrcodegen { + +QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) : + modeBits(mode) { + numBitsCharCount[0] = cc0; + numBitsCharCount[1] = cc1; + numBitsCharCount[2] = cc2; +} + + +int QrSegment::Mode::getModeBits() const { + return modeBits; +} + + +int QrSegment::Mode::numCharCountBits(int ver) const { + return numBitsCharCount[(ver + 7) / 17]; +} + + +const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14); +const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13); +const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16); +const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12); +const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0); + + +QrSegment QrSegment::makeBytes(const vector &data) { + if (data.size() > static_cast(INT_MAX)) + throw std::length_error("Data too long"); + BitBuffer bb; + for (uint8_t b : data) + bb.appendBits(b, 8); + return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb)); +} + + +QrSegment QrSegment::makeNumeric(const char *digits) { + BitBuffer bb; + int accumData = 0; + int accumCount = 0; + int charCount = 0; + for (; *digits != '\0'; digits++, charCount++) { + char c = *digits; + if (c < '0' || c > '9') + throw std::domain_error("String contains non-numeric characters"); + accumData = accumData * 10 + (c - '0'); + accumCount++; + if (accumCount == 3) { + bb.appendBits(static_cast(accumData), 10); + accumData = 0; + accumCount = 0; + } + } + if (accumCount > 0) // 1 or 2 digits remaining + bb.appendBits(static_cast(accumData), accumCount * 3 + 1); + return QrSegment(Mode::NUMERIC, charCount, std::move(bb)); +} + + +QrSegment QrSegment::makeAlphanumeric(const char *text) { + BitBuffer bb; + int accumData = 0; + int accumCount = 0; + int charCount = 0; + for (; *text != '\0'; text++, charCount++) { + const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text); + if (temp == nullptr) + throw std::domain_error("String contains unencodable characters in alphanumeric mode"); + accumData = accumData * 45 + static_cast(temp - ALPHANUMERIC_CHARSET); + accumCount++; + if (accumCount == 2) { + bb.appendBits(static_cast(accumData), 11); + accumData = 0; + accumCount = 0; + } + } + if (accumCount > 0) // 1 character remaining + bb.appendBits(static_cast(accumData), 6); + return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb)); +} + + +vector QrSegment::makeSegments(const char *text) { + // Select the most efficient segment encoding automatically + vector result; + if (*text == '\0'); // Leave result empty + else if (isNumeric(text)) + result.push_back(makeNumeric(text)); + else if (isAlphanumeric(text)) + result.push_back(makeAlphanumeric(text)); + else { + vector bytes; + for (; *text != '\0'; text++) + bytes.push_back(static_cast(*text)); + result.push_back(makeBytes(bytes)); + } + return result; +} + + +QrSegment QrSegment::makeEci(long assignVal) { + BitBuffer bb; + if (assignVal < 0) + throw std::domain_error("ECI assignment value out of range"); + else if (assignVal < (1 << 7)) + bb.appendBits(static_cast(assignVal), 8); + else if (assignVal < (1 << 14)) { + bb.appendBits(2, 2); + bb.appendBits(static_cast(assignVal), 14); + } else if (assignVal < 1000000L) { + bb.appendBits(6, 3); + bb.appendBits(static_cast(assignVal), 21); + } else + throw std::domain_error("ECI assignment value out of range"); + return QrSegment(Mode::ECI, 0, std::move(bb)); +} + + +QrSegment::QrSegment(Mode md, int numCh, const std::vector &dt) : + mode(md), + numChars(numCh), + data(dt) { + if (numCh < 0) + throw std::domain_error("Invalid value"); +} + + +QrSegment::QrSegment(Mode md, int numCh, std::vector &&dt) : + mode(md), + numChars(numCh), + data(std::move(dt)) { + if (numCh < 0) + throw std::domain_error("Invalid value"); +} + + +int QrSegment::getTotalBits(const vector &segs, int version) { + int result = 0; + for (const QrSegment &seg : segs) { + int ccbits = seg.mode.numCharCountBits(version); + if (seg.numChars >= (1L << ccbits)) + return -1; // The segment's length doesn't fit the field's bit width + if (4 + ccbits > INT_MAX - result) + return -1; // The sum will overflow an int type + result += 4 + ccbits; + if (seg.data.size() > static_cast(INT_MAX - result)) + return -1; // The sum will overflow an int type + result += static_cast(seg.data.size()); + } + return result; +} + + +bool QrSegment::isAlphanumeric(const char *text) { + for (; *text != '\0'; text++) { + if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr) + return false; + } + return true; +} + + +bool QrSegment::isNumeric(const char *text) { + for (; *text != '\0'; text++) { + char c = *text; + if (c < '0' || c > '9') + return false; + } + return true; +} + + +QrSegment::Mode QrSegment::getMode() const { + return mode; +} + + +int QrSegment::getNumChars() const { + return numChars; +} + + +const std::vector &QrSegment::getData() const { + return data; +} + + +const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + + + +int QrCode::getFormatBits(Ecc ecl) { + switch (ecl) { + case Ecc::LOW : return 1; + case Ecc::MEDIUM : return 0; + case Ecc::QUARTILE: return 3; + case Ecc::HIGH : return 2; + default: throw std::logic_error("Assertion error"); + } +} + + +QrCode QrCode::encodeText(const char *text, Ecc ecl) { + vector segs = QrSegment::makeSegments(text); + return encodeSegments(segs, ecl); +} + + +QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) { + vector segs{QrSegment::makeBytes(data)}; + return encodeSegments(segs, ecl); +} + + +QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, + int minVersion, int maxVersion, int mask, bool boostEcl) { + if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7) + throw std::invalid_argument("Invalid value"); + + // Find the minimal version number to use + int version, dataUsedBits; + for (version = minVersion; ; version++) { + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available + dataUsedBits = QrSegment::getTotalBits(segs, version); + if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) + break; // This version number is found to be suitable + if (version >= maxVersion) { // All versions in the range could not fit the given data + std::ostringstream sb; + if (dataUsedBits == -1) + sb << "Segment too long"; + else { + sb << "Data length = " << dataUsedBits << " bits, "; + sb << "Max capacity = " << dataCapacityBits << " bits"; + } + throw data_too_long(sb.str()); + } + } + if (dataUsedBits == -1) + throw std::logic_error("Assertion error"); + + // Increase the error correction level while the data still fits in the current version number + for (Ecc newEcl : vector{Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high + if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8) + ecl = newEcl; + } + + // Concatenate all segments to create the data bit string + BitBuffer bb; + for (const QrSegment &seg : segs) { + bb.appendBits(static_cast(seg.getMode().getModeBits()), 4); + bb.appendBits(static_cast(seg.getNumChars()), seg.getMode().numCharCountBits(version)); + bb.insert(bb.end(), seg.getData().begin(), seg.getData().end()); + } + if (bb.size() != static_cast(dataUsedBits)) + throw std::logic_error("Assertion error"); + + // Add terminator and pad up to a byte if applicable + size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8; + if (bb.size() > dataCapacityBits) + throw std::logic_error("Assertion error"); + bb.appendBits(0, std::min(4, static_cast(dataCapacityBits - bb.size()))); + bb.appendBits(0, (8 - static_cast(bb.size() % 8)) % 8); + if (bb.size() % 8 != 0) + throw std::logic_error("Assertion error"); + + // Pad with alternating bytes until data capacity is reached + for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + bb.appendBits(padByte, 8); + + // Pack bits into bytes in big endian + vector dataCodewords(bb.size() / 8); + for (size_t i = 0; i < bb.size(); i++) + dataCodewords[i >> 3] |= (bb.at(i) ? 1 : 0) << (7 - (i & 7)); + + // Create the QR Code object + return QrCode(version, ecl, dataCodewords, mask); +} + + +QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) : + // Initialize fields and check arguments + version(ver), + errorCorrectionLevel(ecl) { + if (ver < MIN_VERSION || ver > MAX_VERSION) + throw std::domain_error("Version value out of range"); + if (msk < -1 || msk > 7) + throw std::domain_error("Mask value out of range"); + size = ver * 4 + 17; + size_t sz = static_cast(size); + modules = vector >(sz, vector(sz)); // Initially all white + isFunction = vector >(sz, vector(sz)); + + // Compute ECC, draw modules + drawFunctionPatterns(); + const vector allCodewords = addEccAndInterleave(dataCodewords); + drawCodewords(allCodewords); + + // Do masking + if (msk == -1) { // Automatically choose best mask + long minPenalty = LONG_MAX; + for (int i = 0; i < 8; i++) { + applyMask(i); + drawFormatBits(i); + long penalty = getPenaltyScore(); + if (penalty < minPenalty) { + msk = i; + minPenalty = penalty; + } + applyMask(i); // Undoes the mask due to XOR + } + } + if (msk < 0 || msk > 7) + throw std::logic_error("Assertion error"); + this->mask = msk; + applyMask(msk); // Apply the final choice of mask + drawFormatBits(msk); // Overwrite old format bits + + isFunction.clear(); + isFunction.shrink_to_fit(); +} + + +int QrCode::getVersion() const { + return version; +} + + +int QrCode::getSize() const { + return size; +} + + +QrCode::Ecc QrCode::getErrorCorrectionLevel() const { + return errorCorrectionLevel; +} + + +int QrCode::getMask() const { + return mask; +} + + +bool QrCode::getModule(int x, int y) const { + return 0 <= x && x < size && 0 <= y && y < size && module(x, y); +} + + +std::string QrCode::toSvgString(int border) const { + if (border < 0) + throw std::domain_error("Border must be non-negative"); + if (border > INT_MAX / 2 || border * 2 > INT_MAX - size) + throw std::overflow_error("Border too large"); + + std::ostringstream sb; + sb << "\n"; + sb << "\n"; + sb << "\n"; + sb << "\t\n"; + sb << "\t\n"; + sb << "\n"; + return sb.str(); +} + + +void QrCode::drawFunctionPatterns() { + // Draw horizontal and vertical timing patterns + for (int i = 0; i < size; i++) { + setFunctionModule(6, i, i % 2 == 0); + setFunctionModule(i, 6, i % 2 == 0); + } + + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) + drawFinderPattern(3, 3); + drawFinderPattern(size - 4, 3); + drawFinderPattern(3, size - 4); + + // Draw numerous alignment patterns + const vector alignPatPos = getAlignmentPatternPositions(); + size_t numAlign = alignPatPos.size(); + for (size_t i = 0; i < numAlign; i++) { + for (size_t j = 0; j < numAlign; j++) { + // Don't draw on the three finder corners + if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) + drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j)); + } + } + + // Draw configuration data + drawFormatBits(0); // Dummy mask value; overwritten later in the constructor + drawVersion(); +} + + +void QrCode::drawFormatBits(int msk) { + // Calculate error correction code and pack bits + int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3 + int rem = data; + for (int i = 0; i < 10; i++) + rem = (rem << 1) ^ ((rem >> 9) * 0x537); + int bits = (data << 10 | rem) ^ 0x5412; // uint15 + if (bits >> 15 != 0) + throw std::logic_error("Assertion error"); + + // Draw first copy + for (int i = 0; i <= 5; i++) + setFunctionModule(8, i, getBit(bits, i)); + setFunctionModule(8, 7, getBit(bits, 6)); + setFunctionModule(8, 8, getBit(bits, 7)); + setFunctionModule(7, 8, getBit(bits, 8)); + for (int i = 9; i < 15; i++) + setFunctionModule(14 - i, 8, getBit(bits, i)); + + // Draw second copy + for (int i = 0; i < 8; i++) + setFunctionModule(size - 1 - i, 8, getBit(bits, i)); + for (int i = 8; i < 15; i++) + setFunctionModule(8, size - 15 + i, getBit(bits, i)); + setFunctionModule(8, size - 8, true); // Always black +} + + +void QrCode::drawVersion() { + if (version < 7) + return; + + // Calculate error correction code and pack bits + int rem = version; // version is uint6, in the range [7, 40] + for (int i = 0; i < 12; i++) + rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); + long bits = static_cast(version) << 12 | rem; // uint18 + if (bits >> 18 != 0) + throw std::logic_error("Assertion error"); + + // Draw two copies + for (int i = 0; i < 18; i++) { + bool bit = getBit(bits, i); + int a = size - 11 + i % 3; + int b = i / 3; + setFunctionModule(a, b, bit); + setFunctionModule(b, a, bit); + } +} + + +void QrCode::drawFinderPattern(int x, int y) { + for (int dy = -4; dy <= 4; dy++) { + for (int dx = -4; dx <= 4; dx++) { + int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm + int xx = x + dx, yy = y + dy; + if (0 <= xx && xx < size && 0 <= yy && yy < size) + setFunctionModule(xx, yy, dist != 2 && dist != 4); + } + } +} + + +void QrCode::drawAlignmentPattern(int x, int y) { + for (int dy = -2; dy <= 2; dy++) { + for (int dx = -2; dx <= 2; dx++) + setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1); + } +} + + +void QrCode::setFunctionModule(int x, int y, bool isBlack) { + size_t ux = static_cast(x); + size_t uy = static_cast(y); + modules .at(uy).at(ux) = isBlack; + isFunction.at(uy).at(ux) = true; +} + + +bool QrCode::module(int x, int y) const { + return modules.at(static_cast(y)).at(static_cast(x)); +} + + +vector QrCode::addEccAndInterleave(const vector &data) const { + if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel))) + throw std::invalid_argument("Invalid argument"); + + // Calculate parameter numbers + int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; + int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast(errorCorrectionLevel)][version]; + int rawCodewords = getNumRawDataModules(version) / 8; + int numShortBlocks = numBlocks - rawCodewords % numBlocks; + int shortBlockLen = rawCodewords / numBlocks; + + // Split data into blocks and append ECC to each block + vector > blocks; + const vector rsDiv = reedSolomonComputeDivisor(blockEccLen); + for (int i = 0, k = 0; i < numBlocks; i++) { + vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); + k += static_cast(dat.size()); + const vector ecc = reedSolomonComputeRemainder(dat, rsDiv); + if (i < numShortBlocks) + dat.push_back(0); + dat.insert(dat.end(), ecc.cbegin(), ecc.cend()); + blocks.push_back(std::move(dat)); + } + + // Interleave (not concatenate) the bytes from every block into a single sequence + vector result; + for (size_t i = 0; i < blocks.at(0).size(); i++) { + for (size_t j = 0; j < blocks.size(); j++) { + // Skip the padding byte in short blocks + if (i != static_cast(shortBlockLen - blockEccLen) || j >= static_cast(numShortBlocks)) + result.push_back(blocks.at(j).at(i)); + } + } + if (result.size() != static_cast(rawCodewords)) + throw std::logic_error("Assertion error"); + return result; +} + + +void QrCode::drawCodewords(const vector &data) { + if (data.size() != static_cast(getNumRawDataModules(version) / 8)) + throw std::invalid_argument("Invalid argument"); + + size_t i = 0; // Bit index into the data + // Do the funny zigzag scan + for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair + if (right == 6) + right = 5; + for (int vert = 0; vert < size; vert++) { // Vertical counter + for (int j = 0; j < 2; j++) { + size_t x = static_cast(right - j); // Actual x coordinate + bool upward = ((right + 1) & 2) == 0; + size_t y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate + if (!isFunction.at(y).at(x) && i < data.size() * 8) { + modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast(i & 7)); + i++; + } + // If this QR Code has any remainder bits (0 to 7), they were assigned as + // 0/false/white by the constructor and are left unchanged by this method + } + } + } + if (i != data.size() * 8) + throw std::logic_error("Assertion error"); +} + + +void QrCode::applyMask(int msk) { + if (msk < 0 || msk > 7) + throw std::domain_error("Mask value out of range"); + size_t sz = static_cast(size); + for (size_t y = 0; y < sz; y++) { + for (size_t x = 0; x < sz; x++) { + bool invert; + switch (msk) { + case 0: invert = (x + y) % 2 == 0; break; + case 1: invert = y % 2 == 0; break; + case 2: invert = x % 3 == 0; break; + case 3: invert = (x + y) % 3 == 0; break; + case 4: invert = (x / 3 + y / 2) % 2 == 0; break; + case 5: invert = x * y % 2 + x * y % 3 == 0; break; + case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break; + case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break; + default: throw std::logic_error("Assertion error"); + } + modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x)); + } + } +} + + +long QrCode::getPenaltyScore() const { + long result = 0; + + // Adjacent modules in row having same color, and finder-like patterns + for (int y = 0; y < size; y++) { + bool runColor = false; + int runX = 0; + std::array runHistory = {}; + for (int x = 0; x < size; x++) { + if (module(x, y) == runColor) { + runX++; + if (runX == 5) + result += PENALTY_N1; + else if (runX > 5) + result++; + } else { + finderPenaltyAddHistory(runX, runHistory); + if (!runColor) + result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; + runColor = module(x, y); + runX = 1; + } + } + result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3; + } + // Adjacent modules in column having same color, and finder-like patterns + for (int x = 0; x < size; x++) { + bool runColor = false; + int runY = 0; + std::array runHistory = {}; + for (int y = 0; y < size; y++) { + if (module(x, y) == runColor) { + runY++; + if (runY == 5) + result += PENALTY_N1; + else if (runY > 5) + result++; + } else { + finderPenaltyAddHistory(runY, runHistory); + if (!runColor) + result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3; + runColor = module(x, y); + runY = 1; + } + } + result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3; + } + + // 2*2 blocks of modules having same color + for (int y = 0; y < size - 1; y++) { + for (int x = 0; x < size - 1; x++) { + bool color = module(x, y); + if ( color == module(x + 1, y) && + color == module(x, y + 1) && + color == module(x + 1, y + 1)) + result += PENALTY_N2; + } + } + + // Balance of black and white modules + int black = 0; + for (const vector &row : modules) { + for (bool color : row) { + if (color) + black++; + } + } + int total = size * size; // Note that size is odd, so black/total != 1/2 + // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)% + int k = static_cast((std::abs(black * 20L - total * 10L) + total - 1) / total) - 1; + result += k * PENALTY_N4; + return result; +} + + +vector QrCode::getAlignmentPatternPositions() const { + if (version == 1) + return vector(); + else { + int numAlign = version / 7 + 2; + int step = (version == 32) ? 26 : + (version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2; + vector result; + for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step) + result.insert(result.begin(), pos); + result.insert(result.begin(), 6); + return result; + } +} + + +int QrCode::getNumRawDataModules(int ver) { + if (ver < MIN_VERSION || ver > MAX_VERSION) + throw std::domain_error("Version number out of range"); + int result = (16 * ver + 128) * ver + 64; + if (ver >= 2) { + int numAlign = ver / 7 + 2; + result -= (25 * numAlign - 10) * numAlign - 55; + if (ver >= 7) + result -= 36; + } + if (!(208 <= result && result <= 29648)) + throw std::logic_error("Assertion error"); + return result; +} + + +int QrCode::getNumDataCodewords(int ver, Ecc ecl) { + return getNumRawDataModules(ver) / 8 + - ECC_CODEWORDS_PER_BLOCK [static_cast(ecl)][ver] + * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver]; +} + + +vector QrCode::reedSolomonComputeDivisor(int degree) { + if (degree < 1 || degree > 255) + throw std::domain_error("Degree out of range"); + // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1. + // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}. + vector result(static_cast(degree)); + result.at(result.size() - 1) = 1; // Start off with the monomial x^0 + + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), + // and drop the highest monomial term which is always 1x^degree. + // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). + uint8_t root = 1; + for (int i = 0; i < degree; i++) { + // Multiply the current product by (x - r^i) + for (size_t j = 0; j < result.size(); j++) { + result.at(j) = reedSolomonMultiply(result.at(j), root); + if (j + 1 < result.size()) + result.at(j) ^= result.at(j + 1); + } + root = reedSolomonMultiply(root, 0x02); + } + return result; +} + + +vector QrCode::reedSolomonComputeRemainder(const vector &data, const vector &divisor) { + vector result(divisor.size()); + for (uint8_t b : data) { // Polynomial division + uint8_t factor = b ^ result.at(0); + result.erase(result.begin()); + result.push_back(0); + for (size_t i = 0; i < result.size(); i++) + result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor); + } + return result; +} + + +uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) { + // Russian peasant multiplication + int z = 0; + for (int i = 7; i >= 0; i--) { + z = (z << 1) ^ ((z >> 7) * 0x11D); + z ^= ((y >> i) & 1) * x; + } + if (z >> 8 != 0) + throw std::logic_error("Assertion error"); + return static_cast(z); +} + + +int QrCode::finderPenaltyCountPatterns(const std::array &runHistory) const { + int n = runHistory.at(1); + if (n > size * 3) + throw std::logic_error("Assertion error"); + bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n; + return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0) + + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0); +} + + +int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const { + if (currentRunColor) { // Terminate black run + finderPenaltyAddHistory(currentRunLength, runHistory); + currentRunLength = 0; + } + currentRunLength += size; // Add white border to final run + finderPenaltyAddHistory(currentRunLength, runHistory); + return finderPenaltyCountPatterns(runHistory); +} + + +void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const { + if (runHistory.at(0) == 0) + currentRunLength += size; // Add white border to initial run + std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end()); + runHistory.at(0) = currentRunLength; +} + + +bool QrCode::getBit(long x, int i) { + return ((x >> i) & 1) != 0; +} + + +/*---- Tables of constants ----*/ + +const int QrCode::PENALTY_N1 = 3; +const int QrCode::PENALTY_N2 = 3; +const int QrCode::PENALTY_N3 = 40; +const int QrCode::PENALTY_N4 = 10; + + +const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low + {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium + {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile + {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High +}; + +const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low + {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium + {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile + {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High +}; + + +data_too_long::data_too_long(const std::string &msg) : + std::length_error(msg) {} + + + +BitBuffer::BitBuffer() + : std::vector() {} + + +void BitBuffer::appendBits(std::uint32_t val, int len) { + if (len < 0 || len > 31 || val >> len != 0) + throw std::domain_error("Value out of range"); + for (int i = len - 1; i >= 0; i--) // Append bit by bit + this->push_back(((val >> i) & 1) != 0); +} + +} diff --git a/src/external/qr_code_generator/QrCode.hpp b/src/external/qr_code_generator/QrCode.hpp new file mode 100644 index 00000000..7341e410 --- /dev/null +++ b/src/external/qr_code_generator/QrCode.hpp @@ -0,0 +1,556 @@ +/* + * QR Code generator library (C++) + * + * Copyright (c) Project Nayuki. (MIT License) + * https://www.nayuki.io/page/qr-code-generator-library + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +#pragma once + +#include +#include +#include +#include +#include + + +namespace qrcodegen { + +/* + * A segment of character/binary/control data in a QR Code symbol. + * Instances of this class are immutable. + * The mid-level way to create a segment is to take the payload data + * and call a static factory function such as QrSegment::makeNumeric(). + * The low-level way to create a segment is to custom-make the bit buffer + * and call the QrSegment() constructor with appropriate values. + * This segment class imposes no length restrictions, but QR Codes have restrictions. + * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. + * Any segment longer than this is meaningless for the purpose of generating QR Codes. + */ +class QrSegment final { + + /*---- Public helper enumeration ----*/ + + /* + * Describes how a segment's data bits are interpreted. Immutable. + */ + public: class Mode final { + + /*-- Constants --*/ + + public: static const Mode NUMERIC; + public: static const Mode ALPHANUMERIC; + public: static const Mode BYTE; + public: static const Mode KANJI; + public: static const Mode ECI; + + + /*-- Fields --*/ + + // The mode indicator bits, which is a uint4 value (range 0 to 15). + private: int modeBits; + + // Number of character count bits for three different version ranges. + private: int numBitsCharCount[3]; + + + /*-- Constructor --*/ + + private: Mode(int mode, int cc0, int cc1, int cc2); + + + /*-- Methods --*/ + + /* + * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15). + */ + public: int getModeBits() const; + + /* + * (Package-private) Returns the bit width of the character count field for a segment in + * this mode in a QR Code at the given version number. The result is in the range [0, 16]. + */ + public: int numCharCountBits(int ver) const; + + }; + + + + /*---- Static factory functions (mid level) ----*/ + + /* + * Returns a segment representing the given binary data encoded in + * byte mode. All input byte vectors are acceptable. Any text string + * can be converted to UTF-8 bytes and encoded as a byte mode segment. + */ + public: static QrSegment makeBytes(const std::vector &data); + + + /* + * Returns a segment representing the given string of decimal digits encoded in numeric mode. + */ + public: static QrSegment makeNumeric(const char *digits); + + + /* + * Returns a segment representing the given text string encoded in alphanumeric mode. + * The characters allowed are: 0 to 9, A to Z (uppercase only), space, + * dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ + public: static QrSegment makeAlphanumeric(const char *text); + + + /* + * Returns a list of zero or more segments to represent the given text string. The result + * may use various segment modes and switch modes to optimize the length of the bit stream. + */ + public: static std::vector makeSegments(const char *text); + + + /* + * Returns a segment representing an Extended Channel Interpretation + * (ECI) designator with the given assignment value. + */ + public: static QrSegment makeEci(long assignVal); + + + /*---- Public static helper functions ----*/ + + /* + * Tests whether the given string can be encoded as a segment in alphanumeric mode. + * A string is encodable iff each character is in the following set: 0 to 9, A to Z + * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. + */ + public: static bool isAlphanumeric(const char *text); + + + /* + * Tests whether the given string can be encoded as a segment in numeric mode. + * A string is encodable iff each character is in the range 0 to 9. + */ + public: static bool isNumeric(const char *text); + + + + /*---- Instance fields ----*/ + + /* The mode indicator of this segment. Accessed through getMode(). */ + private: Mode mode; + + /* The length of this segment's unencoded data. Measured in characters for + * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode. + * Always zero or positive. Not the same as the data's bit length. + * Accessed through getNumChars(). */ + private: int numChars; + + /* The data bits of this segment. Accessed through getData(). */ + private: std::vector data; + + + /*---- Constructors (low level) ----*/ + + /* + * Creates a new QR Code segment with the given attributes and data. + * The character count (numCh) must agree with the mode and the bit buffer length, + * but the constraint isn't checked. The given bit buffer is copied and stored. + */ + public: QrSegment(Mode md, int numCh, const std::vector &dt); + + + /* + * Creates a new QR Code segment with the given parameters and data. + * The character count (numCh) must agree with the mode and the bit buffer length, + * but the constraint isn't checked. The given bit buffer is moved and stored. + */ + public: QrSegment(Mode md, int numCh, std::vector &&dt); + + + /*---- Methods ----*/ + + /* + * Returns the mode field of this segment. + */ + public: Mode getMode() const; + + + /* + * Returns the character count field of this segment. + */ + public: int getNumChars() const; + + + /* + * Returns the data bits of this segment. + */ + public: const std::vector &getData() const; + + + // (Package-private) Calculates the number of bits needed to encode the given segments at + // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a + // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX. + public: static int getTotalBits(const std::vector &segs, int version); + + + /*---- Private constant ----*/ + + /* The set of all legal characters in alphanumeric mode, where + * each character value maps to the index in the string. */ + private: static const char *ALPHANUMERIC_CHARSET; + +}; + + + +/* + * A QR Code symbol, which is a type of two-dimension barcode. + * Invented by Denso Wave and described in the ISO/IEC 18004 standard. + * Instances of this class represent an immutable square grid of black and white cells. + * The class provides static factory functions to create a QR Code from text or binary data. + * The class covers the QR Code Model 2 specification, supporting all versions (sizes) + * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. + * + * Ways to create a QR Code object: + * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary(). + * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments(). + * - Low level: Custom-make the array of data codeword bytes (including + * segment headers and final padding, excluding error correction codewords), + * supply the appropriate version number, and call the QrCode() constructor. + * (Note that all ways require supplying the desired error correction level.) + */ +class QrCode final { + + /*---- Public helper enumeration ----*/ + + /* + * The error correction level in a QR Code symbol. + */ + public: enum class Ecc { + LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords + MEDIUM , // The QR Code can tolerate about 15% erroneous codewords + QUARTILE, // The QR Code can tolerate about 25% erroneous codewords + HIGH , // The QR Code can tolerate about 30% erroneous codewords + }; + + + // Returns a value in the range 0 to 3 (unsigned 2-bit integer). + private: static int getFormatBits(Ecc ecl); + + + + /*---- Static factory functions (high level) ----*/ + + /* + * Returns a QR Code representing the given Unicode text string at the given error correction level. + * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer + * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible + * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than + * the ecl argument if it can be done without increasing the version. + */ + public: static QrCode encodeText(const char *text, Ecc ecl); + + + /* + * Returns a QR Code representing the given binary data at the given error correction level. + * This function always encodes using the binary segment mode, not any text mode. The maximum number of + * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output. + * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version. + */ + public: static QrCode encodeBinary(const std::vector &data, Ecc ecl); + + + /*---- Static factory functions (mid level) ----*/ + + /* + * Returns a QR Code representing the given segments with the given encoding parameters. + * The smallest possible QR Code version within the given range is automatically + * chosen for the output. Iff boostEcl is true, then the ECC level of the result + * may be higher than the ecl argument if it can be done without increasing the + * version. The mask number is either between 0 to 7 (inclusive) to force that + * mask, or -1 to automatically choose an appropriate mask (which may be slow). + * This function allows the user to create a custom sequence of segments that switches + * between modes (such as alphanumeric and byte) to encode text in less space. + * This is a mid-level API; the high-level API is encodeText() and encodeBinary(). + */ + public: static QrCode encodeSegments(const std::vector &segs, Ecc ecl, + int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters + + + + /*---- Instance fields ----*/ + + // Immutable scalar parameters: + + /* The version number of this QR Code, which is between 1 and 40 (inclusive). + * This determines the size of this barcode. */ + private: int version; + + /* The width and height of this QR Code, measured in modules, between + * 21 and 177 (inclusive). This is equal to version * 4 + 17. */ + private: int size; + + /* The error correction level used in this QR Code. */ + private: Ecc errorCorrectionLevel; + + /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive). + * Even if a QR Code is created with automatic masking requested (mask = -1), + * the resulting object still has a mask value between 0 and 7. */ + private: int mask; + + // Private grids of modules/pixels, with dimensions of size*size: + + // The modules of this QR Code (false = white, true = black). + // Immutable after constructor finishes. Accessed through getModule(). + private: std::vector > modules; + + // Indicates function modules that are not subjected to masking. Discarded when constructor finishes. + private: std::vector > isFunction; + + + + /*---- Constructor (low level) ----*/ + + /* + * Creates a new QR Code with the given version number, + * error correction level, data codeword bytes, and mask number. + * This is a low-level API that most users should not use directly. + * A mid-level API is the encodeSegments() function. + */ + public: QrCode(int ver, Ecc ecl, const std::vector &dataCodewords, int msk); + + + + /*---- Public instance methods ----*/ + + /* + * Returns this QR Code's version, in the range [1, 40]. + */ + public: int getVersion() const; + + + /* + * Returns this QR Code's size, in the range [21, 177]. + */ + public: int getSize() const; + + + /* + * Returns this QR Code's error correction level. + */ + public: Ecc getErrorCorrectionLevel() const; + + + /* + * Returns this QR Code's mask, in the range [0, 7]. + */ + public: int getMask() const; + + + /* + * Returns the color of the module (pixel) at the given coordinates, which is false + * for white or true for black. The top left corner has the coordinates (x=0, y=0). + * If the given coordinates are out of bounds, then false (white) is returned. + */ + public: bool getModule(int x, int y) const; + + + /* + * Returns a string of SVG code for an image depicting this QR Code, with the given number + * of border modules. The string always uses Unix newlines (\n), regardless of the platform. + */ + public: std::string toSvgString(int border) const; + + + + /*---- Private helper methods for constructor: Drawing function modules ----*/ + + // Reads this object's version field, and draws and marks all function modules. + private: void drawFunctionPatterns(); + + + // Draws two copies of the format bits (with its own error correction code) + // based on the given mask and this object's error correction level field. + private: void drawFormatBits(int msk); + + + // Draws two copies of the version bits (with its own error correction code), + // based on this object's version field, iff 7 <= version <= 40. + private: void drawVersion(); + + + // Draws a 9*9 finder pattern including the border separator, + // with the center module at (x, y). Modules can be out of bounds. + private: void drawFinderPattern(int x, int y); + + + // Draws a 5*5 alignment pattern, with the center module + // at (x, y). All modules must be in bounds. + private: void drawAlignmentPattern(int x, int y); + + + // Sets the color of a module and marks it as a function module. + // Only used by the constructor. Coordinates must be in bounds. + private: void setFunctionModule(int x, int y, bool isBlack); + + + // Returns the color of the module at the given coordinates, which must be in range. + private: bool module(int x, int y) const; + + + /*---- Private helper methods for constructor: Codewords and masking ----*/ + + // Returns a new byte string representing the given data with the appropriate error correction + // codewords appended to it, based on this object's version and error correction level. + private: std::vector addEccAndInterleave(const std::vector &data) const; + + + // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire + // data area of this QR Code. Function modules need to be marked off before this is called. + private: void drawCodewords(const std::vector &data); + + + // XORs the codeword modules in this QR Code with the given mask pattern. + // The function modules must be marked and the codeword bits must be drawn + // before masking. Due to the arithmetic of XOR, calling applyMask() with + // the same mask value a second time will undo the mask. A final well-formed + // QR Code needs exactly one (not zero, two, etc.) mask applied. + private: void applyMask(int msk); + + + // Calculates and returns the penalty score based on state of this QR Code's current modules. + // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. + private: long getPenaltyScore() const; + + + + /*---- Private helper functions ----*/ + + // Returns an ascending list of positions of alignment patterns for this version number. + // Each position is in the range [0,177), and are used on both the x and y axes. + // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. + private: std::vector getAlignmentPatternPositions() const; + + + // Returns the number of data bits that can be stored in a QR Code of the given version number, after + // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. + // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. + private: static int getNumRawDataModules(int ver); + + + // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any + // QR Code of the given version number and error correction level, with remainder bits discarded. + // This stateless pure function could be implemented as a (40*4)-cell lookup table. + private: static int getNumDataCodewords(int ver, Ecc ecl); + + + // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be + // implemented as a lookup table over all possible parameter values, instead of as an algorithm. + private: static std::vector reedSolomonComputeDivisor(int degree); + + + // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials. + private: static std::vector reedSolomonComputeRemainder(const std::vector &data, const std::vector &divisor); + + + // Returns the product of the two given field elements modulo GF(2^8/0x11D). + // All inputs are valid. This could be implemented as a 256*256 lookup table. + private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y); + + + // Can only be called immediately after a white run is added, and + // returns either 0, 1, or 2. A helper function for getPenaltyScore(). + private: int finderPenaltyCountPatterns(const std::array &runHistory) const; + + + // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). + private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const; + + + // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). + private: void finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const; + + + // Returns true iff the i'th bit of x is set to 1. + private: static bool getBit(long x, int i); + + + /*---- Constants and tables ----*/ + + // The minimum version number supported in the QR Code Model 2 standard. + public: static constexpr int MIN_VERSION = 1; + + // The maximum version number supported in the QR Code Model 2 standard. + public: static constexpr int MAX_VERSION = 40; + + + // For use in getPenaltyScore(), when evaluating which mask is best. + private: static const int PENALTY_N1; + private: static const int PENALTY_N2; + private: static const int PENALTY_N3; + private: static const int PENALTY_N4; + + + private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; + private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; + +}; + + + +/*---- Public exception class ----*/ + +/* + * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include: + * - Decrease the error correction level if it was greater than Ecc::LOW. + * - If the encodeSegments() function was called with a maxVersion argument, then increase + * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other + * factory functions because they search all versions up to QrCode::MAX_VERSION.) + * - Split the text data into better or optimal segments in order to reduce the number of bits required. + * - Change the text or binary data to be shorter. + * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric). + * - Propagate the error upward to the caller/user. + */ +class data_too_long : public std::length_error { + + public: explicit data_too_long(const std::string &msg); + +}; + + + +/* + * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment. + */ +class BitBuffer final : public std::vector { + + /*---- Constructor ----*/ + + // Creates an empty bit buffer (length 0). + public: BitBuffer(); + + + + /*---- Method ----*/ + + // Appends the given number of low-order bits of the given value + // to this buffer. Requires 0 <= len <= 31 and val < 2^len. + public: void appendBits(std::uint32_t val, int len); + +}; + +} From 921c394edc55f82f48e0486c186c3033c703b2a8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 11:50:09 -0500 Subject: [PATCH 213/417] Update LICENSE --- LICENSE | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 833c9cda..5c2f6162 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2011-2019 Eric Froemling +Note: portions of this software, namely external libraries, are covered by +other licenses such as BSD. See individual licenses under src/external/*. +All other code is covered by the following (MIT License): Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 0804d7fcbbaa10bf53d11893fa423b7cfe4df282 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 13:47:34 -0500 Subject: [PATCH 214/417] pubsync test --- .efrocachemap | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 5d4fda8f..846e4a06 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/72/55/dfa285b98b91dcf3b9a4959b2de7", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/93/f4/e4f6f62cf48e2b945a2e129debc2", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/37/a3cf70e0fcddeedded8a59ea83a1", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/27/d1b008386dab949c7a56e7d91f1f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/52/eb/cd526a92072fc57ceff9ead7be4c", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9d/6f/bdba4c9916b076076608e5c1b10a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1d/4e/1fefad2610732934ec9afacf15e4", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/74/81/60b8c9b55342697d3708827c2fb5", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/75/b7/d1c41081caeefeb6d367ea27d591", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/9a/b6/4f2271173853f4e260c3d50488e6" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/b7/f7a54a77a43a97670bd448dfd3cc", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/55/a35c61332f2b6d761f87f9ec2094", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4d/04/9b581b616ff015783ae7933dcd6b", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/89/e20095265d6f9ba568d983cf7e1f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/e3/65bba5e8585d7fc3f181ad6a3ad4", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/78/26/83c0879bee2364c7ebac1aa0fa0d", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/14/89/b155bde4ec2b545f02dd95948a1d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/56/d7/34926c551b6af98f8cfc038eb772", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ed/4e/8c5687c5130c5e99e355ddca6e92", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/38/e075856c1a5bac98885c03c92c3e" } \ No newline at end of file From 87b6716d59a34bf585cdaaf267899d384e26b8af Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 13:52:02 -0500 Subject: [PATCH 215/417] Adding more C++ sources --- .efrocachemap | 20 +- .idea/dictionaries/ericf.xml | 15 +- config/config.json | 16 + src/ballistica/ballistica.cc | 343 +++++++ src/ballistica/ballistica.h | 226 +++++ src/ballistica/core/context.cc | 142 +++ src/ballistica/core/context.h | 128 +++ src/ballistica/core/exception.cc | 83 ++ src/ballistica/core/exception.h | 82 ++ src/ballistica/core/fatal_error.cc | 169 ++++ src/ballistica/core/fatal_error.h | 33 + src/ballistica/core/inline.cc | 11 + src/ballistica/core/inline.h | 143 +++ src/ballistica/core/logging.cc | 214 +++++ src/ballistica/core/logging.h | 35 + src/ballistica/core/macros.cc | 106 +++ src/ballistica/core/macros.h | 166 ++++ src/ballistica/core/module.cc | 50 + src/ballistica/core/module.h | 70 ++ src/ballistica/core/object.cc | 233 +++++ src/ballistica/core/object.h | 671 +++++++++++++ src/ballistica/core/thread.cc | 630 ++++++++++++ src/ballistica/core/thread.h | 249 +++++ src/ballistica/core/types.h | 1068 +++++++++++++++++++++ src/ballistica/generic/base64.cc | 161 ++++ src/ballistica/generic/base64.h | 16 + src/ballistica/generic/buffer.h | 95 ++ src/ballistica/generic/huffman.cc | 590 ++++++++++++ src/ballistica/generic/huffman.h | 61 ++ src/ballistica/generic/json.cc | 1105 ++++++++++++++++++++++ src/ballistica/generic/json.h | 239 +++++ src/ballistica/generic/lambda_runnable.h | 38 + src/ballistica/generic/real_timer.h | 49 + src/ballistica/generic/runnable.cc | 11 + src/ballistica/generic/runnable.h | 23 + src/ballistica/generic/timer.cc | 55 ++ src/ballistica/generic/timer.h | 41 + src/ballistica/generic/timer_list.cc | 271 ++++++ src/ballistica/generic/timer_list.h | 68 ++ src/ballistica/generic/utf8.cc | 449 +++++++++ src/ballistica/generic/utf8.h | 85 ++ src/ballistica/generic/utils.cc | 639 +++++++++++++ src/ballistica/generic/utils.h | 387 ++++++++ tools/batools/updateproject.py | 38 +- tools/efrotools/__init__.py | 21 - tools/efrotools/code.py | 9 +- 46 files changed, 9299 insertions(+), 55 deletions(-) create mode 100644 src/ballistica/ballistica.cc create mode 100644 src/ballistica/ballistica.h create mode 100644 src/ballistica/core/context.cc create mode 100644 src/ballistica/core/context.h create mode 100644 src/ballistica/core/exception.cc create mode 100644 src/ballistica/core/exception.h create mode 100644 src/ballistica/core/fatal_error.cc create mode 100644 src/ballistica/core/fatal_error.h create mode 100644 src/ballistica/core/inline.cc create mode 100644 src/ballistica/core/inline.h create mode 100644 src/ballistica/core/logging.cc create mode 100644 src/ballistica/core/logging.h create mode 100644 src/ballistica/core/macros.cc create mode 100644 src/ballistica/core/macros.h create mode 100644 src/ballistica/core/module.cc create mode 100644 src/ballistica/core/module.h create mode 100644 src/ballistica/core/object.cc create mode 100644 src/ballistica/core/object.h create mode 100644 src/ballistica/core/thread.cc create mode 100644 src/ballistica/core/thread.h create mode 100644 src/ballistica/core/types.h create mode 100644 src/ballistica/generic/base64.cc create mode 100644 src/ballistica/generic/base64.h create mode 100644 src/ballistica/generic/buffer.h create mode 100644 src/ballistica/generic/huffman.cc create mode 100644 src/ballistica/generic/huffman.h create mode 100644 src/ballistica/generic/json.cc create mode 100644 src/ballistica/generic/json.h create mode 100644 src/ballistica/generic/lambda_runnable.h create mode 100644 src/ballistica/generic/real_timer.h create mode 100644 src/ballistica/generic/runnable.cc create mode 100644 src/ballistica/generic/runnable.h create mode 100644 src/ballistica/generic/timer.cc create mode 100644 src/ballistica/generic/timer.h create mode 100644 src/ballistica/generic/timer_list.cc create mode 100644 src/ballistica/generic/timer_list.h create mode 100644 src/ballistica/generic/utf8.cc create mode 100644 src/ballistica/generic/utf8.h create mode 100644 src/ballistica/generic/utils.cc create mode 100644 src/ballistica/generic/utils.h diff --git a/.efrocachemap b/.efrocachemap index 846e4a06..fb411c5e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/b7/f7a54a77a43a97670bd448dfd3cc", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ae/55/a35c61332f2b6d761f87f9ec2094", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4d/04/9b581b616ff015783ae7933dcd6b", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/db/89/e20095265d6f9ba568d983cf7e1f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/e3/65bba5e8585d7fc3f181ad6a3ad4", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/78/26/83c0879bee2364c7ebac1aa0fa0d", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/14/89/b155bde4ec2b545f02dd95948a1d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/56/d7/34926c551b6af98f8cfc038eb772", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ed/4e/8c5687c5130c5e99e355ddca6e92", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/8d/38/e075856c1a5bac98885c03c92c3e" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e3/43/5df3f99b46aa9b6aff2db87fabb4", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b1/06/b993362a65a5760ddfb10f2c59b9", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/99/2234c89a65d7e5d8463556d9df5e", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/96/f289ec31cdada6f41de5dce382bd", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/8d/6f2752d858b097c318920ff09cf5", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/77/1d/7986d62c92d9f34ca85396168923", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a3/da/d5f88e92926543f61bd5dd80321e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/60/8e/d7efd5e7d7a94439453909527d4e", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/b3/8124ea626db8dbd7b1744c335c7c", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/27/f7/87a5d3b8648352ac40398f86dc8e" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 5bde834d..fae1c944 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack ack'ed + ack acked acks acnt @@ -151,8 +151,8 @@ bacommon badguy bafoundation - ballistica ballistica's + ballistica ballisticacore ballisticacorecb bamaster @@ -793,8 +793,8 @@ gamedata gameinstance gamemap - gamepad gamepad's + gamepad gamepadadvanced gamepads gamepadselect @@ -1177,8 +1177,8 @@ lsqlite lssl lstart - lstr lstr's + lstr lstrs lsval ltex @@ -1362,6 +1362,9 @@ nosub nosyncdir nosyncdirs + nosyncfile + nosyncfiles + nosynctool nosynctools notdir npos @@ -1800,8 +1803,8 @@ sessionname sessionplayer sessionplayers - sessionteam sessionteam's + sessionteam sessionteams sessiontype setactivity @@ -2131,8 +2134,8 @@ txtw typeargs typecheck - typechecker typechecker's + typechecker typedval typeshed typestr diff --git a/config/config.json b/config/config.json index 793059ca..ac760956 100644 --- a/config/config.json +++ b/config/config.json @@ -2,6 +2,22 @@ "code_source_dirs": [ "src/ballistica" ], + "cpplint_blacklist": [ + "src/ballistica/generic/json.cc", + "src/ballistica/generic/json.h", + "src/ballistica/generic/utf8.cc", + "src/ballistica/graphics/texture/dds.h", + "src/ballistica/graphics/texture/ktx.cc", + "src/ballistica/platform/android/android_gl3.h", + "src/ballistica/platform/apple/app_delegate.h", + "src/ballistica/platform/apple/scripting_bridge_music.h", + "src/ballistica/platform/android/utf8/checked.h", + "src/ballistica/platform/android/utf8/unchecked.h", + "src/ballistica/platform/android/utf8/core.h", + "src/ballistica/platform/apple/sdl_main_mac.h", + "src/ballistica/platform/oculus/main_rift.cc", + "src/ballistica/platform/android/android_gl3.c" + ], "name": "BallisticaCore", "public": true, "pylint_ignored_untracked_deps": [ diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc new file mode 100644 index 00000000..82fa265b --- /dev/null +++ b/src/ballistica/ballistica.cc @@ -0,0 +1,343 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/ballistica.h" + +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_config.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_server.h" +#include "ballistica/core/fatal_error.h" +#include "ballistica/core/logging.h" +#include "ballistica/core/thread.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/dynamics/bg/bg_dynamics_server.h" +#include "ballistica/game/account.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/input/input.h" +#include "ballistica/media/media.h" +#include "ballistica/media/media_server.h" +#include "ballistica/networking/network_write_module.h" +#include "ballistica/networking/networking.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +// These are set automatically via script; don't change here. +const int kAppBuildNumber = 20192; +const char* kAppVersion = "1.5.26"; +const char* kBlessingHash = nullptr; + +// Our standalone globals. +// These are separated out for easy access. +// Everything else should go into AppGlobals (or more ideally into a class). +int g_early_log_writes{10}; +Thread* g_main_thread{}; +AppGlobals* g_app_globals{}; +AppConfig* g_app_config{}; +App* g_app{}; +Account* g_account{}; +Game* g_game{}; +BGDynamics* g_bg_dynamics{}; +BGDynamicsServer* g_bg_dynamics_server{}; +Platform* g_platform{}; +Utils* g_utils{}; +UI* g_ui{}; +Graphics* g_graphics{}; +Python* g_python{}; +Input* g_input{}; +GraphicsServer* g_graphics_server{}; +Media* g_media{}; +Audio* g_audio{}; +MediaServer* g_media_server{}; +AudioServer* g_audio_server{}; +StdInputModule* g_std_input_module{}; +NetworkReader* g_network_reader{}; +Networking* g_networking{}; +NetworkWriteModule* g_network_write_module{}; +TextGraphics* g_text_graphics{}; + +// Basic overview of our bootstrapping process: +// 1: All threads and globals are created and provisioned. Everything above +// should exist at the end of this step (if it is going to exist). +// Threads should not be talking to each other yet at this point. +// 2: The system is set in motion. Game thread is told to load/apply the config. +// This kicks off an initial-screen-creation message sent to the +// graphics-server thread. Other systems are informed that bootstrapping +// is complete and they are free to talk to each other. Initial input-devices +// are added, media loads can begin (at least ones not dependent on the +// screen/renderer), etc. +// 3: The initial screen is created on the graphics-server thread in response +// to the message sent from the game thread. A completion notice is sent +// back to the game thread when done. +// 4: Back on the game thread, any renderer-dependent media-loads/etc. can begin +// and lastly the initial game session is kicked off. + +auto BallisticaMain(int argc, char** argv) -> int { + try { + // Even at the absolute start of execution we should be able to + // phone home on errors. Set BA_CRASH_TEST=1 to test this. + if (const char* crashenv = getenv("BA_CRASH_TEST")) { + if (!strcmp(crashenv, "1")) { + FatalError("Fatal-Error-Test"); + } + } + + // ------------------------------------------------------------------------- + // Phase 1: Create and provision all globals. + // ------------------------------------------------------------------------- + + g_app_globals = new AppGlobals(argc, argv); + g_platform = Platform::Create(); + g_platform->PostInit(); + g_account = new Account(); + g_utils = new Utils(); + Scene::Init(); + + // Create a Thread wrapper around the current (main) thread. + g_main_thread = new Thread(ThreadIdentifier::kMain, ThreadType::kMain); + + // Spin up g_app. + g_platform->CreateApp(); + + // Spin up our other standard threads. + auto* media_thread = new Thread(ThreadIdentifier::kMedia); + g_app_globals->pausable_threads.push_back(media_thread); + auto* audio_thread = new Thread(ThreadIdentifier::kAudio); + g_app_globals->pausable_threads.push_back(audio_thread); + auto* game_thread = new Thread(ThreadIdentifier::kGame); + g_app_globals->pausable_threads.push_back(game_thread); + auto* network_write_thread = new Thread(ThreadIdentifier::kNetworkWrite); + g_app_globals->pausable_threads.push_back(network_write_thread); + + // And add our other standard modules to them. + game_thread->AddModule(); + network_write_thread->AddModule(); + media_thread->AddModule(); + g_main_thread->AddModule(); + audio_thread->AddModule(); + + // Now let the platform spin up any other threads/modules it uses. + // (bg-dynamics in non-headless builds, stdin/stdout where applicable, etc.) + g_platform->CreateAuxiliaryModules(); + + // Ok at this point we can be considered up-and-running. + g_app_globals->is_bootstrapped = true; + + // ------------------------------------------------------------------------- + // Phase 2: Set things in motion. + // ------------------------------------------------------------------------- + + // Ok; now that we're bootstrapped, tell the game thread to read and apply + // the config which should kick off the real action. + g_game->PushApplyConfigCall(); + + // Let the app and platform do whatever else it wants here such as adding + // initial input devices/etc. + g_app->OnBootstrapComplete(); + g_platform->OnBootstrapComplete(); + + // ------------------------------------------------------------------------- + // Phase 3/4: Create a screen and/or kick off game (in other threads). + // ------------------------------------------------------------------------- + + if (g_app->UsesEventLoop()) { + // On our event-loop using platforms we now simply sit in our event loop + // until the app is quit. + g_main_thread->RunEventLoop(false); + } else { + // In this case we'll now simply return and let the OS feed us events + // until the app quits. + // However we may need to 'prime the pump' first. For instance, + // if the main thread event loop is driven by frame draws, it may need to + // manually pump events until drawing begins (otherwise it will never + // process the 'create-screen' event and wind up deadlocked). + g_app->PrimeEventPump(); + } + } catch (const std::exception& exc) { + std::string error_msg = + std::string("Unhandled exception in BallisticaMain(): ") + exc.what(); + + FatalError::ReportFatalError(error_msg, true); + bool exit_cleanly = !IsUnmodifiedBlessedBuild(); + bool handled = FatalError::HandleFatalError(exit_cleanly, true); + + // Do the default thing if it's not been handled. + if (!handled) { + if (exit_cleanly) { + exit(1); + } else { + throw; + } + } + } + // printf("BLESSED? %d\n", static_cast(IsUnmodifiedBlessedBuild())); + + g_platform->WillExitMain(false); + return g_app_globals->return_value; +} + +auto GetRealTime() -> millisecs_t { + millisecs_t t = g_platform->GetTicks(); + + // If we're at a different time than our last query, do our funky math. + if (t != g_app_globals->last_real_time_ticks) { + std::lock_guard lock(g_app_globals->real_time_mutex); + millisecs_t passed = t - g_app_globals->last_real_time_ticks; + + // GetTicks() is supposed to be monotonic but I've seen 'passed' + // equal -1 even when it is using std::chrono::steady_clock. Let's do + // our own filtering here to make 100% sure we don't go backwards. + if (passed < 0) { + passed = 0; + } else { + // Super big times-passed probably means we went to sleep or something; + // clamp to a reasonable value. + if (passed > 250) { + passed = 250; + } + } + g_app_globals->real_time += passed; + g_app_globals->last_real_time_ticks = t; + } + return g_app_globals->real_time; +} + +auto FatalError(const std::string& message) -> void { + FatalError::ReportFatalError(message, false); + bool exit_cleanly = !IsUnmodifiedBlessedBuild(); + bool handled = FatalError::HandleFatalError(exit_cleanly, false); + assert(handled); +} + +auto GetUniqueSessionIdentifier() -> const std::string& { + static std::string session_id; + static bool have_session_id = false; + if (!have_session_id) { + srand(static_cast( + Platform::GetCurrentMilliseconds())); // NOLINT + uint32_t tval = static_cast(rand()); // NOLINT + assert(g_platform); + session_id = g_platform->GetUniqueDeviceIdentifier() + std::to_string(tval); + have_session_id = true; + if (session_id.size() >= 100) { + Log("WARNING: session id longer than it should be."); + } + } + return session_id; +} + +auto InGameThread() -> bool { + return (g_game && g_game->thread()->IsCurrent()); +} + +auto InMainThread() -> bool { + return (g_app_globals + && std::this_thread::get_id() == g_app_globals->main_thread_id); +} + +auto InGraphicsThread() -> bool { + return (g_graphics_server && g_graphics_server->thread()->IsCurrent()); +} + +auto InAudioThread() -> bool { + return (g_audio_server && g_audio_server->thread()->IsCurrent()); +} + +auto InBGDynamicsThread() -> bool { +#if !BA_HEADLESS_BUILD + return (g_bg_dynamics_server && g_bg_dynamics_server->thread()->IsCurrent()); +#else + return false; +#endif +} + +auto InMediaThread() -> bool { + return (g_media_server && g_media_server->thread()->IsCurrent()); +} + +auto InNetworkWriteThread() -> bool { + return (g_network_write_module + && g_network_write_module->thread()->IsCurrent()); +} + +auto GetInterfaceType() -> UIScale { return g_app_globals->ui_scale; } + +void Log(const std::string& msg, bool to_stdout, bool to_server) { + Logging::Log(msg, to_stdout, to_server); +} + +auto IsVRMode() -> bool { return g_app_globals->vr_mode; } + +auto IsStdinATerminal() -> bool { return g_app_globals->is_stdin_a_terminal; } + +void ScreenMessage(const std::string& s, const Vector3f& color) { + if (g_game) { + g_game->PushScreenMessage(s, color); + } else { + Log("ScreenMessage before g_game init (will be lost): '" + s + "'"); + } +} + +void ScreenMessage(const std::string& msg) { + ScreenMessage(msg, {1.0f, 1.0f, 1.0f}); +} + +auto GetCurrentThreadName() -> std::string { + return Thread::GetCurrentThreadName(); +} + +auto IsBootstrapped() -> bool { return g_app_globals->is_bootstrapped; } + +// Used by our built in exception type. +void SetPythonException(PyExcType python_type, const char* description) { + Python::SetPythonException(python_type, description); +} + +auto IsUnmodifiedBlessedBuild() -> bool { + // Assume debug builds are not blessed (we'll determine this after + // we finish calcing blessing hash, but this we don't get false positives + // up until that point) + if (g_buildconfig.debug_build()) { + return false; + } + + // Return false if we're unblessed or it seems that the user is likely + // mucking around with stuff. If we just don't know yet + // (for instance if blessing has calc hasn't completed) we assume we're + // clean. + if (g_app_globals && g_app_globals->user_ran_commands) { + return false; + } + + // If they're using custom app scripts, just consider it modified. + // Otherwise can can tend to get errors in early bootstrapping before + // we've been able to calc hashes to see if things are modified. + if (g_platform && g_platform->using_custom_app_python_dir()) { + return false; + } + + // If we don't have an embedded blessing hash, we're not blessed. Duh. + if (kBlessingHash == nullptr) { + return false; + } + + // If we have an embedded hash and we've calced ours + // and it doesn't match, consider ourself modified. + return !(g_app_globals && !g_app_globals->calced_blessing_hash.empty() + && g_app_globals->calced_blessing_hash != kBlessingHash); +} + +} // namespace ballistica + +// If desired, define main() in the global namespace. +#if BA_DEFINE_MAIN +auto main(int argc, char** argv) -> int { + return ballistica::BallisticaMain(argc, argv); +} +#endif diff --git a/src/ballistica/ballistica.h b/src/ballistica/ballistica.h new file mode 100644 index 00000000..b615fa98 --- /dev/null +++ b/src/ballistica/ballistica.h @@ -0,0 +1,226 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_BALLISTICA_H_ +#define BALLISTICA_BALLISTICA_H_ + +// Try to ensure they're providing proper config stuff. +#ifndef BA_HAVE_CONFIG +#error platform config has not been defined! +#endif + +// FIXME: We need to update to C++17 to get unified std::abs(). +// Until we do that, int types are defined in +// and float/double in , meaning its possible to call the wrong +// version if we aren't careful and only include one header. +// For now just including both here at the top level to hopefully +// minimize problems. +#ifdef __cplusplus +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "ballistica/core/exception.h" +#include "ballistica/core/inline.h" +#include "ballistica/core/macros.h" +#include "ballistica/core/types.h" + +// BA 2.0 UI testing. +#define BA_TOOLBAR_TEST 0 + +#ifdef __cplusplus + +namespace ballistica { + +extern const int kAppBuildNumber; +extern const char* kAppVersion; +extern const char* kBlessingHash; + +// Protocol version we host games with and write replays to. +// This should be incremented whenever there are changes made to the +// session-commands layer (new/removed/changed nodes, attrs, data files, +// behavior, etc.) +// Note that the packet/gamepacket/message layer can vary more organically based +// on build-numbers of connected clients/servers since none of that data is +// stored; this just needs to be observed for all the scene stuff that +// goes into replays since a single stream can get played/replayed on different +// builds (as long as they support that protocol version). +const int kProtocolVersion = 33; + +// Oldest protocol version we can act as a client to. +// This can generally be left as-is as long as only +// new nodes/attrs/commands are added and existing +// stuff is unchanged. +const int kProtocolVersionMin = 24; + +// FIXME: We should separate out connection protocol from scene protocol. We +// want to be able to watch really old replays if possible but being able to +// connect to old clients is much less important (and slows progress). + +// Protocol additions: +// 25: added a few new achievement graphics and new node attrs for displaying +// stuff in front of the UI +// 26: added penguin +// 27: added templates for LOTS of characters +// 28: added cyborg and enabled fallback sounds and textures +// 29: added bunny and eggs +// 30: added support for resource-strings in text-nodes and screen-messages +// 31: added support for short-form resource-strings, time-display-node, and +// string-to-string attr connections +// 32: added json based player profiles message, added shield +// alwaysShowHealthBar attr +// 33: handshake/handshake-response now send json dicts instead of +// just player-specs +// 34: new image_node enums, data assets. + +const int kDefaultPort = 43210; +const int kDefaultTelnetPort = 43250; + +const float kTVBorder = 0.075f; +const float kVRBorder = 0.085f; + +// Largest UDP packets we attempt to send. +// (is there a definitive answer on what this should be?) +const int kMaxPacketSize = 700; + +// Extra bytes added to message packets. +const int kMessagePacketHeaderSize = 6; + +// The screen, no matter what size/aspect, will always +// fit this virtual rectangle, so placing UI elements within +// these coords is always safe. +// (we currently match the screen ratio of an iPhone 5). +const int kBaseVirtualResX = 1207; +const int kBaseVirtualResY = 680; + +// Magic numbers at the start of our file types. +const int kBobFileID = 45623; +const int kCobFileID = 13466; +const int kBrpFileID = 83749; + +const float kPi = 3.1415926535897932384626433832795028841971693993751f; +const float kPiDeg = kPi / 180.0f; +const float kDegPi = 180.0f / kPi; + +// Sim step size in milliseconds. +const int kGameStepMilliseconds = 8; + +// Sim step size in seconds. +const float kGameStepSeconds = + (static_cast(kGameStepMilliseconds) / 1000.0f); + +// Globals. +extern int g_early_log_writes; +extern Account* g_account; +extern App* g_app; +extern AppConfig* g_app_config; +extern AppGlobals* g_app_globals; +extern Audio* g_audio; +extern AudioServer* g_audio_server; +extern BGDynamics* g_bg_dynamics; +extern BGDynamicsServer* g_bg_dynamics_server; +extern Context* g_context; +extern Game* g_game; +extern Graphics* g_graphics; +extern GraphicsServer* g_graphics_server; +extern Input* g_input; +extern Thread* g_main_thread; +extern Media* g_media; +extern MediaServer* g_media_server; +extern Networking* g_networking; +extern NetworkReader* g_network_reader; +extern NetworkWriteModule* g_network_write_module; +extern Platform* g_platform; +extern Python* g_python; +extern StdInputModule* g_std_input_module; +extern TextGraphics* g_text_graphics; +extern UI* g_ui; +extern Utils* g_utils; + +/// Main ballistica entry point. +auto BallisticaMain(int argc, char** argv) -> int; + +/// Return a string that should be universally unique to this device and +/// running instance of the app. +auto GetUniqueSessionIdentifier() -> const std::string&; + +/// Have our main threads/modules all been inited yet? +auto IsBootstrapped() -> bool; + +/// Does it appear that we are a blessed build with no known user-modifications? +auto IsUnmodifiedBlessedBuild() -> bool; + +// The following is a smattering of convenience functions declared in our top +// level namespace. Functionality can be exposed here if it is used often +// enough that avoiding the extra class includes seems like an overall +// compile-time/convenience win. + +// Print a momentary message on the screen. +auto ScreenMessage(const std::string& msg) -> void; +auto ScreenMessage(const std::string& msg, const Vector3f& color) -> void; + +/// Log a fatal error and kill the app. +/// Can be called from any thread at any time. +/// message is a message to be shown to the user if possible. +/// This will attempt to ship all accumulated logs to the master-server +/// so the standard Log() call can be used before this to include extra +/// info not relevant to the end user. +auto FatalError(const std::string& message = "") -> void; + +// Check current-threads. +auto InMainThread() -> bool; // (main and graphics are same currently) +auto InGraphicsThread() -> bool; // (main and graphics are same currently) +auto InGameThread() -> bool; +auto InAudioThread() -> bool; +auto InBGDynamicsThread() -> bool; +auto InMediaThread() -> bool; +auto InNetworkWriteThread() -> bool; + +/// Return a human-readable name for the current thread. +auto GetCurrentThreadName() -> std::string; + +/// Write a string to the log. +/// This will go to stdout, windows debug log, android log, etc. +/// A trailing newline will be added. +auto Log(const std::string& msg, bool to_stdout = true, bool to_server = true) + -> void; + +auto GetInterfaceType() -> UIScale; + +/// Return true if stdin seems to be coming from a terminal +/// (so we know to print prompts, etc). +auto IsStdinATerminal() -> bool; + +/// Are we running in a VR environment? +auto IsVRMode() -> bool; + +/// Are we running headless? +inline auto HeadlessMode() -> bool { + // (currently a build-time value but this could change later) + return g_buildconfig.headless_build(); +} + +/// Return a lightly-filtered 'real' time value in milliseconds. +/// The value returned here will never go backwards or skip ahead +/// by significant amounts (even if the app has been sleeping or whatnot). +auto GetRealTime() -> millisecs_t; + +/// Return a random float value. Not guaranteed to be deterministic or +/// consistent across platforms. +inline auto RandomFloat() -> float { + // FIXME: should convert this to something thread-safe. + return static_cast( + (static_cast(rand()) / RAND_MAX)); // NOLINT +} + +auto SetPythonException(PyExcType python_type, const char* description) -> void; + +} // namespace ballistica + +#endif // __cplusplus + +#endif // BALLISTICA_BALLISTICA_H_ diff --git a/src/ballistica/core/context.cc b/src/ballistica/core/context.cc new file mode 100644 index 00000000..1c0b15df --- /dev/null +++ b/src/ballistica/core/context.cc @@ -0,0 +1,142 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/context.h" + +#include + +#include "ballistica/game/host_activity.h" +#include "ballistica/generic/runnable.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +// Dynamically allocate this; don't want it torn down on quit. +Context* g_context = nullptr; + +void Context::Init() { + assert(!g_context); + g_context = new Context(nullptr); +} + +ContextTarget::ContextTarget() = default; +ContextTarget::~ContextTarget() = default; + +auto ContextTarget::GetHostSession() -> HostSession* { return nullptr; } + +auto ContextTarget::GetAsHostActivity() -> HostActivity* { return nullptr; } +auto ContextTarget::GetAsUIContext() -> UI* { return nullptr; } +auto ContextTarget::GetMutableScene() -> Scene* { return nullptr; } + +Context::Context() : target(g_context->target) { assert(InGameThread()); } + +auto Context::operator==(const Context& other) const -> bool { + return (target.get() == other.target.get()); +} + +Context::Context(ContextTarget* target_in) : target(target_in) {} + +auto Context::GetHostSession() const -> HostSession* { + assert(InGameThread()); + if (target.exists()) return target->GetHostSession(); + return nullptr; +} + +auto Context::GetHostActivity() const -> HostActivity* { + ContextTarget* c = target.get(); + HostActivity* a = c ? c->GetAsHostActivity() : nullptr; + assert(a == dynamic_cast(c)); // This should always match. + return a; +} + +auto Context::GetMutableScene() const -> Scene* { + ContextTarget* c = target.get(); + Scene* sg = c ? c->GetMutableScene() : nullptr; + return sg; +} + +auto Context::GetUIContext() const -> UI* { + ContextTarget* c = target.get(); + UI* uiContext = c ? c->GetAsUIContext() : nullptr; + assert(uiContext == dynamic_cast(c)); + return uiContext; +} + +ScopedSetContext::ScopedSetContext(const Object::Ref& target) { + assert(InGameThread()); + assert(g_context); + context_prev_ = *g_context; + g_context->target = target; +} + +ScopedSetContext::ScopedSetContext(ContextTarget* target) { + assert(InGameThread()); + assert(g_context); + context_prev_ = *g_context; + g_context->target = target; +} + +ScopedSetContext::ScopedSetContext(const Context& context) { + assert(InGameThread()); + assert(g_context); + context_prev_ = *g_context; + *g_context = context; +} + +ScopedSetContext::~ScopedSetContext() { + assert(InGameThread()); + assert(g_context); + // Restore old. + *g_context = context_prev_; +} + +auto ContextTarget::NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int { + // Make sure the passed runnable has a ref-count already + // (don't want them to rely on us to create initial one). + assert(runnable.exists()); + assert(runnable->is_valid_refcounted_object()); + + switch (timetype) { + case TimeType::kSim: + throw Exception("Can't create 'sim' type timers in this context"); + case TimeType::kBase: + throw Exception("Can't create 'base' type timers in this context"); + case TimeType::kReal: + throw Exception("Can't create 'real' type timers in this context"); + default: + throw Exception("Can't create that type timer in this context"); + } +} +void ContextTarget::DeleteTimer(TimeType timetype, int timer_id) { + // We throw on NewTimer; lets just ignore anything that comes + // through here to avoid messing up destructors. + Log("ContextTarget::DeleteTimer() called; unexpected."); +} + +auto ContextTarget::GetTime(TimeType timetype) -> millisecs_t { + throw Exception("Unsupported time type for this context"); +} + +auto ContextTarget::GetTexture(const std::string& name) + -> Object::Ref { + throw Exception("GetTexture() not supported in this context"); +} + +auto ContextTarget::GetSound(const std::string& name) -> Object::Ref { + throw Exception("GetSound() not supported in this context"); +} + +auto ContextTarget::GetData(const std::string& name) -> Object::Ref { + throw Exception("GetData() not supported in this context"); +} + +auto ContextTarget::GetModel(const std::string& name) -> Object::Ref { + throw Exception("GetModel() not supported in this context"); +} + +auto ContextTarget::GetCollideModel(const std::string& name) + -> Object::Ref { + throw Exception("GetCollideModel() not supported in this context"); +} + +} // namespace ballistica diff --git a/src/ballistica/core/context.h b/src/ballistica/core/context.h new file mode 100644 index 00000000..89cdb714 --- /dev/null +++ b/src/ballistica/core/context.h @@ -0,0 +1,128 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_CONTEXT_H_ +#define BALLISTICA_CORE_CONTEXT_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Stores important environmental state such as the recipient of commands. +// Callbacks and other mechanisms should save/restore the context so that their +// effects properly apply to the place they came from. +class Context { + public: + static void Init(); + + static auto current() -> const Context& { + assert(g_context); + + // Context can only be accessed from the game thread. + BA_PRECONDITION(InGameThread()); + + return *g_context; + } + static void set_current(const Context& context) { + // Context can only be accessed from the game thread. + BA_PRECONDITION(InGameThread()); + + *g_context = context; + } + + // Return the current context target, raising an Exception if there is none. + static auto current_target() -> ContextTarget& { + ContextTarget* t = current().target.get(); + if (t == nullptr) { + throw Exception("No context target set."); + } + return *t; + } + + // Default constructor will capture a copy of the current global context. + Context(); + explicit Context(ContextTarget* sgc); + auto operator==(const Context& other) const -> bool; + + Object::WeakRef target; + + // If the current Context is (or is part of) a HostSession, return it; + // otherwise return nullptr. be aware that this will return a session if the + // context is *either* a host-activity or a host-session + auto GetHostSession() const -> HostSession*; + + // return the current context as an HostActivity if it is one; otherwise + // nullptr (faster than a dynamic_cast) + auto GetHostActivity() const -> HostActivity*; + + // if the current context contains a scene that can be manipulated by + // standard commands, this returns it. This includes host-sessions, + // host-activities, and the UI context. + auto GetMutableScene() const -> Scene*; + + // return the current context as a UIContext if it is one; otherwise nullptr + // (faster than a dynamic_cst) + auto GetUIContext() const -> UI*; +}; + +// An interface for interaction with the engine; loading and wrangling media, +// nodes, etc. +// Note: it would seem like in an ideal world this could just be a pure +// virtual interface. +// However various things use WeakRef so technically they do +// all need to inherit from Object anyway. +class ContextTarget : public Object { + public: + ContextTarget(); + ~ContextTarget() override; + + // returns the HostSession associated with this context, (if there is one). + virtual auto GetHostSession() -> HostSession*; + + // Utility functions for casting; faster than dynamic_cast. + virtual auto GetAsHostActivity() -> HostActivity*; + virtual auto GetAsUIContext() -> UI*; + virtual auto GetMutableScene() -> Scene*; + + // Timer create/destroy functions. + // Times are specified in milliseconds. + // Exceptions should be thrown for unsupported timetypes in NewTimer. + // Default NewTimer implementation throws a descriptive error, so it can + // be useful to fall back on for unsupported cases. + // NOTE: make sure runnables passed in here already have non-zero + // ref-counts since a ref might not be grabbed here. + virtual auto NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int; + virtual void DeleteTimer(TimeType timetype, int timer_id); + + virtual auto GetTexture(const std::string& name) -> Object::Ref; + virtual auto GetSound(const std::string& name) -> Object::Ref; + virtual auto GetData(const std::string& name) -> Object::Ref; + virtual auto GetModel(const std::string& name) -> Object::Ref; + virtual auto GetCollideModel(const std::string& name) + -> Object::Ref; + + // Return the current time of a given type in milliseconds. + // Exceptions should be thrown for unsupported timetypes. + // Default implementation throws a descriptive error so can be + // useful to fall back on for unsupported cases + virtual auto GetTime(TimeType timetype) -> millisecs_t; +}; + +// Use this to push/pop a change to the current context +class ScopedSetContext { + public: + explicit ScopedSetContext(const Object::Ref& context); + explicit ScopedSetContext(ContextTarget* context); + explicit ScopedSetContext(const Context& context); + ~ScopedSetContext(); + + private: + BA_DISALLOW_CLASS_COPIES(ScopedSetContext); + Context context_prev_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_CORE_CONTEXT_H_ diff --git a/src/ballistica/core/exception.cc b/src/ballistica/core/exception.cc new file mode 100644 index 00000000..8327415e --- /dev/null +++ b/src/ballistica/core/exception.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/exception.h" + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +auto GetShortExceptionDescription(const std::exception& exc) -> const char* { + if (auto b_exc = dynamic_cast(&exc)) { + return b_exc->message(); + } + return exc.what(); +} + +Exception::Exception(std::string message_in, PyExcType python_type) + : message_(std::move(message_in)), python_type_(python_type) { + thread_name_ = GetCurrentThreadName(); + + // Attempt to capture a stack-trace here we can print out later if desired. + if (g_platform != nullptr) { + stack_trace_ = g_platform->GetStackTrace(); + } +} +Exception::Exception(PyExcType python_type) : python_type_(python_type) { + thread_name_ = GetCurrentThreadName(); + + // Attempt to capture a stack-trace here we can print out later if desired. + if (g_platform != nullptr) { + stack_trace_ = g_platform->GetStackTrace(); + } +} + +// Copy constructor. +Exception::Exception(const Exception& other) noexcept { + try { + thread_name_ = other.thread_name_; + message_ = other.message_; + full_description_ = other.full_description_; + python_type_ = other.python_type_; + if (other.stack_trace_) { + stack_trace_ = other.stack_trace_->copy(); + } + } catch (const std::exception&) { + // Hmmm not sure what we should do if this happens; + // for now we'll just wind up with some parts of our + // shiny new exception copy potentially missing. + // Better than crashing I suppose. + } +} + +Exception::~Exception() { delete stack_trace_; } + +auto Exception::what() const noexcept -> const char* { + // Return a nice pretty stack trace and other relevant info. + try { + // This call is const so we're technically not supposed to modify ourself, + // but a one-time flattening of our description into an internal buffer + // should be fine. + if (full_description_.empty()) { + if (stack_trace_ != nullptr) { + const_cast(this)->full_description_ = + message_ + "\nThrown from " + thread_name_ + " thread:\n" + + stack_trace_->GetDescription(); + } else { + const_cast(this)->full_description_ = message_; + } + } + return full_description_.c_str(); + } catch (const std::exception&) { + // Welp; we tried. + return "Error generating ballistica::Exception::what(); oh dear."; + } +} + +void Exception::SetPyError() const noexcept { + SetPythonException(python_type_, GetShortExceptionDescription(*this)); +} + +} // namespace ballistica diff --git a/src/ballistica/core/exception.h b/src/ballistica/core/exception.h new file mode 100644 index 00000000..92c36af3 --- /dev/null +++ b/src/ballistica/core/exception.h @@ -0,0 +1,82 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_EXCEPTION_H_ +#define BALLISTICA_CORE_EXCEPTION_H_ +#ifdef __cplusplus + +#include +#include + +#include "ballistica/core/types.h" + +namespace ballistica { + +// Notes on our C++ exception handling: +// +// std::exception in broken into two subclass categories, logic_error +// and runtime_error. It is my understanding that logic_error should be used +// as a sort of non-fatal assert() for things that the program is doing +// incorrectly, while runtime_error applies to external things such as user +// input (a user entering a name containing invalid characters, etc). +// +// In practice, we currently handle both sides identically, so the distinction +// is not really important to us. We also translate C++ exceptions to and +// from Python exceptions as their respective stacks unwind, so the distinction +// tends to get lost anyway. +// +// So for the time being we have a simple single ballistica::Exception type +// inheriting directly from std::exception that we use for pretty much anything +// going wrong. It contains useful tidbits such as a stack trace to help +// diagnose issues. We can expand on this or branch off into more particular +// types if/when the need arises. +// +// Note that any sites *catching* exception should catch std::exception +// (unless they have a particular need to catch a more specific type). This +// preserves our freedom to add variants under std::logic_error or +// std::runtime_error at a later time and also catches exceptions coming from +// std itself. + +class PlatformStackTrace; + +/// Get a short description for an exception. +/// By default, our Exception classes provide what() values that may include +/// backtraces of the throw location or other extended info that can be useful +/// to have printed in crash reports/etc. In some cases this extended info is +/// not desired, however, such as when converting a C++ exception to a Python +/// one (which will have its own backtrace and other context). This function +/// will return the raw message only if passed one of our Exceptions, and +/// simply what() in other cases. +auto GetShortExceptionDescription(const std::exception& exc) -> const char*; + +class Exception : public std::exception { + public: + // NOTE: When adding exception types here, add a corresponding + // handler in Python::SetPythonException. + + explicit Exception(std::string message = "", + PyExcType python_type = PyExcType::kRuntime); + explicit Exception(PyExcType python_type); + Exception(const Exception& other) noexcept; + ~Exception() override; + + /// Return the full description for this exception which may include + /// backtraces/etc. + auto what() const noexcept -> const char* override; + + /// Return only the raw message passed to this exception on creation. + auto message() const noexcept -> const char* { return message_.c_str(); } + + void SetPyError() const noexcept; + + private: + std::string thread_name_; + std::string message_; + std::string full_description_; + PyExcType python_type_; + PlatformStackTrace* stack_trace_{}; +}; + +} // namespace ballistica + +#endif // __cplusplus +#endif // BALLISTICA_CORE_EXCEPTION_H_ diff --git a/src/ballistica/core/fatal_error.cc b/src/ballistica/core/fatal_error.cc new file mode 100644 index 00000000..a4e81aee --- /dev/null +++ b/src/ballistica/core/fatal_error.cc @@ -0,0 +1,169 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/fatal_error.h" + +#include "ballistica/app/app.h" +#include "ballistica/core/logging.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { +auto FatalError::ReportFatalError(const std::string& message, + bool in_top_level_exception_handler) -> void { + // We want to report the first fatal error that happens; if further ones + // happen they are probably red herrings. + static bool ran = false; + if (ran) { + return; + } + ran = true; + + // Our main goal here varies based off whether we are an unmodified + // blessed build. If we are, our main goal is to communicate as much info + // about the error to the master server, and communicating to the user is + // a stretch goal. + // If we are unblessed or modified, the main goals are communicating the error + // to the user and exiting the app cleanly (so we don't pollute our crash + // records with results of user tinkering). + + // Try to avoid crash reports if we're not a clean blessed build. + // bool exit_cleanly = !IsUnmodifiedBlessedBuild(); + // printf("BLESSED %d\n", static_cast(IsUnmodifiedBlessedBuild())); + + // Give the platform the opportunity to completely override our handling. + if (g_platform) { + auto handled = + g_platform->ReportFatalError(message, in_top_level_exception_handler); + if (handled) { + return; + } + } + + std::string dialog_msg = message; + if (!dialog_msg.empty()) { + dialog_msg += "\n"; + } + // (No longer adding this note; individual errors to which the log is + // relevant can do to themselves). + // dialog_msg += "See BallisticaCore log for details."; + + auto starttime = time(nullptr); + + // Launch a thread and give it a chance to directly send our logs to the + // master-server. The standard mechanism probably won't get the job done + // since it relies on the game thread loop and we're likely blocking that. + // But generally we want to stay in this function and call abort() or whatnot + // from here so that our stack trace makes it into platform logs. + int result{}; + + std::string logmsg = + std::string("FATAL ERROR:") + (!message.empty() ? " " : "") + message; + + // Try to include a stack trace if we're being called from outside of a + // top-level exception handler. Otherwise the trace isn't really useful + // since we know where those are anyway. + if (!in_top_level_exception_handler) { + if (g_platform) { + PlatformStackTrace* trace{g_platform->GetStackTrace()}; + if (trace) { + std::string tracestr = trace->GetDescription(); + if (!tracestr.empty()) { + logmsg += ("\nSTACK-TRACE-BEGIN:\n" + tracestr + "\nSTACK-TRACE-END"); + } + delete trace; + } + } + } + + // Prevent the early-log insta-send mechanism from firing since we do + // basically the same thing ourself here (avoid sending the same logs twice). + g_early_log_writes = 0; + + Logging::Log(logmsg); + + std::string prefix = "FATAL-ERROR-LOG:"; + std::string suffix; + + // If we have no globals yet, include this message explicitly + // since it won't be part of the standard log. + if (g_app_globals == nullptr) { + suffix = logmsg; + } + Logging::DirectSendLogs(prefix, suffix, true, &result); + + // If we're able to show a fatal-error dialog synchronously, do so. + if (g_platform && g_platform->CanShowBlockingFatalErrorDialog()) { + DoBlockingFatalErrorDialog(dialog_msg); + } + + // Wait until the log submit has finished or a bit of time has passed.. + while (time(nullptr) - starttime < 10) { + if (result != 0) { + break; + } + Platform::SleepMS(100); + } +} + +auto FatalError::DoBlockingFatalErrorDialog(const std::string& message) + -> void { + // If we're in the main thread; just fire off the dialog directly. + // Otherwise tell the main thread to do it and wait around until it's done. + if (InMainThread()) { + g_platform->BlockingFatalErrorDialog(message); + } else { + bool started{}; + bool finished{}; + bool* startedptr{&started}; + bool* finishedptr{&finished}; + g_app->PushCall([message, startedptr, finishedptr] { + *startedptr = true; + g_platform->BlockingFatalErrorDialog(message); + *finishedptr = true; + }); + + // Wait a short amount of time for the main thread to take action. + // There's a chance that it can't (if threads are paused, if it is + // blocked on a synchronous call to another thread, etc.) so if we don't + // see something happening soon, just give up on showing a dialog. + auto starttime = Platform::GetCurrentMilliseconds(); + while (!started) { + if (Platform::GetCurrentMilliseconds() - starttime > 1000) { + return; + } + Platform::SleepMS(10); + } + while (!finished) { + Platform::SleepMS(10); + } + } +} + +auto FatalError::HandleFatalError(bool exit_cleanly, + bool in_top_level_exception_handler) -> bool { + // Give the platform the opportunity to completely override our handling. + if (g_platform) { + auto handled = g_platform->HandleFatalError(exit_cleanly, + in_top_level_exception_handler); + if (handled) { + return true; + } + } + + // If we're not being called as part of a top-level exception handler, + // bring the app down ourself. + if (!in_top_level_exception_handler) { + if (exit_cleanly) { + Log("Calling exit(1)..."); + exit(1); + } else { + Log("Calling abort()..."); + abort(); + } + } + + // Otherwise its up to who called us + // (they might let the caught exception bubble up) + return false; +} + +} // namespace ballistica diff --git a/src/ballistica/core/fatal_error.h b/src/ballistica/core/fatal_error.h new file mode 100644 index 00000000..3388287c --- /dev/null +++ b/src/ballistica/core/fatal_error.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_FATAL_ERROR_H_ +#define BALLISTICA_CORE_FATAL_ERROR_H_ + +#include + +namespace ballistica { + +class FatalError { + public: + /// Report a fatal error to the master-server/user/etc. Note that reporting + /// only happens for the first invocation of this call; additional calls + /// are no-ops. + static auto ReportFatalError(const std::string& message, + bool in_top_level_exception_handler) -> void; + + /// Handle a fatal error. This can involve calling exit(), abort(), setting + /// up an asynchronous quit, etc. Returns true if the fatal-error has been + /// handled; otherwise it is up to the caller (this should only be the case + /// when in_top_level_exception_handler is true). + /// Unlike ReportFatalError, the logic in this call can be invoked repeatedly + /// and should be prepared for that possibility in the case of recursive + /// fatal errors/etc. + static auto HandleFatalError(bool clean_exit, + bool in_top_level_exception_handler) -> bool; + + private: + static auto DoBlockingFatalErrorDialog(const std::string& message) -> void; +}; + +} // namespace ballistica +#endif // BALLISTICA_CORE_FATAL_ERROR_H_ diff --git a/src/ballistica/core/inline.cc b/src/ballistica/core/inline.cc new file mode 100644 index 00000000..a84b8e11 --- /dev/null +++ b/src/ballistica/core/inline.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#if 0 // Satisfy both CppLint and CLang.. +#include "ballistica/core/inline.h" +#endif + +namespace ballistica { + +auto InlineDebugExplicitBool(bool val) -> bool { return val; } + +} // namespace ballistica diff --git a/src/ballistica/core/inline.h b/src/ballistica/core/inline.h new file mode 100644 index 00000000..944b8587 --- /dev/null +++ b/src/ballistica/core/inline.h @@ -0,0 +1,143 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_INLINE_H_ +#define BALLISTICA_CORE_INLINE_H_ + +#ifdef __cplusplus + +#include +#include +#include + +// Bits of functionality that are useful enough to include fully as +// inlines/templates in our top level namespace. + +namespace ballistica { + +// Support functions we declare in our .cc file; not for public use. +// auto InlineDebugExplicitBool(bool val) -> bool; + +/// Return the same bool value passed in, but obfuscated enough in debug mode +/// that no 'value is always true/false', 'code will never run', type warnings +/// should appear. In release builds it should optimize away to a no-op. +inline auto explicit_bool(bool val) -> bool { +#if BA_DEBUG_BUILD + return InlineDebugExplicitBool(val); +#else + return val; +#endif +} + +/// Simply a static_cast, but in debug builds casts the results back to ensure +/// the value fits into the receiver unchanged. Handy as a sanity check when +/// stuffing a 32 bit value into a 16 bit container, etc. +template +auto static_cast_check_fit(IN_TYPE in) -> OUT_TYPE { + // Make sure we don't try to use this when casting to or from floats or + // doubles. We don't expect to always get the same value back + // on casting back in that case. + static_assert(!std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value, + "static_cast_check_fit cannot be used with floats or doubles."); +#if BA_DEBUG_BUILD + assert(static_cast(static_cast(in)) == in); +#endif + return static_cast(in); +} + +/// Like static_cast_check_fit, but runs checks even in release builds and +/// throws an Exception on failure. +template +auto static_cast_check_fit_always(IN_TYPE in) -> OUT_TYPE { + // Make sure we don't try to use this when casting to or from floats or + // doubles. We don't expect to always get the same value back + // on casting back in that case. + static_assert( + !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value + && !std::is_same::value, + "static_cast_always_checked cannot be used with floats or doubles."); + auto out = static_cast(in); + if (static_cast(out) != in) { + throw Exception("static_cast_check_fit_always failed for value " + + std::to_string(in) + "."); + } + return static_cast(in); +} + +/// Simply a static_cast, but in debug builds also runs a dynamic cast to +/// ensure the results would have been the same. Handy for keeping casts +/// lightweight when types are known while still having a sanity check. +template +auto static_cast_check_type(IN_TYPE in) -> OUT_TYPE { + auto out_static = static_cast(in); +#if BA_DEBUG_BUILD + auto out_dynamic = dynamic_cast(in); + assert(out_static == out_dynamic); +#endif + return out_static; +} + +// This call hijacks compile-type pretty-function-printing functionality +// to give human-readable strings for arbitrary types. Note that these +// will not be consistent across platforms and should only be used for +// logging/debugging. Also note that this code is dependent on very specific +// compiler output which could change at any time; to watch out for this +// it is recommended to add static_assert()s somewhere to ensure that +// output for a few given types matches expected result(s). +template +constexpr auto static_type_name_constexpr(bool debug_full = false) + -> std::string_view { + std::string_view name, prefix, suffix; +#ifdef __clang__ + name = __PRETTY_FUNCTION__; + prefix = + "std::string_view ballistica::" + "static_type_name_constexpr(bool) [T = "; + suffix = "]"; +#elif defined(__GNUC__) + name = __PRETTY_FUNCTION__; + prefix = + "constexpr std::string_view " + "ballistica::static_type_name_constexpr(bool) " + "[with T = "; + suffix = "; std::string_view = std::basic_string_view]"; +#elif defined(_MSC_VER) + name = __FUNCSIG__; + prefix = + "class std::basic_string_view > " + "__cdecl ballistica::static_type_name_constexpr<"; + suffix = ">(bool)"; +#else +#error unimplemented +#endif + if (debug_full) { + return name; + } + name.remove_prefix(prefix.size()); + name.remove_suffix(suffix.size()); + return name; +} + +/// Return a human-readable string for the template type. +template +static auto static_type_name(bool debug_full = false) -> std::string { + return std::string(static_type_name_constexpr(debug_full)); +} + +} // namespace ballistica + +#endif // __cplusplus + +#endif // BALLISTICA_CORE_INLINE_H_ diff --git a/src/ballistica/core/logging.cc b/src/ballistica/core/logging.cc new file mode 100644 index 00000000..8a3f32a1 --- /dev/null +++ b/src/ballistica/core/logging.cc @@ -0,0 +1,214 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/logging.h" + +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/ballistica.h" +#include "ballistica/game/game.h" +#include "ballistica/networking/networking.h" +#include "ballistica/networking/telnet_server.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +static void PrintCommon(const std::string& s) { + // Print to in-game console. + { + if (g_game != nullptr) { + g_game->PushConsolePrintCall(s); + } else { + if (g_platform != nullptr) { + g_platform->HandleLog( + "Warning: Log() called before game-thread setup; " + "will not appear on in-game console.\n"); + } + } + } + // Print to any telnet clients. + if (g_app_globals && g_app_globals->telnet_server) { + g_app_globals->telnet_server->PushPrint(s); + } +} + +void Logging::PrintStdout(const std::string& s, bool flush) { + fprintf(stdout, "%s", s.c_str()); + if (flush) { + fflush(stdout); + } + PrintCommon(s); +} + +void Logging::PrintStderr(const std::string& s, bool flush) { + fprintf(stderr, "%s", s.c_str()); + if (flush) { + fflush(stderr); + } + PrintCommon(s); +} + +void Logging::Log(const std::string& msg, bool to_stdout, bool to_server) { + if (to_stdout) { + PrintStdout(msg + "\n", true); + } + + // Ship to the platform logging mechanism (android-log, stderr, etc.) + // if that's available yet. + if (g_platform != nullptr) { + g_platform->HandleLog(msg); + } + + // Ship to master-server/etc. + if (to_server) { + // Route through platform-specific loggers if present. + // (things like Crashlytics crash-logging) + if (g_platform) { + Platform::DebugLog(msg); + } + + // Add to our complete log. + if (g_app_globals != nullptr) { + std::lock_guard lock(g_app_globals->log_mutex); + if (!g_app_globals->log_full) { + (g_app_globals->log) += (msg + "\n"); + if ((g_app_globals->log).size() > 10000) { + // Allow some reasonable overflow for last statement. + if ((g_app_globals->log).size() > 100000) { + // FIXME: This could potentially chop up utf-8 chars. + (g_app_globals->log).resize(100000); + } + g_app_globals->log += "\n\n"; + g_app_globals->log_full = true; + } + } + } + + // If the game is fully bootstrapped, let the Python layer handle logs. + // It will group log messages intelligently and ship them to the + // master server with various other context info included. + if (g_app_globals && g_app_globals->is_bootstrapped) { + assert(g_python != nullptr); + g_python->PushObjCall(Python::ObjID::kHandleLogCall); + } else { + // For log messages during bootstrapping we ship them immediately since + // we don't know if the Python layer is (or will be) able to. + if (g_early_log_writes > 0) { + g_early_log_writes -= 1; + std::string logprefix = "EARLY-LOG:"; + std::string logsuffix; + + // If we're an early enough error, our global log isn't even available, + // so include this specific message as a suffix instead. + if (g_app_globals == nullptr) { + logsuffix = msg; + } + DirectSendLogs(logprefix, logsuffix, false); + } + } + } +} + +auto Logging::DirectSendLogs(const std::string& prefix, + const std::string& suffix, bool instant, + int* result) -> void { + // Use a rough mechanism to restrict log uploads to 1 send per second. + static time_t last_non_instant_send_time{-1}; + if (!instant) { + auto curtime = Platform::GetCurrentSeconds(); + if (curtime == last_non_instant_send_time) { + return; + } + last_non_instant_send_time = curtime; + } + + std::thread t([prefix, suffix, instant, result]() { + // For non-instant sends, sleep for 2 seconds before sending logs; + // this should capture the just-added log as well as any more that + // got added in the subsequent second when we were not launching new + // send threads. + if (!instant) { + Platform::SleepMS(2000); + } + std::string log; + + // Send our blessing hash only after we've calculated it; don't use our + // internal one. This means that we'll get false-negatives on whether + // direct-sent logs are blessed, but I think that's better than false + // positives. + std::string calced_blessing_hash; + if (g_app_globals) { + std::lock_guard lock(g_app_globals->log_mutex); + log = g_app_globals->log; + calced_blessing_hash = g_app_globals->calced_blessing_hash; + } else { + log = "(g_app_globals not yet inited; no global log available)"; + } + if (!prefix.empty()) { + log = prefix + "\n" + log; + } + if (!suffix.empty()) { + log = log + "\n" + suffix; + } + + // Also send our blessing-calculation state; we may want to distinguish + // between blessing not being calced yet and being confirmed as un-blessed. + // FIXME: should probably do this in python layer log submits too. + std::string bless_calc_state; + if (kBlessingHash == nullptr) { + bless_calc_state = "nointhash"; + } else if (g_app_globals == nullptr) { + bless_calc_state = "noglobs"; + } else if (g_app_globals->calced_blessing_hash.empty()) { + // Mention we're calculating, but also mention if it is likely that + // the user is mucking with stuff. + if (g_app_globals->user_ran_commands + || g_platform->using_custom_app_python_dir()) { + bless_calc_state = "calcing_likely_modded"; + } else { + bless_calc_state = "calcing_not_modded"; + } + } else { + bless_calc_state = "done"; + } + + std::string path{"/bsLog"}; + std::map params{ + {"log", log}, + {"time", "-1"}, + {"userAgentString", g_app_globals ? g_app_globals->user_agent_string + : "(no g_app_globals)"}, + {"newsShow", calced_blessing_hash.c_str()}, + {"bcs", bless_calc_state.c_str()}, + {"build", std::to_string(kAppBuildNumber)}}; + try { + Networking::MasterServerPost(path, params); + if (result) { + *result = 1; // SUCCESS! + } + } catch (const std::exception&) { + // Try our fallback master-server address if that didn't work. + try { + params["log"] = prefix + "(FALLBACK-ADDR):\n" + log; + Networking::MasterServerPost(path, params, true); + if (result) { + *result = 1; // SUCCESS! + } + } catch (const std::exception& exc) { + // Well, we tried; make a note to platform log if available + // that we failed. + if (g_platform != nullptr) { + g_platform->HandleLog(std::string("Early log-to-server failed: ") + + exc.what()); + } + if (result) { + *result = -1; // FAIL!! + } + } + } + }); + t.detach(); +} + +} // namespace ballistica diff --git a/src/ballistica/core/logging.h b/src/ballistica/core/logging.h new file mode 100644 index 00000000..bd2ab768 --- /dev/null +++ b/src/ballistica/core/logging.h @@ -0,0 +1,35 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_LOGGING_H_ +#define BALLISTICA_CORE_LOGGING_H_ + +#include + +namespace ballistica { + +class Logging { + public: + /// Print a string directly to stdout as well as the in-game console + /// and any connected telnet consoles. + static auto PrintStdout(const std::string& s, bool flush = false) -> void; + + /// Print a string directly to stderr as well as the in-game console + /// and any connected telnet consoles. + static auto PrintStderr(const std::string& s, bool flush = false) -> void; + + /// Write a string to the debug log. + /// This will go to stdout, windows debug log, android log, etc. depending + /// on the platform. + static auto Log(const std::string& msg, bool to_stdout = true, + bool to_server = true) -> void; + + /// Ship logs to the master-server in a bg thread. If result is passed, + /// it will be set to 1 on success and -1 on error. + static auto DirectSendLogs(const std::string& prefix, + const std::string& suffix, bool instant, + int* result = nullptr) -> void; +}; + +} // namespace ballistica + +#endif // BALLISTICA_CORE_LOGGING_H_ diff --git a/src/ballistica/core/macros.cc b/src/ballistica/core/macros.cc new file mode 100644 index 00000000..73aee581 --- /dev/null +++ b/src/ballistica/core/macros.cc @@ -0,0 +1,106 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/macros.h" + +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +// Snippets of compiled functionality used by our evil macros. + +namespace ballistica { + +void MacroFunctionTimerEnd(millisecs_t starttime, millisecs_t time, + const char* funcname) { + // Currently disabling this for test builds; not really useful for + // the general public. + if (g_buildconfig.test_build()) { + return; + } + millisecs_t endtime = g_platform->GetTicks(); + if (endtime - starttime > time) { + Log("Warning: " + std::to_string(endtime - starttime) + + " milliseconds spent in " + funcname); + } +} + +void MacroFunctionTimerEndThread(millisecs_t starttime, millisecs_t time, + const char* funcname) { + // Currently disabling this for test builds; not really useful for + // the general public. + if (g_buildconfig.test_build()) { + return; + } + millisecs_t endtime = g_platform->GetTicks(); + if (endtime - starttime > time) { + Log("Warning: " + std::to_string(endtime - starttime) + + " milliseconds spent by " + ballistica::GetCurrentThreadName() + + " thread in " + funcname); + } +} + +void MacroFunctionTimerEndEx(millisecs_t starttime, millisecs_t time, + const char* funcname, const std::string& what) { + // Currently disabling this for test builds; not really useful for + // the general public. + if (g_buildconfig.test_build()) { + return; + } + millisecs_t endtime = g_platform->GetTicks(); + if (endtime - starttime > time) { + Log("Warning: " + std::to_string(endtime - starttime) + + " milliseconds spent in " + funcname + " for " + what); + } +} + +void MacroFunctionTimerEndThreadEx(millisecs_t starttime, millisecs_t time, + const char* funcname, + const std::string& what) { + // Currently disabling this for test builds; not really useful for + // the general public. + if (g_buildconfig.test_build()) { + return; + } + millisecs_t endtime = g_platform->GetTicks(); + if (endtime - starttime > time) { + Log("Warning: " + std::to_string(endtime - starttime) + + " milliseconds spent by " + ballistica::GetCurrentThreadName() + + " thread in " + funcname + " for " + what); + } +} + +void MacroTimeCheckEnd(millisecs_t starttime, millisecs_t time, + const char* name, const char* file, int line) { + // Currently disabling this for test builds; not really useful for + // the general public. + if (g_buildconfig.test_build()) { + return; + } + millisecs_t e = g_platform->GetTicks(); + if (e - starttime > time) { + Log(std::string("Warning: ") + name + " took " + + std::to_string(e - starttime) + " milliseconds; " + file + " line " + + std::to_string(line)); + } +} + +void MacroLogErrorTrace(const std::string& msg, const char* fname, int line) { + char buffer[2048]; + snprintf(buffer, sizeof(buffer), "%s:%d:", fname, line); + buffer[sizeof(buffer) - 1] = 0; + Python::PrintStackTrace(); + Log(std::string(buffer) + " error: " + msg); +} + +void MacroLogError(const std::string& msg, const char* fname, int line) { + char e_buffer[2048]; + snprintf(e_buffer, sizeof(e_buffer), "%s:%d:", fname, line); + e_buffer[sizeof(e_buffer) - 1] = 0; + ballistica::Log(std::string(e_buffer) + " error: " + msg); +} + +void MacroLogPythonTrace(const std::string& msg) { + Python::PrintStackTrace(); + Log(msg); +} + +} // namespace ballistica diff --git a/src/ballistica/core/macros.h b/src/ballistica/core/macros.h new file mode 100644 index 00000000..65b81043 --- /dev/null +++ b/src/ballistica/core/macros.h @@ -0,0 +1,166 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_MACROS_H_ +#define BALLISTICA_CORE_MACROS_H_ + +#ifdef __cplusplus +#include +#include +#endif + +#include "ballistica/core/types.h" + +// Various utility macros and related support calls. +// Trying to contain the evil in this one place. + +// Trailing-semicolon note: +// Some macros contain a ((void*) at the end. This is so the macro can be +// followed by a semicolon without triggering an 'empty statement' warning. +// I find standalone function-style macro invocations without semicolons +// tends to confuse code formatters. + +#define BA_STRINGIFY(x) #x + +#define BA_BUILD_COMMAND_FILENAME \ + "" +#define BA_BCFN BA_BUILD_COMMAND_FILENAME + +#if BA_OSTYPE_WINDOWS +#define BA_DIRSLASH "\\" +#else +#define BA_DIRSLASH "/" +#endif + +#if BA_DEBUG_BUILD +#define BA_IFDEBUG(a) a +#else +#define BA_IFDEBUG(a) ((void)0) +#endif + +// Useful for finding hitches. +// Call begin, followed at some point by any of the end versions. +// FIXME: Turn these into C++ classes. +#if BA_DEBUG_BUILD +#define BA_DEBUG_FUNCTION_TIMER_BEGIN() \ + millisecs_t _dfts = g_platform->GetTicks() +#define BA_DEBUG_FUNCTION_TIMER_END(time) \ + ballistica::MacroFunctionTimerEnd(_dfts, time, __PRETTY_FUNCTION__) +#define BA_DEBUG_FUNCTION_TIMER_END_THREAD(time) \ + ballistica::MacroFunctionTimerEndThread(_dfts, time, __PRETTY_FUNCTION__) +#define BA_DEBUG_FUNCTION_TIMER_END_EX(time, what) \ + MacroFunctionTimerEndEx(_dfts, time, __PRETTY_FUNCTION__, what) +#define BA_DEBUG_FUNCTION_TIMER_END_THREAD_EX(time, what) \ + ballistica::MacroFunctionTimerEndThreadEx(_dfts, time, __PRETTY_FUNCTION__, \ + what) +#define BA_DEBUG_TIME_CHECK_BEGIN(name) \ + millisecs_t name##_ts = g_platform->GetTicks() +#define BA_DEBUG_TIME_CHECK_END(name, time) \ + ballistica::MacroTimeCheckEnd(name##_ts, time, #name, __FILE__, __LINE__) +#else +#define BA_DEBUG_FUNCTION_TIMER_BEGIN() ((void)0) +#define BA_DEBUG_FUNCTION_TIMER_END(time) ((void)0) +#define BA_DEBUG_FUNCTION_TIMER_END_THREAD(time) ((void)0) +#define BA_DEBUG_FUNCTION_TIMER_END_EX(time, what) ((void)0) +#define BA_DEBUG_FUNCTION_TIMER_END_THREAD_EX(time, what) ((void)0) +#define BA_DEBUG_TIME_CHECK_BEGIN(name) ((void)0) +#define BA_DEBUG_TIME_CHECK_END(name, time) ((void)0) +#endif + +// Disallow copying for a class. +#define BA_DISALLOW_CLASS_COPIES(type) \ + type(const type& foo) = delete; \ + type& operator=(const type& src) = delete; /* NOLINT (macro parens) */ + +// Call this for errors which are non-fatal but should be noted so they can be +// fixed. +#define BA_LOG_ERROR_TRACE(msg) \ + ballistica::MacroLogErrorTrace(msg, __FILE__, __LINE__) + +#define BA_LOG_ERROR_TRACE_ONCE(msg) \ + { \ + static bool did_log_error_trace_here = false; \ + if (!did_log_error_trace_here) { \ + ballistica::MacroLogErrorTrace(msg, __FILE__, __LINE__); \ + did_log_error_trace_here = true; \ + } \ + } \ + ((void)0) // (see 'Trailing-semicolon note' at top) + +#define BA_LOG_ONCE(msg) \ + { \ + static bool did_log_here = false; \ + if (!did_log_here) { \ + ballistica::Log(msg); \ + did_log_here = true; \ + } \ + } \ + ((void)0) // (see 'Trailing-semicolon note' at top) + +#define BA_LOG_PYTHON_TRACE(msg) ballistica::MacroLogPythonTrace(msg) + +#define BA_LOG_PYTHON_TRACE_ONCE(msg) \ + { \ + static bool did_log_python_trace_here = false; \ + if (!did_log_python_trace_here) { \ + ballistica::MacroLogPythonTrace(msg); \ + did_log_python_trace_here = true; \ + } \ + } \ + ((void)0) // (see 'Trailing-semicolon note' at top) + +/// Test a condition and throw an exception if it fails (on both debug and +/// release builds) +#define BA_PRECONDITION(b) \ + { \ + if (!(b)) { \ + throw ballistica::Exception("Precondition failed: " #b); \ + } \ + } \ + ((void)0) // (see 'Trailing-semicolon note' at top) + +/// Test a condition and simply print a log message if it fails (on both debug +/// and release builds) +#define BA_PRECONDITION_LOG(b) \ + { \ + if (!(b)) { \ + Log("Precondition failed: " #b); \ + } \ + } \ + ((void)0) // (see 'Trailing-semicolon note' at top) + +/// Test a condition and abort the program if it fails (on both debug +/// and release builds) +#define BA_PRECONDITION_FATAL(b) \ + { \ + if (!(b)) { \ + FatalError("Precondition failed: " #b); \ + } \ + } \ + ((void)0) // (see 'Trailing-semicolon note' at top) + +#ifdef __cplusplus + +namespace ballistica { + +// Support functions used by some of our macros; not intended to be used +// directly. +void MacroFunctionTimerEnd(millisecs_t starttime, millisecs_t time, + const char* funcname); +void MacroFunctionTimerEndThread(millisecs_t starttime, millisecs_t time, + const char* funcname); +void MacroFunctionTimerEndEx(millisecs_t starttime, millisecs_t time, + const char* funcname, const std::string& what); +void MacroFunctionTimerEndThreadEx(millisecs_t starttime, millisecs_t time, + const char* funcname, + const std::string& what); +void MacroTimeCheckEnd(millisecs_t starttime, millisecs_t time, + const char* name, const char* file, int line); +void MacroLogErrorTrace(const std::string& msg, const char* fname, int line); +void MacroLogError(const std::string& msg, const char* fname, int line); +void MacroLogPythonTrace(const std::string& msg); + +} // namespace ballistica + +#endif // __cplusplus + +#endif // BALLISTICA_CORE_MACROS_H_ diff --git a/src/ballistica/core/module.cc b/src/ballistica/core/module.cc new file mode 100644 index 00000000..626f8c6f --- /dev/null +++ b/src/ballistica/core/module.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/module.h" + +#include + +#include "ballistica/core/thread.h" + +namespace ballistica { + +void Module::PushLocalRunnable(Runnable* runnable) { + assert(std::this_thread::get_id() == thread()->thread_id()); + runnables_.push_back(runnable); +} + +void Module::PushRunnable(Runnable* runnable) { + // If we're being called from the module's thread, just drop it in the list. + // otherwise send it as a message to the other thread. + if (std::this_thread::get_id() == thread()->thread_id()) { + PushLocalRunnable(runnable); + } else { + thread_->PushModuleRunnable(runnable, id_); + } +} + +Module::Module(std::string name_in, Thread* thread_in) + : thread_(thread_in), name_(std::move(name_in)) { + id_ = thread_->RegisterModule(name_, this); +} + +Module::~Module() = default; + +auto Module::NewThreadTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> Timer* { + return thread_->NewTimer(length, repeat, runnable); +} + +void Module::RunPendingRunnables() { + // Pull all runnables off the list first (its possible for one of these + // runnables to add more) and then process them. + assert(std::this_thread::get_id() == thread()->thread_id()); + std::list runnables; + runnables_.swap(runnables); + for (Runnable* i : runnables) { + i->Run(); + delete i; + } +} + +} // namespace ballistica diff --git a/src/ballistica/core/module.h b/src/ballistica/core/module.h new file mode 100644 index 00000000..4bcccf1c --- /dev/null +++ b/src/ballistica/core/module.h @@ -0,0 +1,70 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_MODULE_H_ +#define BALLISTICA_CORE_MODULE_H_ + +#include +#include +#include +#include + +#include "ballistica/generic/lambda_runnable.h" +#include "ballistica/generic/runnable.h" + +namespace ballistica { + +/// A logical entity that can be added to a thread and make use of its +/// event loop. +class Module { + public: + /// Add a runnable to this module's queue. + /// Pass a Runnable that has been allocated with new(). + /// There must be no existing strong refs to it. + /// It will be owned and disposed of by the module from this point. + void PushRunnable(Runnable* runnable); + + /// Convenience function to push a lambda as a runnable. + template + void PushCall(const F& lambda) { + PushRunnable(NewLambdaRunnableRaw(lambda)); + } + + /// Return the thread this module is running on. + auto thread() const -> Thread* { return thread_; } + + virtual ~Module(); + + /// Push a runnable from the same thread as the module. + void PushLocalRunnable(Runnable* runnable); + + /// Called for each module when its thread is about to be suspended + /// (on platforms such as mobile). + virtual void HandleThreadPause() {} + + /// Called for each module when its thread is about to be resumed + /// (on platforms such as mobile). + virtual void HandleThreadResume() {} + + /// Whether this module has pending runnables. + auto has_pending_runnables() const -> bool { return !runnables_.empty(); } + + /// Used by the module's owner thread to let it do its thing. + void RunPendingRunnables(); + + auto name() const -> const std::string& { return name_; } + + protected: + Module(std::string name, Thread* thread); + auto NewThreadTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> Timer*; + + private: + std::string name_; + int id_{}; + std::list runnables_; + Thread* thread_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_CORE_MODULE_H_ diff --git a/src/ballistica/core/object.cc b/src/ballistica/core/object.cc new file mode 100644 index 00000000..ff6e63e6 --- /dev/null +++ b/src/ballistica/core/object.cc @@ -0,0 +1,233 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/object.h" + +#include +#include +#include +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/generic/utils.h" +#include "ballistica/platform/min_sdl.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +void Object::PrintObjects() { +#if BA_DEBUG_BUILD + std::string s; + { + std::lock_guard lock(g_app_globals->object_list_mutex); + s = std::to_string(g_app_globals->object_count) + " Objects at time " + + std::to_string(GetRealTime()) + ";"; + + if (explicit_bool(true)) { + std::map obj_map; + + // Tally up counts for all types. + int count = 0; + for (Object* o = g_app_globals->object_list_first; o != nullptr; + o = o->object_next_) { + count++; + std::string obj_name = o->GetObjectTypeName(); + auto i = obj_map.find(obj_name); + if (i == obj_map.end()) { + obj_map[obj_name] = 1; + } else { + // Getting complaints that 'second' is unused, but we sort and print + // using this value like 10 lines down. Hmmm. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "UnusedValue" + i->second++; +#pragma clang diagnostic pop + } + } + + // Now sort them by count and print. + std::vector > sorted; + sorted.reserve(obj_map.size()); + for (auto&& i : obj_map) { + sorted.emplace_back(i.second, i.first); + } + std::sort(sorted.begin(), sorted.end()); + for (auto&& i : sorted) { + s += "\n " + std::to_string(i.first) + ": " + i.second; + } + assert(count == g_app_globals->object_count); + } + } + Log(s); +#else + Log("PrintObjects() only functions in debug builds."); +#endif // BA_DEBUG_BUILD +} + +Object::Object() { +#if BA_DEBUG_BUILD + // Mark when we were born. + object_birth_time_ = GetRealTime(); + + // Add ourself to the global object list. + std::lock_guard lock(g_app_globals->object_list_mutex); + object_prev_ = nullptr; + object_next_ = g_app_globals->object_list_first; + g_app_globals->object_list_first = this; + if (object_next_) { + object_next_->object_prev_ = this; + } + g_app_globals->object_count++; +#endif // BA_DEBUG_BUILD +} + +Object::~Object() { +#if BA_DEBUG_BUILD + // Pull ourself from the global obj list. + std::lock_guard lock(g_app_globals->object_list_mutex); + if (object_next_) { + object_next_->object_prev_ = object_prev_; + } + if (object_prev_) { + object_prev_->object_next_ = object_next_; + } else { + g_app_globals->object_list_first = object_next_; + } + g_app_globals->object_count--; + + // More sanity checks. + if (object_strong_ref_count_ != 0) { + // Avoiding Log for these low level errors; can lead to deadlock. + printf( + "Warning: Object is dying with non-zero ref-count; this is bad. " + "(this " + "might mean the object raised an exception in its constructor after " + "being strong-referenced first).\n"); + } + +#endif // BA_DEBUG_BUILD + + // Invalidate all our weak refs. + // We could call Release() on each but we'd have to deactivate the + // thread-check since virtual functions won't work right in a destructor. + // Also we can take a few shortcuts here since we know we're deleting the + // entire list, not just one object. + while (object_weak_refs_) { + auto tmp = object_weak_refs_; + object_weak_refs_ = tmp->next_; + tmp->prev_ = nullptr; + tmp->next_ = nullptr; + tmp->obj_ = nullptr; + } +} + +auto Object::GetObjectTypeName() const -> std::string { + // Default implementation just returns type name. + return g_platform->DemangleCXXSymbol(typeid(*this).name()); +} + +auto Object::GetObjectDescription() const -> std::string { + return "<" + GetObjectTypeName() + " object at " + Utils::PtrToString(this) + + ">"; +} + +auto Object::GetThreadOwnership() const -> Object::ThreadOwnership { +#if BA_DEBUG_BUILD + return thread_ownership_; +#else + // Not used in release build so doesn't matter. + return ThreadOwnership::kAny; +#endif +} + +auto Object::GetDefaultOwnerThread() const -> ThreadIdentifier { + return ThreadIdentifier::kGame; +} + +#if BA_DEBUG_BUILD + +static auto GetCurrentThreadIdentifier() -> ThreadIdentifier { + if (InMainThread()) { + return ThreadIdentifier::kMain; + } else if (InGameThread()) { + return ThreadIdentifier::kGame; + } else if (InAudioThread()) { + return ThreadIdentifier::kAudio; + } else if (InNetworkWriteThread()) { + return ThreadIdentifier::kNetworkWrite; + } else if (InMediaThread()) { + return ThreadIdentifier::kMedia; + } else if (InBGDynamicsThread()) { + return ThreadIdentifier::kBGDynamics; + } else { + throw Exception(std::string("unrecognized thread: ") + + GetCurrentThreadName()); + } +} + +void Object::ObjectThreadCheck() { + if (!thread_checks_enabled_) { + return; + } + + ThreadOwnership thread_ownership = GetThreadOwnership(); + if (thread_ownership == ThreadOwnership::kAny) { + return; + } + + // If we're set to use the next-referencing thread + // and haven't set that yet, do so. + if (thread_ownership == ThreadOwnership::kNextReferencing + && owner_thread_ == ThreadIdentifier::kInvalid) { + owner_thread_ = GetCurrentThreadIdentifier(); + } + + ThreadIdentifier t; + if (thread_ownership == ThreadOwnership::kClassDefault) { + t = GetDefaultOwnerThread(); + } else { + t = owner_thread_; + } +#define DO_FAIL(THREADNAME) \ + throw Exception("ObjectThreadCheck failed for " + GetObjectDescription() \ + + "; expected " THREADNAME " thread; got " \ + + GetCurrentThreadName()) + switch (t) { + case ThreadIdentifier::kMain: + if (!InMainThread()) { + DO_FAIL("Main"); + } + break; + case ThreadIdentifier::kGame: + if (!InGameThread()) { + DO_FAIL("Game"); + } + break; + case ThreadIdentifier::kAudio: + if (!InAudioThread()) { + DO_FAIL("Audio"); + } + break; + case ThreadIdentifier::kNetworkWrite: + if (!InNetworkWriteThread()) { + DO_FAIL("NetworkWrite"); + } + break; + case ThreadIdentifier::kMedia: + if (!InMediaThread()) { + DO_FAIL("Media"); + } + break; + case ThreadIdentifier::kBGDynamics: + if (!InBGDynamicsThread()) { + DO_FAIL("BGDynamics"); + } + break; + default: + throw Exception(); + } +#undef DO_FAIL +} +#endif // BA_DEBUG_BUILD + +} // namespace ballistica diff --git a/src/ballistica/core/object.h b/src/ballistica/core/object.h new file mode 100644 index 00000000..7e0f8b7b --- /dev/null +++ b/src/ballistica/core/object.h @@ -0,0 +1,671 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_OBJECT_H_ +#define BALLISTICA_CORE_OBJECT_H_ + +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +/// Objects supporting strong and weak referencing and thread enforcement. +/// A rule or two for for Objects: +/// Don't throw exceptions out of object destructors; +/// This will break references to that object and lead to crashes if/when they +/// are used. +class Object { + public: + Object(); + virtual ~Object(); + + /// Prints a tally of object types and counts (debug build only). + static void PrintObjects(); + + // Object classes can provide descriptive names for themselves; + // these are used for debugging and other purposes. + // The default is to use the C++ symbol name, demangling it when possible. + // IMPORTANT: Do not rely on this being consistent across builds/platforms. + virtual auto GetObjectTypeName() const -> std::string; + + // Provide a brief description of this particular object; by default returns + // type-name plus address. + virtual auto GetObjectDescription() const -> std::string; + + // This is called when adding or removing a reference to an Object; + // it can perform sanity-tests to make sure references are not being + // added at incorrect times or from incorrect threads. + // The default implementation uses the per-object + // ThreadOwnership/ThreadIdentifier values accessible below. NOTE: this + // check runs only in the debug build so don't add any logical side-effects! +#if BA_DEBUG_BUILD + virtual void ObjectThreadCheck(); +#endif + + enum class ThreadOwnership { + kClassDefault, // Uses class' GetDefaultOwnerThread() call. + kNextReferencing, // Uses whichever thread next acquires/accesses a ref. + kCustom, // Always use a specific thread. + kAny // Any thread is fine. + }; + + /// Called by the default ObjectThreadCheck() to determine ThreadOwnership + /// for an Object. The default uses the object's individual value + /// (which defaults to ThreadOwnership::kClassDefault and can be set via + /// SetThreadOwnership()) + virtual auto GetThreadOwnership() const -> ThreadOwnership; + + /// Return the exact thread to check for with ThreadOwnership::kClassDefault + /// (in the default ObjectThreadCheck implementation at least). + /// Default returns ThreadIdentifier::kGame + virtual auto GetDefaultOwnerThread() const -> ThreadIdentifier; + + /// Set thread ownership values for an individual object. + /// Note that these values may be ignored if ObjectThreadCheck() is + /// overridden, and thread_identifier is only relevant when ownership is + /// ThreadOwnership::kCustom. + /// UPDATE: turning off per-object controls; gonna see if we can get by + /// with just set_thread_checks_enabled() for temp special cases... + void SetThreadOwnership( + ThreadOwnership ownership, + ThreadIdentifier thread_identifier = ThreadIdentifier::kGame) { +#if BA_DEBUG_BUILD + thread_ownership_ = ownership; + if (thread_ownership_ == ThreadOwnership::kNextReferencing) { + owner_thread_ = ThreadIdentifier::kInvalid; + } else { + owner_thread_ = thread_identifier; + } +#endif + } + + // Return true if the object is ref-counted and has at least 1 strong ref. + // This is generally a good thing for calls accepting object ptrs to check. + // Note that this can return false positives in release builds so should + // mainly be used as a debug sanity check (erroring if false) + auto is_valid_refcounted_object() const -> bool { +#if BA_DEBUG_BUILD + if (object_is_dead_) { + return false; + } +#endif + return (object_strong_ref_count_ > 0); + } + + auto object_strong_ref_count() const -> int { + return object_strong_ref_count_; + } + template + class Ref; + template + class WeakRef; + + class WeakRefBase { + public: + WeakRefBase() = default; + ~WeakRefBase() { Release(); } + + void Release() { + if (obj_) { +#if BA_DEBUG_BUILD + obj_->ObjectThreadCheck(); +#endif + if (next_) { + next_->prev_ = prev_; + } + if (prev_) { + prev_->next_ = next_; + } else { + obj_->object_weak_refs_ = next_; + } + obj_ = nullptr; + next_ = prev_ = nullptr; + } else { + assert(next_ == nullptr && prev_ == nullptr); + } + } + + private: + Object* obj_ = nullptr; + WeakRefBase* prev_ = nullptr; + WeakRefBase* next_ = nullptr; + friend class Object; + }; // WeakRefBase + + /// Weak-reference to an instance of a specific Object subclass. + template + class WeakRef : public WeakRefBase { + public: + auto exists() const -> bool { return (obj_ != nullptr); } + + void Clear() { Release(); } + + // Return a pointer or nullptr. + auto get() const -> T* { + // Yes, reinterpret_cast is evil, but we make sure + // we only operate on cases where this is valid + // (see Acquire()). + return reinterpret_cast(obj_); + } + + // These operators throw exceptions if the object is dead. + auto operator*() const -> T& { + if (!obj_) { + throw Exception("Invalid dereference of " + static_type_name()); + } + + // Yes, reinterpret_cast is evil, but we make sure + // we only operate on cases where this is valid + // (see Acquire()). + return *reinterpret_cast(obj_); + } + auto operator->() const -> T* { + if (!obj_) { + throw Exception("Invalid dereference of " + static_type_name()); + } + + // Yes, reinterpret_cast is evil, but we make sure + // we only operate on cases where this is valid + // (see Acquire()). + return reinterpret_cast(obj_); + } + + // Assign/compare with any compatible pointer. + template + auto operator=(U* ptr) -> WeakRef& { + Release(); + + // Go through our template type instead of assigning directly + // to our Object* so we catch invalid assigns at compile-time. + T* tmp = ptr; + if (tmp) Acquire(tmp); + + // More debug sanity checks. + assert(reinterpret_cast(obj_) == ptr); + assert(static_cast(obj_) == ptr); + assert(dynamic_cast(obj_) == ptr); + return *this; + } + template + auto operator==(U* ptr) -> bool { + return (get() == ptr); + } + template + auto operator!=(U* ptr) -> bool { + return (get() != ptr); + } + + // Assign/compare with same type ref (apparently the template below doesn't + // cover this case?). + auto operator=(const WeakRef& ref) -> WeakRef& { + *this = ref.get(); + return *this; + } + auto operator==(const WeakRef& ref) -> bool { + return (get() == ref.get()); + } + auto operator!=(const WeakRef& ref) -> bool { + return (get() != ref.get()); + } + + // Assign/compare with any compatible strong-ref. + template + auto operator=(const Ref& ref) -> WeakRef& { + *this = ref.get(); + return *this; + } + + template + auto operator==(const Ref& ref) -> bool { + return (get() == ref.get()); + } + + template + auto operator!=(const Ref& ref) -> bool { + return (get() != ref.get()); + } + + // Assign/compare with any compatible weak-ref. + template + auto operator=(const WeakRef& ref) -> WeakRef& { + *this = ref.get(); + return *this; + } + + template + auto operator==(const WeakRef& ref) -> bool { + return (get() == ref.get()); + } + + template + auto operator!=(const WeakRef& ref) -> bool { + return (get() != ref.get()); + } + + // Various constructors: + + // Empty. + WeakRef() = default; + + // From our type pointer. + explicit WeakRef(T* obj) { *this = obj; } + + // Copy constructor (only non-explicit one). + WeakRef(const WeakRef& ref) { *this = ref.get(); } + + // From a compatible pointer. + template + explicit WeakRef(U* ptr) { + *this = ptr; + } + + // From a compatible strong ref. + template + explicit WeakRef(const Ref& ref) { + *this = ref; + } + + // From a compatible weak ref. + template + explicit WeakRef(const WeakRef& ref) { + *this = ref; + } + + private: + void Acquire(T* obj) { + if (obj == nullptr) { + throw Exception("Acquiring invalid ptr of " + static_type_name()); + } +#if BA_DEBUG_BUILD + + // Seems like it'd be a good idea to prevent creation of weak-refs to + // objects in their destructors, but it turns out we're currently + // doing this (session points contexts at itself as it dies, etc.) + // Perhaps later can untangle this and change the behavior. + obj->ObjectThreadCheck(); + assert(obj_ == nullptr && next_ == nullptr && prev_ == nullptr); +#endif + if (obj->object_weak_refs_) { + obj->object_weak_refs_->prev_ = this; + next_ = obj->object_weak_refs_; + } + obj->object_weak_refs_ = this; + + // Sanity checking: We make the assumption that static-casting our pointer + // to/from Object gives the same results as reinterpret-casting it; let's + // be certain that's the case. In some cases involving multiple + // inheritance this might not be true, but we avoid those cases in our + // object hierarchy. (the one type of multiple inheritance we allow is + // pure virtual 'interfaces' which should not affect pointer offsets) + assert(static_cast(obj) == reinterpret_cast(obj)); + + // More random sanity checking. + assert(dynamic_cast(reinterpret_cast(obj)) == obj); + obj_ = obj; + } + }; // WeakRef + + // Strong-ref. + template + class Ref { + public: + ~Ref() { Release(); } + auto get() const -> T* { return obj_; } + + // These operators throw an Exception if the object is dead. + auto operator*() const -> T& { + if (!obj_) { + throw Exception("Invalid dereference of " + static_type_name()); + } + return *obj_; + } + auto operator->() const -> T* { + if (!obj_) { + throw Exception("Invalid dereference of " + static_type_name()); + } + return obj_; + } + auto exists() const -> bool { return (obj_ != nullptr); } + void Clear() { Release(); } + + // Assign/compare with any compatible pointer. + template + auto operator=(U* ptr) -> Ref& { + Release(); + if (ptr) { + Acquire(ptr); + } + return *this; + } + template + auto operator==(U* ptr) -> bool { + return (get() == ptr); + } + template + auto operator!=(U* ptr) -> bool { + return (get() != ptr); + } + + auto operator==(const Ref& ref) -> bool { return (get() == ref.get()); } + auto operator!=(const Ref& ref) -> bool { return (get() != ref.get()); } + + // Assign/compare with same type ref (apparently the generic template below + // doesn't cover that case?..) + // DANGER: Seems to still compile if we comment this out, but crashes. + // Should get to the bottom of that. + auto operator=(const Ref& ref) -> Ref& { + assert(this != &ref); // Shouldn't be self-assigning. + *this = ref.get(); + return *this; + } + + // Assign/compare with any compatible strong-ref. + template + auto operator=(const Ref& ref) -> Ref& { + *this = ref.get(); + return *this; + } + + template + auto operator==(const Ref& ref) -> bool { + return (get() == ref.get()); + } + + template + auto operator!=(const Ref& ref) -> bool { + return (get() != ref.get()); + } + + // Assign/compare from any compatible weak-ref. + template + auto operator=(const WeakRef& ref) -> Ref& { + *this = ref.get(); + return *this; + } + + template + auto operator==(const WeakRef& ref) -> bool { + return (get() == ref.get()); + } + + template + auto operator!=(const WeakRef& ref) -> bool { + return (get() != ref.get()); + } + + // Various constructors: + + // Empty. + Ref() = default; + + // From our type pointer. + explicit Ref(T* obj) { *this = obj; } + + // Copy constructor (only non-explicit one). + Ref(const Ref& ref) { *this = ref.get(); } + + // From a compatible pointer. + template + explicit Ref(U* ptr) { + *this = ptr; + } + + // From a compatible strong ref. + template + explicit Ref(const Ref& ref) { + *this = ref; + } + + // From a compatible weak ref. + template + explicit Ref(const WeakRef& ref) { + *this = ref; + } + + private: + void Acquire(T* obj) { + if (obj == nullptr) { + throw Exception("Acquiring invalid ptr of " + static_type_name()); + } + +#if BA_DEBUG_BUILD + obj->ObjectThreadCheck(); + + // Obvs shouldn't be referencing dead stuff. + assert(!obj->object_is_dead_); + + // Complain if creating an initial strong-ref to something + // not marked as ref-counted. + // (should make this an error once we know these are out of the system) + if (!obj->object_has_strong_ref_ + && !obj->object_creating_strong_reffed_) { + // Log only to system log for these low-level errors; + // console or server can cause deadlock due to recursive + // ref-list locks. + printf( + "Incorrectly creating initial strong-ref to %s; use " + "New() or MakeRefCounted()\n", + obj->GetObjectDescription().c_str()); + } + obj->object_has_strong_ref_ = true; +#endif // BA_DEBUG_BUILD + + obj->object_strong_ref_count_++; + obj_ = obj; + } + void Release() { + if (obj_ != nullptr) { +#if BA_DEBUG_BUILD + obj_->ObjectThreadCheck(); +#endif + assert(obj_->object_strong_ref_count_ > 0); + obj_->object_strong_ref_count_--; + T* tmp = obj_; + + // Invalidate ref *before* delete to avoid potential double-release. + obj_ = nullptr; + if (tmp->object_strong_ref_count_ == 0) { +#if BA_DEBUG_BUILD + tmp->object_is_dead_ = true; +#endif + delete tmp; + } + } + } + T* obj_ = nullptr; + }; + + /// Object::New(): The preferred way to create ref-counted Objects. + /// Allocates a new Object with the provided args and returns a strong + /// reference to it. + /// Generally you pass a single type to be instantiated and returned, + /// but you can optionally specify the two separately. + /// (for instance you may want to create a Button but return + /// a Ref to a Widget) + template + [[nodiscard]] static auto New(ARGS&&... args) -> Object::Ref { + auto* ptr = new TALLOC(std::forward(args)...); +#if BA_DEBUG_BUILD + if (ptr->object_creating_strong_reffed_) { + // Avoiding Log for these low level errors; can lead to deadlock. + printf("Object already set up as reffed in New: %s\n", + ptr->GetObjectDescription().c_str()); + } + if (ptr->object_strong_ref_count_ > 0) { + // TODO(ericf): make this an error once its cleared out + printf("Obj strong-ref in constructor: %s\n", + ptr->GetObjectDescription().c_str()); + } + ptr->object_in_constructor_ = false; + ptr->object_creating_strong_reffed_ = true; +#endif // BA_DEBUG_BUILD + return Object::Ref(ptr); + } + + /// In some cases it may be handy to allocate an object for ref-counting + /// but not actually create references yet. (Such as when creating an object + /// in one thread to be passed to another which will own said object) + /// For such cases, allocate using NewDeferred() and then use MakeRefCounted() + /// on the raw Object* to create its initial reference. + /// Note that in debug builds this will run checks to make sure the object + /// wound up being ref-counted. To allocate an object for manual + /// deallocation, use NewUnmanaged() + template + [[nodiscard]] static auto NewDeferred(ARGS&&... args) -> T* { + T* ptr = new T(std::forward(args)...); +#if BA_DEBUG_BUILD + if (ptr->object_strong_ref_count_ > 0) { + printf("Obj strong-ref in constructor: %s\n", + ptr->GetObjectDescription().c_str()); + } + ptr->object_in_constructor_ = false; +#endif + return ptr; + } + + template + static auto MakeRefCounted(T* ptr) -> Object::Ref { +#if BA_DEBUG_BUILD + // Make sure we're operating on a fresh object. + assert(ptr->object_strong_ref_count_ == 0); + if (ptr->object_creating_strong_reffed_) { + // Avoiding Log for these low level errors; can lead to deadlock. + printf("Object already set up as reffed in MakeRefCounted: %s\n", + ptr->GetObjectDescription().c_str()); + } + ptr->object_creating_strong_reffed_ = true; +#endif + return Object::Ref(ptr); + } + + /// Allocate an Object with no ref-counting; for use when an object + /// will be manually managed/deleted. + /// In debug builds, these objects will complain if attempts are made to + /// create strong references to them. + template + [[nodiscard]] static auto NewUnmanaged(ARGS&&... args) -> T* { + T* ptr = new T(std::forward(args)...); +#if BA_DEBUG_BUILD + ptr->object_in_constructor_ = false; +#endif + return ptr; + } + + private: + // Making operator new private here to help ensure all of our dynamic + // allocation/deallocation goes through our special functions (New(), + // NewDeferred(), etc.). However, sticking with original new for release + // builds since it may handle corner cases this does not. +#if BA_DEBUG_BUILD + auto operator new(size_t size) -> void* { return new char[size]; } +#endif + +#if BA_DEBUG_BUILD + bool object_has_strong_ref_{}; + bool object_creating_strong_reffed_{}; + bool object_is_dead_{}; + bool object_in_constructor_{true}; + Object* object_next_{}; + Object* object_prev_{}; + ThreadOwnership thread_ownership_{ThreadOwnership::kClassDefault}; + ThreadIdentifier owner_thread_{ThreadIdentifier::kInvalid}; + bool thread_checks_enabled_{true}; + millisecs_t object_birth_time_{}; + bool object_printed_warning_{}; +#endif + int object_strong_ref_count_{}; + WeakRefBase* object_weak_refs_{}; + BA_DISALLOW_CLASS_COPIES(Object); +}; // Object + +/// Convert a vector of ptrs into a vector of refs. +template +auto PointersToRefs(const std::vector& ptrs) + -> std::vector > { + std::vector > refs; + refs.reserve(ptrs.size()); + for (typename std::vector::const_iterator i = ptrs.begin(); + i != ptrs.end(); i++) { + refs.push_back(Object::Ref(*i)); + } + return refs; +} + +/// Convert a vector of ptrs into a vector of refs. +template +auto PointersToWeakRefs(const std::vector& ptrs) + -> std::vector > { + std::vector > refs; + refs.reserve(ptrs.size()); + for (typename std::vector::const_iterator i = ptrs.begin(); + i != ptrs.end(); i++) { + refs.push_back(Object::WeakRef(*i)); + } + return refs; +} + +/// Convert a vector of refs to a vector of ptrs. +template +auto RefsToPointers(const std::vector >& refs) + -> std::vector { + std::vector ptrs; + auto refs_size = refs.size(); + if (refs_size > 0) { + ptrs.resize(refs_size); + + // Let's just access the memory directly; potentially faster? + T** p = &(ptrs[0]); + for (size_t i = 0; i < refs_size; i++) { + p[i] = refs[i].get(); + } + } + return ptrs; +} + +/// Prune dead refs out of a vector/list. +template +void PruneDeadRefs(T* list) { + for (typename T::iterator i = list->begin(); i != list->end();) { + if (!i->exists()) { + i = list->erase(i); + } else { + i++; + } + } +} + +/// Prune dead refs out of a map/etc. +template +void PruneDeadMapRefs(T* map) { + for (typename T::iterator i = map->begin(); i != map->end();) { + if (!i->second.exists()) { + typename T::iterator i_next = i; + i_next++; + map->erase(i); + i = i_next; + } else { + i++; + } + } +} + +/// Print an Object (handles nullptr too). +inline auto ObjToString(Object* obj) -> std::string { + return obj ? obj->GetObjectDescription() : ""; +} + +// A handy utility which creates a weak-ref in debug mode +// and a simple pointer in release mode. +// This can be used when a pointer *should* always be valid +// but its nice to be sure when the cpu cycles don't matter +#if BA_DEBUG_BUILD +#define BA_DEBUG_PTR(TYPE) Object::WeakRef +#else +#define BA_DEBUG_PTR(TYPE) TYPE* +#endif + +} // namespace ballistica + +#endif // BALLISTICA_CORE_OBJECT_H_ diff --git a/src/ballistica/core/thread.cc b/src/ballistica/core/thread.cc new file mode 100644 index 00000000..f9283720 --- /dev/null +++ b/src/ballistica/core/thread.cc @@ -0,0 +1,630 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/core/thread.h" + +#include + +#include "ballistica/app/app.h" +#include "ballistica/core/fatal_error.h" +#include "ballistica/core/module.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +bool Thread::threads_paused_ = false; + +void Thread::AddCurrentThreadName(const std::string& name) { + std::lock_guard lock(g_app_globals->thread_name_map_mutex); + std::thread::id thread_id = std::this_thread::get_id(); + auto i = g_app_globals->thread_name_map.find(thread_id); + std::string s; + if (i != g_app_globals->thread_name_map.end()) { + s = i->second; + } + if (!strstr(s.c_str(), name.c_str())) { + if (s.empty()) { + s = name; + } else { + s = s + "+" + name; + } + } + g_app_globals->thread_name_map[std::this_thread::get_id()] = s; +} + +void Thread::ClearCurrentThreadName() { + std::lock_guard lock(g_app_globals->thread_name_map_mutex); + auto i = g_app_globals->thread_name_map.find(std::this_thread::get_id()); + if (i != g_app_globals->thread_name_map.end()) { + g_app_globals->thread_name_map.erase(i); + } +} + +void Thread::UpdateMainThreadID() { + auto current_id = std::this_thread::get_id(); + + // This gets called a lot and it may happen before we are spun up, + // so just ignore it in that case.. + if (g_app_globals) { + g_app_globals->main_thread_id = current_id; + } + if (g_app) { + g_app->thread()->set_thread_id(current_id); + } +} + +void Thread::KillModule(const Module& module) { + for (auto i = modules_.begin(); i != modules_.end(); i++) { + if (*i == &module) { + delete *i; + modules_.erase(i); + return; + } + } + throw Exception("Module not found on this thread"); +} + +void Thread::KillModules() { + for (auto i : modules_) { + delete i; + } + modules_.clear(); +} + +// These are all exactly the same, but by running different ones for +// different thread groups makes its easy to see which thread is which +// in profilers, backtraces, etc. +auto Thread::RunGameThread(void* data) -> int { + return static_cast(data)->ThreadMain(); +} + +auto Thread::RunAudioThread(void* data) -> int { + return static_cast(data)->ThreadMain(); +} + +auto Thread::RunBGDynamicThread(void* data) -> int { + return static_cast(data)->ThreadMain(); +} + +auto Thread::RunNetworkWriteThread(void* data) -> int { + return static_cast(data)->ThreadMain(); +} + +auto Thread::RunStdInputThread(void* data) -> int { + return static_cast(data)->ThreadMain(); +} + +auto Thread::RunMediaThread(void* data) -> int { + return static_cast(data)->ThreadMain(); +} + +void Thread::SetPaused(bool paused) { + // Can be toggled from the main thread only. + assert(std::this_thread::get_id() == g_app_globals->main_thread_id); + PushThreadMessage(ThreadMessage(paused ? ThreadMessage::Type::kPause + : ThreadMessage::Type::kResume)); +} + +void Thread::WaitForNextEvent(bool single_cycle) { + // If we're running a single cycle we never stop to wait. + if (single_cycle) { + return; + } + + // We also never wait if any of our modules have pending runnables. + // (we run all existing runnables in each loop cycle, but one of those + // may have enqueued more). + for (auto&& i : modules_) { + if (i->has_pending_runnables()) { + return; + } + } + + // While we're waiting, allow other python threads to run. + if (owns_python_) { + g_python->ReleaseGIL(); + } + + // If we've got active timers, wait for messages with a timeout so we can + // run the next timer payload. + if ((!paused_) && timers_.active_timer_count() > 0) { + millisecs_t real_time = GetRealTime(); + millisecs_t wait_time = timers_.GetTimeToNextExpire(real_time); + if (wait_time > 0) { + std::unique_lock lock(thread_message_mutex_); + if (thread_message_count_ == 0) { + thread_message_cv_.wait_for(lock, std::chrono::milliseconds(wait_time), + [this] { + // Go back to sleep on spurious wakeups + // if we didn't wind up with any new + // messages. + return (thread_message_count_ > 0); + }); + } + } + } else { + // Not running timers; just wait indefinitely for the next message. + std::unique_lock lock(thread_message_mutex_); + if (thread_message_count_ == 0) { + thread_message_cv_.wait(lock, [this] { + // Go back to sleep on spurious wakeups + // (if we didn't wind up with any new messages). + return (thread_message_count_ > 0); + }); + } + } + + if (owns_python_) { + g_python->AcquireGIL(); + } +} + +void Thread::LoopUpkeep(bool single_cycle) { + // Keep our autorelease pool clean on mac/ios + // FIXME: Should define a Platform::ThreadHelper or something + // so we don't have platform-specific code here. +#if BA_XCODE_BUILD + // Let's not do autorelease pools when being called ad-hoc, + // since in that case we're part of another run loop + // (and its crashing on drain for some reason) + if (!single_cycle) { + if (auto_release_pool_) { + g_platform->DrainAutoReleasePool(auto_release_pool_); + auto_release_pool_ = nullptr; + } + auto_release_pool_ = g_platform->NewAutoReleasePool(); + } +#endif +} + +auto Thread::RunEventLoop(bool single_cycle) -> int { + while (true) { + LoopUpkeep(single_cycle); + + WaitForNextEvent(single_cycle); + + // Process all queued thread messages. + std::list thread_messages; + GetThreadMessages(&thread_messages); + for (auto& thread_message : thread_messages) { + switch (thread_message.type) { + case ThreadMessage::Type::kNewModule: { + // Launch a new module and unlock. + ModuleLauncher* tl; + tl = static_cast(thread_message.pval); + tl->Launch(this); + auto cmd = + static_cast(ThreadMessage::Type::kNewModuleConfirm); + WriteToOwner(&cmd, sizeof(cmd)); + break; + } + case ThreadMessage::Type::kRunnable: { + auto module_id = thread_message.ival; + Module* t = GetModule(module_id); + assert(t); + auto e = static_cast(thread_message.pval); + + // Add the event to our list. + t->PushLocalRunnable(e); + RunnablesWhilePausedSanityCheck(e); + + break; + } + case ThreadMessage::Type::kShutdown: { + // Shutdown; die! + done_ = true; + break; + } + case ThreadMessage::Type::kResume: { + assert(paused_); + + // Let all modules do pause-related stuff. + for (auto&& i : modules_) { + i->HandleThreadResume(); + } + paused_ = false; + break; + } + case ThreadMessage::Type::kPause: { + assert(!paused_); + + // Let all modules do pause-related stuff. + for (auto&& i : modules_) { + i->HandleThreadPause(); + } + paused_ = true; + last_pause_time_ = GetRealTime(); + messages_since_paused_ = 0; + break; + } + default: { + throw Exception(); + } + } + + // If the thread is going down. + if (done_) { + break; + } + } + + // Run timers && queued module runnables unless we're paused. + if (!paused_) { + // Run timers. + timers_.Run(GetRealTime()); + + // Run module-messages. + for (auto& module_entry : modules_) { + module_entry->RunPendingRunnables(); + } + } + if (done_ || single_cycle) { + break; + } + } + return 0; +} + +void Thread::RunnablesWhilePausedSanityCheck(Runnable* e) { + // We generally shouldn't be getting messages while paused.. + // (check both our pause-state and the global one; wanna ignore things + // that might slip through if some just-unlocked thread msgs us but we + // haven't been unlocked yet) + + // UPDATE - we are migrating away from distinct message classes and towards + // LambdaRunnables for everything, which means that we can't easily + // see details of what is coming through. Disabling this check for now. +} + +void Thread::GetThreadMessages(std::list* messages) { + assert(messages); + assert(std::this_thread::get_id() == thread_id()); + + // Make sure they passed an empty one in. + assert(messages->empty()); + if (thread_message_count_ > 0) { + std::unique_lock lock(thread_message_mutex_); + assert(thread_messages_.size() == thread_message_count_); + messages->swap(thread_messages_); + thread_message_count_ = 0; + } +} + +void Thread::WriteToOwner(const void* data, uint32_t size) { + assert(std::this_thread::get_id() == thread_id()); + { + std::unique_lock lock(data_to_client_mutex_); + data_to_client_.emplace_back(size); + memcpy(&(data_to_client_.back()[0]), data, size); + } + data_to_client_cv_.notify_all(); +} + +Thread::Thread(ThreadIdentifier identifier_in, ThreadType type_in) + : type_(type_in), identifier_(identifier_in) { + switch (type_) { + case ThreadType::kStandard: { + // Lock down until the thread is up and running. It'll unlock us when + // it's ready to go. + int (*func)(void*); + switch (identifier_) { + case ThreadIdentifier::kGame: + func = RunGameThread; + break; + case ThreadIdentifier::kMedia: + func = RunMediaThread; + break; + case ThreadIdentifier::kMain: + // Shouldn't happen; this thread gets wrapped; not launched. + throw Exception(); + case ThreadIdentifier::kAudio: + func = RunAudioThread; + break; + case ThreadIdentifier::kBGDynamics: + func = RunBGDynamicThread; + break; + case ThreadIdentifier::kNetworkWrite: + func = RunNetworkWriteThread; + break; + case ThreadIdentifier::kStdin: + func = RunStdInputThread; + break; + default: + throw Exception(); + } + + // Let 'er rip. + thread_ = new std::thread(func, this); + + // The thread lets us know when its up and running. + std::unique_lock lock(data_to_client_mutex_); + + uint32_t cmd; + ReadFromThread(&lock, &cmd, sizeof(cmd)); + assert(static_cast(cmd) + == ThreadMessage::Type::kNewThreadConfirm); + break; + } + case ThreadType::kMain: { + // We've got no thread of our own to launch + // so we run our setup stuff right here instead of off in some. + assert(std::this_thread::get_id() == g_app_globals->main_thread_id); + thread_id_ = std::this_thread::get_id(); + + // Hmmm we might want to set our thread name here, + // as we do for other threads? + // However on linux that winds up being what we see in top/etc + // so maybe shouldn't. + break; + } + } +} + +auto Thread::ThreadMain() -> int { + try { + assert(type_ == ThreadType::kStandard); + thread_id_ = std::this_thread::get_id(); + + const char* id_string; + switch (identifier_) { + case ThreadIdentifier::kGame: + id_string = "ballistica game"; + break; + case ThreadIdentifier::kStdin: + id_string = "ballistica stdin"; + break; + case ThreadIdentifier::kMedia: + id_string = "ballistica media"; + break; + case ThreadIdentifier::kFileOut: + id_string = "ballistica file-out"; + break; + case ThreadIdentifier::kMain: + id_string = "ballistica main"; + break; + case ThreadIdentifier::kAudio: + id_string = "ballistica audio"; + break; + case ThreadIdentifier::kBGDynamics: + id_string = "ballistica bg-dynamics"; + break; + case ThreadIdentifier::kNetworkWrite: + id_string = "ballistica network writing"; + break; + default: + throw Exception(); + } + g_platform->SetCurrentThreadName(id_string); + + // Send our owner a confirmation that we're alive. + auto cmd = static_cast(ThreadMessage::Type::kNewThreadConfirm); + WriteToOwner(&cmd, sizeof(cmd)); + + // Now just run our loop until we die. + int result = RunEventLoop(); + + KillModules(); + ClearCurrentThreadName(); + return result; + } catch (const std::exception& e) { + auto error_msg = std::string("Unhandled exception in ") + + GetCurrentThreadName() + " thread:\n" + e.what(); + + FatalError::ReportFatalError(error_msg, true); + bool exit_cleanly = !IsUnmodifiedBlessedBuild(); + bool handled = FatalError::HandleFatalError(exit_cleanly, true); + + // Do the default thing if platform didn't handle it. + if (!handled) { + if (exit_cleanly) { + exit(1); + } else { + throw; + } + } + return 0; + } +} + +void Thread::SetOwnsPython() { + owns_python_ = true; + g_python->AcquireGIL(); +} + +// Explicitly kill the main thread. +void Thread::Quit() { + assert(type_ == ThreadType::kMain); + if (type_ == ThreadType::kMain) { + done_ = true; + } +} + +Thread::~Thread() = default; + +void Thread::LogThreadMessageTally() { + // Prevent recursion. + if (!writing_tally_) { + writing_tally_ = true; + + std::map tally; + Log("Thread message tally (" + std::to_string(thread_messages_.size()) + + " in list):"); + for (auto&& m : thread_messages_) { + std::string s; + switch (m.type) { + case ThreadMessage::Type::kShutdown: + s += "kShutdown"; + break; + case ThreadMessage::Type::kRunnable: + s += "kRunnable"; + break; + case ThreadMessage::Type::kNewModule: + s += "kNewModule"; + break; + case ThreadMessage::Type::kNewModuleConfirm: + s += "kNewModuleConfirm"; + break; + case ThreadMessage::Type::kNewThreadConfirm: + s += "kNewThreadConfirm"; + break; + case ThreadMessage::Type::kPause: + s += "kPause"; + break; + case ThreadMessage::Type::kResume: + s += "kResume"; + break; + default: + s += "UNKNOWN(" + std::to_string(static_cast(m.type)) + ")"; + break; + } + if (m.type == ThreadMessage::Type::kRunnable) { + // Runnable* e; + // e = static_cast(m.pval); + { + std::string m_name = g_platform->DemangleCXXSymbol( + typeid(*(static_cast(m.pval))).name()); + s += std::string(": ") + m_name; + } + } + auto j = tally.find(s); + if (j == tally.end()) { + tally[s] = 1; + } else { + tally[s]++; + } + } + int entry = 1; + for (auto&& i : tally) { + Log(" #" + std::to_string(entry++) + " (" + std::to_string(i.second) + + "x): " + i.first); + } + writing_tally_ = false; + } +} + +void Thread::PushThreadMessage(const ThreadMessage& t) { + { + std::unique_lock lock(thread_message_mutex_); + + // Plop the data on to the list; we're assuming the mutex is locked. + thread_messages_.push_back(t); + + // Keep our own count; apparently size() on an stl list involves + // iterating. + // FIXME: Actually I don't think this is the case anymore; should check. + thread_message_count_++; + assert(thread_message_count_ == thread_messages_.size()); + + // Show message count states. + if (explicit_bool(false)) { + static int one_off = 0; + static int foo = 0; + foo++; + one_off++; + + // Show momemtary spikes. + if (thread_message_count_ > 100 && one_off > 100) { + one_off = 0; + foo = 999; + } + + // Show count periodically. + if ((std::this_thread::get_id() == g_app_globals->main_thread_id) + && foo > 100) { + foo = 0; + Log("MSG COUNT " + std::to_string(thread_message_count_)); + } + } + + if (thread_message_count_ > 1000) { + static bool sent_error = false; + if (!sent_error) { + sent_error = true; + Log("Error: ThreadMessage list > 1000 in thread: " + + GetCurrentThreadName()); + LogThreadMessageTally(); + } + } + + // Prevent runaway mem usage if the list gets out of control. + if (thread_message_count_ > 10000) { + throw Exception("KILLING APP: ThreadMessage list > 10000 in thread: " + + GetCurrentThreadName()); + } + + // Unlock thread-message list and inform thread that there's something + // available. + } + thread_message_cv_.notify_all(); +} + +void Thread::ReadFromThread(std::unique_lock* lock, void* buffer, + uint32_t size) { + // Threads cant read from themselves.. could load to lock-deadlock. + assert(std::this_thread::get_id() != thread_id()); + data_to_client_cv_.wait(*lock, [this] { + // Go back to sleep on spurious wakeups + // (if we didn't wind up with any new messages) + return (!data_to_client_.empty()); + }); + + // Read the oldest thing on our in-data list. + assert(!data_to_client_.empty()); + assert(data_to_client_.front().size() == size); + memcpy(buffer, &(data_to_client_.front()[0]), size); + data_to_client_.pop_front(); +} + +void Thread::SetThreadsPaused(bool paused) { + threads_paused_ = paused; + for (auto&& i : g_app_globals->pausable_threads) { + i->SetPaused(paused); + } +} + +auto Thread::AreThreadsPaused() -> bool { return threads_paused_; } + +auto Thread::RegisterModule(const std::string& name, Module* module) -> int { + AddCurrentThreadName(name); + // This should assure we were properly launched. + // (the ModuleLauncher will set the index to what ours will be) + int index = static_cast(modules_.size()); + // module_entries_.emplace_back(module, name, index); + modules_.push_back(module); + return index; +} + +auto Thread::NewTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> Timer* { + assert(IsCurrent()); + assert(runnable.exists()); + return timers_.NewTimer(GetRealTime(), length, 0, repeat ? -1 : 0, runnable); +} + +auto Thread::GetCurrentThreadName() -> std::string { + if (g_app_globals == nullptr) { + return "unknown(not-yet-inited)"; + } + { + std::lock_guard lock(g_app_globals->thread_name_map_mutex); + auto i = g_app_globals->thread_name_map.find(std::this_thread::get_id()); + if (i != g_app_globals->thread_name_map.end()) { + return i->second; + } + } +#if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS || BA_OSTYPE_LINUX + std::string name = "unknown (sys-name="; + char buffer[256]; + int result = pthread_getname_np(pthread_self(), buffer, sizeof(buffer)); + if (result == 0) { + name += std::string("\"") + buffer + "\")"; + } else { + name += ""; + } + return name; +#else + return "unknown"; +#endif +} + +} // namespace ballistica diff --git a/src/ballistica/core/thread.h b/src/ballistica/core/thread.h new file mode 100644 index 00000000..cb940299 --- /dev/null +++ b/src/ballistica/core/thread.h @@ -0,0 +1,249 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_THREAD_H_ +#define BALLISTICA_CORE_THREAD_H_ + +#include +#include +#include +#include +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/ballistica.h" +#include "ballistica/generic/timer_list.h" +#include "ballistica/platform/min_sdl.h" + +namespace ballistica { + +// A thread with a built-in event loop. +class Thread { + public: + explicit Thread(ThreadIdentifier id, + ThreadType type_in = ThreadType::kStandard); + virtual ~Thread(); + + /// Register a name for the current thread (should generally describe its + /// purpose). If called multiple times, names will be combined with a '+'. ie: + /// "graphics+animation+audio". + void AddCurrentThreadName(const std::string& name); + void ClearCurrentThreadName(); + + static auto GetCurrentThreadName() -> std::string; + + /// Call this if the main thread changes. + static void UpdateMainThreadID(); + + static void SetThreadsPaused(bool enable); + static auto AreThreadsPaused() -> bool; + + auto IsCurrent() const -> bool { + return std::this_thread::get_id() == thread_id(); + } + + // Used to quit the main thread. + void Quit(); + + struct ModuleLauncher { + virtual void Launch(Thread* g) = 0; + virtual ~ModuleLauncher() = default; + }; + + template + struct ModuleLauncherTemplate : public ModuleLauncher { + void Launch(Thread* g) override { new MODULETYPE(g); } + }; + + template + struct ModuleLauncherArgTemplate : public ModuleLauncher { + explicit ModuleLauncherArgTemplate(ARGTYPE arg_in) : arg(arg_in) {} + ARGTYPE arg; + void Launch(Thread* g) override { new MODULETYPE(g, arg); } + }; + + void SetOwnsPython(); + + // Add a new module to a thread. This doesn't return anything. If you need + // a pointer to the module, have it store itself somewhere in its constructor + // or whatnot. Returning a pointer made it too easy to introduce race + // conditions with the thread trying to access itself via this pointer + // before it was set up. + template + void AddModule() { + switch (type_) { + case ThreadType::kStandard: { + // Launching a module in the current thread: do it immediately. + if (IsCurrent()) { + ModuleLauncherTemplate launcher; + launcher.Launch(this); + } else { + // Launching a module in another thread; + // send a module-launcher and wait for the confirmation. + ModuleLauncherTemplate launcher; + ModuleLauncher* tl = &launcher; + PushThreadMessage( + ThreadMessage(ThreadMessage::Type::kNewModule, 0, tl)); + std::unique_lock lock(data_to_client_mutex_); + uint32_t cmd; + ReadFromThread(&lock, &cmd, sizeof(cmd)); + assert(static_cast(cmd) + == ThreadMessage::Type::kNewModuleConfirm); + } + break; + } + case ThreadType::kMain: { + assert(std::this_thread::get_id() == g_app_globals->main_thread_id); + new THREADTYPE(this); + break; + } + default: { + throw Exception(); + } + } + } + + // An alternate version of AddModule that passes an argument along + // to the thread's constructor. + template + void AddModule(ARGTYPE arg) { + switch (type_) { + case ThreadType::kStandard: { + // Launching a module in the current thread: do it immediately. + if (IsCurrent()) { + ModuleLauncherArgTemplate launcher(arg); + launcher.Launch(this); + } else { + // Launching a module in another thread; + // send a module-launcher and wait for the confirmation. + ModuleLauncherArgTemplate launcher(arg); + ModuleLauncher* tl = &launcher; + PushThreadMessage( + ThreadMessage(ThreadMessage::Type::kNewModule, 0, tl)); + + std::unique_lock lock(data_to_client_mutex_); + + uint32_t cmd; + + ReadFromThread(&lock, &cmd, sizeof(cmd)); + + assert(static_cast(cmd) + == ThreadMessage::Type::kNewModuleConfirm); + } + break; + } + case ThreadType::kMain: { + assert(std::this_thread::get_id() == g_app_globals->main_thread_id); + new THREADTYPE(this, arg); + break; + } + default: { + throw Exception(); + } + } + } + void KillModule(const Module& module); + + void SetPaused(bool paused); + auto thread_id() const -> std::thread::id { return thread_id_; } + + // Needed in rare cases where we jump physical threads. + // (Our 'main' thread on Android can switch under us as + // rendering contexts are recreated in new threads/etc.) + void set_thread_id(std::thread::id id) { thread_id_ = id; } + + auto RunEventLoop(bool single_cycle = false) -> int; + auto identifier() const -> ThreadIdentifier { return identifier_; } + + // For use by modules. + auto RegisterModule(const std::string& name, Module* module) -> int; + void PushModuleRunnable(Runnable* runnable, int module_index) { + PushThreadMessage(Thread::ThreadMessage( + Thread::ThreadMessage::Type::kRunnable, module_index, runnable)); + } + + // Register a timer to run on the thread. + auto NewTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> Timer*; + + private: + struct ThreadMessage { + enum class Type { + kShutdown = 999, + kRunnable, + kNewModule, + kNewModuleConfirm, + kNewThreadConfirm, + kPause, + kResume + }; + Type type; + void* pval; + int ival; + explicit ThreadMessage(Type type_in, int ival_in = 0, + void* pval_in = nullptr) + : type(type_in), ival(ival_in), pval(pval_in) {} + }; + static void RunnablesWhilePausedSanityCheck(Runnable* r); + void WaitForNextEvent(bool single_cycle); + void LoopUpkeep(bool once); + void LogThreadMessageTally(); + void ReadFromThread(std::unique_lock* lock, void* buffer, + uint32_t size); + + void WriteToOwner(const void* data, uint32_t size); + bool writing_tally_ = false; + bool paused_ = false; + millisecs_t last_pause_time_ = 0; + int messages_since_paused_ = 0; + millisecs_t last_paused_message_report_time_ = 0; + bool done_ = false; + ThreadType type_; + int listen_sd_ = 0; + std::thread::id thread_id_{}; + ThreadIdentifier identifier_ = ThreadIdentifier::kInvalid; + millisecs_t last_complaint_time_ = 0; + bool owns_python_ = false; + + // FIXME: Should generalize this to some sort of PlatformThreadData class. +#if BA_XCODE_BUILD + void* auto_release_pool_ = nullptr; +#endif + + void KillModules(); + + // These are all exactly the same, but by running different ones for + // different thread groups makes its easy to see which thread is which + // in profilers, backtraces, etc. + static auto RunGameThread(void* data) -> int; + static auto RunAudioThread(void* data) -> int; + static auto RunBGDynamicThread(void* data) -> int; + static auto RunNetworkWriteThread(void* data) -> int; + static auto RunStdInputThread(void* data) -> int; + static auto RunMediaThread(void* data) -> int; + + auto ThreadMain() -> int; + std::thread* thread_; + void GetThreadMessages(std::list* messages); + void PushThreadMessage(const ThreadMessage& t); + std::condition_variable thread_message_cv_; + std::mutex thread_message_mutex_; + std::list thread_messages_; + int thread_message_count_ = 0; + std::condition_variable data_to_client_cv_; + std::mutex data_to_client_mutex_; + std::list > data_to_client_; + std::vector modules_; + auto GetModule(int id) -> Module* { + assert(id >= 0 && id < static_cast(modules_.size())); + return modules_[id]; + } + + // Complete list of all timers created by this group's modules. + TimerList timers_; + static bool threads_paused_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_CORE_THREAD_H_ diff --git a/src/ballistica/core/types.h b/src/ballistica/core/types.h new file mode 100644 index 00000000..3fe73091 --- /dev/null +++ b/src/ballistica/core/types.h @@ -0,0 +1,1068 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CORE_TYPES_H_ +#define BALLISTICA_CORE_TYPES_H_ + +// Types used throughout the project. +// This header should not depend on any others in the project. +// Types can be defined (or predeclared) here if the are used +// in a significant number of places. The aim is to reduce the +// overall number of headers a given source file needs to pull in, +// helping to keep compile times down. + +#ifdef __cplusplus + +// Predeclare a few global namespace things +// (just enough to pass some pointers around without +// requiring system-ish headers). +#if BA_ENABLE_AUDIO +typedef struct ALCcontext_struct ALCcontext; +#endif +typedef struct _object PyObject; +typedef struct _ts PyThreadState; + +#if BA_SDL_BUILD || BA_MINSDL_BUILD +union SDL_Event; +struct SDL_Keysym; +typedef struct _SDL_Joystick SDL_Joystick; +#endif + +namespace ballistica { + +// Used internally for time values. +typedef int64_t millisecs_t; + +// We predeclare all our main ba classes here so that we can +// avoid pulling in their full headers as much as possible +// to keep compile times down. + +class Account; +class App; +class AppConfig; +class AppGlobals; +class AreaOfInterest; +class Audio; +class AudioServer; +class AudioStreamer; +class AudioSource; +class BGDynamics; +class BGDynamicsServer; +class BGDynamicsDrawSnapshot; +class BGDynamicsEmission; +class BGDynamicsFuse; +struct BGDynamicsFuseData; +class BGDynamicsHeightCache; +class BGDynamicsShadow; +struct BGDynamicsShadowData; +class BGDynamicsVolumeLight; +struct BGDynamicsVolumeLightData; +class ButtonWidget; +struct cJSON; +class Camera; +class ClientControllerInterface; +class ClientInputDevice; +class ClientSession; +class CollideModel; +class CollideModelData; +class Collision; +class CollisionCache; +class Connection; +class ConnectionToClient; +class Context; +class ContextTarget; +class ConnectionToClientUDP; +class ConnectionToHost; +class ConnectionToHostUDP; +class ContainerWidget; +class Console; +class CubeMapTexture; +class Data; +class DataData; +class Dynamics; +class FrameDef; +struct FriendScoreSet; +class Game; +class GLContext; +class GlobalsNode; +class Graphics; +class GraphicsServer; +class HostActivity; +class HostSession; +class Huffman; +class ImageMesh; +class ImageWidget; +class Input; +class InputDevice; +struct JointFixedEF; +class Joystick; +class KeyboardInput; +class Material; +class MaterialAction; +class MaterialComponent; +class MaterialConditionNode; +class MaterialContext; +class Matrix44f; +class Media; +class MediaComponentData; +class MediaServer; +class MeshBufferBase; +class MeshBufferVertexSprite; +class MeshBufferVertexSimpleFull; +class MeshBufferVertexSmokeFull; +class Mesh; +class MeshData; +class MeshDataClientHandle; +class MeshIndexBuffer16; +class MeshIndexedSimpleFull; +class MeshIndexedSmokeFull; +class MeshRendererData; +class Model; +class ModelData; +class ModelRendererData; +class NetClientThread; +class NetGraph; +class Networking; +class NetworkReader; +class NetworkWriteModule; +class Node; +class NodeType; +class NodeAttribute; +class NodeAttributeConnection; +class NodeAttributeUnbound; +class Object; +class ObjectComponent; +class GameStream; +class Part; +class Python; +class Platform; +class Player; +class PlayerNode; +class PlayerSpec; +class PythonClassCollideModel; +class PythonClassMaterial; +class PythonClassModel; +class PythonClassSound; +class PythonClassTexture; +class Python; +class PythonRef; +class PythonCommand; +class PythonContextCall; +template +class RealTimer; +class Rect; +class Renderer; +class RenderComponent; +class RenderCommandBuffer; +class RenderPass; +class RenderTarget; +class ReplayClientSession; +class RemoteAppServer; +class RemoteControlInput; +class RigidBody; +class RootUI; +class RootWidget; +class Runnable; +class Scene; +class ScoreToBeat; +class SDLApp; +class SDLContext; +class Session; +class SockAddr; +class Sound; +class SoundData; +class SpriteMesh; +class StackWidget; +class StdInputModule; +class Module; +class TelnetServer; +class TestInput; +class TextGroup; +class TextGraphics; +class TextMesh; +class TextPacker; +class Texture; +class TextureData; +class TexturePreloadData; +class TextureRendererData; +class TextWidget; +class Thread; +class Timer; +class TimerList; +class TouchInput; +class UI; +class Utils; +class Vector2f; +class Vector3f; +class Vector4f; +class VRApp; +class VRGraphics; +class Widget; + +// BA_EXPORT_PYTHON_ENUM +/// Types of input a controller can send to the game. +/// +/// Category: Enums +/// +enum class InputType { + kUpDown = 2, + kLeftRight, + kJumpPress, + kJumpRelease, + kPunchPress, + kPunchRelease, + kBombPress, + kBombRelease, + kPickUpPress, + kPickUpRelease, + kRun, + kFlyPress, + kFlyRelease, + kStartPress, + kStartRelease, + kHoldPositionPress, + kHoldPositionRelease, + kLeftPress, + kLeftRelease, + kRightPress, + kRightRelease, + kUpPress, + kUpRelease, + kDownPress, + kDownRelease, + kLast // Sentinel +}; + +typedef int64_t TimerMedium; + +// BA_EXPORT_PYTHON_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. +/// +/// Category: Enums +/// +/// '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. +enum class UIScale { + kLarge, + kMedium, + kSmall, + kLast // Sentinel. +}; + +// BA_EXPORT_PYTHON_ENUM +/// Specifies the type of time for various operations to target/use. +/// +/// Category: Enums +/// +/// 'sim' time is the local simulation time for an activity or session. +/// It can proceed at different rates depending on game speed, stops +/// for pauses, etc. +/// +/// 'base' is the baseline time for an activity or session. It proceeds +/// consistently regardless of game speed or pausing, but may stop during +/// occurrences such as network outages. +/// +/// 'real' time is mostly based on clock time, with a few exceptions. It may +/// not advance while the app is backgrounded for instance. (the engine +/// attempts to prevent single large time jumps from occurring) +enum class TimeType { + kSim, + kBase, + kReal, + kLast // Sentinel. +}; + +// BA_EXPORT_PYTHON_ENUM +/// Specifies the format time values are provided in. +/// +/// Category: Enums +enum class TimeFormat { + kSeconds, + kMilliseconds, + kLast // Sentinel. +}; + +// BA_EXPORT_PYTHON_ENUM +/// Permissions that can be requested from the OS. +/// +/// Category: Enums +enum class Permission { + kStorage, + kLast // Sentinel. +}; + +// BA_EXPORT_PYTHON_ENUM +/// Special characters the game can print. +/// +/// Category: Enums +enum class SpecialChar { + kDownArrow, + kUpArrow, + kLeftArrow, + kRightArrow, + kTopButton, + kLeftButton, + kRightButton, + kBottomButton, + kDelete, + kShift, + kBack, + kLogoFlat, + kRewindButton, + kPlayPauseButton, + kFastForwardButton, + kDpadCenterButton, + kOuyaButtonO, + kOuyaButtonU, + kOuyaButtonY, + kOuyaButtonA, + kOuyaLogo, + kLogo, + kTicket, + kGooglePlayGamesLogo, + kGameCenterLogo, + kDiceButton1, + kDiceButton2, + kDiceButton3, + kDiceButton4, + kGameCircleLogo, + kPartyIcon, + kTestAccount, + kTicketBacking, + kTrophy1, + kTrophy2, + kTrophy3, + kTrophy0a, + kTrophy0b, + kTrophy4, + kLocalAccount, + kAlibabaLogo, + kFlagUnitedStates, + kFlagMexico, + kFlagGermany, + kFlagBrazil, + kFlagRussia, + kFlagChina, + kFlagUnitedKingdom, + kFlagCanada, + kFlagIndia, + kFlagJapan, + kFlagFrance, + kFlagIndonesia, + kFlagItaly, + kFlagSouthKorea, + kFlagNetherlands, + kFedora, + kHal, + kCrown, + kYinYang, + kEyeBall, + kSkull, + kHeart, + kDragon, + kHelmet, + kMushroom, + kNinjaStar, + kVikingHelmet, + kMoon, + kSpider, + kFireball, + kFlagUnitedArabEmirates, + kFlagQatar, + kFlagEgypt, + kFlagKuwait, + kFlagAlgeria, + kFlagSaudiArabia, + kFlagMalaysia, + kFlagCzechRepublic, + kFlagAustralia, + kFlagSingapore, + kOculusLogo, + kSteamLogo, + kNvidiaLogo, + kFlagIran, + kFlagPoland, + kFlagArgentina, + kFlagPhilippines, + kFlagChile, + kMikirog, + kLast // Sentinel +}; + +enum class MediaType { kTexture, kCollideModel, kModel, kSound, kData, kLast }; + +/// Python exception types we can raise from our own exceptions. +enum class PyExcType { + kRuntime, + kAttribute, + kIndex, + kType, + kValue, + kContext, + kNotFound, + kNodeNotFound, + kActivityNotFound, + kSessionNotFound, + kSessionPlayerNotFound, + kInputDeviceNotFound, + kDelegateNotFound, + kWidgetNotFound +}; + +enum class SystemTextureID { + kUIAtlas, + kButtonSquare, + kWhite, + kFontSmall0, + kFontBig, + kCursor, + kBoxingGlove, + kShield, + kExplosion, + kTextClearButton, + kWindowHSmallVMed, + kWindowHSmallVSmall, + kGlow, + kScrollWidget, + kScrollWidgetGlow, + kFlagPole, + kScorch, + kScorchBig, + kShadow, + kLight, + kShadowSharp, + kLightSharp, + kShadowSoft, + kLightSoft, + kSparks, + kEye, + kEyeTint, + kFuse, + kShrapnel1, + kSmoke, + kCircle, + kCircleOutline, + kCircleNoAlpha, + kCircleOutlineNoAlpha, + kCircleShadow, + kSoftRect, + kSoftRect2, + kSoftRectVertical, + kStartButton, + kBombButton, + kOuyaAButton, + kBackIcon, + kNub, + kArrow, + kMenuButton, + kUsersButton, + kActionButtons, + kTouchArrows, + kTouchArrowsActions, + kRGBStripes, + kUIAtlas2, + kFontSmall1, + kFontSmall2, + kFontSmall3, + kFontSmall4, + kFontSmall5, + kFontSmall6, + kFontSmall7, + kFontExtras, + kFontExtras2, + kFontExtras3, + kFontExtras4, + kCharacterIconMask, + kBlack, + kWings +}; + +enum class SystemCubeMapTextureID { + kReflectionChar, + kReflectionPowerup, + kReflectionSoft, + kReflectionSharp, + kReflectionSharper, + kReflectionSharpest +}; + +enum class SystemSoundID { + kDeek = 0, + kBlip, + kBlank, + kPunch, + kClick, + kErrorBeep, + kSwish, + kSwish2, + kSwish3, + kTap, + kCorkPop, + kGunCock, + kTickingCrazy, + kSparkle, + kSparkle2, + kSparkle3 +}; + +enum class SystemDataID {}; + +enum class SystemModelID { + kButtonSmallTransparent, + kButtonSmallOpaque, + kButtonMediumTransparent, + kButtonMediumOpaque, + kButtonBackTransparent, + kButtonBackOpaque, + kButtonBackSmallTransparent, + kButtonBackSmallOpaque, + kButtonTabTransparent, + kButtonTabOpaque, + kButtonLargeTransparent, + kButtonLargeOpaque, + kButtonLargerTransparent, + kButtonLargerOpaque, + kButtonSquareTransparent, + kButtonSquareOpaque, + kCheckTransparent, + kScrollBarThumbTransparent, + kScrollBarThumbOpaque, + kScrollBarThumbSimple, + kScrollBarThumbShortTransparent, + kScrollBarThumbShortOpaque, + kScrollBarThumbShortSimple, + kScrollBarTroughTransparent, + kTextBoxTransparent, + kImage1x1, + kImage1x1FullScreen, + kImage2x1, + kImage4x1, + kImage16x1, +#if BA_VR_BUILD + kImage1x1VRFullScreen, + kVROverlay, + kVRFade, +#endif + kOverlayGuide, + kWindowHSmallVMedTransparent, + kWindowHSmallVMedOpaque, + kWindowHSmallVSmallTransparent, + kWindowHSmallVSmallOpaque, + kSoftEdgeOutside, + kSoftEdgeInside, + kBoxingGlove, + kShield, + kFlagPole, + kFlagStand, + kScorch, + kEyeBall, + kEyeBallIris, + kEyeLid, + kHairTuft1, + kHairTuft1b, + kHairTuft2, + kHairTuft3, + kHairTuft4, + kShrapnel1, + kShrapnelSlime, + kShrapnelBoard, + kShockWave, + kFlash, + kCylinder, + kArrowFront, + kArrowBack, + kActionButtonLeft, + kActionButtonTop, + kActionButtonRight, + kActionButtonBottom, + kBox, + kLocator, + kLocatorBox, + kLocatorCircle, + kLocatorCircleOutline, + kCrossOut, + kWing +}; + +enum class NodeCollideAttr { + /// Whether or not a collision should occur at all. + /// If this is false for either node in the final context, + /// no collide events are run. + kCollideNode +}; + +enum class PartCollideAttr { + /// Whether or not a collision should occur at all. + /// If this is false for either surface in the final context, + /// no collide events are run. + kCollide, + + /// Whether to honor node-collisions. + /// Turn this on if you want a collision to occur even if + /// The part is ignoring collisions with your node due + /// to an existing NodeModAction. + kUseNodeCollide, + + /// Whether a physical collision happens. + kPhysical, + + /// Friction for physical collisions. + kFriction, + + /// Stiffness for physical collisions. + kStiffness, + + /// Damping for physical collisions. + kDamping, + + /// Bounce for physical collisions. + kBounce +}; + +enum class MaterialCondition { + /// Always evaluates to true. + kTrue, + + /// Always evaluates to false. + kFalse, + + /// Dst part contains specified material; requires 1 arg - material id. + kDstIsMaterial, + + /// Dst part does not contain specified material; requires 1 arg - material + /// id. + kDstNotMaterial, + + /// Dst part is in specified node; requires 1 arg - node id. + kDstIsNode, + + /// Dst part not in specified node; requires 1 arg - node id. + kDstNotNode, + + /// Dst part is specified part; requires 2 args, node id, part id. + kDstIsPart, + + /// Dst part not specified part; requires 2 args, node id, part id. + kDstNotPart, + + /// Dst part contains src material; no args. + kSrcDstSameMaterial, + + /// Dst part does not contain the src material; no args. + kSrcDstDiffMaterial, + + /// Dst and src parts in same node; no args. + kSrcDstSameNode, + + /// Dst and src parts in different node; no args. + kSrcDstDiffNode, + + /// Src part younger than specified value; requires 1 arg - age. + kSrcYoungerThan, + + /// Src part equal to or older than specified value; requires 1 arg - age. + kSrcOlderThan, + + /// Dst part younger than specified value; requires 1 arg - age. + kDstYoungerThan, + + /// Dst part equal to or older than specified value; requires 1 arg - age. + kDstOlderThan, + + /// Src part is already colliding with a part on dst node; no args. + kCollidingDstNode, + + /// Src part is not already colliding with a part on dst node; no args. + kNotCollidingDstNode, + + /// Set to collide at current point in rule evaluation. + kEvalColliding, + + /// Set to not collide at current point in rule evaluation. + kEvalNotColliding +}; + +/// Types of shading. +/// These do not necessarily correspond to actual shader objects in the renderer +/// (a single shader may handle more than one of these, etc). +/// These are simply categories of looks. +enum class ShadingType { + kSimpleColor, + kSimpleColorTransparent, + kSimpleColorTransparentDoubleSided, + kSimpleTexture, + kSimpleTextureModulated, + kSimpleTextureModulatedColorized, + kSimpleTextureModulatedColorized2, + kSimpleTextureModulatedColorized2Masked, + kSimpleTextureModulatedTransparent, + kSimpleTextureModulatedTransFlatness, + kSimpleTextureModulatedTransparentDoubleSided, + kSimpleTextureModulatedTransparentColorized, + kSimpleTextureModulatedTransparentColorized2, + kSimpleTextureModulatedTransparentColorized2Masked, + kSimpleTextureModulatedTransparentShadow, + kSimpleTexModulatedTransShadowFlatness, + kSimpleTextureModulatedTransparentGlow, + kSimpleTextureModulatedTransparentGlowMaskUV2, + kObject, + kObjectTransparent, + kObjectLightShadowTransparent, + kSpecial, + kShield, + kObjectReflect, + kObjectReflectTransparent, + kObjectReflectAddTransparent, + kObjectLightShadow, + kObjectReflectLightShadow, + kObjectReflectLightShadowDoubleSided, + kObjectReflectLightShadowColorized, + kObjectReflectLightShadowColorized2, + kObjectReflectLightShadowAdd, + kObjectReflectLightShadowAddColorized, + kObjectReflectLightShadowAddColorized2, + kSmoke, + kSmokeOverlay, + kPostProcess, + kPostProcessEyes, + kPostProcessNormalDistort, + kSprite, + kCount +}; + +enum class DrawType { kTriangles, kPoints }; + +/// Hints to the renderer - stuff that is changed rarely should be static, +/// and stuff changed often should be dynamic. +enum class MeshDrawType { kStatic, kDynamic }; + +enum class ReflectionType { + kNone, + kChar, + kPowerup, + kSoft, + kSharp, + kSharper, + kSharpest +}; + +/// Command values sent across the wire in netplay. +/// Must remain consistent across versions! +enum class SessionCommand { + kBaseTimeStep, + kStepSceneGraph, + kAddSceneGraph, + kRemoveSceneGraph, + kAddNode, + kNodeOnCreate, + kSetForegroundSceneGraph, + kRemoveNode, + kAddMaterial, + kRemoveMaterial, + kAddMaterialComponent, + kAddTexture, + kRemoveTexture, + kAddModel, + kRemoveModel, + kAddSound, + kRemoveSound, + kAddCollideModel, + kRemoveCollideModel, + kConnectNodeAttribute, + kNodeMessage, + kSetNodeAttrFloat, + kSetNodeAttrInt32, + kSetNodeAttrBool, + kSetNodeAttrFloats, + kSetNodeAttrInt32s, + kSetNodeAttrString, + kSetNodeAttrNode, + kSetNodeAttrNodeNull, + kSetNodeAttrNodes, + kSetNodeAttrPlayer, + kSetNodeAttrPlayerNull, + kSetNodeAttrMaterials, + kSetNodeAttrTexture, + kSetNodeAttrTextureNull, + kSetNodeAttrTextures, + kSetNodeAttrSound, + kSetNodeAttrSoundNull, + kSetNodeAttrSounds, + kSetNodeAttrModel, + kSetNodeAttrModelNull, + kSetNodeAttrModels, + kSetNodeAttrCollideModel, + kSetNodeAttrCollideModelNull, + kSetNodeAttrCollideModels, + kPlaySoundAtPosition, + kPlaySound, + kEmitBGDynamics, + kEndOfFile, + kDynamicsCorrection, + kScreenMessageBottom, + kScreenMessageTop, + kAddData, + kRemoveData +}; + +/// Standard messages to send to nodes. +/// Note: the names of these in python are their camelback forms, +/// so SELF_STATE is "selfState", etc. +enum class NodeMessageType { + /// Generic flash - no args. + kFlash, + /// Celebrate message - one int arg for duration. + kCelebrate, + /// Left-hand celebrate message - one int arg for duration. + kCelebrateL, + /// Right-hand celebrate message - one int arg for duration. + kCelebrateR, + /// Instantaneous impulse 3 vector floats. + kImpulse, + kKickback, + /// Knock the target out for an amount of time. + kKnockout, + /// Make a hurt sound. + kHurtSound, + /// You've been picked up.. lose balance or whatever. + kPickedUp, + /// Make a jump sound. + kJumpSound, + /// Make an attack sound. + kAttackSound, + /// Tell the player to scream. + kScreamSound, + /// Move to stand upon the given point facing the given angle. + /// 3 position floats and one angle float. + kStand, + /// Add or remove footing from a node. + /// First arg is an int - either 1 or -1 for add or subtract. + kFooting +}; + +enum class AccountState { kSignedOut, kSigningIn, kSignedIn }; + +enum class CameraMode { kFollow, kOrbit }; + +enum class MeshDataType { + kIndexedSimpleSplit, + kIndexedObjectSplit, + kIndexedSimpleFull, + kIndexedDualTextureFull, + kIndexedSmokeFull, + kSprite +}; + +struct TouchEvent { + enum class Type { kDown, kUp, kMoved, kCanceled }; + Type type{}; + void* touch{}; + bool overall{}; // For sanity-checks. + float x{}; + float y{}; +}; + +// Standard vertex structs used in rendering/fileIO/etc. +// Remember to make sure components are on 4 byte boundaries. +// (need to find out how strict we need to be on Metal, Vulkan, etc). + +struct VertexSimpleSplitStatic { + uint16_t uv[2]; +}; + +struct VertexSimpleSplitDynamic { + float position[3]; +}; + +struct VertexSimpleFull { + float position[3]; + uint16_t uv[2]; +}; + +struct VertexDualTextureFull { + float position[3]; + uint16_t uv[2]; + uint16_t uv2[2]; +}; + +struct VertexObjectSplitStatic { + uint16_t uv[2]; +}; + +struct VertexObjectSplitDynamic { + float position[3]; + int16_t normal[3]; + int8_t padding[2]; +}; + +struct VertexObjectFull { + float position[3]; + uint16_t uv[2]; + int16_t normal[3]; + uint8_t padding[2]; +}; + +struct VertexSmokeFull { + float position[3]; + float uv[2]; + uint8_t color[4]; + uint8_t diffuse; + uint8_t padding1[3]; + uint8_t erode; + uint8_t padding2[3]; +}; + +struct VertexSprite { + float position[3]; + uint16_t uv[2]; + float size; + float color[4]; +}; + +enum class MeshFormat { + /// 16bit UV, 8bit normal, 8bit pt-index. + kUV16N8Index8, + /// 16bit UV, 8bit normal, 16bit pt-index. + kUV16N8Index16, + /// 16bit UV, 8bit normal, 32bit pt-index. + kUV16N8Index32 +}; + +enum class TextureType { k2D, kCubeMap }; + +enum class TextureFormat { + kNone, + kRGBA_8888, + kRGB_888, + kRGBA_4444, + kRGB_565, + kDXT1, + kDXT5, + kETC1, + kPVR2, + kPVR4, + kETC2_RGB, + kETC2_RGBA +}; + +enum class TextureCompressionType { kS3TC, kPVR, kETC1, kETC2 }; + +enum class TextureMinQuality { kLow, kMedium, kHigh }; + +enum NodeAttributeFlag { kNodeAttributeFlagReadOnly = 1u }; + +enum class NodeAttributeType { + kFloat, + kFloatArray, + kInt, + kIntArray, + kBool, + kString, + kNode, + kNodeArray, + kPlayer, + kMaterialArray, + kTexture, + kTextureArray, + kSound, + kSoundArray, + kModel, + kModelArray, + kCollideModel, + kCollideModelArray +}; + +enum class ThreadType { + /// A normal thread spun up by us. + kStandard, + /// For wrapping a ballistica thread around the existing main thread. + kMain +}; + +/// Used for module-thread identification. +/// Mostly just for debugging, through a few things are affected by this +/// (the GAME thread manages the python GIL, etc). +enum class ThreadIdentifier { + kInvalid, + kGame, + kMedia, + kFileOut, + kMain, + kAudio, + kNetworkWrite, + kSuicide, + kStdin, + kBGDynamics +}; + +enum class AccountType { + kInvalid, + kTest, + kGameCenter, + kGameCircle, + kGooglePlay, + kDevice, + kServer, + kOculus, + kSteam, + kNvidiaChina +}; + +enum class GraphicsQuality { + /// Bare minimum graphics. + kLow, + /// Basic graphics; no post-processing. + kMedium, + /// Graphics with bare minimum post-processing. + kHigh, + /// Graphics with full post-processing. + kHigher, + /// Select graphics options automatically. + kAuto +}; + +enum class TextMeshEntryType { kRegular, kExtras, kOSRendered }; + +enum ModelDrawFlags { kModelDrawFlagNoReflection = 1 }; + +enum class LightShadowType { kNone, kTerrain, kObject }; + +enum class TextureQuality { kAuto, kHigh, kMedium, kLow }; + +typedef Node* NodeCreateFunc(Scene* sg); + +enum class BenchmarkType { kNone, kCPU, kGPU }; + +#if BA_VR_BUILD +enum class VRHandType { kNone, kDaydreamRemote, kOculusTouchL, kOculusTouchR }; +struct VRHandState { + VRHandType type = VRHandType::kNone; + float tx = 0.0f; + float ty = 0.0f; + float tz = 0.0f; + float yaw = 0.0f; + float pitch = 0.0f; + float roll = 0.0f; +}; +struct VRHandsState { + VRHandState l; + VRHandState r; +}; +#endif // BA_VR_BUILD + +} // namespace ballistica + +#endif // __cplusplus + +#endif // BALLISTICA_CORE_TYPES_H_ diff --git a/src/ballistica/generic/base64.cc b/src/ballistica/generic/base64.cc new file mode 100644 index 00000000..b7a76cab --- /dev/null +++ b/src/ballistica/generic/base64.cc @@ -0,0 +1,161 @@ +// Copyright (c) 2011-2020 Eric Froemling +// Derived from code licensed as follows: + +/* + base64.cpp and base64.h + + Copyright (C) 2004-2008 René Nyffenegger + + This source code is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + + 3. This notice may not be removed or altered from any source distribution. + + René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +*/ +#include "ballistica/generic/base64.h" + +#include + +namespace ballistica { + +// NOLINTNEXTLINE(cert-err58-cpp) +static const std::string* base64_chars_non_urlsafe = new std::string( + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"); + +// NOLINTNEXTLINE(cert-err58-cpp) +static const std::string* base64_chars_urlsafe = new std::string( + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"); + +static inline auto is_base64(unsigned char c, bool urlsafe) -> bool { + if (urlsafe) { + return (isalnum(c) || (c == '-') || (c == '_')); + } else { + return (isalnum(c) || (c == '+') || (c == '/')); + } +} + +auto base64_encode(const unsigned char* bytes_to_encode, unsigned int in_len, + bool urlsafe) -> std::string { + std::string ret; + int i = 0; + // int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + static const std::string& base64_chars = + urlsafe ? *base64_chars_urlsafe : *base64_chars_non_urlsafe; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = + static_cast((char_array_3[0] & 0xfcu) >> 2u); + char_array_4[1] = + static_cast(((char_array_3[0] & 0x03u) << 4u) + + ((char_array_3[1] & 0xf0u) >> 4u)); + char_array_4[2] = + static_cast(((char_array_3[1] & 0x0fu) << 2u) + + ((char_array_3[2] & 0xc0u) >> 6u)); + char_array_4[3] = static_cast(char_array_3[2] & 0x3fu); + + for (i = 0; (i < 4); i++) ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) { + for (int j = i; j < 3; j++) { + char_array_3[j] = '\0'; + } + char_array_4[0] = + static_cast((char_array_3[0] & 0xfcu) >> 2u); + char_array_4[1] = static_cast( + ((char_array_3[0] & 0x03u) << 4u) + ((char_array_3[1] & 0xf0u) >> 4u)); + char_array_4[2] = static_cast( + ((char_array_3[1] & 0x0fu) << 2u) + ((char_array_3[2] & 0xc0u) >> 6u)); + char_array_4[3] = static_cast(char_array_3[2u] & 0x3fu); + for (int j = 0; (j < i + 1); j++) { + ret += base64_chars[char_array_4[j]]; + } + while ((i++ < 3)) { + ret += '='; + } + } + + return ret; +} + +auto base64_decode(const std::string& encoded_string, bool urlsafe) + -> std::string { + int in_len = static_cast(encoded_string.size()); + int i = 0; + // int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + static const std::string& base64_chars = + urlsafe ? *base64_chars_urlsafe : *base64_chars_non_urlsafe; + + while (in_len-- && (encoded_string[in_] != '=') + && is_base64((unsigned char)encoded_string[in_], urlsafe)) { + char_array_4[i++] = (unsigned char)encoded_string[in_]; + in_++; + if (i == 4) { + for (i = 0; i < 4; i++) { + char_array_4[i] = + static_cast(base64_chars.find(char_array_4[i])); + } + + char_array_3[0] = static_cast( + (char_array_4[0] << 2u) + ((char_array_4[1] & 0x30u) >> 4u)); + char_array_3[1] = static_cast( + ((char_array_4[1] & 0xfu) << 4u) + ((char_array_4[2] & 0x3cu) >> 2u)); + char_array_3[2] = static_cast( + ((char_array_4[2] & 0x3u) << 6u) + char_array_4[3]); + + for (i = 0; (i < 3); i++) ret += char_array_3[i]; + i = 0; + } + } + if (i) { + for (int j = i; j < 4; j++) { + char_array_4[j] = 0; + } + for (int j = 0; j < 4; j++) { // NOLINT(modernize-loop-convert) + char_array_4[j] = + static_cast(base64_chars.find(char_array_4[j])); + } + char_array_3[0] = static_cast( + (char_array_4[0] << 2u) + ((char_array_4[1] & 0x30u) >> 4u)); + char_array_3[1] = static_cast( + ((char_array_4[1] & 0xfu) << 4u) + ((char_array_4[2] & 0x3cu) >> 2u)); + char_array_3[2] = static_cast( + ((char_array_4[2] & 0x3u) << 6u) + char_array_4[3]); + for (int j = 0; (j < i - 1); j++) { + ret += char_array_3[j]; + } + } + return ret; +} + +} // namespace ballistica diff --git a/src/ballistica/generic/base64.h b/src/ballistica/generic/base64.h new file mode 100644 index 00000000..dcc5deef --- /dev/null +++ b/src/ballistica/generic/base64.h @@ -0,0 +1,16 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_BASE64_H_ +#define BALLISTICA_GENERIC_BASE64_H_ + +#include + +namespace ballistica { + +auto base64_encode(const unsigned char*, unsigned int len, bool urlsafe = false) + -> std::string; +auto base64_decode(const std::string& s, bool urlsafe = false) -> std::string; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_BASE64_H_ diff --git a/src/ballistica/generic/buffer.h b/src/ballistica/generic/buffer.h new file mode 100644 index 00000000..7ac2399b --- /dev/null +++ b/src/ballistica/generic/buffer.h @@ -0,0 +1,95 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_BUFFER_H_ +#define BALLISTICA_GENERIC_BUFFER_H_ + +#include + +#include "ballistica/generic/utils.h" + +namespace ballistica { + +// Simple data-holding buffer class. +// (FIXME: should kill this and just use std::vector for this purpose) +template +class Buffer { + public: + Buffer(const Buffer& b) : data_(nullptr), size_(0) { + Resize(b.size()); + if (b.size() > 0) { + memcpy(data_, b.data_, b.size() * sizeof(T)); + } + } + + ~Buffer() { + if (data_) { + free(data_); + } + } + + auto operator=(const Buffer& src) -> Buffer& { + assert(this != &src); // Shouldn't be self-assigning. + Resize(src.size()); + if (size_ > 0) { + memcpy(data_, src.data_, size_ * sizeof(T)); + } + return *this; + } + + explicit Buffer(size_t size_in = 0) : data_(nullptr), size_(size_in) { + if (size_ > 0) { + Resize(size_); + } + } + + Buffer(const T* data_in, size_t length) : data_(nullptr), size_(0) { + if (length > 0) { + Resize(length); + memcpy(data_, data_in, length * sizeof(T)); + } + } + + /// Get the amount of space needed to embed this buffer + auto GetFlattenedSize() -> size_t { return 4 + size_ * sizeof(T); } + + /// Embed this buffer into a flat memory buffer. + void embed(char** b) { + // Embed our size (in items not bytes). + Utils::EmbedInt32NBO(b, static_cast(size_)); + memcpy(*b, data_, size_ * sizeof(T)); + *b += size_ * sizeof(T); + } + + /// Extract this buffer for a flat memory buffer. + void Extract(const char** b) { + Resize(static_cast_check_fit(Utils::ExtractInt32NBO(b))); + memcpy(data_, *b, size_ * sizeof(T)); + *b += size_ * sizeof(T); + } + + void Resize(size_t new_size) { + if (data_) { + free(data_); + } + if (new_size > 0) { + data_ = static_cast(malloc(new_size * sizeof(T))); + BA_PRECONDITION(data_); + } else { + data_ = nullptr; + } + size_ = new_size; + } + + // gets the length in the buffer's units (not bytes) + auto size() const -> size_t { return size_; } + + auto data() const -> T* { return data_; } + + private: + T* data_; + size_t size_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_BUFFER_H_ diff --git a/src/ballistica/generic/huffman.cc b/src/ballistica/generic/huffman.cc new file mode 100644 index 00000000..18e1550a --- /dev/null +++ b/src/ballistica/generic/huffman.cc @@ -0,0 +1,590 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/generic/huffman.h" + +#include +#include + +#include "ballistica/networking/networking.h" + +namespace ballistica { + +// Yes, I should clean this up to use unsigned vals, but it seems to work +// fine for now so I don't want to touch it. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +// how much data we read in training mode before spitting out results +#if HUFFMAN_TRAINING_MODE +const int kTrainingLength = 200000; +#endif + +// we currently just have a static table of char frequencies - this can be +// generated by setting "training mode" on. +static int g_freqs[] = { + 101342, 9667, 3497, 1072, 0, 3793, 0, 0, 2815, 5235, 0, 0, 0, 3570, 0, 0, + 0, 1383, 0, 0, 0, 2970, 0, 0, 2857, 0, 0, 0, 0, 0, 0, 0, + 0, 1199, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1494, + 1974, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1351, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1475, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static void DoWriteBits(char** ptr, int* bit, int val, int val_bits) { + int src_bit = 0; + while (src_bit < val_bits) { + **ptr |= ((val >> src_bit) & 0x01) << (*bit); // NOLINT + if ((*bit) == 7) (*ptr)++; + (*bit) = ((*bit) + 1) % 8; + src_bit++; + } +} + +Huffman::Huffman() : built(false) { + static_assert(sizeof(g_freqs) == sizeof(int) * 256); + build(); +} + +Huffman::~Huffman() = default; + +auto Huffman::compress(const std::vector& src) + -> std::vector { +#if BA_HUFFMAN_NET_COMPRESSION + + auto length = static_cast(src.size()); + const char* data = (const char*)src.data(); + + // IMPORTANT: + // our uncompressed packets have a type byte at the beginning + // (which should just be a few bits) + // and the compressed ones have a remainder byte (4 bits of which are used) + // ...so the first few bits should always be unused. + // we hijack the highest bit to denote whether we're sending + // a compressed or uncompressed packet (1 for compressed, 0 for uncompressed) + BA_PRECONDITION(data[0] >> 7 == 0); + + // see how many bits we'll need + uint32_t bit_count = 0; + for (uint32_t i = 0; i < length; i++) { + bit_count += nodes_[static_cast(data[i])].bits; + } + + // round up to next byte and add our one-byte header + uint32_t length_out = bit_count / 8 + 1; + if (bit_count % 8) { + length_out++; + } + bit_count %= 8; + + // if compressed is bigger than uncompressed, go with uncompressed - just + // return the data they provided + if ((length_out >= length)) { + return src; + } else { + std::vector out(length_out, 0); + + // first byte gives our number of empty trailing bits + char* ptr = reinterpret_cast(out.data()); + int bit = 0; + + *ptr = static_cast(8 - bit_count % 8); + if (*ptr == 8) { + *ptr = 0; + } + ptr++; + + for (uint32_t i = 0; i < length; i++) { + DoWriteBits(&ptr, &bit, nodes_[static_cast(data[i])].val, + nodes_[static_cast(data[i])].bits); + } + // make sure we're either at the end of our allotted buffer or we're one + // from the end and the bitcount takes care of the rest + assert(ptr - reinterpret_cast(out.data()) == length_out + || (ptr - reinterpret_cast(out.data()) == length_out - 1 + && bit_count != 0)); + assert(bit == bit_count % 8); + + // mark it as compressed + out[0] |= (0x01 << 7); + return out; + } +#else + +#if HUFFMAN_TRAINING_MODE + train(data, length); +#endif + + data_out = data; + length_out = length; +#endif +} + +// hmmm - I saw a crash logged in this function; need to make sure this is +// bulletproof since untrusted data is coming through here.. +auto Huffman::decompress(const std::vector& src) + -> std::vector { +#if BA_HUFFMAN_NET_COMPRESSION + + auto length = static_cast(src.size()); + BA_PRECONDITION(length > 0); + + const char* data = (const char*)src.data(); + + auto remainder = static_cast(*data & 0x0F); + bool compressed = *data >> 7; + + if (compressed) { + std::vector out; + out.reserve(src.size() * 2); // hopefully minimize reallocations.. + + uint32_t bit_length = ((length - 1) * 8); + if (remainder > bit_length) throw Exception("invalid huffman data"); + bit_length -= remainder; + uint32_t bit = 0; + const char* ptr = data + 1; + + // navigate bit by bit through our nodes to build values from binary codes + while (bit < bit_length) { + bool bitval = static_cast((ptr[bit / 8] >> (bit % 8)) & 0x01); + bit++; + + // 1 in first bit denotes huffman compressed + if (bitval) { + int val; + int n = 510; + BA_PRECONDITION(nodes_[n].parent == 0); + while (true) { + BA_PRECONDITION(n <= 510); + + bitval = static_cast((ptr[bit / 8] >> (bit % 8)) & 0x01); + + // 1 for right, 0 for left + if (bitval == 0) { + if (nodes_[n].left_child == -1) { + val = n; + break; + } else { + n = nodes_[n].left_child; + bit++; + } + } else { + if (nodes_[n].right_child == -1) { + val = n; + break; + } else { + n = nodes_[n].right_child; + bit++; + } + } + // ERICF FIX - if both new children are dead-ends, stop reading + // bits; otherwise we might read past the end of the buffer. + // (I assume the original code didn't have child nodes with dual -1s + // so this case probably never came up) + if (nodes_[n].left_child == -1 && nodes_[n].right_child == -1) { + val = n; + break; + } + + if (bit > bit_length) { + throw Exception("huffman decompress got bit > bitlength"); + } + } + out.push_back(static_cast(val)); + } else { + // just read next 8 bits as value + uint8_t val; + if (bit % 8 == 0) { + BA_PRECONDITION((bit / 8) < (length - 1)); + val = static_cast(ptr[bit / 8]); + } else { + BA_PRECONDITION((bit / 8 + 1) < (length - 1)); + val = (static_cast(ptr[bit / 8]) >> bit % 8) + | (static_cast(ptr[bit / 8 + 1]) << (8 - bit % 8)); + } + out.push_back(val); + bit += 8; + if (bit > bit_length) { + throw Exception("huffman decompress got bit > bitlength b"); + } + } + } + BA_PRECONDITION(bit == bit_length); + return out; + } else { + // uncompressed - just provide it as is + return src; + } + +#else + data_out = data; + length_out = length; +#endif +} + +// old janky version.. +#if 0 +void Huffman::compress(const char* data, uint32_t length, const char*& data_out, + uint32_t& length_out) { + if (length > kMaxPacketSize) { + throw Exception("packet too large for huffman compressor: " + + std::to_string(length) + " (packet " + + std::to_string(static_cast(data[0])) + ")"); + } + +#if BA_HUFFMAN_NET_COMPRESSION + + // all our packets have a type bit at the beginning + // we hijack the highest bit to denote whether we're sending + // a compressed or uncompressed packet (1 for compressed, 0 for uncompressed) + BA_PRECONDITION(data[0] >> 7 == 0); + + // length_out = length; + // if (buffer.size() < length_out) + // buffer.resize(length_out); + // memcpy(buffer.data,data,length_out); + + // see how many bits we'll need + uint32_t bit_count = 0; + for (uint32_t i = 0; i < length; i++) { + bit_count += nodes[static_cast(data[i])].bits; + } + + // round up to next byte and add our one-byte header + length_out = bit_count / 8 + 1; + if (bit_count % 8) length_out++; + bit_count %= 8; + + // if compressed is bigger than uncompressed, go with uncompressed - + // just return the data they provided + + // lets always do huffman in debug builds; make sure we aren't making + // any incorrect assumptions about + // where stuff is compressed vs uncompressed. +#if BA_DEBUG_BUILD + bool force = false; +#else + bool force = false; +#endif + + if ((length_out >= length) && !force) { + // throw Exception(); + data_out = data; + length_out = length; + } else { + if (buffer.size() < length_out) { + buffer.resize(length_out); + } + + // first byte gives our number of empty trailing bits + memset(buffer.data, 0, buffer.size()); + char* ptr = buffer.data; + int bit = 0; + + *ptr = (8 - bit_count % 8); + if (*ptr == 8) *ptr = 0; + ptr++; + + for (uint32_t i = 0; i < length; i++) { + DoWriteBits(ptr, bit, nodes[static_cast(data[i])].val, + nodes[static_cast(data[i])].bits); + } + + // make sure we're either at the end of our alloted buffer or we're one + // from the end and the bitcount takes care of the rest + assert(ptr - buffer.data == length_out + || (ptr - buffer.data == length_out - 1 && bit_count != 0)); + assert(bit == bit_count % 8); + // for (int i = 0; i < length_out;i++) + // buffer.data[i]--; + + data_out = buffer.data; + + // mark it as compressed + buffer.data[0] |= (0x01 << 7); + } +#else + +#if HUFFMAN_TRAINING_MODE + train(data, length); +#endif + + data_out = data; + length_out = length; +#endif +} +#endif + +#if 0 +void Huffman::decompress(const char* data, uint32_t length, + const char*& data_out, uint32_t& length_out) { +#if BA_HUFFMAN_NET_COMPRESSION + + uint8_t remainder = *data & 0x0F; + bool compressed = *data >> 7; + + if (compressed) { + uint32_t bit_length = ((length - 1) * 8) - remainder; + + uint32_t bit = 0; + const char* ptr = data + 1; + uint32_t bytes = 0; + + // navigate bit by bit through our nodes to build values from binary codes + while (bit < bit_length) { + bool bitval = (ptr[bit / 8] >> (bit % 8)) & 0x01; + bit++; + + // 1 in first bit denotes huffman compressed + if (bitval) { + int val; + int n = 510; + assert(nodes[n].parent == 0); + while (true) { + bitval = (ptr[bit / 8] >> (bit % 8)) & 0x01; + + // 1 for right, 0 for left + if (bitval == 0) { + if (nodes[n].left_child == -1) { + val = n; + break; + } else { + n = nodes[n].left_child; + bit++; + } + } else { + if (nodes[n].right_child == -1) { + val = n; + break; + } else { + n = nodes[n].right_child; + bit++; + } + } + } + buffer.data[bytes] = val; + bytes++; + } else { + // just read next 8 bits as value + // unsigned int val = (((ptr[(bit+0)/8] >> ((bit+0)%8)) & 0x01) + // << 0) + // | (((ptr[(bit+1)/8] >> ((bit+1)%8)) & 0x01) << 1) + // | (((ptr[(bit+2)/8] >> ((bit+2)%8)) & 0x01) << 2) + // | (((ptr[(bit+3)/8] >> ((bit+3)%8)) & 0x01) << 3) + // | (((ptr[(bit+4)/8] >> ((bit+4)%8)) & 0x01) << 4) + // | (((ptr[(bit+5)/8] >> ((bit+5)%8)) & 0x01) << 5) + // | (((ptr[(bit+6)/8] >> ((bit+6)%8)) & 0x01) << 6) + // | (((ptr[(bit+7)/8] >> ((bit+7)%8)) & 0x01) << 7); + + uint8_t val; + if (bit % 8 == 0) + val = static_cast(ptr[bit / 8]); + else + val = (static_cast(ptr[bit / 8]) >> bit % 8) + | (static_cast(ptr[bit / 8 + 1]) << (8 - bit % 8)); + // uint8_t val2 = (((ptr[(bit+0)/8] >> ((bit+0)%8)) & 0x01) << + // 0) + // | (((ptr[(bit+1)/8] >> ((bit+1)%8)) & 0x01) << 1) + // | (((ptr[(bit+2)/8] >> ((bit+2)%8)) & 0x01) << 2) + // | (((ptr[(bit+3)/8] >> ((bit+3)%8)) & 0x01) << 3) + // | (((ptr[(bit+4)/8] >> ((bit+4)%8)) & 0x01) << 4) + // | (((ptr[(bit+5)/8] >> ((bit+5)%8)) & 0x01) << 5) + // | (((ptr[(bit+6)/8] >> ((bit+6)%8)) & 0x01) << 6) + // | (((ptr[(bit+7)/8] >> ((bit+7)%8)) & 0x01) << 7); + // assert(val2 == val); + buffer.data[bytes] = val; + bytes++; + bit += 8; + // throw Exception(); + } + } + assert(bit == bit_length); + + // fixme?? + if (bytes > kMaxPacketSize) { + Log("HUFFMAN DECOMPRESSING TO TOO LARGE: " + std::to_string(bytes)); + } + assert(bytes <= kMaxPacketSize); + + // throw Exception(); + + // length_out = length; + // if (buffer.size() < length_out) + // buffer.resize(length_out); + // memcpy(buffer.data,data,length_out); + // data_out = buffer.data; + // for (int i = 0; i < length_out;i++) + // buffer.data[i]++; + data_out = buffer.data; + length_out = bytes; + + } else { + // uncompressed - just provide it as is + data_out = data; + length_out = length; + } +#else + data_out = data; + length_out = length; +#endif +} +#endif // 0 + +#if HUFFMAN_TRAINING_MODE +void Huffman::train(const char* buffer, int len) { + if (built) { + test_bytes += len; + for (int i = 0; i < len; i++) { + test_bits_compressed += nodes[static_cast(buffer[i])].bits; + } + static int poo = 0; + poo++; + if (poo > 100) { + poo = 0; + test_bytes = 0; + test_bits_compressed = 0; + } + return; + } + total_length += len; + while (len > 0) { + nodes[static_cast(*buffer)].frequency++; + total_count++; + buffer++; + len--; + } + if (total_length > kTrainingLength) { + Log("HUFFMAN TRAINING COMPLETE:"); + + build(); + + // spit the C array to stdout for insertion into our code + string s = "{"; + for (int i = 0; i < 256; i++) { + s += std::to_string(nodes[i].frequency); + if (i < 255) s += ","; + } + s += "}"; + Log("FINAL: " + s); + } +} +#endif // HUFFMAN_TRAINING_MODE + +void Huffman::build() { + assert(!built); + + // if we're not in training mode, use our hard-coded values +#if 1 + for (int i = 0; i < 256; i++) { + nodes_[i].frequency = g_freqs[i]; + } +#else + // go through and set all but the top 15 or so to zero + // this is because all smaller values will be provided in full binary + // form and thus don't need to be influencing the graph + for (int i = 0; i < 256; i++) { + int bigger = 0; + for (int j = 0; j < 256; j++) { + if (nodes[j].frequency > nodes[i].frequency) { + bigger++; + if (bigger > 15) { + nodes[i].frequency = 0; + break; + } + } + } + } +#endif + + // first 256 nodes are leaves + int node_count = 256; + + // now loop through existing nodes finding the two smallest values without + // parents and creating a new parent node for them with their sum as its + // frequency value once there's only 1 node without a parent we're done + // (that's the root node) + int smallest1; + int smallest2; + while (node_count < 511) { + int i = 0; + + // find first two non-parented nodes + while (nodes_[i].parent != 0) i++; + smallest1 = i; + i++; + while (nodes_[i].parent != 0) i++; + smallest2 = i; + i++; + while (i < node_count) { + if (nodes_[i].parent == 0) { + // compare each node to the larger of the two existing to try and knock + // it off + if (nodes_[smallest1].frequency > nodes_[smallest2].frequency) { + if (nodes_[i].frequency < nodes_[smallest1].frequency) smallest1 = i; + } else { + if (nodes_[i].frequency < nodes_[smallest2].frequency) smallest2 = i; + } + } + i++; + } + nodes_[node_count].frequency = + nodes_[smallest1].frequency + nodes_[smallest2].frequency; + nodes_[smallest1].parent = static_cast(node_count - 255); + nodes_[smallest2].parent = static_cast(node_count - 255); + nodes_[node_count].right_child = static_cast(smallest1); + nodes_[node_count].left_child = static_cast(smallest2); + + node_count++; + } + + assert(nodes_[509].parent != 0); + assert(nodes_[510].parent == 0); + + // now store binary values for each base value (0-255) + for (int i = 0; i < 256; i++) { + // uint32_t val = 0; + nodes_[i].val = 0; + nodes_[i].bits = 0; + int index = i; + while (nodes_[index].parent != 0) { + // 0 if we're left child, 1 if we're right + if (nodes_[nodes_[index].parent + 255].right_child == index) { + nodes_[i].val = static_cast(nodes_[i].val << 1 | 0x01); + } else { + assert(nodes_[nodes_[index].parent + 255].left_child == index); + nodes_[i].val = nodes_[i].val << 1; + } + nodes_[i].bits++; + + index = nodes_[index].parent + 255; + } + // we're slightly different than normal huffman in that + // our first bit denotes whether the following values are the huffman bits + // or the full 8 bit value. + if (nodes_[i].bits >= 8) { + nodes_[i].bits = 8; + // nodes[i].val = nodes[i].val << 1; + nodes_[i].val = static_cast(i << 1); + } else { + nodes_[i].val = static_cast( + nodes_[i].val << 1 + | 0x01); // 1 in first bit denotes huffman compressed + } + // nodes[i].val = 0; + nodes_[i].bits += 1; + } + + built = true; +} + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/generic/huffman.h b/src/ballistica/generic/huffman.h new file mode 100644 index 00000000..44a17f53 --- /dev/null +++ b/src/ballistica/generic/huffman.h @@ -0,0 +1,61 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_HUFFMAN_H_ +#define BALLISTICA_GENERIC_HUFFMAN_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +class Huffman { + public: + Huffman(); + ~Huffman(); + +#if HUFFMAN_TRAINING_MODE + void train(const char* buffer, int len); +#endif + + void build(); + + // NOTE: this assumes the topmost bit of the first byte is unused + // (see details in implementation). + auto compress(const std::vector& src) -> std::vector; + auto decompress(const std::vector& src) -> std::vector; + auto get_built() const -> bool { return built; } + + private: + bool built; +#if HUFFMAN_TRAINING_MODE + uint32_t test_bytes = 0; + uint32_t test_bits_compressed = 0; + int total_count = 0; + int total_length = 0; +#endif + + class Node { + public: + Node() = default; + + // Left child index in node array (-1 for none). + int16_t left_child = -1; + + // Right child index in node array (-1 for none). + int16_t right_child = -1; + + // Parent index in node array (0 for none - add 255 to this to get actual + // index). + uint8_t parent = 0; + uint8_t bits = 0; + uint16_t val = 0; + int frequency = 0; + }; + + Node nodes_[511]; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_HUFFMAN_H_ diff --git a/src/ballistica/generic/json.cc b/src/ballistica/generic/json.cc new file mode 100644 index 00000000..87a0184e --- /dev/null +++ b/src/ballistica/generic/json.cc @@ -0,0 +1,1105 @@ +// Copyright (c) 2011-2020 Eric Froemling +// Derived from code licensed as follows: + +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +/* cJSON */ +/* JSON parser in C. */ + +#include "ballistica/generic/json.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace ballistica { + +// Should tidy this up but don't want to risk breaking it at the moment. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "bugprone-narrowing-conversions" +#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" + +static const char* ep; + +auto cJSON_GetErrorPtr() -> const char* { return ep; } + +static auto cJSON_strcasecmp(const char* s1, const char* s2) -> int { + if (!s1) return (s1 == s2) ? 0 : 1; + if (!s2) return 1; + for (; tolower(*s1) == tolower(*s2); ++s1, ++s2) + if (*s1 == 0) return 0; + return tolower(*(const unsigned char*)s1) + - tolower(*(const unsigned char*)s2); +} + +static void* (*cJSON_malloc)(size_t sz) = malloc; +static void (*cJSON_free)(void* ptr) = free; + +static auto cJSON_strdup(const char* str) -> char* { + size_t len; + char* copy; + + len = strlen(str) + 1; + if (!(copy = static_cast(cJSON_malloc(len)))) { + return nullptr; + } + memcpy(copy, str, len); + return copy; +} + +void cJSON_InitHooks(cJSON_Hooks* hooks) { + if (!hooks) { /* Reset hooks */ + cJSON_malloc = malloc; + cJSON_free = free; + return; + } + + cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc; + cJSON_free = (hooks->free_fn) ? hooks->free_fn : free; +} + +/* Internal constructor. */ +static auto cJSON_New_Item() -> cJSON* { + auto* node = static_cast(cJSON_malloc(sizeof(cJSON))); + if (node) memset(node, 0, sizeof(cJSON)); + return node; +} + +/* Delete a cJSON structure. */ +void cJSON_Delete(cJSON* c) { + cJSON* next; + while (c) { + next = c->next; + if (!(c->type & cJSON_IsReference) && c->child) cJSON_Delete(c->child); + if (!(c->type & cJSON_IsReference) && c->valuestring) + cJSON_free(c->valuestring); + if (c->string) cJSON_free(c->string); + cJSON_free(c); + c = next; + } +} + +/* Parse the input text to generate a number, and populate the result into item. + */ +static auto parse_number(cJSON* item, const char* num) -> const char* { + double n = 0, sign = 1, scale = 0; + int subscale = 0, signsubscale = 1; + + if (*num == '-') { + sign = -1; + num++; + } /* Has sign? */ + if (*num == '0') num++; /* is zero */ + if (*num >= '1' && *num <= '9') do + n = (n * 10.0f) + (*num++ - '0'); + while (*num >= '0' && *num <= '9'); /* Number? */ + if (*num == '.' && num[1] >= '0' && num[1] <= '9') { + num++; + do { + n = (n * 10.0f) + (*num++ - '0'); + scale--; + } while (*num >= '0' && *num <= '9'); + } /* Fractional part? */ + if (*num == 'e' || *num == 'E') /* Exponent? */ + { + num++; + if (*num == '+') + num++; + else if (*num == '-') { + signsubscale = -1; + num++; /* With sign? */ + } + while (*num >= '0' && *num <= '9') + subscale = (subscale * 10) + (*num++ - '0'); /* Number? */ + } + + n = sign * n + * pow(10.0f, + (scale + subscale * signsubscale)); /* number = +/- number.fraction + * 10^+/- exponent */ + + item->valuedouble = n; + item->valueint = (int)n; + item->type = cJSON_Number; + return num; +} + +/* Render the number nicely from the given item into a string. */ +static auto print_number(cJSON* item) -> char* { + char* str; + double d = item->valuedouble; + if (fabs(((double)item->valueint) - d) <= DBL_EPSILON && d <= INT_MAX + && d >= INT_MIN) { + str = (char*)cJSON_malloc(21); /* 2^64+1 can be represented in 21 chars. */ + if (str) sprintf(str, "%d", item->valueint); + } else { + str = (char*)cJSON_malloc(64); /* This is a nice tradeoff. */ + if (str) { + if (fabs(floor(d) - d) <= DBL_EPSILON && fabs(d) < 1.0e60) + sprintf(str, "%.0f", d); + else if (fabs(d) < 1.0e-6 || fabs(d) > 1.0e9) + sprintf(str, "%e", d); + else + sprintf(str, "%f", d); + } + } + return str; +} + +static auto parse_hex4(const char* str) -> unsigned { + unsigned h = 0; + if (*str >= '0' && *str <= '9') + h += (*str) - '0'; + else if (*str >= 'A' && *str <= 'F') + h += 10 + (*str) - 'A'; + else if (*str >= 'a' && *str <= 'f') + h += 10 + (*str) - 'a'; + else + return 0; + h = h << 4; + str++; + if (*str >= '0' && *str <= '9') + h += (*str) - '0'; + else if (*str >= 'A' && *str <= 'F') + h += 10 + (*str) - 'A'; + else if (*str >= 'a' && *str <= 'f') + h += 10 + (*str) - 'a'; + else + return 0; + h = h << 4; + str++; + if (*str >= '0' && *str <= '9') + h += (*str) - '0'; + else if (*str >= 'A' && *str <= 'F') + h += 10 + (*str) - 'A'; + else if (*str >= 'a' && *str <= 'f') + h += 10 + (*str) - 'a'; + else + return 0; + h = h << 4; + str++; + if (*str >= '0' && *str <= '9') + h += (*str) - '0'; + else if (*str >= 'A' && *str <= 'F') + h += 10 + (*str) - 'A'; + else if (*str >= 'a' && *str <= 'f') + h += 10 + (*str) - 'a'; + else + return 0; + return h; +} + +/* Parse the input text into an unescaped cstring, and populate item. */ +static const unsigned char firstByteMark[7] = {0x00, 0x00, 0xC0, 0xE0, + 0xF0, 0xF8, 0xFC}; +static auto parse_string(cJSON* item, const char* str) -> const char* { + const char* ptr = str + 1; + char* ptr2; + char* out; + size_t len = 0; + unsigned uc, uc2; + if (*str != '\"') { + ep = str; + return nullptr; + } /* not a string! */ + + while (*ptr != '\"' && *ptr && ++len) { + if (*ptr++ == '\\') { + ptr++; /* Skip escaped quotes. */ + } + } + + // This is how long we need for the string, roughly. + out = (char*)cJSON_malloc(len + 1); + if (!out) return nullptr; + + ptr = str + 1; + ptr2 = out; + while (*ptr != '\"' && *ptr) { + if (*ptr != '\\') { + *ptr2++ = *ptr++; + } else { + ptr++; + switch (*ptr) { + case 'b': + *ptr2++ = '\b'; + break; + case 'f': + *ptr2++ = '\f'; + break; + case 'n': + *ptr2++ = '\n'; + break; + case 'r': + *ptr2++ = '\r'; + break; + case 't': + *ptr2++ = '\t'; + break; + case 'u': /* transcode utf16 to utf8. */ + uc = parse_hex4(ptr + 1); + ptr += 4; /* get the unicode char. */ + + if ((uc >= 0xDC00 && uc <= 0xDFFF) || uc == 0) { + break; // check for invalid. + } + + // UTF16 surrogate pairs. + if (uc >= 0xD800 && uc <= 0xDBFF) { + if (ptr[1] != '\\' || ptr[2] != 'u') + break; /* missing second-half of surrogate. */ + uc2 = parse_hex4(ptr + 3); + ptr += 6; + if (uc2 < 0xDC00 || uc2 > 0xDFFF) + break; /* invalid second-half of surrogate. */ + uc = 0x10000 + (((uc & 0x3FF) << 10) | (uc2 & 0x3FF)); + } + + len = 4; + if (uc < 0x80) { + len = 1; + } else if (uc < 0x800) { + len = 2; + } else if (uc < 0x10000) { + len = 3; + } + ptr2 += len; + + switch (len) { + case 4: // NOLINT(bugprone-branch-clone) + *--ptr2 = static_cast((uc | 0x80) & 0xBF); + uc >>= 6; + case 3: + *--ptr2 = static_cast((uc | 0x80) & 0xBF); + uc >>= 6; + case 2: + *--ptr2 = static_cast((uc | 0x80) & 0xBF); + uc >>= 6; + case 1: + *--ptr2 = static_cast(uc | firstByteMark[len]); + default: + break; + } + ptr2 += len; + break; + default: + *ptr2++ = *ptr; + break; + } + ptr++; + } + } + *ptr2 = 0; + if (*ptr == '\"') { + ptr++; + } + item->valuestring = out; + item->type = cJSON_String; + return ptr; +} + +/* Render the cstring provided to an escaped version that can be printed. */ +static auto print_string_ptr(const char* str) -> char* { + const char* ptr; + char *ptr2, *out; + size_t len = 0; + unsigned char token; + + if (!str) { + return cJSON_strdup(""); + } + ptr = str; + while ((token = static_cast(*ptr)) && ++len) { + if (strchr("\"\\\b\f\n\r\t", token)) { + len++; + } else if (token < 32) { + len += 5; + } + ptr++; + } + + out = (char*)cJSON_malloc(len + 3); + if (!out) { + return nullptr; + } + + ptr2 = out; + ptr = str; + *ptr2++ = '\"'; + while (*ptr) { + if ((unsigned char)*ptr > 31 && *ptr != '\"' && *ptr != '\\') { + *ptr2++ = *ptr++; + } else { + *ptr2++ = '\\'; + switch (token = static_cast(*ptr++)) { + case '\\': + *ptr2++ = '\\'; + break; + case '\"': + *ptr2++ = '\"'; + break; + case '\b': + *ptr2++ = 'b'; + break; + case '\f': + *ptr2++ = 'f'; + break; + case '\n': + *ptr2++ = 'n'; + break; + case '\r': + *ptr2++ = 'r'; + break; + case '\t': + *ptr2++ = 't'; + break; + default: + sprintf(ptr2, "u%04x", token); + ptr2 += 5; + break; /* escape and print */ + } + } + } + *ptr2++ = '\"'; + *ptr2 = 0; + return out; +} +/* Invote print_string_ptr (which is useful) on an item. */ +static auto print_string(cJSON* item) -> char* { + return print_string_ptr(item->valuestring); +} + +/* Predeclare these prototypes. */ +static auto parse_value(cJSON* item, const char* value) -> const char*; +static auto print_value(cJSON* item, int depth, int fmt) -> char*; +static auto parse_array(cJSON* item, const char* value) -> const char*; +static auto print_array(cJSON* item, int depth, int fmt) -> char*; +static auto parse_object(cJSON* item, const char* value) -> const char*; +static auto print_object(cJSON* item, int depth, int fmt) -> char*; + +/* Utility to jump whitespace and cr/lf */ +static auto skip(const char* in) -> const char* { + while (in && *in && (unsigned char)*in <= 32) in++; + return in; +} + +/* Parse an object - create a new root, and populate. */ +auto cJSON_ParseWithOpts(const char* value, const char** return_parse_end, + int require_null_terminated) -> cJSON* { + cJSON* c = cJSON_New_Item(); + ep = nullptr; + if (!c) { + return nullptr; /* memory fail */ + } + + const char* end = parse_value(c, skip(value)); + if (!end) { + cJSON_Delete(c); + return nullptr; + } /* parse failure. ep is set. */ + + /* if we require null-terminated JSON without appended garbage, skip and then + * check for a null terminator */ + if (require_null_terminated) { + end = skip(end); + if (*end) { + cJSON_Delete(c); + ep = end; + return nullptr; + } + } + if (return_parse_end) *return_parse_end = end; + return c; +} +/* Default options for cJSON_Parse */ +auto cJSON_Parse(const char* value) -> cJSON* { + return cJSON_ParseWithOpts(value, nullptr, 0); +} + +/* Render a cJSON item/entity/structure to text. */ +auto cJSON_Print(cJSON* item) -> char* { return print_value(item, 0, 1); } +auto cJSON_PrintUnformatted(cJSON* item) -> char* { + return print_value(item, 0, 0); +} + +/* Parser core - when encountering text, process appropriately. */ +static auto parse_value(cJSON* item, const char* value) -> const char* { + if (!value) { + return nullptr; /* Fail on null. */ + } + if (!strncmp(value, "null", 4)) { + item->type = cJSON_NULL; + return value + 4; + } + if (!strncmp(value, "false", 5)) { + item->type = cJSON_False; + return value + 5; + } + if (!strncmp(value, "true", 4)) { + item->type = cJSON_True; + item->valueint = 1; + return value + 4; + } + if (*value == '\"') { + return parse_string(item, value); + } + if (*value == '-' || (*value >= '0' && *value <= '9')) { + return parse_number(item, value); + } + if (*value == '[') { + return parse_array(item, value); + } + if (*value == '{') { + return parse_object(item, value); + } + + ep = value; + return nullptr; /* failure. */ +} + +/* Render a value to text. */ +static auto print_value(cJSON* item, int depth, int fmt) -> char* { + char* out = nullptr; + if (!item) { + return nullptr; + } + switch ((item->type) & 255) { + case cJSON_NULL: + out = cJSON_strdup("null"); + break; + case cJSON_False: + out = cJSON_strdup("false"); + break; + case cJSON_True: + out = cJSON_strdup("true"); + break; + case cJSON_Number: + out = print_number(item); + break; + case cJSON_String: + out = print_string(item); + break; + case cJSON_Array: + out = print_array(item, depth, fmt); + break; + case cJSON_Object: + out = print_object(item, depth, fmt); + break; + default: + break; + } + return out; +} + +/* Build an array from input text. */ +static auto parse_array(cJSON* item, const char* value) -> const char* { + cJSON* child; + if (*value != '[') { + ep = value; + return nullptr; + } /* not an array! */ + + item->type = cJSON_Array; + value = skip(value + 1); + if (*value == ']') { + return value + 1; /* empty array. */ + } + + item->child = child = cJSON_New_Item(); + if (!item->child) { + return nullptr; /* memory fail */ + } + value = skip( + parse_value(child, skip(value))); /* skip any spacing, get the value. */ + if (!value) return nullptr; + + while (*value == ',') { + cJSON* new_item; + if (!(new_item = cJSON_New_Item())) { + return nullptr; /* memory fail */ + } + child->next = new_item; + new_item->prev = child; + child = new_item; + value = skip(parse_value(child, skip(value + 1))); + if (!value) { + return nullptr; /* memory fail */ + } + } + + if (*value == ']') { + return value + 1; /* end of array */ + } + ep = value; + return nullptr; /* malformed. */ +} + +/* Render an array to text */ +static auto print_array(cJSON* item, int depth, int fmt) -> char* { + char** entries; + char *out = nullptr, *ptr, *ret; + size_t len = 5; + cJSON* child = item->child; + int numentries = 0, i = 0, fail = 0; + + /* How many entries in the array? */ + while (child) { + numentries++; + child = child->next; + } + /* Explicitly handle numentries==0 */ + if (!numentries) { + out = (char*)cJSON_malloc(3); + if (out) { + strcpy(out, "[]"); // NOLINT + } + return out; + } + /* Allocate an array to hold the values for each */ + entries = (char**)cJSON_malloc(numentries * sizeof(char*)); + if (!entries) { + return nullptr; + } + memset(entries, 0, numentries * sizeof(char*)); + /* Retrieve all the results: */ + child = item->child; + while (child && !fail) { + ret = print_value(child, depth + 1, fmt); + entries[i++] = ret; + if (ret) + len += strlen(ret) + 2 + (fmt ? 1 : 0); + else + fail = 1; + child = child->next; + } + + /* If we didn't fail, try to malloc the output string */ + if (!fail) { + out = (char*)cJSON_malloc(len); + } + /* If that fails, we fail. */ + if (!out) { + fail = 1; + } + + /* Handle failure. */ + if (fail) { + for (i = 0; i < numentries; i++) + if (entries[i]) cJSON_free(entries[i]); + cJSON_free(entries); + return nullptr; + } + + /* Compose the output array. */ + *out = '['; + ptr = out + 1; + *ptr = 0; + for (i = 0; i < numentries; i++) { + strcpy(ptr, entries[i]); // NOLINT + ptr += strlen(entries[i]); + if (i != numentries - 1) { + *ptr++ = ','; + if (fmt) *ptr++ = ' '; + *ptr = 0; + } + cJSON_free(entries[i]); + } + cJSON_free(entries); + *ptr++ = ']'; + *ptr = 0; + return out; +} + +/* Build an object from the text. */ +static auto parse_object(cJSON* item, const char* value) -> const char* { + cJSON* child; + if (*value != '{') { + ep = value; + return nullptr; + } /* not an object! */ + + item->type = cJSON_Object; + value = skip(value + 1); + if (*value == '}') return value + 1; /* empty array. */ + + item->child = child = cJSON_New_Item(); + if (!item->child) return nullptr; + value = skip(parse_string(child, skip(value))); + if (!value) return nullptr; + child->string = child->valuestring; + child->valuestring = nullptr; + if (*value != ':') { + ep = value; + return nullptr; + } /* fail! */ + value = skip(parse_value( + child, skip(value + 1))); /* skip any spacing, get the value. */ + if (!value) return nullptr; + + while (*value == ',') { + cJSON* new_item; + if (!(new_item = cJSON_New_Item())) return nullptr; /* memory fail */ + child->next = new_item; + new_item->prev = child; + child = new_item; + value = skip(parse_string(child, skip(value + 1))); + if (!value) return nullptr; + child->string = child->valuestring; + child->valuestring = nullptr; + if (*value != ':') { + ep = value; + return nullptr; + } /* fail! */ + value = skip(parse_value( + child, skip(value + 1))); /* skip any spacing, get the value. */ + if (!value) return nullptr; + } + + if (*value == '}') return value + 1; /* end of array */ + ep = value; + return nullptr; /* malformed. */ +} + +/* Render an object to text. */ +static auto print_object(cJSON* item, int depth, int fmt) -> char* { + char *out = nullptr, *ptr, *ret, *str; + size_t len = 7; + int i = 0; + int j; + cJSON* child = item->child; + int numentries = 0, fail = 0; + /* Count the number of entries. */ + while (child) { + numentries++; + child = child->next; + } + // Explicitly handle empty object case. + if (!numentries) { + out = (char*)cJSON_malloc(static_cast(fmt ? depth + 4 : 3)); + if (!out) { + return nullptr; + } + ptr = out; + *ptr++ = '{'; + if (fmt) { + *ptr++ = '\n'; + for (i = 0; i < depth - 1; i++) *ptr++ = '\t'; + } + *ptr++ = '}'; + *ptr = 0; + return out; + } + + // Allocate space for the names and the objects. + char** entries = (char**)cJSON_malloc(numentries * sizeof(char*)); + if (!entries) return nullptr; + char** names = (char**)cJSON_malloc(numentries * sizeof(char*)); + if (!names) { + cJSON_free(entries); + return nullptr; + } + memset(entries, 0, sizeof(char*) * numentries); + memset(names, 0, sizeof(char*) * numentries); + + // Collect all the results into our arrays. + child = item->child; + depth++; + if (fmt) len += depth; + while (child) { + names[i] = str = print_string_ptr(child->string); + entries[i++] = ret = print_value(child, depth, fmt); + if (str && ret) + len += strlen(ret) + strlen(str) + 2 + (fmt ? 2 + depth : 0); + else + fail = 1; + child = child->next; + } + + // Try to allocate the output string. + if (!fail) out = (char*)cJSON_malloc(len); + if (!out) fail = 1; + + // Handle failure. + if (fail) { + for (i = 0; i < numentries; i++) { + if (names[i]) cJSON_free(names[i]); + if (entries[i]) cJSON_free(entries[i]); + } + cJSON_free(names); + cJSON_free(entries); + return nullptr; + } + + // Compose the output. + *out = '{'; + ptr = out + 1; + if (fmt) *ptr++ = '\n'; + *ptr = 0; + for (i = 0; i < numentries; i++) { + if (fmt) + for (j = 0; j < depth; j++) *ptr++ = '\t'; + strcpy(ptr, names[i]); // NOLINT + ptr += strlen(names[i]); + *ptr++ = ':'; + if (fmt) *ptr++ = '\t'; + strcpy(ptr, entries[i]); // NOLINT + ptr += strlen(entries[i]); + if (i != numentries - 1) *ptr++ = ','; + if (fmt) *ptr++ = '\n'; + *ptr = 0; + cJSON_free(names[i]); + cJSON_free(entries[i]); + } + + cJSON_free(names); + cJSON_free(entries); + if (fmt) + for (i = 0; i < depth - 1; i++) *ptr++ = '\t'; + *ptr++ = '}'; + *ptr = 0; + return out; +} + +// Get Array size/item / object item. +auto cJSON_GetArraySize(cJSON* array) -> int { + cJSON* c = array->child; + int i = 0; + while (c) { + i++; + c = c->next; + } + return i; +} +auto cJSON_GetArrayItem(cJSON* array, int item) -> cJSON* { + cJSON* c = array->child; + while (c && item > 0) { + item--; + c = c->next; + } + return c; +} +auto cJSON_GetObjectItem(cJSON* object, const char* string) -> cJSON* { + cJSON* c = object->child; + while (c && cJSON_strcasecmp(c->string, string)) c = c->next; + return c; +} + +// Utility for array list handling. +static void suffix_object(cJSON* prev, cJSON* item) { + prev->next = item; + item->prev = prev; +} +// Utility for handling references. +static auto create_reference(cJSON* item) -> cJSON* { + cJSON* ref = cJSON_New_Item(); + if (!ref) return nullptr; + memcpy(ref, item, sizeof(cJSON)); + ref->string = nullptr; + ref->type |= cJSON_IsReference; + ref->next = ref->prev = nullptr; + return ref; +} + +// Add item to array/object. +void cJSON_AddItemToArray(cJSON* array, cJSON* item) { + cJSON* c = array->child; + if (!item) return; + if (!c) { + array->child = item; + } else { + while (c && c->next) c = c->next; + suffix_object(c, item); + } +} +void cJSON_AddItemToObject(cJSON* object, const char* string, cJSON* item) { + if (!item) return; + if (item->string) cJSON_free(item->string); + item->string = cJSON_strdup(string); + cJSON_AddItemToArray(object, item); +} +void cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item) { + cJSON_AddItemToArray(array, create_reference(item)); +} +void cJSON_AddItemReferenceToObject(cJSON* object, const char* string, + cJSON* item) { + cJSON_AddItemToObject(object, string, create_reference(item)); +} + +auto cJSON_DetachItemFromArray(cJSON* array, int which) -> cJSON* { + cJSON* c = array->child; + while (c && which > 0) { + c = c->next; + which--; + } + if (!c) return nullptr; + if (c->prev) c->prev->next = c->next; + if (c->next) c->next->prev = c->prev; + if (c == array->child) array->child = c->next; + c->prev = c->next = nullptr; + return c; +} +void cJSON_DeleteItemFromArray(cJSON* array, int which) { + cJSON_Delete(cJSON_DetachItemFromArray(array, which)); +} +auto cJSON_DetachItemFromObject(cJSON* object, const char* string) -> cJSON* { + int i = 0; + cJSON* c = object->child; + while (c && cJSON_strcasecmp(c->string, string)) { + i++; + c = c->next; + } + if (c) return cJSON_DetachItemFromArray(object, i); + return nullptr; +} +void cJSON_DeleteItemFromObject(cJSON* object, const char* string) { + cJSON_Delete(cJSON_DetachItemFromObject(object, string)); +} + +// Replace array/object items with new ones. +void cJSON_ReplaceItemInArray(cJSON* array, int which, cJSON* newitem) { + cJSON* c = array->child; + while (c && which > 0) { + c = c->next; + which--; + } + if (!c) return; + newitem->next = c->next; + newitem->prev = c->prev; + if (newitem->next) newitem->next->prev = newitem; + if (c == array->child) + array->child = newitem; + else + newitem->prev->next = newitem; + c->next = c->prev = nullptr; + cJSON_Delete(c); +} +void cJSON_ReplaceItemInObject(cJSON* object, const char* string, + cJSON* newitem) { + int i = 0; + cJSON* c = object->child; + while (c && cJSON_strcasecmp(c->string, string)) { + i++; + c = c->next; + } + if (c) { + newitem->string = cJSON_strdup(string); + cJSON_ReplaceItemInArray(object, i, newitem); + } +} + +// Create basic types. +auto cJSON_CreateNull() -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) item->type = cJSON_NULL; + return item; +} +auto cJSON_CreateTrue() -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) item->type = cJSON_True; + return item; +} +auto cJSON_CreateFalse() -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) item->type = cJSON_False; + return item; +} +auto cJSON_CreateBool(int b) -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) item->type = b ? cJSON_True : cJSON_False; + return item; +} +auto cJSON_CreateNumber(double num) -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) { + item->type = cJSON_Number; + item->valuedouble = num; + item->valueint = (int)num; + } + return item; +} +auto cJSON_CreateString(const char* string) -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) { + item->type = cJSON_String; + item->valuestring = cJSON_strdup(string); + } + return item; +} +auto cJSON_CreateArray() -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) item->type = cJSON_Array; + return item; +} +auto cJSON_CreateObject() -> cJSON* { + cJSON* item = cJSON_New_Item(); + if (item) item->type = cJSON_Object; + return item; +} + +// Create Arrays. +auto cJSON_CreateIntArray(const int* numbers, int count) -> cJSON* { + int i; + cJSON *n, *p = nullptr, *a = cJSON_CreateArray(); + for (i = 0; a && i < count; i++) { + n = cJSON_CreateNumber(numbers[i]); + if (!i) + a->child = n; + else + suffix_object(p, n); + p = n; + } + return a; +} +auto cJSON_CreateFloatArray(const float* numbers, int count) -> cJSON* { + int i; + cJSON *n, *p = nullptr, *a = cJSON_CreateArray(); + for (i = 0; a && i < count; i++) { + n = cJSON_CreateNumber(numbers[i]); + if (!i) + a->child = n; + else + suffix_object(p, n); + p = n; + } + return a; +} +auto cJSON_CreateDoubleArray(const double* numbers, int count) -> cJSON* { + int i; + cJSON *n, *p = nullptr, *a = cJSON_CreateArray(); + for (i = 0; a && i < count; i++) { + n = cJSON_CreateNumber(numbers[i]); + if (!i) + a->child = n; + else + suffix_object(p, n); + p = n; + } + return a; +} +auto cJSON_CreateStringArray(const char** strings, int count) -> cJSON* { + int i; + cJSON *n, *p = nullptr, *a = cJSON_CreateArray(); + for (i = 0; a && i < count; i++) { + n = cJSON_CreateString(strings[i]); + if (!i) + a->child = n; + else + suffix_object(p, n); + p = n; + } + return a; +} + +// Duplication. +auto cJSON_Duplicate(cJSON* item, int recurse) -> cJSON* { + cJSON *newitem, *cptr, *nptr = nullptr, *newchild; + /* Bail on bad ptr */ + if (!item) return nullptr; + /* Create new item */ + newitem = cJSON_New_Item(); + if (!newitem) return nullptr; + /* Copy over all vars */ + newitem->type = item->type & (~cJSON_IsReference); + newitem->valueint = item->valueint; + newitem->valuedouble = item->valuedouble; + if (item->valuestring) { + newitem->valuestring = cJSON_strdup(item->valuestring); + if (!newitem->valuestring) { + cJSON_Delete(newitem); + return nullptr; + } + } + if (item->string) { + newitem->string = cJSON_strdup(item->string); + if (!newitem->string) { + cJSON_Delete(newitem); + return nullptr; + } + } + /* If non-recursive, then we're done! */ + if (!recurse) return newitem; + /* Walk the ->next chain for the child. */ + cptr = item->child; + while (cptr) { + newchild = cJSON_Duplicate( + cptr, 1); /* Duplicate (with recurse) each item in the ->next chain */ + if (!newchild) { + cJSON_Delete(newitem); + return nullptr; + } + if (nptr) { + nptr->next = newchild; + newchild->prev = nptr; + nptr = newchild; + } /* If newitem->child already set, then crosswire ->prev and ->next and + move on */ + else { + newitem->child = newchild; + nptr = newchild; + } /* Set newitem->child and move to it */ + cptr = cptr->next; + } + return newitem; +} + +void cJSON_Minify(char* json) { + char* into = json; + while (*json) { + if (*json == ' ') + json++; // NOLINT(bugprone-branch-clone) + else if (*json == '\t') + json++; // Whitespace characters. + else if (*json == '\r') + json++; + else if (*json == '\n') + json++; + else if (*json == '/' && json[1] == '/') + while (*json && *json != '\n') + json++; // double-slash comments, to end of line. + else if (*json == '/' && json[1] == '*') { + while (*json && !(*json == '*' && json[1] == '/')) json++; + json += 2; + } // multiline comments. + else if (*json == '\"') { + *into++ = *json++; + while (*json && *json != '\"') { + if (*json == '\\') *into++ = *json++; + *into++ = *json++; + } + *into++ = *json++; + } // string literals, which are \" sensitive. + else { + *into++ = *json++; // All other characters. + } + } + *into = 0; // and null-terminate. +} + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/generic/json.h b/src/ballistica/generic/json.h new file mode 100644 index 00000000..7577f178 --- /dev/null +++ b/src/ballistica/generic/json.h @@ -0,0 +1,239 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_JSON_H_ +#define BALLISTICA_GENERIC_JSON_H_ + +/* + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include "ballistica/ballistica.h" + +namespace ballistica { + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCUnusedMacroInspection" + +// #ifdef __cplusplus +// extern "C" { +// #endif + +/* cJSON Types: */ +#define cJSON_False 0u +#define cJSON_True 1u +#define cJSON_NULL 2u +#define cJSON_Number 3u +#define cJSON_String 4u +#define cJSON_Array 5u +#define cJSON_Object 6u + +#define cJSON_IsReference 256u + +/* The cJSON structure: */ +typedef struct cJSON { + struct cJSON *next, + *prev; /* next/prev allow you to walk array/object chains. Alternatively, + use GetArraySize/GetArrayItem/GetObjectItem */ + struct cJSON* + child; /* An array or object item will have a child pointer pointing to a + chain of the items in the array/object. */ + + uint32_t type; /* The type of the item, as above. */ + + char* valuestring; /* The item's string, if type==cJSON_String */ + int valueint; /* The item's number, if type==cJSON_Number */ + double valuedouble; /* The item's number, if type==cJSON_Number */ + + char* string; /* The item's name string, if this item is the child of, or is + in the list of subitems of an object. */ +} cJSON; + +typedef struct cJSON_Hooks { + void* (*malloc_fn)(size_t sz); + void (*free_fn)(void* ptr); +} cJSON_Hooks; + +/* Supply malloc, realloc and free functions to cJSON */ +extern void cJSON_InitHooks(cJSON_Hooks* hooks); + +/* Supply a block of JSON, and this returns a cJSON object you can interrogate. + * Call cJSON_Delete when finished. */ +extern auto cJSON_Parse(const char* value) -> cJSON*; +/* Render a cJSON entity to text for transfer/storage. Free the char* when + * finished. */ +extern auto cJSON_Print(cJSON* item) -> char*; +/* Render a cJSON entity to text for transfer/storage without any formatting. + * Free the char* when finished. */ +extern auto cJSON_PrintUnformatted(cJSON* item) -> char*; +/* Delete a cJSON entity and all subentities. */ +extern void cJSON_Delete(cJSON* c); + +/* Returns the number of items in an array (or object). */ +extern auto cJSON_GetArraySize(cJSON* array) -> int; +/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. + */ +extern auto cJSON_GetArrayItem(cJSON* array, int item) -> cJSON*; +/* Get item "string" from object. Case insensitive. */ +extern auto cJSON_GetObjectItem(cJSON* object, const char* string) -> cJSON*; + +/* For analysing failed parses. This returns a pointer to the parse error. + * You'll probably need to look a few chars back to make sense of it. Defined + * when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ +extern auto cJSON_GetErrorPtr() -> const char*; + +/* These calls create a cJSON item of the appropriate type. */ +extern auto cJSON_CreateNull() -> cJSON*; +extern auto cJSON_CreateTrue() -> cJSON*; +extern auto cJSON_CreateFalse() -> cJSON*; +extern auto cJSON_CreateBool(int b) -> cJSON*; +extern auto cJSON_CreateNumber(double num) -> cJSON*; +extern auto cJSON_CreateString(const char* string) -> cJSON*; +extern auto cJSON_CreateArray() -> cJSON*; +extern auto cJSON_CreateObject() -> cJSON*; + +/* These utilities create an Array of count items. */ +extern auto cJSON_CreateIntArray(const int* numbers, int count) -> cJSON*; +extern auto cJSON_CreateFloatArray(const float* numbers, int count) -> cJSON*; +extern auto cJSON_CreateDoubleArray(const double* numbers, int count) -> cJSON*; +extern auto cJSON_CreateStringArray(const char** strings, int count) -> cJSON*; + +/* Append item to the specified array/object. */ +extern void cJSON_AddItemToArray(cJSON* array, cJSON* item); +extern void cJSON_AddItemToObject(cJSON* object, const char* string, + cJSON* item); +/* Append reference to item to the specified array/object. Use this when you + * want to add an existing cJSON to a new cJSON, but don't want to corrupt your + * existing cJSON. */ +extern void cJSON_AddItemReferenceToArray(cJSON* array, cJSON* item); +extern void cJSON_AddItemReferenceToObject(cJSON* object, const char* string, + cJSON* item); + +/* Remove/Detach items from Arrays/Objects. */ +extern auto cJSON_DetachItemFromArray(cJSON* array, int which) -> cJSON*; +extern void cJSON_DeleteItemFromArray(cJSON* array, int which); +extern auto cJSON_DetachItemFromObject(cJSON* object, const char* string) + -> cJSON*; +extern void cJSON_DeleteItemFromObject(cJSON* object, const char* string); + +/* Update array items. */ +extern void cJSON_ReplaceItemInArray(cJSON* array, int which, cJSON* newitem); +extern void cJSON_ReplaceItemInObject(cJSON* object, const char* string, + cJSON* newitem); + +/* Duplicate a cJSON item */ +extern auto cJSON_Duplicate(cJSON* item, int recurse) -> cJSON*; +/* Duplicate will create a new, identical cJSON item to the one you pass, in new +memory that will need to be released. With recurse!=0, it will duplicate any +children connected to the item. The item->next and ->prev pointers are always +zero on return from Duplicate. */ + +/* ParseWithOpts allows you to require (and check) that the JSON is null + * terminated, and to retrieve the pointer to the final byte parsed. */ +extern auto cJSON_ParseWithOpts(const char* value, + const char** return_parse_end, + int require_null_terminated) -> cJSON*; + +extern void cJSON_Minify(char* json); + +/* Macros for creating things quickly. */ +#define cJSON_AddNullToObject(object, name) \ + cJSON_AddItemToObject(object, name, cJSON_CreateNull()) +#define cJSON_AddTrueToObject(object, name) \ + cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) +#define cJSON_AddFalseToObject(object, name) \ + cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) +#define cJSON_AddBoolToObject(object, name, b) \ + cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) +#define cJSON_AddNumberToObject(object, name, n) \ + cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) +#define cJSON_AddStringToObject(object, name, s) \ + cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) + +/* When assigning an integer value, it needs to be propagated to valuedouble + * too. */ +#define cJSON_SetIntValue(object, val) \ + ((object) ? (object)->valueint = (object)->valuedouble = (val) : (val)) + +// ericf addition: c++ wrapper for this stuff. + +// NOTE: once added to a dict/list/etc, the underlying cJSON's +// lifecycle is dependent on its parent, not this object. +// ..So be sure to keep the root JsonObject alive as long as child +// objects are being accessed. +class JsonObject { + public: + ~JsonObject() { + if (obj_ && root_) { + cJSON_Delete(obj_); + } + } + auto root() const -> bool { return root_; } + auto obj() const -> cJSON* { return obj_; } + + // Root objects will clean themselves up. + // turn this off when adding to a dict/list/etc. + // that will take responsibility for that instead. + void set_root(bool val) { root_ = val; } + + protected: + JsonObject() = default; + + // Used by subclasses to fill value. + void set_obj(cJSON* val) { + assert(obj_ == nullptr); + obj_ = val; + } + + private: + cJSON* obj_ = nullptr; + bool root_ = true; +}; + +class JsonDict : public JsonObject { + public: + JsonDict() { set_obj(cJSON_CreateObject()); } + void AddNumber(const std::string& name, double val) { + cJSON_AddItemToObject(obj(), name.c_str(), cJSON_CreateNumber(val)); + } + void AddString(const std::string& name, const std::string& val) { + cJSON_AddItemToObject(obj(), name.c_str(), cJSON_CreateString(val.c_str())); + } + auto PrintUnformatted() -> std::string { + return cJSON_PrintUnformatted(obj()); + } +}; + +// class JsonNumber : public JsonObject { +// public: +// JsonNumber(double val) { set_obj(cJSON_CreateNumber(val)); } +// }; + +// class JsonString : public JsonObject { +// public: +// JsonString(const std::string& s) { set_obj(cJSON_CreateString(s.c_str())); +// } JsonString(const char* s) { set_obj(cJSON_CreateString(s)); } +// }; + +#pragma clang diagnostic pop + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_JSON_H_ diff --git a/src/ballistica/generic/lambda_runnable.h b/src/ballistica/generic/lambda_runnable.h new file mode 100644 index 00000000..c89ed72d --- /dev/null +++ b/src/ballistica/generic/lambda_runnable.h @@ -0,0 +1,38 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_LAMBDA_RUNNABLE_H_ +#define BALLISTICA_GENERIC_LAMBDA_RUNNABLE_H_ + +#include "ballistica/generic/runnable.h" + +namespace ballistica { + +// (don't use this class directly; call NewLambdaRunnable below) +// from what I hear, heavy use of std::function can slow +// compiles down dramatically, so sticking to raw lambdas here +template +class LambdaRunnable : public Runnable { + public: + explicit LambdaRunnable(F lambda) : lambda_(lambda) {} + void Run() override { lambda_(); } + + private: + F lambda_; +}; + +// Call this to allocate and return a raw lambda runnable +template +auto NewLambdaRunnable(const F& lambda) -> Object::Ref { + return Object::New>(lambda); +} + +// Same but returns the raw pointer instead of a ref; +// (used when passing across threads). +template +auto NewLambdaRunnableRaw(const F& lambda) -> Runnable* { + return Object::NewDeferred>(lambda); +} + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_LAMBDA_RUNNABLE_H_ diff --git a/src/ballistica/generic/real_timer.h b/src/ballistica/generic/real_timer.h new file mode 100644 index 00000000..8e324221 --- /dev/null +++ b/src/ballistica/generic/real_timer.h @@ -0,0 +1,49 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_REAL_TIMER_H_ +#define BALLISTICA_GENERIC_REAL_TIMER_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/runnable.h" + +namespace ballistica { + +// Manages a timer which runs on real time and calls a +// 'HandleRealTimerExpired' method on the provided pointer. +template +class RealTimer : public Object { + public: + RealTimer(millisecs_t length, bool repeat, T* delegate) { + assert(g_game); + assert(InGameThread()); + timer_id_ = g_game->NewRealTimer( + length, repeat, Object::New(delegate, this)); + } + void SetLength(uint32_t length) { + assert(InGameThread()); + g_game->SetRealTimerLength(timer_id_, length); + } + ~RealTimer() override { + assert(InGameThread()); + g_game->DeleteRealTimer(timer_id_); + } + + private: + class Callback : public Runnable { + public: + Callback(T* delegate, RealTimer* timer) + : delegate_(delegate), timer_(timer) {} + void Run() override { delegate_->HandleRealTimerExpired(timer_); } + + private: + RealTimer* timer_; + T* delegate_; + }; + int timer_id_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_REAL_TIMER_H_ diff --git a/src/ballistica/generic/runnable.cc b/src/ballistica/generic/runnable.cc new file mode 100644 index 00000000..108a3275 --- /dev/null +++ b/src/ballistica/generic/runnable.cc @@ -0,0 +1,11 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/generic/runnable.h" + +namespace ballistica { + +auto Runnable::GetThreadOwnership() const -> Object::ThreadOwnership { + return ThreadOwnership::kNextReferencing; +} + +} // namespace ballistica diff --git a/src/ballistica/generic/runnable.h b/src/ballistica/generic/runnable.h new file mode 100644 index 00000000..0d600fba --- /dev/null +++ b/src/ballistica/generic/runnable.h @@ -0,0 +1,23 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_RUNNABLE_H_ +#define BALLISTICA_GENERIC_RUNNABLE_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +class Runnable : public Object { + public: + virtual void Run() = 0; + + // these are used on lots of threads; lets + // lock to wherever we're first referenced + auto GetThreadOwnership() const -> ThreadOwnership override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_RUNNABLE_H_ diff --git a/src/ballistica/generic/timer.cc b/src/ballistica/generic/timer.cc new file mode 100644 index 00000000..a45e40c2 --- /dev/null +++ b/src/ballistica/generic/timer.cc @@ -0,0 +1,55 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/generic/timer.h" + +#include "ballistica/generic/timer_list.h" + +namespace ballistica { + +Timer::Timer(TimerList* list_in, int id_in, TimerMedium current_time, + TimerMedium length_in, TimerMedium offset_in, int repeat_count_in) + : list_(list_in), + on_list_(false), + initial_(true), + dead_(false), + list_died_(false), + last_run_time_(current_time), + expire_time_(current_time + offset_in), + id_(id_in), + length_(length_in), + repeat_count_(repeat_count_in) { + list_->timer_count_total_++; +} + +Timer::~Timer() { + // If the list is dead, dont touch the corpse. + if (!list_died_) { + if (on_list_) { + list_->PullTimer(id_); + } else { + // Should never be explicitly deleting the current client timer + // (it should just get marked as dead so the loop can kill it when + // re-submitted). + assert(list_->client_timer_ != this); + } + list_->timer_count_total_--; + } +} + +void Timer::SetLength(TimerMedium l, bool set_start_time, + TimerMedium starttime) { + if (on_list_) { + assert(id_ != 0); // zero denotes "no-id" + Timer* t = list_->PullTimer(id_); + BA_PRECONDITION(t == this); + length_ = l; + if (set_start_time) last_run_time_ = starttime; + expire_time_ = last_run_time_ + length_; + list_->AddTimer(this); + } else { + length_ = l; + if (set_start_time) last_run_time_ = starttime; + } +} + +} // namespace ballistica diff --git a/src/ballistica/generic/timer.h b/src/ballistica/generic/timer.h new file mode 100644 index 00000000..9609286b --- /dev/null +++ b/src/ballistica/generic/timer.h @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_TIMER_H_ +#define BALLISTICA_GENERIC_TIMER_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" +#include "ballistica/generic/runnable.h" + +namespace ballistica { + +class Timer { + public: + auto id() const -> int { return id_; } + auto length() const -> TimerMedium { return length_; } + void SetLength(TimerMedium l, bool set_start_time = false, + TimerMedium starttime = 0); + + private: + Timer(TimerList* list_in, int id_in, TimerMedium current_time, + TimerMedium length_in, TimerMedium offset_in, int repeat_count_in); + virtual ~Timer(); + TimerList* list_{}; + bool on_list_{}; + Timer* next_{}; + bool initial_{}; + bool dead_{}; + bool list_died_{}; + TimerMedium last_run_time_{}; + TimerMedium expire_time_{}; + int id_{}; + TimerMedium length_{}; + int repeat_count_{}; + Object::Ref runnable_; + // FIXME: Shouldn't have friend classes in different files. + friend class TimerList; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_TIMER_H_ diff --git a/src/ballistica/generic/timer_list.cc b/src/ballistica/generic/timer_list.cc new file mode 100644 index 00000000..05143e00 --- /dev/null +++ b/src/ballistica/generic/timer_list.cc @@ -0,0 +1,271 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/generic/timer_list.h" + +#include "ballistica/generic/runnable.h" +#include "ballistica/generic/timer.h" + +namespace ballistica { + +TimerList::TimerList() = default; + +TimerList::~TimerList() { + Clear(); + + // Don't delete the client timer if one exists; just inform it that the list + // is dead. + if (client_timer_) { + client_timer_->list_died_ = true; + } + + if (g_buildconfig.debug_build()) { + if (timer_count_active_ != 0) { + Log("Error: Invalid timerlist state on teardown."); + } + if (timer_count_inactive_ != 0) { + Log("Error: Invalid timerlist state on teardown."); + } + if (!((timer_count_total_ == 0) + || (client_timer_ != nullptr && timer_count_total_ == 1))) { + Log("Error: Invalid timerlist state on teardown."); + } + } +} + +void TimerList::Clear() { + assert(!are_clearing_); + are_clearing_ = true; + while (timers_) { + Timer* t = timers_; + t->on_list_ = false; + timer_count_active_--; + timers_ = t->next_; + delete t; + } + while (timers_inactive_) { + Timer* t = timers_inactive_; + t->on_list_ = false; + timer_count_inactive_--; + timers_inactive_ = t->next_; + delete t; + } + are_clearing_ = false; +} + +// Pull a timer out of the list. +auto TimerList::PullTimer(int timer_id, bool remove) -> Timer* { + Timer* t = timers_; + Timer* p = nullptr; + while (t) { + if (t->id_ == timer_id) { + if (remove) { + if (p) { + p->next_ = t->next_; + } else { + timers_ = t->next_; + } + t->on_list_ = false; + timer_count_active_--; + } + return t; + } + p = t; + t = t->next_; + } + + // Didn't find it. check the inactive list. + t = timers_inactive_; + p = nullptr; + while (t) { + if (t->id_ == timer_id) { + if (remove) { + if (p) { + p->next_ = t->next_; + } else { + timers_inactive_ = t->next_; + } + t->on_list_ = false; + timer_count_inactive_--; + } + return t; + } + p = t; + t = t->next_; + } + + // Not on either list; only other possibility is the current client timer. + if (client_timer_ && client_timer_->id_ == timer_id) { + return client_timer_; + } + return nullptr; +} + +void TimerList::Run(TimerMedium target_time) { + assert(!are_clearing_); + + // Limit our runs to whats initially on the list so we don't spin all day if + // a timer resets itself to run immediately. + // FIXME - what if this timer kills one or more of the initially-expired ones + // ..that means it could potentially run more than once.. does it matter? + int expired_count = GetExpiredCount(target_time); + for (int timers_to_run = expired_count; timers_to_run > 0; timers_to_run--) { + Timer* t = GetExpiredTimer(target_time); + if (t) { + assert(!t->dead_); + try { + t->runnable_->Run(); + } catch (const std::exception&) { + // If something went wrong, put our list back in order and propagate. + if (t->list_died_) { + delete t; // nothing is left but this timer + } else { + SubmitTimer(t); + } + throw; + } + // If this timer killed the list, stop; otherwise put it back and keep on + // trucking. + if (t->list_died_) { + delete t; // nothing is left but this timer + return; + } else { + SubmitTimer(t); + } + } + } +} +auto TimerList::GetExpiredCount(TimerMedium target_time) -> int { + assert(!are_clearing_); + + Timer* t = timers_; + int count = 0; + while (t && t->expire_time_ <= target_time) { + count++; + t = t->next_; + } + return count; +} + +// Returns the next expired timer. When done with the timer, +// return it to the list with Timer::submit() +// (this will either put it back in line or delete it) +auto TimerList::GetExpiredTimer(TimerMedium target_time) -> Timer* { + assert(!are_clearing_); + + Timer* t; + if (timers_ != nullptr && timers_->expire_time_ <= target_time) { + t = timers_; + t->last_run_time_ = target_time; + timers_ = timers_->next_; + timer_count_active_--; + t->on_list_ = false; + + // Exactly one timer at a time can be out in userland and not on + // any list - this is now that one. + assert(client_timer_ == nullptr); + client_timer_ = t; + return t; + } + return nullptr; +} + +auto TimerList::NewTimer(TimerMedium current_time, TimerMedium length, + TimerMedium offset, int repeat_count, + const Object::Ref& runnable) -> Timer* { + assert(!are_clearing_); + auto* t = new Timer(this, next_timer_id_++, current_time, length, offset, + repeat_count); + t->runnable_ = runnable; + t = SubmitTimer(t); + return t; +} + +auto TimerList::GetTimeToNextExpire(TimerMedium current_time) -> TimerMedium { + assert(!are_clearing_); + if (!timers_) { + return (TimerMedium)-1; + } + TimerMedium diff = timers_->expire_time_ - current_time; + return (diff < 0) ? 0 : diff; +} + +auto TimerList::GetTimer(int id) -> Timer* { + assert(!are_clearing_); + + assert(id != 0); // Zero denotes "no-id". + Timer* t = PullTimer(id, false); + return t->dead_ ? nullptr : t; +} + +void TimerList::DeleteTimer(int timer_id) { + assert(timer_id != 0); // zero denotes "no-id" + Timer* t = PullTimer(timer_id); + if (t) { + // If its the client timer, just mark it as dead, so the client can still + // resubmit it without crashing. + if (client_timer_ == t) { + t->dead_ = true; + } else { + // Not in the client domain; kill it now. + delete t; + } + } +} + +auto TimerList::SubmitTimer(Timer* t) -> Timer* { + assert(t->list_ == this); + assert(t->initial_ || t == client_timer_ || t->dead_); + + // Aside from initial timer submissions, only the one client timer should be + // coming thru here. + if (!t->initial_) { + assert(client_timer_ == t); + client_timer_ = nullptr; + } + + // If its a one-shot timer or is dead, kill it. + if ((t->repeat_count_ == 0 && !t->initial_) || t->dead_) { + delete t; + return nullptr; + } else { + // Its still alive. Shove it back in line and tell it to keep working. + if (!t->initial_ && t->repeat_count_ > 0) t->repeat_count_--; + t->initial_ = false; + + // No drift. + if (explicit_bool(false)) { + t->expire_time_ = t->expire_time_ + t->length_; + } else { + // Drift. + t->expire_time_ = t->last_run_time_ + t->length_; + } + AddTimer(t); + return t; + } +} + +void TimerList::AddTimer(Timer* t) { + assert(t && !t->on_list_); + + // If its set to never go off, throw it on the inactive list. + if (t->length_ == -1) { + t->next_ = timers_inactive_; + timers_inactive_ = t; + timer_count_inactive_++; + } else { + Timer** list = &timers_; + + // Go along till we find an expire time later than ourself. + while (*list != nullptr) { + if ((*list)->expire_time_ > t->expire_time_) break; + list = &((*list)->next_); + } + Timer* tmp = (*list); + (*list) = t; + t->next_ = tmp; + timer_count_active_++; + } + t->on_list_ = true; +} + +} // namespace ballistica diff --git a/src/ballistica/generic/timer_list.h b/src/ballistica/generic/timer_list.h new file mode 100644 index 00000000..daf5d7df --- /dev/null +++ b/src/ballistica/generic/timer_list.h @@ -0,0 +1,68 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_TIMER_LIST_H_ +#define BALLISTICA_GENERIC_TIMER_LIST_H_ + +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" + +namespace ballistica { + +class TimerList { + public: + TimerList(); + ~TimerList(); + + // Run timers up to the provided target time. + void Run(TimerMedium target_time); + + // Create a timer with provided runnable. + auto NewTimer(TimerMedium current_time, TimerMedium length, + TimerMedium offset, int repeat_count, + const Object::Ref& runnable) -> Timer*; + + // Return a timer by its id, or nullptr if the timer no longer exists. + auto GetTimer(int id) -> Timer*; + + // Delete a currently-queued timer via its id. + void DeleteTimer(int timer_id); + + // Return the time until the next timer goes off. + // If no timers are present, -1 is returned. + auto GetTimeToNextExpire(TimerMedium current_time) -> TimerMedium; + + // Return the active timer count. Note that this does not include the client + // timer (a timer returned via getExpiredTimer() but not yet re-submitted). + auto active_timer_count() const -> int { return timer_count_active_; } + + auto empty() -> bool { return (timers_ == nullptr); } + + void Clear(); + + private: + // Returns the next expired timer. When done with the timer, + // return it to the list with Timer::submit() + // (this will either put it back in line or delete it) + auto GetExpiredTimer(TimerMedium target_time) -> Timer*; + auto GetExpiredCount(TimerMedium target_time) -> int; + auto PullTimer(int timer_id, bool remove = true) -> Timer*; + auto SubmitTimer(Timer* t) -> Timer*; + void AddTimer(Timer* t); + int timer_count_active_ = 0; + int timer_count_inactive_ = 0; + int timer_count_total_ = 0; + Timer* client_timer_ = nullptr; + Timer* timers_ = nullptr; + Timer* timers_inactive_ = nullptr; + int next_timer_id_ = 1; + bool running_ = false; + bool are_clearing_ = false; + friend class Timer; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_TIMER_LIST_H_ diff --git a/src/ballistica/generic/utf8.cc b/src/ballistica/generic/utf8.cc new file mode 100644 index 00000000..ce668344 --- /dev/null +++ b/src/ballistica/generic/utf8.cc @@ -0,0 +1,449 @@ +// Copyright (c) 2011-2020 Eric Froemling +// Derived from code licensed as follows: + +/* + Basic UTF-8 manipulation routines + by Jeff Bezanson + placed in the public domain Fall 2005 + + This code is designed to provide the utilities you need to manipulate + UTF-8 as an internal string encoding. These functions do not perform the + error checking normally needed when handling UTF-8 data, so if you happen + to be from the Unicode Consortium you will want to flay me alive. + I do this because error checking can be performed at the boundaries (I/O), + with these routines reserved for higher performance on data known to be + valid. +*/ +#include "ballistica/generic/utf8.h" + +#include +#include +#include +#include +#if _WIN32 || _WIN64 +#include +#else +#include +#endif + +namespace ballistica { + +// Should tidy this up but don't want to risk breaking anything for now. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "bugprone-narrowing-conversions" + +static const uint32_t offsetsFromUTF8[6] = {0x00000000UL, 0x00003080UL, + 0x000E2080UL, 0x03C82080UL, + 0xFA082080UL, 0x82082080UL}; + +static const char trailingBytesForUTF8[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5}; + +/* returns length of next utf-8 sequence */ +auto u8_seqlen(const char* s) -> int { + return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1; +} + +/* conversions without error checking + only works for valid UTF-8, i.e. no 5- or 6-byte sequences + srcsz = source size in bytes, or -1 if 0-terminated + sz = dest size in # of wide characters + + returns # characters converted + dest will always be L'\0'-terminated, even if there isn't enough room + for all the characters. + if sz = srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space. +*/ +auto u8_toucs(uint32_t* dest, int sz, const char* src, int srcsz) -> int { + uint32_t ch; + const char* src_end = src + srcsz; + int nb; + int i = 0; + + while (i < sz - 1) { + nb = trailingBytesForUTF8[(unsigned char)*src]; // NOLINT(cert-str34-c) + if (srcsz == -1) { + if (*src == 0) goto done_toucs; + } else { + if (src + nb >= src_end) goto done_toucs; + } + ch = 0; + switch (nb) { + /* these fall through deliberately */ + case 3: // NOLINT(bugprone-branch-clone) + ch += (unsigned char)*src++; + ch <<= 6; + case 2: + ch += (unsigned char)*src++; + ch <<= 6; + case 1: + ch += (unsigned char)*src++; + ch <<= 6; + case 0: + ch += (unsigned char)*src++; + default: + break; + } + ch -= offsetsFromUTF8[nb]; + dest[i++] = ch; + } +done_toucs: + dest[i] = 0; + return i; +} + +/* srcsz = number of source characters, or -1 if 0-terminated + sz = size of dest buffer in bytes + + returns # characters converted + dest will only be '\0'-terminated if there is enough space. this is + for consistency; imagine there are 2 bytes of space left, but the next + character requires 3 bytes. in this case we could NUL-terminate, but in + general we can't when there's insufficient space. therefore this function + only NUL-terminates if all the characters fit, and there's space for + the NUL as well. + the destination string will never be bigger than the source string. +*/ +auto u8_toutf8(char* dest, int sz, const uint32_t* src, int srcsz) -> int { + uint32_t ch; + int i = 0; + char* dest_end = dest + sz; + + while (srcsz < 0 ? src[i] != 0 : i < srcsz) { + ch = src[i]; + if (ch < 0x80) { + if (dest >= dest_end) return i; + *dest++ = (char)ch; + } else if (ch < 0x800) { + if (dest >= dest_end - 1) return i; + *dest++ = static_cast((ch >> 6) | 0xC0); + *dest++ = static_cast((ch & 0x3F) | 0x80); + } else if (ch < 0x10000) { + if (dest >= dest_end - 2) return i; + *dest++ = static_cast((ch >> 12) | 0xE0); + *dest++ = static_cast(((ch >> 6) & 0x3F) | 0x80); + *dest++ = static_cast((ch & 0x3F) | 0x80); + } else if (ch < 0x110000) { + if (dest >= dest_end - 3) return i; + *dest++ = static_cast((ch >> 18) | 0xF0); + *dest++ = static_cast(((ch >> 12) & 0x3F) | 0x80); + *dest++ = static_cast(((ch >> 6) & 0x3F) | 0x80); + *dest++ = static_cast((ch & 0x3F) | 0x80); + } + i++; + } + if (dest < dest_end) *dest = '\0'; + return i; +} + +auto u8_wc_toutf8(char* dest, uint32_t ch) -> int { + if (ch < 0x80) { + dest[0] = (char)ch; + return 1; + } + if (ch < 0x800) { + dest[0] = static_cast((ch >> 6) | 0xC0); + dest[1] = static_cast((ch & 0x3F) | 0x80); + return 2; + } + if (ch < 0x10000) { + dest[0] = static_cast((ch >> 12) | 0xE0); + dest[1] = static_cast(((ch >> 6) & 0x3F) | 0x80); + dest[2] = static_cast((ch & 0x3F) | 0x80); + return 3; + } + if (ch < 0x110000) { + dest[0] = static_cast((ch >> 18) | 0xF0); + dest[1] = static_cast(((ch >> 12) & 0x3F) | 0x80); + dest[2] = static_cast(((ch >> 6) & 0x3F) | 0x80); + dest[3] = static_cast((ch & 0x3F) | 0x80); + return 4; + } + return 0; +} + +/* charnum => byte offset */ +auto u8_offset(const char* str, int charnum) -> int { + int offs = 0; + + while (charnum > 0 && str[offs]) { + (void)(isutf(str[++offs]) || isutf(str[++offs]) || isutf(str[++offs]) + || ++offs); + charnum--; + } + return offs; +} + +/* byte offset => charnum */ +auto u8_charnum(const char* s, int offset) -> int { + int charnum = 0, offs = 0; + + while (offs < offset && s[offs]) { + (void)(isutf(s[++offs]) || isutf(s[++offs]) || isutf(s[++offs]) || ++offs); + charnum++; + } + return charnum; +} + +/* number of characters */ +auto u8_strlen(const char* s) -> int { + int count = 0; + int i = 0; + while (u8_nextchar(s, &i) != 0) { + count++; + } + return count; +} + +auto u8_nextchar(const char* s, int* i) -> uint32_t { + uint32_t ch = 0; + size_t sz = 0; + + do { + ch <<= 6; + ch += (unsigned char)s[(*i)]; + sz++; + } while (s[*i] && (++(*i)) && !isutf(s[*i])); + ch -= offsetsFromUTF8[sz - 1]; + + return ch; +} + +void u8_inc(const char* s, int* i) { + (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || isutf(s[++(*i)]) || ++(*i)); +} + +void u8_dec(const char* s, int* i) { + (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i)); +} + +auto octal_digit(char c) -> int { return (c >= '0' && c <= '7'); } + +auto hex_digit(char c) -> int { + return ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') + || (c >= 'a' && c <= 'f')); +} + +/* assumes that src points to the character after a backslash + returns number of input characters processed */ +auto u8_read_escape_sequence(char* str, uint32_t* dest) -> int { + uint32_t ch; + char digs[9] = "\0\0\0\0\0\0\0\0"; + int dno = 0, i = 1; + + ch = (uint32_t)str[0]; /* take literal character */ // NOLINT(cert-str34-c) + if (str[0] == 'n') + ch = L'\n'; + else if (str[0] == 't') + ch = L'\t'; + else if (str[0] == 'r') + ch = L'\r'; + else if (str[0] == 'b') + ch = L'\b'; + else if (str[0] == 'f') + ch = L'\f'; + else if (str[0] == 'v') + ch = L'\v'; + else if (str[0] == 'a') + ch = L'\a'; + else if (octal_digit(str[0])) { + i = 0; + do { + digs[dno++] = str[i++]; + } while (octal_digit(str[i]) && dno < 3); + ch = static_cast(strtol(digs, nullptr, 8)); + } else if (str[0] == 'x') { + while (hex_digit(str[i]) && dno < 2) { + digs[dno++] = str[i++]; + } + if (dno > 0) ch = static_cast(strtol(digs, nullptr, 16)); + } else if (str[0] == 'u') { + while (hex_digit(str[i]) && dno < 4) { + digs[dno++] = str[i++]; + } + if (dno > 0) ch = static_cast(strtol(digs, nullptr, 16)); + } else if (str[0] == 'U') { + while (hex_digit(str[i]) && dno < 8) { + digs[dno++] = str[i++]; + } + if (dno > 0) ch = static_cast(strtol(digs, nullptr, 16)); + } + *dest = ch; + + return i; +} + +/* convert a string with literal \uxxxx or \Uxxxxxxxx characters to UTF-8 + example: u8_unescape(mybuf, 256, "hello\\u220e") + note the double backslash is needed if called on a C string literal */ +auto u8_unescape(char* buf, int sz, char* src) -> int { + int c = 0, amt; + uint32_t ch; + char temp[4]; + + while (*src && c < sz) { + if (*src == '\\') { + src++; + amt = u8_read_escape_sequence(src, &ch); + } else { + ch = (uint32_t)*src; // NOLINT(cert-str34-c) + amt = 1; + } + src += amt; + amt = u8_wc_toutf8(temp, ch); + if (amt > sz - c) break; + memcpy(&buf[c], temp, static_cast(amt)); + c += amt; + } + if (c < sz) buf[c] = '\0'; + return c; +} + +auto u8_escape_wchar(char* buf, int sz, uint32_t ch) -> int { + if (ch == L'\n') + return snprintf(buf, static_cast(sz), "\\n"); + else if (ch == L'\t') + return snprintf(buf, static_cast(sz), "\\t"); + else if (ch == L'\r') + return snprintf(buf, static_cast(sz), "\\r"); + else if (ch == L'\b') + return snprintf(buf, static_cast(sz), "\\b"); + else if (ch == L'\f') + return snprintf(buf, static_cast(sz), "\\f"); + else if (ch == L'\v') + return snprintf(buf, static_cast(sz), "\\v"); + else if (ch == L'\a') + return snprintf(buf, static_cast(sz), "\\a"); + else if (ch == L'\\') + return snprintf(buf, static_cast(sz), "\\\\"); + else if (ch < 32 || ch == 0x7f) + return snprintf(buf, static_cast(sz), "\\x%hhX", (unsigned char)ch); + else if (ch > 0xFFFF) + return snprintf(buf, static_cast(sz), "\\U%.8X", (uint32_t)ch); + else if (ch >= 0x80 && ch <= 0xFFFF) + return snprintf(buf, static_cast(sz), "\\u%.4hX", + (unsigned short)ch); + + return snprintf(buf, static_cast(sz), "%c", (char)ch); +} + +auto u8_escape(char* buf, int sz, char* src, int escape_quotes) -> int { + int c = 0, i = 0, amt; + + while (src[i] && c < sz) { + if (escape_quotes && src[i] == '"') { + amt = snprintf(buf, static_cast(sz - c), "\\\""); + i++; + } else { + amt = u8_escape_wchar(buf, sz - c, u8_nextchar(src, &i)); + } + c += amt; + buf += amt; + } + if (c < sz) *buf = '\0'; + return c; +} + +auto u8_strchr(char* s, uint32_t ch, int* charn) -> char* { + int i = 0, lasti = 0; + uint32_t c; + + *charn = 0; + while (s[i]) { + c = u8_nextchar(s, &i); + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return nullptr; +} + +auto u8_memchr(char* s, uint32_t ch, size_t sz, int* charn) -> char* { + size_t i = 0, lasti = 0; + uint32_t c; + int csz; + + *charn = 0; + while (i < sz) { + c = static_cast(csz = 0); + do { + c <<= 6; + c += (unsigned char)s[i++]; + csz++; + } while (i < sz && !isutf(s[i])); + c -= offsetsFromUTF8[csz - 1]; + + if (c == ch) { + return &s[lasti]; + } + lasti = i; + (*charn)++; + } + return nullptr; +} + +auto u8_is_locale_utf8(const char* locale) -> int { + /* this code based on libutf8 */ + const char* cp = locale; + + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) { + if (*cp == '.') { + const char* encoding = ++cp; + for (; *cp != '\0' && *cp != '@' && *cp != '+' && *cp != ','; cp++) + ; + if ((cp - encoding == 5 && !strncmp(encoding, "UTF-8", 5)) + || (cp - encoding == 4 && !strncmp(encoding, "utf8", 4))) + return 1; /* it's UTF-8 */ + break; + } + } + return 0; +} + +auto u8_vprintf(char* fmt, va_list ap) -> int { + char* buf; + uint32_t* wcs; + + int sz{512}; + buf = (char*)alloca(sz); +try_print: + int cnt = vsnprintf(buf, static_cast(sz), fmt, ap); + if (cnt >= sz) { + buf = (char*)alloca(cnt - sz + 1); + sz = cnt + 1; + goto try_print; + } + wcs = (uint32_t*)alloca((cnt + 1) * sizeof(uint32_t)); + cnt = u8_toucs(wcs, cnt + 1, buf, cnt); + printf("%ls", (wchar_t*)wcs); + return cnt; +} + +auto u8_printf(char* fmt, ...) -> int { + int cnt; + va_list args; + + va_start(args, fmt); + + cnt = u8_vprintf(fmt, args); + + va_end(args); + return cnt; +} + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/generic/utf8.h b/src/ballistica/generic/utf8.h new file mode 100644 index 00000000..1d7a46ed --- /dev/null +++ b/src/ballistica/generic/utf8.h @@ -0,0 +1,85 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_UTF8_H_ +#define BALLISTICA_GENERIC_UTF8_H_ + +#include + +#include "ballistica/ballistica.h" + +// ericf note: i think this is cutef8?... +namespace ballistica { + +/* is c the start of a utf8 sequence? */ +#define isutf(c) (((c)&0xC0) != 0x80) + +/* convert UTF-8 data to wide character */ +auto u8_toucs(uint32_t* dest, int sz, const char* src, int srcsz) -> int; + +/* the opposite conversion */ +auto u8_toutf8(char* dest, int sz, const uint32_t* src, int srcsz) -> int; + +/* single character to UTF-8 */ +auto u8_wc_toutf8(char* dest, uint32_t ch) -> int; + +/* character number to byte offset */ +auto u8_offset(const char* str, int charnum) -> int; + +/* byte offset to character number */ +auto u8_charnum(const char* s, int offset) -> int; + +/* return next character, updating an index variable */ +auto u8_nextchar(const char* s, int* i) -> uint32_t; + +/* move to next character */ +void u8_inc(const char* s, int* i); + +/* move to previous character */ +void u8_dec(const char* s, int* i); + +/* returns length of next utf-8 sequence */ +auto u8_seqlen(const char* s) -> int; + +/* assuming src points to the character after a backslash, read an + escape sequence, storing the result in dest and returning the number of + input characters processed */ +auto u8_read_escape_sequence(char* src, uint32_t* dest) -> int; + +/* given a wide character, convert it to an ASCII escape sequence stored in + buf, where buf is "sz" bytes. returns the number of characters output. */ +auto u8_escape_wchar(char* buf, int sz, uint32_t ch) -> int; + +/* convert a string "src" containing escape sequences to UTF-8 */ +auto u8_unescape(char* buf, int sz, char* src) -> int; + +/* convert UTF-8 "src" to ASCII with escape sequences. + if escape_quotes is nonzero, quote characters will be preceded by + backslashes as well. */ +auto u8_escape(char* buf, int sz, char* src, int escape_quotes) -> int; + +/* utility predicates used by the above */ +auto octal_digit(char c) -> int; +auto hex_digit(char c) -> int; + +/* return a pointer to the first occurrence of ch in s, or NULL if not + found. character index of found character returned in *charn. */ +auto u8_strchr(char* s, uint32_t ch, int* charn) -> char*; + +/* same as the above, but searches a buffer of a given size instead of + a NUL-terminated string. */ +auto u8_memchr(char* s, uint32_t ch, size_t sz, int* charn) -> char*; + +/* count the number of characters in a UTF-8 string */ +auto u8_strlen(const char* s) -> int; + +auto u8_is_locale_utf8(const char* locale) -> int; + +/* printf where the format string and arguments may be in UTF-8. + you can avoid this function and just use ordinary printf() if the current + locale is UTF-8. */ +auto u8_vprintf(char* fmt, va_list ap) -> int; +auto u8_printf(char* fmt, ...) -> int; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_UTF8_H_ diff --git a/src/ballistica/generic/utils.cc b/src/ballistica/generic/utils.cc new file mode 100644 index 00000000..fbe93847 --- /dev/null +++ b/src/ballistica/generic/utils.cc @@ -0,0 +1,639 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/generic/utils.h" + +#include +#include +#include +#include +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/generic/base64.h" +#include "ballistica/generic/huffman.h" +#include "ballistica/generic/json.h" +#include "ballistica/generic/utf8.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/platform/platform.h" +#include "ballistica/scene/scene.h" + +// FIXME: Cleaner to add the lib to the project(s) instead? +#if BA_OSTYPE_WINDOWS +#pragma comment(lib, "Ws2_32.lib") +#endif + +namespace ballistica { + +#define USE_BAKED_RANDS 1 + +#if BA_OSTYPE_WINDOWS +#endif + +#if USE_BAKED_RANDS +float Utils::precalc_rands_1[kPrecalcRandsCount] = { + 0.00424972f, 0.0470216f, 0.545227f, 0.538243f, 0.214183f, 0.627205f, + 0.194698f, 0.917583f, 0.468622f, 0.0779965f, 0.304211f, 0.773231f, + 0.522742f, 0.378898f, 0.404598f, 0.468434f, 0.081512f, 0.408348f, + 0.0808838f, 0.427364f, 0.226629f, 0.234887f, 0.516467f, 0.0457478f, + 0.455418f, 0.194083f, 0.502244f, 0.0733989f, 0.458193f, 0.898715f, + 0.624819f, 0.70762f, 0.759858f, 0.559276f, 0.956318f, 0.408562f, + 0.206264f, 0.322909f, 0.293165f, 0.524073f, 0.407753f, 0.961242f, + 0.278234f, 0.423968f, 0.631937f, 0.534858f, 0.842336f, 0.786993f, + 0.934668f, 0.739984f, 0.968577f, 0.468159f, 0.804702f, 0.0686368f, + 0.397594f, 0.60871f, 0.485322f, 0.907066f, 0.587516f, 0.364387f, + 0.791611f, 0.899199f, 0.0186556f, 0.446891f, 0.0138f, 0.999024f, + 0.556364f, 0.29821f, 0.23943f, 0.338024f, 0.157135f, 0.25299f, + 0.791138f, 0.367175f, 0.584245f, 0.496136f, 0.358228f, 0.280143f, + 0.538658f, 0.190721f, 0.656737f, 0.010905f, 0.520343f, 0.678249f, + 0.930145f, 0.823978f, 0.457201f, 0.988418f, 0.854635f, 0.955912f, + 0.0226999f, 0.183605f, 0.838141f, 0.210646f, 0.160344f, 0.111269f, + 0.348488f, 0.648031f, 0.844362f, 0.65157f, 0.0598469f, 0.952439f, + 0.265193f, 0.768256f, 0.773861f, 0.723251f, 0.53157f, 0.36183f, + 0.485393f, 0.348683f, 0.551617f, 0.648207f, 0.656125f, 0.879799f, + 0.0674501f, 0.000782927f, 0.607129f, 0.116035f, 0.67095f, 0.692934f, + 0.276618f, 0.137535f, 0.771033f, 0.278625f, 0.686023f, 0.873823f, + 0.254666f, 0.75378f}; +float Utils::precalc_rands_2[kPrecalcRandsCount] = { + 0.425019f, 0.29261f, 0.623541f, 0.241628f, 0.772656f, 0.434116f, + 0.295335f, 0.814317f, 0.122326f, 0.887651f, 0.873536f, 0.692463f, + 0.730894f, 0.142115f, 0.0722184f, 0.977652f, 0.971393f, 0.111517f, + 0.41341f, 0.699999f, 0.955932f, 0.746667f, 0.267962f, 0.883952f, + 0.202871f, 0.952115f, 0.221069f, 0.616162f, 0.842076f, 0.705628f, + 0.332754f, 0.974675f, 0.940277f, 0.756059f, 0.831943f, 0.70631f, + 0.674705f, 0.13903f, 0.22751f, 0.0875125f, 0.101364f, 0.593826f, + 0.271567f, 0.63593f, 0.970994f, 0.359381f, 0.147583f, 0.987353f, + 0.960315f, 0.904639f, 0.874661f, 0.352573f, 0.630782f, 0.578075f, + 0.364932f, 0.588095f, 0.799978f, 0.0502811f, 0.379093f, 0.252171f, + 0.598992f, 0.843808f, 0.544584f, 0.895444f, 0.935885f, 0.592526f, + 0.810681f, 0.0200064f, 0.0986983f, 0.164623f, 0.975185f, 0.0102097f, + 0.648763f, 0.114897f, 0.400273f, 0.549732f, 0.732205f, 0.363931f, + 0.223837f, 0.4427f, 0.770981f, 0.280827f, 0.407232f, 0.323108f, + 0.9429f, 0.594368f, 0.175995f, 0.34f, 0.857507f, 0.016013f, + 0.516969f, 0.847756f, 0.638805f, 0.324338f, 0.897038f, 0.0950314f, + 0.0460401f, 0.449791f, 0.189096f, 0.931966f, 0.846644f, 0.64728f, + 0.096389f, 0.075902f, 0.27798f, 0.673576f, 0.102553f, 0.275159f, + 0.00170948f, 0.319388f, 0.0328678f, 0.411649f, 0.496922f, 0.778794f, + 0.634341f, 0.158655f, 0.0157559f, 0.195268f, 0.663882f, 0.148622f, + 0.118159f, 0.552174f, 0.757064f, 0.854851f, 0.991449f, 0.349681f, + 0.17858f, 0.774876f}; +float Utils::precalc_rands_3[kPrecalcRandsCount] = { + 0.29369f, 0.894838f, 0.857948f, 0.04309f, 0.0296678f, 0.180115f, + 0.694884f, 0.227017f, 0.936936f, 0.746493f, 0.511976f, 0.231185f, + 0.1333f, 0.524805f, 0.774586f, 0.395971f, 0.206664f, 0.274414f, + 0.178939f, 0.88643f, 0.346536f, 0.22934f, 0.635988f, 0.589186f, + 0.652835f, 0.195603f, 0.504794f, 0.831229f, 0.769911f, 0.494712f, + 0.60128f, 0.367987f, 0.239279f, 0.0791311f, 0.469948f, 0.948189f, + 0.760893f, 0.670452f, 0.753765f, 0.822003f, 0.628783f, 0.432039f, + 0.226478f, 0.0678665f, 0.497384f, 0.110421f, 0.428975f, 0.446298f, + 0.00813589f, 0.2634f, 0.434728f, 0.693152f, 0.547276f, 0.702469f, + 0.407723f, 0.11742f, 0.235373f, 0.0738137f, 0.410148f, 0.231855f, + 0.256911f, 0.879873f, 0.818198f, 0.73404f, 0.423038f, 0.577114f, + 0.116636f, 0.247292f, 0.822178f, 0.817466f, 0.940992f, 0.593788f, + 0.751732f, 0.0681611f, 0.38832f, 0.352672f, 0.174289f, 0.582884f, + 0.0338663f, 0.460085f, 0.869757f, 0.854794f, 0.35513f, 0.477297f, + 0.31343f, 0.545157f, 0.943892f, 0.383522f, 0.121732f, 0.131018f, + 0.690497f, 0.231025f, 0.395681f, 0.144711f, 0.521456f, 0.192024f, + 0.796611f, 0.64258f, 0.13998f, 0.560008f, 0.549709f, 0.831634f, + 0.010101f, 0.684939f, 0.00884889f, 0.796426f, 0.603282f, 0.591985f, + 0.731204f, 0.950351f, 0.408559f, 0.592352f, 0.76991f, 0.196648f, + 0.376926f, 0.508574f, 0.809908f, 0.862359f, 0.863431f, 0.884588f, + 0.895885f, 0.391311f, 0.976098f, 0.473118f, 0.286659f, 0.0946781f, + 0.402437f, 0.347471f}; +#else // USE_BAKED_RANDS +float Utils::precalc_rands_1[kPrecalcRandsCount]; +float Utils::precalc_rands_2[kPrecalcRandsCount]; +float Utils::precalc_rands_3[kPrecalcRandsCount]; +#endif // USE_BAKED_RANDS + +Utils::Utils() { + // Is this gonna be consistent cross-platform?... :-/ + srand(543); // NOLINT + + // Test our static-type-name functionality. + // This code runs at compile time and extracts human readable type names using + // __PRETTY_FUNCTION__ type functionality. However, it is dependent on + // specific compiler output and so could break easily if anything changes. + // Here we add some compile-time checks to alert us if that happens. + + // Remember that results can vary per compiler; make sure we match + // one of the expected formats. + static_assert(static_type_name_constexpr() + == "ballistica::AppGlobals *" + || static_type_name_constexpr() + == "ballistica::AppGlobals*" + || static_type_name_constexpr() + == "class ballistica::AppGlobals*"); + Object::Ref testnode{}; + static_assert( + static_type_name_constexpr() + == "ballistica::Object::Ref" + || static_type_name_constexpr() + == "class ballistica::Object::Ref"); + + // int testint{}; + // static_assert(static_type_name_constexpr() == "int"); + + // If anything above breaks, enable this code to debug/fix it. + // This will print a calculated type name as well as the full string + // it was parsed from. Use this to adjust the filtering as necessary so + // the resulting type name matches what is expected. + if (explicit_bool(false)) { + Log("static_type_name check; name is '" + + static_type_name() + "' debug_full is '" + + static_type_name(true) + "'"); + } + + // We now bake these in so they match across platforms... +#if USE_BAKED_RANDS +#else + // set up our precalculated rand vals + for (int i = 0; i < kPrecalcRandsCount; i++) { + precalc_rands_1[i] = static_cast(rand()) / RAND_MAX; // NOLINT + precalc_rands_2[i] = static_cast(rand()) / RAND_MAX; // NOLINT + precalc_rands_3[i] = static_cast(rand()) / RAND_MAX; // NOLINT + } +#endif + huffman_ = std::make_unique(); +} + +Utils::~Utils() = default; + +auto Utils::StringReplaceOne(std::string* target, const std::string& key, + const std::string& replacement) -> bool { + assert(target != nullptr); + size_t pos = target->find(key); + if (pos != std::string::npos) { + target->replace(pos, key.size(), replacement); + return true; + } + return false; +} + +// from https://stackoverflow.com/questions/5343190/ +// how-do-i-replace-all-instances-of-a-string-with-another-string/14678800 +auto Utils::StringReplaceAll(std::string* target, const std::string& key, + const std::string& replacement) -> void { + assert(target != nullptr); + if (key.empty()) { + return; + } + std::string ws_ret; + ws_ret.reserve(target->length()); + size_t start_pos = 0, pos; + while ((pos = target->find(key, start_pos)) != std::string::npos) { + ws_ret += target->substr(start_pos, pos - start_pos); + ws_ret += replacement; + pos += key.length(); + start_pos = pos; + } + ws_ret += target->substr(start_pos); + target->swap(ws_ret); // faster than str = ws_ret; +} + +auto Utils::IsValidUTF8(const std::string& val) -> bool { + std::string out = Utils::GetValidUTF8(val.c_str(), "bsivu8"); + return (out == val); +} + +static auto utf8_check_is_valid(const std::string& string) -> bool { + int c, i, ix, n, j; + for (i = 0, ix = static_cast(string.length()); i < ix; i++) { + c = (unsigned char)string[i]; + // if (c==0x09 || c==0x0a || c==0x0d + // || (0x20 <= c && c <= 0x7e) ) n = 0; // is_printable_ascii + if (0x00 <= c && c <= 0x7f) { + n = 0; // 0bbbbbbb + } else if ((c & 0xE0) == 0xC0) { // NOLINT + n = 1; // 110bbbbb + } else if (c == 0xed && i < (ix - 1) + && ((unsigned char)string[i + 1] & 0xa0) == 0xa0) { // NOLINT + return false; // U+d800 to U+dfff + } else if ((c & 0xF0) == 0xE0) { // NOLINT + n = 2; // 1110bbbb + } else if ((c & 0xF8) == 0xF0) { // NOLINT + n = 3; // 11110bbb + } else { + // else if (($c & 0xFC) == 0xF8) + // n=4; // 111110bb //byte 5, unnecessary in 4 byte UTF-8 + // else if (($c & 0xFE) == 0xFC) + // n=5; // 1111110b //byte 6, unnecessary in 4 byte UTF-8 + + return false; + } + for (j = 0; j < n && i < ix; j++) { // n bytes matching 10bbbbbb follow ? + // NOLINTNEXTLINE + if ((++i == ix) || (((unsigned char)string[i] & 0xC0) != 0x80)) { + return false; + } + } + } + return true; +} + +// added by ericf from http://stackoverflow.com/questions/17316506/ +// strip-invalid-utf8-from-string-in-c-c +// static std::string correct_non_utf_8(std::string *str) { +auto Utils::GetValidUTF8(const char* str, const char* loc) -> std::string { + int i, f_size = static_cast(strlen(str)); + unsigned char c, c2 = 0, c3, c4; + std::string to; + to.reserve(static_cast(f_size)); + + // ok, it seems we're somehow letting some funky utf8 through that's + // causing crashes.. for now lets try this all-or-nothing func and return + // ascii only if it fails + if (!utf8_check_is_valid(str)) { + // now strip out anything but normal ascii... + for (i = 0; i < f_size; i++) { + c = (unsigned char)(str)[i]; + if (c < 127) { // normal ASCII + to.append(1, c); + } + } + + // phone home a few times for bad strings + static int logged_count = 0; + if (logged_count < 10) { + std::string log_str; + for (i = 0; i < f_size; i++) { + c = (unsigned char)(str)[i]; + log_str += std::to_string(static_cast(c)); + if (i + 1 < f_size) { + log_str += ','; + } + } + logged_count++; + Log("GOT INVALID UTF8 SEQUENCE: (" + log_str + "); RETURNING '" + to + + "'; LOC '" + loc + "'"); + } + + } else { + for (i = 0; i < f_size; i++) { + c = (unsigned char)(str)[i]; + if (c < 32) { // control char + if (c == 9 || c == 10 || c == 13) { // allow only \t \n \r + to.append(1, c); + } + continue; + } else if (c < 127) { // normal ASCII + to.append(1, c); + continue; + } else if (c < 160) { + // control char (nothing should be defined here either + // ASCI, ISO_8859-1 or UTF8, so skipping) + if (c2 == 128) { // fix microsoft mess, add euro + to.append(1, (unsigned char)(226)); + to.append(1, (unsigned char)(130)); + to.append(1, (unsigned char)(172)); + } + if (c2 == 133) { // fix IBM mess, add NEL = \n\r + to.append(1, 10); + to.append(1, 13); + } + continue; + } else if (c < 192) { // invalid for UTF8, converting ASCII + to.append(1, (unsigned char)194); + to.append(1, c); + continue; + } else if (c < 194) { // invalid for UTF8, converting ASCII + to.append(1, (unsigned char)195); + to.append(1, c - 64); + continue; + } else if (c < 224 && i + 1 < f_size) { // possibly 2byte UTF8 + c2 = (unsigned char)(str)[i + 1]; + if (c2 > 127 && c2 < 192) { // valid 2byte UTF8 + if (c == 194 && c2 < 160) { // control char, skipping + } else { + to.append(1, c); + to.append(1, c2); + } + i++; + continue; + } + } else if (c < 240 && i + 2 < f_size) { // possibly 3byte UTF8 + c2 = (unsigned char)(str)[i + 1]; + c3 = (unsigned char)(str)[i + 2]; + if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192) { // valid 3byte UTF8 + to.append(1, c); + to.append(1, c2); + to.append(1, c3); + i += 2; + continue; + } + } else if (c < 245 && i + 3 < f_size) { // possibly 4byte UTF8 + c2 = (unsigned char)(str)[i + 1]; + c3 = (unsigned char)(str)[i + 2]; + c4 = (unsigned char)(str)[i + 3]; + if (c2 > 127 && c2 < 192 && c3 > 127 && c3 < 192 && c4 > 127 + && c4 < 192) { + // valid 4byte UTF8 + to.append(1, c); + to.append(1, c2); + to.append(1, c3); + to.append(1, c4); + i += 3; + continue; + } + } + // invalid UTF8, converting ASCII + // (c>245 || string too short for multi-byte)) + to.append(1, (unsigned char)195); + to.append(1, c - 64); + } + } + return to; +} + +auto Utils::UTF8StringLength(const char* val) -> int { + std::string valid_str = GetValidUTF8(val, "gusl1"); + return u8_strlen(valid_str.c_str()); +} + +auto Utils::GetUTF8Value(const char* c) -> uint32_t { + int offset = 0; + uint32_t val = u8_nextchar(c, &offset); + + // Hack: allow showing euro even if we don't support unicode font rendering. + if (!g_buildconfig.enable_os_font_rendering()) { + if (val == 8364) { + val = 0xE000; + } + } + return val; +} + +auto Utils::UTF8FromUnicode(std::vector unichars) -> std::string { + int buffer_size = static_cast(unichars.size() * 4 + 1); + // at most 4 chars per unichar plus ending zero + std::vector buffer(static_cast(buffer_size)); + int len = u8_toutf8(buffer.data(), buffer_size, unichars.data(), + static_cast(unichars.size())); + assert(len == unichars.size()); + buffer.resize(strlen(buffer.data()) + 1); + return buffer.data(); +} + +auto Utils::UnicodeFromUTF8(const std::string& s_in, const char* loc) + -> std::vector { + std::string s = GetValidUTF8(s_in.c_str(), loc); + // worst case every char is a character (plus trailing 0) + std::vector vals(s.size() + 1); + int converted = u8_toucs(&vals[0], static_cast(vals.size()), s.c_str(), + static_cast(s.size())); + vals.resize(static_cast(converted)); + return vals; +} + +auto Utils::UTF8FromUnicodeChar(uint32_t c) -> std::string { + char buffer[10]; + u8_toutf8(buffer, sizeof(buffer), &c, 1); + return buffer; +} + +void Utils::AdvanceUTF8(const char** c) { + int offset = 0; + u8_nextchar(*c, &offset); + *c += offset; +} + +auto Utils::GetJSONString(const char* s) -> std::string { + std::string str; + cJSON* str_obj = cJSON_CreateString(s); + char* str_buffer = cJSON_PrintUnformatted(str_obj); + str = str_buffer; + free(str_buffer); + cJSON_Delete(str_obj); + return str; +} + +auto Utils::PtrToString(const void* val) -> std::string { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%p", val); + return buffer; +} + +static const char* g_default_random_names[] = { + "Flopsy", "Skippy", "Boomer", "Jolly", "Zeus", "Garth", + "Dizzy", "Mullet", "Ogre", "Ginger", "Nippy", "Murphy", + "Crom", "Sparky", "Wedge", "Arthur", "Benji", "Pan", + "Wallace", "Hamish", "Luke", "Cowboy", "Uncas", "Magua", + "Robin", "Lancelot", "Mad Dog", "Maximus", "Leonidas", "Don Quixote", + "Beowulf", "Gilgamesh", "Conan", "Cicero", "Elmer", "Flynn", + "Duck", "Uther", "Darkness", "Sunshine", "Willy", "Elvis", + "Dolph", "Rico", "Magoogan", "Willow", "Rose", "Egg", + "Thunder", "Jack", "Dude", "Walter", "Donny", "Larry", + "Chunk", "Socrates", nullptr}; + +static std::list* g_random_names_list = nullptr; + +auto Utils::GetRandomNameList() -> const std::list& { + assert(InGameThread()); + if (!g_random_names_list) { + // this will init the list with our default english names + SetRandomNameList(std::list(1, "DEFAULT_NAMES")); + } + return *g_random_names_list; +} + +void Utils::SetRandomNameList(const std::list& custom_names) { + assert(InGameThread()); + if (!g_random_names_list) { + g_random_names_list = new std::list; + } else { + g_random_names_list->clear(); + } + bool add_default_names = false; + if (custom_names.empty()) { + add_default_names = true; + } + for (const auto& custom_name : custom_names) { + if (custom_name == "DEFAULT_NAMES") { + add_default_names = true; + } else { + g_random_names_list->push_back(custom_name); + } + } + if (add_default_names) { + for (const char** c = g_default_random_names; *c != nullptr; c++) { + g_random_names_list->push_back(*c); + } + } +} + +#define HEXVAL(x) ('0' + (x) + ((x) > 9u) * 7u) +static auto ToHex(const std::string& s_in) -> std::string { + uint32_t s_size = static_cast(s_in.size()); + std::string s_out; + s_out.resize(static_cast(s_size) * 2); + for (uint32_t i = 0; i < s_size; i++) { + s_out[i * 2] = + static_cast(HEXVAL((static_cast(s_in[i])) >> 4u)); + s_out[i * 2 + 1] = + static_cast(HEXVAL((static_cast(s_in[i]) & 15u))); + } + return s_out; +} +#undef HEXVAL + +static auto FromHex(const std::string& s_in) -> std::string { + int s_size = static_cast(s_in.size()); + BA_PRECONDITION(s_size % 2 == 0); + s_size /= 2; + std::string s_out; + s_out.resize(static_cast(s_size)); + for (int i = 0; i < s_size; i++) { + auto val = (uint32_t)s_in[i * 2]; // NOLINT(cert-str34-c) + if (val >= '0' && val <= '9') { + s_out[i] = static_cast((val - '0') << 4u); + } else if (val >= 'A' && val <= 'F') { + s_out[i] = static_cast((10u + (val - 'A')) << 4u); + } else { + throw Exception(); + } + val = (uint32_t)s_in[i * 2 + 1]; // NOLINT(cert-str34-c) + if (val >= '0' && val <= '9') { + s_out[i] = + static_cast(static_cast(s_out[i]) | (val - '0')); + } else if (val >= 'A' && val <= 'F') { + s_out[i] = static_cast(static_cast(s_out[i]) + | (10 + (val - 'A'))); + } else { + throw Exception(); + } + } + return s_out; +} + +static auto EncryptDecrypt(const std::string& to_encrypt) -> std::string { + assert(g_platform); + const char* key = g_platform->GetUniqueDeviceIdentifier().c_str(); + int key_size = + static_cast(g_platform->GetUniqueDeviceIdentifier().size()); + std::string output = to_encrypt; + for (size_t i = 0; i < to_encrypt.size(); i++) { + output[i] = to_encrypt[i] ^ key[i % (key_size)]; // NOLINT + } + return output; +} + +static auto EncryptDecryptCustom(const std::string& to_encrypt, + const std::string& key_in) -> std::string { + assert(g_platform); + const char* key = key_in.c_str(); + int key_size = static_cast(key_in.size()); + std::string output = to_encrypt; + for (size_t i = 0; i < to_encrypt.size(); i++) { + output[i] = to_encrypt[i] ^ key[i % (key_size)]; // NOLINT + } + return output; +} + +static auto PublicEncryptDecrypt(const std::string& to_encrypt) -> std::string { + std::string key_str = "create an account"; // A non-key-looking key. + const char* key = key_str.c_str(); + int key_size = static_cast(key_str.size()); + std::string output = to_encrypt; + for (size_t i = 0; i < to_encrypt.size(); i++) + output[i] = to_encrypt[i] ^ key[i % (key_size)]; // NOLINT + return output; +} + +auto Utils::LocalEncrypt(const std::string& s_in) -> std::string { + return ToHex(EncryptDecrypt(s_in)); +} + +auto Utils::LocalEncrypt2(const std::string& s_in) -> std::string { + std::string s = EncryptDecrypt(s_in); + return base64_encode((const unsigned char*)s.c_str(), + static_cast(s.size())); +} +auto Utils::EncryptCustom(const std::string& s_in, const std::string& key) + -> std::string { + std::string s = EncryptDecryptCustom(s_in, key); + return base64_encode((const unsigned char*)s.c_str(), + static_cast(s.size())); +} + +auto Utils::LocalDecrypt(const std::string& s_in) -> std::string { + return EncryptDecrypt(FromHex(s_in)); +} + +auto Utils::LocalDecrypt2(const std::string& s_in) -> std::string { + return EncryptDecrypt(base64_decode(s_in)); +} +auto Utils::DecryptCustom(const std::string& s_in, const std::string& key) + -> std::string { + return EncryptDecryptCustom(base64_decode(s_in), key); +} + +auto Utils::PublicEncrypt(const std::string& s_in) -> std::string { + return ToHex(PublicEncryptDecrypt(s_in)); +} + +auto Utils::PublicDecrypt(const std::string& s_in) -> std::string { + return PublicEncryptDecrypt(FromHex(s_in)); +} + +auto Utils::PublicEncrypt2(const std::string& s_in) -> std::string { + std::string s = PublicEncryptDecrypt(s_in); + return base64_encode((const unsigned char*)s.c_str(), + static_cast(s.size())); +} + +auto Utils::PublicDecrypt2(const std::string& s_in) -> std::string { + return PublicEncryptDecrypt(base64_decode(s_in)); +} + +auto Utils::Sphrand(float radius) -> Vector3f { + while (true) { + float x = RandomFloat(); + float y = RandomFloat(); + float z = RandomFloat(); + x = -1.0f + x * 2.0f; + y = -1.0f + y * 2.0f; + z = -1.0f + z * 2.0f; + if (x * x + y * y + z * z <= 1.0f) { + return {x * radius, y * radius, z * radius}; + } + } +} + +auto Utils::FileToString(const std::string& file_name) -> std::string { + std::ifstream file_stream{file_name}; + if (file_stream.fail()) { + throw Exception("Error opening file for reading: '" + file_name + "'"); + } + std::ostringstream str_stream{}; + file_stream >> str_stream.rdbuf(); + if (file_stream.fail() && !file_stream.eof()) { + throw Exception("Error reading file: '" + file_name + "'"); + } + return str_stream.str(); +} + +static void WaitThenDie(millisecs_t wait, const std::string& action) { + Platform::SleepMS(wait); + throw std::runtime_error("Timed out waiting for " + action + "; aborting."); +} + +void Utils::StartSuicideTimer(const std::string& action, millisecs_t delay) { + if (!g_app_globals->started_suicide) { + new std::thread(WaitThenDie, delay, action); + g_app_globals->started_suicide = true; + } +} + +auto Utils::BaseName(const std::string& val) -> std::string { + const char* c = val.c_str(); + const char* lastvalid = c; + while (*c != 0) { + if (*c == '/' || *c == '\\') { + lastvalid = c + 1; + } + ++c; + } + return lastvalid; +} + +} // namespace ballistica diff --git a/src/ballistica/generic/utils.h b/src/ballistica/generic/utils.h new file mode 100644 index 00000000..8d401297 --- /dev/null +++ b/src/ballistica/generic/utils.h @@ -0,0 +1,387 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GENERIC_UTILS_H_ +#define BALLISTICA_GENERIC_UTILS_H_ + +#include +#include +#include +#include +#include + +// Need platform-specific headers here so we can inline calls to htonl/etc. +// (perhaps should move those functions to their own file?) +#if BA_OSTYPE_WINDOWS +#include +#else +#include +#endif +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +const int kPrecalcRandsCount = 128; + +/// A holding tank for miscellaneous functionality not extensive enough to +/// warrant its own class. When possible, things should be moved out of here +/// into more organized locations. +class Utils { + public: + Utils(); + ~Utils(); + + static auto BaseName(const std::string& val) -> std::string; + + static auto PtrToString(const void* val) -> std::string; + + // This should probably live elsewhere... + static auto GetRandomNameList() -> const std::list&; + static void SetRandomNameList(const std::list& names); + + static auto UnicodeFromUTF8(const std::string& s, const char* loc) + -> std::vector; + static auto UTF8FromUnicode(std::vector unichars) -> std::string; + static auto UTF8FromUnicodeChar(uint32_t c) -> std::string; + static auto UTF8StringLength(const char* val) -> int; + + /// Start a timer to kill the app after the set length of time. + /// Use this during shutdown or when trying to send a crash-report before + /// dying just to ensure we don't hang indefinitely. + static void StartSuicideTimer(const std::string& action, millisecs_t delay); + + /// Replace a single occurrence of key with replacement in the target string. + /// Returns whether a replacement occurred. + static auto StringReplaceOne(std::string* target, const std::string& key, + const std::string& replacement) -> bool; + + static auto StringReplaceAll(std::string* target, const std::string& key, + const std::string& replacement) -> void; + + /// Strip out or corrects invalid utf8. + /// This is run under the hood for all the above calls but in some cases + /// (such as the calls below) you may want to run it by hand. + /// Loc is included in debug log output if invalid utf8 is passed in. + static auto GetValidUTF8(const char* str, const char* loc) -> std::string; + + /// Use this for debugging (not optimized for speed). + /// Currently just runs GetValidUTF8 and compares + /// results to original to see if anything got changed. + static auto IsValidUTF8(const std::string& val) -> bool; + + // Escape a string so it can be embedded as part of a flattened json string. + static auto GetJSONString(const char* s) -> std::string; + + // IMPORTANT - These run on 'trusted' utf8 - make sure you've run + // GetValidUTF8 on any data you pass to these + static auto GetUTF8Value(const char* s) -> uint32_t; + static void AdvanceUTF8(const char** s); + + /* The following code uses bitwise operators to determine + if an unsigned integer, x, is a power of two. If x is a power of two, + x is represented in binary with only a single bit; therefore, subtraction + by one removes that bit and flips all the lower-order bits. The bitwise + and + + then effectively checks to see if any bit is the + same. If not, then it's a power of two.*/ + static inline auto IsPowerOfTwo(unsigned int x) -> int { + return !((x - 1) & x); + } + + // Yes this stuff should technically be using unsigned values for the + // bitwise stuff but I'm not brave enough to convert it at the moment. + // Made a quick attempt and everything blew up. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "bugprone-narrowing-conversions" + + static inline auto FloatToHalfI(uint32_t i) -> uint16_t { + int s = (i >> 16) & 0x00008000; // NOLINT + int e = ((i >> 23) & 0x000000ff) - (127 - 15); // NOLINT + int m = i & 0x007fffff; // NOLINT + + if (e <= 0) { + if (e < -10) { + return 0; + } + m = (m | 0x00800000) >> (1 - e); + + return static_cast(s | (m >> 13)); + } else if (e == 0xff - (127 - 15)) { + if (m == 0) { + // Inf + return static_cast(s | 0x7c00); + } else { + // NAN + m >>= 13; + return static_cast(s | 0x7c00 | m | (m == 0)); + } + } else { + if (e > 30) { + // Overflow + return static_cast(s | 0x7c00); + } + + return static_cast(s | (e << 10) | (m >> 13)); + } + } + + static inline auto FloatToHalf(float i) -> uint16_t { + union { + float f; + uint32_t i; + } v{}; + v.f = i; + return FloatToHalfI(v.i); + } + + static inline auto HalfToFloatI(uint16_t y) -> uint32_t { + int s = (y >> 15) & 0x00000001; + int e = (y >> 10) & 0x0000001f; + int m = y & 0x000003ff; + if (e == 0) { + if (m == 0) { // Plus or minus zero + return static_cast(s << 31); + } else { // Denormalized number -- renormalize it + while (!(m & 0x00000400)) { + m <<= 1; + e -= 1; + } + e += 1; + m &= ~0x00000400; + } + } else if (e == 31) { + if (m == 0) { // Inf + return static_cast((s << 31) | 0x7f800000); + } else { // NaN + return static_cast((s << 31) | 0x7f800000 | (m << 13)); + } + } + e = e + (127 - 15); + m = m << 13; + return static_cast((s << 31) | (e << 23) | m); + } + + static inline auto HalfToFloat(uint16_t y) -> float { + union { + float f; + uint32_t i; + } v{}; + v.i = HalfToFloatI(y); + return v.f; + } + + // Value embedding/extracting in buffers. + // Note to self: + // Whenever its possible to do so cleanly, we should migrate to storing + // everything in little-endian and kill off the NBO versions of these. + // I don't anticipate having to run on big-endian hardware anytime soon + // and it'll save us a few cycles. (plus things are a sloppy mix of + // network-byte-ordered and native-ordered as it stands now). + + /// Embed a single bool in a buffer. + static inline void EmbedBool(char** b, bool i) { + **b = i; // NOLINT + (*b)++; + } + + /// Embed up to 8 bools in a buffer (in a single byte) use ExtractBools to + /// pull them out. + static inline void EmbedBools(char** b, bool i1, bool i2 = false, + bool i3 = false, bool i4 = false, + bool i5 = false, bool i6 = false, + bool i7 = false, bool i8 = false) { + **b = uint8_t(i1) | (uint8_t(i2) << 1) | (uint8_t(i3) << 2) // NOLINT + | (uint8_t(i4) << 3) | (uint8_t(i5) << 4) // NOLINT + | (uint8_t(i6) << 5) | (uint8_t(i7) << 6) // NOLINT + | (uint8_t(i8) << 7); // NOLINT + (*b)++; + } + + static inline void EmbedInt8(char** b, int8_t i) { + **b = i; + (*b)++; + } + + /// Embed a 2 byte int (short) into a buffer in network byte order. + static inline void EmbedInt16NBO(char** b, int16_t i) { + i = htons(i); + memcpy(*b, &i, sizeof(i)); + *b += 2; + } + + /// Embed a 4 byte int into a buffer in network-byte-order. + static inline void EmbedInt32NBO(char** b, int32_t i) { + i = htonl(i); + memcpy(*b, &i, sizeof(i)); + *b += 4; + } + + /// Embed a float in 16 bit "half" format (loses some precision) in + /// network-byte-order. + static inline void EmbedFloat16NBO(char** b, float f) { + uint16_t val = htons(FloatToHalf(f)); + memcpy(*b, &val, sizeof(val)); + *b += 2; + } + + /// Embed 4 byte float into a buffer. + static inline void EmbedFloat32(char** b, float f) { + memcpy(*b, &f, 4); + *b += 4; + } + + /// Embed a string into a buffer. + static inline void EmbedString(char** b, const char* s) { + strcpy(*b, s); // NOLINT + *b += strlen(*b) + 1; + } + + static inline auto EmbeddedStringSize(const char* s) -> int { + return static_cast(strlen(s) + 1); + } + + /// Embed a string in a buffer. + static inline void EmbedString(char** b, const std::string& s) { + strcpy(*b, s.c_str()); // NOLINT + *b += s.size() + 1; + } + + /// Return the number of bytes an embedded string with occupy. + static inline auto EmbeddedStringSize(const std::string& s) -> int { + return static_cast(s.size() + 1); + } + + /// Extract a string from a buffer. + static inline auto ExtractString(const char** b) -> std::string { + std::string s = *b; + *b += s.size() + 1; + return s; + } + + /// Extract a single bool from a buffer. + static inline auto ExtractBool(const char** b) -> bool { + bool i = (**b != 0); + (*b)++; + return i; + } + + /// Extract multiple bools from a buffer. + static inline void ExtractBools(const char** b, bool* i1, bool* i2 = nullptr, + bool* i3 = nullptr, bool* i4 = nullptr, + bool* i5 = nullptr, bool* i6 = nullptr, + bool* i7 = nullptr, bool* i8 = nullptr) { + auto i = static_cast(**b); + *i1 = static_cast(i & 0x01); + if (i2) *i2 = static_cast((i >> 1) & 0x01); + if (i3) *i3 = static_cast((i >> 2) & 0x01); + if (i4) *i4 = static_cast((i >> 3) & 0x01); + if (i5) *i5 = static_cast((i >> 4) & 0x01); + if (i6) *i6 = static_cast((i >> 5) & 0x01); + if (i7) *i7 = static_cast((i >> 6) & 0x01); + if (i8) *i8 = static_cast((i >> 7) & 0x01); + (*b)++; + } +#pragma clang diagnostic pop + + /// Extract a 1 byte int from a buffer. + static inline auto ExtractInt8(const char** b) -> int8_t { + int8_t i = **b; + (*b)++; + return i; + } + + /// Extract a 2 byte int from a network-byte-order buffer. + static inline auto ExtractInt16NBO(const char** b) -> int16_t { + int16_t i; + memcpy(&i, *b, sizeof(i)); + *b += 2; + return ntohs(i); // NOLINT + } + + /// Extract a 4 byte int from a network-byte-order buffer. + static inline auto ExtractInt32NBO(const char** b) -> int32_t { + int32_t i; + memcpy(&i, *b, sizeof(i)); + *b += 4; + return ntohl(i); // NOLINT + } + + /// Extract a 2 byte (half) float from a network-byte-order buffer. + static inline auto ExtractFloat16NBO(const char** b) -> float { + uint16_t i; + memcpy(&i, *b, sizeof(i)); + *b += 2; + return HalfToFloat(ntohs(i)); // NOLINT + } + + /// Extract a 4 byte float from a buffer. + static inline auto ExtractFloat32(const char** b) -> float { + float i; + memcpy(&i, *b, 4); + *b += 4; + return i; + } + + /// Return whether a sequence of some type pointer has nullptr members. + template + static auto HasNullMembers(const T& sequence) -> bool { + for (auto&& i : sequence) { + if (i == nullptr) { + return true; + } + } + return false; + } + + /// Simple lists of pre-calculated random values between 0 and 1 + /// (with no particular distribution) + static float precalc_rands_1[]; + static float precalc_rands_2[]; + static float precalc_rands_3[]; + auto huffman() -> Huffman* { return huffman_.get(); } + + /// Encrypt a string in a manner specific to this device. + static auto LocalEncrypt(const std::string& s) -> std::string; + static auto LocalEncrypt2(const std::string& s) -> std::string; + + /// Decode a local string that was encoded specific to this device. + /// Throws an exception on failure. + static auto LocalDecrypt(const std::string& s) -> std::string; + static auto LocalDecrypt2(const std::string& s) -> std::string; + + /// Encrypt a string using a custom key. + static auto EncryptCustom(const std::string& s, const std::string& key) + -> std::string; + /// Decrypt a string using a custom key. + static auto DecryptCustom(const std::string& s, const std::string& key) + -> std::string; + + /// Encrypt/decrypt strings to send to the master-server + static auto PublicEncrypt(const std::string& s) -> std::string; + static auto PublicDecrypt(const std::string& s) -> std::string; + static auto PublicEncrypt2(const std::string& s) -> std::string; + static auto PublicDecrypt2(const std::string& s) -> std::string; + + // FIXME - move to a nice math-y place + static auto Sphrand(float radius = 1.0f) -> Vector3f; + + // read a file into a string, throwing an Exception on error. + static auto FileToString(const std::string& file_name) -> std::string; + + // fixme: move this to a 'Math' class?.. + static auto SmoothStep(float edge0, float edge1, float x) -> float { + float t; + t = std::min(1.0f, std::max(0.0f, (x - edge0) / (edge1 - edge0))); + return t * t * (3.0f - 2.0f * t); + } + + private: + std::unique_ptr huffman_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GENERIC_UTILS_H_ diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index 6ac8a2c1..feb428d3 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -33,9 +33,7 @@ if TYPE_CHECKING: def get_legal_notice_private() -> str: """Return the one line legal notice we expect private files to have.""" - # We just use the first line of the mit license (just the copyright) - from efrotools import MIT_LICENSE - return MIT_LICENSE.splitlines()[0] + return 'Copyright (c) 2011-2020 Eric Froemling' @dataclass @@ -287,27 +285,33 @@ class Updater: can_auto_update=can_auto_update)) def _check_header(self, fname: str) -> None: + from efrotools import get_public_license # Make sure its define guard is correct. guard = (fname[4:].upper().replace('/', '_').replace('.', '_') + '_') with open(fname) as fhdr: lines = fhdr.read().splitlines() - if self._public: - raise RuntimeError('FIXME: Check for full license.') - - # Look for copyright/legal-notice line(s). - line = '// ' + get_legal_notice_private() + # Look for public license line (public or private repo) + # or private license line (private repo only) + line_private = '// ' + get_legal_notice_private() + line_public = get_public_license('c++') lnum = 0 - if lines[lnum] != line: - # Allow auto-correcting if it looks close already - # (don't want to blow away an unrelated line) - allow_auto = 'Copyright' in lines[ - lnum] and 'Eric Froemling' in lines[lnum] - self._add_line_correction(fname, - line_number=lnum, - expected=line, - can_auto_update=allow_auto) + + if self._public: + if lines[lnum] != line_public: + # Allow auto-correcting from private to public line + allow_auto = lines[lnum] == line_private + self._add_line_correction(fname, + line_number=lnum, + expected=line_public, + can_auto_update=allow_auto) + else: + if lines[lnum] not in [line_public, line_private]: + self._add_line_correction(fname, + line_number=lnum, + expected=line_private, + can_auto_update=False) # Check for header guard at top line = '#ifndef ' + guard diff --git a/tools/efrotools/__init__.py b/tools/efrotools/__init__.py index 6fac48dc..83a6a5ca 100644 --- a/tools/efrotools/__init__.py +++ b/tools/efrotools/__init__.py @@ -27,27 +27,6 @@ PYVER = '3.8' # Python binary assumed by these tools. PYTHON_BIN = f'python{PYVER}' if platform.system() != 'Windows' else 'python' -MIT_LICENSE = """Copyright (c) 2011-2020 Eric Froemling - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -""" - def explicit_bool(value: bool) -> bool: """Simply return input value; can avoid unreachable-code type warnings.""" diff --git a/tools/efrotools/code.py b/tools/efrotools/code.py index 2b8ba44e..34b79035 100644 --- a/tools/efrotools/code.py +++ b/tools/efrotools/code.py @@ -64,7 +64,7 @@ def formatcode(projroot: Path, full: bool) -> None: def cpplint(projroot: Path, full: bool) -> None: """Run lint-checking on all code deemed lint-able.""" - # pylint: disable=too-many-locals + # pylint: disable=too-many-locals, too-many-statements import tempfile from concurrent.futures import ThreadPoolExecutor from multiprocessing import cpu_count @@ -124,6 +124,13 @@ def cpplint(projroot: Path, full: bool) -> None: codelines[headercheckline] = ( " if False and include and include.group(1) in ('cfenv',") + # Skip copyright line check (our public repo code is MIT licensed + # so not crucial to keep track of who wrote exactly what) + copyrightline = codelines.index( + ' """Logs an error if no Copyright' + ' message appears at the top of the file."""') + codelines[copyrightline] = ' return' + # Don't complain about unknown NOLINT categories. # (we use them for clang-tidy) unknownlintline = codelines.index( From 0809dbcbfb8271152718443080d706072dcc02d3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 16:23:23 -0500 Subject: [PATCH 216/417] More C++ --- .efrocachemap | 20 +- src/ballistica/app/app.cc | 483 +++++++++++++++++++++++++++++ src/ballistica/app/app.h | 148 +++++++++ src/ballistica/app/app_config.cc | 245 +++++++++++++++ src/ballistica/app/app_config.h | 130 ++++++++ src/ballistica/app/app_globals.cc | 12 + src/ballistica/app/app_globals.h | 99 ++++++ src/ballistica/app/headless_app.cc | 21 ++ src/ballistica/app/headless_app.h | 20 ++ src/ballistica/app/stress_test.cc | 101 ++++++ src/ballistica/app/stress_test.h | 29 ++ src/ballistica/app/vr_app.cc | 110 +++++++ src/ballistica/app/vr_app.h | 48 +++ 13 files changed, 1456 insertions(+), 10 deletions(-) create mode 100644 src/ballistica/app/app.cc create mode 100644 src/ballistica/app/app.h create mode 100644 src/ballistica/app/app_config.cc create mode 100644 src/ballistica/app/app_config.h create mode 100644 src/ballistica/app/app_globals.cc create mode 100644 src/ballistica/app/app_globals.h create mode 100644 src/ballistica/app/headless_app.cc create mode 100644 src/ballistica/app/headless_app.h create mode 100644 src/ballistica/app/stress_test.cc create mode 100644 src/ballistica/app/stress_test.h create mode 100644 src/ballistica/app/vr_app.cc create mode 100644 src/ballistica/app/vr_app.h diff --git a/.efrocachemap b/.efrocachemap index fb411c5e..0ff4b268 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e3/43/5df3f99b46aa9b6aff2db87fabb4", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/b1/06/b993362a65a5760ddfb10f2c59b9", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4f/99/2234c89a65d7e5d8463556d9df5e", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e4/96/f289ec31cdada6f41de5dce382bd", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/62/8d/6f2752d858b097c318920ff09cf5", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/77/1d/7986d62c92d9f34ca85396168923", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/a3/da/d5f88e92926543f61bd5dd80321e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/60/8e/d7efd5e7d7a94439453909527d4e", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/d3/b3/8124ea626db8dbd7b1744c335c7c", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/27/f7/87a5d3b8648352ac40398f86dc8e" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d0/21/cb738075207c3dab9f2389455a69", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/44/d59a1f7d6ee05b58e80ebc3469bf", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/56/6d1f390d348ddf65937af3374d76", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/31/b9/176ba76e48c23d064b6583963a0e", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/18/56c6d3b8788362ceb97005b6b3b6", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a6/bd/da7954fe559403d021b15df72967", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/97/10/138625f676793653620a84cd712b", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ef/a8/4b532f37f74929b834ffd6c2ac5d", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3f/6f/c49674367960a82b19a45641daa6", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/df/a3/90e19f2ef6b2edd17d0f936245f2" } \ No newline at end of file diff --git a/src/ballistica/app/app.cc b/src/ballistica/app/app.cc new file mode 100644 index 00000000..ad1b686f --- /dev/null +++ b/src/ballistica/app/app.cc @@ -0,0 +1,483 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/app/app.h" + +#include "ballistica/core/thread.h" +#include "ballistica/game/game.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/input/device/touch_input.h" +#include "ballistica/input/input.h" +#include "ballistica/networking/network_reader.h" +#include "ballistica/networking/networking.h" +#include "ballistica/networking/telnet_server.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +App::App(Thread* thread) : Module("app", thread) { + assert(g_app == nullptr); + g_app = this; + + // So anyone who needs to use the 'main' thread id can get at it... + Thread::UpdateMainThreadID(); + + // We modify some app behavior when run under the server manager. + auto* envval = getenv("BA_SERVER_WRAPPER_MANAGED"); + server_wrapper_managed_ = (envval && strcmp(envval, "1") == 0); +} + +void App::PostInit() { + // If we've got a nice themed hardware cursor, show it. + // Otherwise hide the hardware cursor; we'll draw it in software. + // (need to run this in postinit because SDL/etc may not be inited yet + // as of App::App(). + g_platform->SetHardwareCursorVisible(g_buildconfig.hardware_cursor()); +} + +App::~App() = default; + +auto App::UsesEventLoop() const -> bool { + // We have 2 redundant values for essentially the same thing; + // should get rid of IsEventPushMode() once we've created + // App subclasses for our various platforms. + return !g_platform->IsEventPushMode(); +} + +void App::PushInterruptSignalSetupCall() { + g_platform->SetupInterruptHandling(); +} + +void App::RunRenderUpkeepCycle() { + // This should only be used in cases where the OS is handling the event loop. + assert(!UsesEventLoop()); + if (UsesEventLoop()) { + return; + } + + // Pump thread messages (we're being driven by frame-draw callbacks + // so this is the only place that it gets done at). + thread()->RunEventLoop(true); // Single pass only. + + // Now do the general app event cycle for whoever needs to process things. + RunEvents(); +} + +void App::RebuildLostGLContext() { + assert(InMainThread()); + assert(g_graphics_server); + if (g_graphics_server) { + g_graphics_server->RebuildLostContext(); + } +} + +void App::DrawFrame(bool during_resize) { + assert(InMainThread()); + + // Its possible to receive frames before we're ready to draw. + if (!g_graphics_server || !g_graphics_server->renderer()) { + return; + } + + millisecs_t starttime = GetRealTime(); + + // A resize-draw event means that we're drawing due to a window resize. + // In this case we ignore regular draw events for a short while + // afterwards which makes resizing smoother. + // FIXME: should figure out the *correct* way to handle this; + // I believe the underlying cause here is some sort of context contention + // across threads. + if (during_resize) { + last_resize_draw_event_time_ = starttime; + } else { + if (starttime - last_resize_draw_event_time_ < (1000 / 30)) { + return; + } + } + g_graphics_server->TryRender(); + RunRenderUpkeepCycle(); +} + +void App::SetScreenResolution(float width, float height) { + assert(InMainThread()); + if (!HeadlessMode()) { + g_graphics_server->VideoResize(width, height); + } +} + +void App::PushShutdownCompleteCall() { + PushCall([this] { ShutdownComplete(); }); +} + +void App::ShutdownComplete() { + assert(g_platform); + + // Need to call our cleanup stuff that would otherwise get called in main. + g_platform->FinalCleanup(); + + done_ = true; + + // Kill our own event loop (or tell the OS to kill its). + if (UsesEventLoop()) { + thread()->Quit(); + } else { + g_platform->QuitApp(); + } +} + +void App::RunEvents() { + if (!HeadlessMode()) { + // there's probably a better place for this... + UpdateStressTesting(); + } + + // Give platforms a chance to pump/handle their own events. + // FIXME: now that we have app class overrides, platform should really + // not be doing event handling. (need to fix rift build). + g_platform->RunEvents(); +} + +void App::UpdatePauseResume() { + if (actually_paused_) { + // Unpause if no one wants pause. + if (!sys_paused_app_ && !user_paused_app_) { + OnResume(); + actually_paused_ = false; + } + } else { + // Pause if anyone wants. + if (sys_paused_app_ || user_paused_app_) { + OnPause(); + actually_paused_ = true; + } + } +} + +void App::OnPause() { + assert(InMainThread()); + + // Avoid reading gyro values for a short time to avoid hitches when restored. + g_graphics->SetGyroEnabled(false); + + // IMPORTANT: Any on-pause related stuff that threads need to do must + // must be done from their HandleThreadPause(). If we push runnables to them + // they may or may not be called before the thread is actually paused. + + Thread::SetThreadsPaused(true); + + assert(g_networking); + g_networking->Pause(); + + assert(g_network_reader); + if (g_network_reader) { + g_network_reader->Pause(); + } + + if (g_app_globals->telnet_server) { + g_app_globals->telnet_server->Pause(); + } + + g_platform->OnAppPause(); +} + +void App::OnResume() { + assert(InMainThread()); + last_app_resume_time_ = GetRealTime(); + Thread::SetThreadsPaused(false); + + g_platform->OnAppResume(); + g_networking->Resume(); + g_network_reader->Resume(); + + if (g_app_globals->telnet_server) { + g_app_globals->telnet_server->Resume(); + } + + // Also let the Python layer do what it needs to + // (starting/stopping music, etc). + g_python->PushObjCall(Python::ObjID::kHandleAppResumeCall); + g_game->PushOnAppResumeCall(); + + g_graphics->SetGyroEnabled(true); + + // When resuming from a paused state, we may want to + // pause whatever game was running when we last were active. + // TODO(efro): we should make this smarter so it doesn't happen if + // we're in a network game or something that we can't pause; + // bringing up the menu doesn't really accomplish anything there. + if (g_app_globals->should_pause) { + g_app_globals->should_pause = false; + + // If we've been completely backgrounded, + // send a menu-press command to the game; this will + // bring up a pause menu if we're in the game/etc. + g_game->PushMainMenuPressCall(nullptr); + } +} + +auto App::GetProductPrice(const std::string& product) -> std::string { + std::lock_guard lock(product_prices_mutex_); + auto i = product_prices_.find(product); + if (i == product_prices_.end()) { + return ""; + } else { + return i->second; + } +} + +void App::SetProductPrice(const std::string& product, + const std::string& price) { + std::lock_guard lock(product_prices_mutex_); + product_prices_[product] = price; +} + +void App::PauseApp() { + assert(InMainThread()); + Platform::DebugLog("PauseApp@" + + std::to_string(Platform::GetCurrentMilliseconds())); + assert(!sys_paused_app_); + sys_paused_app_ = true; + UpdatePauseResume(); +} + +void App::ResumeApp() { + assert(InMainThread()); + Platform::DebugLog("ResumeApp@" + + std::to_string(Platform::GetCurrentMilliseconds())); + assert(sys_paused_app_); + sys_paused_app_ = false; + UpdatePauseResume(); +} + +void App::DidFinishRenderingFrame(FrameDef* frame) {} + +void App::PrimeEventPump() { + assert(!UsesEventLoop()); + + // Pump events manually until a screen gets created. + // At that point we use frame-draws to drive our event loop. + while (!g_graphics_server->initial_screen_created()) { + g_main_thread->RunEventLoop(true); + Platform::SleepMS(1); + } +} + +#pragma mark Push-Calls + +void App::PushShowOnlineScoreUICall(const std::string& show, + const std::string& game, + const std::string& game_version) { + PushCall([this, show, game, game_version] { + assert(InMainThread()); + g_platform->ShowOnlineScoreUI(show, game, game_version); + }); +} + +void App::PushNetworkSetupCall(int port, int telnet_port, bool enable_telnet, + const std::string& telnet_password) { + PushCall([this, port, telnet_port, enable_telnet, telnet_password] { + assert(InMainThread()); + // Kick these off if they don't exist. + // (do we want to support changing ports on existing ones?) + if (g_network_reader == nullptr) { + new NetworkReader(port); + } + if (g_app_globals->telnet_server == nullptr && enable_telnet) { + new TelnetServer(telnet_port); + assert(g_app_globals->telnet_server); + if (telnet_password.empty()) { + g_app_globals->telnet_server->SetPassword(nullptr); + } else { + g_app_globals->telnet_server->SetPassword(telnet_password.c_str()); + } + } + }); +} + +void App::PushPurchaseAckCall(const std::string& purchase, + const std::string& order_id) { + PushCall([this, purchase, order_id] { + g_platform->PurchaseAck(purchase, order_id); + }); +} + +void App::PushGetScoresToBeatCall(const std::string& level, + const std::string& config, + void* py_callback) { + PushCall([this, level, config, py_callback] { + assert(InMainThread()); + g_platform->GetScoresToBeat(level, config, py_callback); + }); +} + +void App::PushPurchaseCall(const std::string& item) { + PushCall([this, item] { + assert(InMainThread()); + g_platform->Purchase(item); + }); +} + +void App::PushRestorePurchasesCall() { + PushCall([this] { + assert(InMainThread()); + g_platform->RestorePurchases(); + }); +} + +void App::PushOpenURLCall(const std::string& url) { + PushCall([this, url] { g_platform->OpenURL(url); }); +} + +void App::PushGetFriendScoresCall(const std::string& game, + const std::string& game_version, void* data) { + PushCall([this, game, game_version, data] { + g_platform->GetFriendScores(game, game_version, data); + }); +} + +void App::PushSubmitScoreCall(const std::string& game, + const std::string& game_version, int64_t score) { + PushCall([this, game, game_version, score] { + g_platform->SubmitScore(game, game_version, score); + }); +} + +void App::PushAchievementReportCall(const std::string& achievement) { + PushCall([this, achievement] { g_platform->ReportAchievement(achievement); }); +} + +void App::PushStringEditCall(const std::string& name, const std::string& value, + int max_chars) { + PushCall([this, name, value, max_chars] { + static millisecs_t last_edit_time = 0; + millisecs_t t = GetRealTime(); + + // Ignore if too close together. + // (in case second request comes in before first takes effect). + if (t - last_edit_time < 1000) { + return; + } + last_edit_time = t; + assert(InMainThread()); + g_platform->EditText(name, value, max_chars); + }); +} + +void App::PushSetStressTestingCall(bool enable, int player_count) { + PushCall([this, enable, player_count] { + bool was_stress_testing = stress_testing_; + stress_testing_ = enable; + stress_test_player_count_ = player_count; + + // If we're turning on, reset our intervals and things. + if (!was_stress_testing && stress_testing_) { + // So our first sample is 1 interval from now... + last_stress_test_update_time_ = GetRealTime(); + // Reset our frames-rendered tally. + if (g_graphics && g_graphics_server->renderer()) { + last_total_frames_rendered_ = + g_graphics_server->renderer()->total_frames_rendered(); + } else { + // Assume zero if there's no graphics yet. + last_total_frames_rendered_ = 0; + } + } + }); +} + +void App::PushResetAchievementsCall() { + PushCall([this] { g_platform->ResetAchievements(); }); +} + +void App::OnBootstrapComplete() { + assert(InMainThread()); + assert(g_input); + + if (!HeadlessMode()) { + // On desktop systems we just assume keyboard input exists and add it + // immediately. + if (g_platform->IsRunningOnDesktop()) { + g_input->PushCreateKeyboardInputDevices(); + } + + // On non-tv, non-desktop, non-vr systems, create a touchscreen input. + if (!g_platform->IsRunningOnTV() && !IsVRMode() + && !g_platform->IsRunningOnDesktop()) { + g_input->CreateTouchInput(); + } + } +} + +void App::PushCursorUpdate(bool vis) { + PushCall([this, vis] { + assert(InMainThread()); + g_platform->SetHardwareCursorVisible(vis); + }); +} + +void App::UpdateStressTesting() { + // Handle a little misc stuff here. + // If we're currently running stress-tests, update that stuff. + if (stress_testing_ && g_input) { + // Update our fake inputs to make our dudes run around. + g_input->ProcessStressTesting(stress_test_player_count_); + + // Every 10 seconds update our stress-test stats. + millisecs_t t = GetRealTime(); + if (t - last_stress_test_update_time_ >= 10000) { + if (stress_test_stats_file_ == nullptr) { + assert(g_platform); + std::string f_name = + g_platform->GetUserPythonDirectory() + "/stress_test_stats.csv"; + stress_test_stats_file_ = g_platform->FOpen(f_name.c_str(), "wb"); + if (stress_test_stats_file_ != nullptr) { + fprintf(stress_test_stats_file_, + "time,averageFps,nodes,models,collideModels,textures,sounds," + "pssMem,sharedDirtyMem,privateDirtyMem\n"); + fflush(stress_test_stats_file_); + if (g_buildconfig.ostype_android()) { + // On android, let the OS know we've added or removed a file + // (limit to android or we'll get an unimplemented warning) + g_platform->AndroidRefreshFile(f_name); + } + } + } + if (stress_test_stats_file_ != nullptr) { + // See how many frames we've rendered this past interval. + int total_frames_rendered; + if (g_graphics && g_graphics_server->renderer()) { + total_frames_rendered = + g_graphics_server->renderer()->total_frames_rendered(); + } else { + total_frames_rendered = last_total_frames_rendered_; + } + float avg = + static_cast(total_frames_rendered + - last_total_frames_rendered_) + / (static_cast(t - last_stress_test_update_time_) / 1000.0f); + last_total_frames_rendered_ = total_frames_rendered; + uint32_t model_count = 0; + uint32_t collide_model_count = 0; + uint32_t texture_count = 0; + uint32_t sound_count = 0; + uint32_t node_count = 0; + if (g_media) { + model_count = g_media->total_model_count(); + collide_model_count = g_media->total_collide_model_count(); + texture_count = g_media->total_texture_count(); + sound_count = g_media->total_sound_count(); + } + assert(g_game); + std::string mem_usage = g_platform->GetMemUsageInfo(); + fprintf(stress_test_stats_file_, "%d,%.1f,%d,%d,%d,%d,%d,%s\n", + static_cast(GetRealTime()), avg, node_count, model_count, + collide_model_count, texture_count, sound_count, + mem_usage.c_str()); + fflush(stress_test_stats_file_); + } + last_stress_test_update_time_ = t; + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/app/app.h b/src/ballistica/app/app.h new file mode 100644 index 00000000..655aad86 --- /dev/null +++ b/src/ballistica/app/app.h @@ -0,0 +1,148 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_APP_APP_H_ +#define BALLISTICA_APP_APP_H_ + +#include +#include +#include + +#include "ballistica/core/module.h" + +namespace ballistica { + +/// Our high level app interface module. +/// It runs in the main thread and is what platform wrappers +/// should primarily interact with. +class App : public Module { + public: + explicit App(Thread* thread); + ~App() override; + + /// This gets run after the constructor completes. + /// Any setup that may trigger a virtual method/etc. should go here. + void PostInit(); + + /// Return whether this class runs its own event loop. + /// If true, BallisticaMain() will continuously ask the app for events + /// until the app is quit, at which point BallisticaMain() returns. + /// If false, BallisticaMain returns immediately and it is assumed + /// that the OS handles the app lifecycle and pushes events to the app + /// via callbacks/etc. + auto UsesEventLoop() const -> bool; + + /// Called for non-event-loop apps to give them an opportunity to + /// ensure they are self-sustaining. For instance, an app relying on + /// frame-draws for its main thread event processing may need to + /// manually pump events until frame rendering begins. + virtual void PrimeEventPump(); + + /// Handle any pending OS events. + /// On normal graphical builds this is triggered by RunRenderUpkeepCycle(); + /// timer intervals for headless builds, etc. + /// Should process any pending OS events, etc. + virtual void RunEvents(); + + // These should be called by the window, view-controller, sdl, + // or whatever is driving the app. They must be called from the main thread. + + /// Should be called on mobile when the app is backgrounded. + /// Pauses threads, closes network sockets, etc. + void PauseApp(); + + auto paused() const -> bool { return actually_paused_; } + + /// Should be called on mobile when the app is foregrounded. + /// Spins threads back up, re-opens network sockets, etc. + void ResumeApp(); + + /// The last time the app was resumed (uses GetRealTime() value). + auto last_app_resume_time() const -> millisecs_t { + return last_app_resume_time_; + } + + /// Should be called when the window/screen resolution changes. + void SetScreenResolution(float width, float height); + + /// Should be called if the platform detects the GL context was lost. + void RebuildLostGLContext(); + + /// Attempt to draw a frame. + void DrawFrame(bool during_resize = false); + + /// Used on platforms where our main thread event processing is driven by + /// frame-draw commands given to us. This should be called after drawing + /// a frame in order to bring game state up to date and process OS events. + void RunRenderUpkeepCycle(); + + /// Called by the graphics-server when drawing completes for a frame. + virtual void DidFinishRenderingFrame(FrameDef* frame); + + /// Return the price of an IAP product as a human-readable string, + /// or an empty string if not found. + /// FIXME: move this to platform. + auto GetProductPrice(const std::string& product) -> std::string; + void SetProductPrice(const std::string& product, const std::string& price); + + auto done() const -> bool { return done_; } + + /// Whether we're running under ballisticacore_server.py + /// (affects some app behavior). + auto server_wrapper_managed() const -> bool { + return server_wrapper_managed_; + } + + virtual void OnBootstrapComplete(); + + // Deferred calls that can be made from other threads. + + void PushCursorUpdate(bool vis); + void PushShowOnlineScoreUICall(const std::string& show, + const std::string& game, + const std::string& game_version); + void PushGetFriendScoresCall(const std::string& game, + const std::string& game_version, void* data); + void PushSubmitScoreCall(const std::string& game, + const std::string& game_version, int64_t score); + void PushAchievementReportCall(const std::string& achievement); + void PushGetScoresToBeatCall(const std::string& level, + const std::string& config, void* py_callback); + void PushOpenURLCall(const std::string& url); + void PushStringEditCall(const std::string& name, const std::string& value, + int max_chars); + void PushSetStressTestingCall(bool enable, int player_count); + void PushPurchaseCall(const std::string& item); + void PushRestorePurchasesCall(); + void PushResetAchievementsCall(); + void PushPurchaseAckCall(const std::string& purchase, + const std::string& order_id); + void PushNetworkSetupCall(int port, int telnet_port, bool enable_telnet, + const std::string& telnet_password); + void PushShutdownCompleteCall(); + void PushInterruptSignalSetupCall(); + + private: + void UpdateStressTesting(); + void UpdatePauseResume(); + void OnPause(); + void OnResume(); + void ShutdownComplete(); + bool done_{}; + bool server_wrapper_managed_{}; + bool sys_paused_app_{}; + bool user_paused_app_{}; + bool actually_paused_{}; + millisecs_t last_resize_draw_event_time_{}; + millisecs_t last_app_resume_time_{}; + std::map product_prices_; + std::mutex product_prices_mutex_; + FILE* stress_test_stats_file_{}; + millisecs_t last_stress_test_update_time_{}; + int last_total_frames_rendered_{}; + bool stress_testing_{}; + int stress_test_player_count_{8}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_APP_APP_H_ diff --git a/src/ballistica/app/app_config.cc b/src/ballistica/app/app_config.cc new file mode 100644 index 00000000..5a9bbcce --- /dev/null +++ b/src/ballistica/app/app_config.cc @@ -0,0 +1,245 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/app/app_config.h" + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +void AppConfig::Init() { new AppConfig(); } + +auto AppConfig::Entry::FloatValue() const -> float { + throw Exception("not a float entry"); +} + +auto AppConfig::Entry::StringValue() const -> std::string { + throw Exception("not a string entry"); +} + +auto AppConfig::Entry::IntValue() const -> int { + throw Exception("not an int entry"); +} + +auto AppConfig::Entry::BoolValue() const -> bool { + throw Exception("not a bool entry"); +} + +auto AppConfig::Entry::DefaultFloatValue() const -> float { + throw Exception("not a float entry"); +} + +auto AppConfig::Entry::DefaultStringValue() const -> std::string { + throw Exception("not a string entry"); +} + +auto AppConfig::Entry::DefaultIntValue() const -> int { + throw Exception("not an int entry"); +} + +auto AppConfig::Entry::DefaultBoolValue() const -> bool { + throw Exception("not a bool entry"); +} + +class AppConfig::StringEntry : public AppConfig::Entry { + public: + StringEntry() = default; + StringEntry(const char* name, std::string default_value) + : Entry(name), default_value_(std::move(default_value)) {} + auto GetType() const -> Type override { return Type::kString; } + auto Resolve() const -> std::string { + return g_python->GetRawConfigValue(name().c_str(), default_value_.c_str()); + } + auto StringValue() const -> std::string override { return Resolve(); } + auto DefaultStringValue() const -> std::string override { + return default_value_; + } + + private: + std::string default_value_; +}; + +class AppConfig::FloatEntry : public AppConfig::Entry { + public: + FloatEntry() = default; + FloatEntry(const char* name, float default_value) + : Entry(name), default_value_(default_value) {} + auto GetType() const -> Type override { return Type::kFloat; } + auto Resolve() const -> float { + return g_python->GetRawConfigValue(name().c_str(), default_value_); + } + auto FloatValue() const -> float override { return Resolve(); } + auto DefaultFloatValue() const -> float override { return default_value_; } + + private: + float default_value_{}; +}; + +class AppConfig::IntEntry : public AppConfig::Entry { + public: + IntEntry() = default; + IntEntry(const char* name, int default_value) + : Entry(name), default_value_(default_value) {} + auto GetType() const -> Type override { return Type::kInt; } + auto Resolve() const -> int { + return g_python->GetRawConfigValue(name().c_str(), default_value_); + } + auto IntValue() const -> int override { return Resolve(); } + auto DefaultIntValue() const -> int override { return default_value_; } + + private: + int default_value_{}; +}; + +class AppConfig::BoolEntry : public AppConfig::Entry { + public: + BoolEntry() = default; + BoolEntry(const char* name, bool default_value) + : Entry(name), default_value_(default_value) {} + auto GetType() const -> Type override { return Type::kBool; } + auto Resolve() const -> bool { + return g_python->GetRawConfigValue(name().c_str(), default_value_); + } + auto BoolValue() const -> bool override { return Resolve(); } + auto DefaultBoolValue() const -> bool override { return default_value_; } + + private: + bool default_value_{}; +}; + +AppConfig::AppConfig() { + // (We're a singleton). + assert(g_app_config == nullptr); + g_app_config = this; + SetupEntries(); +} + +template +void AppConfig::CompleteMap(const T& entry_map) { + for (auto&& i : entry_map) { + assert(entries_by_name_.find(i.second.name()) == entries_by_name_.end()); + assert(i.first < decltype(i.first)::kLast); + entries_by_name_[i.second.name()] = &i.second; + } + + // Make sure all values have entries. +#if BA_DEBUG_BUILD + int last = static_cast(decltype(entry_map.begin()->first)::kLast); // ew + for (int j = 0; j < last; ++j) { + auto i2 = + entry_map.find(static_castfirst)>(j)); + if (i2 == entry_map.end()) { + throw Exception("Missing appconfig entry " + std::to_string(j)); + } + } +#endif +} + +void AppConfig::SetupEntries() { + // Register all our typed entries. + float_entries_[FloatID::kScreenGamma] = FloatEntry("Screen Gamma", 1.0F); + float_entries_[FloatID::kScreenPixelScale] = + FloatEntry("Screen Pixel Scale", 1.0F); + float_entries_[FloatID::kTouchControlsScale] = + FloatEntry("Touch Controls Scale", 1.0F); + float_entries_[FloatID::kTouchControlsScaleMovement] = + FloatEntry("Touch Controls Scale Movement", 1.0F); + float_entries_[FloatID::kTouchControlsScaleActions] = + FloatEntry("Touch Controls Scale Actions", 1.0F); + float_entries_[FloatID::kSoundVolume] = FloatEntry("Sound Volume", 1.0F); + float_entries_[FloatID::kMusicVolume] = FloatEntry("Music Volume", 1.0F); + + // Note: keep this synced with the defaults in MainActivity.java. + float gvrrts_default = g_platform->IsRunningOnDaydream() ? 1.0F : 0.5F; + float_entries_[FloatID::kGoogleVRRenderTargetScale] = + FloatEntry("GVR Render Target Scale", gvrrts_default); + + string_entries_[StringID::kResolutionAndroid] = + StringEntry("Resolution (Android)", "Auto"); + string_entries_[StringID::kTouchActionControlType] = + StringEntry("Touch Action Control Type", "buttons"); + string_entries_[StringID::kTouchMovementControlType] = + StringEntry("Touch Movement Control Type", "swipe"); + string_entries_[StringID::kGraphicsQuality] = + StringEntry("Graphics Quality", "Auto"); + string_entries_[StringID::kTextureQuality] = + StringEntry("Texture Quality", "Auto"); + string_entries_[StringID::kVerticalSync] = + StringEntry("Vertical Sync", "Auto"); + string_entries_[StringID::kVRHeadRelativeAudio] = + StringEntry("VR Head Relative Audio", "Auto"); + string_entries_[StringID::kMacControllerSubsystem] = + StringEntry("Mac Controller Subsystem", "Classic"); + string_entries_[StringID::kTelnetPassword] = + StringEntry("Telnet Password", "changeme"); + + int_entries_[IntID::kPort] = IntEntry("Port", kDefaultPort); + int_entries_[IntID::kTelnetPort] = + IntEntry("Telnet Port", kDefaultTelnetPort); + + bool_entries_[BoolID::kTouchControlsSwipeHidden] = + BoolEntry("Touch Controls Swipe Hidden", false); + bool_entries_[BoolID::kFullscreen] = BoolEntry("Fullscreen", false); + bool_entries_[BoolID::kKickIdlePlayers] = + BoolEntry("Kick Idle Players", false); + bool_entries_[BoolID::kAlwaysUseInternalKeyboard] = + BoolEntry("Always Use Internal Keyboard", false); + bool_entries_[BoolID::kShowFPS] = BoolEntry("Show FPS", false); + bool_entries_[BoolID::kTVBorder] = + BoolEntry("TV Border", g_platform->IsRunningOnTV()); + bool_entries_[BoolID::kKeyboardP2Enabled] = + BoolEntry("Keyboard P2 Enabled", false); + bool_entries_[BoolID::kEnablePackageMods] = + BoolEntry("Enable Package Mods", false); + bool_entries_[BoolID::kChatMuted] = BoolEntry("Chat Muted", false); + bool_entries_[BoolID::kEnableRemoteApp] = + BoolEntry("Enable Remote App", true); + bool_entries_[BoolID::kEnableTelnet] = BoolEntry("Enable Telnet", true); + bool_entries_[BoolID::kDisableCameraShake] = + BoolEntry("Disable Camera Shake", false); + bool_entries_[BoolID::kDisableCameraGyro] = + BoolEntry("Disable Camera Gyro", false); + + // Now add everything to our name map and make sure all is kosher. + CompleteMap(float_entries_); + CompleteMap(int_entries_); + CompleteMap(string_entries_); + CompleteMap(bool_entries_); +} + +auto AppConfig::Resolve(FloatID id) -> float { + auto i = float_entries_.find(id); + if (i == float_entries_.end()) { + throw Exception("Invalid config entry"); + } + return i->second.Resolve(); +} + +auto AppConfig::Resolve(StringID id) -> std::string { + auto i = string_entries_.find(id); + if (i == string_entries_.end()) { + throw Exception("Invalid config entry"); + } + return i->second.Resolve(); +} + +auto AppConfig::Resolve(BoolID id) -> bool { + auto i = bool_entries_.find(id); + if (i == bool_entries_.end()) { + throw Exception("Invalid config entry"); + } + return i->second.Resolve(); +} + +auto AppConfig::Resolve(IntID id) -> int { + auto i = int_entries_.find(id); + if (i == int_entries_.end()) { + throw Exception("Invalid config entry"); + } + return i->second.Resolve(); +} + +} // namespace ballistica diff --git a/src/ballistica/app/app_config.h b/src/ballistica/app/app_config.h new file mode 100644 index 00000000..80d4d3f9 --- /dev/null +++ b/src/ballistica/app/app_config.h @@ -0,0 +1,130 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_APP_APP_CONFIG_H_ +#define BALLISTICA_APP_APP_CONFIG_H_ + +#include +#include +#include +#include + +namespace ballistica { + +// This class wrangles user config values for the app. +// The underlying config data currently lives in the Python layer, +// so at the moment these calls are only usable from the game thread, +// but that may change in the future. +class AppConfig { + public: + // Our official config values: + + enum class FloatID { + kScreenGamma, + kScreenPixelScale, + kTouchControlsScale, + kTouchControlsScaleMovement, + kTouchControlsScaleActions, + kSoundVolume, + kMusicVolume, + kGoogleVRRenderTargetScale, + kLast // Sentinel. + }; + + enum class StringID { + kResolutionAndroid, + kTouchActionControlType, + kTouchMovementControlType, + kGraphicsQuality, + kTextureQuality, + kVerticalSync, + kVRHeadRelativeAudio, + kMacControllerSubsystem, + kTelnetPassword, + kLast // Sentinel. + }; + + enum class IntID { + kPort, + kTelnetPort, + kLast // Sentinel. + }; + + enum class BoolID { + kTouchControlsSwipeHidden, + kFullscreen, + kKickIdlePlayers, + kAlwaysUseInternalKeyboard, + kShowFPS, + kTVBorder, + kKeyboardP2Enabled, + kEnablePackageMods, + kChatMuted, + kEnableRemoteApp, + kEnableTelnet, + kDisableCameraShake, + kDisableCameraGyro, + kLast // Sentinel. + }; + + class Entry { + public: + enum class Type { kString, kInt, kFloat, kBool }; + Entry() = default; + explicit Entry(const char* name) : name_(name) {} + virtual auto GetType() const -> Type = 0; + auto name() const -> const std::string& { return name_; } + virtual auto FloatValue() const -> float; + virtual auto StringValue() const -> std::string; + virtual auto IntValue() const -> int; + virtual auto BoolValue() const -> bool; + virtual auto DefaultFloatValue() const -> float; + virtual auto DefaultStringValue() const -> std::string; + virtual auto DefaultIntValue() const -> int; + virtual auto DefaultBoolValue() const -> bool; + + private: + std::string name_; + }; + + static void Init(); + AppConfig(); + + // Given specific ids, returns resolved values (fastest access). + auto Resolve(FloatID id) -> float; + auto Resolve(StringID id) -> std::string; + auto Resolve(IntID id) -> int; + auto Resolve(BoolID id) -> bool; + + // Given a name, returns an entry (or nullptr). + // You should check the entry's type and request + // the corresponding typed resolved value from it. + auto GetEntry(const std::string& name) -> const Entry* { + auto i = entries_by_name_.find(name); + if (i == entries_by_name_.end()) { + return nullptr; + } + return i->second; + } + + auto entries_by_name() const -> const std::map& { + return entries_by_name_; + } + + private: + class StringEntry; + class FloatEntry; + class IntEntry; + class BoolEntry; + template + void CompleteMap(const T& entry_map); + void SetupEntries(); + std::map entries_by_name_; + std::map float_entries_; + std::map int_entries_; + std::map string_entries_; + std::map bool_entries_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_APP_APP_CONFIG_H_ diff --git a/src/ballistica/app/app_globals.cc b/src/ballistica/app/app_globals.cc new file mode 100644 index 00000000..3afbb3fe --- /dev/null +++ b/src/ballistica/app/app_globals.cc @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/app/app_globals.h" + +namespace ballistica { + +AppGlobals::AppGlobals(int argc_in, char** argv_in) + : argc{argc_in}, + argv{argv_in}, + main_thread_id{std::this_thread::get_id()} {} + +} // namespace ballistica diff --git a/src/ballistica/app/app_globals.h b/src/ballistica/app/app_globals.h new file mode 100644 index 00000000..7af2803e --- /dev/null +++ b/src/ballistica/app/app_globals.h @@ -0,0 +1,99 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_APP_APP_GLOBALS_H_ +#define BALLISTICA_APP_APP_GLOBALS_H_ + +#include +#include +#include +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/networking/master_server_config.h" + +namespace ballistica { + +// The first thing the engine does is allocate an instance of this as g_globals. +// As much as possible, previously static/global values should be moved to here, +// ideally as a temporary measure until they can be placed as non-static members +// in the proper classes. +// Any use of non-trivial global/static values such as class instances should be +// avoided since it can introduce ambiguities during init and teardown. +// For more explanation, see the 'Static and Global Variables' section in the +// Google C++ Style Guide. +class AppGlobals { + public: + AppGlobals(int argc, char** argv); + + /// Program argument count (on applicable platforms). + int argc{}; + + /// Program argument values (on applicable platforms). + char** argv{}; + + std::map node_types; + std::map node_types_by_id; + std::map node_message_types; + std::vector node_message_formats; + std::string calced_blessing_hash; + bool have_mods{}; + bool replay_open{}; + std::vector pausable_threads; + TouchInput* touch_input{}; + std::string console_startup_messages; + std::mutex log_mutex; + std::string log; + bool put_log{}; + bool log_full{}; + int master_server_source{1}; + int session_count{}; + bool shutting_down{}; + bool have_incentivized_ad{true}; + bool should_pause{}; + TelnetServer* telnet_server{}; + Console* console{}; + bool reset_vr_orientation{}; + bool user_ran_commands{}; + UIScale ui_scale{UIScale::kLarge}; + AccountType account_type{AccountType::kInvalid}; + bool remote_server_accepting_connections{true}; + std::string game_commands; + std::string user_agent_string{"BA_USER_AGENT_UNSET (" BA_PLATFORM_STRING ")"}; + int return_value{}; + bool is_stdin_a_terminal{true}; + std::thread::id main_thread_id{}; + bool is_bootstrapped{}; + bool args_handled{}; + std::string user_config_dir; + bool started_suicide{}; + + // Netplay testing. + int buffer_time{1000 / 30}; + + // How often we send dynamics sync packets. + int dynamics_sync_time{500}; + + // How many steps we sample for each bucket. + int delay_samples{20}; + + bool vr_mode{g_buildconfig.vr_build()}; + // Temp dirty way to do some shutdown stuff (FIXME: move to an App method). + void (*temp_cleanup_callback)() = nullptr; + millisecs_t real_time{}; + millisecs_t last_real_time_ticks{}; + std::mutex real_time_mutex; + std::mutex thread_name_map_mutex; + std::map thread_name_map; + std::string master_server_addr{BA_MASTER_SERVER_DEFAULT_ADDR}; + std::string master_server_fallback_addr{BA_MASTER_SERVER_FALLBACK_ADDR}; +#if BA_DEBUG_BUILD + std::mutex object_list_mutex; + Object* object_list_first{}; + int object_count{0}; +#endif +}; + +} // namespace ballistica + +#endif // BALLISTICA_APP_APP_GLOBALS_H_ diff --git a/src/ballistica/app/headless_app.cc b/src/ballistica/app/headless_app.cc new file mode 100644 index 00000000..6d88748e --- /dev/null +++ b/src/ballistica/app/headless_app.cc @@ -0,0 +1,21 @@ +// Copyright (c) 2011-2020 Eric Froemling +#if BA_HEADLESS_BUILD + +#include "ballistica/app/headless_app.h" + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// We could technically use the vanilla App class here since we're not +// changing anything. +HeadlessApp::HeadlessApp(Thread* thread) : App(thread) { + // NewThreadTimer(10, true, NewLambdaRunnable([this] { + // assert(g_app); + // g_app->RunEvents(); + // })); +} + +} // namespace ballistica + +#endif // BA_HEADLESS_BUILD diff --git a/src/ballistica/app/headless_app.h b/src/ballistica/app/headless_app.h new file mode 100644 index 00000000..660b7213 --- /dev/null +++ b/src/ballistica/app/headless_app.h @@ -0,0 +1,20 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_APP_HEADLESS_APP_H_ +#define BALLISTICA_APP_HEADLESS_APP_H_ +#if BA_HEADLESS_BUILD + +#include "ballistica/app/app.h" +#include "ballistica/core/thread.h" + +namespace ballistica { + +class HeadlessApp : public App { + public: + explicit HeadlessApp(Thread* thread); +}; + +} // namespace ballistica + +#endif // BA_HEADLESS_BUILD +#endif // BALLISTICA_APP_HEADLESS_APP_H_ diff --git a/src/ballistica/app/stress_test.cc b/src/ballistica/app/stress_test.cc new file mode 100644 index 00000000..4846e9ac --- /dev/null +++ b/src/ballistica/app/stress_test.cc @@ -0,0 +1,101 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/app/stress_test.h" + +#include "ballistica/ballistica.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/input/input.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +void StressTest::Update() { + assert(InMainThread()); + + // Handle a little misc stuff here. + // If we're currently running stress-tests, update that stuff. + if (stress_testing_ && g_input) { + // Update our fake inputs to make our dudes run around. + g_input->ProcessStressTesting(stress_test_player_count_); + + // Every 10 seconds update our stress-test stats. + millisecs_t t = GetRealTime(); + if (t - last_stress_test_update_time_ >= 10000) { + if (stress_test_stats_file_ == nullptr) { + assert(g_platform); + std::string f_name = + g_platform->GetUserPythonDirectory() + "/stress_test_stats.csv"; + stress_test_stats_file_ = g_platform->FOpen(f_name.c_str(), "wb"); + if (stress_test_stats_file_ != nullptr) { + fprintf(stress_test_stats_file_, + "time,averageFps,nodes,models,collide_models,textures,sounds," + "pssMem,sharedDirtyMem,privateDirtyMem\n"); + fflush(stress_test_stats_file_); + if (g_buildconfig.ostype_android()) { + // On android, let the OS know we've added or removed a file + // (limit to android or we'll get an unimplemented warning). + g_platform->AndroidRefreshFile(f_name); + } + } + } + if (stress_test_stats_file_ != nullptr) { + // See how many frames we've rendered this past interval. + int total_frames_rendered; + if (g_graphics_server && g_graphics_server->renderer()) { + total_frames_rendered = + g_graphics_server->renderer()->total_frames_rendered(); + } else { + total_frames_rendered = last_total_frames_rendered_; + } + float avg = + static_cast(total_frames_rendered + - last_total_frames_rendered_) + / (static_cast(t - last_stress_test_update_time_) / 1000.0f); + last_total_frames_rendered_ = total_frames_rendered; + uint32_t model_count = 0; + uint32_t collide_model_count = 0; + uint32_t texture_count = 0; + uint32_t sound_count = 0; + uint32_t node_count = 0; + if (g_media) { + model_count = g_media->total_model_count(); + collide_model_count = g_media->total_collide_model_count(); + texture_count = g_media->total_texture_count(); + sound_count = g_media->total_sound_count(); + } + assert(g_game); + std::string mem_usage = g_platform->GetMemUsageInfo(); + fprintf(stress_test_stats_file_, "%d,%.1f,%d,%d,%d,%d,%d,%s\n", + static_cast_check_fit(GetRealTime()), avg, node_count, + model_count, collide_model_count, texture_count, sound_count, + mem_usage.c_str()); + fflush(stress_test_stats_file_); + } + last_stress_test_update_time_ = t; + } + } +} + +void StressTest::Set(bool enable, int player_count) { + assert(InMainThread()); + bool was_stress_testing = stress_testing_; + stress_testing_ = enable; + stress_test_player_count_ = player_count; + + // If we're turning on, reset our intervals and things. + if (!was_stress_testing && stress_testing_) { + // So our first sample is 1 interval from now. + last_stress_test_update_time_ = GetRealTime(); + + // Reset our frames-rendered tally. + if (g_graphics_server && g_graphics_server->renderer()) { + last_total_frames_rendered_ = + g_graphics_server->renderer()->total_frames_rendered(); + } else { + // Assume zero if there's no graphics yet. + last_total_frames_rendered_ = 0; + } + } +} +} // namespace ballistica diff --git a/src/ballistica/app/stress_test.h b/src/ballistica/app/stress_test.h new file mode 100644 index 00000000..89c8bed3 --- /dev/null +++ b/src/ballistica/app/stress_test.h @@ -0,0 +1,29 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_APP_STRESS_TEST_H_ +#define BALLISTICA_APP_STRESS_TEST_H_ + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// FIXME: This is not wired up; I just moved things here from App. +class StressTest { + public: + // This used to be a SetStressTesting() call in App. + void Set(bool enable, int player_count); + + // This used to get run from RunEvents() in App. + void Update(); + + private: + FILE* stress_test_stats_file_{}; + millisecs_t last_stress_test_update_time_{}; + bool stress_testing_{}; + int stress_test_player_count_{8}; + int last_total_frames_rendered_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_APP_STRESS_TEST_H_ diff --git a/src/ballistica/app/vr_app.cc b/src/ballistica/app/vr_app.cc new file mode 100644 index 00000000..e7d8909e --- /dev/null +++ b/src/ballistica/app/vr_app.cc @@ -0,0 +1,110 @@ +// Copyright (c) 2011-2020 Eric Froemling +#if BA_VR_BUILD + +#include "ballistica/app/vr_app.h" + +#include "ballistica/game/game.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +VRApp::VRApp(Thread* thread) : App(thread) {} + +void VRApp::PushVRSimpleRemoteStateCall(const VRSimpleRemoteState& state) { + PushCall([this, state] { + // Convert this to a full hands state, adding in some simple elbow + // positioning of our own and left/right. + VRHandsState s; + s.l.tx = -0.2f; + s.l.ty = -0.2f; + s.l.tz = -0.3f; + + // Hmm; for now lets always assign this as right hand even when its in + // left-handed mode to keep things simple on the back-end. Can change later + // if there's a downside to that. + s.r.type = VRHandType::kDaydreamRemote; + s.r.tx = 0.2f; + s.r.ty = -0.2f; + s.r.tz = -0.3f; + s.r.yaw = state.r0; + s.r.pitch = state.r1; + s.r.roll = state.r2; + VRSetHands(s); + }); +} + +void VRApp::VRSetDrawDimensions(int w, int h) { + g_graphics_server->VideoResize(w, h); +} + +void VRApp::VRPreDraw() { + if (!g_graphics_server || !g_graphics_server->renderer()) { + return; + } + assert(InMainThread()); + if (FrameDef* frame_def = g_graphics_server->GetRenderFrameDef()) { + // Note: this could be part of PreprocessRenderFrameDef but + // the non-vr path needs it to be separate since preprocess doesn't + // happen sometimes. Should probably clean that up. + g_graphics_server->RunFrameDefMeshUpdates(frame_def); + + // store this for the duration of this frame + vr_render_frame_def_ = frame_def; + g_graphics_server->PreprocessRenderFrameDef(frame_def); + } +} + +void VRApp::VRPostDraw() { + assert(InMainThread()); + if (!g_graphics_server || !g_graphics_server->renderer()) { + return; + } + if (vr_render_frame_def_) { + g_graphics_server->FinishRenderFrameDef(vr_render_frame_def_); + vr_render_frame_def_ = nullptr; + } + RunRenderUpkeepCycle(); +} + +void VRApp::VRSetHead(float tx, float ty, float tz, float yaw, float pitch, + float roll) { + assert(InMainThread()); + Renderer* renderer = g_graphics_server->renderer(); + if (renderer == nullptr) return; + renderer->VRSetHead(tx, ty, tz, yaw, pitch, roll); +} + +void VRApp::VRSetHands(const VRHandsState& state) { + assert(InMainThread()); + + // Pass this along to the renderer (in this same thread) for drawing + // (so hands can be drawn at their absolute most up-to-date positions, etc). + Renderer* renderer = g_graphics_server->renderer(); + if (renderer == nullptr) return; + renderer->VRSetHands(state); + + // ALSO ship it off to the game/ui thread to actually handle input from it. + g_game->PushVRHandsState(state); +} + +void VRApp::VRDrawEye(int eye, float yaw, float pitch, float roll, float tan_l, + float tan_r, float tan_b, float tan_t, float eye_x, + float eye_y, float eye_z, int viewport_x, + int viewport_y) { + if (!g_graphics_server || !g_graphics_server->renderer()) { + return; + } + assert(InMainThread()); + if (vr_render_frame_def_) { + // set up VR eye stuff... + Renderer* renderer = g_graphics_server->renderer(); + renderer->VRSetEye(eye, yaw, pitch, roll, tan_l, tan_r, tan_b, tan_t, eye_x, + eye_y, eye_z, viewport_x, viewport_y); + g_graphics_server->DrawRenderFrameDef(vr_render_frame_def_); + } +} + +} // namespace ballistica + +#endif // BA_VR_BUILD diff --git a/src/ballistica/app/vr_app.h b/src/ballistica/app/vr_app.h new file mode 100644 index 00000000..ffa0b694 --- /dev/null +++ b/src/ballistica/app/vr_app.h @@ -0,0 +1,48 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_APP_VR_APP_H_ +#define BALLISTICA_APP_VR_APP_H_ + +#if BA_VR_BUILD + +#include "ballistica/app/app.h" + +namespace ballistica { + +class VRApp : public App { + public: + /// For passing in state of Daydream remote (and maybe gear vr?..). + struct VRSimpleRemoteState { + bool right_handed = true; + float r0 = 0.0f; + float r1 = 0.0f; + float r2 = 0.0f; + }; + + /// Return g_app as a VRApp. (assumes it actually is one). + static VRApp* get() { + assert(g_app != nullptr); + assert(dynamic_cast(g_app) == static_cast(g_app)); + return static_cast(g_app); + } + + explicit VRApp(Thread* thread); + void PushVRSimpleRemoteStateCall(const VRSimpleRemoteState& state); + void VRSetDrawDimensions(int w, int h); + void VRPreDraw(); + void VRPostDraw(); + void VRSetHead(float tx, float ty, float tz, float yaw, float pitch, + float roll); + void VRSetHands(const VRHandsState& state); + void VRDrawEye(int eye, float yaw, float pitch, float roll, float tan_l, + float tan_r, float tan_b, float tan_t, float eye_x, + float eye_y, float eye_z, int viewport_x, int viewport_y); + + private: + FrameDef* vr_render_frame_def_{}; +}; + +} // namespace ballistica + +#endif // BA_VR_BUILD +#endif // BALLISTICA_APP_VR_APP_H_ From 4e179475e818b67acd2e9580eaadecbd7a337e75 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 16:49:45 -0500 Subject: [PATCH 217/417] CMake Makefile targets --- .efrocachemap | 20 +++++------ Makefile | 64 +++++++++++++++++++++++++++++++++++- src/ballistica/ballistica.cc | 2 +- 3 files changed, 74 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 0ff4b268..49d3120d 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d0/21/cb738075207c3dab9f2389455a69", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/cd/44/d59a1f7d6ee05b58e80ebc3469bf", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b4/56/6d1f390d348ddf65937af3374d76", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/31/b9/176ba76e48c23d064b6583963a0e", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/37/18/56c6d3b8788362ceb97005b6b3b6", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a6/bd/da7954fe559403d021b15df72967", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/97/10/138625f676793653620a84cd712b", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ef/a8/4b532f37f74929b834ffd6c2ac5d", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3f/6f/c49674367960a82b19a45641daa6", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/df/a3/90e19f2ef6b2edd17d0f936245f2" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/55/e7/7493c35661e347a164ccc9a6e150", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f4/a8/5f874f2c8ee0de54649b3142c2c5", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/cd/e155776004a096cd1981e8c45539", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/44/90/8453cc086294eaf8bd15f4df8332", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/98/2363d625af50c24c6ef3d2e9c58d", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/fd/1b7ecd5d084ea0e52974e463b0be", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1c/76/bb6e52f9bd7d50695d587419f0e4", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/74/61/d3c6283c0136cd3036da24ee7857", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dc/56/9638fcadf876b2dc14ae42a4eb13", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/34/04/47dc06bfb943ef4c41b19394f45a" } \ No newline at end of file diff --git a/Makefile b/Makefile index a33ce896..7910e969 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ help: PREREQS = .cache/checkenv .dir-locals.el \ .mypy.ini .pycheckers .pylintrc .style.yapf .clang-format \ - .projectile .editorconfig + ballisticacore-cmake/.clang-format .projectile .editorconfig # Target that should be built before running most any other build. # This installs tool config files, runs environment checks, etc. @@ -635,6 +635,57 @@ preflight2-full: .PHONY: preflight preflight-full preflight2 preflight2-full +################################################################################ +# # +# CMake # +# # +################################################################################ + +# Set the following from the command line to influence the build: + +# This can be Debug or Release +CMAKE_BUILD_TYPE ?= Debug + +# Host to use when building via cloudshell +CMAKE_CLOUDSHELL_HOST ?= linbeast + +# Base names for assembled packages +CMAKE_CLOUDSHELL_PACKAGE_NAME ?= BallisticaCore +CMAKE_CLOUDSHELL_SERVER_PACKAGE_NAME ?= BallisticaCore_Server + +# Build and run the cmake build. +cmake: cmake-build + @cd ballisticacore-cmake/build/$(CM_BT_LC) && ./ballisticacore + +# Build but don't run it. +cmake-build: assets-cmake resources code + @tools/pcommand cmake_prep_dir ballisticacore-cmake/build/$(CM_BT_LC) + @${STAGE_ASSETS} -cmake ballisticacore-cmake/build/$(CM_BT_LC) + @cd ballisticacore-cmake/build/$(CM_BT_LC) && test -f Makefile \ + || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) ../.. + @cd ballisticacore-cmake/build/$(CM_BT_LC) && ${MAKE} -j${CPUS} + +cmake-clean: + rm -rf ballisticacore-cmake/build/$(CM_BT_LC) + +cmake-server: cmake-server-build + @cd ballisticacore-cmake/build/server-$(CM_BT_LC) && ./ballisticacore + +cmake-server-build: assets-cmake resources code + @tools/pcommand cmake_prep_dir ballisticacore-cmake/build/server-$(CM_BT_LC) + @${STAGE_ASSETS} -cmakeserver ballisticacore-cmake/build/server-$(CM_BT_LC) + @cd ballisticacore-cmake/build/server-$(CM_BT_LC) && test -f Makefile \ + || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true ../.. + @cd ballisticacore-cmake/build/server-$(CM_BT_LC) && ${MAKE} -j${CPUS} + +cmake-server-clean: + rm -rf ballisticacore-cmake/build/server-$(CM_BT_LC) + +# Tell make which of these targets don't represent files. +.PHONY: cmake cmake-build cmake-clean cmake-server cmake-server-build \ + cmake-server-clean + + ################################################################################ # # # Auxiliary # @@ -699,3 +750,14 @@ ENV_SRC = tools/pcommand tools/batools/build.py # Tell make which of these targets don't represent files. .PHONY: + + +################################################################################ +# # +# Auxiliary # +# # +################################################################################ + +# When using CLion, our cmake dir is root. Expose .clang-format there too. +ballisticacore-cmake/.clang-format: .clang-format + @cd ballisticacore-cmake && ln -sf ../.clang-format . diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 82fa265b..8c0228e7 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,7 +29,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20192; +const int kAppBuildNumber = 20193; const char* kAppVersion = "1.5.26"; const char* kBlessingHash = nullptr; From e21082406fd209c595de4360176076878910a5c7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Thu, 1 Oct 2020 17:09:10 -0500 Subject: [PATCH 218/417] Language updates --- .efrocachemap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 49d3120d..ac242c83 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,8 +420,8 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/05/e9/af148b65bebed06c6574f60a6c34", - "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/d0/7c/87e7c5b3685a64f0a3ecd9a16b99", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/86/81/74172efe05c0e0508abf24e2de32", + "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/de/25/74be4875c2a0e22b813a4e1a103b", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", "assets/build/ba_data/data/languages/chinesetraditional.json": "https://files.ballistica.net/cache/ba1/5a/9e/e8cad6f08b2b19803ab20fdc80d0", @@ -440,7 +440,7 @@ "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/9a/3d/9aff685d04d2e1cabb2f9ddafcf3", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/33/04/b1c54ce2b8979cc983aecc781228", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/3e/cc/0da1886e43fa69a18a9ae5593648", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/30/f9/b4f4e8ff8e3c8372162b2c98f3e1", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/88/4b/6745a1a58220772e259f0de51196", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/42/b5/7612cce15fe4555889585108b3ef", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", From 9bc71287d1a56cfe08e27d767c81217a5f17da26 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 10:02:31 -0500 Subject: [PATCH 219/417] Bringing over more C++ stuff... --- .idea/dictionaries/ericf.xml | 12 ++++++------ Makefile | 12 +++++++++++- resources/Makefile | 8 ++++++++ resources/README.md | 4 ++++ 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 resources/Makefile create mode 100644 resources/README.md diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index fae1c944..a1496dc2 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack'ed ack + ack'ed acked acks acnt @@ -151,8 +151,8 @@ bacommon badguy bafoundation - ballistica's ballistica + ballistica's ballisticacore ballisticacorecb bamaster @@ -793,8 +793,8 @@ gamedata gameinstance gamemap - gamepad's gamepad + gamepad's gamepadadvanced gamepads gamepadselect @@ -1177,8 +1177,8 @@ lsqlite lssl lstart - lstr's lstr + lstr's lstrs lsval ltex @@ -1803,8 +1803,8 @@ sessionname sessionplayer sessionplayers - sessionteam's sessionteam + sessionteam's sessionteams sessiontype setactivity @@ -2134,8 +2134,8 @@ txtw typeargs typecheck - typechecker's typechecker + typechecker's typedval typeshed typestr diff --git a/Makefile b/Makefile index 7910e969..850234a0 100644 --- a/Makefile +++ b/Makefile @@ -70,6 +70,16 @@ assets-android: prereqs assets-clean: @cd assets && ${MAKE} clean +# Build resources. +resources: prereqs + @tools/pcommand lazybuild resources_src ${LAZYBUILDDIR}/resources \ + cd resources \&\& ${MAKE} -j${CPUS} resources + +# Clean resources. +resources-clean: + @cd resources && ${MAKE} clean + @rm -f ${LAZYBUILDDIR}/resources + # Remove *ALL* files and directories that aren't managed by git # (except for a few things such as localconfig.json). clean: @@ -85,7 +95,7 @@ clean-list: .PHONY: list prereqs prereqs-clean assets assets-cmake assets-windows \ assets-windows-Win32 assets-windows-x64 \ assets-mac assets-ios assets-android assets-clean \ - -clean-clean\ + resources resources-clean-clean\ clean clean-list diff --git a/resources/Makefile b/resources/Makefile new file mode 100644 index 00000000..46a99a6e --- /dev/null +++ b/resources/Makefile @@ -0,0 +1,8 @@ +# Released under the MIT License. See LICENSE for details. + +# Dummy resources makefile; nothing here for now. +all: resources + +resources: + +clean: diff --git a/resources/README.md b/resources/README.md new file mode 100644 index 00000000..2d7fafc6 --- /dev/null +++ b/resources/README.md @@ -0,0 +1,4 @@ +# BallisticaCore Resources + +This directory should contain sources for a common set of resources such as icons, launch screens, etc. +Run 'make' to compile and push them to their platform-specific locations. From 4fccdb453287780ba0988e73b3c728fc3c8360e8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 10:20:47 -0500 Subject: [PATCH 220/417] Minor makefile fix --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 850234a0..7aae2ae4 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ clean-list: .PHONY: list prereqs prereqs-clean assets assets-cmake assets-windows \ assets-windows-Win32 assets-windows-x64 \ assets-mac assets-ios assets-android assets-clean \ - resources resources-clean-clean\ + resources resources-cleancode-clean \ clean clean-list From 6b92d272606e3602a3e656d98ae831e799cf676b Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 10:57:00 -0500 Subject: [PATCH 221/417] Minor makefile fix 2 --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 7aae2ae4..0a951628 100644 --- a/Makefile +++ b/Makefile @@ -95,7 +95,7 @@ clean-list: .PHONY: list prereqs prereqs-clean assets assets-cmake assets-windows \ assets-windows-Win32 assets-windows-x64 \ assets-mac assets-ios assets-android assets-clean \ - resources resources-cleancode-clean \ + resources resources-clean \ clean clean-list From b70887025208d5782db639ac730fa7695d3b2edf Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 11:09:38 -0500 Subject: [PATCH 222/417] Adding generated-code dir --- Makefile | 12 +++++++++++- src/generated_src/Makefile | 8 ++++++++ src/generated_src/README.md | 3 +++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 src/generated_src/Makefile create mode 100644 src/generated_src/README.md diff --git a/Makefile b/Makefile index 0a951628..ef60f7ff 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,16 @@ resources-clean: @cd resources && ${MAKE} clean @rm -f ${LAZYBUILDDIR}/resources +# Build our generated code. +code: prereqs + @tools/pcommand lazybuild code_gen_src ${LAZYBUILDDIR}/code \ + cd src/generated_src \&\& ${MAKE} -j${CPUS} generated_code + +# Clean generated code. +code-clean: + @cd src/generated_src && ${MAKE} clean + @rm -f ${LAZYBUILDDIR}/code + # Remove *ALL* files and directories that aren't managed by git # (except for a few things such as localconfig.json). clean: @@ -95,7 +105,7 @@ clean-list: .PHONY: list prereqs prereqs-clean assets assets-cmake assets-windows \ assets-windows-Win32 assets-windows-x64 \ assets-mac assets-ios assets-android assets-clean \ - resources resources-clean \ + resources resources-clean code code-clean \ clean clean-list diff --git a/src/generated_src/Makefile b/src/generated_src/Makefile new file mode 100644 index 00000000..d18de50a --- /dev/null +++ b/src/generated_src/Makefile @@ -0,0 +1,8 @@ +# Released under the MIT License. See LICENSE for details. + +# Dummy generated-src makefile; nothing here for now. +all: generated_code + +generated_code: + +clean: diff --git a/src/generated_src/README.md b/src/generated_src/README.md new file mode 100644 index 00000000..d336ad8e --- /dev/null +++ b/src/generated_src/README.md @@ -0,0 +1,3 @@ +# BallisticaCore Generated Files + +This directory should contain files used to generated code From d51bc6db50c414de75c3ceb6463040e65beb15b3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 11:18:43 -0500 Subject: [PATCH 223/417] Tidying --- Makefile | 14 ++++++++++++-- src/generated_src/Makefile | 8 ++++++++ src/generated_src/README.md | 3 +++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 src/generated_src/Makefile create mode 100644 src/generated_src/README.md diff --git a/Makefile b/Makefile index 0a951628..bf2fa2ec 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,17 @@ resources-clean: @cd resources && ${MAKE} clean @rm -f ${LAZYBUILDDIR}/resources -# Remove *ALL* files and directories that aren't managed by git +# Build our generated code. +code: prereqs + @tools/pcommand lazybuild code_gen_src ${LAZYBUILDDIR}/code \ + cd src/generated_src \&\& ${MAKE} -j${CPUS} generated_code + +# Clean our generated code. +code-clean: + @cd src/generated_src && ${MAKE} clean + @rm -f ${LAZYBUILDDIR}/code + +# Remove ALL files and directories that aren't managed by git # (except for a few things such as localconfig.json). clean: @${CHECK_CLEAN_SAFETY} @@ -95,7 +105,7 @@ clean-list: .PHONY: list prereqs prereqs-clean assets assets-cmake assets-windows \ assets-windows-Win32 assets-windows-x64 \ assets-mac assets-ios assets-android assets-clean \ - resources resources-clean \ + resources resources-clean code code-clean \ clean clean-list diff --git a/src/generated_src/Makefile b/src/generated_src/Makefile new file mode 100644 index 00000000..d18de50a --- /dev/null +++ b/src/generated_src/Makefile @@ -0,0 +1,8 @@ +# Released under the MIT License. See LICENSE for details. + +# Dummy generated-src makefile; nothing here for now. +all: generated_code + +generated_code: + +clean: diff --git a/src/generated_src/README.md b/src/generated_src/README.md new file mode 100644 index 00000000..d336ad8e --- /dev/null +++ b/src/generated_src/README.md @@ -0,0 +1,3 @@ +# BallisticaCore Generated Files + +This directory should contain files used to generated code From 94dbe1a946e9390ab0b6db3f3b07a4258418901c Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 11:29:20 -0500 Subject: [PATCH 224/417] More C++ work... --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index bf2fa2ec..6d8b04e7 100644 --- a/Makefile +++ b/Makefile @@ -778,6 +778,9 @@ ENV_SRC = tools/pcommand tools/batools/build.py # # ################################################################################ +# CMake build-type lowercase +CM_BT_LC = $(shell echo $(CMAKE_BUILD_TYPE) | tr A-Z a-z) + # When using CLion, our cmake dir is root. Expose .clang-format there too. ballisticacore-cmake/.clang-format: .clang-format @cd ballisticacore-cmake && ln -sf ../.clang-format . From 6f4820e05415a79fa970233cadfc6191cac944fb Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 11:50:15 -0500 Subject: [PATCH 225/417] Added C++ config headers --- .efrocachemap | 8 +- src/ballistica/config/config_cmake.h | 77 ++++++++ src/ballistica/config/config_common.h | 258 ++++++++++++++++++++++++++ 3 files changed, 339 insertions(+), 4 deletions(-) create mode 100644 src/ballistica/config/config_cmake.h create mode 100644 src/ballistica/config/config_common.h diff --git a/.efrocachemap b/.efrocachemap index ac242c83..3c3b59f8 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3940,8 +3940,8 @@ "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/44/90/8453cc086294eaf8bd15f4df8332", "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/98/2363d625af50c24c6ef3d2e9c58d", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/fd/1b7ecd5d084ea0e52974e463b0be", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/1c/76/bb6e52f9bd7d50695d587419f0e4", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/74/61/d3c6283c0136cd3036da24ee7857", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/dc/56/9638fcadf876b2dc14ae42a4eb13", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/34/04/47dc06bfb943ef4c41b19394f45a" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e8/88/8fe7875aa34660db68e74f25051d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/23/2d/8239623b2d8745b4feb4b380b12a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/2f/03140734daf10cd7e46a29c5c820", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/7a/d23e25fdda6f6b1d9ed3b03040b6" } \ No newline at end of file diff --git a/src/ballistica/config/config_cmake.h b/src/ballistica/config/config_cmake.h new file mode 100644 index 00000000..c4d71dee --- /dev/null +++ b/src/ballistica/config/config_cmake.h @@ -0,0 +1,77 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CONFIG_CONFIG_CMAKE_H_ +#define BALLISTICA_CONFIG_CONFIG_CMAKE_H_ + +// For cmake builds, attempt to figure out what architecture we're running on +// and define stuff accordingly. +#if __APPLE__ + +// Yes Apple, I know GL is deprecated. I don't need constant reminders. You're +// stressing me out. +#define GL_SILENCE_DEPRECATION + +// We currently support regular and client builds on 64 bit mac posix +#if __amd64__ +#define BA_PLATFORM_STRING "x86_64_macos" +#else +#error Unknown processor architecture. +#endif +#define BA_OSTYPE_MACOS 1 +#define HAVE_FRAMEWORK_OPENAL 1 + +#elif __linux__ + +#if __amd64__ +#define BA_PLATFORM_STRING "x86_64_linux" +#define BA_OSTYPE_LINUX 1 +#elif __i386__ +#define BA_PLATFORM_STRING "x86_32_linux" +#define BA_OSTYPE_LINUX 1 +#elif __arm__ +#define BA_PLATFORM_STRING "arm_linux" +#define BA_OSTYPE_LINUX 1 + +#else +#error unknown linux variant +#endif + +#else +#error config_cmake.h: unknown architecture +#endif + +#define dTRIMESH_ENABLED 1 + +#if !BA_HEADLESS_BUILD +#define BA_ENABLE_AUDIO 1 +#define BA_ENABLE_OPENGL 1 +#define BA_SDL_BUILD 1 +#define BA_SDL2_BUILD 1 +#define BA_ENABLE_SDL_JOYSTICKS 1 +#else +#define BA_MINSDL_BUILD 1 +#endif + +// Yup we've got that. +#define BA_ENABLE_EXECINFO_BACKTRACES 1 + +// Allow stdin commands too. +#define BA_USE_STDIN_THREAD 1 + +#define BA_DEFINE_MAIN 1 + +#if !BA_DEBUG_BUILD + +// Used by ODE. +#define dNODEBUG 1 + +// Used by assert. +#ifndef NDEBUG +#define NDEBUG +#endif +#endif // !BA_DEBUG_BUILD + +// This must always be last. +#include "ballistica/config/config_common.h" + +#endif // BALLISTICA_CONFIG_CONFIG_CMAKE_H_ diff --git a/src/ballistica/config/config_common.h b/src/ballistica/config/config_common.h new file mode 100644 index 00000000..ef5197f7 --- /dev/null +++ b/src/ballistica/config/config_common.h @@ -0,0 +1,258 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_CONFIG_CONFIG_COMMON_H_ +#define BALLISTICA_CONFIG_CONFIG_COMMON_H_ + +#ifdef __cplusplus + +#include +#include + +// This header should be included at the very END of each platform config +// header that will be directly used by a build. +namespace ballistica { + +// Default definitions for various things. Per-platform configs +// can override any of these before this is included. + +#ifndef BA_STAT +#define BA_STAT stat +#endif + +#ifndef BA_OSTYPE_WINDOWS +#define BA_OSTYPE_WINDOWS 0 +#endif + +// Are we building for macOS? +#ifndef BA_OSTYPE_MACOS +#define BA_OSTYPE_MACOS 0 +#endif + +// Are we building for iOS? (also covers iPadOS) +#ifndef BA_OSTYPE_IOS +#define BA_OSTYPE_IOS 0 +#endif + +// Are we building for tvOS? +#ifndef BA_OSTYPE_TVOS +#define BA_OSTYPE_TVOS 0 +#endif + +// Are we building for iOS OR tvOS? +#ifndef BA_OSTYPE_IOS_TVOS +#define BA_OSTYPE_IOS_TVOS 0 +#endif + +// Are we building for Android? +#ifndef BA_OSTYPE_ANDROID +#define BA_OSTYPE_ANDROID 0 +#endif + +// Are we building for Linux? +#ifndef BA_OSTYPE_LINUX +#define BA_OSTYPE_LINUX 0 +#endif + +// On windows, are we built as a console app (vs a gui app)? +#ifndef BA_WINDOWS_CONSOLE_BUILD +#define BA_WINDOWS_CONSOLE_BUILD 1 +#endif + +// Does this build support only headless mode? +#ifndef BA_HEADLESS_BUILD +#define BA_HEADLESS_BUILD 0 +#endif + +// Are we building via an XCode project? +#ifndef BA_XCODE_BUILD +#define BA_XCODE_BUILD 0 +#endif + +// Is this our android iircade build? +#ifndef BA_IIRCADE_BUILD +#define BA_IIRCADE_BUILD 0 +#endif + +// Does this build use SDL 1.x? (old mac only) +#ifndef BA_SDL_BUILD +#define BA_SDL_BUILD 0 +#endif + +// Does this build use SDL 2.x? +#ifndef BA_SDL2_BUILD +#define BA_SDL2_BUILD 0 +#endif + +// Does this build use our 'min-sdl' types? +// (basic SDL types we define ourself; no actual SDL dependency) +#ifndef BA_MINSDL_BUILD +#define BA_MINSDL_BUILD 0 +#endif + +// Is this a debug build? +#ifndef BA_DEBUG_BUILD +#define BA_DEBUG_BUILD 0 +#endif + +// Is this a test build? +#ifndef BA_TEST_BUILD +#define BA_TEST_BUILD 0 +#endif + +#ifndef BA_ENABLE_SDL_JOYSTICKS +#define BA_ENABLE_SDL_JOYSTICKS 0 +#endif + +#ifndef BA_USE_ICLOUD +#define BA_USE_ICLOUD 0 +#endif + +#ifndef BA_USE_STORE_KIT +#define BA_USE_STORE_KIT 0 +#endif + +#ifndef BA_USE_GAME_CENTER +#define BA_USE_GAME_CENTER 0 +#endif + +#ifndef BA_PLATFORM_STRING +#error platform string undefined +#endif + +#ifndef BA_USE_STDIN_THREAD +#define BA_USE_STDIN_THREAD 0 +#endif + +#ifndef BA_HARDWARE_CURSOR +#define BA_HARDWARE_CURSOR 0 +#endif + +#ifndef BA_ENABLE_OS_FONT_RENDERING +#define BA_ENABLE_OS_FONT_RENDERING 0 +#endif + +// Does this build support vr mode? (does not mean vr mode is always on) +#ifndef BA_VR_BUILD +#define BA_VR_BUILD 0 +#endif + +// Is this the Google VR build? (Cardboard/Daydream) +#ifndef BA_CARDBOARD_BUILD +#define BA_CARDBOARD_BUILD 0 +#endif + +#ifndef BA_GEARVR_BUILD +#define BA_GEARVR_BUILD 0 +#endif + +#ifndef BA_RIFT_BUILD +#define BA_RIFT_BUILD 0 +#endif + +#ifndef BA_AMAZON_BUILD +#define BA_AMAZON_BUILD 0 +#endif + +#ifndef BA_GOOGLE_BUILD +#define BA_GOOGLE_BUILD 0 +#endif + +#ifndef BA_DEMO_BUILD +#define BA_DEMO_BUILD 0 +#endif + +#ifndef BA_ARCADE_BUILD +#define BA_ARCADE_BUILD 0 +#endif + +#ifndef BA_SOCKET_SEND_DATA_TYPE +#define BA_SOCKET_SEND_DATA_TYPE uint8_t +#endif + +#ifndef BA_SOCKET_SETSOCKOPT_VAL_TYPE +#define BA_SOCKET_SETSOCKOPT_VAL_TYPE int +#endif + +#ifndef BA_SOCKET_SEND_LENGTH_TYPE +#define BA_SOCKET_SEND_LENGTH_TYPE size_t +#endif + +typedef BA_SOCKET_SEND_DATA_TYPE socket_send_data_t; +typedef BA_SOCKET_SEND_LENGTH_TYPE socket_send_length_t; + +bool InlineDebugExplicitBool(bool val); + +// Little hack so we avoid 'value is always true/false' and +// 'code will never/always be run' type warnings when using these in debug +// builds. +#if BA_DEBUG_BUILD +#define EXPBOOL_(val) InlineDebugExplicitBool(val) +#else +#define EXPBOOL_(val) val +#endif + +// We define a compile-time value g_config which contains the same config +// values as our config #defines. We should migrate towards using these values +// whenever possible instead of #if blocks, which should improve support for +// code introspection/refactoring tools and type safety while still optimizing +// out just as nicely as #ifs. (though perhaps should verify that). +// In an ideal world, we should never use #ifs/#ifdefs outside of the platform +// subdir or skipping entire files (header guards, gui stuff on headless builds, +// etc.) +class BuildConfig { + public: + const char* platform_string() const { return BA_PLATFORM_STRING; } + bool debug_build() const { return EXPBOOL_(BA_DEBUG_BUILD); } + bool test_build() const { return EXPBOOL_(BA_TEST_BUILD); } + bool headless_build() const { return EXPBOOL_(BA_HEADLESS_BUILD); } + bool windows_console_build() const { + return EXPBOOL_(BA_WINDOWS_CONSOLE_BUILD); + } + + bool sdl_build() const { return EXPBOOL_(BA_SDL_BUILD); } + bool sdl2_build() const { return EXPBOOL_(BA_SDL2_BUILD); } + bool minsdl_build() const { return EXPBOOL_(BA_MINSDL_BUILD); } + bool enable_sdl_joysticks() const { + return EXPBOOL_(BA_ENABLE_SDL_JOYSTICKS); + } + + bool ostype_windows() const { return EXPBOOL_(BA_OSTYPE_WINDOWS); } + bool ostype_macos() const { return EXPBOOL_(BA_OSTYPE_MACOS); } + bool ostype_ios() const { return EXPBOOL_(BA_OSTYPE_IOS); } + bool ostype_tvos() const { return EXPBOOL_(BA_OSTYPE_TVOS); } + bool ostype_ios_tvos() const { return EXPBOOL_(BA_OSTYPE_IOS_TVOS); } + bool ostype_android() const { return EXPBOOL_(BA_OSTYPE_ANDROID); } + bool ostype_linux() const { return EXPBOOL_(BA_OSTYPE_LINUX); } + + bool xcode_build() const { return EXPBOOL_(BA_XCODE_BUILD); } + bool vr_build() const { return EXPBOOL_(BA_VR_BUILD); } + bool cardboard_build() const { return EXPBOOL_(BA_CARDBOARD_BUILD); } + bool gearvr_build() const { return EXPBOOL_(BA_GEARVR_BUILD); } + bool rift_build() const { return EXPBOOL_(BA_RIFT_BUILD); } + bool amazon_build() const { return EXPBOOL_(BA_AMAZON_BUILD); } + bool google_build() const { return EXPBOOL_(BA_GOOGLE_BUILD); } + bool demo_build() const { return EXPBOOL_(BA_DEMO_BUILD); } + bool arcade_build() const { return EXPBOOL_(BA_ARCADE_BUILD); } + bool iircade_build() const { return EXPBOOL_(BA_IIRCADE_BUILD); } + + bool use_icloud() const { return EXPBOOL_(BA_USE_ICLOUD); } + bool use_store_kit() const { return EXPBOOL_(BA_USE_STORE_KIT); } + bool use_game_center() const { return EXPBOOL_(BA_USE_GAME_CENTER); } + bool use_stdin_thread() const { return EXPBOOL_(BA_USE_STDIN_THREAD); } + bool enable_os_font_rendering() const { + return EXPBOOL_(BA_ENABLE_OS_FONT_RENDERING); + } + bool hardware_cursor() const { return EXPBOOL_(BA_HARDWARE_CURSOR); } +}; + +#undef EXPBOOL_ + +constexpr BuildConfig g_buildconfig; + +} // namespace ballistica + +#endif // __cplusplus + +#define BA_HAVE_CONFIG + +#endif // BALLISTICA_CONFIG_CONFIG_COMMON_H_ From 8c446dd0d63aa91c63800d36847b6d6a1f0e43d3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 13:48:18 -0500 Subject: [PATCH 226/417] More C++ work --- .efrocachemap | 20 +- docs/ba_module.md | 2 +- src/ballistica/app/app_config.cc | 245 - src/ballistica/app/app_globals.cc | 12 - src/ballistica/app/app_globals.h | 3 - src/ballistica/app/headless_app.cc | 21 - src/ballistica/app/stress_test.cc | 101 - src/ballistica/app/vr_app.cc | 110 - src/ballistica/ballistica.cc | 2 +- src/ballistica/game/account.cc | 199 + src/ballistica/game/account.h | 64 + .../game/client_controller_interface.h | 22 + src/ballistica/game/friend_score_set.h | 30 + src/ballistica/game/game.cc | 3165 ++++++++ src/ballistica/game/game.h | 464 ++ src/ballistica/game/game_stream.cc | 1242 ++++ src/ballistica/game/game_stream.h | 159 + src/ballistica/game/host_activity.cc | 528 ++ src/ballistica/game/host_activity.h | 120 + src/ballistica/game/player.cc | 418 ++ src/ballistica/game/player.h | 167 + src/ballistica/game/player_spec.cc | 109 + src/ballistica/game/player_spec.h | 56 + src/ballistica/game/score_to_beat.h | 28 + src/ballistica/game/session/client_session.cc | 1070 +++ src/ballistica/game/session/client_session.h | 99 + src/ballistica/game/session/host_session.cc | 765 ++ src/ballistica/game/session/host_session.h | 131 + .../game/session/net_client_session.cc | 147 + .../game/session/net_client_session.h | 35 + .../game/session/replay_client_session.cc | 321 + .../game/session/replay_client_session.h | 43 + src/ballistica/game/session/session.cc | 36 + src/ballistica/game/session/session.h | 44 + src/ballistica/graphics/area_of_interest.cc | 19 + src/ballistica/graphics/area_of_interest.h | 33 + src/ballistica/graphics/camera.cc | 1016 +++ src/ballistica/graphics/camera.h | 152 + .../graphics/component/empty_component.h | 30 + .../graphics/component/object_component.cc | 195 + .../graphics/component/object_component.h | 166 + .../component/post_process_component.cc | 21 + .../component/post_process_component.h | 31 + .../graphics/component/render_component.cc | 83 + .../graphics/component/render_component.h | 262 + .../graphics/component/shield_component.cc | 9 + .../graphics/component/shield_component.h | 21 + .../graphics/component/simple_component.cc | 228 + .../graphics/component/simple_component.h | 185 + .../graphics/component/smoke_component.cc | 19 + .../graphics/component/smoke_component.h | 39 + .../graphics/component/special_component.cc | 12 + .../graphics/component/special_component.h | 26 + .../graphics/component/sprite_component.cc | 25 + .../graphics/component/sprite_component.h | 61 + src/ballistica/graphics/frame_def.cc | 173 + src/ballistica/graphics/frame_def.h | 228 + src/ballistica/graphics/framebuffer.h | 19 + src/ballistica/graphics/gl/gl_sys.cc | 368 + src/ballistica/graphics/gl/gl_sys.h | 201 + src/ballistica/graphics/gl/renderer_gl.cc | 6617 +++++++++++++++++ src/ballistica/graphics/gl/renderer_gl.h | 263 + src/ballistica/graphics/graphics.cc | 1868 +++++ src/ballistica/graphics/graphics.h | 424 ++ src/ballistica/graphics/graphics_server.cc | 765 ++ src/ballistica/graphics/graphics_server.h | 334 + src/ballistica/graphics/mesh/image_mesh.cc | 17 + src/ballistica/graphics/mesh/image_mesh.h | 27 + src/ballistica/graphics/mesh/mesh.h | 46 + src/ballistica/graphics/mesh/mesh_buffer.h | 28 + .../graphics/mesh/mesh_buffer_base.h | 21 + .../mesh/mesh_buffer_vertex_simple_full.h | 18 + .../mesh/mesh_buffer_vertex_smoke_full.h | 18 + .../graphics/mesh/mesh_buffer_vertex_sprite.h | 18 + src/ballistica/graphics/mesh/mesh_data.cc | 24 + src/ballistica/graphics/mesh/mesh_data.h | 42 + .../graphics/mesh/mesh_data_client_handle.cc | 17 + .../graphics/mesh/mesh_data_client_handle.h | 22 + .../graphics/mesh/mesh_index_buffer_16.h | 17 + .../graphics/mesh/mesh_index_buffer_32.h | 17 + src/ballistica/graphics/mesh/mesh_indexed.h | 41 + .../graphics/mesh/mesh_indexed_base.h | 106 + .../mesh/mesh_indexed_dual_texture_full.h | 18 + .../graphics/mesh/mesh_indexed_object_split.h | 20 + .../graphics/mesh/mesh_indexed_simple_full.h | 18 + .../graphics/mesh/mesh_indexed_simple_split.h | 20 + .../graphics/mesh/mesh_indexed_smoke_full.h | 18 + .../mesh/mesh_indexed_static_dynamic.h | 58 + .../graphics/mesh/mesh_non_indexed.h | 42 + .../graphics/mesh/mesh_renderer_data.h | 15 + src/ballistica/graphics/mesh/sprite_mesh.h | 17 + src/ballistica/graphics/mesh/text_mesh.cc | 574 ++ src/ballistica/graphics/mesh/text_mesh.h | 32 + src/ballistica/graphics/net_graph.cc | 153 + src/ballistica/graphics/net_graph.h | 27 + .../graphics/render_command_buffer.h | 576 ++ src/ballistica/graphics/render_pass.cc | 507 ++ src/ballistica/graphics/render_pass.h | 167 + src/ballistica/graphics/render_target.cc | 84 + src/ballistica/graphics/render_target.h | 47 + src/ballistica/graphics/renderer.cc | 850 +++ src/ballistica/graphics/renderer.h | 298 + .../graphics/text/font_page_map_data.h | 89 + src/ballistica/graphics/text/text_graphics.cc | 1176 +++ src/ballistica/graphics/text/text_graphics.h | 111 + src/ballistica/graphics/text/text_group.cc | 324 + src/ballistica/graphics/text/text_group.h | 85 + src/ballistica/graphics/text/text_packer.cc | 205 + src/ballistica/graphics/text/text_packer.h | 85 + src/ballistica/graphics/texture/dds.cc | 148 + src/ballistica/graphics/texture/dds.h | 157 + src/ballistica/graphics/texture/ktx.cc | 2291 ++++++ src/ballistica/graphics/texture/ktx.h | 29 + src/ballistica/graphics/texture/pvr.cc | 248 + src/ballistica/graphics/texture/pvr.h | 20 + src/ballistica/graphics/vr_graphics.cc | 336 + src/ballistica/graphics/vr_graphics.h | 86 + .../input/device/client_input_device.cc | 102 + .../input/device/client_input_device.h | 44 + src/ballistica/input/device/input_device.cc | 320 + src/ballistica/input/device/input_device.h | 182 + src/ballistica/input/device/joystick.cc | 1568 ++++ src/ballistica/input/device/joystick.h | 201 + src/ballistica/input/device/keyboard_input.cc | 471 ++ src/ballistica/input/device/keyboard_input.h | 60 + src/ballistica/input/device/test_input.cc | 148 + src/ballistica/input/device/test_input.h | 37 + src/ballistica/input/device/touch_input.cc | 1077 +++ src/ballistica/input/device/touch_input.h | 95 + src/ballistica/input/input.cc | 1842 +++++ src/ballistica/input/input.h | 195 + src/ballistica/input/remote_app.cc | 547 ++ src/ballistica/input/remote_app.h | 67 + src/ballistica/input/std_input_module.cc | 82 + src/ballistica/input/std_input_module.h | 19 + src/ballistica/math/matrix44f.cc | 340 + src/ballistica/math/matrix44f.h | 201 + src/ballistica/math/point2d.h | 17 + src/ballistica/math/random.cc | 544 ++ src/ballistica/math/random.h | 17 + src/ballistica/math/rect.h | 21 + src/ballistica/math/vector2f.h | 27 + src/ballistica/math/vector3f.cc | 51 + src/ballistica/math/vector3f.h | 200 + src/ballistica/math/vector4f.h | 33 + .../media/component/collide_model.cc | 46 + .../media/component/collide_model.h | 41 + .../media/component/cube_map_texture.cc | 21 + .../media/component/cube_map_texture.h | 32 + src/ballistica/media/component/data.cc | 45 + src/ballistica/media/component/data.h | 43 + .../media/component/media_component.cc | 37 + .../media/component/media_component.h | 63 + src/ballistica/media/component/model.cc | 45 + src/ballistica/media/component/model.h | 44 + src/ballistica/media/component/sound.cc | 44 + src/ballistica/media/component/sound.h | 37 + src/ballistica/media/component/texture.cc | 59 + src/ballistica/media/component/texture.h | 39 + .../media/data/collide_model_data.cc | 134 + .../media/data/collide_model_data.h | 47 + src/ballistica/media/data/data_data.cc | 50 + src/ballistica/media/data/data_data.h | 47 + .../media/data/media_component_data.cc | 108 + .../media/data/media_component_data.h | 136 + src/ballistica/media/data/model_data.cc | 128 + src/ballistica/media/data/model_data.h | 67 + .../media/data/model_renderer_data.h | 21 + src/ballistica/media/data/sound_data.cc | 322 + src/ballistica/media/data/sound_data.h | 58 + src/ballistica/media/data/texture_data.cc | 450 ++ src/ballistica/media/data/texture_data.h | 62 + .../media/data/texture_preload_data.cc | 577 ++ .../media/data/texture_preload_data.h | 40 + .../media/data/texture_renderer_data.h | 27 + src/ballistica/media/media.cc | 1251 ++++ src/ballistica/media/media.h | 215 + src/ballistica/media/media_server.cc | 240 + src/ballistica/media/media_server.h | 39 + src/ballistica/networking/network_reader.h | 60 + .../networking/network_write_module.h | 21 + src/ballistica/networking/networking.h | 168 + src/ballistica/networking/networking_sys.h | 30 + src/ballistica/networking/sockaddr.h | 55 + src/ballistica/networking/telnet_server.cc | 241 + src/ballistica/networking/telnet_server.h | 49 + .../platform/linux/platform_linux.cc | 72 + .../platform/linux/platform_linux.h | 29 + src/ballistica/platform/min_sdl.h | 792 ++ src/ballistica/platform/platform.cc | 1364 ++++ src/ballistica/platform/platform.h | 515 ++ src/ballistica/platform/sdl/sdl_app.cc | 614 ++ src/ballistica/platform/sdl/sdl_app.h | 65 + 193 files changed, 49975 insertions(+), 504 deletions(-) delete mode 100644 src/ballistica/app/app_config.cc delete mode 100644 src/ballistica/app/app_globals.cc delete mode 100644 src/ballistica/app/headless_app.cc delete mode 100644 src/ballistica/app/stress_test.cc delete mode 100644 src/ballistica/app/vr_app.cc create mode 100644 src/ballistica/game/account.cc create mode 100644 src/ballistica/game/account.h create mode 100644 src/ballistica/game/client_controller_interface.h create mode 100644 src/ballistica/game/friend_score_set.h create mode 100644 src/ballistica/game/game.cc create mode 100644 src/ballistica/game/game.h create mode 100644 src/ballistica/game/game_stream.cc create mode 100644 src/ballistica/game/game_stream.h create mode 100644 src/ballistica/game/host_activity.cc create mode 100644 src/ballistica/game/host_activity.h create mode 100644 src/ballistica/game/player.cc create mode 100644 src/ballistica/game/player.h create mode 100644 src/ballistica/game/player_spec.cc create mode 100644 src/ballistica/game/player_spec.h create mode 100644 src/ballistica/game/score_to_beat.h create mode 100644 src/ballistica/game/session/client_session.cc create mode 100644 src/ballistica/game/session/client_session.h create mode 100644 src/ballistica/game/session/host_session.cc create mode 100644 src/ballistica/game/session/host_session.h create mode 100644 src/ballistica/game/session/net_client_session.cc create mode 100644 src/ballistica/game/session/net_client_session.h create mode 100644 src/ballistica/game/session/replay_client_session.cc create mode 100644 src/ballistica/game/session/replay_client_session.h create mode 100644 src/ballistica/game/session/session.cc create mode 100644 src/ballistica/game/session/session.h create mode 100644 src/ballistica/graphics/area_of_interest.cc create mode 100644 src/ballistica/graphics/area_of_interest.h create mode 100644 src/ballistica/graphics/camera.cc create mode 100644 src/ballistica/graphics/camera.h create mode 100644 src/ballistica/graphics/component/empty_component.h create mode 100644 src/ballistica/graphics/component/object_component.cc create mode 100644 src/ballistica/graphics/component/object_component.h create mode 100644 src/ballistica/graphics/component/post_process_component.cc create mode 100644 src/ballistica/graphics/component/post_process_component.h create mode 100644 src/ballistica/graphics/component/render_component.cc create mode 100644 src/ballistica/graphics/component/render_component.h create mode 100644 src/ballistica/graphics/component/shield_component.cc create mode 100644 src/ballistica/graphics/component/shield_component.h create mode 100644 src/ballistica/graphics/component/simple_component.cc create mode 100644 src/ballistica/graphics/component/simple_component.h create mode 100644 src/ballistica/graphics/component/smoke_component.cc create mode 100644 src/ballistica/graphics/component/smoke_component.h create mode 100644 src/ballistica/graphics/component/special_component.cc create mode 100644 src/ballistica/graphics/component/special_component.h create mode 100644 src/ballistica/graphics/component/sprite_component.cc create mode 100644 src/ballistica/graphics/component/sprite_component.h create mode 100644 src/ballistica/graphics/frame_def.cc create mode 100644 src/ballistica/graphics/frame_def.h create mode 100644 src/ballistica/graphics/framebuffer.h create mode 100644 src/ballistica/graphics/gl/gl_sys.cc create mode 100644 src/ballistica/graphics/gl/gl_sys.h create mode 100644 src/ballistica/graphics/gl/renderer_gl.cc create mode 100644 src/ballistica/graphics/gl/renderer_gl.h create mode 100644 src/ballistica/graphics/graphics.cc create mode 100644 src/ballistica/graphics/graphics.h create mode 100644 src/ballistica/graphics/graphics_server.cc create mode 100644 src/ballistica/graphics/graphics_server.h create mode 100644 src/ballistica/graphics/mesh/image_mesh.cc create mode 100644 src/ballistica/graphics/mesh/image_mesh.h create mode 100644 src/ballistica/graphics/mesh/mesh.h create mode 100644 src/ballistica/graphics/mesh/mesh_buffer.h create mode 100644 src/ballistica/graphics/mesh/mesh_buffer_base.h create mode 100644 src/ballistica/graphics/mesh/mesh_buffer_vertex_simple_full.h create mode 100644 src/ballistica/graphics/mesh/mesh_buffer_vertex_smoke_full.h create mode 100644 src/ballistica/graphics/mesh/mesh_buffer_vertex_sprite.h create mode 100644 src/ballistica/graphics/mesh/mesh_data.cc create mode 100644 src/ballistica/graphics/mesh/mesh_data.h create mode 100644 src/ballistica/graphics/mesh/mesh_data_client_handle.cc create mode 100644 src/ballistica/graphics/mesh/mesh_data_client_handle.h create mode 100644 src/ballistica/graphics/mesh/mesh_index_buffer_16.h create mode 100644 src/ballistica/graphics/mesh/mesh_index_buffer_32.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_base.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_object_split.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_simple_full.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_simple_split.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_smoke_full.h create mode 100644 src/ballistica/graphics/mesh/mesh_indexed_static_dynamic.h create mode 100644 src/ballistica/graphics/mesh/mesh_non_indexed.h create mode 100644 src/ballistica/graphics/mesh/mesh_renderer_data.h create mode 100644 src/ballistica/graphics/mesh/sprite_mesh.h create mode 100644 src/ballistica/graphics/mesh/text_mesh.cc create mode 100644 src/ballistica/graphics/mesh/text_mesh.h create mode 100644 src/ballistica/graphics/net_graph.cc create mode 100644 src/ballistica/graphics/net_graph.h create mode 100644 src/ballistica/graphics/render_command_buffer.h create mode 100644 src/ballistica/graphics/render_pass.cc create mode 100644 src/ballistica/graphics/render_pass.h create mode 100644 src/ballistica/graphics/render_target.cc create mode 100644 src/ballistica/graphics/render_target.h create mode 100644 src/ballistica/graphics/renderer.cc create mode 100644 src/ballistica/graphics/renderer.h create mode 100644 src/ballistica/graphics/text/font_page_map_data.h create mode 100644 src/ballistica/graphics/text/text_graphics.cc create mode 100644 src/ballistica/graphics/text/text_graphics.h create mode 100644 src/ballistica/graphics/text/text_group.cc create mode 100644 src/ballistica/graphics/text/text_group.h create mode 100644 src/ballistica/graphics/text/text_packer.cc create mode 100644 src/ballistica/graphics/text/text_packer.h create mode 100644 src/ballistica/graphics/texture/dds.cc create mode 100644 src/ballistica/graphics/texture/dds.h create mode 100644 src/ballistica/graphics/texture/ktx.cc create mode 100644 src/ballistica/graphics/texture/ktx.h create mode 100644 src/ballistica/graphics/texture/pvr.cc create mode 100644 src/ballistica/graphics/texture/pvr.h create mode 100644 src/ballistica/graphics/vr_graphics.cc create mode 100644 src/ballistica/graphics/vr_graphics.h create mode 100644 src/ballistica/input/device/client_input_device.cc create mode 100644 src/ballistica/input/device/client_input_device.h create mode 100644 src/ballistica/input/device/input_device.cc create mode 100644 src/ballistica/input/device/input_device.h create mode 100644 src/ballistica/input/device/joystick.cc create mode 100644 src/ballistica/input/device/joystick.h create mode 100644 src/ballistica/input/device/keyboard_input.cc create mode 100644 src/ballistica/input/device/keyboard_input.h create mode 100644 src/ballistica/input/device/test_input.cc create mode 100644 src/ballistica/input/device/test_input.h create mode 100644 src/ballistica/input/device/touch_input.cc create mode 100644 src/ballistica/input/device/touch_input.h create mode 100644 src/ballistica/input/input.cc create mode 100644 src/ballistica/input/input.h create mode 100644 src/ballistica/input/remote_app.cc create mode 100644 src/ballistica/input/remote_app.h create mode 100644 src/ballistica/input/std_input_module.cc create mode 100644 src/ballistica/input/std_input_module.h create mode 100644 src/ballistica/math/matrix44f.cc create mode 100644 src/ballistica/math/matrix44f.h create mode 100644 src/ballistica/math/point2d.h create mode 100644 src/ballistica/math/random.cc create mode 100644 src/ballistica/math/random.h create mode 100644 src/ballistica/math/rect.h create mode 100644 src/ballistica/math/vector2f.h create mode 100644 src/ballistica/math/vector3f.cc create mode 100644 src/ballistica/math/vector3f.h create mode 100644 src/ballistica/math/vector4f.h create mode 100644 src/ballistica/media/component/collide_model.cc create mode 100644 src/ballistica/media/component/collide_model.h create mode 100644 src/ballistica/media/component/cube_map_texture.cc create mode 100644 src/ballistica/media/component/cube_map_texture.h create mode 100644 src/ballistica/media/component/data.cc create mode 100644 src/ballistica/media/component/data.h create mode 100644 src/ballistica/media/component/media_component.cc create mode 100644 src/ballistica/media/component/media_component.h create mode 100644 src/ballistica/media/component/model.cc create mode 100644 src/ballistica/media/component/model.h create mode 100644 src/ballistica/media/component/sound.cc create mode 100644 src/ballistica/media/component/sound.h create mode 100644 src/ballistica/media/component/texture.cc create mode 100644 src/ballistica/media/component/texture.h create mode 100644 src/ballistica/media/data/collide_model_data.cc create mode 100644 src/ballistica/media/data/collide_model_data.h create mode 100644 src/ballistica/media/data/data_data.cc create mode 100644 src/ballistica/media/data/data_data.h create mode 100644 src/ballistica/media/data/media_component_data.cc create mode 100644 src/ballistica/media/data/media_component_data.h create mode 100644 src/ballistica/media/data/model_data.cc create mode 100644 src/ballistica/media/data/model_data.h create mode 100644 src/ballistica/media/data/model_renderer_data.h create mode 100644 src/ballistica/media/data/sound_data.cc create mode 100644 src/ballistica/media/data/sound_data.h create mode 100644 src/ballistica/media/data/texture_data.cc create mode 100644 src/ballistica/media/data/texture_data.h create mode 100644 src/ballistica/media/data/texture_preload_data.cc create mode 100644 src/ballistica/media/data/texture_preload_data.h create mode 100644 src/ballistica/media/data/texture_renderer_data.h create mode 100644 src/ballistica/media/media.cc create mode 100644 src/ballistica/media/media.h create mode 100644 src/ballistica/media/media_server.cc create mode 100644 src/ballistica/media/media_server.h create mode 100644 src/ballistica/networking/network_reader.h create mode 100644 src/ballistica/networking/network_write_module.h create mode 100644 src/ballistica/networking/networking.h create mode 100644 src/ballistica/networking/networking_sys.h create mode 100644 src/ballistica/networking/sockaddr.h create mode 100644 src/ballistica/networking/telnet_server.cc create mode 100644 src/ballistica/networking/telnet_server.h create mode 100644 src/ballistica/platform/linux/platform_linux.cc create mode 100644 src/ballistica/platform/linux/platform_linux.h create mode 100644 src/ballistica/platform/min_sdl.h create mode 100644 src/ballistica/platform/platform.cc create mode 100644 src/ballistica/platform/platform.h create mode 100644 src/ballistica/platform/sdl/sdl_app.cc create mode 100644 src/ballistica/platform/sdl/sdl_app.h diff --git a/.efrocachemap b/.efrocachemap index 3c3b59f8..9987ce92 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/55/e7/7493c35661e347a164ccc9a6e150", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f4/a8/5f874f2c8ee0de54649b3142c2c5", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/87/cd/e155776004a096cd1981e8c45539", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/44/90/8453cc086294eaf8bd15f4df8332", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/e8/98/2363d625af50c24c6ef3d2e9c58d", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/7a/fd/1b7ecd5d084ea0e52974e463b0be", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e8/88/8fe7875aa34660db68e74f25051d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/23/2d/8239623b2d8745b4feb4b380b12a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/2f/03140734daf10cd7e46a29c5c820", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/26/7a/d23e25fdda6f6b1d9ed3b03040b6" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/07/e7/d8f0add439e55e3cce5e5768c80f", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/72/faa94ff6532a95c121fcb5a4f788", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d2/d1/99514fbe084fb0480d75f92ecb2c", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dd/5d/f8c5b24579236bef5209d7089044", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5f/ff/5d34815d90dd4cd36f2a6f587958", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/1e/cea9badaf52032adb40e6c3b5e21", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/5d/63/96c2bbbedc03bd23824d7354b07d", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/44/94/4fa92ae4a1e726fb0b37e626e107", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/66/fd/8bb36157e75f78caa5373d9def18", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/af/2d/7546ed3c987435a743442603c21b" } \ No newline at end of file diff --git a/docs/ba_module.md b/docs/ba_module.md index a98f543a..a4b30a75 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-09-30 for Ballistica version 1.5.26 build 20190

    +

    last updated on 2020-10-02 for Ballistica version 1.5.26 build 20194

    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!


    diff --git a/src/ballistica/app/app_config.cc b/src/ballistica/app/app_config.cc deleted file mode 100644 index 5a9bbcce..00000000 --- a/src/ballistica/app/app_config.cc +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/app/app_config.h" - -#include - -#include "ballistica/ballistica.h" -#include "ballistica/platform/platform.h" -#include "ballistica/python/python.h" - -namespace ballistica { - -void AppConfig::Init() { new AppConfig(); } - -auto AppConfig::Entry::FloatValue() const -> float { - throw Exception("not a float entry"); -} - -auto AppConfig::Entry::StringValue() const -> std::string { - throw Exception("not a string entry"); -} - -auto AppConfig::Entry::IntValue() const -> int { - throw Exception("not an int entry"); -} - -auto AppConfig::Entry::BoolValue() const -> bool { - throw Exception("not a bool entry"); -} - -auto AppConfig::Entry::DefaultFloatValue() const -> float { - throw Exception("not a float entry"); -} - -auto AppConfig::Entry::DefaultStringValue() const -> std::string { - throw Exception("not a string entry"); -} - -auto AppConfig::Entry::DefaultIntValue() const -> int { - throw Exception("not an int entry"); -} - -auto AppConfig::Entry::DefaultBoolValue() const -> bool { - throw Exception("not a bool entry"); -} - -class AppConfig::StringEntry : public AppConfig::Entry { - public: - StringEntry() = default; - StringEntry(const char* name, std::string default_value) - : Entry(name), default_value_(std::move(default_value)) {} - auto GetType() const -> Type override { return Type::kString; } - auto Resolve() const -> std::string { - return g_python->GetRawConfigValue(name().c_str(), default_value_.c_str()); - } - auto StringValue() const -> std::string override { return Resolve(); } - auto DefaultStringValue() const -> std::string override { - return default_value_; - } - - private: - std::string default_value_; -}; - -class AppConfig::FloatEntry : public AppConfig::Entry { - public: - FloatEntry() = default; - FloatEntry(const char* name, float default_value) - : Entry(name), default_value_(default_value) {} - auto GetType() const -> Type override { return Type::kFloat; } - auto Resolve() const -> float { - return g_python->GetRawConfigValue(name().c_str(), default_value_); - } - auto FloatValue() const -> float override { return Resolve(); } - auto DefaultFloatValue() const -> float override { return default_value_; } - - private: - float default_value_{}; -}; - -class AppConfig::IntEntry : public AppConfig::Entry { - public: - IntEntry() = default; - IntEntry(const char* name, int default_value) - : Entry(name), default_value_(default_value) {} - auto GetType() const -> Type override { return Type::kInt; } - auto Resolve() const -> int { - return g_python->GetRawConfigValue(name().c_str(), default_value_); - } - auto IntValue() const -> int override { return Resolve(); } - auto DefaultIntValue() const -> int override { return default_value_; } - - private: - int default_value_{}; -}; - -class AppConfig::BoolEntry : public AppConfig::Entry { - public: - BoolEntry() = default; - BoolEntry(const char* name, bool default_value) - : Entry(name), default_value_(default_value) {} - auto GetType() const -> Type override { return Type::kBool; } - auto Resolve() const -> bool { - return g_python->GetRawConfigValue(name().c_str(), default_value_); - } - auto BoolValue() const -> bool override { return Resolve(); } - auto DefaultBoolValue() const -> bool override { return default_value_; } - - private: - bool default_value_{}; -}; - -AppConfig::AppConfig() { - // (We're a singleton). - assert(g_app_config == nullptr); - g_app_config = this; - SetupEntries(); -} - -template -void AppConfig::CompleteMap(const T& entry_map) { - for (auto&& i : entry_map) { - assert(entries_by_name_.find(i.second.name()) == entries_by_name_.end()); - assert(i.first < decltype(i.first)::kLast); - entries_by_name_[i.second.name()] = &i.second; - } - - // Make sure all values have entries. -#if BA_DEBUG_BUILD - int last = static_cast(decltype(entry_map.begin()->first)::kLast); // ew - for (int j = 0; j < last; ++j) { - auto i2 = - entry_map.find(static_castfirst)>(j)); - if (i2 == entry_map.end()) { - throw Exception("Missing appconfig entry " + std::to_string(j)); - } - } -#endif -} - -void AppConfig::SetupEntries() { - // Register all our typed entries. - float_entries_[FloatID::kScreenGamma] = FloatEntry("Screen Gamma", 1.0F); - float_entries_[FloatID::kScreenPixelScale] = - FloatEntry("Screen Pixel Scale", 1.0F); - float_entries_[FloatID::kTouchControlsScale] = - FloatEntry("Touch Controls Scale", 1.0F); - float_entries_[FloatID::kTouchControlsScaleMovement] = - FloatEntry("Touch Controls Scale Movement", 1.0F); - float_entries_[FloatID::kTouchControlsScaleActions] = - FloatEntry("Touch Controls Scale Actions", 1.0F); - float_entries_[FloatID::kSoundVolume] = FloatEntry("Sound Volume", 1.0F); - float_entries_[FloatID::kMusicVolume] = FloatEntry("Music Volume", 1.0F); - - // Note: keep this synced with the defaults in MainActivity.java. - float gvrrts_default = g_platform->IsRunningOnDaydream() ? 1.0F : 0.5F; - float_entries_[FloatID::kGoogleVRRenderTargetScale] = - FloatEntry("GVR Render Target Scale", gvrrts_default); - - string_entries_[StringID::kResolutionAndroid] = - StringEntry("Resolution (Android)", "Auto"); - string_entries_[StringID::kTouchActionControlType] = - StringEntry("Touch Action Control Type", "buttons"); - string_entries_[StringID::kTouchMovementControlType] = - StringEntry("Touch Movement Control Type", "swipe"); - string_entries_[StringID::kGraphicsQuality] = - StringEntry("Graphics Quality", "Auto"); - string_entries_[StringID::kTextureQuality] = - StringEntry("Texture Quality", "Auto"); - string_entries_[StringID::kVerticalSync] = - StringEntry("Vertical Sync", "Auto"); - string_entries_[StringID::kVRHeadRelativeAudio] = - StringEntry("VR Head Relative Audio", "Auto"); - string_entries_[StringID::kMacControllerSubsystem] = - StringEntry("Mac Controller Subsystem", "Classic"); - string_entries_[StringID::kTelnetPassword] = - StringEntry("Telnet Password", "changeme"); - - int_entries_[IntID::kPort] = IntEntry("Port", kDefaultPort); - int_entries_[IntID::kTelnetPort] = - IntEntry("Telnet Port", kDefaultTelnetPort); - - bool_entries_[BoolID::kTouchControlsSwipeHidden] = - BoolEntry("Touch Controls Swipe Hidden", false); - bool_entries_[BoolID::kFullscreen] = BoolEntry("Fullscreen", false); - bool_entries_[BoolID::kKickIdlePlayers] = - BoolEntry("Kick Idle Players", false); - bool_entries_[BoolID::kAlwaysUseInternalKeyboard] = - BoolEntry("Always Use Internal Keyboard", false); - bool_entries_[BoolID::kShowFPS] = BoolEntry("Show FPS", false); - bool_entries_[BoolID::kTVBorder] = - BoolEntry("TV Border", g_platform->IsRunningOnTV()); - bool_entries_[BoolID::kKeyboardP2Enabled] = - BoolEntry("Keyboard P2 Enabled", false); - bool_entries_[BoolID::kEnablePackageMods] = - BoolEntry("Enable Package Mods", false); - bool_entries_[BoolID::kChatMuted] = BoolEntry("Chat Muted", false); - bool_entries_[BoolID::kEnableRemoteApp] = - BoolEntry("Enable Remote App", true); - bool_entries_[BoolID::kEnableTelnet] = BoolEntry("Enable Telnet", true); - bool_entries_[BoolID::kDisableCameraShake] = - BoolEntry("Disable Camera Shake", false); - bool_entries_[BoolID::kDisableCameraGyro] = - BoolEntry("Disable Camera Gyro", false); - - // Now add everything to our name map and make sure all is kosher. - CompleteMap(float_entries_); - CompleteMap(int_entries_); - CompleteMap(string_entries_); - CompleteMap(bool_entries_); -} - -auto AppConfig::Resolve(FloatID id) -> float { - auto i = float_entries_.find(id); - if (i == float_entries_.end()) { - throw Exception("Invalid config entry"); - } - return i->second.Resolve(); -} - -auto AppConfig::Resolve(StringID id) -> std::string { - auto i = string_entries_.find(id); - if (i == string_entries_.end()) { - throw Exception("Invalid config entry"); - } - return i->second.Resolve(); -} - -auto AppConfig::Resolve(BoolID id) -> bool { - auto i = bool_entries_.find(id); - if (i == bool_entries_.end()) { - throw Exception("Invalid config entry"); - } - return i->second.Resolve(); -} - -auto AppConfig::Resolve(IntID id) -> int { - auto i = int_entries_.find(id); - if (i == int_entries_.end()) { - throw Exception("Invalid config entry"); - } - return i->second.Resolve(); -} - -} // namespace ballistica diff --git a/src/ballistica/app/app_globals.cc b/src/ballistica/app/app_globals.cc deleted file mode 100644 index 3afbb3fe..00000000 --- a/src/ballistica/app/app_globals.cc +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/app/app_globals.h" - -namespace ballistica { - -AppGlobals::AppGlobals(int argc_in, char** argv_in) - : argc{argc_in}, - argv{argv_in}, - main_thread_id{std::this_thread::get_id()} {} - -} // namespace ballistica diff --git a/src/ballistica/app/app_globals.h b/src/ballistica/app/app_globals.h index 7af2803e..67b91272 100644 --- a/src/ballistica/app/app_globals.h +++ b/src/ballistica/app/app_globals.h @@ -10,7 +10,6 @@ #include #include "ballistica/ballistica.h" -#include "ballistica/networking/master_server_config.h" namespace ballistica { @@ -85,8 +84,6 @@ class AppGlobals { std::mutex real_time_mutex; std::mutex thread_name_map_mutex; std::map thread_name_map; - std::string master_server_addr{BA_MASTER_SERVER_DEFAULT_ADDR}; - std::string master_server_fallback_addr{BA_MASTER_SERVER_FALLBACK_ADDR}; #if BA_DEBUG_BUILD std::mutex object_list_mutex; Object* object_list_first{}; diff --git a/src/ballistica/app/headless_app.cc b/src/ballistica/app/headless_app.cc deleted file mode 100644 index 6d88748e..00000000 --- a/src/ballistica/app/headless_app.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling -#if BA_HEADLESS_BUILD - -#include "ballistica/app/headless_app.h" - -#include "ballistica/ballistica.h" - -namespace ballistica { - -// We could technically use the vanilla App class here since we're not -// changing anything. -HeadlessApp::HeadlessApp(Thread* thread) : App(thread) { - // NewThreadTimer(10, true, NewLambdaRunnable([this] { - // assert(g_app); - // g_app->RunEvents(); - // })); -} - -} // namespace ballistica - -#endif // BA_HEADLESS_BUILD diff --git a/src/ballistica/app/stress_test.cc b/src/ballistica/app/stress_test.cc deleted file mode 100644 index 4846e9ac..00000000 --- a/src/ballistica/app/stress_test.cc +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/app/stress_test.h" - -#include "ballistica/ballistica.h" -#include "ballistica/graphics/graphics_server.h" -#include "ballistica/graphics/renderer.h" -#include "ballistica/input/input.h" -#include "ballistica/platform/platform.h" - -namespace ballistica { - -void StressTest::Update() { - assert(InMainThread()); - - // Handle a little misc stuff here. - // If we're currently running stress-tests, update that stuff. - if (stress_testing_ && g_input) { - // Update our fake inputs to make our dudes run around. - g_input->ProcessStressTesting(stress_test_player_count_); - - // Every 10 seconds update our stress-test stats. - millisecs_t t = GetRealTime(); - if (t - last_stress_test_update_time_ >= 10000) { - if (stress_test_stats_file_ == nullptr) { - assert(g_platform); - std::string f_name = - g_platform->GetUserPythonDirectory() + "/stress_test_stats.csv"; - stress_test_stats_file_ = g_platform->FOpen(f_name.c_str(), "wb"); - if (stress_test_stats_file_ != nullptr) { - fprintf(stress_test_stats_file_, - "time,averageFps,nodes,models,collide_models,textures,sounds," - "pssMem,sharedDirtyMem,privateDirtyMem\n"); - fflush(stress_test_stats_file_); - if (g_buildconfig.ostype_android()) { - // On android, let the OS know we've added or removed a file - // (limit to android or we'll get an unimplemented warning). - g_platform->AndroidRefreshFile(f_name); - } - } - } - if (stress_test_stats_file_ != nullptr) { - // See how many frames we've rendered this past interval. - int total_frames_rendered; - if (g_graphics_server && g_graphics_server->renderer()) { - total_frames_rendered = - g_graphics_server->renderer()->total_frames_rendered(); - } else { - total_frames_rendered = last_total_frames_rendered_; - } - float avg = - static_cast(total_frames_rendered - - last_total_frames_rendered_) - / (static_cast(t - last_stress_test_update_time_) / 1000.0f); - last_total_frames_rendered_ = total_frames_rendered; - uint32_t model_count = 0; - uint32_t collide_model_count = 0; - uint32_t texture_count = 0; - uint32_t sound_count = 0; - uint32_t node_count = 0; - if (g_media) { - model_count = g_media->total_model_count(); - collide_model_count = g_media->total_collide_model_count(); - texture_count = g_media->total_texture_count(); - sound_count = g_media->total_sound_count(); - } - assert(g_game); - std::string mem_usage = g_platform->GetMemUsageInfo(); - fprintf(stress_test_stats_file_, "%d,%.1f,%d,%d,%d,%d,%d,%s\n", - static_cast_check_fit(GetRealTime()), avg, node_count, - model_count, collide_model_count, texture_count, sound_count, - mem_usage.c_str()); - fflush(stress_test_stats_file_); - } - last_stress_test_update_time_ = t; - } - } -} - -void StressTest::Set(bool enable, int player_count) { - assert(InMainThread()); - bool was_stress_testing = stress_testing_; - stress_testing_ = enable; - stress_test_player_count_ = player_count; - - // If we're turning on, reset our intervals and things. - if (!was_stress_testing && stress_testing_) { - // So our first sample is 1 interval from now. - last_stress_test_update_time_ = GetRealTime(); - - // Reset our frames-rendered tally. - if (g_graphics_server && g_graphics_server->renderer()) { - last_total_frames_rendered_ = - g_graphics_server->renderer()->total_frames_rendered(); - } else { - // Assume zero if there's no graphics yet. - last_total_frames_rendered_ = 0; - } - } -} -} // namespace ballistica diff --git a/src/ballistica/app/vr_app.cc b/src/ballistica/app/vr_app.cc deleted file mode 100644 index e7d8909e..00000000 --- a/src/ballistica/app/vr_app.cc +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling -#if BA_VR_BUILD - -#include "ballistica/app/vr_app.h" - -#include "ballistica/game/game.h" -#include "ballistica/graphics/graphics_server.h" -#include "ballistica/graphics/renderer.h" - -namespace ballistica { - -VRApp::VRApp(Thread* thread) : App(thread) {} - -void VRApp::PushVRSimpleRemoteStateCall(const VRSimpleRemoteState& state) { - PushCall([this, state] { - // Convert this to a full hands state, adding in some simple elbow - // positioning of our own and left/right. - VRHandsState s; - s.l.tx = -0.2f; - s.l.ty = -0.2f; - s.l.tz = -0.3f; - - // Hmm; for now lets always assign this as right hand even when its in - // left-handed mode to keep things simple on the back-end. Can change later - // if there's a downside to that. - s.r.type = VRHandType::kDaydreamRemote; - s.r.tx = 0.2f; - s.r.ty = -0.2f; - s.r.tz = -0.3f; - s.r.yaw = state.r0; - s.r.pitch = state.r1; - s.r.roll = state.r2; - VRSetHands(s); - }); -} - -void VRApp::VRSetDrawDimensions(int w, int h) { - g_graphics_server->VideoResize(w, h); -} - -void VRApp::VRPreDraw() { - if (!g_graphics_server || !g_graphics_server->renderer()) { - return; - } - assert(InMainThread()); - if (FrameDef* frame_def = g_graphics_server->GetRenderFrameDef()) { - // Note: this could be part of PreprocessRenderFrameDef but - // the non-vr path needs it to be separate since preprocess doesn't - // happen sometimes. Should probably clean that up. - g_graphics_server->RunFrameDefMeshUpdates(frame_def); - - // store this for the duration of this frame - vr_render_frame_def_ = frame_def; - g_graphics_server->PreprocessRenderFrameDef(frame_def); - } -} - -void VRApp::VRPostDraw() { - assert(InMainThread()); - if (!g_graphics_server || !g_graphics_server->renderer()) { - return; - } - if (vr_render_frame_def_) { - g_graphics_server->FinishRenderFrameDef(vr_render_frame_def_); - vr_render_frame_def_ = nullptr; - } - RunRenderUpkeepCycle(); -} - -void VRApp::VRSetHead(float tx, float ty, float tz, float yaw, float pitch, - float roll) { - assert(InMainThread()); - Renderer* renderer = g_graphics_server->renderer(); - if (renderer == nullptr) return; - renderer->VRSetHead(tx, ty, tz, yaw, pitch, roll); -} - -void VRApp::VRSetHands(const VRHandsState& state) { - assert(InMainThread()); - - // Pass this along to the renderer (in this same thread) for drawing - // (so hands can be drawn at their absolute most up-to-date positions, etc). - Renderer* renderer = g_graphics_server->renderer(); - if (renderer == nullptr) return; - renderer->VRSetHands(state); - - // ALSO ship it off to the game/ui thread to actually handle input from it. - g_game->PushVRHandsState(state); -} - -void VRApp::VRDrawEye(int eye, float yaw, float pitch, float roll, float tan_l, - float tan_r, float tan_b, float tan_t, float eye_x, - float eye_y, float eye_z, int viewport_x, - int viewport_y) { - if (!g_graphics_server || !g_graphics_server->renderer()) { - return; - } - assert(InMainThread()); - if (vr_render_frame_def_) { - // set up VR eye stuff... - Renderer* renderer = g_graphics_server->renderer(); - renderer->VRSetEye(eye, yaw, pitch, roll, tan_l, tan_r, tan_b, tan_t, eye_x, - eye_y, eye_z, viewport_x, viewport_y); - g_graphics_server->DrawRenderFrameDef(vr_render_frame_def_); - } -} - -} // namespace ballistica - -#endif // BA_VR_BUILD diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 8c0228e7..3bbb99db 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,7 +29,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20193; +const int kAppBuildNumber = 20194; const char* kAppVersion = "1.5.26"; const char* kBlessingHash = nullptr; diff --git a/src/ballistica/game/account.cc b/src/ballistica/game/account.cc new file mode 100644 index 00000000..b432f315 --- /dev/null +++ b/src/ballistica/game/account.cc @@ -0,0 +1,199 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/account.h" + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/utils.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +auto Account::AccountTypeFromString(const std::string& val) -> AccountType { + if (val == "Game Center") { + return AccountType::kGameCenter; + } else if (val == "Game Circle") { + return AccountType::kGameCircle; + } else if (val == "Google Play") { + return AccountType::kGooglePlay; + } else if (val == "Steam") { + return AccountType::kSteam; + } else if (val == "Oculus") { + return AccountType::kOculus; + } else if (val == "NVIDIA China") { + return AccountType::kNvidiaChina; + } else if (val == "Test") { + return AccountType::kTest; + } else if (val == "Local") { + return AccountType::kDevice; + } else if (val == "Server") { + return AccountType::kServer; + } else { + return AccountType::kInvalid; + } +} + +auto Account::AccountTypeToString(AccountType type) -> std::string { + switch (type) { + case AccountType::kGameCenter: + return "Game Center"; + case AccountType::kGameCircle: + return "Game Circle"; + case AccountType::kGooglePlay: + return "Google Play"; + case AccountType::kSteam: + return "Steam"; + case AccountType::kOculus: + return "Oculus"; + case AccountType::kTest: + return "Test"; + case AccountType::kDevice: + return "Local"; + case AccountType::kServer: + return "Server"; + case AccountType::kNvidiaChina: + return "NVIDIA China"; + default: + return ""; + } +} + +auto Account::AccountTypeToIconString(AccountType type) -> std::string { + switch (type) { + case AccountType::kTest: + return g_game->CharStr(SpecialChar::kTestAccount); + case AccountType::kNvidiaChina: + return g_game->CharStr(SpecialChar::kNvidiaLogo); + case AccountType::kGooglePlay: + return g_game->CharStr(SpecialChar::kGooglePlayGamesLogo); + case AccountType::kSteam: + return g_game->CharStr(SpecialChar::kSteamLogo); + case AccountType::kOculus: + return g_game->CharStr(SpecialChar::kOculusLogo); + case AccountType::kGameCenter: + return g_game->CharStr(SpecialChar::kGameCenterLogo); + case AccountType::kGameCircle: + return g_game->CharStr(SpecialChar::kGameCircleLogo); + case AccountType::kDevice: + case AccountType::kServer: + return g_game->CharStr(SpecialChar::kLocalAccount); + default: + return ""; + } +} + +Account::Account() = default; + +auto Account::GetAccountName() -> std::string { + std::lock_guard lock(mutex_); + return account_name_; +} + +auto Account::GetAccountID() -> std::string { + std::lock_guard lock(mutex_); + return account_id_; +} + +auto Account::GetAccountToken() -> std::string { + std::lock_guard lock(mutex_); + return account_token_; +} + +auto Account::GetAccountExtra() -> std::string { + std::lock_guard lock(mutex_); + return account_extra_; +} + +auto Account::GetAccountExtra2() -> std::string { + std::lock_guard lock(mutex_); + return account_extra_2_; +} + +auto Account::GetAccountState(int* state_num) -> AccountState { + std::lock_guard lock(mutex_); + if (state_num) { + *state_num = account_state_num_; + } + return account_state_; +} + +void Account::SetAccountExtra(const std::string& extra) { + std::lock_guard lock(mutex_); + account_extra_ = extra; +} + +void Account::SetAccountExtra2(const std::string& extra) { + std::lock_guard lock(mutex_); + account_extra_2_ = extra; +} + +void Account::SetAccountToken(const std::string& account_id, + const std::string& token) { + std::lock_guard lock(mutex_); + // Hmm does this compare logic belong in here? + if (account_id_ == account_id) { + account_token_ = token; + } +} + +void Account::SetAccount(AccountType account_type, AccountState account_state, + const std::string& account_name, + const std::string& account_id) { + bool call_account_changed = false; + { + std::lock_guard lock(mutex_); + + // We call out to python so need to be in game thread. + assert(InGameThread()); + if (account_state_ != account_state + || g_app_globals->account_type != account_type + || account_id_ != account_id || account_name_ != account_name) { + // Special case: if they sent a sign-out for an account type that is. + // currently not signed in, ignore it. + if (account_state == AccountState::kSignedOut + && (account_type != g_app_globals->account_type)) { + // No-op. + } else { + account_state_ = account_state; + g_app_globals->account_type = account_type; + account_id_ = account_id; + account_name_ = Utils::GetValidUTF8(account_name.c_str(), "gthm"); + + // If they signed out of an account, account type switches to invalid. + if (account_state == AccountState::kSignedOut) { + g_app_globals->account_type = AccountType::kInvalid; + } + account_state_num_ += 1; + call_account_changed = true; + } + } + } + if (call_account_changed) { + // Inform python layer this has changed. + g_python->AccountChanged(); + } +} + +void Account::SetProductsPurchased(const std::vector& products) { + std::lock_guard lock(mutex_); + std::map purchases_old = product_purchases_; + product_purchases_.clear(); + for (auto&& i : products) { + product_purchases_[i] = true; + } + if (product_purchases_ != purchases_old) { + product_purchases_state_++; + } +} + +auto Account::GetProductPurchased(const std::string& product) -> bool { + std::lock_guard lock(mutex_); + auto i = product_purchases_.find(product); + if (i == product_purchases_.end()) { + return false; + } else { + return i->second; + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/account.h b/src/ballistica/game/account.h new file mode 100644 index 00000000..79dc2f8b --- /dev/null +++ b/src/ballistica/game/account.h @@ -0,0 +1,64 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_ACCOUNT_H_ +#define BALLISTICA_GAME_ACCOUNT_H_ + +#include +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// Global account functionality. +class Account { + public: + Account(); + static auto AccountTypeFromString(const std::string& val) -> AccountType; + static auto AccountTypeToString(AccountType type) -> std::string; + static auto AccountTypeToIconString(AccountType type) -> std::string; + + auto GetAccountName() -> std::string; + auto GetAccountID() -> std::string; + auto GetAccountToken() -> std::string; + auto GetAccountExtra() -> std::string; + auto GetAccountExtra2() -> std::string; + + // Return the current account state. + // If an int pointer is passed, state-num will also be returned. + auto GetAccountState(int* state_num = nullptr) -> AccountState; + + // An extra value included when passing our account info to the server + // ..(can be used for platform-specific install-signature stuff, etc). + void SetAccountExtra(const std::string& extra); + void SetAccountExtra2(const std::string& extra); + void SetAccountToken(const std::string& account_id, const std::string& token); + + void SetAccount(AccountType account_type, AccountState account_state, + const std::string& name, const std::string& id); + + void SetProductsPurchased(const std::vector& products); + auto GetProductPurchased(const std::string& product) -> bool; + auto product_purchases_state() const -> int { + return product_purchases_state_; + } + + private: + // Protects all access to this account (we're thread-safe). + std::mutex mutex_; + std::map product_purchases_; + int product_purchases_state_{}; + std::string account_name_; + std::string account_id_; + std::string account_token_; + std::string account_extra_; + std::string account_extra_2_; + AccountState account_state_{AccountState::kSignedOut}; + int account_state_num_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_ACCOUNT_H_ diff --git a/src/ballistica/game/client_controller_interface.h b/src/ballistica/game/client_controller_interface.h new file mode 100644 index 00000000..19bc0d7d --- /dev/null +++ b/src/ballistica/game/client_controller_interface.h @@ -0,0 +1,22 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_CLIENT_CONTROLLER_INTERFACE_H_ +#define BALLISTICA_GAME_CLIENT_CONTROLLER_INTERFACE_H_ + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// An interface for something that can control client-connections. +// (such as an output-stream or a replay-client-session) +// objects can register themselves as the current client-connection-controller +// and then they will get control of all existing (and forthcoming) clients +class ClientControllerInterface { + public: + virtual void OnClientConnected(ConnectionToClient* c) = 0; + virtual void OnClientDisconnected(ConnectionToClient* c) = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_CLIENT_CONTROLLER_INTERFACE_H_ diff --git a/src/ballistica/game/friend_score_set.h b/src/ballistica/game/friend_score_set.h new file mode 100644 index 00000000..a4108c8d --- /dev/null +++ b/src/ballistica/game/friend_score_set.h @@ -0,0 +1,30 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_FRIEND_SCORE_SET_H_ +#define BALLISTICA_GAME_FRIEND_SCORE_SET_H_ + +#include +#include +#include + +namespace ballistica { + +// Used by game-center/etc when reporting friend scores to the game. +struct FriendScoreSet { + FriendScoreSet(bool success, void* user_data) + : success(success), user_data(user_data) {} + struct Entry { + Entry(int score, std::string name, bool is_me) + : score(score), name(std::move(name)), is_me(is_me) {} + int score; + std::string name; + bool is_me; + }; + std::list entries; + bool success; + void* user_data; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_FRIEND_SCORE_SET_H_ diff --git a/src/ballistica/game/game.cc b/src/ballistica/game/game.cc new file mode 100644 index 00000000..77c563f3 --- /dev/null +++ b/src/ballistica/game/game.cc @@ -0,0 +1,3165 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/game.h" + +#include +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_config.h" +#include "ballistica/audio/audio.h" +#include "ballistica/core/thread.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/game/account.h" +#include "ballistica/game/connection/connection_to_client_udp.h" +#include "ballistica/game/connection/connection_to_host_udp.h" +#include "ballistica/game/friend_score_set.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/player.h" +#include "ballistica/game/score_to_beat.h" +#include "ballistica/game/session/client_session.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/game/session/net_client_session.h" +#include "ballistica/game/session/replay_client_session.h" +#include "ballistica/generic/json.h" +#include "ballistica/generic/timer.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/input/device/client_input_device.h" +#include "ballistica/input/device/keyboard_input.h" +#include "ballistica/input/device/touch_input.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/networking/network_write_module.h" +#include "ballistica/networking/networking.h" +#include "ballistica/networking/sockaddr.h" +#include "ballistica/networking/telnet_server.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_command.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/python/python_sys.h" +#include "ballistica/scene/node/globals_node.h" +#include "ballistica/ui/console.h" +#include "ballistica/ui/root_ui.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/root_widget.h" +#include "ballistica/ui/widget/text_widget.h" + +namespace ballistica { + +/// How long a kick vote lasts. +const int kKickVoteDuration = 30000; + +/// How long everyone has to wait to start a new kick vote after a failed one. +const int kKickVoteFailRetryDelay = 60000; + +/// Extra delay for the initiator of a failed vote. +const int kKickVoteFailRetryDelayInitiatorExtra = 120000; + +// Minimum clients that must be present for a kick vote to count. +// (for non-headless builds we require more votes since the host doesn't count +// but may be playing (in a 2on2 with 3 clients, don't want 2 clients able to +// kick). +// NOLINTNEXTLINE(cert-err58-cpp) +const int kKickVoteMinimumClients = (g_buildconfig.headless_build() ? 3 : 4); + +const int kMaxChatMessages = 40; + +// Go with 5 minute ban. +const int kKickBanSeconds = 5 * 60; + +Game::Game(Thread* thread) + : Module("game", thread), + game_roster_(cJSON_CreateArray()), + realtimers_(new TimerList()) { + assert(g_game == nullptr); + g_game = this; + + try { + // Spin up some other game-thread-based stuff. + AppConfig::Init(); + assert(g_graphics == nullptr); + g_graphics = g_platform->CreateGraphics(); + TextGraphics::Init(); + Media::Init(); + Audio::Init(); + if (!HeadlessMode()) { + BGDynamics::Init(); + } + + InitSpecialChars(); + + Context::Init(); + + // Waaah does UI need to be a bs::Object? + // Update: yes it does in order to be a context target. + // (need to be able to create weak-refs to it). + assert(g_ui == nullptr); + g_ui = Object::NewUnmanaged(); + + assert(g_networking == nullptr); + g_networking = new Networking(); + + assert(g_input == nullptr); + g_input = new Input(); + + // Init python and apply our settings immediately. + // This way we can get started loading stuff in the background + // and it'll come in with the correct texture quality etc. + assert(g_python == nullptr); + g_python = new Python(); + g_python->Reset(true); + + // We're the thread that 'owns' python so we need to wrangle the GIL. + thread->SetOwnsPython(); + } catch (const std::exception& e) { + // If anything went wrong, trigger a deferred error. + // This way it is more likely we can show a fatal error dialog + // since the main thread won't be blocking waiting for us to init. + std::string what = e.what(); + PushCall([what] { + // Just throw a standard exception since our what already + // contains a stack trace; if we throw an Exception we wind + // up with a useless second one. + throw std::logic_error(what.c_str()); + }); + } +} + +void Game::InitSpecialChars() { + std::lock_guard lock(special_char_mutex_); + + special_char_strings_[SpecialChar::kDownArrow] = "\xee\x80\x84"; + special_char_strings_[SpecialChar::kUpArrow] = "\xee\x80\x83"; + special_char_strings_[SpecialChar::kLeftArrow] = "\xee\x80\x81"; + special_char_strings_[SpecialChar::kRightArrow] = "\xee\x80\x82"; + special_char_strings_[SpecialChar::kTopButton] = "\xee\x80\x86"; + special_char_strings_[SpecialChar::kLeftButton] = "\xee\x80\x85"; + special_char_strings_[SpecialChar::kRightButton] = "\xee\x80\x87"; + special_char_strings_[SpecialChar::kBottomButton] = "\xee\x80\x88"; + special_char_strings_[SpecialChar::kDelete] = "\xee\x80\x89"; + special_char_strings_[SpecialChar::kShift] = "\xee\x80\x8A"; + special_char_strings_[SpecialChar::kBack] = "\xee\x80\x8B"; + special_char_strings_[SpecialChar::kLogoFlat] = "\xee\x80\x8C"; + special_char_strings_[SpecialChar::kRewindButton] = "\xee\x80\x8D"; + special_char_strings_[SpecialChar::kPlayPauseButton] = "\xee\x80\x8E"; + special_char_strings_[SpecialChar::kFastForwardButton] = "\xee\x80\x8F"; + special_char_strings_[SpecialChar::kDpadCenterButton] = "\xee\x80\x90"; + + special_char_strings_[SpecialChar::kOuyaButtonO] = "\xee\x80\x99"; + special_char_strings_[SpecialChar::kOuyaButtonU] = "\xee\x80\x9A"; + special_char_strings_[SpecialChar::kOuyaButtonY] = "\xee\x80\x9B"; + special_char_strings_[SpecialChar::kOuyaButtonA] = "\xee\x80\x9C"; + special_char_strings_[SpecialChar::kOuyaLogo] = "\xee\x80\x9D"; + special_char_strings_[SpecialChar::kLogo] = "\xee\x80\x9E"; + special_char_strings_[SpecialChar::kTicket] = "\xee\x80\x9F"; + special_char_strings_[SpecialChar::kGooglePlayGamesLogo] = "\xee\x80\xA0"; + special_char_strings_[SpecialChar::kGameCenterLogo] = "\xee\x80\xA1"; + special_char_strings_[SpecialChar::kDiceButton1] = "\xee\x80\xA2"; + special_char_strings_[SpecialChar::kDiceButton2] = "\xee\x80\xA3"; + special_char_strings_[SpecialChar::kDiceButton3] = "\xee\x80\xA4"; + special_char_strings_[SpecialChar::kDiceButton4] = "\xee\x80\xA5"; + special_char_strings_[SpecialChar::kGameCircleLogo] = "\xee\x80\xA6"; + special_char_strings_[SpecialChar::kPartyIcon] = "\xee\x80\xA7"; + special_char_strings_[SpecialChar::kTestAccount] = "\xee\x80\xA8"; + special_char_strings_[SpecialChar::kTicketBacking] = "\xee\x80\xA9"; + special_char_strings_[SpecialChar::kTrophy1] = "\xee\x80\xAA"; + special_char_strings_[SpecialChar::kTrophy2] = "\xee\x80\xAB"; + special_char_strings_[SpecialChar::kTrophy3] = "\xee\x80\xAC"; + special_char_strings_[SpecialChar::kTrophy0a] = "\xee\x80\xAD"; + special_char_strings_[SpecialChar::kTrophy0b] = "\xee\x80\xAE"; + special_char_strings_[SpecialChar::kTrophy4] = "\xee\x80\xAF"; + special_char_strings_[SpecialChar::kLocalAccount] = "\xee\x80\xB0"; + special_char_strings_[SpecialChar::kAlibabaLogo] = "\xee\x80\xB1"; + + special_char_strings_[SpecialChar::kFlagUnitedStates] = "\xee\x80\xB2"; + special_char_strings_[SpecialChar::kFlagMexico] = "\xee\x80\xB3"; + special_char_strings_[SpecialChar::kFlagGermany] = "\xee\x80\xB4"; + special_char_strings_[SpecialChar::kFlagBrazil] = "\xee\x80\xB5"; + special_char_strings_[SpecialChar::kFlagRussia] = "\xee\x80\xB6"; + special_char_strings_[SpecialChar::kFlagChina] = "\xee\x80\xB7"; + special_char_strings_[SpecialChar::kFlagUnitedKingdom] = "\xee\x80\xB8"; + special_char_strings_[SpecialChar::kFlagCanada] = "\xee\x80\xB9"; + special_char_strings_[SpecialChar::kFlagIndia] = "\xee\x80\xBA"; + special_char_strings_[SpecialChar::kFlagJapan] = "\xee\x80\xBB"; + special_char_strings_[SpecialChar::kFlagFrance] = "\xee\x80\xBC"; + special_char_strings_[SpecialChar::kFlagIndonesia] = "\xee\x80\xBD"; + special_char_strings_[SpecialChar::kFlagItaly] = "\xee\x80\xBE"; + special_char_strings_[SpecialChar::kFlagSouthKorea] = "\xee\x80\xBF"; + special_char_strings_[SpecialChar::kFlagNetherlands] = "\xee\x81\x80"; + + special_char_strings_[SpecialChar::kFedora] = "\xee\x81\x81"; + special_char_strings_[SpecialChar::kHal] = "\xee\x81\x82"; + special_char_strings_[SpecialChar::kCrown] = "\xee\x81\x83"; + special_char_strings_[SpecialChar::kYinYang] = "\xee\x81\x84"; + special_char_strings_[SpecialChar::kEyeBall] = "\xee\x81\x85"; + special_char_strings_[SpecialChar::kSkull] = "\xee\x81\x86"; + special_char_strings_[SpecialChar::kHeart] = "\xee\x81\x87"; + special_char_strings_[SpecialChar::kDragon] = "\xee\x81\x88"; + special_char_strings_[SpecialChar::kHelmet] = "\xee\x81\x89"; + special_char_strings_[SpecialChar::kMushroom] = "\xee\x81\x8A"; + + special_char_strings_[SpecialChar::kNinjaStar] = "\xee\x81\x8B"; + special_char_strings_[SpecialChar::kVikingHelmet] = "\xee\x81\x8C"; + special_char_strings_[SpecialChar::kMoon] = "\xee\x81\x8D"; + special_char_strings_[SpecialChar::kSpider] = "\xee\x81\x8E"; + special_char_strings_[SpecialChar::kFireball] = "\xee\x81\x8F"; + + special_char_strings_[SpecialChar::kFlagUnitedArabEmirates] = "\xee\x81\x90"; + special_char_strings_[SpecialChar::kFlagQatar] = "\xee\x81\x91"; + special_char_strings_[SpecialChar::kFlagEgypt] = "\xee\x81\x92"; + special_char_strings_[SpecialChar::kFlagKuwait] = "\xee\x81\x93"; + special_char_strings_[SpecialChar::kFlagAlgeria] = "\xee\x81\x94"; + special_char_strings_[SpecialChar::kFlagSaudiArabia] = "\xee\x81\x95"; + special_char_strings_[SpecialChar::kFlagMalaysia] = "\xee\x81\x96"; + special_char_strings_[SpecialChar::kFlagCzechRepublic] = "\xee\x81\x97"; + special_char_strings_[SpecialChar::kFlagAustralia] = "\xee\x81\x98"; + special_char_strings_[SpecialChar::kFlagSingapore] = "\xee\x81\x99"; + + special_char_strings_[SpecialChar::kOculusLogo] = "\xee\x81\x9A"; + special_char_strings_[SpecialChar::kSteamLogo] = "\xee\x81\x9B"; + special_char_strings_[SpecialChar::kNvidiaLogo] = "\xee\x81\x9C"; + + special_char_strings_[SpecialChar::kFlagIran] = "\xee\x81\x9D"; + special_char_strings_[SpecialChar::kFlagPoland] = "\xee\x81\x9E"; + special_char_strings_[SpecialChar::kFlagArgentina] = "\xee\x81\x9F"; + special_char_strings_[SpecialChar::kFlagPhilippines] = "\xee\x81\xA0"; + special_char_strings_[SpecialChar::kFlagChile] = "\xee\x81\xA1"; + + special_char_strings_[SpecialChar::kMikirog] = "\xee\x81\xA2"; +} + +void Game::SetGameRoster(cJSON* r) { + if (game_roster_ != nullptr) { + cJSON_Delete(game_roster_); + } + game_roster_ = r; +} + +void Game::ResetActivityTracking() { + largest_draw_time_increment_since_last_reset_ = 0; + first_draw_real_time_ = last_draw_real_time_ = g_platform->GetTicks(); +} + +void Game::RegisterClientController(ClientControllerInterface* c) { + // This shouldn't happen, but if there's already a controller registered, + // detach all clients from it. + if (client_controller_) { + Log("RegisterClientController() called " + "but already have a controller; bad."); + for (auto&& i : connections_to_clients_) { + assert(i.second.exists()); + i.second->SetController(nullptr); + } + } + + // Ok, now assign the new and attach all currently-connected clients to it. + client_controller_ = c; + if (client_controller_) { + for (auto&& i : connections_to_clients_) { + assert(i.second.exists()); + if (i.second->can_communicate()) { + i.second->SetController(client_controller_); + } + } + } +} + +void Game::UnregisterClientController(ClientControllerInterface* c) { + assert(c); + + // This shouldn't happen. + if (client_controller_ != c) { + Log("UnregisterClientController() called with a non-registered " + "controller"); + return; + } + + // Ok, detach all our controllers from this guy. + if (client_controller_) { + for (auto&& i : connections_to_clients_) { + i.second->SetController(nullptr); + } + } + client_controller_ = nullptr; +} + +#if BA_VR_BUILD + +void Game::PushVRHandsState(const VRHandsState& state) { + PushCall([this, state] { vr_hands_state_ = state; }); +} + +#endif // BA_VR_BUILD + +void Game::PushMediaPruneCall(int level) { + PushCall([level] { + assert(InGameThread()); + g_media->Prune(level); + }); +} + +void Game::PushSetAccountTokenCall(const std::string& account_id, + const std::string& token) { + PushCall( + [account_id, token] { g_account->SetAccountToken(account_id, token); }); +} + +void Game::PushSetAccountCall(AccountType account_type, + AccountState account_state, + const std::string& account_name, + const std::string& account_id) { + PushCall([this, account_type, account_state, account_name, account_id] { + g_account->SetAccount(account_type, account_state, account_name, + account_id); + }); +} + +void Game::PushInitialScreenCreatedCall() { + PushCall([this] { InitialScreenCreated(); }); +} + +void Game::InitialScreenCreated() { + assert(InGameThread()); + + // Ok; graphics-server is telling us we've got a screen. + + // We can now let the media thread go to town pre-loading system media + // while we wait. + g_media->LoadSystemMedia(); + + // FIXME: ideally we should create this as part of bootstrapping, but + // we need it to be possible to load textures/etc. before the renderer + // exists. + if (!HeadlessMode()) { + assert(!g_app_globals->console); + g_app_globals->console = new Console(); + } + + // Set up our timers. + process_timer_ = + NewThreadTimer(0, true, NewLambdaRunnable([this] { Process(); })); + media_prune_timer_ = + NewThreadTimer(2345, true, NewLambdaRunnable([this] { Prune(); })); + + // Normally we schedule updates when we're asked to draw a frame. + // In headless mode, however, we're not drawing, so we need a dedicated + // timer to take its place. + if (HeadlessMode()) { + headless_update_timer_ = + NewThreadTimer(8, true, NewLambdaRunnable([this] { Update(); })); + } + + RunAppLaunchCommands(); +} + +void Game::PushPurchaseTransactionCall(const std::string& item, + const std::string& receipt, + const std::string& signature, + const std::string& order_id, + bool user_initiated) { + PushCall([this, item, receipt, signature, order_id, user_initiated] { + PurchaseTransaction(item, receipt, signature, order_id, user_initiated); + }); +} + +void Game::PurchaseTransaction(const std::string& item, + const std::string& receipt, + const std::string& signature, + const std::string& order_id, + bool user_initiated) { + assert(InGameThread()); + g_python->AddPurchaseTransaction(item, receipt, signature, order_id, + user_initiated); +} + +void Game::Prune() { g_media->Prune(); } + +void Game::PushAdViewCompleteCall(const std::string& purpose, + bool actually_showed) { + PushCall([this, purpose, actually_showed] { + AdViewComplete(purpose, actually_showed); + }); +} + +void Game::AdViewComplete(const std::string& purpose, bool actually_showed) { + assert(InGameThread()); + CallAdCompletionCall(actually_showed); + + // If they *actually* viewed an ad, and it was a between-game ad, inform the + // user that they can disable them. + if (purpose == "between_game" && actually_showed) { + g_python->obj(Python::ObjID::kRemoveInGameAdsMessageCall).Call(); + } + RunGeneralAdComplete(actually_showed); +} + +void Game::RunGeneralAdComplete(bool actually_showed) { + assert(InGameThread()); + PythonRef ad_complete_call = + g_python->obj(Python::ObjID::kAccountClient).GetAttr("ad_complete"); + if (ad_complete_call.exists()) { + PythonRef args(Py_BuildValue("(Oi)", actually_showed ? Py_True : Py_False, + static_cast(g_platform->GetTicks() + - last_ad_start_time_)), + PythonRef::kSteal); + ad_complete_call.Call(args); + } else { + Log("Error on ad-complete call"); + } +} + +void Game::PushAnalyticsCall(const std::string& type, int increment) { + PushCall([this, type, increment] { Analytics(type, increment); }); +} + +void Game::Analytics(const std::string& type, int increment) { + assert(InGameThread()); + g_python->HandleAnalytics(type, increment); +} + +void Game::PushAwardAdTicketsCall() { + PushCall([this] { AwardAdTickets(); }); +} + +void Game::AwardAdTickets() { + try { + PythonRef add_transaction = + g_python->obj(Python::ObjID::kAccountClient).GetAttr("add_transaction"); + PythonRef args(Py_BuildValue("({ss})", "type", "AWARD_AD_TICKETS"), + PythonRef::kSteal); + if (add_transaction.exists()) add_transaction.Call(args); + g_python->RunTransactions(); + } catch (const std::exception& e) { + Log("Error in AwardAdTicketsMessage: " + std::string(e.what())); + } +} + +void Game::PushAwardAdTournamentEntryCall() { + PushCall([this] { AwardAdTournamentEntry(); }); +} + +void Game::AwardAdTournamentEntry() { + try { + PythonRef add_transaction = + g_python->obj(Python::ObjID::kAccountClient).GetAttr("add_transaction"); + PythonRef args(Py_BuildValue("({ss})", "type", "AWARD_AD_TOURNAMENT_ENTRY"), + PythonRef::kSteal); + if (add_transaction.exists()) add_transaction.Call(args); + g_python->RunTransactions(); + } catch (const std::exception& e) { + Log("Error in AwardAdTournamentEntryMessage: " + std::string(e.what())); + } +} + +// Launch into main menu or whatever else. +void Game::RunAppLaunchCommands() { + assert(!ran_app_launch_commands_); + + // First off, run our python app-launch call. + { + // Run this in the UI context. + ScopedSetContext cp(GetUIContext()); + g_python->obj(Python::ObjID::kOnAppLaunchCall).Call(); + } + + // If we were passed launch command args, run them. + if (!g_app_globals->game_commands.empty()) { + bool success = PythonCommand(g_app_globals->game_commands, BA_BCFN).Run(); + if (!success) { + exit(1); + } + } + + // If the stuff we just ran didn't result in a session, create a default one. + if (!foreground_session_.exists()) { + RunMainMenu(); + } + + UpdateProcessTimer(); + + ran_app_launch_commands_ = true; +} + +Game::~Game() = default; + +// Set up our sleeping based on what we're doing. +void Game::UpdateProcessTimer() { + assert(InGameThread()); + + // This might get called before we set up our timer in some cases. (such as + // very early) should be safe to ignore since we update the interval + // explicitly after creating the timers. + if (!process_timer_) return; + + // If there's loading to do, keep at it rather vigorously. + if (have_pending_loads_) { + assert(process_timer_); + process_timer_->SetLength(1); + } else { + // Otherwise we've got nothing to do; go to sleep until something changes. + assert(process_timer_); + process_timer_->SetLength(-1); + } +} + +void Game::PruneSessions() { + bool have_dead_session = false; + for (auto&& i : sessions_) { + if (i.exists()) { + // If this session is no longer foreground and is ready to die, kill it. + if (i.exists() && i.get() != foreground_session_.get()) { + try { + i.Clear(); + } catch (const std::exception& e) { + Log("Exception killing Session: " + std::string(e.what())); + } + have_dead_session = true; + } + } else { + have_dead_session = true; + } + } + if (have_dead_session) { + std::vector > live_list; + for (auto&& i : sessions_) { + if (i.exists()) { + live_list.push_back(i); + } + } + sessions_.swap(live_list); + } +} + +void Game::SetClientInfoFromMasterServer(const std::string& client_token, + PyObject* info_obj) { + // NOLINTNEXTLINE (python doing bitwise math on signed int) + if (!PyDict_Check(info_obj)) { + Log("got non-dict for master-server client info for token " + client_token + + ": " + Python::ObjToString(info_obj)); + return; + } + for (ConnectionToClient* client : GetConnectionsToClients()) { + if (client->token() == client_token) { + client->HandleMasterServerClientInfo(info_obj); + + // Roster will now include account-id... + game_roster_dirty_ = true; + break; + } + } +} + +void Game::UpdateKickVote() { + if (!kick_vote_in_progress_) { + return; + } + ConnectionToClient* kick_vote_starter = kick_vote_starter_.get(); + ConnectionToClient* kick_vote_target = kick_vote_target_.get(); + + // If the target is no longer with us, silently end. + if (kick_vote_target == nullptr) { + kick_vote_in_progress_ = false; + return; + } + millisecs_t current_time = GetRealTime(); + int total_client_count = 0; + int yes_votes = 0; + int no_votes = 0; + + // Tally current votes for connected clients; if anything has changed, print + // the update and possibly perform the kick. + for (ConnectionToClient* client : GetConnectionsToClients()) { + ++total_client_count; + if (client->kick_voted_) { + if (client->kick_vote_choice_) { + ++yes_votes; + } else { + ++no_votes; + } + } + } + bool vote_failed = false; + + // If we've fallen below the minimum necessary voters or time has run out, + // fail. + if (total_client_count < kKickVoteMinimumClients) { + vote_failed = true; + } + if (current_time > kick_vote_end_time_) { + vote_failed = true; + } + + if (vote_failed) { + SendScreenMessageToClients(R"({"r":"kickVoteFailedText"})", 1, 1, 0); + kick_vote_in_progress_ = false; + + // Disallow kicking for a while for everyone.. but ESPECIALLY so for the guy + // who launched the failed vote. + for (ConnectionToClient* client : GetConnectionsToClients()) { + millisecs_t delay = kKickVoteFailRetryDelay; + if (client == kick_vote_starter) { + delay += kKickVoteFailRetryDelayInitiatorExtra; + } + client->next_kick_vote_allow_time_ = + std::max(client->next_kick_vote_allow_time_, current_time + delay); + } + } else { + int votes_required; + switch (total_client_count) { + case 1: + case 2: + votes_required = 2; // Shouldn't actually be possible. + break; + case 3: + votes_required = HeadlessMode() ? 2 : 3; + break; + case 4: + votes_required = 3; + break; + case 5: + votes_required = HeadlessMode() ? 3 : 4; + break; + case 6: + votes_required = 4; + break; + case 7: + votes_required = HeadlessMode() ? 4 : 5; + break; + default: + votes_required = total_client_count - 3; + break; + } + int votes_needed = votes_required - yes_votes; + if (votes_needed <= 0) { + // ZOMG the vote passed; perform the kick. + SendScreenMessageToClients( + R"({"r":"kickOccurredText","s":[["${NAME}",)" + + Utils::GetJSONString(kick_vote_target->GetCombinedSpec() + .GetDisplayString() + .c_str()) + + "]]}", + 1, 1, 0); + kick_vote_in_progress_ = false; + DisconnectClient(kick_vote_target->id(), kKickBanSeconds); + + } else if (votes_needed != last_kick_votes_needed_) { + last_kick_votes_needed_ = votes_needed; + SendScreenMessageToClients(R"({"r":"votesNeededText","s":[["${NUMBER}",")" + + std::to_string(votes_needed) + "\"]]}", + 1, 1, 0); + } + } +} + +// Bring our scenes, real-time timers, etc up to date. +void Game::Update() { + assert(InGameThread()); + millisecs_t real_time = GetRealTime(); + g_platform->SetDebugKey("LastUpdateTime", + std::to_string(Platform::GetCurrentMilliseconds())); + if (first_update_) { + master_time_offset_ = master_time_ - real_time; + first_update_ = false; + } + in_update_ = true; + g_input->Update(); + UpdateKickVote(); + + // Send the game roster to our clients if it's changed recently. + if (game_roster_dirty_) { + if (real_time > last_game_roster_send_time_ + 2500) { + // Now send it to all connected clients. + std::vector msg = GetGameRosterMessage(); + for (auto&& c : GetConnectionsToClients()) { + c->SendReliableMessage(msg); + } + game_roster_dirty_ = false; + last_game_roster_send_time_ = real_time; + } + } + + // First do housekeeping on our client/host connections. + for (auto&& i : connections_to_clients_) { + BA_IFDEBUG(Object::WeakRef test_ref(i.second)); + i.second->Update(); + + // Make sure the connection didn't kill itself in the update. + assert(test_ref.exists()); + } + + if (connection_to_host_.exists()) { + connection_to_host_->Update(); + } + + // Ok, here's the deal: + // This is where we regulate the speed of everything that's running under us + // (sessions, activities, frame_def-creation, etc) + // we have a master_time which we try to have match real-time as closely + // as possible (unless we physically aren't fast enough to get everything + // done, in which case it'll be slower). We also increment our underlying + // machinery in 8ms increments (1/120 of a second) and try to do 2 updates + // each time we're called, since we're usually being called in a 60hz refresh + // cycle and that'll line our draws up perfectly with our sim steps. + + // TODO(ericf): On modern systems (VR and otherwise) we'll see 80hz, 90hz, + // 120hz, 240hz, etc. It would be great to generalize this to gravitate + // towards clean step patterns in all cases, not just the 60hz and 90hz cases + // we handle now. In general we want stuff like 1,1,2,1,1,2,1,1,2, not + // 1,1,1,2,1,2,2,1,1. + + // Figure out where our net-time *should* be getting to to match real-time. + millisecs_t target_master_time = real_time + master_time_offset_; + millisecs_t amount_behind = target_master_time - master_time_; + + // Normally we assume 60hz so we gravitate towards 2 steps per update to line + // up with our 120hz update timing. + int target_steps = 2; + +#if BA_RIFT_BUILD + // On Rift VR mode we're running 90hz, so lets aim for 1/2/1/2 steps to hit + // our 120hz target. + if (IsVRMode()) { + target_steps = rift_step_index_ + 1; + rift_step_index_ = !rift_step_index_; + } +#endif // BA_RIFT_BUILD + + // Ideally we should be behind by 16 (or 8 for single steps); if its + // *slightly* more than that, let our timing slip a tiny bit to maintain sync. + // This lets us match framerates that are a tiny bit slower than 60hz, such as + // seems to be the case with the Gear VR. + if (amount_behind > 16) { + master_time_offset_ -= 1; + + //.. and recalc these.. + target_master_time = real_time + master_time_offset_; + amount_behind = target_master_time - master_time_; + } + + // if we've fallen behind by a lot, just cut our losses + if (amount_behind > 50) { + master_time_offset_ -= (amount_behind - 50); + target_master_time = real_time + master_time_offset_; + } + + // min/max net-time targets we can aim for; gives us about a steps worth of + // wiggle room to try and keep our exact target cadence + millisecs_t min_target_master_time = + target_master_time >= 8 ? (target_master_time - 8) : 0; + millisecs_t max_target_master_time = target_master_time + 8; + + // run up our real-time timers + realtimers_->Run(real_time); + + // Run session updates until we catch up with projected base time (or run out + // of time). + int step = 1; + + while (true) { + // Try to stick to our target step count whenever possible, but if we get + // too far off target we may need to bail earlier/later. + if (step > target_steps) { + // As long as we're within a step of where we should be, bail now. + if (master_time_ >= min_target_master_time) break; + } else { + // If we've gone too far already, bail. + if (master_time_ >= max_target_master_time) { + // Log("BAILING EARLY"); + // On rift if this is a 2-step and we bailed after 1, aim for 2 again + // next time (otherwise we'll always get 3 singles in a row when this + // happens). +#if BA_RIFT_BUILD + if (IsVRMode() && target_steps == 2 && step == 2) { + rift_step_index_ = !rift_step_index_; + } +#endif // BA_RIFT_BUILD + break; + } + } + + // Update our UI scene/etc. + g_ui->Update(8); + + // Update all of our sessions. + for (auto&& i : sessions_) { + assert(i.exists()); + i->Update(8); + } + + last_session_update_master_time_ = master_time_; + + // Go ahead and prune dead ones. + PruneSessions(); + + // Advance master time.. + master_time_ += 8; + + // Bail if we spend too much time in here. + millisecs_t new_real_time = GetRealTime(); + if (new_real_time - real_time > 30) { + break; + } + step++; + } + in_update_ = false; +} + +// Reset the game to a blank slate. +void Game::Reset() { + assert(InGameThread()); + + // Tear down any existing setup. + // This should allow high-level objects to die gracefully. + assert(g_python->inited()); + + // Tear down our existing session. + foreground_session_.Clear(); + PruneSessions(); + + // If all is well our sessions should all be dead. + if (g_app_globals->session_count != 0) { + Log("Error: session-count is non-zero (" + + std::to_string(g_app_globals->session_count) + ") on Game::Reset."); + } + + // Note: we don't clear real-time timers anymore. Should we?.. + g_ui->Reset(); + g_input->Reset(); + g_graphics->Reset(); + g_python->Reset(); + g_audio->Reset(); + + if (!HeadlessMode()) { + // If we haven't, send a first frame_def to the graphics thread to kick + // things off (it'll start sending us requests for more after it gets the + // first). + if (!have_sent_initial_frame_def_) { + g_graphics->BuildAndPushFrameDef(); + have_sent_initial_frame_def_ = true; + } + } +} + +auto Game::IsInUIContext() const -> bool { + return (g_ui && Context::current().target.get() == g_ui); +} + +void Game::PushShowURLCall(const std::string& url) { + PushCall([url] { + assert(InGameThread()); + assert(g_python); + g_python->ShowURL(url); + }); +} + +auto Game::GetForegroundContext() -> Context { + Session* s = GetForegroundSession(); + if (s) { + return s->GetForegroundContext(); + } else { + return Context(); + } +} + +void Game::PushBackButtonCall(InputDevice* input_device) { + PushCall([this, input_device] { + assert(InGameThread()); + + // Ignore if UI isn't up yet. + if (!g_ui || !g_ui->overlay_root_widget() || !g_ui->screen_root_widget()) { + return; + } + + // If there's a UI up, send along a cancel message. + if (g_ui->overlay_root_widget()->GetChildCount() != 0 + || g_ui->screen_root_widget()->GetChildCount() != 0) { + g_ui->root_widget()->HandleMessage( + WidgetMessage(WidgetMessage::Type::kCancel)); + } else { + // If there's no main screen or overlay windows, ask for a menu owned by + // this device. + MainMenuPress(input_device); + } + }); +} + +void Game::PushStringEditSetCall(const std::string& value) { + PushCall([value] { + if (!g_ui) { + Log("Error: No ui on StringEditSetEvent."); + return; + } +#if BA_OSTYPE_ANDROID + TextWidget* w = TextWidget::GetAndroidStringEditWidget(); + if (w) { + w->SetText(value); + } +#else + throw Exception(); // Shouldn't get here. +#endif + }); +} + +void Game::PushStringEditCancelCall() { + PushCall([] { + if (!g_ui) { + Log("Error: No ui in PushStringEditCancelCall."); + return; + } + }); +} + +// Called by a newly made Session instance to set itself as the current +// session. +void Game::SetForegroundSession(Session* s) { + assert(InGameThread()); + foreground_session_ = s; +} + +void Game::SetForegroundScene(Scene* sg) { + assert(InGameThread()); + if (foreground_scene_.get() != sg) { + foreground_scene_ = sg; + + // If this scene has a globals-node, put it in charge of stuff. + if (GlobalsNode* g = sg->globals_node()) { + g->SetAsForeground(); + } + } +} + +void Game::LaunchClientSession() { + if (in_update_) { + throw Exception( + "can't launch a session from within a session update; use " + "ba.pushcall()"); + } + assert(InGameThread()); + + // Don't want to pick up any old stuff in here. + ScopedSetContext cp(nullptr); + + // This should kill any current session and get us back to a blank slate. + Reset(); + + // Create the new session. + Object::WeakRef old_foreground_session(foreground_session_); + try { + auto s(Object::New()); + sessions_.push_back(s); + + // It should have set itself as FG. + assert(foreground_session_ == s); + } catch (const std::exception& e) { + // If it failed, restore the previous current session and re-throw. + SetForegroundSession(old_foreground_session.get()); + throw Exception(std::string("HostSession failed: ") + e.what()); + } +} + +void Game::LaunchReplaySession(const std::string& file_name) { + if (in_update_) + throw Exception( + "can't launch a session from within a session update; use " + "ba.pushcall()"); + + assert(InGameThread()); + + // Don't want to pick up any old stuff in here. + ScopedSetContext cp(nullptr); + + // This should kill any current session and get us back to a blank slate. + Reset(); + + // Create the new session. + Object::WeakRef old_foreground_session(foreground_session_); + try { + auto s(Object::New(file_name)); + sessions_.push_back(s); + + // It should have set itself as FG. + assert(foreground_session_ == s); + } catch (const std::exception& e) { + // If it failed, restore the previous current session and re-throw the + // exception. + SetForegroundSession(old_foreground_session.get()); + throw Exception(std::string("HostSession failed: ") + e.what()); + } +} + +void Game::LaunchHostSession(PyObject* session_type_obj, + BenchmarkType benchmark_type) { + if (in_update_) { + throw Exception( + "can't call host_session() from within session update; use " + "ba.pushcall()"); + } + + assert(InGameThread()); + + // If for some reason we're still attached to a host, kill the connection. + if (connection_to_host_.exists()) { + Log("Had host-connection during LaunchHostSession(); shouldn't happen."); + connection_to_host_->RequestDisconnect(); + connection_to_host_.Clear(); + has_connection_to_host_ = false; + UpdateGameRoster(); + } + + // Don't want to pick up any old stuff in here. + ScopedSetContext cp(nullptr); + + // This should kill any current session and get us back to a blank slate. + Reset(); + + Object::WeakRef old_foreground_session(foreground_session_); + try { + // Create the new session. + auto s(Object::New(session_type_obj)); + s->set_benchmark_type(benchmark_type); + sessions_.emplace_back(s); + + // It should have set itself as FG. + assert(foreground_session_ == s); + } catch (const std::exception& e) { + // If it failed, restore the previous session context and re-throw the + // exception. + SetForegroundSession(old_foreground_session.get()); + throw Exception(std::string("HostSession failed: ") + e.what()); + } +} + +void Game::RunMainMenu() { + PushCall([this] { + if (g_app_globals->shutting_down) { + return; + } + assert(g_python); + assert(InGameThread()); + PythonRef result = + g_python->obj(Python::ObjID::kLaunchMainMenuSessionCall).Call(); + if (!result.exists()) { + throw Exception("error running main menu"); + } + }); +} + +// Commands run via the in-game console. These are a bit more 'casual' and run +// in the current visible context. + +void Game::PushInGameConsoleScriptCommand(const std::string& command) { + PushCall([this, command] { + // These are always run in whichever context is 'visible'. + ScopedSetContext cp(GetForegroundContext()); + PythonCommand cmd(command, ""); + if (!g_app_globals->user_ran_commands) { + g_app_globals->user_ran_commands = true; + } + if (cmd.CanEval()) { + PyObject* obj = cmd.RunReturnObj(true); + if (obj && obj != Py_None) { + PyObject* s = PyObject_Repr(obj); + if (s) { + const char* c = PyUnicode_AsUTF8(s); + if (g_app_globals->console) { + g_app_globals->console->Print(std::string(c) + "\n"); + } + Py_DECREF(s); + } + Py_DECREF(obj); + } + } else { + // Not eval-able; just run it. + cmd.Run(); + } + }); +} + +// Commands run via stdin. +void Game::PushStdinScriptCommand(const std::string& command) { + PushCall([this, command] { + // These are always run in whichever context is 'visible'. + ScopedSetContext cp(GetForegroundContext()); + PythonCommand cmd(command, ""); + if (!g_app_globals->user_ran_commands) { + g_app_globals->user_ran_commands = true; + } + + // Eval this if possible (so we can possibly print return value). + if (cmd.CanEval()) { + if (PyObject* obj = cmd.RunReturnObj(true)) { + // Print the value if we're running directly from a terminal + // (or being run under the server-manager) + if ((IsStdinATerminal() || g_app->server_wrapper_managed()) + && obj != Py_None) { + PyObject* s = PyObject_Repr(obj); + if (s) { + const char* c = PyUnicode_AsUTF8(s); + printf("%s\n", c); + fflush(stdout); + Py_DECREF(s); + } + } + Py_DECREF(obj); + } + } else { + // Can't eval it; just run it. + cmd.Run(); + } + }); +} + +void Game::PushInterruptSignalCall() { + PushCall([this] { + assert(InGameThread()); + + // Special case; when running under the server-wrapper, we completely + // ignore interrupt signals (the wrapper acts on them). + if (g_app->server_wrapper_managed()) { + return; + } + + // Just go through _ba.quit() + // FIXME: Shouldn't need to go out to the python layer here... + g_python->obj(Python::ObjID::kQuitCall).Call(); + }); +} + +void Game::PushAskUserForTelnetAccessCall() { + PushCall([this] { + assert(InGameThread()); + ScopedSetContext cp(GetUIContext()); + g_python->obj(Python::ObjID::kTelnetAccessRequestCall).Call(); + }); +} + +void Game::HandleThreadPause() { + // Give userspace python stuff a chance to pause. + ScopedSetContext cp(GetUIContextTarget()); + g_python->obj(Python::ObjID::kOnAppPauseCall).Call(); + + // Tell our account client to commit any outstanding changes to disk. + g_python->CommitLocalData(); +} + +// void Game::PushTelnetScriptCommand(const std::string& command) { +// PushCall([this, command] { +// // These are always run in whichever context is 'visible'. +// ScopedSetContext cp(GetForegroundContext()); +// if (!g_app_globals->user_ran_commands) { +// g_app_globals->user_ran_commands = true; +// } +// PythonCommand cmd(command, ""); +// if (cmd.CanEval()) { +// PyObject* obj = cmd.RunReturnObj(true); +// if (obj && obj != Py_None) { +// PyObject* s = PyObject_Repr(obj); +// if (s) { +// const char* c = PyUnicode_AsUTF8(s); +// PushTelnetPrintCall(std::string(c) + "\n"); +// Py_DECREF(s); +// } +// Py_DECREF(obj); +// } +// } else { +// // Not eval-able; just run it. +// cmd.Run(); +// } +// PushTelnetPrintCall("ballisticacore> "); +// }); +// } + +// void Game::PushTelnetPrintCall(const std::string& message) { +// PushCall([message] { +// if (g_app_globals->telnet_server) { +// g_app_globals->telnet_server->Print(message); +// } +// }); +// } + +void Game::PushPythonCall(const Object::Ref& call) { + // Since we're mucking with refs, need to limit to game thread. + BA_PRECONDITION(InGameThread()); + BA_PRECONDITION(call->object_strong_ref_count() > 0); + PushCall([call] { + assert(call.exists()); + call->Run(); + }); +} + +void Game::PushPythonCallArgs(const Object::Ref& call, + const PythonRef& args) { + // Since we're mucking with refs, need to limit to game thread. + BA_PRECONDITION(InGameThread()); + BA_PRECONDITION(call->object_strong_ref_count() > 0); + PushCall([call, args] { + assert(call.exists()); + call->Run(args.get()); + }); +} + +void Game::PushPythonWeakCall(const Object::WeakRef& call) { + // Since we're mucking with refs, need to limit to game thread. + BA_PRECONDITION(InGameThread()); + + // Even though we only hold a weak ref, we expect a valid strong-reffed + // object to be passed in. + assert(call.exists() && call->object_strong_ref_count() > 0); + + PushCall([call] { + if (call.exists()) { + Python::ScopedCallLabel label("PythonWeakCallMessage"); + call->Run(); + } + }); +} + +void Game::PushPythonWeakCallArgs( + const Object::WeakRef& call, const PythonRef& args) { + // Since we're mucking with refs, need to limit to game thread. + BA_PRECONDITION(InGameThread()); + + // Even though we only hold a weak ref, we expect a valid strong-reffed + // object to be passed in. + assert(call.exists() && call->object_strong_ref_count() > 0); + + PushCall([call, args] { + if (call.exists()) call->Run(args.get()); + }); +} + +void Game::PushPythonRawCallable(PyObject* callable) { + PushCall([this, callable] { + assert(InGameThread()); + + // Lets run this in the UI context. + // (can add other options if we need later) + ScopedSetContext cp(GetUIContext()); + + // This event contains a raw python obj with an incremented ref-count. + auto call(Object::New(callable)); + Py_DECREF(callable); // now just held by call + + call->Run(); + }); +} + +void Game::PushScreenMessage(const std::string& message, + const Vector3f& color) { + PushCall([message, color] { g_graphics->AddScreenMessage(message, color); }); +} + +void Game::SetReplaySpeedExponent(int val) { + replay_speed_exponent_ = std::min(3, std::max(-3, val)); + replay_speed_mult_ = powf(2.0f, static_cast(replay_speed_exponent_)); +} + +void Game::SetDebugSpeedExponent(int val) { + debug_speed_exponent_ = val; + debug_speed_mult_ = powf(2.0f, static_cast(debug_speed_exponent_)); + + Session* s = GetForegroundSession(); + if (s) s->DebugSpeedMultChanged(); +} + +void Game::ChangeGameSpeed(int offs) { + assert(InGameThread()); + + // if we're in a replay session, adjust playback speed there + if (dynamic_cast(GetForegroundSession())) { + int old_speed = replay_speed_exponent(); + SetReplaySpeedExponent(replay_speed_exponent() + offs); + if (old_speed != replay_speed_exponent()) { + ScreenMessage( + "{\"r\":\"watchWindow.playbackSpeedText\"," + "\"s\":[[\"${SPEED}\",\"" + + std::to_string(replay_speed_mult()) + "\"]]}"); + } + return; + } + // Otherwise, in debug build, we allow speeding/slowing anything. +#if BA_DEBUG_BUILD + debug_speed_exponent_ += offs; + debug_speed_mult_ = powf(2.0f, static_cast(debug_speed_exponent_)); + ScreenMessage("DEBUG GAME SPEED TO " + std::to_string(debug_speed_mult_)); + Session* s = GetForegroundSession(); + if (s) { + s->DebugSpeedMultChanged(); + } +#endif // BA_DEBUG_BUILD +} + +auto Game::GetUIContext() const -> Context { + return Context(GetUIContextTarget()); +} + +void Game::PushToggleManualCameraCall() { + PushCall([] { g_graphics->ToggleManualCamera(); }); +} + +void Game::PushToggleDebugInfoDisplayCall() { + PushCall([] { g_graphics->ToggleDebugInfoDisplay(); }); +} + +void Game::PushToggleCollisionGeometryDisplayCall() { + PushCall([] { g_graphics->ToggleDebugDraw(); }); +} + +void Game::PushMainMenuPressCall(InputDevice* device) { + PushCall([this, device] { MainMenuPress(device); }); +} + +void Game::MainMenuPress(InputDevice* device) { + assert(InGameThread()); + g_python->HandleDeviceMenuPress(device); +} + +void Game::PushScreenResizeCall(float virtual_width, float virtual_height, + float pixel_width, float pixel_height) { + PushCall([=] { + ScreenResize(virtual_width, virtual_height, pixel_width, pixel_height); + }); +} + +void Game::ScreenResize(float virtual_width, float virtual_height, + float pixel_width, float pixel_height) { + assert(InGameThread()); + assert(g_graphics != nullptr); + if (g_graphics) { + g_graphics->ScreenResize(virtual_width, virtual_height, pixel_width, + pixel_height); + } + if (g_ui) { + g_ui->ScreenSizeChanged(); + } + if (Session* session = GetForegroundSession()) { + session->ScreenSizeChanged(); + } +} + +void Game::PushGameServiceAchievementListCall( + const std::set& achievements) { + PushCall([this, achievements] { GameServiceAchievementList(achievements); }); +} + +void Game::GameServiceAchievementList( + const std::set& achievements) { + assert(g_python); + assert(InGameThread()); + g_python->DispatchRemoteAchievementList(achievements); +} + +void Game::PushScoresToBeatResponseCall(bool success, + const std::list& scores, + void* py_callback) { + PushCall([this, success, scores, py_callback] { + ScoresToBeatResponse(success, scores, py_callback); + }); +} + +void Game::ScoresToBeatResponse(bool success, + const std::list& scores, + void* py_callback) { + assert(g_python); + assert(InGameThread()); + g_python->DispatchScoresToBeatResponse(success, scores, py_callback); +} + +void Game::PushPlaySoundCall(SystemSoundID sound) { + PushCall([sound] { g_audio->PlaySound(g_media->GetSound(sound)); }); +} + +void Game::PushFriendScoreSetCall(const FriendScoreSet& score_set) { + PushCall([score_set] { g_python->HandleFriendScoresCB(score_set); }); +} + +void Game::PushConfirmQuitCall() { + PushCall([this] { + assert(InGameThread()); + if (HeadlessMode()) { + Log("PushConfirmQuitCall() unhandled on headless."); + } else { + // If input is locked, just quit immediately.. a confirm screen wouldn't + // work anyway + if (g_input->IsInputLocked() + || (g_app_globals->console != nullptr + && g_app_globals->console->active())) { + // Just go through _ba.quit() + // FIXME: Shouldn't need to go out to the python layer here... + g_python->obj(Python::ObjID::kQuitCall).Call(); + return; + } else { + // this needs to be run in the UI context + ScopedSetContext cp(GetUIContextTarget()); + + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kSwish)); + g_python->obj(Python::ObjID::kQuitWindowCall).Call(); + + // if we have a keyboard, give it UI ownership + InputDevice* keyboard = g_input->keyboard_input(); + if (keyboard) { + g_ui->SetUIInputDevice(keyboard); + } + } + } + }); +} + +void Game::Draw() { + g_graphics->BuildAndPushFrameDef(); + + // Now bring the game up to date. + // By doing this *after* shipping a new frame_def we're reducing the + // chance of frame drops at the expense of adding a bit of visual latency. + // Could maybe try to be smart about which to do first, but not sure + // if its worth it. + Update(); + + // Update our cheat tests. + millisecs_t now = g_platform->GetTicks(); + millisecs_t elapsed = now - last_draw_real_time_; + if (elapsed > largest_draw_time_increment_since_last_reset_) { + largest_draw_time_increment_since_last_reset_ = elapsed; + } + last_draw_real_time_ = now; + + // Sanity test: can make sure our scene is taking exactly 2 steps + // per frame here.. (should generally be the case on 60hz devices). + if (explicit_bool(false)) { + static int64_t last_step = 0; + HostActivity* ha = GetForegroundContext().GetHostActivity(); + if (ha) { + int64_t step = ha->scene()->stepnum(); + Log(std::to_string(step - last_step)); + last_step = step; + } + } +} + +void Game::PushFrameDefRequest() { + PushCall([this] { Draw(); }); +} + +void Game::PushOnAppResumeCall() { + PushCall([] { + // Wipe out whatever input device was in control of the UI. + assert(g_ui); + g_ui->SetUIInputDevice(nullptr); + }); +} + +// Look through everything in our config dict and act on it. +void Game::ApplyConfig() { + assert(InGameThread()); + + // Not relevant for fullscreen anymore + // since we're fullscreen windows everywhere. + int width = 800; + int height = 600; + + // Texture quality. + TextureQuality texture_quality_requested; + std::string texqualstr = + g_app_config->Resolve(AppConfig::StringID::kTextureQuality); + + if (texqualstr == "Auto") { + texture_quality_requested = TextureQuality::kAuto; + } else if (texqualstr == "High") { + texture_quality_requested = TextureQuality::kHigh; + } else if (texqualstr == "Medium") { + texture_quality_requested = TextureQuality::kMedium; + } else if (texqualstr == "Low") { + texture_quality_requested = TextureQuality::kLow; + } else { + Log("Invalid texture quality: '" + texqualstr + "'; defaulting to low."); + texture_quality_requested = TextureQuality::kLow; + } + + // Graphics quality. + std::string gqualstr = + g_app_config->Resolve(AppConfig::StringID::kGraphicsQuality); + GraphicsQuality graphics_quality_requested; + + if (gqualstr == "Auto") { + graphics_quality_requested = GraphicsQuality::kAuto; + } else if (gqualstr == "Higher") { + graphics_quality_requested = GraphicsQuality::kHigher; + } else if (gqualstr == "High") { + graphics_quality_requested = GraphicsQuality::kHigh; + } else if (gqualstr == "Medium") { + graphics_quality_requested = GraphicsQuality::kMedium; + } else if (gqualstr == "Low") { + graphics_quality_requested = GraphicsQuality::kLow; + } else { + Log("Error: Invalid graphics quality: '" + gqualstr + + "'; defaulting to auto."); + graphics_quality_requested = GraphicsQuality::kAuto; + } + + // Android res string. + std::string android_res = + g_app_config->Resolve(AppConfig::StringID::kResolutionAndroid); + + bool fullscreen = g_app_config->Resolve(AppConfig::BoolID::kFullscreen); + + // Note: when the graphics-thread applies the first set-screen event it will + // trigger the remainder of startup such as media-loading; make sure nothing + // below this will affect that. + g_graphics_server->PushSetScreenCall(fullscreen, width, height, + texture_quality_requested, + graphics_quality_requested, android_res); + + // FIXME: The graphics server should kick this off *AFTER* it sets the actual + // quality values; here we're just sending along our requested values which + // is wrong. If there's a session up, inform it of the (potential) change. + Session* session = GetForegroundSession(); + if (session) { + session->GraphicsQualityChanged(graphics_quality_requested); + } + + if (!HeadlessMode()) { + g_app_globals->remote_server_accepting_connections = + g_app_config->Resolve(AppConfig::BoolID::kEnableRemoteApp); + } + + chat_muted_ = g_app_config->Resolve(AppConfig::BoolID::kChatMuted); + g_graphics->set_show_fps(g_app_config->Resolve(AppConfig::BoolID::kShowFPS)); + + // Set tv border (for both client and server). + bool tv_border = g_app_config->Resolve(AppConfig::BoolID::kTVBorder); + g_graphics_server->PushCall( + [tv_border] { g_graphics_server->set_tv_border(tv_border); }); + + // FIXME: this should exist either on the client or the server; not both. + // (and should be communicated via frameldefs/etc.) + g_graphics->set_tv_border(tv_border); + + g_graphics_server->PushSetScreenGammaCall( + g_app_config->Resolve(AppConfig::FloatID::kScreenGamma)); + g_graphics_server->PushSetScreenPixelScaleCall( + g_app_config->Resolve(AppConfig::FloatID::kScreenPixelScale)); + + TextWidget::set_always_use_internal_keyboard( + g_app_config->Resolve(AppConfig::BoolID::kAlwaysUseInternalKeyboard)); + + // V-sync setting. + std::string v_sync = + g_app_config->Resolve(AppConfig::StringID::kVerticalSync); + bool do_v_sync{}; + bool auto_v_sync{}; + if (v_sync == "Auto") { + do_v_sync = true; + auto_v_sync = true; + } else if (v_sync == "Always") { + do_v_sync = true; + auto_v_sync = false; + } else if (v_sync == "Never") { + do_v_sync = false; + auto_v_sync = false; + } else { + do_v_sync = false; + auto_v_sync = false; + Log("Error: Invalid 'Vertical Sync' value: '" + v_sync + "'"); + } + g_graphics_server->PushSetVSyncCall(do_v_sync, auto_v_sync); + + g_audio->SetVolumes(g_app_config->Resolve(AppConfig::FloatID::kMusicVolume), + g_app_config->Resolve(AppConfig::FloatID::kSoundVolume)); + + // Kick-idle-players setting (hmm is this still relevant?). + auto* host_session = dynamic_cast(foreground_session_.get()); + kick_idle_players_ = + g_app_config->Resolve(AppConfig::BoolID::kKickIdlePlayers); + if (host_session) { + host_session->SetKickIdlePlayers(kick_idle_players_); + } + + // Input doesn't yet exist when we first run; it updates itself initially when + // it comes up (but we do thereafter). + // if (input_) { + assert(g_input); + g_input->ApplyAppConfig(); + // } + + // Set up network ports/states. + int port = g_app_config->Resolve(AppConfig::IntID::kPort); + int telnet_port = g_app_config->Resolve(AppConfig::IntID::kTelnetPort); + + // NOTE: Hard disabling telnet for now in headless builds; + // it was being exploited to own servers. + bool enable_telnet = + g_buildconfig.headless_build() + ? false + : g_app_config->Resolve(AppConfig::BoolID::kEnableTelnet); + std::string telnet_password = + g_app_config->Resolve(AppConfig::StringID::kTelnetPassword); + + g_app->PushNetworkSetupCall(port, telnet_port, enable_telnet, + telnet_password); + + bool disable_camera_shake = + g_app_config->Resolve(AppConfig::BoolID::kDisableCameraShake); + g_graphics->set_camera_shake_disabled(disable_camera_shake); + + bool disable_camera_gyro = + g_app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro); + g_graphics->set_camera_gyro_explicitly_disabled(disable_camera_gyro); + + // Any platform-specific settings. + g_platform->ApplyConfig(); +} + +void Game::PushApplyConfigCall() { + PushCall([this] { ApplyConfig(); }); +} + +void Game::PushRemoveGraphicsServerRenderHoldCall() { + PushCall([] { + // This call acts as a flush of sorts; when it goes through, + // we push a call to the graphics server saying its ok for it + // to start rendering again. Thus any already-queued-up + // frame_defs or whatnot will be ignored. + g_graphics_server->PushRemoveRenderHoldCall(); + }); +} + +void Game::PushSetFriendListCall(const std::vector& friends) { + PushCall([friends] { g_python->DispatchFriendList(friends); }); +} + +void Game::PushFreeMediaComponentRefsCall( + const std::vector*>& components) { + PushCall([components] { + for (auto&& i : components) { + delete i; + } + }); +} + +void Game::PushHavePendingLoadsDoneCall() { + PushCall([] { g_media->ClearPendingLoadsDoneList(); }); +} + +void Game::ToggleConsole() { + assert(InGameThread()); + if (auto console = g_app_globals->console) { + console->ToggleState(); + } +} + +void Game::PushConsolePrintCall(const std::string& msg) { + PushCall([msg] { + // Send them to the console if its been created or store them + // for when it is (unless we're headless in which case it never will). + if (auto console = g_app_globals->console) { + console->Print(msg); + } else if (!HeadlessMode()) { + g_app_globals->console_startup_messages += msg; + } + }); +} + +void Game::PushHavePendingLoadsCall() { + PushCall([this] { + have_pending_loads_ = true; + UpdateProcessTimer(); + }); +} + +void Game::PushShutdownCall(bool soft) { + PushCall([this, soft] { Shutdown(soft); }); +} + +void Game::Shutdown(bool soft) { + assert(InGameThread()); + + if (!g_app_globals->shutting_down) { + g_app_globals->shutting_down = true; + + // Nuke the app if we get stuck shutting down. + Utils::StartSuicideTimer("shutdown", 10000); + + // Call our shutdown callback. + g_python->obj(Python::ObjID::kShutdownCall).Call(); + + // If we have any client/host connections, give them + // a chance to shoot off disconnect packets or whatnot. + for (auto& connection : connections_to_clients_) { + connection.second->RequestDisconnect(); + } + if (connection_to_host_.exists()) { + connection_to_host_->RequestDisconnect(); + } + + // Let's do the same stuff we do when our thread is pausing. (committing + // account-client to disk, etc). + HandleThreadPause(); + + // Attempt to report/store outstanding log stuff. + Python::PutLog(false); + + // Ideally we'd want to give some of the above stuff + // a few seconds to complete, but just calling it done for now. + g_app->PushShutdownCompleteCall(); + } +} + +void Game::ResetInput() { + assert(InGameThread()); + g_input->ResetKeyboardHeldKeys(); + g_input->ResetJoyStickHeldButtons(); +} + +auto Game::RemovePlayer(Player* player) -> void { + assert(InGameThread()); + if (HostSession* host_session = player->GetHostSession()) { + host_session->RemovePlayer(player); + } else { + Log("Got RemovePlayer call but have no host_session"); + } +} + +auto Game::NewRealTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> int { + int offset = 0; + Timer* t = realtimers_->NewTimer(GetRealTime(), length, offset, + repeat ? -1 : 0, runnable); + return t->id(); +} + +void Game::DeleteRealTimer(int timer_id) { realtimers_->DeleteTimer(timer_id); } + +void Game::SetRealTimerLength(int timer_id, millisecs_t length) { + Timer* t = realtimers_->GetTimer(timer_id); + if (t) { + t->SetLength(length); + } else { + Log("Error: Game::SetRealTimerLength() called on nonexistent timer."); + } +} + +void Game::Process() { + have_pending_loads_ = g_media->RunPendingLoadsGameThread(); + UpdateProcessTimer(); +} + +void Game::SetLanguageKeys(const std::map& language) { + assert(InGameThread()); + { + std::lock_guard lock(language_mutex_); + language_ = language; + } + + // Let's also inform existing session stuff so it can update itself. + if (Session* session = GetForegroundSession()) { + session->LanguageChanged(); + } + + // As well as existing UI stuff. + if (Widget* root_widget = g_ui->root_widget()) { + root_widget->OnLanguageChange(); + } + + // Also clear translations on all screen-messages. + g_graphics->ClearScreenMessageTranslations(); +} + +auto DoCompileResourceString(cJSON* obj) -> std::string { + assert(InGameThread()); + assert(obj != nullptr); + + std::string result; + + // If its got a "r" key, look it up as a resource.. (with optional fallback). + cJSON* resource = cJSON_GetObjectItem(obj, "r"); + if (resource == nullptr) { + resource = cJSON_GetObjectItem(obj, "resource"); + // As of build 14318, complain if we find long key names; hope to remove + // them soon. + if (resource != nullptr) { + static bool printed = false; + if (!printed) { + printed = true; + char* c = cJSON_Print(obj); + BA_LOG_ONCE("found long key 'resource' in raw lstr json: " + + std::string(c)); + free(c); + } + } + } + if (resource != nullptr) { + // Look for fallback-resource. + cJSON* fallback_resource = cJSON_GetObjectItem(obj, "f"); + if (fallback_resource == nullptr) { + fallback_resource = cJSON_GetObjectItem(obj, "fallback"); + + // As of build 14318, complain if we find old long key names; hope to + // remove them soon. + if (fallback_resource != nullptr) { + static bool printed = false; + if (!printed) { + printed = true; + char* c = cJSON_Print(obj); + BA_LOG_ONCE("found long key 'fallback' in raw lstr json: " + + std::string(c)); + free(c); + } + } + } + cJSON* fallback_value = cJSON_GetObjectItem(obj, "fv"); + result = g_python->GetResource( + resource->valuestring, + fallback_resource ? fallback_resource->valuestring : nullptr, + fallback_value ? fallback_value->valuestring : nullptr); + } else { + // Apparently not a resource; lets try as a translation ("t" keys). + cJSON* translate = cJSON_GetObjectItem(obj, "t"); + if (translate == nullptr) { + translate = cJSON_GetObjectItem(obj, "translate"); + + // As of build 14318, complain if we find long key names; hope to remove + // them soon. + if (translate != nullptr) { + static bool printed = false; + if (!printed) { + printed = true; + char* c = cJSON_Print(obj); + BA_LOG_ONCE("found long key 'translate' in raw lstr json: " + + std::string(c)); + free(c); + } + } + } + if (translate != nullptr) { + if (translate->type != cJSON_Array + || cJSON_GetArraySize(translate) != 2) { + throw Exception("Expected a 2 member array for translate"); + } + cJSON* category = cJSON_GetArrayItem(translate, 0); + if (category->type != cJSON_String) { + throw Exception( + "First member of translate array (category) must be a string"); + } + cJSON* value = cJSON_GetArrayItem(translate, 1); + if (value->type != cJSON_String) { + throw Exception( + "Second member of translate array (value) must be a string"); + } + result = + g_python->GetTranslation(category->valuestring, value->valuestring); + } else { + // Lastly try it as a value ("value" or "v"). + // (can be useful for feeding explicit strings while still allowing + // translated subs + cJSON* value = cJSON_GetObjectItem(obj, "v"); + if (value == nullptr) { + value = cJSON_GetObjectItem(obj, "value"); + + // As of build 14318, complain if we find long key names; hope to remove + // them soon. + if (value != nullptr) { + static bool printed = false; + if (!printed) { + printed = true; + char* c = cJSON_Print(obj); + BA_LOG_ONCE("found long key 'value' in raw lstr json: " + + std::string(c)); + free(c); + } + } + } + if (value != nullptr) { + if (value->type != cJSON_String) { + throw Exception("Expected a string for value"); + } + result = value->valuestring; + } else { + throw Exception("no 'resource', 'translate', or 'value' keys found"); + } + } + } + // Ok; now no matter what it was, see if it contains any subs and replace + // them. + // ("subs" or "s") + cJSON* subs = cJSON_GetObjectItem(obj, "s"); + if (subs == nullptr) { + subs = cJSON_GetObjectItem(obj, "subs"); + + // As of build 14318, complain if we find long key names; hope to remove + // them soon. + if (subs != nullptr) { + static bool printed = false; + if (!printed) { + printed = true; + char* c = cJSON_Print(obj); + BA_LOG_ONCE("found long key 'subs' in raw lstr json: " + + std::string(c)); + free(c); + } + } + } + if (subs != nullptr) { + if (subs->type != cJSON_Array) { + throw Exception("expected an array for 'subs'"); + } + int subsCount = cJSON_GetArraySize(subs); + for (int i = 0; i < subsCount; i++) { + cJSON* sub = cJSON_GetArrayItem(subs, i); + if (sub->type != cJSON_Array || cJSON_GetArraySize(sub) != 2) { + throw Exception( + "Invalid subs entry; expected length 2 list of sub/replacement."); + } + + // First item should be a string. + cJSON* key = cJSON_GetArrayItem(sub, 0); + if (key->type != cJSON_String) { + throw Exception("Sub keys must be strings."); + } + std::string s_key = key->valuestring; + + // Second item can be a string or a dict; if its a dict, we go recursive. + cJSON* value = cJSON_GetArrayItem(sub, 1); + std::string s_val; + if (value->type == cJSON_String) { + s_val = value->valuestring; + } else if (value->type == cJSON_Object) { + s_val = DoCompileResourceString(value); + } else { + throw Exception("Sub values must be strings or dicts."); + } + + // Replace *ALL* occurrences. + // FIXME: Using this simple logic, If our replace value contains our + // search value we get an infinite loop. For now, just error in that case. + if (s_val.find(s_key) != std::string::npos) { + throw Exception("Subs replace string cannot contain search string."); + } + while (true) { + size_t pos = result.find(s_key); + if (pos == std::string::npos) { + break; + } + result.replace(pos, s_key.size(), s_val); + } + } + } + return result; +} + +auto Game::CompileResourceString(const std::string& s, const std::string& loc, + bool* valid) -> std::string { + assert(InGameThread()); + assert(g_python != nullptr); + + bool dummyvalid; + if (valid == nullptr) { + valid = &dummyvalid; + } + + // Quick out: if it doesn't start with a { and end with a }, treat it as a + // literal and just return it as-is. + if (s.size() < 2 || s[0] != '{' || s[s.size() - 1] != '}') { + *valid = true; + return s; + } + + cJSON* root = cJSON_Parse(s.c_str()); + if (root == nullptr) { + Log("CompileResourceString failed (loc " + loc + "); invalid json: '" + s + + "'"); + *valid = false; + return ""; + } + std::string result; + try { + result = DoCompileResourceString(root); + *valid = true; + } catch (const std::exception& e) { + Log("CompileResourceString failed (loc " + loc + + "): " + std::string(e.what()) + "; str='" + s + "'"); + result = ""; + *valid = false; + } + cJSON_Delete(root); + return result; +} + +auto Game::GetResourceString(const std::string& key) -> std::string { + std::string val; + { + std::lock_guard lock(language_mutex_); + auto i = language_.find(key); + if (i != language_.end()) { + val = i->second; + } + } + return val; +} + +auto Game::CharStr(SpecialChar id) -> std::string { + std::lock_guard lock(special_char_mutex_); + std::string val; + auto i = special_char_strings_.find(id); + if (i != special_char_strings_.end()) { + val = i->second; + } else { + BA_LOG_PYTHON_TRACE_ONCE("invalid key in CharStr(): '" + + std::to_string(static_cast(id)) + "'"); + val = "?"; + } + return val; +} + +void Game::HandleClientDisconnected(int id) { + auto i = connections_to_clients_.find(id); + if (i != connections_to_clients_.end()) { + bool was_connected = i->second->can_communicate(); + std::string leaver_spec = i->second->peer_spec().GetSpecString(); + std::vector leave_msg(leaver_spec.size() + 1); + leave_msg[0] = BA_MESSAGE_PARTY_MEMBER_LEFT; + memcpy(&(leave_msg[1]), leaver_spec.c_str(), leaver_spec.size()); + connections_to_clients_.erase(i); + + // If the client was connected, they were on the roster. + // We need to update it and send it to all remaining clients since they're + // gone. Also inform everyone who just left so they can announce it + // (technically could consolidate these messages but whatever...). + if (was_connected) { + UpdateGameRoster(); + for (auto&& connection : connections_to_clients_) { + if (ShouldAnnouncePartyJoinsAndLeaves()) { + connection.second->SendReliableMessage(leave_msg); + } + } + } + } +} + +void Game::PushClientDisconnectedCall(int id) { + PushCall([this, id] { HandleClientDisconnected(id); }); +} + +auto Game::ShouldAnnouncePartyJoinsAndLeaves() -> bool { + assert(InGameThread()); + + // At the moment we don't announce these for public internet parties.. (too + // much noise). + return !public_party_enabled(); +} + +void Game::CleanUpBeforeConnectingToHost() { + // We can't have connected clients and a host-connection at the same time. + // Make a minimal attempt to disconnect any client connections we have, but + // get them off the list immediately. + // FIXME: Should we have a 'purgatory' for dying client connections?.. + // (they may not get the single 'go away' packet we send here) + ForceDisconnectClients(); + + // Also make sure our public party state is off; this will inform the server + // that it should not be handing out our address to anyone. + assert(g_python); + SetPublicPartyEnabled(false); +} + +auto Game::DisconnectClient(int client_id, int ban_seconds) -> bool { + assert(InGameThread()); + + if (connection_to_host_.exists()) { + // Kick-votes first appeared in 14248 + if (connection_to_host_->build_number() < 14248) { + return false; + } + if (client_id > 255) { + Log("DisconnectClient got client_id > 255 (" + std::to_string(client_id) + + ")"); + } else { + std::vector msg_out(2); + msg_out[0] = BA_MESSAGE_KICK_VOTE; + msg_out[1] = static_cast_check_fit(client_id); + connection_to_host_->SendReliableMessage(msg_out); + return true; + } + } else { + // No host connection - look for clients. + auto i = connections_to_clients_.find(client_id); + + if (i != connections_to_clients_.end()) { + // If this is considered a kick, add an entry to our banned list so we + // know not to let them back in for a while. + if (ban_seconds > 0) { + BanPlayer(i->second->peer_spec(), 1000 * ban_seconds); + } + i->second->RequestDisconnect(); + + // Do the official local disconnect immediately with the sounds and all + // that. + PushClientDisconnectedCall(client_id); + + return true; + } + } + return false; +} + +void Game::ForceDisconnectClients() { + for (auto&& i : connections_to_clients_) { + if (ConnectionToClient* client = i.second.get()) { + client->RequestDisconnect(); + } + } + connections_to_clients_.clear(); +} + +void Game::PushHostConnectedUDPCall(const SockAddr& addr, + bool print_connect_progress) { + PushCall([this, addr, print_connect_progress] { + // Attempt to disconnect any clients we have, turn off public-party + // advertising, etc. + CleanUpBeforeConnectingToHost(); + print_udp_connect_progress_ = print_connect_progress; + connection_to_host_ = Object::New(addr); + has_connection_to_host_ = true; + printed_host_disconnect_ = false; + }); +} + +void Game::PushDisconnectFromHostCall() { + PushCall([this] { + if (connection_to_host_.exists()) { + connection_to_host_->RequestDisconnect(); + } + }); +} + +void Game::PushDisconnectedFromHostCall() { + PushCall([this] { + if (connection_to_host_.exists()) { + bool was_connected = connection_to_host_->can_communicate(); + connection_to_host_.Clear(); + has_connection_to_host_ = false; + + // Clear out our party roster. + UpdateGameRoster(); + + // Go back to main menu *if* the connection was fully connected. + // Otherwise we're still probably sitting at the main menu + // so no need to reset it. + if (was_connected) { + RunMainMenu(); + } + } + }); +} + +void Game::SendScreenMessageToAll(const std::string& s, float r, float g, + float b) { + SendScreenMessageToClients(s, r, g, b); + ScreenMessage(s, {r, g, b}); +} + +void Game::SendScreenMessageToClients(const std::string& s, float r, float g, + float b) { + for (auto&& i : connections_to_clients_) { + if (i.second.exists() && i.second->can_communicate()) { + i.second->SendScreenMessage(s, r, g, b); + } + } +} + +void Game::SendScreenMessageToSpecificClients(const std::string& s, float r, + float g, float b, + const std::vector& clients) { + for (auto&& i : connections_to_clients_) { + if (i.second.exists() && i.second->can_communicate()) { + // Only send if this client is in our list. + for (auto c : clients) { + if (c == i.second->id()) { + i.second->SendScreenMessage(s, r, g, b); + break; + } + } + } + } + + // Now print locally only if -1 is in our list. + for (auto c : clients) { + if (c == -1) { + ScreenMessage(s, {r, g, b}); + break; + } + } +} + +auto Game::GetConnectionToHostUDP() -> ConnectionToHostUDP* { + ConnectionToHost* h = connection_to_host_.get(); + return h ? h->GetAsUDP() : nullptr; +} + +void Game::PushPartyInviteCall(const std::string& name, + const std::string& invite_id) { + PushCall([this, name, invite_id] { PartyInvite(name, invite_id); }); +} + +void Game::PartyInvite(const std::string& name, const std::string& invite_id) { + assert(InGameThread()); + g_python->PartyInvite(name, invite_id); +} + +void Game::PushPartyInviteRevokeCall(const std::string& invite_id) { + PushCall([this, invite_id] { PartyInviteRevoke(invite_id); }); +} + +void Game::PartyInviteRevoke(const std::string& invite_id) { + assert(InGameThread()); + g_python->PartyInviteRevoke(invite_id); +} + +void Game::PushUDPConnectionPacketCall(const std::vector& data, + const SockAddr& addr) { + PushCall([this, data, addr] { UDPConnectionPacket(data, addr); }); +} + +// Called for low level packets coming in pertaining to udp +// host/client-connections. +void Game::UDPConnectionPacket(const std::vector& data_in, + const SockAddr& addr) { + assert(!data_in.empty()); + + const uint8_t* data = &(data_in[0]); + auto data_size = static_cast(data_in.size()); + + switch (data[0]) { + case BA_PACKET_CLIENT_ACCEPT: { + if (data_size == 3) { + uint8_t request_id = data[2]; + + // If we have a udp-host-connection and its request-id matches, we're + // accepted; hooray! + ConnectionToHostUDP* hc = GetConnectionToHostUDP(); + if (hc && hc->request_id() == request_id) { + hc->set_client_id(data[1]); + } + } + break; + } + case BA_PACKET_DISCONNECT_FROM_CLIENT_REQUEST: { + if (data_size == 2) { + // Client is telling us (host) that it wants to disconnect. + uint8_t client_id = data[1]; + + // Wipe that client out (if it still exists). + PushClientDisconnectedCall(client_id); + + // Now send an ack so they know it's been taken care of. + g_network_write_module->PushSendToCall( + {BA_PACKET_DISCONNECT_FROM_CLIENT_ACK, client_id}, addr); + } + break; + } + case BA_PACKET_DISCONNECT_FROM_CLIENT_ACK: { + if (data_size == 2) { + // Host is telling us (client) that we've been disconnected. + uint8_t client_id = data[1]; + ConnectionToHostUDP* hc = GetConnectionToHostUDP(); + if (hc && hc->client_id() == client_id) { + PushDisconnectedFromHostCall(); + } + } + break; + } + case BA_PACKET_DISCONNECT_FROM_HOST_REQUEST: { + if (data_size == 2) { + uint8_t client_id = data[1]; + + // Host is telling us (client) to disconnect. + ConnectionToHostUDP* hc = GetConnectionToHostUDP(); + if (hc && hc->client_id() == client_id) { + PushDisconnectedFromHostCall(); + } + + // Now send an ack so they know it's been taken care of. + g_network_write_module->PushSendToCall( + {BA_PACKET_DISCONNECT_FROM_HOST_ACK, client_id}, addr); + } + break; + } + case BA_PACKET_DISCONNECT_FROM_HOST_ACK: { + break; + } + case BA_PACKET_CLIENT_GAMEPACKET_COMPRESSED: { + if (data_size > 2) { + uint8_t client_id = data[1]; + auto i = connections_to_clients_.find(client_id); + if (i != connections_to_clients_.end()) { + // FIXME: could change HandleGamePacketCompressed to avoid this + // copy. + std::vector data2(data_size - 2); + memcpy(data2.data(), data + 2, data_size - 2); + i->second->HandleGamePacketCompressed(data2); + return; + } else { + // Send a disconnect request aimed at them. + g_network_write_module->PushSendToCall( + {BA_PACKET_DISCONNECT_FROM_HOST_REQUEST, client_id}, addr); + } + } + break; + } + + case BA_PACKET_HOST_GAMEPACKET_COMPRESSED: { + if (data_size > 2) { + uint8_t request_id = data[1]; + + ConnectionToHostUDP* hc = GetConnectionToHostUDP(); + if (hc && hc->request_id() == request_id) { + // FIXME: Should change HandleGamePacketCompressed to avoid this copy. + std::vector data2(data_size - 2); + memcpy(data2.data(), data + 2, data_size - 2); + hc->HandleGamePacketCompressed(data2); + } + } + break; + } + + case BA_PACKET_CLIENT_DENY: + case BA_PACKET_CLIENT_DENY_PARTY_FULL: + case BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY: + case BA_PACKET_CLIENT_DENY_VERSION_MISMATCH: { + if (data_size == 2) { + uint8_t request_id = data[1]; + ConnectionToHostUDP* hc = GetConnectionToHostUDP(); + + // If they're for-sure rejecting *this* connection, kill it. + if (hc && hc->request_id() == request_id) { + bool keep_trying = false; + + // OBSOLETE BUT HERE FOR BACKWARDS COMPAT WITH 1.4.98 servers. + // Newer servers never deny us in this way and simply include + // their protocol version in the handshake they send us, allowing us + // to decide whether we support talking to them or not. + if (data[0] == BA_PACKET_CLIENT_DENY_VERSION_MISMATCH) { + // If we've got more protocols we can try, keep trying to connect + // with our other protocols until one works or we run out. + // FIXME: We should move this logic to the gamepacket or message + // level so it works for all connection types. + keep_trying = hc->SwitchProtocol(); + if (!keep_trying) { + if (!printed_host_disconnect_) { + ScreenMessage( + GetResourceString("connectionFailedVersionMismatchText"), + {1, 0, 0}); + printed_host_disconnect_ = true; + } + } + } else if (data[0] == BA_PACKET_CLIENT_DENY_PARTY_FULL) { + if (!printed_host_disconnect_) { + if (print_udp_connect_progress_) { + ScreenMessage( + GetResourceString("connectionFailedPartyFullText"), + {1, 0, 0}); + } + printed_host_disconnect_ = true; + } + } else if (data[0] == BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY) { + if (!printed_host_disconnect_) { + ScreenMessage( + GetResourceString("connectionFailedHostAlreadyInPartyText"), + {1, 0, 0}); + printed_host_disconnect_ = true; + } + } else { + if (!printed_host_disconnect_) { + ScreenMessage(GetResourceString("connectionRejectedText"), + {1, 0, 0}); + printed_host_disconnect_ = true; + } + } + if (!keep_trying) { + PushDisconnectedFromHostCall(); + } + } + } + break; + } + case BA_PACKET_CLIENT_REQUEST: { + if (data_size > 4) { + // Bytes 2 and 3 are their protocol ID, byte 4 is request ID, the rest + // is session-id. + uint16_t protocol_id; + memcpy(&protocol_id, data + 1, 2); + uint8_t request_id = data[3]; + + // They also send us their session-ID which should + // be completely unique to them; we can use this to lump client + // requests together and such. + std::vector client_name_buffer(data_size - 4 + 1); + memcpy(&(client_name_buffer[0]), data + 4, data_size - 4); + client_name_buffer[data_size - 4] = 0; // terminate string + std::string client_name = &(client_name_buffer[0]); + + if (static_cast(connections_to_clients_.size() + 1) + >= public_party_max_size()) { + // If we've reached our party size limit (including ourself in that + // count), reject. + + // Newer version have a specific party-full message; send that first + // but also follow up with a generic deny message for older clients. + g_network_write_module->PushSendToCall( + {BA_PACKET_CLIENT_DENY_PARTY_FULL, request_id}, addr); + + g_network_write_module->PushSendToCall( + {BA_PACKET_CLIENT_DENY, request_id}, addr); + + } else if (connection_to_host_.exists()) { + // If we're connected to someone else, we can't have clients. + g_network_write_module->PushSendToCall( + {BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY, request_id}, addr); + } else { + // Otherwise go ahead and make them a new client connection. + Object::Ref connection_to_client; + + // Go through and see if we already have a client-connection for + // this request-id. + for (auto&& i : connections_to_clients_) { + if (ConnectionToClientUDP* cc_udp = i.second->GetAsUDP()) { + if (cc_udp->client_name() == client_name) { + connection_to_client = cc_udp; + break; + } + } + } + if (!connection_to_client.exists()) { + // Create them a client object. + // Try to find an unused client-id in the range 0-255. + int client_id = 0; + bool found = false; + for (int i = 0; i < 256; i++) { + int test_id = (next_connection_to_client_id_ + i) % 255; + if (connections_to_clients_.find(test_id) + == connections_to_clients_.end()) { + client_id = test_id; + found = true; + break; + } + } + next_connection_to_client_id_++; + + // If all 255 slots are taken (whaaaaaaa?), reject them. + if (!found) { + std::vector msg_out(2); + msg_out[0] = BA_PACKET_CLIENT_DENY; + msg_out[1] = request_id; + g_network_write_module->PushSendToCall(msg_out, addr); + Log("All client slots full; really?.."); + break; + } + connection_to_client = Object::New( + addr, client_name, request_id, client_id); + connections_to_clients_[client_id] = connection_to_client; + } + + // If we got to this point, regardless of whether + // we already had a connection or not, tell them + // they're accepted. + std::vector msg_out(3); + msg_out[0] = BA_PACKET_CLIENT_ACCEPT; + assert(connection_to_client->id() < 256); + msg_out[1] = + static_cast_check_fit(connection_to_client->id()); + msg_out[2] = request_id; + g_network_write_module->PushSendToCall(msg_out, addr); + } + } + break; + } + default: + // Assuming we can get random other noise in here; + // should just silently ignore. + break; + } +} + +// Can probably kill this. +auto Game::GetConnectionsToClients() -> std::vector { + std::vector connections; + connections.reserve(connections_to_clients_.size()); + for (auto& connections_to_client : connections_to_clients_) { + if (connections_to_client.second.exists()) { + connections.push_back(connections_to_client.second.get()); + } else { + Log("HAVE NONEXISTENT CONNECTION_TO_CLIENT IN LIST; UNEXPECTED"); + } + } + return connections; +} + +#if BA_GOOGLE_BUILD + +void Game::PushClientDisconnectedGooglePlayCall(int google_id) { + PushCall([this, google_id] { + int id = ClientIDFromGooglePlayClientID(google_id); + HandleClientDisconnected(id); + }); +} + +int Game::ClientIDFromGooglePlayClientID(int google_id) { + auto i = google_play_id_to_client_id_map_.find(google_id); + if (i != google_play_id_to_client_id_map_.end()) { + return i->second; + } else { + BA_LOG_ONCE("ClientIDFromGooglePlayClientID failed for id " + + std::to_string(google_id)); + return -1; + } +} + +int Game::GooglePlayClientIDFromClientID(int client_id) { + auto i = client_id_to_google_play_id_map_.find(client_id); + if (i != client_id_to_google_play_id_map_.end()) { + return i->second; + } else { + BA_LOG_ONCE("client_id_to_google_play_id_map_ failed for id " + + std::to_string(client_id)); + return -1; + } +} + +// Called for Google Play connections. +void Game::PushCompressedGamePacketFromHostGooglePlayCall( + const std::vector& data) { + PushCall([this, data] { + if (!connection_to_host_.exists()) { + Log("Error: Got host game-packet message but have no host."); + return; + } + connection_to_host_->HandleGamePacketCompressed(data); + }); +} + +// Called for Google Play connections. +void Game::PushCompressedGamePacketFromClientGooglePlayCall( + int google_client_id, const std::vector& data) { + PushCall([this, google_client_id, data] { + int client_id = ClientIDFromGooglePlayClientID(google_client_id); + auto i = connections_to_clients_.find(client_id); + if (i == connections_to_clients_.end()) { + Log("Error: Got data-from-client msg for nonexistent client."); + return; + } + i->second->HandleGamePacketCompressed(data); + }); +} + +void Game::PushClientConnectedGooglePlayCall(int id) { + PushCall([this, id] { + // Find a free ballistica client_id. + int client_id = 0; + bool found = false; + for (int i = 0; i < 256; i++) { + int test_id = (next_connection_to_client_id_ + i) % 255; + if (connections_to_clients_.find(test_id) + == connections_to_clients_.end()) { + client_id = test_id; + found = true; + break; + } + } + next_connection_to_client_id_++; + + if (found) { + google_play_id_to_client_id_map_[id] = client_id; + client_id_to_google_play_id_map_[client_id] = id; + if (connections_to_clients_.find(client_id) + != connections_to_clients_.end()) { + Log("Error: Got client-connected message" + " for already existing client-id."); + } + connections_to_clients_[client_id] = + g_platform->AndroidGPGSNewConnectionToClient(client_id); + } else { + Log("no client_id available in ClientConnectedGooglePlayCall"); + } + }); +} + +void Game::PushHostConnectedGooglePlayCall() { + PushCall([this] { + // Attempt to disconnect any existing clients we have, turn off public-party + // advertising, etc. + CleanUpBeforeConnectingToHost(); + connection_to_host_ = g_platform->AndroidGPGSNewConnectionToHost(); + has_connection_to_host_ = true; + printed_host_disconnect_ = false; + }); +} + +int Game::GetGooglePlayClientCount() const { + assert(InGameThread()); + int count = 0; + for (auto&& i : connections_to_clients_) { + if (i.second.exists() && i.second->can_communicate() + && g_platform->AndroidIsGPGSConnectionToClient(i.second.get())) { + count++; + } + } + return count; +} +#endif // BA_GOOGLE_BUILD + +auto Game::GetConnectedClientCount() const -> int { + assert(InGameThread()); + int count = 0; + for (auto&& i : connections_to_clients_) { + if (i.second.exists() && i.second->can_communicate()) { + count++; + } + } + return count; +} + +auto Game::GetPartySize() const -> int { + assert(InGameThread()); + assert(game_roster_ != nullptr); + return cJSON_GetArraySize(game_roster_); +} + +void Game::LocalDisplayChatMessage(const std::vector& buffer) { + // 1 type byte, 1 spec-len byte, 1 or more spec chars, 0 or more msg chars. + if (buffer.size() > 3) { + size_t spec_len = buffer[1]; + if (spec_len > 0 && spec_len + 2 <= buffer.size()) { + size_t msg_len = buffer.size() - spec_len - 2; + std::vector b1(spec_len + 1); + memcpy(&(b1[0]), &(buffer[2]), spec_len); + b1[spec_len] = 0; + std::vector b2(msg_len + 1); + if (msg_len > 0) { + memcpy(&(b2[0]), &(buffer[2 + spec_len]), msg_len); + } + b2[msg_len] = 0; + + std::string final_message = + PlayerSpec(b1.data()).GetDisplayString() + ": " + b2.data(); + + // Store it locally. + chat_messages_.push_back(final_message); + while (chat_messages_.size() > kMaxChatMessages) { + chat_messages_.pop_front(); + } + + // Show it on the screen if they don't have their chat window open + // (and don't have chat muted). + if (!g_ui->root_ui()->party_window_open()) { + if (!chat_muted_) { + ScreenMessage(final_message, {0.7f, 1.0f, 0.7f}); + } + } else { + // Party window is open - notify it that there's a new message. + g_python->HandleLocalChatMessage(final_message); + } + if (!chat_muted_) { + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + } + } + } +} + +void Game::SendChatMessage(const std::string& message, + const std::vector* clients, + const std::string* sender_override) { + // Sending to particular clients is only applicable while hosting. + if (clients != nullptr && connection_to_host() != nullptr) { + throw Exception("Can't send chat message to specific clients as a client."); + } + + // Same with overriding sender name + if (sender_override != nullptr && connection_to_host() != nullptr) { + throw Exception( + "Can't send chat message with sender_override as a client."); + } + + std::string our_spec_string; + + if (sender_override != nullptr) { + std::string override_final = *sender_override; + if (override_final.size() > kMaxPartyNameCombinedSize) { + override_final.resize(kMaxPartyNameCombinedSize); + override_final += "..."; + } + our_spec_string = + PlayerSpec::GetDummyPlayerSpec(override_final).GetSpecString(); + } else { + if (connection_to_host() != nullptr) { + // NOTE - we send our own spec string with the chat message whether we're + // a client or server.. however on protocol version 30+ this is ignored + // by the server and replaced with a spec string it generates for us. + // so once we know we're connected to a 30+ server we can start sending + // blank strings as a client. + // (not that it really matters; chat messages are tiny overall) + our_spec_string = PlayerSpec::GetAccountPlayerSpec().GetSpecString(); + } else { + // As a host we want to do the equivalent of + // ConnectionToClient::GetCombinedSpec() except for local connections (so + // send our name as the combination of local players if possible). Look + // for players coming from this client-connection; if we find any, make a + // spec out of their name(s). + std::string p_name_combined; + if (auto* hs = dynamic_cast(GetForegroundSession())) { + for (auto&& p : hs->players()) { + InputDevice* input_device = p->GetInputDevice(); + if (p->accepted() && p->name_is_real() && input_device != nullptr + && !input_device->IsRemoteClient()) { + if (!p_name_combined.empty()) { + p_name_combined += "/"; + } + p_name_combined += p->GetName(); + } + } + } + if (p_name_combined.size() > kMaxPartyNameCombinedSize) { + p_name_combined.resize(kMaxPartyNameCombinedSize); + p_name_combined += "..."; + } + if (!p_name_combined.empty()) { + our_spec_string = + PlayerSpec::GetDummyPlayerSpec(p_name_combined).GetSpecString(); + } else { + our_spec_string = PlayerSpec::GetAccountPlayerSpec().GetSpecString(); + } + } + } + + // If we find a newline, only take the first line (prevent people from + // covering the screen with obnoxious chat messages). + std::string message2 = message; + size_t nlpos = message2.find('\n'); + if (nlpos != std::string::npos) { + message2 = message2.substr(0, nlpos); + } + + // If we're the host, run filters before we send the message out. + // If the filter kills the message, don't send. + bool allow_message = g_python->FilterChatMessage(&message2, -1); + if (!allow_message) { + return; + } + + // 1 byte type + 1 byte spec-string-length + message. + std::vector msg_out(1 + 1 + our_spec_string.size() + + message2.size()); + msg_out[0] = BA_MESSAGE_CHAT; + size_t spec_size = our_spec_string.size(); + assert(spec_size < 256); + msg_out[1] = static_cast(spec_size); + memcpy(&(msg_out[2]), our_spec_string.c_str(), spec_size); + memcpy(&(msg_out[2 + spec_size]), message2.c_str(), message2.size()); + + // If we're a client, send this to the host (it will make its way back to us + // when they send to clients). + if (ConnectionToHost* hc = connection_to_host()) { + hc->SendReliableMessage(msg_out); + } else { + // Ok we're the host. + + // Send to all (or at least some) connected clients. + for (auto&& i : connections_to_clients_) { + // Skip if its going to specific ones and this one doesn't match. + if (clients != nullptr) { + auto found = false; + for (auto&& c : *clients) { + if (c == i.second->id()) { + found = true; + } + } + if (!found) { + continue; + } + } + + if (i.second->can_communicate()) { + i.second->SendReliableMessage(msg_out); + } + } + + // And display locally if the message is addressed to all. + if (clients == nullptr) { + LocalDisplayChatMessage(msg_out); + } + } +} + +auto Game::GetGameRosterMessage() -> std::vector { + // This message is simply a flattened json string of our roster (including + // terminating char). + char* s = cJSON_PrintUnformatted(game_roster_); + // printf("ROSTER MESSAGE %s\n", s); + auto s_len = strlen(s); + std::vector msg(1 + s_len + 1); + msg[0] = BA_MESSAGE_PARTY_ROSTER; + memcpy(&(msg[1]), s, s_len + 1); + free(s); + + return msg; +} + +auto Game::IsPlayerBanned(const PlayerSpec& spec) -> bool { + millisecs_t current_time = GetRealTime(); + + // Now is a good time to prune no-longer-banned specs. + while (!banned_players_.empty() + && banned_players_.front().first < current_time) { + banned_players_.pop_front(); + } + for (auto&& test_spec : banned_players_) { + if (test_spec.second == spec) { + return true; + } + } + return false; +} + +void Game::StartKickVote(ConnectionToClient* starter, + ConnectionToClient* target) { + // Restrict votes per client. + millisecs_t current_time = GetRealTime(); + + if (starter == target) { + // Don't let anyone kick themselves. + starter->SendScreenMessage(R"({"r":"kickVoteCantKickSelfText",)" + R"("f":"kickVoteFailedText"})", + 1, 0, 0); + } else if (target->IsAdmin()) { + // Admins are immune to kicking + starter->SendScreenMessage(R"({"r":"kickVoteCantKickAdminText",)" + R"("f":"kickVoteFailedText"})", + 1, 0, 0); + } else if (starter->IsAdmin()) { + // Admin doing the kicking succeeds instantly. + SendScreenMessageToClients( + R"({"r":"kickOccurredText","s":[["${NAME}",)" + + Utils::GetJSONString( + target->GetCombinedSpec().GetDisplayString().c_str()) + + "]]}", + 1, 1, 0); + DisconnectClient(target->id(), kKickBanSeconds); + starter->SendScreenMessage(R"({"r":"kickVoteCantKickAdminText",)" + R"("f":"kickVoteFailedText"})", + 1, 0, 0); + } else if (!kick_voting_enabled_) { + // No kicking otherwise if its disabled. + starter->SendScreenMessage(R"({"r":"kickVotingDisabledText",)" + R"("f":"kickVoteFailedText"})", + 1, 0, 0); + } else if (kick_vote_in_progress_) { + // Vote in progress error. + starter->SendScreenMessage(R"({"r":"voteInProgressText"})", 1, 0, 0); + } else if (GetConnectedClientCount() < kKickVoteMinimumClients) { + // There's too few clients to effectively vote. + starter->SendScreenMessage(R"({"r":"kickVoteFailedNotEnoughVotersText",)" + R"("f":"kickVoteFailedText"})", + 1, 0, 0); + } else if (current_time < starter->next_kick_vote_allow_time_) { + // Not yet allowed error. + starter->SendScreenMessage( + R"({"r":"voteDelayText","s":[["${NUMBER}",")" + + std::to_string(std::max( + millisecs_t{1}, + (starter->next_kick_vote_allow_time_ - current_time) / 1000)) + + "\"]]}", + 1, 0, 0); + } else { + std::vector connected_clients = + GetConnectionsToClients(); + + // Ok, kick off a vote.. (send the question and instructions to everyone + // except the starter and the target). + for (auto&& client : connected_clients) { + if (client != starter && client != target) { + client->SendScreenMessage( + R"({"r":"kickQuestionText","s":[["${NAME}",)" + + Utils::GetJSONString( + target->GetCombinedSpec().GetDisplayString().c_str()) + + "]]}", + 1, 1, 0); + client->SendScreenMessage(R"({"r":"kickWithChatText","s":)" + R"([["${YES}","'1'"],["${NO}","'0'"]]})", + 1, 1, 0); + } else { + // For the kicker/kickee, simply print that a kick vote has been + // started. + client->SendScreenMessage( + R"({"r":"kickVoteStartedText","s":[["${NAME}",)" + + Utils::GetJSONString( + target->GetCombinedSpec().GetDisplayString().c_str()) + + "]]}", + 1, 1, 0); + } + } + kick_vote_end_time_ = current_time + kKickVoteDuration; + kick_vote_in_progress_ = true; + last_kick_votes_needed_ = -1; // make sure we print starting num + + // Keep track of who started the vote. + kick_vote_starter_ = starter; + kick_vote_target_ = target; + + // Reset votes for all connected clients. + for (ConnectionToClient* client : GetConnectionsToClients()) { + if (client == starter) { + client->kick_voted_ = true; + client->kick_vote_choice_ = true; + } else { + client->kick_voted_ = false; + } + } + } +} + +void Game::BanPlayer(const PlayerSpec& spec, millisecs_t duration) { + banned_players_.emplace_back(GetRealTime() + duration, spec); +} + +void Game::UpdateGameRoster() { + assert(InGameThread()); + + assert(game_roster_ != nullptr); + if (game_roster_ != nullptr) { + cJSON_Delete(game_roster_); + } + + // Our party-roster is just a json array of dicts containing player-specs. + game_roster_ = cJSON_CreateArray(); + + int total_party_size = 1; // include ourself here.. + + // Add ourself first (that's currently how they know we're the party leader) + // ..but only if we have a connected client (otherwise our party is + // considered 'empty'). + + // UPDATE: starting with our big ui revision we'll always include ourself + // here + bool include_self = (GetConnectedClientCount() > 0); +#if BA_TOOLBAR_TEST + include_self = true; +#endif // BA_TOOLBAR_TEST + + if (auto* hs = dynamic_cast(GetForegroundSession())) { + // Add our host-y self. + if (include_self) { + cJSON* client_dict = cJSON_CreateObject(); + cJSON_AddItemToObject( + client_dict, "spec", + cJSON_CreateString( + PlayerSpec::GetAccountPlayerSpec().GetSpecString().c_str())); + + // Add our list of local players. + cJSON* player_array = cJSON_CreateArray(); + for (auto&& p : hs->players()) { + InputDevice* input_device = p->GetInputDevice(); + + // Add some basic info for each local player (only ones with real + // names though; don't wanna send , etc). + if (p->accepted() && p->name_is_real() && input_device != nullptr + && !input_device->IsRemoteClient()) { + cJSON* player_dict = cJSON_CreateObject(); + cJSON_AddItemToObject(player_dict, "n", + cJSON_CreateString(p->GetName().c_str())); + cJSON_AddItemToObject(player_dict, "nf", + cJSON_CreateString(p->GetName(true).c_str())); + cJSON_AddItemToObject(player_dict, "i", cJSON_CreateNumber(p->id())); + cJSON_AddItemToArray(player_array, player_dict); + } + } + cJSON_AddItemToObject(client_dict, "p", player_array); + cJSON_AddItemToObject( + client_dict, "i", + cJSON_CreateNumber(-1)); // -1 client_id means we're the host. + cJSON_AddItemToArray(game_roster_, client_dict); + } + + // Add all connected clients. + for (auto&& i : connections_to_clients_) { + if (i.second->can_communicate()) { + cJSON* client_dict = cJSON_CreateObject(); + cJSON_AddItemToObject( + client_dict, "spec", + cJSON_CreateString(i.second->peer_spec().GetSpecString().c_str())); + + // Add their public account id (or None if we don't have it) + // cJSON* player_accountid{}; + // if (i.second->peer_public_account_id() == "") { + // player_accountid = cJSON_CreateNull(); + // } else { + // player_accountid = + // cJSON_CreateString(i.second->peer_public_account_id().c_str()); + // } + // cJSON_AddItemToObject(client_dict, "a", player_accountid); + + // Also add their list of players. + cJSON* player_array = cJSON_CreateArray(); + + // Include all players that are remote and coming from this same + // client connection. + for (auto&& p : hs->players()) { + InputDevice* input_device = p->GetInputDevice(); + if (p->accepted() && p->name_is_real() && input_device != nullptr + && input_device->IsRemoteClient()) { + auto* cid = static_cast(input_device); + ConnectionToClient* ctc = cid->connection_to_client(); + + // Add some basic info for each remote player. + if (ctc != nullptr && ctc == i.second.get()) { + cJSON* player_dict = cJSON_CreateObject(); + cJSON_AddItemToObject(player_dict, "n", + cJSON_CreateString(p->GetName().c_str())); + cJSON_AddItemToObject( + player_dict, "nf", + cJSON_CreateString(p->GetName(true).c_str())); + cJSON_AddItemToObject(player_dict, "i", + cJSON_CreateNumber(p->id())); + cJSON_AddItemToArray(player_array, player_dict); + } + } + } + cJSON_AddItemToObject(client_dict, "p", player_array); + cJSON_AddItemToObject(client_dict, "i", + cJSON_CreateNumber(i.second->id())); + cJSON_AddItemToArray(game_roster_, client_dict); + total_party_size += 1; + } + } + } + + // Keep the python layer informed on our number of connections; it may want + // to pass the info along to the master server if we're hosting a public + // party. + SetPublicPartySize(total_party_size); + + // Mark the roster as dirty so we know we need to send it to everyone soon. + game_roster_dirty_ = true; +} + +void Game::SetAdCompletionCall(PyObject* obj, bool pass_actually_showed) { + if (obj == Py_None) { + ad_completion_callback_.Clear(); + } else { + ad_completion_callback_ = Object::New(obj); + } + ad_completion_callback_pass_actually_showed_ = pass_actually_showed; + last_ad_start_time_ = g_platform->GetTicks(); +} + +void Game::CallAdCompletionCall(bool actually_showed) { + if (ad_completion_callback_.exists()) { + if (ad_completion_callback_pass_actually_showed_) { + PythonRef args(Py_BuildValue("(O)", actually_showed ? Py_True : Py_False), + PythonRef::kSteal); + ad_completion_callback_->Run(args); + } else { + ad_completion_callback_->Run(); + } + ad_completion_callback_.Clear(); // These are single-fire callbacks. + } +} + +void Game::SetPublicPartyEnabled(bool val) { + assert(InGameThread()); + if (val == public_party_enabled_) { + return; + } + public_party_enabled_ = val; + PushPublicPartyState(); +} + +void Game::SetPublicPartySize(int count) { + assert(InGameThread()); + if (count == public_party_size_) { + return; + } + public_party_size_ = count; + + // Push our new state to the server *ONLY* if public-party is turned on + // (wasteful otherwise). + if (public_party_enabled_) { + PushPublicPartyState(); + } +} + +void Game::SetPublicPartyMaxSize(int count) { + assert(InGameThread()); + if (count == public_party_max_size_) { + return; + } + public_party_max_size_ = count; + + // Push our new state to the server *ONLY* if public-party is turned on + // (wasteful otherwise). + if (public_party_enabled_) { + PushPublicPartyState(); + } +} + +void Game::SetPublicPartyName(const std::string& name) { + assert(InGameThread()); + if (name == public_party_name_) { + return; + } + public_party_name_ = name; + + // Push our new state to the server *ONLY* if public-party is turned on + // (wasteful otherwise). + if (public_party_enabled_) { + PushPublicPartyState(); + } +} + +void Game::SetPublicPartyStatsURL(const std::string& url) { + assert(InGameThread()); + if (url == public_party_stats_url_) { + return; + } + public_party_stats_url_ = url; + + // Push our new state to the server *ONLY* if public-party is turned on + // (wasteful otherwise). + if (public_party_enabled_) { + PushPublicPartyState(); + } +} + +void Game::SetPublicPartyPlayerCount(int count) { + assert(InGameThread()); + if (count == public_party_player_count_) { + return; + } + public_party_player_count_ = count; + + // Push our new state to the server *ONLY* if public-party is turned on + // (wasteful otherwise). + if (public_party_enabled_) { + PushPublicPartyState(); + } +} + +void Game::PushPublicPartyState() { + assert(InGameThread()); + PythonRef call = g_python->obj(Python::ObjID::kAccountClient) + .GetAttr("set_public_party_state"); + if (call.exists()) { + PythonRef args( + Py_BuildValue( + "(iiiiisss)", static_cast(public_party_enabled_), + public_party_size_, public_party_max_size_, + public_party_player_count_, public_party_max_player_count_, + public_party_name_.c_str(), public_party_min_league_.c_str(), + public_party_stats_url_.c_str()), + PythonRef::kSteal); + call.Call(args); + } else { + Log("Error on pushPublicPartyState call"); + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/game.h b/src/ballistica/game/game.h new file mode 100644 index 00000000..c913b37b --- /dev/null +++ b/src/ballistica/game/game.h @@ -0,0 +1,464 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_GAME_H_ +#define BALLISTICA_GAME_GAME_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ballistica/core/module.h" + +namespace ballistica { + +const int kMaxPartyNameCombinedSize = 25; + +/// The Game Module generally runs on a dedicated thread; it manages +/// all game logic, builds frame_defs to send to the graphics-server for +/// rendering, etc. +class Game : public Module { + public: + explicit Game(Thread* thread); + ~Game() override; + auto LaunchHostSession(PyObject* session_type_obj, + BenchmarkType benchmark_type = BenchmarkType::kNone) + -> void; + auto LaunchClientSession() -> void; + auto LaunchReplaySession(const std::string& file_name) -> void; + + auto PushSetAccountCall(AccountType account_type, AccountState account_state, + const std::string& account_name, + const std::string& account_id) -> void; + auto PushSetAccountTokenCall(const std::string& account_id, + const std::string& token) -> void; + auto PushAdViewCompleteCall(const std::string& purpose, bool actually_showed) + -> void; + auto PushAnalyticsCall(const std::string& type, int increment) -> void; + auto PushAwardAdTicketsCall() -> void; + auto PushAwardAdTournamentEntryCall() -> void; + auto PushPurchaseTransactionCall(const std::string& item, + const std::string& receipt, + const std::string& signature, + const std::string& order_id, + bool user_initiated) -> void; + auto PushUDPConnectionPacketCall(const std::vector& data, + const SockAddr& addr) -> void; + auto PushPartyInviteCall(const std::string& name, + const std::string& invite_id) -> void; + auto PushPartyInviteRevokeCall(const std::string& invite_id) -> void; + auto PushInitialScreenCreatedCall() -> void; + auto PushApplyConfigCall() -> void; + auto PushRemoveGraphicsServerRenderHoldCall() -> void; + auto PushInterruptSignalCall() -> void; + + /// Push a generic 'menu press' event, optionally associated with an + /// input device (nullptr to specify none). Note: caller must ensure + /// a RemoveInputDevice() call does not arrive at the game thread + /// before this one. + auto PushMainMenuPressCall(InputDevice* device) -> void; + + /// Notify the game of a screen-size change (used by the graphics server). + auto PushScreenResizeCall(float virtual_width, float virtual_height, + float physical_width, float physical_height) + -> void; + + auto PushGameServiceAchievementListCall( + const std::set& achievements) -> void; + auto PushScoresToBeatResponseCall(bool success, + const std::list& scores, + void* py_callback) -> void; + auto PushToggleCollisionGeometryDisplayCall() -> void; + auto PushToggleDebugInfoDisplayCall() -> void; + auto PushToggleManualCameraCall() -> void; + auto PushHavePendingLoadsDoneCall() -> void; + auto PushFreeMediaComponentRefsCall( + const std::vector*>& components) -> void; + auto PushSetFriendListCall(const std::vector& friends) -> void; + auto PushHavePendingLoadsCall() -> void; + auto PushShutdownCall(bool soft) -> void; + + auto PushInGameConsoleScriptCommand(const std::string& command) -> void; + auto ToggleConsole() -> void; + auto PushConsolePrintCall(const std::string& msg) -> void; + auto PushStdinScriptCommand(const std::string& command) -> void; + auto PushMediaPruneCall(int level) -> void; + auto PushAskUserForTelnetAccessCall() -> void; + + // Push Python call and keep it alive; must be called from game thread. + auto PushPythonCall(const Object::Ref& call) -> void; + auto PushPythonCallArgs(const Object::Ref& call, + const PythonRef& args) -> void; + + // Push Python call without keeping it alive; must be called from game thread. + auto PushPythonWeakCall(const Object::WeakRef& call) + -> void; + auto PushPythonWeakCallArgs(const Object::WeakRef& call, + const PythonRef& args) -> void; + + // Push a raw Python call, decrements its refcount after running. + // Can be pushed from any thread. + auto PushPythonRawCallable(PyObject* callable) -> void; + auto PushScreenMessage(const std::string& message, const Vector3f& color) + -> void; + auto RemovePlayer(Player* player) -> void; + auto PushPlaySoundCall(SystemSoundID sound) -> void; + auto PushConfirmQuitCall() -> void; + auto PushStringEditSetCall(const std::string& value) -> void; + auto PushStringEditCancelCall() -> void; + auto PushFriendScoreSetCall(const FriendScoreSet& score_set) -> void; + auto PushShowURLCall(const std::string& url) -> void; + auto PushBackButtonCall(InputDevice* input_device) -> void; + auto PushOnAppResumeCall() -> void; + auto PushFrameDefRequest() -> void; + auto PushDisconnectFromHostCall() -> void; + auto PushClientDisconnectedCall(int id) -> void; + auto PushHostConnectedUDPCall(const SockAddr& addr, + bool print_connect_progress) -> void; + auto PushDisconnectedFromHostCall() -> void; + auto ChangeGameSpeed(int offs) -> void; + auto ResetInput() -> void; + auto RunMainMenu() -> void; + auto HandleThreadPause() -> void override; + +#if BA_GOOGLE_BUILD + auto PushClientDisconnectedGooglePlayCall(int id) -> void; + int GetGooglePlayClientCount() const; + auto PushHostConnectedGooglePlayCall() -> void; + auto PushClientConnectedGooglePlayCall(int id) -> void; + auto PushCompressedGamePacketFromHostGooglePlayCall( + const std::vector& data) -> void; + auto PushCompressedGamePacketFromClientGooglePlayCall( + int google_client_id, const std::vector& data) -> void; +#endif + +#if BA_VR_BUILD + auto PushVRHandsState(const VRHandsState& state) -> void; + const VRHandsState& vr_hands_state() const { return vr_hands_state_; } +#endif + + // Resets tracking used to detect cheating and tampering in local tournaments. + auto ResetActivityTracking() -> void; + + // Return whichever context is front and center. + auto GetForegroundContext() -> Context; + + // Return whichever session is front and center. + auto GetForegroundSession() const -> Session* { + return foreground_session_.get(); + } + + auto NewRealTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> int; + auto DeleteRealTimer(int timer_id) -> void; + auto SetRealTimerLength(int timer_id, millisecs_t length) -> void; + auto SetLanguageKeys(const std::map& language) + -> void; + auto GetResourceString(const std::string& key) -> std::string; + auto CharStr(SpecialChar id) -> std::string; + auto CompileResourceString(const std::string& s, const std::string& loc, + bool* valid = nullptr) -> std::string; + auto kick_idle_players() const -> bool { return kick_idle_players_; } + auto IsInUIContext() const -> bool; + + // Return the actual UI context (hmm couldn't we just use g_ui?). + auto GetUIContextTarget() const -> UI* { + assert(g_ui); + return g_ui; + } + + // Simply return a context-state pointing to the ui-context (so you don't have + // to include the ui header). + auto GetUIContext() const -> Context; + + // Returns the base time used to drive local sims/etc. This generally tries + // to match real-time but has a bit of leeway to sync up with frame drawing or + // slow down if things are behind (it tries to progress by exactly 1000/60 ms + // each frame, provided we're rendering 60hz). + auto master_time() const -> millisecs_t { return master_time_; } + + auto debug_speed_mult() const -> float { return debug_speed_mult_; } + auto SetDebugSpeedExponent(int val) -> void; + + auto SetReplaySpeedExponent(int val) -> void; + auto replay_speed_exponent() const -> int { return replay_speed_exponent_; } + auto replay_speed_mult() const -> float { return replay_speed_mult_; } + + // Returns our host-connection or nullptr if there is none. + auto connection_to_host() -> ConnectionToHost* { + return connection_to_host_.get(); + } + auto GetConnectionToHostUDP() -> ConnectionToHostUDP*; + + // Send a screen message to all connected clients AND print it on the host. + auto SendScreenMessageToAll(const std::string& s, float r, float g, float b) + -> void; + + // send a screen message to all connected clients + auto SendScreenMessageToClients(const std::string& s, float r, float g, + float b) -> void; + + // Send a screen message to specific connected clients (those matching the IDs + // specified) the id -1 can be used to specify the host. + auto SendScreenMessageToSpecificClients(const std::string& s, float r, + float g, float b, + const std::vector& clients) + -> void; + + // Return our client connections (if any). + // FIXME: this prunes invalid connections, but it is necessary? + // Can we just use connections_to_clients() for direct access? + auto GetConnectionsToClients() -> std::vector; + + // Return the number of connections-to-client with "connected" status true. + auto GetConnectedClientCount() const -> int; + + auto GetPartySize() const -> int; + auto last_connection_to_client_join_time() const -> millisecs_t { + return last_connection_to_client_join_time_; + } + auto set_last_connection_to_client_join_time(millisecs_t val) -> void { + last_connection_to_client_join_time_ = val; + } + + // Simple thread safe query. + auto has_connection_to_host() const -> bool { + return has_connection_to_host_; + } + + auto game_roster() const -> cJSON* { return game_roster_; } + + auto SendChatMessage(const std::string& message, + const std::vector* clients = nullptr, + const std::string* sender_override = nullptr) -> void; + + // Quick test as to whether there are clients. Does not check if they are + // fully connected. + auto has_connection_to_clients() const -> bool { + assert(InGameThread()); + return (!connections_to_clients_.empty()); + } + + auto chat_messages() const -> const std::list& { + return chat_messages_; + } + + // Whoever wants to wrangle current client connections should call this + // to register itself. Note that it must explicitly call unregister when + // unregistering itself. + auto RegisterClientController(ClientControllerInterface* c) -> void; + auto UnregisterClientController(ClientControllerInterface* c) -> void; + + // Used to know which globals is in control currently/etc. + auto GetForegroundScene() const -> Scene* { + assert(InGameThread()); + return foreground_scene_.get(); + } + auto SetForegroundScene(Scene* sg) -> void; + + // Returns true if disconnect attempts are supported. + auto DisconnectClient(int client_id, int ban_seconds) -> bool; + auto UpdateGameRoster() -> void; + auto IsPlayerBanned(const PlayerSpec& spec) -> bool; + auto BanPlayer(const PlayerSpec& spec, millisecs_t duration) -> void; + + // For applying player-profiles data from the master-server. + auto SetClientInfoFromMasterServer(const std::string& client_token, + PyObject* info) -> void; + auto GetPrintUDPConnectProgress() const -> bool { + return print_udp_connect_progress_; + } + + // For cheat detection. Returns the largest amount of time that has passed + // between frames since our last reset (for detecting memory modification + // UIs/etc). + auto largest_draw_time_increment() const -> millisecs_t { + return largest_draw_time_increment_since_last_reset_; + } + + // Anti-hacker stuff. + auto GetTotalTimeSinceReset() const -> millisecs_t { + return last_draw_real_time_ - first_draw_real_time_; + } + auto SetForegroundSession(Session* s) -> void; + auto SetGameRoster(cJSON* r) -> void; + auto LocalDisplayChatMessage(const std::vector& buffer) -> void; + auto ShouldAnnouncePartyJoinsAndLeaves() -> bool; + + auto SetAdCompletionCall(PyObject* obj, bool pass_actually_showed) -> void; + auto CallAdCompletionCall(bool actually_showed) -> void; + auto RunGeneralAdComplete(bool actually_watched) -> void; + + auto StartKickVote(ConnectionToClient* starter, ConnectionToClient* target) + -> void; + auto require_client_authentication() const { + return require_client_authentication_; + } + auto set_require_client_authentication(bool enable) -> void { + require_client_authentication_ = enable; + } + auto set_kick_voting_enabled(bool enable) -> void { + kick_voting_enabled_ = enable; + } + auto set_admin_public_ids(const std::set& ids) -> void { + admin_public_ids_ = ids; + } + const std::set& admin_public_ids() const { + return admin_public_ids_; + } + + auto connections_to_clients() + -> const std::map >& { + return connections_to_clients_; + } + auto client_controller() -> ClientControllerInterface* { + return client_controller_; + } + auto kick_vote_in_progress() const -> bool { return kick_vote_in_progress_; } + +#if BA_GOOGLE_BUILD + auto ClientIDFromGooglePlayClientID(int google_id) -> int; + auto GooglePlayClientIDFromClientID(int client_id) -> int; +#endif + + auto SetPublicPartyEnabled(bool val) -> void; + auto public_party_enabled() const { return public_party_enabled_; } + auto public_party_size() const { return public_party_size_; } + auto SetPublicPartySize(int count) -> void; + auto public_party_max_size() const { return public_party_max_size_; } + auto SetPublicPartyMaxSize(int count) -> void; + auto SetPublicPartyName(const std::string& name) -> void; + auto SetPublicPartyStatsURL(const std::string& name) -> void; + auto public_party_name() const { return public_party_name_; } + auto public_party_player_count() const { return public_party_player_count_; } + auto SetPublicPartyPlayerCount(int count) -> void; + auto ran_app_launch_commands() const { return ran_app_launch_commands_; } + + private: + auto InitSpecialChars() -> void; + auto AdViewComplete(const std::string& purpose, bool actually_showed) -> void; + auto Analytics(const std::string& type, int increment) -> void; + auto AwardAdTickets() -> void; + auto AwardAdTournamentEntry() -> void; + auto Draw() -> void; + auto PurchaseTransaction(const std::string& item, const std::string& receipt, + const std::string& signature, + const std::string& order_id, bool user_initiated) + -> void; + auto UDPConnectionPacket(const std::vector& data, + const SockAddr& addr) -> void; + auto PartyInvite(const std::string& name, const std::string& invite_id) + -> void; + auto PartyInviteRevoke(const std::string& invite_id) -> void; + auto InitialScreenCreated() -> void; + auto MainMenuPress(InputDevice* device) -> void; + auto ScreenResize(float virtual_width, float virtual_height, + float pixel_width, float pixel_height) -> void; + auto GameServiceAchievementList(const std::set& achievements) + -> void; + auto ScoresToBeatResponse(bool success, const std::list& scores, + void* py_callback) -> void; + +#if BA_VR_BUILD + VRHandsState vr_hands_state_; +#endif +#if BA_RIFT_BUILD + int rift_step_index_{}; +#endif + + auto HandleClientDisconnected(int id) -> void; + auto ForceDisconnectClients() -> void; + auto Prune() -> void; // Periodic pruning of dead stuff. + auto Update() -> void; + auto Process() -> void; + auto UpdateKickVote() -> void; + auto RunAppLaunchCommands() -> void; + auto PruneSessions() -> void; + auto ApplyConfig() -> void; + auto UpdateProcessTimer() -> void; + auto Reset() -> void; + auto GetGameRosterMessage() -> std::vector; + auto CleanUpBeforeConnectingToHost() -> void; + auto Shutdown(bool soft) -> void; + auto PushPublicPartyState() -> void; + + std::map google_play_id_to_client_id_map_; + std::map client_id_to_google_play_id_map_; + bool print_udp_connect_progress_{true}; + std::list > banned_players_; + ClientControllerInterface* client_controller_{}; + std::list chat_messages_; + + // Simple flag for thread-safe access. + bool has_connection_to_host_{}; + + // Prevents us from printing multiple 'you got disconnected' messages. + bool printed_host_disconnect_{}; + bool chat_muted_{}; + bool first_update_{true}; + bool game_roster_dirty_{}; + millisecs_t last_connection_to_client_join_time_{}; + int debug_speed_exponent_{}; + float debug_speed_mult_{1.0f}; + int replay_speed_exponent_{}; + float replay_speed_mult_{1.0f}; + bool have_sent_initial_frame_def_{}; + millisecs_t master_time_{}; + millisecs_t master_time_offset_{}; + millisecs_t last_session_update_master_time_{}; + millisecs_t last_game_roster_send_time_{}; + millisecs_t largest_draw_time_increment_since_last_reset_{}; + millisecs_t last_draw_real_time_{}; + millisecs_t first_draw_real_time_{}; + + // *All* existing sessions (including old ones waiting to shut down). + std::vector > sessions_; + Object::WeakRef foreground_scene_; + Object::WeakRef foreground_session_; + std::mutex language_mutex_; + std::map language_; + std::mutex special_char_mutex_; + std::map special_char_strings_; + bool ran_app_launch_commands_{}; + bool kick_idle_players_{}; + std::unique_ptr realtimers_; + Timer* process_timer_{}; + Timer* headless_update_timer_{}; + Timer* media_prune_timer_{}; + Timer* debug_timer_{}; + bool have_pending_loads_{}; + bool in_update_{}; + bool require_client_authentication_{}; + bool kick_voting_enabled_{true}; + std::set admin_public_ids_; + + // Try to minimize the chance a garbage packet will have this id. + int next_connection_to_client_id_{113}; + std::map > connections_to_clients_; + Object::Ref connection_to_host_; + cJSON* game_roster_{}; + millisecs_t kick_vote_end_time_{}; + bool kick_vote_in_progress_{}; + int last_kick_votes_needed_{-1}; + Object::WeakRef kick_vote_starter_; + Object::WeakRef kick_vote_target_; + Object::Ref ad_completion_callback_; + millisecs_t last_ad_start_time_{}; + bool ad_completion_callback_pass_actually_showed_{}; + bool public_party_enabled_{false}; + int public_party_size_{1}; // Always count ourself (is that what we want?). + int public_party_max_size_{8}; + int public_party_player_count_{0}; + int public_party_max_player_count_{8}; + std::string public_party_name_; + std::string public_party_min_league_; + std::string public_party_stats_url_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_GAME_H_ diff --git a/src/ballistica/game/game_stream.cc b/src/ballistica/game/game_stream.cc new file mode 100644 index 00000000..8dd47091 --- /dev/null +++ b/src/ballistica/game/game_stream.cc @@ -0,0 +1,1242 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/game_stream.h" + +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/dynamics/material/material.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/dynamics/material/material_component.h" +#include "ballistica/dynamics/material/material_condition_node.h" +#include "ballistica/dynamics/part.h" +#include "ballistica/game/connection/connection_to_client.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/media/component/data.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/media/media_server.h" +#include "ballistica/networking/networking.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +GameStream::GameStream(HostSession* host_session, bool saveReplay) + : time_(0), + host_session_(host_session), + next_flush_time_(0), + last_physics_correction_time_(0), + last_send_time_(0), + writing_replay_(false) { + if (saveReplay) { + // Sanity check - we should only ever be writing one replay at once. + if (g_app_globals->replay_open) { + Log("ERROR: g_replay_open true at replay start; shouldn't happen."); + } + assert(g_media_server); + g_media_server->PushBeginWriteReplayCall(); + writing_replay_ = true; + g_app_globals->replay_open = true; + } + + // If we're the live output-stream from a host-session, + // take responsibility for feeding all clients to this device. + if (host_session_) { + g_game->RegisterClientController(this); + } +} + +GameStream::~GameStream() { + // Ship our last commands (if it matters..) + Flush(); + + if (writing_replay_) { + // Sanity check: We should only ever be writing one replay at once. + if (!g_app_globals->replay_open) { + Log("ERROR: g_replay_open false at replay close; shouldn't happen."); + } + g_app_globals->replay_open = false; + assert(g_media_server); + g_media_server->PushEndWriteReplayCall(); + writing_replay_ = false; + } + + // If we're wired to the host-session, go ahead and release clients. + if (host_session_) { + g_game->UnregisterClientController(this); + + // Also, in the host-session case, make sure everything cleaned itself up. +#if BA_DEBUG_BUILD + size_t count; + count = GetPointerCount(scenes_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " scene graphs in output stream at shutdown"); + } + count = GetPointerCount(nodes_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " nodes in output stream at shutdown"); + } + count = GetPointerCount(materials_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " materials in output stream at shutdown"); + } + count = GetPointerCount(textures_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " textures in output stream at shutdown"); + } + count = GetPointerCount(models_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " models in output stream at shutdown"); + } + count = GetPointerCount(sounds_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " sounds in output stream at shutdown"); + } + count = GetPointerCount(collide_models_); + if (count != 0) { + Log("ERROR: " + std::to_string(count) + + " collide_models in output stream at shutdown"); + } +#endif // BA_DEBUG_BUILD + } +} + +// Pull the current built-up message. +auto GameStream::GetOutMessage() const -> std::vector { + assert(!host_session_); // this should only be getting used for + // standalone temp ones.. + if (!out_command_.empty()) { + Log("Error: GameStream shutting down with non-empty outCommand"); + } + return out_message_; +} + +template +auto GameStream::GetPointerCount(const std::vector& vec) -> size_t { + size_t count = 0; + + auto size = vec.size(); + T* const* vals = vec.data(); + for (size_t i = 0; i < size; i++) { + if (vals[i] != nullptr) { + count++; + } + } + return count; +} + +// Given a vector of pointers, return an index to an available (nullptr) entry, +// expanding the vector if need be. +template +auto GameStream::GetFreeIndex(std::vector* vec, + std::vector* free_indices) -> size_t { + // If we have any free indices, use one of them. + if (!free_indices->empty()) { + size_t val = free_indices->back(); + free_indices->pop_back(); + return val; + } + + // No free indices; expand the vec and return the new index. + vec->push_back(nullptr); + return vec->size() - 1; +} + +// Add an entry. +template +void GameStream::Add(T* val, std::vector* vec, + std::vector* free_indices) { + // This should only get used when we're being driven by the host-session. + assert(host_session_); + assert(val); + assert(val->stream_id() == -1); + size_t index = GetFreeIndex(vec, free_indices); + (*vec)[index] = val; + val->set_stream_id(index); +} + +// Remove an entry. +template +void GameStream::Remove(T* val, std::vector* vec, + std::vector* free_indices) { + assert(val); + assert(val->stream_id() >= 0); + assert(static_cast(vec->size()) > val->stream_id()); + assert((*vec)[val->stream_id()] == val); + (*vec)[val->stream_id()] = nullptr; + + // Add this to our list of available slots to recycle. + free_indices->push_back(val->stream_id()); + val->clear_stream_id(); +} + +void GameStream::Fail() { + Log("Error writing replay file"); + if (writing_replay_) { + // Sanity check: We should only ever be writing one replay at once. + if (!g_app_globals->replay_open) { + Log("ERROR: g_replay_open false at replay close; shouldn't happen."); + } + assert(g_media_server); + g_media_server->PushEndWriteReplayCall(); + writing_replay_ = false; + g_app_globals->replay_open = false; + } +} + +void GameStream::Flush() { + if (!out_command_.empty()) + Log("Error: GameStream flushing down with non-empty outCommand"); + if (!out_message_.empty()) { + ShipSessionCommandsMessage(); + } +} + +// Writes just a command. +void GameStream::WriteCommand(SessionCommand cmd) { + assert(out_command_.empty()); + + // For now just use full size values. + size_t size = 0; + out_command_.resize(size + 1); + uint8_t* ptr = &out_command_[size]; + *ptr = static_cast(cmd); +} + +// Writes a command plus an int to the stream, using whatever size is optimal. +void GameStream::WriteCommandInt32(SessionCommand cmd, int32_t value) { + assert(out_command_.empty()); + + // For now just use full size values. + size_t size = 0; + out_command_.resize(size + 5); + uint8_t* ptr = &out_command_[size]; + *(ptr++) = static_cast(cmd); + int32_t vals[] = {value}; + memcpy(ptr, vals, 4); +} + +void GameStream::WriteCommandInt32_2(SessionCommand cmd, int32_t value1, + int32_t value2) { + assert(out_command_.empty()); + + // For now just use full size vals. + size_t size = 0; + out_command_.resize(size + 9); + uint8_t* ptr = &out_command_[size]; + *(ptr++) = static_cast(cmd); + int32_t vals[] = {value1, value2}; + memcpy(ptr, vals, 8); +} + +void GameStream::WriteCommandInt32_3(SessionCommand cmd, int32_t value1, + int32_t value2, int32_t value3) { + assert(out_command_.empty()); + + // For now just use full size vals. + size_t size = 0; + out_command_.resize(size + 13); + uint8_t* ptr = &out_command_[size]; + *(ptr++) = static_cast(cmd); + int32_t vals[] = {value1, value2, value3}; + memcpy(ptr, vals, 12); +} + +void GameStream::WriteCommandInt32_4(SessionCommand cmd, int32_t value1, + int32_t value2, int32_t value3, + int32_t value4) { + assert(out_command_.empty()); + + // For now just use full size vals. + size_t size = 0; + out_command_.resize(size + 17); + uint8_t* ptr = &out_command_[size]; + *(ptr++) = static_cast(cmd); + int32_t vals[] = {value1, value2, value3, value4}; + memcpy(ptr, vals, 16); +} + +// FIXME: We don't actually support sending out 64 bit values yet, but +// adding these placeholders for if/when we do. +// They will also catch values greater than 32 bits in debug mode. +// We'll need a protocol update to add support for 64 bit over the wire. +void GameStream::WriteCommandInt64(SessionCommand cmd, int64_t value) { + WriteCommandInt32(cmd, static_cast_check_fit(value)); +} + +void GameStream::WriteCommandInt64_2(SessionCommand cmd, int64_t value1, + int64_t value2) { + WriteCommandInt32_2(cmd, static_cast_check_fit(value1), + static_cast_check_fit(value2)); +} + +void GameStream::WriteCommandInt64_3(SessionCommand cmd, int64_t value1, + int64_t value2, int64_t value3) { + WriteCommandInt32_3(cmd, static_cast_check_fit(value1), + static_cast_check_fit(value2), + static_cast_check_fit(value3)); +} + +void GameStream::WriteCommandInt64_4(SessionCommand cmd, int64_t value1, + int64_t value2, int64_t value3, + int64_t value4) { + WriteCommandInt32_4(cmd, static_cast_check_fit(value1), + static_cast_check_fit(value2), + static_cast_check_fit(value3), + static_cast_check_fit(value4)); +} + +void GameStream::WriteString(const std::string& s) { + // Write length int. + auto string_size = s.size(); + auto size = out_command_.size(); + out_command_.resize(size + 4 + s.size()); + memcpy(&out_command_[size], &string_size, 4); + if (string_size > 0) { + memcpy(&out_command_[size + 4], s.c_str(), string_size); + } +} + +void GameStream::WriteFloat(float val) { + auto size = static_cast(out_command_.size()); + out_command_.resize(size + sizeof(val)); + memcpy(&out_command_[size], &val, 4); +} + +void GameStream::WriteFloats(size_t count, const float* vals) { + assert(count > 0); + auto size = out_command_.size(); + size_t vals_size = sizeof(float) * count; + out_command_.resize(size + vals_size); + memcpy(&(out_command_[size]), vals, vals_size); +} + +void GameStream::WriteInts32(size_t count, const int32_t* vals) { + assert(count > 0); + auto size = out_command_.size(); + size_t vals_size = sizeof(int32_t) * count; + out_command_.resize(size + vals_size); + memcpy(&(out_command_[size]), vals, vals_size); +} + +void GameStream::WriteInts64(size_t count, const int64_t* vals) { + // FIXME: we don't actually support writing 64 bit values to the wire + // at the moment; will need a protocol update for that. + // This is just implemented as a placeholder. + std::vector vals32(count); + for (size_t i = 0; i < count; i++) { + vals32[i] = static_cast_check_fit(vals[i]); + } + WriteInts32(count, vals32.data()); +} + +void GameStream::WriteChars(size_t count, const char* vals) { + assert(count > 0); + auto size = out_command_.size(); + auto vals_size = static_cast(count); + out_command_.resize(size + vals_size); + memcpy(&(out_command_[size]), vals, vals_size); +} + +void GameStream::ShipSessionCommandsMessage() { + BA_PRECONDITION(!out_message_.empty()); + + // Send this message to all client-connections we're attached to. + for (auto& connection : connections_to_clients_) { + (*connection).SendReliableMessage(out_message_); + } + if (writing_replay_) { + AddMessageToReplay(out_message_); + } + out_message_.clear(); + last_send_time_ = GetRealTime(); +} + +void GameStream::AddMessageToReplay(const std::vector& message) { + assert(writing_replay_); + assert(g_media_server); + + assert(!message.empty()); +#if BA_DEBUG_BUILD + switch (message[0]) { + case BA_MESSAGE_SESSION_RESET: + case BA_MESSAGE_SESSION_COMMANDS: + case BA_MESSAGE_SESSION_DYNAMICS_CORRECTION: + break; + default: + throw Exception("unexpected message going to replay: " + + std::to_string(static_cast(message[0]))); + } +#endif // BA_DEBUG_BUILD + g_media_server->PushAddMessageToReplayCall(message); +} + +void GameStream::SendPhysicsCorrection(bool blend) { + assert(host_session_); + + std::vector > messages; + host_session_->GetCorrectionMessages(blend, &messages); + + // FIXME - have to send reliably at the moment since these will most likely be + // bigger than our unreliable packet limit. :-( + for (auto& message : messages) { + for (auto& connections_to_client : connections_to_clients_) { + (*connections_to_client).SendReliableMessage(message); + } + if (writing_replay_) { + AddMessageToReplay(message); + } + } +} + +void GameStream::EndCommand(bool is_time_set) { + assert(!out_command_.empty()); + + int out_message_size; + if (out_message_.empty()) { + // Init the message if we're the first command on it. + out_message_.resize(1); + out_message_[0] = BA_MESSAGE_SESSION_COMMANDS; + out_message_size = 1; + } else { + out_message_size = static_cast(out_message_.size()); + } + + out_message_.resize(out_message_size + 2 + + out_command_.size()); // command length plus data + + auto val = static_cast(out_command_.size()); + memcpy(&(out_message_[out_message_size]), &val, 2); + memcpy(&(out_message_[out_message_size + 2]), &(out_command_[0]), + out_command_.size()); + + // When attached to a host-session, send this message to clients if it's been + // long enough. + + // Also send off occasional correction packets. + if (host_session_) { + // Now if its been long enough and this is a time-step command, send. + millisecs_t real_time = GetRealTime(); + millisecs_t diff = real_time - last_send_time_; + if (is_time_set && diff > g_app_globals->buffer_time) { + ShipSessionCommandsMessage(); + + // Also, as long as we're here, fire off a physics-correction packet every + // now and then. + + // IMPORTANT: We only do this right after shipping off our pending session + // commands; otherwise the client will get the correction that accounts + // for commands that they haven't been sent yet. + diff = real_time - last_physics_correction_time_; + if (diff > g_app_globals->dynamics_sync_time) { + last_physics_correction_time_ = real_time; + SendPhysicsCorrection(true); + } + } + } + out_command_.clear(); +} + +auto GameStream::IsValidScene(Scene* s) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (s != nullptr && s->stream_id() >= 0 + && s->stream_id() < static_cast(scenes_.size()) + && scenes_[s->stream_id()] == s); +} + +auto GameStream::IsValidNode(Node* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(nodes_.size()) + && nodes_[n->stream_id()] == n); +} + +auto GameStream::IsValidTexture(Texture* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(textures_.size()) + && textures_[n->stream_id()] == n); +} + +auto GameStream::IsValidModel(Model* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(models_.size()) + && models_[n->stream_id()] == n); +} + +auto GameStream::IsValidSound(Sound* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(sounds_.size()) + && sounds_[n->stream_id()] == n); +} + +auto GameStream::IsValidData(Data* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(datas_.size()) + && datas_[n->stream_id()] == n); +} + +auto GameStream::IsValidCollideModel(CollideModel* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(collide_models_.size()) + && collide_models_[n->stream_id()] == n); +} + +auto GameStream::IsValidMaterial(Material* n) -> bool { + if (!host_session_) { + return true; // We don't build lists in this mode so can't verify this. + } + return (n != nullptr && n->stream_id() >= 0 + && n->stream_id() < static_cast(materials_.size()) + && materials_[n->stream_id()] == n); +} + +void GameStream::SetTime(millisecs_t t) { + if (time_ == t) { + return; // Ignore redundants. + } + millisecs_t diff = t - time_; + if (diff > 255) { + Log("Error: GameStream got time diff > 255; not expected."); + diff = 255; + } + WriteCommandInt64(SessionCommand::kBaseTimeStep, diff); + time_ = t; + EndCommand(true); +} + +void GameStream::AddScene(Scene* s) { + // Host mode. + if (host_session_) { + Add(s, &scenes_, &free_indices_scene_graphs_); + s->SetOutputStream(this); + } else { + // Dump mode. + assert(s->stream_id() != -1); + } + WriteCommandInt64_2(SessionCommand::kAddSceneGraph, s->stream_id(), + s->time()); + EndCommand(); +} + +void GameStream::RemoveScene(Scene* s) { + WriteCommandInt64(SessionCommand::kRemoveSceneGraph, s->stream_id()); + Remove(s, &scenes_, &free_indices_scene_graphs_); + EndCommand(); +} + +void GameStream::StepScene(Scene* s) { + assert(IsValidScene(s)); + WriteCommandInt64(SessionCommand::kStepSceneGraph, s->stream_id()); + EndCommand(); +} + +void GameStream::AddNode(Node* n) { + assert(n); + if (host_session_) { + Add(n, &nodes_, &free_indices_nodes_); + } else { + assert(n && n->stream_id() != -1); + } + + Scene* sg = n->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_3(SessionCommand::kAddNode, sg->stream_id(), + n->type()->id(), n->stream_id()); + EndCommand(); +} + +void GameStream::NodeOnCreate(Node* n) { + assert(IsValidNode(n)); + WriteCommandInt64(SessionCommand::kNodeOnCreate, n->stream_id()); + EndCommand(); +} + +void GameStream::SetForegroundScene(Scene* sg) { + assert(IsValidScene(sg)); + WriteCommandInt64(SessionCommand::kSetForegroundSceneGraph, sg->stream_id()); + EndCommand(); +} + +void GameStream::RemoveNode(Node* n) { + assert(IsValidNode(n)); + WriteCommandInt64(SessionCommand::kRemoveNode, n->stream_id()); + Remove(n, &nodes_, &free_indices_nodes_); + EndCommand(); +} + +void GameStream::AddTexture(Texture* t) { + // Register an ID in host mode. + if (host_session_) { + Add(t, &textures_, &free_indices_textures_); + } else { + assert(t && t->stream_id() != -1); + } + Scene* sg = t->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_2(SessionCommand::kAddTexture, sg->stream_id(), + t->stream_id()); + WriteString(t->name()); + EndCommand(); +} + +void GameStream::RemoveTexture(Texture* t) { + assert(IsValidTexture(t)); + WriteCommandInt64(SessionCommand::kRemoveTexture, t->stream_id()); + Remove(t, &textures_, &free_indices_textures_); + EndCommand(); +} + +void GameStream::AddModel(Model* t) { + // Register an ID in host mode. + if (host_session_) { + Add(t, &models_, &free_indices_models_); + } else { + assert(t && t->stream_id() != -1); + } + Scene* sg = t->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_2(SessionCommand::kAddModel, sg->stream_id(), + t->stream_id()); + WriteString(t->name()); + EndCommand(); +} + +void GameStream::RemoveModel(Model* t) { + assert(IsValidModel(t)); + WriteCommandInt64(SessionCommand::kRemoveModel, t->stream_id()); + Remove(t, &models_, &free_indices_models_); + EndCommand(); +} + +void GameStream::AddSound(Sound* t) { + // Register an ID in host mode. + if (host_session_) { + Add(t, &sounds_, &free_indices_sounds_); + } else { + assert(t && t->stream_id() != -1); + } + Scene* sg = t->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_2(SessionCommand::kAddSound, sg->stream_id(), + t->stream_id()); + WriteString(t->name()); + EndCommand(); +} + +void GameStream::RemoveSound(Sound* t) { + assert(IsValidSound(t)); + WriteCommandInt64(SessionCommand::kRemoveSound, t->stream_id()); + Remove(t, &sounds_, &free_indices_sounds_); + EndCommand(); +} + +void GameStream::AddData(Data* t) { + // Register an ID in host mode. + if (host_session_) { + Add(t, &datas_, &free_indices_datas_); + } else { + assert(t && t->stream_id() != -1); + } + Scene* sg = t->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_2(SessionCommand::kAddData, sg->stream_id(), + t->stream_id()); + WriteString(t->name()); + EndCommand(); +} + +void GameStream::RemoveData(Data* t) { + assert(IsValidData(t)); + WriteCommandInt64(SessionCommand::kRemoveData, t->stream_id()); + Remove(t, &datas_, &free_indices_datas_); + EndCommand(); +} + +void GameStream::AddCollideModel(CollideModel* t) { + if (host_session_) { + Add(t, &collide_models_, &free_indices_collide_models_); + } else { + assert(t && t->stream_id() != -1); + } + Scene* sg = t->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_2(SessionCommand::kAddCollideModel, sg->stream_id(), + t->stream_id()); + WriteString(t->name()); + EndCommand(); +} + +void GameStream::RemoveCollideModel(CollideModel* t) { + assert(IsValidCollideModel(t)); + WriteCommandInt64(SessionCommand::kRemoveCollideModel, t->stream_id()); + Remove(t, &collide_models_, &free_indices_collide_models_); + EndCommand(); +} + +void GameStream::AddMaterial(Material* m) { + if (host_session_) { + Add(m, &materials_, &free_indices_materials_); + } else { + assert(m && m->stream_id() != -1); + } + Scene* sg = m->scene(); + assert(IsValidScene(sg)); + WriteCommandInt64_2(SessionCommand::kAddMaterial, sg->stream_id(), + m->stream_id()); + EndCommand(); +} + +void GameStream::RemoveMaterial(Material* m) { + assert(IsValidMaterial(m)); + WriteCommandInt64(SessionCommand::kRemoveMaterial, m->stream_id()); + Remove(m, &materials_, &free_indices_materials_); + EndCommand(); +} + +void GameStream::AddMaterialComponent(Material* m, MaterialComponent* c) { + assert(IsValidMaterial(m)); + auto flattened_size = c->GetFlattenedSize(); + assert(flattened_size > 0 && flattened_size < 10000); + WriteCommandInt64_2(SessionCommand::kAddMaterialComponent, m->stream_id(), + static_cast_check_fit(flattened_size)); + size_t size = out_command_.size(); + out_command_.resize(size + flattened_size); + char* ptr = reinterpret_cast(&out_command_[size]); + char* ptr2 = ptr; + c->Flatten(&ptr2, this); + size_t actual_size = ptr2 - ptr; + if (actual_size != flattened_size) { + throw Exception("Expected flattened_size " + std::to_string(flattened_size) + + " got " + std::to_string(actual_size)); + } + EndCommand(); +} + +void GameStream::ConnectNodeAttribute(Node* src_node, + NodeAttributeUnbound* src_attr, + Node* dst_node, + NodeAttributeUnbound* dst_attr) { + assert(IsValidNode(src_node)); + assert(IsValidNode(dst_node)); + assert(src_attr->node_type() == src_node->type()); + assert(dst_attr->node_type() == dst_node->type()); + if (src_node->scene() != dst_node->scene()) { + throw Exception("Nodes are from different scenes"); + } + assert(src_node->scene() == dst_node->scene()); + WriteCommandInt64_4(SessionCommand::kConnectNodeAttribute, + src_node->stream_id(), src_attr->index(), + dst_node->stream_id(), dst_attr->index()); + EndCommand(); +} + +void GameStream::NodeMessage(Node* node, const char* buffer, size_t size) { + assert(IsValidNode(node)); + BA_PRECONDITION(size > 0 && size < 10000); + WriteCommandInt64_2(SessionCommand::kNodeMessage, node->stream_id(), + static_cast_check_fit(size)); + WriteChars(size, buffer); + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, float val) { + assert(IsValidNode(attr.node)); + WriteCommandInt64_2(SessionCommand::kSetNodeAttrFloat, attr.node->stream_id(), + attr.index()); + WriteFloat(val); + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, int64_t val) { + assert(IsValidNode(attr.node)); + WriteCommandInt64_3(SessionCommand::kSetNodeAttrInt32, attr.node->stream_id(), + attr.index(), val); + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, bool val) { + assert(IsValidNode(attr.node)); + WriteCommandInt64_3(SessionCommand::kSetNodeAttrBool, attr.node->stream_id(), + attr.index(), val); + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + size_t count{vals.size()}; + WriteCommandInt64_3(SessionCommand::kSetNodeAttrFloats, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteFloats(count, vals.data()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + size_t count{vals.size()}; + WriteCommandInt64_3(SessionCommand::kSetNodeAttrInt32s, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteInts64(count, vals.data()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::string& val) { + assert(IsValidNode(attr.node)); + WriteCommandInt64_2(SessionCommand::kSetNodeAttrString, + attr.node->stream_id(), attr.index()); + WriteString(val); + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, Node* val) { + assert(IsValidNode(attr.node)); + if (val) { + assert(IsValidNode(val)); + if (attr.node->scene() != val->scene()) { + throw Exception("nodes are from different scenes"); + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrNode, + attr.node->stream_id(), attr.index(), val->stream_id()); + } else { + WriteCommandInt64_2(SessionCommand::kSetNodeAttrNodeNull, + attr.node->stream_id(), attr.index()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); +#if BA_DEBUG_BUILD + for (auto val : vals) { + assert(IsValidNode(val)); + } +#endif + size_t count{vals.size()}; + std::vector vals_out; + if (count > 0) { + vals_out.resize(count); + Scene* scene = attr.node->scene(); + for (size_t i = 0; i < count; i++) { + if (vals[i]->scene() != scene) { + throw Exception("nodes are from different scenes"); + } + vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); + } + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrNodes, attr.node->stream_id(), + attr.index(), static_cast_check_fit(count)); + if (count > 0) { + WriteInts32(count, vals_out.data()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, Player* val) { + // cout << "SET PLAYER ATTR " << attr.getIndex() << endl; +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + + if (g_buildconfig.debug_build()) { + for (auto val : vals) { + assert(IsValidMaterial(val)); + } + } + + size_t count = vals.size(); + std::vector vals_out; + if (count > 0) { + vals_out.resize(count); + Scene* scene = attr.node->scene(); + for (size_t i = 0; i < count; i++) { + if (vals[i]->scene() != scene) { + throw Exception("material/node are from different scenes"); + } + vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); + } + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrMaterials, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteInts32(count, &(vals_out[0])); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, Texture* val) { + if (val) { + assert(IsValidNode(attr.node)); + assert(IsValidTexture(val)); + if (attr.node->scene() != val->scene()) { + throw Exception("texture/node are from different scenes"); + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrTexture, + attr.node->stream_id(), attr.index(), val->stream_id()); + } else { + WriteCommandInt64_2(SessionCommand::kSetNodeAttrTextureNull, + attr.node->stream_id(), attr.index()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + if (g_buildconfig.debug_build()) { + for (auto val : vals) { + assert(IsValidTexture(val)); + } + } + size_t count{vals.size()}; + std::vector vals_out; + if (count > 0) { + vals_out.resize(count); + Scene* scene{attr.node->scene()}; + for (size_t i = 0; i < count; i++) { + if (vals[i]->scene() != scene) { + throw Exception("texture/node are from different scenes"); + } + vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); + } + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrTextures, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteInts32(count, vals_out.data()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, Sound* val) { + if (val) { + assert(IsValidNode(attr.node)); + assert(IsValidSound(val)); + if (attr.node->scene() != val->scene()) { + throw Exception("sound/node are from different scenes"); + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrSound, + attr.node->stream_id(), attr.index(), val->stream_id()); + } else { + WriteCommandInt64_2(SessionCommand::kSetNodeAttrSoundNull, + attr.node->stream_id(), attr.index()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + if (g_buildconfig.debug_build()) { + for (auto val : vals) { + assert(IsValidSound(val)); + } + } + size_t count{vals.size()}; + std::vector vals_out; + if (count > 0) { + vals_out.resize(count); + Scene* scene = attr.node->scene(); + for (size_t i = 0; i < count; i++) { + if (vals[i]->scene() != scene) { + throw Exception("sound/node are from different scenes"); + } + vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); + } + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrSounds, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteInts32(count, &(vals_out[0])); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, Model* val) { + if (val) { + assert(IsValidNode(attr.node)); + assert(IsValidModel(val)); + if (attr.node->scene() != val->scene()) { + throw Exception("model/node are from different scenes"); + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrModel, + attr.node->stream_id(), attr.index(), val->stream_id()); + } else { + WriteCommandInt64_2(SessionCommand::kSetNodeAttrModelNull, + attr.node->stream_id(), attr.index()); + } + EndCommand(); +} + +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + if (g_buildconfig.debug_build()) { + for (auto val : vals) { + assert(IsValidModel(val)); + } + } + size_t count = vals.size(); + std::vector vals_out; + if (count > 0) { + vals_out.resize(count); + Scene* scene = attr.node->scene(); + for (size_t i = 0; i < count; i++) { + if (vals[i]->scene() != scene) { + throw Exception("model/node are from different scenes"); + } + vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); + } + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrModels, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteInts32(count, &(vals_out[0])); + } + EndCommand(); +} +void GameStream::SetNodeAttr(const NodeAttribute& attr, CollideModel* val) { + if (val) { + assert(IsValidNode(attr.node)); + assert(IsValidCollideModel(val)); + if (attr.node->scene() != val->scene()) { + throw Exception("collide_model/node are from different scenes"); + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrCollideModel, + attr.node->stream_id(), attr.index(), val->stream_id()); + } else { + WriteCommandInt64_2(SessionCommand::kSetNodeAttrCollideModelNull, + attr.node->stream_id(), attr.index()); + } + EndCommand(); +} +void GameStream::SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals) { + assert(IsValidNode(attr.node)); + if (g_buildconfig.debug_build()) { + for (auto val : vals) { + assert(IsValidCollideModel(val)); + } + } + size_t count = vals.size(); + std::vector vals_out; + if (count > 0) { + vals_out.resize(count); + Scene* scene = attr.node->scene(); + for (size_t i = 0; i < count; i++) { + if (vals[i]->scene() != scene) { + throw Exception("collide_model/node are from different scenes"); + } + vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); + } + } + WriteCommandInt64_3(SessionCommand::kSetNodeAttrCollideModels, + attr.node->stream_id(), attr.index(), + static_cast_check_fit(count)); + if (count > 0) { + WriteInts32(count, &(vals_out[0])); + } + EndCommand(); +} + +void GameStream::PlaySoundAtPosition(Sound* sound, float volume, float x, + float y, float z) { + assert(IsValidSound(sound)); + assert(IsValidScene(sound->scene())); + + // FIXME: We shouldn't need to be passing all these as full floats. :-( + WriteCommandInt64(SessionCommand::kPlaySoundAtPosition, sound->stream_id()); + WriteFloat(volume); + WriteFloat(x); + WriteFloat(y); + WriteFloat(z); + EndCommand(); +} + +void GameStream::EmitBGDynamics(const BGDynamicsEmission& e) { + WriteCommandInt64_4(SessionCommand::kEmitBGDynamics, + static_cast(e.emit_type), e.count, + static_cast(e.chunk_type), + static_cast(e.tendril_type)); + float fvals[8]; + fvals[0] = e.position.x; + fvals[1] = e.position.y; + fvals[2] = e.position.z; + fvals[3] = e.velocity.x; + fvals[4] = e.velocity.y; + fvals[5] = e.velocity.z; + fvals[6] = e.scale; + fvals[7] = e.spread; + WriteFloats(8, fvals); + EndCommand(); +} + +void GameStream::PlaySound(Sound* sound, float volume) { + assert(IsValidSound(sound)); + assert(IsValidScene(sound->scene())); + + // FIXME: We shouldn't need to be passing all these as full floats. :-( + WriteCommandInt64(SessionCommand::kPlaySound, sound->stream_id()); + WriteFloat(volume); + EndCommand(); +} + +void GameStream::ScreenMessageTop(const std::string& val, float r, float g, + float b, Texture* texture, + Texture* tint_texture, float tint_r, + float tint_g, float tint_b, float tint2_r, + float tint2_g, float tint2_b) { + assert(IsValidTexture(texture)); + assert(IsValidTexture(tint_texture)); + assert(IsValidScene(texture->scene())); + assert(IsValidScene(tint_texture->scene())); + WriteCommandInt64_2(SessionCommand::kScreenMessageTop, texture->stream_id(), + tint_texture->stream_id()); + WriteString(val); + float f[9]; + f[0] = r; + f[1] = g; + f[2] = b; + f[3] = tint_r; + f[4] = tint_g; + f[5] = tint_b; + f[6] = tint2_r; + f[7] = tint2_g; + f[8] = tint2_b; + WriteFloats(9, f); + EndCommand(); +} + +void GameStream::ScreenMessageBottom(const std::string& val, float r, float g, + float b) { + WriteCommand(SessionCommand::kScreenMessageBottom); + WriteString(val); + float color[3]; + color[0] = r; + color[1] = g; + color[2] = b; + WriteFloats(3, color); + EndCommand(); +} + +auto GameStream::GetSoundID(Sound* s) -> int64_t { + assert(IsValidSound(s)); + return s->stream_id(); +} + +auto GameStream::GetMaterialID(Material* m) -> int64_t { + assert(IsValidMaterial(m)); + return m->stream_id(); +} + +void GameStream::OnClientConnected(ConnectionToClient* c) { + // Sanity check - abort if its on either of our lists already. + for (auto& connections_to_client : connections_to_clients_) { + if (connections_to_client == c) { + Log("Error: GameStream::OnClientConnected() got duplicate connection."); + return; + } + } + for (auto& i : connections_to_clients_ignored_) { + if (i == c) { + Log("Error: GameStream::OnClientConnected() got duplicate connection."); + return; + } + } + + { + // First thing, we need to flush all pending session-commands to clients. + // The host-session's current state is the result of having already run + // these commands locally, so if we leave them on the list while 'restoring' + // the new client to our state they'll get essentially double-applied, which + // is bad. (ie: a delete-node command will get called but the node will + // already be gone) + Flush(); + + connections_to_clients_.push_back(c); + + // We create a temporary output stream just for the purpose of building + // a giant session-commands message to reconstruct everything in our + // host-session in its current form. + GameStream out(nullptr, false); + + // Ask the host-session that we came from to dump it's complete state. + host_session_->DumpFullState(&out); + + // Grab the message that's been built up. + // If its not empty, send it to the client. + std::vector out_message = out.GetOutMessage(); + if (!out_message.empty()) { + c->SendReliableMessage(out_message); + } + + // Also send a correction packet to sync up all our dynamics. + // (technically could do this *just* for the new client) + SendPhysicsCorrection(false); + } +} + +void GameStream::OnClientDisconnected(ConnectionToClient* c) { + // Search for it on either our ignored or regular lists. + for (auto i = connections_to_clients_.begin(); + i != connections_to_clients_.end(); i++) { + if (*i == c) { + connections_to_clients_.erase(i); + return; + } + } + for (auto i = connections_to_clients_ignored_.begin(); + i != connections_to_clients_ignored_.end(); i++) { + if (*i == c) { + connections_to_clients_ignored_.erase(i); + return; + } + } + Log("Error: GameStream::OnClientDisconnected() called for connection not on " + "lists"); +} + +} // namespace ballistica diff --git a/src/ballistica/game/game_stream.h b/src/ballistica/game/game_stream.h new file mode 100644 index 00000000..794e522e --- /dev/null +++ b/src/ballistica/game/game_stream.h @@ -0,0 +1,159 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_GAME_STREAM_H_ +#define BALLISTICA_GAME_GAME_STREAM_H_ + +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/game/client_controller_interface.h" + +namespace ballistica { + +// A mechanism for dumping a live session or session-creation-commands to a +// stream of messages that can be saved to file or sent over the network. +class GameStream : public Object, public ClientControllerInterface { + public: + GameStream(HostSession* host_session, bool saveReplay); + ~GameStream() override; + void SetTime(millisecs_t t); + void AddScene(Scene* s); + void RemoveScene(Scene* s); + void StepScene(Scene* s); + void AddNode(Node* n); + void NodeOnCreate(Node* n); + void RemoveNode(Node* n); + void SetForegroundScene(Scene* sg); + void AddMaterial(Material* m); + void RemoveMaterial(Material* m); + void AddMaterialComponent(Material* m, MaterialComponent* c); + void AddTexture(Texture* t); + void RemoveTexture(Texture* t); + void AddModel(Model* t); + void RemoveModel(Model* t); + void AddSound(Sound* t); + void RemoveSound(Sound* t); + void AddData(Data* d); + void RemoveData(Data* d); + void AddCollideModel(CollideModel* t); + void RemoveCollideModel(CollideModel* t); + void ConnectNodeAttribute(Node* src_node, NodeAttributeUnbound* src_attr, + Node* dst_node, NodeAttributeUnbound* dst_attr); + void NodeMessage(Node* node, const char* buffer, size_t size); + void SetNodeAttr(const NodeAttribute& attr, float val); + void SetNodeAttr(const NodeAttribute& attr, int64_t val); + void SetNodeAttr(const NodeAttribute& attr, bool val); + void SetNodeAttr(const NodeAttribute& attr, const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, const std::string& val); + void SetNodeAttr(const NodeAttribute& attr, Node* n); + void SetNodeAttr(const NodeAttribute& attr, const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, Player* n); + void SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, Texture* n); + void SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, Sound* n); + void SetNodeAttr(const NodeAttribute& attr, const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, Model* n); + void SetNodeAttr(const NodeAttribute& attr, const std::vector& vals); + void SetNodeAttr(const NodeAttribute& attr, CollideModel* n); + void SetNodeAttr(const NodeAttribute& attr, + const std::vector& vals); + void PlaySoundAtPosition(Sound* sound, float volume, float x, float y, + float z); + void PlaySound(Sound* sound, float volume); + void EmitBGDynamics(const BGDynamicsEmission& e); + auto GetSoundID(Sound* s) -> int64_t; + auto GetMaterialID(Material* m) -> int64_t; + void ScreenMessageBottom(const std::string& val, float r, float g, float b); + void ScreenMessageTop(const std::string& val, float r, float g, float b, + Texture* texture, Texture* tint_texture, float tint_r, + float tint_g, float tint_b, float tint2_r, + float tint2_g, float tint2_b); + void OnClientConnected(ConnectionToClient* c) override; + void OnClientDisconnected(ConnectionToClient* c) override; + auto GetOutMessage() const -> std::vector; + + private: + HostSession* host_session_; + + // Make sure the scene is in our stream. + auto IsValidScene(Scene* val) -> bool; + auto IsValidNode(Node* val) -> bool; + auto IsValidTexture(Texture* val) -> bool; + auto IsValidModel(Model* val) -> bool; + auto IsValidSound(Sound* val) -> bool; + auto IsValidData(Data* val) -> bool; + auto IsValidCollideModel(CollideModel* val) -> bool; + auto IsValidMaterial(Material* val) -> bool; + millisecs_t next_flush_time_; + void Flush(); + void AddMessageToReplay(const std::vector& message); + + // Individual command going into the commands-messages. + std::vector out_command_; + + // The complete message full of commands. + std::vector out_message_; + std::vector connections_to_clients_; + std::vector connections_to_clients_ignored_; + bool writing_replay_; + void Fail(); + millisecs_t last_physics_correction_time_; + millisecs_t last_send_time_; + void ShipSessionCommandsMessage(); + void SendPhysicsCorrection(bool blend); + void EndCommand(bool is_time_set = false); + void WriteString(const std::string& s); + void WriteFloat(float val); + void WriteFloats(size_t count, const float* vals); + void WriteInts32(size_t count, const int32_t* vals); + void WriteInts64(size_t count, const int64_t* vals); + void WriteChars(size_t count, const char* vals); + void WriteCommand(SessionCommand cmd); + void WriteCommandInt32(SessionCommand cmd, int32_t value); + void WriteCommandInt64(SessionCommand cmd, int64_t value); + void WriteCommandInt32_2(SessionCommand cmd, int32_t value1, int32_t value2); + void WriteCommandInt64_2(SessionCommand cmd, int64_t value1, int64_t value2); + void WriteCommandInt32_3(SessionCommand cmd, int32_t value1, int32_t value2, + int32_t value3); + void WriteCommandInt64_3(SessionCommand cmd, int64_t value1, int64_t value2, + int64_t value3); + void WriteCommandInt32_4(SessionCommand cmd, int32_t value1, int32_t value2, + int32_t value3, int32_t value4); + void WriteCommandInt64_4(SessionCommand cmd, int64_t value1, int64_t value2, + int64_t value3, int64_t value4); + template + auto GetPointerCount(const std::vector& vec) -> size_t; + template + auto GetFreeIndex(std::vector* vec, std::vector* free_indices) + -> size_t; + template + void Add(T* val, std::vector* vec, std::vector* free_indices); + template + void Remove(T* val, std::vector* vec, std::vector* free_indices); + millisecs_t time_; + std::vector scenes_; + std::vector free_indices_scene_graphs_; + std::vector nodes_; + std::vector free_indices_nodes_; + std::vector materials_; + std::vector free_indices_materials_; + std::vector textures_; + std::vector free_indices_textures_; + std::vector models_; + std::vector free_indices_models_; + std::vector sounds_; + std::vector free_indices_sounds_; + std::vector datas_; + std::vector free_indices_datas_; + std::vector collide_models_; + std::vector free_indices_collide_models_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_GAME_STREAM_H_ diff --git a/src/ballistica/game/host_activity.cc b/src/ballistica/game/host_activity.cc new file mode 100644 index 00000000..ce4a1f58 --- /dev/null +++ b/src/ballistica/game/host_activity.cc @@ -0,0 +1,528 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/host_activity.h" + +#include + +#include "ballistica/dynamics/material/material.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/player.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/generic/lambda_runnable.h" +#include "ballistica/generic/timer.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/media/component/data.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/python/python_sys.h" +#include "ballistica/scene/node/globals_node.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +HostActivity::HostActivity(HostSession* host_session) { + // Store a link to the HostSession and add ourself to it. + host_session_ = host_session; + + // Create our game timer - gets called whenever game should step. + step_scene_timer_ = + base_timers_.NewTimer(base_time_, kGameStepMilliseconds, 0, -1, + NewLambdaRunnable([this] { StepScene(); })); + SetGameSpeed(1.0f); + { + ScopedSetContext cp(this); // So scene picks us up as context. + scene_ = Object::New(0); + + // If there's an output stream, add to it. + if (GameStream* out = host_session->GetGameStream()) { + out->AddScene(scene_.get()); + } + } +} + +HostActivity::~HostActivity() { + shutting_down_ = true; + + // Put the scene in shut-down mode before we start killing stuff. + // (this generates warnings, suppresses messages, etc) + scene_->set_shutting_down(true); + + // Clear out all python calls registered in our context. + // (should wipe out refs to our activity and prevent them from running without + // a valid activity context) + for (auto&& i : python_calls_) { + if (i.exists()) { + i->MarkDead(); + } + } + + // Mark all our media dead to clear it out of our output-stream cleanly + for (auto&& i : textures_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + for (auto&& i : models_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + for (auto&& i : sounds_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + for (auto&& i : collide_models_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + for (auto&& i : materials_) { + if (i.exists()) { + i->MarkDead(); + } + } + + // Clear our timers and scene; this should wipe out any remaining refs to our + // python activity, allowing it to die. + base_timers_.Clear(); + sim_timers_.Clear(); + scene_.Clear(); + + // Report outstanding calls. There shouldn't be any at this point. Actually it + // turns out there's generally 1; whichever call was responsible for killing + // this activity will still be in progress.. so let's report on 2 or more I + // guess. +#if BA_DEBUG_BUILD + PruneDeadRefs(&python_calls_); + if (python_calls_.size() > 1) { + std::string s = "WARNING: " + std::to_string(python_calls_.size()) + + " live PythonContextCalls at shutdown for " + + "HostActivity" + " (1 call is expected):"; + int count = 1; + for (auto& python_call : python_calls_) + s += "\n " + std::to_string(count++) + ": " + + (*python_call).GetObjectDescription(); + Log(s); + } +#endif // BA_DEBUG_BUILD +} + +auto HostActivity::GetGameStream() const -> GameStream* { + if (!host_session_.exists()) return nullptr; + return host_session_->GetGameStream(); +} + +void HostActivity::StepScene() { + int cycle_count = 1; + if (host_session_->benchmark_type() == BenchmarkType::kCPU) { + cycle_count = 100; + } + + for (int cycle = 0; cycle < cycle_count; ++cycle) { + assert(InGameThread()); + + // Clear our player-positions for this step. + // FIXME: Move this to scene and/or player node. + assert(host_session_.exists()); + for (auto&& player : host_session_->players()) { + assert(player.exists()); + player->set_have_position(false); + } + + // Run our sim-time timers. + sim_timers_.Run(scene()->time()); + + // Send die-messages/etc to out-of-bounds stuff. + HandleOutOfBoundsNodes(); + + scene()->Step(); + } +} + +void HostActivity::RegisterCall(PythonContextCall* call) { + assert(call); + python_calls_.emplace_back(call); + + // If we're shutting down, just kill the call immediately. + // (we turn all of our calls to no-ops as we shut down) + if (shutting_down_) { + Log("WARNING: adding call to expired activity; call will not function: " + + call->GetObjectDescription()); + call->MarkDead(); + } +} + +void HostActivity::start() { + if (_started) { + Log("Error: Start called twice for activity."); + } + _started = true; +} + +auto HostActivity::GetAsHostActivity() -> HostActivity* { return this; } + +auto HostActivity::NewMaterial(const std::string& name) + -> Object::Ref { + if (shutting_down_) { + throw Exception("can't create materials during activity shutdown"); + } + + auto m(Object::New(name, scene())); + materials_.emplace_back(m); + return m; +} + +auto HostActivity::GetTexture(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during activity shutdown"); + } + return Media::GetMedia(&textures_, name, scene()); +} + +auto HostActivity::GetSound(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during activity shutdown"); + } + return Media::GetMedia(&sounds_, name, scene()); +} + +auto HostActivity::GetData(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during activity shutdown"); + } + return Media::GetMedia(&datas_, name, scene()); +} + +auto HostActivity::GetModel(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during activity shutdown"); + } + return Media::GetMedia(&models_, name, scene()); +} + +auto HostActivity::GetCollideModel(const std::string& name) + -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during activity shutdown"); + } + return Media::GetMedia(&collide_models_, name, scene()); +} + +void HostActivity::SetPaused(bool val) { + if (paused_ == val) { + return; + } + paused_ = val; + UpdateStepTimerLength(); +} + +void HostActivity::SetGameSpeed(float speed) { + if (speed == game_speed_) { + return; + } + assert(speed >= 0.0f); + game_speed_ = speed; + UpdateStepTimerLength(); +} + +void HostActivity::UpdateStepTimerLength() { + if (game_speed_ == 0.0f || paused_) { + step_scene_timer_->SetLength(-1, true, base_time_); + } else { + step_scene_timer_->SetLength( + std::max(1, static_cast( + round(static_cast(kGameStepMilliseconds) + / (game_speed_ * g_game->debug_speed_mult())))), + true, base_time_); + } +} + +void HostActivity::HandleOutOfBoundsNodes() { + if (scene()->out_of_bounds_nodes().empty()) { + out_of_bounds_in_a_row_ = 0; + return; + } + + // Make sure someone's handling our out-of-bounds messages. + out_of_bounds_in_a_row_++; + if (out_of_bounds_in_a_row_ > 100) { + Log("Warning: 100 consecutive out-of-bounds messages sent." + " They are probably not being handled properly"); + int j = 0; + for (auto&& i : scene()->out_of_bounds_nodes()) { + j++; + Node* n = i.get(); + if (n) { + std::string dstr; + PyObject* delegate = n->GetDelegate(); + if (delegate) { + dstr = PythonRef(delegate, PythonRef::kAcquire).Str(); + } + Log(" node #" + std::to_string(j) + ": type='" + n->type()->name() + + "' addr=" + Utils::PtrToString(i.get()) + " name='" + n->label() + + "' delegate=" + dstr); + } + } + out_of_bounds_in_a_row_ = 0; + } + + // Send out-of-bounds messages to newly out-of-bounds nodes. + for (auto&& i : scene()->out_of_bounds_nodes()) { + Node* n = i.get(); + if (n) { + n->DispatchOutOfBoundsMessage(); + } + } +} + +void HostActivity::RegisterPyActivity(PyObject* pyActivityObj) { + assert(pyActivityObj && pyActivityObj != Py_None); + assert(!py_activity_weak_ref_.exists()); + + // Store a python weak-ref to this activity. + py_activity_weak_ref_.Steal(PyWeakref_NewRef(pyActivityObj, nullptr)); +} + +auto HostActivity::GetPyActivity() const -> PyObject* { + PyObject* obj = py_activity_weak_ref_.get(); + if (!obj) return Py_None; + return PyWeakref_GetObject(obj); +} + +auto HostActivity::GetHostSession() -> HostSession* { + return host_session_.get(); +} + +auto HostActivity::GetMutableScene() -> Scene* { + Scene* sg = scene_.get(); + assert(sg); + return sg; +} + +void HostActivity::SetIsForeground(bool val) { + // If we're foreground, set our scene as foreground. + Scene* sg = scene(); + if (val && sg) { + // Set it locally. + g_game->SetForegroundScene(sg); + + // Also push it to clients. + if (GameStream* out = GetGameStream()) { + out->SetForegroundScene(scene_.get()); + } + } +} + +auto HostActivity::globals_node() const -> GlobalsNode* { + return globals_node_.get(); +} + +auto HostActivity::NewSimTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> int { + if (shutting_down_) { + BA_LOG_PYTHON_TRACE_ONCE( + "WARNING: Creating game timer during host-activity shutdown"); + return 123; // Dummy. + } + if (length == 0 && repeat) { + throw Exception("Can't add game-timer with length 0 and repeat on"); + } + if (length < 0) { + throw Exception("Timer length cannot be < 0 (got " + std::to_string(length) + + ")"); + } + + int offset = 0; + Timer* t = sim_timers_.NewTimer(scene()->time(), length, offset, + repeat ? -1 : 0, runnable); + return t->id(); +} + +auto HostActivity::NewBaseTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> int { + if (shutting_down_) { + BA_LOG_PYTHON_TRACE_ONCE( + "WARNING: Creating session-time timer during host-activity shutdown"); + return 123; // dummy... + } + if (length == 0 && repeat) { + throw Exception("Can't add session-time timer with length 0 and repeat on"); + } + if (length < 0) { + throw Exception("Timer length cannot be < 0"); + } + + int offset = 0; + Timer* t = base_timers_.NewTimer(base_time_, length, offset, repeat ? -1 : 0, + runnable); + return t->id(); +} + +void HostActivity::DeleteSimTimer(int timer_id) { + assert(InGameThread()); + if (shutting_down_) return; + sim_timers_.DeleteTimer(timer_id); +} + +void HostActivity::DeleteBaseTimer(int timer_id) { + assert(InGameThread()); + if (shutting_down_) return; + base_timers_.DeleteTimer(timer_id); +} + +auto HostActivity::Update(millisecs_t time_advance) -> millisecs_t { + assert(InGameThread()); + + // We can be killed at any time, so let's keep an eye out for that. + WeakRef test_ref(this); + assert(test_ref.exists()); + + // If we haven't been told to start yet, don't do anything more. + if (!_started) { + return 1000; + } + + // Advance base time by the specified amount, stopping at all timers along the + // way. + millisecs_t target_base_time = base_time_ + time_advance; + while (!base_timers_.empty() + && (base_time_ + base_timers_.GetTimeToNextExpire(base_time_) + <= target_base_time)) { + base_time_ += base_timers_.GetTimeToNextExpire(base_time_); + base_timers_.Run(base_time_); + if (!test_ref.exists()) { + return 1000; // The last timer run might have killed us. + } + } + base_time_ = target_base_time; + + // Periodically prune various dead refs. + if (base_time_ > next_prune_time_) { + PruneDeadMapRefs(&textures_); + PruneDeadMapRefs(&sounds_); + PruneDeadMapRefs(&collide_models_); + PruneDeadMapRefs(&models_); + PruneDeadRefs(&materials_); + PruneDeadRefs(&python_calls_); + next_prune_time_ = base_time_ + 5000; + } + + // Return the time until the next timer goes off. + return base_timers_.empty() ? 1000 + : base_timers_.GetTimeToNextExpire(base_time_); +} + +void HostActivity::ScreenSizeChanged() { scene()->ScreenSizeChanged(); } +void HostActivity::LanguageChanged() { scene()->LanguageChanged(); } +void HostActivity::DebugSpeedMultChanged() { UpdateStepTimerLength(); } +void HostActivity::GraphicsQualityChanged(GraphicsQuality q) { + scene()->GraphicsQualityChanged(q); +} + +void HostActivity::Draw(FrameDef* frame_def) { + if (!_started) return; + scene()->Draw(frame_def); +} + +void HostActivity::DumpFullState(GameStream* out) { + // Add our scene. + if (scene_.exists()) { + scene_->Dump(out); + } + + // Before doing any nodes, we need to create all materials. + // (but *not* their components, which may reference the nodes that we haven't + // made yet) + for (auto&& i : materials_) { + if (Material* m = i.get()) { + out->AddMaterial(m); + } + } + + // Add our media. + for (auto&& i : textures_) { + if (Texture* t = i.second.get()) { + out->AddTexture(t); + } + } + for (auto&& i : sounds_) { + if (Sound* s = i.second.get()) { + out->AddSound(s); + } + } + for (auto&& i : models_) { + if (Model* s = i.second.get()) { + out->AddModel(s); + } + } + for (auto&& i : collide_models_) { + if (CollideModel* m = i.second.get()) { + out->AddCollideModel(m); + } + } + + // Add scene's nodes. + if (scene_.exists()) { + scene_->DumpNodes(out); + } + + // Ok, now we can fill out our materials since nodes/etc they reference + // exists. + for (auto&& i : materials_) { + if (Material* m = i.get()) { + m->DumpComponents(out); + } + } +} + +auto HostActivity::NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int { + // Make sure the runnable passed in is reference-managed already. + // (we may not add an initial reference ourself) + assert(runnable->is_valid_refcounted_object()); + + // We currently support game and base timers. + switch (timetype) { + case TimeType::kSim: + return NewSimTimer(length, repeat, runnable); + case TimeType::kBase: + return NewBaseTimer(length, repeat, runnable); + default: + // Fall back to default for descriptive error otherwise. + return ContextTarget::NewTimer(timetype, length, repeat, runnable); + } +} + +void HostActivity::DeleteTimer(TimeType timetype, int timer_id) { + switch (timetype) { + case TimeType::kSim: + DeleteSimTimer(timer_id); + break; + case TimeType::kBase: + DeleteBaseTimer(timer_id); + break; + default: + // Fall back to default for descriptive error otherwise. + ContextTarget::DeleteTimer(timetype, timer_id); + break; + } +} + +auto HostActivity::GetTime(TimeType timetype) -> millisecs_t { + switch (timetype) { + case TimeType::kSim: + return scene()->time(); + case TimeType::kBase: + return base_time(); + default: + // Fall back to default for descriptive error otherwise. + return ContextTarget::GetTime(timetype); + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/host_activity.h b/src/ballistica/game/host_activity.h new file mode 100644 index 00000000..c8c9f530 --- /dev/null +++ b/src/ballistica/game/host_activity.h @@ -0,0 +1,120 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_HOST_ACTIVITY_H_ +#define BALLISTICA_GAME_HOST_ACTIVITY_H_ + +#include +#include +#include + +#include "ballistica/core/context.h" +#include "ballistica/generic/timer_list.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +class HostActivity : public ContextTarget { + public: + explicit HostActivity(HostSession* host_session); + ~HostActivity() override; + auto GetHostSession() -> HostSession* override; + void SetGameSpeed(float speed); + auto game_speed() const -> float { return game_speed_; } + + // ContextTarget time/timer support. + auto NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int override; + void DeleteTimer(TimeType timetype, int timer_id) override; + auto GetTime(TimeType timetype) -> millisecs_t override; + + /// Return a borrowed ref to the python activity; Py_None if nonexistent. + auto GetPyActivity() const -> PyObject*; + + // All these commands are propagated into the output stream + // in addition to being applied locally. + auto NewMaterial(const std::string& name) -> Object::Ref; + auto GetTexture(const std::string& name) -> Object::Ref override; + auto GetSound(const std::string& name) -> Object::Ref override; + auto GetData(const std::string& name) -> Object::Ref override; + auto GetModel(const std::string& name) -> Object::Ref override; + auto GetCollideModel(const std::string& name) + -> Object::Ref override; + auto Update(millisecs_t time_advance) -> millisecs_t; + auto base_time() const -> millisecs_t { return base_time_; } + auto scene() -> Scene* { + assert(scene_.exists()); + return scene_.get(); + } + void start(); + + // A utility function; faster than dynamic_cast. + auto GetAsHostActivity() -> HostActivity* override; + auto GetMutableScene() -> Scene* override; + void Draw(FrameDef* frame_def); + void ScreenSizeChanged(); + void LanguageChanged(); + void DebugSpeedMultChanged(); + void GraphicsQualityChanged(GraphicsQuality q); + + // Used to register python calls created in this context so we can make sure + // they got properly cleaned up. + void RegisterCall(PythonContextCall* call); + auto shutting_down() const -> bool { return shutting_down_; } + auto globals_node() const -> GlobalsNode*; + void SetPaused(bool val); + auto paused() const -> bool { return paused_; } + void setAllowKickIdlePlayers(bool val) { allow_kick_idle_players_ = val; } + auto getAllowKickIdlePlayers() const -> bool { + return allow_kick_idle_players_; + } + auto GetGameStream() const -> GameStream*; + void DumpFullState(GameStream* out); + + private: + auto NewSimTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> int; + void DeleteSimTimer(int timer_id); + auto NewBaseTimer(millisecs_t length, bool repeat, + const Object::Ref& runnable) -> int; + void DeleteBaseTimer(int timer_id); + void UpdateStepTimerLength(); + Object::WeakRef globals_node_; + void SetIsForeground(bool val); + bool allow_kick_idle_players_ = false; + void StepScene(); + Timer* step_scene_timer_ = nullptr; + std::map > textures_; + std::map > sounds_; + std::map > datas_; + std::map > collide_models_; + std::map > models_; + std::list > materials_; + bool shutting_down_ = false; + + // Our list of python calls created in the context of this activity; + // we clear them as we are shutting down and ensure nothing runs after + // that point. + std::list > python_calls_; + millisecs_t next_prune_time_ = 0; + bool _started = false; + int out_of_bounds_in_a_row_ = 0; + void HandleOutOfBoundsNodes(); + bool paused_ = false; + float game_speed_ = 0.0f; + millisecs_t base_time_ = 0; + Object::Ref scene_; + Object::WeakRef host_session_; + PythonRef py_activity_weak_ref_; + void RegisterPyActivity(PyObject* pyActivity); + + // Want this at the bottom so it dies first since this may cause python stuff + // to access us. + TimerList sim_timers_; + TimerList base_timers_; + friend class HostSession; + friend class GlobalsNode; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_HOST_ACTIVITY_H_ diff --git a/src/ballistica/game/player.cc b/src/ballistica/game/player.cc new file mode 100644 index 00000000..2afdd229 --- /dev/null +++ b/src/ballistica/game/player.cc @@ -0,0 +1,418 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/player.h" + +#include + +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/generic/utils.h" +#include "ballistica/input/device/joystick.h" +#include "ballistica/python/class/python_class_session_player.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +Player::Player(int id_in, HostSession* host_session) + : id_(id_in), creation_time_(GetRealTime()), host_session_(host_session) { + assert(host_session); + assert(InGameThread()); +} + +Player::~Player() { + assert(InGameThread()); + + // If we have an input-device attached to us, detach it. + InputDevice* input_device = input_device_.get(); + if (input_device) { + input_device->DetachFromPlayer(); + } + + // Release our ref to ourself if we have one. + if (py_ref_) { + Py_DECREF(py_ref_); + } +} + +auto Player::GetName(bool full, bool icon) const -> std::string { + std::string n = full ? full_name_ : name_; + + // Quasi-hacky: if they ask for no icon, strip the first char off our string + // if its in the custom-use-range. + if (!icon) { + std::vector uni = Utils::UnicodeFromUTF8(n, "3f94f4f"); + if (!uni.empty() && uni[0] >= 0xE000 && uni[0] <= 0xF8FF) { + uni.erase(uni.begin()); + } + return Utils::UTF8FromUnicode(uni); + } else { + return n; + } +} + +auto Player::GetHostActivity() const -> HostActivity* { + return host_activity_.get(); +} + +void Player::SetHostActivity(HostActivity* a) { + assert(InGameThread()); + + // Make sure we get pulled out of one activity before being added to another. + if (a && in_activity_) { + std::string old_name = + host_activity_.exists() + ? PythonRef(host_activity_->GetPyActivity(), PythonRef::kAcquire) + .Str() + : ""; + std::string new_name = + PythonRef(a->GetPyActivity(), PythonRef::kAcquire).Str(); + BA_LOG_PYTHON_TRACE_ONCE( + "Player::SetHostActivity() called when already in an activity (old=" + + old_name + ", new=" + new_name + ")"); + } else if (!a && !in_activity_) { + BA_LOG_PYTHON_TRACE_ONCE( + "Player::SetHostActivity() called with nullptr when not in an " + "activity"); + } + host_activity_ = a; + in_activity_ = (a != nullptr); +} + +void Player::SetPosition(const Vector3f& position) { + position_ = position; + have_position_ = true; +} + +void Player::ResetInput() { + // Hold a ref to ourself while clearing this to make sure + // we don't die midway as a result of freeing something. + Object::Ref ref(this); + calls_.clear(); + left_held_ = right_held_ = up_held_ = down_held_ = have_position_ = false; +} + +void Player::SetPyTeam(PyObject* team) { + if (team != nullptr && team != Py_None) { + // We store a weak-ref to this. + py_team_weak_ref_.Steal(PyWeakref_NewRef(team, nullptr)); + } else { + py_team_weak_ref_.Release(); + } +} + +auto Player::GetPyTeam() -> PyObject* { + PyObject* obj = py_team_weak_ref_.get(); + if (!obj) { + return Py_None; + } + return PyWeakref_GetObject(obj); +} + +void Player::SetPyCharacter(PyObject* character) { + if (character != nullptr && character != Py_None) { + py_character_.Acquire(character); + } else { + py_character_.Release(); + } +} + +auto Player::GetPyCharacter() -> PyObject* { + return py_character_.exists() ? py_character_.get() : Py_None; +} + +void Player::SetPyColor(PyObject* c) { py_color_.Acquire(c); } +auto Player::GetPyColor() -> PyObject* { + return py_color_.exists() ? py_color_.get() : Py_None; +} + +void Player::SetPyHighlight(PyObject* c) { py_highlight_.Acquire(c); } +auto Player::GetPyHighlight() -> PyObject* { + return py_highlight_.exists() ? py_highlight_.get() : Py_None; +} + +void Player::SetPyActivityPlayer(PyObject* c) { py_activityplayer_.Acquire(c); } +auto Player::GetPyActivityPlayer() -> PyObject* { + return py_activityplayer_.exists() ? py_activityplayer_.get() : Py_None; +} + +auto Player::GetPyRef(bool new_ref) -> PyObject* { + assert(InGameThread()); + if (py_ref_ == nullptr) { + py_ref_ = PythonClassSessionPlayer::Create(this); + } + if (new_ref) { + Py_INCREF(py_ref_); + } + return py_ref_; +} + +void Player::AssignInputCall(InputType type, PyObject* call_obj) { + assert(InGameThread()); + assert(static_cast(type) >= 0 + && static_cast(type) < static_cast(InputType::kLast)); + + // Special case: if they're assigning hold-position-press or + // hold-position-release, or any direction events, we add in a hold-position + // press/release event before we deliver any other events.. that way newly + // created stuff is informed of the hold state and doesn't wrongly think they + // should start moving. + switch (type) { + case InputType::kHoldPositionPress: + case InputType::kHoldPositionRelease: + case InputType::kLeftPress: + case InputType::kLeftRelease: + case InputType::kRightPress: + case InputType::kUpPress: + case InputType::kUpRelease: + case InputType::kDownPress: + case InputType::kDownRelease: + case InputType::kUpDown: + case InputType::kLeftRight: { + send_hold_state_ = true; + break; + } + default: + break; + } + if (call_obj) { + calls_[static_cast(type)] = Object::New(call_obj); + } else { + calls_[static_cast(type)].Clear(); + } + + // If they assigned l/r, immediately send an update for its current value. + if (type == InputType::kLeftRight) { + RunInput(type, lr_state_); + } + + // Same for up/down. + if (type == InputType::kUpDown) { + RunInput(type, ud_state_); + } + + // Same for run. + if (type == InputType::kRun) { + RunInput(type, run_state_); + } + + // Same for fly. + if (type == InputType::kFlyPress && fly_held_) { + RunInput(type); + } +} + +void Player::RunInput(InputType type, float value) { + assert(InGameThread()); + + const float threshold = kJoystickDiscreteThresholdFloat; + + // Most input commands cause us to reset the player's time-out + // there are a few exceptions though - very small analog values + // get ignored since they can come through without user intervention. + bool reset_time_out = true; + if (type == InputType::kLeftRight || type == InputType::kUpDown) { + if (std::abs(value) < 0.3f) { + reset_time_out = false; + } + } + if (type == InputType::kRun) { + if (value < 0.3f) { + reset_time_out = false; + } + } + + // Also ignore hold-position stuff since it can come through without user + // interaction. + if ((type == InputType::kHoldPositionPress) + || (type == InputType::kHoldPositionRelease)) + reset_time_out = false; + + if (reset_time_out) { + time_out_ = BA_PLAYER_TIME_OUT; + } + + // Keep track of the hold-position state that comes through here. + // any-time hold position buttons are re-assigned, we subsequently + // re-send the current hold-state so whatever its driving starts out correctly + // held if need be. + if (type == InputType::kHoldPositionPress) { + hold_position_ = true; + } else if (type == InputType::kHoldPositionRelease) { + hold_position_ = false; + } else if (type == InputType::kFlyPress) { + fly_held_ = true; + } else if (type == InputType::kFlyRelease) { + fly_held_ = false; + } + + // If we were supposed to deliver hold-state, go ahead and do that first. + if (send_hold_state_) { + send_hold_state_ = false; + if (hold_position_) { + RunInput(InputType::kHoldPositionPress); + } else { + RunInput(InputType::kHoldPositionRelease); + } + } + + // Let's make our life simpler by converting held-position-joystick-events.. + { + // We need to store these since we might look at them during a hold-position + // event when we don't have their originating events available. + if (type == InputType::kLeftRight) { + lr_state_ = value; + } + if (type == InputType::kUpDown) { + ud_state_ = value; + } + if (type == InputType::kRun) { + run_state_ = value; + } + + // Special input commands - keep track of left/right and up/down positions + // so we can deliver simple "leftUp", "leftDown", etc type of events + // in addition to the standard absolute leftRight positions, etc. + if (type == InputType::kLeftRight || type == InputType::kHoldPositionPress + || type == InputType::kHoldPositionRelease) { + float arg = lr_state_; + if (hold_position_) { + arg = 0.0f; // Throttle is off. + } + if (left_held_) { + if (arg > -threshold) { + left_held_ = false; + RunInput(InputType::kLeftRelease); + } + } else if (right_held_) { + if (arg < threshold) { + right_held_ = false; + RunInput(InputType::kRightRelease); + } + } else { + if (arg >= threshold) { + if (!left_held_ && !up_held_ && !down_held_) { + right_held_ = true; + RunInput(InputType::kRightPress); + } + } else if (arg <= -threshold) { + if (!right_held_ && !up_held_ && !down_held_) { + left_held_ = true; + RunInput(InputType::kLeftPress); + } + } + } + } + if (type == InputType::kUpDown || type == InputType::kHoldPositionPress + || type == InputType::kHoldPositionRelease) { + float arg = ud_state_; + if (hold_position_) arg = 0.0f; // throttle is off; + if (up_held_) { + if (arg < threshold) { + up_held_ = false; + RunInput(InputType::kUpRelease); + } + } else if (down_held_) { + if (arg > -threshold) { + down_held_ = false; + RunInput(InputType::kDownRelease); + } + } else { + if (arg <= -threshold) { + if (!left_held_ && !right_held_ && !up_held_) { + down_held_ = true; + RunInput(InputType::kDownPress); + } + } else if (arg >= threshold) { + if (!left_held_ && !up_held_ && !right_held_) { + up_held_ = true; + RunInput(InputType::kUpPress); + } + } + } + } + } + + auto j = calls_.find(static_cast(type)); + if (j != calls_.end() && j->second.exists()) { + if (type == InputType::kRun) { + PythonRef args( + Py_BuildValue("(f)", std::min(1.0f, std::max(0.0f, value))), + PythonRef::kSteal); + j->second->Run(args.get()); + } else if (type == InputType::kLeftRight || type == InputType::kUpDown) { + PythonRef args( + Py_BuildValue("(f)", std::min(1.0f, std::max(-1.0f, value))), + PythonRef::kSteal); + j->second->Run(args.get()); + } else { + j->second->Run(); + } + } +} + +auto Player::GetHostSession() const -> HostSession* { + return host_session_.get(); +} + +void Player::SetName(const std::string& name, const std::string& full_name, + bool is_real) { + assert(InGameThread()); + HostSession* host_session = GetHostSession(); + BA_PRECONDITION(host_session); + name_is_real_ = is_real; + name_ = host_session->GetUnusedPlayerName(this, name); + full_name_ = full_name; + + // If we're already in the game and our name is changing, we need to update + // the roster. + if (accepted_) { + g_game->UpdateGameRoster(); + } +} + +void Player::InputCommand(InputType type, float value) { + assert(InGameThread()); + switch (type) { + case InputType::kUpDown: + case InputType::kLeftRight: + case InputType::kRun: + RunInput(type, value); + break; + // case InputType::kReset: + // Log("Error: FIXME: player-input-reset command unimplemented"); + // break; + default: + RunInput(type); + break; + } +} + +void Player::SetInputDevice(InputDevice* input_device) { + input_device_ = input_device; +} + +auto Player::GetPublicAccountID() const -> std::string { + assert(InGameThread()); + if (input_device_.exists()) { + return input_device_->GetPublicAccountID(); + } + return ""; +} + +void Player::SetIcon(const std::string& tex_name, + const std::string& tint_tex_name, + const std::vector& tint_color, + const std::vector& tint2_color) { + assert(tint_color.size() == 3); + assert(tint2_color.size() == 3); + icon_tex_name_ = tex_name; + icon_tint_tex_name_ = tint_tex_name; + icon_tint_color_ = tint_color; + icon_tint2_color_ = tint2_color; + icon_set_ = true; +} + +} // namespace ballistica diff --git a/src/ballistica/game/player.h b/src/ballistica/game/player.h new file mode 100644 index 00000000..00b33c4c --- /dev/null +++ b/src/ballistica/game/player.h @@ -0,0 +1,167 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_PLAYER_H_ +#define BALLISTICA_GAME_PLAYER_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/input/input.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/scene/scene.h" + +// How much time should pass before we kick idle players (in milliseconds). +#define BA_PLAYER_TIME_OUT 60000 +#define BA_PLAYER_TIME_OUT_WARN 10000 + +namespace ballistica { + +// A player (from the game's point of view). +class Player : public Object { + public: + Player(int id, HostSession* host_session); + ~Player() override; + + void SetInputDevice(InputDevice* input_device); + void AssignInputCall(InputType type, PyObject* call_obj); + void InputCommand(InputType type, float value = 0.0f); + + void SetName(const std::string& name, const std::string& full_name, + bool real); + auto GetName(bool full = false, bool icon = true) const -> std::string; + auto name_is_real() const -> bool { return name_is_real_; } + void ResetInput(); + auto GetHostSession() const -> HostSession*; + + auto id() const -> int { return id_; } + + auto NewPyRef() -> PyObject* { return GetPyRef(true); } + auto BorrowPyRef() -> PyObject* { return GetPyRef(false); } + + // Set the player node for the current activity. + void set_node(Node* node) { + assert(InGameThread()); + node_ = node; + } + auto node() const -> Node* { + assert(InGameThread()); + return node_.get(); + } + + void SetPyTeam(PyObject* team); + auto GetPyTeam() -> PyObject*; // Returns a borrowed ref. + + void SetPyCharacter(PyObject* team); + auto GetPyCharacter() -> PyObject*; // Returns a borrowed ref. + + void SetPyColor(PyObject* team); + auto GetPyColor() -> PyObject*; // Returns a borrowed ref. + + void SetPyHighlight(PyObject* team); + auto GetPyHighlight() -> PyObject*; // Returns a borrowed ref. + + void SetPyActivityPlayer(PyObject* team); + auto GetPyActivityPlayer() -> PyObject*; // Returns a borrowed ref. + + void set_has_py_data(bool has) { has_py_data_ = has; } + auto has_py_data() const -> bool { return has_py_data_; } + + auto GetInputDevice() const -> InputDevice* { return input_device_.get(); } + auto GetAge() const -> millisecs_t { return GetRealTime() - creation_time_; } + auto accepted() const -> bool { return accepted_; } + + void SetPosition(const Vector3f& position); + + // If an public account-id can be determined with relative + // certainty for this player, returns it. Otherwise returns + // an empty string. + auto GetPublicAccountID() const -> std::string; + + void SetHostActivity(HostActivity* host_activity); + auto GetHostActivity() const -> HostActivity*; + + auto has_py_ref() -> bool { return (py_ref_ != nullptr); } + + void SetIcon(const std::string& tex_name, const std::string& tint_tex_name, + const std::vector& tint_color, + const std::vector& tint2_color); + + auto icon_tex_name() const -> const std::string& { + BA_PRECONDITION(icon_set_); + return icon_tex_name_; + } + auto icon_tint_tex_name() const -> const std::string& { + BA_PRECONDITION(icon_set_); + return icon_tint_tex_name_; + } + auto icon_tint_color() const -> const std::vector& { + BA_PRECONDITION(icon_set_); + return icon_tint_color_; + } + auto icon_tint2_color() const -> const std::vector& { + BA_PRECONDITION(icon_set_); + return icon_tint2_color_; + } + void set_accepted(bool value) { accepted_ = value; } + auto time_out() const -> millisecs_t { return time_out_; } + void set_time_out(millisecs_t value) { time_out_ = value; } + void set_have_position(bool value) { have_position_ = value; } + + private: + auto GetPyRef(bool new_ref) -> PyObject*; + void RunInput(InputType type, float value = 0.0f); + bool icon_set_{}; + std::string icon_tex_name_; + std::string icon_tint_tex_name_; + std::vector icon_tint_color_; + std::vector icon_tint2_color_; + Object::WeakRef host_session_; + Object::WeakRef host_activity_; + Object::WeakRef node_; + bool in_activity_{}; + Object::WeakRef input_device_; + PyObject* py_ref_{}; + bool accepted_{}; + bool has_py_data_{}; + millisecs_t creation_time_{}; + int id_{}; + std::string name_; + std::string full_name_; + + // Is the current name real (as opposed to a standin + // title such as '') + bool name_is_real_{}; + bool left_held_{}; + bool right_held_{}; + bool up_held_{}; + bool down_held_{}; + bool hold_position_{}; + bool send_hold_state_{}; + bool fly_held_{}; + float lr_state_{}; + float ud_state_{}; + float run_state_{}; + millisecs_t time_out_{BA_PLAYER_TIME_OUT}; + + // Player's position for use by input devices and whatnot for guides. + // FIXME: This info should be acquired through the player node. + bool have_position_{false}; + Vector3f position_{0.0f, 0.0f, 0.0f}; + + // These should be destructed before the rest of our class goes down, + // so they should be here at the bottom.. + // (they might access our name string or other stuff declared above) + // PythonRef py_actor_; + PythonRef py_team_weak_ref_; + PythonRef py_character_; + PythonRef py_color_; + PythonRef py_highlight_; + PythonRef py_activityplayer_; + std::map > calls_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_PLAYER_H_ diff --git a/src/ballistica/game/player_spec.cc b/src/ballistica/game/player_spec.cc new file mode 100644 index 00000000..ecdb7462 --- /dev/null +++ b/src/ballistica/game/player_spec.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/player_spec.h" + +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/account.h" +#include "ballistica/generic/json.h" +#include "ballistica/generic/utils.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +PlayerSpec::PlayerSpec() : account_type_(AccountType::kInvalid) {} + +PlayerSpec::PlayerSpec(const std::string& s) { + cJSON* root_obj = cJSON_Parse(s.c_str()); + bool success = false; + if (root_obj) { + cJSON* name_obj = cJSON_GetObjectItem(root_obj, "n"); + cJSON* short_name_obj = cJSON_GetObjectItem(root_obj, "sn"); + cJSON* account_obj = cJSON_GetObjectItem(root_obj, "a"); + if (name_obj && short_name_obj && account_obj) { + name_ = Utils::GetValidUTF8(name_obj->valuestring, "psps"); + short_name_ = Utils::GetValidUTF8(short_name_obj->valuestring, "psps2"); + + // Account type may technically be something we don't recognize, + // but that's ok.. it'll just be 'invalid' to us in that case + account_type_ = Account::AccountTypeFromString(account_obj->valuestring); + success = true; + } + cJSON_Delete(root_obj); + } + if (!success) { + Log("Error creating PlayerSpec from string: '" + s + "'"); + name_ = ""; + short_name_ = ""; + account_type_ = AccountType::kInvalid; + } +} + +auto PlayerSpec::GetDisplayString() const -> std::string { + return Account::AccountTypeToIconString(account_type_) + name_; +} + +auto PlayerSpec::GetShortName() const -> std::string { + if (short_name_.empty()) { + return name_; + } + return short_name_; +} + +auto PlayerSpec::operator==(const PlayerSpec& spec) const -> bool { + // NOTE: need to add account ID in here once that's available + return (spec.name_ == name_ && spec.short_name_ == short_name_ + && spec.account_type_ == account_type_); +} + +auto PlayerSpec::GetSpecString() const -> std::string { + cJSON* root; + root = cJSON_CreateObject(); + cJSON_AddStringToObject(root, "n", name_.c_str()); + cJSON_AddStringToObject(root, "a", + Account::AccountTypeToString(account_type_).c_str()); + cJSON_AddStringToObject(root, "sn", short_name_.c_str()); + char* out = cJSON_PrintUnformatted(root); + std::string out_s = out; + free(out); + cJSON_Delete(root); + + // We should never allow ourself to have all this add up to more than 256. + assert(out_s.size() < 256); + + return out_s; +} + +auto PlayerSpec::GetAccountPlayerSpec() -> PlayerSpec { + PlayerSpec spec; + if (g_account->GetAccountState() == AccountState::kSignedIn) { + spec.account_type_ = g_app_globals->account_type; + spec.name_ = + Utils::GetValidUTF8(g_account->GetAccountName().c_str(), "bsgaps"); + } else { + spec.name_ = + Utils::GetValidUTF8(g_platform->GetDeviceName().c_str(), "bsgaps2"); + } + if (spec.name_.size() > 100) { + // FIXME should perhaps clamp this in unicode space + Log("account name size too long: '" + spec.name_ + "'"); + spec.name_.resize(100); + spec.name_ = Utils::GetValidUTF8(spec.name_.c_str(), "bsgaps3"); + } + return spec; +} + +auto PlayerSpec::GetDummyPlayerSpec(const std::string& name) -> PlayerSpec { + PlayerSpec spec; + spec.name_ = Utils::GetValidUTF8(name.c_str(), "bsgdps1"); + if (spec.name_.size() > 100) { + // FIXME should perhaps clamp this in unicode space + Log("dummy player spec name too long: '" + spec.name_ + "'"); + spec.name_.resize(100); + spec.name_ = Utils::GetValidUTF8(spec.name_.c_str(), "bsgdps2"); + } + return spec; +} + +} // namespace ballistica diff --git a/src/ballistica/game/player_spec.h b/src/ballistica/game/player_spec.h new file mode 100644 index 00000000..a6bf948f --- /dev/null +++ b/src/ballistica/game/player_spec.h @@ -0,0 +1,56 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_PLAYER_SPEC_H_ +#define BALLISTICA_GAME_PLAYER_SPEC_H_ + +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// a PlayerSpec is a portable description of an entity such as a player or +// client. It can contain long and short names, optional info linking it to a +// real account, and can be passed around easily in string form. +class PlayerSpec { + public: + // inits an invalid player-spec + PlayerSpec(); + auto operator==(const PlayerSpec& spec) const -> bool; + + // create a player-spec from a given spec-string. + // in the case of an error, defaults will be used + // (though the error will be reported) + explicit PlayerSpec(const std::string& s); + + // this returns a full display string for the spec, + // which may include the account icon + auto GetDisplayString() const -> std::string; + + // returns a short version of the player's name + // ideal for displaying in-game; this includes + // no icon and may just be the first name + auto GetShortName() const -> std::string; + + // return the full string form to be passed around + auto GetSpecString() const -> std::string; + + // returns a PlayerSpec for the currently logged in account + // if there is no current logged in account, a dummy-spec is created + // using the device name (so this always returns something reasonable) + static auto GetAccountPlayerSpec() -> PlayerSpec; + + // returns a 'dummy' PlayerSpec using the given name; can be + // used for non-account player profiles, names for non-logged-in + // party hosts, etc. + static auto GetDummyPlayerSpec(const std::string& name) -> PlayerSpec; + + private: + std::string name_; + std::string short_name_; + AccountType account_type_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_PLAYER_SPEC_H_ diff --git a/src/ballistica/game/score_to_beat.h b/src/ballistica/game/score_to_beat.h new file mode 100644 index 00000000..39b084b8 --- /dev/null +++ b/src/ballistica/game/score_to_beat.h @@ -0,0 +1,28 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_SCORE_TO_BEAT_H_ +#define BALLISTICA_GAME_SCORE_TO_BEAT_H_ + +#include +#include + +namespace ballistica { + +// Do we still need this? +class ScoreToBeat { + public: + ScoreToBeat(std::string player_in, std::string type_in, std::string value_in, + double timeIn) + : player(std::move(player_in)), + type(std::move(type_in)), + value(std::move(value_in)), + time(timeIn) {} + std::string player; + std::string type; + std::string value; + double time; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_SCORE_TO_BEAT_H_ diff --git a/src/ballistica/game/session/client_session.cc b/src/ballistica/game/session/client_session.cc new file mode 100644 index 00000000..d0013f3c --- /dev/null +++ b/src/ballistica/game/session/client_session.cc @@ -0,0 +1,1070 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/session/client_session.h" + +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/dynamics/material/material.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/dynamics/material/material_component.h" +#include "ballistica/dynamics/material/material_condition_node.h" +#include "ballistica/dynamics/rigid_body.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/networking/networking.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +// How many buckets we keep around for calculating max-lag-spikes. +const int kDelayBufferBuckets = 20; + +ClientSession::ClientSession() + : base_time_(0), + least_buffered_count_list_(kDelayBufferBuckets, 0), + most_buffered_count_list_(kDelayBufferBuckets, 0), + adjust_counter_(0), + buffer_count_list_index_(0), + steps_on_list_(0), + current_cmd_ptr_(nullptr), + shutting_down_(false) { + ClearSessionObjs(); +} + +void ClientSession::Reset(bool rewind) { + assert(!shutting_down_); + OnReset(rewind); +} + +void ClientSession::OnReset(bool rewind) { + ClearSessionObjs(); + target_base_time_ = base_time_ = 0; +} + +void ClientSession::ClearSessionObjs() { + scenes_.clear(); + nodes_.clear(); + textures_.clear(); + models_.clear(); + sounds_.clear(); + collide_models_.clear(); + materials_.clear(); + commands_pending_.clear(); + commands_.clear(); + steps_on_list_ = 0; +} + +auto ClientSession::DoesFillScreen() const -> bool { + // Look for any scene that has something that covers the background. + for (const auto& scene : scenes_) { + if ((scene.exists()) && (*scene).has_bg_cover()) { + return true; + } + } + return false; +} + +void ClientSession::Draw(FrameDef* f) { + // Just go through and draw all of our scenes. + for (auto&& i : scenes_) { + // NOTE - here we draw scenes in the order they were created, but + // in a host-session we draw session first followed by activities + // (that should be the same order in both cases, but just something to keep + // in mind...) + if (i.exists()) { + i->Draw(f); + } + } +} + +auto ClientSession::ReadByte() -> uint8_t { + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 1) { + throw Exception("state read error"); + } + return *(current_cmd_ptr_++); +} + +auto ClientSession::ReadInt32() -> int32_t { + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 4) { + throw Exception("state read error"); + } + int32_t val; + memcpy(&val, current_cmd_ptr_, sizeof(val)); + current_cmd_ptr_ += 4; + return val; +} + +auto ClientSession::ReadFloat() -> float { + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 4) { + throw Exception("state read error"); + } + float val; + memcpy(&val, current_cmd_ptr_, 4); + current_cmd_ptr_ += 4; + return val; +} + +void ClientSession::ReadFloats(int count, float* vals) { + int size = 4 * count; + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(vals, current_cmd_ptr_, static_cast(size)); + current_cmd_ptr_ += size; +} + +void ClientSession::ReadInt32s(int count, int32_t* vals) { + int size = 4 * count; + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(vals, current_cmd_ptr_, static_cast(size)); + current_cmd_ptr_ += size; +} + +void ClientSession::ReadChars(int count, char* vals) { + int size = count; + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(vals, current_cmd_ptr_, static_cast(size)); + current_cmd_ptr_ += size; +} + +void ClientSession::ReadInt32_3(int32_t* vals) { + size_t size = 3 * 4; + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(vals, current_cmd_ptr_, size); + current_cmd_ptr_ += size; +} + +void ClientSession::ReadInt32_4(int32_t* vals) { + size_t size = 4 * 4; + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(vals, current_cmd_ptr_, size); + current_cmd_ptr_ += size; +} + +void ClientSession::ReadInt32_2(int32_t* vals) { + size_t size = 2 * 4; + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(vals, current_cmd_ptr_, size); + current_cmd_ptr_ += size; +} + +auto ClientSession::ReadString() -> std::string { + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 4) { + throw Exception("state read error"); + } + int32_t size; + memcpy(&size, current_cmd_ptr_, sizeof(size)); + current_cmd_ptr_ += 4; + std::vector buffer(static_cast(size + 1)); + if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { + throw Exception("state read error"); + } + memcpy(&(buffer[0]), current_cmd_ptr_, static_cast(size)); + current_cmd_ptr_ += size; + return &(buffer[0]); +} + +void ClientSession::Update(int time_advance) { + if (shutting_down_) { + return; + } + + // Allow replays to modulate speed, etc. + time_advance = GetActualTimeAdvance(time_advance); + + target_base_time_ += static_cast(time_advance) * correction_; + + try { + // Read and run all events up to our target time. + while (base_time_ < target_base_time_) { + // If we need to do something explicit to keep messages flowing in. + // (informing the replay thread to feed us more, etc). + FetchMessages(); + + // If we've got another command on the list, pull it and run it. + if (!commands_.empty()) { + // Debugging: if this was previously pointed at a buffer, make sure we + // went exactly to the end. +#if BA_DEBUG_BUILD + if (current_cmd_ptr_ != nullptr) { + if (current_cmd_ptr_ != &(current_cmd_[0]) + current_cmd_.size()) { + Log("SIZE ERROR FOR CMD " + + std::to_string(static_cast(current_cmd_[0])) + + " expected " + std::to_string(current_cmd_.size()) + " got " + + std::to_string(current_cmd_ptr_ - &(current_cmd_[0]))); + } + } + assert(current_cmd_ptr_ == current_cmd_.data() + current_cmd_.size()); +#endif + + current_cmd_ = commands_.front(); + commands_.pop_front(); + current_cmd_ptr_ = &(current_cmd_[0]); + } else { + // Any time we run out of commands we immediately pull our target time + // back to where we currently are at. We want to stay *behind* the + // "buffering line". + target_base_time_ = base_time_; + OnCommandBufferUnderrun(); + return; + } + + auto cmd = static_cast(ReadByte()); + + switch (cmd) { + case SessionCommand::kBaseTimeStep: { + int32_t stepsize = ReadInt32(); + BA_PRECONDITION(stepsize > 0); + if (stepsize > 10000) { + throw Exception( + "got abnormally large stepsize; probably a corrupt stream"); + } + steps_on_list_ -= stepsize; + BA_PRECONDITION(steps_on_list_ >= 0); + base_time_ += stepsize; + break; + } + case SessionCommand::kDynamicsCorrection: { + bool blend = current_cmd_[1]; + uint32_t offset = 2; + uint16_t node_count; + memcpy(&node_count, current_cmd_.data() + offset, sizeof(node_count)); + offset += 2; + for (int i = 0; i < node_count; i++) { + uint32_t node_id; + memcpy(&node_id, current_cmd_.data() + offset, sizeof(node_id)); + offset += 4; + int body_count = current_cmd_[offset++]; + Node* n = + (node_id < nodes_.size()) ? nodes_[node_id].get() : nullptr; + for (int j = 0; j < body_count; j++) { + int bodyid = current_cmd_[offset++]; + uint16_t body_data_len; + memcpy(&body_data_len, current_cmd_.data() + offset, + sizeof(body_data_len)); + RigidBody* b = n ? n->GetRigidBody(bodyid) : nullptr; + offset += 2; + const char* p1 = reinterpret_cast(&(current_cmd_[offset])); + const char* p2 = p1; + if (b) { + dBodyID body = b->body(); + const dReal* p = dBodyGetPosition(body); + float old_x = p[0]; + float old_y = p[1]; + float old_z = p[2]; + b->ExtractFull(&p2); + if (p2 - p1 != body_data_len) + throw Exception("Invalid rbd correction data"); + if (blend) { + b->AddBlendOffset(old_x - p[0], old_y - p[1], old_z - p[2]); + } + } + offset += body_data_len; + if (offset > current_cmd_.size()) { + throw Exception("Invalid rbd correction data"); + } + } + if (offset > current_cmd_.size()) + throw Exception("Invalid rbd correction data"); + // extract custom per-node data + uint16_t custom_data_len; + memcpy(&custom_data_len, current_cmd_.data() + offset, + sizeof(custom_data_len)); + offset += 2; + if (custom_data_len != 0) { + std::vector data(custom_data_len); + memcpy(&(data[0]), &(current_cmd_[offset]), custom_data_len); + if (n) n->ApplyResyncData(data); + offset += custom_data_len; + } + if (offset > current_cmd_.size()) { + throw Exception("Invalid rbd correction data"); + } + } + if (offset != current_cmd_.size()) { + throw Exception("invalid rbd correction data"); + } + current_cmd_ptr_ = &(current_cmd_[0]) + offset; + + break; + } + case SessionCommand::kEndOfFile: { + // EOF can happen anytime if they run out of disk space/etc. + // We should expect any state. + Reset(true); + break; + } + case SessionCommand::kAddSceneGraph: { + int32_t cmdvals[2]; + ReadInt32_2(cmdvals); + int32_t id = cmdvals[0]; + millisecs_t starttime = cmdvals[1]; + if (id < 0 || id > 100) { + throw Exception("invalid scene id"); + } + if (static_cast(scenes_.size()) < (id + 1)) { + scenes_.resize(static_cast(id) + 1); + } + assert(!scenes_[id].exists()); + scenes_[id] = Object::New(starttime); + scenes_[id]->stream_id_ = id; + break; + } + case SessionCommand::kRemoveSceneGraph: { + int32_t id = ReadInt32(); + GetScene(id); // Make sure it's valid. + scenes_[id].Clear(); + break; + } + case SessionCommand::kStepSceneGraph: { + int32_t val = ReadInt32(); + Scene* sg = GetScene(val); + sg->Step(); + break; + } + case SessionCommand::kAddNode: { + int32_t vals[3]; // scene-id, nodetype-id, node-id + ReadInt32_3(vals); + Scene* scene = GetScene(vals[0]); + assert(g_app_globals != nullptr); + if (vals[1] < 0 + || vals[1] >= static_cast( + g_app_globals->node_types_by_id.size())) { + throw Exception("invalid node type id"); + } + + NodeType* node_type = g_app_globals->node_types_by_id[vals[1]]; + + // Fail if we get a ridiculous number of nodes. + // FIXME: should enforce this on the server side too. + int id = vals[2]; + if (id < 0 || id > 10000) throw Exception("invalid node id"); + if (static_cast(nodes_.size()) < (id + 1)) { + nodes_.resize(static_cast(id) + 1); + } + assert(!nodes_[id].exists()); + { + ScopedSetContext _cp(this); + nodes_[id] = scene->NewNode(node_type->name(), "", nullptr); + nodes_[id]->set_stream_id(id); + } + break; + } + case SessionCommand::kSetForegroundSceneGraph: { + Scene* scene = GetScene(ReadInt32()); + g_game->SetForegroundScene(scene); + break; + } + case SessionCommand::kNodeMessage: { + int32_t vals[2]; + ReadInt32_2(vals); + Node* n = GetNode(vals[0]); + int32_t msg_size = vals[1]; + if (msg_size < 1 || msg_size > 10000) { + throw Exception("invalid message"); + } + std::vector buffer(static_cast(msg_size)); + ReadChars(msg_size, &buffer[0]); + n->DispatchNodeMessage(&buffer[0]); + break; + } + case SessionCommand::kConnectNodeAttribute: { + int32_t vals[4]; + ReadInt32_4(vals); + Node* src_node = GetNode(vals[0]); + Node* dst_node = GetNode(vals[2]); + NodeAttributeUnbound* src_attr = + src_node->type()->GetAttribute(static_cast(vals[1])); + NodeAttributeUnbound* dst_attr = + dst_node->type()->GetAttribute(static_cast(vals[3])); + src_node->ConnectAttribute(src_attr, dst_node, dst_attr); + break; + } + case SessionCommand::kNodeOnCreate: { + Node* n = GetNode(ReadInt32()); + n->OnCreate(); + break; + } + case SessionCommand::kAddMaterial: { + int32_t vals[2]; // scene-id, material-id + ReadInt32_2(vals); + Scene* scene = GetScene(vals[0]); + // Fail if we get a ridiculous number of materials. + // FIXME: should enforce this on the server side too. + int id = vals[1]; + if (vals[1] < 0 || vals[1] >= 1000) { + throw Exception("invalid material id"); + } + if (static_cast(materials_.size()) < (id + 1)) + materials_.resize(static_cast(id) + 1); + assert(!materials_[id].exists()); + materials_[id] = Object::New("", scene); + materials_[id]->stream_id_ = id; + break; + } + case SessionCommand::kRemoveMaterial: { + int id = ReadInt32(); + GetMaterial(id); // make sure its valid + materials_[id].Clear(); + break; + } + case SessionCommand::kAddMaterialComponent: { + int32_t cmdvals[2]; + ReadInt32_2(cmdvals); + Material* m = GetMaterial(cmdvals[0]); + int component_size = cmdvals[1]; + if (component_size < 1 || component_size > 10000) { + throw Exception("invalid component"); + } + std::vector buffer(static_cast(component_size)); + ReadChars(component_size, &buffer[0]); + auto c(Object::New()); + const char* ptr1 = &buffer[0]; + const char* ptr2 = ptr1; + c->Restore(&ptr2, this); + BA_PRECONDITION(ptr2 - ptr1 == component_size); + m->AddComponent(c); + break; + } + case SessionCommand::kAddTexture: { + int32_t vals[2]; // scene-id, texture-id + ReadInt32_2(vals); + std::string name = ReadString(); + Scene* scene = GetScene(vals[0]); + // Fail if we get a ridiculous number of textures. + // FIXME: Should enforce this on the server side too. + int id = vals[1]; + if (vals[1] < 0 || vals[1] >= 1000) { + throw Exception("invalid texture id"); + } + if (static_cast(textures_.size()) < (id + 1)) { + textures_.resize(static_cast(id) + 1); + } + assert(!textures_[id].exists()); + textures_[id] = Object::New(name, scene); + textures_[id]->stream_id_ = id; + break; + } + case SessionCommand::kRemoveTexture: { + int id = ReadInt32(); + GetTexture(id); // make sure its valid + textures_[id].Clear(); + break; + } + case SessionCommand::kAddModel: { + int32_t vals[2]; // scene-id, model-id + ReadInt32_2(vals); + std::string name = ReadString(); + Scene* scene = GetScene(vals[0]); + + // Fail if we get a ridiculous number of models. + // FIXME: Should enforce this on the server side too. + int id = vals[1]; + if (vals[1] < 0 || vals[1] >= 1000) { + throw Exception("invalid model id"); + } + if (static_cast(models_.size()) < (id + 1)) { + models_.resize(static_cast(id) + 1); + } + assert(!models_[id].exists()); + models_[id] = Object::New(name, scene); + models_[id]->stream_id_ = id; + break; + } + case SessionCommand::kRemoveModel: { + int id = ReadInt32(); + GetModel(id); // make sure its valid + models_[id].Clear(); + break; + } + case SessionCommand::kAddSound: { + int32_t vals[2]; // scene-id, sound-id + ReadInt32_2(vals); + std::string name = ReadString(); + Scene* scene = GetScene(vals[0]); + // Fail if we get a ridiculous number of sounds. + // FIXME: Should enforce this on the server side too. + int id = vals[1]; + if (vals[1] < 0 || vals[1] >= 1000) { + throw Exception("invalid sound id"); + } + if (static_cast(sounds_.size()) < (id + 1)) { + sounds_.resize(static_cast(id) + 1); + } + assert(!sounds_[id].exists()); + sounds_[id] = Object::New(name, scene); + sounds_[id]->stream_id_ = id; + break; + } + case SessionCommand::kRemoveSound: { + int id = ReadInt32(); + GetSound(id); // make sure its valid + sounds_[id].Clear(); + break; + } + case SessionCommand::kAddCollideModel: { + int32_t vals[2]; // scene-id, collide_model-id + ReadInt32_2(vals); + std::string name = ReadString(); + Scene* scene = GetScene(vals[0]); + // Fail if we get a ridiculous number of collide_models. + // FIXME: Should enforce this on the server side too. + int id = vals[1]; + if (vals[1] < 0 || vals[1] >= 1000) { + throw Exception("invalid collide_model id"); + } + if (static_cast(collide_models_.size()) < (id + 1)) { + collide_models_.resize(static_cast(id) + 1); + } + assert(!collide_models_[id].exists()); + collide_models_[id] = Object::New(name, scene); + collide_models_[id]->stream_id_ = id; + break; + } + case SessionCommand::kRemoveCollideModel: { + int id = ReadInt32(); + GetCollideModel(id); // make sure its valid + collide_models_[id].Clear(); + break; + } + case SessionCommand::kRemoveNode: { + int id = ReadInt32(); + Node* n = GetNode(id); + n->scene()->DeleteNode(n); + assert(!nodes_[id].exists()); + break; + } + case SessionCommand::kSetNodeAttrFloat: { + int vals[2]; + ReadInt32_2(vals); + GetNode(vals[0])->GetAttribute(vals[1]).Set(ReadFloat()); + break; + } + case SessionCommand::kSetNodeAttrInt32: { + int32_t vals[3]; + ReadInt32_3(vals); + + // Note; we currently deal in 64 bit ints locally but read/write 32 + // bit over the wire. + GetNode(vals[0])->GetAttribute(vals[1]).Set( + static_cast(vals[2])); + break; + } + case SessionCommand::kSetNodeAttrBool: { + int vals[3]; + ReadInt32_3(vals); + GetNode(vals[0])->GetAttribute(vals[1]).Set( + static_cast(vals[2])); + break; + } + case SessionCommand::kSetNodeAttrFloats: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals(static_cast(count)); + if (count > 0) { + ReadFloats(count, &(vals[0])); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kSetNodeAttrInt32s: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals[0])); + } + // Note: we currently deal in 64 bit ints locally but read/write 32 + // bit over the wire. Convert. + std::vector vals64(static_cast(count)); + for (int i = 0; i < count; i++) { + vals64[i] = vals[i]; + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals64); + break; + } + case SessionCommand::kSetNodeAttrString: { + int vals[2]; + ReadInt32_2(vals); + GetNode(vals[0])->GetAttribute(vals[1]).Set(ReadString()); + break; + } + case SessionCommand::kSetNodeAttrNode: { + int vals[3]; + ReadInt32_3(vals); + GetNode(vals[0])->GetAttribute(vals[1]).Set(GetNode(vals[2])); + break; + } + case SessionCommand::kSetNodeAttrNodeNull: { + int cmdvals[2]; + ReadInt32_2(cmdvals); + Node* val = nullptr; + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrTextureNull: { + int cmdvals[2]; + ReadInt32_2(cmdvals); + Texture* val = nullptr; + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrSoundNull: { + int cmdvals[2]; + ReadInt32_2(cmdvals); + Sound* val = nullptr; + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrModelNull: { + int cmdvals[2]; + ReadInt32_2(cmdvals); + Model* val = nullptr; + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrCollideModelNull: { + int cmdvals[2]; + ReadInt32_2(cmdvals); + CollideModel* val = nullptr; + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrNodes: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals_in(static_cast(count)); + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals_in[0])); + } + for (int i = 0; i < count; i++) { + vals[i] = GetNode(vals_in[i]); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kSetNodeAttrTexture: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + Texture* val = GetTexture(cmdvals[2]); + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrTextures: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals_in(static_cast(count)); + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals_in[0])); + } + for (int i = 0; i < count; i++) { + vals[i] = GetTexture(vals_in[i]); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kSetNodeAttrSound: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + Sound* val = GetSound(cmdvals[2]); + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrSounds: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals_in(static_cast(count)); + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals_in[0])); + } + for (int i = 0; i < count; i++) { + vals[i] = GetSound(vals_in[i]); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kSetNodeAttrModel: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + Model* val = GetModel(cmdvals[2]); + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrModels: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals_in(static_cast(count)); + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals_in[0])); + } + for (int i = 0; i < count; i++) { + vals[i] = GetModel(vals_in[i]); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kSetNodeAttrCollideModel: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + CollideModel* val = GetCollideModel(cmdvals[2]); + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); + break; + } + case SessionCommand::kSetNodeAttrCollideModels: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals_in(static_cast(count)); + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals_in[0])); + } + for (int i = 0; i < count; i++) { + vals[i] = GetCollideModel(vals_in[i]); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kSetNodeAttrMaterials: { + int cmdvals[3]; + ReadInt32_3(cmdvals); + int count = cmdvals[2]; + if (count < 0 || count > 1000) { + throw Exception("invalid array size (" + std::to_string(count) + + ")"); + } + std::vector vals_in(static_cast(count)); + std::vector vals(static_cast(count)); + if (count > 0) { + ReadInt32s(count, &(vals_in[0])); + } + for (int i = 0; i < count; i++) { + vals[i] = GetMaterial(vals_in[i]); + } + GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); + break; + } + case SessionCommand::kPlaySound: { + Sound* sound = GetSound(ReadInt32()); + float volume = ReadFloat(); + g_audio->PlaySound(sound->GetSoundData(), volume); + break; + } + case SessionCommand::kScreenMessageBottom: { + std::string val = ReadString(); + Vector3f color{}; + ReadFloats(3, color.v); + ScreenMessage(val, color); + break; + } + case SessionCommand::kScreenMessageTop: { + int cmdvals[2]; + ReadInt32_2(cmdvals); + Texture* texture = GetTexture(cmdvals[0]); + Texture* tint_texture = GetTexture(cmdvals[1]); + std::string s = ReadString(); + float f[9]; + ReadFloats(9, f); + g_graphics->AddScreenMessage( + s, Vector3f(f[0], f[1], f[2]), true, texture, tint_texture, + Vector3f(f[3], f[4], f[5]), Vector3f(f[6], f[7], f[8])); + break; + } + case SessionCommand::kPlaySoundAtPosition: { + Sound* sound = GetSound(ReadInt32()); + float volume = ReadFloat(); + float x = ReadFloat(); + float y = ReadFloat(); + float z = ReadFloat(); + g_audio->PlaySoundAtPosition(sound->GetSoundData(), volume, x, y, z); + break; + } + case SessionCommand::kEmitBGDynamics: { +#if !BA_HEADLESS_BUILD + BGDynamicsEmission e; +#endif + int cmdvals[4]; + ReadInt32_4(cmdvals); +#if !BA_HEADLESS_BUILD + e.emit_type = (BGDynamicsEmitType)cmdvals[0]; + e.count = cmdvals[1]; + e.chunk_type = (BGDynamicsChunkType)cmdvals[2]; + e.tendril_type = (BGDynamicsTendrilType)cmdvals[3]; +#endif + float vals[8]; + ReadFloats(8, vals); +#if !BA_HEADLESS_BUILD + e.position.x = vals[0]; + e.position.y = vals[1]; + e.position.z = vals[2]; + e.velocity.x = vals[3]; + e.velocity.y = vals[4]; + e.velocity.z = vals[5]; + e.scale = vals[6]; + e.spread = vals[7]; + g_bg_dynamics->Emit(e); +#endif + break; + } + default: + throw Exception("unrecognized stream command: " + + std::to_string(static_cast(cmd))); + } + } + } catch (const std::exception& e) { + Error(e.what()); + } +} // NOLINT (yes this is too long) + +ClientSession::~ClientSession() = default; + +void ClientSession::ScreenSizeChanged() { + // Let all our scenes know. + for (auto&& i : scenes_) { + if (Scene* sg = i.get()) { + sg->ScreenSizeChanged(); + } + } +} + +void ClientSession::LanguageChanged() { + // Let all our scenes know. + for (auto&& i : scenes_) { + if (Scene* sg = i.get()) { + sg->LanguageChanged(); + } + } +} + +auto ClientSession::GetScene(int id) const -> Scene* { + if (id < 0 || id >= static_cast(scenes_.size())) { + throw Exception("Invalid scene id"); + } + Scene* sg = scenes_[id].get(); + if (!sg) { + throw Exception("Invalid scene id"); + } + return sg; +} +auto ClientSession::GetNode(int id) const -> Node* { + if (id < 0 || id >= static_cast(nodes_.size())) { + throw Exception("Invalid node (out of range)"); + } + Node* n = nodes_[id].get(); + if (!n) { + throw Exception("Invalid node id (empty slot)"); + } + return n; +} +auto ClientSession::GetMaterial(int id) const -> Material* { + if (id < 0 || id >= static_cast(materials_.size())) { + throw Exception("Invalid material (out of range)"); + } + Material* n = materials_[id].get(); + if (!n) { + throw Exception("Invalid material id (empty slot)"); + } + return n; +} +auto ClientSession::GetTexture(int id) const -> Texture* { + if (id < 0 || id >= static_cast(textures_.size())) { + throw Exception("Invalid texture (out of range)"); + } + Texture* n = textures_[id].get(); + if (!n) { + throw Exception("Invalid texture id (empty slot)"); + } + return n; +} +auto ClientSession::GetModel(int id) const -> Model* { + if (id < 0 || id >= static_cast(models_.size())) { + throw Exception("Invalid model (out of range)"); + } + Model* n = models_[id].get(); + if (!n) { + throw Exception("Invalid model id (empty slot)"); + } + return n; +} +auto ClientSession::GetSound(int id) const -> Sound* { + if (id < 0 || id >= static_cast(sounds_.size())) { + throw Exception("Invalid sound (out of range)"); + } + Sound* n = sounds_[id].get(); + if (!n) { + throw Exception("Invalid sound id (empty slot)"); + } + return n; +} +auto ClientSession::GetCollideModel(int id) const -> CollideModel* { + if (id < 0 || id >= static_cast(collide_models_.size())) { + throw Exception("Invalid collide_model (out of range)"); + } + CollideModel* n = collide_models_[id].get(); + if (!n) { + throw Exception("Invalid collide_model id (empty slot)"); + } + return n; +} + +void ClientSession::Error(const std::string& description) { + Log("ERROR: client session error: " + description); + End(); +} + +void ClientSession::End() { + if (shutting_down_) return; + shutting_down_ = true; + g_python->PushObjCall(Python::ObjID::kLaunchMainMenuSessionCall); +} + +void ClientSession::HandleSessionMessage(const std::vector& buffer) { + assert(InGameThread()); + + BA_PRECONDITION(!buffer.empty()); + + switch (buffer[0]) { + case BA_MESSAGE_SESSION_RESET: { + // Hmmm; been a while since I wrote this, but wondering why reset isn't + // just a session-command. (Do we not want it added to replays?...) + Reset(false); + break; + } + + case BA_MESSAGE_SESSION_COMMANDS: { + // This is simply 16 bit length followed by command up to the end of the + // packet. Break it apart and feed each command to the client session. + uint32_t offset = 1; + std::vector subBuffer; + while (true) { + uint16_t size; + memcpy(&size, &(buffer[offset]), 2); + if (offset + size > buffer.size()) { + Error("invalid state message"); + return; + } + subBuffer.resize(size); + memcpy(&(subBuffer[0]), &(buffer[offset + 2]), subBuffer.size()); + AddCommand(subBuffer); + offset += 2 + size; // move to next command + if (offset == buffer.size()) { + // lets also use this opportunity to graph our command-buffer size for + // network debugging.. if (NetGraph *graph = + // g_graphics->GetClientSessionStepBufferGraph()) { + // graph->addSample(GetRealTime(), steps_on_list_); + // } + + break; + } + } + break; + } + + case BA_MESSAGE_SESSION_DYNAMICS_CORRECTION: { + // Just drop this in the game's command-stream verbatim, except switch its + // state-ID to a command-ID. + std::vector bufferOut = buffer; + bufferOut[0] = static_cast(SessionCommand::kDynamicsCorrection); + AddCommand(bufferOut); + break; + } + + default: + throw Exception("ClientSession::HandleSessionMessage " + ObjToString(this) + + "got unrecognized message : " + + std::to_string(static_cast(buffer[0])) + + " of size " + std::to_string(buffer.size())); + break; + } +} + +// Add a single command in. +void ClientSession::AddCommand(const std::vector& command) { + // If this is a time-step command, we can dump everything we've been building + // up onto the list to be chewed through by the interpreter (we don't want to + // add things until we have the *entire* step so we don't wind up rendering + // things halfway through some change, etc). + commands_pending_.push_back(command); + if (!command.empty()) { + if (command[0] == static_cast(SessionCommand::kBaseTimeStep)) { + // Keep a tally of how much stepped time we've built up. + steps_on_list_ += command[1]; + for (auto&& i : commands_pending_) { + commands_.push_back(i); + } + commands_pending_.clear(); + } + } +} + +auto ClientSession::GetForegroundContext() -> Context { return Context(this); } + +void ClientSession::GetCorrectionMessages( + bool blend, std::vector >* messages) { + std::vector message; + for (auto&& i : scenes_) { + if (Scene* sg = i.get()) { + message = sg->GetCorrectionMessage(blend); + // A correction packet of size 4 is empty; ignore it. + if (message.size() > 4) { + messages->push_back(message); + } + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/session/client_session.h b/src/ballistica/game/session/client_session.h new file mode 100644 index 00000000..60330a47 --- /dev/null +++ b/src/ballistica/game/session/client_session.h @@ -0,0 +1,99 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_SESSION_CLIENT_SESSION_H_ +#define BALLISTICA_GAME_SESSION_CLIENT_SESSION_H_ + +#include +#include +#include + +#include "ballistica/game/client_controller_interface.h" +#include "ballistica/game/session/session.h" + +namespace ballistica { + +class ClientSession : public Session { + public: + ClientSession(); + ~ClientSession() override; + + // Allows for things like replay speed. + virtual auto GetActualTimeAdvance(int advance_in) -> int { + return advance_in; + } + void Update(int time_advance) override; + void Draw(FrameDef* f) override; + virtual void HandleSessionMessage(const std::vector& buffer); + void Reset(bool rewind); + auto GetForegroundContext() -> Context override; + auto DoesFillScreen() const -> bool override; + void ScreenSizeChanged() override; + void LanguageChanged() override; + auto shutting_down() const -> bool { return shutting_down_; } + void GetCorrectionMessages(bool blend, + std::vector >* messages); + + // Called when attempting to step without input data available. + virtual void OnCommandBufferUnderrun() {} + + // Returns existing objects; throws exceptions if not available. + auto GetScene(int id) const -> Scene*; + auto GetNode(int id) const -> Node*; + auto GetTexture(int id) const -> Texture*; + auto GetModel(int id) const -> Model*; + auto GetCollideModel(int id) const -> CollideModel*; + auto GetMaterial(int id) const -> Material*; + auto GetSound(int id) const -> Sound*; + + protected: + virtual void OnReset(bool rewind); + virtual void FetchMessages() {} + int steps_on_list_; + std::list > commands_; // ready-to-go commands + virtual void Error(const std::string& description); + void End(); + millisecs_t base_time_; + double target_base_time_ = 0.0f; + bool shutting_down_; + std::vector least_buffered_count_list_; // move this to net-client?.. + std::vector most_buffered_count_list_; + int buffer_count_list_index_; + int adjust_counter_; + float correction_ = 1.0f; + float largest_spike_smoothed_ = 0.0f; + float low_pass_smoothed_ = 0.0f; + + private: + void ClearSessionObjs(); + void AddCommand(const std::vector& command); + + // commands being built up for the next time step + // (we want to be able to run *everything* for a given timestep at once + // to avoid drawing things in half-changed states, etc) + std::list > commands_pending_; // commands for the next + std::vector current_cmd_; + uint8_t* current_cmd_ptr_; + auto ReadByte() -> uint8_t; + auto ReadInt32() -> int32_t; + void ReadInt32_2(int32_t* vals); + void ReadInt32_3(int32_t* vals); + void ReadInt32_4(int32_t* vals); + auto ReadString() -> std::string; + auto ReadFloat() -> float; + void ReadFloats(int count, float* vals); + void ReadInt32s(int count, int32_t* vals); + void ReadChars(int count, char* vals); + + protected: + std::vector > scenes_; + std::vector > nodes_; + std::vector > textures_; + std::vector > models_; + std::vector > sounds_; + std::vector > collide_models_; + std::vector > materials_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_SESSION_CLIENT_SESSION_H_ diff --git a/src/ballistica/game/session/host_session.cc b/src/ballistica/game/session/host_session.cc new file mode 100644 index 00000000..914beba7 --- /dev/null +++ b/src/ballistica/game/session/host_session.cc @@ -0,0 +1,765 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/session/host_session.h" + +#include "ballistica/core/context.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/player.h" +#include "ballistica/generic/lambda_runnable.h" +#include "ballistica/generic/timer.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/media/component/data.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_command.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/python/python_sys.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +HostSession::HostSession(PyObject* session_type_obj) + : last_kick_idle_players_decrement_time_(GetRealTime()) { + assert(g_game); + assert(InGameThread()); + assert(session_type_obj != nullptr); + + ScopedSetContext cp(this); + + // FIXME: Should be an attr of the session class, not hard-coded. + is_main_menu_ = + static_cast(strstr(Python::ObjToString(session_type_obj).c_str(), + "bastd.mainmenu.MainMenuSession")); + // Log("MAIN MENU? " + std::to_string(is_main_menu())); + + kick_idle_players_ = g_game->kick_idle_players(); + + // Create a timer to step our session scene. + step_scene_timer_ = + base_timers_.NewTimer(base_time_, kGameStepMilliseconds, 0, -1, + NewLambdaRunnable([this] { StepScene(); })); + + // Set up our output-stream, which will go to a replay and/or the network. + // We don't dump to a replay if we're doing the main menu; that replay + // would be boring. + bool do_replay = !is_main_menu_; + // Log("DO REPLAY? " + std::to_string(do_replay)); + + // At the moment headless-server don't write replays. +#if BA_HEADLESS_BUILD + do_replay = false; +#endif // BA_HEADLESS_BUILD + output_stream_ = Object::New(this, do_replay); + + // Make a scene for our session-level nodes, etc. + scene_ = Object::New(0); + if (output_stream_.exists()) { + output_stream_->AddScene(scene_.get()); + } + + // Fade in from our current blackness. + g_graphics->FadeScreen(true, 250, nullptr); + + // Start by showing the progress bar instead of hitching. + g_graphics->EnableProgressBar(true); + + // Now's a good time to run garbage collection; there should be pretty much + // no game stuff to speak of in existence (provided the last session went + // down peacefully). + g_python->obj(Python::ObjID::kGarbageCollectCall).Call(); + + // Instantiate our python Session instance. + PythonRef obj; + PythonRef session_type(session_type_obj, PythonRef::kAcquire); + { + Python::ScopedCallLabel label("Session instantiation"); + obj = session_type.Call(); + } + if (!obj.exists()) { + throw Exception("Error creating game session: '" + session_type.Str() + + "'"); + } + + // The session python object should have called + // _ba.register_session() in its constructor to set session_py_obj_. + if (session_py_obj_ != obj) { + throw Exception("session not set up correctly"); + } + + // Lastly, keep the python layer fed with our latest player count in case + // it is updating the master-server with our current/max player counts. + g_game->SetPublicPartyPlayerCount(static_cast(players_.size())); +} + +auto HostSession::GetHostSession() -> HostSession* { return this; } + +void HostSession::DestroyHostActivity(HostActivity* a) { + BA_PRECONDITION(a); + BA_PRECONDITION(a->GetHostSession() == this); + if (a == foreground_host_activity_.get()) { + foreground_host_activity_.Clear(); + } + + // Clear it from our activities list if its still on there. + for (auto i = host_activities_.begin(); i < host_activities_.end(); i++) { + if (i->get() == a) { + host_activities_.erase(i); + return; + } + } + + // The only reason it wouldn't be there should be because the activity is + // dying due our clearing of the list in our destructor; make sure that's + // the case. + assert(shutting_down_); +} + +auto HostSession::GetMutableScene() -> Scene* { + assert(scene_.exists()); + return scene_.get(); +} + +void HostSession::DebugSpeedMultChanged() { + // FIXME - should we progress our own scene faster/slower depending on + // this too? Is there really a need to? + + // Let all our activities know. + for (auto&& i : host_activities_) { + i->DebugSpeedMultChanged(); + } +} + +void HostSession::ScreenSizeChanged() { + // Let our internal scene know. + scene()->ScreenSizeChanged(); + + // Also let all our activities know. + for (auto&& i : host_activities_) { + i->ScreenSizeChanged(); + } +} + +void HostSession::LanguageChanged() { + // Let our internal scene know. + scene()->LanguageChanged(); + + // Also let all our activities know. + for (auto&& i : host_activities_) { + i->LanguageChanged(); + } +} + +void HostSession::GraphicsQualityChanged(GraphicsQuality q) { + // Let our internal scene know. + scene()->GraphicsQualityChanged(q); + + // Let all our activities know. + for (auto&& i : host_activities_) { + i->GraphicsQualityChanged(q); + } +} + +auto HostSession::DoesFillScreen() const -> bool { + // FIXME not necessarily the case. + return true; +} + +void HostSession::Draw(FrameDef* f) { + // First draw our session scene. + scene()->Draw(f); + + // Let all our activities draw their own scenes/etc. + for (auto&& i : host_activities_) { + i->Draw(f); + } +} + +auto HostSession::NewTimer(TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int { + if (shutting_down_) { + BA_LOG_PYTHON_TRACE_ONCE( + "WARNING: Creating game timer during host-session shutdown"); + return 123; // dummy... + } + if (length == 0 && repeat) { + throw Exception("Can't add game-timer with length 0 and repeat on"); + } + if (length < 0) { + throw Exception("Timer length cannot be < 0 (got " + std::to_string(length) + + ")"); + } + int offset = 0; + Timer* t = sim_timers_.NewTimer(scene()->time(), length, offset, + repeat ? -1 : 0, runnable); + return t->id(); +} + +void HostSession::DeleteTimer(int timer_id) { + assert(InGameThread()); + if (shutting_down_) return; + sim_timers_.DeleteTimer(timer_id); +} + +auto HostSession::GetSound(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during session shutdown"); + } + return Media::GetMedia(&sounds_, name, scene()); +} + +auto HostSession::GetData(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during session shutdown"); + } + return Media::GetMedia(&datas_, name, scene()); +} + +auto HostSession::GetTexture(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load assets during session shutdown"); + } + return Media::GetMedia(&textures_, name, scene()); +} +auto HostSession::GetModel(const std::string& name) -> Object::Ref { + if (shutting_down_) { + throw Exception("can't load media during session shutdown"); + } + return Media::GetMedia(&models_, name, scene()); +} + +auto HostSession::GetForegroundContext() -> Context { + HostActivity* a = foreground_host_activity_.get(); + if (a) { + return Context(a); + } + return Context(this); +} + +void HostSession::RequestPlayer(InputDevice* device) { + assert(InGameThread()); + + // Ignore if we have no python session obj. + if (!GetSessionPyObj()) { + Log("Error: HostSession::RequestPlayer() called w/no session_py_obj_."); + return; + } + + // Need to at least temporarily create and attach to a player for passing to + // the callback. + int player_id = next_player_id_++; + auto player(Object::New(player_id, this)); + players_.push_back(player); + device->AttachToLocalPlayer(player.get()); + + // Ask the python layer to accept/deny this guy. + bool accept; + { + // Set the session as context. + ScopedSetContext cp(this); + accept = static_cast( + session_py_obj_.GetAttr("_request_player") + .Call(PythonRef(Py_BuildValue("(O)", player->BorrowPyRef()), + PythonRef::kSteal)) + .ValueAsInt()); + if (accept) { + player->set_accepted(true); + } else { + RemovePlayer(player.get()); + } + } + + // If he was accepted, update our game roster with the new info. + if (accept) { + g_game->UpdateGameRoster(); + } + + // Lastly, keep the python layer fed with our latest player count in case it + // is updating the master-server with our current/max player counts. + g_game->SetPublicPartyPlayerCount(static_cast(players_.size())); +} + +void HostSession::RemovePlayer(Player* player) { + assert(player); + + for (auto i = players_.begin(); i != players_.end(); ++i) { + if (i->get() == player) { + // Grab a ref to keep the player alive, pull him off the list, then call + // his leaving callback. + Object::Ref player2 = *i; + players_.erase(i); + + // Only make the callback for this player if they were accepted. + if (player2->accepted()) { + IssuePlayerLeft(player2.get()); + } + + // Update our game roster with the departure. + g_game->UpdateGameRoster(); + + // Lastly, keep the python layer fed with our latest player count in case + // it is updating the master-server with our current/max player counts. + g_game->SetPublicPartyPlayerCount(static_cast(players_.size())); + + return; + } + } + BA_LOG_ERROR_TRACE("Player not found in HostSession::RemovePlayer()"); +} + +void HostSession::IssuePlayerLeft(Player* player) { + assert(player); + assert(InGameThread()); + + try { + if (GetSessionPyObj()) { + if (player) { + // Make sure we're the context for session callbacks. + ScopedSetContext cp(this); + Python::ScopedCallLabel label("Session on_player_leave"); + session_py_obj_.GetAttr("on_player_leave") + .Call(PythonRef(Py_BuildValue("(O)", player->BorrowPyRef()), + PythonRef::kSteal)); + } else { + BA_LOG_PYTHON_TRACE_ONCE("missing player on IssuePlayerLeft"); + } + } else { + Log("WARNING: HostSession: IssuePlayerLeft caled with no " + "session_py_obj_"); + } + } catch (const std::exception& e) { + Log(std::string("Error calling on_player_leave(): ") + e.what()); + } +} + +void HostSession::SetKickIdlePlayers(bool enable) { + // If this has changed, reset our disconnect-time reporting. + assert(InGameThread()); + if (enable != kick_idle_players_) { + last_kick_idle_players_decrement_time_ = GetRealTime(); + } + kick_idle_players_ = enable; +} + +void HostSession::SetForegroundHostActivity(HostActivity* a) { + assert(a); + assert(InGameThread()); + + if (shutting_down_) { + Log("WARNING: SetForegroundHostActivity called during session shutdown; " + "ignoring."); + return; + } + + // Sanity check: make sure the one provided is part of this session. + bool found = false; + for (auto&& i : host_activities_) { + if (i == a) { + found = true; + break; + } + } + if ((a->GetHostSession() != this) || !found) { + throw Exception("HostActivity is not part of this HostSession"); + } + + foreground_host_activity_ = a; + + // Now go through telling each host-activity whether it's foregrounded or not. + // FIXME: Dying sessions never get told they're un-foregrounded.. could that + // ever be a problem? + bool session_is_foreground = (g_game->GetForegroundSession() != nullptr); + for (auto&& i : host_activities_) { + i->SetIsForeground(session_is_foreground && (i == a)); + } +} + +void HostSession::AddHostActivity(HostActivity* a) { + host_activities_.emplace_back(a); +} + +// Called by the constructor of the session python object. +void HostSession::RegisterPySession(PyObject* obj) { + session_py_obj_.Acquire(obj); +} + +// Given an activity python type, instantiates and returns a new activity. +auto HostSession::NewHostActivity(PyObject* activity_type_obj, + PyObject* settings_obj) -> PyObject* { + PythonRef activity_type(activity_type_obj, PythonRef::kAcquire); + if (!activity_type.CallableCheck()) { + throw Exception("Invalid HostActivity type passed; not callable"); + } + + // First generate our C++ activity instance and point the context at it. + auto activity(Object::New(this)); + AddHostActivity(activity.get()); + + ScopedSetContext cp(activity.get()); + + // Now instantiate the python instance.. pass args if some were provided, or + // an empty dict otherwise. + PythonRef args; + if (settings_obj == Py_None) { + args.Steal(Py_BuildValue("({})")); + } else { + args.Steal(Py_BuildValue("(O)", settings_obj)); + } + + PythonRef result = activity_type.Call(args); + if (!result.exists()) { + throw Exception("HostActivity creation failed"); + } + + // If all went well, the python activity constructor should have called + // _ba.register_activity(), so we should be able to get at the same python + // activity we just instantiated through the c++ class. + if (activity->GetPyActivity() != result.get()) { + throw Exception("Error on HostActivity construction"); + } + + PyObject* obj = result.get(); + Py_INCREF(obj); + return obj; +} + +auto HostSession::RegisterPyActivity(PyObject* activity_obj) -> HostActivity* { + // The context should be pointing to an unregistered HostActivity; + // register and return it. + HostActivity* activity = Context::current().GetHostActivity(); + if (!activity) + throw Exception( + "No current activity in RegisterPyActivity; did you remember to call " + "ba.newHostActivity() to instantiate your activity?"); + activity->RegisterPyActivity(activity_obj); + return activity; +} + +void HostSession::DecrementPlayerTimeOuts(millisecs_t millisecs) { + for (auto&& i : players_) { + Player* player = i.get(); + assert(player); + if (player->time_out() < millisecs) { + std::string kick_str = + g_game->GetResourceString("kickIdlePlayersKickedText"); + Utils::StringReplaceOne(&kick_str, "${NAME}", player->GetName()); + ScreenMessage(kick_str); + RemovePlayer(player); + return; // Bail for this round since we prolly mucked with the list. + } else if (player->time_out() > BA_PLAYER_TIME_OUT_WARN + && (player->time_out() - millisecs <= BA_PLAYER_TIME_OUT_WARN)) { + std::string kick_str_1 = + g_game->GetResourceString("kickIdlePlayersWarning1Text"); + Utils::StringReplaceOne(&kick_str_1, "${NAME}", player->GetName()); + Utils::StringReplaceOne(&kick_str_1, "${COUNT}", + std::to_string(BA_PLAYER_TIME_OUT_WARN / 1000)); + ScreenMessage(kick_str_1); + ScreenMessage(g_game->GetResourceString("kickIdlePlayersWarning2Text")); + } + player->set_time_out(player->time_out() - millisecs); + } +} + +void HostSession::ProcessPlayerTimeOuts() { + millisecs_t real_time = GetRealTime(); + + if (foreground_host_activity_.exists() + && foreground_host_activity_->game_speed() > 0.0 + && !foreground_host_activity_->paused() + && foreground_host_activity_->getAllowKickIdlePlayers() + && kick_idle_players_) { + // Let's only do this every now and then. + if (real_time - last_kick_idle_players_decrement_time_ > 1000) { + DecrementPlayerTimeOuts(real_time + - last_kick_idle_players_decrement_time_); + last_kick_idle_players_decrement_time_ = real_time; + } + } else { + // If we're not kicking, we still store the latest time (so it doesnt + // accumulate for when we start again). + last_kick_idle_players_decrement_time_ = real_time; + } +} + +void HostSession::StepScene() { + // Run up our game-time timers. + sim_timers_.Run(scene()->time()); + + // And step. + scene()->Step(); +} + +void HostSession::Update(int time_advance) { + assert(InGameThread()); + + // We can be killed at any time, so let's keep an eye out for that. + WeakRef test_ref(this); + assert(test_ref.exists()); + + ProcessPlayerTimeOuts(); + + GameStream* output_stream = GetGameStream(); + + // Advance base time by the specified amount, + // stopping at all timers along the way. + millisecs_t target_base_time = base_time_ + time_advance; + while (!base_timers_.empty() + && (base_time_ + base_timers_.GetTimeToNextExpire(base_time_) + <= target_base_time)) { + base_time_ += base_timers_.GetTimeToNextExpire(base_time_); + if (output_stream) { + output_stream->SetTime(base_time_); + } + base_timers_.Run(base_time_); + } + base_time_ = target_base_time; + if (output_stream) { + output_stream->SetTime(base_time_); + } + assert(test_ref.exists()); + + // Update our activities (iterate via weak-refs as this list may change under + // us at any time). + std::vector > activities = + PointersToWeakRefs(RefsToPointers(host_activities_)); + for (auto&& i : activities) { + if (i.exists()) { + i->Update(time_advance); + assert(test_ref.exists()); + } + } + assert(test_ref.exists()); + + // Periodically prune various dead refs. + if (base_time_ > next_prune_time_) { + PruneDeadMapRefs(&textures_); + PruneDeadMapRefs(&sounds_); + PruneDeadMapRefs(&models_); + PruneDeadRefs(&python_calls_); + next_prune_time_ = base_time_ + 5000; + } + assert(test_ref.exists()); +} + +HostSession::~HostSession() { + try { + shutting_down_ = true; + + // Put the scene in shut-down mode before we start killing stuff + // (this generates warnings, suppresses messages, etc). + scene_->set_shutting_down(true); + + // Clear out all python calls registered in our context + // (should wipe out refs to our session and prevent them from running + // without a valid session context). + for (auto&& i : python_calls_) { + if (i.exists()) { + i->MarkDead(); + } + } + + // Mark all our media dead to clear it out of our output-stream cleanly. + for (auto&& i : textures_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + for (auto&& i : models_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + for (auto&& i : sounds_) { + if (i.second.exists()) { + i.second->MarkDead(); + } + } + + // Clear our timers and scene; this should wipe out any remaining refs + // to our session scene. + base_timers_.Clear(); + sim_timers_.Clear(); + scene_.Clear(); + + // Kill our python session object. + { + ScopedSetContext cp(this); + session_py_obj_.Release(); + } + + // Kill any remaining activity data. Generally all activities should die + // when the session python object goes down, but lets clean up in case any + // didn't. + for (auto&& i : host_activities_) { + ScopedSetContext cp{Object::Ref(i)}; + i.Clear(); + } + + // Report outstanding calls. There shouldn't be any at this point. Actually + // it turns out there's generally 1; whichever call was responsible for + // killing this activity will still be in progress.. so let's report on 2 or + // more I guess. +#if BA_DEBUG_BUILD + PruneDeadRefs(&python_calls_); + if (python_calls_.size() > 1) { + std::string s = "WARNING: " + std::to_string(python_calls_.size()) + + " live PythonContextCalls at shutdown for " + + "HostSession" + " (1 call is expected):"; + int count = 1; + for (auto&& i : python_calls_) { + s += ("\n " + std::to_string(count++) + ": " + + i->GetObjectDescription()); + } + Log(s); + } +#endif // BA_DEBUG_BUILD + } catch (const std::exception& e) { + Log("Exception in HostSession destructor: " + std::string(e.what())); + } +} + +void HostSession::RegisterCall(PythonContextCall* call) { + assert(call); + python_calls_.emplace_back(call); + + // If we're shutting down, just kill the call immediately. + // (we turn all of our calls to no-ops as we shut down). + if (shutting_down_) { + Log("WARNING: adding call to expired session; call will not function: " + + call->GetObjectDescription()); + call->MarkDead(); + } +} + +auto HostSession::GetUnusedPlayerName(Player* p, const std::string& base_name) + -> std::string { + // Now find the first non-taken variation. + int index = 1; + std::string name_test; + while (true) { + if (index > 1) { + name_test = base_name + " " + std::to_string(index); + } else { + name_test = base_name; + } + bool name_found = false; + for (auto&& j : players_) { + if ((j->GetName() == name_test) && (j.get() != p)) { + name_found = true; + break; + } + } + if (!name_found) break; + index += 1; + } + return name_test; +} + +void HostSession::DumpFullState(GameStream* out) { + // Add session-scene. + if (scene_.exists()) { + scene_->Dump(out); + } + + // Dump media associated with session-scene. + for (auto&& i : textures_) { + if (Texture* t = i.second.get()) { + out->AddTexture(t); + } + } + for (auto&& i : sounds_) { + if (Sound* s = i.second.get()) { + out->AddSound(s); + } + } + for (auto&& i : models_) { + if (Model* s = i.second.get()) { + out->AddModel(s); + } + } + + // Dump session-scene's nodes. + if (scene_.exists()) { + scene_->DumpNodes(out); + } + + // Now let our activities dump themselves. + for (auto&& i : host_activities_) { + i->DumpFullState(out); + } +} + +void HostSession::GetCorrectionMessages( + bool blend, std::vector >* messages) { + std::vector message; + + // Grab correction for session scene (though there shouldn't be one). + if (scene_.exists()) { + message = scene_->GetCorrectionMessage(blend); + if (message.size() > 4) { + // A correction packet of size 4 is empty; ignore it. + messages->push_back(message); + } + } + + // Now do same for activity scenes. + for (auto&& i : host_activities_) { + if (HostActivity* ha = i.get()) { + if (Scene* sg = ha->scene()) { + message = sg->GetCorrectionMessage(blend); + if (message.size() > 4) { + // A correction packet of size 4 is empty; ignore it. + messages->push_back(message); + } + } + } + } +} + +auto HostSession::NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int { + // Make sure the runnable passed in is reference-managed already + // (we may not add an initial reference ourself). + assert(runnable->is_valid_refcounted_object()); + + // We currently support game and base timers. + switch (timetype) { + case TimeType::kSim: + case TimeType::kBase: + // Game and base timers are the same thing for us. + return NewTimer(length, repeat, runnable); + default: + // Gall back to default for descriptive error otherwise. + return ContextTarget::NewTimer(timetype, length, repeat, runnable); + } +} + +void HostSession::DeleteTimer(TimeType timetype, int timer_id) { + switch (timetype) { + case TimeType::kSim: + case TimeType::kBase: + // Game and base timers are the same thing for us. + DeleteTimer(timer_id); + break; + default: + // Fall back to default for descriptive error otherwise. + ContextTarget::DeleteTimer(timetype, timer_id); + break; + } +} + +auto HostSession::GetTime(TimeType timetype) -> millisecs_t { + switch (timetype) { + case TimeType::kSim: + case TimeType::kBase: + return scene_->time(); + default: + // Fall back to default for descriptive error otherwise. + return ContextTarget::GetTime(timetype); + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/session/host_session.h b/src/ballistica/game/session/host_session.h new file mode 100644 index 00000000..812c9799 --- /dev/null +++ b/src/ballistica/game/session/host_session.h @@ -0,0 +1,131 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_SESSION_HOST_SESSION_H_ +#define BALLISTICA_GAME_SESSION_HOST_SESSION_H_ + +#include +#include +#include +#include + +#include "ballistica/core/context.h" +#include "ballistica/game/session/session.h" +#include "ballistica/generic/timer_list.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +class HostSession : public Session { + public: + explicit HostSession(PyObject* session_type_obj); + ~HostSession() override; + + // Return a borrowed python ref. + auto GetSessionPyObj() const -> PyObject* { return session_py_obj_.get(); } + + // Set focus to a Context (it must belong to this session). + void SetForegroundHostActivity(HostActivity* sgc); + auto GetSound(const std::string& name) -> Object::Ref override; + auto GetData(const std::string& name) -> Object::Ref override; + auto GetTexture(const std::string& name) -> Object::Ref override; + auto GetModel(const std::string& name) -> Object::Ref override; + + void SetKickIdlePlayers(bool enable); + + // Update the session. + void Update(int time_advance) override; + + // ContextTarget time/timer support + auto NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int override; + void DeleteTimer(TimeType timetype, int timer_id) override; + auto GetTime(TimeType timetype) -> millisecs_t override; + + // Given an activity python type, instantiate a new activity + // and return a new reference. + auto NewHostActivity(PyObject* activity_type_obj, PyObject* settings_obj) + -> PyObject*; + void DestroyHostActivity(HostActivity* a); + void RemovePlayer(Player* player); + void RequestPlayer(InputDevice* device); + + // Return either a host-activity context or the session-context. + auto GetForegroundContext() -> Context override; + auto DoesFillScreen() const -> bool override; + void Draw(FrameDef* f) override; + void ScreenSizeChanged() override; + void LanguageChanged() override; + void GraphicsQualityChanged(GraphicsQuality q) override; + void DebugSpeedMultChanged() override; + auto GetHostSession() -> HostSession* override; + auto GetMutableScene() -> Scene* override; + auto scene() -> Scene* { + assert(scene_.exists()); + return scene_.get(); + } + void RegisterCall(PythonContextCall* call); + auto GetGameStream() const -> GameStream* { return output_stream_.get(); } + auto is_main_menu() const -> bool { + return is_main_menu_; + } // fixme remove this + void DumpFullState(GameStream* out) override; + void GetCorrectionMessages(bool blend, + std::vector >* messages); + auto base_time() const -> millisecs_t { return base_time_; } + auto players() const -> const std::vector >& { + return players_; + } + + // Called by new py Session to pass themselves to us. + void RegisterPySession(PyObject* obj); + + // Called by new py Activities to pass themselves to us. + auto RegisterPyActivity(PyObject* activity_obj) -> HostActivity*; + + // New HostActivities should call this in their constructors. + void AddHostActivity(HostActivity* sgc); + + auto GetUnusedPlayerName(Player* p, const std::string& base_name) + -> std::string; + + private: + auto NewTimer(TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int; + void DeleteTimer(int timer_id); + void StepScene(); + void ProcessPlayerTimeOuts(); + void DecrementPlayerTimeOuts(millisecs_t millisecs); + void IssuePlayerLeft(Player* player); + + bool is_main_menu_; // FIXME: Remove this. + Object::Ref output_stream_; + Timer* step_scene_timer_; + millisecs_t base_time_ = 0; + TimerList sim_timers_; + TimerList base_timers_; + Object::Ref scene_; + bool shutting_down_ = false; + + // Our list of python calls created in the context of this activity. We + // clear them as we are shutting down and ensure nothing runs after that + // point. + std::list > python_calls_; + std::vector > players_; + int next_player_id_ = 0; + + // Which host-activity has focus at the moment (Players talking to it, etc). + Object::WeakRef foreground_host_activity_; + std::vector > host_activities_; + PythonRef session_py_obj_; + bool kick_idle_players_ = false; + millisecs_t last_kick_idle_players_decrement_time_; + millisecs_t next_prune_time_ = 0; + std::map > textures_; + std::map > sounds_; + std::map > datas_; + std::map > models_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_SESSION_HOST_SESSION_H_ diff --git a/src/ballistica/game/session/net_client_session.cc b/src/ballistica/game/session/net_client_session.cc new file mode 100644 index 00000000..c555cebe --- /dev/null +++ b/src/ballistica/game/session/net_client_session.cc @@ -0,0 +1,147 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/session/net_client_session.h" + +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/connection/connection_to_host.h" +#include "ballistica/media/media_server.h" + +namespace ballistica { + +NetClientSession::NetClientSession() { + // Sanity check: we should only ever be writing one replay at once. + if (g_app_globals->replay_open) { + Log("ERROR: g_replay_open true at netclient start; shouldn't happen."); + } + assert(g_media_server); + g_media_server->PushBeginWriteReplayCall(); + writing_replay_ = true; + g_app_globals->replay_open = true; +} + +NetClientSession::~NetClientSession() { + if (writing_replay_) { + // Sanity check: we should only ever be writing one replay at once. + if (!g_app_globals->replay_open) { + Log("ERROR: g_replay_open false at net-client close; shouldn't happen."); + } + g_app_globals->replay_open = false; + assert(g_media_server); + g_media_server->PushEndWriteReplayCall(); + writing_replay_ = false; + } +} + +void NetClientSession::SetConnectionToHost(ConnectionToHost* c) { + connection_to_host_ = c; +} + +void NetClientSession::OnCommandBufferUnderrun() { + // Any time we run out of data, hit the brakes on our playback speed. + // Update: maybe not. + // correction_ *= 0.99f; +} + +void NetClientSession::Update(int time_advance) { + if (shutting_down_) { + return; + } + + // Now do standard step. + ClientSession::Update(time_advance); + + // And update our timing to try and ensure we don't run out of buffer. + UpdateBuffering(); +} + +void NetClientSession::UpdateBuffering() { + // if (NetGraph *graph = g_graphics->debug_graph_1()) { + // graph->addSample(GetRealTime(), steps_on_list_); + // } + + // Keep record of the most and least amount of time we've had buffered + // recently, and slow down/speed up a bit based on that. + { + int bucket_count = static_cast(least_buffered_count_list_.size()); + + // Change bucket every g_delay_samples samples. + int bucket = (buffer_count_list_index_ / g_app_globals->delay_samples) + % bucket_count; + int bucket_iteration = + buffer_count_list_index_ % g_app_globals->delay_samples; + + // *Set* the value the first iteration in each bucket; do *min* after that. + if (bucket_iteration == 0) { + least_buffered_count_list_[bucket] = steps_on_list_; + most_buffered_count_list_[bucket] = steps_on_list_; + } else { + least_buffered_count_list_[bucket] = + std::min(least_buffered_count_list_[bucket], steps_on_list_); + most_buffered_count_list_[bucket] = + std::max(most_buffered_count_list_[bucket], steps_on_list_); + + // After the last sample in each bucket, feed the max bucket value in + // as the 'low pass' buffer-count. The low-pass curve minus our largest + // spike value should be where we want to aim for in the buffer. + if (bucket_iteration == g_app_globals->delay_samples - 1) { + float smoothing = 0.5f; + low_pass_smoothed_ = + smoothing * low_pass_smoothed_ + + (1.0f - smoothing) + * static_cast(most_buffered_count_list_[bucket]); + } + } + + // Keep track of the largest min/max difference in our sample segments. + int largest_spike = 0; + + buffer_count_list_index_++; + for (int i = 1; i < bucket_count; i++) { + int spike = most_buffered_count_list_[i] - least_buffered_count_list_[i]; + if (spike > largest_spike) { + largest_spike = spike; + } + } + + // Slowly adjust largest spike value based on the biggest in recent history. + { + float smoothing = 0.95f; + largest_spike_smoothed_ = + smoothing * largest_spike_smoothed_ + + (1.0f - smoothing) * static_cast(largest_spike); + } + + // Low pass is the most buffered data we've had in the most recent slot. + float ideal_offset = low_pass_smoothed_ - largest_spike_smoothed_ * 1.0f; + + // Any time we've got no current buffered data, slow down fast. + // (otherwise we can get stuck cruising along with no 0 buffered data and + // things get real jerky looking) + if (steps_on_list_ == 0) { + ideal_offset -= 100.0f; + } + float smoothing = 0.0f; + correction_ = smoothing * correction_ + + (1.0f - smoothing) * (1.0f + 0.002f * ideal_offset); + correction_ = std::min(1.5f, std::max(0.5f, correction_)); + // if (NetGraph *graph = g_graphics->debug_graph_2()) { + // graph->addSample(GetRealTime(), correction_); + // } + } +} +void NetClientSession::HandleSessionMessage( + const std::vector& message) { + // Do the standard thing, but also write this message straight to our replay + // stream if we have one. + ClientSession::HandleSessionMessage(message); + + if (writing_replay_) { + assert(g_media_server); + g_media_server->PushAddMessageToReplayCall(message); + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/session/net_client_session.h b/src/ballistica/game/session/net_client_session.h new file mode 100644 index 00000000..303d598a --- /dev/null +++ b/src/ballistica/game/session/net_client_session.h @@ -0,0 +1,35 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_SESSION_NET_CLIENT_SESSION_H_ +#define BALLISTICA_GAME_SESSION_NET_CLIENT_SESSION_H_ + +#include + +#include "ballistica/game/session/client_session.h" + +namespace ballistica { + +// A client-session fed by a connection to a host. +class NetClientSession : public ClientSession { + public: + NetClientSession(); + ~NetClientSession() override; + auto connection_to_host() const -> ConnectionToHost* { + return connection_to_host_.get(); + } + void SetConnectionToHost(ConnectionToHost* c); + void HandleSessionMessage(const std::vector& buffer) override; + void OnCommandBufferUnderrun() override; + + protected: + void Update(int time_advance) override; + + private: + void UpdateBuffering(); + bool writing_replay_ = false; + Object::WeakRef connection_to_host_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_SESSION_NET_CLIENT_SESSION_H_ diff --git a/src/ballistica/game/session/replay_client_session.cc b/src/ballistica/game/session/replay_client_session.cc new file mode 100644 index 00000000..f38c8362 --- /dev/null +++ b/src/ballistica/game/session/replay_client_session.cc @@ -0,0 +1,321 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/session/replay_client_session.h" + +#include +#include +#include +#include + +#include "ballistica/dynamics/material/material.h" +#include "ballistica/game/connection/connection_to_client.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/generic/huffman.h" +#include "ballistica/generic/utils.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/networking/networking.h" +#include "ballistica/platform/platform.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +auto ReplayClientSession::GetActualTimeAdvance(int advance_in) -> int { + return static_cast( + round(advance_in * pow(2.0f, g_game->replay_speed_exponent()))); +} + +ReplayClientSession::ReplayClientSession(std::string filename) + : file_name_(std::move(filename)), + file_(nullptr), + message_fetch_num_(0), + have_sent_client_message_(false) { + // take responsibility for feeding all clients to this device.. + g_game->RegisterClientController(this); + + // go ahead and just do a reset here, which will get things going.. + Reset(true); +} + +ReplayClientSession::~ReplayClientSession() { + // we no longer are responsible for feeding clients to this device.. + g_game->UnregisterClientController(this); + + if (file_) { + fclose(file_); + file_ = nullptr; + } +} + +void ReplayClientSession::OnClientConnected(ConnectionToClient* c) { + // sanity check - abort if its on either of our lists already + for (ConnectionToClient* i : connections_to_clients_) { + if (i == c) { + Log("Error: ReplayClientSession::OnClientConnected()" + " got duplicate connection"); + return; + } + } + for (ConnectionToClient* i : connections_to_clients_ignored_) { + if (i == c) { + Log("Error: ReplayClientSession::OnClientConnected()" + " got duplicate connection"); + return; + } + } + + // if we've sent *any* commands out to clients so far, we currently have to + // ignore new connections (need to rebuild state to match current session + // state) + { + connections_to_clients_.push_back(c); + + // we create a temporary output stream just for the purpose of building + // a giant session-commands message that we can send to the client + // to build its state up to where we are currently. + GameStream out(nullptr, false); + + // go ahead and dump our full state.. + DumpFullState(&out); + + // grab the message that's been built up.. + // if its not empty, send it to the client. + std::vector out_message = out.GetOutMessage(); + if (!out_message.empty()) c->SendReliableMessage(out_message); + + // also send a correction packet to sync up all our dynamics + // (technically could do this *just* for the new client) + { + std::vector > messages; + bool blend = false; + GetCorrectionMessages(blend, &messages); + + // FIXME - have to send reliably at the moment since these will most + // likely be bigger than our unreliable packet limit.. :-( + for (auto&& i : messages) { + for (auto&& j : connections_to_clients_) { + j->SendReliableMessage(i); + } + } + } + } +} + +void ReplayClientSession::OnClientDisconnected(ConnectionToClient* c) { + // search for it on either our ignored or regular lists.. + for (auto i = connections_to_clients_.begin(); + i != connections_to_clients_.end(); i++) { + if (*i == c) { + connections_to_clients_.erase(i); + return; + } + } + for (auto i = connections_to_clients_ignored_.begin(); + i != connections_to_clients_ignored_.end(); i++) { + if (*i == c) { + connections_to_clients_ignored_.erase(i); + return; + } + } + Log("Error: ReplayClientSession::OnClientDisconnected()" + " called for connection not on lists"); +} + +void ReplayClientSession::FetchMessages() { + if (!file_ || shutting_down()) { + return; + } + + // If we have no messages left, read from the file until we get some. + while (commands_.empty()) { + std::vector buffer; + uint8_t len8; + uint32_t len32; + + // read the size of the message.. + // the first byte represents the actual size if the value is < 254 + // if it is 254, the 2 bytes after it represent size + // if it is 255, the 4 bytes after it represent size + if (fread(&len8, 1, 1, file_) != 1) { + // so they know to be done when they reach the end of the command list + // (instead of just waiting for more commands) + commands_.emplace_back(1, + static_cast(SessionCommand::kEndOfFile)); + fclose(file_); + file_ = nullptr; + return; + } + if (len8 < 254) { + len32 = len8; + } else { + // pull 16 bit len.. + if (len8 == 254) { + uint16_t len16; + if (fread(&len16, 2, 1, file_) != 1) { + // so they know to be done when they reach the end of the command list + // (instead of just waiting for more commands) + commands_.emplace_back( + 1, static_cast(SessionCommand::kEndOfFile)); + fclose(file_); + file_ = nullptr; + return; + } + assert(len16 >= 254); + len32 = len16; + } else { + // pull 32 bit len... + if (fread(&len32, 4, 1, file_) != 1) { + // so they know to be done when they reach the end of the command list + // (instead of just waiting for more commands) + commands_.emplace_back( + 1, static_cast(SessionCommand::kEndOfFile)); + fclose(file_); + file_ = nullptr; + return; + } + assert(len32 > 65535); + } + } + + // read and decompress the actual message.. + BA_PRECONDITION(len32 > 0); + buffer.resize(len32); + if (fread(&(buffer[0]), len32, 1, file_) != 1) { + commands_.emplace_back(1, + static_cast(SessionCommand::kEndOfFile)); + fclose(file_); + file_ = nullptr; + return; + } + std::vector data_decompressed = + g_utils->huffman()->decompress(buffer); + HandleSessionMessage(data_decompressed); + + // Also send it to all client-connections we're attached to. + // NOTE: We currently are sending everything as reliable; we can maybe do + // unreliable for certain type of messages. Though perhaps when passing + // around replays maybe its best to keep everything intact. + have_sent_client_message_ = true; + for (auto&& i : connections_to_clients_) { + i->SendReliableMessage(data_decompressed); + } + message_fetch_num_++; + } +} + +void ReplayClientSession::Error(const std::string& description) { + // Close the replay, announce something went wrong with it, and then do + // standard error response.. + ScreenMessage(g_game->GetResourceString("replayReadErrorText"), {1, 0, 0}); + if (file_) { + fclose(file_); + file_ = nullptr; + } + ClientSession::Error(description); +} + +void ReplayClientSession::OnReset(bool rewind) { + // Handles base resetting. + ClientSession::OnReset(rewind); + + // If we've got any clients attached to us, tell them to reset as well. + for (auto&& i : connections_to_clients_) { + i->SendReliableMessage(std::vector(1, BA_MESSAGE_SESSION_RESET)); + } + + // If rewinding, pop back to the start of our file. + if (rewind) { + if (file_) { + fclose(file_); + file_ = nullptr; + } + + file_ = g_platform->FOpen(file_name_.c_str(), "rb"); + if (!file_) { + Error("can't open file for reading"); + return; + } + + // Read file ID and version to make sure we support this file. + uint32_t file_id; + if ((fread(&file_id, sizeof(file_id), 1, file_) != 1)) { + Error("error reading file_id"); + return; + } + if (file_id != kBrpFileID) { + Error("incorrect file_id"); + return; + } + + // Make sure its a compatible protocol version. + uint16_t version; + if (fread(&version, sizeof(version), 1, file_) != 1) { + Error("error reading version"); + return; + } + if (version > kProtocolVersion || version < kProtocolVersionMin) { + ScreenMessage(g_game->GetResourceString("replayVersionErrorText"), + {1, 0, 0}); + End(); + return; + } + } +} + +void ReplayClientSession::DumpFullState(GameStream* out) { + // This shouldn't actually be replay-specific. Should move this up to + // ClientSession perhaps? + + // Add all scenes. + for (auto&& i : scenes_) { + if (Scene* sg = i.get()) { + sg->Dump(out); + } + } + + // Before doing any nodes, we need to create all materials. + // (but *not* their components, which may reference the nodes that we haven't + // made yet) + for (auto&& i : materials_) { + if (Material* m = i.get()) { + out->AddMaterial(m); + } + } + + // Add all media. + for (auto&& i : textures_) { + if (Texture* t = i.get()) { + out->AddTexture(t); + } + } + for (auto&& i : models_) { + if (Model* s = i.get()) { + out->AddModel(s); + } + } + for (auto&& i : sounds_) { + if (Sound* s = i.get()) { + out->AddSound(s); + } + } + for (auto&& i : collide_models_) { + if (CollideModel* s = i.get()) { + out->AddCollideModel(s); + } + } + + // Add all scene nodes. + for (auto&& i : scenes_) { + if (Scene* sg = i.get()) { + sg->DumpNodes(out); + } + } + + // Now fill out materials since all the nodes/etc they reference exist. + for (auto&& i : materials_) { + if (Material* m = i.get()) { + m->DumpComponents(out); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/game/session/replay_client_session.h b/src/ballistica/game/session/replay_client_session.h new file mode 100644 index 00000000..c6b146b6 --- /dev/null +++ b/src/ballistica/game/session/replay_client_session.h @@ -0,0 +1,43 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_SESSION_REPLAY_CLIENT_SESSION_H_ +#define BALLISTICA_GAME_SESSION_REPLAY_CLIENT_SESSION_H_ + +#include +#include + +#include "ballistica/game/client_controller_interface.h" +#include "ballistica/game/session/client_session.h" + +namespace ballistica { + +// A client-session fed by a connection to a host. +class ReplayClientSession : public ClientSession, + public ClientControllerInterface { + public: + explicit ReplayClientSession(std::string filename); + ~ReplayClientSession() override; + void OnReset(bool rewind) override; + + // Our ClientControllerInterface implementation. + auto GetActualTimeAdvance(int advance_in) -> int override; + void OnClientConnected(ConnectionToClient* c) override; + void OnClientDisconnected(ConnectionToClient* c) override; + void DumpFullState(GameStream* out) override; + + protected: + void Error(const std::string& description) override; + void FetchMessages() override; + + private: + uint32_t message_fetch_num_; + bool have_sent_client_message_; + std::vector connections_to_clients_; + std::vector connections_to_clients_ignored_; + std::string file_name_; + FILE* file_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_SESSION_REPLAY_CLIENT_SESSION_H_ diff --git a/src/ballistica/game/session/session.cc b/src/ballistica/game/session/session.cc new file mode 100644 index 00000000..756e5d9f --- /dev/null +++ b/src/ballistica/game/session/session.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/game/session/session.h" + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/game.h" + +namespace ballistica { + +Session::Session() { + g_app_globals->session_count++; + // new sessions immediately become foreground + g_game->SetForegroundSession(this); +} + +Session::~Session() { g_app_globals->session_count--; } + +void Session::Update(int time_advance) {} + +auto Session::GetForegroundContext() -> Context { return Context(); } + +void Session::Draw(FrameDef*) {} + +void Session::ScreenSizeChanged() {} + +void Session::LanguageChanged() {} + +void Session::GraphicsQualityChanged(GraphicsQuality q) {} + +void Session::DebugSpeedMultChanged() {} + +void Session::DumpFullState(GameStream* out) { + Log("Session::DumpFullState() being called; shouldn't happen."); +} + +} // namespace ballistica diff --git a/src/ballistica/game/session/session.h b/src/ballistica/game/session/session.h new file mode 100644 index 00000000..a6e4f7ca --- /dev/null +++ b/src/ballistica/game/session/session.h @@ -0,0 +1,44 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_SESSION_SESSION_H_ +#define BALLISTICA_GAME_SESSION_SESSION_H_ + +#include "ballistica/core/context.h" +#include "ballistica/core/object.h" + +namespace ballistica { + +class Session : public ContextTarget { + public: + Session(); + ~Session() override; + + // Update the session. Should return real milliseconds until next + // update is needed. + virtual void Update(int time_advance); + + // If this returns false, the screen will be cleared as part of rendering. + virtual auto DoesFillScreen() const -> bool = 0; + + // Draw!!! + virtual void Draw(FrameDef* f); + + // Return the 'frontmost' context in the session. + // This is used for executing console command or other UI hotkeys that should + // apply to whatever the user is seeing. + virtual auto GetForegroundContext() -> Context; + virtual void ScreenSizeChanged(); + virtual void LanguageChanged(); + virtual void GraphicsQualityChanged(GraphicsQuality q); + virtual void DebugSpeedMultChanged(); + auto benchmark_type() const -> BenchmarkType { return benchmark_type_; } + void set_benchmark_type(BenchmarkType val) { benchmark_type_ = val; } + virtual void DumpFullState(GameStream* s); + + private: + BenchmarkType benchmark_type_ = BenchmarkType::kNone; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_SESSION_SESSION_H_ diff --git a/src/ballistica/graphics/area_of_interest.cc b/src/ballistica/graphics/area_of_interest.cc new file mode 100644 index 00000000..645aacc5 --- /dev/null +++ b/src/ballistica/graphics/area_of_interest.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/area_of_interest.h" + +#include "ballistica/ballistica.h" + +namespace ballistica { + +AreaOfInterest::AreaOfInterest(bool in_focus) : in_focus_(in_focus) {} + +AreaOfInterest::~AreaOfInterest() = default; + +void AreaOfInterest::SetRadius(float r_in) { + // We slightly scale this for phone situations. + float extrascale = (GetInterfaceType() == UIScale::kSmall) ? 0.85f : 1.0f; + radius_ = r_in * extrascale; +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/area_of_interest.h b/src/ballistica/graphics/area_of_interest.h new file mode 100644 index 00000000..3fd61feb --- /dev/null +++ b/src/ballistica/graphics/area_of_interest.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_AREA_OF_INTEREST_H_ +#define BALLISTICA_GRAPHICS_AREA_OF_INTEREST_H_ + +#include + +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +class AreaOfInterest { + public: + explicit AreaOfInterest(bool in_focus); + ~AreaOfInterest(); + void set_position(const Vector3f& position) { position_ = position; } + void set_velocity(const Vector3f& velocity) { velocity_ = velocity; } + auto position() const -> const Vector3f& { return position_; } + auto velocity() const -> const Vector3f& { return velocity_; } + void SetRadius(float r); + auto in_focus() const -> bool { return in_focus_; } + auto radius() const -> float { return radius_; } + + private: + Vector3f position_ = {0.0f, 0.0f, 0.0f}; + Vector3f velocity_ = {0.0f, 0.0f, 0.0f}; + float radius_ = 1.0f; + bool in_focus_ = false; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_AREA_OF_INTEREST_H_ diff --git a/src/ballistica/graphics/camera.cc b/src/ballistica/graphics/camera.cc new file mode 100644 index 00000000..4db67f21 --- /dev/null +++ b/src/ballistica/graphics/camera.cc @@ -0,0 +1,1016 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/camera.h" + +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/area_of_interest.h" +#include "ballistica/graphics/frame_def.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/render_pass.h" +#include "ballistica/graphics/vr_graphics.h" +#include "ode/ode_collision_util.h" + +namespace ballistica { + +const float kCameraOffsetX = 0.0f; +const float kCameraOffsetY = -8.3f; +const float kCameraOffsetZ = -7.4f; +const float kMaxFOV = 150.0f; +const float kPanMax = 9.0f; +const float kPanMin = -9.0f; + +Camera::Camera() + : last_mode_set_time_(GetRealTime()), + lock_panning_(IsVRMode()), + pan_speed_scale_(IsVRMode() ? 0.3f : 1.0f) {} + +Camera::~Camera() = default; + +#define DEG2RAD(a) (0.0174532925f * (a)) + +static auto DotProduct(const dVector3 v1, const dVector3 v2) -> float { + return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; +} + +static void ProjectPointOnPlane(dVector3 dst, const dVector3 p, + const dVector3 normal) { + float d; + dVector3 n; + float inv_denom; + inv_denom = 1.0F / DotProduct(normal, normal); + d = DotProduct(normal, p) * inv_denom; + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +void PerpendicularVector(dVector3 dst, const dVector3 src) { + int pos; + int i; + float minelem = 1.0f; + dVector3 tempvec; + + // Find the smallest magnitude axially aligned vector. + for (pos = 0, i = 0; i < 3; i++) { + if (std::abs(src[i]) < minelem) { + pos = i; + minelem = std::abs(src[i]); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0.0f; + tempvec[pos] = 1.0f; + + // Project the point onto the plane defined by src. + ProjectPointOnPlane(dst, tempvec, src); + + // Normalize the result. + dNormalize3(dst); +} + +static void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { + out[0][0] = + in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0]; + out[0][1] = + in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1]; + out[0][2] = + in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2]; + out[1][0] = + in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0]; + out[1][1] = + in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1]; + out[1][2] = + in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2]; + out[2][0] = + in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0]; + out[2][1] = + in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1]; + out[2][2] = + in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2]; +} + +static void Cross(const dVector3 v1, const dVector3 v2, dVector3 cross) { + cross[0] = v1[1] * v2[2] - v1[2] * v2[1]; + cross[1] = v1[2] * v2[0] - v1[0] * v2[2]; + cross[2] = v1[0] * v2[1] - v1[1] * v2[0]; +} + +static void RotatePointAroundVector(dVector3 dst, const dVector3 dir, + const dVector3 point, float degrees) { + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + dVector3 vr, vup, vf; + float rad; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector(vr, dir); + Cross(vr, vf, vup); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + memcpy(im, m, sizeof(im)); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + memset(zrot, 0, sizeof(zrot)); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; + + rad = DEG2RAD(degrees); + zrot[0][0] = cosf(rad); + zrot[0][1] = sinf(rad); + zrot[1][0] = -sinf(rad); + zrot[1][1] = cosf(rad); + + MatrixMultiply(m, zrot, tmpmat); + MatrixMultiply(tmpmat, im, rot); + + for (i = 0; i < 3; i++) { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; + } +} + +void Camera::Shake(float amount) { shake_amount_ += 0.12f * amount; } + +void Camera::UpdateManualMode() { + panning_ = orbiting_ = trucking_ = rolling_ = false; + if (!manual_) { + return; + } + if ((alt_down_ || cmd_down_) && mouse_middle_down_ && mouse_left_down_) { + trucking_ = true; + } else if (ctrl_down_ && mouse_left_down_) { + panning_ = true; + } else if ((alt_down_ || cmd_down_) && mouse_left_down_) { + orbiting_ = true; + } else if ((alt_down_ || cmd_down_) && mouse_right_down_) { + rolling_ = true; + } +} + +void Camera::UpdatePosition() { + // We re-calc our area-of-interest-points here. + area_of_interest_points_.clear(); + + // In non-manual modes, update our position and target automatically. + if (manual_) { + area_of_interest_points_.emplace_back(target_.x, target_.y, target_.z); + } else { + // Non-manual. + + // If we're orbiting, just put a single AOI point in the middle. + if (mode_ == CameraMode::kOrbit) { + target_radius_ = 11; + float dist = 28; + float dist_v = 4.5f; + float altitude = 12; + float world_offset_z = -3; + SetTarget(0, dist_v, world_offset_z); + SetPosition(dist * sinf(heading_), altitude, + dist * cosf(heading_) + world_offset_z); + area_of_interest_points_.emplace_back(target_.x, target_.y, target_.z); + + have_real_areas_of_interest_ = false; + } else { + // Follow mode. + if (explicit_bool(true)) { + float lr_jitter; + { + if (IsVRMode()) { + lr_jitter = 0.0f; + } else { + lr_jitter = + sinf(static_cast(GetRealTime()) / 108.0f) * 0.4f + + sinf(static_cast(GetRealTime()) / 268.0f) * 1.0f; + lr_jitter *= 0.05f; + } + } + + if (!smooth_next_frame_ || lock_panning_) { + pan_pos_ = 0.0f; + pan_speed_ = 0.0f; + pan_target_ = 0.0f; + } + + SetPosition(pan_pos_ + lr_jitter, 20 + 0.5f, 22); + SetTarget(0, 0, 0); // Default. + + float x_min, y_min, z_min, x_max, y_max, z_max; + + if (!areas_of_interest_.empty()) { + float angle_x_min = 0.0f, angle_x_max = 0.0f, angle_y_min = 0.0f, + angle_y_max = 0.0f; + float center_x, center_y, center_z; + + x_min = y_min = z_min = 99999; + x_max = y_max = z_max = -99999; + + // Find the center of all AOI points (clamped to our bounds plus their + // radius as a buffer) + for (auto&& i : areas_of_interest_) { + float x_clamped, y_clamped, z_clamped; + float diameter = i.radius() * 2.0f; + + if (diameter + > (area_of_interest_bounds_[3] - area_of_interest_bounds_[0])) { + x_clamped = + 0.5f + * (area_of_interest_bounds_[3] + area_of_interest_bounds_[0]); + } else { + x_clamped = + std::min(area_of_interest_bounds_[3] - i.radius(), + std::max(area_of_interest_bounds_[0] + i.radius(), + i.position().x)); + } + + if (diameter + > (area_of_interest_bounds_[4] - area_of_interest_bounds_[1])) { + y_clamped = + 0.5f + * (area_of_interest_bounds_[4] + area_of_interest_bounds_[1]); + } else { + y_clamped = + std::min(area_of_interest_bounds_[4] - i.radius(), + std::max(area_of_interest_bounds_[1] + i.radius(), + i.position().y)); + } + + if (diameter + > (area_of_interest_bounds_[5] - area_of_interest_bounds_[2])) { + z_clamped = 0.5f + * ((area_of_interest_bounds_[5] + + area_of_interest_bounds_[2])); + } else { + z_clamped = + std::min(area_of_interest_bounds_[5] - i.radius(), + std::max(area_of_interest_bounds_[2] + i.radius(), + i.position().z)); + } + + x_min = std::min(x_min, x_clamped - i.radius()); + y_min = std::min(y_min, y_clamped - i.radius()); + z_min = std::min(z_min, z_clamped - i.radius()); + x_max = std::max(x_max, x_clamped - i.radius()); + y_max = std::max(y_max, y_clamped - i.radius()); + z_max = std::max(z_max, z_clamped - i.radius()); + + x_min = std::min(x_min, x_clamped + i.radius()); + y_min = std::min(y_min, y_clamped + i.radius()); + z_min = std::min(z_min, z_clamped + i.radius()); + x_max = std::max(x_max, x_clamped + i.radius()); + y_max = std::max(y_max, y_clamped + i.radius()); + z_max = std::max(z_max, z_clamped + i.radius()); + } + + center_x = 0.5f * (x_min + x_max); + center_y = 0.5f * (y_min + y_max); + center_z = 0.5f * (z_min + z_max); + + // As a starting point, aim at the center of these. + SetTarget(center_x, center_y, center_z); + + // Ok, now have a cam position point and base target point. + // now for each point, calc its horizontal and vertical angle from the + // camera's forward vector. + Vector3f cam_forward(target_.x - position_.x, target_.y - position_.y, + target_.z - position_.z); + cam_forward.Normalize(); + Vector3f cam_side = Vector3f::Cross(cam_forward, Vector3f(0, 1, 0)); + cam_side.Normalize(); + Vector3f cam_up = Vector3f::Cross(cam_side, cam_forward); + cam_up.Normalize(); + + int num = 0; + + for (auto&& i : areas_of_interest_) { + // If this point is used for focusing, add it to that list. + if (i.in_focus()) { + // Get the AOI center point clamped to AOI bounds (not taking + // radius into account) + float x_clamped_focus = std::min( + area_of_interest_bounds_[3], + std::max(area_of_interest_bounds_[0], i.position().x)); + float y_clamped_focus = std::min( + area_of_interest_bounds_[4], + std::max(area_of_interest_bounds_[1], i.position().y)); + float z_clamped_focus = std::min( + area_of_interest_bounds_[5], + std::max(area_of_interest_bounds_[2], i.position().z)); + area_of_interest_points_.emplace_back( + x_clamped_focus, y_clamped_focus, z_clamped_focus); + } + + // Now, for camera aiming purposes, add some of their velocity and + // clamp to bounds, taking their radius into account. if our AOI + // sphere is bigger than a given dimension, center it; otherwise + // clamp to the box inset by our radius. + float x_clamped, y_clamped, z_clamped, x_mirrored_clamped; + float diameter = i.radius() * 2.0f; + + if (diameter + > (area_of_interest_bounds_[3] - area_of_interest_bounds_[0])) { + x_clamped = + 0.5f + * (area_of_interest_bounds_[3] + area_of_interest_bounds_[0]); + } else { + x_clamped = + std::min(area_of_interest_bounds_[3] - i.radius(), + std::max(area_of_interest_bounds_[0] + i.radius(), + i.position().x)); + } + + if (diameter + > (area_of_interest_bounds_[4] - area_of_interest_bounds_[1])) { + y_clamped = + 0.5f + * (area_of_interest_bounds_[4] + area_of_interest_bounds_[1]); + } else { + y_clamped = + std::min(area_of_interest_bounds_[4] - i.radius(), + std::max(area_of_interest_bounds_[1] + i.radius(), + i.position().y)); + } + + if (diameter + > (area_of_interest_bounds_[5] - area_of_interest_bounds_[2])) { + z_clamped = 0.5f + * ((area_of_interest_bounds_[5] + + area_of_interest_bounds_[2])); + } else { + z_clamped = + std::min(area_of_interest_bounds_[5] - i.radius(), + std::max(area_of_interest_bounds_[2] + i.radius(), + i.position().z)); + } + + // Let's also do a version mirrored across the camera's x coordinate + // (adding this to our tracked point set causes us zoom out instead + // of rotating generally) + float x_mirrored = position_.x - (i.position().x - position_.x); + if (diameter + > (area_of_interest_bounds_[3] - area_of_interest_bounds_[0])) { + x_mirrored_clamped = + 0.5f + * (area_of_interest_bounds_[3] + area_of_interest_bounds_[0]); + } else { + x_mirrored_clamped = + std::min(area_of_interest_bounds_[3] - i.radius(), + std::max(area_of_interest_bounds_[0] + i.radius(), + x_mirrored)); + } + + Vector3f corner_offs = (cam_side + cam_up) * i.radius(); + + for (int sample = 0; sample < 2; sample++) { + Vector3f to_point{x_clamped - position_.x, + y_clamped - position_.y, + z_clamped - position_.z}; + + // For sample 0, subtract AOI radius in camera-space x and y. + // For sample 1, add them. + // this way we should get the whole sphere. + if (sample == 0) { + to_point -= corner_offs; + } else if (sample == 1) { + to_point += corner_offs; + } else if (sample == 2) { + to_point.v[0] = x_mirrored_clamped - position_.x; + } + + to_point.Normalize(); + float up_amt = Vector3f::Dot(to_point, cam_up); + float side_amt = Vector3f::Dot(to_point, cam_side); + + // Get the vector from the cam to this point, subtract out the + // component parallel to the camera's up vector, and then measure + // the angle to the camera's forward vector. + + float angle_x, angle_y; + + if (std::abs(up_amt) < 0.001f) { + angle_y = 0.0f; + } else { + angle_y = Vector3f::Angle(to_point - cam_side * side_amt, + cam_forward); + } + if (std::abs(side_amt) < 0.001f) { + angle_x = 0.0f; + } else { + angle_x = + Vector3f::Angle(to_point - cam_up * up_amt, cam_forward); + } + if (side_amt > 0) { + angle_x *= -1; + } + if (up_amt > 0) { + angle_y *= -1; + } + if (num == 0) { + angle_x_min = angle_x_max = angle_x; + angle_y_min = angle_y_max = angle_y; + } else { + angle_x_min = std::min(angle_x_min, angle_x); + angle_x_max = std::max(angle_x_max, angle_x); + angle_y_min = std::min(angle_y_min, angle_y); + angle_y_max = std::max(angle_y_max, angle_y); + } + num++; + } + } + + float turn_angle_x = 0.5f * (angle_x_min + angle_x_max); + float turn_angle_y = 0.5f * (angle_y_min + angle_y_max); + + // Get cam target relative to the camera, rotate it on cam left/right, + // and set it. + Vector3f p(target_.x - position_.x, target_.y - position_.y, + target_.z - position_.z); + p = Matrix44fRotate(cam_up, turn_angle_x) * p; + SetTarget(position_.x + p.v[0], position_.y + p.v[1], + position_.z + p.v[2]); + + // Now the same for cam up/down. + // Note: technically we should recalc angles since we just rotated, + // but this should be close enough. + Vector3f p2(target_.x - position_.x, target_.y - position_.y, + target_.z - position_.z); + p2 = Matrix44fRotate(cam_side, -turn_angle_y) * p2; + SetTarget(position_.x + p2.v[0], position_.y + p2.v[1], + position_.z + p2.v[2]); + + field_of_view_x_ = angle_x_max - angle_x_min; + field_of_view_y_ = angle_y_max - angle_y_min; + } else { + // Look at the center of the AOI bounds. + if (area_of_interest_bounds_[0] != -9999) { + x_min = x_max = + 0.5f + * (area_of_interest_bounds_[3] + area_of_interest_bounds_[0]); + y_min = y_max = area_of_interest_bounds_[4] + + 0.5f + * (area_of_interest_bounds_[1] + - area_of_interest_bounds_[4]); + z_min = z_max = + 0.5f + * (area_of_interest_bounds_[5] + area_of_interest_bounds_[2]); + } else { + // Our default area of interest position is a bit higher + // in vr since we want to drag our UI up a bit by default. + x_min = x_max = 0.0f; + y_min = y_max = 3.0f; + z_min = z_max = -5.0f; + + // In vr mode we want or default area-of-interest to line up so that + // our fixed-overlay matrix and our regular overlay matrix come out + // the same. +#if BA_VR_BUILD + if (IsVRMode()) { + // Only apply map's X offset if camera is locked. + x_min = x_max = position_.x + + (kCameraOffsetX + + (lock_panning_ ? vr_offset_smooth_.x : 0.0f) + + vr_extra_offset_.x); + y_min = y_max = + position_.y + + (kCameraOffsetY + vr_offset_smooth_.y + vr_extra_offset_.y) + + kVRFixedOverlayOffsetY; + z_min = z_max = + position_.z + + (kCameraOffsetZ + vr_offset_smooth_.z + vr_extra_offset_.z) + + kVRFixedOverlayOffsetZ; + } +#endif + } + field_of_view_x_ = 45.0f; + field_of_view_y_ = 30.0f; + SetTarget(0.5f * (x_min + x_max), 0.5f * (y_min + y_max), + 0.5f * (z_min + z_max)); + } + + // If we don't have any focusable points, drop in a default. + if (area_of_interest_points_.empty()) { + area_of_interest_points_.emplace_back(0, 0, 0); + have_real_areas_of_interest_ = false; + } else { + have_real_areas_of_interest_ = true; + } + pan_target_ = (x_max + x_min) / 2; + if (pan_target_ > kPanMax) { + pan_target_ = kPanMax; + } else if (pan_target_ < kPanMin) { + pan_target_ = kPanMin; + } + } + } + } + + // If they're on manual, we don't do smoothing or anything fancy. + if (manual_) { + target_.x = target_smoothed_.x = target_.x; + target_.y = target_smoothed_.y = target_.y; + target_.z = target_smoothed_.z = target_.z; + smooth_speed_ = {0.0f, 0.0f, 0.0f}; + smooth_next_frame_ = false; + } else { + if (mode_ == CameraMode::kFollow) { + // Useful to test camera. + if (explicit_bool(false)) { + field_of_view_x_smoothed_ = field_of_view_x_; + field_of_view_y_smoothed_ = field_of_view_y_; + target_smoothed_.x = target_.x; + target_smoothed_.y = target_.y; + target_smoothed_.z = target_.z; + pan_pos_ = pan_target_; + xy_constrain_blend_ = x_constrained_ ? 1.0f : 0.0f; + } + } else { + float dx = target_smoothed_.x - position_.x; + float dy = target_smoothed_.y - position_.y; + float dz = target_smoothed_.z - position_.z; + float target_dist = sqrtf(dx * dx + dy * dy + dz * dz); + + // If we're not smoothing this upcoming frame, snap this value. + if (!smooth_next_frame_) target_radius_smoothed_ = target_radius_; + + float angle = tanf(target_radius_smoothed_ / target_dist); + field_of_view_x_ = 0.001f; // Always want y to be the constrained one. + field_of_view_y_ = (2 * 360 * (angle / (2 * 3.1415f))); + } + } + + // Extra cam-space tweakage (via accelerometer if available). + { + Vector3f to_cam(target_smoothed_.x - position_.x, + target_smoothed_.y - position_.y, + target_smoothed_.z - position_.z); + to_cam.Normalize(); + Vector3f cam_space_lr = Vector3f::Cross(to_cam, Vector3f(0, 1, 0)); + Vector3f cam_space_ud = Vector3f::Cross(cam_space_lr, to_cam); + Vector3f tilt = 0.1f * g_graphics->tilt(); + if (manual_) { + tilt.x = 0.0f; + tilt.y = 0.0f; + } + extra_pos_ = -0.1f * tilt.y * cam_space_lr + 0.1f * tilt.x * cam_space_ud; + extra_pos_2_ = extra_pos_; + extra_pos_2_ += 0.35f * tilt.y * cam_space_lr; + extra_pos_2_ -= 0.35f * tilt.x * cam_space_ud; + up_ = cam_space_ud; + + // A tiny bit of random jitter to our camera pos. + if (!manual_) { + float mag = 2.0f; + extra_pos_2_.x += mag * position_offset_smoothed_.x; + extra_pos_2_.y += mag * position_offset_smoothed_.y; + extra_pos_2_.z += mag * position_offset_smoothed_.z; + } + } +} + +void Camera::Update(millisecs_t elapsed) { + float rand_component = 0.000005f; + float zoom_speed = 0.001f; + float fov_speed_out = 0.0025f; + float fov_speed_in = 0.001f; + float speed = 0.000012f; + float speed_2 = 0.00005f; + float damping = 0.006f; + float damping2 = 0.006f; + float xy_blend_speed = 0.0002f; + millisecs_t real_time = GetRealTime(); + + // Prevent camera "explosions" if we've been unable to update for a while. + elapsed = std::min(millisecs_t{100}, elapsed); + + // In normal mode we orbit; in vr mode we don't. + if (IsVRMode()) { + heading_ = -0.3f; + } else { + heading_ += static_cast(elapsed) / 10000.0f; + } + + int rand_incr_1 = 309; + int rand_incr_2 = 273; + int rand_incr_3 = 247; + + if (mode_ == CameraMode::kOrbit) { + rand_component *= 2.5f; + rand_incr_1 /= 2; + rand_incr_2 /= 2; + rand_incr_3 /= 2; + } + + target_radius_smoothed_ += + elapsed * (target_radius_ - target_radius_smoothed_) * zoom_speed; + + float diff = field_of_view_x_ - field_of_view_x_smoothed_; + field_of_view_x_smoothed_ += + elapsed * diff * (diff > 0.0f ? fov_speed_out : fov_speed_in); + + diff = field_of_view_y_ - field_of_view_y_smoothed_; + field_of_view_y_smoothed_ += + elapsed * diff * (diff > 0.0f ? fov_speed_out : fov_speed_in); + + if (x_constrained_) { + xy_constrain_blend_ += + elapsed * (1.0f - xy_constrain_blend_) * xy_blend_speed; + xy_constrain_blend_ = std::min(1.0f, xy_constrain_blend_); + } else { + xy_constrain_blend_ += + elapsed * (0.0f - xy_constrain_blend_) * xy_blend_speed * elapsed; + xy_constrain_blend_ = std::max(0.0f, xy_constrain_blend_); + } + + if (!IsVRMode()) { + smooth_speed_.x += elapsed * rand_component + * (-0.5f + + Utils::precalc_rands_1[(real_time / rand_incr_1) + % kPrecalcRandsCount]); + smooth_speed_.y += elapsed * rand_component + * (-0.5f + + Utils::precalc_rands_2[(real_time / rand_incr_2) + % kPrecalcRandsCount]); + smooth_speed_.z += elapsed * rand_component + * (-0.5f + + Utils::precalc_rands_3[(real_time / rand_incr_3) + % kPrecalcRandsCount]); + } + + if (RandomFloat() < 0.1f && !IsVRMode()) { + smooth_speed_2_.x += + elapsed * rand_component * 4.0f * (-0.5f + RandomFloat()); + smooth_speed_2_.y += + elapsed * rand_component * 4.0f * (-0.5f + RandomFloat()); + smooth_speed_2_.z += + elapsed * rand_component * 4.0f * (-0.5f + RandomFloat()); + } + + // If we have no important areas of interest, keep our camera from moving too + // fast. + if (!have_real_areas_of_interest_) { + speed *= 0.5f; + } + + for (millisecs_t i = 0; i < elapsed; i++) { + { + float smoothing = 0.8f; + float inv_smoothing = 1.0f - smoothing; + vr_offset_smooth_.x = + smoothing * vr_offset_smooth_.x + inv_smoothing * vr_offset_.x; + vr_offset_smooth_.y = + smoothing * vr_offset_smooth_.y + inv_smoothing * vr_offset_.y; + vr_offset_smooth_.z = + smoothing * vr_offset_smooth_.z + inv_smoothing * vr_offset_.z; + } + smooth_speed_ += (target_ - target_smoothed_) * speed; + smooth_speed_ *= (1.0f - damping); + smooth_speed_2_ += (-position_offset_smoothed_) * speed_2; + smooth_speed_2_ *= (1.0f - damping2); + target_smoothed_ += smooth_speed_; + position_offset_smoothed_ += smooth_speed_2_; + + pan_speed_ += 0.00004f * pan_speed_scale_ * (pan_target_ - position_.x); + pan_speed_ *= 0.97f; + if (position_.x > kPanMax) pan_speed_ -= (position_.x - kPanMax) * 0.00003f; + if (position_.x < kPanMin) pan_speed_ -= (position_.x - kPanMin) * 0.00003f; + pan_pos_ += pan_speed_; + + int iterations = 1; + + // Jostle the camera occasionally if we're shaking. + if (i % iterations == 0 && shake_amount_ > 0.0001f) { + shake_amount_ *= 0.97f; + shake_vel_.x += 0.05f * shake_amount_ + * (0.5f + - Utils::precalc_rands_1[real_time % 122 * i + % kPrecalcRandsCount]); + shake_vel_.y += 0.05f * shake_amount_ + * (0.5f + - Utils::precalc_rands_2[real_time % 323 * i + % kPrecalcRandsCount]); + shake_vel_.z += + 0.05f * shake_amount_ + * (0.5f + - Utils::precalc_rands_3[real_time % 76 * i % kPrecalcRandsCount]); + } + + for (int j = 0; j < iterations; j++) { + shake_pos_ += shake_vel_; + shake_vel_ += -0.001f * shake_pos_; + shake_vel_ *= 0.99f; + } + + if (g_graphics->camera_shake_disabled()) { + shake_vel_ = {0, 0, 0}; + } + } + + // Update audio position more often in vr since we can whip our head around. + uint32_t interval = IsVRMode() ? 50 : 100; + + // Every now and then, update microphone position for audio. + if (real_time - last_listener_update_time_ > interval) { + last_listener_update_time_ = real_time; + bool do_regular_update = true; + if (IsVRMode()) { +#if BA_VR_MODE + VRGraphics* vrgraphics = VRGraphics::get(); + do_regular_update = false; + Vector3f listener_pos = vrgraphics->vr_head_translate() + + vrgraphics->vr_head_forward() * 5.0f; + assert(g_audio_server); + g_audio->SetListenerPosition(listener_pos); + g_audio->SetListenerOrientation(vrgraphics->vr_head_forward(), + vrgraphics->vr_head_up()); +#endif + } + if (explicit_bool(do_regular_update)) { + float to_target = 0.5f; + Vector3f listener_pos( + position_.x + to_target * (target_smoothed_.x - position_.x), + position_.y + to_target * (target_smoothed_.y - position_.y), + position_.z + to_target * (target_smoothed_.z - position_.z)); + assert(g_audio_server); + g_audio->SetListenerPosition(listener_pos); + } + } +} + +void Camera::SetPosition(float x, float y, float z) { + position_.x = x; + position_.y = y; + position_.z = z; +} + +void Camera::SetTarget(float x, float y, float z) { + target_.x = x; + target_.y = y; + target_.z = z; +} + +void Camera::ManualHandleMouseWheel(float value) { + if (!manual_) { + return; + } + + // Make this tiny so that Y is always the constraint. + field_of_view_x_ = 0.1f; + field_of_view_y_ *= (1.0f - 0.1f * value); + if (field_of_view_y_ > kMaxFOV) { + field_of_view_y_ = kMaxFOV; + } else if (field_of_view_y_ < 1.0f) { + field_of_view_y_ = 1.0f; + } +} + +void Camera::ManualHandleMouseMove(float move_h, float move_v) { + if (!manual_) return; + + if (panning_ || trucking_ || orbiting_ || rolling_) { + // get cam vector + dVector3 cam_vec = {target_.x - position_.x, target_.y - position_.y, + target_.z - position_.z}; + float len = dVector3Length(cam_vec); + dNormalize3(cam_vec); + + float fov_width = + 2 * (len * tanf(((field_of_view_y_) / 2) * 0.0174532925f)); + + // get cam side vector + dVector3 up = {0, 1, 0}; + dVector3 side_vec; + dVector3Cross(up, cam_vec, side_vec); + dNormalize3(side_vec); + + // get cam's up vector + dVector3 cam_up; + dVector3Cross(side_vec, cam_vec, cam_up); + dNormalize3(cam_up); + + if (panning_) { + move_h *= fov_width; + move_v *= fov_width; + side_vec[0] *= move_h; + side_vec[1] *= move_h; + side_vec[2] *= move_h; + cam_up[0] *= move_v; + cam_up[1] *= move_v; + cam_up[2] *= move_v; + + position_.x += side_vec[0] + cam_up[0]; + position_.y += side_vec[1] + cam_up[1]; + position_.z += side_vec[2] + cam_up[2]; + target_.x += side_vec[0] + cam_up[0]; + target_.y += side_vec[1] + cam_up[1]; + target_.z += side_vec[2] + cam_up[2]; + } else if (orbiting_) { + dVector3 cam_pos = {position_.x - target_.x, position_.y - target_.y, + position_.z - target_.z}; + RotatePointAroundVector(cam_pos, side_vec, cam_pos, move_v * -100); + RotatePointAroundVector(cam_pos, up, cam_pos, move_h * -100); + position_.x = cam_pos[0] + target_.x; + position_.y = cam_pos[1] + target_.y; + position_.z = cam_pos[2] + target_.z; + + } else if (rolling_) { + // _roll += (move_h + move_v) * 100.0f; + } else if (trucking_) { + cam_vec[0] *= (move_h + move_v) * len; + cam_vec[1] *= (move_h + move_v) * len; + cam_vec[2] *= (move_h + move_v) * len; + position_.x += cam_vec[0]; + position_.y += cam_vec[1]; + position_.z += cam_vec[2]; + } + } +} + +auto Camera::NewAreaOfInterest(bool in_focus) -> AreaOfInterest* { + assert(InGameThread()); + areas_of_interest_.emplace_back(in_focus); + return &areas_of_interest_.back(); +} + +void Camera::DeleteAreaOfInterest(AreaOfInterest* a) { + assert(InGameThread()); + for (auto i = areas_of_interest_.begin(); i != areas_of_interest_.end(); + ++i) { + if (&(*i) == a) { + areas_of_interest_.erase(i); + return; + } + } + throw Exception("Area-of-interest not found"); +} + +void Camera::SetManual(bool enable) { + manual_ = enable; + if (manual_) { + // Reset our target settings to our current smoothed ones + // so we don't see an instant jump to the target. + target_.x = target_smoothed_.x; + target_.y = target_smoothed_.y; + target_.z = target_smoothed_.z; + } else { + smooth_next_frame_ = false; + } +} + +void Camera::SetMode(CameraMode m) { + if (mode_ != m) { + mode_ = m; + smooth_next_frame_ = false; + last_mode_set_time_ = GetRealTime(); + heading_ = kInitialHeading; + } +} + +void Camera::ApplyToFrameDef(FrameDef* frame_def) { + frame_def->set_camera_mode(mode_); + + // FIXME - we should have some sort of support + // for multiple cameras each with their own pass... + // for now, though, there's just a single beauty pass + // which is us + + RenderPass* passes[] = { + frame_def->beauty_pass(), + frame_def->beauty_pass_bg(), +#if BA_VR_BUILD + frame_def->overlay_pass(), + frame_def->GetOverlayFixedPass(), + frame_def->vr_cover_pass(), +#endif + frame_def->overlay_3d_pass(), + frame_def->blit_pass(), + nullptr + }; + + // Currently our x/y fovs are simply enough to fit everything. + // Check the aspect ratio of what we're rendering to and fit them. + + // Add a few degrees just to keep things away from the edges a bit + // since we have various UI elements there. + float extra = 0.0f; + + // If we don't want to smooth this frame, snap these values. + if (!smooth_next_frame_) { + field_of_view_x_smoothed_ = field_of_view_x_; + field_of_view_y_smoothed_ = field_of_view_y_; + } + + float final_fov_y = field_of_view_y_smoothed_ + extra; + if (final_fov_y < 1.0f) { + final_fov_y = 1.0f; + } else if (final_fov_y > 120.0f) { + final_fov_y = 120.0f; + } + float final_fov_x = field_of_view_x_smoothed_ + extra; + if (final_fov_x < 1.0f) { + final_fov_x = 1.0f; + } else if (final_fov_x > 120.0f) { + final_fov_x = 120.0f; + } + float ratio = final_fov_x / final_fov_y; + + // Need to look at a pass to know if we're x or y constrained. + float render_ratio = passes[0]->GetPhysicalAspectRatio(); + + // Update whether we're x-constrained or not. + x_constrained_ = (ratio >= render_ratio); + + // When we're x-constrained, we calc y so that x fits. + float final_fov_y2 = final_fov_x / render_ratio; + + // If we're not smoothing this frame, snap immediately. + if (!smooth_next_frame_) xy_constrain_blend_ = x_constrained_ ? 1.0f : 0.0f; + + // We smoothly blend between our x-constrained and non-x-constrained y values + // so that we don't see a hitch when it switches. + final_fov_y = xy_constrain_blend_ * final_fov_y2 + + (1.0f - xy_constrain_blend_) * final_fov_y; + + final_fov_y = std::max(5.0f, final_fov_y); + + // Reset some last things if we're non-smoothed. + if (!smooth_next_frame_) { + smooth_speed_ = {0.0f, 0.0f, 0.0f}; + shake_amount_ = 0; + shake_pos_ = {0.0f, 0.0f, 0.0f}; + shake_vel_ = {0.0f, 0.0f, 0.0f}; + target_smoothed_ = target_; + up_.x = 0.0f; + up_.y = 1.0f; + up_.z = 0.0f; + vr_offset_smooth_ = vr_offset_; + } + + // Also store original positions with the frame_def in case we want to muck + // with them later (VR, etc). + frame_def->set_cam_original(Vector3f(position_.x + extra_pos_2_.x, + position_.y + extra_pos_2_.y, + position_.z + extra_pos_2_.z)); + + // If we're vr, apply current vr offsets. + if (IsVRMode()) { + if (mode_ == CameraMode::kFollow) { + Vector3f cam_original = frame_def->cam_original(); + + // Only apply map's X offset if our camera is locked. + cam_original.x += kCameraOffsetX + + (lock_panning_ ? vr_offset_smooth_.x : 0.0f) + + vr_extra_offset_.x; + cam_original.y += + kCameraOffsetY + vr_offset_smooth_.y + vr_extra_offset_.y; + cam_original.z += + kCameraOffsetZ + vr_offset_smooth_.z + vr_extra_offset_.z; + frame_def->set_cam_original(cam_original); + } else { + Vector3f cam_original = frame_def->cam_original(); + cam_original.y += 3.0f; + frame_def->set_cam_original(cam_original); + } + } + frame_def->set_cam_target_original(target_smoothed_); + frame_def->set_shake_original(shake_pos_); + + for (RenderPass** p = passes; *p != nullptr; p++) { + assert(!area_of_interest_points_.empty()); + (**p).SetCamera( + position_ + extra_pos_2_, target_smoothed_ + shake_pos_ + extra_pos_, + up_, 4, 1000.0f, + -1.0f, // Auto x fov. + final_fov_y * (g_graphics->tv_border() ? (1.0f + kTVBorder) : 1.0f), + false, 0, 0, 0, 0, // Not using tangent fovs. + area_of_interest_points_); + } + smooth_next_frame_ = true; +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/camera.h b/src/ballistica/graphics/camera.h new file mode 100644 index 00000000..bd0dffdc --- /dev/null +++ b/src/ballistica/graphics/camera.h @@ -0,0 +1,152 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_CAMERA_H_ +#define BALLISTICA_GRAPHICS_CAMERA_H_ + +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +// Hmm this shouldn't be here. +const float kHappyThoughtsZPlane = -5.52f; + +// Default horizontal camera field of view. +const float kCameraFOVY = 60.0f; +const float kInitialHeading = -1.0f; + +// FIXME: looks like this guy gets accessed from a few different threads. +class Camera : public Object { + public: + Camera(); + ~Camera() override; + void Shake(float amount); + void SetManual(bool enable); + auto manual() const -> bool { return manual_; } + void ManualHandleMouseMove(float move_h, float move_v); + void ManualHandleMouseWheel(float val); + + // Update the camera position values - done once per render + void UpdatePosition(); + + // Update camera velocities/etc - done as often as possible. + void Update(millisecs_t elapsed); + void SetPosition(float x, float y, float z); + void SetTarget(float x, float y, float z); + void SetMode(CameraMode m); + void set_area_of_interest_bounds(float min_x, float min_y, float min_z, + float max_x, float max_y, float max_z) { + area_of_interest_bounds_[0] = min_x; + area_of_interest_bounds_[1] = min_y; + area_of_interest_bounds_[2] = min_z; + area_of_interest_bounds_[3] = max_x; + area_of_interest_bounds_[4] = max_y; + area_of_interest_bounds_[5] = max_z; + } + void area_of_interest_bounds(float* min_x, float* min_y, float* min_z, + float* max_x, float* max_y, float* max_z) { + *min_x = area_of_interest_bounds_[0]; + *min_y = area_of_interest_bounds_[1]; + *min_z = area_of_interest_bounds_[2]; + *max_x = area_of_interest_bounds_[3]; + *max_y = area_of_interest_bounds_[4]; + *max_z = area_of_interest_bounds_[5]; + } + void UpdateManualMode(); + + // Sets up the render in the passes we're associated with. Call this anytime + // during a render. + void ApplyToFrameDef(FrameDef* frame_def); + auto field_of_view_y() const -> float { return field_of_view_y_; } + void get_position(float* x, float* y, float* z) const { + *x = position_.x; + *y = position_.y; + *z = position_.z; + } + void target_smoothed(float* x, float* y, float* z) const { + *x = target_smoothed_.x; + *y = target_smoothed_.y; + *z = target_smoothed_.z; + } + void set_alt_down(bool d) { alt_down_ = d; } + void set_cmd_down(bool d) { cmd_down_ = d; } + void set_ctrl_down(bool d) { ctrl_down_ = d; } + void set_mouse_left_down(bool d) { mouse_left_down_ = d; } + void set_mouse_right_down(bool d) { mouse_right_down_ = d; } + void set_mouse_middle_down(bool d) { mouse_middle_down_ = d; } + void set_happy_thoughts_mode(bool h) { happy_thoughts_mode_ = h; } + auto happy_thoughts_mode() const -> bool { return happy_thoughts_mode_; } + auto NewAreaOfInterest(bool inFocus = true) -> AreaOfInterest*; + void DeleteAreaOfInterest(AreaOfInterest* a); + auto mode() const -> CameraMode { return mode_; } + void set_vr_offset(const Vector3f& val) { vr_offset_ = val; } + void set_vr_extra_offset(const Vector3f& val) { vr_extra_offset_ = val; } + auto vr_extra_offset() const -> const Vector3f& { return vr_extra_offset_; } + void set_lock_panning(bool val) { lock_panning_ = val; } + auto lock_panning() const -> bool { return lock_panning_; } + auto pan_speed_scale() const -> float { return pan_speed_scale_; } + void set_pan_speed_scale(float val) { pan_speed_scale_ = val; } + + private: + float pan_speed_scale_{1.0f}; + bool lock_panning_{}; + Vector3f vr_offset_{0.0f, 0.0f, 0.0f}; + Vector3f vr_extra_offset_{0.0f, 0.0f, 0.0f}; + Vector3f vr_offset_smooth_{0.0f, 0.0f, 0.0f}; + millisecs_t last_mode_set_time_{}; + std::list areas_of_interest_; + CameraMode mode_{CameraMode::kFollow}; + bool manual_{}; + bool smooth_next_frame_{}; + bool have_real_areas_of_interest_{}; + + // Manual stuff. + bool panning_{}; + bool orbiting_{}; + bool rolling_{}; + bool trucking_{}; + bool alt_down_{}; + bool cmd_down_{}; + bool ctrl_down_{}; + bool mouse_left_down_{}; + bool mouse_middle_down_{}; + bool mouse_right_down_{}; + float heading_{kInitialHeading}; + Vector3f extra_pos_{0.0f, 0.0f, 0.0f}; + Vector3f extra_pos_2_{0.0f, 0.0f, 0.0f}; + float area_of_interest_bounds_[6]{-9999, -9999, -9999, 9999, 9999, 9999}; + float pan_pos_{}; + float pan_speed_{}; + float pan_target_{}; + float shake_amount_{}; + Vector3f shake_pos_{0.0f, 0.0f, 0.0f}; + Vector3f shake_vel_{0.0f, 0.0f, 0.0f}; + Vector3f position_{0.0f, 1.0f, -1.0f}; + Vector3f target_{0.0f, 1.0f, -1.0f}; + Vector3f target_smoothed_{0.0f, 0.0f, 0.0f}; + Vector3f position_offset_smoothed_{0.0f, 0.0f, 0.0f}; + Vector3f smooth_speed_{0.0f, 0.0f, 0.0f}; + Vector3f smooth_speed_2_{0.0f, 0.0f, 0.0f}; + float target_radius_{2.0f}; + float target_radius_smoothed_{2.0f}; + float field_of_view_x_{5.0f}; + float field_of_view_y_{kCameraFOVY}; + float field_of_view_x_smoothed_{1.0f}; + float field_of_view_y_smoothed_{1.0f}; + millisecs_t last_listener_update_time_{}; + bool happy_thoughts_mode_{}; + float min_target_radius_{5.0f}; + Vector3f up_{0.0f, 1.0f, 0.0f}; + float area_of_interest_near_{1.0f}; + float area_of_interest_far_{2.0f}; + bool x_constrained_{true}; + float xy_constrain_blend_{0.5f}; + std::vector area_of_interest_points_{{0.0f, 0.0f, 0.0f}}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_CAMERA_H_ diff --git a/src/ballistica/graphics/component/empty_component.h b/src/ballistica/graphics/component/empty_component.h new file mode 100644 index 00000000..3b70970a --- /dev/null +++ b/src/ballistica/graphics/component/empty_component.h @@ -0,0 +1,30 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_EMPTY_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_EMPTY_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +// Empty component - has no shader but can be useful for spitting out +// transform/scissor/etc state changes. +class EmptyComponent : public RenderComponent { + public: + explicit EmptyComponent(RenderPass* pass) + : RenderComponent(pass), transparent_(false) {} + void SetTransparent(bool val) { + EnsureConfiguring(); + transparent_ = val; + } + + protected: + void WriteConfig() override { ConfigForEmpty(transparent_); } + + private: + bool transparent_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_EMPTY_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/object_component.cc b/src/ballistica/graphics/component/object_component.cc new file mode 100644 index 00000000..ce333d5e --- /dev/null +++ b/src/ballistica/graphics/component/object_component.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/object_component.h" + +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +void ObjectComponent::WriteConfig() { + // If they didn't give us a texture, just use a blank white texture. + // This is not a common case and easier than forking all our shaders to + // create non-textured versions. + if (!texture_.exists()) { + texture_ = g_media->GetTexture(SystemTextureID::kWhite); + } + if (reflection_ == ReflectionType::kNone) { + assert(!double_sided_); // Unsupported combo. + assert(!colorize_texture_.exists()); // Unsupported combo. + assert(!have_color_add_); // Unsupported combo. + if (light_shadow_ == LightShadowType::kNone) { + if (transparent_) { + ConfigForShading(ShadingType::kObjectTransparent); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + cmd_buffer_->PutTexture(texture_); + } else { + ConfigForShading(ShadingType::kObject); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_); + cmd_buffer_->PutTexture(texture_); + } + } else { + if (transparent_) { + assert(!world_space_); // Unsupported combo. + ConfigForShading(ShadingType::kObjectLightShadowTransparent); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + cmd_buffer_->PutTexture(texture_); + } else { + ConfigForShading(ShadingType::kObjectLightShadow); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutInt(world_space_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_); + cmd_buffer_->PutTexture(texture_); + } + } + } else { + if (light_shadow_ == LightShadowType::kNone) { + assert(!double_sided_); // Unsupported combo. + assert(!colorize_texture_.exists()); // Unsupported combo. + if (transparent_) { + assert(!world_space_); // Unsupported combo. + if (have_color_add_) { + ConfigForShading(ShadingType::kObjectReflectAddTransparent); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + color_add_r_, color_add_g_, color_add_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + cmd_buffer_->PutTexture(texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } else { + ConfigForShading(ShadingType::kObjectReflectTransparent); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + cmd_buffer_->PutTexture(texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } + } else { + ConfigForShading(ShadingType::kObjectReflect); + cmd_buffer_->PutInt(world_space_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + cmd_buffer_->PutTexture(texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } + } else { + // With add. + assert(!transparent_); // Unsupported combo. + if (!have_color_add_) { + if (colorize_texture_.exists()) { + assert(!double_sided_); // Unsupported combo. + assert(!world_space_); // Unsupported combo. + if (do_colorize_2_) { + ConfigForShading(ShadingType::kObjectReflectLightShadowColorized2); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutFloats( + color_r_, color_g_, color_b_, reflection_scale_r_, + reflection_scale_g_, reflection_scale_b_, colorize_color_r_, + colorize_color_g_, colorize_color_b_, colorize_color2_r_, + colorize_color2_g_, colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } else { + ConfigForShading(ShadingType::kObjectReflectLightShadowColorized); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_, colorize_color_r_, + colorize_color_g_, colorize_color_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } + } else { + if (double_sided_) { + ConfigForShading(ShadingType::kObjectReflectLightShadowDoubleSided); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutInt(world_space_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + cmd_buffer_->PutTexture(texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } else { + ConfigForShading(ShadingType::kObjectReflectLightShadow); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutInt(world_space_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + cmd_buffer_->PutTexture(texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } + } + } else { + assert(!double_sided_); // Unsupported combo. + assert(!world_space_); // Unsupported config. + if (colorize_texture_.exists()) { + if (do_colorize_2_) { + ConfigForShading( + ShadingType::kObjectReflectLightShadowAddColorized2); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutFloats( + color_r_, color_g_, color_b_, color_add_r_, color_add_g_, + color_add_b_, reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_, colorize_color_r_, colorize_color_g_, + colorize_color_b_, colorize_color2_r_, colorize_color2_g_, + colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } else { + ConfigForShading( + ShadingType::kObjectReflectLightShadowAddColorized); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_add_r_, + color_add_g_, color_add_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_, colorize_color_r_, + colorize_color_g_, colorize_color_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } + } else { + ConfigForShading(ShadingType::kObjectReflectLightShadowAdd); + cmd_buffer_->PutInt(static_cast(light_shadow_)); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_add_r_, + color_add_g_, color_add_b_, + reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + cmd_buffer_->PutTexture(texture_); + SystemCubeMapTextureID r = + Graphics::CubeMapFromReflectionType(reflection_); + cmd_buffer_->PutCubeMapTexture(g_media->GetCubeMapTexture(r)); + } + } + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/object_component.h b/src/ballistica/graphics/component/object_component.h new file mode 100644 index 00000000..bd0a2165 --- /dev/null +++ b/src/ballistica/graphics/component/object_component.h @@ -0,0 +1,166 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_OBJECT_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_OBJECT_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +class ObjectComponent : public RenderComponent { + public: + explicit ObjectComponent(RenderPass* pass) : RenderComponent(pass) {} + + void SetTexture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + texture_ = t_in->texture_data(); + } else { + texture_.Clear(); + } + } + + void SetTexture(TextureData* t) { + EnsureConfiguring(); + texture_ = t; + } + + void SetColorizeTexture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + colorize_texture_ = t_in->texture_data(); + } else { + colorize_texture_.Clear(); + } + } + + void SetColorizeTexture(TextureData* t) { + EnsureConfiguring(); + colorize_texture_ = t; + } + + void SetDoubleSided(bool enable) { + EnsureConfiguring(); + double_sided_ = enable; + } + + void SetReflection(ReflectionType r) { + EnsureConfiguring(); + reflection_ = r; + } + + void SetReflectionScale(float r, float g, float b) { + EnsureConfiguring(); + reflection_scale_r_ = r; + reflection_scale_g_ = g; + reflection_scale_b_ = b; + } + + void SetPremultiplied(bool val) { + EnsureConfiguring(); + premultiplied_ = val; + } + + void SetTransparent(bool val) { + EnsureConfiguring(); + transparent_ = val; + } + + void SetColor(float r, float g, float b, float a = 1.0f) { + // We support fast inline color changes with drawing streams. + // (avoids having to re-send a whole configure for every color change) + if (state_ == State::kDrawing) { + cmd_buffer_->PutCommand( + RenderCommandBuffer::Command::kObjectComponentInlineColor); + cmd_buffer_->PutFloats(r, g, b, a); + } else { + EnsureConfiguring(); + } + color_r_ = r; + color_g_ = g; + color_b_ = b; + color_a_ = a; + } + + void SetColorizeColor(float r, float g, float b, float a = 1.0f) { + EnsureConfiguring(); + colorize_color_r_ = r; + colorize_color_g_ = g; + colorize_color_b_ = b; + colorize_color_a_ = a; + } + + void SetColorizeColor2(float r, float g, float b, float a = 1.0f) { + EnsureConfiguring(); + colorize_color2_r_ = r; + colorize_color2_g_ = g; + colorize_color2_b_ = b; + colorize_color2_a_ = a; + do_colorize_2_ = true; + } + + void SetAddColor(float r, float g, float b) { + // We support fast inline add-color changes with drawing streams + // (avoids having to re-send a whole configure for every change). + // Make sure to only allow this if we have an add color already; + // otherwise we need to config since we might be switching shaders. + if (state_ == State::kDrawing && have_color_add_) { + cmd_buffer_->PutCommand( + RenderCommandBuffer::Command::kObjectComponentInlineAddColor); + cmd_buffer_->PutFloats(r, g, b); + } else { + EnsureConfiguring(); + } + color_add_r_ = r; + color_add_g_ = g; + color_add_b_ = b; + have_color_add_ = true; + } + + void SetLightShadow(LightShadowType t) { + EnsureConfiguring(); + light_shadow_ = t; + } + + void SetWorldSpace(bool w) { + EnsureConfiguring(); + world_space_ = w; + } + + protected: + void WriteConfig() override; + + protected: + float color_r_{1.0f}; + float color_g_{1.0f}; + float color_b_{1.0f}; + float color_a_{1.0f}; + float colorize_color_r_{1.0f}; + float colorize_color_g_{1.0f}; + float colorize_color_b_{1.0f}; + float colorize_color_a_{1.0f}; + float colorize_color2_r_{}; + float colorize_color2_g_{}; + float colorize_color2_b_{}; + float colorize_color2_a_{}; + float color_add_r_{}; + float color_add_g_{}; + float color_add_b_{}; + float reflection_scale_r_{1.0f}; + float reflection_scale_g_{1.0f}; + float reflection_scale_b_{1.0f}; + Object::Ref texture_; + Object::Ref colorize_texture_; + ReflectionType reflection_{ReflectionType::kNone}; + LightShadowType light_shadow_{LightShadowType::kObject}; + bool world_space_{}; + bool transparent_{}; + bool premultiplied_{}; + bool have_color_add_{}; + bool double_sided_{}; + bool do_colorize_2_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_OBJECT_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/post_process_component.cc b/src/ballistica/graphics/component/post_process_component.cc new file mode 100644 index 00000000..b79dd475 --- /dev/null +++ b/src/ballistica/graphics/component/post_process_component.cc @@ -0,0 +1,21 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/post_process_component.h" + +namespace ballistica { + +void PostProcessComponent::WriteConfig() { + if (eyes_) { + assert(normal_distort_ == 0.0f); // unsupported config + ConfigForShading(ShadingType::kPostProcessEyes); + } else { + if (normal_distort_ != 0.0f) { + ConfigForShading(ShadingType::kPostProcessNormalDistort); + cmd_buffer_->PutFloat(normal_distort_); + } else { + ConfigForShading(ShadingType::kPostProcess); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/post_process_component.h b/src/ballistica/graphics/component/post_process_component.h new file mode 100644 index 00000000..6f47e9b9 --- /dev/null +++ b/src/ballistica/graphics/component/post_process_component.h @@ -0,0 +1,31 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_POST_PROCESS_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_POST_PROCESS_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +class PostProcessComponent : public RenderComponent { + public: + explicit PostProcessComponent(RenderPass* pass) + : RenderComponent(pass), normal_distort_(0.0f), eyes_(false) {} + void setNormalDistort(float d) { + EnsureConfiguring(); + normal_distort_ = d; + } + void setEyes(bool enable) { + EnsureConfiguring(); + eyes_ = enable; + } + + protected: + void WriteConfig() override; + bool eyes_; + float normal_distort_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_POST_PROCESS_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/render_component.cc b/src/ballistica/graphics/component/render_component.cc new file mode 100644 index 00000000..fdb1cc48 --- /dev/null +++ b/src/ballistica/graphics/component/render_component.cc @@ -0,0 +1,83 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/render_component.h" + +#include "ballistica/dynamics/rigid_body.h" +#include "ballistica/graphics/graphics_server.h" + +namespace ballistica { + +void RenderComponent::ScissorPush(const Rect& rIn) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScissorPush); + cmd_buffer_->PutFloats(rIn.l, rIn.b, rIn.r, rIn.t); +} + +#if BA_DEBUG_BUILD +void RenderComponent::ConfigForEmptyDebugChecks(bool transparent) { + assert(InGameThread()); + if (g_graphics->drawing_opaque_only() && transparent) { + throw Exception("Transparent component submitted in opaque-only section"); + } + if (g_graphics->drawing_transparent_only() && !transparent) { + throw Exception("Opaque component submitted in transparent-only section"); + } +} + +void RenderComponent::ConfigForShadingDebugChecks(ShadingType shading_type) { + assert(InGameThread()); + if (g_graphics->drawing_opaque_only() + && Graphics::IsShaderTransparent(shading_type)) { + throw Exception("Transparent component submitted in opaque-only section"); + } + if (g_graphics->drawing_transparent_only() + && !Graphics::IsShaderTransparent(shading_type)) { + throw Exception("Opaque component submitted in transparent-only section"); + } +} +#endif // BA_DEBUG_BUILD + +void RenderComponent::TransformToBody(const RigidBody& b) { + dBodyID body = b.body(); + dGeomID geom = b.geom(); + const dReal* pos_in; + const dReal* r_in; + if (b.type() == RigidBody::Type::kBody) { + pos_in = dBodyGetPosition(body); + r_in = dBodyGetRotation(body); + } else { + pos_in = dGeomGetPosition(geom); + r_in = dGeomGetRotation(geom); + } + float pos[3]; + float r[12]; + for (int x = 0; x < 3; x++) { + pos[x] = pos_in[x]; + } + pos[0] += b.blend_offset().x; + pos[1] += b.blend_offset().y; + pos[2] += b.blend_offset().z; + for (int x = 0; x < 12; x++) { + r[x] = r_in[x]; + } + float matrix[16]; + matrix[0] = r[0]; + matrix[1] = r[4]; + matrix[2] = r[8]; + matrix[3] = 0; + matrix[4] = r[1]; + matrix[5] = r[5]; + matrix[6] = r[9]; + matrix[7] = 0; + matrix[8] = r[2]; + matrix[9] = r[6]; + matrix[10] = r[10]; + matrix[11] = 0; + matrix[12] = pos[0]; + matrix[13] = pos[1]; + matrix[14] = pos[2]; + matrix[15] = 1; + MultMatrix(matrix); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/render_component.h b/src/ballistica/graphics/component/render_component.h new file mode 100644 index 00000000..08ac4fea --- /dev/null +++ b/src/ballistica/graphics/component/render_component.h @@ -0,0 +1,262 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_RENDER_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_RENDER_COMPONENT_H_ + +#include + +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +class RenderComponent { + public: + explicit RenderComponent(RenderPass* pass) + : state_(State::kConfiguring), pass_(pass), cmd_buffer_(nullptr) {} + ~RenderComponent() { + if (state_ != State::kSubmitted) { + Log("Error: RenderComponent dying without submit() having been called."); + } + } + void DrawModel(ModelData* model, uint32_t flags = 0) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDrawModel); + cmd_buffer_->PutInt(flags); + cmd_buffer_->PutModel(model); + } + void DrawModelInstanced(ModelData* model, + const std::vector& matrices, + int flags = 0) { + assert(!matrices.empty()); + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDrawModelInstanced); + cmd_buffer_->PutInt(flags); + cmd_buffer_->PutModel(model); + cmd_buffer_->PutMatrices(matrices); + } + void DrawMesh(Mesh* m, int flags = 0) { + EnsureDrawing(); + if (m->IsValid()) { + cmd_buffer_->frame_def()->AddMesh(m); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDrawMesh); + cmd_buffer_->PutInt(flags); + cmd_buffer_->PutMeshData(m->mesh_data_client_handle()->mesh_data); + } + } + void DrawScreenQuad() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDrawScreenQuad); + } + // draw triangles using old-school gl format.. only for debugging + // and not supported in all configurations + void BeginDebugDrawTriangles() { + EnsureDrawing(); + cmd_buffer_->PutCommand( + RenderCommandBuffer::Command::kBeginDebugDrawTriangles); + } + void BeginDebugDrawLines() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kBeginDebugDrawLines); + } + void Vertex(float x, float y, float z) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kDebugDrawVertex3); + cmd_buffer_->PutFloats(x, y, z); + } + void End() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kEndDebugDraw); + } + void ScissorPush(const Rect& rIn); + void ScissorPop() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScissorPop); + } + void PushTransform() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kPushTransform); + } + void PopTransform() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kPopTransform); + } + void Translate(float x, float y) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTranslate2); + cmd_buffer_->PutFloats(x, y); + } + void Translate(float x, float y, float z) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTranslate3); + cmd_buffer_->PutFloats(x, y, z); + } + void CursorTranslate() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kCursorTranslate); + } + void Rotate(float angle, float x, float y, float z) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kRotate); + cmd_buffer_->PutFloats(angle, x, y, z); + } + void Scale(float x, float y) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScale2); + cmd_buffer_->PutFloats(x, y); + } + void Scale(float x, float y, float z) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScale3); + cmd_buffer_->PutFloats(x, y, z); + } + void ScaleUniform(float s) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kScaleUniform); + cmd_buffer_->PutFloat(s); + } + void MultMatrix(const float* t) { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kMultMatrix); + cmd_buffer_->PutFloatArray16(t); + } + void TransformToBody(const RigidBody& b); +#if BA_VR_BUILD + void VRTransformToRightHand() { + EnsureDrawing(); + cmd_buffer_->PutCommand( + RenderCommandBuffer::Command::kTransformToRightHand); + } + void VRTransformToLeftHand() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTransformToLeftHand); + } + void VRTransformToHead() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTransformToHead); + } +#endif // BA_VR_BUILD + void TranslateToProjectedPoint(float x, float y, float z) { + EnsureDrawing(); + cmd_buffer_->PutCommand( + RenderCommandBuffer::Command::kTranslateToProjectedPoint); + cmd_buffer_->PutFloats(x, y, z); + } + void FlipCullFace() { + EnsureDrawing(); + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kFlipCullFace); + } + void Submit() { + if (state_ != State::kSubmitted) { + // if we were drawing, make note that we're done + if (state_ == State::kDrawing) { +#if BA_DEBUG_BUILD + assert(pass_->frame_def()->defining_component()); + pass_->frame_def()->set_defining_component(false); +#endif // BA_DEBUG_BUILD + } + state_ = State::kSubmitted; + } + } + + protected: + enum class State { kConfiguring, kDrawing, kSubmitted }; + void EnsureConfiguring() { + if (state_ != State::kConfiguring) { + // if we were drawing, make note that we're done +#if BA_DEBUG_BUILD + if (state_ == State::kDrawing) { + assert(pass_->frame_def()->defining_component()); + pass_->frame_def()->set_defining_component(false); + } +#endif // BA_DEBUG_BUILD + state_ = State::kConfiguring; + } + } +#if BA_DEBUG_BUILD + void ConfigForEmptyDebugChecks(bool transparent); + void ConfigForShadingDebugChecks(ShadingType shading_type); +#endif + + // Given a shader type, returns a buffer to write the command stream to. + void ConfigForEmpty(bool transparent) { +#if BA_DEBUG_BUILD + ConfigForEmptyDebugChecks(transparent); +#endif + + assert(!pass_->UsesWorldLists()); + if (transparent) { + cmd_buffer_ = pass_->commands_flat_transparent(); + } else { + cmd_buffer_ = pass_->commands_flat(); + } + } + + // Given a shader type, sets up the config target buffer. + void ConfigForShading(ShadingType shading_type) { + // Determine which buffer to write to, etc. + // Debugging: if we've got transparent-only or opaque-only mode flipped on, + // make sure only those type of components are being submitted. +#if BA_DEBUG_BUILD + ConfigForShadingDebugChecks(shading_type); + // Also make sure only transparent stuff is going into the + // light/shadow/overlay3D passes (we skip rendering the opaque lists there + // since there shouldn't be anything in them, and we're not using depth + // for those so it wouldn't be much of an optimization..) + if ((pass_->type() == RenderPass::Type::kLightPass + || pass_->type() == RenderPass::Type::kLightShadowPass + || pass_->type() == RenderPass::Type::kOverlay3DPass) + && !Graphics::IsShaderTransparent(shading_type)) { + throw Exception( + "Opaque component submitted to light/shadow/overlay3d pass;" + " not cool man."); + } + + // Likewise the blit pass should consist solely of opaque stuff. + if (pass_->type() == RenderPass::Type::kBlitPass + && Graphics::IsShaderTransparent(shading_type)) { + throw Exception( + "Transparent component submitted to blit pass;" + " not cool man."); + } +#endif // BA_DEBUG_BUILD + // Certain passes (overlay, etc) draw objects in the order + // provided. Other passes group by shader for efficiency. + if (pass_->UsesWorldLists()) { + cmd_buffer_ = pass_->GetCommands(shading_type); + } else { + if (Graphics::IsShaderTransparent(shading_type)) { + cmd_buffer_ = pass_->commands_flat_transparent(); + } else { + cmd_buffer_ = pass_->commands_flat(); + } + } + + // Go ahead and throw down the shader command. + cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kShader); + cmd_buffer_->PutInt(static_cast(shading_type)); + } + + void EnsureDrawing() { + if (state_ != State::kDrawing) { + WriteConfig(); + state_ = State::kDrawing; + // make sure we're the only one drawing until we're submitted +#if BA_DEBUG_BUILD + assert(!pass_->frame_def()->defining_component()); + pass_->frame_def()->set_defining_component(true); +#endif // BA_DEBUG_BUILD + } + } + // subclasses should override this to dump + // their needed data to the stream + virtual void WriteConfig() = 0; + + protected: + RenderCommandBuffer* cmd_buffer_; + State state_; + RenderPass* pass_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_RENDER_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/shield_component.cc b/src/ballistica/graphics/component/shield_component.cc new file mode 100644 index 00000000..216e846c --- /dev/null +++ b/src/ballistica/graphics/component/shield_component.cc @@ -0,0 +1,9 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/shield_component.h" + +namespace ballistica { + +void ShieldComponent::WriteConfig() { ConfigForShading(ShadingType::kShield); } + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/shield_component.h b/src/ballistica/graphics/component/shield_component.h new file mode 100644 index 00000000..447df953 --- /dev/null +++ b/src/ballistica/graphics/component/shield_component.h @@ -0,0 +1,21 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_SHIELD_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_SHIELD_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +// handles special cases such as drawing light/shadow/back buffers. +class ShieldComponent : public RenderComponent { + public: + explicit ShieldComponent(RenderPass* pass) : RenderComponent(pass) {} + + protected: + void WriteConfig() override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_SHIELD_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/simple_component.cc b/src/ballistica/graphics/component/simple_component.cc new file mode 100644 index 00000000..6f8228b8 --- /dev/null +++ b/src/ballistica/graphics/component/simple_component.cc @@ -0,0 +1,228 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/simple_component.h" + +namespace ballistica { + +void SimpleComponent::WriteConfig() { + // if we're transparent we don't want to do optimization-based + // shader swapping (ie: when color is 1). This is because it can + // affect draw order, which is important unlike with opaque stuff. + if (transparent_) { + if (texture_.exists()) { + if (colorize_texture_.exists()) { + assert(flatness_ == 0.0f); // unimplemented combo + assert(glow_amount_ == 0.0f); // unimplemented combo + assert(shadow_opacity_ == 0.0f); // unimplemented combo + assert(!double_sided_); // unimplemented combo + assert(!mask_uv2_texture_.exists()); // unimplemented combo + if (do_colorize_2_) { + if (mask_texture_.exists()) { + ConfigForShading( + ShadingType:: + kSimpleTextureModulatedTransparentColorized2Masked); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + colorize_color_r_, colorize_color_g_, + colorize_color_b_, colorize_color2_r_, + colorize_color2_g_, colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + cmd_buffer_->PutTexture(mask_texture_); + } else { + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparentColorized2); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + colorize_color_r_, colorize_color_g_, + colorize_color_b_, colorize_color2_r_, + colorize_color2_g_, colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + } + } else { + assert(!mask_texture_.exists()); // unimplemented combo + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparentColorized); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + colorize_color_r_, colorize_color_g_, + colorize_color_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + } + } else { + // non-colorized with texture + if (double_sided_) { + assert(!mask_texture_.exists()); // unimplemented combo + assert(flatness_ == 0.0f); // unimplemented combo + assert(glow_amount_ == 0.0f); // unimplemented combo + assert(shadow_opacity_ == 0.0f); // unimplemented combo + assert(!mask_texture_.exists()); // unimplemented combo + assert(!mask_uv2_texture_.exists()); // unimplemented combo + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparentDoubleSided); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + cmd_buffer_->PutTexture(texture_); + } else { + if (shadow_opacity_ > 0.0f) { + assert(!mask_texture_.exists()); // unimplemented combo + assert(glow_amount_ == 0.0f); // unimplemented combo + assert(mask_uv2_texture_.exists()); + if (flatness_ != 0.0f) { + ConfigForShading( + ShadingType::kSimpleTexModulatedTransShadowFlatness); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + shadow_offset_x_, shadow_offset_y_, + shadow_blur_, shadow_opacity_, flatness_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(mask_uv2_texture_); + } else { + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparentShadow); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + shadow_offset_x_, shadow_offset_y_, + shadow_blur_, shadow_opacity_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(mask_uv2_texture_); + } + } else { + if (glow_amount_ > 0.0f) { + assert(!mask_texture_.exists()); // unimplemented combo + assert(flatness_ == 0.0f); // unimplemented combo + if (mask_uv2_texture_.exists()) { + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparentGlowMaskUV2); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + glow_amount_, glow_blur_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(mask_uv2_texture_); + } else { + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparentGlow); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + glow_amount_, glow_blur_); + cmd_buffer_->PutTexture(texture_); + } + } else { + if (flatness_ != 0.0f) { + assert(!mask_texture_.exists()); // unimplemented + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransFlatness); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + flatness_); + cmd_buffer_->PutTexture(texture_); + } else { + if (mask_texture_.exists()) { + // currently mask functionality requires colorize too, so + // just send a black texture for that.. + ConfigForShading( + ShadingType:: + kSimpleTextureModulatedTransparentColorized2Masked); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats( + color_r_, color_g_, color_b_, color_a_, colorize_color_r_, + colorize_color_g_, colorize_color_b_, colorize_color2_r_, + colorize_color2_g_, colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture( + g_media->GetTexture(SystemTextureID::kBlack)); + cmd_buffer_->PutTexture(mask_texture_); + } else { + ConfigForShading( + ShadingType::kSimpleTextureModulatedTransparent); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + color_a_); + cmd_buffer_->PutTexture(texture_); + } + } + } + } + } + } + } else { + assert(flatness_ == 0.0f); // unimplemented combo + assert(glow_amount_ == 0.0f); // unimplemented combo + assert(shadow_opacity_ == 0.0f); // unimplemented combo + assert(!colorize_texture_.exists()); // unimplemented combo + assert(!mask_texture_.exists()); // unimplemented combo + assert(!mask_uv2_texture_.exists()); // unimplemented combo + if (double_sided_) { + ConfigForShading(ShadingType::kSimpleColorTransparentDoubleSided); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + } else { + ConfigForShading(ShadingType::kSimpleColorTransparent); + cmd_buffer_->PutInt(premultiplied_); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + } + } + } else { + // when we're opaque we can do some shader-swapping optimizations + // since draw order doesn't matter. + assert(flatness_ == 0.0f); // unimplemented combo + assert(glow_amount_ == 0.0f); // unimplemented combo + assert(shadow_opacity_ == 0.0f); // unimplemented combo + assert(!double_sided_); // not implemented + assert(!mask_uv2_texture_.exists()); // unimplemented combo + if (texture_.exists()) { + if (colorize_texture_.exists()) { + assert(!mask_texture_.exists()); // unimplemented combo + if (do_colorize_2_) { + ConfigForShading(ShadingType::kSimpleTextureModulatedColorized2); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + colorize_color_r_, colorize_color_g_, + colorize_color_b_, colorize_color2_r_, + colorize_color2_g_, colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + } else { + ConfigForShading(ShadingType::kSimpleTextureModulatedColorized); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, + colorize_color_r_, colorize_color_g_, + colorize_color_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(colorize_texture_); + } + } else { + assert(!do_colorize_2_); // unsupported combo + if (mask_texture_.exists()) { + // currently mask functionality requires colorize too, so + // we have to send a black texture along for that.. + ConfigForShading( + ShadingType::kSimpleTextureModulatedColorized2Masked); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_, + colorize_color_r_, colorize_color_g_, + colorize_color_b_, colorize_color2_r_, + colorize_color2_g_, colorize_color2_b_); + cmd_buffer_->PutTexture(texture_); + cmd_buffer_->PutTexture(g_media->GetTexture(SystemTextureID::kBlack)); + cmd_buffer_->PutTexture(mask_texture_); + } else { + // if no color was provided we can do a super-cheap version + if (!have_color_) { + ConfigForShading(ShadingType::kSimpleTexture); + cmd_buffer_->PutTexture(texture_); + } else { + ConfigForShading(ShadingType::kSimpleTextureModulated); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_); + cmd_buffer_->PutTexture(texture_); + } + } + } + } else { + assert(!mask_texture_.exists()); // unimplemented combo + assert(!colorize_texture_.exists()); // unsupported here + ConfigForShading(ShadingType::kSimpleColor); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_); + } + } +} +} // namespace ballistica diff --git a/src/ballistica/graphics/component/simple_component.h b/src/ballistica/graphics/component/simple_component.h new file mode 100644 index 00000000..f6e23fd1 --- /dev/null +++ b/src/ballistica/graphics/component/simple_component.h @@ -0,0 +1,185 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_SIMPLE_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_SIMPLE_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +// used for UI and overlays and things - no world tinting/etc is applied +class SimpleComponent : public RenderComponent { + public: + explicit SimpleComponent(RenderPass* pass) + : RenderComponent(pass), + color_r_(1.0f), + color_g_(1.0f), + color_b_(1.0f), + color_a_(1.0f), + colorize_color_r_(1.0f), + colorize_color_g_(1.0f), + colorize_color_b_(1.0f), + colorize_color_a_(1.0f), + colorize_color2_r_(1.0f), + colorize_color2_g_(1.0f), + colorize_color2_b_(1.0f), + colorize_color2_a_(1.0f), + shadow_offset_x_(0.0f), + shadow_offset_y_(0.0f), + shadow_blur_(0.0f), + shadow_opacity_(0.0f), + glow_amount_(0.0f), + glow_blur_(0.0f), + flatness_(0.0f), + transparent_(false), + premultiplied_(false), + have_color_(false), + double_sided_(false), + do_colorize_2_(false) {} + void SetPremultiplied(bool val) { + EnsureConfiguring(); + premultiplied_ = val; + } + void SetTransparent(bool val) { + EnsureConfiguring(); + transparent_ = val; + } + void SetTexture(TextureData* t) { + EnsureConfiguring(); + texture_ = t; + } + void SetTexture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + texture_ = t_in->texture_data(); + } else { + texture_.Clear(); + } + } + // used with colorize color 1 and 2 + // red areas of the texture will get multiplied by colorize-color1 + // and green areas by colorize-color2 + void SetColorizeTexture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + colorize_texture_ = t_in->texture_data(); + } else { + colorize_texture_.Clear(); + } + } + void SetColorizeTexture(TextureData* t) { + EnsureConfiguring(); + colorize_texture_ = t; + } + // red multiplies source color, green adds colorize1-color, + // and blue adds white + // (currently requires colorize1 and colorize 2 to be set) + void SetMaskTexture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + mask_texture_ = t_in->texture_data(); + } else { + mask_texture_.Clear(); + } + } + void SetMaskTexture(TextureData* t) { + EnsureConfiguring(); + mask_texture_ = t; + } + void SetMaskUV2Texture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + mask_uv2_texture_ = t_in->texture_data(); + } else { + mask_uv2_texture_.Clear(); + } + } + void SetMaskUV2Texture(TextureData* t) { + EnsureConfiguring(); + mask_uv2_texture_ = t; + } + void clearMaskUV2Texture() { + EnsureConfiguring(); + mask_uv2_texture_.Clear(); + } + void SetDoubleSided(bool enable) { + EnsureConfiguring(); + double_sided_ = enable; + } + void SetColor(float r, float g, float b, float a = 1.0f) { + // we support fast inline color changes with drawing streams + // (avoids having to re-send a whole configure for every color change) + // ..make sure to only allow this if we have a color already; otherwise we + // need to config since we might be implicitly switch shaders by setting + // color + if (state_ == State::kDrawing && have_color_) { + cmd_buffer_->PutCommand( + RenderCommandBuffer::Command::kSimpleComponentInlineColor); + cmd_buffer_->PutFloats(r, g, b, a); + } else { + EnsureConfiguring(); + have_color_ = true; + } + color_r_ = r; + color_g_ = g; + color_b_ = b; + color_a_ = a; + } + void SetColorizeColor(float r, float g, float b, float a = 1.0f) { + EnsureConfiguring(); + colorize_color_r_ = r; + colorize_color_g_ = g; + colorize_color_b_ = b; + colorize_color_a_ = a; + } + void SetColorizeColor2(float r, float g, float b, float a = 1.0f) { + EnsureConfiguring(); + colorize_color2_r_ = r; + colorize_color2_g_ = g; + colorize_color2_b_ = b; + colorize_color2_a_ = a; + do_colorize_2_ = true; + } + void SetShadow(float offsetX, float offsetY, float blur, float opacity) { + EnsureConfiguring(); + shadow_offset_x_ = offsetX; + shadow_offset_y_ = offsetY; + shadow_blur_ = blur; + shadow_opacity_ = opacity; + } + void setGlow(float amount, float blur) { + EnsureConfiguring(); + glow_amount_ = amount; + glow_blur_ = blur; + } + void SetFlatness(float flatness) { + EnsureConfiguring(); + flatness_ = flatness; + } + + protected: + void WriteConfig() override; + + protected: + float color_r_, color_g_, color_b_, color_a_; + float colorize_color_r_, colorize_color_g_, colorize_color_b_, + colorize_color_a_; + float colorize_color2_r_, colorize_color2_g_, colorize_color2_b_, + colorize_color2_a_; + float shadow_offset_x_, shadow_offset_y_, shadow_blur_, shadow_opacity_; + float glow_amount_, glow_blur_; + float flatness_; + Object::Ref texture_; + Object::Ref colorize_texture_; + Object::Ref mask_texture_; + Object::Ref mask_uv2_texture_; + bool do_colorize_2_; + bool transparent_; + bool premultiplied_; + bool have_color_; + bool double_sided_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_SIMPLE_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/smoke_component.cc b/src/ballistica/graphics/component/smoke_component.cc new file mode 100644 index 00000000..22a9a52b --- /dev/null +++ b/src/ballistica/graphics/component/smoke_component.cc @@ -0,0 +1,19 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/smoke_component.h" + +namespace ballistica { + +void SmokeComponent::WriteConfig() { + if (overlay_) { + ConfigForShading(ShadingType::kSmokeOverlay); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + cmd_buffer_->PutTexture(g_media->GetTexture(SystemTextureID::kSmoke)); + } else { + ConfigForShading(ShadingType::kSmoke); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + cmd_buffer_->PutTexture(g_media->GetTexture(SystemTextureID::kSmoke)); + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/smoke_component.h b/src/ballistica/graphics/component/smoke_component.h new file mode 100644 index 00000000..698044b9 --- /dev/null +++ b/src/ballistica/graphics/component/smoke_component.h @@ -0,0 +1,39 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_SMOKE_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_SMOKE_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +class SmokeComponent : public RenderComponent { + public: + explicit SmokeComponent(RenderPass* pass) + : RenderComponent(pass), + color_r_(1.0f), + color_g_(1.0f), + color_b_(1.0f), + color_a_(1.0f), + overlay_(false) {} + void SetColor(float r, float g, float b, float a = 1.0f) { + EnsureConfiguring(); + color_r_ = r; + color_g_ = g; + color_b_ = b; + color_a_ = a; + } + void SetOverlay(bool overlay) { + EnsureConfiguring(); + overlay_ = overlay; + } + + protected: + void WriteConfig() override; + float color_r_, color_g_, color_b_, color_a_; + bool overlay_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_SMOKE_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/special_component.cc b/src/ballistica/graphics/component/special_component.cc new file mode 100644 index 00000000..9be04c15 --- /dev/null +++ b/src/ballistica/graphics/component/special_component.cc @@ -0,0 +1,12 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/special_component.h" + +namespace ballistica { + +void SpecialComponent::WriteConfig() { + ConfigForShading(ShadingType::kSpecial); + cmd_buffer_->PutInt(static_cast(source_)); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/special_component.h b/src/ballistica/graphics/component/special_component.h new file mode 100644 index 00000000..ba6ee66b --- /dev/null +++ b/src/ballistica/graphics/component/special_component.h @@ -0,0 +1,26 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_SPECIAL_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_SPECIAL_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +// handles special cases such as drawing light/shadow/back buffers. +class SpecialComponent : public RenderComponent { + public: + enum class Source { kLightBuffer, kLightShadowBuffer, kVROverlayBuffer }; + SpecialComponent(RenderPass* pass, Source s) + : RenderComponent(pass), source_(s) {} + + protected: + void WriteConfig() override; + + private: + Source source_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_SPECIAL_COMPONENT_H_ diff --git a/src/ballistica/graphics/component/sprite_component.cc b/src/ballistica/graphics/component/sprite_component.cc new file mode 100644 index 00000000..4c438f5e --- /dev/null +++ b/src/ballistica/graphics/component/sprite_component.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/component/sprite_component.h" + +namespace ballistica { + +void SpriteComponent::WriteConfig() { + // if they didn't give us a texture, just use a blank white texture; + // this is not a common case and easier than forking all our shaders + // to create non-textured versions. + if (!texture_.exists()) { + texture_ = g_media->GetTexture(SystemTextureID::kWhite); + } + if (exponent_ == 1) { + ConfigForShading(ShadingType::kSprite); + cmd_buffer_->PutFloats(color_r_, color_g_, color_b_, color_a_); + cmd_buffer_->PutInt(overlay_); + cmd_buffer_->PutInt(camera_aligned_); + cmd_buffer_->PutTexture(texture_); + } else { + throw Exception(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/component/sprite_component.h b/src/ballistica/graphics/component/sprite_component.h new file mode 100644 index 00000000..2836034d --- /dev/null +++ b/src/ballistica/graphics/component/sprite_component.h @@ -0,0 +1,61 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_COMPONENT_SPRITE_COMPONENT_H_ +#define BALLISTICA_GRAPHICS_COMPONENT_SPRITE_COMPONENT_H_ + +#include "ballistica/graphics/component/render_component.h" + +namespace ballistica { + +class SpriteComponent : public RenderComponent { + public: + explicit SpriteComponent(RenderPass* pass) : RenderComponent(pass) {} + void SetColor(float r, float g, float b, float a = 1.0f) { + EnsureConfiguring(); + color_r_ = r; + color_g_ = g; + color_b_ = b; + color_a_ = a; + have_color_ = true; + } + void SetCameraAligned(bool c) { + EnsureConfiguring(); + camera_aligned_ = c; + } + void SetOverlay(bool enable) { + EnsureConfiguring(); + overlay_ = enable; + } + void SetExponent(int i) { + EnsureConfiguring(); + exponent_ = static_cast_check_fit(i); + } + void SetTexture(const Object::Ref& t_in) { + EnsureConfiguring(); + if (t_in.exists()) { + texture_ = t_in->texture_data(); + } else { + texture_.Clear(); + } + } + void SetTexture(TextureData* t) { + EnsureConfiguring(); + texture_ = t; + } + + protected: + void WriteConfig() override; + bool have_color_{}; + bool camera_aligned_{}; + bool overlay_{}; + uint8_t exponent_{1}; + float color_r_{1.0f}; + float color_g_{1.0f}; + float color_b_{1.0f}; + float color_a_{1.0f}; + Object::Ref texture_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_COMPONENT_SPRITE_COMPONENT_H_ diff --git a/src/ballistica/graphics/frame_def.cc b/src/ballistica/graphics/frame_def.cc new file mode 100644 index 00000000..d298fa5f --- /dev/null +++ b/src/ballistica/graphics/frame_def.cc @@ -0,0 +1,173 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/frame_def.h" + +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/render_pass.h" +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +FrameDef::FrameDef() + : light_pass_(new RenderPass(RenderPass::Type::kLightPass, this)), + light_shadow_pass_( + new RenderPass(RenderPass::Type::kLightShadowPass, this)), + beauty_pass_(new RenderPass(RenderPass::Type::kBeautyPass, this)), + beauty_pass_bg_(new RenderPass(RenderPass::Type::kBeautyPassBG, this)), + overlay_pass_(new RenderPass(RenderPass::Type::kOverlayPass, this)), + overlay_front_pass_( + new RenderPass(RenderPass::Type::kOverlayFrontPass, this)), + overlay_3d_pass_(new RenderPass(RenderPass::Type::kOverlay3DPass, this)), + vr_cover_pass_(new RenderPass(RenderPass::Type::kVRCoverPass, this)), + overlay_fixed_pass_( + new RenderPass(RenderPass::Type::kOverlayFixedPass, this)), + overlay_flat_pass_( + new RenderPass(RenderPass::Type::kOverlayFlatPass, this)), + blit_pass_(new RenderPass(RenderPass::Type::kBlitPass, this)) {} + +FrameDef::~FrameDef() { assert(InGameThread()); } + +void FrameDef::Reset() { + assert(InGameThread()); + real_time_ = 0; + base_time_ = 0; + base_time_elapsed_ = 0; + frame_number_ = 0; + +#if BA_DEBUG_BUILD + defining_component_ = false; +#endif + + benchmark_type_ = BenchmarkType::kNone; + + mesh_data_creates_.clear(); + mesh_data_destroys_.clear(); + + media_components_.clear(); + meshes_.clear(); + mesh_index_sizes_.clear(); + mesh_buffers_.clear(); + + quality_ = g_graphics_server->quality(); + + assert(g_graphics->has_supports_high_quality_graphics_value()); + orbiting_ = (g_graphics->camera()->mode() == CameraMode::kOrbit); + + shadow_offset_ = g_graphics->shadow_offset(); + shadow_scale_ = g_graphics->shadow_scale(); + shadow_ortho_ = g_graphics->shadow_ortho(); + tint_ = g_graphics->tint(); + ambient_color_ = g_graphics->ambient_color(); + + vignette_outer_ = g_graphics->vignette_outer(); + vignette_inner_ = g_graphics->vignette_inner(); + + light_pass_->Reset(); + light_shadow_pass_->Reset(); + beauty_pass_->Reset(); + beauty_pass_bg_->Reset(); + overlay_pass_->Reset(); + overlay_front_pass_->Reset(); + if (IsVRMode()) { + overlay_flat_pass_->Reset(); + overlay_fixed_pass_->Reset(); + vr_cover_pass_->Reset(); + } + overlay_3d_pass_->Reset(); + blit_pass_->Reset(); + beauty_pass_->set_floor_reflection(g_graphics->floor_reflection()); +} + +void FrameDef::Finalize() { + assert(!defining_component_); + light_pass_->Finalize(); + light_shadow_pass_->Finalize(); + beauty_pass_->Finalize(); + beauty_pass_bg_->Finalize(); + overlay_pass_->Finalize(); + overlay_front_pass_->Finalize(); + if (IsVRMode()) { + overlay_fixed_pass_->Finalize(); + overlay_flat_pass_->Finalize(); + vr_cover_pass_->Finalize(); + } + overlay_3d_pass_->Finalize(); + blit_pass_->Finalize(); +} + +void FrameDef::AddMesh(Mesh* mesh) { + // Add this mesh's data to the frame only if we haven't yet. + if (mesh->last_frame_def_num() != frame_number_) { + mesh->set_last_frame_def_num(frame_number_); + meshes_.push_back(mesh->mesh_data_client_handle()); + switch (mesh->type()) { + case MeshDataType::kIndexedSimpleSplit: { + auto* m = static_cast(mesh); + assert(m); + assert(m == dynamic_cast(mesh)); + mesh_index_sizes_.push_back( + static_cast_check_fit(m->index_data_size())); + mesh_buffers_.emplace_back(m->GetIndexData()); + mesh_buffers_.emplace_back(m->static_data()); + mesh_buffers_.emplace_back(m->dynamic_data()); + break; + } + case MeshDataType::kIndexedObjectSplit: { + auto* m = static_cast(mesh); + assert(m); + assert(m == dynamic_cast(mesh)); + mesh_index_sizes_.push_back( + static_cast_check_fit(m->index_data_size())); + mesh_buffers_.emplace_back(m->GetIndexData()); + mesh_buffers_.emplace_back(m->static_data()); + mesh_buffers_.emplace_back(m->dynamic_data()); + break; + } + case MeshDataType::kIndexedSimpleFull: { + auto* m = static_cast(mesh); + assert(m); + assert(m == dynamic_cast(mesh)); + mesh_index_sizes_.push_back( + static_cast_check_fit(m->index_data_size())); + mesh_buffers_.emplace_back(m->GetIndexData()); + mesh_buffers_.emplace_back(m->data()); + break; + } + case MeshDataType::kIndexedDualTextureFull: { + auto* m = static_cast(mesh); + assert(m); + assert(m == dynamic_cast(mesh)); + mesh_index_sizes_.push_back( + static_cast_check_fit(m->index_data_size())); + mesh_buffers_.emplace_back(m->GetIndexData()); + mesh_buffers_.emplace_back(m->data()); + break; + } + case MeshDataType::kIndexedSmokeFull: { + auto* m = static_cast(mesh); + assert(m); + assert(m == dynamic_cast(mesh)); + mesh_index_sizes_.push_back( + static_cast_check_fit(m->index_data_size())); + mesh_buffers_.emplace_back(m->GetIndexData()); + mesh_buffers_.emplace_back(m->data()); + break; + } + case MeshDataType::kSprite: { + auto* m = static_cast(mesh); + assert(m); + assert(m == dynamic_cast(mesh)); + mesh_index_sizes_.push_back( + static_cast_check_fit(m->index_data_size())); + mesh_buffers_.emplace_back(m->GetIndexData()); + mesh_buffers_.emplace_back(m->data()); + break; + } + default: + throw Exception(); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/frame_def.h b/src/ballistica/graphics/frame_def.h new file mode 100644 index 00000000..5df6de21 --- /dev/null +++ b/src/ballistica/graphics/frame_def.h @@ -0,0 +1,228 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_FRAME_DEF_H_ +#define BALLISTICA_GRAPHICS_FRAME_DEF_H_ + +#include +#include + +#include "ballistica/math/matrix44f.h" +#include "ballistica/math/vector2f.h" +#include "ballistica/media/data/media_component_data.h" + +namespace ballistica { + +/// A flattened representation of a frame; generated by the game thread and sent +/// to the graphics thread to render. +class FrameDef { + public: + auto light_pass() -> RenderPass* { return light_pass_.get(); } + auto light_shadow_pass() -> RenderPass* { return light_shadow_pass_.get(); } + auto beauty_pass() -> RenderPass* { return beauty_pass_.get(); } + auto beauty_pass_bg() -> RenderPass* { return beauty_pass_bg_.get(); } + auto overlay_pass() -> RenderPass* { return overlay_pass_.get(); } + auto overlay_front_pass() -> RenderPass* { return overlay_front_pass_.get(); } + auto vr_near_clip() const -> float { return vr_near_clip_; } + void set_vr_near_clip(float val) { vr_near_clip_ = val; } + auto benchmark_type() const -> BenchmarkType { return benchmark_type_; } + void set_benchmark_type(BenchmarkType val) { benchmark_type_ = val; } + + // Returns the fixed overlay pass if there is one; otherwise the regular. + auto GetOverlayFixedPass() -> RenderPass* { + if (IsVRMode()) { + return overlay_fixed_pass_.get(); + } else { + return overlay_pass_.get(); + } + } + + // Return either the overlay-flat pass (in vr) or regular overlay pass (for + // non-vr). + auto GetOverlayFlatPass() -> RenderPass* { + if (IsVRMode()) { + return overlay_flat_pass_.get(); + } else { + return overlay_pass_.get(); + } + } + auto overlay_3d_pass() -> RenderPass* { return overlay_3d_pass_.get(); } + auto blit_pass() -> RenderPass* { return blit_pass_.get(); } + auto vr_cover_pass() -> RenderPass* { return vr_cover_pass_.get(); } + + // Returns the real-time this frame_def originated at. + // For a more smoothly-incrementing value, + // use getbasetime() + auto real_time() const -> millisecs_t { return real_time_; } + auto frame_number() const -> int64_t { return frame_number_; } + + // Returns the bsGame master-net-time when this was made + // (tries to match real time but is incremented more smoothly + // so is better for drawing purposes) + auto base_time() const -> millisecs_t { return base_time_; } + + // How much base time does this frame-def represent. + auto base_time_elapsed() const -> millisecs_t { return base_time_elapsed_; } + + auto quality() const -> GraphicsQuality { return quality_; } + auto orbiting() const -> bool { return orbiting_; } + auto shadow_offset() const -> const Vector3f& { return shadow_offset_; } + auto shadow_scale() const -> const Vector2f& { return shadow_scale_; } + auto shadow_ortho() const -> bool { return shadow_ortho_; } + auto tint() const -> const Vector3f& { return tint_; } + auto ambient_color() const -> const Vector3f& { return ambient_color_; } + auto vignette_outer() const -> const Vector3f& { return vignette_outer_; } + auto vignette_inner() const -> const Vector3f& { return vignette_inner_; } + + // FIXME: what was this for?..(I think some vr thing?) + auto cam_original() const -> const Vector3f& { return cam_original_; } + auto cam_target_original() const -> const Vector3f& { + return cam_target_original_; + } + void set_cam_original(const Vector3f& val) { cam_original_ = val; } + void set_cam_target_original(const Vector3f& val) { + cam_target_original_ = val; + } + auto camera_mode() const -> CameraMode { return camera_mode_; } + auto vr_overlay_screen_matrix() const -> const Matrix44f& { + return vr_overlay_screen_matrix_; + } + void set_vr_overlay_screen_matrix(const Matrix44f& mat) { + vr_overlay_screen_matrix_ = mat; + } + auto vr_overlay_screen_matrix_fixed() const -> const Matrix44f& { + return vr_overlay_screen_matrix_fixed_; + } + void set_vr_overlay_screen_matrix_fixed(const Matrix44f& mat) { + vr_overlay_screen_matrix_fixed_ = mat; + } + + // Effects requiring availability of a depth texture should + // check this to determine whether they should draw. + auto has_depth_texture() const -> bool { + return (quality_ >= GraphicsQuality::kHigh); + } + void AddComponent(const Object::Ref& component) { + // Add a reference to this component only if we havn't yet. + if (component->last_frame_def_num() != frame_number_) { + component->set_last_frame_def_num(frame_number_); + media_components_.push_back(component); + } + } + void AddMesh(Mesh* mesh); + void set_needs_clear(bool val) { needs_clear_ = val; } + auto needs_clear() const -> bool { return needs_clear_; } + + FrameDef(); + ~FrameDef(); + void Reset(); + void Finalize(); + + void set_base_time_elapsed(millisecs_t val) { base_time_elapsed_ = val; } + void set_real_time(millisecs_t val) { real_time_ = val; } + void set_base_time(millisecs_t val) { base_time_ = val; } + void set_frame_number(int64_t val) { frame_number_ = val; } + + auto overlay_flat_pass() const -> RenderPass* { + return overlay_flat_pass_.get(); + } + auto overlay_fixed_pass() const -> RenderPass* { + return overlay_fixed_pass_.get(); + } + auto overlay_front_pass() const -> RenderPass* { + return overlay_front_pass_.get(); + } + auto overlay_pass() const -> RenderPass* { return overlay_pass_.get(); } + auto vr_cover_pass() const -> RenderPass* { return vr_cover_pass_.get(); } + + void set_mesh_data_creates(const std::vector& creates) { + mesh_data_creates_ = creates; + } + void set_mesh_data_destroys(const std::vector& destroys) { + mesh_data_destroys_ = destroys; + } + auto mesh_data_creates() const -> const std::vector& { + return mesh_data_creates_; + } + auto mesh_data_destroys() const -> const std::vector& { + return mesh_data_destroys_; + } + auto meshes() const -> const std::vector>& { + return meshes_; + } + auto mesh_buffers() const -> const std::vector>& { + return mesh_buffers_; + } + auto mesh_index_sizes() const -> const std::vector& { + return mesh_index_sizes_; + } + auto media_components() const + -> const std::vector>& { + return media_components_; + } + + void set_camera_mode(CameraMode val) { camera_mode_ = val; } + void set_rendering(bool val) { rendering_ = val; } + auto rendering() const -> bool { return rendering_; } + void set_shake_original(const Vector3f& val) { shake_original_ = val; } + auto shake_original() const -> const Vector3f& { return shake_original_; } + +#if BA_DEBUG_BUILD + auto defining_component() const -> bool { return defining_component_; } + void set_defining_component(bool val) { defining_component_ = val; } +#endif + + private: + bool needs_clear_{}; + BenchmarkType benchmark_type_{BenchmarkType::kNone}; + bool rendering_{}; + CameraMode camera_mode_{CameraMode::kFollow}; + Vector3f cam_original_{0.0f, 0.0f, 0.0f}; + Vector3f cam_target_original_{0.0f, 0.0f, 0.0f}; + Vector3f shake_original_{0.0f, 0.0f, 0.0f}; + float vr_near_clip_{}; + Matrix44f vr_overlay_screen_matrix_ = kMatrix44fIdentity; + Matrix44f vr_overlay_screen_matrix_fixed_ = kMatrix44fIdentity; + std::vector mesh_data_creates_; + std::vector mesh_data_destroys_; + + // Meshes/Buffers: + std::vector> meshes_; + std::vector> mesh_buffers_; + std::vector mesh_index_sizes_; + std::vector> media_components_; + +#if BA_DEBUG_BUILD + // Sanity checking: make sure components are completely submitted + // before new ones are started (so we dont get scrambled command buffers). + bool defining_component_{}; +#endif + + std::unique_ptr light_pass_; + std::unique_ptr light_shadow_pass_; + std::unique_ptr beauty_pass_; + std::unique_ptr beauty_pass_bg_; + std::unique_ptr overlay_pass_; + std::unique_ptr overlay_front_pass_; + std::unique_ptr overlay_fixed_pass_; + std::unique_ptr overlay_flat_pass_; + std::unique_ptr vr_cover_pass_; + std::unique_ptr overlay_3d_pass_; + std::unique_ptr blit_pass_; + GraphicsQuality quality_{GraphicsQuality::kLow}; + bool orbiting_{}; + millisecs_t real_time_{}; + millisecs_t base_time_{}; + millisecs_t base_time_elapsed_{}; + int64_t frame_number_{}; + Vector3f shadow_offset_{0.0f, 0.0f, 0.0f}; + Vector2f shadow_scale_{1.0f, 1.0f}; + bool shadow_ortho_{}; + Vector3f tint_{1.0f, 1.0f, 1.0f}; + Vector3f ambient_color_{1.0f, 1.0f, 1.0f}; + Vector3f vignette_outer_{1.0f, 1.0f, 1.0f}; + Vector3f vignette_inner_{1.0f, 1.0f, 1.0f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_FRAME_DEF_H_ diff --git a/src/ballistica/graphics/framebuffer.h b/src/ballistica/graphics/framebuffer.h new file mode 100644 index 00000000..cf3d22e2 --- /dev/null +++ b/src/ballistica/graphics/framebuffer.h @@ -0,0 +1,19 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_FRAMEBUFFER_H_ +#define BALLISTICA_GRAPHICS_FRAMEBUFFER_H_ + +#include "ballistica/core/object.h" + +namespace ballistica { + +class Framebuffer : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kMain; + } +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_FRAMEBUFFER_H_ diff --git a/src/ballistica/graphics/gl/gl_sys.cc b/src/ballistica/graphics/gl/gl_sys.cc new file mode 100644 index 00000000..32a610a5 --- /dev/null +++ b/src/ballistica/graphics/gl/gl_sys.cc @@ -0,0 +1,368 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#if BA_ENABLE_OPENGL +#include "ballistica/graphics/gl/gl_sys.h" + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/platform/sdl/sdl_app.h" + +#if BA_OSTYPE_ANDROID +#include +#if !BA_USE_ES3_INCLUDES +#include "ballistica/platform/android/android_gl3.h" +#endif +#endif + +#if BA_OSTYPE_WINDOWS +#pragma comment(lib, "opengl32.lib") +#pragma comment(lib, "glu32.lib") +#endif + +#if BA_OSTYPE_MACOS +#include +#include +#include +#endif + +#if BA_DEBUG_BUILD +#define DEBUG_CHECK_GL_ERROR \ + { \ + GLenum err = glGetError(); \ + if (err != GL_NO_ERROR) \ + Log("OPENGL ERROR AT LINE " + std::to_string(__LINE__) + ": " \ + + GLErrorToString(err)); \ + } +#else +#define DEBUG_CHECK_GL_ERROR +#endif + +#if BA_OSTYPE_ANDROID +PFNGLDISCARDFRAMEBUFFEREXTPROC _glDiscardFramebufferEXT = nullptr; +#endif + +#if BA_OSTYPE_WINDOWS +PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ = nullptr; +PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC +glGetFramebufferAttachmentParameteriv = nullptr; +PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate = nullptr; +PFNGLACTIVETEXTUREPROC glActiveTexture = nullptr; +PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB = nullptr; +PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = nullptr; +PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = nullptr; +PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = nullptr; +PFNGLCREATEPROGRAMPROC glCreateProgram = nullptr; +PFNGLCREATESHADERPROC glCreateShader = nullptr; +PFNGLSHADERSOURCEPROC glShaderSource = nullptr; +PFNGLCOMPILESHADERPROC glCompileShader = nullptr; +PFNGLLINKPROGRAMPROC glLinkProgram = nullptr; +PFNGLGETINFOLOGARBPROC glGetInfoLogARB = nullptr; +PFNGLATTACHSHADERPROC glAttachShader = nullptr; +PFNGLUSEPROGRAMOBJECTARBPROC glUseProgram = nullptr; +PFNGLGENERATEMIPMAPPROC glGenerateMipmap = nullptr; +PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer = nullptr; +PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer = nullptr; +PFNGLBINDVERTEXARRAYPROC glBindVertexArray = nullptr; +PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation = nullptr; +PFNGLUNIFORM1IPROC glUniform1i = nullptr; +PFNGLUNIFORM1FPROC glUniform1f = nullptr; +PFNGLUNIFORM1FVPROC glUniform1fv = nullptr; +PFNGLUNIFORM2FPROC glUniform2f = nullptr; +PFNGLUNIFORM3FPROC glUniform3f = nullptr; +PFNGLUNIFORM4FPROC glUniform4f = nullptr; +PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers = nullptr; +PFNGLGENBUFFERSPROC glGenBuffers = nullptr; +PFNGLGENVERTEXARRAYSPROC glGenVertexArrays = nullptr; +PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D = nullptr; +PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers = nullptr; +PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer = nullptr; +PFNGLBINDBUFFERPROC glBindBuffer = nullptr; +PFNGLBUFFERDATAPROC glBufferData = nullptr; +PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage = nullptr; +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample = + nullptr; +PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer = nullptr; +PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus = nullptr; +PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers = nullptr; +PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers = nullptr; +PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer = nullptr; +PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray = nullptr; +PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray = nullptr; +PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv = nullptr; +PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation = nullptr; +PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D = nullptr; +PFNGLGETSHADERIVPROC glGetShaderiv = nullptr; +PFNGLGETPROGRAMIVPROC glGetProgramiv = nullptr; +PFNGLDELETESHADERPROC glDeleteShader = nullptr; +PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays = nullptr; +PFNGLDELETEBUFFERSPROC glDeleteBuffers = nullptr; +PFNGLDELETEPROGRAMPROC glDeleteProgram = nullptr; +PFNGLDETACHSHADERPROC glDetachShader = nullptr; +PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog = nullptr; +PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog = nullptr; +#endif // BA_OSTYPE_WINDOWS + +namespace ballistica { + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "EmptyDeclOrStmt" + +GLContext::GLContext(int target_res_x, int target_res_y, bool fullscreen) + : fullscreen_(fullscreen) { + assert(InMainThread()); + bool need_window = true; +#if BA_RIFT_BUILD + // on the rift build we don't need a window when running in vr mode; we just + // use the context we're created into... + if (IsVRMode()) { + need_window = false; + } +#endif // BA_RIFT_BUILD + if (explicit_bool(need_window)) { +#if BA_SDL2_BUILD +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + int flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS; +#else + // Things are a bit more varied on desktop.. + uint32_t flags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN + | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE; + if (fullscreen_) { + flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } +#endif + sdl_window_ = SDL_CreateWindow(nullptr, SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, target_res_x, + target_res_y, flags); + if (!sdl_window_) { + throw Exception("Unable to create SDL Window of size " + + std::to_string(target_res_x) + " by " + + std::to_string(target_res_y)); + } + sdl_gl_context_ = SDL_GL_CreateContext(sdl_window_); + if (!sdl_gl_context_) { + throw Exception("Unable to create SDL GL Context"); + } + SDL_SetWindowTitle(sdl_window_, "BallisticaCore"); + + // Our actual drawable size could differ from the window size on retina + // devices. + int win_size_x, win_size_y; + SDL_GetWindowSize(sdl_window_, &win_size_x, &win_size_y); + SDLApp::get()->SetInitialScreenDimensions(Vector2f( + static_cast(win_size_x), static_cast(win_size_y))); +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + res_x_ = win_size_x; + res_y_ = win_size_y; +#else + SDL_GL_GetDrawableSize(sdl_window_, &res_x_, &res_y_); +#endif // BA_OSTYPE_ANDROID + + // This can come through as zero in some cases (on our cardboard build at + // least). + if (win_size_x != 0) { + pixel_density_ = + static_cast(res_x_) / static_cast(win_size_x); + } +#elif BA_SDL_BUILD // BA_SDL2_BUILD + + int v_flags; + v_flags = SDL_OPENGL; + if (fullscreen_) { + v_flags |= SDL_FULLSCREEN; + // convert to the closest valid fullscreen resolution + // (our last 1.2 build is mac and it's got hacked-in fullscreen-window + // support; so we don't need this) getValidResolution(target_res_x, + // target_res_y); + } else { + v_flags |= SDL_RESIZABLE; + } + surface_ = SDL_SetVideoMode(target_res_x, target_res_y, 32, v_flags); + + // if we failed, fall back to windowed mode. + if (surface_ == nullptr) { + throw Exception("SDL_SetVideoMode() failed for " + + std::to_string(target_res_x) + " by " + + std::to_string(target_res_y) + " fullscreen=" + + std::to_string(static_cast(fullscreen_))); + } + res_x_ = surface_->w; + res_y_ = surface_->h; + SDLApp::get()->SetInitialScreenDimensions(Vector2f(res_x_, res_y_)); + SDL_WM_SetCaption("BallisticaCore", "BallisticaCore"); +#elif BA_OSTYPE_ANDROID + // On Android the Java layer creates a GL setup before even calling us. + // So we have nothing to do here. Hooray! +#else + throw Exception("FIXME: Unimplemented"); +#endif // BA_SDL2_BUILD + } + + // Fetch needed android gl stuff. +#if BA_OSTYPE_ANDROID +#define GET(PTRTYPE, FUNC, REQUIRED) \ + FUNC = (PTRTYPE)eglGetProcAddress(#FUNC); \ + if (!FUNC) FUNC = (PTRTYPE)eglGetProcAddress(#FUNC "EXT"); \ + if (REQUIRED) { \ + BA_PRECONDITION(FUNC != nullptr); \ + } + GET(PFNGLDISCARDFRAMEBUFFEREXTPROC, _glDiscardFramebufferEXT, false); +#endif // BA_OSTYPE_ANDROID + + // Fetch needed windows gl stuff. +#if BA_OSTYPE_WINDOWS +#define GET(PTRTYPE, FUNC, REQUIRED) \ + FUNC = (PTRTYPE)wglGetProcAddress(#FUNC); \ + if (!FUNC) FUNC = (PTRTYPE)wglGetProcAddress(#FUNC "EXT"); \ + if (REQUIRED) { \ + BA_PRECONDITION(FUNC != nullptr); \ + } + GET(PFNGLGETINTERNALFORMATIVPROC, glGetInternalformativ, + false); // for checking msaa level support + GET(PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC, + glGetFramebufferAttachmentParameteriv, false); // for checking srgb stuff + GET(PFNGLBLENDFUNCSEPARATEPROC, glBlendFuncSeparate, + false); // needed for VR overlay + GET(PFNGLACTIVETEXTUREPROC, glActiveTexture, true); + GET(PFNGLCLIENTACTIVETEXTUREARBPROC, glClientActiveTextureARB, true); + GET(PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT, true); + GET(PFNGLPOINTPARAMETERFVARBPROC, glPointParameterfvARB, true); + GET(PFNGLPOINTPARAMETERFARBPROC, glPointParameterfARB, true); + GET(PFNGLCREATEPROGRAMPROC, glCreateProgram, true); + GET(PFNGLCREATESHADERPROC, glCreateShader, true); + GET(PFNGLSHADERSOURCEPROC, glShaderSource, true); + GET(PFNGLCOMPILESHADERPROC, glCompileShader, true); + GET(PFNGLLINKPROGRAMPROC, glLinkProgram, true); + GET(PFNGLGETINFOLOGARBPROC, glGetInfoLogARB, true); + GET(PFNGLATTACHSHADERPROC, glAttachShader, true); + GET(PFNGLUSEPROGRAMOBJECTARBPROC, glUseProgram, true); + GET(PFNGLGENERATEMIPMAPPROC, glGenerateMipmap, true); + GET(PFNGLBINDFRAMEBUFFERPROC, glBindFramebuffer, true); + GET(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation, true); + GET(PFNGLUNIFORM1IPROC, glUniform1i, true); + GET(PFNGLUNIFORM1FPROC, glUniform1f, true); + GET(PFNGLUNIFORM1FVPROC, glUniform1fv, true); + GET(PFNGLUNIFORM2FPROC, glUniform2f, true); + GET(PFNGLUNIFORM3FPROC, glUniform3f, true); + GET(PFNGLUNIFORM4FPROC, glUniform4f, true); + GET(PFNGLGENFRAMEBUFFERSPROC, glGenFramebuffers, true); + GET(PFNGLGENBUFFERSPROC, glGenBuffers, true); + GET(PFNGLFRAMEBUFFERTEXTURE2DPROC, glFramebufferTexture2D, true); + GET(PFNGLGENRENDERBUFFERSPROC, glGenRenderbuffers, true); + GET(PFNGLBINDRENDERBUFFERPROC, glBindRenderbuffer, true); + GET(PFNGLBINDBUFFERPROC, glBindBuffer, true); + GET(PFNGLBUFFERDATAPROC, glBufferData, true); + GET(PFNGLRENDERBUFFERSTORAGEPROC, glRenderbufferStorage, true); + GET(PFNGLFRAMEBUFFERRENDERBUFFERPROC, glFramebufferRenderbuffer, true); + GET(PFNGLCHECKFRAMEBUFFERSTATUSPROC, glCheckFramebufferStatus, true); + GET(PFNGLDELETEFRAMEBUFFERSPROC, glDeleteFramebuffers, true); + GET(PFNGLDELETERENDERBUFFERSPROC, glDeleteRenderbuffers, true); + GET(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer, true); + GET(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray, true); + GET(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray, true); + GET(PFNGLUNIFORMMATRIX4FVARBPROC, glUniformMatrix4fv, true); + GET(PFNGLBINDATTRIBLOCATIONPROC, glBindAttribLocation, true); + GET(PFNGLCOMPRESSEDTEXIMAGE2DPROC, glCompressedTexImage2D, true); + GET(PFNGLGETSHADERIVPROC, glGetShaderiv, true); + GET(PFNGLGETPROGRAMIVPROC, glGetProgramiv, true); + GET(PFNGLDELETESHADERPROC, glDeleteShader, true); + GET(PFNGLDELETEBUFFERSPROC, glDeleteBuffers, true); + GET(PFNGLDELETEPROGRAMPROC, glDeleteProgram, true); + GET(PFNGLDETACHSHADERPROC, glDetachShader, true); + GET(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog, true); + GET(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog, true); + + // Stuff we can live without: + GET(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray, false); + GET(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays, false); + GET(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays, false); + GET(PFNGLBLITFRAMEBUFFERPROC, glBlitFramebuffer, false); + GET(PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC, glRenderbufferStorageMultisample, + false); + +#undef GET +#endif // BA_OSTYPE_WINDOWS + + // So that our window comes up nice and black. + // FIXME should just make the window's blanking color black. + +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + // Not needed here. +#else + +#if BA_SDL2_BUILD + // Gonna wait and see if if still need this. +#else + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + SDL_GL_SwapBuffers(); +#endif // BA_SDL2_BUILD + +#endif // IOS/ANDROID +} +#pragma clang diagnostic pop + +void GLContext::SetVSync(bool enable) { + assert(InMainThread()); + +#if BA_OSTYPE_MACOS + CGLContextObj context = CGLGetCurrentContext(); + BA_PRECONDITION(context); + GLint sync = enable; + CGLSetParameter(context, kCGLCPSwapInterval, &sync); +#else + +#endif // BA_OSTYPE_MACOS +} + +GLContext::~GLContext() { + if (!InMainThread()) { + Log("Error: GLContext dying in non-graphics thread"); + } +#if BA_SDL2_BUILD + +#if BA_RIFT_BUILD + // (in rift we only have a window in 2d mode) + if (!IsVRMode()) { + BA_PRECONDITION_LOG(sdl_window_); + } +#else // BA_RIFT_MODE + BA_PRECONDITION_LOG(sdl_window_); +#endif // BA_RIFT_BUILD + + if (sdl_window_) { + SDL_DestroyWindow(sdl_window_); + sdl_window_ = nullptr; + } +#elif BA_SDL_BUILD + BA_PRECONDITION_LOG(surface_); + if (surface_) { + SDL_FreeSurface(surface_); + surface_ = nullptr; + } +#endif +} + +auto GLErrorToString(GLenum err) -> std::string { + switch (err) { + case GL_NO_ERROR: + return "GL_NO_ERROR"; + case GL_INVALID_ENUM: + return "GL_INVALID_ENUM"; + case GL_INVALID_VALUE: + return "GL_INVALID_VALUE"; + case GL_INVALID_OPERATION: + return "GL_INVALID_OPERATION"; + case GL_OUT_OF_MEMORY: + return "GL_OUT_OF_MEMORY"; + case GL_INVALID_FRAMEBUFFER_OPERATION: + return "GL_INVALID_FRAMEBUFFER_OPERATION"; + default: + return std::to_string(err); + } +} + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL diff --git a/src/ballistica/graphics/gl/gl_sys.h b/src/ballistica/graphics/gl/gl_sys.h new file mode 100644 index 00000000..6006502c --- /dev/null +++ b/src/ballistica/graphics/gl/gl_sys.h @@ -0,0 +1,201 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_GL_GL_SYS_H_ +#define BALLISTICA_GRAPHICS_GL_GL_SYS_H_ + +#if BA_ENABLE_OPENGL + +#if !BA_OSTYPE_WINDOWS +#define GL_GLEXT_PROTOTYPES +#endif + +#include + +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + +#if BA_USE_ES3_INCLUDES +#include +#include +#else +#if BA_SDL_BUILD +#include // needed for ios?... +#include +#else +// FIXME: According to https://developer.android.com/ndk/guides/stable_apis +// we can always link against ES3.1 now that we're API 21+, so we shouldn't +// need our funky stubs and function lookups anymore. +// (though we'll still need to check for availability of 3.x features) +#include +#include +#endif // BA_SDL_BUILD +#endif // BA_USE_ES3_INCLUDES + +// looks like these few defines are currently missing on android +// (s3tc works on some nvidia hardware) +#ifndef GL_COMPRESSED_RGB_S3TC_DXT1_EXT +#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT +#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT +#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 +#endif +#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT +#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#endif + +#else // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + +#if BA_SDL2_BUILD +#include +#elif BA_SDL_BUILD // BA_SDL2_BUILD +#define NO_SDL_GLEXT +#include +#endif // BA_SDL2_BUILD + +#if BA_OSTYPE_MACOS +#include +#endif // BA_OSTYPE_MACOS + +#endif // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + +#include "ballistica/core/object.h" +#include "ballistica/platform/min_sdl.h" + +#if BA_OSTYPE_ANDROID +extern PFNGLDISCARDFRAMEBUFFEREXTPROC _glDiscardFramebufferEXT; +#endif + +#if BA_OSTYPE_WINDOWS +#ifndef WGL_EXT_swap_control +#define WGL_EXT_swap_control 1 +typedef BOOL(WINAPI* PFNWGLSWAPINTERVALEXTPROC)(int interval); +typedef int(WINAPI* PFNWGLGETSWAPINTERVALEXTPROC)(VOID); // NOLINT +#endif // WGL_EXT_swap_control +extern PFNGLGETINTERNALFORMATIVPROC glGetInternalformativ; +extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC + glGetFramebufferAttachmentParameteriv; +extern PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate; +extern PFNGLACTIVETEXTUREPROC glActiveTexture; +extern PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTextureARB; +extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB; +extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB; +extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; +extern PFNGLCREATEPROGRAMPROC glCreateProgram; +extern PFNGLCREATESHADERPROC glCreateShader; +extern PFNGLSHADERSOURCEPROC glShaderSource; +extern PFNGLCOMPILESHADERPROC glCompileShader; +extern PFNGLLINKPROGRAMPROC glLinkProgram; +extern PFNGLGETINFOLOGARBPROC glGetInfoLogARB; +extern PFNGLATTACHSHADERPROC glAttachShader; +extern PFNGLUSEPROGRAMOBJECTARBPROC glUseProgram; +extern PFNGLGENERATEMIPMAPPROC glGenerateMipmap; +extern PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; +extern PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer; +extern PFNGLBINDVERTEXARRAYPROC glBindVertexArray; +extern PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; +extern PFNGLUNIFORM1IPROC glUniform1i; +extern PFNGLUNIFORM1FPROC glUniform1f; +extern PFNGLUNIFORM1FVPROC glUniform1fv; +extern PFNGLUNIFORM2FPROC glUniform2f; +extern PFNGLUNIFORM3FPROC glUniform3f; +extern PFNGLUNIFORM4FPROC glUniform4f; +extern PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; +extern PFNGLGENBUFFERSPROC glGenBuffers; +extern PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; +extern PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; +extern PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers; +extern PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer; +extern PFNGLBINDBUFFERPROC glBindBuffer; +extern PFNGLBUFFERDATAPROC glBufferData; +extern PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage; +extern PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample; +extern PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer; +extern PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; +extern PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; +extern PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers; +extern PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; +extern PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; +extern PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; +extern PFNGLUNIFORMMATRIX4FVARBPROC glUniformMatrix4fv; +extern PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation; +extern PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D; +extern PFNGLGETSHADERIVPROC glGetShaderiv; +extern PFNGLGETPROGRAMIVPROC glGetProgramiv; +extern PFNGLDELETESHADERPROC glDeleteShader; +extern PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; +extern PFNGLDELETEBUFFERSPROC glDeleteBuffers; +extern PFNGLDELETEPROGRAMPROC glDeleteProgram; +extern PFNGLDETACHSHADERPROC glDetachShader; +extern PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; +extern PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; +#endif // BA_OSTYPE_WINDOWS + +#ifndef GL_NV_texture_rectangle +#define GL_TEXTURE_RECTANGLE_NV 0x84F5 +#define GL_TEXTURE_BINDING_RECTANGLE_NV 0x84F6 +#define GL_PROXY_TEXTURE_RECTANGLE_NV 0x84F7 +#define GL_MAX_RECTANGLE_TEXTURE_SIZE_NV 0x84F8 +#endif +#ifndef GL_NV_texture_rectangle +#define GL_NV_texture_rectangle 1 +#endif + +// Support for gl object debug labeling. +#if BA_OSTYPE_IOS_TVOS +#define GL_LABEL_OBJECT(type, obj, label) glLabelObjectEXT(type, obj, 0, label) +#define GL_PUSH_GROUP_MARKER(label) glPushGroupMarkerEXT(0, label) +#define GL_POP_GROUP_MARKER() glPopGroupMarkerEXT() +#else +#define GL_LABEL_OBJECT(type, obj, label) ((void)0) +#define GL_PUSH_GROUP_MARKER(label) ((void)0) +#define GL_POP_GROUP_MARKER() ((void)0) +#endif + +namespace ballistica { + +auto GLErrorToString(GLenum err) -> std::string; + +// Container for OpenGL rendering context data. +class GLContext { + public: + GLContext(int target_res_x, int target_res_y, bool fullScreen); + ~GLContext(); + auto res_x() const -> int { return res_x_; } + auto res_y() const -> int { return res_y_; } + auto pixel_density() const -> float { return pixel_density_; } + void SetVSync(bool enable); + + // Currently no surface/window in this case. +#if BA_SDL2_BUILD + auto sdl_window() const -> SDL_Window* { + assert(sdl_window_); + return sdl_window_; + } +#elif BA_SDL_BUILD // BA_SDL2_BUILD + SDL_Surface* sdl_screen_surface() const { + assert(surface_); + return surface_; + } +#endif // BA_SDL2_BUILD + + private: +#if BA_SDL2_BUILD + SDL_Window* sdl_window_{}; + SDL_GLContext sdl_gl_context_{}; +#endif // BA_SDL2_BUILD + bool fullscreen_{}; + int res_x_{}; + int res_y_{}; + float pixel_density_{1.0f}; +#if BA_SDL_BUILD && !BA_SDL2_BUILD + SDL_Surface* surface_{}; +#endif +}; // GLContext + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL + +#endif // BALLISTICA_GRAPHICS_GL_GL_SYS_H_ diff --git a/src/ballistica/graphics/gl/renderer_gl.cc b/src/ballistica/graphics/gl/renderer_gl.cc new file mode 100644 index 00000000..0ac10649 --- /dev/null +++ b/src/ballistica/graphics/gl/renderer_gl.cc @@ -0,0 +1,6617 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#if BA_ENABLE_OPENGL +#include "ballistica/graphics/gl/renderer_gl.h" + +#include +#include +#include +#include +#include + +#include "ballistica/graphics/component/special_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/mesh/mesh_renderer_data.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/media/data/model_data.h" +#include "ballistica/media/data/model_renderer_data.h" +#include "ballistica/media/data/texture_preload_data.h" +#include "ballistica/media/data/texture_renderer_data.h" + +#if BA_OSTYPE_IOS_TVOS +#include "ballistica/platform/apple/apple_utils.h" +#endif + +#define MSAA_ERROR_TEST 0 + +#if BA_OSTYPE_ANDROID +#include +#include +#if !BA_USE_ES3_INCLUDES +#include "ballistica/platform/android/android_gl3.h" +#endif +#define glDepthRange glDepthRangef +#define glDiscardFramebufferEXT _glDiscardFramebufferEXT +#ifndef GL_RGB565_OES +#define GL_RGB565_OES 0x8D62 +#endif // GL_RGB565_OES +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define glClearDepth glClearDepthf +#endif // BA_OSTYPE_ANDROID + +#if BA_OSTYPE_MACOS +#include +#define glGenVertexArrays glGenVertexArraysAPPLE +#define glDeleteVertexArrays glDeleteVertexArraysAPPLE +#define glBindVertexArray glBindVertexArrayAPPLE +#endif // BA_OSTYPE_MACOS + +#if BA_OSTYPE_IOS_TVOS +void (*glInvalidateFramebuffer)(GLenum target, GLsizei num_attachments, + const GLenum* attachments) = nullptr; +#define glDepthRange glDepthRangef +#define glGenVertexArrays glGenVertexArraysOES +#define glDeleteVertexArrays glDeleteVertexArraysOES +#define glBindVertexArray glBindVertexArrayOES +#define glClearDepth glClearDepthf +#endif // BA_OSTYPE_IOS_TVOS + +// Turn this off to see how much blend overdraw is occurring. +#define ENABLE_BLEND 1 + +// Support legacy drawing purely for debugging (should migrate this to +// post-fixed pipeline). +#if BA_OSTYPE_MACOS +#define ENABLE_DEBUG_DRAWING 1 +#else +#define ENABLE_DEBUG_DRAWING 0 +#endif + +#ifndef GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#endif +#ifndef GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#endif + +#ifndef GL_ETC1_RGB8_OES +#define GL_ETC1_RGB8_OES 0x8D64 +#endif + +#ifndef GL_COMPRESSED_RGB8_ETC2 +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif + +#define CHECK_GL_ERROR _check_gl_error(__LINE__) + +// Handy to check gl stuff on opt builds. +#define FORCE_CHECK_GL_ERRORS 0 + +#if BA_DEBUG_BUILD || FORCE_CHECK_GL_ERRORS +#define DEBUG_CHECK_GL_ERROR _check_gl_error(__LINE__) +#else +#define DEBUG_CHECK_GL_ERROR ((void)0) +#endif + +// OpenGL ES uses precision.. regular GL doesn't +#if (BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID) +#define LOWP "lowp " +#define MEDIUMP "mediump " +#define HIGHP "highp " +#else +#define LOWP +#define MEDIUMP +#define HIGHP +#endif // (BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID) + +// FIXME: Should make proper blur work in VR (perhaps just pass a uniform? +#if BA_VR_BUILD +#define BLURSCALE "0.3 * " +#else +#define BLURSCALE +#endif + +namespace ballistica { + +// Lots of signed bitwise stuff happening in there; should tidy it up. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "bugprone-macro-parentheses" + +bool RendererGL::funky_depth_issue_set_{}; +bool RendererGL::funky_depth_issue_{}; +bool RendererGL::draws_shields_funny_{}; +bool RendererGL::draws_shields_funny_set_{}; + +GLint g_combined_texture_image_unit_count{}; +bool g_anisotropic_support{}; +bool g_vao_support{}; +float g_max_anisotropy{}; +bool g_discard_framebuffer_support{}; +bool g_invalidate_framebuffer_support{}; +bool g_blit_framebuffer_support{}; +bool g_framebuffer_multisample_support{}; +bool g_running_es3{}; +bool g_seamless_cube_maps{}; +int g_msaa_max_samples_rgb565{}; +int g_msaa_max_samples_rgb8{}; + +#if BA_OSTYPE_ANDROID +bool RendererGL::is_speedy_android_device_{}; +bool RendererGL::is_extra_speedy_android_device_{}; +#endif // BA_OSTYPE_ANDROID + +static void _check_gl_error(int line) { + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + const char* version = (const char*)glGetString(GL_VERSION); + const char* vendor = (const char*)glGetString(GL_VENDOR); + const char* renderer = (const char*)glGetString(GL_RENDERER); + Log("Error: OpenGL Error at line " + std::to_string(line) + ": " + + GLErrorToString(err) + "\nrenderer: " + renderer + + "\nvendor: " + vendor + "\nversion: " + version + + "\ntime: " + std::to_string(GetRealTime())); + } +} + +// Flags affecting shader creation. +enum ShaderFlag { + SHD_REFLECTION = 1, + SHD_TEXTURE = 1 << 1, + SHD_MODULATE = 1 << 2, + SHD_COLORIZE = 1 << 3, + SHD_LIGHT_SHADOW = 1 << 4, + SHD_WORLD_SPACE_PTS = 1 << 5, + SHD_DEBUG_PRINT = 1 << 6, + SHD_ADD = 1 << 7, + SHD_OBJ_TRANSPARENT = 1 << 8, + SHD_COLOR = 1 << 9, + SHD_EXP2 = 1 << 10, + SHD_CAMERA_ALIGNED = 1 << 11, + SHD_DISTORT = 1 << 12, + SHD_PREMULTIPLY = 1 << 13, + SHD_OVERLAY = 1 << 14, + SHD_EYES = 1 << 15, + SHD_COLORIZE2 = 1 << 16, + SHD_HIGHER_QUALITY = 1 << 17, + SHD_SHADOW = 1 << 18, + SHD_GLOW = 1 << 19, + SHD_MASKED = 1 << 20, + SHD_MASK_UV2 = 1 << 21, + SHD_CONDITIONAL = 1 << 22, + SHD_FLATNESS = 1 << 23, + SHD_DEPTH_BUG_TEST = 1 << 24 +}; + +// Flags used internally by shaders. +enum ShaderPrivateFlags { + PFLAG_USES_POSITION_ATTR = 1, + PFLAG_USES_UV_ATTR = 1 << 1, + PFLAG_USES_NORMAL_ATTR = 1 << 2, + PFLAG_USES_MODEL_WORLD_MATRIX = 1 << 3, + PFLAG_USES_CAM_POS = 1 << 4, + PFLAG_USES_SHADOW_PROJECTION_MATRIX = 1 << 5, + PFLAG_WORLD_SPACE_PTS = 1 << 6, + PFLAG_USES_ERODE_ATTR = 1 << 7, + PFLAG_USES_COLOR_ATTR = 1 << 8, + PFLAG_USES_SIZE_ATTR = 1 << 9, + PFLAG_USES_DIFFUSE_ATTR = 1 << 10, + PFLAG_USES_CAM_ORIENT_MATRIX = 1 << 11, + PFLAG_USES_MODEL_VIEW_MATRIX = 1 << 12, + PFLAG_USES_UV2_ATTR = 1 << 13 +}; + +// Look for a gl extension prefixed by "GL_ARB", "GL_EXT", etc +// returns true if found. +static auto CheckGLExtension(const char* exts, const char* ext) -> bool { + char b[128]; + snprintf(b, sizeof(b), "OES_%s", ext); + if (strstr(exts, b)) return true; + snprintf(b, sizeof(b), "GL_ARB_%s", ext); + if (strstr(exts, b)) return true; + snprintf(b, sizeof(b), "GL_APPLE_%s", ext); + if (strstr(exts, b)) return true; + snprintf(b, sizeof(b), "GL_EXT_%s", ext); + if (strstr(exts, b)) return true; + snprintf(b, sizeof(b), "GL_NV_%s", ext); + if (strstr(exts, b)) return true; + snprintf(b, sizeof(b), "GL_SGIS_%s", ext); + if (strstr(exts, b)) return true; + snprintf(b, sizeof(b), "GL_IMG_%s", ext); + return strstr(exts, b) != nullptr; +} + +void RendererGL::CheckGLExtensions() { + DEBUG_CHECK_GL_ERROR; + assert(InGraphicsThread()); + // const char *version_str = (const char*)glGetString(GL_VERSION); + + const char* ex = (const char*)glGetString(GL_EXTENSIONS); + assert(ex); + // Log(ex); + + // Log(string("GL VERSION: ")+version_str); + + draws_shields_funny_set_ = true; + + // const char *renderer = (const char*)glGetString(GL_RENDERER); + // const char *vendor = (const char*)glGetString(GL_VENDOR); + // const char *version_str = (const char*)glGetString(GL_VERSION); + // printf("RENDERER %s\nVENDOR %s\nVERSION %s\n",renderer,vendor,version_str); + + // on android, look at the GL version and try to get gl3 funcs to determine if + // we're running ES3 or not +#if BA_OSTYPE_ANDROID + + const char* renderer = (const char*)glGetString(GL_RENDERER); + const char* vendor = (const char*)glGetString(GL_VENDOR); + const char* version_str = (const char*)glGetString(GL_VERSION); + // Log(string("VER ")+version_str); + + bool have_es3; + +#if BA_USE_ES3_INCLUDES + have_es3 = true; +#else + have_es3 = (strstr(version_str, "OpenGL ES 3.") && gl3stubInit()); +#endif + + // if we require ES3 + if (have_es3) { + g_running_es3 = true; + Log(std::string("Using OpenGL ES 3 (vendor: ") + vendor + + ", renderer: " + renderer + ", version: " + version_str + ")", + false, false); + + } else { +#if !BA_USE_ES3_INCLUDES + g_running_es3 = false; + Log(std::string("USING OPENGL ES2 (vendor: ") + vendor + + ", renderer: " + renderer + ", version: " + version_str + ")", + false, false); + + // Can still support some stuff like framebuffer-blit with es2 extensions. + assert(glBlitFramebuffer == nullptr || !first_extension_check_); + glBlitFramebuffer = + (decltype(glBlitFramebuffer))eglGetProcAddress("glBlitFramebufferNV"); + assert(glRenderbufferStorageMultisample == nullptr + || !first_extension_check_); + glRenderbufferStorageMultisample = + (decltype(glRenderbufferStorageMultisample))eglGetProcAddress( + "glRenderbufferStorageMultisampleNV"); + + assert(glGenVertexArrays == nullptr || !first_extension_check_); + glGenVertexArrays = + (decltype(glGenVertexArrays))eglGetProcAddress("glGenVertexArraysOES"); + assert(glDeleteVertexArrays == nullptr || !first_extension_check_); + glDeleteVertexArrays = (decltype(glDeleteVertexArrays))eglGetProcAddress( + "glDeleteVertexArraysOES"); + assert(glBindVertexArray == nullptr || !first_extension_check_); + glBindVertexArray = + (decltype(glBindVertexArray))eglGetProcAddress("glBindVertexArrayOES"); + +#endif // BA_USE_ES3_INCLUDES + } + + DEBUG_CHECK_GL_ERROR; + + // Flag certain devices as 'speedy' - we use this to enable high/higher + // quality and whatnot (even in cases where ES3 isnt available). + is_speedy_android_device_ = false; + is_extra_speedy_android_device_ = false; + is_adreno_ = (strstr(renderer, "Adreno") != nullptr); + draws_shields_funny_ = false; // start optimistic. + + // ali tv box + if (!strcmp(renderer, "Mali-450 MP")) { + is_speedy_android_device_ = true; // this is borderline speedy/extra-speedy + draws_shields_funny_ = true; + } + + // firetv, etc.. lets enable MSAA + if (!strcmp(renderer, "Adreno (TM) 320")) { + is_recent_adreno_ = true; + } + + // this is right on the borderline, but lets go with extra-speedy i guess + if (!strcmp(renderer, "Adreno (TM) 330")) { + is_recent_adreno_ = true; + is_extra_speedy_android_device_ = true; + } + + // *any* of the 4xx or 5xx series are extra-speedy + if (strstr(renderer, "Adreno (TM) 4") || strstr(renderer, "Adreno (TM) 5") + || strstr(renderer, "Adreno (TM) 6")) { + is_extra_speedy_android_device_ = true; + is_recent_adreno_ = true; + } + + // some speedy malis (Galaxy S6 / Galaxy S7-ish) + if (strstr(renderer, "Mali-T760") || strstr(renderer, "Mali-T860") + || strstr(renderer, "Mali-T880")) { + is_extra_speedy_android_device_ = true; + } + // Note 8 is speed-tastic + if (!strcmp(renderer, "Mali-G71") || !strcmp(renderer, "Mali-G72")) { + is_extra_speedy_android_device_ = true; + } + + // covers Nexus player + // HMM Scratch that - this winds up being too slow for phones using this chip. + if (strstr(renderer, "PowerVR Rogue G6430")) { + // is_extra_speedy_android_device_ = true; + } + + // Figure out if we're a Tegra 4/K1/etc since we do some special stuff on + // those... + if (!strcmp(renderer, "NVIDIA Tegra")) { + // tegra 4 won't have ES3 but will have framebuffer_multisample + if (!g_running_es3 && CheckGLExtension(ex, "framebuffer_multisample")) { + is_tegra_4_ = true; + is_speedy_android_device_ = true; + } else if (g_running_es3) { + // running ES3 - must be a K1 (for now) + is_tegra_k1_ = true; + is_extra_speedy_android_device_ = true; + } else { + // looks like Tegra-2 era stuff was just "NVIDIA Tegra" as well... + } + } + + // Also store this globally for a few other bits of the app to use.. + g_platform->set_is_tegra_k1(is_tegra_k1_); + + // Extra-speedy implies speedy too.. + if (is_extra_speedy_android_device_) { + is_speedy_android_device_ = true; + } + +#endif // BA_OSTYPE_ANDROID + + std::list c_types; + assert(g_graphics); + if (CheckGLExtension(ex, "texture_compression_s3tc")) + c_types.push_back(TextureCompressionType::kS3TC); + + // Limiting pvr support to iOS for the moment. +#if !BA_OSTYPE_ANDROID + if (CheckGLExtension(ex, "texture_compression_pvrtc")) + c_types.push_back(TextureCompressionType::kPVR); +#endif + + // All android devices should support etc1. + if (CheckGLExtension(ex, "compressed_ETC1_RGB8_texture")) { + c_types.push_back(TextureCompressionType::kETC1); + } else { +#if BA_OSTYPE_ANDROID + Log("Android device missing ETC1 support"); +#endif + } + + // ETC2 is required for ES3 support (and OpenGL 4.4 or something once we + // eventually get there) + if (g_running_es3) c_types.push_back(TextureCompressionType::kETC2); + + g_graphics_server->SetTextureCompressionTypes(c_types); + + // Check whether we support high-quality mode (requires a few things like + // depth textures) For now lets also disallow high-quality in some VR + // environments. + + if (CheckGLExtension(ex, "depth_texture")) { + supports_depth_textures_ = true; +#if BA_CARDBOARD_BUILD + g_graphics->SetSupportsHighQualityGraphics(false); +#else // BA_CARDBOARD_BUILD + g_graphics->SetSupportsHighQualityGraphics(true); +#endif // BA_CARDBOARD_BUILD + } else { + supports_depth_textures_ = false; + g_graphics->SetSupportsHighQualityGraphics(false); + } + + // Store the tex-compression type we support. + DEBUG_CHECK_GL_ERROR; + + g_anisotropic_support = CheckGLExtension(ex, "texture_filter_anisotropic"); + if (g_anisotropic_support) { + glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &g_max_anisotropy); + } + + DEBUG_CHECK_GL_ERROR; + + // We can run with our without VAOs but they're nice to have. + g_vao_support = + (glGenVertexArrays != nullptr && glDeleteVertexArrays != nullptr + && glBindVertexArray != nullptr + && (g_running_es3 || CheckGLExtension(ex, "vertex_array_object"))); + +#if BA_OSTYPE_IOS_TVOS + g_blit_framebuffer_support = false; + g_framebuffer_multisample_support = false; +#elif BA_OSTYPE_MACOS + g_blit_framebuffer_support = CheckGLExtension(ex, "framebuffer_blit"); + g_framebuffer_multisample_support = false; +#else + g_blit_framebuffer_support = + (glBlitFramebuffer != nullptr + && (g_running_es3 || CheckGLExtension(ex, "framebuffer_blit"))); + g_framebuffer_multisample_support = + (glRenderbufferStorageMultisample != nullptr + && (g_running_es3 || (CheckGLExtension(ex, "framebuffer_multisample")))); +#endif + +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + +#if BA_OSTYPE_IOS_TVOS + g_discard_framebuffer_support = CheckGLExtension(ex, "discard_framebuffer"); +#else + g_discard_framebuffer_support = + (glDiscardFramebufferEXT != nullptr + && CheckGLExtension(ex, "discard_framebuffer")); +#endif + + g_invalidate_framebuffer_support = + (g_running_es3 && glInvalidateFramebuffer != nullptr); +#else + g_discard_framebuffer_support = false; + g_invalidate_framebuffer_support = false; +#endif + + g_seamless_cube_maps = CheckGLExtension(ex, "seamless_cube_map"); + +#if BA_OSTYPE_WINDOWS + // the vmware gl driver breaks horrifically with VAOs turned on + const char* vendor = (const char*)glGetString(GL_VENDOR); + if (strstr(vendor, "VMware")) { + g_vao_support = false; + } +#endif + +#if BA_OSTYPE_ANDROID + // VAOs currently break my poor kindle fire hd to the point of rebooting it + if (!g_running_es3 && !is_tegra_4_) { + g_vao_support = false; + } + + // also they seem to be problematic on zenfone2's gpu. + if (strstr(renderer, "PowerVR Rogue G6430")) { + g_vao_support = false; + } +#endif + + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, + &g_combined_texture_image_unit_count); + + // If we're running ES3, ask about our max multisample counts and whether we + // can enable MSAA. + // enable_msaa_ = false; // start pessimistic + g_msaa_max_samples_rgb565 = g_msaa_max_samples_rgb8 = 0; // start pessimistic + +#if BA_OSTYPE_ANDROID || BA_RIFT_BUILD + bool check_msaa = false; + +#if BA_OSTYPE_ANDROID + if (g_running_es3) { + check_msaa = true; + } +#endif // BA_OSTYPE_ANDROID +#if BA_RIFT_BUILD + check_msaa = true; +#endif // BA_RIFT_BUILD + + if (check_msaa) { + if (glGetInternalformativ != nullptr) { + GLint count; + glGetInternalformativ(GL_RENDERBUFFER, GL_RGB565, GL_NUM_SAMPLE_COUNTS, 1, + &count); + if (count > 0) { + std::vector samples; + samples.resize(static_cast(static_cast(count))); + glGetInternalformativ(GL_RENDERBUFFER, GL_RGB565, GL_SAMPLES, count, + &samples[0]); + g_msaa_max_samples_rgb565 = samples[0]; + } else { + BA_LOG_ONCE("Got 0 samplecounts for RGB565"); + g_msaa_max_samples_rgb565 = 0; + } + } + // RGB8 max multisamples + if (glGetInternalformativ != nullptr) { + GLint count; + glGetInternalformativ(GL_RENDERBUFFER, GL_RGB8, GL_NUM_SAMPLE_COUNTS, 1, + &count); + if (count > 0) { + std::vector samples; + samples.resize(static_cast(count)); + glGetInternalformativ(GL_RENDERBUFFER, GL_RGB8, GL_SAMPLES, count, + &samples[0]); + g_msaa_max_samples_rgb8 = samples[0]; + } else { + BA_LOG_ONCE("Got 0 samplecounts for RGB8"); + g_msaa_max_samples_rgb8 = 0; + } + } + } else { + if (is_tegra_4_) { + // HMM is there a way to query this without ES3? + g_msaa_max_samples_rgb8 = g_msaa_max_samples_rgb565 = 4; + } + } + +#if MSAA_ERROR_TEST + if (enable_msaa_) { + ScreenMessage("MSAA ENABLED"); + Log("Ballistica MSAA Test: MSAA ENABLED", false, false); + } else { + ScreenMessage("MSAA DISABLED"); + Log("Ballistica MSAA Test: MSAA DISABLED", false, false); + } +#endif // MSAA_ERROR_TEST + +#endif // BA_OSTYPE_ANDROID + + DEBUG_CHECK_GL_ERROR; + + first_extension_check_ = false; +} + +auto RendererGL::GetMSAASamplesForFramebuffer(int width, int height) -> int { +#if BA_RIFT_BUILD + return 4; +#else + // we currently aim for 4 up to 800 height and 2 beyond that.. + if (height > 800) { + return 2; + } else { + return 4; + } +#endif +} + +void RendererGL::UpdateMSAAEnabled() { +#if BA_RIFT_BUILD + if (g_msaa_max_samples_rgb8 > 0) { + enable_msaa_ = true; + } else { + enable_msaa_ = false; + } +#else + + // lets allow full 1080p msaa with newer stuff.. + int max_msaa_res = is_tegra_k1_ ? 1200 : 800; + + // to start, see if it looks like we support msaa on paper.. + enable_msaa_ = + ((screen_render_target()->physical_height() + <= static_cast(max_msaa_res)) + && (g_msaa_max_samples_rgb8 > 0) && (g_msaa_max_samples_rgb565 > 0)); + + // ok, lets be careful here.. msaa blitting/etc seems to be particular in + // terms of supported formats/etc so let's only enable it on explicitly-tested + // hardware. + if (!is_tegra_4_ && !is_tegra_k1_ && !is_recent_adreno_) { + enable_msaa_ = false; + } + +#endif // BA_RIFT_BUILD +} + +auto RendererGL::IsMSAAEnabled() const -> bool { return enable_msaa_; } + +static auto GetGLTextureFormat(TextureFormat f) -> GLenum { + switch (f) { + case TextureFormat::kDXT1: + return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case TextureFormat::kDXT5: + return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case TextureFormat::kPVR2: + return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + break; + case TextureFormat::kPVR4: + return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + break; + case TextureFormat::kETC1: + return GL_ETC1_RGB8_OES; + break; + case TextureFormat::kETC2_RGB: + return GL_COMPRESSED_RGB8_ETC2; + break; + case TextureFormat::kETC2_RGBA: + return GL_COMPRESSED_RGBA8_ETC2_EAC; + break; + default: + throw Exception("Invalid TextureFormat: " + + std::to_string(static_cast(f))); + } +} + +// a stand-in for vertex-array-objects for use on systems that don't support +// them directly +class RendererGL::FakeVertexArrayObject { + public: + struct AttrState { + bool enable; + GLuint buffer; + int elem_count; + GLenum elem_type; + bool normalized; + int stride; + size_t offset; + }; + + explicit FakeVertexArrayObject(RendererGL* renderer) + : renderer_(renderer), elem_buffer_(0) { + for (auto& attr : attrs_) { + attr.enable = false; + } + } + + void Bind() { + DEBUG_CHECK_GL_ERROR; + + // First bind our element buffer. + assert(elem_buffer_ != 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elem_buffer_); + + // Now bind/enable the buffers we use and disable the ones we don't. + for (GLuint i = 0; i < kVertexAttrCount; i++) { + if (attrs_[i].enable) { + renderer_->BindArrayBuffer(attrs_[i].buffer); + glVertexAttribPointer(i, attrs_[i].elem_count, attrs_[i].elem_type, + static_cast(attrs_[i].normalized), + attrs_[i].stride, + reinterpret_cast(attrs_[i].offset)); + } + renderer_->SetVertexAttribArrayEnabled(i, attrs_[i].enable); + } + DEBUG_CHECK_GL_ERROR; + } + void SetElementBuffer(GLuint vbo) { elem_buffer_ = vbo; } + void SetAttribBuffer(GLuint buffer, VertexAttr attr, int elem_count, + GLenum elem_type, bool normalized, int stride, + size_t offset) { + assert(attr < RendererGL::kVertexAttrCount); + assert(!attrs_[attr].enable); + attrs_[attr].enable = true; + attrs_[attr].buffer = buffer; + attrs_[attr].elem_count = elem_count; + attrs_[attr].elem_type = elem_type; + attrs_[attr].normalized = normalized; + attrs_[attr].stride = stride; + attrs_[attr].offset = offset; + } + + AttrState attrs_[RendererGL::kVertexAttrCount]{}; + RendererGL* renderer_{}; + GLuint elem_buffer_{}; +}; + +class RendererGL::FramebufferObjectGL : public Framebuffer { + public: + FramebufferObjectGL(RendererGL* renderer_in, int width_in, int height_in, + bool linear_interp_in, bool depth_in, bool is_texture_in, + bool depth_is_texture_in, bool high_quality_in, + bool msaa_in, bool alpha_in) + : width_(width_in), + height_(height_in), + linear_interp_(linear_interp_in), + depth_(depth_in), + is_texture_(is_texture_in), + depth_is_texture_(depth_is_texture_in), + renderer_(renderer_in), + high_quality_(high_quality_in), + msaa_(msaa_in), + alpha_(alpha_in) { + // Desktop stuff is always high-quality +#if BA_OSTYPE_MACOS || BA_OSTYPE_LINUX || BA_OSTYPE_WINDOWS + high_quality_ = true; +#endif + + // Things are finally getting to the point where we can default to + // desktop quality on some mobile stuff. +#if BA_OSTYPE_ANDROID + if (renderer_->is_tegra_k1_) { + high_quality_ = true; + } +#endif + + Load(); + } + + ~FramebufferObjectGL() override { Unload(); } + + void Load(bool force_low_quality = false) { + if (loaded_) return; + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + GLenum status; + DEBUG_CHECK_GL_ERROR; + glGenFramebuffers(1, &framebuffer_); + renderer_->BindFramebuffer(framebuffer_); + DEBUG_CHECK_GL_ERROR; + bool do_high_quality = high_quality_; + if (force_low_quality) do_high_quality = false; + int samples = 0; + if (msaa_) { + // Can't multisample with texture buffers currently. + assert(!is_texture_ && !depth_is_texture_); + + int target_samples = + renderer_->GetMSAASamplesForFramebuffer(width_, height_); + + if (do_high_quality) { + samples = std::min(target_samples, g_msaa_max_samples_rgb8); + } else { + samples = std::min(target_samples, g_msaa_max_samples_rgb565); + } + } + if (is_texture_) { + // attach a texture for the color target + glGenTextures(1, &texture_); + renderer_->BindTexture(GL_TEXTURE_2D, texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + linear_interp_ ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + linear_interp_ ? GL_LINEAR : GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + // On android/ios lets go with 16 bit unless they explicitly request high + // quality. +#if BA_OSTYPE_ANDROID || BA_OSTYPE_IOS_TVOS + GLenum format; + if (alpha_) { + format = do_high_quality ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_4_4_4_4; + } else { + format = do_high_quality ? GL_UNSIGNED_BYTE : GL_UNSIGNED_SHORT_5_6_5; + } +#else + GLenum format = GL_UNSIGNED_BYTE; +#endif + // if (srgbTest) { + // Log("YOOOOOOO"); + // glTexImage2D(GL_TEXTURE_2D, 0, alpha_?GL_SRGB8_ALPHA8:GL_SRGB8, + // _width, _height, 0, alpha_?GL_RGBA:GL_RGB, format, nullptr); + // } else { + glTexImage2D(GL_TEXTURE_2D, 0, alpha_ ? GL_RGBA : GL_RGB, width_, height_, + 0, alpha_ ? GL_RGBA : GL_RGB, format, nullptr); + // } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, texture_, 0); + } else { + // Regular renderbuffer. + assert(!alpha_); // fixme +#if BA_OSTYPE_IOS_TVOS + GLenum format = + GL_RGB565; // FIXME; need to pull ES3 headers in for GL_RGB8 +#elif BA_OSTYPE_ANDROID + GLenum format = do_high_quality ? GL_RGB8 : GL_RGB565; +#else + GLenum format = GL_RGB8; +#endif + glGenRenderbuffers(1, &render_buffer_); + DEBUG_CHECK_GL_ERROR; + glBindRenderbuffer(GL_RENDERBUFFER, render_buffer_); + DEBUG_CHECK_GL_ERROR; + if (samples > 0) { +#if BA_OSTYPE_IOS_TVOS + throw Exception(); +#else + glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, format, + width_, height_); +#endif + } else { + glRenderbufferStorage(GL_RENDERBUFFER, format, width_, height_); + } + DEBUG_CHECK_GL_ERROR; + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, render_buffer_); + DEBUG_CHECK_GL_ERROR; + } + DEBUG_CHECK_GL_ERROR; + if (depth_) { + if (depth_is_texture_) { + glGenTextures(1, &depth_texture_); + DEBUG_CHECK_GL_ERROR; + renderer_->BindTexture(GL_TEXTURE_2D, depth_texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + DEBUG_CHECK_GL_ERROR; + // fixme - need to pull in ES3 stuff for iOS to get GL_DEPTH_COMPONENT24 +#if BA_OSTYPE_IOS_TVOS + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width_, height_, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr); +#else + if (do_high_quality) { +#if BA_OSTYPE_ANDROID + assert(g_running_es3); +#endif // BA_OSTYPE_ANDROID + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, width_, height_, + 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, nullptr); + } else { + glTexImage2D( + GL_TEXTURE_2D, 0, + g_running_es3 ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT, width_, + height_, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, nullptr); + } +#endif // BA_OSTYPE_IOS_TVOS + + DEBUG_CHECK_GL_ERROR; + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_TEXTURE_2D, depth_texture_, 0); + + DEBUG_CHECK_GL_ERROR; + } else { + // Just use a plain old renderbuffer if we don't need it as a texture + // (this is more widely supported). + glGenRenderbuffers(1, &depth_render_buffer_); + DEBUG_CHECK_GL_ERROR; + glBindRenderbuffer(GL_RENDERBUFFER, depth_render_buffer_); + DEBUG_CHECK_GL_ERROR; + + if (samples > 0) { +#if BA_OSTYPE_IOS_TVOS + throw Exception(); +#else + // (GL_DEPTH_COMPONENT24 not available in ES2 it looks like) + bool do24; +#if BA_OSTYPE_ANDROID + do24 = (do_high_quality && g_running_es3); +#else + do24 = do_high_quality; +#endif + + glRenderbufferStorageMultisample( + GL_RENDERBUFFER, samples, + do24 ? GL_DEPTH_COMPONENT24 : GL_DEPTH_COMPONENT16, width_, + height_); + // (do_high_quality && + // g_running_es3)?GL_DEPTH_COMPONENT24:GL_DEPTH_COMPONENT16, _width, + // _height); +#endif + } else { + // FIXME - need to pull in es3 headers to get GL_DEPTH_COMPONENT24 on + // iOS +#if BA_OSTYPE_IOS_TVOS + GLenum format = GL_DEPTH_COMPONENT16; +#else + // (GL_DEPTH_COMPONENT24 not available in ES2 it looks like) + GLenum format = (do_high_quality && g_running_es3) + ? GL_DEPTH_COMPONENT24 + : GL_DEPTH_COMPONENT16; +#endif + + glRenderbufferStorage(GL_RENDERBUFFER, format, width_, height_); + } + + DEBUG_CHECK_GL_ERROR; + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, + GL_RENDERBUFFER, depth_render_buffer_); + DEBUG_CHECK_GL_ERROR; + } + } + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + const char* version = (const char*)glGetString(GL_VERSION); + const char* vendor = (const char*)glGetString(GL_VENDOR); + const char* renderer = (const char*)glGetString(GL_RENDERER); + throw Exception( + "Framebuffer setup failed for " + std::to_string(width_) + " by " + + std::to_string(height_) + " fb with depth " + std::to_string(depth_) + + " asTex " + std::to_string(depth_is_texture_) + " gl-version " + + version + " vendor " + vendor + " renderer " + renderer); + } + // GLint enc; + // glGetFramebufferAttachmentParameteriv(GL_FRAMEBUFFER, + // GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING, &enc); if + // (enc == GL_SRGB) { + // Log("GOT SRGB!!!!!!!!!!!"); + // } else if (enc == GL_LINEAR) { + // Log("GOT LINEAR..."); + // } else { + // Log("GOT OTHER.."); + // } + loaded_ = true; + } + + void Unload() { + assert(InGraphicsThread()); + if (!loaded_) return; + + // If our textures are currently bound as anything, clear that out. + // (otherwise a new texture with that same ID won't be bindable) + for (int& i : renderer_->bound_textures_2d_) { + if (i == texture_) { // NOLINT(bugprone-branch-clone) + i = -1; + } else if (depth_ && (i == depth_texture_)) { + i = -1; + } + } + + if (!g_graphics_server->renderer_context_lost()) { + // Tear down the FBO and texture attachment + if (is_texture_) { + glDeleteTextures(1, &texture_); + } else { + glDeleteRenderbuffers(1, &render_buffer_); + } + if (depth_) { + if (depth_is_texture_) { + glDeleteTextures(1, &depth_texture_); + } else { + glDeleteRenderbuffers(1, &depth_render_buffer_); + } + DEBUG_CHECK_GL_ERROR; + } + + // If this one is current, make sure we re-bind next time. + // (otherwise we might prevent a new framebuffer with a recycled id from + // binding) + if (renderer_->active_framebuffer_ == framebuffer_) { + renderer_->active_framebuffer_ = -1; + } + glDeleteFramebuffers(1, &framebuffer_); + DEBUG_CHECK_GL_ERROR; + } + loaded_ = false; + } + + void Bind() { + assert(InGraphicsThread()); + renderer_->BindFramebuffer(framebuffer_); + // if (time(nullptr)%2 == 0) { + // glDisable(GL_FRAMEBUFFER_SRGB); + // } + } + + auto texture() const -> GLuint { + assert(is_texture_); + return texture_; + } + + auto depth_texture() const -> GLuint { + assert(depth_ && depth_is_texture_); + return depth_texture_; + } + + auto width() const -> int { return width_; } + auto height() const -> int { return height_; } + auto id() const -> GLuint { return framebuffer_; } + + private: + RendererGL* renderer_{}; + bool depth_{}; + bool is_texture_{}; + bool depth_is_texture_{}; + bool high_quality_{}; + bool msaa_{}; + bool alpha_{}; + bool linear_interp_{}; + bool loaded_{}; + int width_{}, height_{}; + GLuint framebuffer_{}, texture_{}, depth_texture_{}, render_buffer_{}, + depth_render_buffer_{}; +}; // FramebufferObject + +// Base class for fragment/vertex shaders. +class RendererGL::ShaderGL : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kMain; + } + + ShaderGL(GLenum type_in, const std::string& src_in) : type_(type_in) { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + assert(type_ == GL_FRAGMENT_SHADER || type_ == GL_VERTEX_SHADER); + shader_ = glCreateShader(type_); + DEBUG_CHECK_GL_ERROR; + BA_PRECONDITION(shader_); + const char* s = src_in.c_str(); + glShaderSource(shader_, 1, &s, nullptr); + glCompileShader(shader_); + GLint compile_status; + glGetShaderiv(shader_, GL_COMPILE_STATUS, &compile_status); + if (compile_status == GL_FALSE) { + const char* version = (const char*)glGetString(GL_VERSION); + const char* vendor = (const char*)glGetString(GL_VENDOR); + const char* renderer = (const char*)glGetString(GL_RENDERER); + // Let's not crash here. We have a better chance of calling home this way + // and theres a chance the game will still be playable. + Log(std::string("Compile failed for ") + GetTypeName() + + " shader:\n------------SOURCE BEGIN-------------\n" + src_in + + "\n-----------SOURCE END-------------\n" + GetInfo() + + "\nrenderer: " + renderer + "\nvendor: " + vendor + + "\nversion:" + version); + } else { + assert(compile_status == GL_TRUE); + std::string info = GetInfo(); + if (!info.empty() + && (strstr(info.c_str(), "error:") || strstr(info.c_str(), "warning:") + || strstr(info.c_str(), "Error:") + || strstr(info.c_str(), "Warning:"))) { + const char* version = (const char*)glGetString(GL_VERSION); + const char* vendor = (const char*)glGetString(GL_VENDOR); + const char* renderer = (const char*)glGetString(GL_RENDERER); + Log(std::string("WARNING: info returned for ") + GetTypeName() + + " shader:\n------------SOURCE BEGIN-------------\n" + src_in + + "\n-----------SOURCE END-------------\n" + info + "\nrenderer: " + + renderer + "\nvendor: " + vendor + "\nversion:" + version); + } + } + DEBUG_CHECK_GL_ERROR; + } + ~ShaderGL() override { + assert(InGraphicsThread()); + if (!g_graphics_server->renderer_context_lost()) { + glDeleteShader(shader_); + DEBUG_CHECK_GL_ERROR; + } + } + auto shader() const -> GLuint { return shader_; } + + private: + auto GetTypeName() const -> const char* { + if (type_ == GL_VERTEX_SHADER) { + return "vertex"; + } else { + return "fragment"; + } + } + auto GetInfo() -> std::string { + static char log[1024]; + GLsizei log_size; + glGetShaderInfoLog(shader_, sizeof(log), &log_size, log); + return log; + } + std::string name_; + GLuint shader_{}; + GLenum type_{}; + BA_DISALLOW_CLASS_COPIES(ShaderGL); +}; // ShaderGL + +//----------------------------------------------------------------- + +class RendererGL::FragmentShaderGL : public RendererGL::ShaderGL { + public: + explicit FragmentShaderGL(const std::string& src_in) + : ShaderGL(GL_FRAGMENT_SHADER, src_in) {} +}; + +//------------------------------------------------------------------- + +class RendererGL::VertexShaderGL : public RendererGL::ShaderGL { + public: + explicit VertexShaderGL(const std::string& src_in) + : ShaderGL(GL_VERTEX_SHADER, src_in) {} +}; + +//------------------------------------------------------------------- + +class RendererGL::ProgramGL { + public: + ProgramGL(RendererGL* renderer, + const Object::Ref& vertex_shader_in, + const Object::Ref& fragment_shader_in, + std::string name, int pflags) + : fragment_shader_(fragment_shader_in), + vertex_shader_(vertex_shader_in), + renderer_(renderer), + pflags_(pflags), + name_(std::move(name)) { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + program_ = glCreateProgram(); + BA_PRECONDITION(program_); + glAttachShader(program_, fragment_shader_->shader()); + glAttachShader(program_, vertex_shader_->shader()); + assert(pflags_ & PFLAG_USES_POSITION_ATTR); + if (pflags_ & PFLAG_USES_POSITION_ATTR) + glBindAttribLocation(program_, kVertexAttrPosition, "position"); + if (pflags_ & PFLAG_USES_UV_ATTR) + glBindAttribLocation(program_, kVertexAttrUV, "uv"); + if (pflags_ & PFLAG_USES_NORMAL_ATTR) + glBindAttribLocation(program_, kVertexAttrNormal, "normal"); + if (pflags_ & PFLAG_USES_ERODE_ATTR) + glBindAttribLocation(program_, kVertexAttrErode, "erode"); + if (pflags_ & PFLAG_USES_COLOR_ATTR) + glBindAttribLocation(program_, kVertexAttrColor, "color"); + if (pflags_ & PFLAG_USES_SIZE_ATTR) + glBindAttribLocation(program_, kVertexAttrSize, "size"); + if (pflags_ & PFLAG_USES_DIFFUSE_ATTR) + glBindAttribLocation(program_, kVertexAttrDiffuse, "diffuse"); + if (pflags_ & PFLAG_USES_UV2_ATTR) + glBindAttribLocation(program_, kVertexAttrUV2, "uv2"); + glLinkProgram(program_); + GLint linkStatus; + glGetProgramiv(program_, GL_LINK_STATUS, &linkStatus); + if (linkStatus == GL_FALSE) { + Log("Link failed for program '" + name_ + "':\n" + GetInfo()); + } else { + assert(linkStatus == GL_TRUE); + + std::string info = GetInfo(); + if (!info.empty() + && (strstr(info.c_str(), "error:") || strstr(info.c_str(), "warning:") + || strstr(info.c_str(), "Error:") + || strstr(info.c_str(), "Warning:"))) { + Log("WARNING: program using frag shader '" + name_ + + "' returned info:\n" + info); + } + } + + // go ahead and bind ourself so child classes can config uniforms and + // whatnot + Bind(); + mvp_uniform_ = glGetUniformLocation(program_, "modelViewProjectionMatrix"); + assert(mvp_uniform_ != -1); + if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) { + model_world_matrix_uniform_ = + glGetUniformLocation(program_, "modelWorldMatrix"); + assert(model_world_matrix_uniform_ != -1); + } + if (pflags_ & PFLAG_USES_MODEL_VIEW_MATRIX) { + model_view_matrix_uniform_ = + glGetUniformLocation(program_, "modelViewMatrix"); + assert(model_view_matrix_uniform_ != -1); + } + if (pflags_ & PFLAG_USES_CAM_POS) { + cam_pos_uniform_ = glGetUniformLocation(program_, "camPos"); + assert(cam_pos_uniform_ != -1); + } + if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) { + cam_orient_matrix_uniform_ = + glGetUniformLocation(program_, "camOrientMatrix"); + assert(cam_orient_matrix_uniform_ != -1); + } + if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) { + light_shadow_projection_matrix_uniform_ = + glGetUniformLocation(program_, "lightShadowProjectionMatrix"); + assert(light_shadow_projection_matrix_uniform_ != -1); + } + } + + virtual ~ProgramGL() { + assert(InGraphicsThread()); + if (!g_graphics_server->renderer_context_lost()) { + glDetachShader(program_, fragment_shader_->shader()); + glDetachShader(program_, vertex_shader_->shader()); + glDeleteProgram(program_); + DEBUG_CHECK_GL_ERROR; + } + } + auto IsBound() const -> bool { + return (renderer()->GetActiveProgram() == this); + } + + auto program() const -> GLuint { return program_; } + + void Bind() { renderer_->UseProgram(this); } + + auto name() const -> const std::string& { return name_; } + + // should grab matrices from the renderer + // or whatever else it needs in prep for drawing + void PrepareToDraw() { + DEBUG_CHECK_GL_ERROR; + + assert(IsBound()); + + // update matrices as necessary... + + uint32_t mvpState = g_graphics_server->GetModelViewProjectionMatrixState(); + if (mvpState != mvp_state_) { + mvp_state_ = mvpState; + glUniformMatrix4fv(mvp_uniform_, 1, 0, + g_graphics_server->GetModelViewProjectionMatrix().m); + } + DEBUG_CHECK_GL_ERROR; + + if (pflags_ & PFLAG_USES_MODEL_WORLD_MATRIX) { + assert(!(pflags_ + & PFLAG_WORLD_SPACE_PTS)); // with world space points this would + // be identity; don't waste time. + uint32_t state = g_graphics_server->GetModelWorldMatrixState(); + if (state != model_world_matrix_state_) { + model_world_matrix_state_ = state; + glUniformMatrix4fv(model_world_matrix_uniform_, 1, 0, + g_graphics_server->GetModelWorldMatrix().m); + } + } + DEBUG_CHECK_GL_ERROR; + + if (pflags_ & PFLAG_USES_MODEL_VIEW_MATRIX) { + assert(!(pflags_ + & PFLAG_WORLD_SPACE_PTS)); // with world space points this would + // be identity; don't waste time. + // there's no state for just modelview but this works + uint32_t state = g_graphics_server->GetModelViewProjectionMatrixState(); + if (state != model_view_matrix_state_) { + model_view_matrix_state_ = state; + glUniformMatrix4fv(model_view_matrix_uniform_, 1, 0, + g_graphics_server->model_view_matrix().m); + } + } + DEBUG_CHECK_GL_ERROR; + + if (pflags_ & PFLAG_USES_CAM_POS) { + uint32_t state = g_graphics_server->cam_pos_state(); + if (state != cam_pos_state_) { + cam_pos_state_ = state; + const Vector3f& p(g_graphics_server->cam_pos()); + glUniform4f(cam_pos_uniform_, p.x, p.y, p.z, 1.0f); + } + } + DEBUG_CHECK_GL_ERROR; + + if (pflags_ & PFLAG_USES_CAM_ORIENT_MATRIX) { + uint32_t state = g_graphics_server->GetCamOrientMatrixState(); + if (state != cam_orient_matrix_state_) { + cam_orient_matrix_state_ = state; + glUniformMatrix4fv(cam_orient_matrix_uniform_, 1, 0, + g_graphics_server->GetCamOrientMatrix().m); + } + } + DEBUG_CHECK_GL_ERROR; + + if (pflags_ & PFLAG_USES_SHADOW_PROJECTION_MATRIX) { + uint32_t state = + g_graphics_server->light_shadow_projection_matrix_state(); + if (state != light_shadow_projection_matrix_state_) { + light_shadow_projection_matrix_state_ = state; + glUniformMatrix4fv( + light_shadow_projection_matrix_uniform_, 1, 0, + g_graphics_server->light_shadow_projection_matrix().m); + } + } + DEBUG_CHECK_GL_ERROR; + } + + protected: + void SetTextureUnit(const char* tex_name, int unit) { + assert(IsBound()); + int c = glGetUniformLocation(program_, tex_name); + if (c == -1) { +#if !MSAA_ERROR_TEST + Log("Error: ShaderGL: " + name_ + ": Can't set texture unit for texture '" + + tex_name + "'"); + DEBUG_CHECK_GL_ERROR; +#endif + } else { + glUniform1i(c, unit); + } + } + + auto GetInfo() -> std::string { + static char log[1024]; + GLsizei log_size; + glGetProgramInfoLog(program_, sizeof(log), &log_size, log); + return log; + } + + auto renderer() const -> RendererGL* { return renderer_; } + + private: + RendererGL* renderer_{}; + Object::Ref fragment_shader_; + Object::Ref vertex_shader_; + std::string name_; + GLuint program_{}; + int pflags_{}; + uint32_t mvp_state_{}; + GLint mvp_uniform_{}; + GLint model_world_matrix_uniform_{}; + GLint model_view_matrix_uniform_{}; + GLint light_shadow_projection_matrix_uniform_{}; + uint32_t light_shadow_projection_matrix_state_{}; + uint32_t model_world_matrix_state_{}; + uint32_t model_view_matrix_state_{}; + GLint cam_pos_uniform_{}; + uint32_t cam_pos_state_{}; + GLint cam_orient_matrix_uniform_{}; + GLuint cam_orient_matrix_state_{}; + BA_DISALLOW_CLASS_COPIES(ProgramGL); +}; // ProgramGL + +class RendererGL::SimpleProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { + kColorTexUnit, + kColorizeTexUnit, + kMaskTexUnit, + kMaskUV2TexUnit, + kBlurTexUnit + }; + + SimpleProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags) { + if (flags & SHD_TEXTURE) { + SetTextureUnit("colorTex", kColorTexUnit); + } + if (flags & SHD_COLORIZE) { + SetTextureUnit("colorizeTex", kColorizeTexUnit); + colorize_color_location_ = + glGetUniformLocation(program(), "colorizeColor"); + assert(colorize_color_location_ != -1); + } + if (flags & SHD_COLORIZE2) { + colorize2_color_location_ = + glGetUniformLocation(program(), "colorize2Color"); + assert(colorize2_color_location_ != -1); + } + if ((!(flags & SHD_TEXTURE)) || (flags & SHD_MODULATE)) { + color_location_ = glGetUniformLocation(program(), "color"); + assert(color_location_ != -1); + } + if (flags & SHD_SHADOW) { + shadow_params_location_ = glGetUniformLocation(program(), "shadowParams"); + assert(shadow_params_location_ != -1); + } + if (flags & SHD_GLOW) { + glow_params_location_ = glGetUniformLocation(program(), "glowParams"); + assert(glow_params_location_ != -1); + } + if (flags & SHD_FLATNESS) { + flatness_location = glGetUniformLocation(program(), "flatness"); + assert(flatness_location != -1); + } + if (flags & SHD_MASKED) { + SetTextureUnit("maskTex", kMaskTexUnit); + } + if (flags & SHD_MASK_UV2) { + SetTextureUnit("maskUV2Tex", kMaskUV2TexUnit); + } + } + void SetColorTexture(const TextureData* t) { + assert(flags_ & SHD_TEXTURE); + assert(IsBound()); + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetColorTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetColor(float r, float g, float b, float a = 1.0f) { + assert((flags_ & SHD_MODULATE) || !(flags_ & SHD_TEXTURE)); + assert(IsBound()); + if (r != r_ || g != g_ || b != b_ || a != a_) { + r_ = r; + g_ = g; + b_ = b; + a_ = a; + glUniform4f(color_location_, r_, g_, b_, a_); + } + } + void SetColorizeColor(float r, float g, float b, float a = 1.0f) { + assert(flags_ & SHD_COLORIZE); + assert(IsBound()); + if (r != colorize_r_ || g != colorize_g_ || b != colorize_b_ + || a != colorize_a_) { + colorize_r_ = r; + colorize_g_ = g; + colorize_b_ = b; + colorize_a_ = a; + glUniform4f(colorize_color_location_, colorize_r_, colorize_g_, + colorize_b_, colorize_a_); + } + } + void SetShadow(float shadow_offset_x, float shadow_offset_y, + float shadow_blur, float shadow_density) { + assert(flags_ & SHD_SHADOW); + assert(IsBound()); + if (shadow_offset_x != shadow_offset_x_ + || shadow_offset_y != shadow_offset_y_ || shadow_blur != shadow_blur_ + || shadow_density != shadow_density_) { + shadow_offset_x_ = shadow_offset_x; + shadow_offset_y_ = shadow_offset_y; + shadow_blur_ = shadow_blur; + shadow_density_ = shadow_density; + glUniform4f(shadow_params_location_, shadow_offset_x_, shadow_offset_y_, + shadow_blur_, shadow_density_ * 0.4f); + } + } + void setGlow(float glow_amount, float glow_blur) { + assert(flags_ & SHD_GLOW); + assert(IsBound()); + if (glow_amount != glow_amount_ || glow_blur != glow_blur_) { + glow_amount_ = glow_amount; + glow_blur_ = glow_blur; + glUniform2f(glow_params_location_, glow_amount_, glow_blur_); + } + } + void SetFlatness(float flatness) { + assert(flags_ & SHD_FLATNESS); + assert(IsBound()); + if (flatness != flatness_) { + flatness_ = flatness; + glUniform1f(flatness_location, flatness_); + } + } + void SetColorize2Color(float r, float g, float b, float a = 1.0f) { + assert(flags_ & SHD_COLORIZE2); + assert(IsBound()); + if (r != colorize2_r_ || g != colorize2_g_ || b != colorize2_b_ + || a != colorize2_a_) { + colorize2_r_ = r; + colorize2_g_ = g; + colorize2_b_ = b; + colorize2_a_ = a; + glUniform4f(colorize2_color_location_, colorize2_r_, colorize2_g_, + colorize2_b_, colorize2_a_); + } + } + void SetColorizeTexture(const TextureData* t) { + assert(flags_ & SHD_COLORIZE); + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorizeTexUnit); + } + void SetMaskTexture(const TextureData* t) { + assert(flags_ & SHD_MASKED); + renderer()->BindTexture(GL_TEXTURE_2D, t, kMaskTexUnit); + } + void SetMaskUV2Texture(const TextureData* t) { + assert(flags_ & SHD_MASK_UV2); + renderer()->BindTexture(GL_TEXTURE_2D, t, kMaskUV2TexUnit); + } + + private: + auto GetName(int flags) -> std::string { + return "SimpleProgramGL texture:" + + std::to_string((flags & SHD_TEXTURE) != 0) + + " modulate:" + std::to_string((flags & SHD_MODULATE) != 0) + + " colorize:" + std::to_string((flags & SHD_COLORIZE) != 0) + + " colorize2:" + std::to_string((flags & SHD_COLORIZE2) != 0) + + " premultiply:" + std::to_string((flags & SHD_PREMULTIPLY) != 0) + + " shadow:" + std::to_string((flags & SHD_SHADOW) != 0) + + " glow:" + std::to_string((flags & SHD_GLOW) != 0) + " masked:" + + std::to_string((flags & SHD_MASKED) != 0) + " maskedUV2:" + + std::to_string((flags & SHD_MASK_UV2) != 0) + " depthBugTest:" + + std::to_string((flags & SHD_DEPTH_BUG_TEST) != 0) + + " flatness:" + std::to_string((flags & SHD_MASK_UV2) != 0); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR; + if (flags & SHD_TEXTURE) pflags |= PFLAG_USES_UV_ATTR; + if (flags & SHD_MASK_UV2) pflags |= PFLAG_USES_UV2_ATTR; + return pflags; + } + auto GetVertexCode(int flags) -> std::string { + std::string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n"; + if ((flags & SHD_TEXTURE) || (flags & SHD_COLORIZE) + || (flags & SHD_COLORIZE2)) + s += "attribute vec2 uv;\n" + "varying vec2 vUV;\n"; + if (flags & SHD_MASK_UV2) + s += "attribute vec2 uv2;\n" + "varying vec2 vUV2;\n"; + if (flags & SHD_SHADOW) + s += "varying vec2 vUVShadow;\n" + "varying vec2 vUVShadow2;\n" + "varying vec2 vUVShadow3;\n" + "uniform " LOWP "vec4 shadowParams;\n"; + s += "void main() {\n"; + if (flags & SHD_TEXTURE) s += " vUV = uv;\n"; + if (flags & SHD_MASK_UV2) s += " vUV2 = uv2;\n"; + if (flags & SHD_SHADOW) + s += " vUVShadow = uv+0.4*vec2(shadowParams.x,shadowParams.y);\n"; + if (flags & SHD_SHADOW) + s += " vUVShadow2 = uv+0.8*vec2(shadowParams.x,shadowParams.y);\n"; + if (flags & SHD_SHADOW) + s += " vUVShadow3 = uv+1.3*vec2(shadowParams.x,shadowParams.y);\n"; + s += " gl_Position = modelViewProjectionMatrix*position;\n" + "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + if (flags & SHD_TEXTURE) s += "uniform " LOWP "sampler2D colorTex;\n"; + if ((flags & SHD_COLORIZE)) + s += "uniform " LOWP + "sampler2D colorizeTex;\n" + "uniform " LOWP "vec4 colorizeColor;\n"; + if ((flags & SHD_COLORIZE2)) s += "uniform " LOWP "vec4 colorize2Color;\n"; + if ((flags & SHD_TEXTURE) || (flags & SHD_COLORIZE) + || (flags & SHD_COLORIZE2)) + s += "varying " LOWP "vec2 vUV;\n"; + if (flags & SHD_MASK_UV2) s += "varying " LOWP "vec2 vUV2;\n"; + if (flags & SHD_FLATNESS) s += "uniform " LOWP "float flatness;\n"; + if (flags & SHD_SHADOW) { + s += "varying " LOWP + "vec2 vUVShadow;\n" + "varying " LOWP + "vec2 vUVShadow2;\n" + "varying " LOWP + "vec2 vUVShadow3;\n" + "uniform " LOWP "vec4 shadowParams;\n"; + } + if (flags & SHD_GLOW) { + s += "uniform " LOWP "vec2 glowParams;\n"; + } + if ((flags & SHD_MODULATE) || (!(flags & SHD_TEXTURE))) + s += "uniform " LOWP "vec4 color;\n"; + if (flags & SHD_MASKED) s += "uniform " LOWP "sampler2D maskTex;\n"; + if (flags & SHD_MASK_UV2) s += "uniform " LOWP "sampler2D maskUV2Tex;\n"; + s += "void main() {\n"; + if (!(flags & SHD_TEXTURE)) { + s += " gl_FragColor = color;\n"; + } else { + std::string blurArg; + if (flags & SHD_GLOW) { + s += " " LOWP + "vec4 cVal = texture2D(colorTex,vUV,glowParams.g);\n" + " gl_FragColor = vec4(color.rgb * cVal.rgb * cVal.a * " + "glowParams.r,0.0)"; // we premultiply this. + if (flags & SHD_MASK_UV2) s += " * vec4(texture2D(maskUV2Tex,vUV2).a)"; + s += ";\n"; + } else { + if ((flags & SHD_COLORIZE) || (flags & SHD_COLORIZE2)) + s += " " LOWP + "vec4 colorizeVal = texture2D(colorizeTex,vUV);\n"; // TEMP TEST + if (flags & SHD_COLORIZE) + s += " " LOWP "float colorizeA = colorizeVal.r;\n"; + if (flags & SHD_COLORIZE2) + s += " " LOWP "float colorizeB = colorizeVal.g;\n"; + if (flags & SHD_MASKED) + s += " " MEDIUMP "vec4 mask = texture2D(maskTex,vUV);"; + + if (flags & SHD_MODULATE) { + if (flags & SHD_FLATNESS) { + s += " " LOWP + "vec4 rawTexColor = texture2D(colorTex,vUV);\n" + " gl_FragColor = color * " + "vec4(mix(rawTexColor.rgb,vec3(1.0),flatness),rawTexColor.a)"; + } else { + s += " gl_FragColor = color * texture2D(colorTex,vUV)"; + } + } else { + s += " gl_FragColor = texture2D(colorTex,vUV)"; + } + + if (flags & SHD_COLORIZE) + s += " * (vec4(1.0-colorizeA)+colorizeColor*colorizeA)"; + if (flags & SHD_COLORIZE2) + s += " * (vec4(1.0-colorizeB)+colorize2Color*colorizeB)"; + if (flags & SHD_MASKED) + s += " * vec4(vec3(mask.r),mask.a) + " + "vec4(vec3(mask.g)*colorizeColor.rgb+vec3(mask.b),0.0)"; + s += ";\n"; + + if (flags & SHD_SHADOW) { + s += " " LOWP + "float shadowA = (texture2D(colorTex,vUVShadow).a + " + "texture2D(colorTex,vUVShadow2,1.0).a + " + "texture2D(colorTex,vUVShadow3,2.0).a) * shadowParams.a"; + + if (flags & SHD_MASK_UV2) s += " * texture2D(maskUV2Tex,vUV2).a"; + s += ";\n"; + s += " gl_FragColor = " + "vec4(gl_FragColor.rgb*gl_FragColor.a,gl_FragColor.a) + " + "(1.0-gl_FragColor.a) * vec4(0,0,0,shadowA);\n"; + s += " gl_FragColor = " + "vec4(gl_FragColor.rgb/" + "max(0.001,gl_FragColor.a),gl_FragColor.a);\n"; + } + } + if (flags & SHD_DEPTH_BUG_TEST) + s += " gl_FragColor = vec4(abs(gl_FragCoord.z-gl_FragColor.r));\n"; + if (flags & SHD_PREMULTIPLY) + s += " gl_FragColor = vec4(gl_FragColor.rgb * " + "gl_FragColor.a,gl_FragColor.a);"; + } + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + float r_{}, g_{}, b_{}, a_{}; + float colorize_r_{}, colorize_g_{}, colorize_b_{}, colorize_a_{}; + float colorize2_r_{}, colorize2_g_{}, colorize2_b_{}, colorize2_a_{}; + float shadow_offset_x_{}, shadow_offset_y_{}, shadow_blur_{}, + shadow_density_{}; + float glow_amount_{}, glow_blur_{}; + float flatness_{}; + GLint color_location_{}; + GLint colorize_color_location_{}; + GLint colorize2_color_location_{}; + GLint shadow_params_location_{}; + GLint glow_params_location_{}; + GLint flatness_location{}; + int flags_{}; +}; // SimpleProgramGL + +class RendererGL::ObjectProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { + kColorTexUnit, + kReflectionTexUnit, + kVignetteTexUnit, + kLightShadowTexUnit, + kColorizeTexUnit + }; + + ObjectProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags), + r_(0), + g_(0), + b_(0), + a_(0), + colorize_r_(0), + colorize_g_(0), + colorize_b_(0), + colorize_a_(0), + colorize2_r_(0), + colorize2_g_(0), + colorize2_b_(0), + colorize2_a_(0), + add_r_(0), + add_g_(0), + add_b_(0), + r_mult_r_(0), + r_mult_g_(0), + r_mult_b_(0), + r_mult_a_(0) { + SetTextureUnit("colorTex", kColorTexUnit); + SetTextureUnit("vignetteTex", kVignetteTexUnit); + color_location_ = glGetUniformLocation(program(), "color"); + assert(color_location_ != -1); + if (flags & SHD_REFLECTION) { + SetTextureUnit("reflectionTex", kReflectionTexUnit); + reflect_mult_location_ = glGetUniformLocation(program(), "reflectMult"); + assert(reflect_mult_location_ != -1); + } + if (flags & SHD_LIGHT_SHADOW) { + SetTextureUnit("lightShadowTex", kLightShadowTexUnit); + } + if (flags & SHD_ADD) { + color_add_location_ = glGetUniformLocation(program(), "colorAdd"); + assert(color_add_location_ != -1); + } + if (flags & SHD_COLORIZE) { + SetTextureUnit("colorizeTex", kColorizeTexUnit); + colorize_color_location_ = + glGetUniformLocation(program(), "colorizeColor"); + assert(colorize_color_location_ != -1); + } + if (flags & SHD_COLORIZE2) { + colorize2_color_location_ = + glGetUniformLocation(program(), "colorize2Color"); + assert(colorize2_color_location_ != -1); + } + } + void SetColorTexture(const TextureData* t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetReflectionTexture(const TextureData* t) { + assert(flags_ & SHD_REFLECTION); + renderer()->BindTexture(GL_TEXTURE_CUBE_MAP, t, kReflectionTexUnit); + } + void SetColor(float r, float g, float b, float a = 1.0f) { + assert(IsBound()); + // include tint.. + if (r * renderer()->tint().x != r_ || g * renderer()->tint().y != g_ + || b * renderer()->tint().z != b_ || a != a_) { + r_ = r * renderer()->tint().x; + g_ = g * renderer()->tint().y; + b_ = b * renderer()->tint().z; + a_ = a; + glUniform4f(color_location_, r_, g_, b_, a_); + } + } + void SetAddColor(float r, float g, float b) { + assert(IsBound()); + if (r != add_r_ || g != add_g_ || b != add_b_) { + add_r_ = r; + add_g_ = g; + add_b_ = b; + glUniform4f(color_add_location_, add_r_, add_g_, add_b_, 0.0f); + } + } + void SetReflectionMult(float r, float g, float b, float a = 0.0f) { + assert(IsBound()); + // include tint and ambient color... + auto renderer = this->renderer(); + float rFin = r * renderer->tint().x * renderer->ambient_color().x; + float gFin = g * renderer->tint().y * renderer->ambient_color().y; + float bFin = b * renderer->tint().z * renderer->ambient_color().z; + if (rFin != r_mult_r_ || gFin != r_mult_g_ || bFin != r_mult_b_ + || a != r_mult_a_) { + r_mult_r_ = rFin; + r_mult_g_ = gFin; + r_mult_b_ = bFin; + r_mult_a_ = a; + assert(flags_ & SHD_REFLECTION); + glUniform4f(reflect_mult_location_, r_mult_r_, r_mult_g_, r_mult_b_, + r_mult_a_); + } + } + void SetVignetteTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kVignetteTexUnit); + } + void SetLightShadowTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kLightShadowTexUnit); + } + + void SetColorizeColor(float r, float g, float b, float a = 1.0f) { + assert(flags_ & SHD_COLORIZE); + assert(IsBound()); + if (r != colorize_r_ || g != colorize_g_ || b != colorize_b_ + || a != colorize_a_) { + colorize_r_ = r; + colorize_g_ = g; + colorize_b_ = b; + colorize_a_ = a; + glUniform4f(colorize_color_location_, colorize_r_, colorize_g_, + colorize_b_, colorize_a_); + } + } + void SetColorize2Color(float r, float g, float b, float a = 1.0f) { + assert(flags_ & SHD_COLORIZE2); + assert(IsBound()); + if (r != colorize2_r_ || g != colorize2_g_ || b != colorize2_b_ + || a != colorize2_a_) { + colorize2_r_ = r; + colorize2_g_ = g; + colorize2_b_ = b; + colorize2_a_ = a; + glUniform4f(colorize2_color_location_, colorize2_r_, colorize2_g_, + colorize2_b_, colorize2_a_); + } + } + void SetColorizeTexture(const TextureData* t) { + assert(flags_ & SHD_COLORIZE); + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorizeTexUnit); + } + + private: + auto GetName(int flags) -> std::string { + return std::string("ObjectProgramGL") + + " reflect:" + std::to_string((flags & SHD_REFLECTION) != 0) + + " lightShadow:" + std::to_string((flags & SHD_LIGHT_SHADOW) != 0) + + " add:" + std::to_string((flags & SHD_ADD) != 0) + " colorize:" + + std::to_string((flags & SHD_COLORIZE) != 0) + " colorize2:" + + std::to_string((flags & SHD_COLORIZE2) != 0) + " transparent:" + + std::to_string((flags & SHD_OBJ_TRANSPARENT) != 0) + " worldSpace:" + + std::to_string((flags & SHD_WORLD_SPACE_PTS) != 0); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_UV_ATTR; + if (flags & SHD_REFLECTION) + pflags |= (PFLAG_USES_NORMAL_ATTR | PFLAG_USES_CAM_POS); + if (((flags & SHD_REFLECTION) || (flags & SHD_LIGHT_SHADOW)) + && !(flags & SHD_WORLD_SPACE_PTS)) + pflags |= PFLAG_USES_MODEL_WORLD_MATRIX; + if (flags & SHD_LIGHT_SHADOW) pflags |= PFLAG_USES_SHADOW_PROJECTION_MATRIX; + if (flags & SHD_WORLD_SPACE_PTS) pflags |= PFLAG_WORLD_SPACE_PTS; + return pflags; + } + auto GetVertexCode(int flags) -> std::string { + std::string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "uniform vec4 camPos;\n" + "attribute vec4 position;\n" + "attribute " LOWP + "vec2 uv;\n" + "varying " LOWP + "vec2 vUV;\n" + "varying " MEDIUMP "vec4 vScreenCoord;\n"; + if ((flags & SHD_REFLECTION) || (flags & SHD_LIGHT_SHADOW)) + s += "uniform mat4 modelWorldMatrix;\n"; + if (flags & SHD_REFLECTION) + s += "attribute " MEDIUMP + "vec3 normal;\n" + "varying " MEDIUMP "vec3 vReflect;\n"; + if (flags & SHD_LIGHT_SHADOW) + s += "uniform mat4 lightShadowProjectionMatrix;\n" + "varying " MEDIUMP "vec4 vLightShadowUV;\n"; + s += + "void main() {\n" + " vUV = uv;\n" + " gl_Position = modelViewProjectionMatrix*position;\n" + " vScreenCoord = vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + if (((flags & SHD_LIGHT_SHADOW) || (flags & SHD_REFLECTION)) + && !(flags & SHD_WORLD_SPACE_PTS)) { + s += " vec4 worldPos = modelWorldMatrix*position;\n"; + } + if (flags & SHD_LIGHT_SHADOW) { + if (flags & SHD_WORLD_SPACE_PTS) + s += " vLightShadowUV = (lightShadowProjectionMatrix*position);\n"; + else + s += " vLightShadowUV = (lightShadowProjectionMatrix*worldPos);\n"; + } + if (flags & SHD_REFLECTION) { + if (flags & SHD_WORLD_SPACE_PTS) + s += " vReflect = reflect(vec3(position - camPos),normal);\n"; + else + s += " vReflect = reflect(vec3(worldPos - " + "camPos),normalize(vec3(modelWorldMatrix * vec4(normal,0.0))));\n"; + } + s += "}"; + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + s = "uniform " LOWP + "sampler2D colorTex;\n" + "uniform " LOWP + "sampler2D vignetteTex;\n" + "uniform " LOWP + "vec4 color;\n" + "varying " LOWP + "vec2 vUV;\n" + "varying " MEDIUMP "vec4 vScreenCoord;\n"; + if (flags & SHD_ADD) s += "uniform " LOWP "vec4 colorAdd;\n"; + if (flags & SHD_REFLECTION) + s += "uniform " LOWP + "samplerCube reflectionTex;\n" + "varying " MEDIUMP + "vec3 vReflect;\n" + "uniform " LOWP "vec4 reflectMult;\n"; + if (flags & SHD_COLORIZE) + s += "uniform " LOWP + "sampler2D colorizeTex;\n" + "uniform " LOWP "vec4 colorizeColor;\n"; + if (flags & SHD_COLORIZE2) s += "uniform " LOWP "vec4 colorize2Color;\n"; + if (flags & SHD_LIGHT_SHADOW) + s += "uniform " LOWP + "sampler2D lightShadowTex;\n" + "varying " MEDIUMP "vec4 vLightShadowUV;\n"; + s += "void main() {\n"; + if (flags & SHD_LIGHT_SHADOW) + s += + " " LOWP + "vec4 lightShadVal = texture2DProj(lightShadowTex,vLightShadowUV);\n"; + if ((flags & SHD_COLORIZE) || (flags & SHD_COLORIZE2)) + s += " " LOWP "vec4 colorizeVal = texture2D(colorizeTex,vUV);\n"; + if (flags & SHD_COLORIZE) + s += " " LOWP "float colorizeA = colorizeVal.r;\n"; + if (flags & SHD_COLORIZE2) + s += " " LOWP "float colorizeB = colorizeVal.g;\n"; + s += " gl_FragColor = (color*texture2D(colorTex,vUV)"; + if (flags & SHD_COLORIZE) + s += " * (vec4(1.0-colorizeA)+colorizeColor*colorizeA)"; + if (flags & SHD_COLORIZE2) + s += " * (vec4(1.0-colorizeB)+colorize2Color*colorizeB)"; + s += ")"; + + // add in lights/shadows + if (flags & SHD_LIGHT_SHADOW) { + if (flags & SHD_OBJ_TRANSPARENT) + s += " * vec4((2.0*lightShadVal).rgb,1) + " + "vec4((lightShadVal-0.5).rgb,0)"; + else + s += " * (2.0*lightShadVal) + (lightShadVal-0.5)"; + } + + // add glow and reflection + if (flags & SHD_REFLECTION) + s += " + (reflectMult*textureCube(reflectionTex,vReflect))"; + if (flags & SHD_ADD) s += " + colorAdd"; + + // subtract vignette + s += " - vec4(texture2DProj(vignetteTex,vScreenCoord).rgb,0)"; + + s += ";\n"; + // s += "gl_FragColor = 0.999 * texture2DProj(vignetteTex,vScreenCoord) + + // 0.01 * gl_FragColor;"; + + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + float r_, g_, b_, a_; + float colorize_r_, colorize_g_, colorize_b_, colorize_a_; + float colorize2_r_, colorize2_g_, colorize2_b_, colorize2_a_; + float add_r_, add_g_, add_b_; + float r_mult_r_, r_mult_g_, r_mult_b_, r_mult_a_; + GLint color_location_; + GLint colorize_color_location_; + GLint colorize2_color_location_; + GLint color_add_location_; + GLint reflect_mult_location_; + int flags_; +}; // ObjectProgramGL + +class RendererGL::SmokeProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { kColorTexUnit, kDepthTexUnit, kBlurTexUnit }; + + SmokeProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags), + r_(0), + g_(0), + b_(0), + a_(0) { + SetTextureUnit("colorTex", kColorTexUnit); + if (flags & SHD_OVERLAY) { + SetTextureUnit("depthTex", kDepthTexUnit); + SetTextureUnit("blurTex", kBlurTexUnit); + } + color_location_ = glGetUniformLocation(program(), "colorMult"); + assert(color_location_ != -1); + } + void SetColorTexture(const TextureData* t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetDepthTexture(GLuint t) { + assert(flags_ & SHD_OVERLAY); + renderer()->BindTexture(GL_TEXTURE_2D, t, kDepthTexUnit); + } + void SetBlurTexture(GLuint t) { + assert(flags_ & SHD_OVERLAY); + renderer()->BindTexture(GL_TEXTURE_2D, t, kBlurTexUnit); + } + void SetColor(float r, float g, float b, float a = 1.0f) { + assert(IsBound()); + // include tint.. + if (r * renderer()->tint().x != r_ || g * renderer()->tint().y != g_ + || b * renderer()->tint().z != b_ || a != a_) { + r_ = r * renderer()->tint().x; + g_ = g * renderer()->tint().y; + b_ = b * renderer()->tint().z; + a_ = a; + glUniform4f(color_location_, r_, g_, b_, a_); + } + } + + private: + auto GetName(int flags) -> std::string { + return std::string("SmokeProgramGL"); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_DIFFUSE_ATTR + | PFLAG_USES_UV_ATTR | PFLAG_WORLD_SPACE_PTS + | PFLAG_USES_ERODE_ATTR | PFLAG_USES_COLOR_ATTR; + return pflags; + } + auto GetVertexCode(int flags) -> std::string { + std::string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n" + "attribute " MEDIUMP + "vec2 uv;\n" + "varying " MEDIUMP + "vec2 vUV;\n" + "attribute " LOWP + "float erode;\n" + "attribute " MEDIUMP + "float diffuse;\n" + "varying " LOWP + "float vErode;\n" + "attribute " MEDIUMP + "vec4 color;\n" + "varying " LOWP + "vec4 vColor;\n" + "uniform " MEDIUMP "vec4 colorMult;\n"; + if (flags & SHD_OVERLAY) + s += "varying " LOWP + "vec4 cDiffuse;\n" + "varying " MEDIUMP "vec4 vScreenCoord;\n"; + s += "void main() {\n" + " vUV = uv;\n" + " gl_Position = modelViewProjectionMatrix*position;\n" + " vErode = erode;\n"; + // in overlay mode we pass color/diffuse to the pixel-shader since we + // combine them there with a blurred bg image to get a soft look. In the + // simple version we just use a flat ambient color here. + if (flags & SHD_OVERLAY) + s += " vScreenCoord = " + "vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n" + " vColor = vec4(vec3(7.0*diffuse),0.7) * color * colorMult;\n" + " cDiffuse = colorMult*(0.3+0.8*diffuse);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + else + s += " vColor = " + "(vec4(vec3(7.0),1.0)*color+vec4(vec3(0.4),0))*vec4(vec3(diffuse),0." + "4) * colorMult;\n"; + s += " vColor *= vec4(vec3(vColor.a),1.0);\n"; // premultiply + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + s = "uniform " LOWP + "sampler2D colorTex;\n" + "varying " MEDIUMP + "vec2 vUV;\n" + "varying " LOWP + "float vErode;\n" + "varying " LOWP "vec4 vColor;\n"; + if (flags & SHD_OVERLAY) + s += "varying " MEDIUMP + "vec4 vScreenCoord;\n" + "uniform " LOWP + "sampler2D depthTex;\n" + "uniform " LOWP + "sampler2D blurTex;\n" + "varying " LOWP "vec4 cDiffuse;\n"; + s += "void main() {\n"; + s += " " LOWP + "float erodeMult = smoothstep(vErode,1.0,texture2D(colorTex,vUV).r);\n" + " gl_FragColor = (vColor*vec4(erodeMult));"; + if (flags & SHD_OVERLAY) { + s += " gl_FragColor += vec4(vec3(gl_FragColor.a),0) * cDiffuse * " + "(0.11+0.8*texture2DProj(blurTex,vScreenCoord));\n"; + s += " " MEDIUMP + " float depth =texture2DProj(depthTex,vScreenCoord).r;\n"; + // adreno bug where depth is returned as 0..1 instead of glDepthRange() + if (GetFunkyDepthIssue()) { + s += " depth = " + std::to_string(kBackingDepth3) + "+depth*(" + + std::to_string(kBackingDepth4) + "-" + + std::to_string(kBackingDepth3) + ");\n"; + } + s += " gl_FragColor *= " + "(1.0-smoothstep(0.0,0.002,gl_FragCoord.z-depth));\n"; + } + + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + float r_, g_, b_, a_; + GLint color_location_; + int flags_; +}; // SmokeProgramGL + +class RendererGL::BlurProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { + kColorTexUnit, + }; + + BlurProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags), + pixel_size_x_(0.0f), + pixel_size_y_(0.0f) { + SetTextureUnit("colorTex", kColorTexUnit); + pixel_size_location_ = glGetUniformLocation(program(), "pixelSize"); + assert(pixel_size_location_ != -1); + } + void SetPixelSize(float x, float y) { + assert(IsBound()); + if (x != pixel_size_x_ || y != pixel_size_y_) { + pixel_size_x_ = x; + pixel_size_y_ = y; + glUniform2f(pixel_size_location_, pixel_size_x_, pixel_size_y_); + } + } + + void SetColorTexture(const TextureData* t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetColorTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + + private: + auto GetName(int flags) -> std::string { + return std::string("BlurProgramGL"); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_UV_ATTR; + return pflags; + } + auto GetVertexCode(int flags) -> std::string { + std::string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n" + "attribute " MEDIUMP + "vec2 uv;\n" + "varying " MEDIUMP + "vec2 vUV1;\n" + "varying " MEDIUMP + "vec2 vUV2;\n" + "varying " MEDIUMP + "vec2 vUV3;\n" + "varying " MEDIUMP + "vec2 vUV4;\n" + "varying " MEDIUMP + "vec2 vUV5;\n" + "varying " MEDIUMP + "vec2 vUV6;\n" + "varying " MEDIUMP + "vec2 vUV7;\n" + "varying " MEDIUMP + "vec2 vUV8;\n" + "uniform " MEDIUMP + "vec2 pixelSize;\n" + "void main() {\n" + " gl_Position = modelViewProjectionMatrix*position;\n" + " vUV1 = uv+vec2(-0.5,0)*pixelSize;\n" + " vUV2 = uv+vec2(-1.5,0)*pixelSize;\n" + " vUV3 = uv+vec2(0.5,0)*pixelSize;\n" + " vUV4 = uv+vec2(1.5,0)*pixelSize;\n" + " vUV5 = uv+vec2(-0.5,1.0)*pixelSize;\n" + " vUV6 = uv+vec2(0.5,1.0)*pixelSize;\n" + " vUV7 = uv+vec2(-0.5,-1.0)*pixelSize;\n" + " vUV8 = uv+vec2(0.5,-1.0)*pixelSize;\n"; + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + s = "uniform " MEDIUMP + "sampler2D colorTex;\n" + "varying " MEDIUMP + "vec2 vUV1;\n" + "varying " MEDIUMP + "vec2 vUV2;\n" + "varying " MEDIUMP + "vec2 vUV3;\n" + "varying " MEDIUMP + "vec2 vUV4;\n" + "varying " MEDIUMP + "vec2 vUV5;\n" + "varying " MEDIUMP + "vec2 vUV6;\n" + "varying " MEDIUMP + "vec2 vUV7;\n" + "varying " MEDIUMP + "vec2 vUV8;\n" + "void main() {\n" + " gl_FragColor = 0.125*(texture2D(colorTex,vUV1)\n" + " + texture2D(colorTex,vUV2)\n" + " + texture2D(colorTex,vUV3)\n" + " + texture2D(colorTex,vUV4)\n" + " + texture2D(colorTex,vUV5)\n" + " + texture2D(colorTex,vUV6)\n" + " + texture2D(colorTex,vUV7)\n" + " + texture2D(colorTex,vUV8));\n" + "}"; + if (flags & SHD_DEBUG_PRINT) { + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + } + return s; + } + + int flags_; + GLint pixel_size_location_; + float pixel_size_x_, pixel_size_y_; +}; // BlurProgramGL + +class RendererGL::ShieldProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { + kDepthTexUnit, + }; + + ShieldProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags) { + SetTextureUnit("depthTex", kDepthTexUnit); + } + void SetDepthTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kDepthTexUnit); + } + + private: + auto GetName(int flags) -> std::string { + return std::string("ShieldProgramGL"); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR; + return pflags; + } + auto GetVertexCode(int flags) -> std::string { + std::string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n" + "varying " HIGHP + "vec4 vScreenCoord;\n" + "void main() {\n" + " gl_Position = modelViewProjectionMatrix*position;\n" + " vScreenCoord = vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + s = "uniform " HIGHP + "sampler2D depthTex;\n" + "varying " HIGHP + "vec4 vScreenCoord;\n" + "void main() {\n" + " " HIGHP "float depth = texture2DProj(depthTex,vScreenCoord).r;\n"; + + // adreno bug where depth is returned as 0..1 instead of glDepthRange() + if (GetFunkyDepthIssue()) { + s += " depth = " + std::to_string(kBackingDepth3) + "+depth*(" + + std::to_string(kBackingDepth4) + "-" + + std::to_string(kBackingDepth3) + ");\n"; + } + // s+= " depth = + // "+std::to_string(kBackingDepth3)+"0.15+depth*(0.9-0.15);\n"; " depth + // *= + // 0.936;\n" " depth = 1.0/(65535.0*((1.0/depth)/16777216.0));\n" " depth + //= 1.0/((1.0/depth)+0.08);\n" " depth += 0.1f;\n" + s += " " HIGHP + "float d = abs(depth - gl_FragCoord.z);\n" + " d = 1.0 - smoothstep(0.0,0.0006,d);\n" + " d = 0.2*smoothstep(0.96,1.0,d)+0.2*d+0.4*d*d*d;\n"; + + // some mali chips seem to have no high precision and thus this looks + // terrible.. + // ..in those cases lets done down the intersection effect significantly + if (GetDrawsShieldsFunny()) { + s += " gl_FragColor = vec4(d*0.13,d*0.1,d,0);\n"; + } else { + s += " gl_FragColor = vec4(d*0.5,d*0.4,d,0);\n"; + } + s += "}"; + + // this shows msaa depth error on bridgit + //" gl_FragColor = vec4(smoothstep(0.73,0.77,depth),0.0,0.0,0.5);\n" + + // " d = 1.0 - smoothstep(0.0,0.0006,d);\n" + // " d = 0.2*smoothstep(0.96,1.0,d)+0.2*d+0.4*d*d*d;\n" + //" if (d < 0.01) gl_FragColor = vec4(0.0,1.0,0.0,0.5);\n" + + //" gl_FragColor = vec4(vec3(10.0*abs(depth-gl_FragCoord.z)),1);\n" + // " gl_FragColor = vec4(0,10.0*abs(depth-gl_FragCoord.z),0,0.1);\n" + // " if (depth < gl_FragCoord.z) gl_FragColor = + // vec4(1.0-10.0*(gl_FragCoord.z-depth),0,0,1);\n" " else gl_FragColor = + // vec4(0,1.0-10.0*(depth-gl_FragCoord.z),0,1);\n" + //" gl_FragColor = vec4(vec3(depth),1);\n" + + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + + int flags_; +}; + +class RendererGL::PostProcessProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { + kColorTexUnit, + kDepthTexUnit, + kColorSlightBlurredTexUnit, + kColorBlurredTexUnit, + kColorBlurredMoreTexUnit + }; + + PostProcessProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags), + dof_near_min_(0), + dof_near_max_(0), + dof_far_min_(0), + dof_far_max_(0), + distort_(0.0f) { + SetTextureUnit("colorTex", kColorTexUnit); + + if (UsesSlightBlurredTex()) + SetTextureUnit("colorSlightBlurredTex", kColorSlightBlurredTexUnit); + if (UsesBlurredTexture()) + SetTextureUnit("colorBlurredTex", kColorBlurredTexUnit); + SetTextureUnit("colorBlurredMoreTex", kColorBlurredMoreTexUnit); + SetTextureUnit("depthTex", kDepthTexUnit); + + dof_location_ = glGetUniformLocation(program(), "dofRange"); +#if !MSAA_ERROR_TEST + assert(dof_location_ != -1); +#endif + + if (flags & SHD_DISTORT) { + distort_location_ = glGetUniformLocation(program(), "distort"); + assert(distort_location_ != -1); + } + } + + auto UsesSlightBlurredTex() -> bool { + return static_cast(flags_ & SHD_EYES); + } + auto UsesBlurredTexture() -> bool { + return static_cast(flags_ & (SHD_HIGHER_QUALITY | SHD_EYES)); + } + void SetColorTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetColorSlightBlurredTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorSlightBlurredTexUnit); + } + void SetColorBlurredMoreTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorBlurredMoreTexUnit); + } + void SetColorBlurredTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorBlurredTexUnit); + } + void SetDepthTexture(GLuint t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kDepthTexUnit); + } + + void SetDepthOfFieldRanges(float near_min, float near_max, float far_min, + float far_max) { + assert(IsBound()); + if (near_min != dof_near_min_ || near_max != dof_near_max_ + || far_min != dof_far_min_ || far_max != dof_far_max_) { + DEBUG_CHECK_GL_ERROR; + dof_near_min_ = near_min; + dof_near_max_ = near_max; + dof_far_min_ = far_min; + dof_far_max_ = far_max; + float vals[4] = {dof_near_min_, dof_near_max_, dof_far_min_, + dof_far_max_}; + glUniform1fv(dof_location_, 4, vals); + DEBUG_CHECK_GL_ERROR; + } + } + void SetDistort(float distort) { + assert(IsBound()); + assert(flags_ & SHD_DISTORT); + if (distort != distort_) { + DEBUG_CHECK_GL_ERROR; + distort_ = distort; + glUniform1f(distort_location_, distort_); + DEBUG_CHECK_GL_ERROR; + } + } + + private: + auto GetName(int flags) -> std::string { + return std::string("PostProcessProgramGL"); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR; + if (flags & SHD_DISTORT) { + pflags |= (PFLAG_USES_NORMAL_ATTR | PFLAG_USES_MODEL_VIEW_MATRIX); + } + return pflags; + } + + // testing MSAA BUG +#if MSAA_ERROR_TEST + string GetVertexCode(int flags) { + string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n"; + if (flags & SHD_DISTORT) + s += "attribute " LOWP + "vec3 normal;\n" + "uniform mat4 modelViewMatrix;\n" + "uniform float distort;\n"; + if (flags & SHD_EYES) s += "varying " HIGHP "float calcedDepth;\n"; + + s += "varying " HIGHP + "vec4 vScreenCoord;\n" + "void main() {\n" + " gl_Position = modelViewProjectionMatrix*position;\n"; + if (flags & SHD_DISTORT) + s += " float eyeDot = " + "abs(normalize(modelViewMatrix*vec4(normal,0.0))).z;\n" + " vec4 posDistorted = " + "modelViewProjectionMatrix*(position-eyeDot*distort*vec4(normal,0));" + "\n" + " vScreenCoord = " + "vec4(posDistorted.xy/posDistorted.w,posDistorted.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + else + s += " vScreenCoord = " + "vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + if (flags & SHD_EYES) + s += " calcedDepth = " + std::to_string(kBackingDepth3) + "+" + + std::to_string(kBackingDepth4 - kBackingDepth3) + + "*(0.5*(gl_Position.z/gl_Position.w)+0.5);\n"; + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + string GetFragmentCode(int flags) { + string s; + s = "uniform " HIGHP + "sampler2D depthTex;\n" + "varying " HIGHP "vec4 vScreenCoord;\n"; + s += "void main() {\n" + " " HIGHP "float depth = texture2DProj(depthTex,vScreenCoord).r;\n"; + s += " gl_FragColor = vec4(vec3(14.0*(depth-0.76)),1);\n"; + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + +#else // msaa bug test + + auto GetVertexCode(int flags) -> std::string { + std::string s; + s = "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n"; + if (flags & SHD_DISTORT) + s += "attribute " LOWP + "vec3 normal;\n" + "uniform mat4 modelViewMatrix;\n" + "uniform float distort;\n"; + if (flags & SHD_EYES) { + s += "varying " HIGHP "float calcedDepth;\n"; + } + + s += "varying " MEDIUMP + "vec4 vScreenCoord;\n" + "void main() {\n" + " gl_Position = modelViewProjectionMatrix*position;\n"; + if (flags & SHD_DISTORT) { + s += " float eyeDot = " + "abs(normalize(modelViewMatrix*vec4(normal,0.0))).z;\n" + " vec4 posDistorted = " + "modelViewProjectionMatrix*(position-eyeDot*distort*vec4(normal,0));" + "\n" + " vScreenCoord = " + "vec4(posDistorted.xy/posDistorted.w,posDistorted.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + } else { + s += " vScreenCoord = " + "vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + } + if (flags & SHD_EYES) { + s += " calcedDepth = " + std::to_string(kBackingDepth3) + "+" + + std::to_string(kBackingDepth4 - kBackingDepth3) + + "*(0.5*(gl_Position.z/gl_Position.w)+0.5);\n"; + } + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + s = "uniform " LOWP + "sampler2D colorTex;\n" + "uniform " LOWP + "sampler2D colorBlurredMoreTex;\n" + "uniform " HIGHP + "sampler2D depthTex;\n" + "varying " MEDIUMP + "vec4 vScreenCoord;\n" + "uniform " LOWP "float dofRange[4];\n"; + if (flags & (SHD_HIGHER_QUALITY | SHD_EYES)) { + s += "uniform " LOWP "sampler2D colorBlurredTex;\n"; + } + if (flags & SHD_EYES) + s += "uniform " LOWP + "sampler2D colorSlightBlurredTex;\n" + "varying " HIGHP "float calcedDepth;\n"; + + s += + "void main() {\n" + " " MEDIUMP "float depth = texture2DProj(depthTex,vScreenCoord).r;\n"; + + bool doConditional = ((flags & SHD_CONDITIONAL) && !(flags & (SHD_EYES))); + + if (doConditional) { + // special-case completely out of focus areas and completely in-focus + // areas.. + s += " if (depth > dofRange[1] && depth < dofRange[2]) {\n"; + if (flags & SHD_HIGHER_QUALITY) { + s += + " " LOWP + "vec4 color = texture2DProj(colorTex,vScreenCoord);\n" + " " LOWP + "vec4 colorBlurred = texture2DProj(colorBlurredTex,vScreenCoord);\n" + " " LOWP + "vec4 colorBlurredMore = " + "0.4*texture2DProj(colorBlurredMoreTex,vScreenCoord);\n" + " " MEDIUMP + "vec4 diff = colorBlurred-color;\n" + " diff = sign(diff) * max(vec4(0.0),abs(diff)-0.12);\n" + " gl_FragColor = (0.55*colorBlurredMore) + " + "(0.62+colorBlurredMore)*(color-diff);\n\n"; + } else { + s += " gl_FragColor = texture2DProj(colorTex,vScreenCoord);\n"; + } + s += " }\n" + " else if (depth < dofRange[0] || depth > dofRange[3]) {\n"; + if (flags & SHD_HIGHER_QUALITY) { + s += + " " LOWP + "vec4 colorBlurred = texture2DProj(colorBlurredTex,vScreenCoord);\n" + " " LOWP + "vec4 colorBlurredMore = " + "0.4*texture2DProj(colorBlurredMoreTex,vScreenCoord);\n" + " gl_FragColor = (0.55*colorBlurredMore) + " + "(0.62+colorBlurredMore)*colorBlurred;\n\n"; + } else { + s += " gl_FragColor = " + "texture2DProj(colorBlurredMoreTex,vScreenCoord);\n"; + } + s += " }\n" + " else{\n"; + } + + // transition areas.. + s += " " LOWP "vec4 color = texture2DProj(colorTex,vScreenCoord);\n"; + if (flags & SHD_EYES) + s += " " LOWP + "vec4 colorSlightBlurred = " + "texture2DProj(colorSlightBlurredTex,vScreenCoord);\n"; + + if (flags & (SHD_HIGHER_QUALITY | SHD_EYES)) { + s += " " LOWP + "vec4 colorBlurred = texture2DProj(colorBlurredTex,vScreenCoord);\n" + " " LOWP + "vec4 colorBlurredMore = " + "0.4*texture2DProj(colorBlurredMoreTex,vScreenCoord);\n" + " " LOWP "float blur = " BLURSCALE + " (smoothstep(dofRange[2],dofRange[3],depth)\n" + " + 1.0 - " + "smoothstep(dofRange[0],dofRange[1],depth));\n" + " " MEDIUMP + "vec4 diff = colorBlurred-color;\n" + " diff = sign(diff) * max(vec4(0.0),abs(diff)-0.12);\n" + " gl_FragColor = (0.55*colorBlurredMore) + " + "(0.62+colorBlurredMore)*mix(color-diff,colorBlurred,blur);\n\n"; + } else { + s += " " LOWP + "vec4 colorBlurredMore = " + "texture2DProj(colorBlurredMoreTex,vScreenCoord);\n" + " " LOWP "float blur = " BLURSCALE + " (smoothstep(dofRange[2],dofRange[3],depth)\n" + " + 1.0 - " + "smoothstep(dofRange[0],dofRange[1],depth));\n" + " gl_FragColor = mix(color,colorBlurredMore,blur);\n\n"; + } + + if (flags & SHD_EYES) { + s += " " MEDIUMP "vec4 diffEye = colorBlurred-color;\n"; + s += " diffEye = sign(diffEye) * max(vec4(0.0),abs(diffEye)-0.06);\n"; + s += " " LOWP + "vec4 baseColorEye = " + "mix(color-10.0*(diffEye),colorSlightBlurred,0.83);\n"; + s += " " LOWP + "vec4 eyeColor = (0.55*colorBlurredMore) + " + "(0.62+colorBlurredMore)*mix(baseColorEye,colorBlurred,blur);\n\n"; + s += " " LOWP + "float dBlend = smoothstep(-0.0004,-0.0001,depth-calcedDepth);\n" + " gl_FragColor = mix(gl_FragColor,eyeColor,dBlend);\n"; + } + if (doConditional) { + s += " }\n"; + } + + // demonstrates MSAA striation issue: + // s += " gl_FragColor = + // mix(gl_FragColor,vec4(vec3(14.0*(depth-0.76)),1),0.999);\n"; + // s += " gl_FragColor = + // vec4(vec3(14.0*(texture2DProj(depthTex,vScreenCoord).r-0.76)),1);\n"; + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } +#endif // msaa bug test + + int flags_; + float dof_near_min_; + float dof_near_max_; + float dof_far_min_; + float dof_far_max_; + GLint dof_location_; + float distort_; + GLint distort_location_; +}; + +class RendererGL::SpriteProgramGL : public RendererGL::ProgramGL { + public: + enum TextureUnit { kColorTexUnit, kDepthTexUnit }; + + SpriteProgramGL(RendererGL* renderer, int flags) + : RendererGL::ProgramGL( + renderer, Object::New(GetVertexCode(flags)), + Object::New(GetFragmentCode(flags)), GetName(flags), + GetPFlags(flags)), + flags_(flags), + r_(0), + g_(0), + b_(0), + a_(0) { + SetTextureUnit("colorTex", kColorTexUnit); + + if (flags & SHD_OVERLAY) { + SetTextureUnit("depthTex", kDepthTexUnit); + } + + if (flags & SHD_COLOR) { + color_location_ = glGetUniformLocation(program(), "colorU"); + assert(color_location_ != -1); + } + DEBUG_CHECK_GL_ERROR; + } + void SetColorTexture(const TextureData* t) { + renderer()->BindTexture(GL_TEXTURE_2D, t, kColorTexUnit); + } + void SetDepthTexture(GLuint t) { + assert(flags_ & SHD_OVERLAY); + renderer()->BindTexture(GL_TEXTURE_2D, t, kDepthTexUnit); + } + void SetColor(float r, float g, float b, float a = 1.0f) { + assert(flags_ & SHD_COLOR); + assert(IsBound()); + if (r != r_ || g != g_ || b != b_ || a != a_) { + r_ = r; + g_ = g; + b_ = b; + a_ = a; + glUniform4f(color_location_, r_, g_, b_, a_); + } + } + + private: + auto GetName(int flags) -> std::string { + return std::string("SpriteProgramGL"); + } + auto GetPFlags(int flags) -> int { + int pflags = PFLAG_USES_POSITION_ATTR | PFLAG_USES_SIZE_ATTR + | PFLAG_USES_COLOR_ATTR | PFLAG_USES_UV_ATTR; + if (flags & SHD_CAMERA_ALIGNED) pflags |= PFLAG_USES_CAM_ORIENT_MATRIX; + return pflags; + } + auto GetVertexCode(int flags) -> std::string { + std::string s; + s += "uniform mat4 modelViewProjectionMatrix;\n" + "attribute vec4 position;\n" + "attribute " MEDIUMP + "vec2 uv;\n" + "attribute " MEDIUMP + "float size;\n" + "varying " MEDIUMP "vec2 vUV;\n"; + + if (flags & SHD_COLOR) s += "uniform " LOWP "vec4 colorU;\n"; + + if (flags & SHD_CAMERA_ALIGNED) s += "uniform mat4 camOrientMatrix;\n"; + + if (flags & SHD_OVERLAY) s += "varying " LOWP "vec4 vScreenCoord;\n"; + + s += "attribute " LOWP + "vec4 color;\n" + "varying " LOWP + "vec4 vColor;\n" + "void main() {\n"; + + if (flags & SHD_CAMERA_ALIGNED) + s += " " HIGHP + "vec4 pLocal = " + "(position+camOrientMatrix*vec4((uv.s-0.5)*size,0,(uv.t-0.5)*size,0)" + ");\n"; + else + s += " " HIGHP + "vec4 pLocal = " + "(position+vec4((uv.s-0.5)*size,0,(uv.t-0.5)*size,0));\n"; + s += " gl_Position = modelViewProjectionMatrix*pLocal;\n" + " vUV = uv;\n"; + if (flags & SHD_COLOR) + s += " vColor = color*colorU;\n"; + else + s += " vColor = color;\n"; + if (flags & SHD_OVERLAY) + s += " vScreenCoord = " + "vec4(gl_Position.xy/gl_Position.w,gl_Position.zw);\n" + " vScreenCoord.xy += vec2(1.0);\n" + " vScreenCoord.xy *= vec2(0.5*vScreenCoord.w);\n"; + s += "}"; + + if (flags & SHD_DEBUG_PRINT) + Log("\nVertex code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + auto GetFragmentCode(int flags) -> std::string { + std::string s; + + s += "uniform " LOWP + "sampler2D colorTex;\n" + "varying " MEDIUMP + "vec2 vUV;\n" + "varying " LOWP "vec4 vColor;\n"; + if (flags & SHD_OVERLAY) + s += "varying " MEDIUMP + "vec4 vScreenCoord;\n" + "uniform " MEDIUMP "sampler2D depthTex;\n"; + + s += "void main() {\n" + " gl_FragColor = vColor*vec4(texture2D(colorTex,vUV).r);\n"; + if (flags & SHD_EXP2) + s += " gl_FragColor = vec4(vUV,0,0) + " + "vec4(gl_FragColor.rgb*gl_FragColor.rgb,gl_FragColor.a);\n"; + if (flags & SHD_OVERLAY) { + s += " " MEDIUMP + "float depth = texture2DProj(depthTex,vScreenCoord).r;\n"; + // adreno 320 bug where depth is returned as 0..1 instead of + // glDepthRange() + if (GetFunkyDepthIssue()) { + s += " depth = " + std::to_string(kBackingDepth3) + "+depth*(" + + std::to_string(kBackingDepth4) + "-" + + std::to_string(kBackingDepth3) + ");\n"; + } + s += " gl_FragColor *= " + "(1.0-smoothstep(0.0,0.001,gl_FragCoord.z-depth));\n"; + } + s += "}"; + if (flags & SHD_DEBUG_PRINT) + Log("\nFragment code for shader '" + GetName(flags) + "':\n\n" + s); + return s; + } + float r_, g_, b_, a_; + GLint color_location_; + + int flags_; +}; + +class RendererGL::TextureDataGL : public TextureRendererData { + public: + TextureDataGL(const TextureData& texture_in, RendererGL* renderer_in) + : tex_media_(&texture_in), texture_(0), renderer_(renderer_in) { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + glGenTextures(1, &texture_); + DEBUG_CHECK_GL_ERROR; + } + + ~TextureDataGL() override { + if (!InGraphicsThread()) { + Log("Error: TextureDataGL dying outside of graphics thread."); + } else { + // if we're currently bound as anything, clear that out + // (otherwise a new texture with that same ID won't be bindable) + for (int i = 0; i < kMaxGLTexUnitsUsed; i++) { + if ((renderer_->bound_textures_2d_[i]) == texture_) { + renderer_->bound_textures_2d_[i] = -1; + } + if ((renderer_->bound_textures_cube_map_[i]) == texture_) { + renderer_->bound_textures_cube_map_[i] = -1; + } + } + if (!g_graphics_server->renderer_context_lost()) { + glDeleteTextures(1, &texture_); + DEBUG_CHECK_GL_ERROR; + } + } + } + + auto GetTexture() const -> GLuint { return texture_; } + + void Load() override { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + + if (tex_media_->texture_type() == TextureType::k2D) { + renderer_->BindTexture(GL_TEXTURE_2D, texture_); + const TexturePreloadData* preload_data = &tex_media_->preload_datas()[0]; + int base_src_level = preload_data->base_level; + assert(preload_data->buffers[base_src_level]); + GraphicsQuality q = g_graphics_server->quality(); + + // Determine whether to use anisotropic sampling on this texture: + // basically all the UI stuff that is only ever seen from straight on + // doesn't need it. + bool allow_ani = true; + + // FIXME - filtering by filename.. once we get this stuff on a server we + // should include this as metadata instead. + const char* n = tex_media_->file_name().c_str(); + + // The following exceptions should *never* need aniso-sampling. + { + if (!strcmp(n, "fontBig")) { // NOLINT(bugprone-branch-clone) + allow_ani = false; + + // Lets splurge on this for higher but not high. + // (names over characters might benefit, though most text doesnt) + } else if (strstr(n, "Icon")) { + allow_ani = false; + } else if (strstr(n, "characterIconMask")) { + allow_ani = false; + } else if (!strcmp(n, "bg")) { + allow_ani = false; + } else if (strstr(n, "light")) { + allow_ani = false; + } else if (strstr(n, "shadow")) { + allow_ani = false; + } else if (!strcmp(n, "sparks")) { + allow_ani = false; + } else if (!strcmp(n, "smoke")) { + allow_ani = false; + } else if (!strcmp(n, "scorch")) { + allow_ani = false; + } else if (!strcmp(n, "scorchBig")) { + allow_ani = false; + } else if (!strcmp(n, "white")) { + allow_ani = false; + } else if (!strcmp(n, "buttonBomb")) { + allow_ani = false; + } else if (!strcmp(n, "buttonJump")) { + allow_ani = false; + } else if (!strcmp(n, "buttonPickUp")) { + allow_ani = false; + } else if (!strcmp(n, "buttonPunch")) { + allow_ani = false; + } else if (strstr(n, "touchArrows")) { + allow_ani = false; + } else if (!strcmp(n, "actionButtons")) { + allow_ani = false; + } + } + // The following are considered 'nice to have' - we turn aniso. off for + // them in anything less than 'higher' mode. + if (allow_ani && (q < GraphicsQuality::kHigher)) { + if (strstr(n, "ColorMask")) { // NOLINT(bugprone-branch-clone) + allow_ani = false; // character color-masks + } else if (strstr(n, "softRect")) { + allow_ani = false; + } else if (strstr(n, "BG")) { + allow_ani = false; // level backgrounds + } else if (!strcmp(n, "explosion")) { + allow_ani = false; + } else if (!strcmp(n, "bar")) { + allow_ani = false; + } + } + + // In higher quality we do anisotropic trilinear mipmap. + if (q >= GraphicsQuality::kHigher) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + if (g_anisotropic_support && allow_ani) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + std::min(16.0f, g_max_anisotropy)); + } + } else if (q >= GraphicsQuality::kHigh) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + if (g_anisotropic_support && allow_ani) + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + std::min(16.0f, g_max_anisotropy)); + } else if (q >= GraphicsQuality::kMedium) { + // In medium quality we don't do anisotropy but do trilinear. + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + } else { + // in low quality we do bilinear + assert(q == GraphicsQuality::kLow); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_NEAREST); + } + + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + int src_level = base_src_level; + int level = 0; + bool all_levels_handled = false; + while (preload_data->buffers[src_level] != nullptr + && !all_levels_handled) { + switch (preload_data->formats[src_level]) { + case TextureFormat::kRGBA_8888: { + glTexImage2D(GL_TEXTURE_2D, level, GL_RGBA, + preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGBA, + GL_UNSIGNED_BYTE, preload_data->buffers[src_level]); + + // At the moment we always just let GL generate mipmaps + // for uncompressed textures; is there any reason not to? + glGenerateMipmap(GL_TEXTURE_2D); + all_levels_handled = true; + break; + } + case TextureFormat::kRGBA_4444: { + glTexImage2D( + GL_TEXTURE_2D, level, GL_RGBA, preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGBA, + GL_UNSIGNED_SHORT_4_4_4_4, preload_data->buffers[src_level]); + + // At the moment we always just let GL generate mipmaps + // for uncompressed textures; is there any reason not to? + glGenerateMipmap(GL_TEXTURE_2D); + all_levels_handled = true; + break; + } + case TextureFormat::kRGB_565: { + glTexImage2D( + GL_TEXTURE_2D, level, GL_RGB, preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, preload_data->buffers[src_level]); + + // At the moment we always just let GL generate mipmaps + // for uncompressed textures; is there any reason not to? + glGenerateMipmap(GL_TEXTURE_2D); + all_levels_handled = true; + break; + } + case TextureFormat::kRGB_888: { + glTexImage2D(GL_TEXTURE_2D, level, GL_RGB, + preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGB, + GL_UNSIGNED_BYTE, preload_data->buffers[src_level]); + + // At the moment we always just let GL generate mipmaps + // for uncompressed textures; is there any reason not to? + glGenerateMipmap(GL_TEXTURE_2D); + all_levels_handled = true; + break; + } + default: { + glCompressedTexImage2D( + GL_TEXTURE_2D, level, + GetGLTextureFormat(preload_data->formats[src_level]), + preload_data->widths[src_level], + preload_data->heights[src_level], 0, + static_cast_check_fit(preload_data->sizes[src_level]), + preload_data->buffers[src_level]); + break; + } + } + src_level++; + level++; + DEBUG_CHECK_GL_ERROR; + } + GL_LABEL_OBJECT(GL_TEXTURE, texture_, tex_media_->GetName().c_str()); + } else if (tex_media_->texture_type() == TextureType::kCubeMap) { + // Cube map. + renderer_->BindTexture(GL_TEXTURE_CUBE_MAP, texture_); + + bool do_generate_mips = false; + for (uint32_t i = 0; i < 6; i++) { + const TexturePreloadData* preload_data = + &tex_media_->preload_datas()[i]; + int base_src_level = preload_data->base_level; + assert(preload_data->buffers[base_src_level]); + + GraphicsQuality q = g_graphics_server->quality(); + + // do trilinear in higher quality; otherwise bilinear is good enough.. + if (q >= GraphicsQuality::kHigher) { + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_LINEAR); + } else { + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, + GL_LINEAR_MIPMAP_NEAREST); + } + + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, + GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, + GL_CLAMP_TO_EDGE); + + int src_level = base_src_level; + int level = 0; + bool generating_remaining_mips = false; + while (preload_data->buffers[src_level] != nullptr + && !generating_remaining_mips) { + switch (preload_data->formats[src_level]) { + case TextureFormat::kRGBA_8888: + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGBA, + preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGBA, + GL_UNSIGNED_BYTE, preload_data->buffers[src_level]); + generating_remaining_mips = do_generate_mips = true; + break; + case TextureFormat::kRGBA_4444: + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGBA, + preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGBA, + GL_UNSIGNED_SHORT_4_4_4_4, + preload_data->buffers[src_level]); + generating_remaining_mips = do_generate_mips = true; + break; + case TextureFormat::kRGB_565: + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGB, + preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, + preload_data->buffers[src_level]); + generating_remaining_mips = do_generate_mips = true; + break; + case TextureFormat::kRGB_888: + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, GL_RGB, + preload_data->widths[src_level], + preload_data->heights[src_level], 0, GL_RGB, + GL_UNSIGNED_BYTE, preload_data->buffers[src_level]); + generating_remaining_mips = do_generate_mips = true; + break; + default: + glCompressedTexImage2D( + GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, level, + GetGLTextureFormat(preload_data->formats[src_level]), + preload_data->widths[src_level], + preload_data->heights[src_level], 0, + static_cast_check_fit( + preload_data->sizes[src_level]), + preload_data->buffers[src_level]); + break; + } + src_level++; + level++; + DEBUG_CHECK_GL_ERROR; + } + } + + // If we're generating remaining mips on the gpu, do so. + if (do_generate_mips) { + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + } + + GL_LABEL_OBJECT(GL_TEXTURE, texture_, tex_media_->GetName().c_str()); + } else { + throw Exception(); + } + DEBUG_CHECK_GL_ERROR; + } + + private: + const TextureData* tex_media_; + RendererGL* renderer_; + GLuint texture_; +}; // TextureDataGL + +void RendererGL::SetViewport(GLint x, GLint y, GLsizei width, GLsizei height) { + if (x != viewport_x_ || y != viewport_y_ || width != viewport_width_ + || height != viewport_height_) { + viewport_x_ = x; + viewport_y_ = y; + viewport_width_ = width; + viewport_height_ = height; + glViewport(viewport_x_, viewport_y_, viewport_width_, viewport_height_); + } +} + +void RendererGL::SetVertexAttribArrayEnabled(GLuint i, bool enabled) { + assert(!g_vao_support); + assert(i < kVertexAttrCount); + if (enabled != vertex_attrib_arrays_enabled_[i]) { + if (enabled) { + glEnableVertexAttribArray(i); + } else { + glDisableVertexAttribArray(i); + } + vertex_attrib_arrays_enabled_[i] = enabled; + } +} + +void RendererGL::BindTextureUnit(uint32_t tex_unit) { + assert(tex_unit >= 0 && tex_unit < kMaxGLTexUnitsUsed); + if (active_tex_unit_ != tex_unit) { + glActiveTexture(GL_TEXTURE0 + tex_unit); + active_tex_unit_ = tex_unit; + } +} + +void RendererGL::BindFramebuffer(GLuint fb) { + if (active_framebuffer_ != fb) { + glBindFramebuffer(GL_FRAMEBUFFER, fb); + active_framebuffer_ = fb; + } +} + +void RendererGL::BindArrayBuffer(GLuint b) { + if (active_array_buffer_ != b) { + glBindBuffer(GL_ARRAY_BUFFER, b); + active_array_buffer_ = b; + } +} + +void RendererGL::BindTexture(GLuint type, const TextureData* t, + GLuint tex_unit) { + if (t) { + auto data = static_cast_check_type(t->renderer_data()); + BindTexture(type, data->GetTexture(), tex_unit); + } else { + // Fallback to noise. + BindTexture(type, random_tex_, tex_unit); + } +} + +void RendererGL::BindTexture(GLuint type, GLuint tex, GLuint tex_unit) { + switch (type) { + case GL_TEXTURE_2D: { + if (tex != bound_textures_2d_[tex_unit]) { + BindTextureUnit(tex_unit); + glBindTexture(type, tex); + bound_textures_2d_[tex_unit] = tex; + } + break; + } + case GL_TEXTURE_CUBE_MAP: { + if (tex != bound_textures_cube_map_[tex_unit]) { + BindTextureUnit(tex_unit); + glBindTexture(type, tex); + bound_textures_cube_map_[tex_unit] = tex; + } + break; + } + default: + throw Exception(); + } +} + +class RendererGL::ModelDataGL : public ModelRendererData { + public: + enum BufferType { kVertices, kIndices, kBufferCount }; + + ModelDataGL(const ModelData& model, RendererGL* renderer) + : renderer_(renderer), fake_vao_(nullptr) { +#if BA_DEBUG_BUILD + name_ = model.GetName(); +#endif // BA_DEBUG_BUILD + + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + + // Create our vertex array to hold all this state (if supported). + if (g_vao_support) { + glGenVertexArrays(1, &vao_); + DEBUG_CHECK_GL_ERROR; + renderer->BindVertexArray(vao_); + DEBUG_CHECK_GL_ERROR; + } else { + fake_vao_ = new FakeVertexArrayObject(renderer_); + } + + glGenBuffers(kBufferCount, vbos_); + + DEBUG_CHECK_GL_ERROR; + + // Fill our vertex data buffer. + renderer_->BindArrayBuffer(vbos_[kVertices]); + DEBUG_CHECK_GL_ERROR; + glBufferData(GL_ARRAY_BUFFER, + static_cast_check_fit(model.vertices().size() + * sizeof(VertexObjectFull)), + &(model.vertices()[0]), GL_STATIC_DRAW); + DEBUG_CHECK_GL_ERROR; + + // ..and point our array at its members. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertices], kVertexAttrPosition, 3, + GL_FLOAT, GL_FALSE, sizeof(VertexObjectFull), + offsetof(VertexObjectFull, position)); + fake_vao_->SetAttribBuffer( + vbos_[kVertices], kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexObjectFull), offsetof(VertexObjectFull, uv)); + fake_vao_->SetAttribBuffer(vbos_[kVertices], kVertexAttrNormal, 3, + GL_SHORT, GL_TRUE, sizeof(VertexObjectFull), + offsetof(VertexObjectFull, normal)); + DEBUG_CHECK_GL_ERROR; + } else { + glVertexAttribPointer( + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexObjectFull), + reinterpret_cast(offsetof(VertexObjectFull, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexObjectFull), + reinterpret_cast(offsetof(VertexObjectFull, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + glVertexAttribPointer( + kVertexAttrNormal, 3, GL_SHORT, GL_TRUE, sizeof(VertexObjectFull), + reinterpret_cast(offsetof(VertexObjectFull, normal))); + glEnableVertexAttribArray(kVertexAttrNormal); + DEBUG_CHECK_GL_ERROR; + } + + // fill our index data buffer + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[kIndices]); + if (!g_vao_support) { + assert(fake_vao_); + fake_vao_->SetElementBuffer(vbos_[kIndices]); + } + + const GLvoid* index_data; + switch (model.GetIndexSize()) { + case 1: { + elem_count_ = static_cast(model.indices8().size()); + index_type_ = GL_UNSIGNED_BYTE; + index_data = static_cast(model.indices8().data()); + break; + } + case 2: { + elem_count_ = static_cast(model.indices16().size()); + index_type_ = GL_UNSIGNED_SHORT; + index_data = static_cast(model.indices16().data()); + break; + } + case 4: { + BA_LOG_ONCE( + "GL WARNING - USING 32 BIT INDICES WHICH WONT WORK IN ES2!!"); + elem_count_ = static_cast(model.indices32().size()); + index_type_ = GL_UNSIGNED_INT; + index_data = static_cast(model.indices32().data()); + break; + } + default: + throw Exception(); + } + glBufferData( + GL_ELEMENT_ARRAY_BUFFER, + static_cast_check_fit(elem_count_ * model.GetIndexSize()), + index_data, GL_STATIC_DRAW); + + DEBUG_CHECK_GL_ERROR; + } // ModelDataGL + + ~ModelDataGL() override { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + + // Unbind if we're bound; otherwise if a new vao pops up with our same ID + // it'd be prevented from binding + if (g_vao_support) { + if (vao_ == renderer_->current_vertex_array_) { + renderer_->BindVertexArray(0); + } + if (!g_graphics_server->renderer_context_lost()) { + glDeleteVertexArrays(1, &vao_); + } + } else { + assert(fake_vao_); + delete fake_vao_; + fake_vao_ = nullptr; + } + // make sure our dying buffer isn't current.. + // (don't wanna prevent binding to a new buffer with a recycled id) + for (unsigned int vbo : vbos_) { + if (vbo == renderer_->active_array_buffer_) { + renderer_->active_array_buffer_ = -1; + } + } + if (!g_graphics_server->renderer_context_lost()) { + glDeleteBuffers(kBufferCount, vbos_); + DEBUG_CHECK_GL_ERROR; + } + } + + void Bind() { + if (g_vao_support) { + renderer_->BindVertexArray(vao_); + DEBUG_CHECK_GL_ERROR; + } else { + assert(fake_vao_); + fake_vao_->Bind(); + DEBUG_CHECK_GL_ERROR; + } + } + void Draw() { + DEBUG_CHECK_GL_ERROR; + if (elem_count_ > 0) { + glDrawElements(GL_TRIANGLES, elem_count_, index_type_, nullptr); + } + DEBUG_CHECK_GL_ERROR; + } + +#if BA_DEBUG_BUILD + auto name() const -> const std::string& { return name_; } +#endif + + private: +#if BA_DEBUG_BUILD + std::string name_; +#endif + + RendererGL* renderer_{}; + uint32_t elem_count_{}; + GLuint index_type_{}; + GLuint vao_{}; + GLuint vbos_[kBufferCount]{}; + FakeVertexArrayObject* fake_vao_{}; +}; // ModelDataGL + +class RendererGL::MeshDataGL : public MeshRendererData { + public: + enum BufferType { + kVertexBufferPrimary, + kIndexBuffer, + kVertexBufferSecondary + }; + enum Flags { + kUsesIndexBuffer = 1u, + kUsesSecondaryBuffer = 1u << 1u, + kUsesDynamicDraw = 1u << 2u + }; + MeshDataGL(RendererGL* renderer, uint32_t flags) + : renderer_(renderer), + uses_secondary_data_(static_cast(flags & kUsesSecondaryBuffer)), + uses_index_data_(static_cast(flags & kUsesIndexBuffer)) { + assert(InGraphicsThread()); + + // Create our vertex array to hold all this state. + if (g_vao_support) { + glGenVertexArrays(1, &vao_); + renderer->BindVertexArray(vao_); + } else { + fake_vao_ = new FakeVertexArrayObject(renderer_); + } + glGenBuffers(GetBufferCount(), vbos_); + } + auto uses_index_data() const -> bool { return uses_index_data_; } + + // Set us up to be recycled. + void Reset() { + index_state_ = primary_state_ = secondary_state_ = 0; + have_index_data_ = have_secondary_data_ = have_primary_data_ = false; + } + + void Bind() { + if (g_vao_support) { + renderer_->BindVertexArray(vao_); + DEBUG_CHECK_GL_ERROR; + } else { + assert(fake_vao_); + fake_vao_->Bind(); + DEBUG_CHECK_GL_ERROR; + } + } + + void Draw(DrawType draw_type) { + DEBUG_CHECK_GL_ERROR; + assert(have_primary_data_); + assert(have_index_data_ || !uses_index_data_); + assert(have_secondary_data_ || !uses_secondary_data_); + GLuint gl_draw_type; + switch (draw_type) { + case DrawType::kTriangles: + gl_draw_type = GL_TRIANGLES; + break; + case DrawType::kPoints: + gl_draw_type = GL_POINTS; + break; + default: + throw Exception(); + } + if (uses_index_data_) { + glDrawElements(gl_draw_type, elem_count_, index_type_, nullptr); + } else { + glDrawArrays(gl_draw_type, 0, elem_count_); + } + DEBUG_CHECK_GL_ERROR; + } + + ~MeshDataGL() override { + assert(InGraphicsThread()); + // unbind if we're bound .. otherwise we might prevent a new with our ID + // from binding + if (g_vao_support) { + if (vao_ == renderer_->current_vertex_array_) { + renderer_->BindVertexArray(0); + } + if (!g_graphics_server->renderer_context_lost()) { + glDeleteVertexArrays(1, &vao_); + } + } else { + assert(fake_vao_); + delete fake_vao_; + fake_vao_ = nullptr; + } + // make sure our dying buffer isn't current.. + // (don't wanna prevent binding to a new buffer with a recycled id) + for (int i = 0; i < GetBufferCount(); i++) { + if (vbos_[i] == renderer_->active_array_buffer_) { + renderer_->active_array_buffer_ = -1; + } + } + if (!g_graphics_server->renderer_context_lost()) { + glDeleteBuffers(GetBufferCount(), vbos_); + DEBUG_CHECK_GL_ERROR; + } + } + + void SetIndexData(MeshIndexBuffer32* data) { + assert(uses_index_data_); + if (data->state != index_state_) { + if (g_vao_support) { + renderer_->BindVertexArray(vao_); + } else { + assert(fake_vao_); + fake_vao_->SetElementBuffer(vbos_[kIndexBuffer]); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[kIndexBuffer]); + elem_count_ = static_cast(data->elements.size()); + assert(elem_count_ > 0); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + static_cast_check_fit( + data->elements.size() * sizeof(data->elements[0])), + &data->elements[0], + dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + index_state_ = data->state; + have_index_data_ = true; + BA_LOG_ONCE("GL WARNING - USING 32 BIT INDICES WHICH WONT WORK IN ES2!!"); + index_type_ = GL_UNSIGNED_INT; + } + } + void SetIndexData(MeshIndexBuffer16* data) { + assert(uses_index_data_); + if (data->state != index_state_) { + if (g_vao_support) { + renderer_->BindVertexArray(vao_); + } else { + assert(fake_vao_); + fake_vao_->SetElementBuffer(vbos_[kIndexBuffer]); + } + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbos_[kIndexBuffer]); + elem_count_ = static_cast(data->elements.size()); + assert(elem_count_ > 0); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + static_cast_check_fit( + data->elements.size() * sizeof(data->elements[0])), + &data->elements[0], + dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + index_state_ = data->state; + have_index_data_ = true; + index_type_ = GL_UNSIGNED_SHORT; + } + } + + // When dynamic-draw is on, it means *all* buffers should be flagged as + // dynamic. + void set_dynamic_draw(bool enable) { dynamic_draw_ = enable; } + + auto vao() const -> GLuint { return vao_; } + + protected: + template + void UpdateBufferData(BufferType buffer_type, MeshBuffer* data, + uint32_t* state, bool* have, GLuint draw_type) { + assert(state && have); + if (data->state != *state) { + DEBUG_CHECK_GL_ERROR; + + // Hmmm didnt think we had to have vao bound here but causes problems on + // qualcomm if not. +#if BA_OSTYPE_ANDROID + if (g_vao_support && renderer_->is_adreno_) { + renderer_->BindVertexArray(vao_); + } +#endif + renderer_->BindArrayBuffer(vbos_[buffer_type]); + assert(!data->elements.empty()); + if (!uses_index_data_ && buffer_type == kVertexBufferPrimary) { + elem_count_ = static_cast(data->elements.size()); + } + glBufferData(GL_ARRAY_BUFFER, + static_cast(data->elements.size() + * sizeof(data->elements[0])), + &(data->elements[0]), draw_type); + DEBUG_CHECK_GL_ERROR; + *state = data->state; + *have = true; + } else { + assert(*have); + } + } + + // FIXME - we should do some sort of ring-buffer system. + GLuint vbos_[3]{}; + GLuint vao_{}; + auto GetBufferCount() const -> int { + return uses_secondary_data_ ? 3 : (uses_index_data_ ? 2 : 1); + } + bool uses_index_data_{}; + bool uses_secondary_data_{}; + uint32_t index_state_{}; + uint32_t primary_state_{}; + uint32_t secondary_state_{}; + bool dynamic_draw_{}; + bool have_index_data_{}; + bool have_primary_data_{}; + bool have_secondary_data_{}; + RendererGL* renderer_{}; + uint32_t elem_count_{}; + GLuint index_type_{GL_UNSIGNED_SHORT}; + FakeVertexArrayObject* fake_vao_{}; +}; // MeshDataGL + +class RendererGL::MeshDataSimpleSplitGL : public RendererGL::MeshDataGL { + public: + explicit MeshDataSimpleSplitGL(RendererGL* renderer) + : MeshDataGL(renderer, kUsesSecondaryBuffer | kUsesIndexBuffer) { + // Set up our static vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrUV, 2, + GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexSimpleSplitStatic), + offsetof(VertexSimpleSplitStatic, uv)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexSimpleSplitStatic), + reinterpret_cast(offsetof(VertexSimpleSplitStatic, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + } + + // ..and our dynamic vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferSecondary], + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexSimpleSplitDynamic), + offsetof(VertexSimpleSplitDynamic, position)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferSecondary]); + glVertexAttribPointer(kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexSimpleSplitDynamic), + reinterpret_cast( + offsetof(VertexSimpleSplitDynamic, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + } + } + void SetStaticData(MeshBuffer* data) { + UpdateBufferData(kVertexBufferPrimary, data, &primary_state_, + &have_primary_data_, GL_STATIC_DRAW); + } + void SetDynamicData(MeshBuffer* data) { + assert(uses_secondary_data_); + UpdateBufferData(kVertexBufferSecondary, data, &secondary_state_, + &have_secondary_data_, + GL_DYNAMIC_DRAW); // this is *always* dynamic + } +}; + +class RendererGL::MeshDataObjectSplitGL : public RendererGL::MeshDataGL { + public: + explicit MeshDataObjectSplitGL(RendererGL* renderer) + : MeshDataGL(renderer, kUsesSecondaryBuffer | kUsesIndexBuffer) { + // Set up our static vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrUV, 2, + GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexObjectSplitStatic), + offsetof(VertexObjectSplitStatic, uv)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexObjectSplitStatic), + reinterpret_cast(offsetof(VertexObjectSplitStatic, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + } + + // ..and our dynamic vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferSecondary], + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexObjectSplitDynamic), + offsetof(VertexObjectSplitDynamic, position)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferSecondary], + kVertexAttrNormal, 3, GL_SHORT, GL_TRUE, + sizeof(VertexObjectSplitDynamic), + offsetof(VertexObjectSplitDynamic, normal)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferSecondary]); + glVertexAttribPointer(kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexObjectSplitDynamic), + reinterpret_cast( + offsetof(VertexObjectSplitDynamic, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + glVertexAttribPointer( + kVertexAttrNormal, 3, GL_SHORT, GL_TRUE, + sizeof(VertexObjectSplitDynamic), + reinterpret_cast(offsetof(VertexObjectSplitDynamic, normal))); + glEnableVertexAttribArray(kVertexAttrNormal); + } + } + void SetStaticData(MeshBuffer* data) { + UpdateBufferData(kVertexBufferPrimary, data, &primary_state_, + &have_primary_data_, GL_STATIC_DRAW); + } + void SetDynamicData(MeshBuffer* data) { + assert(uses_secondary_data_); + UpdateBufferData(kVertexBufferSecondary, data, &secondary_state_, + &have_secondary_data_, + GL_DYNAMIC_DRAW); // this is *always* dynamic + } +}; + +class RendererGL::MeshDataSimpleFullGL : public RendererGL::MeshDataGL { + public: + explicit MeshDataSimpleFullGL(RendererGL* renderer) + : MeshDataGL(renderer, kUsesIndexBuffer) { + // Set up our vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer( + vbos_[kVertexBufferPrimary], kVertexAttrUV, 2, GL_UNSIGNED_SHORT, + GL_TRUE, sizeof(VertexSimpleFull), offsetof(VertexSimpleFull, uv)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexSimpleFull), + offsetof(VertexSimpleFull, position)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexSimpleFull), + reinterpret_cast(offsetof(VertexSimpleFull, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + glVertexAttribPointer( + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexSimpleFull), + reinterpret_cast(offsetof(VertexSimpleFull, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + } + } + void SetData(MeshBuffer* data) { + UpdateBufferData(kVertexBufferPrimary, data, &primary_state_, + &have_primary_data_, + dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + } +}; + +class RendererGL::MeshDataDualTextureFullGL : public RendererGL::MeshDataGL { + public: + explicit MeshDataDualTextureFullGL(RendererGL* renderer) + : MeshDataGL(renderer, kUsesIndexBuffer) { + // Set up our vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrUV, 2, + GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexDualTextureFull), + offsetof(VertexDualTextureFull, uv)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrUV2, 2, + GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexDualTextureFull), + offsetof(VertexDualTextureFull, uv2)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexDualTextureFull), + offsetof(VertexDualTextureFull, position)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexDualTextureFull), + reinterpret_cast(offsetof(VertexDualTextureFull, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + glVertexAttribPointer( + kVertexAttrUV2, 2, GL_UNSIGNED_SHORT, GL_TRUE, + sizeof(VertexDualTextureFull), + reinterpret_cast(offsetof(VertexDualTextureFull, uv2))); + glEnableVertexAttribArray(kVertexAttrUV2); + glVertexAttribPointer( + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexDualTextureFull), + reinterpret_cast(offsetof(VertexDualTextureFull, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + } + } + void SetData(MeshBuffer* data) { + UpdateBufferData(kVertexBufferPrimary, data, &primary_state_, + &have_primary_data_, + dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + } +}; + +class RendererGL::MeshDataSmokeFullGL : public RendererGL::MeshDataGL { + public: + explicit MeshDataSmokeFullGL(RendererGL* renderer) + : MeshDataGL(renderer, kUsesIndexBuffer) { + // Set up our vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrUV, 2, + GL_FLOAT, GL_FALSE, sizeof(VertexSmokeFull), + offsetof(VertexSmokeFull, uv)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, + sizeof(VertexSmokeFull), + offsetof(VertexSmokeFull, position)); + fake_vao_->SetAttribBuffer( + vbos_[kVertexBufferPrimary], kVertexAttrErode, 1, GL_UNSIGNED_BYTE, + GL_TRUE, sizeof(VertexSmokeFull), offsetof(VertexSmokeFull, erode)); + fake_vao_->SetAttribBuffer( + vbos_[kVertexBufferPrimary], kVertexAttrDiffuse, 1, GL_UNSIGNED_BYTE, + GL_TRUE, sizeof(VertexSmokeFull), offsetof(VertexSmokeFull, diffuse)); + fake_vao_->SetAttribBuffer( + vbos_[kVertexBufferPrimary], kVertexAttrColor, 4, GL_UNSIGNED_BYTE, + GL_TRUE, sizeof(VertexSmokeFull), offsetof(VertexSmokeFull, color)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_FLOAT, GL_FALSE, sizeof(VertexSmokeFull), + reinterpret_cast(offsetof(VertexSmokeFull, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + glVertexAttribPointer( + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexSmokeFull), + reinterpret_cast(offsetof(VertexSmokeFull, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + glVertexAttribPointer( + kVertexAttrErode, 1, GL_UNSIGNED_BYTE, GL_TRUE, + sizeof(VertexSmokeFull), + reinterpret_cast(offsetof(VertexSmokeFull, erode))); + glEnableVertexAttribArray(kVertexAttrErode); + glVertexAttribPointer( + kVertexAttrDiffuse, 1, GL_UNSIGNED_BYTE, GL_TRUE, + sizeof(VertexSmokeFull), + reinterpret_cast(offsetof(VertexSmokeFull, diffuse))); + glEnableVertexAttribArray(kVertexAttrDiffuse); + glVertexAttribPointer( + kVertexAttrColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, + sizeof(VertexSmokeFull), + reinterpret_cast(offsetof(VertexSmokeFull, color))); + glEnableVertexAttribArray(kVertexAttrColor); + } + } + void SetData(MeshBuffer* data) { + UpdateBufferData(kVertexBufferPrimary, data, &primary_state_, + &have_primary_data_, + dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + } +}; + +class RendererGL::MeshDataSpriteGL : public RendererGL::MeshDataGL { + public: + explicit MeshDataSpriteGL(RendererGL* renderer) + : MeshDataGL(renderer, kUsesIndexBuffer) { + // Set up our vertex data. + if (fake_vao_) { + fake_vao_->SetAttribBuffer( + vbos_[kVertexBufferPrimary], kVertexAttrPosition, 3, GL_FLOAT, + GL_FALSE, sizeof(VertexSprite), offsetof(VertexSprite, position)); + fake_vao_->SetAttribBuffer( + vbos_[kVertexBufferPrimary], kVertexAttrUV, 2, GL_UNSIGNED_SHORT, + GL_TRUE, sizeof(VertexSprite), offsetof(VertexSprite, uv)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrSize, + 1, GL_FLOAT, GL_FALSE, sizeof(VertexSprite), + offsetof(VertexSprite, size)); + fake_vao_->SetAttribBuffer(vbos_[kVertexBufferPrimary], kVertexAttrColor, + 4, GL_FLOAT, GL_FALSE, sizeof(VertexSprite), + offsetof(VertexSprite, color)); + } else { + renderer_->BindArrayBuffer(vbos_[kVertexBufferPrimary]); + glVertexAttribPointer( + kVertexAttrPosition, 3, GL_FLOAT, GL_FALSE, sizeof(VertexSprite), + reinterpret_cast(offsetof(VertexSprite, position))); + glEnableVertexAttribArray(kVertexAttrPosition); + glVertexAttribPointer( + kVertexAttrUV, 2, GL_UNSIGNED_SHORT, GL_TRUE, sizeof(VertexSprite), + reinterpret_cast(offsetof(VertexSprite, uv))); + glEnableVertexAttribArray(kVertexAttrUV); + glVertexAttribPointer( + kVertexAttrSize, 1, GL_FLOAT, GL_FALSE, sizeof(VertexSprite), + reinterpret_cast(offsetof(VertexSprite, size))); + glEnableVertexAttribArray(kVertexAttrSize); + glVertexAttribPointer( + kVertexAttrColor, 4, GL_FLOAT, GL_FALSE, sizeof(VertexSprite), + reinterpret_cast(offsetof(VertexSprite, color))); + glEnableVertexAttribArray(kVertexAttrColor); + } + } + void SetData(MeshBuffer* data) { + UpdateBufferData(kVertexBufferPrimary, data, &primary_state_, + &have_primary_data_, + dynamic_draw_ ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + } +}; + +class RendererGL::RenderTargetGL : public RenderTarget { + public: + void Bind() { + if (type_ == Type::kFramebuffer) { + assert(framebuffer_.exists()); + framebuffer_->Bind(); + } else { + assert(type_ == Type::kScreen); + renderer_->BindFramebuffer(renderer_->screen_framebuffer_); + } + } + + void DrawBegin(bool must_clear_color, float clear_r, float clear_g, + float clear_b, float clear_a) override { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + + Bind(); + +#if BA_CARDBOARD_BUILD + int x, y; + // viewport offsets only apply to the screen render-target + if (type_ == Type::kScreen) { + x = renderer_->VRGetViewportX(); + y = renderer_->VRGetViewportY(); + } else { + x = 0; + y = 0; + } + renderer_->SetViewport(x, y, physical_width_, physical_height_); +#else + renderer_->SetViewport(0, 0, static_cast(physical_width_), + static_cast(physical_height_)); +#endif + + { + // Clear depth, color, etc. + GLuint clear_mask = 0; + + // If they *requested* a clear for color, do so. Otherwise invalidate. + if (must_clear_color) { + clear_mask |= GL_COLOR_BUFFER_BIT; + } else { + renderer_->InvalidateFramebuffer(true, false, false); + } + + if (depth_) { + // FIXME make sure depth writing is turned on at this point. + // this needs to be on for glClear to work on depth. + if (!renderer_->depth_writing_enabled_) { + BA_LOG_ONCE( + "RendererGL: depth-writing not enabled when clearing depth"); + } + clear_mask |= GL_DEPTH_BUFFER_BIT; + } + + if (clear_mask != 0) { + if (clear_mask & GL_COLOR_BUFFER_BIT) { + glClearColor(clear_r, clear_g, clear_b, clear_a); + DEBUG_CHECK_GL_ERROR; + } + glClear(clear_mask); + DEBUG_CHECK_GL_ERROR; + } + } + } + + auto GetFramebufferID() -> GLuint { + if (type_ == Type::kFramebuffer) { + assert(framebuffer_.exists()); + return framebuffer_->id(); + } else { + return 0; // screen + } + } + auto framebuffer() -> FramebufferObjectGL* { + assert(type_ == Type::kFramebuffer); + return framebuffer_.get(); + } + // Screen. + explicit RenderTargetGL(RendererGL* renderer) + : RenderTarget(Type::kScreen), renderer_(renderer) { + assert(InGraphicsThread()); + depth_ = true; + + // This will update our width/height values. + ScreenSizeChanged(); + } + + // Framebuffer. + RenderTargetGL(RendererGL* renderer, int width, int height, + bool linear_interp, bool depth, bool texture, + bool depth_texture, bool high_quality, bool msaa, bool alpha) + : RenderTarget(Type::kFramebuffer), renderer_(renderer) { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + framebuffer_ = Object::New( + renderer, width, height, linear_interp, depth, texture, depth_texture, + high_quality, msaa, alpha); + physical_width_ = static_cast(width); + physical_height_ = static_cast(height); + depth_ = depth; + DEBUG_CHECK_GL_ERROR; + } + + private: + Object::Ref framebuffer_; + RendererGL* renderer_{}; + friend class RenderPass; +}; // RenderTargetGL + +RendererGL::RendererGL() { + if (explicit_bool(FORCE_CHECK_GL_ERRORS)) { + ScreenMessage("GL ERROR CHECKS ENABLED"); + } + + // For some reason we're getting an immediately + // GL_INVALID_FRAMEBUFFER_OPERATION on EL-CAPITAN, though we shouldn't have + // run any gl code yet. might be worth looking into at some point, but gonna + // ignore for now. +#if BA_OSTYPE_MACOS + glGetError(); +#endif // BA_OSTYPE_MACOS + + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + + SyncGLState(); + DEBUG_CHECK_GL_ERROR; +} + +void RendererGL::CheckFunkyDepthIssue() { + if (funky_depth_issue_set_) { + return; + } + + // Note: this test fails for some reason on some Broadcom VideoCore and older + // NVidia chips (tegra 2?) + // ...so lets limit testing to adreno chips since that's the only place the + // problem is known to happen. + if (!is_adreno_ || !supports_depth_textures_) { + funky_depth_issue_set_ = true; + funky_depth_issue_ = false; + return; + } + + // on some adreno chips, depth buffer values are always returned + // in a 0-1 range in shaders even if a depth range is set; everywhere + // else they return that depth range. + // to test for this we can create a temp buffer, clear it, set a depth range, + // Log("RUNNING DEPTH TEST"); + + Object::Ref test_rt1; + Object::Ref test_rt2; + + test_rt1 = Object::New(this, 32, 32, true, true, true, true, + false, false, false); + DEBUG_CHECK_GL_ERROR; + test_rt2 = Object::New(this, 32, 32, true, false, true, false, + false, false, false); + DEBUG_CHECK_GL_ERROR; + + // this screws up some qualcomm chips.. + SetDepthRange(0.0f, 0.5f); + + // draw a flat color plane into our first render target + SetDepthWriting(true); + SetDepthTesting(true); + SetBlend(false); + SetDoubleSided(false); + test_rt1->DrawBegin(true, 1.0f, 1.0f, 1.0f, 1.0f); + SimpleProgramGL* p = simple_color_prog_; + p->Bind(); + p->SetColor(1, 0, 1); + g_graphics_server->ModelViewReset(); + g_graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 1); + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + DEBUG_CHECK_GL_ERROR; + + // now draw into a second buffer the difference between the + // depth tex lookup and the gl frag depth. + SetDepthWriting(false); + SetDepthTesting(false); + SetBlend(false); + SetDoubleSided(false); + test_rt2->DrawBegin(false, 1.0f, 1.0f, 1.0f, 1.0f); + p = simple_tex_dtest_prog_; + p->Bind(); + g_graphics_server->ModelViewReset(); + g_graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 1); + p->SetColorTexture(test_rt1->framebuffer()->depth_texture()); + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + DEBUG_CHECK_GL_ERROR; + + // now sample a pixel from our render-target + // if the depths matched, the value will be 0; otherwise it'll be 30 or so + // (allow a bit of leeway to account for dithering/etc..) + uint8_t buffer[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + glReadPixels(0, 0, 2, 2, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + + // sample 4 pixels to reduce effects of dithering.. + funky_depth_issue_ = + ((buffer[0] + buffer[4] + buffer[8] + buffer[12]) / 4 >= 15); + funky_depth_issue_set_ = true; + + DEBUG_CHECK_GL_ERROR; +} + +void RendererGL::PushGroupMarker(const char* label) { + GL_PUSH_GROUP_MARKER(label); +} +void RendererGL::PopGroupMarker() { GL_POP_GROUP_MARKER(); } + +void RendererGL::InvalidateFramebuffer(bool color, bool depth, + bool target_read_framebuffer) { + DEBUG_CHECK_GL_ERROR; + + // currently discard is mobile only +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + + if (g_discard_framebuffer_support || g_invalidate_framebuffer_support) { + GLenum attachments[5]; + // need to use different flags for the main framebuffer.. + int count = 0; + if (active_framebuffer_ == 0 && !target_read_framebuffer) { + if (color) { + attachments[count++] = GL_COLOR_EXT; + } + if (depth) { + attachments[count++] = GL_DEPTH_EXT; + } + } else { + if (color) { + attachments[count++] = GL_COLOR_ATTACHMENT0; + } + if (depth) { + attachments[count++] = GL_DEPTH_ATTACHMENT; + } + } + // apparently the oculus docs say glInvalidateFramebuffer errors + // on a mali es3 implementation so they always use glDiscard when present... + if (g_invalidate_framebuffer_support) { +#if BA_OSTYPE_IOS_TVOS + throw Exception(); // shouldnt happen +#else + glInvalidateFramebuffer( + target_read_framebuffer ? GL_READ_FRAMEBUFFER : GL_FRAMEBUFFER, count, + attachments); +#endif + } else { + // if we've got a read-framebuffer we should have invalidate too.. + assert(!target_read_framebuffer); + glDiscardFramebufferEXT(GL_FRAMEBUFFER, count, attachments); + } + DEBUG_CHECK_GL_ERROR; + } +#endif // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID +} + +RendererGL::~RendererGL() { + assert(InGraphicsThread()); + printf("FIXME: need to unload renderer on destroy.\n"); + // Unload(); + DEBUG_CHECK_GL_ERROR; +} + +void RendererGL::UseProgram(ProgramGL* p) { + if (p != current_program_) { + glUseProgram(p->program()); + current_program_ = p; + } +} + +void RendererGL::SyncGLState() { +#if BA_RIFT_BUILD + if (IsVRMode()) { + glFrontFace(GL_CCW); + } + + // if (time(nullptr)%2 == 0) { + // glEnable(GL_FRAMEBUFFER_SRGB); + // } else { + // glDisable(GL_FRAMEBUFFER_SRGB); + // } +#endif // BA_RIFT_BUILD + + active_tex_unit_ = -1; // force a set next time + active_framebuffer_ = -1; // ditto + active_array_buffer_ = -1; // ditto + for (int i = 0; i < kMaxGLTexUnitsUsed; i++) { + bound_textures_2d_[i] = -1; // ditto + bound_textures_cube_map_[i] = -1; // ditto + } + glUseProgram(0); + current_program_ = nullptr; + current_vertex_array_ = 0; + + if (g_vao_support) { + glBindVertexArray(0); + } else { + for (GLuint i = 0; i < kVertexAttrCount; i++) { + glDisableVertexAttribArray(i); + vertex_attrib_arrays_enabled_[i] = false; + } + } + + // wack these out so the next call will definitely call glViewport + viewport_x_ = -9999; + viewport_y_ = -9999; + viewport_width_ = -9999; + viewport_height_ = -9999; + + glDisable(GL_BLEND); + blend_ = false; + + // currently we only ever write to an alpha buffer for our vr flat overlay + // texture, and in that case we need alpha to accumulate; not get overwritten. + // could probably enable this everywhere but I don't know if it's supported on + // all hardware or slower.. + if (IsVRMode()) { +#if BA_OSTYPE_WINDOWS + if (glBlendFuncSeparate == nullptr) { + throw Exception( + "VR mode is not supported by your GPU (no glBlendFuncSeparate); Try " + "updating your drivers?..."); + } +#endif // BA_WINDOWS_BUILD + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + blend_premult_ = false; + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + double_sided_ = false; + draw_front_ = true; + glDisable(GL_DEPTH_TEST); + depth_testing_enabled_ = false; + glDepthMask(static_cast(true)); + depth_writing_enabled_ = true; + draw_at_equal_depth_ = false; + glDepthFunc(GL_LESS); + depth_range_min_ = 0.0f; + depth_range_max_ = 1.0f; + glDepthRange(depth_range_min_, depth_range_max_); +} + +#define GET_MESH_DATA(TYPE, VAR) \ + auto* VAR = static_cast(mesh_data->renderer_data()); \ + assert(VAR&& VAR == dynamic_cast(mesh_data->renderer_data())) + +#define GET_INDEX_BUFFER() \ + assert(buffer != buffers.end()); \ + assert(index_size != index_sizes.end()); \ + MeshIndexBuffer16* indices16{nullptr}; \ + MeshIndexBuffer32* indices32{nullptr}; \ + assert(*index_size == 4 || *index_size == 2); \ + bool use_indices32 = (*index_size == 4); \ + if (use_indices32) { \ + indices32 = static_cast(buffer->get()); \ + assert(indices32&& indices32 \ + == dynamic_cast(buffer->get())); \ + } else { \ + indices16 = static_cast(buffer->get()); \ + assert(indices16&& indices16 \ + == dynamic_cast(buffer->get())); \ + } \ + index_size++; \ + buffer++ + +#define GET_BUFFER(TYPE, VAR) \ + assert(buffer != buffers.end()); \ + auto* VAR = static_cast(buffer->get()); \ + assert(VAR&& VAR == dynamic_cast(buffer->get())); \ + buffer++ + +// Takes all latest mesh data from the client side and applies it +// to our gl implementations. +void RendererGL::UpdateMeshes( + const std::vector >& meshes, + const std::vector& index_sizes, + const std::vector >& buffers) { + auto index_size = index_sizes.begin(); + auto buffer = buffers.begin(); + for (auto&& mesh : meshes) { + // For each mesh, plug in the latest and greatest buffers it + // should be using. + MeshData* mesh_data = mesh->mesh_data; + switch (mesh_data->type()) { + case MeshDataType::kIndexedSimpleSplit: { + GET_MESH_DATA(MeshDataSimpleSplitGL, m); + GET_INDEX_BUFFER(); + GET_BUFFER(MeshBuffer, static_data); + GET_BUFFER(MeshBuffer, dynamic_data); + if (use_indices32) { + m->SetIndexData(indices32); + } else { + m->SetIndexData(indices16); + } + m->SetStaticData(static_data); + m->SetDynamicData(dynamic_data); + break; + } + case MeshDataType::kIndexedObjectSplit: { + GET_MESH_DATA(MeshDataObjectSplitGL, m); + GET_INDEX_BUFFER(); + GET_BUFFER(MeshBuffer, static_data); + GET_BUFFER(MeshBuffer, dynamic_data); + if (use_indices32) { + m->SetIndexData(indices32); + } else { + m->SetIndexData(indices16); + } + m->SetStaticData(static_data); + m->SetDynamicData(dynamic_data); + break; + } + case MeshDataType::kIndexedSimpleFull: { + GET_MESH_DATA(MeshDataSimpleFullGL, m); + GET_INDEX_BUFFER(); + GET_BUFFER(MeshBuffer, data); + if (use_indices32) { + m->SetIndexData(indices32); + } else { + m->SetIndexData(indices16); + } + m->SetData(data); + break; + } + case MeshDataType::kIndexedDualTextureFull: { + GET_MESH_DATA(MeshDataDualTextureFullGL, m); + GET_INDEX_BUFFER(); + GET_BUFFER(MeshBuffer, data); + if (use_indices32) { + m->SetIndexData(indices32); + } else { + m->SetIndexData(indices16); + } + m->SetData(data); + break; + } + case MeshDataType::kIndexedSmokeFull: { + GET_MESH_DATA(MeshDataSmokeFullGL, m); + GET_INDEX_BUFFER(); + GET_BUFFER(MeshBuffer, data); + if (use_indices32) { + m->SetIndexData(indices32); + } else { + m->SetIndexData(indices16); + } + m->SetData(data); + break; + } + case MeshDataType::kSprite: { + GET_MESH_DATA(MeshDataSpriteGL, m); + GET_INDEX_BUFFER(); + GET_BUFFER(MeshBuffer, data); + if (use_indices32) { + m->SetIndexData(indices32); + } else { + m->SetIndexData(indices16); + } + m->SetData(data); + break; + } + default: + throw Exception("Invalid meshdata type: " + + std::to_string(static_cast(mesh_data->type()))); + } + } + // We should have gone through all lists exactly.. + assert(index_size == index_sizes.end()); + assert(buffer == buffers.end()); +} +#undef GET_MESH_DATA +#undef GET_BUFFER +#undef GET_INDEX_BUFFER + +void RendererGL::StandardPostProcessSetup(PostProcessProgramGL* p, + const RenderPass& pass) { + auto* cam_target = static_cast(camera_render_target()); + assert(cam_target + && dynamic_cast(camera_render_target()) + == cam_target); + RenderPass* beauty_pass = pass.frame_def()->beauty_pass(); + assert(beauty_pass); + SetDoubleSided(false); + SetBlend(false); + p->Bind(); + p->SetColorTexture(cam_target->framebuffer()->texture()); + if (p->UsesSlightBlurredTex()) { + p->SetColorSlightBlurredTexture(blur_buffers_[0]->texture()); + } + if (blur_buffers_.size() > 1) { + if (p->UsesBlurredTexture()) { + p->SetColorBlurredTexture(blur_buffers_[1]->texture()); + } + p->SetColorBlurredMoreTexture( + blur_buffers_[blur_buffers_.size() - 1]->texture()); + } else { + if (p->UsesBlurredTexture()) { + p->SetColorBlurredTexture(blur_buffers_[0]->texture()); + } + p->SetColorBlurredMoreTexture(blur_buffers_[0]->texture()); + } + p->SetDepthTexture(cam_target->framebuffer()->depth_texture()); + float dof_near_smoothed = this->dof_near_smoothed(); + float dof_far_smoothed = this->dof_far_smoothed(); + if (pass.frame_def()->orbiting()) { + p->SetDepthOfFieldRanges( + GetZBufferValue(beauty_pass, 0.80f * dof_near_smoothed), + GetZBufferValue(beauty_pass, 0.91f * dof_near_smoothed), + GetZBufferValue(beauty_pass, 1.01f * dof_far_smoothed), + GetZBufferValue(beauty_pass, 1.10f * dof_far_smoothed)); + } else { + p->SetDepthOfFieldRanges( + GetZBufferValue(beauty_pass, 0.93f * dof_near_smoothed), + GetZBufferValue(beauty_pass, 0.99f * dof_near_smoothed), + GetZBufferValue(beauty_pass, 1.03f * dof_far_smoothed), + GetZBufferValue(beauty_pass, 1.09f * dof_far_smoothed)); + } +} + +void RendererGL::ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, + const RenderPass& pass, + RenderTarget* render_target) { + buffer->ReadBegin(); + RenderCommandBuffer::Command cmd; + while ((cmd = buffer->GetCommand()) != RenderCommandBuffer::Command::kEnd) { + switch (cmd) { + case RenderCommandBuffer::Command::kEnd: + break; + case RenderCommandBuffer::Command::kShader: { + auto shader = static_cast(buffer->GetInt()); + switch (shader) { + case ShadingType::kSimpleColor: { + SetDoubleSided(false); + SetBlend(false); + SimpleProgramGL* p = simple_color_prog_; + p->Bind(); + float r, g, b; + buffer->GetFloats(&r, &g, &b); + p->SetColor(r, g, b); + break; + } + case ShadingType::kSimpleColorTransparent: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + SimpleProgramGL* p = simple_color_prog_; + p->Bind(); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + p->SetColor(r, g, b, a); + break; + } + case ShadingType::kSimpleColorTransparentDoubleSided: { + SetDoubleSided(true); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + SimpleProgramGL* p = simple_color_prog_; + p->Bind(); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + p->SetColor(r, g, b, a); + break; + } + case ShadingType::kSimpleTexture: { + SetDoubleSided(false); + SetBlend(false); + SimpleProgramGL* p = simple_tex_prog_; + p->Bind(); + p->SetColorTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulatedTransparent: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + SimpleProgramGL* p = simple_tex_mod_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulatedTransFlatness: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, flatness; + buffer->GetFloats(&r, &g, &b, &a, &flatness); + SimpleProgramGL* p = simple_tex_mod_flatness_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetFlatness(flatness); + break; + } + case ShadingType::kSimpleTextureModulatedTransparentShadow: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, shadow_offset_x, shadow_offset_y, shadow_blur, + shadow_opacity; + buffer->GetFloats(&r, &g, &b, &a, &shadow_offset_x, + &shadow_offset_y, &shadow_blur, &shadow_opacity); + SimpleProgramGL* p = simple_tex_mod_shadow_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + const TextureData* t = buffer->GetTexture(); + const TextureData* t_mask = buffer->GetTexture(); + p->SetColorTexture(t); + // If this isn't a full-res texture, ramp down the blurring we do. + p->SetShadow(shadow_offset_x, shadow_offset_y, + std::max(0.0f, shadow_blur), shadow_opacity); + p->SetMaskUV2Texture(t_mask); + break; + } + case ShadingType::kSimpleTexModulatedTransShadowFlatness: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, shadow_offset_x, shadow_offset_y, shadow_blur, + shadow_opacity, flatness; + buffer->GetFloats(&r, &g, &b, &a, &shadow_offset_x, + &shadow_offset_y, &shadow_blur, &shadow_opacity, + &flatness); + SimpleProgramGL* p = simple_tex_mod_shadow_flatness_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + const TextureData* t = buffer->GetTexture(); + const TextureData* t_mask = buffer->GetTexture(); + p->SetColorTexture(t); + // If this isn't a full-res texture, ramp down the blurring we do. + p->SetShadow(shadow_offset_x, shadow_offset_y, + std::max(0.0f, shadow_blur), shadow_opacity); + p->SetMaskUV2Texture(t_mask); + p->SetFlatness(flatness); + break; + } + case ShadingType::kSimpleTextureModulatedTransparentGlow: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, glow_amount, glow_blur; + buffer->GetFloats(&r, &g, &b, &a, &glow_amount, &glow_blur); + SimpleProgramGL* p = simple_tex_mod_glow_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + const TextureData* t = buffer->GetTexture(); + p->SetColorTexture(t); + + // Glow. + p->setGlow(glow_amount, std::max(0.0f, glow_blur)); + break; + } + case ShadingType::kSimpleTextureModulatedTransparentGlowMaskUV2: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, glow_amount, glow_blur; + buffer->GetFloats(&r, &g, &b, &a, &glow_amount, &glow_blur); + SimpleProgramGL* p = simple_tex_mod_glow_maskuv2_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + const TextureData* t = buffer->GetTexture(); + p->SetColorTexture(t); + const TextureData* t_mask = buffer->GetTexture(); + p->SetMaskUV2Texture(t_mask); + // Glow. + p->setGlow(glow_amount, std::max(0.0f, glow_blur)); + break; + } + case ShadingType::kSimpleTextureModulatedTransparentDoubleSided: { + SetDoubleSided(true); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + SimpleProgramGL* p = simple_tex_mod_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulated: { + SetDoubleSided(false); + SetBlend(false); + float r, g, b; + buffer->GetFloats(&r, &g, &b); + SimpleProgramGL* p = simple_tex_mod_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulatedColorized: { + SetDoubleSided(false); + SetBlend(false); + float r, g, b, colorize_r, colorize_g, colorize_b; + buffer->GetFloats(&r, &g, &b, &colorize_r, &colorize_g, + &colorize_b); + SimpleProgramGL* p = simple_tex_mod_colorized_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorizeTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulatedColorized2: { + SetDoubleSided(false); + SetBlend(false); + float r, g, b, colorize_r, colorize_g, colorize_b, colorize2_r, + colorize2_g, colorize2_b; + buffer->GetFloats(&r, &g, &b, &colorize_r, &colorize_g, &colorize_b, + &colorize2_r, &colorize2_g, &colorize2_b); + SimpleProgramGL* p = simple_tex_mod_colorized2_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorize2Color(colorize2_r, colorize2_g, colorize2_b); + break; + } + case ShadingType::kSimpleTextureModulatedColorized2Masked: { + SetDoubleSided(false); + SetBlend(false); + float r, g, b, a, colorize_r, colorize_g, colorize_b, colorize2_r, + colorize2_g, colorize2_b; + buffer->GetFloats(&r, &g, &b, &a, &colorize_r, &colorize_g, + &colorize_b, &colorize2_r, &colorize2_g, + &colorize2_b); + SimpleProgramGL* p = simple_tex_mod_colorized2_masked_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorize2Color(colorize2_r, colorize2_g, colorize2_b); + p->SetColorizeTexture(buffer->GetTexture()); + p->SetMaskTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulatedTransparentColorized: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, colorize_r, colorize_g, colorize_b; + buffer->GetFloats(&r, &g, &b, &a, &colorize_r, &colorize_g, + &colorize_b); + SimpleProgramGL* p = simple_tex_mod_colorized_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorizeTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSimpleTextureModulatedTransparentColorized2: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, colorize_r, colorize_g, colorize_b, colorize2_r, + colorize2_g, colorize2_b; + buffer->GetFloats(&r, &g, &b, &a, &colorize_r, &colorize_g, + &colorize_b, &colorize2_r, &colorize2_g, + &colorize2_b); + SimpleProgramGL* p = simple_tex_mod_colorized2_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorize2Color(colorize2_r, colorize2_g, colorize2_b); + p->SetColorizeTexture(buffer->GetTexture()); + break; + } + case ShadingType:: + kSimpleTextureModulatedTransparentColorized2Masked: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, colorize_r, colorize_g, colorize_b, colorize2_r, + colorize2_g, colorize2_b; + buffer->GetFloats(&r, &g, &b, &a, &colorize_r, &colorize_g, + &colorize_b, &colorize2_r, &colorize2_g, + &colorize2_b); + SimpleProgramGL* p = simple_tex_mod_colorized2_masked_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorize2Color(colorize2_r, colorize2_g, colorize2_b); + p->SetColorizeTexture(buffer->GetTexture()); + p->SetMaskTexture(buffer->GetTexture()); + break; + } + case ShadingType::kObject: { + SetDoubleSided(false); + SetBlend(false); + float r, g, b; + buffer->GetFloats(&r, &g, &b); + ObjectProgramGL* p = obj_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetVignetteTexture(vignette_tex_); + break; + } + case ShadingType::kSmoke: { + SetDoubleSided(true); + SetBlend(true); + SetBlendPremult(true); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + SmokeProgramGL* p = smoke_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + break; + } + case ShadingType::kSmokeOverlay: { + SetDoubleSided(true); + SetBlend(true); + SetBlendPremult(true); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + SmokeProgramGL* p = smoke_overlay_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetDepthTexture( + static_cast(camera_render_target()) + ->framebuffer() + ->depth_texture()); + p->SetBlurTexture( + blur_buffers_[blur_buffers_.size() - 1]->texture()); + break; + } + case ShadingType::kPostProcessNormalDistort: { + float distort = buffer->GetFloat(); + PostProcessProgramGL* p = postprocess_distort_prog_; + StandardPostProcessSetup(p, pass); + p->SetDistort(distort); + break; + } + case ShadingType::kPostProcess: { + PostProcessProgramGL* p = postprocess_prog_; + StandardPostProcessSetup(p, pass); + break; + } + case ShadingType::kPostProcessEyes: { + assert(postprocess_eyes_prog_); + PostProcessProgramGL* p = postprocess_eyes_prog_; + StandardPostProcessSetup(p, pass); + break; + } + case ShadingType::kSprite: { + SetDoubleSided(false); + SetBlend(true); + SetBlendPremult(true); + + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + bool overlay = static_cast(buffer->GetInt()); + bool cam_aligned = static_cast(buffer->GetInt()); + + SpriteProgramGL* p; + if (cam_aligned) { + if (overlay) { + p = sprite_camalign_overlay_prog_; + } else { + p = sprite_camalign_prog_; + } + } else { + assert(!overlay); // Unsupported combo. + p = sprite_prog_; + } + p->Bind(); + if (overlay) { + p->SetDepthTexture( + static_cast(camera_render_target()) + ->framebuffer() + ->depth_texture()); + } + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + break; + } + case ShadingType::kObjectTransparent: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + + SetBlend(true); + SetBlendPremult(premult); + + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + ObjectProgramGL* p = obj_transparent_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetVignetteTexture(vignette_tex_); + break; + } + case ShadingType::kObjectLightShadow: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + int world_space = buffer->GetInt(); + float r, g, b; + buffer->GetFloats(&r, &g, &b); + ObjectProgramGL* p = world_space ? obj_lightshad_worldspace_prog_ + : obj_lightshad_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectLightShadowTransparent: { + SetDoubleSided(false); + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + auto light_shadow = static_cast(buffer->GetInt()); + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + ObjectProgramGL* p = obj_lightshad_transparent_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + + break; + } + case ShadingType::kObjectReflectLightShadow: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + int world_space = buffer->GetInt(); + float r, g, b, reflect_r, reflect_g, reflect_b; + buffer->GetFloats(&r, &g, &b, &reflect_r, &reflect_g, &reflect_b); + ObjectProgramGL* p = world_space + ? obj_refl_lightshad_worldspace_prog_ + : obj_refl_lightshad_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflectLightShadowDoubleSided: { + // FIXME: This shader isn't actually flipping the normal for the + // back side of the face.. for now we don't care though. + SetDoubleSided(true); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + int world_space = buffer->GetInt(); + + // Verified. + float r, g, b, reflect_r, reflect_g, reflect_b; + buffer->GetFloats(&r, &g, &b, &reflect_r, &reflect_g, &reflect_b); + ObjectProgramGL* p; + + // Testing why reflection is wonky.. + if (explicit_bool(false)) { + p = world_space ? obj_lightshad_worldspace_prog_ + : obj_lightshad_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + buffer->GetTexture(); + } else { + p = world_space ? obj_refl_lightshad_worldspace_prog_ + : obj_refl_lightshad_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + } + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflectLightShadowColorized: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + float r, g, b, reflect_r, reflect_g, reflect_b, colorize_r, + colorize_g, colorize_b; + buffer->GetFloats(&r, &g, &b, &reflect_r, &reflect_g, &reflect_b, + &colorize_r, &colorize_g, &colorize_b); + ObjectProgramGL* p = obj_refl_lightshad_colorize_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetColorizeTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflectLightShadowColorized2: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + + float r, g, b, reflect_r, reflect_g, reflect_b, colorize_r, + colorize_g, colorize_b, colorize2_r, colorize2_g, colorize2_b; + buffer->GetFloats(&r, &g, &b, &reflect_r, &reflect_g, &reflect_b, + &colorize_r, &colorize_g, &colorize_b, + &colorize2_r, &colorize2_g, &colorize2_b); + ObjectProgramGL* p = obj_refl_lightshad_colorize2_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + + p->SetColorizeTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorize2Color(colorize2_r, colorize2_g, colorize2_b); + + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflectLightShadowAdd: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + float r, g, b, add_r, add_g, add_b, reflect_r, reflect_g, reflect_b; + buffer->GetFloats(&r, &g, &b, &add_r, &add_g, &add_b, &reflect_r, + &reflect_g, &reflect_b); + ObjectProgramGL* p = obj_refl_lightshad_add_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetAddColor(add_r, add_g, add_b); + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflectLightShadowAddColorized: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + + float r, g, b, add_r, add_g, add_b, reflect_r, reflect_g, reflect_b, + colorize_r, colorize_g, colorize_b; + buffer->GetFloats(&r, &g, &b, &add_r, &add_g, &add_b, &reflect_r, + &reflect_g, &reflect_b, &colorize_r, &colorize_g, + &colorize_b); + ObjectProgramGL* p = obj_refl_lightshad_add_colorize_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetAddColor(add_r, add_g, add_b); + + p->SetColorizeTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflectLightShadowAddColorized2: { + SetDoubleSided(false); + SetBlend(false); + auto light_shadow = static_cast(buffer->GetInt()); + + float r, g, b, add_r, add_g, add_b, reflect_r, reflect_g, reflect_b, + colorize_r, colorize_g, colorize_b, colorize2_r, colorize2_g, + colorize2_b; + buffer->GetFloats(&r, &g, &b, &add_r, &add_g, &add_b, &reflect_r, + &reflect_g, &reflect_b, &colorize_r, &colorize_g, + &colorize_b, &colorize2_r, &colorize2_g, + &colorize2_b); + ObjectProgramGL* p = obj_refl_lightshad_add_colorize2_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetAddColor(add_r, add_g, add_b); + + p->SetColorizeTexture(buffer->GetTexture()); + p->SetColorizeColor(colorize_r, colorize_g, colorize_b); + p->SetColorize2Color(colorize2_r, colorize2_g, colorize2_b); + + p->SetReflectionTexture(buffer->GetTexture()); + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + + p->SetVignetteTexture(vignette_tex_); + GLuint light_shadow_tex; + switch (light_shadow) { + case LightShadowType::kTerrain: + light_shadow_tex = + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture(); + break; + case LightShadowType::kObject: + light_shadow_tex = + static_cast(light_render_target()) + ->framebuffer() + ->texture(); + break; + default: + throw Exception(); + } + p->SetLightShadowTexture(light_shadow_tex); + break; + } + case ShadingType::kObjectReflect: { + SetDoubleSided(false); + SetBlend(false); + int world_space = buffer->GetInt(); + // verified + float r, g, b, reflect_r, reflect_g, reflect_b; + buffer->GetFloats(&r, &g, &b, &reflect_r, &reflect_g, &reflect_b); + ObjectProgramGL* p = + world_space ? obj_refl_worldspace_prog_ : obj_refl_prog_; + p->Bind(); + p->SetColor(r, g, b); + p->SetColorTexture(buffer->GetTexture()); + p->SetReflectionTexture(buffer->GetTexture()); // reflection + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + break; + } + case ShadingType::kObjectReflectTransparent: { + SetDoubleSided(false); + + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, reflect_r, reflect_g, reflect_b; + buffer->GetFloats(&r, &g, &b, &a, &reflect_r, &reflect_g, + &reflect_b); + ObjectProgramGL* p = obj_refl_transparent_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetReflectionTexture(buffer->GetTexture()); // reflection + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + break; + } + case ShadingType::kObjectReflectAddTransparent: { + SetDoubleSided(false); + + bool premult = static_cast(buffer->GetInt()); + SetBlend(true); + SetBlendPremult(premult); + float r, g, b, a, add_r, add_g, add_b, reflect_r, reflect_g, + reflect_b; + buffer->GetFloats(&r, &g, &b, &a, &add_r, &add_g, &add_b, + &reflect_r, &reflect_g, &reflect_b); + ObjectProgramGL* p = obj_refl_add_transparent_prog_; + p->Bind(); + p->SetColor(r, g, b, a); + p->SetColorTexture(buffer->GetTexture()); + p->SetAddColor(add_r, add_g, add_b); + p->SetReflectionTexture(buffer->GetTexture()); // reflection + p->SetReflectionMult(reflect_r, reflect_g, reflect_b); + break; + } + case ShadingType::kShield: { + SetDoubleSided(true); + SetBlend(true); + SetBlendPremult(true); + ShieldProgramGL* p = shield_prog_; + p->Bind(); + p->SetDepthTexture( + static_cast(camera_render_target()) + ->framebuffer() + ->depth_texture()); + break; + } + case ShadingType::kSpecial: { + SetDoubleSided(false); + + // if we ever need to use non-blend version + // of this in real renders, we should split off a non-blend version + SetBlend(true); + SetBlendPremult(true); + auto source = (SpecialComponent::Source)buffer->GetInt(); + SimpleProgramGL* p = simple_tex_mod_prog_; + p->Bind(); + switch (source) { + case SpecialComponent::Source::kLightBuffer: + p->SetColorTexture( + static_cast(light_render_target()) + ->framebuffer() + ->texture()); + break; + case SpecialComponent::Source::kLightShadowBuffer: + p->SetColorTexture( + static_cast(light_shadow_render_target()) + ->framebuffer() + ->texture()); + break; + case SpecialComponent::Source::kVROverlayBuffer: { + p->SetColorTexture(static_cast( + vr_overlay_flat_render_target()) + ->framebuffer() + ->texture()); + p->SetColor(1, 1, 1, 0.95f); + break; + } + default: + throw Exception(); + break; + } + break; + } + default: + throw Exception(); + } + break; + } + case RenderCommandBuffer::Command::kSimpleComponentInlineColor: { + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + auto* p = static_cast(GetActiveProgram()); + assert(p != nullptr + && p == dynamic_cast(GetActiveProgram())); + p->SetColor(r, g, b, a); + break; + } + case RenderCommandBuffer::Command::kObjectComponentInlineColor: { + float r, g, b, a; + buffer->GetFloats(&r, &g, &b, &a); + auto* p = static_cast(GetActiveProgram()); + assert(p != nullptr + && p == dynamic_cast(GetActiveProgram())); + p->SetColor(r, g, b, a); + break; + } + case RenderCommandBuffer::Command::kObjectComponentInlineAddColor: { + float r, g, b; + buffer->GetFloats(&r, &g, &b); + auto* p = static_cast(GetActiveProgram()); + assert(p != nullptr + && p == dynamic_cast(GetActiveProgram())); + p->SetAddColor(r, g, b); + break; + } + case RenderCommandBuffer::Command::kDrawModel: { + int flags = buffer->GetInt(); + const ModelData* m = buffer->GetModel(); + assert(m); + auto model = static_cast_check_type(m->renderer_data()); + assert(model); + + // if they don't wanna draw in reflections... + if ((flags & kModelDrawFlagNoReflection) && drawing_reflection()) { + break; + } + GetActiveProgram()->PrepareToDraw(); + model->Bind(); + model->Draw(); + break; + } + case RenderCommandBuffer::Command::kDrawModelInstanced: { + int flags = buffer->GetInt(); + const ModelData* m = buffer->GetModel(); + assert(m); + auto model = static_cast_check_type(m->renderer_data()); + assert(model); + Matrix44f* mats; + int count; + mats = buffer->GetMatrices(&count); + // if they don't wanna draw in reflections... + if ((flags & kModelDrawFlagNoReflection) && drawing_reflection()) { + break; + } + model->Bind(); + for (int i = 0; i < count; i++) { + g_graphics_server->PushTransform(); + g_graphics_server->MultMatrix(mats[i]); + GetActiveProgram()->PrepareToDraw(); + model->Draw(); + g_graphics_server->PopTransform(); + } + break; + } + // NOLINTNEXTLINE(bugprone-branch-clone) + case RenderCommandBuffer::Command::kBeginDebugDrawTriangles: { + GetActiveProgram()->PrepareToDraw(); +#if ENABLE_DEBUG_DRAWING + glBegin(GL_TRIANGLES); +#endif + break; + } + case RenderCommandBuffer::Command::kBeginDebugDrawLines: { + GetActiveProgram()->PrepareToDraw(); +#if ENABLE_DEBUG_DRAWING + glBegin(GL_LINES); +#endif + break; + } + case RenderCommandBuffer::Command::kEndDebugDraw: { +#if ENABLE_DEBUG_DRAWING + glEnd(); +#endif // ENABLE_DEBUG_DRAWING + break; + } + case RenderCommandBuffer::Command::kDebugDrawVertex3: { + float x, y, z; + buffer->GetFloats(&x, &y, &z); +#if ENABLE_DEBUG_DRAWING + glVertex3f(x, y, z); +#endif // ENABLE_DEBUG_DRAWING + break; + } + case RenderCommandBuffer::Command::kDrawMesh: { + int flags = buffer->GetInt(); + auto* mesh = buffer->GetMeshRendererData(); + assert(mesh); + if ((flags & kModelDrawFlagNoReflection) && drawing_reflection()) { + break; + } + GetActiveProgram()->PrepareToDraw(); + mesh->Bind(); + mesh->Draw(DrawType::kTriangles); + break; + } + case RenderCommandBuffer::Command::kDrawScreenQuad: { + // Save proj/mv matrices, set up to draw a simple screen quad at the + // back of our depth range, draw, and restore + Matrix44f old_model_view_matrix = + g_graphics_server->model_view_matrix(); + Matrix44f old_projection_matrix = + g_graphics_server->projection_matrix(); + g_graphics_server->SetModelViewMatrix(kMatrix44fIdentity); + g_graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 0.01f); + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + g_graphics_server->SetModelViewMatrix(old_model_view_matrix); + g_graphics_server->SetProjectionMatrix(old_projection_matrix); + break; + } + case RenderCommandBuffer::Command::kScissorPush: { + Rect r; + buffer->GetFloats(&r.l, &r.b, &r.r, &r.t); + + // Convert scissor-values from model space to view space. + // this of course assumes there's no rotations and whatnot.. + Vector3f bot_left_pt = + g_graphics_server->model_view_matrix() * Vector3f(r.l, r.b, 0); + Vector3f top_right_pt = + g_graphics_server->model_view_matrix() * Vector3f(r.r, r.t, 0); + r.l = bot_left_pt.x; + r.b = bot_left_pt.y; + r.r = top_right_pt.x; + r.t = top_right_pt.y; + ScissorPush(r, render_target); + break; + } + case RenderCommandBuffer::Command::kScissorPop: { + ScissorPop(render_target); + break; + } + case RenderCommandBuffer::Command::kPushTransform: { + g_graphics_server->PushTransform(); + break; + } + case RenderCommandBuffer::Command::kTranslate2: { + float x, y; + buffer->GetFloats(&x, &y); + g_graphics_server->Translate(Vector3f(x, y, 0)); + break; + } + case RenderCommandBuffer::Command::kTranslate3: { + float x, y, z; + buffer->GetFloats(&x, &y, &z); + g_graphics_server->Translate(Vector3f(x, y, z)); + break; + } + case RenderCommandBuffer::Command::kCursorTranslate: { + float x, y; + g_platform->GetCursorPosition(&x, &y); + g_graphics_server->Translate(Vector3f(x, y, 0)); + break; + } + case RenderCommandBuffer::Command::kScale2: { + float x, y; + buffer->GetFloats(&x, &y); + g_graphics_server->scale(Vector3f(x, y, 1.0f)); + break; + } + case RenderCommandBuffer::Command::kScale3: { + float x, y, z; + buffer->GetFloats(&x, &y, &z); + g_graphics_server->scale(Vector3f(x, y, z)); + break; + } + case RenderCommandBuffer::Command::kScaleUniform: { + float s = buffer->GetFloat(); + g_graphics_server->scale(Vector3f(s, s, s)); + break; + } +#if BA_VR_BUILD + case RenderCommandBuffer::Command::kTransformToRightHand: { + VRTransformToRightHand(); + break; + } + case RenderCommandBuffer::Command::kTransformToLeftHand: { + VRTransformToLeftHand(); + break; + } + case RenderCommandBuffer::Command::kTransformToHead: { + VRTransformToHead(); + break; + } +#endif // BA_VR_BUILD + case RenderCommandBuffer::Command::kTranslateToProjectedPoint: { + float x, y, z; + buffer->GetFloats(&x, &y, &z); + Vector3f t = pass.frame_def()->beauty_pass()->tex_project_matrix() + * Vector3f(x, y, z); + g_graphics_server->Translate( + Vector3f(t.x * g_graphics_server->screen_virtual_width(), + t.y * g_graphics_server->screen_virtual_height(), 0)); + break; + } + case RenderCommandBuffer::Command::kRotate: { + float angle, x, y, z; + buffer->GetFloats(&angle, &x, &y, &z); + g_graphics_server->Rotate(angle, Vector3f(x, y, z)); + break; + } + case RenderCommandBuffer::Command::kMultMatrix: { + g_graphics_server->MultMatrix(*(buffer->GetMatrix())); + break; + } + case RenderCommandBuffer::Command::kPopTransform: { + g_graphics_server->PopTransform(); + break; + } + case RenderCommandBuffer::Command::kFlipCullFace: { + FlipCullFace(); + break; + } + default: + throw Exception("Invalid command in render-command-buffer"); + } + } + assert(buffer->IsEmpty()); +} // NOLINT (yes this is too long) + +void RendererGL::BlitBuffer(RenderTarget* src_in, RenderTarget* dst_in, + bool depth, bool linear_interpolation, + bool force_shader_mode, bool invalidate_source) { + DEBUG_CHECK_GL_ERROR; + auto* src = static_cast(src_in); + assert(src && src == dynamic_cast(src_in)); + auto* dst = static_cast(dst_in); +#if BA_DEBUG_BUILD + assert(dst && dst == dynamic_cast(dst_in)); +#endif + bool do_shader_blit{true}; + + // If they want depth we *MUST* use glBlitFramebuffer and can't have linear + // interp.. + if (depth) { + assert(g_blit_framebuffer_support && !force_shader_mode); + linear_interpolation = false; + } + // Use glBlitFramebuffer when its available. + // FIXME: This should be available in ES3. +#if !BA_OSTYPE_IOS_TVOS + if (g_blit_framebuffer_support && !force_shader_mode) { + do_shader_blit = false; + DEBUG_CHECK_GL_ERROR; + glBindFramebuffer(GL_READ_FRAMEBUFFER, src->GetFramebufferID()); + DEBUG_CHECK_GL_ERROR; + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, dst->GetFramebufferID()); + DEBUG_CHECK_GL_ERROR; + + glBlitFramebuffer(0, 0, static_cast(src->physical_width()), + static_cast(src->physical_height()), 0, 0, + static_cast(dst->physical_width()), + static_cast(dst->physical_height()), + depth ? (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + : GL_COLOR_BUFFER_BIT, + linear_interpolation ? GL_LINEAR : GL_NEAREST); + DEBUG_CHECK_GL_ERROR; + if (invalidate_source) { + InvalidateFramebuffer(true, depth, true); + } + } else { + do_shader_blit = true; + } +#endif + if (do_shader_blit) { + SetDepthWriting(false); + SetDepthTesting(false); + dst_in->DrawBegin(false); + g_graphics_server->ModelViewReset(); + g_graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 1); + + // Copied from ShadingType::kSimpleColor + SetDoubleSided(false); + SetBlend(false); + SimpleProgramGL* p = simple_tex_prog_; + p->Bind(); + p->SetColorTexture(src->framebuffer()->texture()); + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + DEBUG_CHECK_GL_ERROR; + } +} + +void RendererGL::ScissorPush(const Rect& r_in, RenderTarget* render_target) { + if (scissor_rects_.empty()) { + glEnable(GL_SCISSOR_TEST); + scissor_rects_.push_back(r_in); + } else { + Rect r; + Rect rp = scissor_rects_.back(); + r.l = r_in.l > rp.l ? r_in.l : rp.l; + r.r = r_in.r < rp.r ? r_in.r : rp.r; + r.b = r_in.b > rp.b ? r_in.b : rp.b; + r.t = r_in.t < rp.t ? r_in.t : rp.t; + scissor_rects_.push_back(r); + } + Rect clip = scissor_rects_.back(); + if (clip.l > clip.r) clip.l = clip.r; + if (clip.b > clip.t) clip.b = clip.t; + auto* glt = static_cast(render_target); + float scissor_scale_x = + static_cast(render_target)->GetScissorScaleX(); + float scissor_scale_y = + static_cast(render_target)->GetScissorScaleY(); + glScissor(static_cast(glt->GetScissorX(clip.l)), + static_cast(glt->GetScissorY(clip.b)), + static_cast(scissor_scale_x * (clip.r - clip.l)), + static_cast(scissor_scale_y * (clip.t - clip.b))); + DEBUG_CHECK_GL_ERROR; +} + +void RendererGL::ScissorPop(RenderTarget* render_target) { + BA_PRECONDITION(!scissor_rects_.empty()); + scissor_rects_.pop_back(); + if (scissor_rects_.empty()) { + glDisable(GL_SCISSOR_TEST); + } else { + Rect clip = scissor_rects_.back(); + if (clip.l > clip.r) clip.l = clip.r; + if (clip.b > clip.t) clip.b = clip.t; + auto* glt = static_cast(render_target); + float scissor_scale_x = + static_cast(render_target)->GetScissorScaleX(); + float scissor_scale_y = + static_cast(render_target)->GetScissorScaleY(); + glScissor(static_cast(glt->GetScissorX(clip.l)), + static_cast(glt->GetScissorY(clip.b)), + static_cast(scissor_scale_x * (clip.r - clip.l)), + static_cast(scissor_scale_y * (clip.t - clip.b))); + } + DEBUG_CHECK_GL_ERROR; +} + +// fixme filter our redundant sets.. +void RendererGL::SetDepthWriting(bool enable) { + if (enable != depth_writing_enabled_) { + depth_writing_enabled_ = enable; + glDepthMask(static_cast(enable)); + } +} + +void RendererGL::SetDrawAtEqualDepth(bool enable) { + if (enable != draw_at_equal_depth_) { + draw_at_equal_depth_ = enable; + if (enable) { + glDepthFunc(GL_LEQUAL); + } else { + glDepthFunc(GL_LESS); + } + } +} + +// FIXME FIXME FIXME FIXME +// turning off GL_DEPTH_TEST also disables +// depth writing which we may not want. +// It sounds like the proper thing +// to do in that case is leave GL_DEPTH_TEST on +// and set glDepthFunc(GL_ALWAYS) + +void RendererGL::SetDepthTesting(bool enable) { + if (enable != depth_testing_enabled_) { + depth_testing_enabled_ = enable; + if (enable) { + glEnable(GL_DEPTH_TEST); + } else { + glDisable(GL_DEPTH_TEST); + } + } +} + +void RendererGL::SetDepthRange(float min, float max) { + if (min != depth_range_min_ || max != depth_range_max_) { + depth_range_min_ = min; + depth_range_max_ = max; + glDepthRange(min, max); + } +} + +void RendererGL::FlipCullFace() { + draw_front_ = !draw_front_; + if (draw_front_) { + glCullFace(GL_BACK); + } else { + glCullFace(GL_FRONT); + } +} + +void RendererGL::SetBlend(bool b) { +#if !ENABLE_BLEND + b = false; +#endif + if (blend_ != b) { + blend_ = b; + if (blend_) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + } + } +} +void RendererGL::SetBlendPremult(bool b) { + if (blend_premult_ != b) { + blend_premult_ = b; + if (blend_premult_) { + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + // currently we only ever write to an alpha buffer for our vr overlay + // texture, and in that case we need alpha to accumulate; not get + // overwritten. could probably enable this everywhere but I don't know if + // it's supported on all hardware or is slower or whatnot.. + if (IsVRMode()) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + } + } +} + +void RendererGL::BindVertexArray(GLuint v) { + assert(g_vao_support); + if (v != current_vertex_array_) { + glBindVertexArray(v); + current_vertex_array_ = v; + } +} +void RendererGL::SetDoubleSided(bool d) { + if (double_sided_ != d) { + double_sided_ = d; + if (double_sided_) { + glDisable(GL_CULL_FACE); + } else { + glEnable(GL_CULL_FACE); + } + } +} + +void RendererGL::UpdateVignetteTex(bool force) { + if (force || vignette_quality_ != g_graphics_server->quality() + || vignette_tex_outer_r_ != vignette_outer().x + || vignette_tex_outer_g_ != vignette_outer().y + || vignette_tex_outer_b_ != vignette_outer().z + || vignette_tex_inner_r_ != vignette_inner().x + || vignette_tex_inner_g_ != vignette_inner().y + || vignette_tex_inner_b_ != vignette_inner().z) { + vignette_tex_outer_r_ = vignette_outer().x; + vignette_tex_outer_g_ = vignette_outer().y; + vignette_tex_outer_b_ = vignette_outer().z; + vignette_tex_inner_r_ = vignette_inner().x; + vignette_tex_inner_g_ = vignette_inner().y; + vignette_tex_inner_b_ = vignette_inner().z; + vignette_quality_ = g_graphics_server->quality(); + + const int width = 64; + const int height = 64; + const size_t tex_buffer_size = width * height * 4; + std::vector datavec(tex_buffer_size); + uint8_t* data{datavec.data()}; + float max_c = 0.5f * 0.5f * 0.5f * 0.5f; + uint8_t* b = data; + + float out_r = std::min( + 255.0f, std::max(0.0f, 255.0f * (1.0f - vignette_tex_outer_r_))); + float out_g = std::min( + 255.0f, std::max(0.0f, 255.0f * (1.0f - vignette_tex_outer_g_))); + float out_b = std::min( + 255.0f, std::max(0.0f, 255.0f * (1.0f - vignette_tex_outer_b_))); + float in_r = std::min( + 255.0f, std::max(0.0f, 255.0f * (1.0f - vignette_tex_inner_r_))); + float in_g = std::min( + 255.0f, std::max(0.0f, 255.0f * (1.0f - vignette_tex_inner_g_))); + float in_b = std::min( + 255.0f, std::max(0.0f, 255.0f * (1.0f - vignette_tex_inner_b_))); + + for (int y = 0; y < height; y++) { + float d3 = static_cast(y) / (height - 1); + float d4 = 1.0f - d3; + for (int x = 0; x < width; x++) { + float d1 = static_cast(x) / (width - 1); + float d2 = 1.0f - d1; + float c = 1.0f * (1.0f - ((d1 * d2 * d3 * d4) / max_c)); + c = 0.5f * (c * c) + 0.5f * c; + c = std::min(1.0f, std::max(0.0f, c)); + + b[0] = static_cast(c * out_r + (1.0f - c) * in_r); + b[1] = static_cast(c * out_g + (1.0f - c) * in_g); + b[2] = static_cast(c * out_b + (1.0f - c) * in_b); + b[3] = 255; // alpha + b += 4; + } + } + + glGetError(); // clear error + BindTexture(GL_TEXTURE_2D, vignette_tex_); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, + GL_UNSIGNED_BYTE, data); + + // If 32 bit failed for some reason, attempt 16. + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + static bool reported = false; + if (!reported) { + Log("Error: 32-bit vignette creation failed; falling back to 16."); + reported = true; + } + const int kVignetteTexWidth = 64; + const int kVignetteTexHeight = 32; + const int kVignetteTexBufferSize = kVignetteTexWidth * kVignetteTexHeight; + uint16_t data2[kVignetteTexBufferSize]; + float max_c2 = 0.5f * 0.5f * 0.5f * 0.5f; + uint16_t* b2 = data2; + + float out_r2 = std::min( + 32.0f, std::max(0.0f, 32.0f * (1.0f - vignette_tex_outer_r_))); + float out_g2 = std::min( + 64.0f, std::max(0.0f, 64.0f * (1.0f - vignette_tex_outer_g_))); + float out_b2 = std::min( + 32.0f, std::max(0.0f, 32.0f * (1.0f - vignette_tex_outer_b_))); + float in_r2 = std::min( + 32.0f, std::max(0.0f, 32.0f * (1.0f - vignette_tex_inner_r_))); + float in_g2 = std::min( + 64.0f, std::max(0.0f, 64.0f * (1.0f - vignette_tex_inner_g_))); + float in_b2 = std::min( + 32.0f, std::max(0.0f, 32.0f * (1.0f - vignette_tex_inner_b_))); + + // IMPORTANT - if we tweak anything here we need to tweak vertex + // shaders that calc this on the fly as well.. + for (int y = 0; y < height; y++) { + float d3 = static_cast(y) / (height - 1); + float d4 = 1.0f - d3; + for (int x = 0; x < width; x++) { + float d1 = static_cast(x) / (width - 1); + float d2 = 1.0f - d1; + float c = 1.0f * (1.0f - ((d1 * d2 * d3 * d4) / max_c2)); + c = 0.5f * (c * c) + 0.5f * c; + c = std::min(1.0f, std::max(0.0f, c)); + int red = + std::min(31, static_cast(c * out_r2 + (1.0f - c) * in_r2)); + int green = + std::min(63, static_cast(c * out_g2 + (1.0f - c) * in_g2)); + int blue = + std::min(31, static_cast(c * out_b2 + (1.0f - c) * in_b2)); + *b2 = static_cast(red << 11 | green << 5 | blue); + b2 += 1; + } + } + BindTexture(GL_TEXTURE_2D, vignette_tex_); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, + GL_UNSIGNED_SHORT_5_6_5, data2); + DEBUG_CHECK_GL_ERROR; + } + if (force) { + GL_LABEL_OBJECT(GL_TEXTURE, vignette_tex_, "vignetteTex"); + } + } +} + +auto RendererGL::GetFunkyDepthIssue() -> bool { + if (!funky_depth_issue_set_) { + BA_LOG_ONCE("fetching funky depth issue but not set"); + } + return funky_depth_issue_; +} + +auto RendererGL::GetDrawsShieldsFunny() -> bool { + if (!draws_shields_funny_set_) { + BA_LOG_ONCE("fetching draws-shields-funny value but not set"); + } + return draws_shields_funny_; +} + +void RendererGL::CheckCapabilities() { CheckGLExtensions(); } + +#if BA_OSTYPE_ANDROID +std::string RendererGL::GetAutoAndroidRes() { + assert(InMainThread()); + + const char* renderer = (const char*)glGetString(GL_RENDERER); + + // on the adreno 4xxx or 5xxx series we should be able to do anything... + if (strstr(renderer, "Adreno (TM) 4") || strstr(renderer, "Adreno (TM) 5")) { + // for phones lets go with 1080p (phones most likely have 1920x1080-ish + // aspect ratios) + if (GetInterfaceType() == UIScale::kSmall) { + return "1080p"; + } else { + // tablets are more likely to have 1920x1200 so lets inch a bit higher + return "1200p"; + } + } + + // on extra-speedy devices we should be able to do 1920x1200 + if (is_extra_speedy_android_device_) { + // for phones lets go with 1080p (phones most likely have 1920x1080-ish + // aspect ratios) + if (GetInterfaceType() == UIScale::kSmall) { + return "1080p"; + } else { + // tablets are more likely to have 1920x1200 so lets inch a bit higher + return "1200p"; + } + } + + // Amazon Fire tablet (as of jan '18) needs REAL low res to feel smooth.. + if (g_platform->GetDeviceName() == "Amazon KFAUWI") { + return "480p"; + } + + // fall back to the old 'Auto' values elsewhere + // - this is generally 720p (but varies in a few cases) + return "Auto"; +} +#endif // BA_OSTYPE_ANDROID + +auto RendererGL::GetAutoTextureQuality() -> TextureQuality { + assert(InMainThread()); + + TextureQuality qual{TextureQuality::kHigh}; + +#if BA_OSTYPE_ANDROID + { + // lets be cheaper in VR mode since we have to draw twice.. + if (IsVRMode()) { + qual = TextureQuality::kMedium; + } else { + // ouya is a special case since we have dds textures there; default to + // high +#if BA_OUYA_BUILD + qual = TextureQuality::kHigh; +#else // BA_OUYA_BUILD + // on android we default to high quality mode if we support ETC2; + // otherwise go with medium + if (g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC2) + || is_speedy_android_device_) { + qual = TextureQuality::kHigh; + } else { + qual = TextureQuality::kMedium; + } +#endif // BA_OUYA_BUILD + } + } +#elif BA_OSTYPE_IOS_TVOS + { + if (AppleUtils::IsSlowIOSDevice()) { + qual = TextureQuality::kMedium; + } else { + qual = TextureQuality::kHigh; + } + } +#else // BA_OSTYPE_ANDROID + { + // On other platforms (mac,pc,etc) just default to high. + qual = TextureQuality::kHigh; + } +#endif // BA_OSTYPE_ANDROID + + return qual; +} + +auto RendererGL::GetAutoGraphicsQuality() -> GraphicsQuality { + assert(InMainThread()); + GraphicsQuality q{GraphicsQuality::kMedium}; +#if BA_OSTYPE_ANDROID + // lets be cheaper in VR mode since we draw twice.. + if (IsVRMode()) { + q = GraphicsQuality::kMedium; + } else { + if (is_extra_speedy_android_device_) { + q = GraphicsQuality::kHigher; + } else if (g_running_es3 || is_speedy_android_device_) { + q = GraphicsQuality::kHigh; + } else { + q = GraphicsQuality::kMedium; + } + } +#elif BA_OSTYPE_IOS_TVOS + // on IOS we default to low-quality for slow devices (iphone-4, etc) + // medium for recent-ish ones (ipad2, iphone4s, etc), high for newer-ish + // (iPhone5, iPad4), and higher for anything beyond that + if (AppleUtils::IsSlowIOSDevice()) { + q = GraphicsQuality::kLow; + } else if (AppleUtils::IsMediumIOSDevice()) { + q = GraphicsQuality::kMedium; + } else if (AppleUtils::IsHighIOSDevice()) { + q = GraphicsQuality::kHigh; + } else { + q = GraphicsQuality::kHigher; + } +#else + // Elsewhere (desktops and such) we default to higher. + q = GraphicsQuality::kHigher; +#endif + return q; +} + +void RendererGL::RetainShader(ProgramGL* p) { shaders_.emplace_back(p); } + +void RendererGL::Load() { + assert(InGraphicsThread()); + assert(!data_loaded_); + assert(g_graphics_server->graphics_quality_set()); + if (!got_screen_framebuffer_) { + got_screen_framebuffer_ = true; + + // Grab the current framebuffer and consider that to be our 'screen' + // framebuffer. + // This can be 0 for the main framebuffer or something else. + glGetIntegerv(GL_FRAMEBUFFER_BINDING, + reinterpret_cast(&screen_framebuffer_)); + } + Renderer::Load(); + int high_qual_pp_flag = + g_graphics_server->quality() >= GraphicsQuality::kHigher + ? SHD_HIGHER_QUALITY + : 0; + screen_mesh_ = std::make_unique(this); + VertexSimpleFull v[] = {{{-1, -1, 0}, {0, 0}}, + {{1, -1, 0}, {65535, 0}}, + {{1, 1, 0}, {65535, 65535}}, + {{-1, 1, 0}, {0, 65535}}}; + const uint16_t indices[] = {0, 1, 2, 0, 2, 3}; + MeshBuffer buffer(4, v); + buffer.state = 1; // Necessary for this to set properly. + MeshIndexBuffer16 i_buffer(6, indices); + i_buffer.state = 1; // Necessary for this to set properly. + screen_mesh_->SetData(&buffer); + screen_mesh_->SetIndexData(&i_buffer); + assert(shaders_.empty()); + ProgramGL* p; + p = simple_color_prog_ = new SimpleProgramGL(this, SHD_MODULATE); + RetainShader(p); + p = simple_tex_prog_ = new SimpleProgramGL(this, SHD_TEXTURE); + RetainShader(p); + p = simple_tex_dtest_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_DEPTH_BUG_TEST); + RetainShader(p); + + // Have to run this after we've created the shader to be able to test it. + CheckFunkyDepthIssue(); + p = simple_tex_mod_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_MODULATE); + RetainShader(p); + p = simple_tex_mod_flatness_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_MODULATE | SHD_FLATNESS); + RetainShader(p); + p = simple_tex_mod_shadow_prog_ = new SimpleProgramGL( + this, SHD_TEXTURE | SHD_MODULATE | SHD_SHADOW | SHD_MASK_UV2); + RetainShader(p); + p = simple_tex_mod_shadow_flatness_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_MODULATE | SHD_SHADOW + | SHD_MASK_UV2 | SHD_FLATNESS); + RetainShader(p); + p = simple_tex_mod_glow_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_MODULATE | SHD_GLOW); + RetainShader(p); + p = simple_tex_mod_glow_maskuv2_prog_ = new SimpleProgramGL( + this, SHD_TEXTURE | SHD_MODULATE | SHD_GLOW | SHD_MASK_UV2); + RetainShader(p); + p = simple_tex_mod_colorized_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_MODULATE | SHD_COLORIZE); + RetainShader(p); + p = simple_tex_mod_colorized2_prog_ = new SimpleProgramGL( + this, SHD_TEXTURE | SHD_MODULATE | SHD_COLORIZE | SHD_COLORIZE2); + RetainShader(p); + p = simple_tex_mod_colorized2_masked_prog_ = + new SimpleProgramGL(this, SHD_TEXTURE | SHD_MODULATE | SHD_COLORIZE + | SHD_COLORIZE2 | SHD_MASKED); + RetainShader(p); + p = obj_prog_ = new ObjectProgramGL(this, 0); + RetainShader(p); + p = obj_transparent_prog_ = new ObjectProgramGL(this, SHD_OBJ_TRANSPARENT); + RetainShader(p); + p = obj_lightshad_transparent_prog_ = + new ObjectProgramGL(this, SHD_OBJ_TRANSPARENT | SHD_LIGHT_SHADOW); + RetainShader(p); + p = obj_refl_prog_ = new ObjectProgramGL(this, SHD_REFLECTION); + RetainShader(p); + p = obj_refl_worldspace_prog_ = + new ObjectProgramGL(this, SHD_REFLECTION | SHD_WORLD_SPACE_PTS); + RetainShader(p); + p = obj_refl_transparent_prog_ = + new ObjectProgramGL(this, SHD_REFLECTION | SHD_OBJ_TRANSPARENT); + RetainShader(p); + p = obj_refl_add_transparent_prog_ = + new ObjectProgramGL(this, SHD_REFLECTION | SHD_ADD | SHD_OBJ_TRANSPARENT); + RetainShader(p); + p = obj_lightshad_prog_ = new ObjectProgramGL(this, SHD_LIGHT_SHADOW); + RetainShader(p); + p = obj_lightshad_worldspace_prog_ = + new ObjectProgramGL(this, SHD_LIGHT_SHADOW | SHD_WORLD_SPACE_PTS); + RetainShader(p); + p = obj_refl_lightshad_prog_ = + new ObjectProgramGL(this, SHD_LIGHT_SHADOW | SHD_REFLECTION); + RetainShader(p); + p = obj_refl_lightshad_worldspace_prog_ = new ObjectProgramGL( + this, SHD_LIGHT_SHADOW | SHD_REFLECTION | SHD_WORLD_SPACE_PTS); + RetainShader(p); + p = obj_refl_lightshad_colorize_prog_ = new ObjectProgramGL( + this, SHD_LIGHT_SHADOW | SHD_REFLECTION | SHD_COLORIZE); + RetainShader(p); + p = obj_refl_lightshad_colorize2_prog_ = new ObjectProgramGL( + this, SHD_LIGHT_SHADOW | SHD_REFLECTION | SHD_COLORIZE | SHD_COLORIZE2); + RetainShader(p); + p = obj_refl_lightshad_add_prog_ = + new ObjectProgramGL(this, SHD_LIGHT_SHADOW | SHD_REFLECTION | SHD_ADD); + RetainShader(p); + p = obj_refl_lightshad_add_colorize_prog_ = new ObjectProgramGL( + this, SHD_LIGHT_SHADOW | SHD_REFLECTION | SHD_ADD | SHD_COLORIZE); + RetainShader(p); + p = obj_refl_lightshad_add_colorize2_prog_ = + new ObjectProgramGL(this, SHD_LIGHT_SHADOW | SHD_REFLECTION | SHD_ADD + | SHD_COLORIZE | SHD_COLORIZE2); + RetainShader(p); + p = smoke_prog_ = + new SmokeProgramGL(this, SHD_OBJ_TRANSPARENT | SHD_WORLD_SPACE_PTS); + RetainShader(p); + p = smoke_overlay_prog_ = new SmokeProgramGL( + this, SHD_OBJ_TRANSPARENT | SHD_WORLD_SPACE_PTS | SHD_OVERLAY); + RetainShader(p); + p = sprite_prog_ = new SpriteProgramGL(this, SHD_COLOR); + RetainShader(p); + p = sprite_camalign_prog_ = + new SpriteProgramGL(this, SHD_CAMERA_ALIGNED | SHD_COLOR); + RetainShader(p); + p = sprite_camalign_overlay_prog_ = + new SpriteProgramGL(this, SHD_CAMERA_ALIGNED | SHD_OVERLAY | SHD_COLOR); + RetainShader(p); + p = blur_prog_ = new BlurProgramGL(this, 0); + RetainShader(p); + p = shield_prog_ = new ShieldProgramGL(this, 0); + RetainShader(p); + + // Conditional seems to be a *very* slight win on some architectures (A7), a + // loss on some (A5) and a wash on some (Adreno 320). + // Gonna wait before a clean win before turning it on. + p = postprocess_prog_ = new PostProcessProgramGL(this, high_qual_pp_flag); + RetainShader(p); + if (g_graphics_server->quality() >= GraphicsQuality::kHigher) { + p = postprocess_eyes_prog_ = new PostProcessProgramGL(this, SHD_EYES); + RetainShader(p); + } else { + postprocess_eyes_prog_ = nullptr; + } + p = postprocess_distort_prog_ = + new PostProcessProgramGL(this, SHD_DISTORT | high_qual_pp_flag); + RetainShader(p); + + // Generate our random value texture. + { + glGenTextures(1, &random_tex_); + BindTexture(GL_TEXTURE_2D, random_tex_); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + const int tex_buffer_size = 128 * 128 * 3; + unsigned char data[tex_buffer_size]; + for (unsigned char& i : data) { + i = static_cast(rand()); // NOLINT + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 128, 128, 0, GL_RGB, + GL_UNSIGNED_BYTE, data); + GL_LABEL_OBJECT(GL_TEXTURE, random_tex_, "randomTex"); + } + + // Generate our vignette tex. + { + glGenTextures(1, &vignette_tex_); + BindTexture(GL_TEXTURE_2D, vignette_tex_); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + UpdateVignetteTex(true); + } + + // Let's pre-fill our recyclable mesh-datas list to reduce the need to make + // more which could cause hitches. + assert(recycle_mesh_datas_simple_split_.empty()); + for (int i = 0; i < 10; i++) { + recycle_mesh_datas_simple_split_.push_back(new MeshDataSimpleSplitGL(this)); + } + assert(recycle_mesh_datas_object_split_.empty()); + for (int i = 0; i < 10; i++) { + recycle_mesh_datas_object_split_.push_back(new MeshDataObjectSplitGL(this)); + } + assert(recycle_mesh_datas_simple_full_.empty()); + for (int i = 0; i < 10; i++) { + recycle_mesh_datas_simple_full_.push_back(new MeshDataSimpleFullGL(this)); + } + assert(recycle_mesh_datas_dual_texture_full_.empty()); + for (int i = 0; i < 10; i++) { + recycle_mesh_datas_dual_texture_full_.push_back( + new MeshDataDualTextureFullGL(this)); + } + assert(recycle_mesh_datas_smoke_full_.empty()); + for (int i = 0; i < 2; i++) { + recycle_mesh_datas_smoke_full_.push_back(new MeshDataSmokeFullGL(this)); + } + assert(recycle_mesh_datas_sprite_.empty()); + for (int i = 0; i < 2; i++) { + recycle_mesh_datas_sprite_.push_back(new MeshDataSpriteGL(this)); + } + + // Re-sync with the GL state since we might be dealing with a new context/etc. + SyncGLState(); + DEBUG_CHECK_GL_ERROR; + data_loaded_ = true; +} + +// in +void RendererGL::PostLoad() { + Renderer::PostLoad(); + // control may pass back to cardboard after we've finished loading + // but before we render, (in cases such as graphics settings switches) + // ...and it seems they can screw up our VAOs if we leave them bound... + // so lets be defensive. +#if BA_CARDBOARD_BUILD + SyncGLState(); +#endif +} + +void RendererGL::Unload() { + assert(InGraphicsThread()); + DEBUG_CHECK_GL_ERROR; + assert(data_loaded_); + Renderer::Unload(); + // clear out recycle-mesh-datas + for (auto&& i : recycle_mesh_datas_simple_split_) { + delete i; + } + recycle_mesh_datas_simple_split_.clear(); + for (auto&& i : recycle_mesh_datas_object_split_) { + delete i; + } + recycle_mesh_datas_object_split_.clear(); + for (auto&& i : recycle_mesh_datas_simple_full_) { + delete i; + } + recycle_mesh_datas_simple_full_.clear(); + for (auto&& i : recycle_mesh_datas_dual_texture_full_) { + delete i; + } + recycle_mesh_datas_dual_texture_full_.clear(); + for (auto&& i : recycle_mesh_datas_smoke_full_) { + delete i; + } + recycle_mesh_datas_smoke_full_.clear(); + for (auto&& i : recycle_mesh_datas_sprite_) { + delete i; + } + recycle_mesh_datas_sprite_.clear(); + screen_mesh_.reset(); + if (!g_graphics_server->renderer_context_lost()) { + glDeleteTextures(1, &random_tex_); + glDeleteTextures(1, &vignette_tex_); + } + blur_buffers_.clear(); + shaders_.clear(); + simple_color_prog_ = nullptr; + simple_tex_prog_ = nullptr; + simple_tex_dtest_prog_ = nullptr; + simple_tex_mod_prog_ = nullptr; + simple_tex_mod_flatness_prog_ = nullptr; + simple_tex_mod_shadow_prog_ = nullptr; + simple_tex_mod_shadow_flatness_prog_ = nullptr; + simple_tex_mod_glow_prog_ = nullptr; + simple_tex_mod_glow_maskuv2_prog_ = nullptr; + simple_tex_mod_colorized_prog_ = nullptr; + simple_tex_mod_colorized2_prog_ = nullptr; + simple_tex_mod_colorized2_masked_prog_ = nullptr; + obj_prog_ = nullptr; + obj_transparent_prog_ = nullptr; + obj_refl_prog_ = nullptr; + obj_refl_worldspace_prog_ = nullptr; + obj_refl_transparent_prog_ = nullptr; + obj_refl_add_transparent_prog_ = nullptr; + obj_lightshad_prog_ = nullptr; + obj_lightshad_worldspace_prog_ = nullptr; + obj_refl_lightshad_prog_ = nullptr; + obj_refl_lightshad_worldspace_prog_ = nullptr; + obj_refl_lightshad_colorize_prog_ = nullptr; + obj_refl_lightshad_colorize2_prog_ = nullptr; + obj_refl_lightshad_add_prog_ = nullptr; + obj_refl_lightshad_add_colorize_prog_ = nullptr; + obj_refl_lightshad_add_colorize2_prog_ = nullptr; + smoke_prog_ = nullptr; + smoke_overlay_prog_ = nullptr; + sprite_prog_ = nullptr; + sprite_camalign_prog_ = nullptr; + sprite_camalign_overlay_prog_ = nullptr; + obj_lightshad_transparent_prog_ = nullptr; + blur_prog_ = nullptr; + shield_prog_ = nullptr; + postprocess_prog_ = nullptr; + postprocess_eyes_prog_ = nullptr; + postprocess_distort_prog_ = nullptr; + data_loaded_ = false; + DEBUG_CHECK_GL_ERROR; +} + +auto RendererGL::NewModelData(const ModelData& model) -> ModelRendererData* { + return Object::NewDeferred(model, this); +} +auto RendererGL::NewTextureData(const TextureData& texture) + -> TextureRendererData* { + return Object::NewDeferred(texture, this); +} +auto RendererGL::NewScreenRenderTarget() -> RenderTarget* { + return Object::NewDeferred(this); +} +auto RendererGL::NewFramebufferRenderTarget(int width, int height, + bool linear_interp, bool depth, + bool texture, bool depth_texture, + bool high_quality, bool msaa, + bool alpha) -> RenderTarget* { + return Object::NewDeferred(this, width, height, linear_interp, + depth, texture, depth_texture, + high_quality, msaa, alpha); +} + +auto RendererGL::NewMeshData(MeshDataType mesh_type, MeshDrawType draw_type) + -> MeshRendererData* { + switch (mesh_type) { + case MeshDataType::kIndexedSimpleSplit: { + MeshDataSimpleSplitGL* data; + // use a recycled one if we've got one.. otherwise create a new one + auto i = recycle_mesh_datas_simple_split_.rbegin(); + if (i != recycle_mesh_datas_simple_split_.rend()) { + data = *i; + recycle_mesh_datas_simple_split_.pop_back(); + } else { + data = new MeshDataSimpleSplitGL(this); + } + return data; + break; + } + case MeshDataType::kIndexedObjectSplit: { + MeshDataObjectSplitGL* data; + // use a recycled one if we've got one.. otherwise create a new one + auto i = recycle_mesh_datas_object_split_.rbegin(); + if (i != recycle_mesh_datas_object_split_.rend()) { + data = *i; + recycle_mesh_datas_object_split_.pop_back(); + } else { + data = new MeshDataObjectSplitGL(this); + } + return data; + break; + } + case MeshDataType::kIndexedSimpleFull: { + MeshDataSimpleFullGL* data; + // use a recycled one if we've got one.. otherwise create a new one + auto i = recycle_mesh_datas_simple_full_.rbegin(); + if (i != recycle_mesh_datas_simple_full_.rend()) { + data = *i; + recycle_mesh_datas_simple_full_.pop_back(); + } else { + data = new MeshDataSimpleFullGL(this); + } + data->set_dynamic_draw(draw_type == MeshDrawType::kDynamic); + return data; + break; + } + case MeshDataType::kIndexedDualTextureFull: { + MeshDataDualTextureFullGL* data; + // use a recycled one if we've got one.. otherwise create a new one + auto i = recycle_mesh_datas_dual_texture_full_.rbegin(); + if (i != recycle_mesh_datas_dual_texture_full_.rend()) { + data = *i; + recycle_mesh_datas_dual_texture_full_.pop_back(); + } else { + data = new MeshDataDualTextureFullGL(this); + } + data->set_dynamic_draw(draw_type == MeshDrawType::kDynamic); + return data; + break; + } + case MeshDataType::kIndexedSmokeFull: { + MeshDataSmokeFullGL* data; + // use a recycled one if we've got one.. otherwise create a new one + auto i = recycle_mesh_datas_smoke_full_.rbegin(); + if (i != recycle_mesh_datas_smoke_full_.rend()) { + data = *i; + recycle_mesh_datas_smoke_full_.pop_back(); + } else { + data = new MeshDataSmokeFullGL(this); + } + data->set_dynamic_draw(draw_type == MeshDrawType::kDynamic); + return data; + break; + } + case MeshDataType::kSprite: { + MeshDataSpriteGL* data; + // use a recycled one if we've got one.. otherwise create a new one + auto i = recycle_mesh_datas_sprite_.rbegin(); + if (i != recycle_mesh_datas_sprite_.rend()) { + data = *i; + recycle_mesh_datas_sprite_.pop_back(); + } else { + data = new MeshDataSpriteGL(this); + } + data->set_dynamic_draw(draw_type == MeshDrawType::kDynamic); + return data; + break; + } + default: + throw Exception(); + break; + } +} +void RendererGL::DeleteMeshData(MeshRendererData* source_in, + MeshDataType mesh_type) { + // when we're done with mesh-data we keep it around for recycling... + // it seems that killing off VAO/VBOs can be hitchy (on mac at least) + // hmmm should we have some sort of threshold at which point we kill off + // some?.. + + switch (mesh_type) { + case MeshDataType::kIndexedSimpleSplit: { + auto source = static_cast(source_in); + assert(source + && source == dynamic_cast(source_in)); + source->Reset(); + recycle_mesh_datas_simple_split_.push_back(source); + break; + } + case MeshDataType::kIndexedObjectSplit: { + auto source = static_cast(source_in); + assert(source + && source == dynamic_cast(source_in)); + source->Reset(); + recycle_mesh_datas_object_split_.push_back(source); + break; + } + case MeshDataType::kIndexedSimpleFull: { + auto source = static_cast(source_in); + assert(source + && source == dynamic_cast(source_in)); + source->Reset(); + recycle_mesh_datas_simple_full_.push_back(source); + break; + } + case MeshDataType::kIndexedDualTextureFull: { + auto source = static_cast(source_in); + assert(source + && source == dynamic_cast(source_in)); + source->Reset(); + recycle_mesh_datas_dual_texture_full_.push_back(source); + break; + } + case MeshDataType::kIndexedSmokeFull: { + auto source = static_cast(source_in); + assert(source && source == dynamic_cast(source_in)); + source->Reset(); + recycle_mesh_datas_smoke_full_.push_back(source); + break; + } + case MeshDataType::kSprite: { + auto source = static_cast(source_in); + assert(source && source == dynamic_cast(source_in)); + source->Reset(); + recycle_mesh_datas_sprite_.push_back(source); + break; + } + default: + throw Exception(); + break; + } +} + +void RendererGL::CheckForErrors() { + // lets only check periodically.. i doubt it hurts to run this all the time + // but just in case... + error_check_counter_++; + if (error_check_counter_ > 120) { + error_check_counter_ = 0; + CHECK_GL_ERROR; + } +} + +void RendererGL::DrawDebug() { + if (explicit_bool(false)) { + // Draw our cam buffer if we have it. + if (has_camera_render_target()) { + SetDepthWriting(false); + SetDepthTesting(false); + SetDoubleSided(false); + SetBlend(false); + SimpleProgramGL* p = simple_tex_prog_; + p->Bind(); + + g_graphics_server->ModelViewReset(); + g_graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 1); + + float tx = -0.6f; + float ty = 0.6f; + + g_graphics_server->PushTransform(); + g_graphics_server->scale(Vector3f(0.4f, 0.4f, 0.4f)); + g_graphics_server->Translate(Vector3f(-1.3f, -0.7f, 0)); + + // Draw cam buffer. + g_graphics_server->PushTransform(); + g_graphics_server->Translate(Vector3f(tx, ty, 0)); + tx += 0.2f; + ty -= 0.25f; + g_graphics_server->scale(Vector3f(0.5f, 0.5f, 1.0f)); + p->SetColorTexture(static_cast(camera_render_target()) + ->framebuffer() + ->texture()); + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + g_graphics_server->PopTransform(); + + // Draw blur buffers. + if (explicit_bool(false)) { + for (auto&& i : blur_buffers_) { + g_graphics_server->PushTransform(); + g_graphics_server->Translate(Vector3f(tx, ty, 0)); + tx += 0.2f; + ty -= 0.25f; + g_graphics_server->scale(Vector3f(0.5f, 0.5f, 1.0f)); + p->SetColorTexture(i->texture()); + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + g_graphics_server->PopTransform(); + } + } + g_graphics_server->PopTransform(); + } + } +} + +void RendererGL::GenerateCameraBufferBlurPasses() { + // If our cam-buffer res has changed since last time, regenerate our blur + // buffers. + auto* cam_buffer = static_cast(camera_render_target()); + assert(cam_buffer != nullptr + && dynamic_cast(camera_render_target()) + == cam_buffer); + + if (cam_buffer->physical_width() != last_cam_buffer_width_ + || cam_buffer->physical_height() != last_cam_buffer_height_ + || blur_res_count() != last_blur_res_count_ || blur_buffers_.empty()) { + blur_buffers_.clear(); + last_cam_buffer_width_ = cam_buffer->physical_width(); + last_cam_buffer_height_ = cam_buffer->physical_height(); + last_blur_res_count_ = blur_res_count(); + int w = static_cast(last_cam_buffer_width_); + int h = static_cast(last_cam_buffer_height_); + + // In higher-quality we do multiple levels and 16-bit dithering is kinda + // noticeable and ugly then. + bool high_quality_fbos = + (g_graphics_server->quality() >= GraphicsQuality::kHigher); + for (int i = 0; i < blur_res_count(); i++) { + assert(w % 2 == 0); + assert(h % 2 == 0); + w /= 2; + h /= 2; + blur_buffers_.push_back(Object::New( + this, w, h, + true, // linear_interp + false, // depth + true, // tex + false, // depthTex + high_quality_fbos, // highQuality + false, // msaa + false // alpha + )); // NOLINT(whitespace/parens) + } + + // Final redundant one (we run an extra blur without down-rezing). + if (g_graphics_server->quality() >= GraphicsQuality::kHigher) + blur_buffers_.push_back(Object::New( + this, w, h, + true, // linear_interp + false, // depth + true, // tex + false, // depthTex + false, // highQuality + false, // msaa + false // alpha + )); // NOLINT(whitespace/parens) + } + + // Ok now go through and do the blurring. + SetDepthWriting(false); + SetDepthTesting(false); + g_graphics_server->ModelViewReset(); + g_graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 1); + SetDoubleSided(false); + SetBlend(false); + + BlurProgramGL* p = blur_prog_; + p->Bind(); + + FramebufferObjectGL* src_fb = + static_cast(camera_render_target())->framebuffer(); + for (auto&& i : blur_buffers_) { + FramebufferObjectGL* fb = i.get(); + assert(fb); + fb->Bind(); + SetViewport(0, 0, fb->width(), fb->height()); + InvalidateFramebuffer(true, false, false); + p->SetColorTexture(src_fb->texture()); + if (fb->width() == src_fb->width()) { // Our last one is equal res. + p->SetPixelSize(2.0f / static_cast(fb->width()), + 2.0f / static_cast(fb->height())); + } else { + p->SetPixelSize(1.0f / static_cast(fb->width()), + 1.0f / static_cast(fb->height())); + } + GetActiveProgram()->PrepareToDraw(); + screen_mesh_->Bind(); + screen_mesh_->Draw(DrawType::kTriangles); + src_fb = fb; + } +} + +void RendererGL::CardboardDisableScissor() { glDisable(GL_SCISSOR_TEST); } + +void RendererGL::CardboardEnableScissor() { glEnable(GL_SCISSOR_TEST); } + +void RendererGL::VREyeRenderBegin() { + assert(IsVRMode()); + + // On rift we need to turn off srgb conversion for each eye render + // so we can dump our linear data into oculus' srgb buffer as-is. + // (we really should add proper srgb support to the engine at some point) +#if BA_RIFT_BUILD + glDisable(GL_FRAMEBUFFER_SRGB); +#endif // BA_RIFT_BUILD + + GLuint fb; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, reinterpret_cast(&fb)); + screen_framebuffer_ = fb; +} + +#if BA_VR_BUILD +void RendererGL::VRSyncRenderStates() { + // GL state has been mucked with outside of our code; let's resync stuff.. + SyncGLState(); +} +#endif // BA_VR_BUILD + +void RendererGL::RenderFrameDefEnd() { + // Need to set some states to keep cardboard happy. +#if BA_CARDBOARD_BUILD + if (IsVRMode()) { + SyncGLState(); + glEnable(GL_SCISSOR_TEST); + } +#endif // BA_CARDBOARD_BUILD +} + +#pragma clang diagnostic pop + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL diff --git a/src/ballistica/graphics/gl/renderer_gl.h b/src/ballistica/graphics/gl/renderer_gl.h new file mode 100644 index 00000000..864cdce7 --- /dev/null +++ b/src/ballistica/graphics/gl/renderer_gl.h @@ -0,0 +1,263 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_GL_RENDERER_GL_H_ +#define BALLISTICA_GRAPHICS_GL_RENDERER_GL_H_ + +#include +#include +#include + +#include "ballistica/ballistica.h" + +#if BA_ENABLE_OPENGL + +#include "ballistica/core/object.h" +#include "ballistica/graphics/gl/gl_sys.h" +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +// for now lets not go above 8 since that's what the iPhone 3gs has.. +// ...haha perhaps should revisit this +constexpr int kMaxGLTexUnitsUsed = 5; + +class RendererGL : public Renderer { + class FakeVertexArrayObject; + class TextureDataGL; + class ModelDataGL; + class MeshDataGL; + class MeshDataSimpleSplitGL; + class MeshDataObjectSplitGL; + class MeshDataSimpleFullGL; + class MeshDataDualTextureFullGL; + class MeshDataSmokeFullGL; + class MeshDataSpriteGL; + class RenderTargetGL; + class FramebufferObjectGL; + class ShaderGL; + class FragmentShaderGL; + class VertexShaderGL; + class ProgramGL; + class SimpleProgramGL; + class ObjectProgramGL; + class SmokeProgramGL; + class BlurProgramGL; + class ShieldProgramGL; + class PostProcessProgramGL; + class SpriteProgramGL; + + public: + RendererGL(); + ~RendererGL() override; + void Unload() override; + void Load() override; + void PostLoad() override; + + // our vertex attrs + enum VertexAttr { + kVertexAttrPosition, + kVertexAttrUV, + kVertexAttrNormal, + kVertexAttrErode, + kVertexAttrColor, + kVertexAttrSize, + kVertexAttrDiffuse, + kVertexAttrUV2, + kVertexAttrCount + }; + + void CheckCapabilities() override; + auto GetAutoGraphicsQuality() -> GraphicsQuality override; + auto GetAutoTextureQuality() -> TextureQuality override; +#if BA_OSTYPE_ANDROID + std::string GetAutoAndroidRes() override; +#endif // BA_OSTYPE_ANDROID + + protected: + void DrawDebug() override; + void CheckForErrors() override; + void GenerateCameraBufferBlurPasses() override; + void FlipCullFace() override; + void SetDepthRange(float min, float max) override; + void SetDepthWriting(bool enable) override; + void SetDepthTesting(bool enable) override; + void SetDrawAtEqualDepth(bool enable) override; + auto NewScreenRenderTarget() -> RenderTarget* override; + auto NewFramebufferRenderTarget(int width, int height, bool linear_interp, + bool depth, bool texture, + bool depth_is_texture, bool high_quality, + bool msaa, bool alpha) + -> RenderTarget* override; + auto NewModelData(const ModelData& model) -> ModelRendererData* override; + auto NewTextureData(const TextureData& texture) + -> TextureRendererData* override; + auto NewMeshData(MeshDataType type, MeshDrawType drawType) + -> MeshRendererData* override; + void DeleteMeshData(MeshRendererData* data, MeshDataType type) override; + void ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, + const RenderPass& pass, + RenderTarget* render_target) override; + void BlitBuffer(RenderTarget* src, RenderTarget* dst, bool depth, + bool linear_interpolation, bool force_shader_mode, + bool invalidate_source) override; + void UpdateMeshes( + const std::vector >& meshes, + const std::vector& index_sizes, + const std::vector >& buffers) override; + void PushGroupMarker(const char* label) override; + void PopGroupMarker() override; + auto IsMSAAEnabled() const -> bool override; + void InvalidateFramebuffer(bool color, bool depth, + bool target_read_framebuffer) override; + void VREyeRenderBegin() override; + void CardboardDisableScissor() override; + void CardboardEnableScissor() override; + void RenderFrameDefEnd() override; + +#if BA_VR_BUILD + void VRSyncRenderStates() override; +#endif // BA_VR_BUILD + + // TEMP + auto current_vertex_array() const -> GLuint { return current_vertex_array_; } + + private: + void CheckFunkyDepthIssue(); + auto GetMSAASamplesForFramebuffer(int width, int height) -> int; + void UpdateMSAAEnabled() override; + void CheckGLExtensions(); + void UpdateVignetteTex(bool force) override; + void StandardPostProcessSetup(PostProcessProgramGL* p, + const RenderPass& pass); + void SyncGLState(); + void RetainShader(ProgramGL* p); + void SetViewport(GLint x, GLint y, GLsizei width, GLsizei height); + void UseProgram(ProgramGL* p); + auto GetActiveProgram() const -> ProgramGL* { + assert(current_program_); + return current_program_; + } + void SetDoubleSided(bool d); + void ScissorPush(const Rect& rIn, RenderTarget* render_target); + void ScissorPop(RenderTarget* render_target); + void BindVertexArray(GLuint v); + + // Note: This is only for use when VAOs aren't supported. + void SetVertexAttribArrayEnabled(GLuint i, bool enabled); + void BindTexture(GLuint type, const TextureData* t, GLuint tex_unit = 0); + void BindTexture(GLuint type, GLuint tex, GLuint tex_unit = 0); + void BindTextureUnit(uint32_t tex_unit); + void BindFramebuffer(GLuint fb); + void BindArrayBuffer(GLuint b); + void SetBlend(bool b); + void SetBlendPremult(bool b); + millisecs_t dof_update_time_{}; + std::vector > blur_buffers_; + bool supports_depth_textures_{}; + bool first_extension_check_{true}; + bool is_tegra_4_{}; + bool is_tegra_k1_{}; + bool is_recent_adreno_{}; + bool is_adreno_{}; + bool enable_msaa_{}; + float last_cam_buffer_width_{}; + float last_cam_buffer_height_{}; + int last_blur_res_count_{}; + float vignette_tex_outer_r_{}; + float vignette_tex_outer_g_{}; + float vignette_tex_outer_b_{}; + float vignette_tex_inner_r_{}; + float vignette_tex_inner_g_{}; + float vignette_tex_inner_b_{}; + float depth_range_min_{}; + float depth_range_max_{}; + bool draw_at_equal_depth_{}; + bool depth_writing_enabled_{}; + bool depth_testing_enabled_{}; + bool data_loaded_{}; + bool draw_front_{}; + GLuint screen_framebuffer_{}; + bool got_screen_framebuffer_{}; + GLuint random_tex_{}; + GLuint vignette_tex_{}; + GraphicsQuality vignette_quality_{}; + std::vector > shaders_; + GLint viewport_x_{}; + GLint viewport_y_{}; + GLint viewport_width_{}; + GLint viewport_height_{}; + SimpleProgramGL* simple_color_prog_{}; + SimpleProgramGL* simple_tex_prog_{}; + SimpleProgramGL* simple_tex_dtest_prog_{}; + SimpleProgramGL* simple_tex_mod_prog_{}; + SimpleProgramGL* simple_tex_mod_flatness_prog_{}; + SimpleProgramGL* simple_tex_mod_shadow_prog_{}; + SimpleProgramGL* simple_tex_mod_shadow_flatness_prog_{}; + SimpleProgramGL* simple_tex_mod_glow_prog_{}; + SimpleProgramGL* simple_tex_mod_glow_maskuv2_prog_{}; + SimpleProgramGL* simple_tex_mod_colorized_prog_{}; + SimpleProgramGL* simple_tex_mod_colorized2_prog_{}; + SimpleProgramGL* simple_tex_mod_colorized2_masked_prog_{}; + ObjectProgramGL* obj_prog_{}; + ObjectProgramGL* obj_transparent_prog_{}; + ObjectProgramGL* obj_lightshad_transparent_prog_{}; + ObjectProgramGL* obj_refl_prog_{}; + ObjectProgramGL* obj_refl_worldspace_prog_{}; + ObjectProgramGL* obj_refl_transparent_prog_{}; + ObjectProgramGL* obj_refl_add_transparent_prog_{}; + ObjectProgramGL* obj_lightshad_prog_{}; + ObjectProgramGL* obj_lightshad_worldspace_prog_{}; + ObjectProgramGL* obj_refl_lightshad_prog_{}; + ObjectProgramGL* obj_refl_lightshad_worldspace_prog_{}; + ObjectProgramGL* obj_refl_lightshad_colorize_prog_{}; + ObjectProgramGL* obj_refl_lightshad_colorize2_prog_{}; + ObjectProgramGL* obj_refl_lightshad_add_prog_{}; + ObjectProgramGL* obj_refl_lightshad_add_colorize_prog_{}; + ObjectProgramGL* obj_refl_lightshad_add_colorize2_prog_{}; + SmokeProgramGL* smoke_prog_{}; + SmokeProgramGL* smoke_overlay_prog_{}; + SpriteProgramGL* sprite_prog_{}; + SpriteProgramGL* sprite_camalign_prog_{}; + SpriteProgramGL* sprite_camalign_overlay_prog_{}; + BlurProgramGL* blur_prog_{}; + ShieldProgramGL* shield_prog_{}; + PostProcessProgramGL* postprocess_prog_{}; + PostProcessProgramGL* postprocess_eyes_prog_{}; + PostProcessProgramGL* postprocess_distort_prog_{}; + static auto GetFunkyDepthIssue() -> bool; + static auto GetDrawsShieldsFunny() -> bool; + static bool funky_depth_issue_set_; + static bool funky_depth_issue_; + static bool draws_shields_funny_set_; + static bool draws_shields_funny_; +#if BA_OSTYPE_ANDROID + static bool is_speedy_android_device_; + static bool is_extra_speedy_android_device_; +#endif // BA_OSTYPE_ANDROID + ProgramGL* current_program_{}; + bool double_sided_{}; + std::vector scissor_rects_; + GLuint current_vertex_array_{}; + bool vertex_attrib_arrays_enabled_[kVertexAttrCount]{}; + int active_tex_unit_{}; + int active_framebuffer_{}; + int active_array_buffer_{}; + int bound_textures_2d_[kMaxGLTexUnitsUsed]{}; + int bound_textures_cube_map_[kMaxGLTexUnitsUsed]{}; + bool blend_{}; + bool blend_premult_{}; + std::unique_ptr screen_mesh_; + std::vector recycle_mesh_datas_simple_split_; + std::vector recycle_mesh_datas_object_split_; + std::vector recycle_mesh_datas_simple_full_; + std::vector recycle_mesh_datas_dual_texture_full_; + std::vector recycle_mesh_datas_smoke_full_; + std::vector recycle_mesh_datas_sprite_; + int error_check_counter_{}; +}; + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL + +#endif // BALLISTICA_GRAPHICS_GL_RENDERER_GL_H_ diff --git a/src/ballistica/graphics/graphics.cc b/src/ballistica/graphics/graphics.cc new file mode 100644 index 00000000..8e9a077d --- /dev/null +++ b/src/ballistica/graphics/graphics.cc @@ -0,0 +1,1868 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/graphics.h" + +#include +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/game/connection/connection_to_client.h" +#include "ballistica/game/connection/connection_to_host.h" +#include "ballistica/game/session/session.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/empty_component.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/post_process_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/component/special_component.h" +#include "ballistica/graphics/component/sprite_component.h" +#include "ballistica/graphics/gl/renderer_gl.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/net_graph.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/input/input.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/scene/scene.h" +#include "ballistica/ui/console.h" +#include "ballistica/ui/root_ui.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/root_widget.h" + +namespace ballistica { + +const float kScreenMessageZDepth = -0.06f; +const float kScreenMeshZDepth = -0.05f; +const float kProgressBarZDepth = 0.0f; +const int kProgressBarFadeTime = 500; +const float kDebugImgZDepth = -0.04f; +const float kCursorZDepth = -0.1f; + +auto Graphics::IsShaderTransparent(ShadingType c) -> bool { + switch (c) { + case ShadingType::kSimpleColorTransparent: + case ShadingType::kSimpleColorTransparentDoubleSided: + case ShadingType::kObjectTransparent: + case ShadingType::kObjectLightShadowTransparent: + case ShadingType::kObjectReflectTransparent: + case ShadingType::kObjectReflectAddTransparent: + case ShadingType::kSimpleTextureModulatedTransparent: + case ShadingType::kSimpleTextureModulatedTransFlatness: + case ShadingType::kSimpleTextureModulatedTransparentDoubleSided: + case ShadingType::kSimpleTextureModulatedTransparentColorized: + case ShadingType::kSimpleTextureModulatedTransparentColorized2: + case ShadingType::kSimpleTextureModulatedTransparentColorized2Masked: + case ShadingType::kSimpleTextureModulatedTransparentShadow: + case ShadingType::kSimpleTexModulatedTransShadowFlatness: + case ShadingType::kSimpleTextureModulatedTransparentGlow: + case ShadingType::kSimpleTextureModulatedTransparentGlowMaskUV2: + case ShadingType::kSpecial: + case ShadingType::kShield: + case ShadingType::kSmoke: + case ShadingType::kSmokeOverlay: + case ShadingType::kSprite: + return true; + case ShadingType::kSimpleColor: + case ShadingType::kSimpleTextureModulated: + case ShadingType::kSimpleTextureModulatedColorized: + case ShadingType::kSimpleTextureModulatedColorized2: + case ShadingType::kSimpleTextureModulatedColorized2Masked: + case ShadingType::kSimpleTexture: + case ShadingType::kObject: + case ShadingType::kObjectReflect: + case ShadingType::kObjectLightShadow: + case ShadingType::kObjectReflectLightShadow: + case ShadingType::kObjectReflectLightShadowDoubleSided: + case ShadingType::kObjectReflectLightShadowColorized: + case ShadingType::kObjectReflectLightShadowColorized2: + case ShadingType::kObjectReflectLightShadowAdd: + case ShadingType::kObjectReflectLightShadowAddColorized: + case ShadingType::kObjectReflectLightShadowAddColorized2: + case ShadingType::kPostProcess: + case ShadingType::kPostProcessEyes: + case ShadingType::kPostProcessNormalDistort: + return false; + default: + throw Exception(); // in case we forget to add new ones here... + } +} + +Graphics::Graphics() = default; +Graphics::~Graphics() = default; + +void Graphics::SetGyroEnabled(bool enable) { + // If we're turning back on, suppress gyro updates for a bit. + if (enable && !gyro_enabled_) { + last_suppress_gyro_time_ = GetRealTime(); + } + gyro_enabled_ = enable; +} + +void Graphics::UpdateProgressBarProgress(float target) { + millisecs_t real_time = GetRealTime(); + float p = target; + if (p < 0) { + p = 0; + } + if (real_time - last_progress_bar_draw_time_ > 400) { + last_progress_bar_draw_time_ = real_time - 400; + } + while (last_progress_bar_draw_time_ < real_time) { + last_progress_bar_draw_time_++; + progress_bar_progress_ += (p - progress_bar_progress_) * 0.02f; + } +} + +void Graphics::DrawProgressBar(RenderPass* pass, float opacity) { + millisecs_t real_time = GetRealTime(); + float amount = progress_bar_progress_; + if (amount < 0) amount = 0; + + SimpleComponent c(pass); + c.SetTransparent(true); + float o = opacity; + float delay = 0; + + // Fade in for the first 2 seconds if desired. + if (progress_bar_fade_in_) { + millisecs_t since_start = real_time - last_progress_bar_start_time_; + if (since_start < delay) { + o = 0.0f; + } else if (since_start < 2000 + delay) { + o *= (since_start - delay) / 2000.0f; + } + } + + // Fade out at the end. + if (amount > 0.75f) { + o *= (1.0f - amount) * 4.0f; + } + + float b = pass->virtual_height() / 2.0f - 20.0f; + float t = pass->virtual_height() / 2.0f + 20.0f; + float l = 100.0f; + float r = pass->virtual_width() - 100.0f; + float p = 1.0f - amount; + if (p < 0) { + p = 0; + } else if (p > 1.0f) { + p = 1.0f; + } + p = l + (1.0f - p) * (r - l); + + progress_bar_bottom_mesh_->SetPositionAndSize(l, b, kProgressBarZDepth, + (r - l), (t - b)); + progress_bar_top_mesh_->SetPositionAndSize(l, b, kProgressBarZDepth, (p - l), + (t - b)); + + c.SetColor(0.0f, 0.07f, 0.0f, 1 * o); + c.DrawMesh(progress_bar_bottom_mesh_.get()); + c.Submit(); + + c.SetColor(0.23f, 0.17f, 0.35f, 1 * o); + c.DrawMesh(progress_bar_top_mesh_.get()); + c.Submit(); +} + +void Graphics::SetShadowRange(float lower_bottom, float lower_top, + float upper_bottom, float upper_top) { + assert(lower_top >= lower_bottom && upper_bottom >= lower_top + && upper_top >= upper_bottom); + shadow_lower_bottom_ = lower_bottom; + shadow_lower_top_ = lower_top; + shadow_upper_bottom_ = upper_bottom; + shadow_upper_top_ = upper_top; +} + +auto Graphics::GetShadowDensity(float x, float y, float z) -> float { + if (y < shadow_lower_bottom_) { // NOLINT(bugprone-branch-clone) + return 0.0f; + } else if (y < shadow_lower_top_) { + float amt = + (y - shadow_lower_bottom_) / (shadow_lower_top_ - shadow_lower_bottom_); + return amt; + } else if (y < shadow_upper_bottom_) { + return 1.0f; + } else if (y < shadow_upper_top_) { + float amt = + (y - shadow_upper_bottom_) / (shadow_upper_top_ - shadow_upper_bottom_); + return 1.0f - amt; + } else { + return 0.0f; + } +} + +class Graphics::ScreenMessageEntry { + public: + ScreenMessageEntry(std::string s_in, bool align_left_in, uint32_t c, + const Vector3f& color_in, Texture* texture_in, + Texture* tint_texture_in, const Vector3f& tint_in, + const Vector3f& tint2_in) + : align_left(align_left_in), + creation_time(c), + s_raw(std::move(s_in)), + color(color_in), + texture(texture_in), + tint_texture(tint_texture_in), + tint(tint_in), + tint2(tint2_in), + v_smoothed(0.0f), + translation_dirty(true), + mesh_dirty(true) {} + auto GetText() -> TextGroup&; + void UpdateTranslation(); + bool align_left; + uint32_t creation_time; + Vector3f color; + Vector3f tint; + Vector3f tint2; + std::string s_raw; + std::string s_translated; + Object::Ref texture; + Object::Ref tint_texture; + float v_smoothed; + bool translation_dirty; + bool mesh_dirty; + + private: + Object::Ref s_mesh_; +}; + +// Draw controls and things that lie on top of the action. +void Graphics::DrawMiscOverlays(RenderPass* pass) { + // Every now and then, update our stats. + while (GetRealTime() >= next_stat_update_time_) { + if (GetRealTime() - next_stat_update_time_ > 1000) { + next_stat_update_time_ = GetRealTime() + 1000; + } else { + next_stat_update_time_ += 1000; + } + int total_frames_rendered = + g_graphics_server->renderer()->total_frames_rendered(); + last_fps_ = total_frames_rendered - last_total_frames_rendered_; + last_total_frames_rendered_ = total_frames_rendered; + } + float v{}; + + if (show_fps_) { + char fps_str[32]; + snprintf(fps_str, sizeof(fps_str), "%d", last_fps_); + if (fps_str != fps_string_) { + fps_string_ = fps_str; + if (!fps_text_group_.exists()) { + fps_text_group_ = Object::New(); + } + fps_text_group_->SetText(fps_string_); + } + SimpleComponent c(pass); + c.SetTransparent(true); + if (IsVRMode()) { + c.SetColor(1, 1, 1, 1); + } else { + c.SetColor(0.8f, 0.8f, 0.8f, 1.0f); + } + int text_elem_count = fps_text_group_->GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c.SetTexture(fps_text_group_->GetElementTexture(e)); + if (IsVRMode()) { + c.SetShadow(-0.003f * fps_text_group_->GetElementUScale(e), + -0.003f * fps_text_group_->GetElementVScale(e), 0.0f, 1.0f); + c.SetMaskUV2Texture(fps_text_group_->GetElementMaskUV2Texture(e)); + } + c.SetFlatness(1.0f); + c.DrawMesh(fps_text_group_->GetElementMesh(e)); + } + c.Submit(); + } + + if (show_net_info_) { + char net_info_str[128]; + int64_t in_count = 0; + int64_t in_size = 0; + int64_t in_size_compressed = 0; + int64_t outCount = 0; + int64_t out_size = 0; + int64_t out_size_compressed = 0; + int64_t resends = 0; + int64_t resends_size = 0; + bool do_ping = false; + float ping{}; + bool show = false; + + // Add in/out data for any host connection. + if (ConnectionToHost* connection_to_host = g_game->connection_to_host()) { + if (connection_to_host->can_communicate()) show = true; + in_size += connection_to_host->GetBytesInPerSecond(); + in_size_compressed += connection_to_host->GetBytesInPerSecondCompressed(); + in_count += connection_to_host->GetMessagesInPerSecond(); + out_size += connection_to_host->GetBytesOutPerSecond(); + out_size_compressed += + connection_to_host->GetBytesOutPerSecondCompressed(); + outCount += connection_to_host->GetMessagesOutPerSecond(); + resends += connection_to_host->GetMessageResendsPerSecond(); + resends_size += connection_to_host->GetBytesResentPerSecond(); + ping = connection_to_host->average_ping(); + } else { + int connected_count = 0; + for (auto&& i : g_game->connections_to_clients()) { + ConnectionToClient* client = i.second.get(); + if (client->can_communicate()) { + show = true; + connected_count += 1; + } + in_size += client->GetBytesInPerSecond(); + in_size_compressed += client->GetBytesInPerSecondCompressed(); + in_count += client->GetMessagesInPerSecond(); + out_size += client->GetBytesOutPerSecond(); + out_size_compressed += client->GetBytesOutPerSecondCompressed(); + outCount += client->GetMessagesOutPerSecond(); + resends += client->GetMessageResendsPerSecond(); + resends_size += client->GetBytesResentPerSecond(); + ping += client->average_ping(); + } + + // We want an average for ping. + if (connected_count > 0) { + ping /= static_cast(connected_count); + } + } + + if (show) { + if (do_ping) { + snprintf(net_info_str, sizeof(net_info_str), + "ping: %f\nin: %d/%d/%d\nout: %d/%d/%d\nrpt: " + "%d/%d", + ping, static_cast_check_fit(in_size), + static_cast_check_fit(in_size_compressed), + static_cast_check_fit(in_count), + static_cast_check_fit(out_size), + static_cast_check_fit(out_size_compressed), + static_cast_check_fit(outCount), + static_cast_check_fit(resends_size), + static_cast_check_fit(resends)); + } else { + snprintf(net_info_str, sizeof(net_info_str), + "in: %d/%d/%d\nout: %d/%d/%d\nrpt: %d/%d", + static_cast_check_fit(in_size), + static_cast_check_fit(in_size_compressed), + static_cast_check_fit(in_count), + static_cast_check_fit(out_size), + static_cast_check_fit(out_size_compressed), + static_cast_check_fit(outCount), + static_cast_check_fit(resends_size), + static_cast_check_fit(resends)); + } + net_info_str[sizeof(net_info_str) - 1] = 0; // in case we overran.. + if (net_info_str != net_info_string_) { + net_info_string_ = net_info_str; + if (!net_info_text_group_.exists()) { + net_info_text_group_ = Object::New(); + } + net_info_text_group_->SetText(net_info_string_); + } + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(0.8f, 0.8f, 0.8f, 1.0f); + int text_elem_count = net_info_text_group_->GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c.SetTexture(net_info_text_group_->GetElementTexture(e)); + c.SetFlatness(1.0f); + c.PushTransform(); + c.Translate(4.0f, + (show_fps_ ? 66.0f : 40.0f) + (do_ping ? 17.0f : 0.0f), + kScreenMessageZDepth); + c.Scale(0.7f, 0.7f); + c.DrawMesh(net_info_text_group_->GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + + // Draw debug graphs. + if (explicit_bool(false)) { + if (!debug_graph_1_.exists()) { + debug_graph_1_ = Object::New(); + } + debug_graph_1_->Draw(pass, GetRealTime(), 50.0f, 50.0f, 500.0f, 100.0f); + if (!debug_graph_2_.exists()) { + debug_graph_2_ = Object::New(); + } + debug_graph_2_->Draw(pass, GetRealTime(), 50.0f, 160.0f, 500.0f, 100.0f); + } + + // Screen messages (bottom). + { + // Delete old ones. + if (!screen_messages_.empty()) { + millisecs_t cutoff; + if (GetRealTime() > 5000) { + cutoff = GetRealTime() - 5000; + for (auto i = screen_messages_.begin(); i != screen_messages_.end();) { + if (i->creation_time < cutoff) { + auto next = i; + next++; + screen_messages_.erase(i); + i = next; + } else { + i++; + } + } + } + } + + // Delete if we have too many. + while ((screen_messages_.size()) > 4) { + screen_messages_.erase(screen_messages_.begin()); + } + + // Draw all existing. + if (!screen_messages_.empty()) { + bool vr = IsVRMode(); + + // These are less disruptive in the middle for menus but at the bottom + // during gameplay. + float start_v = g_graphics->screen_virtual_height() * 0.05f; + float scale; + switch (GetInterfaceType()) { + case UIScale::kSmall: + scale = 1.5f; + break; + case UIScale::kMedium: + scale = 1.2f; + break; + default: + scale = 1.0f; + break; + } + + // Shadows. + { + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetTexture(g_media->GetTexture(SystemTextureID::kSoftRectVertical)); + + float screen_width = g_graphics->screen_virtual_width(); + + v = start_v; + + millisecs_t youngest_age = 9999; + + for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend(); + i++) { + // Update the translation if need be. + i->UpdateTranslation(); + + millisecs_t age = GetRealTime() - i->creation_time; + youngest_age = std::min(youngest_age, age); + float s_extra = 1.0f; + if (age < 100) { + s_extra = std::min(1.2f, 1.2f * (age / 100.0f)); + } else if (age < 150) { + s_extra = 1.2f - 0.2f * ((150.0f - age) / 50.0f); + } + + float a; + if (age > 3000) { + a = 1.0f - static_cast(age - 3000) / 2000; + } else { + a = 1; + } + a *= 0.8f; + + if (vr) { + a *= 0.8f; + } + + assert(!i->translation_dirty); + float str_height = + g_text_graphics->GetStringHeight(i->s_translated.c_str()); + float str_width = + g_text_graphics->GetStringWidth(i->s_translated.c_str()); + + if ((str_width * scale) > (screen_width - 40)) { + s_extra *= ((screen_width - 40) / (str_width * scale)); + } + + float r = i->color.x; + float g = i->color.y; + float b = i->color.z; + GetSafeColor(&r, &g, &b); + + float v_extra = scale * (youngest_age * 0.01f); + + float fade; + if (age < 100) { + fade = 1.0f; + } else { + fade = std::max(0.0f, (200.0f - age) / 100.0f); + } + c.SetColor(r * fade, g * fade, b * fade, a); + + c.PushTransform(); + if (i->v_smoothed == 0.0f) { + i->v_smoothed = v + v_extra; + } else { + float smoothing = 0.8f; + i->v_smoothed = + smoothing * i->v_smoothed + (1.0f - smoothing) * (v + v_extra); + } + c.Translate(screen_width * 0.5f, i->v_smoothed, + vr ? 60 : kScreenMessageZDepth); + if (vr) { + // Let's drop down a bit in vr mode. + c.Translate(0, -10.0f, 0); + c.Scale((str_width + 60) * scale * s_extra, + (str_height + 20) * scale * s_extra); + + // Align our bottom with where we just scaled from. + c.Translate(0, 0.5f, 0); + } else { + c.Scale((str_width + 110) * scale * s_extra, + (str_height + 40) * scale * s_extra); + + // Align our bottom with where we just scaled from. + c.Translate(0, 0.5f, 0); + } + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + + v += scale * (36 + str_height); + if (v > g_graphics->screen_virtual_height() + 30) { + break; + } + } + c.Submit(); + } + + // Now the strings themselves. + { + SimpleComponent c(pass); + c.SetTransparent(true); + + float screen_width = g_graphics->screen_virtual_width(); + v = start_v; + millisecs_t youngest_age = 9999; + + for (auto i = screen_messages_.rbegin(); i != screen_messages_.rend(); + i++) { + millisecs_t age = GetRealTime() - i->creation_time; + youngest_age = std::min(youngest_age, age); + float s_extra = 1.0f; + if (age < 100) { + s_extra = std::min(1.2f, 1.2f * (age / 100.0f)); + } else if (age < 150) { + s_extra = 1.2f - 0.2f * ((150.0f - age) / 50.0f); + } + float a; + if (age > 3000) { + a = 1.0f - static_cast(age - 3000) / 2000; + } else { + a = 1; + } + assert(!i->translation_dirty); + float str_height = + g_text_graphics->GetStringHeight(i->s_translated.c_str()); + float str_width = + g_text_graphics->GetStringWidth(i->s_translated.c_str()); + + if ((str_width * scale) > (screen_width - 40)) { + s_extra *= ((screen_width - 40) / (str_width * scale)); + } + float r = i->color.x; + float g = i->color.y; + float b = i->color.z; + GetSafeColor(&r, &g, &b, 0.85f); + + int elem_count = i->GetText().GetElementCount(); + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureData* t = i->GetText().GetElementTexture(e); + if (!t->preloaded()) continue; + c.SetTexture(t); + if (i->GetText().GetElementCanColor(e)) { + c.SetColor(r, g, b, a); + } else { + c.SetColor(1, 1, 1, a); + } + c.SetFlatness(i->GetText().GetElementMaxFlatness(e)); + c.PushTransform(); + c.Translate(screen_width * 0.5f, i->v_smoothed, + vr ? 150 : kScreenMessageZDepth); + c.Scale(scale * s_extra, scale * s_extra); + c.Translate(0, 20); + c.DrawMesh(i->GetText().GetElementMesh(e)); + c.PopTransform(); + } + + v += scale * (36 + str_height); + if (v > g_graphics->screen_virtual_height() + 30) break; + } + c.Submit(); + } + } + } + + // Screen messages (top). + { + // Delete old ones. + if (!screen_messages_top_.empty()) { + millisecs_t cutoff; + if (GetRealTime() > 5000) { + cutoff = GetRealTime() - 5000; + for (auto i = screen_messages_top_.begin(); + i != screen_messages_top_.end();) { + if (i->creation_time < cutoff) { + auto next = i; + next++; + screen_messages_top_.erase(i); + i = next; + } else { + i++; + } + } + } + } + + // Delete if we have too many. + while ((screen_messages_top_.size()) > 6) { + screen_messages_top_.erase(screen_messages_top_.begin()); + } + + if (!screen_messages_top_.empty()) { + SimpleComponent c(pass); + c.SetTransparent(true); + + // Draw all existing. + float h = pass->virtual_width() - 300.0f; + v = g_graphics->screen_virtual_height() - 50.0f; + + float v_base = g_graphics->screen_virtual_height(); + float last_v = -999.0f; + + float min_spacing = 25.0f; + + for (auto i = screen_messages_top_.rbegin(); + i != screen_messages_top_.rend(); i++) { + // Update the translation if need be. + i->UpdateTranslation(); + + millisecs_t age = GetRealTime() - i->creation_time; + float s_extra = 1.0f; + if (age < 100) { + s_extra = std::min(1.1f, 1.1f * (age / 100.0f)); + } else if (age < 150) { + s_extra = 1.1f - 0.1f * ((150.0f - age) / 50.0f); + } + + float a; + if (age > 3000) { + a = 1.0f - static_cast(age - 3000) / 2000; + } else { + a = 1; + } + + i->v_smoothed += 0.1f; + if (i->v_smoothed - last_v < min_spacing) { + i->v_smoothed += + 8.0f * (1.0f - ((i->v_smoothed - last_v) / min_spacing)); + } + last_v = i->v_smoothed; + + // Draw the image if they provided one. + if (i->texture.exists()) { + c.Submit(); + + SimpleComponent c2(pass); + c2.SetTransparent(true); + c2.SetTexture(i->texture); + if (i->tint_texture.exists()) { + c2.SetColorizeTexture(i->tint_texture); + c2.SetColorizeColor(i->tint.x, i->tint.y, i->tint.z); + c2.SetColorizeColor2(i->tint2.x, i->tint2.y, i->tint2.z); + c2.SetMaskTexture( + g_media->GetTexture(SystemTextureID::kCharacterIconMask)); + } + c2.SetColor(1, 1, 1, a); + c2.PushTransform(); + c2.Translate(h - 14, v_base + 10 + i->v_smoothed, + kScreenMessageZDepth); + c2.Scale(22.0f * s_extra, 22.0f * s_extra); + c2.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c2.PopTransform(); + c2.Submit(); + } + + float r = i->color.x; + float g = i->color.y; + float b = i->color.z; + GetSafeColor(&r, &g, &b); + + int elem_count = i->GetText().GetElementCount(); + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureData* t = i->GetText().GetElementTexture(e); + if (!t->preloaded()) continue; + c.SetTexture(t); + if (i->GetText().GetElementCanColor(e)) { + c.SetColor(r, g, b, a); + } else { + c.SetColor(1, 1, 1, a); + } + c.SetShadow(-0.003f * i->GetText().GetElementUScale(e), + -0.003f * i->GetText().GetElementVScale(e), 0.0f, + 1.0f * a); + c.SetFlatness(i->GetText().GetElementMaxFlatness(e)); + c.SetMaskUV2Texture(i->GetText().GetElementMaskUV2Texture(e)); + c.PushTransform(); + c.Translate(h, v_base + 2 + i->v_smoothed, kScreenMessageZDepth); + c.Scale(0.6f * s_extra, 0.6f * s_extra); + c.DrawMesh(i->GetText().GetElementMesh(e)); + c.PopTransform(); + } + assert(!i->translation_dirty); + v -= g_text_graphics->GetStringHeight(i->s_translated.c_str()) * 0.6f + + 8.0f; + } + c.Submit(); + } + } +} + +void Graphics::GetSafeColor(float* red, float* green, float* blue, + float target_intensity) { + assert(red && green && blue); + + // Mult our color up to try and hit the target intensity. + float intensity = 0.2989f * (*red) + 0.5870f * (*green) + 0.1140f * (*blue); + if (intensity < target_intensity) { + float s = target_intensity / std::max(0.001f, intensity); + *red = std::min(1.0f, (*red) * s); + *green = std::min(1.0f, (*green) * s); + *blue = std::min(1.0f, (*blue) * s); + } + + // We may still be short of our target intensity due to clamping (ie: (10,0,0) + // will not look any brighter than (1,0,0)) if that's the case, just convert + // the difference to a grey value and add that to all channels... this *still* + // might not get us there so lets do it a few times if need be. (i'm sure + // there's a less bone-headed way to do this) + for (int i = 0; i < 4; i++) { + float remaining = + (0.2989f * (*red) + 0.5870f * (*green) + 0.1140f * (*blue)) - 1.0f; + if (remaining > 0.0f) { + *red = std::min(1.0f, (*red) + 0.2989f * remaining); + *green = std::min(1.0f, (*green) + 0.5870f * remaining); + *blue = std::min(1.0f, (*blue) + 0.1140f * remaining); + } else { + break; + } + } +} + +void Graphics::AddScreenMessage(const std::string& msg, const Vector3f& color, + bool top, Texture* texture, + Texture* tint_texture, const Vector3f& tint, + const Vector3f& tint2) { + // So we know we're always dealing with valid utf8. + std::string m = Utils::GetValidUTF8(msg.c_str(), "ga9msg"); + + assert(InGameThread()); + if (top) { + float start_v = -40.0f; + if (!screen_messages_top_.empty()) { + start_v = std::min( + start_v, + std::max(-100.0f, screen_messages_top_.back().v_smoothed - 25.0f)); + } + screen_messages_top_.emplace_back(m, true, GetRealTime(), color, texture, + tint_texture, tint, tint2); + screen_messages_top_.back().v_smoothed = start_v; + } else { + screen_messages_.emplace_back(m, false, GetRealTime(), color, texture, + tint_texture, tint, tint2); + } +} + +void Graphics::Reset() { + fade_ = 0; + fade_start_ = 0; + + if (!camera_.exists()) { + camera_ = Object::New(); + } + + // Wipe out top screen messages since they might be using textures that are + // being reset. Bottom ones are ok since they have no textures. + screen_messages_top_.clear(); +} + +void Graphics::InitInternalComponents(FrameDef* frame_def) { + RenderPass* pass = frame_def->GetOverlayFlatPass(); + + screen_mesh_ = Object::New(); + + // Let's draw a bit bigger than screen to account for tv-border-mode. + float w = pass->virtual_width(); + float h = pass->virtual_height(); + if (IsVRMode()) { + screen_mesh_->SetPositionAndSize( + -(0.5f * kVRBorder) * w, (-0.5f * kVRBorder) * h, kScreenMeshZDepth, + (1.0f + kVRBorder) * w, (1.0f + kVRBorder) * h); + } else { + screen_mesh_->SetPositionAndSize( + -(0.5f * kTVBorder) * w, (-0.5f * kTVBorder) * h, kScreenMeshZDepth, + (1.0f + kTVBorder) * w, (1.0f + kTVBorder) * h); + } + progress_bar_top_mesh_ = Object::New(); + progress_bar_bottom_mesh_ = Object::New(); + load_dot_mesh_ = Object::New(); + load_dot_mesh_->SetPositionAndSize(0, 0, 0, 2, 2); +} + +auto Graphics::GetEmptyFrameDef() -> FrameDef* { + assert(InGameThread()); + FrameDef* frame_def; + + // Grab a ready-to-use recycled one if available. + if (!recycle_frame_defs_.empty()) { + frame_def = recycle_frame_defs_.back(); + recycle_frame_defs_.pop_back(); + } else { + frame_def = new FrameDef(); + } + frame_def->Reset(); + return frame_def; +} + +void Graphics::ClearFrameDefDeleteList() { + assert(InGameThread()); + std::lock_guard lock(frame_def_delete_list_mutex_); + + for (auto& i : frame_def_delete_list_) { + // We recycle our frame_defs so we don't have to reallocate all those + // buffers. + if (recycle_frame_defs_.size() < 5) { + recycle_frame_defs_.push_back(i); + } else { + delete i; + } + } + frame_def_delete_list_.clear(); +} + +void Graphics::FadeScreen(bool to, millisecs_t time, PyObject* endcall) { + // 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("WARNING: 2 fades overlapping; running first fade-end-call early"); + } + g_game->PushPythonCall(fade_end_call_); + fade_end_call_.Clear(); + } + set_fade_start_on_next_draw_ = true; + fade_time_ = time; + fade_out_ = !to; + if (endcall) { + fade_end_call_ = Object::New(endcall); + } + fade_ = 1.0f; +} + +void Graphics::DrawLoadDot(RenderPass* pass) { + // Draw a little bugger in the corner if we're loading something. + SimpleComponent c(pass); + c.SetTransparent(true); + + // Draw red if we've got graphics stuff loading. Green if only other stuff + // left. + if (g_media->GetGraphicalPendingLoadCount() > 0) { + c.SetColor(0.2f, 0, 0, 1); + } else { + c.SetColor(0, 0.2f, 0, 1); + } + c.DrawMesh(load_dot_mesh_.get()); + c.Submit(); +} + +void Graphics::UpdateGyro(millisecs_t real_time, millisecs_t elapsed) { + Vector3f tilt = gyro_vals_; + + // Our gyro vals get set from another thread and we don't use a lock, + // so perhaps there's a chance we get corrupted float values here?.. + // Let's watch out for crazy vals just in case. + for (float& i : tilt.v) { + // Check for NaN and Inf: + if (!std::isfinite(i)) { + i = 0.0f; + } + + // Clamp crazy big values: + i = std::min(100.0f, std::max(-100.0f, i)); + } + + // Our math was calibrated for 60hz (16ms per frame); + // adjust for other framerates... + float timescale = static_cast(elapsed) / 16.0f; + + // If we've recently been told to suppress the gyro, zero these. + // (prevents hitches when being restored, etc) + if (!gyro_enabled_ || camera_gyro_explicitly_disabled_ + || (real_time - last_suppress_gyro_time_ < 1000)) { + tilt = Vector3f{0.0, 0.0, 0.0}; + } + + float tilt_smoothing = 0.0f; + tilt_smoothed_ = + tilt_smoothing * tilt_smoothed_ + (1.0f - tilt_smoothing) * tilt; + + tilt_vel_ = tilt_smoothed_ * 3.0f; + tilt_pos_ += tilt_vel_ * timescale; + + // Technically this will behave slightly differently at different time scales, + // but it should be close to correct.. + // tilt_pos_ *= 0.991f; + tilt_pos_ *= std::max(0.0, 1.0f - 0.01 * timescale); + + // Some gyros seem wonky and either give us crazy big values or consistently + // offset ones. Let's keep a running tally of magnitude that slowly drops over + // time, and if it reaches a certain value lets just kill gyro input. + if (gyro_broken_) { + tilt_pos_ *= 0.0f; + } else { + gyro_mag_test_ += tilt_vel_.Length() * 0.01f * timescale; + gyro_mag_test_ = std::max(0.0f, gyro_mag_test_ - 0.02f * timescale); + if (gyro_mag_test_ > 100.0f) { + ScreenMessage("Wonky gyro; disabling tilt.", {1, 0, 0}); + gyro_broken_ = true; + } + } +} + +void Graphics::ApplyCamera(FrameDef* frame_def) { + camera_->Update(frame_def->base_time_elapsed()); + camera_->UpdatePosition(); + camera_->ApplyToFrameDef(frame_def); +} + +void Graphics::DrawWorld(Session* session, FrameDef* frame_def) { + // Draw all session contents (nodes, etc.) + overlay_node_z_depth_ = -0.95f; + if (session) { + session->Draw(frame_def); + frame_def->set_benchmark_type(session->benchmark_type()); + } + if (!HeadlessMode()) { + g_bg_dynamics->Draw(frame_def); + } + + // Lastly draw any blotches that have been building up. + DrawBlotches(frame_def); + + // Add a few explicit things to a few passes. + DrawBoxingGlovesTest(frame_def); +} + +void Graphics::BuildAndPushFrameDef() { + assert(InGameThread()); + assert(camera_.exists()); + + // We should not be building/pushing any frames until after + // app-launch-commands have been run.. + BA_PRECONDITION_FATAL(g_game->ran_app_launch_commands()); + + // This should no longer be necessary.. + WaitForRendererToExist(); + + Session* session = g_game->GetForegroundSession(); + bool session_fills_screen = session ? session->DoesFillScreen() : false; + millisecs_t real_time = GetRealTime(); + + // Store how much time this frame_def represents. + millisecs_t net_time = g_game->master_time(); + millisecs_t elapsed = + std::min(millisecs_t{50}, net_time - last_create_frame_def_time_); + last_create_frame_def_time_ = net_time; + + UpdateGyro(real_time, elapsed); + + FrameDef* frame_def = GetEmptyFrameDef(); + frame_def->set_real_time(real_time); + frame_def->set_base_time(g_game->master_time()); + frame_def->set_base_time_elapsed(elapsed); + frame_def->set_frame_number(frame_def_count_++); + + if (!internal_components_inited_) { + InitInternalComponents(frame_def); + internal_components_inited_ = true; + } + + ApplyCamera(frame_def); + + // Clear to black for either progress bar or when we've got no meaningful + // session to draw. + frame_def->set_needs_clear(progress_bar_ || !session_fills_screen); + + if (progress_bar_) { + UpdateAndDrawProgressBar(frame_def, real_time); + } else { + // Ok, we're drawing a real frame. + + DrawWorld(session, frame_def); + + // Now some overlay stuff. + RenderPass* overlay_pass = frame_def->overlay_pass(); + + DrawUI(frame_def); + + // Let input draw anything it needs to. (touch input graphics, etc) + g_input->Draw(frame_def); + + DrawMiscOverlays(overlay_pass); + + // Draw console. + if (!HeadlessMode() && g_app_globals->console) { + g_app_globals->console->Draw(overlay_pass); + } + + DrawCursor(overlay_pass, real_time); + + // 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). + if (frame_def->quality() >= GraphicsQuality::kHigh) { + PostProcessComponent c(frame_def->blit_pass()); + c.DrawScreenQuad(); + c.Submit(); + } + + DrawFades(frame_def, real_time); + + // 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 (IsVRMode()) { + if (frame_def->GetOverlayFlatPass()->HasDrawCommands()) { + if (!g_ui->IsWindowPresent()) { + BA_LOG_ONCE( + "Drawing in overlay pass in VR mode without UI; shouldn't " + "happen!"); + } + } + } + + if (g_media->GetPendingLoadCount() > 0) { + DrawLoadDot(overlay_pass); + } + + // Lastly, if we had anything waiting to run until the progress bar was + // gone, run it. + g_python->RunCleanFrameCommands(); + } + + 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. + frame_def->set_mesh_data_creates(mesh_data_creates_); + mesh_data_creates_.clear(); + frame_def->set_mesh_data_destroys(mesh_data_destroys_); + mesh_data_destroys_.clear(); + + g_graphics_server->SetFrameDef(frame_def); + + // Clean up frame_defs awaiting deletion. + ClearFrameDefDeleteList(); + + // Clear our blotches out regardless of whether we rendered them. + blotch_indices_.clear(); + blotch_verts_.clear(); + blotch_soft_indices_.clear(); + blotch_soft_verts_.clear(); + blotch_soft_obj_indices_.clear(); + blotch_soft_obj_verts_.clear(); +} + +auto Graphics::DrawUI(FrameDef* frame_def) -> void { g_ui->Draw(frame_def); } + +void Graphics::DrawBoxingGlovesTest(FrameDef* frame_def) { + // Test: boxing glove. + if (explicit_bool(false)) { + float a = 0; + + // Blit. + if (explicit_bool(true)) { + PostProcessComponent c(frame_def->blit_pass()); + c.setNormalDistort(0.07f); + c.PushTransform(); + c.Translate(0, 7, -3.3f); + c.Scale(10, 10, 10); + c.Rotate(a, 0, 0, 1); + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + c.Submit(); + } + + // Beauty. + if (explicit_bool(false)) { + ObjectComponent c(frame_def->beauty_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBoxingGlove)); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.4f, 0.4f, 0.4f); + c.PushTransform(); + c.Translate(0.0f, 3.7f, -3.3f); + c.Scale(10.0f, 10.0f, 10.0f); + c.Rotate(a, 0.0f, 0.0f, 1.0f); + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + c.Submit(); + } + + // Light. + if (explicit_bool(true)) { + SimpleComponent c(frame_def->light_shadow_pass()); + c.SetColor(0.16f, 0.11f, 0.1f, 1.0f); + c.SetTransparent(true); + c.PushTransform(); + c.Translate(0.0f, 3.7f, -3.3f); + c.Scale(10.0f, 10.0f, 10.0f); + c.Rotate(a, 0.0f, 0.0f, 1.0f); + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + c.Submit(); + } + } +} + +void Graphics::DrawDebugBuffers(RenderPass* pass) { + if (explicit_bool(false)) { + { + SpecialComponent c(pass, SpecialComponent::Source::kLightBuffer); + float csize = 100; + c.PushTransform(); + c.Translate(70, 400, kDebugImgZDepth); + c.Scale(csize, csize); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + } + { + SpecialComponent c(pass, SpecialComponent::Source::kLightShadowBuffer); + float csize = 100; + c.PushTransform(); + c.Translate(70, 250, kDebugImgZDepth); + c.Scale(csize, csize); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + } + } +} + +void Graphics::UpdateAndDrawProgressBar(FrameDef* frame_def, + millisecs_t real_time) { + RenderPass* pass = frame_def->overlay_pass(); + UpdateProgressBarProgress( + 1.0f + - static_cast(g_media->GetGraphicalPendingLoadCount()) + / static_cast(progress_bar_loads_)); + DrawProgressBar(pass, 1.0f); + + // If we were drawing a progress bar, see if everything is now loaded.. if + // so, start rendering normally next frame. + int count = g_media->GetGraphicalPendingLoadCount(); + if (count <= 0) { + progress_bar_ = false; + progress_bar_end_time_ = real_time; + } + if (g_media->GetPendingLoadCount() > 0) { + DrawLoadDot(pass); + } +} + +void Graphics::DrawFades(FrameDef* frame_def, millisecs_t real_time) { + RenderPass* overlay_pass = frame_def->overlay_pass(); + + // Guard against accidental fades that never fade back in. + if (fade_ <= 0.0f && fade_out_) { + millisecs_t faded_time = real_time - (fade_start_ + fade_time_); + if (faded_time > 15000) { + Log("FORCE-ENDING STUCK FADE"); + fade_out_ = false; + fade_ = 1.0f; + fade_time_ = 1000; + fade_start_ = real_time; + } + } + + // Update fade values. + if (fade_ > 0) { + if (set_fade_start_on_next_draw_) { + set_fade_start_on_next_draw_ = false; + fade_start_ = real_time; + } + bool was_done = fade_ <= 0; + if (real_time <= fade_start_) { + fade_ = 1; + } else if ((real_time - fade_start_) < fade_time_) { + fade_ = 1.0f + - (static_cast(real_time - fade_start_) + / static_cast(fade_time_)); + if (fade_ <= 0) fade_ = 0.00001f; + } else { + fade_ = 0; + if (!was_done && fade_end_call_.exists()) { + g_game->PushPythonCall(fade_end_call_); + fade_end_call_.Clear(); + } + } + } + + // Draw a fade if we're either in a fade or fading back in from a + // progress-bar screen. + if (fade_ > 0.00001f || fade_out_ + || (real_time - progress_bar_end_time_ < kProgressBarFadeTime)) { + float a = fade_out_ ? 1 - fade_ : fade_; + if (real_time - progress_bar_end_time_ < kProgressBarFadeTime) { + a = 1.0f * a + + (1.0f + - static_cast(real_time - progress_bar_end_time_) + / static_cast(kProgressBarFadeTime)) + * (1.0f - a); + } + if (IsVRMode()) { +#if BA_VR_BUILD + SimpleComponent c(frame_def->vr_cover_pass()); + c.SetTransparent(false); + Vector3f cam_pt = {0.0f, 0.0f, 0.0f}; + Vector3f cam_target_pt = {0.0f, 0.0f, 0.0f}; + cam_pt = + Vector3f(frame_def->cam_original().x, frame_def->cam_original().y, + frame_def->cam_original().z); + // in vr follow-mode the cam point gets tweaked.. (fixme should probably + // just do this on the camera end) + if (frame_def->camera_mode() == CameraMode::kOrbit) { + // fudge this one up a bit; looks better that way.. + cam_target_pt = Vector3f(frame_def->cam_target_original().x, + frame_def->cam_target_original().y + 6.0f, + frame_def->cam_target_original().z); + } else { + cam_target_pt = Vector3f(frame_def->cam_target_original().x, + frame_def->cam_target_original().y, + frame_def->cam_target_original().z); + } + Vector3f diff = cam_target_pt - cam_pt; + diff.Normalize(); + Vector3f side = Vector3f::Cross(diff, Vector3f(0.0f, 1.0f, 0.0f)); + Vector3f up = Vector3f::Cross(diff, side); + c.SetColor(0, 0, 0); + c.PushTransform(); + // we start in vr-overlay screen space; get back to world.. + c.Translate(cam_pt.x, cam_pt.y, cam_pt.z); + c.MultMatrix(Matrix44fOrient(diff, up).m); + // at the very end we stay turned around so we get 100% black + if (a < 0.98f) { + c.Translate(0, 0, 40.0f * a); + c.Rotate(180, 1, 0, 0); + } + float inv_a = 1.0f - a; + float s = 100.0f * inv_a + 5.0f * a; + c.Scale(s, s, s); + c.DrawModel(g_media->GetModel(SystemModelID::kVRFade)); + c.PopTransform(); + c.Submit(); +#else // BA_VR_BUILD + throw Exception(); +#endif // BA_VR_BUILD + } else { + SimpleComponent c(overlay_pass); + c.SetTransparent(a < 1.0f); + c.SetColor(0, 0, 0, a); + c.DrawMesh(screen_mesh_.get()); + c.Submit(); + } + + // If we're doing a progress-bar fade, throw in the fading progress bar. + if (real_time - progress_bar_end_time_ < kProgressBarFadeTime / 2) { + float o = (1.0f + - static_cast(real_time - progress_bar_end_time_) + / (static_cast(kProgressBarFadeTime) * 0.5f)); + UpdateProgressBarProgress(1.0f); + DrawProgressBar(overlay_pass, o); + } + } +} + +void Graphics::DrawCursor(RenderPass* pass, millisecs_t real_time) { + assert(InGameThread()); + + bool can_show_cursor = g_platform->IsRunningOnDesktop(); + bool should_show_cursor = camera_->manual() || g_input->IsCursorVisible(); + + if (g_buildconfig.hardware_cursor()) { + // If we're using a hardware cursor, ship hardware cursor visibility + // updates to the app thread periodically. + bool new_cursor_visibility = false; + if (can_show_cursor && should_show_cursor) { + new_cursor_visibility = true; + } + + // Ship this state when it changes and also every now and then just in + // case things go wonky. + if (new_cursor_visibility != hardware_cursor_visible_ + || real_time - last_cursor_visibility_event_time_ > 2000) { + hardware_cursor_visible_ = new_cursor_visibility; + last_cursor_visibility_event_time_ = real_time; + g_app->PushCursorUpdate(hardware_cursor_visible_); + } + } else { + // Draw software cursor. + if (can_show_cursor && should_show_cursor) { + SimpleComponent c(pass); + c.SetTransparent(true); + float csize = 50.0f; + c.SetTexture(g_media->GetTexture(SystemTextureID::kCursor)); + c.PushTransform(); + + // Note: we don't plug in known cursor position values here; we tell the + // renderer to insert the latest values on its end; this lessens cursor + // lag substantially. + c.CursorTranslate(); + c.Translate(csize * 0.44f, csize * -0.44f, kCursorZDepth); + c.Scale(csize, csize); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + } + } +} + +void Graphics::DrawBlotches(FrameDef* frame_def) { + if (!this->blotch_verts_.empty()) { + if (!this->shadow_blotch_mesh_.exists()) + this->shadow_blotch_mesh_ = Object::New(); + this->shadow_blotch_mesh_->SetIndexData(Object::New( + this->blotch_indices_.size(), &this->blotch_indices_[0])); + this->shadow_blotch_mesh_->SetData(Object::New>( + this->blotch_verts_.size(), &this->blotch_verts_[0])); + SpriteComponent c(frame_def->light_shadow_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kLight)); + c.DrawMesh(this->shadow_blotch_mesh_.get()); + c.Submit(); + } + if (!this->blotch_soft_verts_.empty()) { + if (!this->shadow_blotch_soft_mesh_.exists()) + this->shadow_blotch_soft_mesh_ = Object::New(); + this->shadow_blotch_soft_mesh_->SetIndexData(Object::New( + this->blotch_soft_indices_.size(), &this->blotch_soft_indices_[0])); + this->shadow_blotch_soft_mesh_->SetData( + Object::New>(this->blotch_soft_verts_.size(), + &this->blotch_soft_verts_[0])); + SpriteComponent c(frame_def->light_shadow_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kLightSoft)); + c.DrawMesh(this->shadow_blotch_soft_mesh_.get()); + c.Submit(); + } + if (!this->blotch_soft_obj_verts_.empty()) { + if (!this->shadow_blotch_soft_obj_mesh_.exists()) { + this->shadow_blotch_soft_obj_mesh_ = Object::New(); + } + this->shadow_blotch_soft_obj_mesh_->SetIndexData( + Object::New(this->blotch_soft_obj_indices_.size(), + &this->blotch_soft_obj_indices_[0])); + this->shadow_blotch_soft_obj_mesh_->SetData( + Object::New>( + this->blotch_soft_obj_verts_.size(), + &this->blotch_soft_obj_verts_[0])); + SpriteComponent c(frame_def->light_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kLightSoft)); + c.DrawMesh(this->shadow_blotch_soft_obj_mesh_.get()); + c.Submit(); + } +} + +void Graphics::SetSupportsHighQualityGraphics(bool s) { + supports_high_quality_graphics_ = s; + has_supports_high_quality_graphics_value_ = true; +} + +void Graphics::ClearScreenMessageTranslations() { + for (auto&& i : screen_messages_) { + i.translation_dirty = true; + } + for (auto&& i : screen_messages_top_) { + i.translation_dirty = true; + } +} + +void Graphics::ReturnCompletedFrameDef(FrameDef* frame_def) { + std::lock_guard lock(frame_def_delete_list_mutex_); + g_graphics->frame_def_delete_list_.push_back(frame_def); +} + +void Graphics::AddMeshDataCreate(MeshData* d) { + assert(InGameThread()); + assert(g_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. + mesh_data_creates_.push_back(d); +} + +void Graphics::AddMeshDataDestroy(MeshData* d) { + assert(InGameThread()); + assert(g_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. + mesh_data_destroys_.push_back(d); +} + +void Graphics::EnableProgressBar(bool fade_in) { + assert(InGameThread()); + progress_bar_loads_ = g_media->GetGraphicalPendingLoadCount(); + assert(progress_bar_loads_ >= 0); + if (progress_bar_loads_ > 0) { + progress_bar_ = true; + progress_bar_fade_in_ = fade_in; + last_progress_bar_draw_time_ = GetRealTime(); + last_progress_bar_start_time_ = last_progress_bar_draw_time_; + progress_bar_progress_ = 0.0f; + } +} + +void Graphics::ToggleManualCamera() { + assert(InGameThread()); + camera_->SetManual(!camera_->manual()); + if (camera_->manual()) { + ScreenMessage("Manual Camera On"); + } else { + ScreenMessage("Manual Camera Off"); + } +} + +void Graphics::LocalCameraShake(float mag) { + assert(InGameThread()); + if (camera_.exists()) { + camera_->Shake(mag); + } +} + +void Graphics::ToggleDebugInfoDisplay() { + assert(InGameThread()); + debug_info_display_ = !debug_info_display_; + if (debug_info_display_) { + ScreenMessage("debug info on\n"); + } else { + ScreenMessage("debug info off\n"); + } +} + +void Graphics::ToggleDebugDraw() { + assert(InGameThread()); + debug_draw_ = !debug_draw_; + if (g_graphics_server->renderer()) { + g_graphics_server->renderer()->set_debug_draw_mode(debug_draw_); + } +} + +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_graphics_server == nullptr + || g_graphics_server->renderer() == nullptr) { + BA_LOG_ONCE( + "BuildAndPushFrameDef() called before renderer is up; spinning..."); + Platform::SleepMS(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; +} + +void Graphics::DoDrawBlotch(std::vector* indices, + std::vector* verts, + const Vector3f& pos, float size, float r, float g, + float b, float a) { + assert(InGameThread()); + assert(indices && verts); + + // Add verts. + assert((*verts).size() < 65536); + auto count = static_cast((*verts).size()); + (*verts).resize(count + 4); + { + VertexSprite& p((*verts)[count]); + p.position[0] = pos.x; + p.position[1] = pos.y; + p.position[2] = pos.z; + p.uv[0] = 0; + p.uv[1] = 0; + p.size = size; + p.color[0] = r; + p.color[1] = g; + p.color[2] = b; + p.color[3] = a; + } + { + VertexSprite& p((*verts)[count + 1]); + p.position[0] = pos.x; + p.position[1] = pos.y; + p.position[2] = pos.z; + p.uv[0] = 0; + p.uv[1] = 65535; + p.size = size; + p.color[0] = r; + p.color[1] = g; + p.color[2] = b; + p.color[3] = a; + } + { + VertexSprite& p((*verts)[count + 2]); + p.position[0] = pos.x; + p.position[1] = pos.y; + p.position[2] = pos.z; + p.uv[0] = 65535; + p.uv[1] = 0; + p.size = size; + p.color[0] = r; + p.color[1] = g; + p.color[2] = b; + p.color[3] = a; + } + { + VertexSprite& p((*verts)[count + 3]); + p.position[0] = pos.x; + p.position[1] = pos.y; + p.position[2] = pos.z; + p.uv[0] = 65535; + p.uv[1] = 65535; + p.size = size; + p.color[0] = r; + p.color[1] = g; + p.color[2] = b; + p.color[3] = a; + } + + // Add indices. + { + size_t i_count = (*indices).size(); + (*indices).resize(i_count + 6); + uint16_t* i = &(*indices)[i_count]; + i[0] = count; + i[1] = static_cast(count + 1); + i[2] = static_cast(count + 2); + i[3] = static_cast(count + 1); + i[4] = static_cast(count + 3); + i[5] = static_cast(count + 2); + } +} + +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. + + 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, + } + }; + // clang-format on + m->SetIndexData(Object::New(6, indices)); + m->SetData(Object::New>(4, vertices)); + + } else { + bool flipped = true; + uint16_t indices[15]; + VertexSimpleFull v[15]; + float x = -tanf(amt * (3.141592f * 2.0f)); + uint16_t i = 0; + + // First 45 degrees past 12:00. + if (amt > 0.875f) { + if (flipped) { + v[i].uv[0] = 0; + v[i].uv[1] = 0; + v[i].position[0] = -1; + v[i].position[1] = 1; + v[i].position[2] = 0; + indices[i] = i; + i++; + v[i].uv[0] = static_cast(65535 - 65535 * 0.5f); + v[i].uv[1] = static_cast(65535 * 0.5f); + v[i].position[0] = 0; + v[i].position[1] = 0; + v[i].position[2] = 0; + indices[i] = i; + i++; + v[i].uv[0] = static_cast(65535 - 65535 * (0.5f + x * 0.5f)); + v[i].uv[1] = 0; + v[i].position[0] = -x; + v[i].position[1] = 1; + v[i].position[2] = 0; + indices[i] = i; + i++; + } + } + + // Top right down to bot-right. + if (amt > 0.625f) { + float y = (amt > 0.875f ? -1.0f : 1.0f / tanf(amt * (3.141592f * 2.0f))); + if (flipped) { + v[i].uv[0] = 0; + v[i].uv[1] = static_cast(65535 * (0.5f + y * 0.5f)); + v[i].position[0] = -1; + v[i].position[1] = -y; + v[i].position[2] = 0; + indices[i] = i; + i++; + v[i].uv[0] = 0; + v[i].uv[1] = 65535; + v[i].position[0] = -1; + v[i].position[1] = -1; + v[i].position[2] = 0; + indices[i] = i; + i++; + v[i].uv[0] = static_cast(65535 - 65535 * 0.5f); + v[i].uv[1] = static_cast(65535 * 0.5f); + v[i].position[0] = 0; + v[i].position[1] = 0; + v[i].position[2] = 0; + indices[i] = i; + i++; + } + } + + // Bot right to bot left. + if (amt > 0.375f) { + float x2 = (amt > 0.625f ? 1.0f : tanf(amt * (3.141592f * 2.0f))); + if (flipped) { + v[i].uv[0] = static_cast(65535 - 65535 * (0.5f + x2 * 0.5f)); + v[i].uv[1] = 65535; + v[i].position[0] = -x2; + v[i].position[1] = -1; + v[i].position[2] = 0; + indices[i] = i; + i++; + + v[i].uv[0] = 65535; + v[i].uv[1] = 65535; + v[i].position[0] = 1; + v[i].position[1] = -1; + v[i].position[2] = 0; + indices[i] = i; + i++; + + v[i].uv[0] = static_cast(65535 - 65535 * 0.5f); + v[i].uv[1] = static_cast(65535 * 0.5f); + v[i].position[0] = 0; + v[i].position[1] = 0; + v[i].position[2] = 0; + indices[i] = i; + i++; + } + } + + // Bot left to top left. + if (amt > 0.125f) { + float y = (amt > 0.375f ? -1.0f : 1.0f / tanf(amt * (3.141592f * 2.0f))); + + if (flipped) { + v[i].uv[0] = static_cast(65535 - 65535 * 0.5f); + v[i].uv[1] = static_cast(65535 * 0.5f); + v[i].position[0] = 0; + v[i].position[1] = 0; + v[i].position[2] = 0; + indices[i] = i; + i++; + + v[i].uv[0] = 65535; + v[i].uv[1] = static_cast(65535 * (0.5f - 0.5f * y)); + v[i].position[0] = 1; + v[i].position[1] = y; + v[i].position[2] = 0; + indices[i] = i; + i++; + + v[i].uv[0] = 65535; + v[i].uv[1] = 0; + v[i].position[0] = 1; + v[i].position[1] = 1; + v[i].position[2] = 0; + indices[i] = i; + i++; + } + } + + // Top left to top mid. + { + float x2 = (amt > 0.125f ? 1.0f : tanf(amt * (3.141592f * 2.0f))); + if (flipped) { + v[i].uv[0] = static_cast(65535 - 65535 * 0.5f); + v[i].uv[1] = static_cast(65535 * 0.5f); + v[i].position[0] = 0; + v[i].position[1] = 0; + v[i].position[2] = 0; + indices[i] = i; + i++; + + v[i].uv[0] = static_cast(65535 - 65535 * (0.5f - x2 * 0.5f)); + v[i].uv[1] = 0; + v[i].position[0] = x2; + v[i].position[1] = 1; + v[i].position[2] = 0; + indices[i] = i; + i++; + + v[i].uv[0] = static_cast(65535 - 65535 * 0.5f); + v[i].uv[1] = 0; + v[i].position[0] = 0; + v[i].position[1] = 1; + v[i].position[2] = 0; + indices[i] = i; + i++; + } + } + m->SetIndexData(Object::New(i, indices)); + m->SetData(Object::New>(i, v)); + } +} + +auto Graphics::ScreenMessageEntry::GetText() -> TextGroup& { + assert(!translation_dirty); + if (!s_mesh_.exists()) { + s_mesh_ = Object::New(); + mesh_dirty = true; + } + if (mesh_dirty) { + s_mesh_->SetText( + s_translated, + align_left ? TextMesh::HAlign::kLeft : TextMesh::HAlign::kCenter, + TextMesh::VAlign::kBottom); + mesh_dirty = false; + } + return *s_mesh_; +} + +void Graphics::ScreenResize(float virtual_width, float virtual_height, + float pixel_width, float pixel_height) { + assert(InGameThread()); + res_x_virtual_ = virtual_width; + res_y_virtual_ = virtual_height; + res_x_ = pixel_width; + res_y_ = pixel_height; + + // Need to rebuild internal components (some are sized to the screen). + internal_components_inited_ = false; +} + +void Graphics::ScreenMessageEntry::UpdateTranslation() { + if (translation_dirty) { + s_translated = g_game->CompileResourceString( + s_raw, "Graphics::ScreenMessageEntry::UpdateTranslation"); + translation_dirty = false; + mesh_dirty = true; + } +} + +auto Graphics::CubeMapFromReflectionType(ReflectionType reflection_type) + -> SystemCubeMapTextureID { + switch (reflection_type) { + case ReflectionType::kChar: + return SystemCubeMapTextureID::kReflectionChar; + case ReflectionType::kPowerup: + return SystemCubeMapTextureID::kReflectionPowerup; + case ReflectionType::kSoft: + return SystemCubeMapTextureID::kReflectionSoft; + case ReflectionType::kSharp: + return SystemCubeMapTextureID::kReflectionSharp; + case ReflectionType::kSharper: + return SystemCubeMapTextureID::kReflectionSharper; + case ReflectionType::kSharpest: + return SystemCubeMapTextureID::kReflectionSharpest; + default: + throw Exception(); + } +} + +auto Graphics::StringFromReflectionType(ReflectionType r) -> std::string { + switch (r) { + case ReflectionType::kSoft: + return "soft"; + break; + case ReflectionType::kChar: + return "char"; + break; + case ReflectionType::kPowerup: + return "powerup"; + break; + case ReflectionType::kSharp: + return "sharp"; + break; + case ReflectionType::kSharper: + return "sharper"; + break; + case ReflectionType::kSharpest: + return "sharpest"; + break; + case ReflectionType::kNone: + return "none"; + break; + default: + throw Exception("Invalid reflection value: " + + std::to_string(static_cast(r))); + break; + } +} + +auto Graphics::ReflectionTypeFromString(const std::string& s) + -> ReflectionType { + ReflectionType r; + if (s == "soft") { + r = ReflectionType::kSoft; + } else if (s == "char") { + r = ReflectionType::kChar; + } else if (s == "powerup") { + r = ReflectionType::kPowerup; + } else if (s == "sharp") { + r = ReflectionType::kSharp; + } else if (s == "sharper") { + r = ReflectionType::kSharper; + } else if (s == "sharpest") { + r = ReflectionType::kSharpest; + } else if (s.empty() || s == "none") { + r = ReflectionType::kNone; + } else { + throw Exception("invalid reflection type: '" + s + "'"); + } + return r; +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/graphics.h b/src/ballistica/graphics/graphics.h new file mode 100644 index 00000000..5a842041 --- /dev/null +++ b/src/ballistica/graphics/graphics.h @@ -0,0 +1,424 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_GRAPHICS_H_ +#define BALLISTICA_GRAPHICS_GRAPHICS_H_ + +#include +#include +#include +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/math/rect.h" +#include "ballistica/math/vector2f.h" + +namespace ballistica { + +// Light/shadow res is divided by this to get pure light res. +const int kLightResDiv = 4; + +// How we divide up our z depth spectrum: +const float kBackingDepth5 = 1.0f; + +// Background +// blit-shapes (with cam buffer) +const float kBackingDepth4 = 0.9f; + +// World (without cam buffer) or overlay-3d (with cam buffer) +const float kBackingDepth3C = 0.65f; +const float kBackingDepth3B = 0.4f; +const float kBackingDepth3 = 0.15f; + +// Overlay-3d (without cam buffer) / overlay(vr) +const float kBackingDepth2C = 0.147f; +const float kBackingDepth2B = 0.143f; +const float kBackingDepth2 = 0.14f; + +// Overlay(non-vr) // cover (vr) +const float kBackingDepth1B = 0.01f; +const float kBackingDepth1 = 0.0f; + +const float kShadowNeutral = 0.5f; + +// Client class for graphics operations (used from the game thread). +class Graphics { + public: + Graphics(); + virtual ~Graphics(); + + static auto IsShaderTransparent(ShadingType c) -> bool; + static auto CubeMapFromReflectionType(ReflectionType reflection_type) + -> SystemCubeMapTextureID; + + // Given a string, return a reflection type. + static auto ReflectionTypeFromString(const std::string& s) -> ReflectionType; + + // ..and the opposite. + static auto StringFromReflectionType(ReflectionType reflectionType) + -> std::string; + + auto Reset() -> void; + auto BuildAndPushFrameDef() -> void; + + virtual auto ApplyCamera(FrameDef* frame_def) -> void; + + // Called when the GraphicsServer's screen configuration changes. + auto ScreenResize(float virtual_width, float virtual_height, + float physical_width, float physical_height) -> void; + + // Called when the GraphicsServer has sent us a frame-def for deletion. + auto ReturnCompletedFrameDef(FrameDef* frame_def) -> void; + + auto screen_pixel_width() const -> float { return res_x_; } + auto screen_pixel_height() const -> float { return res_y_; } + + // Return the size of the virtual screen. This value should always + // be used for interface positioning, etc. + auto screen_virtual_width() const -> float { return res_x_virtual_; } + auto screen_virtual_height() const -> float { return res_y_virtual_; } + + auto ClearScreenMessageTranslations() -> void; + + // Given a point in space, returns the shadow density that should be drawn + // into the shadow pass. Does this belong somewhere else? + auto GetShadowDensity(float x, float y, float z) -> float; + + static auto GetSafeColor(float* r, float* g, float* b, + float target_intensity = 0.6f) -> void; + + // Print a message to the on-screen list. + auto AddScreenMessage(const std::string& msg, + const Vector3f& color = Vector3f{1, 1, 1}, + bool top = false, Texture* texture = nullptr, + Texture* tint_texture = nullptr, + const Vector3f& tint = Vector3f{1, 1, 1}, + const Vector3f& tint2 = Vector3f{1, 1, 1}) -> void; + + // Fade the local screen in or out over the given time period. + auto FadeScreen(bool to, millisecs_t time, PyObject* endcall) -> void; + + static auto DrawRadialMeter(MeshIndexedSimpleFull* m, float amt) -> void; + + // Ways to add a few simple component types quickly. + // (uses particle rendering for efficient batches). + auto DrawBlotch(const Vector3f& pos, float size, float r, float g, float b, + float a) -> void { + DoDrawBlotch(&blotch_indices_, &blotch_verts_, pos, size, r, g, b, a); + } + + auto DrawBlotchSoft(const Vector3f& pos, float size, float r, float g, + float b, float a) -> void { + DoDrawBlotch(&blotch_soft_indices_, &blotch_soft_verts_, pos, size, r, g, b, + a); + } + + // Draw a soft blotch on objects; not terrain. + auto DrawBlotchSoftObj(const Vector3f& pos, float size, float r, float g, + float b, float a) -> void { + DoDrawBlotch(&blotch_soft_obj_indices_, &blotch_soft_obj_verts_, pos, size, + r, g, b, a); + } + + // Enable progress bar drawing locally. + auto EnableProgressBar(bool fade_in) -> void; + + auto camera() -> Camera* { return camera_.get(); } + auto ToggleManualCamera() -> void; + auto LocalCameraShake(float intensity) -> void; + auto ToggleDebugDraw() -> void; + auto debug_info_display() const -> bool { return debug_info_display_; } + auto ToggleDebugInfoDisplay() -> void; + auto SetGyroEnabled(bool enable) -> void; + auto floor_reflection() const -> bool { + assert(InGameThread()); + return floor_reflection_; + } + auto set_floor_reflection(bool val) -> void { + assert(InGameThread()); + floor_reflection_ = val; + } + auto set_shadow_offset(const Vector3f& val) -> void { + assert(InGameThread()); + shadow_offset_ = val; + } + auto set_shadow_scale(float x, float y) -> void { + assert(InGameThread()); + shadow_scale_.x = x; + shadow_scale_.y = y; + } + auto set_shadow_ortho(bool o) -> void { + assert(InGameThread()); + shadow_ortho_ = o; + } + auto tint() -> const Vector3f& { return tint_; } + auto set_tint(const Vector3f& val) -> void { + assert(InGameThread()); + tint_ = val; + } + + auto set_ambient_color(const Vector3f& val) -> void { + assert(InGameThread()); + ambient_color_ = val; + } + auto set_vignette_outer(const Vector3f& val) -> void { + assert(InGameThread()); + vignette_outer_ = val; + } + auto set_vignette_inner(const Vector3f& val) -> void { + assert(InGameThread()); + vignette_inner_ = val; + } + auto shadow_offset() const -> const Vector3f& { + assert(InGameThread()); + return shadow_offset_; + } + auto shadow_scale() const -> const Vector2f& { + assert(InGameThread()); + return shadow_scale_; + } + auto tint() const -> const Vector3f& { + assert(InGameThread()); + return tint_; + } + auto ambient_color() const -> const Vector3f& { + assert(InGameThread()); + return ambient_color_; + } + auto vignette_outer() const -> const Vector3f& { + assert(InGameThread()); + return vignette_outer_; + } + auto vignette_inner() const -> const Vector3f& { + assert(InGameThread()); + return vignette_inner_; + } + auto shadow_ortho() const -> bool { + assert(InGameThread()); + return shadow_ortho_; + } + auto SetShadowRange(float lower_bottom, float lower_top, float upper_bottom, + float upper_top) -> void; + auto ReleaseFadeEndCommand() -> void; + auto set_show_fps(bool val) -> void { show_fps_ = val; } + + // FIXME - move to graphics_server + auto set_tv_border(bool val) -> void { + assert(InGameThread()); + tv_border_ = val; + } + auto tv_border() const -> bool { + assert(InGameThread()); + return tv_border_; + } + + // Nodes that draw flat stuff into the overlay pass should query this z value + // for where to draw in z. + auto overlay_node_z_depth() -> float { + fetched_overlay_node_z_depth_ = true; + return overlay_node_z_depth_; + } + + // This should be called before/after drawing each node to keep the value + // incrementing. + auto PreNodeDraw() -> void { fetched_overlay_node_z_depth_ = false; } + auto PostNodeDraw() -> void { + if (fetched_overlay_node_z_depth_) { + overlay_node_z_depth_ *= 0.99f; + } + } + + auto accel() const -> const Vector3f& { return accel_pos_; } + auto tilt() const -> const Vector3f& { return tilt_pos_; } + + auto PixelToVirtualX(float x) const -> float { + if (tv_border_) { + // In this case, 0 to 1 in physical coords maps to -0.05f to 1.05f in + // virtual. + return (-0.5f * kTVBorder) * res_x_virtual_ + + (1.0f + kTVBorder) * res_x_virtual_ * (x / res_x_); + } + return x * (res_x_virtual_ / res_x_); + } + auto PixelToVirtualY(float y) const -> float { + if (tv_border_) { + // In this case, 0 to 1 in physical coords maps to -0.05f to 1.05f in + // virtual. + return (-0.5f * kTVBorder) * res_y_virtual_ + + (1.0f + kTVBorder) * res_y_virtual_ * (y / res_y_); + } + return y * (res_y_virtual_ / res_y_); + } + auto supports_high_quality_graphics() const -> bool { + assert(has_supports_high_quality_graphics_value_); + return supports_high_quality_graphics_; + } + auto SetSupportsHighQualityGraphics(bool s) -> void; + auto has_supports_high_quality_graphics_value() const -> bool { + return has_supports_high_quality_graphics_value_; + } + auto set_internal_components_inited(bool val) -> void { + internal_components_inited_ = val; + } + auto set_gyro_vals(const Vector3f& vals) -> void { gyro_vals_ = vals; } + // auto draw_overlay_bounds() const -> bool { return draw_overlay_bounds_; } + // auto set_draw_overlay_bounds(bool val) -> void { draw_overlay_bounds_ = + // val; } + auto show_net_info() const -> bool { return show_net_info_; } + auto set_show_net_info(bool val) -> void { show_net_info_ = val; } + auto debug_graph_1() const -> NetGraph* { return debug_graph_1_.get(); } + auto debug_graph_2() const -> NetGraph* { return debug_graph_2_.get(); } + + // Used by meshes. + auto AddMeshDataCreate(MeshData* d) -> void; + auto AddMeshDataDestroy(MeshData* d) -> void; + + // For debugging: ensures that only transparent or opaque components + // are submitted while enabled. + auto drawing_transparent_only() const -> bool { + return drawing_transparent_only_; + } + auto set_drawing_transparent_only(bool val) -> void { + drawing_transparent_only_ = val; + } + + auto drawing_opaque_only() const -> bool { return drawing_opaque_only_; } + auto set_drawing_opaque_only(bool val) -> void { drawing_opaque_only_ = val; } + + // Handle testing values from _ba.value_test() + virtual auto ValueTest(const std::string& arg, double* absval, + double* deltaval, double* outval) -> bool; + virtual auto DrawUI(FrameDef* frame_def) -> void; + virtual auto DrawWorld(Session* session, FrameDef* frame_def) -> void; + + auto set_camera_shake_disabled(bool disabled) -> void { + camera_shake_disabled_ = disabled; + } + auto camera_shake_disabled() const { return camera_shake_disabled_; } + auto set_camera_gyro_explicitly_disabled(bool disabled) -> void { + camera_gyro_explicitly_disabled_ = disabled; + } + + private: + class ScreenMessageEntry; + auto DrawBoxingGlovesTest(FrameDef* frame_def) -> void; + auto DrawBlotches(FrameDef* frame_def) -> void; + auto DrawCursor(RenderPass* pass, millisecs_t real_time) -> void; + auto DrawFades(FrameDef* frame_def, millisecs_t real_time) -> void; + auto DrawDebugBuffers(RenderPass* pass) -> void; + auto WaitForRendererToExist() -> void; + + auto UpdateAndDrawProgressBar(FrameDef* frame_def, millisecs_t real_time) + -> void; + auto DoDrawBlotch(std::vector* indices, + std::vector* verts, const Vector3f& pos, + float size, float r, float g, float b, float a) -> void; + auto GetEmptyFrameDef() -> FrameDef*; + auto InitInternalComponents(FrameDef* frame_def) -> void; + auto DrawMiscOverlays(RenderPass* pass) -> void; + auto DrawLoadDot(RenderPass* pass) -> void; + auto ClearFrameDefDeleteList() -> void; + auto DrawProgressBar(RenderPass* pass, float opacity) -> void; + auto UpdateProgressBarProgress(float target) -> void; + auto UpdateGyro(millisecs_t real_time, millisecs_t elapsed) -> void; + + bool drawing_transparent_only_{}; + bool drawing_opaque_only_{}; + std::vector mesh_data_creates_; + std::vector mesh_data_destroys_; + bool has_supports_high_quality_graphics_value_{}; + bool supports_high_quality_graphics_ = false; + millisecs_t last_create_frame_def_time_{}; + Vector3f shadow_offset_{0.0f, 0.0f, 0.0f}; + Vector2f shadow_scale_{1.0f, 1.0f}; + bool shadow_ortho_ = false; + Vector3f tint_{1.0f, 1.0f, 1.0f}; + Vector3f ambient_color_{1.0f, 1.0f, 1.0f}; + Vector3f vignette_outer_{0.0f, 0.0f, 0.0f}; + Vector3f vignette_inner_{1.0f, 1.0f, 1.0f}; + std::vector recycle_frame_defs_; + millisecs_t last_jitter_update_time_ = 0; + Vector3f jitter_{0.0f, 0.0f, 0.0f}; + Vector3f accel_smoothed_{0.0f, 0.0f, 0.0f}; + Vector3f accel_smoothed2_{0.0f, 0.0f, 0.0f}; + Vector3f accel_hi_pass_{0.0f, 0.0f, 0.0f}; + Vector3f accel_vel_{0.0f, 0.0f, 0.0f}; + Vector3f accel_pos_{0.0f, 0.0f, 0.0f}; + Vector3f tilt_smoothed_ = {0.0f, 0.0f, 0.0f}; + Vector3f tilt_vel_{0.0f, 0.0f, 0.0f}; + Vector3f tilt_pos_{0.0f, 0.0f, 0.0f}; + bool gyro_broken_{}; + float gyro_mag_test_{}; + bool fetched_overlay_node_z_depth_{}; + float overlay_node_z_depth_{}; + bool internal_components_inited_{}; + Object::Ref screen_mesh_; + Object::Ref progress_bar_bottom_mesh_; + Object::Ref progress_bar_top_mesh_; + Object::Ref load_dot_mesh_; + Object::Ref fps_text_group_; + Object::Ref net_info_text_group_; + Object::Ref shadow_blotch_mesh_; + Object::Ref shadow_blotch_soft_mesh_; + Object::Ref shadow_blotch_soft_obj_mesh_; + std::string fps_string_; + std::string net_info_string_; + std::vector blotch_indices_; + std::vector blotch_verts_; + std::vector blotch_soft_indices_; + std::vector blotch_soft_verts_; + std::vector blotch_soft_obj_indices_; + std::vector blotch_soft_obj_verts_; + bool show_fps_{}; + bool show_net_info_{}; + bool tv_border_{}; + bool floor_reflection_{}; + Object::Ref debug_graph_1_; + Object::Ref debug_graph_2_; + std::mutex frame_def_delete_list_mutex_; + std::vector frame_def_delete_list_; + bool debug_draw_{}; + bool debug_info_display_{}; + Object::Ref camera_; + millisecs_t next_stat_update_time_{}; + int last_total_frames_rendered_{}; + int last_fps_{}; + std::list screen_messages_; + std::list screen_messages_top_; + bool set_fade_start_on_next_draw_{}; + millisecs_t fade_start_{}; + millisecs_t fade_time_{}; + bool fade_out_{true}; + Object::Ref fade_end_call_; + float fade_{}; + Vector3f gyro_vals_{0.0f, 0.0, 0.0f}; + float res_x_{100}; + float res_y_{100}; + float res_x_virtual_{100}; + float res_y_virtual_{100}; + int progress_bar_loads_{}; + bool progress_bar_{}; + bool progress_bar_fade_in_{}; + millisecs_t progress_bar_end_time_{-9999}; + float progress_bar_progress_{}; + millisecs_t last_progress_bar_draw_time_{}; + millisecs_t last_progress_bar_start_time_{}; + float screen_gamma_{1.0f}; + float shadow_lower_bottom_{-4.0f}; + float shadow_lower_top_{4.0f}; + float shadow_upper_bottom_{30.0f}; + float shadow_upper_top_{40.0f}; + bool hardware_cursor_visible_{}; + bool camera_shake_disabled_{}; + bool camera_gyro_explicitly_disabled_{}; + millisecs_t last_cursor_visibility_event_time_{}; + int64_t frame_def_count_{1}; + bool gyro_enabled_{true}; + millisecs_t last_suppress_gyro_time_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_GRAPHICS_H_ diff --git a/src/ballistica/graphics/graphics_server.cc b/src/ballistica/graphics/graphics_server.cc new file mode 100644 index 00000000..af77a907 --- /dev/null +++ b/src/ballistica/graphics/graphics_server.cc @@ -0,0 +1,765 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/graphics_server.h" + +#include +#include + +#include "ballistica/core/thread.h" +#include "ballistica/generic/lambda_runnable.h" +#include "ballistica/graphics/gl/renderer_gl.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/platform/platform.h" +#include "ballistica/scene/scene.h" + +// FIXME: clear out this conditional stuff. +#if BA_SDL_BUILD +#include "ballistica/platform/sdl/sdl_app.h" +#else +#include "ballistica/app/app.h" +#endif + +namespace ballistica { + +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD +void GraphicsServer::FullscreenCheck() { + if (!fullscreen_enabled()) { +#if BA_ENABLE_OPENGL + SDL_WM_ToggleFullScreen(gl_context_->sdl_screen_surface()); +#endif + } +} +#endif + +GraphicsServer::GraphicsServer(Thread* thread) : Module("graphics", thread) { + // We're a singleton. + assert(g_graphics_server == nullptr); + g_graphics_server = this; + + // For janky old non-event-push mode, just fall back on a timer for rendering. + if (!g_platform->IsEventPushMode()) { + render_timer_ = NewThreadTimer(1000 / 60, true, + NewLambdaRunnable([this] { TryRender(); })); + } +} + +GraphicsServer::~GraphicsServer() { assert(g_graphics); } + +void GraphicsServer::SetRenderHold() { + assert(InGraphicsThread()); + render_hold_++; +} + +void GraphicsServer::SetFrameDef(FrameDef* framedef) { + // Note: we're just setting the framedef directly here + // even though this gets called from the game thread. + // Ideally it would seem we should push these to our thread + // event list, but currently we spin-lock waiting for new + // frames to appear which would prevent that from working; + // we would need to change that code. + assert(frame_def_ == nullptr); + frame_def_ = framedef; +} + +auto GraphicsServer::GetRenderFrameDef() -> FrameDef* { + assert(InGraphicsThread()); + millisecs_t real_time = GetRealTime(); + + if (!renderer_) { + return nullptr; + } + + // If the app says it's minimized minimized, don't do anything. + // (on iOS we'll get shut down if we make GL calls in this state, etc) + if (g_app->paused()) { + return nullptr; + } + + // Do some incremental loading every time we try to render. + g_media->RunPendingGraphicsLoads(); + + // Spin and wait for a short bit for a frame_def to appear. If it does, we + // grab it, render it, and also message the game thread to start generating + // another one. + while (true) { + if (frame_def_) { + FrameDef* frame_def = frame_def_; + frame_def_ = nullptr; + + // Tell the game thread we're ready for the next frame_def so it can start + // building it while we render this one. + g_game->PushFrameDefRequest(); + return frame_def; + } + + // If there's no frame_def for us, sleep for a bit and wait for it. + // But if we've been waiting for too long, give up. + // On some platforms such as android, this frame will still get flipped + // whether we draw in it or not, so we really dont want to not draw if we + // can help it. + millisecs_t t = GetRealTime() - real_time; + if (t >= 1000) { + break; // Fail. + } + Platform::SleepMS(2); + } + return nullptr; +} + +// Runs any mesh updates contained in the frame-def. +void GraphicsServer::RunFrameDefMeshUpdates(FrameDef* frame_def) { + assert(InGraphicsThread()); + + // Run any mesh-data creates/destroys included with this frame_def. + for (auto&& i : frame_def->mesh_data_creates()) { + assert(i != nullptr); + i->iterator_ = mesh_datas_.insert(mesh_datas_.end(), i); + i->Load(renderer_); + } + for (auto&& i : frame_def->mesh_data_destroys()) { + assert(i != nullptr); + i->Unload(renderer_); + mesh_datas_.erase(i->iterator_); + } +} + +// Renders shadow passes and other common parts of a frame_def. +void GraphicsServer::PreprocessRenderFrameDef(FrameDef* frame_def) { + assert(InGraphicsThread()); + + // Now let the renderer do any preprocess passes (shadows, etc). + renderer_->PreprocessFrameDef(frame_def); +} + +// Does the default drawing to the screen, either from the left or right stereo +// eye or in mono. +void GraphicsServer::DrawRenderFrameDef(FrameDef* frame_def, int eye) { + renderer_->RenderFrameDef(frame_def); +} + +// Clean up the frame_def once done drawing it. +void GraphicsServer::FinishRenderFrameDef(FrameDef* frame_def) { + renderer_->FinishFrameDef(frame_def); + + // Let the app know a frame render is complete (it may need to do a swap/etc). + g_app->DidFinishRenderingFrame(frame_def); +} + +void GraphicsServer::TryRender() { + assert(InGraphicsThread()); + + if (FrameDef* frame_def = GetRenderFrameDef()) { + // Note: we always run mesh updates contained in the framedef + // even if we don't actually render it. + // (Hmm this seems flaky; will TryRender always get called + // for each FrameDef?... perhaps we should separate mesh updates + // from FrameDefs? Or change our logic so that frame-defs *always* get + // rendered. + RunFrameDefMeshUpdates(frame_def); + + // Only actually render if we have a screen and aren't in a hold. + auto target = renderer()->screen_render_target(); + if (target != nullptr && render_hold_ == 0) { + PreprocessRenderFrameDef(frame_def); + DrawRenderFrameDef(frame_def); + FinishRenderFrameDef(frame_def); + } + + // Send this frame_def back to the game thread for deletion. + g_graphics->ReturnCompletedFrameDef(frame_def); + } +} + +// Reload all media (for debugging/benchmarking purposes). +void GraphicsServer::ReloadMedia() { + assert(InMainThread()); + + // Immediately unload all renderer data here in this thread. + if (renderer_) { + g_media->UnloadRendererBits(true, true); + } + + // Set a render-hold so we ignore all frame_defs up until the point at which + // we receive the corresponding remove-hold. + // (At which point subsequent frame-defs will be be progress-bar frame_defs so + // we won't hitch if we actually render them.) + assert(g_graphics_server); + SetRenderHold(); + + // Now tell the game thread to kick off loads for everything, flip on + // progress bar drawing, and then tell the graphics thread to stop ignoring + // frame-defs. + g_game->PushCall([this] { + g_media->MarkAllMediaForLoad(); + g_graphics->EnableProgressBar(false); + PushRemoveRenderHoldCall(); + }); +} + +// Call when renderer context has been lost. +void GraphicsServer::RebuildLostContext() { + assert(InGraphicsThread()); + + if (!renderer_) { + Log("Error: No renderer on GraphicsServer::_rebuildContext."); + return; + } + + // Mark our context as lost so the renderer knows to not try and tear things + // down itself. + set_renderer_context_lost(true); + + // Unload all texture and model data here in the render thread. + g_media->UnloadRendererBits(true, true); + + // Also unload dynamic meshes. + for (auto&& i : mesh_datas_) { + i->Unload(renderer_); + } + + // And other internal renderer stuff. + renderer_->Unload(); + + set_renderer_context_lost(false); + + // Now reload. + renderer_->Load(); + + // Also (re)load all dynamic meshes. + for (auto&& i : mesh_datas_) { + i->Load(renderer_); + } + + renderer_->ScreenSizeChanged(); + + // Set a render-hold so we ignore all frame_defs up until the point at which + // we receive the corresponding remove-hold. + // (At which point subsequent frame-defs will be be progress-bar frame_defs so + // we won't hitch if we actually render them.) + SetRenderHold(); + + // Now tell the game thread to kick off loads for everything, flip on progress + // bar drawing, and then tell the graphics thread to stop ignoring frame-defs. + g_game->PushCall([this] { + g_media->MarkAllMediaForLoad(); + g_graphics->EnableProgressBar(false); + PushRemoveRenderHoldCall(); + }); +} + +void GraphicsServer::SetScreen(bool fullscreen, int width, int height, + TextureQuality texture_quality_requested, + GraphicsQuality graphics_quality_requested, + const std::string& android_res) { + assert(InGraphicsThread()); + + // If we know what we support, filter out requests we don't support + // (will keep us from rebuilding contexts due to our requested and actual + // values not lining up). + if (g_graphics->has_supports_high_quality_graphics_value()) { + if (!g_graphics->supports_high_quality_graphics() + && (graphics_quality_requested == GraphicsQuality::kHigh + || graphics_quality_requested == GraphicsQuality::kHigher)) { + graphics_quality_requested = GraphicsQuality::kMedium; + } + } + +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD + bool create_fullscreen_check_timer = false; +#endif + + bool do_toggle_fs = false; + bool do_set_existing_fs = false; + + if (HeadlessMode()) { + // We don't actually make or update a renderer in headless, but we + // still need to set our list of supported textures types/etc. to avoid + // complaints. + std::list c_types; + SetTextureCompressionTypes(c_types); + quality_requested_ = quality_actual_ = GraphicsQuality::kLow; + graphics_quality_set_ = true; + texture_quality_requested_ = texture_quality_actual_ = TextureQuality::kLow; + texture_quality_set_ = true; + } else { + // OK - starting in SDL2 we never pass in specific resolution requests.. + // we request fullscreen-windows for full-screen situations and that's it. + // (otherwise we may wind up with huge windows due to passing in desktop + // resolutions and retina wonkiness) + width = 800; + height = 600; + + // We should never have to recreate the context after the initial time on + // our modern builds. + bool need_full_context_rebuild = (!renderer_); + bool need_renderer_reload; + + // We need a full renderer reload if quality values have changed. + need_renderer_reload = + ((texture_quality_requested_ != texture_quality_requested) + || (quality_requested_ != graphics_quality_requested) + || !texture_quality_set() || !graphics_quality_set()); + + // This stuff requires a full context rebuild. + if (need_full_context_rebuild || need_renderer_reload) { + HandleFullContextScreenRebuild(need_full_context_rebuild, fullscreen, + width, height, graphics_quality_requested, + texture_quality_requested); + // On mac, we let window save/restore handle our fullscreen restoring for + // us. However if document restore is turned off we'll start windowed on + // every launch. So if we're trying to make a fullscreen setup, lets + // check after a short delay to make sure we have it, and run a + // full-screen-toggle ourself if not. +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD + if (fullscreen) { + create_fullscreen_check_timer = true; + } +#endif // BA_OSTYPE_MACOS + + } else { + // on SDL2 builds we can just set fullscreen on the existing window; no + // need for a context rebuild +#if BA_SDL2_BUILD + do_set_existing_fs = true; +#else + // On our old custom SDL1.2 mac build, fullscreen toggling winds up here. + // this doesn't require a context rebuild either. + if (fullscreen != fullscreen_enabled()) { + do_toggle_fs = true; + } +#endif // BA_SDL2_BUILD + } + + HandlePushAndroidRes(android_res); + +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && BA_SDL_BUILD + if (create_fullscreen_check_timer) { + NewThreadTimer(1000, false, + NewLambdaRunnable([this] { FullscreenCheck(); })); + } +#endif // BA_OSTYPE_MACOS + + HandleFullscreenToggling(do_set_existing_fs, do_toggle_fs, fullscreen); + } + + // The first time we complete setting up our screen, we send a message + // back to the game thread to complete the init process.. (they can't start + // loading graphics and things until we have our context set up so we know + // what types of textures to load, etc) + if (!initial_screen_created_) { + initial_screen_created_ = true; + g_game->PushInitialScreenCreatedCall(); + } +} + +void GraphicsServer::HandleFullContextScreenRebuild( + bool need_full_context_rebuild, bool fullscreen, int width, int height, + GraphicsQuality graphics_quality_requested, + TextureQuality texture_quality_requested) { + // Unload renderer-specific data (display-lists, internal textures, etc) + if (renderer_) { + // Unload all textures and models.. these will be reloaded as-needed + // automatically for the new context.. + g_media->UnloadRendererBits(true, true); + + // Also unload all dynamic meshes. + for (auto&& i : mesh_datas_) { + i->Unload(renderer_); + } + + // And all internal renderer stuff. + renderer_->Unload(); + } + + // Handle screen/context recreation. + if (need_full_context_rebuild) { + // On mac we store the values we *want* separate from those we get.. (so + // we know when our request has changed; not our result). +#if !(BA_OSTYPE_MACOS && BA_XCODE_BUILD) + fullscreen_enabled_ = fullscreen; +#endif + + target_res_x_ = static_cast(width); + target_res_y_ = static_cast(height); + +#if BA_ENABLE_OPENGL + gl_context_ = std::make_unique(width, height, fullscreen); + res_x_ = static_cast(gl_context_->res_x()); + res_y_ = static_cast(gl_context_->res_y()); +#endif + + UpdateVirtualScreenRes(); + + // Inform the game thread of the latest values. + g_game->PushScreenResizeCall(res_x_virtual_, res_y_virtual_, res_x_, + res_y_); + } + + if (!renderer_) { +#if BA_ENABLE_OPENGL + renderer_ = new RendererGL(); +#endif + } + + // Make sure we've done this first so we can properly set auto values and + // whatnot. + renderer_->CheckCapabilities(); + + // Update graphics quality. + quality_requested_ = graphics_quality_requested; + if (quality_requested_ == GraphicsQuality::kAuto) { + quality_actual_ = renderer_->GetAutoGraphicsQuality(); + } else { + quality_actual_ = quality_requested_; + } + + // If we don't support high quality graphics, make sure we're no higher than + // medium. + BA_PRECONDITION(g_graphics->has_supports_high_quality_graphics_value()); + if (!g_graphics->supports_high_quality_graphics() + && quality_actual_ >= GraphicsQuality::kHigh) { + quality_actual_ = GraphicsQuality::kMedium; + } + graphics_quality_set_ = true; + + // Update texture quality. + texture_quality_requested_ = texture_quality_requested; + if (texture_quality_requested_ == TextureQuality::kAuto) { + texture_quality_actual_ = renderer_->GetAutoTextureQuality(); + } else { + texture_quality_actual_ = texture_quality_requested_; + } + texture_quality_set_ = true; + + // Ok we've got our qualities figured out; now load/update the renderer. + renderer_->Load(); + + // Also (re)load all existing dynamic meshes. + for (auto&& i : mesh_datas_) { + i->Load(renderer_); + } + renderer_->ScreenSizeChanged(); + renderer_->PostLoad(); + + // Set a render-hold so we ignore all frame_defs up until the point at which + // we receive the corresponding remove-hold. + // (At which point subsequent frame-defs will be be progress-bar frame_defs + // so we won't hitch if we actually render them.) + SetRenderHold(); + + // Now tell the game thread to kick off loads for everything, flip on + // progress bar drawing, and then tell the graphics thread to stop ignoring + // frame-defs. + g_game->PushCall([this] { + g_media->MarkAllMediaForLoad(); + g_graphics->set_internal_components_inited(false); + g_graphics->EnableProgressBar(false); + PushRemoveRenderHoldCall(); + }); +} + +// Given physical res, calculate virtual res. +void GraphicsServer::CalcVirtualRes(float* x, float* y) { + float x_in = (*x); + float y_in = (*y); + if ((*x) / (*y) > static_cast(kBaseVirtualResX) + / static_cast(kBaseVirtualResY)) { + (*y) = kBaseVirtualResY; + (*x) = (*y) * (x_in / y_in); + } else { + *x = kBaseVirtualResX; + *y = (*x) * (y_in / x_in); + } +} + +void GraphicsServer::UpdateVirtualScreenRes() { + assert(InGraphicsThread()); + // In vr mode our virtual res is independent of our screen size. + // (since it gets drawn to an overlay) + if (IsVRMode()) { + res_x_virtual_ = kBaseVirtualResX; + res_y_virtual_ = kBaseVirtualResY; + } else { + res_x_virtual_ = res_x_; + res_y_virtual_ = res_y_; + CalcVirtualRes(&res_x_virtual_, &res_y_virtual_); + } +} + +void GraphicsServer::VideoResize(float h, float v) { + assert(InGraphicsThread()); + + if (target_res_x_ == h && target_res_y_ == v) { + return; + } + + target_res_x_ = h; + target_res_y_ = v; + res_x_ = h; + res_y_ = v; + UpdateVirtualScreenRes(); + + // Inform the game thread of the latest values. + g_game->PushScreenResizeCall(res_x_virtual_, res_y_virtual_, res_x_, res_y_); + if (renderer_) { + renderer_->ScreenSizeChanged(); + } +} + +// FIXME: Shouldn't have android-specific code in here. +void GraphicsServer::HandlePushAndroidRes(const std::string& android_res) { + if (g_buildconfig.ostype_android()) { + // We push android res to the java layer here. We don't actually worry + // about screen-size-changed callbacks and whatnot, since those will happen + // automatically once things actually change. We just want to be sure that + // we have a renderer so we can calc what our auto res should be. + assert(renderer_); + std::string fin_res; + if (android_res == "Auto") { + fin_res = renderer_->GetAutoAndroidRes(); + } else { + fin_res = android_res; + } + g_platform->AndroidSetResString(fin_res); + } +} + +void GraphicsServer::HandleFullscreenToggling(bool do_set_existing_fs, + bool do_toggle_fs, + bool fullscreen) { + if (do_set_existing_fs) { +#if BA_SDL2_BUILD + bool rift_vr_mode = false; +#if BA_RIFT_BUILD + if (IsVRMode()) { + rift_vr_mode = true; + } +#endif // BA_RIFT_BUILD + if (explicit_bool(!rift_vr_mode)) { +#if BA_OSTYPE_IOS_TVOS + set_fullscreen_enabled(true); + +#else // BA_OSTYPE_IOS_TVOS + uint32_t fullscreen_flag = SDL_WINDOW_FULLSCREEN_DESKTOP; + SDL_SetWindowFullscreen(gl_context_->sdl_window(), + fullscreen ? fullscreen_flag : 0); + + // Ideally this should be driven by OS events and not just explicitly by + // us (so, for instance, if someone presses fullscreen on mac we'd know + // we've gone into fullscreen). But this works for now. + set_fullscreen_enabled(fullscreen); +#endif // BA_OSTYPE_IOS_TVOS + } +#endif // BA_SDL2_BUILD + } else if (do_toggle_fs) { + // If we're doing a fullscreen-toggle, we need to do it after coming out of + // sync mode (because the toggle triggers sync-mode itself). +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD +#if BA_ENABLE_OPENGL + SDL_WM_ToggleFullScreen(gl_context_->sdl_screen_surface()); +#endif +#endif // macos && xcode_build + } +} + +void GraphicsServer::SetTextureCompressionTypes( + const std::list& types) { + texture_compression_types_ = 0; // Reset. + for (auto&& i : types) { + texture_compression_types_ |= (0x01u << (static_cast(i))); + } + texture_compression_types_set_ = true; +} + +void GraphicsServer::SetOrthoProjection(float left, float right, float bottom, + float top, float nearval, + float farval) { + float tx = -((right + left) / (right - left)); + float ty = -((top + bottom) / (top - bottom)); + float tz = -((farval + nearval) / (farval - nearval)); + + projection_matrix_.m[0] = 2.0f / (right - left); + projection_matrix_.m[4] = 0.0f; + projection_matrix_.m[8] = 0.0f; + projection_matrix_.m[12] = tx; + + projection_matrix_.m[1] = 0.0f; + projection_matrix_.m[5] = 2.0f / (top - bottom); + projection_matrix_.m[9] = 0.0f; + projection_matrix_.m[13] = ty; + + projection_matrix_.m[2] = 0.0f; + projection_matrix_.m[6] = 0.0f; + projection_matrix_.m[10] = -2.0f / (farval - nearval); + projection_matrix_.m[14] = tz; + + projection_matrix_.m[3] = 0.0f; + projection_matrix_.m[7] = 0.0f; + projection_matrix_.m[11] = 0.0f; + projection_matrix_.m[15] = 1.0f; + + model_view_projection_matrix_dirty_ = true; + projection_matrix_state_++; +} + +void GraphicsServer::SetCamera(const Vector3f& eye, const Vector3f& target, + const Vector3f& up_vector) { + assert(InGraphicsThread()); + + // Reset the modelview stack. + model_view_stack_.clear(); + + auto forward = (target - eye).Normalized(); + auto side = Vector3f::Cross(forward, up_vector).Normalized(); + Vector3f up = Vector3f::Cross(side, forward); + + //------------------ + model_view_matrix_.m[0] = side.x; + model_view_matrix_.m[4] = side.y; + model_view_matrix_.m[8] = side.z; + model_view_matrix_.m[12] = 0.0f; + //------------------ + model_view_matrix_.m[1] = up.x; + model_view_matrix_.m[5] = up.y; + model_view_matrix_.m[9] = up.z; + model_view_matrix_.m[13] = 0.0f; + //------------------ + model_view_matrix_.m[2] = -forward.x; + model_view_matrix_.m[6] = -forward.y; + model_view_matrix_.m[10] = -forward.z; + model_view_matrix_.m[14] = 0.0f; + //------------------ + model_view_matrix_.m[3] = model_view_matrix_.m[7] = model_view_matrix_.m[11] = + 0.0f; + model_view_matrix_.m[15] = 1.0f; + //------------------ + model_view_matrix_ = + Matrix44fTranslate(-eye.x, -eye.y, -eye.z) * model_view_matrix_; + view_world_matrix_ = model_view_matrix_.Inverse(); + + model_view_projection_matrix_dirty_ = true; + model_world_matrix_dirty_ = true; + + cam_pos_ = eye; + cam_target_ = target; + cam_pos_state_++; + cam_orient_matrix_dirty_ = true; +} + +void GraphicsServer::UpdateCamOrientMatrix() { + assert(InGraphicsThread()); + if (cam_orient_matrix_dirty_) { + cam_orient_matrix_ = kMatrix44fIdentity; + Vector3f to_cam = cam_pos_ - cam_target_; + to_cam.Normalize(); + Vector3f world_up(0, 1, 0); + Vector3f side = Vector3f::Cross(world_up, to_cam); + side.Normalize(); + Vector3f up = Vector3f::Cross(side, to_cam); + cam_orient_matrix_.m[0] = side.x; + cam_orient_matrix_.m[1] = side.y; + cam_orient_matrix_.m[2] = side.z; + cam_orient_matrix_.m[4] = to_cam.x; + cam_orient_matrix_.m[5] = to_cam.y; + cam_orient_matrix_.m[6] = to_cam.z; + cam_orient_matrix_.m[8] = up.x; + cam_orient_matrix_.m[9] = up.y; + cam_orient_matrix_.m[10] = up.z; + cam_orient_matrix_.m[3] = cam_orient_matrix_.m[7] = + cam_orient_matrix_.m[11] = cam_orient_matrix_.m[12] = + cam_orient_matrix_.m[13] = cam_orient_matrix_.m[14] = 0.0f; + cam_orient_matrix_.m[15] = 1.0f; + cam_orient_matrix_state_++; + } +} + +#pragma mark PushCalls + +void GraphicsServer::PushSetScreenCall(bool fullscreen, int width, int height, + TextureQuality texture_quality, + GraphicsQuality graphics_quality, + const std::string& android_res) { + PushCall([=] { + SetScreen(fullscreen, width, height, texture_quality, graphics_quality, + android_res); + }); +} + +void GraphicsServer::PushReloadMediaCall() { + PushCall([this] { ReloadMedia(); }); +} + +void GraphicsServer::PushSetScreenGammaCall(float gamma) { + PushCall([this, gamma] { + assert(InGraphicsThread()); + if (!renderer_) { + return; + } + renderer_->set_screen_gamma(gamma); + }); +} + +void GraphicsServer::PushSetScreenPixelScaleCall(float pixel_scale) { + PushCall([this, pixel_scale] { + assert(InGraphicsThread()); + if (!renderer_) { + return; + } + renderer_->set_pixel_scale(pixel_scale); + }); +} + +void GraphicsServer::PushSetVSyncCall(bool sync, bool auto_sync) { + PushCall([this, sync, auto_sync] { + assert(InGraphicsThread()); + +#if BA_SDL_BUILD + + // Currently only supported for SDLApp. + // May want to revisit this later. + if (g_buildconfig.sdl_build()) { + // Even if we were built with SDL, we may not be running in sdl-app-mode + // (for instance, Rift in VR mode). Only do this if we're an sdl app. + if (auto app = dynamic_cast(g_app)) { + v_sync_ = sync; + auto_vsync_ = auto_sync; + if (gl_context_) { + app->SetAutoVSync(auto_vsync_); + // Set it directly if not auto... + if (!auto_vsync_) { + gl_context_->SetVSync(v_sync_); + } + } else { + Log("Error: Got SetVSyncCall with no gl context."); + } + } + } +#endif // BA_HEADLESS_BUILD + }); +} + +void GraphicsServer::PushComponentUnloadCall( + const std::vector*>& components) { + PushCall([this, components] { + // Unload all components we were passed. + for (auto&& i : components) { + (**i).Unload(); + } + // ..and then ship these pointers back to the game thread so it can free the + // references. + g_game->PushFreeMediaComponentRefsCall(components); + }); +} + +void GraphicsServer::PushRemoveRenderHoldCall() { + PushCall([this] { + assert(render_hold_); + render_hold_--; + if (render_hold_ < 0) { + Log("Error: RenderHold < 0"); + render_hold_ = 0; + } + }); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/graphics_server.h b/src/ballistica/graphics/graphics_server.h new file mode 100644 index 00000000..589bf1d4 --- /dev/null +++ b/src/ballistica/graphics/graphics_server.h @@ -0,0 +1,334 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_GRAPHICS_SERVER_H_ +#define BALLISTICA_GRAPHICS_GRAPHICS_SERVER_H_ + +#include +#include +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/module.h" +#include "ballistica/core/object.h" +#include "ballistica/math/matrix44f.h" + +namespace ballistica { + +// Runs in the main thread and renders frame_defs shipped to it by the +// Graphics +class GraphicsServer : public Module { + public: + explicit GraphicsServer(Thread* thread); + auto PushSetScreenGammaCall(float gamma) -> void; + auto PushSetScreenPixelScaleCall(float pixel_scale) -> void; + auto PushSetVSyncCall(bool sync, bool auto_sync) -> void; + auto PushSetScreenCall(bool fullscreen, int width, int height, + TextureQuality texture_quality, + GraphicsQuality graphics_quality, + const std::string& android_res) -> void; + auto PushReloadMediaCall() -> void; + auto PushRemoveRenderHoldCall() -> void; + auto PushComponentUnloadCall( + const std::vector*>& components) -> void; + auto SetRenderHold() -> void; + + // Used by the game thread to pass frame-defs to the graphics server + // for rendering. + auto SetFrameDef(FrameDef* framedef) -> void; + + // returns the next frame_def needing to be rendered, waiting for it to arrive + // if necessary. this can return nullptr if no frame_defs come in within a + // reasonable amount of time. a frame_def here *must* be rendered and disposed + // of using the RenderFrameDef* calls + auto GetRenderFrameDef() -> FrameDef*; + + auto RunFrameDefMeshUpdates(FrameDef* frame_def) -> void; + + // renders shadow passes and other common parts of a frame_def + auto PreprocessRenderFrameDef(FrameDef* frame_def) -> void; + + // Does the default drawing to the screen, either from the left or right + // stereo eye or in mono. + auto DrawRenderFrameDef(FrameDef* frame_def, int eye = -1) -> void; + + // Clean up the frame_def once done drawing it. + auto FinishRenderFrameDef(FrameDef* frame_def) -> void; + + // Equivalent to calling GetRenderFrameDef() and then preprocess, draw (in + // mono), and finish. + auto TryRender() -> void; + + // init the modelview matrix to look here + auto SetCamera(const Vector3f& eye, const Vector3f& target, + const Vector3f& up) -> void; + auto SetOrthoProjection(float left, float right, float bottom, float top, + float near, float far) -> void; + auto ModelViewReset() -> void { + model_view_matrix_ = kMatrix44fIdentity; + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + model_view_stack_.clear(); + } + auto SetProjectionMatrix(const Matrix44f& p) -> void { + projection_matrix_ = p; + model_view_projection_matrix_dirty_ = true; + projection_matrix_state_++; + } + auto projection_matrix_state() -> uint32_t { + return projection_matrix_state_; + } + + auto SetLightShadowProjectionMatrix(const Matrix44f& p) -> void { + // This will generally get repeatedly set to the same value + // so we can do nothing most of the time. + if (p != light_shadow_projection_matrix_) { + light_shadow_projection_matrix_ = p; + light_shadow_projection_matrix_state_++; + } + } + auto light_shadow_projection_matrix_state() const -> uint32_t { + return light_shadow_projection_matrix_state_; + } + auto light_shadow_projection_matrix() const -> const Matrix44f& { + return light_shadow_projection_matrix_; + } + + // Returns the modelview * projection matrix. + auto GetModelViewProjectionMatrix() -> const Matrix44f& { + UpdateModelViewProjectionMatrix(); + return model_view_projection_matrix_; + } + + auto GetModelViewProjectionMatrixState() -> uint32_t { + UpdateModelViewProjectionMatrix(); + return model_view_projection_matrix_state_; + } + + auto GetModelWorldMatrix() -> const Matrix44f& { + UpdateModelWorldMatrix(); + return model_world_matrix_; + } + + auto GetModelWorldMatrixState() -> uint32_t { + UpdateModelWorldMatrix(); + return model_world_matrix_state_; + } + + auto cam_pos() -> const Vector3f& { return cam_pos_; } + auto cam_pos_state() -> uint32_t { return cam_pos_state_; } + auto GetCamOrientMatrix() -> const Matrix44f& { + UpdateCamOrientMatrix(); + return cam_orient_matrix_; + } + + auto GetCamOrientMatrixState() -> uint32_t { + UpdateCamOrientMatrix(); + return cam_orient_matrix_state_; + } + + auto model_view_matrix() const -> const Matrix44f& { + return model_view_matrix_; + } + auto SetModelViewMatrix(const Matrix44f& m) -> void { + model_view_matrix_ = m; + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + } + + auto projection_matrix() const -> const Matrix44f& { + return projection_matrix_; + } + auto PushTransform() -> void { + model_view_stack_.push_back(model_view_matrix_); + assert(model_view_stack_.size() < 20); + } + + auto PopTransform() -> void { + assert(!model_view_stack_.empty()); + model_view_matrix_ = model_view_stack_.back(); + model_view_stack_.pop_back(); + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + } + + auto Translate(const Vector3f& t) -> void { + model_view_matrix_ = Matrix44fTranslate(t) * model_view_matrix_; + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + } + + auto Rotate(float angle, const Vector3f& axis) -> void { + model_view_matrix_ = Matrix44fRotate(axis, angle) * model_view_matrix_; + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + } + + auto MultMatrix(const Matrix44f& m) -> void { + model_view_matrix_ = m * model_view_matrix_; + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + } + + auto scale(const Vector3f& s) -> void { + model_view_matrix_ = Matrix44fScale(s) * model_view_matrix_; + model_view_projection_matrix_dirty_ = model_world_matrix_dirty_ = true; + } + + auto RebuildLostContext() -> void; + ~GraphicsServer() override; + + auto renderer() { return renderer_; } + auto quality() const -> GraphicsQuality { + assert(graphics_quality_set_); + return quality_actual_; + } + + auto texture_quality() const -> TextureQuality { + assert(texture_quality_set_); + return texture_quality_actual_; + } + + auto screen_pixel_width() const -> float { + assert(InMainThread()); + return res_x_; + } + auto screen_pixel_height() const -> float { + assert(InMainThread()); + return res_y_; + } + + auto screen_virtual_width() const -> float { + assert(InMainThread()); + return res_x_virtual_; + } + auto screen_virtual_height() const -> float { + assert(InMainThread()); + return res_y_virtual_; + } + auto set_tv_border(bool val) -> void { + assert(InMainThread()); + tv_border_ = val; + } + auto tv_border() const { + assert(InMainThread()); + return tv_border_; + } + + auto graphics_quality_set() const { return graphics_quality_set_; } + auto texture_quality_set() const { return texture_quality_set_; } + + auto SupportsTextureCompressionType(TextureCompressionType t) const -> bool { + assert(texture_compression_types_set_); + return ((texture_compression_types_ & (0x01u << static_cast(t))) + != 0u); + } + auto SetTextureCompressionTypes( + const std::list& types) -> void; + + auto texture_compression_types_are_set() const { + return texture_compression_types_set_; + } + auto set_renderer_context_lost(bool lost) -> auto { + renderer_context_lost_ = lost; + } + auto renderer_context_lost() const { return renderer_context_lost_; } + auto fullscreen_enabled() const { return fullscreen_enabled_; } + + // This doesn't actually toggle fullscreen. It is used to inform the game + // when fullscreen changes under it. + auto set_fullscreen_enabled(bool fs) -> void { fullscreen_enabled_ = fs; } + auto VideoResize(float h, float v) -> void; + +#if BA_ENABLE_OPENGL + auto gl_context() const -> GLContext* { return gl_context_.get(); } +#endif + + auto graphics_quality_requested() const { return quality_requested_; } + auto texture_quality_requested() const { return texture_quality_requested_; } + auto renderer() const { return renderer_; } + auto initial_screen_created() const { return initial_screen_created_; } + + private: + auto HandleFullscreenToggling(bool do_set_existing_fs, bool do_toggle_fs, + bool fullscreen) -> void; + auto HandlePushAndroidRes(const std::string& android_res) -> void; + auto HandleFullContextScreenRebuild( + bool need_full_context_rebuild, bool fullscreen, int width, int height, + GraphicsQuality graphics_quality_requested, + TextureQuality texture_quality_requested) -> void; + + // Update virtual screen dimensions based on the current physical ones. + static auto CalcVirtualRes(float* x, float* y) -> void; + + auto UpdateVirtualScreenRes() -> void; + auto UpdateCamOrientMatrix() -> void; + auto ReloadMedia() -> void; + auto UpdateModelViewProjectionMatrix() -> void { + if (model_view_projection_matrix_dirty_) { + model_view_projection_matrix_ = model_view_matrix_ * projection_matrix_; + model_view_projection_matrix_state_++; + model_view_projection_matrix_dirty_ = false; + } + } + auto UpdateModelWorldMatrix() -> void { + if (model_world_matrix_dirty_) { + model_world_matrix_ = model_view_matrix_ * view_world_matrix_; + model_world_matrix_state_++; + model_world_matrix_dirty_ = false; + } + } +#if BA_ENABLE_OPENGL + std::unique_ptr gl_context_; +#endif + float res_x_{}; + float res_y_{}; + float res_x_virtual_{0.0f}; + float res_y_virtual_{0.0f}; + bool tv_border_{}; + bool renderer_context_lost_{}; + uint32_t texture_compression_types_{}; + bool texture_compression_types_set_{}; + TextureQuality texture_quality_requested_{TextureQuality::kLow}; + TextureQuality texture_quality_actual_{TextureQuality::kLow}; + GraphicsQuality quality_requested_{GraphicsQuality::kLow}; + GraphicsQuality quality_actual_{GraphicsQuality::kLow}; + bool graphics_quality_set_{}; + bool texture_quality_set_{}; + bool fullscreen_enabled_{}; + float target_res_x_{800.0f}; + float target_res_y_{600.0f}; + + Matrix44f model_view_matrix_{kMatrix44fIdentity}; + Matrix44f view_world_matrix_{kMatrix44fIdentity}; + Matrix44f projection_matrix_{kMatrix44fIdentity}; + Matrix44f model_view_projection_matrix_{kMatrix44fIdentity}; + Matrix44f model_world_matrix_{kMatrix44fIdentity}; + std::vector model_view_stack_; + uint32_t projection_matrix_state_{1}; + uint32_t model_view_projection_matrix_state_{1}; + uint32_t model_world_matrix_state_{1}; + bool model_view_projection_matrix_dirty_{true}; + bool model_world_matrix_dirty_{true}; + Matrix44f light_shadow_projection_matrix_{kMatrix44fIdentity}; + uint32_t light_shadow_projection_matrix_state_{1}; + Vector3f cam_pos_{0.0f, 0.0f, 0.0f}; + Vector3f cam_target_{0.0f, 0.0f, 0.0f}; + uint32_t cam_pos_state_{1}; + Matrix44f cam_orient_matrix_ = kMatrix44fIdentity; + uint32_t cam_orient_matrix_state_{1}; + bool cam_orient_matrix_dirty_{true}; + std::list mesh_datas_; + bool v_sync_{}; + bool auto_vsync_{}; + auto SetScreen(bool fullscreen, int width, int height, + TextureQuality texture_quality, + GraphicsQuality graphics_quality, + const std::string& android_res) -> void; + Timer* render_timer_{}; + Renderer* renderer_{}; + FrameDef* frame_def_{}; + bool initial_screen_created_{}; + int render_hold_{}; +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD + void FullscreenCheck(); +#endif +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_GRAPHICS_SERVER_H_ diff --git a/src/ballistica/graphics/mesh/image_mesh.cc b/src/ballistica/graphics/mesh/image_mesh.cc new file mode 100644 index 00000000..1d915b5a --- /dev/null +++ b/src/ballistica/graphics/mesh/image_mesh.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/mesh/image_mesh.h" + +namespace ballistica { + +const uint16_t kImageMeshIndices[] = {0, 1, 2, 1, 3, 2}; +const VertexSimpleSplitStatic kImageMeshVerticesStatic[] = { + {0, 65535}, {65535, 65535}, {0, 0}, {65535, 0}}; + +ImageMesh::ImageMesh() { + SetIndexData(Object::New(6, kImageMeshIndices)); + SetStaticData(Object::New >( + 4, kImageMeshVerticesStatic)); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/mesh/image_mesh.h b/src/ballistica/graphics/mesh/image_mesh.h new file mode 100644 index 00000000..2044ddc6 --- /dev/null +++ b/src/ballistica/graphics/mesh/image_mesh.h @@ -0,0 +1,27 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_IMAGE_MESH_H_ +#define BALLISTICA_GRAPHICS_MESH_IMAGE_MESH_H_ + +#include "ballistica/graphics/mesh/mesh_indexed_simple_split.h" + +namespace ballistica { + +// a mesh set up to draw images +class ImageMesh : public MeshIndexedSimpleSplit { + public: + ImageMesh(); + void SetPositionAndSize(float x, float y, float z, float width, + float height) { + VertexSimpleSplitDynamic vdynamic[] = {{x, y, z}, + {x + width, y, z}, + {x, y + height, z}, + {x + width, y + height, z}}; + SetDynamicData( + Object::New>(4, vdynamic)); + } +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_IMAGE_MESH_H_ diff --git a/src/ballistica/graphics/mesh/mesh.h b/src/ballistica/graphics/mesh/mesh.h new file mode 100644 index 00000000..185bcc82 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh.h @@ -0,0 +1,46 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_H_ + +#include "ballistica/core/object.h" +#include "ballistica/graphics/mesh/mesh_data.h" +#include "ballistica/graphics/mesh/mesh_data_client_handle.h" + +namespace ballistica { + +// A user-defined dynamic mesh (unlike a model which is completely static) +class Mesh : public Object { + public: + auto type() const -> MeshDataType { return type_; } + auto mesh_data_client_handle() -> Object::Ref& { + return mesh_data_client_handle_; + } + + // Return whether it is safe to attempt drawing with present data. + virtual auto IsValid() const -> bool = 0; + auto last_frame_def_num() const -> int64_t { return last_frame_def_num_; } + void set_last_frame_def_num(int64_t f) { last_frame_def_num_ = f; } + + protected: + explicit Mesh(MeshDataType type, + MeshDrawType draw_type = MeshDrawType::kStatic) + : valid_(false), type_(type), last_frame_def_num_(0) { + mesh_data_client_handle_ = + Object::New(new MeshData(type, draw_type)); + } + + private: + int64_t last_frame_def_num_{}; + MeshDataType type_{}; + + // Renderer data for this mesh. We keep this as a shared pointer + // so that frame_defs or other things using this mesh can keep it alive + // even if we go away. + Object::Ref mesh_data_client_handle_; + bool valid_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_H_ diff --git a/src/ballistica/graphics/mesh/mesh_buffer.h b/src/ballistica/graphics/mesh/mesh_buffer.h new file mode 100644 index 00000000..009b5ae2 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_buffer.h @@ -0,0 +1,28 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_H_ + +#include +#include + +#include "ballistica/graphics/mesh/mesh_buffer_base.h" + +namespace ballistica { + +// Buffer for arbitrary mesh data. +template +class MeshBuffer : public MeshBufferBase { + public: + MeshBuffer() = default; + explicit MeshBuffer(size_t initial_size) : elements(initial_size) {} + MeshBuffer(size_t initial_size, const T* initial_data) + : elements(initial_size) { + memcpy(&elements[0], initial_data, initial_size * sizeof(T)); + } + std::vector elements; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_H_ diff --git a/src/ballistica/graphics/mesh/mesh_buffer_base.h b/src/ballistica/graphics/mesh/mesh_buffer_base.h new file mode 100644 index 00000000..0a498f49 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_buffer_base.h @@ -0,0 +1,21 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_BASE_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_BASE_H_ + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Buffers used by the game thread to pass indices/vertices/etc. to meshes in +// the graphics thread. Note that it is safe to create these in other threads; +// you just need to turn off thread-checks until you pass ownership to the game +// thread. (or just avoid creating references outside of the game thread) +class MeshBufferBase : public Object { + public: + uint32_t state; // which dynamicState value on the mesh this corresponds to +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_BASE_H_ diff --git a/src/ballistica/graphics/mesh/mesh_buffer_vertex_simple_full.h b/src/ballistica/graphics/mesh/mesh_buffer_vertex_simple_full.h new file mode 100644 index 00000000..27f65892 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_buffer_vertex_simple_full.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SIMPLE_FULL_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SIMPLE_FULL_H_ + +#include "ballistica/graphics/mesh/mesh_buffer.h" + +namespace ballistica { + +// just make this a vanilla child class of our template +// (simply so we could predeclare this) +class MeshBufferVertexSimpleFull : public MeshBuffer { + using MeshBuffer::MeshBuffer; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SIMPLE_FULL_H_ diff --git a/src/ballistica/graphics/mesh/mesh_buffer_vertex_smoke_full.h b/src/ballistica/graphics/mesh/mesh_buffer_vertex_smoke_full.h new file mode 100644 index 00000000..31ef65ec --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_buffer_vertex_smoke_full.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SMOKE_FULL_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SMOKE_FULL_H_ + +#include "ballistica/graphics/mesh/mesh_buffer.h" + +namespace ballistica { + +// just make this a vanilla child class of our template +// (simply so we could predeclare this) +class MeshBufferVertexSmokeFull : public MeshBuffer { + using MeshBuffer::MeshBuffer; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SMOKE_FULL_H_ diff --git a/src/ballistica/graphics/mesh/mesh_buffer_vertex_sprite.h b/src/ballistica/graphics/mesh/mesh_buffer_vertex_sprite.h new file mode 100644 index 00000000..e2288f9e --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_buffer_vertex_sprite.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SPRITE_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SPRITE_H_ + +#include "ballistica/graphics/mesh/mesh_buffer.h" + +namespace ballistica { + +// just make this a vanilla child class of our template +// (simply so we could predeclare this) +class MeshBufferVertexSprite : public MeshBuffer { + using MeshBuffer::MeshBuffer; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_BUFFER_VERTEX_SPRITE_H_ diff --git a/src/ballistica/graphics/mesh/mesh_data.cc b/src/ballistica/graphics/mesh/mesh_data.cc new file mode 100644 index 00000000..ba409272 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_data.cc @@ -0,0 +1,24 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/mesh/mesh_data.h" + +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +void MeshData::Load(Renderer* renderer) { + assert(InGraphicsThread()); + if (!renderer_data_) { + renderer_data_ = renderer->NewMeshData(type(), draw_type()); + } +} + +void MeshData::Unload(Renderer* renderer) { + assert(InGraphicsThread()); + if (renderer_data_) { + renderer->DeleteMeshData(renderer_data_, type()); + renderer_data_ = nullptr; + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/mesh/mesh_data.h b/src/ballistica/graphics/mesh/mesh_data.h new file mode 100644 index 00000000..1dd956c9 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_data.h @@ -0,0 +1,42 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_DATA_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_DATA_H_ + +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// The portion of a mesh that is owned by the graphics thread. +// This contains the renderer-specific data (GL buffers, etc) +class MeshData { + public: + MeshData(MeshDataType type, MeshDrawType draw_type) + : type_(type), draw_type_(draw_type) {} + virtual ~MeshData() { + if (renderer_data_) { + Log("Error: MeshData going down with rendererData intact!"); + } + } + std::list::iterator iterator_; + auto type() -> MeshDataType { return type_; } + auto draw_type() -> MeshDrawType { return draw_type_; } + void Load(Renderer* renderer); + void Unload(Renderer* renderer); + auto renderer_data() const -> MeshRendererData* { + assert(renderer_data_); + return renderer_data_; + } + + private: + MeshRendererData* renderer_data_{}; + MeshDataType type_{}; + MeshDrawType draw_type_{}; + BA_DISALLOW_CLASS_COPIES(MeshData); +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_DATA_H_ diff --git a/src/ballistica/graphics/mesh/mesh_data_client_handle.cc b/src/ballistica/graphics/mesh/mesh_data_client_handle.cc new file mode 100644 index 00000000..a0e26a78 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_data_client_handle.cc @@ -0,0 +1,17 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/mesh/mesh_data_client_handle.h" + +#include "ballistica/graphics/graphics.h" + +namespace ballistica { + +MeshDataClientHandle::MeshDataClientHandle(MeshData* d) : mesh_data(d) { + g_graphics->AddMeshDataCreate(mesh_data); +} + +MeshDataClientHandle::~MeshDataClientHandle() { + g_graphics->AddMeshDataDestroy(mesh_data); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/mesh/mesh_data_client_handle.h b/src/ballistica/graphics/mesh/mesh_data_client_handle.h new file mode 100644 index 00000000..f0eae583 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_data_client_handle.h @@ -0,0 +1,22 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_DATA_CLIENT_HANDLE_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_DATA_CLIENT_HANDLE_H_ + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Client-side (game-thread) handle to server-side (graphics-thread) mesh data. +// Server-side data will be created when this object is instantiated and +// cleared when this object goes down. +class MeshDataClientHandle : public Object { + public: + explicit MeshDataClientHandle(MeshData* d); + ~MeshDataClientHandle() override; + MeshData* mesh_data; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_DATA_CLIENT_HANDLE_H_ diff --git a/src/ballistica/graphics/mesh/mesh_index_buffer_16.h b/src/ballistica/graphics/mesh/mesh_index_buffer_16.h new file mode 100644 index 00000000..84e21a39 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_index_buffer_16.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEX_BUFFER_16_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEX_BUFFER_16_H_ + +#include "ballistica/graphics/mesh/mesh_buffer.h" + +namespace ballistica { + +// standard buffer for indices +class MeshIndexBuffer16 : public MeshBuffer { + using MeshBuffer::MeshBuffer; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEX_BUFFER_16_H_ diff --git a/src/ballistica/graphics/mesh/mesh_index_buffer_32.h b/src/ballistica/graphics/mesh/mesh_index_buffer_32.h new file mode 100644 index 00000000..3cf64da5 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_index_buffer_32.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEX_BUFFER_32_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEX_BUFFER_32_H_ + +#include "ballistica/graphics/mesh/mesh_buffer.h" + +namespace ballistica { + +// standard buffer for indices +class MeshIndexBuffer32 : public MeshBuffer { + using MeshBuffer::MeshBuffer; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEX_BUFFER_32_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed.h b/src/ballistica/graphics/mesh/mesh_indexed.h new file mode 100644 index 00000000..2841ea11 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed.h @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_H_ + +#include "ballistica/graphics/mesh/mesh_indexed_base.h" + +namespace ballistica { + +// Mesh using indices and vertex data (all either static or dynamic). +// Supports both 16 and 32 bit indices. +template +class MeshIndexed : public MeshIndexedBase { + public: + explicit MeshIndexed(MeshDrawType draw_type = MeshDrawType::kDynamic) + : MeshIndexedBase(T, draw_type) {} + void SetData(const Object::Ref>& data) { + assert(!data->elements.empty()); + data_ = data; + data_->state = ++data_state_; + } + auto data() const -> const Object::Ref>& { return data_; } + + auto IsValid() const -> bool override { + if (!data_.exists() || data_->elements.empty() + || !MeshIndexedBase::IsValid()) { + return false; + } + + // Make sure our index size covers our element count. + return IndexSizeIsValid(data_->elements.size()); + } + + private: + Object::Ref> data_; + uint32_t data_state_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_base.h b/src/ballistica/graphics/mesh/mesh_indexed_base.h new file mode 100644 index 00000000..e8daed0c --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_base.h @@ -0,0 +1,106 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_BASE_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_BASE_H_ + +#include "ballistica/graphics/mesh/mesh.h" +#include "ballistica/graphics/mesh/mesh_index_buffer_16.h" +#include "ballistica/graphics/mesh/mesh_index_buffer_32.h" + +namespace ballistica { + +// Mesh supporting index data. +class MeshIndexedBase : public Mesh { + public: + explicit MeshIndexedBase(MeshDataType type, + MeshDrawType draw_type = MeshDrawType::kDynamic) + : Mesh(type, draw_type) {} + + auto index_data_size() const -> int { + assert(index_data_size_ != 0); + return index_data_size_; + } + + void SetIndexData(const Object::Ref& data) { + assert(data.exists() && !data->elements.empty()); + // unlike vertex data, index data might often remain the same, so lets test + // for that and avoid some gl updates.. + if (index_data_32_.exists()) { + assert(data.exists() && index_data_32_.get()); + if (data->elements == index_data_32_->elements) { + return; // just keep our existing one + } + } + index_data_32_ = data; + index_data_32_->state = ++index_state_; + index_data_size_ = 4; + // kill any other index data we have + index_data_16_.Clear(); + } + + void SetIndexData(const Object::Ref& data) { + assert(data.exists() && !data->elements.empty()); + // unlike vertex data, index data might often remain the same, so lets test + // for that and avoid some gl updates.. + if (index_data_16_.exists()) { + assert(index_data_16_.get()); + if (data->elements == index_data_16_->elements) { + return; // just keep our existing one + } + } + // FIXME - we should probably just pass in a strong ref as an arg?... + index_data_16_ = data; + index_data_16_->state = ++index_state_; + index_data_size_ = 2; + // kill any other index data we have + index_data_32_.Clear(); + } + + // call this if you have nothing to draw + void SetEmpty() { + index_data_16_.Clear(); + index_data_32_.Clear(); + } + auto IsValid() const -> bool override { + switch (index_data_size()) { + case 4: + return (index_data_32_.exists() && !index_data_32_->elements.empty()); + case 2: + return (index_data_16_.exists() && !index_data_16_->elements.empty()); + default: + return false; + } + } + // Checks for valid index sizes given a data length. + // Will print a one-time warning and return false if invalid. + // For use by subclasses in their IsValid() overrides + auto IndexSizeIsValid(size_t data_size) const -> bool { + if (index_data_size() == 2 && data_size > 65535) { + BA_LOG_ONCE("ERROR: got mesh data with > 65535 elems and 16 bit indices: " + + GetObjectDescription() + + ". This case requires 32 bit indices."); + return false; + } + return true; + } + auto GetIndexData() const -> MeshBufferBase* { + switch (index_data_size()) { + case 4: + return index_data_32_.get(); + case 2: + return index_data_16_.get(); + default: + throw Exception(); + } + } + + private: + Object::Ref index_data_32_; + Object::Ref index_data_16_; + int index_data_size_ = 0; + uint32_t index_state_ = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_BASE_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h b/src/ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h new file mode 100644 index 00000000..8194061d --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_DUAL_TEXTURE_FULL_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_DUAL_TEXTURE_FULL_H_ + +#include "ballistica/graphics/mesh/mesh_indexed.h" + +namespace ballistica { + +class MeshIndexedDualTextureFull + : public MeshIndexed { + using MeshIndexed::MeshIndexed; // wheee c++11 magic +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_DUAL_TEXTURE_FULL_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_object_split.h b/src/ballistica/graphics/mesh/mesh_indexed_object_split.h new file mode 100644 index 00000000..c1f57a3b --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_object_split.h @@ -0,0 +1,20 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_OBJECT_SPLIT_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_OBJECT_SPLIT_H_ + +#include "ballistica/graphics/mesh/mesh_indexed_static_dynamic.h" + +namespace ballistica { + +// a mesh with static indices and UVs and dynamic positions and normals +class MeshIndexedObjectSplit + : public MeshIndexedStaticDynamic { + using MeshIndexedStaticDynamic::MeshIndexedStaticDynamic; // c++11 magic! +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_OBJECT_SPLIT_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_simple_full.h b/src/ballistica/graphics/mesh/mesh_indexed_simple_full.h new file mode 100644 index 00000000..9e7190c5 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_simple_full.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SIMPLE_FULL_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SIMPLE_FULL_H_ + +#include "ballistica/graphics/mesh/mesh_indexed.h" + +namespace ballistica { + +// a simple mesh with all data provided together (either static or dynamic) +class MeshIndexedSimpleFull + : public MeshIndexed { + using MeshIndexed::MeshIndexed; // wheee c++11 magic +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SIMPLE_FULL_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_simple_split.h b/src/ballistica/graphics/mesh/mesh_indexed_simple_split.h new file mode 100644 index 00000000..d74f3095 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_simple_split.h @@ -0,0 +1,20 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SIMPLE_SPLIT_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SIMPLE_SPLIT_H_ + +#include "ballistica/graphics/mesh/mesh_indexed_static_dynamic.h" + +namespace ballistica { + +// a mesh with static indices and UVs and dynamic positions +class MeshIndexedSimpleSplit + : public MeshIndexedStaticDynamic { + using MeshIndexedStaticDynamic::MeshIndexedStaticDynamic; // c++11 magic! +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SIMPLE_SPLIT_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_smoke_full.h b/src/ballistica/graphics/mesh/mesh_indexed_smoke_full.h new file mode 100644 index 00000000..a4e4bd26 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_smoke_full.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SMOKE_FULL_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SMOKE_FULL_H_ + +#include "ballistica/graphics/mesh/mesh_indexed.h" + +namespace ballistica { + +// a mesh with all data provided together (either static or dynamic) +class MeshIndexedSmokeFull + : public MeshIndexed { + using MeshIndexed::MeshIndexed; // wheee c++11 magic +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_SMOKE_FULL_H_ diff --git a/src/ballistica/graphics/mesh/mesh_indexed_static_dynamic.h b/src/ballistica/graphics/mesh/mesh_indexed_static_dynamic.h new file mode 100644 index 00000000..a1aeff0a --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_indexed_static_dynamic.h @@ -0,0 +1,58 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_STATIC_DYNAMIC_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_STATIC_DYNAMIC_H_ + +#include "ballistica/graphics/mesh/mesh_indexed_base.h" + +namespace ballistica { + +// mesh with static indices, some static vertex data, +// and some dynamic vertex data +template +class MeshIndexedStaticDynamic : public MeshIndexedBase { + public: + MeshIndexedStaticDynamic() : MeshIndexedBase(T) {} + void SetStaticData(const Object::Ref>& data) { + assert(data->elements.size() > 0); + static_data_ = data; + static_data_->state = ++static_state_; + } + void SetDynamicData(const Object::Ref>& data) { + assert(data->elements.size() > 0); + dynamic_data_ = data; + dynamic_data_->state = ++dynamic_state_; + } + auto IsValid() const -> bool override { + if (!static_data_.exists() || static_data_->elements.empty() + || !dynamic_data_.exists() || dynamic_data_->elements.empty() + || !MeshIndexedBase::IsValid()) { + return false; + } + + // Static and dynamic data sizes should always match, right? + if (static_data_->elements.size() != dynamic_data_->elements.size()) { + BA_LOG_ONCE("ERROR: mesh static and dynamic data sizes do not match"); + return false; + } + + // Make sure our index size covers our element count. + return IndexSizeIsValid(static_data_->elements.size()); + } + auto static_data() const -> const Object::Ref>& { + return static_data_; + } + auto dynamic_data() const -> const Object::Ref>& { + return dynamic_data_; + } + + private: + Object::Ref> static_data_; + Object::Ref> dynamic_data_; + uint32_t static_state_{}; + uint32_t dynamic_state_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_INDEXED_STATIC_DYNAMIC_H_ diff --git a/src/ballistica/graphics/mesh/mesh_non_indexed.h b/src/ballistica/graphics/mesh/mesh_non_indexed.h new file mode 100644 index 00000000..e0509379 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_non_indexed.h @@ -0,0 +1,42 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_NON_INDEXED_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_NON_INDEXED_H_ + +#include "ballistica/graphics/mesh/mesh.h" + +namespace ballistica { + +// Mesh using non-indexed vertex data. Good for situations where vertices +// are never shared between primitives (such as drawing points/sprites/etc). +template +class MeshNonIndexed : public Mesh { + public: + explicit MeshNonIndexed(MeshDrawType drawType = MeshDrawType::kDynamic) + : Mesh(T, drawType), data_state_(0) {} + // NOLINTNEXTLINE + void SetData(const Object::Ref>& data) { + data_ = data; + data_->state = ++data_state_; + } + + // Call this if you have nothing to draw. + void SetEmpty() { data_.clear(); } + auto IsValid() const -> bool override { +#if BA_DEBUG_BUILD + // Make extra sure that we're actually valid in debug mode. + if (data_.exists()) { + assert(data_->elements.size() > 0); + } +#endif + return (data_.exists()); + } + + private: + Object::Ref> data_{}; + uint32_t data_state_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_NON_INDEXED_H_ diff --git a/src/ballistica/graphics/mesh/mesh_renderer_data.h b/src/ballistica/graphics/mesh/mesh_renderer_data.h new file mode 100644 index 00000000..67b1eba7 --- /dev/null +++ b/src/ballistica/graphics/mesh/mesh_renderer_data.h @@ -0,0 +1,15 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_MESH_RENDERER_DATA_H_ +#define BALLISTICA_GRAPHICS_MESH_MESH_RENDERER_DATA_H_ + +namespace ballistica { + +class MeshRendererData { + public: + virtual ~MeshRendererData() = default; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_MESH_RENDERER_DATA_H_ diff --git a/src/ballistica/graphics/mesh/sprite_mesh.h b/src/ballistica/graphics/mesh/sprite_mesh.h new file mode 100644 index 00000000..e07bc502 --- /dev/null +++ b/src/ballistica/graphics/mesh/sprite_mesh.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_SPRITE_MESH_H_ +#define BALLISTICA_GRAPHICS_MESH_SPRITE_MESH_H_ + +#include "ballistica/graphics/mesh/mesh_indexed.h" + +namespace ballistica { + +// an indexed sprite-mesh +class SpriteMesh : public MeshIndexed { + using MeshIndexed::MeshIndexed; // wheeee c++11 magic +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_SPRITE_MESH_H_ diff --git a/src/ballistica/graphics/mesh/text_mesh.cc b/src/ballistica/graphics/mesh/text_mesh.cc new file mode 100644 index 00000000..c68e8649 --- /dev/null +++ b/src/ballistica/graphics/mesh/text_mesh.cc @@ -0,0 +1,574 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/mesh/text_mesh.h" + +#include +#include +#include + +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/graphics/text/text_packer.h" + +namespace ballistica { + +TextMesh::TextMesh() : MeshIndexedDualTextureFull(MeshDrawType::kStatic) {} + +void TextMesh::SetText(const std::string& text_in, HAlign alignment_h, + VAlign alignment_v, bool big, uint32_t min_val, + uint32_t max_val, TextMeshEntryType entry_type, + TextPacker* packer) { + if (text_in == text_) { + // Covers corner case where we assign a new string to empty. + if (text_in.empty()) { + SetEmpty(); + } + return; + } + text_ = text_in; + + assert(Utils::IsValidUTF8(text_)); + + const char* txt = text_in.c_str(); + + // Quick-out for empty strings. + if (txt[0] == 0) { + SetEmpty(); + return; + } + + if (entry_type == TextMeshEntryType::kOSRendered) { + assert(packer != nullptr); + } + + // Start buffers big enough to handle the worst case + // (every char being a discrete letter). + int text_size = static_cast(text_in.size()); + assert(text_size > 0); + Object::Ref indices16; + Object::Ref indices32; + + // Go with 32 bit indices if there's any chance we'll have over 65535 pts; + // otherwise go with 16 bit. + // NOTE: disabling 32 bit indices for now; turns out they're + // not supported in OpenGL ES2 :-( + // It may be worth adding logic to split up meshes into multiple + // draw-calls. (or we can just wait until ES2 is dead). + if (explicit_bool(false) && 4 * text_size > 65535) { + indices32 = Object::New(6 * (text_size)); + } else { + indices16 = Object::New(6 * (text_size)); + } + auto vertices(Object::New>(4 * text_size)); + + uint16_t* index16 = indices16.exists() ? indices16->elements.data() : nullptr; + uint32_t* index32 = indices32.exists() ? indices32->elements.data() : nullptr; + + VertexDualTextureFull* v = &vertices->elements[0]; + uint32_t index_offset = 0; + float x = 0; + float x_offset, y_offset; + x_offset = x; + + float char_width; + float char_height; + float row_height; + float char_offset_h; + float char_offset_v; + + char_width = char_height = 32.0f; + row_height = kTextRowHeight; + char_offset_h = -3.0f; + char_offset_v = 7.0f; + uint32_t char_val; + float line_length; + + float l = 0; + float r = 0; + float b = 0; + float t = 0; + + float text_height; + + // Pre-calc the height of the text (if needed). + switch (alignment_v) { + case VAlign::kNone: + case VAlign::kTop: + text_height = 0; // Not used here. + break; + case VAlign::kCenter: + case VAlign::kBottom: { + int rows = 1; + for (const char* c = txt; *c != 0; c++) { + if (*c == '\n') rows++; + } + text_height = static_cast(rows) * row_height; + break; + } + default: + throw Exception(); + } + + switch (alignment_v) { + case VAlign::kNone: + y_offset = b + char_offset_v; + break; + case VAlign::kTop: + y_offset = b + char_offset_v + (t - b) - row_height; + break; + case VAlign::kCenter: + y_offset = + b + char_offset_v + ((t - b) / 2) + (text_height / 2) - row_height; + break; + case VAlign::kBottom: + y_offset = b + char_offset_v + text_height - row_height; + break; + default: + throw Exception(); + } + + const char* tc = txt; + bool first_char = true; + + std::vector os_span; + + while (*tc != 0) { + const char* tc_prev = tc; + + char_val = Utils::GetUTF8Value(tc); + + Utils::AdvanceUTF8(&tc); + + // Reset alignment on new lines. + if (first_char || char_val == '\n') { + // If we've been building an os-span, add it to the text-packer. + if (char_val == '\n' && !os_span.empty()) { + Rect r2; + float width; + std::string s = Utils::UTF8FromUnicode(os_span); + g_text_graphics->GetOSTextSpanBoundsAndWidth(s, &r2, &width); + if (packer) { + packer->AddSpan(s, x_offset, y_offset, r2); + } + os_span.clear(); + } + + switch (alignment_h) { + case HAlign::kLeft: + x_offset = l + char_offset_h; + break; + case HAlign::kCenter: + case HAlign::kRight: { + // For some alignments we need to pre-calc the length of the line. + line_length = 0; + const char* c; + + // If this was the first char, include it in this line tally. + // if it was a newline, don't. + if (first_char) { + c = tc_prev; + } else { + c = tc; + } + + // We have the OS render some chars, broken into single-line spans. + std::vector os_span_l; + + while (true) { + uint32_t val; + if (*c == 0) { // NOLINT(bugprone-branch-clone) + break; + } else if (*c == '\n') { + break; + } else { + val = Utils::GetUTF8Value(c); + Utils::AdvanceUTF8(&c); + + // Special case: if we're already doing an OS-span, tack certain + // chars onto it instead of switching back to glyph mode. + // (to reduce the number of times we switch back and forth) + if (TextGraphics::IsOSDrawableAscii(val) && !os_span_l.empty()) { + os_span_l.push_back(val); + } else if (TextGraphics::Glyph* g = + g_text_graphics->GetGlyph(val, big)) { + // Flipping back to glyphs; if we had been building an os_span, + // tally it. + if (!os_span_l.empty()) { + std::string s = Utils::UTF8FromUnicode(os_span_l); + line_length += g_text_graphics->GetOSTextSpanWidth(s); + os_span_l.clear(); + } + line_length += char_width * g->advance; + } else { + // Not a glyph char: add it to our current span to handle + // through the OS. + + if (g_buildconfig.enable_os_font_rendering()) { + os_span_l.push_back(val); + } + } + } + } + + // Add final os_span if there is one. + if (!os_span_l.empty()) { + std::string s = Utils::UTF8FromUnicode(os_span_l); + line_length += g_text_graphics->GetOSTextSpanWidth(s); + os_span_l.clear(); + } + if (alignment_h == HAlign::kCenter) { + x_offset = l + char_offset_h + ((r - l) / 2) - (line_length / 2); + } else { + x_offset = l + char_offset_h + (r - l) - line_length; + } + break; + } + default: + throw Exception(); + } + first_char = false; + } + + switch (char_val) { // NOLINT + case '\n': + y_offset -= row_height; + break; + + default: { + bool draw = true; + if (char_val < min_val || char_val > max_val) draw = false; + + // Only draw the private-use range when doing our extras sheets. + // (technically OS might be able to render these but don't allow that) + if (entry_type != TextMeshEntryType::kExtras + && (char_val >= 0xE000 && char_val <= 0xF8FF)) { + draw = false; + } + + // Special case: if we're already doing an OS-span, tack certain + // chars onto it instead of switching back to glyph mode. + // (to reduce the number of times we switch back and forth) + if (TextGraphics::IsOSDrawableAscii(char_val) && !os_span.empty()) { + os_span.push_back(char_val); + } else if (TextGraphics::Glyph* glyph = + g_text_graphics->GetGlyph(char_val, big)) { + // If we had been building up an OS-text span, + // commit it since we're flipping to glyphs now. + if (!os_span.empty()) { + Rect r2; + float width; + std::string s = Utils::UTF8FromUnicode(os_span); + g_text_graphics->GetOSTextSpanBoundsAndWidth(s, &r2, &width); + if (packer) packer->AddSpan(s, x_offset, y_offset, r2); + x_offset += width; + os_span.clear(); + } + + // Draw this glyph. + if (draw) { + float v_min = glyph->tex_min_y; + float v_max = glyph->tex_max_y; + float u_min = glyph->tex_min_x; + float u_max = glyph->tex_max_x; + auto v_max_i = static_cast(65535.0f * v_max); + auto v_min_i = static_cast(65535.0f * v_min); + auto u_max_i = static_cast(65535.0f * u_max); + auto u_min_i = static_cast(65535.0f * u_min); + + if (index16) { + *index16++ = static_cast_check_fit(index_offset + 0); + *index16++ = static_cast_check_fit(index_offset + 1); + *index16++ = static_cast_check_fit(index_offset + 2); + *index16++ = static_cast_check_fit(index_offset + 1); + *index16++ = static_cast_check_fit(index_offset + 3); + *index16++ = static_cast_check_fit(index_offset + 2); + } + if (index32) { + *index32++ = index_offset + 0; + *index32++ = index_offset + 1; + *index32++ = index_offset + 2; + *index32++ = index_offset + 1; + *index32++ = index_offset + 3; + *index32++ = index_offset + 2; + } + + // Bot left. + v->position[0] = x_offset + char_width * glyph->pen_offset_x; + v->position[1] = y_offset + char_height * glyph->pen_offset_y; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_min_i); + v->uv[1] = static_cast_check_fit(v_min_i); + v->uv2[0] = 0; + v->uv2[1] = 65535; + v++; + + // Bot right. + v->position[0] = + x_offset + char_width * (glyph->pen_offset_x + glyph->x_size); + v->position[1] = y_offset + char_height * glyph->pen_offset_y; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_max_i); + v->uv[1] = static_cast_check_fit(v_min_i); + v->uv2[0] = 65535; + v->uv2[1] = 65535; + v++; + + // Top left. + v->position[0] = x_offset + char_width * (glyph->pen_offset_x); + v->position[1] = + y_offset + char_height * (glyph->pen_offset_y + glyph->y_size); + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_min_i); + v->uv[1] = static_cast_check_fit(v_max_i); + v->uv2[0] = 0; + v->uv2[1] = 0; + v++; + + // Top right. + v->position[0] = + x_offset + char_width * (glyph->pen_offset_x + glyph->x_size); + v->position[1] = + y_offset + char_height * (glyph->pen_offset_y + glyph->y_size); + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_max_i); + v->uv[1] = static_cast_check_fit(v_max_i); + v->uv2[0] = 65535; + v->uv2[1] = 0; + v++; + index_offset += 4; + } + x_offset += char_width * glyph->advance; + } else { + // Add to the single-line span we'll ask the OS to render. + if (g_buildconfig.enable_os_font_rendering()) { + os_span.push_back(char_val); + } + } + break; + } + } + } + + // Commit any final OS-text span (can skip this if we're not + // the one drawing OS text). + if ((!os_span.empty()) && packer) { + Rect r2; + float width; + std::string s = Utils::UTF8FromUnicode(os_span); + g_text_graphics->GetOSTextSpanBoundsAndWidth(s, &r2, &width); + packer->AddSpan(s, x_offset, y_offset, r2); + os_span.clear(); + } + + // Now if we've been building a text-packer, + // compile it and add its final spans to our mesh. + if (packer) { + std::vector spans; + packer->compile(); + + // DEBUGGING - add a single quad above our first + // span showing the entire texture for debugging purposes + if (explicit_bool(false) && !packer->spans().empty()) { + int v_max_i = static_cast(65535 * 1.0f); + int v_min_i = static_cast(65535 * 0.0f); + int u_max_i = static_cast(65535 * 1.0f); + int u_min_i = static_cast(65535 * 0.0f); + + if (index16) { + *index16++ = static_cast_check_fit(index_offset + 0); + *index16++ = static_cast_check_fit(index_offset + 1); + *index16++ = static_cast_check_fit(index_offset + 2); + *index16++ = static_cast_check_fit(index_offset + 1); + *index16++ = static_cast_check_fit(index_offset + 3); + *index16++ = static_cast_check_fit(index_offset + 2); + } + if (index32) { + *index32++ = index_offset + 0; + *index32++ = index_offset + 1; + *index32++ = index_offset + 2; + *index32++ = index_offset + 1; + *index32++ = index_offset + 3; + *index32++ = index_offset + 2; + } + + x_offset = + packer->spans().front().bounds.l + packer->spans().front().x - 80.0f; + y_offset = + packer->spans().front().bounds.t + packer->spans().front().y + 90.0f; + + float width = static_cast(packer->texture_width()) * 0.7f; + float height = static_cast(packer->texture_height()) * 0.7f; + + // Bottom left. + v->position[0] = x_offset; + v->position[1] = y_offset; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_min_i); + v->uv[1] = static_cast_check_fit(v_max_i); + v->uv2[0] = 0; + v->uv2[1] = 65535; + v++; + + // Bottom right. + v->position[0] = x_offset + width; + v->position[1] = y_offset; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_max_i); + v->uv[1] = static_cast_check_fit(v_max_i); + v->uv2[0] = 65535; + v->uv2[1] = 65535; + v++; + + // Top left. + v->position[0] = x_offset; + v->position[1] = y_offset + height; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_min_i); + v->uv[1] = static_cast_check_fit(v_min_i); + v->uv2[0] = 0; + v->uv2[1] = 0; + v++; + + // Top right. + v->position[0] = x_offset + width; + v->position[1] = y_offset + height; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_max_i); + v->uv[1] = static_cast_check_fit(v_min_i); + v->uv2[0] = 65535; + v->uv2[1] = 0; + v++; + + index_offset += 4; + } + + for (auto&& i : packer->spans()) { + int v_max_i = + std::max(0, std::min(65535, static_cast(65535 * i.v_max))); + int v_min_i = + std::max(0, std::min(65535, static_cast(65535 * i.v_min))); + int u_max_i = + std::max(0, std::min(65535, static_cast(65535 * i.u_max))); + int u_min_i = + std::max(0, std::min(65535, static_cast(65535 * i.u_min))); + + if (index16) { + *index16++ = static_cast_check_fit(index_offset + 0); + *index16++ = static_cast_check_fit(index_offset + 1); + *index16++ = static_cast_check_fit(index_offset + 2); + *index16++ = static_cast_check_fit(index_offset + 1); + *index16++ = static_cast_check_fit(index_offset + 3); + *index16++ = static_cast_check_fit(index_offset + 2); + } + if (index32) { + *index32++ = index_offset + 0; + *index32++ = index_offset + 1; + *index32++ = index_offset + 2; + *index32++ = index_offset + 1; + *index32++ = index_offset + 3; + *index32++ = index_offset + 2; + } + + // Fudge-factor for lining OS-spans up with our stuff. + x_offset = i.x + 3.0f; + y_offset = i.y; + + // Bot left. + v->position[0] = x_offset + i.draw_bounds.l; + v->position[1] = y_offset + i.draw_bounds.b; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_min_i); + v->uv[1] = static_cast_check_fit(v_max_i); + v->uv2[0] = 0; + v->uv2[1] = 65535; + v++; + + // Bot right. + v->position[0] = x_offset + i.draw_bounds.r; + v->position[1] = y_offset + i.draw_bounds.b; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_max_i); + v->uv[1] = static_cast_check_fit(v_max_i); + v->uv2[0] = 65535; + v->uv2[1] = 65535; + v++; + + // Top left. + v->position[0] = x_offset + i.draw_bounds.l; + v->position[1] = y_offset + i.draw_bounds.t; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_min_i); + v->uv[1] = static_cast_check_fit(v_min_i); + v->uv2[0] = 0; + v->uv2[1] = 0; + v++; + + // Top right. + v->position[0] = x_offset + i.draw_bounds.r; + v->position[1] = y_offset + i.draw_bounds.t; + v->position[2] = 0; + v->uv[0] = static_cast_check_fit(u_max_i); + v->uv[1] = static_cast_check_fit(v_min_i); + v->uv2[0] = 65535; + v->uv2[1] = 0; + v++; + + index_offset += 4; + } + } + + // Make sure we didn't overshoot the end of our buffer. + if (index16) { + assert((index16 - indices16->elements.data()) + <= static_cast(indices16->elements.size())); + } + if (index32) { + assert((index32 - indices32->elements.data()) + <= static_cast(indices32->elements.size())); + } + assert((v - (&(vertices->elements[0]))) + <= static_cast(vertices->elements.size())); + + // clamp to what we actually used.. + if (index16) { + indices16->elements.resize(index16 - (indices16->elements.data())); + } + if (index32) { + indices32->elements.resize(index32 - (indices32->elements.data())); + } + vertices->elements.resize(v - (&(vertices->elements[0]))); + + // Either set data or abort if empty. + if (index16 && !indices16->elements.empty()) { + SetIndexData(indices16); + SetData(vertices); + } else if (index32 && !indices32->elements.empty()) { + // In a lot of cases we actually wind up with fewer than 65535 pts. + // (we theoretically could have needed more which is why we went 32bit). + // ...lets go ahead and downsize to 16 bit in this case to save a wee bit + // of gpu memory. + if (vertices->elements.size() < 65535) { + int size = static_cast(indices32->elements.size()); + indices16 = Object::NewDeferred(size); + uint16_t* i16 = indices16->elements.data(); + uint32_t* i32 = indices32->elements.data(); + for (int i = 0; i < size; i++) { + *i16++ = static_cast_check_fit(*i32++); + } + assert((i32 - indices32->elements.data()) + <= static_cast(indices32->elements.size())); + assert((i16 - indices16->elements.data()) + <= static_cast(indices16->elements.size())); + SetIndexData(indices16); + } else { + // we *actually* need 32 bit indices... + SetIndexData(indices32); + } + SetData(vertices); + } else { + SetEmpty(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/mesh/text_mesh.h b/src/ballistica/graphics/mesh/text_mesh.h new file mode 100644 index 00000000..ca73c141 --- /dev/null +++ b/src/ballistica/graphics/mesh/text_mesh.h @@ -0,0 +1,32 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_MESH_TEXT_MESH_H_ +#define BALLISTICA_GRAPHICS_MESH_TEXT_MESH_H_ + +#include + +#include "ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h" + +namespace ballistica { + +// a mesh set up to draw text +// in general you should not use this directly; use TextGroup below, which will +// automatically handle switching meshes/textures in order to support the full +// unicode range +class TextMesh : public MeshIndexedDualTextureFull { + public: + enum class HAlign { kLeft, kCenter, kRight }; + enum class VAlign { kNone, kBottom, kCenter, kTop }; + TextMesh(); + void SetText(const std::string& text, HAlign alignment_h, VAlign alignment_v, + bool big, uint32_t min_val, uint32_t max_val, + TextMeshEntryType entry_type, TextPacker* packer); + auto text() const -> const std::string& { return text_; } + + private: + std::string text_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_MESH_TEXT_MESH_H_ diff --git a/src/ballistica/graphics/net_graph.cc b/src/ballistica/graphics/net_graph.cc new file mode 100644 index 00000000..86b4f427 --- /dev/null +++ b/src/ballistica/graphics/net_graph.cc @@ -0,0 +1,153 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/net_graph.h" + +#include +#include + +#include "ballistica/graphics/component/simple_component.h" + +namespace ballistica { + +class NetGraph::Impl { + public: + std::list> samples; + double duration = 2000.0; + double v_max_smoothed = 1.0; + ImageMesh bg_mesh; + MeshIndexedSimpleFull value_mesh; + TextGroup max_vel_text; +}; + +NetGraph::NetGraph() : impl_(new NetGraph::Impl()) {} + +NetGraph::~NetGraph() = default; + +void NetGraph::AddSample(double time, double value) { + impl_->samples.emplace_back(time, value); + double cutoffTime = time - impl_->duration; + + // Go ahead and prune old ones here so we don't grow out of control. + std::list>::iterator i; + for (i = impl_->samples.begin(); i != impl_->samples.end();) { + if (i->first < cutoffTime) { + auto i_next = i; + ++i_next; + impl_->samples.erase(i); + i = i_next; + } else { + break; + } + } +} + +void NetGraph::Draw(RenderPass* pass, double time, double x, double y, double w, + double h) { + impl_->bg_mesh.SetPositionAndSize( + static_cast(x), static_cast(y), 0.0f, static_cast(w), + static_cast(h)); + + int num_samples = static_cast(impl_->samples.size()); + + // Draw values (provided we have at least 2 samples) + bool draw_values = (num_samples >= 2); + if (draw_values) { + double t_left = time - impl_->duration; + double t_right = time; + double t_width = t_right - t_left; + double v_bottom = 0.0f; + + // Find the max y value we have and smoothly transition our bounds towards + // that. + double v_max = 0.0; + for (auto&& s : impl_->samples) { + if (s.second > v_max) { + v_max = s.second; + } + } + double smoothing = 0.95; + impl_->v_max_smoothed = + smoothing * impl_->v_max_smoothed + (1.0 - smoothing) * v_max * 1.1; + + double v_top = impl_->v_max_smoothed; + double v_height = v_top - v_bottom; + + // We need 2 verts per sample. + auto vertex_buffer( + Object::New>(num_samples * 2)); + VertexSimpleFull* v = vertex_buffer->elements.data(); + for (auto&& s : impl_->samples) { + double t = s.first; + double val = s.second; + double vx = x + w * ((t - t_left) / t_width); + double vy = y + h * ((val - v_bottom) / v_height); + v->position[0] = static_cast(vx); + v->position[1] = static_cast(y); + v->position[2] = 0.0f; + v->uv[0] = v->uv[1] = 0; + v++; + v->position[0] = static_cast(vx); + v->position[1] = static_cast(vy); + v->position[2] = 0.0f; + v->uv[0] = v->uv[1] = 0; + v++; + } + + // We need 2 tris per sample (minus the last). + auto index_buffer(Object::New((num_samples - 1) * 6)); + uint16_t* i = index_buffer->elements.data(); + auto s = impl_->samples.begin(); + int v_count = 0; + while (true) { + auto s_next = s; + ++s_next; + if (s_next == impl_->samples.end()) { + break; + } else { + *i++ = static_cast_check_fit(v_count); + *i++ = static_cast_check_fit(v_count + 2); + *i++ = static_cast_check_fit(v_count + 1); + *i++ = static_cast_check_fit(v_count + 2); + *i++ = static_cast_check_fit(v_count + 3); + *i++ = static_cast_check_fit(v_count + 1); + } + v_count += 2; + s = s_next; + } + impl_->value_mesh.SetIndexData(index_buffer); + impl_->value_mesh.SetData(vertex_buffer); + } + + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(0.35f, 0.0f, 0.0f, 0.9f); + c.DrawMesh(&impl_->bg_mesh); + c.SetColor(0.0f, 1.0f, 0.0f, 0.85f); + if (draw_values) { + c.DrawMesh(&impl_->value_mesh); + } + c.Submit(); + + char val_str[32]; + snprintf(val_str, sizeof(val_str), "%.2f", impl_->v_max_smoothed); + impl_->max_vel_text.SetText(val_str, TextMesh::HAlign::kLeft, + TextMesh::VAlign::kTop); + + SimpleComponent c2(pass); + c2.SetTransparent(true); + c2.SetColor(1, 0, 0, 1); + c2.PushTransform(); + c2.Translate(static_cast(x), static_cast(y + h)); + float scale = static_cast(h) * 0.006f; + c2.Scale(scale, scale); + int text_elem_count = impl_->max_vel_text.GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c2.SetTexture(impl_->max_vel_text.GetElementTexture(e)); + c2.SetFlatness(1.0f); + c2.DrawMesh(impl_->max_vel_text.GetElementMesh(e)); + } + c2.PopTransform(); + c2.Submit(); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/net_graph.h b/src/ballistica/graphics/net_graph.h new file mode 100644 index 00000000..40b72227 --- /dev/null +++ b/src/ballistica/graphics/net_graph.h @@ -0,0 +1,27 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_NET_GRAPH_H_ +#define BALLISTICA_GRAPHICS_NET_GRAPH_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +class NetGraph : public Object { + public: + NetGraph(); + ~NetGraph() override; + void AddSample(double time, double value); + void Draw(RenderPass* pass, double time, double x, double y, double w, + double h); + + private: + class Impl; + std::unique_ptr impl_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_NET_GRAPH_H_ diff --git a/src/ballistica/graphics/render_command_buffer.h b/src/ballistica/graphics/render_command_buffer.h new file mode 100644 index 00000000..27f8af98 --- /dev/null +++ b/src/ballistica/graphics/render_command_buffer.h @@ -0,0 +1,576 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_RENDER_COMMAND_BUFFER_H_ +#define BALLISTICA_GRAPHICS_RENDER_COMMAND_BUFFER_H_ + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/graphics/frame_def.h" +#include "ballistica/graphics/mesh/mesh.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" + +namespace ballistica { + +class RenderCommandBuffer { + public: + // IMPORTANT: make sure to update has_draw_commands with any new + // ones added here. + enum class Command { + kEnd, + kShader, + kDrawModel, + kDrawModelInstanced, + kDrawMesh, + kDrawScreenQuad, + kScissorPush, + kScissorPop, + kPushTransform, + kPopTransform, + kTranslate2, + kTranslate3, + kCursorTranslate, + kScaleUniform, + kTranslateToProjectedPoint, +#if BA_VR_BUILD + kTransformToRightHand, + kTransformToLeftHand, + kTransformToHead, +#endif + kScale2, + kScale3, + kRotate, + kMultMatrix, + kFlipCullFace, + kSimpleComponentInlineColor, + kObjectComponentInlineColor, + kObjectComponentInlineAddColor, + kBeginDebugDrawTriangles, + kBeginDebugDrawLines, + kEndDebugDraw, + kDebugDrawVertex3 + }; + + RenderCommandBuffer() = default; + void PutCommand(Command c) { + assert(!finalized_); + commands_.push_back(c); + } + + void PutFloat(float val) { + assert(!finalized_); + fvals_.push_back(val); + } + + void PutFloats(float f1, float f2) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 2); + float* f = &(fvals_[s]); + *f++ = f1; + *f = f2; + } + + void PutFloats(float f1, float f2, float f3) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 3); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f = f3; + } + + void PutFloats(float f1, float f2, float f3, float f4) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 4); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f = f4; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 5); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f = f5; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 6); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f = f6; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6, + float f7) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 7); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f++ = f6; + *f = f7; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6, + float f7, float f8) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 8); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f++ = f6; + *f++ = f7; + *f = f8; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6, + float f7, float f8, float f9) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 9); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f++ = f6; + *f++ = f7; + *f++ = f8; + *f = f9; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6, + float f7, float f8, float f9, float f10) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 10); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f++ = f6; + *f++ = f7; + *f++ = f8; + *f++ = f9; + *f = f10; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6, + float f7, float f8, float f9, float f10, float f11, + float f12) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 12); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f++ = f6; + *f++ = f7; + *f++ = f8; + *f++ = f9; + *f++ = f10; + *f++ = f11; + *f = f12; + } + + void PutFloats(float f1, float f2, float f3, float f4, float f5, float f6, + float f7, float f8, float f9, float f10, float f11, float f12, + float f13, float f14, float f15) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 15); + float* f = &(fvals_[s]); + *f++ = f1; + *f++ = f2; + *f++ = f3; + *f++ = f4; + *f++ = f5; + *f++ = f6; + *f++ = f7; + *f++ = f8; + *f++ = f9; + *f++ = f10; + *f++ = f11; + *f++ = f12; + *f++ = f13; + *f++ = f14; + *f = f15; + } + + void PutFloatArray16(const float* f_in) { + assert(!finalized_); + int s = static_cast(fvals_.size()); + fvals_.resize(fvals_.size() + 16); + float* f = &(fvals_[s]); + memcpy(f, f_in, sizeof(float) * 16); + } + + void PutMatrices(const std::vector& mats) { + assert(!finalized_); + static_assert(sizeof(Matrix44f[2]) == sizeof(float[16][2])); + ivals_.push_back(static_cast(mats.size())); + int s = static_cast(fvals_.size()); + int f_count = static_cast(16 * mats.size()); + fvals_.resize(fvals_.size() + f_count); + float* f = &(fvals_[s]); + const float* f_in = mats[0].m; + memcpy(f, f_in, sizeof(float) * f_count); + } + + void PutInt(int val) { + assert(!finalized_); + ivals_.push_back(val); + } + + void PutModel(ModelData* model) { + assert(frame_def_); + assert(!finalized_); + frame_def_->AddComponent(Object::Ref(model)); + models_.push_back(model); + } + + void PutTexture(TextureData* texture) { + assert(frame_def_); + assert(!finalized_); + frame_def_->AddComponent(Object::Ref(texture)); + textures_.push_back(texture); + } + + void PutTexture(const Object::Ref& texture) { + assert(texture.exists()); + PutTexture(texture.get()); + } + + void PutCubeMapTexture(TextureData* texture) { + assert(frame_def_); + assert(!finalized_); + frame_def_->AddComponent(Object::Ref(texture)); + textures_.push_back(texture); + } + + void PutMeshData(MeshData* mesh_data) { + assert(!finalized_); + mesh_datas_.push_back(mesh_data); + } + + // Return next item. + auto GetCommand() -> Command { + assert(finalized_); + assert(commands_index_ <= commands_.size()); + return (commands_index_ == commands_.size()) ? Command::kEnd + : commands_[commands_index_++]; + } + + auto GetInt() -> int { + assert(finalized_); + assert(ivals_index_ < ivals_.size()); + return ivals_[ivals_index_++]; + } + + auto GetFloat() -> float { + assert(finalized_); + assert(fvals_index_ < fvals_.size()); + return fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2) { + assert(finalized_); + assert(fvals_index_ + 2 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3) { + assert(finalized_); + assert(fvals_index_ + 3 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4) { + assert(finalized_); + assert(fvals_index_ + 4 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5) { + assert(finalized_); + assert(fvals_index_ + 5 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6) { + assert(finalized_); + assert(fvals_index_ + 6 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6, float* f7) { + assert(finalized_); + assert(fvals_index_ + 7 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + *f7 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6, float* f7, float* f8) { + assert(finalized_); + assert(fvals_index_ + 8 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + *f7 = fvals_[fvals_index_++]; + *f8 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6, float* f7, float* f8, float* f9) { + assert(finalized_); + assert(fvals_index_ + 9 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + *f7 = fvals_[fvals_index_++]; + *f8 = fvals_[fvals_index_++]; + *f9 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6, float* f7, float* f8, float* f9, float* f10) { + assert(finalized_); + assert(fvals_index_ + 10 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + *f7 = fvals_[fvals_index_++]; + *f8 = fvals_[fvals_index_++]; + *f9 = fvals_[fvals_index_++]; + *f10 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6, float* f7, float* f8, float* f9, float* f10, + float* f11, float* f12) { + assert(finalized_); + assert(fvals_index_ + 12 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + *f7 = fvals_[fvals_index_++]; + *f8 = fvals_[fvals_index_++]; + *f9 = fvals_[fvals_index_++]; + *f10 = fvals_[fvals_index_++]; + *f11 = fvals_[fvals_index_++]; + *f12 = fvals_[fvals_index_++]; + } + + void GetFloats(float* f1, float* f2, float* f3, float* f4, float* f5, + float* f6, float* f7, float* f8, float* f9, float* f10, + float* f11, float* f12, float* f13, float* f14, float* f15) { + assert(finalized_); + assert(fvals_index_ + 15 <= fvals_.size()); + *f1 = fvals_[fvals_index_++]; + *f2 = fvals_[fvals_index_++]; + *f3 = fvals_[fvals_index_++]; + *f4 = fvals_[fvals_index_++]; + *f5 = fvals_[fvals_index_++]; + *f6 = fvals_[fvals_index_++]; + *f7 = fvals_[fvals_index_++]; + *f8 = fvals_[fvals_index_++]; + *f9 = fvals_[fvals_index_++]; + *f10 = fvals_[fvals_index_++]; + *f11 = fvals_[fvals_index_++]; + *f12 = fvals_[fvals_index_++]; + *f13 = fvals_[fvals_index_++]; + *f14 = fvals_[fvals_index_++]; + *f15 = fvals_[fvals_index_++]; + } + + auto GetMatrix() -> Matrix44f* { + assert(finalized_); + assert(fvals_index_ + 16 <= fvals_.size()); + static_assert(sizeof(Matrix44f) == sizeof(float[16])); + auto* m = reinterpret_cast(&fvals_[fvals_index_]); + fvals_index_ += 16; + return m; + } + + auto GetMatrices(int* count) -> Matrix44f* { + assert(finalized_); + assert(ivals_index_ < ivals_.size()); + *count = ivals_[ivals_index_++]; + int f_count = 16 * (*count); + assert(fvals_index_ + f_count <= fvals_.size()); + static_assert(sizeof(Matrix44f[2]) == sizeof(float[16][2])); + auto* m = reinterpret_cast(&fvals_[fvals_index_]); + fvals_index_ += f_count; + return m; + } + + auto GetModel() -> const ModelData* { + assert(finalized_); + assert(models_index_ < models_.size()); + return models_[models_index_++]; + } + + template + auto GetMeshRendererData() -> T* { + assert(finalized_); + assert(mesh_datas_index_ < mesh_datas_.size()); + T* m; + m = static_cast(mesh_datas_[mesh_datas_index_]->renderer_data()); + assert(m); + assert( + m == dynamic_cast(mesh_datas_[mesh_datas_index_]->renderer_data())); + mesh_datas_index_++; + return m; + } + + auto GetTexture() -> const TextureData* { + assert(finalized_); + assert(textures_index_ < textures_.size()); + return textures_[textures_index_++]; + } + + void Reset() { + commands_.resize(0); + fvals_.resize(0); + ivals_.resize(0); + models_.resize(0); + textures_.resize(0); + mesh_datas_.resize(0); + finalized_ = false; + } + + // Call once done writing to buffer. + void Finalize() { + assert(!finalized_); + finalized_ = true; + } + + // Set up iterators to read back data. + void ReadBegin() { + assert(finalized_); + commands_index_ = 0; + fvals_index_ = 0; + ivals_index_ = 0; + models_index_ = 0; + textures_index_ = 0; + mesh_datas_index_ = 0; + } + auto has_draw_commands() const -> bool { + for (auto& command : commands_) { + switch (command) { + case Command::kDrawModel: + case Command::kDrawModelInstanced: + case Command::kDrawMesh: + case Command::kDrawScreenQuad: + return true; + default: + break; + } + } + return false; + } + + // Sanity check: Makes sure all buffer iterators are at their end. + auto IsEmpty() -> bool { + return ( + (commands_index_ == commands_.size()) && (fvals_index_ == fvals_.size()) + && (ivals_index_ == ivals_.size()) && (models_index_ == models_.size()) + && (textures_index_ == textures_.size()) + && (mesh_datas_index_ == mesh_datas_.size())); + } + + auto frame_def() const -> FrameDef* { + assert(frame_def_); + return frame_def_; + } + + void set_frame_def(FrameDef* f) { frame_def_ = f; } + + private: + std::vector commands_; + std::vector fvals_; + std::vector ivals_; + std::vector models_{}; + std::vector textures_{}; + std::vector mesh_datas_{}; + unsigned int commands_index_{}; + unsigned int fvals_index_{}; + unsigned int ivals_index_{}; + unsigned int models_index_{}; + unsigned int textures_index_{}; + unsigned int mesh_datas_index_{}; + bool finalized_{}; + FrameDef* frame_def_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_RENDER_COMMAND_BUFFER_H_ diff --git a/src/ballistica/graphics/render_pass.cc b/src/ballistica/graphics/render_pass.cc new file mode 100644 index 00000000..b5ace645 --- /dev/null +++ b/src/ballistica/graphics/render_pass.cc @@ -0,0 +1,507 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/render_pass.h" + +#include +#include + +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" + +// Turn this off to not draw any transparent stuff. +#define DRAW_TRANSPARENT 1 + +namespace ballistica { + +const float kCamNearClip = 4.0f; +const float kCamFarClip = 1000.0f; + +RenderPass::RenderPass(RenderPass::Type type_in, FrameDef* frame_def_in) + : type_(type_in), frame_def_(frame_def_in) { + // Create/init our command buffers. + if (UsesWorldLists()) { + for (auto& command : commands_) { + command = std::make_unique(); + + // FIXME: Could just pass in constructor? + command->set_frame_def(frame_def_); + } + } else { + commands_flat_transparent_ = std::make_unique(); + commands_flat_transparent_->set_frame_def(frame_def_); + commands_flat_ = std::make_unique(); + + // FIXME: Could just pass in constructor? + commands_flat_->set_frame_def(frame_def_); + } +} + +RenderPass::~RenderPass() = default; + +void RenderPass::Render(RenderTarget* render_target, bool transparent) { + assert(InGraphicsThread()); + + if (explicit_bool(!DRAW_TRANSPARENT) && transparent) { + return; + } +#undef DRAW_TRANSPRENT + + Renderer* renderer = g_graphics_server->renderer(); + + // Set up camera & depth. + switch (type()) { + case Type::kBeautyPass: { + g_graphics_server->SetCamera(cam_pos_, cam_target_, cam_up_); + // If this changes, make sure to change + // it before _drawCameraBuffer() too. + + // FIXME: + // If we're drawing our cam into its own buffer we could technically + // use its full depth range ...otherwise we need to share with the + // other onscreen elements (but maybe its good to use the limited + // range regardless to make sure we can) + renderer->SetDepthRange(kBackingDepth3, kBackingDepth4); + SetFrustum(cam_near_clip_, cam_far_clip_); + + tex_project_matrix_ = g_graphics_server->GetModelViewProjectionMatrix(); + model_view_matrix_ = g_graphics_server->model_view_matrix(); + model_view_projection_matrix_ = + g_graphics_server->GetModelViewProjectionMatrix(); + + // Store our matrix to get things in screen space. + tex_project_matrix_ *= Matrix44fScale(0.5f); + tex_project_matrix_ *= Matrix44fTranslate(0.5f, 0.5f, 0); + break; + } + case Type::kOverlay3DPass: { + g_graphics_server->SetCamera(cam_pos_, cam_target_, cam_up_); + + // If we drew the world directly to the screen we need to use a depth + // range that lies fully in front of that range so we don't get obscured + // by any of the world. + + // However if we drew the world to an offscreen buffer this isn't a + // problem; nothing exists in that range. In that case lets draw to the + // same range so we can do easy depth comparisons to the offscreen world's + // depth (for overlay fog, blurs, etc) + + // Use same region as world. + if (renderer->has_camera_render_target()) { + // Use beauty-pass depth region + renderer->SetDepthRange(kBackingDepth3, kBackingDepth4); + } else { + // Use region in front of world + renderer->SetDepthRange(kBackingDepth2, kBackingDepth3); + } + SetFrustum(cam_near_clip_, cam_far_clip_); + break; + } + case Type::kVRCoverPass: { + g_graphics_server->SetCamera(cam_pos_, cam_target_, cam_up_); + + // We use the front depth range where the overlays would + // live in the non-vr path. + renderer->SetDepthRange(kBackingDepth1, kBackingDepth2); + SetFrustum(cam_near_clip_, cam_far_clip_); + break; + } + case Type::kBlitPass: { + g_graphics_server->SetCamera(cam_pos_, cam_target_, cam_up_); + + // We render into a little sliver of the depth buffer in the + // back just in front of the backing blit. + assert(renderer->has_camera_render_target()); + renderer->SetDepthRange(kBackingDepth4, kBackingDepth5); + SetFrustum(cam_near_clip_, cam_far_clip_); + break; + } + case Type::kBeautyPassBG: { + g_graphics_server->SetCamera(cam_pos_, cam_target_, cam_up_); + renderer->SetDepthRange(kBackingDepth3, kBackingDepth4); + SetFrustum(cam_near_clip_, cam_far_clip_); + break; + } + case Type::kOverlayPass: + case Type::kOverlayFrontPass: + case Type::kOverlayFixedPass: + case Type::kOverlayFlatPass: { + // In vr mode we draw the flat-overlay into its own buffer so can use + // the full depth range (shouldn't matter but why not?...) shouldn't. + if (IsVRMode()) { + // In vr mode, our overlay-flat pass is ortho-projected + // while our regular overlay is just rendered in world space using + // the vr-overlay matrix. + if (type() == Type::kOverlayFlatPass) { + g_graphics_server->ModelViewReset(); + renderer->SetDepthRange(0, 1); // we can use full depth range!! + float amt = 0.5f * kVRBorder; + float w = virtual_width(); + float h = virtual_height(); + g_graphics_server->SetOrthoProjection( + -amt * w, (1.0f + amt) * w, -amt * h, (1.0f + amt) * h, -1, 1); + } else { + g_graphics_server->SetCamera(cam_pos_, cam_target_, cam_up_); + // We set the same depth ranges as the overlay-3d pass since + // we're essentially doing the same thing. See explanation in the + // overlay-3d case above the one difference is that we split the + // range between our fixed overlay and our regular overlay passes + // (we want fixed-overlay stuff on bottom). + if (renderer->has_camera_render_target()) { + if (type() == Type::kOverlayFrontPass) { + renderer->SetDepthRange(kBackingDepth3, kBackingDepth3B); + } else if (type() == Type::kOverlayPass) { + renderer->SetDepthRange(kBackingDepth3B, kBackingDepth3C); + } else { + renderer->SetDepthRange(kBackingDepth3C, kBackingDepth4); + } + } else { + if (type() == Type::kOverlayFrontPass) { + renderer->SetDepthRange(kBackingDepth2, kBackingDepth2B); + } else if (type() == Type::kOverlayPass) { + renderer->SetDepthRange(kBackingDepth2B, kBackingDepth2C); + } else { + renderer->SetDepthRange(kBackingDepth2C, kBackingDepth3); + } + } + SetFrustum(cam_near_clip_, cam_far_clip_); + + // Now move to wherever our 2d plane in space is to start with. + if (type() == Type::kOverlayPass + || type() == Type::kOverlayFrontPass) { + g_graphics_server->MultMatrix( + frame_def()->vr_overlay_screen_matrix()); + } else { + assert(type() == Type::kOverlayFixedPass); + g_graphics_server->MultMatrix( + frame_def()->vr_overlay_screen_matrix_fixed()); + } + } + } else { + // Nn non-vr mode both our overlays are just ortho projected. + g_graphics_server->ModelViewReset(); + if (type() == Type::kOverlayFrontPass) { + renderer->SetDepthRange(kBackingDepth1, kBackingDepth1B); + } else { + renderer->SetDepthRange(kBackingDepth1B, kBackingDepth2); + } + if (g_graphics_server->tv_border()) { + float amt = 0.5f * kTVBorder; + float w = virtual_width(); + float h = virtual_height(); + g_graphics_server->SetOrthoProjection( + -amt * w, (1.0f + amt) * w, -amt * h, (1.0f + amt) * h, -1, 1); + } else { + g_graphics_server->SetOrthoProjection(0, virtual_width(), 0, + virtual_height(), -1, 1); + } + } + break; + } + case Type::kLightPass: + case Type::kLightShadowPass: { + // Ortho shadows. + if (renderer->shadow_ortho()) { + g_graphics_server->ModelViewReset(); + g_graphics_server->SetOrthoProjection(-12, 12, -12, 12, 10, 100); + g_graphics_server->Translate(Vector3f(0, 0, renderer->light_tz())); + g_graphics_server->Rotate(80, Vector3f(1.0f, 0, 0)); + const Vector3f& soffs = renderer->shadow_offset(); + g_graphics_server->Translate(Vector3f(-soffs.x, -soffs.y, -soffs.z)); + g_graphics_server->scale(Vector3f(1.0f / renderer->shadow_scale_x(), + 1.0f, + 1.0f / renderer->shadow_scale_z())); + } else { + float fovy = 45.0f * kPi / 180.0f; + float fovx = fovy; + float near_val = 10; + float far_val = 100; + float x = near_val * tanf(fovx); + float y = near_val * tanf(fovy); + + g_graphics_server->SetProjectionMatrix( + Matrix44fFrustum(-x, x, -y, y, near_val, far_val)); + g_graphics_server->ModelViewReset(); + g_graphics_server->Translate( + Vector3f(0.0f, 0.0f, renderer->light_tz())); + g_graphics_server->Rotate(renderer->light_pitch(), + Vector3f(1.0f, 0.0f, 0.0f)); + g_graphics_server->Rotate(renderer->light_heading(), + Vector3f(0.0f, 1.0f, 0.0f)); + const Vector3f& soffs = renderer->shadow_offset(); + + // Well, this is slightly terrifying; '-soffs' is causing crashes + // here but multing by -1.000001f works. + // (generally just on android 4.3 on atom processors) + g_graphics_server->Translate(Vector3f( + -1.000001f * soffs.x, -1.000001f * soffs.y, -1.000001f * soffs.z)); + } + + // ...now store the matrix we'll use to project this as a texture + // FIXME: most of these calculations could be cached instead of + // redoing them every pass + tex_project_matrix_ = g_graphics_server->GetModelViewProjectionMatrix(); + model_view_matrix_ = g_graphics_server->model_view_matrix(); + model_view_projection_matrix_ = + g_graphics_server->GetModelViewProjectionMatrix(); + tex_project_matrix_ *= Matrix44fScale(0.5f); + tex_project_matrix_ *= Matrix44fTranslate(0.5f, 0.5f, 0); + g_graphics_server->SetLightShadowProjectionMatrix(tex_project_matrix_); + + break; + } + default: + throw Exception(); + } + + // Some passes draw stuff into the world bucketed by type. + if (UsesWorldLists()) { + // For opaque stuff, render non-reflected(above-ground), + // then reflected(below-ground) stuff (less overdraw that way) + // for transparent stuff we do the opposite so we get better layering. + ReflectionSubPass reflection_sub_passes[2]; + if (transparent) { + reflection_sub_passes[0] = ReflectionSubPass::kMirrored; + reflection_sub_passes[1] = ReflectionSubPass::kRegular; + } else { + reflection_sub_passes[0] = ReflectionSubPass::kRegular; + reflection_sub_passes[1] = ReflectionSubPass::kMirrored; + } + + for (auto reflection_sub_pass : reflection_sub_passes) { + bool doing_reflection = false; + if (reflection_sub_pass == ReflectionSubPass::kMirrored) { + // Only actually draw reflection pass if quality >= high + // and floor-reflections are on. + if (floor_reflection() + && frame_def()->quality() >= GraphicsQuality::kHigher) { + doing_reflection = true; + renderer->set_drawing_reflection(true); + g_graphics_server->PushTransform(); + Matrix44f m = Matrix44fScale(Vector3f(1, -1, 1)); + g_graphics_server->MultMatrix(m); + renderer->FlipCullFace(); // Flip into reflection drawing. + } else { + continue; + } + } else { + renderer->set_drawing_reflection(false); + } + + // Render everything with the same material together to + // minimize gl state changes. + + // Organize shaders that are likely to be occluding other stuff first. + ShadingType component_types_opaque[] = { + ShadingType::kSimpleColor, + ShadingType::kSimpleTexture, + ShadingType::kSimpleTextureModulated, + ShadingType::kSimpleTextureModulatedColorized, + ShadingType::kSimpleTextureModulatedColorized2, + ShadingType::kSimpleTextureModulatedColorized2Masked, + ShadingType::kObjectReflectLightShadow, + ShadingType::kObjectLightShadow, + ShadingType::kObjectReflect, + ShadingType::kObject, + ShadingType::kObjectReflectLightShadowDoubleSided, + ShadingType::kObjectReflectLightShadowColorized, + ShadingType::kObjectReflectLightShadowColorized2, + ShadingType::kObjectReflectLightShadowAdd, + ShadingType::kObjectReflectLightShadowAddColorized, + ShadingType::kObjectReflectLightShadowAddColorized2}; + + ShadingType component_types_transparent[] = { + ShadingType::kSimpleColorTransparent, + ShadingType::kSimpleColorTransparentDoubleSided, + ShadingType::kObjectTransparent, + ShadingType::kObjectLightShadowTransparent, + ShadingType::kObjectReflectTransparent, + ShadingType::kObjectReflectAddTransparent, + ShadingType::kSimpleTextureModulatedTransparent, + ShadingType::kSimpleTextureModulatedTransFlatness, + ShadingType::kSimpleTextureModulatedTransparentDoubleSided, + ShadingType::kSimpleTextureModulatedTransparentColorized, + ShadingType::kSimpleTextureModulatedTransparentColorized2, + ShadingType::kSimpleTextureModulatedTransparentColorized2Masked, + ShadingType::kSimpleTextureModulatedTransparentShadow, + ShadingType::kSimpleTexModulatedTransShadowFlatness, + ShadingType::kSimpleTextureModulatedTransparentGlow, + ShadingType::kSimpleTextureModulatedTransparentGlowMaskUV2, + ShadingType::kSmoke, + ShadingType::kSprite}; + + ShadingType* component_types; + int component_type_count; + if (transparent) { + component_types = component_types_transparent; + component_type_count = + (sizeof(component_types_transparent) / sizeof(ShadingType)); + } else { + component_types = component_types_opaque; + component_type_count = + (sizeof(component_types_opaque) / sizeof(ShadingType)); + } + + for (int c = 0; c < component_type_count; c++) { + renderer->ProcessRenderCommandBuffer( + commands_[static_cast(component_types[c])].get(), *this, + render_target); + } + + if (doing_reflection) { + renderer->FlipCullFace(); // Flip out of reflection drawing. + g_graphics_server->PopTransform(); + } + } + renderer->set_drawing_reflection(false); + } else { + // ..and some passes draw flat lists in order added. + if (transparent) { + renderer->ProcessRenderCommandBuffer(commands_flat_transparent_.get(), + *this, render_target); + } else { + renderer->ProcessRenderCommandBuffer(commands_flat_.get(), *this, + render_target); + } + } +} + +void RenderPass::SetCamera( + const Vector3f& pos, const Vector3f& target, const Vector3f& up, + float near_clip_in, float far_clip_in, float fov_x_in, float fov_y_in, + bool use_fov_tangents, float fov_tan_l, float fov_tan_r, float fov_tan_b, + float fov_tan_t, const std::vector& area_of_interest_points) { + cam_pos_ = pos; + cam_target_ = target; + cam_up_ = up; + cam_near_clip_ = near_clip_in; + cam_far_clip_ = far_clip_in; + cam_use_fov_tangents_ = use_fov_tangents; + cam_fov_x_ = fov_x_in; + cam_fov_y_ = fov_y_in; + cam_fov_l_tan_ = fov_tan_l; + cam_fov_r_tan_ = fov_tan_r; + cam_fov_b_tan_ = fov_tan_b; + cam_fov_t_tan_ = fov_tan_t; + cam_area_of_interest_points_ = area_of_interest_points; +} + +void RenderPass::Reset() { + virtual_width_ = 0; + virtual_height_ = 0; + physical_width_ = 0; + physical_height_ = 0; + floor_reflection_ = false; + cam_pos_ = {0.0f, 0.0f, 0.0f}; + cam_target_ = {0.0f, 0.0f, 1.0f}; + cam_up_ = {0.0f, 1.0f, 0.0f}; + cam_near_clip_ = kCamNearClip; + cam_far_clip_ = kCamFarClip; + cam_fov_x_ = -1.0f; + cam_fov_y_ = 40.0f; + tex_project_matrix_ = kMatrix44fIdentity; + + Renderer* renderer = g_graphics_server->renderer(); + + // Figure our our width/height for drawing commands to reference + // (we cant wait until the drawing is actually occurring because + // that happens in another thread later) + switch (type()) { + case Type::kBeautyPass: + case Type::kBeautyPassBG: + case Type::kOverlay3DPass: + case Type::kOverlayPass: + case Type::kOverlayFrontPass: + case Type::kOverlayFlatPass: + case Type::kVRCoverPass: + case Type::kOverlayFixedPass: + case Type::kBlitPass: + physical_width_ = g_graphics->screen_pixel_width(); + physical_height_ = g_graphics->screen_pixel_height(); + break; + case Type::kLightPass: + physical_width_ = physical_height_ = + static_cast(renderer->shadow_res()) / kLightResDiv; + break; + case Type::kLightShadowPass: + physical_width_ = physical_height_ = + static_cast(renderer->shadow_res()); + break; + default: + throw Exception(); + } + + // By default, logical width matches physical width, but for overlay passes + // it can be independent. + switch (type()) { + case Type::kOverlayPass: + case Type::kOverlayFrontPass: + case Type::kOverlayFixedPass: + case Type::kOverlayFlatPass: + virtual_width_ = g_graphics->screen_virtual_width(); + virtual_height_ = g_graphics->screen_virtual_height(); + break; + default: + virtual_width_ = physical_width_; + virtual_height_ = physical_height_; + break; + } + + // Clear the command buffers this pass cares about. + if (UsesWorldLists()) { + for (auto& command : commands_) { + command->Reset(); + } + } else { + commands_flat_->Reset(); + commands_flat_transparent_->Reset(); + } +} + +void RenderPass::SetFrustum(float near_val, float far_val) { + assert(InGraphicsThread()); + // If we're using fov-tangents: + if (cam_use_fov_tangents_) { + float l = near_val * cam_fov_l_tan_; + float r = near_val * cam_fov_r_tan_; + float t = near_val * cam_fov_t_tan_; + float b = near_val * cam_fov_b_tan_; + projection_matrix_ = Matrix44fFrustum(-l, r, -b, t, near_val, far_val); + } else { + // Old angle-based stuff: + float x; + float angleY = (cam_fov_y_ / 2.0f) * kPi / 180.0f; + float y = near_val * tanf(angleY); + + // Fov-x < 0 implies to use aspect ratio. + if (cam_fov_x_ > 0.0f) { + float angleX = (cam_fov_x_ / 2.0f) * kPi / 180.0f; + x = near_val * tanf(angleX); + } else { + x = y * GetPhysicalAspectRatio(); + } + projection_matrix_ = Matrix44fFrustum(-x, x, -y, y, near_val, far_val); + } + g_graphics_server->SetProjectionMatrix(projection_matrix_); +} + +void RenderPass::Finalize() { + if (UsesWorldLists()) { + for (auto& command : commands_) { + command->Finalize(); + } + } else { + commands_flat_->Finalize(); + commands_flat_transparent_->Finalize(); + } +} + +auto RenderPass::HasDrawCommands() const -> bool { + if (UsesWorldLists()) { + throw Exception(); + } else { + return (commands_flat_transparent_->has_draw_commands() + || commands_flat_->has_draw_commands()); + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/render_pass.h b/src/ballistica/graphics/render_pass.h new file mode 100644 index 00000000..6c794519 --- /dev/null +++ b/src/ballistica/graphics/render_pass.h @@ -0,0 +1,167 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_RENDER_PASS_H_ +#define BALLISTICA_GRAPHICS_RENDER_PASS_H_ + +#include +#include + +#include "ballistica/math/matrix44f.h" + +namespace ballistica { + +// A drawing context for one pass. This can be a render to the screen, a shadow +// pass, a window, etc. +class RenderPass { + public: + enum class ReflectionSubPass { kRegular, kMirrored }; + enum class Type { + kLightShadowPass, + kLightPass, + kBeautyPass, + kBeautyPassBG, + kBlitPass, + // Standard 2d overlay stuff. May be drawn in 2d or on a plane in 3d + // space (in vr). In VR, each of these elements are drawn individually + // and can thus have their own depth. also in VR this overlay repositions + // itself per level; use kOverlayFixedPass for items that shouldn't. + // this overlay may be obscured by UI. Use OVERLAY_FRONT_PASS if you need + // things to show up in front of UI. + kOverlayPass, + // Just like kOverlayPass but guaranteed to draw in front of UI. + kOverlayFrontPass, + // Actually drawn in regular 3d space - for life bars, names, etc that + // need to overlay regular 3d stuff but exist in the world. + kOverlay3DPass, + // Only used in VR - overlay stuff drawn into a flat 2d texture so that + // scissoring/etc works (the UI uses this). + kOverlayFlatPass, + /// Only used in VR - stuff that needs to cover absolutely everything + /// else (like the 3d wipe fade). + kVRCoverPass, + // Only used in VR - overlay elements that should always be fixed in space. + kOverlayFixedPass + }; + + RenderPass(Type type_in, FrameDef* frame_def); + virtual ~RenderPass(); + + auto type() const -> Type { return type_; } + + // The physical size of the drawing surface. + auto physical_width() const -> float { return physical_width_; } + auto physical_height() const -> float { return physical_height_; } + + // The virtual size of the drawing surface. + // This may or may not have anything to do with the physical size + // (for instance the overlay pass in VR has its own bounds which + // is completely independent of the physical surface it gets drawn into). + auto virtual_width() const -> float { return virtual_width_; } + auto virtual_height() const -> float { return virtual_height_; } + + // Should objects be rendered 'underground' in this pass? + auto floor_reflection() const -> bool { return floor_reflection_; } + void set_floor_reflection(bool val) { floor_reflection_ = val; } + auto GetPhysicalAspectRatio() const -> float { + return physical_width() / physical_height(); + } + void SetCamera(const Vector3f& pos, const Vector3f& target, + const Vector3f& up, float near_clip, float far_clip, + float fov_x, // Set to -1 for auto. + float fov_y, bool use_fov_tangents, float fov_tan_l, + float fov_tan_r, float fov_tan_b, float fov_tan_t, + const std::vector& area_of_interest_points); + auto frame_def() const -> FrameDef* { return frame_def_; } + void Render(RenderTarget* t, bool transparent); + auto tex_project_matrix() const -> const Matrix44f& { + return tex_project_matrix_; + } + auto projection_matrix() const -> const Matrix44f& { + return projection_matrix_; + } + auto model_view_matrix() const -> const Matrix44f& { + return model_view_matrix_; + } + auto model_view_projection_matrix() const -> const Matrix44f& { + return model_view_projection_matrix_; + } + auto HasDrawCommands() const -> bool; + void Finalize(); + void Reset(); + + // Whether this pass draws stuff from the per-shader command lists + auto UsesWorldLists() const -> bool { + switch (type()) { + case Type::kBeautyPass: + case Type::kBeautyPassBG: + return true; + case Type::kOverlayPass: + case Type::kOverlayFrontPass: + case Type::kOverlay3DPass: + case Type::kVRCoverPass: + case Type::kOverlayFlatPass: + case Type::kOverlayFixedPass: + case Type::kBlitPass: + case Type::kLightPass: + case Type::kLightShadowPass: + return false; + default: + throw Exception(); + } + } + auto commands_flat() const -> RenderCommandBuffer* { + return commands_flat_.get(); + } + auto commands_flat_transparent() const -> RenderCommandBuffer* { + return commands_flat_transparent_.get(); + } + auto GetCommands(ShadingType type) const -> RenderCommandBuffer* { + return commands_[static_cast(type)].get(); + } + + auto cam_area_of_interest_points() const -> const std::vector& { + return cam_area_of_interest_points_; + } + + private: + void SetFrustum(float near_val, float far_val); + + // Our pass holds sets of draw-commands bucketed by section and + // component-type. + std::unique_ptr + commands_[static_cast(ShadingType::kCount)]; + std::unique_ptr commands_flat_; + std::unique_ptr commands_flat_transparent_; + Vector3f cam_pos_{0.0f, 0.0f, 0.0f}; + Vector3f cam_target_{0.0f, 0.0f, 0.0f}; + Vector3f cam_up_{0.0f, 0.0f, 0.0f}; + float cam_near_clip_{}; + float cam_far_clip_{}; + float cam_fov_x_{}; + float cam_fov_y_{}; + + // We can now alternately supply left, right, top, bottom frustum tangents. + bool cam_use_fov_tangents_{}; + float cam_fov_l_tan_{1.0f}; + float cam_fov_r_tan_{1.0f}; + float cam_fov_t_tan_{1.0f}; + float cam_fov_b_tan_{1.0f}; + std::vector cam_area_of_interest_points_; + Type type_{}; + + // For lights/shadows. + Matrix44f tex_project_matrix_{kMatrix44fIdentity}; + Matrix44f projection_matrix_{kMatrix44fIdentity}; + Matrix44f model_view_matrix_{kMatrix44fIdentity}; + Matrix44f model_view_projection_matrix_{kMatrix44fIdentity}; + bool floor_reflection_{}; + FrameDef* frame_def_{}; + float physical_width_{}; + float physical_height_{}; + float virtual_width_{}; + float virtual_height_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_RENDER_PASS_H_ diff --git a/src/ballistica/graphics/render_target.cc b/src/ballistica/graphics/render_target.cc new file mode 100644 index 00000000..cdbb828c --- /dev/null +++ b/src/ballistica/graphics/render_target.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/render_target.h" + +#include "ballistica/graphics/graphics_server.h" + +namespace ballistica { + +RenderTarget::RenderTarget(Type type) : type_(type) { + assert(InGraphicsThread()); +} + +RenderTarget::~RenderTarget() = default; + +void RenderTarget::ScreenSizeChanged() { + assert(type_ == Type::kScreen); + physical_width_ = g_graphics_server->screen_pixel_width(); + physical_height_ = g_graphics_server->screen_pixel_height(); +} + +auto RenderTarget::GetScissorX(float x) const -> float { + if (IsVRMode()) { + // map -0.05f to 1.1f in logical coordinates to 0 to 1 physical ones + float res_x_virtual = g_graphics_server->screen_virtual_width(); + return physical_width_ + * (((x / res_x_virtual) + (kVRBorder * 0.5f)) / (1.0f + kVRBorder)); + } else { + if (g_graphics_server->tv_border()) { + // map -0.05f to 1.1f in logical coordinates to 0 to 1 physical ones + float res_x_virtual = g_graphics_server->screen_virtual_width(); + return physical_width_ + * (((x / res_x_virtual) + (kTVBorder * 0.5f)) + / (1.0f + kTVBorder)); + } else { + return (physical_width_ / g_graphics_server->screen_virtual_width()) * x; + } + } +} +auto RenderTarget::GetScissorY(float y) const -> float { + if (IsVRMode()) { + // map -0.05f to 1.1f in logical coordinates to 0 to 1 physical ones + float res_y_virtual = g_graphics_server->screen_virtual_height(); + return physical_height_ + * (((y / res_y_virtual) + (kVRBorder * 0.5f)) / (1.0f + kVRBorder)); + } else { + if (g_graphics_server->tv_border()) { + // map -0.05f to 1.1f in logical coordinates to 0 to 1 physical ones + float res_y_virtual = g_graphics_server->screen_virtual_height(); + return physical_height_ + * (((y / res_y_virtual) + (kTVBorder * 0.5f)) + / (1.0f + kTVBorder)); + } else { + return (physical_height_ / g_graphics_server->screen_virtual_height()) + * y; + } + } +} +auto RenderTarget::GetScissorScaleX() const -> float { + if (IsVRMode()) { + float f = physical_width_ / g_graphics_server->screen_virtual_width(); + return f / (1.0f + kVRBorder); + } else { + float f = physical_width_ / g_graphics_server->screen_virtual_width(); + if (g_graphics_server->tv_border()) { + return f / (1.0f + kTVBorder); + } + return f; + } +} + +auto RenderTarget::GetScissorScaleY() const -> float { + if (IsVRMode()) { + float f = physical_height_ / g_graphics_server->screen_virtual_height(); + return f / (1.0f + kVRBorder); + } else { + float f = physical_height_ / g_graphics_server->screen_virtual_height(); + if (g_graphics_server->tv_border()) { + return f / (1.0f + kTVBorder); + } + return f; + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/render_target.h b/src/ballistica/graphics/render_target.h new file mode 100644 index 00000000..ef88585e --- /dev/null +++ b/src/ballistica/graphics/render_target.h @@ -0,0 +1,47 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_RENDER_TARGET_H_ +#define BALLISTICA_GRAPHICS_RENDER_TARGET_H_ + +#include "ballistica/core/object.h" +#include "ballistica/math/vector4f.h" + +namespace ballistica { + +// Encapsulates framebuffers, main windows, etc. +class RenderTarget : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kMain; + } + enum class Type { kScreen, kFramebuffer }; + explicit RenderTarget(Type type); + ~RenderTarget() override; + + // Clear depth, color, etc and get set to draw. + virtual void DrawBegin(bool clear, float clear_r, float clear_g, + float clear_b, float clear_a) = 0; + void DrawBegin(bool clear, + const Vector4f& clear_color = {0.0f, 0.0f, 0.0f, 1.0f}) { + DrawBegin(clear, clear_color.x, clear_color.y, clear_color.z, + clear_color.w); + } + + void ScreenSizeChanged(); + auto physical_width() const -> float { return physical_width_; } + auto physical_height() const -> float { return physical_height_; } + auto GetScissorScaleX() const -> float; + auto GetScissorScaleY() const -> float; + auto GetScissorX(float x) const -> float; + auto GetScissorY(float y) const -> float; + + protected: + float physical_width_{}; + float physical_height_{}; + bool depth_{}; + Type type_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_RENDER_TARGET_H_ diff --git a/src/ballistica/graphics/renderer.cc b/src/ballistica/graphics/renderer.cc new file mode 100644 index 00000000..ac5c7e14 --- /dev/null +++ b/src/ballistica/graphics/renderer.cc @@ -0,0 +1,850 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/renderer.h" + +#include +#include + +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/text/text_packer.h" +#include "ballistica/graphics/vr_graphics.h" + +// FIXME: Clear out conditional stuff. +#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD +#include "ballistica/platform/min_sdl.h" +#endif + +#if BA_VR_BUILD +#include "ballistica/app/app_globals.h" +#endif + +namespace ballistica { + +#if BA_VR_BUILD +const float kBaseVRWorldScale = 1.38f; +const float kInvVRHeadScale = 1.0f / (kBaseVRWorldScale * kDefaultVRHeadScale); +#endif + +// There can be only one!.. at a time. +static bool have_renderer = false; + +Renderer::Renderer() { + assert(!have_renderer); + have_renderer = true; +} + +Renderer::~Renderer() { + assert(have_renderer); + have_renderer = false; +} + +void Renderer::PreprocessFrameDef(FrameDef* frame_def) { + assert(InGraphicsThread()); + + // If this frame_def was made in a different quality mode than we're + // currently in, don't try to render it. + if (frame_def->quality() != g_graphics_server->quality()) { + frame_def->set_rendering(false); + return; + } + frame_def->set_rendering(true); + + // Some VR environments muck with render states before/after + // they call us; resync as needed.... +#if BA_VR_BUILD + if (IsVRMode()) { + VRSyncRenderStates(); + } +#endif // BA_VR_BUILD + + // Setup various high level stuff to match the frame_def + // (tint colors, resolutions, etc). + UpdateSizesQualitiesAndColors(frame_def); + + // Handle a weird gamma reset issue on our legacy mac build (SDL 1.2). +#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD + HandleFunkyMacGammaIssue(frame_def); +#endif + + // In some cases we draw to a lower-res backing buffer instead of native + // screen res. + UpdatePixelScaleAndBackingBuffer(frame_def); + + // Update the buffers for world drawing, blurred versions of that, etc. + UpdateCameraRenderTargets(frame_def); + + // (re)create our light/shadow buffers if need be + UpdateLightAndShadowBuffers(frame_def); + + // Update various VR values such as clip planes and head positions. +#if BA_VR_BUILD + VRPreprocess(frame_def); +#endif // BA_VR_BUILD + + // Pull latest mesh data in from this frame_def. + UpdateMeshes(frame_def->meshes(), frame_def->mesh_index_sizes(), + frame_def->mesh_buffers()); + + // Ensure all media used by this frame_def is loaded. + LoadMedia(frame_def); + + // Draw our light/shadow textures. + RenderLightAndShadowPasses(frame_def); + + // In vr mode we draw our UI into a buffer. +#if BA_VR_BUILD + VRDrawOverlayFlatPass(frame_def); +#endif // BA_VR_BUILD +} + +// actually render one of these frame_def suckers... +// (called within the graphics thread) +void Renderer::RenderFrameDef(FrameDef* frame_def) { + assert(InGraphicsThread()); + + // If preprocess decided not to render this. + if (!frame_def->rendering()) return; + + // Set camera/hand/etc positioning with latest VR data if applicable. + // (we do this here at render time as opposed to frame construction time + // so we have the most up-to-date data possible). +#if BA_VR_BUILD + VRUpdateForEyeRender(frame_def); +#endif // BA_VR_BUILD + + // In higher-quality modes we draw the world into the camera buffer + // which we'll later render into the backing buffer with depth-of-field + // and other stuff added. + if (camera_render_target_.exists()) { + DrawWorldToCameraBuffer(frame_def); + } + + // ..now draw everything into our backing target; either our camera + // buffer (high qual modes) or the world (med/low qual). + PushGroupMarker("Backing Opaque Pass"); + SetDepthWriting(true); + SetDepthTesting(true); + RenderTarget* backing; + if (backing_render_target_.exists()) { + backing = backing_render_target(); + } else { + backing = screen_render_target(); + } + + bool backing_needs_clear = frame_def->needs_clear(); +#if BA_CARDBOARD_BUILD + // On cardboard, our two eyes are drawn into the same FBO, + // so we can't invalidate the buffer when drawing our second eye + // (since that could wipe out the first eye which has already been drawn) + // ..so for the second eye we force a clear, which nicely stays within the + // already-set-up scissor-rect + if (vr_eye_ == 1) { + backing_needs_clear = true; + } +#endif + backing->DrawBegin(backing_needs_clear); + + bool overlays_in_3d = IsVRMode(); + bool overlays_in_2d = !overlays_in_3d; + + // Draw opaque stuff front-to-back. + if (overlays_in_2d) { + frame_def->overlay_front_pass()->Render(backing, false); + frame_def->overlay_pass()->Render(backing, false); + } + + // In vr mode, the front section of the depth buffer that would have been + // used for our 2d ortho overlays is instead used for our vr-fade pass, + // which is nothing but our little bomb shaped transition wipe thing + // (it needs its own depth section otherwise it intersects with stuff out in + // the world). + if (overlays_in_3d) { + frame_def->vr_cover_pass()->Render(backing, false); + frame_def->overlay_front_pass()->Render(backing, false); + frame_def->overlay_pass()->Render(backing, false); + frame_def->overlay_fixed_pass()->Render(backing, false); + } + if (camera_render_target_.exists()) { + UpdateDOFParams(frame_def); + // We've already drawn the world. + // Now just draw our blit shapes (opaque shapes which blit portions of the + // camera render to the screen) ..these is so we can do things like + // distortion on large areas without blitting any part of the bg more than + // once. (unlike if we did that in the overlay-3d pass or whatnot). + frame_def->blit_pass()->Render(backing, false); + } else { + // Otherwise just draw the world straight to the backing + // (lower quality modes). + frame_def->beauty_pass()->Render(backing, false); + frame_def->beauty_pass_bg()->Render(backing, false); + } + PopGroupMarker(); + PushGroupMarker("Backing Transparent Pass"); + SetDepthWriting(false); + + // We may run out of precision in our depth buffer for deeply nested UI stuff + // and whatnot. This ensures overlay stuff never gets occluded by stuff + // 'behind' it because of this lack of precision. + SetDrawAtEqualDepth(true); + + // Now draw transparent stuff back to front. + if (camera_render_target_.exists()) { + // When copying camera buffer to the backing there's nothing transparent + // to draw. + } else { + frame_def->beauty_pass_bg()->Render(backing, true); + frame_def->beauty_pass()->Render(backing, true); + } + frame_def->overlay_3d_pass()->Render(backing, true); + if (overlays_in_3d) { + frame_def->overlay_fixed_pass()->Render(backing, true); + frame_def->overlay_pass()->Render(backing, true); + frame_def->overlay_front_pass()->Render(backing, true); + } + if (overlays_in_2d) { + frame_def->overlay_pass()->Render(backing, true); + frame_def->overlay_front_pass()->Render(backing, true); + } + + // In vr mode, the front section of the depth buffer that would have been + // used for our 2d ortho overlays is instead used for our vr-fade pass, + // which is nothing but our little bomb shaped transition wipe thing + // (it needs its own depth section otherwise it intersects with stuff out + // in the world). + if (overlays_in_3d) { + frame_def->vr_cover_pass()->Render(backing, true); + } + + // For debugging our DOF passes, etc. + DrawDebug(); + PopGroupMarker(); + + // If we've been drawing to a backing buffer, blit it to the screen. + if (backing_render_target_.exists()) { + // FIXME - should we just be discarding both depth and color + // after the blit?.. (of course, this code path shouldn't be used on + // mobile/slow-stuff so maybe it doesn't matter) + + // We're now done with the depth buffer on our backing; just need to copy + // color to the screen buffer. + InvalidateFramebuffer(false, true, false); + + // Note: We're forcing a shader-based blit for the moment; hardware blit + // seems to be flaky on qualcomm hardware as of jan 14 (adreno 330, adreno + // 320). + BlitBuffer(backing, screen_render_target(), false, true, true, true); + } + + // Lastly, we no longer need depth on our screen target. + InvalidateFramebuffer(false, true, false); + + RenderFrameDefEnd(); +} + +void Renderer::FinishFrameDef(FrameDef* frame_def) { + frames_rendered_count_++; + + // Give the renderer a chance to check for/report errors. + CheckForErrors(); +} + +#if BA_VR_BUILD + +void Renderer::VRPreprocess(FrameDef* frame_def) { + if (!IsVRMode()) { + return; + } + + // if we're in VR mode, make sure we've got our VR overlay target + if (!vr_overlay_flat_render_target_.exists()) { + // find this res to be ideal on current gen equipment + // (2017-ish, 1st gen rift/gear-vr/etc) + // ..can revisit once higher-res stuff is commonplace + int base_res = 1024; + vr_overlay_flat_render_target_ = NewFramebufferRenderTarget( + base_res, + base_res + * (static_cast(kBaseVirtualResY) + / static_cast(kBaseVirtualResX)), + true, // linear_interp + true, // depth + true, // tex + false, // depthTex + true, // high-quality + false, // msaa + true // alpha + ); // NOLINT(whitespace/parens) + } + auto* vrgraphics = VRGraphics::get(); + + // Also store our custom near clip plane dist. + frame_def->set_vr_near_clip(vrgraphics->vr_near_clip()); + + Vector3f cam_pt(frame_def->cam_original().x, frame_def->cam_original().y, + frame_def->cam_original().z); + + float world_scale = + kBaseVRWorldScale * VRGraphics::get()->vr_test_head_scale(); + + float extra_yaw = + (frame_def->camera_mode() == CameraMode::kOrbit) ? -0.3f : 0.0f; + vr_base_transform_ = Matrix44fRotate(Vector3f(0, 1, 0), extra_yaw * kDegPi) + * Matrix44fScale(world_scale) + * Matrix44fTranslate(cam_pt.x, cam_pt.y, cam_pt.z); + + // given our raw VR head/hand transforms, calc our in-game transforms + vr_transform_right_hand_ = + Matrix44fRotate(Vector3f(0, 0, 1), -vr_raw_hands_state_.r.roll * kDegPi) + * Matrix44fRotate(Vector3f(1, 0, 0), + -vr_raw_hands_state_.r.pitch * kDegPi) + * Matrix44fRotate(Vector3f(0, 1, 0), + 180.0f + vr_raw_hands_state_.r.yaw * kDegPi) + * Matrix44fScale(kInvVRHeadScale) + * Matrix44fTranslate(vr_raw_hands_state_.r.tx, vr_raw_hands_state_.r.ty, + vr_raw_hands_state_.r.tz) + * vr_base_transform_; + vr_transform_left_hand_ = + Matrix44fRotate(Vector3f(0, 0, 1), -vr_raw_hands_state_.l.roll * kDegPi) + * Matrix44fRotate(Vector3f(1, 0, 0), + -vr_raw_hands_state_.l.pitch * kDegPi) + * Matrix44fRotate(Vector3f(0, 1, 0), + 180.0f + vr_raw_hands_state_.l.yaw * kDegPi) + * Matrix44fScale(kInvVRHeadScale) + * Matrix44fTranslate(vr_raw_hands_state_.l.tx, vr_raw_hands_state_.l.ty, + vr_raw_hands_state_.l.tz) + * vr_base_transform_; + vr_transform_head_ = + Matrix44fRotate(Vector3f(0, 0, 1), -vr_raw_head_roll_ * kDegPi) + * Matrix44fRotate(Vector3f(1, 0, 0), -vr_raw_head_pitch_ * kDegPi) + * Matrix44fRotate(Vector3f(0, 1, 0), 180.0f + vr_raw_head_yaw_ * kDegPi) + * Matrix44fScale(kInvVRHeadScale) + * Matrix44fTranslate(vr_raw_head_tx_, vr_raw_head_ty_, vr_raw_head_tz_) + * vr_base_transform_; + + if (g_app_globals->reset_vr_orientation) { + g_app_globals->reset_vr_orientation = false; + } + + Vector3f translate = vr_transform_head_.GetTranslate(); + Vector3f forward = vr_transform_head_.LocalZAxis(); + Vector3f up = vr_transform_head_.LocalYAxis(); + + // stuff this into our graphics state for rendered stuff to use + vrgraphics->set_vr_head_forward(forward); + vrgraphics->set_vr_head_up(up); + vrgraphics->set_vr_head_translate(translate); +} + +void Renderer::VRUpdateForEyeRender(FrameDef* frame_def) { + if (!IsVRMode()) { + return; + } + VREyeRenderBegin(); + float world_scale = + kBaseVRWorldScale * VRGraphics::get()->vr_test_head_scale(); + Matrix44f eye_transform = + Matrix44fRotate(Vector3f(0, 0, 1), -vr_eye_roll_ * kDegPi) + * Matrix44fRotate(Vector3f(1, 0, 0), -vr_eye_pitch_ * kDegPi) + * Matrix44fRotate(Vector3f(0, 1, 0), 180.0f + (vr_eye_yaw_)*kDegPi) + * Matrix44fScale(kInvVRHeadScale) + * Matrix44fTranslate(vr_eye_x_, vr_eye_y_, vr_eye_z_) + * vr_base_transform_; + + // lastly, plug our eye_transform into our render pass cameras + // NOTE - because VR has different clipping requirements, + // we may be setting a different near plane than our usual drawing + // which currently throws off some of our hard-coded shaders such as DOF.. + // need to look into refactoring those to behave with varied clip ranges. + // For now we work around it by minimizing DOF effects in VR mode. + Vector3f offs = eye_transform * Vector3f(0, 0, 0); + // shaking in VR is odd; turn it off for now. + float shake_amt = 0.00f; + float shake_pos_x = frame_def->shake_original().x * shake_amt; + float shake_pos_y = frame_def->shake_original().y * shake_amt; + float shake_pos_z = frame_def->shake_original().z * shake_amt; + Vector3f target_offs = + eye_transform + * Vector3f(0 + shake_pos_x, 0 + shake_pos_y, 1 + shake_pos_z); + Vector3f up = (eye_transform * Vector3f(0, 1, 0)) - offs; + float near_clip = frame_def->vr_near_clip(); + // if we're doing VR cameras, overwrite the default camera with + // the eye cam here.. + RenderPass* passes[] = {frame_def->beauty_pass(), + frame_def->beauty_pass_bg(), + frame_def->overlay_3d_pass(), + frame_def->blit_pass(), + frame_def->overlay_pass(), + frame_def->overlay_front_pass(), + frame_def->vr_cover_pass(), + frame_def->GetOverlayFixedPass(), + nullptr}; + for (RenderPass** p = passes; *p != nullptr; p++) { + (**p).SetCamera(offs, target_offs, up, near_clip, 1000.0f, + vr_fov_degrees_x_, vr_fov_degrees_y_, vr_use_fov_tangents_, + vr_fov_l_tan_, vr_fov_r_tan_, vr_fov_b_tan_, vr_fov_t_tan_, + passes[0]->cam_area_of_interest_points()); + } +} + +void Renderer::VRDrawOverlayFlatPass(FrameDef* frame_def) { + if (IsVRMode()) { + // The overlay-flat pass should generally only have commands in it + // when UI is visible; skip rendering it if not. + if (frame_def->overlay_flat_pass()->HasDrawCommands()) { + PushGroupMarker("VR Overlay Flat Pass"); + SetDepthWriting(true); + SetDepthTesting(true); + RenderTarget* r_target = vr_overlay_flat_render_target(); + r_target->DrawBegin(true, 0, 0, 0, 0); + frame_def->overlay_flat_pass()->Render(r_target, false); // opaque stuff + SetDepthWriting(false); + + // So our transparent stuff matching opaque stuff in depth gets drawn. + SetDrawAtEqualDepth(true); + + // Transparent stuff. + frame_def->overlay_flat_pass()->Render(r_target, true); + PopGroupMarker(); + SetDepthWriting(false); + SetDepthTesting(false); + SetDrawAtEqualDepth(false); + } + } +} + +void Renderer::VRTransformToRightHand() { + g_graphics_server->MultMatrix(vr_transform_right_hand_); +} + +void Renderer::VRTransformToLeftHand() { + g_graphics_server->MultMatrix(vr_transform_left_hand_); +} +void Renderer::VRTransformToHead() { + g_graphics_server->MultMatrix(vr_transform_head_); +} + +#endif // BA_VR_BUILD + +void Renderer::UpdateSizesQualitiesAndColors(FrameDef* frame_def) { + // If screen-size has changed, handle that. + if (screen_size_dirty_) { + msaa_enabled_dirty_ = true; + screen_render_target()->ScreenSizeChanged(); + + // These render targets are dependent on screen size so they need to be + // remade. + camera_render_target_.Clear(); + camera_msaa_render_target_.Clear(); + backing_render_target_.Clear(); + screen_size_dirty_ = false; + } + + // Update quality settings to match this frame_def. + if (last_render_quality_ != frame_def->quality()) { + light_render_target_.Clear(); + light_shadow_render_target_.Clear(); + if (IsVRMode()) { + vr_overlay_flat_render_target_.Clear(); + } + } + last_render_quality_ = frame_def->quality(); + set_shadow_offset(Vector3f(frame_def->shadow_offset().x, + frame_def->shadow_offset().y, + frame_def->shadow_offset().z)); + set_shadow_scale(frame_def->shadow_scale().x, frame_def->shadow_scale().y); + set_shadow_ortho(frame_def->shadow_ortho()); + set_tint(1.5f * frame_def->tint()); // FIXME; why the 1.5? + set_ambient_color(frame_def->ambient_color()); + set_vignette_inner(frame_def->vignette_inner()); + if (IsVRMode()) { + // In VR mode we dont want vignetting; + // just use the inner color for both in and out. + set_vignette_outer(frame_def->vignette_inner()); + } else { + set_vignette_outer(frame_def->vignette_outer()); + } + UpdateVignetteTex(false); +} + +void Renderer::UpdateLightAndShadowBuffers(FrameDef* frame_def) { + if (!light_render_target_.exists() || !light_shadow_render_target_.exists()) { + assert(screen_render_target_.exists()); + + // Base shadow res on quality. + if (frame_def->quality() >= GraphicsQuality::kHigher) { + shadow_res_ = 1024; + // NOLINTNEXTLINE(bugprone-branch-clone) + } else if (frame_def->quality() >= GraphicsQuality::kHigh) { + shadow_res_ = 512; + } else if (frame_def->quality() >= GraphicsQuality::kMedium) { + shadow_res_ = 512; + } else { + shadow_res_ = 256; + } + + // 16 bit dithering is a bit noticeable here.. + bool high_qual = true; + light_render_target_ = Object::MakeRefCounted(NewFramebufferRenderTarget( + shadow_res_ / kLightResDiv, shadow_res_ / kLightResDiv, + true, // linear_interp + false, // depth + true, // tex + false, // depthTex + high_qual, // high-quality + false, // msaa + false // alpha + )); // NOLINT(whitespace/parens) + light_shadow_render_target_ = Object::MakeRefCounted( + NewFramebufferRenderTarget(shadow_res_, shadow_res_, + true, // linear_interp + false, // depth + true, // tex + false, // depthTex + high_qual, // high-quality + false, // msaa + false // alpha + )); // NOLINT(whitespace/parens) + } +} + +void Renderer::RenderLightAndShadowPasses(FrameDef* frame_def) { + float light_pitch = 90; + float light_heading = 0; + float light_tz = -22; + SetLight(light_pitch, light_heading, light_tz); + + // Draw our light/shadow buffers. + SetDepthWriting(false); + SetDepthTesting(false); + SetDrawAtEqualDepth(false); + PushGroupMarker("Light Pass"); + RenderTarget* r_target = light_render_target(); + r_target->DrawBegin(true, kShadowNeutral, kShadowNeutral, kShadowNeutral, + 1.0f); + frame_def->light_pass()->Render(r_target, true); + PopGroupMarker(); + PushGroupMarker("LightShadow Pass"); + r_target = light_shadow_render_target(); + r_target->DrawBegin(true, kShadowNeutral, kShadowNeutral, kShadowNeutral, + 1.0f); + frame_def->light_shadow_pass()->Render(r_target, true); + PopGroupMarker(); +} + +void Renderer::UpdateCameraRenderTargets(FrameDef* frame_def) { + // Create or destroy our camera render-target as necessary. + // In higher-quality modes we render the world into a buffer + // so we can do depth-of-field filtering and whatnot. + if (frame_def->quality() >= GraphicsQuality::kHigh) { + if (!camera_render_target_.exists()) { + float pixel_scale_fin = std::min(1.0f, std::max(0.1f, pixel_scale_)); + int w = static_cast(screen_render_target_->physical_width() + * pixel_scale_fin); + int h = static_cast(screen_render_target_->physical_height() + * pixel_scale_fin); + + // Calc and store the number of blur levels we'll want + // based on this resolution. + int max_res = std::max(w, h); + blur_res_count_ = 0; + int blur_res = max_res; + while (blur_res > 250) { + blur_res_count_++; + blur_res /= 2; + } + + // Enforce a minimum. + if (blur_res_count_ < 4) { + blur_res_count_ = 4; + } + + // We limit to a single blur pass in high-quality. + if (frame_def->quality() == GraphicsQuality::kHigh + && blur_res_count_ > 1) { + blur_res_count_ = 1; + } + + // Now tweak our cam render target res so that its evenly divisible by + // 2 for that many levels. + int foo = 1; + for (int i = 0; i < blur_res_count_; i++) { + foo *= 2; + } + w = ((w % foo == 0) ? w : (w + (foo - (w % foo)))); + h = ((h % foo == 0) ? h : (h + (foo - (h % foo)))); + camera_render_target_ = Object::MakeRefCounted(NewFramebufferRenderTarget( + w, h, + true, // linear-interp + true, // depth + true, // tex + true, // depth-tex + false, // high-qual + false, // msaa + false // alpha + )); // NOLINT(whitespace/parens) + + // If screen size just changed or whatnot, + // update whether we should do msaa. + if (msaa_enabled_dirty_) { + UpdateMSAAEnabled(); + msaa_enabled_dirty_ = false; + } + + // If we're doing msaa, also create a multi-sample version of the same. + // We'll draw into this and then blit it to our normal texture-backed + // camera-target. + if (IsMSAAEnabled()) { + camera_msaa_render_target_ = + NewFramebufferRenderTarget(w, h, + false, // linear-interp + true, // depth + false, // tex + false, // depth-tex + false, // high-qual + true, // msaa + false // alpha + ); // NOLINT(whitespace/parens) + } + } + } else { + camera_render_target_.Clear(); + camera_msaa_render_target_.Clear(); + blur_res_count_ = 0; + } +} + +void Renderer::UpdatePixelScaleAndBackingBuffer(FrameDef* frame_def) { + // If our pixel-scale is changing its essentially the same as a resolution + // change, so we wanna rebuild our light/shadow buffers and all that. + if (pixel_scale_requested_ != pixel_scale_) { + ScreenSizeChanged(); + } + + // Create or destroy our backing render-target as necessary. + // We need our backing buffer for non-1.0 pixel-scales. + if (pixel_scale_requested_ != 1.0f) { + if (pixel_scale_requested_ != pixel_scale_ + || !backing_render_target_.exists()) { + float pixel_scale_fin = + std::min(1.0f, std::max(0.1f, pixel_scale_requested_)); + int w = static_cast(screen_render_target_->physical_width() + * pixel_scale_fin); + int h = static_cast(screen_render_target_->physical_height() + * pixel_scale_fin); + backing_render_target_ = + NewFramebufferRenderTarget(w, h, + true, // linear interp + true, // depth + true, // tex + false, // depth tex + false, // highquality + false, // msaa, + false // alpha + ); // NOLINT(whitespace/parens) + } + } else { + // Otherwise we don't need backing buffer. Kill it if it exists. + if (backing_render_target_.exists()) { + backing_render_target_.Clear(); + } + } + pixel_scale_ = pixel_scale_requested_; +} + +void Renderer::LoadMedia(FrameDef* frame_def) { + millisecs_t t = GetRealTime(); + for (auto&& i : frame_def->media_components()) { + MediaComponentData* mc = i.get(); + assert(mc); + mc->Load(); + + // Also mark them as used so they get kept around for a bit. + mc->set_last_used_time(t); + } +} + +#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD +void Renderer::HandleFunkyMacGammaIssue(FrameDef* frame_def) { + // FIXME - for some reason, on mac, gamma is getting switched back to + // default about 1 second after a res change, etc... + // so if we're using a non-1.0 gamma, lets keep setting it periodically + // to force the issue + millisecs_t t = GetRealTime(); + if (screen_gamma_requested_ != screen_gamma_ + || (t - last_screen_gamma_update_time_ > 300 && screen_gamma_ != 1.0f)) { + screen_gamma_ = screen_gamma_requested_; + SDL_SetGamma(screen_gamma_, screen_gamma_, screen_gamma_); + last_screen_gamma_update_time_ = t; + } +} +#endif + +void Renderer::DrawWorldToCameraBuffer(FrameDef* frame_def) { +#if BA_CARDBOARD_BUILD + // On cardboard theres a scissor setup enabled when we come in; + // we need to turn that off while drawing to our other framebuffer since it + // screws things up there. + CardboardDisableScissor(); +#endif + + PushGroupMarker("Camera Opaque Pass"); + SetDepthWriting(true); + SetDepthTesting(true); + RenderTarget* cam_target = has_camera_msaa_render_target() + ? camera_msaa_render_target() + : camera_render_target(); + cam_target->DrawBegin(frame_def->needs_clear()); + + // Draw opaque stuff front-to-back. + frame_def->beauty_pass()->Render(cam_target, false); + frame_def->beauty_pass_bg()->Render(cam_target, false); + PopGroupMarker(); + PushGroupMarker("Camera Transparent Pass"); + + // Draw transparent stuff back-to-front. + SetDepthWriting(false); + frame_def->beauty_pass_bg()->Render(cam_target, true); + frame_def->beauty_pass()->Render(cam_target, true); + + // If we drew into the MSAA version, blit it over to the texture version. + if (has_camera_msaa_render_target()) { + BlitBuffer(camera_msaa_render_target(), camera_render_target(), + true, // Depth. + false, // linear_interpolation + false, // force_shader_blit + true // invalidate_source + ); // NOLINT(whitespace/parens) + } + GenerateCameraBufferBlurPasses(); + PopGroupMarker(); + +#if BA_CARDBOARD_BUILD + CardboardEnableScissor(); +#endif +} + +void Renderer::UpdateDOFParams(FrameDef* frame_def) { + RenderPass* beauty_pass = frame_def->beauty_pass(); + assert(beauty_pass); + const std::vector& areas_of_interest( + beauty_pass->cam_area_of_interest_points()); + float min_z, max_z; + if (!areas_of_interest.empty()) { + // find min/max z for our areas of interest + min_z = 9999.0f; + max_z = -9999.0f; + for (auto i : areas_of_interest) { + float z = (beauty_pass->model_view_projection_matrix() * i).z; + if (z > max_z) { + max_z = z; + } + if (z < min_z) { + min_z = z; + } + } + } else { + min_z = max_z = 0; + } + + if ((frame_def->real_time() - dof_update_time_ > 100)) { + dof_update_time_ = frame_def->real_time() - 100; + } + float smoothing = 0.995f; + while (dof_update_time_ < frame_def->real_time()) { + dof_update_time_++; + dof_near_smoothed_ = + smoothing * dof_near_smoothed_ + (1.0f - smoothing) * min_z; + dof_far_smoothed_ = + smoothing * dof_far_smoothed_ + (1.0f - smoothing) * max_z; + } +} + +void Renderer::ScreenSizeChanged() { + assert(InGraphicsThread()); + + // We can actually get these events at times when we don't have a valid + // gl context, so instead of doing any GL work here let's just make a note to + // do so next time we render. + screen_size_dirty_ = true; +} + +void Renderer::CheckCapabilities() {} + +void Renderer::Unload() { + light_render_target_.Clear(); + light_shadow_render_target_.Clear(); + vr_overlay_flat_render_target_.Clear(); + screen_render_target_.Clear(); + backing_render_target_.Clear(); +} + +void Renderer::Load() { + screen_render_target_ = Object::MakeRefCounted(NewScreenRenderTarget()); + + // Restore current gamma value. + if (screen_gamma_ != 1.0f) { +#if BA_SDL2_BUILD + // Not supporting gamma in SDL2 currently. +#elif BA_SDL_BUILD + SDL_SetGamma(screen_gamma_, screen_gamma_, screen_gamma_); +#endif + } +} + +void Renderer::PostLoad() { + // This is called after all loading is done; + // the renderer may choose to do any final setting up here. +} + +void Renderer::SetLight(float pitch, float heading, float tz) { + light_pitch_ = pitch; + light_heading_ = heading; + light_tz_ = tz; +} + +#if BA_VR_BUILD +void Renderer::VRSetHead(float tx, float ty, float tz, float yaw, float pitch, + float roll) { + vr_raw_head_tx_ = tx; + vr_raw_head_ty_ = ty; + vr_raw_head_tz_ = tz; + vr_raw_head_yaw_ = yaw; + vr_raw_head_pitch_ = pitch; + vr_raw_head_roll_ = roll; +} +void Renderer::VRSetEye(int eye, float yaw, float pitch, float roll, + float tan_l, float tan_r, float tan_b, float tan_t, + float eye_x, float eye_y, float eye_z, int viewport_x, + int viewport_y) { + // these are flipped for whatever reason... grumble grumble math grumble + vr_fov_l_tan_ = tan_r; + vr_fov_r_tan_ = tan_l; + vr_fov_b_tan_ = tan_b; + vr_fov_t_tan_ = tan_t; + vr_eye_x_ = eye_x; + vr_eye_y_ = eye_y; + vr_eye_z_ = eye_z; + vr_use_fov_tangents_ = true; + vr_fov_degrees_x_ = vr_fov_degrees_y_ = 30.0f; + vr_eye_ = eye; + vr_eye_yaw_ = yaw; + vr_eye_pitch_ = pitch; + vr_eye_roll_ = roll; + vr_viewport_x_ = viewport_x; + vr_viewport_y_ = viewport_y; +} +#endif // BA_VR_BUILD + +auto Renderer::GetZBufferValue(RenderPass* pass, float dist) -> float { + float z = std::min(1.0f, std::max(-1.0f, dist)); + // Remap from -1,1 to our depth-buffer-range. + z = 0.5f * (z + 1.0f); + z = kBackingDepth3 + z * (kBackingDepth4 - kBackingDepth3); + return z; +} + +auto Renderer::GetAutoAndroidRes() -> std::string { + throw Exception("This should be overridden."); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/renderer.h b/src/ballistica/graphics/renderer.h new file mode 100644 index 00000000..b0ff2946 --- /dev/null +++ b/src/ballistica/graphics/renderer.h @@ -0,0 +1,298 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_RENDERER_H_ +#define BALLISTICA_GRAPHICS_RENDERER_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/graphics/frame_def.h" +#include "ballistica/graphics/framebuffer.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/mesh/image_mesh.h" +#include "ballistica/graphics/mesh/mesh.h" +#include "ballistica/graphics/mesh/mesh_buffer.h" +#include "ballistica/graphics/mesh/mesh_buffer_base.h" +#include "ballistica/graphics/mesh/mesh_buffer_vertex_simple_full.h" +#include "ballistica/graphics/mesh/mesh_buffer_vertex_smoke_full.h" +#include "ballistica/graphics/mesh/mesh_buffer_vertex_sprite.h" +#include "ballistica/graphics/mesh/mesh_data.h" +#include "ballistica/graphics/mesh/mesh_data_client_handle.h" +#include "ballistica/graphics/mesh/mesh_index_buffer_16.h" +#include "ballistica/graphics/mesh/mesh_index_buffer_32.h" +#include "ballistica/graphics/mesh/mesh_indexed.h" +#include "ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h" +#include "ballistica/graphics/mesh/mesh_indexed_object_split.h" +#include "ballistica/graphics/mesh/mesh_indexed_simple_full.h" +#include "ballistica/graphics/mesh/mesh_indexed_simple_split.h" +#include "ballistica/graphics/mesh/mesh_indexed_smoke_full.h" +#include "ballistica/graphics/mesh/mesh_indexed_static_dynamic.h" +#include "ballistica/graphics/mesh/mesh_non_indexed.h" +#include "ballistica/graphics/mesh/sprite_mesh.h" +#include "ballistica/graphics/mesh/text_mesh.h" +#include "ballistica/graphics/render_command_buffer.h" +#include "ballistica/graphics/render_pass.h" +#include "ballistica/graphics/render_target.h" +#include "ballistica/graphics/text/text_group.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/media/data/model_data.h" +#include "ballistica/media/media.h" + +namespace ballistica { + +// The renderer is responsible for converting a frame_def to onscreen pixels +class Renderer { + public: + Renderer(); + virtual ~Renderer(); + + // Given a z-distance in world-space, returns a beauty-pass z-buffer + // value from 0 to 1. + auto GetZBufferValue(RenderPass* pass, float dist) -> float; + + // All 3 of these must be called during a render. + void PreprocessFrameDef(FrameDef* frame_def); + void RenderFrameDef(FrameDef* frame_def); + void FinishFrameDef(FrameDef* frame_def); + + // This needs to be generalized. + void SetLight(float pitch, float heading, float tz); + void set_shadow_offset(const Vector3f& offset) { shadow_offset_ = offset; } + void set_shadow_scale(float x, float z) { + shadow_scale_x_ = x; + shadow_scale_z_ = z; + } + void set_shadow_ortho(bool ortho) { shadow_ortho_ = ortho; } + void set_tint(const Vector3f& val) { tint_ = val; } + void set_ambient_color(const Vector3f& val) { ambient_color_ = val; } + void set_vignette_outer(const Vector3f& val) { vignette_outer_ = val; } + void set_vignette_inner(const Vector3f& val) { vignette_inner_ = val; } + auto tint() const -> const Vector3f& { return tint_; } + auto ambient_color() const -> const Vector3f& { return ambient_color_; } + auto vignette_outer() const -> const Vector3f& { return vignette_outer_; } + auto vignette_inner() const -> const Vector3f& { return vignette_inner_; } + auto shadow_ortho() const -> bool { return shadow_ortho_; } + auto shadow_offset() const -> const Vector3f& { return shadow_offset_; } + auto shadow_scale_x() const -> float { return shadow_scale_x_; } + auto shadow_scale_z() const -> float { return shadow_scale_z_; } + auto light_tz() const -> float { return light_tz_; } + auto light_pitch() const -> float { return light_pitch_; } + auto light_heading() const -> float { return light_heading_; } + void set_pixel_scale(float s) { pixel_scale_requested_ = s; } + void set_screen_gamma(float val) { screen_gamma_requested_ = val; } + void set_debug_draw_mode(bool debugModeIn) { debug_draw_mode_ = debugModeIn; } + auto debug_draw_mode() -> bool { return debug_draw_mode_; } + + // Used when recreating contexts. + virtual void Unload(); + virtual void Load(); + virtual void PostLoad(); + virtual void CheckCapabilities(); + virtual auto GetAutoGraphicsQuality() -> GraphicsQuality = 0; + virtual auto GetAutoTextureQuality() -> TextureQuality = 0; + + virtual auto GetAutoAndroidRes() -> std::string; + + void ScreenSizeChanged(); + auto has_camera_render_target() const -> bool { + return camera_render_target_.exists(); + } + auto has_camera_msaa_render_target() const -> bool { + return camera_msaa_render_target_.exists(); + } + auto camera_render_target() -> RenderTarget* { + assert(camera_render_target_.exists()); + return camera_render_target_.get(); + } + auto camera_msaa_render_target() -> RenderTarget* { + assert(camera_msaa_render_target_.exists()); + return camera_msaa_render_target_.get(); + } + auto backing_render_target() -> RenderTarget* { + assert(backing_render_target_.exists()); + return backing_render_target_.get(); + } + auto screen_render_target() -> RenderTarget* { + assert(screen_render_target_.exists()); + return screen_render_target_.get(); + } + auto light_render_target() -> RenderTarget* { + assert(light_render_target_.exists()); + return light_render_target_.get(); + } + auto light_shadow_render_target() -> RenderTarget* { + assert(light_shadow_render_target_.exists()); + return light_shadow_render_target_.get(); + } + auto vr_overlay_flat_render_target() -> RenderTarget* { + assert(vr_overlay_flat_render_target_.exists()); + return vr_overlay_flat_render_target_.get(); + } + auto shadow_res() const -> int { return shadow_res_; } + auto blur_res_count() const -> int { return blur_res_count_; } + auto drawing_reflection() const -> bool { return drawing_reflection_; } + void set_drawing_reflection(bool val) { drawing_reflection_ = val; } + auto dof_near_smoothed() const -> float { return dof_near_smoothed_; } + auto dof_far_smoothed() const -> float { return dof_far_smoothed_; } + auto total_frames_rendered() -> int { return frames_rendered_count_; } + +#if BA_VR_BUILD + void VRSetHead(float tx, float ty, float tz, float yaw, float pitch, + float roll); + void VRSetHands(const VRHandsState& state) { vr_raw_hands_state_ = state; } + void VRSetEye(int eye, float yaw, float pitch, float roll, float tanL, + float tanR, float tanB, float tanT, float eyeX, float eyeY, + float eyeZ, int viewport_x, int viewport_y); + int VRGetViewportX() const { return vr_viewport_x_; } + int VRGetViewportY() const { return vr_viewport_y_; } +#endif // BA_VR_BUILD + + virtual auto NewModelData(const ModelData& model) -> ModelRendererData* = 0; + virtual auto NewTextureData(const TextureData& texture) + -> TextureRendererData* = 0; + virtual auto NewMeshData(MeshDataType t, MeshDrawType drawType) + -> MeshRendererData* = 0; + virtual void DeleteMeshData(MeshRendererData* data, MeshDataType t) = 0; + virtual void ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, + const RenderPass& pass, + RenderTarget* render_target) = 0; + virtual void SetDepthRange(float min, float max) = 0; + virtual void FlipCullFace() = 0; + + protected: + virtual void DrawDebug() = 0; + virtual void CheckForErrors() = 0; + virtual void UpdateVignetteTex(bool force) = 0; + virtual void GenerateCameraBufferBlurPasses() = 0; + virtual void UpdateMeshes( + const std::vector>& meshes, + const std::vector& index_sizes, + const std::vector>& buffers) = 0; + virtual void SetDepthWriting(bool enable) = 0; + virtual void SetDepthTesting(bool enable) = 0; + virtual void SetDrawAtEqualDepth(bool enable) = 0; + virtual void InvalidateFramebuffer(bool color, bool depth, + bool target_read_framebuffer) = 0; + virtual auto NewScreenRenderTarget() -> RenderTarget* = 0; + virtual auto NewFramebufferRenderTarget(int width, int height, + bool linear_interp, bool depth, + bool texture, bool depth_texture, + bool high_quality, bool msaa, + bool alpha) -> RenderTarget* = 0; + virtual void PushGroupMarker(const char* label) = 0; + virtual void PopGroupMarker() = 0; + virtual void BlitBuffer(RenderTarget* src, RenderTarget* dst, bool depth, + bool linear_interpolation, bool force_shader_blit, + bool invalidate_source) = 0; + virtual auto IsMSAAEnabled() const -> bool = 0; + virtual void UpdateMSAAEnabled() = 0; + virtual void VREyeRenderBegin() = 0; + virtual void RenderFrameDefEnd() = 0; + virtual void CardboardDisableScissor() = 0; + virtual void CardboardEnableScissor() = 0; +#if BA_VR_BUILD + void VRTransformToRightHand(); + void VRTransformToLeftHand(); + void VRTransformToHead(); + virtual void VRSyncRenderStates() = 0; +#endif + + private: + void UpdateLightAndShadowBuffers(FrameDef* frame_def); + void RenderLightAndShadowPasses(FrameDef* frame_def); + void UpdateSizesQualitiesAndColors(FrameDef* frame_def); + void DrawWorldToCameraBuffer(FrameDef* frame_def); + void UpdatePixelScaleAndBackingBuffer(FrameDef* frame_def); + void UpdateCameraRenderTargets(FrameDef* frame_def); +#if BA_OSTYPE_MACOS && BA_SDL_BUILD && !BA_SDL2_BUILD + void HandleFunkyMacGammaIssue(FrameDef* frame_def); +#endif + void LoadMedia(FrameDef* frame_def); + void UpdateDOFParams(FrameDef* frame_def); +#if BA_VR_BUILD + void VRPreprocess(FrameDef* frame_def); + void VRUpdateForEyeRender(FrameDef* frame_def); + void VRDrawOverlayFlatPass(FrameDef* frame_def); + // raw values from vr system + VRHandsState vr_raw_hands_state_; + float vr_raw_head_tx_ = 0.0f; + float vr_raw_head_ty_ = 0.0f; + float vr_raw_head_tz_ = 0.0f; + float vr_raw_head_yaw_ = 0.0f; + float vr_raw_head_pitch_ = 0.0f; + float vr_raw_head_roll_ = 0.0f; + // final game-space transforms + Matrix44f vr_base_transform_ = kMatrix44fIdentity; + Matrix44f vr_transform_right_hand_ = kMatrix44fIdentity; + Matrix44f vr_transform_left_hand_ = kMatrix44fIdentity; + Matrix44f vr_transform_head_ = kMatrix44fIdentity; + // values for current eye render + bool vr_use_fov_tangents_ = false; + float vr_fov_l_tan_ = 1.0f; + float vr_fov_r_tan_ = 1.0f; + float vr_fov_b_tan_ = 1.0f; + float vr_fov_t_tan_ = 1.0f; + float vr_fov_degrees_x_ = 30.0f; + float vr_fov_degrees_y_ = 30.0f; + float vr_eye_x_ = 0.0f; + float vr_eye_y_ = 0.0f; + float vr_eye_z_ = 0.0f; + int vr_eye_ = 0; + float vr_eye_yaw_ = 0.0f; + float vr_eye_pitch_ = 0.0f; + float vr_eye_roll_ = 0.0f; + int vr_viewport_x_ = 0; + int vr_viewport_y_ = 0; +#endif // BA_VR_BUILD + bool screen_size_dirty_{}; + bool msaa_enabled_dirty_{}; + millisecs_t dof_update_time_{}; + bool dof_delay_{true}; + float dof_near_smoothed_{}; + float dof_far_smoothed_{}; + bool drawing_reflection_{}; + int blur_res_count_{}; + float light_pitch_{}; + float light_heading_{}; + float light_tz_{-22.0f}; + Vector3f shadow_offset_{0.0f, 0.0f, 0.0f}; + float shadow_scale_x_{1.0f}; + float shadow_scale_z_{1.0f}; + bool shadow_ortho_{}; + Vector3f tint_{1.0f, 1.0f, 1.0f}; + Vector3f ambient_color_{1.0f, 1.0f, 1.0f}; + Vector3f vignette_outer_{0.0f, 0.0f, 0.0f}; + Vector3f vignette_inner_{1.0f, 1.0f, 1.0f}; + int shadow_res_{-1}; + float screen_gamma_requested_{1.0f}; + float screen_gamma_{1.0f}; + float pixel_scale_requested_{1.0f}; + float pixel_scale_{1.0f}; + Object::Ref screen_render_target_; + Object::Ref backing_render_target_; + Object::Ref camera_render_target_; + Object::Ref camera_msaa_render_target_; + Object::Ref light_render_target_; + Object::Ref light_shadow_render_target_; + Object::Ref vr_overlay_flat_render_target_; + millisecs_t last_screen_gamma_update_time_{}; + int last_commands_buffer_size_{}; + int last_f_vals_buffer_size_{}; + int last_i_vals_buffer_size_{}; + int last_models_buffer_size_{}; + int last_textures_buffer_size_{}; + bool debug_draw_mode_{}; + int frames_rendered_count_{}; + + // The *actual* current quality (set based on the + // currently-rendering frame_def) + GraphicsQuality last_render_quality_{GraphicsQuality::kLow}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_RENDERER_H_ diff --git a/src/ballistica/graphics/text/font_page_map_data.h b/src/ballistica/graphics/text/font_page_map_data.h new file mode 100644 index 00000000..d1a20d0a --- /dev/null +++ b/src/ballistica/graphics/text/font_page_map_data.h @@ -0,0 +1,89 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXT_FONT_PAGE_MAP_DATA_H_ +#define BALLISTICA_GRAPHICS_TEXT_FONT_PAGE_MAP_DATA_H_ + +// this file was generated automatically from the font construction tool on +// 2015-06-27 +// NOTE: IT HAS BEEN MODIFIED BY HAND SINCE!!! IF WE RECREATE IT VIA TOOL +// AT SOME POINT WE NEED TO UPDATE THE TOOL!!!!!!!! + +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/text/text_graphics.h" + +namespace ballistica { +// the total number of glyph pages we have +#define BA_GLYPH_PAGE_COUNT 8 + +// the total number of glyphs we have +const int kGlyphCount = 1280; + +// the starting glyph index for each page +uint32_t g_glyph_page_start_index_map[8] = {0, 258, 416, 546, + 698, 981, 1138, 1276}; + +// the number of glyphs on each page +uint32_t g_glyph_page_glyph_counts[8] = {258, 158, 130, 152, 283, 157, 138, 4}; + +// our dynamically-loaded glyph structs for each page +TextGraphics::Glyph* g_glyph_pages[8] = {nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr}; + +// the page index for each glyph +uint16_t g_glyph_map[kGlyphCount] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 7, 7, 7, 7}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_TEXT_FONT_PAGE_MAP_DATA_H_ diff --git a/src/ballistica/graphics/text/text_graphics.cc b/src/ballistica/graphics/text/text_graphics.cc new file mode 100644 index 00000000..aed7d7fa --- /dev/null +++ b/src/ballistica/graphics/text/text_graphics.cc @@ -0,0 +1,1176 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/text/text_graphics.h" + +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/text/font_page_map_data.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +class TextGraphics::TextSpanBoundsCacheEntry : public Object { + public: + std::string string; + Rect r; + float width{}; + std::map>::iterator + map_iterator_; + std::list>::iterator list_iterator_; +}; + +void TextGraphics::Init() { + assert(InGameThread()); + assert(g_text_graphics == nullptr); + g_text_graphics = new TextGraphics(); +} + +TextGraphics::TextGraphics() { + // Init glyph values for our custom font pages + // (just a 5x5 array currently). + for (int page = 0; page < 4; page++) { + for (int x = 0; x < 5; x++) { + for (int y = 0; y < 5; y++) { + int index = 25 * page + y * 5 + x; + Glyph& g(glyphs_extras_[index]); + + float extra_advance = 0.0f; + + g.pen_offset_x = 0.1f; + g.pen_offset_y = -0.2f; + + g.x_size = 1.0f; + g.y_size = 1.0f; + + // Euro symbol should be a bit smaller. + if (index == 0) { + g.x_size = 0.8f; + g.y_size = 0.8f; + } + + // Move all arrows down a bit. + if (index > 0 && index < 5) { + g.pen_offset_y -= 0.1f; + } + + // Shrink account logos and move them up a bit. + if (index == 29 || index == 32 || index == 33 || index == 38 + || index == 40 || index == 48 || index == 49) { + g.pen_offset_y += 0.4f; + extra_advance += 0.08f; + g.x_size *= 0.55f; + g.y_size *= 0.55f; + } + + // Same with the logo and all the icons on sheets 3 and 4. + if (index == 30 || (index >= 50 && index < 100)) { + // A few are *extra* big + if (index == 67 || index == 65 || index == 70 || index == 72 + || index == 73 || index == 75 || index == 76 || index == 78 + || index == 79) { + g.pen_offset_y += 0.31f; + if (index == 70) g.pen_offset_y -= 0.02f; + extra_advance += 0.04f; + g.x_size *= 0.75f; + g.y_size *= 0.75f; + } else { + g.pen_offset_y += 0.4f; + extra_advance += 0.08f; + g.x_size *= 0.55f; + g.y_size *= 0.55f; + } + } + g.advance = g.x_size - 0.09f + extra_advance; + + // Ticket overlay should be big and shouldn't advance us at all. + if (index == 41) { + g.x_size *= 1.1f; + g.y_size *= 1.1f; + g.pen_offset_x -= 0.3f; + g.pen_offset_y -= 0.1f; + g.advance = 0; + } + + // Trophies should be big. + if (index >= 42 && index <= 47) { + float s = 1.5f; + g.x_size *= s; + g.y_size *= s; + g.pen_offset_x -= 0.07f; + g.pen_offset_y -= 0.2f; + g.advance *= s; + } + + // Up/down arrows are a bit thinner. + if (index == 3 || index == 4) { + g.advance -= 0.3f; + g.pen_offset_x -= 0.15f; + } + + g.tex_min_x = 0.2f * static_cast(x); + g.tex_min_y = 0.2f * static_cast(y + 1); + g.tex_max_x = 0.2f * static_cast(x + 1); + g.tex_max_y = 0.2f * static_cast(y); + } + } + } + + // init glyph values for our big font page + // (a 8x8 array) + { + float x_offs = 0.009f; + float y_offs = 0.0059f; + float scale_extra = -0.012f; + for (int x = 0; x < 8; x++) { + for (int y = 0; y < 8; y++) { + int c = y * 8 + x; + Glyph& g(glyphs_big_[c]); + g.pen_offset_x = 0.05f; + g.pen_offset_y = -0.215f; + float w = 0.41f; + float bot_offset = 0.0f; + float left_offset = 0.0f; + float right_offset = 0.0f; + float top_offset = 0.0f; + switch (c) { + case 0: // NOLINT(bugprone-branch-clone) + w = 0.415f; + break; // A + case 1: + w = 0.415f; + break; // B + case 2: + w = 0.40f; + break; // C + case 4: + w = 0.315f; + break; // E + case 5: + w = 0.31f; + break; // F + case 7: + w = 0.42f; + break; // H + case 8: + w = 0.215f; + break; // I + case 9: + w = 0.38f; + break; // J + case 10: + w = 0.42f; + break; // K + case 11: + w = 0.345f; + break; // L + case 12: + w = 0.56f; + break; // M + case 13: + w = 0.42f; + break; // N + case 15: + w = 0.38f; + break; // P + case 16: + bot_offset = 0.07f; + break; // Q + case 18: // NOLINT(bugprone-branch-clone) + w = 0.375f; + break; // S + case 19: + w = 0.375f; + break; // T + case 20: + w = 0.43f; + break; // U + case 21: + w = 0.42f; + break; // V + case 22: + w = 0.625f; + break; // W + case 23: + w = 0.36f; + break; // X + case 24: + w = 0.4f; + break; // Y + case 25: + w = 0.34f; + break; // Z + case 26: + w = 0.37f; + break; // 0 + case 27: + w = 0.28f; + break; // 1 + case 28: // NOLINT(bugprone-branch-clone) + w = 0.37f; + break; // 2 + case 29: + w = 0.37f; + break; // 3 + case 30: + w = 0.37f; + break; // 4 + case 31: + w = 0.37f; + break; // 5 + case 32: // NOLINT(bugprone-branch-clone) + w = 0.36f; + break; // 6 + case 33: + w = 0.36f; + break; // 7 + case 34: // NOLINT(bugprone-branch-clone) + w = 0.37f; + break; // 8 + case 35: + w = 0.37f; + break; // 9 + case 36: + w = 0.18f; + break; // ! + case 37: + w = 0.35f; + break; // ? + case 38: + w = 0.21f; + top_offset = -0.72f; + break; // . + case 39: + w = 0.30f; + top_offset = -0.44f; + bot_offset = -0.3f; + break; // - + case 40: + w = 0.20f; + top_offset = -0.3f; + bot_offset = 0.0f; + break; // : + case 41: + w = 0.6f; + top_offset = -0.19f; + bot_offset = -0.1f; + break; // % + case 42: + w = 0.54f; + top_offset = -0.16f; + bot_offset = -0.1f; + break; // # + case 43: // NOLINT(bugprone-branch-clone) + w = 0.18f; + break; // upside-down ! + case 44: + w = 0.18f; + break; // space + default: + break; + } + bot_offset += 0.04f; + right_offset += 0.04f; + top_offset += 0.03f; + left_offset += 0.03f; + + g.advance = w * 1.15f; + g.x_size = 1.03f; + g.y_size = 1.03f; + g.tex_min_x = (1.0f / 8.0f) * static_cast(x) + x_offs; + g.tex_min_y = + (1.0f / 8.0f) * static_cast(y + 1) + y_offs + scale_extra; + g.tex_max_x = + (1.0f / 8.0f) * static_cast(x + 1) + x_offs + scale_extra; + g.tex_max_y = (1.0f / 8.0f) * static_cast(y) + y_offs; + + // just scooted letters over.. account for that + float foo_x = 0.0183f; + float foo_y = 0.000f; + g.tex_min_x += foo_x; + g.tex_max_x += foo_x; + g.tex_min_y += foo_y; + g.tex_max_y += foo_y; + + // clamp based on char width + float scale = w * 1.32f; + g.x_size *= scale; + g.tex_max_x = g.tex_min_x + (g.tex_max_x - g.tex_min_x) * scale; + + // add bot offset + if (bot_offset != 0.0f) { + g.tex_min_y = g.tex_max_y + + (g.tex_min_y - g.tex_max_y) + * ((g.y_size + bot_offset) / g.y_size); + g.pen_offset_y -= bot_offset; + g.y_size += bot_offset; + } + // add left offset + if (left_offset != 0.0f) { + g.tex_min_x = g.tex_max_x + + (g.tex_min_x - g.tex_max_x) + * ((g.x_size + left_offset) / g.x_size); + g.pen_offset_x -= left_offset; + g.x_size += left_offset; + } + // add right offset + if (right_offset != 0.0f) { + g.tex_max_x = g.tex_min_x + + (g.tex_max_x - g.tex_min_x) + * ((g.x_size + right_offset) / g.x_size); + g.x_size += right_offset; + } + // add top offset + if (top_offset != 0.0f) { + g.tex_max_y = g.tex_min_y + + (g.tex_max_y - g.tex_min_y) + * ((g.y_size + top_offset) / g.y_size); + g.y_size += top_offset; + } + + if (g.tex_max_x > 1.0f || g.tex_max_x < 0.0f || g.tex_min_x > 1.0 + || g.tex_min_x < 0.0f || g.tex_max_y > 1.0f || g.tex_max_y < 0.0 + || g.tex_min_y > 1.0f || g.tex_min_y < 0.0f) { + BA_LOG_ONCE("Warning: glyph bounds error"); + } + } + } + } +} + +static auto GetBigGlyphIndex(uint32_t char_val) -> int { + int index; + switch (char_val) { + case 'A': + case 'a': + case 0x00C0: + case 0x00E0: + case 0x00C1: + case 0x00E1: + case 0x00C2: + case 0x00E2: + case 0x00C3: + case 0x00E3: + case 0x00C4: + case 0x00E4: + case 0x00C5: + case 0x00E5: + case 0x0100: + case 0x0101: + case 0x0102: + case 0x0103: + case 0x0104: + case 0x0105: + index = 0; + break; + case 'B': + case 'b': + index = 1; + break; + case 'C': + case 'c': + case 0x0106: + case 0x0107: + case 0x0108: + case 0x0109: + case 0x010A: + case 0x010B: + case 0x010C: + case 0x010D: + index = 2; + break; + case 'D': + case 'd': + case 0x00D0: + case 0x010E: + case 0x010F: + case 0x0110: + case 0x0111: + index = 3; + break; + case 'E': + case 'e': + case 0x00C8: + case 0x00E8: + case 0x00C9: + case 0x00E9: + case 0x00CA: + case 0x00EA: + case 0x00CB: + case 0x00EB: + case 0x0112: + case 0x0113: + case 0x0114: + case 0x0115: + case 0x0116: + case 0x0117: + case 0x0118: + case 0x0119: + case 0x011A: + case 0x011B: + index = 4; + break; + case 'F': + case 'f': + index = 5; + break; + case 'G': + case 'g': + case 0x011C: + case 0x011D: + case 0x011E: + case 0x011F: + case 0x0120: + case 0x0121: + case 0x0122: + case 0x0123: + index = 6; + break; + case 'H': + case 'h': + case 0x0124: + case 0x0125: + case 0x0126: + case 0x0127: + index = 7; + break; + case 'I': + case 'i': + case 0x00CD: + case 0x00ED: + case 0x00CE: + case 0x00EE: + case 0x00CF: + case 0x00EF: + case 0x0128: + case 0x0129: + case 0x012A: + case 0x012B: + case 0x012C: + case 0x012D: + case 0x012E: + case 0x012F: + case 0x0130: + index = 8; + break; + case 'J': + case 'j': + case 0x0134: + case 0x0135: + index = 9; + break; + case 'K': + case 'k': + case 0x0136: + case 0x0137: + case 0x0138: + index = 10; + break; + case 'L': + case 'l': + case 0x0139: + case 0x013A: + case 0x013B: + case 0x013C: + case 0x013D: + case 0x013E: + case 0x013F: + case 0x0140: + case 0x0141: + case 0x0142: + index = 11; + break; + case 'M': + case 'm': + index = 12; + break; + case 'N': + case 'n': + case 0x00D1: + case 0x00F1: + case 0x0143: + case 0x0144: + case 0x0145: + case 0x0146: + case 0x0147: + case 0x0148: + case 0x0149: + case 0x014A: + case 0x014B: + index = 13; + break; + case 'O': + case 'o': + case 0x00D2: + case 0x00F2: + case 0x00D3: + case 0x00F3: + case 0x00D4: + case 0x00F4: + case 0x00D5: + case 0x00F5: + case 0x00D6: + case 0x00F6: + case 0x014C: + case 0x014D: + case 0x014E: + case 0x014F: + case 0x0150: + case 0x0151: + index = 14; + break; + case 'P': + case 'p': + index = 15; + break; + case 'Q': + case 'q': + index = 16; + break; + case 'R': + case 'r': + case 0x0154: + case 0x0155: + case 0x0156: + case 0x0157: + case 0x0158: + case 0x0159: + index = 17; + break; + case 'S': + case 's': + case 0x015A: + case 0x015B: + case 0x015C: + case 0x015D: + case 0x015E: + case 0x015F: + case 0x0160: + case 0x0161: + index = 18; + break; + case 'T': + case 't': + case 0x0162: + case 0x0163: + case 0x0164: + case 0x0165: + case 0x0166: + case 0x0167: + index = 19; + break; + case 'U': + case 'u': + case 0x00D9: + case 0x00F9: + case 0x00DA: + case 0x00FA: + case 0x00DB: + case 0x00FB: + case 0x00DC: + case 0x00FC: + case 0x0168: + case 0x0169: + case 0x016A: + case 0x016B: + case 0x016C: + case 0x016D: + case 0x016E: + case 0x016F: + case 0x0170: + case 0x0171: + case 0x0172: + case 0x0173: + index = 20; + break; + case 'V': + case 'v': + index = 21; + break; + case 'W': + case 'w': + case 0x0174: + case 0x0175: + index = 22; + break; + case 'X': + case 'x': + index = 23; + break; + case 'Y': + case 'y': + case 0x00DD: + case 0x00FD: + case 0x00FF: + case 0x0176: + case 0x0177: + case 0x0178: + index = 24; + break; + case 'Z': + case 'z': + case 0x0179: + case 0x017A: + case 0x017B: + case 0x017C: + case 0x017D: + case 0x017E: + index = 25; + break; + case '0': + index = 26; + break; + case '1': + index = 27; + break; + case '2': + index = 28; + break; + case '3': + index = 29; + break; + case '4': + index = 30; + break; + case '5': + index = 31; + break; + case '6': + index = 32; + break; + case '7': + index = 33; + break; + case '8': + index = 34; + break; + case '9': + index = 35; + break; + case '!': + index = 36; + break; + case '?': + index = 37; + break; + case '.': + index = 38; + break; + case '-': + index = 39; + break; + case ':': + index = 40; + break; + case '%': + index = 41; + break; + case '#': + index = 42; + break; + case 161: + index = 43; + break; // upside-down ! + case ' ': + index = 44; + break; + default: + index = -1; + break; + } + return index; +} + +auto TextGraphics::GetBigCharIndex(int c) -> int { + int index; + if (c >= 'a' && c <= 'z') { + index = c - 'a'; + } else if (c >= 'A' && c <= 'Z') { + index = c - 'A'; + } else if (c >= '0' && c <= '9') { + index = c - '0' + 26; + } else { + switch (c) { + case '!': + index = 36; + break; + case '?': + index = 37; + break; + case '.': + index = 38; + break; + case '-': + index = 39; + break; + case ':': + index = 40; + break; + case '%': + index = 41; + break; + case '#': + index = 42; + break; + + case 192: + case 193: + case 194: + case 195: + case 196: + case 197: + case 198: + index = 'a' - 'a'; + break; + case 199: + index = 'c' - 'a'; + break; + case 200: + case 201: + case 202: + case 203: + index = 'e' - 'a'; + break; + case 204: + case 205: + case 206: + case 207: + index = 'i' - 'a'; + break; + case 208: + index = 'd' - 'a'; + break; + case 209: + index = 'n' - 'a'; + break; + case 210: + case 211: + case 212: + case 213: + case 216: + index = 'o' - 'a'; + break; + case 217: + case 218: + case 219: + case 220: + index = 'u' - 'a'; + break; + case 221: + index = 'y' - 'a'; + break; + case 224: + case 225: + case 226: + case 227: + case 228: + case 229: + case 230: + index = 'a' - 'a'; + break; + case 231: + index = 'c' - 'a'; + break; + case 232: + case 233: + case 234: + case 235: + index = 'e' - 'a'; + break; + case 236: + case 237: + case 238: + case 239: + index = 'i' - 'a'; + break; + case 240: + index = 'o' - 'a'; + break; + case 241: + index = 'n' - 'a'; + break; + case 242: + case 243: + case 244: + case 245: + case 246: + case 248: + index = 'o' - 'a'; + break; + case 249: + case 250: + case 251: + case 252: + index = 'u' - 'a'; + break; + case 253: + index = 'y' - 'a'; + break; + case 254: + index = 'p' - 'a'; + break; + case 255: + index = 'y' - 'a'; + break; + default: + index = -1; + } + } + return index; +} + +void TextGraphics::LoadGlyphPage(uint32_t index) { + std::lock_guard lock(glyph_load_mutex_); + + // Its possible someone else coulda loaded it since we last checked. + if (g_glyph_pages[index] == nullptr) { + char buffer[256]; + snprintf(buffer, sizeof(buffer), "ba_data/fonts/fontSmall%d.fdata", index); + FILE* f = g_platform->FOpen(buffer, "rb"); + BA_PRECONDITION(f); + BA_PRECONDITION(sizeof(TextGraphics::Glyph[2]) == sizeof(float[18])); + uint32_t total_size = sizeof(Glyph) * g_glyph_page_glyph_counts[index]; + g_glyph_pages[index] = static_cast(malloc(total_size)); + BA_PRECONDITION(g_glyph_pages[index]); + BA_PRECONDITION(fread(g_glyph_pages[index], total_size, 1, f) == 1); + fclose(f); + } +} + +void TextGraphics::GetFontPageCharRange(int page, uint32_t* first_char, + uint32_t* last_char) { + // Our special pages: + switch (page) { + case static_cast(FontPage::kOSRendered): { + // we allow the OS to render anything not in one of our glyph textures + // (technically this overlaps the private-use range which we use our own + // textures for, but that's handled as a special-case by + // TextGroup::setText + (*first_char) = kGlyphCount; + (*last_char) = kTextMaxUnicodeVal; // hmm what's the max unicode value we + // should ever see?.. + break; + } + case static_cast(FontPage::kExtras1): { + (*first_char) = 0xE000; + (*last_char) = (*first_char) + 24; + break; + } + case static_cast(FontPage::kExtras2): { + (*first_char) = 0xE000 + 25; + (*last_char) = (*first_char) + 24; + break; + } + case static_cast(FontPage::kExtras3): { + (*first_char) = 0xE000 + 50; + (*last_char) = (*first_char) + 24; + break; + } + case static_cast(FontPage::kExtras4): { + (*first_char) = 0xE000 + 75; + (*last_char) = (*first_char) + 24; + break; + } + default: { + assert(page < BA_GLYPH_PAGE_COUNT); + (*first_char) = g_glyph_page_start_index_map[page]; + (*last_char) = (*first_char) + g_glyph_page_glyph_counts[page] - 1; + break; + } + } +} + +void TextGraphics::GetFontPagesForText(const std::string& text, + std::set* font_pages) { + int last_page = -1; + std::vector unicode = Utils::UnicodeFromUTF8(text, "c03853"); + for (uint32_t val : unicode) { + int page; + + // Hack: allow showing euro even if we don't support unicode font rendering. + if (g_buildconfig.enable_os_font_rendering()) { + if (val == 8364) { + val = 0xE000; + } + } + + // For values in the custom-char range (U+E000–U+F8FF) we point at our own + // custom page(s) + if (val >= 0xE000 && val <= 0xF8FF) { + // The 25 chars after this are in our fontExtras sheet. + if (val < 0xE000 + 25) { + // Special value denoting our custom font page. + page = static_cast(FontPage::kExtras1); + } else if (val < 0xE000 + 50) { + // Special value denoting our custom font page. + page = static_cast(FontPage::kExtras2); + } else if (val < 0xE000 + 75) { + // Special value denoting our custom font page. + page = static_cast(FontPage::kExtras3); + } else if (val < 0xE000 + 100) { + // Special value denoting our custom font page. + page = static_cast(FontPage::kExtras4); + } else { + // We dont cover this.. just go with '?' + val = '?'; + page = g_glyph_map[val]; + } + } else if (val >= kGlyphCount) { + // Otherwise if its outside of our texture-coverage area. + if (g_buildconfig.enable_os_font_rendering()) { + page = static_cast(FontPage::kOSRendered); + } else { + val = '?'; + page = g_glyph_map[val]; + } + } else { + // yay we cover it! + page = g_glyph_map[val]; + } + // compare to lastPage to avoid doing a set insert for *everything* since + // most will be the same + if (page != last_page) { + (*font_pages).insert(page); + last_page = page; + } + } +} + +auto TextGraphics::HaveBigChars(const std::string& text) -> bool { + std::vector unicode = Utils::UnicodeFromUTF8(text, "fnc93rh"); + for (unsigned int val : unicode) { + if (GetBigGlyphIndex(val) == -1) { + // Don't count misses for newlines, spaces, etc. + if ((val != '\n') && (val != '\r')) { + return false; + } + } + } + return true; // Success! +} + +inline auto IsSpecialChar(uint32_t val) -> bool { + return (val >= 0xE000 && val < (0xE000 + 100)); +} + +auto TextGraphics::HaveChars(const std::string& text) -> bool { + if (g_buildconfig.enable_os_font_rendering()) { + return true; + } else { + std::vector unicode = Utils::UnicodeFromUTF8(text, "c957fj"); + for (auto&& val : unicode) { + // There's a few special chars we have. + if (val >= kGlyphCount && !IsSpecialChar(val)) { + return false; + } + } + return true; // Success! + } +} + +auto TextGraphics::GetGlyph(uint32_t val, bool big) -> TextGraphics::Glyph* { + if (big) { + int index = GetBigGlyphIndex(val); + if (index == -1) index = 37; // default to '?' + return &glyphs_big_[index]; + } else { + // Special case; if its in our custom range, handle it special. + if (IsSpecialChar(val)) { + return &glyphs_extras_[val - 0xE000]; + } else if (val >= kGlyphCount) { + return nullptr; + } + uint32_t page = g_glyph_map[val]; + uint32_t start_index = g_glyph_page_start_index_map[page]; + uint32_t local_index = val - start_index; + if (g_glyph_pages[page] == nullptr) { + LoadGlyphPage(page); + } + return &g_glyph_pages[page][local_index]; + } +} + +void TextGraphics::GetOSTextSpanBoundsAndWidth(const std::string& s, Rect* r, + float* width) { + assert(InGameThread()); + + // Asking the OS to calculate text bounds sounds expensive, + // so let's use a cache of recent results. + auto i = text_span_bounds_cache_map_.find(s); + if (i != text_span_bounds_cache_map_.end()) { + Object::Ref entry = i->second; + *r = entry->r; + *width = entry->width; + + // Send this entry to the back of the list since we used it. + text_span_bounds_cache_.erase(entry->list_iterator_); + + // I guess inspection doesn't realize entry lives on after this?... +#pragma clang diagnostic push +#pragma ide diagnostic ignored "UnusedValue" + entry->list_iterator_ = + text_span_bounds_cache_.insert(text_span_bounds_cache_.end(), entry); +#pragma clang diagnostic pop + return; + } + auto entry(Object::New()); + entry->string = s; + if (g_buildconfig.enable_os_font_rendering()) { + g_platform->GetTextBoundsAndWidth(s, &entry->r, &entry->width); + } else { + BA_LOG_ONCE( + "FIXME: GetOSTextSpanBoundsAndWidth unimplemented on this platform"); + r->l = 0.0f; + r->r = 1.0f; + r->t = 1.0f; + r->b = 0.0f; + *width = 1.0f; + } + entry->list_iterator_ = + text_span_bounds_cache_.insert(text_span_bounds_cache_.end(), entry); + entry->map_iterator_ = + text_span_bounds_cache_map_.insert(std::make_pair(s, entry)).first; + *r = entry->r; + *width = entry->width; + + // Keep cache from growing too large. + while (text_span_bounds_cache_.size() > 300) { + text_span_bounds_cache_map_.erase( + text_span_bounds_cache_.front()->map_iterator_); + text_span_bounds_cache_.pop_front(); + } +} + +auto TextGraphics::GetStringWidth(const char* text, bool big) -> float { + assert(Utils::IsValidUTF8(text)); + + // even if they ask for the big font, their string might not support it... + big = (big && TextGraphics::HaveBigChars(text)); + + float char_width = 32.0f; + const char* t = text; + float line_length = 0; + float max_line_length = 0; + + // We have the OS render some chars, broken into single-line spans. + std::vector os_span; + + while (*t != 0) { + if (*t == '\n') { + // Add/reset os-span. + if (!os_span.empty()) { + std::string s = Utils::UTF8FromUnicode(os_span); + line_length += GetOSTextSpanWidth(s); + os_span.clear(); + } + if (line_length > max_line_length) max_line_length = line_length; + line_length = 0; + t++; + } else { + uint32_t val = Utils::GetUTF8Value(t); + Utils::AdvanceUTF8(&t); + // Special case: if we're already doing an OS-span, tack certain + // chars onto it instead of switching back to glyph mode. + // (to reduce the number of times we switch back and forth) + if (TextGraphics::IsOSDrawableAscii(val) && !os_span.empty()) { + os_span.push_back(val); + } else if (Glyph* g = GetGlyph(val, big)) { + // If we *had* been building a span, add its length. + if (!os_span.empty()) { + std::string s = Utils::UTF8FromUnicode(os_span); + line_length += GetOSTextSpanWidth(s); + os_span.clear(); + } + line_length += char_width * g->advance; + } else { + // Add to os-span. + if (g_buildconfig.enable_os_font_rendering()) { + os_span.push_back(val); + } + } + } + } + // Tally final span if there is one. + if (!os_span.empty()) { + std::string s = Utils::UTF8FromUnicode(os_span); + line_length += GetOSTextSpanWidth(s); + os_span.clear(); + } + // Check last line. + if (line_length > max_line_length) { + max_line_length = line_length; + } + return max_line_length; +} + +auto TextGraphics::GetStringHeight(const char* text) -> float { + size_t str_size = strlen(text); + int char_val; + float y_offset = 0; + for (size_t i = 0; i < str_size; i++) { + char_val = ((unsigned char*)text)[i]; + if (char_val == '\n') y_offset += kTextRowHeight; + } + return y_offset + kTextRowHeight; +} + +void TextGraphics::BreakUpString(const char* text, float width, + std::vector* v) { + assert(Utils::IsValidUTF8(text)); + v->clear(); + std::vector buffer_(strlen(text) + 1); + char* buffer(&(buffer_[0])); + strcpy(buffer, text); // NOLINT + float char_width = 32.0f; + float line_length = 0; + const char* s_begin = buffer; + const char* t = buffer; + while (true) { + // If we hit a newline or string end, dump a string. + if (*t == '\n' || *t == 0) { + bool is_end = (*t == 0); + // So we can just use s_begin as a string. + *(char*)t = 0; // NOLINT hmmm this code is ugly + v->push_back(Utils::GetValidUTF8(s_begin, "gbus")); + line_length = 0.0f; + if (is_end) { + break; // done! + } else { + t++; + s_begin = t; + } + } else { + if (*t == 0) throw Exception(); + uint32_t val = Utils::GetUTF8Value(t); + Utils::AdvanceUTF8(&t); + + // Special case: if we're already doing an OS-span, tack certain + // chars onto it instead of switching back to glyph mode. + // (to reduce the number of times we switch back and forth). + // NOLINTNEXTLINE(bugprone-branch-clone) + if (TextGraphics::IsOSDrawableAscii(val) && explicit_bool(false)) { + // I think I disabled this for consistency?... + // FIXME FIXME FIXME - handle this along with stuff below.. + } else if (Glyph* g = GetGlyph(val, false)) { + line_length += char_width * g->advance; + } else { + // FIXME FIXME FIXME - need to clump non-glyph characters into + // spans and use OS text stuff to get their lengths. + } + + // If this char puts us over the width, clip a line. + if (line_length > width) { + line_length = 0.0f; + char tmp = *t; + *(char*)t = 0; // NOLINT temp for string copy + v->push_back(Utils::GetValidUTF8(s_begin, "gbus2")); + *(char*)t = tmp; // NOLINT + s_begin = t; + } + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/text/text_graphics.h b/src/ballistica/graphics/text/text_graphics.h new file mode 100644 index 00000000..aca2e9f2 --- /dev/null +++ b/src/ballistica/graphics/text/text_graphics.h @@ -0,0 +1,111 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXT_TEXT_GRAPHICS_H_ +#define BALLISTICA_GRAPHICS_TEXT_TEXT_GRAPHICS_H_ + +#include +#include +#include +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/math/rect.h" + +namespace ballistica { + +// Largest unicode value we ask the OS to draw for us. +const int kTextMaxUnicodeVal = 999999; +const float kTextRowHeight = 32.0f; + +// Encapsulates text-display functionality used by the game thread. +class TextGraphics { + public: + static void Init(); + + TextGraphics(); + + enum class FontPage { + kOSRendered = 9989, + kExtras1 = 9990, + kExtras2 = 9991, + kExtras3 = 9992, + kExtras4 = 9993 + }; + + struct Glyph { + float pen_offset_x; + float pen_offset_y; + float advance; + float x_size; + float y_size; + float tex_min_x; + float tex_min_y; + float tex_max_x; + float tex_max_y; + }; + + static auto GetBigCharIndex(int c) -> int; + + // Returns a glyph or nullptr if it is unavailable. + auto GetGlyph(uint32_t value, bool big) -> Glyph*; + static auto HaveBigChars(const std::string& string) -> bool; + static auto HaveChars(const std::string& string) -> bool; + void GetFontPagesForText(const std::string& text, std::set* font_pages); + void GetFontPageCharRange(int page, uint32_t* first_char, + uint32_t* last_char); + auto GetOSTextSpanWidth(const std::string& s) -> float { + Rect r; + float width; + GetOSTextSpanBoundsAndWidth(s, &r, &width); + return width; + } + void GetOSTextSpanBoundsAndWidth(const std::string& s, Rect* r, float* width); + + // Returns the width of a string + auto GetStringWidth(const char* s, bool big = false) -> float; + auto GetStringWidth(const std::string& s, bool big = false) -> float { + return GetStringWidth(s.c_str(), big); + } + + // Returns the height of a string + auto GetStringHeight(const char* s) -> float; + auto GetStringHeight(const std::string& s) -> float { + return GetStringHeight(s.c_str()); + } + + // Given a target width, breaks the string up into multiple strings so they + // fit within it + void BreakUpString(const char* text, float width, + std::vector* v); + + // Some chars we allow the OS to draw in some cases but draw ourselves in + // others (to minimize the amount of switching back and forth). + static auto IsOSDrawableAscii(int val) -> bool { + // ( exclude a few that usually come in pairs so we + // avoid one side looking different than the other ) + return (((val >= ' ' && val <= '/') || (val >= ':' && val <= '@') + || (val >= '[' && val <= '`') || (val >= '{' && val <= '~')) + && (val != '\'') && (val != '"') && (val != '[') && (val != ']') + && (val != '{') && (val != '}') && (val != '(') && (val != ')')); + } + + private: + class TextSpanBoundsCacheEntry; + void LoadGlyphPage(uint32_t index); + + // Map of entries for fast lookup. + std::map > + text_span_bounds_cache_map_; + + // List of entries for sorting by last-use-time + std::list > text_span_bounds_cache_; + std::mutex glyph_load_mutex_; + Glyph glyphs_extras_[100]{}; + Glyph glyphs_big_[64]{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_TEXT_TEXT_GRAPHICS_H_ diff --git a/src/ballistica/graphics/text/text_group.cc b/src/ballistica/graphics/text/text_group.cc new file mode 100644 index 00000000..0b5d7947 --- /dev/null +++ b/src/ballistica/graphics/text/text_group.cc @@ -0,0 +1,324 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/text/text_group.h" + +#include +#include +#include + +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/graphics/text/text_packer.h" + +namespace ballistica { + +void TextGroup::SetText(const std::string& text, TextMesh::HAlign alignment_h, + TextMesh::VAlign alignment_v, bool big, + float resolution_scale) { + text_ = text; + + // In order to *actually* draw big, all our letters + // must be available in the big font. + big_ = (big && TextGraphics::HaveBigChars(text)); + + // If we had an OS texture for custom drawing, release it. + // (it should stick around for a while; we'll be able to re-grab + // the same one if we havn't changed) + os_texture_.Clear(); + + // If we're drawing big we always just need 1 font page (the big one). + if (big_) { + // Now create entries for each page we use. + entries_.clear(); + std::unique_ptr entry(new TextMeshEntry()); + entry->u_scale = entry->v_scale = 1.5f; + entry->can_color = true; + entry->max_flatness = 1.0f; + entry->mesh.SetText(text, alignment_h, alignment_v, true, 0, 65535, + TextMeshEntryType::kRegular, nullptr); + entry->tex = g_media->GetTexture(SystemTextureID::kFontBig); + entries_.push_back(std::move(entry)); + + } else { + // Drawing non-big; we might use any number of font pages. + + // First, calc which font pages we'll need to draw this text. + std::set font_pages; + g_text_graphics->GetFontPagesForText(text, &font_pages); + + // Now create entries for each page we use. + // (we iterate this in reverse so that our custom pages draw first; + // we want that stuff to show up underneath normal text since we + // sometimes use it as backing elements,etc) + entries_.clear(); + for (auto i = font_pages.rbegin(); i != font_pages.rend(); i++) { + uint32_t min, max; + g_text_graphics->GetFontPageCharRange(*i, &min, &max); + std::unique_ptr entry(new TextMeshEntry()); + + // Our custom font page IDs start at value 9990 (kExtras1); + // make sure for all private-use unicode chars (U+E000–U+F8FF) + // that we only use these font pages and not OS rendering or other + // pages (even if those technically support that range) + if (*i >= static_cast(TextGraphics::FontPage::kExtras1)) { + entry->type = TextMeshEntryType::kExtras; + entry->u_scale = entry->v_scale = 3.0f; + entry->max_flatness = 1.0f; + } else if (*i == static_cast(TextGraphics::FontPage::kOSRendered)) { + entry->type = TextMeshEntryType::kOSRendered; + + // Let's allow partial flattening of OS text (keeps emojis somewhat + // recognizable but allows us to set it apart from our icons and + // whatnot which are always full color) + // entry->max_flatness = 0.65f; + + // UPDATE: scratch that; washed out emojis just look crappy. + entry->max_flatness = 0.0f; + + // We'll set uv_scale for this guy below; we don't know what it is + // until we've generated our text-packer. + } else { + entry->type = TextMeshEntryType::kRegular; + entry->u_scale = entry->v_scale = 1.0f; + entry->max_flatness = 1.0f; + } + + // Currently we can color or flatten everything except the second, third, + // and fourth extras pages (those are all pre-colored characters; + // flattening or coloring would mess them up) + entry->can_color = + ((*i != static_cast(TextGraphics::FontPage::kExtras2)) + && (*i != static_cast(TextGraphics::FontPage::kExtras3)) + && (*i != static_cast(TextGraphics::FontPage::kExtras4))); + + // For the few we can't color, we don't want to be able to + // flatten them either. + if (!entry->can_color) entry->max_flatness = 0.0f; + + // For OS-rendered text we fill out a text-packer will all the spans + // we'll need. we then hand that over to the OS to draw and create + // our texture from that. + Object::Ref packer; + if (entry->type == TextMeshEntryType::kOSRendered) { + packer = Object::New(resolution_scale); + } + + entry->mesh.SetText(text, alignment_h, alignment_v, false, min, max, + entry->type, packer.get()); + + if (packer.exists()) { + // If we made a text-packer, we need to fetch/generate a texture + // that matches it. + // There should only ever be one of these. + assert(!os_texture_.exists()); + { + Media::MediaListsLock lock; + os_texture_ = g_media->GetTextureData(packer.get()); + } + + // We also need to know what uv-scales to use for shadows/etc. + // This should be proportional to the font-scale over the texture + // dimension so that its always visually similar. + float t_scale = packer->text_scale() * 500.0f; + entry->u_scale = t_scale / static_cast(packer->texture_width()); + entry->v_scale = t_scale / static_cast(packer->texture_height()); + } + switch (*i) { + case 0: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall0); + break; + case 1: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall1); + break; + case 2: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall2); + break; + case 3: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall3); + break; + case 4: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall4); + break; + case 5: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall5); + break; + case 6: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall6); + break; + case 7: + entry->tex = g_media->GetTexture(SystemTextureID::kFontSmall7); + break; + case static_cast(TextGraphics::FontPage::kOSRendered): + entry->tex = os_texture_; + break; + case static_cast(TextGraphics::FontPage::kExtras1): + entry->tex = g_media->GetTexture(SystemTextureID::kFontExtras); + break; + case static_cast(TextGraphics::FontPage::kExtras2): + entry->tex = g_media->GetTexture(SystemTextureID::kFontExtras2); + break; + case static_cast(TextGraphics::FontPage::kExtras3): + entry->tex = g_media->GetTexture(SystemTextureID::kFontExtras3); + break; + case static_cast(TextGraphics::FontPage::kExtras4): + entry->tex = g_media->GetTexture(SystemTextureID::kFontExtras4); + break; + default: + throw Exception(); + } + entries_.push_back(std::move(entry)); + } + } +} + +void TextGroup::GetCaratPts(const std::string& text_in, + TextMesh::HAlign alignment_h, + TextMesh::VAlign alignment_v, int carat_position, + float* carat_x, float* carat_y) { + assert(carat_x && carat_y); + assert(Utils::IsValidUTF8(text_in)); + const char* txt = text_in.c_str(); + float x = 0; + float x_offset; + float y_offset; + x_offset = x; + float char_width{32.0}; + uint32_t char_val; + float row_height = kTextRowHeight; + float line_length; + float l{0.0f}; + float r{0.0f}; + float b{0.0f}; + float t{0.0f}; + float text_height; + float char_offset_h{-3.0f}; + float char_offset_v{-3.0f}; + + // Calc the height of the text where needed. + switch (alignment_v) { + case TextMesh::VAlign::kNone: + case TextMesh::VAlign::kTop: + text_height = 0; // Not used here. + break; + case TextMesh::VAlign::kCenter: + case TextMesh::VAlign::kBottom: { + int rows = 1; + for (const char* c = txt; *c != 0; c++) { + if (*c == '\n') rows++; + } + text_height = static_cast(rows) * row_height; + break; + } + default: + throw Exception(); + } + switch (alignment_v) { + case TextMesh::VAlign::kNone: + y_offset = b + char_offset_v; + break; + case TextMesh::VAlign::kTop: + y_offset = b + char_offset_v + (t - b) - row_height; + break; + case TextMesh::VAlign::kCenter: + y_offset = + b + char_offset_v + ((t - b) / 2) + (text_height / 2) - row_height; + break; + case TextMesh::VAlign::kBottom: + y_offset = b + char_offset_v + text_height - row_height; + break; + default: + throw Exception(); + } + const char* tc = txt; + bool first_char = true; + std::vector line; + int char_num = 0; + while (*tc != 0) { + const char* tv_prev = tc; + char_val = Utils::GetUTF8Value(tc); + Utils::AdvanceUTF8(&tc); + + // Reset alignment on new lines. + if (first_char || char_val == '\n') { + switch (alignment_h) { + case TextMesh::HAlign::kLeft: + x_offset = l + char_offset_h; + line.clear(); + break; + case TextMesh::HAlign::kCenter: + case TextMesh::HAlign::kRight: { + // Find the length of this line. + line_length = 0; + const char* c; + + // If this was the first char, include it in this line tally + // if it was a newline, don't. + if (first_char) { + c = tv_prev; + } else { + c = tc; + } + while (true) { + // Note Sept 2019: this was set to uint8_t. Assuming that was an + // accident? + uint32_t val; + if (*c == 0) { // NOLINT(bugprone-branch-clone) + break; + } else if (*c == '\n') { + break; + } else { + val = Utils::GetUTF8Value(c); + Utils::AdvanceUTF8(&c); + + // Special case: if we're already doing an OS-span, tack certain + // chars onto it instead of switching back to glyph mode. + // (to reduce the number of times we switch back and forth) + if (TextGraphics::Glyph* g = + g_text_graphics->GetGlyph(val, big_)) { + line_length += char_width * g->advance; + } else { + // TODO(ericf): add non-glyph chars into spans and ask + // the OS for their length + } + } + } + if (alignment_h == TextMesh::HAlign::kCenter) { + x_offset = l + char_offset_h + ((r - l) / 2) - (line_length / 2); + line.clear(); + } else { + x_offset = l + char_offset_h + (r - l) - line_length; + line.clear(); + } + break; + } + default: + throw Exception(); + } + first_char = false; + } + switch (char_val) { + case '\n': + y_offset -= row_height; + break; + case '\r': + case ' ': + break; + default: { + } + } + if (carat_position == char_num) { + break; + } + if (char_val != '\n') { + line.push_back(char_val); + } + char_num++; + } + *carat_x = + x_offset + + g_text_graphics->GetStringWidth(Utils::UTF8FromUnicode(line).c_str()); + *carat_y = y_offset; +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/text/text_group.h b/src/ballistica/graphics/text/text_group.h new file mode 100644 index 00000000..a9756e25 --- /dev/null +++ b/src/ballistica/graphics/text/text_group.h @@ -0,0 +1,85 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXT_TEXT_GROUP_H_ +#define BALLISTICA_GRAPHICS_TEXT_TEXT_GROUP_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/graphics/mesh/text_mesh.h" +#include "ballistica/media/data/texture_data.h" +#include "ballistica/media/media.h" + +namespace ballistica { + +// encapsulates the multiple meshes and textures necessary to +// draw arbitrary text. To actually draw the text, iterate over the meshes +// and textures this class provides to you, drawing each in the same manner +class TextGroup : public Object { + public: + // the number of meshes needing to be drawn for this text + auto GetElementCount() -> int { return static_cast(entries_.size()); } + auto GetElementMesh(int index) const -> TextMesh* { + assert(index < static_cast(entries_.size())); + return &(entries_[index]->mesh); + } + auto GetElementTexture(int index) const -> TextureData* { + assert(index < static_cast(entries_.size())); + return entries_[index]->tex.get(); + } + // if you are doing any shader effects in UV-space (such as drop-shadows), + // scale them by this ..this will account for different character sheets + // with different sized characters + auto GetElementUScale(int index) -> float { + assert(index < static_cast(entries_.size())); + return entries_[index]->u_scale; + } + auto GetElementVScale(int index) -> float { + assert(index < static_cast(entries_.size())); + return entries_[index]->v_scale; + } + auto GetElementMaxFlatness(int index) const -> float { + assert(index < static_cast(entries_.size())); + return entries_[index]->max_flatness; + } + auto GetElementCanColor(int index) const -> bool { + assert(index < static_cast(entries_.size())); + return entries_[index]->can_color; + } + auto GetElementMaskUV2Texture(int index) const -> TextureData* { + assert(index < static_cast(entries_.size())); + return g_media->GetTexture(entries_[index]->type + == TextMeshEntryType::kOSRendered + ? SystemTextureID::kSoftRect2 + : SystemTextureID::kSoftRect); + } + void SetText(const std::string& text, + TextMesh::HAlign alignment_h = TextMesh::HAlign::kLeft, + TextMesh::VAlign alignment_v = TextMesh::VAlign::kNone, + bool big = false, float resolution_scale = 1.0f); + auto getText() const -> const std::string& { return text_; } + void GetCaratPts(const std::string& text_in, TextMesh::HAlign alignment_h, + TextMesh::VAlign alignment_v, int carat_pos, float* carat_x, + float* carat_y); + + private: + struct TextMeshEntry { + TextMeshEntryType type; + Object::Ref tex; + TextMesh mesh; + float u_scale; + float v_scale; + bool can_color; + float max_flatness; + }; + Object::Ref os_texture_; + std::vector> entries_; + std::string text_; + bool big_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_TEXT_TEXT_GROUP_H_ diff --git a/src/ballistica/graphics/text/text_packer.cc b/src/ballistica/graphics/text/text_packer.cc new file mode 100644 index 00000000..384d1f46 --- /dev/null +++ b/src/ballistica/graphics/text/text_packer.cc @@ -0,0 +1,205 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/text/text_packer.h" + +#include + +namespace ballistica { + +TextPacker::TextPacker(float resolution_scale) + : resolution_scale_{resolution_scale} {} + +TextPacker::~TextPacker() = default; + +void TextPacker::AddSpan(const std::string& text, float x, float y, + const Rect& bounds) { + spans_.emplace_back(); + Span& s(spans_.back()); + s.string = text; + s.x = x; + s.y = y; + s.u_min = 0.0f; + s.u_max = 1.0f; + s.v_min = 0.0f; + s.v_max = 1.0f; + s.bounds = bounds; +} + +// FIXME - we currently run into minor problems because we measure our text +// bounds at one size and then scale that linearly when trying to fit things +// into the texture. However, fonts don't always scale linearly (and even when +// that's an option it can be expensive). + +void TextPacker::compile() { + assert(!compiled_); + if (spans_.empty()) { + compiled_ = true; + return; + } + float max_width = 2048.0; + float max_height = 2048.0; + float width = 32.0; + float height = 32.0; + float scale = resolution_scale_ * 2.0f; + float span_buffer = 3.0f; // Note: buffer scales along with text. + float widest_unscaled_span_width = 0.0f; + + // Find our widest span width; we'll use this to determine the width + // of the texture (and whether we need to scale our text down to fit). + for (auto& span : spans_) { + float w = span.bounds.width() + 2.0f * span_buffer; + if (w > widest_unscaled_span_width) widest_unscaled_span_width = w; + } + + // Ok, lets crank our width up until its a bit wider than the widest span + // width (should hopefully allow for at least a few spans per line in + // general). + while (width < (widest_unscaled_span_width * scale * 1.2f) + && width < max_width) { + width *= 2; + } + + // Alternately, if we're too big, crank our scale down so that our widest span + // fits. + if (widest_unscaled_span_width * scale > width * 0.9f) { + scale *= ((width * 0.9f) / (widest_unscaled_span_width * scale)); + } + float start_height = height; + int mini_shrink_tries = 0; + + // Ok; we've now locked in a width and scale. + // Now we go through and position our spans. + // We may need to do this more than once if our height comes out too big. + // (hopefully this will never be a problem in practice) + while (true) { + height = start_height; + + // We currently just lay out left-to-right, top-to-bottom. + // This could be somewhat wasteful in particular configurations. + // (leaving half-filled lines, etc) so it might be worth improving later. + float widest_fill_right = 0.0f; + float fill_right = 0.0f; + float fill_bottom = 0.0f; + float line_height = 0.0f; + for (auto&& i : spans_) { + float span_width = (i.bounds.width() + 2.0f * span_buffer) * scale; + float span_height = + (std::abs(i.bounds.height()) + 2.0f * span_buffer) * scale; + + // Start a new line if this would put us past the end. + if (fill_right + span_width > width) { + if (fill_right > widest_fill_right) { + widest_fill_right = fill_right; // Keep track of how far over we go. + } + fill_right = 0.0f; + fill_bottom += line_height; + line_height = 0.0f; + } + + // Position x such that x + left bound - buffer lines up with our current + // right point. + float to_left = (i.bounds.l - span_buffer) * scale; + i.tex_x = fill_right - to_left; + fill_right += span_width; + + // Position y such that y - top bound - buffer lines up with our current + // bottom point. + float to_top = (-i.bounds.t - span_buffer) * scale; + i.tex_y = fill_bottom - to_top; + + // If our total height is greater than the current line height, expand the + // line's. + if (span_height > line_height) { + line_height = span_height; + } + + // Increase height if need be. + while ((fill_bottom + line_height) > height) { + height *= 2; + } + } + if (fill_right > widest_fill_right) widest_fill_right = fill_right; + + float mini_shrink_threshold_h = 0.55f; + float mini_shrink_threshold_v = 0.55f; + + if (height > max_height) { + // If it doesn't fit, repeat again with a smaller scale until it does. + + // Dropping our scale has a disproportional effect on the final height + // (since it opens up more relative horizontal space). + // I'm not sure how to figure out how much to drop by other than + // incrementally dropping values until we fit. + scale *= 0.75f; + + } else if (((widest_fill_right < (width * mini_shrink_threshold_h) + && width > 16) + || fill_bottom + line_height + < (height * mini_shrink_threshold_v)) + && mini_shrink_tries < 3) { + // If we're here it means we *barely* use more than half of the texture in + // one direction or the other; let's shrink just a tiny bit and we should + // be able to chop our texture size in half + if (widest_fill_right < width * mini_shrink_threshold_h && width > 16) { + float scale_val = 0.99f * (((width * 0.5f) / widest_fill_right)); + if (scale_val < 1.0f) { + // FIXME - should think about a fixed multiplier here; + // under the hood the system might be caching glyphs based on scale + // and this would leave us with fewer different scales in the end and + // thus better caching performance + scale *= scale_val; + } + width /= 2; + } else { + float scale_val = 0.99f * (height * 0.5f) / (fill_bottom + line_height); + if (scale_val < 1.0f) { + // FIXME - should think about a fixed multiplier here; + // under the hood the system might be caching glyphs based on scale + // and this would leave us with fewer different scales in the end and + // thus better caching performance + scale *= scale_val; + } + } + mini_shrink_tries += 1; + } else { + // we fit; hooray! + break; + } + } + + // Lastly, now that our texture width and height are completely finalized, we + // can calculate UVs. + for (auto&& i : spans_) { + // Now store uv coords for this span; they should include the buffer. + i.u_min = (i.tex_x + (i.bounds.l - span_buffer) * scale) / width; + i.u_max = (i.tex_x + (i.bounds.r + span_buffer) * scale) / width; + i.v_max = (i.tex_y + (-i.bounds.b + span_buffer) * scale) / height; + i.v_min = (i.tex_y + (-i.bounds.t - span_buffer) * scale) / height; + + // Also calculate draw-bounds which accounts for our buffer. + i.draw_bounds.l = (i.bounds.l - span_buffer); + i.draw_bounds.r = (i.bounds.r + span_buffer); + i.draw_bounds.t = (i.bounds.t + span_buffer); + i.draw_bounds.b = (i.bounds.b - span_buffer); + } + + // TODO(ericf): now we calculate a hash that's unique to this text + // configuration; we'll use that as a key for the texture we'll generate/use. + // ..this way multiple meshes can share the same generated texture. + // *technically* we could calculate this hash and check for an existing + // texture before we bother laying out our spans, but that might not save us + // much time and would complicate things. + hash_ = std::to_string(resolution_scale_); + for (auto&& i : spans_) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "!SP!%f|%f|", i.x, i.y); + hash_ += buffer; + hash_ += i.string; + } + texture_width_ = static_cast(width); + texture_height_ = static_cast(height); + text_scale_ = scale; + compiled_ = true; +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/text/text_packer.h b/src/ballistica/graphics/text/text_packer.h new file mode 100644 index 00000000..0a8d0509 --- /dev/null +++ b/src/ballistica/graphics/text/text_packer.h @@ -0,0 +1,85 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXT_TEXT_PACKER_H_ +#define BALLISTICA_GRAPHICS_TEXT_TEXT_PACKER_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/math/rect.h" + +namespace ballistica { + +class TextPacker : public Object { + public: + explicit TextPacker(float resolution_scale); + ~TextPacker() override; + + // Adds a span. We could calculate bounds ourselves, but it's often needed + // outside of here anyway so might as well recycle. + void AddSpan(const std::string& text, float x, float y, const Rect& bounds); + + auto hash() const -> const std::string& { + assert(compiled_); + return hash_; + } + + struct Span { + std::vector unichars; + std::string string; + + // Position to draw this span at. + float x; + float y; + + // Bounds to draw this span with. + Rect draw_bounds; + + // Texture position to draw this span's text at. + float tex_x; + float tex_y; + + // Text-space bounds. + Rect bounds; + float u_min; + float u_max; + float v_min; + float v_max; + }; + + // Once done adding spans, call this to calculate final span UV values, + // texture configuration, and hash. + void compile(); + + auto spans() const -> const std::list& { return spans_; } + + auto texture_width() const -> int { + assert(compiled_); + return texture_width_; + } + + auto texture_height() const -> int { + assert(compiled_); + return texture_height_; + } + + auto text_scale() const -> float { + assert(compiled_); + return text_scale_; + } + + private: + float resolution_scale_; + int texture_width_{}; + int texture_height_{}; + float text_scale_{}; + std::string hash_; + bool compiled_{false}; + std::list spans_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_TEXT_TEXT_PACKER_H_ diff --git a/src/ballistica/graphics/texture/dds.cc b/src/ballistica/graphics/texture/dds.cc new file mode 100644 index 00000000..b3748ba2 --- /dev/null +++ b/src/ballistica/graphics/texture/dds.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/texture/dds.h" + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/platform/platform.h" + +#if BA_ENABLE_OPENGL + +/* DDS loader written by Jon Watte 2002 */ +/* Permission granted to use freely, as long as Jon Watte */ +/* is held harmless for all possible damages resulting from */ +/* your use or failure to use this code. */ +/* No warranty is expressed or implied. Use at your own risk, */ +/* or not at all. */ + +namespace ballistica { + +// Should tidy this up to use unsigned vals but don't want to touch for now. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +struct DdsLoadInfo { + bool compressed; + bool swap; + bool palette; + unsigned int divSize; + unsigned int blockBytes; + TextureFormat internal_format; + int externalFormat; + int type; +}; + +DdsLoadInfo loadInfoDXT1 = {true, false, false, 4, 8, TextureFormat::kDXT1}; +DdsLoadInfo loadInfoDXT5 = {true, false, false, 4, 16, TextureFormat::kDXT5}; +DdsLoadInfo loadInfoETC1 = {true, false, false, 4, 8, TextureFormat::kETC1}; + +void LoadDDS(const std::string& file_name, unsigned char** buffers, int* widths, + int* heights, TextureFormat* formats, size_t* sizes, + TextureQuality texture_quality, int min_quality, int* base_level) { + (*base_level) = 0; + + FILE* f = g_platform->FOpen(file_name.c_str(), "rb"); + if (!f) throw Exception("can't open file: \"" + file_name + "\""); + + DDS_header hdr{}; + + // DDS is so simple to read, too + BA_PRECONDITION(fread(&hdr, sizeof(hdr), 1, f) == 1); + BA_PRECONDITION(hdr.dwMagic == DDS_MAGIC); + BA_PRECONDITION(hdr.dwSize == 124); + + if (hdr.dwMagic != DDS_MAGIC || hdr.dwSize != 124 + || !(hdr.dwFlags & DDSD_PIXELFORMAT) || !(hdr.dwFlags & DDSD_CAPS)) { + throw Exception("invalid DDS file: \"" + file_name + "\""); + } + + int x_size = static_cast_check_fit(hdr.dwWidth); + int y_size = static_cast_check_fit(hdr.dwHeight); + + BA_PRECONDITION(!(x_size & (x_size - 1))); + BA_PRECONDITION(!(y_size & (y_size - 1))); + + DdsLoadInfo* li; + + if (PF_IS_DXT1(hdr.sPixelFormat)) { + li = &loadInfoDXT1; + } else if (PF_IS_DXT5(hdr.sPixelFormat)) { + li = &loadInfoDXT5; + } else if (PF_IS_EXTENDED(hdr.sPixelFormat)) { + DDS_header_DX10 hExt; + + BA_PRECONDITION(fread(&hExt, sizeof(hExt), 1, f) == 1); + + // Format should be unknown. + // Hmmm we have no way of determining that this is etc1 data so we just + // assume.. ew. + BA_PRECONDITION(hExt.dxgiFormat == 0); + + // Dimension should be tex2d(3). + BA_PRECONDITION(hExt.resourceDimension == 3); + BA_PRECONDITION(hExt.arraySize == 1); + + li = &loadInfoETC1; + + } else { + throw Exception("Unsupported data type in DDS file \"" + file_name + "\""); + } + + auto x = static_cast(x_size); + auto y = static_cast(y_size); + + int mip_map_count = (hdr.dwFlags & DDSD_MIPMAPCOUNT) + ? static_cast(hdr.dwMipMapCount) + : 1; + + // try dropping a level for med/low quality.. + if ((texture_quality == TextureQuality::kLow + || texture_quality == TextureQuality::kMedium) + && (min_quality < 2) && mip_map_count >= (*base_level) + 1) + (*base_level)++; + + // and one more for low in some cases.... + if (texture_quality == TextureQuality::kLow && (min_quality < 1) + && (x_size > 128) && (y_size > 128) && mip_map_count >= (*base_level) + 1) + (*base_level)++; + + if (li->compressed) { + size_t size = std::max(li->divSize, x) / li->divSize + * std::max(li->divSize, y) / li->divSize * li->blockBytes; + + for (int ix = 0; ix < mip_map_count; ++ix) { + // Load or skip levels depending on our quality. + if ((*base_level) <= ix) { + sizes[ix] = static_cast(size); + buffers[ix] = (unsigned char*)malloc(size); + BA_PRECONDITION(buffers[ix]); + widths[ix] = static_cast(x); + heights[ix] = static_cast(y); + formats[ix] = li->internal_format; + BA_PRECONDITION(fread(buffers[ix], size, 1, f) == 1); + } else { + buffers[ix] = nullptr; + BA_PRECONDITION(fseek(f, static_cast_check_fit(size), // NOLINT + SEEK_CUR) + == 0); + } + + x = (x + 1u) >> 1u; + y = (y + 1u) >> 1u; + size = std::max(li->divSize, x) / li->divSize * std::max(li->divSize, y) + / li->divSize * li->blockBytes; + } + } else if (li->palette) { + throw Exception("palette support disabled"); + } else { + throw Exception("regular tex dds support disabled"); + } + fclose(f); +} + +#pragma clang diagnostic pop + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL diff --git a/src/ballistica/graphics/texture/dds.h b/src/ballistica/graphics/texture/dds.h new file mode 100644 index 00000000..4d7a050d --- /dev/null +++ b/src/ballistica/graphics/texture/dds.h @@ -0,0 +1,157 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXTURE_DDS_H_ +#define BALLISTICA_GRAPHICS_TEXTURE_DDS_H_ + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCUnusedMacroInspection" + +/* DDS loader written by Jon Watte 2002 */ +/* Permission granted to use freely, as long as Jon Watte */ +/* is held harmless for all possible damages resulting from */ +/* your use or failure to use this code. */ +/* No warranty is expressed or implied. Use at your own risk, */ +/* or not at all. */ + +#include + +#include "ballistica/ballistica.h" + +#if BA_ENABLE_OPENGL + +// little-endian, of course +#define DDS_MAGIC 0x20534444 + +// DDS_header.dwFlags +#define DDSD_CAPS 0x00000001 +#define DDSD_HEIGHT 0x00000002 +#define DDSD_WIDTH 0x00000004 +#define DDSD_PITCH 0x00000008 +#define DDSD_PIXELFORMAT 0x00001000 +#define DDSD_MIPMAPCOUNT 0x00020000 +#define DDSD_LINEARSIZE 0x00080000 +#define DDSD_DEPTH 0x00800000 + +// DDS_header.sPixelFormat.dwFlags +#define DDPF_ALPHAPIXELS 0x00000001 +#define DDPF_FOURCC 0x00000004 +#define DDPF_INDEXED 0x00000020 +#define DDPF_RGB 0x00000040 + +// DDS_header.sCaps.dwCaps1 +#define DDSCAPS_COMPLEX 0x00000008 +#define DDSCAPS_TEXTURE 0x00001000 +#define DDSCAPS_MIPMAP 0x00400000 + +// DDS_header.sCaps.dwCaps2 +#define DDSCAPS2_CUBEMAP 0x00000200 +#define DDSCAPS2_CUBEMAP_POSITIVEX 0x00000400 +#define DDSCAPS2_CUBEMAP_NEGATIVEX 0x00000800 +#define DDSCAPS2_CUBEMAP_POSITIVEY 0x00001000 +#define DDSCAPS2_CUBEMAP_NEGATIVEY 0x00002000 +#define DDSCAPS2_CUBEMAP_POSITIVEZ 0x00004000 +#define DDSCAPS2_CUBEMAP_NEGATIVEZ 0x00008000 +#define DDSCAPS2_VOLUME 0x00200000 + +#define D3DFMT_DXT1 0x31545844 // '1TXD' - DXT1 compression texture format +#define D3DFMT_DXT2 0x32545844 // '2TXD' - DXT2 compression texture format +#define D3DFMT_DXT3 0x33545844 // '3TXD' - DXT3 compression texture format +#define D3DFMT_DXT4 0x34545844 // '4TXD' - DXT4 compression texture format +#define D3DFMT_DXT5 0x35545844 // '5TXD' - DXT5 compression texture format + +#define D3DFMT_EXTENDED 0x30315844 // '01XD' - newer dds format + +#define PF_IS_EXTENDED(pf) \ + (((pf).dwFlags & DDPF_FOURCC) && ((pf).dwFourCC == D3DFMT_EXTENDED)) + +#define PF_IS_DXT1(pf) \ + (((pf).dwFlags & DDPF_FOURCC) && ((pf).dwFourCC == D3DFMT_DXT1)) + +#define PF_IS_DXT3(pf) \ + (((pf).dwFlags & DDPF_FOURCC) && ((pf).dwFourCC == D3DFMT_DXT3)) + +#define PF_IS_DXT5(pf) \ + (((pf).dwFlags & DDPF_FOURCC) && ((pf).dwFourCC == D3DFMT_DXT5)) + +#define PF_IS_BGRA8(pf) \ + (((pf).dwFlags & DDPF_RGB) && ((pf).dwFlags & DDPF_ALPHAPIXELS) \ + && ((pf).dwRGBBitCount == 32) && ((pf).dwRBitMask == 0xff0000) \ + && ((pf).dwGBitMask == 0xff00) && ((pf).dwBBitMask == 0xff) \ + && ((pf).dwAlphaBitMask == 0xff000000U)) + +#define PF_IS_BGR8(pf) \ + (((pf).dwFlags & DDPF_ALPHAPIXELS) && !((pf).dwFlags & DDPF_ALPHAPIXELS) \ + && ((pf).dwRGBBitCount == 24) && ((pf).dwRBitMask == 0xff0000) \ + && ((pf).dwGBitMask == 0xff00) && ((pf).dwBBitMask == 0xff)) + +#define PF_IS_BGR5A1(pf) \ + (((pf).dwFlags & DDPF_RGB) && ((pf).dwFlags & DDPF_ALPHAPIXELS) \ + && ((pf).dwRGBBitCount == 16) && ((pf).dwRBitMask == 0x00007c00) \ + && ((pf).dwGBitMask == 0x000003e0) && ((pf).dwBBitMask == 0x0000001f) \ + && ((pf).dwAlphaBitMask == 0x00008000)) + +#define PF_IS_BGR565(pf) \ + (((pf).dwFlags & DDPF_RGB) && !((pf).dwFlags & DDPF_ALPHAPIXELS) \ + && ((pf).dwRGBBitCount == 16) && ((pf).dwRBitMask == 0x0000f800) \ + && ((pf).dwGBitMask == 0x000007e0) && ((pf).dwBBitMask == 0x0000001f)) + +#define PF_IS_INDEX8(pf) \ + (((pf).dwFlags & DDPF_INDEXED) && ((pf).dwRGBBitCount == 8)) + +#pragma clang diagnostic pop + +namespace ballistica { + +union DDS_header { + struct { + unsigned int dwMagic; + unsigned int dwSize; + unsigned int dwFlags; + unsigned int dwHeight; + unsigned int dwWidth; + unsigned int dwPitchOrLinearSize; + unsigned int dwDepth; + unsigned int dwMipMapCount; + unsigned int dwReserved1[11]; + + // DDPIXELFORMAT + struct { + unsigned int dwSize; + unsigned int dwFlags; + unsigned int dwFourCC; + unsigned int dwRGBBitCount; + unsigned int dwRBitMask; + unsigned int dwGBitMask; + unsigned int dwBBitMask; + unsigned int dwAlphaBitMask; + } sPixelFormat; + + // DDCAPS2 + struct { + unsigned int dwCaps1; + unsigned int dwCaps2; + unsigned int dwDDSX; + unsigned int dwReserved; + } sCaps; + unsigned int dwReserved2; + }; + char data[128]; +}; + +typedef struct { + unsigned int dxgiFormat; + unsigned int resourceDimension; + unsigned int miscFlag; + unsigned int arraySize; + unsigned int reserved; +} DDS_header_DX10; + +void LoadDDS(const std::string& file_name, unsigned char** buffers, int* widths, + int* heights, TextureFormat* formats, size_t* sizes, + TextureQuality texture_quality, int min_quality, int* base_level); + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL + +#endif // BALLISTICA_GRAPHICS_TEXTURE_DDS_H_ diff --git a/src/ballistica/graphics/texture/ktx.cc b/src/ballistica/graphics/texture/ktx.cc new file mode 100644 index 00000000..ec3b3f12 --- /dev/null +++ b/src/ballistica/graphics/texture/ktx.cc @@ -0,0 +1,2291 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/texture/ktx.h" + +#include "ballistica/platform/platform.h" + +#if !BA_HEADLESS_BUILD + +namespace ballistica { + +// Inspection is not terribly happy about this file but it works so not +// gonna touch it for now. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "bugprone-narrowing-conversions" +#pragma ide diagnostic ignored "bugprone-macro-parentheses" +#pragma ide diagnostic ignored "UnusedValue" + +#pragma ide diagnostic ignored "cppcoreguidelines-narrowing-conversions" +#pragma ide diagnostic ignored "OCUnusedMacroInspection" +#pragma ide diagnostic ignored "clang-analyzer-deadcode.DeadStores" +#pragma clang diagnostic ignored "-Wunused-variable" + +// We don't want this to be dependent on GL so +// lets just define the few bits we need here +#ifndef GL_COMPRESSED_RGB8_ETC2 +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif +#ifndef GL_ETC1_RGB8_OES +#define GL_ETC1_RGB8_OES 0x8D64 +#endif +#ifndef GL_RGB +#define GL_RGB 0x1907 +#endif +#ifndef GL_RGBA +#define GL_RGBA 0x1908 +#endif +#ifndef GL_UNSIGNED_BYTE +#define GL_UNSIGNED_BYTE 0x1401 +#endif +typedef uint8_t GLubyte; +typedef unsigned int GLenum; +typedef int GLint; + +#define KTX_IDENTIFIER_REF \ + { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A } +#define KTX_ENDIAN_REF (0x04030201) +#define KTX_ENDIAN_REF_REV (0x01020304) +#define KTX_HEADER_SIZE (64) + +typedef struct KTX_header_t { + uint8_t identifier[12]; + uint32_t endianness; + uint32_t glType; + uint32_t glTypeSize; + uint32_t glFormat; + uint32_t glInternalFormat; + uint32_t glBaseInternalFormat; + uint32_t pixelWidth; + uint32_t pixelHeight; + uint32_t pixelDepth; + uint32_t numberOfArrayElements; + uint32_t numberOfFaces; + uint32_t numberOfMipmapLevels; + uint32_t bytesOfKeyValueData; +} KTX_header; + +void LoadKTX(const std::string& file_name, unsigned char** buffers, int* widths, + int* heights, TextureFormat* formats, size_t* sizes, + TextureQuality texture_quality, int min_quality, int* base_level) { + FILE* f = g_platform->FOpen(file_name.c_str(), "rb"); + if (!f) throw Exception("can't open file: \"" + file_name + "\""); + + KTX_header_t header{}; + static_assert(sizeof(header) == KTX_HEADER_SIZE); + BA_PRECONDITION(fread(&header, sizeof(header), 1, f) == 1); + + // Make some assumptions; we don't support arrays, more than 1 face, or kv + // data of any form. + BA_PRECONDITION(header.endianness == KTX_ENDIAN_REF); + BA_PRECONDITION(header.numberOfArrayElements == 0); + BA_PRECONDITION(header.numberOfFaces == 1); + BA_PRECONDITION(header.bytesOfKeyValueData == 0); + BA_PRECONDITION(header.pixelWidth > 0 && header.pixelHeight > 0 + && header.pixelDepth == 0); + + TextureFormat internal_format; + + if (header.glInternalFormat == GL_COMPRESSED_RGB8_ETC2) { + internal_format = TextureFormat::kETC2_RGB; + // NOLINTNEXTLINE(bugprone-branch-clone) + } else if (header.glInternalFormat == GL_COMPRESSED_RGBA8_ETC2_EAC) { + internal_format = TextureFormat::kETC2_RGBA; + } else if (header.glInternalFormat == GL_COMPRESSED_RGBA8_ETC2_EAC) { + internal_format = TextureFormat::kETC2_RGBA; + } else if (header.glInternalFormat == GL_ETC1_RGB8_OES) { + internal_format = TextureFormat::kETC1; + } else { + throw Exception(); + } + + uint32_t size = 0; + uint32_t sizeRounded = 0; + + int x = header.pixelWidth; + int y = header.pixelHeight; + + (*base_level) = 0; + + // Try dropping a level for med/low quality. + if ((texture_quality == TextureQuality::kLow + || texture_quality == TextureQuality::kMedium) + && (min_quality < 2) + && static_cast_check_fit(header.numberOfMipmapLevels) + >= (*base_level) + 1) { + (*base_level)++; + } + + // And one more for low in some cases. + if (texture_quality == TextureQuality::kLow && (min_quality < 1) + && (header.pixelWidth > 128) && (header.pixelHeight > 128) + && static_cast_check_fit(header.numberOfMipmapLevels) + >= (*base_level) + 1) { + (*base_level)++; + } + + for (uint32_t level = 0; level < header.numberOfMipmapLevels; ++level) { + if (fread(&size, sizeof(size), 1, f) != 1) + throw Exception("Error reading texture: '" + file_name + "'"); + sizeRounded = (size + 3) & ~(uint32_t)3; + BA_PRECONDITION( + size == sizeRounded); // Not currently handling this. Is it necessary? + + if ((*base_level) <= static_cast_check_fit(level)) { + sizes[level] = size; + buffers[level] = (unsigned char*)malloc(size); + BA_PRECONDITION(buffers[level]); + widths[level] = static_cast(x); + heights[level] = static_cast(y); + formats[level] = internal_format; + BA_PRECONDITION(fread(buffers[level], size, 1, f) == 1); + } else { + buffers[level] = nullptr; + BA_PRECONDITION(fseek(f, static_cast_check_fit(size), SEEK_CUR) + == 0); + } + x = (x + 1) >> 1; + y = (y + 1) >> 1; + } + fclose(f); +} + +/** + + @~English + @page licensing Licensing + + @section etcdec etcdec.cxx License + + etcdec.cxx is made available under the terms and conditions of the following + License Agreement. + + Software License Agreement + + PLEASE REVIEW THE FOLLOWING TERMS AND CONDITIONS PRIOR TO USING THE + ERICSSON TEXTURE COMPRESSION CODEC SOFTWARE (THE "SOFTWARE"). THE USE + OF THE SOFTWARE IS SUBJECT TO THE TERMS AND CONDITIONS OF THE + FOLLOWING SOFTWARE LICENSE AGREEMENT (THE "SLA"). IF YOU DO NOT ACCEPT + SUCH TERMS AND CONDITIONS YOU MAY NOT USE THE SOFTWARE. + + Subject to the terms and conditions of the SLA, the licensee of the + Software (the "Licensee") hereby, receives a non-exclusive, + non-transferable, limited, free-of-charge, perpetual and worldwide + license, to copy, use, distribute and modify the Software, but only + for the purpose of developing, manufacturing, selling, using and + distributing products including the Software in binary form, which + products are used for compression and/or decompression according to + the Khronos standard specifications OpenGL, OpenGL ES and + WebGL. Notwithstanding anything of the above, Licensee may distribute + [etcdec.cxx] in source code form provided (i) it is in unmodified + form; and (ii) it is included in software owned by Licensee. + + If Licensee institutes, or threatens to institute, patent litigation + against Ericsson or Ericsson's affiliates for using the Software for + developing, having developed, manufacturing, having manufactured, + selling, offer for sale, importing, using, leasing, operating, + repairing and/or distributing products (i) within the scope of the + Khronos framework; or (ii) using software or other intellectual + property rights owned by Ericsson or its affiliates and provided under + the Khronos framework, Ericsson shall have the right to terminate this + SLA with immediate effect. Moreover, if Licensee institutes, or + threatens to institute, patent litigation against any other licensee + of the Software for using the Software in products within the scope of + the Khronos framework, Ericsson shall have the right to terminate this + SLA with immediate effect. However, should Licensee institute, or + threaten to institute, patent litigation against any other licensee of + the Software based on such other licensee's use of any other software + together with the Software, then Ericsson shall have no right to + terminate this SLA. + + This SLA does not transfer to Licensee any ownership to any Ericsson + or third party intellectual property rights. All rights not expressly + granted by Ericsson under this SLA are hereby expressly + reserved. Furthermore, nothing in this SLA shall be construed as a + right to use or sell products in a manner which conveys or purports to + convey whether explicitly, by principles of implied license, or + otherwise, any rights to any third party, under any patent of Ericsson + or of Ericsson's affiliates covering or relating to any combination of + the Software with any other software or product (not licensed + hereunder) where the right applies specifically to the combination and + not to the software or product itself. + + THE SOFTWARE IS PROVIDED "AS IS". ERICSSON MAKES NO REPRESENTATIONS OF + ANY KIND, EXTENDS NO WARRANTIES OR CONDITIONS OF ANY KIND, EITHER + EXPRESS, IMPLIED OR STATUTORY; INCLUDING, BUT NOT LIMITED TO, EXPRESS, + IMPLIED OR STATUTORY WARRANTIES OR CONDITIONS OF TITLE, + MERCHANTABILITY, SATISFACTORY QUALITY, SUITABILITY, AND FITNESS FOR A + PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE + OF THE SOFTWARE IS WITH THE LICENSEE. SHOULD THE SOFTWARE PROVE + DEFECTIVE, THE LICENSEE ASSUMES THE COST OF ALL NECESSARY SERVICING, + REPAIR OR CORRECTION. ERICSSON MAKES NO WARRANTY THAT THE MANUFACTURE, + SALE, OFFERING FOR SALE, DISTRIBUTION, LEASE, USE OR IMPORTATION UNDER + THE SLA WILL BE FREE FROM INFRINGEMENT OF PATENTS, COPYRIGHTS OR OTHER + INTELLECTUAL PROPERTY RIGHTS OF OTHERS, AND THE VALIDITY OF THE + LICENSE AND THE SLA ARE SUBJECT TO LICENSEE'S SOLE RESPONSIBILITY TO + MAKE SUCH DETERMINATION AND ACQUIRE SUCH LICENSES AS MAY BE NECESSARY + WITH RESPECT TO PATENTS, COPYRIGHT AND OTHER INTELLECTUAL PROPERTY OF + THIRD PARTIES. + + THE LICENSEE ACKNOWLEDGES AND ACCEPTS THAT THE SOFTWARE (I) IS NOT + LICENSED FOR; (II) IS NOT DESIGNED FOR OR INTENDED FOR; AND (III) MAY + NOT BE USED FOR; ANY MISSION CRITICAL APPLICATIONS SUCH AS, BUT NOT + LIMITED TO OPERATION OF NUCLEAR OR HEALTHCARE COMPUTER SYSTEMS AND/OR + NETWORKS, AIRCRAFT OR TRAIN CONTROL AND/OR COMMUNICATION SYSTEMS OR + ANY OTHER COMPUTER SYSTEMS AND/OR NETWORKS OR CONTROL AND/OR + COMMUNICATION SYSTEMS ALL IN WHICH CASE THE FAILURE OF THE SOFTWARE + COULD LEAD TO DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL, MATERIAL OR + ENVIRONMENTAL DAMAGE. LICENSEE'S RIGHTS UNDER THIS LICENSE WILL + TERMINATE AUTOMATICALLY AND IMMEDIATELY WITHOUT NOTICE IF LICENSEE + FAILS TO COMPLY WITH THIS PARAGRAPH. + + IN NO EVENT SHALL ERICSSON BE LIABLE FOR ANY DAMAGES WHATSOEVER, + INCLUDING BUT NOT LIMITED TO PERSONAL INJURY, ANY GENERAL, SPECIAL, + INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF OR IN + CONNECTION WITH THE USE OR INABILITY TO USE THE SOFTWARE (INCLUDING + BUT NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERUPTIONS, OR ANY + OTHER COMMERCIAL DAMAGES OR LOSSES, LOSS OF DATA OR DATA BEING + RENDERED INACCURATE OR LOSSES SUSTAINED BY THE LICENSEE OR THIRD + PARTIES OR A FAILURE OF THE SOFTWARE TO OPERATE WITH ANY OTHER + SOFTWARE) REGARDLESS OF THE THEORY OF LIABILITY (CONTRACT, TORT, OR + OTHERWISE), EVEN IF THE LICENSEE OR ANY OTHER PARTY HAS BEEN ADVISED + OF THE POSSIBILITY OF SUCH DAMAGES. + + Licensee acknowledges that "ERICSSON ///" is the corporate trademark + of Telefonaktiebolaget LM Ericsson and that both "Ericsson" and the + figure "///" are important features of the trade names of + Telefonaktiebolaget LM Ericsson. Nothing contained in these terms and + conditions shall be deemed to grant Licensee any right, title or + interest in the word "Ericsson" or the figure "///". No delay or + omission by Ericsson to exercise any right or power shall impair any + such right or power to be construed to be a waiver thereof. Consent by + Ericsson to, or waiver of, a breach by the Licensee shall not + constitute consent to, waiver of, or excuse for any other different or + subsequent breach. + + This SLA shall be governed by the substantive law of Sweden. Any + dispute, controversy or claim arising out of or in connection with + this SLA, or the breach, termination or invalidity thereof, shall be + submitted to the exclusive jurisdiction of the Swedish Courts. + +*/ + +//// etcpack v2.74 +//// +//// NO WARRANTY +//// +//// BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE THE PROGRAM IS PROVIDED +//// "AS IS". ERICSSON MAKES NO REPRESENTATIONS OF ANY KIND, EXTENDS NO +//// WARRANTIES OR CONDITIONS OF ANY KIND; EITHER EXPRESS, IMPLIED OR +//// STATUTORY; INCLUDING, BUT NOT LIMITED TO, EXPRESS, IMPLIED OR +//// STATUTORY WARRANTIES OR CONDITIONS OF TITLE, MERCHANTABILITY, +//// SATISFACTORY QUALITY, SUITABILITY AND FITNESS FOR A PARTICULAR +//// PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +//// PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME +//// THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. ERICSSON +//// MAKES NO WARRANTY THAT THE MANUFACTURE, SALE, OFFERING FOR SALE, +//// DISTRIBUTION, LEASE, USE OR IMPORTATION UNDER THE LICENSE WILL BE FREE +//// FROM INFRINGEMENT OF PATENTS, COPYRIGHTS OR OTHER INTELLECTUAL +//// PROPERTY RIGHTS OF OTHERS, AND THE VALIDITY OF THE LICENSE IS SUBJECT +//// TO YOUR SOLE RESPONSIBILITY TO MAKE SUCH DETERMINATION AND ACQUIRE +//// SUCH LICENSES AS MAY BE NECESSARY WITH RESPECT TO PATENTS, COPYRIGHT +//// AND OTHER INTELLECTUAL PROPERTY OF THIRD PARTIES. +//// +//// FOR THE AVOIDANCE OF DOUBT THE PROGRAM (I) IS NOT LICENSED FOR; (II) +//// IS NOT DESIGNED FOR OR INTENDED FOR; AND (III) MAY NOT BE USED FOR; +//// ANY MISSION CRITICAL APPLICATIONS SUCH AS, BUT NOT LIMITED TO +//// OPERATION OF NUCLEAR OR HEALTHCARE COMPUTER SYSTEMS AND/OR NETWORKS, +//// AIRCRAFT OR TRAIN CONTROL AND/OR COMMUNICATION SYSTEMS OR ANY OTHER +//// COMPUTER SYSTEMS AND/OR NETWORKS OR CONTROL AND/OR COMMUNICATION +//// SYSTEMS ALL IN WHICH CASE THE FAILURE OF THE PROGRAM COULD LEAD TO +//// DEATH, PERSONAL INJURY, OR SEVERE PHYSICAL, MATERIAL OR ENVIRONMENTAL +//// DAMAGE. YOUR RIGHTS UNDER THIS LICENSE WILL TERMINATE AUTOMATICALLY +//// AND IMMEDIATELY WITHOUT NOTICE IF YOU FAIL TO COMPLY WITH THIS +//// PARAGRAPH. +//// +//// IN NO EVENT WILL ERICSSON, BE LIABLE FOR ANY DAMAGES WHATSOEVER, +//// INCLUDING BUT NOT LIMITED TO PERSONAL INJURY, ANY GENERAL, SPECIAL, +//// INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN +//// CONNECTION WITH THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +//// NOT LIMITED TO LOSS OF PROFITS, BUSINESS INTERUPTIONS, OR ANY OTHER +//// COMMERCIAL DAMAGES OR LOSSES, LOSS OF DATA OR DATA BEING RENDERED +//// INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF +//// THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) REGARDLESS OF THE +//// THEORY OF LIABILITY (CONTRACT, TORT OR OTHERWISE), EVEN IF SUCH HOLDER +//// OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +//// +//// (C) Ericsson AB 2013. All Rights Reserved. +//// + +#include +#include + +// Typedefs +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef short int16; + +// Macros to help with bit extraction/insertion +#define SHIFT(size, startpos) ((startpos) - (size) + 1) +#define MASK(size, startpos) (((2 << (size - 1)) - 1) << SHIFT(size, startpos)) +#define PUTBITS(dest, data, size, startpos) \ + dest = ((dest & ~MASK(size, startpos)) \ + | ((data << SHIFT(size, startpos)) & MASK(size, startpos))) +#define SHIFTHIGH(size, startpos) (((startpos)-32) - (size) + 1) +#define MASKHIGH(size, startpos) \ + (((1 << (size)) - 1) << SHIFTHIGH(size, startpos)) +#define PUTBITSHIGH(dest, data, size, startpos) \ + dest = ((dest & ~MASKHIGH(size, startpos)) \ + | ((data << SHIFTHIGH(size, startpos)) & MASKHIGH(size, startpos))) +#define GETBITS(source, size, startpos) \ + (((source) >> ((startpos) - (size) + 1)) & ((1 << (size)) - 1)) +#define GETBITSHIGH(source, size, startpos) \ + (((source) >> (((startpos)-32) - (size) + 1)) & ((1 << (size)) - 1)) +#ifndef PGMOUT +#define PGMOUT 0 +#endif +// Thumb macros and definitions +#define R_BITS59T 4 +#define G_BITS59T 4 +#define B_BITS59T 4 +#define R_BITS58H 4 +#define G_BITS58H 4 +#define B_BITS58H 4 +#define MAXIMUM_ERROR (255 * 255 * 16 * 1000) +#define R 0 +#define G 1 +#define B 2 +#define BLOCKHEIGHT 4 +#define BLOCKWIDTH 4 +#define BINPOW(power) (1 << (power)) +#define TABLE_BITS_59T 3 +#define TABLE_BITS_58H 3 + +// Helper Macros +#define CLAMP(ll, x, ul) (((x) < (ll)) ? (ll) : (((x) > (ul)) ? (ul) : (x))) +#define JAS_ROUND(x) (((x) < 0.0) ? ((int)((x)-0.5)) : ((int)((x) + 0.5))) + +#define RED_CHANNEL(img, width, x, y, channels) \ + img[channels * (y * width + x) + 0] +#define GREEN_CHANNEL(img, width, x, y, channels) \ + img[channels * (y * width + x) + 1] +#define BLUE_CHANNEL(img, width, x, y, channels) \ + img[channels * (y * width + x) + 2] +#define ALPHA_CHANNEL(img, width, x, y, channels) \ + img[channels * (y * width + x) + 3] + +// Global tables +static uint8 table59T[8] = {3, 6, 11, 16, 23, + 32, 41, 64}; // 3-bit table for the 59 bit T-mode +static uint8 table58H[8] = {3, 6, 11, 16, 23, + 32, 41, 64}; // 3-bit table for the 58 bit H-mode +static int compressParams[16][4] = { + {-8, -2, 2, 8}, {-8, -2, 2, 8}, {-17, -5, 5, 17}, + {-17, -5, 5, 17}, {-29, -9, 9, 29}, {-29, -9, 9, 29}, + {-42, -13, 13, 42}, {-42, -13, 13, 42}, {-60, -18, 18, 60}, + {-60, -18, 18, 60}, {-80, -24, 24, 80}, {-80, -24, 24, 80}, + {-106, -33, 33, 106}, {-106, -33, 33, 106}, {-183, -47, 47, 183}, + {-183, -47, 47, 183}}; +static int unscramble[4] = {2, 3, 1, 0}; +int alphaTableInitialized = 0; +int alphaTable[256][8]; +int alphaBase[16][4] = { + {-15, -9, -6, -3}, {-13, -10, -7, -3}, {-13, -8, -5, -2}, {-13, -6, -4, -2}, + {-12, -8, -6, -3}, {-11, -9, -7, -3}, {-11, -8, -7, -4}, {-11, -8, -5, -3}, + {-10, -8, -6, -2}, {-10, -8, -5, -2}, {-10, -8, -4, -2}, {-10, -7, -5, -2}, + {-10, -7, -4, -3}, {-10, -3, -2, -1}, {-9, -8, -6, -4}, {-9, -7, -5, -3}}; + +// Global variables +int formatSigned = 0; + +// Enums +enum { PATTERN_H = 0, PATTERN_T = 1 }; + +// Code used to create the valtab +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void setupAlphaTable() { + if (alphaTableInitialized) return; + alphaTableInitialized = 1; + + // read table used for alpha compression + int buf; + for (int i = 16; i < 32; i++) { + for (int j = 0; j < 8; j++) { + buf = alphaBase[i - 16][3 - j % 4]; + if (j < 4) + alphaTable[i][j] = buf; + else + alphaTable[i][j] = (-buf - 1); + } + } + + // beyond the first 16 values, the rest of the table is implicit.. so + // calculate that! + for (int i = 0; i < 256; i++) { + // fill remaining slots in table with multiples of the first ones. + int mul = i / 16; + int old = 16 + i % 16; + for (int j = 0; j < 8; j++) { + alphaTable[i][j] = alphaTable[old][j] * mul; + // note: we don't do clamping here, though we could, because we'll be + // clamped afterwards anyway. + } + } +} + +// Read a word in big endian style +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +// void read_big_endian_2byte_word(unsigned short* blockadr, FILE* f) { +// uint8 bytes[2]; +// unsigned short block; + +// fread(&bytes[0], 1, 1, f); +// fread(&bytes[1], 1, 1, f); + +// block = 0; +// block |= bytes[0]; +// block = block << 8; +// block |= bytes[1]; + +// blockadr[0] = block; +// } + +// Read a word in big endian style +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +// void read_big_endian_4byte_word(unsigned int* blockadr, FILE* f) { +// uint8 bytes[4]; +// unsigned int block; + +// fread(&bytes[0], 1, 1, f); +// fread(&bytes[1], 1, 1, f); +// fread(&bytes[2], 1, 1, f); +// fread(&bytes[3], 1, 1, f); + +// block = 0; +// block |= bytes[0]; +// block = block << 8; +// block |= bytes[1]; +// block = block << 8; +// block |= bytes[2]; +// block = block << 8; +// block |= bytes[3]; + +// blockadr[0] = block; +// } + +// The format stores the bits for the three extra modes in a roundabout way to +// be able to fit them without increasing the bit rate. This function converts +// them into something that is easier to work with. NO WARRANTY --- SEE +// STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved. +void unstuff57bits(unsigned int planar_word1, unsigned int planar_word2, + unsigned int& planar57_word1, unsigned int& planar57_word2) { + // Get bits from twotimer configuration for 57 bits + // + // Go to this bit layout: + // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // ----------------------------------------------------------------------------------------------- + // |R0 |G01G02 |B01B02 ;B03 |RH1 |RH2|GH | + // ----------------------------------------------------------------------------------------------- + // + // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 + // 8 7 6 5 4 3 2 1 0 + // ----------------------------------------------------------------------------------------------- + // |BH |RV |GV |BV | not used + // | + // ----------------------------------------------------------------------------------------------- + // + // From this: + // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // ------------------------------------------------------------------------------------------------ + // |//|R0 |G01|/|G02 |B01|/ // //|B02 |//|B03 + // |RH1 |df|RH2| + // ------------------------------------------------------------------------------------------------ + // + // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 + // 8 7 6 5 4 3 2 1 0 + // ----------------------------------------------------------------------------------------------- + // |GH |BH |RV |GV |BV | + // ----------------------------------------------------------------------------------------------- + // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // --------------------------------------------------------------------------------------------------- + // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 + // | table | table |diff|flip| | R1' (5 bits) | dR2 | G1' (5 bits) | + // dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | + // --------------------------------------------------------------------------------------------------- + + uint8 RO, GO1, GO2, BO1, BO2, BO3, RH1, RH2, GH, BH, RV, GV, BV; + + RO = static_cast(GETBITSHIGH(planar_word1, 6, 62)); + GO1 = static_cast(GETBITSHIGH(planar_word1, 1, 56)); + GO2 = static_cast(GETBITSHIGH(planar_word1, 6, 54)); + BO1 = static_cast(GETBITSHIGH(planar_word1, 1, 48)); + BO2 = static_cast(GETBITSHIGH(planar_word1, 2, 44)); + BO3 = static_cast(GETBITSHIGH(planar_word1, 3, 41)); + RH1 = static_cast(GETBITSHIGH(planar_word1, 5, 38)); + RH2 = static_cast(GETBITSHIGH(planar_word1, 1, 32)); + GH = static_cast(GETBITS(planar_word2, 7, 31)); + BH = static_cast(GETBITS(planar_word2, 6, 24)); + RV = static_cast(GETBITS(planar_word2, 6, 18)); + GV = static_cast(GETBITS(planar_word2, 7, 12)); + BV = static_cast(GETBITS(planar_word2, 6, 5)); + + planar57_word1 = 0; + planar57_word2 = 0; + PUTBITSHIGH(planar57_word1, RO, 6, 63); + PUTBITSHIGH(planar57_word1, GO1, 1, 57); + PUTBITSHIGH(planar57_word1, GO2, 6, 56); + PUTBITSHIGH(planar57_word1, BO1, 1, 50); + PUTBITSHIGH(planar57_word1, BO2, 2, 49); + PUTBITSHIGH(planar57_word1, BO3, 3, 47); + PUTBITSHIGH(planar57_word1, RH1, 5, 44); + PUTBITSHIGH(planar57_word1, RH2, 1, 39); + PUTBITSHIGH(planar57_word1, GH, 7, 38); + PUTBITS(planar57_word2, BH, 6, 31); + PUTBITS(planar57_word2, RV, 6, 25); + PUTBITS(planar57_word2, GV, 7, 19); + PUTBITS(planar57_word2, BV, 6, 12); +} + +// The format stores the bits for the three extra modes in a roundabout way to +// be able to fit them without increasing the bit rate. This function converts +// them into something that is easier to work with. NO WARRANTY --- SEE +// STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved. +void unstuff58bits(unsigned int thumbH_word1, unsigned int thumbH_word2, + unsigned int& thumbH58_word1, unsigned int& thumbH58_word2) { + // Go to this layout: + // + // |63 62 61 60 59 58|57 56 55 54 53 52 51|50 49|48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33|32 | + // |-------empty-----|part0---------------|part1|part2------------------------------------------|part3| + // + // from this: + // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // --------------------------------------------------------------------------------------------------| + // |//|part0 |// // //|part1|//|part2 |df|part3| + // --------------------------------------------------------------------------------------------------| + + unsigned int part0, part1, part2, part3; + + // move parts + part0 = GETBITSHIGH(thumbH_word1, 7, 62); + part1 = GETBITSHIGH(thumbH_word1, 2, 52); + part2 = GETBITSHIGH(thumbH_word1, 16, 49); + part3 = GETBITSHIGH(thumbH_word1, 1, 32); + thumbH58_word1 = 0; + PUTBITSHIGH(thumbH58_word1, part0, 7, 57); + PUTBITSHIGH(thumbH58_word1, part1, 2, 50); + PUTBITSHIGH(thumbH58_word1, part2, 16, 48); + PUTBITSHIGH(thumbH58_word1, part3, 1, 32); + + thumbH58_word2 = thumbH_word2; +} + +// The format stores the bits for the three extra modes in a roundabout way to +// be able to fit them without increasing the bit rate. This function converts +// them into something that is easier to work with. NO WARRANTY --- SEE +// STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights Reserved. +void unstuff59bits(unsigned int thumbT_word1, unsigned int thumbT_word2, + unsigned int& thumbT59_word1, unsigned int& thumbT59_word2) { + // Get bits from twotimer configuration 59 bits. + // + // Go to this bit layout: + // + // |63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 + // 40 39|38 37 36 35|34 33 32| + // |----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green + // 1--|--blue 1---|--dist--| + // + // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 + // 08 07 06 05 04 03 02 01 00| + // |----------------------------------------index + // bits---------------------------------------------| + // + // + // From this: + // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // ----------------------------------------------------------------------------------------------- + // |// // //|R0a |//|R0b |G0 |B0 |R1 |G1 |B1 |da + // |df|db| + // ----------------------------------------------------------------------------------------------- + // + // |31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 + // 08 07 06 05 04 03 02 01 00| + // |----------------------------------------index + // bits---------------------------------------------| + // + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // ----------------------------------------------------------------------------------------------- + // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol 2 + // | table | table |df|fp| | R1' (5 bits) | dR2 | G1' (5 bits) | dG2 + // | B1' (5 bits) | dB2 | cw 1 | cw 2 |bt|bt| + // ------------------------------------------------------------------------------------------------ + + uint8 R0a; + + // Fix middle part + thumbT59_word1 = thumbT_word1 >> 1; + // Fix db (lowest bit of d) + PUTBITSHIGH(thumbT59_word1, thumbT_word1, 1, 32); + // Fix R0a (top two bits of R0) + R0a = static_cast(GETBITSHIGH(thumbT_word1, 2, 60)); + PUTBITSHIGH(thumbT59_word1, R0a, 2, 58); + + // Zero top part (not needed) + PUTBITSHIGH(thumbT59_word1, 0, 5, 63); + + thumbT59_word2 = thumbT_word2; +} + +// The color bits are expanded to the full color +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressColor(int R_B, int G_B, int B_B, uint8(colors_RGB444)[2][3], + uint8(colors)[2][3]) { + // The color should be retrieved as: + // + // c = round(255/(r_bits^2-1))*comp_color + // + // This is similar to bit replication + // + // Note -- this code only work for bit replication from 4 bits and up --- 3 + // bits needs two copy operations. + + colors[0][R] = (colors_RGB444[0][R] << (8 - R_B)) + | (colors_RGB444[0][R] >> (R_B - (8 - R_B))); + colors[0][G] = (colors_RGB444[0][G] << (8 - G_B)) + | (colors_RGB444[0][G] >> (G_B - (8 - G_B))); + colors[0][B] = (colors_RGB444[0][B] << (8 - B_B)) + | (colors_RGB444[0][B] >> (B_B - (8 - B_B))); + colors[1][R] = (colors_RGB444[1][R] << (8 - R_B)) + | (colors_RGB444[1][R] >> (R_B - (8 - R_B))); + colors[1][G] = (colors_RGB444[1][G] << (8 - G_B)) + | (colors_RGB444[1][G] >> (G_B - (8 - G_B))); + colors[1][B] = (colors_RGB444[1][B] << (8 - B_B)) + | (colors_RGB444[1][B] >> (B_B - (8 - B_B))); +} + +void calculatePaintColors59T(uint8 d, uint8 p, uint8(colors)[2][3], + uint8(possible_colors)[4][3]) { + ////////////////////////////////////////////// + // + // C3 C1 C4----C1---C2 + // | | | + // | | | + // |-------| | + // | | | + // | | | + // C4 C2 C3 + // + ////////////////////////////////////////////// + + // C4 + possible_colors[3][R] = + static_cast(CLAMP(0, colors[1][R] - table59T[d], 255)); + possible_colors[3][G] = + static_cast(CLAMP(0, colors[1][G] - table59T[d], 255)); + possible_colors[3][B] = + static_cast(CLAMP(0, colors[1][B] - table59T[d], 255)); + + if (p == PATTERN_T) { + // C3 + possible_colors[0][R] = colors[0][R]; + possible_colors[0][G] = colors[0][G]; + possible_colors[0][B] = colors[0][B]; + // C2 + possible_colors[1][R] = + static_cast(CLAMP(0, colors[1][R] + table59T[d], 255)); + possible_colors[1][G] = + static_cast(CLAMP(0, colors[1][G] + table59T[d], 255)); + possible_colors[1][B] = + static_cast(CLAMP(0, colors[1][B] + table59T[d], 255)); + // C1 + possible_colors[2][R] = colors[1][R]; + possible_colors[2][G] = colors[1][G]; + possible_colors[2][B] = colors[1][B]; + + } else { + printf("Invalid pattern. Terminating"); + exit(1); + } +} +// Decompress a T-mode block (simple packing) +// Simple 59T packing: +//|63 62 61 60 59|58 57 56 55|54 53 52 51|50 49 48 47|46 45 44 43|42 41 40 39|38 +// 37 36 35|34 33 32| +//|----empty-----|---red 0---|--green 0--|--blue 0---|---red 1---|--green +// 1--|--blue 1---|--dist--| +// +//|31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 09 08 07 06 +// 05 04 03 02 01 00| +//|----------------------------------------index +// bits---------------------------------------------| +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockTHUMB59Tc(unsigned int block_part1, + unsigned int block_part2, uint8* img, int width, + int height, int startx, int starty, + int channels) { + uint8 colorsRGB444[2][3]; + uint8 colors[2][3]; + uint8 paint_colors[4][3]; + uint8 distance; + uint8 block_mask[4][4]; + + // First decode left part of block. + colorsRGB444[0][R] = static_cast(GETBITSHIGH(block_part1, 4, 58)); + colorsRGB444[0][G] = static_cast(GETBITSHIGH(block_part1, 4, 54)); + colorsRGB444[0][B] = static_cast(GETBITSHIGH(block_part1, 4, 50)); + + colorsRGB444[1][R] = static_cast(GETBITSHIGH(block_part1, 4, 46)); + colorsRGB444[1][G] = static_cast(GETBITSHIGH(block_part1, 4, 42)); + colorsRGB444[1][B] = static_cast(GETBITSHIGH(block_part1, 4, 38)); + + distance = static_cast(GETBITSHIGH(block_part1, TABLE_BITS_59T, 34)); + + // Extend the two colors to RGB888 + decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); + calculatePaintColors59T(distance, PATTERN_T, colors, paint_colors); + + // Choose one of the four paint colors for each texel + for (uint8 x = 0; x < BLOCKWIDTH; ++x) { + for (uint8 y = 0; y < BLOCKHEIGHT; ++y) { + // block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2); + block_mask[x][y] = + static_cast(GETBITS(block_part2, 1, (y + x * 4) + 16) << 1); + block_mask[x][y] |= GETBITS(block_part2, 1, (y + x * 4)); + img[channels * ((starty + y) * width + startx + x) + R] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][R], 255)); // RED + img[channels * ((starty + y) * width + startx + x) + G] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][G], 255)); // GREEN + img[channels * ((starty + y) * width + startx + x) + B] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][B], 255)); // BLUE + } + } +} + +void decompressBlockTHUMB59T(unsigned int block_part1, unsigned int block_part2, + uint8* img, int width, int height, int startx, + int starty) { + decompressBlockTHUMB59Tc(block_part1, block_part2, img, width, height, startx, + starty, 3); +} + +// Calculate the paint colors from the block colors +// using a distance d and one of the H- or T-patterns. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void calculatePaintColors58H(uint8 d, uint8 p, uint8(colors)[2][3], + uint8(possible_colors)[4][3]) { + ////////////////////////////////////////////// + // + // C3 C1 C4----C1---C2 + // | | | + // | | | + // |-------| | + // | | | + // | | | + // C4 C2 C3 + // + ////////////////////////////////////////////// + + // C4 + possible_colors[3][R] = + static_cast(CLAMP(0, colors[1][R] - table58H[d], 255)); + possible_colors[3][G] = + static_cast(CLAMP(0, colors[1][G] - table58H[d], 255)); + possible_colors[3][B] = + static_cast(CLAMP(0, colors[1][B] - table58H[d], 255)); + + if (p == PATTERN_H) { + // C1 + possible_colors[0][R] = + static_cast(CLAMP(0, colors[0][R] + table58H[d], 255)); + possible_colors[0][G] = + static_cast(CLAMP(0, colors[0][G] + table58H[d], 255)); + possible_colors[0][B] = + static_cast(CLAMP(0, colors[0][B] + table58H[d], 255)); + // C2 + possible_colors[1][R] = + static_cast(CLAMP(0, colors[0][R] - table58H[d], 255)); + possible_colors[1][G] = + static_cast(CLAMP(0, colors[0][G] - table58H[d], 255)); + possible_colors[1][B] = + static_cast(CLAMP(0, colors[0][B] - table58H[d], 255)); + // C3 + possible_colors[2][R] = + static_cast(CLAMP(0, colors[1][R] + table58H[d], 255)); + possible_colors[2][G] = + static_cast(CLAMP(0, colors[1][G] + table58H[d], 255)); + possible_colors[2][B] = + static_cast(CLAMP(0, colors[1][B] + table58H[d], 255)); + } else { + printf("Invalid pattern. Terminating"); + exit(1); + } +} + +// Decompress an H-mode block +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockTHUMB58Hc(unsigned int block_part1, + unsigned int block_part2, uint8* img, int width, + int height, int startx, int starty, + int channels) { + unsigned int col0, col1; + uint8 colors[2][3]; + uint8 colorsRGB444[2][3]; + uint8 paint_colors[4][3]; + uint8 distance; + uint8 block_mask[4][4]; + + // First decode left part of block. + colorsRGB444[0][R] = static_cast(GETBITSHIGH(block_part1, 4, 57)); + colorsRGB444[0][G] = static_cast(GETBITSHIGH(block_part1, 4, 53)); + colorsRGB444[0][B] = static_cast(GETBITSHIGH(block_part1, 4, 49)); + + colorsRGB444[1][R] = static_cast(GETBITSHIGH(block_part1, 4, 45)); + colorsRGB444[1][G] = static_cast(GETBITSHIGH(block_part1, 4, 41)); + colorsRGB444[1][B] = static_cast(GETBITSHIGH(block_part1, 4, 37)); + + distance = 0; + distance = static_cast((GETBITSHIGH(block_part1, 2, 33)) << 1); + + col0 = GETBITSHIGH(block_part1, 12, 57); + col1 = GETBITSHIGH(block_part1, 12, 45); + + if (col0 >= col1) { + distance |= 1; + } + + // Extend the two colors to RGB888 + decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); + + calculatePaintColors58H(distance, PATTERN_H, colors, paint_colors); + + // Choose one of the four paint colors for each texel + for (uint8 x = 0; x < BLOCKWIDTH; ++x) { + for (uint8 y = 0; y < BLOCKHEIGHT; ++y) { + // block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2); + block_mask[x][y] = + static_cast(GETBITS(block_part2, 1, (y + x * 4) + 16) << 1); + block_mask[x][y] |= GETBITS(block_part2, 1, (y + x * 4)); + img[channels * ((starty + y) * width + startx + x) + R] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][R], 255)); // RED + img[channels * ((starty + y) * width + startx + x) + G] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][G], 255)); // GREEN + img[channels * ((starty + y) * width + startx + x) + B] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][B], 255)); // BLUE + } + } +} +void decompressBlockTHUMB58H(unsigned int block_part1, unsigned int block_part2, + uint8* img, int width, int height, int startx, + int starty) { + decompressBlockTHUMB58Hc(block_part1, block_part2, img, width, height, startx, + starty, 3); +} + +// Decompress the planar mode. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockPlanar57c(unsigned int compressed57_1, + unsigned int compressed57_2, uint8* img, + int width, int height, int startx, int starty, + int channels) { + uint8 colorO[3], colorH[3], colorV[3]; + + colorO[0] = static_cast(GETBITSHIGH(compressed57_1, 6, 63)); + colorO[1] = static_cast(GETBITSHIGH(compressed57_1, 7, 57)); + colorO[2] = static_cast(GETBITSHIGH(compressed57_1, 6, 50)); + colorH[0] = static_cast(GETBITSHIGH(compressed57_1, 6, 44)); + colorH[1] = static_cast(GETBITSHIGH(compressed57_1, 7, 38)); + colorH[2] = static_cast(GETBITS(compressed57_2, 6, 31)); + colorV[0] = static_cast(GETBITS(compressed57_2, 6, 25)); + colorV[1] = static_cast(GETBITS(compressed57_2, 7, 19)); + colorV[2] = static_cast(GETBITS(compressed57_2, 6, 12)); + + colorO[0] = (colorO[0] << 2) | (colorO[0] >> 4); + colorO[1] = (colorO[1] << 1) | (colorO[1] >> 6); + colorO[2] = (colorO[2] << 2) | (colorO[2] >> 4); + + colorH[0] = (colorH[0] << 2) | (colorH[0] >> 4); + colorH[1] = (colorH[1] << 1) | (colorH[1] >> 6); + colorH[2] = (colorH[2] << 2) | (colorH[2] >> 4); + + colorV[0] = (colorV[0] << 2) | (colorV[0] >> 4); + colorV[1] = (colorV[1] << 1) | (colorV[1] >> 6); + colorV[2] = (colorV[2] << 2) | (colorV[2] >> 4); + + int xx, yy; + + for (xx = 0; xx < 4; xx++) { + for (yy = 0; yy < 4; yy++) { + img[channels * width * (starty + yy) + channels * (startx + xx) + 0] = + static_cast( + CLAMP(0, + ((xx * (colorH[0] - colorO[0]) + + yy * (colorV[0] - colorO[0]) + 4 * colorO[0] + 2) + >> 2), + 255)); + img[channels * width * (starty + yy) + channels * (startx + xx) + 1] = + static_cast( + CLAMP(0, + ((xx * (colorH[1] - colorO[1]) + + yy * (colorV[1] - colorO[1]) + 4 * colorO[1] + 2) + >> 2), + 255)); + img[channels * width * (starty + yy) + channels * (startx + xx) + 2] = + static_cast( + CLAMP(0, + ((xx * (colorH[2] - colorO[2]) + + yy * (colorV[2] - colorO[2]) + 4 * colorO[2] + 2) + >> 2), + 255)); + + // Equivalent method + /*img[channels*width*(starty+yy) + channels*(startx+xx) + 0] = +(int)CLAMP(0, JAS_ROUND((xx*(colorH[0]-colorO[0])/4.0f + +yy*(colorV[0]-colorO[0])/4.0f + colorO[0])), 255); +img[channels*width*(starty+yy) ++ channels*(startx+xx) + 1] = (int)CLAMP(0, +JAS_ROUND((xx*(colorH[1]-colorO[1])/4.0f + yy*(colorV[1]-colorO[1])/4.0f + +colorO[1])), 255); +img[channels*width*(starty+yy) + channels*(startx+xx) + 2] = (int)CLAMP(0, +JAS_ROUND((xx*(colorH[2]-colorO[2])/4.0f + yy*(colorV[2]-colorO[2])/4.0f + +colorO[2])), 255);*/ + } + } +} +void decompressBlockPlanar57(unsigned int compressed57_1, + unsigned int compressed57_2, uint8* img, int width, + int height, int startx, int starty) { + decompressBlockPlanar57c(compressed57_1, compressed57_2, img, width, height, + startx, starty, 3); +} +// Decompress an ETC1 block (or ETC2 using individual or differential mode). +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockDiffFlipC(unsigned int block_part1, + unsigned int block_part2, uint8* img, int width, + int height, int startx, int starty, + int channels) { + uint8 avg_color[3], enc_color1[3], enc_color2[3]; + signed char diff[3]; + int table; + int index, shift; + int r, g, b; + int diffbit; + int flipbit; + + diffbit = (GETBITSHIGH(block_part1, 1, 33)); + flipbit = (GETBITSHIGH(block_part1, 1, 32)); + + if (!diffbit) { + // We have diffbit = 0. + + // First decode left part of block. + avg_color[0] = static_cast(GETBITSHIGH(block_part1, 4, 63)); + avg_color[1] = static_cast(GETBITSHIGH(block_part1, 4, 55)); + avg_color[2] = static_cast(GETBITSHIGH(block_part1, 4, 47)); + + // Here, we should really multiply by 17 instead of 16. This can + // be done by just copying the four lower bits to the upper ones + // while keeping the lower bits. + avg_color[0] |= (avg_color[0] << 4); + avg_color[1] |= (avg_color[1] << 4); + avg_color[2] |= (avg_color[2] << 4); + + table = GETBITSHIGH(block_part1, 3, 39) << 1; + + unsigned int pixel_indices_MSB, pixel_indices_LSB; + + pixel_indices_MSB = GETBITS(block_part2, 16, 31); + pixel_indices_LSB = GETBITS(block_part2, 16, 15); + + if ((flipbit) == 0) { + // We should not flip + shift = 0; + for (int x = startx; x < startx + 2; x++) { + for (int y = starty; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + } + } else { + // We should flip + shift = 0; + for (int x = startx; x < startx + 4; x++) { + for (int y = starty; y < starty + 2; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + shift += 2; + } + } + + // Now decode other part of block. + avg_color[0] = static_cast(GETBITSHIGH(block_part1, 4, 59)); + avg_color[1] = static_cast(GETBITSHIGH(block_part1, 4, 51)); + avg_color[2] = static_cast(GETBITSHIGH(block_part1, 4, 43)); + + // Here, we should really multiply by 17 instead of 16. This can + // be done by just copying the four lower bits to the upper ones + // while keeping the lower bits. + avg_color[0] |= (avg_color[0] << 4); + avg_color[1] |= (avg_color[1] << 4); + avg_color[2] |= (avg_color[2] << 4); + + table = GETBITSHIGH(block_part1, 3, 36) << 1; + pixel_indices_MSB = GETBITS(block_part2, 16, 31); + pixel_indices_LSB = GETBITS(block_part2, 16, 15); + + if ((flipbit) == 0) { + // We should not flip + shift = 8; + for (int x = startx + 2; x < startx + 4; x++) { + for (int y = starty; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + } + } else { + // We should flip + shift = 2; + for (int x = startx; x < startx + 4; x++) { + for (int y = starty + 2; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + shift += 2; + } + } + } else { + // We have diffbit = 1. + + // 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 + // 40 39 38 37 36 35 34 33 32 + // --------------------------------------------------------------------------------------------------- + // | base col1 | dcol 2 | base col1 | dcol 2 | base col 1 | dcol + // 2 | table | table |diff|flip| | R1' (5 bits) | dR2 | G1' (5 + // bits) | dG2 | B1' (5 bits) | dB2 | cw 1 | cw 2 |bit |bit | + // --------------------------------------------------------------------------------------------------- + // + // + // c) bit layout in bits 31 through 0 (in both cases) + // + // 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 + // 8 7 6 5 4 3 2 1 0 + // -------------------------------------------------------------------------------------------------- + // | most significant pixel index bits | least + // significant pixel index bits | | p| o| n| m| l| k| j| i| h| g| + // f| e| d| c| b| a| p| o| n| m| l| k| j| i| h| g| f| e| d| c | b | a | + // -------------------------------------------------------------------------------------------------- + + // First decode left part of block. + enc_color1[0] = static_cast(GETBITSHIGH(block_part1, 5, 63)); + enc_color1[1] = static_cast(GETBITSHIGH(block_part1, 5, 55)); + enc_color1[2] = static_cast(GETBITSHIGH(block_part1, 5, 47)); + + // Expand from 5 to 8 bits + avg_color[0] = (enc_color1[0] << 3) | (enc_color1[0] >> 2); + avg_color[1] = (enc_color1[1] << 3) | (enc_color1[1] >> 2); + avg_color[2] = (enc_color1[2] << 3) | (enc_color1[2] >> 2); + + table = GETBITSHIGH(block_part1, 3, 39) << 1; + + unsigned int pixel_indices_MSB, pixel_indices_LSB; + + pixel_indices_MSB = GETBITS(block_part2, 16, 31); + pixel_indices_LSB = GETBITS(block_part2, 16, 15); + + if ((flipbit) == 0) { + // We should not flip + shift = 0; + for (int x = startx; x < startx + 2; x++) { + for (int y = starty; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + } + } else { + // We should flip + shift = 0; + for (int x = startx; x < startx + 4; x++) { + for (int y = starty; y < starty + 2; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + shift += 2; + } + } + + // Now decode right part of block. + diff[0] = static_cast(GETBITSHIGH(block_part1, 3, 58)); + diff[1] = static_cast(GETBITSHIGH(block_part1, 3, 50)); + diff[2] = static_cast(GETBITSHIGH(block_part1, 3, 42)); + + // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5); + diff[1] = (diff[1] << 5); + diff[2] = (diff[2] << 5); + diff[0] = diff[0] >> 5; + diff[1] = diff[1] >> 5; + diff[2] = diff[2] >> 5; + + // Calculate second color + enc_color2[0] = enc_color1[0] + diff[0]; + enc_color2[1] = enc_color1[1] + diff[1]; + enc_color2[2] = enc_color1[2] + diff[2]; + + // Expand from 5 to 8 bits + avg_color[0] = (enc_color2[0] << 3) | (enc_color2[0] >> 2); + avg_color[1] = (enc_color2[1] << 3) | (enc_color2[1] >> 2); + avg_color[2] = (enc_color2[2] << 3) | (enc_color2[2] >> 2); + + table = GETBITSHIGH(block_part1, 3, 36) << 1; + pixel_indices_MSB = GETBITS(block_part2, 16, 31); + pixel_indices_LSB = GETBITS(block_part2, 16, 15); + + if ((flipbit) == 0) { + // We should not flip + shift = 8; + for (int x = startx + 2; x < startx + 4; x++) { + for (int y = starty; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + } + } else { + // We should flip + shift = 2; + for (int x = startx; x < startx + 4; x++) { + for (int y = starty + 2; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + r = RED_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[0] + compressParams[table][index], 255)); + g = GREEN_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[1] + compressParams[table][index], 255)); + b = BLUE_CHANNEL(img, width, x, y, channels) = static_cast( + CLAMP(0, avg_color[2] + compressParams[table][index], 255)); + } + shift += 2; + } + } + } +} +void decompressBlockDiffFlip(unsigned int block_part1, unsigned int block_part2, + uint8* img, int width, int height, int startx, + int starty) { + decompressBlockDiffFlipC(block_part1, block_part2, img, width, height, startx, + starty, 3); +} + +// Decompress an ETC2 RGB block +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockETC2c(unsigned int block_part1, unsigned int block_part2, + uint8* img, int width, int height, int startx, + int starty, int channels) { + int diffbit; + signed char color1[3]; + signed char diff[3]; + signed char red, green, blue; + + diffbit = (GETBITSHIGH(block_part1, 1, 33)); + + if (diffbit) { + // We have diffbit = 1; + + // Base color + color1[0] = static_cast(GETBITSHIGH(block_part1, 5, 63)); + color1[1] = static_cast(GETBITSHIGH(block_part1, 5, 55)); + color1[2] = static_cast(GETBITSHIGH(block_part1, 5, 47)); + + // Diff color + diff[0] = static_cast(GETBITSHIGH(block_part1, 3, 58)); + diff[1] = static_cast(GETBITSHIGH(block_part1, 3, 50)); + diff[2] = static_cast(GETBITSHIGH(block_part1, 3, 42)); + + // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5); + diff[1] = (diff[1] << 5); + diff[2] = (diff[2] << 5); + diff[0] = diff[0] >> 5; + diff[1] = diff[1] >> 5; + diff[2] = diff[2] >> 5; + + red = color1[0] + diff[0]; + green = color1[1] + diff[1]; + blue = color1[2] + diff[2]; + + if (red < 0 || red > 31) { + unsigned int block59_part1, block59_part2; + unstuff59bits(block_part1, block_part2, block59_part1, block59_part2); + decompressBlockTHUMB59Tc(block59_part1, block59_part2, img, width, height, + startx, starty, channels); + } else if (green < 0 || green > 31) { + unsigned int block58_part1, block58_part2; + unstuff58bits(block_part1, block_part2, block58_part1, block58_part2); + decompressBlockTHUMB58Hc(block58_part1, block58_part2, img, width, height, + startx, starty, channels); + } else if (blue < 0 || blue > 31) { + unsigned int block57_part1, block57_part2; + + unstuff57bits(block_part1, block_part2, block57_part1, block57_part2); + decompressBlockPlanar57c(block57_part1, block57_part2, img, width, height, + startx, starty, channels); + } else { + decompressBlockDiffFlipC(block_part1, block_part2, img, width, height, + startx, starty, channels); + } + } else { + // We have diffbit = 0; + decompressBlockDiffFlipC(block_part1, block_part2, img, width, height, + startx, starty, channels); + } +} +void decompressBlockETC2(unsigned int block_part1, unsigned int block_part2, + uint8* img, int width, int height, int startx, + int starty) { + decompressBlockETC2c(block_part1, block_part2, img, width, height, startx, + starty, 3); +} +// Decompress an ETC2 block with punchthrough alpha +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockDifferentialWithAlphaC(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alpha, int width, int height, + int startx, int starty, + int channelsRGB) { + uint8 avg_color[3], enc_color1[3], enc_color2[3]; + signed char diff[3]; + int table; + int index, shift; + int r, g, b; + int diffbit; + int flipbit; + int channelsA; + + if (channelsRGB == 3) { + // We will decode the alpha data to a separate memory area. + channelsA = 1; + } else { + // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4; + alpha = &img[0 + 3]; + } + + // the diffbit now encodes whether or not the entire alpha channel is 255. + diffbit = (GETBITSHIGH(block_part1, 1, 33)); + flipbit = (GETBITSHIGH(block_part1, 1, 32)); + + // First decode left part of block. + enc_color1[0] = static_cast(GETBITSHIGH(block_part1, 5, 63)); + enc_color1[1] = static_cast(GETBITSHIGH(block_part1, 5, 55)); + enc_color1[2] = static_cast(GETBITSHIGH(block_part1, 5, 47)); + + // Expand from 5 to 8 bits + avg_color[0] = (enc_color1[0] << 3) | (enc_color1[0] >> 2); + avg_color[1] = (enc_color1[1] << 3) | (enc_color1[1] >> 2); + avg_color[2] = (enc_color1[2] << 3) | (enc_color1[2] >> 2); + + table = GETBITSHIGH(block_part1, 3, 39) << 1; + + unsigned int pixel_indices_MSB, pixel_indices_LSB; + + pixel_indices_MSB = GETBITS(block_part2, 16, 31); + pixel_indices_LSB = GETBITS(block_part2, 16, 15); + + if ((flipbit) == 0) { + // We should not flip + shift = 0; + for (int x = startx; x < startx + 2; x++) { + for (int y = starty; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + + int mod = compressParams[table][index]; + if (diffbit == 0 && (index == 1 || index == 2)) { + mod = 0; + } + + r = RED_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[0] + mod, 255)); + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[1] + mod, 255)); + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[2] + mod, 255)); + if (diffbit == 0 && index == 1) { + alpha[(y * width + x) * channelsA] = 0; + r = RED_CHANNEL(img, width, x, y, channelsRGB) = 0; + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = 0; + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = 0; + } else { + alpha[(y * width + x) * channelsA] = 255; + } + } + } + } else { + // We should flip + shift = 0; + for (int x = startx; x < startx + 4; x++) { + for (int y = starty; y < starty + 2; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + int mod = compressParams[table][index]; + if (diffbit == 0 && (index == 1 || index == 2)) { + mod = 0; + } + r = RED_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[0] + mod, 255)); + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[1] + mod, 255)); + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[2] + mod, 255)); + if (diffbit == 0 && index == 1) { + alpha[(y * width + x) * channelsA] = 0; + r = RED_CHANNEL(img, width, x, y, channelsRGB) = 0; + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = 0; + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = 0; + } else { + alpha[(y * width + x) * channelsA] = 255; + } + } + shift += 2; + } + } + // Now decode right part of block. + diff[0] = static_cast(GETBITSHIGH(block_part1, 3, 58)); + diff[1] = static_cast(GETBITSHIGH(block_part1, 3, 50)); + diff[2] = static_cast(GETBITSHIGH(block_part1, 3, 42)); + + // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5); + diff[1] = (diff[1] << 5); + diff[2] = (diff[2] << 5); + diff[0] = diff[0] >> 5; + diff[1] = diff[1] >> 5; + diff[2] = diff[2] >> 5; + + // Calculate second color + enc_color2[0] = enc_color1[0] + diff[0]; + enc_color2[1] = enc_color1[1] + diff[1]; + enc_color2[2] = enc_color1[2] + diff[2]; + + // Expand from 5 to 8 bits + avg_color[0] = (enc_color2[0] << 3) | (enc_color2[0] >> 2); + avg_color[1] = (enc_color2[1] << 3) | (enc_color2[1] >> 2); + avg_color[2] = (enc_color2[2] << 3) | (enc_color2[2] >> 2); + + table = GETBITSHIGH(block_part1, 3, 36) << 1; + pixel_indices_MSB = GETBITS(block_part2, 16, 31); + pixel_indices_LSB = GETBITS(block_part2, 16, 15); + + if ((flipbit) == 0) { + // We should not flip + shift = 8; + for (int x = startx + 2; x < startx + 4; x++) { + for (int y = starty; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + int mod = compressParams[table][index]; + if (diffbit == 0 && (index == 1 || index == 2)) { + mod = 0; + } + + r = RED_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[0] + mod, 255)); + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[1] + mod, 255)); + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[2] + mod, 255)); + if (diffbit == 0 && index == 1) { + alpha[(y * width + x) * channelsA] = 0; + r = RED_CHANNEL(img, width, x, y, channelsRGB) = 0; + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = 0; + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = 0; + } else { + alpha[(y * width + x) * channelsA] = 255; + } + } + } + } else { + // We should flip + shift = 2; + for (int x = startx; x < startx + 4; x++) { + for (int y = starty + 2; y < starty + 4; y++) { + index = ((pixel_indices_MSB >> shift) & 1) << 1; + index |= ((pixel_indices_LSB >> shift) & 1); + shift++; + index = unscramble[index]; + int mod = compressParams[table][index]; + if (diffbit == 0 && (index == 1 || index == 2)) { + mod = 0; + } + + r = RED_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[0] + mod, 255)); + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[1] + mod, 255)); + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = + static_cast(CLAMP(0, avg_color[2] + mod, 255)); + if (diffbit == 0 && index == 1) { + alpha[(y * width + x) * channelsA] = 0; + r = RED_CHANNEL(img, width, x, y, channelsRGB) = 0; + g = GREEN_CHANNEL(img, width, x, y, channelsRGB) = 0; + b = BLUE_CHANNEL(img, width, x, y, channelsRGB) = 0; + } else { + alpha[(y * width + x) * channelsA] = 255; + } + } + shift += 2; + } + } +} +void decompressBlockDifferentialWithAlpha(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alpha, int width, int height, + int startx, int starty) { + decompressBlockDifferentialWithAlphaC(block_part1, block_part2, img, alpha, + width, height, startx, starty, 3); +} + +// similar to regular decompression, but alpha channel is set to 0 if pixel +// index is 2, otherwise 255. NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) +// Ericsson AB 2013. All Rights Reserved. +void decompressBlockTHUMB59TAlphaC(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alpha, int width, int height, + int startx, int starty, int channelsRGB) { + uint8 colorsRGB444[2][3]; + uint8 colors[2][3]; + uint8 paint_colors[4][3]; + uint8 distance; + uint8 block_mask[4][4]; + int channelsA; + + if (channelsRGB == 3) { + // We will decode the alpha data to a separate memory area. + channelsA = 1; + } else { + // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4; + alpha = &img[0 + 3]; + } + + // First decode left part of block. + colorsRGB444[0][R] = static_cast(GETBITSHIGH(block_part1, 4, 58)); + colorsRGB444[0][G] = static_cast(GETBITSHIGH(block_part1, 4, 54)); + colorsRGB444[0][B] = static_cast(GETBITSHIGH(block_part1, 4, 50)); + + colorsRGB444[1][R] = static_cast(GETBITSHIGH(block_part1, 4, 46)); + colorsRGB444[1][G] = static_cast(GETBITSHIGH(block_part1, 4, 42)); + colorsRGB444[1][B] = static_cast(GETBITSHIGH(block_part1, 4, 38)); + + distance = static_cast(GETBITSHIGH(block_part1, TABLE_BITS_59T, 34)); + + // Extend the two colors to RGB888 + decompressColor(R_BITS59T, G_BITS59T, B_BITS59T, colorsRGB444, colors); + calculatePaintColors59T(distance, PATTERN_T, colors, paint_colors); + + // Choose one of the four paint colors for each texel + for (uint8 x = 0; x < BLOCKWIDTH; ++x) { + for (uint8 y = 0; y < BLOCKHEIGHT; ++y) { + // block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2); + block_mask[x][y] = + static_cast(GETBITS(block_part2, 1, (y + x * 4) + 16) << 1); + block_mask[x][y] |= GETBITS(block_part2, 1, (y + x * 4)); + img[channelsRGB * ((starty + y) * width + startx + x) + R] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][R], 255)); // RED + img[channelsRGB * ((starty + y) * width + startx + x) + G] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][G], 255)); // GREEN + img[channelsRGB * ((starty + y) * width + startx + x) + B] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][B], 255)); // BLUE + if (block_mask[x][y] == 2) { + alpha[channelsA * (x + startx + (y + starty) * width)] = 0; + img[channelsRGB * ((starty + y) * width + startx + x) + R] = 0; + img[channelsRGB * ((starty + y) * width + startx + x) + G] = 0; + img[channelsRGB * ((starty + y) * width + startx + x) + B] = 0; + } else + alpha[channelsA * (x + startx + (y + starty) * width)] = 255; + } + } +} +void decompressBlockTHUMB59TAlpha(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alpha, int width, int height, + int startx, int starty) { + decompressBlockTHUMB59TAlphaC(block_part1, block_part2, img, alpha, width, + height, startx, starty, 3); +} + +// Decompress an H-mode block with alpha +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockTHUMB58HAlphaC(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alpha, int width, int height, + int startx, int starty, int channelsRGB) { + unsigned int col0, col1; + uint8 colors[2][3]; + uint8 colorsRGB444[2][3]; + uint8 paint_colors[4][3]; + uint8 distance; + uint8 block_mask[4][4]; + int channelsA; + + if (channelsRGB == 3) { + // We will decode the alpha data to a separate memory area. + channelsA = 1; + } else { + // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4; + alpha = &img[0 + 3]; + } + + // First decode left part of block. + colorsRGB444[0][R] = static_cast(GETBITSHIGH(block_part1, 4, 57)); + colorsRGB444[0][G] = static_cast(GETBITSHIGH(block_part1, 4, 53)); + colorsRGB444[0][B] = static_cast(GETBITSHIGH(block_part1, 4, 49)); + + colorsRGB444[1][R] = static_cast(GETBITSHIGH(block_part1, 4, 45)); + colorsRGB444[1][G] = static_cast(GETBITSHIGH(block_part1, 4, 41)); + colorsRGB444[1][B] = static_cast(GETBITSHIGH(block_part1, 4, 37)); + + distance = 0; + distance = static_cast((GETBITSHIGH(block_part1, 2, 33)) << 1); + + col0 = GETBITSHIGH(block_part1, 12, 57); + col1 = GETBITSHIGH(block_part1, 12, 45); + + if (col0 >= col1) { + distance |= 1; + } + + // Extend the two colors to RGB888 + decompressColor(R_BITS58H, G_BITS58H, B_BITS58H, colorsRGB444, colors); + + calculatePaintColors58H(distance, PATTERN_H, colors, paint_colors); + + // Choose one of the four paint colors for each texel + for (uint8 x = 0; x < BLOCKWIDTH; ++x) { + for (uint8 y = 0; y < BLOCKHEIGHT; ++y) { + // block_mask[x][y] = GETBITS(block_part2,2,31-(y*4+x)*2); + block_mask[x][y] = + static_cast(GETBITS(block_part2, 1, (y + x * 4) + 16) << 1); + block_mask[x][y] |= GETBITS(block_part2, 1, (y + x * 4)); + img[channelsRGB * ((starty + y) * width + startx + x) + R] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][R], 255)); // RED + img[channelsRGB * ((starty + y) * width + startx + x) + G] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][G], 255)); // GREEN + img[channelsRGB * ((starty + y) * width + startx + x) + B] = + static_cast( + CLAMP(0, paint_colors[block_mask[x][y]][B], 255)); // BLUE + + if (block_mask[x][y] == 2) { + alpha[channelsA * (x + startx + (y + starty) * width)] = 0; + img[channelsRGB * ((starty + y) * width + startx + x) + R] = 0; + img[channelsRGB * ((starty + y) * width + startx + x) + G] = 0; + img[channelsRGB * ((starty + y) * width + startx + x) + B] = 0; + } else + alpha[channelsA * (x + startx + (y + starty) * width)] = 255; + } + } +} +void decompressBlockTHUMB58HAlpha(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alpha, int width, int height, + int startx, int starty) { + decompressBlockTHUMB58HAlphaC(block_part1, block_part2, img, alpha, width, + height, startx, starty, 3); +} +// Decompression function for ETC2_RGBA1 format. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +void decompressBlockETC21BitAlphaC(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alphaimg, int width, int height, + int startx, int starty, int channelsRGB) { + int diffbit; + signed char color1[3]; + signed char diff[3]; + signed char red, green, blue; + int channelsA; + + if (channelsRGB == 3) { + // We will decode the alpha data to a separate memory area. + channelsA = 1; + } else { + // We will decode the RGB data and the alpha data to the same memory area, + // interleaved as RGBA. + channelsA = 4; + alphaimg = &img[0 + 3]; + } + + diffbit = (GETBITSHIGH(block_part1, 1, 33)); + + if (diffbit) { + // We have diffbit = 1, meaning no transparent pixels. regular + // decompression. + + // Base color + color1[0] = static_cast(GETBITSHIGH(block_part1, 5, 63)); + color1[1] = static_cast(GETBITSHIGH(block_part1, 5, 55)); + color1[2] = static_cast(GETBITSHIGH(block_part1, 5, 47)); + + // Diff color + diff[0] = static_cast(GETBITSHIGH(block_part1, 3, 58)); + diff[1] = static_cast(GETBITSHIGH(block_part1, 3, 50)); + diff[2] = static_cast(GETBITSHIGH(block_part1, 3, 42)); + + // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5); + diff[1] = (diff[1] << 5); + diff[2] = (diff[2] << 5); + diff[0] = diff[0] >> 5; + diff[1] = diff[1] >> 5; + diff[2] = diff[2] >> 5; + + red = color1[0] + diff[0]; + green = color1[1] + diff[1]; + blue = color1[2] + diff[2]; + + if (red < 0 || red > 31) { + unsigned int block59_part1, block59_part2; + unstuff59bits(block_part1, block_part2, block59_part1, block59_part2); + decompressBlockTHUMB59Tc(block59_part1, block59_part2, img, width, height, + startx, starty, channelsRGB); + } else if (green < 0 || green > 31) { + unsigned int block58_part1, block58_part2; + unstuff58bits(block_part1, block_part2, block58_part1, block58_part2); + decompressBlockTHUMB58Hc(block58_part1, block58_part2, img, width, height, + startx, starty, channelsRGB); + } else if (blue < 0 || blue > 31) { + unsigned int block57_part1, block57_part2; + + unstuff57bits(block_part1, block_part2, block57_part1, block57_part2); + decompressBlockPlanar57c(block57_part1, block57_part2, img, width, height, + startx, starty, channelsRGB); + } else { + decompressBlockDifferentialWithAlphaC(block_part1, block_part2, img, + alphaimg, width, height, startx, + starty, channelsRGB); + } + for (int x = startx; x < startx + 4; x++) { + for (int y = starty; y < starty + 4; y++) { + alphaimg[channelsA * (x + y * width)] = 255; + } + } + } else { + // We have diffbit = 0, transparent pixels. Only T-, H- or regular diff-mode + // possible. + + // Base color + color1[0] = static_cast(GETBITSHIGH(block_part1, 5, 63)); + color1[1] = static_cast(GETBITSHIGH(block_part1, 5, 55)); + color1[2] = static_cast(GETBITSHIGH(block_part1, 5, 47)); + + // Diff color + diff[0] = static_cast(GETBITSHIGH(block_part1, 3, 58)); + diff[1] = static_cast(GETBITSHIGH(block_part1, 3, 50)); + diff[2] = static_cast(GETBITSHIGH(block_part1, 3, 42)); + + // Extend sign bit to entire byte. + diff[0] = (diff[0] << 5); + diff[1] = (diff[1] << 5); + diff[2] = (diff[2] << 5); + diff[0] = diff[0] >> 5; + diff[1] = diff[1] >> 5; + diff[2] = diff[2] >> 5; + + red = color1[0] + diff[0]; + green = color1[1] + diff[1]; + blue = color1[2] + diff[2]; + if (red < 0 || red > 31) { + unsigned int block59_part1, block59_part2; + unstuff59bits(block_part1, block_part2, block59_part1, block59_part2); + decompressBlockTHUMB59TAlphaC(block59_part1, block59_part2, img, alphaimg, + width, height, startx, starty, channelsRGB); + } else if (green < 0 || green > 31) { + unsigned int block58_part1, block58_part2; + unstuff58bits(block_part1, block_part2, block58_part1, block58_part2); + decompressBlockTHUMB58HAlphaC(block58_part1, block58_part2, img, alphaimg, + width, height, startx, starty, channelsRGB); + } else if (blue < 0 || blue > 31) { + unsigned int block57_part1, block57_part2; + + unstuff57bits(block_part1, block_part2, block57_part1, block57_part2); + decompressBlockPlanar57c(block57_part1, block57_part2, img, width, height, + startx, starty, channelsRGB); + for (int x = startx; x < startx + 4; x++) { + for (int y = starty; y < starty + 4; y++) { + alphaimg[channelsA * (x + y * width)] = 255; + } + } + } else + decompressBlockDifferentialWithAlphaC(block_part1, block_part2, img, + alphaimg, width, height, startx, + starty, channelsRGB); + } +} +void decompressBlockETC21BitAlpha(unsigned int block_part1, + unsigned int block_part2, uint8* img, + uint8* alphaimg, int width, int height, + int startx, int starty) { + decompressBlockETC21BitAlphaC(block_part1, block_part2, img, alphaimg, width, + height, startx, starty, 3); +} +// +// Utility functions used for alpha compression +// + +// bit number frompos is extracted from input, and moved to bit number topos in +// the return value. NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson +// AB 2013. All Rights Reserved. +auto getbit(uint8 input, int frompos, int topos) -> uint8 { + // uint8 output=0; + if (frompos > topos) + return static_cast(((1 << frompos) & input) >> (frompos - topos)); + return static_cast(((1 << frompos) & input) << (topos - frompos)); +} + +// takes as input a value, returns the value clamped to the interval [0,255]. +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +auto clamp(int val) -> int { + if (val < 0) val = 0; + if (val > 255) val = 255; + return val; +} + +// Decodes tha alpha component in a block coded with +// GL_COMPRESSED_RGBA8_ETC2_EAC. Note that this decoding is slightly different +// from that of GL_COMPRESSED_R11_EAC. However, a hardware decoder can share +// gates between the two formats as explained in the specification under +// GL_COMPRESSED_R11_EAC. NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) +// Ericsson AB 2013. All Rights Reserved. +void decompressBlockAlphaC(uint8* data, uint8* img, int width, int height, + int ix, int iy, int channels) { + int alpha = data[0]; + int table = data[1]; + + int bit = 0; + int byte = 2; + // extract an alpha value for each pixel. + for (int x = 0; x < 4; x++) { + for (int y = 0; y < 4; y++) { + // Extract table index + int index = 0; + for (int bitpos = 0; bitpos < 3; bitpos++) { + index |= getbit(data[byte], 7 - bit, 2 - bitpos); + bit++; + if (bit > 7) { + bit = 0; + byte++; + } + } + img[(ix + x + (iy + y) * width) * channels] = + static_cast(clamp(alpha + alphaTable[table][index])); + } + } +} +void decompressBlockAlpha(uint8* data, uint8* img, int width, int height, + int ix, int iy) { + decompressBlockAlphaC(data, img, width, height, ix, iy, 1); +} + +// Does decompression and then immediately converts from 11 bit signed to a +// 16-bit format. +// +// NO WARRANTY --- SEE STATEMENT IN TOP OF FILE (C) Ericsson AB 2013. All Rights +// Reserved. +auto get16bits11signed(int base, int table, int mul, int index) -> int16 { + int elevenbase = base - 128; + if (elevenbase == -128) elevenbase = -127; + elevenbase *= 8; + // i want the positive value here + int tabVal = -alphaBase[table][3 - index % 4] - 1; + // and the sign, please + int sign = 1 - (index / 4); + + if (sign) tabVal = tabVal + 1; + int elevenTabVal = tabVal * 8; + + if (mul != 0) + elevenTabVal *= mul; + else + elevenTabVal /= 8; + + if (sign) elevenTabVal = -elevenTabVal; + + // calculate sum + int elevenbits = elevenbase + elevenTabVal; + + // clamp.. + if (elevenbits >= 1024) + elevenbits = 1023; + else if (elevenbits < -1023) + elevenbits = -1023; + // this is the value we would actually output.. + // but there aren't any good 11-bit file or uncompressed GL formats + // so we extend to 15 bits signed. + sign = elevenbits < 0; + elevenbits = abs(elevenbits); + auto fifteenbits = static_cast((elevenbits << 5) + (elevenbits >> 5)); + auto sixteenbits = static_cast(fifteenbits); + + if (sign) sixteenbits = -sixteenbits; + + return sixteenbits; +} + +// Does decompression and then immediately converts from 11 bit signed to a +// 16-bit format Calculates the 11 bit value represented by base, table, mul and +// index, and extends it to 16 bits. NO WARRANTY --- SEE STATEMENT IN TOP OF +// FILE (C) Ericsson AB 2013. All Rights Reserved. +auto get16bits11bits(int base, int table, int mul, int index) -> uint16 { + int elevenbase = base * 8 + 4; + + // i want the positive value here + int tabVal = -alphaBase[table][3 - index % 4] - 1; + // and the sign, please + int sign = 1 - (index / 4); + + if (sign) tabVal = tabVal + 1; + int elevenTabVal = tabVal * 8; + + if (mul != 0) + elevenTabVal *= mul; + else + elevenTabVal /= 8; + + if (sign) elevenTabVal = -elevenTabVal; + + // calculate sum + int elevenbits = elevenbase + elevenTabVal; + + // clamp.. + if (elevenbits >= 256 * 8) + elevenbits = 256 * 8 - 1; + else if (elevenbits < 0) + elevenbits = 0; + // elevenbits now contains the 11 bit alpha value as defined in the spec. + + // extend to 16 bits before returning, since we don't have any good 11-bit + // file formats. + auto sixteenbits = static_cast((elevenbits << 5) + (elevenbits >> 6)); + + return sixteenbits; +} + +// Decompresses a block using one of the GL_COMPRESSED_R11_EAC or +// GL_COMPRESSED_SIGNED_R11_EAC-formats NO WARRANTY --- SEE STATEMENT IN TOP OF +// FILE (C) Ericsson AB 2013. All Rights Reserved. +void decompressBlockAlpha16bitC(uint8* data, uint8* img, int width, int height, + int ix, int iy, int channels) { + int alpha = data[0]; + int table = data[1]; + + if (formatSigned) { + // if we have a signed format, the base value is given as a signed byte. We + // convert it to (0-255) here, so more code can be shared with the unsigned + // mode. + alpha = *((signed char*)(&data[0])); + alpha = alpha + 128; + } + + int bit = 0; + int byte = 2; + // extract an alpha value for each pixel. + for (int x = 0; x < 4; x++) { + for (int y = 0; y < 4; y++) { + // Extract table index + int index = 0; + for (int bitpos = 0; bitpos < 3; bitpos++) { + index |= getbit(data[byte], 7 - bit, 2 - bitpos); + bit++; + if (bit > 7) { + bit = 0; + byte++; + } + } + int windex = channels * (2 * (ix + x + (iy + y) * width)); +#if !PGMOUT + if (formatSigned) { + *(int16*)&img[windex] = + get16bits11signed(alpha, (table % 16), (table / 16), index); + } else { + *(uint16*)&img[windex] = + get16bits11bits(alpha, (table % 16), (table / 16), index); + } +#else + // make data compatible with the .pgm format. See the comment in + // compressBlockAlpha16() for details. + uint16 uSixteen; + if (formatSigned) { + // the pgm-format only allows unsigned images, + // so we add 2^15 to get a 16-bit value. + uSixteen = get16bits11signed(alpha, (table % 16), (table / 16), index) + + 256 * 128; + } else { + uSixteen = get16bits11bits(alpha, (table % 16), (table / 16), index); + } + // byte swap for pgm + img[windex] = uSixteen / 256; + img[windex + 1] = uSixteen % 256; +#endif + } + } +} + +void decompressBlockAlpha16bit(uint8* data, uint8* img, int width, int height, + int ix, int iy) { + decompressBlockAlpha16bitC(data, img, width, height, ix, iy, 1); +} + +static void readBigEndian4byteWord(uint32_t* pBlock, const GLubyte* s) { + *pBlock = (s[0] << 24) | (s[1] << 16) | (s[2] << 8) | s[3]; +} + +void KTXUnpackETC(const GLubyte* srcETC, const GLenum srcFormat, + uint32_t activeWidth, uint32_t activeHeight, + GLubyte** dstImage, GLenum* format, GLenum* internal_format, + GLenum* type, GLint R16Formats, bool supportsSRGB) { + unsigned int width, height; + unsigned int block_part1, block_part2; + unsigned int x, y; + /*const*/ auto* src = (GLubyte*)srcETC; + // AF_11BIT is used to compress R11 & RG11 though its not alpha data. + enum { AF_NONE, AF_1BIT, AF_8BIT, AF_11BIT } alphaFormat = AF_NONE; + int dstChannels, dstChannelBytes; + + switch (srcFormat) { + // case GL_COMPRESSED_SIGNED_R11_EAC: + // if (R16Formats & _KTX_R16_FORMATS_SNORM) { + // dstChannelBytes = sizeof(GLshort); + // dstChannels = 1; + // formatSigned = GL_TRUE; + // *internal_format = GL_R16_SNORM; + // *format = GL_RED; + // *type = GL_SHORT; + // alphaFormat = AF_11BIT; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + // case GL_COMPRESSED_R11_EAC: + // if (R16Formats & _KTX_R16_FORMATS_NORM) { + // dstChannelBytes = sizeof(GLshort); + // dstChannels = 1; + // formatSigned = GL_FALSE; + // *internal_format = GL_R16; + // *format = GL_RED; + // *type = GL_UNSIGNED_SHORT; + // alphaFormat = AF_11BIT; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + // case GL_COMPRESSED_SIGNED_RG11_EAC: + // if (R16Formats & _KTX_R16_FORMATS_SNORM) { + // dstChannelBytes = sizeof(GLshort); + // dstChannels = 2; + // formatSigned = GL_TRUE; + // *internal_format = GL_RG16_SNORM; + // *format = GL_RG; + // *type = GL_SHORT; + // alphaFormat = AF_11BIT; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + // case GL_COMPRESSED_RG11_EAC: + // if (R16Formats & _KTX_R16_FORMATS_NORM) { + // dstChannelBytes = sizeof(GLshort); + // dstChannels = 2; + // formatSigned = GL_FALSE; + // *internal_format = GL_RG16; + // *format = GL_RG; + // *type = GL_UNSIGNED_SHORT; + // alphaFormat = AF_11BIT; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + case GL_ETC1_RGB8_OES: + case GL_COMPRESSED_RGB8_ETC2: + dstChannelBytes = sizeof(GLubyte); + dstChannels = 3; + //*internal_format = GL_RGB8; + *format = GL_RGB; + *type = GL_UNSIGNED_BYTE; + break; + + case GL_COMPRESSED_RGBA8_ETC2_EAC: + dstChannelBytes = sizeof(GLubyte); + dstChannels = 4; + //*internal_format = GL_RGBA8; + *format = GL_RGBA; + *type = GL_UNSIGNED_BYTE; + alphaFormat = AF_8BIT; + break; + + // case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: + // dstChannelBytes = sizeof(GLubyte); + // dstChannels = 4; + // *internal_format = GL_RGBA8; + // *format = GL_RGBA; + // *type = GL_UNSIGNED_BYTE; + // alphaFormat = AF_1BIT; + // break; + + // case GL_COMPRESSED_SRGB8_ETC2: + // if (supportsSRGB) { + // dstChannelBytes = sizeof(GLubyte); + // dstChannels = 3; + // *internal_format = GL_SRGB8; + // *format = GL_RGB; + // *type = GL_UNSIGNED_BYTE; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + // case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: + // if (supportsSRGB) { + // dstChannelBytes = sizeof(GLubyte); + // dstChannels = 4; + // *internal_format = GL_SRGB8_ALPHA8; + // *format = GL_RGBA; + // *type = GL_UNSIGNED_BYTE; + // alphaFormat = AF_8BIT; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + // case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: + // if (supportsSRGB) { + // dstChannelBytes = sizeof(GLubyte); + // dstChannels = 4; + // *internal_format = GL_SRGB8_ALPHA8; + // *format = GL_RGBA; + // *type = GL_UNSIGNED_BYTE; + // alphaFormat = AF_1BIT; + // } else + // return KTX_UNSUPPORTED_TEXTURE_TYPE; + // break; + + default: + throw Exception(); + // assert(0); // Upper levels should be passing only one of the above + // srcFormats. + } + + /* active_{width,height} show how many pixels contain active data, + * (the rest are just for making sure we have a 2*a x 4*b size). + */ + + /* Compute the full width & height. */ + width = ((activeWidth + 3) / 4) * 4; + height = ((activeHeight + 3) / 4) * 4; + + /* printf("Width = %d, Height = %d\n", width, height); */ + /* printf("active pixel area: top left %d x %d area.\n", activeWidth, + * activeHeight); */ + + *dstImage = (GLubyte*)malloc(dstChannels * dstChannelBytes * width * height); + if (!*dstImage) { + throw Exception(); + // return KTX_OUT_OF_MEMORY; + } + + if (alphaFormat != AF_NONE) setupAlphaTable(); + + // NOTE: none of the decompress functions actually use the parameter + if (alphaFormat == AF_11BIT) { + throw Exception(); + // // One or two 11-bit alpha channels for R or RG. + // for (y = 0; y < height / 4; y++) { + // for (x = 0; x < width / 4; x++) { + // decompressBlockAlpha16bitC(src, *dstImage, width, height, 4 * x, 4 + // * y, + // dstChannels); + // src += 8; + // // if (srcFormat == GL_COMPRESSED_RG11_EAC || srcFormat == + // // GL_COMPRESSED_SIGNED_RG11_EAC) { + // decompressBlockAlpha16bitC(src, + // // *dstImage + dstChannelBytes, width, height, 4*x, 4*y, + // dstChannels); + // // src += 8; + // // } + // } + // } + } else { + for (y = 0; y < height / 4; y++) { + for (x = 0; x < width / 4; x++) { + // Decode alpha channel for RGBA + if (alphaFormat == AF_8BIT) { + decompressBlockAlphaC(src, *dstImage + 3, width, height, 4 * x, 4 * y, + dstChannels); + src += 8; + } + // Decode color dstChannels + readBigEndian4byteWord(&block_part1, src); + src += 4; + readBigEndian4byteWord(&block_part2, src); + src += 4; + if (alphaFormat == AF_1BIT) + decompressBlockETC21BitAlphaC(block_part1, block_part2, *dstImage, + nullptr, width, height, 4 * x, 4 * y, + dstChannels); + else + decompressBlockETC2c(block_part1, block_part2, *dstImage, width, + height, 4 * x, 4 * y, dstChannels); + } + } + } + + /* Ok, now write out the active pixels to the destination image. + * (But only if the active pixels differ from the total pixels) + */ + + if (!(height == activeHeight && width == activeWidth)) { + int dstPixelBytes = dstChannels * dstChannelBytes; + int dstRowBytes = dstPixelBytes * width; + int activeRowBytes = activeWidth * dstPixelBytes; + auto* newimg = (GLubyte*)malloc(dstPixelBytes * activeWidth * activeHeight); + unsigned int xx, yy; + int zz; + + if (!newimg) { + free(*dstImage); + // return KTX_OUT_OF_MEMORY; + throw Exception(); + } + + /* Convert from total area to active area: */ + + for (yy = 0; yy < activeHeight; yy++) { + for (xx = 0; xx < activeWidth; xx++) { + for (zz = 0; zz < dstPixelBytes; zz++) { + // NOLINTNEXTLINE + newimg[yy * activeRowBytes + xx * dstPixelBytes + zz] = + (*dstImage)[yy * dstRowBytes + xx * dstPixelBytes + zz]; + } + } + } + + free(*dstImage); + *dstImage = newimg; + } +} + +#pragma clang diagnostic pop + +} // namespace ballistica + +#endif // !BA_HEADLESS_BUILD diff --git a/src/ballistica/graphics/texture/ktx.h b/src/ballistica/graphics/texture/ktx.h new file mode 100644 index 00000000..0f9463b8 --- /dev/null +++ b/src/ballistica/graphics/texture/ktx.h @@ -0,0 +1,29 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXTURE_KTX_H_ +#define BALLISTICA_GRAPHICS_TEXTURE_KTX_H_ + +#include + +#include "ballistica/ballistica.h" + +// currently need gl for this stuff.. probably not necessary. +#if BA_ENABLE_OPENGL + +namespace ballistica { + +void LoadKTX(const std::string& file_name, unsigned char** buffers, int* widths, + int* heights, TextureFormat* formats, size_t* sizes, + TextureQuality texture_quality, int min_quality, int* base_level); + +void KTXUnpackETC(const uint8_t* src_etc, unsigned int src_format, + uint32_t active_width, uint32_t active_height, + uint8_t** dst_image, unsigned int* format, + unsigned int* internal_format, unsigned int* type, + int r16_formats, bool supports_srgb); + +} // namespace ballistica + +#endif // BA_ENABLE_OPENGL + +#endif // BALLISTICA_GRAPHICS_TEXTURE_KTX_H_ diff --git a/src/ballistica/graphics/texture/pvr.cc b/src/ballistica/graphics/texture/pvr.cc new file mode 100644 index 00000000..94762aaf --- /dev/null +++ b/src/ballistica/graphics/texture/pvr.cc @@ -0,0 +1,248 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/graphics/texture/pvr.h" + +#include +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +#define PVR_TEXTURE_FLAG_TYPE_MASK 0xffu + +enum { kPVRTextureFlagTypePVRTC_2 = 24, kPVRTextureFlagTypePVRTC_4 }; + +typedef struct _PVRTexHeader { + uint32_t headerLength; + uint32_t height; + uint32_t width; + uint32_t numMipmaps; + uint32_t flags; + uint32_t dataLength; + uint32_t bpp; + uint32_t bitmaskRed; + uint32_t bitmaskGreen; + uint32_t bitmaskBlue; + uint32_t bitmaskAlpha; + uint32_t pvrTag; + uint32_t num_surfs; +} PVRTexHeader; + +typedef struct _PVRTexHeader2 { + uint32_t version; + uint32_t flags; + uint64_t pixel_format; + uint32_t color_space; + uint32_t channel_type; + uint32_t height; + uint32_t width; + uint32_t depth; + uint32_t num_surfs; + uint32_t num_faces; + uint32_t numMipmaps; + uint32_t metaSize; +} PVRTexHeader2; + +void LoadPVR(const std::string& file_name, unsigned char** buffers, int* widths, + int* heights, TextureFormat* formats, size_t* sizes, + TextureQuality texture_quality, int min_quality, int* base_level) { + (*base_level) = 0; + + FILE* f = g_platform->FOpen(file_name.c_str(), "rb"); + if (!f) throw Exception("can't open file: \"" + file_name + "\""); + + TextureFormat internal_format; + + uint32_t block_size, width_blocks, height_blocks; + uint32_t width, height, bpp, format_flags; + + if (explicit_bool(true)) { + _PVRTexHeader2 hdr2{}; + + BA_PRECONDITION(fread(&hdr2, 52, 1, f) == 1); + BA_PRECONDITION(hdr2.version == 0x03525650); + BA_PRECONDITION(hdr2.flags == 0); + BA_PRECONDITION(hdr2.color_space == 0); // linear RGB + BA_PRECONDITION(hdr2.channel_type == 0); // unsigned byte normalized + BA_PRECONDITION(hdr2.pixel_format == 2 + || hdr2.pixel_format == 3); // PVRTC 4pp RGB/RGBA + BA_PRECONDITION(hdr2.num_surfs == 1); + BA_PRECONDITION(hdr2.num_faces == 1); + BA_PRECONDITION(hdr2.depth == 1); + + internal_format = TextureFormat::kPVR4; + + // Skip over metadata. + BA_PRECONDITION(fseek(f, + static_cast_check_fit(hdr2.metaSize), // NOLINT + SEEK_CUR) + == 0); + + width = hdr2.width; + height = hdr2.height; + + int mip_map_count = static_cast_check_fit(hdr2.numMipmaps); + + // Try dropping a level for med/low quality. + if ((texture_quality == TextureQuality::kLow + || texture_quality == TextureQuality::kMedium) + && (min_quality < 2) + && static_cast_check_fit(mip_map_count) >= (*base_level) + 1) + (*base_level)++; + + // And one more for low in some cases. + if (texture_quality == TextureQuality::kLow && (min_quality < 1) + && (width > 128) && (height > 128) + && mip_map_count >= (*base_level) + 1) + (*base_level)++; + + // Calculate the data size for each texture level and respect the minimum + // number of blocks + for (int ix = 0; ix < mip_map_count; ix++) { + { + block_size = 4 * 4; // Pixel by pixel block size for 4bpp + width_blocks = width / 4; + height_blocks = height / 4; + bpp = 4; + } + + // Clamp to minimum number of blocks + if (width_blocks < 2) { + width_blocks = 2; + } + if (height_blocks < 2) { + height_blocks = 2; + } + + uint32_t data_size{width_blocks * height_blocks + * ((block_size * bpp) / 8)}; + + // Load or skip levels depending on our quality. + if ((*base_level) <= ix) { + sizes[ix] = data_size; + buffers[ix] = (unsigned char*)malloc(data_size); + BA_PRECONDITION(buffers[ix]); + widths[ix] = width; + heights[ix] = height; + formats[ix] = internal_format; + BA_PRECONDITION(fread(buffers[ix], data_size, 1, f) == 1); + } else { + buffers[ix] = nullptr; + BA_PRECONDITION(fseek(f, + static_cast_check_fit(data_size), // NOLINT + SEEK_CUR) + == 0); + } + width = std::max(width >> 1u, 1u); + height = std::max(height >> 1u, 1u); + } + } else { + uint32_t pvrTag; + + uint32_t data_offset = 0; + + _PVRTexHeader hdr{}; + + BA_PRECONDITION(fread(&hdr, sizeof(hdr), 1, f) == 1); + BA_PRECONDITION(hdr.headerLength == sizeof(_PVRTexHeader)); + + pvrTag = hdr.pvrTag; + if (gPVRTexIdentifier[0] != ((pvrTag >> 0u) & 0xffu) + || gPVRTexIdentifier[1] != ((pvrTag >> 8u) & 0xffu) + || gPVRTexIdentifier[2] != ((pvrTag >> 16u) & 0xffu) + || gPVRTexIdentifier[3] != ((pvrTag >> 24u) & 0xffu)) { + throw Exception("Invalid PVR file: \"" + file_name + "\""); + } + + format_flags = hdr.flags & PVR_TEXTURE_FLAG_TYPE_MASK; + + if (format_flags != kPVRTextureFlagTypePVRTC_4 + && format_flags != kPVRTextureFlagTypePVRTC_2) + throw Exception("Invalid PVR format in file: \"" + file_name + "\""); + + if (format_flags == kPVRTextureFlagTypePVRTC_4) { + internal_format = TextureFormat::kPVR4; + } else if (explicit_bool(format_flags == kPVRTextureFlagTypePVRTC_2)) { + internal_format = TextureFormat::kPVR2; + } else { + throw Exception(); + } + + uint32_t data_length{hdr.dataLength}; + + width = hdr.width; + height = hdr.height; + + int mip_map_count = static_cast_check_fit(hdr.numMipmaps + 1); + + // Try dropping a level for med/low quality. + if ((texture_quality == TextureQuality::kLow + || texture_quality == TextureQuality::kMedium) + && (min_quality < 2) && mip_map_count >= (*base_level) + 1) { + (*base_level)++; + } + + // And one more for low in some cases. + if (texture_quality == TextureQuality::kLow && (min_quality < 1) + && (width > 128) && (height > 128) + && mip_map_count >= (*base_level) + 1) + (*base_level)++; + + // Calculate the data size for each texture level and respect the minimum + // number of blocks + int ix = 0; + while (data_offset < data_length) { + if (format_flags == kPVRTextureFlagTypePVRTC_4) { + block_size = 4 * 4; // Pixel by pixel block size for 4bpp + width_blocks = width / 4; + height_blocks = height / 4; + bpp = 4; + } else { + block_size = 8 * 4; // Pixel by pixel block size for 2bpp + width_blocks = width / 8; + height_blocks = height / 4; + bpp = 2; + } + + // Clamp to minimum number of blocks. + if (width_blocks < 2) { + width_blocks = 2; + } + if (height_blocks < 2) { + height_blocks = 2; + } + + uint32_t data_size{width_blocks * height_blocks + * ((block_size * bpp) / 8)}; + + // Load or skip levels depending on our quality. + if ((*base_level) <= ix) { + sizes[ix] = data_size; + buffers[ix] = (unsigned char*)malloc(data_size); + BA_PRECONDITION(buffers[ix]); + widths[ix] = width; + heights[ix] = height; + formats[ix] = internal_format; + BA_PRECONDITION(fread(buffers[ix], data_size, 1, f) == 1); + } else { + buffers[ix] = nullptr; + BA_PRECONDITION(fseek(f, + static_cast_check_fit(data_size), // NOLINT + SEEK_CUR) + == 0); + } + data_offset += data_size; + + width = std::max(width >> 1u, 1u); + height = std::max(height >> 1u, 1u); + ix++; + } + BA_PRECONDITION(ix == mip_map_count); + } + fclose(f); +} + +} // namespace ballistica diff --git a/src/ballistica/graphics/texture/pvr.h b/src/ballistica/graphics/texture/pvr.h new file mode 100644 index 00000000..27a50f08 --- /dev/null +++ b/src/ballistica/graphics/texture/pvr.h @@ -0,0 +1,20 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_TEXTURE_PVR_H_ +#define BALLISTICA_GRAPHICS_TEXTURE_PVR_H_ + +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +static char gPVRTexIdentifier[5] = "PVR!"; + +void LoadPVR(const std::string& file_name, unsigned char** buffers, int* widths, + int* heights, TextureFormat* formats, size_t* sizes, + TextureQuality texture_quality, int min_quality, int* base_level); + +} // namespace ballistica + +#endif // BALLISTICA_GRAPHICS_TEXTURE_PVR_H_ diff --git a/src/ballistica/graphics/vr_graphics.cc b/src/ballistica/graphics/vr_graphics.cc new file mode 100644 index 00000000..0342d428 --- /dev/null +++ b/src/ballistica/graphics/vr_graphics.cc @@ -0,0 +1,336 @@ +// Copyright (c) 2011-2020 Eric Froemling +#if BA_VR_BUILD + +#include "ballistica/graphics/vr_graphics.h" + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/game.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/component/special_component.h" +#include "ballistica/graphics/frame_def.h" +#include "ballistica/graphics/render_pass.h" + +namespace ballistica { + +static auto ValueTestFloat(float* storage, double* absval, double* deltaval) + -> double { + if (absval) { + *storage = static_cast(*absval); + } + if (deltaval) { + *storage += static_cast(*deltaval); + } + return *storage; +} + +static auto ValueTestBool(bool* storage, double* absval, double* deltaval) + -> double { + if (absval) { + *storage = static_cast(*absval); + } + if (deltaval) { + *storage = (*deltaval > 0.5); + } + return static_cast(*storage); +} + +auto VRGraphics::ValueTest(const std::string& arg, double* absval, + double* deltaval, double* outval) -> bool { + if (arg == "vrOverlayScale") { + *outval = ValueTestFloat(&vr_overlay_scale_, absval, deltaval); + } else if (arg == "lockVROverlay") { + *outval = ValueTestBool(&lock_vr_overlay_, absval, deltaval); + } else if (arg == "showOverlayBounds") { + *outval = ValueTestBool(&draw_overlay_bounds_, absval, deltaval); + } else if (arg == "headScale") { + *outval = ValueTestFloat(&vr_test_head_scale_, absval, deltaval); + } else if (arg == "vrCamOffsetY") { + Camera* camera = g_graphics->camera(); + if (camera) { + Vector3f val = camera->vr_extra_offset(); + if (deltaval) { + camera->set_vr_extra_offset(Vector3f(val.x, val.y + *deltaval, val.z)); + } + if (absval) { + camera->set_vr_extra_offset(Vector3f(val.x, *absval, val.z)); + } + *outval = camera->vr_extra_offset().y; + } + } else if (arg == "vrCamOffsetZ") { + Camera* camera = g_graphics->camera(); + if (camera) { + Vector3f val = camera->vr_extra_offset(); + if (deltaval) { + camera->set_vr_extra_offset(Vector3f(val.x, val.y, val.z + *deltaval)); + } + if (absval) { + camera->set_vr_extra_offset(Vector3f(val.x, val.y, *absval)); + } + *outval = camera->vr_extra_offset().z; + } + } else { + // Unhandled. + return false; + } + return true; +} + +void VRGraphics::ApplyCamera(FrameDef* frame_def) { + Graphics::ApplyCamera(frame_def); + + CalcVROverlayMatrices(frame_def); +} + +void VRGraphics::DrawWorld(Session* session, FrameDef* frame_def) { + // Draw the standard world. + Graphics::DrawWorld(session, frame_def); + + // Draw extra VR-Only bits. + DrawVRControllers(frame_def); +} + +void VRGraphics::DrawUI(FrameDef* frame_def) { + // Draw the UI normally, but then blit its texture into 3d space. + Graphics::DrawUI(frame_def); + + // In VR mode we have to draw our overlay-flat texture into space as + // part of the regular overlay pass. + DrawVROverlay(frame_def); + + // We may want to see the bounds of our overlay. + DrawOverlayBounds(frame_def->overlay_pass()); +} + +void VRGraphics::CalcVROverlayMatrices(FrameDef* frame_def) { + // For VR mode, calc our overlay matrix for use in positioning overlay + // elements. + if (IsVRMode()) { + Vector3f cam_target_pt(frame_def->cam_target_original()); + Matrix44f vr_overlay_matrix{kMatrix44fIdentity}; + Matrix44f vr_overlay_matrix_fixed{kMatrix44fIdentity}; + + // In orbit mode, we sit in the middle and face the camera. + if (frame_def->camera_mode() == CameraMode::kOrbit) { + Vector3f cam_pt(frame_def->cam_original()); + Vector3f cam_target_pt_2(0, 11, -3.3f); + vr_overlay_matrix_fixed = vr_overlay_matrix = + CalcVROverlayMatrix(cam_pt, cam_target_pt_2); + + } else { + // Follow mode. + + // In vr follow-mode the cam point gets tweaked. + // FIXME: Should probably just do this on the camera end. + Vector3f cam_pt = frame_def->cam_original(); + + // During gameplay lets just affix X to our camera (the camera tries to + // match the target's x anyway).. this results in less shuffling. + if (frame_def->camera_mode() == CameraMode::kFollow) { + cam_target_pt.x = cam_pt.x; + } + + // Calc y and z values that are completely fixed to the camera center. + float fixed_y = cam_pt.y + kVRFixedOverlayOffsetY; + float fixed_z = cam_pt.z + kVRFixedOverlayOffsetZ; + + // We smoothly blend our target point between the map-specific + // center-point and our fixed point (between levels we want our two + // overlays to line up since there may be elements coordinated across + // them). + + // FIXME: This shouldn't be based on frames. + { + float this_y, this_z; + if (vr_overlay_center_enabled_) { + this_y = vr_overlay_center_.y; + this_z = vr_overlay_center_.z; + } else { + this_y = fixed_y; + this_z = fixed_z; + } + float smoothing = 0.93f; + float smoothing_inv = 1.0f - smoothing; + + vr_cam_target_pt_smoothed_y_ = + smoothing * vr_cam_target_pt_smoothed_y_ + smoothing_inv * this_y; + vr_cam_target_pt_smoothed_z_ = + smoothing * vr_cam_target_pt_smoothed_z_ + smoothing_inv * this_z; + + cam_target_pt.y = vr_cam_target_pt_smoothed_y_; + cam_target_pt.z = vr_cam_target_pt_smoothed_z_; + } + + vr_overlay_matrix = CalcVROverlayMatrix(cam_pt, cam_target_pt); + + // We also always calc a completely fixed matrix for some elements that + // should *never* move such as score-screens. + cam_target_pt.y = fixed_y; + cam_target_pt.z = fixed_z; + vr_overlay_matrix_fixed = CalcVROverlayMatrix(cam_pt, cam_target_pt); + } + + // Calc a screen-matrix that gives us a drawing area of + // kBaseVirtualResX by kBaseVirtualResY. + frame_def->set_vr_overlay_screen_matrix( + Matrix44fTranslate(-0.5f * kBaseVirtualResX, -0.5f * kBaseVirtualResY, + 0.0f) + * Matrix44fScale( + Vector3f(1.0f / (kBaseVirtualResX * (1.0f + kVRBorder)), + 1.0f / (kBaseVirtualResY * (1.0f + kVRBorder)), + 1.0f / (kBaseVirtualResX * (1.0f + kVRBorder)))) + * vr_overlay_matrix); + + // If we have a fixed-version of the matrix, do the same calcs for it; + // otherwise just copy the non-fixed. + frame_def->set_vr_overlay_screen_matrix_fixed( + Matrix44fTranslate(-0.5f * kBaseVirtualResX, -0.5f * kBaseVirtualResY, + 0.0f) + * Matrix44fScale( + Vector3f(1.0f / (kBaseVirtualResX * (1.0f + kVRBorder)), + 1.0f / (kBaseVirtualResY * (1.0f + kVRBorder)), + 1.0f / (kBaseVirtualResX * (1.0f + kVRBorder)))) + * vr_overlay_matrix_fixed); + + if (lock_vr_overlay_) { + frame_def->set_vr_overlay_screen_matrix( + frame_def->vr_overlay_screen_matrix_fixed()); + } + } +} + +auto VRGraphics::CalcVROverlayMatrix(const Vector3f& cam_pt, + const Vector3f& cam_target_pt) const + -> Matrix44f { + Matrix44f m = Matrix44fTranslate(cam_target_pt); + Vector3f diff = cam_pt - cam_target_pt; + diff.Normalize(); + Vector3f side = Vector3f::Cross(diff, Vector3f(0.0f, -1.0f, 0.0f)); + Vector3f up = Vector3f::Cross(diff, side); + m = Matrix44fOrient(diff, up) * m; + + // Push up and out towards the eye a bit. + m = Matrix44fTranslate(0, 2, 1) * m; + + // Scale based on distance to the camera so we're always roughly the same size + // in view. + float dist = (cam_target_pt - cam_pt).Length(); + float base_scale = dist * 1.08f * 1.1f * vr_overlay_scale_; + return Matrix44fScale(Vector3f(base_scale, + base_scale + * (static_cast(kBaseVirtualResY) + / static_cast(kBaseVirtualResX)), + base_scale)) + * m; +} +void VRGraphics::DrawVROverlay(FrameDef* frame_def) { + // In vr mode we have draw our overlay-flat texture in to space + // as part of our regular overlay pass. + // NOTE: this assumes nothing after this point gets drawn into + // the overlay-flat pass (otherwise it may get skipped). + // This should be a safe assumption since this is pretty much just for + // widgets. + if (IsVRMode() && frame_def->overlay_flat_pass()->HasDrawCommands()) { + // Draw our overlay-flat stuff into our overlay pass. + SpecialComponent c(frame_def->overlay_pass(), + SpecialComponent::Source::kVROverlayBuffer); + c.PushTransform(); + c.Translate(0.5f * kBaseVirtualResX, 0.5f * kBaseVirtualResY, 0.0f); + c.Scale(kBaseVirtualResX * (1.0f + kVRBorder), + kBaseVirtualResY * (1.0f + kVRBorder), + kBaseVirtualResX * (1.0f + kVRBorder)); + c.DrawModel(g_media->GetModel(SystemModelID::kVROverlay)); + c.PopTransform(); + c.Submit(); + } +} +void VRGraphics::DrawOverlayBounds(RenderPass* pass) { + // We can optionally draw a guide to show the edges of the overlay pass + if (draw_overlay_bounds_) { + SimpleComponent c(pass); + c.SetColor(1, 0, 0); + c.PushTransform(); + float width = screen_virtual_width(); + float height = screen_virtual_height(); + + // Slight offset in z to reduce z fighting. + c.Translate(0.5f * width, 0.5f * height, 1.0f); + c.Scale(width, height, 100.0f); + c.DrawModel(g_media->GetModel(SystemModelID::kOverlayGuide)); + c.PopTransform(); + c.Submit(); + } +} + +void VRGraphics::DrawVRControllers(FrameDef* frame_def) { + if (!IsVRMode()) { + return; + } + + // Disabling this for now. + return; + + // DEBUG - draw boxing glove just in front of our head transform to verify + // it's in the right place + if (false) { + ObjectComponent c(frame_def->beauty_pass()); + c.SetColor(1, 0, 0); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBoxingGlove)); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.4f, 0.4f, 0.4f); + c.PushTransform(); + c.VRTransformToHead(); + c.Translate(0, 0, 5); + c.Scale(2, 2, 2); + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + c.Submit(); + } + + // test right hand + const VRHandsState& s(g_game->vr_hands_state()); + + switch (s.r.type) { + case VRHandType::kOculusTouchR: + case VRHandType::kDaydreamRemote: { + ObjectComponent c(frame_def->beauty_pass()); + c.SetColor(0, 1, 0); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBoxingGlove)); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.4f, 0.4f, 0.4f); + c.PushTransform(); + c.VRTransformToRightHand(); + c.Scale(10, 10, 10); + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + c.Submit(); + break; + } + default: + break; + } + + switch (s.l.type) { + case VRHandType::kOculusTouchL: { + ObjectComponent c(frame_def->beauty_pass()); + c.SetColor(0, 0, 1); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBoxingGlove)); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.4f, 0.4f, 0.4f); + c.PushTransform(); + c.VRTransformToLeftHand(); + c.Scale(10, 10, 10); + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + c.Submit(); + break; + } + default: + break; + } +} + +} // namespace ballistica + +#endif // BA_VR_BUILD diff --git a/src/ballistica/graphics/vr_graphics.h b/src/ballistica/graphics/vr_graphics.h new file mode 100644 index 00000000..aad80eba --- /dev/null +++ b/src/ballistica/graphics/vr_graphics.h @@ -0,0 +1,86 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GRAPHICS_VR_GRAPHICS_H_ +#define BALLISTICA_GRAPHICS_VR_GRAPHICS_H_ + +#if BA_VR_BUILD + +#include + +#include "ballistica/graphics/graphics.h" + +namespace ballistica { + +const float kDefaultVRHeadScale = 18.0f; +const float kVRFixedOverlayOffsetY = -7.0f; +const float kVRFixedOverlayOffsetZ = -22.0f; + +class VRGraphics : public Graphics { + public: + /// Return g_graphics as a VRGraphics. (assumes it actually is one). + static VRGraphics* get() { + assert(g_graphics != nullptr); + assert(dynamic_cast(g_graphics) + == static_cast(g_graphics)); + return static_cast(g_graphics); + } + void ApplyCamera(FrameDef* frame_def) override; + void DrawWorld(Session* session, FrameDef* frame_def) override; + void DrawUI(FrameDef* frame_def) override; + + auto vr_head_forward() const -> const Vector3f& { return vr_head_forward_; } + auto vr_head_up() const -> const Vector3f& { return vr_head_up_; } + auto vr_head_translate() const -> const Vector3f& { + return vr_head_translate_; + } + void set_vr_head_forward(const Vector3f& v) { vr_head_forward_ = v; } + void set_vr_head_up(const Vector3f& v) { vr_head_up_ = v; } + void set_vr_head_translate(const Vector3f& v) { vr_head_translate_ = v; } + void set_vr_overlay_center(const Vector3f& val) { + assert(InGameThread()); + vr_overlay_center_ = val; + } + auto vr_overlay_center() const -> const Vector3f& { + return vr_overlay_center_; + } + void set_vr_overlay_center_enabled(bool val) { + assert(InGameThread()); + vr_overlay_center_enabled_ = val; + } + auto vr_overlay_center_enabled() const -> bool { + return vr_overlay_center_enabled_; + } + auto vr_near_clip() const -> float { return vr_near_clip_; } + void set_vr_near_clip(float val) { vr_near_clip_ = val; } + auto ValueTest(const std::string& arg, double* absval, double* deltaval, + double* outval) -> bool override; + + float vr_test_head_scale() const { return vr_test_head_scale_; } + + private: + void CalcVROverlayMatrices(FrameDef* frame_def); + auto CalcVROverlayMatrix(const Vector3f& cam_pt, + const Vector3f& cam_target_pt) const -> Matrix44f; + void DrawVROverlay(FrameDef* frame_def); + void DrawOverlayBounds(RenderPass* pass); + void DrawVRControllers(FrameDef* frame_def); + + float vr_overlay_scale_{1.0f}; + float vr_near_clip_{4.0f}; + float vr_cam_target_pt_smoothed_y_{}; + float vr_cam_target_pt_smoothed_z_{}; + Vector3f vr_head_forward_{0.0f, 0.0f, -1.0f}; + Vector3f vr_head_up_{0.0f, 1.0f, 0.0f}; + Vector3f vr_head_translate_{0.0f, 0.0f, 0.0f}; + Vector3f vr_overlay_center_{0.0f, 0.0f, 0.0f}; + bool vr_overlay_center_enabled_{}; + bool lock_vr_overlay_{}; + bool draw_overlay_bounds_{}; + float vr_test_head_scale_{kDefaultVRHeadScale}; +}; + +} // namespace ballistica + +#endif // BA_VR_BUILD + +#endif // BALLISTICA_GRAPHICS_VR_GRAPHICS_H_ diff --git a/src/ballistica/input/device/client_input_device.cc b/src/ballistica/input/device/client_input_device.cc new file mode 100644 index 00000000..8c7e32ee --- /dev/null +++ b/src/ballistica/input/device/client_input_device.cc @@ -0,0 +1,102 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/device/client_input_device.h" + +#include +#include + +#include "ballistica/game/connection/connection_to_client.h" +#include "ballistica/game/player.h" +#include "ballistica/networking/networking.h" + +namespace ballistica { + +ClientInputDevice::ClientInputDevice(int remote_device_id, + ConnectionToClient* connection_to_client) + : remote_device_id_(remote_device_id), + connection_to_client_(connection_to_client) {} + +// Hmm do we need to send a remote-detach in this case? +// I don't think so; if we're dying it means the connection is dying +// which means we probably couldn't communicate anyway and +// the other end will free the input-device up +ClientInputDevice::~ClientInputDevice() = default; + +auto ClientInputDevice::GetRawDeviceName() -> std::string { + return "Client Input Device"; +} + +auto ClientInputDevice::GetClientID() const -> int { + if (ConnectionToClient* c = connection_to_client_.get()) { + return c->id(); + } else { + Log("ClientInputDevice::get_client_id(): connection_to_client no longer " + "exists; returning -1.."); + return -1; + } +} + +auto ClientInputDevice::GetPlayerProfiles() const -> PyObject* { + if (connection_to_client_.exists()) { + return connection_to_client_->GetPlayerProfiles(); + } + return nullptr; +} + +auto ClientInputDevice::GetAccountName(bool full) const -> std::string { + assert(InGameThread()); + if (connection_to_client_.exists()) { + if (full) { + return connection_to_client_->peer_spec().GetDisplayString(); + } else { + return connection_to_client_->peer_spec().GetShortName(); + } + } + return "???"; +} + +auto ClientInputDevice::GetPublicAccountID() const -> std::string { + assert(InGameThread()); + if (connection_to_client_.exists()) { + return connection_to_client_->peer_public_account_id(); + } + return ""; +} + +void ClientInputDevice::AttachToLocalPlayer(Player* player) { + if (ConnectionToClient* c = connection_to_client_.get()) { + // Send a new-style message with a 32 bit player-id. + // (added during protocol 29; not always present) + { + std::vector data(6); + data[0] = BA_MESSAGE_ATTACH_REMOTE_PLAYER_2; + data[1] = static_cast_check_fit(remote_device_id_); + int val = player->id(); + memcpy(&(data[2]), &val, sizeof(val)); + c->SendReliableMessage(data); + } + + // We also need to send an old-style message as a fallback. + // FIXME: Can remove this once backwards-compat-protocol is > 29. + { + std::vector data(3); + data[0] = BA_MESSAGE_ATTACH_REMOTE_PLAYER; + data[1] = static_cast_check_fit(remote_device_id_); + data[2] = static_cast_check_fit(player->id()); + c->SendReliableMessage(data); + } + } + InputDevice::AttachToLocalPlayer(player); +} + +void ClientInputDevice::DetachFromPlayer() { + if (ConnectionToClient* c = connection_to_client_.get()) { + std::vector data(2); + data[0] = BA_MESSAGE_DETACH_REMOTE_PLAYER; + data[1] = static_cast_check_fit(remote_device_id_); + c->SendReliableMessage(data); + } + InputDevice::DetachFromPlayer(); +} + +} // namespace ballistica diff --git a/src/ballistica/input/device/client_input_device.h b/src/ballistica/input/device/client_input_device.h new file mode 100644 index 00000000..b24edbdd --- /dev/null +++ b/src/ballistica/input/device/client_input_device.h @@ -0,0 +1,44 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_DEVICE_CLIENT_INPUT_DEVICE_H_ +#define BALLISTICA_INPUT_DEVICE_CLIENT_INPUT_DEVICE_H_ + +#include + +#include "ballistica/input/device/input_device.h" + +namespace ballistica { + +/// Represents a remote player on a client connected to us. +class ClientInputDevice : public InputDevice { + public: + ClientInputDevice(int remote_device_id, + ConnectionToClient* connection_to_client); + ~ClientInputDevice() override; + + auto GetRawDeviceName() -> std::string override; + auto IsRemoteClient() const -> bool override { return true; } + auto GetClientID() const -> int override; + auto IsLocal() -> bool override { return false; } + + // Return player-profiles dict if available; otherwise nullptr. + auto GetPlayerProfiles() const -> PyObject* override; + auto GetAccountName(bool full) const -> std::string override; + auto GetPublicAccountID() const -> std::string override; + void AttachToLocalPlayer(Player* player) override; + void DetachFromPlayer() override; + void PassInputCommand(InputType type, float value) { + InputCommand(type, value); + } + auto connection_to_client() const -> ConnectionToClient* { + return connection_to_client_.get(); + } + + private: + Object::WeakRef connection_to_client_; + int remote_device_id_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_DEVICE_CLIENT_INPUT_DEVICE_H_ diff --git a/src/ballistica/input/device/input_device.cc b/src/ballistica/input/device/input_device.cc new file mode 100644 index 00000000..e0cb0215 --- /dev/null +++ b/src/ballistica/input/device/input_device.cc @@ -0,0 +1,320 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/device/input_device.h" + +#include +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/connection/connection_to_host.h" +#include "ballistica/game/player.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/game/session/net_client_session.h" +#include "ballistica/game/session/replay_client_session.h" +#include "ballistica/networking/networking.h" +#include "ballistica/python/class/python_class_input_device.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +static std::map* g_rand_name_registry = nullptr; +std::list g_default_names; + +InputDevice::InputDevice() = default; + +auto InputDevice::ShouldBeHiddenFromUser() -> bool { + // Ask the input system whether they want to ignore us.. + return g_input->ShouldCompletelyIgnoreInputDevice(this); +} + +auto InputDevice::GetDeviceName() -> std::string { + assert(InGameThread()); + return GetRawDeviceName(); +} + +void InputDevice::ResetRandomNames() { + assert(InGameThread()); + if (g_rand_name_registry == nullptr) return; + g_rand_name_registry->clear(); +} + +// Given a full name "SomeJoyStick #3" etc, reserves/returns a persistent random +// name for it. +static auto GetRandomName(const std::string& full_name) -> std::string { + assert(InGameThread()); + + // Hmm; statically allocating this is giving some crashes on shutdown :-( + if (g_rand_name_registry == nullptr) { + g_rand_name_registry = new std::map(); + } + + auto i = g_rand_name_registry->find(full_name); + if (i == g_rand_name_registry->end()) { + // Doesn't exist. Pull a random one and add it. + // Refill the global list if its empty. + if (g_default_names.empty()) { + const std::list& random_name_list = + Utils::GetRandomNameList(); + for (const auto& i2 : random_name_list) { + g_default_names.push_back(i2); + } + } + + // Ok now pull a random one off the list and assign it to us + int index = static_cast(rand() % g_default_names.size()); // NOLINT + auto i3 = g_default_names.begin(); + for (int j = 0; j < index; j++) { + i3++; + } + (*g_rand_name_registry)[full_name] = *i3; + g_default_names.erase(i3); + } + return (*g_rand_name_registry)[full_name]; +} + +auto InputDevice::GetPlayerProfiles() const -> PyObject* { return nullptr; } + +auto InputDevice::GetPublicAccountID() const -> std::string { + assert(InGameThread()); + + // this default implementation assumes the device is local + // so just returns the locally signed in account's public id.. + + // the master-server makes our public account-id available to us + // through a misc-read-val; look for that.. + std::string pub_id = + g_python->GetAccountMiscReadVal2String("resolvedAccountID"); + return pub_id; +} + +auto InputDevice::GetAccountName(bool full) const -> std::string { + assert(InGameThread()); + if (full) { + return PlayerSpec::GetAccountPlayerSpec().GetDisplayString(); + } else { + return PlayerSpec::GetAccountPlayerSpec().GetShortName(); + } +} + +auto InputDevice::IsRemoteClient() const -> bool { return false; } + +auto InputDevice::GetClientID() const -> int { return -1; } + +auto InputDevice::GetDefaultPlayerName() -> std::string { + assert(InGameThread()); + char buffer[256]; + snprintf(buffer, sizeof(buffer), "%s %s", GetDeviceName().c_str(), + GetPersistentIdentifier().c_str()); + std::string default_name = GetRandomName(buffer); + return default_name; +} + +auto InputDevice::GetButtonName(int id) -> std::string { + // By default just say 'button 1' or whatnot. + // FIXME: should return this in Lstr json form. + return g_game->GetResourceString("buttonText") + " " + std::to_string(id); +} + +auto InputDevice::GetAxisName(int id) -> std::string { + // By default just return 'axis 5' or whatnot. + // FIXME: should return this in Lstr json form. + return g_game->GetResourceString("axisText") + " " + std::to_string(id); +} + +auto InputDevice::HasMeaningfulButtonNames() -> bool { return false; } + +auto InputDevice::GetPersistentIdentifier() const -> std::string { + assert(InGameThread()); + char buffer[128]; + snprintf(buffer, sizeof(buffer), "#%d", number_); + return buffer; +} + +InputDevice::~InputDevice() { + assert(InGameThread()); + assert(!player_.exists()); + // release our python ref to ourself if we have one + if (py_ref_) { + Py_DECREF(py_ref_); + } +} + +// when the host-session tells us to attach to a player +void InputDevice::AttachToLocalPlayer(Player* player) { + if (player_.exists()) { + Log("Error: InputDevice::AttachToLocalPlayer() called with already " + "existing " + "player"); + return; + } + if (remote_player_.exists()) { + Log("Error: InputDevice::AttachToLocalPlayer() called with already " + "existing " + "remote-player"); + return; + } + player_ = player; + player_->SetInputDevice(this); +} + +void InputDevice::AttachToRemotePlayer(ConnectionToHost* connection_to_host, + int remote_player_id) { + assert(connection_to_host); + if (player_.exists()) { + Log("Error: InputDevice::AttachToRemotePlayer()" + " called with already existing " + "player"); + return; + } + if (remote_player_.exists()) { + Log("Error: InputDevice::AttachToRemotePlayer()" + " called with already existing " + "remote-player"); + return; + } + remote_player_ = connection_to_host; + remote_player_id_ = remote_player_id; +} + +void InputDevice::RemoveRemotePlayerFromGame() { + if (ConnectionToHost* connection_to_host = remote_player_.get()) { + std::vector data(2); + data[0] = BA_MESSAGE_REMOVE_REMOTE_PLAYER; + data[1] = static_cast_check_fit(index()); + connection_to_host->SendReliableMessage(data); + } else { + Log("Error: RemoveRemotePlayerFromGame called without remote player"); + } +} + +void InputDevice::DetachFromPlayer() { + if (player_.exists()) { + player_->SetInputDevice(nullptr); + player_.Clear(); + } + // Hmmm.. DetachFromPlayer() doesn't get called if the remote connection dies, + // but since its a weak-ref it should be all good since we don't do anything + // here except clear the weak-ref anyway... + if (remote_player_.exists()) { + remote_player_.Clear(); + } +} + +auto InputDevice::GetRemotePlayer() const -> ConnectionToHost* { + return remote_player_.get(); +} + +// Called to let the current host/client-session know that we'd like to control +// something please. +void InputDevice::RequestPlayer() { + assert(InGameThread()); + + // Make note that we're being used in some way. + last_input_time_ = g_game->master_time(); + + if (player_.exists()) { + Log("Error: InputDevice::RequestPlayer()" + " called with already-existing player"); + return; + } + if (remote_player_.exists()) { + Log("Error: InputDevice::RequestPlayer() called with already-existing " + "remote-player"); + return; + } + + // If we have a local host-session, ask it for a player.. otherwise if we have + // a client-session, ask it for a player. + assert(g_game); + if (auto* hs = dynamic_cast(g_game->GetForegroundSession())) { + { + Python::ScopedCallLabel label("requestPlayer"); + hs->RequestPlayer(this); + } + } else if (auto* client_session = dynamic_cast( + g_game->GetForegroundSession())) { + if (ConnectionToHost* connection_to_host = + client_session->connection_to_host()) { + std::vector data(2); + data[0] = BA_MESSAGE_REQUEST_REMOTE_PLAYER; + data[1] = static_cast_check_fit(index()); + connection_to_host->SendReliableMessage(data); + } + } + // If we're in a replay or the game is still bootstrapping, just ignore.. +} + +void InputDevice::ShipBufferIfFull() { + assert(remote_player_.exists()); + ConnectionToHost* hc = remote_player_.get(); + + // Ship the buffer once it gets big enough or once enough time has passed. + millisecs_t real_time = GetRealTime(); + size_t size = remote_input_commands_buffer_.size(); + if (size > 2 + && (static_cast(real_time - last_remote_input_commands_send_time_) + > g_app_globals->buffer_time + || size > 400)) { + last_remote_input_commands_send_time_ = real_time; + hc->SendReliableMessage(remote_input_commands_buffer_); + remote_input_commands_buffer_.clear(); + } +} + +// If we're attached to a remote player, ship completed packets every now and +// then. +void InputDevice::Update() { + if (remote_player_.exists()) { + ShipBufferIfFull(); + } +} + +void InputDevice::UpdateLastInputTime() { + last_input_time_ = g_game->master_time(); +} + +void InputDevice::InputCommand(InputType type, float value) { + assert(InGameThread()); + + // Make note that we're being used in some way. + UpdateLastInputTime(); + + if (Player* p = player_.get()) { + p->InputCommand(type, value); + } else if (remote_player_.exists()) { + // Add to existing buffer of input-commands. + { + size_t size = remote_input_commands_buffer_.size(); + // Init if empty; we'll fill in count(bytes 2+3) later. + if (size == 0) { + size = 2; + remote_input_commands_buffer_.resize(size); + remote_input_commands_buffer_[0] = + BA_MESSAGE_REMOTE_PLAYER_INPUT_COMMANDS; + remote_input_commands_buffer_[1] = + static_cast_check_fit(index()); + } + // Now add this command; add 1 byte for type, 4 for value. + remote_input_commands_buffer_.resize(remote_input_commands_buffer_.size() + + 5); + remote_input_commands_buffer_[size] = static_cast(type); + memcpy(&(remote_input_commands_buffer_[size + 1]), &value, 4); + } + } +} + +void InputDevice::ResetHeldStates() {} + +auto InputDevice::GetPyInputDevice(bool new_ref) -> PyObject* { + assert(InGameThread()); + if (py_ref_ == nullptr) { + py_ref_ = PythonClassInputDevice::Create(this); + } + if (new_ref) Py_INCREF(py_ref_); + return py_ref_; +} + +auto InputDevice::GetPartyButtonName() const -> std::string { return ""; } + +} // namespace ballistica diff --git a/src/ballistica/input/device/input_device.h b/src/ballistica/input/device/input_device.h new file mode 100644 index 00000000..6c852a51 --- /dev/null +++ b/src/ballistica/input/device/input_device.h @@ -0,0 +1,182 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_DEVICE_INPUT_DEVICE_H_ +#define BALLISTICA_INPUT_DEVICE_INPUT_DEVICE_H_ + +#include +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +/// Base class for game input devices (keyboard, joystick, etc). +/// InputDevices can be allocated in any thread (generally on the main +/// thread in response to some system event). An AddInputDevice() call +/// should then be pushed to the game thread to inform it of the new device. +/// Deletion of the input-device is then handled by the game thread +/// and can be triggered by pushing a RemoveInputDevice() call to it. +class InputDevice : public Object { + public: + InputDevice(); + ~InputDevice() override; + + /// Called when the device is attached/detached to a local player. + virtual void AttachToLocalPlayer(Player* player); + virtual void AttachToRemotePlayer(ConnectionToHost* connection_to_host, + int remote_player_id); + virtual void DetachFromPlayer(); + + /// Issues a command to the remote game to remove the player we're attached + /// to. + void RemoveRemotePlayerFromGame(); + + /// Return the (not necessarily unique) name of the input device. + auto GetDeviceName() -> std::string; + virtual void ResetHeldStates(); + + /// Return the default base player name for players using this input device. + virtual auto GetDefaultPlayerName() -> std::string; + + /// Return the name of the signed-in account associated with this device + /// (for remote players, returns their account). + virtual auto GetAccountName(bool full) const -> std::string; + + /// Return the public Account ID of the signed-in account associated + /// with this device, or an empty string if not (yet) available. + /// Note that in some cases there may be a delay before this value + /// is available. (remote player account IDs are verified with the + /// master server before becoming available, etc) + virtual auto GetPublicAccountID() const -> std::string; + + /// Returns player-profiles dict if available; otherwise nullptr. + virtual auto GetPlayerProfiles() const -> PyObject*; + + /// Return the name of the button used to evoke the party menu. + virtual auto GetPartyButtonName() const -> std::string; + + /// Returns a number specific to this device type (saying this is the Nth + /// device of this type). + auto device_number() const -> int { return number_; } + auto GetPersistentIdentifier() const -> std::string; + auto attached_to_player() const -> bool { + return player_.exists() || remote_player_.exists(); + } + auto GetRemotePlayer() const -> ConnectionToHost*; + auto GetPlayer() const -> Player* { return player_.get(); } + + /// Return the overall device index; unique to all devices. + auto index() const -> int { return index_; } + + /// Read new control values from config. + virtual void UpdateMapping() {} + + /// Called during the game loop - for manual button repeats, etc. + virtual void Update(); + + /// Return client id or -1 if local. + virtual auto GetClientID() const -> int; + + // FIXME: redundant. + virtual auto IsRemoteClient() const -> bool; + +#if BA_SDL_BUILD || BA_MINSDL_BUILD + virtual void HandleSDLEvent(const SDL_Event* e) {} +#endif + virtual auto GetAllowsConfiguring() -> bool { return true; } + + virtual auto IsController() -> bool { return false; } + virtual auto IsSDLController() -> bool { return false; } + virtual auto IsTouchScreen() -> bool { return false; } + virtual auto IsRemoteControl() -> bool { return false; } + virtual auto IsTestInput() -> bool { return false; } + virtual auto IsKeyboard() -> bool { return false; } + virtual auto IsMFiController() -> bool { return false; } + virtual auto IsLocal() -> bool { return true; } + virtual auto IsUIOnly() -> bool { return false; } + virtual auto IsRemoteApp() -> bool { return false; } + + /// Override this to return true if you implement get_button_name(). + // virtual auto HasButtonNames() -> bool { return false; } + + /// Return a human-readable name for a button/key. + virtual auto GetButtonName(int index) -> std::string; + + /// Return a human-readable name for an axis. + virtual auto GetAxisName(int index) -> std::string; + + /// Return whether button-names returned by GetButtonName() for this + /// device are identifiable to the user on the input-device itself. + /// For example, if a gamepad returns 'A', 'B', 'X', 'Y', etc. as names, + /// this should return true, but if it returns 'button 123', 'button 124', + /// etc. then it should return false. + virtual auto HasMeaningfulButtonNames() -> bool; + + /// Should return true if the input device has a start button and + /// that button activates default widgets (will cause a start icon to show up + /// on them). + virtual auto start_button_activates_default_widget() -> bool { return false; } + auto NewPyRef() -> PyObject* { return GetPyInputDevice(true); } + auto BorrowPyRef() -> PyObject* { return GetPyInputDevice(false); } + auto has_py_ref() -> bool { return (py_ref_ != nullptr); } + auto last_input_time() const -> millisecs_t { return last_input_time_; } + virtual auto ShouldBeHiddenFromUser() -> bool; + static void ResetRandomNames(); + + protected: + void ShipBufferIfFull(); + + /// Pass some input command on to whatever we're connected to + /// (player or remote-player). + void InputCommand(InputType type, float value = 0.0f); + + /// Called for all devices when they've successfully been added + /// to the input-device list, have a valid ID, name, etc. + virtual void ConnectionComplete() {} + + /// Subclasses should call this to request a player in the local game. + void RequestPlayer(); + + /// Return a human-readable name for the device's type. + /// This is used for display and also for storing configs/etc. + virtual auto GetRawDeviceName() -> std::string { return "Input Device"; } + + /// Return any extra description for the device. + /// This portion is only used for display and not for storing configs. + /// An example is Mac PS3 controllers; they return "(bluetooth)" or "(usb)" + /// here depending on how they are connected. + virtual auto GetDeviceExtraDescription() -> std::string { return ""; } + + /// Devices that have a way of identifying uniquely against other devices of + /// the same type (a serial number, usb-port, etc) should return that here as + /// a string. + virtual auto GetDeviceIdentifier() -> std::string { return ""; } + + auto remote_player_id() const -> int { return remote_player_id_; } + void UpdateLastInputTime(); + + private: + millisecs_t last_remote_input_commands_send_time_ = 0; + std::vector remote_input_commands_buffer_; + + // note: this is in base-net-time + millisecs_t last_input_time_ = 0; + + // We're attached to *one* of these two. + Object::WeakRef player_; + Object::WeakRef remote_player_; + + int remote_player_id_ = -1; + PyObject* py_ref_ = nullptr; + auto GetPyInputDevice(bool new_ref) -> PyObject*; + void set_index(int index_in) { index_ = index_in; } + void set_numbered_identifier(int n) { number_ = n; } + int index_ = -1; // Our overall device index. + int number_ = -1; // Our type-specific number. + friend class Input; + BA_DISALLOW_CLASS_COPIES(InputDevice); +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_DEVICE_INPUT_DEVICE_H_ diff --git a/src/ballistica/input/device/joystick.cc b/src/ballistica/input/device/joystick.cc new file mode 100644 index 00000000..93662f6f --- /dev/null +++ b/src/ballistica/input/device/joystick.cc @@ -0,0 +1,1568 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/device/joystick.h" + +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/game/player.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_command.h" +#include "ballistica/ui/root_ui.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/container_widget.h" + +namespace ballistica { + +const char* kMFiControllerName = "iOS/Mac Controller"; + +const int kJoystickRepeatDelay{500}; + +// Joy values below this are candidates for calibration. +const float kJoystickCalibrationThreshold{6000.0f}; + +// Joy events with at least this much movement break calibration. +const float kJoystickCalibrationBreakThreshold{300.0f}; + +// How long we gotta remain motionless for calibration to kick in. +const int kJoystickCalibrationTimeThreshold{1000}; + +// How fast calibration occurs. +const float kJoystickCalibrationSpeed = 0.7f; + +Joystick::Joystick(int sdl_joystick_id, const std::string& custom_device_name, + bool can_configure, bool calibrate) + : calibration_threshold_(kJoystickCalibrationThreshold), + calibration_break_threshold_(kJoystickCalibrationBreakThreshold), + custom_device_name_(custom_device_name), + can_configure_(can_configure), + creation_time_(GetRealTime()), + calibrate_(calibrate) { + // This is the default calibration for 'non-full' analog calibration. + for (float& analog_calibration_val : analog_calibration_vals_) { + analog_calibration_val = 0.6f; + } + + if (custom_device_name == "TestInput") { + is_test_input_ = true; + } + + sdl_joystick_id_ = sdl_joystick_id; + + // Non-negative values here mean its an SDL joystick. + if (sdl_joystick_id != -1) { +#if BA_ENABLE_SDL_JOYSTICKS + // Standard SDL joysticks should be getting created in the main thread. + // Custom joysticks can come from anywhere. + assert(InMainThread()); + + sdl_joystick_ = SDL_JoystickOpen(sdl_joystick_id); + assert(sdl_joystick_); + + // In SDL2 we're passed a device-id but that's only used to open the + // joystick; events and most everything else use an instance ID, so we store + // that instead. +#if BA_SDL2_BUILD + sdl_joystick_id_ = SDL_JoystickInstanceID(sdl_joystick_); + raw_sdl_joystick_name_ = SDL_JoystickName(sdl_joystick_); + + // Special case: on windows, xinput stuff comes in with unique names + // "XInput Controller #3", etc. Let's replace these with simply "XInput + // Controller" so configuring/etc is sane. + if (strstr(raw_sdl_joystick_name_.c_str(), "XInput Controller") + && raw_sdl_joystick_name_.size() >= 20 + && raw_sdl_joystick_name_.size() <= 22) { + raw_sdl_joystick_name_ = "XInput Controller"; + } +#else + raw_sdl_joystick_name_ = SDL_JoystickName(sdl_joystick_id_); +#endif // BA_SDL2_BUILD + + // If its an SDL joystick and we're using our custom sdl 1.2 build, ask it. +#if BA_XCODE_BUILD && BA_OSTYPE_MACOS && !BA_SDL2_BUILD + raw_sdl_joystick_identifier_ = SDL_JoystickIdentifier(sdl_joystick_id_); +#endif + + // Some special-cases on mac. + if (strstr(raw_sdl_joystick_name_.c_str(), "PLAYSTATION") != nullptr) { + is_mac_ps3_controller_ = true; + } + +#else // BA_ENABLE_SDL_JOYSTICKS + throw Exception(); // Shouldn't happen. +#endif // BA_ENABLE_SDL_JOYSTICKS + + } else { + // Its a manual joystick. + sdl_joystick_ = nullptr; + + is_mfi_controller_ = (custom_device_name_ == kMFiControllerName); + is_mac_wiimote_ = (custom_device_name_ == "Wiimote"); + + // Hard code a few remote controls. + // The newer way to do this is just set 'UI-Only' on the device config + is_remote_control_ = ((custom_device_name_ == "Amazon Remote") + || (custom_device_name_ == "Amazon Bluetooth Dev") + || (custom_device_name_ == "Amazon Fire TV Remote") + || (custom_device_name_ == "Nexus Remote")); + } +} + +auto Joystick::GetAxisName(int index) -> std::string { + // On android, lets return some popular axis names. + + if (g_buildconfig.ostype_android()) { + // Due to our stupid 1-based values we have to subtract 1 from our value to + // get the android motion-event constant. + // FIXME: should just make a call to android to get these values.. + switch (index) { + case 1: + return "Analog X"; + case 2: + return "Analog Y"; + case 12: + return "Analog Z"; + case 13: + return "Right Analog X"; + case 14: + return "Right Analog Y"; + case 15: + return "Right Analog Z"; + case 23: + return "Gas"; + case 24: + return "Brake"; + case 16: + return "Hat X"; + case 17: + return "Hat Y"; + case 18: + return "Left Trigger"; + case 19: + return "Right Trigger"; + default: + break; + } + } + + // Fall back to default implementation if we didn't cover it. + return InputDevice::GetAxisName(index); +} + +auto Joystick::HasMeaningfulButtonNames() -> bool { + // Only return true in cases where we know we have proper names + // for stuff. + if (is_mfi_controller_) { + return true; + } + return g_buildconfig.ostype_android(); +} + +auto Joystick::GetButtonName(int index) -> std::string { + // FIXME: Should get fancier here now that PS4 and XBone + // controllers are supported through this. + if (is_mfi_controller_) { + switch (index) { + case 1: + return "A"; + case 2: + return "X"; + case 3: + return "B"; + case 4: + return "Y"; + default: + break; + } + } + if (g_buildconfig.ostype_android()) { + // Special case: if this is a samsung controller, return the dice + // button icons. + if (strstr(GetDeviceName().c_str(), "Samsung Game Pad EI")) { + switch (index) { + case 101: + return g_game->CharStr(SpecialChar::kDiceButton4); // Y + case 100: + return g_game->CharStr(SpecialChar::kDiceButton3); // X + case 98: + return g_game->CharStr(SpecialChar::kDiceButton2); // B + case 97: + return g_game->CharStr(SpecialChar::kDiceButton1); // A + default: + break; + } + } + + // Some standard android button names: + switch (index) { + case 20: + return "Dpad Up"; + case 22: + return "Dpad Left"; + case 23: + return "Dpad Right"; + case 21: + return "Dpad Down"; + case 101: + return "Y"; + case 100: + return "X"; + case 98: + return "B"; + case 97: + return "A"; + case 83: + return "Menu"; + case 110: + return "Select"; + case 111: + return "Mode"; + case 109: + return "Start"; + case 107: + return "Thumb-L"; + case 108: + return "Thumb-R"; + case 103: + return "L1"; + case 104: + return "R1"; + case 105: + return "L2"; + case 106: + return "R2"; + case 126: + return "Forward"; + case 189: + return "B1"; + case 190: + return "B2"; + case 191: + return "B3"; + case 192: + return "B4"; + case 193: + return "B5"; + case 194: + return "B6"; + case 195: + return "B7"; + case 196: + return "B8"; + case 197: + return "B9"; + case 198: + return "B10"; + case 199: + return "B11"; + case 200: + return "B12"; + case 201: + return "B13"; + case 202: + return "B14"; + case 203: + return "B15"; + case 204: + return "B16"; + case 90: + return g_game->CharStr(SpecialChar::kRewindButton); + case 91: + return g_game->CharStr(SpecialChar::kFastForwardButton); + case 24: + return g_game->CharStr(SpecialChar::kDpadCenterButton); + case 86: + return g_game->CharStr(SpecialChar::kPlayPauseButton); + default: + break; + } + } + return InputDevice::GetButtonName(index); +} + +Joystick::~Joystick() { + if (!InGameThread()) { + Log("Error: Joystick dying in wrong thread."); + } + + // Kill our child if need be. + if (child_joy_stick_) { + g_input->RemoveInputDevice(child_joy_stick_, true); + child_joy_stick_ = nullptr; + } + + // If we're a wiimote, announce our departure. + if (g_buildconfig.ostype_macos() && is_mac_wiimote_) { + char msg[255]; + + int num = device_number(); + + // If we disconnected before any events came through, treat it as an error. + snprintf(msg, sizeof(msg), "Wii Remote #%d", num); + + // Ask the user to try again if the disconnect was immediate. + std::string s; + if (GetRealTime() - creation_time_ < 5000) { + s = g_game->GetResourceString("controllerDisconnectedTryAgainText"); + } else { + s = g_game->GetResourceString("controllerDisconnectedText"); + } + Utils::StringReplaceOne(&s, "${CONTROLLER}", msg); + ScreenMessage(s); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kCorkPop)); + } + + // Have SDL actually close the joystick in the main thread. + // Send a message back to the main thread to close this SDL Joystick. + // HMMM - can we just have the main thread close the joystick immediately + // before informing us its dead?.. i don't think we actually use it at all + // here in the game thread.. + if (sdl_joystick_) { +#if BA_ENABLE_SDL_JOYSTICKS + assert(g_app); + auto joystick = sdl_joystick_; + g_app->PushCall([joystick] { SDL_JoystickClose(joystick); }); + sdl_joystick_ = nullptr; +#else + Log("sdl_joystick_ set in non-sdl-joystick build destructor."); +#endif // BA_ENABLE_SDL_JOYSTICKS + } +} + +auto Joystick::GetDefaultPlayerName() -> std::string { + if (!custom_default_player_name_.empty()) { + return custom_default_player_name_; + } + return InputDevice::GetDefaultPlayerName(); +} + +void Joystick::ConnectionComplete() { + assert(InGameThread()); + + // Special case for mac wiimotes. + if (g_buildconfig.ostype_macos() && is_mac_wiimote_) { + char msg[128]; + + int num = device_number(); + + snprintf(msg, sizeof(msg), "Wii Remote #%d", num); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kGunCock)); + + // Replace ${CONTROLLER} with it in our message. + std::string s = g_game->GetResourceString("controllerConnectedText"); + Utils::StringReplaceOne(&s, "${CONTROLLER}", msg); + ScreenMessage(s); + return; + } +} + +auto Joystick::ShouldBeHiddenFromUser() -> bool { + std::string d_name = GetDeviceName(); + + // To lowercase. + int sz = static_cast(d_name.size()); + for (int i = 0; i < sz; i++) { + if (d_name[i] <= 'Z' && d_name[i] >= 'A') d_name[i] -= ('Z' - 'z'); + } + + const char* n = d_name.c_str(); + if (strstr(n, "mouse") || strstr(n, "keyboard") + || strstr(n, "athome_remote")) { + return true; + } else { + return InputDevice::ShouldBeHiddenFromUser(); + } +} + +auto Joystick::GetCalibratedValue(float raw, float neutral) const -> int32_t { + int32_t val; + float dead_zone = 0.5f; + float mag, target; + if (raw > neutral) { + mag = ((raw - neutral) / (calibration_threshold_ - neutral)); + target = calibration_threshold_; + } else { + mag = ((raw - neutral) / (-calibration_threshold_ - neutral)); + target = -calibration_threshold_; + } + if (mag < dead_zone) { + val = 0; + } else { + val = static_cast((1.0f - dead_zone) * mag * target); + } + return val; +} + +void Joystick::Update() { + InputDevice::Update(); + + assert(InGameThread()); + + // We seem to get a fair amount of bogus direction-pressed events from newly + // plugged in joysticks.. this leads to continuous scrolling in menus and such + // ...so lets reset our state once early after we're created. + if (!did_initial_reset_) { + ResetHeldStates(); + did_initial_reset_ = true; + } + + // Let's take this opportunity to update our calibration + // (should probably have a specific place to do that but this works) + if (calibrate_) { + millisecs_t time = GetRealTime(); + + // If we're doing 'aggressive' auto-recalibration we expand extents outward + // but suck them inward a tiny bit too to account for jitter or random fluke + // points. + if (auto_recalibrate_analog_stick_) { + int cell = static_cast( + (atan2(static_cast(jaxis_y_), static_cast(jaxis_x_)) + + kPi) + * ((kJoystickAnalogCalibrationDivisions) / (2.0f * kPi))); + cell = + std::min(kJoystickAnalogCalibrationDivisions - 1, std::max(0, cell)); + float x = jaxis_x_ / 32767.0f; + float y = jaxis_y_ / 32767.0f; + float mag = sqrtf(x * x + y * y); + if (mag > analog_calibration_vals_[cell]) { + analog_calibration_vals_[cell] = std::min(1.0f, mag); + + // Push the cell value up towards us a bit and also have it fall by a + // constant amount. + analog_calibration_vals_[cell] = std::min( + 1.0f, + std::max(0.25f, + 0.9f + * (analog_calibration_vals_[cell] + + (mag - analog_calibration_vals_[cell]) * 0.15f))); + } + } + + // Calibration: if we've been below our calibration thresholds for more than + // calibration-time, start averaging our current value into our calibrated + // neutral. + if (time - calibration_start_time_x_ > kJoystickCalibrationTimeThreshold + && (static_cast(std::abs(jaxis_raw_x_)) + < calibration_threshold_)) { + calibrated_neutral_x_ = + kJoystickCalibrationSpeed * jaxis_raw_x_ + + (1.0f - kJoystickCalibrationSpeed) * calibrated_neutral_x_; + + // Grab our new calibrated x value.. if it differs from the current, ship + // an event. + if (static_cast(std::abs(jaxis_raw_x_)) < calibration_threshold_) { + int32_t x = GetCalibratedValue(jaxis_raw_x_, calibrated_neutral_x_); + if (x != jaxis_x_) { + jaxis_x_ = x; + InputCommand(InputType::kLeftRight, + static_cast(jaxis_x_) / 32767.0f); + } + } + } + + if (time - calibration_start_time_y_ > kJoystickCalibrationTimeThreshold + && (static_cast(std::abs(jaxis_raw_y_)) + < calibration_threshold_)) { + calibrated_neutral_y_ = + kJoystickCalibrationSpeed * jaxis_raw_y_ + + (1.0f - kJoystickCalibrationSpeed) * calibrated_neutral_y_; + + // Grab our new calibrated x value.. if it differs from the current, ship + // an event. + if (fabs(static_cast(jaxis_raw_y_)) < calibration_threshold_) { + int32_t y = GetCalibratedValue(jaxis_raw_y_, calibrated_neutral_y_); + if (y != jaxis_y_) { + jaxis_y_ = y; + InputCommand(InputType::kUpDown, + static_cast(jaxis_y_) / 32767.0f); + } + } + } + } + + // If a button's being held, potentially pass repeats along. + if (up_held_ || down_held_ || left_held_ || right_held_) { + // Don't ask for the widget unless we have something held. + // (otherwise we prevent other inputs from getting at it) + if (g_ui->GetWidgetForInput(this)) { + millisecs_t repeat_delay = kJoystickRepeatDelay; + + millisecs_t t = GetRealTime(); + WidgetMessage::Type c = WidgetMessage::Type::kEmptyMessage; + if (t - last_hold_time_ < repeat_delay) { + return; + } + + if (t - last_hold_time_ >= repeat_delay) { + bool pass = false; + if (up_held_) { + pass = true; + c = WidgetMessage::Type::kMoveUp; + } else if (down_held_) { + pass = true; + c = WidgetMessage::Type::kMoveDown; + } else if (left_held_) { + pass = true; + c = WidgetMessage::Type::kMoveLeft; + } else if (right_held_) { + pass = true; + c = WidgetMessage::Type::kMoveRight; + } + if (pass) { + g_ui->SendWidgetMessage(WidgetMessage(c)); + } + + // Set another repeat to happen sooner. + last_hold_time_ = t - static_cast(repeat_delay * 0.8f); + } + } + } +} + +void Joystick::SetStandardExtendedButtons() { + // Assign some non-zero dpad values so we can drive them in custom joysticks. + up_button_ = 20; + down_button_ = 21; + left_button_ = 22; + right_button_ = 23; + run_trigger1_ = 10; + run_trigger2_ = 11; + back_button_ = 12; + remote_enter_button_ = 13; +} + +void Joystick::ResetHeldStates() { + // So we push events through even if there's a dialog in the way. + resetting_ = true; + + // Send ourself neutral joystick events. + SDL_Event e; + + dpad_right_held_ = dpad_left_held_ = dpad_up_held_ = dpad_down_held_ = false; + run_buttons_held_.clear(); + run_trigger1_value_ = run_trigger2_value_ = 0.0f; + UpdateRunningState(); + + if (hat_held_) { + e.type = SDL_JOYHATMOTION; + e.jhat.hat = static_cast_check_fit(hat_); + e.jhat.value = SDL_HAT_CENTERED; + HandleSDLEvent(&e); + } + + e.type = SDL_JOYAXISMOTION; + e.jaxis.axis = static_cast_check_fit(analog_lr_); + e.jaxis.value = static_cast(calibrated_neutral_x_); + HandleSDLEvent(&e); + + e.type = SDL_JOYAXISMOTION; + e.jaxis.axis = static_cast_check_fit(analog_ud_); + e.jaxis.value = static_cast(calibrated_neutral_y_); + HandleSDLEvent(&e); + + resetting_ = false; +} + +void Joystick::HandleSDLEvent(const SDL_Event* e) { + assert(InGameThread()); + + // If we've got a child joystick, send them any events they're set to handle. + if (child_joy_stick_) { + assert(g_game); + + bool send = false; + switch (e->type) { + case SDL_JOYAXISMOTION: { + // If its their analog stick or one of their run-triggers, send. + if (e->jaxis.axis == child_joy_stick_->analog_lr_ + || e->jaxis.axis == child_joy_stick_->analog_ud_ + || e->jaxis.axis == child_joy_stick_->run_trigger1_ + || e->jaxis.axis == child_joy_stick_->run_trigger2_) + send = true; + break; + } + case SDL_JOYHATMOTION: { + // If its their dpad hat, send. + if (e->jhat.hat == child_joy_stick_->hat_) send = true; + break; + } + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: { + // If its one of their 4 action buttons, 2 run buttons, or start, send. + if (e->jbutton.button == child_joy_stick_->jump_button_ + || e->jbutton.button == child_joy_stick_->punch_button_ + || e->jbutton.button == child_joy_stick_->bomb_button_ + || e->jbutton.button == child_joy_stick_->pickup_button_ + || e->jbutton.button == child_joy_stick_->start_button_ + || e->jbutton.button == child_joy_stick_->start_button_2_ + || e->jbutton.button == child_joy_stick_->run_button1_ + || e->jbutton.button == child_joy_stick_->run_button2_) + send = true; + break; + } + default: + break; + } + if (send) { + g_input->PushJoystickEvent(*e, child_joy_stick_); + return; + } + } + + // If we're set to ignore events completely, do so. + if (ignore_completely_) { + return; + } + + millisecs_t time = GetRealTime(); + SDL_Event e2; + + // Ignore analog-stick input while we're holding a hat switch or d-pad + // buttons. + if ((e->type == SDL_JOYAXISMOTION + && (e->jaxis.axis == analog_lr_ || e->jaxis.axis == analog_ud_)) + && (hat_held_ || dpad_right_held_ || dpad_left_held_ || dpad_up_held_ + || dpad_down_held_)) + return; + + bool isHoldPositionEvent = false; + + // Keep track of whether hold-position is being held. If so, we don't send + // window events. (some joysticks always give us significant axis values but + // rely on hold position to keep from doing stuff usually). + if (e->type == SDL_JOYBUTTONDOWN + && e->jbutton.button == hold_position_button_) { + need_to_send_held_state_ = true; + hold_position_held_ = true; + isHoldPositionEvent = true; + } + if (e->type == SDL_JOYBUTTONUP + && e->jbutton.button == hold_position_button_) { + need_to_send_held_state_ = true; + hold_position_held_ = false; + isHoldPositionEvent = true; + } + + // Let's ignore events for just a moment after we're created. + // (some joysticks seem to spit out erroneous button-pressed events when + // first plugged in ). + if (time - creation_time_ < 250 && !isHoldPositionEvent) { + return; + } + + // If we're using dpad-buttons, let's convert those events into joystick + // events. + // FIXME: should we do the same for hat buttons just to keep things + // consistent? + if (up_button_ >= 0 || left_button_ >= 0 || right_button_ >= 0 + || down_button_ >= 0 || up_button2_ >= 0 || left_button2_ >= 0 + || right_button2_ >= 0 || down_button2_ >= 0) { + switch (e->type) { + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + if (e->jbutton.button == right_button_ + || e->jbutton.button == right_button2_) { // D-pad right. + e2.type = SDL_JOYAXISMOTION; + e2.jaxis.axis = static_cast_check_fit(analog_lr_); + dpad_right_held_ = (e->type == SDL_JOYBUTTONDOWN); + e2.jaxis.value = static_cast_check_fit( + dpad_right_held_ ? (dpad_left_held_ ? 0 : 32767) + : dpad_left_held_ ? -32767 : 0); + e = &e2; + } else if (e->jbutton.button == left_button_ + || e->jbutton.button == left_button2_) { + e2.type = SDL_JOYAXISMOTION; + e2.jaxis.axis = static_cast_check_fit(analog_lr_); + dpad_left_held_ = (e->type == SDL_JOYBUTTONDOWN); + e2.jaxis.value = static_cast_check_fit( + dpad_right_held_ ? (dpad_left_held_ ? 0 : 32767) + : dpad_left_held_ ? -32767 : 0); + e = &e2; + } else if (e->jbutton.button == up_button_ + || e->jbutton.button == up_button2_) { + e2.type = SDL_JOYAXISMOTION; + e2.jaxis.axis = static_cast_check_fit(analog_ud_); + dpad_up_held_ = (e->type == SDL_JOYBUTTONDOWN); + e2.jaxis.value = static_cast_check_fit( + dpad_up_held_ ? (dpad_down_held_ ? 0 : -32767) + : dpad_down_held_ ? 32767 : 0); + e = &e2; + } else if (e->jbutton.button == down_button_ + || e->jbutton.button == down_button2_) { + e2.type = SDL_JOYAXISMOTION; + e2.jaxis.axis = static_cast_check_fit(analog_ud_); + dpad_down_held_ = (e->type == SDL_JOYBUTTONDOWN); + e2.jaxis.value = static_cast_check_fit( + dpad_up_held_ ? (dpad_down_held_ ? 0 : -32767) + : dpad_down_held_ ? 32767 : 0); + e = &e2; + } + break; + default: + break; + } + } + + // Track our hat-held state independently. + if (e->type == SDL_JOYHATMOTION && e->jhat.hat == hat_) { + switch (e->jhat.value) { + case SDL_HAT_CENTERED: + hat_held_ = false; + break; + case SDL_HAT_UP: + case SDL_HAT_DOWN: + case SDL_HAT_LEFT: + case SDL_HAT_RIGHT: + case SDL_HAT_LEFTUP: // NOLINT (signed bitwise) + case SDL_HAT_RIGHTUP: // NOLINT (signed bitwise) + case SDL_HAT_RIGHTDOWN: // NOLINT (signed bitwise) + case SDL_HAT_LEFTDOWN: // NOLINT (signed bitwise) + hat_held_ = true; + break; + default: + BA_LOG_ONCE("Error: Invalid hat value: " + + std::to_string(static_cast(e->jhat.value))); + break; + } + } + + // If its the ignore button, ignore it. + if ((e->type == SDL_JOYBUTTONDOWN || e->type == SDL_JOYBUTTONUP) + && (e->jbutton.button == ignored_button_ + || e->jbutton.button == ignored_button2_ + || e->jbutton.button == ignored_button3_ + || e->jbutton.button == ignored_button4_)) { + return; + } + + // A little pre-filtering on mac PS3 gamepads. (try to filter out some noise + // we're seeing, etc). + if (g_buildconfig.ostype_macos() && is_mac_ps3_controller_) { + switch (e->type) { + case SDL_JOYAXISMOTION: { + // On my ps3 controller, I seem to be seeing occasional joy-axis-events + // coming in with values of -32768 when nothing is being touched. + // Filtering those out here.. Should look into this more and see if its + // SDL's fault or else forward a bug to apple. + if ((e->jaxis.axis == 0 || e->jaxis.axis == 1) + && e->jaxis.value == -32768 + && (time - ps3_last_joy_press_time_ > 2000) && !ps3_jaxis1_pressed_ + && !ps3_jaxis2_pressed_) { + printf( + "BAJoyStick notice: filtering out errand PS3 axis %d value of " + "%d\n", + static_cast(e->jaxis.axis), + static_cast(e->jaxis.value)); + fflush(stdout); + + // std::cout << "BSJoyStick notice: filtering out errant PS3 axis " << + // int(e->jaxis.axis) << " value of " << e->jaxis.value << std::endl; + return; + } + + if (abs(e->jaxis.value) >= kJoystickDiscreteThreshold) { + ps3_last_joy_press_time_ = time; + } + + // Keep track of whether its pressed for next time. + if (e->jaxis.axis == 0) { + ps3_jaxis1_pressed_ = (abs(e->jaxis.value) > 3000); + } else if (e->jaxis.axis == 1) { + ps3_jaxis2_pressed_ = (abs(e->jaxis.value) > 3000); + } + + break; + } + default: + break; + } + } + + // A few high level button press interceptions. + if (e->type == SDL_JOYBUTTONDOWN) { + if (e->jbutton.button == start_button_ + || e->jbutton.button == start_button_2_) { + // If there's some UI up already, we just pass this along to it. + // otherwise we request a main menu. + if (g_ui && g_ui->screen_root_widget() + && g_ui->screen_root_widget()->HasChildren()) { + // Do nothing in this case. + } else { + // If there's no menu up, + // tell the game to pop it up and snag menu ownership for ourself. + g_game->PushMainMenuPressCall(this); + return; + } + } + + // On our oculus build, select presses reset the orientation. + if (e->jbutton.button == vr_reorient_button_ && IsVRMode()) { + ScreenMessage(g_game->GetResourceString("vrOrientationResetText"), + {0, 1, 0}); + g_app_globals->reset_vr_orientation = true; + return; + } + } + + // Update some calibration parameters. + if (e->type == SDL_JOYAXISMOTION) { + if (e->jaxis.axis == analog_lr_) { + // If we've moved by more than a small amount, break calibration. + if (static_cast(abs(e->jaxis.value - jaxis_raw_x_)) + > calibration_break_threshold_) { + calibration_start_time_x_ = time; + } + jaxis_raw_x_ = e->jaxis.value; + + // Just take note if we're below our calibration threshold + // (actual calibration happens in update-repeats). + if (static_cast(abs(e->jaxis.value)) > calibration_threshold_) { + calibration_start_time_x_ = time; + } + } else if (e->jaxis.axis == analog_ud_) { + // If we've moved by more than a small amount, break calibration. + if (static_cast(abs(e->jaxis.value - jaxis_raw_y_)) + > calibration_break_threshold_) { + calibration_start_time_y_ = time; + } + jaxis_raw_y_ = e->jaxis.value; + + // Just take note if we're below our calibration threshold + // (actual calibration happens in update-repeats). + if (static_cast(abs(e->jaxis.value)) > calibration_threshold_) { + calibration_start_time_y_ = time; + } + } + } + + // If we're in a dialog, send dialog events. + // We keep track of special x/y values for dialog usage. + // These are formed as combinations of the actual joy value + // and the hold-position state. + // Think of hold-position as somewhat of a 'magnitude' to the joy event's + // direction. They're really one and the same event. (we just need to store + // their states ourselves since they don't both come through at once). + bool isAnalogStickJAxisEvent = false; + if (e->type == SDL_JOYAXISMOTION) { + if (e->jaxis.axis == analog_lr_) { + dialog_jaxis_x_ = e->jaxis.value; + isAnalogStickJAxisEvent = true; + } else if (e->jaxis.axis == analog_ud_) { + dialog_jaxis_y_ = e->jaxis.value; + isAnalogStickJAxisEvent = true; + } + } + int dialogJaxisX = dialog_jaxis_x_; + if (hold_position_held_) { + dialogJaxisX = 0; // Throttle is off. + } + int dialogJaxisY = dialog_jaxis_y_; + if (hold_position_held_) { + dialogJaxisY = 0; // Throttle is off. + } + + // We might not wanna grab at the UI if we're a axis-motion event + // below our 'pressed' threshold.. Otherwise fuzzy analog joystick + // readings would cause rampant UI stealing even if no events are being sent. + bool would_go_to_dialog = false; + WidgetMessage::Type wm = WidgetMessage::Type::kEmptyMessage; + + if (isAnalogStickJAxisEvent || isHoldPositionEvent) { + // Even when we're not sending, clear out some 'held' states. + if (left_held_ && dialogJaxisX >= -kJoystickDiscreteThreshold) { + left_held_ = false; + } + if (right_held_ && dialogJaxisX <= kJoystickDiscreteThreshold) { + right_held_ = false; + } + if (up_held_ && dialogJaxisY >= -kJoystickDiscreteThreshold) { + up_held_ = false; + } + if (down_held_ && dialogJaxisY <= kJoystickDiscreteThreshold) { + down_held_ = false; + } + if ((!right_held_) && dialogJaxisX > kJoystickDiscreteThreshold) + would_go_to_dialog = true; + if ((!left_held_) && dialogJaxisX < -kJoystickDiscreteThreshold) + would_go_to_dialog = true; + if ((!up_held_) && dialogJaxisY < -kJoystickDiscreteThreshold) + would_go_to_dialog = true; + if ((!down_held_) && dialogJaxisY > kJoystickDiscreteThreshold) + would_go_to_dialog = true; + } else if ((e->type == SDL_JOYHATMOTION && e->jhat.hat == hat_) + || (e->type == SDL_JOYBUTTONDOWN + && e->jbutton.button != hold_position_button_)) { + // Other button-downs and hat motions always go. + would_go_to_dialog = true; + } + + // Resets always circumvent dialogs. + if (resetting_) would_go_to_dialog = false; + + // Anything that would go to a dialog also counts to mark us as + // 'recently-used'. + if (would_go_to_dialog) { + UpdateLastInputTime(); + } + + if (would_go_to_dialog && g_ui->GetWidgetForInput(this)) { + bool pass = false; + + // Special case.. either joy-axis-motion or hold-position events trigger + // these. + if (isAnalogStickJAxisEvent || isHoldPositionEvent) { + if (dialogJaxisX > kJoystickDiscreteThreshold) { + // To the right. + if (!right_held_ && !up_held_ && !down_held_) { + last_hold_time_ = GetRealTime(); + right_held_ = true; + wm = WidgetMessage::Type::kMoveRight; + pass = true; + } + } else if (dialogJaxisX < -kJoystickDiscreteThreshold) { + if (!left_held_ && !up_held_ && !down_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveLeft; + pass = true; + left_held_ = true; + } + } + if (dialogJaxisY > kJoystickDiscreteThreshold) { + if (!down_held_ && !left_held_ && !right_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveDown; + pass = true; + down_held_ = true; + } + } else if (dialogJaxisY < -kJoystickDiscreteThreshold) { + if (!up_held_ && !left_held_ && !right_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveUp; + pass = true; + up_held_ = true; + } + } + } + + switch (e->type) { + case SDL_JOYAXISMOTION: + break; + + case SDL_JOYHATMOTION: { + if (e->jhat.hat == hat_) { + switch (e->jhat.value) { + case SDL_HAT_LEFT: { + if (!left_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveLeft; + pass = true; + left_held_ = true; + right_held_ = false; + } + break; + } + + case SDL_HAT_RIGHT: { + if (!right_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveRight; + pass = true; + right_held_ = true; + left_held_ = false; + } + break; + } + case SDL_HAT_UP: { + if (!up_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveUp; + pass = true; + up_held_ = true; + down_held_ = false; + } + break; + } + case SDL_HAT_DOWN: { + if (!down_held_) { + last_hold_time_ = GetRealTime(); + wm = WidgetMessage::Type::kMoveDown; + pass = true; + down_held_ = true; + up_held_ = false; + } + break; + } + case SDL_HAT_CENTERED: { + up_held_ = false; + down_held_ = false; + left_held_ = false; + right_held_ = false; + } + default: + break; + } + } + break; + } + case SDL_JOYBUTTONDOWN: { + if (e->jbutton.button != hold_position_button_) { + pass = true; + if (e->jbutton.button == start_button_ + || e->jbutton.button == start_button_2_) { + if (start_button_activates_default_widget_) + wm = WidgetMessage::Type::kStart; + else + pass = false; + } else if (e->jbutton.button == bomb_button_ + || e->jbutton.button == back_button_) { + wm = WidgetMessage::Type::kCancel; + } else { + // FIXME: Need a call we can make for this. + bool do_party_button = false; + int party_size = g_game->GetPartySize(); + if (party_size > 1 || g_game->connection_to_host() + || g_ui->root_ui()->always_draw_party_icon()) { + do_party_button = true; + } + + // Toggle the party UI if we're pressing the party button. + // (currently don't allow remote to do this.. need to make it + // customizable) + if (do_party_button && e->jbutton.button == pickup_button_ + && (!IsRemoteControl())) { + pass = false; + g_ui->root_ui()->ActivatePartyIcon(); + break; + } + wm = WidgetMessage::Type::kActivate; + } + } + } break; + default: + break; + } + if (pass) { + g_ui->SendWidgetMessage(WidgetMessage(wm)); + } + return; + } + + // If there's a UI up (even if we didn't get it) lets not pass events along. + // The only exception is if we're doing a reset. + Widget* root{}; + if (g_ui) { + root = g_ui->screen_root_widget(); + } + if (root && root->HasChildren() && !resetting_) { + return; + } + + if (!attached_to_player()) { + if (e->type == SDL_JOYBUTTONDOWN + && (e->jbutton.button != hold_position_button_) + && (e->jbutton.button != back_button_)) { + if (ui_only_ || e->jbutton.button == remote_enter_button_) { + millisecs_t current_time = GetRealTime(); + if (current_time - last_ui_only_print_time_ > 5000) { + g_python->obj(Python::ObjID::kUIRemotePressCall).Call(); + last_ui_only_print_time_ = current_time; + } + } else { + RequestPlayer(); + // we always want to inform new players of our hold-position-state.. + // make a note to do that. + need_to_send_held_state_ = true; + } + } + return; + } + + // Ok we've got a player; just send events along. + + // Held state is a special case; we wanna always send that along first thing + // if its changed. This is because some joysticks rely on it being on by + // default. + if (need_to_send_held_state_) { + if (hold_position_held_) { + InputCommand(InputType::kHoldPositionPress); + } else { + InputCommand(InputType::kHoldPositionRelease); + } + need_to_send_held_state_ = false; + } + + switch (e->type) { + case SDL_JOYAXISMOTION: { + // Handle run-trigger presses. + if (e->jaxis.axis == run_trigger1_ || e->jaxis.axis == run_trigger2_) { + if (e->jaxis.axis == run_trigger1_) { + float value = static_cast(e->jaxis.value) / 32767.0f; + + // If we're calibrating, update calibration bounds and calc a + // calibrated value. + if (calibrate_) { + if (value < run_trigger1_min_) { + run_trigger1_min_ = value; + } else if (value > run_trigger1_max_) { + run_trigger1_max_ = value; + } + run_trigger1_value_ = (value - run_trigger1_min_) + / (run_trigger1_max_ - run_trigger1_min_); + } else { + run_trigger1_value_ = value; + } + } else { + float value = static_cast(e->jaxis.value) / 32767.0f; + + // If we're calibrating, update calibration bounds and calc a + // calibrated value. + if (calibrate_) { + if (value < run_trigger2_min_) { + run_trigger2_min_ = value; + } else if (value > run_trigger2_max_) { + run_trigger2_max_ = value; + } + run_trigger2_value_ = (value - run_trigger2_min_) + / (run_trigger2_max_ - run_trigger2_min_); + } else { + run_trigger2_value_ = value; + } + } + UpdateRunningState(); + } + InputType input_type; + int32_t input_value; + if (e->jaxis.axis == analog_lr_) { + input_type = InputType::kLeftRight; + input_value = e->jaxis.value; + if (calibrate_) { + if (static_cast(abs(jaxis_raw_x_)) < calibration_threshold_ + && static_cast(abs(jaxis_raw_y_)) + < calibration_threshold_) { + input_value = + GetCalibratedValue(input_value, calibrated_neutral_x_); + } + } + if (input_value > 32767) { + input_value = 32767; + } else if (input_value < -32767) { + input_value = -32767; + } + jaxis_x_ = input_value; + } else if (e->jaxis.axis == analog_ud_) { + input_type = InputType::kUpDown; + input_value = e->jaxis.value; + if (calibrate_) { + if (static_cast(abs(jaxis_raw_x_)) < calibration_threshold_ + && static_cast(abs(jaxis_raw_y_)) + < calibration_threshold_) { + input_value = + GetCalibratedValue(input_value, calibrated_neutral_y_); + } + } + input_value = -input_value; + if (input_value > 32767) { + input_value = 32767; + } else if (input_value < -32767) { + input_value = -32767; + } + jaxis_y_ = input_value; + } else { + break; + } + + // Update extent calibration and scale based on that. + if (calibrate_) { + // Handle analog stick calibration.. 'full' auto-recalibration. + if (auto_recalibrate_analog_stick_) { + int cell = static_cast( + (atan2(static_cast(jaxis_y_), static_cast(jaxis_x_)) + + kPi) + * ((kJoystickAnalogCalibrationDivisions) / (2.0f * kPi))); + cell = std::min(kJoystickAnalogCalibrationDivisions - 1, + std::max(0, cell)); + input_value *= (1.0f / analog_calibration_vals_[cell]); + if (input_value > 32767) { + input_value = 32767; + } else if (input_value < -32767) { + input_value = -32767; + } + } + } + InputCommand(input_type, static_cast(input_value) / 32767.0f); + break; + } + case SDL_JOYBUTTONDOWN: { + if (unassigned_buttons_run_ || e->jbutton.button == punch_button_ + || e->jbutton.button == jump_button_ + || e->jbutton.button == bomb_button_ + || e->jbutton.button == pickup_button_ + || e->jbutton.button == run_button1_ + || e->jbutton.button == run_button2_) { + run_buttons_held_.insert(e->jbutton.button); + } + UpdateRunningState(); + if (e->jbutton.button == jump_button_) { + // FIXME: we should just do one or the other here depending on the game + // mode to reduce the number of events sent. + InputCommand(InputType::kJumpPress); + InputCommand(InputType::kFlyPress); + } else if (e->jbutton.button == punch_button_) { + InputCommand(InputType::kPunchPress); + } else if (e->jbutton.button == bomb_button_) { + InputCommand(InputType::kBombPress); + } else if (e->jbutton.button == pickup_button_) { + InputCommand(InputType::kPickUpPress); + } + break; + } + case SDL_JOYBUTTONUP: { + { + auto i = run_buttons_held_.find(e->jbutton.button); + if (i != run_buttons_held_.end()) { + run_buttons_held_.erase(i); + } + UpdateRunningState(); + } + if (e->jbutton.button == jump_button_) { + InputCommand(InputType::kJumpRelease); + InputCommand(InputType::kFlyRelease); + } else if (e->jbutton.button == punch_button_) { + InputCommand(InputType::kPunchRelease); + } else if (e->jbutton.button == bomb_button_) { + InputCommand(InputType::kBombRelease); + } else if (e->jbutton.button == pickup_button_) { + InputCommand(InputType::kPickUpRelease); + } + break; + } + case SDL_JOYBALLMOTION: { + break; + } + case SDL_JOYHATMOTION: { + if (e->jhat.hat == hat_) { + int16_t input_value_lr = 0; + int16_t input_value_ud = 0; + switch (e->jhat.value) { + case SDL_HAT_CENTERED: + input_value_lr = 0; + input_value_ud = 0; + break; + case SDL_HAT_UP: + input_value_lr = 0; + input_value_ud = 32767; + break; + case SDL_HAT_DOWN: + input_value_lr = 0; + input_value_ud = -32767; + break; + case SDL_HAT_LEFT: + input_value_lr = -32767; + input_value_ud = 0; + break; + case SDL_HAT_RIGHT: + input_value_lr = 32767; + input_value_ud = 0; + break; + case SDL_HAT_LEFTUP: // NOLINT (signed bitwise) + input_value_lr = -32767; + input_value_ud = 32767; + break; + case SDL_HAT_RIGHTUP: // NOLINT (signed bitwise) + input_value_lr = 32767; + input_value_ud = 32767; + break; + case SDL_HAT_RIGHTDOWN: // NOLINT (signed bitwise) + input_value_lr = 32767; + input_value_ud = -32767; + break; + case SDL_HAT_LEFTDOWN: // NOLINT (signed bitwise) + input_value_lr = -32767; + input_value_ud = -32767; + break; + default: + break; + } + InputCommand(InputType::kLeftRight, + static_cast(input_value_lr) / 32767.0f); + InputCommand(InputType::kUpDown, + static_cast(input_value_ud) / 32767.0f); + } + break; + } + default: + break; + } +} // NOLINT(readability/fn_size) Yes I know this is too long. + +void Joystick::UpdateRunningState() { + if (!attached_to_player()) { + return; + } + float value; + float prev_value = run_value_; + + // If there's a button held, our default value is 1.0. + if (!run_buttons_held_.empty()) { + value = 1.0f; + } else { + value = 0.0f; + } + + // Now check our analog run triggers. + value = std::max(value, run_trigger1_value_); + value = std::max(value, run_trigger2_value_); + + if (value != prev_value) { + run_value_ = value; + InputCommand(InputType::kRun, run_value_); + } +} + +void Joystick::UpdateMapping() { + assert(InGameThread()); + + // This doesn't apply to manual ones (except children which are). + if (!can_configure_ && !parent_joy_stick_) { + return; + } + + // If we're a child, use our parent's id to search for config values and just + // tack on a '2'. + Joystick* js = parent_joy_stick_ ? parent_joy_stick_ : this; + std::string ext = parent_joy_stick_ ? "_B" : ""; + + // Grab all button values from Python. Traditionally we stored these + // with the first index 1 so we need to subtract 1 to get the zero-indexed + // value. (grumble). + jump_button_ = g_python->GetControllerValue(js, "buttonJump" + ext) - 1; + punch_button_ = g_python->GetControllerValue(js, "buttonPunch" + ext) - 1; + bomb_button_ = g_python->GetControllerValue(js, "buttonBomb" + ext) - 1; + pickup_button_ = g_python->GetControllerValue(js, "buttonPickUp" + ext) - 1; + start_button_ = g_python->GetControllerValue(js, "buttonStart" + ext) - 1; + start_button_2_ = g_python->GetControllerValue(js, "buttonStart2" + ext) - 1; + hold_position_button_ = + g_python->GetControllerValue(js, "buttonHoldPosition" + ext) - 1; + run_button1_ = g_python->GetControllerValue(js, "buttonRun1" + ext) - 1; + run_button2_ = g_python->GetControllerValue(js, "buttonRun2" + ext) - 1; + vr_reorient_button_ = + g_python->GetControllerValue(js, "buttonVRReorient" + ext) - 1; + ignored_button_ = g_python->GetControllerValue(js, "buttonIgnored" + ext) - 1; + ignored_button2_ = + g_python->GetControllerValue(js, "buttonIgnored2" + ext) - 1; + ignored_button3_ = + g_python->GetControllerValue(js, "buttonIgnored3" + ext) - 1; + ignored_button4_ = + g_python->GetControllerValue(js, "buttonIgnored4" + ext) - 1; + int old_run_trigger_1 = run_trigger1_; + run_trigger1_ = g_python->GetControllerValue(js, "triggerRun1" + ext) - 1; + int old_run_trigger_2 = run_trigger2_; + run_trigger2_ = g_python->GetControllerValue(js, "triggerRun2" + ext) - 1; + up_button_ = g_python->GetControllerValue(js, "buttonUp" + ext) - 1; + left_button_ = g_python->GetControllerValue(js, "buttonLeft" + ext) - 1; + right_button_ = g_python->GetControllerValue(js, "buttonRight" + ext) - 1; + down_button_ = g_python->GetControllerValue(js, "buttonDown" + ext) - 1; + up_button2_ = g_python->GetControllerValue(js, "buttonUp2" + ext) - 1; + left_button2_ = g_python->GetControllerValue(js, "buttonLeft2" + ext) - 1; + right_button2_ = g_python->GetControllerValue(js, "buttonRight2" + ext) - 1; + down_button2_ = g_python->GetControllerValue(js, "buttonDown2" + ext) - 1; + unassigned_buttons_run_ = static_cast( + g_python->GetControllerValue(js, "unassignedButtonsRun" + ext)); + + // If our run trigger has changed, reset its calibration. + // NOTE: It looks like on Mac we're getting analog trigger values from -1 to 1 + // while on Android we're getting from 0 to 1.. adding this calibration stuff + // allows us to cover both cases though. + if (old_run_trigger_1 != run_trigger1_) { + run_trigger1_min_ = 0.2f; + run_trigger1_max_ = 0.8f; + } + if (old_run_trigger_2 != run_trigger2_) { + run_trigger2_min_ = 0.2f; + run_trigger2_max_ = 0.8f; + } + + int ival = g_python->GetControllerValue(js, "uiOnly" + ext); + if (ival == -1) { + ui_only_ = false; + } else { + ui_only_ = static_cast(ival); + } + + ival = g_python->GetControllerValue(js, "ignoreCompletely" + ext); + if (ival == -1) { + ignore_completely_ = false; + } else { + ignore_completely_ = static_cast(ival); + } + + ival = g_python->GetControllerValue(js, "autoRecalibrateAnalogSticks" + ext); + + { + bool was_on = auto_recalibrate_analog_stick_; + if (ival == -1) { + auto_recalibrate_analog_stick_ = false; + } else { + auto_recalibrate_analog_stick_ = static_cast(ival); + } + bool is_on = auto_recalibrate_analog_stick_; + + // If we're flipping on full auto-recalibration, start our extents small. + if (!was_on && is_on) { + for (float& analog_calibration_val : analog_calibration_vals_) { + analog_calibration_val = 0.25f; + } + } + + // If we're flipping it off, reset to default calibration values. + if (was_on && !is_on) { + for (float& analog_calibration_val : analog_calibration_vals_) { + analog_calibration_val = 0.6f; + } + } + } + + ival = g_python->GetControllerValue( + js, "startButtonActivatesDefaultWidget" + ext); + + if (ival == -1) { + start_button_activates_default_widget_ = true; + } else { + start_button_activates_default_widget_ = static_cast(ival); + } + + // Update calibration stuff. + float as = g_python->GetControllerFloatValue(js, "analogStickDeadZone" + ext); + + if (as < 0) { + as = 1.0f; + } + + // Avoid possibility of divide-by-zero errors. + if (as < 0.01f) { + as = 0.01f; + } + + calibration_threshold_ = kJoystickCalibrationThreshold * as; + calibration_break_threshold_ = kJoystickCalibrationBreakThreshold * as; + + hat_ = g_python->GetControllerValue(js, "dpad" + ext) - 1; + + // If unset, use our default. + if (hat_ == -2) { + if (parent_joy_stick_) { + hat_ = 1; + } else { + hat_ = 0; + } + } + + // Grab our analog stick. + analog_lr_ = g_python->GetControllerValue(js, "analogStickLR" + ext) - 1; + + // If we got unset, set to our default. + if (analog_lr_ == -2) { + if (parent_joy_stick_) { + analog_lr_ = 4; + } else { + analog_lr_ = 0; + } + } + + analog_ud_ = g_python->GetControllerValue(js, "analogStickUD" + ext) - 1; + + // If we got unset, set to our default. + if (analog_ud_ == -2) { + if (parent_joy_stick_) { + analog_ud_ = 5; + } else { + analog_ud_ = 1; + } + } + + // See whether we have a child-joystick and create it if need be. + if (!parent_joy_stick_) { + int enable = g_python->GetControllerValue(js, "enableSecondary"); + if (enable == -1) { + enable = 0; + } + + // Create if need be. + if (enable) { + char m[256]; + snprintf(m, sizeof(m), "%s B", GetDeviceName().c_str()); + if (!child_joy_stick_) { + child_joy_stick_ = + Object::NewDeferred(-1, // Not an sdl joystick. + m, // Device name. + false, // Allow configuring. + true); // Do calibrate. + child_joy_stick_->parent_joy_stick_ = this; + assert(g_input); + g_input->AddInputDevice(child_joy_stick_, true); + } + } else { + // Kill if need be. + if (child_joy_stick_) { + g_input->RemoveInputDevice(child_joy_stick_, true); + child_joy_stick_ = nullptr; + } + } + } +} + +auto Joystick::GetRawDeviceName() -> std::string { + if (!custom_device_name_.empty()) { + return custom_device_name_; + } + + // For sdl joysticks just return the sdl string. + if (sdl_joystick_) { + std::string s = raw_sdl_joystick_name_; + if (s.empty()) { + s = "untitled joystick"; + } + return s; + } else { + // The one case we can currently hit this is with android controllers - (if + // an empty name is passed for the controller type). + return "Unknown Input Device"; + } +} + +auto Joystick::GetDeviceExtraDescription() -> std::string { + std::string s; + + // On mac, PS3 controllers can connect via USB or bluetooth, + // and it can be confusing if one is doing both, + // so lets specify here. + if (GetDeviceName() == "PLAYSTATION(R)3 Controller") { + // For bluetooth we get a serial in the form "04-76-6e-d1-17-90" while + // on USB we get a simple int (the usb location id): "-9340234" + // so lets consider it wireless if its got a dash not at the beginning. + s = " (USB)"; + + auto dname = GetDeviceIdentifier(); + for (const char* tst = dname.c_str(); *tst; tst++) { + if (*tst == '-' && tst != dname) { + s = " (Bluetooth)"; + } + } + } + + return s; +} + +auto Joystick::GetDeviceIdentifier() -> std::string { + return raw_sdl_joystick_identifier_; +} + +auto Joystick::GetPartyButtonName() const -> std::string { + return g_game->CharStr(SpecialChar::kTopButton); +} + +} // namespace ballistica diff --git a/src/ballistica/input/device/joystick.h b/src/ballistica/input/device/joystick.h new file mode 100644 index 00000000..597ec4a4 --- /dev/null +++ b/src/ballistica/input/device/joystick.h @@ -0,0 +1,201 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_DEVICE_JOYSTICK_H_ +#define BALLISTICA_INPUT_DEVICE_JOYSTICK_H_ + +#include +#include + +#include "ballistica/input/device/input_device.h" + +namespace ballistica { + +// iOS controllers feel more natural with a lower threshold here, +// but it throws off cheap controllers elsewhere. +// not sure what's the right answer.. (should revisit) +const int kJoystickDiscreteThreshold{15000}; +const float kJoystickDiscreteThresholdFloat{0.46f}; +const int kJoystickAnalogCalibrationDivisions{20}; +extern const char* kMFiControllerName; + +/// A physical game controller. +class Joystick : public InputDevice { + public: + // Create from an SDL joystick id. + // Pass -1 to create a manual joystick from a non-sdl-source. + // (in which case you are in charge of feeding it SDL events to make it go) + explicit Joystick(int index, const std::string& custom_device_name = "", + bool can_configure = true, bool calibrate = true); + + ~Joystick() override; + + void HandleSDLEvent(const SDL_Event* e) override; + + void UpdateMapping() override; + void Update() override; + void ResetHeldStates() override; + + auto sdl_joystick_id() const -> int { return sdl_joystick_id_; } + auto sdl_joystick() const -> SDL_Joystick* { return sdl_joystick_; } + + auto GetAllowsConfiguring() -> bool override { return can_configure_; } + + // We treat anything marked as 'ui-only' as a remote too. + // (perhaps should consolidate this with IsUIOnly?.. + // ...except there's some remotes we want to be able to join the game; hmmm) + auto IsRemoteControl() -> bool override { + return (is_remote_control_ || ui_only_); + } + + auto GetPartyButtonName() const -> std::string override; + auto GetDefaultPlayerName() -> std::string override; + + auto GetButtonName(int index) -> std::string override; + auto GetAxisName(int index) -> std::string override; + + auto IsController() -> bool override { return true; } + auto IsSDLController() -> bool override { return (sdl_joystick_ != nullptr); } + + auto ShouldBeHiddenFromUser() -> bool override; + + auto IsUIOnly() -> bool override { return ui_only_; } + + auto IsTestInput() -> bool override { return is_test_input_; } + auto IsRemoteApp() -> bool override { return is_remote_app_; } + auto IsMFiController() -> bool override { return is_mfi_controller_; } + + void set_is_remote_app(bool val) { is_remote_app_ = val; } + void set_is_mfi_controller(bool val) { is_mfi_controller_ = val; } + + void SetStandardExtendedButtons(); + void SetStartButtonActivatesDefaultWidget(bool value) { + start_button_activates_default_widget_ = value; + } + + void set_custom_default_player_name(const std::string& val) { + custom_default_player_name_ = val; + } + auto HasMeaningfulButtonNames() -> bool override; + + protected: + auto GetRawDeviceName() -> std::string override; + auto GetDeviceExtraDescription() -> std::string override; + auto GetDeviceIdentifier() -> std::string override; + void ConnectionComplete() override; + + auto start_button_activates_default_widget() -> bool override { + return start_button_activates_default_widget_; + } + + private: + void UpdateRunningState(); + auto GetCalibratedValue(float raw, float neutral) const -> int32_t; + + std::string custom_default_player_name_; + std::string raw_sdl_joystick_name_; + std::string raw_sdl_joystick_identifier_; + float run_value_{}; + Joystick* child_joy_stick_{}; + Joystick* parent_joy_stick_{}; + millisecs_t last_ui_only_print_time_{}; + bool ui_only_{}; + bool unassigned_buttons_run_{true}; + bool start_button_activates_default_widget_{true}; + bool auto_recalibrate_analog_stick_{}; + millisecs_t creation_time_{}; + bool did_initial_reset_{}; + + // FIXME - should take this out and replace it with a bool + // (we never actually access the sdl joystick directly outside of our + // constructor) + SDL_Joystick* sdl_joystick_{}; + + bool is_test_input_{}; + bool is_remote_control_{}; + bool is_remote_app_{}; + bool is_mfi_controller_{}; + bool is_mac_ps3_controller_{}; + bool is_mac_wiimote_{}; + + millisecs_t ps3_last_joy_press_time_{-10000}; + + // For dialogs. + bool left_held_{}; + bool right_held_{}; + bool up_held_{}; + bool down_held_{}; + bool hold_position_held_{}; + bool need_to_send_held_state_{}; + int hat_{}; + int analog_lr_{}; + int analog_ud_{1}; + millisecs_t last_hold_time_{}; + bool hat_held_{}; + bool dpad_right_held_{}; + bool dpad_left_held_{}; + bool dpad_up_held_{}; + bool dpad_down_held_{}; + + // Mappings of ba buttons to SDL buttons. + int jump_button_{}; + int punch_button_{1}; + int bomb_button_{2}; + int pickup_button_{3}; + int start_button_{5}; + int start_button_2_{-1}; + int hold_position_button_{25}; + int back_button_{-1}; + + // Used on rift build; we have one button which we disallow from joining but + // the rest we allow. (all devices are treated as one and the same there). + int remote_enter_button_{-1}; + bool ignore_completely_{}; + int ignored_button_{-1}; + int ignored_button2_{-1}; + int ignored_button3_{-1}; + int ignored_button4_{-1}; + int run_button1_{-1}; + int run_button2_{-1}; + int run_trigger1_{-1}; + int run_trigger2_{-1}; + int vr_reorient_button_{-1}; + float run_trigger1_min_{}; + float run_trigger1_max_{}; + float run_trigger2_min_{}; + float run_trigger2_max_{}; + float run_trigger1_value_{}; + float run_trigger2_value_{}; + int left_button_{-1}; + int right_button_{-1}; + int up_button_{-1}; + int down_button_{-1}; + int left_button2_{-1}; + int right_button2_{-1}; + int up_button2_{-1}; + int down_button2_{-1}; + std::set run_buttons_held_; + int sdl_joystick_id_{}; + bool ps3_jaxis1_pressed_{}; + bool ps3_jaxis2_pressed_{}; + float calibration_threshold_{}; + float calibration_break_threshold_{}; + float analog_calibration_vals_[kJoystickAnalogCalibrationDivisions]{}; + std::string custom_device_name_; + bool can_configure_{}; + int32_t dialog_jaxis_x_{}; + int32_t dialog_jaxis_y_{}; + int32_t jaxis_raw_x_{}; + int32_t jaxis_raw_y_{}; + int32_t jaxis_x_{}; + int32_t jaxis_y_{}; + millisecs_t calibration_start_time_x_{}; + float calibrated_neutral_x_{}; + millisecs_t calibration_start_time_y_{}; + float calibrated_neutral_y_{}; + bool resetting_{}; + bool calibrate_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_DEVICE_JOYSTICK_H_ diff --git a/src/ballistica/input/device/keyboard_input.cc b/src/ballistica/input/device/keyboard_input.cc new file mode 100644 index 00000000..d3e739f5 --- /dev/null +++ b/src/ballistica/input/device/keyboard_input.cc @@ -0,0 +1,471 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/device/keyboard_input.h" + +#include "ballistica/game/player.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/container_widget.h" + +namespace ballistica { + +KeyboardInput::KeyboardInput(KeyboardInput* parentKeyboardInputIn) { + if (parentKeyboardInputIn) { + parent_keyboard_input_ = parentKeyboardInputIn; + assert(parent_keyboard_input_->child_keyboard_input_ == nullptr); + + // Currently we assume only 2 keyboard inputs. + assert(parent_keyboard_input_->parent_keyboard_input_ == nullptr); + parent_keyboard_input_->child_keyboard_input_ = this; + up_key_ = SDLK_w; + down_key_ = SDLK_s; + left_key_ = SDLK_a; + right_key_ = SDLK_d; + jump_key_ = SDLK_1; + punch_key_ = SDLK_2; + bomb_key_ = SDLK_3; + pick_up_key_ = SDLK_4; + hold_position_key_ = SDLK_6; + start_key_ = SDLK_KP_7; + } else { + up_key_ = SDLK_UP; + down_key_ = SDLK_DOWN; + left_key_ = SDLK_LEFT; + right_key_ = SDLK_RIGHT; + jump_key_ = SDLK_SPACE; + punch_key_ = SDLK_v; + bomb_key_ = SDLK_b; + pick_up_key_ = SDLK_c; + hold_position_key_ = SDLK_y; + start_key_ = SDLK_F5; + } +} + +KeyboardInput::~KeyboardInput() = default; + +auto KeyboardInput::HandleKey(const SDL_Keysym* keysym, bool repeat, bool down) + -> bool { + // Only allow the *main* keyboard to talk to the UI + if (parent_keyboard_input_ == nullptr) { + if (g_ui->GetWidgetForInput(this)) { + bool pass = false; + WidgetMessage::Type c = WidgetMessage::Type::kEmptyMessage; + if (down) { + switch (keysym->sym) { + case SDLK_TAB: + if (keysym->mod & KMOD_SHIFT) { // NOLINT (signed bitwise) + c = WidgetMessage::Type::kTabPrev; + } else { + c = WidgetMessage::Type::kTabNext; + } + pass = true; + break; + case SDLK_LEFT: + c = WidgetMessage::Type::kMoveLeft; + pass = true; + break; + case SDLK_RIGHT: + c = WidgetMessage::Type::kMoveRight; + pass = true; + break; + case SDLK_UP: + c = WidgetMessage::Type::kMoveUp; + pass = true; + break; + case SDLK_DOWN: + c = WidgetMessage::Type::kMoveDown; + pass = true; + break; + case SDLK_SPACE: + case SDLK_KP_ENTER: + case SDLK_RETURN: + if (!repeat) { + c = WidgetMessage::Type::kActivate; + pass = true; + } + break; + case SDLK_ESCAPE: + // (limit to kb1 so we don't get double-beeps on failure) + c = WidgetMessage::Type::kCancel; + pass = true; + break; + default: + + // for remaining keys, lets see if they map to our assigned + // movement/actions. If so, we handle them. + if (keysym->sym == start_key_ || keysym->sym == jump_key_ + || keysym->sym == punch_key_ || keysym->sym == pick_up_key_) { + c = WidgetMessage::Type::kActivate; + pass = true; + } else if (keysym->sym == bomb_key_) { + c = WidgetMessage::Type::kCancel; + pass = true; + } else if (keysym->sym == left_key_) { + c = WidgetMessage::Type::kMoveLeft; + pass = true; + } else if (keysym->sym == right_key_) { + c = WidgetMessage::Type::kMoveRight; + pass = true; + } else if (keysym->sym == up_key_) { + c = WidgetMessage::Type::kMoveUp; + pass = true; + } else if (keysym->sym == down_key_) { + c = WidgetMessage::Type::kMoveDown; + pass = true; + } + + // if we're keyboard 1 we always send at least a key press event + // along.. + if (!parent_keyboard_input_ && !pass) { + c = WidgetMessage::Type::kKey; + pass = true; + } + break; + } + } + if (pass) { + g_ui->SendWidgetMessage(WidgetMessage(c, keysym)); + } + return (pass); + } + } + + // Bring up menu if start is pressed. + if (keysym->sym == start_key_ && !repeat && g_ui && g_ui->screen_root_widget() + && g_ui->screen_root_widget()->GetChildCount() == 0) { + g_game->PushMainMenuPressCall(this); + return true; + } + + // At this point, if we have a child input, let it try to handle things. + if (child_keyboard_input_ && enable_child_) { + if (child_keyboard_input_->HandleKey(keysym, repeat, down)) { + return true; + } + } + + if (!attached_to_player()) { + if (down + && ((keysym->sym == jump_key_) || (keysym->sym == punch_key_) + || (keysym->sym == bomb_key_) + || (keysym->sym == pick_up_key_) + // Main keyboard accepts enter/return as join-request. + || (device_number() == 1 && (keysym->sym == SDLK_KP_ENTER)) + || (device_number() == 1 && (keysym->sym == SDLK_RETURN)))) { + RequestPlayer(); + return true; + } + return false; + } + InputType input_type{}; + bool have_input_2{}; + InputType input_type_2{}; + int16_t input_value{}; + int16_t input_value_2{}; + bool player_input{}; + + // Hack to prevent unused-value lint bug. + // (removing init values from input_type and input_type_2 gives a + // 'possibly uninited value used' warning but leaving them gives a + // 'values unused' warning. Grumble.) + explicit_bool(input_type + == (explicit_bool(false) ? input_type_2 : InputType::kLast)); + + if (!repeat) { + // Keyboard 1 supports assigned keys plus arrow keys if they're unused. + if (keysym->sym == left_key_ + || (device_number() == 1 && keysym->sym == SDLK_LEFT + && !left_key_assigned())) { + player_input = true; + input_type = InputType::kLeftRight; + left_held_ = down; + if (down) { + if (right_held_) { + input_value = 0; + } else { + input_value = -32767; + } + } else { + if (right_held_) { + input_value = 32767; + } + } + } else if (keysym->sym == right_key_ + || (device_number() == 1 && keysym->sym == SDLK_RIGHT + && !right_key_assigned())) { + // Keyboard 1 supports assigned keys plus arrow keys if they're unused. + player_input = true; + input_type = InputType::kLeftRight; + right_held_ = down; + if (down) { + if (left_held_) { + input_value = 0; + } else { + input_value = 32767; + } + } else { + if (left_held_) { + input_value = -32767; + } + } + } else if (keysym->sym == up_key_ + || (device_number() == 1 && keysym->sym == SDLK_UP + && !up_key_assigned())) { + player_input = true; + input_type = InputType::kUpDown; + up_held_ = down; + if (down) { + if (down_held_) { + input_value = 0; + } else { + input_value = 32767; + } + } else { + if (down_held_) input_value = -32767; + } + } else if (keysym->sym == down_key_ + || (device_number() == 1 && keysym->sym == SDLK_DOWN + && !down_key_assigned())) { + player_input = true; + input_type = InputType::kUpDown; + down_held_ = down; + if (down) { + if (up_held_) { + input_value = 0; + } else { + input_value = -32767; + } + } else { + if (up_held_) input_value = 32767; + } + } else if (keysym->sym == punch_key_) { + player_input = true; + UpdateRun(keysym->sym, down); + if (down) { + input_type = InputType::kPunchPress; + } else { + input_type = InputType::kPunchRelease; + } + } else if (keysym->sym == bomb_key_) { + player_input = true; + UpdateRun(keysym->sym, down); + if (down) + input_type = InputType::kBombPress; + else + input_type = InputType::kBombRelease; + } else if (keysym->sym == hold_position_key_) { + player_input = true; + if (down) { + input_type = InputType::kHoldPositionPress; + } else { + input_type = InputType::kHoldPositionRelease; + } + } else if (keysym->sym == pick_up_key_) { + player_input = true; + UpdateRun(keysym->sym, down); + if (down) { + input_type = InputType::kPickUpPress; + } else { + input_type = InputType::kPickUpRelease; + } + } else if ((device_number() == 1 && keysym->sym == SDLK_RETURN) + || (device_number() == 1 && keysym->sym == SDLK_KP_ENTER) + || keysym->sym == jump_key_) { + // Keyboard 1 claims certain keys if they are otherwise unclaimed + // (arrow keys, enter/return, etc). + player_input = true; + UpdateRun(keysym->sym, down); + if (down) { + input_type = InputType::kJumpPress; + have_input_2 = true; + input_type_2 = InputType::kFlyPress; + } else { + input_type = InputType::kJumpRelease; + have_input_2 = true; + input_type_2 = InputType::kFlyRelease; + } + } else { + // Any other keys get processed as run keys. + // keypad keys go to player 2 - anything else to player 1. + switch (keysym->sym) { + case SDLK_KP_0: + case SDLK_KP_1: + case SDLK_KP_2: + case SDLK_KP_3: + case SDLK_KP_4: + case SDLK_KP_5: + case SDLK_KP_6: + case SDLK_KP_7: + case SDLK_KP_8: + case SDLK_KP_9: + case SDLK_KP_PLUS: + case SDLK_KP_MINUS: + case SDLK_KP_ENTER: + if (device_number() == 2) { + UpdateRun(keysym->sym, down); + return true; + } + break; + default: + if (device_number() == 1) { + UpdateRun(keysym->sym, down); + return true; + } + break; + } + } + } + + if (player_input) { + InputCommand(input_type, static_cast(input_value) / 32767.0f); + if (have_input_2) { + InputCommand(input_type_2, static_cast(input_value_2) / 32767.0f); + } + return true; + } else { + return false; + } +} + +void KeyboardInput::ResetHeldStates() { + down_held_ = up_held_ = left_held_ = right_held_ = false; + bool was_held = false; + if (!keys_held_.empty()) { + was_held = true; + } + keys_held_.clear(); + if (was_held) { + InputCommand(InputType::kRun, 0.0f); + } +} + +void KeyboardInput::UpdateRun(SDL_Keycode key, bool down) { + bool was_held = (!keys_held_.empty()); + if (down) { + keys_held_.insert(key); + if (!was_held) { + InputCommand(InputType::kRun, 1.0f); + } + } else { + // Remove this key if we find it. + auto iter = keys_held_.find(key); + if (iter != keys_held_.end()) { + keys_held_.erase(iter); + } + bool is_held = (!keys_held_.empty()); + if (was_held && !is_held) { + InputCommand(InputType::kRun, 0.0f); + } + } +} + +void KeyboardInput::UpdateMapping() { + assert(InGameThread()); + + SDL_Keycode up_key_default, down_key_default, left_key_default, + right_key_default, jump_key_default, punch_key_default, bomb_key_default, + pick_up_key_default, hold_position_key_default, start_key_default; + + if (parent_keyboard_input_) { + up_key_default = SDLK_UP; + down_key_default = SDLK_DOWN; + left_key_default = SDLK_LEFT; + right_key_default = SDLK_RIGHT; + + jump_key_default = SDLK_KP_2; + punch_key_default = SDLK_KP_1; + bomb_key_default = SDLK_KP_6; + pick_up_key_default = SDLK_KP_5; + hold_position_key_default = (SDL_Keycode)-1; + start_key_default = SDLK_KP_7; + + } else { + up_key_default = SDLK_w; + down_key_default = SDLK_s; + left_key_default = SDLK_a; + right_key_default = SDLK_d; + jump_key_default = SDLK_k; + punch_key_default = SDLK_j; + bomb_key_default = SDLK_o; + pick_up_key_default = SDLK_i; + + hold_position_key_default = (SDL_Keycode)-1; + start_key_default = (SDL_Keycode)-1; + } + + // We keep track of whether anyone is using arrow keys + // If not, we allow them to function for movement. + left_key_assigned_ = right_key_assigned_ = up_key_assigned_ = + down_key_assigned_ = false; + + int val; + + val = g_python->GetControllerValue(this, "buttonJump"); + jump_key_ = (val == -1) ? jump_key_default : (SDL_Keycode)val; + UpdateArrowKeys(jump_key_); + + val = g_python->GetControllerValue(this, "buttonPunch"); + punch_key_ = (val == -1) ? punch_key_default : (SDL_Keycode)val; + UpdateArrowKeys(punch_key_); + + val = g_python->GetControllerValue(this, "buttonBomb"); + bomb_key_ = (val == -1) ? bomb_key_default : (SDL_Keycode)val; + UpdateArrowKeys(bomb_key_); + + val = g_python->GetControllerValue(this, "buttonPickUp"); + pick_up_key_ = (val == -1) ? pick_up_key_default : (SDL_Keycode)val; + UpdateArrowKeys(pick_up_key_); + + val = g_python->GetControllerValue(this, "buttonHoldPosition"); + hold_position_key_ = + (val == -1) ? hold_position_key_default : (SDL_Keycode)val; + UpdateArrowKeys(hold_position_key_); + + val = g_python->GetControllerValue(this, "buttonStart"); + start_key_ = (val == -1) ? start_key_default : (SDL_Keycode)val; + UpdateArrowKeys(start_key_); + + val = g_python->GetControllerValue(this, "buttonUp"); + up_key_ = (val == -1) ? up_key_default : (SDL_Keycode)val; + UpdateArrowKeys(up_key_); + + val = g_python->GetControllerValue(this, "buttonDown"); + down_key_ = (val == -1) ? down_key_default : (SDL_Keycode)val; + UpdateArrowKeys(down_key_); + + val = g_python->GetControllerValue(this, "buttonLeft"); + left_key_ = (val == -1) ? left_key_default : (SDL_Keycode)val; + UpdateArrowKeys(left_key_); + + val = g_python->GetControllerValue(this, "buttonRight"); + right_key_ = (val == -1) ? right_key_default : (SDL_Keycode)val; + UpdateArrowKeys(right_key_); + + enable_child_ = true; + + up_held_ = down_held_ = left_held_ = right_held_ = false; +} + +void KeyboardInput::UpdateArrowKeys(SDL_Keycode key) { + if (key == SDLK_UP) { + up_key_assigned_ = true; + } else if (key == SDLK_DOWN) { + down_key_assigned_ = true; + } else if (key == SDLK_LEFT) { + left_key_assigned_ = true; + } else if (key == SDLK_RIGHT) { + right_key_assigned_ = true; + } +} + +auto KeyboardInput::GetButtonName(int index) -> std::string { + return g_platform->GetKeyName(index); + // return InputDevice::GetButtonName(index); +} + +auto KeyboardInput::GetRawDeviceName() -> std::string { return "Keyboard"; } +auto KeyboardInput::GetPartyButtonName() const -> std::string { return "F5"; } +auto KeyboardInput::HasMeaningfulButtonNames() -> bool { return true; } + +} // namespace ballistica diff --git a/src/ballistica/input/device/keyboard_input.h b/src/ballistica/input/device/keyboard_input.h new file mode 100644 index 00000000..23e597c1 --- /dev/null +++ b/src/ballistica/input/device/keyboard_input.h @@ -0,0 +1,60 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_DEVICE_KEYBOARD_INPUT_H_ +#define BALLISTICA_INPUT_DEVICE_KEYBOARD_INPUT_H_ + +#include +#include + +#include "ballistica/input/device/input_device.h" +#include "ballistica/platform/min_sdl.h" + +namespace ballistica { + +class KeyboardInput : public InputDevice { + public: + explicit KeyboardInput(KeyboardInput* parent); + ~KeyboardInput() override; + auto HandleKey(const SDL_Keysym* keysym, bool repeat, bool down) -> bool; + auto UpdateMapping() -> void override; + auto GetRawDeviceName() -> std::string override; + auto ResetHeldStates() -> void override; + auto left_key_assigned() const { return left_key_assigned_; } + auto right_key_assigned() const { return right_key_assigned_; } + auto up_key_assigned() const { return up_key_assigned_; } + auto down_key_assigned() const { return down_key_assigned_; } + auto GetPartyButtonName() const -> std::string override; + auto IsKeyboard() -> bool override { return true; } + auto HasMeaningfulButtonNames() -> bool override; + auto GetButtonName(int index) -> std::string override; + + private: + auto UpdateArrowKeys(SDL_Keycode key) -> void; + auto UpdateRun(SDL_Keycode key, bool down) -> void; + SDL_Keycode up_key_{}; + SDL_Keycode down_key_{}; + SDL_Keycode left_key_{}; + SDL_Keycode right_key_{}; + SDL_Keycode jump_key_{}; + SDL_Keycode punch_key_{}; + SDL_Keycode bomb_key_{}; + SDL_Keycode pick_up_key_{}; + SDL_Keycode hold_position_key_{}; + SDL_Keycode start_key_{}; + bool down_held_{}; + bool up_held_{}; + bool left_held_{}; + bool right_held_{}; + bool enable_child_{}; + bool left_key_assigned_{}; + bool right_key_assigned_{}; + bool up_key_assigned_{}; + bool down_key_assigned_{}; + KeyboardInput* parent_keyboard_input_{}; + KeyboardInput* child_keyboard_input_{}; + std::set keys_held_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_DEVICE_KEYBOARD_INPUT_H_ diff --git a/src/ballistica/input/device/test_input.cc b/src/ballistica/input/device/test_input.cc new file mode 100644 index 00000000..be821d5c --- /dev/null +++ b/src/ballistica/input/device/test_input.cc @@ -0,0 +1,148 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/device/test_input.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/input/device/joystick.h" +#include "ballistica/input/input.h" +#include "ballistica/platform/min_sdl.h" + +namespace ballistica { + +TestInput::TestInput() { + joystick_ = Object::NewDeferred(-1, // not an sdl joystick + "TestInput", // device name + false, // allow configuring? + false); // calibrate?; + g_input->PushAddInputDeviceCall(joystick_, true); +} + +TestInput::~TestInput() { g_input->PushRemoveInputDeviceCall(joystick_, true); } + +void TestInput::Reset() { + assert(InMainThread()); + reset_ = true; +} + +void TestInput::HandleAlreadyPressedTwice() { + if (print_already_did2_) { + print_already_did2_ = false; + } +} + +void TestInput::Process(millisecs_t time) { + assert(InMainThread()); + + if (reset_) { + reset_ = false; + join_end_time_ = time + 7000; // do joining for the next few seconds + join_start_time_ = time + 1000; + join_press_count_ = 0; + print_non_join_ = true; + print_already_did2_ = true; + } + + if (print_non_join_ && time >= join_end_time_) { + print_non_join_ = false; + } + + if (time > next_event_time_) { + next_event_time_ = time + static_cast(RandomFloat() * 300.0f); + + // Do absolutely nothing before join start time. + if (time < join_start_time_) { + return; + } + + float r = RandomFloat(); + + SDL_Event e; + if (r < 0.5f) { + // Movement change. + r = RandomFloat(); + if (r < 0.3f) { + lr_ = ud_ = 0; + } else { + lr_ = std::max( + -32767, + std::min(32767, + static_cast(-50000.0f + 100000.0f * RandomFloat()))); + ud_ = std::max( + -32767, + std::min(32767, + static_cast(-50000.0f + 100000.0f * RandomFloat()))); + } + e.type = SDL_JOYAXISMOTION; + e.jaxis.axis = 0; + e.jaxis.value = static_cast_check_fit(ud_); + g_input->PushJoystickEvent(e, joystick_); + e.jaxis.axis = 1; + e.jaxis.value = static_cast_check_fit(lr_); + g_input->PushJoystickEvent(e, joystick_); + } else { + // Button change. + r = RandomFloat(); + if (r > 0.75f) { + // Jump: + // Don't do more than 2 presses while joining. + if (!jump_pressed_ && time < join_end_time_ && join_press_count_ > 1) { + HandleAlreadyPressedTwice(); + } else { + jump_pressed_ = !jump_pressed_; + if (jump_pressed_) join_press_count_++; + e.type = jump_pressed_ ? SDL_JOYBUTTONDOWN : SDL_JOYBUTTONUP; + e.jbutton.button = 0; + g_input->PushJoystickEvent(e, joystick_); + } + } else if (r > 0.5f) { + // Bomb: + // Don't do more than 2 presses while joining. + if (!bomb_pressed_ && time < join_end_time_ && join_press_count_ > 1) { + HandleAlreadyPressedTwice(); + } else { + bomb_pressed_ = !bomb_pressed_; + + // This counts as a join press *only* if its the first. + // (presses after that simply change our character) + if (join_press_count_ == 0 && bomb_pressed_) { + // cout << "GOT BOMB AS FIRST PRESS " << this << endl; + join_press_count_++; + } + e.type = bomb_pressed_ ? SDL_JOYBUTTONDOWN : SDL_JOYBUTTONUP; + e.jbutton.button = 2; + g_input->PushJoystickEvent(e, joystick_); + } + + } else if (r > 0.25f) { + // Grab: + // Don't do more than 2 presses while joining. + if (!pickup_pressed_ && time < join_end_time_ + && join_press_count_ > 1) { + HandleAlreadyPressedTwice(); + } else { + pickup_pressed_ = !pickup_pressed_; + if (pickup_pressed_) join_press_count_++; + e.type = pickup_pressed_ ? SDL_JOYBUTTONDOWN : SDL_JOYBUTTONUP; + e.jbutton.button = 3; + g_input->PushJoystickEvent(e, joystick_); + } + } else { + // Punch: + // Don't do more than 2 presses while joining. + if (!punch_pressed_ && time < join_end_time_ && join_press_count_ > 1) { + HandleAlreadyPressedTwice(); + } else { + punch_pressed_ = !punch_pressed_; + if (punch_pressed_) join_press_count_++; + e.type = punch_pressed_ ? SDL_JOYBUTTONDOWN : SDL_JOYBUTTONUP; + e.jbutton.button = 1; + g_input->PushJoystickEvent(e, joystick_); + } + } + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/input/device/test_input.h b/src/ballistica/input/device/test_input.h new file mode 100644 index 00000000..5f349144 --- /dev/null +++ b/src/ballistica/input/device/test_input.h @@ -0,0 +1,37 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_DEVICE_TEST_INPUT_H_ +#define BALLISTICA_INPUT_DEVICE_TEST_INPUT_H_ + +#include "ballistica/ballistica.h" + +namespace ballistica { + +class TestInput { + public: + TestInput(); + virtual ~TestInput(); + void Process(millisecs_t time); + void Reset(); + + private: + void HandleAlreadyPressedTwice(); + int lr_{}; + int ud_{}; + bool jump_pressed_{}; + bool bomb_pressed_{}; + bool pickup_pressed_{}; + bool punch_pressed_{}; + millisecs_t next_event_time_{}; + millisecs_t join_start_time_{}; + millisecs_t join_end_time_{9999}; + int join_press_count_{}; + bool reset_{true}; + Joystick* joystick_{}; + bool print_non_join_{}; + bool print_already_did2_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_DEVICE_TEST_INPUT_H_ diff --git a/src/ballistica/input/device/touch_input.cc b/src/ballistica/input/device/touch_input.cc new file mode 100644 index 00000000..98cff073 --- /dev/null +++ b/src/ballistica/input/device/touch_input.cc @@ -0,0 +1,1077 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/device/touch_input.h" + +#include +#include + +#include "ballistica/app/app_config.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/player.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_command.h" +#include "ballistica/scene/node/player_node.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +const float kButtonSpread = 10.0f; +const float kDrawDepth = -0.07f; + +// Given coords within a (-1,-1) to (1,1) box, +// convert them such that their length is never greater than 1. +static void CircleToBoxCoords(float* lr, float* ud) { + if (std::abs((*lr)) < 0.0001f || std::abs((*ud)) < 0.0001f) { + return; // Not worth doing anything. + } + + // Project them out to hit the border. + float s; + if (std::abs((*lr)) > std::abs((*ud))) { + s = 1.0f / std::abs((*lr)); + } else { + s = 1.0f / std::abs((*ud)); + } + float proj_lr = (*lr) * s; + float proj_ud = (*ud) * s; + float proj_len = sqrtf(proj_lr * proj_lr + proj_ud * proj_ud); + (*lr) *= proj_len; + (*ud) *= proj_len; +} + +void TouchInput::HandleTouchEvent(TouchEvent::Type type, void* touch, float x, + float y) { + // Currently we completely ignore these when in editing mode; + // In that case we get fed in SDL mouse events + // (so we can properly mask interaction with widgets, etc). + if (editing()) { + return; + } + + switch (type) { + case TouchEvent::Type::kDown: { + HandleTouchDown(touch, x, y); + break; + } + case TouchEvent::Type::kCanceled: + case TouchEvent::Type::kUp: { + HandleTouchUp(touch, x, y); + break; + } + case TouchEvent::Type::kMoved: { + HandleTouchMoved(touch, x, y); + break; + } + default: + throw Exception(); + } +} + +TouchInput::TouchInput() { + switch (GetInterfaceType()) { + case UIScale::kSmall: + base_controls_scale_ = 2.0f; + world_draw_scale_ = 1.2f; + break; + case UIScale::kMedium: + base_controls_scale_ = 1.5f; + world_draw_scale_ = 1.1f; + break; + default: + base_controls_scale_ = 1.0f; + world_draw_scale_ = 1.0f; + break; + } + + assert(g_app_globals->touch_input == nullptr); + g_app_globals->touch_input = this; +} + +TouchInput::~TouchInput() = default; + +void TouchInput::UpdateButtons(bool new_touch) { + millisecs_t real_time = GetRealTime(); + float spread_scaled_actions = + kButtonSpread * base_controls_scale_ * controls_scale_actions_; + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + float edge_buffer = spread_scaled_actions; + + if (new_touch && action_control_type_ == ActionControlType::kSwipe) { + buttons_x_ = buttons_touch_x_; + buttons_y_ = buttons_touch_y_; + } + + // See which button we're closest to. + float bomb_mag = buttons_touch_x_ - buttons_x_; + float punch_mag = buttons_x_ - buttons_touch_x_; + float jump_mag = buttons_y_ - buttons_touch_y_; + float pickup_mag = buttons_touch_y_ - buttons_y_; + float max_mag = + std::max(std::max(std::max(bomb_mag, punch_mag), jump_mag), pickup_mag); + bool closest_to_bomb = false; + bool closest_to_punch = false; + bool closest_to_jump = false; + bool closest_to_pickup = false; + if (bomb_mag == max_mag) { + closest_to_bomb = true; + } else if (punch_mag == max_mag) { + closest_to_punch = true; + } else if (jump_mag == max_mag) { + closest_to_jump = true; + } else if (pickup_mag == max_mag) { + closest_to_pickup = true; + } else { + throw Exception(); + } + if (buttons_touch_) { + last_buttons_touch_time_ = GetRealTime(); + } + + // Handle swipe mode. + if (action_control_type_ == ActionControlType::kSwipe) { + // If we're dragging on one axis, center the other axis. + if (closest_to_bomb + // NOLINTNEXTLINE(bugprone-branch-clone) + && buttons_touch_x_ >= buttons_x_ + spread_scaled_actions) { + buttons_y_ = buttons_touch_y_; + } else if (closest_to_punch + && buttons_touch_x_ <= buttons_x_ - spread_scaled_actions) { + buttons_y_ = buttons_touch_y_; + } else if (closest_to_pickup + // NOLINTNEXTLINE(bugprone-branch-clone) + && buttons_touch_y_ >= buttons_y_ + spread_scaled_actions) { + buttons_x_ = buttons_touch_x_; + } else if (closest_to_jump + && buttons_touch_y_ <= buttons_y_ - spread_scaled_actions) { + buttons_x_ = buttons_touch_x_; + } + + // Drag along the axis we're dragging. + float spread_scaled_actions_extra = 1.01f * spread_scaled_actions; + if (closest_to_bomb + && buttons_touch_x_ >= buttons_x_ + spread_scaled_actions_extra) { + buttons_x_ = buttons_touch_x_ - spread_scaled_actions_extra; + } else if (closest_to_punch + && buttons_touch_x_ + <= buttons_x_ - spread_scaled_actions_extra) { + buttons_x_ = buttons_touch_x_ + spread_scaled_actions_extra; + } else if (closest_to_pickup + && buttons_touch_y_ + >= buttons_y_ + spread_scaled_actions_extra) { + buttons_y_ = buttons_touch_y_ - spread_scaled_actions_extra; + } else if (closest_to_jump + && buttons_touch_y_ + <= buttons_y_ - spread_scaled_actions_extra) { + buttons_y_ = buttons_touch_y_ + spread_scaled_actions_extra; + } + + // Keep them away from screen edges. + if (buttons_x_ > width - edge_buffer) { + buttons_x_ = width - edge_buffer; + } + if (buttons_y_ > height - edge_buffer) { + buttons_y_ = height - edge_buffer; + } else if (buttons_y_ < edge_buffer) { + buttons_y_ = edge_buffer; + } + + // Handle new presses. + if (buttons_touch_) { + if (!bomb_held_ + && buttons_touch_x_ >= buttons_x_ + spread_scaled_actions) { + bomb_held_ = true; + last_bomb_press_time_ = real_time; + InputCommand(InputType::kBombPress); + } + if (!punch_held_ + && buttons_touch_x_ <= buttons_x_ - spread_scaled_actions) { + punch_held_ = true; + last_punch_press_time_ = real_time; + InputCommand(InputType::kPunchPress); + } + if (!jump_held_ + && buttons_touch_y_ <= buttons_y_ - spread_scaled_actions) { + jump_held_ = true; + last_jump_press_time_ = real_time; + InputCommand(InputType::kJumpPress); + } + if (!pickup_held_ + && buttons_touch_y_ >= buttons_y_ + spread_scaled_actions) { + pickup_held_ = true; + last_pickup_press_time_ = real_time; + InputCommand(InputType::kPickUpPress); + } + } + + // Handle releases. + if (bomb_held_ + && (!buttons_touch_ + || buttons_touch_x_ < buttons_x_ + spread_scaled_actions)) { + bomb_held_ = false; + last_bomb_held_time_ = real_time; + InputCommand(InputType::kBombRelease); + } + if (punch_held_ + && (!buttons_touch_ + || buttons_touch_x_ > buttons_x_ - spread_scaled_actions)) { + punch_held_ = false; + last_punch_held_time_ = real_time; + InputCommand(InputType::kPunchRelease); + } + if (jump_held_ + && (!buttons_touch_ + || buttons_touch_y_ > buttons_y_ - spread_scaled_actions)) { + jump_held_ = false; + last_jump_held_time_ = real_time; + InputCommand(InputType::kJumpRelease); + } + if (pickup_held_ + && (!buttons_touch_ + || buttons_touch_y_ < buttons_y_ + spread_scaled_actions)) { + pickup_held_ = false; + last_pickup_held_time_ = real_time; + InputCommand(InputType::kPickUpRelease); + } + } else { + bool was_bomb_held = bomb_held_; + bool was_jump_held = jump_held_; + bool was_pickup_held = pickup_held_; + bool was_punch_held = punch_held_; + bomb_held_ = jump_held_ = pickup_held_ = punch_held_ = false; + if (buttons_touch_) { + if (closest_to_bomb) { + bomb_held_ = true; + if (!was_bomb_held) { + last_bomb_press_time_ = real_time; + InputCommand(InputType::kBombPress); + } + } else if (closest_to_punch) { + punch_held_ = true; + if (!was_punch_held) { + last_punch_press_time_ = real_time; + InputCommand(InputType::kPunchPress); + } + } else if (closest_to_jump) { + jump_held_ = true; + if (!was_jump_held) { + last_jump_press_time_ = real_time; + // fixme should just send one or the other.. + InputCommand(InputType::kJumpPress); + InputCommand(InputType::kFlyPress); + } + } else if (closest_to_pickup) { + pickup_held_ = true; + if (!was_pickup_held) { + last_pickup_press_time_ = real_time; + InputCommand(InputType::kPickUpPress); + } + } + } + + // Handle releases. + if (was_bomb_held && !bomb_held_) { + last_bomb_held_time_ = real_time; + InputCommand(InputType::kBombRelease); + } + if (was_punch_held && !punch_held_) { + punch_held_ = false; + last_punch_held_time_ = real_time; + InputCommand(InputType::kPunchRelease); + } + if (was_jump_held && !jump_held_) { + jump_held_ = false; + last_jump_held_time_ = real_time; + // fixme should just send one or the other.. + InputCommand(InputType::kJumpRelease); + InputCommand(InputType::kFlyRelease); + } + if (was_pickup_held && !pickup_held_) { + pickup_held_ = false; + last_pickup_held_time_ = real_time; + InputCommand(InputType::kPickUpRelease); + } + } +} + +void TouchInput::UpdateDPad() { + // Keep our base somewhat close to our drag point. + float max_dist = 30.0f * base_controls_scale_ * controls_scale_move_; + + // Keep it within a circle of max_dist radius. + float x = (d_pad_x_ - d_pad_base_x_) / max_dist; + float y = (d_pad_y_ - d_pad_base_y_) / max_dist; + float len = sqrtf(x * x + y * y); + + // In swipe mode we move our base around to follow the touch. + if (movement_control_type_ == MovementControlType::kSwipe) { + // If this is the first move event, scoot our base towards our current point + // by a small amount. This is meant to counter the fact that the first + // touch-moved event is always significantly far from the touch-down and + // allows us to start out moving slowly. + if (!did_first_move_ && (x != 0 || y != 0)) { + if (len != 0.0f) { + float offs = 0.8f * std::min(len, 0.8f); + d_pad_base_x_ += x * max_dist * (offs / len); + d_pad_base_y_ += y * max_dist * (offs / len); + x = (d_pad_x_ - d_pad_base_x_) / max_dist; + y = (d_pad_y_ - d_pad_base_y_) / max_dist; + len = sqrtf(x * x + y * y); + } + did_first_move_ = true; + } + + if (len > 1.0f) { + float inv_len = 1.0f / len; + x *= inv_len; + y *= inv_len; + d_pad_base_x_ = d_pad_x_ - x * max_dist; + d_pad_base_y_ = d_pad_y_ - y * max_dist; + } + } else { + // Likewise in joystick mode we keep our touch near the base. + if (len > 1.0f) { + float inv_len = 1.0f / len; + x *= inv_len; + y *= inv_len; + d_pad_x_ = d_pad_base_x_ + x * max_dist; + d_pad_y_ = d_pad_base_y_ + y * max_dist; + } + } + + d_pad_draw_x_ = x; + d_pad_draw_y_ = y; + + // Although its a circle we need to deliver box coords.. (ie: upper-left is + // -1,1). + CircleToBoxCoords(&x, &y); + + float remap = 1.0f; + InputCommand(InputType::kLeftRight, x * remap); + InputCommand(InputType::kUpDown, y * remap); +} + +void TouchInput::Draw(FrameDef* frame_def) { + assert(InGameThread()); + bool active = (!g_ui->IsWindowPresent()); + millisecs_t real_time = frame_def->real_time(); + + // Update our action center whenever possible in case screen is resized. + if (!buttons_touch_) { + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + buttons_x_ = width * buttons_default_frac_x_; + buttons_y_ = height * buttons_default_frac_y_; + } + // Same for dpad. + if (!d_pad_touch_) { + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + d_pad_x_ = d_pad_base_x_ = width * d_pad_default_frac_x_; + d_pad_y_ = d_pad_base_y_ = height * d_pad_default_frac_y_; + } + + // Update time-dependent stuff to this point. + if ((real_time - update_time_ > 500) && (real_time - update_time_ < 99999)) { + update_time_ = real_time - 500; + } + while (update_time_ < real_time) { + update_time_ += 10; + + // Update presence based on whether or not we're active. + if ((attached_to_player() && active) || editing_) { + presence_ = std::min(1.0f, presence_ + 0.06f); + } else { + presence_ = std::max(0.0f, presence_ - 0.06f); + } + + if (action_control_type_ == ActionControlType::kSwipe) { + // Overall backing opacity fades in and out based on whether we have a + // button touch. + if (buttons_touch_ || editing_) { + button_fade_ = std::min(1.0f, button_fade_ + 0.06f); + } else { + button_fade_ = std::max(0.0f, button_fade_ - 0.015f); + } + + // If there's a button touch but its not on a button, slowly move the + // center towards it (keeps us from slowly sliding onto a button press + // while trying to run and stuff). + if (buttons_touch_ && !bomb_held_ && !punch_held_ && !pickup_held_ + && !jump_held_) { + buttons_x_ += 0.015f * (buttons_touch_x_ - buttons_x_); + buttons_y_ += 0.015f * (buttons_touch_y_ - buttons_y_); + } + } else { + button_fade_ = 1.0f; + } + } + + if (presence_ > 0.0f) { + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + SimpleComponent c(frame_def->GetOverlayFlatPass()); + c.SetTransparent(true); + + float sc_move = base_controls_scale_ * controls_scale_move_ + * (200.0f - presence_ * 100.0f); + float sc_actions = base_controls_scale_ * controls_scale_actions_ + * (200.0f - presence_ * 100.0f); + + bool do_draw; + if (movement_control_type_ == MovementControlType::kSwipe) { + do_draw = (!d_pad_touch_ && !swipe_controls_hidden_); + } else { + do_draw = true; // always draw in joystick mode + } + + if (do_draw) { + float sc2 = sc_move; + if (movement_control_type_ == MovementControlType::kSwipe) sc2 *= 0.6f; + + if (movement_control_type_ == MovementControlType::kSwipe) { + c.SetTexture(g_media->GetTexture(SystemTextureID::kTouchArrows)); + if (editing_) { + float val = 1.5f + sinf(real_time * 0.02f); + c.SetColor(val, val, 1.0f, 1.0f); + } + } else { + float val; + if (editing_) { + val = 0.35f + 0.15f * sinf(real_time * 0.02f); + } else { + val = 0.35f; + } + c.SetColor(0.5f, 0.3f, 0.8f, val); + c.SetTexture(g_media->GetTexture(SystemTextureID::kCircle)); + } + + float x_offs = + width * (-0.1f - d_pad_default_frac_x_) * (1.0f - presence_); + float y_offs = + height * (-0.1f - d_pad_default_frac_y_) * (1.0f - presence_); + + c.PushTransform(); + c.Translate(d_pad_base_x_ + x_offs, d_pad_base_y_ + y_offs, kDrawDepth); + c.Scale(sc2, sc2); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + + if (movement_control_type_ == MovementControlType::kJoystick) { + float val; + if (editing_) { + val = 0.35f + 0.15f * sinf(real_time * 0.02f); + } else { + val = 0.35f; + } + c.SetColor(0.0f, 0.0f, 0.0f, val); + c.PushTransform(); + c.Translate(d_pad_x_ + x_offs, d_pad_y_ + y_offs, kDrawDepth); + c.Scale(sc_move * 0.5f, sc_move * 0.5f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + } + } + + if (!buttons_touch_ && action_control_type_ == ActionControlType::kSwipe + && !swipe_controls_hidden_) { + float sc2 = sc_actions; + if (action_control_type_ == ActionControlType::kSwipe) sc2 *= 0.6f; + c.SetTexture(g_media->GetTexture(SystemTextureID::kTouchArrowsActions)); + if (editing_) { + float val = 1.5f + sinf(real_time * 0.02f); + c.SetColor(val, val, 1.0f, 1.0f); + } else { + c.SetColor(1.0f, 1.0f, 1.0f, 1.0f); + } + c.PushTransform(); + float x_offs = + width * (1.1f - buttons_default_frac_x_) * (1.0f - presence_); + float y_offs = + height * (-0.1f - buttons_default_frac_y_) * (1.0f - presence_); + c.Translate(buttons_x_ + x_offs, buttons_y_ + y_offs, kDrawDepth); + c.Scale(sc2, sc2); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + } + c.Submit(); + } + + bool have_player_position = false; + std::vector player_position(3); + if (attached_to_player()) { + PlayerNode* player_node = nullptr; + + // Try to come up with whichever scene is in the foreground, and try + // to pull a node for the player we're attached to. + + if (HostActivity* host_activity = + g_game->GetForegroundContext().GetHostActivity()) { + if (Player* player = GetPlayer()) { + player_node = host_activity->scene()->GetPlayerNode(player->id()); + } + } else { + if (Scene* scene = g_game->GetForegroundScene()) { + player_node = scene->GetPlayerNode(remote_player_id()); + } + } + if (player_node) { + have_player_position = true; + player_position = player_node->position(); + } + } + + SimpleComponent c(frame_def->GetOverlayFlatPass()); + c.SetTransparent(true); + + uint32_t residual_time = 130; + + // Draw buttons. + bool do_draw; + if (action_control_type_ == ActionControlType::kButtons) { + do_draw = (presence_ > 0.0f); + } else { + do_draw = (active); + } + + if (do_draw) { + float base_fade; + + if (action_control_type_ == ActionControlType::kSwipe) { + base_fade = 0.25f; + } else { + base_fade = 0.8f; + c.SetTexture(g_media->GetTexture(SystemTextureID::kActionButtons)); + } + + float x_offs; + float y_offs; + if (action_control_type_ == ActionControlType::kSwipe) { + x_offs = -buttons_x_; + y_offs = -buttons_y_ - 75; + } else { + x_offs = y_offs = 0.0f; + + // Do transition in button mode. + if (presence_ < 1.0f) { + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + x_offs = width * (1.1f - buttons_default_frac_x_) * (1.0f - presence_); + y_offs = + height * (-0.1f - buttons_default_frac_y_) * (1.0f - presence_); + } + } + + float s = 0.5f; + + // In buttons mode we draw based on our UI size. Otherwise we draw in the + // world at a constant scale. + if (action_control_type_ == ActionControlType::kButtons) { + s *= 3.0f * base_controls_scale_ * controls_scale_actions_; + } else { + // When not drawing under the character we obey ui size. + if (!have_player_position) { + s *= 0.5f * 1.5f * base_controls_scale_ * controls_scale_actions_; + } else { + s *= world_draw_scale_; + } + } + + float b_width = 50.0f * s; + float half_b_width = 0.0f; + + float button_spread_s = 0.0f * s; + + if (action_control_type_ == ActionControlType::kSwipe) { + button_spread_s *= 2.0f; + } + + bool was_held; + float pop; + float pop_time = 100.0f; + + c.PushTransform(); + + // In swipe mode we draw under our character when possible, and above the + // touch otherwise. + if (action_control_type_ == ActionControlType::kSwipe) { + if (have_player_position) { + c.TranslateToProjectedPoint(player_position[0], player_position[1], + player_position[2]); + } else { + float s2 = base_controls_scale_ * controls_scale_actions_; + c.Translate(buttons_touch_start_x_ - s2 * 50.0f, + buttons_touch_start_y_ + 75.0f + s2 * 50.0f, 0.0f); + } + } + + float squash = 1.3f; + float stretch = 1.3f; + + float s_extra = 1.0f; + if (editing_) s_extra = 0.7f + 0.3f * sinf(real_time * 0.02f); + + // Bomb. + was_held = + bomb_held_ || (real_time - last_bomb_press_time_ < residual_time); + if ((button_fade_ > 0.0f) || bomb_held_ || was_held) { + pop = std::max(0.0f, + 1.0f + - static_cast(real_time - last_bomb_press_time_) + / pop_time); + if (was_held) { + c.SetColor(1.5f, 2.0f * pop, 2.0f * pop, 1.0f); + } else { + c.SetColor(0.65f * s_extra, 0.0f, 0.0f, base_fade * button_fade_); + } + + c.PushTransform(); + c.Translate(buttons_x_ + button_spread_s + half_b_width + x_offs, + buttons_y_ + y_offs, kDrawDepth); + if (bomb_held_) { + c.Scale(stretch * b_width, squash * b_width); + } else { + c.Scale(b_width, b_width); + } + c.DrawModel(g_media->GetModel(SystemModelID::kActionButtonRight)); + c.PopTransform(); + } + + // Punch. + was_held = + punch_held_ || (real_time - last_punch_press_time_ < residual_time); + if ((button_fade_ > 0.0f) || punch_held_ || was_held) { + pop = std::max( + 0.0f, 1.0f + - static_cast(real_time - last_punch_press_time_) + / pop_time); + if (was_held) { + c.SetColor(1.3f + 2.0f * pop, 1.3f + 2.0f * pop, 0.0f + 2.0f * pop, + 1.0f); + } else { + c.SetColor(0.9f * s_extra, 0.9f * s_extra, 0.2f * s_extra, + base_fade * button_fade_); + } + c.PushTransform(); + c.Translate(buttons_x_ - button_spread_s - half_b_width + x_offs, + buttons_y_ + y_offs, kDrawDepth); + if (punch_held_) { + c.Scale(stretch * b_width, squash * b_width); + } else { + c.Scale(b_width, b_width); + } + c.DrawModel(g_media->GetModel(SystemModelID::kActionButtonLeft)); + c.PopTransform(); + } + + // Jump. + was_held = + jump_held_ || (real_time - last_jump_press_time_ < residual_time); + if ((button_fade_ > 0.0f) || jump_held_ || was_held) { + pop = std::max(0.0f, + 1.0f + - static_cast(real_time - last_jump_press_time_) + / pop_time); + if (was_held) { + c.SetColor(1.8f * pop, 1.2f + 0.9f * pop, 2.0f * pop, 1.0f); + } else { + c.SetColor(0.0f, 0.8f * s_extra, 0.0f, base_fade * button_fade_); + } + c.PushTransform(); + c.Translate(buttons_x_ + x_offs, + buttons_y_ - button_spread_s - half_b_width + y_offs, + kDrawDepth); + if (jump_held_) { + c.Scale(squash * b_width, stretch * b_width); + } else { + c.Scale(b_width, b_width); + } + c.DrawModel(g_media->GetModel(SystemModelID::kActionButtonBottom)); + c.PopTransform(); + } + + // Pickup. + was_held = + pickup_held_ || (real_time - last_pickup_press_time_ < residual_time); + if ((button_fade_ > 0.0f) || pickup_held_ || was_held) { + pop = std::max( + 0.0f, 1.0f + - static_cast(real_time - last_pickup_press_time_) + / pop_time); + if (was_held) { + c.SetColor(0.5f + 1.4f * pop, 0.8f + 2.4f * pop, 2.0f + 0.4f * pop, + 1.0f); + } else { + c.SetColor(0.3f * s_extra, 0.65f * s_extra, 1.0f * s_extra, + base_fade * button_fade_); + } + c.PushTransform(); + c.Translate(buttons_x_ + x_offs, + buttons_y_ + button_spread_s + half_b_width + y_offs, + kDrawDepth); + if (pickup_held_) { + c.Scale(squash * b_width, stretch * b_width); + } else { + c.Scale(b_width, b_width); + } + c.DrawModel(g_media->GetModel(SystemModelID::kActionButtonTop)); + c.PopTransform(); + } + + // Center point. + if (buttons_touch_ && action_control_type_ == ActionControlType::kSwipe) { + c.SetTexture(g_media->GetTexture(SystemTextureID::kCircle)); + c.SetColor(1.0f, 1.0f, 0.0f, 0.8f); + c.PushTransform(); + + // We need to scale this up/down relative to the scale we're drawing at + // since we're not drawing in screen space. + float diff_x = buttons_touch_x_ - buttons_x_; + float diff_y = buttons_touch_y_ - buttons_y_; + + if (have_player_position) { + c.Translate(buttons_x_ + + 2.3f * world_draw_scale_ * diff_x + / (base_controls_scale_ * controls_scale_actions_) + + x_offs, + buttons_y_ + + 2.3f * world_draw_scale_ * diff_y + / (base_controls_scale_ * controls_scale_actions_) + + y_offs, + kDrawDepth); + } else { + c.Translate(buttons_x_ + 0.5f * 1.55f * 2.3f * diff_x + x_offs, + buttons_y_ + 0.5f * 1.55f * 2.3f * diff_y + y_offs, + kDrawDepth); + } + c.Scale(b_width * 0.3f, b_width * 0.3f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + } + c.PopTransform(); + } + c.Submit(); + + bool draw_in_world = have_player_position; + + // Always draw when we've got a world-pos. if not, only draw on screen in + // swipe mode. + if (d_pad_touch_ + && (draw_in_world + || movement_control_type_ == MovementControlType::kSwipe)) { + // Circle. + SimpleComponent c2(draw_in_world ? frame_def->overlay_3d_pass() + : frame_def->GetOverlayFlatPass()); + c2.SetTransparent(true); + if (buttons_touch_) { + c2.SetColor(1.0f, 0.3f, 0.2f, 0.45f); + } else { + c2.SetColor(1.0f, 1.0f, 0.0f, 0.45f); + } + + bool zero_len; + if (std::abs(d_pad_draw_x_) > 0.00001f + || std::abs(d_pad_draw_y_) > 0.00001f) { + d_pad_draw_dir_ = Vector3f(d_pad_draw_x_, 0.0f, -d_pad_draw_y_); + zero_len = false; + } else { + zero_len = true; + } + + // Line. + float dist = sqrtf(d_pad_draw_dir_.x * d_pad_draw_dir_.x + + d_pad_draw_dir_.z * d_pad_draw_dir_.z); + if (zero_len) { + dist = 0.05f; + } + + c2.SetTexture(g_media->GetTexture(SystemTextureID::kArrow)); + Matrix44f orient = + Matrix44fOrient(d_pad_draw_dir_, Vector3f(0.0f, 1.0f, 0.0f)); + c2.PushTransform(); + + // Drawing in the 3d world. + if (draw_in_world) { + c2.Translate(player_position[0], player_position[1] - 0.5f, + player_position[2]); + + // In happy thoughts mode show the arrow on the xy plane instead of xz. + if (g_graphics->camera()->happy_thoughts_mode()) { + c2.Translate(0.0f, 0.5f, 0.0f); + c2.Rotate(90.0f, 1.0f, 0.0f, 0.0f); + } + } else { + // Drawing on 2d overlay. + float s = base_controls_scale_ * controls_scale_move_; + c2.Translate(d_pad_start_x_ + s * 50.0f, d_pad_start_y_ + s * 50.0f, + 0.0f); + c2.ScaleUniform(s * 50.0f); + c2.Rotate(90.0f, 1.0f, 0.0f, 0.0f); + } + + c2.MultMatrix(orient.m); + c2.Rotate(-90.0f, 1.0f, 0.0f, 0.0f); + + c2.ScaleUniform(0.8f); + + c2.PushTransform(); + c2.Translate(0.0f, dist * -0.5f, 0.0f); + c2.Scale(0.15f, dist, 0.2f); + c2.DrawModel(g_media->GetModel(SystemModelID::kArrowBack)); + c2.PopTransform(); + + c2.PushTransform(); + c2.Translate(0.0f, dist * -1.0f - 0.15f, 0.0f); + c2.Scale(0.45f, 0.3f, 0.3f); + c2.DrawModel(g_media->GetModel(SystemModelID::kArrowFront)); + c2.PopTransform(); + + c2.PopTransform(); + c2.Submit(); + } +} + +void TouchInput::UpdateMapping() { + assert(InGameThread()); + + std::string touch_movement_type = + g_app_config->Resolve(AppConfig::StringID::kTouchMovementControlType); + if (touch_movement_type == "swipe") { + movement_control_type_ = TouchInput::MovementControlType::kSwipe; + } else if (touch_movement_type == "joystick") { + movement_control_type_ = TouchInput::MovementControlType::kJoystick; + } else { + Log("Error: Invalid touch-movement-type: " + touch_movement_type); + movement_control_type_ = TouchInput::MovementControlType::kSwipe; + } + std::string touch_action_type = + g_app_config->Resolve(AppConfig::StringID::kTouchActionControlType); + if (touch_action_type == "swipe") { + action_control_type_ = TouchInput::ActionControlType::kSwipe; + } else if (touch_action_type == "buttons") { + action_control_type_ = TouchInput::ActionControlType::kButtons; + } else { + Log("Error: Invalid touch-action-type: " + touch_action_type); + action_control_type_ = TouchInput::ActionControlType::kSwipe; + } + + controls_scale_move_ = + g_app_config->Resolve(AppConfig::FloatID::kTouchControlsScaleMovement); + controls_scale_actions_ = + g_app_config->Resolve(AppConfig::FloatID::kTouchControlsScaleActions); + swipe_controls_hidden_ = + g_app_config->Resolve(AppConfig::BoolID::kTouchControlsSwipeHidden); + + // Start with defaults. + switch (GetInterfaceType()) { + case UIScale::kSmall: + buttons_default_frac_x_ = 0.88f; + buttons_default_frac_y_ = 0.2f; + d_pad_default_frac_x_ = 0.12f; + d_pad_default_frac_y_ = 0.2f; + break; + case UIScale::kMedium: + buttons_default_frac_x_ = 0.89f; + buttons_default_frac_y_ = 0.2f; + d_pad_default_frac_x_ = 0.11f; + d_pad_default_frac_y_ = 0.2f; + break; + default: + buttons_default_frac_x_ = 0.9f; + buttons_default_frac_y_ = 0.3f; + d_pad_default_frac_x_ = 0.1f; + d_pad_default_frac_y_ = 0.3f; + break; + } + + // Now override with config. + d_pad_default_frac_x_ = + g_python->GetRawConfigValue("Touch DPad X", d_pad_default_frac_x_); + d_pad_default_frac_y_ = + g_python->GetRawConfigValue("Touch DPad Y", d_pad_default_frac_y_); + buttons_default_frac_x_ = + g_python->GetRawConfigValue("Touch Buttons X", buttons_default_frac_x_); + buttons_default_frac_y_ = + g_python->GetRawConfigValue("Touch Buttons Y", buttons_default_frac_y_); +} + +auto TouchInput::HandleTouchDown(void* touch, float x, float y) -> bool { + assert(InGameThread()); + + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + + // If we're in edit mode, see if the touch should become an edit-dpad touch or + // an edit-button touch. + if (editing_) { + float x_diff = x - d_pad_base_x_; + float y_diff = y - d_pad_base_y_; + float len = sqrtf(x_diff * x_diff + y_diff * y_diff) + / (base_controls_scale_ * controls_scale_move_); + if (len < 40.0f) { + d_pad_drag_touch_ = touch; + d_pad_drag_x_offs_ = x_diff; + d_pad_drag_y_offs_ = y_diff; + return true; + } + + x_diff = x - buttons_x_; + y_diff = y - buttons_y_; + len = sqrtf(x_diff * x_diff + y_diff * y_diff) + / (base_controls_scale_ * controls_scale_actions_); + if (len < 40.0f) { + buttons_drag_touch_ = touch; + buttons_drag_x_offs_ = x_diff; + buttons_drag_y_offs_ = y_diff; + return true; + } + return false; // We don't claim the event. + + } else { + // Normal in-game operation: + + // Normal operation is disabled while a UI is up. + if (g_ui->IsWindowPresent()) { + return false; + } + + if (!attached_to_player()) { + // Ignore touches at the very top (so we don't interfere with the menu). + if (y < height * 0.8f) { + RequestPlayer(); + + // Joining with the touchscreen can sometimes + // be accidental if there's a trackpad on the controller. + // ..so lets issue a warning to that effect if there's already + // controllers active.. (only if we got a player though). + if (attached_to_player() && g_input->HaveControllerWithPlayer()) { + ScreenMessage(g_game->GetResourceString("touchScreenJoinWarningText"), + {1.0f, 1.0f, 0.0f}); + } + } + } else { + // If its on the left side, this is our new dpad touch. + if (x < width * 0.5f) { + d_pad_touch_ = touch; + did_first_move_ = false; + if (movement_control_type_ == MovementControlType::kSwipe) { + d_pad_base_x_ = x; + d_pad_base_y_ = y; + } + d_pad_x_ = x; + d_pad_y_ = y; + d_pad_start_x_ = x; + d_pad_start_y_ = y; + + UpdateDPad(); + } else if (y < height * 0.8f) { + // Its on the right side (and below the menu), handle buttons. + // Start running if this is a new press. + if (buttons_touch_ == nullptr) { + InputCommand(InputType::kRun, 1.0f); + // in swipe mode we count this as a fly-press + if (action_control_type_ == ActionControlType::kSwipe) { + InputCommand(InputType::kFlyPress); + } + } + buttons_touch_ = touch; + buttons_touch_x_ = buttons_touch_start_x_ = x; + buttons_touch_y_ = buttons_touch_start_y_ = y; + + UpdateButtons(true); + } + } + } + return true; +} + +auto TouchInput::HandleTouchUp(void* touch, float x, float y) -> bool { + assert(InGameThread()); + + // Release dpad drag touch. + if (touch == d_pad_drag_touch_) { + d_pad_drag_touch_ = nullptr; + + // Write the current frac to our config. + g_python->SetRawConfigValue("Touch DPad X", d_pad_default_frac_x_); + g_python->SetRawConfigValue("Touch DPad Y", d_pad_default_frac_y_); + } + + if (touch == buttons_drag_touch_) { + buttons_drag_touch_ = nullptr; + + // Write the current frac to our config. + g_python->SetRawConfigValue("Touch Buttons X", buttons_default_frac_x_); + g_python->SetRawConfigValue("Touch Buttons Y", buttons_default_frac_y_); + } + + // Release on button touch. + if (touch == buttons_touch_) { + InputCommand(InputType::kRun, 0.0f); + if (action_control_type_ == ActionControlType::kSwipe) { + InputCommand(InputType::kFlyRelease); + } + buttons_touch_x_ = x; + buttons_touch_y_ = y; + buttons_touch_ = nullptr; + UpdateButtons(); + } + + // If it was our dpad touch, stop tracking. + if (touch == d_pad_touch_) { + d_pad_x_ = d_pad_base_x_; + d_pad_y_ = d_pad_base_y_; + d_pad_touch_ = nullptr; + UpdateDPad(); + } + return true; +} + +auto TouchInput::HandleTouchMoved(void* touch, float x, float y) -> bool { + assert(InGameThread()); + if (touch == d_pad_drag_touch_) { + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + float ratio_x = + std::min(0.45f, std::max(0.0f, (x - d_pad_drag_x_offs_) / width)); + float ratio_y = + std::min(0.9f, std::max(0.0f, (y - d_pad_drag_y_offs_) / height)); + d_pad_default_frac_x_ = ratio_x; + d_pad_default_frac_y_ = ratio_y; + } + if (touch == buttons_drag_touch_) { + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + float ratio_x = + std::min(1.0f, std::max(0.55f, (x - buttons_drag_x_offs_) / width)); + float ratio_y = + std::min(0.9f, std::max(0.0f, (y - buttons_drag_y_offs_) / height)); + buttons_default_frac_x_ = ratio_x; + buttons_default_frac_y_ = ratio_y; + } + + // Ignore button/pad touches while gui is up. + if (g_ui->IsWindowPresent()) { + return false; + } + if (touch == buttons_touch_) { + buttons_touch_x_ = x; + buttons_touch_y_ = y; + UpdateButtons(); + } + + // If it was our dpad touch, update tracking. + if (touch == d_pad_touch_) { + d_pad_x_ = x; + d_pad_y_ = y; + UpdateDPad(); + } + return true; +} + +auto TouchInput::GetRawDeviceName() -> std::string { return "TouchScreen"; } + +} // namespace ballistica diff --git a/src/ballistica/input/device/touch_input.h b/src/ballistica/input/device/touch_input.h new file mode 100644 index 00000000..a2d2f389 --- /dev/null +++ b/src/ballistica/input/device/touch_input.h @@ -0,0 +1,95 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_DEVICE_TOUCH_INPUT_H_ +#define BALLISTICA_INPUT_DEVICE_TOUCH_INPUT_H_ + +#include + +#include "ballistica/input/device/input_device.h" +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +/// A touchscreen based controller for mobile devices. +class TouchInput : public InputDevice { + public: + TouchInput(); + ~TouchInput() override; + auto GetAllowsConfiguring() -> bool override { return false; } + void HandleTouchEvent(TouchEvent::Type type, void* touch, float x, float y); + auto HandleTouchDown(void* touch, float x, float y) -> bool; + auto HandleTouchUp(void* touch, float x, float y) -> bool; + auto HandleTouchMoved(void* touch, float x, float y) -> bool; + void Draw(FrameDef* frame_def); + void set_editing(bool e) { editing_ = e; } + auto editing() const -> bool { return editing_; } + auto IsTouchScreen() -> bool override { return true; } + void UpdateMapping() override; + enum class MovementControlType { kJoystick, kSwipe }; + enum class ActionControlType { kButtons, kSwipe }; + + protected: + auto GetRawDeviceName() -> std::string override; + + private: + void UpdateDPad(); + void UpdateButtons(bool new_touch = false); + MovementControlType movement_control_type_{MovementControlType::kSwipe}; + ActionControlType action_control_type_{ActionControlType::kButtons}; + float controls_scale_move_{1.0f}; + float controls_scale_actions_{1.0f}; + bool swipe_controls_hidden_{}; + float presence_{}; + float button_fade_{}; + bool editing_{}; + void* d_pad_touch_{}; + void* d_pad_drag_touch_{}; + float d_pad_drag_x_offs_{}; + float d_pad_drag_y_offs_{}; + float d_pad_start_x_{}; + float d_pad_start_y_{}; + bool did_first_move_{}; + float d_pad_base_x_{}; + float d_pad_base_y_{}; + float d_pad_x_{}; + float d_pad_y_{}; + + // Button coordinates are provided in virtual screen space. + float buttons_default_frac_x_{}; + float buttons_default_frac_y_{}; + float d_pad_default_frac_x_{}; + float d_pad_default_frac_y_{}; + float buttons_x_{-100.0f}; + float buttons_y_{-100.0f}; + float buttons_touch_start_x_{}; + float buttons_touch_start_y_{}; + void* buttons_touch_{}; + float buttons_touch_x_{-100.0f}; + float buttons_touch_y_{-100.0f}; + void* buttons_drag_touch_{}; + float buttons_drag_x_offs_{}; + float buttons_drag_y_offs_{}; + float base_controls_scale_{1.0f}; + float world_draw_scale_{1.0f}; + bool bomb_held_{}; + bool punch_held_{}; + bool jump_held_{}; + bool pickup_held_{}; + float d_pad_draw_x_{}; + float d_pad_draw_y_{}; + Vector3f d_pad_draw_dir_{1.0f, 0.0f, 0.0f}; + millisecs_t last_buttons_touch_time_{}; + millisecs_t last_punch_held_time_{}; + millisecs_t last_pickup_held_time_{}; + millisecs_t last_bomb_held_time_{}; + millisecs_t last_jump_held_time_{}; + millisecs_t last_punch_press_time_{}; + millisecs_t last_pickup_press_time_{}; + millisecs_t last_bomb_press_time_{}; + millisecs_t last_jump_press_time_{}; + millisecs_t update_time_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_DEVICE_TOUCH_INPUT_H_ diff --git a/src/ballistica/input/input.cc b/src/ballistica/input/input.cc new file mode 100644 index 00000000..f32b5026 --- /dev/null +++ b/src/ballistica/input/input.cc @@ -0,0 +1,1842 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/input.h" + +#include + +#include "ballistica/app/app_config.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/game/player.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/input/device/joystick.h" +#include "ballistica/input/device/keyboard_input.h" +#include "ballistica/input/device/test_input.h" +#include "ballistica/input/device/touch_input.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/console.h" +#include "ballistica/ui/root_ui.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/root_widget.h" + +namespace ballistica { + +// Though it seems strange, input is actually owned by the game thread, not the +// app thread. This keeps things simple for game logic interacting with input +// stuff (controller names, counts, etc) but means we need to be prudent about +// properly passing stuff between the game and app thread as needed. + +// The following was pulled from sdl2 +#if BA_SDL2_BUILD || BA_MINSDL_BUILD +static const char* const scancode_names[SDL_NUM_SCANCODES] = { + nullptr, + nullptr, + nullptr, + nullptr, + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + "Return", + "Escape", + "Backspace", + "Tab", + "Space", + "-", + "=", + "[", + "]", + "\\", + "#", + ";", + "'", + "`", + ",", + ".", + "/", + "CapsLock", + "F1", + "F2", + "F3", + "F4", + "F5", + "F6", + "F7", + "F8", + "F9", + "F10", + "F11", + "F12", + "PrintScreen", + "ScrollLock", + "Pause", + "Insert", + "Home", + "PageUp", + "Delete", + "End", + "PageDown", + "Right", + "Left", + "Down", + "Up", + "Numlock", + "Keypad /", + "Keypad *", + "Keypad -", + "Keypad +", + "Keypad Enter", + "Keypad 1", + "Keypad 2", + "Keypad 3", + "Keypad 4", + "Keypad 5", + "Keypad 6", + "Keypad 7", + "Keypad 8", + "Keypad 9", + "Keypad 0", + "Keypad .", + nullptr, + "Application", + "Power", + "Keypad =", + "F13", + "F14", + "F15", + "F16", + "F17", + "F18", + "F19", + "F20", + "F21", + "F22", + "F23", + "F24", + "Execute", + "Help", + "Menu", + "Select", + "Stop", + "Again", + "Undo", + "Cut", + "Copy", + "Paste", + "Find", + "Mute", + "VolumeUp", + "VolumeDown", + nullptr, + nullptr, + nullptr, + "Keypad ,", + "Keypad = (AS400)", + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + "AltErase", + "SysReq", + "Cancel", + "Clear", + "Prior", + "Return", + "Separator", + "Out", + "Oper", + "Clear / Again", + "CrSel", + "ExSel", + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + "Keypad 00", + "Keypad 000", + "ThousandsSeparator", + "DecimalSeparator", + "CurrencyUnit", + "CurrencySubUnit", + "Keypad (", + "Keypad )", + "Keypad {", + "Keypad }", + "Keypad Tab", + "Keypad Backspace", + "Keypad A", + "Keypad B", + "Keypad C", + "Keypad D", + "Keypad E", + "Keypad F", + "Keypad XOR", + "Keypad ^", + "Keypad %", + "Keypad <", + "Keypad >", + "Keypad &", + "Keypad &&", + "Keypad |", + "Keypad ||", + "Keypad :", + "Keypad #", + "Keypad Space", + "Keypad @", + "Keypad !", + "Keypad MemStore", + "Keypad MemRecall", + "Keypad MemClear", + "Keypad MemAdd", + "Keypad MemSubtract", + "Keypad MemMultiply", + "Keypad MemDivide", + "Keypad +/-", + "Keypad Clear", + "Keypad ClearEntry", + "Keypad Binary", + "Keypad Octal", + "Keypad Decimal", + "Keypad Hexadecimal", + nullptr, + nullptr, + "Left Ctrl", + "Left Shift", + "Left Alt", + "Left GUI", + "Right Ctrl", + "Right Shift", + "Right Alt", + "Right GUI", + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + "ModeSwitch", + "AudioNext", + "AudioPrev", + "AudioStop", + "AudioPlay", + "AudioMute", + "MediaSelect", + "WWW", + "Mail", + "Calculator", + "Computer", + "AC Search", + "AC Home", + "AC Back", + "AC Forward", + "AC Stop", + "AC Refresh", + "AC Bookmarks", + "BrightnessDown", + "BrightnessUp", + "DisplaySwitch", + "KBDIllumToggle", + "KBDIllumDown", + "KBDIllumUp", + "Eject", + "Sleep", + "App1", + "App2", + "AudioRewind", + "AudioFastForward", +}; +#endif // BA_SDL2_BUILD || BA_MINSDL_BUILD + +Input::Input() { + // We're a singleton. + // assert(g_input == nullptr); + // g_input = this; + + assert(InGameThread()); + + // Config should have always been read by this point; right? + // assert(g_python); + // UpdateEnabledControllerSubsystems(); +} + +void Input::PushCreateKeyboardInputDevices() { + g_game->PushCall([this] { CreateKeyboardInputDevices(); }); +} + +void Input::CreateKeyboardInputDevices() { + assert(InGameThread()); + if (keyboard_input_ != nullptr || keyboard_input_2_ != nullptr) { + Log("Error: CreateKeyboardInputDevices called with existing kbs."); + return; + } + keyboard_input_ = Object::NewDeferred(nullptr); + AddInputDevice(keyboard_input_, false); + keyboard_input_2_ = Object::NewDeferred(keyboard_input_); + AddInputDevice(keyboard_input_2_, false); +} + +void Input::PushDestroyKeyboardInputDevices() { + g_game->PushCall([this] { DestroyKeyboardInputDevices(); }); +} + +void Input::DestroyKeyboardInputDevices() { + assert(InGameThread()); + if (keyboard_input_ == nullptr || keyboard_input_2_ == nullptr) { + Log("Error: DestroyKeyboardInputDevices called with null kb(s)."); + return; + } + RemoveInputDevice(keyboard_input_, false); + keyboard_input_ = nullptr; + RemoveInputDevice(keyboard_input_2_, false); + keyboard_input_2_ = nullptr; +} + +Input::~Input() = default; + +auto Input::GetInputDevice(int id) -> InputDevice* { + if (id < 0 || id >= static_cast(input_devices_.size())) { + return nullptr; + } + return input_devices_[id].get(); +} + +auto Input::GetInputDevice(const std::string& name, + const std::string& unique_id) -> InputDevice* { + assert(InGameThread()); + for (auto&& i : input_devices_) { + if (i.exists() && (i->GetDeviceName() == name) + && i->GetPersistentIdentifier() == unique_id) { + return i.get(); + } + } + return nullptr; +} + +auto Input::GetNewNumberedIdentifier(const std::string& name, + const std::string& identifier) -> int { + assert(InGameThread()); + + // Stuff like reserved_identifiers["JoyStickType"]["0x812312314"] = 2; + + // First off, if we came with an identifier, see if we've got a reserved + // number already. + if (!identifier.empty()) { + auto i = reserved_identifiers_.find(name); + if (i != reserved_identifiers_.end()) { + auto j = i->second.find(identifier); + if (j != i->second.end()) { + return j->second; + } + } + } + + int num = 1; + int full_id; + while (true) { + bool in_use = false; + + // Scan other devices with the same device-name and find the first number + // suffix that's not taken. + for (auto&& i : input_devices_) { + if (i.exists()) { + if ((i->GetRawDeviceName() == name) && i->number_ == num) { + in_use = true; + break; + } + } + } + if (!in_use) { + // Ok so far its unused.. however input devices that provide non-empty + // identifiers (serial number, usb-id, etc) reserve their number for the + // duration of the game, so we need to check against all reserved numbers + // so we don't steal someones... (so that if they disconnect and reconnect + // they'll get the same number and thus the same name, etc) + if (!identifier.empty()) { + auto i = reserved_identifiers_.find(name); + if (i != reserved_identifiers_.end()) { + for (auto&& j : i->second) { + if (j.second == num) { + in_use = true; + break; + } + } + } + } + + // If its *still* clear lets nab it. + if (!in_use) { + full_id = num; + + // If we have an identifier, reserve it. + if (!identifier.empty()) { + reserved_identifiers_[name][identifier] = num; + } + break; + } + } + num++; + } + return full_id; +} + +void Input::CreateTouchInput() { + assert(InMainThread()); + assert(touch_input_ == nullptr); + touch_input_ = Object::NewDeferred(); + PushAddInputDeviceCall(touch_input_, false); +} + +void Input::AnnounceConnects() { + static bool first_print = true; + + // For the first announcement just say "X controllers detected" and don't have + // a sound. + if (first_print && GetRealTime() < 10000) { + first_print = false; + + // Disabling this completely for now; being more lenient with devices + // allowed on android means this will often come back with large numbers. + bool do_print{false}; + + // If there's been several connected, just give a number. + if (explicit_bool(do_print)) { + if (newly_connected_controllers_.size() > 1) { + std::string s = g_game->GetResourceString("controllersDetectedText"); + Utils::StringReplaceOne( + &s, "${COUNT}", + std::to_string(newly_connected_controllers_.size())); + ScreenMessage(s); + } else { + ScreenMessage(g_game->GetResourceString("controllerDetectedText")); + } + } + } else { + // If there's been several connected, just give a number. + if (newly_connected_controllers_.size() > 1) { + std::string s = g_game->GetResourceString("controllersConnectedText"); + Utils::StringReplaceOne( + &s, "${COUNT}", std::to_string(newly_connected_controllers_.size())); + ScreenMessage(s); + } else { + // If its just one, name it. + std::string s = g_game->GetResourceString("controllerConnectedText"); + Utils::StringReplaceOne(&s, "${CONTROLLER}", + newly_connected_controllers_.front()); + ScreenMessage(s); + } + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kGunCock)); + } + + newly_connected_controllers_.clear(); +} + +void Input::AnnounceDisconnects() { + // If there's been several connected, just give a number. + if (newly_disconnected_controllers_.size() > 1) { + std::string s = g_game->GetResourceString("controllersDisconnectedText"); + Utils::StringReplaceOne( + &s, "${COUNT}", std::to_string(newly_disconnected_controllers_.size())); + ScreenMessage(s); + } else { + // If its just one, name it. + std::string s = g_game->GetResourceString("controllerDisconnectedText"); + Utils::StringReplaceOne(&s, "${CONTROLLER}", + newly_disconnected_controllers_.front()); + ScreenMessage(s); + } + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kCorkPop)); + + newly_disconnected_controllers_.clear(); +} + +void Input::ShowStandardInputDeviceConnectedMessage(InputDevice* j) { + assert(InGameThread()); + std::string suffix; + suffix += j->GetPersistentIdentifier(); + suffix += j->GetDeviceExtraDescription(); + if (!suffix.empty()) { + suffix = " " + suffix; + } + newly_connected_controllers_.push_back(j->GetDeviceName() + suffix); + + // Set a timer to go off and announce the accumulated additions. + if (connect_print_timer_id_ != 0) { + g_game->DeleteRealTimer(connect_print_timer_id_); + } + connect_print_timer_id_ = g_game->NewRealTimer( + 250, false, NewLambdaRunnable([this] { AnnounceConnects(); })); +} + +void Input::ShowStandardInputDeviceDisconnectedMessage(InputDevice* j) { + assert(InGameThread()); + + newly_disconnected_controllers_.push_back(j->GetDeviceName() + " " + + j->GetPersistentIdentifier() + + j->GetDeviceExtraDescription()); + + // Set a timer to go off and announce the accumulated additions. + if (disconnect_print_timer_id_ != 0) { + g_game->DeleteRealTimer(disconnect_print_timer_id_); + } + disconnect_print_timer_id_ = g_game->NewRealTimer( + 250, false, NewLambdaRunnable([this] { AnnounceDisconnects(); })); +} + +void Input::PushAddInputDeviceCall(InputDevice* input_device, + bool standard_message) { + g_game->PushCall([this, input_device, standard_message] { + AddInputDevice(input_device, standard_message); + }); +} + +void Input::AddInputDevice(InputDevice* input, bool standard_message) { + assert(InGameThread()); + + // Lets go through and find the first unused input-device id and use that + // (might as well keep our list small if we can). + int index = 0; + bool found_slot = false; + for (auto& input_device : input_devices_) { + if (!input_device.exists()) { + input_device = Object::MakeRefCounted(input); + found_slot = true; + input->set_index(index); + break; + } + index++; + } + if (!found_slot) { + input_devices_.push_back(Object::MakeRefCounted(input)); + input->set_index(static_cast(input_devices_.size() - 1)); + } + + // We also want to give this input-device as unique an identifier as + // possible. We ask it for its own string which hopefully includes a serial + // or something, but if it doesn't and thus matches an already-existing one, + // we tack an index on to it. that way we can at least uniquely address them + // based off how many are connected. + input->set_numbered_identifier(GetNewNumberedIdentifier( + input->GetRawDeviceName(), input->GetDeviceIdentifier())); + input->ConnectionComplete(); // Let it do any announcing it wants to. + + // Update controls for just this guy. + input->UpdateMapping(); + + // Need to do this after updating controls, as some control settings can + // affect things we count (such as whether start activates default button). + UpdateInputDeviceCounts(); + + if (g_buildconfig.ostype_macos()) { + // Special case: on mac, the first time a iOS/Mac controller is connected, + // let the user know they may want to enable them if they're currently set + // as ignored. (the default at the moment is to only use classic device + // support). + static bool printed_ios_mac_controller_warning = false; + if (!printed_ios_mac_controller_warning && ignore_mfi_controllers_ + && input->IsMFiController()) { + ScreenMessage(R"({"r":"macControllerSubsystemMFiNoteText"})", {1, 1, 0}); + printed_ios_mac_controller_warning = true; + } + } + + if (standard_message && !input->ShouldBeHiddenFromUser()) { + ShowStandardInputDeviceConnectedMessage(input); + } +} + +void Input::PushRemoveInputDeviceCall(InputDevice* input_device, + bool standard_message) { + g_game->PushCall([this, input_device, standard_message] { + RemoveInputDevice(input_device, standard_message); + }); +} + +void Input::RemoveInputDevice(InputDevice* input, bool standard_message) { + assert(InGameThread()); + + if (standard_message && !input->ShouldBeHiddenFromUser()) { + ShowStandardInputDeviceDisconnectedMessage(input); + } + + // Just look for it in our list.. if we find it, simply clear the ref + // (we need to keep the pointer around so our list indices don't change). + for (auto& input_device : input_devices_) { + if (input_device.exists() && (input_device.get() == input)) { + // Pull it off the list before killing it (in case it triggers another + // kill itself). + Object::Ref device = input_device; + + // Ok we cleared its slot in our vector; now we just have + // the local variable 'device' keeping it alive. + input_device.Clear(); + + // If we're attached to a local or remote player, kill the player. + if (input->attached_to_player()) { + if (input->GetPlayer() != nullptr) { + // NOTE: we now remove the player instantly instead of pushing + // a call to do it; otherwise its possible that someone tries + // to access the player's inputdevice before the call goes + // through which would lead to an exception. + g_game->RemovePlayer(input->GetPlayer()); + // g_game->PushRemovePlayerCall(input->GetPlayer()); + } + if (input->GetRemotePlayer() != nullptr) { + input->RemoveRemotePlayerFromGame(); + } + device->DetachFromPlayer(); + } + + // This should kill the device. + // FIXME: since many devices get allocated in the main thread, + // should we not kill it there too?... + device.Clear(); + UpdateInputDeviceCounts(); + return; + } + } + throw Exception("Input::RemoveInputDevice: invalid device provided"); +} + +void Input::UpdateInputDeviceCounts() { + assert(InGameThread()); + + have_button_using_inputs_ = false; + have_start_activated_default_button_inputs_ = false; + have_non_touch_inputs_ = false; + int total = 0; + int controller_count = 0; + for (auto& input_device : input_devices_) { + // Ok, we now limit non-keyboard non-touchscreen devices to ones that have + // been active recently.. (we're starting to get lots of virtual devices and + // other cruft on android; don't wanna show controller UIs just due to + // those) + if (input_device.exists() + && ((*input_device).IsTouchScreen() || (*input_device).IsKeyboard() + || ((*input_device).last_input_time() != 0 + && g_game->master_time() - (*input_device).last_input_time() + < 60000))) { + total++; + if (!(*input_device).IsTouchScreen()) { + have_non_touch_inputs_ = true; + } + if ((*input_device).start_button_activates_default_widget()) { + have_start_activated_default_button_inputs_ = true; + } + if ((*input_device).IsController()) { + have_button_using_inputs_ = true; + if (!(*input_device).IsUIOnly() && !(*input_device).IsTestInput()) { + controller_count++; + } + } + } + } + if (controller_count > max_controller_count_so_far_) { + max_controller_count_so_far_ = controller_count; + if (max_controller_count_so_far_ == 1) { + g_python->PushObjCall(Python::ObjID::kAwardInControlAchievementCall); + } else if (max_controller_count_so_far_ == 2) { + g_python->PushObjCall(Python::ObjID::kAwardDualWieldingAchievementCall); + } + } +} + +auto Input::GetLocalActiveInputDeviceCount() -> int { + assert(InGameThread()); + + // This can get called alot so lets cache the value. + millisecs_t current_time = g_game->master_time(); + if (current_time != last_have_many_local_active_input_devices_check_time_) { + last_have_many_local_active_input_devices_check_time_ = current_time; + + int count = 0; + for (auto& input_device : input_devices_) { + // Only count non-keyboard, non-touchscreen, local devices that have been + // used in the last minute. + if (input_device.exists() && !(*input_device).IsKeyboard() + && !(*input_device).IsTouchScreen() && !(*input_device).IsUIOnly() + && (*input_device).IsLocal() + && ((*input_device).last_input_time() != 0 + && g_game->master_time() - (*input_device).last_input_time() + < 60000)) { + count++; + } + } + local_active_input_device_count_ = count; + } + return local_active_input_device_count_; +} + +auto Input::HaveControllerWithPlayer() -> bool { + assert(InGameThread()); + for (auto& input_device : input_devices_) { + if (input_device.exists() && (*input_device).IsController() + && (*input_device).attached_to_player()) { + return true; + } + } + return false; +} + +auto Input::HaveRemoteAppController() -> bool { + assert(InGameThread()); + for (auto& input_device : input_devices_) { + if (input_device.exists() && (*input_device).IsRemoteApp()) { + return true; + } + } + return false; +} + +auto Input::GetInputDevicesWithName(const std::string& name) + -> std::vector { + std::vector vals; + if (!HeadlessMode()) { + for (auto& input_device : input_devices_) { + if (input_device.exists()) { + auto* js = dynamic_cast(input_device.get()); + if (js && js->GetDeviceName() == name) { + vals.push_back(js); + } + } + } + } + return vals; +} + +auto Input::GetConfigurableGamePads() -> std::vector { + assert(InGameThread()); + std::vector vals; + if (!HeadlessMode()) { + for (auto& input_device : input_devices_) { + if (input_device.exists()) { + auto* js = dynamic_cast(input_device.get()); + if (js && js->GetAllowsConfiguring() && !js->ShouldBeHiddenFromUser()) { + vals.push_back(js); + } + } + } + } + return vals; +} + +auto Input::ShouldCompletelyIgnoreInputDevice(InputDevice* input_device) + -> bool { + if (g_buildconfig.ostype_macos()) { + if (ignore_mfi_controllers_ && input_device->IsMFiController()) { + return true; + } + } + return ignore_sdl_controllers_ && input_device->IsSDLController(); +} + +auto Input::GetIdleTime() const -> millisecs_t { + return GetRealTime() - last_input_time_; +} + +void Input::UpdateEnabledControllerSubsystems() { + assert(IsBootstrapped()); + + // First off, on mac, let's update whether we want to completely ignore either + // the classic or the iOS/Mac controller subsystems. + if (g_buildconfig.ostype_macos()) { + std::string sys = + g_app_config->Resolve(AppConfig::StringID::kMacControllerSubsystem); + if (sys == "Classic") { + ignore_mfi_controllers_ = true; + ignore_sdl_controllers_ = false; + } else if (sys == "MFi") { + ignore_mfi_controllers_ = false; + ignore_sdl_controllers_ = true; + } else if (sys == "Both") { + ignore_mfi_controllers_ = false; + ignore_sdl_controllers_ = false; + } else { + BA_LOG_ONCE("Invalid mac-controller-subsystem value: '" + sys + "'"); + } + } +} + +// Tells all inputs to update their controls based on the app config. +void Input::ApplyAppConfig() { + assert(InGameThread()); + + UpdateEnabledControllerSubsystems(); + + // It's technically possible that updating these controls will add or remove + // devices, thus changing the input_devices_ list, so lets work with a copy of + // it. + std::vector > input_devices = input_devices_; + for (auto& input_device : input_devices) { + if (input_device.exists()) { + input_device->UpdateMapping(); + } + } +} + +void Input::Update() { + assert(InGameThread()); + + millisecs_t real_time = GetRealTime(); + + // If input has been locked an excessively long amount of time, unlock it. + if (input_lock_count_temp_) { + if (real_time - last_input_temp_lock_time_ > 10000) { + Log("Error: Input has been temp-locked for 10 seconds; unlocking."); + input_lock_count_temp_ = 0; + PrintLockLabels(); + input_lock_temp_labels_.clear(); + input_unlock_temp_labels_.clear(); + } + } + + // We now need to update our input-device numbers dynamically since they're + // based on recently-active devices. + // ..we do this much more often for the first few seconds to keep + // controller-usage from being as annoying. + // millisecs_t incr = (real_time > 10000) ? 468 : 98; + // Update: don't remember why that was annoying; trying a single value for + // now. + millisecs_t incr = 249; + if (real_time - last_input_device_count_update_time_ > incr) { + UpdateInputDeviceCounts(); + last_input_device_count_update_time_ = real_time; + } + + for (auto& input_device : input_devices_) { + if (input_device.exists()) { + (*input_device).Update(); + } + } +} + +void Input::Reset() { + assert(InGameThread()); + + // Detach all inputs from players. + for (auto& input_device : input_devices_) { + if (input_device.exists()) { + input_device->DetachFromPlayer(); + } + } +} + +void Input::LockAllInput(bool permanent, const std::string& label) { + assert(InGameThread()); + if (permanent) { + input_lock_count_permanent_++; + input_lock_permanent_labels_.push_back(label); + } else { + input_lock_count_temp_++; + if (input_lock_count_temp_ == 1) { + last_input_temp_lock_time_ = GetRealTime(); + } + input_lock_temp_labels_.push_back(label); + + recent_input_locks_unlocks_.push_back("temp lock: " + label + " time " + + std::to_string(GetRealTime())); + while (recent_input_locks_unlocks_.size() > 10) { + recent_input_locks_unlocks_.pop_front(); + } + } +} + +void Input::UnlockAllInput(bool permanent, const std::string& label) { + assert(InGameThread()); + + recent_input_locks_unlocks_.push_back( + permanent + ? "permanent unlock: " + : "temp unlock: " + label + " time " + std::to_string(GetRealTime())); + while (recent_input_locks_unlocks_.size() > 10) + recent_input_locks_unlocks_.pop_front(); + + if (permanent) { + input_lock_count_permanent_--; + input_unlock_permanent_labels_.push_back(label); + if (input_lock_count_permanent_ < 0) { + BA_LOG_PYTHON_TRACE_ONCE("lock-count-permanent < 0"); + PrintLockLabels(); + input_lock_count_permanent_ = 0; + } + + // When lock counts get back down to zero, clear our labels since all is + // well. + if (input_lock_count_permanent_ == 0) { + input_lock_permanent_labels_.clear(); + input_unlock_permanent_labels_.clear(); + } + } else { + input_lock_count_temp_--; + input_unlock_temp_labels_.push_back(label); + if (input_lock_count_temp_ < 0) { + Log("WARNING: temp input unlock at time " + std::to_string(GetRealTime()) + + " with no active lock: '" + label + "'"); + // This is to be expected since we can reset this to 0. + input_lock_count_temp_ = 0; + } + + // When lock counts get back down to zero, clear our labels since all is + // well. + if (input_lock_count_temp_ == 0) { + input_lock_temp_labels_.clear(); + input_unlock_temp_labels_.clear(); + } + } +} + +void Input::PrintLockLabels() { + std::string s = + "INPUT LOCK REPORT (time=" + std::to_string(GetRealTime()) + "):"; + int num; + + s += "\n " + std::to_string(input_lock_temp_labels_.size()) + " TEMP LOCKS:"; + num = 1; + for (auto& input_lock_temp_label : input_lock_temp_labels_) { + s += "\n " + std::to_string(num++) + ": " + input_lock_temp_label; + } + + s += "\n " + std::to_string(input_unlock_temp_labels_.size()) + + " TEMP UNLOCKS:"; + num = 1; + for (auto& input_unlock_temp_label : input_unlock_temp_labels_) { + s += "\n " + std::to_string(num++) + ": " + input_unlock_temp_label; + } + + s += "\n " + std::to_string(input_lock_permanent_labels_.size()) + + " PERMANENT LOCKS:"; + num = 1; + for (auto& input_lock_permanent_label : input_lock_permanent_labels_) { + s += "\n " + std::to_string(num++) + ": " + input_lock_permanent_label; + } + + s += "\n " + std::to_string(input_unlock_permanent_labels_.size()) + + " PERMANENT UNLOCKS:"; + num = 1; + for (auto& input_unlock_permanent_label : input_unlock_permanent_labels_) { + s += "\n " + std::to_string(num++) + ": " + input_unlock_permanent_label; + } + s += "\n " + std::to_string(recent_input_locks_unlocks_.size()) + + " MOST RECENT LOCKS:"; + num = 1; + for (auto& recent_input_locks_unlock : recent_input_locks_unlocks_) { + s += "\n " + std::to_string(num++) + ": " + recent_input_locks_unlock; + } + + Log(s); +} + +void Input::ProcessStressTesting(int player_count) { + assert(InMainThread()); + assert(player_count >= 0); + + millisecs_t time = GetRealTime(); + + // FIXME: If we don't check for stress_test_last_leave_time_ we totally + // confuse the game.. need to be able to survive that. + + // Kill some off if we have too many. + while (static_cast(test_inputs_.size()) > player_count) { + delete test_inputs_.front(); + test_inputs_.pop_front(); + } + + // If we have less than full test-inputs, add one randomly. + if (static_cast(test_inputs_.size()) < player_count + && ((rand() % 1000 < 10))) { // NOLINT + test_inputs_.push_back(new TestInput()); + } + + // Every so often lets kill the oldest one off. + if (explicit_bool(true)) { + if (test_inputs_.size() > 0 && (rand() % 2000 < 3)) { // NOLINT + stress_test_last_leave_time_ = time; + + // Usually do oldest; sometimes newest. + if (rand() % 5 == 0) { // NOLINT + delete test_inputs_.back(); + test_inputs_.pop_back(); + } else { + delete test_inputs_.front(); + test_inputs_.pop_front(); + } + } + } + + if (time - stress_test_time_ > 1000) { + stress_test_time_ = time; // reset.. + for (auto& test_input : test_inputs_) { + (*test_input).Reset(); + } + } + while (stress_test_time_ < time) { + stress_test_time_++; + for (auto& test_input : test_inputs_) { + (*test_input).Process(stress_test_time_); + } + } +} + +void Input::HandleBackPress(bool from_toolbar) { + assert(InGameThread()); + + // This can come through occasionally before our UI is up it seems? + // Just ignore in that case. + if (g_ui == nullptr || g_ui->screen_root_widget() == nullptr + || g_ui->overlay_root_widget() == nullptr + || g_ui->root_widget() == nullptr) { + // Log("HandleBackPress() called without main UI"); + return; + } + + // If there's no dialogs/windows up, ask for a menu (owned by the touch-input + // if available). + if (g_ui->screen_root_widget()->GetChildCount() == 0 + && g_ui->overlay_root_widget()->GetChildCount() == 0) { + g_game->PushMainMenuPressCall(touch_input_); + } else { + if (from_toolbar) { + // NOTE - this means the toolbar back button can never apply to overlay + // widgets; is that ok?... + g_ui->screen_root_widget()->HandleMessage( + WidgetMessage(WidgetMessage::Type::kCancel)); + } else { + g_ui->root_widget()->HandleMessage( + WidgetMessage(WidgetMessage::Type::kCancel)); + } + } +} + +void Input::PushTextInputEvent(const std::string& text) { + g_game->PushCall([this, text] { + ResetIdleTime(); + + // Ignore if input is locked. + if (IsInputLocked()) { + return; + } + if (g_app_globals->console != nullptr + && g_app_globals->console->HandleTextEditing(text)) { + return; + } + g_ui->SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kTextInput, + nullptr, 0, 0, 0, 0, text.c_str())); + }); +} + +auto Input::PushJoystickEvent(const SDL_Event& event, InputDevice* input_device) + -> void { + g_game->PushCall([this, event, input_device] { + HandleJoystickEvent(event, input_device); + }); +} + +void Input::HandleJoystickEvent(const SDL_Event& event, + InputDevice* input_device) { + assert(InGameThread()); + assert(input_device); + + if (ShouldCompletelyIgnoreInputDevice(input_device)) { + return; + } + if (IsInputLocked()) { + return; + } + + // Make note that we're not idle. + ResetIdleTime(); + + // And that this particular device isn't idle either. + input_device->UpdateLastInputTime(); + + // Give Python a crack at it for captures, etc. + if (g_python->HandleJoystickEvent(event, input_device)) { + return; + } + + input_device->HandleSDLEvent(&event); +} + +void Input::PushKeyPressEvent(const SDL_Keysym& keysym) { + g_game->PushCall([this, keysym] { HandleKeyPress(&keysym); }); +} + +void Input::PushKeyReleaseEvent(const SDL_Keysym& keysym) { + g_game->PushCall([this, keysym] { HandleKeyRelease(&keysym); }); +} + +void Input::HandleKeyPress(const SDL_Keysym* keysym) { + assert(InGameThread()); + + ResetIdleTime(); + + // Ignore all key presses if input is locked. + if (IsInputLocked()) { + return; + } + + // Give Python a crack at it for captures, etc. + if (g_python->HandleKeyPressEvent(*keysym)) { + return; + } + + // Regardless of what else we do, keep track of mod key states. + // (for things like manual camera moves. For individual key presses + // ideally we should use the modifiers bundled with the key presses) + UpdateModKeyStates(keysym, true); + + bool repeat_press; + if (keys_held_.count(keysym->sym) != 0) { + repeat_press = true; + } else { + repeat_press = false; + keys_held_.insert(keysym->sym); + } + + // Mobile-specific stuff. + if (g_buildconfig.ostype_ios_tvos() || g_buildconfig.ostype_android()) { + switch (keysym->sym) { + // FIXME: See if this stuff is still necessary. Was this perhaps + // specifically to support the console? + case SDLK_DELETE: + case SDLK_RETURN: + case SDLK_KP_ENTER: + case SDLK_BACKSPACE: { + // FIXME: I don't remember what this was put here for, but now that we + // have hardware keyboards it crashes text fields by sending them a + // TEXT_INPUT message with no string.. I made them resistant to that + // case but wondering if we can take this out?... + g_ui->SendWidgetMessage( + WidgetMessage(WidgetMessage::Type::kTextInput, keysym)); + break; + } + default: + break; + } + } + + // A few things that apply only to non-mobile. + if (!g_buildconfig.ostype_ios_tvos() && !g_buildconfig.ostype_android()) { + // Command-F or Control-F toggles full-screen. + if (!repeat_press && keysym->sym == SDLK_f + && ((keysym->mod & KMOD_CTRL) || (keysym->mod & KMOD_GUI))) { // NOLINT + g_python->obj(Python::ObjID::kToggleFullscreenCall).Call(); + return; + } + + // Command-Q or Control-Q quits. + if (!repeat_press && keysym->sym == SDLK_q + && ((keysym->mod & KMOD_CTRL) || (keysym->mod & KMOD_GUI))) { // NOLINT + g_game->PushConfirmQuitCall(); + } + } + if (g_app_globals->console != nullptr + && g_app_globals->console->HandleKeyPress(keysym)) { + return; + } + + bool handled = false; + + // None of the following stuff accepts key repeats. + if (!repeat_press) { + switch (keysym->sym) { + // Menu button on android/etc. pops up the menu. + case SDLK_MENU: { + if (g_ui && g_ui->screen_root_widget()) { + // If there's no dialogs/windows up, ask for a menu (owned by the + // touch-screen if available). + if (g_ui->screen_root_widget()->GetChildCount() == 0) { + g_game->PushMainMenuPressCall(touch_input_); + } + } + handled = true; + break; + } + case SDLK_AC_BACK: { + HandleBackPress(false); + handled = true; + break; + } + + case SDLK_EQUALS: + case SDLK_PLUS: + g_game->ChangeGameSpeed(1); + handled = true; + break; + + case SDLK_MINUS: + g_game->ChangeGameSpeed(-1); + handled = true; + break; + + case SDLK_F5: { + g_ui->root_ui()->TogglePartyWindowKeyPress(); + handled = true; + break; + } + + case SDLK_F7: + g_game->PushToggleManualCameraCall(); + handled = true; + break; + + case SDLK_F8: + g_game->PushToggleDebugInfoDisplayCall(); + handled = true; + break; + + case SDLK_F9: + g_python->PushObjCall(Python::ObjID::kLanguageTestToggleCall); + handled = true; + break; + + case SDLK_F10: + g_game->PushToggleCollisionGeometryDisplayCall(); + handled = true; + break; + + case SDLK_ESCAPE: + + if (g_ui && g_ui->screen_root_widget() && g_ui->root_widget() + && g_ui->overlay_root_widget()) { + // If there's no dialogs/windows up, ask for a menu owned by the + // keyboard. + if (g_ui->screen_root_widget()->GetChildCount() == 0 + && g_ui->overlay_root_widget()->GetChildCount() == 0) { + if (keyboard_input_) { + g_game->PushMainMenuPressCall(keyboard_input_); + } + } else { + // Ok there's a UI up.. send along a cancel message. + g_ui->root_widget()->HandleMessage( + WidgetMessage(WidgetMessage::Type::kCancel)); + } + } + handled = true; + break; + + default: + break; + } + } + + // If we haven't claimed it, pass it along as potential player/widget input. + if (!handled) { + if (keyboard_input_) { + keyboard_input_->HandleKey(keysym, repeat_press, true); + } + } +} + +void Input::HandleKeyRelease(const SDL_Keysym* keysym) { + assert(InGameThread()); + + // Note: we want to let these through even if input is locked. + + ResetIdleTime(); + + // Give Python a crack at it for captures, etc. + if (g_python->HandleKeyReleaseEvent(*keysym)) { + return; + } + + // Regardless of what else we do, keep track of mod key states. + // (for things like manual camera moves. For individual key presses + // ideally we should use the modifiers bundled with the key presses) + UpdateModKeyStates(keysym, false); + + // In some cases we may receive duplicate key-release events + // (if a keyboard reset was run it deals out key releases but then the + // keyboard driver issues them as well) + if (keys_held_.count(keysym->sym) == 0) { + return; + } + + keys_held_.erase(keysym->sym); + + if (IsInputLocked()) { + return; + } + + bool handled = false; + + if (g_app_globals->console != nullptr + && g_app_globals->console->HandleKeyRelease(keysym)) { + handled = true; + } + + // If we haven't claimed it, pass it along as potential player input. + if (!handled) { + if (keyboard_input_) { + keyboard_input_->HandleKey(keysym, false, false); + } + } +} + +auto Input::UpdateModKeyStates(const SDL_Keysym* keysym, bool press) -> void { + switch (keysym->sym) { + case SDLK_LCTRL: + case SDLK_RCTRL: { + if (Camera* c = g_graphics->camera()) { + c->set_ctrl_down(press); + } + break; + } + case SDLK_LALT: + case SDLK_RALT: { + if (Camera* c = g_graphics->camera()) { + c->set_alt_down(press); + } + break; + } + case SDLK_LGUI: + case SDLK_RGUI: { + if (Camera* c = g_graphics->camera()) { + c->set_cmd_down(press); + } + break; + } + default: + break; + } +} + +auto Input::PushMouseScrollEvent(const Vector2f& amount) -> void { + g_game->PushCall([this, amount] { HandleMouseScroll(amount); }); +} + +auto Input::HandleMouseScroll(const Vector2f& amount) -> void { + assert(InGameThread()); + if (IsInputLocked()) { + return; + } + ResetIdleTime(); + + Widget* root_widget = g_ui->root_widget(); + if (std::abs(amount.y) > 0.0001f && root_widget) { + root_widget->HandleMessage(WidgetMessage(WidgetMessage::Type::kMouseWheel, + nullptr, cursor_pos_x_, + cursor_pos_y_, amount.y)); + } + if (std::abs(amount.x) > 0.0001f && root_widget) { + root_widget->HandleMessage(WidgetMessage(WidgetMessage::Type::kMouseWheelH, + nullptr, cursor_pos_x_, + cursor_pos_y_, amount.x)); + } + mouse_move_count_++; + + Camera* camera = g_graphics->camera(); + if (camera) { + if (camera->manual()) { + camera->ManualHandleMouseWheel(0.005f * amount.y); + } + } +} + +auto Input::PushSmoothMouseScrollEvent(const Vector2f& velocity, bool momentum) + -> void { + g_game->PushCall([this, velocity, momentum] { + HandleSmoothMouseScroll(velocity, momentum); + }); +} + +auto Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) + -> void { + assert(InGameThread()); + if (IsInputLocked()) { + return; + } + ResetIdleTime(); + + bool handled = false; + Widget* root_widget = g_ui->root_widget(); + if (root_widget) { + handled = root_widget->HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseWheelVelocity, nullptr, + cursor_pos_x_, cursor_pos_y_, velocity.y, momentum)); + root_widget->HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseWheelVelocityH, nullptr, + cursor_pos_x_, cursor_pos_y_, velocity.x, momentum)); + } + last_mouse_move_time_ = GetRealTime(); + mouse_move_count_++; + + Camera* camera = g_graphics->camera(); + if (!handled && camera) { + if (camera->manual()) { + camera->ManualHandleMouseWheel(-0.25f * velocity.y); + } + } +} + +auto Input::PushMouseMotionEvent(const Vector2f& position) -> void { + g_game->PushCall([this, position] { HandleMouseMotion(position); }); +} + +auto Input::HandleMouseMotion(const Vector2f& position) -> void { + assert(g_graphics); + assert(InGameThread()); + ResetIdleTime(); + + float old_cursor_pos_x = cursor_pos_x_; + float old_cursor_pos_y = cursor_pos_y_; + + // Convert normalized view coords to our virtual ones. + cursor_pos_x_ = g_graphics->PixelToVirtualX( + position.x * g_graphics->screen_pixel_width()); + cursor_pos_y_ = g_graphics->PixelToVirtualY( + position.y * g_graphics->screen_pixel_height()); + + last_mouse_move_time_ = GetRealTime(); + mouse_move_count_++; + + bool handled2{}; + + // If we have a touch-input in editing mode, pass along events to it. + // (it usually handles its own events but here we want it to play nice + // with stuff under it by blocking touches, etc) + if (touch_input_ && touch_input_->editing()) { + touch_input_->HandleTouchMoved(reinterpret_cast(1), cursor_pos_x_, + cursor_pos_y_); + } + + // UI interaction. + Widget* root_widget = g_ui->root_widget(); + if (root_widget && !IsInputLocked()) + handled2 = root_widget->HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseMove, nullptr, cursor_pos_x_, + cursor_pos_y_)); + + // Manual camera motion. + Camera* camera = g_graphics->camera(); + if (!handled2 && camera && camera->manual()) { + float move_h = + (cursor_pos_x_ - old_cursor_pos_x) / g_graphics->screen_virtual_width(); + float move_v = + (cursor_pos_y_ - old_cursor_pos_y) / g_graphics->screen_virtual_width(); + camera->ManualHandleMouseMove(move_h, move_v); + } + + g_ui->root_ui()->HandleMouseMotion(cursor_pos_x_, cursor_pos_y_); +} + +auto Input::PushMouseDownEvent(int button, const Vector2f& position) -> void { + g_game->PushCall( + [this, button, position] { HandleMouseDown(button, position); }); +} + +auto Input::HandleMouseDown(int button, const Vector2f& position) -> void { + assert(g_graphics); + assert(InGameThread()); + + if (IsInputLocked()) { + return; + } + + if (g_ui == nullptr || g_ui->screen_root_widget() == nullptr) { + return; + } + + ResetIdleTime(); + + last_mouse_move_time_ = GetRealTime(); + mouse_move_count_++; + + // printf("Mouse down at %f %f\n", position.x, position.y); + + // Convert normalized view coords to our virtual ones. + cursor_pos_x_ = g_graphics->PixelToVirtualX( + position.x * g_graphics->screen_pixel_width()); + cursor_pos_y_ = g_graphics->PixelToVirtualY( + position.y * g_graphics->screen_pixel_height()); + + millisecs_t click_time = GetRealTime(); + bool double_click = (click_time - last_click_time_ <= double_click_time_); + last_click_time_ = click_time; + + bool handled2 = false; + Widget* root_widget = g_ui->root_widget(); + + // If we have a touch-input in editing mode, pass along events to it. + // (it usually handles its own events but here we want it to play nice + // with stuff under it by blocking touches, etc) + if (touch_input_ && touch_input_->editing()) { + handled2 = touch_input_->HandleTouchDown(reinterpret_cast(1), + cursor_pos_x_, cursor_pos_y_); + } + + if (!handled2) { + if (g_ui->root_ui()->HandleMouseButtonDown(cursor_pos_x_, cursor_pos_y_)) { + handled2 = true; + } + } + + if (root_widget && !handled2) { + handled2 = root_widget->HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseDown, nullptr, cursor_pos_x_, + cursor_pos_y_, double_click ? 2 : 1)); + } + + // Manual camera input. + Camera* camera = g_graphics->camera(); + if (!handled2 && camera) { + switch (button) { + case SDL_BUTTON_LEFT: + camera->set_mouse_left_down(true); + break; + case SDL_BUTTON_RIGHT: + camera->set_mouse_right_down(true); + break; + case SDL_BUTTON_MIDDLE: + camera->set_mouse_middle_down(true); + break; + default: + break; + } + camera->UpdateManualMode(); + } +} + +auto Input::PushMouseUpEvent(int button, const Vector2f& position) -> void { + g_game->PushCall( + [this, button, position] { HandleMouseUp(button, position); }); +} + +auto Input::HandleMouseUp(int button, const Vector2f& position) -> void { + assert(InGameThread()); + ResetIdleTime(); + + // Convert normalized view coords to our virtual ones. + cursor_pos_x_ = g_graphics->PixelToVirtualX( + position.x * g_graphics->screen_pixel_width()); + cursor_pos_y_ = g_graphics->PixelToVirtualY( + position.y * g_graphics->screen_pixel_height()); + + bool handled2{}; + + // If we have a touch-input in editing mode, pass along events to it. + // (it usually handles its own events but here we want it to play nice + // with stuff under it by blocking touches, etc) + if (touch_input_ && touch_input_->editing()) { + touch_input_->HandleTouchUp(reinterpret_cast(1), cursor_pos_x_, + cursor_pos_y_); + } + + Widget* root_widget = g_ui->root_widget(); + if (root_widget) + handled2 = root_widget->HandleMessage(WidgetMessage( + WidgetMessage::Type::kMouseUp, nullptr, cursor_pos_x_, cursor_pos_y_)); + Camera* camera = g_graphics->camera(); + if (!handled2 && camera) { + switch (button) { + case SDL_BUTTON_LEFT: + camera->set_mouse_left_down(false); + break; + case SDL_BUTTON_RIGHT: + camera->set_mouse_right_down(false); + break; + case SDL_BUTTON_MIDDLE: + camera->set_mouse_middle_down(false); + break; + default: + break; + } + camera->UpdateManualMode(); + } + g_ui->root_ui()->HandleMouseButtonUp(cursor_pos_x_, cursor_pos_y_); +} + +void Input::PushTouchEvent(const TouchEvent& e) { + g_game->PushCall([e, this] { HandleTouchEvent(e); }); +} + +void Input::HandleTouchEvent(const TouchEvent& e) { + assert(InGameThread()); + assert(g_graphics); + + if (IsInputLocked()) { + return; + } + + ResetIdleTime(); + + // float x = e.x; + // float y = e.y; + + if (g_buildconfig.ostype_ios_tvos()) { + printf("FIXME: update touch handling\n"); + } + + float x = g_graphics->PixelToVirtualX(e.x * g_graphics->screen_pixel_width()); + float y = + g_graphics->PixelToVirtualY(e.y * g_graphics->screen_pixel_height()); + + if (e.overall) { + // Sanity test: if the OS tells us that this is the beginning of an, + // overall multitouch gesture, it should always be winding up as our + // single_touch_. + if (e.type == TouchEvent::Type::kDown && single_touch_ != nullptr) { + BA_LOG_ONCE("Got touch labeled first but will not be our single."); + } + + // Also: if the OS tells us that this is the end of an overall multi-touch + // gesture, it should mean that our single_touch_ has ended or will be. + if ((e.type == TouchEvent::Type::kUp + || e.type == TouchEvent::Type::kCanceled) + && single_touch_ != nullptr && single_touch_ != e.touch) { + BA_LOG_ONCE("Last touch coming up is not single touch!"); + } + } + + // We keep track of one 'single' touch which we pass along as + // mouse events which covers most UI stuff. + if (e.type == TouchEvent::Type::kDown && single_touch_ == nullptr) { + single_touch_ = e.touch; + HandleMouseDown(SDL_BUTTON_LEFT, Vector2f(e.x, e.y)); + } + + if (e.type == TouchEvent::Type::kMoved && e.touch == single_touch_) { + HandleMouseMotion(Vector2f(e.x, e.y)); + } + + // Currently just applying touch-cancel the same as touch-up here; + // perhaps should be smarter in the future. + if ((e.type == TouchEvent::Type::kUp || e.type == TouchEvent::Type::kCanceled) + && (e.touch == single_touch_ || e.overall)) { + single_touch_ = nullptr; + HandleMouseUp(SDL_BUTTON_LEFT, Vector2f(e.x, e.y)); + } + + // If we've got a touch input device, forward events along to it. + if (touch_input_) { + touch_input_->HandleTouchEvent(e.type, e.touch, x, y); + } +} + +void Input::ResetJoyStickHeldButtons() { + for (auto&& i : input_devices_) { + if (i.exists()) { + i->ResetHeldStates(); + } + } +} + +// Send key-ups for any currently-held keys. +void Input::ResetKeyboardHeldKeys() { + assert(InGameThread()); + if (!HeadlessMode()) { + // Synthesize key-ups for all our held keys. + while (!keys_held_.empty()) { + SDL_Keysym k; + memset(&k, 0, sizeof(k)); + k.sym = (SDL_Keycode)(*keys_held_.begin()); + HandleKeyRelease(&k); + } + } +} + +void Input::Draw(FrameDef* frame_def) { + // Draw touch input visual guides. + if (touch_input_) { + touch_input_->Draw(frame_def); + } +} + +auto Input::IsCursorVisible() const -> bool { + assert(InGameThread()); + if (!g_ui) { + return false; + } + ContainerWidget* screen_root_widget = g_ui->screen_root_widget(); + + // Keeps mouse hidden to start with.. + if (mouse_move_count_ < 2) { + return false; + } + bool val; + + // Show our cursor if any dialogs/windows are up or else if its been + // moved very recently. + if (screen_root_widget && screen_root_widget->GetChildCount() > 0) { + val = (GetRealTime() - last_mouse_move_time_ < 5000); + } else { + val = (GetRealTime() - last_mouse_move_time_ < 1000); + } + return val; +} + +// The following was pulled from sdl2 +#if BA_SDL2_BUILD || BA_MINSDL_BUILD + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +static char* UCS4ToUTF8(uint32_t ch, char* dst) { + auto* p = reinterpret_cast(dst); + if (ch <= 0x7F) { + *p = static_cast(ch); + ++dst; + } else if (ch <= 0x7FF) { + p[0] = static_cast(0xC0 | static_cast((ch >> 6) & 0x1F)); + p[1] = static_cast(0x80 | static_cast(ch & 0x3F)); + dst += 2; + } else if (ch <= 0xFFFF) { + p[0] = static_cast(0xE0 | static_cast((ch >> 12) & 0x0F)); + p[1] = static_cast(0x80 | static_cast((ch >> 6) & 0x3F)); + p[2] = static_cast(0x80 | static_cast(ch & 0x3F)); + dst += 3; + } else if (ch <= 0x1FFFFF) { + p[0] = static_cast(0xF0 | static_cast((ch >> 18) & 0x07)); + p[1] = static_cast(0x80 | static_cast((ch >> 12) & 0x3F)); + p[2] = static_cast(0x80 | static_cast((ch >> 6) & 0x3F)); + p[3] = static_cast(0x80 | static_cast(ch & 0x3F)); + dst += 4; + } else if (ch <= 0x3FFFFFF) { + p[0] = static_cast(0xF8 | static_cast((ch >> 24) & 0x03)); + p[1] = static_cast(0x80 | static_cast((ch >> 18) & 0x3F)); + p[2] = static_cast(0x80 | static_cast((ch >> 12) & 0x3F)); + p[3] = static_cast(0x80 | static_cast((ch >> 6) & 0x3F)); + p[4] = static_cast(0x80 | static_cast(ch & 0x3F)); + dst += 5; + } else { + p[0] = static_cast(0xFC | static_cast((ch >> 30) & 0x01)); + p[1] = static_cast(0x80 | static_cast((ch >> 24) & 0x3F)); + p[2] = static_cast(0x80 | static_cast((ch >> 18) & 0x3F)); + p[3] = static_cast(0x80 | static_cast((ch >> 12) & 0x3F)); + p[4] = static_cast(0x80 | static_cast((ch >> 6) & 0x3F)); + p[5] = static_cast(0x80 | static_cast(ch & 0x3F)); + dst += 6; + } + return dst; +} +#pragma clang diagnostic pop + +const char* GetScancodeName(SDL_Scancode scancode) { + const char* name; + if (static_cast(scancode) < SDL_SCANCODE_UNKNOWN + || scancode >= SDL_NUM_SCANCODES) { + BA_LOG_ONCE("GetScancodeName passed invalid scancode " + + std::to_string(static_cast(scancode))); + return ""; + } + + name = scancode_names[scancode]; + if (name) + return name; + else + return ""; +} + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +auto Input::GetKeyName(int keycode) -> std::string { + SDL_Keycode key{keycode}; + static char name[8]; + char* end; + + if (key & SDLK_SCANCODE_MASK) { + return GetScancodeName((SDL_Scancode)(key & ~SDLK_SCANCODE_MASK)); + } + + switch (key) { + case SDLK_RETURN: + return GetScancodeName(SDL_SCANCODE_RETURN); + case SDLK_ESCAPE: + return GetScancodeName(SDL_SCANCODE_ESCAPE); + case SDLK_BACKSPACE: + return GetScancodeName(SDL_SCANCODE_BACKSPACE); + case SDLK_TAB: + return GetScancodeName(SDL_SCANCODE_TAB); + case SDLK_SPACE: + return GetScancodeName(SDL_SCANCODE_SPACE); + case SDLK_DELETE: + return GetScancodeName(SDL_SCANCODE_DELETE); + default: + /* Unaccented letter keys on latin keyboards are normally + labeled in upper case (and probably on others like Greek or + Cyrillic too, so if you happen to know for sure, please + adapt this). */ + if (key >= 'a' && key <= 'z') { + key -= 32; + } + + end = UCS4ToUTF8(static_cast(key), name); + *end = '\0'; + return name; + } +} +#pragma clang diagnostic pop +#endif // BA_SDL2_BUILD || BA_MINSDL_BUILD + +} // namespace ballistica diff --git a/src/ballistica/input/input.h b/src/ballistica/input/input.h new file mode 100644 index 00000000..c58ebd8e --- /dev/null +++ b/src/ballistica/input/input.h @@ -0,0 +1,195 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_INPUT_H_ +#define BALLISTICA_INPUT_INPUT_H_ + +#include +#include +#include +#include +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +/// Class for managing input; owned and used by the game thread. +class Input { + public: + Input(); + virtual ~Input(); + + // Add an input device. Must be called from the game thread; otherwise use + // PushAddInputDeviceCall. + auto AddInputDevice(InputDevice* input, bool standard_message) -> void; + + // Removes a previously-added input-device. Must be called from the + // game thread; otherwise use PushRemoveInputDeviceCall. + auto RemoveInputDevice(InputDevice* input, bool standard_message) -> void; + + // Given a device name and persistent identifier for it, returns a device or + // nullptr note that this can return hidden devices (ones the user has flagged + // as totally-ignored, etc). + auto GetInputDevice(const std::string& name, const std::string& persistent_id) + -> InputDevice*; + + // Return a device by id. + // Note that this can return hidden devices (ones the user has flagged as + // totally-ignored, etc). + auto GetInputDevice(int id) -> InputDevice*; + + // Return all input devices with this name. + auto GetInputDevicesWithName(const std::string& name) + -> std::vector; + + auto Reset() -> void; + auto LockAllInput(bool permanent, const std::string& label) -> void; + auto UnlockAllInput(bool permanent, const std::string& label) -> void; + auto IsInputLocked() const -> bool { + return ((input_lock_count_temp_ > 0) || (input_lock_count_permanent_ > 0)); + } + auto cursor_pos_x() const -> float { return cursor_pos_x_; } + auto cursor_pos_y() const -> float { return cursor_pos_y_; } + + auto IsCursorVisible() const -> bool; + + // Return list of gamepads that are user-visible and able to be configured. + auto GetConfigurableGamePads() -> std::vector; + + // Reset all keyboard keys to a non-held state and deal out associated + // messages - used before switching keyboard focus to a new context + // so that the old one is not stuck with a held key forever. + auto ResetKeyboardHeldKeys() -> void; + + auto GetKeyName(int keycode) -> std::string; + + // Same idea but for joysticks. + auto ResetJoyStickHeldButtons() -> void; + auto ShouldCompletelyIgnoreInputDevice(InputDevice* input_device) -> bool; + auto ApplyAppConfig() -> void; + + auto touch_input() const -> TouchInput* { return touch_input_; } + auto have_non_touch_inputs() const -> bool { return have_non_touch_inputs_; } + auto have_button_using_inputs() const -> bool { + return have_button_using_inputs_; + } + auto have_start_activated_default_button_inputs() const -> bool { + return have_start_activated_default_button_inputs_; + } + auto Draw(FrameDef* frame_def) -> void; + + // Get the total idle time for the system. + // FIXME - should better coordinate this with InputDevice::getLastUsedTime(). + auto GetIdleTime() const -> millisecs_t; + + // Should be called whenever user-input of some form comes through. + auto ResetIdleTime() -> void { last_input_time_ = GetRealTime(); } + + // Should be called regularly to update button repeats, etc. + auto Update() -> void; + + // returns true if more than one non-keyboard device has been active recently + // ..this is used to determine whether we need to have strict menu ownership + // (otherwise menu use would be chaotic with 8 players connected) + auto HaveManyLocalActiveInputDevices() -> bool { + return GetLocalActiveInputDeviceCount() > 1; + } + auto GetLocalActiveInputDeviceCount() -> int; + + // Return true if there are any joysticks with players attached. + // The touch-input uses this to warn the user if it looks like they + // may have accidentally joined the game using a controller touchpad or + // something. + auto HaveControllerWithPlayer() -> bool; + auto HaveRemoteAppController() -> bool; + auto HandleBackPress(bool from_toolbar) -> void; + auto ProcessStressTesting(int player_count) -> void; + auto keyboard_input() const -> KeyboardInput* { return keyboard_input_; } + auto keyboard_input_2() const -> KeyboardInput* { return keyboard_input_2_; } + auto CreateTouchInput() -> void; + + auto PushTextInputEvent(const std::string& text) -> void; + auto PushKeyPressEvent(const SDL_Keysym& keysym) -> void; + auto PushKeyReleaseEvent(const SDL_Keysym& keysym) -> void; + auto PushMouseDownEvent(int button, const Vector2f& position) -> void; + auto PushMouseUpEvent(int button, const Vector2f& position) -> void; + auto PushMouseMotionEvent(const Vector2f& position) -> void; + auto PushSmoothMouseScrollEvent(const Vector2f& velocity, bool momentum) + -> void; + auto PushMouseScrollEvent(const Vector2f& amount) -> void; + auto PushJoystickEvent(const SDL_Event& event, InputDevice* input_device) + -> void; + auto PushAddInputDeviceCall(InputDevice* input_device, bool standard_message) + -> void; + auto PushRemoveInputDeviceCall(InputDevice* input_device, + bool standard_message) -> void; + auto PushTouchEvent(const TouchEvent& touch_event) -> void; + auto PushDestroyKeyboardInputDevices() -> void; + auto PushCreateKeyboardInputDevices() -> void; + + private: + auto UpdateInputDeviceCounts() -> void; + auto GetNewNumberedIdentifier(const std::string& name, + const std::string& identifier) -> int; + auto UpdateEnabledControllerSubsystems() -> void; + auto AnnounceConnects() -> void; + auto AnnounceDisconnects() -> void; + auto HandleKeyPress(const SDL_Keysym* keysym) -> void; + auto HandleKeyRelease(const SDL_Keysym* keysym) -> void; + auto HandleMouseMotion(const Vector2f& position) -> void; + auto HandleMouseDown(int button, const Vector2f& position) -> void; + auto HandleMouseUp(int button, const Vector2f& position) -> void; + auto HandleMouseScroll(const Vector2f& amount) -> void; + auto HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) -> void; + auto HandleJoystickEvent(const SDL_Event& event, InputDevice* input_device) + -> void; + auto HandleTouchEvent(const TouchEvent& e) -> void; + auto ShowStandardInputDeviceConnectedMessage(InputDevice* j) -> void; + auto ShowStandardInputDeviceDisconnectedMessage(InputDevice* j) -> void; + auto PrintLockLabels() -> void; + auto UpdateModKeyStates(const SDL_Keysym* keysym, bool press) -> void; + auto CreateKeyboardInputDevices() -> void; + auto DestroyKeyboardInputDevices() -> void; + int local_active_input_device_count_{}; + millisecs_t last_have_many_local_active_input_devices_check_time_{}; + std::map > reserved_identifiers_; + int max_controller_count_so_far_{}; + std::list newly_connected_controllers_; + std::list newly_disconnected_controllers_; + int connect_print_timer_id_{}; + int disconnect_print_timer_id_{}; + bool have_button_using_inputs_{}; + bool have_start_activated_default_button_inputs_{}; + bool have_non_touch_inputs_{}; + float cursor_pos_x_{}; + float cursor_pos_y_{}; + millisecs_t last_input_time_{}; + millisecs_t last_click_time_{}; + millisecs_t double_click_time_{200}; + millisecs_t last_mouse_move_time_{}; + int mouse_move_count_{}; + std::vector > input_devices_; + KeyboardInput* keyboard_input_ = nullptr; + KeyboardInput* keyboard_input_2_ = nullptr; + TouchInput* touch_input_ = nullptr; + int input_lock_count_temp_ = 0; + int input_lock_count_permanent_ = 0; + std::list input_lock_temp_labels_; + std::list input_unlock_temp_labels_; + std::list input_lock_permanent_labels_; + std::list input_unlock_permanent_labels_; + std::list recent_input_locks_unlocks_; + std::set keys_held_; + millisecs_t last_input_device_count_update_time_ = 0; + millisecs_t last_input_temp_lock_time_ = 0; + bool ignore_mfi_controllers_ = false; + bool ignore_sdl_controllers_ = false; + std::list test_inputs_; + millisecs_t stress_test_time_{}; + millisecs_t stress_test_last_leave_time_{}; + void* single_touch_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_INPUT_H_ diff --git a/src/ballistica/input/remote_app.cc b/src/ballistica/input/remote_app.cc new file mode 100644 index 00000000..23a82b19 --- /dev/null +++ b/src/ballistica/input/remote_app.cc @@ -0,0 +1,547 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/remote_app.h" + +#if BA_OSTYPE_WINDOWS +#include +#pragma comment(lib, "ws2_32.lib") +#else +#include +#include +#include + +#include +#endif + +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/ballistica.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/utils.h" +#include "ballistica/input/input.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/media/media.h" +#include "ballistica/networking/network_reader.h" +#include "ballistica/platform/min_sdl.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +// Just used privately by the remote-server machinery. +enum class RemoteAppServer::RemoteEventType { + kDPadH, + kDPadV, + kPunchPress, + kPunchRelease, + kJumpPress, + kJumpRelease, + kThrowPress, + kThrowRelease, + kBombPress, + kBombRelease, + kMenu, // Old. + kMenuPress, + kMenuRelease, + kHoldPositionPress, + kHoldPositionRelease, + kRunPress, + kRunRelease +}; + +RemoteAppServer::RemoteAppServer() = default; + +RemoteAppServer::~RemoteAppServer() = default; + +void RemoteAppServer::HandleData(int socket, uint8_t* buffer, size_t amt, + struct sockaddr* addr, size_t addr_len) { + if (amt == 0) { + return; + } + switch (buffer[0]) { + case BA_PACKET_REMOTE_GAME_QUERY: { + // Ship them a response packet with our name. + char msg[256]; + std::string name = g_platform->GetDeviceName(); + msg[0] = BA_PACKET_REMOTE_GAME_RESPONSE; + strncpy(msg + 1, name.c_str(), sizeof(msg) - 1); + msg[255] = 0; + size_t msg_len = 1 + strlen(msg + 1); + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, msg, static_cast_check_fit(msg_len), + 0, addr, static_cast(addr_len)); + + // if (result != msg_len) { + // Hmm; ive seen errno 64 (network down) and 65 (package not installed) + // here, but I don't know what we could do in response. Just gonna ignore + // them. + // } + break; + } + case BA_PACKET_REMOTE_ID_REQUEST: { + if (amt < 5 || amt > 127) { + BA_LOG_ONCE( + "Error: received invalid BA_PACKET_REMOTE_ID_REQUEST of length " + + std::to_string(amt)); + break; + } + + // Second byte is protocol version. + int protocol_version = buffer[1]; + + // Make sure we speak the same language. + if (protocol_version != kRemoteAppProtocolVersion) { + uint8_t data[2] = { + BA_PACKET_REMOTE_DISCONNECT, + static_cast_check_fit(RemoteError::kVersionMismatch)}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), sizeof(data), 0, addr, + static_cast(addr_len)); + break; + } + + // Third and fourth bytes are request id. + int16_t request_id; + memcpy(&request_id, buffer + 2, sizeof(request_id)); + + // This is now a protocol-version-request. It used to be an address index + // from the other end so probably will be a value between 1 and 5 or so on + // older builds. + int protocol_request = buffer[4]; + int protocol_response = + protocol_request; // Old default was to return same value. + + // If they sent 50, it means they want protocol v2 (24 bit states). + // In that case we return 100 to say 'ok, we support that version'. + // Note to self (years later): please explain to me why I did this. + bool using_v2 = (protocol_request == 50); + if (using_v2) { + protocol_response = 100; + } + + // Remaining bytes are name (up to 100 bytes). + char name[101]; + assert(amt >= 5); + size_t name_len = amt - 5; + if (name_len > 100) { + name_len = 100; + } + strncpy(name, reinterpret_cast(buffer) + 5, name_len); + name[name_len] = 0; + int client_id = GetClient(request_id, addr, static_cast(addr_len), + name, using_v2); + + // If we've got a slot for this client, tell them what their id is. + if (client_id != -1) { + uint8_t data[3] = {BA_PACKET_REMOTE_ID_RESPONSE, + static_cast(client_id), + static_cast(protocol_response)}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), sizeof(data), 0, addr, + static_cast(addr_len)); + } else { + // No room. + uint8_t data[2] = {BA_PACKET_REMOTE_DISCONNECT, + static_cast_check_fit( + RemoteError::kNotAcceptingConnections)}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), sizeof(data), 0, addr, + static_cast(addr_len)); + } + break; + } + case BA_PACKET_REMOTE_DISCONNECT: { + // They told us they're leaving.. free up their slot. + if (amt == 2 && buffer[1] < kMaxRemoteAppClients) { + int joystickID = buffer[1]; + + // Tell our delegate to kill its local joystick. + RemoteAppClient* client = clients_ + joystickID; + if (clients_[joystickID].in_use) { + // Print 'Billy Bob's iPhone Disconnected'. + char m[256]; + snprintf(m, sizeof(m), "%s", client->display_name); + + // Replace ${CONTROLLER} with it in our message. + std::string s = + g_game->GetResourceString("controllerDisconnectedText"); + Utils::StringReplaceOne(&s, "${CONTROLLER}", m); + g_game->PushScreenMessage(s, Vector3f(1, 1, 1)); + g_game->PushPlaySoundCall(SystemSoundID::kCorkPop); + g_input->PushRemoveInputDeviceCall(client->joystick_, false); + client->joystick_ = nullptr; + client->in_use = false; + client->name[0] = 0; + } + + // Send an ack. + uint8_t data[1] = {BA_PACKET_REMOTE_DISCONNECT_ACK}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), 1, 0, addr, + static_cast(addr_len)); + } + break; + } + case BA_PACKET_REMOTE_STATE2: { + // Has to be at least 4 bytes. + // (msg-type, joystick-id, state-count, starting-state-id) + if (amt < 4) { + break; + } + + uint8_t joystick_id = buffer[1]; + uint8_t state_count = buffer[2]; + uint8_t state_id = buffer[3]; + + // If its not an active joystick, let them know they're not playing + // (this can happen if they time-out but still try to keep talking to us). + if (!clients_[joystick_id].in_use) { + uint8_t data[2] = { + BA_PACKET_REMOTE_DISCONNECT, + static_cast_check_fit(RemoteError::kNotConnected)}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), sizeof(data), 0, addr, + static_cast(addr_len)); + break; + } + + // Each state is 2 bytes. So make sure our length adds up. + if (amt != 4 + state_count * 3) { + BA_LOG_ONCE("Error: Invalid state packet"); + return; + } + RemoteAppClient* client = clients_ + joystick_id; + + // Take note that we heard from them. + client->last_contact_time = GetRealTime(); + + // Ok now iterate. + uint8_t* val = buffer + 4; + for (int i = 0; i < state_count; i++) { + // If we're behind enough, just skip ahead to here + uint8_t diff = state_id - client->next_state_id; + + // Diffs close to 255 are probably just retransmitted states we just + // looked at. + if (diff > 10 && diff < 200) { + client->next_state_id = state_id; + } + + // If this is the next state we're looking for, apply it. + if (client->next_state_id == state_id) { + uint32_t last_state = client->state; + uint32_t state = val[0] + (val[1] << 8u) + (val[2] << 16u); + uint32_t h_raw = (state >> 8u) & 0xFFu; + uint32_t v_raw = (state >> 16u) & 0xFFu; + uint32_t h_raw_last = (last_state >> 8u) & 0xFFu; + uint32_t v_raw_last = (last_state >> 16u) & 0xFFu; + float dpad_h, dpad_v; + dpad_h = -1.0f + 2.0f * (h_raw / 255.0f); + dpad_v = -1.0f + 2.0f * (v_raw / 255.0f); + float last_dpad_h, last_dpad_v; + last_dpad_h = -1.0f + 2.0f * (h_raw_last / 255.0f); + last_dpad_v = -1.0f + 2.0f * (v_raw_last / 255.0f); + + // Process this first since it can affect how other events are + // handled. + if ((last_state & kRemoteStateHoldPosition) + && !(state & kRemoteStateHoldPosition)) { + HandleRemoteEvent(client, RemoteEventType::kHoldPositionRelease); + } else if (!(last_state & kRemoteStateHoldPosition) + && (state & kRemoteStateHoldPosition)) { + HandleRemoteEvent(client, RemoteEventType::kHoldPositionPress); + } + if (dpad_h != last_dpad_h) { + HandleRemoteFloatEvent(client, RemoteEventType::kDPadH, dpad_h); + } + if (dpad_v != last_dpad_v) { + HandleRemoteFloatEvent(client, RemoteEventType::kDPadV, dpad_v); + } + if ((last_state & kRemoteStateBomb) && !(state & kRemoteStateBomb)) { + HandleRemoteEvent(client, RemoteEventType::kBombRelease); + } else if (!(last_state & kRemoteStateBomb) + && (state & kRemoteStateBomb)) { + HandleRemoteEvent(client, RemoteEventType::kBombPress); + } + if ((last_state & kRemoteStateJump) && !(state & kRemoteStateJump)) { + HandleRemoteEvent(client, RemoteEventType::kJumpRelease); + } else if (!(last_state & kRemoteStateJump) + && (state & kRemoteStateJump)) { + HandleRemoteEvent(client, RemoteEventType::kJumpPress); + } + if ((last_state & kRemoteStatePunch) + && !(state & kRemoteStatePunch)) { + HandleRemoteEvent(client, RemoteEventType::kPunchRelease); + } else if (!(last_state & kRemoteStatePunch) + && (state & kRemoteStatePunch)) { + HandleRemoteEvent(client, RemoteEventType::kPunchPress); + } + if ((last_state & kRemoteStateThrow) + && !(state & kRemoteStateThrow)) { + HandleRemoteEvent(client, RemoteEventType::kThrowRelease); + } else if (!(last_state & kRemoteStateThrow) + && (state & kRemoteStateThrow)) { + HandleRemoteEvent(client, RemoteEventType::kThrowPress); + } + if ((last_state & kRemoteStateMenu) && !(state & kRemoteStateMenu)) { + HandleRemoteEvent(client, RemoteEventType::kMenuRelease); + } else if (!(last_state & kRemoteStateMenu) + && (state & kRemoteStateMenu)) { + HandleRemoteEvent(client, RemoteEventType::kMenuPress); + } + if ((last_state & kRemoteStateRun) && !(state & kRemoteStateRun)) { + HandleRemoteEvent(client, RemoteEventType::kRunRelease); + } else if (!(last_state & kRemoteStateRun) + && (state & kRemoteStateRun)) { + HandleRemoteEvent(client, RemoteEventType::kRunPress); + } + client->state = state; + client->next_state_id++; + } + state_id++; + val += 3; + } + + // Ok now send an ack with the state ID we're looking for next. + uint8_t data[2] = {BA_PACKET_REMOTE_STATE_ACK, client->next_state_id}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), 2, 0, addr, + static_cast(addr_len)); + + break; + } + case BA_PACKET_REMOTE_STATE: { + // Has to be at least 4 bytes. + // (msg-type, joystick-id, state-count, starting-state-id) + if (amt < 4) break; + + // This was used on older versions of the remote app; no longer supported. + { + uint8_t data[2] = { + BA_PACKET_REMOTE_DISCONNECT, + static_cast_check_fit(RemoteError::kVersionMismatch)}; + + // This needs to be locked during any sd changes/writes. + std::lock_guard lock(g_network_reader->sd_mutex()); + sendto(socket, reinterpret_cast(data), sizeof(data), 0, addr, + static_cast(addr_len)); + break; + } + } + default: + break; + } +} + +auto RemoteAppServer::GetClient(int request_id, struct sockaddr* addr, + size_t addr_len, const char* name, + bool using_v2) -> int { + // If we're not accepting connections at all, reject 'em. + if (!g_app_globals->remote_server_accepting_connections) { + return -1; + } + + // First see if we have an id for this name. (we no longer care about + // request-id). + for (int i = 0; i < kMaxRemoteAppClients; i++) { + // We now have clients include unique IDs in their name so we simply compare + // to name. + // This allows re-establishing connections and whatnot. + if (strcmp(name, "") != 0 && !strcmp(name, clients_[i].name)) { + // If the request id has changed it means that they rebooted their remote + // or something; lets take note of that. + if (clients_[i].request_id != request_id) { + clients_[i].request_id = request_id; + + // Print 'Billy Bob's iPhone Reconnected'. + char m[256]; + snprintf(m, sizeof(m), "%s", clients_[i].display_name); + + // Replace ${CONTROLLER} with it in our message. + std::string s = g_game->GetResourceString("controllerReconnectedText"); + Utils::StringReplaceOne(&s, "${CONTROLLER}", m); + g_game->PushScreenMessage(s, Vector3f(1, 1, 1)); + g_game->PushPlaySoundCall(SystemSoundID::kGunCock); + } + clients_[i].in_use = true; + return i; + } + } + + // Don't reuse a slot for 5 seconds. + millisecs_t cooldown_time = GetRealTime() - 5000; + + // Ok, not there already.. now look for a non-taken one and return that. + for (int i = 0; i < kMaxRemoteAppClients; i++) { + if (!clients_[i].in_use && clients_[i].last_contact_time < cooldown_time) { + // Ok lets fill out the client. + clients_[i].in_use = true; + clients_[i].next_state_id = 0; + clients_[i].state = 0; + BA_PRECONDITION(addr_len <= sizeof(clients_[i].address)); + memcpy(&clients_[i].address, addr, addr_len); + clients_[i].address_size = addr_len; + strncpy(clients_[i].name, name, sizeof(clients_[i].name)); + clients_[i].name[sizeof(clients_[i].name) - 1] = + 0; // in case we overflowed + + // Display-name is simply name with everything after '#' removed (which is + // only used as a unique ID). + strcpy(clients_[i].display_name, clients_[i].name); // NOLINT + char* c = strchr(clients_[i].display_name, '#'); + if (c) *c = 0; + clients_[i].last_contact_time = GetRealTime(); + clients_[i].request_id = request_id; + char m[256]; + + // Print 'Billy Bob's iPhone Connected' + snprintf(m, sizeof(m), "%s", clients_[i].display_name); + + // Replace ${CONTROLLER} with it in our message. + std::string s = g_game->GetResourceString("controllerConnectedText"); + Utils::StringReplaceOne(&s, "${CONTROLLER}", m); + g_game->PushScreenMessage(s, Vector3f(1, 1, 1)); + g_game->PushPlaySoundCall(SystemSoundID::kGunCock); + std::string utf8 = Utils::GetValidUTF8(clients_[i].display_name, "rsgc1"); + clients_[i].joystick_ = Object::NewDeferred( + -1, // not an sdl joystick + "RemoteApp: " + + utf8, // device name (we now incorporate the name they send us) + false, // don't allow configuring + using_v2); // calibrate in v2; not v1 + clients_[i].joystick_->set_is_remote_app(true); + + // If they name they supplied was <= 10 characters, use it as our default + // character name. + if (Utils::UTF8StringLength(utf8.c_str()) <= 10) { + clients_[i].joystick_->set_custom_default_player_name(utf8); + } + assert(g_game); + g_input->PushAddInputDeviceCall(clients_[i].joystick_, false); + return i; + } + } + // Sorry no room. + return -1; +} + +void RemoteAppServer::HandleRemoteEvent(RemoteAppClient* client, + RemoteEventType b) { + // Ok we got some data from the remote. + // All we have to do is translate it into an SDL event and feed it to our + // manual joystick we made. + SDL_Event e{}; + bool send = true; + switch (b) { + case RemoteEventType::kBombPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 2; + break; + case RemoteEventType::kBombRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 2; + break; + + // Could actually call the menu func directly, + // but it should be fine to just emulate it via the button-press. + case RemoteEventType::kMenu: + case RemoteEventType::kMenuPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 5; + break; + case RemoteEventType::kMenuRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 5; + break; + case RemoteEventType::kJumpPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 0; + break; + case RemoteEventType::kJumpRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 0; + break; + case RemoteEventType::kThrowPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 3; + break; + case RemoteEventType::kThrowRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 3; + break; + case RemoteEventType::kPunchPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 1; + break; + case RemoteEventType::kPunchRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 1; + break; + case RemoteEventType::kHoldPositionPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 25; + break; + case RemoteEventType::kHoldPositionRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 25; + break; + case RemoteEventType::kRunPress: + e.type = SDL_JOYBUTTONDOWN; + e.jbutton.button = 64; + break; + case RemoteEventType::kRunRelease: + e.type = SDL_JOYBUTTONUP; + e.jbutton.button = 64; + break; + + default: + send = false; + break; + } + if (send) { + assert(g_game); + g_input->PushJoystickEvent(e, client->joystick_); + } +} + +void RemoteAppServer::HandleRemoteFloatEvent(RemoteAppClient* client, + RemoteEventType b, float val) { + SDL_Event e{}; + bool send = true; + switch (b) { + case RemoteEventType::kDPadH: + e.type = SDL_JOYAXISMOTION; + e.jaxis.axis = 0; + e.jaxis.value = static_cast(32767 * val); + break; + case RemoteEventType::kDPadV: + e.type = SDL_JOYAXISMOTION; + e.jaxis.axis = 1; + e.jaxis.value = static_cast(32767 * val); + break; + default: + send = false; + break; + } + if (send) { + assert(g_game); + g_input->PushJoystickEvent(e, client->joystick_); + } +} + +} // namespace ballistica diff --git a/src/ballistica/input/remote_app.h b/src/ballistica/input/remote_app.h new file mode 100644 index 00000000..62a48625 --- /dev/null +++ b/src/ballistica/input/remote_app.h @@ -0,0 +1,67 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_REMOTE_APP_H_ +#define BALLISTICA_INPUT_REMOTE_APP_H_ + +#include "ballistica/input/device/joystick.h" +#include "ballistica/networking/networking.h" +#include "ballistica/networking/networking_sys.h" + +namespace ballistica { + +constexpr int kRemoteAppProtocolVersion = 121; +constexpr int kMaxRemoteAppClients = 24; + +enum class RemoteError { + kVersionMismatch, + kGameShuttingDown, + kNotAcceptingConnections, + kNotConnected +}; + +enum RemoteState { + kRemoteStateMenu = 1u << 0u, + kRemoteStateJump = 1u << 1u, + kRemoteStatePunch = 1u << 2u, + kRemoteStateThrow = 1u << 3u, + kRemoteStateBomb = 1u << 4u, + kRemoteStateRun = 1u << 5u, + kRemoteStateFly = 1u << 6u, + kRemoteStateHoldPosition = 1u << 7u, + // Second byte is d-pad h-value and third byte is d-pad v-value. +}; + +class RemoteAppServer { + public: + RemoteAppServer(); + ~RemoteAppServer(); + + // Feed the remote-server with data coming in to a listening udp socket. + void HandleData(int sd, uint8_t* data, size_t data_size, + struct sockaddr* from, size_t from_size); + + private: + auto GetClient(int request_id, struct sockaddr* addr, size_t addr_len, + const char* name, bool using_v2) -> int; + struct RemoteAppClient { + bool in_use{}; + int request_id{}; + char name[101]{}; + char display_name[101]{}; + struct sockaddr_storage address {}; + size_t address_size{}; + millisecs_t last_contact_time{}; + uint8_t next_state_id{}; + uint32_t state{}; + Joystick* joystick_{}; + }; + RemoteAppClient clients_[kMaxRemoteAppClients]{}; + enum class RemoteEventType; + void HandleRemoteEvent(RemoteAppClient* client, RemoteEventType msg); + void HandleRemoteFloatEvent(RemoteAppClient* client, RemoteEventType msg, + float val); +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_REMOTE_APP_H_ diff --git a/src/ballistica/input/std_input_module.cc b/src/ballistica/input/std_input_module.cc new file mode 100644 index 00000000..19ac6e39 --- /dev/null +++ b/src/ballistica/input/std_input_module.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/input/std_input_module.h" + +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/game.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +StdInputModule::StdInputModule(Thread* thread) : Module("stdin", thread) { + assert(g_std_input_module == nullptr); + g_std_input_module = this; +} + +StdInputModule::~StdInputModule() = default; + +void StdInputModule::PushBeginReadCall() { + PushCall([this] { + bool stdin_is_terminal = IsStdinATerminal(); + + while (true) { + // Print a prompt if we're a tty. + // We send this to the game thread so it happens AFTER the + // results of the last script-command message we may have just sent. + if (stdin_is_terminal) { + g_game->PushCall([] { + if (!g_app_globals->shutting_down) { + printf(">>> "); + fflush(stdout); + } + }); + } + + // Was using getline, but switched to + // new fgets based approach (more portable). + // Ideally at some point we can wire up to the Python api to get behavior + // more like the actual Python command line. + char buffer[4096]; + char* val = fgets(buffer, sizeof(buffer), stdin); + if (val) { + int last_char = static_cast(strlen(buffer) - 1); + + // Clip off our last char if its a newline (just to keep things tidier). + if (last_char >= 0 && buffer[last_char] == '\n') { + buffer[last_char] = 0; + } + g_game->PushStdinScriptCommand(buffer); + } else { + // At the moment we bail on any read error. + if (feof(stdin)) { + if (stdin_is_terminal) { + // Ok this is strange: on windows consoles, it seems that Ctrl-C in + // a terminal immediately closes our stdin even if we catch the + // interrupt, and then our python interrupt handler runs a moment + // later. This means we wind up telling the user that EOF was + // reached and they should Ctrl-C to quit right after they've hit + // Ctrl-C to quit. To hopefully avoid this, let's hold off on the + // print for a second and see if a shutdown has begun first. + // (or, more likely, just never print because the app has exited). + if (g_buildconfig.windows_console_build()) { + Platform::SleepMS(250); + } + if (!g_app_globals->shutting_down) { + printf("Stdin EOF reached. Use Ctrl-C to quit.\n"); + fflush(stdout); + } + } + } else { + Log("StdInputModule got non-eof error reading stdin: " + + std::to_string(ferror(stdin))); + } + break; + } + } + }); +} + +} // namespace ballistica diff --git a/src/ballistica/input/std_input_module.h b/src/ballistica/input/std_input_module.h new file mode 100644 index 00000000..74a1e66d --- /dev/null +++ b/src/ballistica/input/std_input_module.h @@ -0,0 +1,19 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_INPUT_STD_INPUT_MODULE_H_ +#define BALLISTICA_INPUT_STD_INPUT_MODULE_H_ + +#include "ballistica/core/module.h" + +namespace ballistica { + +class StdInputModule : public Module { + public: + explicit StdInputModule(Thread* thread); + ~StdInputModule() override; + void PushBeginReadCall(); +}; + +} // namespace ballistica + +#endif // BALLISTICA_INPUT_STD_INPUT_MODULE_H_ diff --git a/src/ballistica/math/matrix44f.cc b/src/ballistica/math/matrix44f.cc new file mode 100644 index 00000000..fcdb3e10 --- /dev/null +++ b/src/ballistica/math/matrix44f.cc @@ -0,0 +1,340 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/math/matrix44f.h" + +namespace ballistica { + +auto Matrix44fRotate(const Vector3f& axis, float angle) -> Matrix44f { + // Page 466, Graphics Gems + + Matrix44f rotate{kMatrix44fIdentity}; + + float s = sinf(-angle * kPiDeg); + float c = cosf(-angle * kPiDeg); + float t = 1 - c; + + Vector3f ax = axis / sqrtf(axis.LengthSquared()); + + float x = ax.x; + float y = ax.y; + float z = ax.z; + + rotate.set(0, 0, t * x * x + c); + rotate.set(1, 0, t * y * x + s * z); + rotate.set(2, 0, t * z * x - s * y); + + rotate.set(0, 1, t * x * y - s * z); + rotate.set(1, 1, t * y * y + c); + rotate.set(2, 1, t * z * y + s * x); + + rotate.set(0, 2, t * x * z + s * y); + rotate.set(1, 2, t * y * z - s * x); + rotate.set(2, 2, t * z * z + c); + + return rotate; +} + +auto Matrix44fRotate(float azimuth, float elevation) -> Matrix44f { + Matrix44f rotate{kMatrix44fIdentity}; + + float ca = cosf(azimuth * kPiDeg); + float sa = sinf(azimuth * kPiDeg); + float cb = cosf(elevation * kPiDeg); + float sb = sinf(elevation * kPiDeg); + + rotate.set(0, 0, cb); + rotate.set(1, 0, 0); + rotate.set(2, 0, -sb); + + rotate.set(0, 1, -sa * sb); + rotate.set(1, 1, ca); + rotate.set(2, 1, -sa * cb); + + rotate.set(0, 2, ca * sb); + rotate.set(1, 2, sa); + rotate.set(2, 2, ca * cb); + + return rotate; +} + +auto Matrix44fOrient(const Vector3f& x, const Vector3f& y, const Vector3f& z) + -> Matrix44f { + Matrix44f orient{kMatrix44fIdentity}; + + orient.set(0, 0, x.x); + orient.set(0, 1, x.y); + orient.set(0, 2, x.z); + + orient.set(1, 0, y.x); + orient.set(1, 1, y.y); + orient.set(1, 2, y.z); + + orient.set(2, 0, z.x); + orient.set(2, 1, z.y); + orient.set(2, 2, z.z); + + return orient; +} + +auto Matrix44fOrient(const Vector3f& direction, const Vector3f& up) + -> Matrix44f { + assert(direction.LengthSquared() > 0.0f); + assert(up.LengthSquared() > 0.0f); + + Vector3f d(direction); + d.Normalize(); + + Vector3f u(up); + u.Normalize(); + + return Matrix44fOrient(Vector3f::Cross(u, d), u, d); +} + +auto Matrix44fFrustum(float left, float right, float bottom, float top, + float nearval, float farval) -> Matrix44f { + float m_persp[16] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, -1, 0, 0, 0, 0}; + m_persp[0] = (2.0f * nearval) / (right - left); + m_persp[5] = (2.0f * nearval) / (top - bottom); + m_persp[10] = -(farval + nearval) / (farval - nearval); + m_persp[8] = -(right + left) / (right - left); + m_persp[9] = (top + bottom) / (top - bottom); + m_persp[10] = -(farval + nearval) / (farval - nearval); + m_persp[14] = -2 * farval * nearval / (farval - nearval); + return Matrix44f(m_persp); +} + +auto Matrix44f::Transpose() const -> Matrix44f { + Matrix44f tmp; // NOLINT: uninitialized on purpose. + for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { + tmp.set(j, i, get(i, j)); + } + } + return tmp; +} + +// +// From Mesa-2.2\src\glu\project.c +// + +// +// Compute the inverse of a 4x4 matrix. Contributed by scotter@lafn.org +// + +static void InvertMatrixGeneral(const float* mat, float* out) { +/* NB. OpenGL Matrices are COLUMN major. */ +#define MAT(m, r, c) (mat)[(c)*4 + (r)] + +/* Here's some shorthand converting standard (row,column) to index. */ +#define m11 MAT(mat, 0, 0) +#define m12 MAT(mat, 0, 1) +#define m13 MAT(mat, 0, 2) +#define m14 MAT(mat, 0, 3) +#define m21 MAT(mat, 1, 0) +#define m22 MAT(mat, 1, 1) +#define m23 MAT(mat, 1, 2) +#define m24 MAT(mat, 1, 3) +#define m31 MAT(mat, 2, 0) +#define m32 MAT(mat, 2, 1) +#define m33 MAT(mat, 2, 2) +#define m34 MAT(mat, 2, 3) +#define m41 MAT(mat, 3, 0) +#define m42 MAT(mat, 3, 1) +#define m43 MAT(mat, 3, 2) +#define m44 MAT(mat, 3, 3) + + float det; + float d12, d13, d23, d24, d34, d41; + float tmp[16]; /* Allow out == in. */ + + /* Inverse = adjoint / det. (See linear algebra texts.)*/ + + /* pre-compute 2x2 dets for last two rows when computing */ + /* cofnodes of first two rows. */ + d12 = (m31 * m42 - m41 * m32); + d13 = (m31 * m43 - m41 * m33); + d23 = (m32 * m43 - m42 * m33); + d24 = (m32 * m44 - m42 * m34); + d34 = (m33 * m44 - m43 * m34); + d41 = (m34 * m41 - m44 * m31); + + tmp[0] = (m22 * d34 - m23 * d24 + m24 * d23); + tmp[1] = -(m21 * d34 + m23 * d41 + m24 * d13); + tmp[2] = (m21 * d24 + m22 * d41 + m24 * d12); + tmp[3] = -(m21 * d23 - m22 * d13 + m23 * d12); + + /* Compute determinant as early as possible using these cofnodes. */ + det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2] + m14 * tmp[3]; + + /* Run singularity test. */ + if (det == 0.0f) { + memcpy(out, kMatrix44fIdentity.m, 16 * sizeof(float)); + } else { + float invDet = 1.0f / det; + /* Compute rest of inverse. */ + tmp[0] *= invDet; + tmp[1] *= invDet; + tmp[2] *= invDet; + tmp[3] *= invDet; + + tmp[4] = -(m12 * d34 - m13 * d24 + m14 * d23) * invDet; + tmp[5] = (m11 * d34 + m13 * d41 + m14 * d13) * invDet; + tmp[6] = -(m11 * d24 + m12 * d41 + m14 * d12) * invDet; + tmp[7] = (m11 * d23 - m12 * d13 + m13 * d12) * invDet; + + /* Pre-compute 2x2 dets for first two rows when computing */ + /* cofnodes of last two rows. */ + d12 = m11 * m22 - m21 * m12; + d13 = m11 * m23 - m21 * m13; + d23 = m12 * m23 - m22 * m13; + d24 = m12 * m24 - m22 * m14; + d34 = m13 * m24 - m23 * m14; + d41 = m14 * m21 - m24 * m11; + + tmp[8] = (m42 * d34 - m43 * d24 + m44 * d23) * invDet; + tmp[9] = -(m41 * d34 + m43 * d41 + m44 * d13) * invDet; + tmp[10] = (m41 * d24 + m42 * d41 + m44 * d12) * invDet; + tmp[11] = -(m41 * d23 - m42 * d13 + m43 * d12) * invDet; + tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23) * invDet; + tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13) * invDet; + tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12) * invDet; + tmp[15] = (m31 * d23 - m32 * d13 + m33 * d12) * invDet; + + memcpy(out, tmp, 16 * sizeof(float)); + } + +#undef m11 +#undef m12 +#undef m13 +#undef m14 +#undef m21 +#undef m22 +#undef m23 +#undef m24 +#undef m31 +#undef m32 +#undef m33 +#undef m34 +#undef m41 +#undef m42 +#undef m43 +#undef m44 +#undef MAT +} + +// +// Invert matrix mat. This algorithm contributed by Stephane Rehel +// +// + +static void InvertMatrix(const float* mat, float* out) { +/* NB. OpenGL Matrices are COLUMN major. */ +#define MAT(mat, r, c) (mat)[(c)*4 + (r)] + +/* Here's some shorthand converting standard (row,column) to index. */ +#define m11 MAT(mat, 0, 0) +#define m12 MAT(mat, 0, 1) +#define m13 MAT(mat, 0, 2) +#define m14 MAT(mat, 0, 3) +#define m21 MAT(mat, 1, 0) +#define m22 MAT(mat, 1, 1) +#define m23 MAT(mat, 1, 2) +#define m24 MAT(mat, 1, 3) +#define m31 MAT(mat, 2, 0) +#define m32 MAT(mat, 2, 1) +#define m33 MAT(mat, 2, 2) +#define m34 MAT(mat, 2, 3) +#define m41 MAT(mat, 3, 0) +#define m42 MAT(mat, 3, 1) +#define m43 MAT(mat, 3, 2) +#define m44 MAT(mat, 3, 3) + + float det; + float tmp[16]; /* Allow out == in. */ + + if (m41 != 0.f || m42 != 0.f || m43 != 0.f || m44 != 1.f) { + InvertMatrixGeneral(mat, out); + return; + } + + /* Inverse = adjoint / det. (See linear algebra texts.)*/ + + tmp[0] = m22 * m33 - m23 * m32; + tmp[1] = m23 * m31 - m21 * m33; + tmp[2] = m21 * m32 - m22 * m31; + + /* Compute determinant as early as possible using these cofnodes. */ + det = m11 * tmp[0] + m12 * tmp[1] + m13 * tmp[2]; + + /* Run singularity test. */ + if (det == 0.0f) { + memcpy(out, kMatrix44fIdentity.m, 16 * sizeof(float)); + } else { + float d12, d13, d23, d24, d34, d41; + float im11, im12, im13, im14; + + det = 1.f / det; + + /* Compute rest of inverse. */ + tmp[0] *= det; + tmp[1] *= det; + tmp[2] *= det; + tmp[3] = 0.f; + + im11 = m11 * det; + im12 = m12 * det; + im13 = m13 * det; + im14 = m14 * det; + tmp[4] = im13 * m32 - im12 * m33; + tmp[5] = im11 * m33 - im13 * m31; + tmp[6] = im12 * m31 - im11 * m32; + tmp[7] = 0.f; + + /* Pre-compute 2x2 dets for first two rows when computing */ + /* cofnodes of last two rows. */ + d12 = im11 * m22 - m21 * im12; + d13 = im11 * m23 - m21 * im13; + d23 = im12 * m23 - m22 * im13; + d24 = im12 * m24 - m22 * im14; + d34 = im13 * m24 - m23 * im14; + d41 = im14 * m21 - m24 * im11; + + tmp[8] = d23; + tmp[9] = -d13; + tmp[10] = d12; + tmp[11] = 0.f; + + tmp[12] = -(m32 * d34 - m33 * d24 + m34 * d23); + tmp[13] = (m31 * d34 + m33 * d41 + m34 * d13); + tmp[14] = -(m31 * d24 + m32 * d41 + m34 * d12); + tmp[15] = 1.f; + + memcpy(out, tmp, 16 * sizeof(float)); + } + +#undef m11 +#undef m12 +#undef m13 +#undef m14 +#undef m21 +#undef m22 +#undef m23 +#undef m24 +#undef m31 +#undef m32 +#undef m33 +#undef m34 +#undef m41 +#undef m42 +#undef m43 +#undef m44 +#undef MAT +} + +auto Matrix44f::Inverse() const -> Matrix44f { + Matrix44f inv; // NOLINT: uninitialized on purpose + InvertMatrix(m, inv.m); + return inv; +} + +} // namespace ballistica diff --git a/src/ballistica/math/matrix44f.h b/src/ballistica/math/matrix44f.h new file mode 100644 index 00000000..b90d2f2e --- /dev/null +++ b/src/ballistica/math/matrix44f.h @@ -0,0 +1,201 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_MATRIX44F_H_ +#define BALLISTICA_MATH_MATRIX44F_H_ + +#include // for memcpy + +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +class Matrix44f { + public: + // Stop linter complaints about uninitialized members. + // (It seems our union might be confusing it, and in some cases + // we want to leave things uninited). +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-use-equals-default" +#pragma ide diagnostic ignored "cppcoreguidelines-pro-type-member-init" + + // Default constructor (leaves uninitialized) + Matrix44f() = default; + + Matrix44f(float m00, float m01, float m02, float m03, float m10, float m11, + float m12, float m13, float m20, float m21, float m22, float m23, + float m30, float m31, float m32, float m33) + : m00(m00), + m01(m01), + m02(m02), + m03(m03), + m10(m10), + m11(m11), + m12(m12), + m13(m13), + m20(m20), + m21(m21), + m22(m22), + m23(m23), + m30(m30), + m31(m31), + m32(m32), + m33(m33) {} + + // Construct from array. + explicit Matrix44f(const float* matrix) { memcpy(m, matrix, sizeof(m)); } + + // Construct from array. + explicit Matrix44f(const double* matrix) { + float* i = m; + const double* j = matrix; + for (int k = 0; k < 16; i++, j++, k++) { + *i = static_cast(*j); + } + } + +#pragma clang diagnostic pop + + // Matrix multiplication. + auto operator*(const Matrix44f& other) const -> Matrix44f { + Matrix44f prod; // NOLINT: uninitialized on purpose. + for (int c = 0; c < 4; c++) { + for (int r = 0; r < 4; r++) { + prod.set(c, r, + get(c, 0) * other.get(0, r) + get(c, 1) * other.get(1, r) + + get(c, 2) * other.get(2, r) + + get(c, 3) * other.get(3, r)); + } + } + return prod; + } + + auto tx() const -> float { return m[12]; } + auto ty() const -> float { return m[13]; } + auto tz() const -> float { return m[14]; } + + void set_tx(float v) { m[12] = v; } + void set_ty(float v) { m[13] = v; } + void set_tz(float v) { m[14] = v; } + + auto GetTranslate() const -> Vector3f { return {tx(), ty(), tz()}; } + + auto LocalXAxis() const -> Vector3f { return {m[0], m[1], m[2]}; } + auto LocalYAxis() const -> Vector3f { return {m[4], m[5], m[6]}; } + auto LocalZAxis() const -> Vector3f { return {m[8], m[9], m[10]}; } + + // In-place matrix multiplication. + auto operator*=(const Matrix44f& other) -> Matrix44f& { + return (*this) = (*this) * other; + } + + // Matrix transformation of 3D vector. + auto operator*(const Vector3f& vec) const -> Vector3f { + float prod[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + for (int r = 0; r < 4; r++) { + for (int c = 0; c < 3; c++) prod[r] += vec.v[c] * get(c, r); + prod[r] += get(3, r); + } + float div = 1.0f / prod[3]; + return {prod[0] * div, prod[1] * div, prod[2] * div}; + } + + // Rotate/scale a 3d vector. + auto TransformAsNormal(const Vector3f& val) const -> Vector3f { + // There's probably a smarter way to do this via 3x3 matrices?.. + Matrix44f m2{*this}; + m2.set_tx(0); + m2.set_ty(0); + m2.set_tz(0); + return m2 * val; + } + + // Equality operator. + auto operator==(const Matrix44f& other) const -> bool { + return !memcmp(m, other.m, sizeof(m)); + } + + // Not-equal operator. + auto operator!=(const Matrix44f& other) const -> bool { + return memcmp(m, other.m, sizeof(m)) != 0; + } + + // Calculate matrix inverse. + auto Inverse() const -> Matrix44f; + + // Calculate matrix transpose. + auto Transpose() const -> Matrix44f; + + union { + struct { + float m00, m10, m20, m30; + float m01, m11, m21, m31; + float m02, m12, m22, m32; + float m03, m13, m23, m33; + }; + float m[16]; + }; + + void set(const int col, const int row, const float val) { + m[col * 4 + row] = val; + } + + auto get(const int col, const int row) const -> float { + return m[col * 4 + row]; + } + + auto element(const int col, const int row) -> float& { + return m[col * 4 + row]; + } +}; + +const Matrix44f kMatrix44fIdentity{1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f}; + +inline auto Matrix44fTranslate(const Vector3f& trans) -> Matrix44f { + Matrix44f translate{kMatrix44fIdentity}; + translate.set(3, 0, trans.v[0]); + translate.set(3, 1, trans.v[1]); + translate.set(3, 2, trans.v[2]); + return translate; +} + +inline auto Matrix44fTranslate(const float x, const float y, const float z) + -> Matrix44f { + Matrix44f translate{kMatrix44fIdentity}; + translate.set(3, 0, x); + translate.set(3, 1, y); + translate.set(3, 2, z); + return translate; +} + +inline auto Matrix44fScale(const float sf) -> Matrix44f { + Matrix44f mat{kMatrix44fIdentity}; + mat.set(0, 0, sf); + mat.set(1, 1, sf); + mat.set(2, 2, sf); + return mat; +} + +inline auto Matrix44fScale(const Vector3f& sf) -> Matrix44f { + Matrix44f scale{kMatrix44fIdentity}; + scale.set(0, 0, sf.v[0]); + scale.set(1, 1, sf.v[1]); + scale.set(2, 2, sf.v[2]); + return scale; +} + +auto Matrix44fRotate(const Vector3f& axis, float angle) -> Matrix44f; +auto Matrix44fRotate(float azimuth, float elevation) -> Matrix44f; +auto Matrix44fOrient(const Vector3f& x, const Vector3f& y, const Vector3f& z) + -> Matrix44f; + +// Note: direction and up need to be perpendicular and normalized here. +auto Matrix44fOrient(const Vector3f& direction, const Vector3f& up) + -> Matrix44f; +auto Matrix44fFrustum(float left, float right, float bottom, float top, + float near, float far) -> Matrix44f; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_MATRIX44F_H_ diff --git a/src/ballistica/math/point2d.h b/src/ballistica/math/point2d.h new file mode 100644 index 00000000..4a0cacb4 --- /dev/null +++ b/src/ballistica/math/point2d.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_POINT2D_H_ +#define BALLISTICA_MATH_POINT2D_H_ + +namespace ballistica { + +// 2d point; pretty barebones at the moment.. +struct Point2D { + float x, y; + Point2D() : x(0), y(0) {} + Point2D(float x_in, float y_in) : x(x_in), y(y_in) {} +}; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_POINT2D_H_ diff --git a/src/ballistica/math/random.cc b/src/ballistica/math/random.cc new file mode 100644 index 00000000..5f9e531b --- /dev/null +++ b/src/ballistica/math/random.cc @@ -0,0 +1,544 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/math/random.h" + +#include +#include +#include +#include + +namespace ballistica { + +#define RAND_RANGE(min, max) \ + (min) + (static_cast(rand()) / RAND_MAX) * ((max) - (min)) // NOLINT + +class SmoothGen1D { + public: + SmoothGen1D() = default; + ~SmoothGen1D() = default; + auto GetX(int index) -> float { + Expand(static_cast(index)); + return vals_x[index]; + } + + private: + void Expand(uint32_t index) { + if (index >= vals_x.size()) { + if (vals_x.empty()) { + float initial_x = RAND_RANGE(0, 1); + root = std::make_unique(0, 1, initial_x); + vals_x.push_back(initial_x); + } + for (auto i = static_cast(vals_x.size()); i <= index; i++) { + float x; + root->GetNewValue(&x); + vals_x.push_back(x); + } + } + } + + class Node { + public: + Node(float min_x_in, float max_x_in, float first_val_x) + : min_x(min_x_in), max_x(max_x_in) { + // Store our initial value in the right section. + assert(first_val_x >= min_x && first_val_x <= max_x); + + float mid_x = min_x + (max_x - min_x) * 0.5f; + + Section q; + if (first_val_x < mid_x) { + q = kx; + } else { + q = kX; + } + + initial_x[q] = first_val_x; + int stored = 0; + for (int i = 0; i < 2; i++) { + if (i != q) { + sections[stored] = (Section)i; + stored++; + } + } + val_count = 1; + } + ~Node() = default; + void GetNewValue(float* x) { + if (val_count % 2 == 0) ResetSections(); + Section q = PullRandomSection(); + assert(val_count != 0); + + // We gen the rest of our first 2 values ourself. + if (val_count < 2) { + switch (q) { + case kx: + (*x) = initial_x[q] = + RAND_RANGE(min_x, min_x + (max_x - min_x) * 0.5f); + break; + case kX: + (*x) = initial_x[q] = + RAND_RANGE(min_x + (max_x - min_x) * 0.5f, max_x); + } + } else { + if (val_count == 2) { + // Make child nodes and feed them their initial values. + float mid_x = min_x + (max_x - min_x) * 0.5f; + children[kx] = std::make_unique(min_x, mid_x, initial_x[kx]); + children[kX] = std::make_unique(mid_x, max_x, initial_x[kX]); + } + + // After this point we let our children do the work. + children[q]->GetNewValue(x); + } + val_count++; + } + + private: + enum Section { kx, kX }; + + std::unique_ptr children[2]; + + // Pull a section and remove it from our list. + auto PullRandomSection() -> Section { + int remaining_sections = 2 - val_count % 2; + int q_picked = rand() % remaining_sections; // NOLINT + Section q_val = sections[q_picked]; + int pos_new = 0; + for (int pos_old = 0; pos_old < remaining_sections; pos_old++) { + if (pos_old != q_picked) { + sections[pos_new] = sections[pos_old]; + pos_new++; + } + } + return q_val; + } + void ResetSections() { + sections[0] = kx; + sections[1] = kX; + } + Section sections[2]{}; + float initial_x[2]{}; + float min_x, max_x; + int val_count; + }; + std::unique_ptr root; + std::vector vals_x; +}; + +class SmoothGen2D { + public: + SmoothGen2D() = default; + ~SmoothGen2D() = default; + auto GetX(int index) -> float { + Expand(static_cast(index)); + return vals_x[index]; + } + auto GetY(int index) -> float { + Expand(static_cast(index)); + return vals_y[index]; + } + + private: + void Expand(uint32_t index) { + if (index >= vals_x.size()) { + if (vals_x.empty()) { + float initial_x = RAND_RANGE(0, 1); + float initial_y = RAND_RANGE(0, 1); + root = std::make_unique(0, 0, 1, 1, initial_x, initial_y); + vals_x.push_back(initial_x); + vals_y.push_back(initial_y); + } + for (auto i = static_cast(vals_x.size()); i <= index; i++) { + float x, y; + root->GetNewValue(&x, &y); + vals_x.push_back(x); + vals_y.push_back(y); + } + } + } + + class Node { + public: + Node(float min_x_in, float min_y_in, float max_x_in, float max_y_in, + float first_val_x, float first_val_y) + : min_x(min_x_in), max_x(max_x_in), min_y(min_y_in), max_y(max_y_in) { + // Store our initial value in the right section. + assert(first_val_x >= min_x && first_val_x <= max_x); + assert(first_val_y >= min_y && first_val_y <= max_y); + + float mid_x = min_x + (max_x - min_x) * 0.5f; + float mid_y = min_y + (max_y - min_y) * 0.5f; + + Section q; + if (first_val_x < mid_x) { + if (first_val_y < mid_y) { + q = kxy; + } else { + q = kxY; + } + } else { + if (first_val_y < mid_y) { + q = kXy; + } else { + q = kXY; + } + } + initial_x[q] = first_val_x; + initial_y[q] = first_val_y; + int stored = 0; + for (int i = 0; i < 4; i++) { + if (i != q) { + sections[stored] = (Section)i; + stored++; + } + } + val_count = 1; + } + ~Node() = default; + void GetNewValue(float* x, float* y) { + if (val_count % 4 == 0) ResetSections(); + Section q = PullRandomSection(); + + assert(val_count != 0); + + // We gen the rest of our first 4 values ourself. + if (val_count < 4) { + switch (q) { + case kxy: + case kXy: + (*y) = initial_y[q] = + RAND_RANGE(min_y, min_y + (max_y - min_y) * 0.5f); + break; + case kxY: + case kXY: + (*y) = initial_y[q] = + RAND_RANGE(min_y + (max_y - min_y) * 0.5f, max_y); + } + switch (q) { + case kxy: + case kxY: + (*x) = initial_x[q] = + RAND_RANGE(min_x, min_x + (max_x - min_x) * 0.5f); + break; + case kXy: + case kXY: + (*x) = initial_x[q] = + RAND_RANGE(min_x + (max_x - min_x) * 0.5f, max_x); + } + } else { + if (val_count == 4) { + // Make child nodes and feed them their initial values. + float mid_x = min_x + (max_x - min_x) * 0.5f; + float mid_y = min_y + (max_y - min_y) * 0.5f; + children[kxy] = std::make_unique( + min_x, min_y, mid_x, mid_y, initial_x[kxy], initial_y[kxy]); + children[kXy] = std::make_unique( + mid_x, min_y, max_x, mid_y, initial_x[kXy], initial_y[kXy]); + children[kXY] = std::make_unique( + mid_x, mid_y, max_x, max_y, initial_x[kXY], initial_y[kXY]); + children[kxY] = std::make_unique( + min_x, mid_y, mid_x, max_y, initial_x[kxY], initial_y[kxY]); + } + + // After this point we let our children do the work. + children[q]->GetNewValue(x, y); + } + val_count++; + } + + private: + enum Section { kxy, kXy, kxY, kXY }; + + std::unique_ptr children[4]; + + // Pull a section and remove it from our list. + auto PullRandomSection() -> Section { + int remaining_sections = 4 - val_count % 4; + int q_picked = rand() % remaining_sections; // NOLINT + Section q_val = sections[q_picked]; + int pos_new = 0; + for (int pos_old = 0; pos_old < remaining_sections; pos_old++) { + if (pos_old != q_picked) { + sections[pos_new] = sections[pos_old]; + pos_new++; + } + } + return q_val; + } + void ResetSections() { + sections[0] = kxy; + sections[1] = kXy; + sections[2] = kXY; + sections[3] = kxY; + } + Section sections[4]{}; + float initial_x[4]{}; + float initial_y[4]{}; + float min_x, min_y, max_x, max_y; + int val_count; + }; + std::unique_ptr root; + std::vector vals_x; + std::vector vals_y; +}; + +class SmoothGen3D { + public: + SmoothGen3D() = default; + ~SmoothGen3D() = default; + auto GetX(int index) -> float { + Expand(static_cast(index)); + return vals_x[index]; + } + auto GetY(int index) -> float { + Expand(static_cast(index)); + return vals_y[index]; + } + auto GetZ(int index) -> float { + Expand(static_cast(index)); + return vals_z[index]; + } + + private: + void Expand(uint32_t index) { + if (index >= vals_x.size()) { + if (vals_x.empty()) { + float initial_x = RAND_RANGE(0, 1); + float initial_y = RAND_RANGE(0, 1); + float initial_z = RAND_RANGE(0, 1); + root = std::make_unique(0, 0, 0, 1, 1, 1, initial_x, initial_y, + initial_z); + vals_x.push_back(initial_x); + vals_y.push_back(initial_y); + vals_z.push_back(initial_z); + } + for (auto i = static_cast(vals_x.size()); i <= index; i++) { + float x, y, z; + root->GetNewValue(&x, &y, &z); + vals_x.push_back(x); + vals_y.push_back(y); + vals_z.push_back(z); + } + } + } + + class Node { + public: + Node(float min_x_in, float min_y_in, float min_z_in, float max_x_in, + float max_y_in, float max_z_in, float first_val_x, float first_val_y, + float first_val_z) + : min_x(min_x_in), + max_x(max_x_in), + min_y(min_y_in), + max_y(max_y_in), + min_z(min_z_in), + max_z(max_z_in) { + // store our initial value in the right section... + assert(first_val_x >= min_x && first_val_x <= max_x); + assert(first_val_y >= min_y && first_val_y <= max_y); + assert(first_val_z >= min_z && first_val_z <= max_z); + + float mid_x = min_x + (max_x - min_x) * 0.5f; + float mid_y = min_y + (max_y - min_y) * 0.5f; + float mid_z = min_z + (max_z - min_z) * 0.5f; + + Section q; + if (first_val_x < mid_x) { + if (first_val_y < mid_y) { + if (first_val_z < mid_z) { + q = kxyz; + } else { + q = kxyZ; + } + } else { + if (first_val_z < mid_z) { + q = kxYz; + } else { + q = kxYZ; + } + } + } else { + if (first_val_y < mid_y) { + if (first_val_z < mid_z) { + q = kXyz; + } else { + q = kXyZ; + } + } else { + if (first_val_z < mid_z) { + q = kXYz; + } else { + q = kXYZ; + } + } + } + + initial_x[q] = first_val_x; + initial_y[q] = first_val_y; + initial_z[q] = first_val_z; + int stored = 0; + for (int i = 0; i < 8; i++) { + if (i != q) { + sections[stored] = (Section)i; + stored++; + } + } + val_count = 1; + } + ~Node() = default; + void GetNewValue(float* x, float* y, float* z) { + if (val_count % 8 == 0) ResetSections(); + + Section q = PullRandomSection(); + + assert(val_count != 0); + + // We gen the rest of our first 8 values ourself. + if (val_count < 8) { + switch (q) { + case kxyz: + case kxyZ: + case kxYz: + case kxYZ: + (*x) = initial_x[q] = + RAND_RANGE(min_x, min_x + (max_x - min_x) * 0.5f); + break; + case kXyz: + case kXyZ: + case kXYz: + case kXYZ: + (*x) = initial_x[q] = + RAND_RANGE(min_x + (max_x - min_x) * 0.5f, max_x); + } + switch (q) { + case kxyz: + case kxyZ: + case kXyz: + case kXyZ: + (*y) = initial_y[q] = + RAND_RANGE(min_y, min_y + (max_y - min_y) * 0.5f); + break; + case kxYz: + case kxYZ: + case kXYz: + case kXYZ: + (*y) = initial_y[q] = + RAND_RANGE(min_y + (max_y - min_y) * 0.5f, max_y); + } + switch (q) { + case kxyz: + case kXyz: + case kXYz: + case kxYz: + (*z) = initial_z[q] = + RAND_RANGE(min_z, min_z + (max_z - min_z) * 0.5f); + break; + case kxyZ: + case kXyZ: + case kXYZ: + case kxYZ: + (*z) = initial_z[q] = + RAND_RANGE(min_z + (max_z - min_z) * 0.5f, max_z); + } + } else { + if (val_count == 8) { + // make child nodes and feed them their initial values... + float mid_x = min_x + (max_x - min_x) * 0.5f; + float mid_y = min_y + (max_y - min_y) * 0.5f; + float mid_z = min_z + (max_z - min_z) * 0.5f; + children[kxyz] = std::make_unique( + min_x, min_y, min_z, mid_x, mid_y, mid_z, initial_x[kxyz], + initial_y[kxyz], initial_z[kxyz]); + children[kxyZ] = std::make_unique( + min_x, min_y, mid_z, mid_x, mid_y, max_z, initial_x[kxyZ], + initial_y[kxyZ], initial_z[kxyZ]); + children[kXyz] = std::make_unique( + mid_x, min_y, min_z, max_x, mid_y, mid_z, initial_x[kXyz], + initial_y[kXyz], initial_z[kXyz]); + children[kXyZ] = std::make_unique( + mid_x, min_y, mid_z, max_x, mid_y, max_z, initial_x[kXyZ], + initial_y[kXyZ], initial_z[kXyZ]); + children[kXYz] = std::make_unique( + mid_x, mid_y, min_z, max_x, max_y, mid_z, initial_x[kXYz], + initial_y[kXYz], initial_z[kXYz]); + children[kXYZ] = std::make_unique( + mid_x, mid_y, mid_z, max_x, max_y, max_z, initial_x[kXYZ], + initial_y[kXYZ], initial_z[kXYZ]); + children[kxYz] = std::make_unique( + min_x, mid_y, min_z, mid_x, max_y, mid_z, initial_x[kxYz], + initial_y[kxYz], initial_z[kxYz]); + children[kxYZ] = std::make_unique( + min_x, mid_y, mid_z, mid_x, max_y, max_z, initial_x[kxYZ], + initial_y[kxYZ], initial_z[kxYZ]); + } + + // After this point we let our children do the work. + children[q]->GetNewValue(x, y, z); + } + val_count++; + } + + private: + enum Section { kxyz, kxyZ, kXyz, kXyZ, kxYz, kxYZ, kXYz, kXYZ }; + + std::unique_ptr children[8]; + + // Pull a section and remove it from our list. + auto PullRandomSection() -> Section { + int remaining_sections = 8 - val_count % 8; + int q_picked = rand() % remaining_sections; // NOLINT + Section q_val = sections[q_picked]; + int pos_new = 0; + for (int pos_old = 0; pos_old < remaining_sections; pos_old++) { + if (pos_old != q_picked) { + sections[pos_new] = sections[pos_old]; + pos_new++; + } + } + return q_val; + } + void ResetSections() { + for (int i = 0; i < 8; i++) sections[i] = (Section)i; + } + Section sections[8]{}; + float initial_x[8]{}; + float initial_y[8]{}; + float initial_z[8]{}; + float min_x, min_y, min_z, max_x, max_y, max_z; + int val_count; + }; + std::unique_ptr root; + std::vector vals_x; + std::vector vals_y; + std::vector vals_z; +}; + +void Random::GenList1D(float* list, int size) { + SmoothGen1D gen; + gen.GetX(size - 1); // Expand it in one fell swoop + for (int i = 0; i < size; i++) { + list[i] = gen.GetX(i); + } +} + +void Random::GenList2D(float (*list)[2], int size) { + SmoothGen2D gen; + gen.GetX(size - 1); // Expand it in one fell swoop + for (int i = 0; i < size; i++) { + list[i][0] = gen.GetX(i); + list[i][1] = gen.GetY(i); + } +} + +void Random::GenList3D(float (*list)[3], int size) { + SmoothGen3D gen; + gen.GetX(size - 1); // Expand it in one fell swoop + for (int i = 0; i < size; i++) { + list[i][0] = gen.GetX(i); + list[i][1] = gen.GetY(i); + list[i][2] = gen.GetZ(i); + } +} + +} // namespace ballistica diff --git a/src/ballistica/math/random.h b/src/ballistica/math/random.h new file mode 100644 index 00000000..4418dfd0 --- /dev/null +++ b/src/ballistica/math/random.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_RANDOM_H_ +#define BALLISTICA_MATH_RANDOM_H_ + +namespace ballistica { + +class Random { + public: + static void GenList1D(float* list, int size); + static void GenList2D(float (*list)[2], int size); + static void GenList3D(float (*list)[3], int size); +}; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_RANDOM_H_ diff --git a/src/ballistica/math/rect.h b/src/ballistica/math/rect.h new file mode 100644 index 00000000..bd7778cc --- /dev/null +++ b/src/ballistica/math/rect.h @@ -0,0 +1,21 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_RECT_H_ +#define BALLISTICA_MATH_RECT_H_ + +// A Generic 2d rect. +namespace ballistica { + +class Rect { + public: + float l{}, r{}, b{}, t{}; + Rect() = default; + Rect(float l_in, float b_in, float r_in, float t_in) + : l(l_in), r(r_in), b(b_in), t(t_in) {} + auto width() const -> float { return r - l; } + auto height() const -> float { return t - b; } +}; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_RECT_H_ diff --git a/src/ballistica/math/vector2f.h b/src/ballistica/math/vector2f.h new file mode 100644 index 00000000..e9ad463f --- /dev/null +++ b/src/ballistica/math/vector2f.h @@ -0,0 +1,27 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_VECTOR2F_H_ +#define BALLISTICA_MATH_VECTOR2F_H_ + +namespace ballistica { + +class Vector2f { + public: + // Leaves uninitialized. + Vector2f() {} // NOLINT + Vector2f(float x, float y) : x(x), y(y) {} // NOLINT + + union { + struct { + float x; + float y; + }; + float v[2]; + }; +}; + +const Vector2f kVector2f0{0.0f, 0.0f}; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_VECTOR2F_H_ diff --git a/src/ballistica/math/vector3f.cc b/src/ballistica/math/vector3f.cc new file mode 100644 index 00000000..fa49eb60 --- /dev/null +++ b/src/ballistica/math/vector3f.cc @@ -0,0 +1,51 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +auto Vector3f::Dominant() const -> int { + const float x = std::abs(v[0]); + const float y = std::abs(v[1]); + const float z = std::abs(v[2]); + if (x > y && x > z) { + return 0; + } else { + if (y > z) { + return 1; + } else { + return 2; + } + } +} + +auto Vector3f::Angle(const Vector3f& v1, const Vector3f& v2) -> float { + float s = sqrtf(v1.LengthSquared() * v2.LengthSquared()); + assert(s != 0.0f); + return (360.0f / (2.0f * kPi)) * acosf(Dot(v1, v2) / s); +} + +auto Vector3f::PlaneNormal(const Vector3f& v1, const Vector3f& v2, + const Vector3f& v3) -> Vector3f { + return Cross(v2 - v1, v3 - v1); +} + +auto Vector3f::Polar(float lat, float longitude) -> Vector3f { + return {cosf(lat * kPiDeg) * cosf(longitude * kPiDeg), sinf(lat * kPiDeg), + cosf(lat * kPiDeg) * sinf(longitude * kPiDeg)}; +} + +void Vector3f::OrthogonalSystem(Vector3f* a, Vector3f* b, Vector3f* c) { + a->Normalize(); + if (std::abs(a->z) > 0.8f) { + *b = Cross(*a, kVector3fY); + *c = Cross(*a, *b); + } else { + *b = Cross(*a, kVector3fZ); + *c = Cross(*a, *b); + } + b->Normalize(); + c->Normalize(); +} + +} // namespace ballistica diff --git a/src/ballistica/math/vector3f.h b/src/ballistica/math/vector3f.h new file mode 100644 index 00000000..afc402bf --- /dev/null +++ b/src/ballistica/math/vector3f.h @@ -0,0 +1,200 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_VECTOR3F_H_ +#define BALLISTICA_MATH_VECTOR3F_H_ + +#include +#include // for memcpy +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +class Vector3f { + public: + // Default constructor (leaves uninitialized) + Vector3f() = default; + + // Constructor. + Vector3f(float x, float y, float z) : x(x), y(y), z(z) {} // NOLINT + + // Constructor. + explicit Vector3f(const float* vals) { // NOLINT + memcpy(v, vals, sizeof(v)); + } // NOLINT + + // Constructor. + explicit Vector3f(const std::vector& vals) { // NOLINT + assert(vals.size() == 3); + memcpy(v, vals.data(), sizeof(v)); + } + + auto Normalized() const -> Vector3f { + Vector3f v2(*this); + v2.Normalize(); + return v2; + } + + // Equality operator. + auto operator==(const Vector3f& other) const -> bool { + return x == other.x && y == other.y && z == other.z; + } + + // Inequality operator. + auto operator!=(const Vector3f& other) const -> bool { + return x != other.x || y != other.y || z != other.z; + } + + // Equality operator: x==a && y==a && z==a/ + auto operator==(const float& a) const -> bool { + return x == a && y == a && z == a; + } + + // Less-than comparison. + auto operator<(const Vector3f& other) const -> bool { + if (x != other.x) return x < other.x; + if (y != other.y) return y < other.y; + return z < other.z; + } + + // Greater-than comparison. + auto operator>(const Vector3f& other) const -> bool { + if (x != other.x) return x > other.x; + if (y != other.y) return y > other.y; + return z > other.z; + } + + // Assignment operator. + auto operator=(const float* vals) -> Vector3f& { + memcpy(v, vals, sizeof(v)); + return *this; + } + + // Assignment operator. + auto operator=(const double* vals) -> Vector3f& { + x = static_cast(vals[0]); + y = static_cast(vals[1]); + z = static_cast(vals[2]); + return *this; + } + + // Addition in place. + auto operator+=(const Vector3f& other) -> Vector3f& { + x += other.x; + y += other.y; + z += other.z; + return *this; + } + + // Subtraction in place. + auto operator-=(const Vector3f& other) -> Vector3f& { + x -= other.x; + y -= other.y; + z -= other.z; + return *this; + } + + auto Dot(const Vector3f& other) const -> float { + return x * other.x + y * other.y + z * other.z; + } + + // Multiply in place. + auto operator*=(float val) -> Vector3f& { + x *= val; + y *= val; + z *= val; + return *this; + } + + // Negative. + auto operator-() const -> Vector3f { return {-x, -y, -z}; } + + auto operator/(float val) const -> Vector3f { + assert(val != 0.0f); + float inv = 1.0f / val; + return {x * inv, y * inv, z * inv}; + } + + auto operator*(float val) const -> Vector3f { + return {val * x, val * y, val * z}; + } + // (allow NUM * VEC order) + friend auto operator*(float val, const Vector3f& vec) -> Vector3f { + return vec * val; + } + auto operator+(const Vector3f& other) const -> Vector3f { + return {x + other.x, y + other.y, z + other.z}; + } + auto operator-(const Vector3f& other) const -> Vector3f { + return {x - other.x, y - other.y, z - other.z}; + } + + void Scale(const Vector3f& val) { + x *= val.x; + y *= val.y; + z *= val.z; + } + + // Normalise the vector: |x| = 1.0. + void Normalize() { + const float mag = sqrtf(LengthSquared()); + if (mag == 0.0f) return; + const float mag_inv = 1.0f / mag; + x *= mag_inv; + y *= mag_inv; + z *= mag_inv; + } + + // Make x, y and z positive. + void MakeAbs() { + x = std::abs(x); + y = std::abs(y); + z = std::abs(z); + } + + // Find the dominant component: x, y or z. + auto Dominant() const -> int; + + // Squared length of vector. + auto LengthSquared() const -> float { return ((*this).Dot(*this)); } + + // Length of vector. + auto Length() const -> float { return sqrtf((*this).Dot(*this)); } + + union { + struct { + float x; + float y; + float z; + }; + float v[3]; + }; + + static auto Cross(const Vector3f& v1, const Vector3f& v2) -> Vector3f { + return {v1.v[1] * v2.v[2] - v1.v[2] * v2.v[1], + v1.v[2] * v2.v[0] - v1.v[0] * v2.v[2], + v1.v[0] * v2.v[1] - v1.v[1] * v2.v[0]}; + } + + static auto PlaneNormal(const Vector3f& v1, const Vector3f& v2, + const Vector3f& v3) -> Vector3f; + static auto Polar(float lat, float longitude) -> Vector3f; + + static void OrthogonalSystem(Vector3f* a, Vector3f* b, Vector3f* c); + + static auto Dot(const Vector3f& v1, const Vector3f& v2) -> float { + return (v1.x * v2.x + v1.y * v2.y + v1.z * v2.z); + } + static auto Angle(const Vector3f& v1, const Vector3f& v2) -> float; +}; + +const Vector3f kVector3fX{1.0f, 0.0f, 0.0f}; +const Vector3f kVector3fY{0.0f, 1.0f, 0.0f}; +const Vector3f kVector3fZ{0.0f, 0.0f, 1.0f}; +const Vector3f kVector3f0{0.0f, 0.0f, 0.0f}; +const Vector3f kVector3f1{1.0f, 1.0f, 1.0f}; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_VECTOR3F_H_ diff --git a/src/ballistica/math/vector4f.h b/src/ballistica/math/vector4f.h new file mode 100644 index 00000000..c66f46c5 --- /dev/null +++ b/src/ballistica/math/vector4f.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MATH_VECTOR4F_H_ +#define BALLISTICA_MATH_VECTOR4F_H_ + +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +class Vector4f { + public: + Vector4f() = default; + // NOLINTNEXTLINE saying we don't init v but in effect we do. + Vector4f(float x, float y, float z, float w) : x(x), y(y), z(z), w(w) {} + + auto xyz() const -> Vector3f { return {x, y, z}; } + + union { + struct { + float x; + float y; + float z; + float w; + }; + float v[4]; + }; +}; + +const Vector4f kVector4f0{0.0f, 0.0f, 0.0f, 0.0f}; + +} // namespace ballistica + +#endif // BALLISTICA_MATH_VECTOR4F_H_ diff --git a/src/ballistica/media/component/collide_model.cc b/src/ballistica/media/component/collide_model.cc new file mode 100644 index 00000000..23c39486 --- /dev/null +++ b/src/ballistica/media/component/collide_model.cc @@ -0,0 +1,46 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/collide_model.h" + +#include + +#include "ballistica/game/game_stream.h" +#include "ballistica/python/class/python_class_collide_model.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +CollideModel::CollideModel(const std::string& name, Scene* scene) + : MediaComponent(name, scene), dead_(false) { + assert(InGameThread()); + if (scene) { + if (GameStream* os = scene->GetGameStream()) { + os->AddCollideModel(this); + } + } + { + Media::MediaListsLock lock; + collide_model_data_ = g_media->GetCollideModelData(name); + } + assert(collide_model_data_.exists()); +} + +CollideModel::~CollideModel() { MarkDead(); } + +void CollideModel::MarkDead() { + if (dead_) { + return; + } + if (Scene* s = scene()) { + if (GameStream* os = s->GetGameStream()) { + os->RemoveCollideModel(this); + } + } + dead_ = true; +} + +auto CollideModel::CreatePyObject() -> PyObject* { + return PythonClassCollideModel::Create(this); +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/collide_model.h b/src/ballistica/media/component/collide_model.h new file mode 100644 index 00000000..7b8fa1e8 --- /dev/null +++ b/src/ballistica/media/component/collide_model.h @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_COLLIDE_MODEL_H_ +#define BALLISTICA_MEDIA_COMPONENT_COLLIDE_MODEL_H_ + +#include + +#include "ballistica/media/component/media_component.h" +#include "ballistica/media/data/collide_model_data.h" +#include "ballistica/media/media.h" + +namespace ballistica { + +// user-facing collide_model class +class CollideModel : public MediaComponent { + public: + CollideModel(const std::string& name, Scene* scene); + ~CollideModel() override; + + // return the CollideModelData currently associated with this collide_model + // note that a collide_model's data can change over time as different + // versions are spooled in/out/etc + auto collide_model_data() const -> CollideModelData* { + return collide_model_data_.get(); + } + auto GetMediaComponentTypeName() const -> std::string override { + return "CollideModel"; + } + void MarkDead(); + + protected: + auto CreatePyObject() -> PyObject* override; + + private: + bool dead_; + Object::Ref collide_model_data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_COLLIDE_MODEL_H_ diff --git a/src/ballistica/media/component/cube_map_texture.cc b/src/ballistica/media/component/cube_map_texture.cc new file mode 100644 index 00000000..384cb43e --- /dev/null +++ b/src/ballistica/media/component/cube_map_texture.cc @@ -0,0 +1,21 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/cube_map_texture.h" + +#include "ballistica/media/media.h" + +namespace ballistica { + +CubeMapTexture::CubeMapTexture(const std::string& name, Scene* scene) + : MediaComponent(name, scene) { + assert(InGameThread()); + + // cant currently add these to scenes so nothing to do here.. + { + Media::MediaListsLock lock; + texture_data_ = g_media->GetCubeMapTextureData(name); + } + assert(texture_data_.exists()); +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/cube_map_texture.h b/src/ballistica/media/component/cube_map_texture.h new file mode 100644 index 00000000..c72e4623 --- /dev/null +++ b/src/ballistica/media/component/cube_map_texture.h @@ -0,0 +1,32 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_CUBE_MAP_TEXTURE_H_ +#define BALLISTICA_MEDIA_COMPONENT_CUBE_MAP_TEXTURE_H_ + +#include + +#include "ballistica/media/component/media_component.h" +#include "ballistica/media/data/texture_data.h" + +namespace ballistica { + +// user-facing texture class +class CubeMapTexture : public MediaComponent { + public: + CubeMapTexture(const std::string& name, Scene* s); + + // return the TextureData currently associated with this texture + // note that a texture's data can change over time as different + // versions are spooled in/out/etc + auto GetTextureData() const -> TextureData* { return texture_data_.get(); } + auto GetMediaComponentTypeName() const -> std::string override { + return "CubeMapTexture"; + } + + private: + Object::Ref texture_data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_CUBE_MAP_TEXTURE_H_ diff --git a/src/ballistica/media/component/data.cc b/src/ballistica/media/component/data.cc new file mode 100644 index 00000000..8e1361a2 --- /dev/null +++ b/src/ballistica/media/component/data.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/data.h" + +#include "ballistica/game/game_stream.h" +#include "ballistica/python/class/python_class_data.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +Data::Data(const std::string& name, Scene* scene) + : MediaComponent(name, scene), dead_(false) { + assert(InGameThread()); + + if (scene) { + if (GameStream* os = scene->GetGameStream()) { + os->AddData(this); + } + } + { + Media::MediaListsLock lock; + data_data_ = g_media->GetDataData(name); + } + assert(data_data_.exists()); +} + +Data::~Data() { MarkDead(); } + +void Data::MarkDead() { + if (dead_) { + return; + } + if (Scene* s = scene()) { + if (GameStream* os = s->GetGameStream()) { + os->RemoveData(this); + } + } + dead_ = true; +} + +auto Data::CreatePyObject() -> PyObject* { + return PythonClassData::Create(this); +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/data.h b/src/ballistica/media/component/data.h new file mode 100644 index 00000000..30e926a2 --- /dev/null +++ b/src/ballistica/media/component/data.h @@ -0,0 +1,43 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_DATA_H_ +#define BALLISTICA_MEDIA_COMPONENT_DATA_H_ + +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" +#include "ballistica/media/component/media_component.h" +#include "ballistica/media/data/data_data.h" +#include "ballistica/media/data/media_component_data.h" +#include "ballistica/media/media.h" + +namespace ballistica { + +// user-facing data class +class Data : public MediaComponent { + public: + Data(const std::string& name, Scene* scene); + ~Data() override; + + // return the DataData currently associated with this data + // note that a data's data can change over time as different + // versions are spooled in/out/etc. + auto data_data() const -> DataData* { return data_data_.get(); } + auto GetMediaComponentTypeName() const -> std::string override { + return "Data"; + } + void MarkDead(); + + protected: + auto CreatePyObject() -> PyObject* override; + + private: + bool dead_; + Object::Ref data_data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_DATA_H_ diff --git a/src/ballistica/media/component/media_component.cc b/src/ballistica/media/component/media_component.cc new file mode 100644 index 00000000..4fe11860 --- /dev/null +++ b/src/ballistica/media/component/media_component.cc @@ -0,0 +1,37 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/media_component.h" + +#include +#include + +#include "ballistica/python/python_sys.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +MediaComponent::MediaComponent(std::string name, Scene* scene) + : name_(std::move(name)), scene_(scene) {} + +auto MediaComponent::GetPyRef(bool new_ref) -> PyObject* { + if (!py_object_) { + // if we have no python object, create it + py_object_ = CreatePyObject(); + assert(py_object_ != nullptr); + } + if (new_ref) { + Py_INCREF(py_object_); + } + return py_object_; +} + +auto MediaComponent::GetObjectDescription() const -> std::string { + return ""; +} + +void MediaComponent::ClearPyObject() { + assert(py_object_ != nullptr); + py_object_ = nullptr; +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/media_component.h b/src/ballistica/media/component/media_component.h new file mode 100644 index 00000000..84887de1 --- /dev/null +++ b/src/ballistica/media/component/media_component.h @@ -0,0 +1,63 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_MEDIA_COMPONENT_H_ +#define BALLISTICA_MEDIA_COMPONENT_MEDIA_COMPONENT_H_ + +#include + +#include "ballistica/core/context.h" +#include "ballistica/core/object.h" + +namespace ballistica { + +class MediaComponent : public Object { + public: + MediaComponent(std::string name, Scene* scene); + auto name() const -> std::string { return name_; } + + // Returns true if this texture was created in the UI context. + // UI stuff should check this before accepting a texture. + auto IsFromUIContext() const -> bool { + return (context_.GetUIContext() != nullptr); + } + auto has_py_object() const -> bool { return (py_object_ != nullptr); } + auto NewPyRef() -> PyObject* { return GetPyRef(true); } + auto BorrowPyRef() -> PyObject* { return GetPyRef(false); } + auto GetObjectDescription() const -> std::string override; + auto scene() const -> Scene* { return scene_.get(); } + + // Called by python wrapper objs when they are dying. + void ClearPyObject(); + + auto stream_id() const -> int64_t { return stream_id_; } + void set_stream_id(int64_t val) { + assert(stream_id_ == -1); + stream_id_ = val; + } + + void clear_stream_id() { + assert(stream_id_ != -1); + stream_id_ = -1; + } + + protected: + virtual auto GetMediaComponentTypeName() const -> std::string = 0; + + // Create a python representation of this object. + virtual auto CreatePyObject() -> PyObject* = 0; + + private: + int64_t stream_id_{-1}; + Object::WeakRef scene_; + PyObject* py_object_{}; + + // Return a python reference to the object, (creating python obj if needed). + auto GetPyRef(bool new_ref = true) -> PyObject*; + std::string name_; + Context context_; + friend class ClientSession; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_MEDIA_COMPONENT_H_ diff --git a/src/ballistica/media/component/model.cc b/src/ballistica/media/component/model.cc new file mode 100644 index 00000000..e5060444 --- /dev/null +++ b/src/ballistica/media/component/model.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/model.h" + +#include "ballistica/game/game_stream.h" +#include "ballistica/python/class/python_class_model.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +Model::Model(const std::string& name, Scene* scene) + : MediaComponent(name, scene), dead_(false) { + assert(InGameThread()); + + if (scene) { + if (GameStream* os = scene->GetGameStream()) { + os->AddModel(this); + } + } + { + Media::MediaListsLock lock; + model_data_ = g_media->GetModelData(name); + } + assert(model_data_.exists()); +} + +Model::~Model() { MarkDead(); } + +void Model::MarkDead() { + if (dead_) { + return; + } + if (Scene* s = scene()) { + if (GameStream* os = s->GetGameStream()) { + os->RemoveModel(this); + } + } + dead_ = true; +} + +auto Model::CreatePyObject() -> PyObject* { + return PythonClassModel::Create(this); +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/model.h b/src/ballistica/media/component/model.h new file mode 100644 index 00000000..c7a8968b --- /dev/null +++ b/src/ballistica/media/component/model.h @@ -0,0 +1,44 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_MODEL_H_ +#define BALLISTICA_MEDIA_COMPONENT_MODEL_H_ + +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" +#include "ballistica/media/component/media_component.h" +#include "ballistica/media/data/media_component_data.h" +#include "ballistica/media/data/model_data.h" +#include "ballistica/media/data/model_renderer_data.h" +#include "ballistica/media/media.h" + +namespace ballistica { + +// user-facing model class +class Model : public MediaComponent { + public: + Model(const std::string& name, Scene* scene); + ~Model() override; + + // return the ModelData currently associated with this model + // note that a model's data can change over time as different + // versions are spooled in/out/etc + auto model_data() const -> ModelData* { return model_data_.get(); } + auto GetMediaComponentTypeName() const -> std::string override { + return "Model"; + } + void MarkDead(); + + protected: + auto CreatePyObject() -> PyObject* override; + + private: + bool dead_; + Object::Ref model_data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_MODEL_H_ diff --git a/src/ballistica/media/component/sound.cc b/src/ballistica/media/component/sound.cc new file mode 100644 index 00000000..218146cf --- /dev/null +++ b/src/ballistica/media/component/sound.cc @@ -0,0 +1,44 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/sound.h" + +#include "ballistica/game/game_stream.h" +#include "ballistica/media/data/sound_data.h" +#include "ballistica/media/media.h" +#include "ballistica/python/class/python_class_sound.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +Sound::Sound(const std::string& name, Scene* scene) + : MediaComponent(name, scene) { + assert(InGameThread()); + if (scene) { + if (GameStream* os = scene->GetGameStream()) { + os->AddSound(this); + } + } + { + Media::MediaListsLock lock; + sound_data_ = g_media->GetSoundData(name); + } + assert(sound_data_.exists()); +} + +Sound::~Sound() { MarkDead(); } + +void Sound::MarkDead() { + if (dead_) return; + if (Scene* s = scene()) { + if (GameStream* os = s->GetGameStream()) { + os->RemoveSound(this); + } + } + dead_ = true; +} + +auto Sound::CreatePyObject() -> PyObject* { + return PythonClassSound::Create(this); +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/sound.h b/src/ballistica/media/component/sound.h new file mode 100644 index 00000000..e712cced --- /dev/null +++ b/src/ballistica/media/component/sound.h @@ -0,0 +1,37 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_SOUND_H_ +#define BALLISTICA_MEDIA_COMPONENT_SOUND_H_ + +#include +#include + +#include "ballistica/media/component/media_component.h" + +namespace ballistica { + +class Sound : public MediaComponent { + public: + Sound(const std::string& name, Scene* scene); + ~Sound() override; + + // Return the SoundData currently associated with this sound. + // Note that a sound's data can change over time as different + // versions are spooled in/out/etc. + auto GetSoundData() const -> SoundData* { return sound_data_.get(); } + auto GetMediaComponentTypeName() const -> std::string override { + return "Sound"; + } + void MarkDead(); + + protected: + auto CreatePyObject() -> PyObject* override; + + private: + bool dead_{}; + Object::Ref sound_data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_SOUND_H_ diff --git a/src/ballistica/media/component/texture.cc b/src/ballistica/media/component/texture.cc new file mode 100644 index 00000000..3948927a --- /dev/null +++ b/src/ballistica/media/component/texture.cc @@ -0,0 +1,59 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/component/texture.h" + +#include + +#include "ballistica/game/game_stream.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/python/class/python_class_texture.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +Texture::Texture(const std::string& name, Scene* scene) + : MediaComponent(name, scene), dead_(false) { + assert(InGameThread()); + + // Add to the provided scene to get a numeric ID. + if (scene) { + if (GameStream* os = scene->GetGameStream()) { + os->AddTexture(this); + } + } + { + Media::MediaListsLock lock; + texture_data_ = g_media->GetTextureData(name); + } + assert(texture_data_.exists()); +} + +// qrcode version +Texture::Texture(const std::string& qr_url) : MediaComponent(qr_url, nullptr) { + assert(InGameThread()); + { + Media::MediaListsLock lock; + texture_data_ = g_media->GetTextureDataQRCode(qr_url); + } + assert(texture_data_.exists()); +} + +Texture::~Texture() { MarkDead(); } + +void Texture::MarkDead() { + if (dead_) { + return; + } + if (Scene* s = scene()) { + if (GameStream* os = s->GetGameStream()) { + os->RemoveTexture(this); + } + } + dead_ = true; +} + +auto Texture::CreatePyObject() -> PyObject* { + return PythonClassTexture::Create(this); +} + +} // namespace ballistica diff --git a/src/ballistica/media/component/texture.h b/src/ballistica/media/component/texture.h new file mode 100644 index 00000000..d03ed2e5 --- /dev/null +++ b/src/ballistica/media/component/texture.h @@ -0,0 +1,39 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_COMPONENT_TEXTURE_H_ +#define BALLISTICA_MEDIA_COMPONENT_TEXTURE_H_ + +#include + +#include "ballistica/media/component/media_component.h" +#include "ballistica/media/data/texture_data.h" + +namespace ballistica { + +// User-facing texture class. +class Texture : public MediaComponent { + public: + Texture(const std::string& name, Scene* scene); + explicit Texture(const std::string& qr_url); + ~Texture() override; + + // Return the TextureData currently associated with this texture. + // Note that a texture's data can change over time as different + // versions are spooled in/out/etc. + auto texture_data() const -> TextureData* { return texture_data_.get(); } + auto GetMediaComponentTypeName() const -> std::string override { + return "Texture"; + } + void MarkDead(); + + protected: + auto CreatePyObject() -> PyObject* override; + + private: + bool dead_ = false; + Object::Ref texture_data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_COMPONENT_TEXTURE_H_ diff --git a/src/ballistica/media/data/collide_model_data.cc b/src/ballistica/media/data/collide_model_data.cc new file mode 100644 index 00000000..2486c341 --- /dev/null +++ b/src/ballistica/media/data/collide_model_data.cc @@ -0,0 +1,134 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/collide_model_data.h" + +#include + +#include "ballistica/media/media.h" + +namespace ballistica { + +CollideModelData::CollideModelData(const std::string& file_name_in) + : file_name_(file_name_in) { + file_name_full_ = + g_media->FindMediaFile(Media::FileType::kCollisionModel, file_name_in); + valid_ = true; +} + +void CollideModelData::DoPreload() { + assert(!file_name_.empty()); + + FILE* f = g_platform->FOpen(file_name_full_.c_str(), "rb"); + uint32_t i_vals[2]; + if (!f) { + throw Exception("Can't open collide model: '" + file_name_full_ + "'"); + } + + uint32_t version; + if (fread(&version, sizeof(version), 1, f) != 1) { + throw Exception("Error reading file header for '" + file_name_full_ + "'"); + } + + if (version != kCobFileID) { + throw Exception("File '" + file_name_full_ + + " is in an old format or not a cob file (got id " + + std::to_string(version) + ", " + + std::to_string(kCobFileID) + ")"); + } + + // Read the vertex count and face count. + if (fread(i_vals, sizeof(i_vals), 1, f) != 1) { + throw Exception("Read failed for " + file_name_full_); + } + + size_t vertex_count = i_vals[0]; + size_t tri_count = i_vals[1]; + + // Need 3 floats per vertex. + vertices_.resize(vertex_count * 3); + + // Need 3 indices per face. + indices_.resize(tri_count * 3); + + // Need 3 floats per face-normal. + normals_.resize(tri_count * 3); + + if (fread(&(vertices_[0]), vertices_.size() * sizeof(dReal), 1, f) != 1) { + throw Exception("Read failed for " + file_name_full_); + } + if (fread(&(indices_[0]), indices_.size() * sizeof(uint32_t), 1, f) != 1) { + throw Exception("Read failed for " + file_name_full_); + } + if (fread(&(normals_[0]), normals_.size() * sizeof(dReal), 1, f) != 1) { + throw Exception("Read failed for " + file_name_full_); + } + + fclose(f); + + tri_mesh_data_ = dGeomTriMeshDataCreate(); + BA_PRECONDITION(tri_mesh_data_); + + if (!HeadlessMode()) { + tri_mesh_data_bg_ = dGeomTriMeshDataCreate(); + BA_PRECONDITION(tri_mesh_data_bg_); + } + +#ifdef dSINGLE + dGeomTriMeshDataBuildSingle1( + tri_mesh_data_, &(vertices_[0]), 3 * sizeof(dReal), + static_cast_check_fit(vertex_count), &(indices_[0]), + static_cast(indices_.size()), 3 * sizeof(uint32_t), &(normals_[0])); + if (!HeadlessMode()) { + dGeomTriMeshDataBuildSingle1(tri_mesh_data_bg_, &(vertices_[0]), + 3 * sizeof(dReal), i_vals[0], &(indices_[0]), + static_cast(indices_.size()), + 3 * sizeof(uint32_t), &(normals_[0])); + } +#else +#ifndef dDOUBLE +#error single or double precition not defined +#endif + dGeomTriMeshDataBuildDouble1( + tri_mesh_data_, &(vertices_[0]), 3 * sizeof(dReal), vertex_count, + &(indices_[0]), indices_.size(), 3 * sizeof(uint32_t), &(normals_[0])); + if (!HeadlessMode()) { + dGeomTriMeshDataBuildDouble1( + tri_mesh_data_bg_, &(vertices_[0]), 3 * sizeof(dReal), i_vals[0], + &(indices_[0]), indices_.size(), 3 * sizeof(uint32_t), &(normals_[0])); + } +#endif // dSINGLE +} // namespace ballistica + +void CollideModelData::DoLoad() { assert(InGameThread()); } + +void CollideModelData::DoUnload() { + // TODO(ericf): if we want to support in-game reloading we need + // to keep track of what ODE trimeshes are using our data and update + // them all accordingly on unload/loads... + + // we should still be fine for regular pruning unloads though; + // if there are no references remaining to us then nothing in the + // game should be using us. + + if (!valid_) { + return; + } + + dGeomTriMeshDataDestroy(tri_mesh_data_); + if (tri_mesh_data_bg_) { + dGeomTriMeshDataDestroy(tri_mesh_data_bg_); + } +} + +auto CollideModelData::GetMeshData() -> dTriMeshDataID { + assert(tri_mesh_data_); + return tri_mesh_data_; +} + +auto CollideModelData::GetBGMeshData() -> dTriMeshDataID { + assert(loaded()); + assert(!HeadlessMode()); + return tri_mesh_data_bg_; +} + +} // namespace ballistica diff --git a/src/ballistica/media/data/collide_model_data.h b/src/ballistica/media/data/collide_model_data.h new file mode 100644 index 00000000..3e3223d3 --- /dev/null +++ b/src/ballistica/media/data/collide_model_data.h @@ -0,0 +1,47 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_COLLIDE_MODEL_DATA_H_ +#define BALLISTICA_MEDIA_DATA_COLLIDE_MODEL_DATA_H_ + +#include +#include + +#include "ballistica/media/data/media_component_data.h" +#include "ode/ode.h" + +namespace ballistica { + +// Loadable model for collision detection. +class CollideModelData : public MediaComponentData { + public: + CollideModelData() = default; + explicit CollideModelData(const std::string& file_name_in); + void DoPreload() override; + void DoLoad() override; + void DoUnload() override; + auto GetMediaType() const -> MediaType override { + return MediaType::kCollideModel; + } + auto GetName() const -> std::string override { + if (!file_name_full_.empty()) { + return file_name_full_; + } else { + return "invalid CollideModel"; + } + } + auto GetMeshData() -> dTriMeshDataID; + auto GetBGMeshData() -> dTriMeshDataID; + + private: + std::string file_name_; + std::string file_name_full_; + std::vector vertices_; + std::vector indices_; + std::vector normals_; + dTriMeshDataID tri_mesh_data_{}; + dTriMeshDataID tri_mesh_data_bg_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_COLLIDE_MODEL_DATA_H_ diff --git a/src/ballistica/media/data/data_data.cc b/src/ballistica/media/data/data_data.cc new file mode 100644 index 00000000..05555b03 --- /dev/null +++ b/src/ballistica/media/data/data_data.cc @@ -0,0 +1,50 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/data_data.h" + +#include "ballistica/media/media.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +DataData::DataData(const std::string& file_name_in) : file_name_(file_name_in) { + file_name_full_ = + g_media->FindMediaFile(Media::FileType::kData, file_name_in); + valid_ = true; +} + +void DataData::DoPreload() { + // NOTE TO SELF: originally I tried to grab the GIL here and do our actual + // Python loading in Preload(). However this resulted in deadlock + // in the following case: + // - asset thread grabs payload lock for Preload() + // - asset thread tries to grab GIL in Preload(); spins. + // - meanwhile, something in game thread has called Load() + // - game thread holds GIL by default and now spins waiting on payload lock. + // - deadlock :-( + + // ...so the new plan is to simply load the file into a string in Preload() + // and then do the Python work in Load(). This should still avoid the nastiest + // IO-related hitches at least.. + + raw_input_ = Utils::FileToString(file_name_full_); +} + +void DataData::DoLoad() { + assert(InGameThread()); + assert(valid_); + PythonRef args(Py_BuildValue("(s)", raw_input_.c_str()), PythonRef::kSteal); + object_ = g_python->obj(Python::ObjID::kJsonLoadsCall).Call(args); + if (!object_.exists()) { + throw Exception("Unable to load data: '" + file_name_ + "'."); + } +} + +void DataData::DoUnload() { + assert(InGameThread()); + assert(valid_); + object_.Release(); +} + +} // namespace ballistica diff --git a/src/ballistica/media/data/data_data.h b/src/ballistica/media/data/data_data.h new file mode 100644 index 00000000..d6b2d64f --- /dev/null +++ b/src/ballistica/media/data/data_data.h @@ -0,0 +1,47 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_DATA_DATA_H_ +#define BALLISTICA_MEDIA_DATA_DATA_DATA_H_ + +#include + +#include "ballistica/media/data/media_component_data.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +class DataData : public MediaComponentData { + public: + DataData() = default; + explicit DataData(const std::string& file_name_in); + + void DoPreload() override; + void DoLoad() override; + void DoUnload() override; + + auto GetMediaType() const -> MediaType override { return MediaType::kData; } + auto GetName() const -> std::string override { + if (!file_name_full_.empty()) { + return file_name_full_; + } else { + return "invalid data"; + } + } + auto object() -> const PythonRef& { + assert(InGameThread()); + assert(loaded()); + return object_; + } + auto file_name() const -> const std::string& { return file_name_; } + auto file_name_full() const -> const std::string& { return file_name_full_; } + + private: + PythonRef object_; + std::string file_name_; + std::string file_name_full_; + std::string raw_input_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_DATA_DATA_H_ diff --git a/src/ballistica/media/data/media_component_data.cc b/src/ballistica/media/data/media_component_data.cc new file mode 100644 index 00000000..9d7fc411 --- /dev/null +++ b/src/ballistica/media/data/media_component_data.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/media_component_data.h" + +namespace ballistica { + +MediaComponentData::MediaComponentData() { + assert(InGameThread()); + assert(g_media); + last_used_time_ = GetRealTime(); +} + +MediaComponentData::~MediaComponentData() { + // at the moment whoever owns the last reference to us + // needs to make sure to unload us before we die.. + // I feel like there should be a more elegant solution to that. + assert(g_media); + assert(!locked()); + assert(!loaded()); +} + +void MediaComponentData::Preload(bool already_locked) { + LockGuard lock(this, already_locked ? LockGuard::Type::kDontLock + : LockGuard::Type::kLock); + if (!preloaded_) { + assert(!loaded_); +#if BA_SHOW_LOADS_UNLOADS + printf("pre-loading %s\n", GetName().c_str()); +#endif + BA_PRECONDITION(locked()); + preload_start_time_ = GetRealTime(); + DoPreload(); + preload_end_time_ = GetRealTime(); + preloaded_ = true; + } +} + +void MediaComponentData::Load(bool already_locked) { + LockGuard lock(this, already_locked ? LockGuard::Type::kDontLock + : LockGuard::Type::kLock); + if (!preloaded_) { + Preload(true); + } + + if (!loaded_) { +#if BA_SHOW_LOADS_UNLOADS + printf("loading %s\n", GetName().c_str()); +#endif + assert(preloaded_ && !loaded_); + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + BA_PRECONDITION(locked()); + load_start_time_ = GetRealTime(); + DoLoad(); + load_end_time_ = GetRealTime(); + BA_DEBUG_FUNCTION_TIMER_END_THREAD_EX(50, GetName()); + loaded_ = true; + } +} + +void MediaComponentData::Unload(bool already_locked) { + LockGuard lock(this, already_locked ? LockGuard::Type::kDontLock + : LockGuard::Type::kLock); + + // if somehow we're told to unload after we've preloaded but before load, + // finish the load first... (don't wanna worry about guarding against that + // case) + // UPDATE: is this still necessary? It's a holdover from when we had + // potentially-multi-stage loads... now we just have a single load always. + if (preloaded_ && !loaded_) { + Load(true); + } + if (loaded_ && preloaded_) { +#if BA_SHOW_LOADS_UNLOADS + printf("unloading %s\n", GetName().c_str()); +#endif + BA_PRECONDITION(locked()); + DoUnload(); + preloaded_ = false; + loaded_ = false; + } +} + +MediaComponentData::LockGuard::LockGuard(MediaComponentData* data, Type type) + : data_(data) { + switch (type) { + case kLock: { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + data_->Lock(); + holds_lock_ = true; + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); + break; + } + case kInheritLock: + holds_lock_ = true; + break; + case kDontLock: + break; + default: + throw Exception(); + } +} + +MediaComponentData::LockGuard::~LockGuard() { + if (holds_lock_) { + data_->Unlock(); + } +} +} // namespace ballistica diff --git a/src/ballistica/media/data/media_component_data.h b/src/ballistica/media/data/media_component_data.h new file mode 100644 index 00000000..7ab99e25 --- /dev/null +++ b/src/ballistica/media/data/media_component_data.h @@ -0,0 +1,136 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_MEDIA_COMPONENT_DATA_H_ +#define BALLISTICA_MEDIA_DATA_MEDIA_COMPONENT_DATA_H_ + +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +/// Base class for loadable media components. +class MediaComponentData : public Object { + public: + MediaComponentData(); + ~MediaComponentData() override; + void Preload(bool already_locked = false); + void Load(bool already_locked = false); + void Unload(bool already_locked = false); + auto preloaded() const -> bool { return preloaded_; } + auto loaded() const -> bool { return preloaded_ && loaded_; } + virtual auto GetMediaType() const -> MediaType = 0; + + // Return name or another identifier. For debugging purposes. + virtual auto GetName() const -> std::string { return "invalid"; } + virtual auto GetNameFull() const -> std::string { return GetName(); } + + // Used to lock asset payloads for modification in a RAII manner. + // FIXME - need to better define the times when payloads need to + // be locked. For instance, we ensure everything is loaded at the + // beginning of drawing a frame, but technically is anything preventing + // it from being unloaded during the draw?.. + class LockGuard { + public: + enum Type { kLock, kInheritLock, kDontLock }; + explicit LockGuard(MediaComponentData* data, Type type = kLock); + ~LockGuard(); + + // Does this guard hold a lock? + auto holds_lock() const -> bool { return holds_lock_; } + + private: + MediaComponentData* data_ = nullptr; + bool holds_lock_ = false; + }; + + // Attempt to lock the component without blocking. returns true if + // successful. In the case of success, use a LockGuard with + // kInheritLock to release the lock. + auto TryLock() -> bool { + bool val = mutex_.try_lock(); + if (val) { + assert(!locked_); + locked_ = true; + } + return val; + } + + auto locked() const -> bool { return locked_; } + auto last_used_time() const -> millisecs_t { return last_used_time_; } + void set_last_used_time(millisecs_t val) { last_used_time_ = val; } + + // Used by the renderer when adding component refs to frame_defs. + auto last_frame_def_num() const -> int64_t { return last_frame_def_num_; } + void set_last_frame_def_num(int64_t last) { last_frame_def_num_ = last; } + auto preload_time() const -> millisecs_t { + return preload_end_time_ - preload_start_time_; + } + auto load_time() const -> millisecs_t { + return load_end_time_ - load_start_time_; + } + + // Sanity testing. + auto valid() const -> bool { return valid_; } + + protected: + // Preload the component's data. This may be called from any thread so must + // be safe regardless (ie: just load data into the component; don't make GL + // calls, etc). + virtual void DoPreload() = 0; + + // This is always called by the main thread that uses the component to finish + // loading. ie: whatever thread is running opengl will call this for textures, + // audio thread for sounds, etc as much heavy lifting as possible should be + // done in DoPreload but interaction with the corresponding api (gl, al, etc) + // is done here. + virtual void DoLoad() = 0; + + // Unload the component. This is always called by the main component thread + // (same as DoLoad). + virtual void DoUnload() = 0; + + // Do we still use/need this? + bool valid_ = false; + + private: + // Lock the component - components must be locked whenever using them. + void Lock() { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + mutex_.lock(); + assert(!locked_); + locked_ = true; + BA_DEBUG_FUNCTION_TIMER_END_THREAD_EX(20, GetName()); + } + + // Unlock the component. each call to lock must be accompanied by one of + // these. + void Unlock() { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + assert(locked_); + locked_ = false; + mutex_.unlock(); + BA_DEBUG_FUNCTION_TIMER_END_THREAD_EX(20, GetName()); + } + + bool locked_ = false; + millisecs_t preload_start_time_ = 0; + millisecs_t preload_end_time_ = 0; + millisecs_t load_start_time_ = 0; + millisecs_t load_end_time_ = 0; + + // We keep track of what frame_def we've been added to so + // we only include a single reference to ourself in it. + int64_t last_frame_def_num_ = 0; + millisecs_t last_used_time_ = 0; + bool preloaded_ = false; + bool loaded_ = false; + std::mutex mutex_; + BA_DISALLOW_CLASS_COPIES(MediaComponentData); +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_MEDIA_COMPONENT_DATA_H_ diff --git a/src/ballistica/media/data/model_data.cc b/src/ballistica/media/data/model_data.cc new file mode 100644 index 00000000..c0081f02 --- /dev/null +++ b/src/ballistica/media/data/model_data.cc @@ -0,0 +1,128 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/model_data.h" + +#include +#include + +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/media/media.h" + +namespace ballistica { + +ModelData::ModelData(const std::string& file_name_in) + : file_name_(file_name_in) { + file_name_full_ = + g_media->FindMediaFile(Media::FileType::kModel, file_name_in); + valid_ = true; +} + +void ModelData::DoPreload() { + // In headless, don't load anything. +#if !BA_HEADLESS_BUILD + + assert(!file_name_.empty()); + FILE* f = g_platform->FOpen(file_name_full_.c_str(), "rb"); + if (!f) { + throw Exception("Can't open model: '" + file_name_full_ + "'"); + } + + // We currently read/write in little-endian since that's all we run on at the + // moment. +#if WORDS_BIGENDIAN +#error FIX THIS FOR BIG ENDIAN +#endif + + uint32_t version; + if (fread(&version, sizeof(version), 1, f) != 1) { + throw Exception("Error reading file header for '" + file_name_full_ + "'"); + } + if (version != kBobFileID) { + throw Exception("File: '" + file_name_full_ + + "' is an old format or not a bob file (got id " + + std::to_string(version) + ", " + + std::to_string(kBobFileID) + ")"); + } + + uint32_t mesh_format; + if (fread(&mesh_format, sizeof(mesh_format), 1, f) != 1) { + throw Exception("Error reading mesh_format for '" + file_name_full_ + "'"); + } + format_ = static_cast(mesh_format); + BA_PRECONDITION((format_ == MeshFormat::kUV16N8Index8) + || (format_ == MeshFormat::kUV16N8Index16) + || (format_ == MeshFormat::kUV16N8Index32)); + + uint32_t vertex_count; + if (fread(&vertex_count, sizeof(vertex_count), 1, f) != 1) { + throw Exception("Error reading vertex_count for '" + file_name_full_ + "'"); + } + + uint32_t face_count; + if (fread(&face_count, sizeof(face_count), 1, f) != 1) { + throw Exception("Error reading face_count for '" + file_name_full_ + "'"); + } + + vertices_.resize(vertex_count); + if (fread(&(vertices_[0]), vertices_.size() * sizeof(VertexObjectFull), 1, f) + != 1) { + throw Exception("Read failed for " + file_name_full_); + } + switch (GetIndexSize()) { + case 1: { + indices8_.resize(face_count * 3); + if (fread(indices8_.data(), indices8_.size() * sizeof(uint8_t), 1, f) + != 1) { + throw Exception("Read failed for " + file_name_full_); + } + break; + } + case 2: { + indices16_.resize(face_count * 3); + if (fread(indices16_.data(), indices16_.size() * sizeof(uint16_t), 1, f) + != 1) { + throw Exception("Read failed for " + file_name_full_); + } + break; + } + case 4: { + indices32_.resize(face_count * 3); + if (fread(indices32_.data(), indices32_.size() * sizeof(uint32_t), 1, f) + != 1) { + throw Exception("Read failed for " + file_name_full_); + } + break; + } + default: + throw Exception(); + } + + fclose(f); + +#endif // BA_HEADLESS_BUILD +} + +void ModelData::DoLoad() { + assert(!renderer_data_.exists()); + renderer_data_ = Object::MakeRefCounted( + g_graphics_server->renderer()->NewModelData(*this)); + + // once we're loaded lets free up our vert data memory + std::vector().swap(vertices_); + std::vector().swap(indices8_); + std::vector().swap(indices16_); + std::vector().swap(indices32_); +} + +void ModelData::DoUnload() { + assert(valid_); + assert(renderer_data_.exists()); + std::vector().swap(vertices_); + std::vector().swap(indices8_); + std::vector().swap(indices16_); + std::vector().swap(indices32_); + renderer_data_.Clear(); +} + +} // namespace ballistica diff --git a/src/ballistica/media/data/model_data.h b/src/ballistica/media/data/model_data.h new file mode 100644 index 00000000..cb155c6c --- /dev/null +++ b/src/ballistica/media/data/model_data.h @@ -0,0 +1,67 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_MODEL_DATA_H_ +#define BALLISTICA_MEDIA_DATA_MODEL_DATA_H_ + +#include +#include + +#include "ballistica/media/data/media_component_data.h" +#include "ballistica/media/data/model_renderer_data.h" + +namespace ballistica { + +class ModelData : public MediaComponentData { + public: + ModelData() = default; + explicit ModelData(const std::string& file_name_in); + void DoPreload() override; + void DoLoad() override; + void DoUnload() override; + auto GetMediaType() const -> MediaType override { return MediaType::kModel; } + auto GetName() const -> std::string override { + if (!file_name_full_.empty()) { + return file_name_full_; + } else { + return "invalid Model"; + } + } + auto renderer_data() const -> ModelRendererData* { + assert(renderer_data_.exists()); + return renderer_data_.get(); + } + auto vertices() const -> const std::vector& { + return vertices_; + } + auto indices8() const -> const std::vector& { return indices8_; } + auto indices16() const -> const std::vector& { return indices16_; } + auto indices32() const -> const std::vector& { return indices32_; } + auto GetIndexSize() const -> int { + switch (format_) { + case MeshFormat::kUV16N8Index8: + return 1; + case MeshFormat::kUV16N8Index16: + return 2; + case MeshFormat::kUV16N8Index32: + return 4; + default: + throw Exception(); + } + } + + private: + Object::Ref renderer_data_; + std::string file_name_; + std::string file_name_full_; + MeshFormat format_{}; + std::vector vertices_; + std::vector indices8_; + std::vector indices16_; + std::vector indices32_; + friend class ModelRendererData; + BA_DISALLOW_CLASS_COPIES(ModelData); +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_MODEL_DATA_H_ diff --git a/src/ballistica/media/data/model_renderer_data.h b/src/ballistica/media/data/model_renderer_data.h new file mode 100644 index 00000000..ad23080a --- /dev/null +++ b/src/ballistica/media/data/model_renderer_data.h @@ -0,0 +1,21 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_MODEL_RENDERER_DATA_H_ +#define BALLISTICA_MEDIA_DATA_MODEL_RENDERER_DATA_H_ + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Renderer-specific data (gl display list, etc) +// this is provided by the renderer +class ModelRendererData : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kMain; + } +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_MODEL_RENDERER_DATA_H_ diff --git a/src/ballistica/media/data/sound_data.cc b/src/ballistica/media/data/sound_data.cc new file mode 100644 index 00000000..a9048843 --- /dev/null +++ b/src/ballistica/media/data/sound_data.cc @@ -0,0 +1,322 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/sound_data.h" + +#include + +#include + +#if BA_ENABLE_AUDIO +#if BA_USE_TREMOR_VORBIS +#include "ivorbisfile.h" // NOLINT +#else +#include +#endif +#endif // BA_ENABLE_AUDIO + +#include +#include + +#include "ballistica/audio/audio_server.h" +#include "ballistica/media/media.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +// Need to move away from OpenAL on Apple stuff. +#if __clang__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +namespace ballistica { + +#if BA_ENABLE_AUDIO + +const int kReadBufferSize = 32768; // 32 KB buffers + +static auto CallbackRead(void* ptr, size_t size, size_t nmemb, + void* data_source) -> size_t { + return fread(ptr, size, nmemb, static_cast(data_source)); +} +static auto CallbackSeek(void* data_source, ogg_int64_t offset, int whence) + -> int { + return fseek(static_cast(data_source), + static_cast_check_fit(offset), whence); // NOLINT +} +static auto CallbackClose(void* data_source) -> int { + return fclose(static_cast(data_source)); +} +static long CallbackTell(void* data_source) { // NOLINT (vorbis uses long) + return ftell(static_cast(data_source)); +} + +// This function loads a .ogg file into a memory buffer and returns +// the format and frequency. return value is true on success or false if a +// fallback was used +static auto LoadOgg(const char* file_name, std::vector* buffer, + ALenum* format, ALsizei* freq) -> bool { + int bit_stream; + int bytes; + char array[kReadBufferSize]; // Local fixed size array + FILE* f; + bool fallback = false; + + // Open for binary reading. + f = g_platform->FOpen(file_name, "rb"); + if (f == nullptr) { + fallback = true; + Log(std::string("Error: Can't open sound file '") + file_name + + "' for reading..."); + + // Attempt a fallback standin; if that doesn't work, throw in the towel. + file_name = "data/global/audio/blank.ogg"; + f = g_platform->FOpen(file_name, "rb"); + if (f == nullptr) + throw Exception(std::string("Can't open fallback sound file '") + + file_name + "' for reading..."); + } + + vorbis_info* p_info; + OggVorbis_File ogg_file; + ov_callbacks callbacks; + callbacks.read_func = CallbackRead; + callbacks.seek_func = CallbackSeek; + callbacks.close_func = CallbackClose; + callbacks.tell_func = CallbackTell; + + // Try opening the given file + if (ov_open_callbacks(f, &ogg_file, nullptr, 0, callbacks) != 0) { + Log(std::string("Error decoding sound file '") + file_name + "'"); + + fclose(f); + + // Attempt fallback. + file_name = "data/global/audio/blank.ogg"; + f = g_platform->FOpen(file_name, "rb"); + + // If fallback doesn't work, throw in the towel. + if (f == nullptr) + throw Exception(std::string("Can't open fallback sound file '") + + file_name + "' for reading..."); + if (ov_open_callbacks(f, &ogg_file, nullptr, 0, callbacks) != 0) + throw Exception(std::string("Error decoding fallback sound file '") + + file_name + "'"); + } + + // Get some information about the OGG file. + p_info = ov_info(&ogg_file, -1); + + // Check the number of channels. Always use 16-bit samples. + if (p_info->channels == 1) { + (*format) = AL_FORMAT_MONO16; + } else { + (*format) = AL_FORMAT_STEREO16; + } + + // The frequency of the sampling rate. + (*freq) = static_cast(p_info->rate); + + bool corrupt = false; + + // Keep reading until all is read. + do { + // Read up to a buffer's worth of decoded sound data. +#if BA_USE_TREMOR_VORBIS + bytes = static_cast( + ov_read(&ogg_file, array, kReadBufferSize, &bit_stream)); +#else + bytes = static_cast( + ov_read(&ogg_file, array, kReadBufferSize, 0, 2, 1, &bit_stream)); +#endif + + // If something went wrong in the decode, just spit out an empty sound and + // an error message that the user should re-install. + if (bytes < 0) { + corrupt = true; + ov_clear(&ogg_file); + break; + } + + // Append to end of buffer + buffer->insert(buffer->end(), array, array + bytes); + } while (bytes > 0); + + // Clean up! + ov_clear(&ogg_file); + + if (corrupt) { + static bool reported_corrupt = false; + if (!reported_corrupt) { + reported_corrupt = true; + g_python->PushObjCall(Python::ObjID::kPrintCorruptFileErrorCall); + } + (*buffer) = std::vector(32 * 100, 0); + } + + if ((*buffer).empty()) { + throw Exception(std::string("Error: got zero-length buffer from ogg-file '") + + file_name + "'"); + } + return !fallback; +} + +static void LoadCachedOgg(const char* file_name, std::vector* buffer, + ALenum* format, ALsizei* freq) { + std::string sound_cache_dir = + g_platform->GetConfigDirectory() + "/audiocache"; + static bool made_sound_cache_dir = false; + if (!made_sound_cache_dir) { + g_platform->MakeDir(sound_cache_dir); + made_sound_cache_dir = true; + } + std::vector b(strlen(file_name) + 1); + memcpy(b.data(), file_name, b.size()); + for (char* c = &b[0]; *c != 0; c++) { + if ((*c) == '/') *c = '_'; + } + std::string cache_file_name = sound_cache_dir + "/" + &b[0] + ".cache"; + + // If we have a cache file and it matches the mod time on the ogg, attempt to + // load it. + struct BA_STAT stat_ogg {}; + time_t ogg_mod_time = 0; + if (g_platform->Stat(file_name, &stat_ogg) == 0) { + ogg_mod_time = stat_ogg.st_mtime; + } + FILE* f_cache = g_platform->FOpen(cache_file_name.c_str(), "rb"); + if (f_cache && ogg_mod_time != 0) { + bool got_cache = false; + time_t cache_mod_time; + if (fread(&cache_mod_time, sizeof(cache_mod_time), 1, f_cache) == 1) { + if (cache_mod_time == ogg_mod_time) { + if (fread(&(*format), sizeof((*format)), 1, f_cache) == 1) { + if (fread(&(*freq), sizeof((*freq)), 1, f_cache) == 1) { + uint32_t buffer_size; + if (fread(&buffer_size, sizeof(buffer_size), 1, f_cache) == 1) { + (*buffer).resize(buffer_size); + if (fread(&(*buffer)[0], buffer_size, 1, f_cache) == 1) { + got_cache = true; + } + } + } + } + } + } + fclose(f_cache); + if (got_cache) { + // At a loss for how this happened, but wound up loading cache files + // with invalid formats of 0 once. Report and ignore if we see + // something like that. + if (*format != AL_FORMAT_MONO16 && *format != AL_FORMAT_STEREO16) { + Log(std::string("Ignoring invalid audio cache of ") + file_name + + " with format " + std::to_string(*format)); + } else { + return; // SUCCESS!!!! + } + } + } + + // Ok that didn't work. Load the actual ogg. + (*buffer).clear(); + bool success = LoadOgg(file_name, buffer, format, freq); + + // If the load went cleanly, attempt to write a cache file. + if (success) { + FILE* f = g_platform->FOpen(cache_file_name.c_str(), "wb"); + bool success2 = false; + if (f) { + if (fwrite(&ogg_mod_time, sizeof(ogg_mod_time), 1, f) == 1) { + if (fwrite(&(*format), sizeof((*format)), 1, f) == 1) { + if (fwrite(&(*freq), sizeof((*freq)), 1, f) == 1) { + auto buffer_size = static_cast((*buffer).size()); + if (fwrite(&buffer_size, sizeof(buffer_size), 1, f) == 1) { + if (fwrite(&(*buffer)[0], buffer_size, 1, f) == 1) { + success2 = true; + } + } + } + } + } + fclose(f); + + // Attempt to clean up if it looks like something went wrong. + if (!success2) { + g_platform->Unlink(cache_file_name.c_str()); + } + } + } +} + +#endif // BA_ENABLE_AUDIO + +SoundData::SoundData(const std::string& file_name_in) + : file_name_(file_name_in), + is_streamed_(false), +#if BA_ENABLE_AUDIO + buffer_(0), +#endif // BA_ENABLE_AUDIO + last_play_time_(0) { + file_name_full_ = + g_media->FindMediaFile(Media::FileType::kSound, file_name_in); + valid_ = true; +} + +void SoundData::DoPreload() { +#if BA_ENABLE_AUDIO + + // Its an ogg sound file. + // if it has 'music' in its name, we'll stream it; + // otherwise we load it in its entirety into our load-buffer. + if (strstr(file_name_full_.c_str(), "Music.ogg")) { + is_streamed_ = true; + } else if (strstr(file_name_full_.c_str(), ".ogg")) { + is_streamed_ = false; + LoadCachedOgg(file_name_full_.c_str(), &load_buffer_, &format_, &freq_); + } else { + throw Exception("Unsupported sound file (needs to end in .ogg): '" + + file_name_full_ + "'"); + } +#endif // BA_ENABLE_AUDIO +} + +void SoundData::DoLoad() { + assert(InAudioThread()); + assert(valid_); + +#if BA_ENABLE_AUDIO + assert(!g_audio_server->paused()); + + // Note: streamed sources create buffers as they're used; not here. + if (!is_streamed_) { + // Generate our buffer. + CHECK_AL_ERROR; + alGenBuffers(1, &buffer_); + CHECK_AL_ERROR; + + // Preload pulled data into our load-buffer, and send that along to openal. + alBufferData(buffer_, format_, &load_buffer_[0], + static_cast(load_buffer_.size()), freq_); + + CHECK_AL_ERROR; + + // Done with load buffer; clear its used memory. + std::vector().swap(load_buffer_); + } + + CHECK_AL_ERROR; +#endif // BA_ENABLE_AUDIO +} + +void SoundData::DoUnload() { + assert(valid_); + assert(InAudioThread()); +#if BA_ENABLE_AUDIO + if (!is_streamed_) { + assert(buffer_); + CHECK_AL_ERROR; + alDeleteBuffers(1, &buffer_); + CHECK_AL_ERROR; + } +#endif // BA_ENABLE_AUDIO +} + +} // namespace ballistica diff --git a/src/ballistica/media/data/sound_data.h b/src/ballistica/media/data/sound_data.h new file mode 100644 index 00000000..f1bc3092 --- /dev/null +++ b/src/ballistica/media/data/sound_data.h @@ -0,0 +1,58 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_SOUND_DATA_H_ +#define BALLISTICA_MEDIA_DATA_SOUND_DATA_H_ + +#include +#include + +#include "ballistica/audio/al_sys.h" +#include "ballistica/media/data/media_component_data.h" + +namespace ballistica { + +class SoundData : public MediaComponentData { + public: + SoundData() = default; + explicit SoundData(const std::string& file_name_in); + void DoPreload() override; + void DoLoad() override; + + // FIXME: Should make sure the sound_data isn't in use before unloading it. + void DoUnload() override; + auto GetMediaType() const -> MediaType override { return MediaType::kSound; } + auto GetName() const -> std::string override { + if (!file_name_full_.empty()) + return file_name_full_; + else + return "invalid sound"; + } +#if BA_ENABLE_AUDIO + auto format() const -> ALenum { return format_; } + auto buffer() const -> ALuint { + assert(!is_streamed_); + return buffer_; + } +#endif // BA_ENABLE_AUDIO + auto is_streamed() const -> bool { return is_streamed_; } + auto file_name() const -> const std::string& { return file_name_; } + auto file_name_full() const -> const std::string& { return file_name_full_; } + void UpdatePlayTime() { last_play_time_ = GetRealTime(); } + auto last_play_time() const -> millisecs_t { return last_play_time_; } + + private: + std::string file_name_; + std::string file_name_full_; + bool is_streamed_{}; +#if BA_ENABLE_AUDIO + ALuint buffer_{}; + ALenum format_{}; + ALsizei freq_{}; +#endif // BA_ENABLE_AUDIO + std::vector load_buffer_; + millisecs_t last_play_time_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_SOUND_DATA_H_ diff --git a/src/ballistica/media/data/texture_data.cc b/src/ballistica/media/data/texture_data.cc new file mode 100644 index 00000000..0b43a6e1 --- /dev/null +++ b/src/ballistica/media/data/texture_data.cc @@ -0,0 +1,450 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/texture_data.h" + +#include +#include +#include +#include + +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/graphics/text/text_packer.h" +#include "ballistica/graphics/texture/dds.h" +#include "ballistica/graphics/texture/ktx.h" +#include "ballistica/graphics/texture/pvr.h" +#include "ballistica/media/data/texture_preload_data.h" +#include "ballistica/media/data/texture_renderer_data.h" +#include "ballistica/media/media.h" +#include "external/qr_code_generator/QrCode.hpp" + +namespace ballistica { + +static void rgba8888_unpremultiply_in_place(void* src, size_t cb) { + // Compute the actual number of pixel elements in the buffer. + size_t cpel = cb / 4; + auto* psrc = static_cast(src); + auto* pdst = static_cast(src); + for (size_t i = 0; i < cpel; i++) { + int r = *psrc++; + int g = *psrc++; + int b = *psrc++; + int a = *psrc++; + if (a == 0) { + *pdst++ = 255; + *pdst++ = 255; + *pdst++ = 255; + *pdst++ = 0; + } else { + *pdst++ = static_cast_check_fit(std::min(255, r * 255 / a)); + *pdst++ = static_cast_check_fit(std::min(255, g * 255 / a)); + *pdst++ = static_cast_check_fit(std::min(255, b * 255 / a)); + *pdst++ = static_cast_check_fit(a); + } + } +} + +TextureData::TextureData() = default; +TextureData::TextureData(const std::string& file_in, TextureType type_in, + TextureMinQuality min_quality_in) + : file_name_(file_in), type_(type_in), min_quality_(min_quality_in) { + file_name_full_ = g_media->FindMediaFile(Media::FileType::kTexture, file_in); + valid_ = true; +} + +TextureData::TextureData(TextPacker* packer) : packer_(packer) { + file_name_ = packer->hash(); + valid_ = true; +} + +TextureData::TextureData(const std::string& qr_url) : is_qr_code_(true) { + file_name_ = qr_url; + valid_ = true; +} + +TextureData::~TextureData() = default; + +void TextureData::DoPreload() { + assert(valid_); + + assert(g_graphics_server + && g_graphics_server->texture_compression_types_are_set()); + + // We figure out which LOD should be our base level based on quality. + TextureQuality texture_quality = g_graphics_server->texture_quality(); + + // If we're a text-texture. + if (packer_.exists()) { + assert(type_ == TextureType::k2D); + + int width = packer_->texture_width(); + int height = packer_->texture_height(); + float quality_scale = 1.0f; + + if (texture_quality == TextureQuality::kMedium) { + width /= 2; + height /= 2; + quality_scale *= 0.5f; + } else if (texture_quality == TextureQuality::kLow) { + width /= 4; + height /= 4; + quality_scale *= 0.25f; + } + float scale = packer_->text_scale() * quality_scale; + + std::vector strings; + std::vector positions; + std::vector visible_widths; + + int index = 0; + const std::list& spans = packer_->spans(); + for (const auto& span : spans) { + strings.push_back(span.string); + positions.push_back(span.tex_x * quality_scale); + positions.push_back(span.tex_y * quality_scale); + visible_widths.push_back((span.bounds.r - span.bounds.l)); + index++; + } + + assert(!strings.empty()); + assert(strings.size() * 2 == positions.size()); + + void* tex_ref{g_platform->CreateTextTexture( + width, height, strings, positions, visible_widths, scale)}; + uint8_t* pixels{g_platform->GetTextTextureData(tex_ref)}; + + assert(pixels); + assert(tex_ref); + + // For now just copy it over to our local 32 bit buffer. + // As an optimization we could convert it to RGBA4444 on the fly or perhaps + // even just alpha if there's no non-white colors present. + // NOTE: This data is also coming in premultiplied (on apple at least) so we + // need to take care of that. + preload_datas_.resize(1); + assert(width >= 0 && height >= 0); + size_t buffer_size = + static_cast(width) * static_cast(height) * 4u; + auto* buffer = static_cast(malloc(buffer_size)); + preload_datas_[0].buffers[0] = buffer; + memcpy(buffer, pixels, buffer_size); + rgba8888_unpremultiply_in_place(buffer, buffer_size); + preload_datas_[0].widths[0] = width; + preload_datas_[0].heights[0] = height; + preload_datas_[0].formats[0] = TextureFormat::kRGBA_8888; + preload_datas_[0].base_level = 0; + + g_platform->FreeTextTexture(tex_ref); + + // Downsample this down to rgba4444 in-place. + TexturePreloadData::rgba8888_to_rgba4444_in_place(buffer, buffer_size); + preload_datas_[0].formats[0] = TextureFormat::kRGBA_4444; + + } else if (is_qr_code_) { + const qrcodegen::QrCode qr2{qrcodegen::QrCode::encodeText( + file_name_.c_str(), qrcodegen::QrCode::Ecc::HIGH)}; + int qr_size = qr2.getSize(); + + int width = 512; + int height = 512; + preload_datas_.resize(1); + assert(width >= 0 && height >= 0); + size_t buffer_size = + static_cast(width) * static_cast(height) * 2u; + auto* buffer = static_cast(malloc(buffer_size)); + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + float xf = static_cast(x) / static_cast(width); + float yf = static_cast(y) / static_cast(height); + uint16_t* dst = buffer + width * y + x; + int x2 = static_cast( + floor((xf - 0.05f) * (static_cast(qr_size) * 1.1f))); + int y2 = static_cast( + floor((yf - 0.05f) * (static_cast(qr_size) * 1.1f))); + if (x2 >= 0 && x2 < qr_size && y2 >= 0 && y2 < qr_size + && qr2.getModule(x2, y2)) { + *dst = 0; + } else { + *dst = 0xffff; + } + } + } + preload_datas_[0].buffers[0] = reinterpret_cast(buffer); + preload_datas_[0].widths[0] = width; + preload_datas_[0].heights[0] = height; + preload_datas_[0].formats[0] = TextureFormat::kRGB_565; + preload_datas_[0].base_level = 0; + } else { + if (type_ == TextureType::k2D) { + preload_datas_.resize(1); + + int file_name_size = static_cast(file_name_full_.size()); + BA_PRECONDITION(file_name_size > 4); + + // Etc1 or dxt3 for non-alpha and dxt5 for alpha (.android_dds files). + if (file_name_size > 12 + && !strcmp(file_name_full_.c_str() + file_name_size - 12, + ".android_dds")) { +#if BA_ENABLE_OPENGL + LoadDDS(file_name_full_, preload_datas_[0].buffers, + preload_datas_[0].widths, preload_datas_[0].heights, + preload_datas_[0].formats, preload_datas_[0].sizes, + texture_quality, static_cast(min_quality_), + &preload_datas_[0].base_level); +#else + throw Exception(); +#endif + + // We should only be loading this if we support etc1 in hardware. + assert(g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC1)); + + // Decompress dxt1/dxt5 ones if we don't natively support S3TC. + if (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kS3TC)) { + if ((preload_datas_[0].formats[preload_datas_[0].base_level] + == TextureFormat::kDXT5) + || (preload_datas_[0].formats[preload_datas_[0].base_level] + == TextureFormat::kDXT1)) { + preload_datas_[0].ConvertToUncompressed(this); + } + } + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".dds")) { + // Dxt1 for non-alpha and dxt5 for alpha (.dds files). +#if BA_ENABLE_OPENGL + LoadDDS(file_name_full_, preload_datas_[0].buffers, + preload_datas_[0].widths, preload_datas_[0].heights, + preload_datas_[0].formats, preload_datas_[0].sizes, + texture_quality, static_cast(min_quality_), + &preload_datas_[0].base_level); +#else + throw Exception(); +#endif + + // Decompress dxt1/dxt5 if we don't natively support it. + if (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kS3TC)) { + preload_datas_[0].ConvertToUncompressed(this); + } + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".ktx")) { + // Etc2 or etc1 for non-alpha and etc2 for alpha (.ktx files). + try { +#if BA_ENABLE_OPENGL + LoadKTX(file_name_full_, preload_datas_[0].buffers, + preload_datas_[0].widths, preload_datas_[0].heights, + preload_datas_[0].formats, preload_datas_[0].sizes, + texture_quality, static_cast(min_quality_), + &preload_datas_[0].base_level); +#else + throw Exception(); +#endif + } catch (const std::exception& e) { + throw Exception("Error loading file '" + file_name_full_ + + "': " + e.what()); + } + + // Decompress etc2 if we don't natively support it. + if (((preload_datas_[0].formats[preload_datas_[0].base_level] + == TextureFormat::kETC2_RGB) + || (preload_datas_[0].formats[preload_datas_[0].base_level] + == TextureFormat::kETC2_RGBA)) + && (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC2))) { + preload_datas_[0].ConvertToUncompressed(this); + } + + // Decompress etc1 if we don't natively support it. + if ((preload_datas_[0].formats[preload_datas_[0].base_level] + == TextureFormat::kETC1) + && (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC1))) { + preload_datas_[0].ConvertToUncompressed(this); + } + + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".pvr")) { + // Pvr for all (.pvr files). + LoadPVR(file_name_full_, preload_datas_[0].buffers, + preload_datas_[0].widths, preload_datas_[0].heights, + preload_datas_[0].formats, preload_datas_[0].sizes, + texture_quality, static_cast(min_quality_), + &preload_datas_[0].base_level); + + // We should only be loading this if we support pvr in hardware. + assert(g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kPVR)); + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".nop")) { + // Dummy path for headless; nothing to do here. + } else { + throw Exception("Invalid texture file name: '" + file_name_full_ + "'"); + } + + } else if (type_ == TextureType::kCubeMap) { + preload_datas_.resize(6); + std::string name; + int file_name_size = static_cast(file_name_full_.size()); + BA_PRECONDITION(file_name_size > 4); + for (int d = 0; d < 6; d++) { + name = file_name_full_; + switch (d) { + case 0: + name.replace(name.find('#'), 1, "_+x"); + break; + case 1: + name.replace(name.find('#'), 1, "_-x"); + break; + case 2: + name.replace(name.find('#'), 1, "_+y"); + break; + case 3: + name.replace(name.find('#'), 1, "_-y"); + break; + case 4: + name.replace(name.find('#'), 1, "_+z"); + break; + case 5: + name.replace(name.find('#'), 1, "_-z"); + break; + default: + throw Exception(); + } + + // Etc1 or dxt3 for non-alpha and dxt5 for alpha (.android_dds files). + if (file_name_size > 12 + && !strcmp(file_name_full_.c_str() + file_name_size - 12, + ".android_dds")) { + try { +#if BA_ENABLE_OPENGL + LoadDDS(name, preload_datas_[d].buffers, preload_datas_[d].widths, + preload_datas_[d].heights, preload_datas_[d].formats, + preload_datas_[d].sizes, texture_quality, + static_cast(min_quality_), + &preload_datas_[d].base_level); +#else + throw Exception(); +#endif + } catch (const std::exception& e) { + throw Exception("Error loading file '" + file_name_full_ + + "': " + e.what()); + } + + // We should only be loading this if we support etc1 in hardware. + assert(g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC1)); + + // Decompress dxt1/dxt5 ones if we don't natively support S3TC. + if (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kS3TC)) { + if ((preload_datas_[d].formats[preload_datas_[d].base_level] + == TextureFormat::kDXT5) + || (preload_datas_[d].formats[preload_datas_[d].base_level] + == TextureFormat::kDXT1)) { + preload_datas_[d].ConvertToUncompressed(this); + } + } + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".dds")) { +#if BA_ENABLE_OPENGL + // Dxt1 for non-alpha and dxt5 for alpha (.dds files). + LoadDDS(name, preload_datas_[d].buffers, preload_datas_[d].widths, + preload_datas_[d].heights, preload_datas_[d].formats, + preload_datas_[d].sizes, texture_quality, + static_cast(min_quality_), + &preload_datas_[d].base_level); +#else + throw Exception(); +#endif + + // Decompress dxt1/dxt5 if we don't natively support it. + if (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kS3TC)) { + preload_datas_[d].ConvertToUncompressed(this); + } + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".ktx")) { + // Etc2 or etc1 for non-alpha and etc2 for alpha (.ktx files) +#if BA_ENABLE_OPENGL + LoadKTX(name, preload_datas_[d].buffers, preload_datas_[d].widths, + preload_datas_[d].heights, preload_datas_[d].formats, + preload_datas_[d].sizes, texture_quality, + static_cast(min_quality_), + &preload_datas_[d].base_level); +#else + throw Exception(); +#endif + + // Decompress etc2 ones if we don't natively support them. + if (((preload_datas_[d].formats[preload_datas_[d].base_level] + == TextureFormat::kETC2_RGB) + || (preload_datas_[d].formats[preload_datas_[d].base_level] + == TextureFormat::kETC2_RGBA)) + && (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC2))) { + preload_datas_[d].ConvertToUncompressed(this); + } + + // Decompress etc1 if we don't natively support it. + if ((preload_datas_[d].formats[preload_datas_[d].base_level] + == TextureFormat::kETC1) + && (!g_graphics_server->SupportsTextureCompressionType( + TextureCompressionType::kETC1))) { + preload_datas_[d].ConvertToUncompressed(this); + } + + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".pvr")) { + // Pvr for both non-alpha and alpha (.pvr files). + try { + LoadPVR(name, preload_datas_[d].buffers, preload_datas_[d].widths, + preload_datas_[d].heights, preload_datas_[d].formats, + preload_datas_[d].sizes, texture_quality, + static_cast(min_quality_), + &preload_datas_[d].base_level); + } catch (const std::exception& e) { + throw Exception("Error loading file '" + file_name_full_ + + "': " + e.what()); + } + } else if (!strcmp(file_name_full_.c_str() + file_name_size - 4, + ".nop")) { + // Dummy path for headless; nothing to do here. + } else { + throw Exception("Invalid texture file name: '" + file_name_full_ + + "'"); + } + } + } else { + throw Exception("unknown texture type"); + } + } +} + +void TextureData::DoLoad() { + assert(InGraphicsThread()); + assert(!renderer_data_.exists()); + renderer_data_ = Object::MakeRefCounted( + g_graphics_server->renderer()->NewTextureData(*this)); + assert(renderer_data_.exists()); + renderer_data_->Load(); + + // Store our base-level from the preload-data so we know if we're lower than + // full quality. + assert(!preload_datas_.empty()); + base_level_ = preload_datas_[0].base_level; + + // If we're done, kill our preload data. + preload_datas_.clear(); +} + +void TextureData::DoUnload() { + assert(InGraphicsThread()); + assert(valid_); + assert(renderer_data_.exists()); + renderer_data_.Clear(); + base_level_ = 0; +} + +} // namespace ballistica diff --git a/src/ballistica/media/data/texture_data.h b/src/ballistica/media/data/texture_data.h new file mode 100644 index 00000000..1083f101 --- /dev/null +++ b/src/ballistica/media/data/texture_data.h @@ -0,0 +1,62 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_TEXTURE_DATA_H_ +#define BALLISTICA_MEDIA_DATA_TEXTURE_DATA_H_ + +#include +#include + +#include "ballistica/media/data/media_component_data.h" + +namespace ballistica { + +// Loadable texture media component. +class TextureData : public MediaComponentData { + public: + TextureData(); + ~TextureData() override; + + // pass a newly allocated TextPacker pointer here; TextureData takes ownership + // and handles cleaning it up + explicit TextureData(TextPacker* packer); + explicit TextureData(const std::string& file_in, TextureType type_in, + TextureMinQuality min_quality_in); + explicit TextureData(const std::string& qr_url); + auto GetName() const -> std::string override { + return (!file_name_.empty()) ? file_name_ : "invalid texture"; + } + auto GetNameFull() const -> std::string override { return file_name_full(); } + auto file_name() const -> const std::string& { return file_name_; } + auto file_name_full() const -> const std::string& { return file_name_full_; } + auto GetMediaType() const -> MediaType override { + return MediaType::kTexture; + } + void DoPreload() override; + void DoLoad() override; + void DoUnload() override; + auto texture_type() const -> TextureType { return type_; } + auto is_qr_code() const -> bool { return is_qr_code_; } + auto preload_datas() const -> const std::vector& { + return preload_datas_; + } + auto renderer_data() const -> TextureRendererData* { + assert(renderer_data_.exists()); + return renderer_data_.get(); + } + auto base_level() const -> int { return base_level_; } + + private: + Object::Ref packer_; + bool is_qr_code_ = false; + std::string file_name_; + std::string file_name_full_; + std::vector preload_datas_; + TextureType type_ = TextureType::k2D; + TextureMinQuality min_quality_ = TextureMinQuality::kLow; + Object::Ref renderer_data_; + int base_level_ = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_TEXTURE_DATA_H_ diff --git a/src/ballistica/media/data/texture_preload_data.cc b/src/ballistica/media/data/texture_preload_data.cc new file mode 100644 index 00000000..aa78d528 --- /dev/null +++ b/src/ballistica/media/data/texture_preload_data.cc @@ -0,0 +1,577 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/data/texture_preload_data.h" + +#include +#include + +#include "ballistica/graphics/texture/ktx.h" +#include "ballistica/media/component/texture.h" + +namespace ballistica { + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "bugprone-narrowing-conversions" + +#ifndef GL_COMPRESSED_RGB8_ETC2 +#define GL_COMPRESSED_RGB8_ETC2 0x9274 +#endif +#ifndef GL_COMPRESSED_RGBA8_ETC2_EAC +#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278 +#endif +#ifndef GL_ETC1_RGB8_OES +#define GL_ETC1_RGB8_OES 0x8D64 +#endif + +void TexturePreloadData::rgba8888_to_rgba4444_in_place(void* src, size_t cb) { + // Compute the actual number of pixel elements in the buffer. + size_t cpel = cb / 4; + auto* psrc = static_cast(src); + auto* pdst = static_cast(src); + + int r_dither = 0; + int g_dither = 0; + int b_dither = 0; + int a_dither = 0; + + // reset our dithering slightly randomly to reduce + // patterns (might be a smarter way to do this) + int d_reset = rand() % 100; // NOLINT + + // Convert every pixel. + for (size_t i = 0; i < cpel; i++) { + // Read a source pixel. + int pel = psrc[i]; // NOLINT + + // Unpack the source data as 8 bit values. + int r = pel & 0xff; + int g = (pel >> 8) & 0xff; + int b = (pel >> 16) & 0xff; + int a = (pel >> 24) & 0xff; + r = std::min(255, std::max(0, r + r_dither)); + g = std::min(255, std::max(0, g + g_dither)); + b = std::min(255, std::max(0, b + b_dither)); + a = std::min(255, std::max(0, a + a_dither)); + // convert to 4 bit values + int r2 = r >> 4; + int g2 = g >> 4; + int b2 = b >> 4; + int a2 = a >> 4; + + r_dither = r - (r2 << 4); + g_dither = g - (g2 << 4); + b_dither = b - (b2 << 4); + a_dither = a - (a2 << 4); + + d_reset--; + if (d_reset <= 0) { + r_dither = g_dither = b_dither = a_dither = 0; + d_reset = rand() % 100; // NOLINT + } + + pdst[i] = + static_cast_check_fit(a2 | b2 << 4 | g2 << 8 | r2 << 12); + } +} + +static void rgba8888_to_rgb888_in_place(void* src, int cb) { + int i; + + // Compute the actual number of pixel elements in the buffer. + int cpel = cb / 4; + auto* psrc = static_cast(src); + auto* pdst = static_cast(src); + for (i = 0; i < cpel; i++) { + *pdst++ = *psrc++; // NOLINT + *pdst++ = *psrc++; + *pdst++ = *psrc++; + psrc++; + } +} + +static void rgb888_to_rgb565_in_place(void* src, size_t cb) { + // compute the actual number of pixel elements in the buffer. + size_t cpel = cb / 3; + auto* psrc = static_cast(src); + auto* pdst = static_cast(src); + + int r_dither = 0; + int g_dither = 0; + int b_dither = 0; + + // reset our dithering slightly randomly to reduce + // patterns (might be a smarter way to do this) + int d_reset = rand() % 100; // NOLINT + + // convert every pixel + for (size_t i = 0; i < cpel; i++) { + // read a source pixel + int r = *psrc++; // NOLINT + int g = *psrc++; + int b = *psrc++; + // unpack the source data as 8 bit values + r = std::min(255, std::max(0, r + r_dither)); + g = std::min(255, std::max(0, g + g_dither)); + b = std::min(255, std::max(0, b + b_dither)); + + // convert to 565 + int r2 = r >> 3; + int g2 = g >> 2; + int b2 = b >> 3; + + r_dither = r - (r2 << 3); + g_dither = g - (g2 << 2); + b_dither = b - (b2 << 3); + + d_reset--; + if (d_reset <= 0) { + r_dither = g_dither = b_dither = 0; + d_reset = rand() % 100; // NOLINT + } + + *pdst++ = static_cast_check_fit(b2 | g2 << 5 | r2 << 11); + } +} + +// ----------------------------------------------------------------------------- +// S3TC DXT1 / DXT5 Texture Decompression Routines +// Author: Benjamin Dobell - http://www.glassechidna.com.au +// +// Feel free to use these methods in any open-source, freeware or commercial +// projects. It's not necessary to credit me however I would be grateful if you +// chose to do so. I'll also be very interested to hear what projects make use +// of this code. Feel free to drop me a line via the contact form on the Glass +// Echidna website. +// +// NOTE: The code was written for a little endian system where sizeof(int32_t) +// == 4. +// ----------------------------------------------------------------------------- + +// uint32_t PackRGBA(): Helper method that packs RGBA channels into a single 4 +// byte pixel. +// +// unsigned char r: red channel. +// unsigned char g: green channel. +// unsigned char b: blue channel. +// unsigned char a: alpha channel. + +static auto PackRGBA(unsigned char r, unsigned char g, unsigned char b, + unsigned char a) -> uint32_t { + return ((a << 24) | (b << 16) | (g << 8) | r); +} + +// void DecompressBlockDXT1(): Decompresses one block of a DXT1 texture and +// stores the resulting pixels at the appropriate offset in 'image'. +// +// uint32_t x: x-coordinate of the +// first pixel in the block. uint32_t y: y-coordinate of the first pixel in the +// block. uint32_t width: width of the texture being decompressed. uint32_t +// height: height of the texture being decompressed. const unsigned char +// *blockStorage: pointer to the block to decompress. uint32_t *image: +// pointer to image where the decompressed pixel data should be stored. +static void DecompressBlockDXT1(uint32_t x, uint32_t y, uint32_t width, + uint32_t height, + const unsigned char* block_storage, + uint32_t* image) { + uint16_t color0, color1; + memcpy(&color0, block_storage, sizeof(color0)); + memcpy(&color1, block_storage + 2, sizeof(color1)); + + uint32_t temp; + + temp = (color0 >> 11u) * 255u + 16u; + auto r0 = (unsigned char)((temp / 32u + temp) / 32u); + temp = ((color0 & 0x07E0u) >> 5u) * 255u + 32u; + auto g0 = (unsigned char)((temp / 64u + temp) / 64u); + temp = (color0 & 0x001Fu) * 255u + 16u; + auto b0 = (unsigned char)((temp / 32 + temp) / 32); + + temp = (color1 >> 11u) * 255u + 16u; + auto r1 = (unsigned char)((temp / 32u + temp) / 32u); + temp = ((color1 & 0x07E0u) >> 5u) * 255u + 32u; + auto g1 = (unsigned char)((temp / 64u + temp) / 64u); + temp = (color1 & 0x001Fu) * 255u + 16u; + auto b1 = (unsigned char)((temp / 32u + temp) / 32u); + + uint32_t code = *reinterpret_cast(block_storage + 4); + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + uint32_t final_color = 0; + auto positionCode = + static_cast((code >> 2 * (4 * j + i)) & 0x03); + + if (color0 > color1) { + switch (positionCode) { + case 0: + final_color = PackRGBA(r0, g0, b0, 255); + break; + case 1: + final_color = PackRGBA(r1, g1, b1, 255); + break; + case 2: + final_color = + PackRGBA(static_cast((2 * r0 + r1) / 3), + static_cast((2 * g0 + g1) / 3), + static_cast((2 * b0 + b1) / 3), 255); + break; + case 3: + final_color = + PackRGBA(static_cast((r0 + 2 * r1) / 3), + static_cast((g0 + 2 * g1) / 3), + static_cast((b0 + 2 * b1) / 3), 255); + break; + default: + break; + } + } else { + switch (positionCode) { + case 0: + final_color = PackRGBA(r0, g0, b0, 255); + break; + case 1: + final_color = PackRGBA(r1, g1, b1, 255); + break; + case 2: + final_color = PackRGBA(static_cast((r0 + r1) / 2), + static_cast((g0 + g1) / 2), + static_cast((b0 + b1) / 2), 255); + break; + case 3: + final_color = PackRGBA(0, 0, 0, 255); + break; + default: + break; + } + } + if ((x + i < width) && (y + j < height)) { + image[(y + j) * width + (x + i)] = final_color; + } + } + } +} + +// void BlockDecompressImageDXT1(): Decompresses all the blocks of a DXT1 +// compressed texture and stores the resulting pixels in 'image'. +// +// uint32_t width: Texture width. +// uint32_t height: Texture height. +// const unsigned char *block_storage: pointer to compressed DXT1 blocks. +// uint32_t *image: pointer to the image where the +// decompressed pixels will be stored. + +static void BlockDecompressImageDXT1(uint32_t width, uint32_t height, + const unsigned char* block_storage, + uint32_t* image) { + uint32_t block_count_x = (width + 3) / 4; + uint32_t block_count_y = (height + 3) / 4; + // uint32_t blockWidth = (width < 4) ? width : 4; + // uint32_t blockHeight = (height < 4) ? height : 4; + + for (uint32_t j = 0; j < block_count_y; j++) { + for (uint32_t i = 0; i < block_count_x; i++) { + DecompressBlockDXT1(i * 4, j * 4, width, height, block_storage + i * 8, + image); + } + block_storage += block_count_x * 8; + } +} + +// void DecompressBlockDXT5(): Decompresses one block of a DXT5 texture and +// stores the resulting pixels at the appropriate offset in 'image'. +// +// uint32_t x: x-coordinate of the +// first pixel in the block. uint32_t y: y-coordinate of the first pixel in the +// block. uint32_t width: width of the texture being decompressed. uint32_t +// height: height of the texture being decompressed. const unsigned char +// *block_storage: pointer to the block to decompress. uint32_t *image: +// pointer to image where the decompressed pixel data should be stored. + +static void DecompressBlockDXT5(uint32_t x, uint32_t y, uint32_t width, + uint32_t height, const uint8_t* block_storage, + uint32_t* image) { + uint8_t alpha0 = *block_storage; + uint8_t alpha1 = *(block_storage + 1); + + const uint8_t* bits = block_storage + 2; + uint32_t alpha_code_1 = + bits[2] | (bits[3] << 8) | (bits[4] << 16) | (bits[5] << 24); + uint16_t alpha_code_2 = bits[0] | (bits[1] << 8); + + uint16_t color0, color1; + memcpy(&color0, block_storage + 8, sizeof(color0)); + memcpy(&color1, block_storage + 10, sizeof(color1)); + + uint32_t temp; + + temp = (color0 >> 11u) * 255u + 16u; + auto r0 = (uint8_t)((temp / 32u + temp) / 32u); + temp = ((color0 & 0x07E0u) >> 5u) * 255u + 32u; + auto g0 = (uint8_t)((temp / 64u + temp) / 64u); + temp = (color0 & 0x001Fu) * 255u + 16u; + auto b0 = (uint8_t)((temp / 32u + temp) / 32u); + + temp = (color1 >> 11u) * 255u + 16u; + auto r1 = (uint8_t)((temp / 32u + temp) / 32u); + temp = ((color1 & 0x07E0u) >> 5u) * 255u + 32u; + auto g1 = (uint8_t)((temp / 64u + temp) / 64u); + temp = (color1 & 0x001Fu) * 255u + 16u; + auto b1 = (uint8_t)((temp / 32u + temp) / 32u); + + uint32_t code = *reinterpret_cast(block_storage + 12); + + for (int j = 0; j < 4; j++) { + for (int i = 0; i < 4; i++) { + int alpha_code_index = 3 * (4 * j + i); + int alpha_code; + + if (alpha_code_index <= 12) { + alpha_code = (alpha_code_2 >> alpha_code_index) & 0x07; + } else if (alpha_code_index == 15) { + // NOLINTNEXTLINE + alpha_code = (alpha_code_2 >> 15) | ((alpha_code_1 << 1) & 0x06); + } else { + // NOLINTNEXTLINE + alpha_code = (alpha_code_1 >> (alpha_code_index - 16)) & 0x07; + } + + uint8_t final_alpha; + if (alpha_code == 0) { + final_alpha = alpha0; + } else if (alpha_code == 1) { + final_alpha = alpha1; + } else { + if (alpha0 > alpha1) { + final_alpha = static_cast( + ((8 - alpha_code) * alpha0 + (alpha_code - 1) * alpha1) / 7); + } else { + if (alpha_code == 6) { + final_alpha = 0; + } else if (alpha_code == 7) { + final_alpha = 255; + } else { + final_alpha = static_cast( + ((6 - alpha_code) * alpha0 + (alpha_code - 1) * alpha1) / 5); + } + } + } + + auto colorCode = static_cast((code >> 2 * (4 * j + i)) & 0x03); + + uint32_t final_color = 0; + switch (colorCode) { + case 0: + final_color = PackRGBA(r0, g0, b0, final_alpha); + break; + case 1: + final_color = PackRGBA(r1, g1, b1, final_alpha); + break; + case 2: + final_color = + PackRGBA(static_cast((2 * r0 + r1) / 3), + static_cast((2 * g0 + g1) / 3), + static_cast((2 * b0 + b1) / 3), final_alpha); + break; + case 3: + final_color = + PackRGBA(static_cast((r0 + 2 * r1) / 3), + static_cast((g0 + 2 * g1) / 3), + static_cast((b0 + 2 * b1) / 3), final_alpha); + break; + default: + break; + } + + if ((x + i < width) && (y + j < height)) { + image[(y + j) * width + (x + i)] = final_color; + } + } + } +} + +static void BlockDecompressImageDXT5(uint32_t width, uint32_t height, + const uint8_t* block_storage, + uint32_t* image) { + uint32_t block_count_x = (width + 3) / 4; + uint32_t block_count_y = (height + 3) / 4; + for (uint32_t j = 0; j < block_count_y; j++) { + for (uint32_t i = 0; i < block_count_x; i++) + DecompressBlockDXT5(i * 4, j * 4, width, height, block_storage + i * 16, + image); + block_storage += block_count_x * 16; + } +} + +void TexturePreloadData::ConvertToUncompressed(TextureData* texture) { + // FIXME; we could technically get better quality on our + // lower mip levels by dynamically generating them in this + // case instead of decompressing each level. + for (int i = 0; i < kMaxTextureLevels; i++) { + // Convert all non-empty texture slots. + if (formats[i] != TextureFormat::kNone) { + if (formats[i] == TextureFormat::kDXT1) { + // Lets go 32 bit for now. + uint8_t* old_buffer = buffers[i]; + assert(widths[i] >= 0 && heights[i] >= 0); + size_t b_size = static_cast(widths[i]) + * static_cast(heights[i]) * 4u; + auto* new_buffer = static_cast(malloc(b_size)); + assert(new_buffer); + buffers[i] = new_buffer; + formats[i] = TextureFormat::kRGBA_8888; + BlockDecompressImageDXT1(static_cast(widths[i]), + static_cast(heights[i]), old_buffer, + reinterpret_cast(new_buffer)); + free(reinterpret_cast(old_buffer)); + + // Ok; this gave us RGBA data, but we don't need the A since DXT1 has no + // alpha.. + rgba8888_to_rgb888_in_place(buffers[i], widths[i] * heights[i] * 4); + formats[i] = TextureFormat::kRGB_888; + } else if (formats[i] == TextureFormat::kDXT5) { + // lets go 32 bit for now + uint8_t* old_buffer = buffers[i]; + assert(widths[i] >= 0 && heights[i] >= 0); + size_t b_size = static_cast(widths[i]) + * static_cast(heights[i]) * 4u; + auto* new_buffer = static_cast(malloc(b_size)); + assert(new_buffer); + buffers[i] = new_buffer; + formats[i] = TextureFormat::kRGBA_8888; + BlockDecompressImageDXT5(static_cast(widths[i]), + static_cast(heights[i]), old_buffer, + reinterpret_cast(new_buffer)); + free(reinterpret_cast(old_buffer)); + } else if (formats[i] == TextureFormat::kETC2_RGBA) { + // Let's go 32 bit for now. + uint8_t* old_buffer = buffers[i]; + uint8_t* new_buffer = nullptr; + + if (explicit_bool(true)) { +#if BA_ENABLE_OPENGL + unsigned int format; + unsigned int internal_format; + unsigned int type; + KTXUnpackETC(old_buffer, GL_COMPRESSED_RGBA8_ETC2_EAC, + static_cast(widths[i]), + static_cast(heights[i]), &new_buffer, &format, + &internal_format, &type, 0, false); +#else + throw Exception(); +#endif // BA_ENABLE_OPENGL + } else { + assert(widths[i] >= 0 && heights[i] >= 0); + size_t b_size = static_cast(widths[i]) + * static_cast(heights[i]) * 4u; + new_buffer = static_cast(malloc(b_size)); + } + BA_PRECONDITION(new_buffer); + buffers[i] = new_buffer; + formats[i] = TextureFormat::kRGBA_8888; + free(reinterpret_cast(old_buffer)); + } else if (formats[i] == TextureFormat::kETC2_RGB) { + // lets go 32 bit for now + uint8_t* old_buffer = buffers[i]; + uint8_t* new_buffer = nullptr; +#if BA_ENABLE_OPENGL + unsigned int format; + unsigned int internal_format; + unsigned int type; + if (explicit_bool(true)) { + KTXUnpackETC(old_buffer, GL_COMPRESSED_RGB8_ETC2, + static_cast(widths[i]), + static_cast(heights[i]), &new_buffer, &format, + &internal_format, &type, 0, false); + } else { + assert(widths[i] >= 0 && heights[i] >= 0); + size_t b_size = static_cast(widths[i]) + * static_cast(heights[i]) * 3u; + new_buffer = static_cast(malloc(b_size)); + } +#else + throw Exception(); +#endif // BA_ENABLE_OPENGL + BA_PRECONDITION(new_buffer); + buffers[i] = new_buffer; + formats[i] = TextureFormat::kRGB_888; + free(reinterpret_cast(old_buffer)); + } else if (formats[i] == TextureFormat::kETC1) { + // lets go 32 bit for now + uint8_t* old_buffer = buffers[i]; + uint8_t* new_buffer = nullptr; +#if BA_ENABLE_OPENGL + unsigned int format; + unsigned int internal_format; + unsigned int type; + if (explicit_bool(true)) { + KTXUnpackETC(old_buffer, GL_ETC1_RGB8_OES, + static_cast(widths[i]), + static_cast(heights[i]), &new_buffer, &format, + &internal_format, &type, 0, false); + } else { + assert(widths[i] >= 0 && heights[i] >= 0); + size_t b_size = static_cast(widths[i]) + * static_cast(heights[i]) * 3u; + new_buffer = static_cast(malloc(b_size)); + memset(new_buffer, 128, b_size); + } +#else + throw Exception(); +#endif + BA_PRECONDITION(new_buffer); + buffers[i] = new_buffer; + formats[i] = TextureFormat::kRGB_888; + free(reinterpret_cast(old_buffer)); + } else { + throw Exception("Can't convert tex format " + + std::to_string(static_cast(formats[i])) + + " to uncompressed"); + } + + // ok, for RGBA stuff let's go ahead and convert to dithered 4444 instead + // of 8888 (the exception is cube-maps; we want to keep those as high + // bitdepth as possible since dithering is quite noticeable in + // reflections) + if (formats[i] == TextureFormat::kRGBA_8888 + && texture->texture_type() != TextureType::kCubeMap) { + assert(widths[i] >= 0 && heights[i] >= 0); + size_t buffer_size = static_cast(widths[i]) + * static_cast(heights[i]) * 4u; + rgba8888_to_rgba4444_in_place(buffers[i], buffer_size); + formats[i] = TextureFormat::kRGBA_4444; + } + + // convert RGB 888 to RGB 565 to get our sizes down a bit + // (again, make an exception for cube-maps) + if (formats[i] == TextureFormat::kRGB_888 + && texture->texture_type() != TextureType::kCubeMap) { + assert(widths[i] >= 0 && heights[i] >= 0); + size_t buffer_size = static_cast(widths[i]) + * static_cast(heights[i]) * 3u; + rgb888_to_rgb565_in_place(buffers[i], buffer_size); + formats[i] = TextureFormat::kRGB_565; + } + + // ok; nowadays for uncompressed stuff we just load the top level + // and generate the rest on the gpu. This should give us nicer + // quality than decompressed lower-level mip images would + // and is hopefully faster too.. + // HMMM actually the quality argument may be iffy in cases where + // we're dithering.. (or maybe not?) + break; + } + } +} + +TexturePreloadData::~TexturePreloadData() { + for (auto& buffer : buffers) { + if (buffer) { + free(buffer); + } + } +} + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/media/data/texture_preload_data.h b/src/ballistica/media/data/texture_preload_data.h new file mode 100644 index 00000000..db0454df --- /dev/null +++ b/src/ballistica/media/data/texture_preload_data.h @@ -0,0 +1,40 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_TEXTURE_PRELOAD_DATA_H_ +#define BALLISTICA_MEDIA_DATA_TEXTURE_PRELOAD_DATA_H_ + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// Determined by the biggest tex dimension we support (current 4096). +// FIXME: Should define that dimension as a constant somewhere. +const int kMaxTextureLevels = 14; + +// Temporary data that is passed along to the renderer when creating +// rendererdata. This may include sdl surfaces and/or compressed buffers. +class TexturePreloadData { + public: + static void rgba8888_to_rgba4444_in_place(void* src, size_t cb); + + TexturePreloadData() { + // There isn't a way to do this in bracket-init, is there? + // (aside from writing out all values manually I mean). + for (auto& format : formats) { + format = TextureFormat::kNone; + } + } + ~TexturePreloadData(); + void ConvertToUncompressed(TextureData* texture); + + uint8_t* buffers[kMaxTextureLevels]{}; + size_t sizes[kMaxTextureLevels]{}; + TextureFormat formats[kMaxTextureLevels]{}; + int widths[kMaxTextureLevels]{}; + int heights[kMaxTextureLevels]{}; + int base_level{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_TEXTURE_PRELOAD_DATA_H_ diff --git a/src/ballistica/media/data/texture_renderer_data.h b/src/ballistica/media/data/texture_renderer_data.h new file mode 100644 index 00000000..ca7a71de --- /dev/null +++ b/src/ballistica/media/data/texture_renderer_data.h @@ -0,0 +1,27 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_DATA_TEXTURE_RENDERER_DATA_H_ +#define BALLISTICA_MEDIA_DATA_TEXTURE_RENDERER_DATA_H_ + +namespace ballistica { + +// Renderer-specific data (gl tex, etc) +// this is extended by the renderer +class TextureRendererData : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kMain; + } + + // Create the renderer data but don't load it in yet. + TextureRendererData() = default; + + // load the data. + // if incremental is true, return whether the load was completed + // (non-incremental loads should always complete) + virtual void Load() = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_DATA_TEXTURE_RENDERER_DATA_H_ diff --git a/src/ballistica/media/media.cc b/src/ballistica/media/media.cc new file mode 100644 index 00000000..0f80f5f9 --- /dev/null +++ b/src/ballistica/media/media.cc @@ -0,0 +1,1251 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/media.h" + +#if !BA_OSTYPE_WINDOWS +#include +#endif + +#include +#include + +#include "ballistica/audio/audio_server.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/timer.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/text/text_packer.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/media/component/data.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/media/data/data_data.h" +#include "ballistica/media/data/sound_data.h" +#include "ballistica/media/media_server.h" +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +// Debug printing. +#define BA_SHOW_LOADS_UNLOADS 0 +#define SHOW_PRUNING_INFO 0 + +// Standard prune time for unused media: 10 minutes (1000ms * 60 * 10). +#define STANDARD_MEDIA_PRUNE_TIME 600000 + +// More aggressive prune time for dynamically-generated text-textures: 10 +// seconds. +#define TEXT_TEXTURE_PRUNE_TIME 10000 + +#define QR_TEXTURE_PRUNE_TIME 10000 + +// How long we should spend loading media in each runPendingLoads() call. +#define PENDING_LOAD_PROCESS_TIME 5 + +void Media::Init() { + // Just create our singleton. + assert(g_media == nullptr); + g_media = new Media(); +} + +Media::Media() { + media_paths_.emplace_back("ba_data"); + for (bool& have_pending_load : have_pending_loads_) { + have_pending_load = false; + } +} + +void Media::LoadSystemTexture(SystemTextureID id, const char* name) { + assert(media_lists_locked_); + system_textures_.push_back(GetTextureData(name)); + assert(system_textures_.size() == static_cast(id) + 1); +} + +void Media::LoadSystemCubeMapTexture(SystemCubeMapTextureID id, + const char* name) { + assert(media_lists_locked_); + system_cube_map_textures_.push_back(GetCubeMapTextureData(name)); + assert(system_cube_map_textures_.size() == static_cast(id) + 1); +} + +void Media::LoadSystemSound(SystemSoundID id, const char* name) { + system_sounds_.push_back(GetSoundData(name)); + assert(system_sounds_.size() == static_cast(id) + 1); +} + +void Media::LoadSystemData(SystemDataID id, const char* name) { + system_datas_.push_back(GetDataData(name)); + assert(system_datas_.size() == static_cast(id) + 1); +} + +void Media::LoadSystemModel(SystemModelID id, const char* name) { + system_models_.push_back(GetModelData(name)); + assert(system_models_.size() == static_cast(id) + 1); +} + +void Media::LoadSystemMedia() { + assert(InGameThread()); + assert(g_audio_server && g_media_server && g_graphics_server); + assert(g_graphics_server + && g_graphics_server->texture_compression_types_are_set()); + assert(g_graphics && g_graphics_server->texture_quality_set()); + + // Just grab the lock once for all this stuff for efficiency. + MediaListsLock lock; + + // System textures: + LoadSystemTexture(SystemTextureID::kUIAtlas, "uiAtlas"); + LoadSystemTexture(SystemTextureID::kButtonSquare, "buttonSquare"); + LoadSystemTexture(SystemTextureID::kWhite, "white"); + LoadSystemTexture(SystemTextureID::kFontSmall0, "fontSmall0"); + LoadSystemTexture(SystemTextureID::kFontBig, "fontBig"); + LoadSystemTexture(SystemTextureID::kCursor, "cursor"); + LoadSystemTexture(SystemTextureID::kBoxingGlove, "boxingGlovesColor"); + LoadSystemTexture(SystemTextureID::kShield, "shield"); + LoadSystemTexture(SystemTextureID::kExplosion, "explosion"); + LoadSystemTexture(SystemTextureID::kTextClearButton, "textClearButton"); + LoadSystemTexture(SystemTextureID::kWindowHSmallVMed, "windowHSmallVMed"); + LoadSystemTexture(SystemTextureID::kWindowHSmallVSmall, "windowHSmallVSmall"); + LoadSystemTexture(SystemTextureID::kGlow, "glow"); + LoadSystemTexture(SystemTextureID::kScrollWidget, "scrollWidget"); + LoadSystemTexture(SystemTextureID::kScrollWidgetGlow, "scrollWidgetGlow"); + LoadSystemTexture(SystemTextureID::kFlagPole, "flagPoleColor"); + LoadSystemTexture(SystemTextureID::kScorch, "scorch"); + LoadSystemTexture(SystemTextureID::kScorchBig, "scorchBig"); + LoadSystemTexture(SystemTextureID::kShadow, "shadow"); + LoadSystemTexture(SystemTextureID::kLight, "light"); + LoadSystemTexture(SystemTextureID::kShadowSharp, "shadowSharp"); + LoadSystemTexture(SystemTextureID::kLightSharp, "lightSharp"); + LoadSystemTexture(SystemTextureID::kShadowSoft, "shadowSoft"); + LoadSystemTexture(SystemTextureID::kLightSoft, "lightSoft"); + LoadSystemTexture(SystemTextureID::kSparks, "sparks"); + LoadSystemTexture(SystemTextureID::kEye, "eyeColor"); + LoadSystemTexture(SystemTextureID::kEyeTint, "eyeColorTintMask"); + LoadSystemTexture(SystemTextureID::kFuse, "fuse"); + LoadSystemTexture(SystemTextureID::kShrapnel1, "shrapnel1Color"); + LoadSystemTexture(SystemTextureID::kSmoke, "smoke"); + LoadSystemTexture(SystemTextureID::kCircle, "circle"); + LoadSystemTexture(SystemTextureID::kCircleOutline, "circleOutline"); + LoadSystemTexture(SystemTextureID::kCircleNoAlpha, "circleNoAlpha"); + LoadSystemTexture(SystemTextureID::kCircleOutlineNoAlpha, + "circleOutlineNoAlpha"); + LoadSystemTexture(SystemTextureID::kCircleShadow, "circleShadow"); + LoadSystemTexture(SystemTextureID::kSoftRect, "softRect"); + LoadSystemTexture(SystemTextureID::kSoftRect2, "softRect2"); + LoadSystemTexture(SystemTextureID::kSoftRectVertical, "softRectVertical"); + LoadSystemTexture(SystemTextureID::kStartButton, "startButton"); + LoadSystemTexture(SystemTextureID::kBombButton, "bombButton"); + LoadSystemTexture(SystemTextureID::kOuyaAButton, "ouyaAButton"); + LoadSystemTexture(SystemTextureID::kBackIcon, "backIcon"); + LoadSystemTexture(SystemTextureID::kNub, "nub"); + LoadSystemTexture(SystemTextureID::kArrow, "arrow"); + LoadSystemTexture(SystemTextureID::kMenuButton, "menuButton"); + LoadSystemTexture(SystemTextureID::kUsersButton, "usersButton"); + LoadSystemTexture(SystemTextureID::kActionButtons, "actionButtons"); + LoadSystemTexture(SystemTextureID::kTouchArrows, "touchArrows"); + LoadSystemTexture(SystemTextureID::kTouchArrowsActions, "touchArrowsActions"); + LoadSystemTexture(SystemTextureID::kRGBStripes, "rgbStripes"); + LoadSystemTexture(SystemTextureID::kUIAtlas2, "uiAtlas2"); + LoadSystemTexture(SystemTextureID::kFontSmall1, "fontSmall1"); + LoadSystemTexture(SystemTextureID::kFontSmall2, "fontSmall2"); + LoadSystemTexture(SystemTextureID::kFontSmall3, "fontSmall3"); + LoadSystemTexture(SystemTextureID::kFontSmall4, "fontSmall4"); + LoadSystemTexture(SystemTextureID::kFontSmall5, "fontSmall5"); + LoadSystemTexture(SystemTextureID::kFontSmall6, "fontSmall6"); + LoadSystemTexture(SystemTextureID::kFontSmall7, "fontSmall7"); + LoadSystemTexture(SystemTextureID::kFontExtras, "fontExtras"); + LoadSystemTexture(SystemTextureID::kFontExtras2, "fontExtras2"); + LoadSystemTexture(SystemTextureID::kFontExtras3, "fontExtras3"); + LoadSystemTexture(SystemTextureID::kFontExtras4, "fontExtras4"); + LoadSystemTexture(SystemTextureID::kCharacterIconMask, "characterIconMask"); + LoadSystemTexture(SystemTextureID::kBlack, "black"); + LoadSystemTexture(SystemTextureID::kWings, "wings"); + + // System cube map textures: + LoadSystemCubeMapTexture(SystemCubeMapTextureID::kReflectionChar, + "reflectionChar#"); + LoadSystemCubeMapTexture(SystemCubeMapTextureID::kReflectionPowerup, + "reflectionPowerup#"); + LoadSystemCubeMapTexture(SystemCubeMapTextureID::kReflectionSoft, + "reflectionSoft#"); + LoadSystemCubeMapTexture(SystemCubeMapTextureID::kReflectionSharp, + "reflectionSharp#"); + LoadSystemCubeMapTexture(SystemCubeMapTextureID::kReflectionSharper, + "reflectionSharper#"); + LoadSystemCubeMapTexture(SystemCubeMapTextureID::kReflectionSharpest, + "reflectionSharpest#"); + + // System sounds: + LoadSystemSound(SystemSoundID::kDeek, "deek"); + LoadSystemSound(SystemSoundID::kBlip, "blip"); + LoadSystemSound(SystemSoundID::kBlank, "blank"); + LoadSystemSound(SystemSoundID::kPunch, "punch01"); + LoadSystemSound(SystemSoundID::kClick, "click01"); + LoadSystemSound(SystemSoundID::kErrorBeep, "error"); + LoadSystemSound(SystemSoundID::kSwish, "swish"); + LoadSystemSound(SystemSoundID::kSwish2, "swish2"); + LoadSystemSound(SystemSoundID::kSwish3, "swish3"); + LoadSystemSound(SystemSoundID::kTap, "tap"); + LoadSystemSound(SystemSoundID::kCorkPop, "corkPop"); + LoadSystemSound(SystemSoundID::kGunCock, "gunCocking"); + LoadSystemSound(SystemSoundID::kTickingCrazy, "tickingCrazy"); + LoadSystemSound(SystemSoundID::kSparkle, "sparkle01"); + LoadSystemSound(SystemSoundID::kSparkle2, "sparkle02"); + LoadSystemSound(SystemSoundID::kSparkle3, "sparkle03"); + + // System datas: + // (crickets) + + // System models: + LoadSystemModel(SystemModelID::kButtonSmallTransparent, + "buttonSmallTransparent"); + LoadSystemModel(SystemModelID::kButtonSmallOpaque, "buttonSmallOpaque"); + LoadSystemModel(SystemModelID::kButtonMediumTransparent, + "buttonMediumTransparent"); + LoadSystemModel(SystemModelID::kButtonMediumOpaque, "buttonMediumOpaque"); + LoadSystemModel(SystemModelID::kButtonBackTransparent, + "buttonBackTransparent"); + LoadSystemModel(SystemModelID::kButtonBackOpaque, "buttonBackOpaque"); + LoadSystemModel(SystemModelID::kButtonBackSmallTransparent, + "buttonBackSmallTransparent"); + LoadSystemModel(SystemModelID::kButtonBackSmallOpaque, + "buttonBackSmallOpaque"); + LoadSystemModel(SystemModelID::kButtonTabTransparent, "buttonTabTransparent"); + LoadSystemModel(SystemModelID::kButtonTabOpaque, "buttonTabOpaque"); + LoadSystemModel(SystemModelID::kButtonLargeTransparent, + "buttonLargeTransparent"); + LoadSystemModel(SystemModelID::kButtonLargeOpaque, "buttonLargeOpaque"); + LoadSystemModel(SystemModelID::kButtonLargerTransparent, + "buttonLargerTransparent"); + LoadSystemModel(SystemModelID::kButtonLargerOpaque, "buttonLargerOpaque"); + LoadSystemModel(SystemModelID::kButtonSquareTransparent, + "buttonSquareTransparent"); + LoadSystemModel(SystemModelID::kButtonSquareOpaque, "buttonSquareOpaque"); + LoadSystemModel(SystemModelID::kCheckTransparent, "checkTransparent"); + LoadSystemModel(SystemModelID::kScrollBarThumbTransparent, + "scrollBarThumbTransparent"); + LoadSystemModel(SystemModelID::kScrollBarThumbOpaque, "scrollBarThumbOpaque"); + LoadSystemModel(SystemModelID::kScrollBarThumbSimple, "scrollBarThumbSimple"); + LoadSystemModel(SystemModelID::kScrollBarThumbShortTransparent, + "scrollBarThumbShortTransparent"); + LoadSystemModel(SystemModelID::kScrollBarThumbShortOpaque, + "scrollBarThumbShortOpaque"); + LoadSystemModel(SystemModelID::kScrollBarThumbShortSimple, + "scrollBarThumbShortSimple"); + LoadSystemModel(SystemModelID::kScrollBarTroughTransparent, + "scrollBarTroughTransparent"); + LoadSystemModel(SystemModelID::kTextBoxTransparent, "textBoxTransparent"); + LoadSystemModel(SystemModelID::kImage1x1, "image1x1"); + LoadSystemModel(SystemModelID::kImage1x1FullScreen, "image1x1FullScreen"); + LoadSystemModel(SystemModelID::kImage2x1, "image2x1"); + LoadSystemModel(SystemModelID::kImage4x1, "image4x1"); + LoadSystemModel(SystemModelID::kImage16x1, "image16x1"); +#if BA_VR_BUILD + LoadSystemModel(SystemModelID::kImage1x1VRFullScreen, "image1x1VRFullScreen"); + LoadSystemModel(SystemModelID::kVROverlay, "vrOverlay"); + LoadSystemModel(SystemModelID::kVRFade, "vrFade"); +#endif // BA_VR_BUILD + LoadSystemModel(SystemModelID::kOverlayGuide, "overlayGuide"); + LoadSystemModel(SystemModelID::kWindowHSmallVMedTransparent, + "windowHSmallVMedTransparent"); + LoadSystemModel(SystemModelID::kWindowHSmallVMedOpaque, + "windowHSmallVMedOpaque"); + LoadSystemModel(SystemModelID::kWindowHSmallVSmallTransparent, + "windowHSmallVSmallTransparent"); + LoadSystemModel(SystemModelID::kWindowHSmallVSmallOpaque, + "windowHSmallVSmallOpaque"); + LoadSystemModel(SystemModelID::kSoftEdgeOutside, "softEdgeOutside"); + LoadSystemModel(SystemModelID::kSoftEdgeInside, "softEdgeInside"); + LoadSystemModel(SystemModelID::kBoxingGlove, "boxingGlove"); + LoadSystemModel(SystemModelID::kShield, "shield"); + LoadSystemModel(SystemModelID::kFlagPole, "flagPole"); + LoadSystemModel(SystemModelID::kFlagStand, "flagStand"); + LoadSystemModel(SystemModelID::kScorch, "scorch"); + LoadSystemModel(SystemModelID::kEyeBall, "eyeBall"); + LoadSystemModel(SystemModelID::kEyeBallIris, "eyeBallIris"); + LoadSystemModel(SystemModelID::kEyeLid, "eyeLid"); + LoadSystemModel(SystemModelID::kHairTuft1, "hairTuft1"); + LoadSystemModel(SystemModelID::kHairTuft1b, "hairTuft1b"); + LoadSystemModel(SystemModelID::kHairTuft2, "hairTuft2"); + LoadSystemModel(SystemModelID::kHairTuft3, "hairTuft3"); + LoadSystemModel(SystemModelID::kHairTuft4, "hairTuft4"); + LoadSystemModel(SystemModelID::kShrapnel1, "shrapnel1"); + LoadSystemModel(SystemModelID::kShrapnelSlime, "shrapnelSlime"); + LoadSystemModel(SystemModelID::kShrapnelBoard, "shrapnelBoard"); + LoadSystemModel(SystemModelID::kShockWave, "shockWave"); + LoadSystemModel(SystemModelID::kFlash, "flash"); + LoadSystemModel(SystemModelID::kCylinder, "cylinder"); + LoadSystemModel(SystemModelID::kArrowFront, "arrowFront"); + LoadSystemModel(SystemModelID::kArrowBack, "arrowBack"); + LoadSystemModel(SystemModelID::kActionButtonLeft, "actionButtonLeft"); + LoadSystemModel(SystemModelID::kActionButtonTop, "actionButtonTop"); + LoadSystemModel(SystemModelID::kActionButtonRight, "actionButtonRight"); + LoadSystemModel(SystemModelID::kActionButtonBottom, "actionButtonBottom"); + LoadSystemModel(SystemModelID::kBox, "box"); + LoadSystemModel(SystemModelID::kLocator, "locator"); + LoadSystemModel(SystemModelID::kLocatorBox, "locatorBox"); + LoadSystemModel(SystemModelID::kLocatorCircle, "locatorCircle"); + LoadSystemModel(SystemModelID::kLocatorCircleOutline, "locatorCircleOutline"); + LoadSystemModel(SystemModelID::kCrossOut, "crossOut"); + LoadSystemModel(SystemModelID::kWing, "wing"); + + // Hooray! + system_media_loaded_ = true; +} + +Media::~Media() = default; + +void Media::PrintLoadInfo() { + std::string s; + char buffer[256]; + int num = 1; + + // Need to lock lists while iterating over them. + MediaListsLock lock; + s = "Media load results: (all times in milliseconds):\n"; + snprintf(buffer, sizeof(buffer), " %-50s %10s %10s", "FILE", + "PRELOAD_TIME", "LOAD_TIME"); + s += buffer; + Log(s, true, false); + millisecs_t total_preload_time = 0; + millisecs_t total_load_time = 0; + assert(media_lists_locked_); + for (auto&& i : models_) { + millisecs_t preload_time = i.second->preload_time(); + millisecs_t load_time = i.second->load_time(); + total_preload_time += preload_time; + total_load_time += load_time; + snprintf(buffer, sizeof(buffer), "%-3d %-50s %10d %10d", num, + i.second->GetName().c_str(), + static_cast_check_fit(preload_time), + static_cast_check_fit(load_time)); + Log(buffer, true, false); + num++; + } + assert(media_lists_locked_); + for (auto&& i : collide_models_) { + millisecs_t preload_time = i.second->preload_time(); + millisecs_t load_time = i.second->load_time(); + total_preload_time += preload_time; + total_load_time += load_time; + snprintf(buffer, sizeof(buffer), "%-3d %-50s %10d %10d", num, + i.second->GetName().c_str(), + static_cast_check_fit(preload_time), + static_cast_check_fit(load_time)); + Log(buffer, true, false); + num++; + } + assert(media_lists_locked_); + for (auto&& i : sounds_) { + millisecs_t preload_time = i.second->preload_time(); + millisecs_t load_time = i.second->load_time(); + total_preload_time += preload_time; + total_load_time += load_time; + snprintf(buffer, sizeof(buffer), "%-3d %-50s %10d %10d", num, + i.second->GetName().c_str(), + static_cast_check_fit(preload_time), + static_cast_check_fit(load_time)); + Log(buffer, true, false); + num++; + } + assert(media_lists_locked_); + for (auto&& i : datas_) { + millisecs_t preload_time = i.second->preload_time(); + millisecs_t load_time = i.second->load_time(); + total_preload_time += preload_time; + total_load_time += load_time; + snprintf(buffer, sizeof(buffer), "%-3d %-50s %10d %10d", num, + i.second->GetName().c_str(), + static_cast_check_fit(preload_time), + static_cast_check_fit(load_time)); + Log(buffer, true, false); + num++; + } + assert(media_lists_locked_); + for (auto&& i : textures_) { + millisecs_t preload_time = i.second->preload_time(); + millisecs_t load_time = i.second->load_time(); + total_preload_time += preload_time; + total_load_time += load_time; + snprintf(buffer, sizeof(buffer), "%-3d %-50s %10d %10d", num, + i.second->file_name_full().c_str(), + static_cast_check_fit(preload_time), + static_cast_check_fit(load_time)); + Log(buffer, true, false); + num++; + } + snprintf(buffer, sizeof(buffer), + "Total preload time (loading data from disk): %i\nTotal load time " + "(feeding data to OpenGL, etc): %i", + static_cast(total_preload_time), + static_cast(total_load_time)); + Log(buffer, true, false); +} + +void Media::MarkAllMediaForLoad() { + assert(InGameThread()); + + // Need to keep lists locked while iterating over them. + MediaListsLock m_lock; + for (auto&& i : textures_) { + if (!i.second->preloaded()) { + MediaComponentData::LockGuard lock(i.second.get()); + have_pending_loads_[static_cast(MediaType::kTexture)] = true; + MarkComponentForLoad(i.second.get()); + } + } + for (auto&& i : text_textures_) { + if (!i.second->preloaded()) { + MediaComponentData::LockGuard lock(i.second.get()); + have_pending_loads_[static_cast(MediaType::kTexture)] = true; + MarkComponentForLoad(i.second.get()); + } + } + for (auto&& i : qr_textures_) { + if (!i.second->preloaded()) { + MediaComponentData::LockGuard lock(i.second.get()); + have_pending_loads_[static_cast(MediaType::kTexture)] = true; + MarkComponentForLoad(i.second.get()); + } + } + for (auto&& i : models_) { + if (!i.second->preloaded()) { + MediaComponentData::LockGuard lock(i.second.get()); + have_pending_loads_[static_cast(MediaType::kModel)] = true; + MarkComponentForLoad(i.second.get()); + } + } +} + +// Call this from the graphics thread to immediately unload all +// media used by it. (for when GL context gets lost, etc). +void Media::UnloadRendererBits(bool do_textures, bool do_models) { + assert(InGraphicsThread()); + // need to keep lists locked while iterating over them.. + MediaListsLock m_lock; + if (do_textures) { + assert(media_lists_locked_); + for (auto&& i : textures_) { + MediaComponentData::LockGuard lock(i.second.get()); + i.second->Unload(true); + } + for (auto&& i : text_textures_) { + MediaComponentData::LockGuard lock(i.second.get()); + i.second->Unload(true); + } + for (auto&& i : qr_textures_) { + MediaComponentData::LockGuard lock(i.second.get()); + i.second->Unload(true); + } + } + if (do_models) { + for (auto&& i : models_) { + MediaComponentData::LockGuard lock(i.second.get()); + i.second->Unload(true); + } + } +} + +auto Media::GetModelData(const std::string& file_name) + -> Object::Ref { + return GetComponentData(file_name, &models_); +} + +auto Media::GetSoundData(const std::string& file_name) + -> Object::Ref { + return GetComponentData(file_name, &sounds_); +} + +auto Media::GetDataData(const std::string& file_name) -> Object::Ref { + return GetComponentData(file_name, &datas_); +} + +auto Media::GetCollideModelData(const std::string& file_name) + -> Object::Ref { + return GetComponentData(file_name, &collide_models_); +} + +template +auto Media::GetComponentData(const std::string& file_name, + std::map >* c_list) + -> Object::Ref { + assert(InGameThread()); + assert(media_lists_locked_); + auto i = c_list->find(file_name); + if (i != c_list->end()) { + return Object::Ref(i->second.get()); + } else { + auto d(Object::New(file_name)); + (*c_list)[file_name] = d; + { + MediaComponentData::LockGuard lock(d.get()); + have_pending_loads_[static_cast(d->GetMediaType())] = true; + MarkComponentForLoad(d.get()); + } + d->set_last_used_time(GetRealTime()); + return d; + } +} + +auto Media::GetTextureData(TextPacker* packer) -> Object::Ref { + assert(InGameThread()); + assert(media_lists_locked_); + const std::string& hash(packer->hash()); + auto i = text_textures_.find(hash); + if (i != text_textures_.end()) { + return Object::Ref(i->second.get()); + } else { + auto d(Object::New(packer)); + text_textures_[hash] = d; + { + MediaComponentData::LockGuard lock(d.get()); + have_pending_loads_[static_cast(d->GetMediaType())] = true; + MarkComponentForLoad(d.get()); + } + d->set_last_used_time(GetRealTime()); + return d; + } +} + +auto Media::GetTextureDataQRCode(const std::string& url) + -> Object::Ref { + assert(InGameThread()); + assert(media_lists_locked_); + auto i = qr_textures_.find(url); + if (i != qr_textures_.end()) { + return Object::Ref(i->second.get()); + } else { + auto d(Object::New(url)); + qr_textures_[url] = d; + { + MediaComponentData::LockGuard lock(d.get()); + have_pending_loads_[static_cast(d->GetMediaType())] = true; + MarkComponentForLoad(d.get()); + } + d->set_last_used_time(GetRealTime()); + return d; + } +} + +// Eww can't recycle GetComponent here since we need extra stuff (tex-type arg) +// ..should fix. +auto Media::GetCubeMapTextureData(const std::string& file_name) + -> Object::Ref { + assert(InGameThread()); + assert(media_lists_locked_); + auto i = textures_.find(file_name); + if (i != textures_.end()) { + return Object::Ref(i->second.get()); + } else { + auto d(Object::New(file_name, TextureType::kCubeMap, + TextureMinQuality::kLow)); + textures_[file_name] = d; + { + MediaComponentData::LockGuard lock(d.get()); + have_pending_loads_[static_cast(d->GetMediaType())] = true; + MarkComponentForLoad(d.get()); + } + d->set_last_used_time(GetRealTime()); + return d; + } +} + +// Eww; can't recycle GetComponent here since we need extra stuff (quality +// settings, etc). Should fix. +auto Media::GetTextureData(const std::string& file_name) + -> Object::Ref { + assert(InGameThread()); + assert(media_lists_locked_); + auto i = textures_.find(file_name); + if (i != textures_.end()) { + return Object::Ref(i->second.get()); + } else { + static std::set* quality_map_medium = nullptr; + static std::set* quality_map_high = nullptr; + static bool quality_maps_inited = false; + + // TEMP - we currently set min quality based on filename; + // in the future this will be stored with the texture package or whatnot + if (!quality_maps_inited) { + quality_maps_inited = true; + quality_map_medium = new std::set(); + quality_map_high = new std::set(); + const char* vals_med[] = { + "fontSmall0", "fontSmall1", "fontSmall2", "fontSmall3", "fontSmall4", + "fontSmall5", "fontSmall6", "fontSmall7", "fontExtras", nullptr}; + + const char* vals_high[] = {"frostyIcon", "jackIcon", "melIcon", + "santaIcon", "ninjaIcon", "neoSpazIcon", + "zoeIcon", "kronkIcon", "scrollWidgetGlow", + "glow", nullptr}; + + for (const char** val3 = vals_med; *val3 != nullptr; val3++) { + quality_map_medium->insert(*val3); + } + for (const char** val2 = vals_high; *val2 != nullptr; val2++) { + quality_map_high->insert(*val2); + } + } + + TextureMinQuality min_quality = TextureMinQuality::kLow; + if (quality_map_medium->find(file_name) != quality_map_medium->end()) { + min_quality = TextureMinQuality::kMedium; + } else if (quality_map_high->find(file_name) != quality_map_high->end()) { + min_quality = TextureMinQuality::kHigh; + } + + auto d(Object::New(file_name, TextureType::k2D, min_quality)); + textures_[file_name] = d; + { + MediaComponentData::LockGuard lock(d.get()); + have_pending_loads_[static_cast(d->GetMediaType())] = true; + MarkComponentForLoad(d.get()); + } + d->set_last_used_time(GetRealTime()); + return d; + } +} + +void Media::MarkComponentForLoad(MediaComponentData* c) { + assert(InGameThread()); + + assert(c->locked()); + + // *allocate* a reference as a standalone pointer so we can be + // sure this guy sticks around until it's been sent all the way + // through the preload/load cycle. (since other threads will be touching it) + // once it makes it back to us we can delete the ref (in + // ClearPendingLoadsDoneList) + + auto media_ptr = new Object::Ref(c); + g_media_server->PushRunnable(Object::NewDeferred(media_ptr)); +} + +auto Media::GetModelPendingLoadCount() -> int { + if (!have_pending_loads_[static_cast(MediaType::kModel)]) { + return 0; + } + MediaListsLock lock; + int total = GetComponentPendingLoadCount(&models_, MediaType::kModel); + if (total == 0) { + // When fully loaded, stop counting. + have_pending_loads_[static_cast(MediaType::kModel)] = false; + } + return total; +} + +auto Media::GetTexturePendingLoadCount() -> int { + if (!have_pending_loads_[static_cast(MediaType::kTexture)]) { + return 0; + } + MediaListsLock lock; + int total = + (GetComponentPendingLoadCount(&textures_, MediaType::kTexture) + + GetComponentPendingLoadCount(&text_textures_, MediaType::kTexture) + + GetComponentPendingLoadCount(&qr_textures_, MediaType::kTexture)); + if (total == 0) { + // When fully loaded, stop counting. + have_pending_loads_[static_cast(MediaType::kTexture)] = false; + } + return total; +} + +auto Media::GetSoundPendingLoadCount() -> int { + if (!have_pending_loads_[static_cast(MediaType::kSound)]) { + return 0; + } + MediaListsLock lock; + int total = GetComponentPendingLoadCount(&sounds_, MediaType::kSound); + if (total == 0) { + // When fully loaded, stop counting. + have_pending_loads_[static_cast(MediaType::kSound)] = false; + } + return total; +} + +auto Media::GetDataPendingLoadCount() -> int { + if (!have_pending_loads_[static_cast(MediaType::kData)]) { + return 0; + } + MediaListsLock lock; + int total = GetComponentPendingLoadCount(&datas_, MediaType::kData); + if (total == 0) { + // When fully loaded, stop counting. + have_pending_loads_[static_cast(MediaType::kData)] = false; + } + return total; +} + +auto Media::GetCollideModelPendingLoadCount() -> int { + if (!have_pending_loads_[static_cast(MediaType::kCollideModel)]) { + return 0; + } + MediaListsLock lock; + int total = + GetComponentPendingLoadCount(&collide_models_, MediaType::kCollideModel); + if (total == 0) { + // When fully loaded, stop counting. + have_pending_loads_[static_cast(MediaType::kCollideModel)] = false; + } + return total; +} + +auto Media::GetGraphicalPendingLoadCount() -> int { + // Each of these calls lock the media-lists so we don't. + return GetModelPendingLoadCount() + GetTexturePendingLoadCount(); +} + +auto Media::GetPendingLoadCount() -> int { + // Each of these calls lock the media-lists so we don't. + return GetModelPendingLoadCount() + GetTexturePendingLoadCount() + + GetDataPendingLoadCount() + GetSoundPendingLoadCount() + + GetCollideModelPendingLoadCount(); +} + +template +auto Media::GetComponentPendingLoadCount( + std::map >* t_list, MediaType type) -> int { + assert(InGameThread()); + assert(media_lists_locked_); + + int c = 0; + for (auto&& i : (*t_list)) { + if (i.second.exists()) { + if (i.second->TryLock()) { + MediaComponentData::LockGuard lock( + i.second.get(), MediaComponentData::LockGuard::Type::kInheritLock); + if (!i.second->loaded()) { + c++; + } + } else { + c++; + } + } + } + return c; +} + +// Runs the pending loads that need to run from the audio thread. +auto Media::RunPendingAudioLoads() -> bool { + assert(InAudioThread()); + return RunPendingLoadList(&pending_loads_sounds_); +} + +// Runs the pending loads that need to run from the graphics thread. +auto Media::RunPendingGraphicsLoads() -> bool { + assert(InGraphicsThread()); + return RunPendingLoadList(&pending_loads_graphics_); +} + +// Runs the pending loads that run in the main thread. Also clears the list of +// done loads. +auto Media::RunPendingLoadsGameThread() -> bool { + assert(InGameThread()); + return RunPendingLoadList(&pending_loads_other_); +} + +template +auto Media::RunPendingLoadList(std::vector*>* c_list) -> bool { + bool flush = false; + millisecs_t starttime = GetRealTime(); + + std::vector*> l; + std::vector*> l_unfinished; + std::vector*> l_finished; + { + std::lock_guard lock(pending_load_list_mutex_); + + // If we're already out of time. + if (!flush && GetRealTime() - starttime > PENDING_LOAD_PROCESS_TIME) { + bool return_val = (!c_list->empty()); + return return_val; + } + + // Save time if there's nothing to load. + if (c_list->empty()) { + return false; + } + + // Pull the contents of c_list and set it to empty. + l.swap(*c_list); + } + + // Run loads on our list until either the list is empty or we're out of time + // (don't want to block here for very long...) + // We should also think about the fact that even if a load is quick here it + // may add work on the graphics thread/etc so maybe we should add other + // restrictions. + bool out_of_time = false; + if (!l.empty()) { + while (true) { + for (auto i = l.begin(); i != l.end(); i++) { + if (!out_of_time) { + (***i).Load(false); + + // If the load finished, pop it on our "done-loading" list.. otherwise + // keep it around. + l_finished.push_back(*i); // else l_unfinished.push_back(*i); + if (GetRealTime() - starttime > PENDING_LOAD_PROCESS_TIME && !flush) { + out_of_time = true; + } + } else { + // Already out of time - just save this one for later. + l_unfinished.push_back(*i); + } + } + l = l_unfinished; + l_unfinished.clear(); + if (l.empty() || out_of_time) { + break; + } + } + } + + // Now add unfinished ones back onto the original list and finished ones into + // the done list. + { + std::lock_guard lock(pending_load_list_mutex_); + for (auto&& i : l) { + c_list->push_back(i); + } + for (auto&& i : l_finished) { + pending_loads_done_.push_back(i); + } + } + + // if we dumped anything on the pending loads done list, shake the game thread + // to tell it to kill the reference.. + if (!l_finished.empty()) { + assert(g_game); + g_game->PushHavePendingLoadsDoneCall(); + } + return (!l.empty()); +} + +void Media::Prune(int level) { + assert(InGameThread()); + millisecs_t current_time = GetRealTime(); + + // need lists locked while accessing/modifying them + MediaListsLock lock; + + // we can specify level for more aggressive pruning (during memory warnings + // and whatnot) + millisecs_t standard_media_prune_time = STANDARD_MEDIA_PRUNE_TIME; + millisecs_t text_texture_prune_time = TEXT_TEXTURE_PRUNE_TIME; + millisecs_t qr_texture_prune_time = QR_TEXTURE_PRUNE_TIME; + switch (level) { + case 1: + standard_media_prune_time = 120000; // 2 min + text_texture_prune_time = 1000; // 1 sec + qr_texture_prune_time = 1000; // 1 sec + break; + case 2: + standard_media_prune_time = 30000; // 30 sec + text_texture_prune_time = 1000; // 1 sec + qr_texture_prune_time = 1000; // 1 sec + break; + case 3: + standard_media_prune_time = 5000; // 5 sec + text_texture_prune_time = 1000; // 1 sec + qr_texture_prune_time = 1000; // 1 sec + break; + default: + break; + } + + std::vector*> graphics_thread_unloads; + std::vector*> audio_thread_unloads; + +#if SHOW_PRUNING_INFO + assert(media_lists_locked_); + int old_texture_count = textures_.size(); + int old_text_texture_count = text_textures_.size(); + int old_qr_texture_count = qr_textures_.size(); + int old_model_count = models_.size(); + int old_collide_model_count = collide_models_.size(); + int old_sound_count = sounds_.size(); +#endif // SHOW_PRUNING_INFO + + // prune textures.. + assert(media_lists_locked_); + for (auto i = textures_.begin(); i != textures_.end();) { + TextureData* texture_data = i->second.get(); + // attempt to prune if there are no references remaining except our own and + // its been a while since it was used + if (current_time - texture_data->last_used_time() + > standard_media_prune_time + && (texture_data->object_strong_ref_count() <= 1)) { + // if its preloaded/loaded we need to ask the graphics thread to unload it + // first + if (texture_data->preloaded()) { + // allocate a reference to keep this texture_data alive while the unload + // is happening + graphics_thread_unloads.push_back( + new Object::Ref(texture_data)); + auto i_next = i; + i_next++; + textures_.erase(i); + i = i_next; + } + } else { + i++; + } + } + + // prune text-textures more aggressively since we may generate lots of them + // FIXME - we may want to prune based on total number of these instead of + // time.. + assert(media_lists_locked_); + for (auto i = text_textures_.begin(); i != text_textures_.end();) { + TextureData* texture_data = i->second.get(); + // attempt to prune if there are no references remaining except our own and + // its been a while since it was used + if (current_time - texture_data->last_used_time() > text_texture_prune_time + && (texture_data->object_strong_ref_count() <= 1)) { + // if its preloaded/loaded we need to ask the graphics thread to unload it + // first + if (texture_data->preloaded()) { + // allocate a reference to keep this texture_data alive while the unload + // is happening + graphics_thread_unloads.push_back( + new Object::Ref(texture_data)); + auto i_next = i; + i_next++; + text_textures_.erase(i); + i = i_next; + } + } else { + i++; + } + } + + // prune textures + assert(media_lists_locked_); + for (auto i = qr_textures_.begin(); i != qr_textures_.end();) { + TextureData* texture_data = i->second.get(); + // attempt to prune if there are no references remaining except our own and + // its been a while since it was used + if (current_time - texture_data->last_used_time() > qr_texture_prune_time + && (texture_data->object_strong_ref_count() <= 1)) { + // if its preloaded/loaded we need to ask the graphics thread to unload it + // first + if (texture_data->preloaded()) { + // allocate a reference to keep this texture_data alive while the unload + // is happening + graphics_thread_unloads.push_back( + new Object::Ref(texture_data)); + auto i_next = i; + i_next++; + qr_textures_.erase(i); + i = i_next; + } + } else { + i++; + } + } + + // prune models.. + assert(media_lists_locked_); + for (auto i = models_.begin(); i != models_.end();) { + ModelData* model_data = i->second.get(); + // attempt to prune if there are no references remaining except our own and + // its been a while since it was used + if (current_time - model_data->last_used_time() > standard_media_prune_time + && (model_data->object_strong_ref_count() <= 1)) { + // if its preloaded/loaded we need to ask the graphics thread to unload it + // first + if (model_data->preloaded()) { + // allocate a reference to keep this model_data alive while the unload + // is happening + graphics_thread_unloads.push_back( + new Object::Ref(model_data)); + auto i_next = i; + i_next++; + models_.erase(i); + i = i_next; + } + } else { + i++; + } + } + + // Prune collide-models. + assert(media_lists_locked_); + for (auto i = collide_models_.begin(); i != collide_models_.end();) { + CollideModelData* collide_model_data = i->second.get(); + // attempt to prune if there are no references remaining except our own and + // its been a while since it was used (unlike other media we never prune + // these if there's still references to them + if (current_time - collide_model_data->last_used_time() + > standard_media_prune_time + && (collide_model_data->object_strong_ref_count() <= 1)) { + // we can unload it immediately since that happens in the game thread... + collide_model_data->Unload(); + auto i_next = i; + ++i_next; + collide_models_.erase(i); + i = i_next; + } else { + i++; + } + } + + // Prune sounds. + // (DISABLED FOR NOW - getting AL errors; need to better determine which + // sounds are still in active use by OpenAL and ensure references exist for + // them somewhere while that is the case + if (explicit_bool(false)) { + assert(media_lists_locked_); + for (auto i = sounds_.begin(); i != sounds_.end();) { + SoundData* sound_data = i->second.get(); + // Attempt to prune if there are no references remaining except our own + // and its been a while since it was used. + if (current_time - sound_data->last_used_time() + > standard_media_prune_time + && (sound_data->object_strong_ref_count() <= 1)) { + // If its preloaded/loaded we need to ask the graphics thread to unload + // it first. + if (sound_data->preloaded()) { + // Allocate a reference to keep this sound_data alive while the unload + // is happening. + audio_thread_unloads.push_back( + new Object::Ref(sound_data)); + auto i_next = i; + i_next++; + sounds_.erase(i); + i = i_next; + } + } else { + i++; + } + } + } + + if (!graphics_thread_unloads.empty()) { + g_graphics_server->PushComponentUnloadCall(graphics_thread_unloads); + } + if (!audio_thread_unloads.empty()) { + g_audio_server->PushComponentUnloadCall(audio_thread_unloads); + } + +#if SHOW_PRUNING_INFO + assert(media_lists_locked_); + if (textures_.size() != old_texture_count) { + Log("Textures pruned from " + std::to_string(old_texture_count) + " to " + + std::to_string(textures_.size())); + } + if (text_textures_.size() != old_text_texture_count) { + Log("TextTextures pruned from " + std::to_string(old_text_texture_count) + + " to " + std::to_string(text_textures_.size())); + } + if (qr_textures_.size() != old_qr_texture_count) { + Log("QrTextures pruned from " + std::to_string(old_qr_texture_count) + + " to " + std::to_string(qr_textures_.size())); + } + if (models_.size() != old_model_count) { + Log("Models pruned from " + std::to_string(old_model_count) + " to " + + std::to_string(models_.size())); + } + if (collide_models_.size() != old_collide_model_count) { + Log("CollideModels pruned from " + std::to_string(old_collide_model_count) + + " to " + std::to_string(collide_models_.size())); + } + if (sounds_.size() != old_sound_count) { + Log("Sounds pruned from " + std::to_string(old_sound_count) + " to " + + std::to_string(sounds_.size())); + } +#endif // SHOW_PRUNING_INFO +} + +auto Media::FindMediaFile(FileType type, const std::string& name) + -> std::string { + std::string file_out; + + // We don't protect package-path access so make sure its always from here. + assert(InGameThread()); + + const char* ext = ""; + const char* prefix = ""; + + switch (type) { + case FileType::kSound: +#if BA_HEADLESS_BUILD + return "headless_dummy_path.sound"; +#else // BA_HEADLESS_BUILD + prefix = "audio/"; + ext = ".ogg"; + break; +#endif // BA_HEADLESS_BUILD + + case FileType::kModel: +#if BA_HEADLESS_BUILD + return "headless_dummy_path.model"; +#else // BA_HEADLESS_BUILD + prefix = "models/"; + ext = ".bob"; + break; +#endif // BA_HEADLESS_BUILD + + case FileType::kCollisionModel: + prefix = "models/"; + ext = ".cob"; + break; + + case FileType::kData: + prefix = "data/"; + ext = ".json"; + break; + + case FileType::kTexture: { +#if BA_HEADLESS_BUILD + if (strchr(name.c_str(), '#')) { + return "headless_dummy_path#.nop"; + } else { + return "headless_dummy_path.nop"; + } +#else // BA_HEADLESS_BUILD + + assert(g_graphics_server + && g_graphics_server->texture_compression_types_are_set()); + assert(g_graphics_server && g_graphics_server->texture_quality_set()); + prefix = "textures/"; + +#if BA_OSTYPE_ANDROID && !BA_ANDROID_DDS_BUILD + // On most android builds we go for .kvm, which contains etc2 and etc1. + ext = ".ktx"; +#elif BA_OSTYPE_IOS_TVOS + // On iOS we use pvr. + ext = ".pvr"; +#else + // all else defaults to dds + ext = ".dds"; +#endif +#endif // BA_HEADLESS_BUILD + break; + } + default: + break; + } + + const std::vector& media_paths_used = media_paths_; + + for (auto&& i : media_paths_used) { + struct BA_STAT stats {}; + file_out = i + "/" + prefix + name + ext; // NOLINT + int result; + + // '#' denotes a cube map texture, which is actually 6 files. + if (strchr(file_out.c_str(), '#')) { + std::string tmp_name = file_out; + tmp_name.replace(tmp_name.find('#'), 1, "_+x"); + + // Just look for one of them i guess. + result = g_platform->Stat(tmp_name.c_str(), &stats); + } else { + result = g_platform->Stat(file_out.c_str(), &stats); + } + if (result == 0) { + if (S_ISREG(stats.st_mode)) { // NOLINT + return file_out; + } + } + } + + // We wanna fail gracefully for some types. + if (type == FileType::kSound && name != "blank") { + Log("Unable to load audio: '" + name + "'; trying fallback..."); + return FindMediaFile(type, "blank"); + } else if (type == FileType::kTexture && name != "white") { + Log("Unable to load texture: '" + name + "'; trying fallback..."); + return FindMediaFile(type, "white"); + } + + throw Exception("Can't find media: \"" + name + "\""); + // return file_out; +} + +void Media::AddPendingLoad(Object::Ref* c) { + switch ((**c).GetMediaType()) { + case MediaType::kTexture: + case MediaType::kModel: { + // Tell the graphics thread there's pending loads... + std::lock_guard lock(pending_load_list_mutex_); + pending_loads_graphics_.push_back(c); + break; + } + case MediaType::kSound: { + // Tell the audio thread there's pending loads. + { + std::lock_guard lock(pending_load_list_mutex_); + pending_loads_sounds_.push_back(c); + } + g_audio_server->PushHavePendingLoadsCall(); + break; + } + default: { + // Tell the game thread there's pending loads. + { + std::lock_guard lock(pending_load_list_mutex_); + pending_loads_other_.push_back(c); + } + g_game->PushHavePendingLoadsCall(); + break; + } + } +} + +void Media::ClearPendingLoadsDoneList() { + assert(InGameThread()); + + std::lock_guard lock(pending_load_list_mutex_); + + // Our explicitly-allocated reference pointer has made it back to us here in + // the game thread. + // We can now kill the reference knowing that it's safe for this component + // to die at any time (anyone needing it to be alive now should be holding a + // reference themselves). + for (Object::Ref* i : pending_loads_done_) { + delete i; + } + pending_loads_done_.clear(); +} + +void Media::PreloadRunnable::Run() { + assert(InMediaThread()); + + // add our pointer to one of the preload lists and shake our preload thread to + // wake it up + if ((**c).GetMediaType() == MediaType::kSound) { + g_media_server->pending_preloads_audio_.push_back(c); + } else { + g_media_server->pending_preloads_.push_back(c); + } + g_media_server->process_timer_->SetLength(0); +} + +void Media::AddPackage(const std::string& name, const std::string& path) { + // we don't protect package-path access so make sure its always from here.. + assert(InGameThread()); +#if BA_DEBUG_BUILD + if (packages_.find(name) != packages_.end()) { + Log("WARNING: adding duplicate package: '" + name + "'"); + } +#endif // BA_DEBUG_BUILD + packages_[name] = path; +} + +Media::MediaListsLock::MediaListsLock() { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + g_media->media_lists_mutex_.lock(); + assert(!g_media->media_lists_locked_); + g_media->media_lists_locked_ = true; + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); +} + +Media::MediaListsLock::~MediaListsLock() { + assert(g_media->media_lists_locked_); + g_media->media_lists_locked_ = false; + g_media->media_lists_mutex_.unlock(); +} + +} // namespace ballistica diff --git a/src/ballistica/media/media.h b/src/ballistica/media/media.h new file mode 100644 index 00000000..54d49e49 --- /dev/null +++ b/src/ballistica/media/media.h @@ -0,0 +1,215 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_MEDIA_H_ +#define BALLISTICA_MEDIA_MEDIA_H_ + +#include +#include +#include + +#include "ballistica/core/context.h" +#include "ballistica/core/module.h" +#include "ballistica/core/object.h" + +namespace ballistica { + +/// Global media wrangling class. +class Media { + public: + static void Init(); + ~Media(); + + /// Handy function to try to return a bit of media from a std::map + /// of weak-refs, loading/adding it if need be. + template + static auto GetMedia(std::map >* list, + const std::string& name, Scene* scene) + -> Object::Ref { + assert(InGameThread()); + assert(list); + auto i = list->find(name); + + // If we have an entry pointing to a live component, just return a new ref + // to it. + if (i != list->end() && i->second.exists()) { + return Object::Ref(i->second.get()); + } else { + // Otherwise make a new one, pop a weak-ref on our list, and return a + // strong-ref to it. + auto t(Object::New(name, scene)); + (*list)[name] = t; + return t; + } + } + + void AddPackage(const std::string& name, const std::string& path); + void Prune(int level = 0); + + /// Finish loading any media that has been preloaded but still needs to be + /// loaded by the proper thread. + auto RunPendingLoadsGameThread() -> bool; + + /// Return true if audio loads remain to be done. + auto RunPendingAudioLoads() -> bool; + + /// Return true if graphics loads remain to be done. + auto RunPendingGraphicsLoads() -> bool; + void ClearPendingLoadsDoneList(); + template + auto RunPendingLoadList(std::vector*>* cList) -> bool; + + /// This function takes a newly allocated pointer which + /// is deleted once the load is completed. + void AddPendingLoad(Object::Ref* c); + struct PreloadRunnable; + enum class FileType { kModel, kCollisionModel, kTexture, kSound, kData }; + auto FindMediaFile(FileType fileType, const std::string& file_in) + -> std::string; + + /// Unload renderer-specific bits only (gl display lists, etc) - used when + /// recreating/adjusting the renderer. + void UnloadRendererBits(bool textures, bool models); + + /// Should be called from the game thread after UnloadRendererBits(); + /// kicks off bg loads for all existing unloaded media. + void MarkAllMediaForLoad(); + void PrintLoadInfo(); + + auto GetModelPendingLoadCount() -> int; + auto GetTexturePendingLoadCount() -> int; + auto GetSoundPendingLoadCount() -> int; + auto GetDataPendingLoadCount() -> int; + auto GetCollideModelPendingLoadCount() -> int; + + /// Return the total number of graphics related pending loads. + auto GetGraphicalPendingLoadCount() -> int; + + /// Return the total number of pending loads. + auto GetPendingLoadCount() -> int; + + /// You must hold one of these locks while calling Get*Data() below. + class MediaListsLock { + public: + MediaListsLock(); + ~MediaListsLock(); + }; + + /// Load/cache media (make sure you hold a MediaListsLock). + auto GetTextureData(const std::string& file_name) -> Object::Ref; + auto GetTextureData(TextPacker* packer) -> Object::Ref; + auto GetTextureDataQRCode(const std::string& file_name) + -> Object::Ref; + auto GetCubeMapTextureData(const std::string& file_name) + -> Object::Ref; + auto GetModelData(const std::string& file_name) -> Object::Ref; + auto GetSoundData(const std::string& file_name) -> Object::Ref; + auto GetDataData(const std::string& file_name) -> Object::Ref; + auto GetCollideModelData(const std::string& file_name) + -> Object::Ref; + + // Get system assets. + auto GetTexture(SystemTextureID id) -> TextureData* { + BA_PRECONDITION_FATAL(system_media_loaded_); // Revert to assert later. + assert(InGameThread()); + assert(static_cast(id) < system_textures_.size()); + return system_textures_[static_cast(id)].get(); + } + auto GetCubeMapTexture(SystemCubeMapTextureID id) -> TextureData* { + BA_PRECONDITION_FATAL(system_media_loaded_); // Revert to assert later. + assert(InGameThread()); + assert(static_cast(id) < system_cube_map_textures_.size()); + return system_cube_map_textures_[static_cast(id)].get(); + } + auto GetSound(SystemSoundID id) -> SoundData* { + BA_PRECONDITION_FATAL(system_media_loaded_); // Revert to assert later. + assert(InGameThread()); + assert(static_cast(id) < system_sounds_.size()); + return system_sounds_[static_cast(id)].get(); + } + auto GetModel(SystemModelID id) -> ModelData* { + BA_PRECONDITION_FATAL(system_media_loaded_); // Revert to assert later. + assert(InGameThread()); + assert(static_cast(id) < system_models_.size()); + return system_models_[static_cast(id)].get(); + } + + /// Load up hard-coded media for interface, etc. + void LoadSystemMedia(); + + auto total_model_count() const -> uint32_t { + return static_cast(models_.size()); + } + auto total_texture_count() const -> uint32_t { + return static_cast(textures_.size() + text_textures_.size() + + qr_textures_.size()); + } + auto total_sound_count() const -> uint32_t { + return static_cast(sounds_.size()); + } + auto total_collide_model_count() const -> uint32_t { + return static_cast(collide_models_.size()); + } + struct PreloadRunnable : public Runnable { + explicit PreloadRunnable(Object::Ref* c_in) : c(c_in) {} + void Run() override; + Object::Ref* c; + }; + + private: + Media(); + static void MarkComponentForLoad(MediaComponentData* c); + void LoadSystemTexture(SystemTextureID id, const char* name); + void LoadSystemCubeMapTexture(SystemCubeMapTextureID id, const char* name); + void LoadSystemSound(SystemSoundID id, const char* name); + void LoadSystemData(SystemDataID id, const char* name); + void LoadSystemModel(SystemModelID id, const char* name); + + template + auto GetComponentPendingLoadCount( + std::map >* t_list, MediaType type) -> int; + + template + auto GetComponentData(const std::string& file_name, + std::map >* c_list) + -> Object::Ref; + + std::vector media_paths_; + bool have_pending_loads_[static_cast(MediaType::kLast)]{}; + std::map packages_; + + // For use by MediaListsLock; don't manually acquire + std::mutex media_lists_mutex_; + + // Will be true while a MediaListsLock exists. Good to debug-verify this + // during any media list access. + bool media_lists_locked_{}; + + // 'hard-wired' internal media + bool system_media_loaded_{}; + std::vector > system_textures_; + std::vector > system_cube_map_textures_; + std::vector > system_sounds_; + std::vector > system_datas_; + std::vector > system_models_; + + // All existing media by filename (including internal). + std::map > textures_; + std::map > text_textures_; + std::map > qr_textures_; + std::map > models_; + std::map > sounds_; + std::map > datas_; + std::map > collide_models_; + + // Components that have been preloaded but need to be loaded. + std::mutex pending_load_list_mutex_; + std::vector*> pending_loads_graphics_; + std::vector*> pending_loads_sounds_; + std::vector*> pending_loads_datas_; + std::vector*> pending_loads_other_; + std::vector*> pending_loads_done_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_MEDIA_H_ diff --git a/src/ballistica/media/media_server.cc b/src/ballistica/media/media_server.cc new file mode 100644 index 00000000..e869506e --- /dev/null +++ b/src/ballistica/media/media_server.cc @@ -0,0 +1,240 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/media/media_server.h" + +#include +#include + +#include "ballistica/generic/huffman.h" +#include "ballistica/generic/timer.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/media/data/media_component_data.h" +#include "ballistica/media/media.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +MediaServer::MediaServer(Thread* thread) + : Module("media", thread), + writing_replay_(false), + replay_message_bytes_(0), + replays_broken_(false), + replay_out_file_(nullptr) { + assert(g_media_server == nullptr); + g_media_server = this; + + // get our thread to give us periodic processing time... + process_timer_ = + NewThreadTimer(1000, true, NewLambdaRunnable([this] { Process(); })); +} + +MediaServer::~MediaServer() = default; + +void MediaServer::PushBeginWriteReplayCall() { + PushCall([this] { + if (replays_broken_) { + return; + } + + // we only allow writing one replay at once; make sure that's actually the + // case + if (writing_replay_) { + Log("MediaServer got BeginWriteReplayCall while already writing"); + WriteReplayMessages(); + if (replay_out_file_) { + fclose(replay_out_file_); + } + replay_out_file_ = nullptr; + replays_broken_ = true; + return; + } + writing_replay_ = true; + + std::string f_name = "__lastReplay"; + assert(g_platform); + std::string file_path = + g_platform->GetReplaysDir() + BA_DIRSLASH + f_name + ".brp"; + replay_out_file_ = g_platform->FOpen(file_path.c_str(), "wb"); + replay_bytes_written_ = 0; + + if (!replay_out_file_) { + Log("ERROR: unable to open output-stream file: '" + file_path + "'"); + } else { + // write file id and protocol-version + // NOTE - we always write replays in our host protocol version + // no matter what the client stream is + uint32_t file_id = kBrpFileID; + uint16_t version = kProtocolVersion; + if ((fwrite(&file_id, sizeof(file_id), 1, replay_out_file_) != 1) + || (fwrite(&version, sizeof(version), 1, replay_out_file_) != 1)) { + fclose(replay_out_file_); + replay_out_file_ = nullptr; + Log("error writing replay file header: " + + g_platform->GetErrnoString()); + } + replay_bytes_written_ = 5; + } + + // trigger our process timer to go off immediately + // (we may need to wake it up) + g_media_server->process_timer_->SetLength(0); + }); +} + +void MediaServer::PushAddMessageToReplayCall(const std::vector& data) { + PushCall([this, data] { + if (replays_broken_) { + return; + } + + // sanity check.. + if (!writing_replay_) { + Log("MediaServer got AddMessageToReplayCall while not writing replay"); + replays_broken_ = true; + return; + } + + // just add it to our list + if (replay_out_file_) { + // if we've got too much data built up (lets go with 10 megs for now), + // abort + if (replay_message_bytes_ > 10000000) { + Log("replay output buffer exceeded 10 megs; aborting replay"); + fclose(replay_out_file_); + replay_out_file_ = nullptr; + replay_message_bytes_ = 0; + replay_messages_.clear(); + return; + } + replay_message_bytes_ += data.size(); + replay_messages_.push_back(data); + } + }); +} + +void MediaServer::PushEndWriteReplayCall() { + PushCall([this] { + if (replays_broken_) { + return; + } + + // sanity check.. + if (!writing_replay_) { + Log("_finishWritingReplay called while not writing"); + replays_broken_ = true; + return; + } + WriteReplayMessages(); + + // whether or not we actually have a file has no impact on our + // writing_replay_ status.. + if (replay_out_file_) { + fclose(replay_out_file_); + replay_out_file_ = nullptr; + } + writing_replay_ = false; + }); +} + +void MediaServer::WriteReplayMessages() { + if (replay_out_file_) { + for (auto&& i : replay_messages_) { + std::vector data_compressed = g_utils->huffman()->compress(i); + + // If message length is < 254, write length as one byte. + // If its between 254 and 65535, write 254 and then 2 length bytes + // otherwise write 255 and then 4 length bytes. + auto len32 = static_cast(data_compressed.size()); + { + uint8_t len8; + if (len32 < 254) { + len8 = static_cast_check_fit(len32); + } else if (len32 < 65535) { + len8 = 254; + } else { + len8 = 255; + } + if (fwrite(&len8, 1, 1, replay_out_file_) != 1) { + fclose(replay_out_file_); + replay_out_file_ = nullptr; + Log("error writing replay file: " + g_platform->GetErrnoString()); + return; + } + } + // write 16 bit val if need be.. + if (len32 >= 254) { + if (len32 <= 65535) { + auto len16 = static_cast_check_fit(len32); + if (fwrite(&len16, 2, 1, replay_out_file_) != 1) { + fclose(replay_out_file_); + replay_out_file_ = nullptr; + Log("error writing replay file: " + g_platform->GetErrnoString()); + return; + } + } else { + if (fwrite(&len32, 4, 1, replay_out_file_) != 1) { + fclose(replay_out_file_); + replay_out_file_ = nullptr; + Log("error writing replay file: " + g_platform->GetErrnoString()); + return; + } + } + } + // write buffer + size_t result = fwrite(&(data_compressed[0]), data_compressed.size(), 1, + replay_out_file_); + if (result != 1) { + fclose(replay_out_file_); + replay_out_file_ = nullptr; + Log("error writing replay file: " + g_platform->GetErrnoString()); + return; + } + replay_bytes_written_ += data_compressed.size() + 2; + } + replay_messages_.clear(); + replay_message_bytes_ = 0; + } +} + +void MediaServer::Process() { + // make sure we don't do any loading until we know what kind/quality of + // textures we'll be loading + if (!g_media || !g_graphics_server + || !g_graphics_server->texture_compression_types_are_set() // NOLINT + || !g_graphics_server->texture_quality_set()) { + return; + } + + // process exactly 1 preload item.. empty out our non-audio list first + // (audio is less likely to cause noticeable hitches if it needs to be loaded + // on-demand, so that's a lower priority for us) + if (!pending_preloads_.empty()) { + (**pending_preloads_.back()).Preload(); + // pass the ref-pointer along to the load queue + g_media->AddPendingLoad(pending_preloads_.back()); + pending_preloads_.pop_back(); + } else if (!pending_preloads_audio_.empty()) { + (**pending_preloads_audio_.back()).Preload(); + // pass the ref-pointer along to the load queue + g_media->AddPendingLoad(pending_preloads_audio_.back()); + pending_preloads_audio_.pop_back(); + } + + // if we're writing a replay, dump anything we've got built up.. + if (writing_replay_) { + WriteReplayMessages(); + } + + // if we've got nothing left, set our timer to go off every now and then if + // we're writing a replay.. otherwise just sleep indefinitely. + if (pending_preloads_.empty() && pending_preloads_audio_.empty()) { + if (writing_replay_) { + process_timer_->SetLength(1000); + } else { + process_timer_->SetLength(-1); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/media/media_server.h b/src/ballistica/media/media_server.h new file mode 100644 index 00000000..b52b1cd0 --- /dev/null +++ b/src/ballistica/media/media_server.h @@ -0,0 +1,39 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_MEDIA_MEDIA_SERVER_H_ +#define BALLISTICA_MEDIA_MEDIA_SERVER_H_ + +#include +#include + +#include "ballistica/core/module.h" + +namespace ballistica { + +class MediaServer : public Module { + public: + explicit MediaServer(Thread* thread); + ~MediaServer() override; + void PushBeginWriteReplayCall(); + void PushEndWriteReplayCall(); + void PushAddMessageToReplayCall(const std::vector& data); + + private: + void Process(); + void WriteReplayMessages(); + FILE* replay_out_file_{}; + size_t replay_bytes_written_{}; + bool writing_replay_{}; + bool replays_broken_{}; + std::list > replay_messages_; + size_t replay_message_bytes_{}; + Timer* process_timer_{}; + std::vector*> pending_preloads_; + std::vector*> pending_preloads_audio_; + friend struct PreloadRunnable; + friend class Media; +}; + +} // namespace ballistica + +#endif // BALLISTICA_MEDIA_MEDIA_SERVER_H_ diff --git a/src/ballistica/networking/network_reader.h b/src/ballistica/networking/network_reader.h new file mode 100644 index 00000000..e6ff0bd5 --- /dev/null +++ b/src/ballistica/networking/network_reader.h @@ -0,0 +1,60 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_NETWORKING_NETWORK_READER_H_ +#define BALLISTICA_NETWORKING_NETWORK_READER_H_ + +#include +#include +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// This is a special thread that manages the game's main network sockets; +// it handles creating/destroying them as well as listening for incoming +// packets. it is not a normal BA thread so doesn't have the ability to receive +// messages (it generally sits blocked in a select() call). Writing to these +// sockets takes place in other threads; just make sure to lock the mutex and +// ensure the sockets exist before doing the actual write. +class NetworkReader { + public: + explicit NetworkReader(int port); + ~NetworkReader(); + auto Pause() -> void; + auto Resume() -> void; + auto port4() const { return port4_; } + auto port6() const { return port6_; } + auto sd_mutex() -> std::mutex& { return sd_mutex_; } + auto sd4() const { return sd4_; } + auto sd6() const { return sd6_; } + + private: + auto HandleJSONPing(const std::string& data) -> std::string; + auto PokeSelf() -> void; + auto RunThread() -> int; + static auto RunThreadStatic(void* self) -> int { + return static_cast(self)->RunThread(); + } + std::unique_ptr remote_server_; + int sd4_{-1}; + int sd6_{-1}; + std::mutex sd_mutex_; + + // This needs to be locked while modifying or writing to either the ipv4 or + // ipv6 socket. The one exception is when the network-reader thread is reading + // from them, since there is no chance of anyone else reading or modifying + // them. (that is all handled by the net-reader thread). + int port4_{-1}; + int port6_{-1}; + std::thread* thread_{}; + bool paused_{}; + std::mutex paused_mutex_; + std::condition_variable paused_cv_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_NETWORKING_NETWORK_READER_H_ diff --git a/src/ballistica/networking/network_write_module.h b/src/ballistica/networking/network_write_module.h new file mode 100644 index 00000000..821d3e77 --- /dev/null +++ b/src/ballistica/networking/network_write_module.h @@ -0,0 +1,21 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_NETWORKING_NETWORK_WRITE_MODULE_H_ +#define BALLISTICA_NETWORKING_NETWORK_WRITE_MODULE_H_ + +#include + +#include "ballistica/core/module.h" + +namespace ballistica { + +// this thread handles network output and whatnot +class NetworkWriteModule : public Module { + public: + void PushSendToCall(const std::vector& msg, const SockAddr& addr); + explicit NetworkWriteModule(Thread* thread); +}; + +} // namespace ballistica + +#endif // BALLISTICA_NETWORKING_NETWORK_WRITE_MODULE_H_ diff --git a/src/ballistica/networking/networking.h b/src/ballistica/networking/networking.h new file mode 100644 index 00000000..fa4c8816 --- /dev/null +++ b/src/ballistica/networking/networking.h @@ -0,0 +1,168 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_NETWORKING_NETWORKING_H_ +#define BALLISTICA_NETWORKING_NETWORKING_H_ + +#include +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// Packet types (first byte of raw udp packet). +// These packets can apply to our UDP connection layer, Remote App, etc. +// and don't exist for other connection mechanisms (GPGS, etc). +#define BA_PACKET_REMOTE_PING 0 +#define BA_PACKET_REMOTE_PONG 1 +#define BA_PACKET_REMOTE_ID_REQUEST 2 +#define BA_PACKET_REMOTE_ID_RESPONSE 3 +#define BA_PACKET_REMOTE_DISCONNECT 4 +#define BA_PACKET_REMOTE_STATE 5 +#define BA_PACKET_REMOTE_STATE_ACK 6 +#define BA_PACKET_REMOTE_DISCONNECT_ACK 7 +#define BA_PACKET_REMOTE_GAME_QUERY 8 +#define BA_PACKET_REMOTE_GAME_RESPONSE 9 +#define BA_PACKET_REMOTE_STATE2 10 + +// Very simple 1 byte packet/response used to test accessibility. +#define BA_PACKET_SIMPLE_PING 11 +#define BA_PACKET_SIMPLE_PONG 12 + +// Fancier ping packet that can contain arbitrary data snippets. +// (so we can include stuff like current player counts, etc. in our response) +#define BA_PACKET_JSON_PING 13 +#define BA_PACKET_JSON_PONG 14 + +// Used on android to wake our socket up so we can kill it. +#define BA_PACKET_POKE 21 + +// Local network game scanning. +#define BA_PACKET_GAME_QUERY 22 +#define BA_PACKET_GAME_QUERY_RESPONSE 23 +#define BA_PACKET_CLIENT_REQUEST 24 +#define BA_PACKET_CLIENT_ACCEPT 25 +#define BA_PACKET_CLIENT_DENY 26 +#define BA_PACKET_CLIENT_DENY_VERSION_MISMATCH 27 +#define BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY 28 +#define BA_PACKET_CLIENT_DENY_PARTY_FULL 29 +#define BA_PACKET_DISCONNECT_FROM_CLIENT_REQUEST 32 +#define BA_PACKET_DISCONNECT_FROM_CLIENT_ACK 33 +#define BA_PACKET_DISCONNECT_FROM_HOST_REQUEST 34 +#define BA_PACKET_DISCONNECT_FROM_HOST_ACK 35 +#define BA_PACKET_CLIENT_GAMEPACKET_COMPRESSED 36 +#define BA_PACKET_HOST_GAMEPACKET_COMPRESSED 37 + +// Gamepackets are chunks of compressed data that apply specifically to a +// ballistica game connection. These packets can be provided over the UDP +// connection layer or by any other transport layer. When decompressed they have +// the following types as their first byte. NOTE - these originally shared a +// domain with BA_PACKET, but now they're independent... so need to avoid value +// clashes.. (hmm did i mean to say NO need?) +#define BA_GAMEPACKET_HANDSHAKE 15 +#define BA_GAMEPACKET_HANDSHAKE_RESPONSE 16 +#define BA_GAMEPACKET_MESSAGE 17 +#define BA_GAMEPACKET_MESSAGE_UNRELIABLE 18 +#define BA_GAMEPACKET_DISCONNECT 19 +#define BA_GAMEPACKET_KEEPALIVE 20 + +// Messages is our high level layer that sits on top of gamepackets. +// They can be any size and will always arrive in the order they were sent +// (though ones marked unreliable may be dropped). +#define BA_MESSAGE_SESSION_RESET 0 +#define BA_MESSAGE_SESSION_COMMANDS 1 +#define BA_MESSAGE_SESSION_DYNAMICS_CORRECTION 2 +#define BA_MESSAGE_REQUEST_REMOTE_PLAYER 4 +#define BA_MESSAGE_ATTACH_REMOTE_PLAYER 5 // OBSOLETE (use the _2 version) +#define BA_MESSAGE_DETACH_REMOTE_PLAYER 6 +#define BA_MESSAGE_REMOTE_PLAYER_INPUT_COMMANDS 7 +#define BA_MESSAGE_REMOVE_REMOTE_PLAYER 8 +#define BA_MESSAGE_PARTY_ROSTER 9 +#define BA_MESSAGE_CHAT 10 +#define BA_MESSAGE_PARTY_MEMBER_JOINED 11 +#define BA_MESSAGE_PARTY_MEMBER_LEFT 12 + +// Hmmm; should multipart logic exist at the gamepacket layer instead?... +// A: that would require the re-send logic to be aware of multi-packet messages +// so maybe this is best. +#define BA_MESSAGE_MULTIPART 13 +#define BA_MESSAGE_MULTIPART_END 14 +#define BA_MESSAGE_CLIENT_PLAYER_PROFILES 15 +#define BA_MESSAGE_ATTACH_REMOTE_PLAYER_2 16 +#define BA_MESSAGE_HOST_INFO 17 +#define BA_MESSAGE_CLIENT_INFO 18 +#define BA_MESSAGE_KICK_VOTE 19 + +// General purpose json message type; its "t" entry is is an int corresponding +// to the BA_JMESSAGE types below. +#define BA_MESSAGE_JMESSAGE 20 +#define BA_MESSAGE_CLIENT_PLAYER_PROFILES_JSON 21 + +#define BA_JMESSAGE_SCREEN_MESSAGE 0 + +// Enable huffman compression for all net packets? +#define BA_HUFFMAN_NET_COMPRESSION 1 + +// Enable training mode to build the huffman tree. +// This will spit a C array of ints to stdout based on net data. +// we currently hard code our tree. +#if !BA_HUFFMAN_NET_COMPRESSION +#define HUFFMAN_TRAINING_MODE 0 +#endif + +// Bits used by the game thread for network communication. +class Networking { + public: + // Send a message to an address. This may block for a brief moment, so it can + // be more efficient to send a SendToMessage to the NetworkWrite thread which + // will do this there. + static void SendTo(const std::vector& buffer, const SockAddr& addr); + Networking(); + ~Networking(); + + // Run a cycle of host scanning (basically sending out a broadcast packet to + // see who's out there). + void HostScanCycle(); + void EndHostScanning(); + + // Called on mobile platforms when going into the background, etc + // (when all networking should be shut down) + void Pause(); + void Resume(); + struct ScanResultsEntry { + std::string display_string; + std::string address; + }; + auto GetScanResults() -> std::vector; + + /// Sends a POST request to the master server and returns the response. + /// path should be something like "/mystatspage". + /// Throws std::exceptions (NOT ballistica Exceptions) if something goes + /// wrong. + static auto MasterServerPost( + const std::string& path, + const std::map& parameters, + bool use_fallback_addr = false) -> std::string; + + /// Sends a GET request to the master server and returns the response. + /// path should be something like "/mystatspage". + /// Throws std::exceptions (NOT ballistica Exceptions) if something goes + /// wrong. + static auto MasterServerGet(const std::string& path, + bool use_fallback_addr = false) -> std::string; + + private: + void PruneScanResults(); + struct ScanResultsEntryPriv; + std::map scan_results_; + std::mutex scan_results_mutex_; + uint32_t next_scan_query_id_{}; + int scan_socket_{-1}; + bool running_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_NETWORKING_NETWORKING_H_ diff --git a/src/ballistica/networking/networking_sys.h b/src/ballistica/networking/networking_sys.h new file mode 100644 index 00000000..b21e9e65 --- /dev/null +++ b/src/ballistica/networking/networking_sys.h @@ -0,0 +1,30 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_NETWORKING_NETWORKING_SYS_H_ +#define BALLISTICA_NETWORKING_NETWORKING_SYS_H_ + +// Include everything needed for standard sockets api usage. + +#if BA_OSTYPE_WINDOWS +// (need includes to stay in this order to disabling formatting) +// clang-format off +#include +#include +// clang-format on +#else +#include +#include +#include +#include +#include +#include +#if BA_OSTYPE_ANDROID +#include "ballistica/platform/android/ifaddrs_android_ext.h" +#else +#include +#endif +#endif +#include +#include + +#endif // BALLISTICA_NETWORKING_NETWORKING_SYS_H_ diff --git a/src/ballistica/networking/sockaddr.h b/src/ballistica/networking/sockaddr.h new file mode 100644 index 00000000..25916e00 --- /dev/null +++ b/src/ballistica/networking/sockaddr.h @@ -0,0 +1,55 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_NETWORKING_SOCKADDR_H_ +#define BALLISTICA_NETWORKING_SOCKADDR_H_ + +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/networking/networking_sys.h" + +namespace ballistica { + +class SockAddr { + public: + SockAddr() { memset(&addr_, 0, sizeof(addr_)); } + + // Creates from an ipv4 or ipv6 address string; + // throws an exception on error. + SockAddr(const std::string& addr, int port); + explicit SockAddr(const sockaddr_storage& addr_in) { + addr_ = addr_in; + assert(addr_.ss_family == AF_INET || addr_.ss_family == AF_INET6); + } + auto GetSockAddr() const -> const sockaddr* { + return reinterpret_cast(&addr_); + } + auto GetSockAddrLen() const -> socklen_t { + switch (addr_.ss_family) { + case AF_INET: + return sizeof(sockaddr_in); + case AF_INET6: + return sizeof(sockaddr_in6); + default: + throw Exception(); + } + } + auto IsV6() const -> bool { + switch (addr_.ss_family) { + case AF_INET: + return false; + case AF_INET6: + return true; + default: + throw Exception(); + } + } + + private: + sockaddr_storage addr_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_NETWORKING_SOCKADDR_H_ diff --git a/src/ballistica/networking/telnet_server.cc b/src/ballistica/networking/telnet_server.cc new file mode 100644 index 00000000..39d4be31 --- /dev/null +++ b/src/ballistica/networking/telnet_server.cc @@ -0,0 +1,241 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/networking/telnet_server.h" + +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/ballistica.h" +#include "ballistica/core/context.h" +#include "ballistica/game/game.h" +#include "ballistica/networking/networking.h" +#include "ballistica/networking/networking_sys.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python_command.h" +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +TelnetServer::TelnetServer(int port) : port_(port) { + thread_ = new std::thread(RunThreadStatic, this); + assert(g_app_globals->telnet_server == nullptr); + g_app_globals->telnet_server = this; + + // NOTE: we consider access implicitly granted on headless builds + // since we can't pop up the request dialog. + // There is still password protection and we now don't even spin + // up the telnet socket by default on servers. + if (HeadlessMode()) { + user_has_granted_access_ = true; + } +} + +void TelnetServer::Pause() { + assert(InMainThread()); + assert(!paused_); + { + std::unique_lock lock(paused_mutex_); + paused_ = true; + } + + // FIXME - need a way to kill these sockets; + // On iOS they die automagically but not android. + // attempted to force-close at some point but it didn't work (on android at + // least) +} + +void TelnetServer::Resume() { + assert(InMainThread()); + assert(paused_); + { + std::unique_lock lock(paused_mutex_); + paused_ = false; + } + + // Poke our thread so it can go on its way. + paused_cv_.notify_all(); +} + +auto TelnetServer::RunThread() -> int { + // Do this whole thing in a loop. + // If we get put to sleep we just start over. + while (true) { + // Sleep until we're unpaused. + if (paused_) { + std::unique_lock lock(paused_mutex_); + paused_cv_.wait(lock, [this] { return (!paused_); }); + } + + sd_ = socket(AF_INET, SOCK_STREAM, 0); + if (sd_ < 0) { + Log("Error: Unable to open host socket; errno " + std::to_string(errno)); + return 0; + } + + // Make it reusable. + int on = 1; + int status = + setsockopt(sd_, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); + if (-1 == status) Log("Error setting SO_REUSEADDR on telnet server"); + + // Bind to local server port. + struct sockaddr_in serv_addr {}; + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // NOLINT + int result; + serv_addr.sin_port = htons(port_); // NOLINT + result = ::bind(sd_, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); + if (result != 0) { + return 0; + } + char buffer[10000]; + const char* prompt = "ballisticacore> "; + const char* password_prompt = "password:"; + + // Now just listen and forward msg along to people. + while (true) { + struct sockaddr_storage from {}; + socklen_t from_size = sizeof(from); + if (listen(sd_, 0) == 0) { + client_sd_ = accept(sd_, (struct sockaddr*)&from, &from_size); + if (client_sd_ < 0) { + break; + } + + // If we dont have access and havnt asked the user for it yet, ask them. + if (!user_has_granted_access_ && g_game + && !have_asked_user_for_access_) { + g_game->PushAskUserForTelnetAccessCall(); + have_asked_user_for_access_ = true; + } + + // Require password for each connection if we have one + reading_password_ = require_password_; + + if (g_game) { + if (reading_password_) { + PushPrint(password_prompt); + } else { + PushPrint(prompt); + } + } + while (true) { + result = + static_cast(recv(client_sd_, buffer, sizeof(buffer) - 1, 0)); + + // Socket closed/disconnected. + if (result == 0 || result == -1) { + // We got closed for whatever reason. + if (client_sd_ != -1) { + g_platform->CloseSocket(client_sd_); + } + client_sd_ = -1; + break; + } else { + buffer[result] = 0; + + // Looks like these come in with '\r\n' at the end.. lets strip + // that. + if (result > 0 && (buffer[result - 1] == '\n')) { + buffer[result - 1] = 0; + if (result > 1 && (buffer[result - 2] == '\r')) + buffer[result - 2] = 0; + } + if (g_game) { + if (user_has_granted_access_) { + if (reading_password_) { + if (GetRealTime() - last_try_time_ < 2000) { + PushPrint( + std::string("retried too soon; please wait a moment " + "and try again.\n") + + password_prompt); + } else if (buffer == password_) { + reading_password_ = false; + PushPrint(prompt); + } else { + last_try_time_ = GetRealTime(); + PushPrint(std::string("incorrect.\n") + password_prompt); + } + } else { + PushTelnetScriptCommand(buffer); + } + } else { + PushPrint(g_game->GetResourceString("telnetAccessDeniedText")); + } + } + } + } + } else { + // Listening failed; abort. + if (sd_ != -1) { + g_platform->CloseSocket(sd_); + } + break; + } + } + + // Sleep for a moment to keep us from running wild if we're unable to block. + Platform::SleepMS(1000); + } +} + +void TelnetServer::PushTelnetScriptCommand(const std::string& command) { + assert(g_game); + if (g_game == nullptr) { + return; + } + g_game->PushCall([this, command] { + // These are always run in whichever context is 'visible'. + ScopedSetContext cp(g_game->GetForegroundContext()); + if (!g_app_globals->user_ran_commands) { + g_app_globals->user_ran_commands = true; + } + PythonCommand cmd(command, ""); + if (cmd.CanEval()) { + PyObject* obj = cmd.RunReturnObj(true); + if (obj && obj != Py_None) { + PyObject* s = PyObject_Repr(obj); + if (s) { + const char* c = PyUnicode_AsUTF8(s); + PushPrint(std::string(c) + "\n"); + Py_DECREF(s); + } + Py_DECREF(obj); + } + } else { + // Not eval-able; just run it. + cmd.Run(); + } + PushPrint("ballisticacore> "); + }); +} + +void TelnetServer::PushPrint(const std::string& s) { + assert(g_game); + g_game->PushCall([this, s] { Print(s); }); +} + +void TelnetServer::Print(const std::string& s) { + // Currently we make the assumption that *only* the game thread writes to our + // socket. + assert(InGameThread()); + if (client_sd_ != -1) { + send(client_sd_, s.c_str(), + static_cast_check_fit(s.size()), 0); + } +} + +TelnetServer::~TelnetServer() = default; + +void TelnetServer::SetAccessEnabled(bool v) { user_has_granted_access_ = v; } + +void TelnetServer::SetPassword(const char* password) { + if (password != nullptr) { + password_ = password; + require_password_ = true; + } else { + require_password_ = false; + } +} + +} // namespace ballistica diff --git a/src/ballistica/networking/telnet_server.h b/src/ballistica/networking/telnet_server.h new file mode 100644 index 00000000..fd0b0d09 --- /dev/null +++ b/src/ballistica/networking/telnet_server.h @@ -0,0 +1,49 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_NETWORKING_TELNET_SERVER_H_ +#define BALLISTICA_NETWORKING_TELNET_SERVER_H_ + +#include +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +class TelnetServer { + public: + explicit TelnetServer(int port); + ~TelnetServer(); + auto Pause() -> void; + auto Resume() -> void; + auto PushTelnetScriptCommand(const std::string& command) -> void; + auto PushPrint(const std::string& s) -> void; + auto SetAccessEnabled(bool v) -> void; + auto SetPassword(const char* password) -> void; // nullptr == no password + + private: + auto RunThread() -> int; + auto Print(const std::string& s) -> void; + static auto RunThreadStatic(void* self) -> int { + return static_cast(self)->RunThread(); + } + int sd_{-1}; + int client_sd_{-1}; + int port_{}; + std::thread* thread_{}; + bool have_asked_user_for_access_{}; + bool user_has_granted_access_{}; + bool paused_{}; + bool reading_password_{}; + bool require_password_{}; + millisecs_t last_try_time_{}; + std::string password_; + std::mutex paused_mutex_; + std::condition_variable paused_cv_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_NETWORKING_TELNET_SERVER_H_ diff --git a/src/ballistica/platform/linux/platform_linux.cc b/src/ballistica/platform/linux/platform_linux.cc new file mode 100644 index 00000000..47550ef9 --- /dev/null +++ b/src/ballistica/platform/linux/platform_linux.cc @@ -0,0 +1,72 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#if BA_OSTYPE_LINUX +#include "ballistica/platform/linux/platform_linux.h" + +#include + +#include + +namespace ballistica { + +PlatformLinux::PlatformLinux() {} + +std::string PlatformLinux::GenerateUUID() { + std::string val; + char buffer[100]; + FILE* fd_out = popen("cat /proc/sys/kernel/random/uuid", "r"); + if (fd_out) { + int size = fread(buffer, 1, 99, fd_out); + fclose(fd_out); + if (size == 37) { + buffer[size - 1] = 0; // chop off trailing newline + val = buffer; + } + } + if (val == "") { + throw Exception("kernel uuid not available"); + } + return val; +} + +bool PlatformLinux::DoHasTouchScreen() { return false; } + +void PlatformLinux::DoOpenURL(const std::string& url) { + // hmmm is there a more universal option than this?... + int result = system((std::string("xdg-open \"") + url + "\"").c_str()); + if (result != 0) { + ScreenMessage("error on xdg-open"); + } +} + +void PlatformLinux::OpenFileExternally(const std::string& path) { + std::string cmd = std::string("xdg-open \"") + path + "\""; + int result = system(cmd.c_str()); + if (result != 0) { + Log("Error: Got return value " + std::to_string(result) + + " on xdg-open cmd '" + cmd + "'"); + } +} + +void PlatformLinux::OpenDirExternally(const std::string& path) { + std::string cmd = std::string("xdg-open \"") + path + "\""; + int result = system(cmd.c_str()); + if (result != 0) { + Log("Error: Got return value " + std::to_string(result) + + " on xdg-open cmd '" + cmd + "'"); + } +} + +std::string PlatformLinux::GetPlatformName() { return "linux"; } + +std::string PlatformLinux::GetSubplatformName() { +#if BA_TEST_BUILD + return "test"; +#else + return ""; +#endif +} + +} // namespace ballistica + +#endif // BA_OSTYPE_LINUX diff --git a/src/ballistica/platform/linux/platform_linux.h b/src/ballistica/platform/linux/platform_linux.h new file mode 100644 index 00000000..bebeefc7 --- /dev/null +++ b/src/ballistica/platform/linux/platform_linux.h @@ -0,0 +1,29 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PLATFORM_LINUX_PLATFORM_LINUX_H_ +#define BALLISTICA_PLATFORM_LINUX_PLATFORM_LINUX_H_ +#if BA_OSTYPE_LINUX + +#include + +#include "ballistica/platform/platform.h" + +namespace ballistica { + +class PlatformLinux : public Platform { + public: + PlatformLinux(); + std::string GetDeviceUUIDPrefix() override { return "l"; } + std::string GenerateUUID() override; + bool DoHasTouchScreen() override; + void DoOpenURL(const std::string& url) override; + void OpenFileExternally(const std::string& path) override; + void OpenDirExternally(const std::string& path) override; + std::string GetPlatformName() override; + std::string GetSubplatformName() override; +}; + +} // namespace ballistica + +#endif // BA_OSTYPE_LINUX +#endif // BALLISTICA_PLATFORM_LINUX_PLATFORM_LINUX_H_ diff --git a/src/ballistica/platform/min_sdl.h b/src/ballistica/platform/min_sdl.h new file mode 100644 index 00000000..8b6abfb3 --- /dev/null +++ b/src/ballistica/platform/min_sdl.h @@ -0,0 +1,792 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PLATFORM_MIN_SDL_H_ +#define BALLISTICA_PLATFORM_MIN_SDL_H_ + +// A bit of history: +// +// Ballistica originally used SDL as its sole library for events, +// window-management, etc. on all platforms. This means a lot of the low level +// event handling code was written with SDL types. +// +// Over time, for various reasons, I started converting bits of functionality +// over to native platform APIs, to the point where nowadays SDL's role is +// largely vestigial in some builds; SDL types are getting passed around but +// not actually being supplied by SDL. +// +// Moving forward, my plan has been to clean things up so that SDL can be +// completely removed from platforms that don't actually use it (though +// still fully supported for platforms where it makes sense). That's where +// this header comes in. +// +// The minimum bits of SDL still needed to compile the game have been copied +// here for use by 'non-sdl' platforms. This mainly includes things like event +// types and keysyms. +// +// On platforms using 'full' SDL, this header simply includes the full sdl +// headers. +// +// The idea is that, over time, the SDL types contained here can be replaced +// with ballistica-specific types added to types.h. The 'full' SDL platform +// layer can then translate its SDL types to ballistica types in the same way +// that other platform code translates their native types, and eventually SDL +// usage should be nicely contained to platform/sdl/* for the platforms that +// want it. + +/* + Simple DirectMedia Layer + Copyright (C) 1997-2012 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +#if BA_SDL_BUILD +#include "SDL.h" +#else + +typedef int32_t SDL_Keycode; + +typedef enum { + SDL_SCANCODE_UNKNOWN = 0, + + SDL_SCANCODE_A = 4, + SDL_SCANCODE_B = 5, + SDL_SCANCODE_C = 6, + SDL_SCANCODE_D = 7, + SDL_SCANCODE_E = 8, + SDL_SCANCODE_F = 9, + SDL_SCANCODE_G = 10, + SDL_SCANCODE_H = 11, + SDL_SCANCODE_I = 12, + SDL_SCANCODE_J = 13, + SDL_SCANCODE_K = 14, + SDL_SCANCODE_L = 15, + SDL_SCANCODE_M = 16, + SDL_SCANCODE_N = 17, + SDL_SCANCODE_O = 18, + SDL_SCANCODE_P = 19, + SDL_SCANCODE_Q = 20, + SDL_SCANCODE_R = 21, + SDL_SCANCODE_S = 22, + SDL_SCANCODE_T = 23, + SDL_SCANCODE_U = 24, + SDL_SCANCODE_V = 25, + SDL_SCANCODE_W = 26, + SDL_SCANCODE_X = 27, + SDL_SCANCODE_Y = 28, + SDL_SCANCODE_Z = 29, + + SDL_SCANCODE_1 = 30, + SDL_SCANCODE_2 = 31, + SDL_SCANCODE_3 = 32, + SDL_SCANCODE_4 = 33, + SDL_SCANCODE_5 = 34, + SDL_SCANCODE_6 = 35, + SDL_SCANCODE_7 = 36, + SDL_SCANCODE_8 = 37, + SDL_SCANCODE_9 = 38, + SDL_SCANCODE_0 = 39, + + SDL_SCANCODE_RETURN = 40, + SDL_SCANCODE_ESCAPE = 41, + SDL_SCANCODE_BACKSPACE = 42, + SDL_SCANCODE_TAB = 43, + SDL_SCANCODE_SPACE = 44, + + SDL_SCANCODE_MINUS = 45, + SDL_SCANCODE_EQUALS = 46, + SDL_SCANCODE_LEFTBRACKET = 47, + SDL_SCANCODE_RIGHTBRACKET = 48, + SDL_SCANCODE_BACKSLASH = 49, + SDL_SCANCODE_NONUSHASH = 50, + SDL_SCANCODE_SEMICOLON = 51, + SDL_SCANCODE_APOSTROPHE = 52, + SDL_SCANCODE_GRAVE = 53, + SDL_SCANCODE_COMMA = 54, + SDL_SCANCODE_PERIOD = 55, + SDL_SCANCODE_SLASH = 56, + + SDL_SCANCODE_CAPSLOCK = 57, + + SDL_SCANCODE_F1 = 58, + SDL_SCANCODE_F2 = 59, + SDL_SCANCODE_F3 = 60, + SDL_SCANCODE_F4 = 61, + SDL_SCANCODE_F5 = 62, + SDL_SCANCODE_F6 = 63, + SDL_SCANCODE_F7 = 64, + SDL_SCANCODE_F8 = 65, + SDL_SCANCODE_F9 = 66, + SDL_SCANCODE_F10 = 67, + SDL_SCANCODE_F11 = 68, + SDL_SCANCODE_F12 = 69, + + SDL_SCANCODE_PRINTSCREEN = 70, + SDL_SCANCODE_SCROLLLOCK = 71, + SDL_SCANCODE_PAUSE = 72, + SDL_SCANCODE_INSERT = 73, + SDL_SCANCODE_HOME = 74, + SDL_SCANCODE_PAGEUP = 75, + SDL_SCANCODE_DELETE = 76, + SDL_SCANCODE_END = 77, + SDL_SCANCODE_PAGEDOWN = 78, + SDL_SCANCODE_RIGHT = 79, + SDL_SCANCODE_LEFT = 80, + SDL_SCANCODE_DOWN = 81, + SDL_SCANCODE_UP = 82, + + SDL_SCANCODE_NUMLOCKCLEAR = 83, + SDL_SCANCODE_KP_DIVIDE = 84, + SDL_SCANCODE_KP_MULTIPLY = 85, + SDL_SCANCODE_KP_MINUS = 86, + SDL_SCANCODE_KP_PLUS = 87, + SDL_SCANCODE_KP_ENTER = 88, + SDL_SCANCODE_KP_1 = 89, + SDL_SCANCODE_KP_2 = 90, + SDL_SCANCODE_KP_3 = 91, + SDL_SCANCODE_KP_4 = 92, + SDL_SCANCODE_KP_5 = 93, + SDL_SCANCODE_KP_6 = 94, + SDL_SCANCODE_KP_7 = 95, + SDL_SCANCODE_KP_8 = 96, + SDL_SCANCODE_KP_9 = 97, + SDL_SCANCODE_KP_0 = 98, + SDL_SCANCODE_KP_PERIOD = 99, + + SDL_SCANCODE_NONUSBACKSLASH = 100, + SDL_SCANCODE_APPLICATION = 101, + SDL_SCANCODE_POWER = 102, + SDL_SCANCODE_KP_EQUALS = 103, + SDL_SCANCODE_F13 = 104, + SDL_SCANCODE_F14 = 105, + SDL_SCANCODE_F15 = 106, + SDL_SCANCODE_F16 = 107, + SDL_SCANCODE_F17 = 108, + SDL_SCANCODE_F18 = 109, + SDL_SCANCODE_F19 = 110, + SDL_SCANCODE_F20 = 111, + SDL_SCANCODE_F21 = 112, + SDL_SCANCODE_F22 = 113, + SDL_SCANCODE_F23 = 114, + SDL_SCANCODE_F24 = 115, + SDL_SCANCODE_EXECUTE = 116, + SDL_SCANCODE_HELP = 117, + SDL_SCANCODE_MENU = 118, + SDL_SCANCODE_SELECT = 119, + SDL_SCANCODE_STOP = 120, + SDL_SCANCODE_AGAIN = 121, + SDL_SCANCODE_UNDO = 122, + SDL_SCANCODE_CUT = 123, + SDL_SCANCODE_COPY = 124, + SDL_SCANCODE_PASTE = 125, + SDL_SCANCODE_FIND = 126, + SDL_SCANCODE_MUTE = 127, + SDL_SCANCODE_VOLUMEUP = 128, + SDL_SCANCODE_VOLUMEDOWN = 129, + + SDL_SCANCODE_KP_COMMA = 133, + SDL_SCANCODE_KP_EQUALSAS400 = 134, + + SDL_SCANCODE_INTERNATIONAL1 = 135, + SDL_SCANCODE_INTERNATIONAL2 = 136, + SDL_SCANCODE_INTERNATIONAL3 = 137, + SDL_SCANCODE_INTERNATIONAL4 = 138, + SDL_SCANCODE_INTERNATIONAL5 = 139, + SDL_SCANCODE_INTERNATIONAL6 = 140, + SDL_SCANCODE_INTERNATIONAL7 = 141, + SDL_SCANCODE_INTERNATIONAL8 = 142, + SDL_SCANCODE_INTERNATIONAL9 = 143, + SDL_SCANCODE_LANG1 = 144, + SDL_SCANCODE_LANG2 = 145, + SDL_SCANCODE_LANG3 = 146, + SDL_SCANCODE_LANG4 = 147, + SDL_SCANCODE_LANG5 = 148, + SDL_SCANCODE_LANG6 = 149, + SDL_SCANCODE_LANG7 = 150, + SDL_SCANCODE_LANG8 = 151, + SDL_SCANCODE_LANG9 = 152, + + SDL_SCANCODE_ALTERASE = 153, + SDL_SCANCODE_SYSREQ = 154, + SDL_SCANCODE_CANCEL = 155, + SDL_SCANCODE_CLEAR = 156, + SDL_SCANCODE_PRIOR = 157, + SDL_SCANCODE_RETURN2 = 158, + SDL_SCANCODE_SEPARATOR = 159, + SDL_SCANCODE_OUT = 160, + SDL_SCANCODE_OPER = 161, + SDL_SCANCODE_CLEARAGAIN = 162, + SDL_SCANCODE_CRSEL = 163, + SDL_SCANCODE_EXSEL = 164, + + SDL_SCANCODE_KP_00 = 176, + SDL_SCANCODE_KP_000 = 177, + SDL_SCANCODE_THOUSANDSSEPARATOR = 178, + SDL_SCANCODE_DECIMALSEPARATOR = 179, + SDL_SCANCODE_CURRENCYUNIT = 180, + SDL_SCANCODE_CURRENCYSUBUNIT = 181, + SDL_SCANCODE_KP_LEFTPAREN = 182, + SDL_SCANCODE_KP_RIGHTPAREN = 183, + SDL_SCANCODE_KP_LEFTBRACE = 184, + SDL_SCANCODE_KP_RIGHTBRACE = 185, + SDL_SCANCODE_KP_TAB = 186, + SDL_SCANCODE_KP_BACKSPACE = 187, + SDL_SCANCODE_KP_A = 188, + SDL_SCANCODE_KP_B = 189, + SDL_SCANCODE_KP_C = 190, + SDL_SCANCODE_KP_D = 191, + SDL_SCANCODE_KP_E = 192, + SDL_SCANCODE_KP_F = 193, + SDL_SCANCODE_KP_XOR = 194, + SDL_SCANCODE_KP_POWER = 195, + SDL_SCANCODE_KP_PERCENT = 196, + SDL_SCANCODE_KP_LESS = 197, + SDL_SCANCODE_KP_GREATER = 198, + SDL_SCANCODE_KP_AMPERSAND = 199, + SDL_SCANCODE_KP_DBLAMPERSAND = 200, + SDL_SCANCODE_KP_VERTICALBAR = 201, + SDL_SCANCODE_KP_DBLVERTICALBAR = 202, + SDL_SCANCODE_KP_COLON = 203, + SDL_SCANCODE_KP_HASH = 204, + SDL_SCANCODE_KP_SPACE = 205, + SDL_SCANCODE_KP_AT = 206, + SDL_SCANCODE_KP_EXCLAM = 207, + SDL_SCANCODE_KP_MEMSTORE = 208, + SDL_SCANCODE_KP_MEMRECALL = 209, + SDL_SCANCODE_KP_MEMCLEAR = 210, + SDL_SCANCODE_KP_MEMADD = 211, + SDL_SCANCODE_KP_MEMSUBTRACT = 212, + SDL_SCANCODE_KP_MEMMULTIPLY = 213, + SDL_SCANCODE_KP_MEMDIVIDE = 214, + SDL_SCANCODE_KP_PLUSMINUS = 215, + SDL_SCANCODE_KP_CLEAR = 216, + SDL_SCANCODE_KP_CLEARENTRY = 217, + SDL_SCANCODE_KP_BINARY = 218, + SDL_SCANCODE_KP_OCTAL = 219, + SDL_SCANCODE_KP_DECIMAL = 220, + SDL_SCANCODE_KP_HEXADECIMAL = 221, + + SDL_SCANCODE_LCTRL = 224, + SDL_SCANCODE_LSHIFT = 225, + SDL_SCANCODE_LALT = 226, + SDL_SCANCODE_LGUI = 227, + SDL_SCANCODE_RCTRL = 228, + SDL_SCANCODE_RSHIFT = 229, + SDL_SCANCODE_RALT = 230, + SDL_SCANCODE_RGUI = 231, + + SDL_SCANCODE_MODE = 257, + + SDL_SCANCODE_AUDIONEXT = 258, + SDL_SCANCODE_AUDIOPREV = 259, + SDL_SCANCODE_AUDIOSTOP = 260, + SDL_SCANCODE_AUDIOPLAY = 261, + SDL_SCANCODE_AUDIOMUTE = 262, + SDL_SCANCODE_MEDIASELECT = 263, + SDL_SCANCODE_WWW = 264, + SDL_SCANCODE_MAIL = 265, + SDL_SCANCODE_CALCULATOR = 266, + SDL_SCANCODE_COMPUTER = 267, + SDL_SCANCODE_AC_SEARCH = 268, + SDL_SCANCODE_AC_HOME = 269, + SDL_SCANCODE_AC_BACK = 270, + SDL_SCANCODE_AC_FORWARD = 271, + SDL_SCANCODE_AC_STOP = 272, + SDL_SCANCODE_AC_REFRESH = 273, + SDL_SCANCODE_AC_BOOKMARKS = 274, + + SDL_SCANCODE_BRIGHTNESSDOWN = 275, + SDL_SCANCODE_BRIGHTNESSUP = 276, + SDL_SCANCODE_DISPLAYSWITCH = 277, + SDL_SCANCODE_KBDILLUMTOGGLE = 278, + SDL_SCANCODE_KBDILLUMDOWN = 279, + SDL_SCANCODE_KBDILLUMUP = 280, + SDL_SCANCODE_EJECT = 281, + SDL_SCANCODE_SLEEP = 282, + + SDL_NUM_SCANCODES = 512 +} SDL_Scancode; + +#define SDLK_SCANCODE_MASK (1 << 30) +#define SDL_SCANCODE_TO_KEYCODE(X) (X | SDLK_SCANCODE_MASK) + +enum { + SDLK_UNKNOWN = 0, + + SDLK_RETURN = '\r', + SDLK_ESCAPE = '\033', + SDLK_BACKSPACE = '\b', + SDLK_TAB = '\t', + SDLK_SPACE = ' ', + SDLK_EXCLAIM = '!', + SDLK_QUOTEDBL = '"', + SDLK_HASH = '#', + SDLK_PERCENT = '%', + SDLK_DOLLAR = '$', + SDLK_AMPERSAND = '&', + SDLK_QUOTE = '\'', + SDLK_LEFTPAREN = '(', + SDLK_RIGHTPAREN = ')', + SDLK_ASTERISK = '*', + SDLK_PLUS = '+', + SDLK_COMMA = ',', + SDLK_MINUS = '-', + SDLK_PERIOD = '.', + SDLK_SLASH = '/', + SDLK_0 = '0', + SDLK_1 = '1', + SDLK_2 = '2', + SDLK_3 = '3', + SDLK_4 = '4', + SDLK_5 = '5', + SDLK_6 = '6', + SDLK_7 = '7', + SDLK_8 = '8', + SDLK_9 = '9', + SDLK_COLON = ':', + SDLK_SEMICOLON = ';', + SDLK_LESS = '<', + SDLK_EQUALS = '=', + SDLK_GREATER = '>', + SDLK_QUESTION = '?', + SDLK_AT = '@', + /* + Skip uppercase letters + */ + SDLK_LEFTBRACKET = '[', + SDLK_BACKSLASH = '\\', + SDLK_RIGHTBRACKET = ']', + SDLK_CARET = '^', + SDLK_UNDERSCORE = '_', + SDLK_BACKQUOTE = '`', + SDLK_a = 'a', + SDLK_b = 'b', + SDLK_c = 'c', + SDLK_d = 'd', + SDLK_e = 'e', + SDLK_f = 'f', + SDLK_g = 'g', + SDLK_h = 'h', + SDLK_i = 'i', + SDLK_j = 'j', + SDLK_k = 'k', + SDLK_l = 'l', + SDLK_m = 'm', + SDLK_n = 'n', + SDLK_o = 'o', + SDLK_p = 'p', + SDLK_q = 'q', + SDLK_r = 'r', + SDLK_s = 's', + SDLK_t = 't', + SDLK_u = 'u', + SDLK_v = 'v', + SDLK_w = 'w', + SDLK_x = 'x', + SDLK_y = 'y', + SDLK_z = 'z', + + SDLK_CAPSLOCK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CAPSLOCK), + + SDLK_F1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F1), + SDLK_F2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F2), + SDLK_F3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F3), + SDLK_F4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F4), + SDLK_F5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F5), + SDLK_F6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F6), + SDLK_F7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F7), + SDLK_F8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F8), + SDLK_F9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F9), + SDLK_F10 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F10), + SDLK_F11 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F11), + SDLK_F12 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F12), + + SDLK_PRINTSCREEN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRINTSCREEN), + SDLK_SCROLLLOCK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SCROLLLOCK), + SDLK_PAUSE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAUSE), + SDLK_INSERT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_INSERT), + SDLK_HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HOME), + SDLK_PAGEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEUP), + SDLK_DELETE = '\177', + SDLK_END = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_END), + SDLK_PAGEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PAGEDOWN), + SDLK_RIGHT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RIGHT), + SDLK_LEFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LEFT), + SDLK_DOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DOWN), + SDLK_UP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UP), + + SDLK_NUMLOCKCLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_NUMLOCKCLEAR), + SDLK_KP_DIVIDE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DIVIDE), + SDLK_KP_MULTIPLY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MULTIPLY), + SDLK_KP_MINUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MINUS), + SDLK_KP_PLUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUS), + SDLK_KP_ENTER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_ENTER), + SDLK_KP_1 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_1), + SDLK_KP_2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_2), + SDLK_KP_3 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_3), + SDLK_KP_4 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_4), + SDLK_KP_5 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_5), + SDLK_KP_6 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_6), + SDLK_KP_7 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_7), + SDLK_KP_8 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_8), + SDLK_KP_9 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_9), + SDLK_KP_0 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_0), + SDLK_KP_PERIOD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERIOD), + + SDLK_APPLICATION = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_APPLICATION), + SDLK_POWER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_POWER), + SDLK_KP_EQUALS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALS), + SDLK_F13 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F13), + SDLK_F14 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F14), + SDLK_F15 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F15), + SDLK_F16 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F16), + SDLK_F17 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F17), + SDLK_F18 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F18), + SDLK_F19 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F19), + SDLK_F20 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F20), + SDLK_F21 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F21), + SDLK_F22 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F22), + SDLK_F23 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F23), + SDLK_F24 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_F24), + SDLK_EXECUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXECUTE), + SDLK_HELP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_HELP), + SDLK_MENU = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MENU), + SDLK_SELECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SELECT), + SDLK_STOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_STOP), + SDLK_AGAIN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AGAIN), + SDLK_UNDO = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_UNDO), + SDLK_CUT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CUT), + SDLK_COPY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COPY), + SDLK_PASTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PASTE), + SDLK_FIND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_FIND), + SDLK_MUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MUTE), + SDLK_VOLUMEUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEUP), + SDLK_VOLUMEDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_VOLUMEDOWN), + SDLK_KP_COMMA = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COMMA), + SDLK_KP_EQUALSAS400 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EQUALSAS400), + + SDLK_ALTERASE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_ALTERASE), + SDLK_SYSREQ = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SYSREQ), + SDLK_CANCEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CANCEL), + SDLK_CLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEAR), + SDLK_PRIOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_PRIOR), + SDLK_RETURN2 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RETURN2), + SDLK_SEPARATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SEPARATOR), + SDLK_OUT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OUT), + SDLK_OPER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_OPER), + SDLK_CLEARAGAIN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CLEARAGAIN), + SDLK_CRSEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CRSEL), + SDLK_EXSEL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EXSEL), + + SDLK_KP_00 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_00), + SDLK_KP_000 = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_000), + SDLK_THOUSANDSSEPARATOR = + SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_THOUSANDSSEPARATOR), + SDLK_DECIMALSEPARATOR = + SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DECIMALSEPARATOR), + SDLK_CURRENCYUNIT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYUNIT), + SDLK_CURRENCYSUBUNIT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CURRENCYSUBUNIT), + SDLK_KP_LEFTPAREN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTPAREN), + SDLK_KP_RIGHTPAREN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTPAREN), + SDLK_KP_LEFTBRACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LEFTBRACE), + SDLK_KP_RIGHTBRACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_RIGHTBRACE), + SDLK_KP_TAB = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_TAB), + SDLK_KP_BACKSPACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BACKSPACE), + SDLK_KP_A = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_A), + SDLK_KP_B = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_B), + SDLK_KP_C = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_C), + SDLK_KP_D = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_D), + SDLK_KP_E = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_E), + SDLK_KP_F = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_F), + SDLK_KP_XOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_XOR), + SDLK_KP_POWER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_POWER), + SDLK_KP_PERCENT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PERCENT), + SDLK_KP_LESS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_LESS), + SDLK_KP_GREATER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_GREATER), + SDLK_KP_AMPERSAND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AMPERSAND), + SDLK_KP_DBLAMPERSAND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLAMPERSAND), + SDLK_KP_VERTICALBAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_VERTICALBAR), + SDLK_KP_DBLVERTICALBAR = + SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DBLVERTICALBAR), + SDLK_KP_COLON = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_COLON), + SDLK_KP_HASH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HASH), + SDLK_KP_SPACE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_SPACE), + SDLK_KP_AT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_AT), + SDLK_KP_EXCLAM = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_EXCLAM), + SDLK_KP_MEMSTORE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSTORE), + SDLK_KP_MEMRECALL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMRECALL), + SDLK_KP_MEMCLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMCLEAR), + SDLK_KP_MEMADD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMADD), + SDLK_KP_MEMSUBTRACT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMSUBTRACT), + SDLK_KP_MEMMULTIPLY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMMULTIPLY), + SDLK_KP_MEMDIVIDE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_MEMDIVIDE), + SDLK_KP_PLUSMINUS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_PLUSMINUS), + SDLK_KP_CLEAR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEAR), + SDLK_KP_CLEARENTRY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_CLEARENTRY), + SDLK_KP_BINARY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_BINARY), + SDLK_KP_OCTAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_OCTAL), + SDLK_KP_DECIMAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_DECIMAL), + SDLK_KP_HEXADECIMAL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KP_HEXADECIMAL), + + SDLK_LCTRL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LCTRL), + SDLK_LSHIFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LSHIFT), + SDLK_LALT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LALT), + SDLK_LGUI = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_LGUI), + SDLK_RCTRL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RCTRL), + SDLK_RSHIFT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RSHIFT), + SDLK_RALT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RALT), + SDLK_RGUI = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_RGUI), + + SDLK_MODE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MODE), + + SDLK_AUDIONEXT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIONEXT), + SDLK_AUDIOPREV = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOPREV), + SDLK_AUDIOSTOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOSTOP), + SDLK_AUDIOPLAY = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOPLAY), + SDLK_AUDIOMUTE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOMUTE), + SDLK_MEDIASELECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MEDIASELECT), + SDLK_WWW = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_WWW), + SDLK_MAIL = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_MAIL), + SDLK_CALCULATOR = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_CALCULATOR), + SDLK_COMPUTER = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_COMPUTER), + SDLK_AC_SEARCH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_SEARCH), + SDLK_AC_HOME = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_HOME), + SDLK_AC_BACK = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BACK), + SDLK_AC_FORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_FORWARD), + SDLK_AC_STOP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_STOP), + SDLK_AC_REFRESH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_REFRESH), + SDLK_AC_BOOKMARKS = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AC_BOOKMARKS), + + SDLK_BRIGHTNESSDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_BRIGHTNESSDOWN), + SDLK_BRIGHTNESSUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_BRIGHTNESSUP), + SDLK_DISPLAYSWITCH = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_DISPLAYSWITCH), + SDLK_KBDILLUMTOGGLE = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMTOGGLE), + SDLK_KBDILLUMDOWN = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMDOWN), + SDLK_KBDILLUMUP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_KBDILLUMUP), + SDLK_EJECT = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_EJECT), + SDLK_SLEEP = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_SLEEP) +}; + +typedef enum { + KMOD_NONE = 0x0000, + KMOD_LSHIFT = 0x0001, + KMOD_RSHIFT = 0x0002, + KMOD_LCTRL = 0x0040, + KMOD_RCTRL = 0x0080, + KMOD_LALT = 0x0100, + KMOD_RALT = 0x0200, + KMOD_LGUI = 0x0400, + KMOD_RGUI = 0x0800, + KMOD_NUM = 0x1000, + KMOD_CAPS = 0x2000, + KMOD_MODE = 0x4000, + KMOD_RESERVED = 0x8000 +} SDL_Keymod; + +#define KMOD_CTRL (KMOD_LCTRL | KMOD_RCTRL) +#define KMOD_SHIFT (KMOD_LSHIFT | KMOD_RSHIFT) +#define KMOD_ALT (KMOD_LALT | KMOD_RALT) +#define KMOD_GUI (KMOD_LGUI | KMOD_RGUI) + +typedef struct SDL_Keysym { + int scancode; + SDL_Keycode sym; + uint16_t mod; + uint32_t unicode; +} SDL_Keysym; + +typedef enum { + SDL_FIRSTEVENT = 0, + + SDL_QUIT = 0x100, + + SDL_WINDOWEVENT = 0x200, + SDL_SYSWMEVENT, + + SDL_KEYDOWN = 0x300, + SDL_KEYUP, + SDL_TEXTEDITING, + SDL_TEXTINPUT, + + SDL_MOUSEMOTION = 0x400, + SDL_MOUSEBUTTONDOWN, + SDL_MOUSEBUTTONUP, + SDL_MOUSEWHEEL, + + SDL_INPUTMOTION = 0x500, + SDL_INPUTBUTTONDOWN, + SDL_INPUTBUTTONUP, + SDL_INPUTWHEEL, + SDL_INPUTPROXIMITYIN, + SDL_INPUTPROXIMITYOUT, + + SDL_JOYAXISMOTION = 0x600, + SDL_JOYBALLMOTION, + SDL_JOYHATMOTION, + SDL_JOYBUTTONDOWN, + SDL_JOYBUTTONUP, + SDL_JOYDEVICEADDED, + SDL_JOYDEVICEREMOVED, + + SDL_CONTROLLERAXISMOTION = 0x650, + SDL_CONTROLLERBUTTONDOWN, + SDL_CONTROLLERBUTTONUP, + SDL_CONTROLLERDEVICEADDED, + SDL_CONTROLLERDEVICEREMOVED, + + SDL_FINGERDOWN = 0x700, + SDL_FINGERUP, + SDL_FINGERMOTION, + SDL_TOUCHBUTTONDOWN, + SDL_TOUCHBUTTONUP, + + SDL_DOLLARGESTURE = 0x800, + SDL_DOLLARRECORD, + SDL_MULTIGESTURE, + + SDL_CLIPBOARDUPDATE = 0x900, + + SDL_DROPFILE = 0x1000, + + // ericf additions + SDL_DRAWEVENT = 0x1100, + SDL_RESIZEDRAWEVENT, + SDL_CONTEXTLOSTEVENT, + + SDL_USEREVENT = 0x8000, + + SDL_LASTEVENT = 0xFFFF +} SDL_EventType; + +typedef struct SDL_JoyAxisEvent { + uint32_t type; + uint32_t timestamp; + uint8_t which; + uint8_t axis; + uint8_t padding1; + uint8_t padding2; + int value; +} SDL_JoyAxisEvent; + +typedef struct SDL_JoyHatEvent { + uint32_t type; + uint32_t timestamp; + uint8_t which; + uint8_t hat; + uint8_t value; + uint8_t padding1; +} SDL_JoyHatEvent; + +#define SDL_HAT_CENTERED 0x00 +#define SDL_HAT_UP 0x01 +#define SDL_HAT_RIGHT 0x02 +#define SDL_HAT_DOWN 0x04 +#define SDL_HAT_LEFT 0x08 +#define SDL_HAT_RIGHTUP (SDL_HAT_RIGHT | SDL_HAT_UP) +#define SDL_HAT_RIGHTDOWN (SDL_HAT_RIGHT | SDL_HAT_DOWN) +#define SDL_HAT_LEFTUP (SDL_HAT_LEFT | SDL_HAT_UP) +#define SDL_HAT_LEFTDOWN (SDL_HAT_LEFT | SDL_HAT_DOWN) + +typedef struct SDL_MouseMotionEvent { + uint32_t type; + uint32_t timestamp; + uint32_t windowID; + uint8_t state; + uint8_t padding1; + uint8_t padding2; + uint8_t padding3; + int x; + int y; + int xrel; + int yrel; +} SDL_MouseMotionEvent; + +typedef struct SDL_JoyButtonEvent { + uint32_t type; + uint32_t timestamp; + uint8_t which; + uint8_t button; + uint8_t state; + uint8_t padding1; +} SDL_JoyButtonEvent; + +typedef struct SDL_MouseWheelEvent { + uint32_t type; + uint32_t timestamp; + uint32_t windowID; + int x; + int y; +} SDL_MouseWheelEvent; + +typedef struct SDL_MouseButtonEvent { + uint32_t type; + uint32_t timestamp; + uint32_t windowID; + uint8_t button; + uint8_t state; + uint8_t padding1; + uint8_t padding2; + int x; + int y; +} SDL_MouseButtonEvent; + +#define SDL_BUTTON(X) (1 << ((X)-1)) +#define SDL_BUTTON_LEFT 1 +#define SDL_BUTTON_MIDDLE 2 +#define SDL_BUTTON_RIGHT 3 +#define SDL_BUTTON_X1 4 +#define SDL_BUTTON_X2 5 +#define SDL_BUTTON_LMASK SDL_BUTTON(SDL_BUTTON_LEFT) +#define SDL_BUTTON_MMASK SDL_BUTTON(SDL_BUTTON_MIDDLE) +#define SDL_BUTTON_RMASK SDL_BUTTON(SDL_BUTTON_RIGHT) +#define SDL_BUTTON_X1MASK SDL_BUTTON(SDL_BUTTON_X1) +#define SDL_BUTTON_X2MASK SDL_BUTTON(SDL_BUTTON_X2) + +#define SDL_TEXTINPUTEVENT_TEXT_SIZE (32) + +typedef struct SDL_TextInputEvent { + uint32_t type; + uint32_t timestamp; + uint32_t windowID; + char text[SDL_TEXTINPUTEVENT_TEXT_SIZE]; +} SDL_TextInputEvent; + +typedef struct SDL_KeyboardEvent { + uint32_t type; + uint32_t timestamp; + uint32_t windowID; + uint8_t state; + uint8_t repeat; + uint8_t padding2; + uint8_t padding3; + SDL_Keysym keysym; +} SDL_KeyboardEvent; + +typedef union SDL_Event { + uint32_t type; + SDL_KeyboardEvent key; + SDL_TextInputEvent text; + SDL_MouseMotionEvent motion; + SDL_MouseButtonEvent button; + SDL_MouseWheelEvent wheel; + SDL_JoyAxisEvent jaxis; + SDL_JoyHatEvent jhat; + SDL_JoyButtonEvent jbutton; +} SDL_Event; + +#endif // BA_SDL_BUILD +#endif // BALLISTICA_PLATFORM_MIN_SDL_H_ diff --git a/src/ballistica/platform/platform.cc b/src/ballistica/platform/platform.cc new file mode 100644 index 00000000..3f5293ff --- /dev/null +++ b/src/ballistica/platform/platform.cc @@ -0,0 +1,1364 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/platform/platform.h" + +#if !BA_OSTYPE_WINDOWS +#include +#endif +#include + +// Trying to avoid platform-specific headers here except for +// a few mostly-cross-platform bits where its worth the mess. +#if !BA_OSTYPE_WINDOWS +#if BA_ENABLE_EXECINFO_BACKTRACES +#include +#endif +#include +#include +#include +#include +#endif + +#include +#include +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/headless_app.h" +#include "ballistica/app/vr_app.h" +#include "ballistica/core/thread.h" +#include "ballistica/dynamics/bg/bg_dynamics_server.h" +#include "ballistica/game/friend_score_set.h" +#include "ballistica/game/game.h" +#include "ballistica/game/score_to_beat.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/mesh/sprite_mesh.h" +#include "ballistica/graphics/vr_graphics.h" +#include "ballistica/input/input.h" +#include "ballistica/input/std_input_module.h" +#include "ballistica/networking/networking_sys.h" +#include "ballistica/platform/sdl/sdl_app.h" +#include "ballistica/python/python.h" + +// ------------------------- PLATFORM SELECTION -------------------------------- + +// This ugly chunk of macros simply pulls in the correct platform class header +// for each platform and defines the actual class g_platform will be. + +// Android --------------------------------------------------------------------- + +#if BA_OSTYPE_ANDROID +#if BA_GOOGLE_BUILD +#include "ballistica/platform/android/google/platform_android_google.h" +#define BA_PLATFORM_CLASS PlatformAndroidGoogle +#elif BA_AMAZON_BUILD +#include "ballistica/platform/android/amazon/platform_android_amazon.h" +#define BA_PLATFORM_CLASS PlatformAndroidAmazon +#elif BA_CARDBOARD_BUILD +#include "ballistica/platform/android/cardboard/platform_android_cardboard.h" +#define BA_PLATFORM_CLASS PlatformAndroidCardboard +#else // Generic android. +#include "ballistica/platform/android/platform_android.h" +#define BA_PLATFORM_CLASS PlatformAndroid +#endif // (Android subplatform) + +// Apple ----------------------------------------------------------------------- + +#elif BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS +#include "ballistica/platform/apple/platform_apple.h" +#define BA_PLATFORM_CLASS PlatformApple + +// Windows --------------------------------------------------------------------- + +#elif BA_OSTYPE_WINDOWS +#if BA_RIFT_BUILD +#include "ballistica/platform/windows/platform_windows_oculus.h" +#define BA_PLATFORM_CLASS PlatformWindowsOculus +#else // generic windows +#include "ballistica/platform/windows/platform_windows.h" +#define BA_PLATFORM_CLASS PlatformWindows +#endif // windows subtype + +// Linux ----------------------------------------------------------------------- + +#elif BA_OSTYPE_LINUX +#include "ballistica/platform/linux/platform_linux.h" +#define BA_PLATFORM_CLASS PlatformLinux +#else + +// Generic --------------------------------------------------------------------- + +#define BA_PLATFORM_CLASS Platform + +#endif + +// ----------------------- END PLATFORM SELECTION ------------------------------ + +#ifndef BA_PLATFORM_CLASS +#error no BA_PLATFORM_CLASS defined for this platform +#endif + +namespace ballistica { + +auto Platform::Create() -> Platform* { + auto platform = new BA_PLATFORM_CLASS(); + return platform; +} + +void Platform::FinalCleanup() { + if (g_app_globals->temp_cleanup_callback) { + g_app_globals->temp_cleanup_callback(); + } +} + +Platform::Platform() : starttime_(GetCurrentMilliseconds()) {} + +auto Platform::PostInit() -> void {} + +Platform::~Platform() = default; + +auto Platform::GetUniqueDeviceIdentifier() -> const std::string& { + if (!have_device_uuid_) { + device_uuid_ = GetDeviceUUIDPrefix(); + + std::string real_unique_uuid; + bool have_real_unique_uuid = GetRealDeviceUUID(&real_unique_uuid); + if (have_real_unique_uuid) { + device_uuid_ += real_unique_uuid; + } + + // Keep demo/arcade uuids unique. + if (g_buildconfig.demo_build()) { + device_uuid_ += "_d"; + } else if (g_buildconfig.arcade_build()) { + device_uuid_ += "_a"; + } + + // Ok, as a fallback on platforms where we don't yet have a way to get a + // real UUID, lets do our best to generate one and stuff it in a file + // in our config dir. This should be globally-unique, but the downside is + // the user can tamper with it. + if (!have_real_unique_uuid) { + std::string path = GetConfigDirectory() + BA_DIRSLASH + ".bsuuid"; + + if (FILE* f = FOpen(path.c_str(), "rb")) { + // There's an existing one; read it. + char buffer[100]; + size_t size = fread(buffer, 1, 99, f); + if (size >= 0) { + assert(size < 100); + buffer[size] = 0; + device_uuid_ += buffer; + } + fclose(f); + } else { + // No existing one; generate it. + std::string val = GenerateUUID(); + device_uuid_ += val; + if (FILE* f2 = FOpen(path.c_str(), "wb")) { + size_t result = fwrite(val.c_str(), val.size(), 1, f2); + if (result != 1) Log("unable to write bsuuid file."); + fclose(f2); + } else { + Log("unable to open bsuuid file for writing: '" + path + "'"); + } + } + } + have_device_uuid_ = true; + } + return device_uuid_; +} + +auto Platform::GetDeviceUUIDPrefix() -> std::string { + Log("GetDeviceUUIDPrefix() unimplemented"); + return "u"; +} + +auto Platform::GetRealDeviceUUID(std::string* uuid) -> bool { return false; } + +auto Platform::GenerateUUID() -> std::string { + throw Exception("GenerateUUID() unimplemented"); +} + +auto Platform::GetDefaultConfigDir() -> std::string { + std::string config_dir; + // As a default, look for a HOME env var and use that if present + // this will cover linux and command-line macOS. + char* home = getenv("HOME"); + if (home) { + config_dir = std::string(home) + "/.ballisticacore"; + } else { + printf("GetDefaultConfigDir: can't get env var \"HOME\"\n"); + fflush(stdout); + throw Exception(); + } + return config_dir; +} + +auto Platform::GetConfigFilePath() -> std::string { + return GetConfigDirectory() + BA_DIRSLASH + "config.json"; +} + +auto Platform::GetLowLevelConfigValue(const char* key, int default_value) + -> int { + std::string path = GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key; + int val = default_value; + FILE* f = FOpen(path.c_str(), "r"); + if (f) { + int val2; + int result = fscanf(f, "%d", &val2); // NOLINT + if (result == 1) { + // I'm guessing scanned val is probably untouched on failure + // but why risk it? Let's only copy it in if it looks successful. + val = val2; + } + fclose(f); + } + return val; +} + +void Platform::SetLowLevelConfigValue(const char* key, int value) { + std::string path = GetConfigDirectory() + BA_DIRSLASH + ".cvar_" + key; + std::string out = std::to_string(value); + FILE* f = FOpen(path.c_str(), "w"); + if (f) { + size_t result = fwrite(out.c_str(), out.size(), 1, f); + if (result != 1) Log("unable to write low level config file."); + fclose(f); + } else { + Log("unable to open low level config file for writing."); + } +} + +auto Platform::GetUserPythonDirectory() -> std::string { + // Make sure it exists the first time we run. + static bool attempted_to_make_user_scripts_dir = false; + + if (!attempted_to_make_user_scripts_dir) { + user_scripts_dir_ = DoGetUserPythonDirectory(); + + // Attempt to make it. (it's ok if this fails) + MakeDir(user_scripts_dir_, true); + attempted_to_make_user_scripts_dir = true; + } + return user_scripts_dir_; +} + +auto Platform::GetAppPythonDirectory() -> std::string { + static bool checked_dir = false; + if (!checked_dir) { + checked_dir = true; + + // If there is a sys/VERSION in the user-python dir we use that. + app_python_dir_ = GetUserPythonDirectory() + BA_DIRSLASH + "sys" + + BA_DIRSLASH + kAppVersion; + + // Fall back to our default if that doesn't exist. + if (FilePathExists(app_python_dir_)) { + using_custom_app_python_dir_ = true; + Log("Using custom app Python path: '" + + (GetUserPythonDirectory() + BA_DIRSLASH + "sys" + BA_DIRSLASH + + kAppVersion) + + "'.", + true, false); + + } else { + // Going with relative paths for cleaner tracebacks... + app_python_dir_ = std::string("ba_data") + BA_DIRSLASH + "python"; + } + } + return app_python_dir_; +} + +auto Platform::GetSitePythonDirectory() -> std::string { + static bool checked_dir = false; + if (!checked_dir) { + checked_dir = true; + + if (!FilePathExists(site_python_dir_)) { + // Going with relative paths for cleaner tracebacks... + site_python_dir_ = + std::string("ba_data") + BA_DIRSLASH + "python-site-packages"; + } + } + return site_python_dir_; +} + +auto Platform::GetReplaysDir() -> std::string { + static bool made_dir = false; + if (!made_dir) { + replays_dir_ = GetConfigDirectory() + BA_DIRSLASH + "replays"; + MakeDir(replays_dir_); + made_dir = true; + } + return replays_dir_; +} + +// rename() supporting UTF8 strings. +auto Platform::Rename(const char* oldname, const char* newname) -> int { + // this covers non-windows platforms +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + return rename(oldname, newname); +#endif +} + +auto Platform::Remove(const char* path) -> int { + // this covers non-windows platforms +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + return remove(path); +#endif +} + +// stat() supporting UTF8 strings. +auto Platform::Stat(const char* path, struct BA_STAT* buffer) -> int { + // this covers non-windows platforms +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + return stat(path, buffer); +#endif +} + +// fopen() supporting UTF8 strings. +auto Platform::FOpen(const char* path, const char* mode) -> FILE* { + // this covers non-windows platforms +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + return fopen(path, mode); +#endif +} + +auto Platform::FilePathExists(const std::string& name) -> bool { + struct BA_STAT buffer {}; + return (Stat(name.c_str(), &buffer) == 0); +} + +auto Platform::GetSocketErrorString() -> std::string { + // On default platforms we just look at errno. + return GetErrnoString(); +} + +auto Platform::GetSocketError() -> int { + // by default this is simply errno + return errno; +} + +auto Platform::GetErrnoString() -> std::string { + // this covers non-windows platforms +#if BA_OSTYPE_WINDOWS + throw Exception(); +#elif BA_OSTYPE_LINUX + // We seem to be getting a gnu-specific version on linux + // which returns a char pointer that doesn't always point + // to the provided buffer. Sounds like there's a way to + // get the posix version which returns an error int through some + // #define magic but just gonna handle both flavors for now + char buffer[256]; + buffer[0] = 0; + const char* s = strerror_r(errno, buffer, sizeof(buffer)); + buffer[255] = 0; // Not sure if we need to clamp on overrun but cant hurt. + return s; +#else + char buffer[256]; + buffer[0] = 0; + strerror_r(errno, buffer, sizeof(buffer)); + buffer[255] = 0; // Not sure if we need to clamp on overrun but cant hurt. + return buffer; +#endif +} + +// Return the ballisticacore config dir +// This does not vary across versions. +auto Platform::GetConfigDirectory() -> std::string { + // Make sure args have been handled since we use them. + assert(g_app_globals->args_handled); + + if (!have_config_dir_) { + // If the user provided cfgdir as an arg. + if (!g_app_globals->user_config_dir.empty()) { + config_dir_ = g_app_globals->user_config_dir; + } else { + config_dir_ = GetDefaultConfigDir(); + } + + // Try to make sure the config dir exists. + MakeDir(config_dir_); + + have_config_dir_ = true; + } + return config_dir_; +} + +void Platform::MakeDir(const std::string& dir, bool quiet) { + bool exists = FilePathExists(dir); + if (!exists) { + DoMakeDir(dir, quiet); + + // Non-quiet call should result in directory existing. + // (or an exception should have been raised) + assert(quiet || FilePathExists(dir)); + } +} + +auto Platform::GetExternalStoragePath() -> std::string { + throw Exception("GetExternalStoragePath() unimplemented"); +} + +auto Platform::DoGetUserPythonDirectory() -> std::string { + return GetConfigDirectory() + BA_DIRSLASH + "mods"; +} + +void Platform::DoMakeDir(const std::string& dir, bool quiet) { + // Default case here covers all non-windows platforms. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + int result = mkdir(dir.c_str(), + // NOLINTNEXTLINE (signed values in bitwise stuff) + S_IRWXU | S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH); + if (result != 0 && errno != EEXIST && !quiet) { + throw Exception("Unable to create directory '" + dir + "' (errno " + + std::to_string(errno) + ")"); + } +#endif +} + +auto Platform::GetLocale() -> std::string { + const char* lang = getenv("LANG"); + if (lang) { + return lang; + } else { + if (!g_buildconfig.headless_build()) { + BA_LOG_ONCE("No LANG value available; defaulting to en_US"); + } + return "en_US"; + } +} + +auto Platform::GetDeviceName() -> std::string { + static std::string device_name; + static bool have_device_name = false; + + // In headless-mode we always return our party name if that's available + // (otherwise everything will just be BallisticaCore Game). + // UPDATE: hmm don't think I like this. Device-name is supposed to go into + // user-agent-strings and whatnot. + // Should probably inject public party name at a higher level. + if (g_buildconfig.headless_build()) { + // Hmm this might be called from non-main threads; should + // think about ensuring this is thread-safe perhaps. + if (g_python != nullptr) { + std::string pname = g_game->public_party_name(); + if (!pname.empty()) { + device_name = pname; + have_device_name = true; + } + } + } + + if (!have_device_name) { + device_name = DoGetDeviceName(); + + // Hmm seem to get some funky invalid utf8 out of + // this sometimes (mainly on windows). Should look into that + // more closely or at least log it somewhere. + device_name = Utils::GetValidUTF8(device_name.c_str(), "dn"); + have_device_name = true; + } + return device_name; +} + +auto Platform::DoGetDeviceName() -> std::string { + return "BallisticaCore Game"; +} + +auto Platform::IsRunningOnTV() -> bool { return false; } + +auto Platform::HasTouchScreen() -> bool { + if (!have_has_touchscreen_value_) { + have_touchscreen_ = DoHasTouchScreen(); + have_has_touchscreen_value_ = true; + } + return have_touchscreen_; +} + +auto Platform::IsRunningOnFireTV() -> bool { return false; } + +auto Platform::IsRunningOnDaydream() -> bool { return false; } + +auto Platform::DoHasTouchScreen() -> bool { throw Exception("UNIMPLEMENTED"); } + +auto Platform::IsRunningOnDesktop() -> bool { + // Default case to cover mac, win, etc. + return true; +} + +void Platform::SleepMS(millisecs_t ms) { + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + +// General one-time initialization stuff +static void Init() { + // Sanity check: make sure asserts are stripped out of release builds + // (NDEBUG should do this). +#if !BA_DEBUG_BUILD +#ifndef NDEBUG +#error Expected NDEBUG to be defined for release builds. +#endif // NDEBUG + assert(true); +#endif // !BA_DEBUG_BUILD + + // Are we running in a terminal? + if (g_buildconfig.use_stdin_thread()) { + g_app_globals->is_stdin_a_terminal = g_platform->IsStdinATerminal(); + } else { + g_app_globals->is_stdin_a_terminal = false; + } + + // If we're running in a terminal, print some info. + if (g_app_globals->is_stdin_a_terminal) { + if (g_buildconfig.headless_build()) { + printf("BallisticaCore Headless %s build %d.\n", kAppVersion, + kAppBuildNumber); + fflush(stdout); + } else { + printf("BallisticaCore %s build %d.\n", kAppVersion, kAppBuildNumber); + fflush(stdout); + } + } + + g_app_globals->user_agent_string = g_platform->GetUserAgentString(); + + // Figure out where our data is and chdir there. + g_platform->SetupDataDirectory(); + + // Run these just to make sure these dirs exist. + // (otherwise they might not get made if nothing writes to them). + g_platform->GetConfigDirectory(); + g_platform->GetUserPythonDirectory(); +} + +static void HandleArgs(int argc, char** argv) { + assert(!g_app_globals->args_handled); + g_app_globals->args_handled = true; + + // If there's just one arg and it's "--version", return the version. + if (argc == 2 && !strcmp(argv[1], "--version")) { + printf("Ballistica %s build %d\n", kAppVersion, kAppBuildNumber); + fflush(stdout); + exit(0); + } + for (int i = 1; i < argc; ++i) { + // In our rift build, a '-2d' arg causes us to run in regular 2d mode. + if (g_buildconfig.rift_build() && !strcmp(argv[i], "-2d")) { + g_app_globals->vr_mode = false; + } else if (!strcmp(argv[i], "-exec")) { + if (i + 1 < argc) { + g_app_globals->game_commands = argv[i + 1]; + } else { + printf("%s", "Error: expected arg after -exec\n"); + fflush(stdout); + exit(-1); + } + } else if (!strcmp(argv[i], "-cfgdir")) { + if (i + 1 < argc) { + g_app_globals->user_config_dir = argv[i + 1]; + + // Need to remove this limitation!!! + // Don't remember why it's here; something about not being able to + // create nested directories properly in windows. But perhaps we + // can just error if a dir is provided that's invalid. + if (g_app_globals->user_config_dir != "ba_root") { + printf("%s", "ERROR: -cfgdir currently has to be 'ba_root'\n"); + fflush(stdout); + exit(-1); + } + + // Need to convert this to an abs path since we chdir soon. + std::string buffer = g_platform->GetCWD(); + if (buffer.empty()) { + printf("%s", "ERROR: unable to get cwd for cfgdir setup\n"); + fflush(stdout); + exit(-1); + } + g_app_globals->user_config_dir = + std::string(buffer) + BA_DIRSLASH + g_app_globals->user_config_dir; + } else { + Log("ERROR: expected arg after -cfgdir"); + exit(-1); + } + } + } + + // In Android's case we have to pull our exec arg from the java/kotlin layer. + if (g_buildconfig.ostype_android()) { + g_app_globals->game_commands = g_platform->GetAndroidExecArg(); + } + + // TEMP/HACK: hard code launch args. + if (explicit_bool(false)) { + if (g_buildconfig.ostype_android()) { + g_app_globals->game_commands = + "import ba.internal; ba.internal.run_stress_test()"; + } + } +} + +void Platform::CreateApp() { + assert(g_app_globals); + assert(InMainThread()); + + // Hmm do these belong here?... + HandleArgs(g_app_globals->argc, g_app_globals->argv); + Init(); + +// TEMP - need to init sdl on our legacy mac build even though its not +// technically an SDL app. Kill this once the old mac build is gone. +#if BA_LEGACY_MACOS_BUILD + SDLApp::InitSDL(); +#endif + +#if BA_HEADLESS_BUILD + g_main_thread->AddModule(); +#elif BA_RIFT_BUILD + // Rift build can spin up in either VR or regular mode. + if (g_app_globals->vr_mode) { + g_main_thread->AddModule(); + } else { + g_main_thread->AddModule(); + } +#elif BA_CARDBOARD_BUILD + g_main_thread->AddModule(); +#elif BA_SDL_BUILD + g_main_thread->AddModule(); +#else + g_main_thread->AddModule(); +#endif + + // Let app do any init it needs to after it is fully constructed. + g_app->PostInit(); +} + +auto Platform::CreateGraphics() -> Graphics* { + assert(InGameThread()); +#if BA_VR_BUILD + return new VRGraphics(); +#else + return new Graphics(); +#endif +} + +auto Platform::GetKeyName(int keycode) -> std::string { + // On our actual SDL platforms we're trying to be *pure* sdl so + // call their function for this. Otherwise we call our own version + // of it which is basically the same thing (at least for now). +#if BA_SDL_BUILD && !BA_MINSDL_BUILD + return SDL_GetKeyName(static_cast(keycode)); +#else + return g_input->GetKeyName(keycode); +#endif +} + +void Platform::CreateAuxiliaryModules() { +#if !BA_HEADLESS_BUILD + auto bg_dynamics_thread = new Thread(ThreadIdentifier::kBGDynamics); + g_app_globals->pausable_threads.push_back(bg_dynamics_thread); +#endif +#if !BA_HEADLESS_BUILD + bg_dynamics_thread->AddModule(); +#endif + + if (g_buildconfig.use_stdin_thread()) { + // Start listening for stdin commands (on platforms where that makes sense). + // Note: this thread blocks indefinitely for input so we don't add it to the + // pausable list. + auto std_input_thread = new Thread(ThreadIdentifier::kStdin); + std_input_thread->AddModule(); + g_std_input_module->PushBeginReadCall(); + } +} + +void Platform::WillExitMain(bool errored) {} + +auto Platform::GetInterfaceType() -> UIScale { + // Handles mac/pc/linux cases. + return UIScale::kLarge; +} + +void Platform::HandleLog(const std::string& msg) { + // Do nothing by default. +} + +auto Platform::ReportFatalError(const std::string& message, + bool in_top_level_exception_handler) -> bool { + // Don't override handling by default. + return false; +} + +auto Platform::HandleFatalError(bool exit_cleanly, + bool in_top_level_exception_handler) -> bool { + // Don't override handling by default. + return false; +} + +auto Platform::CanShowBlockingFatalErrorDialog() -> bool { + if (g_buildconfig.sdl2_build()) { + return true; + } else { + return false; + } +} + +auto Platform::BlockingFatalErrorDialog(const std::string& message) -> void { +#if BA_SDL2_BUILD + assert(InMainThread()); + if (!HeadlessMode()) { + SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Fatal Error", + message.c_str(), nullptr); + } +#endif +} + +void Platform::SetupDataDirectory() { +// This covers non-windows cases. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + // Default to './ba_data'. + DIR* d = opendir("ba_data"); + if (d == nullptr) { + throw Exception("ba_data directory not found."); + } + closedir(d); +#endif + + // Apparently Android NDK 22 includes std::filesystem; once that is out + // then we should be able to use this everywhere. + // Oh - and we also need to wait for GCC 8, so when we switch to Ubuntu20... + // Oh; and we should see if switch/etc. supports it before making it a hard + // requirement. + // if (!std::filesystem::is_directory("ba_data")) { + // throw Exception("ba_data directory not found."); + // } +} + +void Platform::SetEnv(const std::string& name, const std::string& value) { +// This covers non-windows cases. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + auto result = setenv(name.c_str(), value.c_str(), true); + if (result != 0) { + throw Exception("Failed to set environment variable '" + name + + "'; errno=" + std::to_string(errno)); + } +#endif +} + +auto Platform::IsStdinATerminal() -> bool { +// This covers non-windows cases. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + return static_cast(isatty(fileno(stdin))); +#endif +} + +auto Platform::GetOSVersionString() -> std::string { return ""; } + +auto Platform::GetUserAgentString() -> std::string { + // Fetch our device name here from main thread so it'll be safe + // to from other threads later (it gets cached as a string) + std::string device = GetDeviceName(); + + std::string version = GetOSVersionString(); + if (!version.empty()) { + version = " " + version; + } + + // Include a store identifier in the build. + std::string subplatform; + if (g_buildconfig.headless_build()) { + subplatform = "HdlS"; + } else if (g_buildconfig.cardboard_build()) { + subplatform = "GpCb"; + } else if (g_buildconfig.gearvr_build()) { + subplatform = "OcGVRSt"; + } else if (g_buildconfig.rift_build()) { + subplatform = "OcRftSt"; + } else if (g_buildconfig.amazon_build()) { + subplatform = "AmSt"; + } else if (g_buildconfig.google_build()) { + subplatform = "GpSt"; + } else if (g_buildconfig.use_store_kit() && g_buildconfig.ostype_macos()) { + subplatform = "McApSt"; + } else if (g_buildconfig.use_store_kit() && g_buildconfig.ostype_ios()) { + subplatform = "IosApSt"; + } else if (g_buildconfig.use_store_kit() && g_buildconfig.ostype_tvos()) { + subplatform = "TvsApSt"; + } else if (g_buildconfig.demo_build()) { + subplatform = "DeMo"; + } else if (g_buildconfig.arcade_build()) { + subplatform = "ArCd"; + } else if (g_buildconfig.iircade_build()) { + subplatform = "iiRcd"; + } else { + subplatform = "TstB"; + } + + if (!subplatform.empty()) { + subplatform = " " + subplatform; + } + if (IsRunningOnTV()) { + subplatform += " OnTV"; + } + return std::string("BallisticaCore ") + kAppVersion + subplatform + " (" + + std::to_string(kAppBuildNumber) + ") (" + + g_buildconfig.platform_string() + version + "; " + device + "; " + + GetLocale() + ")"; +} + +auto Platform::GetCWD() -> std::string { +// Covers non-windows cases. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + char buffer[PATH_MAX]; + return getcwd(buffer, sizeof(buffer)); +#endif +} + +auto Platform::GetAndroidExecArg() -> std::string { return ""; } + +void Platform::GetTextBoundsAndWidth(const std::string& text, Rect* r, + float* width) { + throw Exception(); +} + +void Platform::FreeTextTexture(void* tex) { throw Exception(); } + +auto Platform::CreateTextTexture(int width, int height, + const std::vector& strings, + const std::vector& positions, + const std::vector& widths, float scale) + -> void* { + throw Exception(); +} + +auto Platform::GetTextTextureData(void* tex) -> uint8_t* { throw Exception(); } + +void Platform::OnBootstrapComplete() {} + +auto Platform::ConvertIncomingLeaderboardScore( + const std::string& leaderboard_id, int score) -> int { + return score; +} + +void Platform::GetFriendScores(const std::string& game, + const std::string& game_version, void* data) { + // As a default, just fail gracefully. + Log("FIXME: GetFriendScores unimplemented"); + g_game->PushFriendScoreSetCall(FriendScoreSet(false, data)); +} + +void Platform::SubmitScore(const std::string& game, const std::string& version, + int64_t score) { + Log("FIXME: SubmitScore() unimplemented"); +} + +void Platform::ReportAchievement(const std::string& achievement) {} + +auto Platform::HaveLeaderboard(const std::string& game, + const std::string& config) -> bool { + return false; +} + +void Platform::EditText(const std::string& title, const std::string& value, + int max_chars) { + Log("FIXME: EditText() unimplemented"); +} + +void Platform::ShowOnlineScoreUI(const std::string& show, + const std::string& game, + const std::string& game_version) { + Log("FIXME: ShowOnlineScoreUI() unimplemented"); +} + +void Platform::Purchase(const std::string& item) { + // Just print 'unavailable' by default. + g_python->PushObjCall(Python::ObjID::kUnavailableMessageCall); +} + +void Platform::RestorePurchases() { Log("RestorePurchases() unimplemented"); } + +void Platform::AndroidSetResString(const std::string& res) { + throw Exception(); +} + +void Platform::ApplyConfig() {} + +void Platform::AndroidSynthesizeBackPress() { + Log("AndroidSynthesizeBackPress() unimplemented"); +} + +void Platform::AndroidQuitActivity() { + Log("AndroidQuitActivity() unimplemented"); +} + +auto Platform::GetDeviceAccountID() -> std::string { + if (HeadlessMode()) { + return "S-" + GetUniqueDeviceIdentifier(); + } + + // Everything else is just considered a 'local' account, though we may + // give unique ids for unique builds.. + if (g_buildconfig.iircade_build()) { + return "L-iRc" + GetUniqueDeviceIdentifier(); + } + return "L-" + GetUniqueDeviceIdentifier(); +} + +auto Platform::DemangleCXXSymbol(const std::string& s) -> std::string { + // Do __cxa_demangle on platforms that support it. + // FIXME; I believe there's an equivalent call for windows; should research. +#if !BA_OSTYPE_WINDOWS + int demangle_status; + + // If we pass null for buffers, this mallocs one for us that we have to free. + char* demangled_name = + abi::__cxa_demangle(s.c_str(), nullptr, nullptr, &demangle_status); + if (demangled_name != nullptr) { + if (demangle_status != 0) { + BA_LOG_ONCE("__cxa_demangle got buffer but non-zero status; unexpected"); + } + std::string retval = demangled_name; + free(static_cast(demangled_name)); + return retval; + } else { + return s; + } +#else + return s; +#endif +} + +auto Platform::NewAutoReleasePool() -> void* { throw Exception(); } + +void Platform::DrainAutoReleasePool(void* pool) { throw Exception(); } + +auto Platform::AndroidGPGSNewConnectionToClient(int id) -> ConnectionToClient* { + throw Exception(); +} +auto Platform::AndroidGPGSNewConnectionToHost() -> ConnectionToHost* { + throw Exception(); +} + +auto Platform::AndroidIsGPGSConnectionToClient(ConnectionToClient* c) -> bool { + throw Exception(); +} + +void Platform::OpenURL(const std::string& url) { + // Can't open URLs in VR - just tell the game thread to show the url. + if (IsVRMode()) { + g_game->PushShowURLCall(url); + return; + } + + // Otherwise fall back to our platform-specific handler. + g_platform->DoOpenURL(url); +} + +void Platform::DoOpenURL(const std::string& url) { + Log("DoOpenURL unimplemented on this platform."); +} + +void Platform::ResetAchievements() { Log("ResetAchievements() unimplemented"); } + +void Platform::GameCenterLogin() { throw Exception(); } + +void Platform::PurchaseAck(const std::string& purchase, + const std::string& order_id) { + Log("PurchaseAck() unimplemented"); +} + +void Platform::RunEvents() {} + +auto Platform::GetMemUsageInfo() -> std::string { return "0,0,0"; } + +void Platform::OnAppPause() {} +void Platform::OnAppResume() {} + +void Platform::MusicPlayerPlay(PyObject* target) { + Log("MusicPlayerPlay() unimplemented on this platform"); +} +void Platform::MusicPlayerStop() { + Log("MusicPlayerStop() unimplemented on this platform"); +} +void Platform::MusicPlayerShutdown() { + Log("MusicPlayerShutdown() unimplemented on this platform"); +} + +void Platform::MusicPlayerSetVolume(float volume) { + Log("MusicPlayerSetVolume() unimplemented on this platform"); +} + +auto Platform::IsOSPlayingMusic() -> bool { return false; } + +void Platform::AndroidShowAppInvite(const std::string& title, + const std::string& message, + const std::string& code) { + Log("AndroidShowAppInvite() unimplemented"); +} + +void Platform::IncrementAnalyticsCount(const std::string& name, int increment) { +} + +void Platform::IncrementAnalyticsCountRaw(const std::string& name, + int increment) {} + +void Platform::IncrementAnalyticsCountRaw2(const std::string& name, + int uses_increment, int increment) {} + +void Platform::SetAnalyticsScreen(const std::string& screen) {} + +void Platform::SubmitAnalyticsCounts() {} + +void Platform::SetPlatformMiscReadVals(const std::string& vals) {} + +void Platform::AndroidRefreshFile(const std::string& file) { + Log("AndroidRefreshFile() unimplemented"); +} + +void Platform::ShowAd(const std::string& purpose) { + Log("ShowAd() unimplemented"); +} + +auto Platform::GetHasAds() -> bool { return false; } + +auto Platform::GetHasVideoAds() -> bool { + // By default we assume we have this anywhere we have ads. + return GetHasAds(); +} + +void Platform::AndroidGPGSPartyInvitePlayers() { + Log("AndroidGPGSPartyInvitePlayers() unimplemented"); +} + +void Platform::AndroidGPGSPartyShowInvites() { + Log("AndroidGPGSPartyShowInvites() unimplemented"); +} + +void Platform::AndroidGPGSPartyInviteAccept(const std::string& invite_id) { + Log("AndroidGPGSPartyInviteAccept() unimplemented"); +} + +void Platform::SignIn(const std::string& account_type) { + Log("SignIn() unimplemented"); +} + +void Platform::SignOut() { Log("SignOut() unimplemented"); } + +void Platform::AndroidShowWifiSettings() { + Log("AndroidShowWifiSettings() unimplemented"); +} + +void Platform::SetHardwareCursorVisible(bool visible) { +// FIXME: Forward this to app?.. +#if BA_SDL_BUILD + SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); +#endif +} + +void Platform::QuitApp() { exit(g_app_globals->return_value); } + +void Platform::GetScoresToBeat(const std::string& level, + const std::string& config, void* py_callback) { + // By default, return nothing. + g_game->PushScoresToBeatResponseCall(false, std::list(), + py_callback); +} + +void Platform::OpenFileExternally(const std::string& path) { + Log("OpenFileExternally() unimplemented"); +} + +void Platform::OpenDirExternally(const std::string& path) { + Log("OpenDirExternally() unimplemented"); +} + +void Platform::MacMusicAppInit() { Log("MacMusicAppInit() unimplemented"); } + +auto Platform::MacMusicAppGetVolume() -> int { + Log("MacMusicAppGetVolume() unimplemented"); + return 0; +} + +void Platform::MacMusicAppSetVolume(int volume) { + Log("MacMusicAppSetVolume() unimplemented"); +} + +void Platform::MacMusicAppGetLibrarySource() { + Log("MacMusicAppGetLibrarySource() unimplemented"); +} + +void Platform::MacMusicAppStop() { Log("MacMusicAppStop() unimplemented"); } + +auto Platform::MacMusicAppPlayPlaylist(const std::string& playlist) -> bool { + Log("MacMusicAppPlayPlaylist() unimplemented"); + return false; +} +auto Platform::MacMusicAppGetPlaylists() -> std::list { + Log("MacMusicAppGetPlaylists() unimplemented"); + return std::list(); +} + +void Platform::StartListeningForWiiRemotes() { + Log("StartListeningForWiiRemotes() unimplemented"); +} + +void Platform::StopListeningForWiiRemotes() { + Log("StopListeningForWiiRemotes() unimplemented"); +} + +void Platform::SetCurrentThreadName(const std::string& name) { + // Currently we leave the main thread alone, otherwise we show up as + // "BallisticaMainThread" under "top" on linux (should check other platforms). + if (InMainThread()) { + return; + } +#if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS + pthread_setname_np(name.c_str()); +#elif BA_OSTYPE_LINUX || BA_OSTYPE_ANDROID + pthread_setname_np(pthread_self(), name.c_str()); +#endif +} + +void Platform::Unlink(const char* path) { + // This covers all but windows. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + unlink(path); +#endif +} + +auto Platform::IsEventPushMode() -> bool { return false; } + +auto Platform::GetDisplayResolution(int* x, int* y) -> bool { return false; } + +void Platform::CloseSocket(int socket) { +// This covers all but windows. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + close(socket); +#endif +} + +auto Platform::SocketPair(int domain, int type, int protocol, int socks[2]) + -> int { + // This covers all but windows. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + return socketpair(domain, type, protocol, socks); +#endif +} + +auto Platform::GetBroadcastAddrs() -> std::vector { +// This covers all but windows. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + std::vector addrs; + struct ifaddrs* ifaddr; + if (getifaddrs(&ifaddr) != -1) { + int i = 0; + for (ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + // Turns out this can be null if the interface has no addrs. + if (ifa->ifa_addr == nullptr) { + continue; + } + int family = ifa->ifa_addr->sa_family; + if (family == AF_INET) { + if (ifa->ifa_addr != nullptr) { + uint32_t addr = ntohl( // NOLINT (clang-tidy signed bitwise whining) + (reinterpret_cast(ifa->ifa_addr))->sin_addr.s_addr); + uint32_t sub = ntohl( // NOLINT (clang-tidy signed bitwise whining) + (reinterpret_cast(ifa->ifa_netmask)) + ->sin_addr.s_addr); + uint32_t broadcast = addr | (~sub); + addrs.push_back(broadcast); + i++; + } + } + } + freeifaddrs(ifaddr); + } + return addrs; +#endif +} + +auto Platform::SetSocketNonBlocking(int sd) -> bool { +// This covers all but windows. +#if BA_OSTYPE_WINDOWS + throw Exception(); +#else + int result = fcntl(sd, F_SETFL, O_NONBLOCK); + if (result != 0) { + Log("Error setting non-blocking socket: " + + g_platform->GetSocketErrorString()); + return false; + } + return true; +#endif +} + +auto Platform::GetTicks() -> millisecs_t { + return GetCurrentMilliseconds() - starttime_; +} + +auto Platform::GetPlatformName() -> std::string { + throw Exception("UNIMPLEMENTED"); +} + +auto Platform::GetSubplatformName() -> std::string { + // This doesnt always have to be set. + return ""; +} + +auto Platform::ContainsPythonDist() -> bool { return false; } + +#pragma mark Stack Traces + +#if BA_ENABLE_EXECINFO_BACKTRACES + +// Stack traces using the functionality in execinfo.h +class PlatformStackTraceExecInfo : public PlatformStackTrace { + public: + static constexpr int kMaxStackLevels = 64; + + // The stack trace should capture the stack state immediately upon + // construction but should do the bare minimum amount of work to store it. Any + // expensive operations such as symbolification should be deferred until + // GetDescription(). + PlatformStackTraceExecInfo() { nsize_ = backtrace(array_, kMaxStackLevels); } + + auto GetDescription() noexcept -> std::string override { + try { + std::string s; + char** symbols = backtrace_symbols(array_, nsize_); + for (int i = 0; i < nsize_; i++) { + s += std::string(symbols[i]); + if (i < nsize_ - 1) { + s += "\n"; + } + } + free(symbols); + return s; + } catch (const std::exception&) { + return "backtrace construction failed."; + } + } + + auto copy() const noexcept -> PlatformStackTrace* override { + try { + auto s = new PlatformStackTraceExecInfo(*this); + + // Vanilla copy constructor should do the right thing here. + assert(s->nsize_ == nsize_ + && memcmp(s->array_, array_, sizeof(array_)) == 0); + return s; + } catch (const std::exception&) { + // If this is failing we're in big trouble anyway. + return nullptr; + } + } + + private: + void* array_[kMaxStackLevels]{}; + int nsize_{}; +}; +#endif + +auto Platform::GetStackTrace() -> PlatformStackTrace* { +// Our default handler here supports execinfo backtraces where available +// and gives nothing elsewhere. +#if BA_ENABLE_EXECINFO_BACKTRACES + return new PlatformStackTraceExecInfo(); +#else + return nullptr; +#endif +} + +void Platform::RequestPermission(Permission p) { + // No-op. +} + +auto Platform::HavePermission(Permission p) -> bool { + // Its assumed everything is accessible unless we override saying no. + return true; +} + +#if !BA_OSTYPE_WINDOWS +static void HandleSIGINT(int s) { + if (g_game) { + g_game->PushInterruptSignalCall(); + } else { + Log("SigInt handler called before g_game exists."); + } +} +#endif + +void Platform::SetupInterruptHandling() { + // For non-windows platforms, set up a handler for Ctrl-C. +#if !BA_OSTYPE_WINDOWS + struct sigaction handler {}; + handler.sa_handler = HandleSIGINT; + sigemptyset(&handler.sa_mask); + handler.sa_flags = 0; + sigaction(SIGINT, &handler, nullptr); +#endif +} + +void Platform::GetCursorPosition(float* x, float* y) { + assert(x && y); + + // By default, just use our latest event-delivered cursor position; + // this should work everywhere though perhaps might not be most optimal. + if (g_input == nullptr) { + *x = 0.0f; + *y = 0.0f; + return; + } + *x = g_input->cursor_pos_x(); + *y = g_input->cursor_pos_y(); +} +auto Platform::SetDebugKey(const std::string& key, const std::string& value) + -> void {} + +auto Platform::HandleDebugLog(const std::string& msg) -> void {} + +auto Platform::GetCurrentMilliseconds() -> millisecs_t { + return std::chrono::time_point_cast( + std::chrono::steady_clock::now()) + .time_since_epoch() + .count(); +} + +auto Platform::GetCurrentSeconds() -> int64_t { + return std::chrono::time_point_cast( + std::chrono::steady_clock::now()) + .time_since_epoch() + .count(); +} + +} // namespace ballistica diff --git a/src/ballistica/platform/platform.h b/src/ballistica/platform/platform.h new file mode 100644 index 00000000..96897d39 --- /dev/null +++ b/src/ballistica/platform/platform.h @@ -0,0 +1,515 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PLATFORM_PLATFORM_H_ +#define BALLISTICA_PLATFORM_PLATFORM_H_ + +#include + +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +/// For capturing and printing stack-traces and related errors. +/// Platforms should subclass this and return instances in GetStackTrace(). +class PlatformStackTrace { + public: + // The stack trace should capture the stack state immediately upon + // construction but should do the bare minimum amount of work to store it. Any + // expensive operations such as symbolification should be deferred until + // GetDescription(). + virtual ~PlatformStackTrace() = default; + + // Return a human readable version of the trace (with symbolification if + // available). + virtual auto GetDescription() noexcept -> std::string = 0; + + // Should return a copy of itself allocated via new() (or nullptr if not + // possible). + virtual auto copy() const noexcept -> PlatformStackTrace* = 0; +}; + +// This class attempts to abstract away most platform-specific functionality. +// Ideally we should need to pull in no platform-specific system headers outside +// of the platform*.cc files and can just go through this. +class Platform { + public: + static auto Create() -> Platform*; + Platform(); + virtual ~Platform(); + +#pragma mark LIFECYCLE/SETTINGS ------------------------------------------------ + + /// Called right after g_platform is created/assigned. Any platform + /// functionality depending on a complete g_platform object existing can + /// be run here. + virtual auto PostInit() -> void; + + /// Create the proper App module and add it to the main_thread. + void CreateApp(); + + /// Create the appropriate Graphics subclass for the app. + Graphics* CreateGraphics(); + + virtual void CreateAuxiliaryModules(); + virtual void WillExitMain(bool errored); + + // Inform the platform that all subsystems are up and running and it can + // start talking to them. + virtual void OnBootstrapComplete(); + + // Get/set values before standard game settings are available + // (for values needed before SDL init/etc). + // FIXME: We should have some sort of 'bootconfig.json' file for these. + // (or simply read the regular config in via c++ immediately) + auto GetLowLevelConfigValue(const char* key, int default_value) -> int; + void SetLowLevelConfigValue(const char* key, int value); + + // Called when the app config is being read/applied. + virtual void ApplyConfig(); + + // Called when the app should set itself up to intercept ctrl-c presses. + virtual void SetupInterruptHandling(); + + void FinalCleanup(); + +#pragma mark FILES ------------------------------------------------------------- + + // remove() support UTF8 strings. + virtual auto Remove(const char* path) -> int; + + // stat() supporting UTF8 strings. + virtual auto Stat(const char* path, struct BA_STAT* buffer) -> int; + + // fopen() supporting UTF8 strings. + virtual auto FOpen(const char* path, const char* mode) -> FILE*; + + // rename() supporting UTF8 strings. + // For cross-platform consistency, this should also remove any file that + // exists at the target location first. + virtual auto Rename(const char* oldname, const char* newname) -> int; + + // Simple cross-platform check for existence of a file. + auto FilePathExists(const std::string& name) -> bool; + + /// Attempt to make a directory; raise an Exception if unable, + /// unless quiet is true. + void MakeDir(const std::string& dir, bool quiet = false); + + // Return the current working directory. + virtual auto GetCWD() -> std::string; + + // Unlink a file. + virtual void Unlink(const char* path); + +#pragma mark PRINTING/LOGGING -------------------------------------------------- + + // Send a message to the default platform handler. + // IMPORTANT: No Object::Refs should be created or destroyed within this call, + // or deadlock can occur. + virtual void HandleLog(const std::string& msg); + +#pragma mark ENVIRONMENT ------------------------------------------------------- + + // Return a simple name for the platform: 'mac', 'windows', 'linux', etc. + virtual auto GetPlatformName() -> std::string; + + // Return a simple name for the subplatform: 'amazon', 'google', etc. + virtual auto GetSubplatformName() -> std::string; + + // Are we running in event-push-mode? + // With this on, we return from Main() and the system handles the event loop. + // With it off, we loop in Main() ourself. + virtual auto IsEventPushMode() -> bool; + + // Return the interface type based on the environment (phone, tablet, etc). + virtual auto GetInterfaceType() -> UIScale; + + // Return a string *reasonably* likely to be unique and consistent for this + // device. Do not assume this is globally unique and *do not* assume that it + // will never ever change (hardware upgrades may affect it, etc). + virtual auto GetUniqueDeviceIdentifier() -> const std::string&; + + // Returns the ID to use for the device account + auto GetDeviceAccountID() -> std::string; + auto GetConfigDirectory() -> std::string; + auto GetConfigFilePath() -> std::string; + auto GetUserPythonDirectory() -> std::string; + auto GetAppPythonDirectory() -> std::string; + auto GetSitePythonDirectory() -> std::string; + auto GetReplaysDir() -> std::string; + + // Return en_US or whatnot. + virtual auto GetLocale() -> std::string; + virtual void SetupDataDirectory(); + virtual auto GetUserAgentString() -> std::string; + virtual auto GetOSVersionString() -> std::string; + + /// Set an environment variable as utf8, overwriting if it already exists. + /// Raises an exception on errors. + virtual void SetEnv(const std::string& name, const std::string& value); + + // Are we being run from a terminal? (should we show prompts, etc?). + virtual auto IsStdinATerminal() -> bool; + + // Return hostname or other id suitable for network searches, etc. + auto GetDeviceName() -> std::string; + + // Are we running on a tv? + virtual auto IsRunningOnTV() -> bool; + + // Are we on a daydream enabled android device? + virtual auto IsRunningOnDaydream() -> bool; + + // Do we have touchscreen hardware? + auto HasTouchScreen() -> bool; + + // Are we running on a desktop setup in general? + virtual auto IsRunningOnDesktop() -> bool; + + // Are we running on fireTV hardware? + virtual auto IsRunningOnFireTV() -> bool; + + // Return the external storage path (currently only relevant on android). + virtual auto GetExternalStoragePath() -> std::string; + + // For enabling some special hardware optimizations for nvidia. + auto is_tegra_k1() const -> bool { return is_tegra_k1_; } + void set_is_tegra_k1(bool val) { is_tegra_k1_ = val; } + + // Return true if this platform includes its own python distribution + // (defaults to false). + virtual auto ContainsPythonDist() -> bool; + +#pragma mark INPUT DEVICES ----------------------------------------------------- + + // Return a name for a ballistica keycode. + virtual auto GetKeyName(int keycode) -> std::string; + +#pragma mark IN APP PURCHASES -------------------------------------------------- + + virtual void Purchase(const std::string& item); + + // Restore purchases (currently only relevant on apple platforms). + virtual void RestorePurchases(); + + // purchase ack'ed by the master-server (so can consume) + virtual void PurchaseAck(const std::string& purchase, + const std::string& order_id); + +#pragma mark ANDROID ----------------------------------------------------------- + + virtual auto GetAndroidExecArg() -> std::string; + virtual void AndroidSetResString(const std::string& res); + virtual auto AndroidIsGPGSConnectionToClient(ConnectionToClient* c) -> bool; + virtual auto AndroidGPGSNewConnectionToClient(int id) -> ConnectionToClient*; + virtual auto AndroidGPGSNewConnectionToHost() -> ConnectionToHost*; + virtual void AndroidSynthesizeBackPress(); + virtual void AndroidQuitActivity(); + virtual void AndroidShowAppInvite(const std::string& title, + const std::string& message, + const std::string& code); + virtual void AndroidRefreshFile(const std::string& file); + virtual void AndroidGPGSPartyInvitePlayers(); + virtual void AndroidGPGSPartyShowInvites(); + virtual void AndroidGPGSPartyInviteAccept(const std::string& invite_id); + virtual void AndroidShowWifiSettings(); + +#pragma mark PERMISSIONS ------------------------------------------------------- + + /// Request the permission asynchronously. + /// If the permission cannot be requested (due to having been denied, etc) + /// then this may also present a message or pop-up instructing the user how + /// to manually grant the permission (up to individual platforms to + /// implement). + virtual void RequestPermission(Permission p); + + /// Returns true if this permission has been granted (or if asking is not + /// required for it). + virtual auto HavePermission(Permission p) -> bool; + +#pragma mark ANALYTICS --------------------------------------------------------- + + virtual void SetAnalyticsScreen(const std::string& screen); + virtual void IncrementAnalyticsCount(const std::string& name, int increment); + virtual void IncrementAnalyticsCountRaw(const std::string& name, + int increment); + virtual void IncrementAnalyticsCountRaw2(const std::string& name, + int uses_increment, int increment); + virtual void SubmitAnalyticsCounts(); + +#pragma mark APPLE ------------------------------------------------------------- + + virtual auto NewAutoReleasePool() -> void*; + virtual void DrainAutoReleasePool(void* pool); + // FIXME: Can we consolidate these with the general music playback calls? + virtual void MacMusicAppInit(); + virtual auto MacMusicAppGetVolume() -> int; + virtual void MacMusicAppSetVolume(int volume); + virtual void MacMusicAppGetLibrarySource(); + virtual void MacMusicAppStop(); + virtual auto MacMusicAppPlayPlaylist(const std::string& playlist) -> bool; + virtual auto MacMusicAppGetPlaylists() -> std::list; + +#pragma mark TEXT RENDERING ---------------------------------------------------- + + // Set bounds/width info for a bit of text. + // (will only be called in BA_ENABLE_OS_FONT_RENDERING is set) + virtual void GetTextBoundsAndWidth(const std::string& text, Rect* r, + float* width); + virtual void FreeTextTexture(void* tex); + virtual auto CreateTextTexture(int width, int height, + const std::vector& strings, + const std::vector& positions, + const std::vector& widths, float scale) + -> void*; + virtual auto GetTextTextureData(void* tex) -> uint8_t*; + +#pragma mark ACCOUNTS ---------------------------------------------------------- + + virtual void SignIn(const std::string& account_type); + virtual void SignOut(); + virtual void GameCenterLogin(); + +#pragma mark MUSIC PLAYBACK ---------------------------------------------------- + + // FIXME: currently these are wired up on android; need to generalize + // to support mac/itunes or other music player types. + virtual void MusicPlayerPlay(PyObject* target); + virtual void MusicPlayerStop(); + virtual void MusicPlayerShutdown(); + virtual void MusicPlayerSetVolume(float volume); + +#pragma mark ADS --------------------------------------------------------------- + + virtual void ShowAd(const std::string& purpose); + + // Return whether we have the ability to show *any* ads. + virtual auto GetHasAds() -> bool; + + // Return whether we have the ability to show longer-form video ads (suitable + // for rewards). + virtual auto GetHasVideoAds() -> bool; + +#pragma mark GAME SERVICES ----------------------------------------------------- + + // Given a raw leaderboard score, convert it to what the game uses. + // For instance, platforms may return times as milliseconds while we require + // hundredths of a second, etc. + virtual auto ConvertIncomingLeaderboardScore( + const std::string& leaderboard_id, int score) -> int; + + virtual void GetFriendScores(const std::string& game, + const std::string& game_version, + void* py_callback); + virtual void SubmitScore(const std::string& game, const std::string& version, + int64_t score); + virtual void ReportAchievement(const std::string& achievement); + virtual auto HaveLeaderboard(const std::string& game, + const std::string& config) -> bool; + + virtual void ShowOnlineScoreUI(const std::string& show, + const std::string& game, + const std::string& game_version); + virtual void ResetAchievements(); + +#pragma mark NETWORKING -------------------------------------------------------- + + virtual void CloseSocket(int socket); + virtual auto SocketPair(int domain, int type, int protocol, int socks[2]) + -> int; + virtual auto GetBroadcastAddrs() -> std::vector; + virtual auto SetSocketNonBlocking(int sd) -> bool; + +#pragma mark ERRORS & DEBUGGING ------------------------------------------------ + + // Should return a subclass of PlatformStackTrace allocated via new. + // Platforms with no meaningful stack trace functionality can return nullptr. + virtual auto GetStackTrace() -> PlatformStackTrace*; + + // Called during stress testing. + virtual auto GetMemUsageInfo() -> std::string; + + // Optionally override fatal error reporting. If true is returned, default + // fatal error reporting will not run. + virtual auto ReportFatalError(const std::string& message, + bool in_top_level_exception_handler) -> bool; + + // Optionally override fatal error handling. If true is returned, default + // fatal error handling will not run. + virtual auto HandleFatalError(bool exit_cleanly, + bool in_top_level_exception_handler) -> bool; + + // If this platform has the ability to show a blocking dialog on the main + // thread for fatal errors, return true here. + virtual auto CanShowBlockingFatalErrorDialog() -> bool; + + // Called on the main thread when a fatal error occurs. + // Will only be called if CanShowBlockingFatalErrorDialog() is true. + virtual auto BlockingFatalErrorDialog(const std::string& message) -> void; + + // Use this instead of looking at errno (translates winsock errors to errno). + virtual auto GetSocketError() -> int; + + // Return a string for the current value of errno. + virtual auto GetErrnoString() -> std::string; + + // Return a description of errno (unix) or WSAGetLastError() (windows). + virtual auto GetSocketErrorString() -> std::string; + + /// Set a key to be included in crash logs or other debug cases. + /// This is expected to be lightweight as it may be called often. + virtual auto SetDebugKey(const std::string& key, const std::string& value) + -> void; + + /// Print a log message to be included in crash logs or other debug + /// mechanisms. Standard log messages (at least with to_server=true) get + /// send here as well. It can be useful to call this directly to report + /// extra details that may help in debugging, as these calls are not + /// considered 'noteworthy' or presented to the user as standard Log() + /// calls are. + virtual auto HandleDebugLog(const std::string& msg) -> void; + + static auto DebugLog(const std::string& msg) -> void { + if (g_platform) { + g_platform->HandleDebugLog(msg); + } + } + + /// Shortcut to set last native Python call we made. + static auto SetLastPyCall(const std::string& name) { + if (g_platform) { + g_platform->py_call_num_++; + g_platform->SetDebugKey( + "LastPyCall" + std::to_string(g_platform->py_call_num_ % 10), + std::to_string(g_platform->py_call_num_) + ":" + name + "@" + + std::to_string(GetCurrentMilliseconds())); + } + } + +#pragma mark MISC -------------------------------------------------------------- + + // Return a monotonic time measurement in milliseconds since launch. + // To get a time value that is guaranteed to not jump around or go backwards, + // use ballistica::GetRealTime() (which is an abstraction around this). + auto GetTicks() -> millisecs_t; + + // A raw milliseconds value (not relative to launch time). + static auto GetCurrentMilliseconds() -> millisecs_t; + static auto GetCurrentSeconds() -> int64_t; + + static void SleepMS(millisecs_t ms); + + // Pop up a text edit dialog. + virtual void EditText(const std::string& title, const std::string& value, + int max_chars); + + // Open the provided URL in a browser or whatnot. + void OpenURL(const std::string& url); + virtual auto DemangleCXXSymbol(const std::string& s) -> std::string; + + // Called each time through the main event loop; for custom pumping/handling. + virtual void RunEvents(); + + // Called when the app module is pausing. + // Note: only app-thread (main thread) stuff should happen here. + // (don't push calls to other threads/etc). + virtual void OnAppPause(); + + // Called when the app module is resuming. + virtual void OnAppResume(); + + // Is the OS currently playing music? (so we can avoid doing so). + virtual auto IsOSPlayingMusic() -> bool; + + // Pass platform-specific misc-read-vals along to the OS (as a json string). + virtual void SetPlatformMiscReadVals(const std::string& vals); + + // Show/hide the hardware cursor. + virtual void SetHardwareCursorVisible(bool visible); + + // Get the most up-to-date cursor position. + virtual void GetCursorPosition(float* x, float* y); + + // Quit the app (can be immediate or via posting some high level event). + virtual void QuitApp(); + + // Do we want to deprecate this?... + virtual void GetScoresToBeat(const std::string& level, + const std::string& config, void* py_callback); + + // Open a file using the system default method (in another app, etc.) + virtual void OpenFileExternally(const std::string& path); + + // Open a directory using the system default method (Finder, etc.) + virtual void OpenDirExternally(const std::string& path); + + // Currently mac-only (could be generalized though). + virtual void StartListeningForWiiRemotes(); + + // Currently mac-only (could be generalized though). + virtual void StopListeningForWiiRemotes(); + + // Set the name of the current thread (for debugging). + virtual void SetCurrentThreadName(const std::string& name); + + // If display-resolution can be directly set on this platform, + // return true and set the native full res here. Otherwise return false; + virtual auto GetDisplayResolution(int* x, int* y) -> bool; + + auto using_custom_app_python_dir() const { + return using_custom_app_python_dir_; + } + + protected: + // Open the provided URL in a browser or whatnot. + virtual void DoOpenURL(const std::string& url); + + // Called once per platform to determine touchscreen presence. + virtual auto DoHasTouchScreen() -> bool; + virtual auto DoGetDeviceName() -> std::string; + + // Attempt to actually create a directory. + // Should not except if it already exists or if quiet is true. + virtual void DoMakeDir(const std::string& dir, bool quiet); + + // Calc the user scripts dir path for this platform. + // This will be called once and the path cached. + virtual auto DoGetUserPythonDirectory() -> std::string; + + // Return the default config directory for this platform. + virtual auto GetDefaultConfigDir() -> std::string; + + // Return the prefix to use for device UUIDs on this platform. + virtual auto GetDeviceUUIDPrefix() -> std::string; + + // Return whether there is an actual unique UUID available for this platform, + // and also return it if so. + virtual auto GetRealDeviceUUID(std::string* uuid) -> bool; + + // Generate a random UUID string. + virtual auto GenerateUUID() -> std::string; + + private: + int py_call_num_{}; + bool using_custom_app_python_dir_{}; + bool have_config_dir_{}; + bool have_has_touchscreen_value_{}; + bool have_touchscreen_{}; + bool is_tegra_k1_{}; + millisecs_t starttime_{}; + std::string device_uuid_; + bool have_device_uuid_{}; + std::string config_dir_; + std::string user_scripts_dir_; + std::string app_python_dir_; + std::string site_python_dir_; + std::string replays_dir_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PLATFORM_PLATFORM_H_ diff --git a/src/ballistica/platform/sdl/sdl_app.cc b/src/ballistica/platform/sdl/sdl_app.cc new file mode 100644 index 00000000..c6537f6c --- /dev/null +++ b/src/ballistica/platform/sdl/sdl_app.cc @@ -0,0 +1,614 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#if BA_SDL_BUILD + +#include "ballistica/platform/sdl/sdl_app.h" + +#include + +#include "ballistica/core/thread.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/game/game.h" +#include "ballistica/graphics/gl/gl_sys.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/input/device/joystick.h" +#include "ballistica/input/input.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +// NOTE TO SELF: slowly try to phase everything out from here and into +// non-sdl event/call pushes. +void SDLApp::HandleSDLEvent(const SDL_Event& event) { + assert(InMainThread()); + + switch (event.type) { + case SDL_JOYAXISMOTION: + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + case SDL_JOYBALLMOTION: + case SDL_JOYHATMOTION: { + // It seems that joystick connection/disconnection callbacks can fire + // while there are still events for that joystick in the queue. + // So take care to ignore events for no-longer-existing joysticks. + assert(event.jaxis.which == event.jbutton.which + && event.jaxis.which == event.jhat.which); + if (static_cast(event.jbutton.which) >= sdl_joysticks_.size() + || sdl_joysticks_[event.jbutton.which] == nullptr) { + return; + } + Joystick* js = GetSDLJoyStickInput(&event); + if (js) { + if (g_input) { + g_input->PushJoystickEvent(event, js); + } + } else { + Log("Error: Unable to get SDL Joystick for event type " + + std::to_string(event.type)); + } + break; + } + + case SDL_MOUSEBUTTONDOWN: { + const SDL_MouseButtonEvent* e = &event.button; + + // Convert sdl's coords to normalized view coords. + float x = static_cast(e->x) / screen_dimensions_.x; + float y = 1.0f - static_cast(e->y) / screen_dimensions_.y; + if (g_input) { + g_input->PushMouseDownEvent(e->button, Vector2f(x, y)); + } + break; + } + case SDL_MOUSEBUTTONUP: { + const SDL_MouseButtonEvent* e = &event.button; + + // Convert sdl's coords to normalized view coords. + float x = static_cast(e->x) / screen_dimensions_.x; + float y = 1.0f - static_cast(e->y) / screen_dimensions_.y; + if (g_input) { + g_input->PushMouseUpEvent(e->button, Vector2f(x, y)); + } + break; + } + case SDL_MOUSEMOTION: { + const SDL_MouseMotionEvent* e = &event.motion; + + // Convert sdl's coords to normalized view coords. + float x = static_cast(e->x) / screen_dimensions_.x; + float y = 1.0f - static_cast(e->y) / screen_dimensions_.y; + if (g_input) { + g_input->PushMouseMotionEvent(Vector2f(x, y)); + } + break; + } + case SDL_KEYDOWN: { + if (g_input) { + g_input->PushKeyPressEvent(event.key.keysym); + } + break; + } + case SDL_KEYUP: { + if (g_input) { + g_input->PushKeyReleaseEvent(event.key.keysym); + } + break; + } + +#if BA_SDL2_BUILD || BA_MINSDL_BUILD + case SDL_MOUSEWHEEL: { + const SDL_MouseWheelEvent* e = &event.wheel; + + // Seems in general scrolling is a lot faster on mac SDL compared to + // windows/linux. (maybe its just for trackpads/etc..).. so lets + // compensate. + int scroll_speed; + if (g_buildconfig.ostype_android()) { + scroll_speed = 1; + } else if (g_buildconfig + .ostype_macos()) { // NOLINT(bugprone-branch-clone) + scroll_speed = 500; + } else { + scroll_speed = 500; + } + if (g_input) { + g_input->PushMouseScrollEvent( + Vector2f(static_cast(e->x * scroll_speed), + static_cast(e->y * scroll_speed))); + } + break; + } +#endif // BA_SDL2_BUILD + +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD + case SDL_SMOOTHSCROLLEVENT: { + const SDL_SmoothScrollEvent* e = &event.scroll; + if (g_input) { + g_input->PushSmoothMouseScrollEvent( + Vector2f(0.2f * e->deltaX, -0.2f * e->deltaY), e->momentum); + } + break; + } +#endif + + // Currently used in our some of our heavily customized builds. + // Should replace this with some sort of PushDrawEvent() thing. +#if BA_XCODE_BUILD + case SDL_RESIZEDRAWEVENT: + case SDL_DRAWEVENT: { + DrawFrame(event.type == SDL_RESIZEDRAWEVENT); + break; + } +#endif // BA_OSTYPE_MACOS || BA_OSTYPE_ANDROID + + // Is there a reason we need to ignore these on ios? + // do they even happen there? + // UPDATE: I think the even types are just not defined on our old iOS SDL. +#if BA_SDL2_BUILD && !BA_OSTYPE_IOS_TVOS && BA_ENABLE_SDL_JOYSTICKS + case SDL_JOYDEVICEREMOVED: + // In this case we're passed the instance-id of the joystick. + SDLJoystickDisconnected(event.jdevice.which); + break; + case SDL_JOYDEVICEADDED: + SDLJoystickConnected(event.jdevice.which); + break; +#endif + + case SDL_QUIT: + g_game->PushShutdownCall(false); + break; + +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD + case SDL_FULLSCREENSWITCH: + // Our custom hacked-up SDL informs *us* when our window enters or exits + // fullscreen. Let's commit this to our config so that we're in sync.. + g_python->PushObjCall(event.user.code + ? Python::ObjID::kSetConfigFullscreenOnCall + : Python::ObjID::kSetConfigFullscreenOffCall); + g_graphics_server->set_fullscreen_enabled(event.user.code); + break; +#endif + +#if BA_SDL2_BUILD + + case SDL_TEXTINPUT: { + if (g_input) { + g_input->PushTextInputEvent(event.text.text); + } + break; + } + + case SDL_WINDOWEVENT: { + switch (event.window.event) { + case SDL_WINDOWEVENT_MINIMIZED: // NOLINT(bugprone-branch-clone) + + // Hmm do we want to pause the app on desktop when minimized? + // Gonna say no for now. +#if BA_OSTYPE_IOS_TVOS + PauseApp(); +#endif + break; + + case SDL_WINDOWEVENT_RESTORED: +#if BA_OSTYPE_IOS_TVOS + ResumeApp(); +#endif + break; + + case SDL_WINDOWEVENT_RESIZED: + case SDL_WINDOWEVENT_SIZE_CHANGED: { +#if BA_OSTYPE_IOS_TVOS + // Do nothing here currently. +#else // Generic SDL: + int pixels_x, pixels_y; + SDL_GL_GetDrawableSize(g_graphics_server->gl_context()->sdl_window(), + &pixels_x, &pixels_y); + + // Pixel density is number of pixels divided by window dimension. + screen_dimensions_ = Vector2f(event.window.data1, event.window.data2); + SetScreenResolution(static_cast(pixels_x), + static_cast(pixels_y)); +#endif // BA_OSTYPE_IOS_TVOS + + break; + } + default: + break; + } + break; + default: + break; + } +#else // BA_SDL2_BUILD + case SDL_VIDEORESIZE: { + screen_dimensions_ = Vector2f(event.resize.w, event.resize.h); + SetScreenResolution(event.resize.w, event.resize.h); + break; + } +#endif // BA_SDL2_BUILD + } +} + +auto FilterSDLEvent(const SDL_Event* event) -> int { + try { + // If this event is coming from this thread, handle it immediately. + if (std::this_thread::get_id() == g_app_globals->main_thread_id) { + auto app = static_cast_check_type(g_app); + assert(app); + if (app) { + app->HandleSDLEvent(*event); + } + return false; // We handled it; sdl doesn't need to keep it. + } else { + // Otherwise just let SDL post it to the normal queue.. we process this + // every now and then to pick these up. + return true; // sdl should keep this. + } + } catch (const std::exception& e) { + BA_LOG_ONCE(std::string("Exception in inline SDL-Event handling: ") + + e.what()); + throw; + } +} + +#if BA_SDL2_BUILD +inline auto FilterSDL2Event(void* user_data, SDL_Event* event) -> int { + return FilterSDLEvent(event); +} +#endif + +// Note: can move this to SDLApp::SDLApp() once it is no longer needed by +// the legacy mac build. +void SDLApp::InitSDL() { + assert(g_platform != nullptr); + + if (g_buildconfig.ostype_macos()) { + // We don't want sdl to translate command/option clicks to different mouse + // buttons dernit. + g_platform->SetEnv("SDL_HAS3BUTTONMOUSE", "1"); + } + + // Let's turn on extra GL debugging on linux debug builds. + if (g_buildconfig.ostype_linux() && g_buildconfig.debug_build()) { + g_platform->SetEnv("MESA_DEBUG", "true"); + } + + uint32_t sdl_flags{}; + + // We can skip joysticks and video for headless. + if (!g_buildconfig.headless_build()) { + sdl_flags |= SDL_INIT_VIDEO; + if (explicit_bool(true)) { + sdl_flags |= SDL_INIT_JOYSTICK; + + // KILL THIS ONCE MAC SDL1.2 BUILD IS DEAD. + // Register our hotplug callbacks in our funky custom mac build. +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD + SDL_JoystickSetHotPlugCallbacks(SDLApp::SDLJoystickConnected, + SDLApp::SDLJoystickDisconnected); +#endif + } + } + + // Whatever fancy-pants stuff SDL is trying to do with catching signals/etc, + // we don't want it. + sdl_flags |= SDL_INIT_NOPARACHUTE; + + // We want xinput on windows. + if (g_buildconfig.ostype_windows()) { + if (!g_platform->GetLowLevelConfigValue("enablexinput", 1)) { + SDL_SetHint(SDL_HINT_XINPUT_ENABLED, "0"); + } + } + + int result = SDL_Init(sdl_flags); + if (result < 0) { + throw Exception(std::string("SDL_Init failed: ") + SDL_GetError()); + } + + // KILL THIS ONCE SDL IS NO LONGER USED ON IOS BUILD + if (g_buildconfig.ostype_ios_tvos() || g_buildconfig.ostype_android()) { + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + } + + // KILL THIS ONCE MAC SDL 1.2 BUILD IS DEAD +#if !BA_SDL2_BUILD + SDL_EnableUNICODE(true); + SDL_EnableKeyRepeat(200, 50); +#endif +} + +SDLApp::SDLApp(Thread* thread) : App(thread) { + InitSDL(); + + // If we're not running our own even loop, we set up a filter to intercept + // SDL events the moment they're generated and we process them immediately. + // This way we don't have to poll for events and can be purely callback-based, + // which fits in nicely with most modern event models. + if (!UsesEventLoop()) { +#if BA_SDL2_BUILD + SDL_SetEventFilter(FilterSDL2Event, nullptr); +#else + SDL_SetEventFilter(FilterSDLEvent); +#endif // BA_SDL2_BUILD + } else { + // Otherwise we do the standard old SDL polling stuff. + + // Set up a timer to chew through events every now and then. Polling isn't + // super elegant, but is necessary in SDL's case. (SDLWaitEvent() itself is + // pretty much a loop with SDL_PollEvents() followed by SDL_Delay(10) until + // something is returned; In spirit, we're pretty much doing that same + // thing, except that we're free to handle other matters concurrently + // instead of being locked in a delay call. + NewThreadTimer(10, true, NewLambdaRunnable([this] { + assert(g_app); + g_app->RunEvents(); + })); + } +} + +void SDLApp::RunEvents() { + App::RunEvents(); + + // Now run all pending SDL events until we run out or we're told to quit. + SDL_Event event; + while (SDL_PollEvent(&event) && (!done())) { + HandleSDLEvent(event); + } +} + +void SDLApp::DidFinishRenderingFrame(FrameDef* frame) { + App::DidFinishRenderingFrame(frame); + SwapBuffers(); +} + +void SDLApp::DoSwap() { + assert(InMainThread()); + + if (g_buildconfig.debug_build()) { + millisecs_t diff = GetRealTime() - swap_start_time_; + if (diff > 5) { + Log("WARNING: Swap handling delay of " + std::to_string(diff)); + } + } + +#if BA_ENABLE_OPENGL +#if BA_SDL2_BUILD + SDL_GL_SwapWindow(g_graphics_server->gl_context()->sdl_window()); +#else + SDL_GL_SwapBuffers(); +#endif // BA_SDL2_BUILD +#endif // BA_ENABLE_OPENGL + + millisecs_t cur_time = GetRealTime(); + + // Do some post-render analysis/updates. + if (last_swap_time_ != 0) { + millisecs_t diff2 = cur_time - last_swap_time_; + if (auto_vsync_) { + UpdateAutoVSync(static_cast(diff2)); + } + + // If we drop to a super-crappy FPS lets take some countermeasures + // such as telling BG-dynamics to kill off some stuff. + if (diff2 >= 1000 / 20) { + too_slow_frame_count_++; + } else { + too_slow_frame_count_ = 0; + } + + // Several slow frames in a row and we take action. + if (too_slow_frame_count_ > 10) { + too_slow_frame_count_ = 0; + + // A common cause of slowness is excessive smoke and bg stuff; + // lets tell the bg dynamics thread to tone it down. + g_bg_dynamics->TooSlow(); + } + } + last_swap_time_ = cur_time; +} + +void SDLApp::SwapBuffers() { + swap_start_time_ = GetRealTime(); + assert(thread()->IsCurrent()); + DoSwap(); + + // FIXME: Move this somewhere reasonable. Not here. + // On mac/ios we wanna delay our game-center login until we've drawn a few + // frames, so lets do that here. + // ...hmm; why is that? I don't remember. Should revisit. + if (g_buildconfig.use_game_center()) { + static int f_count = 0; + f_count++; + if (f_count == 5) { + g_platform->GameCenterLogin(); + } + } +} + +void SDLApp::UpdateAutoVSync(int diff) { + assert(auto_vsync_); + + // If we're currently vsyncing, watch for slow frames. + if (vsync_enabled_) { + // Keep a smoothed average of the FPS we get with VSync on. + { + float this_fps = 1000.0f / static_cast(diff); + float smoothing = 0.95f; + average_vsync_fps_ = + smoothing * average_vsync_fps_ + (1.0f - smoothing) * this_fps; + } + + // If framerate drops significantly below 60, flip vsync off to get a + // better framerate (but *only* if we're pretty sure we can hit 60 with + // it on; otherwise if we're on a 30hz monitor we'll get into a cycle of + // flipping it off and on repeatedly since we slow down a lot with it on + // and then speed up a lot with it off). + if (diff >= 1000 / 40 && average_vsync_fps_ > 55.0f) { + vsync_bad_frame_count_++; + } else { + vsync_bad_frame_count_ = 0; + } + + if (vsync_bad_frame_count_ >= 10) { + vsync_enabled_ = false; +#if BA_ENABLE_OPENGL + g_graphics_server->gl_context()->SetVSync(vsync_enabled_); +#endif + vsync_good_frame_count_ = 0; + } + } else { + // Vsync is currently off.. watch for framerate staying consistently high + // and then turn it on again. + if (diff <= 1000 / 50) { + vsync_good_frame_count_++; + } else { + vsync_good_frame_count_ = 0; + } + if (vsync_good_frame_count_ >= 60) { + vsync_enabled_ = true; +#if BA_ENABLE_OPENGL + g_graphics_server->gl_context()->SetVSync(vsync_enabled_); +#endif + vsync_bad_frame_count_ = 0; + } + } +} + +void SDLApp::SetAutoVSync(bool enable) { + auto_vsync_ = enable; + // If we're doing auto, start with vsync on. + if (enable) { + vsync_enabled_ = true; +#if BA_ENABLE_OPENGL + g_graphics_server->gl_context()->SetVSync(vsync_enabled_); +#endif + } +} + +void SDLApp::OnBootstrapComplete() { + App::OnBootstrapComplete(); + + if (!HeadlessMode() && g_buildconfig.enable_sdl_joysticks()) { + // Add initial sdl joysticks. any added/removed after this will be handled + // via events. (it seems (on mac at least) even the initial ones are handled + // via events, so lets make sure we handle redundant joystick connections + // gracefully. + if (explicit_bool(true)) { + int joystick_count = SDL_NumJoysticks(); + for (int i = 0; i < joystick_count; i++) { + SDLApp::SDLJoystickConnected(i); + } + + // We want events from joysticks. + SDL_JoystickEventState(SDL_ENABLE); + } + } +} + +void SDLApp::SDLJoystickConnected(int device_index) { + assert(InMainThread()); + + // We add all existing inputs when bootstrapping is complete; we should + // never be getting these before that happens. + if (g_input == nullptr || g_app == nullptr || !IsBootstrapped()) { + Log("Unexpected SDLJoystickConnected early in boot sequence."); + return; + } + + // Create the joystick here in the main thread and then pass it over to the + // game thread to be added to the game. + if (g_buildconfig.ostype_ios_tvos()) { + BA_LOG_ONCE("WTF GOT SDL-JOY-CONNECTED ON IOS"); + } else { + auto* j = Object::NewDeferred(device_index); + if (g_buildconfig.sdl2_build() && g_buildconfig.enable_sdl_joysticks()) { + int instance_id = SDL_JoystickInstanceID(j->sdl_joystick()); + get()->AddSDLInputDevice(j, instance_id); + } else { + get()->AddSDLInputDevice(j, device_index); + } + } +} + +void SDLApp::SDLJoystickDisconnected(int index) { + assert(InMainThread()); + assert(index >= 0); + get()->RemoveSDLInputDevice(index); +} + +auto SDLApp::SetInitialScreenDimensions(const Vector2f& dimensions) -> void { + screen_dimensions_ = dimensions; +} + +void SDLApp::AddSDLInputDevice(Joystick* input, int index) { + assert(g_input != nullptr); + assert(input != nullptr); + assert(InMainThread()); + assert(index >= 0); + + // Keep a mapping of SDL input-device indices to Joysticks. + if (static_cast_check_fit(sdl_joysticks_.size()) <= index) { + sdl_joysticks_.resize(static_cast(index) + 1, nullptr); + } + sdl_joysticks_[index] = input; + + g_input->PushAddInputDeviceCall(input, true); +} + +void SDLApp::RemoveSDLInputDevice(int index) { + assert(InMainThread()); + assert(index >= 0); + Joystick* j = GetSDLJoyStickInput(index); + assert(j); + if (static_cast_check_fit(sdl_joysticks_.size()) > index) { + sdl_joysticks_[index] = nullptr; + } else { + Log("Error: Invalid index on RemoveSDLInputDevice: size is " + + std::to_string(sdl_joysticks_.size()) + "; index is " + + std::to_string(index)); + } + g_input->PushRemoveInputDeviceCall(j, true); +} + +auto SDLApp::GetSDLJoyStickInput(const SDL_Event* e) const -> Joystick* { + assert(InMainThread()); + int joy_id; + + // Attempt to pull the joystick id from the event. + switch (e->type) { + case SDL_JOYAXISMOTION: + joy_id = e->jaxis.which; + break; + case SDL_JOYBUTTONDOWN: + case SDL_JOYBUTTONUP: + joy_id = e->jbutton.which; + break; + case SDL_JOYBALLMOTION: + joy_id = e->jball.which; + break; + case SDL_JOYHATMOTION: + joy_id = e->jhat.which; + break; + default: + return nullptr; + } + return GetSDLJoyStickInput(joy_id); +} + +auto SDLApp::GetSDLJoyStickInput(int sdl_joystick_id) const -> Joystick* { + assert(InMainThread()); + for (auto sdl_joystick : sdl_joysticks_) { + if ((sdl_joystick != nullptr) && (*sdl_joystick).sdl_joystick_id() >= 0 + && (*sdl_joystick).sdl_joystick_id() == sdl_joystick_id) + return sdl_joystick; + } + return nullptr; // Epic fail. +} + +} // namespace ballistica + +#endif // BA_SDL_BUILD diff --git a/src/ballistica/platform/sdl/sdl_app.h b/src/ballistica/platform/sdl/sdl_app.h new file mode 100644 index 00000000..4d2fa085 --- /dev/null +++ b/src/ballistica/platform/sdl/sdl_app.h @@ -0,0 +1,65 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PLATFORM_SDL_SDL_APP_H_ +#define BALLISTICA_PLATFORM_SDL_SDL_APP_H_ + +#if BA_SDL_BUILD + +#include + +#include "ballistica/app/app.h" +#include "ballistica/math/vector2f.h" + +namespace ballistica { + +class SDLApp : public App { + public: + static auto InitSDL() -> void; + explicit SDLApp(Thread* thread); + auto HandleSDLEvent(const SDL_Event& event) -> void; + auto RunEvents() -> void override; + auto DidFinishRenderingFrame(FrameDef* frame) -> void override; + auto SetAutoVSync(bool enable) -> void; + static auto SDLJoystickConnected(int index) -> void; + static auto SDLJoystickDisconnected(int index) -> void; + auto OnBootstrapComplete() -> void override; + + /// Return g_app as a SDLApp. (assumes it actually is one). + static SDLApp* get() { + assert(g_app != nullptr); + assert(dynamic_cast(g_app) == static_cast(g_app)); + return static_cast(g_app); + } + auto SetInitialScreenDimensions(const Vector2f& dimensions) -> void; + + private: + // Given an sdl joystick ID, returns our ballistica input for it. + auto GetSDLJoyStickInput(int sdl_joystick_id) const -> Joystick*; + + // The same but using sdl events. + auto GetSDLJoyStickInput(const SDL_Event* e) const -> Joystick*; + + auto DoSwap() -> void; + auto SwapBuffers() -> void; + auto UpdateAutoVSync(int diff) -> void; + auto AddSDLInputDevice(Joystick* input, int index) -> void; + auto RemoveSDLInputDevice(int index) -> void; + millisecs_t last_swap_time_{}; + millisecs_t swap_start_time_{}; + int too_slow_frame_count_{}; + bool auto_vsync_{}; + bool vsync_enabled_{true}; + float average_vsync_fps_{60.0f}; + int vsync_good_frame_count_{}; + int vsync_bad_frame_count_{}; + std::vector sdl_joysticks_; + + /// This is in points; not pixels. + Vector2f screen_dimensions_{1.0f, 1.0f}; +}; + +} // namespace ballistica + +#endif // BA_SDL_BUILD + +#endif // BALLISTICA_PLATFORM_SDL_SDL_APP_H_ From 18ec4dc2640110ebebab8dab849feebb81c64073 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 2 Oct 2020 15:21:39 -0500 Subject: [PATCH 227/417] Yet more C++ stuff --- .efrocachemap | 14 +- src/ballistica/game/account.cc | 199 -- src/ballistica/game/game.cc | 3165 ----------------- src/ballistica/game/game_stream.cc | 1242 ------- src/ballistica/game/host_activity.cc | 528 --- src/ballistica/game/host_activity.h | 2 +- src/ballistica/game/player.cc | 418 --- src/ballistica/game/player_spec.cc | 109 - src/ballistica/game/session/client_session.cc | 1070 ------ src/ballistica/game/session/host_session.cc | 765 ---- .../game/session/net_client_session.cc | 147 - .../game/session/replay_client_session.cc | 321 -- src/ballistica/game/session/session.cc | 36 - 13 files changed, 8 insertions(+), 8008 deletions(-) delete mode 100644 src/ballistica/game/account.cc delete mode 100644 src/ballistica/game/game.cc delete mode 100644 src/ballistica/game/game_stream.cc delete mode 100644 src/ballistica/game/host_activity.cc delete mode 100644 src/ballistica/game/player.cc delete mode 100644 src/ballistica/game/player_spec.cc delete mode 100644 src/ballistica/game/session/client_session.cc delete mode 100644 src/ballistica/game/session/host_session.cc delete mode 100644 src/ballistica/game/session/net_client_session.cc delete mode 100644 src/ballistica/game/session/replay_client_session.cc delete mode 100644 src/ballistica/game/session/session.cc diff --git a/.efrocachemap b/.efrocachemap index 9987ce92..f968205e 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/07/e7/d8f0add439e55e3cce5e5768c80f", + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/10/7681acdbd8feccb27175d6ab8609", "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/72/faa94ff6532a95c121fcb5a4f788", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d2/d1/99514fbe084fb0480d75f92ecb2c", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/97/99/5ba65477f8b846beb98d146a1d2c", "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dd/5d/f8c5b24579236bef5209d7089044", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/5f/ff/5d34815d90dd4cd36f2a6f587958", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ba/af/659cd48bd1be9b22ba3006ccb5f9", "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/1e/cea9badaf52032adb40e6c3b5e21", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/5d/63/96c2bbbedc03bd23824d7354b07d", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/44/94/4fa92ae4a1e726fb0b37e626e107", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/66/fd/8bb36157e75f78caa5373d9def18", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/af/2d/7546ed3c987435a743442603c21b" + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/53/c0a2b1c2ee30397db0eb367b688c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8b/a1/c3471ecf846cce50d9220f7214c3", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fa/95/87cc2ad7f0e780b02cd9ac633d3d", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/31/6f/9a29e7100425f8a364208ba40f4f" } \ No newline at end of file diff --git a/src/ballistica/game/account.cc b/src/ballistica/game/account.cc deleted file mode 100644 index b432f315..00000000 --- a/src/ballistica/game/account.cc +++ /dev/null @@ -1,199 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/account.h" - -#include "ballistica/app/app_globals.h" -#include "ballistica/game/game.h" -#include "ballistica/generic/utils.h" -#include "ballistica/python/python.h" - -namespace ballistica { - -auto Account::AccountTypeFromString(const std::string& val) -> AccountType { - if (val == "Game Center") { - return AccountType::kGameCenter; - } else if (val == "Game Circle") { - return AccountType::kGameCircle; - } else if (val == "Google Play") { - return AccountType::kGooglePlay; - } else if (val == "Steam") { - return AccountType::kSteam; - } else if (val == "Oculus") { - return AccountType::kOculus; - } else if (val == "NVIDIA China") { - return AccountType::kNvidiaChina; - } else if (val == "Test") { - return AccountType::kTest; - } else if (val == "Local") { - return AccountType::kDevice; - } else if (val == "Server") { - return AccountType::kServer; - } else { - return AccountType::kInvalid; - } -} - -auto Account::AccountTypeToString(AccountType type) -> std::string { - switch (type) { - case AccountType::kGameCenter: - return "Game Center"; - case AccountType::kGameCircle: - return "Game Circle"; - case AccountType::kGooglePlay: - return "Google Play"; - case AccountType::kSteam: - return "Steam"; - case AccountType::kOculus: - return "Oculus"; - case AccountType::kTest: - return "Test"; - case AccountType::kDevice: - return "Local"; - case AccountType::kServer: - return "Server"; - case AccountType::kNvidiaChina: - return "NVIDIA China"; - default: - return ""; - } -} - -auto Account::AccountTypeToIconString(AccountType type) -> std::string { - switch (type) { - case AccountType::kTest: - return g_game->CharStr(SpecialChar::kTestAccount); - case AccountType::kNvidiaChina: - return g_game->CharStr(SpecialChar::kNvidiaLogo); - case AccountType::kGooglePlay: - return g_game->CharStr(SpecialChar::kGooglePlayGamesLogo); - case AccountType::kSteam: - return g_game->CharStr(SpecialChar::kSteamLogo); - case AccountType::kOculus: - return g_game->CharStr(SpecialChar::kOculusLogo); - case AccountType::kGameCenter: - return g_game->CharStr(SpecialChar::kGameCenterLogo); - case AccountType::kGameCircle: - return g_game->CharStr(SpecialChar::kGameCircleLogo); - case AccountType::kDevice: - case AccountType::kServer: - return g_game->CharStr(SpecialChar::kLocalAccount); - default: - return ""; - } -} - -Account::Account() = default; - -auto Account::GetAccountName() -> std::string { - std::lock_guard lock(mutex_); - return account_name_; -} - -auto Account::GetAccountID() -> std::string { - std::lock_guard lock(mutex_); - return account_id_; -} - -auto Account::GetAccountToken() -> std::string { - std::lock_guard lock(mutex_); - return account_token_; -} - -auto Account::GetAccountExtra() -> std::string { - std::lock_guard lock(mutex_); - return account_extra_; -} - -auto Account::GetAccountExtra2() -> std::string { - std::lock_guard lock(mutex_); - return account_extra_2_; -} - -auto Account::GetAccountState(int* state_num) -> AccountState { - std::lock_guard lock(mutex_); - if (state_num) { - *state_num = account_state_num_; - } - return account_state_; -} - -void Account::SetAccountExtra(const std::string& extra) { - std::lock_guard lock(mutex_); - account_extra_ = extra; -} - -void Account::SetAccountExtra2(const std::string& extra) { - std::lock_guard lock(mutex_); - account_extra_2_ = extra; -} - -void Account::SetAccountToken(const std::string& account_id, - const std::string& token) { - std::lock_guard lock(mutex_); - // Hmm does this compare logic belong in here? - if (account_id_ == account_id) { - account_token_ = token; - } -} - -void Account::SetAccount(AccountType account_type, AccountState account_state, - const std::string& account_name, - const std::string& account_id) { - bool call_account_changed = false; - { - std::lock_guard lock(mutex_); - - // We call out to python so need to be in game thread. - assert(InGameThread()); - if (account_state_ != account_state - || g_app_globals->account_type != account_type - || account_id_ != account_id || account_name_ != account_name) { - // Special case: if they sent a sign-out for an account type that is. - // currently not signed in, ignore it. - if (account_state == AccountState::kSignedOut - && (account_type != g_app_globals->account_type)) { - // No-op. - } else { - account_state_ = account_state; - g_app_globals->account_type = account_type; - account_id_ = account_id; - account_name_ = Utils::GetValidUTF8(account_name.c_str(), "gthm"); - - // If they signed out of an account, account type switches to invalid. - if (account_state == AccountState::kSignedOut) { - g_app_globals->account_type = AccountType::kInvalid; - } - account_state_num_ += 1; - call_account_changed = true; - } - } - } - if (call_account_changed) { - // Inform python layer this has changed. - g_python->AccountChanged(); - } -} - -void Account::SetProductsPurchased(const std::vector& products) { - std::lock_guard lock(mutex_); - std::map purchases_old = product_purchases_; - product_purchases_.clear(); - for (auto&& i : products) { - product_purchases_[i] = true; - } - if (product_purchases_ != purchases_old) { - product_purchases_state_++; - } -} - -auto Account::GetProductPurchased(const std::string& product) -> bool { - std::lock_guard lock(mutex_); - auto i = product_purchases_.find(product); - if (i == product_purchases_.end()) { - return false; - } else { - return i->second; - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/game.cc b/src/ballistica/game/game.cc deleted file mode 100644 index 77c563f3..00000000 --- a/src/ballistica/game/game.cc +++ /dev/null @@ -1,3165 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/game.h" - -#include -#include -#include - -#include "ballistica/app/app.h" -#include "ballistica/app/app_config.h" -#include "ballistica/audio/audio.h" -#include "ballistica/core/thread.h" -#include "ballistica/dynamics/bg/bg_dynamics.h" -#include "ballistica/game/account.h" -#include "ballistica/game/connection/connection_to_client_udp.h" -#include "ballistica/game/connection/connection_to_host_udp.h" -#include "ballistica/game/friend_score_set.h" -#include "ballistica/game/host_activity.h" -#include "ballistica/game/player.h" -#include "ballistica/game/score_to_beat.h" -#include "ballistica/game/session/client_session.h" -#include "ballistica/game/session/host_session.h" -#include "ballistica/game/session/net_client_session.h" -#include "ballistica/game/session/replay_client_session.h" -#include "ballistica/generic/json.h" -#include "ballistica/generic/timer.h" -#include "ballistica/graphics/graphics.h" -#include "ballistica/graphics/graphics_server.h" -#include "ballistica/graphics/text/text_graphics.h" -#include "ballistica/input/device/client_input_device.h" -#include "ballistica/input/device/keyboard_input.h" -#include "ballistica/input/device/touch_input.h" -#include "ballistica/math/vector3f.h" -#include "ballistica/networking/network_write_module.h" -#include "ballistica/networking/networking.h" -#include "ballistica/networking/sockaddr.h" -#include "ballistica/networking/telnet_server.h" -#include "ballistica/python/python.h" -#include "ballistica/python/python_command.h" -#include "ballistica/python/python_context_call.h" -#include "ballistica/python/python_sys.h" -#include "ballistica/scene/node/globals_node.h" -#include "ballistica/ui/console.h" -#include "ballistica/ui/root_ui.h" -#include "ballistica/ui/ui.h" -#include "ballistica/ui/widget/root_widget.h" -#include "ballistica/ui/widget/text_widget.h" - -namespace ballistica { - -/// How long a kick vote lasts. -const int kKickVoteDuration = 30000; - -/// How long everyone has to wait to start a new kick vote after a failed one. -const int kKickVoteFailRetryDelay = 60000; - -/// Extra delay for the initiator of a failed vote. -const int kKickVoteFailRetryDelayInitiatorExtra = 120000; - -// Minimum clients that must be present for a kick vote to count. -// (for non-headless builds we require more votes since the host doesn't count -// but may be playing (in a 2on2 with 3 clients, don't want 2 clients able to -// kick). -// NOLINTNEXTLINE(cert-err58-cpp) -const int kKickVoteMinimumClients = (g_buildconfig.headless_build() ? 3 : 4); - -const int kMaxChatMessages = 40; - -// Go with 5 minute ban. -const int kKickBanSeconds = 5 * 60; - -Game::Game(Thread* thread) - : Module("game", thread), - game_roster_(cJSON_CreateArray()), - realtimers_(new TimerList()) { - assert(g_game == nullptr); - g_game = this; - - try { - // Spin up some other game-thread-based stuff. - AppConfig::Init(); - assert(g_graphics == nullptr); - g_graphics = g_platform->CreateGraphics(); - TextGraphics::Init(); - Media::Init(); - Audio::Init(); - if (!HeadlessMode()) { - BGDynamics::Init(); - } - - InitSpecialChars(); - - Context::Init(); - - // Waaah does UI need to be a bs::Object? - // Update: yes it does in order to be a context target. - // (need to be able to create weak-refs to it). - assert(g_ui == nullptr); - g_ui = Object::NewUnmanaged(); - - assert(g_networking == nullptr); - g_networking = new Networking(); - - assert(g_input == nullptr); - g_input = new Input(); - - // Init python and apply our settings immediately. - // This way we can get started loading stuff in the background - // and it'll come in with the correct texture quality etc. - assert(g_python == nullptr); - g_python = new Python(); - g_python->Reset(true); - - // We're the thread that 'owns' python so we need to wrangle the GIL. - thread->SetOwnsPython(); - } catch (const std::exception& e) { - // If anything went wrong, trigger a deferred error. - // This way it is more likely we can show a fatal error dialog - // since the main thread won't be blocking waiting for us to init. - std::string what = e.what(); - PushCall([what] { - // Just throw a standard exception since our what already - // contains a stack trace; if we throw an Exception we wind - // up with a useless second one. - throw std::logic_error(what.c_str()); - }); - } -} - -void Game::InitSpecialChars() { - std::lock_guard lock(special_char_mutex_); - - special_char_strings_[SpecialChar::kDownArrow] = "\xee\x80\x84"; - special_char_strings_[SpecialChar::kUpArrow] = "\xee\x80\x83"; - special_char_strings_[SpecialChar::kLeftArrow] = "\xee\x80\x81"; - special_char_strings_[SpecialChar::kRightArrow] = "\xee\x80\x82"; - special_char_strings_[SpecialChar::kTopButton] = "\xee\x80\x86"; - special_char_strings_[SpecialChar::kLeftButton] = "\xee\x80\x85"; - special_char_strings_[SpecialChar::kRightButton] = "\xee\x80\x87"; - special_char_strings_[SpecialChar::kBottomButton] = "\xee\x80\x88"; - special_char_strings_[SpecialChar::kDelete] = "\xee\x80\x89"; - special_char_strings_[SpecialChar::kShift] = "\xee\x80\x8A"; - special_char_strings_[SpecialChar::kBack] = "\xee\x80\x8B"; - special_char_strings_[SpecialChar::kLogoFlat] = "\xee\x80\x8C"; - special_char_strings_[SpecialChar::kRewindButton] = "\xee\x80\x8D"; - special_char_strings_[SpecialChar::kPlayPauseButton] = "\xee\x80\x8E"; - special_char_strings_[SpecialChar::kFastForwardButton] = "\xee\x80\x8F"; - special_char_strings_[SpecialChar::kDpadCenterButton] = "\xee\x80\x90"; - - special_char_strings_[SpecialChar::kOuyaButtonO] = "\xee\x80\x99"; - special_char_strings_[SpecialChar::kOuyaButtonU] = "\xee\x80\x9A"; - special_char_strings_[SpecialChar::kOuyaButtonY] = "\xee\x80\x9B"; - special_char_strings_[SpecialChar::kOuyaButtonA] = "\xee\x80\x9C"; - special_char_strings_[SpecialChar::kOuyaLogo] = "\xee\x80\x9D"; - special_char_strings_[SpecialChar::kLogo] = "\xee\x80\x9E"; - special_char_strings_[SpecialChar::kTicket] = "\xee\x80\x9F"; - special_char_strings_[SpecialChar::kGooglePlayGamesLogo] = "\xee\x80\xA0"; - special_char_strings_[SpecialChar::kGameCenterLogo] = "\xee\x80\xA1"; - special_char_strings_[SpecialChar::kDiceButton1] = "\xee\x80\xA2"; - special_char_strings_[SpecialChar::kDiceButton2] = "\xee\x80\xA3"; - special_char_strings_[SpecialChar::kDiceButton3] = "\xee\x80\xA4"; - special_char_strings_[SpecialChar::kDiceButton4] = "\xee\x80\xA5"; - special_char_strings_[SpecialChar::kGameCircleLogo] = "\xee\x80\xA6"; - special_char_strings_[SpecialChar::kPartyIcon] = "\xee\x80\xA7"; - special_char_strings_[SpecialChar::kTestAccount] = "\xee\x80\xA8"; - special_char_strings_[SpecialChar::kTicketBacking] = "\xee\x80\xA9"; - special_char_strings_[SpecialChar::kTrophy1] = "\xee\x80\xAA"; - special_char_strings_[SpecialChar::kTrophy2] = "\xee\x80\xAB"; - special_char_strings_[SpecialChar::kTrophy3] = "\xee\x80\xAC"; - special_char_strings_[SpecialChar::kTrophy0a] = "\xee\x80\xAD"; - special_char_strings_[SpecialChar::kTrophy0b] = "\xee\x80\xAE"; - special_char_strings_[SpecialChar::kTrophy4] = "\xee\x80\xAF"; - special_char_strings_[SpecialChar::kLocalAccount] = "\xee\x80\xB0"; - special_char_strings_[SpecialChar::kAlibabaLogo] = "\xee\x80\xB1"; - - special_char_strings_[SpecialChar::kFlagUnitedStates] = "\xee\x80\xB2"; - special_char_strings_[SpecialChar::kFlagMexico] = "\xee\x80\xB3"; - special_char_strings_[SpecialChar::kFlagGermany] = "\xee\x80\xB4"; - special_char_strings_[SpecialChar::kFlagBrazil] = "\xee\x80\xB5"; - special_char_strings_[SpecialChar::kFlagRussia] = "\xee\x80\xB6"; - special_char_strings_[SpecialChar::kFlagChina] = "\xee\x80\xB7"; - special_char_strings_[SpecialChar::kFlagUnitedKingdom] = "\xee\x80\xB8"; - special_char_strings_[SpecialChar::kFlagCanada] = "\xee\x80\xB9"; - special_char_strings_[SpecialChar::kFlagIndia] = "\xee\x80\xBA"; - special_char_strings_[SpecialChar::kFlagJapan] = "\xee\x80\xBB"; - special_char_strings_[SpecialChar::kFlagFrance] = "\xee\x80\xBC"; - special_char_strings_[SpecialChar::kFlagIndonesia] = "\xee\x80\xBD"; - special_char_strings_[SpecialChar::kFlagItaly] = "\xee\x80\xBE"; - special_char_strings_[SpecialChar::kFlagSouthKorea] = "\xee\x80\xBF"; - special_char_strings_[SpecialChar::kFlagNetherlands] = "\xee\x81\x80"; - - special_char_strings_[SpecialChar::kFedora] = "\xee\x81\x81"; - special_char_strings_[SpecialChar::kHal] = "\xee\x81\x82"; - special_char_strings_[SpecialChar::kCrown] = "\xee\x81\x83"; - special_char_strings_[SpecialChar::kYinYang] = "\xee\x81\x84"; - special_char_strings_[SpecialChar::kEyeBall] = "\xee\x81\x85"; - special_char_strings_[SpecialChar::kSkull] = "\xee\x81\x86"; - special_char_strings_[SpecialChar::kHeart] = "\xee\x81\x87"; - special_char_strings_[SpecialChar::kDragon] = "\xee\x81\x88"; - special_char_strings_[SpecialChar::kHelmet] = "\xee\x81\x89"; - special_char_strings_[SpecialChar::kMushroom] = "\xee\x81\x8A"; - - special_char_strings_[SpecialChar::kNinjaStar] = "\xee\x81\x8B"; - special_char_strings_[SpecialChar::kVikingHelmet] = "\xee\x81\x8C"; - special_char_strings_[SpecialChar::kMoon] = "\xee\x81\x8D"; - special_char_strings_[SpecialChar::kSpider] = "\xee\x81\x8E"; - special_char_strings_[SpecialChar::kFireball] = "\xee\x81\x8F"; - - special_char_strings_[SpecialChar::kFlagUnitedArabEmirates] = "\xee\x81\x90"; - special_char_strings_[SpecialChar::kFlagQatar] = "\xee\x81\x91"; - special_char_strings_[SpecialChar::kFlagEgypt] = "\xee\x81\x92"; - special_char_strings_[SpecialChar::kFlagKuwait] = "\xee\x81\x93"; - special_char_strings_[SpecialChar::kFlagAlgeria] = "\xee\x81\x94"; - special_char_strings_[SpecialChar::kFlagSaudiArabia] = "\xee\x81\x95"; - special_char_strings_[SpecialChar::kFlagMalaysia] = "\xee\x81\x96"; - special_char_strings_[SpecialChar::kFlagCzechRepublic] = "\xee\x81\x97"; - special_char_strings_[SpecialChar::kFlagAustralia] = "\xee\x81\x98"; - special_char_strings_[SpecialChar::kFlagSingapore] = "\xee\x81\x99"; - - special_char_strings_[SpecialChar::kOculusLogo] = "\xee\x81\x9A"; - special_char_strings_[SpecialChar::kSteamLogo] = "\xee\x81\x9B"; - special_char_strings_[SpecialChar::kNvidiaLogo] = "\xee\x81\x9C"; - - special_char_strings_[SpecialChar::kFlagIran] = "\xee\x81\x9D"; - special_char_strings_[SpecialChar::kFlagPoland] = "\xee\x81\x9E"; - special_char_strings_[SpecialChar::kFlagArgentina] = "\xee\x81\x9F"; - special_char_strings_[SpecialChar::kFlagPhilippines] = "\xee\x81\xA0"; - special_char_strings_[SpecialChar::kFlagChile] = "\xee\x81\xA1"; - - special_char_strings_[SpecialChar::kMikirog] = "\xee\x81\xA2"; -} - -void Game::SetGameRoster(cJSON* r) { - if (game_roster_ != nullptr) { - cJSON_Delete(game_roster_); - } - game_roster_ = r; -} - -void Game::ResetActivityTracking() { - largest_draw_time_increment_since_last_reset_ = 0; - first_draw_real_time_ = last_draw_real_time_ = g_platform->GetTicks(); -} - -void Game::RegisterClientController(ClientControllerInterface* c) { - // This shouldn't happen, but if there's already a controller registered, - // detach all clients from it. - if (client_controller_) { - Log("RegisterClientController() called " - "but already have a controller; bad."); - for (auto&& i : connections_to_clients_) { - assert(i.second.exists()); - i.second->SetController(nullptr); - } - } - - // Ok, now assign the new and attach all currently-connected clients to it. - client_controller_ = c; - if (client_controller_) { - for (auto&& i : connections_to_clients_) { - assert(i.second.exists()); - if (i.second->can_communicate()) { - i.second->SetController(client_controller_); - } - } - } -} - -void Game::UnregisterClientController(ClientControllerInterface* c) { - assert(c); - - // This shouldn't happen. - if (client_controller_ != c) { - Log("UnregisterClientController() called with a non-registered " - "controller"); - return; - } - - // Ok, detach all our controllers from this guy. - if (client_controller_) { - for (auto&& i : connections_to_clients_) { - i.second->SetController(nullptr); - } - } - client_controller_ = nullptr; -} - -#if BA_VR_BUILD - -void Game::PushVRHandsState(const VRHandsState& state) { - PushCall([this, state] { vr_hands_state_ = state; }); -} - -#endif // BA_VR_BUILD - -void Game::PushMediaPruneCall(int level) { - PushCall([level] { - assert(InGameThread()); - g_media->Prune(level); - }); -} - -void Game::PushSetAccountTokenCall(const std::string& account_id, - const std::string& token) { - PushCall( - [account_id, token] { g_account->SetAccountToken(account_id, token); }); -} - -void Game::PushSetAccountCall(AccountType account_type, - AccountState account_state, - const std::string& account_name, - const std::string& account_id) { - PushCall([this, account_type, account_state, account_name, account_id] { - g_account->SetAccount(account_type, account_state, account_name, - account_id); - }); -} - -void Game::PushInitialScreenCreatedCall() { - PushCall([this] { InitialScreenCreated(); }); -} - -void Game::InitialScreenCreated() { - assert(InGameThread()); - - // Ok; graphics-server is telling us we've got a screen. - - // We can now let the media thread go to town pre-loading system media - // while we wait. - g_media->LoadSystemMedia(); - - // FIXME: ideally we should create this as part of bootstrapping, but - // we need it to be possible to load textures/etc. before the renderer - // exists. - if (!HeadlessMode()) { - assert(!g_app_globals->console); - g_app_globals->console = new Console(); - } - - // Set up our timers. - process_timer_ = - NewThreadTimer(0, true, NewLambdaRunnable([this] { Process(); })); - media_prune_timer_ = - NewThreadTimer(2345, true, NewLambdaRunnable([this] { Prune(); })); - - // Normally we schedule updates when we're asked to draw a frame. - // In headless mode, however, we're not drawing, so we need a dedicated - // timer to take its place. - if (HeadlessMode()) { - headless_update_timer_ = - NewThreadTimer(8, true, NewLambdaRunnable([this] { Update(); })); - } - - RunAppLaunchCommands(); -} - -void Game::PushPurchaseTransactionCall(const std::string& item, - const std::string& receipt, - const std::string& signature, - const std::string& order_id, - bool user_initiated) { - PushCall([this, item, receipt, signature, order_id, user_initiated] { - PurchaseTransaction(item, receipt, signature, order_id, user_initiated); - }); -} - -void Game::PurchaseTransaction(const std::string& item, - const std::string& receipt, - const std::string& signature, - const std::string& order_id, - bool user_initiated) { - assert(InGameThread()); - g_python->AddPurchaseTransaction(item, receipt, signature, order_id, - user_initiated); -} - -void Game::Prune() { g_media->Prune(); } - -void Game::PushAdViewCompleteCall(const std::string& purpose, - bool actually_showed) { - PushCall([this, purpose, actually_showed] { - AdViewComplete(purpose, actually_showed); - }); -} - -void Game::AdViewComplete(const std::string& purpose, bool actually_showed) { - assert(InGameThread()); - CallAdCompletionCall(actually_showed); - - // If they *actually* viewed an ad, and it was a between-game ad, inform the - // user that they can disable them. - if (purpose == "between_game" && actually_showed) { - g_python->obj(Python::ObjID::kRemoveInGameAdsMessageCall).Call(); - } - RunGeneralAdComplete(actually_showed); -} - -void Game::RunGeneralAdComplete(bool actually_showed) { - assert(InGameThread()); - PythonRef ad_complete_call = - g_python->obj(Python::ObjID::kAccountClient).GetAttr("ad_complete"); - if (ad_complete_call.exists()) { - PythonRef args(Py_BuildValue("(Oi)", actually_showed ? Py_True : Py_False, - static_cast(g_platform->GetTicks() - - last_ad_start_time_)), - PythonRef::kSteal); - ad_complete_call.Call(args); - } else { - Log("Error on ad-complete call"); - } -} - -void Game::PushAnalyticsCall(const std::string& type, int increment) { - PushCall([this, type, increment] { Analytics(type, increment); }); -} - -void Game::Analytics(const std::string& type, int increment) { - assert(InGameThread()); - g_python->HandleAnalytics(type, increment); -} - -void Game::PushAwardAdTicketsCall() { - PushCall([this] { AwardAdTickets(); }); -} - -void Game::AwardAdTickets() { - try { - PythonRef add_transaction = - g_python->obj(Python::ObjID::kAccountClient).GetAttr("add_transaction"); - PythonRef args(Py_BuildValue("({ss})", "type", "AWARD_AD_TICKETS"), - PythonRef::kSteal); - if (add_transaction.exists()) add_transaction.Call(args); - g_python->RunTransactions(); - } catch (const std::exception& e) { - Log("Error in AwardAdTicketsMessage: " + std::string(e.what())); - } -} - -void Game::PushAwardAdTournamentEntryCall() { - PushCall([this] { AwardAdTournamentEntry(); }); -} - -void Game::AwardAdTournamentEntry() { - try { - PythonRef add_transaction = - g_python->obj(Python::ObjID::kAccountClient).GetAttr("add_transaction"); - PythonRef args(Py_BuildValue("({ss})", "type", "AWARD_AD_TOURNAMENT_ENTRY"), - PythonRef::kSteal); - if (add_transaction.exists()) add_transaction.Call(args); - g_python->RunTransactions(); - } catch (const std::exception& e) { - Log("Error in AwardAdTournamentEntryMessage: " + std::string(e.what())); - } -} - -// Launch into main menu or whatever else. -void Game::RunAppLaunchCommands() { - assert(!ran_app_launch_commands_); - - // First off, run our python app-launch call. - { - // Run this in the UI context. - ScopedSetContext cp(GetUIContext()); - g_python->obj(Python::ObjID::kOnAppLaunchCall).Call(); - } - - // If we were passed launch command args, run them. - if (!g_app_globals->game_commands.empty()) { - bool success = PythonCommand(g_app_globals->game_commands, BA_BCFN).Run(); - if (!success) { - exit(1); - } - } - - // If the stuff we just ran didn't result in a session, create a default one. - if (!foreground_session_.exists()) { - RunMainMenu(); - } - - UpdateProcessTimer(); - - ran_app_launch_commands_ = true; -} - -Game::~Game() = default; - -// Set up our sleeping based on what we're doing. -void Game::UpdateProcessTimer() { - assert(InGameThread()); - - // This might get called before we set up our timer in some cases. (such as - // very early) should be safe to ignore since we update the interval - // explicitly after creating the timers. - if (!process_timer_) return; - - // If there's loading to do, keep at it rather vigorously. - if (have_pending_loads_) { - assert(process_timer_); - process_timer_->SetLength(1); - } else { - // Otherwise we've got nothing to do; go to sleep until something changes. - assert(process_timer_); - process_timer_->SetLength(-1); - } -} - -void Game::PruneSessions() { - bool have_dead_session = false; - for (auto&& i : sessions_) { - if (i.exists()) { - // If this session is no longer foreground and is ready to die, kill it. - if (i.exists() && i.get() != foreground_session_.get()) { - try { - i.Clear(); - } catch (const std::exception& e) { - Log("Exception killing Session: " + std::string(e.what())); - } - have_dead_session = true; - } - } else { - have_dead_session = true; - } - } - if (have_dead_session) { - std::vector > live_list; - for (auto&& i : sessions_) { - if (i.exists()) { - live_list.push_back(i); - } - } - sessions_.swap(live_list); - } -} - -void Game::SetClientInfoFromMasterServer(const std::string& client_token, - PyObject* info_obj) { - // NOLINTNEXTLINE (python doing bitwise math on signed int) - if (!PyDict_Check(info_obj)) { - Log("got non-dict for master-server client info for token " + client_token - + ": " + Python::ObjToString(info_obj)); - return; - } - for (ConnectionToClient* client : GetConnectionsToClients()) { - if (client->token() == client_token) { - client->HandleMasterServerClientInfo(info_obj); - - // Roster will now include account-id... - game_roster_dirty_ = true; - break; - } - } -} - -void Game::UpdateKickVote() { - if (!kick_vote_in_progress_) { - return; - } - ConnectionToClient* kick_vote_starter = kick_vote_starter_.get(); - ConnectionToClient* kick_vote_target = kick_vote_target_.get(); - - // If the target is no longer with us, silently end. - if (kick_vote_target == nullptr) { - kick_vote_in_progress_ = false; - return; - } - millisecs_t current_time = GetRealTime(); - int total_client_count = 0; - int yes_votes = 0; - int no_votes = 0; - - // Tally current votes for connected clients; if anything has changed, print - // the update and possibly perform the kick. - for (ConnectionToClient* client : GetConnectionsToClients()) { - ++total_client_count; - if (client->kick_voted_) { - if (client->kick_vote_choice_) { - ++yes_votes; - } else { - ++no_votes; - } - } - } - bool vote_failed = false; - - // If we've fallen below the minimum necessary voters or time has run out, - // fail. - if (total_client_count < kKickVoteMinimumClients) { - vote_failed = true; - } - if (current_time > kick_vote_end_time_) { - vote_failed = true; - } - - if (vote_failed) { - SendScreenMessageToClients(R"({"r":"kickVoteFailedText"})", 1, 1, 0); - kick_vote_in_progress_ = false; - - // Disallow kicking for a while for everyone.. but ESPECIALLY so for the guy - // who launched the failed vote. - for (ConnectionToClient* client : GetConnectionsToClients()) { - millisecs_t delay = kKickVoteFailRetryDelay; - if (client == kick_vote_starter) { - delay += kKickVoteFailRetryDelayInitiatorExtra; - } - client->next_kick_vote_allow_time_ = - std::max(client->next_kick_vote_allow_time_, current_time + delay); - } - } else { - int votes_required; - switch (total_client_count) { - case 1: - case 2: - votes_required = 2; // Shouldn't actually be possible. - break; - case 3: - votes_required = HeadlessMode() ? 2 : 3; - break; - case 4: - votes_required = 3; - break; - case 5: - votes_required = HeadlessMode() ? 3 : 4; - break; - case 6: - votes_required = 4; - break; - case 7: - votes_required = HeadlessMode() ? 4 : 5; - break; - default: - votes_required = total_client_count - 3; - break; - } - int votes_needed = votes_required - yes_votes; - if (votes_needed <= 0) { - // ZOMG the vote passed; perform the kick. - SendScreenMessageToClients( - R"({"r":"kickOccurredText","s":[["${NAME}",)" - + Utils::GetJSONString(kick_vote_target->GetCombinedSpec() - .GetDisplayString() - .c_str()) - + "]]}", - 1, 1, 0); - kick_vote_in_progress_ = false; - DisconnectClient(kick_vote_target->id(), kKickBanSeconds); - - } else if (votes_needed != last_kick_votes_needed_) { - last_kick_votes_needed_ = votes_needed; - SendScreenMessageToClients(R"({"r":"votesNeededText","s":[["${NUMBER}",")" - + std::to_string(votes_needed) + "\"]]}", - 1, 1, 0); - } - } -} - -// Bring our scenes, real-time timers, etc up to date. -void Game::Update() { - assert(InGameThread()); - millisecs_t real_time = GetRealTime(); - g_platform->SetDebugKey("LastUpdateTime", - std::to_string(Platform::GetCurrentMilliseconds())); - if (first_update_) { - master_time_offset_ = master_time_ - real_time; - first_update_ = false; - } - in_update_ = true; - g_input->Update(); - UpdateKickVote(); - - // Send the game roster to our clients if it's changed recently. - if (game_roster_dirty_) { - if (real_time > last_game_roster_send_time_ + 2500) { - // Now send it to all connected clients. - std::vector msg = GetGameRosterMessage(); - for (auto&& c : GetConnectionsToClients()) { - c->SendReliableMessage(msg); - } - game_roster_dirty_ = false; - last_game_roster_send_time_ = real_time; - } - } - - // First do housekeeping on our client/host connections. - for (auto&& i : connections_to_clients_) { - BA_IFDEBUG(Object::WeakRef test_ref(i.second)); - i.second->Update(); - - // Make sure the connection didn't kill itself in the update. - assert(test_ref.exists()); - } - - if (connection_to_host_.exists()) { - connection_to_host_->Update(); - } - - // Ok, here's the deal: - // This is where we regulate the speed of everything that's running under us - // (sessions, activities, frame_def-creation, etc) - // we have a master_time which we try to have match real-time as closely - // as possible (unless we physically aren't fast enough to get everything - // done, in which case it'll be slower). We also increment our underlying - // machinery in 8ms increments (1/120 of a second) and try to do 2 updates - // each time we're called, since we're usually being called in a 60hz refresh - // cycle and that'll line our draws up perfectly with our sim steps. - - // TODO(ericf): On modern systems (VR and otherwise) we'll see 80hz, 90hz, - // 120hz, 240hz, etc. It would be great to generalize this to gravitate - // towards clean step patterns in all cases, not just the 60hz and 90hz cases - // we handle now. In general we want stuff like 1,1,2,1,1,2,1,1,2, not - // 1,1,1,2,1,2,2,1,1. - - // Figure out where our net-time *should* be getting to to match real-time. - millisecs_t target_master_time = real_time + master_time_offset_; - millisecs_t amount_behind = target_master_time - master_time_; - - // Normally we assume 60hz so we gravitate towards 2 steps per update to line - // up with our 120hz update timing. - int target_steps = 2; - -#if BA_RIFT_BUILD - // On Rift VR mode we're running 90hz, so lets aim for 1/2/1/2 steps to hit - // our 120hz target. - if (IsVRMode()) { - target_steps = rift_step_index_ + 1; - rift_step_index_ = !rift_step_index_; - } -#endif // BA_RIFT_BUILD - - // Ideally we should be behind by 16 (or 8 for single steps); if its - // *slightly* more than that, let our timing slip a tiny bit to maintain sync. - // This lets us match framerates that are a tiny bit slower than 60hz, such as - // seems to be the case with the Gear VR. - if (amount_behind > 16) { - master_time_offset_ -= 1; - - //.. and recalc these.. - target_master_time = real_time + master_time_offset_; - amount_behind = target_master_time - master_time_; - } - - // if we've fallen behind by a lot, just cut our losses - if (amount_behind > 50) { - master_time_offset_ -= (amount_behind - 50); - target_master_time = real_time + master_time_offset_; - } - - // min/max net-time targets we can aim for; gives us about a steps worth of - // wiggle room to try and keep our exact target cadence - millisecs_t min_target_master_time = - target_master_time >= 8 ? (target_master_time - 8) : 0; - millisecs_t max_target_master_time = target_master_time + 8; - - // run up our real-time timers - realtimers_->Run(real_time); - - // Run session updates until we catch up with projected base time (or run out - // of time). - int step = 1; - - while (true) { - // Try to stick to our target step count whenever possible, but if we get - // too far off target we may need to bail earlier/later. - if (step > target_steps) { - // As long as we're within a step of where we should be, bail now. - if (master_time_ >= min_target_master_time) break; - } else { - // If we've gone too far already, bail. - if (master_time_ >= max_target_master_time) { - // Log("BAILING EARLY"); - // On rift if this is a 2-step and we bailed after 1, aim for 2 again - // next time (otherwise we'll always get 3 singles in a row when this - // happens). -#if BA_RIFT_BUILD - if (IsVRMode() && target_steps == 2 && step == 2) { - rift_step_index_ = !rift_step_index_; - } -#endif // BA_RIFT_BUILD - break; - } - } - - // Update our UI scene/etc. - g_ui->Update(8); - - // Update all of our sessions. - for (auto&& i : sessions_) { - assert(i.exists()); - i->Update(8); - } - - last_session_update_master_time_ = master_time_; - - // Go ahead and prune dead ones. - PruneSessions(); - - // Advance master time.. - master_time_ += 8; - - // Bail if we spend too much time in here. - millisecs_t new_real_time = GetRealTime(); - if (new_real_time - real_time > 30) { - break; - } - step++; - } - in_update_ = false; -} - -// Reset the game to a blank slate. -void Game::Reset() { - assert(InGameThread()); - - // Tear down any existing setup. - // This should allow high-level objects to die gracefully. - assert(g_python->inited()); - - // Tear down our existing session. - foreground_session_.Clear(); - PruneSessions(); - - // If all is well our sessions should all be dead. - if (g_app_globals->session_count != 0) { - Log("Error: session-count is non-zero (" - + std::to_string(g_app_globals->session_count) + ") on Game::Reset."); - } - - // Note: we don't clear real-time timers anymore. Should we?.. - g_ui->Reset(); - g_input->Reset(); - g_graphics->Reset(); - g_python->Reset(); - g_audio->Reset(); - - if (!HeadlessMode()) { - // If we haven't, send a first frame_def to the graphics thread to kick - // things off (it'll start sending us requests for more after it gets the - // first). - if (!have_sent_initial_frame_def_) { - g_graphics->BuildAndPushFrameDef(); - have_sent_initial_frame_def_ = true; - } - } -} - -auto Game::IsInUIContext() const -> bool { - return (g_ui && Context::current().target.get() == g_ui); -} - -void Game::PushShowURLCall(const std::string& url) { - PushCall([url] { - assert(InGameThread()); - assert(g_python); - g_python->ShowURL(url); - }); -} - -auto Game::GetForegroundContext() -> Context { - Session* s = GetForegroundSession(); - if (s) { - return s->GetForegroundContext(); - } else { - return Context(); - } -} - -void Game::PushBackButtonCall(InputDevice* input_device) { - PushCall([this, input_device] { - assert(InGameThread()); - - // Ignore if UI isn't up yet. - if (!g_ui || !g_ui->overlay_root_widget() || !g_ui->screen_root_widget()) { - return; - } - - // If there's a UI up, send along a cancel message. - if (g_ui->overlay_root_widget()->GetChildCount() != 0 - || g_ui->screen_root_widget()->GetChildCount() != 0) { - g_ui->root_widget()->HandleMessage( - WidgetMessage(WidgetMessage::Type::kCancel)); - } else { - // If there's no main screen or overlay windows, ask for a menu owned by - // this device. - MainMenuPress(input_device); - } - }); -} - -void Game::PushStringEditSetCall(const std::string& value) { - PushCall([value] { - if (!g_ui) { - Log("Error: No ui on StringEditSetEvent."); - return; - } -#if BA_OSTYPE_ANDROID - TextWidget* w = TextWidget::GetAndroidStringEditWidget(); - if (w) { - w->SetText(value); - } -#else - throw Exception(); // Shouldn't get here. -#endif - }); -} - -void Game::PushStringEditCancelCall() { - PushCall([] { - if (!g_ui) { - Log("Error: No ui in PushStringEditCancelCall."); - return; - } - }); -} - -// Called by a newly made Session instance to set itself as the current -// session. -void Game::SetForegroundSession(Session* s) { - assert(InGameThread()); - foreground_session_ = s; -} - -void Game::SetForegroundScene(Scene* sg) { - assert(InGameThread()); - if (foreground_scene_.get() != sg) { - foreground_scene_ = sg; - - // If this scene has a globals-node, put it in charge of stuff. - if (GlobalsNode* g = sg->globals_node()) { - g->SetAsForeground(); - } - } -} - -void Game::LaunchClientSession() { - if (in_update_) { - throw Exception( - "can't launch a session from within a session update; use " - "ba.pushcall()"); - } - assert(InGameThread()); - - // Don't want to pick up any old stuff in here. - ScopedSetContext cp(nullptr); - - // This should kill any current session and get us back to a blank slate. - Reset(); - - // Create the new session. - Object::WeakRef old_foreground_session(foreground_session_); - try { - auto s(Object::New()); - sessions_.push_back(s); - - // It should have set itself as FG. - assert(foreground_session_ == s); - } catch (const std::exception& e) { - // If it failed, restore the previous current session and re-throw. - SetForegroundSession(old_foreground_session.get()); - throw Exception(std::string("HostSession failed: ") + e.what()); - } -} - -void Game::LaunchReplaySession(const std::string& file_name) { - if (in_update_) - throw Exception( - "can't launch a session from within a session update; use " - "ba.pushcall()"); - - assert(InGameThread()); - - // Don't want to pick up any old stuff in here. - ScopedSetContext cp(nullptr); - - // This should kill any current session and get us back to a blank slate. - Reset(); - - // Create the new session. - Object::WeakRef old_foreground_session(foreground_session_); - try { - auto s(Object::New(file_name)); - sessions_.push_back(s); - - // It should have set itself as FG. - assert(foreground_session_ == s); - } catch (const std::exception& e) { - // If it failed, restore the previous current session and re-throw the - // exception. - SetForegroundSession(old_foreground_session.get()); - throw Exception(std::string("HostSession failed: ") + e.what()); - } -} - -void Game::LaunchHostSession(PyObject* session_type_obj, - BenchmarkType benchmark_type) { - if (in_update_) { - throw Exception( - "can't call host_session() from within session update; use " - "ba.pushcall()"); - } - - assert(InGameThread()); - - // If for some reason we're still attached to a host, kill the connection. - if (connection_to_host_.exists()) { - Log("Had host-connection during LaunchHostSession(); shouldn't happen."); - connection_to_host_->RequestDisconnect(); - connection_to_host_.Clear(); - has_connection_to_host_ = false; - UpdateGameRoster(); - } - - // Don't want to pick up any old stuff in here. - ScopedSetContext cp(nullptr); - - // This should kill any current session and get us back to a blank slate. - Reset(); - - Object::WeakRef old_foreground_session(foreground_session_); - try { - // Create the new session. - auto s(Object::New(session_type_obj)); - s->set_benchmark_type(benchmark_type); - sessions_.emplace_back(s); - - // It should have set itself as FG. - assert(foreground_session_ == s); - } catch (const std::exception& e) { - // If it failed, restore the previous session context and re-throw the - // exception. - SetForegroundSession(old_foreground_session.get()); - throw Exception(std::string("HostSession failed: ") + e.what()); - } -} - -void Game::RunMainMenu() { - PushCall([this] { - if (g_app_globals->shutting_down) { - return; - } - assert(g_python); - assert(InGameThread()); - PythonRef result = - g_python->obj(Python::ObjID::kLaunchMainMenuSessionCall).Call(); - if (!result.exists()) { - throw Exception("error running main menu"); - } - }); -} - -// Commands run via the in-game console. These are a bit more 'casual' and run -// in the current visible context. - -void Game::PushInGameConsoleScriptCommand(const std::string& command) { - PushCall([this, command] { - // These are always run in whichever context is 'visible'. - ScopedSetContext cp(GetForegroundContext()); - PythonCommand cmd(command, ""); - if (!g_app_globals->user_ran_commands) { - g_app_globals->user_ran_commands = true; - } - if (cmd.CanEval()) { - PyObject* obj = cmd.RunReturnObj(true); - if (obj && obj != Py_None) { - PyObject* s = PyObject_Repr(obj); - if (s) { - const char* c = PyUnicode_AsUTF8(s); - if (g_app_globals->console) { - g_app_globals->console->Print(std::string(c) + "\n"); - } - Py_DECREF(s); - } - Py_DECREF(obj); - } - } else { - // Not eval-able; just run it. - cmd.Run(); - } - }); -} - -// Commands run via stdin. -void Game::PushStdinScriptCommand(const std::string& command) { - PushCall([this, command] { - // These are always run in whichever context is 'visible'. - ScopedSetContext cp(GetForegroundContext()); - PythonCommand cmd(command, ""); - if (!g_app_globals->user_ran_commands) { - g_app_globals->user_ran_commands = true; - } - - // Eval this if possible (so we can possibly print return value). - if (cmd.CanEval()) { - if (PyObject* obj = cmd.RunReturnObj(true)) { - // Print the value if we're running directly from a terminal - // (or being run under the server-manager) - if ((IsStdinATerminal() || g_app->server_wrapper_managed()) - && obj != Py_None) { - PyObject* s = PyObject_Repr(obj); - if (s) { - const char* c = PyUnicode_AsUTF8(s); - printf("%s\n", c); - fflush(stdout); - Py_DECREF(s); - } - } - Py_DECREF(obj); - } - } else { - // Can't eval it; just run it. - cmd.Run(); - } - }); -} - -void Game::PushInterruptSignalCall() { - PushCall([this] { - assert(InGameThread()); - - // Special case; when running under the server-wrapper, we completely - // ignore interrupt signals (the wrapper acts on them). - if (g_app->server_wrapper_managed()) { - return; - } - - // Just go through _ba.quit() - // FIXME: Shouldn't need to go out to the python layer here... - g_python->obj(Python::ObjID::kQuitCall).Call(); - }); -} - -void Game::PushAskUserForTelnetAccessCall() { - PushCall([this] { - assert(InGameThread()); - ScopedSetContext cp(GetUIContext()); - g_python->obj(Python::ObjID::kTelnetAccessRequestCall).Call(); - }); -} - -void Game::HandleThreadPause() { - // Give userspace python stuff a chance to pause. - ScopedSetContext cp(GetUIContextTarget()); - g_python->obj(Python::ObjID::kOnAppPauseCall).Call(); - - // Tell our account client to commit any outstanding changes to disk. - g_python->CommitLocalData(); -} - -// void Game::PushTelnetScriptCommand(const std::string& command) { -// PushCall([this, command] { -// // These are always run in whichever context is 'visible'. -// ScopedSetContext cp(GetForegroundContext()); -// if (!g_app_globals->user_ran_commands) { -// g_app_globals->user_ran_commands = true; -// } -// PythonCommand cmd(command, ""); -// if (cmd.CanEval()) { -// PyObject* obj = cmd.RunReturnObj(true); -// if (obj && obj != Py_None) { -// PyObject* s = PyObject_Repr(obj); -// if (s) { -// const char* c = PyUnicode_AsUTF8(s); -// PushTelnetPrintCall(std::string(c) + "\n"); -// Py_DECREF(s); -// } -// Py_DECREF(obj); -// } -// } else { -// // Not eval-able; just run it. -// cmd.Run(); -// } -// PushTelnetPrintCall("ballisticacore> "); -// }); -// } - -// void Game::PushTelnetPrintCall(const std::string& message) { -// PushCall([message] { -// if (g_app_globals->telnet_server) { -// g_app_globals->telnet_server->Print(message); -// } -// }); -// } - -void Game::PushPythonCall(const Object::Ref& call) { - // Since we're mucking with refs, need to limit to game thread. - BA_PRECONDITION(InGameThread()); - BA_PRECONDITION(call->object_strong_ref_count() > 0); - PushCall([call] { - assert(call.exists()); - call->Run(); - }); -} - -void Game::PushPythonCallArgs(const Object::Ref& call, - const PythonRef& args) { - // Since we're mucking with refs, need to limit to game thread. - BA_PRECONDITION(InGameThread()); - BA_PRECONDITION(call->object_strong_ref_count() > 0); - PushCall([call, args] { - assert(call.exists()); - call->Run(args.get()); - }); -} - -void Game::PushPythonWeakCall(const Object::WeakRef& call) { - // Since we're mucking with refs, need to limit to game thread. - BA_PRECONDITION(InGameThread()); - - // Even though we only hold a weak ref, we expect a valid strong-reffed - // object to be passed in. - assert(call.exists() && call->object_strong_ref_count() > 0); - - PushCall([call] { - if (call.exists()) { - Python::ScopedCallLabel label("PythonWeakCallMessage"); - call->Run(); - } - }); -} - -void Game::PushPythonWeakCallArgs( - const Object::WeakRef& call, const PythonRef& args) { - // Since we're mucking with refs, need to limit to game thread. - BA_PRECONDITION(InGameThread()); - - // Even though we only hold a weak ref, we expect a valid strong-reffed - // object to be passed in. - assert(call.exists() && call->object_strong_ref_count() > 0); - - PushCall([call, args] { - if (call.exists()) call->Run(args.get()); - }); -} - -void Game::PushPythonRawCallable(PyObject* callable) { - PushCall([this, callable] { - assert(InGameThread()); - - // Lets run this in the UI context. - // (can add other options if we need later) - ScopedSetContext cp(GetUIContext()); - - // This event contains a raw python obj with an incremented ref-count. - auto call(Object::New(callable)); - Py_DECREF(callable); // now just held by call - - call->Run(); - }); -} - -void Game::PushScreenMessage(const std::string& message, - const Vector3f& color) { - PushCall([message, color] { g_graphics->AddScreenMessage(message, color); }); -} - -void Game::SetReplaySpeedExponent(int val) { - replay_speed_exponent_ = std::min(3, std::max(-3, val)); - replay_speed_mult_ = powf(2.0f, static_cast(replay_speed_exponent_)); -} - -void Game::SetDebugSpeedExponent(int val) { - debug_speed_exponent_ = val; - debug_speed_mult_ = powf(2.0f, static_cast(debug_speed_exponent_)); - - Session* s = GetForegroundSession(); - if (s) s->DebugSpeedMultChanged(); -} - -void Game::ChangeGameSpeed(int offs) { - assert(InGameThread()); - - // if we're in a replay session, adjust playback speed there - if (dynamic_cast(GetForegroundSession())) { - int old_speed = replay_speed_exponent(); - SetReplaySpeedExponent(replay_speed_exponent() + offs); - if (old_speed != replay_speed_exponent()) { - ScreenMessage( - "{\"r\":\"watchWindow.playbackSpeedText\"," - "\"s\":[[\"${SPEED}\",\"" - + std::to_string(replay_speed_mult()) + "\"]]}"); - } - return; - } - // Otherwise, in debug build, we allow speeding/slowing anything. -#if BA_DEBUG_BUILD - debug_speed_exponent_ += offs; - debug_speed_mult_ = powf(2.0f, static_cast(debug_speed_exponent_)); - ScreenMessage("DEBUG GAME SPEED TO " + std::to_string(debug_speed_mult_)); - Session* s = GetForegroundSession(); - if (s) { - s->DebugSpeedMultChanged(); - } -#endif // BA_DEBUG_BUILD -} - -auto Game::GetUIContext() const -> Context { - return Context(GetUIContextTarget()); -} - -void Game::PushToggleManualCameraCall() { - PushCall([] { g_graphics->ToggleManualCamera(); }); -} - -void Game::PushToggleDebugInfoDisplayCall() { - PushCall([] { g_graphics->ToggleDebugInfoDisplay(); }); -} - -void Game::PushToggleCollisionGeometryDisplayCall() { - PushCall([] { g_graphics->ToggleDebugDraw(); }); -} - -void Game::PushMainMenuPressCall(InputDevice* device) { - PushCall([this, device] { MainMenuPress(device); }); -} - -void Game::MainMenuPress(InputDevice* device) { - assert(InGameThread()); - g_python->HandleDeviceMenuPress(device); -} - -void Game::PushScreenResizeCall(float virtual_width, float virtual_height, - float pixel_width, float pixel_height) { - PushCall([=] { - ScreenResize(virtual_width, virtual_height, pixel_width, pixel_height); - }); -} - -void Game::ScreenResize(float virtual_width, float virtual_height, - float pixel_width, float pixel_height) { - assert(InGameThread()); - assert(g_graphics != nullptr); - if (g_graphics) { - g_graphics->ScreenResize(virtual_width, virtual_height, pixel_width, - pixel_height); - } - if (g_ui) { - g_ui->ScreenSizeChanged(); - } - if (Session* session = GetForegroundSession()) { - session->ScreenSizeChanged(); - } -} - -void Game::PushGameServiceAchievementListCall( - const std::set& achievements) { - PushCall([this, achievements] { GameServiceAchievementList(achievements); }); -} - -void Game::GameServiceAchievementList( - const std::set& achievements) { - assert(g_python); - assert(InGameThread()); - g_python->DispatchRemoteAchievementList(achievements); -} - -void Game::PushScoresToBeatResponseCall(bool success, - const std::list& scores, - void* py_callback) { - PushCall([this, success, scores, py_callback] { - ScoresToBeatResponse(success, scores, py_callback); - }); -} - -void Game::ScoresToBeatResponse(bool success, - const std::list& scores, - void* py_callback) { - assert(g_python); - assert(InGameThread()); - g_python->DispatchScoresToBeatResponse(success, scores, py_callback); -} - -void Game::PushPlaySoundCall(SystemSoundID sound) { - PushCall([sound] { g_audio->PlaySound(g_media->GetSound(sound)); }); -} - -void Game::PushFriendScoreSetCall(const FriendScoreSet& score_set) { - PushCall([score_set] { g_python->HandleFriendScoresCB(score_set); }); -} - -void Game::PushConfirmQuitCall() { - PushCall([this] { - assert(InGameThread()); - if (HeadlessMode()) { - Log("PushConfirmQuitCall() unhandled on headless."); - } else { - // If input is locked, just quit immediately.. a confirm screen wouldn't - // work anyway - if (g_input->IsInputLocked() - || (g_app_globals->console != nullptr - && g_app_globals->console->active())) { - // Just go through _ba.quit() - // FIXME: Shouldn't need to go out to the python layer here... - g_python->obj(Python::ObjID::kQuitCall).Call(); - return; - } else { - // this needs to be run in the UI context - ScopedSetContext cp(GetUIContextTarget()); - - g_audio->PlaySound(g_media->GetSound(SystemSoundID::kSwish)); - g_python->obj(Python::ObjID::kQuitWindowCall).Call(); - - // if we have a keyboard, give it UI ownership - InputDevice* keyboard = g_input->keyboard_input(); - if (keyboard) { - g_ui->SetUIInputDevice(keyboard); - } - } - } - }); -} - -void Game::Draw() { - g_graphics->BuildAndPushFrameDef(); - - // Now bring the game up to date. - // By doing this *after* shipping a new frame_def we're reducing the - // chance of frame drops at the expense of adding a bit of visual latency. - // Could maybe try to be smart about which to do first, but not sure - // if its worth it. - Update(); - - // Update our cheat tests. - millisecs_t now = g_platform->GetTicks(); - millisecs_t elapsed = now - last_draw_real_time_; - if (elapsed > largest_draw_time_increment_since_last_reset_) { - largest_draw_time_increment_since_last_reset_ = elapsed; - } - last_draw_real_time_ = now; - - // Sanity test: can make sure our scene is taking exactly 2 steps - // per frame here.. (should generally be the case on 60hz devices). - if (explicit_bool(false)) { - static int64_t last_step = 0; - HostActivity* ha = GetForegroundContext().GetHostActivity(); - if (ha) { - int64_t step = ha->scene()->stepnum(); - Log(std::to_string(step - last_step)); - last_step = step; - } - } -} - -void Game::PushFrameDefRequest() { - PushCall([this] { Draw(); }); -} - -void Game::PushOnAppResumeCall() { - PushCall([] { - // Wipe out whatever input device was in control of the UI. - assert(g_ui); - g_ui->SetUIInputDevice(nullptr); - }); -} - -// Look through everything in our config dict and act on it. -void Game::ApplyConfig() { - assert(InGameThread()); - - // Not relevant for fullscreen anymore - // since we're fullscreen windows everywhere. - int width = 800; - int height = 600; - - // Texture quality. - TextureQuality texture_quality_requested; - std::string texqualstr = - g_app_config->Resolve(AppConfig::StringID::kTextureQuality); - - if (texqualstr == "Auto") { - texture_quality_requested = TextureQuality::kAuto; - } else if (texqualstr == "High") { - texture_quality_requested = TextureQuality::kHigh; - } else if (texqualstr == "Medium") { - texture_quality_requested = TextureQuality::kMedium; - } else if (texqualstr == "Low") { - texture_quality_requested = TextureQuality::kLow; - } else { - Log("Invalid texture quality: '" + texqualstr + "'; defaulting to low."); - texture_quality_requested = TextureQuality::kLow; - } - - // Graphics quality. - std::string gqualstr = - g_app_config->Resolve(AppConfig::StringID::kGraphicsQuality); - GraphicsQuality graphics_quality_requested; - - if (gqualstr == "Auto") { - graphics_quality_requested = GraphicsQuality::kAuto; - } else if (gqualstr == "Higher") { - graphics_quality_requested = GraphicsQuality::kHigher; - } else if (gqualstr == "High") { - graphics_quality_requested = GraphicsQuality::kHigh; - } else if (gqualstr == "Medium") { - graphics_quality_requested = GraphicsQuality::kMedium; - } else if (gqualstr == "Low") { - graphics_quality_requested = GraphicsQuality::kLow; - } else { - Log("Error: Invalid graphics quality: '" + gqualstr - + "'; defaulting to auto."); - graphics_quality_requested = GraphicsQuality::kAuto; - } - - // Android res string. - std::string android_res = - g_app_config->Resolve(AppConfig::StringID::kResolutionAndroid); - - bool fullscreen = g_app_config->Resolve(AppConfig::BoolID::kFullscreen); - - // Note: when the graphics-thread applies the first set-screen event it will - // trigger the remainder of startup such as media-loading; make sure nothing - // below this will affect that. - g_graphics_server->PushSetScreenCall(fullscreen, width, height, - texture_quality_requested, - graphics_quality_requested, android_res); - - // FIXME: The graphics server should kick this off *AFTER* it sets the actual - // quality values; here we're just sending along our requested values which - // is wrong. If there's a session up, inform it of the (potential) change. - Session* session = GetForegroundSession(); - if (session) { - session->GraphicsQualityChanged(graphics_quality_requested); - } - - if (!HeadlessMode()) { - g_app_globals->remote_server_accepting_connections = - g_app_config->Resolve(AppConfig::BoolID::kEnableRemoteApp); - } - - chat_muted_ = g_app_config->Resolve(AppConfig::BoolID::kChatMuted); - g_graphics->set_show_fps(g_app_config->Resolve(AppConfig::BoolID::kShowFPS)); - - // Set tv border (for both client and server). - bool tv_border = g_app_config->Resolve(AppConfig::BoolID::kTVBorder); - g_graphics_server->PushCall( - [tv_border] { g_graphics_server->set_tv_border(tv_border); }); - - // FIXME: this should exist either on the client or the server; not both. - // (and should be communicated via frameldefs/etc.) - g_graphics->set_tv_border(tv_border); - - g_graphics_server->PushSetScreenGammaCall( - g_app_config->Resolve(AppConfig::FloatID::kScreenGamma)); - g_graphics_server->PushSetScreenPixelScaleCall( - g_app_config->Resolve(AppConfig::FloatID::kScreenPixelScale)); - - TextWidget::set_always_use_internal_keyboard( - g_app_config->Resolve(AppConfig::BoolID::kAlwaysUseInternalKeyboard)); - - // V-sync setting. - std::string v_sync = - g_app_config->Resolve(AppConfig::StringID::kVerticalSync); - bool do_v_sync{}; - bool auto_v_sync{}; - if (v_sync == "Auto") { - do_v_sync = true; - auto_v_sync = true; - } else if (v_sync == "Always") { - do_v_sync = true; - auto_v_sync = false; - } else if (v_sync == "Never") { - do_v_sync = false; - auto_v_sync = false; - } else { - do_v_sync = false; - auto_v_sync = false; - Log("Error: Invalid 'Vertical Sync' value: '" + v_sync + "'"); - } - g_graphics_server->PushSetVSyncCall(do_v_sync, auto_v_sync); - - g_audio->SetVolumes(g_app_config->Resolve(AppConfig::FloatID::kMusicVolume), - g_app_config->Resolve(AppConfig::FloatID::kSoundVolume)); - - // Kick-idle-players setting (hmm is this still relevant?). - auto* host_session = dynamic_cast(foreground_session_.get()); - kick_idle_players_ = - g_app_config->Resolve(AppConfig::BoolID::kKickIdlePlayers); - if (host_session) { - host_session->SetKickIdlePlayers(kick_idle_players_); - } - - // Input doesn't yet exist when we first run; it updates itself initially when - // it comes up (but we do thereafter). - // if (input_) { - assert(g_input); - g_input->ApplyAppConfig(); - // } - - // Set up network ports/states. - int port = g_app_config->Resolve(AppConfig::IntID::kPort); - int telnet_port = g_app_config->Resolve(AppConfig::IntID::kTelnetPort); - - // NOTE: Hard disabling telnet for now in headless builds; - // it was being exploited to own servers. - bool enable_telnet = - g_buildconfig.headless_build() - ? false - : g_app_config->Resolve(AppConfig::BoolID::kEnableTelnet); - std::string telnet_password = - g_app_config->Resolve(AppConfig::StringID::kTelnetPassword); - - g_app->PushNetworkSetupCall(port, telnet_port, enable_telnet, - telnet_password); - - bool disable_camera_shake = - g_app_config->Resolve(AppConfig::BoolID::kDisableCameraShake); - g_graphics->set_camera_shake_disabled(disable_camera_shake); - - bool disable_camera_gyro = - g_app_config->Resolve(AppConfig::BoolID::kDisableCameraGyro); - g_graphics->set_camera_gyro_explicitly_disabled(disable_camera_gyro); - - // Any platform-specific settings. - g_platform->ApplyConfig(); -} - -void Game::PushApplyConfigCall() { - PushCall([this] { ApplyConfig(); }); -} - -void Game::PushRemoveGraphicsServerRenderHoldCall() { - PushCall([] { - // This call acts as a flush of sorts; when it goes through, - // we push a call to the graphics server saying its ok for it - // to start rendering again. Thus any already-queued-up - // frame_defs or whatnot will be ignored. - g_graphics_server->PushRemoveRenderHoldCall(); - }); -} - -void Game::PushSetFriendListCall(const std::vector& friends) { - PushCall([friends] { g_python->DispatchFriendList(friends); }); -} - -void Game::PushFreeMediaComponentRefsCall( - const std::vector*>& components) { - PushCall([components] { - for (auto&& i : components) { - delete i; - } - }); -} - -void Game::PushHavePendingLoadsDoneCall() { - PushCall([] { g_media->ClearPendingLoadsDoneList(); }); -} - -void Game::ToggleConsole() { - assert(InGameThread()); - if (auto console = g_app_globals->console) { - console->ToggleState(); - } -} - -void Game::PushConsolePrintCall(const std::string& msg) { - PushCall([msg] { - // Send them to the console if its been created or store them - // for when it is (unless we're headless in which case it never will). - if (auto console = g_app_globals->console) { - console->Print(msg); - } else if (!HeadlessMode()) { - g_app_globals->console_startup_messages += msg; - } - }); -} - -void Game::PushHavePendingLoadsCall() { - PushCall([this] { - have_pending_loads_ = true; - UpdateProcessTimer(); - }); -} - -void Game::PushShutdownCall(bool soft) { - PushCall([this, soft] { Shutdown(soft); }); -} - -void Game::Shutdown(bool soft) { - assert(InGameThread()); - - if (!g_app_globals->shutting_down) { - g_app_globals->shutting_down = true; - - // Nuke the app if we get stuck shutting down. - Utils::StartSuicideTimer("shutdown", 10000); - - // Call our shutdown callback. - g_python->obj(Python::ObjID::kShutdownCall).Call(); - - // If we have any client/host connections, give them - // a chance to shoot off disconnect packets or whatnot. - for (auto& connection : connections_to_clients_) { - connection.second->RequestDisconnect(); - } - if (connection_to_host_.exists()) { - connection_to_host_->RequestDisconnect(); - } - - // Let's do the same stuff we do when our thread is pausing. (committing - // account-client to disk, etc). - HandleThreadPause(); - - // Attempt to report/store outstanding log stuff. - Python::PutLog(false); - - // Ideally we'd want to give some of the above stuff - // a few seconds to complete, but just calling it done for now. - g_app->PushShutdownCompleteCall(); - } -} - -void Game::ResetInput() { - assert(InGameThread()); - g_input->ResetKeyboardHeldKeys(); - g_input->ResetJoyStickHeldButtons(); -} - -auto Game::RemovePlayer(Player* player) -> void { - assert(InGameThread()); - if (HostSession* host_session = player->GetHostSession()) { - host_session->RemovePlayer(player); - } else { - Log("Got RemovePlayer call but have no host_session"); - } -} - -auto Game::NewRealTimer(millisecs_t length, bool repeat, - const Object::Ref& runnable) -> int { - int offset = 0; - Timer* t = realtimers_->NewTimer(GetRealTime(), length, offset, - repeat ? -1 : 0, runnable); - return t->id(); -} - -void Game::DeleteRealTimer(int timer_id) { realtimers_->DeleteTimer(timer_id); } - -void Game::SetRealTimerLength(int timer_id, millisecs_t length) { - Timer* t = realtimers_->GetTimer(timer_id); - if (t) { - t->SetLength(length); - } else { - Log("Error: Game::SetRealTimerLength() called on nonexistent timer."); - } -} - -void Game::Process() { - have_pending_loads_ = g_media->RunPendingLoadsGameThread(); - UpdateProcessTimer(); -} - -void Game::SetLanguageKeys(const std::map& language) { - assert(InGameThread()); - { - std::lock_guard lock(language_mutex_); - language_ = language; - } - - // Let's also inform existing session stuff so it can update itself. - if (Session* session = GetForegroundSession()) { - session->LanguageChanged(); - } - - // As well as existing UI stuff. - if (Widget* root_widget = g_ui->root_widget()) { - root_widget->OnLanguageChange(); - } - - // Also clear translations on all screen-messages. - g_graphics->ClearScreenMessageTranslations(); -} - -auto DoCompileResourceString(cJSON* obj) -> std::string { - assert(InGameThread()); - assert(obj != nullptr); - - std::string result; - - // If its got a "r" key, look it up as a resource.. (with optional fallback). - cJSON* resource = cJSON_GetObjectItem(obj, "r"); - if (resource == nullptr) { - resource = cJSON_GetObjectItem(obj, "resource"); - // As of build 14318, complain if we find long key names; hope to remove - // them soon. - if (resource != nullptr) { - static bool printed = false; - if (!printed) { - printed = true; - char* c = cJSON_Print(obj); - BA_LOG_ONCE("found long key 'resource' in raw lstr json: " - + std::string(c)); - free(c); - } - } - } - if (resource != nullptr) { - // Look for fallback-resource. - cJSON* fallback_resource = cJSON_GetObjectItem(obj, "f"); - if (fallback_resource == nullptr) { - fallback_resource = cJSON_GetObjectItem(obj, "fallback"); - - // As of build 14318, complain if we find old long key names; hope to - // remove them soon. - if (fallback_resource != nullptr) { - static bool printed = false; - if (!printed) { - printed = true; - char* c = cJSON_Print(obj); - BA_LOG_ONCE("found long key 'fallback' in raw lstr json: " - + std::string(c)); - free(c); - } - } - } - cJSON* fallback_value = cJSON_GetObjectItem(obj, "fv"); - result = g_python->GetResource( - resource->valuestring, - fallback_resource ? fallback_resource->valuestring : nullptr, - fallback_value ? fallback_value->valuestring : nullptr); - } else { - // Apparently not a resource; lets try as a translation ("t" keys). - cJSON* translate = cJSON_GetObjectItem(obj, "t"); - if (translate == nullptr) { - translate = cJSON_GetObjectItem(obj, "translate"); - - // As of build 14318, complain if we find long key names; hope to remove - // them soon. - if (translate != nullptr) { - static bool printed = false; - if (!printed) { - printed = true; - char* c = cJSON_Print(obj); - BA_LOG_ONCE("found long key 'translate' in raw lstr json: " - + std::string(c)); - free(c); - } - } - } - if (translate != nullptr) { - if (translate->type != cJSON_Array - || cJSON_GetArraySize(translate) != 2) { - throw Exception("Expected a 2 member array for translate"); - } - cJSON* category = cJSON_GetArrayItem(translate, 0); - if (category->type != cJSON_String) { - throw Exception( - "First member of translate array (category) must be a string"); - } - cJSON* value = cJSON_GetArrayItem(translate, 1); - if (value->type != cJSON_String) { - throw Exception( - "Second member of translate array (value) must be a string"); - } - result = - g_python->GetTranslation(category->valuestring, value->valuestring); - } else { - // Lastly try it as a value ("value" or "v"). - // (can be useful for feeding explicit strings while still allowing - // translated subs - cJSON* value = cJSON_GetObjectItem(obj, "v"); - if (value == nullptr) { - value = cJSON_GetObjectItem(obj, "value"); - - // As of build 14318, complain if we find long key names; hope to remove - // them soon. - if (value != nullptr) { - static bool printed = false; - if (!printed) { - printed = true; - char* c = cJSON_Print(obj); - BA_LOG_ONCE("found long key 'value' in raw lstr json: " - + std::string(c)); - free(c); - } - } - } - if (value != nullptr) { - if (value->type != cJSON_String) { - throw Exception("Expected a string for value"); - } - result = value->valuestring; - } else { - throw Exception("no 'resource', 'translate', or 'value' keys found"); - } - } - } - // Ok; now no matter what it was, see if it contains any subs and replace - // them. - // ("subs" or "s") - cJSON* subs = cJSON_GetObjectItem(obj, "s"); - if (subs == nullptr) { - subs = cJSON_GetObjectItem(obj, "subs"); - - // As of build 14318, complain if we find long key names; hope to remove - // them soon. - if (subs != nullptr) { - static bool printed = false; - if (!printed) { - printed = true; - char* c = cJSON_Print(obj); - BA_LOG_ONCE("found long key 'subs' in raw lstr json: " - + std::string(c)); - free(c); - } - } - } - if (subs != nullptr) { - if (subs->type != cJSON_Array) { - throw Exception("expected an array for 'subs'"); - } - int subsCount = cJSON_GetArraySize(subs); - for (int i = 0; i < subsCount; i++) { - cJSON* sub = cJSON_GetArrayItem(subs, i); - if (sub->type != cJSON_Array || cJSON_GetArraySize(sub) != 2) { - throw Exception( - "Invalid subs entry; expected length 2 list of sub/replacement."); - } - - // First item should be a string. - cJSON* key = cJSON_GetArrayItem(sub, 0); - if (key->type != cJSON_String) { - throw Exception("Sub keys must be strings."); - } - std::string s_key = key->valuestring; - - // Second item can be a string or a dict; if its a dict, we go recursive. - cJSON* value = cJSON_GetArrayItem(sub, 1); - std::string s_val; - if (value->type == cJSON_String) { - s_val = value->valuestring; - } else if (value->type == cJSON_Object) { - s_val = DoCompileResourceString(value); - } else { - throw Exception("Sub values must be strings or dicts."); - } - - // Replace *ALL* occurrences. - // FIXME: Using this simple logic, If our replace value contains our - // search value we get an infinite loop. For now, just error in that case. - if (s_val.find(s_key) != std::string::npos) { - throw Exception("Subs replace string cannot contain search string."); - } - while (true) { - size_t pos = result.find(s_key); - if (pos == std::string::npos) { - break; - } - result.replace(pos, s_key.size(), s_val); - } - } - } - return result; -} - -auto Game::CompileResourceString(const std::string& s, const std::string& loc, - bool* valid) -> std::string { - assert(InGameThread()); - assert(g_python != nullptr); - - bool dummyvalid; - if (valid == nullptr) { - valid = &dummyvalid; - } - - // Quick out: if it doesn't start with a { and end with a }, treat it as a - // literal and just return it as-is. - if (s.size() < 2 || s[0] != '{' || s[s.size() - 1] != '}') { - *valid = true; - return s; - } - - cJSON* root = cJSON_Parse(s.c_str()); - if (root == nullptr) { - Log("CompileResourceString failed (loc " + loc + "); invalid json: '" + s - + "'"); - *valid = false; - return ""; - } - std::string result; - try { - result = DoCompileResourceString(root); - *valid = true; - } catch (const std::exception& e) { - Log("CompileResourceString failed (loc " + loc - + "): " + std::string(e.what()) + "; str='" + s + "'"); - result = ""; - *valid = false; - } - cJSON_Delete(root); - return result; -} - -auto Game::GetResourceString(const std::string& key) -> std::string { - std::string val; - { - std::lock_guard lock(language_mutex_); - auto i = language_.find(key); - if (i != language_.end()) { - val = i->second; - } - } - return val; -} - -auto Game::CharStr(SpecialChar id) -> std::string { - std::lock_guard lock(special_char_mutex_); - std::string val; - auto i = special_char_strings_.find(id); - if (i != special_char_strings_.end()) { - val = i->second; - } else { - BA_LOG_PYTHON_TRACE_ONCE("invalid key in CharStr(): '" - + std::to_string(static_cast(id)) + "'"); - val = "?"; - } - return val; -} - -void Game::HandleClientDisconnected(int id) { - auto i = connections_to_clients_.find(id); - if (i != connections_to_clients_.end()) { - bool was_connected = i->second->can_communicate(); - std::string leaver_spec = i->second->peer_spec().GetSpecString(); - std::vector leave_msg(leaver_spec.size() + 1); - leave_msg[0] = BA_MESSAGE_PARTY_MEMBER_LEFT; - memcpy(&(leave_msg[1]), leaver_spec.c_str(), leaver_spec.size()); - connections_to_clients_.erase(i); - - // If the client was connected, they were on the roster. - // We need to update it and send it to all remaining clients since they're - // gone. Also inform everyone who just left so they can announce it - // (technically could consolidate these messages but whatever...). - if (was_connected) { - UpdateGameRoster(); - for (auto&& connection : connections_to_clients_) { - if (ShouldAnnouncePartyJoinsAndLeaves()) { - connection.second->SendReliableMessage(leave_msg); - } - } - } - } -} - -void Game::PushClientDisconnectedCall(int id) { - PushCall([this, id] { HandleClientDisconnected(id); }); -} - -auto Game::ShouldAnnouncePartyJoinsAndLeaves() -> bool { - assert(InGameThread()); - - // At the moment we don't announce these for public internet parties.. (too - // much noise). - return !public_party_enabled(); -} - -void Game::CleanUpBeforeConnectingToHost() { - // We can't have connected clients and a host-connection at the same time. - // Make a minimal attempt to disconnect any client connections we have, but - // get them off the list immediately. - // FIXME: Should we have a 'purgatory' for dying client connections?.. - // (they may not get the single 'go away' packet we send here) - ForceDisconnectClients(); - - // Also make sure our public party state is off; this will inform the server - // that it should not be handing out our address to anyone. - assert(g_python); - SetPublicPartyEnabled(false); -} - -auto Game::DisconnectClient(int client_id, int ban_seconds) -> bool { - assert(InGameThread()); - - if (connection_to_host_.exists()) { - // Kick-votes first appeared in 14248 - if (connection_to_host_->build_number() < 14248) { - return false; - } - if (client_id > 255) { - Log("DisconnectClient got client_id > 255 (" + std::to_string(client_id) - + ")"); - } else { - std::vector msg_out(2); - msg_out[0] = BA_MESSAGE_KICK_VOTE; - msg_out[1] = static_cast_check_fit(client_id); - connection_to_host_->SendReliableMessage(msg_out); - return true; - } - } else { - // No host connection - look for clients. - auto i = connections_to_clients_.find(client_id); - - if (i != connections_to_clients_.end()) { - // If this is considered a kick, add an entry to our banned list so we - // know not to let them back in for a while. - if (ban_seconds > 0) { - BanPlayer(i->second->peer_spec(), 1000 * ban_seconds); - } - i->second->RequestDisconnect(); - - // Do the official local disconnect immediately with the sounds and all - // that. - PushClientDisconnectedCall(client_id); - - return true; - } - } - return false; -} - -void Game::ForceDisconnectClients() { - for (auto&& i : connections_to_clients_) { - if (ConnectionToClient* client = i.second.get()) { - client->RequestDisconnect(); - } - } - connections_to_clients_.clear(); -} - -void Game::PushHostConnectedUDPCall(const SockAddr& addr, - bool print_connect_progress) { - PushCall([this, addr, print_connect_progress] { - // Attempt to disconnect any clients we have, turn off public-party - // advertising, etc. - CleanUpBeforeConnectingToHost(); - print_udp_connect_progress_ = print_connect_progress; - connection_to_host_ = Object::New(addr); - has_connection_to_host_ = true; - printed_host_disconnect_ = false; - }); -} - -void Game::PushDisconnectFromHostCall() { - PushCall([this] { - if (connection_to_host_.exists()) { - connection_to_host_->RequestDisconnect(); - } - }); -} - -void Game::PushDisconnectedFromHostCall() { - PushCall([this] { - if (connection_to_host_.exists()) { - bool was_connected = connection_to_host_->can_communicate(); - connection_to_host_.Clear(); - has_connection_to_host_ = false; - - // Clear out our party roster. - UpdateGameRoster(); - - // Go back to main menu *if* the connection was fully connected. - // Otherwise we're still probably sitting at the main menu - // so no need to reset it. - if (was_connected) { - RunMainMenu(); - } - } - }); -} - -void Game::SendScreenMessageToAll(const std::string& s, float r, float g, - float b) { - SendScreenMessageToClients(s, r, g, b); - ScreenMessage(s, {r, g, b}); -} - -void Game::SendScreenMessageToClients(const std::string& s, float r, float g, - float b) { - for (auto&& i : connections_to_clients_) { - if (i.second.exists() && i.second->can_communicate()) { - i.second->SendScreenMessage(s, r, g, b); - } - } -} - -void Game::SendScreenMessageToSpecificClients(const std::string& s, float r, - float g, float b, - const std::vector& clients) { - for (auto&& i : connections_to_clients_) { - if (i.second.exists() && i.second->can_communicate()) { - // Only send if this client is in our list. - for (auto c : clients) { - if (c == i.second->id()) { - i.second->SendScreenMessage(s, r, g, b); - break; - } - } - } - } - - // Now print locally only if -1 is in our list. - for (auto c : clients) { - if (c == -1) { - ScreenMessage(s, {r, g, b}); - break; - } - } -} - -auto Game::GetConnectionToHostUDP() -> ConnectionToHostUDP* { - ConnectionToHost* h = connection_to_host_.get(); - return h ? h->GetAsUDP() : nullptr; -} - -void Game::PushPartyInviteCall(const std::string& name, - const std::string& invite_id) { - PushCall([this, name, invite_id] { PartyInvite(name, invite_id); }); -} - -void Game::PartyInvite(const std::string& name, const std::string& invite_id) { - assert(InGameThread()); - g_python->PartyInvite(name, invite_id); -} - -void Game::PushPartyInviteRevokeCall(const std::string& invite_id) { - PushCall([this, invite_id] { PartyInviteRevoke(invite_id); }); -} - -void Game::PartyInviteRevoke(const std::string& invite_id) { - assert(InGameThread()); - g_python->PartyInviteRevoke(invite_id); -} - -void Game::PushUDPConnectionPacketCall(const std::vector& data, - const SockAddr& addr) { - PushCall([this, data, addr] { UDPConnectionPacket(data, addr); }); -} - -// Called for low level packets coming in pertaining to udp -// host/client-connections. -void Game::UDPConnectionPacket(const std::vector& data_in, - const SockAddr& addr) { - assert(!data_in.empty()); - - const uint8_t* data = &(data_in[0]); - auto data_size = static_cast(data_in.size()); - - switch (data[0]) { - case BA_PACKET_CLIENT_ACCEPT: { - if (data_size == 3) { - uint8_t request_id = data[2]; - - // If we have a udp-host-connection and its request-id matches, we're - // accepted; hooray! - ConnectionToHostUDP* hc = GetConnectionToHostUDP(); - if (hc && hc->request_id() == request_id) { - hc->set_client_id(data[1]); - } - } - break; - } - case BA_PACKET_DISCONNECT_FROM_CLIENT_REQUEST: { - if (data_size == 2) { - // Client is telling us (host) that it wants to disconnect. - uint8_t client_id = data[1]; - - // Wipe that client out (if it still exists). - PushClientDisconnectedCall(client_id); - - // Now send an ack so they know it's been taken care of. - g_network_write_module->PushSendToCall( - {BA_PACKET_DISCONNECT_FROM_CLIENT_ACK, client_id}, addr); - } - break; - } - case BA_PACKET_DISCONNECT_FROM_CLIENT_ACK: { - if (data_size == 2) { - // Host is telling us (client) that we've been disconnected. - uint8_t client_id = data[1]; - ConnectionToHostUDP* hc = GetConnectionToHostUDP(); - if (hc && hc->client_id() == client_id) { - PushDisconnectedFromHostCall(); - } - } - break; - } - case BA_PACKET_DISCONNECT_FROM_HOST_REQUEST: { - if (data_size == 2) { - uint8_t client_id = data[1]; - - // Host is telling us (client) to disconnect. - ConnectionToHostUDP* hc = GetConnectionToHostUDP(); - if (hc && hc->client_id() == client_id) { - PushDisconnectedFromHostCall(); - } - - // Now send an ack so they know it's been taken care of. - g_network_write_module->PushSendToCall( - {BA_PACKET_DISCONNECT_FROM_HOST_ACK, client_id}, addr); - } - break; - } - case BA_PACKET_DISCONNECT_FROM_HOST_ACK: { - break; - } - case BA_PACKET_CLIENT_GAMEPACKET_COMPRESSED: { - if (data_size > 2) { - uint8_t client_id = data[1]; - auto i = connections_to_clients_.find(client_id); - if (i != connections_to_clients_.end()) { - // FIXME: could change HandleGamePacketCompressed to avoid this - // copy. - std::vector data2(data_size - 2); - memcpy(data2.data(), data + 2, data_size - 2); - i->second->HandleGamePacketCompressed(data2); - return; - } else { - // Send a disconnect request aimed at them. - g_network_write_module->PushSendToCall( - {BA_PACKET_DISCONNECT_FROM_HOST_REQUEST, client_id}, addr); - } - } - break; - } - - case BA_PACKET_HOST_GAMEPACKET_COMPRESSED: { - if (data_size > 2) { - uint8_t request_id = data[1]; - - ConnectionToHostUDP* hc = GetConnectionToHostUDP(); - if (hc && hc->request_id() == request_id) { - // FIXME: Should change HandleGamePacketCompressed to avoid this copy. - std::vector data2(data_size - 2); - memcpy(data2.data(), data + 2, data_size - 2); - hc->HandleGamePacketCompressed(data2); - } - } - break; - } - - case BA_PACKET_CLIENT_DENY: - case BA_PACKET_CLIENT_DENY_PARTY_FULL: - case BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY: - case BA_PACKET_CLIENT_DENY_VERSION_MISMATCH: { - if (data_size == 2) { - uint8_t request_id = data[1]; - ConnectionToHostUDP* hc = GetConnectionToHostUDP(); - - // If they're for-sure rejecting *this* connection, kill it. - if (hc && hc->request_id() == request_id) { - bool keep_trying = false; - - // OBSOLETE BUT HERE FOR BACKWARDS COMPAT WITH 1.4.98 servers. - // Newer servers never deny us in this way and simply include - // their protocol version in the handshake they send us, allowing us - // to decide whether we support talking to them or not. - if (data[0] == BA_PACKET_CLIENT_DENY_VERSION_MISMATCH) { - // If we've got more protocols we can try, keep trying to connect - // with our other protocols until one works or we run out. - // FIXME: We should move this logic to the gamepacket or message - // level so it works for all connection types. - keep_trying = hc->SwitchProtocol(); - if (!keep_trying) { - if (!printed_host_disconnect_) { - ScreenMessage( - GetResourceString("connectionFailedVersionMismatchText"), - {1, 0, 0}); - printed_host_disconnect_ = true; - } - } - } else if (data[0] == BA_PACKET_CLIENT_DENY_PARTY_FULL) { - if (!printed_host_disconnect_) { - if (print_udp_connect_progress_) { - ScreenMessage( - GetResourceString("connectionFailedPartyFullText"), - {1, 0, 0}); - } - printed_host_disconnect_ = true; - } - } else if (data[0] == BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY) { - if (!printed_host_disconnect_) { - ScreenMessage( - GetResourceString("connectionFailedHostAlreadyInPartyText"), - {1, 0, 0}); - printed_host_disconnect_ = true; - } - } else { - if (!printed_host_disconnect_) { - ScreenMessage(GetResourceString("connectionRejectedText"), - {1, 0, 0}); - printed_host_disconnect_ = true; - } - } - if (!keep_trying) { - PushDisconnectedFromHostCall(); - } - } - } - break; - } - case BA_PACKET_CLIENT_REQUEST: { - if (data_size > 4) { - // Bytes 2 and 3 are their protocol ID, byte 4 is request ID, the rest - // is session-id. - uint16_t protocol_id; - memcpy(&protocol_id, data + 1, 2); - uint8_t request_id = data[3]; - - // They also send us their session-ID which should - // be completely unique to them; we can use this to lump client - // requests together and such. - std::vector client_name_buffer(data_size - 4 + 1); - memcpy(&(client_name_buffer[0]), data + 4, data_size - 4); - client_name_buffer[data_size - 4] = 0; // terminate string - std::string client_name = &(client_name_buffer[0]); - - if (static_cast(connections_to_clients_.size() + 1) - >= public_party_max_size()) { - // If we've reached our party size limit (including ourself in that - // count), reject. - - // Newer version have a specific party-full message; send that first - // but also follow up with a generic deny message for older clients. - g_network_write_module->PushSendToCall( - {BA_PACKET_CLIENT_DENY_PARTY_FULL, request_id}, addr); - - g_network_write_module->PushSendToCall( - {BA_PACKET_CLIENT_DENY, request_id}, addr); - - } else if (connection_to_host_.exists()) { - // If we're connected to someone else, we can't have clients. - g_network_write_module->PushSendToCall( - {BA_PACKET_CLIENT_DENY_ALREADY_IN_PARTY, request_id}, addr); - } else { - // Otherwise go ahead and make them a new client connection. - Object::Ref connection_to_client; - - // Go through and see if we already have a client-connection for - // this request-id. - for (auto&& i : connections_to_clients_) { - if (ConnectionToClientUDP* cc_udp = i.second->GetAsUDP()) { - if (cc_udp->client_name() == client_name) { - connection_to_client = cc_udp; - break; - } - } - } - if (!connection_to_client.exists()) { - // Create them a client object. - // Try to find an unused client-id in the range 0-255. - int client_id = 0; - bool found = false; - for (int i = 0; i < 256; i++) { - int test_id = (next_connection_to_client_id_ + i) % 255; - if (connections_to_clients_.find(test_id) - == connections_to_clients_.end()) { - client_id = test_id; - found = true; - break; - } - } - next_connection_to_client_id_++; - - // If all 255 slots are taken (whaaaaaaa?), reject them. - if (!found) { - std::vector msg_out(2); - msg_out[0] = BA_PACKET_CLIENT_DENY; - msg_out[1] = request_id; - g_network_write_module->PushSendToCall(msg_out, addr); - Log("All client slots full; really?.."); - break; - } - connection_to_client = Object::New( - addr, client_name, request_id, client_id); - connections_to_clients_[client_id] = connection_to_client; - } - - // If we got to this point, regardless of whether - // we already had a connection or not, tell them - // they're accepted. - std::vector msg_out(3); - msg_out[0] = BA_PACKET_CLIENT_ACCEPT; - assert(connection_to_client->id() < 256); - msg_out[1] = - static_cast_check_fit(connection_to_client->id()); - msg_out[2] = request_id; - g_network_write_module->PushSendToCall(msg_out, addr); - } - } - break; - } - default: - // Assuming we can get random other noise in here; - // should just silently ignore. - break; - } -} - -// Can probably kill this. -auto Game::GetConnectionsToClients() -> std::vector { - std::vector connections; - connections.reserve(connections_to_clients_.size()); - for (auto& connections_to_client : connections_to_clients_) { - if (connections_to_client.second.exists()) { - connections.push_back(connections_to_client.second.get()); - } else { - Log("HAVE NONEXISTENT CONNECTION_TO_CLIENT IN LIST; UNEXPECTED"); - } - } - return connections; -} - -#if BA_GOOGLE_BUILD - -void Game::PushClientDisconnectedGooglePlayCall(int google_id) { - PushCall([this, google_id] { - int id = ClientIDFromGooglePlayClientID(google_id); - HandleClientDisconnected(id); - }); -} - -int Game::ClientIDFromGooglePlayClientID(int google_id) { - auto i = google_play_id_to_client_id_map_.find(google_id); - if (i != google_play_id_to_client_id_map_.end()) { - return i->second; - } else { - BA_LOG_ONCE("ClientIDFromGooglePlayClientID failed for id " - + std::to_string(google_id)); - return -1; - } -} - -int Game::GooglePlayClientIDFromClientID(int client_id) { - auto i = client_id_to_google_play_id_map_.find(client_id); - if (i != client_id_to_google_play_id_map_.end()) { - return i->second; - } else { - BA_LOG_ONCE("client_id_to_google_play_id_map_ failed for id " - + std::to_string(client_id)); - return -1; - } -} - -// Called for Google Play connections. -void Game::PushCompressedGamePacketFromHostGooglePlayCall( - const std::vector& data) { - PushCall([this, data] { - if (!connection_to_host_.exists()) { - Log("Error: Got host game-packet message but have no host."); - return; - } - connection_to_host_->HandleGamePacketCompressed(data); - }); -} - -// Called for Google Play connections. -void Game::PushCompressedGamePacketFromClientGooglePlayCall( - int google_client_id, const std::vector& data) { - PushCall([this, google_client_id, data] { - int client_id = ClientIDFromGooglePlayClientID(google_client_id); - auto i = connections_to_clients_.find(client_id); - if (i == connections_to_clients_.end()) { - Log("Error: Got data-from-client msg for nonexistent client."); - return; - } - i->second->HandleGamePacketCompressed(data); - }); -} - -void Game::PushClientConnectedGooglePlayCall(int id) { - PushCall([this, id] { - // Find a free ballistica client_id. - int client_id = 0; - bool found = false; - for (int i = 0; i < 256; i++) { - int test_id = (next_connection_to_client_id_ + i) % 255; - if (connections_to_clients_.find(test_id) - == connections_to_clients_.end()) { - client_id = test_id; - found = true; - break; - } - } - next_connection_to_client_id_++; - - if (found) { - google_play_id_to_client_id_map_[id] = client_id; - client_id_to_google_play_id_map_[client_id] = id; - if (connections_to_clients_.find(client_id) - != connections_to_clients_.end()) { - Log("Error: Got client-connected message" - " for already existing client-id."); - } - connections_to_clients_[client_id] = - g_platform->AndroidGPGSNewConnectionToClient(client_id); - } else { - Log("no client_id available in ClientConnectedGooglePlayCall"); - } - }); -} - -void Game::PushHostConnectedGooglePlayCall() { - PushCall([this] { - // Attempt to disconnect any existing clients we have, turn off public-party - // advertising, etc. - CleanUpBeforeConnectingToHost(); - connection_to_host_ = g_platform->AndroidGPGSNewConnectionToHost(); - has_connection_to_host_ = true; - printed_host_disconnect_ = false; - }); -} - -int Game::GetGooglePlayClientCount() const { - assert(InGameThread()); - int count = 0; - for (auto&& i : connections_to_clients_) { - if (i.second.exists() && i.second->can_communicate() - && g_platform->AndroidIsGPGSConnectionToClient(i.second.get())) { - count++; - } - } - return count; -} -#endif // BA_GOOGLE_BUILD - -auto Game::GetConnectedClientCount() const -> int { - assert(InGameThread()); - int count = 0; - for (auto&& i : connections_to_clients_) { - if (i.second.exists() && i.second->can_communicate()) { - count++; - } - } - return count; -} - -auto Game::GetPartySize() const -> int { - assert(InGameThread()); - assert(game_roster_ != nullptr); - return cJSON_GetArraySize(game_roster_); -} - -void Game::LocalDisplayChatMessage(const std::vector& buffer) { - // 1 type byte, 1 spec-len byte, 1 or more spec chars, 0 or more msg chars. - if (buffer.size() > 3) { - size_t spec_len = buffer[1]; - if (spec_len > 0 && spec_len + 2 <= buffer.size()) { - size_t msg_len = buffer.size() - spec_len - 2; - std::vector b1(spec_len + 1); - memcpy(&(b1[0]), &(buffer[2]), spec_len); - b1[spec_len] = 0; - std::vector b2(msg_len + 1); - if (msg_len > 0) { - memcpy(&(b2[0]), &(buffer[2 + spec_len]), msg_len); - } - b2[msg_len] = 0; - - std::string final_message = - PlayerSpec(b1.data()).GetDisplayString() + ": " + b2.data(); - - // Store it locally. - chat_messages_.push_back(final_message); - while (chat_messages_.size() > kMaxChatMessages) { - chat_messages_.pop_front(); - } - - // Show it on the screen if they don't have their chat window open - // (and don't have chat muted). - if (!g_ui->root_ui()->party_window_open()) { - if (!chat_muted_) { - ScreenMessage(final_message, {0.7f, 1.0f, 0.7f}); - } - } else { - // Party window is open - notify it that there's a new message. - g_python->HandleLocalChatMessage(final_message); - } - if (!chat_muted_) { - g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); - } - } - } -} - -void Game::SendChatMessage(const std::string& message, - const std::vector* clients, - const std::string* sender_override) { - // Sending to particular clients is only applicable while hosting. - if (clients != nullptr && connection_to_host() != nullptr) { - throw Exception("Can't send chat message to specific clients as a client."); - } - - // Same with overriding sender name - if (sender_override != nullptr && connection_to_host() != nullptr) { - throw Exception( - "Can't send chat message with sender_override as a client."); - } - - std::string our_spec_string; - - if (sender_override != nullptr) { - std::string override_final = *sender_override; - if (override_final.size() > kMaxPartyNameCombinedSize) { - override_final.resize(kMaxPartyNameCombinedSize); - override_final += "..."; - } - our_spec_string = - PlayerSpec::GetDummyPlayerSpec(override_final).GetSpecString(); - } else { - if (connection_to_host() != nullptr) { - // NOTE - we send our own spec string with the chat message whether we're - // a client or server.. however on protocol version 30+ this is ignored - // by the server and replaced with a spec string it generates for us. - // so once we know we're connected to a 30+ server we can start sending - // blank strings as a client. - // (not that it really matters; chat messages are tiny overall) - our_spec_string = PlayerSpec::GetAccountPlayerSpec().GetSpecString(); - } else { - // As a host we want to do the equivalent of - // ConnectionToClient::GetCombinedSpec() except for local connections (so - // send our name as the combination of local players if possible). Look - // for players coming from this client-connection; if we find any, make a - // spec out of their name(s). - std::string p_name_combined; - if (auto* hs = dynamic_cast(GetForegroundSession())) { - for (auto&& p : hs->players()) { - InputDevice* input_device = p->GetInputDevice(); - if (p->accepted() && p->name_is_real() && input_device != nullptr - && !input_device->IsRemoteClient()) { - if (!p_name_combined.empty()) { - p_name_combined += "/"; - } - p_name_combined += p->GetName(); - } - } - } - if (p_name_combined.size() > kMaxPartyNameCombinedSize) { - p_name_combined.resize(kMaxPartyNameCombinedSize); - p_name_combined += "..."; - } - if (!p_name_combined.empty()) { - our_spec_string = - PlayerSpec::GetDummyPlayerSpec(p_name_combined).GetSpecString(); - } else { - our_spec_string = PlayerSpec::GetAccountPlayerSpec().GetSpecString(); - } - } - } - - // If we find a newline, only take the first line (prevent people from - // covering the screen with obnoxious chat messages). - std::string message2 = message; - size_t nlpos = message2.find('\n'); - if (nlpos != std::string::npos) { - message2 = message2.substr(0, nlpos); - } - - // If we're the host, run filters before we send the message out. - // If the filter kills the message, don't send. - bool allow_message = g_python->FilterChatMessage(&message2, -1); - if (!allow_message) { - return; - } - - // 1 byte type + 1 byte spec-string-length + message. - std::vector msg_out(1 + 1 + our_spec_string.size() - + message2.size()); - msg_out[0] = BA_MESSAGE_CHAT; - size_t spec_size = our_spec_string.size(); - assert(spec_size < 256); - msg_out[1] = static_cast(spec_size); - memcpy(&(msg_out[2]), our_spec_string.c_str(), spec_size); - memcpy(&(msg_out[2 + spec_size]), message2.c_str(), message2.size()); - - // If we're a client, send this to the host (it will make its way back to us - // when they send to clients). - if (ConnectionToHost* hc = connection_to_host()) { - hc->SendReliableMessage(msg_out); - } else { - // Ok we're the host. - - // Send to all (or at least some) connected clients. - for (auto&& i : connections_to_clients_) { - // Skip if its going to specific ones and this one doesn't match. - if (clients != nullptr) { - auto found = false; - for (auto&& c : *clients) { - if (c == i.second->id()) { - found = true; - } - } - if (!found) { - continue; - } - } - - if (i.second->can_communicate()) { - i.second->SendReliableMessage(msg_out); - } - } - - // And display locally if the message is addressed to all. - if (clients == nullptr) { - LocalDisplayChatMessage(msg_out); - } - } -} - -auto Game::GetGameRosterMessage() -> std::vector { - // This message is simply a flattened json string of our roster (including - // terminating char). - char* s = cJSON_PrintUnformatted(game_roster_); - // printf("ROSTER MESSAGE %s\n", s); - auto s_len = strlen(s); - std::vector msg(1 + s_len + 1); - msg[0] = BA_MESSAGE_PARTY_ROSTER; - memcpy(&(msg[1]), s, s_len + 1); - free(s); - - return msg; -} - -auto Game::IsPlayerBanned(const PlayerSpec& spec) -> bool { - millisecs_t current_time = GetRealTime(); - - // Now is a good time to prune no-longer-banned specs. - while (!banned_players_.empty() - && banned_players_.front().first < current_time) { - banned_players_.pop_front(); - } - for (auto&& test_spec : banned_players_) { - if (test_spec.second == spec) { - return true; - } - } - return false; -} - -void Game::StartKickVote(ConnectionToClient* starter, - ConnectionToClient* target) { - // Restrict votes per client. - millisecs_t current_time = GetRealTime(); - - if (starter == target) { - // Don't let anyone kick themselves. - starter->SendScreenMessage(R"({"r":"kickVoteCantKickSelfText",)" - R"("f":"kickVoteFailedText"})", - 1, 0, 0); - } else if (target->IsAdmin()) { - // Admins are immune to kicking - starter->SendScreenMessage(R"({"r":"kickVoteCantKickAdminText",)" - R"("f":"kickVoteFailedText"})", - 1, 0, 0); - } else if (starter->IsAdmin()) { - // Admin doing the kicking succeeds instantly. - SendScreenMessageToClients( - R"({"r":"kickOccurredText","s":[["${NAME}",)" - + Utils::GetJSONString( - target->GetCombinedSpec().GetDisplayString().c_str()) - + "]]}", - 1, 1, 0); - DisconnectClient(target->id(), kKickBanSeconds); - starter->SendScreenMessage(R"({"r":"kickVoteCantKickAdminText",)" - R"("f":"kickVoteFailedText"})", - 1, 0, 0); - } else if (!kick_voting_enabled_) { - // No kicking otherwise if its disabled. - starter->SendScreenMessage(R"({"r":"kickVotingDisabledText",)" - R"("f":"kickVoteFailedText"})", - 1, 0, 0); - } else if (kick_vote_in_progress_) { - // Vote in progress error. - starter->SendScreenMessage(R"({"r":"voteInProgressText"})", 1, 0, 0); - } else if (GetConnectedClientCount() < kKickVoteMinimumClients) { - // There's too few clients to effectively vote. - starter->SendScreenMessage(R"({"r":"kickVoteFailedNotEnoughVotersText",)" - R"("f":"kickVoteFailedText"})", - 1, 0, 0); - } else if (current_time < starter->next_kick_vote_allow_time_) { - // Not yet allowed error. - starter->SendScreenMessage( - R"({"r":"voteDelayText","s":[["${NUMBER}",")" - + std::to_string(std::max( - millisecs_t{1}, - (starter->next_kick_vote_allow_time_ - current_time) / 1000)) - + "\"]]}", - 1, 0, 0); - } else { - std::vector connected_clients = - GetConnectionsToClients(); - - // Ok, kick off a vote.. (send the question and instructions to everyone - // except the starter and the target). - for (auto&& client : connected_clients) { - if (client != starter && client != target) { - client->SendScreenMessage( - R"({"r":"kickQuestionText","s":[["${NAME}",)" - + Utils::GetJSONString( - target->GetCombinedSpec().GetDisplayString().c_str()) - + "]]}", - 1, 1, 0); - client->SendScreenMessage(R"({"r":"kickWithChatText","s":)" - R"([["${YES}","'1'"],["${NO}","'0'"]]})", - 1, 1, 0); - } else { - // For the kicker/kickee, simply print that a kick vote has been - // started. - client->SendScreenMessage( - R"({"r":"kickVoteStartedText","s":[["${NAME}",)" - + Utils::GetJSONString( - target->GetCombinedSpec().GetDisplayString().c_str()) - + "]]}", - 1, 1, 0); - } - } - kick_vote_end_time_ = current_time + kKickVoteDuration; - kick_vote_in_progress_ = true; - last_kick_votes_needed_ = -1; // make sure we print starting num - - // Keep track of who started the vote. - kick_vote_starter_ = starter; - kick_vote_target_ = target; - - // Reset votes for all connected clients. - for (ConnectionToClient* client : GetConnectionsToClients()) { - if (client == starter) { - client->kick_voted_ = true; - client->kick_vote_choice_ = true; - } else { - client->kick_voted_ = false; - } - } - } -} - -void Game::BanPlayer(const PlayerSpec& spec, millisecs_t duration) { - banned_players_.emplace_back(GetRealTime() + duration, spec); -} - -void Game::UpdateGameRoster() { - assert(InGameThread()); - - assert(game_roster_ != nullptr); - if (game_roster_ != nullptr) { - cJSON_Delete(game_roster_); - } - - // Our party-roster is just a json array of dicts containing player-specs. - game_roster_ = cJSON_CreateArray(); - - int total_party_size = 1; // include ourself here.. - - // Add ourself first (that's currently how they know we're the party leader) - // ..but only if we have a connected client (otherwise our party is - // considered 'empty'). - - // UPDATE: starting with our big ui revision we'll always include ourself - // here - bool include_self = (GetConnectedClientCount() > 0); -#if BA_TOOLBAR_TEST - include_self = true; -#endif // BA_TOOLBAR_TEST - - if (auto* hs = dynamic_cast(GetForegroundSession())) { - // Add our host-y self. - if (include_self) { - cJSON* client_dict = cJSON_CreateObject(); - cJSON_AddItemToObject( - client_dict, "spec", - cJSON_CreateString( - PlayerSpec::GetAccountPlayerSpec().GetSpecString().c_str())); - - // Add our list of local players. - cJSON* player_array = cJSON_CreateArray(); - for (auto&& p : hs->players()) { - InputDevice* input_device = p->GetInputDevice(); - - // Add some basic info for each local player (only ones with real - // names though; don't wanna send , etc). - if (p->accepted() && p->name_is_real() && input_device != nullptr - && !input_device->IsRemoteClient()) { - cJSON* player_dict = cJSON_CreateObject(); - cJSON_AddItemToObject(player_dict, "n", - cJSON_CreateString(p->GetName().c_str())); - cJSON_AddItemToObject(player_dict, "nf", - cJSON_CreateString(p->GetName(true).c_str())); - cJSON_AddItemToObject(player_dict, "i", cJSON_CreateNumber(p->id())); - cJSON_AddItemToArray(player_array, player_dict); - } - } - cJSON_AddItemToObject(client_dict, "p", player_array); - cJSON_AddItemToObject( - client_dict, "i", - cJSON_CreateNumber(-1)); // -1 client_id means we're the host. - cJSON_AddItemToArray(game_roster_, client_dict); - } - - // Add all connected clients. - for (auto&& i : connections_to_clients_) { - if (i.second->can_communicate()) { - cJSON* client_dict = cJSON_CreateObject(); - cJSON_AddItemToObject( - client_dict, "spec", - cJSON_CreateString(i.second->peer_spec().GetSpecString().c_str())); - - // Add their public account id (or None if we don't have it) - // cJSON* player_accountid{}; - // if (i.second->peer_public_account_id() == "") { - // player_accountid = cJSON_CreateNull(); - // } else { - // player_accountid = - // cJSON_CreateString(i.second->peer_public_account_id().c_str()); - // } - // cJSON_AddItemToObject(client_dict, "a", player_accountid); - - // Also add their list of players. - cJSON* player_array = cJSON_CreateArray(); - - // Include all players that are remote and coming from this same - // client connection. - for (auto&& p : hs->players()) { - InputDevice* input_device = p->GetInputDevice(); - if (p->accepted() && p->name_is_real() && input_device != nullptr - && input_device->IsRemoteClient()) { - auto* cid = static_cast(input_device); - ConnectionToClient* ctc = cid->connection_to_client(); - - // Add some basic info for each remote player. - if (ctc != nullptr && ctc == i.second.get()) { - cJSON* player_dict = cJSON_CreateObject(); - cJSON_AddItemToObject(player_dict, "n", - cJSON_CreateString(p->GetName().c_str())); - cJSON_AddItemToObject( - player_dict, "nf", - cJSON_CreateString(p->GetName(true).c_str())); - cJSON_AddItemToObject(player_dict, "i", - cJSON_CreateNumber(p->id())); - cJSON_AddItemToArray(player_array, player_dict); - } - } - } - cJSON_AddItemToObject(client_dict, "p", player_array); - cJSON_AddItemToObject(client_dict, "i", - cJSON_CreateNumber(i.second->id())); - cJSON_AddItemToArray(game_roster_, client_dict); - total_party_size += 1; - } - } - } - - // Keep the python layer informed on our number of connections; it may want - // to pass the info along to the master server if we're hosting a public - // party. - SetPublicPartySize(total_party_size); - - // Mark the roster as dirty so we know we need to send it to everyone soon. - game_roster_dirty_ = true; -} - -void Game::SetAdCompletionCall(PyObject* obj, bool pass_actually_showed) { - if (obj == Py_None) { - ad_completion_callback_.Clear(); - } else { - ad_completion_callback_ = Object::New(obj); - } - ad_completion_callback_pass_actually_showed_ = pass_actually_showed; - last_ad_start_time_ = g_platform->GetTicks(); -} - -void Game::CallAdCompletionCall(bool actually_showed) { - if (ad_completion_callback_.exists()) { - if (ad_completion_callback_pass_actually_showed_) { - PythonRef args(Py_BuildValue("(O)", actually_showed ? Py_True : Py_False), - PythonRef::kSteal); - ad_completion_callback_->Run(args); - } else { - ad_completion_callback_->Run(); - } - ad_completion_callback_.Clear(); // These are single-fire callbacks. - } -} - -void Game::SetPublicPartyEnabled(bool val) { - assert(InGameThread()); - if (val == public_party_enabled_) { - return; - } - public_party_enabled_ = val; - PushPublicPartyState(); -} - -void Game::SetPublicPartySize(int count) { - assert(InGameThread()); - if (count == public_party_size_) { - return; - } - public_party_size_ = count; - - // Push our new state to the server *ONLY* if public-party is turned on - // (wasteful otherwise). - if (public_party_enabled_) { - PushPublicPartyState(); - } -} - -void Game::SetPublicPartyMaxSize(int count) { - assert(InGameThread()); - if (count == public_party_max_size_) { - return; - } - public_party_max_size_ = count; - - // Push our new state to the server *ONLY* if public-party is turned on - // (wasteful otherwise). - if (public_party_enabled_) { - PushPublicPartyState(); - } -} - -void Game::SetPublicPartyName(const std::string& name) { - assert(InGameThread()); - if (name == public_party_name_) { - return; - } - public_party_name_ = name; - - // Push our new state to the server *ONLY* if public-party is turned on - // (wasteful otherwise). - if (public_party_enabled_) { - PushPublicPartyState(); - } -} - -void Game::SetPublicPartyStatsURL(const std::string& url) { - assert(InGameThread()); - if (url == public_party_stats_url_) { - return; - } - public_party_stats_url_ = url; - - // Push our new state to the server *ONLY* if public-party is turned on - // (wasteful otherwise). - if (public_party_enabled_) { - PushPublicPartyState(); - } -} - -void Game::SetPublicPartyPlayerCount(int count) { - assert(InGameThread()); - if (count == public_party_player_count_) { - return; - } - public_party_player_count_ = count; - - // Push our new state to the server *ONLY* if public-party is turned on - // (wasteful otherwise). - if (public_party_enabled_) { - PushPublicPartyState(); - } -} - -void Game::PushPublicPartyState() { - assert(InGameThread()); - PythonRef call = g_python->obj(Python::ObjID::kAccountClient) - .GetAttr("set_public_party_state"); - if (call.exists()) { - PythonRef args( - Py_BuildValue( - "(iiiiisss)", static_cast(public_party_enabled_), - public_party_size_, public_party_max_size_, - public_party_player_count_, public_party_max_player_count_, - public_party_name_.c_str(), public_party_min_league_.c_str(), - public_party_stats_url_.c_str()), - PythonRef::kSteal); - call.Call(args); - } else { - Log("Error on pushPublicPartyState call"); - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/game_stream.cc b/src/ballistica/game/game_stream.cc deleted file mode 100644 index 8dd47091..00000000 --- a/src/ballistica/game/game_stream.cc +++ /dev/null @@ -1,1242 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/game_stream.h" - -#include - -#include "ballistica/app/app_globals.h" -#include "ballistica/dynamics/bg/bg_dynamics.h" -#include "ballistica/dynamics/material/material.h" -#include "ballistica/dynamics/material/material_action.h" -#include "ballistica/dynamics/material/material_component.h" -#include "ballistica/dynamics/material/material_condition_node.h" -#include "ballistica/dynamics/part.h" -#include "ballistica/game/connection/connection_to_client.h" -#include "ballistica/game/session/host_session.h" -#include "ballistica/media/component/collide_model.h" -#include "ballistica/media/component/data.h" -#include "ballistica/media/component/model.h" -#include "ballistica/media/component/texture.h" -#include "ballistica/media/media_server.h" -#include "ballistica/networking/networking.h" -#include "ballistica/scene/node/node_attribute.h" -#include "ballistica/scene/node/node_type.h" -#include "ballistica/scene/scene.h" - -namespace ballistica { - -GameStream::GameStream(HostSession* host_session, bool saveReplay) - : time_(0), - host_session_(host_session), - next_flush_time_(0), - last_physics_correction_time_(0), - last_send_time_(0), - writing_replay_(false) { - if (saveReplay) { - // Sanity check - we should only ever be writing one replay at once. - if (g_app_globals->replay_open) { - Log("ERROR: g_replay_open true at replay start; shouldn't happen."); - } - assert(g_media_server); - g_media_server->PushBeginWriteReplayCall(); - writing_replay_ = true; - g_app_globals->replay_open = true; - } - - // If we're the live output-stream from a host-session, - // take responsibility for feeding all clients to this device. - if (host_session_) { - g_game->RegisterClientController(this); - } -} - -GameStream::~GameStream() { - // Ship our last commands (if it matters..) - Flush(); - - if (writing_replay_) { - // Sanity check: We should only ever be writing one replay at once. - if (!g_app_globals->replay_open) { - Log("ERROR: g_replay_open false at replay close; shouldn't happen."); - } - g_app_globals->replay_open = false; - assert(g_media_server); - g_media_server->PushEndWriteReplayCall(); - writing_replay_ = false; - } - - // If we're wired to the host-session, go ahead and release clients. - if (host_session_) { - g_game->UnregisterClientController(this); - - // Also, in the host-session case, make sure everything cleaned itself up. -#if BA_DEBUG_BUILD - size_t count; - count = GetPointerCount(scenes_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " scene graphs in output stream at shutdown"); - } - count = GetPointerCount(nodes_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " nodes in output stream at shutdown"); - } - count = GetPointerCount(materials_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " materials in output stream at shutdown"); - } - count = GetPointerCount(textures_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " textures in output stream at shutdown"); - } - count = GetPointerCount(models_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " models in output stream at shutdown"); - } - count = GetPointerCount(sounds_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " sounds in output stream at shutdown"); - } - count = GetPointerCount(collide_models_); - if (count != 0) { - Log("ERROR: " + std::to_string(count) - + " collide_models in output stream at shutdown"); - } -#endif // BA_DEBUG_BUILD - } -} - -// Pull the current built-up message. -auto GameStream::GetOutMessage() const -> std::vector { - assert(!host_session_); // this should only be getting used for - // standalone temp ones.. - if (!out_command_.empty()) { - Log("Error: GameStream shutting down with non-empty outCommand"); - } - return out_message_; -} - -template -auto GameStream::GetPointerCount(const std::vector& vec) -> size_t { - size_t count = 0; - - auto size = vec.size(); - T* const* vals = vec.data(); - for (size_t i = 0; i < size; i++) { - if (vals[i] != nullptr) { - count++; - } - } - return count; -} - -// Given a vector of pointers, return an index to an available (nullptr) entry, -// expanding the vector if need be. -template -auto GameStream::GetFreeIndex(std::vector* vec, - std::vector* free_indices) -> size_t { - // If we have any free indices, use one of them. - if (!free_indices->empty()) { - size_t val = free_indices->back(); - free_indices->pop_back(); - return val; - } - - // No free indices; expand the vec and return the new index. - vec->push_back(nullptr); - return vec->size() - 1; -} - -// Add an entry. -template -void GameStream::Add(T* val, std::vector* vec, - std::vector* free_indices) { - // This should only get used when we're being driven by the host-session. - assert(host_session_); - assert(val); - assert(val->stream_id() == -1); - size_t index = GetFreeIndex(vec, free_indices); - (*vec)[index] = val; - val->set_stream_id(index); -} - -// Remove an entry. -template -void GameStream::Remove(T* val, std::vector* vec, - std::vector* free_indices) { - assert(val); - assert(val->stream_id() >= 0); - assert(static_cast(vec->size()) > val->stream_id()); - assert((*vec)[val->stream_id()] == val); - (*vec)[val->stream_id()] = nullptr; - - // Add this to our list of available slots to recycle. - free_indices->push_back(val->stream_id()); - val->clear_stream_id(); -} - -void GameStream::Fail() { - Log("Error writing replay file"); - if (writing_replay_) { - // Sanity check: We should only ever be writing one replay at once. - if (!g_app_globals->replay_open) { - Log("ERROR: g_replay_open false at replay close; shouldn't happen."); - } - assert(g_media_server); - g_media_server->PushEndWriteReplayCall(); - writing_replay_ = false; - g_app_globals->replay_open = false; - } -} - -void GameStream::Flush() { - if (!out_command_.empty()) - Log("Error: GameStream flushing down with non-empty outCommand"); - if (!out_message_.empty()) { - ShipSessionCommandsMessage(); - } -} - -// Writes just a command. -void GameStream::WriteCommand(SessionCommand cmd) { - assert(out_command_.empty()); - - // For now just use full size values. - size_t size = 0; - out_command_.resize(size + 1); - uint8_t* ptr = &out_command_[size]; - *ptr = static_cast(cmd); -} - -// Writes a command plus an int to the stream, using whatever size is optimal. -void GameStream::WriteCommandInt32(SessionCommand cmd, int32_t value) { - assert(out_command_.empty()); - - // For now just use full size values. - size_t size = 0; - out_command_.resize(size + 5); - uint8_t* ptr = &out_command_[size]; - *(ptr++) = static_cast(cmd); - int32_t vals[] = {value}; - memcpy(ptr, vals, 4); -} - -void GameStream::WriteCommandInt32_2(SessionCommand cmd, int32_t value1, - int32_t value2) { - assert(out_command_.empty()); - - // For now just use full size vals. - size_t size = 0; - out_command_.resize(size + 9); - uint8_t* ptr = &out_command_[size]; - *(ptr++) = static_cast(cmd); - int32_t vals[] = {value1, value2}; - memcpy(ptr, vals, 8); -} - -void GameStream::WriteCommandInt32_3(SessionCommand cmd, int32_t value1, - int32_t value2, int32_t value3) { - assert(out_command_.empty()); - - // For now just use full size vals. - size_t size = 0; - out_command_.resize(size + 13); - uint8_t* ptr = &out_command_[size]; - *(ptr++) = static_cast(cmd); - int32_t vals[] = {value1, value2, value3}; - memcpy(ptr, vals, 12); -} - -void GameStream::WriteCommandInt32_4(SessionCommand cmd, int32_t value1, - int32_t value2, int32_t value3, - int32_t value4) { - assert(out_command_.empty()); - - // For now just use full size vals. - size_t size = 0; - out_command_.resize(size + 17); - uint8_t* ptr = &out_command_[size]; - *(ptr++) = static_cast(cmd); - int32_t vals[] = {value1, value2, value3, value4}; - memcpy(ptr, vals, 16); -} - -// FIXME: We don't actually support sending out 64 bit values yet, but -// adding these placeholders for if/when we do. -// They will also catch values greater than 32 bits in debug mode. -// We'll need a protocol update to add support for 64 bit over the wire. -void GameStream::WriteCommandInt64(SessionCommand cmd, int64_t value) { - WriteCommandInt32(cmd, static_cast_check_fit(value)); -} - -void GameStream::WriteCommandInt64_2(SessionCommand cmd, int64_t value1, - int64_t value2) { - WriteCommandInt32_2(cmd, static_cast_check_fit(value1), - static_cast_check_fit(value2)); -} - -void GameStream::WriteCommandInt64_3(SessionCommand cmd, int64_t value1, - int64_t value2, int64_t value3) { - WriteCommandInt32_3(cmd, static_cast_check_fit(value1), - static_cast_check_fit(value2), - static_cast_check_fit(value3)); -} - -void GameStream::WriteCommandInt64_4(SessionCommand cmd, int64_t value1, - int64_t value2, int64_t value3, - int64_t value4) { - WriteCommandInt32_4(cmd, static_cast_check_fit(value1), - static_cast_check_fit(value2), - static_cast_check_fit(value3), - static_cast_check_fit(value4)); -} - -void GameStream::WriteString(const std::string& s) { - // Write length int. - auto string_size = s.size(); - auto size = out_command_.size(); - out_command_.resize(size + 4 + s.size()); - memcpy(&out_command_[size], &string_size, 4); - if (string_size > 0) { - memcpy(&out_command_[size + 4], s.c_str(), string_size); - } -} - -void GameStream::WriteFloat(float val) { - auto size = static_cast(out_command_.size()); - out_command_.resize(size + sizeof(val)); - memcpy(&out_command_[size], &val, 4); -} - -void GameStream::WriteFloats(size_t count, const float* vals) { - assert(count > 0); - auto size = out_command_.size(); - size_t vals_size = sizeof(float) * count; - out_command_.resize(size + vals_size); - memcpy(&(out_command_[size]), vals, vals_size); -} - -void GameStream::WriteInts32(size_t count, const int32_t* vals) { - assert(count > 0); - auto size = out_command_.size(); - size_t vals_size = sizeof(int32_t) * count; - out_command_.resize(size + vals_size); - memcpy(&(out_command_[size]), vals, vals_size); -} - -void GameStream::WriteInts64(size_t count, const int64_t* vals) { - // FIXME: we don't actually support writing 64 bit values to the wire - // at the moment; will need a protocol update for that. - // This is just implemented as a placeholder. - std::vector vals32(count); - for (size_t i = 0; i < count; i++) { - vals32[i] = static_cast_check_fit(vals[i]); - } - WriteInts32(count, vals32.data()); -} - -void GameStream::WriteChars(size_t count, const char* vals) { - assert(count > 0); - auto size = out_command_.size(); - auto vals_size = static_cast(count); - out_command_.resize(size + vals_size); - memcpy(&(out_command_[size]), vals, vals_size); -} - -void GameStream::ShipSessionCommandsMessage() { - BA_PRECONDITION(!out_message_.empty()); - - // Send this message to all client-connections we're attached to. - for (auto& connection : connections_to_clients_) { - (*connection).SendReliableMessage(out_message_); - } - if (writing_replay_) { - AddMessageToReplay(out_message_); - } - out_message_.clear(); - last_send_time_ = GetRealTime(); -} - -void GameStream::AddMessageToReplay(const std::vector& message) { - assert(writing_replay_); - assert(g_media_server); - - assert(!message.empty()); -#if BA_DEBUG_BUILD - switch (message[0]) { - case BA_MESSAGE_SESSION_RESET: - case BA_MESSAGE_SESSION_COMMANDS: - case BA_MESSAGE_SESSION_DYNAMICS_CORRECTION: - break; - default: - throw Exception("unexpected message going to replay: " - + std::to_string(static_cast(message[0]))); - } -#endif // BA_DEBUG_BUILD - g_media_server->PushAddMessageToReplayCall(message); -} - -void GameStream::SendPhysicsCorrection(bool blend) { - assert(host_session_); - - std::vector > messages; - host_session_->GetCorrectionMessages(blend, &messages); - - // FIXME - have to send reliably at the moment since these will most likely be - // bigger than our unreliable packet limit. :-( - for (auto& message : messages) { - for (auto& connections_to_client : connections_to_clients_) { - (*connections_to_client).SendReliableMessage(message); - } - if (writing_replay_) { - AddMessageToReplay(message); - } - } -} - -void GameStream::EndCommand(bool is_time_set) { - assert(!out_command_.empty()); - - int out_message_size; - if (out_message_.empty()) { - // Init the message if we're the first command on it. - out_message_.resize(1); - out_message_[0] = BA_MESSAGE_SESSION_COMMANDS; - out_message_size = 1; - } else { - out_message_size = static_cast(out_message_.size()); - } - - out_message_.resize(out_message_size + 2 - + out_command_.size()); // command length plus data - - auto val = static_cast(out_command_.size()); - memcpy(&(out_message_[out_message_size]), &val, 2); - memcpy(&(out_message_[out_message_size + 2]), &(out_command_[0]), - out_command_.size()); - - // When attached to a host-session, send this message to clients if it's been - // long enough. - - // Also send off occasional correction packets. - if (host_session_) { - // Now if its been long enough and this is a time-step command, send. - millisecs_t real_time = GetRealTime(); - millisecs_t diff = real_time - last_send_time_; - if (is_time_set && diff > g_app_globals->buffer_time) { - ShipSessionCommandsMessage(); - - // Also, as long as we're here, fire off a physics-correction packet every - // now and then. - - // IMPORTANT: We only do this right after shipping off our pending session - // commands; otherwise the client will get the correction that accounts - // for commands that they haven't been sent yet. - diff = real_time - last_physics_correction_time_; - if (diff > g_app_globals->dynamics_sync_time) { - last_physics_correction_time_ = real_time; - SendPhysicsCorrection(true); - } - } - } - out_command_.clear(); -} - -auto GameStream::IsValidScene(Scene* s) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (s != nullptr && s->stream_id() >= 0 - && s->stream_id() < static_cast(scenes_.size()) - && scenes_[s->stream_id()] == s); -} - -auto GameStream::IsValidNode(Node* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(nodes_.size()) - && nodes_[n->stream_id()] == n); -} - -auto GameStream::IsValidTexture(Texture* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(textures_.size()) - && textures_[n->stream_id()] == n); -} - -auto GameStream::IsValidModel(Model* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(models_.size()) - && models_[n->stream_id()] == n); -} - -auto GameStream::IsValidSound(Sound* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(sounds_.size()) - && sounds_[n->stream_id()] == n); -} - -auto GameStream::IsValidData(Data* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(datas_.size()) - && datas_[n->stream_id()] == n); -} - -auto GameStream::IsValidCollideModel(CollideModel* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(collide_models_.size()) - && collide_models_[n->stream_id()] == n); -} - -auto GameStream::IsValidMaterial(Material* n) -> bool { - if (!host_session_) { - return true; // We don't build lists in this mode so can't verify this. - } - return (n != nullptr && n->stream_id() >= 0 - && n->stream_id() < static_cast(materials_.size()) - && materials_[n->stream_id()] == n); -} - -void GameStream::SetTime(millisecs_t t) { - if (time_ == t) { - return; // Ignore redundants. - } - millisecs_t diff = t - time_; - if (diff > 255) { - Log("Error: GameStream got time diff > 255; not expected."); - diff = 255; - } - WriteCommandInt64(SessionCommand::kBaseTimeStep, diff); - time_ = t; - EndCommand(true); -} - -void GameStream::AddScene(Scene* s) { - // Host mode. - if (host_session_) { - Add(s, &scenes_, &free_indices_scene_graphs_); - s->SetOutputStream(this); - } else { - // Dump mode. - assert(s->stream_id() != -1); - } - WriteCommandInt64_2(SessionCommand::kAddSceneGraph, s->stream_id(), - s->time()); - EndCommand(); -} - -void GameStream::RemoveScene(Scene* s) { - WriteCommandInt64(SessionCommand::kRemoveSceneGraph, s->stream_id()); - Remove(s, &scenes_, &free_indices_scene_graphs_); - EndCommand(); -} - -void GameStream::StepScene(Scene* s) { - assert(IsValidScene(s)); - WriteCommandInt64(SessionCommand::kStepSceneGraph, s->stream_id()); - EndCommand(); -} - -void GameStream::AddNode(Node* n) { - assert(n); - if (host_session_) { - Add(n, &nodes_, &free_indices_nodes_); - } else { - assert(n && n->stream_id() != -1); - } - - Scene* sg = n->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_3(SessionCommand::kAddNode, sg->stream_id(), - n->type()->id(), n->stream_id()); - EndCommand(); -} - -void GameStream::NodeOnCreate(Node* n) { - assert(IsValidNode(n)); - WriteCommandInt64(SessionCommand::kNodeOnCreate, n->stream_id()); - EndCommand(); -} - -void GameStream::SetForegroundScene(Scene* sg) { - assert(IsValidScene(sg)); - WriteCommandInt64(SessionCommand::kSetForegroundSceneGraph, sg->stream_id()); - EndCommand(); -} - -void GameStream::RemoveNode(Node* n) { - assert(IsValidNode(n)); - WriteCommandInt64(SessionCommand::kRemoveNode, n->stream_id()); - Remove(n, &nodes_, &free_indices_nodes_); - EndCommand(); -} - -void GameStream::AddTexture(Texture* t) { - // Register an ID in host mode. - if (host_session_) { - Add(t, &textures_, &free_indices_textures_); - } else { - assert(t && t->stream_id() != -1); - } - Scene* sg = t->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_2(SessionCommand::kAddTexture, sg->stream_id(), - t->stream_id()); - WriteString(t->name()); - EndCommand(); -} - -void GameStream::RemoveTexture(Texture* t) { - assert(IsValidTexture(t)); - WriteCommandInt64(SessionCommand::kRemoveTexture, t->stream_id()); - Remove(t, &textures_, &free_indices_textures_); - EndCommand(); -} - -void GameStream::AddModel(Model* t) { - // Register an ID in host mode. - if (host_session_) { - Add(t, &models_, &free_indices_models_); - } else { - assert(t && t->stream_id() != -1); - } - Scene* sg = t->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_2(SessionCommand::kAddModel, sg->stream_id(), - t->stream_id()); - WriteString(t->name()); - EndCommand(); -} - -void GameStream::RemoveModel(Model* t) { - assert(IsValidModel(t)); - WriteCommandInt64(SessionCommand::kRemoveModel, t->stream_id()); - Remove(t, &models_, &free_indices_models_); - EndCommand(); -} - -void GameStream::AddSound(Sound* t) { - // Register an ID in host mode. - if (host_session_) { - Add(t, &sounds_, &free_indices_sounds_); - } else { - assert(t && t->stream_id() != -1); - } - Scene* sg = t->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_2(SessionCommand::kAddSound, sg->stream_id(), - t->stream_id()); - WriteString(t->name()); - EndCommand(); -} - -void GameStream::RemoveSound(Sound* t) { - assert(IsValidSound(t)); - WriteCommandInt64(SessionCommand::kRemoveSound, t->stream_id()); - Remove(t, &sounds_, &free_indices_sounds_); - EndCommand(); -} - -void GameStream::AddData(Data* t) { - // Register an ID in host mode. - if (host_session_) { - Add(t, &datas_, &free_indices_datas_); - } else { - assert(t && t->stream_id() != -1); - } - Scene* sg = t->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_2(SessionCommand::kAddData, sg->stream_id(), - t->stream_id()); - WriteString(t->name()); - EndCommand(); -} - -void GameStream::RemoveData(Data* t) { - assert(IsValidData(t)); - WriteCommandInt64(SessionCommand::kRemoveData, t->stream_id()); - Remove(t, &datas_, &free_indices_datas_); - EndCommand(); -} - -void GameStream::AddCollideModel(CollideModel* t) { - if (host_session_) { - Add(t, &collide_models_, &free_indices_collide_models_); - } else { - assert(t && t->stream_id() != -1); - } - Scene* sg = t->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_2(SessionCommand::kAddCollideModel, sg->stream_id(), - t->stream_id()); - WriteString(t->name()); - EndCommand(); -} - -void GameStream::RemoveCollideModel(CollideModel* t) { - assert(IsValidCollideModel(t)); - WriteCommandInt64(SessionCommand::kRemoveCollideModel, t->stream_id()); - Remove(t, &collide_models_, &free_indices_collide_models_); - EndCommand(); -} - -void GameStream::AddMaterial(Material* m) { - if (host_session_) { - Add(m, &materials_, &free_indices_materials_); - } else { - assert(m && m->stream_id() != -1); - } - Scene* sg = m->scene(); - assert(IsValidScene(sg)); - WriteCommandInt64_2(SessionCommand::kAddMaterial, sg->stream_id(), - m->stream_id()); - EndCommand(); -} - -void GameStream::RemoveMaterial(Material* m) { - assert(IsValidMaterial(m)); - WriteCommandInt64(SessionCommand::kRemoveMaterial, m->stream_id()); - Remove(m, &materials_, &free_indices_materials_); - EndCommand(); -} - -void GameStream::AddMaterialComponent(Material* m, MaterialComponent* c) { - assert(IsValidMaterial(m)); - auto flattened_size = c->GetFlattenedSize(); - assert(flattened_size > 0 && flattened_size < 10000); - WriteCommandInt64_2(SessionCommand::kAddMaterialComponent, m->stream_id(), - static_cast_check_fit(flattened_size)); - size_t size = out_command_.size(); - out_command_.resize(size + flattened_size); - char* ptr = reinterpret_cast(&out_command_[size]); - char* ptr2 = ptr; - c->Flatten(&ptr2, this); - size_t actual_size = ptr2 - ptr; - if (actual_size != flattened_size) { - throw Exception("Expected flattened_size " + std::to_string(flattened_size) - + " got " + std::to_string(actual_size)); - } - EndCommand(); -} - -void GameStream::ConnectNodeAttribute(Node* src_node, - NodeAttributeUnbound* src_attr, - Node* dst_node, - NodeAttributeUnbound* dst_attr) { - assert(IsValidNode(src_node)); - assert(IsValidNode(dst_node)); - assert(src_attr->node_type() == src_node->type()); - assert(dst_attr->node_type() == dst_node->type()); - if (src_node->scene() != dst_node->scene()) { - throw Exception("Nodes are from different scenes"); - } - assert(src_node->scene() == dst_node->scene()); - WriteCommandInt64_4(SessionCommand::kConnectNodeAttribute, - src_node->stream_id(), src_attr->index(), - dst_node->stream_id(), dst_attr->index()); - EndCommand(); -} - -void GameStream::NodeMessage(Node* node, const char* buffer, size_t size) { - assert(IsValidNode(node)); - BA_PRECONDITION(size > 0 && size < 10000); - WriteCommandInt64_2(SessionCommand::kNodeMessage, node->stream_id(), - static_cast_check_fit(size)); - WriteChars(size, buffer); - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, float val) { - assert(IsValidNode(attr.node)); - WriteCommandInt64_2(SessionCommand::kSetNodeAttrFloat, attr.node->stream_id(), - attr.index()); - WriteFloat(val); - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, int64_t val) { - assert(IsValidNode(attr.node)); - WriteCommandInt64_3(SessionCommand::kSetNodeAttrInt32, attr.node->stream_id(), - attr.index(), val); - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, bool val) { - assert(IsValidNode(attr.node)); - WriteCommandInt64_3(SessionCommand::kSetNodeAttrBool, attr.node->stream_id(), - attr.index(), val); - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - size_t count{vals.size()}; - WriteCommandInt64_3(SessionCommand::kSetNodeAttrFloats, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteFloats(count, vals.data()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - size_t count{vals.size()}; - WriteCommandInt64_3(SessionCommand::kSetNodeAttrInt32s, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteInts64(count, vals.data()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::string& val) { - assert(IsValidNode(attr.node)); - WriteCommandInt64_2(SessionCommand::kSetNodeAttrString, - attr.node->stream_id(), attr.index()); - WriteString(val); - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, Node* val) { - assert(IsValidNode(attr.node)); - if (val) { - assert(IsValidNode(val)); - if (attr.node->scene() != val->scene()) { - throw Exception("nodes are from different scenes"); - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrNode, - attr.node->stream_id(), attr.index(), val->stream_id()); - } else { - WriteCommandInt64_2(SessionCommand::kSetNodeAttrNodeNull, - attr.node->stream_id(), attr.index()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); -#if BA_DEBUG_BUILD - for (auto val : vals) { - assert(IsValidNode(val)); - } -#endif - size_t count{vals.size()}; - std::vector vals_out; - if (count > 0) { - vals_out.resize(count); - Scene* scene = attr.node->scene(); - for (size_t i = 0; i < count; i++) { - if (vals[i]->scene() != scene) { - throw Exception("nodes are from different scenes"); - } - vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); - } - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrNodes, attr.node->stream_id(), - attr.index(), static_cast_check_fit(count)); - if (count > 0) { - WriteInts32(count, vals_out.data()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, Player* val) { - // cout << "SET PLAYER ATTR " << attr.getIndex() << endl; -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - - if (g_buildconfig.debug_build()) { - for (auto val : vals) { - assert(IsValidMaterial(val)); - } - } - - size_t count = vals.size(); - std::vector vals_out; - if (count > 0) { - vals_out.resize(count); - Scene* scene = attr.node->scene(); - for (size_t i = 0; i < count; i++) { - if (vals[i]->scene() != scene) { - throw Exception("material/node are from different scenes"); - } - vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); - } - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrMaterials, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteInts32(count, &(vals_out[0])); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, Texture* val) { - if (val) { - assert(IsValidNode(attr.node)); - assert(IsValidTexture(val)); - if (attr.node->scene() != val->scene()) { - throw Exception("texture/node are from different scenes"); - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrTexture, - attr.node->stream_id(), attr.index(), val->stream_id()); - } else { - WriteCommandInt64_2(SessionCommand::kSetNodeAttrTextureNull, - attr.node->stream_id(), attr.index()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - if (g_buildconfig.debug_build()) { - for (auto val : vals) { - assert(IsValidTexture(val)); - } - } - size_t count{vals.size()}; - std::vector vals_out; - if (count > 0) { - vals_out.resize(count); - Scene* scene{attr.node->scene()}; - for (size_t i = 0; i < count; i++) { - if (vals[i]->scene() != scene) { - throw Exception("texture/node are from different scenes"); - } - vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); - } - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrTextures, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteInts32(count, vals_out.data()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, Sound* val) { - if (val) { - assert(IsValidNode(attr.node)); - assert(IsValidSound(val)); - if (attr.node->scene() != val->scene()) { - throw Exception("sound/node are from different scenes"); - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrSound, - attr.node->stream_id(), attr.index(), val->stream_id()); - } else { - WriteCommandInt64_2(SessionCommand::kSetNodeAttrSoundNull, - attr.node->stream_id(), attr.index()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - if (g_buildconfig.debug_build()) { - for (auto val : vals) { - assert(IsValidSound(val)); - } - } - size_t count{vals.size()}; - std::vector vals_out; - if (count > 0) { - vals_out.resize(count); - Scene* scene = attr.node->scene(); - for (size_t i = 0; i < count; i++) { - if (vals[i]->scene() != scene) { - throw Exception("sound/node are from different scenes"); - } - vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); - } - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrSounds, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteInts32(count, &(vals_out[0])); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, Model* val) { - if (val) { - assert(IsValidNode(attr.node)); - assert(IsValidModel(val)); - if (attr.node->scene() != val->scene()) { - throw Exception("model/node are from different scenes"); - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrModel, - attr.node->stream_id(), attr.index(), val->stream_id()); - } else { - WriteCommandInt64_2(SessionCommand::kSetNodeAttrModelNull, - attr.node->stream_id(), attr.index()); - } - EndCommand(); -} - -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - if (g_buildconfig.debug_build()) { - for (auto val : vals) { - assert(IsValidModel(val)); - } - } - size_t count = vals.size(); - std::vector vals_out; - if (count > 0) { - vals_out.resize(count); - Scene* scene = attr.node->scene(); - for (size_t i = 0; i < count; i++) { - if (vals[i]->scene() != scene) { - throw Exception("model/node are from different scenes"); - } - vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); - } - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrModels, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteInts32(count, &(vals_out[0])); - } - EndCommand(); -} -void GameStream::SetNodeAttr(const NodeAttribute& attr, CollideModel* val) { - if (val) { - assert(IsValidNode(attr.node)); - assert(IsValidCollideModel(val)); - if (attr.node->scene() != val->scene()) { - throw Exception("collide_model/node are from different scenes"); - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrCollideModel, - attr.node->stream_id(), attr.index(), val->stream_id()); - } else { - WriteCommandInt64_2(SessionCommand::kSetNodeAttrCollideModelNull, - attr.node->stream_id(), attr.index()); - } - EndCommand(); -} -void GameStream::SetNodeAttr(const NodeAttribute& attr, - const std::vector& vals) { - assert(IsValidNode(attr.node)); - if (g_buildconfig.debug_build()) { - for (auto val : vals) { - assert(IsValidCollideModel(val)); - } - } - size_t count = vals.size(); - std::vector vals_out; - if (count > 0) { - vals_out.resize(count); - Scene* scene = attr.node->scene(); - for (size_t i = 0; i < count; i++) { - if (vals[i]->scene() != scene) { - throw Exception("collide_model/node are from different scenes"); - } - vals_out[i] = static_cast_check_fit(vals[i]->stream_id()); - } - } - WriteCommandInt64_3(SessionCommand::kSetNodeAttrCollideModels, - attr.node->stream_id(), attr.index(), - static_cast_check_fit(count)); - if (count > 0) { - WriteInts32(count, &(vals_out[0])); - } - EndCommand(); -} - -void GameStream::PlaySoundAtPosition(Sound* sound, float volume, float x, - float y, float z) { - assert(IsValidSound(sound)); - assert(IsValidScene(sound->scene())); - - // FIXME: We shouldn't need to be passing all these as full floats. :-( - WriteCommandInt64(SessionCommand::kPlaySoundAtPosition, sound->stream_id()); - WriteFloat(volume); - WriteFloat(x); - WriteFloat(y); - WriteFloat(z); - EndCommand(); -} - -void GameStream::EmitBGDynamics(const BGDynamicsEmission& e) { - WriteCommandInt64_4(SessionCommand::kEmitBGDynamics, - static_cast(e.emit_type), e.count, - static_cast(e.chunk_type), - static_cast(e.tendril_type)); - float fvals[8]; - fvals[0] = e.position.x; - fvals[1] = e.position.y; - fvals[2] = e.position.z; - fvals[3] = e.velocity.x; - fvals[4] = e.velocity.y; - fvals[5] = e.velocity.z; - fvals[6] = e.scale; - fvals[7] = e.spread; - WriteFloats(8, fvals); - EndCommand(); -} - -void GameStream::PlaySound(Sound* sound, float volume) { - assert(IsValidSound(sound)); - assert(IsValidScene(sound->scene())); - - // FIXME: We shouldn't need to be passing all these as full floats. :-( - WriteCommandInt64(SessionCommand::kPlaySound, sound->stream_id()); - WriteFloat(volume); - EndCommand(); -} - -void GameStream::ScreenMessageTop(const std::string& val, float r, float g, - float b, Texture* texture, - Texture* tint_texture, float tint_r, - float tint_g, float tint_b, float tint2_r, - float tint2_g, float tint2_b) { - assert(IsValidTexture(texture)); - assert(IsValidTexture(tint_texture)); - assert(IsValidScene(texture->scene())); - assert(IsValidScene(tint_texture->scene())); - WriteCommandInt64_2(SessionCommand::kScreenMessageTop, texture->stream_id(), - tint_texture->stream_id()); - WriteString(val); - float f[9]; - f[0] = r; - f[1] = g; - f[2] = b; - f[3] = tint_r; - f[4] = tint_g; - f[5] = tint_b; - f[6] = tint2_r; - f[7] = tint2_g; - f[8] = tint2_b; - WriteFloats(9, f); - EndCommand(); -} - -void GameStream::ScreenMessageBottom(const std::string& val, float r, float g, - float b) { - WriteCommand(SessionCommand::kScreenMessageBottom); - WriteString(val); - float color[3]; - color[0] = r; - color[1] = g; - color[2] = b; - WriteFloats(3, color); - EndCommand(); -} - -auto GameStream::GetSoundID(Sound* s) -> int64_t { - assert(IsValidSound(s)); - return s->stream_id(); -} - -auto GameStream::GetMaterialID(Material* m) -> int64_t { - assert(IsValidMaterial(m)); - return m->stream_id(); -} - -void GameStream::OnClientConnected(ConnectionToClient* c) { - // Sanity check - abort if its on either of our lists already. - for (auto& connections_to_client : connections_to_clients_) { - if (connections_to_client == c) { - Log("Error: GameStream::OnClientConnected() got duplicate connection."); - return; - } - } - for (auto& i : connections_to_clients_ignored_) { - if (i == c) { - Log("Error: GameStream::OnClientConnected() got duplicate connection."); - return; - } - } - - { - // First thing, we need to flush all pending session-commands to clients. - // The host-session's current state is the result of having already run - // these commands locally, so if we leave them on the list while 'restoring' - // the new client to our state they'll get essentially double-applied, which - // is bad. (ie: a delete-node command will get called but the node will - // already be gone) - Flush(); - - connections_to_clients_.push_back(c); - - // We create a temporary output stream just for the purpose of building - // a giant session-commands message to reconstruct everything in our - // host-session in its current form. - GameStream out(nullptr, false); - - // Ask the host-session that we came from to dump it's complete state. - host_session_->DumpFullState(&out); - - // Grab the message that's been built up. - // If its not empty, send it to the client. - std::vector out_message = out.GetOutMessage(); - if (!out_message.empty()) { - c->SendReliableMessage(out_message); - } - - // Also send a correction packet to sync up all our dynamics. - // (technically could do this *just* for the new client) - SendPhysicsCorrection(false); - } -} - -void GameStream::OnClientDisconnected(ConnectionToClient* c) { - // Search for it on either our ignored or regular lists. - for (auto i = connections_to_clients_.begin(); - i != connections_to_clients_.end(); i++) { - if (*i == c) { - connections_to_clients_.erase(i); - return; - } - } - for (auto i = connections_to_clients_ignored_.begin(); - i != connections_to_clients_ignored_.end(); i++) { - if (*i == c) { - connections_to_clients_ignored_.erase(i); - return; - } - } - Log("Error: GameStream::OnClientDisconnected() called for connection not on " - "lists"); -} - -} // namespace ballistica diff --git a/src/ballistica/game/host_activity.cc b/src/ballistica/game/host_activity.cc deleted file mode 100644 index ce4a1f58..00000000 --- a/src/ballistica/game/host_activity.cc +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/host_activity.h" - -#include - -#include "ballistica/dynamics/material/material.h" -#include "ballistica/game/game_stream.h" -#include "ballistica/game/player.h" -#include "ballistica/game/session/host_session.h" -#include "ballistica/generic/lambda_runnable.h" -#include "ballistica/generic/timer.h" -#include "ballistica/input/device/input_device.h" -#include "ballistica/media/component/collide_model.h" -#include "ballistica/media/component/data.h" -#include "ballistica/media/component/model.h" -#include "ballistica/media/component/texture.h" -#include "ballistica/python/python.h" -#include "ballistica/python/python_context_call.h" -#include "ballistica/python/python_sys.h" -#include "ballistica/scene/node/globals_node.h" -#include "ballistica/scene/node/node_type.h" -#include "ballistica/scene/scene.h" - -namespace ballistica { - -HostActivity::HostActivity(HostSession* host_session) { - // Store a link to the HostSession and add ourself to it. - host_session_ = host_session; - - // Create our game timer - gets called whenever game should step. - step_scene_timer_ = - base_timers_.NewTimer(base_time_, kGameStepMilliseconds, 0, -1, - NewLambdaRunnable([this] { StepScene(); })); - SetGameSpeed(1.0f); - { - ScopedSetContext cp(this); // So scene picks us up as context. - scene_ = Object::New(0); - - // If there's an output stream, add to it. - if (GameStream* out = host_session->GetGameStream()) { - out->AddScene(scene_.get()); - } - } -} - -HostActivity::~HostActivity() { - shutting_down_ = true; - - // Put the scene in shut-down mode before we start killing stuff. - // (this generates warnings, suppresses messages, etc) - scene_->set_shutting_down(true); - - // Clear out all python calls registered in our context. - // (should wipe out refs to our activity and prevent them from running without - // a valid activity context) - for (auto&& i : python_calls_) { - if (i.exists()) { - i->MarkDead(); - } - } - - // Mark all our media dead to clear it out of our output-stream cleanly - for (auto&& i : textures_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - for (auto&& i : models_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - for (auto&& i : sounds_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - for (auto&& i : collide_models_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - for (auto&& i : materials_) { - if (i.exists()) { - i->MarkDead(); - } - } - - // Clear our timers and scene; this should wipe out any remaining refs to our - // python activity, allowing it to die. - base_timers_.Clear(); - sim_timers_.Clear(); - scene_.Clear(); - - // Report outstanding calls. There shouldn't be any at this point. Actually it - // turns out there's generally 1; whichever call was responsible for killing - // this activity will still be in progress.. so let's report on 2 or more I - // guess. -#if BA_DEBUG_BUILD - PruneDeadRefs(&python_calls_); - if (python_calls_.size() > 1) { - std::string s = "WARNING: " + std::to_string(python_calls_.size()) - + " live PythonContextCalls at shutdown for " - + "HostActivity" + " (1 call is expected):"; - int count = 1; - for (auto& python_call : python_calls_) - s += "\n " + std::to_string(count++) + ": " - + (*python_call).GetObjectDescription(); - Log(s); - } -#endif // BA_DEBUG_BUILD -} - -auto HostActivity::GetGameStream() const -> GameStream* { - if (!host_session_.exists()) return nullptr; - return host_session_->GetGameStream(); -} - -void HostActivity::StepScene() { - int cycle_count = 1; - if (host_session_->benchmark_type() == BenchmarkType::kCPU) { - cycle_count = 100; - } - - for (int cycle = 0; cycle < cycle_count; ++cycle) { - assert(InGameThread()); - - // Clear our player-positions for this step. - // FIXME: Move this to scene and/or player node. - assert(host_session_.exists()); - for (auto&& player : host_session_->players()) { - assert(player.exists()); - player->set_have_position(false); - } - - // Run our sim-time timers. - sim_timers_.Run(scene()->time()); - - // Send die-messages/etc to out-of-bounds stuff. - HandleOutOfBoundsNodes(); - - scene()->Step(); - } -} - -void HostActivity::RegisterCall(PythonContextCall* call) { - assert(call); - python_calls_.emplace_back(call); - - // If we're shutting down, just kill the call immediately. - // (we turn all of our calls to no-ops as we shut down) - if (shutting_down_) { - Log("WARNING: adding call to expired activity; call will not function: " - + call->GetObjectDescription()); - call->MarkDead(); - } -} - -void HostActivity::start() { - if (_started) { - Log("Error: Start called twice for activity."); - } - _started = true; -} - -auto HostActivity::GetAsHostActivity() -> HostActivity* { return this; } - -auto HostActivity::NewMaterial(const std::string& name) - -> Object::Ref { - if (shutting_down_) { - throw Exception("can't create materials during activity shutdown"); - } - - auto m(Object::New(name, scene())); - materials_.emplace_back(m); - return m; -} - -auto HostActivity::GetTexture(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during activity shutdown"); - } - return Media::GetMedia(&textures_, name, scene()); -} - -auto HostActivity::GetSound(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during activity shutdown"); - } - return Media::GetMedia(&sounds_, name, scene()); -} - -auto HostActivity::GetData(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during activity shutdown"); - } - return Media::GetMedia(&datas_, name, scene()); -} - -auto HostActivity::GetModel(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during activity shutdown"); - } - return Media::GetMedia(&models_, name, scene()); -} - -auto HostActivity::GetCollideModel(const std::string& name) - -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during activity shutdown"); - } - return Media::GetMedia(&collide_models_, name, scene()); -} - -void HostActivity::SetPaused(bool val) { - if (paused_ == val) { - return; - } - paused_ = val; - UpdateStepTimerLength(); -} - -void HostActivity::SetGameSpeed(float speed) { - if (speed == game_speed_) { - return; - } - assert(speed >= 0.0f); - game_speed_ = speed; - UpdateStepTimerLength(); -} - -void HostActivity::UpdateStepTimerLength() { - if (game_speed_ == 0.0f || paused_) { - step_scene_timer_->SetLength(-1, true, base_time_); - } else { - step_scene_timer_->SetLength( - std::max(1, static_cast( - round(static_cast(kGameStepMilliseconds) - / (game_speed_ * g_game->debug_speed_mult())))), - true, base_time_); - } -} - -void HostActivity::HandleOutOfBoundsNodes() { - if (scene()->out_of_bounds_nodes().empty()) { - out_of_bounds_in_a_row_ = 0; - return; - } - - // Make sure someone's handling our out-of-bounds messages. - out_of_bounds_in_a_row_++; - if (out_of_bounds_in_a_row_ > 100) { - Log("Warning: 100 consecutive out-of-bounds messages sent." - " They are probably not being handled properly"); - int j = 0; - for (auto&& i : scene()->out_of_bounds_nodes()) { - j++; - Node* n = i.get(); - if (n) { - std::string dstr; - PyObject* delegate = n->GetDelegate(); - if (delegate) { - dstr = PythonRef(delegate, PythonRef::kAcquire).Str(); - } - Log(" node #" + std::to_string(j) + ": type='" + n->type()->name() - + "' addr=" + Utils::PtrToString(i.get()) + " name='" + n->label() - + "' delegate=" + dstr); - } - } - out_of_bounds_in_a_row_ = 0; - } - - // Send out-of-bounds messages to newly out-of-bounds nodes. - for (auto&& i : scene()->out_of_bounds_nodes()) { - Node* n = i.get(); - if (n) { - n->DispatchOutOfBoundsMessage(); - } - } -} - -void HostActivity::RegisterPyActivity(PyObject* pyActivityObj) { - assert(pyActivityObj && pyActivityObj != Py_None); - assert(!py_activity_weak_ref_.exists()); - - // Store a python weak-ref to this activity. - py_activity_weak_ref_.Steal(PyWeakref_NewRef(pyActivityObj, nullptr)); -} - -auto HostActivity::GetPyActivity() const -> PyObject* { - PyObject* obj = py_activity_weak_ref_.get(); - if (!obj) return Py_None; - return PyWeakref_GetObject(obj); -} - -auto HostActivity::GetHostSession() -> HostSession* { - return host_session_.get(); -} - -auto HostActivity::GetMutableScene() -> Scene* { - Scene* sg = scene_.get(); - assert(sg); - return sg; -} - -void HostActivity::SetIsForeground(bool val) { - // If we're foreground, set our scene as foreground. - Scene* sg = scene(); - if (val && sg) { - // Set it locally. - g_game->SetForegroundScene(sg); - - // Also push it to clients. - if (GameStream* out = GetGameStream()) { - out->SetForegroundScene(scene_.get()); - } - } -} - -auto HostActivity::globals_node() const -> GlobalsNode* { - return globals_node_.get(); -} - -auto HostActivity::NewSimTimer(millisecs_t length, bool repeat, - const Object::Ref& runnable) -> int { - if (shutting_down_) { - BA_LOG_PYTHON_TRACE_ONCE( - "WARNING: Creating game timer during host-activity shutdown"); - return 123; // Dummy. - } - if (length == 0 && repeat) { - throw Exception("Can't add game-timer with length 0 and repeat on"); - } - if (length < 0) { - throw Exception("Timer length cannot be < 0 (got " + std::to_string(length) - + ")"); - } - - int offset = 0; - Timer* t = sim_timers_.NewTimer(scene()->time(), length, offset, - repeat ? -1 : 0, runnable); - return t->id(); -} - -auto HostActivity::NewBaseTimer(millisecs_t length, bool repeat, - const Object::Ref& runnable) -> int { - if (shutting_down_) { - BA_LOG_PYTHON_TRACE_ONCE( - "WARNING: Creating session-time timer during host-activity shutdown"); - return 123; // dummy... - } - if (length == 0 && repeat) { - throw Exception("Can't add session-time timer with length 0 and repeat on"); - } - if (length < 0) { - throw Exception("Timer length cannot be < 0"); - } - - int offset = 0; - Timer* t = base_timers_.NewTimer(base_time_, length, offset, repeat ? -1 : 0, - runnable); - return t->id(); -} - -void HostActivity::DeleteSimTimer(int timer_id) { - assert(InGameThread()); - if (shutting_down_) return; - sim_timers_.DeleteTimer(timer_id); -} - -void HostActivity::DeleteBaseTimer(int timer_id) { - assert(InGameThread()); - if (shutting_down_) return; - base_timers_.DeleteTimer(timer_id); -} - -auto HostActivity::Update(millisecs_t time_advance) -> millisecs_t { - assert(InGameThread()); - - // We can be killed at any time, so let's keep an eye out for that. - WeakRef test_ref(this); - assert(test_ref.exists()); - - // If we haven't been told to start yet, don't do anything more. - if (!_started) { - return 1000; - } - - // Advance base time by the specified amount, stopping at all timers along the - // way. - millisecs_t target_base_time = base_time_ + time_advance; - while (!base_timers_.empty() - && (base_time_ + base_timers_.GetTimeToNextExpire(base_time_) - <= target_base_time)) { - base_time_ += base_timers_.GetTimeToNextExpire(base_time_); - base_timers_.Run(base_time_); - if (!test_ref.exists()) { - return 1000; // The last timer run might have killed us. - } - } - base_time_ = target_base_time; - - // Periodically prune various dead refs. - if (base_time_ > next_prune_time_) { - PruneDeadMapRefs(&textures_); - PruneDeadMapRefs(&sounds_); - PruneDeadMapRefs(&collide_models_); - PruneDeadMapRefs(&models_); - PruneDeadRefs(&materials_); - PruneDeadRefs(&python_calls_); - next_prune_time_ = base_time_ + 5000; - } - - // Return the time until the next timer goes off. - return base_timers_.empty() ? 1000 - : base_timers_.GetTimeToNextExpire(base_time_); -} - -void HostActivity::ScreenSizeChanged() { scene()->ScreenSizeChanged(); } -void HostActivity::LanguageChanged() { scene()->LanguageChanged(); } -void HostActivity::DebugSpeedMultChanged() { UpdateStepTimerLength(); } -void HostActivity::GraphicsQualityChanged(GraphicsQuality q) { - scene()->GraphicsQualityChanged(q); -} - -void HostActivity::Draw(FrameDef* frame_def) { - if (!_started) return; - scene()->Draw(frame_def); -} - -void HostActivity::DumpFullState(GameStream* out) { - // Add our scene. - if (scene_.exists()) { - scene_->Dump(out); - } - - // Before doing any nodes, we need to create all materials. - // (but *not* their components, which may reference the nodes that we haven't - // made yet) - for (auto&& i : materials_) { - if (Material* m = i.get()) { - out->AddMaterial(m); - } - } - - // Add our media. - for (auto&& i : textures_) { - if (Texture* t = i.second.get()) { - out->AddTexture(t); - } - } - for (auto&& i : sounds_) { - if (Sound* s = i.second.get()) { - out->AddSound(s); - } - } - for (auto&& i : models_) { - if (Model* s = i.second.get()) { - out->AddModel(s); - } - } - for (auto&& i : collide_models_) { - if (CollideModel* m = i.second.get()) { - out->AddCollideModel(m); - } - } - - // Add scene's nodes. - if (scene_.exists()) { - scene_->DumpNodes(out); - } - - // Ok, now we can fill out our materials since nodes/etc they reference - // exists. - for (auto&& i : materials_) { - if (Material* m = i.get()) { - m->DumpComponents(out); - } - } -} - -auto HostActivity::NewTimer(TimeType timetype, TimerMedium length, bool repeat, - const Object::Ref& runnable) -> int { - // Make sure the runnable passed in is reference-managed already. - // (we may not add an initial reference ourself) - assert(runnable->is_valid_refcounted_object()); - - // We currently support game and base timers. - switch (timetype) { - case TimeType::kSim: - return NewSimTimer(length, repeat, runnable); - case TimeType::kBase: - return NewBaseTimer(length, repeat, runnable); - default: - // Fall back to default for descriptive error otherwise. - return ContextTarget::NewTimer(timetype, length, repeat, runnable); - } -} - -void HostActivity::DeleteTimer(TimeType timetype, int timer_id) { - switch (timetype) { - case TimeType::kSim: - DeleteSimTimer(timer_id); - break; - case TimeType::kBase: - DeleteBaseTimer(timer_id); - break; - default: - // Fall back to default for descriptive error otherwise. - ContextTarget::DeleteTimer(timetype, timer_id); - break; - } -} - -auto HostActivity::GetTime(TimeType timetype) -> millisecs_t { - switch (timetype) { - case TimeType::kSim: - return scene()->time(); - case TimeType::kBase: - return base_time(); - default: - // Fall back to default for descriptive error otherwise. - return ContextTarget::GetTime(timetype); - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/host_activity.h b/src/ballistica/game/host_activity.h index c8c9f530..36820f3c 100644 --- a/src/ballistica/game/host_activity.h +++ b/src/ballistica/game/host_activity.h @@ -63,7 +63,7 @@ class HostActivity : public ContextTarget { auto globals_node() const -> GlobalsNode*; void SetPaused(bool val); auto paused() const -> bool { return paused_; } - void setAllowKickIdlePlayers(bool val) { allow_kick_idle_players_ = val; } + void set_allow_kick_idle_players(bool val) { allow_kick_idle_players_ = val; } auto getAllowKickIdlePlayers() const -> bool { return allow_kick_idle_players_; } diff --git a/src/ballistica/game/player.cc b/src/ballistica/game/player.cc deleted file mode 100644 index 2afdd229..00000000 --- a/src/ballistica/game/player.cc +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/player.h" - -#include - -#include "ballistica/game/host_activity.h" -#include "ballistica/game/session/host_session.h" -#include "ballistica/generic/utils.h" -#include "ballistica/input/device/joystick.h" -#include "ballistica/python/class/python_class_session_player.h" -#include "ballistica/python/python.h" -#include "ballistica/python/python_context_call.h" -#include "ballistica/scene/node/node_attribute.h" -#include "ballistica/scene/node/node_type.h" - -namespace ballistica { - -Player::Player(int id_in, HostSession* host_session) - : id_(id_in), creation_time_(GetRealTime()), host_session_(host_session) { - assert(host_session); - assert(InGameThread()); -} - -Player::~Player() { - assert(InGameThread()); - - // If we have an input-device attached to us, detach it. - InputDevice* input_device = input_device_.get(); - if (input_device) { - input_device->DetachFromPlayer(); - } - - // Release our ref to ourself if we have one. - if (py_ref_) { - Py_DECREF(py_ref_); - } -} - -auto Player::GetName(bool full, bool icon) const -> std::string { - std::string n = full ? full_name_ : name_; - - // Quasi-hacky: if they ask for no icon, strip the first char off our string - // if its in the custom-use-range. - if (!icon) { - std::vector uni = Utils::UnicodeFromUTF8(n, "3f94f4f"); - if (!uni.empty() && uni[0] >= 0xE000 && uni[0] <= 0xF8FF) { - uni.erase(uni.begin()); - } - return Utils::UTF8FromUnicode(uni); - } else { - return n; - } -} - -auto Player::GetHostActivity() const -> HostActivity* { - return host_activity_.get(); -} - -void Player::SetHostActivity(HostActivity* a) { - assert(InGameThread()); - - // Make sure we get pulled out of one activity before being added to another. - if (a && in_activity_) { - std::string old_name = - host_activity_.exists() - ? PythonRef(host_activity_->GetPyActivity(), PythonRef::kAcquire) - .Str() - : ""; - std::string new_name = - PythonRef(a->GetPyActivity(), PythonRef::kAcquire).Str(); - BA_LOG_PYTHON_TRACE_ONCE( - "Player::SetHostActivity() called when already in an activity (old=" - + old_name + ", new=" + new_name + ")"); - } else if (!a && !in_activity_) { - BA_LOG_PYTHON_TRACE_ONCE( - "Player::SetHostActivity() called with nullptr when not in an " - "activity"); - } - host_activity_ = a; - in_activity_ = (a != nullptr); -} - -void Player::SetPosition(const Vector3f& position) { - position_ = position; - have_position_ = true; -} - -void Player::ResetInput() { - // Hold a ref to ourself while clearing this to make sure - // we don't die midway as a result of freeing something. - Object::Ref ref(this); - calls_.clear(); - left_held_ = right_held_ = up_held_ = down_held_ = have_position_ = false; -} - -void Player::SetPyTeam(PyObject* team) { - if (team != nullptr && team != Py_None) { - // We store a weak-ref to this. - py_team_weak_ref_.Steal(PyWeakref_NewRef(team, nullptr)); - } else { - py_team_weak_ref_.Release(); - } -} - -auto Player::GetPyTeam() -> PyObject* { - PyObject* obj = py_team_weak_ref_.get(); - if (!obj) { - return Py_None; - } - return PyWeakref_GetObject(obj); -} - -void Player::SetPyCharacter(PyObject* character) { - if (character != nullptr && character != Py_None) { - py_character_.Acquire(character); - } else { - py_character_.Release(); - } -} - -auto Player::GetPyCharacter() -> PyObject* { - return py_character_.exists() ? py_character_.get() : Py_None; -} - -void Player::SetPyColor(PyObject* c) { py_color_.Acquire(c); } -auto Player::GetPyColor() -> PyObject* { - return py_color_.exists() ? py_color_.get() : Py_None; -} - -void Player::SetPyHighlight(PyObject* c) { py_highlight_.Acquire(c); } -auto Player::GetPyHighlight() -> PyObject* { - return py_highlight_.exists() ? py_highlight_.get() : Py_None; -} - -void Player::SetPyActivityPlayer(PyObject* c) { py_activityplayer_.Acquire(c); } -auto Player::GetPyActivityPlayer() -> PyObject* { - return py_activityplayer_.exists() ? py_activityplayer_.get() : Py_None; -} - -auto Player::GetPyRef(bool new_ref) -> PyObject* { - assert(InGameThread()); - if (py_ref_ == nullptr) { - py_ref_ = PythonClassSessionPlayer::Create(this); - } - if (new_ref) { - Py_INCREF(py_ref_); - } - return py_ref_; -} - -void Player::AssignInputCall(InputType type, PyObject* call_obj) { - assert(InGameThread()); - assert(static_cast(type) >= 0 - && static_cast(type) < static_cast(InputType::kLast)); - - // Special case: if they're assigning hold-position-press or - // hold-position-release, or any direction events, we add in a hold-position - // press/release event before we deliver any other events.. that way newly - // created stuff is informed of the hold state and doesn't wrongly think they - // should start moving. - switch (type) { - case InputType::kHoldPositionPress: - case InputType::kHoldPositionRelease: - case InputType::kLeftPress: - case InputType::kLeftRelease: - case InputType::kRightPress: - case InputType::kUpPress: - case InputType::kUpRelease: - case InputType::kDownPress: - case InputType::kDownRelease: - case InputType::kUpDown: - case InputType::kLeftRight: { - send_hold_state_ = true; - break; - } - default: - break; - } - if (call_obj) { - calls_[static_cast(type)] = Object::New(call_obj); - } else { - calls_[static_cast(type)].Clear(); - } - - // If they assigned l/r, immediately send an update for its current value. - if (type == InputType::kLeftRight) { - RunInput(type, lr_state_); - } - - // Same for up/down. - if (type == InputType::kUpDown) { - RunInput(type, ud_state_); - } - - // Same for run. - if (type == InputType::kRun) { - RunInput(type, run_state_); - } - - // Same for fly. - if (type == InputType::kFlyPress && fly_held_) { - RunInput(type); - } -} - -void Player::RunInput(InputType type, float value) { - assert(InGameThread()); - - const float threshold = kJoystickDiscreteThresholdFloat; - - // Most input commands cause us to reset the player's time-out - // there are a few exceptions though - very small analog values - // get ignored since they can come through without user intervention. - bool reset_time_out = true; - if (type == InputType::kLeftRight || type == InputType::kUpDown) { - if (std::abs(value) < 0.3f) { - reset_time_out = false; - } - } - if (type == InputType::kRun) { - if (value < 0.3f) { - reset_time_out = false; - } - } - - // Also ignore hold-position stuff since it can come through without user - // interaction. - if ((type == InputType::kHoldPositionPress) - || (type == InputType::kHoldPositionRelease)) - reset_time_out = false; - - if (reset_time_out) { - time_out_ = BA_PLAYER_TIME_OUT; - } - - // Keep track of the hold-position state that comes through here. - // any-time hold position buttons are re-assigned, we subsequently - // re-send the current hold-state so whatever its driving starts out correctly - // held if need be. - if (type == InputType::kHoldPositionPress) { - hold_position_ = true; - } else if (type == InputType::kHoldPositionRelease) { - hold_position_ = false; - } else if (type == InputType::kFlyPress) { - fly_held_ = true; - } else if (type == InputType::kFlyRelease) { - fly_held_ = false; - } - - // If we were supposed to deliver hold-state, go ahead and do that first. - if (send_hold_state_) { - send_hold_state_ = false; - if (hold_position_) { - RunInput(InputType::kHoldPositionPress); - } else { - RunInput(InputType::kHoldPositionRelease); - } - } - - // Let's make our life simpler by converting held-position-joystick-events.. - { - // We need to store these since we might look at them during a hold-position - // event when we don't have their originating events available. - if (type == InputType::kLeftRight) { - lr_state_ = value; - } - if (type == InputType::kUpDown) { - ud_state_ = value; - } - if (type == InputType::kRun) { - run_state_ = value; - } - - // Special input commands - keep track of left/right and up/down positions - // so we can deliver simple "leftUp", "leftDown", etc type of events - // in addition to the standard absolute leftRight positions, etc. - if (type == InputType::kLeftRight || type == InputType::kHoldPositionPress - || type == InputType::kHoldPositionRelease) { - float arg = lr_state_; - if (hold_position_) { - arg = 0.0f; // Throttle is off. - } - if (left_held_) { - if (arg > -threshold) { - left_held_ = false; - RunInput(InputType::kLeftRelease); - } - } else if (right_held_) { - if (arg < threshold) { - right_held_ = false; - RunInput(InputType::kRightRelease); - } - } else { - if (arg >= threshold) { - if (!left_held_ && !up_held_ && !down_held_) { - right_held_ = true; - RunInput(InputType::kRightPress); - } - } else if (arg <= -threshold) { - if (!right_held_ && !up_held_ && !down_held_) { - left_held_ = true; - RunInput(InputType::kLeftPress); - } - } - } - } - if (type == InputType::kUpDown || type == InputType::kHoldPositionPress - || type == InputType::kHoldPositionRelease) { - float arg = ud_state_; - if (hold_position_) arg = 0.0f; // throttle is off; - if (up_held_) { - if (arg < threshold) { - up_held_ = false; - RunInput(InputType::kUpRelease); - } - } else if (down_held_) { - if (arg > -threshold) { - down_held_ = false; - RunInput(InputType::kDownRelease); - } - } else { - if (arg <= -threshold) { - if (!left_held_ && !right_held_ && !up_held_) { - down_held_ = true; - RunInput(InputType::kDownPress); - } - } else if (arg >= threshold) { - if (!left_held_ && !up_held_ && !right_held_) { - up_held_ = true; - RunInput(InputType::kUpPress); - } - } - } - } - } - - auto j = calls_.find(static_cast(type)); - if (j != calls_.end() && j->second.exists()) { - if (type == InputType::kRun) { - PythonRef args( - Py_BuildValue("(f)", std::min(1.0f, std::max(0.0f, value))), - PythonRef::kSteal); - j->second->Run(args.get()); - } else if (type == InputType::kLeftRight || type == InputType::kUpDown) { - PythonRef args( - Py_BuildValue("(f)", std::min(1.0f, std::max(-1.0f, value))), - PythonRef::kSteal); - j->second->Run(args.get()); - } else { - j->second->Run(); - } - } -} - -auto Player::GetHostSession() const -> HostSession* { - return host_session_.get(); -} - -void Player::SetName(const std::string& name, const std::string& full_name, - bool is_real) { - assert(InGameThread()); - HostSession* host_session = GetHostSession(); - BA_PRECONDITION(host_session); - name_is_real_ = is_real; - name_ = host_session->GetUnusedPlayerName(this, name); - full_name_ = full_name; - - // If we're already in the game and our name is changing, we need to update - // the roster. - if (accepted_) { - g_game->UpdateGameRoster(); - } -} - -void Player::InputCommand(InputType type, float value) { - assert(InGameThread()); - switch (type) { - case InputType::kUpDown: - case InputType::kLeftRight: - case InputType::kRun: - RunInput(type, value); - break; - // case InputType::kReset: - // Log("Error: FIXME: player-input-reset command unimplemented"); - // break; - default: - RunInput(type); - break; - } -} - -void Player::SetInputDevice(InputDevice* input_device) { - input_device_ = input_device; -} - -auto Player::GetPublicAccountID() const -> std::string { - assert(InGameThread()); - if (input_device_.exists()) { - return input_device_->GetPublicAccountID(); - } - return ""; -} - -void Player::SetIcon(const std::string& tex_name, - const std::string& tint_tex_name, - const std::vector& tint_color, - const std::vector& tint2_color) { - assert(tint_color.size() == 3); - assert(tint2_color.size() == 3); - icon_tex_name_ = tex_name; - icon_tint_tex_name_ = tint_tex_name; - icon_tint_color_ = tint_color; - icon_tint2_color_ = tint2_color; - icon_set_ = true; -} - -} // namespace ballistica diff --git a/src/ballistica/game/player_spec.cc b/src/ballistica/game/player_spec.cc deleted file mode 100644 index ecdb7462..00000000 --- a/src/ballistica/game/player_spec.cc +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/player_spec.h" - -#include - -#include "ballistica/app/app_globals.h" -#include "ballistica/game/account.h" -#include "ballistica/generic/json.h" -#include "ballistica/generic/utils.h" -#include "ballistica/platform/platform.h" - -namespace ballistica { - -PlayerSpec::PlayerSpec() : account_type_(AccountType::kInvalid) {} - -PlayerSpec::PlayerSpec(const std::string& s) { - cJSON* root_obj = cJSON_Parse(s.c_str()); - bool success = false; - if (root_obj) { - cJSON* name_obj = cJSON_GetObjectItem(root_obj, "n"); - cJSON* short_name_obj = cJSON_GetObjectItem(root_obj, "sn"); - cJSON* account_obj = cJSON_GetObjectItem(root_obj, "a"); - if (name_obj && short_name_obj && account_obj) { - name_ = Utils::GetValidUTF8(name_obj->valuestring, "psps"); - short_name_ = Utils::GetValidUTF8(short_name_obj->valuestring, "psps2"); - - // Account type may technically be something we don't recognize, - // but that's ok.. it'll just be 'invalid' to us in that case - account_type_ = Account::AccountTypeFromString(account_obj->valuestring); - success = true; - } - cJSON_Delete(root_obj); - } - if (!success) { - Log("Error creating PlayerSpec from string: '" + s + "'"); - name_ = ""; - short_name_ = ""; - account_type_ = AccountType::kInvalid; - } -} - -auto PlayerSpec::GetDisplayString() const -> std::string { - return Account::AccountTypeToIconString(account_type_) + name_; -} - -auto PlayerSpec::GetShortName() const -> std::string { - if (short_name_.empty()) { - return name_; - } - return short_name_; -} - -auto PlayerSpec::operator==(const PlayerSpec& spec) const -> bool { - // NOTE: need to add account ID in here once that's available - return (spec.name_ == name_ && spec.short_name_ == short_name_ - && spec.account_type_ == account_type_); -} - -auto PlayerSpec::GetSpecString() const -> std::string { - cJSON* root; - root = cJSON_CreateObject(); - cJSON_AddStringToObject(root, "n", name_.c_str()); - cJSON_AddStringToObject(root, "a", - Account::AccountTypeToString(account_type_).c_str()); - cJSON_AddStringToObject(root, "sn", short_name_.c_str()); - char* out = cJSON_PrintUnformatted(root); - std::string out_s = out; - free(out); - cJSON_Delete(root); - - // We should never allow ourself to have all this add up to more than 256. - assert(out_s.size() < 256); - - return out_s; -} - -auto PlayerSpec::GetAccountPlayerSpec() -> PlayerSpec { - PlayerSpec spec; - if (g_account->GetAccountState() == AccountState::kSignedIn) { - spec.account_type_ = g_app_globals->account_type; - spec.name_ = - Utils::GetValidUTF8(g_account->GetAccountName().c_str(), "bsgaps"); - } else { - spec.name_ = - Utils::GetValidUTF8(g_platform->GetDeviceName().c_str(), "bsgaps2"); - } - if (spec.name_.size() > 100) { - // FIXME should perhaps clamp this in unicode space - Log("account name size too long: '" + spec.name_ + "'"); - spec.name_.resize(100); - spec.name_ = Utils::GetValidUTF8(spec.name_.c_str(), "bsgaps3"); - } - return spec; -} - -auto PlayerSpec::GetDummyPlayerSpec(const std::string& name) -> PlayerSpec { - PlayerSpec spec; - spec.name_ = Utils::GetValidUTF8(name.c_str(), "bsgdps1"); - if (spec.name_.size() > 100) { - // FIXME should perhaps clamp this in unicode space - Log("dummy player spec name too long: '" + spec.name_ + "'"); - spec.name_.resize(100); - spec.name_ = Utils::GetValidUTF8(spec.name_.c_str(), "bsgdps2"); - } - return spec; -} - -} // namespace ballistica diff --git a/src/ballistica/game/session/client_session.cc b/src/ballistica/game/session/client_session.cc deleted file mode 100644 index d0013f3c..00000000 --- a/src/ballistica/game/session/client_session.cc +++ /dev/null @@ -1,1070 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/session/client_session.h" - -#include "ballistica/app/app_globals.h" -#include "ballistica/audio/audio.h" -#include "ballistica/dynamics/bg/bg_dynamics.h" -#include "ballistica/dynamics/material/material.h" -#include "ballistica/dynamics/material/material_action.h" -#include "ballistica/dynamics/material/material_component.h" -#include "ballistica/dynamics/material/material_condition_node.h" -#include "ballistica/dynamics/rigid_body.h" -#include "ballistica/graphics/graphics.h" -#include "ballistica/media/component/collide_model.h" -#include "ballistica/media/component/model.h" -#include "ballistica/media/component/texture.h" -#include "ballistica/networking/networking.h" -#include "ballistica/python/python.h" -#include "ballistica/scene/node/node_attribute.h" -#include "ballistica/scene/node/node_type.h" -#include "ballistica/scene/scene.h" - -namespace ballistica { - -// How many buckets we keep around for calculating max-lag-spikes. -const int kDelayBufferBuckets = 20; - -ClientSession::ClientSession() - : base_time_(0), - least_buffered_count_list_(kDelayBufferBuckets, 0), - most_buffered_count_list_(kDelayBufferBuckets, 0), - adjust_counter_(0), - buffer_count_list_index_(0), - steps_on_list_(0), - current_cmd_ptr_(nullptr), - shutting_down_(false) { - ClearSessionObjs(); -} - -void ClientSession::Reset(bool rewind) { - assert(!shutting_down_); - OnReset(rewind); -} - -void ClientSession::OnReset(bool rewind) { - ClearSessionObjs(); - target_base_time_ = base_time_ = 0; -} - -void ClientSession::ClearSessionObjs() { - scenes_.clear(); - nodes_.clear(); - textures_.clear(); - models_.clear(); - sounds_.clear(); - collide_models_.clear(); - materials_.clear(); - commands_pending_.clear(); - commands_.clear(); - steps_on_list_ = 0; -} - -auto ClientSession::DoesFillScreen() const -> bool { - // Look for any scene that has something that covers the background. - for (const auto& scene : scenes_) { - if ((scene.exists()) && (*scene).has_bg_cover()) { - return true; - } - } - return false; -} - -void ClientSession::Draw(FrameDef* f) { - // Just go through and draw all of our scenes. - for (auto&& i : scenes_) { - // NOTE - here we draw scenes in the order they were created, but - // in a host-session we draw session first followed by activities - // (that should be the same order in both cases, but just something to keep - // in mind...) - if (i.exists()) { - i->Draw(f); - } - } -} - -auto ClientSession::ReadByte() -> uint8_t { - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 1) { - throw Exception("state read error"); - } - return *(current_cmd_ptr_++); -} - -auto ClientSession::ReadInt32() -> int32_t { - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 4) { - throw Exception("state read error"); - } - int32_t val; - memcpy(&val, current_cmd_ptr_, sizeof(val)); - current_cmd_ptr_ += 4; - return val; -} - -auto ClientSession::ReadFloat() -> float { - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 4) { - throw Exception("state read error"); - } - float val; - memcpy(&val, current_cmd_ptr_, 4); - current_cmd_ptr_ += 4; - return val; -} - -void ClientSession::ReadFloats(int count, float* vals) { - int size = 4 * count; - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(vals, current_cmd_ptr_, static_cast(size)); - current_cmd_ptr_ += size; -} - -void ClientSession::ReadInt32s(int count, int32_t* vals) { - int size = 4 * count; - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(vals, current_cmd_ptr_, static_cast(size)); - current_cmd_ptr_ += size; -} - -void ClientSession::ReadChars(int count, char* vals) { - int size = count; - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(vals, current_cmd_ptr_, static_cast(size)); - current_cmd_ptr_ += size; -} - -void ClientSession::ReadInt32_3(int32_t* vals) { - size_t size = 3 * 4; - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(vals, current_cmd_ptr_, size); - current_cmd_ptr_ += size; -} - -void ClientSession::ReadInt32_4(int32_t* vals) { - size_t size = 4 * 4; - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(vals, current_cmd_ptr_, size); - current_cmd_ptr_ += size; -} - -void ClientSession::ReadInt32_2(int32_t* vals) { - size_t size = 2 * 4; - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(vals, current_cmd_ptr_, size); - current_cmd_ptr_ += size; -} - -auto ClientSession::ReadString() -> std::string { - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - 4) { - throw Exception("state read error"); - } - int32_t size; - memcpy(&size, current_cmd_ptr_, sizeof(size)); - current_cmd_ptr_ += 4; - std::vector buffer(static_cast(size + 1)); - if (current_cmd_ptr_ > &(current_cmd_[0]) + current_cmd_.size() - size) { - throw Exception("state read error"); - } - memcpy(&(buffer[0]), current_cmd_ptr_, static_cast(size)); - current_cmd_ptr_ += size; - return &(buffer[0]); -} - -void ClientSession::Update(int time_advance) { - if (shutting_down_) { - return; - } - - // Allow replays to modulate speed, etc. - time_advance = GetActualTimeAdvance(time_advance); - - target_base_time_ += static_cast(time_advance) * correction_; - - try { - // Read and run all events up to our target time. - while (base_time_ < target_base_time_) { - // If we need to do something explicit to keep messages flowing in. - // (informing the replay thread to feed us more, etc). - FetchMessages(); - - // If we've got another command on the list, pull it and run it. - if (!commands_.empty()) { - // Debugging: if this was previously pointed at a buffer, make sure we - // went exactly to the end. -#if BA_DEBUG_BUILD - if (current_cmd_ptr_ != nullptr) { - if (current_cmd_ptr_ != &(current_cmd_[0]) + current_cmd_.size()) { - Log("SIZE ERROR FOR CMD " - + std::to_string(static_cast(current_cmd_[0])) - + " expected " + std::to_string(current_cmd_.size()) + " got " - + std::to_string(current_cmd_ptr_ - &(current_cmd_[0]))); - } - } - assert(current_cmd_ptr_ == current_cmd_.data() + current_cmd_.size()); -#endif - - current_cmd_ = commands_.front(); - commands_.pop_front(); - current_cmd_ptr_ = &(current_cmd_[0]); - } else { - // Any time we run out of commands we immediately pull our target time - // back to where we currently are at. We want to stay *behind* the - // "buffering line". - target_base_time_ = base_time_; - OnCommandBufferUnderrun(); - return; - } - - auto cmd = static_cast(ReadByte()); - - switch (cmd) { - case SessionCommand::kBaseTimeStep: { - int32_t stepsize = ReadInt32(); - BA_PRECONDITION(stepsize > 0); - if (stepsize > 10000) { - throw Exception( - "got abnormally large stepsize; probably a corrupt stream"); - } - steps_on_list_ -= stepsize; - BA_PRECONDITION(steps_on_list_ >= 0); - base_time_ += stepsize; - break; - } - case SessionCommand::kDynamicsCorrection: { - bool blend = current_cmd_[1]; - uint32_t offset = 2; - uint16_t node_count; - memcpy(&node_count, current_cmd_.data() + offset, sizeof(node_count)); - offset += 2; - for (int i = 0; i < node_count; i++) { - uint32_t node_id; - memcpy(&node_id, current_cmd_.data() + offset, sizeof(node_id)); - offset += 4; - int body_count = current_cmd_[offset++]; - Node* n = - (node_id < nodes_.size()) ? nodes_[node_id].get() : nullptr; - for (int j = 0; j < body_count; j++) { - int bodyid = current_cmd_[offset++]; - uint16_t body_data_len; - memcpy(&body_data_len, current_cmd_.data() + offset, - sizeof(body_data_len)); - RigidBody* b = n ? n->GetRigidBody(bodyid) : nullptr; - offset += 2; - const char* p1 = reinterpret_cast(&(current_cmd_[offset])); - const char* p2 = p1; - if (b) { - dBodyID body = b->body(); - const dReal* p = dBodyGetPosition(body); - float old_x = p[0]; - float old_y = p[1]; - float old_z = p[2]; - b->ExtractFull(&p2); - if (p2 - p1 != body_data_len) - throw Exception("Invalid rbd correction data"); - if (blend) { - b->AddBlendOffset(old_x - p[0], old_y - p[1], old_z - p[2]); - } - } - offset += body_data_len; - if (offset > current_cmd_.size()) { - throw Exception("Invalid rbd correction data"); - } - } - if (offset > current_cmd_.size()) - throw Exception("Invalid rbd correction data"); - // extract custom per-node data - uint16_t custom_data_len; - memcpy(&custom_data_len, current_cmd_.data() + offset, - sizeof(custom_data_len)); - offset += 2; - if (custom_data_len != 0) { - std::vector data(custom_data_len); - memcpy(&(data[0]), &(current_cmd_[offset]), custom_data_len); - if (n) n->ApplyResyncData(data); - offset += custom_data_len; - } - if (offset > current_cmd_.size()) { - throw Exception("Invalid rbd correction data"); - } - } - if (offset != current_cmd_.size()) { - throw Exception("invalid rbd correction data"); - } - current_cmd_ptr_ = &(current_cmd_[0]) + offset; - - break; - } - case SessionCommand::kEndOfFile: { - // EOF can happen anytime if they run out of disk space/etc. - // We should expect any state. - Reset(true); - break; - } - case SessionCommand::kAddSceneGraph: { - int32_t cmdvals[2]; - ReadInt32_2(cmdvals); - int32_t id = cmdvals[0]; - millisecs_t starttime = cmdvals[1]; - if (id < 0 || id > 100) { - throw Exception("invalid scene id"); - } - if (static_cast(scenes_.size()) < (id + 1)) { - scenes_.resize(static_cast(id) + 1); - } - assert(!scenes_[id].exists()); - scenes_[id] = Object::New(starttime); - scenes_[id]->stream_id_ = id; - break; - } - case SessionCommand::kRemoveSceneGraph: { - int32_t id = ReadInt32(); - GetScene(id); // Make sure it's valid. - scenes_[id].Clear(); - break; - } - case SessionCommand::kStepSceneGraph: { - int32_t val = ReadInt32(); - Scene* sg = GetScene(val); - sg->Step(); - break; - } - case SessionCommand::kAddNode: { - int32_t vals[3]; // scene-id, nodetype-id, node-id - ReadInt32_3(vals); - Scene* scene = GetScene(vals[0]); - assert(g_app_globals != nullptr); - if (vals[1] < 0 - || vals[1] >= static_cast( - g_app_globals->node_types_by_id.size())) { - throw Exception("invalid node type id"); - } - - NodeType* node_type = g_app_globals->node_types_by_id[vals[1]]; - - // Fail if we get a ridiculous number of nodes. - // FIXME: should enforce this on the server side too. - int id = vals[2]; - if (id < 0 || id > 10000) throw Exception("invalid node id"); - if (static_cast(nodes_.size()) < (id + 1)) { - nodes_.resize(static_cast(id) + 1); - } - assert(!nodes_[id].exists()); - { - ScopedSetContext _cp(this); - nodes_[id] = scene->NewNode(node_type->name(), "", nullptr); - nodes_[id]->set_stream_id(id); - } - break; - } - case SessionCommand::kSetForegroundSceneGraph: { - Scene* scene = GetScene(ReadInt32()); - g_game->SetForegroundScene(scene); - break; - } - case SessionCommand::kNodeMessage: { - int32_t vals[2]; - ReadInt32_2(vals); - Node* n = GetNode(vals[0]); - int32_t msg_size = vals[1]; - if (msg_size < 1 || msg_size > 10000) { - throw Exception("invalid message"); - } - std::vector buffer(static_cast(msg_size)); - ReadChars(msg_size, &buffer[0]); - n->DispatchNodeMessage(&buffer[0]); - break; - } - case SessionCommand::kConnectNodeAttribute: { - int32_t vals[4]; - ReadInt32_4(vals); - Node* src_node = GetNode(vals[0]); - Node* dst_node = GetNode(vals[2]); - NodeAttributeUnbound* src_attr = - src_node->type()->GetAttribute(static_cast(vals[1])); - NodeAttributeUnbound* dst_attr = - dst_node->type()->GetAttribute(static_cast(vals[3])); - src_node->ConnectAttribute(src_attr, dst_node, dst_attr); - break; - } - case SessionCommand::kNodeOnCreate: { - Node* n = GetNode(ReadInt32()); - n->OnCreate(); - break; - } - case SessionCommand::kAddMaterial: { - int32_t vals[2]; // scene-id, material-id - ReadInt32_2(vals); - Scene* scene = GetScene(vals[0]); - // Fail if we get a ridiculous number of materials. - // FIXME: should enforce this on the server side too. - int id = vals[1]; - if (vals[1] < 0 || vals[1] >= 1000) { - throw Exception("invalid material id"); - } - if (static_cast(materials_.size()) < (id + 1)) - materials_.resize(static_cast(id) + 1); - assert(!materials_[id].exists()); - materials_[id] = Object::New("", scene); - materials_[id]->stream_id_ = id; - break; - } - case SessionCommand::kRemoveMaterial: { - int id = ReadInt32(); - GetMaterial(id); // make sure its valid - materials_[id].Clear(); - break; - } - case SessionCommand::kAddMaterialComponent: { - int32_t cmdvals[2]; - ReadInt32_2(cmdvals); - Material* m = GetMaterial(cmdvals[0]); - int component_size = cmdvals[1]; - if (component_size < 1 || component_size > 10000) { - throw Exception("invalid component"); - } - std::vector buffer(static_cast(component_size)); - ReadChars(component_size, &buffer[0]); - auto c(Object::New()); - const char* ptr1 = &buffer[0]; - const char* ptr2 = ptr1; - c->Restore(&ptr2, this); - BA_PRECONDITION(ptr2 - ptr1 == component_size); - m->AddComponent(c); - break; - } - case SessionCommand::kAddTexture: { - int32_t vals[2]; // scene-id, texture-id - ReadInt32_2(vals); - std::string name = ReadString(); - Scene* scene = GetScene(vals[0]); - // Fail if we get a ridiculous number of textures. - // FIXME: Should enforce this on the server side too. - int id = vals[1]; - if (vals[1] < 0 || vals[1] >= 1000) { - throw Exception("invalid texture id"); - } - if (static_cast(textures_.size()) < (id + 1)) { - textures_.resize(static_cast(id) + 1); - } - assert(!textures_[id].exists()); - textures_[id] = Object::New(name, scene); - textures_[id]->stream_id_ = id; - break; - } - case SessionCommand::kRemoveTexture: { - int id = ReadInt32(); - GetTexture(id); // make sure its valid - textures_[id].Clear(); - break; - } - case SessionCommand::kAddModel: { - int32_t vals[2]; // scene-id, model-id - ReadInt32_2(vals); - std::string name = ReadString(); - Scene* scene = GetScene(vals[0]); - - // Fail if we get a ridiculous number of models. - // FIXME: Should enforce this on the server side too. - int id = vals[1]; - if (vals[1] < 0 || vals[1] >= 1000) { - throw Exception("invalid model id"); - } - if (static_cast(models_.size()) < (id + 1)) { - models_.resize(static_cast(id) + 1); - } - assert(!models_[id].exists()); - models_[id] = Object::New(name, scene); - models_[id]->stream_id_ = id; - break; - } - case SessionCommand::kRemoveModel: { - int id = ReadInt32(); - GetModel(id); // make sure its valid - models_[id].Clear(); - break; - } - case SessionCommand::kAddSound: { - int32_t vals[2]; // scene-id, sound-id - ReadInt32_2(vals); - std::string name = ReadString(); - Scene* scene = GetScene(vals[0]); - // Fail if we get a ridiculous number of sounds. - // FIXME: Should enforce this on the server side too. - int id = vals[1]; - if (vals[1] < 0 || vals[1] >= 1000) { - throw Exception("invalid sound id"); - } - if (static_cast(sounds_.size()) < (id + 1)) { - sounds_.resize(static_cast(id) + 1); - } - assert(!sounds_[id].exists()); - sounds_[id] = Object::New(name, scene); - sounds_[id]->stream_id_ = id; - break; - } - case SessionCommand::kRemoveSound: { - int id = ReadInt32(); - GetSound(id); // make sure its valid - sounds_[id].Clear(); - break; - } - case SessionCommand::kAddCollideModel: { - int32_t vals[2]; // scene-id, collide_model-id - ReadInt32_2(vals); - std::string name = ReadString(); - Scene* scene = GetScene(vals[0]); - // Fail if we get a ridiculous number of collide_models. - // FIXME: Should enforce this on the server side too. - int id = vals[1]; - if (vals[1] < 0 || vals[1] >= 1000) { - throw Exception("invalid collide_model id"); - } - if (static_cast(collide_models_.size()) < (id + 1)) { - collide_models_.resize(static_cast(id) + 1); - } - assert(!collide_models_[id].exists()); - collide_models_[id] = Object::New(name, scene); - collide_models_[id]->stream_id_ = id; - break; - } - case SessionCommand::kRemoveCollideModel: { - int id = ReadInt32(); - GetCollideModel(id); // make sure its valid - collide_models_[id].Clear(); - break; - } - case SessionCommand::kRemoveNode: { - int id = ReadInt32(); - Node* n = GetNode(id); - n->scene()->DeleteNode(n); - assert(!nodes_[id].exists()); - break; - } - case SessionCommand::kSetNodeAttrFloat: { - int vals[2]; - ReadInt32_2(vals); - GetNode(vals[0])->GetAttribute(vals[1]).Set(ReadFloat()); - break; - } - case SessionCommand::kSetNodeAttrInt32: { - int32_t vals[3]; - ReadInt32_3(vals); - - // Note; we currently deal in 64 bit ints locally but read/write 32 - // bit over the wire. - GetNode(vals[0])->GetAttribute(vals[1]).Set( - static_cast(vals[2])); - break; - } - case SessionCommand::kSetNodeAttrBool: { - int vals[3]; - ReadInt32_3(vals); - GetNode(vals[0])->GetAttribute(vals[1]).Set( - static_cast(vals[2])); - break; - } - case SessionCommand::kSetNodeAttrFloats: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals(static_cast(count)); - if (count > 0) { - ReadFloats(count, &(vals[0])); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kSetNodeAttrInt32s: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals[0])); - } - // Note: we currently deal in 64 bit ints locally but read/write 32 - // bit over the wire. Convert. - std::vector vals64(static_cast(count)); - for (int i = 0; i < count; i++) { - vals64[i] = vals[i]; - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals64); - break; - } - case SessionCommand::kSetNodeAttrString: { - int vals[2]; - ReadInt32_2(vals); - GetNode(vals[0])->GetAttribute(vals[1]).Set(ReadString()); - break; - } - case SessionCommand::kSetNodeAttrNode: { - int vals[3]; - ReadInt32_3(vals); - GetNode(vals[0])->GetAttribute(vals[1]).Set(GetNode(vals[2])); - break; - } - case SessionCommand::kSetNodeAttrNodeNull: { - int cmdvals[2]; - ReadInt32_2(cmdvals); - Node* val = nullptr; - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrTextureNull: { - int cmdvals[2]; - ReadInt32_2(cmdvals); - Texture* val = nullptr; - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrSoundNull: { - int cmdvals[2]; - ReadInt32_2(cmdvals); - Sound* val = nullptr; - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrModelNull: { - int cmdvals[2]; - ReadInt32_2(cmdvals); - Model* val = nullptr; - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrCollideModelNull: { - int cmdvals[2]; - ReadInt32_2(cmdvals); - CollideModel* val = nullptr; - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrNodes: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals_in(static_cast(count)); - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals_in[0])); - } - for (int i = 0; i < count; i++) { - vals[i] = GetNode(vals_in[i]); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kSetNodeAttrTexture: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - Texture* val = GetTexture(cmdvals[2]); - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrTextures: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals_in(static_cast(count)); - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals_in[0])); - } - for (int i = 0; i < count; i++) { - vals[i] = GetTexture(vals_in[i]); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kSetNodeAttrSound: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - Sound* val = GetSound(cmdvals[2]); - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrSounds: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals_in(static_cast(count)); - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals_in[0])); - } - for (int i = 0; i < count; i++) { - vals[i] = GetSound(vals_in[i]); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kSetNodeAttrModel: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - Model* val = GetModel(cmdvals[2]); - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrModels: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals_in(static_cast(count)); - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals_in[0])); - } - for (int i = 0; i < count; i++) { - vals[i] = GetModel(vals_in[i]); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kSetNodeAttrCollideModel: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - CollideModel* val = GetCollideModel(cmdvals[2]); - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(val); - break; - } - case SessionCommand::kSetNodeAttrCollideModels: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals_in(static_cast(count)); - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals_in[0])); - } - for (int i = 0; i < count; i++) { - vals[i] = GetCollideModel(vals_in[i]); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kSetNodeAttrMaterials: { - int cmdvals[3]; - ReadInt32_3(cmdvals); - int count = cmdvals[2]; - if (count < 0 || count > 1000) { - throw Exception("invalid array size (" + std::to_string(count) - + ")"); - } - std::vector vals_in(static_cast(count)); - std::vector vals(static_cast(count)); - if (count > 0) { - ReadInt32s(count, &(vals_in[0])); - } - for (int i = 0; i < count; i++) { - vals[i] = GetMaterial(vals_in[i]); - } - GetNode(cmdvals[0])->GetAttribute(cmdvals[1]).Set(vals); - break; - } - case SessionCommand::kPlaySound: { - Sound* sound = GetSound(ReadInt32()); - float volume = ReadFloat(); - g_audio->PlaySound(sound->GetSoundData(), volume); - break; - } - case SessionCommand::kScreenMessageBottom: { - std::string val = ReadString(); - Vector3f color{}; - ReadFloats(3, color.v); - ScreenMessage(val, color); - break; - } - case SessionCommand::kScreenMessageTop: { - int cmdvals[2]; - ReadInt32_2(cmdvals); - Texture* texture = GetTexture(cmdvals[0]); - Texture* tint_texture = GetTexture(cmdvals[1]); - std::string s = ReadString(); - float f[9]; - ReadFloats(9, f); - g_graphics->AddScreenMessage( - s, Vector3f(f[0], f[1], f[2]), true, texture, tint_texture, - Vector3f(f[3], f[4], f[5]), Vector3f(f[6], f[7], f[8])); - break; - } - case SessionCommand::kPlaySoundAtPosition: { - Sound* sound = GetSound(ReadInt32()); - float volume = ReadFloat(); - float x = ReadFloat(); - float y = ReadFloat(); - float z = ReadFloat(); - g_audio->PlaySoundAtPosition(sound->GetSoundData(), volume, x, y, z); - break; - } - case SessionCommand::kEmitBGDynamics: { -#if !BA_HEADLESS_BUILD - BGDynamicsEmission e; -#endif - int cmdvals[4]; - ReadInt32_4(cmdvals); -#if !BA_HEADLESS_BUILD - e.emit_type = (BGDynamicsEmitType)cmdvals[0]; - e.count = cmdvals[1]; - e.chunk_type = (BGDynamicsChunkType)cmdvals[2]; - e.tendril_type = (BGDynamicsTendrilType)cmdvals[3]; -#endif - float vals[8]; - ReadFloats(8, vals); -#if !BA_HEADLESS_BUILD - e.position.x = vals[0]; - e.position.y = vals[1]; - e.position.z = vals[2]; - e.velocity.x = vals[3]; - e.velocity.y = vals[4]; - e.velocity.z = vals[5]; - e.scale = vals[6]; - e.spread = vals[7]; - g_bg_dynamics->Emit(e); -#endif - break; - } - default: - throw Exception("unrecognized stream command: " - + std::to_string(static_cast(cmd))); - } - } - } catch (const std::exception& e) { - Error(e.what()); - } -} // NOLINT (yes this is too long) - -ClientSession::~ClientSession() = default; - -void ClientSession::ScreenSizeChanged() { - // Let all our scenes know. - for (auto&& i : scenes_) { - if (Scene* sg = i.get()) { - sg->ScreenSizeChanged(); - } - } -} - -void ClientSession::LanguageChanged() { - // Let all our scenes know. - for (auto&& i : scenes_) { - if (Scene* sg = i.get()) { - sg->LanguageChanged(); - } - } -} - -auto ClientSession::GetScene(int id) const -> Scene* { - if (id < 0 || id >= static_cast(scenes_.size())) { - throw Exception("Invalid scene id"); - } - Scene* sg = scenes_[id].get(); - if (!sg) { - throw Exception("Invalid scene id"); - } - return sg; -} -auto ClientSession::GetNode(int id) const -> Node* { - if (id < 0 || id >= static_cast(nodes_.size())) { - throw Exception("Invalid node (out of range)"); - } - Node* n = nodes_[id].get(); - if (!n) { - throw Exception("Invalid node id (empty slot)"); - } - return n; -} -auto ClientSession::GetMaterial(int id) const -> Material* { - if (id < 0 || id >= static_cast(materials_.size())) { - throw Exception("Invalid material (out of range)"); - } - Material* n = materials_[id].get(); - if (!n) { - throw Exception("Invalid material id (empty slot)"); - } - return n; -} -auto ClientSession::GetTexture(int id) const -> Texture* { - if (id < 0 || id >= static_cast(textures_.size())) { - throw Exception("Invalid texture (out of range)"); - } - Texture* n = textures_[id].get(); - if (!n) { - throw Exception("Invalid texture id (empty slot)"); - } - return n; -} -auto ClientSession::GetModel(int id) const -> Model* { - if (id < 0 || id >= static_cast(models_.size())) { - throw Exception("Invalid model (out of range)"); - } - Model* n = models_[id].get(); - if (!n) { - throw Exception("Invalid model id (empty slot)"); - } - return n; -} -auto ClientSession::GetSound(int id) const -> Sound* { - if (id < 0 || id >= static_cast(sounds_.size())) { - throw Exception("Invalid sound (out of range)"); - } - Sound* n = sounds_[id].get(); - if (!n) { - throw Exception("Invalid sound id (empty slot)"); - } - return n; -} -auto ClientSession::GetCollideModel(int id) const -> CollideModel* { - if (id < 0 || id >= static_cast(collide_models_.size())) { - throw Exception("Invalid collide_model (out of range)"); - } - CollideModel* n = collide_models_[id].get(); - if (!n) { - throw Exception("Invalid collide_model id (empty slot)"); - } - return n; -} - -void ClientSession::Error(const std::string& description) { - Log("ERROR: client session error: " + description); - End(); -} - -void ClientSession::End() { - if (shutting_down_) return; - shutting_down_ = true; - g_python->PushObjCall(Python::ObjID::kLaunchMainMenuSessionCall); -} - -void ClientSession::HandleSessionMessage(const std::vector& buffer) { - assert(InGameThread()); - - BA_PRECONDITION(!buffer.empty()); - - switch (buffer[0]) { - case BA_MESSAGE_SESSION_RESET: { - // Hmmm; been a while since I wrote this, but wondering why reset isn't - // just a session-command. (Do we not want it added to replays?...) - Reset(false); - break; - } - - case BA_MESSAGE_SESSION_COMMANDS: { - // This is simply 16 bit length followed by command up to the end of the - // packet. Break it apart and feed each command to the client session. - uint32_t offset = 1; - std::vector subBuffer; - while (true) { - uint16_t size; - memcpy(&size, &(buffer[offset]), 2); - if (offset + size > buffer.size()) { - Error("invalid state message"); - return; - } - subBuffer.resize(size); - memcpy(&(subBuffer[0]), &(buffer[offset + 2]), subBuffer.size()); - AddCommand(subBuffer); - offset += 2 + size; // move to next command - if (offset == buffer.size()) { - // lets also use this opportunity to graph our command-buffer size for - // network debugging.. if (NetGraph *graph = - // g_graphics->GetClientSessionStepBufferGraph()) { - // graph->addSample(GetRealTime(), steps_on_list_); - // } - - break; - } - } - break; - } - - case BA_MESSAGE_SESSION_DYNAMICS_CORRECTION: { - // Just drop this in the game's command-stream verbatim, except switch its - // state-ID to a command-ID. - std::vector bufferOut = buffer; - bufferOut[0] = static_cast(SessionCommand::kDynamicsCorrection); - AddCommand(bufferOut); - break; - } - - default: - throw Exception("ClientSession::HandleSessionMessage " + ObjToString(this) - + "got unrecognized message : " - + std::to_string(static_cast(buffer[0])) - + " of size " + std::to_string(buffer.size())); - break; - } -} - -// Add a single command in. -void ClientSession::AddCommand(const std::vector& command) { - // If this is a time-step command, we can dump everything we've been building - // up onto the list to be chewed through by the interpreter (we don't want to - // add things until we have the *entire* step so we don't wind up rendering - // things halfway through some change, etc). - commands_pending_.push_back(command); - if (!command.empty()) { - if (command[0] == static_cast(SessionCommand::kBaseTimeStep)) { - // Keep a tally of how much stepped time we've built up. - steps_on_list_ += command[1]; - for (auto&& i : commands_pending_) { - commands_.push_back(i); - } - commands_pending_.clear(); - } - } -} - -auto ClientSession::GetForegroundContext() -> Context { return Context(this); } - -void ClientSession::GetCorrectionMessages( - bool blend, std::vector >* messages) { - std::vector message; - for (auto&& i : scenes_) { - if (Scene* sg = i.get()) { - message = sg->GetCorrectionMessage(blend); - // A correction packet of size 4 is empty; ignore it. - if (message.size() > 4) { - messages->push_back(message); - } - } - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/session/host_session.cc b/src/ballistica/game/session/host_session.cc deleted file mode 100644 index 914beba7..00000000 --- a/src/ballistica/game/session/host_session.cc +++ /dev/null @@ -1,765 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/session/host_session.h" - -#include "ballistica/core/context.h" -#include "ballistica/game/game_stream.h" -#include "ballistica/game/host_activity.h" -#include "ballistica/game/player.h" -#include "ballistica/generic/lambda_runnable.h" -#include "ballistica/generic/timer.h" -#include "ballistica/graphics/graphics.h" -#include "ballistica/input/device/input_device.h" -#include "ballistica/media/component/data.h" -#include "ballistica/media/component/model.h" -#include "ballistica/media/component/sound.h" -#include "ballistica/media/component/texture.h" -#include "ballistica/python/python.h" -#include "ballistica/python/python_command.h" -#include "ballistica/python/python_context_call.h" -#include "ballistica/python/python_sys.h" -#include "ballistica/scene/scene.h" - -namespace ballistica { - -HostSession::HostSession(PyObject* session_type_obj) - : last_kick_idle_players_decrement_time_(GetRealTime()) { - assert(g_game); - assert(InGameThread()); - assert(session_type_obj != nullptr); - - ScopedSetContext cp(this); - - // FIXME: Should be an attr of the session class, not hard-coded. - is_main_menu_ = - static_cast(strstr(Python::ObjToString(session_type_obj).c_str(), - "bastd.mainmenu.MainMenuSession")); - // Log("MAIN MENU? " + std::to_string(is_main_menu())); - - kick_idle_players_ = g_game->kick_idle_players(); - - // Create a timer to step our session scene. - step_scene_timer_ = - base_timers_.NewTimer(base_time_, kGameStepMilliseconds, 0, -1, - NewLambdaRunnable([this] { StepScene(); })); - - // Set up our output-stream, which will go to a replay and/or the network. - // We don't dump to a replay if we're doing the main menu; that replay - // would be boring. - bool do_replay = !is_main_menu_; - // Log("DO REPLAY? " + std::to_string(do_replay)); - - // At the moment headless-server don't write replays. -#if BA_HEADLESS_BUILD - do_replay = false; -#endif // BA_HEADLESS_BUILD - output_stream_ = Object::New(this, do_replay); - - // Make a scene for our session-level nodes, etc. - scene_ = Object::New(0); - if (output_stream_.exists()) { - output_stream_->AddScene(scene_.get()); - } - - // Fade in from our current blackness. - g_graphics->FadeScreen(true, 250, nullptr); - - // Start by showing the progress bar instead of hitching. - g_graphics->EnableProgressBar(true); - - // Now's a good time to run garbage collection; there should be pretty much - // no game stuff to speak of in existence (provided the last session went - // down peacefully). - g_python->obj(Python::ObjID::kGarbageCollectCall).Call(); - - // Instantiate our python Session instance. - PythonRef obj; - PythonRef session_type(session_type_obj, PythonRef::kAcquire); - { - Python::ScopedCallLabel label("Session instantiation"); - obj = session_type.Call(); - } - if (!obj.exists()) { - throw Exception("Error creating game session: '" + session_type.Str() - + "'"); - } - - // The session python object should have called - // _ba.register_session() in its constructor to set session_py_obj_. - if (session_py_obj_ != obj) { - throw Exception("session not set up correctly"); - } - - // Lastly, keep the python layer fed with our latest player count in case - // it is updating the master-server with our current/max player counts. - g_game->SetPublicPartyPlayerCount(static_cast(players_.size())); -} - -auto HostSession::GetHostSession() -> HostSession* { return this; } - -void HostSession::DestroyHostActivity(HostActivity* a) { - BA_PRECONDITION(a); - BA_PRECONDITION(a->GetHostSession() == this); - if (a == foreground_host_activity_.get()) { - foreground_host_activity_.Clear(); - } - - // Clear it from our activities list if its still on there. - for (auto i = host_activities_.begin(); i < host_activities_.end(); i++) { - if (i->get() == a) { - host_activities_.erase(i); - return; - } - } - - // The only reason it wouldn't be there should be because the activity is - // dying due our clearing of the list in our destructor; make sure that's - // the case. - assert(shutting_down_); -} - -auto HostSession::GetMutableScene() -> Scene* { - assert(scene_.exists()); - return scene_.get(); -} - -void HostSession::DebugSpeedMultChanged() { - // FIXME - should we progress our own scene faster/slower depending on - // this too? Is there really a need to? - - // Let all our activities know. - for (auto&& i : host_activities_) { - i->DebugSpeedMultChanged(); - } -} - -void HostSession::ScreenSizeChanged() { - // Let our internal scene know. - scene()->ScreenSizeChanged(); - - // Also let all our activities know. - for (auto&& i : host_activities_) { - i->ScreenSizeChanged(); - } -} - -void HostSession::LanguageChanged() { - // Let our internal scene know. - scene()->LanguageChanged(); - - // Also let all our activities know. - for (auto&& i : host_activities_) { - i->LanguageChanged(); - } -} - -void HostSession::GraphicsQualityChanged(GraphicsQuality q) { - // Let our internal scene know. - scene()->GraphicsQualityChanged(q); - - // Let all our activities know. - for (auto&& i : host_activities_) { - i->GraphicsQualityChanged(q); - } -} - -auto HostSession::DoesFillScreen() const -> bool { - // FIXME not necessarily the case. - return true; -} - -void HostSession::Draw(FrameDef* f) { - // First draw our session scene. - scene()->Draw(f); - - // Let all our activities draw their own scenes/etc. - for (auto&& i : host_activities_) { - i->Draw(f); - } -} - -auto HostSession::NewTimer(TimerMedium length, bool repeat, - const Object::Ref& runnable) -> int { - if (shutting_down_) { - BA_LOG_PYTHON_TRACE_ONCE( - "WARNING: Creating game timer during host-session shutdown"); - return 123; // dummy... - } - if (length == 0 && repeat) { - throw Exception("Can't add game-timer with length 0 and repeat on"); - } - if (length < 0) { - throw Exception("Timer length cannot be < 0 (got " + std::to_string(length) - + ")"); - } - int offset = 0; - Timer* t = sim_timers_.NewTimer(scene()->time(), length, offset, - repeat ? -1 : 0, runnable); - return t->id(); -} - -void HostSession::DeleteTimer(int timer_id) { - assert(InGameThread()); - if (shutting_down_) return; - sim_timers_.DeleteTimer(timer_id); -} - -auto HostSession::GetSound(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during session shutdown"); - } - return Media::GetMedia(&sounds_, name, scene()); -} - -auto HostSession::GetData(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during session shutdown"); - } - return Media::GetMedia(&datas_, name, scene()); -} - -auto HostSession::GetTexture(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load assets during session shutdown"); - } - return Media::GetMedia(&textures_, name, scene()); -} -auto HostSession::GetModel(const std::string& name) -> Object::Ref { - if (shutting_down_) { - throw Exception("can't load media during session shutdown"); - } - return Media::GetMedia(&models_, name, scene()); -} - -auto HostSession::GetForegroundContext() -> Context { - HostActivity* a = foreground_host_activity_.get(); - if (a) { - return Context(a); - } - return Context(this); -} - -void HostSession::RequestPlayer(InputDevice* device) { - assert(InGameThread()); - - // Ignore if we have no python session obj. - if (!GetSessionPyObj()) { - Log("Error: HostSession::RequestPlayer() called w/no session_py_obj_."); - return; - } - - // Need to at least temporarily create and attach to a player for passing to - // the callback. - int player_id = next_player_id_++; - auto player(Object::New(player_id, this)); - players_.push_back(player); - device->AttachToLocalPlayer(player.get()); - - // Ask the python layer to accept/deny this guy. - bool accept; - { - // Set the session as context. - ScopedSetContext cp(this); - accept = static_cast( - session_py_obj_.GetAttr("_request_player") - .Call(PythonRef(Py_BuildValue("(O)", player->BorrowPyRef()), - PythonRef::kSteal)) - .ValueAsInt()); - if (accept) { - player->set_accepted(true); - } else { - RemovePlayer(player.get()); - } - } - - // If he was accepted, update our game roster with the new info. - if (accept) { - g_game->UpdateGameRoster(); - } - - // Lastly, keep the python layer fed with our latest player count in case it - // is updating the master-server with our current/max player counts. - g_game->SetPublicPartyPlayerCount(static_cast(players_.size())); -} - -void HostSession::RemovePlayer(Player* player) { - assert(player); - - for (auto i = players_.begin(); i != players_.end(); ++i) { - if (i->get() == player) { - // Grab a ref to keep the player alive, pull him off the list, then call - // his leaving callback. - Object::Ref player2 = *i; - players_.erase(i); - - // Only make the callback for this player if they were accepted. - if (player2->accepted()) { - IssuePlayerLeft(player2.get()); - } - - // Update our game roster with the departure. - g_game->UpdateGameRoster(); - - // Lastly, keep the python layer fed with our latest player count in case - // it is updating the master-server with our current/max player counts. - g_game->SetPublicPartyPlayerCount(static_cast(players_.size())); - - return; - } - } - BA_LOG_ERROR_TRACE("Player not found in HostSession::RemovePlayer()"); -} - -void HostSession::IssuePlayerLeft(Player* player) { - assert(player); - assert(InGameThread()); - - try { - if (GetSessionPyObj()) { - if (player) { - // Make sure we're the context for session callbacks. - ScopedSetContext cp(this); - Python::ScopedCallLabel label("Session on_player_leave"); - session_py_obj_.GetAttr("on_player_leave") - .Call(PythonRef(Py_BuildValue("(O)", player->BorrowPyRef()), - PythonRef::kSteal)); - } else { - BA_LOG_PYTHON_TRACE_ONCE("missing player on IssuePlayerLeft"); - } - } else { - Log("WARNING: HostSession: IssuePlayerLeft caled with no " - "session_py_obj_"); - } - } catch (const std::exception& e) { - Log(std::string("Error calling on_player_leave(): ") + e.what()); - } -} - -void HostSession::SetKickIdlePlayers(bool enable) { - // If this has changed, reset our disconnect-time reporting. - assert(InGameThread()); - if (enable != kick_idle_players_) { - last_kick_idle_players_decrement_time_ = GetRealTime(); - } - kick_idle_players_ = enable; -} - -void HostSession::SetForegroundHostActivity(HostActivity* a) { - assert(a); - assert(InGameThread()); - - if (shutting_down_) { - Log("WARNING: SetForegroundHostActivity called during session shutdown; " - "ignoring."); - return; - } - - // Sanity check: make sure the one provided is part of this session. - bool found = false; - for (auto&& i : host_activities_) { - if (i == a) { - found = true; - break; - } - } - if ((a->GetHostSession() != this) || !found) { - throw Exception("HostActivity is not part of this HostSession"); - } - - foreground_host_activity_ = a; - - // Now go through telling each host-activity whether it's foregrounded or not. - // FIXME: Dying sessions never get told they're un-foregrounded.. could that - // ever be a problem? - bool session_is_foreground = (g_game->GetForegroundSession() != nullptr); - for (auto&& i : host_activities_) { - i->SetIsForeground(session_is_foreground && (i == a)); - } -} - -void HostSession::AddHostActivity(HostActivity* a) { - host_activities_.emplace_back(a); -} - -// Called by the constructor of the session python object. -void HostSession::RegisterPySession(PyObject* obj) { - session_py_obj_.Acquire(obj); -} - -// Given an activity python type, instantiates and returns a new activity. -auto HostSession::NewHostActivity(PyObject* activity_type_obj, - PyObject* settings_obj) -> PyObject* { - PythonRef activity_type(activity_type_obj, PythonRef::kAcquire); - if (!activity_type.CallableCheck()) { - throw Exception("Invalid HostActivity type passed; not callable"); - } - - // First generate our C++ activity instance and point the context at it. - auto activity(Object::New(this)); - AddHostActivity(activity.get()); - - ScopedSetContext cp(activity.get()); - - // Now instantiate the python instance.. pass args if some were provided, or - // an empty dict otherwise. - PythonRef args; - if (settings_obj == Py_None) { - args.Steal(Py_BuildValue("({})")); - } else { - args.Steal(Py_BuildValue("(O)", settings_obj)); - } - - PythonRef result = activity_type.Call(args); - if (!result.exists()) { - throw Exception("HostActivity creation failed"); - } - - // If all went well, the python activity constructor should have called - // _ba.register_activity(), so we should be able to get at the same python - // activity we just instantiated through the c++ class. - if (activity->GetPyActivity() != result.get()) { - throw Exception("Error on HostActivity construction"); - } - - PyObject* obj = result.get(); - Py_INCREF(obj); - return obj; -} - -auto HostSession::RegisterPyActivity(PyObject* activity_obj) -> HostActivity* { - // The context should be pointing to an unregistered HostActivity; - // register and return it. - HostActivity* activity = Context::current().GetHostActivity(); - if (!activity) - throw Exception( - "No current activity in RegisterPyActivity; did you remember to call " - "ba.newHostActivity() to instantiate your activity?"); - activity->RegisterPyActivity(activity_obj); - return activity; -} - -void HostSession::DecrementPlayerTimeOuts(millisecs_t millisecs) { - for (auto&& i : players_) { - Player* player = i.get(); - assert(player); - if (player->time_out() < millisecs) { - std::string kick_str = - g_game->GetResourceString("kickIdlePlayersKickedText"); - Utils::StringReplaceOne(&kick_str, "${NAME}", player->GetName()); - ScreenMessage(kick_str); - RemovePlayer(player); - return; // Bail for this round since we prolly mucked with the list. - } else if (player->time_out() > BA_PLAYER_TIME_OUT_WARN - && (player->time_out() - millisecs <= BA_PLAYER_TIME_OUT_WARN)) { - std::string kick_str_1 = - g_game->GetResourceString("kickIdlePlayersWarning1Text"); - Utils::StringReplaceOne(&kick_str_1, "${NAME}", player->GetName()); - Utils::StringReplaceOne(&kick_str_1, "${COUNT}", - std::to_string(BA_PLAYER_TIME_OUT_WARN / 1000)); - ScreenMessage(kick_str_1); - ScreenMessage(g_game->GetResourceString("kickIdlePlayersWarning2Text")); - } - player->set_time_out(player->time_out() - millisecs); - } -} - -void HostSession::ProcessPlayerTimeOuts() { - millisecs_t real_time = GetRealTime(); - - if (foreground_host_activity_.exists() - && foreground_host_activity_->game_speed() > 0.0 - && !foreground_host_activity_->paused() - && foreground_host_activity_->getAllowKickIdlePlayers() - && kick_idle_players_) { - // Let's only do this every now and then. - if (real_time - last_kick_idle_players_decrement_time_ > 1000) { - DecrementPlayerTimeOuts(real_time - - last_kick_idle_players_decrement_time_); - last_kick_idle_players_decrement_time_ = real_time; - } - } else { - // If we're not kicking, we still store the latest time (so it doesnt - // accumulate for when we start again). - last_kick_idle_players_decrement_time_ = real_time; - } -} - -void HostSession::StepScene() { - // Run up our game-time timers. - sim_timers_.Run(scene()->time()); - - // And step. - scene()->Step(); -} - -void HostSession::Update(int time_advance) { - assert(InGameThread()); - - // We can be killed at any time, so let's keep an eye out for that. - WeakRef test_ref(this); - assert(test_ref.exists()); - - ProcessPlayerTimeOuts(); - - GameStream* output_stream = GetGameStream(); - - // Advance base time by the specified amount, - // stopping at all timers along the way. - millisecs_t target_base_time = base_time_ + time_advance; - while (!base_timers_.empty() - && (base_time_ + base_timers_.GetTimeToNextExpire(base_time_) - <= target_base_time)) { - base_time_ += base_timers_.GetTimeToNextExpire(base_time_); - if (output_stream) { - output_stream->SetTime(base_time_); - } - base_timers_.Run(base_time_); - } - base_time_ = target_base_time; - if (output_stream) { - output_stream->SetTime(base_time_); - } - assert(test_ref.exists()); - - // Update our activities (iterate via weak-refs as this list may change under - // us at any time). - std::vector > activities = - PointersToWeakRefs(RefsToPointers(host_activities_)); - for (auto&& i : activities) { - if (i.exists()) { - i->Update(time_advance); - assert(test_ref.exists()); - } - } - assert(test_ref.exists()); - - // Periodically prune various dead refs. - if (base_time_ > next_prune_time_) { - PruneDeadMapRefs(&textures_); - PruneDeadMapRefs(&sounds_); - PruneDeadMapRefs(&models_); - PruneDeadRefs(&python_calls_); - next_prune_time_ = base_time_ + 5000; - } - assert(test_ref.exists()); -} - -HostSession::~HostSession() { - try { - shutting_down_ = true; - - // Put the scene in shut-down mode before we start killing stuff - // (this generates warnings, suppresses messages, etc). - scene_->set_shutting_down(true); - - // Clear out all python calls registered in our context - // (should wipe out refs to our session and prevent them from running - // without a valid session context). - for (auto&& i : python_calls_) { - if (i.exists()) { - i->MarkDead(); - } - } - - // Mark all our media dead to clear it out of our output-stream cleanly. - for (auto&& i : textures_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - for (auto&& i : models_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - for (auto&& i : sounds_) { - if (i.second.exists()) { - i.second->MarkDead(); - } - } - - // Clear our timers and scene; this should wipe out any remaining refs - // to our session scene. - base_timers_.Clear(); - sim_timers_.Clear(); - scene_.Clear(); - - // Kill our python session object. - { - ScopedSetContext cp(this); - session_py_obj_.Release(); - } - - // Kill any remaining activity data. Generally all activities should die - // when the session python object goes down, but lets clean up in case any - // didn't. - for (auto&& i : host_activities_) { - ScopedSetContext cp{Object::Ref(i)}; - i.Clear(); - } - - // Report outstanding calls. There shouldn't be any at this point. Actually - // it turns out there's generally 1; whichever call was responsible for - // killing this activity will still be in progress.. so let's report on 2 or - // more I guess. -#if BA_DEBUG_BUILD - PruneDeadRefs(&python_calls_); - if (python_calls_.size() > 1) { - std::string s = "WARNING: " + std::to_string(python_calls_.size()) - + " live PythonContextCalls at shutdown for " - + "HostSession" + " (1 call is expected):"; - int count = 1; - for (auto&& i : python_calls_) { - s += ("\n " + std::to_string(count++) + ": " - + i->GetObjectDescription()); - } - Log(s); - } -#endif // BA_DEBUG_BUILD - } catch (const std::exception& e) { - Log("Exception in HostSession destructor: " + std::string(e.what())); - } -} - -void HostSession::RegisterCall(PythonContextCall* call) { - assert(call); - python_calls_.emplace_back(call); - - // If we're shutting down, just kill the call immediately. - // (we turn all of our calls to no-ops as we shut down). - if (shutting_down_) { - Log("WARNING: adding call to expired session; call will not function: " - + call->GetObjectDescription()); - call->MarkDead(); - } -} - -auto HostSession::GetUnusedPlayerName(Player* p, const std::string& base_name) - -> std::string { - // Now find the first non-taken variation. - int index = 1; - std::string name_test; - while (true) { - if (index > 1) { - name_test = base_name + " " + std::to_string(index); - } else { - name_test = base_name; - } - bool name_found = false; - for (auto&& j : players_) { - if ((j->GetName() == name_test) && (j.get() != p)) { - name_found = true; - break; - } - } - if (!name_found) break; - index += 1; - } - return name_test; -} - -void HostSession::DumpFullState(GameStream* out) { - // Add session-scene. - if (scene_.exists()) { - scene_->Dump(out); - } - - // Dump media associated with session-scene. - for (auto&& i : textures_) { - if (Texture* t = i.second.get()) { - out->AddTexture(t); - } - } - for (auto&& i : sounds_) { - if (Sound* s = i.second.get()) { - out->AddSound(s); - } - } - for (auto&& i : models_) { - if (Model* s = i.second.get()) { - out->AddModel(s); - } - } - - // Dump session-scene's nodes. - if (scene_.exists()) { - scene_->DumpNodes(out); - } - - // Now let our activities dump themselves. - for (auto&& i : host_activities_) { - i->DumpFullState(out); - } -} - -void HostSession::GetCorrectionMessages( - bool blend, std::vector >* messages) { - std::vector message; - - // Grab correction for session scene (though there shouldn't be one). - if (scene_.exists()) { - message = scene_->GetCorrectionMessage(blend); - if (message.size() > 4) { - // A correction packet of size 4 is empty; ignore it. - messages->push_back(message); - } - } - - // Now do same for activity scenes. - for (auto&& i : host_activities_) { - if (HostActivity* ha = i.get()) { - if (Scene* sg = ha->scene()) { - message = sg->GetCorrectionMessage(blend); - if (message.size() > 4) { - // A correction packet of size 4 is empty; ignore it. - messages->push_back(message); - } - } - } - } -} - -auto HostSession::NewTimer(TimeType timetype, TimerMedium length, bool repeat, - const Object::Ref& runnable) -> int { - // Make sure the runnable passed in is reference-managed already - // (we may not add an initial reference ourself). - assert(runnable->is_valid_refcounted_object()); - - // We currently support game and base timers. - switch (timetype) { - case TimeType::kSim: - case TimeType::kBase: - // Game and base timers are the same thing for us. - return NewTimer(length, repeat, runnable); - default: - // Gall back to default for descriptive error otherwise. - return ContextTarget::NewTimer(timetype, length, repeat, runnable); - } -} - -void HostSession::DeleteTimer(TimeType timetype, int timer_id) { - switch (timetype) { - case TimeType::kSim: - case TimeType::kBase: - // Game and base timers are the same thing for us. - DeleteTimer(timer_id); - break; - default: - // Fall back to default for descriptive error otherwise. - ContextTarget::DeleteTimer(timetype, timer_id); - break; - } -} - -auto HostSession::GetTime(TimeType timetype) -> millisecs_t { - switch (timetype) { - case TimeType::kSim: - case TimeType::kBase: - return scene_->time(); - default: - // Fall back to default for descriptive error otherwise. - return ContextTarget::GetTime(timetype); - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/session/net_client_session.cc b/src/ballistica/game/session/net_client_session.cc deleted file mode 100644 index c555cebe..00000000 --- a/src/ballistica/game/session/net_client_session.cc +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/session/net_client_session.h" - -#include -#include - -#include "ballistica/app/app_globals.h" -#include "ballistica/game/connection/connection_to_host.h" -#include "ballistica/media/media_server.h" - -namespace ballistica { - -NetClientSession::NetClientSession() { - // Sanity check: we should only ever be writing one replay at once. - if (g_app_globals->replay_open) { - Log("ERROR: g_replay_open true at netclient start; shouldn't happen."); - } - assert(g_media_server); - g_media_server->PushBeginWriteReplayCall(); - writing_replay_ = true; - g_app_globals->replay_open = true; -} - -NetClientSession::~NetClientSession() { - if (writing_replay_) { - // Sanity check: we should only ever be writing one replay at once. - if (!g_app_globals->replay_open) { - Log("ERROR: g_replay_open false at net-client close; shouldn't happen."); - } - g_app_globals->replay_open = false; - assert(g_media_server); - g_media_server->PushEndWriteReplayCall(); - writing_replay_ = false; - } -} - -void NetClientSession::SetConnectionToHost(ConnectionToHost* c) { - connection_to_host_ = c; -} - -void NetClientSession::OnCommandBufferUnderrun() { - // Any time we run out of data, hit the brakes on our playback speed. - // Update: maybe not. - // correction_ *= 0.99f; -} - -void NetClientSession::Update(int time_advance) { - if (shutting_down_) { - return; - } - - // Now do standard step. - ClientSession::Update(time_advance); - - // And update our timing to try and ensure we don't run out of buffer. - UpdateBuffering(); -} - -void NetClientSession::UpdateBuffering() { - // if (NetGraph *graph = g_graphics->debug_graph_1()) { - // graph->addSample(GetRealTime(), steps_on_list_); - // } - - // Keep record of the most and least amount of time we've had buffered - // recently, and slow down/speed up a bit based on that. - { - int bucket_count = static_cast(least_buffered_count_list_.size()); - - // Change bucket every g_delay_samples samples. - int bucket = (buffer_count_list_index_ / g_app_globals->delay_samples) - % bucket_count; - int bucket_iteration = - buffer_count_list_index_ % g_app_globals->delay_samples; - - // *Set* the value the first iteration in each bucket; do *min* after that. - if (bucket_iteration == 0) { - least_buffered_count_list_[bucket] = steps_on_list_; - most_buffered_count_list_[bucket] = steps_on_list_; - } else { - least_buffered_count_list_[bucket] = - std::min(least_buffered_count_list_[bucket], steps_on_list_); - most_buffered_count_list_[bucket] = - std::max(most_buffered_count_list_[bucket], steps_on_list_); - - // After the last sample in each bucket, feed the max bucket value in - // as the 'low pass' buffer-count. The low-pass curve minus our largest - // spike value should be where we want to aim for in the buffer. - if (bucket_iteration == g_app_globals->delay_samples - 1) { - float smoothing = 0.5f; - low_pass_smoothed_ = - smoothing * low_pass_smoothed_ - + (1.0f - smoothing) - * static_cast(most_buffered_count_list_[bucket]); - } - } - - // Keep track of the largest min/max difference in our sample segments. - int largest_spike = 0; - - buffer_count_list_index_++; - for (int i = 1; i < bucket_count; i++) { - int spike = most_buffered_count_list_[i] - least_buffered_count_list_[i]; - if (spike > largest_spike) { - largest_spike = spike; - } - } - - // Slowly adjust largest spike value based on the biggest in recent history. - { - float smoothing = 0.95f; - largest_spike_smoothed_ = - smoothing * largest_spike_smoothed_ - + (1.0f - smoothing) * static_cast(largest_spike); - } - - // Low pass is the most buffered data we've had in the most recent slot. - float ideal_offset = low_pass_smoothed_ - largest_spike_smoothed_ * 1.0f; - - // Any time we've got no current buffered data, slow down fast. - // (otherwise we can get stuck cruising along with no 0 buffered data and - // things get real jerky looking) - if (steps_on_list_ == 0) { - ideal_offset -= 100.0f; - } - float smoothing = 0.0f; - correction_ = smoothing * correction_ - + (1.0f - smoothing) * (1.0f + 0.002f * ideal_offset); - correction_ = std::min(1.5f, std::max(0.5f, correction_)); - // if (NetGraph *graph = g_graphics->debug_graph_2()) { - // graph->addSample(GetRealTime(), correction_); - // } - } -} -void NetClientSession::HandleSessionMessage( - const std::vector& message) { - // Do the standard thing, but also write this message straight to our replay - // stream if we have one. - ClientSession::HandleSessionMessage(message); - - if (writing_replay_) { - assert(g_media_server); - g_media_server->PushAddMessageToReplayCall(message); - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/session/replay_client_session.cc b/src/ballistica/game/session/replay_client_session.cc deleted file mode 100644 index f38c8362..00000000 --- a/src/ballistica/game/session/replay_client_session.cc +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/session/replay_client_session.h" - -#include -#include -#include -#include - -#include "ballistica/dynamics/material/material.h" -#include "ballistica/game/connection/connection_to_client.h" -#include "ballistica/game/game_stream.h" -#include "ballistica/generic/huffman.h" -#include "ballistica/generic/utils.h" -#include "ballistica/math/vector3f.h" -#include "ballistica/networking/networking.h" -#include "ballistica/platform/platform.h" -#include "ballistica/scene/scene.h" - -namespace ballistica { - -auto ReplayClientSession::GetActualTimeAdvance(int advance_in) -> int { - return static_cast( - round(advance_in * pow(2.0f, g_game->replay_speed_exponent()))); -} - -ReplayClientSession::ReplayClientSession(std::string filename) - : file_name_(std::move(filename)), - file_(nullptr), - message_fetch_num_(0), - have_sent_client_message_(false) { - // take responsibility for feeding all clients to this device.. - g_game->RegisterClientController(this); - - // go ahead and just do a reset here, which will get things going.. - Reset(true); -} - -ReplayClientSession::~ReplayClientSession() { - // we no longer are responsible for feeding clients to this device.. - g_game->UnregisterClientController(this); - - if (file_) { - fclose(file_); - file_ = nullptr; - } -} - -void ReplayClientSession::OnClientConnected(ConnectionToClient* c) { - // sanity check - abort if its on either of our lists already - for (ConnectionToClient* i : connections_to_clients_) { - if (i == c) { - Log("Error: ReplayClientSession::OnClientConnected()" - " got duplicate connection"); - return; - } - } - for (ConnectionToClient* i : connections_to_clients_ignored_) { - if (i == c) { - Log("Error: ReplayClientSession::OnClientConnected()" - " got duplicate connection"); - return; - } - } - - // if we've sent *any* commands out to clients so far, we currently have to - // ignore new connections (need to rebuild state to match current session - // state) - { - connections_to_clients_.push_back(c); - - // we create a temporary output stream just for the purpose of building - // a giant session-commands message that we can send to the client - // to build its state up to where we are currently. - GameStream out(nullptr, false); - - // go ahead and dump our full state.. - DumpFullState(&out); - - // grab the message that's been built up.. - // if its not empty, send it to the client. - std::vector out_message = out.GetOutMessage(); - if (!out_message.empty()) c->SendReliableMessage(out_message); - - // also send a correction packet to sync up all our dynamics - // (technically could do this *just* for the new client) - { - std::vector > messages; - bool blend = false; - GetCorrectionMessages(blend, &messages); - - // FIXME - have to send reliably at the moment since these will most - // likely be bigger than our unreliable packet limit.. :-( - for (auto&& i : messages) { - for (auto&& j : connections_to_clients_) { - j->SendReliableMessage(i); - } - } - } - } -} - -void ReplayClientSession::OnClientDisconnected(ConnectionToClient* c) { - // search for it on either our ignored or regular lists.. - for (auto i = connections_to_clients_.begin(); - i != connections_to_clients_.end(); i++) { - if (*i == c) { - connections_to_clients_.erase(i); - return; - } - } - for (auto i = connections_to_clients_ignored_.begin(); - i != connections_to_clients_ignored_.end(); i++) { - if (*i == c) { - connections_to_clients_ignored_.erase(i); - return; - } - } - Log("Error: ReplayClientSession::OnClientDisconnected()" - " called for connection not on lists"); -} - -void ReplayClientSession::FetchMessages() { - if (!file_ || shutting_down()) { - return; - } - - // If we have no messages left, read from the file until we get some. - while (commands_.empty()) { - std::vector buffer; - uint8_t len8; - uint32_t len32; - - // read the size of the message.. - // the first byte represents the actual size if the value is < 254 - // if it is 254, the 2 bytes after it represent size - // if it is 255, the 4 bytes after it represent size - if (fread(&len8, 1, 1, file_) != 1) { - // so they know to be done when they reach the end of the command list - // (instead of just waiting for more commands) - commands_.emplace_back(1, - static_cast(SessionCommand::kEndOfFile)); - fclose(file_); - file_ = nullptr; - return; - } - if (len8 < 254) { - len32 = len8; - } else { - // pull 16 bit len.. - if (len8 == 254) { - uint16_t len16; - if (fread(&len16, 2, 1, file_) != 1) { - // so they know to be done when they reach the end of the command list - // (instead of just waiting for more commands) - commands_.emplace_back( - 1, static_cast(SessionCommand::kEndOfFile)); - fclose(file_); - file_ = nullptr; - return; - } - assert(len16 >= 254); - len32 = len16; - } else { - // pull 32 bit len... - if (fread(&len32, 4, 1, file_) != 1) { - // so they know to be done when they reach the end of the command list - // (instead of just waiting for more commands) - commands_.emplace_back( - 1, static_cast(SessionCommand::kEndOfFile)); - fclose(file_); - file_ = nullptr; - return; - } - assert(len32 > 65535); - } - } - - // read and decompress the actual message.. - BA_PRECONDITION(len32 > 0); - buffer.resize(len32); - if (fread(&(buffer[0]), len32, 1, file_) != 1) { - commands_.emplace_back(1, - static_cast(SessionCommand::kEndOfFile)); - fclose(file_); - file_ = nullptr; - return; - } - std::vector data_decompressed = - g_utils->huffman()->decompress(buffer); - HandleSessionMessage(data_decompressed); - - // Also send it to all client-connections we're attached to. - // NOTE: We currently are sending everything as reliable; we can maybe do - // unreliable for certain type of messages. Though perhaps when passing - // around replays maybe its best to keep everything intact. - have_sent_client_message_ = true; - for (auto&& i : connections_to_clients_) { - i->SendReliableMessage(data_decompressed); - } - message_fetch_num_++; - } -} - -void ReplayClientSession::Error(const std::string& description) { - // Close the replay, announce something went wrong with it, and then do - // standard error response.. - ScreenMessage(g_game->GetResourceString("replayReadErrorText"), {1, 0, 0}); - if (file_) { - fclose(file_); - file_ = nullptr; - } - ClientSession::Error(description); -} - -void ReplayClientSession::OnReset(bool rewind) { - // Handles base resetting. - ClientSession::OnReset(rewind); - - // If we've got any clients attached to us, tell them to reset as well. - for (auto&& i : connections_to_clients_) { - i->SendReliableMessage(std::vector(1, BA_MESSAGE_SESSION_RESET)); - } - - // If rewinding, pop back to the start of our file. - if (rewind) { - if (file_) { - fclose(file_); - file_ = nullptr; - } - - file_ = g_platform->FOpen(file_name_.c_str(), "rb"); - if (!file_) { - Error("can't open file for reading"); - return; - } - - // Read file ID and version to make sure we support this file. - uint32_t file_id; - if ((fread(&file_id, sizeof(file_id), 1, file_) != 1)) { - Error("error reading file_id"); - return; - } - if (file_id != kBrpFileID) { - Error("incorrect file_id"); - return; - } - - // Make sure its a compatible protocol version. - uint16_t version; - if (fread(&version, sizeof(version), 1, file_) != 1) { - Error("error reading version"); - return; - } - if (version > kProtocolVersion || version < kProtocolVersionMin) { - ScreenMessage(g_game->GetResourceString("replayVersionErrorText"), - {1, 0, 0}); - End(); - return; - } - } -} - -void ReplayClientSession::DumpFullState(GameStream* out) { - // This shouldn't actually be replay-specific. Should move this up to - // ClientSession perhaps? - - // Add all scenes. - for (auto&& i : scenes_) { - if (Scene* sg = i.get()) { - sg->Dump(out); - } - } - - // Before doing any nodes, we need to create all materials. - // (but *not* their components, which may reference the nodes that we haven't - // made yet) - for (auto&& i : materials_) { - if (Material* m = i.get()) { - out->AddMaterial(m); - } - } - - // Add all media. - for (auto&& i : textures_) { - if (Texture* t = i.get()) { - out->AddTexture(t); - } - } - for (auto&& i : models_) { - if (Model* s = i.get()) { - out->AddModel(s); - } - } - for (auto&& i : sounds_) { - if (Sound* s = i.get()) { - out->AddSound(s); - } - } - for (auto&& i : collide_models_) { - if (CollideModel* s = i.get()) { - out->AddCollideModel(s); - } - } - - // Add all scene nodes. - for (auto&& i : scenes_) { - if (Scene* sg = i.get()) { - sg->DumpNodes(out); - } - } - - // Now fill out materials since all the nodes/etc they reference exist. - for (auto&& i : materials_) { - if (Material* m = i.get()) { - m->DumpComponents(out); - } - } -} - -} // namespace ballistica diff --git a/src/ballistica/game/session/session.cc b/src/ballistica/game/session/session.cc deleted file mode 100644 index 756e5d9f..00000000 --- a/src/ballistica/game/session/session.cc +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (c) 2011-2020 Eric Froemling - -#include "ballistica/game/session/session.h" - -#include "ballistica/app/app_globals.h" -#include "ballistica/game/game.h" - -namespace ballistica { - -Session::Session() { - g_app_globals->session_count++; - // new sessions immediately become foreground - g_game->SetForegroundSession(this); -} - -Session::~Session() { g_app_globals->session_count--; } - -void Session::Update(int time_advance) {} - -auto Session::GetForegroundContext() -> Context { return Context(); } - -void Session::Draw(FrameDef*) {} - -void Session::ScreenSizeChanged() {} - -void Session::LanguageChanged() {} - -void Session::GraphicsQualityChanged(GraphicsQuality q) {} - -void Session::DebugSpeedMultChanged() {} - -void Session::DumpFullState(GameStream* out) { - Log("Session::DumpFullState() being called; shouldn't happen."); -} - -} // namespace ballistica From 81365a665e912536045f7fed99e3a2e8973f6fff Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 3 Oct 2020 13:45:39 -0500 Subject: [PATCH 228/417] More C++ Work --- .efrocachemap | 20 ++++++++++---------- .idea/dictionaries/ericf.xml | 13 +++++++------ src/ballistica/ballistica.cc | 6 ++++-- src/ballistica/ballistica.h | 5 +++++ src/ballistica/core/types.h | 1 + 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index f968205e..b6dd77ac 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/10/7681acdbd8feccb27175d6ab8609", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/72/faa94ff6532a95c121fcb5a4f788", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/97/99/5ba65477f8b846beb98d146a1d2c", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dd/5d/f8c5b24579236bef5209d7089044", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/ba/af/659cd48bd1be9b22ba3006ccb5f9", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/45/1e/cea9badaf52032adb40e6c3b5e21", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9c/53/c0a2b1c2ee30397db0eb367b688c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/8b/a1/c3471ecf846cce50d9220f7214c3", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/fa/95/87cc2ad7f0e780b02cd9ac633d3d", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/31/6f/9a29e7100425f8a364208ba40f4f" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/0a/ea925f186b90fc6825826a172ff4", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/33/c6/eef5bce22b04b76d250086bf0f8e", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/9c/f478ef45dd97e24820875692febf", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d1/a1/1abc324a112757d413b783b4604f", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/1b/926ca3d53ed7b3a5c915f6cef903", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/1c/b15ca147f7fde42f92c7178bc8b1", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/cd/23e1c5e72dc5ec432f1d4453246c", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ff/a9/3aac029e7bf8511eb3cf0a40a454", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a0/04/8274ec50900ee6ba4bc68960f074", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/98/9f/1a878cf5afa75ce59130ecf39d3b" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index a1496dc2..53679d5c 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack ack'ed + ack acked acks acnt @@ -151,8 +151,8 @@ bacommon badguy bafoundation - ballistica ballistica's + ballistica ballisticacore ballisticacorecb bamaster @@ -793,8 +793,8 @@ gamedata gameinstance gamemap - gamepad gamepad's + gamepad gamepadadvanced gamepads gamepadselect @@ -1177,8 +1177,8 @@ lsqlite lssl lstart - lstr lstr's + lstr lstrs lsval ltex @@ -1803,8 +1803,8 @@ sessionname sessionplayer sessionplayers - sessionteam sessionteam's + sessionteam sessionteams sessiontype setactivity @@ -1853,6 +1853,7 @@ snakeshadow sname snode + sockaddr socketmodule socketserver somevar @@ -2134,8 +2135,8 @@ txtw typeargs typecheck - typechecker typechecker's + typechecker typedval typeshed typestr diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 3bbb99db..6ffc85c2 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,7 +29,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20194; +const int kAppBuildNumber = 20195; const char* kAppVersion = "1.5.26"; const char* kBlessingHash = nullptr; @@ -40,6 +40,7 @@ int g_early_log_writes{10}; Thread* g_main_thread{}; AppGlobals* g_app_globals{}; AppConfig* g_app_config{}; +AppInternal* g_app_internal{}; App* g_app{}; Account* g_account{}; Game* g_game{}; @@ -81,7 +82,7 @@ TextGraphics* g_text_graphics{}; auto BallisticaMain(int argc, char** argv) -> int { try { // Even at the absolute start of execution we should be able to - // phone home on errors. Set BA_CRASH_TEST=1 to test this. + // phone home on errors. Set env var BA_CRASH_TEST=1 to test this. if (const char* crashenv = getenv("BA_CRASH_TEST")) { if (!strcmp(crashenv, "1")) { FatalError("Fatal-Error-Test"); @@ -93,6 +94,7 @@ auto BallisticaMain(int argc, char** argv) -> int { // ------------------------------------------------------------------------- g_app_globals = new AppGlobals(argc, argv); + g_app_internal = CreateAppInternal(); g_platform = Platform::Create(); g_platform->PostInit(); g_account = new Account(); diff --git a/src/ballistica/ballistica.h b/src/ballistica/ballistica.h index b615fa98..b8b7a0e7 100644 --- a/src/ballistica/ballistica.h +++ b/src/ballistica/ballistica.h @@ -119,6 +119,7 @@ extern Account* g_account; extern App* g_app; extern AppConfig* g_app_config; extern AppGlobals* g_app_globals; +extern AppInternal* g_app_internal; extern Audio* g_audio; extern AudioServer* g_audio_server; extern BGDynamics* g_bg_dynamics; @@ -151,6 +152,10 @@ auto GetUniqueSessionIdentifier() -> const std::string&; /// Have our main threads/modules all been inited yet? auto IsBootstrapped() -> bool; +/// Create/init our internal (non-public) parts. +auto CreateAppInternal() -> AppInternal*; +auto AppInternalGameThreadInit() -> void; + /// Does it appear that we are a blessed build with no known user-modifications? auto IsUnmodifiedBlessedBuild() -> bool; diff --git a/src/ballistica/core/types.h b/src/ballistica/core/types.h index 3fe73091..0457d6e5 100644 --- a/src/ballistica/core/types.h +++ b/src/ballistica/core/types.h @@ -40,6 +40,7 @@ class Account; class App; class AppConfig; class AppGlobals; +class AppInternal; class AreaOfInterest; class Audio; class AudioServer; From 7de28df23d01a079822c5ba3ae7ca5c3c58fffab Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 9 Oct 2020 09:15:58 -0700 Subject: [PATCH 229/417] Language updates and C++ work --- .efrocachemap | 24 ++++++++++----------- .idea/dictionaries/ericf.xml | 12 +++++------ docs/ba_module.md | 2 +- src/ballistica/ballistica.cc | 38 +--------------------------------- src/ballistica/ballistica.h | 2 +- src/ballistica/core/logging.cc | 2 +- 6 files changed, 22 insertions(+), 58 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index b6dd77ac..b662c580 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -420,7 +420,7 @@ "assets/build/ba_data/audio/zoeOw.ogg": "https://files.ballistica.net/cache/ba1/04/0a/c4f7d2794b018593ab0b2bcb07f0", "assets/build/ba_data/audio/zoePickup01.ogg": "https://files.ballistica.net/cache/ba1/06/4d/18777c9a2eb2207a2891a2837a70", "assets/build/ba_data/audio/zoeScream01.ogg": "https://files.ballistica.net/cache/ba1/81/90/23ab1ecc8c55267bd904a9c05344", - "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/86/81/74172efe05c0e0508abf24e2de32", + "assets/build/ba_data/data/langdata.json": "https://files.ballistica.net/cache/ba1/f5/92/636aa7d2257db81d98bd17d43ffd", "assets/build/ba_data/data/languages/arabic.json": "https://files.ballistica.net/cache/ba1/de/25/74be4875c2a0e22b813a4e1a103b", "assets/build/ba_data/data/languages/belarussian.json": "https://files.ballistica.net/cache/ba1/49/5f/b29bb65369040892fe6601801637", "assets/build/ba_data/data/languages/chinese.json": "https://files.ballistica.net/cache/ba1/c3/3f/c37ac3c65ac65f171af9313a502a", @@ -440,7 +440,7 @@ "assets/build/ba_data/data/languages/indonesian.json": "https://files.ballistica.net/cache/ba1/9a/3d/9aff685d04d2e1cabb2f9ddafcf3", "assets/build/ba_data/data/languages/italian.json": "https://files.ballistica.net/cache/ba1/33/04/b1c54ce2b8979cc983aecc781228", "assets/build/ba_data/data/languages/korean.json": "https://files.ballistica.net/cache/ba1/0a/84/bbb6ed2abf66509406f534cbbb52", - "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/30/f9/b4f4e8ff8e3c8372162b2c98f3e1", + "assets/build/ba_data/data/languages/persian.json": "https://files.ballistica.net/cache/ba1/1e/67/f8d1d6579698c10af9da2ecb62d9", "assets/build/ba_data/data/languages/polish.json": "https://files.ballistica.net/cache/ba1/88/4b/6745a1a58220772e259f0de51196", "assets/build/ba_data/data/languages/portuguese.json": "https://files.ballistica.net/cache/ba1/42/b5/7612cce15fe4555889585108b3ef", "assets/build/ba_data/data/languages/romanian.json": "https://files.ballistica.net/cache/ba1/44/3c/7cc06ca8d5475e1687d0ed05bdbf", @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/12/0a/ea925f186b90fc6825826a172ff4", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/33/c6/eef5bce22b04b76d250086bf0f8e", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bf/9c/f478ef45dd97e24820875692febf", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/d1/a1/1abc324a112757d413b783b4604f", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/1b/926ca3d53ed7b3a5c915f6cef903", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e2/1c/b15ca147f7fde42f92c7178bc8b1", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ec/cd/23e1c5e72dc5ec432f1d4453246c", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ff/a9/3aac029e7bf8511eb3cf0a40a454", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/a0/04/8274ec50900ee6ba4bc68960f074", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/98/9f/1a878cf5afa75ce59130ecf39d3b" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/7e/56adde97a5cb545933bdd52700d9", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3c/f9/d971d471660647f1eacb768f0d10", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ef/b7/aa17c70752baab2bd4ea970b7b2d", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/43/77/27920088a7fb8490a833623894a1", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/70/3a/36ff319dbed727b6bd148073e278", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/81/5d46cb2627d0ae1f0c59a9dd123a", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3a/8f/502e7fef458bb05da2864f4724ea", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/60/38/2d0e9f0cf486bae30056f3d3c11a", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/37/a6/ae4e2bf9c60fc0cbfd66136dc344", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/02/f4/907cfc73510e071f9ab5ca914646" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 53679d5c..cc801a97 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack'ed ack + ack'ed acked acks acnt @@ -151,8 +151,8 @@ bacommon badguy bafoundation - ballistica's ballistica + ballistica's ballisticacore ballisticacorecb bamaster @@ -793,8 +793,8 @@ gamedata gameinstance gamemap - gamepad's gamepad + gamepad's gamepadadvanced gamepads gamepadselect @@ -1177,8 +1177,8 @@ lsqlite lssl lstart - lstr's lstr + lstr's lstrs lsval ltex @@ -1803,8 +1803,8 @@ sessionname sessionplayer sessionplayers - sessionteam's sessionteam + sessionteam's sessionteams sessiontype setactivity @@ -2135,8 +2135,8 @@ txtw typeargs typecheck - typechecker's typechecker + typechecker's typedval typeshed typestr diff --git a/docs/ba_module.md b/docs/ba_module.md index a4b30a75..8f282d8e 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-10-02 for Ballistica version 1.5.26 build 20194

    +

    last updated on 2020-10-09 for Ballistica version 1.5.26 build 20195

    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!


    diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 6ffc85c2..a977a442 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,9 +29,8 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20195; +const int kAppBuildNumber = 20196; const char* kAppVersion = "1.5.26"; -const char* kBlessingHash = nullptr; // Our standalone globals. // These are separated out for easy access. @@ -178,7 +177,6 @@ auto BallisticaMain(int argc, char** argv) -> int { } } } - // printf("BLESSED? %d\n", static_cast(IsUnmodifiedBlessedBuild())); g_platform->WillExitMain(false); return g_app_globals->return_value; @@ -301,40 +299,6 @@ void SetPythonException(PyExcType python_type, const char* description) { Python::SetPythonException(python_type, description); } -auto IsUnmodifiedBlessedBuild() -> bool { - // Assume debug builds are not blessed (we'll determine this after - // we finish calcing blessing hash, but this we don't get false positives - // up until that point) - if (g_buildconfig.debug_build()) { - return false; - } - - // Return false if we're unblessed or it seems that the user is likely - // mucking around with stuff. If we just don't know yet - // (for instance if blessing has calc hasn't completed) we assume we're - // clean. - if (g_app_globals && g_app_globals->user_ran_commands) { - return false; - } - - // If they're using custom app scripts, just consider it modified. - // Otherwise can can tend to get errors in early bootstrapping before - // we've been able to calc hashes to see if things are modified. - if (g_platform && g_platform->using_custom_app_python_dir()) { - return false; - } - - // If we don't have an embedded blessing hash, we're not blessed. Duh. - if (kBlessingHash == nullptr) { - return false; - } - - // If we have an embedded hash and we've calced ours - // and it doesn't match, consider ourself modified. - return !(g_app_globals && !g_app_globals->calced_blessing_hash.empty() - && g_app_globals->calced_blessing_hash != kBlessingHash); -} - } // namespace ballistica // If desired, define main() in the global namespace. diff --git a/src/ballistica/ballistica.h b/src/ballistica/ballistica.h index b8b7a0e7..ec319921 100644 --- a/src/ballistica/ballistica.h +++ b/src/ballistica/ballistica.h @@ -38,7 +38,6 @@ namespace ballistica { extern const int kAppBuildNumber; extern const char* kAppVersion; -extern const char* kBlessingHash; // Protocol version we host games with and write replays to. // This should be incremented whenever there are changes made to the @@ -155,6 +154,7 @@ auto IsBootstrapped() -> bool; /// Create/init our internal (non-public) parts. auto CreateAppInternal() -> AppInternal*; auto AppInternalGameThreadInit() -> void; +auto AppInternalHasBlessingHash() -> bool; /// Does it appear that we are a blessed build with no known user-modifications? auto IsUnmodifiedBlessedBuild() -> bool; diff --git a/src/ballistica/core/logging.cc b/src/ballistica/core/logging.cc index 8a3f32a1..3867415f 100644 --- a/src/ballistica/core/logging.cc +++ b/src/ballistica/core/logging.cc @@ -156,7 +156,7 @@ auto Logging::DirectSendLogs(const std::string& prefix, // between blessing not being calced yet and being confirmed as un-blessed. // FIXME: should probably do this in python layer log submits too. std::string bless_calc_state; - if (kBlessingHash == nullptr) { + if (!AppInternalHasBlessingHash()) { bless_calc_state = "nointhash"; } else if (g_app_globals == nullptr) { bless_calc_state = "noglobs"; From c414c686a186803c1fa86f0efa2fc9da216ee2dc Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 9 Oct 2020 09:50:50 -0700 Subject: [PATCH 230/417] Improved auto-rebuilding --- tools/batools/pcommand.py | 54 +++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index ab802fdd..227f089a 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -15,7 +15,7 @@ from typing import TYPE_CHECKING from efrotools.pcommand import PROJROOT if TYPE_CHECKING: - from typing import Optional, List, Set + from typing import Optional, List, Set, Dict def stage_server_file() -> None: @@ -721,27 +721,32 @@ def update_project() -> None: def cmake_prep_dir() -> None: - """Create a dir, recreating it when cmake version changes. + """Create a dir, recreating it when cmake/python/etc. version changes. - Useful to prevent builds from breaking when cmake is updated. + Useful to prevent builds from breaking when cmake or other components + are updated. """ + # pylint: disable=too-many-locals import os import subprocess + import json from efro.error import CleanError from efro.terminal import Clr + from efrotools import PYVER if len(sys.argv) != 3: raise CleanError('Expected 1 arg (dir name)') dirname = sys.argv[2] - # Look for cmake version associated with the dir. - verfilename = os.path.join(dirname, '.ba_cmake_version') - ver: Optional[str] + verfilename = os.path.join(dirname, '.ba_cmake_env') + + versions: Dict[str, str] if os.path.isfile(verfilename): with open(verfilename) as infile: - ver = infile.read() + versions = json.loads(infile.read()) + assert isinstance(versions, dict) else: - ver = None + versions = {} # Get version of installed cmake. cmake_ver_output = subprocess.run(['cmake', '--version'], @@ -749,12 +754,35 @@ def cmake_prep_dir() -> None: capture_output=True).stdout.decode() cmake_ver = cmake_ver_output.splitlines()[0].split('cmake version ')[1] + cmake_ver_existing = versions.get('cmake') + assert isinstance(cmake_ver_existing, (str, type(None))) + + # Get specific version of our target python. + python_ver_output = subprocess.run([f'python{PYVER}', '--version'], + check=True, + capture_output=True).stdout.decode() + python_ver = python_ver_output.splitlines()[0].split('Python ')[1] + + python_ver_existing = versions.get('python') + assert isinstance(python_ver_existing, (str, type(None))) + # If they don't match, blow away the dir and write the current version. - if ver != cmake_ver: - if ver is not None: - print(f'{Clr.BLU}CMake version changed from {ver} to {cmake_ver};' - f' clearing existing build at "{dirname}".{Clr.RST}') + if cmake_ver_existing != cmake_ver or python_ver_existing != python_ver: + if (cmake_ver_existing != cmake_ver + and cmake_ver_existing is not None): + print(f'{Clr.BLU}CMake version changed from {cmake_ver_existing}' + f' to {cmake_ver}; clearing existing build at' + f' "{dirname}".{Clr.RST}') + if (python_ver_existing != python_ver + and python_ver_existing is not None): + print(f'{Clr.BLU}Python version changed from {python_ver_existing}' + f' to {python_ver}; clearing existing build at' + f' "{dirname}".{Clr.RST}') subprocess.run(['rm', '-rf', dirname], check=True) os.makedirs(dirname, exist_ok=True) with open(verfilename, 'w') as outfile: - outfile.write(cmake_ver) + outfile.write( + json.dumps({ + 'cmake': cmake_ver, + 'python': python_ver + })) From 64b008c30415d42cd673797d40e5290e7aceaff4 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Fri, 9 Oct 2020 17:10:21 -0700 Subject: [PATCH 231/417] Bringing over more c++ stuff --- .efrocachemap | 20 +- .idea/dictionaries/ericf.xml | 14 +- assets/src/ba_data/python/ba/_coopgame.py | 3 +- .../ba_data/python/ba/_freeforallsession.py | 6 +- assets/src/ba_data/python/ba/_gameresults.py | 4 +- assets/src/ba_data/python/ba/_hooks.py | 5 - assets/src/ba_data/python/ba/_store.py | 5 +- .../ba_data/python/bastd/activity/coopjoin.py | 4 +- .../python/bastd/activity/coopscore.py | 3 +- .../python/bastd/ui/playlist/browser.py | 3 +- .../bastd/ui/playlist/customizebrowser.py | 3 +- .../python/bastd/ui/profile/browser.py | 3 +- .../python/bastd/ui/soundtrack/browser.py | 3 +- docs/ba_module.md | 2 +- src/ballistica/ballistica.cc | 2 +- src/ballistica/ballistica.h | 27 +- src/ballistica/game/game.h | 31 +- src/ballistica/generic/utils.cc | 124 - src/ballistica/generic/utils.h | 22 - src/ballistica/input/device/input_device.cc | 10 +- src/ballistica/python/class/python_class.cc | 69 + src/ballistica/python/class/python_class.h | 28 + .../class/python_class_activity_data.cc | 183 ++ .../python/class/python_class_activity_data.h | 39 + .../class/python_class_collide_model.cc | 110 + .../python/class/python_class_collide_model.h | 34 + .../python/class/python_class_context.cc | 227 ++ .../python/class/python_class_context.h | 37 + .../python/class/python_class_context_call.cc | 130 + .../python/class/python_class_context_call.h | 33 + .../python/class/python_class_data.cc | 139 + .../python/class/python_class_data.h | 36 + .../python/class/python_class_input_device.cc | 446 +++ .../python/class/python_class_input_device.h | 52 + .../python/class/python_class_material.cc | 712 +++++ .../python/class/python_class_material.h | 46 + .../python/class/python_class_model.cc | 109 + .../python/class/python_class_model.h | 34 + .../python/class/python_class_node.cc | 458 +++ .../python/class/python_class_node.h | 52 + .../python/class/python_class_session_data.cc | 114 + .../python/class/python_class_session_data.h | 36 + .../class/python_class_session_player.cc | 746 +++++ .../class/python_class_session_player.h | 62 + .../python/class/python_class_sound.cc | 108 + .../python/class/python_class_sound.h | 34 + .../python/class/python_class_texture.cc | 109 + .../python/class/python_class_texture.h | 34 + .../python/class/python_class_timer.cc | 195 ++ .../python/class/python_class_timer.h | 35 + .../python/class/python_class_vec3.cc | 350 +++ .../python/class/python_class_vec3.h | 49 + .../python/class/python_class_widget.cc | 288 ++ .../python/class/python_class_widget.h | 45 + .../python/methods/python_methods_app.cc | 1196 ++++++++ .../python/methods/python_methods_app.h | 17 + .../python/methods/python_methods_gameplay.cc | 765 +++++ .../python/methods/python_methods_gameplay.h | 17 + .../python/methods/python_methods_graphics.cc | 315 ++ .../python/methods/python_methods_graphics.h | 17 + .../python/methods/python_methods_input.cc | 394 +++ .../python/methods/python_methods_input.h | 18 + .../python/methods/python_methods_media.cc | 563 ++++ .../python/methods/python_methods_media.h | 18 + .../methods/python_methods_networking.cc | 610 ++++ .../methods/python_methods_networking.h | 18 + .../python/methods/python_methods_system.cc | 1031 +++++++ .../python/methods/python_methods_system.h | 18 + .../python/methods/python_methods_ui.cc | 2710 +++++++++++++++++ .../python/methods/python_methods_ui.h | 18 + src/ballistica/python/python.h | 420 +++ src/ballistica/python/python_command.cc | 202 ++ src/ballistica/python/python_command.h | 73 + src/ballistica/python/python_context_call.cc | 135 + src/ballistica/python/python_context_call.h | 54 + .../python/python_context_call_runnable.h | 25 + src/ballistica/python/python_ref.cc | 185 ++ src/ballistica/python/python_ref.h | 130 + src/ballistica/python/python_sys.h | 84 + tools/batools/build.py | 4 +- tools/efro/util.py | 42 + 81 files changed, 14338 insertions(+), 214 deletions(-) create mode 100644 src/ballistica/python/class/python_class.cc create mode 100644 src/ballistica/python/class/python_class.h create mode 100644 src/ballistica/python/class/python_class_activity_data.cc create mode 100644 src/ballistica/python/class/python_class_activity_data.h create mode 100644 src/ballistica/python/class/python_class_collide_model.cc create mode 100644 src/ballistica/python/class/python_class_collide_model.h create mode 100644 src/ballistica/python/class/python_class_context.cc create mode 100644 src/ballistica/python/class/python_class_context.h create mode 100644 src/ballistica/python/class/python_class_context_call.cc create mode 100644 src/ballistica/python/class/python_class_context_call.h create mode 100644 src/ballistica/python/class/python_class_data.cc create mode 100644 src/ballistica/python/class/python_class_data.h create mode 100644 src/ballistica/python/class/python_class_input_device.cc create mode 100644 src/ballistica/python/class/python_class_input_device.h create mode 100644 src/ballistica/python/class/python_class_material.cc create mode 100644 src/ballistica/python/class/python_class_material.h create mode 100644 src/ballistica/python/class/python_class_model.cc create mode 100644 src/ballistica/python/class/python_class_model.h create mode 100644 src/ballistica/python/class/python_class_node.cc create mode 100644 src/ballistica/python/class/python_class_node.h create mode 100644 src/ballistica/python/class/python_class_session_data.cc create mode 100644 src/ballistica/python/class/python_class_session_data.h create mode 100644 src/ballistica/python/class/python_class_session_player.cc create mode 100644 src/ballistica/python/class/python_class_session_player.h create mode 100644 src/ballistica/python/class/python_class_sound.cc create mode 100644 src/ballistica/python/class/python_class_sound.h create mode 100644 src/ballistica/python/class/python_class_texture.cc create mode 100644 src/ballistica/python/class/python_class_texture.h create mode 100644 src/ballistica/python/class/python_class_timer.cc create mode 100644 src/ballistica/python/class/python_class_timer.h create mode 100644 src/ballistica/python/class/python_class_vec3.cc create mode 100644 src/ballistica/python/class/python_class_vec3.h create mode 100644 src/ballistica/python/class/python_class_widget.cc create mode 100644 src/ballistica/python/class/python_class_widget.h create mode 100644 src/ballistica/python/methods/python_methods_app.cc create mode 100644 src/ballistica/python/methods/python_methods_app.h create mode 100644 src/ballistica/python/methods/python_methods_gameplay.cc create mode 100644 src/ballistica/python/methods/python_methods_gameplay.h create mode 100644 src/ballistica/python/methods/python_methods_graphics.cc create mode 100644 src/ballistica/python/methods/python_methods_graphics.h create mode 100644 src/ballistica/python/methods/python_methods_input.cc create mode 100644 src/ballistica/python/methods/python_methods_input.h create mode 100644 src/ballistica/python/methods/python_methods_media.cc create mode 100644 src/ballistica/python/methods/python_methods_media.h create mode 100644 src/ballistica/python/methods/python_methods_networking.cc create mode 100644 src/ballistica/python/methods/python_methods_networking.h create mode 100644 src/ballistica/python/methods/python_methods_system.cc create mode 100644 src/ballistica/python/methods/python_methods_system.h create mode 100644 src/ballistica/python/methods/python_methods_ui.cc create mode 100644 src/ballistica/python/methods/python_methods_ui.h create mode 100644 src/ballistica/python/python.h create mode 100644 src/ballistica/python/python_command.cc create mode 100644 src/ballistica/python/python_command.h create mode 100644 src/ballistica/python/python_context_call.cc create mode 100644 src/ballistica/python/python_context_call.h create mode 100644 src/ballistica/python/python_context_call_runnable.h create mode 100644 src/ballistica/python/python_ref.cc create mode 100644 src/ballistica/python/python_ref.h create mode 100644 src/ballistica/python/python_sys.h diff --git a/.efrocachemap b/.efrocachemap index b662c580..c3d10c8a 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6e/7e/56adde97a5cb545933bdd52700d9", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3c/f9/d971d471660647f1eacb768f0d10", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ef/b7/aa17c70752baab2bd4ea970b7b2d", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/43/77/27920088a7fb8490a833623894a1", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/70/3a/36ff319dbed727b6bd148073e278", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/83/81/5d46cb2627d0ae1f0c59a9dd123a", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/3a/8f/502e7fef458bb05da2864f4724ea", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/60/38/2d0e9f0cf486bae30056f3d3c11a", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/37/a6/ae4e2bf9c60fc0cbfd66136dc344", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/02/f4/907cfc73510e071f9ab5ca914646" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/43/efceea678ab45ebe36c72ff6fa79", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/15/d5/29d9b25931f5c91a7a0db8cd6260", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bc/bf/286df9a4a78d01c5bd02bee224cd", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/24/d5/6f25f7ffbdcf3dde835ca8213544", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/d1/f745c2663299168c982f752802d0", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9b/dd/90e274f18a93c82e9c2c29a59b41", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9d/9a/c14692e42e5a7376b665af6a8463", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2a/c8/f661b157edda3920f8834124d24b", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7e/ed/5db67414f8d9444f91631a448bc0", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7d/9f/9ff4e4c2d64c3dfac362f2b5af15" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index cc801a97..37848787 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -29,8 +29,8 @@ achname achs acinstance - ack ack'ed + ack acked acks acnt @@ -100,6 +100,7 @@ asdict aspx assertnode + asserttype assetbundle assetcache assetdata @@ -151,8 +152,8 @@ bacommon badguy bafoundation - ballistica ballistica's + ballistica ballisticacore ballisticacorecb bamaster @@ -313,6 +314,7 @@ checkpaths checkroundover checksums + checktype childnode chinesetraditional chipfork @@ -793,8 +795,8 @@ gamedata gameinstance gamemap - gamepad gamepad's + gamepad gamepadadvanced gamepads gamepadselect @@ -1177,8 +1179,8 @@ lsqlite lssl lstart - lstr lstr's + lstr lstrs lsval ltex @@ -1803,8 +1805,8 @@ sessionname sessionplayer sessionplayers - sessionteam sessionteam's + sessionteam sessionteams sessiontype setactivity @@ -2135,8 +2137,8 @@ txtw typeargs typecheck - typechecker typechecker's + typechecker typedval typeshed typestr diff --git a/assets/src/ba_data/python/ba/_coopgame.py b/assets/src/ba_data/python/ba/_coopgame.py index d04c2c69..f1a516f3 100644 --- a/assets/src/ba_data/python/ba/_coopgame.py +++ b/assets/src/ba_data/python/ba/_coopgame.py @@ -67,6 +67,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): def _show_standard_scores_to_beat_ui(self, scores: List[Dict[str, Any]]) -> None: + from efro.util import asserttype from ba._gameutils import timestring, animate from ba._nodeactor import NodeActor from ba._enums import TimeFormat @@ -74,7 +75,7 @@ class CoopGameActivity(GameActivity[PlayerType, TeamType]): if scores is not None: # Sort by originating date so that the most recent is first. - scores.sort(reverse=True, key=lambda s: s['time']) + scores.sort(reverse=True, key=lambda s: asserttype(s['time'], int)) # Now make a display for the most recent challenge. for score in scores: diff --git a/assets/src/ba_data/python/ba/_freeforallsession.py b/assets/src/ba_data/python/ba/_freeforallsession.py index 73304cc5..e81eb47d 100644 --- a/assets/src/ba_data/python/ba/_freeforallsession.py +++ b/assets/src/ba_data/python/ba/_freeforallsession.py @@ -53,6 +53,7 @@ class FreeForAllSession(MultiTeamSession): def _switch_to_score_screen(self, results: ba.GameResults) -> None: # pylint: disable=cyclic-import + from efro.util import asserttype from bastd.activity.drawscore import DrawScoreScreenActivity from bastd.activity.multiteamvictory import ( TeamSeriesVictoryScoreScreenActivity) @@ -80,8 +81,9 @@ class FreeForAllSession(MultiTeamSession): team for team in self.sessionteams if team.customdata['score'] >= self._ffa_series_length ] - series_winners.sort(reverse=True, - key=lambda tm: (tm.customdata['score'])) + series_winners.sort( + reverse=True, + key=lambda t: asserttype(t.customdata['score'], int)) if (len(series_winners) == 1 or (len(series_winners) > 1 and series_winners[0].customdata['score'] != diff --git a/assets/src/ba_data/python/ba/_gameresults.py b/assets/src/ba_data/python/ba/_gameresults.py index 65bd3ef8..563c9527 100644 --- a/assets/src/ba_data/python/ba/_gameresults.py +++ b/assets/src/ba_data/python/ba/_gameresults.py @@ -8,6 +8,7 @@ import weakref from dataclasses import dataclass from typing import TYPE_CHECKING +from efro.util import asserttype from ba._team import Team, SessionTeam if TYPE_CHECKING: @@ -187,7 +188,8 @@ class GameResults: sval.append(team) results: List[Tuple[Optional[int], List[ba.SessionTeam]]] = list(winners.items()) - results.sort(reverse=not self._lower_is_better, key=lambda x: x[0]) + results.sort(reverse=not self._lower_is_better, + key=lambda x: asserttype(x[0], int)) # Also group the 'None' scores. none_sessionteams: List[ba.SessionTeam] = [] diff --git a/assets/src/ba_data/python/ba/_hooks.py b/assets/src/ba_data/python/ba/_hooks.py index 368d35ca..1365329a 100644 --- a/assets/src/ba_data/python/ba/_hooks.py +++ b/assets/src/ba_data/python/ba/_hooks.py @@ -328,11 +328,6 @@ def local_chat_message(msg: str) -> None: _ba.app.ui.party_window().on_chat_message(msg) -def handle_remote_achievement_list(completed_achievements: List[str]) -> None: - from ba import _achievement - _achievement.set_completed_achievements(completed_achievements) - - def get_player_icon(sessionplayer: ba.SessionPlayer) -> Dict[str, Any]: info = sessionplayer.get_icon_info() return { diff --git a/assets/src/ba_data/python/ba/_store.py b/assets/src/ba_data/python/ba/_store.py index 09252e47..9bf0ec38 100644 --- a/assets/src/ba_data/python/ba/_store.py +++ b/assets/src/ba_data/python/ba/_store.py @@ -500,8 +500,9 @@ def get_available_sale_time(tab: str) -> Optional[int]: if to_end > 0: sale_times.append(int(to_end * 1000)) - # Return the smallest time i guess? - return min(sale_times) if sale_times else None + # Return the smallest time I guess? + sale_times_int = [t for t in sale_times if isinstance(t, int)] + return min(sale_times_int) if sale_times_int else None except Exception: from ba import _error diff --git a/assets/src/ba_data/python/bastd/activity/coopjoin.py b/assets/src/ba_data/python/bastd/activity/coopjoin.py index 9e63747a..3a62e68b 100644 --- a/assets/src/ba_data/python/bastd/activity/coopjoin.py +++ b/assets/src/ba_data/python/bastd/activity/coopjoin.py @@ -57,12 +57,14 @@ class CoopJoinActivity(JoinActivity): scores: Optional[List[Dict[str, Any]]]) -> None: # pylint: disable=too-many-locals # pylint: disable=too-many-statements + from efro.util import asserttype from bastd.actor.text import Text from ba.internal import get_achievements_for_coop_level # Sort by originating date so that the most recent is first. if scores is not None: - scores.sort(reverse=True, key=lambda score: score['time']) + scores.sort(reverse=True, + key=lambda score: asserttype(score['time'], int)) # We only show achievements and challenges for CoopGameActivities. session = self.session diff --git a/assets/src/ba_data/python/bastd/activity/coopscore.py b/assets/src/ba_data/python/bastd/activity/coopscore.py index 15d1c9fe..a870f8f9 100644 --- a/assets/src/ba_data/python/bastd/activity/coopscore.py +++ b/assets/src/ba_data/python/bastd/activity/coopscore.py @@ -873,6 +873,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): # pylint: disable=too-many-locals # pylint: disable=too-many-branches # pylint: disable=too-many-statements + from efro.util import asserttype # delay a bit if results come in too fast assert self._begin_time is not None base_delay = max(0, 1.9 - (ba.time() - self._begin_time)) @@ -909,7 +910,7 @@ class CoopScoreScreen(ba.Activity[ba.Player, ba.Team]): break results.append(our_score_entry) results.sort(reverse=self._score_order == 'increasing', - key=lambda x: x[0]) + key=lambda x: asserttype(x[0], int)) # If we're not submitting our own score, we still want to change the # name of our own score to 'Me'. diff --git a/assets/src/ba_data/python/bastd/ui/playlist/browser.py b/assets/src/ba_data/python/bastd/ui/playlist/browser.py index af37ace9..284ff31f 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/browser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/browser.py @@ -284,6 +284,7 @@ class PlaylistBrowserWindow(ba.Window): # pylint: disable=too-many-branches # pylint: disable=too-many-locals # pylint: disable=too-many-nested-blocks + from efro.util import asserttype from ba.internal import (get_map_class, get_default_free_for_all_playlist, get_default_teams_playlist, filter_playlist) @@ -303,7 +304,7 @@ class PlaylistBrowserWindow(ba.Window): items = [(i[0].decode(), i[1]) if not isinstance(i[0], str) else i for i in items] - items.sort(key=lambda x2: x2[0].lower()) + items.sort(key=lambda x2: asserttype(x2[0], str).lower()) items = [['__default__', None]] + items # default is always first count = len(items) diff --git a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py index f743e412..8387c12a 100644 --- a/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py +++ b/assets/src/ba_data/python/bastd/ui/playlist/customizebrowser.py @@ -299,6 +299,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): _ba.lock_all_input() def _refresh(self, select_playlist: str = None) -> None: + from efro.util import asserttype old_selection = self._selected_playlist_name # If there was no prev selection, look in prefs. @@ -318,7 +319,7 @@ class PlaylistCustomizeBrowserWindow(ba.Window): items = [(i[0].decode(), i[1]) if not isinstance(i[0], str) else i for i in items] - items.sort(key=lambda x: x[0].lower()) + items.sort(key=lambda x: asserttype(x[0], str).lower()) items = [['__default__', None]] + items # Default is always first. index = 0 diff --git a/assets/src/ba_data/python/bastd/ui/profile/browser.py b/assets/src/ba_data/python/bastd/ui/profile/browser.py index ca67d641..6521b815 100644 --- a/assets/src/ba_data/python/bastd/ui/profile/browser.py +++ b/assets/src/ba_data/python/bastd/ui/profile/browser.py @@ -270,6 +270,7 @@ class ProfileBrowserWindow(ba.Window): def _refresh(self) -> None: # pylint: disable=too-many-locals + from efro.util import asserttype from ba.internal import (PlayerProfilesChangedMessage, get_player_profile_colors, get_player_profile_icon) @@ -281,7 +282,7 @@ class ProfileBrowserWindow(ba.Window): self._profiles = ba.app.config.get('Player Profiles', {}) assert self._profiles is not None items = list(self._profiles.items()) - items.sort(key=lambda x: x[0].lower()) + items.sort(key=lambda x: asserttype(x[0], str).lower()) index = 0 account_name: Optional[str] if _ba.get_account_state() == 'signed_in': diff --git a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py index 3fcb5d89..ffb6898f 100644 --- a/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py +++ b/assets/src/ba_data/python/bastd/ui/soundtrack/browser.py @@ -362,6 +362,7 @@ class SoundtrackBrowserWindow(ba.Window): return ba.Lstr(value=soundtrack) def _refresh(self, select_soundtrack: str = None) -> None: + from efro.util import asserttype self._allow_changing_soundtracks = False old_selection = self._selected_soundtrack @@ -377,7 +378,7 @@ class SoundtrackBrowserWindow(ba.Window): self._soundtracks = ba.app.config.get('Soundtracks', {}) assert self._soundtracks is not None items = list(self._soundtracks.items()) - items.sort(key=lambda x: x[0].lower()) + items.sort(key=lambda x: asserttype(x[0], str).lower()) items = [('__default__', None)] + items # default is always first index = 0 for pname, _pval in items: diff --git a/docs/ba_module.md b/docs/ba_module.md index 8f282d8e..4b1bcdc7 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-10-09 for Ballistica version 1.5.26 build 20195

    +

    last updated on 2020-10-09 for Ballistica version 1.5.26 build 20198

    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!


    diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index a977a442..1ba009e9 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,7 +29,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20196; +const int kAppBuildNumber = 20198; const char* kAppVersion = "1.5.26"; // Our standalone globals. diff --git a/src/ballistica/ballistica.h b/src/ballistica/ballistica.h index ec319921..f4c05fe0 100644 --- a/src/ballistica/ballistica.h +++ b/src/ballistica/ballistica.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -151,10 +152,32 @@ auto GetUniqueSessionIdentifier() -> const std::string&; /// Have our main threads/modules all been inited yet? auto IsBootstrapped() -> bool; -/// Create/init our internal (non-public) parts. +/// Internal bits. auto CreateAppInternal() -> AppInternal*; -auto AppInternalGameThreadInit() -> void; +auto AppInternalPythonInit() -> PyObject*; +auto AppInternalPythonInit2() -> void; auto AppInternalHasBlessingHash() -> bool; +auto AppInternalPutLog(bool fatal) -> bool; +auto AppInternalAwardAdTickets() -> void; +auto AppInternalAwardAdTournamentEntry() -> void; +auto AppInternalSetAdCompletionCall(PyObject* obj, bool pass_actually_showed) + -> void; +auto AppInternalPushAdViewComplete(const std::string& purpose, + bool actually_showed) -> void; +auto AppInternalPushPublicPartyState() -> void; +auto AppInternalPushSetFriendListCall(const std::vector& friends) + -> void; +auto AppInternalDispatchRemoteAchievementList(const std::set& achs) + -> void; +auto AppInternalPushAnalyticsCall(const std::string& type, int increment) + -> void; +auto AppInternalPushPurchaseTransactionCall(const std::string& item, + const std::string& receipt, + const std::string& signature, + const std::string& order_id, + bool user_initiated) -> void; +auto AppInternalGetPublicAccountID() -> std::string; +auto AppInternalOnGameThreadPause() -> void; /// Does it appear that we are a blessed build with no known user-modifications? auto IsUnmodifiedBlessedBuild() -> bool; diff --git a/src/ballistica/game/game.h b/src/ballistica/game/game.h index c913b37b..c09334eb 100644 --- a/src/ballistica/game/game.h +++ b/src/ballistica/game/game.h @@ -36,16 +36,8 @@ class Game : public Module { const std::string& account_id) -> void; auto PushSetAccountTokenCall(const std::string& account_id, const std::string& token) -> void; - auto PushAdViewCompleteCall(const std::string& purpose, bool actually_showed) - -> void; - auto PushAnalyticsCall(const std::string& type, int increment) -> void; auto PushAwardAdTicketsCall() -> void; auto PushAwardAdTournamentEntryCall() -> void; - auto PushPurchaseTransactionCall(const std::string& item, - const std::string& receipt, - const std::string& signature, - const std::string& order_id, - bool user_initiated) -> void; auto PushUDPConnectionPacketCall(const std::vector& data, const SockAddr& addr) -> void; auto PushPartyInviteCall(const std::string& name, @@ -78,7 +70,6 @@ class Game : public Module { auto PushHavePendingLoadsDoneCall() -> void; auto PushFreeMediaComponentRefsCall( const std::vector*>& components) -> void; - auto PushSetFriendListCall(const std::vector& friends) -> void; auto PushHavePendingLoadsCall() -> void; auto PushShutdownCall(bool soft) -> void; @@ -289,10 +280,6 @@ class Game : public Module { auto LocalDisplayChatMessage(const std::vector& buffer) -> void; auto ShouldAnnouncePartyJoinsAndLeaves() -> bool; - auto SetAdCompletionCall(PyObject* obj, bool pass_actually_showed) -> void; - auto CallAdCompletionCall(bool actually_showed) -> void; - auto RunGeneralAdComplete(bool actually_watched) -> void; - auto StartKickVote(ConnectionToClient* starter, ConnectionToClient* target) -> void; auto require_client_authentication() const { @@ -330,6 +317,15 @@ class Game : public Module { auto public_party_size() const { return public_party_size_; } auto SetPublicPartySize(int count) -> void; auto public_party_max_size() const { return public_party_max_size_; } + auto public_party_max_player_count() const { + return public_party_max_player_count_; + } + auto public_party_min_league() const -> const std::string& { + return public_party_min_league_; + } + auto public_party_stats_url() const -> const std::string& { + return public_party_stats_url_; + } auto SetPublicPartyMaxSize(int count) -> void; auto SetPublicPartyName(const std::string& name) -> void; auto SetPublicPartyStatsURL(const std::string& name) -> void; @@ -341,14 +337,9 @@ class Game : public Module { private: auto InitSpecialChars() -> void; auto AdViewComplete(const std::string& purpose, bool actually_showed) -> void; - auto Analytics(const std::string& type, int increment) -> void; auto AwardAdTickets() -> void; auto AwardAdTournamentEntry() -> void; auto Draw() -> void; - auto PurchaseTransaction(const std::string& item, const std::string& receipt, - const std::string& signature, - const std::string& order_id, bool user_initiated) - -> void; auto UDPConnectionPacket(const std::vector& data, const SockAddr& addr) -> void; auto PartyInvite(const std::string& name, const std::string& invite_id) @@ -384,7 +375,6 @@ class Game : public Module { auto GetGameRosterMessage() -> std::vector; auto CleanUpBeforeConnectingToHost() -> void; auto Shutdown(bool soft) -> void; - auto PushPublicPartyState() -> void; std::map google_play_id_to_client_id_map_; std::map client_id_to_google_play_id_map_; @@ -446,9 +436,6 @@ class Game : public Module { int last_kick_votes_needed_{-1}; Object::WeakRef kick_vote_starter_; Object::WeakRef kick_vote_target_; - Object::Ref ad_completion_callback_; - millisecs_t last_ad_start_time_{}; - bool ad_completion_callback_pass_actually_showed_{}; bool public_party_enabled_{false}; int public_party_size_{1}; // Always count ourself (is that what we want?). int public_party_max_size_{8}; diff --git a/src/ballistica/generic/utils.cc b/src/ballistica/generic/utils.cc index fbe93847..8788a98c 100644 --- a/src/ballistica/generic/utils.cc +++ b/src/ballistica/generic/utils.cc @@ -461,130 +461,6 @@ void Utils::SetRandomNameList(const std::list& custom_names) { } } -#define HEXVAL(x) ('0' + (x) + ((x) > 9u) * 7u) -static auto ToHex(const std::string& s_in) -> std::string { - uint32_t s_size = static_cast(s_in.size()); - std::string s_out; - s_out.resize(static_cast(s_size) * 2); - for (uint32_t i = 0; i < s_size; i++) { - s_out[i * 2] = - static_cast(HEXVAL((static_cast(s_in[i])) >> 4u)); - s_out[i * 2 + 1] = - static_cast(HEXVAL((static_cast(s_in[i]) & 15u))); - } - return s_out; -} -#undef HEXVAL - -static auto FromHex(const std::string& s_in) -> std::string { - int s_size = static_cast(s_in.size()); - BA_PRECONDITION(s_size % 2 == 0); - s_size /= 2; - std::string s_out; - s_out.resize(static_cast(s_size)); - for (int i = 0; i < s_size; i++) { - auto val = (uint32_t)s_in[i * 2]; // NOLINT(cert-str34-c) - if (val >= '0' && val <= '9') { - s_out[i] = static_cast((val - '0') << 4u); - } else if (val >= 'A' && val <= 'F') { - s_out[i] = static_cast((10u + (val - 'A')) << 4u); - } else { - throw Exception(); - } - val = (uint32_t)s_in[i * 2 + 1]; // NOLINT(cert-str34-c) - if (val >= '0' && val <= '9') { - s_out[i] = - static_cast(static_cast(s_out[i]) | (val - '0')); - } else if (val >= 'A' && val <= 'F') { - s_out[i] = static_cast(static_cast(s_out[i]) - | (10 + (val - 'A'))); - } else { - throw Exception(); - } - } - return s_out; -} - -static auto EncryptDecrypt(const std::string& to_encrypt) -> std::string { - assert(g_platform); - const char* key = g_platform->GetUniqueDeviceIdentifier().c_str(); - int key_size = - static_cast(g_platform->GetUniqueDeviceIdentifier().size()); - std::string output = to_encrypt; - for (size_t i = 0; i < to_encrypt.size(); i++) { - output[i] = to_encrypt[i] ^ key[i % (key_size)]; // NOLINT - } - return output; -} - -static auto EncryptDecryptCustom(const std::string& to_encrypt, - const std::string& key_in) -> std::string { - assert(g_platform); - const char* key = key_in.c_str(); - int key_size = static_cast(key_in.size()); - std::string output = to_encrypt; - for (size_t i = 0; i < to_encrypt.size(); i++) { - output[i] = to_encrypt[i] ^ key[i % (key_size)]; // NOLINT - } - return output; -} - -static auto PublicEncryptDecrypt(const std::string& to_encrypt) -> std::string { - std::string key_str = "create an account"; // A non-key-looking key. - const char* key = key_str.c_str(); - int key_size = static_cast(key_str.size()); - std::string output = to_encrypt; - for (size_t i = 0; i < to_encrypt.size(); i++) - output[i] = to_encrypt[i] ^ key[i % (key_size)]; // NOLINT - return output; -} - -auto Utils::LocalEncrypt(const std::string& s_in) -> std::string { - return ToHex(EncryptDecrypt(s_in)); -} - -auto Utils::LocalEncrypt2(const std::string& s_in) -> std::string { - std::string s = EncryptDecrypt(s_in); - return base64_encode((const unsigned char*)s.c_str(), - static_cast(s.size())); -} -auto Utils::EncryptCustom(const std::string& s_in, const std::string& key) - -> std::string { - std::string s = EncryptDecryptCustom(s_in, key); - return base64_encode((const unsigned char*)s.c_str(), - static_cast(s.size())); -} - -auto Utils::LocalDecrypt(const std::string& s_in) -> std::string { - return EncryptDecrypt(FromHex(s_in)); -} - -auto Utils::LocalDecrypt2(const std::string& s_in) -> std::string { - return EncryptDecrypt(base64_decode(s_in)); -} -auto Utils::DecryptCustom(const std::string& s_in, const std::string& key) - -> std::string { - return EncryptDecryptCustom(base64_decode(s_in), key); -} - -auto Utils::PublicEncrypt(const std::string& s_in) -> std::string { - return ToHex(PublicEncryptDecrypt(s_in)); -} - -auto Utils::PublicDecrypt(const std::string& s_in) -> std::string { - return PublicEncryptDecrypt(FromHex(s_in)); -} - -auto Utils::PublicEncrypt2(const std::string& s_in) -> std::string { - std::string s = PublicEncryptDecrypt(s_in); - return base64_encode((const unsigned char*)s.c_str(), - static_cast(s.size())); -} - -auto Utils::PublicDecrypt2(const std::string& s_in) -> std::string { - return PublicEncryptDecrypt(base64_decode(s_in)); -} - auto Utils::Sphrand(float radius) -> Vector3f { while (true) { float x = RandomFloat(); diff --git a/src/ballistica/generic/utils.h b/src/ballistica/generic/utils.h index 8d401297..45117d82 100644 --- a/src/ballistica/generic/utils.h +++ b/src/ballistica/generic/utils.h @@ -343,28 +343,6 @@ class Utils { static float precalc_rands_3[]; auto huffman() -> Huffman* { return huffman_.get(); } - /// Encrypt a string in a manner specific to this device. - static auto LocalEncrypt(const std::string& s) -> std::string; - static auto LocalEncrypt2(const std::string& s) -> std::string; - - /// Decode a local string that was encoded specific to this device. - /// Throws an exception on failure. - static auto LocalDecrypt(const std::string& s) -> std::string; - static auto LocalDecrypt2(const std::string& s) -> std::string; - - /// Encrypt a string using a custom key. - static auto EncryptCustom(const std::string& s, const std::string& key) - -> std::string; - /// Decrypt a string using a custom key. - static auto DecryptCustom(const std::string& s, const std::string& key) - -> std::string; - - /// Encrypt/decrypt strings to send to the master-server - static auto PublicEncrypt(const std::string& s) -> std::string; - static auto PublicDecrypt(const std::string& s) -> std::string; - static auto PublicEncrypt2(const std::string& s) -> std::string; - static auto PublicDecrypt2(const std::string& s) -> std::string; - // FIXME - move to a nice math-y place static auto Sphrand(float radius = 1.0f) -> Vector3f; diff --git a/src/ballistica/input/device/input_device.cc b/src/ballistica/input/device/input_device.cc index e0cb0215..a47a9a11 100644 --- a/src/ballistica/input/device/input_device.cc +++ b/src/ballistica/input/device/input_device.cc @@ -78,14 +78,10 @@ auto InputDevice::GetPlayerProfiles() const -> PyObject* { return nullptr; } auto InputDevice::GetPublicAccountID() const -> std::string { assert(InGameThread()); - // this default implementation assumes the device is local - // so just returns the locally signed in account's public id.. + // This default implementation assumes the device is local + // so just returns the locally signed in account's public id. - // the master-server makes our public account-id available to us - // through a misc-read-val; look for that.. - std::string pub_id = - g_python->GetAccountMiscReadVal2String("resolvedAccountID"); - return pub_id; + return AppInternalGetPublicAccountID(); } auto InputDevice::GetAccountName(bool full) const -> std::string { diff --git a/src/ballistica/python/class/python_class.cc b/src/ballistica/python/class/python_class.cc new file mode 100644 index 00000000..38316058 --- /dev/null +++ b/src/ballistica/python/class/python_class.cc @@ -0,0 +1,69 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class.h" + +#include "ballistica/ballistica.h" + +namespace ballistica { + +void PythonClass::SetupType(PyTypeObject* obj) { + PyTypeObject t = { + PyVarObject_HEAD_INIT(nullptr, 0) + // .tp_name = "ba.Object", + // .tp_basicsize = sizeof(PythonClass), + // .tp_itemsize = 0, + // .tp_dealloc = (destructor)tp_dealloc, + // .tp_repr = (reprfunc)tp_repr, + // .tp_getattro = (getattrofunc)tp_getattro, + // .tp_setattro = (setattrofunc)tp_setattro, + // .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + // .tp_doc = "A ballistica object.", + // .tp_new = tp_new, + }; + + // python samples use the initializer style above, but it fails + // in g++ and sounds like it might not be allowed in c++ anyway, + // ..so this is close enough... + // (and still more readable than setting ALL values positionally) + assert(t.tp_itemsize == 0); // should all be zeroed though.. + t.tp_name = "ba.Object"; + t.tp_basicsize = sizeof(PythonClass); + t.tp_itemsize = 0; + t.tp_dealloc = (destructor)tp_dealloc; + // t.tp_repr = (reprfunc)tp_repr; + t.tp_getattro = (getattrofunc)tp_getattro; + t.tp_setattro = (setattrofunc)tp_setattro; + // NOLINTNEXTLINE (signed bitwise ops) + t.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + t.tp_doc = "A ballistica object."; + t.tp_new = tp_new; + + memcpy(obj, &t, sizeof(t)); +} + +auto PythonClass::tp_repr(PythonClass* self) -> PyObject* { + BA_PYTHON_TRY; + return Py_BuildValue("s", ""); + BA_PYTHON_CATCH; +} +auto PythonClass::tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + return reinterpret_cast(self); +} +void PythonClass::tp_dealloc(PythonClass* self) { + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} +auto PythonClass::tp_getattro(PythonClass* node, PyObject* attr) -> PyObject* { + BA_PYTHON_TRY; + return PyObject_GenericGetAttr(reinterpret_cast(node), attr); + BA_PYTHON_CATCH; +} +auto PythonClass::tp_setattro(PythonClass* node, PyObject* attr, PyObject* val) + -> int { + BA_PYTHON_TRY; + return PyObject_GenericSetAttr(reinterpret_cast(node), attr, val); + BA_PYTHON_INT_CATCH; +} + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class.h b/src/ballistica/python/class/python_class.h new file mode 100644 index 00000000..b25834b2 --- /dev/null +++ b/src/ballistica/python/class/python_class.h @@ -0,0 +1,28 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +// a convenient base class for defining custom python types +class PythonClass { + public: + PyObject_HEAD; + static void SetupType(PyTypeObject* obj); + + private: + static auto tp_repr(PythonClass* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject*; + static void tp_dealloc(PythonClass* self); + static auto tp_getattro(PythonClass* node, PyObject* attr) -> PyObject*; + static auto tp_setattro(PythonClass* node, PyObject* attr, PyObject* val) + -> int; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_H_ diff --git a/src/ballistica/python/class/python_class_activity_data.cc b/src/ballistica/python/class/python_class_activity_data.cc new file mode 100644 index 00000000..793c539e --- /dev/null +++ b/src/ballistica/python/class/python_class_activity_data.cc @@ -0,0 +1,183 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_activity_data.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/generic/utils.h" + +namespace ballistica { + +auto PythonClassActivityData::nb_bool(PythonClassActivityData* self) -> int { + return self->host_activity_->exists(); +} + +PyNumberMethods PythonClassActivityData::as_number_; + +void PythonClassActivityData::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "_ba.ActivityData"; + obj->tp_basicsize = sizeof(PythonClassActivityData); + obj->tp_doc = "(internal)"; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + + // We provide number methods only for bool functionality. + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_bool = (inquiry)nb_bool; + obj->tp_as_number = &as_number_; +} + +auto PythonClassActivityData::Create(HostActivity* host_activity) -> PyObject* { + auto* py_activity_data = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + BA_PRECONDITION(py_activity_data); + *(py_activity_data->host_activity_) = host_activity; + return reinterpret_cast(py_activity_data); +} + +auto PythonClassActivityData::GetHostActivity() const -> HostActivity* { + HostActivity* host_activity = host_activity_->get(); + if (!host_activity) + throw Exception( + "Invalid ActivityData; this activity has probably been expired and " + "should not be getting used."); + return host_activity; +} + +auto PythonClassActivityData::tp_repr(PythonClassActivityData* self) + -> PyObject* { + BA_PYTHON_TRY; + return Py_BuildValue( + "s", (std::string("host_activity_->get()) + " >") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassActivityData::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = + reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + self->host_activity_ = new Object::WeakRef(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassActivityData::tp_dealloc(PythonClassActivityData* self) { + BA_PYTHON_TRY; + + // These have to be destructed in the game thread; send them along to + // it if need be; otherwise do it immediately. + if (!InGameThread()) { + Object::WeakRef* h = self->host_activity_; + g_game->PushCall([h] { delete h; }); + } else { + delete self->host_activity_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassActivityData::exists(PythonClassActivityData* self) + -> PyObject* { + BA_PYTHON_TRY; + + HostActivity* host_activity = self->host_activity_->get(); + if (host_activity) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + + BA_PYTHON_CATCH; +} + +auto PythonClassActivityData::make_foreground(PythonClassActivityData* self) + -> PyObject* { + BA_PYTHON_TRY; + + HostActivity* a = self->host_activity_->get(); + if (!a) { + throw Exception("Invalid activity.", PyExcType::kActivityNotFound); + } + HostSession* session = a->GetHostSession(); + if (!session) { + throw Exception("Activity's Session not found.", + PyExcType::kSessionNotFound); + } + session->SetForegroundHostActivity(a); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassActivityData::start(PythonClassActivityData* self) + -> PyObject* { + BA_PYTHON_TRY; + + HostActivity* a = self->host_activity_->get(); + if (!a) { + throw Exception("Invalid activity data.", PyExcType::kActivityNotFound); + } + a->start(); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassActivityData::expire(PythonClassActivityData* self) + -> PyObject* { + BA_PYTHON_TRY; + HostActivity* a = self->host_activity_->get(); + + // The python side may have stuck around after our c++ side was + // torn down; that's ok. + if (a) { + HostSession* session = a->GetHostSession(); + if (!session) { + throw Exception("Activity's Session not found.", + PyExcType::kSessionNotFound); + } + session->DestroyHostActivity(a); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyTypeObject PythonClassActivityData::type_obj; +PyMethodDef PythonClassActivityData::tp_methods[] = { + {"exists", (PyCFunction)exists, METH_NOARGS, + "exists() -> bool\n" + "\n" + "Returns whether the ActivityData still exists.\n" + "Most functionality will fail on a nonexistent instance."}, + {"make_foreground", (PyCFunction)make_foreground, METH_NOARGS, + "make_foreground() -> None\n" + "\n" + "Sets this activity as the foreground one in its session."}, + {"expire", (PyCFunction)expire, METH_NOARGS, + "expire() -> None\n" + "\n" + "Expires the internal data for the activity"}, + {"start", (PyCFunction)start, METH_NOARGS, + "start() -> None\n" + "\n" + "Begins the activity running"}, + {nullptr}}; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_activity_data.h b/src/ballistica/python/class/python_class_activity_data.h new file mode 100644 index 00000000..4da2a532 --- /dev/null +++ b/src/ballistica/python/class/python_class_activity_data.h @@ -0,0 +1,39 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_ACTIVITY_DATA_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_ACTIVITY_DATA_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassActivityData : public PythonClass { + public: + static auto type_name() -> const char* { return "ActivityData"; } + static void SetupType(PyTypeObject* obj); + static auto Create(HostActivity* host_activity) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto GetHostActivity() const -> HostActivity*; + + private: + static PyMethodDef tp_methods[]; + static auto tp_repr(PythonClassActivityData* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassActivityData* self); + static auto exists(PythonClassActivityData* self) -> PyObject*; + static auto make_foreground(PythonClassActivityData* self) -> PyObject*; + static auto start(PythonClassActivityData* self) -> PyObject*; + static auto expire(PythonClassActivityData* self) -> PyObject*; + Object::WeakRef* host_activity_; + static auto nb_bool(PythonClassActivityData* self) -> int; + static PyNumberMethods as_number_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_ACTIVITY_DATA_H_ diff --git a/src/ballistica/python/class/python_class_collide_model.cc b/src/ballistica/python/class/python_class_collide_model.cc new file mode 100644 index 00000000..8411b23a --- /dev/null +++ b/src/ballistica/python/class/python_class_collide_model.cc @@ -0,0 +1,110 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_collide_model.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/media/component/collide_model.h" + +namespace ballistica { + +auto PythonClassCollideModel::tp_repr(PythonClassCollideModel* self) + -> PyObject* { + BA_PYTHON_TRY; + Object::Ref m = *(self->collide_model_); + return Py_BuildValue( + "s", (std::string("name() + "\"") : "(empty ref)") + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +void PythonClassCollideModel::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.CollideModel"; + obj->tp_basicsize = sizeof(PythonClassCollideModel); + obj->tp_doc = + "A reference to a collide-model.\n" + "\n" + "Category: Asset Classes\n" + "\n" + "Use ba.getcollidemodel() to instantiate one."; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; +} + +auto PythonClassCollideModel::Create(CollideModel* collide_model) -> PyObject* { + s_create_empty_ = true; // prevent class from erroring on create + auto* t = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!t) { + throw Exception("ba.CollideModel creation failed."); + } + *(t->collide_model_) = collide_model; + return reinterpret_cast(t); +} + +auto PythonClassCollideModel::GetCollideModel(bool doraise) const + -> CollideModel* { + CollideModel* collide_model = collide_model_->get(); + if (!collide_model && doraise) { + throw Exception("Invalid CollideModel.", PyExcType::kNotFound); + } + return collide_model; +} + +auto PythonClassCollideModel::tp_new(PyTypeObject* type, PyObject* args, + PyObject* kwds) -> PyObject* { + auto* self = + reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + if (!s_create_empty_) { + throw Exception( + "Can't instantiate CollideModels directly; use " + "ba.getcollidemodel() to get them."); + } + self->collide_model_ = new Object::Ref(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassCollideModel::Delete(Object::Ref* ref) { + assert(InGameThread()); + // if we're the py-object for a collide_model, clear them out + // (FIXME - we should pass the old pointer in here to sanity-test that we + // were their ref) + if (ref->exists()) { + (*ref)->ClearPyObject(); + } + delete ref; +} + +void PythonClassCollideModel::tp_dealloc(PythonClassCollideModel* self) { + BA_PYTHON_TRY; + // these have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately + if (!InGameThread()) { + Object::Ref* c = self->collide_model_; + g_game->PushCall([c] { Delete(c); }); + } else { + Delete(self->collide_model_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +bool PythonClassCollideModel::s_create_empty_ = false; +PyTypeObject PythonClassCollideModel::type_obj; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_collide_model.h b/src/ballistica/python/class/python_class_collide_model.h new file mode 100644 index 00000000..d59c3442 --- /dev/null +++ b/src/ballistica/python/class/python_class_collide_model.h @@ -0,0 +1,34 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_COLLIDE_MODEL_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_COLLIDE_MODEL_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassCollideModel : public PythonClass { + public: + static auto type_name() -> const char* { return "CollideModel"; } + static auto tp_repr(PythonClassCollideModel* self) -> PyObject*; + static void SetupType(PyTypeObject* obj); + static PyTypeObject type_obj; + static auto Create(CollideModel* collide_model) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + auto GetCollideModel(bool doraise = true) const -> CollideModel*; + + private: + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject*; + static void Delete(Object::Ref* ref); + static void tp_dealloc(PythonClassCollideModel* self); + static bool s_create_empty_; + Object::Ref* collide_model_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_COLLIDE_MODEL_H_ diff --git a/src/ballistica/python/class/python_class_context.cc b/src/ballistica/python/class/python_class_context.cc new file mode 100644 index 00000000..b5539c98 --- /dev/null +++ b/src/ballistica/python/class/python_class_context.cc @@ -0,0 +1,227 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_context.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +void PythonClassContext::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Context"; + obj->tp_basicsize = sizeof(PythonClassContext); + obj->tp_doc = + "Context(source: Any)\n" + "\n" + "A game context state.\n" + "\n" + "Category: General Utility Classes\n" + "\n" + "Many operations such as ba.newnode() or ba.gettexture() operate\n" + "implicitly on the current context. Each ba.Activity has its own\n" + "Context and objects within that activity (nodes, media, etc) can only\n" + "interact with other objects from that context.\n" + "\n" + "In general, as a modder, you should not need to worry about contexts,\n" + "since timers and other callbacks will take care of saving and\n" + "restoring the context automatically, but there may be rare cases where\n" + "you need to deal with them, such as when loading media in for use in\n" + "the UI (there is a special 'ui' context for all user-interface-related\n" + "functionality)\n" + "\n" + "When instantiating a ba.Context instance, a single 'source' argument\n" + "is passed, which can be one of the following strings/objects:\n\n" + "'empty':\n" + " Gives an empty context; it can be handy to run code here to ensure\n" + " it does no loading of media, creation of nodes, etc.\n" + "\n" + "'current':\n" + " Sets the context object to the current context.\n" + "\n" + "'ui':\n" + " Sets to the UI context. UI functions as well as loading of media to\n" + " be used in said functions must happen in the UI context.\n" + "\n" + "A ba.Activity instance:\n" + " Gives the context for the provided ba.Activity.\n" + " Most all code run during a game happens in an Activity's Context.\n" + "\n" + "A ba.Session instance:\n" + " Gives the context for the provided ba.Session.\n" + " Generally a user should not need to run anything here.\n" + "\n" + "\n" + "Usage:\n" + "\n" + "Contexts are generally used with the python 'with' statement, which\n" + "sets the context as current on entry and resets it to the previous\n" + "value on exit.\n" + "\n" + "# Example: load a few textures into the UI context\n" + "# (for use in widgets, etc):\n" + "with ba.Context('ui'):\n" + " tex1 = ba.gettexture('foo_tex_1')\n" + " tex2 = ba.gettexture('foo_tex_2')\n"; + + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_richcompare = (richcmpfunc)tp_richcompare; + obj->tp_methods = tp_methods; +} + +auto PythonClassContext::tp_repr(PythonClassContext* self) -> PyObject* { + BA_PYTHON_TRY; + + std::string context_str; + if (self->context_->GetUIContext()) { + context_str = "ui"; + } else if (HostActivity* ha = self->context_->GetHostActivity()) { + PythonRef ha_obj(ha->GetPyActivity(), PythonRef::kAcquire); + if (ha_obj.get() != Py_None) { + context_str = ha_obj.Str(); + } else { + context_str = ha->GetObjectDescription(); + } + } else if (self->context_->target.exists()) { + context_str = self->context_->target->GetObjectDescription(); + } else { + context_str = "empty"; + } + context_str = ""; + return PyUnicode_FromString(context_str.c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassContext::tp_richcompare(PythonClassContext* c1, PyObject* c2, + int op) -> PyObject* { + // always return false against other types + if (!Check(c2)) { + Py_RETURN_FALSE; + } + bool eq = (*(c1->context_) + == *((reinterpret_cast(c2))->context_)); + if (op == Py_EQ) { + if (eq) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else if (op == Py_NE) { + if (!eq) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else { + // don't support other ops + Py_RETURN_NOTIMPLEMENTED; + } +} + +auto PythonClassContext::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + PyObject* source_obj = Py_None; + if (!PyArg_ParseTuple(args, "O", &source_obj)) { + return nullptr; + } + + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + + Context cs(nullptr); + + if (Python::IsPyString(source_obj)) { + std::string source = Python::GetPyString(source_obj); + if (source == "ui") { + cs = Context(g_game->GetUIContextTarget()); + } else if (source == "UI") { + BA_LOG_ONCE("'UI' context-target option is deprecated; please use 'ui'"); + Python::PrintStackTrace(); + cs = Context(g_game->GetUIContextTarget()); + } else if (source == "current") { + cs = Context::current(); + } else if (source == "empty") { + cs = Context(nullptr); + } else { + throw Exception("invalid context identifier: '" + source + "'"); + } + } else if (Python::IsPyHostActivity(source_obj)) { + cs = Context(Python::GetPyHostActivity(source_obj)); + } else if (Python::IsPySession(source_obj)) { + auto* hs = dynamic_cast(Python::GetPySession(source_obj)); + assert(hs != nullptr); + cs = Context(hs); + } else { + throw Exception( + "Invalid argument to ba.Context(): " + Python::ObjToString(source_obj) + + "; expected 'ui', 'current', 'empty', a ba.Activity, or a " + "ba.Session"); + } + + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + self->context_ = new Context(cs); + self->context_prev_ = new Context(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); + BA_PYTHON_CATCH; +} + +void PythonClassContext::tp_dealloc(PythonClassContext* self) { + BA_PYTHON_TRY; + // Contexts have to be deleted in the game thread; + // ship them to it for deletion if need be; otherwise do it immediately. + if (!InGameThread()) { + Context* c = self->context_; + Context* c2 = self->context_prev_; + g_game->PushCall([c, c2] { + delete c; + delete c2; + }); + } else { + delete self->context_; + delete self->context_prev_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassContext::__enter__(PythonClassContext* self) -> PyObject* { + BA_PYTHON_TRY; + *(self->context_prev_) = Context::current(); + Context::set_current(*(self->context_)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassContext::__exit__(PythonClassContext* self, PyObject* args) + -> PyObject* { + BA_PYTHON_TRY; + Context::set_current(*(self->context_prev_)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyTypeObject PythonClassContext::type_obj; +PyMethodDef PythonClassContext::tp_methods[] = { + {"__enter__", (PyCFunction)__enter__, METH_NOARGS, + "enter call for 'with' functionality"}, + {"__exit__", (PyCFunction)__exit__, METH_VARARGS, + "exit call for 'with' functionality"}, + {nullptr}}; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_context.h b/src/ballistica/python/class/python_class_context.h new file mode 100644 index 00000000..9065fb37 --- /dev/null +++ b/src/ballistica/python/class/python_class_context.h @@ -0,0 +1,37 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_CONTEXT_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_CONTEXT_H_ + +#include "ballistica/core/context.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassContext : public PythonClass { + public: + static auto type_name() -> const char* { return "Context"; } + static void SetupType(PyTypeObject* obj); + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto context() const -> const Context& { return *context_; } + + private: + static PyMethodDef tp_methods[]; + static auto tp_repr(PythonClassContext* self) -> PyObject*; + static auto tp_richcompare(PythonClassContext* c1, PyObject* c2, int op) + -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassContext* self); + static auto __enter__(PythonClassContext* self) -> PyObject*; + static auto __exit__(PythonClassContext* self, PyObject* args) -> PyObject*; + Context* context_; + Context* context_prev_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_CONTEXT_H_ diff --git a/src/ballistica/python/class/python_class_context_call.cc b/src/ballistica/python/class/python_class_context_call.cc new file mode 100644 index 00000000..69d0854b --- /dev/null +++ b/src/ballistica/python/class/python_class_context_call.cc @@ -0,0 +1,130 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_context_call.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/python/python_context_call.h" + +namespace ballistica { + +void PythonClassContextCall::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.ContextCall"; + obj->tp_basicsize = sizeof(PythonClassContextCall); + obj->tp_doc = + "ContextCall(call: Callable)\n" + "\n" + "A context-preserving callable.\n" + "\n" + "Category: General Utility Classes\n" + "\n" + "A ContextCall wraps a callable object along with a reference\n" + "to the current context (see ba.Context); it handles restoring the\n" + "context when run and automatically clears itself if the context\n" + "it belongs to shuts down.\n" + "\n" + "Generally you should not need to use this directly; all standard\n" + "Ballistica callbacks involved with timers, materials, UI functions,\n" + "etc. handle this under-the-hood you don't have to worry about it.\n" + "The only time it may be necessary is if you are implementing your\n" + "own callbacks, such as a worker thread that does some action and then\n" + "runs some game code when done. By wrapping said callback in one of\n" + "these, you can ensure that you will not inadvertently be keeping the\n" + "current activity alive or running code in a torn-down (expired)\n" + "context.\n" + "\n" + "You can also use ba.WeakCall for similar functionality, but\n" + "ContextCall has the added bonus that it will not run during context\n" + "shutdown, whereas ba.WeakCall simply looks at whether the target\n" + "object still exists.\n" + "\n" + "# Example A: code like this can inadvertently prevent our activity\n" + "# (self) from ending until the operation completes, since the bound\n" + "# method we're passing (self.dosomething) contains a strong-reference\n" + "# to self).\n" + "start_some_long_action(callback_when_done=self.dosomething)\n" + "\n" + "# Example B: in this case our activity (self) can still die\n" + "# properly; the callback will clear itself when the activity starts\n" + "# shutting down, becoming a harmless no-op and releasing the reference\n" + "# to our activity.\n" + "start_long_action(callback_when_done=ba.ContextCall(self.mycallback))\n"; + + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + obj->tp_call = (ternaryfunc)tp_call; +} + +auto PythonClassContextCall::tp_call(PythonClassContextCall* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) + return nullptr; + + (*(self->context_call_))->Run(); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassContextCall::tp_repr(PythonClassContextCall* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(self->context_call_->exists()); + return PyUnicode_FromString( + ("") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassContextCall::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = + reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + + // try to do anything that may throw an exception before/during our + // placement-new so we don't have to worry about tearing it down if + // something goes wrong afterwards + PyObject* source_obj = Py_None; + if (!PyArg_ParseTuple(args, "O", &source_obj)) return nullptr; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + self->context_call_ = new Object::Ref( + Object::New(source_obj)); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassContextCall::tp_dealloc(PythonClassContextCall* self) { + BA_PYTHON_TRY; + // these have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately + if (!InGameThread()) { + Object::Ref* c = self->context_call_; + g_game->PushCall([c] { delete c; }); + } else { + delete self->context_call_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +PyTypeObject PythonClassContextCall::type_obj; +PyMethodDef PythonClassContextCall::tp_methods[] = {{nullptr}}; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_context_call.h b/src/ballistica/python/class/python_class_context_call.h new file mode 100644 index 00000000..34e830fd --- /dev/null +++ b/src/ballistica/python/class/python_class_context_call.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_CONTEXT_CALL_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_CONTEXT_CALL_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassContextCall : public PythonClass { + public: + static auto type_name() -> const char* { return "ContextCall"; } + static void SetupType(PyTypeObject* obj); + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + + private: + static PyMethodDef tp_methods[]; + static auto tp_call(PythonClassContextCall* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto tp_repr(PythonClassContextCall* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassContextCall* self); + Object::Ref* context_call_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_CONTEXT_CALL_H_ diff --git a/src/ballistica/python/class/python_class_data.cc b/src/ballistica/python/class/python_class_data.cc new file mode 100644 index 00000000..2f8b9113 --- /dev/null +++ b/src/ballistica/python/class/python_class_data.cc @@ -0,0 +1,139 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_data.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/media/component/data.h" + +namespace ballistica { + +auto PythonClassData::tp_repr(PythonClassData* self) -> PyObject* { + BA_PYTHON_TRY; + Object::Ref m = *(self->data_); + return Py_BuildValue( + "s", (std::string("name() + "\"") : "(empty ref)") + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +void PythonClassData::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Data"; + obj->tp_basicsize = sizeof(PythonClassData); + obj->tp_doc = + "A reference to a data object.\n" + "\n" + "Category: Asset Classes\n" + "\n" + "Use ba.getdata() to instantiate one."; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_methods = tp_methods; +} + +auto PythonClassData::Create(Data* data) -> PyObject* { + s_create_empty_ = true; // prevent class from erroring on create + auto* t = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!t) { + throw Exception("ba.Data creation failed."); + } + *(t->data_) = data; + return reinterpret_cast(t); +} + +auto PythonClassData::GetData(bool doraise) const -> Data* { + Data* data = data_->get(); + if (!data && doraise) { + throw Exception("Invalid Data.", PyExcType::kNotFound); + } + return data; +} + +auto PythonClassData::tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + if (!s_create_empty_) { + throw Exception( + "Can't instantiate Datas directly; use ba.getdata() to get " + "them."); + } + self->data_ = new Object::Ref(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassData::Delete(Object::Ref* ref) { + assert(InGameThread()); + + // if we're the py-object for a data, clear them out + // (FIXME - wej should pass the old pointer in here to sanity-test that we + // were their ref) + if (ref->exists()) { + (*ref)->ClearPyObject(); + } + delete ref; +} + +void PythonClassData::tp_dealloc(PythonClassData* self) { + BA_PYTHON_TRY; + // these have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately + if (!InGameThread()) { + Object::Ref* s = self->data_; + g_game->PushCall([s] { Delete(s); }); + } else { + Delete(self->data_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassData::GetValue(PythonClassData* self) -> PyObject* { + BA_PYTHON_TRY; + Data* data = self->data_->get(); + if (data == nullptr) { + throw Exception("Invalid data object.", PyExcType::kNotFound); + } + // haha really need to rename this class. + DataData* datadata = data->data_data(); + datadata->Load(); + datadata->set_last_used_time(GetRealTime()); + PyObject* obj = datadata->object().get(); + assert(obj); + Py_INCREF(obj); + return obj; + BA_PYTHON_CATCH; +} + +bool PythonClassData::s_create_empty_ = false; +PyTypeObject PythonClassData::type_obj; + +PyMethodDef PythonClassData::tp_methods[] = { + {"getvalue", (PyCFunction)GetValue, METH_NOARGS, + "getvalue() -> Any\n" + "\n" + "Return the data object's value.\n" + "\n" + "This can consist of anything representable by json (dicts, lists,\n" + "numbers, bools, None, etc).\n" + "Note that this call will block if the data has not yet been loaded,\n" + "so it can be beneficial to plan a short bit of time between when\n" + "the data object is requested and when it's value is accessed.\n"}, + {nullptr}}; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_data.h b/src/ballistica/python/class/python_class_data.h new file mode 100644 index 00000000..075fbad6 --- /dev/null +++ b/src/ballistica/python/class/python_class_data.h @@ -0,0 +1,36 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_DATA_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_DATA_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassData : public PythonClass { + public: + static auto type_name() -> const char* { return "Data"; } + static PyTypeObject type_obj; + static auto tp_repr(PythonClassData* self) -> PyObject*; + static void SetupType(PyTypeObject* obj); + static auto Create(Data* data) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + auto GetData(bool doraise = true) const -> Data*; + + private: + static PyMethodDef tp_methods[]; + static auto GetValue(PythonClassData* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject*; + static void tp_dealloc(PythonClassData* self); + static void Delete(Object::Ref* ref); + static bool s_create_empty_; + Object::Ref* data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_DATA_H_ diff --git a/src/ballistica/python/class/python_class_input_device.cc b/src/ballistica/python/class/python_class_input_device.cc new file mode 100644 index 00000000..6176f119 --- /dev/null +++ b/src/ballistica/python/class/python_class_input_device.cc @@ -0,0 +1,446 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_input_device.h" + +#include + +#include "ballistica/game/player.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/input/device/keyboard_input.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +// Ignore a few things that python macros do. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "RedundantCast" + +void PythonClassInputDevice::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.InputDevice"; + obj->tp_basicsize = sizeof(PythonClassInputDevice); + obj->tp_doc = + "An input-device such as a gamepad, touchscreen, or keyboard.\n" + "\n" + "Category: Gameplay Classes\n" + "\n" + "Attributes:\n" + "\n" + " allows_configuring: bool\n" + " Whether the input-device can be configured.\n" + "\n" + " has_meaningful_button_names: bool\n" + " Whether button names returned by this instance match labels\n" + " on the actual device. (Can be used to determine whether to show\n" + " them in controls-overlays, etc.)\n" + "\n" + " player: Optional[ba.SessionPlayer]\n" + " The player associated with this input device.\n" + "\n" + " client_id: int\n" + " The numeric client-id this device is associated with.\n" + " This is only meaningful for remote client inputs; for\n" + " all local devices this will be -1.\n" + "\n" + " name: str\n" + " The name of the device.\n" + "\n" + " unique_identifier: str\n" + " A string that can be used to persistently identify the device,\n" + " even among other devices of the same type. Used for saving\n" + " prefs, etc.\n" + "\n" + " id: int\n" + " The unique numeric id of this device.\n" + "\n" + " instance_number: int\n" + " The number of this device among devices of the same type.\n" + "\n" + " is_controller_app: bool\n" + " Whether this input-device represents a locally-connected\n" + " controller-app.\n" + "\n" + " is_remote_client: bool\n" + " Whether this input-device represents a remotely-connected\n" + " client.\n" + "\n"; + + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + obj->tp_getattro = (getattrofunc)tp_getattro; + obj->tp_setattro = (setattrofunc)tp_setattro; + + // We provide number methods only for bool functionality. + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_bool = (inquiry)nb_bool; + obj->tp_as_number = &as_number_; +} + +auto PythonClassInputDevice::Create(InputDevice* input_device) -> PyObject* { + // Make sure we only have one python ref per material. + if (input_device) { + assert(!input_device->has_py_ref()); + } + auto* py_input_device = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + if (!py_input_device) { + throw Exception("ba.InputDevice creation failed."); + } + *(py_input_device->input_device_) = input_device; + return reinterpret_cast(py_input_device); +} + +auto PythonClassInputDevice::GetInputDevice() const -> InputDevice* { + InputDevice* input_device = input_device_->get(); + if (!input_device) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return input_device; +} + +auto PythonClassInputDevice::tp_repr(PythonClassInputDevice* self) + -> PyObject* { + BA_PYTHON_TRY; + InputDevice* d = self->input_device_->get(); + int input_device_id = d ? d->index() : -1; + std::string dname = d ? d->GetDeviceName() : "invalid device"; + return Py_BuildValue("s", + (std::string("") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::nb_bool(PythonClassInputDevice* self) -> int { + return self->input_device_->exists(); +} + +PyNumberMethods PythonClassInputDevice::as_number_; + +auto PythonClassInputDevice::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = + reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + self->input_device_ = new Object::WeakRef(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassInputDevice::tp_dealloc(PythonClassInputDevice* self) { + BA_PYTHON_TRY; + // These have to be destructed in the game thread - send them along to it if + // need be. + // FIXME: Technically the main thread has a pointer to a dead PyObject + // until the delete goes through; could that ever be a problem? + if (!InGameThread()) { + Object::WeakRef* d = self->input_device_; + g_game->PushCall([d] { delete d; }); + } else { + delete self->input_device_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassInputDevice::tp_getattro(PythonClassInputDevice* self, + PyObject* attr) -> PyObject* { + BA_PYTHON_TRY; + assert(PyUnicode_Check(attr)); // NOLINT (signed bitwise ops) + const char* s = PyUnicode_AsUTF8(attr); + if (!strcmp(s, "player")) { + InputDevice* input_device = self->input_device_->get(); + if (!input_device) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + Player* player = input_device->GetPlayer(); + if (player != nullptr) { + return player->NewPyRef(); + } + Py_RETURN_NONE; + } else if (!strcmp(s, "allows_configuring")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + if (d->GetAllowsConfiguring()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else if (!strcmp(s, "has_meaningful_button_names")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + if (d->HasMeaningfulButtonNames()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else if (!strcmp(s, "client_id")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyLong_FromLong(d->GetClientID()); + } else if (!strcmp(s, "name")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyUnicode_FromString(d->GetDeviceName().c_str()); + } else if (!strcmp(s, "unique_identifier")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyUnicode_FromString(d->GetPersistentIdentifier().c_str()); + } else if (!strcmp(s, "id")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyLong_FromLong(d->index()); + } else if (!strcmp(s, "instance_number")) { + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyLong_FromLong(d->device_number()); + } else if (!strcmp(s, "is_controller_app")) { + InputDevice* input_device = self->input_device_->get(); + if (!input_device) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + if (input_device->IsRemoteApp()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else if (!strcmp(s, "is_remote_client")) { + InputDevice* input_device = self->input_device_->get(); + if (!input_device) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + if (input_device->IsRemoteClient()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } + + // Fall back to generic behavior. + PyObject* val; + val = PyObject_GenericGetAttr(reinterpret_cast(self), attr); + return val; + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::tp_setattro(PythonClassInputDevice* self, + PyObject* attr, PyObject* val) -> int { + BA_PYTHON_TRY; + assert(PyUnicode_Check(attr)); // NOLINT (signed bitwise) + throw Exception("Attr '" + std::string(PyUnicode_AsUTF8(attr)) + + "' is not settable on input device objects."); + // return PyObject_GenericSetAttr(reinterpret_cast(self), attr, + // val); + BA_PYTHON_INT_CATCH; +} + +auto PythonClassInputDevice::RemoveRemotePlayerFromGame( + PythonClassInputDevice* self) -> PyObject* { + BA_PYTHON_TRY; + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + d->RemoveRemotePlayerFromGame(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::GetDefaultPlayerName(PythonClassInputDevice* self) + -> PyObject* { + BA_PYTHON_TRY; + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyUnicode_FromString(d->GetDefaultPlayerName().c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::GetPlayerProfiles(PythonClassInputDevice* self) + -> PyObject* { + BA_PYTHON_TRY; + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + if (PyObject* profiles = d->GetPlayerProfiles()) { + Py_INCREF(profiles); + return profiles; + } else { + return Py_BuildValue("{}"); // Empty dict. + } + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::GetAccountName(PythonClassInputDevice* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + int full; + static const char* kwlist[] = {"full", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &full)) { + return nullptr; + } + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyUnicode_FromString( + d->GetAccountName(static_cast(full)).c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::IsConnectedToRemotePlayer( + PythonClassInputDevice* self) -> PyObject* { + BA_PYTHON_TRY; + InputDevice* input_device = self->input_device_->get(); + if (!input_device) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + if (input_device->GetRemotePlayer()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::Exists(PythonClassInputDevice* self) -> PyObject* { + BA_PYTHON_TRY; + if (self->input_device_->exists()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::GetAxisName(PythonClassInputDevice* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + int id; + static const char* kwlist[] = {"axis_id", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", + const_cast(kwlist), &id)) { + return nullptr; + } + InputDevice* input_device = self->input_device_->get(); + if (!input_device) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + return PyUnicode_FromString(input_device->GetAxisName(id).c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassInputDevice::GetButtonName(PythonClassInputDevice* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + int id{}; + static const char* kwlist[] = {"button_id", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", + const_cast(kwlist), &id)) { + return nullptr; + } + InputDevice* d = self->input_device_->get(); + if (!d) { + throw Exception(PyExcType::kInputDeviceNotFound); + } + + // Ask the input-device for the button name. + std::string bname = d->GetButtonName(id); + + // If this doesn't appear to be lstr json itself, convert it to that. + if (bname.length() < 1 || bname.c_str()[0] != '{') { + Utils::StringReplaceAll(&bname, "\"", "\\\""); + bname = R"({"v":")" + bname + "\"}"; + } + PythonRef args2(Py_BuildValue("(s)", bname.c_str()), PythonRef::kSteal); + PythonRef results = + g_python->obj(Python::ObjID::kLstrFromJsonCall).Call(args2); + return results.NewRef(); + + BA_PYTHON_CATCH; +} + +PyTypeObject PythonClassInputDevice::type_obj; +PyMethodDef PythonClassInputDevice::tp_methods[] = { + {"remove_remote_player_from_game", (PyCFunction)RemoveRemotePlayerFromGame, + METH_NOARGS, + "remove_remote_player_from_game() -> None\n" + "\n" + "(internal)"}, + {"is_connected_to_remote_player", (PyCFunction)IsConnectedToRemotePlayer, + METH_NOARGS, + "is_connected_to_remote_player() -> bool\n" + "\n" + "(internal)"}, + {"exists", (PyCFunction)Exists, METH_NOARGS, + "exists() -> bool\n" + "\n" + "Return whether the underlying device for this object is still present."}, + {"get_button_name", (PyCFunction)GetButtonName, + METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise ops) + "get_button_name(button_id: int) -> ba.Lstr\n" + "\n" + "Given a button ID, return a human-readable name for that key/button.\n" + "\n" + "Can return an empty string if the value is not meaningful to humans."}, + // NOLINTNEXTLINE (signed bitwise ops) + {"get_axis_name", (PyCFunction)GetAxisName, METH_VARARGS | METH_KEYWORDS, + "get_axis_name(axis_id: int) -> str\n" + "\n" + "Given an axis ID, return the name of the axis on this device.\n" + "\n" + "Can return an empty string if the value is not meaningful to humans."}, + {"get_default_player_name", (PyCFunction)GetDefaultPlayerName, METH_NOARGS, + "get_default_player_name() -> str\n" + "\n" + "(internal)\n" + "\n" + "Returns the default player name for this device. (used for the 'random'\n" + "profile)"}, + {"get_account_name", (PyCFunction)GetAccountName, + METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise ops) + "get_account_name(full: bool) -> str\n" + "\n" + "Returns the account name associated with this device.\n" + "\n" + "(can be used to get account names for remote players)"}, + {"get_player_profiles", (PyCFunction)GetPlayerProfiles, METH_NOARGS, + "get_player_profiles() -> dict\n" + "\n" + "(internal)"}, + {nullptr}}; // namespace ballistica + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_input_device.h b/src/ballistica/python/class/python_class_input_device.h new file mode 100644 index 00000000..a3508939 --- /dev/null +++ b/src/ballistica/python/class/python_class_input_device.h @@ -0,0 +1,52 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_INPUT_DEVICE_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_INPUT_DEVICE_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassInputDevice : public PythonClass { + public: + static auto type_name() -> const char* { return "InputDevice"; } + static void SetupType(PyTypeObject* obj); + static auto Create(InputDevice* input_device) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto GetInputDevice() const -> InputDevice*; + + private: + static PyMethodDef tp_methods[]; + static auto tp_repr(PythonClassInputDevice* self) -> PyObject*; + static auto tp_getattro(PythonClassInputDevice* self, PyObject* attr) + -> PyObject*; + static auto tp_setattro(PythonClassInputDevice* self, PyObject* attr, + PyObject* val) -> int; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassInputDevice* self); + static auto nb_bool(PythonClassInputDevice* self) -> int; + static auto RemoveRemotePlayerFromGame(PythonClassInputDevice* self) + -> PyObject*; + static auto GetDefaultPlayerName(PythonClassInputDevice* self) -> PyObject*; + static auto GetPlayerProfiles(PythonClassInputDevice* self) -> PyObject*; + static auto GetAccountName(PythonClassInputDevice* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto IsConnectedToRemotePlayer(PythonClassInputDevice* self) + -> PyObject*; + static auto Exists(PythonClassInputDevice* self) -> PyObject*; + static auto GetAxisName(PythonClassInputDevice* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto GetButtonName(PythonClassInputDevice* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static PyNumberMethods as_number_; + Object::WeakRef* input_device_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_INPUT_DEVICE_H_ diff --git a/src/ballistica/python/class/python_class_material.cc b/src/ballistica/python/class/python_class_material.cc new file mode 100644 index 00000000..21d5a93a --- /dev/null +++ b/src/ballistica/python/class/python_class_material.cc @@ -0,0 +1,712 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_material.h" + +#include +#include + +#include "ballistica/dynamics/material/impact_sound_material_action.h" +#include "ballistica/dynamics/material/material.h" +#include "ballistica/dynamics/material/material_component.h" +#include "ballistica/dynamics/material/material_condition_node.h" +#include "ballistica/dynamics/material/node_message_material_action.h" +#include "ballistica/dynamics/material/node_mod_material_action.h" +#include "ballistica/dynamics/material/node_user_message_material_action.h" +#include "ballistica/dynamics/material/part_mod_material_action.h" +#include "ballistica/dynamics/material/python_call_material_action.h" +#include "ballistica/dynamics/material/roll_sound_material_action.h" +#include "ballistica/dynamics/material/skid_sound_material_action.h" +#include "ballistica/dynamics/material/sound_material_action.h" +#include "ballistica/game/game.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +// Ignore signed bitwise stuff since python macros do a lot of it. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "RedundantCast" + +bool PythonClassMaterial::s_create_empty_ = false; +PyTypeObject PythonClassMaterial::type_obj; + +static void DoAddConditions(PyObject* cond_obj, + Object::Ref* c); +static void DoAddAction(PyObject* actions_obj, + std::vector >* actions); + +// Attrs we expose through our custom getattr/setattr. +#define ATTR_LABEL "label" + +// The set we expose via dir(). +static const char* extra_dir_attrs[] = {ATTR_LABEL, nullptr}; + +void PythonClassMaterial::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Material"; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_basicsize = sizeof(PythonClassMaterial); + + // clang-format off + obj->tp_doc = + "Material(label: str = None)\n" + "\n" + "An entity applied to game objects to modify collision behavior.\n" + "\n" + "Category: Gameplay Classes\n" + "\n" + "A material can affect physical characteristics, generate sounds,\n" + "or trigger callback functions when collisions occur.\n" + "\n" + "Materials are applied to 'parts', which are groups of one or more\n" + "rigid bodies created as part of a ba.Node. Nodes can have any number\n" + "of parts, each with its own set of materials. Generally materials are\n" + "specified as array attributes on the Node. The 'spaz' node, for\n" + "example, has various attributes such as 'materials',\n" + "'roller_materials', and 'punch_materials', which correspond to the\n" + "various parts it creates.\n" + "\n" + "Use ba.Material() to instantiate a blank material, and then use its\n" + "add_actions() method to define what the material does.\n" + "\n" + "Attributes:\n" + "\n" + " " ATTR_LABEL ": str\n" + " A label for the material; only used for debugging.\n"; + // clang-format on + + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_methods = tp_methods; + obj->tp_getattro = (getattrofunc)tp_getattro; + obj->tp_setattro = (setattrofunc)tp_setattro; +} + +auto PythonClassMaterial::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + + // Do anything that might throw an exception *before* our placement-new + // stuff so we don't have to worry about cleaning it up on errors. + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + PyObject* name_obj = Py_None; + std::string name; + Object::Ref m; + if (!s_create_empty_) { + static const char* kwlist[] = {"label", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|O", + const_cast(kwlist), &name_obj)) { + return nullptr; + } + if (name_obj != Py_None) { + name = Python::GetPyString(name_obj); + } else { + name = Python::GetPythonFileLocation(); + } + + if (HostActivity* host_activity = Context::current().GetHostActivity()) { + m = host_activity->NewMaterial(name); + m->set_py_object(reinterpret_cast(self)); + } else { + throw Exception("Can't create materials in this context.", + PyExcType::kContext); + } + } + self->material_ = new Object::Ref(m); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassMaterial::Delete(Object::Ref* m) { + assert(InGameThread()); + + // If we're the py-object for a material, clear them out. + if (m->exists()) { + assert((*m)->py_object() != nullptr); + (*m)->set_py_object(nullptr); + } + delete m; +} + +void PythonClassMaterial::tp_dealloc(PythonClassMaterial* self) { + BA_PYTHON_TRY; + + // These have to be deleted in the game thread - push a call if + // need be.. otherwise do it immediately. + if (!InGameThread()) { + Object::Ref* ptr = self->material_; + g_game->PushCall([ptr] { Delete(ptr); }); + } else { + Delete(self->material_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassMaterial::tp_repr(PythonClassMaterial* self) -> PyObject* { + BA_PYTHON_TRY; + return Py_BuildValue( + "s", + std::string("").c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassMaterial::tp_getattro(PythonClassMaterial* self, PyObject* attr) + -> PyObject* { + BA_PYTHON_TRY; + + // Assuming this will always be a str? + assert(PyUnicode_Check(attr)); + + const char* s = PyUnicode_AsUTF8(attr); + + if (!strcmp(s, ATTR_LABEL)) { + Material* material = self->material_->get(); + if (!material) { + throw Exception("Invalid Material.", PyExcType::kNotFound); + } + return PyUnicode_FromString(material->label().c_str()); + } + + // Fall back to generic behavior. + PyObject* val; + val = PyObject_GenericGetAttr(reinterpret_cast(self), attr); + return val; + BA_PYTHON_CATCH; +} + +auto PythonClassMaterial::tp_setattro(PythonClassMaterial* self, PyObject* attr, + PyObject* val) -> int { + BA_PYTHON_TRY; + assert(PyUnicode_Check(attr)); + + throw Exception("Attr '" + std::string(PyUnicode_AsUTF8(attr)) + + "' is not settable on Material objects.", + PyExcType::kAttribute); + + // return PyObject_GenericSetAttr(reinterpret_cast(self), attr, + // val); + BA_PYTHON_INT_CATCH; +} + +auto PythonClassMaterial::Dir(PythonClassMaterial* self) -> PyObject* { + BA_PYTHON_TRY; + + // Start with the standard python dir listing. + PyObject* dir_list = Python::generic_dir(reinterpret_cast(self)); + assert(PyList_Check(dir_list)); + + // ..and add in our custom attr names. + for (const char** name = extra_dir_attrs; *name != nullptr; name++) { + PyList_Append( + dir_list, + PythonRef(PyUnicode_FromString(*name), PythonRef::kSteal).get()); + } + PyList_Sort(dir_list); + return dir_list; + + BA_PYTHON_CATCH; +} + +auto PythonClassMaterial::AddActions(PythonClassMaterial* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* conditions_obj{Py_None}; + PyObject* actions_obj{nullptr}; + const char* kwlist[] = {"actions", "conditions", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|O", + const_cast(kwlist), &actions_obj, + &conditions_obj)) { + return nullptr; + } + + Object::Ref conditions; + if (conditions_obj != Py_None) { + DoAddConditions(conditions_obj, &conditions); + } + + Material* m = self->material_->get(); + if (!m) { + throw Exception("Invalid Material.", PyExcType::kNotFound); + } + std::vector > actions; + if (PyTuple_Check(actions_obj)) { + Py_ssize_t size = PyTuple_GET_SIZE(actions_obj); + if (size > 0) { + // If the first item is a string, process this tuple as a single action. + if (PyUnicode_Check(PyTuple_GET_ITEM(actions_obj, 0))) { + DoAddAction(actions_obj, &actions); + } else { + // Otherwise each item is assumed to be an action. + for (Py_ssize_t i = 0; i < size; i++) { + DoAddAction(PyTuple_GET_ITEM(actions_obj, i), &actions); + } + } + } + } else { + PyErr_SetString(PyExc_AttributeError, + "expected a tuple for \"actions\" argument"); + return nullptr; + } + m->AddComponent(Object::New(conditions, actions)); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyMethodDef PythonClassMaterial::tp_methods[] = { + {"add_actions", (PyCFunction)AddActions, METH_VARARGS | METH_KEYWORDS, + "add_actions(actions: Tuple, conditions: Optional[Tuple] = None)\n" + " -> None\n" + "\n" + "Add one or more actions to the material, optionally with conditions.\n" + "\n" + "Conditions:\n" + "\n" + "Conditions are provided as tuples which can be combined to form boolean\n" + "logic. A single condition might look like ('condition_name', cond_arg),\n" + "or a more complex nested one might look like (('some_condition',\n" + "cond_arg), 'or', ('another_condition', cond2_arg)).\n" + "\n" + "'and', 'or', and 'xor' are available to chain together 2 conditions, as\n" + " seen above.\n" + "\n" + "Available Conditions:\n" + "\n" + "('they_have_material', material) - does the part we\'re hitting have a\n" + " given ba.Material?\n" + "\n" + "('they_dont_have_material', material) - does the part we\'re hitting\n" + " not have a given ba.Material?\n" + "\n" + "('eval_colliding') - is 'collide' true at this point in material\n" + " evaluation? (see the modify_part_collision action)\n" + "\n" + "('eval_not_colliding') - is 'collide' false at this point in material\n" + " evaluation? (see the modify_part_collision action)\n" + "\n" + "('we_are_younger_than', age) - is our part younger than 'age'\n" + " (in milliseconds)?\n" + "\n" + "('we_are_older_than', age) - is our part older than 'age'\n" + " (in milliseconds)?\n" + "\n" + "('they_are_younger_than', age) - is the part we're hitting younger than\n" + " 'age' (in milliseconds)?\n" + "\n" + "('they_are_older_than', age) - is the part we're hitting older than\n" + " 'age' (in milliseconds)?\n" + "\n" + "('they_are_same_node_as_us') - does the part we're hitting belong to\n" + " the same ba.Node as us?\n" + "\n" + "('they_are_different_node_than_us') - does the part we're hitting\n" + " belong to a different ba.Node than us?\n" + "\n" + "Actions:\n" + "\n" + "In a similar manner, actions are specified as tuples. Multiple actions\n" + "can be specified by providing a tuple of tuples.\n" + "\n" + "Available Actions:\n" + "\n" + "('call', when, callable) - calls the provided callable; 'when' can be\n" + " either 'at_connect' or 'at_disconnect'. 'at_connect' means to fire\n" + " when the two parts first come in contact; 'at_disconnect' means to\n" + " fire once they cease being in contact.\n" + "\n" + "('message', who, when, message_obj) - sends a message object; 'who' can\n" + " be either 'our_node' or 'their_node', 'when' can be 'at_connect' or\n" + " 'at_disconnect', and message_obj is the message object to send.\n" + " This has the same effect as calling the node's handlemessage()\n" + " method.\n" + "\n" + "('modify_part_collision', attr, value) - changes some characteristic\n" + " of the physical collision that will occur between our part and their\n" + " part. This change will remain in effect as long as the two parts\n" + " remain overlapping. This means if you have a part with a material\n" + " that turns 'collide' off against parts younger than 100ms, and it\n" + " touches another part that is 50ms old, it will continue to not\n" + " collide with that part until they separate, even if the 100ms\n" + " threshold is passed. Options for attr/value are: 'physical' (boolean\n" + " value; whether a *physical* response will occur at all), 'friction'\n" + " (float value; how friction-y the physical response will be),\n" + " 'collide' (boolean value; whether *any* collision will occur at all,\n" + " including non-physical stuff like callbacks), 'use_node_collide'\n" + " (boolean value; whether to honor modify_node_collision overrides for\n" + " this collision), 'stiffness' (float value, how springy the physical\n" + " response is), 'damping' (float value, how damped the physical\n" + " response is), 'bounce' (float value; how bouncy the physical response\n" + " is).\n" + "\n" + "('modify_node_collision', attr, value) - similar to\n" + " modify_part_collision, but operates at a node-level.\n" + " collision attributes set here will remain in effect as long as\n" + " *anything* from our part's node and their part's node overlap.\n" + " A key use of this functionality is to prevent new nodes from\n" + " colliding with each other if they appear overlapped;\n" + " if modify_part_collision is used, only the individual parts that\n" + " were overlapping would avoid contact, but other parts could still\n" + " contact leaving the two nodes 'tangled up'. Using\n" + " modify_node_collision ensures that the nodes must completely\n" + " separate before they can start colliding. Currently the only attr\n" + " available here is 'collide' (a boolean value).\n" + "\n" + "('sound', sound, volume) - plays a ba.Sound when a collision occurs, at\n" + " a given volume, regardless of the collision speed/etc.\n" + "\n" + "('impact_sound', sound, targetImpulse, volume) - plays a sound when a\n" + " collision occurs, based on the speed of impact. Provide a ba.Sound, a\n" + " target-impulse, and a volume.\n" + "\n" + "('skid_sound', sound, targetImpulse, volume) - plays a sound during a\n" + " collision when parts are 'scraping' against each other. Provide a\n" + " ba.Sound, a target-impulse, and a volume.\n" + "\n" + "('roll_sound', sound, targetImpulse, volume) - plays a sound during a\n" + " collision when parts are 'rolling' against each other. Provide a\n" + " ba.Sound, a target-impulse, and a volume.\n" + "\n" + "# example 1: create a material that lets us ignore\n" + "# collisions against any nodes we touch in the first\n" + "# 100 ms of our existence; handy for preventing us from\n" + "# exploding outward if we spawn on top of another object:\n" + "m = ba.Material()\n" + "m.add_actions(conditions=(('we_are_younger_than', 100),\n" + " 'or',('they_are_younger_than', 100)),\n" + " actions=('modify_node_collision', 'collide', False))\n" + "\n" + "# example 2: send a DieMessage to anything we touch, but cause\n" + "# no physical response. This should cause any ba.Actor to drop dead:\n" + "m = ba.Material()\n" + "m.add_actions(actions=(('modify_part_collision', 'physical', False),\n" + " ('message', 'their_node', 'at_connect',\n" + " ba.DieMessage())))\n" + "\n" + "# example 3: play some sounds when we're contacting the ground:\n" + "m = ba.Material()\n" + "m.add_actions(conditions=('they_have_material',\n" + " shared.footing_material),\n" + " actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n" + " ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n" + "\n"}, + {"__dir__", (PyCFunction)Dir, METH_NOARGS, + "allows inclusion of our custom attrs in standard python dir()"}, + + {nullptr}}; + +void DoAddConditions(PyObject* cond_obj, + Object::Ref* c) { + assert(InGameThread()); + if (PyTuple_Check(cond_obj)) { + Py_ssize_t size = PyTuple_GET_SIZE(cond_obj); + if (size < 1) { + throw Exception("Malformed arguments.", PyExcType::kValue); + } + + PyObject* first = PyTuple_GET_ITEM(cond_obj, 0); + assert(first); + + // If the first element is a string, + // its a leaf node; process its elements as a single statement. + if (PyUnicode_Check(first)) { + (*c) = Object::New(); + (*c)->opmode = MaterialConditionNode::OpMode::LEAF_NODE; + int argc; + const char* cond_str = PyUnicode_AsUTF8(first); + bool first_arg_is_material = false; + if (!strcmp(cond_str, "they_have_material")) { + argc = 1; + first_arg_is_material = true; + (*c)->cond = MaterialCondition::kDstIsMaterial; + } else if (!strcmp(cond_str, "they_dont_have_material")) { + argc = 1; + first_arg_is_material = true; + (*c)->cond = MaterialCondition::kDstNotMaterial; + } else if (!strcmp(cond_str, "eval_colliding")) { + argc = 0; + (*c)->cond = MaterialCondition::kEvalColliding; + } else if (!strcmp(cond_str, "eval_not_colliding")) { + argc = 0; + (*c)->cond = MaterialCondition::kEvalNotColliding; + } else if (!strcmp(cond_str, "we_are_younger_than")) { + argc = 1; + (*c)->cond = MaterialCondition::kSrcYoungerThan; + } else if (!strcmp(cond_str, "we_are_older_than")) { + argc = 1; + (*c)->cond = MaterialCondition::kSrcOlderThan; + } else if (!strcmp(cond_str, "they_are_younger_than")) { + argc = 1; + (*c)->cond = MaterialCondition::kDstYoungerThan; + } else if (!strcmp(cond_str, "they_are_older_than")) { + argc = 1; + (*c)->cond = MaterialCondition::kDstOlderThan; + } else if (!strcmp(cond_str, "they_are_same_node_as_us")) { + argc = 0; + (*c)->cond = MaterialCondition::kSrcDstSameNode; + } else if (!strcmp(cond_str, "they_are_different_node_than_us")) { + argc = 0; + (*c)->cond = MaterialCondition::kSrcDstDiffNode; + } else { + throw Exception( + std::string("Invalid material condition: \"") + cond_str + "\".", + PyExcType::kValue); + } + if (size != (argc + 1)) { + throw Exception( + std::string("Wrong number of arguments for condition: \"") + + cond_str + "\".", + PyExcType::kValue); + } + if (argc > 0) { + if (first_arg_is_material) { + (*c)->val1_material = + Python::GetPyMaterial(PyTuple_GET_ITEM(cond_obj, 1)); + } else { + PyObject* o = PyTuple_GET_ITEM(cond_obj, 1); + if (!PyLong_Check(o)) { + throw Exception( + std::string("Expected int for first arg of condition: \"") + + cond_str + "\".", + PyExcType::kType); + } + (*c)->val1 = static_cast(PyLong_AsLong(o)); + } + } + if (argc > 1) { + PyObject* o = PyTuple_GET_ITEM(cond_obj, 2); + if (!PyLong_Check(o)) { + throw Exception( + std::string("Expected int for second arg of condition: \"") + + cond_str + "\".", + PyExcType::kType); + } + (*c)->val1 = static_cast(PyLong_AsLong(o)); + } + } else if (PyTuple_Check(first)) { + // First item is a tuple - assume its a tuple of size 3+2*n + // containing tuples for odd index vals and operators for even. + if (size < 3 || (size % 2 != 1)) { + throw Exception("Malformed conditional statement.", PyExcType::kValue); + } + Object::Ref c2; + Object::Ref c2_prev; + for (Py_ssize_t i = 0; i < (size - 1); i += 2) { + c2 = Object::New(); + if (c2_prev.exists()) { + c2->left_child = c2_prev; + } else { + DoAddConditions(PyTuple_GET_ITEM(cond_obj, i), &c2->left_child); + } + DoAddConditions(PyTuple_GET_ITEM(cond_obj, i + 2), &c2->right_child); + + // Pull a string from between to set up our opmode with. + std::string opmode_str = + Python::GetPyString(PyTuple_GET_ITEM(cond_obj, i + 1)); + const char* opmode = opmode_str.c_str(); + if (!strcmp(opmode, "&&") || !strcmp(opmode, "and")) { + c2->opmode = MaterialConditionNode::OpMode::AND_OPERATOR; + } else if (!strcmp(opmode, "||") || !strcmp(opmode, "or")) { + c2->opmode = MaterialConditionNode::OpMode::OR_OPERATOR; + } else if (!strcmp(opmode, "^") || !strcmp(opmode, "xor")) { + c2->opmode = MaterialConditionNode::OpMode::XOR_OPERATOR; + } else { + throw Exception( + std::string("Invalid conditional operator: \"") + opmode + "\".", + PyExcType::kValue); + } + c2_prev = c2; + } + // Keep our lowest level. + (*c) = c2; + } + } else { + throw Exception("Conditions argument not a tuple.", PyExcType::kType); + } +} + +void DoAddAction(PyObject* actions_obj, + std::vector >* actions) { + assert(InGameThread()); + if (!PyTuple_Check(actions_obj)) { + throw Exception("Expected a tuple.", PyExcType::kType); + } + Py_ssize_t size = PyTuple_GET_SIZE(actions_obj); + assert(size > 0); + PyObject* obj = PyTuple_GET_ITEM(actions_obj, 0); + std::string type = Python::GetPyString(obj); + if (type == "call") { + if (size != 3) { + throw Exception("Expected 3 values for command action tuple.", + PyExcType::kValue); + } + std::string when = Python::GetPyString(PyTuple_GET_ITEM(actions_obj, 1)); + bool at_disconnect; + if (when == "at_connect") { + at_disconnect = false; + } else if (when == "at_disconnect") { + at_disconnect = true; + } else { + throw Exception("Invalid command execution time: '" + when + "'.", + PyExcType::kValue); + } + PyObject* call_obj = PyTuple_GET_ITEM(actions_obj, 2); + (*actions).push_back(Object::New( + at_disconnect, call_obj)); + } else if (type == "message") { + if (size < 4) { + throw Exception("Expected >= 4 values for message action tuple.", + PyExcType::kValue); + } + std::string target = Python::GetPyString(PyTuple_GET_ITEM(actions_obj, 1)); + bool target_other_val; + if (target == "our_node") { + target_other_val = false; + } else if (target == "their_node") { + target_other_val = true; + } else { + throw Exception("Invalid message target: '" + target + "'.", + PyExcType::kValue); + } + std::string when = Python::GetPyString(PyTuple_GET_ITEM(actions_obj, 2)); + bool at_disconnect; + if (when == "at_connect") { + at_disconnect = false; + } else if (when == "at_disconnect") { + at_disconnect = true; + } else { + throw Exception("Invalid command execution time: '" + when + "'.", + PyExcType::kValue); + } + + // Pull the rest of the message. + Buffer b; + PyObject* user_message_obj = nullptr; + Python::DoBuildNodeMessage(actions_obj, 3, &b, &user_message_obj); + if (user_message_obj) { + (*actions).push_back( + Object::New( + target_other_val, at_disconnect, user_message_obj)); + } else if (b.size() > 0) { + (*actions).push_back( + Object::New( + target_other_val, at_disconnect, b.data(), b.size())); + } + } else if (type == "modify_node_collision") { + if (size != 3) { + throw Exception( + "Expected 3 values for modify_node_collision action tuple.", + PyExcType::kValue); + } + std::string attr = Python::GetPyString(PyTuple_GET_ITEM(actions_obj, 1)); + NodeCollideAttr attr_type; + if (attr == "collide") { + attr_type = NodeCollideAttr::kCollideNode; + } else { + throw Exception("Invalid node mod attr: '" + attr + "'.", + PyExcType::kValue); + } + + // Pull value. + float val = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 2)); + (*actions).push_back( + Object::New(attr_type, val)); + } else if (type == "modify_part_collision") { + if (size != 3) { + throw Exception( + "Expected 3 values for modify_part_collision action tuple.", + PyExcType::kValue); + } + PartCollideAttr attr_type; + std::string attr = Python::GetPyString(PyTuple_GET_ITEM(actions_obj, 1)); + if (attr == "physical") { + attr_type = PartCollideAttr::kPhysical; + } else if (attr == "friction") { + attr_type = PartCollideAttr::kFriction; + } else if (attr == "collide") { + attr_type = PartCollideAttr::kCollide; + } else if (attr == "use_node_collide") { + attr_type = PartCollideAttr::kUseNodeCollide; + } else if (attr == "stiffness") { + attr_type = PartCollideAttr::kStiffness; + } else if (attr == "damping") { + attr_type = PartCollideAttr::kDamping; + } else if (attr == "bounce") { + attr_type = PartCollideAttr::kBounce; + } else { + throw Exception("Invalid part mod attr: '" + attr + "'.", + PyExcType::kValue); + } + float val = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 2)); + (*actions).push_back( + Object::New(attr_type, val)); + } else if (type == "sound") { + if (size != 3) { + throw Exception("Expected 3 values for sound action tuple.", + PyExcType::kValue); + } + Sound* sound = Python::GetPySound(PyTuple_GET_ITEM(actions_obj, 1)); + float volume = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 2)); + (*actions).push_back( + Object::New(sound, volume)); + } else if (type == "impact_sound") { + if (size != 4) { + throw Exception("Expected 4 values for impact_sound action tuple.", + PyExcType::kValue); + } + PyObject* sounds_obj = PyTuple_GET_ITEM(actions_obj, 1); + std::vector sounds; + if (PySequence_Check(sounds_obj)) { + sounds = Python::GetPySounds(sounds_obj); // Sequence of sounds. + } else { + sounds.push_back(Python::GetPySound(sounds_obj)); // Single sound. + } + if (sounds.empty()) { + throw Exception("Require at least 1 sound.", PyExcType::kValue); + } + if (Utils::HasNullMembers(sounds)) { + throw Exception("One or more invalid sound refs passed.", + PyExcType::kValue); + } + float target_impulse = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 2)); + float volume = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 3)); + (*actions).push_back(Object::New( + sounds, target_impulse, volume)); + } else if (type == "skid_sound") { + if (size != 4) { + throw Exception("Expected 4 values for skid_sound action tuple.", + PyExcType::kValue); + } + Sound* sound = Python::GetPySound(PyTuple_GET_ITEM(actions_obj, 1)); + float target_impulse = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 2)); + float volume = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 3)); + (*actions).push_back(Object::New( + sound, target_impulse, volume)); + } else if (type == "roll_sound") { + if (size != 4) { + throw Exception("Expected 4 values for roll_sound action tuple.", + PyExcType::kValue); + } + Sound* sound = Python::GetPySound(PyTuple_GET_ITEM(actions_obj, 1)); + float target_impulse = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 2)); + float volume = Python::GetPyFloat(PyTuple_GET_ITEM(actions_obj, 3)); + (*actions).push_back(Object::New( + sound, target_impulse, volume)); + } else { + throw Exception("Invalid action type: '" + type + "'.", PyExcType::kValue); + } +} + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_material.h b/src/ballistica/python/class/python_class_material.h new file mode 100644 index 00000000..7e759903 --- /dev/null +++ b/src/ballistica/python/class/python_class_material.h @@ -0,0 +1,46 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_MATERIAL_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_MATERIAL_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassMaterial : public PythonClass { + public: + static auto type_name() -> const char* { return "Material"; } + static void SetupType(PyTypeObject* obj); + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + + auto GetMaterial(bool doraise = true) const -> Material* { + Material* m = material_->get(); + if ((!m) && doraise) throw Exception("Invalid Material"); + return m; + } + + private: + static bool s_create_empty_; + static PyMethodDef tp_methods[]; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void Delete(Object::Ref* m); + static void tp_dealloc(PythonClassMaterial* self); + static auto tp_getattro(PythonClassMaterial* self, PyObject* attr) + -> PyObject*; + static auto tp_setattro(PythonClassMaterial* self, PyObject* attr, + PyObject* val) -> int; + static auto tp_repr(PythonClassMaterial* self) -> PyObject*; + static auto AddActions(PythonClassMaterial* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto Dir(PythonClassMaterial* self) -> PyObject*; + Object::Ref* material_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_MATERIAL_H_ diff --git a/src/ballistica/python/class/python_class_model.cc b/src/ballistica/python/class/python_class_model.cc new file mode 100644 index 00000000..65966b02 --- /dev/null +++ b/src/ballistica/python/class/python_class_model.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_model.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/media/component/model.h" + +namespace ballistica { + +auto PythonClassModel::tp_repr(PythonClassModel* self) -> PyObject* { + BA_PYTHON_TRY; + Object::Ref m = *(self->model_); + return Py_BuildValue( + "s", (std::string("name() + "\"") : "(empty ref)") + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +void PythonClassModel::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Model"; + obj->tp_basicsize = sizeof(PythonClassModel); + obj->tp_doc = + "A reference to a model.\n" + "\n" + "Category: Asset Classes\n" + "\n" + "Models are used for drawing.\n" + "Use ba.getmodel() to instantiate one."; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; +} + +auto PythonClassModel::Create(Model* model) -> PyObject* { + s_create_empty_ = true; // prevent class from erroring on create + auto* t = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!t) { + throw Exception("ba.Model creation failed."); + } + *(t->model_) = model; + return reinterpret_cast(t); +} + +auto PythonClassModel::GetModel(bool doraise) const -> Model* { + Model* model = model_->get(); + if (!model && doraise) { + throw Exception("Invalid Model.", PyExcType::kNotFound); + } + return model; +} + +auto PythonClassModel::tp_new(PyTypeObject* type, PyObject* args, + PyObject* kwds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + if (!s_create_empty_) { + throw Exception( + "Can't instantiate Models directly; use ba.getmodel() to get " + "them."); + } + self->model_ = new Object::Ref(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassModel::Delete(Object::Ref* ref) { + assert(InGameThread()); + + // if we're the py-object for a model, clear them out + // (FIXME - we should pass the old pointer in here to sanity-test that we + // were their ref) + if (ref->exists()) { + (*ref)->ClearPyObject(); + } + delete ref; +} + +void PythonClassModel::tp_dealloc(PythonClassModel* self) { + BA_PYTHON_TRY; + // these have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately + if (!InGameThread()) { + Object::Ref* m = self->model_; + g_game->PushCall([m] { Delete(m); }); + } else { + Delete(self->model_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +bool PythonClassModel::s_create_empty_ = false; +PyTypeObject PythonClassModel::type_obj; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_model.h b/src/ballistica/python/class/python_class_model.h new file mode 100644 index 00000000..b6ca9f7c --- /dev/null +++ b/src/ballistica/python/class/python_class_model.h @@ -0,0 +1,34 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_MODEL_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_MODEL_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassModel : public PythonClass { + public: + static auto type_name() -> const char* { return "Model"; } + static auto tp_repr(PythonClassModel* self) -> PyObject*; + static void SetupType(PyTypeObject* obj); + static PyTypeObject type_obj; + static auto Create(Model* model) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + auto GetModel(bool doraise = true) const -> Model*; + + private: + static bool s_create_empty_; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject*; + static void tp_dealloc(PythonClassModel* self); + static void Delete(Object::Ref* ref); + Object::Ref* model_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_MODEL_H_ diff --git a/src/ballistica/python/class/python_class_node.cc b/src/ballistica/python/class/python_class_node.cc new file mode 100644 index 00000000..cee7795e --- /dev/null +++ b/src/ballistica/python/class/python_class_node.cc @@ -0,0 +1,458 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_node.h" + +#include +#include + +#include "ballistica/game/game_stream.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +// Ignore a few things that python macros do. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "RedundantCast" + +PyNumberMethods PythonClassNode::as_number_; + +void PythonClassNode::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_name = "ba.Node"; + obj->tp_basicsize = sizeof(PythonClassNode); + obj->tp_doc = + "Reference to a Node; the low level building block of the game.\n" + "\n" + "Category: Gameplay Classes\n" + "\n" + "At its core, a game is nothing more than a scene of Nodes\n" + "with attributes getting interconnected or set over time.\n" + "\n" + "A ba.Node instance should be thought of as a weak-reference\n" + "to a game node; *not* the node itself. This means a Node's\n" + "lifecycle is completely independent of how many Python references\n" + "to it exist. To explicitly add a new node to the game, use\n" + "ba.newnode(), and to explicitly delete one, use ba.Node.delete().\n" + "ba.Node.exists() can be used to determine if a Node still points to\n" + "a live node in the game.\n" + "\n" + "You can use ba.Node(None) to instantiate an invalid\n" + "Node reference (sometimes used as attr values/etc)."; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_getattro = (getattrofunc)tp_getattro; + obj->tp_setattro = (setattrofunc)tp_setattro; + obj->tp_methods = tp_methods; + + // We provide number methods only for bool functionality. + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_bool = (inquiry)nb_bool; + obj->tp_as_number = &as_number_; +} + +auto PythonClassNode::Create(Node* node) -> PyObject* { + // Make sure we only have one python ref per node. + if (node) { + assert(!node->has_py_ref()); + } + + s_create_empty_ = true; // Prevent class from erroring on create. + auto* py_node = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!py_node) { + throw Exception("ba.Node creation failed."); + } + + *(py_node->node_) = node; + return reinterpret_cast(py_node); +} + +auto PythonClassNode::GetNode(bool doraise) const -> Node* { + Node* n = node_->get(); + if (!n && doraise) { + throw Exception(PyExcType::kNodeNotFound); + } + return n; +} + +auto PythonClassNode::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + if (!s_create_empty_) { + if (!PyTuple_Check(args) || (PyTuple_GET_SIZE(args) != 1) + || (keywds != nullptr) || (PyTuple_GET_ITEM(args, 0) != Py_None)) { + throw Exception( + "Can't create Nodes this way; use ba.newnode() or use " + "ba.Node(None) to get an invalid reference."); + } + } + self->node_ = new Object::WeakRef(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassNode::tp_dealloc(PythonClassNode* self) { + BA_PYTHON_TRY; + // These have to be deleted in the game thread; send the ptr along if need + // be; otherwise do it immediately. + if (!InGameThread()) { + Object::WeakRef* n = self->node_; + g_game->PushCall([n] { delete n; }); + } else { + delete self->node_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassNode::tp_repr(PythonClassNode* self) -> PyObject* { + BA_PYTHON_TRY; + Node* node = self->node_->get(); + return Py_BuildValue( + "s", + std::string("id()) + " ") : "") + + (node ? ("'" + node->label() + "'") : "(empty ref)") + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassNode::tp_getattro(PythonClassNode* self, PyObject* attr) + -> PyObject* { + BA_PYTHON_TRY; + + // Do we need to support other attr types? + assert(PyUnicode_Check(attr)); + + // If our node exists and has this attr, return it. + // Otherwise do default python path. + Node* node = self->node_->get(); + const char* attr_name = PyUnicode_AsUTF8(attr); + if (node && node->HasAttribute(attr_name)) { + return Python::GetNodeAttr(node, attr_name); + } else { + return PyObject_GenericGetAttr(reinterpret_cast(self), attr); + } + BA_PYTHON_CATCH; +} + +auto PythonClassNode::Exists(PythonClassNode* self) -> PyObject* { + BA_PYTHON_TRY; + if (self->node_->exists()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PythonClassNode::GetNodeType(PythonClassNode* self) -> PyObject* { + BA_PYTHON_TRY; + + Node* node = self->node_->get(); + if (!node) { + throw Exception(PyExcType::kNodeNotFound); + } + return PyUnicode_FromString(node->type()->name().c_str()); + + BA_PYTHON_CATCH; +} + +auto PythonClassNode::GetName(PythonClassNode* self) -> PyObject* { + BA_PYTHON_TRY; + + Node* node = self->node_->get(); + if (!node) { + throw Exception(PyExcType::kNodeNotFound); + } + return PyUnicode_FromString(node->label().c_str()); + + BA_PYTHON_CATCH; +} + +auto PythonClassNode::GetDelegate(PythonClassNode* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + static const char* kwlist[] = {"type", "doraise", nullptr}; + PyObject* type_obj{}; + int doraise{}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|p", + const_cast(kwlist), &type_obj, + &doraise)) { + return nullptr; + } + Node* node = self->node_->get(); + if (!node) { + throw Exception(PyExcType::kNodeNotFound); + } + if (!PyType_Check(type_obj)) { + throw Exception("Passed type arg is not a type.", PyExcType::kType); + } + if (PyObject* obj = node->GetDelegate()) { + int isinst = PyObject_IsInstance(obj, type_obj); + if (isinst == -1) { + return nullptr; + } + if (isinst) { + Py_INCREF(obj); + return obj; + } else { + if (doraise) { + throw Exception("Requested delegate type not found on '" + + node->type()->name() + + "' node. (type=" + Python::ObjToString(type_obj) + + ", delegate=" + Python::ObjToString(obj) + ")", + PyExcType::kDelegateNotFound); + } + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassNode::Delete(PythonClassNode* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + int ignore_missing = 1; + static const char* kwlist[] = {"ignore_missing", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|i", const_cast(kwlist), &ignore_missing)) { + return nullptr; + } + Node* node = self->node_->get(); + if (!node) { + if (!ignore_missing) { + throw Exception(PyExcType::kNodeNotFound); + } + } else { + node->scene()->DeleteNode(node); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassNode::HandleMessage(PythonClassNode* self, PyObject* args) + -> PyObject* { + BA_PYTHON_TRY; + Py_ssize_t tuple_size = PyTuple_GET_SIZE(args); + if (tuple_size < 1) { + PyErr_SetString(PyExc_AttributeError, "must provide at least 1 arg"); + return nullptr; + } + Buffer b; + PyObject* user_message_obj; + Python::DoBuildNodeMessage(args, 0, &b, &user_message_obj); + + // Should we fail if the node doesn't exist?? + Node* node = self->node_->get(); + if (node) { + HostActivity* host_activity = node->context().GetHostActivity(); + if (!host_activity) { + throw Exception("Invalid context.", PyExcType::kContext); + } + // For user messages we pass them directly to the node + // since by their nature they don't go out over the network and are just + // for use within the scripting system. + if (user_message_obj) { + node->DispatchUserMessage(user_message_obj, "Node User-Message dispatch"); + } else { + if (GameStream* output_stream = node->scene()->GetGameStream()) { + output_stream->NodeMessage(node, b.data(), b.size()); + } + node->DispatchNodeMessage(b.data()); + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassNode::AddDeathAction(PythonClassNode* self, PyObject* args) + -> PyObject* { + BA_PYTHON_TRY; + PyObject* call_obj; + if (!PyArg_ParseTuple(args, "O", &call_obj)) { + return nullptr; + } + Node* n = self->node_->get(); + if (!n) { + throw Exception(PyExcType::kNodeNotFound); + } + + // We don't have to go through a host-activity but lets make sure we're in + // one. + HostActivity* host_activity = n->context().GetHostActivity(); + if (!host_activity) { + throw Exception("Invalid context.", PyExcType::kContext); + } + n->AddNodeDeathAction(call_obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassNode::ConnectAttr(PythonClassNode* self, PyObject* args) + -> PyObject* { + BA_PYTHON_TRY; + PyObject* dst_node_obj; + Node* node = self->node_->get(); + if (!node) { + throw Exception(PyExcType::kNodeNotFound); + } + char *src_attr_name, *dst_attr_name; + if (!PyArg_ParseTuple(args, "sOs", &src_attr_name, &dst_node_obj, + &dst_attr_name)) { + return nullptr; + } + + // Allow dead-refs and None. + Node* dst_node = Python::GetPyNode(dst_node_obj, true, true); + if (!dst_node) { + throw Exception(PyExcType::kNodeNotFound); + } + NodeAttributeUnbound* src_attr = + node->type()->GetAttribute(std::string(src_attr_name)); + NodeAttributeUnbound* dst_attr = + dst_node->type()->GetAttribute(std::string(dst_attr_name)); + + // Push to output_stream first to catch scene mismatch errors. + if (GameStream* output_stream = node->scene()->GetGameStream()) { + output_stream->ConnectNodeAttribute(node, src_attr, dst_node, dst_attr); + } + + // Now apply locally. + node->ConnectAttribute(src_attr, dst_node, dst_attr); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassNode::Dir(PythonClassNode* self) -> PyObject* { + BA_PYTHON_TRY; + + // Start with the standard python dir listing. + PyObject* dir_list = Python::generic_dir(reinterpret_cast(self)); + assert(PyList_Check(dir_list)); + + // ..now grab all this guy's BA attributes and add them in. + Node* node = self->node_->get(); + if (node) { + std::list attrs; + node->ListAttributes(&attrs); + for (auto& attr : attrs) { + PyList_Append(dir_list, PythonRef(PyUnicode_FromString(attr.c_str()), + PythonRef::kSteal) + .get()); + } + } + PyList_Sort(dir_list); + return dir_list; + BA_PYTHON_CATCH; +} + +auto PythonClassNode::nb_bool(PythonClassNode* self) -> int { + return self->node_->exists(); +} + +auto PythonClassNode::tp_setattro(PythonClassNode* self, PyObject* attr, + PyObject* val) -> int { + BA_PYTHON_TRY; + + // FIXME: do we need to support other attr types? + assert(PyUnicode_Check(attr)); + Node* n = self->node_->get(); + if (!n) { + throw Exception(PyExcType::kNodeNotFound); + } + Python::SetNodeAttr(n, PyUnicode_AsUTF8(attr), val); + return 0; + BA_PYTHON_INT_CATCH; +} + +PyMethodDef PythonClassNode::tp_methods[] = { + {"exists", (PyCFunction)Exists, METH_NOARGS, + "exists() -> bool\n" + "\n" + "Returns whether the Node still exists.\n" + "Most functionality will fail on a nonexistent Node, so it's never a bad\n" + "idea to check this.\n" + "\n" + "Note that you can also use the boolean operator for this same\n" + "functionality, so a statement such as \"if mynode\" will do\n" + "the right thing both for Node objects and values of None."}, + {"getnodetype", (PyCFunction)GetNodeType, METH_NOARGS, + "getnodetype() -> str\n" + "\n" + "Return the type of Node referenced by this object as a string.\n" + "(Note this is different from the Python type which is always ba.Node)"}, + {"getname", (PyCFunction)GetName, METH_NOARGS, + "getname() -> str\n" + "\n" + "Return the name assigned to a Node; used mainly for debugging"}, + {"getdelegate", (PyCFunction)GetDelegate, METH_VARARGS | METH_KEYWORDS, + "getdelegate(type: Type, doraise: bool = False) -> \n" + "\n" + "Return the node's current delegate object if it matches a certain type.\n" + "\n" + "If the node has no delegate or it is not an instance of the passed\n" + "type, then None will be returned. If 'doraise' is True, then an\n" + "ba.DelegateNotFoundError will be raised instead."}, + {"delete", (PyCFunction)Delete, METH_VARARGS | METH_KEYWORDS, + "delete(ignore_missing: bool = True) -> None\n" + "\n" + "Delete the node. Ignores already-deleted nodes if ignore_missing\n" + "is True; otherwise a ba.NodeNotFoundError is thrown."}, + {"handlemessage", (PyCFunction)HandleMessage, METH_VARARGS, + "handlemessage(*args: Any) -> None\n" + "\n" + "General message handling; can be passed any message object.\n" + "\n" + "All standard message objects are forwarded along to the ba.Node's\n" + "delegate for handling (generally the ba.Actor that made the node).\n" + "\n" + "ba.Nodes are unique, however, in that they can be passed a second\n" + "form of message; 'node-messages'. These consist of a string type-name\n" + "as a first argument along with the args specific to that type name\n" + "as additional arguments.\n" + "Node-messages communicate directly with the low-level node layer\n" + "and are delivered simultaneously on all game clients,\n" + "acting as an alternative to setting node attributes."}, + {"add_death_action", (PyCFunction)AddDeathAction, METH_VARARGS, + "add_death_action(action: Callable[[], None]) -> None\n" + "\n" + "Add a callable object to be called upon this node's death.\n" + "Note that these actions are run just after the node dies, not before.\n"}, + {"connectattr", (PyCFunction)ConnectAttr, METH_VARARGS, + "connectattr(srcattr: str, dstnode: Node, dstattr: str) -> None\n" + "\n" + "Connect one of this node's attributes to an attribute on another node.\n" + "This will immediately set the target attribute's value to that of the\n" + "source attribute, and will continue to do so once per step as long as\n" + "the two nodes exist. The connection can be severed by setting the\n" + "target attribute to any value or connecting another node attribute\n" + "to it.\n" + "\n" + "# Example: create a locator and attach a light to it:\n" + "light = ba.newnode('light')\n" + "loc = ba.newnode('locator', attrs={'position': (0,10,0)})\n" + "loc.connectattr('position', light, 'position')"}, + {"__dir__", (PyCFunction)Dir, METH_NOARGS, + "allows inclusion of our custom attrs in standard python dir()"}, + {nullptr}}; + +bool PythonClassNode::s_create_empty_ = false; +PyTypeObject PythonClassNode::type_obj; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_node.h b/src/ballistica/python/class/python_class_node.h new file mode 100644 index 00000000..6e19773b --- /dev/null +++ b/src/ballistica/python/class/python_class_node.h @@ -0,0 +1,52 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_NODE_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_NODE_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class PythonClassNode : public PythonClass { + public: + static auto type_name() -> const char* { return "Node"; } + static void SetupType(PyTypeObject* obj); + static auto Create(Node* node) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto GetNode(bool doraise = true) const -> Node*; + + private: + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassNode* self); + static auto tp_repr(PythonClassNode* self) -> PyObject*; + static auto tp_getattro(PythonClassNode* self, PyObject* attr) -> PyObject*; + static auto tp_setattro(PythonClassNode* self, PyObject* attr, PyObject* val) + -> int; + static auto Exists(PythonClassNode* self) -> PyObject*; + static auto GetNodeType(PythonClassNode* self) -> PyObject*; + static auto GetName(PythonClassNode* self) -> PyObject*; + static auto GetDelegate(PythonClassNode* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto Delete(PythonClassNode* self, PyObject* args, PyObject* keywds) + -> PyObject*; + static auto HandleMessage(PythonClassNode* self, PyObject* args) -> PyObject*; + static auto AddDeathAction(PythonClassNode* self, PyObject* args) + -> PyObject*; + static auto ConnectAttr(PythonClassNode* self, PyObject* args) -> PyObject*; + static auto Dir(PythonClassNode* self) -> PyObject*; + static auto nb_bool(PythonClassNode* self) -> int; + static bool s_create_empty_; + static PyMethodDef tp_methods[]; + Object::WeakRef* node_; + static PyNumberMethods as_number_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_NODE_H_ diff --git a/src/ballistica/python/class/python_class_session_data.cc b/src/ballistica/python/class/python_class_session_data.cc new file mode 100644 index 00000000..57aadb34 --- /dev/null +++ b/src/ballistica/python/class/python_class_session_data.cc @@ -0,0 +1,114 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_session_data.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/game/session/session.h" +#include "ballistica/generic/utils.h" + +namespace ballistica { + +auto PythonClassSessionData::nb_bool(PythonClassSessionData* self) -> int { + return self->session_->exists(); +} + +PyNumberMethods PythonClassSessionData::as_number_; + +void PythonClassSessionData::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "_ba.SessionData"; + obj->tp_basicsize = sizeof(PythonClassSessionData); + obj->tp_doc = "(internal)"; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + + // We provide number methods only for bool functionality. + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_bool = (inquiry)nb_bool; + obj->tp_as_number = &as_number_; +} + +auto PythonClassSessionData::Create(Session* session) -> PyObject* { + auto* py_session_data = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + BA_PRECONDITION(py_session_data); + *(py_session_data->session_) = session; + return reinterpret_cast(py_session_data); +} + +auto PythonClassSessionData::GetSession() const -> Session* { + Session* session = session_->get(); + if (!session) { + throw Exception("Invalid SessionData.", PyExcType::kSessionNotFound); + } + return session; +} + +auto PythonClassSessionData::tp_repr(PythonClassSessionData* self) + -> PyObject* { + BA_PYTHON_TRY; + return Py_BuildValue("s", (std::string("session_->get()) + " >") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassSessionData::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = + reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + self->session_ = new Object::WeakRef(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassSessionData::tp_dealloc(PythonClassSessionData* self) { + BA_PYTHON_TRY; + // These have to be deleted in the game thread; + // ...send the ptr along if need be. + // FIXME: technically the main thread has a pointer to a dead PyObject + // until the delete goes through; could that ever be a problem? + if (!InGameThread()) { + Object::WeakRef* s = self->session_; + g_game->PushCall([s] { delete s; }); + } else { + delete self->session_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassSessionData::Exists(PythonClassSessionData* self) -> PyObject* { + BA_PYTHON_TRY; + Session* sgc = self->session_->get(); + if (sgc) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +PyTypeObject PythonClassSessionData::type_obj; +PyMethodDef PythonClassSessionData::tp_methods[] = { + {"exists", (PyCFunction)Exists, METH_NOARGS, + "exists() -> bool\n" + "\n" + "Returns whether the SessionData still exists.\n" + "Most functionality will fail on a nonexistent instance."}, + {nullptr}}; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_session_data.h b/src/ballistica/python/class/python_class_session_data.h new file mode 100644 index 00000000..1d32287b --- /dev/null +++ b/src/ballistica/python/class/python_class_session_data.h @@ -0,0 +1,36 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SESSION_DATA_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SESSION_DATA_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassSessionData : public PythonClass { + public: + static auto type_name() -> const char* { return "SessionData"; } + static void SetupType(PyTypeObject* obj); + static auto Create(Session* session) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto GetSession() const -> Session*; + + private: + static PyMethodDef tp_methods[]; + static auto tp_repr(PythonClassSessionData* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassSessionData* self); + static auto Exists(PythonClassSessionData* self) -> PyObject*; + Object::WeakRef* session_; + static auto nb_bool(PythonClassSessionData* self) -> int; + static PyNumberMethods as_number_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SESSION_DATA_H_ diff --git a/src/ballistica/python/class/python_class_session_player.cc b/src/ballistica/python/class/python_class_session_player.cc new file mode 100644 index 00000000..a407107b --- /dev/null +++ b/src/ballistica/python/class/python_class_session_player.cc @@ -0,0 +1,746 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_session_player.h" + +#include +#include + +#include "ballistica/game/host_activity.h" +#include "ballistica/game/player.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "RedundantCast" + +auto PythonClassSessionPlayer::nb_bool(PythonClassSessionPlayer* self) -> int { + return self->player_->exists(); +} + +PyNumberMethods PythonClassSessionPlayer::as_number_; + +// Attrs we expose through our custom getattr/setattr. +#define ATTR_IN_GAME "in_game" +#define ATTR_SESSIONTEAM "sessionteam" +#define ATTR_COLOR "color" +#define ATTR_HIGHLIGHT "highlight" +#define ATTR_CHARACTER "character" +#define ATTR_ACTIVITYPLAYER "activityplayer" +#define ATTR_ID "id" +#define ATTR_INPUT_DEVICE "inputdevice" + +// The set we expose via dir(). +static const char* extra_dir_attrs[] = { + ATTR_ID, ATTR_IN_GAME, ATTR_SESSIONTEAM, ATTR_COLOR, + ATTR_HIGHLIGHT, ATTR_CHARACTER, ATTR_INPUT_DEVICE, nullptr}; + +void PythonClassSessionPlayer::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.SessionPlayer"; + obj->tp_basicsize = sizeof(PythonClassSessionPlayer); + + // clang-format off + + obj->tp_doc = + "A reference to a player in the ba.Session.\n" + "\n" + "Category: Gameplay Classes\n" + "\n" + "These are created and managed internally and\n" + "provided to your Session/Activity instances.\n" + "Be aware that, like ba.Nodes, ba.SessionPlayer objects are 'weak'\n" + "references under-the-hood; a player can leave the game at\n" + " any point. For this reason, you should make judicious use of the\n" + "ba.SessionPlayer.exists() method (or boolean operator) to ensure\n" + "that a SessionPlayer is still present if retaining references to one\n" + "for any length of time.\n" + "\n" + "Attributes:\n" + "\n" + " " ATTR_ID ": int\n" + " The unique numeric ID of the Player.\n" + "\n" + " Note that you can also use the boolean operator for this same\n" + " functionality, so a statement such as \"if player\" will do\n" + " the right thing both for Player objects and values of None.\n" + "\n" + " " ATTR_IN_GAME ": bool\n" + " This bool value will be True once the Player has completed\n" + " any lobby character/team selection.\n" + "\n" + " " ATTR_SESSIONTEAM ": ba.SessionTeam\n" + " The ba.SessionTeam this Player is on. If the SessionPlayer\n" + " is still in its lobby selecting a team/etc. then a\n" + " ba.SessionTeamNotFoundError will be raised.\n" + "\n" + " " ATTR_INPUT_DEVICE ": ba.InputDevice\n" + " The input device associated with the player.\n" + "\n" + " " ATTR_COLOR ": Sequence[float]\n" + " The base color for this Player.\n" + " In team games this will match the ba.SessionTeam's color.\n" + "\n" + " " ATTR_HIGHLIGHT ": Sequence[float]\n" + " A secondary color for this player.\n" + " This is used for minor highlights and accents\n" + " to allow a player to stand apart from his teammates\n" + " who may all share the same team (primary) color.\n" + "\n" + " " ATTR_CHARACTER ": str\n" + " The character this player has selected in their profile.\n" + "\n" + " " ATTR_ACTIVITYPLAYER ": Optional[ba.Player]\n" + " The current game-specific instance for this player.\n"; + + // clang-format on + + obj->tp_new = tp_new; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_getattro = (getattrofunc)tp_getattro; + obj->tp_setattro = (setattrofunc)tp_setattro; + + // We provide number methods only for bool functionality. + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_bool = (inquiry)nb_bool; + obj->tp_as_number = &as_number_; +} + +auto PythonClassSessionPlayer::Create(Player* player) -> PyObject* { + // Make sure we only have one python ref per material. + if (player) { + assert(!player->has_py_ref()); + } + s_create_empty_ = true; // Prevent class from erroring on create. + auto* py_player = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!py_player) { + throw Exception("ba.Player creation failed."); + } + + *(py_player->player_) = player; + return reinterpret_cast(py_player); +} + +auto PythonClassSessionPlayer::GetPlayer(bool doraise) const -> Player* { + Player* player = player_->get(); + if ((!player) && doraise) { + throw Exception("Invalid SessionPlayer.", + PyExcType::kSessionPlayerNotFound); + } + return player; +} + +auto PythonClassSessionPlayer::tp_repr(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + Player* p = self->player_->get(); + int player_id = p ? p->id() : -1; + std::string p_name = p ? p->GetName() : "invalid"; + return Py_BuildValue("s", + (std::string("") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = + reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + + // If the user is creating one, make sure they passed None to get an + // invalid ref. + if (!s_create_empty_) { + if (!PyTuple_Check(args) || (PyTuple_GET_SIZE(args) != 1) + || (keywds != nullptr) || (PyTuple_GET_ITEM(args, 0) != Py_None)) + throw Exception( + "Can't instantiate SessionPlayers. To create an invalid" + " SessionPlayer reference, call ba.SessionPlayer(None)."); + } + self->player_ = new Object::WeakRef(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassSessionPlayer::tp_dealloc(PythonClassSessionPlayer* self) { + BA_PYTHON_TRY; + + // These have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately. + if (!InGameThread()) { + Object::WeakRef* p = self->player_; + g_game->PushCall([p] { delete p; }); + } else { + delete self->player_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassSessionPlayer::tp_getattro(PythonClassSessionPlayer* self, + PyObject* attr) -> PyObject* { + BA_PYTHON_TRY; + + assert(InGameThread()); + + // Assuming this will always be a str? + assert(PyUnicode_Check(attr)); + + const char* s = PyUnicode_AsUTF8(attr); + if (!strcmp(s, ATTR_IN_GAME)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + + // We get placed on a team as soon as we finish in the lobby + // so lets use that as whether we're in-game or not. + PyObject* team = p->GetPyTeam(); + assert(team != nullptr); + if (team == Py_None) { + Py_RETURN_FALSE; + } else { + Py_RETURN_TRUE; + } + } else if (!strcmp(s, ATTR_ID)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + return PyLong_FromLong(p->id()); + } else if (!strcmp(s, ATTR_INPUT_DEVICE)) { + Player* player = self->player_->get(); + if (!player) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + InputDevice* input_device = player->GetInputDevice(); + if (input_device) { + return input_device->NewPyRef(); + } + throw Exception(PyExcType::kInputDeviceNotFound); + } else if (!strcmp(s, ATTR_SESSIONTEAM)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + PyObject* team = p->GetPyTeam(); + assert(team != nullptr); + if (team == Py_None) { + PyErr_SetString( + g_python->obj(Python::ObjID::kSessionTeamNotFoundError).get(), + "SessionTeam does not exist."); + return nullptr; + } + Py_INCREF(team); + return team; + } else if (!strcmp(s, ATTR_CHARACTER)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + if (!p->has_py_data()) { + BA_LOG_ONCE("Error: Calling getAttr for player attr '" + std::string(s) + + "' without data set."); + } + PyObject* obj = p->GetPyCharacter(); + Py_INCREF(obj); + return obj; + } else if (!strcmp(s, ATTR_COLOR)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + if (!p->has_py_data()) { + BA_LOG_ONCE("Error: Calling getAttr for player attr '" + std::string(s) + + "' without data set."); + } + PyObject* obj = p->GetPyColor(); + Py_INCREF(obj); + return obj; + } else if (!strcmp(s, ATTR_HIGHLIGHT)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + if (!p->has_py_data()) { + BA_LOG_ONCE("Error: Calling getAttr for player attr '" + std::string(s) + + "' without data set."); + } + PyObject* obj = p->GetPyHighlight(); + Py_INCREF(obj); + return obj; + } else if (!strcmp(s, ATTR_ACTIVITYPLAYER)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + if (!p->has_py_data()) { + BA_LOG_ONCE("Error: Calling getAttr for player attr '" + std::string(s) + + "' without data set."); + } + PyObject* obj = p->GetPyActivityPlayer(); + Py_INCREF(obj); + return obj; + } + + // Fall back to generic behavior. + PyObject* val; + val = PyObject_GenericGetAttr(reinterpret_cast(self), attr); + return val; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::tp_setattro(PythonClassSessionPlayer* self, + PyObject* attr, PyObject* val) + -> int { + BA_PYTHON_TRY; + // Assuming this will always be a str? + assert(PyUnicode_Check(attr)); + const char* s = PyUnicode_AsUTF8(attr); + + if (!strcmp(s, ATTR_ACTIVITYPLAYER)) { + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + p->SetPyActivityPlayer(val); + return 0; + } + throw Exception("Attr '" + std::string(PyUnicode_AsUTF8(attr)) + + "' is not settable on SessionPlayer objects.", + PyExcType::kAttribute); + // return PyObject_GenericSetAttr(reinterpret_cast(self), attr, + // val); + BA_PYTHON_INT_CATCH; +} + +auto PythonClassSessionPlayer::GetName(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + int full = false; + int icon = true; + static const char* kwlist[] = {"full", "icon", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|pp", + const_cast(kwlist), &full, &icon)) { + return nullptr; + } + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + return PyUnicode_FromString( + p->GetName(static_cast(full), static_cast(icon)).c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::Exists(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + if (self->player_->exists()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::SetName(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* name_obj; + PyObject* full_name_obj = Py_None; + + // This should be false for temp names like . + int real = 1; + static const char* kwlist[] = {"name", "full_name", "real", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|Op", + const_cast(kwlist), &name_obj, + &full_name_obj, &real)) { + return nullptr; + } + std::string name = Python::GetPyString(name_obj); + std::string full_name = + (full_name_obj == Py_None) ? name : Python::GetPyString(full_name_obj); + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + p->SetName(name, full_name, static_cast(real)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::ResetInput(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + p->ResetInput(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::AssignInputCall(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* input_type_obj; + PyObject* call_obj; + static const char* kwlist[] = {"type", "call", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO", + const_cast(kwlist), &input_type_obj, + &call_obj)) { + return nullptr; + } + Player* player = self->player_->get(); + if (!player) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + if (Python::IsPyEnum_InputType(input_type_obj)) { + InputType input_type = Python::GetPyEnum_InputType(input_type_obj); + player->AssignInputCall(input_type, call_obj); + } else { + if (!PyTuple_Check(input_type_obj)) { + PyErr_SetString(PyExc_TypeError, + "Expected InputType or tuple for type arg."); + return nullptr; + } + Py_ssize_t tuple_size = PyTuple_GET_SIZE(input_type_obj); + for (Py_ssize_t i = 0; i < tuple_size; i++) { + PyObject* obj = PyTuple_GET_ITEM(input_type_obj, i); + if (!Python::IsPyEnum_InputType(obj)) { + PyErr_SetString(PyExc_TypeError, "Expected tuple of InputTypes."); + return nullptr; + } + InputType input_type = Python::GetPyEnum_InputType(obj); + player->AssignInputCall(input_type, call_obj); + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::RemoveFromGame(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Player* player = self->player_->get(); + if (!player) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } else { + HostSession* host_session = player->GetHostSession(); + if (!host_session) { + throw Exception("Player's host-session not found.", + PyExcType::kSessionNotFound); + } + host_session->RemovePlayer(player); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::GetTeam(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + PyObject* team = p->GetPyTeam(); + Py_INCREF(team); + return team; + BA_PYTHON_CATCH; +} + +// NOTE: this returns their PUBLIC account-id; we want to keep +// actual account-ids as hidden as possible for now. +auto PythonClassSessionPlayer::GetAccountID(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + std::string account_id = p->GetPublicAccountID(); + if (account_id.empty()) { + Py_RETURN_NONE; + } + return PyUnicode_FromString(account_id.c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::SetData(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* team_obj; + PyObject* character_obj; + PyObject* color_obj; + PyObject* highlight_obj; + static const char* kwlist[] = {"team", "character", "color", "highlight", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "OOOO", const_cast(kwlist), &team_obj, + &character_obj, &color_obj, &highlight_obj)) { + return nullptr; + } + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + p->set_has_py_data(true); + p->SetPyTeam(team_obj); + p->SetPyCharacter(character_obj); + p->SetPyColor(color_obj); + p->SetPyHighlight(highlight_obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::GetIconInfo(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + std::vector color = p->icon_tint_color(); + std::vector color2 = p->icon_tint2_color(); + return Py_BuildValue( + "{sssss(fff)s(fff)}", "texture", p->icon_tex_name().c_str(), + "tint_texture", p->icon_tint_tex_name().c_str(), "tint_color", color[0], + color[1], color[2], "tint2_color", color2[0], color2[1], color2[2]); + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::SetIconInfo(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* texture_name_obj; + PyObject* tint_texture_name_obj; + PyObject* tint_color_obj; + PyObject* tint2_color_obj; + static const char* kwlist[] = {"texture", "tint_texture", "tint_color", + "tint2_color", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "OOOO", const_cast(kwlist), &texture_name_obj, + &tint_texture_name_obj, &tint_color_obj, &tint2_color_obj)) { + return nullptr; + } + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + std::string texture_name = Python::GetPyString(texture_name_obj); + std::string tint_texture_name = Python::GetPyString(tint_texture_name_obj); + std::vector tint_color = Python::GetPyFloats(tint_color_obj); + if (tint_color.size() != 3) { + throw Exception("Expected 3 floats for tint-color.", PyExcType::kValue); + } + std::vector tint2_color = Python::GetPyFloats(tint2_color_obj); + if (tint2_color.size() != 3) { + throw Exception("Expected 3 floats for tint-color.", PyExcType::kValue); + } + p->SetIcon(texture_name, tint_texture_name, tint_color, tint2_color); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::SetActivity(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* activity_obj; + static const char* kwlist[] = {"activity", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &activity_obj)) { + return nullptr; + } + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + HostActivity* a; + if (activity_obj == Py_None) { + a = nullptr; + } else { + a = Python::GetPyHostActivity(activity_obj); + } + p->SetHostActivity(a); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::SetNode(PythonClassSessionPlayer* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + PyObject* node_obj; + static const char* kwlist[] = {"node", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &node_obj)) { + return nullptr; + } + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + Node* node; + if (node_obj == Py_None) { + node = nullptr; + } else { + node = Python::GetPyNode(node_obj); + } + p->set_node(node); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::GetIcon(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Player* p = self->player_->get(); + if (!p) { + throw Exception(PyExcType::kSessionPlayerNotFound); + } + + // Now kindly ask the activity to load/return an icon for us. + PythonRef args(Py_BuildValue("(O)", p->BorrowPyRef()), PythonRef::kSteal); + PythonRef results; + { + Python::ScopedCallLabel label("get_player_icon"); + results = g_python->obj(Python::ObjID::kGetPlayerIconCall).Call(args); + } + return results.NewRef(); + BA_PYTHON_CATCH; +} + +auto PythonClassSessionPlayer::Dir(PythonClassSessionPlayer* self) + -> PyObject* { + BA_PYTHON_TRY; + + // Start with the standard python dir listing. + PyObject* dir_list = Python::generic_dir(reinterpret_cast(self)); + assert(PyList_Check(dir_list)); + + // ..and add in our custom attr names. + for (const char** name = extra_dir_attrs; *name != nullptr; name++) { + PyList_Append( + dir_list, + PythonRef(PyUnicode_FromString(*name), PythonRef::kSteal).get()); + } + PyList_Sort(dir_list); + return dir_list; + + BA_PYTHON_CATCH; +} + +bool PythonClassSessionPlayer::s_create_empty_ = false; +PyTypeObject PythonClassSessionPlayer::type_obj; +PyMethodDef PythonClassSessionPlayer::tp_methods[] = { + {"getname", (PyCFunction)GetName, METH_VARARGS | METH_KEYWORDS, + "getname(full: bool = False, icon: bool = True) -> str\n" + "\n" + "Returns the player's name. If icon is True, the long version of the\n" + "name may include an icon."}, + {"setname", (PyCFunction)SetName, METH_VARARGS | METH_KEYWORDS, + "setname(name: str, full_name: str = None, real: bool = True)\n" + " -> None\n" + "\n" + "Set the player's name to the provided string.\n" + "A number will automatically be appended if the name is not unique from\n" + "other players."}, + {"resetinput", (PyCFunction)ResetInput, METH_NOARGS, + "resetinput() -> None\n" + "\n" + "Clears out the player's assigned input actions."}, + {"exists", (PyCFunction)Exists, METH_NOARGS, + "exists() -> bool\n" + "\n" + "Return whether the underlying player is still in the game."}, + {"assigninput", (PyCFunction)AssignInputCall, METH_VARARGS | METH_KEYWORDS, + "assigninput(type: Union[ba.InputType, Tuple[ba.InputType, ...]],\n" + " call: Callable) -> None\n" + "\n" + "Set the python callable to be run for one or more types of input."}, + {"remove_from_game", (PyCFunction)RemoveFromGame, METH_NOARGS, + "remove_from_game() -> None\n" + "\n" + "Removes the player from the game."}, + {"get_account_id", (PyCFunction)GetAccountID, METH_VARARGS | METH_KEYWORDS, + "get_account_id() -> str\n" + "\n" + "Return the Account ID this player is signed in under, if\n" + "there is one and it can be determined with relative certainty.\n" + "Returns None otherwise. Note that this may require an active\n" + "internet connection (especially for network-connected players)\n" + "and may return None for a short while after a player initially\n" + "joins (while verification occurs)."}, + {"setdata", (PyCFunction)SetData, METH_VARARGS | METH_KEYWORDS, + "setdata(team: ba.SessionTeam, character: str,\n" + " color: Sequence[float], highlight: Sequence[float]) -> None\n" + "\n" + "(internal)"}, + {"set_icon_info", (PyCFunction)SetIconInfo, METH_VARARGS | METH_KEYWORDS, + "set_icon_info(texture: str, tint_texture: str,\n" + " tint_color: Sequence[float], tint2_color: Sequence[float]) -> None\n" + "\n" + "(internal)"}, + {"setactivity", (PyCFunction)SetActivity, METH_VARARGS | METH_KEYWORDS, + "setactivity(activity: Optional[ba.Activity]) -> None\n" + "\n" + "(internal)"}, + {"setnode", (PyCFunction)SetNode, METH_VARARGS | METH_KEYWORDS, + "setnode(node: Optional[Node]) -> None\n" + "\n" + "(internal)"}, + {"get_icon", (PyCFunction)GetIcon, METH_NOARGS, + "get_icon() -> Dict[str, Any]\n" + "\n" + "Returns the character's icon (images, colors, etc contained in a dict)"}, + {"get_icon_info", (PyCFunction)GetIconInfo, METH_NOARGS, + "get_icon_info() -> Dict[str, Any]\n" + "\n" + "(internal)"}, + {"__dir__", (PyCFunction)Dir, METH_NOARGS, + "allows inclusion of our custom attrs in standard python dir()"}, + {nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_session_player.h b/src/ballistica/python/class/python_class_session_player.h new file mode 100644 index 00000000..bbfb8223 --- /dev/null +++ b/src/ballistica/python/class/python_class_session_player.h @@ -0,0 +1,62 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SESSION_PLAYER_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SESSION_PLAYER_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassSessionPlayer : public PythonClass { + public: + static auto type_name() -> const char* { return "SessionPlayer"; } + static void SetupType(PyTypeObject* obj); + static auto Create(Player* player) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto GetPlayer(bool doraise) const -> Player*; + + private: + static bool s_create_empty_; + static PyMethodDef tp_methods[]; + static auto tp_repr(PythonClassSessionPlayer* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassSessionPlayer* self); + static auto tp_getattro(PythonClassSessionPlayer* self, PyObject* attr) + -> PyObject*; + static auto tp_setattro(PythonClassSessionPlayer* self, PyObject* attr, + PyObject* val) -> int; + static auto GetName(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto Exists(PythonClassSessionPlayer* self) -> PyObject*; + static auto SetName(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto ResetInput(PythonClassSessionPlayer* self) -> PyObject*; + static auto AssignInputCall(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto RemoveFromGame(PythonClassSessionPlayer* self) -> PyObject*; + static auto GetTeam(PythonClassSessionPlayer* self) -> PyObject*; + static auto GetAccountID(PythonClassSessionPlayer* self) -> PyObject*; + static auto SetData(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto GetIconInfo(PythonClassSessionPlayer* self) -> PyObject*; + static auto SetIconInfo(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto SetActivity(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto SetNode(PythonClassSessionPlayer* self, PyObject* args, + PyObject* keywds) -> PyObject*; + static auto GetIcon(PythonClassSessionPlayer* self) -> PyObject*; + static auto Dir(PythonClassSessionPlayer* self) -> PyObject*; + Object::WeakRef* player_; + static auto nb_bool(PythonClassSessionPlayer* self) -> int; + static PyNumberMethods as_number_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SESSION_PLAYER_H_ diff --git a/src/ballistica/python/class/python_class_sound.cc b/src/ballistica/python/class/python_class_sound.cc new file mode 100644 index 00000000..960fa0dc --- /dev/null +++ b/src/ballistica/python/class/python_class_sound.cc @@ -0,0 +1,108 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_sound.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +auto PythonClassSound::tp_repr(PythonClassSound* self) -> PyObject* { + BA_PYTHON_TRY; + Object::Ref m = *(self->sound_); + return Py_BuildValue( + "s", (std::string("name() + "\"") : "(empty ref)") + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +void PythonClassSound::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Sound"; + obj->tp_basicsize = sizeof(PythonClassSound); + obj->tp_doc = + "A reference to a sound.\n" + "\n" + "Category: Asset Classes\n" + "\n" + "Use ba.getsound() to instantiate one."; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; +} + +auto PythonClassSound::Create(Sound* sound) -> PyObject* { + s_create_empty_ = true; // prevent class from erroring on create + auto* t = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!t) { + throw Exception("ba.Sound creation failed."); + } + *(t->sound_) = sound; + return reinterpret_cast(t); +} + +auto PythonClassSound::GetSound(bool doraise) const -> Sound* { + Sound* sound = sound_->get(); + if (!sound && doraise) { + throw Exception("Invalid Sound.", PyExcType::kNotFound); + } + return sound; +} + +auto PythonClassSound::tp_new(PyTypeObject* type, PyObject* args, + PyObject* kwds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + if (!s_create_empty_) { + throw Exception( + "Can't instantiate Sounds directly; use ba.getsound() to get " + "them."); + } + self->sound_ = new Object::Ref(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassSound::Delete(Object::Ref* ref) { + assert(InGameThread()); + + // if we're the py-object for a sound, clear them out + // (FIXME - wej should pass the old pointer in here to sanity-test that we + // were their ref) + if (ref->exists()) { + (*ref)->ClearPyObject(); + } + delete ref; +} + +void PythonClassSound::tp_dealloc(PythonClassSound* self) { + BA_PYTHON_TRY; + // these have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately + if (!InGameThread()) { + Object::Ref* s = self->sound_; + g_game->PushCall([s] { Delete(s); }); + } else { + Delete(self->sound_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +bool PythonClassSound::s_create_empty_ = false; +PyTypeObject PythonClassSound::type_obj; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_sound.h b/src/ballistica/python/class/python_class_sound.h new file mode 100644 index 00000000..ccb68bb7 --- /dev/null +++ b/src/ballistica/python/class/python_class_sound.h @@ -0,0 +1,34 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SOUND_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SOUND_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassSound : public PythonClass { + public: + static auto type_name() -> const char* { return "Sound"; } + static PyTypeObject type_obj; + static auto tp_repr(PythonClassSound* self) -> PyObject*; + static void SetupType(PyTypeObject* obj); + static auto Create(Sound* sound) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + auto GetSound(bool doraise = true) const -> Sound*; + + private: + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* kwds) + -> PyObject*; + static void tp_dealloc(PythonClassSound* self); + static void Delete(Object::Ref* ref); + static bool s_create_empty_; + Object::Ref* sound_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_SOUND_H_ diff --git a/src/ballistica/python/class/python_class_texture.cc b/src/ballistica/python/class/python_class_texture.cc new file mode 100644 index 00000000..3a366036 --- /dev/null +++ b/src/ballistica/python/class/python_class_texture.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_texture.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/media/component/texture.h" + +namespace ballistica { + +auto PythonClassTexture::tp_repr(PythonClassTexture* self) -> PyObject* { + BA_PYTHON_TRY; + Object::Ref t = *(self->texture_); + return Py_BuildValue( + "s", (std::string("name() + "\"") : "(empty ref)") + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +void PythonClassTexture::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Texture"; + obj->tp_basicsize = sizeof(PythonClassTexture); + obj->tp_doc = + "A reference to a texture.\n" + "\n" + "Category: Asset Classes\n" + "\n" + "Use ba.gettexture() to instantiate one."; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; +} + +auto PythonClassTexture::Create(Texture* texture) -> PyObject* { + s_create_empty_ = true; // prevent class from erroring on create + assert(texture != nullptr); + auto* t = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + s_create_empty_ = false; + if (!t) { + throw Exception("ba.Texture creation failed."); + } + *(t->texture_) = texture; + return reinterpret_cast(t); +} + +auto PythonClassTexture::GetTexture(bool doraise) const -> Texture* { + Texture* texture = texture_->get(); + if (!texture && doraise) { + throw Exception("Invalid Texture.", PyExcType::kNotFound); + } + return texture; +} + +auto PythonClassTexture::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + if (!s_create_empty_) { + throw Exception( + "Can't instantiate Textures directly; use ba.gettexture() to get " + "them."); + } + self->texture_ = new Object::Ref(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassTexture::Delete(Object::Ref* ref) { + assert(InGameThread()); + + // If we're the py-object for a texture, kill our reference to it. + // (FIXME - we should pass the old py obj pointer in here to + // make sure that we were their python obj as a sanity test) + if (ref->exists()) { + (*ref)->ClearPyObject(); + } + delete ref; +} + +void PythonClassTexture::tp_dealloc(PythonClassTexture* self) { + BA_PYTHON_TRY; + // These have to be deleted in the game thread - send the ptr along if need + // be; otherwise do it immediately. + if (!InGameThread()) { + Object::Ref* t = self->texture_; + g_game->PushCall([t] { Delete(t); }); + } else { + Delete(self->texture_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +bool PythonClassTexture::s_create_empty_ = false; +PyTypeObject PythonClassTexture::type_obj; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_texture.h b/src/ballistica/python/class/python_class_texture.h new file mode 100644 index 00000000..e0cb92c8 --- /dev/null +++ b/src/ballistica/python/class/python_class_texture.h @@ -0,0 +1,34 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_TEXTURE_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_TEXTURE_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassTexture : public PythonClass { + public: + static auto type_name() -> const char* { return "Texture"; } + static auto tp_repr(PythonClassTexture* self) -> PyObject*; + static void SetupType(PyTypeObject* obj); + static PyTypeObject type_obj; + static auto Create(Texture* texture) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + auto GetTexture(bool doraise = true) const -> Texture*; + + private: + static bool s_create_empty_; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassTexture* self); + static void Delete(Object::Ref* ref); + Object::Ref* texture_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_TEXTURE_H_ diff --git a/src/ballistica/python/class/python_class_timer.cc b/src/ballistica/python/class/python_class_timer.cc new file mode 100644 index 00000000..5dc2b7ce --- /dev/null +++ b/src/ballistica/python/class/python_class_timer.cc @@ -0,0 +1,195 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_timer.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/python/python_context_call_runnable.h" + +namespace ballistica { + +void PythonClassTimer::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Timer"; + obj->tp_basicsize = sizeof(PythonClassTimer); + obj->tp_doc = + "Timer(time: float, call: Callable[[], Any], repeat: bool = False,\n" + " timetype: ba.TimeType = TimeType.SIM,\n" + " timeformat: ba.TimeFormat = TimeFormat.SECONDS,\n" + " suppress_format_warning: bool = False)\n" + "\n" + "Timers are used to run code at later points in time.\n" + "\n" + "Category: General Utility Classes\n" + "\n" + "This class encapsulates a timer in the current ba.Context.\n" + "The underlying timer will be destroyed when either this object is\n" + "no longer referenced or when its Context (Activity, etc.) dies. If you\n" + "do not want to worry about keeping a reference to your timer around,\n" + "you should use the ba.timer() function instead.\n" + "\n" + "time: length of time (in seconds by default) that the timer will wait\n" + "before firing. Note that the actual delay experienced may vary\n " + "depending on the timetype. (see below)\n" + "\n" + "call: A callable Python object. Note that the timer will retain a\n" + "strong reference to the callable for as long as it exists, so you\n" + "may want to look into concepts such as ba.WeakCall if that is not\n" + "desired.\n" + "\n" + "repeat: if True, the timer will fire repeatedly, with each successive\n" + "firing having the same delay as the first.\n" + "\n" + "timetype can be either 'sim', 'base', or 'real'. It defaults to\n" + "'sim'. Types are explained below:\n" + "\n" + "'sim' time maps to local simulation time in ba.Activity or ba.Session\n" + "Contexts. This means that it may progress slower in slow-motion play\n" + "modes, stop when the game is paused, etc. This time type is not\n" + "available in UI contexts.\n" + "\n" + "'base' time is also linked to gameplay in ba.Activity or ba.Session\n" + "Contexts, but it progresses at a constant rate regardless of\n " + "slow-motion states or pausing. It can, however, slow down or stop\n" + "in certain cases such as network outages or game slowdowns due to\n" + "cpu load. Like 'sim' time, this is unavailable in UI contexts.\n" + "\n" + "'real' time always maps to actual clock time with a bit of filtering\n" + "added, regardless of Context. (the filtering prevents it from going\n" + "backwards or jumping forward by large amounts due to the app being\n" + "backgrounded, system time changing, etc.)\n" + "Real time timers are currently only available in the UI context.\n" + "\n" + "the 'timeformat' arg defaults to SECONDS but can also be MILLISECONDS\n" + "if you want to pass time as milliseconds.\n" + "\n" + "# Example: use a Timer object to print repeatedly for a few seconds:\n" + "def say_it():\n" + " ba.screenmessage('BADGER!')\n" + "def stop_saying_it():\n" + " self.t = None\n" + " ba.screenmessage('MUSHROOM MUSHROOM!')\n" + "# create our timer; it will run as long as we hold self.t\n" + "self.t = ba.Timer(0.3, say_it, repeat=True)\n" + "# now fire off a one-shot timer to kill it\n" + "ba.timer(3.89, stop_saying_it)"; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; +} + +auto PythonClassTimer::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + + self->context_ = new Context(); + + PyObject* length_obj{}; + int64_t length; + int repeat{}; + int suppress_format_warning{}; + PyObject* call_obj{}; + PyObject* time_type_obj{}; + PyObject* time_format_obj{}; + static const char* kwlist[] = {"time", "call", + "repeat", "timetype", + "timeformat", "suppress_format_warning", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "OO|pOOp", const_cast(kwlist), &length_obj, + &call_obj, &repeat, &time_type_obj, &time_format_obj, + &suppress_format_warning)) { + return nullptr; + } + + auto time_type = TimeType::kSim; + if (time_type_obj != nullptr) { + time_type = Python::GetPyEnum_TimeType(time_type_obj); + } + auto time_format = TimeFormat::kSeconds; + if (time_format_obj != nullptr) { + time_format = Python::GetPyEnum_TimeFormat(time_format_obj); + } + +#if BA_TEST_BUILD || BA_DEBUG_BUILD + if (!suppress_format_warning) { + g_python->TimeFormatCheck(time_format, length_obj); + } +#endif + + // We currently work with integer milliseconds internally. + if (time_format == TimeFormat::kSeconds) { + length = static_cast(Python::GetPyDouble(length_obj) * 1000.0); + } else if (time_format == TimeFormat::kMilliseconds) { + length = Python::GetPyInt64(length_obj); + } else { + throw Exception("Invalid timeformat: '" + + std::to_string(static_cast(time_format)) + + "'.", + PyExcType::kValue); + } + if (length < 0) { + throw Exception("Timer length < 0.", PyExcType::kValue); + } + + auto runnable(Object::New(call_obj)); + + self->time_type_ = time_type; + + // Now just make sure we've got a valid context-target and ask us to + // make us a timer. + if (!self->context_->target.exists()) { + throw Exception("Invalid current context.", PyExcType::kContext); + } + self->timer_id_ = self->context_->target->NewTimer( + self->time_type_, length, static_cast(repeat), runnable); + self->have_timer_ = true; + + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} +void PythonClassTimer::DoDelete(bool have_timer, TimeType time_type, + int timer_id, Context* context) { + assert(InGameThread()); + if (!context) { + return; + } + if (context->target.exists() && have_timer) { + context->target->DeleteTimer(time_type, timer_id); + } + delete context; +} + +void PythonClassTimer::tp_dealloc(PythonClassTimer* self) { + BA_PYTHON_TRY; + // These have to be deleted in the game thread. + if (!InGameThread()) { + auto a0 = self->have_timer_; + auto a1 = self->time_type_; + auto a2 = self->timer_id_; + auto a3 = self->context_; + g_game->PushCall( + [a0, a1, a2, a3] { PythonClassTimer::DoDelete(a0, a1, a2, a3); }); + } else { + DoDelete(self->have_timer_, self->time_type_, self->timer_id_, + self->context_); + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +PyTypeObject PythonClassTimer::type_obj; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_timer.h b/src/ballistica/python/class/python_class_timer.h new file mode 100644 index 00000000..7c04f93d --- /dev/null +++ b/src/ballistica/python/class/python_class_timer.h @@ -0,0 +1,35 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_TIMER_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_TIMER_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/python/class/python_class.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +class PythonClassTimer : public PythonClass { + public: + static auto type_name() -> const char* { return "Timer"; } + static void SetupType(PyTypeObject* obj); + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + + private: + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassTimer* self); + static void DoDelete(bool have_timer, TimeType time_type, int timer_id, + Context* context); + TimeType time_type_; + int timer_id_; + Context* context_; + bool have_timer_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_TIMER_H_ diff --git a/src/ballistica/python/class/python_class_vec3.cc b/src/ballistica/python/class/python_class_vec3.cc new file mode 100644 index 00000000..1f396f5d --- /dev/null +++ b/src/ballistica/python/class/python_class_vec3.cc @@ -0,0 +1,350 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_vec3.h" + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/python/python.h" + +// FIXME: +// We currently call abc.Sequence.register(_ba.Vec3) which registers us as +// a Sequence type (so that isinstance(ba.Vec3(), abc.Sequence) == True). +// However the abc module lists a few things as part of the Sequence interface +// that we don't currently provide: index() and count() +namespace ballistica { + +// Ignore a few things that python macros do. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "RedundantCast" + +static const int kMemberCount = 3; + +PyTypeObject PythonClassVec3::type_obj; +PySequenceMethods PythonClassVec3::as_sequence_; +PyNumberMethods PythonClassVec3::as_number_; + +void PythonClassVec3::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Vec3"; + obj->tp_basicsize = sizeof(PythonClassVec3); + obj->tp_doc = + "A vector of 3 floats.\n" + "\n" + "Category: General Utility Classes\n" + "\n" + "These can be created the following ways (checked in this order):\n" + "- with no args, all values are set to 0\n" + "- with a single numeric arg, all values are set to that value\n" + "- with a single three-member sequence arg, sequence values are copied\n" + "- otherwise assumes individual x/y/z args (positional or keywords)" + "\n" + "Attributes:\n" + "\n" + " x: float\n" + " The vector's X component.\n" + "\n" + " y: float\n" + " The vector's Y component.\n" + "\n" + " z: float\n" + " The vector's Z component.\n"; + + obj->tp_new = tp_new; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + obj->tp_getattro = (getattrofunc)tp_getattro; + obj->tp_setattro = (setattrofunc)tp_setattro; + obj->tp_richcompare = (richcmpfunc)tp_richcompare; + + // Sequence functionality. + memset(&as_sequence_, 0, sizeof(as_sequence_)); + as_sequence_.sq_length = (lenfunc)sq_length; + as_sequence_.sq_item = (ssizeargfunc)sq_item; + as_sequence_.sq_ass_item = (ssizeobjargproc)sq_ass_item; + obj->tp_as_sequence = &as_sequence_; + + // Number functionality. + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_add = (binaryfunc)nb_add; + as_number_.nb_subtract = (binaryfunc)nb_subtract; + as_number_.nb_multiply = (binaryfunc)nb_multiply; + as_number_.nb_negative = (unaryfunc)nb_negative; + obj->tp_as_number = &as_number_; + + // Note: we could fill out the in-place versions of these + // if we're not going for immutability.. +} + +auto PythonClassVec3::Create(const Vector3f& val) -> PyObject* { + auto obj = + reinterpret_cast(type_obj.tp_alloc(&type_obj, 0)); + if (obj) { + obj->value = val; + } + return reinterpret_cast(obj); +} + +auto PythonClassVec3::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + + // Accept a numeric sequence of length 3. + assert(args != nullptr); + assert(PyTuple_Check(args)); + Py_ssize_t numargs = PyTuple_GET_SIZE(args); + if (numargs == 1 && PySequence_Check(PyTuple_GET_ITEM(args, 0))) { + auto vals = Python::GetPyFloats(PyTuple_GET_ITEM(args, 0)); + if (vals.size() != 3) { + throw Exception("Expected a 3 member numeric sequence.", + PyExcType::kValue); + } + self->value.x = vals[0]; + self->value.y = vals[1]; + self->value.z = vals[2]; + } else if (numargs == 1 + && Python::CanGetPyDouble(PyTuple_GET_ITEM(args, 0))) { + float val = Python::GetPyFloat(PyTuple_GET_ITEM(args, 0)); + self->value.x = self->value.y = self->value.z = val; + } else { + // Otherwise interpret as individual x, y, z float vals defaulting to 0. + static const char* kwlist[] = {"x", "y", "z", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|fff", const_cast(kwlist), &self->value.x, + &self->value.y, &self->value.z)) { + Py_TYPE(self)->tp_free(reinterpret_cast(self)); + return nullptr; + } + } + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +auto PythonClassVec3::tp_repr(PythonClassVec3* self) -> PyObject* { + BA_PYTHON_TRY; + char buffer[128]; + snprintf(buffer, sizeof(buffer), "ba.Vec3(%f, %f, %f)", self->value.x, + self->value.y, self->value.z); + return Py_BuildValue("s", buffer); + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::sq_length(PythonClassVec3* self) -> Py_ssize_t { + return kMemberCount; +} + +auto PythonClassVec3::sq_item(PythonClassVec3* self, Py_ssize_t i) + -> PyObject* { + if (i < 0 || i >= kMemberCount) { + PyErr_SetString(PyExc_IndexError, "Vec3 index out of range"); + return nullptr; + } + return PyFloat_FromDouble(self->value.v[i]); +} + +auto PythonClassVec3::sq_ass_item(PythonClassVec3* self, Py_ssize_t i, + PyObject* valobj) -> int { + BA_PYTHON_TRY; + if (i < 0 || i >= kMemberCount) { + throw Exception("Vec3 index out of range.", PyExcType::kValue); + } + float val = Python::GetPyFloat(valobj); + self->value.v[i] = val; + return 0; + BA_PYTHON_INT_CATCH; +} + +auto PythonClassVec3::nb_add(PythonClassVec3* l, PythonClassVec3* r) + -> PyObject* { + BA_PYTHON_TRY; + + // We can add if both sides are Vec3. + if (Check(reinterpret_cast(l)) + && Check(reinterpret_cast(r))) { + return Create(l->value + r->value); + } + + // Otherwise we got nothin'. + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::nb_subtract(PythonClassVec3* l, PythonClassVec3* r) + -> PyObject* { + BA_PYTHON_TRY; + + // We can subtract if both sides are Vec3. + if (Check(reinterpret_cast(l)) + && Check(reinterpret_cast(r))) { + return Create(l->value - r->value); + } + + // Otherwise we got nothin'. + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::nb_negative(PythonClassVec3* self) -> PyObject* { + return Create(-self->value); +} + +auto PythonClassVec3::nb_multiply(PyObject* l, PyObject* r) -> PyObject* { + BA_PYTHON_TRY; + + // If left side is vec3. + if (Check(l)) { + // Try right as single number. + if (Python::CanGetPyDouble(r)) { + assert(Check(l)); + return Create(reinterpret_cast(l)->value + * Python::GetPyFloat(r)); + } + + // Try right as a vec3-able value. + if (Python::CanGetPyVector3f(r)) { + Vector3f& lvec(reinterpret_cast(l)->value); + Vector3f rvec(Python::GetPyVector3f(r)); + return Create( + Vector3f(lvec.x * rvec.x, lvec.y * rvec.y, lvec.z * rvec.z)); + } + } else { + // Ok, right must be vec3 (by definition). + assert(Check(r)); + + // Try left as single value. + if (Python::CanGetPyDouble(l)) { + assert(Check(r)); + return Create(Python::GetPyFloat(l) + * reinterpret_cast(r)->value); + } + + // Try left as a vec3-able value. + if (Python::CanGetPyVector3f(l)) { + Vector3f lvec(Python::GetPyVector3f(l)); + Vector3f& rvec(reinterpret_cast(r)->value); + return Create( + Vector3f(lvec.x * rvec.x, lvec.y * rvec.y, lvec.z * rvec.z)); + } + } + + // Ok we got nothin'. + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::tp_richcompare(PythonClassVec3* c1, PyObject* c2, int op) + -> PyObject* { + // Always return false against other types. + if (!Check(c2)) { + Py_RETURN_FALSE; + } + bool eq = (c1->value == (reinterpret_cast(c2))->value); + if (op == Py_EQ) { + if (eq) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else if (op == Py_NE) { + if (!eq) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + } else { + // Don't support other ops. + Py_RETURN_NOTIMPLEMENTED; + } +} + +auto PythonClassVec3::Length(PythonClassVec3* self) -> PyObject* { + BA_PYTHON_TRY; + return PyFloat_FromDouble(self->value.Length()); + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::Normalized(PythonClassVec3* self) -> PyObject* { + BA_PYTHON_TRY; + return Create(self->value.Normalized()); + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::Dot(PythonClassVec3* self, PyObject* other) -> PyObject* { + BA_PYTHON_TRY; + return PyFloat_FromDouble(self->value.Dot(Python::GetPyVector3f(other))); + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::Cross(PythonClassVec3* self, PyObject* other) + -> PyObject* { + BA_PYTHON_TRY; + return Create(Vector3f::Cross(self->value, Python::GetPyVector3f(other))); + BA_PYTHON_CATCH; +} + +PyMethodDef PythonClassVec3::tp_methods[] = { + {"length", (PyCFunction)Length, METH_NOARGS, + "length() -> float\n" + "\n" + "Returns the length of the vector."}, + {"normalized", (PyCFunction)Normalized, METH_NOARGS, + "normalized() -> Vec3\n" + "\n" + "Returns a normalized version of the vector."}, + {"dot", (PyCFunction)Dot, METH_O, + "dot(other: Vec3) -> float\n" + "\n" + "Returns the dot product of this vector and another."}, + {"cross", (PyCFunction)Cross, METH_O, + "cross(other: Vec3) -> Vec3\n" + "\n" + "Returns the cross product of this vector and another."}, + {nullptr}}; + +auto PythonClassVec3::tp_getattro(PythonClassVec3* self, PyObject* attr) + -> PyObject* { + BA_PYTHON_TRY; + assert(PyUnicode_Check(attr)); + + const char* s = PyUnicode_AsUTF8(attr); + if (!strcmp(s, "x")) { + return PyFloat_FromDouble(self->value.x); + } else if (!strcmp(s, "y")) { + return PyFloat_FromDouble(self->value.y); + } else if (!strcmp(s, "z")) { + return PyFloat_FromDouble(self->value.z); + } + return PyObject_GenericGetAttr(reinterpret_cast(self), attr); + BA_PYTHON_CATCH; +} + +auto PythonClassVec3::tp_setattro(PythonClassVec3* self, PyObject* attrobj, + PyObject* valobj) -> int { + BA_PYTHON_TRY; + assert(PyUnicode_Check(attrobj)); + const char* attr = PyUnicode_AsUTF8(attrobj); + float val = Python::GetPyFloat(valobj); + if (!strcmp(attr, "x")) { + self->value.x = val; + } else if (!strcmp(attr, "y")) { + self->value.y = val; + } else if (!strcmp(attr, "z")) { + self->value.z = val; + } else { + throw Exception("Attr '" + std::string(attr) + "' is not settable.", + PyExcType::kAttribute); + } + return 0; + BA_PYTHON_INT_CATCH; +} + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_vec3.h b/src/ballistica/python/class/python_class_vec3.h new file mode 100644 index 00000000..7cbb02c5 --- /dev/null +++ b/src/ballistica/python/class/python_class_vec3.h @@ -0,0 +1,49 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_VEC3_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_VEC3_H_ + +#include "ballistica/math/vector3f.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassVec3 : public PythonClass { + public: + static auto type_name() -> const char* { return "Vec3"; } + static void SetupType(PyTypeObject* obj); + static auto Create(const Vector3f& val) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static auto Length(PythonClassVec3* self) -> PyObject*; + static auto Normalized(PythonClassVec3* self) -> PyObject*; + static auto Dot(PythonClassVec3* self, PyObject* other) -> PyObject*; + static auto Cross(PythonClassVec3* self, PyObject* other) -> PyObject*; + static PyTypeObject type_obj; + Vector3f value; + + private: + static PyMethodDef tp_methods[]; + static PySequenceMethods as_sequence_; + static PyNumberMethods as_number_; + static auto tp_repr(PythonClassVec3* self) -> PyObject*; + static auto sq_length(PythonClassVec3* self) -> Py_ssize_t; + static auto sq_item(PythonClassVec3* self, Py_ssize_t i) -> PyObject*; + static auto sq_ass_item(PythonClassVec3* self, Py_ssize_t i, PyObject* val) + -> int; + static auto nb_add(PythonClassVec3* l, PythonClassVec3* r) -> PyObject*; + static auto nb_subtract(PythonClassVec3* l, PythonClassVec3* r) -> PyObject*; + static auto nb_multiply(PyObject* l, PyObject* r) -> PyObject*; + static auto nb_negative(PythonClassVec3* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static auto tp_getattro(PythonClassVec3* self, PyObject* attr) -> PyObject*; + static auto tp_richcompare(PythonClassVec3* c1, PyObject* c2, int op) + -> PyObject*; + static auto tp_setattro(PythonClassVec3* self, PyObject* attr, PyObject* val) + -> int; +}; + +} // namespace ballistica +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_VEC3_H_ diff --git a/src/ballistica/python/class/python_class_widget.cc b/src/ballistica/python/class/python_class_widget.cc new file mode 100644 index 00000000..dde68f46 --- /dev/null +++ b/src/ballistica/python/class/python_class_widget.cc @@ -0,0 +1,288 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/class/python_class_widget.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/ui/widget/container_widget.h" +#include "ballistica/ui/widget/widget.h" + +namespace ballistica { + +auto PythonClassWidget::nb_bool(PythonClassWidget* self) -> int { + return self->widget_->exists(); +} + +PyNumberMethods PythonClassWidget::as_number_; + +void PythonClassWidget::SetupType(PyTypeObject* obj) { + PythonClass::SetupType(obj); + obj->tp_name = "ba.Widget"; + obj->tp_basicsize = sizeof(PythonClassWidget); + obj->tp_doc = + "Internal type for low level UI elements; buttons, windows, etc.\n" + "\n" + "Category: User Interface Classes\n" + "\n" + "This class represents a weak reference to a widget object\n" + "in the internal c++ layer. Currently, functions such as\n" + "ba.buttonwidget() must be used to instantiate or edit these."; + obj->tp_new = tp_new; + obj->tp_dealloc = (destructor)tp_dealloc; + obj->tp_repr = (reprfunc)tp_repr; + obj->tp_methods = tp_methods; + + // we provide number methods only for bool functionality + memset(&as_number_, 0, sizeof(as_number_)); + as_number_.nb_bool = (inquiry)nb_bool; + obj->tp_as_number = &as_number_; +} + +auto PythonClassWidget::Create(Widget* widget) -> PyObject* { + // Make sure we only have one python ref per widget. + if (widget) { + assert(!widget->has_py_ref()); + } + + auto* py_widget = reinterpret_cast( + PyObject_CallObject(reinterpret_cast(&type_obj), nullptr)); + if (!py_widget) throw Exception("ba.Widget creation failed"); + + *(py_widget->widget_) = widget; + return reinterpret_cast(py_widget); +} + +auto PythonClassWidget::GetWidget() const -> Widget* { + Widget* w = widget_->get(); + if (!w) throw Exception("Invalid widget"); + return w; +} + +auto PythonClassWidget::tp_repr(PythonClassWidget* self) -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + return Py_BuildValue("s", (std::string("GetWidgetTypeName() : "") + + "' widget " + Utils::PtrToString(w) + ">") + .c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::tp_new(PyTypeObject* type, PyObject* args, + PyObject* keywds) -> PyObject* { + auto* self = reinterpret_cast(type->tp_alloc(type, 0)); + if (self) { + BA_PYTHON_TRY; + if (!InGameThread()) { + throw Exception( + "ERROR: " + std::string(type_obj.tp_name) + + " objects must only be created in the game thread (current is (" + + GetCurrentThreadName() + ")."); + } + self->widget_ = new Object::WeakRef(); + BA_PYTHON_NEW_CATCH; + } + return reinterpret_cast(self); +} + +void PythonClassWidget::tp_dealloc(PythonClassWidget* self) { + BA_PYTHON_TRY; + // these have to be destructed in the game thread - send them along to it if + // need be + if (!InGameThread()) { + Object::WeakRef* w = self->widget_; + g_game->PushCall([w] { delete w; }); + } else { + delete self->widget_; + } + BA_PYTHON_DEALLOC_CATCH; + Py_TYPE(self)->tp_free(reinterpret_cast(self)); +} + +auto PythonClassWidget::Exists(PythonClassWidget* self) -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + if (w) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::GetWidgetType(PythonClassWidget* self) -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + if (!w) { + throw Exception(PyExcType::kWidgetNotFound); + } + return PyUnicode_FromString(w->GetWidgetTypeName().c_str()); + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::Activate(PythonClassWidget* self) -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + if (!w) { + throw Exception(PyExcType::kWidgetNotFound); + } + w->Activate(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::GetChildren(PythonClassWidget* self) -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + if (!w) { + throw Exception(PyExcType::kWidgetNotFound); + } + PyObject* py_list = PyList_New(0); + auto* cw = dynamic_cast(w); + if (cw) { + for (auto&& i : cw->widgets()) { + assert(i.exists()); + PyList_Append(py_list, i->BorrowPyRef()); + } + } + return py_list; + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::GetSelectedChild(PythonClassWidget* self) -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + if (!w) { + throw Exception(PyExcType::kWidgetNotFound); + } + auto* cw = dynamic_cast(w); + if (cw) { + Widget* selected_widget = cw->selected_widget(); + if (selected_widget) return selected_widget->NewPyRef(); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::GetScreenSpaceCenter(PythonClassWidget* self) + -> PyObject* { + BA_PYTHON_TRY; + Widget* w = self->widget_->get(); + if (!w) { + throw Exception(PyExcType::kWidgetNotFound); + } + float x, y; + w->GetCenter(&x, &y); + + // this gives us coords in the widget's parent's space; translate from that + // to screen space + if (ContainerWidget* parent = w->parent_widget()) { + parent->WidgetPointToScreen(&x, &y); + } + // ..but we actually want to return points relative to the center of the + // screen (so they're useful as stack-offset values) + float screen_width = g_graphics->screen_virtual_width(); + float screen_height = g_graphics->screen_virtual_height(); + x -= screen_width * 0.5f; + y -= screen_height * 0.5f; + return Py_BuildValue("(ff)", x, y); + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::Delete(PythonClassWidget* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + int ignore_missing = true; + static const char* kwlist[] = {"ignore_missing", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|i", const_cast(kwlist), &ignore_missing)) { + return nullptr; + } + Widget* w = self->widget_->get(); + if (!w) { + if (!ignore_missing) { + throw Exception(PyExcType::kWidgetNotFound); + } + } else { + ContainerWidget* p = w->parent_widget(); + if (p) { + p->DeleteWidget(w); + } else { + Log("Error: Can't delete widget: no parent."); + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PythonClassWidget::AddDeleteCallback(PythonClassWidget* self, + PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + PyObject* call_obj; + static const char* kwlist[] = {"call", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &call_obj)) { + return nullptr; + } + Widget* w = self->widget_->get(); + if (!w) { + throw Exception(PyExcType::kWidgetNotFound); + } + w->AddOnDeleteCall(call_obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyTypeObject PythonClassWidget::type_obj; +PyMethodDef PythonClassWidget::tp_methods[] = { + {"exists", (PyCFunction)Exists, METH_NOARGS, + "exists() -> bool\n" + "\n" + "Returns whether the Widget still exists.\n" + "Most functionality will fail on a nonexistent widget.\n" + "\n" + "Note that you can also use the boolean operator for this same\n" + "functionality, so a statement such as \"if mywidget\" will do\n" + "the right thing both for Widget objects and values of None."}, + {"get_widget_type", (PyCFunction)GetWidgetType, METH_NOARGS, + "get_widget_type() -> str\n" + "\n" + "Return the internal type of the Widget as a string. Note that this is\n" + "different from the Python ba.Widget type, which is the same for all\n" + "widgets."}, + {"activate", (PyCFunction)Activate, METH_NOARGS, + "activate() -> None\n" + "\n" + "Activates a widget; the same as if it had been clicked."}, + {"get_children", (PyCFunction)GetChildren, METH_NOARGS, + "get_children() -> List[ba.Widget]\n" + "\n" + "Returns any child Widgets of this Widget."}, + {"get_screen_space_center", (PyCFunction)GetScreenSpaceCenter, METH_NOARGS, + "get_screen_space_center() -> Tuple[float, float]\n" + "\n" + "Returns the coords of the Widget center relative to the center of the\n" + "screen. This can be useful for placing pop-up windows and other special\n" + "cases."}, + {"get_selected_child", (PyCFunction)GetSelectedChild, METH_NOARGS, + "get_selected_child() -> Optional[ba.Widget]\n" + "\n" + "Returns the selected child Widget or None if nothing is selected."}, + // NOLINTNEXTLINE (signed bitwise stuff) + {"delete", (PyCFunction)Delete, METH_VARARGS | METH_KEYWORDS, + "delete(ignore_missing: bool = True) -> None\n" + "\n" + "Delete the Widget. Ignores already-deleted Widgets if ignore_missing\n" + " is True; otherwise an Exception is thrown."}, + {"add_delete_callback", (PyCFunction)AddDeleteCallback, + METH_VARARGS | METH_KEYWORDS, // NOLINT (signed bitwise stuff) + "add_delete_callback(call: Callable) -> None\n" + "\n" + "Add a call to be run immediately after this widget is destroyed."}, + {nullptr}}; + +} // namespace ballistica diff --git a/src/ballistica/python/class/python_class_widget.h b/src/ballistica/python/class/python_class_widget.h new file mode 100644 index 00000000..5b74f127 --- /dev/null +++ b/src/ballistica/python/class/python_class_widget.h @@ -0,0 +1,45 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_WIDGET_H_ +#define BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_WIDGET_H_ + +#include "ballistica/core/object.h" +#include "ballistica/python/class/python_class.h" + +namespace ballistica { + +class PythonClassWidget : public PythonClass { + public: + static void SetupType(PyTypeObject* obj); + static auto type_name() -> const char* { return "Widget"; } + static auto Create(Widget* widget) -> PyObject*; + static auto Check(PyObject* o) -> bool { + return PyObject_TypeCheck(o, &type_obj); + } + static PyTypeObject type_obj; + auto GetWidget() const -> Widget*; + + private: + static PyMethodDef tp_methods[]; + static auto tp_repr(PythonClassWidget* self) -> PyObject*; + static auto tp_new(PyTypeObject* type, PyObject* args, PyObject* keywds) + -> PyObject*; + static void tp_dealloc(PythonClassWidget* self); + static auto Exists(PythonClassWidget* self) -> PyObject*; + static auto GetWidgetType(PythonClassWidget* self) -> PyObject*; + static auto Activate(PythonClassWidget* self) -> PyObject*; + static auto GetChildren(PythonClassWidget* self) -> PyObject*; + static auto GetSelectedChild(PythonClassWidget* self) -> PyObject*; + static auto GetScreenSpaceCenter(PythonClassWidget* self) -> PyObject*; + static auto Delete(PythonClassWidget* self, PyObject* args, PyObject* keywds) + -> PyObject*; + static auto AddDeleteCallback(PythonClassWidget* self, PyObject* args, + PyObject* keywds) -> PyObject*; + Object::WeakRef* widget_; + static auto nb_bool(PythonClassWidget* self) -> int; + static PyNumberMethods as_number_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_CLASS_PYTHON_CLASS_WIDGET_H_ diff --git a/src/ballistica/python/methods/python_methods_app.cc b/src/ballistica/python/methods/python_methods_app.cc new file mode 100644 index 00000000..c5d8c3af --- /dev/null +++ b/src/ballistica/python/methods/python_methods_app.cc @@ -0,0 +1,1196 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_app.h" + +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/core/logging.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/game/session/replay_client_session.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/python/class/python_class_activity_data.h" +#include "ballistica/python/class/python_class_session_data.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call_runnable.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +// Python does lots of signed bitwise stuff; turn off those warnings here. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "RedundantCast" + +auto PyAppName(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("app_name"); + + // This will get subbed out by standard filtering. + return PyUnicode_FromString("ballisticacore"); + BA_PYTHON_CATCH; +} + +auto PyAppNameUpper(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("app_name_upper"); + + // This will get subbed out by standard filtering. + return PyUnicode_FromString("BallisticaCore"); + BA_PYTHON_CATCH; +} + +auto PyIsXCodeBuild(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("is_xcode_build"); + if (g_buildconfig.xcode_build()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyCanDisplayFullUnicode(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("can_display_full_unicode"); + if (g_buildconfig.enable_os_font_rendering()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyGetSession(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_session"); + int raise = true; + static const char* kwlist[] = {"doraise", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|i", + const_cast(kwlist), &raise)) { + return nullptr; + } + if (HostSession* hs = Context::current().GetHostSession()) { + PyObject* obj = hs->GetSessionPyObj(); + if (obj) { + Py_INCREF(obj); + return obj; + } + } else { + if (raise) { + throw Exception(PyExcType::kSessionNotFound); + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyNewHostSession(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("new_host_session"); + const char* benchmark_type_str = nullptr; + static const char* kwlist[] = {"sessiontype", "benchmark_type", nullptr}; + PyObject* sessiontype_obj; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|s", + const_cast(kwlist), &sessiontype_obj, + &benchmark_type_str)) { + return nullptr; + } + BenchmarkType benchmark_type = BenchmarkType::kNone; + if (benchmark_type_str != nullptr) { + if (!strcmp(benchmark_type_str, "cpu")) { + benchmark_type = BenchmarkType::kCPU; + } else if (!strcmp(benchmark_type_str, "gpu")) { + benchmark_type = BenchmarkType::kGPU; + } else { + throw Exception( + "Invalid benchmark type: '" + std::string(benchmark_type_str) + "'", + PyExcType::kValue); + } + } + g_game->LaunchHostSession(sessiontype_obj, benchmark_type); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyNewReplaySession(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("new_replay_session"); + std::string file_name; + PyObject* file_name_obj; + static const char* kwlist[] = {"file_name", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O", const_cast(kwlist), &file_name_obj)) { + return nullptr; + } + file_name = Python::GetPyString(file_name_obj); + g_game->LaunchReplaySession(file_name); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIsInReplay(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("is_in_replay"); + BA_PRECONDITION(InGameThread()); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + if (dynamic_cast(g_game->GetForegroundSession())) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyRegisterSession(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("register_session"); + assert(InGameThread()); + PyObject* session_obj; + static const char* kwlist[] = {"session", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &session_obj)) { + return nullptr; + } + HostSession* hsc = Context::current().GetHostSession(); + if (!hsc) { + throw Exception("No HostSession found."); + } + + // Store our py obj with our HostSession and return + // the HostSession to be stored with our py obj. + hsc->RegisterPySession(session_obj); + return PythonClassSessionData::Create(hsc); + BA_PYTHON_CATCH; +} + +auto PyRegisterActivity(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("register_activity"); + assert(InGameThread()); + PyObject* activity_obj; + static const char* kwlist[] = {"activity", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &activity_obj)) { + return nullptr; + } + HostSession* hs = Context::current().GetHostSession(); + if (!hs) { + throw Exception("No HostSession found"); + } + + // Generate and return an ActivityData for this guy.. + // (basically just a link to its C++ equivalent). + return PythonClassActivityData::Create(hs->RegisterPyActivity(activity_obj)); + BA_PYTHON_CATCH; +} + +auto PyGetForegroundHostSession(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_foreground_host_session"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + + // Note: we return None if not in the game thread. + HostSession* s = InGameThread() + ? g_game->GetForegroundContext().GetHostSession() + : nullptr; + if (s != nullptr) { + PyObject* obj = s->GetSessionPyObj(); + Py_INCREF(obj); + return obj; + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyNewActivity(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("new_activity"); + + static const char* kwlist[] = {"activity_type", "settings", nullptr}; + PyObject* activity_type_obj; + PyObject* settings_obj = Py_None; + PythonRef settings; + + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|O", + const_cast(kwlist), + &activity_type_obj, &settings_obj)) { + return nullptr; + } + + // If they passed a settings dict, make a shallow copy of it (so we dont + // inadvertently mess up level lists or whatever the settings came from). + if (settings_obj != Py_None) { + if (!PyDict_Check(settings_obj)) { + throw Exception("Expected a dict for settings.", PyExcType::kType); + } + PythonRef args2(Py_BuildValue("(O)", settings_obj), PythonRef::kSteal); + settings = g_python->obj(Python::ObjID::kShallowCopyCall).Call(args2); + if (!settings.exists()) { + throw Exception("Unable to shallow-copy settings."); + } + } else { + settings.Acquire(settings_obj); + } + + HostSession* hs = Context::current().GetHostSession(); + if (!hs) { + throw Exception("No HostSession found.", PyExcType::kContext); + } + return hs->NewHostActivity(activity_type_obj, settings.get()); + + BA_PYTHON_CATCH; +} + +auto PyGetActivity(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_activity"); + int raise = true; + static const char* kwlist[] = {"doraise", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|i", + const_cast(kwlist), &raise)) { + return nullptr; + } + + // Fail gracefully if called from outside the game thread. + if (!InGameThread()) { + Py_RETURN_NONE; + } + + if (HostActivity* hostactivity = Context::current().GetHostActivity()) { + PyObject* obj = hostactivity->GetPyActivity(); + Py_INCREF(obj); + return obj; + } else { + if (raise) { + throw Exception(PyExcType::kActivityNotFound); + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyPushCall(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("push_call"); + PyObject* call_obj; + int from_other_thread{}; + int suppress_warning{}; + static const char* kwlist[] = {"call", "from_other_thread", + "suppress_other_thread_warning", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|ip", + const_cast(kwlist), &call_obj, + &from_other_thread, &suppress_warning)) { + return nullptr; + } + + // The from-other-thread case is basically a different call. + if (from_other_thread) { + // Warn the user not to use this from the game thread since it doesnt + // save/restore context. + if (!suppress_warning && InGameThread()) { + g_python->IssueCallInGameThreadWarning(call_obj); + } + + // This gets called from other python threads so we can't construct + // Objects and things here or we'll trip our thread-checks. Instead we + // just increment the python object's refcount and pass it along raw; + // the game thread decrements it on the other end. + Py_INCREF(call_obj); + g_game->PushPythonRawCallable(call_obj); + } else { + if (!InGameThread()) { + throw Exception("You must use from_other_thread mode."); + } + g_game->PushPythonCall(Object::New(call_obj)); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyTime(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("time"); + + PyObject* time_type_obj = nullptr; + PyObject* time_format_obj = nullptr; + static const char* kwlist[] = {"timetype", "timeformat", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|OO", + const_cast(kwlist), &time_type_obj, + &time_format_obj)) { + return nullptr; + } + + auto time_type = TimeType::kSim; + if (time_type_obj != nullptr) { + time_type = Python::GetPyEnum_TimeType(time_type_obj); + } + auto time_format = TimeFormat::kSeconds; + if (time_format_obj != nullptr) { + time_format = Python::GetPyEnum_TimeFormat(time_format_obj); + } + + millisecs_t timeval; + if (time_type == TimeType::kReal) { + // Special case; we don't require a context for 'real'. + timeval = GetRealTime(); + } else { + // Make sure we've got a valid context-target and ask it for + // this type of time. + if (!Context::current().target.exists()) { + throw Exception(PyExcType::kContext); + } + timeval = Context::current().target->GetTime(time_type); + } + + if (time_format == TimeFormat::kSeconds) { + return PyFloat_FromDouble(0.001 * timeval); + } else if (time_format == TimeFormat::kMilliseconds) { + return PyLong_FromLong(static_cast_check_fit(timeval)); // NOLINT + } else { + throw Exception( + "Invalid timeformat: " + std::to_string(static_cast(time_format)), + PyExcType::kValue); + } + BA_PYTHON_CATCH; +} + +auto PyTimer(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + assert(InGameThread()); + Platform::SetLastPyCall("timer"); + + PyObject* length_obj; + int64_t length; + int repeat = 0; + int suppress_format_warning = 0; + PyObject* call_obj; + PyObject* time_type_obj = nullptr; + PyObject* time_format_obj = nullptr; + static const char* kwlist[] = {"time", "call", + "repeat", "timetype", + "timeformat", "suppress_format_warning", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "OO|pOOp", const_cast(kwlist), &length_obj, + &call_obj, &repeat, &time_type_obj, &time_format_obj, + &suppress_format_warning)) { + return nullptr; + } + + auto time_type = TimeType::kSim; + if (time_type_obj != nullptr) { + time_type = Python::GetPyEnum_TimeType(time_type_obj); + } + auto time_format = TimeFormat::kSeconds; + if (time_format_obj != nullptr) { + time_format = Python::GetPyEnum_TimeFormat(time_format_obj); + } + +#if BA_TEST_BUILD || BA_DEBUG_BUILD + if (!suppress_format_warning) { + g_python->TimeFormatCheck(time_format, length_obj); + } +#endif + + // We currently work with integer milliseconds internally. + if (time_format == TimeFormat::kSeconds) { + length = static_cast(Python::GetPyDouble(length_obj) * 1000.0); + } else if (time_format == TimeFormat::kMilliseconds) { + length = Python::GetPyInt64(length_obj); + } else { + throw Exception("invalid timeformat: '" + + std::to_string(static_cast(time_format)) + "'", + PyExcType::kValue); + } + if (length < 0) { + throw Exception("Timer length < 0", PyExcType::kValue); + } + + // Grab a ref to this here so it doesn't leak on exceptions. + auto runnable(Object::New(call_obj)); + + // Special case; we disallow repeating real timers currently. + if (time_type == TimeType::kReal && repeat) { + throw Exception("Repeating real timers not allowed here; use ba.Timer().", + PyExcType::kValue); + } + + // Now just make sure we've got a valid context-target and ask us to + // make us a timer. + if (!Context::current().target.exists()) { + throw Exception(PyExcType::kContext); + } + Context::current().target->NewTimer(time_type, length, + static_cast(repeat), runnable); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyScreenMessage(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("screen_message"); + const char* message = nullptr; + PyObject* color_obj = Py_None; + int top = 0; + int transient = 0; + PyObject* image_obj = Py_None; + PyObject* message_obj; + PyObject* clients_obj = Py_None; + int log = 0; + static const char* kwlist[] = {"message", "color", "top", "image", + "log", "clients", "transient", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O|OpOiOi", const_cast(kwlist), &message_obj, + &color_obj, &top, &image_obj, &log, &clients_obj, &transient)) { + return nullptr; + } + std::string message_str = Python::GetPyString(message_obj); + message = message_str.c_str(); + Vector3f color{1, 1, 1}; + if (color_obj != Py_None) { + color = Python::GetPyVector3f(color_obj); + } + if (message == nullptr) { + PyErr_SetString(PyExc_AttributeError, "No message provided"); + return nullptr; + } + if (log) { + Log(message); + } + + // Transient messages get sent to clients as high-level messages instead of + // being embedded into the game-stream. + if (transient) { + // This option doesn't support top or icons currently. + if (image_obj != Py_None) { + throw Exception( + "The 'image' option is not currently supported for transient mode " + "messages.", + PyExcType::kValue); + } + if (top) { + throw Exception( + "The 'top' option is not currently supported for transient mode " + "messages.", + PyExcType::kValue); + } + std::vector client_ids; + if (clients_obj != Py_None) { + std::vector client_ids2 = Python::GetPyInts(clients_obj); + g_game->SendScreenMessageToSpecificClients(message, color.x, color.y, + color.z, client_ids2); + } else { + g_game->SendScreenMessageToAll(message, color.x, color.y, color.z); + } + } else { + // Currently specifying client_ids only works for transient messages; we'd + // need a protocol change to support that in game output streams. + // (or maintaining separate streams per client; yuck) + if (clients_obj != Py_None) { + throw Exception( + "Specifying clients only works when using the 'transient' option", + PyExcType::kValue); + } + Scene* context_scene = Context::current().GetMutableScene(); + GameStream* output_stream = + context_scene ? context_scene->GetGameStream() : nullptr; + + Texture* texture = nullptr; + Texture* tint_texture = nullptr; + Vector3f tint_color{1.0f, 1.0f, 1.0f}; + Vector3f tint2_color{1.0f, 1.0f, 1.0f}; + if (image_obj != Py_None) { + if (PyDict_Check(image_obj)) { + PyObject* obj = PyDict_GetItemString(image_obj, "texture"); + if (!obj) + throw Exception("Provided image dict contains no 'texture' entry.", + PyExcType::kValue); + texture = Python::GetPyTexture(obj); + + obj = PyDict_GetItemString(image_obj, "tint_texture"); + if (!obj) + throw Exception( + "Provided image dict contains no 'tint_texture' entry.", + PyExcType::kValue); + tint_texture = Python::GetPyTexture(obj); + + obj = PyDict_GetItemString(image_obj, "tint_color"); + if (!obj) + throw Exception("Provided image dict contains no 'tint_color' entry", + PyExcType::kValue); + tint_color = Python::GetPyVector3f(obj); + obj = PyDict_GetItemString(image_obj, "tint2_color"); + if (!obj) + throw Exception("Provided image dict contains no 'tint2_color' entry", + PyExcType::kValue); + tint2_color = Python::GetPyVector3f(obj); + } else { + texture = Python::GetPyTexture(image_obj); + } + } + if (output_stream) { + // FIXME: for now we just do bottom messages. + if (texture == nullptr && !top) { + output_stream->ScreenMessageBottom(message, color.x, color.y, color.z); + } else if (top && texture != nullptr && tint_texture != nullptr) { + if (texture->scene() != context_scene) { + throw Exception("Texture is not from the current context.", + PyExcType::kContext); + } + if (tint_texture->scene() != context_scene) + throw Exception("Tint-texture is not from the current context.", + PyExcType::kContext); + output_stream->ScreenMessageTop( + message, color.x, color.y, color.z, texture, tint_texture, + tint_color.x, tint_color.y, tint_color.z, tint2_color.x, + tint2_color.y, tint2_color.z); + } else { + Log("Error: unhandled screenmessage output_stream case"); + } + } + + // Now display it locally. + g_graphics->AddScreenMessage(message, color, static_cast(top), + texture, tint_texture, tint_color, + tint2_color); + } + + Py_RETURN_NONE; + + BA_PYTHON_CATCH; +} + +auto PyQuit(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("quit"); + static const char* kwlist[] = {"soft", "back", nullptr}; + int soft = 0; + int back = 0; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|ii", + const_cast(kwlist), &soft, &back)) { + return nullptr; + } + + // FIXME this should all just go through platform + + if (g_buildconfig.ostype_ios_tvos()) { + // This should never be called on iOS + Log("Error: Quit called."); + } + + bool handled = false; + + // A few types get handled specially on android. + if (g_buildconfig.ostype_android()) { + if (!handled && back) { + // Back-quit simply synthesizes a back press. + // Note to self: I remember this behaved slightly differently than + // doing a soft quit but I should remind myself how... + g_platform->AndroidSynthesizeBackPress(); + handled = true; + } + if (!handled && soft) { + // Soft-quit just kills our activity but doesn't run app shutdown. + // Thus we'll be able to spin back up (reset to the main menu) + // if the user re-launches us. + g_platform->AndroidQuitActivity(); + handled = true; + } + } + if (!handled) { + g_game->PushShutdownCall(false); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +#if BA_DEBUG_BUILD +auto PyBless(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("bless"); + ScreenMessage("WOULD BLESS BUILD " + std::to_string(kAppBuildNumber)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} +#endif // BA_DEBUG_BUILD + +auto PyApplyConfig(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("apply_config"); + + // Hmm; python runs in the game thread; technically we could just run + // ApplyConfig() immediately (though pushing is probably safer). + g_game->PushApplyConfigCall(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyCommitConfig(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("commit_config"); + PyObject* config_obj; + static const char* kwlist[] = {"config", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &config_obj)) { + return nullptr; + } + if (config_obj == nullptr || !Python::IsPyString(config_obj)) { + throw Exception("ERROR ON JSON DUMP"); + } + std::string final_str = Python::GetPyString(config_obj); + std::string path = g_platform->GetConfigFilePath(); + std::string path_temp = path + ".tmp"; + std::string path_prev = path + ".prev"; + if (explicit_bool(true)) { + FILE* f_out = g_platform->FOpen(path_temp.c_str(), "wb"); + if (f_out == nullptr) { + throw Exception("Error opening config file for writing: '" + path_temp + + "': " + g_platform->GetErrnoString()); + } + + // Write to temp file. + size_t result = fwrite(&final_str[0], final_str.size(), 1, f_out); + if (result != 1) { + fclose(f_out); + throw Exception("Error writing config file to '" + path_temp + + "': " + g_platform->GetErrnoString()); + } + fclose(f_out); + + // Now backup any existing config to .prev. + if (g_platform->FilePathExists(path)) { + // On windows, rename doesn't overwrite existing files.. need to kill + // the old explicitly. + // (hmm; should we just do this everywhere for consistency?) + if (g_buildconfig.ostype_windows()) { + if (g_platform->FilePathExists(path_prev)) { + int result2 = g_platform->Remove(path_prev.c_str()); + if (result2 != 0) { + throw Exception("Error removing prev config file '" + path_prev + + "': " + g_platform->GetErrnoString()); + } + } + } + int result2 = g_platform->Rename(path.c_str(), path_prev.c_str()); + if (result2 != 0) { + throw Exception("Error backing up config file to '" + path_prev + + "': " + g_platform->GetErrnoString()); + } + } + + // Now move temp into place. + int result2 = g_platform->Rename(path_temp.c_str(), path.c_str()); + if (result2 != 0) { + throw Exception("Error renaming temp config file to final '" + path + + "': " + g_platform->GetErrnoString()); + } + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyEnv(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("env"); + + static PyObject* env_obj = nullptr; + + // Just build this once and recycle it. + if (env_obj == nullptr) { + std::string config_path = g_platform->GetConfigFilePath(); + PyObject* is_debug_build_obj; +#if BA_DEBUG_BUILD + is_debug_build_obj = Py_True; +#else + is_debug_build_obj = Py_False; +#endif + PyObject* is_test_build_obj; +#if BA_TEST_BUILD + is_test_build_obj = Py_True; +#else + is_test_build_obj = Py_False; +#endif + bool demo_mode{g_buildconfig.demo_build()}; + bool arcade_mode{g_buildconfig.arcade_build()}; + bool iircade_mode{g_buildconfig.arcade_build()}; + + const char* ui_scale; + switch (GetInterfaceType()) { + case UIScale::kLarge: + ui_scale = "large"; + break; + case UIScale::kMedium: + ui_scale = "medium"; + break; + case UIScale::kSmall: + ui_scale = "small"; + break; + default: + throw Exception(); + } + // clang-format off + env_obj = Py_BuildValue( + "{" + "si" // build_number + "ss" // config_file_path + "ss" // locale + "ss" // user_agent_string + "ss" // version + "sO" // debug_build + "sO" // test_build + "ss" // python_directory_user + "ss" // python_directory_app + "ss" // platform + "ss" // subplatform + "ss" // ui_scale + "sO" // on_tv + "sO" // vr_mode + "sO" // toolbar_test + "sO" // demo_mode + "sO" // arcade_mode + "sO" // iircade_mode + "si" // protocol_version + "sO" // headless_mode + "ss" // python_directory_app_site + "}", + "build_number", kAppBuildNumber, + "config_file_path", config_path.c_str(), + "locale", g_platform->GetLocale().c_str(), + "user_agent_string", g_app_globals->user_agent_string.c_str(), + "version", kAppVersion, + "debug_build", is_debug_build_obj, + "test_build", is_test_build_obj, + "python_directory_user", g_platform->GetUserPythonDirectory().c_str(), + "python_directory_app", g_platform->GetAppPythonDirectory().c_str(), + "platform", g_platform->GetPlatformName().c_str(), + "subplatform", g_platform->GetSubplatformName().c_str(), + "ui_scale", ui_scale, + "on_tv", g_platform->IsRunningOnTV() ? Py_True : Py_False, + "vr_mode", IsVRMode() ? Py_True : Py_False, + "toolbar_test", BA_TOOLBAR_TEST ? Py_True : Py_False, + "demo_mode", demo_mode ? Py_True : Py_False, + "arcade_mode", g_buildconfig.arcade_build() ? Py_True : Py_False, + "iircade_mode", g_buildconfig.iircade_build() ? Py_True: Py_False, + "protocol_version", kProtocolVersion, + "headless_mode", HeadlessMode() ? Py_True : Py_False, + "python_directory_app_site", + g_platform->GetSitePythonDirectory().c_str()); + // clang-format on + } + Py_INCREF(env_obj); + g_python->set_env_obj(env_obj); + return env_obj; + BA_PYTHON_CATCH; +} + +auto PySetStressTesting(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_stress_testing"); + int testing; + int player_count; + if (!PyArg_ParseTuple(args, "pi", &testing, &player_count)) { + return nullptr; + } + g_app->PushSetStressTestingCall(static_cast(testing), player_count); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyPrintStdout(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("print_stdout"); + const char* s; + if (!PyArg_ParseTuple(args, "s", &s)) { + return nullptr; + } + Logging::PrintStdout(s); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyPrintStderr(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("print_stderr"); + const char* s; + if (!PyArg_ParseTuple(args, "s", &s)) { + return nullptr; + } + Logging::PrintStderr(s); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyLog(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("log"); + static const char* kwlist[] = {"message", "to_stdout", "to_server", nullptr}; + int to_server = 1; + int to_stdout = 1; + std::string message; + PyObject* message_obj; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|pp", + const_cast(kwlist), &message_obj, + &to_stdout, &to_server)) { + return nullptr; + } + message = Python::GetPyString(message_obj); + Log(message, static_cast(to_stdout), static_cast(to_server)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyTimeFormatCheck(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("time_format_check"); + static const char* kwlist[] = {"time_format", "length", nullptr}; + PyObject* time_format_obj; + PyObject* length_obj; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "OO", + const_cast(kwlist), &time_format_obj, + &length_obj)) { + return nullptr; + } + auto time_format = Python::GetPyEnum_TimeFormat(time_format_obj); + + g_python->TimeFormatCheck(time_format, length_obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsApp::methods_def[] = { + {"appname", (PyCFunction)PyAppName, METH_NOARGS, + "appname() -> str\n" + "\n" + "(internal)\n"}, + {"appnameupper", (PyCFunction)PyAppNameUpper, METH_NOARGS, + "appnameupper() -> str\n" + "\n" + "(internal)\n" + "\n" + "Return whether this build of the game can display full unicode such as\n" + "Emoji, Asian languages, etc.\n"}, + {"is_xcode_build", (PyCFunction)PyIsXCodeBuild, METH_NOARGS, + "is_xcode_build() -> bool\n" + "\n" + "(internal)\n"}, + {"can_display_full_unicode", (PyCFunction)PyCanDisplayFullUnicode, + METH_NOARGS, + "can_display_full_unicode() -> bool\n" + "\n" + "(internal)\n"}, + {"time_format_check", (PyCFunction)PyTimeFormatCheck, + METH_VARARGS | METH_KEYWORDS, + "time_format_check(time_format: ba.TimeFormat, length: Union[float, " + "int])\n" + " -> None\n" + "\n" + "(internal)\n" + "\n" + "Logs suspicious time values for timers or animate calls.\n" + "\n" + "(for helping with the transition from milliseconds-based time calls\n" + "to seconds-based ones)"}, + + {"log", (PyCFunction)PyLog, METH_VARARGS | METH_KEYWORDS, + "log(message: str, to_stdout: bool = True,\n" + " to_server: bool = True) -> None\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "Log a message. This goes to the default logging mechanism depending\n" + "on the platform (stdout on mac, android log on android, etc).\n" + "\n" + "Log messages also go to the in-game console unless 'to_console'\n" + "is False. They are also sent to the master-server for use in analyzing\n" + "issues unless to_server is False.\n" + "\n" + "Python's standard print() is wired to call this (with default values)\n" + "so in most cases you can just use that."}, + + {"print_stdout", PyPrintStdout, METH_VARARGS, + "print_stdout(message: str) -> None\n" + "\n" + "(internal)"}, + + {"print_stderr", PyPrintStderr, METH_VARARGS, + "print_stderr(message: str) -> None\n" + "\n" + "(internal)"}, + + {"set_stress_testing", PySetStressTesting, METH_VARARGS, + "set_stress_testing(testing: bool, player_count: int) -> None\n" + "\n" + "(internal)"}, + + {"env", (PyCFunction)PyEnv, METH_NOARGS, + "env() -> dict\n" + "\n" + "(internal)\n" + "\n" + "Returns a dict containing general info about the operating environment\n" + "such as version, platform, etc.\n" + "This info is now exposed through ba.App; refer to those docs for\n" + "info on specific elements."}, + + {"commit_config", (PyCFunction)PyCommitConfig, METH_VARARGS | METH_KEYWORDS, + "commit_config(config: str) -> None\n" + "\n" + "(internal)"}, + + {"apply_config", PyApplyConfig, METH_VARARGS, + "apply_config() -> None\n" + "\n" + "(internal)"}, + +#if BA_DEBUG_BUILD + {"bless", (PyCFunction)PyBless, METH_VARARGS | METH_KEYWORDS, + "bless() -> None\n" + "\n" + "(internal)"}, +#endif + + {"quit", (PyCFunction)PyQuit, METH_VARARGS | METH_KEYWORDS, + "quit(soft: bool = False, back: bool = False) -> None\n" + "\n" + "Quit the game.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "On systems like android, 'soft' will end the activity but keep the\n" + "app running."}, + + {"screenmessage", (PyCFunction)PyScreenMessage, + METH_VARARGS | METH_KEYWORDS, + "screenmessage(message: Union[str, ba.Lstr],\n" + " color: Sequence[float] = None, top: bool = False,\n" + " image: Dict[str, Any] = None, log: bool = False,\n" + " clients: Sequence[int] = None, transient: bool = False) -> None\n" + "\n" + "Print a message to the local client's screen, in a given color.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "If 'top' is True, the message will go to the top message area.\n" + "For 'top' messages, 'image' can be a texture to display alongside the\n" + "message.\n" + "If 'log' is True, the message will also be printed to the output log\n" + "'clients' can be a list of client-ids the message should be sent to,\n" + "or None to specify that everyone should receive it.\n" + "If 'transient' is True, the message will not be included in the\n" + "game-stream and thus will not show up when viewing replays.\n" + "Currently the 'clients' option only works for transient messages."}, + + {"timer", (PyCFunction)PyTimer, METH_VARARGS | METH_KEYWORDS, + "timer(time: float, call: Callable[[], Any], repeat: bool = False,\n" + " timetype: ba.TimeType = TimeType.SIM,\n" + " timeformat: ba.TimeFormat = TimeFormat.SECONDS,\n" + " suppress_format_warning: bool = False)\n" + " -> None\n" + "\n" + "Schedule a call to run at a later point in time.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "This function adds a timer to the current ba.Context.\n" + "This timer cannot be canceled or modified once created. If you\n" + " require the ability to do so, use the ba.Timer class instead.\n" + "\n" + "time: length of time (in seconds by default) that the timer will wait\n" + "before firing. Note that the actual delay experienced may vary\n " + "depending on the timetype. (see below)\n" + "\n" + "call: A callable Python object. Note that the timer will retain a\n" + "strong reference to the callable for as long as it exists, so you\n" + "may want to look into concepts such as ba.WeakCall if that is not\n" + "desired.\n" + "\n" + "repeat: if True, the timer will fire repeatedly, with each successive\n" + "firing having the same delay as the first.\n" + "\n" + "timetype can be either 'sim', 'base', or 'real'. It defaults to\n" + "'sim'. Types are explained below:\n" + "\n" + "'sim' time maps to local simulation time in ba.Activity or ba.Session\n" + "Contexts. This means that it may progress slower in slow-motion play\n" + "modes, stop when the game is paused, etc. This time type is not\n" + "available in UI contexts.\n" + "\n" + "'base' time is also linked to gameplay in ba.Activity or ba.Session\n" + "Contexts, but it progresses at a constant rate regardless of\n " + "slow-motion states or pausing. It can, however, slow down or stop\n" + "in certain cases such as network outages or game slowdowns due to\n" + "cpu load. Like 'sim' time, this is unavailable in UI contexts.\n" + "\n" + "'real' time always maps to actual clock time with a bit of filtering\n" + "added, regardless of Context. (the filtering prevents it from going\n" + "backwards or jumping forward by large amounts due to the app being\n" + "backgrounded, system time changing, etc.)\n" + "Real time timers are currently only available in the UI context.\n" + "\n" + "the 'timeformat' arg defaults to seconds but can also be milliseconds.\n" + "\n" + "# timer example: print some stuff through time:\n" + "ba.screenmessage('hello from now!')\n" + "ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))\n" + "ba.timer(2.0, ba.Call(ba.screenmessage, 'hello from the future 2!'))\n"}, + + {"time", (PyCFunction)PyTime, METH_VARARGS | METH_KEYWORDS, + "time(timetype: ba.TimeType = TimeType.SIM,\n" + " timeformat: ba.TimeFormat = TimeFormat.SECONDS)\n" + " -> \n" + "\n" + "Return the current time.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "The time returned depends on the current ba.Context and timetype.\n" + "\n" + "timetype can be either SIM, BASE, or REAL. It defaults to\n" + "SIM. Types are explained below:\n" + "\n" + "SIM time maps to local simulation time in ba.Activity or ba.Session\n" + "Contexts. This means that it may progress slower in slow-motion play\n" + "modes, stop when the game is paused, etc. This time type is not\n" + "available in UI contexts.\n" + "\n" + "BASE time is also linked to gameplay in ba.Activity or ba.Session\n" + "Contexts, but it progresses at a constant rate regardless of\n " + "slow-motion states or pausing. It can, however, slow down or stop\n" + "in certain cases such as network outages or game slowdowns due to\n" + "cpu load. Like 'sim' time, this is unavailable in UI contexts.\n" + "\n" + "REAL time always maps to actual clock time with a bit of filtering\n" + "added, regardless of Context. (the filtering prevents it from going\n" + "backwards or jumping forward by large amounts due to the app being\n" + "backgrounded, system time changing, etc.)\n" + "\n" + "the 'timeformat' arg defaults to SECONDS which returns float seconds,\n" + "but it can also be MILLISECONDS to return integer milliseconds.\n" + "\n" + "Note: If you need pure unfiltered clock time, just use the standard\n" + "Python functions such as time.time()."}, + + {"pushcall", (PyCFunction)PyPushCall, METH_VARARGS | METH_KEYWORDS, + "pushcall(call: Callable, from_other_thread: bool = False,\n" + " suppress_other_thread_warning: bool = False ) -> None\n" + "\n" + "Pushes a call onto the event loop to be run during the next cycle.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "This can be handy for calls that are disallowed from within other\n" + "callbacks, etc.\n" + "\n" + "This call expects to be used in the game thread, and will automatically\n" + "save and restore the ba.Context to behave seamlessly.\n" + "\n" + "If you want to push a call from outside of the game thread,\n" + "however, you can pass 'from_other_thread' as True. In this case\n" + "the call will always run in the UI context on the game thread."}, + + {"getactivity", (PyCFunction)PyGetActivity, METH_VARARGS | METH_KEYWORDS, + "getactivity(doraise: bool = True) -> \n" + "\n" + "Return the current ba.Activity instance.\n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "Note that this is based on context; thus code run in a timer generated\n" + "in Activity 'foo' will properly return 'foo' here, even if another\n" + "Activity has since been created or is transitioning in.\n" + "If there is no current Activity, raises a ba.ActivityNotFoundError.\n" + "If doraise is False, None will be returned instead in that case."}, + + {"newactivity", (PyCFunction)PyNewActivity, METH_VARARGS | METH_KEYWORDS, + "newactivity(activity_type: Type[ba.Activity],\n" + " settings: dict = None) -> ba.Activity\n" + "\n" + "Instantiates a ba.Activity given a type object.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "Activities require special setup and thus cannot be directly\n" + "instantiated; you must go through this function."}, + + {"get_foreground_host_session", (PyCFunction)PyGetForegroundHostSession, + METH_VARARGS | METH_KEYWORDS, + "get_foreground_host_session() -> Optional[ba.Session]\n" + "\n" + "(internal)\n" + "\n" + "Return the ba.Session currently being displayed, or None if there is\n" + "none."}, + + {"register_activity", (PyCFunction)PyRegisterActivity, + METH_VARARGS | METH_KEYWORDS, + "register_activity(activity: ba.Activity) -> ActivityData\n" + "\n" + "(internal)"}, + + {"register_session", (PyCFunction)PyRegisterSession, + METH_VARARGS | METH_KEYWORDS, + "register_session(session: ba.Session) -> SessionData\n" + "\n" + "(internal)"}, + + {"is_in_replay", (PyCFunction)PyIsInReplay, METH_VARARGS | METH_KEYWORDS, + "is_in_replay() -> bool\n" + "\n" + "(internal)"}, + + {"new_replay_session", (PyCFunction)PyNewReplaySession, + METH_VARARGS | METH_KEYWORDS, + "new_replay_session(file_name: str) -> None\n" + "\n" + "(internal)"}, + + {"new_host_session", (PyCFunction)PyNewHostSession, + METH_VARARGS | METH_KEYWORDS, + "new_host_session(sessiontype: Type[ba.Session],\n" + " benchmark_type: str = None) -> None\n" + "\n" + "(internal)"}, + + {"getsession", (PyCFunction)PyGetSession, METH_VARARGS | METH_KEYWORDS, + "getsession(doraise: bool = True) -> \n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "Returns the current ba.Session instance.\n" + "Note that this is based on context; thus code being run in the UI\n" + "context will return the UI context here even if a game Session also\n" + "exists, etc. If there is no current Session, an Exception is raised, " + "or\n" + "if doraise is False then None is returned instead."}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_app.h b/src/ballistica/python/methods/python_methods_app.h new file mode 100644 index 00000000..26467755 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_app.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_APP_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_APP_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// App related individual python methods for our module. +class PythonMethodsApp { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_APP_H_ diff --git a/src/ballistica/python/methods/python_methods_gameplay.cc b/src/ballistica/python/methods/python_methods_gameplay.cc new file mode 100644 index 00000000..54f3c7b2 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_gameplay.cc @@ -0,0 +1,765 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_gameplay.h" + +#include +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/dynamics/collision.h" +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/game/connection/connection_to_client.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/player_spec.h" +#include "ballistica/generic/json.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call_runnable.h" +#include "ballistica/scene/node/node.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +auto PyNewNode(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("new_node"); + Node* n = g_python->DoNewNode(args, keywds); + if (!n) { + return nullptr; + } + return n->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyPrintNodes(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("print_nodes"); + HostActivity* host_activity = + g_game->GetForegroundContext().GetHostActivity(); + if (!host_activity) { + throw Exception(PyExcType::kContext); + } + Scene* scene = host_activity->scene(); + std::string s; + int count = 1; + for (auto&& i : scene->nodes()) { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "#%d: type: %-14s desc: %s", count, + i->type()->name().c_str(), i->label().c_str()); + s += buffer; + Log(buffer); + count++; + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetNodes(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_nodes"); + HostActivity* host_activity = Context::current().GetHostActivity(); + if (!host_activity) { + throw Exception(PyExcType::kContext); + } + Scene* scene = host_activity->scene(); + PyObject* py_list = PyList_New(0); + for (auto&& i : scene->nodes()) { + PyList_Append(py_list, i->BorrowPyRef()); + } + return py_list; + BA_PYTHON_CATCH; +} + +static auto DoGetCollideValue(Dynamics* dynamics, const Collision* c, + const char* name) -> PyObject* { + BA_PYTHON_TRY; + if (!strcmp(name, "depth")) { + return Py_BuildValue("f", c->depth); + } else if (!strcmp(name, "position")) { + return Py_BuildValue("(fff)", c->x, c->y, c->z); + } else if (!strcmp(name, "sourcenode")) { + if (!dynamics->in_collide_message()) { + PyErr_SetString( + PyExc_AttributeError, + "collide value 'sourcenode' is only valid while processing " + "collide messages"); + return nullptr; + } + Node* n = dynamics->GetActiveCollideSrcNode(); + if (n) { + return n->NewPyRef(); + } else { + Py_RETURN_NONE; + } + } else if (!strcmp(name, "opposingnode")) { + if (!dynamics->in_collide_message()) { + PyErr_SetString( + PyExc_AttributeError, + "collide value 'opposingnode' is only valid while processing " + "collide messages"); + return nullptr; + } + Node* n = dynamics->GetActiveCollideDstNode(); + if (n) { + return n->NewPyRef(); + } else { + Py_RETURN_NONE; + } + } else if (!strcmp(name, "opposingbody")) { + return Py_BuildValue("i", dynamics->GetCollideMessageReverseOrder() + ? c->body_id_2 + : c->body_id_1); + } else { + PyErr_SetString( + PyExc_AttributeError, + (std::string("\"") + name + "\" is not a valid collide value name") + .c_str()); + return nullptr; + } + BA_PYTHON_CATCH; +} + +auto PyGetCollisionInfo(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_collision_info"); + HostActivity* host_activity = Context::current().GetHostActivity(); + if (!host_activity) { + throw Exception(PyExcType::kContext); + } + Dynamics* dynamics = host_activity->scene()->dynamics(); + assert(dynamics); + PyObject* obj = nullptr; + + // Take arg list as individual items or possibly a single tuple + Py_ssize_t argc = PyTuple_GET_SIZE(args); + if (argc > 1) { + obj = args; + } else if (argc == 1) { + obj = PyTuple_GET_ITEM(args, 0); + } + Collision* c = dynamics->active_collision(); + if (!c) { + PyErr_SetString(PyExc_RuntimeError, + "This must be called from a collision callback."); + return nullptr; + } + if (PyUnicode_Check(obj)) { + return DoGetCollideValue(dynamics, c, PyUnicode_AsUTF8(obj)); + } else if (PyTuple_Check(obj)) { + Py_ssize_t size = PyTuple_GET_SIZE(obj); + PyObject* return_tuple = PyTuple_New(size); + for (Py_ssize_t i = 0; i < size; i++) { + PyObject* o = PyTuple_GET_ITEM(obj, i); + if (PyUnicode_Check(o)) { + PyObject* val_obj = DoGetCollideValue(dynamics, c, PyUnicode_AsUTF8(o)); + if (val_obj) { + PyTuple_SetItem(return_tuple, i, val_obj); + } else { + Py_DECREF(return_tuple); + return nullptr; + } + } else { + Py_DECREF(return_tuple); + PyErr_SetString(PyExc_TypeError, "Expected a string as tuple member."); + return nullptr; + } + } + return return_tuple; + } else { + PyErr_SetString(PyExc_TypeError, "Expected a string or tuple."); + return nullptr; + } + BA_PYTHON_CATCH; +} + +auto PyCameraShake(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("camera_shake"); + assert(InGameThread()); + float intensity = 1.0f; + static const char* kwlist[] = {"intensity", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|f", + const_cast(kwlist), &intensity)) { + return nullptr; + } + g_graphics->LocalCameraShake(intensity); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyPlaySound(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("play_sound"); + + assert(InGameThread()); + PyObject* sound_obj; + float volume = 1.0f; + int host_only = 0; + PyObject* pos_obj = Py_None; + static const char* kwlist[] = {"sound", "volume", "position", "host_only", + nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|fOp", + const_cast(kwlist), &sound_obj, + &volume, &pos_obj, &host_only)) { + return nullptr; + } + + Sound* sound = Python::GetPySound(sound_obj); + + // Can play sounds in a host scene context. + if (Scene* scene = Context::current().GetMutableScene()) { + if (sound->scene() != scene) { + throw Exception("Sound was not loaded in this context.", + PyExcType::kContext); + } + if (pos_obj != Py_None) { + std::vector vals = Python::GetPyFloats(pos_obj); + if (vals.size() != 3) { + throw Exception("Expected 3 floats for pos (got " + + std::to_string(vals.size()) + ")", + PyExcType::kValue); + } + scene->PlaySoundAtPosition(sound, volume, vals[0], vals[1], vals[2], + static_cast(host_only)); + } else { + scene->PlaySound(sound, volume, static_cast(host_only)); + } + } else { + throw Exception("Can't play sounds in this context.", PyExcType::kContext); + } + + Py_RETURN_NONE; + + BA_PYTHON_CATCH; +} + +auto PyEmitFx(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("emit_fx"); + static const char* kwlist[] = {"position", "velocity", "count", + "scale", "spread", "chunk_type", + "emit_type", "tendril_type", nullptr}; + PyObject* pos_obj = Py_None; + PyObject* vel_obj = Py_None; + int count = 10; + float scale = 1.0f; + float spread = 1.0f; + const char* chunk_type_str = "rock"; + const char* emit_type_str = "chunks"; + const char* tendril_type_str = "smoke"; + assert(InGameThread()); + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O|Oiffsss", const_cast(kwlist), &pos_obj, + &vel_obj, &count, &scale, &spread, &chunk_type_str, &emit_type_str, + &tendril_type_str)) { + return nullptr; + } + float x, y, z; + assert(pos_obj); + { + std::vector vals = Python::GetPyFloats(pos_obj); + if (vals.size() != 3) { + throw Exception("Expected 3 floats for position.", PyExcType::kValue); + } + x = vals[0]; + y = vals[1]; + z = vals[2]; + } + float vx = 0.0f; + float vy = 0.0f; + float vz = 0.0f; + if (vel_obj != Py_None) { + std::vector vals = Python::GetPyFloats(vel_obj); + if (vals.size() != 3) { + throw Exception("Expected 3 floats for velocity.", PyExcType::kValue); + } + vx = vals[0]; + vy = vals[1]; + vz = vals[2]; + } + BGDynamicsChunkType chunk_type; + if (!strcmp(chunk_type_str, "rock")) { + chunk_type = BGDynamicsChunkType::kRock; + } else if (!strcmp(chunk_type_str, "ice")) { + chunk_type = BGDynamicsChunkType::kIce; + } else if (!strcmp(chunk_type_str, "slime")) { + chunk_type = BGDynamicsChunkType::kSlime; + } else if (!strcmp(chunk_type_str, "metal")) { + chunk_type = BGDynamicsChunkType::kMetal; + } else if (!strcmp(chunk_type_str, "spark")) { + chunk_type = BGDynamicsChunkType::kSpark; + } else if (!strcmp(chunk_type_str, "splinter")) { + chunk_type = BGDynamicsChunkType::kSplinter; + } else if (!strcmp(chunk_type_str, "sweat")) { + chunk_type = BGDynamicsChunkType::kSweat; + } else { + throw Exception( + "Invalid chunk type: '" + std::string(chunk_type_str) + "'.", + PyExcType::kValue); + } + BGDynamicsTendrilType tendril_type; + if (!strcmp(tendril_type_str, "smoke")) { + tendril_type = BGDynamicsTendrilType::kSmoke; + } else if (!strcmp(tendril_type_str, "thin_smoke")) { + tendril_type = BGDynamicsTendrilType::kThinSmoke; + } else if (!strcmp(tendril_type_str, "ice")) { + tendril_type = BGDynamicsTendrilType::kIce; + } else { + throw Exception( + "Invalid tendril type: '" + std::string(tendril_type_str) + "'.", + PyExcType::kValue); + } + BGDynamicsEmitType emit_type; + if (!strcmp(emit_type_str, "chunks")) { + emit_type = BGDynamicsEmitType::kChunks; + } else if (!strcmp(emit_type_str, "stickers")) { + emit_type = BGDynamicsEmitType::kStickers; + } else if (!strcmp(emit_type_str, "tendrils")) { + emit_type = BGDynamicsEmitType::kTendrils; + } else if (!strcmp(emit_type_str, "distortion")) { + emit_type = BGDynamicsEmitType::kDistortion; + } else if (!strcmp(emit_type_str, "flag_stand")) { + emit_type = BGDynamicsEmitType::kFlagStand; + } else { + throw Exception("Invalid emit type: '" + std::string(emit_type_str) + "'.", + PyExcType::kValue); + } + if (Scene* scene = Context::current().GetMutableScene()) { + BGDynamicsEmission e; + e.emit_type = emit_type; + e.position = Vector3f(x, y, z); + e.velocity = Vector3f(vx, vy, vz); + e.count = count; + e.scale = scale; + e.spread = spread; + e.chunk_type = chunk_type; + e.tendril_type = tendril_type; + if (GameStream* output_stream = scene->GetGameStream()) { + output_stream->EmitBGDynamics(e); + } +#if !BA_HEADLESS_BUILD + g_bg_dynamics->Emit(e); +#endif // !BA_HEADLESS_BUILD + } else { + throw Exception("Can't emit bg dynamics in this context.", + PyExcType::kContext); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetMapBounds(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_map_bounds"); + HostActivity* host_activity = Context::current().GetHostActivity(); + if (!host_activity) { + throw Exception(PyExcType::kContext); + } + float xmin, ymin, zmin, xmax, ymax, zmax; + assert(InGameThread()); + if (!PyArg_ParseTuple(args, "(ffffff)", &xmin, &ymin, &zmin, &xmax, &ymax, + &zmax)) { + return nullptr; + } + host_activity->scene()->SetMapBounds(xmin, ymin, zmin, xmax, ymax, zmax); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetForegroundHostActivity(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_foreground_host_activity"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + + // Note: we return None if not in the game thread. + HostActivity* h = InGameThread() + ? g_game->GetForegroundContext().GetHostActivity() + : nullptr; + if (h != nullptr) { + PyObject* obj = h->GetPyActivity(); + Py_INCREF(obj); + return obj; + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetGameRoster(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_game_roster"); + BA_PRECONDITION(InGameThread()); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + PythonRef py_client_list(PyList_New(0), PythonRef::kSteal); + cJSON* party = g_game->game_roster(); + assert(party); + int len = cJSON_GetArraySize(party); + for (int i = 0; i < len; i++) { + cJSON* client = cJSON_GetArrayItem(party, i); + assert(client); + cJSON* spec = cJSON_GetObjectItem(client, "spec"); + cJSON* players = cJSON_GetObjectItem(client, "p"); + PythonRef py_player_list(PyList_New(0), PythonRef::kSteal); + if (players != nullptr) { + int plen = cJSON_GetArraySize(players); + for (int j = 0; j < plen; ++j) { + cJSON* player = cJSON_GetArrayItem(players, j); + if (player != nullptr) { + cJSON* name = cJSON_GetObjectItem(player, "n"); + cJSON* py_name_full = cJSON_GetObjectItem(player, "nf"); + cJSON* id_obj = cJSON_GetObjectItem(player, "i"); + int id_val = id_obj ? id_obj->valueint : -1; + if (name != nullptr && name->valuestring != nullptr + && py_name_full != nullptr && py_name_full->valuestring != nullptr + && id_val != -1) { + PythonRef py_player( + Py_BuildValue( + "{sssssi}", "name", + Utils::GetValidUTF8(name->valuestring, "ggr1").c_str(), + "name_full", + Utils::GetValidUTF8(py_name_full->valuestring, "ggr2") + .c_str(), + "id", id_val), + PythonRef::kSteal); + // This increments ref. + PyList_Append(py_player_list.get(), py_player.get()); + } + } + } + } + + // If there's a client_id with this data, include it; otherwise pass None. + cJSON* client_id = cJSON_GetObjectItem(client, "i"); + int clientid{}; + PythonRef client_id_ref; + if (client_id != nullptr) { + clientid = client_id->valueint; + client_id_ref.Steal(PyLong_FromLong(clientid)); + } else { + client_id_ref.Acquire(Py_None); + } + + // Let's also include a public account-id if we have one. + std::string account_id; + if (clientid == -1) { + account_id = AppInternalGetPublicAccountID(); + } else { + auto client2 = g_game->connections_to_clients().find(clientid); + if (client2 != g_game->connections_to_clients().end()) { + account_id = client2->second->peer_public_account_id(); + } + } + PythonRef account_id_ref; + if (account_id.empty()) { + account_id_ref.Acquire(Py_None); + } else { + account_id_ref.Steal(PyUnicode_FromString(account_id.c_str())); + } + + // Py_BuildValue steals a ref; gotta increment ourself (edit: NO IT DOESNT) + // Py_INCREF(py_player_list.get()); + PythonRef py_client( + Py_BuildValue( + "{sssssOsOsO}", "display_string", + (spec && spec->valuestring) + ? PlayerSpec(spec->valuestring).GetDisplayString().c_str() + : "", + "spec_string", (spec && spec->valuestring) ? spec->valuestring : "", + "players", py_player_list.get(), "client_id", client_id_ref.get(), + "account_id", account_id_ref.get()), + PythonRef::kSteal); + PyList_Append(py_client_list.get(), + py_client.get()); // this increments ref + } + return py_client_list.NewRef(); + BA_PYTHON_CATCH; +} + +auto PyGetScoresToBeat(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_scores_to_beat"); + const char* level; + const char* config; + PyObject* callback_obj = Py_None; + static const char* kwlist[] = {"level", "config", "callback", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ssO", + const_cast(kwlist), &level, &config, + &callback_obj)) { + return nullptr; + } + + // Allocate a Call object for this and pass its pointer to the main thread; + // we'll ref/de-ref it when it comes back. + auto* call = Object::NewDeferred(callback_obj); + g_app->PushGetScoresToBeatCall(level, config, call); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetDebugSpeedExponent(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_debug_speed_exponent"); + int speed; + if (!PyArg_ParseTuple(args, "i", &speed)) { + return nullptr; + } + HostActivity* host_activity = Context::current().GetHostActivity(); + if (!host_activity) { + throw Exception(PyExcType::kContext); + } +#if BA_DEBUG_BUILD + g_game->SetDebugSpeedExponent(speed); +#else + throw Exception("This call only functions in the debug build."); +#endif + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetReplaySpeedExponent(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_replay_speed_exponent"); + assert(g_game); + return PyLong_FromLong(g_game->replay_speed_exponent()); + BA_PYTHON_CATCH; +} + +auto PySetReplaySpeedExponent(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_replay_speed_exponent"); + int speed; + if (!PyArg_ParseTuple(args, "i", &speed)) return nullptr; + assert(g_game); + g_game->SetReplaySpeedExponent(speed); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyResetGameActivityTracking(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("reset_game_activity_tracking"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + if (g_game) { + g_game->ResetActivityTracking(); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyResetRandomPlayerNames(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("reset_random_player_names"); + InputDevice::ResetRandomNames(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetRandomNames(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_random_names"); + PyObject* list = PyList_New(0); + const std::list& random_name_list = Utils::GetRandomNameList(); + for (const auto& i : random_name_list) { + assert(Utils::IsValidUTF8(i)); + PyObject* obj = PyUnicode_FromString(i.c_str()); + PyList_Append(list, obj); + Py_DECREF(obj); + } + return list; + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsGameplay::methods_def[] = { + {"get_random_names", PyGetRandomNames, METH_VARARGS, + "get_random_names() -> list\n" + "\n" + "(internal)\n" + "\n" + "Returns the random names used by the game."}, + + {"reset_random_player_names", (PyCFunction)PyResetRandomPlayerNames, + METH_VARARGS | METH_KEYWORDS, + "reset_random_player_names() -> None\n" + "\n" + "(internal)"}, + + {"reset_game_activity_tracking", (PyCFunction)PyResetGameActivityTracking, + METH_VARARGS | METH_KEYWORDS, + "reset_game_activity_tracking() -> None\n" + "\n" + "(internal)"}, + + {"set_replay_speed_exponent", PySetReplaySpeedExponent, METH_VARARGS, + "set_replay_speed_exponent(speed: int) -> None\n" + "\n" + "(internal)\n" + "\n" + "Set replay speed. Actual displayed speed is pow(2,speed)."}, + + {"get_replay_speed_exponent", PyGetReplaySpeedExponent, METH_VARARGS, + "get_replay_speed_exponent() -> int\n" + "\n" + "(internal)\n" + "\n" + "Returns current replay speed value. Actual displayed speed is " + "pow(2,speed)."}, + + {"set_debug_speed_exponent", PySetDebugSpeedExponent, METH_VARARGS, + "set_debug_speed_exponent(speed: int) -> None\n" + "\n" + "(internal)\n" + "\n" + "Sets the debug speed scale for the game. Actual speed is pow(2,speed)."}, + + {"get_scores_to_beat", (PyCFunction)PyGetScoresToBeat, + METH_VARARGS | METH_KEYWORDS, + "get_scores_to_beat(level: str, config: str, callback: Callable) -> None\n" + "\n" + "(internal)"}, + + {"get_game_roster", (PyCFunction)PyGetGameRoster, + METH_VARARGS | METH_KEYWORDS, + "get_game_roster() -> List[Dict[str, Any]]\n" + "\n" + "(internal)"}, + + {"get_foreground_host_activity", (PyCFunction)PyGetForegroundHostActivity, + METH_VARARGS | METH_KEYWORDS, + "get_foreground_host_activity() -> Optional[ba.Activity]\n" + "\n" + "(internal)\n" + "\n" + "Returns the ba.Activity currently in the foreground, or None if there\n" + "is none.\n"}, + + {"set_map_bounds", (PyCFunction)PySetMapBounds, + METH_VARARGS | METH_KEYWORDS, + "set_map_bounds(bounds: Tuple[float, float, float, float, float, float])\n" + " -> None\n" + "\n" + "(internal)\n" + "\n" + "Set map bounds. Generally nodes that go outside of this box are " + "killed."}, + + {"emitfx", (PyCFunction)PyEmitFx, METH_VARARGS | METH_KEYWORDS, + "emitfx(position: Sequence[float],\n" + " velocity: Optional[Sequence[float]] = None,\n" + " count: int = 10, scale: float = 1.0, spread: float = 1.0,\n" + " chunk_type: str = 'rock', emit_type: str ='chunks',\n" + " tendril_type: str = 'smoke') -> None\n" + "\n" + "Emit particles, smoke, etc. into the fx sim layer.\n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "The fx sim layer is a secondary dynamics simulation that runs in\n" + "the background and just looks pretty; it does not affect gameplay.\n" + "Note that the actual amount emitted may vary depending on graphics\n" + "settings, exiting element counts, or other factors."}, + + {"playsound", (PyCFunction)PyPlaySound, METH_VARARGS | METH_KEYWORDS, + "playsound(sound: Sound, volume: float = 1.0,\n" + " position: Sequence[float] = None, host_only: bool = False) -> None\n" + "\n" + "Play a ba.Sound a single time.\n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "If position is not provided, the sound will be at a constant volume\n" + "everywhere. Position should be a float tuple of size 3."}, + + {"camerashake", (PyCFunction)PyCameraShake, METH_VARARGS | METH_KEYWORDS, + "camerashake(intensity: float = 1.0) -> None\n" + "\n" + "Shake the camera.\n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "Note that some cameras and/or platforms (such as VR) may not display\n" + "camera-shake, so do not rely on this always being visible to the\n" + "player as a gameplay cue."}, + + {"get_collision_info", PyGetCollisionInfo, METH_VARARGS, + "get_collision_info(*args: Any) -> Any\n" + "\n" + "Return collision related values\n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "Returns a single collision value or tuple of values such as location,\n" + "depth, nodes involved, etc. Only call this in the handler of a\n" + "collision-triggered callback or message"}, + + {"getnodes", PyGetNodes, METH_VARARGS, + "getnodes() -> list\n" + "\n" + "Return all nodes in the current ba.Context." + "\n" + "Category: Gameplay Functions"}, + + {"printnodes", PyPrintNodes, METH_VARARGS, + "printnodes() -> None\n" + "\n" + "Print various info about existing nodes; useful for debugging.\n" + "\n" + "Category: Gameplay Functions"}, + + {"newnode", (PyCFunction)PyNewNode, METH_VARARGS | METH_KEYWORDS, + "newnode(type: str, owner: ba.Node = None,\n" + "attrs: dict = None, name: str = None, delegate: Any = None)\n" + " -> Node\n" + "\n" + "Add a node of the given type to the game.\n" + "\n" + "Category: Gameplay Functions\n" + "\n" + "If a dict is provided for 'attributes', the node's initial attributes\n" + "will be set based on them.\n" + "\n" + "'name', if provided, will be stored with the node purely for debugging\n" + "purposes. If no name is provided, an automatic one will be generated\n" + "such as 'terrain@foo.py:30'.\n" + "\n" + "If 'delegate' is provided, Python messages sent to the node will go to\n" + "that object's handlemessage() method. Note that the delegate is stored\n" + "as a weak-ref, so the node itself will not keep the object alive.\n" + "\n" + "if 'owner' is provided, the node will be automatically killed when that\n" + "object dies. 'owner' can be another node or a ba.Actor"}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_gameplay.h b/src/ballistica/python/methods/python_methods_gameplay.h new file mode 100644 index 00000000..95b0e8c1 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_gameplay.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GAMEPLAY_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GAMEPLAY_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// Gameplay related individual python methods for our module. +class PythonMethodsGameplay { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GAMEPLAY_H_ diff --git a/src/ballistica/python/methods/python_methods_graphics.cc b/src/ballistica/python/methods/python_methods_graphics.cc new file mode 100644 index 00000000..92bbf923 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_graphics.cc @@ -0,0 +1,315 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_graphics.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call_runnable.h" + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +auto PyCharStr(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("charstr"); + PyObject* name_obj; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &name_obj)) { + return nullptr; + } + assert(g_game); + auto id(Python::GetPyEnum_SpecialChar(name_obj)); + assert(Utils::IsValidUTF8(g_game->CharStr(id))); + return PyUnicode_FromString(g_game->CharStr(id).c_str()); + BA_PYTHON_CATCH; +} + +auto PySafeColor(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("safecolor"); + PyObject* color_obj; + float red, green, blue; + float target_intensity = 0.6f; + static const char* kwlist[] = {"color", "target_intensity", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|f", + const_cast(kwlist), &color_obj, + &target_intensity)) { + return nullptr; + } + if (!PySequence_Check(color_obj)) { + throw Exception("Expected a sequence.", PyExcType::kType); + } + int len = static_cast(PySequence_Length(color_obj)); + if (len != 3 && len != 4) { + throw Exception("Expected a 3 or 4 length sequence; got " + + Python::ObjToString(color_obj) + ".", + PyExcType::kValue); + } + PythonRef red_obj(PySequence_GetItem(color_obj, 0), PythonRef::kSteal); + PythonRef green_obj(PySequence_GetItem(color_obj, 1), PythonRef::kSteal); + PythonRef blue_obj(PySequence_GetItem(color_obj, 2), PythonRef::kSteal); + red = Python::GetPyFloat(red_obj.get()); + green = Python::GetPyFloat(green_obj.get()); + blue = Python::GetPyFloat(blue_obj.get()); + Graphics::GetSafeColor(&red, &green, &blue, target_intensity); + if (len == 3) { + return Py_BuildValue("(fff)", red, green, blue); + } else { + PythonRef alpha_obj(PySequence_GetItem(color_obj, 3), PythonRef::kSteal); + float alpha = Python::GetPyFloat(alpha_obj.get()); + return Py_BuildValue("(ffff)", red, green, blue, alpha); + } + BA_PYTHON_CATCH; +} + +auto PyGetMaxGraphicsQuality(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_max_graphics_quality"); + if (g_graphics && g_graphics->has_supports_high_quality_graphics_value() + && g_graphics->supports_high_quality_graphics()) { + return Py_BuildValue("s", "High"); + } else { + return Py_BuildValue("s", "Medium"); + } + BA_PYTHON_CATCH; +} + +auto PyEvaluateLstr(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("evaluate_lstr"); + const char* value; + static const char* kwlist[] = {"value", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &value)) { + return nullptr; + } + return PyUnicode_FromString( + g_game->CompileResourceString(value, "evaluate_lstr").c_str()); + BA_PYTHON_CATCH; +} + +auto PyGetStringHeight(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_string_height"); + std::string s; + int suppress_warning = 0; + PyObject* s_obj; + static const char* kwlist[] = {"string", "suppress_warning", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i", + const_cast(kwlist), &s_obj, + &suppress_warning)) { + return nullptr; + } + if (!suppress_warning) { + BA_LOG_PYTHON_TRACE( + "get_string_height() use is heavily discouraged as it reduces " + "language-independence; pass suppress_warning=True if you must use " + "it."); + } + s = Python::GetPyString(s_obj); +#if BA_DEBUG_BUILD + if (g_game->CompileResourceString(s, "get_string_height test") != s) { + BA_LOG_PYTHON_TRACE( + "resource-string passed to get_string_height; this should be avoided"); + } +#endif + assert(g_graphics); + return Py_BuildValue("f", g_text_graphics->GetStringHeight(s)); + BA_PYTHON_CATCH; +} + +auto PyGetStringWidth(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_string_width"); + std::string s; + PyObject* s_obj; + int suppress_warning = 0; + static const char* kwlist[] = {"string", "suppress_warning", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|i", + const_cast(kwlist), &s_obj, + &suppress_warning)) { + return nullptr; + } + if (!suppress_warning) { + BA_LOG_PYTHON_TRACE( + "get_string_width() use is heavily discouraged as it reduces " + "language-independence; pass suppress_warning=True if you must use " + "it."); + } + s = Python::GetPyString(s_obj); +#if BA_DEBUG_BUILD + if (g_game->CompileResourceString(s, "get_string_width debug test") != s) { + BA_LOG_PYTHON_TRACE( + "resource-string passed to get_string_width; this should be avoided"); + } +#endif + assert(g_graphics); + return Py_BuildValue("f", g_text_graphics->GetStringWidth(s)); + BA_PYTHON_CATCH; +} + +auto PyHaveChars(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("have_chars"); + std::string text; + PyObject* text_obj; + static const char* kwlist[] = {"text", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &text_obj)) { + return nullptr; + } + text = Python::GetPyString(text_obj); + if (TextGraphics::HaveChars(text)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyAddCleanFrameCallback(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("add_clean_frame_callback"); + PyObject* call_obj; + static const char* kwlist[] = {"call", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &call_obj)) { + return nullptr; + } + g_python->AddCleanFrameCommand(Object::New(call_obj)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyHasGammaControl(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("has_gamma_control"); + // phasing this out; our old non-sdl2 mac has gamma controls but nothing newer + // does... +#if BA_OSTYPE_MACOS && !BA_SDL2_BUILD + Py_RETURN_TRUE; +#else + Py_RETURN_FALSE; +#endif + BA_PYTHON_CATCH; +} + +auto PyGetDisplayResolution(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_display_resolution"); + int x = 0; + int y = 0; + bool have_res = g_platform->GetDisplayResolution(&x, &y); + if (have_res) { + return Py_BuildValue("(ii)", x, y); + } else { + Py_RETURN_NONE; + } + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsGraphics::methods_def[] = { + {"get_display_resolution", PyGetDisplayResolution, METH_VARARGS, + "get_display_resolution() -> Optional[Tuple[int, int]]\n" + "\n" + "(internal)\n" + "\n" + "Return the currently selected display resolution for fullscreen\n" + "display. Returns None if resolutions cannot be directly set."}, + + {"has_gamma_control", PyHasGammaControl, METH_VARARGS, + "has_gamma_control() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Returns whether the system can adjust overall screen gamma)"}, + + {"add_clean_frame_callback", (PyCFunction)PyAddCleanFrameCallback, + METH_VARARGS | METH_KEYWORDS, + "add_clean_frame_callback(call: Callable) -> None\n" + "\n" + "(internal)\n" + "\n" + "Provide an object to be called once the next non-progress-bar-frame has\n" + "been rendered. Useful for queueing things to load in the background\n" + "without elongating any current progress-bar-load."}, + + {"have_chars", (PyCFunction)PyHaveChars, METH_VARARGS | METH_KEYWORDS, + "have_chars(text: str) -> bool\n" + "\n" + "(internal)"}, + + {"get_string_width", (PyCFunction)PyGetStringWidth, + METH_VARARGS | METH_KEYWORDS, + "get_string_width(string: str, suppress_warning: bool = False) -> float\n" + "\n" + "(internal)\n" + "\n" + "Given a string, returns its width using the standard small app\n" + "font."}, + + {"get_string_height", (PyCFunction)PyGetStringHeight, + METH_VARARGS | METH_KEYWORDS, + "get_string_height(string: str, suppress_warning: bool = False) -> float\n" + "\n" + "(internal)\n" + "\n" + "Given a string, returns its height using the standard small app\n" + "font."}, + + {"evaluate_lstr", (PyCFunction)PyEvaluateLstr, METH_VARARGS | METH_KEYWORDS, + "evaluate_lstr(value: str) -> str\n" + "\n" + "(internal)"}, + + {"get_max_graphics_quality", PyGetMaxGraphicsQuality, METH_VARARGS, + "get_max_graphics_quality() -> str\n" + "\n" + "(internal)\n" + "\n" + "Return the max graphics-quality supported on the current hardware."}, + + {"safecolor", (PyCFunction)PySafeColor, METH_VARARGS | METH_KEYWORDS, + "safecolor(color: Sequence[float], target_intensity: float = 0.6)\n" + " -> Tuple[float, ...]\n" + "\n" + "Given a color tuple, return a color safe to display as text.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "Accepts tuples of length 3 or 4. This will slightly brighten very\n" + "dark colors, etc."}, + + {"charstr", (PyCFunction)PyCharStr, METH_VARARGS | METH_KEYWORDS, + "charstr(char_id: ba.SpecialChar) -> str\n" + "\n" + "Get a unicode string representing a special character.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "Note that these utilize the private-use block of unicode characters\n" + "(U+E000-U+F8FF) and are specific to the game; exporting or rendering\n" + "them elsewhere will be meaningless.\n" + "\n" + "see ba.SpecialChar for the list of available characters."}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_graphics.h b/src/ballistica/python/methods/python_methods_graphics.h new file mode 100644 index 00000000..022dcfc0 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_graphics.h @@ -0,0 +1,17 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// Graphics related individual python methods for our module. +class PythonMethodsGraphics { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_GRAPHICS_H_ diff --git a/src/ballistica/python/methods/python_methods_input.cc b/src/ballistica/python/methods/python_methods_input.cc new file mode 100644 index 00000000..e98cc541 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_input.cc @@ -0,0 +1,394 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_input.h" + +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/game.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/input/device/touch_input.h" +#include "ballistica/input/input.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +auto PyGetConfigurableGamePads(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_configurable_game_pads"); + std::vector gamepads = g_input->GetConfigurableGamePads(); + PyObject* list = PyList_New(0); + for (auto&& i : gamepads) { + PyObject* obj = i->NewPyRef(); + PyList_Append(list, obj); + Py_DECREF(obj); + } + return list; + BA_PYTHON_CATCH; +} + +auto PyHaveTouchScreenInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("have_touch_screen_input"); + if (g_app_globals->touch_input) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyStartListeningForWiiRemotes(PyObject* self, PyObject* args) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("start_listening_for_wii_remotes"); + g_platform->StartListeningForWiiRemotes(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyStopListeningForWiiRemotes(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("stop_listening_for_wii_remotes"); + g_platform->StopListeningForWiiRemotes(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetDeviceAccount(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_device_account"); + std::string name; + PyObject* name_obj; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &name_obj)) { + return nullptr; + } + name = Python::GetPyString(name_obj); + AccountType account_type; + + // on headless builds we keep these distinct from regular + // device accounts (so we get a 'ServerXXX' name, etc) +#if BA_HEADLESS_BUILD + account_type = AccountType::kServer; +#else + account_type = AccountType::kDevice; +#endif + g_game->PushSetAccountCall(account_type, AccountState::kSignedIn, name, + g_platform->GetDeviceAccountID()); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetDeviceLoginID(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_device_login_id"); + assert(Utils::IsValidUTF8(g_platform->GetDeviceAccountID())); + return PyUnicode_FromString(g_platform->GetDeviceAccountID().c_str()); + BA_PYTHON_CATCH; +} + +auto PySetTouchscreenEditing(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_touchscreen_editing"); + int editing; + if (!PyArg_ParseTuple(args, "p", &editing)) { + return nullptr; + } + if (g_app_globals->touch_input) { + g_app_globals->touch_input->set_editing(static_cast(editing)); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyCaptureGamePadInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("capture_gamepad_input"); + assert(InGameThread()); + assert(g_python); + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return nullptr; + } + g_python->CaptureGamePadInput(obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyReleaseGamePadInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("release_gamepad_input"); + assert(InGameThread()); + assert(g_python); + g_python->ReleaseGamePadInput(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyCaptureKeyboardInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("capture_keyboard_input"); + assert(InGameThread()); + if (!g_python) { + return nullptr; + } + PyObject* obj; + if (!PyArg_ParseTuple(args, "O", &obj)) { + return nullptr; + } + g_python->CaptureKeyboardInput(obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyReleaseKeyboardInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("release_keyboard_input"); + assert(InGameThread()); + if (!g_python) { + return nullptr; + } + g_python->ReleaseKeyboardInput(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyLockAllInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("lock_all_input"); + assert(InGameThread()); + assert(g_input); + g_input->LockAllInput(false, Python::GetPythonFileLocation()); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyUnlockAllInput(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("unlock_all_input"); + assert(InGameThread()); + assert(g_input); + g_input->UnlockAllInput(false, Python::GetPythonFileLocation()); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetUIInputDevice(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_ui_input_device"); + assert(InGameThread()); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + InputDevice* d = g_ui->GetUIInputDevice(); + if (d) { + return d->NewPyRef(); + } else { + Py_RETURN_NONE; + } + BA_PYTHON_CATCH; +} + +auto PySetUIInputDevice(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_ui_input_device"); + assert(InGameThread()); + static const char* kwlist[] = {"input", nullptr}; + PyObject* input_device_obj = Py_None; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O", const_cast(kwlist), &input_device_obj)) { + return nullptr; + } + g_ui->SetUIInputDevice((input_device_obj == Py_None) + ? nullptr + : Python::GetPyInputDevice(input_device_obj)); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetInputDevice(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_input_device"); + assert(InGameThread()); + const char* name; + const char* unique_id; + int doraise = true; + static const char* kwlist[] = {"name", "unique_id", "doraise", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "ss|i", + const_cast(kwlist), &name, + &unique_id, &doraise)) { + return nullptr; + } + InputDevice* d = g_input->GetInputDevice(name, unique_id); + if (d) { + return d->NewPyRef(); + } else { + if (doraise) { + throw Exception(std::string("Input device not found: '") + name + " " + + unique_id + "'.", + PyExcType::kInputDeviceNotFound); + } else { + Py_RETURN_NONE; + } + } + BA_PYTHON_CATCH; +} + +auto PyGetLocalActiveInputDevicesCount(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_local_active_input_devices_count"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + BA_PRECONDITION(g_input); + return PyLong_FromLong(g_input->GetLocalActiveInputDeviceCount()); + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsInput::methods_def[] = { + {"get_local_active_input_devices_count", + (PyCFunction)PyGetLocalActiveInputDevicesCount, + METH_VARARGS | METH_KEYWORDS, + "get_local_active_input_devices_count() -> int\n" + "\n" + "(internal)"}, + + {"getinputdevice", (PyCFunction)PyGetInputDevice, + METH_VARARGS | METH_KEYWORDS, + "getinputdevice(name: str, unique_id: str, doraise: bool = True)\n" + " -> \n" + "\n" + "(internal)\n" + "\n" + "Given a type name and a unique identifier, returns an InputDevice.\n" + "Throws an Exception if the input-device is not found, or returns None\n" + "if 'doraise' is False.\n"}, + + {"set_ui_input_device", (PyCFunction)PySetUIInputDevice, + METH_VARARGS | METH_KEYWORDS, + "set_ui_input_device(input_device: Optional[ba.InputDevice]) -> None\n" + "\n" + "(internal)\n" + "\n" + "Sets the input-device that currently owns the user interface."}, + + {"get_ui_input_device", (PyCFunction)PyGetUIInputDevice, + METH_VARARGS | METH_KEYWORDS, + "get_ui_input_device() -> ba.InputDevice\n" + "\n" + "(internal)\n" + "\n" + "Returns the input-device that currently owns the user interface, or\n" + "None if there is none."}, + + {"unlock_all_input", PyUnlockAllInput, METH_VARARGS, + "unlock_all_input() -> None\n" + "\n" + "(internal)\n" + "\n" + "Resumes normal keyboard, mouse, and gamepad event processing."}, + + {"lock_all_input", PyLockAllInput, METH_VARARGS, + "lock_all_input() -> None\n" + "\n" + "(internal)\n" + "\n" + "Prevents all keyboard, mouse, and gamepad events from being processed."}, + + {"release_keyboard_input", PyReleaseKeyboardInput, METH_VARARGS, + "release_keyboard_input() -> None\n" + "\n" + "(internal)\n" + "\n" + "Resumes normal keyboard event processing."}, + + {"capture_keyboard_input", PyCaptureKeyboardInput, METH_VARARGS, + "capture_keyboard_input(call: Callable[[dict], None]) -> None\n" + "\n" + "(internal)\n" + "\n" + "Add a callable to be called for subsequent keyboard-game-pad events.\n" + "The method is passed a dict containing info about the event."}, + + {"release_gamepad_input", PyReleaseGamePadInput, METH_VARARGS, + "release_gamepad_input() -> None\n" + "\n" + "(internal)\n" + "\n" + "Resumes normal gamepad event processing."}, + + {"capture_gamepad_input", PyCaptureGamePadInput, METH_VARARGS, + "capture_gamepad_input(call: Callable[[dict], None]) -> None\n" + "\n" + "(internal)\n" + "\n" + "Add a callable to be called for subsequent gamepad events.\n" + "The method is passed a dict containing info about the event."}, + + {"set_touchscreen_editing", PySetTouchscreenEditing, METH_VARARGS, + "set_touchscreen_editing(editing: bool) -> None\n" + "\n" + "(internal)"}, + + {"get_device_login_id", (PyCFunction)PyGetDeviceLoginID, + METH_VARARGS | METH_KEYWORDS, "internal"}, + + {"set_device_account", (PyCFunction)PySetDeviceAccount, + METH_VARARGS | METH_KEYWORDS, "internal"}, + + {"stop_listening_for_wii_remotes", PyStopListeningForWiiRemotes, + METH_VARARGS, + "stop_listening_for_wii_remotes() -> None\n" + "\n" + "(internal)\n" + "\n" + "Stop listening for connections from wii remotes."}, + + {"start_listening_for_wii_remotes", PyStartListeningForWiiRemotes, + METH_VARARGS, + "start_listening_for_wii_remotes() -> None\n" + "\n" + "(internal)\n" + "\n" + "Start listening for connections from wii remotes."}, + + {"have_touchscreen_input", PyHaveTouchScreenInput, METH_VARARGS, + "have_touchscreen_input() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Returns whether or not a touch-screen input is present"}, + + {"get_configurable_game_pads", PyGetConfigurableGamePads, METH_VARARGS, + "get_configurable_game_pads() -> list\n" + "\n" + "(internal)\n" + "\n" + "Returns a list of the currently connected gamepads that can be\n" + "configured."}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_input.h b/src/ballistica/python/methods/python_methods_input.h new file mode 100644 index 00000000..7b2821cf --- /dev/null +++ b/src/ballistica/python/methods/python_methods_input.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_INPUT_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_INPUT_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +// Input related individual python methods for our module. +class PythonMethodsInput { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_INPUT_H_ diff --git a/src/ballistica/python/methods/python_methods_media.cc b/src/ballistica/python/methods/python_methods_media.cc new file mode 100644 index 00000000..bd775568 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_media.cc @@ -0,0 +1,563 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_media.h" + +#include +#if 0 // Cpplint errs w/o this, CLion errs with it. Hard to please everybody. +#include +#endif + +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/media/component/data.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +auto PyGetTexture(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("gettexture"); + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + return Context::current_target().GetTexture(name)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetPackageTexture(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpackagetexture"); + const char* name; + PyObject* package_obj; + static const char* kwlist[] = {"package", "name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os", + const_cast(kwlist), &package_obj, + &name)) { + return nullptr; + } + auto fullname = g_python->ValidatedPackageAssetName(package_obj, name); + return Context::current_target().GetTexture(fullname)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetSound(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getsound"); + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + return Context::current_target().GetSound(name)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetPackageSound(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpackagesound"); + const char* name; + PyObject* package_obj; + static const char* kwlist[] = {"package", "name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os", + const_cast(kwlist), &package_obj, + &name)) { + return nullptr; + } + auto fullname = g_python->ValidatedPackageAssetName(package_obj, name); + return Context::current_target().GetSound(fullname)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetData(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getdata"); + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + return Context::current_target().GetData(name)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetPackageData(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpackagedata"); + const char* name; + PyObject* package_obj; + static const char* kwlist[] = {"package", "name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os", + const_cast(kwlist), &package_obj, + &name)) { + return nullptr; + } + auto fullname = g_python->ValidatedPackageAssetName(package_obj, name); + return Context::current_target().GetData(fullname)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetModel(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getmodel"); + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + return Context::current_target().GetModel(name)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetPackageModel(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpackagemodel"); + const char* name; + PyObject* package_obj; + static const char* kwlist[] = {"package", "name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os", + const_cast(kwlist), &package_obj, + &name)) { + return nullptr; + } + auto fullname = g_python->ValidatedPackageAssetName(package_obj, name); + return Context::current_target().GetTexture(fullname)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetCollideModel(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getcollidemodel"); + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + return Context::current_target().GetCollideModel(name)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyGetPackageCollideModel(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpackagecollidemodel"); + const char* name; + PyObject* package_obj; + static const char* kwlist[] = {"package", "name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "Os", + const_cast(kwlist), &package_obj, + &name)) { + return nullptr; + } + auto fullname = g_python->ValidatedPackageAssetName(package_obj, name); + return Context::current_target().GetCollideModel(fullname)->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyMusicPlayerStop(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("musicplayerstop"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_platform->MusicPlayerStop(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMusicPlayerPlay(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("musicplayerplay"); + PyObject* files_obj; + static const char* kwlist[] = {"files", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &files_obj)) { + return nullptr; + } + g_platform->MusicPlayerPlay(files_obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMusicPlayerSetVolume(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("musicplayersetvolume"); + float volume; + static const char* kwlist[] = {"volume", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "f", + const_cast(kwlist), &volume)) { + return nullptr; + } + g_platform->MusicPlayerSetVolume(volume); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMusicPlayerShutdown(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("musicplayershutdown"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_platform->MusicPlayerShutdown(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyReloadMedia(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("reloadmedia"); + assert(g_graphics_server); + g_graphics_server->PushReloadMediaCall(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetQRCodeTexture(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getqrcodetexture"); + const char* url; + static const char* kwlist[] = {"url", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &url)) { + return nullptr; + } + // FIXME - should add this to context; for now just hard-coded for UI though + if (Context::current().GetUIContext() != nullptr) { + // these textures aren't actually stored in the UI context; + // we just make sure we're here so we're not corrupting a game/session. + return Object::New(url)->NewPyRef(); + } else { + throw Exception("QR-Code textures can only be created in the UI context.", + PyExcType::kContext); + } + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppInit(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappinit"); + g_platform->MacMusicAppInit(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppGetVolume(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappgetvolume"); + return PyLong_FromLong(g_platform->MacMusicAppGetVolume()); + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppSetVolume(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappsetvolume"); + int volume; + static const char* kwlist[] = {"volume", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", + const_cast(kwlist), &volume)) { + return nullptr; + } + g_platform->MacMusicAppSetVolume(volume); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppGetLibrarySource(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappgetlibrarysource"); + g_platform->MacMusicAppGetLibrarySource(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppStop(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappstop"); + g_platform->MacMusicAppStop(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppPlayPlaylist(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappplayplaylist"); + std::string playlist; + PyObject* playlist_obj; + static const char* kwlist[] = {"playlist", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &playlist_obj)) { + return nullptr; + } + playlist = Python::GetPyString(playlist_obj); + if (g_platform->MacMusicAppPlayPlaylist(playlist)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyMacMusicAppGetPlaylists(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("macmusicappgetplaylists"); + PyObject* py_list = PyList_New(0); + std::list playlists = g_platform->MacMusicAppGetPlaylists(); + for (auto&& i : playlists) { + PyObject* str_obj = PyUnicode_FromString(i.c_str()); + PyList_Append(py_list, str_obj); + Py_DECREF(str_obj); + } + return py_list; + BA_PYTHON_CATCH; +} + +auto PyIsOSPlayingMusic(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("isosplayingmusic"); + if (g_platform->IsOSPlayingMusic()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsMedia::methods_def[] = { + {"is_os_playing_music", (PyCFunction)PyIsOSPlayingMusic, + METH_VARARGS | METH_KEYWORDS, + "is_os_playing_music() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Tells whether the OS is currently playing music of some sort.\n" + "\n" + "(Used to determine whether the game should avoid playing its own)"}, + + {"mac_music_app_init", (PyCFunction)PyMacMusicAppInit, + METH_VARARGS | METH_KEYWORDS, + "mac_music_app_init() -> None\n" + "\n" + "(internal)"}, + + {"mac_music_app_get_volume", (PyCFunction)PyMacMusicAppGetVolume, + METH_VARARGS | METH_KEYWORDS, + "mac_music_app_get_volume() -> int\n" + "\n" + "(internal)"}, + + {"mac_music_app_set_volume", (PyCFunction)PyMacMusicAppSetVolume, + METH_VARARGS | METH_KEYWORDS, + "mac_music_app_set_volume(volume: int) -> None\n" + "\n" + "(internal)"}, + + {"mac_music_app_get_library_source", + (PyCFunction)PyMacMusicAppGetLibrarySource, METH_VARARGS | METH_KEYWORDS, + "mac_music_app_get_library_source() -> None\n" + "\n" + "(internal)"}, + + {"mac_music_app_stop", (PyCFunction)PyMacMusicAppStop, + METH_VARARGS | METH_KEYWORDS, + "mac_music_app_stop() -> None\n" + "\n" + "(internal)"}, + + {"mac_music_app_play_playlist", (PyCFunction)PyMacMusicAppPlayPlaylist, + METH_VARARGS | METH_KEYWORDS, + "mac_music_app_play_playlist(playlist: str) -> bool\n" + "\n" + "(internal)"}, + + {"mac_music_app_get_playlists", (PyCFunction)PyMacMusicAppGetPlaylists, + METH_VARARGS | METH_KEYWORDS, + "mac_music_app_get_playlists() -> List[str]\n" + "\n" + "(internal)"}, + + {"get_qrcode_texture", (PyCFunction)PyGetQRCodeTexture, + METH_VARARGS | METH_KEYWORDS, + "get_qrcode_texture(url: str) -> ba.Texture\n" + "\n" + "(internal)"}, + + {"reload_media", PyReloadMedia, METH_VARARGS, + "reload_media() -> None\n" + "\n" + "(internal)\n" + "\n" + "Reload all currently loaded game media; useful for\n" + "development/debugging."}, + + {"music_player_shutdown", (PyCFunction)PyMusicPlayerShutdown, + METH_VARARGS | METH_KEYWORDS, + "music_player_shutdown() -> None\n" + "\n" + "(internal)\n" + "\n" + "Finalizes internal music file playback (for internal use)"}, + + {"music_player_set_volume", (PyCFunction)PyMusicPlayerSetVolume, + METH_VARARGS | METH_KEYWORDS, + "music_player_set_volume(volume: float) -> None\n" + "\n" + "(internal)\n" + "\n" + "Sets internal music player volume (for internal use)"}, + + {"music_player_play", (PyCFunction)PyMusicPlayerPlay, + METH_VARARGS | METH_KEYWORDS, + "music_player_play(files: Any) -> None\n" + "\n" + "(internal)\n" + "\n" + "Starts internal music file playback (for internal use)"}, + + {"music_player_stop", (PyCFunction)PyMusicPlayerStop, + METH_VARARGS | METH_KEYWORDS, + "music_player_stop() -> None\n" + "\n" + "(internal)\n" + "\n" + "Stops internal music file playback (for internal use)"}, + + {"getcollidemodel", (PyCFunction)PyGetCollideModel, + METH_VARARGS | METH_KEYWORDS, + "getcollidemodel(name: str) -> ba.CollideModel\n" + "\n" + "Return a collide-model, loading it if necessary.\n" + "\n" + "Category: Asset Functions\n" + "\n" + "Collide-models are used in physics calculations for such things as\n" + "terrain.\n" + "\n" + "Note that this function returns immediately even if the media has yet\n" + "to be loaded. To avoid hitches, instantiate your media objects in\n" + "advance of when you will be using them, allowing time for them to load\n" + "in the background if necessary."}, + + {"get_package_collide_model", (PyCFunction)PyGetPackageCollideModel, + METH_VARARGS | METH_KEYWORDS, + "get_package_collide_model(package: ba.AssetPackage, name: str)\n" + "-> ba.CollideModel\n" + "\n" + "(internal)\n"}, + + {"getmodel", (PyCFunction)PyGetModel, METH_VARARGS | METH_KEYWORDS, + "getmodel(name: str) -> ba.Model\n" + "\n" + "Return a model, loading it if necessary.\n" + "\n" + "Category: Asset Functions\n" + "\n" + "Note that this function returns immediately even if the media has yet\n" + "to be loaded. To avoid hitches, instantiate your media objects in\n" + "advance of when you will be using them, allowing time for them to load\n" + "in the background if necessary."}, + + {"get_package_model", (PyCFunction)PyGetPackageModel, + METH_VARARGS | METH_KEYWORDS, + "get_package_model(package: ba.AssetPackage, name: str) -> ba.Model\n" + "\n" + "(internal)\n"}, + + {"getsound", (PyCFunction)PyGetSound, METH_VARARGS | METH_KEYWORDS, + "getsound(name: str) -> ba.Sound\n" + "\n" + "Return a sound, loading it if necessary.\n" + "\n" + "Category: Asset Functions\n" + "\n" + "Note that this function returns immediately even if the media has yet\n" + "to be loaded. To avoid hitches, instantiate your media objects in\n" + "advance of when you will be using them, allowing time for them to load\n" + "in the background if necessary."}, + + {"get_package_sound", (PyCFunction)PyGetPackageSound, + METH_VARARGS | METH_KEYWORDS, + "get_package_sound(package: ba.AssetPackage, name: str) -> ba.Sound\n" + "\n" + "(internal).\n"}, + + {"getdata", (PyCFunction)PyGetData, METH_VARARGS | METH_KEYWORDS, + "getdata(name: str) -> ba.Data\n" + "\n" + "Return a data, loading it if necessary.\n" + "\n" + "Category: Asset Functions\n" + "\n" + "Note that this function returns immediately even if the media has yet\n" + "to be loaded. To avoid hitches, instantiate your media objects in\n" + "advance of when you will be using them, allowing time for them to load\n" + "in the background if necessary."}, + + {"get_package_data", (PyCFunction)PyGetPackageData, + METH_VARARGS | METH_KEYWORDS, + "get_package_data(package: ba.AssetPackage, name: str) -> ba.Data\n" + "\n" + "(internal).\n"}, + + {"gettexture", (PyCFunction)PyGetTexture, METH_VARARGS | METH_KEYWORDS, + "gettexture(name: str) -> ba.Texture\n" + "\n" + "Return a texture, loading it if necessary.\n" + "\n" + "Category: Asset Functions\n" + "\n" + "Note that this function returns immediately even if the media has yet\n" + "to be loaded. To avoid hitches, instantiate your media objects in\n" + "advance of when you will be using them, allowing time for them to load\n" + "in the background if necessary."}, + + {"get_package_texture", (PyCFunction)PyGetPackageTexture, + METH_VARARGS | METH_KEYWORDS, + "get_package_texture(package: ba.AssetPackage, name: str) -> ba.Texture\n" + "\n" + "(internal)"}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_media.h b/src/ballistica/python/methods/python_methods_media.h new file mode 100644 index 00000000..69bc5f48 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_media.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_MEDIA_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_MEDIA_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// Media related individual python methods for our module. +class PythonMethodsMedia { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_MEDIA_H_ diff --git a/src/ballistica/python/methods/python_methods_networking.cc b/src/ballistica/python/methods/python_methods_networking.cc new file mode 100644 index 00000000..2d5cb1eb --- /dev/null +++ b/src/ballistica/python/methods/python_methods_networking.cc @@ -0,0 +1,610 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_networking.h" + +#include +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/game/connection/connection_to_host.h" +#include "ballistica/game/game.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/networking/master_server_config.h" +#include "ballistica/networking/network_reader.h" +#include "ballistica/networking/networking.h" +#include "ballistica/networking/sockaddr.h" +#include "ballistica/networking/telnet_server.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +auto PyGetPublicPartyEnabled(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpublicpartyenabled"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) + return nullptr; + assert(g_python); + if (g_game->public_party_enabled()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PySetPublicPartyEnabled(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("setpublicpartyenabled"); + int enable; + static const char* kwlist[] = {"enabled", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &enable)) { + return nullptr; + } + assert(g_python); + g_game->SetPublicPartyEnabled(static_cast(enable)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetPublicPartyName(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("setpublicpartyname"); + PyObject* name_obj; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &name_obj)) { + return nullptr; + } + std::string name = Python::GetPyString(name_obj); + assert(g_python); + g_game->SetPublicPartyName(name); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetPublicPartyStatsURL(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("setpublicpartystatsurl"); + PyObject* url_obj; + static const char* kwlist[] = {"url", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &url_obj)) { + return nullptr; + } + // The call expects an empty string for the no-url option. + std::string url = (url_obj == Py_None) ? "" : Python::GetPyString(url_obj); + assert(g_python); + g_game->SetPublicPartyStatsURL(url); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetPublicPartyMaxSize(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("getpublicpartymaxsize"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + assert(g_python); + return PyLong_FromLong(g_game->public_party_max_size()); + BA_PYTHON_CATCH; +} + +auto PySetPublicPartyMaxSize(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("setpublicpartymaxsize"); + int max_size; + static const char* kwlist[] = {"max_size", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", + const_cast(kwlist), &max_size)) { + return nullptr; + } + assert(g_python); + g_game->SetPublicPartyMaxSize(max_size); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetAuthenticateClients(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_authenticate_clients"); + int enable; + static const char* kwlist[] = {"enable", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &enable)) { + return nullptr; + } + assert(g_game); + g_game->set_require_client_authentication(static_cast(enable)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetAdmins(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_admins"); + PyObject* admins_obj; + static const char* kwlist[] = {"admins", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &admins_obj)) { + return nullptr; + } + assert(g_game); + + auto admins = Python::GetPyStrings(admins_obj); + std::set adminset; + for (auto&& admin : admins) { + adminset.insert(admin); + } + g_game->set_admin_public_ids(adminset); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetEnableDefaultKickVoting(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_enable_default_kick_voting"); + int enable; + static const char* kwlist[] = {"enable", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &enable)) { + return nullptr; + } + assert(g_game); + g_game->set_kick_voting_enabled(static_cast(enable)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyConnectToParty(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("connect_to_party"); + std::string address; + PyObject* address_obj; + int port = kDefaultPort; + + // Whether we should print standard 'connecting...' and 'party full..' + // messages when false, only odd errors such as version incompatibility will + // be printed and most connection attempts will be silent todo: could + // generalize this to pass all results to a callback instead + int print_progress = 1; + static const char* kwlist[] = {"address", "port", "print_progress", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|ip", + const_cast(kwlist), &address_obj, + &port, &print_progress)) { + return nullptr; + } + address = Python::GetPyString(address_obj); + + // Disallow in headless build (people were using this for spam-bots). + + if (HeadlessMode()) { + throw Exception("Not available in headless mode."); + } + + SockAddr s; + try { + s = SockAddr(address, port); + + // HACK: CLion currently flags our catch clause as unreachable even + // though SockAddr constructor can throw exceptions. Work around that here. + if (explicit_bool(false)) { + throw Exception(); + } + } catch (const std::exception&) { + ScreenMessage(g_game->GetResourceString("invalidAddressErrorText"), + {1, 0, 0}); + Py_RETURN_NONE; + } + g_game->PushHostConnectedUDPCall(s, static_cast(print_progress)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyAcceptPartyInvitation(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("accept_party_invitation"); + const char* invite_id; + static const char* kwlist[] = {"invite_id", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &invite_id)) { + return nullptr; + } + g_platform->AndroidGPGSPartyInviteAccept(invite_id); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetGooglePlayPartyClientCount(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_google_play_party_client_count"); + BA_PRECONDITION(InGameThread()); +#if BA_GOOGLE_BUILD + return PyLong_FromLong(g_game->GetGooglePlayClientCount()); +#else + return PyLong_FromLong(0); +#endif + BA_PYTHON_CATCH; +} + +auto PyClientInfoQueryResponse(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("client_info_query_response"); + const char* token; + PyObject* response_obj; + static const char* kwlist[] = {"token", "response", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "sO", + const_cast(kwlist), &token, + &response_obj)) { + return nullptr; + } + g_game->SetClientInfoFromMasterServer(token, response_obj); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetConnectionToHostInfo(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_connection_to_host_info"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + ConnectionToHost* hc = g_game->connection_to_host(); + if (hc) { + return Py_BuildValue("{sssi}", "name", hc->party_name().c_str(), + "build_number", hc->build_number()); + } else { + return Py_BuildValue("{}"); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyDisconnectFromHost(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("disconnect_from_host"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_game->PushDisconnectFromHostCall(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyDisconnectClient(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("disconnect_client"); + int client_id; + int ban_time = 300; // Old default before we exposed this. + static const char* kwlist[] = {"client_id", "ban_time", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|i", + const_cast(kwlist), &client_id, + &ban_time)) { + return nullptr; + } + bool kickable = g_game->DisconnectClient(client_id, ban_time); + if (kickable) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyGetGamePort(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_game_port"); + int port = 0; + if (g_network_reader != nullptr) { + // hmmm; we're just fetching the ipv4 port here; + // 6 could be different.... + port = g_network_reader->port4(); + } + return Py_BuildValue("i", port); + BA_PYTHON_CATCH; +} + +auto PyGetMasterServerAddress(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_master_server_address"); + int source = -1; // use default.. + if (!PyArg_ParseTuple(args, "|i", &source)) { + return nullptr; + } + // source -1 implies to use current one + if (source == -1) { + source = g_app_globals->master_server_source; + } + const char* addr; + if (source == 0) { + addr = BA_MASTER_SERVER_DEFAULT_ADDR; + } else if (source == 1) { + addr = BA_MASTER_SERVER_FALLBACK_ADDR; + } else { + BA_LOG_ONCE("Error: Got unexpected source: " + std::to_string(source) + + "."); + addr = BA_MASTER_SERVER_FALLBACK_ADDR; + } + return PyUnicode_FromString(addr); + BA_PYTHON_CATCH; +} + +auto PySetMasterServerSource(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_master_server_source"); + int source; + if (!PyArg_ParseTuple(args, "i", &source)) return nullptr; + if (source != 0 && source != 1) { + BA_LOG_ONCE("Error: Invalid server source: " + std::to_string(source) + + "."); + source = 1; + } + g_app_globals->master_server_source = source; + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetTelnetAccessEnabled(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_telnet_access_enabled"); + assert(InGameThread()); + int enable; + static const char* kwlist[] = {"enable", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &enable)) { + return nullptr; + } + if (g_app_globals->telnet_server) { + g_app_globals->telnet_server->SetAccessEnabled(static_cast(enable)); + } else { + throw Exception("Telnet server not enabled."); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyHostScanCycle(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("host_scan_cycle"); + g_networking->HostScanCycle(); + std::vector results = + g_networking->GetScanResults(); + PyObject* py_list = PyList_New(0); + for (auto&& i : results) { + PyList_Append(py_list, Py_BuildValue("{ssss}", "display_string", + i.display_string.c_str(), "address", + i.address.c_str())); + } + return py_list; + BA_PYTHON_CATCH; +} + +auto PyEndHostScanning(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("end_host_scanning"); + g_networking->EndHostScanning(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyHaveConnectedClients(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("have_connected_clients"); + if (g_game->GetConnectedClientCount() > 0) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyInvitePlayers(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("invite_players"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_platform->AndroidGPGSPartyInvitePlayers(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsNetworking::methods_def[] = { + {"invite_players", (PyCFunction)PyInvitePlayers, + METH_VARARGS | METH_KEYWORDS, + "invite_players() -> None\n" + "\n" + "(internal)" + "\n" + "Category: General Utility Functions"}, + + {"have_connected_clients", (PyCFunction)PyHaveConnectedClients, + METH_VARARGS | METH_KEYWORDS, + "have_connected_clients() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"end_host_scanning", (PyCFunction)PyEndHostScanning, + METH_VARARGS | METH_KEYWORDS, + "end_host_scanning() -> None\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"host_scan_cycle", (PyCFunction)PyHostScanCycle, + METH_VARARGS | METH_KEYWORDS, + "host_scan_cycle() -> list\n" + "\n" + "(internal)"}, + + {"set_telnet_access_enabled", (PyCFunction)PySetTelnetAccessEnabled, + METH_VARARGS | METH_KEYWORDS, + "set_telnet_access_enabled(enable: bool)\n" + " -> None\n" + "\n" + "(internal)"}, + + {"set_master_server_source", PySetMasterServerSource, METH_VARARGS, + "set_master_server_source(source: int) -> None\n" + "\n" + "(internal)"}, + + {"get_master_server_address", PyGetMasterServerAddress, METH_VARARGS, + "get_master_server_address(source: int = -1) -> str\n" + "\n" + "(internal)\n" + "\n" + "Return the address of the master server."}, + + {"get_game_port", PyGetGamePort, METH_VARARGS, + "get_game_port() -> int\n" + "\n" + "(internal)\n" + "\n" + "Return the port ballistica is hosting on."}, + + {"disconnect_from_host", (PyCFunction)PyDisconnectFromHost, + METH_VARARGS | METH_KEYWORDS, + "disconnect_from_host() -> None\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"disconnect_client", (PyCFunction)PyDisconnectClient, + METH_VARARGS | METH_KEYWORDS, + "disconnect_client(client_id: int, ban_time: int = 300) -> bool\n" + "\n" + "(internal)"}, + + {"get_connection_to_host_info", (PyCFunction)PyGetConnectionToHostInfo, + METH_VARARGS | METH_KEYWORDS, + "get_connection_to_host_info() -> dict\n" + "\n" + "(internal)"}, + + {"client_info_query_response", (PyCFunction)PyClientInfoQueryResponse, + METH_VARARGS | METH_KEYWORDS, + "client_info_query_response(token: str, response: Any) -> None\n" + "\n" + "(internal)"}, + + {"get_google_play_party_client_count", + (PyCFunction)PyGetGooglePlayPartyClientCount, METH_VARARGS | METH_KEYWORDS, + "get_google_play_party_client_count() -> int\n" + "\n" + "(internal)"}, + + {"accept_party_invitation", (PyCFunction)PyAcceptPartyInvitation, + METH_VARARGS | METH_KEYWORDS, + "accept_party_invitation(invite_id: str) -> None\n" + "\n" + "(internal)"}, + + {"connect_to_party", (PyCFunction)PyConnectToParty, + METH_VARARGS | METH_KEYWORDS, + "connect_to_party(address: str, port: int = None,\n" + " print_progress: bool = True) -> None\n" + "\n" + "(internal)"}, + + {"set_authenticate_clients", (PyCFunction)PySetAuthenticateClients, + METH_VARARGS | METH_KEYWORDS, + "set_authenticate_clients(enable: bool) -> None\n" + "\n" + "(internal)"}, + + {"set_admins", (PyCFunction)PySetAdmins, METH_VARARGS | METH_KEYWORDS, + "set_admins(admins: List[str]) -> None\n" + "\n" + "(internal)"}, + + {"set_enable_default_kick_voting", + (PyCFunction)PySetEnableDefaultKickVoting, METH_VARARGS | METH_KEYWORDS, + "set_enable_default_kick_voting(enable: bool) -> None\n" + "\n" + "(internal)"}, + + {"set_public_party_max_size", (PyCFunction)PySetPublicPartyMaxSize, + METH_VARARGS | METH_KEYWORDS, + "set_public_party_max_size(max_size: int) -> None\n" + "\n" + "(internal)"}, + + {"get_public_party_max_size", (PyCFunction)PyGetPublicPartyMaxSize, + METH_VARARGS | METH_KEYWORDS, + "get_public_party_max_size() -> int\n" + "\n" + "(internal)"}, + + {"set_public_party_stats_url", (PyCFunction)PySetPublicPartyStatsURL, + METH_VARARGS | METH_KEYWORDS, + "set_public_party_stats_url(url: Optional[str]) -> None\n" + "\n" + "(internal)"}, + + {"set_public_party_name", (PyCFunction)PySetPublicPartyName, + METH_VARARGS | METH_KEYWORDS, + "set_public_party_name(name: str) -> None\n" + "\n" + "(internal)"}, + + {"set_public_party_enabled", (PyCFunction)PySetPublicPartyEnabled, + METH_VARARGS | METH_KEYWORDS, + "set_public_party_enabled(enabled: bool) -> None\n" + "\n" + "(internal)"}, + + {"get_public_party_enabled", (PyCFunction)PyGetPublicPartyEnabled, + METH_VARARGS | METH_KEYWORDS, + "get_public_party_enabled() -> bool\n" + "\n" + "(internal)"}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_networking.h b/src/ballistica/python/methods/python_methods_networking.h new file mode 100644 index 00000000..bb6a2c42 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_networking.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_NETWORKING_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_NETWORKING_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// Networking related individual python methods for our module. +class PythonMethodsNetworking { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_NETWORKING_H_ diff --git a/src/ballistica/python/methods/python_methods_system.cc b/src/ballistica/python/methods/python_methods_system.cc new file mode 100644 index 00000000..89691355 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_system.cc @@ -0,0 +1,1031 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_system.h" + +#include +#include +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_config.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/game/session/replay_client_session.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/input/input.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/media/media.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call_runnable.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +// Ignore signed bitwise warnings; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" +#pragma ide diagnostic ignored "RedundantCast" + +auto PyIsRunningOnOuya(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("is_running_on_ouya"); + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PySetUpSigInt(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_up_sig_int"); + if (g_app) { + g_app->PushInterruptSignalSetupCall(); + } else { + Log("SigInt handler called before g_app exists."); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIsRunningOnFireTV(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("is_running_on_fire_tv"); + if (g_platform->IsRunningOnFireTV()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyHavePermission(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("have_permission"); + BA_PRECONDITION(InGameThread()); + Permission permission; + PyObject* permission_obj; + static const char* kwlist[] = {"permission", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O", const_cast(kwlist), &permission_obj)) { + return nullptr; + } + + permission = Python::GetPyEnum_Permission(permission_obj); + + if (g_platform->HavePermission(permission)) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyRequestPermission(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("request_permission"); + BA_PRECONDITION(InGameThread()); + Permission permission; + PyObject* permission_obj; + static const char* kwlist[] = {"permission", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O", const_cast(kwlist), &permission_obj)) { + return nullptr; + } + + permission = Python::GetPyEnum_Permission(permission_obj); + g_platform->RequestPermission(permission); + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyInGameThread(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("in_game_thread"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + if (InGameThread()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PySetThreadName(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_thread_name"); + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + g_platform->SetCurrentThreadName(name); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetThreadName(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_thread_name"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + return PyUnicode_FromString(GetCurrentThreadName().c_str()); + BA_PYTHON_CATCH; +} + +// returns an extra hash value that can be incorporated into security checks; +// this contains things like whether console commands have been run, etc. +auto PyExtraHashValue(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("extra_hash_value"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + const char* h = (g_app_globals->user_ran_commands ? "cjief3l" : "wofocj8"); + return PyUnicode_FromString(h); + BA_PYTHON_CATCH; +} + +auto PySetHaveMods(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_have_mods"); + int have_mods; + if (!PyArg_ParseTuple(args, "p", &have_mods)) return nullptr; + g_app_globals->have_mods = static_cast(have_mods); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetIdleTime(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_idle_time"); + return PyLong_FromLong(static_cast_check_fit( // NOLINT + g_input ? g_input->GetIdleTime() : 0)); + BA_PYTHON_CATCH; +} + +auto PyHasUserRunCommands(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("has_user_run_commands"); + if (g_app_globals->user_ran_commands) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyHasUserMods(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("has_user_mods"); + if (g_app_globals->have_mods) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyValueTest(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("value_test"); + const char* arg; + double change = 0.0f; + double absolute = 0.0f; + bool have_change = false; + bool have_absolute = false; + PyObject* change_obj = Py_None; + PyObject* absolute_obj = Py_None; + static const char* kwlist[] = {"arg", "change", "absolute", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|OO", + const_cast(kwlist), &arg, + &change_obj, &absolute_obj)) { + return nullptr; + } + if (change_obj != Py_None) { + if (absolute_obj != Py_None) { + throw Exception("Can't provide both a change and absolute"); + } + have_change = true; + change = Python::GetPyDouble(change_obj); + } + if (absolute_obj != Py_None) { + have_absolute = true; + absolute = Python::GetPyDouble(absolute_obj); + } + double return_val = 0.0f; + if (!strcmp(arg, "bufferTime")) { + if (have_change) { + g_app_globals->buffer_time += static_cast(change); + } + if (have_absolute) { + g_app_globals->buffer_time = static_cast(absolute); + } + g_app_globals->buffer_time = std::max(0, g_app_globals->buffer_time); + return_val = g_app_globals->buffer_time; + } else if (!strcmp(arg, "delaySampling")) { + if (have_change) { + g_app_globals->delay_samples += static_cast(change); + } + if (have_absolute) { + g_app_globals->buffer_time = static_cast(absolute); + } + g_app_globals->delay_samples = std::max(1, g_app_globals->delay_samples); + return_val = g_app_globals->delay_samples; + } else if (!strcmp(arg, "dynamicsSyncTime")) { + if (have_change) { + g_app_globals->dynamics_sync_time += static_cast(change); + } + if (have_absolute) { + g_app_globals->dynamics_sync_time = static_cast(absolute); + } + g_app_globals->dynamics_sync_time = + std::max(0, g_app_globals->dynamics_sync_time); + return_val = g_app_globals->dynamics_sync_time; + } else if (!strcmp(arg, "showNetInfo")) { + if (have_change && change > 0.5f) { + g_graphics->set_show_net_info(true); + } + if (have_change && change < -0.5f) { + g_graphics->set_show_net_info(false); + } + if (have_absolute) { + g_graphics->set_show_net_info(static_cast(absolute)); + } + return_val = g_graphics->show_net_info(); + } else if (!strcmp(arg, "allowCameraMovement")) { + Camera* camera = g_graphics->camera(); + if (camera) { + if (have_change && change > 0.5f) { + camera->set_lock_panning(false); + } + if (have_change && change < -0.5f) { + camera->set_lock_panning(true); + } + if (have_absolute) { + camera->set_lock_panning(!static_cast(absolute)); + } + return_val = !camera->lock_panning(); + } + } else if (!strcmp(arg, "cameraPanSpeedScale")) { + Camera* camera = g_graphics->camera(); + if (camera) { + double val = camera->pan_speed_scale(); + if (have_change) { + camera->set_pan_speed_scale(static_cast(val + change)); + } + if (have_absolute) { + camera->set_pan_speed_scale(static_cast(absolute)); + } + if (camera->pan_speed_scale() < 0) { + camera->set_pan_speed_scale(0); + } + return_val = camera->pan_speed_scale(); + } + } else { + auto handled = + g_graphics->ValueTest(arg, have_absolute ? &absolute : nullptr, + have_change ? &change : nullptr, &return_val); + if (!handled) { + ScreenMessage("invalid arg: " + std::string(arg)); + } + } + + return PyFloat_FromDouble(return_val); + + BA_PYTHON_CATCH; +} + +auto PyDebugPrintPyErr(PyObject* self, PyObject* args) -> PyObject* { + Platform::SetLastPyCall("debug_print_py_err"); + if (PyErr_Occurred()) { + // we pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks + // (nodes, actors existing after their games have ended) + PyErr_PrintEx(0); + PyErr_Clear(); + } + Py_RETURN_NONE; +} + +auto PyPrintContext(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("print_context"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + Python::LogContextAuto(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyPrintLoadInfo(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("print_load_info"); + g_media->PrintLoadInfo(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetReplaysDir(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_replays_dir"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + return PyUnicode_FromString(g_platform->GetReplaysDir().c_str()); + BA_PYTHON_CATCH; +} + +auto PyGetAppConfigDefaultValue(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_app_config_default_value"); + const char* key = ""; + static const char* kwlist[] = {"key", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &key)) { + return nullptr; + } + const AppConfig::Entry* entry = g_app_config->GetEntry(key); + if (entry == nullptr) { + throw Exception("Invalid config value '" + std::string(key) + "'", + PyExcType::kValue); + } + switch (entry->GetType()) { + case AppConfig::Entry::Type::kString: + return PyUnicode_FromString(entry->DefaultStringValue().c_str()); + case AppConfig::Entry::Type::kInt: + return PyLong_FromLong(entry->DefaultIntValue()); + case AppConfig::Entry::Type::kFloat: + return PyFloat_FromDouble(entry->DefaultFloatValue()); + case AppConfig::Entry::Type::kBool: + if (entry->DefaultBoolValue()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + default: + throw Exception(PyExcType::kValue); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyAppConfigGetBuiltinKeys(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("app_config_get_builtin_keys"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + PythonRef list(PyList_New(0), PythonRef::kSteal); + for (auto&& i : g_app_config->entries_by_name()) { + PyList_Append(list.get(), PyUnicode_FromString(i.first.c_str())); + } + return list.HandOver(); + BA_PYTHON_CATCH; +} + +auto PyResolveAppConfigValue(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("resolve_app_config_value"); + + const char* key; + static const char* kwlist[] = {"key", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &key)) { + return nullptr; + } + auto entry = g_app_config->GetEntry(key); + if (entry == nullptr) { + throw Exception("Invalid config value '" + std::string(key) + "'.", + PyExcType::kValue); + } + switch (entry->GetType()) { + case AppConfig::Entry::Type::kString: + return PyUnicode_FromString(entry->StringValue().c_str()); + case AppConfig::Entry::Type::kInt: + return PyLong_FromLong(entry->IntValue()); + case AppConfig::Entry::Type::kFloat: + return PyFloat_FromDouble(entry->FloatValue()); + case AppConfig::Entry::Type::kBool: + if (entry->BoolValue()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + + default: + throw Exception(PyExcType::kValue); + } + BA_PYTHON_CATCH; +} + +auto PyGetLowLevelConfigValue(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_low_level_config_value"); + const char* key; + int default_value; + static const char* kwlist[] = {"key", "default_value", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "si", const_cast(kwlist), &key, &default_value)) + return nullptr; + return PyLong_FromLong( + g_platform->GetLowLevelConfigValue(key, default_value)); + BA_PYTHON_CATCH; +} + +auto PySetLowLevelConfigValue(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_low_level_config_value"); + const char* key; + int value; + static const char* kwlist[] = {"key", "value", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "si", + const_cast(kwlist), &key, &value)) + return nullptr; + g_platform->SetLowLevelConfigValue(key, value); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetPlatformMiscReadVals(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_platform_misc_read_vals"); + PyObject* vals_obj; + static const char* kwlist[] = {"mode", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", + const_cast(kwlist), &vals_obj)) { + return nullptr; + } + std::string vals = Python::GetPyString(vals_obj); + g_platform->SetPlatformMiscReadVals(vals); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetLogFilePath(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_log_file_path"); + std::string config_dir = g_platform->GetConfigDirectory(); + std::string logpath = config_dir + BA_DIRSLASH + "log.json"; + return PyUnicode_FromString(logpath.c_str()); + BA_PYTHON_CATCH; +} + +auto PyIsLogFull(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("is_log_full"); + if (g_app_globals->log_full) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyGetLog(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("get_log"); + std::string log_fin; + { + std::lock_guard lock(g_app_globals->log_mutex); + log_fin = g_app_globals->log; + } + // we want to use something with error handling here since the last + // bit of this string could be truncated utf8 chars.. + return PyUnicode_FromString( + Utils::GetValidUTF8(log_fin.c_str(), "_glg1").c_str()); + BA_PYTHON_CATCH; +} + +auto PyMarkLogSent(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("mark_log_sent"); + // this way we won't try to send it at shutdown time and whatnot + g_app_globals->put_log = true; + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIncrementAnalyticsCount(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("increment_analytics_count"); + const char* name; + int increment = 1; + static const char* kwlist[] = {"name", "increment", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "s|p", const_cast(kwlist), &name, &increment)) { + return nullptr; + } + g_platform->IncrementAnalyticsCount(name, increment); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIncrementAnalyticsCountRaw(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("increment_analytics_count_raw"); + const char* name; + int increment = 1; + static const char* kwlist[] = {"name", "increment", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "s|i", const_cast(kwlist), &name, &increment)) { + return nullptr; + } + g_platform->IncrementAnalyticsCountRaw(name, increment); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIncrementAnalyticsCountRaw2(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("increment_analytics_count_raw2"); + const char* name; + int uses_increment = 1; + int increment = 1; + static const char* kwlist[] = {"name", "uses_increment", "increment", + nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|ii", + const_cast(kwlist), &name, + &uses_increment, &increment)) { + return nullptr; + } + g_platform->IncrementAnalyticsCountRaw2(name, uses_increment, increment); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySubmitAnalyticsCounts(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("submit_analytics_counts"); + g_platform->SubmitAnalyticsCounts(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetAnalyticsScreen(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_analytics_screen"); + const char* screen; + static const char* kwlist[] = {"screen", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &screen)) { + return nullptr; + } + g_platform->SetAnalyticsScreen(screen); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetInternalLanguageKeys(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_internal_language_keys"); + PyObject* list_obj; + PyObject* random_names_list_obj; + if (!PyArg_ParseTuple(args, "OO", &list_obj, &random_names_list_obj)) { + return nullptr; + } + BA_PRECONDITION(PyList_Check(list_obj)); + BA_PRECONDITION(PyList_Check(random_names_list_obj)); + std::map language; + int size = static_cast(PyList_GET_SIZE(list_obj)); + for (int i = 0; i < size; i++) { + PyObject* entry = PyList_GET_ITEM(list_obj, i); + if (!PyTuple_Check(entry) || PyTuple_GET_SIZE(entry) != 2 + || !PyUnicode_Check(PyTuple_GET_ITEM(entry, 0)) + || !PyUnicode_Check(PyTuple_GET_ITEM(entry, 1))) { + throw Exception("Invalid root language data."); + } + language[PyUnicode_AsUTF8(PyTuple_GET_ITEM(entry, 0))] = + PyUnicode_AsUTF8(PyTuple_GET_ITEM(entry, 1)); + } + size = static_cast(PyList_GET_SIZE(random_names_list_obj)); + std::list random_names; + for (int i = 0; i < size; i++) { + PyObject* entry = PyList_GET_ITEM(random_names_list_obj, i); + if (!PyUnicode_Check(entry)) { + throw Exception("Got non-string in random name list.", PyExcType::kType); + } + random_names.emplace_back(PyUnicode_AsUTF8(entry)); + } + Utils::SetRandomNameList(random_names); + assert(g_game); + g_game->SetLanguageKeys(language); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIsOuyaBuild(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("is_ouya_builds"); + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyAndroidMediaScanFile(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("android_media_scan_file"); + const char* file_name; + static const char* kwlist[] = {"file_name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &file_name)) { + return nullptr; + } + g_platform->AndroidRefreshFile(file_name); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyAndroidGetExternalStoragePath(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("android_get_external_storage_path"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } +#if BA_OSTYPE_ANDROID + std::string path = g_platform->GetExternalStoragePath(); + if (path.empty()) { + Py_RETURN_NONE; + } else { + assert(Utils::IsValidUTF8(path)); + return PyUnicode_FromString(path.c_str()); + } +#else // BA_OSTYPE_ANDROID + throw Exception("Only valid on android."); +#endif // BA_OSTYPE_ANDROID + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyAndroidShowWifiSettings(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("android_show_wifi_settings"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_platform->AndroidShowWifiSettings(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyPrintObjects(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("print_objects"); + Object::PrintObjects(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyDoOnce(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("do_once"); + if (g_python->DoOnce()) { + Py_RETURN_TRUE; + } + Py_RETURN_FALSE; + BA_PYTHON_CATCH; +} + +auto PyApp(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("app"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + return g_python->obj(Python::ObjID::kApp).NewRef(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsSystem::methods_def[] = { + {"printobjects", (PyCFunction)PyPrintObjects, METH_VARARGS | METH_KEYWORDS, + "printobjects() -> None\n" + "\n" + "Print debugging info about game objects.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "This call only functions in debug builds of the game.\n" + "It prints various info about the current object count, etc."}, + + {"do_once", (PyCFunction)PyDoOnce, METH_VARARGS | METH_KEYWORDS, + "do_once() -> bool\n" + "\n" + "Return whether this is the first time running a line of code.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "This is used by 'print_once()' type calls to keep from overflowing\n" + "logs. The call functions by registering the filename and line where\n" + "The call is made from. Returns True if this location has not been\n" + "registered already, and False if it has.\n" + "\n" + "# Example: this print will only fire for the first loop iteration:\n" + "for i in range(10):\n" + " if ba.do_once():\n" + " print('Hello once from loop!')"}, + + {"_app", (PyCFunction)PyApp, METH_VARARGS | METH_KEYWORDS, + "_app() -> ba.App\n" + "\n" + "(internal)"}, + + {"android_media_scan_file", (PyCFunction)PyAndroidMediaScanFile, + METH_VARARGS | METH_KEYWORDS, + "android_media_scan_file(file_name: str) -> None\n" + "\n" + "(internal)\n" + "\n" + "Refreshes Android MTP Index for a file; use this to get file\n" + "modifications to be reflected in Android File Transfer."}, + + {"android_get_external_storage_path", + (PyCFunction)PyAndroidGetExternalStoragePath, METH_VARARGS | METH_KEYWORDS, + "android_get_external_storage_path() -> str\n" + "\n" + "(internal)\n" + "\n" + "Returns the android external storage path, or None if there is none on\n" + "this device"}, + + {"android_show_wifi_settings", (PyCFunction)PyAndroidShowWifiSettings, + METH_VARARGS | METH_KEYWORDS, + "android_show_wifi_settings() -> None\n" + "\n" + "(internal)"}, + + {"is_ouya_build", PyIsOuyaBuild, METH_VARARGS, + "is_ouya_build() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Returns whether we're running the ouya-specific version"}, + + {"set_internal_language_keys", PySetInternalLanguageKeys, METH_VARARGS, + "set_internal_language_keys(listobj: List[Tuple[str, str]],\n" + " random_names_list: List[Tuple[str, str]]) -> None\n" + "\n" + "(internal)"}, + + {"set_analytics_screen", (PyCFunction)PySetAnalyticsScreen, + METH_VARARGS | METH_KEYWORDS, + "set_analytics_screen(screen: str) -> None\n" + "\n" + "Used for analytics to see where in the app players spend their time.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "Generally called when opening a new window or entering some UI.\n" + "'screen' should be a string description of an app location\n" + "('Main Menu', etc.)"}, + + {"submit_analytics_counts", (PyCFunction)PySubmitAnalyticsCounts, + METH_VARARGS | METH_KEYWORDS, + "submit_analytics_counts() -> None\n" + "\n" + "(internal)"}, + + {"increment_analytics_count_raw_2", + (PyCFunction)PyIncrementAnalyticsCountRaw2, METH_VARARGS | METH_KEYWORDS, + "increment_analytics_count_raw_2(name: str,\n" + " uses_increment: bool = True, increment: int = 1) -> None\n" + "\n" + "(internal)"}, + + {"increment_analytics_counts_raw", + (PyCFunction)PyIncrementAnalyticsCountRaw, METH_VARARGS | METH_KEYWORDS, + "increment_analytics_counts_raw(name: str, increment: int = 1) -> None\n" + "\n" + "(internal)"}, + + {"increment_analytics_count", (PyCFunction)PyIncrementAnalyticsCount, + METH_VARARGS | METH_KEYWORDS, + "increment_analytics_count(name: str, increment: int = 1) -> None\n" + "\n" + "(internal)"}, + + {"mark_log_sent", (PyCFunction)PyMarkLogSent, METH_VARARGS | METH_KEYWORDS, + "mark_log_sent() -> None\n" + "\n" + "(internal)"}, + + {"getlog", (PyCFunction)PyGetLog, METH_VARARGS | METH_KEYWORDS, + "getlog() -> str\n" + "\n" + "(internal)"}, + + {"is_log_full", PyIsLogFull, METH_VARARGS, + "is_log_full() -> bool\n" + "\n" + "(internal)"}, + + {"get_log_file_path", PyGetLogFilePath, METH_VARARGS, + "get_log_file_path() -> str\n" + "\n" + "(internal)\n" + "\n" + "Return the path to the app log file."}, + + {"set_platform_misc_read_vals", (PyCFunction)PySetPlatformMiscReadVals, + METH_VARARGS | METH_KEYWORDS, + "set_platform_misc_read_vals(mode: str) -> None\n" + "\n" + "(internal)"}, + + {"set_low_level_config_value", (PyCFunction)PySetLowLevelConfigValue, + METH_VARARGS | METH_KEYWORDS, + "set_low_level_config_value(key: str, value: int) -> None\n" + "\n" + "(internal)"}, + + {"get_low_level_config_value", (PyCFunction)PyGetLowLevelConfigValue, + METH_VARARGS | METH_KEYWORDS, + "get_low_level_config_value(key: str, default_value: int) -> int\n" + "\n" + "(internal)"}, + + {"resolve_appconfig_value", (PyCFunction)PyResolveAppConfigValue, + METH_VARARGS | METH_KEYWORDS, + "resolve_appconfig_value(key: str) -> Any\n" + "\n" + "(internal)"}, + + {"get_appconfig_default_value", (PyCFunction)PyGetAppConfigDefaultValue, + METH_VARARGS | METH_KEYWORDS, + "get_appconfig_default_value(key: str) -> Any\n" + "\n" + "(internal)"}, + + {"get_appconfig_builtin_keys", (PyCFunction)PyAppConfigGetBuiltinKeys, + METH_VARARGS | METH_KEYWORDS, + "get_appconfig_builtin_keys() -> List[str]\n" + "\n" + "(internal)"}, + + {"get_replays_dir", (PyCFunction)PyGetReplaysDir, + METH_VARARGS | METH_KEYWORDS, + "get_replays_dir() -> str\n" + "\n" + "(internal)"}, + + {"print_load_info", (PyCFunction)PyPrintLoadInfo, + METH_VARARGS | METH_KEYWORDS, + "print_load_info() -> None\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"print_context", (PyCFunction)PyPrintContext, METH_VARARGS | METH_KEYWORDS, + "print_context() -> None\n" + "\n" + "(internal)\n" + "\n" + "Prints info about the current context state; for debugging.\n"}, + + {"debug_print_py_err", PyDebugPrintPyErr, METH_VARARGS, + "debug_print_py_err() -> None\n" + "\n" + "(internal)\n" + "\n" + "Debugging func for tracking leaked Python errors in the C++ layer.."}, + + {"value_test", (PyCFunction)PyValueTest, METH_VARARGS | METH_KEYWORDS, + "value_test(arg: str, change: float = None, absolute: float = None)\n" + " -> float\n" + "\n" + "(internal)"}, + + {"has_user_mods", PyHasUserMods, METH_VARARGS, + "has_user_mods() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Returns whether the system varies from default configuration\n" + "(by user mods, etc)"}, + + {"has_user_run_commands", PyHasUserRunCommands, METH_VARARGS, + "has_user_run_commands() -> bool\n" + "\n" + "(internal)"}, + + {"get_idle_time", PyGetIdleTime, METH_VARARGS, + "get_idle_time() -> int\n" + "\n" + "(internal)\n" + "\n" + "Returns the amount of time since any game input has been processed"}, + + {"set_have_mods", PySetHaveMods, METH_VARARGS, + "set_have_mods(have_mods: bool) -> None\n" + "\n" + "(internal)"}, + + {"ehv", (PyCFunction)PyExtraHashValue, METH_VARARGS | METH_KEYWORDS, + "ehv() -> None\n" + "\n" + "(internal)"}, + + {"get_thread_name", (PyCFunction)PyGetThreadName, + METH_VARARGS | METH_KEYWORDS, + "get_thread_name() -> str\n" + "\n" + "(internal)\n" + "\n" + "Returns the name of the current thread.\n" + "This may vary depending on platform and should not be used in logic;\n" + "only for debugging."}, + + {"set_thread_name", (PyCFunction)PySetThreadName, + METH_VARARGS | METH_KEYWORDS, + "set_thread_name(name: str) -> None\n" + "\n" + "(internal)\n" + "\n" + "Sets the name of the current thread (on platforms where this is\n" + "available). Thread names are only for debugging and should not be\n" + "used in logic, as naming behavior can vary across platforms.\n"}, + + {"in_game_thread", (PyCFunction)PyInGameThread, + METH_VARARGS | METH_KEYWORDS, + "in_game_thread() -> bool\n" + "\n" + "(internal)\n" + "\n" + "Returns whether or not the current thread is the game thread."}, + + {"request_permission", (PyCFunction)PyRequestPermission, + METH_VARARGS | METH_KEYWORDS, + "request_permission(permission: ba.Permission) -> None\n" + "\n" + "(internal)"}, + + {"have_permission", (PyCFunction)PyHavePermission, + METH_VARARGS | METH_KEYWORDS, + "have_permission(permission: ba.Permission) -> bool\n" + "\n" + "(internal)"}, + + {"is_running_on_fire_tv", PyIsRunningOnFireTV, METH_VARARGS, + "is_running_on_fire_tv() -> bool\n" + "\n" + "(internal)"}, + + {"is_running_on_ouya", PyIsRunningOnOuya, METH_VARARGS, + "is_running_on_ouya() -> bool\n" + "\n" + "(internal)"}, + + {"setup_sigint", (PyCFunction)PySetUpSigInt, METH_NOARGS, + "setup_sigint() -> None\n" + "\n" + "(internal)"}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_system.h b/src/ballistica/python/methods/python_methods_system.h new file mode 100644 index 00000000..d22017db --- /dev/null +++ b/src/ballistica/python/methods/python_methods_system.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_SYSTEM_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_SYSTEM_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// System related individual python methods for our module. +class PythonMethodsSystem { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_SYSTEM_H_ diff --git a/src/ballistica/python/methods/python_methods_ui.cc b/src/ballistica/python/methods/python_methods_ui.cc new file mode 100644 index 00000000..38fddc48 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_ui.cc @@ -0,0 +1,2710 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/methods/python_methods_ui.h" + +#include +#include + +#include "ballistica/app/app.h" +#include "ballistica/app/app_globals.h" +#include "ballistica/game/account.h" +#include "ballistica/game/game.h" +#include "ballistica/input/input.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/root_ui.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/button_widget.h" +#include "ballistica/ui/widget/check_box_widget.h" +#include "ballistica/ui/widget/column_widget.h" +#include "ballistica/ui/widget/container_widget.h" +#include "ballistica/ui/widget/h_scroll_widget.h" +#include "ballistica/ui/widget/image_widget.h" +#include "ballistica/ui/widget/root_widget.h" +#include "ballistica/ui/widget/row_widget.h" +#include "ballistica/ui/widget/scroll_widget.h" +#include "ballistica/ui/widget/text_widget.h" + +#if !BA_HEADLESS_BUILD +extern "C" void SDL_ericf_focus(); +#endif + +namespace ballistica { + +// Ignore signed bitwise stuff; python macros do it quite a bit. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "hicpp-signed-bitwise" + +auto PyButtonWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("buttonwidget"); + PyObject* size_obj = Py_None; + PyObject* pos_obj = Py_None; + PyObject* label_obj = Py_None; + PyObject* parent_obj = Py_None; + PyObject* edit_obj = Py_None; + ContainerWidget* parent_widget = nullptr; + PyObject* on_activate_call_obj = Py_None; + PyObject* color_obj = Py_None; + PyObject* down_widget_obj = Py_None; + Widget* down_widget = nullptr; + PyObject* up_widget_obj = Py_None; + Widget* up_widget = nullptr; + PyObject* left_widget_obj = Py_None; + Widget* left_widget = nullptr; + PyObject* right_widget_obj = Py_None; + Widget* right_widget = nullptr; + PyObject* texture_obj = Py_None; + PyObject* tint_texture_obj = Py_None; + PyObject* text_scale_obj = Py_None; + PyObject* textcolor_obj = Py_None; + PyObject* enable_sound_obj = Py_None; + PyObject* model_transparent_obj = Py_None; + PyObject* model_opaque_obj = Py_None; + PyObject* repeat_obj = Py_None; + PyObject* scale_obj = Py_None; + PyObject* transition_delay_obj = Py_None; + PyObject* on_select_call_obj = Py_None; + PyObject* button_type_obj = Py_None; + PyObject* extra_touch_border_scale_obj = Py_None; + PyObject* selectable_obj = Py_None; + PyObject* show_buffer_top_obj = Py_None; + PyObject* icon_obj = Py_None; + PyObject* iconscale_obj = Py_None; + PyObject* icon_tint_obj = Py_None; + PyObject* icon_color_obj = Py_None; + PyObject* autoselect_obj = Py_None; + PyObject* mask_texture_obj = Py_None; + PyObject* tint_color_obj = Py_None; + PyObject* tint2_color_obj = Py_None; + PyObject* text_flatness_obj = Py_None; + PyObject* text_res_scale_obj = Py_None; + PyObject* enabled_obj = Py_None; + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "on_activate_call", + "label", + "color", + "down_widget", + "up_widget", + "left_widget", + "right_widget", + "texture", + "text_scale", + "textcolor", + "enable_sound", + "model_transparent", + "model_opaque", + "repeat", + "scale", + "transition_delay", + "on_select_call", + "button_type", + "extra_touch_border_scale", + "selectable", + "show_buffer_top", + "icon", + "iconscale", + "icon_tint", + "icon_color", + "autoselect", + "mask_texture", + "tint_texture", + "tint_color", + "tint2_color", + "text_flatness", + "text_res_scale", + "enabled", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + const_cast(kwlist), &edit_obj, &parent_obj, &size_obj, + &pos_obj, &on_activate_call_obj, &label_obj, &color_obj, + &down_widget_obj, &up_widget_obj, &left_widget_obj, &right_widget_obj, + &texture_obj, &text_scale_obj, &textcolor_obj, &enable_sound_obj, + &model_transparent_obj, &model_opaque_obj, &repeat_obj, &scale_obj, + &transition_delay_obj, &on_select_call_obj, &button_type_obj, + &extra_touch_border_scale_obj, &selectable_obj, &show_buffer_top_obj, + &icon_obj, &iconscale_obj, &icon_tint_obj, &icon_color_obj, + &autoselect_obj, &mask_texture_obj, &tint_texture_obj, + &tint_color_obj, &tint2_color_obj, &text_flatness_obj, + &text_res_scale_obj, &enabled_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context docs)", + PyExcType::kContext); + } + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref b; + if (edit_obj != Py_None) { + b = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!b.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (parent_widget == nullptr) { + throw Exception("Parent widget nonexistent or not a container.", + PyExcType::kWidgetNotFound); + } + b = Object::New(); + } + + // set applicable values ---------------------------- + if (label_obj != Py_None) { + b->SetText(Python::GetPyString(label_obj)); + } + if (on_activate_call_obj != Py_None) { + b->set_on_activate_call(on_activate_call_obj); + } + + if (down_widget_obj != Py_None) { + down_widget = Python::GetPyWidget(down_widget_obj); + if (!down_widget) { + throw Exception("Invalid down widget.", PyExcType::kWidgetNotFound); + } + b->set_down_widget(down_widget); + } + if (up_widget_obj != Py_None) { + up_widget = Python::GetPyWidget(up_widget_obj); + if (!up_widget) { + throw Exception("Invalid up widget.", PyExcType::kWidgetNotFound); + } + b->set_up_widget(up_widget); + } + if (autoselect_obj != Py_None) { + b->set_auto_select(Python::GetPyBool(autoselect_obj)); + } + if (left_widget_obj != Py_None) { + left_widget = Python::GetPyWidget(left_widget_obj); + if (!left_widget) { + throw Exception("Invalid left widget.", PyExcType::kWidgetNotFound); + } + b->set_left_widget(left_widget); + } + if (right_widget_obj != Py_None) { + right_widget = Python::GetPyWidget(right_widget_obj); + if (!right_widget) { + throw Exception("Invalid right widget.", PyExcType::kWidgetNotFound); + } + b->set_right_widget(right_widget); + } + if (model_transparent_obj != Py_None) { + b->SetModelTransparent(Python::GetPyModel(model_transparent_obj)); + } + if (show_buffer_top_obj != Py_None) { + b->set_show_buffer_top(Python::GetPyFloat(show_buffer_top_obj)); + } + if (model_opaque_obj != Py_None) { + b->SetModelOpaque(Python::GetPyModel(model_opaque_obj)); + } + if (on_select_call_obj != Py_None) { + b->SetOnSelectCall(on_select_call_obj); + } + if (selectable_obj != Py_None) { + b->set_selectable(Python::GetPyBool(selectable_obj)); + } + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + b->set_width(p.x); + b->set_height(p.y); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + b->set_translate(p.x, p.y); + } + if (scale_obj != Py_None) { + b->set_scale(Python::GetPyFloat(scale_obj)); + } + if (iconscale_obj != Py_None) { + b->set_icon_scale(Python::GetPyFloat(iconscale_obj)); + } + if (icon_tint_obj != Py_None) { + b->set_icon_tint(Python::GetPyFloat(icon_tint_obj)); + } + if (icon_color_obj != Py_None) { + std::vector c = Python::GetPyFloats(icon_color_obj); + if (c.size() != 3 && c.size() != 4) { + throw Exception("Expected 3 or 4 floats for icon_color.", + PyExcType::kValue); + } + b->set_icon_color(c[0], c[1], c[2], (c.size() > 3) ? c[3] : 1.0f); + } + if (extra_touch_border_scale_obj != Py_None) { + b->set_extra_touch_border_scale( + Python::GetPyFloat(extra_touch_border_scale_obj)); + } + if (texture_obj != Py_None) { + b->SetTexture(Python::GetPyTexture(texture_obj)); + } + if (mask_texture_obj != Py_None) { + b->SetMaskTexture(Python::GetPyTexture(mask_texture_obj)); + } + if (tint_texture_obj != Py_None) { + b->SetTintTexture(Python::GetPyTexture(tint_texture_obj)); + } + if (icon_obj != Py_None) { + b->SetIcon(Python::GetPyTexture(icon_obj)); + } + if (button_type_obj != Py_None) { + std::string button_type = Python::GetPyString(button_type_obj); + if (button_type == "back") { + b->set_style(ButtonWidget::Style::kBack); + } else if (button_type == "backSmall") { + b->set_style(ButtonWidget::Style::kBackSmall); + } else if (button_type == "regular") { + b->set_style(ButtonWidget::Style::kRegular); + } else if (button_type == "square") { + b->set_style(ButtonWidget::Style::kSquare); + } else if (button_type == "tab") { + b->set_style(ButtonWidget::Style::kTab); + } else { + throw Exception("Invalid button type: " + button_type + ".", + PyExcType::kValue); + } + } + if (repeat_obj != Py_None) { + b->set_repeat(Python::GetPyBool(repeat_obj)); + } + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for color.", PyExcType::kValue); + } + b->SetColor(c[0], c[1], c[2]); + } + if (textcolor_obj != Py_None) { + std::vector c = Python::GetPyFloats(textcolor_obj); + if (c.size() != 3 && c.size() != 4) { + throw Exception("Expected 3 or 4 floats for textcolor.", + PyExcType::kValue); + } + b->set_text_color(c[0], c[1], c[2], (c.size() > 3) ? c[3] : 1.0f); + } + if (tint_color_obj != Py_None) { + std::vector c = Python::GetPyFloats(tint_color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for tint_color.", PyExcType::kValue); + } + b->set_tint_color(c[0], c[1], c[2]); + } + if (tint2_color_obj != Py_None) { + std::vector c = Python::GetPyFloats(tint2_color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for tint2_color.", PyExcType::kValue); + } + b->set_tint2_color(c[0], c[1], c[2]); + } + if (text_flatness_obj != Py_None) { + b->set_text_flatness(Python::GetPyFloat(text_flatness_obj)); + } + if (text_scale_obj != Py_None) { + b->set_text_scale(Python::GetPyFloat(text_scale_obj)); + } + if (enable_sound_obj != Py_None) { + b->set_enable_sound(Python::GetPyBool(enable_sound_obj)); + } + if (transition_delay_obj != Py_None) { + // We accept this as seconds; widget takes milliseconds. +#if BA_TEST_BUILD + g_python->TimeFormatCheck(TimeFormat::kSeconds, transition_delay_obj); +#endif + b->set_transition_delay(1000.0f * Python::GetPyFloat(transition_delay_obj)); + } + if (text_res_scale_obj != Py_None) { + b->SetTextResScale(Python::GetPyFloat(text_res_scale_obj)); + } + if (enabled_obj != Py_None) { + b->set_enabled(Python::GetPyBool(selectable_obj)); + } + + // If making a new widget add it at the end. + if (edit_obj == Py_None) { + g_ui->AddWidget(b.get(), parent_widget); + } + + return b->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyCheckBoxWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("checkboxwidget"); + PyObject* size_obj = Py_None; + PyObject* pos_obj = Py_None; + PyObject* text_obj = Py_None; + PyObject* value_obj = Py_None; + PyObject* on_value_change_call_obj = Py_None; + PyObject* on_select_call_obj = Py_None; + PyObject* scale_obj = Py_None; + PyObject* is_radio_button_obj = Py_None; + PyObject* maxwidth_obj = Py_None; + PyObject* parent_obj = Py_None; + PyObject* edit_obj = Py_None; + ContainerWidget* parent_widget = nullptr; + PyObject* text_scale_obj = Py_None; + PyObject* textcolor_obj = Py_None; + PyObject* autoselect_obj = Py_None; + PyObject* color_obj = Py_None; + + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "text", + "value", + "on_value_change_call", + "on_select_call", + "text_scale", + "textcolor", + "scale", + "is_radio_button", + "maxwidth", + "autoselect", + "color", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOO", const_cast(kwlist), + &edit_obj, &parent_obj, &size_obj, &pos_obj, &text_obj, &value_obj, + &on_value_change_call_obj, &on_select_call_obj, &text_scale_obj, + &textcolor_obj, &scale_obj, &is_radio_button_obj, &maxwidth_obj, + &autoselect_obj, &color_obj)) { + return nullptr; + } + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + } + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref widget; + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (parent_widget == nullptr) { + throw Exception("Parent widget nonexistent or not a container.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + } + + // set applicable values ---------------------------- + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + if (autoselect_obj != Py_None) { + widget->set_auto_select(Python::GetPyBool(autoselect_obj)); + } + if (text_obj != Py_None) { + widget->SetText(Python::GetPyString(text_obj)); + } + if (value_obj != Py_None) { + widget->SetValue(Python::GetPyBool(value_obj)); + } + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() != 3) + throw Exception("Expected 3 floats for color.", PyExcType::kValue); + widget->set_color(c[0], c[1], c[2]); + } + if (maxwidth_obj != Py_None) { + widget->SetMaxWidth(Python::GetPyFloat(maxwidth_obj)); + } + if (is_radio_button_obj != Py_None) { + widget->SetIsRadioButton(Python::GetPyBool(is_radio_button_obj)); + } + if (scale_obj != Py_None) { + widget->set_scale(Python::GetPyFloat(scale_obj)); + } + if (on_value_change_call_obj != Py_None) { + widget->SetOnValueChangeCall(on_value_change_call_obj); + } + if (on_select_call_obj != Py_None) { + widget->SetOnSelectCall(on_select_call_obj); + } + if (text_scale_obj != Py_None) { + widget->SetTextScale(Python::GetPyFloat(text_scale_obj)); + } + if (textcolor_obj != Py_None) { + std::vector c = Python::GetPyFloats(textcolor_obj); + if (c.size() != 3 && c.size() != 4) { + throw Exception("Expected 3 or 4 float values for textcolor.", + PyExcType::kValue); + } + if (c.size() == 3) { + widget->set_text_color(c[0], c[1], c[2], 1.0f); + } else { + widget->set_text_color(c[0], c[1], c[2], c[3]); + } + } + + // if making a new widget add it at the end + if (edit_obj == Py_None) { + g_ui->AddWidget(widget.get(), parent_widget); + } + + return widget->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyImageWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("imagewidget"); + PyObject* size_obj = Py_None; + PyObject* pos_obj = Py_None; + PyObject* texture_obj = Py_None; + PyObject* tint_texture_obj = Py_None; + ContainerWidget* parent_widget = nullptr; + PyObject* parent_obj = Py_None; + PyObject* edit_obj = Py_None; + PyObject* color_obj = Py_None; + PyObject* tint_color_obj = Py_None; + PyObject* tint2_color_obj = Py_None; + PyObject* opacity_obj = Py_None; + PyObject* model_transparent_obj = Py_None; + PyObject* model_opaque_obj = Py_None; + PyObject* has_alpha_channel_obj = Py_None; + PyObject* transition_delay_obj = Py_None; + PyObject* draw_controller_obj = Py_None; + PyObject* tilt_scale_obj = Py_None; + PyObject* mask_texture_obj = Py_None; + PyObject* radial_amount_obj = Py_None; + + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "color", + "texture", + "opacity", + "model_transparent", + "model_opaque", + "has_alpha_channel", + "tint_texture", + "tint_color", + "transition_delay", + "draw_controller", + "tint2_color", + "tilt_scale", + "mask_texture", + "radial_amount", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOOOOO", const_cast(kwlist), + &edit_obj, &parent_obj, &size_obj, &pos_obj, &color_obj, &texture_obj, + &opacity_obj, &model_transparent_obj, &model_opaque_obj, + &has_alpha_channel_obj, &tint_texture_obj, &tint_color_obj, + &transition_delay_obj, &draw_controller_obj, &tint2_color_obj, + &tilt_scale_obj, &mask_texture_obj, &radial_amount_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + } + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref b; + if (edit_obj != Py_None) { + b = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!b.exists()) + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (parent_widget == nullptr) { + throw Exception("Parent widget nonexistent or not a container.", + PyExcType::kWidgetNotFound); + } + b = Object::New(); + } + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + b->set_width(p.x); + b->set_height(p.y); + } + if (texture_obj != Py_None) { + b->SetTexture(Python::GetPyTexture(texture_obj)); + } + if (tint_texture_obj != Py_None) { + b->SetTintTexture(Python::GetPyTexture(tint_texture_obj)); + } + if (mask_texture_obj != Py_None) { + b->SetMaskTexture(Python::GetPyTexture(mask_texture_obj)); + } + if (model_opaque_obj != Py_None) { + b->SetModelOpaque(Python::GetPyModel(model_opaque_obj)); + } + if (model_transparent_obj != Py_None) { + b->SetModelTransparent(Python::GetPyModel(model_transparent_obj)); + } + if (draw_controller_obj != Py_None) { + auto* dcw = Python::GetPyWidget(draw_controller_obj); + if (!dcw) { + throw Exception("Invalid or nonexistent draw-controller widget.", + PyExcType::kWidgetNotFound); + } + b->set_draw_control_parent(dcw); + } + if (has_alpha_channel_obj != Py_None) { + b->set_has_alpha_channel(Python::GetPyBool(has_alpha_channel_obj)); + } + if (opacity_obj != Py_None) { + b->set_opacity(Python::GetPyFloat(opacity_obj)); + } + if (radial_amount_obj != Py_None) { + b->set_radial_amount(Python::GetPyFloat(radial_amount_obj)); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + b->set_translate(p.x, p.y); + } + if (transition_delay_obj != Py_None) { + // We accept this as seconds; widget takes milliseconds. +#if BA_TEST_BUILD + g_python->TimeFormatCheck(TimeFormat::kSeconds, transition_delay_obj); +#endif + b->set_transition_delay(1000.0f * Python::GetPyFloat(transition_delay_obj)); + } + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for color.", PyExcType::kValue); + } + b->set_color(c[0], c[1], c[2]); + } + if (tint_color_obj != Py_None) { + std::vector c = Python::GetPyFloats(tint_color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for tint_color.", PyExcType::kValue); + } + b->set_tint_color(c[0], c[1], c[2]); + } + if (tint2_color_obj != Py_None) { + std::vector c = Python::GetPyFloats(tint2_color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for tint2_color.", PyExcType::kValue); + } + b->set_tint2_color(c[0], c[1], c[2]); + } + if (tilt_scale_obj != Py_None) { + b->set_tilt_scale(Python::GetPyFloat(tilt_scale_obj)); + } + + // if making a new widget add it at the end + if (edit_obj == Py_None) { + g_ui->AddWidget(b.get(), parent_widget); + } + + return b->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyColumnWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("columnwidget"); + + PyObject* size_obj{Py_None}; + PyObject* pos_obj{Py_None}; + PyObject* background_obj{Py_None}; + PyObject* selected_child_obj{Py_None}; + PyObject* visible_child_obj{Py_None}; + PyObject* single_depth_obj{Py_None}; + PyObject* print_list_exit_instructions_obj{Py_None}; + PyObject* parent_obj{Py_None}; + PyObject* edit_obj{Py_None}; + ContainerWidget* parent_widget{}; + PyObject* left_border_obj{Py_None}; + PyObject* top_border_obj{Py_None}; + PyObject* bottom_border_obj{Py_None}; + PyObject* selection_loops_to_parent_obj{Py_None}; + PyObject* border_obj{Py_None}; + PyObject* margin_obj{Py_None}; + PyObject* claims_left_right_obj{Py_None}; + PyObject* claims_tab_obj{Py_None}; + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "background", + "selected_child", + "visible_child", + "single_depth", + "print_list_exit_instructions", + "left_border", + "top_border", + "bottom_border", + "selection_loops_to_parent", + "border", + "margin", + "claims_left_right", + "claims_tab", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOOOO", const_cast(kwlist), + &edit_obj, &parent_obj, &size_obj, &pos_obj, &background_obj, + &selected_child_obj, &visible_child_obj, &single_depth_obj, + &print_list_exit_instructions_obj, &left_border_obj, &top_border_obj, + &bottom_border_obj, &selection_loops_to_parent_obj, &border_obj, + &margin_obj, &claims_left_right_obj, &claims_tab_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context " + "docs).", + PyExcType::kContext); + } + // if (!g_game->IsInUIContext()) { BA_LOG_PYTHON_TRACE("ERROR: This should be + // called within the UI context (see ba.Context docs)");} + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref widget; + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (!parent_widget) { + throw Exception("Invalid or nonexistent parent widget.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + } + + // Set applicable values ---------------------------- + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (single_depth_obj != Py_None) { + widget->set_single_depth(Python::GetPyBool(single_depth_obj)); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + if (left_border_obj != Py_None) { + widget->set_left_border(Python::GetPyFloat(left_border_obj)); + } + if (top_border_obj != Py_None) { + widget->set_top_border(Python::GetPyFloat(top_border_obj)); + } + if (border_obj != Py_None) { + widget->set_border(Python::GetPyFloat(border_obj)); + } + if (margin_obj != Py_None) { + widget->set_margin(Python::GetPyFloat(margin_obj)); + } + if (bottom_border_obj != Py_None) { + widget->set_bottom_border(Python::GetPyFloat(bottom_border_obj)); + } + if (print_list_exit_instructions_obj != Py_None) { + widget->set_should_print_list_exit_instructions( + Python::GetPyBool(print_list_exit_instructions_obj)); + } + if (background_obj != Py_None) { + widget->set_background(Python::GetPyBool(background_obj)); + } + if (selected_child_obj != Py_None) { + widget->SelectWidget(Python::GetPyWidget(selected_child_obj)); + } + if (visible_child_obj != Py_None) { + widget->ShowWidget(Python::GetPyWidget(visible_child_obj)); + } + if (selection_loops_to_parent_obj != Py_None) { + widget->set_selection_loops_to_parent( + Python::GetPyBool(selection_loops_to_parent_obj)); + } + if (claims_left_right_obj != Py_None) { + widget->set_claims_left_right(Python::GetPyBool(claims_left_right_obj)); + } + if (claims_tab_obj != Py_None) { + widget->set_claims_tab(Python::GetPyBool(claims_tab_obj)); + } + + // if making a new widget add it at the end + if (edit_obj == Py_None) { + g_ui->AddWidget(widget.get(), parent_widget); + } + + return widget->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("containerwidget"); + PyObject* size_obj = Py_None; + PyObject* pos_obj = Py_None; + PyObject* background_obj = Py_None; + PyObject* selected_child_obj = Py_None; + PyObject* transition_obj = Py_None; + PyObject* cancel_button_obj = Py_None; + PyObject* start_button_obj = Py_None; + PyObject* root_selectable_obj = Py_None; + PyObject* on_activate_call_obj = Py_None; + PyObject* claims_left_right_obj = Py_None; + PyObject* claims_up_down_obj = Py_None; + PyObject* claims_tab_obj = Py_None; + PyObject* selection_loops_obj = Py_None; + PyObject* selection_loops_to_parent_obj = Py_None; + PyObject* scale_obj = Py_None; + PyObject* on_outside_click_call_obj = Py_None; + PyObject* print_list_exit_instructions_obj = Py_None; + PyObject* single_depth_obj = Py_None; + PyObject* visible_child_obj = Py_None; + PyObject* stack_offset_obj = Py_None; + PyObject* scale_origin_stack_offset_obj = Py_None; + PyObject* color_obj = Py_None; + PyObject* on_cancel_call_obj = Py_None; + PyObject* click_activate_obj = Py_None; + PyObject* always_highlight_obj = Py_None; + PyObject* parent_obj = Py_None; + ContainerWidget* parent_widget; + PyObject* edit_obj = Py_None; + PyObject* selectable_obj = Py_None; + PyObject* toolbar_visibility_obj = Py_None; + PyObject* on_select_call_obj = Py_None; + PyObject* claim_outside_clicks_obj = Py_None; + + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "background", + "selected_child", + "transition", + "cancel_button", + "start_button", + "root_selectable", + "on_activate_call", + "claims_left_right", + "claims_tab", + "selection_loops", + "selection_loops_to_parent", + "scale", + "on_outside_click_call", + "single_depth", + "visible_child", + "stack_offset", + "color", + "on_cancel_call", + "print_list_exit_instructions", + "click_activate", + "always_highlight", + "selectable", + "scale_origin_stack_offset", + "toolbar_visibility", + "on_select_call", + "claim_outside_clicks", + "claims_up_down", + nullptr}; + + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + const_cast(kwlist), &edit_obj, &parent_obj, &size_obj, + &pos_obj, &background_obj, &selected_child_obj, &transition_obj, + &cancel_button_obj, &start_button_obj, &root_selectable_obj, + &on_activate_call_obj, &claims_left_right_obj, &claims_tab_obj, + &selection_loops_obj, &selection_loops_to_parent_obj, &scale_obj, + &on_outside_click_call_obj, &single_depth_obj, &visible_child_obj, + &stack_offset_obj, &color_obj, &on_cancel_call_obj, + &print_list_exit_instructions_obj, &click_activate_obj, + &always_highlight_obj, &selectable_obj, + &scale_origin_stack_offset_obj, &toolbar_visibility_obj, + &on_select_call_obj, &claim_outside_clicks_obj, + &claims_up_down_obj)) { + return nullptr; + } + + if (!g_game->IsInUIContext()) + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref widget; + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + } else { + if (parent_obj == Py_None) { + BA_PRECONDITION(g_ui && g_ui->screen_root_widget() != nullptr); + } + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (!parent_widget) { + throw Exception("Invalid or nonexistent parent widget.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + g_ui->AddWidget(widget.get(), parent_widget); + } + + // Set applicable values. + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + if (on_cancel_call_obj != Py_None) { + widget->SetOnCancelCall(on_cancel_call_obj); + } + if (scale_obj != Py_None) { + widget->set_scale(Python::GetPyFloat(scale_obj)); + } + if (on_select_call_obj != Py_None) { + widget->SetOnSelectCall(on_select_call_obj); + } + if (selectable_obj != Py_None) { + widget->set_selectable(Python::GetPyBool(selectable_obj)); + } + if (single_depth_obj != Py_None) { + widget->set_single_depth(Python::GetPyBool(single_depth_obj)); + } + if (stack_offset_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(stack_offset_obj); + widget->set_stack_offset(p.x, p.y); + } + if (scale_origin_stack_offset_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(scale_origin_stack_offset_obj); + widget->SetScaleOriginStackOffset(p.x, p.y); + } + if (visible_child_obj != Py_None) { + widget->ShowWidget(Python::GetPyWidget(visible_child_obj)); + } + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() != 3 && c.size() != 4) { + throw Exception("Expected 3 or floats for color.", PyExcType::kValue); + } + if (c.size() == 3) { + widget->set_color(c[0], c[1], c[2], 1.0f); + } else { + widget->set_color(c[0], c[1], c[2], c[3]); + } + } + + if (on_activate_call_obj != Py_None) { + widget->SetOnActivateCall(on_activate_call_obj); + } + + if (on_outside_click_call_obj != Py_None) { + widget->SetOnOutsideClickCall(on_outside_click_call_obj); + } + + if (background_obj != Py_None) { + widget->set_background(Python::GetPyBool(background_obj)); + } + if (root_selectable_obj != Py_None) { + widget->SetRootSelectable(Python::GetPyBool(root_selectable_obj)); + } + if (selected_child_obj != Py_None) { + // special case: passing 0 implies deselect + if (PyLong_Check(selected_child_obj) + && (PyLong_AsLong(selected_child_obj) == 0)) { + widget->SelectWidget(nullptr); + } else { + widget->SelectWidget(Python::GetPyWidget(selected_child_obj)); + } + } + + if (transition_obj != Py_None) { + std::string t = Python::GetPyString(transition_obj); + if (t == "in_left") + widget->SetTransition(ContainerWidget::TRANSITION_IN_LEFT); + else if (t == "in_right") + widget->SetTransition(ContainerWidget::TRANSITION_IN_RIGHT); + else if (t == "out_left") + widget->SetTransition(ContainerWidget::TRANSITION_OUT_LEFT); + else if (t == "out_right") + widget->SetTransition(ContainerWidget::TRANSITION_OUT_RIGHT); + else if (t == "in_scale") + widget->SetTransition(ContainerWidget::TRANSITION_IN_SCALE); + else if (t == "out_scale") + widget->SetTransition(ContainerWidget::TRANSITION_OUT_SCALE); + } + + if (cancel_button_obj != Py_None) { + auto* button_widget = + dynamic_cast(Python::GetPyWidget(cancel_button_obj)); + if (!button_widget) { + throw Exception("Invalid cancel_button.", PyExcType::kWidgetNotFound); + } + widget->SetCancelButton(button_widget); + } + if (start_button_obj != Py_None) { + auto* button_widget = + dynamic_cast(Python::GetPyWidget(start_button_obj)); + if (!button_widget) { + throw Exception("Invalid start_button.", PyExcType::kWidgetNotFound); + } + widget->SetStartButton(button_widget); + } + if (claims_left_right_obj != Py_None) { + widget->set_claims_left_right(Python::GetPyBool(claims_left_right_obj)); + } + if (claims_up_down_obj != Py_None) { + widget->set_claims_up_down(Python::GetPyBool(claims_up_down_obj)); + } + if (claims_tab_obj != Py_None) { + widget->set_claims_tab(Python::GetPyBool(claims_tab_obj)); + } + if (selection_loops_obj != Py_None) { + widget->set_selection_loops(Python::GetPyBool(selection_loops_obj)); + } + if (selection_loops_to_parent_obj != Py_None) { + widget->set_selection_loops_to_parent( + Python::GetPyBool(selection_loops_to_parent_obj)); + } + if (print_list_exit_instructions_obj != Py_None) { + widget->set_should_print_list_exit_instructions( + Python::GetPyBool(print_list_exit_instructions_obj)); + } + if (click_activate_obj != Py_None) { + widget->set_click_activate(Python::GetPyBool(click_activate_obj)); + } + if (always_highlight_obj != Py_None) { + widget->set_always_highlight(Python::GetPyBool(always_highlight_obj)); + } + if (toolbar_visibility_obj != Py_None) { + Widget::ToolbarVisibility val; + std::string sval = Python::GetPyString(toolbar_visibility_obj); + if (sval == "menu_minimal") { + val = Widget::ToolbarVisibility::kMenuMinimal; + } else if (sval == "menu_minimal_no_back") { + val = Widget::ToolbarVisibility::kMenuMinimalNoBack; + } else if (sval == "menu_full") { + val = Widget::ToolbarVisibility::kMenuFull; + } else if (sval == "menu_currency") { + val = Widget::ToolbarVisibility::kMenuCurrency; + } else if (sval == "menu_full_root") { + val = Widget::ToolbarVisibility::kMenuFullRoot; + } else if (sval == "in_game") { + val = Widget::ToolbarVisibility::kInGame; + } else if (sval == "inherit") { + val = Widget::ToolbarVisibility::kInherit; + } else { + throw Exception("Invalid toolbar_visibility: '" + sval + "'.", + PyExcType::kValue); + } + widget->SetToolbarVisibility(val); + } + if (claim_outside_clicks_obj != Py_None) { + widget->set_claims_outside_clicks( + Python::GetPyBool(claim_outside_clicks_obj)); + } + return widget->NewPyRef(); + BA_PYTHON_CATCH; +} + +auto PyRowWidget(PyObject* /* self */, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("rowwidget"); + + PyObject* size_obj{Py_None}; + PyObject* pos_obj{Py_None}; + PyObject* background_obj{Py_None}; + PyObject* selected_child_obj{Py_None}; + PyObject* visible_child_obj{Py_None}; + PyObject* parent_obj{Py_None}; + PyObject* edit_obj{Py_None}; + ContainerWidget* parent_widget{}; + PyObject* claims_left_right_obj{Py_None}; + PyObject* claims_tab_obj{Py_None}; + PyObject* selection_loops_to_parent_obj{Py_None}; + + static const char* kwlist[] = {"edit", "parent", + "size", "position", + "background", "selected_child", + "visible_child", "claims_left_right", + "claims_tab", "selection_loops_to_parent", + nullptr}; + + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOO", const_cast(kwlist), &edit_obj, + &parent_obj, &size_obj, &pos_obj, &background_obj, + &selected_child_obj, &visible_child_obj, &claims_left_right_obj, + &claims_tab_obj, &selection_loops_to_parent_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + + // Called within the UI context (see ba.Context docs)");} + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // Grab the edited widget or create a new one. + Object::Ref widget; + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (!parent_widget) { + throw Exception("invalid or nonexistent parent widget.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + } + + // Set applicable values. + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + + if (background_obj != Py_None) { + widget->set_background(Python::GetPyBool(background_obj)); + } + if (selected_child_obj != Py_None) { + widget->SelectWidget(Python::GetPyWidget(selected_child_obj)); + } + if (visible_child_obj != Py_None) { + widget->ShowWidget(Python::GetPyWidget(visible_child_obj)); + } + if (claims_left_right_obj != Py_None) { + widget->set_claims_left_right(Python::GetPyBool(claims_left_right_obj)); + } + if (claims_tab_obj != Py_None) { + widget->set_claims_tab(Python::GetPyBool(claims_tab_obj)); + } + if (selection_loops_to_parent_obj != Py_None) { + widget->set_selection_loops_to_parent( + Python::GetPyBool(selection_loops_to_parent_obj)); + } + + // If making a new widget, add it to the parent. + if (edit_obj == Py_None) { + g_ui->AddWidget(widget.get(), parent_widget); + } + + return widget->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyScrollWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("scrollwidget"); + PyObject* size_obj{Py_None}; + PyObject* pos_obj{Py_None}; + PyObject* background_obj{Py_None}; + PyObject* selected_child_obj{Py_None}; + PyObject* capture_arrows_obj{Py_None}; + PyObject* on_select_call_obj{Py_None}; + PyObject* parent_obj{Py_None}; + PyObject* edit_obj{Py_None}; + PyObject* center_small_content_obj{Py_None}; + ContainerWidget* parent_widget{}; + PyObject* color_obj{Py_None}; + PyObject* highlight_obj{Py_None}; + PyObject* border_opacity_obj{Py_None}; + PyObject* simple_culling_v_obj{Py_None}; + PyObject* selection_loops_to_parent_obj{Py_None}; + PyObject* claims_left_right_obj{Py_None}; + PyObject* claims_tab_obj{Py_None}; + + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "background", + "selected_child", + "capture_arrows", + "on_select_call", + "center_small_content", + "color", + "highlight", + "border_opacity", + "simple_culling_v", + "selection_loops_to_parent", + "claims_left_right", + "claims_tab", + nullptr}; + + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOOO", const_cast(kwlist), + &edit_obj, &parent_obj, &size_obj, &pos_obj, &background_obj, + &selected_child_obj, &capture_arrows_obj, &on_select_call_obj, + ¢er_small_content_obj, &color_obj, &highlight_obj, + &border_opacity_obj, &simple_culling_v_obj, + &selection_loops_to_parent_obj, &claims_left_right_obj, + &claims_tab_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + } + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // Grab the edited widget or create a new one. --------------------- + Object::Ref widget; + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent edit widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (!parent_widget) { + throw Exception("Invalid or nonexistent parent widget.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + } + + // Set applicable values. ---------------------------- + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + if (highlight_obj != Py_None) { + widget->set_highlight(Python::GetPyBool(highlight_obj)); + } + if (border_opacity_obj != Py_None) { + widget->set_border_opacity(Python::GetPyFloat(border_opacity_obj)); + } + if (on_select_call_obj != Py_None) { + widget->SetOnSelectCall(on_select_call_obj); + } + if (center_small_content_obj != Py_None) { + widget->set_center_small_content( + Python::GetPyBool(center_small_content_obj)); + } + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for color.", PyExcType::kValue); + } + widget->set_color(c[0], c[1], c[2]); + } + if (capture_arrows_obj != Py_None) { + widget->set_capture_arrows(Python::GetPyBool(capture_arrows_obj)); + } + if (background_obj != Py_None) { + widget->set_background(Python::GetPyBool(background_obj)); + } + if (simple_culling_v_obj != Py_None) { + widget->set_simple_culling_v(Python::GetPyFloat(simple_culling_v_obj)); + } + if (selected_child_obj != Py_None) { + widget->SelectWidget(Python::GetPyWidget(selected_child_obj)); + } + if (selection_loops_to_parent_obj != Py_None) { + widget->set_selection_loops_to_parent( + Python::GetPyBool(selection_loops_to_parent_obj)); + } + if (claims_left_right_obj != Py_None) { + widget->set_claims_left_right(Python::GetPyBool(claims_left_right_obj)); + } + if (claims_tab_obj != Py_None) { + widget->set_claims_tab(Python::GetPyBool(claims_tab_obj)); + } + + // If making a new widget add it at the end. + if (edit_obj == Py_None) { + g_ui->AddWidget(widget.get(), parent_widget); + } + return widget->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyHScrollWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("hscrollwidget"); + + PyObject* size_obj = Py_None; + PyObject* pos_obj = Py_None; + PyObject* background_obj = Py_None; + PyObject* selected_child_obj = Py_None; + PyObject* capture_arrows_obj = Py_None; + PyObject* on_select_call_obj = Py_None; + PyObject* parent_obj = Py_None; + PyObject* edit_obj = Py_None; + PyObject* center_small_content_obj = Py_None; + ContainerWidget* parent_widget = nullptr; + PyObject* color_obj = Py_None; + PyObject* highlight_obj = Py_None; + PyObject* border_opacity_obj = Py_None; + PyObject* simple_culling_h_obj = Py_None; + PyObject* claims_left_right_obj = Py_None; + PyObject* claims_tab_obj = Py_None; + + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "background", + "selected_child", + "capture_arrows", + "on_select_call", + "center_small_content", + "color", + "highlight", + "border_opacity", + "simple_culling_h", + "claims_left_right", + "claims_tab", + nullptr}; + + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOO", const_cast(kwlist), + &edit_obj, &parent_obj, &size_obj, &pos_obj, &background_obj, + &selected_child_obj, &capture_arrows_obj, &on_select_call_obj, + ¢er_small_content_obj, &color_obj, &highlight_obj, + &border_opacity_obj, &simple_culling_h_obj, &claims_left_right_obj, + &claims_tab_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + } + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref widget; + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent edit widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (!parent_widget) { + throw Exception("Invalid or nonexistent parent widget.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + } + + // set applicable values ---------------------------- + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + if (highlight_obj != Py_None) { + widget->set_highlight(Python::GetPyBool(highlight_obj)); + } + if (border_opacity_obj != Py_None) { + widget->setBorderOpacity(Python::GetPyFloat(border_opacity_obj)); + } + if (on_select_call_obj != Py_None) { + widget->SetOnSelectCall(on_select_call_obj); + } + if (center_small_content_obj != Py_None) { + widget->SetCenterSmallContent(Python::GetPyBool(center_small_content_obj)); + } + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() != 3) { + throw Exception("Expected 3 floats for color.", PyExcType::kValue); + } + widget->setColor(c[0], c[1], c[2]); + } + if (capture_arrows_obj != Py_None) { + widget->set_capture_arrows(Python::GetPyBool(capture_arrows_obj)); + } + if (background_obj != Py_None) { + widget->set_background(Python::GetPyBool(background_obj)); + } + if (simple_culling_h_obj != Py_None) { + widget->set_simple_culling_h(Python::GetPyFloat(simple_culling_h_obj)); + } + if (selected_child_obj != Py_None) { + widget->SelectWidget(Python::GetPyWidget(selected_child_obj)); + } + if (claims_left_right_obj != Py_None) { + widget->set_claims_left_right(Python::GetPyBool(claims_left_right_obj)); + } + if (claims_tab_obj != Py_None) { + widget->set_claims_tab(Python::GetPyBool(claims_tab_obj)); + } + + // if making a new widget add it at the end + if (edit_obj == Py_None) { + g_ui->AddWidget(widget.get(), parent_widget); + } + return widget->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyTextWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("textwidget"); + PyObject* size_obj = Py_None; + PyObject* pos_obj = Py_None; + PyObject* text_obj = Py_None; + PyObject* v_align_obj = Py_None; + PyObject* h_align_obj = Py_None; + PyObject* editable_obj = Py_None; + PyObject* padding_obj = Py_None; + PyObject* on_return_press_call_obj = Py_None; + PyObject* on_activate_call_obj = Py_None; + PyObject* selectable_obj = Py_None; + PyObject* max_chars_obj = Py_None; + PyObject* color_obj = Py_None; + PyObject* click_activate_obj = Py_None; + PyObject* on_select_call_obj = Py_None; + PyObject* maxwidth_obj = Py_None; + PyObject* max_height_obj = Py_None; + PyObject* scale_obj = Py_None; + PyObject* corner_scale_obj = Py_None; + PyObject* always_highlight_obj = Py_None; + PyObject* draw_controller_obj = Py_None; + PyObject* description_obj = Py_None; + PyObject* transition_delay_obj = Py_None; + PyObject* flatness_obj = Py_None; + PyObject* shadow_obj = Py_None; + PyObject* big_obj = Py_None; + PyObject* parent_obj = Py_None; + ContainerWidget* parent_widget = nullptr; + PyObject* edit_obj = Py_None; + PyObject* query_obj = Py_None; + PyObject* autoselect_obj = Py_None; + PyObject* rotate_obj = Py_None; + PyObject* enabled_obj = Py_None; + PyObject* force_internal_editing_obj = Py_None; + PyObject* always_show_carat_obj = Py_None; + PyObject* extra_touch_border_scale_obj = Py_None; + PyObject* res_scale_obj = Py_None; + + static const char* kwlist[] = {"edit", + "parent", + "size", + "position", + "text", + "v_align", + "h_align", + "editable", + "padding", + "on_return_press_call", + "on_activate_call", + "selectable", + "query", + "max_chars", + "color", + "click_activate", + "on_select_call", + "always_highlight", + "draw_controller", + "scale", + "corner_scale", + "description", + "transition_delay", + "maxwidth", + "max_height", + "flatness", + "shadow", + "autoselect", + "rotate", + "enabled", + "force_internal_editing", + "always_show_carat", + "big", + "extra_touch_border_scale", + "res_scale", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + const_cast(kwlist), &edit_obj, &parent_obj, &size_obj, + &pos_obj, &text_obj, &v_align_obj, &h_align_obj, &editable_obj, + &padding_obj, &on_return_press_call_obj, &on_activate_call_obj, + &selectable_obj, &query_obj, &max_chars_obj, &color_obj, + &click_activate_obj, &on_select_call_obj, &always_highlight_obj, + &draw_controller_obj, &scale_obj, &corner_scale_obj, &description_obj, + &transition_delay_obj, &maxwidth_obj, &max_height_obj, &flatness_obj, + &shadow_obj, &autoselect_obj, &rotate_obj, &enabled_obj, + &force_internal_editing_obj, &always_show_carat_obj, &big_obj, + &extra_touch_border_scale_obj, &res_scale_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + // if (!g_game->IsInUIContext()) { BA_LOG_PYTHON_TRACE("ERROR: This should be + // called within the UI context (see ba.Context docs)");} + ScopedSetContext cp(g_game->GetUIContextTarget()); + + // grab the edited widget or create a new one --------------------- + Object::Ref widget; + if (query_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(query_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + return PyUnicode_FromString(widget->text_raw().c_str()); + } + if (edit_obj != Py_None) { + widget = dynamic_cast(Python::GetPyWidget(edit_obj)); + if (!widget.exists()) { + throw Exception("Invalid or nonexistent widget.", + PyExcType::kWidgetNotFound); + } + } else { + parent_widget = + parent_obj == Py_None + ? g_ui->screen_root_widget() + : dynamic_cast(Python::GetPyWidget(parent_obj)); + if (!parent_widget) { + throw Exception("Invalid or nonexistent parent widget.", + PyExcType::kWidgetNotFound); + } + widget = Object::New(); + } + + // Set applicable values ---------------------------- + if (max_chars_obj != Py_None) { + widget->set_max_chars( + static_cast_check_fit(Python::GetPyInt64(max_chars_obj))); + } + if (size_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(size_obj); + widget->SetWidth(p.x); + widget->SetHeight(p.y); + } + if (description_obj != Py_None) { + // FIXME - compiling Lstr values to flat strings before passing them in; + // we should probably extend TextWidget to handle this internally, but + // punting on that for now.. + widget->set_description(g_game->CompileResourceString( + Python::GetPyString(description_obj), "textwidget set desc")); + } + if (autoselect_obj != Py_None) { + widget->set_auto_select(Python::GetPyBool(autoselect_obj)); + } + if (transition_delay_obj != Py_None) { + // we accept this as seconds; widget takes milliseconds +#if BA_TEST_BUILD + g_python->TimeFormatCheck(TimeFormat::kSeconds, transition_delay_obj); +#endif + widget->set_transition_delay(1000.0f + * Python::GetPyFloat(transition_delay_obj)); + } + if (enabled_obj != Py_None) { + widget->SetEnabled(Python::GetPyBool(enabled_obj)); + } + if (always_show_carat_obj != Py_None) { + widget->set_always_show_carat(Python::GetPyBool(always_show_carat_obj)); + } + if (big_obj != Py_None) { + widget->SetBig(Python::GetPyBool(big_obj)); + } + if (force_internal_editing_obj != Py_None) { + widget->set_force_internal_editing( + Python::GetPyBool(force_internal_editing_obj)); + } + if (pos_obj != Py_None) { + Point2D p = Python::GetPyPoint2D(pos_obj); + widget->set_translate(p.x, p.y); + } + if (flatness_obj != Py_None) { + widget->set_flatness(Python::GetPyFloat(flatness_obj)); + } + if (rotate_obj != Py_None) { + widget->set_rotate(Python::GetPyFloat(rotate_obj)); + } + if (shadow_obj != Py_None) { + widget->set_shadow(Python::GetPyFloat(shadow_obj)); + } + if (maxwidth_obj != Py_None) { + widget->set_max_width(Python::GetPyFloat(maxwidth_obj)); + } + if (max_height_obj != Py_None) { + widget->set_max_height(Python::GetPyFloat(max_height_obj)); + } + // note: need to make sure to set this before settings text + // (influences whether we look for json strings or not) + if (editable_obj != Py_None) { + widget->SetEditable(Python::GetPyBool(editable_obj)); + } + + if (text_obj != Py_None) { + widget->SetText(Python::GetPyString(text_obj)); + } + if (h_align_obj != Py_None) { + std::string halign = Python::GetPyString(h_align_obj); + if (halign == "left") { + widget->set_halign(TextWidget::HAlign::kLeft); + } else if (halign == "center") { + widget->set_halign(TextWidget::HAlign::kCenter); + } else if (halign == "right") { + widget->set_halign(TextWidget::HAlign::kRight); + } else { + throw Exception("Invalid halign.", PyExcType::kValue); + } + } + if (v_align_obj != Py_None) { + std::string valign = Python::GetPyString(v_align_obj); + if (valign == "top") { + widget->set_valign(TextWidget::VAlign::kTop); + } else if (valign == "center") { + widget->set_valign(TextWidget::VAlign::kCenter); + } else if (valign == "bottom") { + widget->set_valign(TextWidget::VAlign::kBottom); + } else { + throw Exception("Invalid valign.", PyExcType::kValue); + } + } + if (always_highlight_obj != Py_None) { + widget->set_always_highlight(Python::GetPyBool(always_highlight_obj)); + } + if (padding_obj != Py_None) { + widget->set_padding(Python::GetPyFloat(padding_obj)); + } + if (scale_obj != Py_None) { + widget->set_center_scale(Python::GetPyFloat(scale_obj)); + } + // *normal* widget scale.. we currently plug 'scale' into 'centerScale'. ew. + if (corner_scale_obj != Py_None) { + widget->set_scale(Python::GetPyFloat(corner_scale_obj)); + } + if (draw_controller_obj != Py_None) { + auto* dcw = Python::GetPyWidget(draw_controller_obj); + if (!dcw) { + throw Exception("Invalid or nonexistent draw-controller widget.", + PyExcType::kWidgetNotFound); + } + widget->set_draw_control_parent(dcw); + } + if (on_return_press_call_obj != Py_None) { + widget->set_on_return_press_call(on_return_press_call_obj); + } + if (on_select_call_obj != Py_None) { + widget->SetOnSelectCall(on_select_call_obj); + } + if (on_activate_call_obj != Py_None) { + widget->set_on_activate_call(on_activate_call_obj); + } + if (selectable_obj != Py_None) + widget->set_selectable(Python::GetPyBool(selectable_obj)); + + if (color_obj != Py_None) { + std::vector c = Python::GetPyFloats(color_obj); + if (c.size() == 3) { + widget->set_color(c[0], c[1], c[2], 1.0f); + } else if (c.size() == 4) { + widget->set_color(c[0], c[1], c[2], c[3]); + } else { + throw Exception("Expected 3 or 4 floats for color.", PyExcType::kValue); + } + } + if (click_activate_obj != Py_None) { + widget->set_click_activate(Python::GetPyBool(click_activate_obj)); + } + if (extra_touch_border_scale_obj != Py_None) { + widget->set_extra_touch_border_scale( + Python::GetPyFloat(extra_touch_border_scale_obj)); + } + if (res_scale_obj != Py_None) { + widget->set_res_scale(Python::GetPyFloat(res_scale_obj)); + } + + // if making a new widget add it at the end + if (edit_obj == Py_None) { + g_ui->AddWidget(widget.get(), parent_widget); + } + return widget->NewPyRef(); + + BA_PYTHON_CATCH; +} + +auto PyWidgetCall(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("widget"); + + PyObject* edit_obj = Py_None; + PyObject* down_widget_obj = Py_None; + PyObject* up_widget_obj = Py_None; + PyObject* left_widget_obj = Py_None; + PyObject* right_widget_obj = Py_None; + PyObject* show_buffer_top_obj = Py_None; + PyObject* show_buffer_bottom_obj = Py_None; + PyObject* show_buffer_left_obj = Py_None; + PyObject* show_buffer_right_obj = Py_None; + PyObject* autoselect_obj = Py_None; + + static const char* kwlist[] = {"edit", + "up_widget", + "down_widget", + "left_widget", + "right_widget", + "show_buffer_top", + "show_buffer_bottom", + "show_buffer_left", + "show_buffer_right", + "autoselect", + nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "O|OOOOOOOOO", const_cast(kwlist), &edit_obj, + &up_widget_obj, &down_widget_obj, &left_widget_obj, &right_widget_obj, + &show_buffer_top_obj, &show_buffer_bottom_obj, &show_buffer_left_obj, + &show_buffer_right_obj, &autoselect_obj)) + return nullptr; + + if (!g_game->IsInUIContext()) { + throw Exception( + "This must be called within the UI context (see ba.Context docs).", + PyExcType::kContext); + } + ScopedSetContext cp(g_game->GetUIContextTarget()); + + Widget* widget = nullptr; + if (edit_obj != Py_None) { + widget = Python::GetPyWidget(edit_obj); + } + if (!widget) + throw Exception("Invalid or nonexistent widget passed.", + PyExcType::kWidgetNotFound); + + if (down_widget_obj != Py_None) { + Widget* down_widget = Python::GetPyWidget(down_widget_obj); + if (!down_widget) { + throw Exception("Invalid down widget.", PyExcType::kWidgetNotFound); + } + widget->set_down_widget(down_widget); + } + if (up_widget_obj != Py_None) { + Widget* up_widget = Python::GetPyWidget(up_widget_obj); + if (!up_widget) { + throw Exception("Invalid up widget.", PyExcType::kWidgetNotFound); + } + widget->set_up_widget(up_widget); + } + if (left_widget_obj != Py_None) { + Widget* left_widget = Python::GetPyWidget(left_widget_obj); + if (!left_widget) { + throw Exception("Invalid left widget.", PyExcType::kWidgetNotFound); + } + widget->set_left_widget(left_widget); + } + if (right_widget_obj != Py_None) { + Widget* right_widget = Python::GetPyWidget(right_widget_obj); + if (!right_widget) { + throw Exception("Invalid right widget.", PyExcType::kWidgetNotFound); + } + widget->set_right_widget(right_widget); + } + if (show_buffer_top_obj != Py_None) { + widget->set_show_buffer_top(Python::GetPyFloat(show_buffer_top_obj)); + } + if (show_buffer_bottom_obj != Py_None) { + widget->set_show_buffer_bottom(Python::GetPyFloat(show_buffer_bottom_obj)); + } + if (show_buffer_left_obj != Py_None) { + widget->set_show_buffer_left(Python::GetPyFloat(show_buffer_left_obj)); + } + if (show_buffer_right_obj != Py_None) { + widget->set_show_buffer_right(Python::GetPyFloat(show_buffer_right_obj)); + } + if (autoselect_obj != Py_None) { + widget->set_auto_select(Python::GetPyBool(autoselect_obj)); + } + + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyUIBounds(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("uibounds"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + assert(g_graphics); + // note: to be safe, we return our min guaranteed screen bounds; not our + // current (which can be bigger) + float x = 0.5f * kBaseVirtualResX; + float virtual_res_y = kBaseVirtualResY; + float y = 0.5f * virtual_res_y; + return Py_BuildValue("(ffff)", -x, x, -y, y); + BA_PYTHON_CATCH; +} + +auto PyFocusWindow(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("focuswindow"); + + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + assert(InGameThread()); +#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD + SDL_ericf_focus(); +#else +#endif + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyShowOnlineScoreUI(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("show_online_score_ui"); + const char* show = "general"; + PyObject* game_obj = Py_None; + PyObject* game_version_obj = Py_None; + static const char* kwlist[] = {"show", "game", "game_version", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|sOO", + const_cast(kwlist), &show, &game_obj, + &game_version_obj)) { + return nullptr; + } + std::string game; + if (game_obj != Py_None) { + game = Python::GetPyString(game_obj); + } + std::string game_version; + if (game_version_obj != Py_None) { + game_version = Python::GetPyString(game_version_obj); + } + g_app->PushShowOnlineScoreUICall(show, game, game_version); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyFadeScreen(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("fade_screen"); + + // This can only be called in the UI context. + int fade = 0; + float time = 0.25; + PyObject* endcall = nullptr; + static const char* kwlist[] = {"to", "time", "endcall", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "|pfO", + const_cast(kwlist), &fade, &time, + &endcall)) { + return nullptr; + } + g_graphics->FadeScreen(static_cast(fade), + static_cast(1000.0f * time), endcall); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyShowAd(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("show_ad"); + BA_PRECONDITION(InGameThread()); + const char* purpose; + PyObject* on_completion_call_obj = Py_None; + int pass_actually_showed = false; + static const char* kwlist[] = {"purpose", "on_completion_call", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "s|O", const_cast(kwlist), &purpose, + &on_completion_call_obj, &pass_actually_showed)) { + return nullptr; + } + AppInternalSetAdCompletionCall(on_completion_call_obj, + static_cast(pass_actually_showed)); + + // In cases where we support ads, store our callback and kick one off. + // We'll then fire our callback once its done. + // If we *don't* support ads, just store our callback and then kick off + // an ad-view-complete message ourself so the event flow is similar.. + if (g_platform->GetHasAds()) { + g_platform->ShowAd(purpose); + } else { + AppInternalPushAdViewComplete(purpose, false); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +// (same as PyShowAd but passes actually_showed arg in callback) +auto PyShowAd2(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("show_ad_2"); + BA_PRECONDITION(InGameThread()); + const char* purpose; + PyObject* on_completion_call_obj = Py_None; + int pass_actually_showed = true; + static const char* kwlist[] = {"purpose", "on_completion_call", nullptr}; + if (!PyArg_ParseTupleAndKeywords( + args, keywds, "s|O", const_cast(kwlist), &purpose, + &on_completion_call_obj, &pass_actually_showed)) { + return nullptr; + } + AppInternalSetAdCompletionCall(on_completion_call_obj, + static_cast(pass_actually_showed)); + + // In cases where we support ads, store our callback and kick one off. + // We'll then fire our callback once its done. + // If we *don't* support ads, just store our callback and then kick off + // an ad-view-complete message ourself so the event flow is similar.. + if (g_platform->GetHasAds()) { + g_platform->ShowAd(purpose); + } else { + AppInternalPushAdViewComplete(purpose, false); + } + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyShowAppInvite(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("show_app_invite"); + std::string title; + std::string message; + std::string code; + PyObject* title_obj; + PyObject* message_obj; + PyObject* code_obj; + static const char* kwlist[] = {"title", "message", "code", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOO", + const_cast(kwlist), &title_obj, + &message_obj, &code_obj)) { + return nullptr; + } + title = Python::GetPyString(title_obj); + message = Python::GetPyString(message_obj); + code = Python::GetPyString(code_obj); + g_platform->AndroidShowAppInvite(title, message, code); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyShowProgressBar(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("show_progress_bar"); + + g_graphics->EnableProgressBar(false); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyShowInvitesUI(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("show_invites_ui"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_platform->AndroidGPGSPartyShowInvites(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PySetPartyIconAlwaysVisible(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("set_party_icon_always_visible"); + + int value; + static const char* kwlist[] = {"value", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &value)) { + return nullptr; + } + assert(g_input); + g_ui->root_ui()->set_always_draw_party_icon(static_cast(value)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyChatMessage(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("chat_message"); + std::string message; + PyObject* message_obj; + PyObject* clients_obj = Py_None; + PyObject* sender_override_obj = Py_None; + std::string sender_override; + const std::string* sender_override_p{}; + std::vector* clients_p{}; + + static const char* kwlist[] = {"message", "clients", "sender_override", + nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|OO", + const_cast(kwlist), &message_obj, + &clients_obj, &sender_override_obj)) { + return nullptr; + } + message = Python::GetPyString(message_obj); + if (sender_override_obj != Py_None) { + sender_override = Python::GetPyString(sender_override_obj); + sender_override_p = &sender_override; + } + + if (clients_obj != Py_None) { + std::vector clients = Python::GetPyInts(clients_obj); + clients_p = &clients; + } + g_game->SendChatMessage(message, clients_p, sender_override_p); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetChatMessages(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("get_chat_messages"); + + BA_PRECONDITION(InGameThread()); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + PyObject* py_list = PyList_New(0); + for (auto&& i : g_game->chat_messages()) { + PyList_Append(py_list, PyUnicode_FromString(i.c_str())); + } + return py_list; + BA_PYTHON_CATCH; +} + +auto PySetPartyWindowOpen(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("set_party_window_open"); + int value; + static const char* kwlist[] = {"value", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", + const_cast(kwlist), &value)) { + return nullptr; + } + assert(g_input); + g_ui->root_ui()->set_party_window_open(static_cast(value)); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyGetSpecialWidget(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("get_special_widget"); + + const char* name; + static const char* kwlist[] = {"name", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &name)) { + return nullptr; + } + RootWidget* root_widget = g_ui->root_widget(); + assert(root_widget); + Widget* w = root_widget->GetSpecialWidget(name); + if (w == nullptr) { + throw Exception("Invalid special widget name '" + std::string(name) + "'.", + PyExcType::kValue); + } + return w->NewPyRef(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +// returns an extra hash value that can be incorporated into security checks; +// this contains things like whether console commands have been run, etc. +auto PyHaveIncentivizedAd(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("have_incentivized_ad"); + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + if (g_app_globals->have_incentivized_ad) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +// this returns whether it makes sense to show an currently +auto PyCanShowAd(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("can_show_ad"); + + BA_PRECONDITION(InGameThread()); + // if we've got any network connections, no ads.. + // (don't want to make someone on the other end wait or risk disconnecting + // them or whatnot) also disallow ads if remote apps are connected; at least + // on android ads pause our activity which disconnects the remote app.. (could + // potentially still allow on other platforms; should verify..) + if (g_game->connection_to_host() || g_game->has_connection_to_clients() + || g_input->HaveRemoteAppController()) { + Py_RETURN_FALSE; + } + Py_RETURN_TRUE; // all systems go.. + BA_PYTHON_CATCH; +} + +auto PyHasVideoAds(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("has_video_ads"); + if (g_platform->GetHasVideoAds()) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +auto PyBackPress(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("back_press"); + + static const char* kwlist[] = {nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "", + const_cast(kwlist))) { + return nullptr; + } + g_input->HandleBackPress(true); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyOpenURL(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("open_url"); + const char* address = nullptr; + static const char* kwlist[] = {"address", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &address)) { + return nullptr; + } + assert(g_app); + g_app->PushOpenURLCall(address); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyOpenFileExternally(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("open_file_externally"); + + char* path = nullptr; + static const char* kwlist[] = {"path", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &path)) { + return nullptr; + } + g_platform->OpenFileExternally(path); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyOpenDirExternally(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + BA_PYTHON_TRY; + Platform::SetLastPyCall("open_dir_externally"); + char* path = nullptr; + static const char* kwlist[] = {"path", nullptr}; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &path)) { + return nullptr; + } + g_platform->OpenDirExternally(path); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyConsolePrint(PyObject* self, PyObject* args) -> PyObject* { + BA_PYTHON_TRY; + + Platform::SetLastPyCall("console_print"); + +#if !BA_HEADLESS_BUILD + Py_ssize_t tuple_size = PyTuple_GET_SIZE(args); + PyObject* obj; + for (Py_ssize_t i = 0; i < tuple_size; i++) { + obj = PyTuple_GET_ITEM(args, i); + PyObject* str_obj = PyObject_Str(obj); + if (!str_obj) { + PyErr_Clear(); // In case this is caught without setting the py exc. + throw Exception(); + } + const char* c = PyUnicode_AsUTF8(str_obj); + g_game->PushConsolePrintCall(c); + Py_DECREF(str_obj); + } +#endif // !BA_HEADLESS_BUILD + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +auto PyIsPartyIconVisible(PyObject* self, PyObject* args, PyObject* keywds) + -> PyObject* { + Platform::SetLastPyCall("is_party_icon_visible"); + BA_PYTHON_TRY; + bool party_button_active = + (g_game->GetConnectedClientCount() > 0 || g_game->connection_to_host() + || g_ui->root_ui()->always_draw_party_icon()); + if (party_button_active) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } + BA_PYTHON_CATCH; +} + +PyMethodDef PythonMethodsUI::methods_def[] = { + {"is_party_icon_visible", (PyCFunction)PyIsPartyIconVisible, + METH_VARARGS | METH_KEYWORDS, + "is_party_icon_visible() -> bool\n" + "\n" + "(internal)"}, + + {"console_print", PyConsolePrint, METH_VARARGS, + "console_print(*args: Any) -> None\n" + "\n" + "(internal)\n" + "\n" + "Print the provided args to the game console (using str()).\n" + "For most debugging/info purposes you should just use Python's standard\n" + "print, which will show up in the game console as well."}, + + {"open_dir_externally", (PyCFunction)PyOpenDirExternally, + METH_VARARGS | METH_KEYWORDS, + "open_dir_externally(path: str) -> None\n" + "\n" + "(internal)\n" + "\n" + "Open the provided dir in the default external app."}, + + {"open_file_externally", (PyCFunction)PyOpenFileExternally, + METH_VARARGS | METH_KEYWORDS, + "open_file_externally(path: str) -> None\n" + "\n" + "(internal)\n" + "\n" + "Open the provided file in the default external app."}, + + {"open_url", (PyCFunction)PyOpenURL, METH_VARARGS | METH_KEYWORDS, + "open_url(address: str) -> None\n" + "\n" + "Open a provided URL.\n" + "\n" + "Category: General Utility Functions\n" + "\n" + "Open the provided url in a web-browser, or display the URL\n" + "string in a window if that isn't possible.\n"}, + + {"back_press", (PyCFunction)PyBackPress, METH_VARARGS | METH_KEYWORDS, + "back_press() -> None\n" + "\n" + "(internal)"}, + + {"has_video_ads", (PyCFunction)PyHasVideoAds, METH_VARARGS | METH_KEYWORDS, + "has_video_ads() -> bool\n" + "\n" + "(internal)"}, + + {"can_show_ad", (PyCFunction)PyCanShowAd, METH_VARARGS | METH_KEYWORDS, + "can_show_ad() -> bool\n" + "\n" + "(internal)"}, + + {"have_incentivized_ad", (PyCFunction)PyHaveIncentivizedAd, + METH_VARARGS | METH_KEYWORDS, + "have_incentivized_ad() -> bool\n" + "\n" + "(internal)"}, + + {"get_special_widget", (PyCFunction)PyGetSpecialWidget, + METH_VARARGS | METH_KEYWORDS, + "get_special_widget(name: str) -> Widget\n" + "\n" + "(internal)"}, + + {"set_party_window_open", (PyCFunction)PySetPartyWindowOpen, + METH_VARARGS | METH_KEYWORDS, + "set_party_window_open(value: bool) -> None\n" + "\n" + "(internal)"}, + + {"get_chat_messages", (PyCFunction)PyGetChatMessages, + METH_VARARGS | METH_KEYWORDS, + "get_chat_messages() -> List[str]\n" + "\n" + "(internal)"}, + + {"chatmessage", (PyCFunction)PyChatMessage, METH_VARARGS | METH_KEYWORDS, + "chatmessage(message: Union[str, ba.Lstr],\n" + " clients: Sequence[int] = None,\n" + " sender_override: str = None) -> None\n" + "\n" + "(internal)"}, + + {"set_party_icon_always_visible", (PyCFunction)PySetPartyIconAlwaysVisible, + METH_VARARGS | METH_KEYWORDS, + "set_party_icon_always_visible(value: bool) -> None\n" + "\n" + "(internal)"}, + + {"show_invites_ui", (PyCFunction)PyShowInvitesUI, + METH_VARARGS | METH_KEYWORDS, + "show_invites_ui() -> None\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"show_progress_bar", (PyCFunction)PyShowProgressBar, + METH_VARARGS | METH_KEYWORDS, + "show_progress_bar() -> None\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"show_app_invite", (PyCFunction)PyShowAppInvite, + METH_VARARGS | METH_KEYWORDS, + "show_app_invite(title: Union[str, ba.Lstr],\n" + " message: Union[str, ba.Lstr],\n" + " code: str) -> None\n" + "\n" + "(internal)\n" + "\n" + "Category: General Utility Functions"}, + + {"show_ad", (PyCFunction)PyShowAd, METH_VARARGS | METH_KEYWORDS, + "show_ad(purpose: str, on_completion_call: Callable[[], None] = None)\n" + " -> None\n" + "\n" + "(internal)"}, + + {"show_ad_2", (PyCFunction)PyShowAd2, METH_VARARGS | METH_KEYWORDS, + "show_ad_2(purpose: str,\n" + " on_completion_call: Callable[[bool], None] = None)\n" + " -> None\n" + "\n" + "(internal)"}, + + {"fade_screen", (PyCFunction)PyFadeScreen, METH_VARARGS | METH_KEYWORDS, + "fade_screen(to: int = 0, time: float = 0.25,\n" + " endcall: Optional[Callable[[], None]] = None) -> None\n" + "\n" + "(internal)\n" + "\n" + "Fade the local game screen in our out from black over a duration of\n" + "time. if \"to\" is 0, the screen will fade out to black. Otherwise it\n" + "will fade in from black. If endcall is provided, it will be run after a\n" + "completely faded frame is drawn."}, + + {"show_online_score_ui", (PyCFunction)PyShowOnlineScoreUI, + METH_VARARGS | METH_KEYWORDS, + "show_online_score_ui(show: str = 'general', game: str = None,\n" + " game_version: str = None) -> None\n" + "\n" + "(internal)"}, + + {"focus_window", (PyCFunction)PyFocusWindow, METH_VARARGS | METH_KEYWORDS, + "focus_window() -> None\n" + "\n" + "(internal)\n" + "\n" + "A workaround for some unintentional backgrounding that occurs on mac"}, + + {"uibounds", (PyCFunction)PyUIBounds, METH_VARARGS | METH_KEYWORDS, + "uibounds() -> Tuple[float, float, float, float]\n" + "\n" + "(internal)\n" + "\n" + "Returns a tuple of 4 values: (x-min, x-max, y-min, y-max) representing\n" + "the range of values that can be plugged into a root level\n" + "ba.ContainerWidget's stack_offset value while guaranteeing that its\n" + "center remains onscreen.\n"}, + + {"buttonwidget", (PyCFunction)PyButtonWidget, METH_VARARGS | METH_KEYWORDS, + "buttonwidget(edit: ba.Widget = None,\n" + " parent: ba.Widget = None,\n" + " size: Sequence[float] = None,\n" + " position: Sequence[float] = None,\n" + " on_activate_call: Callable = None,\n" + " label: Union[str, ba.Lstr] = None,\n" + " color: Sequence[float] = None,\n" + " down_widget: ba.Widget = None,\n" + " up_widget: ba.Widget = None,\n" + " left_widget: ba.Widget = None,\n" + " right_widget: ba.Widget = None,\n" + " texture: ba.Texture = None,\n" + " text_scale: float = None,\n" + " textcolor: Sequence[float] = None,\n" + " enable_sound: bool = None,\n" + " model_transparent: ba.Model = None,\n" + " model_opaque: ba.Model = None,\n" + " repeat: bool = None,\n" + " scale: float = None,\n" + " transition_delay: float = None,\n" + " on_select_call: Callable = None,\n" + " button_type: str = None,\n" + " extra_touch_border_scale: float = None,\n" + " selectable: bool = None,\n" + " show_buffer_top: float = None,\n" + " icon: ba.Texture = None,\n" + " iconscale: float = None,\n" + " icon_tint: float = None,\n" + " icon_color: Sequence[float] = None,\n" + " autoselect: bool = None,\n" + " mask_texture: ba.Texture = None,\n" + " tint_texture: ba.Texture = None,\n" + " tint_color: Sequence[float] = None,\n" + " tint2_color: Sequence[float] = None,\n" + " text_flatness: float = None,\n" + " text_res_scale: float = None,\n" + " enabled: bool = None) -> ba.Widget\n" + "\n" + "Create or edit a button widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"checkboxwidget", (PyCFunction)PyCheckBoxWidget, + METH_VARARGS | METH_KEYWORDS, + "checkboxwidget(edit: ba.Widget = None,\n" + " parent: ba.Widget = None,\n" + " size: Sequence[float] = None,\n" + " position: Sequence[float] = None,\n" + " text: Union[ba.Lstr, str] = None,\n" + " value: bool = None,\n" + " on_value_change_call: Callable[[bool], None] = None,\n" + " on_select_call: Callable[[], None] = None,\n" + " text_scale: float = None,\n" + " textcolor: Sequence[float] = None,\n" + " scale: float = None,\n" + " is_radio_button: bool = None,\n" + " maxwidth: float = None,\n" + " autoselect: bool = None,\n" + " color: Sequence[float] = None) -> ba.Widget\n" + "\n" + "Create or edit a check-box widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"imagewidget", (PyCFunction)PyImageWidget, METH_VARARGS | METH_KEYWORDS, + "imagewidget(edit: ba.Widget = None, parent: ba.Widget = None,\n" + " size: Sequence[float] = None, position: Sequence[float] = None,\n" + " color: Sequence[float] = None, texture: ba.Texture = None,\n" + " opacity: float = None, model_transparent: ba.Model = None,\n" + " model_opaque: ba.Model = None, has_alpha_channel: bool = True,\n" + " tint_texture: ba.Texture = None, tint_color: Sequence[float] = None,\n" + " transition_delay: float = None, draw_controller: ba.Widget = None,\n" + " tint2_color: Sequence[float] = None, tilt_scale: float = None,\n" + " mask_texture: ba.Texture = None, radial_amount: float = None)\n" + " -> ba.Widget\n" + "\n" + "Create or edit an image widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"columnwidget", (PyCFunction)PyColumnWidget, METH_VARARGS | METH_KEYWORDS, + "columnwidget(edit: ba.Widget = None,\n" + " parent: ba.Widget = None,\n" + " size: Sequence[float] = None,\n" + " position: Sequence[float] = None,\n" + " background: bool = None,\n" + " selected_child: ba.Widget = None,\n" + " visible_child: ba.Widget = None,\n" + " single_depth: bool = None,\n" + " print_list_exit_instructions: bool = None,\n" + " left_border: float = None,\n" + " top_border: float = None,\n" + " bottom_border: float = None,\n" + " selection_loops_to_parent: bool = None,\n" + " border: float = None,\n" + " margin: float = None,\n" + " claims_left_right: bool = None,\n" + " claims_tab: bool = None) -> ba.Widget\n" + "\n" + "Create or edit a column widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"containerwidget", (PyCFunction)PyContainerWidget, + METH_VARARGS | METH_KEYWORDS, + "containerwidget(edit: ba.Widget = None,\n" + " parent: ba.Widget = None,\n" + " size: Sequence[float] = None,\n" + " position: Sequence[float] = None,\n" + " background: bool = None,\n" + " selected_child: ba.Widget = None,\n" + " transition: str = None,\n" + " cancel_button: ba.Widget = None,\n" + " start_button: ba.Widget = None,\n" + " root_selectable: bool = None,\n" + " on_activate_call: Callable[[], None] = None,\n" + " claims_left_right: bool = None,\n" + " claims_tab: bool = None,\n" + " selection_loops: bool = None,\n" + " selection_loops_to_parent: bool = None,\n" + " scale: float = None,\n" + " on_outside_click_call: Callable[[], None] = None,\n" + " single_depth: bool = None,\n" + " visible_child: ba.Widget = None,\n" + " stack_offset: Sequence[float] = None,\n" + " color: Sequence[float] = None,\n" + " on_cancel_call: Callable[[], None] = None,\n" + " print_list_exit_instructions: bool = None,\n" + " click_activate: bool = None,\n" + " always_highlight: bool = None,\n" + " selectable: bool = None,\n" + " scale_origin_stack_offset: Sequence[float] = None,\n" + " toolbar_visibility: str = None,\n" + " on_select_call: Callable[[], None] = None,\n" + " claim_outside_clicks: bool = None,\n" + " claims_up_down: bool = None) -> ba.Widget\n" + "\n" + "Create or edit a container widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"rowwidget", (PyCFunction)PyRowWidget, METH_VARARGS | METH_KEYWORDS, + "rowwidget(edit: Widget = None, parent: Widget = None,\n" + " size: Sequence[float] = None,\n" + " position: Sequence[float] = None,\n" + " background: bool = None, selected_child: Widget = None,\n" + " visible_child: Widget = None,\n" + " claims_left_right: bool = None,\n" + " claims_tab: bool = None,\n" + " selection_loops_to_parent: bool = None) -> Widget\n" + "\n" + "Create or edit a row widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"scrollwidget", (PyCFunction)PyScrollWidget, METH_VARARGS | METH_KEYWORDS, + "scrollwidget(edit: ba.Widget = None, parent: ba.Widget = None,\n" + " size: Sequence[float] = None, position: Sequence[float] = None,\n" + " background: bool = None, selected_child: ba.Widget = None,\n" + " capture_arrows: bool = False, on_select_call: Callable = None,\n" + " center_small_content: bool = None, color: Sequence[float] = None,\n" + " highlight: bool = None, border_opacity: float = None,\n" + " simple_culling_v: float = None,\n" + " selection_loops_to_parent: bool = None,\n" + " claims_left_right: bool = None,\n" + " claims_tab: bool = None) -> ba.Widget\n" + "\n" + "Create or edit a scroll widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"hscrollwidget", (PyCFunction)PyHScrollWidget, + METH_VARARGS | METH_KEYWORDS, + "hscrollwidget(edit: ba.Widget = None, parent: ba.Widget = None,\n" + " size: Sequence[float] = None, position: Sequence[float] = None,\n" + " background: bool = None, selected_child: ba.Widget = None,\n" + " capture_arrows: bool = None,\n" + " on_select_call: Callable[[], None] = None,\n" + " center_small_content: bool = None, color: Sequence[float] = None,\n" + " highlight: bool = None, border_opacity: float = None,\n" + " simple_culling_h: float = None,\n" + " claims_left_right: bool = None,\n" + " claims_tab: bool = None) -> ba.Widget\n" + "\n" + "Create or edit a horizontal scroll widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"textwidget", (PyCFunction)PyTextWidget, METH_VARARGS | METH_KEYWORDS, + "textwidget(edit: Widget = None, parent: Widget = None,\n" + " size: Sequence[float] = None, position: Sequence[float] = None,\n" + " text: Union[str, ba.Lstr] = None, v_align: str = None,\n" + " h_align: str = None, editable: bool = None, padding: float = None,\n" + " on_return_press_call: Callable[[], None] = None,\n" + " on_activate_call: Callable[[], None] = None,\n" + " selectable: bool = None, query: Widget = None, max_chars: int = None,\n" + " color: Sequence[float] = None, click_activate: bool = None,\n" + " on_select_call: Callable[[], None] = None,\n" + " always_highlight: bool = None, draw_controller: Widget = None,\n" + " scale: float = None, corner_scale: float = None,\n" + " description: Union[str, ba.Lstr] = None,\n" + " transition_delay: float = None, maxwidth: float = None,\n" + " max_height: float = None, flatness: float = None,\n" + " shadow: float = None, autoselect: bool = None, rotate: float = None,\n" + " enabled: bool = None, force_internal_editing: bool = None,\n" + " always_show_carat: bool = None, big: bool = None,\n" + " extra_touch_border_scale: float = None, res_scale: float = None)\n" + " -> Widget\n" + "\n" + "Create or edit a text widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Pass a valid existing ba.Widget as 'edit' to modify it; otherwise\n" + "a new one is created and returned. Arguments that are not set to None\n" + "are applied to the Widget."}, + + {"widget", (PyCFunction)PyWidgetCall, METH_VARARGS | METH_KEYWORDS, + "widget(edit: ba.Widget = None, up_widget: ba.Widget = None,\n" + " down_widget: ba.Widget = None, left_widget: ba.Widget = None,\n" + " right_widget: ba.Widget = None, show_buffer_top: float = None,\n" + " show_buffer_bottom: float = None, show_buffer_left: float = None,\n" + " show_buffer_right: float = None, autoselect: bool = None) -> None\n" + "\n" + "Edit common attributes of any widget.\n" + "\n" + "Category: User Interface Functions\n" + "\n" + "Unlike other UI calls, this can only be used to edit, not to create.\n"}, + + {nullptr, nullptr, 0, nullptr}}; + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_ui.h b/src/ballistica/python/methods/python_methods_ui.h new file mode 100644 index 00000000..7070a2e1 --- /dev/null +++ b/src/ballistica/python/methods/python_methods_ui.h @@ -0,0 +1,18 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_UI_H_ +#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_UI_H_ + +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +/// UI related individual python methods for our module. +class PythonMethodsUI { + public: + static PyMethodDef methods_def[]; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_UI_H_ diff --git a/src/ballistica/python/python.h b/src/ballistica/python/python.h new file mode 100644 index 00000000..6efe9fbe --- /dev/null +++ b/src/ballistica/python/python.h @@ -0,0 +1,420 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_PYTHON_H_ +#define BALLISTICA_PYTHON_PYTHON_H_ + +#include +#include +#include +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/context.h" +#include "ballistica/core/object.h" +#include "ballistica/generic/buffer.h" +#include "ballistica/generic/runnable.h" +#include "ballistica/math/point2d.h" +#include "ballistica/platform/min_sdl.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +/// General python support/infrastructure class. +class Python { + public: + /// When calling a python callable directly, you can use the following + /// to push and pop a text label which will be printed as 'call' in errors. + class ScopedCallLabel { + public: + explicit ScopedCallLabel(const char* label) { + prev_label_ = current_label_; + } + ~ScopedCallLabel() { current_label_ = prev_label_; } + static auto current_label() -> const char* { return current_label_; } + + private: + const char* prev_label_ = nullptr; + static const char* current_label_; + BA_DISALLOW_CLASS_COPIES(ScopedCallLabel); + }; + + /// Use this to protect Python code that may be run in cases where we don't + /// hold the Global Interpreter Lock (GIL) (basically anything outside of the + /// game thread). + class ScopedInterpreterLock { + public: + ScopedInterpreterLock(); + ~ScopedInterpreterLock(); + + private: + class Impl; + Impl* impl_ = nullptr; + }; + + /// Return whether the current thread holds the global-interpreter-lock. + /// We must always hold the GIL while running python code. + /// This *should* generally be the case by default, but this can be handy for + /// sanity checking that. + static auto HaveGIL() -> bool; + + /// Attempt to print the python stack trace. + static void PrintStackTrace(); + + /// Pass any PyObject* (including nullptr) to get a readable string + /// (basically equivalent of str(foo)). + static auto ObjToString(PyObject* obj) -> std::string; + + /// Given an asset-package python object and a media name, verify + /// that the asset-package is valid in the current context and return + /// its fully qualified name if so. Throw an Exception if not. + auto ValidatedPackageAssetName(PyObject* package, const char* name) + -> std::string; + + static void LogContextForCallableLabel(const char* label); + static void LogContextEmpty(); + static void LogContextAuto(); + static void LogContextNonGameThread(); + Python(); + ~Python(); + + void Reset(bool init = true); + + auto GetContextBaseString() -> std::string; + auto GetControllerValue(InputDevice* input_device, + const std::string& value_name) -> int; + auto GetControllerFloatValue(InputDevice* input_device, + const std::string& value_name) -> float; + void HandleDeviceMenuPress(InputDevice* input_device); + auto GetLastPlayerNameFromInputDevice(InputDevice* input_device) + -> std::string; + void AcquireGIL(); + void ReleaseGIL(); + + void LaunchStringEdit(TextWidget* w); + void CaptureGamePadInput(PyObject* obj); + void ReleaseGamePadInput(); + void CaptureKeyboardInput(PyObject* obj); + void ReleaseKeyboardInput(); + void HandleFriendScoresCB(const FriendScoreSet& ss); + void IssueCallInGameThreadWarning(PyObject* call); + + /// Borrowed from python's source code: used in overriding of objects' dir() + /// results. + static auto generic_dir(PyObject* self) -> PyObject*; + + /// For use by g_game in passing events along to the python layer (for + /// captured input, etc). + auto HandleJoystickEvent(const SDL_Event& event, + InputDevice* input_device = nullptr) -> bool; + auto HandleKeyPressEvent(const SDL_Keysym& keysym) -> bool; + auto HandleKeyReleaseEvent(const SDL_Keysym& keysym) -> bool; + + auto inited() const -> bool { return inited_; } + + /// Attempt to push the log to the server - returns true if no error occurs + /// (note; this doesn't mean that the log actually made it; just that it got + /// sent off) + static auto PutLog(bool fatal, bool short_suicide_timer = true) -> bool; + + /// Filter incoming chat message from client. + /// If returns false, message should be ignored. + auto FilterChatMessage(std::string* message, int client_id) -> bool; + + /// Pass a chat message along to the python UI layer for handling.. + void HandleLocalChatMessage(const std::string& message); + + void DispatchScoresToBeatResponse( + bool success, const std::list& scores_to_beat, + void* PyCallback); + + /// Pop up an in-game window to show a url (NOT in a browser). + void ShowURL(const std::string& url); + + void AddCleanFrameCommand(const Object::Ref& c); + void RunCleanFrameCommands(); + + /// Return a minimal filename/position string such as 'foo.py:201' based + /// on the python stack state. This shouldn't be too expensive to fetch and + /// is useful as an object identifier/etc. + static auto GetPythonFileLocation(bool pretty = true) -> std::string; + + void PartyInvite(const std::string& player, const std::string& invite_id); + void PartyInviteRevoke(const std::string& invite_id); + void set_env_obj(PyObject* obj) { env_ = obj; } + auto env_obj() const -> PyObject* { + assert(env_); + return env_; + } + auto main_dict() const -> PyObject* { + assert(main_dict_); + return main_dict_; + } + void PlayMusic(const std::string& music_type, bool continuous); + + // Fetch raw values from the config dict. The default value is returned if + // the requested value is not present or not of a compatible type. + // Note: to get app config values you should generally use the bs::AppConfig + // functions (which themselves call these functions) + auto GetRawConfigValue(const char* name) + -> PyObject*; // (returns a borrowed ref) + auto GetRawConfigValue(const char* name, const char* default_value) + -> std::string; + auto GetRawConfigValue(const char* name, float default_value) -> float; + auto GetRawConfigValue(const char* name, int default_value) -> int; + auto GetRawConfigValue(const char* name, bool default_value) -> bool; + void SetRawConfigValue(const char* name, float value); + + void RunDeepLink(const std::string& url); + auto GetResource(const char* key, const char* fallback_resource = nullptr, + const char* fallback_value = nullptr) -> std::string; + auto GetTranslation(const char* category, const char* s) -> std::string; + + // For checking and pulling values out of python objects. + // These will all throw Exceptions on errors. + static auto GetPyString(PyObject* o) -> std::string; + static auto GetPyInt64(PyObject* o) -> int64_t; + static auto GetPyInt(PyObject* o) -> int; + static auto GetPyNode(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Node*; + static auto GetPyNodes(PyObject* o) -> std::vector; + static auto GetPyMaterials(PyObject* o) -> std::vector; + static auto GetPyTextures(PyObject* o) -> std::vector; + static auto GetPyModels(PyObject* o) -> std::vector; + static auto GetPySounds(PyObject* o) -> std::vector; + static auto GetPyCollideModels(PyObject* o) -> std::vector; + static auto GetPyCollideModel(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> CollideModel*; + static auto IsPySession(PyObject* o) -> bool; + static auto GetPySession(PyObject* o) -> Session*; + static auto IsPyString(PyObject* o) -> bool; + static auto GetPyBool(PyObject* o) -> bool; + static auto GetPyHostActivity(PyObject* o) -> HostActivity*; + static auto IsPyHostActivity(PyObject* o) -> bool; + static auto GetPyInputDevice(PyObject* o) -> InputDevice*; + static auto IsPyPlayer(PyObject* o) -> bool; + static auto GetPyPlayer(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Player*; + static auto GetPySessionPlayer(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Player*; + static auto GetPyMaterial(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Material*; + static auto GetPyTexture(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Texture*; + static auto GetPyModel(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Model*; + static auto GetPySound(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Sound*; + static auto GetPyData(PyObject* o, bool allow_empty_ref = false, + bool allow_none = false) -> Data*; + static auto GetPyWidget(PyObject* o) -> Widget*; + static auto CanGetPyDouble(PyObject* o) -> bool; + static auto GetPyFloat(PyObject* o) -> float { + return static_cast(GetPyDouble(o)); + } + static auto GetPyDouble(PyObject* o) -> double; + static auto GetPyFloats(PyObject* o) -> std::vector; + static auto GetPyInts64(PyObject* o) -> std::vector; + static auto GetPyInts(PyObject* o) -> std::vector; + static auto GetPyStrings(PyObject* o) -> std::vector; + static auto GetPyUInts64(PyObject* o) -> std::vector; + static auto GetPyPoint2D(PyObject* o) -> Point2D; + static auto CanGetPyVector3f(PyObject* o) -> bool; + static auto GetPyVector3f(PyObject* o) -> Vector3f; + + static auto GetPyEnum_Permission(PyObject* obj) -> Permission; + static auto GetPyEnum_SpecialChar(PyObject* obj) -> SpecialChar; + static auto GetPyEnum_TimeType(PyObject* obj) -> TimeType; + static auto GetPyEnum_TimeFormat(PyObject* obj) -> TimeFormat; + static auto IsPyEnum_InputType(PyObject* obj) -> bool; + static auto GetPyEnum_InputType(PyObject* obj) -> InputType; + + static auto GetNodeAttr(Node* node, const char* attribute_name) -> PyObject*; + static void SetNodeAttr(Node* node, const char* attr_name, + PyObject* value_obj); + + static void SetPythonException(PyExcType exctype, const char* description); + + static void DoBuildNodeMessage(PyObject* args, int arg_offset, + Buffer* b, PyObject** user_message_obj); + auto DoNewNode(PyObject* args, PyObject* keywds) -> Node*; + + /// Identifiers for specific Python objects we grab references to for easy + /// access. + enum class ObjID { + kEmptyTuple, + kApp, + kEnv, + kDeepCopyCall, + kShallowCopyCall, + kShouldShatterMessageClass, + kImpactDamageMessageClass, + kPickedUpMessageClass, + kDroppedMessageClass, + kOutOfBoundsMessageClass, + kPickUpMessageClass, + kDropMessageClass, + kShowURLWindowCall, + kActivityClass, + kSessionClass, + kJsonDumpsCall, + kJsonLoadsCall, + kGetDeviceValueCall, + kDeviceMenuPressCall, + kGetLastPlayerNameFromInputDeviceCall, + kOnScreenKeyboardClass, + kFilterChatMessageCall, + kHandleLocalChatMessageCall, + kHandlePartyInviteCall, + kHandlePartyInviteRevokeCall, + kDoPlayMusicCall, + kDeepLinkCall, + kGetResourceCall, + kTranslateCall, + kLStrClass, + kCallClass, + kGarbageCollectCall, + kConfig, + kOnAppLaunchCall, + kClientInfoQueryResponseCall, + kResetToMainMenuCall, + kSetConfigFullscreenOnCall, + kSetConfigFullscreenOffCall, + kNotSignedInScreenMessageCall, + kConnectingToPartyMessageCall, + kRejectingInviteAlreadyInPartyMessageCall, + kConnectionFailedMessageCall, + kTemporarilyUnavailableMessageCall, + kInProgressMessageCall, + kErrorMessageCall, + kPurchaseNotValidErrorCall, + kPurchaseAlreadyInProgressErrorCall, + kGearVRControllerWarningCall, + kVROrientationResetCBMessageCall, + kVROrientationResetMessageCall, + kHandleAppResumeCall, + kHandleLogCall, + kLaunchMainMenuSessionCall, + kLanguageTestToggleCall, + kAwardInControlAchievementCall, + kAwardDualWieldingAchievementCall, + kPrintCorruptFileErrorCall, + kPlayGongSoundCall, + kLaunchCoopGameCall, + kPurchasesRestoredMessageCall, + kDismissWiiRemotesWindowCall, + kUnavailableMessageCall, + kSubmitAnalyticsCountsCall, + kSetLastAdNetworkCall, + kNoGameCircleMessageCall, + kEmptyCall, + kLevelIconPressCall, + kTrophyIconPressCall, + kCoinIconPressCall, + kTicketIconPressCall, + kBackButtonPressCall, + kFriendsButtonPressCall, + kPrintTraceCall, + kToggleFullscreenCall, + kPartyIconActivateCall, + kReadConfigCall, + kUIRemotePressCall, + kQuitWindowCall, + kRemoveInGameAdsMessageCall, + kTelnetAccessRequestCall, + kOnAppPauseCall, + kQuitCall, + kShutdownCall, + kGCDisableCall, + kShowPostPurchaseMessageCall, + kContextError, + kNotFoundError, + kNodeNotFoundError, + kSessionTeamNotFoundError, + kInputDeviceNotFoundError, + kDelegateNotFoundError, + kSessionPlayerNotFoundError, + kWidgetNotFoundError, + kActivityNotFoundError, + kSessionNotFoundError, + kAssetPackageClass, + kTimeFormatClass, + kTimeTypeClass, + kInputTypeClass, + kPermissionClass, + kSpecialCharClass, + kPlayerClass, + kGetPlayerIconCall, + kLstrFromJsonCall, + kLast // Sentinel; must be at end. + }; + + /// Access a particular Python object we've grabbed/stored. + auto obj(ObjID id) const -> const PythonRef& { + assert(id < ObjID::kLast); + if (g_buildconfig.debug_build()) { + if (!objs_[static_cast(id)].exists()) { + throw Exception("Python::obj() called on nonexistent val " + + std::to_string(static_cast(id))); + } + } + return objs_[static_cast(id)]; + } + + /// Return whether we have a particular Python object. + auto objexists(ObjID id) const -> bool { + assert(id < ObjID::kLast); + return objs_[static_cast(id)].exists(); + } + + /// Push a call to a preset obj to the game thread + /// (will be run in the UI context). + void PushObjCall(ObjID obj); + + /// Push a call with a single string arg. + void PushObjCall(ObjID obj, const std::string& arg); + + /// Register python location and returns true if it has not + /// yet been registered. (for print-once type stuff). + auto DoOnce() -> bool; + + /// Check values passed to timer functions; triggers warnings + /// for cases that look like they're passing milliseconds as seconds + /// or vice versa... (can remove this once things are settled in). + void TimeFormatCheck(TimeFormat time_format, PyObject* length_obj); + + private: + /// Check/set debug related initialization. + void SetupInterpreterDebugState(); + + /// Set up system paths if needed (for embedded builds). + void SetupPythonHome(); + + /// Set the value for a named object. + void SetObj(ObjID id, PyObject* pyobj, bool incref = false); + + /// Set the value for a named object and verify that it is a callable. + void SetObjCallable(ObjID id, PyObject* pyobj, bool incref = false); + + /// Set the value for a named object to the result of a Python expression. + void SetObj(ObjID id, const char* expression); + + /// Set the value for a named object to the result of a Python expression + /// and verify that it is callable. + void SetObjCallable(ObjID id, const char* expression); + + std::set do_once_locations_; + PythonRef objs_[static_cast(ObjID::kLast)]; + bool inited_{}; + std::list > clean_frame_commands_; + PythonRef game_pad_call_; + PythonRef keyboard_call_; + PyObject* empty_dict_object_{}; + PyObject* main_dict_{}; + PyObject* env_{}; + PyThreadState* thread_state_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_PYTHON_H_ diff --git a/src/ballistica/python/python_command.cc b/src/ballistica/python/python_command.cc new file mode 100644 index 00000000..5e517d83 --- /dev/null +++ b/src/ballistica/python/python_command.cc @@ -0,0 +1,202 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/python_command.h" + +#include + +#include "ballistica/python/python.h" +#include "ballistica/python/python_sys.h" + +// Save/restore current command for logging/etc. +// this isn't exception-safe, but we should never let +// exceptions bubble up through python api calls anyway +// or we'll have bigger problems on our hands. +#define PUSH_PYCOMMAND(OBJ) \ + PythonCommand* prev_pycmd = current_command_; \ + current_command_ = OBJ +#define POP_PYCOMMAND() current_command_ = prev_pycmd + +namespace ballistica { + +PythonCommand* PythonCommand::current_command_ = nullptr; + +PythonCommand::PythonCommand() = default; + +PythonCommand::PythonCommand(std::string command_in) + : command_(std::move(command_in)) {} + +PythonCommand::PythonCommand(std::string command_in, std::string file_name_in) + : command_(std::move(command_in)), file_name_(std::move(file_name_in)) {} + +PythonCommand::PythonCommand(const PythonCommand& c) : command_(c.command_) {} + +auto PythonCommand::operator=(const PythonCommand& src) -> PythonCommand& { + if (&src == this) { + return *this; + } + file_code_obj_.Release(); + eval_code_obj_.Release(); + command_ = src.command_; + return *this; +} + +auto PythonCommand::operator=(const std::string& src) -> PythonCommand& { + file_code_obj_.Release(); + eval_code_obj_.Release(); + command_ = src; + return *this; +} + +void PythonCommand::CompileForExec() { + assert(Python::HaveGIL()); + assert(file_code_obj_.get() == nullptr); + PyObject* o = + Py_CompileString(command_.c_str(), file_name_.c_str(), Py_file_input); + if (o == nullptr) { + // we pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks + // (nodes, actors existing after their games have ended) + PyErr_PrintEx(0); + } else { + file_code_obj_.Acquire(o); + } +} + +void PythonCommand::CompileForEval(bool print_errors) { + assert(Python::HaveGIL()); + assert(eval_code_obj_.get() == nullptr); + PyObject* o = + Py_CompileString(command_.c_str(), file_name_.c_str(), Py_eval_input); + if (o == nullptr) { + if (print_errors) { + // we pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks + // (nodes, actors existing after their games have ended) + PyErr_PrintEx(0); + } + PyErr_Clear(); + } else { + eval_code_obj_.Acquire(o); + } +} + +PythonCommand::~PythonCommand() { dead_ = true; } + +auto PythonCommand::Run() -> bool { + assert(Python::HaveGIL()); + if (!g_python) { + // This probably means the game is dying; let's not + // throw an exception here so we don't mask the original error. + Log("PythonCommand: not running due to null g_python"); + return false; + } + assert(!dead_); + if (!file_code_obj_.get()) { + CompileForExec(); + assert(!dead_); + } + if (file_code_obj_.get()) { + PUSH_PYCOMMAND(this); + PyObject* v = PyEval_EvalCode(file_code_obj_.get(), g_python->main_dict(), + g_python->main_dict()); + POP_PYCOMMAND(); + + // Technically the python call could have killed us; + // make sure that didn't happen. + assert(!dead_); + if (v == nullptr) { + // Save/restore error or it can mess with context print calls. + BA_PYTHON_ERROR_SAVE; + Log("ERROR: exception in Python call:"); + LogContext(); + BA_PYTHON_ERROR_RESTORE; + + // We pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion + // checks (nodes, actors existing after their games have ended). + PyErr_PrintEx(0); + PyErr_Clear(); + } else { + Py_DECREF(v); + return true; + } + } + return false; +} + +auto PythonCommand::CanEval() -> bool { + assert(Python::HaveGIL()); + assert(g_python); + if (!eval_code_obj_.get()) { + CompileForEval(false); + } + if (!eval_code_obj_.get()) { + PyErr_Clear(); + return false; + } + PyErr_Clear(); + return true; +} + +auto PythonCommand::RunReturnObj(bool print_errors) -> PyObject* { + assert(Python::HaveGIL()); + assert(g_python); + assert(!dead_); + if (!eval_code_obj_.get()) { + CompileForEval(print_errors); + assert(!dead_); + } + if (!eval_code_obj_.get()) { + if (print_errors) { + // Save/restore error or it can mess with context print calls. + BA_PYTHON_ERROR_SAVE; + Log("ERROR: exception in Python call:"); + LogContext(); + BA_PYTHON_ERROR_RESTORE; + // We pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks + // (nodes, actors existing after their games have ended) + PyErr_PrintEx(0); + } + + // Consider the python error handled at this point. + // If C++ land wants to throw an exception or whatnot based on this result, + // that's a totally different thing. + PyErr_Clear(); + return nullptr; + } + PUSH_PYCOMMAND(this); + PyObject* v = PyEval_EvalCode(eval_code_obj_.get(), g_python->main_dict(), + g_python->main_dict()); + POP_PYCOMMAND(); + assert(!dead_); + if (v == nullptr) { + if (print_errors) { + // save/restore error or it can mess with context print calls + BA_PYTHON_ERROR_SAVE; + Log("ERROR: exception in Python call:"); + LogContext(); + BA_PYTHON_ERROR_RESTORE; + // we pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks + // (nodes, actors existing after their games have ended) + PyErr_PrintEx(0); + } + + // Consider the python error handled at this point. + // If C++ land wants to throw an exception or whatnot based on this result, + // that's a totally different thing. + PyErr_Clear(); + return nullptr; + } + return v; +} + +void PythonCommand::LogContext() { + assert(Python::HaveGIL()); + std::string s = std::string(" call: ") + command(); + s += g_python->GetContextBaseString(); + Log(s); +} + +} // namespace ballistica diff --git a/src/ballistica/python/python_command.h b/src/ballistica/python/python_command.h new file mode 100644 index 00000000..e6029ee0 --- /dev/null +++ b/src/ballistica/python/python_command.h @@ -0,0 +1,73 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_PYTHON_COMMAND_H_ +#define BALLISTICA_PYTHON_PYTHON_COMMAND_H_ + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +// String based python commands. +// Does not save/restore context or anything; +// for that functionality use PythonContextCall; + +// Note to self: originally I though I'd be using this in a lot of places, +// so I added the ability to compile once and run repeatedly, quietly capture +// output instead of printing it, etc. Now, however, its usage is pretty +// much limited to a few places such as handling stdin and the in-game console. +// (Most places it is much cleaner to work with proper python modules and just +// interact with PyObject* refs to them) +// I should look and see if python's default high level calls would suffice +// for these purposes and potentially kill this off. +class PythonCommand { + public: + PythonCommand(); + PythonCommand(std::string command); // NOLINT (want to allow char*) + + static auto current_command() -> PythonCommand* { return current_command_; } + // file_name will be listed on error output + PythonCommand(std::string command, std::string file_name); + PythonCommand(const PythonCommand& other); + + // copy a command + auto operator=(const PythonCommand& other) -> PythonCommand&; + + // set the command to a new command string + auto operator=(const std::string& command) -> PythonCommand&; + ~PythonCommand(); + auto command() -> const std::string& { return command_; } + + /// Run the command. + /// return true if the command was successfully run + /// (not to be confused with the command's result) + /// This works for non-eval-able commands. + auto Run() -> bool; + + /// Run thecommand and return the result as a new Python reference. + /// Only works for eval-able commands. + /// Returns nullptr on errors, but Python error state will be cleared. + auto RunReturnObj(bool print_errors = false) -> PyObject*; + + void LogContext(); + + /// Return true if the command can be evaluated; otherwise it can only be + /// executed + auto CanEval() -> bool; + void CompileForExec(); + void CompileForEval(bool print_errors); + + private: + bool dead_ = false; + PythonRef file_code_obj_; + PythonRef eval_code_obj_; + std::string command_; + std::string file_name_; + static PythonCommand* current_command_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_PYTHON_COMMAND_H_ diff --git a/src/ballistica/python/python_context_call.cc b/src/ballistica/python/python_context_call.cc new file mode 100644 index 00000000..a503c971 --- /dev/null +++ b/src/ballistica/python/python_context_call.cc @@ -0,0 +1,135 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/python_context_call.h" + +#include "ballistica/game/host_activity.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +// FIXME - should be static member var +PythonContextCall* PythonContextCall::current_call_ = nullptr; + +PythonContextCall::PythonContextCall(PyObject* obj_in) { + assert(InGameThread()); + // as a sanity test, store the current context ptr just to make sure it + // hasn't changed when we run +#if BA_DEBUG_BUILD + context_target_sanity_test_ = context_.target.get(); +#endif // BA_DEBUG_BUILD + BA_PRECONDITION(PyCallable_Check(obj_in)); + object_.Acquire(obj_in); + GetTrace(); + // ok now we need to register this call with whatever the context is; + // it can be stored in a host-activity, a host-session, or the UI context. + // whoever it is registered with will explicitly release its contents on + // shutdown and ensure that nothing gets run after that point. + if (HostActivity* ha = context_.GetHostActivity()) { + ha->RegisterCall(this); + } else if (HostSession* hs = context_.GetHostSession()) { + hs->RegisterCall(this); + } else if (context_.GetUIContext()) { + // UI context never currently dies so no registering necessary here.. + } else { + throw Exception( + "Invalid context; ContextCalls must be created in a non-expired " + "Activity, Session, or UI context. (call obj = " + + Python::ObjToString(obj_in) + ").", + PyExcType::kContext); + } +} + +PythonContextCall::~PythonContextCall() { + // lets set up context while we take our stuff down + // (we may be holding refs to actors or whatnot) + ScopedSetContext cp(context_); + object_.Release(); +} + +auto PythonContextCall::GetObjectDescription() const -> std::string { + return ""; +} + +void PythonContextCall::GetTrace() { + PyFrameObject* f = PyThreadState_GET()->frame; + if (f) { + // grab the file/line now in case we error + // (useful for debugging simple timers and callbacks and such) + file_loc_ = Python::GetPythonFileLocation(); + } +} + +// called by our owning context when it goes down +// we should clear ourself out to be a no-op if we still happen to be called +void PythonContextCall::MarkDead() { + dead_ = true; + object_.Release(); +} + +void PythonContextCall::Run(PyObject* args) { + assert(this); + + if (!g_python) { + // This probably means the game is dying; let's not + // throw an exception here so we don't mask the original error. + Log("PythonCommand: not running due to null g_python"); + return; + } + + if (dead_) { + return; + } + + // Sanity test: make sure our context didn't go away. +#if BA_DEBUG_BUILD + if (context_.target.get() != context_target_sanity_test_) { + Log("WARNING: running Call after it's context has died: " + object_.Str()); + } +#endif // BA_DEBUG_BUILD + + // Restore the context from when we were made. + ScopedSetContext cp(context_); + + // Hold a ref to this call throughout this process + // so we know it'll still exist if we need to report + // exception info and whatnot. + Object::Ref keep_alive_ref(this); + + PythonContextCall* prev_call = current_call_; + current_call_ = this; + assert(Python::HaveGIL()); + PyObject* o = PyObject_Call( + object_.get(), + args ? args : g_python->obj(Python::ObjID::kEmptyTuple).get(), nullptr); + current_call_ = prev_call; + + if (o) { + Py_DECREF(o); + } else { + // Save/restore python error or it can mess with context print calls. + BA_PYTHON_ERROR_SAVE; + + Log("ERROR: exception in Python call:"); + LogContext(); + BA_PYTHON_ERROR_RESTORE; + + // We pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks. + // (nodes, actors existing after their games have ended). + PyErr_PrintEx(0); + PyErr_Clear(); + } +} + +void PythonContextCall::LogContext() { + assert(InGameThread()); + std::string s = std::string(" root call: ") + object().Str(); + s += ("\n root call origin: " + file_loc()); + s += g_python->GetContextBaseString(); + Log(s); +} + +} // namespace ballistica diff --git a/src/ballistica/python/python_context_call.h b/src/ballistica/python/python_context_call.h new file mode 100644 index 00000000..f91100cb --- /dev/null +++ b/src/ballistica/python/python_context_call.h @@ -0,0 +1,54 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_PYTHON_CONTEXT_CALL_H_ +#define BALLISTICA_PYTHON_PYTHON_CONTEXT_CALL_H_ + +#include + +#include "ballistica/core/context.h" +#include "ballistica/core/object.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +// A callable and context-state wrapped up in a convenient package. +// Handy for use with user-submitted callbacks, as it restores context +// state from when it was created and prints various useful bits of info +// on exceptions. +class PythonContextCall : public Object { + public: + static auto current_call() -> PythonContextCall* { return current_call_; } + PythonContextCall() = default; + ~PythonContextCall() override; + + /// Initialize from either a single callable object, or a tuple with a + /// callable and optionally args and keywords + explicit PythonContextCall(PyObject* callable); + void Run(PyObject* args = nullptr); + void Run(const PythonRef& args) { Run(args.get()); } + auto Exists() const -> bool { return object_.exists(); } + auto GetObjectDescription() const -> std::string override; + void MarkDead(); + auto object() const -> const PythonRef& { return object_; } + auto file_loc() const -> const std::string& { return file_loc_; } + void LogContext(); + + private: + void GetTrace(); // we try to grab basic trace info + std::string file_loc_; + int line_{}; + bool dead_ = false; + PythonRef object_; + Context context_; +#if BA_DEBUG_BUILD + ContextTarget* context_target_sanity_test_{}; +#endif + static PythonContextCall* current_call_; +}; + +// FIXME: this should be static member var +extern PythonContextCall* g_current_python_call; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_PYTHON_CONTEXT_CALL_H_ diff --git a/src/ballistica/python/python_context_call_runnable.h b/src/ballistica/python/python_context_call_runnable.h new file mode 100644 index 00000000..0d1a99a2 --- /dev/null +++ b/src/ballistica/python/python_context_call_runnable.h @@ -0,0 +1,25 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_PYTHON_CONTEXT_CALL_RUNNABLE_H_ +#define BALLISTICA_PYTHON_PYTHON_CONTEXT_CALL_RUNNABLE_H_ + +#include "ballistica/python/python_context_call.h" + +namespace ballistica { + +// a simple runnable that stores and runs a python context call +class PythonContextCallRunnable : public Runnable { + public: + explicit PythonContextCallRunnable(PyObject* o) + : call(Object::New(o)) {} + Object::Ref call; + void Run() override { + assert(call.exists()); + call->Run(); + } + virtual ~PythonContextCallRunnable() = default; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_PYTHON_CONTEXT_CALL_RUNNABLE_H_ diff --git a/src/ballistica/python/python_ref.cc b/src/ballistica/python/python_ref.cc new file mode 100644 index 00000000..edd908cc --- /dev/null +++ b/src/ballistica/python/python_ref.cc @@ -0,0 +1,185 @@ +// Copyright (c) 2011-2020 Eric Froemling + +#include "ballistica/python/python_ref.h" + +#include "ballistica/math/vector2f.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_sys.h" + +namespace ballistica { + +// Ignore a few things that python macros do. +#pragma clang diagnostic push +#pragma ide diagnostic ignored "RedundantCast" + +PythonRef::PythonRef(PyObject* obj_in, ReferenceBehavior b) { + assert(g_python); + assert(Python::HaveGIL()); + switch (b) { + case kSteal: + Steal(obj_in); + break; + case kStealWeak: + if (obj_in) { + Steal(obj_in); + } + break; + case kAcquire: + Acquire(obj_in); + break; + case kAcquireWeak: + if (obj_in) { + Acquire(obj_in); + break; + } + break; + } +} + +void PythonRef::Acquire(PyObject* obj_in) { + BA_PRECONDITION(obj_in); + assert(g_python); + assert(Python::HaveGIL()); + + // Assign and increment the new one before decrementing our old + // (in case its the same one or prev gets deallocated and accesses us + // somehow). + PyObject* prev = obj_; + Py_INCREF(obj_in); + obj_ = obj_in; + if (prev) { + Py_DECREF(prev); + } +} + +void PythonRef::Steal(PyObject* obj_in) { + BA_PRECONDITION(obj_in); + assert(g_python); + assert(Python::HaveGIL()); + + // Assign before decrementing the old + // (in case prev gets deallocated and accesses us somehow). + PyObject* prev = obj_; + obj_ = obj_in; + if (prev) { + Py_DECREF(prev); + } +} + +void PythonRef::Release() { + assert(g_python); + assert(Python::HaveGIL()); + + // Py_CLEAR uses a temp variable and assigns o to nullptr first + // so we're safe if the clear triggers something that (again) releases or + // destroys us. + if (obj_) { + Py_CLEAR(obj_); + } +} + +auto PythonRef::Str() const -> std::string { + assert(Python::HaveGIL()); + if (!obj_) { + return ""; + } + PyObject* obj = PyObject_Str(obj_); + if (!obj) { + return ""; + } + PythonRef s(obj, PythonRef::kSteal); + assert(PyUnicode_Check(obj)); // NOLINT (signed with bitwise) + return PyUnicode_AsUTF8(s.get()); +} + +auto PythonRef::Repr() const -> std::string { + assert(Python::HaveGIL()); + BA_PRECONDITION(obj_); + PythonRef s(PyObject_Repr(obj_), PythonRef::kSteal); + assert(PyUnicode_Check(s.get())); // NOLINT (signed with bitwise) + return PyUnicode_AsUTF8(s.get()); +} + +auto PythonRef::ValueAsString() const -> std::string { + assert(Python::HaveGIL()); + BA_PRECONDITION(obj_); + return Python::GetPyString(obj_); +} + +auto PythonRef::ValueAsInt() const -> int64_t { + assert(Python::HaveGIL()); + BA_PRECONDITION(obj_); + return Python::GetPyInt64(obj_); +} + +auto PythonRef::GetAttr(const char* name) const -> PythonRef { + assert(g_python); + assert(Python::HaveGIL()); + BA_PRECONDITION(obj_); + PyObject* val = PyObject_GetAttrString(get(), name); + if (!val) { + PyErr_Clear(); + throw Exception("Attribute not found: '" + std::string(name) + "'.", + PyExcType::kAttribute); + } + return PythonRef(val, PythonRef::kSteal); +} + +auto PythonRef::NewRef() const -> PyObject* { + assert(Python::HaveGIL()); + if (obj_ == nullptr) { + throw Exception("PythonRef::NewRef() called with nullptr obj_"); + } + Py_INCREF(obj_); + return obj_; +} + +auto PythonRef::CallableCheck() const -> bool { + BA_PRECONDITION(obj_); + assert(Python::HaveGIL()); + return static_cast(PyCallable_Check(obj_)); +} + +auto PythonRef::Call(PyObject* args, PyObject* keywds, bool print_errors) const + -> PythonRef { + assert(obj_); + assert(g_python); + assert(Python::HaveGIL()); + assert(CallableCheck()); + assert(args); + assert(PyTuple_Check(args)); // NOLINT (signed bitwise stuff) + assert(!keywds || PyDict_Check(keywds)); // NOLINT (signed bitwise) + PyObject* out = PyObject_Call(obj_, args, keywds); + if (!out) { + if (print_errors) { + // Save/restore error or it can mess with context print calls. + BA_PYTHON_ERROR_SAVE; + Log("ERROR: exception in Python call:"); + Python::LogContextAuto(); + BA_PYTHON_ERROR_RESTORE; + + // We pass zero here to avoid grabbing references to this exception + // which can cause objects to stick around and trip up our deletion checks + // (nodes, actors existing after their games have ended). + PyErr_PrintEx(0); + } + PyErr_Clear(); + } + return out ? PythonRef(out, PythonRef::kSteal) : PythonRef(); +} + +auto PythonRef::Call() const -> PythonRef { + return Call(g_python->obj(Python::ObjID::kEmptyTuple).get()); +} + +auto PythonRef::Call(const Vector2f& val) const -> PythonRef { + assert(Python::HaveGIL()); + PythonRef args(Py_BuildValue("((ff))", val.x, val.y), PythonRef::kSteal); + return Call(args); +} + +PythonRef::~PythonRef() { Release(); } + +#pragma clang diagnostic pop + +} // namespace ballistica diff --git a/src/ballistica/python/python_ref.h b/src/ballistica/python/python_ref.h new file mode 100644 index 00000000..5f26d38c --- /dev/null +++ b/src/ballistica/python/python_ref.h @@ -0,0 +1,130 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_PYTHON_REF_H_ +#define BALLISTICA_PYTHON_PYTHON_REF_H_ + +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +/// A simple managed Python object reference. +class PythonRef { + public: + /// Defines referencing behavior when creating new instances. + enum ReferenceBehavior { + /// Steal the provided object reference (and throw an Exception if it is + /// nullptr). + kSteal, + /// Steal the provided object reference or set as unreferenced if it is + /// nullptr. + kStealWeak, + /// Acquire a new reference to the provided object (and throw an Exception + /// if it is nullptr). + kAcquire, + /// Acquire a new reference to the provided object or set as unreferenced if + /// it is nullptr. + kAcquireWeak + }; + + /// Creates in an unreferenced state. + PythonRef() {} // NOLINT (using '= default' here errors) + + /// See ReferenceBehavior docs. + PythonRef(PyObject* other, ReferenceBehavior behavior); + + /// Copy constructor acquires a new reference (or sets as unreferenced) + /// depending on other. + PythonRef(const PythonRef& other) { *this = other; } + virtual ~PythonRef(); + + /// Assignment from another PythonRef acquires a reference to the object + /// referenced by other if there is one. If other has no reference, any + /// reference of ours is cleared to match. + auto operator=(const PythonRef& other) -> PythonRef& { + assert(this != &other); // Shouldn't be self-assigning. + if (other.exists()) { + Acquire(other.get()); + } else { + Release(); + } + return *this; + } + + /// Comparing to another PythonRef does a pointer comparison + /// (so basically the 'is' keyword in Python). + /// Note that two unreferenced PythonRefs will be equal. + auto operator==(const PythonRef& other) const -> bool { + return (get() == other.get()); + } + auto operator!=(const PythonRef& other) const -> bool { + return !(*this == other); + } + + /// Acquire a new reference to the passed object. Throws an exception if + /// nullptr is passed. + void Acquire(PyObject* obj); + + /// Steal the passed reference. Throws an Exception if nullptr is passed. + void Steal(PyObject* obj); + + /// Release the held reference (if one is held). + void Release(); + + /// Clear the ref without decrementing its count and return the raw PyObject* + auto HandOver() -> PyObject* { + assert(obj_); + PyObject* obj = obj_; + obj_ = nullptr; + return obj; + } + + /// Return the underlying PyObject pointer. + auto get() const -> PyObject* { return obj_; } + + /// Increment the ref-count for the underlying PyObject and return it as a + /// pointer. + auto NewRef() const -> PyObject*; + + /// Return whether we are pointing to a PyObject. + auto exists() const -> bool { return obj_ != nullptr; } + + /// Return a ref to an attribute on our PyObject or throw an Exception. + auto GetAttr(const char* name) const -> PythonRef; + + /// The equivalent of calling python str() on the contained PyObject. + auto Str() const -> std::string; + + /// The equivalent of calling repr() on the contained PyObject. + auto Repr() const -> std::string; + + /// For unicode, string, and ba.Lstr types, returns a utf8 string. + /// Throws an exception for other types. + auto ValueAsString() const -> std::string; + auto ValueAsInt() const -> int64_t; + + /// Returns whether the underlying PyObject is callable. + auto CallableCheck() const -> bool; + + /// Call the PyObject. On error, (optionally) prints errors and returns empty + /// ref. + auto Call(PyObject* args, PyObject* keywds = nullptr, + bool print_errors = true) const -> PythonRef; + auto Call(const PythonRef& args, const PythonRef& keywds = PythonRef(), + bool print_errors = true) const -> PythonRef { + return Call(args.get(), keywds.get(), print_errors); + } + auto Call() const -> PythonRef; + + /// Call with various args.. + auto Call(const Vector2f& val) const + -> PythonRef; // (val will be passed as tuple) + + private: + PyObject* obj_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_PYTHON_PYTHON_REF_H_ diff --git a/src/ballistica/python/python_sys.h b/src/ballistica/python/python_sys.h new file mode 100644 index 00000000..5afb2741 --- /dev/null +++ b/src/ballistica/python/python_sys.h @@ -0,0 +1,84 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PYTHON_PYTHON_SYS_H_ +#define BALLISTICA_PYTHON_PYTHON_SYS_H_ + +// Any code that actually runs any python logic should include this. +// This header pulls in the actual python includes and also defines some handy +// macros and functions for working with python objects. + +// This is the ONE place we actually include python. +#include +#include +#include + +#include + +// Saving/restoring Python error state; useful when function PyObject_Str() +// or other functionality is needed during error reporting; by default it +// craps out when an error is set. +#define BA_PYTHON_ERROR_SAVE \ + PyObject* pes_perr = nullptr; \ + PyObject* pes_pvalue = nullptr; \ + PyObject* pes_ptraceback = nullptr; \ + PyErr_Fetch(&pes_perr, &pes_pvalue, &pes_ptraceback) + +#define BA_PYTHON_ERROR_RESTORE \ + PyErr_Restore(pes_perr, pes_pvalue, pes_ptraceback) + +// Some macros to handle/propagate C++ exceptions within Python calls. +#define BA_PYTHON_TRY \ + try { \ + ((void)0) + +// Set Python error state based on the caught C++ exception and returns null. +#define BA_PYTHON_CATCH \ + } \ + catch (const Exception& e) { \ + e.SetPyError(); \ + return nullptr; \ + } \ + catch (const std::exception& e) { \ + PyErr_SetString(PyExc_RuntimeError, GetShortExceptionDescription(e)); \ + return nullptr; \ + } \ + ((void)0) + +// For use in tp_new; sets Python err, frees aborted self, returns null. +#define BA_PYTHON_NEW_CATCH \ + } \ + catch (const Exception& e) { \ + e.SetPyError(); \ + Py_TYPE(self)->tp_free(reinterpret_cast(self)); \ + return nullptr; \ + } \ + catch (const std::exception& e) { \ + PyErr_SetString(PyExc_RuntimeError, GetShortExceptionDescription(e)); \ + Py_TYPE(self)->tp_free(reinterpret_cast(self)); \ + return nullptr; \ + } \ + ((void)0) + +// For use in tp_dealloc; simply prints the error. +#define BA_PYTHON_DEALLOC_CATCH \ + } \ + catch (const std::exception& e) { \ + Log(std::string("Error: tp_dealloc exception: ") \ + + GetShortExceptionDescription(e)); \ + } \ + ((void)0) + +// Sets Python error and returns -1. +#define BA_PYTHON_INT_CATCH \ + } \ + catch (const Exception& e) { \ + e.SetPyError(); \ + return -1; \ + } \ + catch (const std::exception& e) { \ + PyErr_SetString(PyExc_RuntimeError, GetShortExceptionDescription(e)); \ + return -1; \ + } \ + ((void)0) + +#endif // BALLISTICA_PYTHON_PYTHON_SYS_H_ diff --git a/tools/batools/build.py b/tools/batools/build.py index 259df7f0..f80e6d6c 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -30,10 +30,10 @@ class PipRequirement: PIP_REQUIREMENTS = [ PipRequirement(modulename='pylint', minversion=[2, 6, 0]), - PipRequirement(modulename='mypy', minversion=[0, 782]), + PipRequirement(modulename='mypy', minversion=[0, 790]), PipRequirement(modulename='yapf', minversion=[0, 30, 0]), PipRequirement(modulename='cpplint', minversion=[1, 5, 4]), - PipRequirement(modulename='pytest', minversion=[6, 0, 2]), + PipRequirement(modulename='pytest', minversion=[6, 1, 1]), PipRequirement(modulename='typing_extensions'), PipRequirement(modulename='pytz'), PipRequirement(modulename='yaml', pipname='PyYAML'), diff --git a/tools/efro/util.py b/tools/efro/util.py index 1140ba27..4cbeb88f 100644 --- a/tools/efro/util.py +++ b/tools/efro/util.py @@ -306,3 +306,45 @@ def make_hash(obj: Any) -> int: # NOTE: there is sorted works correctly because it compares only # unique first values (i.e. dict keys) return hash(tuple(frozenset(sorted(new_obj.items())))) + + +def asserttype(obj: Any, typ: Type[T]) -> T: + """Return an object typed as a given type. + + Assert is used to check its actual type, so only use this when + failures are not expected. Otherwise use checktype. + """ + assert isinstance(obj, typ) + return obj + + +def checktype(obj: Any, typ: Type[T]) -> T: + """Return an object typed as a given type. + + Always checks the type at runtime with isinstance and throws a TypeError + on failure. Use asserttype for more efficient (but less safe) equivalent. + """ + if not isinstance(obj, typ): + raise TypeError(f'Expected a {typ}; got a {type(obj)}.') + return obj + + +def assert_non_optional(obj: Optional[T]) -> T: + """Return an object with Optional typing removed. + + Assert is used to check its actual type, so only use this when + failures are not expected. Use check_non_optional otherwise. + """ + assert obj is not None + return obj + + +def check_non_optional(obj: Optional[T]) -> T: + """Return an object with Optional typing removed. + + Always checks the actual type and throws a TypeError on failure. + Use assert_non_optional for a more efficient (but less safe) equivalent. + """ + if obj is None: + raise TypeError('Got None value in check_non_optional.') + return obj From c549d2f372148ad4b122a5a4e80c1c88ec98589f Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 09:43:44 -0700 Subject: [PATCH 232/417] Tidying --- .efrocachemap | 20 +++++++++---------- .../.idea/dictionaries/ericf.xml | 1 - ballisticacore-cmake/CMakeLists.txt | 2 +- docs/ba_module.md | 2 +- src/ballistica/ballistica.cc | 2 +- src/ballistica/game/game.h | 3 --- src/ballistica/python/python.h | 5 ----- 7 files changed, 13 insertions(+), 22 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index c3d10c8a..1a30a79c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3934,14 +3934,14 @@ "assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/6b/43/efceea678ab45ebe36c72ff6fa79", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/15/d5/29d9b25931f5c91a7a0db8cd6260", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/bc/bf/286df9a4a78d01c5bd02bee224cd", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/24/d5/6f25f7ffbdcf3dde835ca8213544", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/d1/f745c2663299168c982f752802d0", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/9b/dd/90e274f18a93c82e9c2c29a59b41", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9d/9a/c14692e42e5a7376b665af6a8463", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/2a/c8/f661b157edda3920f8834124d24b", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7e/ed/5db67414f8d9444f91631a448bc0", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/7d/9f/9ff4e4c2d64c3dfac362f2b5af15" + "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/26/3b/ea7dd76e5cf6407dc7e20576f191", + "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ed/2a/ba83223990092ce3a4eafd491c76", + "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/cd/67cb2a544dada857323d01ff6337", + "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fc/8c/2bbe38abf6f4e718f9af83d5b120", + "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/9a/ed85e7110f940e24a3358fd01b39", + "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/94/406ef9f6014282c1852190765faf", + "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ef/13/78a497e9a6055369470bf58d318e", + "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/10/42/5a50d344b3adb1441bbd14e244ed", + "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3f/00/85d7560c026c81847d6591ab2c7f", + "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/fb/f7017b6091830f47194a37e5d63f" } \ No newline at end of file diff --git a/ballisticacore-cmake/.idea/dictionaries/ericf.xml b/ballisticacore-cmake/.idea/dictionaries/ericf.xml index 2467a179..db058f62 100644 --- a/ballisticacore-cmake/.idea/dictionaries/ericf.xml +++ b/ballisticacore-cmake/.idea/dictionaries/ericf.xml @@ -398,7 +398,6 @@ ifaddr ifaddrs ifdebug - iiarcade iiiiisss illum ilock diff --git a/ballisticacore-cmake/CMakeLists.txt b/ballisticacore-cmake/CMakeLists.txt index 81fd98a8..967dbef0 100644 --- a/ballisticacore-cmake/CMakeLists.txt +++ b/ballisticacore-cmake/CMakeLists.txt @@ -183,7 +183,7 @@ target_include_directories(ballisticacore PRIVATE ${EXTRA_INCLUDE_DIRS} ) -# NOTE: seems we need to add 'dl' here for raspberry pi with manually +# NOTE: seems we need to add 'dl' here for raspberry pi with a manually # built Python 3.8. Might be able to remove later. target_link_libraries(ballisticacore PRIVATE ballisticacore_private ode pthread ${Python_LIBRARIES} diff --git a/docs/ba_module.md b/docs/ba_module.md index 4b1bcdc7..e7465286 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-10-09 for Ballistica version 1.5.26 build 20198

    +

    last updated on 2020-10-10 for Ballistica version 1.5.26 build 20199

    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!


    diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 1ba009e9..8956bf88 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,7 +29,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20198; +const int kAppBuildNumber = 20199; const char* kAppVersion = "1.5.26"; // Our standalone globals. diff --git a/src/ballistica/game/game.h b/src/ballistica/game/game.h index c09334eb..7dabd7ad 100644 --- a/src/ballistica/game/game.h +++ b/src/ballistica/game/game.h @@ -336,9 +336,6 @@ class Game : public Module { private: auto InitSpecialChars() -> void; - auto AdViewComplete(const std::string& purpose, bool actually_showed) -> void; - auto AwardAdTickets() -> void; - auto AwardAdTournamentEntry() -> void; auto Draw() -> void; auto UDPConnectionPacket(const std::vector& data, const SockAddr& addr) -> void; diff --git a/src/ballistica/python/python.h b/src/ballistica/python/python.h index 6efe9fbe..78985b75 100644 --- a/src/ballistica/python/python.h +++ b/src/ballistica/python/python.h @@ -112,11 +112,6 @@ class Python { auto inited() const -> bool { return inited_; } - /// Attempt to push the log to the server - returns true if no error occurs - /// (note; this doesn't mean that the log actually made it; just that it got - /// sent off) - static auto PutLog(bool fatal, bool short_suicide_timer = true) -> bool; - /// Filter incoming chat message from client. /// If returns false, message should be ignored. auto FilterChatMessage(std::string* message, int client_id) -> bool; From 94dce555c886b882d7cdb35895d3ce59da80b3e9 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 14:53:24 -0700 Subject: [PATCH 233/417] groundwork for ARM support in prefab builds --- .efrocachemap | 24 +- .idea/dictionaries/ericf.xml | 2 + Makefile | 404 +++++++++++++++++----------- ballisticacore-cmake/CMakeLists.txt | 2 +- tools/batools/build.py | 19 +- tools/batools/pcommand.py | 5 + 6 files changed, 278 insertions(+), 178 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 1a30a79c..b3087f56 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,16 +3932,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ac/96/c3b9934061393fe09cc90ff24b8d", - "build/prefab/linux-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/38/2b/5641b3b40846f74f232771ac0457", - "build/prefab/linux/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/26/3b/ea7dd76e5cf6407dc7e20576f191", - "build/prefab/linux/release/ballisticacore": "https://files.ballistica.net/cache/ba1/ed/2a/ba83223990092ce3a4eafd491c76", - "build/prefab/mac-server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fe/cd/67cb2a544dada857323d01ff6337", - "build/prefab/mac-server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fc/8c/2bbe38abf6f4e718f9af83d5b120", - "build/prefab/mac/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3d/9a/ed85e7110f940e24a3358fd01b39", - "build/prefab/mac/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f7/94/406ef9f6014282c1852190765faf", - "build/prefab/windows-server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/ef/13/78a497e9a6055369470bf58d318e", - "build/prefab/windows-server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/10/42/5a50d344b3adb1441bbd14e244ed", - "build/prefab/windows/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3f/00/85d7560c026c81847d6591ab2c7f", - "build/prefab/windows/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/80/fb/f7017b6091830f47194a37e5d63f" + "build/prefab/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/be/d2d88cedd80218236cace5782990", + "build/prefab/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/be/9d/3dc0431a002e197163134a5dc881", + "build/prefab/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c0/d3/95030ef9319c3c8ed13e75254583", + "build/prefab/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/f7/170ffdbec21643a4a80e181023b3", + "build/prefab/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/62/c7a083e3aa2f93005c5354678207", + "build/prefab/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e5/c4/e5be2fa6ebe5ff81a99c3608a73d", + "build/prefab/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/0e/902db411f7298917a8d3b0b13ec2", + "build/prefab/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fd/0f/8bc3a7dc565a0dd376f124d747d5", + "build/prefab/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3c/78/d8cd734a0ccab60c2e0ea3a97370", + "build/prefab/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2b/b7/c193aa65c8adf613f543036b8af4", + "build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/37/68bc656f1f94994754301d0c742e", + "build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/d1/db8211bd2df1e435dcb7f6823fc2" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 37848787..188136d2 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -349,6 +349,7 @@ cmds cmembers cmodel + cmpf cnode codecsmodule codefilenames @@ -2266,6 +2267,7 @@ winempty winnergroup winnergroups + winplat winplt winprj winprune diff --git a/Makefile b/Makefile index 6d8b04e7..dfd5d3ed 100644 --- a/Makefile +++ b/Makefile @@ -151,293 +151,388 @@ prefab-server-release-build: # Specific platform prefab targets: -RUN_PREFAB_MAC_DEBUG = cd build/prefab/mac/debug && ./ballisticacore +RUN_PREFAB_MAC_X86_64_DEBUG = cd build/prefab/mac_x86_64/debug \ + && ./ballisticacore -prefab-mac-debug: prefab-mac-debug-build - @tools/pcommand ensure_prefab_platform mac - @${RUN_PREFAB_MAC_DEBUG} +RUN_PREFAB_MAC_ARM64_DEBUG = cd build/prefab/mac_arm64/debug \ + && ./ballisticacore -prefab-mac-debug-build: prereqs assets-cmake \ - build/prefab/mac/debug/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/mac/debug +prefab-mac-x86-64-debug: prefab-mac-x86-64-debug-build + @tools/pcommand ensure_prefab_platform mac_x86_64 + @${RUN_PREFAB_MAC_X86_64_DEBUG} -build/prefab/mac/debug/ballisticacore: .efrocachemap +prefab-mac-arm64-debug: prefab-mac-arm64-debug-build + @tools/pcommand ensure_prefab_platform mac_arm64 + @${RUN_PREFAB_MAC_ARM64_DEBUG} + +prefab-mac-x86-64-debug-build: prereqs assets-cmake \ + build/prefab/mac_x86_64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/mac_x86_64/debug + +prefab-mac-arm64-debug-build: prereqs assets-cmake \ + build/prefab/mac_arm64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/mac_arm64/debug + +build/prefab/mac_%/debug/ballisticacore: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_MAC_RELEASE = cd build/prefab/mac/release && ./ballisticacore +RUN_PREFAB_MAC_X86_64_RELEASE = cd build/prefab/mac_x86_64/release \ + && ./ballisticacore -prefab-mac-release: prefab-mac-release-build - @tools/pcommand ensure_prefab_platform mac - @${RUN_PREFAB_MAC_RELEASE} +RUN_PREFAB_MAC_ARM64_RELEASE = cd build/prefab/mac_arm64/release \ + && ./ballisticacore -prefab-mac-release-build: prereqs assets-cmake \ - build/prefab/mac/release/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/mac/release +prefab-mac-x86-64-release: prefab-mac-x86-64-release-build + @tools/pcommand ensure_prefab_platform mac_x86_64 + @${RUN_PREFAB_MAC_X86_64_RELEASE} -build/prefab/mac/release/ballisticacore: .efrocachemap +prefab-mac-arm64-release: prefab-mac-arm64-release-build + @tools/pcommand ensure_prefab_platform mac_arm64 + @${RUN_PREFAB_MAC_ARM64_RELEASE} + +prefab-mac-x86-64-release-build: prereqs assets-cmake \ + build/prefab/mac_x86_64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/mac_x86_64/release + +prefab-mac-arm64-release-build: prereqs assets-cmake \ + build/prefab/mac_arm64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/mac_arm64/release + +build/prefab/mac_%/release/ballisticacore: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_MAC_SERVER_DEBUG = cd build/prefab/mac-server/debug \ +RUN_PREFAB_MAC_X86_64_SERVER_DEBUG = cd build/prefab/mac_x86_64_server/debug \ && ./ballisticacore_server -prefab-mac-server-debug: prefab-mac-server-debug-build - @tools/pcommand ensure_prefab_platform mac - @${RUN_PREFAB_MAC_SERVER_DEBUG} +RUN_PREFAB_MAC_ARM64_SERVER_DEBUG = cd build/prefab/mac_arm64_server/debug \ + && ./ballisticacore_server -prefab-mac-server-debug-build: prereqs assets-cmake \ - build/prefab/mac-server/debug/dist/ballisticacore_headless \ - build/prefab/mac-server/debug/ballisticacore_server \ - build/prefab/mac-server/debug/config_template.yaml \ - build/prefab/mac-server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/debug/dist +prefab-mac-x86-64-server-debug: prefab-mac-x86-64-server-debug-build + @tools/pcommand ensure_prefab_platform mac_x86_64 + @${RUN_PREFAB_MAC_X86_64_SERVER_DEBUG} -build/prefab/mac-server/debug/ballisticacore_server: \ +prefab-mac-arm64-server-debug: prefab-mac-arm64-server-debug-build + @tools/pcommand ensure_prefab_platform mac_arm64 + @${RUN_PREFAB_MAC_ARM64_SERVER_DEBUG} + +prefab-mac-x86-64-server-debug-build: prereqs assets-cmake \ + build/prefab/mac_x86_64_server/debug/dist/ballisticacore_headless \ + build/prefab/mac_x86_64_server/debug/ballisticacore_server \ + build/prefab/mac_x86_64_server/debug/config_template.yaml \ + build/prefab/mac_x86_64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/mac_x86_64_server/debug/dist + +prefab-mac-arm64-server-debug-build: prereqs assets-cmake \ + build/prefab/mac_arm64_server/debug/dist/ballisticacore_headless \ + build/prefab/mac_arm64_server/debug/ballisticacore_server \ + build/prefab/mac_arm64_server/debug/config_template.yaml \ + build/prefab/mac_arm64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/mac_arm64_server/debug/dist + +build/prefab/mac_%_server/debug/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/mac-server/debug/config_template.yaml: \ +build/prefab/mac_%_server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/mac-server/debug/README.txt: \ +build/prefab/mac_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/mac-server/debug/dist/ballisticacore_headless: .efrocachemap +build/prefab/mac_%_server/debug/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_MAC_SERVER_RELEASE = cd build/prefab/mac-server/release \ - && ./ballisticacore_server +RUN_PREFAB_MAC_X86_64_SERVER_RELEASE = cd \ + build/prefab/mac_x86_64_server/release && ./ballisticacore_server -prefab-mac-server-release: prefab-mac-server-release-build - @tools/pcommand ensure_prefab_platform mac - @${RUN_PREFAB_MAC_SERVER_RELEASE} +RUN_PREFAB_MAC_ARM64_SERVER_RELEASE = cd \ + build/prefab/mac_arm64_server/release && ./ballisticacore_server -prefab-mac-server-release-build: prereqs assets-cmake \ - build/prefab/mac-server/release/dist/ballisticacore_headless \ - build/prefab/mac-server/release/ballisticacore_server \ - build/prefab/mac-server/release/config_template.yaml \ - build/prefab/mac-server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/mac-server/release/dist +prefab-mac-x86-64-server-release: prefab-mac-x86-64-server-release-build + @tools/pcommand ensure_prefab_platform mac_x86_64 + @${RUN_PREFAB_MAC_X86_64_SERVER_RELEASE} -build/prefab/mac-server/release/ballisticacore_server: \ +prefab-mac-arm64-server-release: prefab-mac-arm64-server-release-build + @tools/pcommand ensure_prefab_platform mac_arm64 + @${RUN_PREFAB_MAC_ARM64_SERVER_RELEASE} + +prefab-mac-x86-64-server-release-build: prereqs assets-cmake \ + build/prefab/mac_x86_64_server/release/dist/ballisticacore_headless \ + build/prefab/mac_x86_64_server/release/ballisticacore_server \ + build/prefab/mac_x86_64_server/release/config_template.yaml \ + build/prefab/mac_x86_64_server/release/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/mac_x86_64_server/release/dist + +prefab-mac-arm64-server-release-build: prereqs assets-cmake \ + build/prefab/mac_arm64_server/release/dist/ballisticacore_headless \ + build/prefab/mac_arm64_server/release/ballisticacore_server \ + build/prefab/mac_arm64_server/release/config_template.yaml \ + build/prefab/mac_arm64_server/release/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/mac_arm64_server/release/dist + +build/prefab/mac_%_server/release/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/mac-server/release/config_template.yaml: \ +build/prefab/mac_%_server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file release $< $@ -build/prefab/mac-server/release/README.txt: \ +build/prefab/mac_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/mac-server/release/dist/ballisticacore_headless: .efrocachemap +build/prefab/mac_%_server/release/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_LINUX_DEBUG = cd build/prefab/linux/debug && ./ballisticacore +RUN_PREFAB_LINUX_X86_64_DEBUG = cd \ + build/prefab/linux_x86_64/debug && ./ballisticacore -prefab-linux-debug: prefab-linux-debug-build - @tools/pcommand ensure_prefab_platform linux - @${RUN_PREFAB_LINUX_DEBUG} +RUN_PREFAB_LINUX_ARM64_DEBUG = cd \ + build/prefab/linux_arm64/debug && ./ballisticacore -prefab-linux-debug-build: prereqs assets-cmake \ - build/prefab/linux/debug/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/linux/debug +prefab-linux-x86-64-debug: prefab-linux-x86-64-debug-build + @tools/pcommand ensure_prefab_platform linux_x86_64 + @${RUN_PREFAB_LINUX_X86_64_DEBUG} -build/prefab/linux/debug/ballisticacore: .efrocachemap +prefab-linux-arm64-debug: prefab-linux-arm64-debug-build + @tools/pcommand ensure_prefab_platform linux_arm64 + @${RUN_PREFAB_LINUX_ARM64_DEBUG} + +prefab-linux-x86-64-debug-build: prereqs assets-cmake \ + build/prefab/linux_x86_64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/linux_x86_64/debug + +prefab-linux-arm64-debug-build: prereqs assets-cmake \ + build/prefab/linux_arm64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/linux_arm64/debug + +build/prefab/linux_%/debug/ballisticacore: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_LINUX_RELEASE = cd build/prefab/linux/release && ./ballisticacore +RUN_PREFAB_LINUX_X86_64_RELEASE = cd \ + build/prefab/linux_x86_64/release && ./ballisticacore -prefab-linux-release: prefab-linux-release-build - @tools/pcommand ensure_prefab_platform linux - @${RUN_PREFAB_LINUX_RELEASE} +RUN_PREFAB_LINUX_ARM64_RELEASE = cd \ + build/prefab/linux_arm64/release && ./ballisticacore -prefab-linux-release-build: prereqs assets-cmake \ - build/prefab/linux/release/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/linux/release +prefab-linux-x86-64-release: prefab-linux-x86-64-release-build + @tools/pcommand ensure_prefab_platform linux_x86_64 + @${RUN_PREFAB_LINUX_X86_64_RELEASE} -build/prefab/linux/release/ballisticacore: .efrocachemap +prefab-linux-arm64-release: prefab-linux-arm64-release-build + @tools/pcommand ensure_prefab_platform linux_arm64 + @${RUN_PREFAB_LINUX_ARM64_RELEASE} + +prefab-linux-x86-64-release-build: prereqs assets-cmake \ + build/prefab/linux_x86_64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/linux_x86_64/release + +prefab-linux-arm64-release-build: prereqs assets-cmake \ + build/prefab/linux_arm64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/linux_arm64/release + +build/prefab/linux_%/release/ballisticacore: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_LINUX_SERVER_DEBUG = cd build/prefab/linux-server/debug \ - && ./ballisticacore_server +RUN_PREFAB_LINUX_X86_64_SERVER_DEBUG = cd \ + build/prefab/linux_x86_64_server/debug && ./ballisticacore_server -prefab-linux-server-debug: prefab-linux-server-debug-build - @tools/pcommand ensure_prefab_platform linux - @${RUN_PREFAB_LINUX_SERVER_DEBUG} +RUN_PREFAB_LINUX_ARM64_SERVER_DEBUG = cd \ + build/prefab/linux_arm64_server/debug && ./ballisticacore_server -prefab-linux-server-debug-build: prereqs assets-cmake \ - build/prefab/linux-server/debug/dist/ballisticacore_headless \ - build/prefab/linux-server/debug/ballisticacore_server \ - build/prefab/linux-server/debug/config_template.yaml \ - build/prefab/linux-server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/debug/dist +prefab-linux-x86-64-server-debug: prefab-linux-x86-64-server-debug-build + @tools/pcommand ensure_prefab_platform linux_x86_64 + @${RUN_PREFAB_LINUX_X86_64_SERVER_DEBUG} -build/prefab/linux-server/debug/ballisticacore_server: \ +prefab-linux-arm64-server-debug: prefab-linux-arm64-server-debug-build + @tools/pcommand ensure_prefab_platform linux_arm64 + @${RUN_PREFAB_LINUX_ARM64_SERVER_DEBUG} + +prefab-linux-x86-64-server-debug-build: prereqs assets-cmake \ + build/prefab/linux_x86_64_server/debug/dist/ballisticacore_headless \ + build/prefab/linux_x86_64_server/debug/ballisticacore_server \ + build/prefab/linux_x86_64_server/debug/config_template.yaml \ + build/prefab/linux_x86_64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/linux_x86_64_server/debug/dist + +prefab-linux-arm64-server-debug-build: prereqs assets-cmake \ + build/prefab/linux_arm64_server/debug/dist/ballisticacore_headless \ + build/prefab/linux_arm64_server/debug/ballisticacore_server \ + build/prefab/linux_arm64_server/debug/config_template.yaml \ + build/prefab/linux_arm64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/linux_arm64_server/debug/dist + +build/prefab/linux_%_server/debug/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/linux-server/debug/config_template.yaml: \ +build/prefab/linux_%_server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/linux-server/debug/README.txt: \ +build/prefab/linux_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/linux-server/debug/dist/ballisticacore_headless: .efrocachemap +build/prefab/linux_%_server/debug/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_LINUX_SERVER_RELEASE = cd build/prefab/linux-server/release \ - && ./ballisticacore_server +RUN_PREFAB_LINUX_X86_64_SERVER_RELEASE = cd \ + build/prefab/linux_x86_64_server/release && ./ballisticacore_server -prefab-linux-server-release: prefab-linux-server-release-build - @tools/pcommand ensure_prefab_platform linux - @${RUN_PREFAB_LINUX_SERVER_RELEASE} +RUN_PREFAB_LINUX_ARM64_SERVER_RELEASE = cd \ + build/prefab/linux_arm64_server/release && ./ballisticacore_server -prefab-linux-server-release-build: prereqs assets-cmake \ - build/prefab/linux-server/release/dist/ballisticacore_headless \ - build/prefab/linux-server/release/ballisticacore_server \ - build/prefab/linux-server/release/config_template.yaml \ - build/prefab/linux-server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/linux-server/release/dist +prefab-linux-x86-64-server-release: prefab-linux-x86-64-server-release-build + @tools/pcommand ensure_prefab_platform linux_x86_64 + @${RUN_PREFAB_LINUX_X86_64_SERVER_RELEASE} -build/prefab/linux-server/release/ballisticacore_server: \ +prefab-linux-x86-64-server-release-build: prereqs assets-cmake \ + build/prefab/linux_x86_64_server/release/dist/ballisticacore_headless \ + build/prefab/linux_x86_64_server/release/ballisticacore_server \ + build/prefab/linux_x86_64_server/release/config_template.yaml \ + build/prefab/linux_x86_64_server/release/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/linux_x86_64_server/release/dist + +build/prefab/linux_%_server/release/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/linux-server/release/config_template.yaml: \ +build/prefab/linux_%_server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file release $< $@ -build/prefab/linux-server/release/README.txt: \ +build/prefab/linux_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/linux-server/release/dist/ballisticacore_headless: .efrocachemap +build/prefab/linux_%_server/release/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ -PREFAB_WINDOWS_PLATFORM = Win32 +WINPLAT_X86 = Win32 -RUN_PREFAB_WINDOWS_DEBUG = cd build/prefab/windows/debug && ./BallisticaCore.exe +RUN_PREFAB_WINDOWS_X86_DEBUG = cd build/prefab/windows_x86/debug \ + && ./BallisticaCore.exe -prefab-windows-debug: prefab-windows-debug-build - @tools/pcommand ensure_prefab_platform windows - @{RUN_PREFAB_WINDOWS_DEBUG} +prefab-windows-x86-debug: prefab-windows-x86-debug-build + @tools/pcommand ensure_prefab_platform windows_x86 + @{RUN_PREFAB_WINDOWS_X86_DEBUG} -prefab-windows-debug-build: prereqs assets-windows-${PREFAB_WINDOWS_PLATFORM} \ - build/prefab/windows/debug/BallisticaCore.exe - @${STAGE_ASSETS} -win-${PREFAB_WINDOWS_PLATFORM}-Debug \ -build/prefab/windows/debug +prefab-windows-x86-debug-build: prereqs assets-windows-${WINPLAT_X86} \ + build/prefab/windows_x86/debug/BallisticaCore.exe + @${STAGE_ASSETS} -win-${WINPLAT_X86}-Debug \ +build/prefab/windows_x86/debug -build/prefab/windows/debug/BallisticaCore.exe: .efrocachemap +build/prefab/windows_x86/debug/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_WINDOWS_RELEASE = cd build/prefab/windows/release \ +RUN_PREFAB_WINDOWS_X86_RELEASE = cd build/prefab/windows_x86/release \ && ./BallisticaCore.exe -prefab-windows-release: prefab-windows-release-build - @tools/pcommand ensure_prefab_platform windows - @{RUN_PREFAB_WINDOWS_RELEASE} +prefab-windows-x86-release: prefab-windows-x86-release-build + @tools/pcommand ensure_prefab_platform windows_x86 + @{RUN_PREFAB_WINDOWS_X86_RELEASE} -prefab-windows-release-build: prereqs \ - assets-windows-${PREFAB_WINDOWS_PLATFORM} \ - build/prefab/windows/release/BallisticaCore.exe - @${STAGE_ASSETS} -win-${PREFAB_WINDOWS_PLATFORM}-Release \ -build/prefab/windows/release +prefab-windows-x86-release-build: prereqs \ + assets-windows-${WINPLAT_X86} \ + build/prefab/windows_x86/release/BallisticaCore.exe + @${STAGE_ASSETS} -win-${WINPLAT_X86}-Release \ +build/prefab/windows_x86/release -build/prefab/windows/release/BallisticaCore.exe: .efrocachemap +build/prefab/windows_x86/release/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_WINDOWS_SERVER_DEBUG = cd build/prefab/windows-server/debug \ +RUN_PREFAB_WINDOWS_X86_SERVER_DEBUG = cd build/prefab/windows_x86_server/debug \ && dist/python.exe ballisticacore_server.py -prefab-windows-server-debug: prefab-windows-server-debug-build - @tools/pcommand ensure_prefab_platform windows - @{RUN_PREFAB_WINDOWS_SERVER_DEBUG} +prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build + @tools/pcommand ensure_prefab_platform windows_x86 + @{RUN_PREFAB_WINDOWS_X86_SERVER_DEBUG} -prefab-windows-server-debug-build: prereqs \ - assets-windows-${PREFAB_WINDOWS_PLATFORM} \ - build/prefab/windows-server/debug/dist/ballisticacore_headless.exe \ - build/prefab/windows-server/debug/launch_ballisticacore_server.bat \ - build/prefab/windows-server/debug/ballisticacore_server.py \ - build/prefab/windows-server/debug/config_template.yaml \ - build/prefab/windows-server/debug/README.txt - @${STAGE_ASSETS} -winserver-${PREFAB_WINDOWS_PLATFORM}-Debug \ - build/prefab/windows-server/debug/dist +prefab-windows-x86-server-debug-build: prereqs \ + assets-windows-${WINPLAT_X86} \ + build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe \ + build/prefab/windows_x86_server/debug/launch_ballisticacore_server.bat \ + build/prefab/windows_x86_server/debug/ballisticacore_server.py \ + build/prefab/windows_x86_server/debug/config_template.yaml \ + build/prefab/windows_x86_server/debug/README.txt + @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Debug \ + build/prefab/windows_x86_server/debug/dist -build/prefab/windows-server/debug/dist/ballisticacore_headless.exe: .efrocachemap +build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe: .efrocachemap @tools/pcommand efrocache_get $@ -build/prefab/windows-server/debug/ballisticacore_server.py: \ +build/prefab/windows_%_server/debug/ballisticacore_server.py: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/windows-server/debug/launch_ballisticacore_server.bat: \ +build/prefab/windows_%_server/debug/launch_ballisticacore_server.bat: \ assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/windows-server/debug/config_template.yaml: \ +build/prefab/windows_%_server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/windows-server/debug/README.txt: \ +build/prefab/windows_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ -RUN_PREFAB_WINDOWS_SERVER_RELEASE = cd build/prefab/windows-server/release \ - && dist/python.exe -O ballisticacore_server.py +RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE = cd \ + build/prefab/windows_x86_server/release \ + && dist/python.exe -O ballisticacore_server.py -prefab-windows-server-release: prefab-windows-server-release-build - @tools/pcommand ensure_prefab_platform windows - @{RUN_PREFAB_WINDOWS_SERVER_RELEASE} +prefab-windows-x86-server-release: prefab-windows-x86-server-release-build + @tools/pcommand ensure_prefab_platform windows_x86 + @{RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE} -prefab-windows-server-release-build: prereqs \ - assets-windows-${PREFAB_WINDOWS_PLATFORM} \ - build/prefab/windows-server/release/dist/ballisticacore_headless.exe \ - build/prefab/windows-server/release/launch_ballisticacore_server.bat \ - build/prefab/windows-server/release/ballisticacore_server.py \ - build/prefab/windows-server/release/config_template.yaml \ - build/prefab/windows-server/release/README.txt - @${STAGE_ASSETS} -winserver-${PREFAB_WINDOWS_PLATFORM}-Release \ - build/prefab/windows-server/release/dist +prefab-windows-x86-server-release-build: prereqs \ + assets-windows-${WINPLAT_X86} \ + build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe \ + build/prefab/windows_x86_server/release/launch_ballisticacore_server.bat \ + build/prefab/windows_x86_server/release/ballisticacore_server.py \ + build/prefab/windows_x86_server/release/config_template.yaml \ + build/prefab/windows_x86_server/release/README.txt + @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Release \ + build/prefab/windows_x86_server/release/dist -build/prefab/windows-server/release/dist/ballisticacore_headless.exe: .efrocachemap +build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe: .efrocachemap @tools/pcommand efrocache_get $@ -build/prefab/windows-server/release/ballisticacore_server.py: \ +build/prefab/windows_%_server/release/ballisticacore_server.py: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/windows-server/release/launch_ballisticacore_server.bat: \ +build/prefab/windows_%_server/release/launch_ballisticacore_server.bat: \ assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/windows-server/release/config_template.yaml: \ +build/prefab/windows_%_server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file release $< $@ -build/prefab/windows-server/release/README.txt: \ +build/prefab/windows_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ @@ -768,19 +863,12 @@ ENV_SRC = tools/pcommand tools/batools/build.py @mkdir -p .cache @touch .cache/checkenv -# Tell make which of these targets don't represent files. -.PHONY: - - -################################################################################ -# # -# Auxiliary # -# # -################################################################################ - # CMake build-type lowercase CM_BT_LC = $(shell echo $(CMAKE_BUILD_TYPE) | tr A-Z a-z) # When using CLion, our cmake dir is root. Expose .clang-format there too. ballisticacore-cmake/.clang-format: .clang-format @cd ballisticacore-cmake && ln -sf ../.clang-format . + +# Tell make which of these targets don't represent files. +.PHONY: diff --git a/ballisticacore-cmake/CMakeLists.txt b/ballisticacore-cmake/CMakeLists.txt index 967dbef0..4de0a9f7 100644 --- a/ballisticacore-cmake/CMakeLists.txt +++ b/ballisticacore-cmake/CMakeLists.txt @@ -186,5 +186,5 @@ target_include_directories(ballisticacore PRIVATE # NOTE: seems we need to add 'dl' here for raspberry pi with a manually # built Python 3.8. Might be able to remove later. target_link_libraries(ballisticacore PRIVATE - ballisticacore_private ode pthread ${Python_LIBRARIES} + ballisticacore_internal ode pthread ${Python_LIBRARIES} ${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl) diff --git a/tools/batools/build.py b/tools/batools/build.py index f80e6d6c..2d09ee9b 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -455,19 +455,24 @@ def get_current_prefab_platform() -> str: system = platform.system() machine = platform.machine() if system == 'Darwin': - # Currently there's just x86_64 on mac; - # will need to revisit when arm - # cpus happen. - return 'mac' + if machine == 'x86_64': + return 'mac_x86_64' + # TODO: add support for arm macs. + raise RuntimeError(f'make_prefab: unsupported mac machine type:' + f' {machine}.') if system == 'Linux': # If it looks like we're in Windows Subsystem for Linux, # go with the Windows version. if 'microsoft' in platform.uname().release.lower(): - return 'windows' + # TODO: add support for arm windows + if machine == 'x86_64': + return 'windows_x86' + raise RuntimeError(f'make_prefab: unsupported win machine type:' + f' {machine}.') - # We currently only support x86_64 linux. + # TODO: add support for arm linux. if machine == 'x86_64': - return 'linux' + return 'linux_x86_64' raise RuntimeError(f'make_prefab: unsupported linux machine type:' f' {machine}.') raise RuntimeError(f'make_prefab: unrecognized platform:' diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 227f089a..722e1c85 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -34,6 +34,8 @@ def stage_server_file() -> None: print(f'Building server file: {os.path.basename(outfilename)}') + os.makedirs(os.path.dirname(outfilename), exist_ok=True) + basename = os.path.basename(infilename) if basename == 'config_template.yaml': # Inject all available config values into the config file. @@ -581,6 +583,9 @@ def make_prefab() -> None: raise RuntimeError('Expected one argument') target = batools.build.PrefabTarget(sys.argv[2]) platform = batools.build.get_current_prefab_platform() + + # We use dashes instead of underscores in target names. + platform = platform.replace('_', '-') try: subprocess.run(['make', f'prefab-{platform}-{target.value}-build'], check=True) From 3c8cea09cb039c1124389a06fba679e6113c3886 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 15:23:58 -0700 Subject: [PATCH 234/417] Fixing windows prefab debug build --- tools/batools/assetstaging.py | 2 +- tools/batools/pcommand.py | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 3137d602..286c3198 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -263,7 +263,7 @@ def _sync_windows_extras(cfg: Config) -> None: 'SDL2.dll' ] elif cfg.win_type == 'winserver': - toplevelfiles += ['python.exe'] + toplevelfiles += [f'python{dbgsfx}.exe'] # Include debug dlls so folks without msvc can run them. if cfg.debug: diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 722e1c85..88e47418 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -57,14 +57,19 @@ def stage_server_file() -> None: # Run Python in opt mode for release builds. with open(infilename) as infile: lines = infile.read().splitlines() - if mode == 'release': - lines[1] = replace_one( - lines[1], ':: Python interpreter.', - ':: Python interpreter.' - ' (in opt mode so we use bundled .opt-1.pyc files)') - lines[2] = replace_one( - lines[2], 'dist\\\\python.exe ballisticacore_server.py', - 'dist\\\\python.exe -O ballisticacore_server.py') + if mode == 'release': + lines[1] = replace_one( + lines[1], ':: Python interpreter.', ':: Python interpreter.' + ' (in opt mode so we use bundled .opt-1.pyc files)') + lines[2] = replace_one( + lines[2], 'dist\\\\python.exe ballisticacore_server.py', + 'dist\\\\python.exe -O ballisticacore_server.py') + else: + # In debug mode we use the bundled debug interpreter. + lines[2] = replace_one( + lines[2], 'dist\\\\python.exe ballisticacore_server.py', + 'dist\\\\python_d.exe ballisticacore_server.py') + with open(outfilename, 'w') as outfile: outfile.write('\n'.join(lines) + '\n') else: From 812d9b269ac9690bb2d8e0dec27a76a04f5220c8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 15:30:38 -0700 Subject: [PATCH 235/417] Missed file --- tools/batools/assetstaging.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 286c3198..f5f5f672 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -252,8 +252,8 @@ def _sync_windows_extras(cfg: Config) -> None: _run(cmd) # Now sync the top level individual files that we want. - # (we could technically copy everything over but this keeps staging - # dirs a bit tidier) + # We could technically copy everything over but this keeps staging + # dirs a bit tidier. dbgsfx = '_d' if cfg.debug else '' toplevelfiles: List[str] = [f'python38{dbgsfx}.dll'] From caf6995b9b6e056513a1029410bcf28bf9a6b604 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 15:36:17 -0700 Subject: [PATCH 236/417] Another minor correction for win prefab --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index dfd5d3ed..b2377e88 100644 --- a/Makefile +++ b/Makefile @@ -458,7 +458,7 @@ build/prefab/windows_x86/release/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ RUN_PREFAB_WINDOWS_X86_SERVER_DEBUG = cd build/prefab/windows_x86_server/debug \ - && dist/python.exe ballisticacore_server.py + && dist/python_d.exe ballisticacore_server.py prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build @tools/pcommand ensure_prefab_platform windows_x86 From e72367d3c4b426ce4ba7aa60c8126938860180dd Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 16:39:53 -0700 Subject: [PATCH 237/417] Workaround for error due to case sensitive filenames under WSL --- tools/batools/assetstaging.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index f5f5f672..204e68d8 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -240,7 +240,11 @@ def _sync_windows_extras(cfg: Config) -> None: pyd_rules = "--exclude '*_d.pyd' --include '*.pyd'" for dirname in ('DLLs', 'Lib'): - _run(f'mkdir -p "{cfg.dst}/{dirname}"') + # EWW: seems windows python currently sets its path to ./lib but it + # comes with Lib. Windows is normally case-insensitive but this messes + # it up when running under WSL. Let's install it as lib for now. + dstdirname = 'lib' if dirname == 'Lib' else dirname + _run(f'mkdir -p "{cfg.dst}/{dstdirname}"') cmd = ('rsync --recursive --update --delete --delete-excluded ' ' --prune-empty-dirs' " --include '*.ico' --include '*.cat'" @@ -248,7 +252,7 @@ def _sync_windows_extras(cfg: Config) -> None: " --include '*.py' --include '*." + OPT_PYC_SUFFIX + "'" " --include '*/' --exclude '*' \"" + os.path.join(cfg.win_extras_src, dirname) + '/" ' - '"' + cfg.dst + '/' + dirname + '/"') + '"' + cfg.dst + '/' + dstdirname + '/"') _run(cmd) # Now sync the top level individual files that we want. From 105bab96784c2b3acc2a4140e3e7ab9b01c618a8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sat, 10 Oct 2020 16:48:34 -0700 Subject: [PATCH 238/417] More on same workaround... --- .efrocachemap | 24 ++++++++++++------------ docs/ba_module.md | 2 +- src/ballistica/ballistica.cc | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index b3087f56..9d111569 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,16 +3932,16 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/a7/be/d2d88cedd80218236cace5782990", - "build/prefab/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/be/9d/3dc0431a002e197163134a5dc881", - "build/prefab/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c0/d3/95030ef9319c3c8ed13e75254583", - "build/prefab/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/f7/170ffdbec21643a4a80e181023b3", - "build/prefab/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/9c/62/c7a083e3aa2f93005c5354678207", - "build/prefab/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e5/c4/e5be2fa6ebe5ff81a99c3608a73d", - "build/prefab/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/0e/902db411f7298917a8d3b0b13ec2", - "build/prefab/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fd/0f/8bc3a7dc565a0dd376f124d747d5", - "build/prefab/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/3c/78/d8cd734a0ccab60c2e0ea3a97370", - "build/prefab/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/2b/b7/c193aa65c8adf613f543036b8af4", - "build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/4c/37/68bc656f1f94994754301d0c742e", - "build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/15/d1/db8211bd2df1e435dcb7f6823fc2" + "build/prefab/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/03/0f/4c4eeb516e212430405a62df4d96", + "build/prefab/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/9e/7ea5f6279b578671feec089a5f0b", + "build/prefab/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/93/97bf38a3110c61b82d5610e58cf7", + "build/prefab/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/b2/397c21672fccd98eb357feff9f86", + "build/prefab/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/6e/c940715181bee2013b23b46ddd2e", + "build/prefab/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c5/0f/6024c36bc2371ab59f4521f7c235", + "build/prefab/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/04/e9/e26dc0e97c51e4bb77ffeed959fc", + "build/prefab/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/0d/5fa79510c0cc55cad9480dfd8271", + "build/prefab/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b3/3e/a23ac72d41c78bc0b2e7c09559c3", + "build/prefab/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/44/7f/51dccf7eda919d1b138248d05481", + "build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fa/79/8d6c716b900bdd0a4aae18cb5767", + "build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c5/a8/0f9242124c4ee116ec01576a7fd4" } \ No newline at end of file diff --git a/docs/ba_module.md b/docs/ba_module.md index e7465286..8157dae5 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-10-10 for Ballistica version 1.5.26 build 20199

    +

    last updated on 2020-10-10 for Ballistica version 1.5.26 build 20200

    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!


    diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 8956bf88..49d3c88e 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -29,7 +29,7 @@ namespace ballistica { // These are set automatically via script; don't change here. -const int kAppBuildNumber = 20199; +const int kAppBuildNumber = 20200; const char* kAppVersion = "1.5.26"; // Our standalone globals. From 8c4702ff661547f4be1b46c70276e06e6dc0dbfa Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 11 Oct 2020 11:04:49 -0700 Subject: [PATCH 239/417] Adding prefab ballistica_internal lib builds --- .efrocachemap | 32 +++--- Makefile | 268 +++++++++++++++++++++++++++----------------------- 2 files changed, 167 insertions(+), 133 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 9d111569..3a892046 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,16 +3932,24 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/03/0f/4c4eeb516e212430405a62df4d96", - "build/prefab/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/9e/7ea5f6279b578671feec089a5f0b", - "build/prefab/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b9/93/97bf38a3110c61b82d5610e58cf7", - "build/prefab/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/4c/b2/397c21672fccd98eb357feff9f86", - "build/prefab/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/3e/6e/c940715181bee2013b23b46ddd2e", - "build/prefab/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/c5/0f/6024c36bc2371ab59f4521f7c235", - "build/prefab/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/04/e9/e26dc0e97c51e4bb77ffeed959fc", - "build/prefab/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/df/0d/5fa79510c0cc55cad9480dfd8271", - "build/prefab/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/b3/3e/a23ac72d41c78bc0b2e7c09559c3", - "build/prefab/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/44/7f/51dccf7eda919d1b138248d05481", - "build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/fa/79/8d6c716b900bdd0a4aae18cb5767", - "build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/c5/a8/0f9242124c4ee116ec01576a7fd4" + "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/0f/c39e95977f3a01a96cac80ec9bee", + "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/57/c4/9ac4ec70c2f05a9754f69ba6f839", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/dd/ef1331fc04e88b62dafaf1e918ac", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/74/e5/3d76af6120ae4fac97ccd6d06aa1", + "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/85/2238ffb603143734e13f3923a34a", + "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/92/077762bb04a6957d5d7b81ccb3bf", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/ad/0962b48f84dde0e97a5fbc5d73b3", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/5b/c3c17254122f4e2b8648fedab32c", + "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/07/26/1eee5b94f1e7a2e5a0e98d88e88a", + "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/48/08/617bb551588cdca232fdaec2ff07", + "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e3/62/3e05f6f18f0394a0d7d172749790", + "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/eb/43/297a13121358d1bf9e01d4cc5f6d", + "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9c/fa/dd352f6c3cb26ede0a21f24d5454", + "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", + "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", + "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b4/33/477ad3318aac7568fb71748ad494", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/14/94/28743f847250acd121027bb03140", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/73/e0/1b2bebae1e1603d36a38ef3264e2", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5e/e0/b8809648f1ac93dd4c5303549cc6" } \ No newline at end of file diff --git a/Makefile b/Makefile index b2377e88..20045064 100644 --- a/Makefile +++ b/Makefile @@ -151,10 +151,10 @@ prefab-server-release-build: # Specific platform prefab targets: -RUN_PREFAB_MAC_X86_64_DEBUG = cd build/prefab/mac_x86_64/debug \ +RUN_PREFAB_MAC_X86_64_DEBUG = cd build/prefab/full/mac_x86_64/debug \ && ./ballisticacore -RUN_PREFAB_MAC_ARM64_DEBUG = cd build/prefab/mac_arm64/debug \ +RUN_PREFAB_MAC_ARM64_DEBUG = cd build/prefab/full/mac_arm64/debug \ && ./ballisticacore prefab-mac-x86-64-debug: prefab-mac-x86-64-debug-build @@ -166,20 +166,23 @@ prefab-mac-arm64-debug: prefab-mac-arm64-debug-build @${RUN_PREFAB_MAC_ARM64_DEBUG} prefab-mac-x86-64-debug-build: prereqs assets-cmake \ - build/prefab/mac_x86_64/debug/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/mac_x86_64/debug + build/prefab/full/mac_x86_64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/mac_x86_64/debug prefab-mac-arm64-debug-build: prereqs assets-cmake \ - build/prefab/mac_arm64/debug/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/mac_arm64/debug + build/prefab/full/mac_arm64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/mac_arm64/debug -build/prefab/mac_%/debug/ballisticacore: .efrocachemap +build/prefab/full/mac_%/debug/ballisticacore: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_MAC_X86_64_RELEASE = cd build/prefab/mac_x86_64/release \ +build/prefab/lib/mac_%/debug/libballisticacore_internal.a: .efrocachemap + @tools/pcommand efrocache_get $@ + +RUN_PREFAB_MAC_X86_64_RELEASE = cd build/prefab/full/mac_x86_64/release \ && ./ballisticacore -RUN_PREFAB_MAC_ARM64_RELEASE = cd build/prefab/mac_arm64/release \ +RUN_PREFAB_MAC_ARM64_RELEASE = cd build/prefab/full/mac_arm64/release \ && ./ballisticacore prefab-mac-x86-64-release: prefab-mac-x86-64-release-build @@ -191,21 +194,24 @@ prefab-mac-arm64-release: prefab-mac-arm64-release-build @${RUN_PREFAB_MAC_ARM64_RELEASE} prefab-mac-x86-64-release-build: prereqs assets-cmake \ - build/prefab/mac_x86_64/release/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/mac_x86_64/release + build/prefab/full/mac_x86_64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/mac_x86_64/release prefab-mac-arm64-release-build: prereqs assets-cmake \ - build/prefab/mac_arm64/release/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/mac_arm64/release + build/prefab/full/mac_arm64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/mac_arm64/release -build/prefab/mac_%/release/ballisticacore: .efrocachemap +build/prefab/full/mac_%/release/ballisticacore: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_MAC_X86_64_SERVER_DEBUG = cd build/prefab/mac_x86_64_server/debug \ - && ./ballisticacore_server +build/prefab/lib/mac_%/release/libballisticacore_internal.a: .efrocachemap + @tools/pcommand efrocache_get $@ -RUN_PREFAB_MAC_ARM64_SERVER_DEBUG = cd build/prefab/mac_arm64_server/debug \ - && ./ballisticacore_server +RUN_PREFAB_MAC_X86_64_SERVER_DEBUG = cd \ + build/prefab/full/mac_x86_64_server/debug && ./ballisticacore_server + +RUN_PREFAB_MAC_ARM64_SERVER_DEBUG = cd \ + build/prefab/full/mac_arm64_server/debug && ./ballisticacore_server prefab-mac-x86-64-server-debug: prefab-mac-x86-64-server-debug-build @tools/pcommand ensure_prefab_platform mac_x86_64 @@ -216,42 +222,45 @@ prefab-mac-arm64-server-debug: prefab-mac-arm64-server-debug-build @${RUN_PREFAB_MAC_ARM64_SERVER_DEBUG} prefab-mac-x86-64-server-debug-build: prereqs assets-cmake \ - build/prefab/mac_x86_64_server/debug/dist/ballisticacore_headless \ - build/prefab/mac_x86_64_server/debug/ballisticacore_server \ - build/prefab/mac_x86_64_server/debug/config_template.yaml \ - build/prefab/mac_x86_64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/mac_x86_64_server/debug/dist + build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/mac_x86_64_server/debug/ballisticacore_server \ + build/prefab/full/mac_x86_64_server/debug/config_template.yaml \ + build/prefab/full/mac_x86_64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_x86_64_server/debug/dist prefab-mac-arm64-server-debug-build: prereqs assets-cmake \ - build/prefab/mac_arm64_server/debug/dist/ballisticacore_headless \ - build/prefab/mac_arm64_server/debug/ballisticacore_server \ - build/prefab/mac_arm64_server/debug/config_template.yaml \ - build/prefab/mac_arm64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/mac_arm64_server/debug/dist + build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/mac_arm64_server/debug/ballisticacore_server \ + build/prefab/full/mac_arm64_server/debug/config_template.yaml \ + build/prefab/full/mac_arm64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_arm64_server/debug/dist -build/prefab/mac_%_server/debug/ballisticacore_server: \ +build/prefab/full/mac_%_server/debug/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/mac_%_server/debug/config_template.yaml: \ +build/prefab/full/mac_%_server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/mac_%_server/debug/README.txt: \ +build/prefab/full/mac_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/mac_%_server/debug/dist/ballisticacore_headless: .efrocachemap +build/prefab/full/mac_%_server/debug/dist/ballisticacore_headless: .efrocachemap + @tools/pcommand efrocache_get $@ + +build/prefab/lib/mac_%_server/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ RUN_PREFAB_MAC_X86_64_SERVER_RELEASE = cd \ - build/prefab/mac_x86_64_server/release && ./ballisticacore_server + build/prefab/full/mac_x86_64_server/release && ./ballisticacore_server RUN_PREFAB_MAC_ARM64_SERVER_RELEASE = cd \ - build/prefab/mac_arm64_server/release && ./ballisticacore_server + build/prefab/full/mac_arm64_server/release && ./ballisticacore_server prefab-mac-x86-64-server-release: prefab-mac-x86-64-server-release-build @tools/pcommand ensure_prefab_platform mac_x86_64 @@ -262,42 +271,45 @@ prefab-mac-arm64-server-release: prefab-mac-arm64-server-release-build @${RUN_PREFAB_MAC_ARM64_SERVER_RELEASE} prefab-mac-x86-64-server-release-build: prereqs assets-cmake \ - build/prefab/mac_x86_64_server/release/dist/ballisticacore_headless \ - build/prefab/mac_x86_64_server/release/ballisticacore_server \ - build/prefab/mac_x86_64_server/release/config_template.yaml \ - build/prefab/mac_x86_64_server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/mac_x86_64_server/release/dist + build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless \ + build/prefab/full/mac_x86_64_server/release/ballisticacore_server \ + build/prefab/full/mac_x86_64_server/release/config_template.yaml \ + build/prefab/full/mac_x86_64_server/release/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_x86_64_server/release/dist prefab-mac-arm64-server-release-build: prereqs assets-cmake \ - build/prefab/mac_arm64_server/release/dist/ballisticacore_headless \ - build/prefab/mac_arm64_server/release/ballisticacore_server \ - build/prefab/mac_arm64_server/release/config_template.yaml \ - build/prefab/mac_arm64_server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/mac_arm64_server/release/dist + build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless \ + build/prefab/full/mac_arm64_server/release/ballisticacore_server \ + build/prefab/full/mac_arm64_server/release/config_template.yaml \ + build/prefab/full/mac_arm64_server/release/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_arm64_server/release/dist -build/prefab/mac_%_server/release/ballisticacore_server: \ +build/prefab/full/mac_%_server/release/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/mac_%_server/release/config_template.yaml: \ +build/prefab/full/mac_%_server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file release $< $@ -build/prefab/mac_%_server/release/README.txt: \ +build/prefab/full/mac_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/mac_%_server/release/dist/ballisticacore_headless: .efrocachemap +build/prefab/full/mac_%_server/release/dist/ballisticacore_headless: .efrocachemap + @tools/pcommand efrocache_get $@ + +build/prefab/lib/mac_%_server/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_X86_64_DEBUG = cd \ - build/prefab/linux_x86_64/debug && ./ballisticacore + build/prefab/full/linux_x86_64/debug && ./ballisticacore RUN_PREFAB_LINUX_ARM64_DEBUG = cd \ - build/prefab/linux_arm64/debug && ./ballisticacore + build/prefab/full/linux_arm64/debug && ./ballisticacore prefab-linux-x86-64-debug: prefab-linux-x86-64-debug-build @tools/pcommand ensure_prefab_platform linux_x86_64 @@ -308,21 +320,24 @@ prefab-linux-arm64-debug: prefab-linux-arm64-debug-build @${RUN_PREFAB_LINUX_ARM64_DEBUG} prefab-linux-x86-64-debug-build: prereqs assets-cmake \ - build/prefab/linux_x86_64/debug/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/linux_x86_64/debug + build/prefab/full/linux_x86_64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/linux_x86_64/debug prefab-linux-arm64-debug-build: prereqs assets-cmake \ - build/prefab/linux_arm64/debug/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/linux_arm64/debug + build/prefab/full/linux_arm64/debug/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/linux_arm64/debug -build/prefab/linux_%/debug/ballisticacore: .efrocachemap +build/prefab/full/linux_%/debug/ballisticacore: .efrocachemap + @tools/pcommand efrocache_get $@ + +build/prefab/lib/linux_%/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_X86_64_RELEASE = cd \ - build/prefab/linux_x86_64/release && ./ballisticacore + build/prefab/full/linux_x86_64/release && ./ballisticacore RUN_PREFAB_LINUX_ARM64_RELEASE = cd \ - build/prefab/linux_arm64/release && ./ballisticacore + build/prefab/full/linux_arm64/release && ./ballisticacore prefab-linux-x86-64-release: prefab-linux-x86-64-release-build @tools/pcommand ensure_prefab_platform linux_x86_64 @@ -333,21 +348,24 @@ prefab-linux-arm64-release: prefab-linux-arm64-release-build @${RUN_PREFAB_LINUX_ARM64_RELEASE} prefab-linux-x86-64-release-build: prereqs assets-cmake \ - build/prefab/linux_x86_64/release/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/linux_x86_64/release + build/prefab/full/linux_x86_64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/linux_x86_64/release prefab-linux-arm64-release-build: prereqs assets-cmake \ - build/prefab/linux_arm64/release/ballisticacore - @${STAGE_ASSETS} -cmake build/prefab/linux_arm64/release + build/prefab/full/linux_arm64/release/ballisticacore + @${STAGE_ASSETS} -cmake build/prefab/full/linux_arm64/release -build/prefab/linux_%/release/ballisticacore: .efrocachemap +build/prefab/full/linux_%/release/ballisticacore: .efrocachemap + @tools/pcommand efrocache_get $@ + +build/prefab/lib/linux_%/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_X86_64_SERVER_DEBUG = cd \ - build/prefab/linux_x86_64_server/debug && ./ballisticacore_server + build/prefab/full/linux_x86_64_server/debug && ./ballisticacore_server RUN_PREFAB_LINUX_ARM64_SERVER_DEBUG = cd \ - build/prefab/linux_arm64_server/debug && ./ballisticacore_server + build/prefab/full/linux_arm64_server/debug && ./ballisticacore_server prefab-linux-x86-64-server-debug: prefab-linux-x86-64-server-debug-build @tools/pcommand ensure_prefab_platform linux_x86_64 @@ -358,75 +376,82 @@ prefab-linux-arm64-server-debug: prefab-linux-arm64-server-debug-build @${RUN_PREFAB_LINUX_ARM64_SERVER_DEBUG} prefab-linux-x86-64-server-debug-build: prereqs assets-cmake \ - build/prefab/linux_x86_64_server/debug/dist/ballisticacore_headless \ - build/prefab/linux_x86_64_server/debug/ballisticacore_server \ - build/prefab/linux_x86_64_server/debug/config_template.yaml \ - build/prefab/linux_x86_64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/linux_x86_64_server/debug/dist + build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/linux_x86_64_server/debug/ballisticacore_server \ + build/prefab/full/linux_x86_64_server/debug/config_template.yaml \ + build/prefab/full/linux_x86_64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/full/linux_x86_64_server/debug/dist prefab-linux-arm64-server-debug-build: prereqs assets-cmake \ - build/prefab/linux_arm64_server/debug/dist/ballisticacore_headless \ - build/prefab/linux_arm64_server/debug/ballisticacore_server \ - build/prefab/linux_arm64_server/debug/config_template.yaml \ - build/prefab/linux_arm64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/linux_arm64_server/debug/dist + build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/linux_arm64_server/debug/ballisticacore_server \ + build/prefab/full/linux_arm64_server/debug/config_template.yaml \ + build/prefab/full/linux_arm64_server/debug/README.txt + @${STAGE_ASSETS} -cmakeserver build/prefab/full/linux_arm64_server/debug/dist -build/prefab/linux_%_server/debug/ballisticacore_server: \ +build/prefab/full/linux_%_server/debug/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/linux_%_server/debug/config_template.yaml: \ +build/prefab/full/linux_%_server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/linux_%_server/debug/README.txt: \ +build/prefab/full/linux_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/linux_%_server/debug/dist/ballisticacore_headless: .efrocachemap +build/prefab/full/linux_%_server/debug/dist/ballisticacore_headless: .efrocachemap + @tools/pcommand efrocache_get $@ + +build/prefab/lib/linux_%_server/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ RUN_PREFAB_LINUX_X86_64_SERVER_RELEASE = cd \ - build/prefab/linux_x86_64_server/release && ./ballisticacore_server + build/prefab/full/linux_x86_64_server/release && ./ballisticacore_server RUN_PREFAB_LINUX_ARM64_SERVER_RELEASE = cd \ - build/prefab/linux_arm64_server/release && ./ballisticacore_server + build/prefab/full/linux_arm64_server/release && ./ballisticacore_server prefab-linux-x86-64-server-release: prefab-linux-x86-64-server-release-build @tools/pcommand ensure_prefab_platform linux_x86_64 @${RUN_PREFAB_LINUX_X86_64_SERVER_RELEASE} prefab-linux-x86-64-server-release-build: prereqs assets-cmake \ - build/prefab/linux_x86_64_server/release/dist/ballisticacore_headless \ - build/prefab/linux_x86_64_server/release/ballisticacore_server \ - build/prefab/linux_x86_64_server/release/config_template.yaml \ - build/prefab/linux_x86_64_server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/linux_x86_64_server/release/dist + build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless \ + build/prefab/full/linux_x86_64_server/release/ballisticacore_server \ + build/prefab/full/linux_x86_64_server/release/config_template.yaml \ + build/prefab/full/linux_x86_64_server/release/README.txt + @${STAGE_ASSETS} \ + -cmakeserver build/prefab/full/linux_x86_64_server/release/dist -build/prefab/linux_%_server/release/ballisticacore_server: \ +build/prefab/full/linux_%_server/release/ballisticacore_server: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/linux_%_server/release/config_template.yaml: \ +build/prefab/full/linux_%_server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file release $< $@ -build/prefab/linux_%_server/release/README.txt: \ +build/prefab/full/linux_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ -build/prefab/linux_%_server/release/dist/ballisticacore_headless: .efrocachemap +build/prefab/full/linux_%_server/release/dist/ballisticacore_headless: .efrocachemap + @tools/pcommand efrocache_get $@ + +build/prefab/lib/linux_%_server/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ WINPLAT_X86 = Win32 -RUN_PREFAB_WINDOWS_X86_DEBUG = cd build/prefab/windows_x86/debug \ +RUN_PREFAB_WINDOWS_X86_DEBUG = cd build/prefab/full/windows_x86/debug \ && ./BallisticaCore.exe prefab-windows-x86-debug: prefab-windows-x86-debug-build @@ -434,14 +459,14 @@ prefab-windows-x86-debug: prefab-windows-x86-debug-build @{RUN_PREFAB_WINDOWS_X86_DEBUG} prefab-windows-x86-debug-build: prereqs assets-windows-${WINPLAT_X86} \ - build/prefab/windows_x86/debug/BallisticaCore.exe + build/prefab/full/windows_x86/debug/BallisticaCore.exe @${STAGE_ASSETS} -win-${WINPLAT_X86}-Debug \ -build/prefab/windows_x86/debug +build/prefab/full/windows_x86/debug -build/prefab/windows_x86/debug/BallisticaCore.exe: .efrocachemap +build/prefab/full/windows_x86/debug/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_WINDOWS_X86_RELEASE = cd build/prefab/windows_x86/release \ +RUN_PREFAB_WINDOWS_X86_RELEASE = cd build/prefab/full/windows_x86/release \ && ./BallisticaCore.exe prefab-windows-x86-release: prefab-windows-x86-release-build @@ -450,14 +475,15 @@ prefab-windows-x86-release: prefab-windows-x86-release-build prefab-windows-x86-release-build: prereqs \ assets-windows-${WINPLAT_X86} \ - build/prefab/windows_x86/release/BallisticaCore.exe + build/prefab/full/windows_x86/release/BallisticaCore.exe @${STAGE_ASSETS} -win-${WINPLAT_X86}-Release \ -build/prefab/windows_x86/release +build/prefab/full/windows_x86/release -build/prefab/windows_x86/release/BallisticaCore.exe: .efrocachemap +build/prefab/full/windows_x86/release/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ -RUN_PREFAB_WINDOWS_X86_SERVER_DEBUG = cd build/prefab/windows_x86_server/debug \ +RUN_PREFAB_WINDOWS_X86_SERVER_DEBUG = cd \ + build/prefab/full/windows_x86_server/debug \ && dist/python_d.exe ballisticacore_server.py prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build @@ -466,38 +492,38 @@ prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build prefab-windows-x86-server-debug-build: prereqs \ assets-windows-${WINPLAT_X86} \ - build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe \ - build/prefab/windows_x86_server/debug/launch_ballisticacore_server.bat \ - build/prefab/windows_x86_server/debug/ballisticacore_server.py \ - build/prefab/windows_x86_server/debug/config_template.yaml \ - build/prefab/windows_x86_server/debug/README.txt + build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe \ + build/prefab/full/windows_x86_server/debug/launch_ballisticacore_server.bat \ + build/prefab/full/windows_x86_server/debug/ballisticacore_server.py \ + build/prefab/full/windows_x86_server/debug/config_template.yaml \ + build/prefab/full/windows_x86_server/debug/README.txt @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Debug \ - build/prefab/windows_x86_server/debug/dist + build/prefab/full/windows_x86_server/debug/dist -build/prefab/windows_x86_server/debug/dist/ballisticacore_headless.exe: .efrocachemap +build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe: .efrocachemap @tools/pcommand efrocache_get $@ -build/prefab/windows_%_server/debug/ballisticacore_server.py: \ +build/prefab/full/windows_%_server/debug/ballisticacore_server.py: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/windows_%_server/debug/launch_ballisticacore_server.bat: \ +build/prefab/full/windows_%_server/debug/launch_ballisticacore_server.bat: \ assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/windows_%_server/debug/config_template.yaml: \ +build/prefab/full/windows_%_server/debug/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file debug $< $@ -build/prefab/windows_%_server/debug/README.txt: \ +build/prefab/full/windows_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE = cd \ - build/prefab/windows_x86_server/release \ + build/prefab/full/windows_x86_server/release \ && dist/python.exe -O ballisticacore_server.py prefab-windows-x86-server-release: prefab-windows-x86-server-release-build @@ -506,33 +532,33 @@ prefab-windows-x86-server-release: prefab-windows-x86-server-release-build prefab-windows-x86-server-release-build: prereqs \ assets-windows-${WINPLAT_X86} \ - build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe \ - build/prefab/windows_x86_server/release/launch_ballisticacore_server.bat \ - build/prefab/windows_x86_server/release/ballisticacore_server.py \ - build/prefab/windows_x86_server/release/config_template.yaml \ - build/prefab/windows_x86_server/release/README.txt + build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe \ + build/prefab/full/windows_x86_server/release/launch_ballisticacore_server.bat \ + build/prefab/full/windows_x86_server/release/ballisticacore_server.py \ + build/prefab/full/windows_x86_server/release/config_template.yaml \ + build/prefab/full/windows_x86_server/release/README.txt @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Release \ - build/prefab/windows_x86_server/release/dist + build/prefab/full/windows_x86_server/release/dist -build/prefab/windows_x86_server/release/dist/ballisticacore_headless.exe: .efrocachemap +build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe: .efrocachemap @tools/pcommand efrocache_get $@ -build/prefab/windows_%_server/release/ballisticacore_server.py: \ +build/prefab/full/windows_%_server/release/ballisticacore_server.py: \ assets/src/server/ballisticacore_server.py tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/windows_%_server/release/launch_ballisticacore_server.bat: \ +build/prefab/full/windows_%_server/release/launch_ballisticacore_server.bat: \ assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py @tools/pcommand stage_server_file release $< $@ -build/prefab/windows_%_server/release/config_template.yaml: \ +build/prefab/full/windows_%_server/release/config_template.yaml: \ assets/src/server/config_template.yaml \ tools/batools/build.py \ tools/batools/pcommand.py \ tools/bacommon/servermanager.py @tools/pcommand stage_server_file release $< $@ -build/prefab/windows_%_server/release/README.txt: \ +build/prefab/full/windows_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ From cb1636b77690a7d984985c1cb4354e4dc76be8c8 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 11 Oct 2020 11:22:24 -0700 Subject: [PATCH 240/417] Makefile tidying --- .efrocachemap | 8 +++--- Makefile | 68 ++++++++++++++++++++++++++++++++++++++------------- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 3a892046..3d7210af 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3948,8 +3948,8 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b4/33/477ad3318aac7568fb71748ad494", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/14/94/28743f847250acd121027bb03140", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/73/e0/1b2bebae1e1603d36a38ef3264e2", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5e/e0/b8809648f1ac93dd4c5303549cc6" + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/47/43/8bdcb42f145f020d3327e42aba34", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/58/5d3d5e242ffc1331dcdd215977e0", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f8/73/58929632a662fa66a026d9b14ab6", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8b/54/fb5a72392a53cca6ef29f78633ae" } \ No newline at end of file diff --git a/Makefile b/Makefile index 20045064..f235df09 100644 --- a/Makefile +++ b/Makefile @@ -149,8 +149,16 @@ prefab-server-debug-build: prefab-server-release-build: @tools/pcommand make_prefab server-release +# Clean all prefab builds. +prefab-clean: + rm -rf build/prefab + # Specific platform prefab targets: +WINPLAT_X86 = Win32 + +# Mac debug: + RUN_PREFAB_MAC_X86_64_DEBUG = cd build/prefab/full/mac_x86_64/debug \ && ./ballisticacore @@ -179,6 +187,8 @@ build/prefab/full/mac_%/debug/ballisticacore: .efrocachemap build/prefab/lib/mac_%/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Mac release: + RUN_PREFAB_MAC_X86_64_RELEASE = cd build/prefab/full/mac_x86_64/release \ && ./ballisticacore @@ -207,6 +217,8 @@ build/prefab/full/mac_%/release/ballisticacore: .efrocachemap build/prefab/lib/mac_%/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Mac server debug: + RUN_PREFAB_MAC_X86_64_SERVER_DEBUG = cd \ build/prefab/full/mac_x86_64_server/debug && ./ballisticacore_server @@ -256,6 +268,8 @@ build/prefab/full/mac_%_server/debug/dist/ballisticacore_headless: .efrocachemap build/prefab/lib/mac_%_server/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Mac server release: + RUN_PREFAB_MAC_X86_64_SERVER_RELEASE = cd \ build/prefab/full/mac_x86_64_server/release && ./ballisticacore_server @@ -305,6 +319,8 @@ build/prefab/full/mac_%_server/release/dist/ballisticacore_headless: .efrocachem build/prefab/lib/mac_%_server/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Linux debug: + RUN_PREFAB_LINUX_X86_64_DEBUG = cd \ build/prefab/full/linux_x86_64/debug && ./ballisticacore @@ -333,6 +349,8 @@ build/prefab/full/linux_%/debug/ballisticacore: .efrocachemap build/prefab/lib/linux_%/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Linux release: + RUN_PREFAB_LINUX_X86_64_RELEASE = cd \ build/prefab/full/linux_x86_64/release && ./ballisticacore @@ -361,6 +379,8 @@ build/prefab/full/linux_%/release/ballisticacore: .efrocachemap build/prefab/lib/linux_%/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Linux server debug: + RUN_PREFAB_LINUX_X86_64_SERVER_DEBUG = cd \ build/prefab/full/linux_x86_64_server/debug && ./ballisticacore_server @@ -410,6 +430,8 @@ build/prefab/full/linux_%_server/debug/dist/ballisticacore_headless: .efrocachem build/prefab/lib/linux_%_server/debug/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ +# Linux server release: + RUN_PREFAB_LINUX_X86_64_SERVER_RELEASE = cd \ build/prefab/full/linux_x86_64_server/release && ./ballisticacore_server @@ -449,7 +471,7 @@ build/prefab/full/linux_%_server/release/dist/ballisticacore_headless: .efrocach build/prefab/lib/linux_%_server/release/libballisticacore_internal.a: .efrocachemap @tools/pcommand efrocache_get $@ -WINPLAT_X86 = Win32 +# Windows debug: RUN_PREFAB_WINDOWS_X86_DEBUG = cd build/prefab/full/windows_x86/debug \ && ./BallisticaCore.exe @@ -466,6 +488,8 @@ build/prefab/full/windows_x86/debug build/prefab/full/windows_x86/debug/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ +# Windows release: + RUN_PREFAB_WINDOWS_X86_RELEASE = cd build/prefab/full/windows_x86/release \ && ./BallisticaCore.exe @@ -482,6 +506,8 @@ build/prefab/full/windows_x86/release build/prefab/full/windows_x86/release/BallisticaCore.exe: .efrocachemap @tools/pcommand efrocache_get $@ +# Windows server debug: + RUN_PREFAB_WINDOWS_X86_SERVER_DEBUG = cd \ build/prefab/full/windows_x86_server/debug \ && dist/python_d.exe ballisticacore_server.py @@ -522,6 +548,8 @@ build/prefab/full/windows_%_server/debug/README.txt: \ assets/src/server/README.txt @cp $< $@ +# Windows server release: + RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE = cd \ build/prefab/full/windows_x86_server/release \ && dist/python.exe -O ballisticacore_server.py @@ -562,23 +590,29 @@ build/prefab/full/windows_%_server/release/README.txt: \ assets/src/server/README.txt @cp $< $@ -prefab-clean: - rm -rf build/prefab - # Tell make which of these targets don't represent files. -.PHONY: prefab-debug prefab-debug-build prefab-release prefab-release-build \ - prefab-server-debug prefab-server-debug-build prefab-server-release \ - prefab-server-release-build prefab-mac-debug prefab-mac-debug-build \ - prefab-mac-release prefab-mac-release-build prefab-mac-server-debug \ - prefab-mac-server-debug-build prefab-mac-server-release \ - prefab-mac-server-release-build prefab-linux-debug prefab-linux-debug-build \ - prefab-linux-release prefab-linux-release-build prefab-linux-server-debug \ - prefab-linux-server-debug-build prefab-linux-server-release \ - prefab-linux-server-release-build prefab-windows-debug \ - prefab-windows-debug-build prefab-windows-release \ - prefab-windows-release-build prefab-windows-server-debug \ - prefab-windows-server-debug-build prefab-windows-server-release \ - prefab-windows-server-release-build prefab-clean +.PHONY: prefab-debug prefab-release prefab-debug-build prefab-release-build \ + prefab-server-debug prefab-server-release prefab-server-debug-build \ + prefab-server-release-build prefab-clean _cmake_prefab_binary \ + _cmake_prefab_server_binary prefab-mac-x86-64-debug prefab-mac-arm64-debug \ + prefab-mac-x86-64-debug-build prefab-mac-arm64-debug-build \ + prefab-mac-x86-64-release prefab-mac-arm64-release \ + prefab-mac-x86-64-release-build prefab-mac-arm64-release-build \ + prefab-mac-x86-64-server-debug prefab-mac-arm64-server-debug \ + prefab-mac-x86-64-server-debug-build prefab-mac-arm64-server-debug-build \ + prefab-mac-x86-64-server-release prefab-mac-arm64-server-release \ + prefab-mac-x86-64-server-release-build prefab-mac-arm64-server-release-build \ + prefab-linux-x86-64-debug prefab-linux-arm64-debug \ + prefab-linux-x86-64-debug-build prefab-linux-arm64-debug-build \ + prefab-linux-x86-64-release prefab-linux-arm64-release \ + prefab-linux-x86-64-release-build prefab-linux-arm64-release-build \ + prefab-linux-x86-64-server-debug prefab-linux-arm64-server-debug \ + prefab-linux-x86-64-server-debug-build prefab-linux-arm64-server-debug-build \ + prefab-linux-x86-64-server-release prefab-linux-x86-64-server-release-build \ + prefab-windows-x86-debug prefab-windows-x86-debug-build \ + prefab-windows-x86-release prefab-windows-x86-release-build \ + prefab-windows-x86-server-debug prefab-windows-x86-server-debug-build \ + prefab-windows-x86-server-release prefab-windows-x86-server-release-build ################################################################################ From 1a7c0ef7285845465d89a6a48063e2c9453c8448 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 11 Oct 2020 11:52:55 -0700 Subject: [PATCH 241/417] CMake builds now go to the root build dir --- .efrocachemap | 8 ++++---- Makefile | 41 ++++++++++++++++++----------------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 3d7210af..3eccef2c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3948,8 +3948,8 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/47/43/8bdcb42f145f020d3327e42aba34", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/58/5d3d5e242ffc1331dcdd215977e0", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f8/73/58929632a662fa66a026d9b14ab6", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8b/54/fb5a72392a53cca6ef29f78633ae" + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f7/16/01f6978b6262c3033aadfb4ad24f", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d8/21/d65fb091c26cc7b683768ea19705", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/13/0c/a2f421ae193496383524772a1e76", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c9/a7/f55ab74860ab4f6ef4983e144e76" } \ No newline at end of file diff --git a/Makefile b/Makefile index f235df09..b901ecca 100644 --- a/Makefile +++ b/Makefile @@ -612,7 +612,7 @@ build/prefab/full/windows_%_server/release/README.txt: \ prefab-windows-x86-debug prefab-windows-x86-debug-build \ prefab-windows-x86-release prefab-windows-x86-release-build \ prefab-windows-x86-server-debug prefab-windows-x86-server-debug-build \ - prefab-windows-x86-server-release prefab-windows-x86-server-release-build + prefab-windows-x86-server-release prefab-windows-x86-server-release-build ################################################################################ @@ -818,43 +818,38 @@ preflight2-full: # Set the following from the command line to influence the build: -# This can be Debug or Release +# This can be Debug or Release. CMAKE_BUILD_TYPE ?= Debug -# Host to use when building via cloudshell -CMAKE_CLOUDSHELL_HOST ?= linbeast - -# Base names for assembled packages -CMAKE_CLOUDSHELL_PACKAGE_NAME ?= BallisticaCore -CMAKE_CLOUDSHELL_SERVER_PACKAGE_NAME ?= BallisticaCore_Server - # Build and run the cmake build. cmake: cmake-build - @cd ballisticacore-cmake/build/$(CM_BT_LC) && ./ballisticacore + @cd build/cmake/$(CM_BT_LC) && ./ballisticacore # Build but don't run it. cmake-build: assets-cmake resources code - @tools/pcommand cmake_prep_dir ballisticacore-cmake/build/$(CM_BT_LC) - @${STAGE_ASSETS} -cmake ballisticacore-cmake/build/$(CM_BT_LC) - @cd ballisticacore-cmake/build/$(CM_BT_LC) && test -f Makefile \ - || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) ../.. - @cd ballisticacore-cmake/build/$(CM_BT_LC) && ${MAKE} -j${CPUS} + @tools/pcommand cmake_prep_dir build/cmake/$(CM_BT_LC) + @${STAGE_ASSETS} -cmake build/cmake/$(CM_BT_LC) + @cd build/cmake/$(CM_BT_LC) && test -f Makefile \ + || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ + ../../../ballisticacore-cmake + @cd build/cmake/$(CM_BT_LC) && ${MAKE} -j${CPUS} cmake-clean: - rm -rf ballisticacore-cmake/build/$(CM_BT_LC) + rm -rf build/cmake/$(CM_BT_LC) cmake-server: cmake-server-build - @cd ballisticacore-cmake/build/server-$(CM_BT_LC) && ./ballisticacore + @cd build/cmake/server-$(CM_BT_LC) && ./ballisticacore cmake-server-build: assets-cmake resources code - @tools/pcommand cmake_prep_dir ballisticacore-cmake/build/server-$(CM_BT_LC) - @${STAGE_ASSETS} -cmakeserver ballisticacore-cmake/build/server-$(CM_BT_LC) - @cd ballisticacore-cmake/build/server-$(CM_BT_LC) && test -f Makefile \ - || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true ../.. - @cd ballisticacore-cmake/build/server-$(CM_BT_LC) && ${MAKE} -j${CPUS} + @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC) + @${STAGE_ASSETS} -cmakeserver build/cmake/server-$(CM_BT_LC) + @cd build/cmake/server-$(CM_BT_LC) && test -f Makefile \ + || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \ + ../../../ballisticacore-cmake + @cd build/cmake/server-$(CM_BT_LC) && ${MAKE} -j${CPUS} cmake-server-clean: - rm -rf ballisticacore-cmake/build/server-$(CM_BT_LC) + rm -rf build/cmake/server-$(CM_BT_LC) # Tell make which of these targets don't represent files. .PHONY: cmake cmake-build cmake-clean cmake-server cmake-server-build \ From 24cc7e9e99a1cfe864db07566b3856791d336ff7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 11 Oct 2020 14:53:48 -0700 Subject: [PATCH 242/417] More work on prefab system --- .efrocachemap | 8 +- .idea/dictionaries/ericf.xml | 4 + Makefile | 166 +++++----------------------- tools/batools/assetstaging.py | 197 +++++++++++++++++++++++++++------- tools/batools/build.py | 9 +- tools/batools/pcommand.py | 51 +-------- 6 files changed, 197 insertions(+), 238 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 3eccef2c..34490194 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3948,8 +3948,8 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f7/16/01f6978b6262c3033aadfb4ad24f", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d8/21/d65fb091c26cc7b683768ea19705", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/13/0c/a2f421ae193496383524772a1e76", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c9/a7/f55ab74860ab4f6ef4983e144e76" + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/41/6b/19bf8c7fa531a27076d1c0babaff", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fd/66/69bc3327543d711753013b9fc821", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/80/37/41e0842744af078a54e2477045e0", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cf/f5/f2df776067491dbc09500c9c3966" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 188136d2..642be9b5 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -541,6 +541,7 @@ dstattr dstbase dstdata + dstdirname dstfile dstfin dstjson @@ -1098,6 +1099,7 @@ levelname lfull lfval + libballisticacore libcrypto libdir libegl @@ -1262,6 +1264,7 @@ modders modename modestr + modeval modpack modtimes moduledir @@ -1794,6 +1797,7 @@ servercfg servercmd serverdialog + serverdst serverget servermanager servermode diff --git a/Makefile b/Makefile index b901ecca..e93c078f 100644 --- a/Makefile +++ b/Makefile @@ -235,32 +235,11 @@ prefab-mac-arm64-server-debug: prefab-mac-arm64-server-debug-build prefab-mac-x86-64-server-debug-build: prereqs assets-cmake \ build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless \ - build/prefab/full/mac_x86_64_server/debug/ballisticacore_server \ - build/prefab/full/mac_x86_64_server/debug/config_template.yaml \ - build/prefab/full/mac_x86_64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_x86_64_server/debug/dist + @${STAGE_ASSETS} -cmakeserver -debug build/prefab/full/mac_x86_64_server/debug prefab-mac-arm64-server-debug-build: prereqs assets-cmake \ build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless \ - build/prefab/full/mac_arm64_server/debug/ballisticacore_server \ - build/prefab/full/mac_arm64_server/debug/config_template.yaml \ - build/prefab/full/mac_arm64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_arm64_server/debug/dist - -build/prefab/full/mac_%_server/debug/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/pcommand.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/mac_%_server/debug/config_template.yaml: \ - assets/src/server/config_template.yaml \ - tools/batools/build.py \ - tools/batools/pcommand.py \ - tools/bacommon/servermanager.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/mac_%_server/debug/README.txt: \ - assets/src/server/README.txt - @cp $< $@ + @${STAGE_ASSETS} -cmakeserver -debug build/prefab/full/mac_arm64_server/debug build/prefab/full/mac_%_server/debug/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ @@ -286,32 +265,13 @@ prefab-mac-arm64-server-release: prefab-mac-arm64-server-release-build prefab-mac-x86-64-server-release-build: prereqs assets-cmake \ build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless \ - build/prefab/full/mac_x86_64_server/release/ballisticacore_server \ - build/prefab/full/mac_x86_64_server/release/config_template.yaml \ - build/prefab/full/mac_x86_64_server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_x86_64_server/release/dist + @${STAGE_ASSETS} -cmakeserver -release \ + build/prefab/full/mac_x86_64_server/release prefab-mac-arm64-server-release-build: prereqs assets-cmake \ build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless \ - build/prefab/full/mac_arm64_server/release/ballisticacore_server \ - build/prefab/full/mac_arm64_server/release/config_template.yaml \ - build/prefab/full/mac_arm64_server/release/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/full/mac_arm64_server/release/dist - -build/prefab/full/mac_%_server/release/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/pcommand.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/mac_%_server/release/config_template.yaml: \ - assets/src/server/config_template.yaml \ - tools/batools/build.py \ - tools/batools/pcommand.py \ - tools/bacommon/servermanager.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/mac_%_server/release/README.txt: \ - assets/src/server/README.txt - @cp $< $@ + @${STAGE_ASSETS} -cmakeserver -release \ + build/prefab/full/mac_arm64_server/release build/prefab/full/mac_%_server/release/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ @@ -397,32 +357,13 @@ prefab-linux-arm64-server-debug: prefab-linux-arm64-server-debug-build prefab-linux-x86-64-server-debug-build: prereqs assets-cmake \ build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless \ - build/prefab/full/linux_x86_64_server/debug/ballisticacore_server \ - build/prefab/full/linux_x86_64_server/debug/config_template.yaml \ - build/prefab/full/linux_x86_64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/full/linux_x86_64_server/debug/dist + @${STAGE_ASSETS} -cmakeserver -debug \ + build/prefab/full/linux_x86_64_server/debug prefab-linux-arm64-server-debug-build: prereqs assets-cmake \ build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless \ - build/prefab/full/linux_arm64_server/debug/ballisticacore_server \ - build/prefab/full/linux_arm64_server/debug/config_template.yaml \ - build/prefab/full/linux_arm64_server/debug/README.txt - @${STAGE_ASSETS} -cmakeserver build/prefab/full/linux_arm64_server/debug/dist - -build/prefab/full/linux_%_server/debug/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/pcommand.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/linux_%_server/debug/config_template.yaml: \ - assets/src/server/config_template.yaml \ - tools/batools/build.py \ - tools/batools/pcommand.py \ - tools/bacommon/servermanager.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/linux_%_server/debug/README.txt: \ - assets/src/server/README.txt - @cp $< $@ + @${STAGE_ASSETS} -cmakeserver -debug \ + build/prefab/full/linux_arm64_server/debug build/prefab/full/linux_%_server/debug/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ @@ -442,28 +383,19 @@ prefab-linux-x86-64-server-release: prefab-linux-x86-64-server-release-build @tools/pcommand ensure_prefab_platform linux_x86_64 @${RUN_PREFAB_LINUX_X86_64_SERVER_RELEASE} +prefab-linux-arm64-server-release: prefab-linux-arm64-server-release-build + @tools/pcommand ensure_prefab_platform linux_arm64 + @${RUN_PREFAB_LINUX_ARM64_SERVER_RELEASE} + prefab-linux-x86-64-server-release-build: prereqs assets-cmake \ build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless \ - build/prefab/full/linux_x86_64_server/release/ballisticacore_server \ - build/prefab/full/linux_x86_64_server/release/config_template.yaml \ - build/prefab/full/linux_x86_64_server/release/README.txt - @${STAGE_ASSETS} \ - -cmakeserver build/prefab/full/linux_x86_64_server/release/dist + @${STAGE_ASSETS} -cmakeserver -release \ + build/prefab/full/linux_x86_64_server/release -build/prefab/full/linux_%_server/release/ballisticacore_server: \ - assets/src/server/ballisticacore_server.py tools/batools/pcommand.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/linux_%_server/release/config_template.yaml: \ - assets/src/server/config_template.yaml \ - tools/batools/build.py \ - tools/batools/pcommand.py \ - tools/bacommon/servermanager.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/linux_%_server/release/README.txt: \ - assets/src/server/README.txt - @cp $< $@ +prefab-linux-arm64-server-release-build: prereqs assets-cmake \ + build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless \ + @${STAGE_ASSETS} -cmakeserver -release \ + build/prefab/full/linux_arm64_server/release build/prefab/full/linux_%_server/release/dist/ballisticacore_headless: .efrocachemap @tools/pcommand efrocache_get $@ @@ -519,35 +451,12 @@ prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build prefab-windows-x86-server-debug-build: prereqs \ assets-windows-${WINPLAT_X86} \ build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe \ - build/prefab/full/windows_x86_server/debug/launch_ballisticacore_server.bat \ - build/prefab/full/windows_x86_server/debug/ballisticacore_server.py \ - build/prefab/full/windows_x86_server/debug/config_template.yaml \ - build/prefab/full/windows_x86_server/debug/README.txt @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Debug \ - build/prefab/full/windows_x86_server/debug/dist + build/prefab/full/windows_x86_server/debug build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe: .efrocachemap @tools/pcommand efrocache_get $@ -build/prefab/full/windows_%_server/debug/ballisticacore_server.py: \ - assets/src/server/ballisticacore_server.py tools/batools/pcommand.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/windows_%_server/debug/launch_ballisticacore_server.bat: \ - assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/windows_%_server/debug/config_template.yaml: \ - assets/src/server/config_template.yaml \ - tools/batools/build.py \ - tools/batools/pcommand.py \ - tools/bacommon/servermanager.py - @tools/pcommand stage_server_file debug $< $@ - -build/prefab/full/windows_%_server/debug/README.txt: \ - assets/src/server/README.txt - @cp $< $@ - # Windows server release: RUN_PREFAB_WINDOWS_X86_SERVER_RELEASE = cd \ @@ -560,36 +469,13 @@ prefab-windows-x86-server-release: prefab-windows-x86-server-release-build prefab-windows-x86-server-release-build: prereqs \ assets-windows-${WINPLAT_X86} \ - build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe \ - build/prefab/full/windows_x86_server/release/launch_ballisticacore_server.bat \ - build/prefab/full/windows_x86_server/release/ballisticacore_server.py \ - build/prefab/full/windows_x86_server/release/config_template.yaml \ - build/prefab/full/windows_x86_server/release/README.txt + build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Release \ - build/prefab/full/windows_x86_server/release/dist + build/prefab/full/windows_x86_server/release build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe: .efrocachemap @tools/pcommand efrocache_get $@ -build/prefab/full/windows_%_server/release/ballisticacore_server.py: \ - assets/src/server/ballisticacore_server.py tools/batools/pcommand.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/windows_%_server/release/launch_ballisticacore_server.bat: \ - assets/src/server/launch_ballisticacore_server.bat tools/batools/pcommand.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/windows_%_server/release/config_template.yaml: \ - assets/src/server/config_template.yaml \ - tools/batools/build.py \ - tools/batools/pcommand.py \ - tools/bacommon/servermanager.py - @tools/pcommand stage_server_file release $< $@ - -build/prefab/full/windows_%_server/release/README.txt: \ - assets/src/server/README.txt - @cp $< $@ - # Tell make which of these targets don't represent files. .PHONY: prefab-debug prefab-release prefab-debug-build prefab-release-build \ prefab-server-debug prefab-server-release prefab-server-debug-build \ @@ -608,7 +494,9 @@ build/prefab/full/windows_%_server/release/README.txt: \ prefab-linux-x86-64-release-build prefab-linux-arm64-release-build \ prefab-linux-x86-64-server-debug prefab-linux-arm64-server-debug \ prefab-linux-x86-64-server-debug-build prefab-linux-arm64-server-debug-build \ - prefab-linux-x86-64-server-release prefab-linux-x86-64-server-release-build \ + prefab-linux-x86-64-server-release prefab-linux-arm64-server-release \ + prefab-linux-x86-64-server-release-build \ + prefab-linux-arm64-server-release-build \ prefab-windows-x86-debug prefab-windows-x86-debug-build \ prefab-windows-x86-release prefab-windows-x86-release-build \ prefab-windows-x86-server-debug prefab-windows-x86-server-debug-build \ @@ -842,7 +730,7 @@ cmake-server: cmake-server-build cmake-server-build: assets-cmake resources code @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC) - @${STAGE_ASSETS} -cmakeserver build/cmake/server-$(CM_BT_LC) + @${STAGE_ASSETS} -cmakeserver -${CM_BT_LC} build/cmake/server-$(CM_BT_LC) @cd build/cmake/server-$(CM_BT_LC) && test -f Makefile \ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \ ../../../ballisticacore-cmake diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 204e68d8..6d418694 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -16,6 +16,7 @@ from efrotools import PYVER if TYPE_CHECKING: from typing import Optional, List + from pathlib import Path # Suffix for the pyc files we include in stagings. # We're using deterministic opt pyc files; see PEP 552. @@ -33,6 +34,7 @@ class Config: # We always calc src relative to this script. self.src = self.projroot + '/assets/build' self.dst: Optional[str] = None + self.serverdst: Optional[str] = None self.win_extras_src: Optional[str] = None self.win_platform: Optional[str] = None self.win_type: Optional[str] = None @@ -104,12 +106,13 @@ class Config: self.win_platform = winplt self.win_type = wintype assert winempty == '' - self.dst = args[1] self.tex_suffix = '.dds' if wintype == 'win': - pass + self.dst = args[-1] elif wintype == 'winserver': + self.dst = os.path.join(args[-1], 'dist') + self.serverdst = args[-1] self.include_textures = False self.include_audio = False self.include_models = False @@ -143,10 +146,20 @@ class Config: self.dst = args[1] self.tex_suffix = '.dds' elif '-cmakeserver' in args: - self.dst = args[1] + self.dst = os.path.join(args[-1], 'dist') + self.serverdst = args[-1] self.include_textures = False self.include_audio = False self.include_models = False + # Require either -debug or -release in args. + if '-debug' in args: + self.debug = True + assert '-release' not in args + elif '-release' in args: + self.debug = False + else: + raise RuntimeError( + "Expected either '-debug' or '-release' in args.") elif '-xcode-mac' in args: self.src = os.environ['SOURCE_ROOT'] + '/assets/build' self.dst = (os.environ['TARGET_BUILD_DIR'] + '/' + @@ -314,35 +327,7 @@ def _sync_pylib(cfg: Config) -> None: _run(cmd) -def main(projroot: str, args: Optional[List[str]] = None) -> None: - """Stage assets for a build.""" - - if args is None: - args = sys.argv - - cfg = Config(projroot) - cfg.parse_args(args) - - # Ok, now for every top level dir in src, come up with a nice single - # command to sync the needed subset of it to dst. - - # We can now use simple speedy timestamp based updates since - # we no longer have to try to preserve timestamps to get .pyc files - # to behave (hooray!) - - # Do our stripped down pylib dir for platforms that use that. - if cfg.include_pylib: - _sync_pylib(cfg) - else: - if cfg.dst is not None and os.path.isdir(cfg.dst + '/pylib'): - subprocess.run(['rm', '-rf', cfg.dst + '/pylib'], check=True) - - # On windows we need to pull in some dlls and this and that - # (we also include a non-stripped-down set of python libs). - if cfg.win_extras_src is not None: - _sync_windows_extras(cfg) - - # Now standard common game data. +def _sync_standard_game_data(cfg: Config) -> None: assert cfg.dst is not None _run('mkdir -p "' + cfg.dst + '/ba_data"') cmd = ('rsync --recursive --update --delete --delete-excluded' @@ -374,15 +359,147 @@ def main(projroot: str, args: Optional[List[str]] = None) -> None: cfg.dst + '/ba_data/"') _run(cmd) + +def _sync_server_files(cfg: Config) -> None: + assert cfg.serverdst is not None + modeval = 'debug' if cfg.debug else 'release' + stage_server_file(projroot=cfg.projroot, + mode=modeval, + infilename='assets/src/server/ballisticacore_server.py', + outfilename=os.path.join( + cfg.serverdst, + 'ballisticacore_server.py' if cfg.win_type + is not None else 'ballisticacore_server')) + stage_server_file(projroot=cfg.projroot, + mode=modeval, + infilename='assets/src/server/README.txt', + outfilename=os.path.join(cfg.serverdst, 'README.txt')) + stage_server_file(projroot=cfg.projroot, + mode=modeval, + infilename='assets/src/server/config_template.yaml', + outfilename=os.path.join(cfg.serverdst, + 'config_template.yaml')) + if cfg.win_type is not None: + stage_server_file( + projroot=cfg.projroot, + mode=modeval, + infilename='assets/src/server/launch_ballisticacore_server.bat', + outfilename=os.path.join(cfg.serverdst, + 'launch_ballisticacore_server.bat')) + + +def _write_if_changed(path: str, + contents: str, + make_executable: bool = False) -> None: + changed: bool + try: + with open(path) as infile: + existing = infile.read() + changed = (contents != existing) + except FileNotFoundError: + changed = True + if changed: + with open(path, 'w') as outfile: + outfile.write(contents) + if make_executable: + subprocess.run(['chmod', '+x', path], check=True) + + +def stage_server_file(projroot: str, mode: str, infilename: str, + outfilename: str) -> None: + """Stage files for the server environment with some filtering.""" + import batools.build + from efrotools import replace_one + if mode not in ('debug', 'release'): + raise RuntimeError(f"Invalid server-file-staging mode '{mode}';" + f" expected 'debug' or 'release'.") + + print(f'Building server file: {os.path.basename(outfilename)}') + + os.makedirs(os.path.dirname(outfilename), exist_ok=True) + + basename = os.path.basename(infilename) + if basename == 'config_template.yaml': + # Inject all available config values into the config file. + _write_if_changed( + outfilename, + batools.build.filter_server_config(str(projroot), infilename)) + + elif basename == 'ballisticacore_server.py': + # Run Python in opt mode for release builds. + with open(infilename) as infile: + lines = infile.read().splitlines() + if mode == 'release': + lines[0] = replace_one(lines[0], + f'#!/usr/bin/env python{PYVER}', + f'#!/usr/bin/env -S python{PYVER} -O') + _write_if_changed(outfilename, + '\n'.join(lines) + '\n', + make_executable=True) + elif basename == 'README.txt': + with open(infilename) as infile: + readme = infile.read() + _write_if_changed(outfilename, readme) + elif basename == 'launch_ballisticacore_server.bat': + # Run Python in opt mode for release builds. + with open(infilename) as infile: + lines = infile.read().splitlines() + if mode == 'release': + lines[1] = replace_one( + lines[1], ':: Python interpreter.', ':: Python interpreter.' + ' (in opt mode so we use bundled .opt-1.pyc files)') + lines[2] = replace_one( + lines[2], 'dist\\\\python.exe ballisticacore_server.py', + 'dist\\\\python.exe -O ballisticacore_server.py') + else: + # In debug mode we use the bundled debug interpreter. + lines[2] = replace_one( + lines[2], 'dist\\\\python.exe ballisticacore_server.py', + 'dist\\\\python_d.exe ballisticacore_server.py') + + with open(outfilename, 'w') as outfile: + outfile.write('\n'.join(lines) + '\n') + else: + raise RuntimeError(f"Unknown server file for staging: '{basename}'.") + + +def main(projroot: str, args: Optional[List[str]] = None) -> None: + """Stage assets for a build.""" + + if args is None: + args = sys.argv + + cfg = Config(projroot) + cfg.parse_args(args) + + # Ok, now for every top level dir in src, come up with a nice single + # command to sync the needed subset of it to dst. + + # We can now use simple speedy timestamp based updates since + # we no longer have to try to preserve timestamps to get .pyc files + # to behave (hooray!) + + # Do our stripped down pylib dir for platforms that use that. + if cfg.include_pylib: + _sync_pylib(cfg) + else: + if cfg.dst is not None and os.path.isdir(cfg.dst + '/pylib'): + subprocess.run(['rm', '-rf', cfg.dst + '/pylib'], check=True) + + # Sync our server files if we're doing that. + if cfg.serverdst is not None: + _sync_server_files(cfg) + + # On windows we need to pull in some dlls and this and that + # (we also include a non-stripped-down set of python libs). + if cfg.win_extras_src is not None: + _sync_windows_extras(cfg) + + # Standard stuff in ba_data + _sync_standard_game_data(cfg) + # On Android we need to build a payload file so it knows # what to pull out of the apk. if cfg.include_payload_file: + assert cfg.dst is not None _write_payload_file(cfg.dst, cfg.is_payload_full) - - -# if __name__ == '__main__': -# try: -# main() -# except CleanError as exc: -# exc.pretty_print() -# sys.exit(1) diff --git a/tools/batools/build.py b/tools/batools/build.py index 2d09ee9b..5a638f1e 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -648,15 +648,12 @@ def _get_server_config_template_yaml(projroot: str) -> str: return '\n'.join(lines_out) -def filter_server_config(projroot: str, infilepath: str, - outfilepath: str) -> None: +def filter_server_config(projroot: str, infilepath: str) -> str: """Add commented-out config options to a server config.""" with open(infilepath) as infile: cfg = infile.read() - cfg = cfg.replace('#__CONFIG_TEMPLATE_VALUES__', - _get_server_config_template_yaml(projroot)) - with open(outfilepath, 'w') as outfile: - outfile.write(cfg) + return cfg.replace('#__CONFIG_TEMPLATE_VALUES__', + _get_server_config_template_yaml(projroot)) def update_docs_md(check: bool) -> None: diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 88e47418..995fdaad 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -20,61 +20,14 @@ if TYPE_CHECKING: def stage_server_file() -> None: """Stage files for the server environment with some filtering.""" - import os - import subprocess - import batools.build from efro.error import CleanError - from efrotools import replace_one - from efrotools import PYVER + import batools.assetstaging if len(sys.argv) != 5: raise CleanError('Expected 3 args (mode, infile, outfile).') mode, infilename, outfilename = sys.argv[2], sys.argv[3], sys.argv[4] - if mode not in ('debug', 'release'): - raise CleanError(f"Invalid mode '{mode}'; expected debug or release.") - - print(f'Building server file: {os.path.basename(outfilename)}') - - os.makedirs(os.path.dirname(outfilename), exist_ok=True) - - basename = os.path.basename(infilename) - if basename == 'config_template.yaml': - # Inject all available config values into the config file. - batools.build.filter_server_config(str(PROJROOT), infilename, + batools.assetstaging.stage_server_file(str(PROJROOT), mode, infilename, outfilename) - elif basename == 'ballisticacore_server.py': - # Run Python in opt mode for release builds. - with open(infilename) as infile: - lines = infile.read().splitlines() - if mode == 'release': - lines[0] = replace_one(lines[0], - f'#!/usr/bin/env python{PYVER}', - f'#!/usr/bin/env -S python{PYVER} -O') - with open(outfilename, 'w') as outfile: - outfile.write('\n'.join(lines) + '\n') - subprocess.run(['chmod', '+x', outfilename], check=True) - elif basename == 'launch_ballisticacore_server.bat': - # Run Python in opt mode for release builds. - with open(infilename) as infile: - lines = infile.read().splitlines() - if mode == 'release': - lines[1] = replace_one( - lines[1], ':: Python interpreter.', ':: Python interpreter.' - ' (in opt mode so we use bundled .opt-1.pyc files)') - lines[2] = replace_one( - lines[2], 'dist\\\\python.exe ballisticacore_server.py', - 'dist\\\\python.exe -O ballisticacore_server.py') - else: - # In debug mode we use the bundled debug interpreter. - lines[2] = replace_one( - lines[2], 'dist\\\\python.exe ballisticacore_server.py', - 'dist\\\\python_d.exe ballisticacore_server.py') - - with open(outfilename, 'w') as outfile: - outfile.write('\n'.join(lines) + '\n') - else: - raise CleanError(f"Unknown server file for staging: '{basename}'.") - def py_examine() -> None: """Run a python examination at a given point in a given file.""" From 65d8547bdef268f361607003962c7520bcefa8e3 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 11 Oct 2020 15:02:43 -0700 Subject: [PATCH 243/417] Prefab Makefile fixes --- .efrocachemap | 8 ++++---- Makefile | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index 34490194..b76048f9 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3948,8 +3948,8 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/41/6b/19bf8c7fa531a27076d1c0babaff", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/fd/66/69bc3327543d711753013b9fc821", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/80/37/41e0842744af078a54e2477045e0", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cf/f5/f2df776067491dbc09500c9c3966" + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/18/f9/490e5f1e52e7e5aa119d1f4d2b40", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/df/79/37f928a3f1fd5a3219f0d80d6fbd", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ba/f3/b1bff5e3faeeacd03f9ae836c776", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5e/1e/3542fe128ce7b3c9aa727f02dcb9" } \ No newline at end of file diff --git a/Makefile b/Makefile index e93c078f..fcf7f453 100644 --- a/Makefile +++ b/Makefile @@ -234,11 +234,11 @@ prefab-mac-arm64-server-debug: prefab-mac-arm64-server-debug-build @${RUN_PREFAB_MAC_ARM64_SERVER_DEBUG} prefab-mac-x86-64-server-debug-build: prereqs assets-cmake \ - build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -debug build/prefab/full/mac_x86_64_server/debug prefab-mac-arm64-server-debug-build: prereqs assets-cmake \ - build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -debug build/prefab/full/mac_arm64_server/debug build/prefab/full/mac_%_server/debug/dist/ballisticacore_headless: .efrocachemap @@ -264,12 +264,12 @@ prefab-mac-arm64-server-release: prefab-mac-arm64-server-release-build @${RUN_PREFAB_MAC_ARM64_SERVER_RELEASE} prefab-mac-x86-64-server-release-build: prereqs assets-cmake \ - build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless \ + build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -release \ build/prefab/full/mac_x86_64_server/release prefab-mac-arm64-server-release-build: prereqs assets-cmake \ - build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless \ + build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -release \ build/prefab/full/mac_arm64_server/release @@ -356,12 +356,12 @@ prefab-linux-arm64-server-debug: prefab-linux-arm64-server-debug-build @${RUN_PREFAB_LINUX_ARM64_SERVER_DEBUG} prefab-linux-x86-64-server-debug-build: prereqs assets-cmake \ - build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -debug \ build/prefab/full/linux_x86_64_server/debug prefab-linux-arm64-server-debug-build: prereqs assets-cmake \ - build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless \ + build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -debug \ build/prefab/full/linux_arm64_server/debug @@ -388,12 +388,12 @@ prefab-linux-arm64-server-release: prefab-linux-arm64-server-release-build @${RUN_PREFAB_LINUX_ARM64_SERVER_RELEASE} prefab-linux-x86-64-server-release-build: prereqs assets-cmake \ - build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless \ + build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -release \ build/prefab/full/linux_x86_64_server/release prefab-linux-arm64-server-release-build: prereqs assets-cmake \ - build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless \ + build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless @${STAGE_ASSETS} -cmakeserver -release \ build/prefab/full/linux_arm64_server/release @@ -450,7 +450,7 @@ prefab-windows-x86-server-debug: prefab-windows-x86-server-debug-build prefab-windows-x86-server-debug-build: prereqs \ assets-windows-${WINPLAT_X86} \ - build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe \ + build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe @${STAGE_ASSETS} -winserver-${WINPLAT_X86}-Debug \ build/prefab/full/windows_x86_server/debug From 6cdc92e39d10788295335401c19f45a4b58290d7 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Sun, 11 Oct 2020 15:48:41 -0700 Subject: [PATCH 244/417] cmake server targets now use wrapper script --- .efrocachemap | 8 ++++---- Makefile | 14 ++++++++------ tools/batools/assetstaging.py | 3 +-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index b76048f9..bfcf9bf7 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3948,8 +3948,8 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/18/f9/490e5f1e52e7e5aa119d1f4d2b40", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/df/79/37f928a3f1fd5a3219f0d80d6fbd", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ba/f3/b1bff5e3faeeacd03f9ae836c776", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5e/1e/3542fe128ce7b3c9aa727f02dcb9" + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6b/16/c058434a86f13606cbd6bec7167c", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/e2/f1ef7e986d9b3cc9e5f2d392def7", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bd/b3/3e5c54b74ce8f4d606e766823903", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5a/5a/077d74f31286ced414f08cbd1f94" } \ No newline at end of file diff --git a/Makefile b/Makefile index fcf7f453..2062ad68 100644 --- a/Makefile +++ b/Makefile @@ -719,22 +719,24 @@ cmake-build: assets-cmake resources code @${STAGE_ASSETS} -cmake build/cmake/$(CM_BT_LC) @cd build/cmake/$(CM_BT_LC) && test -f Makefile \ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ - ../../../ballisticacore-cmake + ${PWD}/ballisticacore-cmake @cd build/cmake/$(CM_BT_LC) && ${MAKE} -j${CPUS} cmake-clean: rm -rf build/cmake/$(CM_BT_LC) cmake-server: cmake-server-build - @cd build/cmake/server-$(CM_BT_LC) && ./ballisticacore + @cd build/cmake/server-$(CM_BT_LC) && ./ballisticacore_server cmake-server-build: assets-cmake resources code - @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC) + @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC)/dist @${STAGE_ASSETS} -cmakeserver -${CM_BT_LC} build/cmake/server-$(CM_BT_LC) - @cd build/cmake/server-$(CM_BT_LC) && test -f Makefile \ + @cd build/cmake/server-$(CM_BT_LC)/dist && test -f Makefile \ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \ - ../../../ballisticacore-cmake - @cd build/cmake/server-$(CM_BT_LC) && ${MAKE} -j${CPUS} + ${PWD}/ballisticacore-cmake + @cd build/cmake/server-$(CM_BT_LC)/dist && ${MAKE} -j${CPUS} + @cd build/cmake/server-$(CM_BT_LC)/dist && test -f ballisticacore_headless \ + || ln -sf ballisticacore ballisticacore_headless cmake-server-clean: rm -rf build/cmake/server-$(CM_BT_LC) diff --git a/tools/batools/assetstaging.py b/tools/batools/assetstaging.py index 6d418694..a66ce5c3 100755 --- a/tools/batools/assetstaging.py +++ b/tools/batools/assetstaging.py @@ -457,8 +457,7 @@ def stage_server_file(projroot: str, mode: str, infilename: str, lines[2], 'dist\\\\python.exe ballisticacore_server.py', 'dist\\\\python_d.exe ballisticacore_server.py') - with open(outfilename, 'w') as outfile: - outfile.write('\n'.join(lines) + '\n') + _write_if_changed(outfilename, '\n'.join(lines) + '\n') else: raise RuntimeError(f"Unknown server file for staging: '{basename}'.") From 0b8e59f4789b338b2f14855a32fea361b702cbad Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 12 Oct 2020 09:40:37 -0700 Subject: [PATCH 245/417] Wiring up prefab internal libs to cmake builds --- .efrocachemap | 8 +++--- Makefile | 10 ++++++- ballisticacore-cmake/CMakeLists.txt | 2 +- tools/batools/pcommand.py | 41 +++++++++++++++++++++++++++++ tools/pcommand | 2 +- 5 files changed, 56 insertions(+), 7 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index bfcf9bf7..dcba6120 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3948,8 +3948,8 @@ "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/6b/16/c058434a86f13606cbd6bec7167c", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/e2/f1ef7e986d9b3cc9e5f2d392def7", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/bd/b3/3e5c54b74ce8f4d606e766823903", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5a/5a/077d74f31286ced414f08cbd1f94" + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7d/48/48c832b29b04ec4ccc261d56603b", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ce/5c/d36f3f9da946fbee20c3977b94a4", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/ff/eb2be69f12eca21808614649776b", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5f/8c/a767dd7cfd77dcef570feab477f1" } \ No newline at end of file diff --git a/Makefile b/Makefile index 2062ad68..08b5882b 100644 --- a/Makefile +++ b/Makefile @@ -716,6 +716,7 @@ cmake: cmake-build # Build but don't run it. cmake-build: assets-cmake resources code @tools/pcommand cmake_prep_dir build/cmake/$(CM_BT_LC) + @tools/pcommand update_prefab_libs standard ${CM_BT_LC} @${STAGE_ASSETS} -cmake build/cmake/$(CM_BT_LC) @cd build/cmake/$(CM_BT_LC) && test -f Makefile \ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) \ @@ -730,6 +731,7 @@ cmake-server: cmake-server-build cmake-server-build: assets-cmake resources code @tools/pcommand cmake_prep_dir build/cmake/server-$(CM_BT_LC)/dist + @tools/pcommand update_prefab_libs server ${CM_BT_LC} @${STAGE_ASSETS} -cmakeserver -${CM_BT_LC} build/cmake/server-$(CM_BT_LC) @cd build/cmake/server-$(CM_BT_LC)/dist && test -f Makefile \ || cmake -DCMAKE_BUILD_TYPE=$(CMAKE_BUILD_TYPE) -DHEADLESS=true \ @@ -811,9 +813,15 @@ ENV_SRC = tools/pcommand tools/batools/build.py # CMake build-type lowercase CM_BT_LC = $(shell echo $(CMAKE_BUILD_TYPE) | tr A-Z a-z) +_update-prefab-libs: + @tools/pcommand update_prefab_libs standard ${CM_BT_LC} + +_update-prefab-libs-server: + @tools/pcommand update_prefab_libs server ${CM_BT_LC} + # When using CLion, our cmake dir is root. Expose .clang-format there too. ballisticacore-cmake/.clang-format: .clang-format @cd ballisticacore-cmake && ln -sf ../.clang-format . # Tell make which of these targets don't represent files. -.PHONY: +.PHONY: _cmake-prefab-lib diff --git a/ballisticacore-cmake/CMakeLists.txt b/ballisticacore-cmake/CMakeLists.txt index 4de0a9f7..a1e2aec1 100644 --- a/ballisticacore-cmake/CMakeLists.txt +++ b/ballisticacore-cmake/CMakeLists.txt @@ -186,5 +186,5 @@ target_include_directories(ballisticacore PRIVATE # NOTE: seems we need to add 'dl' here for raspberry pi with a manually # built Python 3.8. Might be able to remove later. target_link_libraries(ballisticacore PRIVATE - ballisticacore_internal ode pthread ${Python_LIBRARIES} + ${CMAKE_CURRENT_BINARY_DIR}/prefablib/libballisticacore_internal.a ode pthread ${Python_LIBRARIES} ${SDL2_LIBRARIES} ${EXTRA_LIBRARIES} dl) diff --git a/tools/batools/pcommand.py b/tools/batools/pcommand.py index 995fdaad..f0fbebef 100644 --- a/tools/batools/pcommand.py +++ b/tools/batools/pcommand.py @@ -683,6 +683,47 @@ def update_project() -> None: Updater(check=check, fix=fix).run() +def update_prefab_libs() -> None: + """Update prefab internal libs for builds.""" + import subprocess + import os + from efro.error import CleanError + import batools.build + if len(sys.argv) != 4: + raise CleanError('Expected 2 args (standard/server, debug/release)') + buildtype = sys.argv[2] + mode = sys.argv[3] + if buildtype not in {'standard', 'server'}: + raise CleanError(f'Invalid buildtype: {buildtype}') + if mode not in {'debug', 'release'}: + raise CleanError(f'Invalid mode: {mode}') + platform = batools.build.get_current_prefab_platform() + suffix = '_server' if buildtype == 'server' else '' + target = (f'build/prefab/lib/{platform}{suffix}/{mode}/' + f'libballisticacore_internal.a') + + # Build the target and then copy it to dst if it doesn't exist there yet + # or the existing one is older than our target. + subprocess.run(['make', target], check=True) + + prefix = 'server-' if buildtype == 'server' else '' + suffix = '/dist' if buildtype == 'server' else '' + libdir = f'build/cmake/{prefix}{mode}{suffix}/prefablib' + libpath = os.path.join(libdir, 'libballisticacore_internal.a') + + update = True + time1 = os.path.getmtime(target) + if os.path.exists(libpath): + time2 = os.path.getmtime(libpath) + if time1 <= time2: + update = False + + if update: + if not os.path.exists(libdir): + os.makedirs(libdir, exist_ok=True) + subprocess.run(['cp', target, libdir], check=True) + + def cmake_prep_dir() -> None: """Create a dir, recreating it when cmake/python/etc. version changes. diff --git a/tools/pcommand b/tools/pcommand index 9a582a34..0e328029 100755 --- a/tools/pcommand +++ b/tools/pcommand @@ -37,7 +37,7 @@ from batools.pcommand import ( list_pip_reqs, install_pip_reqs, checkenv, ensure_prefab_platform, prefab_run_var, make_prefab, update_makebob, lazybuild, android_archive_unstripped_libs, efro_gradle, stage_assets, - update_assets_makefile, update_project, cmake_prep_dir) + update_assets_makefile, update_project, update_prefab_libs, cmake_prep_dir) # pylint: enable=unused-import if TYPE_CHECKING: From f1607965a662207befd1b1b54e693b8bcdf15544 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 12 Oct 2020 10:00:59 -0700 Subject: [PATCH 246/417] Tiding and license line fixes --- .efrocachemap | 40 +++++++++---------- .idea/dictionaries/ericf.xml | 4 ++ Makefile | 6 --- docs/ba_module.md | 2 +- src/ballistica/app/app.cc | 2 +- src/ballistica/ballistica.cc | 2 +- src/ballistica/core/context.cc | 2 +- src/ballistica/core/exception.cc | 2 +- src/ballistica/core/fatal_error.cc | 2 +- src/ballistica/core/inline.cc | 2 +- src/ballistica/core/logging.cc | 2 +- src/ballistica/core/macros.cc | 2 +- src/ballistica/core/module.cc | 2 +- src/ballistica/core/object.cc | 2 +- src/ballistica/core/thread.cc | 2 +- src/ballistica/generic/base64.cc | 2 +- src/ballistica/generic/huffman.cc | 2 +- src/ballistica/generic/json.cc | 2 +- src/ballistica/generic/runnable.cc | 2 +- src/ballistica/generic/timer.cc | 2 +- src/ballistica/generic/timer_list.cc | 2 +- src/ballistica/generic/utf8.cc | 2 +- src/ballistica/generic/utils.cc | 2 +- src/ballistica/graphics/area_of_interest.cc | 2 +- src/ballistica/graphics/camera.cc | 2 +- .../graphics/component/object_component.cc | 2 +- .../component/post_process_component.cc | 2 +- .../graphics/component/render_component.cc | 2 +- .../graphics/component/shield_component.cc | 2 +- .../graphics/component/simple_component.cc | 2 +- .../graphics/component/smoke_component.cc | 2 +- .../graphics/component/special_component.cc | 2 +- .../graphics/component/sprite_component.cc | 2 +- src/ballistica/graphics/frame_def.cc | 2 +- src/ballistica/graphics/gl/gl_sys.cc | 2 +- src/ballistica/graphics/gl/renderer_gl.cc | 2 +- src/ballistica/graphics/graphics.cc | 2 +- src/ballistica/graphics/graphics_server.cc | 2 +- src/ballistica/graphics/mesh/image_mesh.cc | 2 +- src/ballistica/graphics/mesh/mesh_data.cc | 2 +- .../graphics/mesh/mesh_data_client_handle.cc | 2 +- src/ballistica/graphics/mesh/text_mesh.cc | 2 +- src/ballistica/graphics/net_graph.cc | 2 +- src/ballistica/graphics/render_pass.cc | 2 +- src/ballistica/graphics/render_target.cc | 2 +- src/ballistica/graphics/renderer.cc | 2 +- src/ballistica/graphics/text/text_graphics.cc | 2 +- src/ballistica/graphics/text/text_group.cc | 2 +- src/ballistica/graphics/text/text_packer.cc | 2 +- src/ballistica/graphics/texture/dds.cc | 2 +- src/ballistica/graphics/texture/ktx.cc | 2 +- src/ballistica/graphics/texture/pvr.cc | 2 +- src/ballistica/graphics/vr_graphics.cc | 2 +- .../input/device/client_input_device.cc | 2 +- src/ballistica/input/device/input_device.cc | 2 +- src/ballistica/input/device/joystick.cc | 2 +- src/ballistica/input/device/keyboard_input.cc | 2 +- src/ballistica/input/device/test_input.cc | 2 +- src/ballistica/input/device/touch_input.cc | 2 +- src/ballistica/input/input.cc | 2 +- src/ballistica/input/remote_app.cc | 2 +- src/ballistica/input/std_input_module.cc | 2 +- src/ballistica/math/matrix44f.cc | 2 +- src/ballistica/math/random.cc | 2 +- src/ballistica/math/vector3f.cc | 2 +- .../media/component/collide_model.cc | 2 +- .../media/component/cube_map_texture.cc | 2 +- src/ballistica/media/component/data.cc | 2 +- .../media/component/media_component.cc | 2 +- src/ballistica/media/component/model.cc | 2 +- src/ballistica/media/component/sound.cc | 2 +- src/ballistica/media/component/texture.cc | 2 +- .../media/data/collide_model_data.cc | 2 +- src/ballistica/media/data/data_data.cc | 2 +- .../media/data/media_component_data.cc | 2 +- src/ballistica/media/data/model_data.cc | 2 +- src/ballistica/media/data/sound_data.cc | 2 +- src/ballistica/media/data/texture_data.cc | 2 +- .../media/data/texture_preload_data.cc | 2 +- src/ballistica/media/media.cc | 2 +- src/ballistica/media/media_server.cc | 2 +- src/ballistica/networking/telnet_server.cc | 2 +- .../platform/linux/platform_linux.cc | 2 +- src/ballistica/platform/platform.cc | 2 +- src/ballistica/platform/sdl/sdl_app.cc | 2 +- src/ballistica/python/class/python_class.cc | 2 +- .../class/python_class_activity_data.cc | 2 +- .../class/python_class_collide_model.cc | 2 +- .../python/class/python_class_context.cc | 2 +- .../python/class/python_class_context_call.cc | 2 +- .../python/class/python_class_data.cc | 2 +- .../python/class/python_class_input_device.cc | 2 +- .../python/class/python_class_material.cc | 2 +- .../python/class/python_class_model.cc | 2 +- .../python/class/python_class_node.cc | 2 +- .../python/class/python_class_session_data.cc | 2 +- .../class/python_class_session_player.cc | 2 +- .../python/class/python_class_sound.cc | 2 +- .../python/class/python_class_texture.cc | 2 +- .../python/class/python_class_timer.cc | 2 +- .../python/class/python_class_vec3.cc | 2 +- .../python/class/python_class_widget.cc | 2 +- .../python/methods/python_methods_app.cc | 2 +- .../python/methods/python_methods_gameplay.cc | 2 +- .../python/methods/python_methods_graphics.cc | 2 +- .../python/methods/python_methods_input.cc | 2 +- .../python/methods/python_methods_media.cc | 2 +- .../methods/python_methods_networking.cc | 2 +- .../python/methods/python_methods_system.cc | 2 +- .../python/methods/python_methods_ui.cc | 2 +- src/ballistica/python/python_command.cc | 2 +- src/ballistica/python/python_context_call.cc | 2 +- src/ballistica/python/python_ref.cc | 2 +- tools/batools/build.py | 2 +- tools/batools/updateproject.py | 30 ++++++-------- 115 files changed, 147 insertions(+), 155 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index dcba6120..e398a06c 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,24 +3932,24 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/24/0f/c39e95977f3a01a96cac80ec9bee", - "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/57/c4/9ac4ec70c2f05a9754f69ba6f839", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/48/dd/ef1331fc04e88b62dafaf1e918ac", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/74/e5/3d76af6120ae4fac97ccd6d06aa1", - "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/85/2238ffb603143734e13f3923a34a", - "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/a0/92/077762bb04a6957d5d7b81ccb3bf", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a4/ad/0962b48f84dde0e97a5fbc5d73b3", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/e7/5b/c3c17254122f4e2b8648fedab32c", - "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/07/26/1eee5b94f1e7a2e5a0e98d88e88a", - "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/48/08/617bb551588cdca232fdaec2ff07", - "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e3/62/3e05f6f18f0394a0d7d172749790", - "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/eb/43/297a13121358d1bf9e01d4cc5f6d", - "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/9c/fa/dd352f6c3cb26ede0a21f24d5454", - "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/32/03/d4dd9c398eab7c7da62b2e7a4096", - "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/f5/cb2b3a42e4384d6ac4dfe7a98213", - "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/06/aa/fc55996ce9a1a3e898d1348873ff", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7d/48/48c832b29b04ec4ccc261d56603b", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ce/5c/d36f3f9da946fbee20c3977b94a4", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/ff/eb2be69f12eca21808614649776b", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/5f/8c/a767dd7cfd77dcef570feab477f1" + "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6c/03d5c4811e2ffb2f341a042f676e", + "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/c0/7025f06247748ad8f0516389e4f8", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/36/4393ce5c02ebf21a6a2dbb0614eb", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/7d/2c551af0ebc26c93f52a87b02ca0", + "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/b2/ff5199a4437852f09d2d7096896d", + "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/06/5a/d683bd2197262a9baec17b7306a6", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/07/08fe94d637f560acfd450d722393", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cc/ae/2855e9d714ea0c7ceaf4f42a4dc2", + "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/fc/16cf6c1cb45381b377c1d3bac058", + "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/81/de/d2b16c91eed65ab721149488f399", + "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/5d/89/1ec1c4058821e52e117142c7fbc4", + "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9e/90/315e8edc3ab7bc1080d18e29cf8d", + "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/68/8d61d116af2df5617a11e5ae2d9d", + "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/62/fa796628f2840d880dd421f9c821", + "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f0/d0/e1e69b545cf166ce4e679621307f", + "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b1/d0/14df0a36c445e8a2e67eb8802911", + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/26/eb/3f9b13ea38c9f7af8ff0532258e8", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/56/442362d6eab98a42da31ba8cc9d6", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8f/f9/dd209379992a04c479f4cb5e3e85", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b0/d7/5ec4bfbf10cf520d2c2b85530176" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 642be9b5..2b0fe477 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -237,6 +237,7 @@ btnh btnv btnx + btype buildblessing buildblessingcheck builddir @@ -344,6 +345,7 @@ clrhdr clrnames clrred + cmakelists cmakeserver cmathmodule cmds @@ -1112,6 +1114,7 @@ libogg libopena libopenal + libpath libpython libsd libsdl @@ -1548,6 +1551,7 @@ prec precommand preexec + prefablib preflightfast preflightfull preflighting diff --git a/Makefile b/Makefile index 08b5882b..5ff7949c 100644 --- a/Makefile +++ b/Makefile @@ -813,12 +813,6 @@ ENV_SRC = tools/pcommand tools/batools/build.py # CMake build-type lowercase CM_BT_LC = $(shell echo $(CMAKE_BUILD_TYPE) | tr A-Z a-z) -_update-prefab-libs: - @tools/pcommand update_prefab_libs standard ${CM_BT_LC} - -_update-prefab-libs-server: - @tools/pcommand update_prefab_libs server ${CM_BT_LC} - # When using CLion, our cmake dir is root. Expose .clang-format there too. ballisticacore-cmake/.clang-format: .clang-format @cd ballisticacore-cmake && ln -sf ../.clang-format . diff --git a/docs/ba_module.md b/docs/ba_module.md index 8157dae5..423d0bc6 100644 --- a/docs/ba_module.md +++ b/docs/ba_module.md @@ -1,5 +1,5 @@ -

    last updated on 2020-10-10 for Ballistica version 1.5.26 build 20200

    +

    last updated on 2020-10-12 for Ballistica version 1.5.26 build 20200

    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!


    diff --git a/src/ballistica/app/app.cc b/src/ballistica/app/app.cc index ad1b686f..cf5f4c61 100644 --- a/src/ballistica/app/app.cc +++ b/src/ballistica/app/app.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/app/app.h" diff --git a/src/ballistica/ballistica.cc b/src/ballistica/ballistica.cc index 49d3c88e..c83b7446 100644 --- a/src/ballistica/ballistica.cc +++ b/src/ballistica/ballistica.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/ballistica.h" diff --git a/src/ballistica/core/context.cc b/src/ballistica/core/context.cc index 1c0b15df..c6467102 100644 --- a/src/ballistica/core/context.cc +++ b/src/ballistica/core/context.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/context.h" diff --git a/src/ballistica/core/exception.cc b/src/ballistica/core/exception.cc index 8327415e..5082b97a 100644 --- a/src/ballistica/core/exception.cc +++ b/src/ballistica/core/exception.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/exception.h" diff --git a/src/ballistica/core/fatal_error.cc b/src/ballistica/core/fatal_error.cc index a4e81aee..30759cce 100644 --- a/src/ballistica/core/fatal_error.cc +++ b/src/ballistica/core/fatal_error.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/fatal_error.h" diff --git a/src/ballistica/core/inline.cc b/src/ballistica/core/inline.cc index a84b8e11..2eef8180 100644 --- a/src/ballistica/core/inline.cc +++ b/src/ballistica/core/inline.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #if 0 // Satisfy both CppLint and CLang.. #include "ballistica/core/inline.h" diff --git a/src/ballistica/core/logging.cc b/src/ballistica/core/logging.cc index 3867415f..6831ecba 100644 --- a/src/ballistica/core/logging.cc +++ b/src/ballistica/core/logging.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/logging.h" diff --git a/src/ballistica/core/macros.cc b/src/ballistica/core/macros.cc index 73aee581..ed4a25bb 100644 --- a/src/ballistica/core/macros.cc +++ b/src/ballistica/core/macros.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/macros.h" diff --git a/src/ballistica/core/module.cc b/src/ballistica/core/module.cc index 626f8c6f..7743fcb6 100644 --- a/src/ballistica/core/module.cc +++ b/src/ballistica/core/module.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/module.h" diff --git a/src/ballistica/core/object.cc b/src/ballistica/core/object.cc index ff6e63e6..fe09a89c 100644 --- a/src/ballistica/core/object.cc +++ b/src/ballistica/core/object.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/object.h" diff --git a/src/ballistica/core/thread.cc b/src/ballistica/core/thread.cc index f9283720..c74ed90c 100644 --- a/src/ballistica/core/thread.cc +++ b/src/ballistica/core/thread.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/core/thread.h" diff --git a/src/ballistica/generic/base64.cc b/src/ballistica/generic/base64.cc index b7a76cab..19f5ed0f 100644 --- a/src/ballistica/generic/base64.cc +++ b/src/ballistica/generic/base64.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. // Derived from code licensed as follows: /* diff --git a/src/ballistica/generic/huffman.cc b/src/ballistica/generic/huffman.cc index 18e1550a..f2d24348 100644 --- a/src/ballistica/generic/huffman.cc +++ b/src/ballistica/generic/huffman.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/generic/huffman.h" diff --git a/src/ballistica/generic/json.cc b/src/ballistica/generic/json.cc index 87a0184e..1f6ca367 100644 --- a/src/ballistica/generic/json.cc +++ b/src/ballistica/generic/json.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. // Derived from code licensed as follows: /* diff --git a/src/ballistica/generic/runnable.cc b/src/ballistica/generic/runnable.cc index 108a3275..b6a8d79d 100644 --- a/src/ballistica/generic/runnable.cc +++ b/src/ballistica/generic/runnable.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/generic/runnable.h" diff --git a/src/ballistica/generic/timer.cc b/src/ballistica/generic/timer.cc index a45e40c2..882a3cb5 100644 --- a/src/ballistica/generic/timer.cc +++ b/src/ballistica/generic/timer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/generic/timer.h" diff --git a/src/ballistica/generic/timer_list.cc b/src/ballistica/generic/timer_list.cc index 05143e00..964b36e3 100644 --- a/src/ballistica/generic/timer_list.cc +++ b/src/ballistica/generic/timer_list.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/generic/timer_list.h" diff --git a/src/ballistica/generic/utf8.cc b/src/ballistica/generic/utf8.cc index ce668344..b4f40f21 100644 --- a/src/ballistica/generic/utf8.cc +++ b/src/ballistica/generic/utf8.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. // Derived from code licensed as follows: /* diff --git a/src/ballistica/generic/utils.cc b/src/ballistica/generic/utils.cc index 8788a98c..d2c9812d 100644 --- a/src/ballistica/generic/utils.cc +++ b/src/ballistica/generic/utils.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/generic/utils.h" diff --git a/src/ballistica/graphics/area_of_interest.cc b/src/ballistica/graphics/area_of_interest.cc index 645aacc5..f62bcc13 100644 --- a/src/ballistica/graphics/area_of_interest.cc +++ b/src/ballistica/graphics/area_of_interest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/area_of_interest.h" diff --git a/src/ballistica/graphics/camera.cc b/src/ballistica/graphics/camera.cc index 4db67f21..43cd8b4e 100644 --- a/src/ballistica/graphics/camera.cc +++ b/src/ballistica/graphics/camera.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/camera.h" diff --git a/src/ballistica/graphics/component/object_component.cc b/src/ballistica/graphics/component/object_component.cc index ce333d5e..a0fda454 100644 --- a/src/ballistica/graphics/component/object_component.cc +++ b/src/ballistica/graphics/component/object_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/object_component.h" diff --git a/src/ballistica/graphics/component/post_process_component.cc b/src/ballistica/graphics/component/post_process_component.cc index b79dd475..c410d9ba 100644 --- a/src/ballistica/graphics/component/post_process_component.cc +++ b/src/ballistica/graphics/component/post_process_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/post_process_component.h" diff --git a/src/ballistica/graphics/component/render_component.cc b/src/ballistica/graphics/component/render_component.cc index fdb1cc48..533474ff 100644 --- a/src/ballistica/graphics/component/render_component.cc +++ b/src/ballistica/graphics/component/render_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/render_component.h" diff --git a/src/ballistica/graphics/component/shield_component.cc b/src/ballistica/graphics/component/shield_component.cc index 216e846c..cbd9e948 100644 --- a/src/ballistica/graphics/component/shield_component.cc +++ b/src/ballistica/graphics/component/shield_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/shield_component.h" diff --git a/src/ballistica/graphics/component/simple_component.cc b/src/ballistica/graphics/component/simple_component.cc index 6f8228b8..0b31e541 100644 --- a/src/ballistica/graphics/component/simple_component.cc +++ b/src/ballistica/graphics/component/simple_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/simple_component.h" diff --git a/src/ballistica/graphics/component/smoke_component.cc b/src/ballistica/graphics/component/smoke_component.cc index 22a9a52b..9d7aaa35 100644 --- a/src/ballistica/graphics/component/smoke_component.cc +++ b/src/ballistica/graphics/component/smoke_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/smoke_component.h" diff --git a/src/ballistica/graphics/component/special_component.cc b/src/ballistica/graphics/component/special_component.cc index 9be04c15..c3f79e5d 100644 --- a/src/ballistica/graphics/component/special_component.cc +++ b/src/ballistica/graphics/component/special_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/special_component.h" diff --git a/src/ballistica/graphics/component/sprite_component.cc b/src/ballistica/graphics/component/sprite_component.cc index 4c438f5e..d9f052bc 100644 --- a/src/ballistica/graphics/component/sprite_component.cc +++ b/src/ballistica/graphics/component/sprite_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/component/sprite_component.h" diff --git a/src/ballistica/graphics/frame_def.cc b/src/ballistica/graphics/frame_def.cc index d298fa5f..e7098216 100644 --- a/src/ballistica/graphics/frame_def.cc +++ b/src/ballistica/graphics/frame_def.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/frame_def.h" diff --git a/src/ballistica/graphics/gl/gl_sys.cc b/src/ballistica/graphics/gl/gl_sys.cc index 32a610a5..b2e66444 100644 --- a/src/ballistica/graphics/gl/gl_sys.cc +++ b/src/ballistica/graphics/gl/gl_sys.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #if BA_ENABLE_OPENGL #include "ballistica/graphics/gl/gl_sys.h" diff --git a/src/ballistica/graphics/gl/renderer_gl.cc b/src/ballistica/graphics/gl/renderer_gl.cc index 0ac10649..0c853ad2 100644 --- a/src/ballistica/graphics/gl/renderer_gl.cc +++ b/src/ballistica/graphics/gl/renderer_gl.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #if BA_ENABLE_OPENGL #include "ballistica/graphics/gl/renderer_gl.h" diff --git a/src/ballistica/graphics/graphics.cc b/src/ballistica/graphics/graphics.cc index 8e9a077d..e74db670 100644 --- a/src/ballistica/graphics/graphics.cc +++ b/src/ballistica/graphics/graphics.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/graphics.h" diff --git a/src/ballistica/graphics/graphics_server.cc b/src/ballistica/graphics/graphics_server.cc index af77a907..61696137 100644 --- a/src/ballistica/graphics/graphics_server.cc +++ b/src/ballistica/graphics/graphics_server.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/graphics_server.h" diff --git a/src/ballistica/graphics/mesh/image_mesh.cc b/src/ballistica/graphics/mesh/image_mesh.cc index 1d915b5a..6045e1d8 100644 --- a/src/ballistica/graphics/mesh/image_mesh.cc +++ b/src/ballistica/graphics/mesh/image_mesh.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/mesh/image_mesh.h" diff --git a/src/ballistica/graphics/mesh/mesh_data.cc b/src/ballistica/graphics/mesh/mesh_data.cc index ba409272..e2de4570 100644 --- a/src/ballistica/graphics/mesh/mesh_data.cc +++ b/src/ballistica/graphics/mesh/mesh_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/mesh/mesh_data.h" diff --git a/src/ballistica/graphics/mesh/mesh_data_client_handle.cc b/src/ballistica/graphics/mesh/mesh_data_client_handle.cc index a0e26a78..79c073c8 100644 --- a/src/ballistica/graphics/mesh/mesh_data_client_handle.cc +++ b/src/ballistica/graphics/mesh/mesh_data_client_handle.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/mesh/mesh_data_client_handle.h" diff --git a/src/ballistica/graphics/mesh/text_mesh.cc b/src/ballistica/graphics/mesh/text_mesh.cc index c68e8649..895cf43b 100644 --- a/src/ballistica/graphics/mesh/text_mesh.cc +++ b/src/ballistica/graphics/mesh/text_mesh.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/mesh/text_mesh.h" diff --git a/src/ballistica/graphics/net_graph.cc b/src/ballistica/graphics/net_graph.cc index 86b4f427..1a618646 100644 --- a/src/ballistica/graphics/net_graph.cc +++ b/src/ballistica/graphics/net_graph.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/net_graph.h" diff --git a/src/ballistica/graphics/render_pass.cc b/src/ballistica/graphics/render_pass.cc index b5ace645..9b78edef 100644 --- a/src/ballistica/graphics/render_pass.cc +++ b/src/ballistica/graphics/render_pass.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/render_pass.h" diff --git a/src/ballistica/graphics/render_target.cc b/src/ballistica/graphics/render_target.cc index cdbb828c..4f31918d 100644 --- a/src/ballistica/graphics/render_target.cc +++ b/src/ballistica/graphics/render_target.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/render_target.h" diff --git a/src/ballistica/graphics/renderer.cc b/src/ballistica/graphics/renderer.cc index ac5c7e14..1e7a0059 100644 --- a/src/ballistica/graphics/renderer.cc +++ b/src/ballistica/graphics/renderer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/renderer.h" diff --git a/src/ballistica/graphics/text/text_graphics.cc b/src/ballistica/graphics/text/text_graphics.cc index aed7d7fa..f0634e21 100644 --- a/src/ballistica/graphics/text/text_graphics.cc +++ b/src/ballistica/graphics/text/text_graphics.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/text/text_graphics.h" diff --git a/src/ballistica/graphics/text/text_group.cc b/src/ballistica/graphics/text/text_group.cc index 0b5d7947..239656db 100644 --- a/src/ballistica/graphics/text/text_group.cc +++ b/src/ballistica/graphics/text/text_group.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/text/text_group.h" diff --git a/src/ballistica/graphics/text/text_packer.cc b/src/ballistica/graphics/text/text_packer.cc index 384d1f46..e769a9b6 100644 --- a/src/ballistica/graphics/text/text_packer.cc +++ b/src/ballistica/graphics/text/text_packer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/text/text_packer.h" diff --git a/src/ballistica/graphics/texture/dds.cc b/src/ballistica/graphics/texture/dds.cc index b3748ba2..02f2c700 100644 --- a/src/ballistica/graphics/texture/dds.cc +++ b/src/ballistica/graphics/texture/dds.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/texture/dds.h" diff --git a/src/ballistica/graphics/texture/ktx.cc b/src/ballistica/graphics/texture/ktx.cc index ec3b3f12..76cd4369 100644 --- a/src/ballistica/graphics/texture/ktx.cc +++ b/src/ballistica/graphics/texture/ktx.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/texture/ktx.h" diff --git a/src/ballistica/graphics/texture/pvr.cc b/src/ballistica/graphics/texture/pvr.cc index 94762aaf..1a0a9acf 100644 --- a/src/ballistica/graphics/texture/pvr.cc +++ b/src/ballistica/graphics/texture/pvr.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/graphics/texture/pvr.h" diff --git a/src/ballistica/graphics/vr_graphics.cc b/src/ballistica/graphics/vr_graphics.cc index 0342d428..fd8d043c 100644 --- a/src/ballistica/graphics/vr_graphics.cc +++ b/src/ballistica/graphics/vr_graphics.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #if BA_VR_BUILD #include "ballistica/graphics/vr_graphics.h" diff --git a/src/ballistica/input/device/client_input_device.cc b/src/ballistica/input/device/client_input_device.cc index 8c7e32ee..7cd2f23b 100644 --- a/src/ballistica/input/device/client_input_device.cc +++ b/src/ballistica/input/device/client_input_device.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/device/client_input_device.h" diff --git a/src/ballistica/input/device/input_device.cc b/src/ballistica/input/device/input_device.cc index a47a9a11..66a7886a 100644 --- a/src/ballistica/input/device/input_device.cc +++ b/src/ballistica/input/device/input_device.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/device/input_device.h" diff --git a/src/ballistica/input/device/joystick.cc b/src/ballistica/input/device/joystick.cc index 93662f6f..4bf4692b 100644 --- a/src/ballistica/input/device/joystick.cc +++ b/src/ballistica/input/device/joystick.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/device/joystick.h" diff --git a/src/ballistica/input/device/keyboard_input.cc b/src/ballistica/input/device/keyboard_input.cc index d3e739f5..988e0db8 100644 --- a/src/ballistica/input/device/keyboard_input.cc +++ b/src/ballistica/input/device/keyboard_input.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/device/keyboard_input.h" diff --git a/src/ballistica/input/device/test_input.cc b/src/ballistica/input/device/test_input.cc index be821d5c..782e661b 100644 --- a/src/ballistica/input/device/test_input.cc +++ b/src/ballistica/input/device/test_input.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/device/test_input.h" diff --git a/src/ballistica/input/device/touch_input.cc b/src/ballistica/input/device/touch_input.cc index 98cff073..57b51a75 100644 --- a/src/ballistica/input/device/touch_input.cc +++ b/src/ballistica/input/device/touch_input.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/device/touch_input.h" diff --git a/src/ballistica/input/input.cc b/src/ballistica/input/input.cc index f32b5026..2ea36124 100644 --- a/src/ballistica/input/input.cc +++ b/src/ballistica/input/input.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/input.h" diff --git a/src/ballistica/input/remote_app.cc b/src/ballistica/input/remote_app.cc index 23a82b19..4ee86c7d 100644 --- a/src/ballistica/input/remote_app.cc +++ b/src/ballistica/input/remote_app.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/remote_app.h" diff --git a/src/ballistica/input/std_input_module.cc b/src/ballistica/input/std_input_module.cc index 19ac6e39..6b772bfc 100644 --- a/src/ballistica/input/std_input_module.cc +++ b/src/ballistica/input/std_input_module.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/input/std_input_module.h" diff --git a/src/ballistica/math/matrix44f.cc b/src/ballistica/math/matrix44f.cc index fcdb3e10..1477feb0 100644 --- a/src/ballistica/math/matrix44f.cc +++ b/src/ballistica/math/matrix44f.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/math/matrix44f.h" diff --git a/src/ballistica/math/random.cc b/src/ballistica/math/random.cc index 5f9e531b..06bf143e 100644 --- a/src/ballistica/math/random.cc +++ b/src/ballistica/math/random.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/math/random.h" diff --git a/src/ballistica/math/vector3f.cc b/src/ballistica/math/vector3f.cc index fa49eb60..bee04ae9 100644 --- a/src/ballistica/math/vector3f.cc +++ b/src/ballistica/math/vector3f.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/math/vector3f.h" diff --git a/src/ballistica/media/component/collide_model.cc b/src/ballistica/media/component/collide_model.cc index 23c39486..64633e36 100644 --- a/src/ballistica/media/component/collide_model.cc +++ b/src/ballistica/media/component/collide_model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/collide_model.h" diff --git a/src/ballistica/media/component/cube_map_texture.cc b/src/ballistica/media/component/cube_map_texture.cc index 384cb43e..29e75f0a 100644 --- a/src/ballistica/media/component/cube_map_texture.cc +++ b/src/ballistica/media/component/cube_map_texture.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/cube_map_texture.h" diff --git a/src/ballistica/media/component/data.cc b/src/ballistica/media/component/data.cc index 8e1361a2..a62b458e 100644 --- a/src/ballistica/media/component/data.cc +++ b/src/ballistica/media/component/data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/data.h" diff --git a/src/ballistica/media/component/media_component.cc b/src/ballistica/media/component/media_component.cc index 4fe11860..cb99c240 100644 --- a/src/ballistica/media/component/media_component.cc +++ b/src/ballistica/media/component/media_component.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/media_component.h" diff --git a/src/ballistica/media/component/model.cc b/src/ballistica/media/component/model.cc index e5060444..62653746 100644 --- a/src/ballistica/media/component/model.cc +++ b/src/ballistica/media/component/model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/model.h" diff --git a/src/ballistica/media/component/sound.cc b/src/ballistica/media/component/sound.cc index 218146cf..1850625a 100644 --- a/src/ballistica/media/component/sound.cc +++ b/src/ballistica/media/component/sound.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/sound.h" diff --git a/src/ballistica/media/component/texture.cc b/src/ballistica/media/component/texture.cc index 3948927a..d5863c4d 100644 --- a/src/ballistica/media/component/texture.cc +++ b/src/ballistica/media/component/texture.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/component/texture.h" diff --git a/src/ballistica/media/data/collide_model_data.cc b/src/ballistica/media/data/collide_model_data.cc index 2486c341..2ee3cab4 100644 --- a/src/ballistica/media/data/collide_model_data.cc +++ b/src/ballistica/media/data/collide_model_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/collide_model_data.h" diff --git a/src/ballistica/media/data/data_data.cc b/src/ballistica/media/data/data_data.cc index 05555b03..80221384 100644 --- a/src/ballistica/media/data/data_data.cc +++ b/src/ballistica/media/data/data_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/data_data.h" diff --git a/src/ballistica/media/data/media_component_data.cc b/src/ballistica/media/data/media_component_data.cc index 9d7fc411..1ceae56f 100644 --- a/src/ballistica/media/data/media_component_data.cc +++ b/src/ballistica/media/data/media_component_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/media_component_data.h" diff --git a/src/ballistica/media/data/model_data.cc b/src/ballistica/media/data/model_data.cc index c0081f02..c977e3ae 100644 --- a/src/ballistica/media/data/model_data.cc +++ b/src/ballistica/media/data/model_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/model_data.h" diff --git a/src/ballistica/media/data/sound_data.cc b/src/ballistica/media/data/sound_data.cc index a9048843..1eefa6a6 100644 --- a/src/ballistica/media/data/sound_data.cc +++ b/src/ballistica/media/data/sound_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/sound_data.h" diff --git a/src/ballistica/media/data/texture_data.cc b/src/ballistica/media/data/texture_data.cc index 0b43a6e1..16e52ab6 100644 --- a/src/ballistica/media/data/texture_data.cc +++ b/src/ballistica/media/data/texture_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/texture_data.h" diff --git a/src/ballistica/media/data/texture_preload_data.cc b/src/ballistica/media/data/texture_preload_data.cc index aa78d528..b39c79ff 100644 --- a/src/ballistica/media/data/texture_preload_data.cc +++ b/src/ballistica/media/data/texture_preload_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/data/texture_preload_data.h" diff --git a/src/ballistica/media/media.cc b/src/ballistica/media/media.cc index 0f80f5f9..ecc1a14a 100644 --- a/src/ballistica/media/media.cc +++ b/src/ballistica/media/media.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/media.h" diff --git a/src/ballistica/media/media_server.cc b/src/ballistica/media/media_server.cc index e869506e..ed927cd1 100644 --- a/src/ballistica/media/media_server.cc +++ b/src/ballistica/media/media_server.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/media/media_server.h" diff --git a/src/ballistica/networking/telnet_server.cc b/src/ballistica/networking/telnet_server.cc index 39d4be31..69702fd6 100644 --- a/src/ballistica/networking/telnet_server.cc +++ b/src/ballistica/networking/telnet_server.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/networking/telnet_server.h" diff --git a/src/ballistica/platform/linux/platform_linux.cc b/src/ballistica/platform/linux/platform_linux.cc index 47550ef9..a126fc8b 100644 --- a/src/ballistica/platform/linux/platform_linux.cc +++ b/src/ballistica/platform/linux/platform_linux.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #if BA_OSTYPE_LINUX #include "ballistica/platform/linux/platform_linux.h" diff --git a/src/ballistica/platform/platform.cc b/src/ballistica/platform/platform.cc index 3f5293ff..cac35412 100644 --- a/src/ballistica/platform/platform.cc +++ b/src/ballistica/platform/platform.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/platform/platform.h" diff --git a/src/ballistica/platform/sdl/sdl_app.cc b/src/ballistica/platform/sdl/sdl_app.cc index c6537f6c..6cd2c6a9 100644 --- a/src/ballistica/platform/sdl/sdl_app.cc +++ b/src/ballistica/platform/sdl/sdl_app.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #if BA_SDL_BUILD diff --git a/src/ballistica/python/class/python_class.cc b/src/ballistica/python/class/python_class.cc index 38316058..00e458d8 100644 --- a/src/ballistica/python/class/python_class.cc +++ b/src/ballistica/python/class/python_class.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class.h" diff --git a/src/ballistica/python/class/python_class_activity_data.cc b/src/ballistica/python/class/python_class_activity_data.cc index 793c539e..e4a28343 100644 --- a/src/ballistica/python/class/python_class_activity_data.cc +++ b/src/ballistica/python/class/python_class_activity_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_activity_data.h" diff --git a/src/ballistica/python/class/python_class_collide_model.cc b/src/ballistica/python/class/python_class_collide_model.cc index 8411b23a..cb1cb177 100644 --- a/src/ballistica/python/class/python_class_collide_model.cc +++ b/src/ballistica/python/class/python_class_collide_model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_collide_model.h" diff --git a/src/ballistica/python/class/python_class_context.cc b/src/ballistica/python/class/python_class_context.cc index b5539c98..6379ba58 100644 --- a/src/ballistica/python/class/python_class_context.cc +++ b/src/ballistica/python/class/python_class_context.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_context.h" diff --git a/src/ballistica/python/class/python_class_context_call.cc b/src/ballistica/python/class/python_class_context_call.cc index 69d0854b..dd48845b 100644 --- a/src/ballistica/python/class/python_class_context_call.cc +++ b/src/ballistica/python/class/python_class_context_call.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_context_call.h" diff --git a/src/ballistica/python/class/python_class_data.cc b/src/ballistica/python/class/python_class_data.cc index 2f8b9113..2476aad5 100644 --- a/src/ballistica/python/class/python_class_data.cc +++ b/src/ballistica/python/class/python_class_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_data.h" diff --git a/src/ballistica/python/class/python_class_input_device.cc b/src/ballistica/python/class/python_class_input_device.cc index 6176f119..21b1286f 100644 --- a/src/ballistica/python/class/python_class_input_device.cc +++ b/src/ballistica/python/class/python_class_input_device.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_input_device.h" diff --git a/src/ballistica/python/class/python_class_material.cc b/src/ballistica/python/class/python_class_material.cc index 21d5a93a..adfc05ef 100644 --- a/src/ballistica/python/class/python_class_material.cc +++ b/src/ballistica/python/class/python_class_material.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_material.h" diff --git a/src/ballistica/python/class/python_class_model.cc b/src/ballistica/python/class/python_class_model.cc index 65966b02..3480a59e 100644 --- a/src/ballistica/python/class/python_class_model.cc +++ b/src/ballistica/python/class/python_class_model.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_model.h" diff --git a/src/ballistica/python/class/python_class_node.cc b/src/ballistica/python/class/python_class_node.cc index cee7795e..6f0543fb 100644 --- a/src/ballistica/python/class/python_class_node.cc +++ b/src/ballistica/python/class/python_class_node.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_node.h" diff --git a/src/ballistica/python/class/python_class_session_data.cc b/src/ballistica/python/class/python_class_session_data.cc index 57aadb34..ad1ffacd 100644 --- a/src/ballistica/python/class/python_class_session_data.cc +++ b/src/ballistica/python/class/python_class_session_data.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_session_data.h" diff --git a/src/ballistica/python/class/python_class_session_player.cc b/src/ballistica/python/class/python_class_session_player.cc index a407107b..8b8026fc 100644 --- a/src/ballistica/python/class/python_class_session_player.cc +++ b/src/ballistica/python/class/python_class_session_player.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_session_player.h" diff --git a/src/ballistica/python/class/python_class_sound.cc b/src/ballistica/python/class/python_class_sound.cc index 960fa0dc..c3062523 100644 --- a/src/ballistica/python/class/python_class_sound.cc +++ b/src/ballistica/python/class/python_class_sound.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_sound.h" diff --git a/src/ballistica/python/class/python_class_texture.cc b/src/ballistica/python/class/python_class_texture.cc index 3a366036..066bac50 100644 --- a/src/ballistica/python/class/python_class_texture.cc +++ b/src/ballistica/python/class/python_class_texture.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_texture.h" diff --git a/src/ballistica/python/class/python_class_timer.cc b/src/ballistica/python/class/python_class_timer.cc index 5dc2b7ce..e432f2a7 100644 --- a/src/ballistica/python/class/python_class_timer.cc +++ b/src/ballistica/python/class/python_class_timer.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_timer.h" diff --git a/src/ballistica/python/class/python_class_vec3.cc b/src/ballistica/python/class/python_class_vec3.cc index 1f396f5d..01add733 100644 --- a/src/ballistica/python/class/python_class_vec3.cc +++ b/src/ballistica/python/class/python_class_vec3.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_vec3.h" diff --git a/src/ballistica/python/class/python_class_widget.cc b/src/ballistica/python/class/python_class_widget.cc index dde68f46..f7e18620 100644 --- a/src/ballistica/python/class/python_class_widget.cc +++ b/src/ballistica/python/class/python_class_widget.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/class/python_class_widget.h" diff --git a/src/ballistica/python/methods/python_methods_app.cc b/src/ballistica/python/methods/python_methods_app.cc index c5d8c3af..260430b1 100644 --- a/src/ballistica/python/methods/python_methods_app.cc +++ b/src/ballistica/python/methods/python_methods_app.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_app.h" diff --git a/src/ballistica/python/methods/python_methods_gameplay.cc b/src/ballistica/python/methods/python_methods_gameplay.cc index 54f3c7b2..bd45ab7a 100644 --- a/src/ballistica/python/methods/python_methods_gameplay.cc +++ b/src/ballistica/python/methods/python_methods_gameplay.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_gameplay.h" diff --git a/src/ballistica/python/methods/python_methods_graphics.cc b/src/ballistica/python/methods/python_methods_graphics.cc index 92bbf923..b7342b52 100644 --- a/src/ballistica/python/methods/python_methods_graphics.cc +++ b/src/ballistica/python/methods/python_methods_graphics.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_graphics.h" diff --git a/src/ballistica/python/methods/python_methods_input.cc b/src/ballistica/python/methods/python_methods_input.cc index e98cc541..5d008e66 100644 --- a/src/ballistica/python/methods/python_methods_input.cc +++ b/src/ballistica/python/methods/python_methods_input.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_input.h" diff --git a/src/ballistica/python/methods/python_methods_media.cc b/src/ballistica/python/methods/python_methods_media.cc index bd775568..92cf06be 100644 --- a/src/ballistica/python/methods/python_methods_media.cc +++ b/src/ballistica/python/methods/python_methods_media.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_media.h" diff --git a/src/ballistica/python/methods/python_methods_networking.cc b/src/ballistica/python/methods/python_methods_networking.cc index 2d5cb1eb..d74a6d9e 100644 --- a/src/ballistica/python/methods/python_methods_networking.cc +++ b/src/ballistica/python/methods/python_methods_networking.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_networking.h" diff --git a/src/ballistica/python/methods/python_methods_system.cc b/src/ballistica/python/methods/python_methods_system.cc index 89691355..3fc550c2 100644 --- a/src/ballistica/python/methods/python_methods_system.cc +++ b/src/ballistica/python/methods/python_methods_system.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_system.h" diff --git a/src/ballistica/python/methods/python_methods_ui.cc b/src/ballistica/python/methods/python_methods_ui.cc index 38fddc48..7668c073 100644 --- a/src/ballistica/python/methods/python_methods_ui.cc +++ b/src/ballistica/python/methods/python_methods_ui.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/methods/python_methods_ui.h" diff --git a/src/ballistica/python/python_command.cc b/src/ballistica/python/python_command.cc index 5e517d83..a9f70b36 100644 --- a/src/ballistica/python/python_command.cc +++ b/src/ballistica/python/python_command.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/python_command.h" diff --git a/src/ballistica/python/python_context_call.cc b/src/ballistica/python/python_context_call.cc index a503c971..3233dca6 100644 --- a/src/ballistica/python/python_context_call.cc +++ b/src/ballistica/python/python_context_call.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/python_context_call.h" diff --git a/src/ballistica/python/python_ref.cc b/src/ballistica/python/python_ref.cc index edd908cc..329fbfe3 100644 --- a/src/ballistica/python/python_ref.cc +++ b/src/ballistica/python/python_ref.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011-2020 Eric Froemling +// Released under the MIT License. See LICENSE for details. #include "ballistica/python/python_ref.h" diff --git a/tools/batools/build.py b/tools/batools/build.py index 5a638f1e..e2527896 100644 --- a/tools/batools/build.py +++ b/tools/batools/build.py @@ -569,7 +569,7 @@ def update_makebob() -> None: subprocess.run(['make', 'cmake-build'], check=True, env=env) subprocess.run( [ - 'cp', '-v', 'ballisticacore-cmake/build/release/make_bob', + 'cp', '-v', 'build/cmake/release/make_bob', 'tools/make_bob/mac_x86_64/' ], check=True, diff --git a/tools/batools/updateproject.py b/tools/batools/updateproject.py index feb428d3..09310206 100755 --- a/tools/batools/updateproject.py +++ b/tools/batools/updateproject.py @@ -255,19 +255,8 @@ class Updater: with open(fname) as infile: lines = infile.read().splitlines() - # Look for license line(s) if self._license_line_checks: - legal_notice = '// ' + get_legal_notice_private() - lnum = 0 - if lines[lnum] != legal_notice: - # Allow auto-correcting if it looks close already - # (don't want to blow away an unrelated line) - allow_auto = 'Copyright' in lines[ - lnum] and 'Eric Froemling' in lines[lnum] - self._add_line_correction(fname, - line_number=lnum, - expected=legal_notice, - can_auto_update=allow_auto) + self._check_c_license(fname, lines) def _check_headers(self) -> None: for header_file_raw in self._header_files: @@ -284,14 +273,9 @@ class Updater: expected=expected, can_auto_update=can_auto_update)) - def _check_header(self, fname: str) -> None: + def _check_c_license(self, fname: str, lines: List[str]) -> None: from efrotools import get_public_license - # Make sure its define guard is correct. - guard = (fname[4:].upper().replace('/', '_').replace('.', '_') + '_') - with open(fname) as fhdr: - lines = fhdr.read().splitlines() - # Look for public license line (public or private repo) # or private license line (private repo only) line_private = '// ' + get_legal_notice_private() @@ -313,6 +297,16 @@ class Updater: expected=line_private, can_auto_update=False) + def _check_header(self, fname: str) -> None: + + # Make sure its define guard is correct. + guard = (fname[4:].upper().replace('/', '_').replace('.', '_') + '_') + with open(fname) as fhdr: + lines = fhdr.read().splitlines() + + if self._license_line_checks: + self._check_c_license(fname, lines) + # Check for header guard at top line = '#ifndef ' + guard lnum = 2 From fd8497884308a8a6627d2dfa8f594de142ea0612 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 12 Oct 2020 10:35:28 -0700 Subject: [PATCH 247/417] Adding prefab server build to ci --- .github/workflows/ci.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95490cfa..7d1bf608 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,8 +11,8 @@ on: jobs: - # We run most of our testing on linux but it should apply to mac too; - # we can always add an explicit mac job if it seems worthwhile. + # We run most of our testing only on linux but it should apply to mac too; + # we can always add an explicit mac job later if it seems worthwhile. ci_unix: runs-on: ubuntu-20.04 steps: @@ -25,10 +25,12 @@ jobs: run: tools/pcommand install_pip_reqs - name: Run checks and tests run: make -j2 check test + - name: Prefab server build + run: make prefab-server-debug-build # Most of our toolset doesn't work on raw windows (outside of WSL). # However, it's nice to at least run unit tests there since some behavior - # (filesystem, etc) can vary significantly. + # (filesystem, etc) can vary significantly between windows and linux/apple. ci_windows: runs-on: windows-latest steps: From 81987882289dd6303d1b221b0033bc53a93f8577 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 12 Oct 2020 10:41:49 -0700 Subject: [PATCH 248/417] Removing build from ci - adds too much time --- .github/workflows/ci.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d1bf608..c3c00bdd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,8 +25,6 @@ jobs: run: tools/pcommand install_pip_reqs - name: Run checks and tests run: make -j2 check test - - name: Prefab server build - run: make prefab-server-debug-build # Most of our toolset doesn't work on raw windows (outside of WSL). # However, it's nice to at least run unit tests there since some behavior From ae1f93b87f940c7f77e03cb7ce5c4bc0cabc6a38 Mon Sep 17 00:00:00 2001 From: Eric Froemling Date: Mon, 12 Oct 2020 11:58:49 -0700 Subject: [PATCH 249/417] Making more of the C++ layer buildable --- .efrocachemap | 40 +- .idea/dictionaries/ericf.xml | 4 + ballisticacore-cmake/CMakeLists.txt | 435 ++ src/ballistica/audio/al_sys.cc | 51 + src/ballistica/audio/al_sys.h | 41 + src/ballistica/audio/audio.cc | 180 + src/ballistica/audio/audio.h | 82 + src/ballistica/audio/audio_server.cc | 1166 +++ src/ballistica/audio/audio_server.h | 142 + src/ballistica/audio/audio_source.cc | 133 + src/ballistica/audio/audio_source.h | 71 + src/ballistica/audio/audio_streamer.cc | 145 + src/ballistica/audio/audio_streamer.h | 62 + src/ballistica/audio/ogg_stream.cc | 136 + src/ballistica/audio/ogg_stream.h | 43 + src/ballistica/dynamics/bg/bg_dynamics.cc | 376 + src/ballistica/dynamics/bg/bg_dynamics.h | 84 + .../dynamics/bg/bg_dynamics_draw_snapshot.h | 79 + .../dynamics/bg/bg_dynamics_fuse.cc | 41 + src/ballistica/dynamics/bg/bg_dynamics_fuse.h | 24 + .../dynamics/bg/bg_dynamics_fuse_data.h | 113 + .../dynamics/bg/bg_dynamics_height_cache.cc | 173 + .../dynamics/bg/bg_dynamics_height_cache.h | 42 + .../dynamics/bg/bg_dynamics_server.cc | 2657 +++++++ .../dynamics/bg/bg_dynamics_server.h | 170 + .../dynamics/bg/bg_dynamics_shadow.cc | 53 + .../dynamics/bg/bg_dynamics_shadow.h | 36 + .../dynamics/bg/bg_dynamics_shadow_data.h | 46 + .../dynamics/bg/bg_dynamics_volume_light.cc | 47 + .../dynamics/bg/bg_dynamics_volume_light.h | 25 + .../bg/bg_dynamics_volume_light_data.h | 30 + src/ballistica/dynamics/collision.h | 44 + src/ballistica/dynamics/collision_cache.cc | 355 + src/ballistica/dynamics/collision_cache.h | 58 + src/ballistica/dynamics/dynamics.cc | 1114 +++ src/ballistica/dynamics/dynamics.h | 128 + .../material/impact_sound_material_action.cc | 74 + .../material/impact_sound_material_action.h | 39 + src/ballistica/dynamics/material/material.cc | 81 + src/ballistica/dynamics/material/material.h | 61 + .../dynamics/material/material_action.h | 51 + .../dynamics/material/material_component.cc | 227 + .../dynamics/material/material_component.h | 44 + .../material/material_condition_node.cc | 90 + .../material/material_condition_node.h | 59 + .../dynamics/material/material_context.cc | 93 + .../dynamics/material/material_context.h | 90 + .../material/node_message_material_action.cc | 45 + .../material/node_message_material_action.h | 42 + .../material/node_mod_material_action.cc | 41 + .../material/node_mod_material_action.h | 28 + .../node_user_message_material_action.cc | 61 + .../node_user_message_material_action.h | 30 + .../material/part_mod_material_action.cc | 58 + .../material/part_mod_material_action.h | 28 + .../material/python_call_material_action.cc | 51 + .../material/python_call_material_action.h | 26 + .../material/roll_sound_material_action.cc | 53 + .../material/roll_sound_material_action.h | 32 + .../material/skid_sound_material_action.cc | 54 + .../material/skid_sound_material_action.h | 33 + .../material/sound_material_action.cc | 33 + .../dynamics/material/sound_material_action.h | 32 + src/ballistica/dynamics/part.cc | 131 + src/ballistica/dynamics/part.h | 139 + src/ballistica/dynamics/rigid_body.cc | 693 ++ src/ballistica/dynamics/rigid_body.h | 215 + src/ballistica/game/connection/connection.h | 145 + .../game/connection/connection_to_client.h | 76 + .../connection/connection_to_client_udp.h | 40 + .../game/connection/connection_to_host.h | 47 + .../game/connection/connection_to_host_udp.h | 50 + .../platform/apple/platform_apple.h | 86 + .../methods/python_methods_networking.cc | 610 -- .../methods/python_methods_networking.h | 18 - src/ballistica/scene/node/anim_curve_node.cc | 136 + src/ballistica/scene/node/anim_curve_node.h | 75 + src/ballistica/scene/node/bomb_node.cc | 85 + src/ballistica/scene/node/bomb_node.h | 31 + src/ballistica/scene/node/combine_node.cc | 68 + src/ballistica/scene/node/combine_node.h | 58 + src/ballistica/scene/node/explosion_node.cc | 224 + src/ballistica/scene/node/explosion_node.h | 44 + src/ballistica/scene/node/flag_node.cc | 691 ++ src/ballistica/scene/node/flag_node.h | 77 + src/ballistica/scene/node/flash_node.cc | 60 + src/ballistica/scene/node/flash_node.h | 33 + src/ballistica/scene/node/globals_node.cc | 444 ++ src/ballistica/scene/node/globals_node.h | 130 + src/ballistica/scene/node/image_node.cc | 400 + src/ballistica/scene/node/image_node.h | 124 + src/ballistica/scene/node/light_node.cc | 153 + src/ballistica/scene/node/light_node.h | 54 + src/ballistica/scene/node/locator_node.cc | 179 + src/ballistica/scene/node/locator_node.h | 63 + src/ballistica/scene/node/math_node.cc | 116 + src/ballistica/scene/node/math_node.h | 36 + src/ballistica/scene/node/node.cc | 425 + src/ballistica/scene/node/node.h | 226 + src/ballistica/scene/node/node_attribute.cc | 270 + src/ballistica/scene/node/node_attribute.h | 1016 +++ .../scene/node/node_attribute_connection.cc | 108 + .../scene/node/node_attribute_connection.h | 26 + src/ballistica/scene/node/node_type.h | 82 + src/ballistica/scene/node/null_node.cc | 29 + src/ballistica/scene/node/null_node.h | 22 + src/ballistica/scene/node/player_node.cc | 48 + src/ballistica/scene/node/player_node.h | 29 + src/ballistica/scene/node/prop_node.cc | 718 ++ src/ballistica/scene/node/prop_node.h | 188 + src/ballistica/scene/node/region_node.cc | 106 + src/ballistica/scene/node/region_node.h | 41 + src/ballistica/scene/node/scorch_node.cc | 80 + src/ballistica/scene/node/scorch_node.h | 40 + .../scene/node/session_globals_node.cc | 50 + .../scene/node/session_globals_node.h | 22 + src/ballistica/scene/node/shield_node.cc | 287 + src/ballistica/scene/node/shield_node.h | 53 + src/ballistica/scene/node/sound_node.cc | 145 + src/ballistica/scene/node/sound_node.h | 46 + src/ballistica/scene/node/spaz_node.cc | 6817 +++++++++++++++++ src/ballistica/scene/node/spaz_node.h | 570 ++ src/ballistica/scene/node/terrain_node.cc | 259 + src/ballistica/scene/node/terrain_node.h | 89 + src/ballistica/scene/node/text_node.cc | 646 ++ src/ballistica/scene/node/text_node.h | 122 + .../scene/node/texture_sequence_node.cc | 76 + .../scene/node/texture_sequence_node.h | 33 + .../scene/node/time_display_node.cc | 137 + src/ballistica/scene/node/time_display_node.h | 71 + src/ballistica/scene/scene.cc | 624 ++ src/ballistica/scene/scene.h | 111 + src/ballistica/ui/console.cc | 364 + src/ballistica/ui/console.h | 70 + src/ballistica/ui/root_ui.cc | 394 + src/ballistica/ui/root_ui.h | 49 + src/ballistica/ui/ui.cc | 454 ++ src/ballistica/ui/ui.h | 149 + src/ballistica/ui/widget/button_widget.cc | 594 ++ src/ballistica/ui/widget/button_widget.h | 146 + src/ballistica/ui/widget/check_box_widget.cc | 325 + src/ballistica/ui/widget/check_box_widget.h | 92 + src/ballistica/ui/widget/column_widget.cc | 61 + src/ballistica/ui/widget/column_widget.h | 42 + src/ballistica/ui/widget/container_widget.cc | 1965 +++++ src/ballistica/ui/widget/container_widget.h | 277 + src/ballistica/ui/widget/h_scroll_widget.cc | 810 ++ src/ballistica/ui/widget/h_scroll_widget.h | 120 + src/ballistica/ui/widget/image_widget.cc | 180 + src/ballistica/ui/widget/image_widget.h | 118 + src/ballistica/ui/widget/root_widget.cc | 1138 +++ src/ballistica/ui/widget/root_widget.h | 68 + src/ballistica/ui/widget/row_widget.cc | 48 + src/ballistica/ui/widget/row_widget.h | 26 + src/ballistica/ui/widget/scroll_widget.cc | 845 ++ src/ballistica/ui/widget/scroll_widget.h | 120 + src/ballistica/ui/widget/stack_widget.cc | 35 + src/ballistica/ui/widget/stack_widget.h | 42 + src/ballistica/ui/widget/text_widget.cc | 929 +++ src/ballistica/ui/widget/text_widget.h | 160 + src/ballistica/ui/widget/widget.cc | 241 + src/ballistica/ui/widget/widget.h | 320 + tools/batools/updateproject.py | 52 +- tools/efrotools/__init__.py | 2 +- 164 files changed, 38709 insertions(+), 652 deletions(-) create mode 100644 src/ballistica/audio/al_sys.cc create mode 100644 src/ballistica/audio/al_sys.h create mode 100644 src/ballistica/audio/audio.cc create mode 100644 src/ballistica/audio/audio.h create mode 100644 src/ballistica/audio/audio_server.cc create mode 100644 src/ballistica/audio/audio_server.h create mode 100644 src/ballistica/audio/audio_source.cc create mode 100644 src/ballistica/audio/audio_source.h create mode 100644 src/ballistica/audio/audio_streamer.cc create mode 100644 src/ballistica/audio/audio_streamer.h create mode 100644 src/ballistica/audio/ogg_stream.cc create mode 100644 src/ballistica/audio/ogg_stream.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics.cc create mode 100644 src/ballistica/dynamics/bg/bg_dynamics.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_fuse.cc create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_fuse.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_fuse_data.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_height_cache.cc create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_height_cache.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_server.cc create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_server.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_shadow.cc create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_shadow.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_shadow_data.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_volume_light.cc create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_volume_light.h create mode 100644 src/ballistica/dynamics/bg/bg_dynamics_volume_light_data.h create mode 100644 src/ballistica/dynamics/collision.h create mode 100644 src/ballistica/dynamics/collision_cache.cc create mode 100644 src/ballistica/dynamics/collision_cache.h create mode 100644 src/ballistica/dynamics/dynamics.cc create mode 100644 src/ballistica/dynamics/dynamics.h create mode 100644 src/ballistica/dynamics/material/impact_sound_material_action.cc create mode 100644 src/ballistica/dynamics/material/impact_sound_material_action.h create mode 100644 src/ballistica/dynamics/material/material.cc create mode 100644 src/ballistica/dynamics/material/material.h create mode 100644 src/ballistica/dynamics/material/material_action.h create mode 100644 src/ballistica/dynamics/material/material_component.cc create mode 100644 src/ballistica/dynamics/material/material_component.h create mode 100644 src/ballistica/dynamics/material/material_condition_node.cc create mode 100644 src/ballistica/dynamics/material/material_condition_node.h create mode 100644 src/ballistica/dynamics/material/material_context.cc create mode 100644 src/ballistica/dynamics/material/material_context.h create mode 100644 src/ballistica/dynamics/material/node_message_material_action.cc create mode 100644 src/ballistica/dynamics/material/node_message_material_action.h create mode 100644 src/ballistica/dynamics/material/node_mod_material_action.cc create mode 100644 src/ballistica/dynamics/material/node_mod_material_action.h create mode 100644 src/ballistica/dynamics/material/node_user_message_material_action.cc create mode 100644 src/ballistica/dynamics/material/node_user_message_material_action.h create mode 100644 src/ballistica/dynamics/material/part_mod_material_action.cc create mode 100644 src/ballistica/dynamics/material/part_mod_material_action.h create mode 100644 src/ballistica/dynamics/material/python_call_material_action.cc create mode 100644 src/ballistica/dynamics/material/python_call_material_action.h create mode 100644 src/ballistica/dynamics/material/roll_sound_material_action.cc create mode 100644 src/ballistica/dynamics/material/roll_sound_material_action.h create mode 100644 src/ballistica/dynamics/material/skid_sound_material_action.cc create mode 100644 src/ballistica/dynamics/material/skid_sound_material_action.h create mode 100644 src/ballistica/dynamics/material/sound_material_action.cc create mode 100644 src/ballistica/dynamics/material/sound_material_action.h create mode 100644 src/ballistica/dynamics/part.cc create mode 100644 src/ballistica/dynamics/part.h create mode 100644 src/ballistica/dynamics/rigid_body.cc create mode 100644 src/ballistica/dynamics/rigid_body.h create mode 100644 src/ballistica/game/connection/connection.h create mode 100644 src/ballistica/game/connection/connection_to_client.h create mode 100644 src/ballistica/game/connection/connection_to_client_udp.h create mode 100644 src/ballistica/game/connection/connection_to_host.h create mode 100644 src/ballistica/game/connection/connection_to_host_udp.h create mode 100644 src/ballistica/platform/apple/platform_apple.h delete mode 100644 src/ballistica/python/methods/python_methods_networking.cc delete mode 100644 src/ballistica/python/methods/python_methods_networking.h create mode 100644 src/ballistica/scene/node/anim_curve_node.cc create mode 100644 src/ballistica/scene/node/anim_curve_node.h create mode 100644 src/ballistica/scene/node/bomb_node.cc create mode 100644 src/ballistica/scene/node/bomb_node.h create mode 100644 src/ballistica/scene/node/combine_node.cc create mode 100644 src/ballistica/scene/node/combine_node.h create mode 100644 src/ballistica/scene/node/explosion_node.cc create mode 100644 src/ballistica/scene/node/explosion_node.h create mode 100644 src/ballistica/scene/node/flag_node.cc create mode 100644 src/ballistica/scene/node/flag_node.h create mode 100644 src/ballistica/scene/node/flash_node.cc create mode 100644 src/ballistica/scene/node/flash_node.h create mode 100644 src/ballistica/scene/node/globals_node.cc create mode 100644 src/ballistica/scene/node/globals_node.h create mode 100644 src/ballistica/scene/node/image_node.cc create mode 100644 src/ballistica/scene/node/image_node.h create mode 100644 src/ballistica/scene/node/light_node.cc create mode 100644 src/ballistica/scene/node/light_node.h create mode 100644 src/ballistica/scene/node/locator_node.cc create mode 100644 src/ballistica/scene/node/locator_node.h create mode 100644 src/ballistica/scene/node/math_node.cc create mode 100644 src/ballistica/scene/node/math_node.h create mode 100644 src/ballistica/scene/node/node.cc create mode 100644 src/ballistica/scene/node/node.h create mode 100644 src/ballistica/scene/node/node_attribute.cc create mode 100644 src/ballistica/scene/node/node_attribute.h create mode 100644 src/ballistica/scene/node/node_attribute_connection.cc create mode 100644 src/ballistica/scene/node/node_attribute_connection.h create mode 100644 src/ballistica/scene/node/node_type.h create mode 100644 src/ballistica/scene/node/null_node.cc create mode 100644 src/ballistica/scene/node/null_node.h create mode 100644 src/ballistica/scene/node/player_node.cc create mode 100644 src/ballistica/scene/node/player_node.h create mode 100644 src/ballistica/scene/node/prop_node.cc create mode 100644 src/ballistica/scene/node/prop_node.h create mode 100644 src/ballistica/scene/node/region_node.cc create mode 100644 src/ballistica/scene/node/region_node.h create mode 100644 src/ballistica/scene/node/scorch_node.cc create mode 100644 src/ballistica/scene/node/scorch_node.h create mode 100644 src/ballistica/scene/node/session_globals_node.cc create mode 100644 src/ballistica/scene/node/session_globals_node.h create mode 100644 src/ballistica/scene/node/shield_node.cc create mode 100644 src/ballistica/scene/node/shield_node.h create mode 100644 src/ballistica/scene/node/sound_node.cc create mode 100644 src/ballistica/scene/node/sound_node.h create mode 100644 src/ballistica/scene/node/spaz_node.cc create mode 100644 src/ballistica/scene/node/spaz_node.h create mode 100644 src/ballistica/scene/node/terrain_node.cc create mode 100644 src/ballistica/scene/node/terrain_node.h create mode 100644 src/ballistica/scene/node/text_node.cc create mode 100644 src/ballistica/scene/node/text_node.h create mode 100644 src/ballistica/scene/node/texture_sequence_node.cc create mode 100644 src/ballistica/scene/node/texture_sequence_node.h create mode 100644 src/ballistica/scene/node/time_display_node.cc create mode 100644 src/ballistica/scene/node/time_display_node.h create mode 100644 src/ballistica/scene/scene.cc create mode 100644 src/ballistica/scene/scene.h create mode 100644 src/ballistica/ui/console.cc create mode 100644 src/ballistica/ui/console.h create mode 100644 src/ballistica/ui/root_ui.cc create mode 100644 src/ballistica/ui/root_ui.h create mode 100644 src/ballistica/ui/ui.cc create mode 100644 src/ballistica/ui/ui.h create mode 100644 src/ballistica/ui/widget/button_widget.cc create mode 100644 src/ballistica/ui/widget/button_widget.h create mode 100644 src/ballistica/ui/widget/check_box_widget.cc create mode 100644 src/ballistica/ui/widget/check_box_widget.h create mode 100644 src/ballistica/ui/widget/column_widget.cc create mode 100644 src/ballistica/ui/widget/column_widget.h create mode 100644 src/ballistica/ui/widget/container_widget.cc create mode 100644 src/ballistica/ui/widget/container_widget.h create mode 100644 src/ballistica/ui/widget/h_scroll_widget.cc create mode 100644 src/ballistica/ui/widget/h_scroll_widget.h create mode 100644 src/ballistica/ui/widget/image_widget.cc create mode 100644 src/ballistica/ui/widget/image_widget.h create mode 100644 src/ballistica/ui/widget/root_widget.cc create mode 100644 src/ballistica/ui/widget/root_widget.h create mode 100644 src/ballistica/ui/widget/row_widget.cc create mode 100644 src/ballistica/ui/widget/row_widget.h create mode 100644 src/ballistica/ui/widget/scroll_widget.cc create mode 100644 src/ballistica/ui/widget/scroll_widget.h create mode 100644 src/ballistica/ui/widget/stack_widget.cc create mode 100644 src/ballistica/ui/widget/stack_widget.h create mode 100644 src/ballistica/ui/widget/text_widget.cc create mode 100644 src/ballistica/ui/widget/text_widget.h create mode 100644 src/ballistica/ui/widget/widget.cc create mode 100644 src/ballistica/ui/widget/widget.h diff --git a/.efrocachemap b/.efrocachemap index e398a06c..3878fa79 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -3932,24 +3932,24 @@ "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/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f", - "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/88/6c/03d5c4811e2ffb2f341a042f676e", - "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/3f/c0/7025f06247748ad8f0516389e4f8", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/c9/36/4393ce5c02ebf21a6a2dbb0614eb", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/7d/2c551af0ebc26c93f52a87b02ca0", - "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/b2/ff5199a4437852f09d2d7096896d", - "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/06/5a/d683bd2197262a9baec17b7306a6", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/26/07/08fe94d637f560acfd450d722393", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/cc/ae/2855e9d714ea0c7ceaf4f42a4dc2", - "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/46/fc/16cf6c1cb45381b377c1d3bac058", - "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/81/de/d2b16c91eed65ab721149488f399", - "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/5d/89/1ec1c4058821e52e117142c7fbc4", - "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/9e/90/315e8edc3ab7bc1080d18e29cf8d", - "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ea/68/8d61d116af2df5617a11e5ae2d9d", - "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b9/62/fa796628f2840d880dd421f9c821", - "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f0/d0/e1e69b545cf166ce4e679621307f", - "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b1/d0/14df0a36c445e8a2e67eb8802911", - "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/26/eb/3f9b13ea38c9f7af8ff0532258e8", - "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/cc/56/442362d6eab98a42da31ba8cc9d6", - "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8f/f9/dd209379992a04c479f4cb5e3e85", - "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b0/d7/5ec4bfbf10cf520d2c2b85530176" + "build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/7d/82/ee9dbd4e5f7979376228d6953bf2", + "build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/8b/1b/28311c0a6459e5d4fba5b8646f3e", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/01/bb/1aa148fa278d31cb6674174b194f", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/98/7b/5f1bcd5a6ac1916ca35e10c28a30", + "build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/64/03/694933268214ba930b6f38b9c6c0", + "build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/e1/49/88c92b0f65857a88f6eaaee04483", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a0/f6/39e7caccbbcd4cd442145c17a05f", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/1d/c6/20d9325e37de411bc6fe3d41d503", + "build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/ab/14/4cf9664fb0de75dcb20b596ded74", + "build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/c3/9a/39b182b32184ae177611078f03ff", + "build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/70/e2/b993cf8dd5ede4d9e6ce42cd8c24", + "build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/60/03/166e19fae3db8f6e4b5c6a59a520", + "build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/e8/ed/62a752dbeeca8f5e99725d42e7e7", + "build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/a9/568023651355fdd0ce7a865c2872", + "build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/0d/25/2d023ef6acd6ae5aa09bf12158d3", + "build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/42/be/79eec8bc7b2cc914cc6cb8ed0769", + "build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/83/00/c2e4c96a434c1ac16e9f8b8a401e", + "build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/03/94/b12016e90c0c650b3c3222bc2453", + "build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/f2/9e/fd1ff58204bf80d0b02edfa79293", + "build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/26/5c/a738eaa3e553bb00814f2376cb5a" } \ No newline at end of file diff --git a/.idea/dictionaries/ericf.xml b/.idea/dictionaries/ericf.xml index 2b0fe477..917d442e 100644 --- a/.idea/dictionaries/ericf.xml +++ b/.idea/dictionaries/ericf.xml @@ -1009,6 +1009,7 @@ installdir instancer interfacetype + internalsrc interstitials intex intp @@ -1370,8 +1371,10 @@ nospeak nosub nosyncdir + nosyncdirlist nosyncdirs nosyncfile + nosyncfilelist nosyncfiles nosynctool nosynctools @@ -1821,6 +1824,7 @@ setactivity setalpha setbuild + setconfig setdata setlanguage setmusic diff --git a/ballisticacore-cmake/CMakeLists.txt b/ballisticacore-cmake/CMakeLists.txt index a1e2aec1..8809727e 100644 --- a/ballisticacore-cmake/CMakeLists.txt +++ b/ballisticacore-cmake/CMakeLists.txt @@ -174,6 +174,441 @@ add_executable(ballisticacore ${BA_SRC_ROOT}/external/qr_code_generator/QrCode.cpp # AUTOGENERATED_PUBLIC_BEGIN (this section is managed by the "update_project" tool) ${BA_SRC_ROOT}/ballistica/app/app.cc + ${BA_SRC_ROOT}/ballistica/app/app.h + ${BA_SRC_ROOT}/ballistica/app/app_config.h + ${BA_SRC_ROOT}/ballistica/app/app_globals.h + ${BA_SRC_ROOT}/ballistica/app/headless_app.h + ${BA_SRC_ROOT}/ballistica/app/stress_test.h + ${BA_SRC_ROOT}/ballistica/app/vr_app.h + ${BA_SRC_ROOT}/ballistica/audio/al_sys.cc + ${BA_SRC_ROOT}/ballistica/audio/al_sys.h + ${BA_SRC_ROOT}/ballistica/audio/audio.cc + ${BA_SRC_ROOT}/ballistica/audio/audio.h + ${BA_SRC_ROOT}/ballistica/audio/audio_server.cc + ${BA_SRC_ROOT}/ballistica/audio/audio_server.h + ${BA_SRC_ROOT}/ballistica/audio/audio_source.cc + ${BA_SRC_ROOT}/ballistica/audio/audio_source.h + ${BA_SRC_ROOT}/ballistica/audio/audio_streamer.cc + ${BA_SRC_ROOT}/ballistica/audio/audio_streamer.h + ${BA_SRC_ROOT}/ballistica/audio/ogg_stream.cc + ${BA_SRC_ROOT}/ballistica/audio/ogg_stream.h + ${BA_SRC_ROOT}/ballistica/ballistica.cc + ${BA_SRC_ROOT}/ballistica/ballistica.h + ${BA_SRC_ROOT}/ballistica/config/config_cmake.h + ${BA_SRC_ROOT}/ballistica/config/config_common.h + ${BA_SRC_ROOT}/ballistica/core/context.cc + ${BA_SRC_ROOT}/ballistica/core/context.h + ${BA_SRC_ROOT}/ballistica/core/exception.cc + ${BA_SRC_ROOT}/ballistica/core/exception.h + ${BA_SRC_ROOT}/ballistica/core/fatal_error.cc + ${BA_SRC_ROOT}/ballistica/core/fatal_error.h + ${BA_SRC_ROOT}/ballistica/core/inline.cc + ${BA_SRC_ROOT}/ballistica/core/inline.h + ${BA_SRC_ROOT}/ballistica/core/logging.cc + ${BA_SRC_ROOT}/ballistica/core/logging.h + ${BA_SRC_ROOT}/ballistica/core/macros.cc + ${BA_SRC_ROOT}/ballistica/core/macros.h + ${BA_SRC_ROOT}/ballistica/core/module.cc + ${BA_SRC_ROOT}/ballistica/core/module.h + ${BA_SRC_ROOT}/ballistica/core/object.cc + ${BA_SRC_ROOT}/ballistica/core/object.h + ${BA_SRC_ROOT}/ballistica/core/thread.cc + ${BA_SRC_ROOT}/ballistica/core/thread.h + ${BA_SRC_ROOT}/ballistica/core/types.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics.cc + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_fuse.cc + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_fuse.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_fuse_data.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_height_cache.cc + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_height_cache.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_server.cc + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_server.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_shadow.cc + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_shadow.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_shadow_data.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_volume_light.cc + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_volume_light.h + ${BA_SRC_ROOT}/ballistica/dynamics/bg/bg_dynamics_volume_light_data.h + ${BA_SRC_ROOT}/ballistica/dynamics/collision.h + ${BA_SRC_ROOT}/ballistica/dynamics/collision_cache.cc + ${BA_SRC_ROOT}/ballistica/dynamics/collision_cache.h + ${BA_SRC_ROOT}/ballistica/dynamics/dynamics.cc + ${BA_SRC_ROOT}/ballistica/dynamics/dynamics.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/impact_sound_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/impact_sound_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/material.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/material.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_component.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_component.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_condition_node.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_condition_node.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_context.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/material_context.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/node_message_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/node_message_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/node_mod_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/node_mod_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/node_user_message_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/node_user_message_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/part_mod_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/part_mod_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/python_call_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/python_call_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/roll_sound_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/roll_sound_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/skid_sound_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/skid_sound_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/material/sound_material_action.cc + ${BA_SRC_ROOT}/ballistica/dynamics/material/sound_material_action.h + ${BA_SRC_ROOT}/ballistica/dynamics/part.cc + ${BA_SRC_ROOT}/ballistica/dynamics/part.h + ${BA_SRC_ROOT}/ballistica/dynamics/rigid_body.cc + ${BA_SRC_ROOT}/ballistica/dynamics/rigid_body.h + ${BA_SRC_ROOT}/ballistica/game/account.h + ${BA_SRC_ROOT}/ballistica/game/client_controller_interface.h + ${BA_SRC_ROOT}/ballistica/game/connection/connection.h + ${BA_SRC_ROOT}/ballistica/game/connection/connection_to_client.h + ${BA_SRC_ROOT}/ballistica/game/connection/connection_to_client_udp.h + ${BA_SRC_ROOT}/ballistica/game/connection/connection_to_host.h + ${BA_SRC_ROOT}/ballistica/game/connection/connection_to_host_udp.h + ${BA_SRC_ROOT}/ballistica/game/friend_score_set.h + ${BA_SRC_ROOT}/ballistica/game/game.h + ${BA_SRC_ROOT}/ballistica/game/game_stream.h + ${BA_SRC_ROOT}/ballistica/game/host_activity.h + ${BA_SRC_ROOT}/ballistica/game/player.h + ${BA_SRC_ROOT}/ballistica/game/player_spec.h + ${BA_SRC_ROOT}/ballistica/game/score_to_beat.h + ${BA_SRC_ROOT}/ballistica/game/session/client_session.h + ${BA_SRC_ROOT}/ballistica/game/session/host_session.h + ${BA_SRC_ROOT}/ballistica/game/session/net_client_session.h + ${BA_SRC_ROOT}/ballistica/game/session/replay_client_session.h + ${BA_SRC_ROOT}/ballistica/game/session/session.h + ${BA_SRC_ROOT}/ballistica/generic/base64.cc + ${BA_SRC_ROOT}/ballistica/generic/base64.h + ${BA_SRC_ROOT}/ballistica/generic/buffer.h + ${BA_SRC_ROOT}/ballistica/generic/huffman.cc + ${BA_SRC_ROOT}/ballistica/generic/huffman.h + ${BA_SRC_ROOT}/ballistica/generic/json.cc + ${BA_SRC_ROOT}/ballistica/generic/json.h + ${BA_SRC_ROOT}/ballistica/generic/lambda_runnable.h + ${BA_SRC_ROOT}/ballistica/generic/real_timer.h + ${BA_SRC_ROOT}/ballistica/generic/runnable.cc + ${BA_SRC_ROOT}/ballistica/generic/runnable.h + ${BA_SRC_ROOT}/ballistica/generic/timer.cc + ${BA_SRC_ROOT}/ballistica/generic/timer.h + ${BA_SRC_ROOT}/ballistica/generic/timer_list.cc + ${BA_SRC_ROOT}/ballistica/generic/timer_list.h + ${BA_SRC_ROOT}/ballistica/generic/utf8.cc + ${BA_SRC_ROOT}/ballistica/generic/utf8.h + ${BA_SRC_ROOT}/ballistica/generic/utils.cc + ${BA_SRC_ROOT}/ballistica/generic/utils.h + ${BA_SRC_ROOT}/ballistica/graphics/area_of_interest.cc + ${BA_SRC_ROOT}/ballistica/graphics/area_of_interest.h + ${BA_SRC_ROOT}/ballistica/graphics/camera.cc + ${BA_SRC_ROOT}/ballistica/graphics/camera.h + ${BA_SRC_ROOT}/ballistica/graphics/component/empty_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/object_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/object_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/post_process_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/post_process_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/render_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/render_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/shield_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/shield_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/simple_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/simple_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/smoke_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/smoke_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/special_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/special_component.h + ${BA_SRC_ROOT}/ballistica/graphics/component/sprite_component.cc + ${BA_SRC_ROOT}/ballistica/graphics/component/sprite_component.h + ${BA_SRC_ROOT}/ballistica/graphics/frame_def.cc + ${BA_SRC_ROOT}/ballistica/graphics/frame_def.h + ${BA_SRC_ROOT}/ballistica/graphics/framebuffer.h + ${BA_SRC_ROOT}/ballistica/graphics/gl/gl_sys.cc + ${BA_SRC_ROOT}/ballistica/graphics/gl/gl_sys.h + ${BA_SRC_ROOT}/ballistica/graphics/gl/renderer_gl.cc + ${BA_SRC_ROOT}/ballistica/graphics/gl/renderer_gl.h + ${BA_SRC_ROOT}/ballistica/graphics/graphics.cc + ${BA_SRC_ROOT}/ballistica/graphics/graphics.h + ${BA_SRC_ROOT}/ballistica/graphics/graphics_server.cc + ${BA_SRC_ROOT}/ballistica/graphics/graphics_server.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/image_mesh.cc + ${BA_SRC_ROOT}/ballistica/graphics/mesh/image_mesh.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_buffer.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_buffer_base.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_buffer_vertex_simple_full.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_buffer_vertex_smoke_full.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_buffer_vertex_sprite.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_data.cc + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_data.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_data_client_handle.cc + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_data_client_handle.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_index_buffer_16.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_index_buffer_32.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_base.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_dual_texture_full.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_object_split.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_simple_full.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_simple_split.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_smoke_full.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_indexed_static_dynamic.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_non_indexed.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/mesh_renderer_data.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/sprite_mesh.h + ${BA_SRC_ROOT}/ballistica/graphics/mesh/text_mesh.cc + ${BA_SRC_ROOT}/ballistica/graphics/mesh/text_mesh.h + ${BA_SRC_ROOT}/ballistica/graphics/net_graph.cc + ${BA_SRC_ROOT}/ballistica/graphics/net_graph.h + ${BA_SRC_ROOT}/ballistica/graphics/render_command_buffer.h + ${BA_SRC_ROOT}/ballistica/graphics/render_pass.cc + ${BA_SRC_ROOT}/ballistica/graphics/render_pass.h + ${BA_SRC_ROOT}/ballistica/graphics/render_target.cc + ${BA_SRC_ROOT}/ballistica/graphics/render_target.h + ${BA_SRC_ROOT}/ballistica/graphics/renderer.cc + ${BA_SRC_ROOT}/ballistica/graphics/renderer.h + ${BA_SRC_ROOT}/ballistica/graphics/text/font_page_map_data.h + ${BA_SRC_ROOT}/ballistica/graphics/text/text_graphics.cc + ${BA_SRC_ROOT}/ballistica/graphics/text/text_graphics.h + ${BA_SRC_ROOT}/ballistica/graphics/text/text_group.cc + ${BA_SRC_ROOT}/ballistica/graphics/text/text_group.h + ${BA_SRC_ROOT}/ballistica/graphics/text/text_packer.cc + ${BA_SRC_ROOT}/ballistica/graphics/text/text_packer.h + ${BA_SRC_ROOT}/ballistica/graphics/texture/dds.cc + ${BA_SRC_ROOT}/ballistica/graphics/texture/dds.h + ${BA_SRC_ROOT}/ballistica/graphics/texture/ktx.cc + ${BA_SRC_ROOT}/ballistica/graphics/texture/ktx.h + ${BA_SRC_ROOT}/ballistica/graphics/texture/pvr.cc + ${BA_SRC_ROOT}/ballistica/graphics/texture/pvr.h + ${BA_SRC_ROOT}/ballistica/graphics/vr_graphics.cc + ${BA_SRC_ROOT}/ballistica/graphics/vr_graphics.h + ${BA_SRC_ROOT}/ballistica/input/device/client_input_device.cc + ${BA_SRC_ROOT}/ballistica/input/device/client_input_device.h + ${BA_SRC_ROOT}/ballistica/input/device/input_device.cc + ${BA_SRC_ROOT}/ballistica/input/device/input_device.h + ${BA_SRC_ROOT}/ballistica/input/device/joystick.cc + ${BA_SRC_ROOT}/ballistica/input/device/joystick.h + ${BA_SRC_ROOT}/ballistica/input/device/keyboard_input.cc + ${BA_SRC_ROOT}/ballistica/input/device/keyboard_input.h + ${BA_SRC_ROOT}/ballistica/input/device/test_input.cc + ${BA_SRC_ROOT}/ballistica/input/device/test_input.h + ${BA_SRC_ROOT}/ballistica/input/device/touch_input.cc + ${BA_SRC_ROOT}/ballistica/input/device/touch_input.h + ${BA_SRC_ROOT}/ballistica/input/input.cc + ${BA_SRC_ROOT}/ballistica/input/input.h + ${BA_SRC_ROOT}/ballistica/input/remote_app.cc + ${BA_SRC_ROOT}/ballistica/input/remote_app.h + ${BA_SRC_ROOT}/ballistica/input/std_input_module.cc + ${BA_SRC_ROOT}/ballistica/input/std_input_module.h + ${BA_SRC_ROOT}/ballistica/math/matrix44f.cc + ${BA_SRC_ROOT}/ballistica/math/matrix44f.h + ${BA_SRC_ROOT}/ballistica/math/point2d.h + ${BA_SRC_ROOT}/ballistica/math/random.cc + ${BA_SRC_ROOT}/ballistica/math/random.h + ${BA_SRC_ROOT}/ballistica/math/rect.h + ${BA_SRC_ROOT}/ballistica/math/vector2f.h + ${BA_SRC_ROOT}/ballistica/math/vector3f.cc + ${BA_SRC_ROOT}/ballistica/math/vector3f.h + ${BA_SRC_ROOT}/ballistica/math/vector4f.h + ${BA_SRC_ROOT}/ballistica/media/component/collide_model.cc + ${BA_SRC_ROOT}/ballistica/media/component/collide_model.h + ${BA_SRC_ROOT}/ballistica/media/component/cube_map_texture.cc + ${BA_SRC_ROOT}/ballistica/media/component/cube_map_texture.h + ${BA_SRC_ROOT}/ballistica/media/component/data.cc + ${BA_SRC_ROOT}/ballistica/media/component/data.h + ${BA_SRC_ROOT}/ballistica/media/component/media_component.cc + ${BA_SRC_ROOT}/ballistica/media/component/media_component.h + ${BA_SRC_ROOT}/ballistica/media/component/model.cc + ${BA_SRC_ROOT}/ballistica/media/component/model.h + ${BA_SRC_ROOT}/ballistica/media/component/sound.cc + ${BA_SRC_ROOT}/ballistica/media/component/sound.h + ${BA_SRC_ROOT}/ballistica/media/component/texture.cc + ${BA_SRC_ROOT}/ballistica/media/component/texture.h + ${BA_SRC_ROOT}/ballistica/media/data/collide_model_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/collide_model_data.h + ${BA_SRC_ROOT}/ballistica/media/data/data_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/data_data.h + ${BA_SRC_ROOT}/ballistica/media/data/media_component_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/media_component_data.h + ${BA_SRC_ROOT}/ballistica/media/data/model_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/model_data.h + ${BA_SRC_ROOT}/ballistica/media/data/model_renderer_data.h + ${BA_SRC_ROOT}/ballistica/media/data/sound_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/sound_data.h + ${BA_SRC_ROOT}/ballistica/media/data/texture_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/texture_data.h + ${BA_SRC_ROOT}/ballistica/media/data/texture_preload_data.cc + ${BA_SRC_ROOT}/ballistica/media/data/texture_preload_data.h + ${BA_SRC_ROOT}/ballistica/media/data/texture_renderer_data.h + ${BA_SRC_ROOT}/ballistica/media/media.cc + ${BA_SRC_ROOT}/ballistica/media/media.h + ${BA_SRC_ROOT}/ballistica/media/media_server.cc + ${BA_SRC_ROOT}/ballistica/media/media_server.h + ${BA_SRC_ROOT}/ballistica/networking/network_reader.h + ${BA_SRC_ROOT}/ballistica/networking/network_write_module.h + ${BA_SRC_ROOT}/ballistica/networking/networking.h + ${BA_SRC_ROOT}/ballistica/networking/networking_sys.h + ${BA_SRC_ROOT}/ballistica/networking/sockaddr.h + ${BA_SRC_ROOT}/ballistica/networking/telnet_server.cc + ${BA_SRC_ROOT}/ballistica/networking/telnet_server.h + ${BA_SRC_ROOT}/ballistica/platform/apple/platform_apple.h + ${BA_SRC_ROOT}/ballistica/platform/linux/platform_linux.cc + ${BA_SRC_ROOT}/ballistica/platform/linux/platform_linux.h + ${BA_SRC_ROOT}/ballistica/platform/min_sdl.h + ${BA_SRC_ROOT}/ballistica/platform/platform.cc + ${BA_SRC_ROOT}/ballistica/platform/platform.h + ${BA_SRC_ROOT}/ballistica/platform/sdl/sdl_app.cc + ${BA_SRC_ROOT}/ballistica/platform/sdl/sdl_app.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_activity_data.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_activity_data.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_collide_model.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_collide_model.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_context.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_context.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_context_call.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_context_call.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_data.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_data.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_input_device.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_input_device.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_material.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_material.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_model.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_model.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_node.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_node.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_session_data.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_session_data.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_session_player.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_session_player.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_sound.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_sound.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_texture.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_texture.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_timer.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_timer.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_vec3.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_vec3.h + ${BA_SRC_ROOT}/ballistica/python/class/python_class_widget.cc + ${BA_SRC_ROOT}/ballistica/python/class/python_class_widget.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_app.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_app.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_gameplay.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_gameplay.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_graphics.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_graphics.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_input.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_input.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_media.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_media.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_system.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_system.h + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_ui.cc + ${BA_SRC_ROOT}/ballistica/python/methods/python_methods_ui.h + ${BA_SRC_ROOT}/ballistica/python/python.h + ${BA_SRC_ROOT}/ballistica/python/python_command.cc + ${BA_SRC_ROOT}/ballistica/python/python_command.h + ${BA_SRC_ROOT}/ballistica/python/python_context_call.cc + ${BA_SRC_ROOT}/ballistica/python/python_context_call.h + ${BA_SRC_ROOT}/ballistica/python/python_context_call_runnable.h + ${BA_SRC_ROOT}/ballistica/python/python_ref.cc + ${BA_SRC_ROOT}/ballistica/python/python_ref.h + ${BA_SRC_ROOT}/ballistica/python/python_sys.h + ${BA_SRC_ROOT}/ballistica/scene/node/anim_curve_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/anim_curve_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/bomb_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/bomb_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/combine_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/combine_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/explosion_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/explosion_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/flag_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/flag_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/flash_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/flash_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/globals_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/globals_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/image_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/image_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/light_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/light_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/locator_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/locator_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/math_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/math_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/node.h + ${BA_SRC_ROOT}/ballistica/scene/node/node_attribute.cc + ${BA_SRC_ROOT}/ballistica/scene/node/node_attribute.h + ${BA_SRC_ROOT}/ballistica/scene/node/node_attribute_connection.cc + ${BA_SRC_ROOT}/ballistica/scene/node/node_attribute_connection.h + ${BA_SRC_ROOT}/ballistica/scene/node/node_type.h + ${BA_SRC_ROOT}/ballistica/scene/node/null_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/null_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/player_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/player_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/prop_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/prop_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/region_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/region_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/scorch_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/scorch_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/session_globals_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/session_globals_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/shield_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/shield_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/sound_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/sound_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/spaz_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/spaz_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/terrain_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/terrain_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/text_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/text_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/texture_sequence_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/texture_sequence_node.h + ${BA_SRC_ROOT}/ballistica/scene/node/time_display_node.cc + ${BA_SRC_ROOT}/ballistica/scene/node/time_display_node.h + ${BA_SRC_ROOT}/ballistica/scene/scene.cc + ${BA_SRC_ROOT}/ballistica/scene/scene.h + ${BA_SRC_ROOT}/ballistica/ui/console.cc + ${BA_SRC_ROOT}/ballistica/ui/console.h + ${BA_SRC_ROOT}/ballistica/ui/root_ui.cc + ${BA_SRC_ROOT}/ballistica/ui/root_ui.h + ${BA_SRC_ROOT}/ballistica/ui/ui.cc + ${BA_SRC_ROOT}/ballistica/ui/ui.h + ${BA_SRC_ROOT}/ballistica/ui/widget/button_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/button_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/check_box_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/check_box_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/column_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/column_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/container_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/container_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/h_scroll_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/h_scroll_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/image_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/image_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/root_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/root_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/row_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/row_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/scroll_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/scroll_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/stack_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/stack_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/text_widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/text_widget.h + ${BA_SRC_ROOT}/ballistica/ui/widget/widget.cc + ${BA_SRC_ROOT}/ballistica/ui/widget/widget.h # AUTOGENERATED_PUBLIC_END ) diff --git a/src/ballistica/audio/al_sys.cc b/src/ballistica/audio/al_sys.cc new file mode 100644 index 00000000..11518df6 --- /dev/null +++ b/src/ballistica/audio/al_sys.cc @@ -0,0 +1,51 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/audio/al_sys.h" + +#include "ballistica/audio/audio_server.h" +#include "ballistica/generic/utils.h" + +// Need to move away from OpenAL on Apple stuff. +#if __clang__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +#if BA_ENABLE_AUDIO + +namespace ballistica { + +void _check_al_error(const char* file, int line) { + if (g_audio_server->paused()) { + Log(Utils::BaseName(file) + ":" + std::to_string(line) + + ": Checking OpenAL error while paused."); + } + ALenum al_err = alGetError(); + if (al_err != AL_NO_ERROR) { + Log(Utils::BaseName(file) + ":" + std::to_string(line) + + ": OpenAL Error: " + GetALErrorString(al_err) + ";"); + } +} + +auto GetALErrorString(ALenum err) -> const char* { + static char undefErrStr[128]; +#define DO_AL_ERR_CASE(a) \ + case a: \ + return #a + switch (err) { + DO_AL_ERR_CASE(AL_INVALID_NAME); + DO_AL_ERR_CASE(AL_ILLEGAL_ENUM); + DO_AL_ERR_CASE(AL_INVALID_VALUE); + DO_AL_ERR_CASE(AL_ILLEGAL_COMMAND); + DO_AL_ERR_CASE(AL_OUT_OF_MEMORY); + default: { + snprintf(undefErrStr, sizeof(undefErrStr), "(unrecognized: 0x%X (%d))", + err, err); + return undefErrStr; + } + } +#undef DO_AL_ERR_CASE +} + +} // namespace ballistica + +#endif // BA_ENABLE_AUDIO diff --git a/src/ballistica/audio/al_sys.h b/src/ballistica/audio/al_sys.h new file mode 100644 index 00000000..44b1c740 --- /dev/null +++ b/src/ballistica/audio/al_sys.h @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_AUDIO_AL_SYS_H_ +#define BALLISTICA_AUDIO_AL_SYS_H_ + +#include + +#include "ballistica/ballistica.h" + +#if BA_ENABLE_AUDIO + +#if HAVE_FRAMEWORK_OPENAL +#include +#include +#else +#include +#include +#endif + +#define CHECK_AL_ERROR _check_al_error(__FILE__, __LINE__) +#if BA_DEBUG_BUILD +#define DEBUG_CHECK_AL_ERROR CHECK_AL_ERROR +#else +#define DEBUG_CHECK_AL_ERROR ((void)0) +#endif + +namespace ballistica { + +const int kAudioStreamBufferSize = 4096 * 8; +const int kAudioStreamBufferCount = 7; + +// Some OpenAL Error handling utils. +auto GetALErrorString(ALenum err) -> const char*; + +void _check_al_error(const char* file, int line); + +} // namespace ballistica + +#endif // BA_ENABLE_AUDIO + +#endif // BALLISTICA_AUDIO_AL_SYS_H_ diff --git a/src/ballistica/audio/audio.cc b/src/ballistica/audio/audio.cc new file mode 100644 index 00000000..4fcb6e2e --- /dev/null +++ b/src/ballistica/audio/audio.cc @@ -0,0 +1,180 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/audio/audio.h" + +#include "ballistica/audio/audio_server.h" +#include "ballistica/audio/audio_source.h" +#include "ballistica/media/data/sound_data.h" + +namespace ballistica { + +Audio::Audio() { assert(InGameThread()); } + +void Audio::Init() { + // Init our singleton. + assert(g_audio == nullptr); + g_audio = new Audio(); +} + +void Audio::Reset() { + assert(InGameThread()); + g_audio_server->PushResetCall(); +} + +void Audio::SetVolumes(float music_volume, float sound_volume) { + g_audio_server->PushSetVolumesCall(music_volume, sound_volume); +} + +void Audio::SetSoundPitch(float pitch) { + g_audio_server->PushSetSoundPitchCall(pitch); +} + +void Audio::SetListenerPosition(const Vector3f& p) { + g_audio_server->PushSetListenerPositionCall(p); +} + +void Audio::SetListenerOrientation(const Vector3f& forward, + const Vector3f& up) { + g_audio_server->PushSetListenerOrientationCall(forward, up); +} + +// This stops a particular sound play ID only. +void Audio::PushSourceStopSoundCall(uint32_t play_id) { + g_audio_server->PushCall( + [this, play_id] { g_audio_server->StopSound(play_id); }); +} + +void Audio::PushSourceFadeOutCall(uint32_t play_id, uint32_t time) { + g_audio_server->PushCall( + [this, play_id, time] { g_audio_server->FadeSoundOut(play_id, time); }); +} + +auto Audio::SourceBeginNew() -> AudioSource* { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + + AudioSource* s = nullptr; + { + // Gotta make sure to hold this until we've locked the source. + // Otherwise theoretically the audio thread could make our source available + // again before we can use it. + std::lock_guard lock(available_sources_mutex_); + + // If there's an available source, reserve and return it. + auto i = available_sources_.begin(); + if (i != available_sources_.end()) { + s = *i; + available_sources_.erase(i); + assert(s->available()); + assert(s->client_queue_size() == 0); + s->set_available(false); + } + if (s) { + s->Lock(1); + assert(!s->available()); + s->set_client_queue_size(s->client_queue_size() + 1); + } + } + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); + return s; +} + +auto Audio::IsSoundPlaying(uint32_t play_id) -> bool { + uint32_t source_id = AudioServer::source_id_from_play_id(play_id); + assert(client_sources_.size() > source_id); + client_sources_[source_id]->Lock(2); + bool result = (client_sources_[source_id]->play_id() == play_id); + client_sources_[source_id]->Unlock(); + return result; +} + +auto Audio::SourceBeginExisting(uint32_t play_id, uint32_t debug_id) + -> AudioSource* { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + uint32_t source_id = AudioServer::source_id_from_play_id(play_id); + + // Ok, the audio thread fills in this source list, + // so theoretically a client could call this before the audio thread + // has set it up. However no one should be trying to get a playing + // sound unless they've already started playing one which implies + // everything was set up already. I think we're good. + assert(g_audio->client_sources_.size() > source_id); + + // If this guy's still got the play id they're asking about, lock/return it. + client_sources_[source_id]->Lock(debug_id); + + if (client_sources_[source_id]->play_id() == play_id) { + assert(!client_sources_[source_id]->available()); + client_sources_[source_id]->set_client_queue_size( + client_sources_[source_id]->client_queue_size() + 1); + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); + return client_sources_[source_id]; + } + + // No-go; unlock and return empty-handed. + client_sources_[source_id]->Unlock(); + + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); + return nullptr; +} + +auto Audio::ShouldPlay(SoundData* sound) -> bool { + millisecs_t time = GetRealTime(); + assert(sound); + return (time - sound->last_play_time() > 50); +} + +void Audio::PlaySound(SoundData* sound, float volume) { + assert(InGameThread()); + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + assert(sound); + if (!ShouldPlay(sound)) { + return; + } + AudioSource* s = SourceBeginNew(); + if (s) { + // In vr mode, play non-positional sounds positionally in space roughly + // where the menu is. + if (IsVRMode()) { + s->SetGain(volume); + s->SetPositional(true); + float x = 0.0f; + float y = 4.5f; + float z = -3.0f; + s->SetPosition(x, y, z); + s->Play(sound); + s->End(); + } else { + s->SetGain(volume); + s->SetPositional(false); + s->Play(sound); + s->End(); + } + } + BA_DEBUG_FUNCTION_TIMER_END(20); +} + +void Audio::PlaySoundAtPosition(SoundData* sound, float volume, float x, + float y, float z) { + assert(sound); + if (!ShouldPlay(sound)) { + return; + } + // Run locally. + if (AudioSource* source = SourceBeginNew()) { + source->SetGain(volume); + source->SetPositional(true); + source->SetPosition(x, y, z); + source->Play(sound); + source->End(); + } +} + +void Audio::AddClientSource(AudioSource* source) { + client_sources_.push_back(source); +} + +void Audio::MakeSourceAvailable(AudioSource* source) { + available_sources_.push_back(source); +} + +} // namespace ballistica diff --git a/src/ballistica/audio/audio.h b/src/ballistica/audio/audio.h new file mode 100644 index 00000000..20ec7060 --- /dev/null +++ b/src/ballistica/audio/audio.h @@ -0,0 +1,82 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_AUDIO_AUDIO_H_ +#define BALLISTICA_AUDIO_AUDIO_H_ + +#include +#include +#include + +#include "ballistica/core/module.h" +#include "ballistica/core/object.h" + +namespace ballistica { + +/// Client class for audio operations; +/// used by the game and/or other threads. +class Audio { + public: + static void Init(); + void Reset(); + + void SetVolumes(float music_volume, float sound_volume); + + void SetListenerPosition(const Vector3f& p); + void SetListenerOrientation(const Vector3f& forward, const Vector3f& up); + void SetSoundPitch(float pitch); + + // Return a pointer to a locked sound source, or nullptr if they're all busy. + // The sound source will be reset to standard settings (no loop, fade 1, pos + // 0,0,0, etc). + // Send the source any immediate commands and then unlock it. + // For later modifications, re-retrieve the sound with GetPlayingSound() + auto SourceBeginNew() -> AudioSource*; + + // If a sound play id is playing, locks and returns its sound source. + // on success, you must unlock the source once done with it. + auto SourceBeginExisting(uint32_t play_id, uint32_t debug_id) -> AudioSource*; + + // Return true if the sound id is currently valid. This is not guaranteed + // to be super accurate, but can be used to determine if a sound is still + // playing. + auto IsSoundPlaying(uint32_t play_id) -> bool; + + // Simple one-shot play functions. + void PlaySound(SoundData* s, float volume = 1.0f); + void PlaySoundAtPosition(SoundData* sound, float volume, float x, float y, + float z); + + // Call this if you want to prevent repeated plays of the same sound. It'll + // tell you if the sound has been played recently. The one-shot sound-play + // functions use this under the hood. (PlaySound, PlaySoundAtPosition). + auto ShouldPlay(SoundData* s) -> bool; + + // Hmm; shouldn't these be accessed through the Source class? + void PushSourceFadeOutCall(uint32_t play_id, uint32_t time); + void PushSourceStopSoundCall(uint32_t play_id); + + void AddClientSource(AudioSource* source); + + void MakeSourceAvailable(AudioSource* source); + auto available_sources_mutex() -> std::mutex& { + return available_sources_mutex_; + } + + private: + Audio(); + + // Flat list of client sources indexed by id. + std::vector client_sources_; + + // List of sources that are ready to use. + // This is kept filled by the audio thread + // and used by the client. + std::vector available_sources_; + + // This must be locked whenever accessing the availableSources list. + std::mutex available_sources_mutex_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_AUDIO_AUDIO_H_ diff --git a/src/ballistica/audio/audio_server.cc b/src/ballistica/audio/audio_server.cc new file mode 100644 index 00000000..992bd619 --- /dev/null +++ b/src/ballistica/audio/audio_server.cc @@ -0,0 +1,1166 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/audio/audio_server.h" + +#include +#include +#include +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/al_sys.h" +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_source.h" +#include "ballistica/audio/audio_streamer.h" +#include "ballistica/audio/ogg_stream.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/timer.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/media/data/sound_data.h" +#include "ballistica/media/media.h" + +// Need to move away from OpenAL on Apple stuff. +#if __clang__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +namespace ballistica { + +// FIXME: move these to platform. +extern "C" void opensl_pause_playback(); +extern "C" void opensl_resume_playback(); + +#if BA_RIFT_BUILD +extern std::string g_rift_audio_device_name; +#endif + +const int kAudioProcessIntervalNormal = 500; +const int kAudioProcessIntervalFade = 50; +const int kAudioProcessIntervalPendingLoad = 1; +const bool kShowInUseSounds = false; + +int AudioServer::al_source_count_ = 0; + +/// Location for sound emission (server version). +class AudioServer::ThreadSource : public Object { + public: + // The id is returned as the lo-word of the identifier + // returned by "play". If valid is returned as false, there are no + // hardware channels available (or another error) and the source should + // not be used. + ThreadSource(AudioServer* audio_thread, int id, bool* valid); + ~ThreadSource() override; + void Reset() { + SetIsMusic(false); + SetPositional(true); + SetPosition(0, 0, 0); + SetGain(1.0f); + SetFade(1); + SetLooping(false); + } + + /// Set whether a sound is "music". + /// This influences which volume controls affect it. + void SetIsMusic(bool m); + + /// Set whether a source is positional. + /// A non-positional source's position coords are always relative to the + /// listener - ie: 0, 0, 0 will always be centered. + void SetPositional(bool p); + void SetPosition(float x, float y, float z); + void SetGain(float g); + void SetFade(float f); + void SetLooping(bool loop); + auto Play(const Object::Ref* s) -> uint32_t; + void Stop(); + auto play_count() -> uint32_t { return play_count_; } + auto is_streamed() const -> bool { return is_streamed_; } + auto current_is_music() const -> bool { return current_is_music_; } + auto want_to_play() const -> bool { return want_to_play_; } + auto is_actually_playing() const -> bool { return is_actually_playing_; } + auto play_id() const -> uint32_t { + return (play_count_ << 16u) | (static_cast(id_) & 0xFFFFu); + } + void UpdateAvailability(); + auto GetDefaultOwnerThread() const -> ThreadIdentifier override; + auto client_source() const -> AudioSource* { return client_source_.get(); } + auto source_sound() const -> SoundData* { + return source_sound_ ? source_sound_->get() : nullptr; + } + + void UpdatePitch(); + void UpdateVolume(); + void ExecStop(); + void ExecPlay(); + void Update(); + + private: + bool looping_ = false; + std::unique_ptr client_source_; + float fade_ = 1.0f; + float gain_ = 1.0f; + AudioServer* audio_thread_; + bool valid_ = false; + const Object::Ref* source_sound_ = nullptr; + int id_; + uint32_t play_count_ = 0; + bool is_actually_playing_ = false; + bool want_to_play_ = false; +#if BA_ENABLE_AUDIO + ALuint source_ = 0; +#endif + bool is_streamed_ = false; + + /// Whether we should be designated as "music" next time we play. + bool is_music_ = false; + + /// Whether currently playing as music. + bool current_is_music_ = false; + +#if BA_ENABLE_AUDIO + Object::Ref streamer_; +#endif + + friend class AudioServer; +}; // ThreadSource + +struct AudioServer::SoundFadeNode { + uint32_t play_id; + millisecs_t starttime; + millisecs_t endtime; + bool out; + SoundFadeNode(uint32_t play_id_in, millisecs_t duration_in, bool out_in) + : play_id(play_id_in), + starttime(GetRealTime()), + endtime(GetRealTime() + duration_in), + out(out_in) {} +}; + +void AudioServer::SetPaused(bool pause) { + if (!paused_) { + if (!pause) { + Log("Error: got audio unpause request when already unpaused."); + } else { +#if BA_OSTYPE_IOS_TVOS + // apple recommends this during audio-interruptions.. + // http://developer.apple.com/library/ios/#documentation/Audio/Conceptual/AudioSessionProgrammingGuide/Cookbook/ + // Cookbook.html#//apple_ref/doc/uid/TP40007875-CH6-SW38 + alcMakeContextCurrent(nullptr); +#endif + +// On android lets tell open-sl to stop its processing. +#if BA_OSTYPE_ANDROID + opensl_pause_playback(); +#endif // BA_OSTYPE_ANDROID + + paused_ = true; + } + } else { + // unpause if requested.. + if (pause) { + Log("Error: Got audio pause request when already paused."); + } else { +#if BA_OSTYPE_IOS_TVOS + // apple recommends this during audio-interruptions.. + // http://developer.apple.com/library/ios/#documentation/Audio/ + // Conceptual/AudioSessionProgrammingGuide/Cookbook/ + // Cookbook.html#//apple_ref/doc/uid/TP40007875-CH6-SW38 +#if BA_ENABLE_AUDIO + alcMakeContextCurrent(alc_context_); // hmm is this necessary?.. +#endif +#endif +// On android lets tell openal-soft to stop processing. +#if BA_OSTYPE_ANDROID + opensl_resume_playback(); +#endif // BA_OSTYPE_ANDROID + + paused_ = false; +#if BA_ENABLE_AUDIO + CHECK_AL_ERROR; +#endif // BA_ENABLE_AUDIO + + // Go through all of our sources and stop any we've wanted to stop while + // paused. + for (auto&& i : sources_) { + if ((!i->want_to_play()) && (i->is_actually_playing())) { + i->ExecStop(); + } + } + } + } +} + +void AudioServer::PushSourceSetIsMusicCall(uint32_t play_id, bool val) { + PushCall([this, play_id, val] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->SetIsMusic(val); + } + }); +} + +void AudioServer::PushSourceSetPositionalCall(uint32_t play_id, bool val) { + PushCall([this, play_id, val] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->SetPositional(val); + } + }); +} + +void AudioServer::PushSourceSetPositionCall(uint32_t play_id, + const Vector3f& p) { + PushCall([this, play_id, p] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->SetPosition(p.x, p.y, p.z); + } + }); +} + +void AudioServer::PushSourceSetGainCall(uint32_t play_id, float val) { + PushCall([this, play_id, val] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->SetGain(val); + } + }); +} + +void AudioServer::PushSourceSetFadeCall(uint32_t play_id, float val) { + PushCall([this, play_id, val] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->SetFade(val); + } + }); +} + +void AudioServer::PushSourceSetLoopingCall(uint32_t play_id, bool val) { + PushCall([this, play_id, val] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->SetLooping(val); + } + }); +} + +void AudioServer::PushSourcePlayCall(uint32_t play_id, + Object::Ref* sound) { + PushCall([this, play_id, sound] { + ThreadSource* s = GetPlayingSound(play_id); + + // If this play command is valid, pass it along. + // Otherwise return it immediately for deletion. + if (s) { + s->Play(sound); + } else { + AddSoundRefDelete(sound); + } + + // Let's take this opportunity to pass on newly available sources. + // This way the more things clients are playing, the more + // tight our source availability checking gets (instead of solely relying on + // our periodic process() calls). + UpdateAvailableSources(); + }); +} + +void AudioServer::PushSourceStopCall(uint32_t play_id) { + PushCall([this, play_id] { + ThreadSource* s = GetPlayingSound(play_id); + if (s) { + s->Stop(); + } + }); +} + +void AudioServer::PushSourceEndCall(uint32_t play_id) { + PushCall([this, play_id] { + ThreadSource* s = GetPlayingSound(play_id); + assert(s); + s->client_source()->Lock(5); + s->client_source()->set_client_queue_size( + s->client_source()->client_queue_size() - 1); + assert(s->client_source()->client_queue_size() >= 0); + s->client_source()->Unlock(); + }); +} + +void AudioServer::PushResetCall() { + PushCall([this] { Reset(); }); +} + +void AudioServer::PushSetListenerPositionCall(const Vector3f& p) { + PushCall([this, p] { +#if BA_ENABLE_AUDIO + if (!paused_) { + ALfloat lpos[3] = {p.x, p.y, p.z}; + alListenerfv(AL_POSITION, lpos); + CHECK_AL_ERROR; + } +#endif // BA_ENABLE_AUDIO + }); +} + +void AudioServer::PushSetListenerOrientationCall(const Vector3f& forward, + const Vector3f& up) { + PushCall([this, forward, up] { +#if BA_ENABLE_AUDIO + if (!paused_) { + ALfloat lorient[6] = {forward.x, forward.y, forward.z, up.x, up.y, up.z}; + alListenerfv(AL_ORIENTATION, lorient); + CHECK_AL_ERROR; + } +#endif // BA_ENABLE_AUDIO + }); +} + +AudioServer::AudioServer(Thread* thread) : Module("audio", thread) { + // we're a singleton.. + assert(g_audio_server == nullptr); + g_audio_server = this; + + // Get our thread to give us periodic processing time. + process_timer_ = NewThreadTimer(kAudioProcessIntervalNormal, true, + NewLambdaRunnable([this] { Process(); })); + +#if BA_ENABLE_AUDIO + + // Bring up OpenAL stuff. + { + const char* alDeviceName = nullptr; + +// On the rift build in vr mode we need to make sure we open the rift audio +// device. +#if BA_RIFT_BUILD + if (IsVRMode()) { + ALboolean enumeration = + alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"); + if (enumeration == AL_FALSE) { + Log("OpenAL enumeration extensions missing."); + } else { + const ALCchar* devices = + alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER); + const ALCchar *device = devices, *next = devices + 1; + size_t len = 0; + + // If the string is blank, we weren't able to find the oculus + // audio device. In that case we'll just go with default. + if (g_rift_audio_device_name != "") { + // Log("AL Devices list:"); + // Log("----------"); + while (device && *device != '\0' && next && *next != '\0') { + // These names seem to be things like "OpenAL Soft on FOO" + // ..we should be able to search for FOO. + if (strstr(device, g_rift_audio_device_name.c_str())) { + alDeviceName = device; + } + len = strlen(device); + device += (len + 1); + next += (len + 2); + } + // Log("----------"); + } + } + } +#endif // BA_RIFT_BUILD + + ALCdevice* device; + device = alcOpenDevice(alDeviceName); + BA_PRECONDITION(device); + alc_context_ = alcCreateContext(device, nullptr); + BA_PRECONDITION(alc_context_); + BA_PRECONDITION(alcMakeContextCurrent(alc_context_)); + CHECK_AL_ERROR; + } + + ALfloat listener_pos[] = {0.0f, 0.0f, 0.0f}; + ALfloat listener_vel[] = {0.0f, 0.0f, 0.0f}; + ALfloat listener_ori[] = {0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f}; + + alListenerfv(AL_POSITION, listener_pos); + alListenerfv(AL_VELOCITY, listener_vel); + alListenerfv(AL_ORIENTATION, listener_ori); + CHECK_AL_ERROR; + + // Create our sources. + int target_source_count = 30; + for (int i = 0; i < target_source_count; i++) { + bool valid = false; + auto s(Object::New(this, i, &valid)); + if (valid) { + s->client_source_ = std::make_unique(i); + g_audio->AddClientSource(&(*s->client_source_)); + sound_source_refs_.push_back(s); + sources_.push_back(&(*s)); + } else { + Log("Error: Made " + std::to_string(i) + " sources; (wanted " + + std::to_string(target_source_count) + ")."); + break; + } + } + CHECK_AL_ERROR; + + // Now make available any stopped sources (should be all of them). + UpdateAvailableSources(); + +#endif // BA_ENABLE_AUDIO +} + +AudioServer::~AudioServer() { +#if BA_ENABLE_AUDIO + sound_source_refs_.clear(); + + // Take down AL stuff. + { + ALCdevice* device; + BA_PRECONDITION_LOG(alcMakeContextCurrent(nullptr)); + device = alcGetContextsDevice(alc_context_); + alcDestroyContext(alc_context_); + assert(alcGetError(device) == ALC_NO_ERROR); + alcCloseDevice(device); + } + assert(streaming_sources_.empty()); + assert(al_source_count_ == 0); + +#endif // BA_ENABLE_AUDIO +} + +void AudioServer::UpdateAvailableSources() { + for (auto&& i : sources_) { + i->UpdateAvailability(); + } + +// Some sanity checking. Every now and then lets go through our sources +// and see how many are in use, how many are currently locked by the client, +// etc. +#if (BA_DEBUG_BUILD || BA_TEST_BUILD) + millisecs_t t = GetRealTime(); + if (t - last_sanity_check_time_ > 5000) { + last_sanity_check_time_ = t; + + int source_count = 0; + int in_use_source_count = 0; + std::list sounds; + for (auto&& i : sources_) { + source_count++; + + if (!i->client_source()->TryLock(4)) { + in_use_source_count++; + + // If this source has been locked for a long time, + // that probably means somebody's grabbing a source but never + // resubmitting it. + if (t - i->client_source()->last_lock_time() > 10000) { + Log("Error: Client audio source has been locked for too long; " + "probably leaked. (debug id " + + std::to_string(i->client_source()->lock_debug_id()) + ")"); + } + continue; + } + if (!i->client_source()->available()) { + in_use_source_count++; + + if (explicit_bool(kShowInUseSounds) && i->source_sound()) { + sounds.push_back((*i->source_sound()).file_name()); + } + } + i->client_source()->Unlock(); + } + + if (explicit_bool(kShowInUseSounds)) { + printf( + "------------------------------------------\n" + "%d out of %d sources in use\n", + in_use_source_count, source_count); + for (auto&& i : sounds) { + printf("%s\n", i.c_str()); + } + fflush(stdout); + } + } +#endif +} + +void AudioServer::StopSound(uint32_t play_id) { + uint32_t source = source_id_from_play_id(play_id); + uint32_t count = play_count_from_play_id(play_id); + if (source < sources_.size()) { + if (count == sources_[source]->play_count()) sources_[source]->Stop(); + } +} + +auto AudioServer::GetPlayingSound(uint32_t play_id) + -> AudioServer::ThreadSource* { + uint32_t source = source_id_from_play_id(play_id); + uint32_t count = play_count_from_play_id(play_id); + assert(source < sources_.size()); + if (source < sources_.size()) { + // If the sound has finished playing or whatnot, we + // want to make it available to the client as a new sound, + // not return it here. + sources_[source]->UpdateAvailability(); + + // If it still looks like its ours, return it.. + if (count == sources_[source]->play_count()) { + return sources_[source]; + } + } + return nullptr; +} + +void AudioServer::UpdateTimerInterval() { + // If we've got pending loads, go into uber-hyperactive mode. + if (have_pending_loads_) { + assert(process_timer_); + process_timer_->SetLength(kAudioProcessIntervalPendingLoad); + } else { + // If we're processing fades, run a bit higher-speed than usual + // for smoothness' sake. + if (!sound_fade_nodes_.empty()) { + assert(process_timer_); + process_timer_->SetLength(kAudioProcessIntervalFade); + } else { + // Nothing but normal activity; just run enough to keep + // buffers filled and whatnot. + assert(process_timer_); + process_timer_->SetLength(kAudioProcessIntervalNormal); + } + } +} + +void AudioServer::SetSoundPitch(float pitch) { + sound_pitch_ = pitch; + if (sound_pitch_ < 0.01f) sound_pitch_ = 0.01f; + for (auto&& i : sources_) { + i->UpdatePitch(); + } +} + +void AudioServer::SetSoundVolume(float volume) { + sound_volume_ = volume; + if (sound_volume_ > 3.0f) { + sound_volume_ = 3.0f; + } + if (sound_volume_ < 0) { + sound_volume_ = 0; + } + for (auto&& i : sources_) { + i->UpdateVolume(); + } +} + +void AudioServer::SetMusicVolume(float volume) { + music_volume_ = volume; + if (music_volume_ > 3.0f) music_volume_ = 3.0f; + if (music_volume_ < 0) music_volume_ = 0; + UpdateMusicPlayState(); + for (auto&& i : sources_) { + i->UpdateVolume(); + } +} + +// Start or stop music playback based on volume/pause-state/etc. +void AudioServer::UpdateMusicPlayState() { + bool should_be_playing = ((music_volume_ > 0.000001f) && !paused_); + + // Flip any playing music off. + if (!should_be_playing) { + for (auto&& i : sources_) { + if (i->current_is_music() && i->is_actually_playing()) { + i->ExecStop(); + } + } + } else { + // Flip music back on that should be playing. + for (auto&& i : sources_) { + if (i->current_is_music() && i->want_to_play() + && (!i->is_actually_playing())) { + i->ExecPlay(); + } + } + } +} + +void AudioServer::Process() { + millisecs_t real_time = GetRealTime(); + + assert(InAudioThread()); + + // If we're paused we don't do nothin'. + if (!paused_) { + // Do some loading... + have_pending_loads_ = g_media->RunPendingAudioLoads(); + + // Keep that available-sources list filled. + UpdateAvailableSources(); + + // Update our fading sound volumes. + if (real_time - last_sound_fade_process_time_ > 50) { + ProcessSoundFades(); + last_sound_fade_process_time_ = real_time; + } + + // Update streaming sources. + if (real_time - last_stream_process_time_ > 100) { + last_stream_process_time_ = real_time; + for (auto&& i : streaming_sources_) { + i->Update(); + } + } +#if BA_ENABLE_AUDIO + CHECK_AL_ERROR; +#endif + } + UpdateTimerInterval(); +} + +void AudioServer::Reset() { + // Stop all playing sounds. + for (auto&& i : sources_) { + i->Stop(); + } + SetSoundPitch(1.0f); +} + +void AudioServer::ProcessSoundFades() { + auto i = sound_fade_nodes_.begin(); + decltype(i) i_next; + while (i != sound_fade_nodes_.end()) { + i_next = i; + i_next++; + + AudioServer::ThreadSource* s = GetPlayingSound(i->second.play_id); + if (s) { + if (GetRealTime() > i->second.endtime) { + StopSound(i->second.play_id); + sound_fade_nodes_.erase(i); + } else { + float fade_val = + 1 + - (static_cast(GetRealTime() - i->second.starttime) + / static_cast(i->second.endtime - i->second.starttime)); + s->SetFade(fade_val); + } + } else { + sound_fade_nodes_.erase(i); + } + i = i_next; + } +} + +void AudioServer::FadeSoundOut(uint32_t play_id, uint32_t time) { + // Pop a new node on the list (this won't overwrite the old if there is one). + sound_fade_nodes_.insert( + std::make_pair(play_id, SoundFadeNode(play_id, time, true))); +} + +void AudioServer::DeleteMediaComponent(MediaComponentData* c) { + assert(InAudioThread()); + c->Unload(); + delete c; +} + +AudioServer::ThreadSource::ThreadSource(AudioServer* audio_thread_in, int id_in, + bool* valid_out) + : id_(id_in), audio_thread_(audio_thread_in) { +#if BA_ENABLE_AUDIO + assert(valid_out != nullptr); + CHECK_AL_ERROR; + + // Generate our sources. + alGenSources(1, &source_); + ALenum err = alGetError(); + valid_ = (err == AL_NO_ERROR); + if (!valid_) { + Log(std::string("Error: AL Error ") + GetALErrorString(err) + + " on source creation."); + } else { + // In vr mode we keep the microphone a bit closer to the camera + // for realism purposes, so we need stuff louder in general. + if (IsVRMode()) { + alSourcef(source_, AL_MAX_DISTANCE, 100); + alSourcef(source_, AL_REFERENCE_DISTANCE, 7.5f); + } else { + // In regular mode our mic is stuck closer to the action + // so less loudness is needed. + alSourcef(source_, AL_MAX_DISTANCE, 100); + alSourcef(source_, AL_REFERENCE_DISTANCE, 5.0f); + } + alSourcef(source_, AL_ROLLOFF_FACTOR, 0.3f); + CHECK_AL_ERROR; + } + *valid_out = valid_; + if (valid_) al_source_count_++; + +#endif // BA_ENABLE_AUDIO +} + +AudioServer::ThreadSource::~ThreadSource() { +#if BA_ENABLE_AUDIO + + if (!valid_) { + return; + } + Stop(); + + // Remove us from sources list. + for (auto i = audio_thread_->sources_.begin(); + i != audio_thread_->sources_.end(); ++i) { + if (*i == this) { + audio_thread_->sources_.erase(i); + break; + } + } + + assert(!is_actually_playing_ && !want_to_play_); + assert(!source_sound_); + + alDeleteSources(1, &source_); + CHECK_AL_ERROR; + al_source_count_--; + +#endif // BA_ENABLE_AUDIO +} + +auto AudioServer::ThreadSource::GetDefaultOwnerThread() const + -> ThreadIdentifier { + return ThreadIdentifier::kAudio; +} + +void AudioServer::ThreadSource::UpdateAvailability() { +#if BA_ENABLE_AUDIO + + assert(InAudioThread()); + + // If its waiting to be picked up by a client or has pending client commands, + // skip. + if (!client_source_->TryLock(6)) { + return; + } + + // Already available or has pending client commands; don't change anything. + if (client_source_->available() || client_source_->client_queue_size() > 0) { + client_source_->Unlock(); + return; + } + + // We consider ourselves busy if there's an active looping play command + // (regardless of its actual physical play state - music could be turned off, + // stuttering, etc). + // If its non-looping, we check its play state and snatch it if its not + // playing. + bool busy; + if (looping_ || (is_streamed_ && streamer_.exists() && streamer_->loops())) { + busy = want_to_play_; + } else { + // If our context is paused, we know nothing is playing + // (and we cant ask AL cuz we have no context). + if (g_audio_server->paused()) { + busy = false; + } else { + ALint state; + alGetSourcei(source_, AL_SOURCE_STATE, &state); + CHECK_AL_ERROR; + busy = (state == AL_PLAYING); + } + } + + // Ok, now if we can get a lock on the availability list, go ahead and + // make this guy available; give him a new play id and reset his state. + // If we can't get a lock its no biggie.. we'll come back to this guy later. + + if (!busy) { + if (g_audio->available_sources_mutex().try_lock()) { + std::lock_guard lock(g_audio->available_sources_mutex(), + std::adopt_lock); + Stop(); + Reset(); +#if BA_DEBUG_BUILD + uint32_t old_play_id = play_id(); +#endif + // Needs to always be a 16 bit value. + play_count_ = (play_count_ + 1) % 30000; + assert(old_play_id != play_id()); + client_source_->MakeAvailable(play_id()); + } + } + client_source_->Unlock(); + +#endif // BA_ENABLE_AUDIO +} + +void AudioServer::ThreadSource::Update() { +#if BA_ENABLE_AUDIO + assert(is_streamed_ && is_actually_playing_); + streamer_->Update(); +#endif +} + +void AudioServer::ThreadSource::SetIsMusic(bool m) { is_music_ = m; } + +void AudioServer::ThreadSource::SetGain(float g) { + gain_ = g; + UpdateVolume(); +} + +void AudioServer::ThreadSource::SetFade(float f) { + fade_ = f; + UpdateVolume(); +} + +void AudioServer::ThreadSource::SetLooping(bool loop) { + looping_ = loop; + if (!g_audio_server->paused()) { +#if BA_ENABLE_AUDIO + alSourcei(source_, AL_LOOPING, loop); + CHECK_AL_ERROR; +#endif + } +} + +void AudioServer::ThreadSource::SetPositional(bool p) { +#if BA_ENABLE_AUDIO + if (!g_audio_server->paused()) { + // TODO(ericf): Don't allow setting of positional + // on stereo sounds - we check this at initial play() + // but should do it here too. + alSourcei(source_, AL_SOURCE_RELATIVE, !p); + CHECK_AL_ERROR; + } +#endif +} + +void AudioServer::ThreadSource::SetPosition(float x, float y, float z) { +#if BA_ENABLE_AUDIO + if (!g_audio_server->paused()) { + bool oob = false; + if (x < -500) { + oob = true; + x = -500; + } else if (x > 500) { + oob = true; + x = 500; + } + if (y < -500) { + oob = true; + y = -500; + } else if (y > 500) { + oob = true; + y = 500; + } + if (z < -500) { + oob = true; + z = -500; + } else if (z > 500) { + oob = true; + z = 500; + } + if (oob) { + BA_LOG_ONCE( + "Error: AudioServer::ThreadSource::SetPosition" + " got out-of-bounds value."); + } + ALfloat source_pos[] = {x, y, z}; + alSourcefv(source_, AL_POSITION, source_pos); + CHECK_AL_ERROR; + } +#endif // BA_ENABLE_AUDIO +} + +// Actually begin playback. +void AudioServer::ThreadSource::ExecPlay() { +#if BA_ENABLE_AUDIO + + assert(source_sound_->exists()); + assert((**source_sound_).valid()); + assert((**source_sound_).loaded()); + assert(!is_actually_playing_); + CHECK_AL_ERROR; + + if (is_streamed_) { + // Turn off looping on the source - the streamer handles looping for us. + alSourcei(source_, AL_LOOPING, false); + CHECK_AL_ERROR; + looping_ = false; + + // Push us on the list of streaming sources if we're not on it. + for (auto&& i : audio_thread_->streaming_sources_) { + if (i == this) { + throw Exception(); + } + } + audio_thread_->streaming_sources_.push_back(this); + + // Make sure stereo sounds aren't positional. + // This is default behavior on Mac/Win but we enforce it for linux. + // (though currently linux stereo sounds play in mono... eww)) + + bool do_normal = true; + // In vr mode, play non-positional sounds positionally in space roughly + // where the menu is. + if (IsVRMode()) { + do_normal = false; + SetPositional(true); + SetPosition(0.0f, 4.5f, -3.0f); + } + + if (do_normal) { + SetPositional(false); + SetPosition(0, 0, 0); + } + + // Play if we're supposed to. + if (!streamer_->Play()) { + throw Exception(); + } + + } else { // Not streamed + // Make sure stereo sounds aren't positional. + // This is default behavior on Mac/Win but we enforce it for linux. + // (though currently linux stereo sounds play in mono... eww)) + if ((**source_sound_).format() == AL_FORMAT_STEREO16) { + SetPositional(false); + SetPosition(0, 0, 0); + } + alSourcePlay(source_); + CHECK_AL_ERROR; + } + is_actually_playing_ = true; + +#endif // BA_ENABLE_AUDIO +} + +auto AudioServer::ThreadSource::Play(const Object::Ref* sound) + -> uint32_t { +#if BA_ENABLE_AUDIO + + // FatalError("Testing other thread."); + + assert(InAudioThread()); + assert(sound->exists()); + + // Stop whatever we were doing. + Stop(); + + assert(source_sound_ == nullptr); + source_sound_ = sound; + + if (!g_audio_server->paused()) { + // Ok, here's where we might start needing to access our media.. can't hold + // off any longer.. + (**source_sound_).Load(); + + is_streamed_ = (**source_sound_).is_streamed(); + current_is_music_ = is_music_; + + if (is_streamed_) { + streamer_ = Object::New( + (**source_sound_).file_name_full().c_str(), source_, looping_); + } else { + alSourcei(source_, AL_BUFFER, (**source_sound_).buffer()); + } + CHECK_AL_ERROR; + + // Always update our volume and pitch here (we may be changing from music to + // nonMusic, etc) + UpdateVolume(); + UpdatePitch(); + + bool music_should_play = ((g_audio_server->music_volume_ > 0.000001f) + && !g_audio_server->paused()); + if ((!current_is_music_) || music_should_play) { + ExecPlay(); + } + } + want_to_play_ = true; + +#endif // BA_ENABLE_AUDIO + + return play_id(); +} + +void AudioServer::ThreadSource::ExecStop() { +#if BA_ENABLE_AUDIO + assert(InAudioThread()); + assert(!g_audio_server->paused()); + assert(is_actually_playing_); + if (streamer_.exists()) { + assert(is_streamed_); + streamer_->Stop(); + for (auto i = audio_thread_->streaming_sources_.begin(); + i != audio_thread_->streaming_sources_.end(); ++i) { + if (*i == this) { + audio_thread_->streaming_sources_.erase(i); + break; + } + } + } else { + alSourceStop(source_); + CHECK_AL_ERROR; + } + CHECK_AL_ERROR; + is_actually_playing_ = false; + +#endif // BA_ENABLE_AUDIO +} + +// Do a complete stop.. take us off the music list, detach our source, etc. +void AudioServer::ThreadSource::Stop() { +#if BA_ENABLE_AUDIO + assert(g_audio_server); + + // If our context is paused we can't actually stop now; just record our + // intent. + if (g_audio_server->paused()) { + want_to_play_ = false; + } else { + if (is_actually_playing_) ExecStop(); + if (streamer_.exists()) { + streamer_.Clear(); + } + // If we've got an attached sound, toss it back to the main thread + // to free up... + // (we can't kill media-refs outside of the main thread) + if (source_sound_) { + assert(g_media); + g_audio_server->AddSoundRefDelete(source_sound_); + source_sound_ = nullptr; + } + want_to_play_ = false; + } +#endif // BA_ENABLE_AUDIO +} + +void AudioServer::ThreadSource::UpdateVolume() { +#if BA_ENABLE_AUDIO + assert(InAudioThread()); + if (!g_audio_server->paused()) { + float val = gain_ * fade_; + if (current_is_music()) { + val *= audio_thread_->music_volume() / 7.0f; + } else { + val *= audio_thread_->sound_volume(); + } + alSourcef(source_, AL_GAIN, std::max(0.0f, val)); + CHECK_AL_ERROR; + } +#endif // BA_ENABLE_AUDIO +} + +void AudioServer::ThreadSource::UpdatePitch() { +#if BA_ENABLE_AUDIO + assert(InAudioThread()); + if (!g_audio_server->paused()) { + float val = 1.0f; + if (current_is_music()) { + } else { + val *= audio_thread_->sound_pitch(); + } + alSourcef(source_, AL_PITCH, val); + CHECK_AL_ERROR; + } +#endif // BA_ENABLE_AUDIO +} + +void AudioServer::PushSetVolumesCall(float music_volume, float sound_volume) { + PushCall([this, music_volume, sound_volume] { + SetSoundVolume(sound_volume); + SetMusicVolume(music_volume); + }); +} + +void AudioServer::PushSetSoundPitchCall(float val) { + PushCall([this, val] { SetSoundPitch(val); }); +} + +void AudioServer::PushSetPausedCall(bool pause) { + PushCall([this, pause] { + if (g_buildconfig.ostype_android()) { + Log("Error: Shouldn't be getting SetPausedCall on android."); + } + SetPaused(pause); + }); +} + +void AudioServer::PushComponentUnloadCall( + const std::vector*>& components) { + PushCall([this, components] { + // Unload all components we were passed.. + for (auto&& i : components) { + (**i).Unload(); + } + // ..and then ship these pointers back to the game thread so it can free the + // references + g_game->PushFreeMediaComponentRefsCall(components); + }); +} + +void AudioServer::PushHavePendingLoadsCall() { + PushCall([this] { + have_pending_loads_ = true; + UpdateTimerInterval(); + }); +} + +void AudioServer::AddSoundRefDelete(const Object::Ref* c) { + { + std::lock_guard lock(sound_ref_delete_list_mutex_); + sound_ref_delete_list_.push_back(c); + } + // Now push a call to the game thread to do the deletes. + g_game->PushCall([] { g_audio_server->ClearSoundRefDeleteList(); }); +} + +void AudioServer::ClearSoundRefDeleteList() { + assert(InGameThread()); + std::lock_guard lock(sound_ref_delete_list_mutex_); + for (const Object::Ref* i : sound_ref_delete_list_) { + delete i; + } + sound_ref_delete_list_.clear(); +} + +void AudioServer::BeginInterruption() { + assert(!InAudioThread()); + g_audio_server->PushSetPausedCall(true); + + // Wait a reasonable amount of time for the thread to act on it. + millisecs_t t = GetRealTime(); + while (true) { + if (g_audio_server->paused()) { + break; + } + if (GetRealTime() - t > 1000) { + Log("Error: Timed out waiting for audio pause."); + break; + } + Platform::SleepMS(2); + } +} + +void AudioServer::HandleThreadPause() { SetPaused(true); } + +void AudioServer::HandleThreadResume() { SetPaused(false); } + +void AudioServer::EndInterruption() { + assert(!InAudioThread()); + g_audio_server->PushSetPausedCall(false); + + // Wait a reasonable amount of time for the thread to act on it. + millisecs_t t = GetRealTime(); + while (true) { + if (!g_audio_server->paused()) { + break; + } + if (GetRealTime() - t > 1000) { + Log("Error: Timed out waiting for audio unpause."); + break; + } + Platform::SleepMS(2); + } +} + +} // namespace ballistica diff --git a/src/ballistica/audio/audio_server.h b/src/ballistica/audio/audio_server.h new file mode 100644 index 00000000..68f89598 --- /dev/null +++ b/src/ballistica/audio/audio_server.h @@ -0,0 +1,142 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_AUDIO_AUDIO_SERVER_H_ +#define BALLISTICA_AUDIO_AUDIO_SERVER_H_ + +#include +#include +#include + +#include "ballistica/core/module.h" + +namespace ballistica { + +/// A module that handles audio processing. +class AudioServer : public Module { + public: + static auto source_id_from_play_id(uint32_t play_id) -> uint32_t { + return play_id & 0xFFFFu; + } + + static auto play_count_from_play_id(uint32_t play_id) -> uint32_t { + return play_id >> 16u; + } + + explicit AudioServer(Thread* o); + + void PushSetVolumesCall(float music_volume, float sound_volume); + void PushSetSoundPitchCall(float val); + void PushSetPausedCall(bool pause); + + void HandleThreadPause() override; + void HandleThreadResume() override; + + static void BeginInterruption(); + static void EndInterruption(); + + void PushSetListenerPositionCall(const Vector3f& p); + void PushSetListenerOrientationCall(const Vector3f& forward, + const Vector3f& up); + void PushResetCall(); + void PushHavePendingLoadsCall(); + void PushComponentUnloadCall( + const std::vector*>& components); + + /// For use by g_game_module(). + void ClearSoundRefDeleteList(); + + auto paused() const -> bool { return paused_; } + + private: + class ThreadSource; + ~AudioServer() override; + + // Client sources use these to pass settings to the server. + void PushSourceSetIsMusicCall(uint32_t play_id, bool val); + void PushSourceSetPositionalCall(uint32_t play_id, bool val); + void PushSourceSetPositionCall(uint32_t play_id, const Vector3f& p); + void PushSourceSetGainCall(uint32_t play_id, float val); + void PushSourceSetFadeCall(uint32_t play_id, float val); + void PushSourceSetLoopingCall(uint32_t play_id, bool val); + void PushSourcePlayCall(uint32_t play_id, Object::Ref* sound); + void PushSourceStopCall(uint32_t play_id); + void PushSourceEndCall(uint32_t play_id); + + void SetPaused(bool paused); + + // Fade a playing sound out over the given time. If it is already + // fading or does not exist, does nothing. + void FadeSoundOut(uint32_t play_id, uint32_t time); + + // Stop a sound from playing if it exists. + void StopSound(uint32_t play_id); + void SetMusicVolume(float volume); + void SetSoundVolume(float volume); + void SetSoundPitch(float pitch); + auto music_volume() -> float { return music_volume_; } + auto sound_volume() -> float { return sound_volume_; } + auto sound_pitch() -> float { return sound_pitch_; } + + /// If a sound play id is currently playing, return the sound. + auto GetPlayingSound(uint32_t play_id) -> ThreadSource*; + + void Reset(); + void Process(); + + /// Send a component to the audio thread to delete. + void DeleteMediaComponent(MediaComponentData* c); + + void UpdateTimerInterval(); + void UpdateAvailableSources(); + void UpdateMusicPlayState(); + void ProcessSoundFades(); + + // Some threads such as audio hold onto allocated Media-Component-Refs to keep + // media components alive that they need. Media-Component-Refs, however, must + // be disposed of in the game thread, so they are passed back to it through + // this function. + void AddSoundRefDelete(const Object::Ref* c); + + Timer* process_timer_{}; + bool have_pending_loads_{}; + bool paused_{}; + millisecs_t last_sound_fade_process_time_{}; + +#if BA_ENABLE_AUDIO + ALCcontext* alc_context_; +#endif + + float sound_volume_{1.0f}; + float sound_pitch_{1.0f}; + float music_volume_{1.0f}; + + /// Indexed list of sources. + std::vector sources_; + std::vector streaming_sources_; + millisecs_t last_stream_process_time_{}; + + // Holds refs to all sources. + // Use sources, not this, for faster iterating. + std::vector > sound_source_refs_; + struct SoundFadeNode; + std::map sound_fade_nodes_; + + // This mutex controls access to our list of media component shared ptrs to + // delete in the main thread. + std::mutex sound_ref_delete_list_mutex_; + + // Our list of sound media components to delete via the main thread. + std::vector*> sound_ref_delete_list_; + + millisecs_t last_sanity_check_time_{}; + + static int al_source_count_; + + // FIXME: Try to kill these. + friend class AudioSource; + friend class Audio; +}; + +} // namespace ballistica + +#endif // BALLISTICA_AUDIO_AUDIO_SERVER_H_ diff --git a/src/ballistica/audio/audio_source.cc b/src/ballistica/audio/audio_source.cc new file mode 100644 index 00000000..fe2d1127 --- /dev/null +++ b/src/ballistica/audio/audio_source.cc @@ -0,0 +1,133 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/audio/audio_source.h" + +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_server.h" +#include "ballistica/math/vector3f.h" +#include "ballistica/media/data/sound_data.h" + +namespace ballistica { + +AudioSource::AudioSource(int id_in) : id_(id_in) {} + +AudioSource::~AudioSource() { assert(client_queue_size_ == 0); } + +void AudioSource::MakeAvailable(uint32_t play_id_new) { + assert(AudioServer::source_id_from_play_id(play_id_new) == id_); + assert(client_queue_size_ == 0); + assert(locked()); + play_id_ = play_id_new; + assert(!available_); + assert(g_audio); + g_audio->MakeSourceAvailable(this); + available_ = true; +} + +void AudioSource::SetIsMusic(bool val) { + assert(g_audio_server); + assert(client_queue_size_ > 0); + g_audio_server->PushSourceSetIsMusicCall(play_id_, val); +} + +void AudioSource::SetPositional(bool val) { + assert(g_audio_server); + assert(client_queue_size_ > 0); + g_audio_server->PushSourceSetPositionalCall(play_id_, val); +} + +void AudioSource::SetPosition(float x, float y, float z) { + assert(g_audio_server); + assert(client_queue_size_ > 0); +#if BA_DEBUG_BUILD + if (std::isnan(x) || std::isnan(y) || std::isnan(z)) { + Log("Error: Got nan value in AudioSource::SetPosition."); + } +#endif + g_audio_server->PushSourceSetPositionCall(play_id_, Vector3f(x, y, z)); +} + +void AudioSource::SetGain(float val) { + assert(g_audio_server); + assert(client_queue_size_ > 0); + g_audio_server->PushSourceSetGainCall(play_id_, val); +} + +void AudioSource::SetFade(float val) { + assert(g_audio_server); + assert(client_queue_size_ > 0); + g_audio_server->PushSourceSetFadeCall(play_id_, val); +} + +void AudioSource::SetLooping(bool val) { + assert(g_audio_server); + assert(client_queue_size_ > 0); + g_audio_server->PushSourceSetLoopingCall(play_id_, val); +} + +auto AudioSource::Play(SoundData* ptr_in) -> uint32_t { + assert(ptr_in); + assert(g_audio_server); + assert(client_queue_size_ > 0); + + // allocate a new reference to this guy and pass it along + // to the thread... (these refs can't be created or destroyed + // or have their ref-counts changed outside of the main thread...) + // the thread will then send back this allocated ptr when its done + // with it for the main thread to destroy. + + ptr_in->UpdatePlayTime(); + auto ptr = new Object::Ref(ptr_in); + g_audio_server->PushSourcePlayCall(play_id_, ptr); + return play_id_; +} + +void AudioSource::Stop() { + assert(g_audio_server); + assert(client_queue_size_ > 0); + g_audio_server->PushSourceStopCall(play_id_); +} + +void AudioSource::End() { + assert(client_queue_size_ > 0); + // send the thread a "this source is potentially free now" message + assert(g_audio_server); + g_audio_server->PushSourceEndCall(play_id_); + Unlock(); +} + +void AudioSource::Lock(int debug_id) { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + mutex_.lock(); +#if BA_DEBUG_BUILD + last_lock_time_ = GetRealTime(); + lock_debug_id_ = debug_id; + locked_ = true; +#endif + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); +} + +auto AudioSource::TryLock(int debug_id) -> bool { + bool locked = mutex_.try_lock(); +#if (BA_DEBUG_BUILD || BA_TEST_BUILD) + if (locked) { + locked_ = true; + last_lock_time_ = GetRealTime(); + lock_debug_id_ = debug_id; + } +#endif + return locked; +} + +void AudioSource::Unlock() { + BA_DEBUG_FUNCTION_TIMER_BEGIN(); + mutex_.unlock(); + BA_DEBUG_FUNCTION_TIMER_END_THREAD(20); +#if BA_DEBUG_BUILD || BA_TEST_BUILD + locked_ = false; +#endif +} + +} // namespace ballistica diff --git a/src/ballistica/audio/audio_source.h b/src/ballistica/audio/audio_source.h new file mode 100644 index 00000000..3663d77c --- /dev/null +++ b/src/ballistica/audio/audio_source.h @@ -0,0 +1,71 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_AUDIO_AUDIO_SOURCE_H_ +#define BALLISTICA_AUDIO_AUDIO_SOURCE_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Location for sound emission (client version) +class AudioSource { + public: + // Sets whether a source is "music". + // This mainly just influences which volume controls + // affect it. + void SetIsMusic(bool m); + + // Sets whether a source is positional. + // A non-positional source's position coords are always + // relative to the listener. ie: 0,0,0 will always be centered. + void SetPositional(bool p); + void SetPosition(float x, float y, float z); + void SetGain(float g); + void SetFade(float f); + void SetLooping(bool loop); + auto Play(SoundData* ptr) -> uint32_t; + void Stop(); + + // Always call this when done sending commands to the source. + void End(); + ~AudioSource(); + + // Lock the source. Sources must be locked whenever calling any public func. + void Lock(int debug_id); + + // Attempt to lock the source, but will not block. Returns true if + // successful. + auto TryLock(int debug_id) -> bool; + void Unlock(); + explicit AudioSource(int id); + auto id() const -> int { return id_; } +#if BA_DEBUG_BUILD || BA_TEST_BUILD + auto last_lock_time() const -> millisecs_t { return last_lock_time_; } + auto lock_debug_id() const -> int { return lock_debug_id_; } + auto locked() const -> bool { return locked_; } +#endif + auto available() const -> bool { return available_; } + void set_available(bool val) { available_ = val; } + void MakeAvailable(uint32_t play_id); + auto client_queue_size() const -> int { return client_queue_size_; } + void set_client_queue_size(int val) { client_queue_size_ = val; } + auto play_id() const -> uint32_t { return play_id_; } + + private: + std::mutex mutex_; +#if BA_DEBUG_BUILD || BA_TEST_BUILD + millisecs_t last_lock_time_ = 0; + int lock_debug_id_ = 0; + bool locked_ = false; +#endif + int client_queue_size_ = 0; + bool available_ = false; + int id_ = 0; + uint32_t play_id_ = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_AUDIO_AUDIO_SOURCE_H_ diff --git a/src/ballistica/audio/audio_streamer.cc b/src/ballistica/audio/audio_streamer.cc new file mode 100644 index 00000000..4711e171 --- /dev/null +++ b/src/ballistica/audio/audio_streamer.cc @@ -0,0 +1,145 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/audio/audio_streamer.h" + +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_server.h" + +// Need to move away from OpenAL on Apple stuff. +#if __clang__ +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + +namespace ballistica { + +#if BA_ENABLE_AUDIO +AudioStreamer::AudioStreamer(const char* file_name, ALuint source_in, bool loop) + : source_(source_in), file_name_(file_name), loops_(loop) { + assert(InAudioThread()); + alGenBuffers(kAudioStreamBufferCount, buffers_); + CHECK_AL_ERROR; +} + +AudioStreamer::~AudioStreamer() { + assert(!playing_); + assert(g_audio_server); + + alDeleteBuffers(kAudioStreamBufferCount, buffers_); + CHECK_AL_ERROR; +} + +auto AudioStreamer::Play() -> bool { + CHECK_AL_ERROR; + assert(!playing_); + playing_ = true; + + // In case the source is already attached to something. + DetachBuffers(); + + // Fill all our buffers with data. + for (unsigned int buffer : buffers_) { + if (!Stream(buffer)) { + return false; + } + } + + alSourceQueueBuffers(source_, kAudioStreamBufferCount, buffers_); + CHECK_AL_ERROR; + + alSourcePlay(source_); + CHECK_AL_ERROR; + + return true; +} + +void AudioStreamer::Stop() { + CHECK_AL_ERROR; + assert(playing_); + alSourceStop(source_); + CHECK_AL_ERROR; + playing_ = false; + DetachBuffers(); + DoStop(); +} + +void AudioStreamer::Update() { + if (eof_) return; + + CHECK_AL_ERROR; + + assert(playing_); + + ALint queued; + ALint processed; + + // See how many buffers have been processed. + alGetSourcei(source_, AL_BUFFERS_QUEUED, &queued); + CHECK_AL_ERROR; + alGetSourcei(source_, AL_BUFFERS_PROCESSED, &processed); + CHECK_AL_ERROR; + + // A fun anomaly in the linux version; we sometimes get more + // "processed" buffers than we have queued. + if (queued < processed) { + Log("Error: streamer oddness: queued(" + std::to_string(queued) + + "); processed(" + std::to_string(processed) + ")"); + processed = queued; + } + + // Pull the completed ones off, refill them, and queue them back up. + while (processed--) { + ALuint buffer; + alSourceUnqueueBuffers(source_, 1, &buffer); + CHECK_AL_ERROR; + Stream(buffer); + if (!eof_) { + alSourceQueueBuffers(source_, 1, &buffer); + CHECK_AL_ERROR; + } + } + + // Restart playback if need be. + ALenum state; + alGetSourcei(source_, AL_SOURCE_STATE, &state); + CHECK_AL_ERROR; + + if (state != AL_PLAYING) { + printf("AudioServer::Streamer: restarting playback\n"); + fflush(stdout); + + alSourcePlay(source_); + CHECK_AL_ERROR; + } +} + +void AudioStreamer::DetachBuffers() { +#if BA_DEBUG_BUILD + ALint state; + alGetSourcei(source_, AL_SOURCE_STATE, &state); + CHECK_AL_ERROR; + assert(state == AL_INITIAL || state == AL_STOPPED); +#endif + + // This should clear everything. + alSourcei(source_, AL_BUFFER, 0); + CHECK_AL_ERROR; +} + +auto AudioStreamer::Stream(ALuint buffer) -> bool { + char pcm[kAudioStreamBufferSize]; + int size = 0; + unsigned int rate; + CHECK_AL_ERROR; + DoStream(pcm, &size, &rate); + if (size > 0) { + alBufferData(buffer, al_format(), pcm, size, rate); + CHECK_AL_ERROR; + } else { + eof_ = true; + } + return true; +} + +#endif // BA_ENABLE_AUDIO + +} // namespace ballistica diff --git a/src/ballistica/audio/audio_streamer.h b/src/ballistica/audio/audio_streamer.h new file mode 100644 index 00000000..82ce85f0 --- /dev/null +++ b/src/ballistica/audio/audio_streamer.h @@ -0,0 +1,62 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_AUDIO_AUDIO_STREAMER_H_ +#define BALLISTICA_AUDIO_AUDIO_STREAMER_H_ + +#include +#include + +#include "ballistica/audio/al_sys.h" // FIXME: shouldn't need this here. +#include "ballistica/core/object.h" + +namespace ballistica { + +#if BA_ENABLE_AUDIO +// Provider for streamed audio data. +class AudioStreamer : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kAudio; + } + AudioStreamer(const char* file_name, ALuint source, bool loop); + ~AudioStreamer() override; + auto Play() -> bool; + void Stop(); + void Update(); + enum Format { INVALID_FORMAT, MONO16_FORMAT, STEREO16_FORMAT }; + auto al_format() const -> ALenum { + switch (format_) { + case MONO16_FORMAT: + return AL_FORMAT_MONO16; + case STEREO16_FORMAT: + return AL_FORMAT_STEREO16; + default: + break; + } + return INVALID_FORMAT; + } + auto loops() const -> bool { return loops_; } + auto file_name() const -> const std::string& { return file_name_; } + + protected: + virtual void DoStop() = 0; + virtual void DoStream(char* pcm, int* size, unsigned int* rate) = 0; + auto Stream(ALuint buffer) -> bool; + void DetachBuffers(); + void set_format(Format format) { format_ = format; } + + private: + Format format_ = INVALID_FORMAT; + bool playing_ = false; + ALuint buffers_[kAudioStreamBufferCount]{}; + ALuint source_ = 0; + std::string file_name_; + bool loops_ = false; + bool eof_ = false; +}; + +#endif // BA_ENABLE_AUDIO + +} // namespace ballistica + +#endif // BALLISTICA_AUDIO_AUDIO_STREAMER_H_ diff --git a/src/ballistica/audio/ogg_stream.cc b/src/ballistica/audio/ogg_stream.cc new file mode 100644 index 00000000..185a29a8 --- /dev/null +++ b/src/ballistica/audio/ogg_stream.cc @@ -0,0 +1,136 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/audio/ogg_stream.h" + +#include + +#include "ballistica/platform/platform.h" + +namespace ballistica { + +#if BA_ENABLE_AUDIO + +static auto CallbackRead(void* ptr, size_t size, size_t nmemb, + void* data_source) -> size_t { + return fread(ptr, size, nmemb, static_cast(data_source)); +} + +static auto CallbackSeek(void* data_source, ogg_int64_t offset, int whence) + -> int { + return fseek(static_cast(data_source), + static_cast_check_fit(offset), whence); // NOLINT +} +static auto CallbackClose(void* data_source) -> int { + return fclose(static_cast(data_source)); +} +static long CallbackTell(void* data_source) { // NOLINT (ogg wants long) + return ftell(static_cast(data_source)); +} + +OggStream::OggStream(const char* file_name, ALuint source, bool loop) + : AudioStreamer(file_name, source, loop), have_ogg_file_(false) { + int result; + FILE* f; + if (!(f = g_platform->FOpen(file_name, "rb"))) { + throw Exception("can't open ogg file: '" + std::string(file_name) + "'"); + } + ov_callbacks callbacks; + callbacks.read_func = CallbackRead; + callbacks.seek_func = CallbackSeek; + callbacks.close_func = CallbackClose; + callbacks.tell_func = CallbackTell; + + // Have to use callbacks here as codewarrior's FILE struct doesn't + // seem to agree with what vorbis expects... oh well. + // Ericf note Aug 2019: Wow I have comments here old enough to be referencing + // codewarrior; that's awesome! + result = ov_open_callbacks(f, &ogg_file_, nullptr, 0, callbacks); + if (result < 0) { + fclose(f); + throw Exception(GetErrorString(result)); + } + have_ogg_file_ = true; + + vorbis_info_ = ov_info(&ogg_file_, -1); + if (vorbis_info_->channels == 1) { + set_format(MONO16_FORMAT); + } else { + set_format(STEREO16_FORMAT); + } +} + +OggStream::~OggStream() { + if (have_ogg_file_) { + ov_clear(&ogg_file_); + } +} + +void OggStream::DoStop() { + if (have_ogg_file_) ov_pcm_seek(&ogg_file_, 0); +} + +void OggStream::DoStream(char* pcm, int* size, unsigned int* rate) { + int section; + int result; + while ((*size) < kAudioStreamBufferSize) { + // tremor's ov_read takes fewer args +#if (BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID) + result = static_cast(ov_read( + &ogg_file_, pcm + (*size), kAudioStreamBufferSize - (*size), §ion)); +#else + result = static_cast(ov_read(&ogg_file_, pcm + (*size), + kAudioStreamBufferSize - (*size), 0, 2, 1, + §ion)); +#endif // BA_OSTYPE_IOS_TVOS + + if (result > 0) { + (*size) += result; + } else { + if (result < 0) { + static bool reported_error = false; + if (!reported_error) { + reported_error = true; + Log("Error streaming ogg file: '" + file_name() + "'."); + } + if (loops()) { + ov_pcm_seek(&ogg_file_, 0); + } else { + return; + } + } else { + // we hit the end of the file; either reset and keep reading if we're + // looping or just return what we got + if (loops()) { + ov_pcm_seek(&ogg_file_, 0); + } else { + return; + } + } + } + } + if ((*size) == 0 && loops()) { + throw Exception(); + } + (*rate) = static_cast(vorbis_info_->rate); +} + +auto OggStream::GetErrorString(int code) -> std::string { + switch (code) { + case OV_EREAD: + return std::string("Read from media."); + case OV_ENOTVORBIS: + return std::string("Not Vorbis data."); + case OV_EVERSION: + return std::string("Vorbis version mismatch."); + case OV_EBADHEADER: + return std::string("Invalid Vorbis header."); + case OV_EFAULT: + return std::string("Internal logic fault (bug or heap/stack corruption."); + default: + return std::string("Unknown Ogg error."); + } +} + +#endif // BA_ENABLE_AUDIO + +} // namespace ballistica diff --git a/src/ballistica/audio/ogg_stream.h b/src/ballistica/audio/ogg_stream.h new file mode 100644 index 00000000..caec2b39 --- /dev/null +++ b/src/ballistica/audio/ogg_stream.h @@ -0,0 +1,43 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_AUDIO_OGG_STREAM_H_ +#define BALLISTICA_AUDIO_OGG_STREAM_H_ + +#include "ballistica/audio/audio_streamer.h" + +#if BA_ENABLE_AUDIO +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID +#include "ivorbisfile.h" // NOLINT +#else +#include +#endif // BA_OSTYPE_IOS_TVOS +#endif // BA_ENABLE_AUDIO + +#include + +namespace ballistica { + +#if BA_ENABLE_AUDIO + +// Handles streaming ogg audio. +class OggStream : public AudioStreamer { + public: + OggStream(const char* file_name, ALuint source, bool loop); + ~OggStream() override; + + protected: + void DoStop() override; + void DoStream(char* pcm, int* size, unsigned int* rate) override; + + private: + auto GetErrorString(int code) -> std::string; + OggVorbis_File ogg_file_{}; + bool have_ogg_file_; + vorbis_info* vorbis_info_; +}; + +#endif // BA_ENABLE_AUDIO + +} // namespace ballistica + +#endif // BALLISTICA_AUDIO_OGG_STREAM_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics.cc b/src/ballistica/dynamics/bg/bg_dynamics.cc new file mode 100644 index 00000000..ade14fdf --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics.cc @@ -0,0 +1,376 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/bg/bg_dynamics.h" + +#include +#include + +#include "ballistica/core/thread.h" +#include "ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h" +#include "ballistica/dynamics/bg/bg_dynamics_fuse_data.h" +#include "ballistica/dynamics/bg/bg_dynamics_shadow_data.h" +#include "ballistica/dynamics/bg/bg_dynamics_volume_light_data.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/smoke_component.h" +#include "ballistica/graphics/component/sprite_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/media/component/collide_model.h" + +namespace ballistica { + +void BGDynamics::Init() { + // Just init our singleton. + new BGDynamics(); +} + +BGDynamics::BGDynamics() { + assert(InGameThread()); + assert(g_bg_dynamics == nullptr); + g_bg_dynamics = this; +} + +void BGDynamics::AddTerrain(CollideModelData* o) { + assert(InGameThread()); + + // Allocate a fresh reference to keep this collide-model alive as long as + // we're using it. Once we're done, we'll pass the pointer back to the + // main thread to free. + auto* model_ref = new Object::Ref(o); + g_bg_dynamics_server->PushAddTerrainCall(model_ref); +} + +void BGDynamics::RemoveTerrain(CollideModelData* o) { + assert(InGameThread()); + g_bg_dynamics_server->PushRemoveTerrainCall(o); +} + +void BGDynamics::Emit(const BGDynamicsEmission& e) { + assert(InGameThread()); + g_bg_dynamics_server->PushEmitCall(e); +} + +// Call friend client to step our sim. +void BGDynamics::Step(const Vector3f& cam_pos) { + assert(InGameThread()); + + // The BG dynamics thread just processes steps as fast as it can; + // we need to throttle what we send or tell it to cut back if its behind + int step_count = g_bg_dynamics_server->step_count(); + + // If we're really getting behind, start pruning stuff. + if (step_count > 3) { + TooSlow(); + } + + // If we're slightly behind, just don't send this step; + // the bg dynamics will slow down a bit but nothing will disappear this way. + if (step_count > 1) return; + + // Pass a newly allocated raw pointer to the bg-dynamics thread; it takes care + // of disposing it when done. + auto d = Object::NewDeferred(); + d->cam_pos = cam_pos; + + { // Shadows. + BA_DEBUG_TIME_CHECK_BEGIN(bg_dynamic_shadow_list_lock); + { + std::lock_guard lock( + g_bg_dynamics_server->shadow_list_mutex_); + auto size = g_bg_dynamics_server->shadows_.size(); + d->shadow_step_data_.resize(size); + if (size > 0) { + BGDynamicsShadowData** sd_client = &(g_bg_dynamics_server->shadows_[0]); + std::pair* sd = + &(d->shadow_step_data_[0]); + for (size_t i = 0; i < size; i++) { + // Set to nullptr (for ignore) if the client side is dead. + sd[i].first = sd_client[i]->client_dead ? nullptr : sd_client[i]; + sd[i].second.position = sd_client[i]->pos_client; + } + } + } + BA_DEBUG_TIME_CHECK_END(bg_dynamic_shadow_list_lock, 10); + } + { // Volume lights. + BA_DEBUG_TIME_CHECK_BEGIN(bg_dynamic_volumelights_list_lock); + { + std::lock_guard lock( + g_bg_dynamics_server->volume_light_list_mutex_); + auto size = g_bg_dynamics_server->volume_lights_.size(); + d->volume_light_step_data_.resize(size); + if (size > 0) { + BGDynamicsVolumeLightData** vd_client = + &(g_bg_dynamics_server->volume_lights_[0]); + std::pair* vd = + &(d->volume_light_step_data_[0]); + for (size_t i = 0; i < size; i++) { + // Set to nullptr (for ignore) if the client side is dead. + vd[i].first = vd_client[i]->client_dead ? nullptr : vd_client[i]; + vd[i].second.pos = vd_client[i]->pos_client; + vd[i].second.radius = vd_client[i]->radius_client; + vd[i].second.r = vd_client[i]->r_client; + vd[i].second.g = vd_client[i]->g_client; + vd[i].second.b = vd_client[i]->b_client; + } + } + } + BA_DEBUG_TIME_CHECK_END(bg_dynamic_volumelights_list_lock, 10); + } + { // Fuses. + BA_DEBUG_TIME_CHECK_BEGIN(bg_dynamic_fuse_list_lock); + { + std::lock_guard lock(g_bg_dynamics_server->fuse_list_mutex_); + auto size = g_bg_dynamics_server->fuses_.size(); + d->fuse_step_data_.resize(size); + if (size > 0) { + BGDynamicsFuseData** fd_client = &(g_bg_dynamics_server->fuses_[0]); + std::pair* fd = + &(d->fuse_step_data_[0]); + for (size_t i = 0; i < size; i++) { + // Set to nullptr (for ignore) if the client side is dead. + fd[i].first = fd_client[i]->client_dead_ ? nullptr : fd_client[i]; + fd[i].second.transform = fd_client[i]->transform_client_; + fd[i].second.have_transform = fd_client[i]->have_transform_client_; + fd[i].second.length = fd_client[i]->length_client_; + } + } + } + BA_DEBUG_TIME_CHECK_END(bg_dynamic_fuse_list_lock, 10); + } + + // Increase our step count and ship it. + { + std::lock_guard lock(g_bg_dynamics_server->step_count_mutex_); + g_bg_dynamics_server->step_count_++; + } + + // Ok send the thread on its way. + g_bg_dynamics_server->PushStepCall(d); +} + +void BGDynamics::SetDrawSnapshot(BGDynamicsDrawSnapshot* s) { + // We were passed a raw pointer; assign it to our unique_ptr which will + // take ownership of it and handle disposing it when we get the next one. + draw_snapshot_ = std::unique_ptr(s); +} + +void BGDynamics::TooSlow() { + if (!Thread::AreThreadsPaused()) { + g_bg_dynamics_server->PushTooSlowCall(); + } +} + +void BGDynamics::SetDebrisFriction(float val) { + assert(InGameThread()); + g_bg_dynamics_server->PushSetDebrisFrictionCall(val); +} + +void BGDynamics::SetDebrisKillHeight(float val) { + assert(InGameThread()); + g_bg_dynamics_server->PushSetDebrisKillHeightCall(val); +} + +void BGDynamics::Draw(FrameDef* frame_def) { + assert(InGameThread()); + + BGDynamicsDrawSnapshot* ds{draw_snapshot_.get()}; + if (!ds) { + return; + } + + // Draw sparks. + if (ds->spark_vertices.exists()) { + if (!sparks_mesh_.exists()) sparks_mesh_ = Object::New(); + sparks_mesh_->SetIndexData(ds->spark_indices); + sparks_mesh_->SetData( + Object::Ref>(ds->spark_vertices)); + + // In high-quality we draw in the overlay pass so we don't get wiped + // out by depth-of-field. + bool draw_in_overlay = (frame_def->quality() >= GraphicsQuality::kHigh); + SpriteComponent c(draw_in_overlay ? frame_def->overlay_3d_pass() + : frame_def->beauty_pass()); + c.SetCameraAligned(true); + c.SetColor(2.0f, 2.0f, 2.0f, 1.0f); + c.SetOverlay(draw_in_overlay); + c.SetTexture(g_media->GetTexture(SystemTextureID::kSparks)); + c.DrawMesh(sparks_mesh_.get(), kModelDrawFlagNoReflection); + c.Submit(); + } + + // Draw lights. + if (ds->light_vertices.exists()) { + assert(ds->light_indices.exists()); + assert(!ds->light_indices->elements.empty()); + assert(!ds->light_vertices->elements.empty()); + if (!lights_mesh_.exists()) lights_mesh_ = Object::New(); + lights_mesh_->SetIndexData(ds->light_indices); + lights_mesh_->SetData( + Object::Ref>(ds->light_vertices)); + SpriteComponent c(frame_def->light_shadow_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kLightSoft)); + c.DrawMesh(lights_mesh_.get()); + c.Submit(); + } + + // Draw shadows. + if (ds->shadow_vertices.exists()) { + assert(ds->shadow_indices.exists()); + if (!shadows_mesh_.exists()) shadows_mesh_ = Object::New(); + shadows_mesh_->SetIndexData(ds->shadow_indices); + shadows_mesh_->SetData( + Object::Ref>(ds->shadow_vertices)); + SpriteComponent c(frame_def->light_shadow_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kLight)); + c.DrawMesh(shadows_mesh_.get()); + c.Submit(); + } + + // Draw chunks. + DrawChunks(frame_def, &ds->rocks, BGDynamicsChunkType::kRock); + DrawChunks(frame_def, &ds->ice, BGDynamicsChunkType::kIce); + DrawChunks(frame_def, &ds->slime, BGDynamicsChunkType::kSlime); + DrawChunks(frame_def, &ds->metal, BGDynamicsChunkType::kMetal); + DrawChunks(frame_def, &ds->sparks, BGDynamicsChunkType::kSpark); + DrawChunks(frame_def, &ds->splinters, BGDynamicsChunkType::kSplinter); + DrawChunks(frame_def, &ds->sweats, BGDynamicsChunkType::kSweat); + DrawChunks(frame_def, &ds->flag_stands, BGDynamicsChunkType::kFlagStand); + + // Draw tendrils. + if (ds->tendril_vertices.exists()) { + if (!tendrils_mesh_.exists()) + tendrils_mesh_ = Object::New(); + tendrils_mesh_->SetIndexData(ds->tendril_indices); + tendrils_mesh_->SetData( + Object::Ref>(ds->tendril_vertices)); + bool draw_in_overlay = (frame_def->quality() >= GraphicsQuality::kHigh); + SmokeComponent c(draw_in_overlay ? frame_def->overlay_3d_pass() + : frame_def->beauty_pass()); + c.SetOverlay(draw_in_overlay); + c.SetColor(1.0f, 1.0f, 1.0f, 1.0f); + c.DrawMesh(tendrils_mesh_.get(), kModelDrawFlagNoReflection); + c.Submit(); + + // Shadows. + if (frame_def->quality() >= GraphicsQuality::kHigher) { + for (auto&& i : ds->tendril_shadows) { + if (i.density > 0.0001f) { + Vector3f& p(i.p); + g_graphics->DrawBlotch(p, 2.0f * i.density, 0.02f * i.density, + 0.01f * i.density, 0, 0.15f * i.density); + } + } + } + } + + // Draw fuses. + if (ds->fuse_vertices.exists()) { + // Update our mesh with this data. + if (!fuses_mesh_.exists()) + fuses_mesh_ = Object::New(); + fuses_mesh_->SetIndexData(ds->fuse_indices); + fuses_mesh_->SetData( + Object::Ref>(ds->fuse_vertices)); + { // Draw! + ObjectComponent c(frame_def->beauty_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kFuse)); + c.DrawMesh(fuses_mesh_.get(), kModelDrawFlagNoReflection); + c.Submit(); + } + } +} + +void BGDynamics::DrawChunks(FrameDef* frame_def, + std::vector* draw_snapshot, + BGDynamicsChunkType chunk_type) { + if (!draw_snapshot || draw_snapshot->empty()) { + return; + } + + // Draw ourself into the beauty pass. + ModelData* model; + switch (chunk_type) { + case BGDynamicsChunkType::kFlagStand: + model = g_media->GetModel(SystemModelID::kFlagStand); + break; + case BGDynamicsChunkType::kSplinter: + model = g_media->GetModel(SystemModelID::kShrapnelBoard); + break; + case BGDynamicsChunkType::kSlime: + model = g_media->GetModel(SystemModelID::kShrapnelSlime); + break; + default: + model = g_media->GetModel(SystemModelID::kShrapnel1); + break; + } + ObjectComponent c(frame_def->beauty_pass()); + + // Set up shading. + switch (chunk_type) { + case BGDynamicsChunkType::kRock: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.2f, 0.2f, 0.2f); + c.SetColor(0.6f, 0.6f, 0.5f); + break; + } + case BGDynamicsChunkType::kIce: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kSharp); + c.SetAddColor(0.5f, 0.5f, 0.9f); + break; + } + case BGDynamicsChunkType::kSlime: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kSharper); + c.SetReflectionScale(3.0f, 3.0f, 3.0f); + c.SetColor(0.0f, 0.0f, 0.0f); + c.SetAddColor(0.6f, 0.7f, 0.08f); + break; + } + case BGDynamicsChunkType::kMetal: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kPowerup); + c.SetColor(0.5f, 0.5f, 0.55f); + break; + } + case BGDynamicsChunkType::kSpark: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kSharp); + c.SetColor(0.0f, 0.0f, 0.0f, 1.0f); + c.SetReflectionScale(4.0f, 3.0f, 2.0f); + c.SetAddColor(3.0f, 0.8f, 0.6f); + break; + } + case BGDynamicsChunkType::kSplinter: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kSoft); + c.SetColor(1.0f, 0.8f, 0.5f); + break; + } + case BGDynamicsChunkType::kSweat: { + c.SetTransparent(true); + c.SetPremultiplied(true); + c.SetLightShadow(LightShadowType::kNone); + c.SetTexture(g_media->GetTexture(SystemTextureID::kShrapnel1)); + c.SetReflection(ReflectionType::kSharp); + c.SetReflectionScale(0.5f, 0.4f, 0.3f); + c.SetColor(0.2f, 0.15f, 0.15f, 0.07f); + c.SetAddColor(0.05f, 0.05f, 0.01f); + break; + } + case BGDynamicsChunkType::kFlagStand: { + c.SetTexture(g_media->GetTexture(SystemTextureID::kFlagPole)); + c.SetReflection(ReflectionType::kSharp); + c.SetColor(0.9f, 0.6f, 0.3f, 1.0f); + break; + } + default: + throw Exception(); + } + c.DrawModelInstanced(model, *draw_snapshot, kModelDrawFlagNoReflection); + c.Submit(); +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/bg/bg_dynamics.h b/src/ballistica/dynamics/bg/bg_dynamics.h new file mode 100644 index 00000000..42fe1a15 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics.h @@ -0,0 +1,84 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_H_ + +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/math/vector3f.h" + +namespace ballistica { + +enum class BGDynamicsEmitType { + kChunks, + kStickers, + kTendrils, + kDistortion, + kFlagStand, + kFairyDust +}; + +enum class BGDynamicsTendrilType { kSmoke, kThinSmoke, kIce }; + +enum class BGDynamicsChunkType { + kRock, + kIce, + kSlime, + kMetal, + kSpark, + kSplinter, + kSweat, + kFlagStand +}; + +class BGDynamicsEmission { + public: + BGDynamicsEmitType emit_type = BGDynamicsEmitType::kChunks; + Vector3f position{0.0f, 0.0f, 0.0f}; + Vector3f velocity{0.0f, 0.0f, 0.0f}; + int count{0}; + float scale{1.0f}; + float spread{1.0f}; + BGDynamicsChunkType chunk_type{BGDynamicsChunkType::kRock}; + BGDynamicsTendrilType tendril_type{BGDynamicsTendrilType::kSmoke}; +}; + +// client (game thread) functionality for bg dynamics +class BGDynamics { + public: + static void Init(); + + void Emit(const BGDynamicsEmission& def); + void Step(const Vector3f& cam_pos); + + // can be called to inform the bg dynamics thread to kill off some + // smoke/chunks/etc if rendering is chugging or whatnot. + void TooSlow(); + + // Draws the last snapshot the bg-dynamics-server has delivered to us + void Draw(FrameDef* frame_def); + void SetDebrisFriction(float val); + void SetDebrisKillHeight(float val); + void AddTerrain(CollideModelData* o); + void RemoveTerrain(CollideModelData* o); + + // (sent to us by the bg dynamics server) + void SetDrawSnapshot(BGDynamicsDrawSnapshot* s); + + private: + BGDynamics(); + void DrawChunks(FrameDef* frame_def, std::vector* instances, + BGDynamicsChunkType chunk_type); + Object::Ref lights_mesh_; + Object::Ref shadows_mesh_; + Object::Ref sparks_mesh_; + Object::Ref tendrils_mesh_; + Object::Ref fuses_mesh_; + std::unique_ptr draw_snapshot_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h b/src/ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h new file mode 100644 index 00000000..0fceae6c --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h @@ -0,0 +1,79 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_DRAW_SNAPSHOT_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_DRAW_SNAPSHOT_H_ + +#include + +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +// Big chunk of data sent back from the bg-dynamics server thread +// to the game thread for drawing. +class BGDynamicsDrawSnapshot { + public: + struct TendrilShadow { + TendrilShadow(const Vector3f& p_in, float density_in) + : p(p_in), density(density_in) {} + Vector3f p; + float density; + }; + + // These are created in the bg-dynamics thread, and object ownership + // needs to be switched back the the game-thread default when it is passed + // over or else the debug thread-access-checks will error. + void SetGameThreadOwnership() { + if (g_buildconfig.debug_build()) { + for (Object* o : {static_cast(tendril_indices.get()), + static_cast(tendril_vertices.get()), + static_cast(fuse_indices.get()), + static_cast(fuse_vertices.get()), + static_cast(shadow_indices.get()), + static_cast(shadow_vertices.get()), + static_cast(light_indices.get()), + static_cast(light_vertices.get()), + static_cast(spark_indices.get()), + static_cast(spark_vertices.get())}) { + if (o) { + o->SetThreadOwnership(Object::ThreadOwnership::kClassDefault); + } + } + } + } + + // Particles. + std::vector rocks; + std::vector ice; + std::vector slime; + std::vector metal; + std::vector sparks; + std::vector splinters; + std::vector sweats; + std::vector flag_stands; + + // Tendrils. + Object::Ref tendril_indices; + Object::Ref tendril_vertices; + std::vector tendril_shadows; + + // Fuses. + Object::Ref fuse_indices; + Object::Ref fuse_vertices; + + // Shadows. + Object::Ref shadow_indices; + Object::Ref shadow_vertices; + + // Lights. + Object::Ref light_indices; + Object::Ref light_vertices; + + // Sparks. + Object::Ref spark_indices; + Object::Ref spark_vertices; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_DRAW_SNAPSHOT_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_fuse.cc b/src/ballistica/dynamics/bg/bg_dynamics_fuse.cc new file mode 100644 index 00000000..98689380 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_fuse.cc @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/bg/bg_dynamics_fuse.h" + +#include "ballistica/dynamics/bg/bg_dynamics_fuse_data.h" + +namespace ballistica { + +BGDynamicsFuse::BGDynamicsFuse() { + assert(g_bg_dynamics_server); + assert(InGameThread()); + + // Allocate our data. We'll pass this to the BGDynamics thread and + // it'll then own it. + data_ = new BGDynamicsFuseData(); + g_bg_dynamics_server->PushAddFuseCall(data_); +} + +BGDynamicsFuse::~BGDynamicsFuse() { + assert(g_bg_dynamics_server); + assert(InGameThread()); + + // Let the data know the client side is dead + // so we're no longer included in step messages. + // (since by the time the worker gets the the data will be gone). + data_->client_dead_ = true; + g_bg_dynamics_server->PushRemoveFuseCall(data_); +} + +void BGDynamicsFuse::SetTransform(const Matrix44f& t) { + assert(InGameThread()); + data_->transform_client_ = t; + data_->have_transform_client_ = true; +} + +void BGDynamicsFuse::SetLength(float length) { + assert(InGameThread()); + data_->length_client_ = length; +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/bg/bg_dynamics_fuse.h b/src/ballistica/dynamics/bg/bg_dynamics_fuse.h new file mode 100644 index 00000000..b0e8c9e6 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_fuse.h @@ -0,0 +1,24 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_FUSE_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_FUSE_H_ + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// Client controlled fuse. +class BGDynamicsFuse { + public: + BGDynamicsFuse(); + ~BGDynamicsFuse(); + void SetTransform(const Matrix44f& m); + void SetLength(float l); + + private: + BGDynamicsFuseData* data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_FUSE_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_fuse_data.h b/src/ballistica/dynamics/bg/bg_dynamics_fuse_data.h new file mode 100644 index 00000000..5ffe4122 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_fuse_data.h @@ -0,0 +1,113 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_FUSE_DATA_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_FUSE_DATA_H_ + +#include + +#include "ballistica/dynamics/bg/bg_dynamics_server.h" + +namespace ballistica { + +const int kFusePointCount = 4; + +struct BGDynamicsFuseData { + void Synchronize() { + transform_worker_ = transform_client_; + have_transform_worker_ = have_transform_client_; + length_worker_ = length_client_; + } + + void Update(BGDynamicsServer* dyn) { + // Do nothing if we havn't received an initial transform. + if (!have_transform_worker_) { + return; + } + seg_len_ = 0.2f * std::max(0.01f, length_worker_); + + if (!initial_position_set_) { + // Snap all our stuff into place on the initial transform. + Vector3f pt = transform_worker_.GetTranslate(); + target_pts_[0] = dyn_pts_[0] = pt; + auto up = Vector3f(&transform_worker_.m[4]); + for (int i = 1; i < kFusePointCount; i++) { + target_pts_[i] = target_pts_[i - 1] + up * seg_len_; + dyn_pts_[i] = target_pts_[i]; + up = (target_pts_[i] - target_pts_[i - 1]).Normalized(); + } + initial_position_set_ = true; + } else { + // ..otherwise dynamically update it. + Vector3f pt = transform_worker_.GetTranslate(); + target_pts_[0] = dyn_pts_[0] = pt; + auto up = Vector3f(&transform_worker_.m[4]); + auto back = Vector3f(&transform_worker_.m[8]); + up = (up + -0.03f * back).Normalized(); + float bAmt = 0.0f; + Vector3f oldTipPos = dyn_pts_[kFusePointCount - 1]; + for (int i = 1; i < kFusePointCount; i++) { + target_pts_[i] = dyn_pts_[i - 1] + up * seg_len_; + float thisFollowAmt = (i == 1 ? 0.5f : 0.2f); + dyn_pts_[i] += thisFollowAmt * (target_pts_[i] - dyn_pts_[i]); + dyn_pts_[i] += Vector3f(0, -0.014f * 0.2f * length_worker_, 0); + up = (dyn_pts_[i] - dyn_pts_[i - 1] - bAmt * back).Normalized(); + dyn_pts_[i] = dyn_pts_[i - 1] + up * seg_len_; + bAmt += 0.01f * length_worker_; + } + + // Spit out a spark. + float r, g, b, a; + if (length_worker_ > 0.66f) { + r = 1.6f; + g = 1.5f; + b = 0.4f; + a = 0.5f; + } else if (length_worker_ > 0.33f) { + r = 2.0f; + g = 0.7f; + b = 0.3f; + a = 0.2f; + } else { + r = 3.0f; + g = 0.5f; + b = 0.4f; + a = 0.3f; + } + int count = 2; + if (dyn->graphics_quality() <= GraphicsQuality::kLow) { + count = 1; + } + + for (int i = 0; i < count; i++) { + float rand_f = RandomFloat(); + float d_life = -0.08f; + float d_size = 0.000f + 0.04f * rand_f * rand_f; + + dyn->spark_particles()->Emit(dyn_pts_[kFusePointCount - 1], + dyn_pts_[kFusePointCount - 1] - oldTipPos, + r, g, b, a, d_life, 0.02f, d_size, + 0.8f); // Flicker. + } + } + } + + bool client_dead_{}; + float seg_len_{}; + Vector3f target_pts_[kFusePointCount]{}; + Vector3f dyn_pts_[kFusePointCount]{}; + float length_client_{1.0f}; + float length_worker_{1.0f}; + + // Values owned by the client. + Matrix44f transform_client_{kMatrix44fIdentity}; + + // Values owned by the worker thread. + Matrix44f transform_worker_{kMatrix44fIdentity}; + bool have_transform_client_{}; + bool have_transform_worker_{}; + bool initial_position_set_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_FUSE_DATA_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_height_cache.cc b/src/ballistica/dynamics/bg/bg_dynamics_height_cache.cc new file mode 100644 index 00000000..36b7e38d --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_height_cache.cc @@ -0,0 +1,173 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/bg/bg_dynamics_height_cache.h" + +#include + +namespace ballistica { + +const int kBGDynamicsHeightCacheMaxContacts = 20; + +BGDynamicsHeightCache::BGDynamicsHeightCache() + : dirty_(true), + shadow_ray_(nullptr), + x_min_(-1.0f), + x_max_(1.0f), + y_min_(-1.0f), + y_max_(1.0f), + z_min_(-1.0f), + z_max_(1.0f) { + grid_width_ = 1; + grid_height_ = 1; +} + +BGDynamicsHeightCache::~BGDynamicsHeightCache() { + if (shadow_ray_) { + dGeomDestroy(shadow_ray_); + } +} + +auto BGDynamicsHeightCache::SampleCell(int x, int z) -> float { + int index = z * grid_width_ + x; + assert(index >= 0 && index < static_cast(heights_.size()) + && index < static_cast(heights_valid_.size())); + if (heights_valid_[index]) { + return heights_[index]; + } else { + Vector3f p( + x_min_ + + ((static_cast(x) + 0.5f) / static_cast(grid_width_)) + * (x_max_ - x_min_), + y_max_, + z_min_ + + ((static_cast(z) + 0.5f) + / static_cast(grid_height_)) + * (z_max_ - z_min_)); + assert(shadow_ray_); + dGeomSetPosition(shadow_ray_, p.x, p.y, p.z); + float shadow_dist = y_max_ - y_min_; + for (auto& geom : geoms_) { + dContact contact[1]; + if (dCollide(shadow_ray_, geom, kBGDynamicsHeightCacheMaxContacts, + &contact[0].geom, sizeof(dContact))) { + float len = p.y - contact[0].geom.pos[1]; + if (len < shadow_dist) { + shadow_dist = len; + } + } + } + float height = y_max_ - shadow_dist; + heights_[index] = height; + heights_valid_[index] = 1; + return height; + } +} + +auto BGDynamicsHeightCache::Sample(const Vector3f& pos) -> float { + if (dirty_) { + Update(); + } + + // Get sample point in grid coords. + float x = + static_cast(grid_width_) * ((pos.x - x_min_) / (x_max_ - x_min_)) + - 0.5f; + float z = + static_cast(grid_height_) * ((pos.z - z_min_) / (z_max_ - z_min_)) + - 0.5f; + + // Sample the 4 contributing cells. + int x_min = static_cast(floor(x)); + x_min = std::max(0, std::min(grid_width_ - 1, x_min)); + int x_max = static_cast(ceil(x)); + x_max = std::max(0, std::min(grid_width_ - 1, x_max)); + float x_blend = fmod(x, 1.0f); + int z_min = static_cast(floor(z)); + z_min = std::max(0, std::min(grid_height_ - 1, z_min)); + int z_max = static_cast(ceil(z)); + z_max = std::max(0, std::min(grid_height_ - 1, z_max)); + float zBlend = fmod(z, 1.0f); + + float xz = SampleCell(x_min, z_min); + float xZ = SampleCell(x_min, z_max); + float Xz = SampleCell(x_max, z_min); + float XZ = SampleCell(x_max, z_max); + + // Weighted blend per row. + float zFin = xz * (1.0f - x_blend) + Xz * x_blend; + float ZFin = xZ * (1.0f - x_blend) + XZ * x_blend; + + // Weighted blend of the two rows. + return zFin * (1.0f - zBlend) + ZFin * zBlend; +} + +void BGDynamicsHeightCache::SetGeoms(const std::vector& geoms) { + dirty_ = true; + geoms_ = geoms; +} + +void BGDynamicsHeightCache::Update() { + // Calc our full dimensions. + if (geoms_.empty()) { + x_min_ = -1.0f; + x_max_ = 1.0f; + y_min_ = -1.0f; + y_max_ = 1.0f; + z_min_ = -1.0f; + z_max_ = 1.0f; + } else { + auto i = geoms_.begin(); + dReal aabb[6]; + dGeomGetAABB(*i, aabb); + float x = aabb[0]; + float X = aabb[1]; + float y = aabb[2]; + float Y = aabb[3]; + float z = aabb[4]; + float Z = aabb[5]; + for (i++; i != geoms_.end(); i++) { + dGeomGetAABB(*i, aabb); + if (aabb[0] < x) x = aabb[0]; + if (aabb[1] > X) X = aabb[1]; + if (aabb[2] < y) y = aabb[2]; + if (aabb[3] > Y) Y = aabb[3]; + if (aabb[4] < z) z = aabb[4]; + if (aabb[5] > Z) Z = aabb[5]; + } + float buffer = 0.3f; + x_min_ = x - buffer; + x_max_ = X + buffer; + y_min_ = y - buffer; + y_max_ = Y + buffer; + z_min_ = z - buffer; + z_max_ = Z + buffer; + } + + // (Re)create our shadow ray with the new dimensions. + if (shadow_ray_) { + dGeomDestroy(shadow_ray_); + } + shadow_ray_ = dCreateRay(nullptr, y_max_ - y_min_); + dGeomRaySet(shadow_ray_, 0, 0, 0, 0, -1, 0); // Aim straight down. + dGeomRaySetClosestHit(shadow_ray_, true); + + // Update/clear our cell grid based on our dimensions. + grid_width_ = + std::max(1, std::min(256, static_cast((x_max_ - x_min_) * 8))); + grid_height_ = + std::max(1, std::min(256, static_cast((z_max_ - z_min_) * 8))); + + assert(grid_width_ >= 0 && grid_height_ >= 0); + auto cell_count_u = static_cast(grid_width_ * grid_height_); + if (cell_count_u != heights_.size()) { + heights_.clear(); + heights_.resize(cell_count_u); + heights_valid_.clear(); + heights_valid_.resize(cell_count_u); + } + memset(&heights_valid_[0], 0, cell_count_u); + + dirty_ = false; +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/bg/bg_dynamics_height_cache.h b/src/ballistica/dynamics/bg/bg_dynamics_height_cache.h new file mode 100644 index 00000000..71502ff5 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_height_cache.h @@ -0,0 +1,42 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_HEIGHT_CACHE_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_HEIGHT_CACHE_H_ + +#include + +#include "ballistica/math/vector3f.h" +#include "ode/ode.h" + +namespace ballistica { + +// given geoms, creates/samples a height map on the fly +// for fast but not-perfectly-accurate height values +class BGDynamicsHeightCache { + public: + BGDynamicsHeightCache(); + ~BGDynamicsHeightCache(); + auto Sample(const Vector3f& pos) -> float; + void SetGeoms(const std::vector& geoms); + + private: + auto SampleCell(int x, int y) -> float; + void Update(); + std::vector geoms_; + std::vector heights_; + std::vector heights_valid_; + bool dirty_; + dGeomID shadow_ray_; + int grid_width_; + int grid_height_; + float x_min_; + float x_max_; + float y_min_; + float y_max_; + float z_min_; + float z_max_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_HEIGHT_CACHE_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_server.cc b/src/ballistica/dynamics/bg/bg_dynamics_server.cc new file mode 100644 index 00000000..a145c24e --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_server.cc @@ -0,0 +1,2657 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/bg/bg_dynamics_server.h" + +#include +#include +#include +#include + +#include "ballistica/dynamics/bg/bg_dynamics_draw_snapshot.h" +#include "ballistica/dynamics/bg/bg_dynamics_fuse_data.h" +#include "ballistica/dynamics/bg/bg_dynamics_height_cache.h" +#include "ballistica/dynamics/bg/bg_dynamics_shadow_data.h" +#include "ballistica/dynamics/bg/bg_dynamics_volume_light_data.h" +#include "ballistica/dynamics/collision_cache.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/platform/platform.h" + +namespace ballistica { + +// Some triangle-on-box cases generate tons of contacts; lets try limiting it +// this way.. If that doesn't work we'll crank this up and add collision +// simplification. +const int kMaxBGDynamicsContacts = 20; + +// How far from the shadow will be max size and min density. +const float kMaxShadowGrowDist = 3.0f; + +// How far behind something a shadow caster has to be to go transparent. +const float kShadowOccludeDistance = 0.5f; + +// How big the shadow gets at its max dist. +const float kMaxShadowScale = 3.0f; + +const float kSmokeBaseGlow = 0.0f; +const float kSmokeGlow = 400.0f; + +// FIXME: Should get rid of this stuff. +#if BA_DEBUG_BUILD +struct DebugLine { + DebugLine(const Vector3f& p1_in, const Vector3f& p2_in, + const Vector3f& color_in) + : p1(p1_in), p2(p2_in), color(color_in) {} + Vector3f p1; + Vector3f p2; + Vector3f color; +}; + +// Eww these aren't thread-safe but they're just for debugging so whatever. +std::vector g_debug_lines; +std::vector g_debug_points; +#endif // BA_DEBUG_BUILD + +// FIXME: Move to a nice math-y place. +inline auto Reflect(const Vector3f& v, const Vector3f& normal) -> Vector3f { + Vector3f n_projected = normal * (v.Dot(normal.Normalized())); + return -(n_projected - (v - n_projected)); +} + +static void CalcERPCFM(dReal stiffness, dReal damping, dReal* erp, dReal* cfm) { + if (stiffness <= 0.0f && damping <= 0.0f) { + *erp = 0.0f; + // cfm = dInfinity; // doesn't seem to be happy... + *cfm = 9999999999.0f; + } else { + *erp = (kGameStepSeconds * stiffness) + / ((kGameStepSeconds * stiffness) + damping); + *cfm = 1.0f / ((kGameStepSeconds * stiffness) + damping); + } +} + +class BGDynamicsServer::Terrain { + public: + Terrain(BGDynamicsServer* t, Object::Ref* collide_model_in) + : collide_model_(collide_model_in) { + assert((**collide_model_).loaded()); + geom_ = dCreateTriMesh(nullptr, (**collide_model_).GetBGMeshData(), nullptr, + nullptr, nullptr); + } + + auto GetCollideModel() const -> CollideModelData* { + return collide_model_->get(); + } + + ~Terrain() { + dGeomDestroy(geom_); + // We were passed an allocated pointer to a CollideModelData strong-ref + // object to keep it alive while we're using it. We need to pass that + // back to the main thread to get freed. + if (collide_model_) { + Object::Ref* ref = collide_model_; + g_game->PushCall([ref] { + (**ref).set_last_used_time(GetRealTime()); + delete ref; + }); + collide_model_ = nullptr; + } + } + + auto geom() const -> dGeomID { return geom_; } + + private: + Object::Ref* collide_model_; + dGeomID geom_; +}; + +class BGDynamicsServer::Field { + public: + Field(BGDynamicsServer* t, const Vector3f& pos, float mag) : pos_(pos) { + rad_ = 5; + mag_ = mag; + birth_time_ = t->time(); + lifespan_ = 500; + } + ~Field() = default; + + auto rad() const -> dReal { return rad_; } + auto pos() const -> Vector3f { return pos_; } + auto amt() const -> dReal { return amt_; } + void set_amt(dReal val) { amt_ = val; } + auto birth_time() const -> uint32_t { return birth_time_; } + auto lifespan() const -> dReal { return lifespan_; } + auto mag() const -> dReal { return mag_; } + + private: + Vector3f pos_; + dReal rad_; + dReal mag_; + uint32_t birth_time_; + dReal lifespan_; + dReal amt_{}; +}; + +class BGDynamicsServer::Tendril { + public: + struct Point { + Vector3f p{0.0f, 0.0f, 0.0f}; + Vector3f v{0.0f, 0.0f, 0.0f}; + Vector3f p_distorted{0.0f, 0.0f, 0.0f}; + float tex_coords[2]{}; + float erode{}; + float erode_rate{}; + float bouyancy{}; + float brightness{}; + float fade{}; + float fade_rate{}; + float age{}; + float glow_r{}; + float glow_g{}; + float glow_b{}; + void Update(const Tendril& t) { + p += v * kGameStepSeconds; + age += kGameStepMilliseconds; + v *= 0.992f; + v.y -= 0.003f * bouyancy; // Bouyancy. + v.x += 0.005f * t.wind_amt_; // Slight side drift. + erode *= (1.0f - 0.06f * erode_rate); + if (age > 750 * fade_rate) fade *= 1.0f - 0.0085f * fade_rate; + } + void UpdateDistortion(const BGDynamicsServer& d) { + p_distorted = p; + for (auto&& fi : d.fields_) { + const Field& f(*fi); + float fRad = f.rad(); + float fRadSquared = fRad * fRad; + Vector3f diff = p_distorted - f.pos(); + float dist_squared = diff.LengthSquared(); + if (dist_squared <= fRadSquared) { + float dist = sqrtf(dist_squared); + + // Shift our point towards or away from the field by its calced mag. + float mag = f.amt(); + + // Points closer than MAG to the field are scaled by their + // ratio of dist to mag. + if (dist < -mag) mag *= (dist / -mag); + float falloff = + (1.0f - (dist / fRad)); // falloff with dist from field + mag *= falloff; + Vector3f diff_norm = diff.Normalized(); + p_distorted += diff_norm * mag; + + // Also apply a very slight amount of actual outward force to ourself + // (only if we're kinda old though - otherwise it screws with our + // initial shape too much). + if (age > 400) { + v += Vector3f(diff_norm.x * 0.03f, diff_norm.y * 0.01f, + diff_norm.z * 0.03f) + * falloff; + } + } + } + } + + void UpdateGlow(const BGDynamicsServer& d, float glow_scale) { + glow_r = glow_g = glow_b = 0.0f; + for (auto&& li : d.volume_lights_) { + BGDynamicsVolumeLightData& l(*li); + Vector3f& pLight(l.pos_worker); + float light_rad = l.radius_worker * 9.0f; // Lets grow it a bit. + float light_rad_squared = light_rad * light_rad; + float dist_squared = (pLight - p).LengthSquared(); + if (dist_squared <= light_rad_squared) { + float dist = sqrtf(dist_squared); + float val = (1.0f - dist / light_rad); + val = val * val; + glow_r += val * l.r_worker; + glow_g += val * l.g_worker; + glow_b += val * l.b_worker; + } + } + glow_r *= glow_scale; + glow_g *= glow_scale; + glow_b *= glow_scale; + } + }; + + struct Slice { + Point p1; + Point p2; + float emit_rate{}; // What the emit rate was at this slice. + float start_erode{}; // What the start-erode value was at this slice. + float start_spread{}; // What the start-erode value was at this slice. + auto GetCenter() const -> Vector3f { return (p1.p * 0.5f) + (p2.p * 0.5f); } + auto isFullyTransparent() const -> bool { + return (p1.fade < 0.01f && p2.fade < 0.01f); + } + }; + + explicit Tendril(BGDynamicsServer* t) + : has_updated_(false), controller_(nullptr), emitting_(true) { + emit_rate_ = 0.8f + 0.4f * RandomFloat(); + birth_time_ = t->time(); + radius_ = 0.1f + RandomFloat() * 0.1f; + tex_coord_ = RandomFloat(); + start_erode_ = 0.1f; + start_spread_ = 4.0f; + side_spread_rate_ = 1.0f; + point_rand_scale_ = 1.0f; + slice_rand_scale_ = 1.0f; + tex_change_rate_ = 1.0f; + emit_rate_falloff_rate_ = 1.0f; + start_brightness_max_ = 0.9f; + start_brightness_min_ = 0.3f; + brightness_rand_ = 0.5f; + start_fade_scale_ = 1.0f; + glow_scale_ = 1.0f; + } + void SetController(TendrilController* tc) { + assert((controller_ == nullptr) ^ (tc == nullptr)); + controller_ = tc; + } + void UpdateSlices(BGDynamicsServer* t) { + for (auto&& i : slices_) { + i.p1.Update(*this); + i.p2.Update(*this); + + // Push them together slightly if they're getting too far apart. + Vector3f diff = i.p1.p - i.p2.p; + if (diff.LengthSquared() > 2.5f) { + i.p1.v += diff * -0.1f; + i.p2.v += diff * 0.1f; + } + } + + // No shadows for thin tendrils. + if (type_ == BGDynamicsTendrilType::kThinSmoke) { + shadow_density_ = 0.0f; + } else { + float blend = 0.995f; + + auto i = slices_.begin(); + if (i == slices_.end()) { + shadow_density_ = 0.0f; + } + int count = 0; + while (i != slices_.end()) { + shadow_position_ = + blend * shadow_position_ + (1.0f - blend) * i->GetCenter(); + shadow_density_ = blend * shadow_density_ + + (1.0f - blend) * (i->p1.fade + i->p2.fade) * 0.5f; + count++; + if (count > 4) break; // only use first few.. + i++; + } + } + } + + // Clear out old fully transparent slices. + void PruneSlices() { + // Clip transparent ones off the front. + while (true) { + auto i = slices_.begin(); + if (i == slices_.end()) break; + auto i_next = i; + i_next++; + if (i_next != slices_.end() && i->isFullyTransparent() + && i_next->isFullyTransparent()) { + slices_.pop_front(); + } else { + break; + } + } + + // ...and back. + while (true) { + auto i = slices_.rbegin(); + if (i == slices_.rend()) break; + auto i_next = i; + i_next++; + if (i_next != slices_.rend() && i->isFullyTransparent() + && i_next->isFullyTransparent()) { + slices_.pop_back(); + } else { + break; + } + } + } + + ~Tendril(); + + auto type() const -> BGDynamicsTendrilType { return type_; } + + private: + TendrilController* controller_; + Vector3f shadow_position_{0.0f, 0.0f, 0.0f}; + bool shading_flip_{}; + float wind_amt_{}; + float shadow_density_{}; + float emit_rate_{}; + float start_erode_{}; + float start_spread_{}; + float side_spread_rate_{}; + float point_rand_scale_{}; + float slice_rand_scale_{}; + float tex_change_rate_{}; + float emit_rate_falloff_rate_{}; + float start_brightness_max_{}; + float start_brightness_min_{}; + float brightness_rand_{}; + float start_fade_scale_{}; + float glow_scale_{}; + bool emitting_{}; + bool has_updated_{}; + std::list slices_{}; + Slice cur_slice_{}; + Vector3f position_{0.0f, 0.0f, 0.0f}; + Vector3f prev_pos_{0.0f, 0.0f, 0.0f}; + Vector3f velocity_{0.0f, 0.0f, 0.0f}; + Vector3f medium_velocity_{0.0f, 0.0f, 0.0f}; + uint32_t birth_time_{}; + float tex_coord_{}; + float radius_{}; + BGDynamicsTendrilType type_{}; + friend class BGDynamicsServer; +}; + +class BGDynamicsServer::TendrilController { + public: + explicit TendrilController(Tendril* t) { + tendril_ = t; + tendril_->SetController(this); + } + ~TendrilController() { + // If we have a tendril, tell it we're dying and that its done emitting. + if (tendril_) { + tendril_->SetController(nullptr); + tendril_->emit_rate_ = 0.0f; + } + } + void update(const Vector3f& pos, const Vector3f& vel) { + if (tendril_) { + tendril_->prev_pos_ = tendril_->position_; + tendril_->position_ = pos; + tendril_->velocity_ = vel; + } + } + + private: + Tendril* tendril_; + friend class Tendril; +}; + +class BGDynamicsServer::Chunk { + public: + Chunk(BGDynamicsServer* t, const BGDynamicsEmission& event, bool dynamic, + bool can_die = true, const Vector3f& d_bias = kVector3f0) + : shadow_dist_(9999), + type_(event.chunk_type), + dynamic_(dynamic), + can_die_(can_die), + tendril_controller_(nullptr) { + birth_time_ = t->time(); + flicker_ = 1.0f; + flicker_scale_ = RandomFloat(); + flicker_scale_ = 1.0f - (flicker_scale_ * flicker_scale_); + if (type_ != BGDynamicsChunkType::kFlagStand) { + if (type_ == BGDynamicsChunkType::kSplinter) { + size_[0] = event.scale * 0.15f * (0.4f + 0.6f * RandomFloat()); + size_[1] = event.scale * 0.15f * (0.4f + 0.6f * RandomFloat()); + size_[2] = event.scale * 0.15f * (0.4f + 0.6f * RandomFloat()) * 5.0f; + } else { + size_[0] = event.scale * 0.15f * (0.3f + 0.7f * RandomFloat()); + size_[1] = event.scale * 0.15f * (0.3f + 0.7f * RandomFloat()); + size_[2] = event.scale * 0.15f * (0.3f + 0.7f * RandomFloat()); + } + } else { + size_[0] = size_[1] = size_[2] = 1.0f; + } + + lifespan_ = 10000; + if (type_ == BGDynamicsChunkType::kSpark) { + lifespan_ = 500 + RandomFloat() * 1500; + if (RandomFloat() < 0.1f) lifespan_ *= 3.0f; + } else if (type_ == BGDynamicsChunkType::kSweat) { + lifespan_ = 200 + RandomFloat() * 400; + if (RandomFloat() < 0.1f) lifespan_ *= 2.0f; + } else if (type_ == BGDynamicsChunkType::kFlagStand) { + lifespan_ = 99999999.0f; + } + + if (dynamic_) { + body_ = dBodyCreate(t->ode_world_); + geom_ = dCreateBox(nullptr, size_[0], size_[1], size_[2]); + dGeomSetBody(geom_, body_); + dMass m; + dMassSetBox(&m, 1.0f, size_[0], size_[1], size_[2]); + + dBodySetMass(body_, &m); + + Vector3f v = event.velocity; + float spread = event.spread; + Vector3f v_rand = (Utils::Sphrand() + d_bias).Normalized() * RandomFloat() + * 40.0f * spread; + + dBodySetPosition(body_, event.position.x, event.position.y, + event.position.z); + dBodySetLinearVel(body_, v.x + v_rand.x, v.y + v_rand.y, v.z + v_rand.z); + dBodySetAngularVel(body_, (RandomFloat() - 0.5f) * 5.0f, + (RandomFloat() - 0.5f) * 5.0f, + (RandomFloat() - 0.5f) * 5.0f); + } else { + Vector3f axis{}; + if (type_ == BGDynamicsChunkType::kFlagStand) { + axis = Vector3f(0, 1, 0); + } else { + axis = Utils::Sphrand(); + } + Matrix44f m = Matrix44fScale(Vector3f(size_[0], size_[1], size_[2])) + * Matrix44fRotate(axis, RandomFloat() * 360.0f) + * Matrix44fTranslate(event.position); + for (int i = 0; i < 16; i++) { + static_transform_[i] = m.m[i]; + } + + // Assume we're sitting on the ground. + shadow_dist_ = 0.0f; + } + } + auto body() const -> dBodyID { return body_; } + + auto geom() const -> dGeomID { return geom_; } + + auto type() const -> BGDynamicsChunkType { return type_; } + + ~Chunk() { + delete tendril_controller_; + if (dynamic_) { + dBodyDestroy(body_); + dGeomDestroy(geom_); + } + } + + void UpdateTendril() { + if (tendril_controller_) { + tendril_controller_->update(Vector3f(dBodyGetPosition(body_)), + Vector3f(dBodyGetLinearVel(body_))); + } + } + auto can_die() const -> bool { return can_die_; } + auto dynamic() const -> bool { return dynamic_; } + auto size() const -> const float* { return size_; } + auto static_transform() const -> const float* { return static_transform_; } + + private: + TendrilController* tendril_controller_; + bool dynamic_; + bool can_die_; + dReal lifespan_; + dReal flicker_; + dReal flicker_scale_; + float static_transform_[16]{}; + BGDynamicsChunkType type_{}; + uint32_t birth_time_{}; + dBodyID body_{}; + dGeomID geom_{}; + float size_[3]{}; + float shadow_dist_; + friend class BGDynamicsServer; +}; // Chunk + +// Contains 2 ping-ponging particle buffers. +void BGDynamicsServer::ParticleSet::Emit(const Vector3f& pos, + const Vector3f& vel, float r, float g, + float b, float a, float dlife, + float size, float d_size, + float flicker) { + particles[current_set].resize(particles[current_set].size() + 1); + Particle& p(particles[current_set].back()); + p.x = pos.x; + p.y = pos.y; + p.z = pos.z; + p.vx = vel.x * 1.0f + 0.02f * (RandomFloat() - 0.5f); + p.vy = vel.y * 1.0f + 0.02f * (RandomFloat() - 0.5f); + p.vz = vel.z * 1.0f + 0.02f * (RandomFloat() - 0.5f); + p.r = r; + p.g = g; + p.b = b; + p.a = a; + p.life = 1.0f; + assert(dlife < 0.0f); + p.d_life = dlife; + p.size = size; + p.flicker = 1.0f; + p.flicker_scale = flicker; + p.d_size = d_size; +} + +void BGDynamicsServer::ParticleSet::UpdateAndCreateSnapshot( + Object::Ref* index_buffer, + Object::Ref* buffer) { + auto p_count = static_cast(particles[current_set].size()); + + // Quick-out: return empty. + if (p_count == 0) { + return; + } + + Particle* p_src = &particles[current_set][0]; + + // Resize target to fit if all particles stay alive. + particles[!current_set].resize(particles[current_set].size()); + Particle* p_dst = &particles[!current_set][0]; + + auto* ibuf = Object::NewDeferred(p_count * 6); + + // Game thread is default owner; needs to be us until we hand it over. + ibuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + *index_buffer = Object::MakeRefCounted(ibuf); + auto* vbuf = Object::NewDeferred(p_count * 4); + + // Game thread is default owner; needs to be us until we hand it over. + vbuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + *buffer = Object::MakeRefCounted(vbuf); + + uint16_t* i_render = &(*index_buffer)->elements[0]; + VertexSprite* p_render = &(*buffer)->elements[0]; + uint32_t p_index = 0; + uint32_t p_count_remaining = 0; + uint32_t p_count_rendered = 0; + for (uint32_t i = 0; i < p_count; i++) { + float life = p_src->life + p_src->d_life; + + // Our opacity drops rapidly at the end. + float o = 1.0f - life; + o = 1.0f - (o * o * o); + float size = std::max(0.0f, p_src->size + p_src->d_size); + + // Kill the particle if life or size falls to 0. + if (life > 0.0f && size > 0) { + p_count_remaining++; + p_dst->life = life; + p_dst->size = size; + p_dst->x = p_src->x + p_src->vx; + p_dst->y = p_src->y + p_src->vy; + p_dst->z = p_src->z + p_src->vz; + p_dst->r = p_src->r; + p_dst->g = p_src->g; + p_dst->b = p_src->b; + p_dst->a = p_src->a; + p_dst->vx = p_src->vx; + p_dst->vy = p_src->vy - 0.00001f; + p_dst->vz = p_src->vz; + p_dst->d_life = p_src->d_life; + p_dst->d_size = p_src->d_size; + p_dst->flicker_scale = p_src->flicker_scale; + + // Every so often update our flicker value if we're flickering. + if (p_src->flicker_scale != 0.0f) { + if (RandomFloat() < 0.2f) { + p_dst->flicker = std::max( + 0.0f, 1.0f + (RandomFloat() - 0.5f) * p_src->flicker_scale); + } else { + p_dst->flicker = p_src->flicker; + } + } else { + p_dst->flicker = 1.0f; + } + + // Render this point if its got a positive size. + if (p_dst->flicker > 0.0f && p_dst->size > 0.0f) { + p_count_rendered++; + + // Add our 6 indices. + { + i_render[0] = static_cast(p_index); + i_render[1] = static_cast(p_index + 1); + i_render[2] = static_cast(p_index + 2); + i_render[3] = static_cast(p_index + 1); + i_render[4] = static_cast(p_index + 3); + i_render[5] = static_cast(p_index + 2); + } + + p_render[0].uv[0] = 0; + p_render[0].uv[1] = 0; + p_render[1].uv[0] = 0; + p_render[1].uv[1] = 65535; + p_render[2].uv[0] = 65535; + p_render[2].uv[1] = 0; + p_render[3].uv[0] = 65535; + p_render[3].uv[1] = 65535; + + p_render[0].position[0] = p_render[1].position[0] = + p_render[2].position[0] = p_render[3].position[0] = p_dst->x; + p_render[0].position[1] = p_render[1].position[1] = + p_render[2].position[1] = p_render[3].position[1] = p_dst->y; + p_render[0].position[2] = p_render[1].position[2] = + p_render[2].position[2] = p_render[3].position[2] = p_dst->z; + p_render[0].size = p_render[1].size = p_render[2].size = + p_render[3].size = p_dst->size * p_dst->flicker; + p_render[0].color[0] = p_render[1].color[0] = p_render[2].color[0] = + p_render[3].color[0] = p_dst->r * o; + p_render[0].color[1] = p_render[1].color[1] = p_render[2].color[1] = + p_render[3].color[1] = p_dst->g * o; + p_render[0].color[2] = p_render[1].color[2] = p_render[2].color[2] = + p_render[3].color[2] = p_dst->b * o; + p_render[0].color[3] = p_render[1].color[3] = p_render[2].color[3] = + p_render[3].color[3] = p_dst->a * o; + + i_render += 6; + p_render += 4; + p_index += 4; + } + p_dst++; + } + p_src++; + } + + // Clamp dst and render sets to account for deaths. + if (p_count != p_count_remaining) { + particles[!current_set].resize(p_count_remaining); + } + + if (p_count != p_count_rendered) { + // If we dropped all the way to zero, return empty. + // Otherwise return a downsized buffer. + if (p_count_rendered == 0) { + *index_buffer = Object::Ref(); + *buffer = Object::Ref(); + } else { + (*index_buffer)->elements.resize(p_count_rendered * 6); + (*buffer)->elements.resize(p_count_rendered * 4); + } + } + current_set = !current_set; +} + +BGDynamicsServer::BGDynamicsServer(Thread* thread) + : Module("bgDynamics", thread), + height_cache_(new BGDynamicsHeightCache()), + collision_cache_(new CollisionCache) { + BA_PRECONDITION(g_bg_dynamics_server == nullptr); + g_bg_dynamics_server = this; + + ode_world_ = dWorldCreate(); + assert(ode_world_); + dWorldSetGravity(ode_world_, 0.0f, -20.0f, 0.0f); + dWorldSetContactSurfaceLayer(ode_world_, 0.001f); + dWorldSetAutoDisableFlag(ode_world_, true); + dWorldSetAutoDisableSteps(ode_world_, 5); + dWorldSetAutoDisableLinearThreshold(ode_world_, 0.6f); + dWorldSetAutoDisableAngularThreshold(ode_world_, 0.6f); + dWorldSetAutoDisableSteps(ode_world_, 10); + dWorldSetAutoDisableTime(ode_world_, 0); + dWorldSetQuickStepNumIterations(ode_world_, 3); + ode_contact_group_ = dJointGroupCreate(0); + assert(ode_contact_group_); +} + +BGDynamicsServer::~BGDynamicsServer() = default; + +BGDynamicsServer::Tendril::~Tendril() { + // If we have a controller, tell them not to call us anymore. + if (controller_) { + controller_->tendril_ = nullptr; + } +} + +void BGDynamicsServer::UpdateFuses() { + for (auto&& i : fuses_) { + i->Update(this); + } +} + +void BGDynamicsServer::UpdateTendrils() { + int render_slice_count = 0; + + for (auto i = tendrils_.begin(); i != tendrils_.end();) { + Tendril& t(**i); + + // Kill off fully-dead tendrils. + if (!t.emitting_ && t.slices_.size() < 2) { + auto i_next = i; + i_next++; + if (t.type_ == BGDynamicsTendrilType::kThinSmoke) { + tendril_count_thin_--; + } else { + tendril_count_thick_--; + } + assert(tendril_count_thin_ >= 0 && tendril_count_thick_ >= 0); + delete *i; + tendrils_.erase(i); + i = i_next; + continue; + } + + // Clip transparent bits off the ends. + t.PruneSlices(); + + // Step existing tendril points. + t.UpdateSlices(this); + + // Update the tendrils physics if it is not being controlled. + if (t.controller_ == nullptr) { + t.prev_pos_ = t.position_; + t.velocity_ += Vector3f(0, -0.1f, 0); // Gravity. + t.position_ += t.velocity_ * kGameStepSeconds; + } + + // If we're still emitting, potentially drop in some new slices. + if (t.emitting_) { + // Step from our last slice to our current position, + // dropping in new slices as we go. + Vector3f p = {0.0f, 0.0f, 0.0f}; + float tex_coord{}; + float emit_rate{}; + float start_erode{}; + float start_spread{}; + int slice_count = static_cast(t.slices_.size()); + if (slice_count > 0) { + p = t.slices_.back().GetCenter(); + tex_coord = t.slices_.back().p1.tex_coords[1]; + emit_rate = t.slices_.back().emit_rate; + start_erode = t.slices_.back().start_erode; + start_spread = t.slices_.back().start_spread; + } else { + p = t.prev_pos_; + tex_coord = t.tex_coord_; + emit_rate = t.emit_rate_; + start_erode = t.start_erode_; + start_spread = t.start_spread_; + } + Vector3f march_dir = t.position_ - p; + float dist = march_dir.Length(); + + // We flip our shading depending on which way the tendril is pointing + // so that the light side is generally up. + float start_brightness{}; + float start_brightness_2{}; + if (t.shading_flip_) { + start_brightness = t.start_brightness_max_; + start_brightness_2 = t.start_brightness_min_; + } else { + start_brightness = t.start_brightness_min_; + start_brightness_2 = t.start_brightness_max_; + } + + float start_brightness_rand = t.brightness_rand_; + float erode_rate_randomness = 0.5f; + float fade_rate_randomness = 2.0f; + + if (dist > 0.001f) { + float span = 0.5f; + march_dir = march_dir.Normalized() * span; + Vector3f from_cam = cam_pos_ - p; + Vector3f side_vec = Vector3f::Cross(march_dir, from_cam).Normalized(); + + float inherit_velocity = 0.015f; + + // If this is our first step, drop down a span immediately. + if (!t.has_updated_) { + Vector3f r_uniform = Utils::Sphrand(0.2f * t.slice_rand_scale_); + float density = emit_rate > 0.1f ? 1.0f : emit_rate / 0.1f; + + t.slices_.emplace_back(); + Tendril::Slice& slice(t.slices_.back()); + slice.emit_rate = emit_rate; + slice.start_erode = start_erode; + slice.start_spread = start_spread; + slice.p1.p = p - t.radius_ * side_vec * start_spread; + slice.p1.v = t.medium_velocity_ * 0.3f + + t.velocity_ * inherit_velocity * 0.1f + - side_vec * t.radius_ * t.side_spread_rate_ + r_uniform + + Utils::Sphrand(0.13f * t.point_rand_scale_); + slice.p1.tex_coords[0] = 0.0f; + slice.p1.tex_coords[1] = tex_coord; + slice.p1.erode = t.start_erode_; + slice.p1.erode_rate = std::max( + 0.0f, density + erode_rate_randomness * (RandomFloat() - 0.5f)); + slice.p1.age = 0.0f; + slice.p1.bouyancy = 0.3f + 0.2f * RandomFloat(); + slice.p1.brightness = std::max( + 0.0f, start_brightness + + (RandomFloat() - 0.5f) * start_brightness_rand); + slice.p1.fade = 0.0f; + slice.p1.glow_r = slice.p1.glow_g = slice.p1.glow_b = 0.0f; + slice.p1.fade_rate = 1.0f + fade_rate_randomness * (RandomFloat()); + + slice.p2.p = p + t.radius_ * side_vec * start_spread; + slice.p2.v = t.medium_velocity_ * 0.3f + + t.velocity_ * inherit_velocity * 0.1f + + side_vec * t.radius_ * t.side_spread_rate_ + r_uniform + + Utils::Sphrand(0.13f * t.point_rand_scale_); + slice.p2.tex_coords[0] = 0.25f; + slice.p2.tex_coords[1] = tex_coord; + slice.p2.erode = t.start_erode_; + slice.p2.erode_rate = std::max( + 0.0f, density + erode_rate_randomness * (RandomFloat() - 0.5f)); + slice.p2.age = 0.0f; + slice.p2.bouyancy = 0.3f + 0.2f * RandomFloat(); + slice.p2.brightness = std::max( + 0.0f, start_brightness_2 + + (RandomFloat() - 0.5f) * start_brightness_rand); + slice.p2.fade = 0.0f; + slice.p2.glow_r = slice.p2.glow_g = slice.p2.glow_b = 0.0f; + slice.p2.fade_rate = 1.0f + fade_rate_randomness * (RandomFloat()); + } + + t.has_updated_ = true; + float tex_change_rate = 0.18f * t.tex_change_rate_; + float emit_change_rate = -0.4f * t.emit_rate_falloff_rate_; + float start_erode_change_rate = 1.0f; + float start_spread_change_rate = -0.35f; + + // Reset our tex coord to that of the last span for marching purposes. + for (; dist > span; dist -= span) { // NOLINT + p += march_dir; + tex_coord += span * tex_change_rate; + emit_rate = std::max(0.0f, emit_rate + span * emit_change_rate); + start_erode = + std::min(1.0f, start_erode + span * start_erode_change_rate); + start_spread = + std::max(1.0f, start_spread + span * start_spread_change_rate); + + // General density stays high until emit rate gets low. + float density = emit_rate > 0.1f ? 1.0f : emit_rate / 0.1f; + + Vector3f r_uniform = Utils::Sphrand(0.2f * t.slice_rand_scale_); + t.slices_.emplace_back(); + Tendril::Slice& slice(t.slices_.back()); + slice.emit_rate = emit_rate; + slice.start_erode = start_erode; + slice.start_spread = start_spread; + slice.p1.p = p - t.radius_ * side_vec * start_spread; + slice.p1.v = t.medium_velocity_ * 0.3f + + t.velocity_ * inherit_velocity + - side_vec * t.radius_ * t.side_spread_rate_ + r_uniform + + Utils::Sphrand(0.2f * t.point_rand_scale_); + slice.p1.tex_coords[0] = 0.0f; + slice.p1.tex_coords[1] = tex_coord; + slice.p1.erode = start_erode; + slice.p1.erode_rate = std::max( + 0.0f, density + erode_rate_randomness * (RandomFloat() - 0.5f)); + slice.p1.age = 0.0f; + slice.p1.bouyancy = 0.3f + 0.2f * RandomFloat(); + slice.p1.brightness = std::max( + 0.0f, start_brightness + + (RandomFloat() - 0.5f) * start_brightness_rand); + slice.p1.fade = density * t.start_fade_scale_; + slice.p1.glow_r = slice.p1.glow_g = slice.p1.glow_b = 0.0f; + slice.p1.fade_rate = 1.0f + fade_rate_randomness * (RandomFloat()); + + slice.p2.p = p + t.radius_ * side_vec * start_spread; + slice.p2.v = t.medium_velocity_ * 0.3f + + t.velocity_ * inherit_velocity + + side_vec * t.radius_ * t.side_spread_rate_ + r_uniform + + Utils::Sphrand(0.2f * t.point_rand_scale_); + slice.p2.tex_coords[0] = 0.25f; + slice.p2.tex_coords[1] = tex_coord; + slice.p2.erode = start_erode; + slice.p2.erode_rate = std::max( + 0.0f, density + erode_rate_randomness * (RandomFloat() - 0.5f)); + slice.p2.age = 0.0f; + slice.p2.bouyancy = 0.3f + 0.2f * RandomFloat(); + slice.p2.brightness = std::max( + 0.0f, start_brightness_2 + + (RandomFloat() - 0.5f) * start_brightness_rand); + slice.p2.fade = density * t.start_fade_scale_; + slice.p2.glow_r = slice.p2.glow_g = slice.p2.glow_b = 0.0f; + slice.p2.fade_rate = 1.0f + fade_rate_randomness * (RandomFloat()); + + // If our emit rate has dropped to zero, this will be our last span. + if (t.emit_rate_ <= 0.001f) t.emitting_ = false; + } + // Add leftover dist to wind up with our current tex-coord/emit-rate. + t.tex_coord_ = tex_coord + (dist * tex_change_rate); + t.emit_rate_ = emit_rate + (dist * emit_change_rate); + t.start_erode_ = start_erode + (dist * start_erode_change_rate); + t.start_spread_ = + std::max(1.0f, start_spread + dist * start_spread_change_rate); + + // Update our at-emitter slice. + float density = t.emit_rate_ > 0.1f ? 1.0f : t.emit_rate_ / 0.1f; + + t.cur_slice_.p1.p = + t.position_ - t.radius_ * side_vec * t.start_spread_; + t.cur_slice_.p1.tex_coords[0] = 0.0f; + t.cur_slice_.p1.tex_coords[1] = t.tex_coord_; + t.cur_slice_.p1.erode = t.start_erode_; + t.cur_slice_.p1.erode_rate = std::max( + 0.0f, density + erode_rate_randomness * (RandomFloat() - 0.5f)); + t.cur_slice_.p1.age = 0.0f; + t.cur_slice_.p1.brightness = start_brightness; + t.cur_slice_.p1.fade = density * t.start_fade_scale_; + t.cur_slice_.p1.glow_r = t.cur_slice_.p1.glow_g = + t.cur_slice_.p1.glow_b = 0.0f; + t.cur_slice_.p1.fade_rate = + 1.0f + fade_rate_randomness * (RandomFloat()); + + t.cur_slice_.p2.p = + t.position_ + t.radius_ * side_vec * t.start_spread_; + t.cur_slice_.p2.tex_coords[0] = 0.25f; + t.cur_slice_.p2.tex_coords[1] = t.tex_coord_; + t.cur_slice_.p2.erode = t.start_erode_; + t.cur_slice_.p2.erode_rate = std::max( + 0.0f, density + erode_rate_randomness * (RandomFloat() - 0.5f)); + t.cur_slice_.p2.age = 0.0f; + t.cur_slice_.p2.brightness = start_brightness_2; + t.cur_slice_.p2.fade = density * t.start_fade_scale_; + t.cur_slice_.p2.glow_r = t.cur_slice_.p2.glow_g = + t.cur_slice_.p2.glow_b = 0.0f; + t.cur_slice_.p2.fade_rate = + 1.0f + fade_rate_randomness * (RandomFloat()); + } + } + + // Ok now update lighting and distortion on our tendril points and store + // them for rendering. + { + for (auto&& s : t.slices_) { + render_slice_count++; + s.p1.UpdateGlow(*this, t.glow_scale_); + s.p2.UpdateGlow(*this, t.glow_scale_); + s.p1.UpdateDistortion(*this); + s.p2.UpdateDistortion(*this); + } + // Also update our in-progress ones. + render_slice_count++; + t.cur_slice_.p1.UpdateGlow(*this, t.glow_scale_); + t.cur_slice_.p2.UpdateGlow(*this, t.glow_scale_); + t.cur_slice_.p1.UpdateDistortion(*this); + t.cur_slice_.p2.UpdateDistortion(*this); + } + i++; + } +} + +void BGDynamicsServer::Clear() { + // Clear chunks. + { + auto i = chunks_.begin(); + while (i != chunks_.end()) { + delete *i; + chunks_.erase(i); + chunk_count_--; + i = chunks_.begin(); + assert(chunk_count_ >= 0); + } + assert(chunk_count_ == 0); + } + + // ..and tendrils. + { + auto i = tendrils_.begin(); + while (i != tendrils_.end()) { + if ((**i).type_ == BGDynamicsTendrilType::kThinSmoke) { + tendril_count_thin_--; + } else { + tendril_count_thick_--; + } + delete *i; + tendrils_.erase(i); + i = tendrils_.begin(); + } + assert(tendril_count_thin_ == 0 && tendril_count_thick_ == 0); + } +} + +void BGDynamicsServer::PushEmitCall(const BGDynamicsEmission& def) { + PushCall([this, def] { Emit(def); }); +} + +void BGDynamicsServer::Emit(const BGDynamicsEmission& def) { + assert(InBGDynamicsThread()); + + if (def.emit_type == BGDynamicsEmitType::kDistortion) { + fields_.push_back(new Field(this, def.position, def.spread)); + return; + } + + // First off, lets ramp down the number of things we're making depending + // on settings or how many we already have, etc. + int emit_count = def.count; + + int tendril_thick_max = 20; + int tendril_thin_max = 14; + int chunk_max = 200; + + // Scale our counts down based on a few things. + if (graphics_quality_ <= GraphicsQuality::kLow) { + emit_count = static_cast(static_cast(emit_count) * 0.35f); + tendril_thick_max = 0; + tendril_thin_max = 0; + chunk_max = static_cast(static_cast(chunk_max) * 0.5f); + } else if (graphics_quality_ <= GraphicsQuality::kMedium) { + tendril_thick_max = + static_cast(static_cast(tendril_thick_max) * 0.5f); + tendril_thin_max = + static_cast(static_cast(tendril_thin_max) * 0.5f); + chunk_max = static_cast(static_cast(chunk_max) * 0.75f); + } else if (graphics_quality_ == GraphicsQuality::kHigh) { + emit_count = static_cast(static_cast(emit_count) * 0.8f); + tendril_thick_max = + static_cast(static_cast(tendril_thick_max) * 0.6f); + tendril_thin_max = + static_cast(static_cast(tendril_thin_max) * 0.6f); + chunk_max = static_cast(static_cast(chunk_max) * 0.75f); + } else { +// (higher-quality) + +// On k1 android let's ramp things up even more. +#if BA_OSTYPE_ANDROID + if (g_platform->is_tegra_k1()) { + chunk_max = static_cast(static_cast(chunk_max) * 1.5f); + emit_count = static_cast(static_cast(emit_count) * 1.5f); + tendril_thin_max = + static_cast(static_cast(tendril_thin_max) * 1.25f); + } +#endif // BA_OSTYPE_ANDROID + +#if BA_RIFT_BUILD + // rift build is gonna be running on beefy hardware; let's go crazy + // here.. + chunk_max *= 2.5f; + emit_count *= 2.5f; + tendril_thin_max *= 2.5f; +#endif + +#if BA_DEMO_BUILD + // lets beef up our demo kiosk build too.. what the heck. + chunk_max *= 2.5f; + emit_count *= 2.5f; + tendril_thin_max *= 2.5f; +#endif + } + + if (def.emit_type == BGDynamicsEmitType::kTendrils) { + if (def.tendril_type == BGDynamicsTendrilType::kThinSmoke) { + // For thin tendrils, start scaling back once we pass 8 tendrils. + // Once we're at tendril_thin_max, stop adding completely. + int scale_count = tendril_thin_max / 3; + if (tendril_count_thin_ >= tendril_thin_max) { + emit_count = 0; + } else if (tendril_count_thin_ > scale_count) { + emit_count = static_cast( + static_cast(emit_count) + * (1.0f + - static_cast(tendril_count_thin_ - scale_count) + / static_cast(tendril_thin_max - scale_count))); + } + } else { + // For thick tendrils, start scaling back once we pass 8 tendrils. + // Once we're at tendril_thick_max, stop adding completely. + int scale_count = tendril_thick_max / 3; + if (tendril_count_thick_ >= tendril_thick_max) { + emit_count = 0; + } else if (tendril_count_thick_ > scale_count) { + emit_count = static_cast( + static_cast(emit_count) + * (1.0f + - static_cast(tendril_count_thick_ - scale_count) + / static_cast(tendril_thick_max - scale_count))); + } + } + } else { + // For debris, start scaling back once we pass 50.. at chunk_max lets + // stop. + if (chunk_count_ >= chunk_max) { + emit_count = 0; + } else if (chunk_count_ > 50) { + emit_count = + static_cast(static_cast(emit_count) + * (1.0f + - static_cast(chunk_count_ - 50) + / static_cast(chunk_max - 50))); + } + } + + bool near_surface = false; + Vector3f surface_normal = {0.0f, 0.0f, 0.0f}; + float surface_closeness = 0.0f; + + // For the chunks/tendrils case, lets throw down a ray in the provided + // velocity direction. If we hit something nearby, we can use that info + // to adjust our emission. + if (def.emit_type == BGDynamicsEmitType::kChunks + || def.emit_type == BGDynamicsEmitType::kTendrils) { + dGeomID ray = dCreateRay(nullptr, 2.0f); + dGeomRaySetClosestHit(ray, true); + Vector3f dir = def.velocity; + dir.y -= RandomFloat() * 10.0f; // bias downward + dGeomRaySet(ray, def.position.x, def.position.y, def.position.z, dir.x, + dir.y, dir.z); + dContact contact[1]; + for (auto&& t : terrains_) { + dGeomID t_geom = t->geom(); + if (dCollide(ray, t_geom, 1, &contact[0].geom, sizeof(dContact))) { + near_surface = true; + surface_normal = contact[0].geom.normal; + float len = (Vector3f(contact[0].geom.pos) - def.position).Length(); + // At length 0.1, closeness is 1; at 2 its 0. + surface_closeness = + 1.0f - std::min(1.0f, std::max(0.0f, (len - 0.2f) / (2.0f - 0.2f))); + break; + } + } + + dGeomDestroy(ray); + } + + Vector3f d_bias = {0.0f, 0.0f, 0.0f}; + if (near_surface) + d_bias = surface_normal * RandomFloat() * 6.0f * surface_closeness; + + switch (def.emit_type) { + case BGDynamicsEmitType::kChunks: { + // Tone down bias on splinters - we always want those flying + // every which way. + if (def.chunk_type == BGDynamicsChunkType::kSplinter) { + d_bias *= 0.3f; + } + + for (int i = 0; i < emit_count; i++) { + // Bias *most* of our chunks (looks too empty if *everything* is + // going one direction). + + auto* chunk = new Chunk(this, def, true, true, + RandomFloat() < 0.8f ? d_bias : kVector3f0); + + bool do_tendril = false; + if (def.chunk_type == BGDynamicsChunkType::kSpark + && RandomFloat() < 0.13f) { // NOLINT(bugprone-branch-clone) + do_tendril = true; + } else if (def.chunk_type == BGDynamicsChunkType::kSplinter + && RandomFloat() < 0.2f) { + do_tendril = true; + } + + // If we're emitting sparks, every now and then give one of them a + // smoke tendril. + if (do_tendril) { + // Create a tendril, create a controller for it, and store it + // with the chunk. + { + BGDynamicsTendrilType tendril_type = + BGDynamicsTendrilType::kThinSmoke; + auto* t = new Tendril(this); + t->type_ = tendril_type; + t->shading_flip_ = false; + t->wind_amt_ = 0.4f + RandomFloat() * 1.6f; + t->shadow_density_ = 1.0f; + { + t->radius_ *= 0.15f; + t->side_spread_rate_ = 0.3f; + t->point_rand_scale_ = 0.5f; + t->slice_rand_scale_ = 0.5f; + t->tex_change_rate_ = 1.5f + RandomFloat() * 2.0f; + t->emit_rate_falloff_rate_ = 0.2f + RandomFloat() * 0.6f; + t->start_brightness_max_ = 0.92f; + t->start_brightness_min_ = 0.9f; + t->brightness_rand_ = 0.1f; + t->start_fade_scale_ = 0.15f + RandomFloat() * 0.2f; + t->glow_scale_ = 1.0f; + } + tendrils_.push_back(t); + tendril_count_thin_++; + auto* c = new TendrilController(t); + chunk->tendril_controller_ = c; + chunk->UpdateTendril(); + } + } + chunks_.push_back(chunk); + chunk_count_++; + } + break; + } + case BGDynamicsEmitType::kStickers: { + BGDynamicsEmission edef = def; + dGeomID ray = dCreateRay(nullptr, 4.0f); + dGeomRaySetClosestHit(ray, true); + for (int i = 0; i < emit_count; i++) { + Vector3f dir = Utils::Sphrand(def.spread); + dir.y -= def.spread * 2.5f * RandomFloat(); // bias downward + dGeomRaySet(ray, def.position.x, def.position.y + 0.5f, def.position.z, + dir.x, dir.y, dir.z); + dContact contact[1]; + for (auto&& t : terrains_) { + dGeomID t_geom = t->geom(); + if (dCollide(ray, t_geom, 1, &contact[0].geom, sizeof(dContact))) { + // Create a static chunk at this hit point. + edef.position = Vector3f(contact[0].geom.pos); + chunks_.push_back(new Chunk(this, edef, false)); + chunk_count_++; + } + } + } + dGeomDestroy(ray); + break; + } + case BGDynamicsEmitType::kTendrils: { +#if BA_DEBUG_BUILD + g_debug_lines.clear(); + g_debug_points.clear(); + g_debug_points.push_back(def.position); +#endif + + float ray_len = 1.5f; + float ray_offset = 0.3f; + dGeomID ray = dCreateRay(nullptr, ray_len); + dGeomRaySetClosestHit(ray, true); + for (int i = 0; i < emit_count; i++) { + Vector3f dir = (Utils::Sphrand() + d_bias * 0.5f).Normalized(); + dGeomRaySet(ray, def.position.x, def.position.y + ray_offset, + def.position.z, dir.x, dir.y, dir.z); + dContact contact[1]; + Vector3f pos = {0.0f, 0.0f, 0.0f}; + Vector3f vel = {0.0f, 0.0f, 0.0f}; + bool hit = false; + for (auto&& t : terrains_) { + dGeomID t_geom = t->geom(); + if (dCollide(ray, t_geom, 1, &contact[0].geom, sizeof(dContact))) { + pos = Vector3f(contact[0].geom.pos); + vel = Reflect(dir, Vector3f(contact[0].geom.normal)); + // bias direction up a bit.. this way it'll hopefully be less + // likely to point underground when we smash it down on the + // camera plane + vel.y += RandomFloat() * def.spread * 1.0f; + hit = true; + break; + } + } + if (!hit) { + // since dbias pushes us all in a direction away from a surface, + // nudge our start pos in the opposite dir a bit so we butt up + // against the surface more + pos = def.position + d_bias * RandomFloat() * -0.3f; + vel = dir; + } +#if BA_DEBUG_BUILD + g_debug_lines.emplace_back( + def.position + Vector3f(0, ray_offset, 0), + def.position + Vector3f(0, ray_offset, 0) + (dir * ray_len), + hit ? Vector3f(1, 0, 0) : Vector3f(0, 1, 0)); +#endif + + Vector3f to_cam = (cam_pos_ - pos).Normalized(); + + // Push the velocity towards the camera z plane to minimize + // artifacts from moving towards/away from cam. + Vector3f cam_component = to_cam * (vel.Dot(to_cam)); + vel -= 0.8f * cam_component; + + // Let's also push our pos towards the cam a wee bit so less is + // clipped. + pos += to_cam * 0.8f; + + // Now that we've got direction, assign random velocity. + vel = vel.Normalized() * (10.0f + RandomFloat() * 30.0f); + + { + auto* t = new Tendril(this); + t->type_ = def.tendril_type; + t->prev_pos_ = t->position_ = pos; + t->shadow_position_ = pos; + t->shading_flip_ = (vel.x > 0.0f); + t->wind_amt_ = 0.4f + RandomFloat() * 1.6f; + t->shadow_density_ = 1.0f; + t->velocity_ = vel; + if (def.tendril_type == BGDynamicsTendrilType::kThinSmoke) { + t->radius_ *= 0.2f; + t->side_spread_rate_ = 0.3f; + t->point_rand_scale_ = 0.3f; + t->tex_change_rate_ = 1.0f + RandomFloat() * 2.0f; + t->emit_rate_falloff_rate_ = 0.45f + RandomFloat() * 0.2f; + t->start_brightness_max_ = 0.82f; + t->start_brightness_min_ = 0.8f; + t->brightness_rand_ = 0.1f; + t->start_fade_scale_ = 0.1f + RandomFloat() * 0.2f; + t->glow_scale_ = 0.15f; + } else { + t->radius_ *= 0.7f + RandomFloat() * 0.2f; + t->side_spread_rate_ = 0.2f + 4.0f * RandomFloat(); + t->emit_rate_falloff_rate_ = 0.9f + RandomFloat() * 0.6f; + t->glow_scale_ = 1.0f; + } + tendrils_.push_back(t); + if (def.tendril_type == BGDynamicsTendrilType::kThinSmoke) { + tendril_count_thin_++; + } else { + tendril_count_thick_++; + } + } + } + dGeomDestroy(ray); + break; + } + case BGDynamicsEmitType::kFlagStand: { + float ray_len = 10.0f; + dGeomID ray = dCreateRay(nullptr, ray_len); + dGeomRaySetClosestHit(ray, true); + Vector3f dir(0.0f, -1.0f, 0.0f); + dGeomRaySet(ray, def.position.x, def.position.y, def.position.z, dir.x, + dir.y, dir.z); + dContact contact[1]; + for (auto&& t : terrains_) { + dGeomID t_geom = t->geom(); + if (dCollide(ray, t_geom, 1, &contact[0].geom, sizeof(dContact))) { + BGDynamicsEmission edef = def; + edef.chunk_type = BGDynamicsChunkType::kFlagStand; + edef.position = Vector3f(contact[0].geom.pos); + chunks_.push_back(new Chunk(this, edef, false, false)); + chunk_count_++; + break; + } + } + dGeomDestroy(ray); + break; + } + case BGDynamicsEmitType::kFairyDust: { + spark_particles_->Emit( + Vector3f(def.position.x + 0.9f * (RandomFloat() - 0.5f), + def.position.y + 0.9f * (RandomFloat() - 0.5f), + def.position.z + 0.9f * (RandomFloat() - 0.5f)), + 0.001f * def.velocity, 0.8f + 3.0f * +RandomFloat(), + 0.8f + 3.0f * RandomFloat(), 0.8f + 3.0f * RandomFloat(), 0, + -0.01f, // dlife + 0.05f + 0.05f * RandomFloat(), // size + -0.001f, // dsize + 5.0f // flicker intensity + ); // NOLINT(whitespace/parens) + break; + } + default: { + int t = static_cast(def.emit_type); + BA_LOG_ONCE("Invalid bg-dynamics emit type: " + std::to_string(t)); + break; + } + } +} + +void BGDynamicsServer::PushRemoveTerrainCall(CollideModelData* collide_model) { + PushCall([this, collide_model] { + assert(collide_model != nullptr); + bool found = false; + for (auto i = terrains_.begin(); i != terrains_.end(); ++i) { + if ((**i).GetCollideModel() == collide_model) { + found = true; + delete *i; + terrains_.erase(i); + break; + } + } + if (!found) { + throw Exception("invalid RemoveTerrainCall"); + } + + // Rebuild geom list from our present terrains. + std::vector geoms; + geoms.reserve(terrains_.size()); + for (auto&& i : terrains_) { + geoms.push_back(i->geom()); + } + height_cache_->SetGeoms(geoms); + collision_cache_->SetGeoms(geoms); + + // Clear existing stuff whenever this changes. + Clear(); + }); +} + +void BGDynamicsServer::PushAddShadowCall(BGDynamicsShadowData* shadow_data) { + PushCall([this, shadow_data] { + assert(InBGDynamicsThread()); + std::lock_guard lock(shadow_list_mutex_); + shadows_.push_back(shadow_data); + }); +} + +void BGDynamicsServer::PushRemoveShadowCall(BGDynamicsShadowData* shadow_data) { + PushCall([this, shadow_data] { + assert(InBGDynamicsThread()); + bool found = false; + { + std::lock_guard lock(shadow_list_mutex_); + for (auto i = shadows_.begin(); i != shadows_.end(); ++i) { + if ((*i) == shadow_data) { + found = true; + shadows_.erase(i); + break; + } + } + } + assert(found); + delete shadow_data; + }); +} + +void BGDynamicsServer::PushAddVolumeLightCall( + BGDynamicsVolumeLightData* volume_light_data) { + PushCall([this, volume_light_data] { + // Add to our internal list. + std::lock_guard lock(volume_light_list_mutex_); + volume_lights_.push_back(volume_light_data); + }); +} + +void BGDynamicsServer::PushRemoveVolumeLightCall( + BGDynamicsVolumeLightData* volume_light_data) { + PushCall([this, volume_light_data] { + // Remove from our list and kill. + bool found = false; + { + std::lock_guard lock(volume_light_list_mutex_); + for (auto i = volume_lights_.begin(); i != volume_lights_.end(); ++i) { + if ((*i) == volume_light_data) { + found = true; + volume_lights_.erase(i); + break; + } + } + } + assert(found); + delete volume_light_data; + }); +} + +void BGDynamicsServer::PushAddFuseCall(BGDynamicsFuseData* fuse_data) { + PushCall([this, fuse_data] { + std::lock_guard lock(fuse_list_mutex_); + fuses_.push_back(fuse_data); + }); +} + +void BGDynamicsServer::PushRemoveFuseCall(BGDynamicsFuseData* fuse_data) { + PushCall([this, fuse_data] { + bool found = false; + { + std::lock_guard lock(fuse_list_mutex_); + for (auto i = fuses_.begin(); i != fuses_.end(); i++) { + if ((*i) == fuse_data) { + found = true; + fuses_.erase(i); + break; + } + } + } + assert(found); + delete fuse_data; + }); +} + +void BGDynamicsServer::PushSetDebrisFrictionCall(float friction) { + PushCall([this, friction] { debris_friction_ = friction; }); +} + +void BGDynamicsServer::PushSetDebrisKillHeightCall(float height) { + PushCall([this, height] { debris_kill_height_ = height; }); +} + +auto BGDynamicsServer::CreateDrawSnapshot() -> BGDynamicsDrawSnapshot* { + assert(InBGDynamicsThread()); + + auto* ss = new BGDynamicsDrawSnapshot(); + + uint32_t rock_count = 0; + uint32_t ice_count = 0; + uint32_t slime_count = 0; + uint32_t metal_count = 0; + uint32_t spark_count = 0; + uint32_t splinter_count = 0; + uint32_t sweat_count = 0; + uint32_t flag_stand_count = 0; + + uint32_t shadow_max_count = 0; + uint32_t light_max_count = 0; + uint32_t shadow_drawn_count = 0; + uint32_t light_drawn_count = 0; + + for (auto&& i : chunks_) { + BGDynamicsChunkType t = i->type(); + switch (t) { + case BGDynamicsChunkType::kRock: + rock_count++; + break; + case BGDynamicsChunkType::kIce: + ice_count++; + break; + case BGDynamicsChunkType::kSlime: + slime_count++; + break; + case BGDynamicsChunkType::kMetal: + metal_count++; + break; + case BGDynamicsChunkType::kSpark: + spark_count++; + break; + case BGDynamicsChunkType::kSplinter: + splinter_count++; + break; + case BGDynamicsChunkType::kSweat: + sweat_count++; + break; + case BGDynamicsChunkType::kFlagStand: + flag_stand_count++; + break; + } + // tally shadow/lights + switch (t) { + case BGDynamicsChunkType::kFlagStand: + case BGDynamicsChunkType::kSweat: + break; // these have no shadows + case BGDynamicsChunkType::kIce: + case BGDynamicsChunkType::kSpark: + light_max_count++; + break; + default: + shadow_max_count++; + break; + } + } + + Matrix44f* c_rock = nullptr; + Matrix44f* c_ice = nullptr; + Matrix44f* c_slime = nullptr; + Matrix44f* c_metal = nullptr; + Matrix44f* c_spark = nullptr; + Matrix44f* c_splinter = nullptr; + Matrix44f* c_sweat = nullptr; + Matrix44f* c_flag_stand = nullptr; + + if (rock_count > 0) { + ss->rocks.resize(rock_count); + c_rock = ss->rocks.data(); + } + if (ice_count > 0) { + ss->ice.resize(ice_count); + c_ice = ss->ice.data(); + } + if (slime_count > 0) { + ss->slime.resize(slime_count); + c_slime = ss->slime.data(); + } + if (metal_count > 0) { + ss->metal.resize(metal_count); + c_metal = ss->metal.data(); + } + if (spark_count > 0) { + ss->sparks.resize(spark_count); + c_spark = ss->sparks.data(); + } + if (splinter_count > 0) { + ss->splinters.resize(splinter_count); + c_splinter = ss->splinters.data(); + } + if (sweat_count > 0) { + ss->sweats.resize(sweat_count); + c_sweat = ss->sweats.data(); + } + if (flag_stand_count > 0) { + ss->flag_stands.resize(flag_stand_count); + c_flag_stand = ss->flag_stands.data(); + } + + // Allocate buffers as if we're drawing *all* lights/shadows for chunks. + // We may prune this down. + uint16_t *s_index = nullptr, *l_index = nullptr; + VertexSprite *s_vertex = nullptr, *l_vertex = nullptr; + uint32_t s_vertex_index = 0, l_vertex_index = 0; + if (shadow_max_count > 0) { + auto* ibuf = Object::NewDeferred(shadow_max_count * 6); + + // Game thread is default owner; needs to be us until we hand it over. + ibuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->shadow_indices = Object::MakeRefCounted(ibuf); + s_index = &ss->shadow_indices->elements[0]; + auto* vbuf = + Object::NewDeferred(shadow_max_count * 4); + + // Game thread is default owner; needs to be us until we hand it over. + vbuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->shadow_vertices = Object::MakeRefCounted(vbuf); + s_vertex = &ss->shadow_vertices->elements[0]; + s_vertex_index = 0; + } + if (light_max_count > 0) { + auto* ibuf = Object::NewDeferred(light_max_count * 6); + + // Game thread is default owner; needs to be us until we hand it over. + ibuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->light_indices = Object::MakeRefCounted(ibuf); + l_index = &ss->light_indices->elements[0]; + auto* vbuf = + Object::NewDeferred(light_max_count * 4); + + // Game thread is default owner; needs to be us until we hand it over. + vbuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->light_vertices = Object::MakeRefCounted(vbuf); + l_vertex = &ss->light_vertices->elements[0]; + l_vertex_index = 0; + } + + Matrix44f* c{}; + + for (auto&& i : chunks_) { + BGDynamicsChunkType type = i->type(); + switch (type) { + case BGDynamicsChunkType::kRock: + c = c_rock; + break; + case BGDynamicsChunkType::kIce: + c = c_ice; + break; + case BGDynamicsChunkType::kSlime: + c = c_slime; + break; + case BGDynamicsChunkType::kMetal: + c = c_metal; + break; + case BGDynamicsChunkType::kSpark: + c = c_spark; + break; + case BGDynamicsChunkType::kSplinter: + c = c_splinter; + break; + case BGDynamicsChunkType::kSweat: + c = c_sweat; + break; + case BGDynamicsChunkType::kFlagStand: + c = c_flag_stand; + break; + } + + const float* s = i->size(); + if (i->dynamic()) { + dBodyID b = i->body(); + const dReal* p = dBodyGetPosition(b); + const dReal* r = dBodyGetRotation(b); + (*c).m[0] = r[0] * s[0]; // NOLINT: clang-tidy says possible null + (*c).m[1] = r[4] * s[0]; + (*c).m[2] = r[8] * s[0]; + (*c).m[3] = 0; + (*c).m[4] = r[1] * s[1]; + (*c).m[5] = r[5] * s[1]; + (*c).m[6] = r[9] * s[1]; + (*c).m[7] = 0; + (*c).m[8] = r[2] * s[2]; + (*c).m[9] = r[6] * s[2]; + (*c).m[10] = r[10] * s[2]; + (*c).m[11] = 0; + (*c).m[12] = p[0]; + (*c).m[13] = p[1]; + (*c).m[14] = p[2]; + (*c).m[15] = 1; + } else { + // NOLINTNEXTLINE: clang-tidy complaining of possible null here. + memcpy((*c).m, i->static_transform(), sizeof((*c))); + } + + // Shadow size is just average of our dimensions. + float shadow_size = (s[0] + s[1] + s[2]) * 0.3333f; + + // These are elongated so shadows are a bit big by default. + if (type == BGDynamicsChunkType::kSplinter) shadow_size *= 0.65f; + float flicker = i->flicker_; + float shadow_dist = i->shadow_dist_; + float life = std::min( + 1.0f, (static_cast(time_) - i->birth_time_) / i->lifespan_); + + // Shrink our matrix down over time. + switch (type) { + case BGDynamicsChunkType::kSpark: + case BGDynamicsChunkType::kSweat: { + float shrink_scale = (1.0f - life) * flicker; + Matrix44f* m = &(*c); + (*m) = Matrix44fScale(shrink_scale) * (*m); + break; + } + default: { + // Regular chunks shrink only when on the ground. + float sd = shadow_dist; + Matrix44f* m = &(*c); + if (sd < 1.0f && sd >= 0) { + float sink = -sd * life; + (*m) = (*m) * Matrix44fTranslate(0, sink, 0); + } + float shrink_scale = 1.0f - life; + (*m) = Matrix44fScale(shrink_scale) * (*m); + break; + } + } + + // Go ahead and build a buffer for our lights/shadows so when it comes + // time to draw we just have to upload it. + float shadow_scale_mult = 1.0f; + float max_shadow_scale = 2.3f; + float max_shadow_grow_dist = 2.0f; + float max_shadow_dist = 1.0f; + bool draw_shadow{}; + bool draw_light{}; + switch (type) { + case BGDynamicsChunkType::kIce: + case BGDynamicsChunkType::kSpark: { + draw_shadow = false; + draw_light = true; + shadow_scale_mult *= 8.0f; + break; + } + case BGDynamicsChunkType::kFlagStand: + case BGDynamicsChunkType::kSweat: + draw_shadow = false; + draw_light = false; + break; // These have no shadows. + default: { + draw_shadow = true; + draw_light = false; + } + } + + if (draw_shadow || draw_light) { + // Only draw light/shadow if we're within our max/min distances + // from the ground. + if (shadow_dist > -kShadowOccludeDistance + && shadow_dist < max_shadow_dist) { + float sd = shadow_dist; + + // Ok we'll draw this fella. + uint16_t* this_i{}; + VertexSprite* this_v{}; + uint32_t this_v_index{}; + if (draw_shadow) { + shadow_drawn_count++; + this_i = s_index; + this_v = s_vertex; + this_v_index = s_vertex_index; + s_index += 6; + s_vertex += 4; + s_vertex_index += 4; + } else { + light_drawn_count++; + assert(draw_light); + this_i = l_index; + this_v = l_vertex; + this_v_index = l_vertex_index; + l_index += 6; + l_vertex += 4; + l_vertex_index += 4; + } + + float* m = c->m; + + // As we get farther from the ground, our shadow gets bigger and + // softer. + float shadow_scale{}; + float density{}; + + // Negative shadow_dist means some object is in front of our + // shadow-caster. In this case lets keep our scale the same + // as it would have been at zero dist but fade our density + // out gradually as we become more deeply submerged. + if (sd <= 0.0f) { + shadow_scale = 1.0f; + density = 1.0f - std::min(1.0f, -sd / kShadowOccludeDistance); + } else { + // Normal non-submerged shadow. + shadow_scale = + 1.0f + + std::max(0.0f, std::min(1.0f, (sd / max_shadow_grow_dist)) + * (max_shadow_scale - 1.0f)); + density = 0.5f * g_graphics->GetShadowDensity(m[12], m[13], m[14]) + * (1.0f - (sd / max_shadow_dist)); + } + + // Sink down over the course of our lifespan if we + // know where the ground is. + float sink = 0.0f; + if (sd < 1.0f && sd >= 0.0f) { + sink = -sd * life; + } + shadow_scale *= (1.0f - life); + assert(shadow_scale >= 0.0f); + + // Drop our density as our shadow scale grows. + // Do this *after* this is used to modulate density. + shadow_scale *= shadow_scale_mult; + + // Add our 6 indices. + { + this_i[0] = static_cast(this_v_index); + this_i[1] = static_cast(this_v_index + 1); + this_i[2] = static_cast(this_v_index + 2); + this_i[3] = static_cast(this_v_index + 1); + this_i[4] = static_cast(this_v_index + 3); + this_i[5] = static_cast(this_v_index + 2); + } + + // Add our 4 verts. + this_v[0].uv[0] = 0; + this_v[0].uv[1] = 0; + this_v[1].uv[0] = 0; + this_v[1].uv[1] = 65535; + this_v[2].uv[0] = 65535; + this_v[2].uv[1] = 0; + this_v[3].uv[0] = 65535; + this_v[3].uv[1] = 65535; + + switch (type) { + case BGDynamicsChunkType::kIce: { + this_v[0].color[0] = this_v[1].color[0] = this_v[2].color[0] = + this_v[3].color[0] = 0.1f * density; + this_v[0].color[1] = this_v[1].color[1] = this_v[2].color[1] = + this_v[3].color[1] = 0.1f * density; + this_v[0].color[2] = this_v[1].color[2] = this_v[2].color[2] = + this_v[3].color[2] = 0.2f * density; + this_v[0].color[3] = this_v[1].color[3] = this_v[2].color[3] = + this_v[3].color[3] = 0.2f * density; + break; + } + case BGDynamicsChunkType::kSpark: { + this_v[0].color[0] = this_v[1].color[0] = this_v[2].color[0] = + this_v[3].color[0] = 0.3f * density; + this_v[0].color[1] = this_v[1].color[1] = this_v[2].color[1] = + this_v[3].color[1] = 0.12f * density; + this_v[0].color[2] = this_v[1].color[2] = this_v[2].color[2] = + this_v[3].color[2] = 0.10f * density; + this_v[0].color[3] = this_v[1].color[3] = this_v[2].color[3] = + this_v[3].color[3] = 0.1f * density; + break; + } + default: { + this_v[0].color[0] = this_v[1].color[0] = this_v[2].color[0] = + this_v[3].color[0] = 0.0f; + this_v[0].color[1] = this_v[1].color[1] = this_v[2].color[1] = + this_v[3].color[1] = 0.0f; + this_v[0].color[2] = this_v[1].color[2] = this_v[2].color[2] = + this_v[3].color[2] = 0.0f; + this_v[0].color[3] = this_v[1].color[3] = this_v[2].color[3] = + this_v[3].color[3] = 0.4f * density; + break; + } + } + this_v[0].position[0] = this_v[1].position[0] = this_v[2].position[0] = + this_v[3].position[0] = m[12]; + this_v[0].position[1] = this_v[1].position[1] = this_v[2].position[1] = + this_v[3].position[1] = m[13] + sink; + this_v[0].position[2] = this_v[1].position[2] = this_v[2].position[2] = + this_v[3].position[2] = m[14]; + this_v[0].size = this_v[1].size = this_v[2].size = this_v[3].size = + 2.8f * shadow_size * shadow_scale; + } + } + c++; + switch (type) { + case BGDynamicsChunkType::kRock: + c_rock = c; + break; + case BGDynamicsChunkType::kIce: + c_ice = c; + break; + case BGDynamicsChunkType::kSlime: + c_slime = c; + break; + case BGDynamicsChunkType::kMetal: + c_metal = c; + break; + case BGDynamicsChunkType::kSpark: + c_spark = c; + break; + case BGDynamicsChunkType::kSplinter: + c_splinter = c; + break; + case BGDynamicsChunkType::kSweat: + c_sweat = c; + break; + case BGDynamicsChunkType::kFlagStand: + c_flag_stand = c; + break; + } + } + if (shadow_max_count > 0) { + if (shadow_drawn_count == 0) { + // If we didn't actually draw *any*, completely kill our buffers. + ss->shadow_indices.Clear(); + ss->shadow_vertices.Clear(); + } else if (shadow_drawn_count != shadow_max_count) { + // Otherwise resize our buffers down to what we actually used. + assert(s_index - (&ss->shadow_indices->elements[0]) + == shadow_drawn_count * 6); + assert(s_vertex - (&ss->shadow_vertices->elements[0]) + == shadow_drawn_count * 4); + assert(ss->shadow_indices->elements.size() == shadow_max_count * 6); + ss->shadow_indices->elements.resize(shadow_drawn_count * 6); + assert(ss->shadow_vertices->elements.size() == shadow_max_count * 4); + ss->shadow_vertices->elements.resize(shadow_drawn_count * 4); + } else { + assert(s_index - (&ss->shadow_indices->elements[0]) + == shadow_max_count * 6); + assert(s_vertex - (&ss->shadow_vertices->elements[0]) + == shadow_max_count * 4); + } + } + if (light_max_count > 0) { + // If we didn't actually draw *any*, clear our buffers. + if (light_drawn_count == 0) { + ss->light_indices.Clear(); + ss->light_vertices.Clear(); + } else if (light_drawn_count != light_max_count) { + // Otherwise resize our buffers down to what we actually used. + assert(l_index - (&ss->light_indices->elements[0]) + == light_drawn_count * 6); + assert(l_vertex - (&ss->light_vertices->elements[0]) + == light_drawn_count * 4); + assert(ss->light_indices->elements.size() == light_max_count * 6); + ss->light_indices->elements.resize(light_drawn_count * 6); + assert(ss->light_vertices->elements.size() == light_max_count * 4); + ss->light_vertices->elements.resize(light_drawn_count * 4); + } else { + assert(l_index - (&ss->light_indices->elements[0]) + == light_max_count * 6); + assert(l_vertex - (&ss->light_vertices->elements[0]) + == light_max_count * 4); + } + } + + // Now add tendrils. + { + int smoke_slice_count = 0; + int smoke_index_count = 0; + int shadow_count = 0; + for (auto&& i : tendrils_) { + const Tendril& t(*i); + if (!t.has_updated_) continue; + int slice_count = + static_cast(t.slices_.size() + (t.emitting_ ? 1 : 0)); + if (slice_count > 1) { + shadow_count++; + smoke_index_count += (slice_count - 1) * 6; + smoke_slice_count += slice_count; + } + } + if (smoke_slice_count > 0) { + auto* ibuf = Object::NewDeferred(smoke_index_count); + + // Game thread is default owner; needs to be us until we hand it over. + ibuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->tendril_indices = Object::MakeRefCounted(ibuf); + uint16_t* index = &ss->tendril_indices->elements[0]; + auto* vbuf = + Object::NewDeferred(smoke_slice_count * 2); + + // Game thread is default owner; needs to be us until we hand it over. + vbuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->tendril_vertices = Object::MakeRefCounted(vbuf); + VertexSmokeFull* v = &ss->tendril_vertices->elements[0]; + ss->tendril_shadows.reserve(static_cast(shadow_count)); + int v_num = 0; + for (auto&& i : tendrils_) { + const Tendril& t(*i); + if (!t.has_updated_) { + continue; + } + int slice_count = + static_cast(t.slices_.size() + (t.emitting_ ? 1 : 0)); + if (slice_count < 2) { + continue; + } + ss->tendril_shadows.emplace_back(t.shadow_position_, t.shadow_density_); + for (auto&& slc : t.slices_) { + v->position[0] = slc.p1.p_distorted.x; + v->position[1] = slc.p1.p_distorted.y; + v->position[2] = slc.p1.p_distorted.z; + v->uv[0] = slc.p1.tex_coords[0]; + v->uv[1] = slc.p1.tex_coords[1]; + v->erode = static_cast(std::max( + 0, std::min(255, static_cast(255.0f * slc.p1.erode)))); + float fade = std::min(1.0f, slc.p1.fade); + v->color[0] = static_cast(std::max( + 0, std::min(255, static_cast(kSmokeGlow * slc.p1.glow_r)))); + v->color[1] = static_cast(std::max( + 0, std::min(255, static_cast(kSmokeGlow * slc.p1.glow_g)))); + v->color[2] = static_cast(std::max( + 0, std::min(255, static_cast(kSmokeGlow * slc.p1.glow_b)))); + v->color[3] = static_cast( + std::max(0, std::min(255, static_cast(255.0f * fade)))); + v->diffuse = static_cast(std::max( + 0, std::min(255, static_cast(255.0f * slc.p1.brightness)))); + v++; + v->position[0] = slc.p2.p_distorted.x; + v->position[1] = slc.p2.p_distorted.y; + v->position[2] = slc.p2.p_distorted.z; + v->uv[0] = slc.p2.tex_coords[0]; + v->uv[1] = slc.p2.tex_coords[1]; + v->erode = static_cast(std::max( + 0, std::min(255, static_cast(255.0f * slc.p2.erode)))); + fade = std::min(1.0f, slc.p2.fade); + v->color[0] = static_cast(std::max( + 0, + std::min(255, static_cast(kSmokeBaseGlow + + kSmokeGlow * slc.p2.glow_r)))); + v->color[1] = static_cast(std::max( + 0, + std::min(255, static_cast(kSmokeBaseGlow + + kSmokeGlow * slc.p2.glow_g)))); + v->color[2] = static_cast(std::max( + 0, + std::min(255, static_cast(kSmokeBaseGlow + + kSmokeGlow * slc.p2.glow_b)))); + v->color[3] = static_cast( + std::max(0, std::min(255, static_cast(255.0f * fade)))); + v->diffuse = static_cast(std::max( + 0, std::min(255, static_cast(255.0f * slc.p2.brightness)))); + v++; + } + + // Spit out the in-progress slice if the tendril is still emitting. + if (t.emitting_) { + v->position[0] = t.cur_slice_.p1.p_distorted.x; + v->position[1] = t.cur_slice_.p1.p_distorted.y; + v->position[2] = t.cur_slice_.p1.p_distorted.z; + v->uv[0] = t.cur_slice_.p1.tex_coords[0]; + v->uv[1] = t.cur_slice_.p1.tex_coords[1]; + v->erode = std::max( + 0, + std::min(255, static_cast(255.0f * t.cur_slice_.p1.erode))); + float fade = std::min(1.0f, t.cur_slice_.p1.fade); + v->color[0] = std::max( + 0, std::min(255, static_cast( + kSmokeBaseGlow + + kSmokeGlow * t.cur_slice_.p1.glow_r))); + v->color[1] = std::max( + 0, std::min(255, static_cast( + kSmokeBaseGlow + + kSmokeGlow * t.cur_slice_.p1.glow_g))); + v->color[2] = std::max( + 0, std::min(255, static_cast( + kSmokeBaseGlow + + kSmokeGlow * t.cur_slice_.p1.glow_b))); + v->color[3] = static_cast( + std::max(0, std::min(255, static_cast(255.0f * fade)))); + v->diffuse = std::max( + 0, std::min(255, static_cast(255.0f + * t.cur_slice_.p1.brightness))); + v++; + v->position[0] = t.cur_slice_.p2.p_distorted.x; + v->position[1] = t.cur_slice_.p2.p_distorted.y; + v->position[2] = t.cur_slice_.p2.p_distorted.z; + v->uv[0] = t.cur_slice_.p2.tex_coords[0]; + v->uv[1] = t.cur_slice_.p2.tex_coords[1]; + v->erode = std::max( + 0, + std::min(255, static_cast(255.0f * t.cur_slice_.p2.erode))); + fade = std::min(1.0f, t.cur_slice_.p2.fade); + v->color[0] = std::max( + 0, std::min(255, static_cast( + kSmokeBaseGlow + + kSmokeGlow * t.cur_slice_.p2.glow_r))); + v->color[1] = std::max( + 0, std::min(255, static_cast( + kSmokeBaseGlow + + kSmokeGlow * t.cur_slice_.p2.glow_g))); + v->color[2] = std::max( + 0, std::min(255, static_cast( + kSmokeBaseGlow + + kSmokeGlow * t.cur_slice_.p2.glow_b))); + v->color[3] = static_cast( + std::max(0, std::min(255, static_cast(255.0f * fade)))); + v->diffuse = std::max( + 0, std::min(255, static_cast(255.0f + * t.cur_slice_.p2.brightness))); + v++; + } + + // Now write the tri indices for this slice. + for (int j = 0; j < slice_count - 1; j++) { + *index++ = static_cast(v_num); + *index++ = static_cast(v_num + 1); + *index++ = static_cast(v_num + 2); + *index++ = static_cast(v_num + 2); + *index++ = static_cast(v_num + 1); + *index++ = static_cast(v_num + 3); + v_num += 2; + } + v_num += 2; + } + assert(ss->tendril_shadows.size() == shadow_count); + assert(index == (&ss->tendril_indices->elements[0]) + smoke_index_count); + assert(v + == (&ss->tendril_vertices->elements[0]) + (smoke_slice_count * 2)); + } + } + + // Now add fuses. + { + int fuse_count = 0; + for (auto&& i : fuses_) { + if (i->initial_position_set_) { + fuse_count++; + } + } + + if (fuse_count > 0) { + auto index_count = + static_cast(6 * (kFusePointCount - 1) * fuse_count); + auto vertex_count = + static_cast(2 * kFusePointCount * fuse_count); + + auto* ibuf = Object::NewDeferred(index_count); + + // Game thread is default owner; needs to be us until we hand it over. + ibuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->fuse_indices = Object::MakeRefCounted(ibuf); + auto* vbuf = + Object::NewDeferred(vertex_count); + + // Game thread is default owner; needs to be us until we hand it over. + vbuf->SetThreadOwnership(Object::ThreadOwnership::kNextReferencing); + ss->fuse_vertices = Object::MakeRefCounted(vbuf); + + uint16_t* index = &ss->fuse_indices->elements[0]; + VertexSimpleFull* v = &ss->fuse_vertices->elements[0]; + int p_num = 0; + uint16_t uv_inc = 65535 / (kFusePointCount - 1); + + for (auto&& i : fuses_) { + BGDynamicsFuseData& fuse(*i); + if (!fuse.initial_position_set_) continue; + + for (int j = 0; j < kFusePointCount - 1; j++) { + *index++ = static_cast(p_num); + *index++ = static_cast(p_num + 1); + *index++ = static_cast(p_num + 2); + + *index++ = static_cast(p_num + 2); + *index++ = static_cast(p_num + 1); + *index++ = static_cast(p_num + 3); + p_num += 2; + } + p_num += 2; + + uint16_t uv = 65535; + + Vector3f from_cam = (cam_pos_ - fuse.dyn_pts_[0]).Normalized() * 0.2f; + Vector3f side{}; + + // We push fuse points slightly towards cam so they're less likely to + // get occluded by stuff. + Vector3f cam_offs = {0.0f, 0.0f, 0.0f}; + + for (int j = 0; j < kFusePointCount; j++) { + if (j == 0) { + side = + Vector3f::Cross(from_cam, (fuse.dyn_pts_[1] - fuse.dyn_pts_[0])) + .Normalized() + * 0.03f; + } else { + side = Vector3f::Cross(from_cam, + (fuse.dyn_pts_[j] - fuse.dyn_pts_[j - 1])) + .Normalized() + * 0.03f; + } + + v->position[0] = fuse.dyn_pts_[j].x + side.x + cam_offs.x; + v->position[1] = fuse.dyn_pts_[j].y + side.y + cam_offs.y; + v->position[2] = fuse.dyn_pts_[j].z + side.z + cam_offs.z; + v->uv[0] = 0; + v->uv[1] = uv; + v++; + v->position[0] = fuse.dyn_pts_[j].x - side.x + cam_offs.x; + v->position[1] = fuse.dyn_pts_[j].y - side.y + cam_offs.y; + v->position[2] = fuse.dyn_pts_[j].z - side.z + cam_offs.z; + v->uv[0] = 65535; + v->uv[1] = uv; + v++; + uv -= uv_inc; + } + } + assert(v == &ss->fuse_vertices->elements[0] + vertex_count); + assert(index == &ss->fuse_indices->elements[0] + index_count); + } + } + + // Now sparks. + if (!spark_particles_) { + spark_particles_ = std::make_unique(); + } + spark_particles_->UpdateAndCreateSnapshot(&ss->spark_indices, + &ss->spark_vertices); + + return ss; +} // NOLINT (yes this should be shorter) + +void BGDynamicsServer::PushTooSlowCall() { + PushCall([this] { + if (chunk_count_ > 0 || tendril_count_thick_ > 0 + || tendril_count_thin_ > 0) { + // Ok lets kill a small percentage of our oldest chunks. + int killcount = static_cast(0.1f * chunks_.size()); + int killed = 0; + auto i = chunks_.begin(); + while (i != chunks_.end()) { + if (killed >= killcount) break; + auto i_next = i; + i_next++; + + // Kill it if its killable; otherwise move to next. + if ((**i).can_die()) { + delete (*i); + chunks_.erase(i); + chunk_count_--; + killed++; + } + i = i_next; + } + // ...and tendrils. + killcount = static_cast(0.2f * tendrils_.size()); + for (int j = 0; j < killcount; j++) { + Tendril* t = *tendrils_.begin(); + if (t->type_ == BGDynamicsTendrilType::kThinSmoke) { + tendril_count_thin_--; + } else { + tendril_count_thick_--; + } + assert(tendril_count_thin_ >= 0 && tendril_count_thick_ >= 0); + delete t; + tendrils_.erase(tendrils_.begin()); + } + } + }); +} + +void BGDynamicsServer::Step(StepData* step_data) { + assert(InBGDynamicsThread()); + assert(step_data); + + // Grab a ref to the raw StepData pointer we were passed.. we now own the + // data. + auto ref(Object::MakeRefCounted(step_data)); + + // Keep this in sync with the game thread's. + graphics_quality_ = g_graphics_server->graphics_quality_requested(); + + cam_pos_ = step_data->cam_pos; + + // Apply all step data sent to us for our entities. + for (auto&& i : step_data->shadow_step_data_) { + BGDynamicsShadowData* shadow{i.first}; + if (shadow) { + const ShadowStepData& shadow_step(i.second); + shadow->pos_worker = shadow_step.position; + } + } + for (auto&& i : step_data->volume_light_step_data_) { + BGDynamicsVolumeLightData* volume_light{i.first}; + if (volume_light) { + const VolumeLightStepData& volume_light_step(i.second); + volume_light->pos_worker = volume_light_step.pos; + volume_light->radius_worker = volume_light_step.radius; + volume_light->r_worker = volume_light_step.r; + volume_light->g_worker = volume_light_step.g; + volume_light->b_worker = volume_light_step.b; + } + } + for (auto&& i : step_data->fuse_step_data_) { + BGDynamicsFuseData* fuse{i.first}; + if (fuse) { + const FuseStepData& fuse_step(i.second); + fuse->transform_worker_ = fuse_step.transform; + fuse->have_transform_worker_ = fuse_step.have_transform; + fuse->length_worker_ = fuse_step.length; + } + } + + // Handle shadows first since they need to get back to the client + // as soon as possible. + UpdateShadows(); + + // Go ahead and run this step for all our existing stuff. + dJointGroupEmpty(ode_contact_group_); + UpdateFields(); + UpdateChunks(); + UpdateTendrils(); + UpdateFuses(); + + // Step the world. + dWorldQuickStep(ode_world_, kGameStepSeconds); + + // Now generate a snapshot of our state and send it to the game thread + // so they can draw us. + BGDynamicsDrawSnapshot* snapshot = CreateDrawSnapshot(); + g_game->PushCall([snapshot] { + snapshot->SetGameThreadOwnership(); + g_bg_dynamics->SetDrawSnapshot(snapshot); + }); + + time_ += kGameStepMilliseconds; // milliseconds per step + + // Give our collision cache a bit of processing time here and + // there to fill itself in slowly. + collision_cache_->Precalc(); + + // Job's done! + { + std::lock_guard lock(step_count_mutex_); + step_count_--; + } + assert(step_count_ >= 0); +} + +void BGDynamicsServer::PushStepCall(StepData* data) { + PushCall([this, data] { Step(data); }); +} + +void BGDynamicsServer::PushAddTerrainCall( + Object::Ref* collide_model) { + PushCall([this, collide_model] { + assert(InBGDynamicsThread()); + assert(collide_model != nullptr); + + // Make sure its loaded (might not be when we get it). + (**collide_model).Load(); + + // (the terrain now owns the ref pointer passed in) + terrains_.push_back(new Terrain(this, collide_model)); + + // Rebuild geom list from our present terrains. + std::vector geoms; + geoms.reserve(terrains_.size()); + for (auto&& i : terrains_) { + geoms.push_back(i->geom()); + } + height_cache_->SetGeoms(geoms); + collision_cache_->SetGeoms(geoms); + + // Reset our chunks whenever anything changes. + Clear(); + }); +} + +void BGDynamicsServer::UpdateFields() { + auto i = fields_.begin(); + while (i != fields_.end()) { + Field& f(**i); + + // First off, kill this field if its time has come. + { + bool kill = false; + if (static_cast(time_ - f.birth_time()) > f.lifespan()) { + kill = true; + } + if (kill) { + auto i_next = i; + i_next++; + delete *i; + fields_.erase(i); + i = i_next; + continue; + } + } + + // Update its distortion amount based on age (get an age in 0-1). + float age = static_cast(time() - f.birth_time()) / f.lifespan(); + + float time_scale = 1.3f; + float start_mag = 0.0f; + float suck_mag = -0.4f; + float suck_end_time = 0.05f * time_scale; + float bulge_mag = 0.7f; + float bulge_end_time = 0.2f * time_scale; + float suck_2_mag = -0.05f; + float suck_2_end_time = 0.4f * time_scale; + float end_mag = 0.0f; + + // Ramp negative from 0 to 0.3. + if (age < suck_end_time) { + f.set_amt(start_mag + + (suck_mag - start_mag) + * Utils::SmoothStep(0.0f, suck_end_time, age)); + } else if (age < bulge_end_time) { + f.set_amt(suck_mag + + (bulge_mag - suck_mag) + * Utils::SmoothStep(suck_end_time, bulge_end_time, age)); + } else if (age < suck_2_end_time) { + f.set_amt( + bulge_mag + + (suck_2_mag - bulge_mag) + * Utils::SmoothStep(bulge_end_time, suck_2_end_time, age)); + } else { + f.set_amt(suck_2_mag + + (end_mag - suck_2_mag) + * Utils::SmoothStep(suck_2_end_time, 1.0f, age)); + } + f.set_amt(f.amt() * f.mag()); + i++; + } +} + +void BGDynamicsServer::TerrainCollideCallback(void* data, dGeomID geom1, + dGeomID geom2) { + auto* dyn = static_cast(data); + dContact contact[kMaxBGDynamicsContacts]; // max contacts per box-box + + if (int numc = dCollide(geom1, geom2, kMaxBGDynamicsContacts, + &contact[0].geom, sizeof(dContact))) { + BGDynamicsChunkType type = dyn->cb_type_; + dBodyID body = dyn->cb_body_; + float f_mult = type == BGDynamicsChunkType::kIce ? 0.04f : 1.0f; + + // Slime chunks just slow down on collisions. + if (type == BGDynamicsChunkType::kSlime) { + const dReal* vel = dBodyGetLinearVel(body); + dBodySetLinearVel(body, vel[0] * 0.1f, vel[1] * 0.1f, vel[2] * 0.1f); + vel = dBodyGetAngularVel(body); + dBodySetAngularVel(body, vel[0] * 0.8f, vel[1] * 0.8f, vel[2] * 0.8f); + } else { + // Only look at some contacts. + // If we restrict the number of contacts returned we seem to get + // lopsided contacts and failing collisions, but if we just increment + // through all contacts at > 1 it seems to work ok. + int contact_incr = 1; + if (numc > 4) { + contact_incr = 2; + if (numc > 9) { + contact_incr = 3; + if (numc > 14) { + contact_incr = 4; + } + } + } + + for (int i = 0; i < numc; i += contact_incr) { + // NOLINTNEXTLINE + contact[i].surface.mode = dContactBounce | dContactSoftCFM + | dContactSoftERP | dContactApprox1; + contact[i].surface.mu2 = 0; + contact[i].surface.bounce_vel = 0.1f; + contact[i].surface.mu = 0.5f * dyn->debris_friction_ * f_mult; + contact[i].surface.bounce = 0.4f; + contact[i].surface.soft_cfm = dyn->cb_cfm_; + contact[i].surface.soft_erp = dyn->cb_erp_; + dJointID constraint = dJointCreateContact( + dyn->ode_world_, dyn->ode_contact_group_, contact + i); + dJointAttach(constraint, body, nullptr); + } + } + } +} + +void BGDynamicsServer::UpdateChunks() { + dReal stiffness = 1000.0f; + dReal damping = 10.0f; + dReal erp{}, cfm{}; + CalcERPCFM(stiffness, damping, &erp, &cfm); + cb_erp_ = erp; + cb_cfm_ = cfm; + + // We don't use a space since we don't want everything to intercollide; + // rather we explicitly test everything against our terrain objects; + // this keeps things simple. + + for (auto i = chunks_.begin(); i != chunks_.end();) { + Chunk& c(**i); + + // first off, kill this chunk if its time has come + { + bool kill = false; + if (static_cast(time_ - c.birth_time_) > c.lifespan_) { + kill = true; + } + + // If we've fallen off the level. + if (c.dynamic()) { + const dReal* pos = dGeomGetPosition(c.geom_); + if (pos[1] < debris_kill_height_) kill = true; + } + if (kill) { + auto i_next = i; + i_next++; + delete *i; + chunks_.erase(i); + chunk_count_--; + assert(chunk_count_ >= 0); + i = i_next; + continue; + } + } + BGDynamicsChunkType type = c.type(); + + // Some spark-specific stuff. + if (type == BGDynamicsChunkType::kSpark) { + if (RandomFloat() < 0.1f) { + float fs = c.flicker_scale_; + c.flicker_ = fs * RandomFloat() + (1.0f - fs) * 0.8f; + } + } else if (type == BGDynamicsChunkType::kSweat) { + // Some sweat-specific stuff. + if (RandomFloat() < 0.25f) { + c.flicker_ = RandomFloat(); + } + } + + // Most stuff only applies to dynamic chunks. + if (c.dynamic()) { + dGeomID geom = c.geom(); + dBodyID body = c.body(); + if (type == BGDynamicsChunkType::kSlime) { + // add some drag on slime chunks + const dReal* vel = dBodyGetLinearVel(body); + dBodySetLinearVel(body, vel[0] * 0.99f, vel[1] * 0.99f, vel[2] * 0.99f); + } + if (type == BGDynamicsChunkType::kSpark) { + // Add some drag on spark. + const dReal* vel = dBodyGetLinearVel(body); + + // Also add a bit of upward to counteract gravity. + float vel_squared = vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]; + + // Slow down fast if we're going fast. + // Otherwise slow down more gradually. + if (vel_squared > 14) { + dBodySetLinearVel(body, vel[0] * 0.94f, 0.13f + vel[1] * 0.94f, + vel[2] * 0.94f); + } else { + dBodySetLinearVel(body, vel[0] * 0.99f, 0.07f + vel[1] * 0.99f, + vel[2] * 0.99f); + } + } else if (type == BGDynamicsChunkType::kSweat) { + // Add some drag on sweat. + const dReal* vel = dBodyGetLinearVel(body); + + // Also add a bit of upward to counteract gravity. + float vel_squared = vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]; + + // Slow down fast if we're going fast. + // Otherwise slow down more gradually. + if (vel_squared > 14) { + dBodySetLinearVel(body, vel[0] * 0.93f, 0.13f + vel[1] * 0.93f, + vel[2] * 0.93f); + } else { + dBodySetLinearVel(body, vel[0] * 0.97f, 0.11f + vel[1] * 0.97f, + vel[2] * 0.97f); + } + } else if (type == BGDynamicsChunkType::kSplinter) { + // Add some drag on slime chunks. + const dReal* vel = dBodyGetLinearVel(body); + dBodySetLinearVel(body, vel[0] * 0.995f, vel[1] * 0.995f, + vel[2] * 0.995f); + vel = dBodyGetAngularVel(body); + dBodySetAngularVel(body, vel[0] * 0.995f, vel[1] * 0.995f, + vel[2] * 0.995f); + } else { + const dReal* vel = dBodyGetAngularVel(body); + if (vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2] > 500) { + // Drastic slowdown for super fast stuff. + dBodySetAngularVel(body, vel[0] * 0.75f, vel[1] * 0.75f, + vel[2] * 0.75f); + } else { + dBodySetAngularVel(body, vel[0] * 0.995f, vel[1] * 0.995f, + vel[2] * 0.995f); + } + } + + // If this chunk is disabled, we don't need to do anything + // (since no terrain ever moves to wake us back up). + // Also we skip sweat since that neither casts shadows or collides. + if (dBodyIsEnabled(body) && type != BGDynamicsChunkType::kSweat) { + // Move our shadow ray to where we are and reset our shadow length. + const dReal* pos = dGeomGetPosition(geom); + // Update shadow dist. + c.shadow_dist_ = pos[1] - height_cache_->Sample(Vector3f(pos)); + cb_type_ = type; + cb_body_ = body; + collision_cache_->CollideAgainstGeom(geom, this, + TerrainCollideCallback); + // Tell it to update any tendril it might have. + c.UpdateTendril(); + } + } + i++; + } +} + +void BGDynamicsServer::UpdateShadows() { + // First go through and calculate distances for all shadows. + for (auto&& s : shadows_) { + float shadow_dist = s->pos_worker.y - height_cache_->Sample(s->pos_worker); + + // Update scale/density based on these values. + // Negative shadow_dist means some object is in front of our + // shadow-caster. In this case lets keep our scale the same as it would + // have been at zero dist but fade our density out gradually as we become + // more deeply submerged. + if (shadow_dist < 0.0f) { + s->shadow_scale_worker = 1.0f; + s->shadow_density_worker = + 1.0f - std::min(1.0f, -shadow_dist / kShadowOccludeDistance); + } else { + // Normal non-submerged shadow. + float max_scale = 1.0f + (kMaxShadowScale - 1.0f) * s->height_scaling; + float scale = + 1.0f + + std::max(0.0f, std::min(1.0f, (shadow_dist / kMaxShadowGrowDist)) + * (max_scale - 1.0f)); + s->shadow_scale_worker = scale; + s->shadow_density_worker = + 1.0f + - 0.7f + * std::max(0.0f, + std::min(1.0f, (shadow_dist / kMaxShadowGrowDist))); + } + } + + // Now plop this back onto the client side all at once. + { + BA_DEBUG_TIME_CHECK_BEGIN(bg_dynamic_shadow_list_lock); + { + std::lock_guard lock(shadow_list_mutex_); + for (auto&& s : shadows_) { + s->UpdateClientData(); + } + } + BA_DEBUG_TIME_CHECK_END(bg_dynamic_shadow_list_lock, 10); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/bg/bg_dynamics_server.h b/src/ballistica/dynamics/bg/bg_dynamics_server.h new file mode 100644 index 00000000..d8d23ee6 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_server.h @@ -0,0 +1,170 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SERVER_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SERVER_H_ + +#include +#include +#include +#include + +#include "ballistica/core/module.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/math/vector3f.h" +#include "ode/ode.h" + +namespace ballistica { + +class BGDynamicsServer : public Module { + public: + struct Particle { + float x; + float y; + float z; + // Note that velocities here are in units-per-step (avoids a mult). + float vx; + float vy; + float vz; + float r; + float g; + float b; + float a; + float life; + float d_life; + float flicker; + float flicker_scale; + float size; + float d_size; + }; + + class ParticleSet { + public: + std::vector particles[2]; + int current_set; + ParticleSet() : current_set(0) {} + void Emit(const Vector3f& pos, const Vector3f& vel, float r, float g, + float b, float a, float dlife, float size, float d_size, + float flicker); + void UpdateAndCreateSnapshot(Object::Ref* index_buffer, + Object::Ref* buffer); + }; + struct ShadowStepData { + Vector3f position; + }; + struct VolumeLightStepData { + Vector3f pos{}; + float radius{}; + float r{}; + float g{}; + float b{}; + }; + struct FuseStepData { + Matrix44f transform{}; + bool have_transform{}; + float length{}; + }; + class StepData : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kBGDynamics; + } + Vector3f cam_pos{0.0f, 0.0f, 0.0f}; + + // Basically a bit list of pointers to the current set of + // shadows/volumes/fuses and client values for them. + std::vector > + shadow_step_data_; + std::vector > + volume_light_step_data_; + std::vector > fuse_step_data_; + }; + + explicit BGDynamicsServer(Thread* thread); + ~BGDynamicsServer() override; + auto time() const -> uint32_t { return time_; } + auto graphics_quality() const -> GraphicsQuality { return graphics_quality_; } + + void PushAddVolumeLightCall(BGDynamicsVolumeLightData* volume_light_data); + void PushRemoveVolumeLightCall(BGDynamicsVolumeLightData* volume_light_data); + void PushAddFuseCall(BGDynamicsFuseData* fuse_data); + void PushRemoveFuseCall(BGDynamicsFuseData* fuse_data); + void PushAddShadowCall(BGDynamicsShadowData* shadow_data); + void PushRemoveShadowCall(BGDynamicsShadowData* shadow_data); + void PushAddTerrainCall(Object::Ref* collide_model); + void PushRemoveTerrainCall(CollideModelData* collide_model); + void PushEmitCall(const BGDynamicsEmission& def); + auto spark_particles() const -> ParticleSet* { + return spark_particles_.get(); + } + auto step_count() const -> int { return step_count_; } + + private: + class Terrain; + class Chunk; + class Field; + class Tendril; + class TendrilController; + + static void TerrainCollideCallback(void* data, dGeomID o1, dGeomID o2); + + void Emit(const BGDynamicsEmission& def); + void PushStepCall(StepData* data); + void Step(StepData* data); + void PushTooSlowCall(); + void PushSetDebrisFrictionCall(float friction); + void PushSetDebrisKillHeightCall(float height); + void Clear(); + void UpdateFields(); + void UpdateChunks(); + void UpdateTendrils(); + void UpdateFuses(); + void UpdateShadows(); + auto CreateDrawSnapshot() -> BGDynamicsDrawSnapshot*; + BGDynamicsChunkType cb_type_ = BGDynamicsChunkType::kRock; + dBodyID cb_body_{}; + float cb_cfm_{0.0f}; + float cb_erp_{0.0f}; + + // FIXME: We're assuming at the moment + // that collide-models passed to this thread never get deallocated. ew. + MeshIndexedSmokeFull* tendrils_smoke_mesh_{nullptr}; + MeshIndexedSimpleFull* fuses_mesh_{nullptr}; + SpriteMesh* shadows_mesh_{nullptr}; + SpriteMesh* lights_mesh_{nullptr}; + SpriteMesh* sparks_mesh_{nullptr}; + int miss_count_{0}; + Vector3f cam_pos_{0.0f, 0.0f, 0.0f}; + std::vector terrains_; + std::vector shadows_; + std::vector volume_lights_; + std::vector fuses_; + dWorldID ode_world_{nullptr}; + dJointGroupID ode_contact_group_{nullptr}; + + // Held by the dynamics module when changing any of these lists. + // Should be grabbed by a client if they need to access the list safely. + std::mutex shadow_list_mutex_; + std::mutex volume_light_list_mutex_; + std::mutex fuse_list_mutex_; + int step_count_{0}; + std::mutex step_count_mutex_; + std::unique_ptr spark_particles_{nullptr}; + std::list chunks_; + std::list fields_; + std::list tendrils_; + int tendril_count_thick_{0}; + int tendril_count_thin_{0}; + int chunk_count_{0}; + std::unique_ptr height_cache_; + std::unique_ptr collision_cache_; + uint32_t time_{0}; // Internal time step. + float debris_friction_{1.0f}; + float debris_kill_height_{-50.0f}; + GraphicsQuality graphics_quality_{GraphicsQuality::kLow}; + friend class BGDynamics; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SERVER_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_shadow.cc b/src/ballistica/dynamics/bg/bg_dynamics_shadow.cc new file mode 100644 index 00000000..e7d736bf --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_shadow.cc @@ -0,0 +1,53 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/bg/bg_dynamics_shadow.h" + +#include "ballistica/dynamics/bg/bg_dynamics_server.h" +#include "ballistica/dynamics/bg/bg_dynamics_shadow_data.h" +#include "ballistica/graphics/graphics.h" + +namespace ballistica { + +BGDynamicsShadow::BGDynamicsShadow(float height_scaling) { + assert(InGameThread()); + + // allocate our shadow data.. we'll pass this to the BGDynamics thread + // and it'll then own it + data_ = new BGDynamicsShadowData(height_scaling); + assert(g_bg_dynamics_server); + g_bg_dynamics_server->PushAddShadowCall(data_); +} + +BGDynamicsShadow::~BGDynamicsShadow() { + assert(InGameThread()); + assert(g_bg_dynamics_server); + + // let the data know the client side is dead + // so we're no longer included in step messages + // (since by the time the worker gets the the data will be gone) + data_->client_dead = true; + g_bg_dynamics_server->PushRemoveShadowCall(data_); +} + +void BGDynamicsShadow::SetPosition(const Vector3f& pos) { + assert(InGameThread()); + data_->pos_client = pos; +} + +auto BGDynamicsShadow::GetPosition() const -> const Vector3f& { + assert(InGameThread()); + return data_->pos_client; +} + +void BGDynamicsShadow::GetValues(float* scale, float* density) const { + assert(InGameThread()); + assert(scale); + assert(density); + + *scale = data_->shadow_scale_client; + *density = data_->shadow_density_client + * g_graphics->GetShadowDensity( + data_->pos_client.x, data_->pos_client.y, data_->pos_client.z); +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/bg/bg_dynamics_shadow.h b/src/ballistica/dynamics/bg/bg_dynamics_shadow.h new file mode 100644 index 00000000..e50ffb9f --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_shadow.h @@ -0,0 +1,36 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SHADOW_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SHADOW_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" + +namespace ballistica { + +// A utility class for client use which uses ray-testing and +// BG collision terrains to create a variably dense/soft shadow +// based on how high it is above terrain. +// Clients should give their current position information to the shadow +// at update time and then at render time it'll be all set to go. +// (shadows update in the bg dynamics stepping process) +class BGDynamicsShadow { + public: + explicit BGDynamicsShadow(float height_scaling = 1.0f); + ~BGDynamicsShadow(); + void SetPosition(const Vector3f& pos); + auto GetPosition() const -> const Vector3f&; + + // Return scale and density for the shadow. + // this also takes into account the height based shadow density + // (g_graphics->GetShadowDensity()) so you don't have to. + void GetValues(float* scale, float* density) const; + + private: + BGDynamicsShadowData* data_{}; + BA_DISALLOW_CLASS_COPIES(BGDynamicsShadow); +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SHADOW_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_shadow_data.h b/src/ballistica/dynamics/bg/bg_dynamics_shadow_data.h new file mode 100644 index 00000000..1ec313ea --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_shadow_data.h @@ -0,0 +1,46 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SHADOW_DATA_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SHADOW_DATA_H_ + +namespace ballistica { + +struct BGDynamicsShadowData { + explicit BGDynamicsShadowData(float height_scaling) + : height_scaling(height_scaling) {} + + void UpdateClientData() { + // Copy data over with a bit of smoothing + // (so our shadow doesn't jump instantly when we go over and edge/etc.) + float smoothing{0.8f}; + shadow_scale_client = smoothing * shadow_scale_client + + (1.0f - smoothing) * shadow_scale_worker; + shadow_density_client = smoothing * shadow_density_client + + (1.0f - smoothing) * shadow_density_worker; + } + + void Synchronize() { pos_worker = pos_client; } + + bool client_dead{}; + float height_scaling{}; + + // For use by worker: + + // position value owned by the client (write-only). + Vector3f pos_client{0.0f, 0.0f, 0.0f}; + + // Position value owned by the worker thread (read-only). + Vector3f pos_worker{0.0f, 0.0f, 0.0f}; + + // Calculated values owned by the worker thread (write-only). + float shadow_scale_worker{1.0f}; + float shadow_density_worker{0.0f}; + + // Result values owned by the client (read-only). + float shadow_scale_client{1.0f}; + float shadow_density_client{0.0f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_SHADOW_DATA_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_volume_light.cc b/src/ballistica/dynamics/bg/bg_dynamics_volume_light.cc new file mode 100644 index 00000000..768b2d3b --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_volume_light.cc @@ -0,0 +1,47 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/bg/bg_dynamics_volume_light.h" + +#include "ballistica/dynamics/bg/bg_dynamics_volume_light_data.h" + +namespace ballistica { + +BGDynamicsVolumeLight::BGDynamicsVolumeLight() { + assert(InGameThread()); + // allocate our light data.. we'll pass this to the BGDynamics thread + // and it'll then own it + data_ = new BGDynamicsVolumeLightData(); + assert(g_bg_dynamics_server); + g_bg_dynamics_server->PushAddVolumeLightCall(data_); +} + +BGDynamicsVolumeLight::~BGDynamicsVolumeLight() { + assert(InGameThread()); + + // let the data know the client side is dead + // so we're no longer included in step messages + // (since by the time the worker gets the the data will be gone) + data_->client_dead = true; + + assert(g_bg_dynamics_server); + g_bg_dynamics_server->PushRemoveVolumeLightCall(data_); +} + +void BGDynamicsVolumeLight::SetPosition(const Vector3f& pos) { + assert(InGameThread()); + data_->pos_client = pos; +} + +void BGDynamicsVolumeLight::SetRadius(float radius) { + assert(InGameThread()); + data_->radius_client = radius; +} + +void BGDynamicsVolumeLight::SetColor(float r, float g, float b) { + assert(InGameThread()); + data_->r_client = r; + data_->g_client = g; + data_->b_client = b; +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/bg/bg_dynamics_volume_light.h b/src/ballistica/dynamics/bg/bg_dynamics_volume_light.h new file mode 100644 index 00000000..20ebc2db --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_volume_light.h @@ -0,0 +1,25 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_VOLUME_LIGHT_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_VOLUME_LIGHT_H_ + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Client-controlled lights for bg smoke. +class BGDynamicsVolumeLight : public Object { + public: + BGDynamicsVolumeLight(); + ~BGDynamicsVolumeLight() override; + void SetPosition(const Vector3f& pos); + void SetRadius(float radius); + void SetColor(float r, float g, float b); + + private: + BGDynamicsVolumeLightData* data_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_VOLUME_LIGHT_H_ diff --git a/src/ballistica/dynamics/bg/bg_dynamics_volume_light_data.h b/src/ballistica/dynamics/bg/bg_dynamics_volume_light_data.h new file mode 100644 index 00000000..61e31941 --- /dev/null +++ b/src/ballistica/dynamics/bg/bg_dynamics_volume_light_data.h @@ -0,0 +1,30 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_VOLUME_LIGHT_DATA_H_ +#define BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_VOLUME_LIGHT_DATA_H_ + +#include "ballistica/dynamics/bg/bg_dynamics_server.h" + +namespace ballistica { + +struct BGDynamicsVolumeLightData { + bool client_dead{}; + + // Position value owned by the client. + Vector3f pos_client{0.0f, 0.0f, 0.0f}; + float radius_client{}; + float r_client{}; + float g_client{}; + float b_client{}; + + // Position value owned by the worker thread. + Vector3f pos_worker{0.0f, 0.0f, 0.0f}; + float radius_worker{}; + float r_worker{}; + float g_worker{}; + float b_worker{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_BG_BG_DYNAMICS_VOLUME_LIGHT_DATA_H_ diff --git a/src/ballistica/dynamics/collision.h b/src/ballistica/dynamics/collision.h new file mode 100644 index 00000000..8f93fc47 --- /dev/null +++ b/src/ballistica/dynamics/collision.h @@ -0,0 +1,44 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_COLLISION_H_ +#define BALLISTICA_DYNAMICS_COLLISION_H_ + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ode/ode.h" + +namespace ballistica { + +// Stores info about an occurring collision. +// Note than just because a collision exists between two parts doesn't mean +// they're physically colliding in the simulation. It is just a shortcut to +// determine what behavior, if any, exists between two parts which are currently +// overlapping in the simulation. +class Collision : public Object { + public: + explicit Collision(Scene* scene) : src_context(scene), dst_context(scene) {} + int claim_count{}; // Used when checking for out-of-date-ness. + bool collide{true}; + int contact_count{}; // Current number of contacts. + float depth{}; // Current collision depth. + float x{}; + float y{}; + float z{}; + float impact{}; + float skid{}; + float roll{}; + Object::WeakRef src_part; // Ref to make sure still alive. + Object::WeakRef dst_part; // Ref to make sure still alive. + int body_id_1{-1}; + int body_id_2{-1}; + std::vector collide_feedback; + MaterialContext src_context; + MaterialContext dst_context; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_COLLISION_H_ diff --git a/src/ballistica/dynamics/collision_cache.cc b/src/ballistica/dynamics/collision_cache.cc new file mode 100644 index 00000000..63ab02b3 --- /dev/null +++ b/src/ballistica/dynamics/collision_cache.cc @@ -0,0 +1,355 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/collision_cache.h" + +#include + +#include "ballistica/graphics/component/simple_component.h" +#include "ode/ode_collision_kernel.h" +#include "ode/ode_collision_space_internal.h" +#include "ode/ode_collision_util.h" +#include "ode/ode_objects_private.h" + +namespace ballistica { + +CollisionCache::CollisionCache() + : dirty_(true), + shadow_ray_(nullptr), + x_min_(-1), + x_max_(1), + y_min_(-1), + y_max_(1), + z_min_(-1), + z_max_(1) { + grid_width_ = 1; + grid_height_ = 1; + test_box_ = dCreateBox(nullptr, 1, 1, 1); +} + +CollisionCache::~CollisionCache() { + if (shadow_ray_) { + dGeomDestroy(shadow_ray_); + } + dGeomDestroy(test_box_); +} + +void CollisionCache::SetGeoms(const std::vector& geoms) { + dirty_ = true; + geoms_ = geoms; +} + +void CollisionCache::Draw(FrameDef* frame_def) { + if (cells_.empty()) { + return; + } + SimpleComponent c(frame_def->beauty_pass()); + c.SetTransparent(true); + c.SetColor(0, 1, 0, 0.1f); + float cell_width = (1.0f / static_cast(grid_width_)); + float cell_height = (1.0f / static_cast(grid_height_)); + c.PushTransform(); + c.Translate((x_min_ + x_max_) * 0.5f, 0, (z_min_ + z_max_) * 0.5f); + c.Scale(x_max_ - x_min_, 1, z_max_ - z_min_); + c.PushTransform(); + c.Scale(1, 0.01f, 1); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + c.Translate(-0.5f + 0.5f * cell_width, 0, -0.5f + 0.5f * cell_height); + for (int x = 0; x < grid_width_; x++) { + for (int z = 0; z < grid_height_; z++) { + int cell_index = z * grid_width_ + x; + assert(cell_index >= 0 && cell_index < static_cast(glow_.size())); + if (glow_[cell_index]) { + c.SetColor(1, 1, 1, 0.2f); + } else { + c.SetColor(0, 0, 1, 0.2f); + } + c.PushTransform(); + c.Translate(static_cast(x) / static_cast(grid_width_), + cells_[cell_index].height_confirmed_collide_, + static_cast(z) / static_cast(grid_height_)); + c.Scale(0.95f * cell_width, 0.01f, 0.95f * cell_height); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + if (glow_[cell_index]) { + c.SetColor(1, 1, 1, 0.2f); + } else { + c.SetColor(1, 0, 0, 0.2f); + } + c.PushTransform(); + c.Translate(static_cast(x) / static_cast(grid_width_), + cells_[cell_index].height_confirmed_empty_, + static_cast(z) / static_cast(grid_height_)); + c.Scale(0.95f * cell_width, 0.01f, 0.95f * cell_height); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + glow_[cell_index] = 0; + } + } + c.PopTransform(); + c.Submit(); + + if (explicit_bool(false)) { + SimpleComponent c2(frame_def->overlay_3d_pass()); + c2.SetTransparent(true); + c2.SetColor(1, 0, 0, 1.0f); + float cell_width2 = (1.0f / static_cast(grid_width_)); + float cell_height2 = (1.0f / static_cast(grid_height_)); + c2.PushTransform(); + c2.Translate((x_min_ + x_max_) * 0.5f, 0, (z_min_ + z_max_) * 0.5f); + c2.Scale(x_max_ - x_min_, 1, z_max_ - z_min_); + c2.PushTransform(); + c2.Scale(1, 0.01f, 1); + c2.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c2.PopTransform(); + c2.Translate(-0.5f + 0.5f * cell_width2, 0, -0.5f + 0.5f * cell_height2); + for (int x = 0; x < grid_width_; x++) { + for (int z = 0; z < grid_height_; z++) { + int cell_index = z * grid_width_ + x; + assert(cell_index >= 0 && cell_index < static_cast(glow_.size())); + if (glow_[cell_index]) { + c2.SetColor(1, 1, 1, 0.2f); + } else { + c2.SetColor(1, 0, 0, 0.2f); + } + c2.PushTransform(); + c2.Translate(static_cast(x) / static_cast(grid_width_), + cells_[cell_index].height_confirmed_empty_, + static_cast(z) / static_cast(grid_height_)); + c2.Scale(0.95f * cell_width2, 0.01f, 0.95f * cell_height2); + c2.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c2.PopTransform(); + if (glow_[cell_index]) { + c2.SetColor(1, 1, 1, 0.2f); + } else { + c2.SetColor(0, 0, 1, 0.2f); + } + c2.PushTransform(); + c2.Translate(static_cast(x) / static_cast(grid_width_), + cells_[cell_index].height_confirmed_collide_, + static_cast(z) / static_cast(grid_height_)); + c2.Scale(0.95f * cell_width2, 0.01f, 0.95f * cell_height2); + c2.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c2.PopTransform(); + + glow_[cell_index] = 0; + } + } + c2.PopTransform(); + c2.Submit(); + } +} + +void CollisionCache::Precalc() { + Update(); + + if (precalc_index_ >= cells_.size()) { + precalc_index_ = 0; // Loop. + } + + auto x = static_cast(precalc_index_ % grid_width_); + auto z = static_cast(precalc_index_ / grid_width_); + assert(x >= 0 && x < grid_width_); + assert(z >= 0 && z < grid_height_); + TestCell(precalc_index_++, x, z); +} + +void CollisionCache::CollideAgainstGeom(dGeomID g1, void* data, + dNearCallback* callback) { + // Update bounds, test for quick out against our height map, + // and proceed to a full test on a positive result. + g1->recomputeAABB(); + + if (dirty_) Update(); + + // Do a quick out if its not within our cache bounds at all. + dReal* bounds1 = g1->aabb; + if (bounds1[0] > x_max_ || bounds1[1] < x_min_ || bounds1[2] > y_max_ + || bounds1[3] < y_min_ || bounds1[4] > z_max_ || bounds1[5] < z_min_) { + return; + } + + int x_min = static_cast(static_cast(grid_width_) + * ((g1->aabb[0] - x_min_) / (x_max_ - x_min_))); + x_min = std::max(0, std::min(grid_width_ - 1, x_min)); + int z_min = static_cast(static_cast(grid_height_) + * ((g1->aabb[4] - z_min_) / (z_max_ - z_min_))); + z_min = std::max(0, std::min(grid_height_ - 1, z_min)); + + int x_max = static_cast(static_cast(grid_width_) + * ((g1->aabb[1] - x_min_) / (x_max_ - x_min_))); + x_max = std::max(0, std::min(grid_width_ - 1, x_max)); + int z_max = static_cast(static_cast(grid_height_) + * ((g1->aabb[5] - z_min_) / (z_max_ - z_min_))); + z_max = std::max(0, std::min(grid_height_ - 1, z_max)); + + // If all cells are confirmed empty to the bottom of our AABB, we're done. + bool possible_hit = false; + for (int z = z_min; z <= z_max; z++) { + auto cell_index = static_cast(z * grid_width_); + for (int x = x_min; x <= x_max; x++) { + if (bounds1[2] <= cells_[cell_index + x].height_confirmed_empty_) { + possible_hit = true; + break; + } + } + if (possible_hit) { + break; + } + } + if (!possible_hit) { + return; + } + + // Ok looks like we need to run collisions. + int t_count = static_cast(geoms_.size()); + for (int i = 0; i < t_count; i++) { + dxGeom* g2 = geoms_[i]; + collideAABBs(g1, g2, data, callback); + } + + // While we're here, lets run one pass of tests on these cells to zero in on + // the actual collide/empty cutoff. + for (int z = z_min; z <= z_max; z++) { + int base_index = z * grid_width_; + for (int x = x_min; x <= x_max; x++) { + int cell_index = base_index + x; + assert(cell_index >= 0); + TestCell(static_cast(cell_index), x, z); + } + } +} + +void CollisionCache::TestCell(size_t cell_index, int x, int z) { + int t_count = static_cast(geoms_.size()); + float top = cells_[cell_index].height_confirmed_empty_; + + // Midway point. + float bottom = (cells_[cell_index].height_confirmed_collide_ + top) * 0.5f; + float height = top - bottom; + + // Don't wanna test with too thin a box.. may miss stuff. + float box_height = std::max(1.0f, height); + if (height > 0.01f) { + glow_[cell_index] = 1; + + dGeomSetPosition(test_box_, + x_min_ + cell_width_ * (0.5f + static_cast(x)), + bottom + box_height * 0.5f, + z_min_ + cell_height_ * (0.5f + static_cast(z))); + dGeomBoxSetLengths(test_box_, cell_width_, box_height, cell_height_); + + dContact contact[1]; + bool collided = false; + + // See if we collide with *any* terrain. + for (int i = 0; i < t_count; i++) { + if (dCollide(test_box_, geoms_[i], 1, &contact[0].geom, + sizeof(dContact))) { + collided = true; + break; + } + } + + // Ok, we collided. We can move our confirmed collide floor up to + // our bottom. + if (collided) { + cells_[cell_index].height_confirmed_collide_ = + std::max(cells_[cell_index].height_confirmed_collide_, bottom); + } else { + // Didn't collide. Move confirmed empty region to our bottom. + cells_[cell_index].height_confirmed_empty_ = + std::min(cells_[cell_index].height_confirmed_empty_, bottom); + } + // This shouldn' happen but just in case. + cells_[cell_index].height_confirmed_empty_ = + std::max(cells_[cell_index].height_confirmed_empty_, + cells_[cell_index].height_confirmed_collide_); + } +} + +void CollisionCache::CollideAgainstSpace(dSpaceID space, void* data, + dNearCallback* callback) { + // We handle our own testing against trimeshes so we can bring our fancy + // caching into play. + if (!geoms_.empty()) { + // Intersect all geoms in the space against all terrains. + for (dxGeom* g1 = space->first; g1; g1 = g1->next) { + CollideAgainstGeom(g1, data, callback); + } + } +} + +void CollisionCache::Update() { + if (!dirty_) { + return; + } + + // Calc our full dimensions. + if (geoms_.empty()) { + x_min_ = -1; + x_max_ = 1; + y_min_ = -1; + y_max_ = 1; + z_min_ = -1; + z_max_ = 1; + } else { + auto i = geoms_.begin(); + dReal aabb[6]; + dGeomGetAABB(*i, aabb); + float x = aabb[0]; + float X = aabb[1]; + float y = aabb[2]; + float Y = aabb[3]; + float z = aabb[4]; + float Z = aabb[5]; + for (i++; i != geoms_.end(); i++) { + dGeomGetAABB(*i, aabb); + if (aabb[0] < x) x = aabb[0]; + if (aabb[1] > X) X = aabb[1]; + if (aabb[2] < y) y = aabb[2]; + if (aabb[3] > Y) Y = aabb[3]; + if (aabb[4] < z) z = aabb[4]; + if (aabb[5] > Z) Z = aabb[5]; + } + float buffer = 0.3f; + x_min_ = x - buffer; + x_max_ = X + buffer; + y_min_ = y - buffer; + y_max_ = Y + buffer; + z_min_ = z - buffer; + z_max_ = Z + buffer; + } + + // (Re)create our shadow ray with the new dimensions. + if (shadow_ray_) { + dGeomDestroy(shadow_ray_); + } + shadow_ray_ = dCreateRay(nullptr, y_max_ - y_min_); + dGeomRaySet(shadow_ray_, 0, 0, 0, 0, -1, 0); // aim straight down + dGeomRaySetClosestHit(shadow_ray_, true); + + // Update/clear our cell grid based on our dimensions. + grid_width_ = + std::max(1, std::min(256, static_cast((x_max_ - x_min_) * 1.3f))); + grid_height_ = + std::max(1, std::min(256, static_cast((z_max_ - z_min_) * 1.3f))); + + assert(grid_width_ >= 0 && grid_height_ >= 0); + auto cell_count = static_cast(grid_width_ * grid_height_); + cells_.clear(); + cells_.resize(cell_count); + for (uint32_t i = 0; i < cell_count; i++) { + cells_[i].height_confirmed_empty_ = y_max_; + cells_[i].height_confirmed_collide_ = y_min_; + } + cell_width_ = (x_max_ - x_min_) / static_cast(grid_width_); + cell_height_ = (z_max_ - z_min_) / static_cast(grid_height_); + glow_.clear(); + glow_.resize(cell_count); + memset(&glow_[0], 0, cell_count); + precalc_index_ = 0; + dirty_ = false; +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/collision_cache.h b/src/ballistica/dynamics/collision_cache.h new file mode 100644 index 00000000..dffb3c5c --- /dev/null +++ b/src/ballistica/dynamics/collision_cache.h @@ -0,0 +1,58 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_COLLISION_CACHE_H_ +#define BALLISTICA_DYNAMICS_COLLISION_CACHE_H_ + +#include + +#include "ballistica/ballistica.h" +#include "ode/ode.h" + +namespace ballistica { + +// Given geoms, creates/samples a height map on the fly +// which can be used for very fast AABB tests against the geometry. +class CollisionCache { + public: + CollisionCache(); + ~CollisionCache(); + + // If returns true, the provided AABB *may* intersect the geoms. + void SetGeoms(const std::vector& geoms); + void Draw(FrameDef* f); // For debugging. + void CollideAgainstSpace(dSpaceID space, void* data, dNearCallback* callback); + void CollideAgainstGeom(dGeomID geom, void* data, dNearCallback* callback); + + // Call this periodically (once per cycle or so) to slowly fill in + // the cache so there's less to do during spurts of activity; + void Precalc(); + + private: + void TestCell(size_t cell_index, int x, int z); + void Update(); + uint32_t precalc_index_{}; + std::vector geoms_; + struct Cell { + float height_confirmed_empty_; + float height_confirmed_collide_; + }; + std::vector cells_; + std::vector glow_; + bool dirty_; + dGeomID shadow_ray_; + dGeomID test_box_; + int grid_width_; + int grid_height_; + float cell_width_{}; + float cell_height_{}; + float x_min_; + float x_max_; + float y_min_; + float y_max_; + float z_min_; + float z_max_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_COLLISION_CACHE_H_ diff --git a/src/ballistica/dynamics/dynamics.cc b/src/ballistica/dynamics/dynamics.cc new file mode 100644 index 00000000..a8837a3e --- /dev/null +++ b/src/ballistica/dynamics/dynamics.cc @@ -0,0 +1,1114 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/dynamics.h" + +#include +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_source.h" +#include "ballistica/dynamics/collision.h" +#include "ballistica/dynamics/collision_cache.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/dynamics/part.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/scene/scene.h" +#include "ode/ode_collision_kernel.h" +#include "ode/ode_collision_util.h" + +namespace ballistica { + +// Max contacts for rigid body collisions. +// TODO(ericf): Probably a good idea to accept more than this +// and then randomly discard some - otherwise +// we may get contacts only at one end of an object, etc. +#define MAX_CONTACTS 20 + +// Given two parts, returns true if part1 is major in +// the storage order. +static auto IsInStoreOrder(int64_t node1, int part1, int64_t node2, int part2) + -> bool { + assert(node1 >= 0 && part1 >= 0 && node2 >= 0 && part2 >= 0); + + // Node with smaller id is primary search node. + if (node1 < node2) { + return true; + } else if (node1 > node2) { + return false; + } else { + // If nodes are same, classify by part id. + // If part ids are the same, it doesnt matter. + return (part1 < part2); + } +} + +// Modified version of dBodyGetPointVel - instead of applying the body's +// linear and angular velocities, we apply a provided force and torque +// to get its local equivalent. +void do_dBodyGetLocalFeedback(dBodyID b, dReal px, dReal py, dReal pz, + dReal lvx, dReal lvy, dReal lvz, dReal avx, + dReal avy, dReal avz, dVector3 result) { + dAASSERT(b); + dVector3 p; + p[0] = px - b->pos[0]; + p[1] = py - b->pos[1]; + p[2] = pz - b->pos[2]; + p[3] = 0; + result[0] = lvx; + result[1] = lvy; + result[2] = lvz; + dReal avel[4]; + avel[0] = avx; + avel[1] = avy; + avel[2] = avz; + avel[3] = 0; + dCROSS(result, +=, avel, p); +} + +// Stores info about a collision needing a reset +// (used when parts change materials). +class Dynamics::CollisionReset { + public: + int node1; + int node2; + int part1; + int part2; + CollisionReset(int node1_in, int part1_in, int node2_in, int part2_in) + : node1(node1_in), node2(node2_in), part1(part1_in), part2(part2_in) {} +}; + +class Dynamics::CollisionEvent { + public: + Object::Ref action; + Object::Ref collision; + Object::WeakRef node1; // first event node + Object::WeakRef node2; // second event node + CollisionEvent(Node* node1_in, Node* node2_in, + const Object::Ref& action_in, + const Object::Ref& collision_in) + : node1(node1_in), + node2(node2_in), + action(action_in), + collision(collision_in) {} +}; + +Dynamics::Dynamics(Scene* scene_in) + : scene_(scene_in), collision_cache_(new CollisionCache()) { + ResetODE(); +} + +Dynamics::~Dynamics() { + if (in_process_) { + Log("Error: Dynamics going down within Process() call;" + " should not happen."); + } + ShutdownODE(); +} + +void Dynamics::Draw(FrameDef* frame_def) { + // draw collisions if desired.. +#if BA_DEBUG_BUILD && 0 + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetColor(1, 0, 0); + c.SetTransparent(true); + for (auto&& i : debug_collisions_) { + c.PushTransform(); + c.Translate(i.x(), i.y(), i.z()); + c.scaleUniform(0.05f); + c.DrawModel(g_media->GetModel(Media::BOX_MODEL)); + c.PopTransform(); + } + c.Submit(); + debug_collisions_.clear(); +#endif // BA_DEBUG_BUILD +} + +void Dynamics::ResetCollision(int64_t node1, int part1, int64_t node2, + int part2) { + // Make sure this isn't called while we're in the middle of processing + // collides (it shouldn't be possible but just in case). + BA_PRECONDITION(!processing_collisions_); + + // We don't actually do any resetting here; we just store a notice that + // these two parts should be separated and the notice is sent out at + // collide process time. + collision_resets_.emplace_back(node1, part1, node2, part2); +} + +void Dynamics::AddTrimesh(dGeomID g) { + assert(dGeomGetClass(g) == dTriMeshClass); + trimeshes_.push_back(g); + + // Do a one-time bbox update; these never move so this should cover us. + g->recomputeAABB(); + g->gflags &= (~(GEOM_DIRTY | GEOM_AABB_BAD)); // NOLINT + + // Update our collision cache. + collision_cache_->SetGeoms(trimeshes_); +} + +void Dynamics::RemoveTrimesh(dGeomID g) { + assert(dGeomGetClass(g) == dTriMeshClass); + for (auto i = trimeshes_.begin(); i != trimeshes_.end(); i++) { + if ((*i) == g) { + trimeshes_.erase(i); + + // Update our collision cache. + collision_cache_->SetGeoms(trimeshes_); + return; + } + } + throw Exception("trimesh not found"); +} + +class Dynamics::SrcPartCollideMap { + public: + std::map > dst_part_collisions; +}; + +class Dynamics::DstNodeCollideMap { + public: + std::map src_parts; + int collideDisabled; + DstNodeCollideMap() : collideDisabled(0) {} + ~DstNodeCollideMap() = default; +}; + +class Dynamics::SrcNodeCollideMap { + public: + std::map dst_nodes; +}; + +auto Dynamics::AreColliding(const Part& p1_in, const Part& p2_in) -> bool { + const Part* p1; + const Part* p2; + if (IsInStoreOrder(p1_in.node()->id(), p1_in.id(), p2_in.node()->id(), + p2_in.id())) { + p1 = &p1_in; + p2 = &p2_in; + } else { + p1 = &p2_in; + p2 = &p1_in; + } + + // Go down the hierarchy until we either find a missing level or + // find the collision. + auto i = node_collisions_.find(p1->node()->id()); + if (i != node_collisions_.end()) { + auto j = i->second.dst_nodes.find(p2->node()->id()); + if (j != i->second.dst_nodes.end()) { + auto k = j->second.src_parts.find(p1->id()); + if (k != j->second.src_parts.end()) { + auto l = k->second.dst_part_collisions.find(p2->id()); + if (l != k->second.dst_part_collisions.end()) return true; + } + } + } + return false; +} + +auto Dynamics::GetCollision(Part* p1_in, Part* p2_in, MaterialContext** cc1, + MaterialContext** cc2) -> Collision* { + Part* p1; + Part* p2; + + if (IsInStoreOrder(p1_in->node()->id(), p1_in->id(), p2_in->node()->id(), + p2_in->id())) { + p1 = p1_in; + p2 = p2_in; + } else { + p1 = p2_in; + p2 = p1_in; + } + + std::pair >::iterator, bool> i = + node_collisions_[p1->node()->id()] + .dst_nodes[p2->node()->id()] + .src_parts[p1->id()] + .dst_part_collisions.insert( + std::make_pair(p2->id(), Object::Ref())); + + Collision* new_collision; + + // If it didnt exist, go ahead and set up the collision. + if (i.second) { + i.first->second = Object::New(scene_); + new_collision = i.first->second.get(); + } else { + new_collision = nullptr; + } + + (*cc1) = &i.first->second->src_context; + (*cc2) = &i.first->second->dst_context; + + // Continue setting it up. + if (new_collision) { + new_collision->src_part = p1; + new_collision->dst_part = p2; + + // Init contexts with parts' defaults. + (*cc1)->collide = p1->default_collides(); + (*cc2)->collide = p2->default_collides(); + + // Apply each part's materials to its context. + p1->ApplyMaterials(*cc1, p1, p2); + p2->ApplyMaterials(*cc2, p2, p1); + + // If either disabled collisions between these two nodes, store that. + DstNodeCollideMap* dncm = + &node_collisions_[p1->node()->id()].dst_nodes[p2->node()->id()]; + if (!(*cc1)->node_collide || !(*cc2)->node_collide) { + dncm->collideDisabled = true; + } + + // Don't collide if either context doesnt want us to or if the nodes + // aren't colliding (unless either context wants to ignore node + // collision status). + new_collision->collide = + ((*cc1)->collide && (*cc2)->collide + && (!dncm->collideDisabled || !(*cc1)->use_node_collide + || !(*cc2)->use_node_collide)); + + // If theres a physical collision involved, inform the parts + // so they can keep track of who they're touching. + if (new_collision->collide) { + bool physical = (*cc1)->physical && (*cc2)->physical; + p1->SetCollidingWith(p2->node()->id(), p2->id(), true, physical); + if (p1 != p2) { + p2->SetCollidingWith(p1->node()->id(), p1->id(), true, physical); + } + + // Also add all new-collide events to the global list + // (to be executed after all contacts are found). + for (auto& connect_action : (*cc1)->connect_actions) + collision_events_.emplace_back(p1->node(), p2->node(), connect_action, + Object::Ref(new_collision)); + for (auto& connect_action : (*cc2)->connect_actions) + collision_events_.emplace_back(p2->node(), p1->node(), connect_action, + Object::Ref(new_collision)); + } + } + + // Regardless, set it as claimed so we know its current. + i.first->second->claim_count++; + + return &(*(i.first->second)); +} + +void Dynamics::HandleDisconnect( + const std::map::iterator& + i, + const std::map::iterator& + j, + const std::map::iterator& k, + const std::map >::iterator& l) { + // Handle disconnect equivalents if they were colliding. + if (l->second->collide) { + // Add the contexts' disconnect commands to be executed. + for (auto m = l->second->src_context.disconnect_actions.begin(); + m != l->second->src_context.disconnect_actions.end(); m++) { + Part* src_part = l->second->src_part.get(); + Part* dst_part = l->second->dst_part.get(); + collision_events_.emplace_back(src_part ? src_part->node() : nullptr, + dst_part ? dst_part->node() : nullptr, *m, + l->second); + } + + for (auto m = l->second->dst_context.disconnect_actions.begin(); + m != l->second->dst_context.disconnect_actions.end(); m++) { + Part* src_part = l->second->src_part.get(); + Part* dst_part = l->second->dst_part.get(); + collision_events_.emplace_back(dst_part ? dst_part->node() : nullptr, + src_part ? src_part->node() : nullptr, *m, + l->second); + } + + // Now see if either of the two parts involved still exist and if they do, + // tell them they're no longer colliding with the other. + bool physical = + l->second->src_context.physical && l->second->dst_context.physical; + Part* p1 = l->second->dst_part.get(); + Part* p2 = l->second->src_part.get(); + if (p1) { + assert(p1 == l->second->dst_part.get()); + p1->SetCollidingWith(i->first, k->first, false, physical); // NOLINT + } + if (p2) { + assert(p2 == l->second->src_part.get()); + } + if (p2 && (p2 != p1)) { + p2->SetCollidingWith(j->first, l->first, false, physical); // NOLINT + } + } + + // Remove this particular collision. + k->second.dst_part_collisions.erase(l); +} + +void Dynamics::ProcessCollisions() { + processing_collisions_ = true; + + collision_count_ = 0; + + // First handle our explicitly reset collisions. + // For each reset request, we check if the surfaces are colliding and if so + // we separate them and add their separation commands to our to-do list. + if (!collision_resets_.empty()) { + for (auto& collision_reset : collision_resets_) { + int n1, n2; + int p1, p2; + + if (IsInStoreOrder(collision_reset.node1, collision_reset.part1, + collision_reset.node2, collision_reset.part2)) { + n1 = collision_reset.node1; + p1 = collision_reset.part1; + n2 = collision_reset.node2; + p2 = collision_reset.part2; + } else { + n1 = collision_reset.node2; + p1 = collision_reset.part2; + n2 = collision_reset.node1; + p2 = collision_reset.part1; + } + + // Go down the hierarchy until we either find a missing level or + // find the collision to reset. + { + auto i = node_collisions_.find(n1); + if (i != node_collisions_.end()) { + auto j = i->second.dst_nodes.find(n2); + if (j != i->second.dst_nodes.end()) { + auto k = j->second.src_parts.find(p1); + if (k != j->second.src_parts.end()) { + auto l = k->second.dst_part_collisions.find(p2); + if (l != k->second.dst_part_collisions.end()) { + // They were colliding - separate them. + HandleDisconnect(i, j, k, l); + } + + // Erase if none left. + if (k->second.dst_part_collisions.empty()) { + j->second.src_parts.erase(k); + } + } + + // Erase if none left. + if (j->second.src_parts.empty()) i->second.dst_nodes.erase(j); + } + + // Erase if none left. + if (i->second.dst_nodes.empty()) node_collisions_.erase(i); + } + } + } + collision_resets_.clear(); + } + + // Reset our claim counts. When we run collision tests, claim counts + // will be incremented for things that are still in contact. + for (auto& node_collision : node_collisions_) { + for (auto& dst_node : node_collision.second.dst_nodes) { + for (auto& src_part : dst_node.second.src_parts) { + for (auto& dst_part_collision : src_part.second.dst_part_collisions) { + dst_part_collision.second->claim_count = 0; + } + } + } + } + + // Process all standard collisions. This will trigger our callback which + // do the real work (add collisions to list, store commands to be + // called, etc). + dSpaceCollide(ode_space_, this, &DoCollideCallback); + + // Collide our trimeshes against everything. + collision_cache_->CollideAgainstSpace(ode_space_, this, &DoCollideCallback); + + // Do a bit of precalc each cycle. + collision_cache_->Precalc(); + + // Now go through our list of currently-colliding stuff, + // setting parts' currently-colliding-with lists + // based on current info, + // removing unclaimed collisions and empty groups. + std::map::iterator i_next; + std::map::iterator j_next; + std::map::iterator k_next; + std::map >::iterator l_next; + for (auto i = node_collisions_.begin(); i != node_collisions_.end(); + i = i_next) { + i_next = i; + i_next++; + for (auto j = i->second.dst_nodes.begin(); j != i->second.dst_nodes.end(); + j = j_next) { + j_next = j; + j_next++; + for (auto k = j->second.src_parts.begin(); k != j->second.src_parts.end(); + k = k_next) { + k_next = k; + k_next++; + for (auto l = k->second.dst_part_collisions.begin(); + l != k->second.dst_part_collisions.end(); l = l_next) { + l_next = l; + l_next++; + + // Not claimed; separating. + if (!l->second->claim_count) { + HandleDisconnect(i, j, k, l); + } + } + if (k->second.dst_part_collisions.empty()) { + j->second.src_parts.erase(k); + } + } + if (j->second.src_parts.empty()) { + i->second.dst_nodes.erase(j); + } + } + if (i->second.dst_nodes.empty()) { + node_collisions_.erase(i); + } + } + + // We're now done processing collisions - its now safe to reset + // collisions, etc. since we're no longer going through the lists. + processing_collisions_ = false; + + // Execute all events that we built up due to collisions. + for (auto&& i : collision_events_) { + active_collision_ = i.collision.get(); + active_collide_src_node_ = i.node1; + active_collide_dst_node_ = i.node2; + i.action->Execute(i.node1.get(), i.node2.get(), scene_); + } + active_collision_ = nullptr; + collision_events_.clear(); +} + +void Dynamics::process() { + in_process_ = true; + real_time_ = GetRealTime(); // Update this once so we can recycle results. + ProcessCollisions(); + dWorldQuickStep(ode_world_, kGameStepSeconds); + dJointGroupEmpty(ode_contact_group_); + in_process_ = false; +} + +void Dynamics::DoCollideCallback(void* data, dGeomID o1, dGeomID o2) { + auto* d = static_cast(data); + d->CollideCallback(o1, o2); +} + +// Run collisions for everything. Store any callbacks that will need to be made +// and run them after all collision constraints are made. +// This way we know all bodies and their associated nodes, etc are valid +// throughout collision processing. +void Dynamics::CollideCallback(dGeomID o1, dGeomID o2) { + dBodyID b1 = dGeomGetBody(o1); + dBodyID b2 = dGeomGetBody(o2); + + auto* r1 = static_cast(dGeomGetData(o1)); + auto* r2 = static_cast(dGeomGetData(o2)); + assert(r1 && r2); + + // If both of these guys are either terrain (a trimesh) or an inactive body, + // we can skip actually testing for a collision. + if ((dGeomGetClass(o1) == dTriMeshClass && b2 && !dBodyIsEnabled(b2)) + || (dGeomGetClass(o2) == dTriMeshClass && b1 && !dBodyIsEnabled(b1))) { + // We do, however, need to poke any existing collision so a disconnect event + // doesn't occur if we were colliding. + Part* p1_in = r1->part(); + Part* p2_in = r2->part(); + assert(p1_in && p2_in); + Part* p1; + Part* p2; + + if (IsInStoreOrder(p1_in->node()->id(), p1_in->id(), p2_in->node()->id(), + p2_in->id())) { + p1 = p1_in; + p2 = p2_in; + } else { + p1 = p2_in; + p2 = p1_in; + } + auto i = node_collisions_.find(p1->node()->id()); + if (i != node_collisions_.end()) { + auto j = i->second.dst_nodes.find(p2->node()->id()); + if (j != i->second.dst_nodes.end()) { + auto k = j->second.src_parts.find(p1->id()); + if (k != j->second.src_parts.end()) { + auto l = k->second.dst_part_collisions.find(p2->id()); + if (l != k->second.dst_part_collisions.end()) { +#pragma clang diagnostic push +#pragma ide diagnostic ignored "UnusedValue" + l->second->claim_count++; +#pragma clang diagnostic pop + } + } + } + } + return; + } + + // Check their overall types to count out some basics + // (landscapes never collide against landscapes, etc). + if (!((r1->collide_type() & r2->collide_mask()) + && (r2->collide_type() & r1->collide_mask()))) { // NOLINT + return; + } + + Part* p1 = r1->part(); + Part* p2 = r2->part(); + assert(p1 && p2); + + // Pre-filter collisions. + if (!(p1->node()->PreFilterCollision(r1, r2) + && p2->node()->PreFilterCollision(r2, r1))) { + return; + } + + // Perhaps an optimization could be to avoid collision testing + // if we're certain two materials will never result in a collision? + // I don't think calculating full material-states before each collision + // detection test would be economical but if there's a simple way to know + // they'll never collide. + dContact contact[MAX_CONTACTS]; // up to MAX_CONTACTS contacts per pair + if (int numc = + dCollide(o1, o2, MAX_CONTACTS, &contact[0].geom, sizeof(dContact))) { + MaterialContext* cc1; + MaterialContext* cc2; + + // Create or acquire a collision. + Collision* c = GetCollision(p1, p2, &cc1, &cc2); + + // If theres no physical collision between these two suckers we're done. + if (!c->collide) { + return; + } + + // Store body IDs for use in callback messages. + // There may be more than one body ID per part-on-part contact + // but we just keep one at the moment. + c->body_id_1 = r1->id(); + c->body_id_2 = r2->id(); + + // Get average depth for all contacts. + if (numc > 0) { + float d = 0; + for (int i = 0; i < numc; i++) { + d += contact[i].geom.depth; + } + c->depth = d / static_cast(numc); + } + + // Get average position for all contacts. + float apx = 0; + float apy = 0; + float apz = 0; + if (numc > 0) { + for (int i = 0; i < numc; i++) { + apx += contact[i].geom.pos[0]; + apy += contact[i].geom.pos[1]; + apz += contact[i].geom.pos[2]; + } + auto fnumc = static_cast(numc); + apx /= fnumc; + apy /= fnumc; + apz /= fnumc; + } + c->x = apx; + c->y = apy; + c->z = apz; + + // If theres an impact sound, skid sound, or roll sound attached to this + // collision, calculate applicable values. + // Impact is based on the component of the vector (force x relative + // velocity) that is parallel to the collision normal. + // Skid is the component tangential to the collision normal. + // Roll is based on tangential velocity multiplied by parallel force. + bool get_feedback_for_these_collisions = false; + + if (cc1->complex_sound || cc2->complex_sound) { + millisecs_t real_time = real_time_; + + // Its possible that we have more than one set of colliding things + // that resolve to the same collision record + // (multiple bodies in the same part, etc). + // However we can only calc feedback for the first one we come across + // (there's only one feedback buffer in the Collision). + if (c->claim_count == 1) { + get_feedback_for_these_collisions = true; + } + + dVector3 an; + an[0] = an[1] = an[2] = 0; + dVector3 b1v; + dVector3 b2v; + dVector3 b1cv; + dVector3 b2cv; + + // Get average collide normal for all contacts. + { + if (numc > 0) { + for (int i = 0; i < numc; i++) { + an[0] += contact[i].geom.normal[0]; + an[1] += contact[i].geom.normal[1]; + an[2] += contact[i].geom.normal[2]; + } + auto fnumc = static_cast(numc); + an[0] /= fnumc; + an[1] /= fnumc; + an[2] /= fnumc; + } + + const dReal* v; + + // Get body velocities at the avg contact point in global coords. + if (b1) { + v = dBodyGetLinearVel(b1); + b1cv[0] = v[0]; + b1cv[1] = v[1]; + b1cv[2] = v[2]; + dBodyGetPointVel(b1, apx, apy, apz, b1v); + } else { + b1cv[0] = b1cv[1] = b1cv[2] = 0; + b1v[0] = b1v[1] = b1v[2] = 0; + } + if (b2) { + v = dBodyGetLinearVel(b2); + b2cv[0] = v[0]; + b2cv[1] = v[1]; + b2cv[2] = v[2]; + dBodyGetPointVel(b2, apx, apy, apz, b2v); + } else { + b2cv[0] = b2cv[1] = b2cv[2] = 0; + b2v[0] = b2v[1] = b2v[2] = 0; + } + } + + dVector3 local_feedback; + if (!c->collide_feedback.empty()) { + assert(b1 || b2); + dBodyID fb; + float affx = 0; + float affy = 0; + float affz = 0; + float aftx = 0; + float afty = 0; + float aftz = 0; + + // Get one or the other force. Once we convert it to local + // it should be equal/opposite. + if (b1) { + fb = b1; + for (auto& i : c->collide_feedback) { + affx += i.f1[0]; + affy += i.f1[1]; + affz += i.f1[2]; + aftx += i.t1[0]; + afty += i.t1[1]; + aftz += i.t1[2]; + } + } else { + fb = b2; + for (auto& i : c->collide_feedback) { + affx += i.f2[0]; + affy += i.f2[1]; + affz += i.f2[2]; + aftx += i.t2[0]; + afty += i.t2[1]; + aftz += i.t2[2]; + } + } + dMass mass; + dBodyGetMass(fb, &mass); + + // Average them and divide by mass to normalize the force. + float count = c->collide_feedback.size(); + affx /= (count * mass.mass * 10.0f); + affy /= (count * mass.mass * 10.0f); + affz /= (count * mass.mass * 10.0f); + aftx /= (count * mass.mass * 10.0f); + afty /= (count * mass.mass * 10.0f); + aftz /= (count * mass.mass * 10.0f); + + // Get local feedback. + do_dBodyGetLocalFeedback(fb, apx, apy, apz, affx, affy, affz, aftx, + afty, aftz, local_feedback); + + // TODO(ericf): normalize feedback based on body mass so all bodies can + // use similar ranges? ... hmm maybe not a good idea.. larger object + // *should* be louder plus then we're using object mass, which doesnt + // account for objects + // connected to it via fixed constraints, etc + // the sound should simply have a impulse associated with it - + // anything less than that will scale appropriately + } else { + local_feedback[0] = 0; + local_feedback[1] = 0; + local_feedback[2] = 0; + } + + // Combine both velocities into one relative velocity for the contact + // point. + dVector3 rvel; + rvel[0] = b2v[0] - b1v[0]; + rvel[1] = b2v[1] - b1v[1]; + rvel[2] = b2v[2] - b1v[2]; + + // Get our overall relative velocity (at the objects' centers-of-gravity + // we use this to determine roll. + dVector3 crvel; + crvel[0] = b2cv[0] - b1cv[0]; + crvel[1] = b2cv[1] - b1cv[1]; + crvel[2] = b2cv[2] - b1cv[2]; + + // Now multiply our feedback force by our relative velocity and use the + // component of that which is parallel to our collide normal as "impact" + // and the tangential component as "skid". + { + dVector3 vec = {local_feedback[0] * rvel[0], + local_feedback[1] * rvel[1], + local_feedback[2] * rvel[2]}; + float cur_impact = std::abs(dDOT(an, vec)) / 3; + float vec_len = dVector3Length(vec); + float cur_skid = sqrtf(vec_len * vec_len - cur_impact * cur_impact) / 2; + + // Roll is calculated as the component of force parallel to the normal + // multiplied by the tangential velocity component (relative + // center-of-gravity velocities - not at the contact point). + float cur_roll; + { + float vparallel = dDOT(an, crvel); + float vec_len_2 = dVector3Length(crvel); + float vtangential = + sqrtf(vec_len_2 * vec_len_2 - vparallel * vparallel); + cur_roll = (vtangential); + } + cur_roll -= cur_impact; + cur_skid -= cur_impact; + if (cur_roll < 0) { + cur_roll = 0; + } + if (cur_skid < 0) { + cur_skid = 0; + } + + // Weigh our new values with previous ones to get more smooth consistent + // values over time. + float impact_weight = 0.3f; + float skid_weight = 0.1f; + float roll_weight = 0.1f; + + c->impact = + (1.0f - impact_weight) * c->impact + impact_weight * cur_impact; + c->skid = (1.0f - skid_weight) * c->skid + skid_weight * cur_skid; + c->roll = (1.0f - roll_weight) * c->roll + roll_weight * cur_roll; + + // Draw debugging lines - red for impact, green for skid, blue for roll. + // if (scene_->getShowCollisions()) { + // g_graphics_server->addDebugDrawObject( + // new GraphicsServer::DebugDrawLine( + // apx, apy, apz, + // apx+0*0.5f*c->impact, + // apy+1*0.5f*c->impact, + // apz+0*0.5f*c->impact, 15, 1, 0, 0)); + // g_graphics_server->addDebugDrawObject( + // new GraphicsServer::DebugDrawLine( + // apx, apy, apz, + // apx-0*0.5f*c->skid, + // apy-1*0.5f*c->skid, + // apz-0*0.5f*c->skid, 10, 0, 1, 0)); + // g_graphics_server->addDebugDrawObject( + // new GraphicsServer::DebugDrawLine( + // apx, apy, apz, + // apx+1*0.5f*c->roll, + // apy+0*0.5f*c->roll, + // apz+0*0.5f*c->roll, 15, 0, 0, 1)); + // } + + // Play impact sounds if its been long enough since last. + // Clip if impact value is low enough (otherwise we'd be running tiny + // little impact sounds constantly). + // Also only play impact sound when our current impact is less than + // our average (so that as impact spikes we hit it near the top instead + // of on the way up). + if ((real_time - p1->last_impact_sound_time() >= 500) + || (real_time - p2->last_impact_sound_time() > 500)) { + float clip = 0.15f; + MaterialContext* contexts[] = {cc1, cc2}; + for (auto context : contexts) { + for (auto&& i : context->impact_sounds) { + if (c->impact > i.target_impulse * clip + && cur_impact < c->impact) { + float volume = i.target_impulse > 0.0001f + ? (c->impact - (i.target_impulse * clip)) + / (i.target_impulse * (1.0f - clip)) + : 1.0f; + + if (volume > 1) volume = 1; + assert(i.sound.exists()); + if (AudioSource* source = g_audio->SourceBeginNew()) { + source->SetGain(volume * i.volume); + source->SetPosition(apx, apy, apz); + source->Play(i.sound->GetSoundData()); + p1->set_last_impact_sound_time(real_time); + p2->set_last_impact_sound_time(real_time); + last_impact_sound_time_ = real_time; + source->End(); + } + } + } + } + } + + // Play skid sounds. + { + float clip = 0.15f; + MaterialContext* contexts[] = {cc1, cc2}; + for (auto context : contexts) { + for (auto&& i : context->skid_sounds) { + if (c->skid > i.target_impulse * clip) { + float volume = i.target_impulse > 0.0001f + ? (c->skid - (i.target_impulse * clip)) + / (i.target_impulse * (1.0f - clip)) + : 1.0f; + if (volume > 1) volume = 1; + + // If we're already playing, just adjust volume + // and position - otherwise get a sound started. + if (i.playing) { + AudioSource* s = g_audio->SourceBeginExisting(i.play_id, 101); + if (s) { + s->SetGain(volume * i.volume); + s->SetPosition(apx, apy, apz); + s->End(); + } else { + // Spare ourself some trouble next time. + i.playing = false; + } + } else if (real_time - p1->last_skid_sound_time() >= 250 + || real_time - p2->last_skid_sound_time() > 250) { + assert(i.sound.exists()); + if (AudioSource* source = g_audio->SourceBeginNew()) { + source->SetLooping(true); + source->SetGain(volume * i.volume); + source->SetPosition(apx, apy, apz); + i.play_id = source->Play(i.sound->GetSoundData()); + i.playing = true; + p1->set_last_skid_sound_time(real_time); + p2->set_last_skid_sound_time(real_time); + source->End(); + } + } + } else { + // Skid values are low - stop any playing skid sounds. + if (i.playing) { + g_audio->PushSourceFadeOutCall(i.play_id, 200); + i.playing = false; + } + } + } + } + } + + // Play roll sounds. + { + float clip = 0.15f; + MaterialContext* contexts[] = {cc1, cc2}; + for (auto context : contexts) { + for (auto&& i : context->roll_sounds) { + if (c->roll > i.target_impulse * clip) { + float volume = i.target_impulse > 0.0001f + ? (c->roll - (i.target_impulse * clip)) + / (i.target_impulse * (1.0f - clip)) + : 1; + if (volume > 1) volume = 1; + + // If we're already playing, just adjust volume + // and position; otherwise get a sound started. + if (i.playing) { + AudioSource* s = g_audio->SourceBeginExisting(i.play_id, 102); + if (s) { + s->SetGain(volume * i.volume); + s->SetPosition(apx, apy, apz); + s->End(); + } else { + // spare ourself some trouble next time + i.playing = false; + } + } else if (real_time - p1->last_roll_sound_time() >= 250 + || real_time - p2->last_roll_sound_time() > 250) { + assert(i.sound.exists()); + if (AudioSource* source = g_audio->SourceBeginNew()) { + source->SetLooping(true); + source->SetGain(volume * i.volume); + source->SetPosition(apx, apy, apz); + i.play_id = source->Play(i.sound->GetSoundData()); + i.playing = true; + p1->set_last_roll_sound_time(real_time); + p2->set_last_roll_sound_time(real_time); + source->End(); + } + } + } else { + // roll values are low - stop any playing roll sounds + if (i.playing) { + g_audio->PushSourceFadeOutCall(i.play_id, 200); + i.playing = false; + } + } + } + } + } + } + if (get_feedback_for_these_collisions) { + assert(numc >= 0); + c->collide_feedback.resize(static_cast(numc)); + } + } + + // Play collide sounds when new contacts happen + // or when the averaged collide-position relative to + // both objects changes by a largeish amount. + // (in a normal rolling or sliding situation, the collide position + // will stay relatively constant in at least one of the object's + // frame-of-reference) + bool play_collide_sounds = false; + + // Normal sounds should just happen on initial contact creation. + if (c->contact_count == 0 && numc > 0) { + play_collide_sounds = true; + } + + c->contact_count = numc; + + if (play_collide_sounds) { + for (auto&& i : cc1->connect_sounds) { + assert(i.sound.exists()); + if (AudioSource* source = g_audio->SourceBeginNew()) { + source->SetPosition(apx, apy, apz); + source->SetGain(i.volume); + source->Play(i.sound->GetSoundData()); + source->End(); + } + } + for (auto&& i : cc2->connect_sounds) { + assert(i.sound.exists()); + if (AudioSource* source = g_audio->SourceBeginNew()) { + source->SetPosition(apx, apy, apz); + source->SetGain(i.volume); + source->Play(i.sound->GetSoundData()); + source->End(); + } + } + } + + // Set up collision constraints for this frame as long + // as theres at least one body involved. + if ((b1 || b2) && (cc1->physical && cc2->physical)) { + float friction = 1.2f * sqrtf(cc1->friction * cc2->friction); + float bounce = sqrtf(cc1->bounce * cc2->bounce); + float stiffness; + if (cc1->stiffness < 0.00000001f || cc2->stiffness < 0.00000001f) { + stiffness = 0.00000001f; + } else { + stiffness = 8000 * sqrtf(cc1->stiffness * cc2->stiffness); + } + float damping = 80 * cc1->damping + cc2->damping; + if ((stiffness < 0.00000001f) && (damping < 0.00000001f)) { + damping = 0.00000001f; + } + + // Cfm/erp (based off stiffness/damping). + float erp = (kGameStepSeconds * stiffness) + / ((kGameStepSeconds * stiffness) + damping); + float cfm = 1.0f / ((kGameStepSeconds * stiffness) + damping); + + // Normally a geom against a body does not automatically wake the body. + // However we explicitly do so in certain cases (if the geom is moving, + // etc). + if (r1->geom_wake_on_collide() || r2->geom_wake_on_collide()) { + if (b1) { + dBodyEnable(b1); + } + if (b2) { + dBodyEnable(b2); + } + } + bool do_collide = true; + + // Set up our contacts. + // FIXME should really do some merging in cases with > 15 or so contacts + // (which seem to occur often with boxes and such). + + for (int i = 0; i < numc; i += 1) { + // NOLINTNEXTLINE + contact[i].surface.mode = dContactBounce | dContactSoftCFM + | dContactSoftERP | dContactApprox1; + contact[i].surface.mu2 = 0; + contact[i].surface.bounce_vel = 0.1f; + contact[i].surface.mu = friction; + contact[i].surface.bounce = bounce; + contact[i].surface.soft_cfm = cfm; + contact[i].surface.soft_erp = erp; + } + + // Let each side of the collision modify our stuff. If any party objects + // to the collision occurring, we scrap the whole plan. + if ((!r1->CallCollideCallbacks(contact, numc, r2)) + || (!r2->CallCollideCallbacks(contact, numc, r1))) { + do_collide = false; + } + if (do_collide) { + collision_count_ += numc; + for (int i = 0; i < numc; i += 1) { + dJointID constraint = + dJointCreateContact(ode_world_, ode_contact_group_, contact + i); + dJointAttach(constraint, b1, b2); + if (get_feedback_for_these_collisions) { + dJointSetFeedback(constraint, &c->collide_feedback[i]); + } + } + } + } + } +} + +void Dynamics::ShutdownODE() { + if (ode_space_) { + dSpaceDestroy(ode_space_); + ode_space_ = nullptr; + } + if (ode_world_) { + dWorldDestroy(ode_world_); + ode_world_ = nullptr; + } + if (ode_contact_group_) { + dJointGroupDestroy(ode_contact_group_); + ode_contact_group_ = nullptr; + } +} + +void Dynamics::ResetODE() { + ShutdownODE(); + ode_world_ = dWorldCreate(); + assert(ode_world_); + dWorldSetGravity(ode_world_, 0, -20, 0); + dWorldSetContactSurfaceLayer(ode_world_, 0.001f); + dWorldSetAutoDisableFlag(ode_world_, true); + dWorldSetAutoDisableSteps(ode_world_, 5); + dWorldSetAutoDisableLinearThreshold(ode_world_, 0.1f); + dWorldSetAutoDisableAngularThreshold(ode_world_, 0.1f); + dWorldSetAutoDisableSteps(ode_world_, 10); + dWorldSetAutoDisableTime(ode_world_, 0); + dWorldSetQuickStepNumIterations(ode_world_, 10); + ode_space_ = dHashSpaceCreate(nullptr); + assert(ode_space_); + ode_contact_group_ = dJointGroupCreate(0); + assert(ode_contact_group_); + dRandSetSeed(5432); +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/dynamics.h b/src/ballistica/dynamics/dynamics.h new file mode 100644 index 00000000..ca9792f9 --- /dev/null +++ b/src/ballistica/dynamics/dynamics.h @@ -0,0 +1,128 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_DYNAMICS_H_ +#define BALLISTICA_DYNAMICS_DYNAMICS_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ode/ode.h" + +namespace ballistica { + +class Dynamics : public Object { + public: + explicit Dynamics(Scene* scene_in); + ~Dynamics() override; + void Draw(FrameDef* frame_def); // Draw any debug stuff, etc. + auto ode_world() -> dWorldID { return ode_world_; } + auto getContactGroup() -> dJointGroupID { return ode_contact_group_; } + auto space() -> dSpaceID { return ode_space_; } + + // Discontinues a collision. Used by parts when changing materials + // so that new collisions may enter effect. + void ResetCollision(int64_t node1, int part1, int64_t node2, int part2); + + // Used by collision callbacks - internal. + auto active_collision() const -> Collision* { return active_collision_; } + + // Used by collision callbacks - internal. + auto GetActiveCollideSrcNode() -> Node* { + assert(active_collision_); + return (collide_message_reverse_order_ ? active_collide_dst_node_ + : active_collide_src_node_) + .get(); + } + // Used by collision callbacks - internal. + auto GetActiveCollideDstNode() -> Node* { + assert(active_collision_); + return (collide_message_reverse_order_ ? active_collide_src_node_ + : active_collide_dst_node_) + .get(); + } + auto GetCollideMessageReverseOrder() const -> bool { + return collide_message_reverse_order_; + } + + // Used by collide message handlers. + void set_collide_message_state(bool inCollideMessageIn, + bool target_other_in = false) { + in_collide_message_ = inCollideMessageIn; + collide_message_reverse_order_ = target_other_in; + } + auto in_collide_message() const -> bool { return in_collide_message_; } + void process(); + void increment_skid_sound_count() { skid_sound_count_++; } + void decrement_skid_sound_count() { skid_sound_count_--; } + auto skid_sound_count() const -> int { return skid_sound_count_; } + void incrementRollSoundCount() { roll_sound_count_++; } + void decrement_roll_sound_count() { roll_sound_count_--; } + auto getRollSoundCount() const -> int { return roll_sound_count_; } + + // We do some fancy collision testing stuff for trimeshes instead + // of going through regular ODE space collision testing.. so we have + // to keep track of these ourself. + void AddTrimesh(dGeomID g); + void RemoveTrimesh(dGeomID g); + + auto collision_count() const -> int { return collision_count_; } + auto process_real_time() const -> millisecs_t { return real_time_; } + auto last_impact_sound_time() const -> millisecs_t { + return last_impact_sound_time_; + } + auto in_process() const -> bool { return in_process_; } + + private: + auto AreColliding(const Part& p1, const Part& p2) -> bool; + class SrcNodeCollideMap; + class DstNodeCollideMap; + class SrcPartCollideMap; + class CollisionEvent; + class CollisionReset; + std::vector collision_resets_; + + // Return a collision object between these two parts, + // creating a new one if need be. + auto GetCollision(Part* p1, Part* p2, MaterialContext** cc1, + MaterialContext** cc2) -> Collision*; + + // Contains in-progress collisions for current nodes. + std::map node_collisions_; + std::vector collision_events_; + void HandleDisconnect( + const std::map::iterator& i, + const std::map::iterator& j, + const std::map::iterator& k, + const std::map >::iterator& l); + void ResetODE(); + void ShutdownODE(); + static void DoCollideCallback(void* data, dGeomID o1, dGeomID o2); + void CollideCallback(dGeomID o1, dGeomID o2); + void ProcessCollisions(); + bool processing_collisions_ = false; + dWorldID ode_world_ = nullptr; + dJointGroupID ode_contact_group_ = nullptr; + dSpaceID ode_space_ = nullptr; + millisecs_t real_time_ = 0; + bool in_process_ = false; + std::vector trimeshes_; + millisecs_t last_impact_sound_time_ = 0; + int skid_sound_count_ = 0; + int roll_sound_count_ = 0; + int collision_count_ = 0; + Scene* scene_; + bool in_collide_message_ = false; + bool collide_message_reverse_order_ = false; + Collision* active_collision_ = nullptr; + Object::WeakRef active_collide_src_node_; + Object::WeakRef active_collide_dst_node_; + std::unique_ptr collision_cache_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_DYNAMICS_H_ diff --git a/src/ballistica/dynamics/material/impact_sound_material_action.cc b/src/ballistica/dynamics/material/impact_sound_material_action.cc new file mode 100644 index 00000000..8e5f1b30 --- /dev/null +++ b/src/ballistica/dynamics/material/impact_sound_material_action.cc @@ -0,0 +1,74 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/impact_sound_material_action.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/session/client_session.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +auto ImpactSoundMaterialAction::GetFlattenedSize() -> size_t { + // 1 byte for number of sounds plus 1 int per sound + return 1 + 4 * sounds.size() + 2 + 2; +} + +void ImpactSoundMaterialAction::Flatten(char** buffer, + GameStream* output_stream) { + assert(sounds.size() < 100); + auto sound_count{static_cast(sounds.size())}; + Utils::EmbedInt8(buffer, sound_count); + for (int i = 0; i < sound_count; i++) { + Utils::EmbedInt32NBO(buffer, + static_cast_check_fit( + output_stream->GetSoundID(sounds[i].get()))); + } + Utils::EmbedFloat16NBO(buffer, target_impulse_); + Utils::EmbedFloat16NBO(buffer, volume_); +} + +void ImpactSoundMaterialAction::Restore(const char** buffer, + ClientSession* cs) { + int count{Utils::ExtractInt8(buffer)}; + BA_PRECONDITION(count > 0 && count < 100); + sounds.clear(); + for (int i = 0; i < count; i++) { + sounds.emplace_back(cs->GetSound(Utils::ExtractInt32NBO(buffer))); + } + target_impulse_ = Utils::ExtractFloat16NBO(buffer); + volume_ = Utils::ExtractFloat16NBO(buffer); +} + +void ImpactSoundMaterialAction::Apply(MaterialContext* context, + const Part* src_part, + const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + assert(context->dynamics.exists()); + assert(context->dynamics->in_process()); + + // For now lets avoid this in low-quality graphics mode (should we make + // a low-quality sound mode?) + if (g_graphics_server + && g_graphics_server->quality() < GraphicsQuality::kMedium) { + return; + } + + // Let's only process impact-sounds a bit after the last one finished. + // (cut down on processing) + if (context->dynamics->process_real_time() + - context->dynamics->last_impact_sound_time() + > 100) { + assert(!sounds.empty()); + context->impact_sounds.emplace_back( + context, sounds[rand() % sounds.size()].get(), // NOLINT + target_impulse_, volume_); + context->complex_sound = true; + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/impact_sound_material_action.h b/src/ballistica/dynamics/material/impact_sound_material_action.h new file mode 100644 index 00000000..b64368c9 --- /dev/null +++ b/src/ballistica/dynamics/material/impact_sound_material_action.h @@ -0,0 +1,39 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_IMPACT_SOUND_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_IMPACT_SOUND_MATERIAL_ACTION_H_ + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +// A sound created based on collision forces parallel to the collision normal. +class ImpactSoundMaterialAction : public MaterialAction { + public: + ImpactSoundMaterialAction() = default; + ImpactSoundMaterialAction(const std::vector& sounds_in, + float target_impulse_in, float volume_in) + : sounds(PointersToRefs(sounds_in)), + target_impulse_(target_impulse_in), + volume_(volume_in) {} + std::vector > sounds; + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + auto GetType() const -> Type override { return Type::IMPACT_SOUND; } + auto GetFlattenedSize() -> size_t override; + void Flatten(char** buffer, GameStream* output_stream) override; + void Restore(const char** buffer, ClientSession* cs) override; + + private: + float target_impulse_{}; + float volume_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_IMPACT_SOUND_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/material.cc b/src/ballistica/dynamics/material/material.cc new file mode 100644 index 00000000..4be741ee --- /dev/null +++ b/src/ballistica/dynamics/material/material.cc @@ -0,0 +1,81 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/material.h" + +#include +#include + +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/dynamics/material/material_component.h" +#include "ballistica/dynamics/material/material_condition_node.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/python/python_sys.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +Material::Material(std::string name_in, Scene* scene) + : label_(std::move(name_in)), scene_(scene) { + // If we're being made in a scene with an output stream, + // write ourself to it. + assert(scene); + if (GameStream* os = scene->GetGameStream()) { + os->AddMaterial(this); + } +} + +void Material::MarkDead() { + if (dead_) { + return; + } + components_.clear(); + + // If we're in a scene with an output-stream, inform them of our demise. + Scene* scene = scene_.get(); + if (scene) { + if (GameStream* os = scene->GetGameStream()) { + os->RemoveMaterial(this); + } + } + dead_ = true; +} + +auto Material::GetPyRef(bool new_ref) -> PyObject* { + if (!py_object_) { + throw Exception("This material is not associated with a python object"); + } + if (new_ref) { + Py_INCREF(py_object_); + } + return py_object_; +} + +Material::~Material() { MarkDead(); } + +void Material::Apply(MaterialContext* s, const Part* src_part, + const Part* dst_part) { + // Apply all applicable components to the context. + for (auto& component : components_) { + if (component->eval_conditions(component->conditions, *this, src_part, + dst_part, *s)) { + component->Apply(s, src_part, dst_part); + } + } +} + +void Material::AddComponent(const Object::Ref& c) { + // If there's an output stream, push this to that first + if (GameStream* output_stream = scene()->GetGameStream()) { + output_stream->AddMaterialComponent(this, c.get()); + } + components_.push_back(c); +} + +void Material::DumpComponents(GameStream* out) { + for (auto& i : components_) { + assert(i.exists()); + out->AddMaterialComponent(this, i.get()); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/material.h b/src/ballistica/dynamics/material/material.h new file mode 100644 index 00000000..e1ea134b --- /dev/null +++ b/src/ballistica/dynamics/material/material.h @@ -0,0 +1,61 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_H_ + +#include +#include + +#include "ballistica/media/component/sound.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +/// A material defines actions that occur when a part collides with another part +/// (or separates from it after colliding). Materials can set up any number of +/// actions to occur dependent on what opposing materials are being hit, what +/// nodes are being hit, etc. +class Material : public Object { + public: + Material(std::string name, Scene* scene); + ~Material() override; + + /// Add a new component to the material. + /// Pass a component allocated via new. + void AddComponent(const Object::Ref& c); + + /// Apply the material to a context. + void Apply(MaterialContext* s, const Part* src_part, const Part* dst_part); + auto label() const -> const std::string& { return label_; } + auto hasPyObject() const -> bool { return (py_object_ != nullptr); } + auto NewPyRef() -> PyObject* { return GetPyRef(true); } + auto BorrowPyRef() -> PyObject* { return GetPyRef(false); } + void MarkDead(); + auto scene() const -> Scene* { return scene_.get(); } + void DumpComponents(GameStream* out); + auto stream_id() const -> int64_t { return stream_id_; } + void set_stream_id(int64_t val) { + assert(stream_id_ == -1); + stream_id_ = val; + } + void clear_stream_id() { + assert(stream_id_ != -1); + stream_id_ = -1; + } + void set_py_object(PyObject* obj) { py_object_ = obj; } + auto py_object() const -> PyObject* { return py_object_; } + + private: + bool dead_ = false; + int64_t stream_id_ = -1; + Object::WeakRef scene_; + PyObject* py_object_ = nullptr; + auto GetPyRef(bool new_ref = true) -> PyObject*; + std::string label_; + std::vector > components_; + friend class ClientSession; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_H_ diff --git a/src/ballistica/dynamics/material/material_action.h b/src/ballistica/dynamics/material/material_action.h new file mode 100644 index 00000000..443992fb --- /dev/null +++ b/src/ballistica/dynamics/material/material_action.h @@ -0,0 +1,51 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_ACTION_H_ + +#include "ballistica/core/object.h" + +namespace ballistica { + +class MaterialAction : public Object { + public: + enum class Type { + NODE_MESSAGE, + SCRIPT_COMMAND, + SCRIPT_CALL, + SOUND, + IMPACT_SOUND, + SKID_SOUND, + ROLL_SOUND, + NODE_MOD, + PART_MOD, + NODE_USER_MESSAGE + }; + MaterialAction() = default; + virtual auto GetType() const -> Type = 0; + virtual void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) = 0; + virtual void Execute(Node* node1, Node* node2, Scene* scene) {} + virtual auto GetFlattenedSize() -> size_t { return 0; } + virtual void Flatten(char** buffer, GameStream* output_stream) {} + virtual void Restore(const char** buffer, ClientSession* cs) {} + auto IsNeededOnClient() -> bool { + switch (GetType()) { + case Type::NODE_MESSAGE: + case Type::SOUND: + case Type::IMPACT_SOUND: + case Type::SKID_SOUND: + case Type::ROLL_SOUND: + case Type::NODE_MOD: + case Type::PART_MOD: + return true; + default: + return false; + } + } +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/material_component.cc b/src/ballistica/dynamics/material/material_component.cc new file mode 100644 index 00000000..3284d5ff --- /dev/null +++ b/src/ballistica/dynamics/material/material_component.cc @@ -0,0 +1,227 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/material_component.h" + +#include "ballistica/dynamics/material/impact_sound_material_action.h" +#include "ballistica/dynamics/material/material.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/dynamics/material/material_condition_node.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/dynamics/material/node_message_material_action.h" +#include "ballistica/dynamics/material/node_mod_material_action.h" +#include "ballistica/dynamics/material/part_mod_material_action.h" +#include "ballistica/dynamics/material/python_call_material_action.h" +#include "ballistica/dynamics/material/roll_sound_material_action.h" +#include "ballistica/dynamics/material/skid_sound_material_action.h" +#include "ballistica/dynamics/material/sound_material_action.h" +#include "ballistica/dynamics/part.h" +#include "ballistica/generic/utils.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +auto MaterialComponent::eval_conditions( + const Object::Ref& condition, const Material& c, + const Part* part, const Part* opposing_part, const MaterialContext& s) + -> bool { + // If there's no condition, succeed. + if (!condition.exists()) { + return true; + } + + // If we're a leaf node, evaluate. + if (condition->opmode == MaterialConditionNode::OpMode::LEAF_NODE) { + switch (condition->cond) { + case MaterialCondition::kTrue: + return true; + case MaterialCondition::kFalse: + return false; + case MaterialCondition::kDstIsMaterial: + return ( + (opposing_part->ContainsMaterial(condition->val1_material.get()))); + case MaterialCondition::kDstNotMaterial: + return ( + !(opposing_part->ContainsMaterial(condition->val1_material.get()))); + case MaterialCondition::kDstIsPart: + return ((opposing_part->id() == condition->val1)); + case MaterialCondition::kDstNotPart: + return opposing_part->id() != condition->val1; + case MaterialCondition::kSrcDstSameMaterial: + return ((opposing_part->ContainsMaterial(&c))); + case MaterialCondition::kSrcDstDiffMaterial: + return (!(opposing_part->ContainsMaterial(&c))); + case MaterialCondition::kSrcDstSameNode: + return ((opposing_part->node() == part->node())); + case MaterialCondition::kSrcDstDiffNode: + return opposing_part->node() != part->node(); + case MaterialCondition::kSrcYoungerThan: + return part->GetAge() < condition->val1; + case MaterialCondition::kSrcOlderThan: + return ((part->GetAge() >= condition->val1)); + case MaterialCondition::kDstYoungerThan: + return opposing_part->GetAge() < condition->val1; + case MaterialCondition::kDstOlderThan: + return ((opposing_part->GetAge() >= condition->val1)); + case MaterialCondition::kCollidingDstNode: + return (part->IsCollidingWith(opposing_part->node()->id())); + case MaterialCondition::kNotCollidingDstNode: + return (!(part->IsCollidingWith(opposing_part->node()->id()))); + case MaterialCondition::kEvalColliding: + return s.collide && s.node_collide; + case MaterialCondition::kEvalNotColliding: + return (!s.collide || !s.node_collide); + default: + throw Exception(); + } + } else { + // A trunk node; eval our left and right children and return + // the boolean operation between them. + assert(condition->left_child.exists()); + assert(condition->right_child.exists()); + + bool left_result = + eval_conditions(condition->left_child, c, part, opposing_part, s); + + // In some cases we don't even need to calc the right result. + switch (condition->opmode) { + case MaterialConditionNode::OpMode::AND_OPERATOR: + // AND can't succeed if left is false. + if (!left_result) return false; + break; + case MaterialConditionNode::OpMode::OR_OPERATOR: + // OR has succeeded if we've got a true. + if (left_result) return true; + break; + default: + break; + } + + bool right_result = + eval_conditions(condition->right_child, c, part, opposing_part, s); + + switch (condition->opmode) { + case MaterialConditionNode::OpMode::AND_OPERATOR: + return left_result && right_result; + case MaterialConditionNode::OpMode::OR_OPERATOR: + return left_result || right_result; + case MaterialConditionNode::OpMode::XOR_OPERATOR: + return ((left_result && !right_result) + || (!left_result && right_result)); + default: + throw Exception(); + } + } +} + +auto MaterialComponent::GetFlattenedSize() -> size_t { + size_t size{}; + + // Embed a byte telling whether we have conditions or not. + size += 1; + + // Embed the size of the condition tree. + if (conditions.exists()) { + size += conditions->GetFlattenedSize(); + } + + // An int32 for the action count. + size += sizeof(uint32_t); + + // Plus the total size of all actions. + for (auto& action : actions) { + if (action->IsNeededOnClient()) { + // 1 type byte plus the action's size. + size += 1 + action->GetFlattenedSize(); + } + } + return size; +} + +void MaterialComponent::Flatten(char** buffer, GameStream* output_stream) { + // Embed a byte telling whether we have conditions. + Utils::EmbedInt8(buffer, conditions.exists()); + + // If we have conditions, have the tree embed itself. + if (conditions.exists()) { + conditions->Flatten(buffer, output_stream); + } + + // Embed our action count; we have to manually go through and count + // actions that we'll be sending. + int count = 0; + for (auto& action : actions) { + if ((*action).IsNeededOnClient()) { + assert((*action).GetType() != MaterialAction::Type::NODE_USER_MESSAGE); + count++; + } + } + Utils::EmbedInt32NBO(buffer, count); + + // Embed our actions. + for (auto& action : actions) { + if ((*action).IsNeededOnClient()) { + Utils::EmbedInt8(buffer, static_cast((*action).GetType())); + (*action).Flatten(buffer, output_stream); + } + } +} + +void MaterialComponent::Restore(const char** buffer, ClientSession* cs) { + // Pull the byte telling us if we have conditions. + bool haveConditions = Utils::ExtractInt8(buffer); + + // If there's conditions, create a condition node and have it extract itself. + if (haveConditions) { + conditions = Object::New(); + conditions->Restore(buffer, cs); + } + + // Pull our action count. + int action_count = Utils::ExtractInt32NBO(buffer); + + // Restore all actions. + for (int i = 0; i < action_count; i++) { + // Pull the action type. + auto type = static_cast(Utils::ExtractInt8(buffer)); + Object::Ref action; + switch (type) { + case MaterialAction::Type::NODE_MESSAGE: + action = Object::New(); + break; + case MaterialAction::Type::SOUND: + action = Object::New(); + break; + case MaterialAction::Type::IMPACT_SOUND: + action = Object::New(); + break; + case MaterialAction::Type::SKID_SOUND: + action = Object::New(); + break; + case MaterialAction::Type::ROLL_SOUND: + action = Object::New(); + break; + case MaterialAction::Type::PART_MOD: + action = Object::New(); + break; + case MaterialAction::Type::NODE_MOD: + action = Object::New(); + break; + default: + Log("Error: Invalid material action: '" + + std::to_string(static_cast(type)) + "'."); + throw Exception(); + } + action->Restore(buffer, cs); + actions.push_back(action); + } +} + +void MaterialComponent::Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part) { + assert(context && src_part && dst_part); + for (auto& action : actions) { + (*action).Apply(context, src_part, dst_part, action); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/material_component.h b/src/ballistica/dynamics/material/material_component.h new file mode 100644 index 00000000..fba0df8f --- /dev/null +++ b/src/ballistica/dynamics/material/material_component.h @@ -0,0 +1,44 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_COMPONENT_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_COMPONENT_H_ + +#include +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +// A component of a material - comprises one or more conditions and actions. +class MaterialComponent : public Object { + public: + auto GetDefaultOwnerThread() const -> ThreadIdentifier override { + return ThreadIdentifier::kGame; + } + + auto GetFlattenedSize() -> size_t; + void Flatten(char** buffer, GameStream* output_stream); + void Restore(const char** buffer, ClientSession* cs); + + // Actions are stored as shared pointers so references + // to them can be stored with pending events + // in case the component is deleted before they are run. + std::vector > actions; + Object::Ref conditions; + auto eval_conditions(const Object::Ref& condition, + const Material& c, const Part* part, + const Part* opposing_part, const MaterialContext& s) + -> bool; + + // Apply the component to a context. + void Apply(MaterialContext* c, const Part* src_part, const Part* dst_part); + MaterialComponent() = default; + MaterialComponent(const Object::Ref& conditions_in, + std::vector > actions_in) + : conditions(conditions_in), actions(std::move(actions_in)) {} +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_COMPONENT_H_ diff --git a/src/ballistica/dynamics/material/material_condition_node.cc b/src/ballistica/dynamics/material/material_condition_node.cc new file mode 100644 index 00000000..22300cdc --- /dev/null +++ b/src/ballistica/dynamics/material/material_condition_node.cc @@ -0,0 +1,90 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/material_condition_node.h" + +#include "ballistica/dynamics/material/material.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/session/client_session.h" +#include "ballistica/generic/utils.h" + +namespace ballistica { + +auto MaterialConditionNode::GetFlattenedSize() -> size_t { + // we need one byte for our opmode + // plus the condition byte and either 0, 1, or 2 values depending on our + // condition if we're a leaf node, otherwise add the size of our children + size_t size = 1; + if (opmode == OpMode::LEAF_NODE) { + size += 1 + sizeof(uint32_t) * GetValueCount(); + } else { + size += (left_child->GetFlattenedSize() + right_child->GetFlattenedSize()); + } + return size; +} + +void MaterialConditionNode::Flatten(char** buffer, GameStream* output_stream) { + // Pack our opmode in. Or if we're a leaf note stick zero in. + Utils::EmbedInt8(buffer, static_cast(opmode)); + if (opmode == OpMode::LEAF_NODE) { + Utils::EmbedInt8(buffer, static_cast(cond)); + switch (GetValueCount()) { + case 0: + break; + case 1: { + // If this condition uses the material val1, embed its stream ID + if (cond == MaterialCondition::kDstIsMaterial + || cond == MaterialCondition::kDstNotMaterial) { + Utils::EmbedInt32NBO( + buffer, static_cast_check_fit( + output_stream->GetMaterialID(val1_material.get()))); + } else { + Utils::EmbedInt32NBO(buffer, val1); + } + break; + } + case 2: + Utils::EmbedInt32NBO(buffer, val1); + Utils::EmbedInt32NBO(buffer, val2); + break; + default: + throw Exception(); + } + } else { + left_child->Flatten(buffer, output_stream); + right_child->Flatten(buffer, output_stream); + } +} + +void MaterialConditionNode::Restore(const char** buffer, ClientSession* cs) { + opmode = static_cast(Utils::ExtractInt8(buffer)); + if (opmode == OpMode::LEAF_NODE) { + cond = static_cast(Utils::ExtractInt8(buffer)); + int val_count = GetValueCount(); + switch (val_count) { + case 0: + break; + case 1: + if (cond == MaterialCondition::kDstIsMaterial + || cond == MaterialCondition::kDstNotMaterial) { + val1_material = cs->GetMaterial(Utils::ExtractInt32NBO(buffer)); + } else { + val1 = Utils::ExtractInt32NBO(buffer); + } + break; + case 2: + val1 = Utils::ExtractInt32NBO(buffer); + val2 = Utils::ExtractInt32NBO(buffer); + break; + default: + throw Exception(); + } + } else { + // not a leaf node - make ourself some children + left_child = Object::New(); + left_child->Restore(buffer, cs); + right_child = Object::New(); + right_child->Restore(buffer, cs); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/material_condition_node.h b/src/ballistica/dynamics/material/material_condition_node.h new file mode 100644 index 00000000..0764bf31 --- /dev/null +++ b/src/ballistica/dynamics/material/material_condition_node.h @@ -0,0 +1,59 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_CONDITION_NODE_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_CONDITION_NODE_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/core/object.h" + +namespace ballistica { + +class MaterialConditionNode : public Object { + public: + enum class OpMode { LEAF_NODE = 0, AND_OPERATOR, OR_OPERATOR, XOR_OPERATOR }; + Object::Ref left_child; + Object::Ref right_child; + OpMode opmode{}; + MaterialCondition cond{}; + int val1{}; + Object::Ref val1_material; + int val2{}; + + // Return the number of values used by this node + // assumes the node is a leaf node. + auto GetValueCount() -> int { + assert(opmode == OpMode::LEAF_NODE); + switch (cond) { + case MaterialCondition::kTrue: + case MaterialCondition::kFalse: + case MaterialCondition::kSrcDstSameMaterial: + case MaterialCondition::kSrcDstDiffMaterial: + case MaterialCondition::kSrcDstSameNode: + case MaterialCondition::kSrcDstDiffNode: + case MaterialCondition::kCollidingDstNode: + case MaterialCondition::kNotCollidingDstNode: + case MaterialCondition::kEvalColliding: + case MaterialCondition::kEvalNotColliding: + return 0; + case MaterialCondition::kDstIsMaterial: + case MaterialCondition::kDstNotMaterial: + case MaterialCondition::kSrcYoungerThan: + case MaterialCondition::kSrcOlderThan: + case MaterialCondition::kDstYoungerThan: + case MaterialCondition::kDstOlderThan: + return 1; + case MaterialCondition::kDstIsPart: + case MaterialCondition::kDstNotPart: + return 2; + default: + throw Exception(); + } + } + auto GetFlattenedSize() -> size_t; + void Flatten(char** buffer, GameStream* output_stream); + void Restore(const char** buffer, ClientSession* cs); +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_CONDITION_NODE_H_ diff --git a/src/ballistica/dynamics/material/material_context.cc b/src/ballistica/dynamics/material/material_context.cc new file mode 100644 index 00000000..5c901ec0 --- /dev/null +++ b/src/ballistica/dynamics/material/material_context.cc @@ -0,0 +1,93 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/material_context.h" + +#include "ballistica/audio/audio.h" +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +MaterialContext::MaterialContext(Scene* scene) + : dynamics(scene->dynamics()), + friction(1.0f), + stiffness(1.0f), + damping(1.0f), + bounce(0), + collide(true), + node_collide(true), + use_node_collide(true), + physical(true), + complex_sound(false) {} + +MaterialContext::SkidSoundEntry::SkidSoundEntry( + const MaterialContext::SkidSoundEntry& other) { + *this = other; + assert(context); +#if BA_DEBUG_BUILD + assert(context->dynamics.exists()); +#endif + assert(context->dynamics->in_process()); + context->dynamics->increment_skid_sound_count(); +} + +MaterialContext::SkidSoundEntry::SkidSoundEntry(MaterialContext* context_in, + Sound* sound_in, + float target_impulse_in, + float volume_in) + : context(context_in), + sound(sound_in), + target_impulse(target_impulse_in), + volume(volume_in), + playing(false) { + assert(context); + assert(context->dynamics.exists()); + assert(context->dynamics->in_process()); + context->dynamics->increment_skid_sound_count(); +} + +MaterialContext::SkidSoundEntry::~SkidSoundEntry() { + assert(context); + assert(context->dynamics.exists()); + context->dynamics->decrement_skid_sound_count(); + if (playing) { + g_audio->PushSourceFadeOutCall(play_id, 200); + } +} + +MaterialContext::RollSoundEntry::RollSoundEntry(MaterialContext* context_in, + Sound* sound_in, + float target_impulse_in, + float volume_in) + : context(context_in), + sound(sound_in), + target_impulse(target_impulse_in), + volume(volume_in), + playing(false) { + assert(context); + assert(context->dynamics.exists()); + assert(context->dynamics->in_process()); + context->dynamics->incrementRollSoundCount(); +} + +MaterialContext::RollSoundEntry::RollSoundEntry( + const MaterialContext::RollSoundEntry& other) { + *this = other; + assert(context); + assert(context->dynamics.exists()); + assert(context->dynamics->in_process()); + context->dynamics->incrementRollSoundCount(); +} + +MaterialContext::RollSoundEntry::~RollSoundEntry() { + assert(context); + assert(context->dynamics.exists()); + context->dynamics->decrement_roll_sound_count(); + if (playing) { + g_audio->PushSourceFadeOutCall(play_id, 200); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/material_context.h b/src/ballistica/dynamics/material/material_context.h new file mode 100644 index 00000000..b25765b9 --- /dev/null +++ b/src/ballistica/dynamics/material/material_context.h @@ -0,0 +1,90 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_CONTEXT_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_CONTEXT_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +// Contexts materials use when getting and setting collision data +class MaterialContext { + public: + BA_DEBUG_PTR(Dynamics) dynamics; + float friction{}; + float stiffness{}; + float damping{}; + float bounce{}; + bool collide{}; + bool node_collide{}; + bool use_node_collide{}; + bool physical{}; + + // This should get set to true if + // anything is added to impact_sounds, skid_sounds, or roll_sounds. + // This way we know to calculate collision forces, relative velocities, etc. + bool complex_sound{}; + std::vector > connect_actions; + std::vector > disconnect_actions; + struct SoundEntry { + Object::Ref sound; + float volume; + SoundEntry(Sound* sound_in, float volume_in) + : sound(sound_in), volume(volume_in) {} + }; + class ImpactSoundEntry { + public: + MaterialContext* context; + Object::Ref sound; + float volume; + float target_impulse; + ImpactSoundEntry(MaterialContext* context, Sound* sound_in, + float target_impulse_in, float volume_in) + : context(context), + sound(sound_in), + target_impulse(target_impulse_in), + volume(volume_in) {} + }; + class SkidSoundEntry { + public: + MaterialContext* context{}; + Object::Ref sound; + float volume{}; + float target_impulse{}; + // Used to keep track of the playing sound. + uint32_t play_id{}; + bool playing{}; + SkidSoundEntry(MaterialContext* context, Sound* sound_in, + float target_impulse_in, float volume_in); + ~SkidSoundEntry(); + SkidSoundEntry(const SkidSoundEntry& other); + }; + class RollSoundEntry { + public: + MaterialContext* context{}; + Object::Ref sound; + float volume{}; + float target_impulse{}; + // Used to keep track of the playing sound. + uint32_t play_id{}; + bool playing{}; + RollSoundEntry(MaterialContext* context, Sound* sound_in, + float target_impulse_in, float volume_in); + RollSoundEntry(const RollSoundEntry& other); + ~RollSoundEntry(); + }; + std::vector connect_sounds; + std::vector impact_sounds; + std::vector skid_sounds; + std::vector roll_sounds; + explicit MaterialContext(Scene* scene_in); + + private: + BA_DISALLOW_CLASS_COPIES(MaterialContext); +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_MATERIAL_CONTEXT_H_ diff --git a/src/ballistica/dynamics/material/node_message_material_action.cc b/src/ballistica/dynamics/material/node_message_material_action.cc new file mode 100644 index 00000000..3baf8190 --- /dev/null +++ b/src/ballistica/dynamics/material/node_message_material_action.cc @@ -0,0 +1,45 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/node_message_material_action.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { +NodeMessageMaterialAction::NodeMessageMaterialAction(bool target_other_in, + bool at_disconnect_in, + const char* data_in, + size_t length_in) + : target_other(target_other_in), + at_disconnect(at_disconnect_in), + data(data_in, length_in) { + assert(length_in > 0); +} + +void NodeMessageMaterialAction::Apply(MaterialContext* context, + const Part* src_part, + const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + if (at_disconnect) { + context->disconnect_actions.push_back(p); + } else { + context->connect_actions.push_back(p); + } +} + +void NodeMessageMaterialAction::Execute(Node* node1, Node* node2, + Scene* scene) { + Node* node = target_other ? node2 : node1; + if (node) { + scene->dynamics()->set_collide_message_state(true, target_other); + assert(node); + assert(data.data()); + node->DispatchNodeMessage(data.data()); + scene->dynamics()->set_collide_message_state(false); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/node_message_material_action.h b/src/ballistica/dynamics/material/node_message_material_action.h new file mode 100644 index 00000000..eb1ecd85 --- /dev/null +++ b/src/ballistica/dynamics/material/node_message_material_action.h @@ -0,0 +1,42 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_NODE_MESSAGE_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_NODE_MESSAGE_MATERIAL_ACTION_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/generic/buffer.h" + +namespace ballistica { + +// Regular message. +class NodeMessageMaterialAction : public MaterialAction { + public: + NodeMessageMaterialAction() = default; + NodeMessageMaterialAction(bool target_other_in, bool at_disconnect_in, + const char* data_in, size_t length_in); + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + void Execute(Node* node1, Node* node2, Scene* scene) override; + bool target_other{}; + bool at_disconnect{}; + Buffer data; + auto GetType() const -> Type override { return Type::NODE_MESSAGE; } + auto GetFlattenedSize() -> size_t override { + // 1 byte for bools + data + return static_cast(1 + data.GetFlattenedSize()); + } + void Flatten(char** buffer, GameStream* output_stream) override { + Utils::EmbedBools(buffer, target_other, at_disconnect); + data.embed(buffer); + } + void Restore(const char** buffer, ClientSession* cs) override { + Utils::ExtractBools(buffer, &target_other, &at_disconnect); + data.Extract(buffer); + } +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_NODE_MESSAGE_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/node_mod_material_action.cc b/src/ballistica/dynamics/material/node_mod_material_action.cc new file mode 100644 index 00000000..f15a8c0b --- /dev/null +++ b/src/ballistica/dynamics/material/node_mod_material_action.cc @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/node_mod_material_action.h" + +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/generic/utils.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +auto NodeModMaterialAction::GetType() const -> MaterialAction::Type { + return Type::NODE_MOD; +} + +auto NodeModMaterialAction::GetFlattenedSize() -> size_t { return 1 + 4; } + +void NodeModMaterialAction::Flatten(char** buffer, GameStream* output_stream) { + Utils::EmbedInt8(buffer, static_cast(attr)); + Utils::EmbedFloat32(buffer, attr_val); +} + +void NodeModMaterialAction::Restore(const char** buffer, ClientSession* cs) { + attr = static_cast(Utils::ExtractInt8(buffer)); + attr_val = Utils::ExtractFloat32(buffer); +} + +void NodeModMaterialAction::Apply(MaterialContext* context, + const Part* src_part, const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + // Go ahead and make our modification to the context. + switch (attr) { + case NodeCollideAttr::kCollideNode: + context->node_collide = static_cast(attr_val); + break; + default: + throw Exception(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/node_mod_material_action.h b/src/ballistica/dynamics/material/node_mod_material_action.h new file mode 100644 index 00000000..27fd9a3d --- /dev/null +++ b/src/ballistica/dynamics/material/node_mod_material_action.h @@ -0,0 +1,28 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_NODE_MOD_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_NODE_MOD_MATERIAL_ACTION_H_ + +#include "ballistica/dynamics/material/material_action.h" + +namespace ballistica { + +class NodeModMaterialAction : public MaterialAction { + public: + NodeModMaterialAction() = default; + NodeModMaterialAction(NodeCollideAttr attr_in, float attr_val_in) + : attr(attr_in), attr_val(attr_val_in) {} + NodeCollideAttr attr{}; + float attr_val{}; + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + auto GetType() const -> Type override; + auto GetFlattenedSize() -> size_t override; + void Flatten(char** buffer, GameStream* output_stream) override; + void Restore(const char** buffer, ClientSession* cs) override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_NODE_MOD_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/node_user_message_material_action.cc b/src/ballistica/dynamics/material/node_user_message_material_action.cc new file mode 100644 index 00000000..01a1f044 --- /dev/null +++ b/src/ballistica/dynamics/material/node_user_message_material_action.cc @@ -0,0 +1,61 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/node_user_message_material_action.h" + +#include "ballistica/core/context.h" +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/scene/node/node.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +NodeUserMessageMaterialAction::NodeUserMessageMaterialAction( + bool target_other_in, bool at_disconnect_in, PyObject* user_message_obj_in) + : target_other(target_other_in), at_disconnect(at_disconnect_in) { + user_message_obj.Acquire(user_message_obj_in); +} + +void NodeUserMessageMaterialAction::Apply( + MaterialContext* context, const Part* src_part, const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + if (at_disconnect) { + context->disconnect_actions.push_back(p); + } else { + context->connect_actions.push_back(p); + } +} + +NodeUserMessageMaterialAction::~NodeUserMessageMaterialAction() = default; + +void NodeUserMessageMaterialAction::Execute(Node* node1, Node* node2, + Scene* scene) { + // See who they want to send the message to. + Node* target_node = target_other ? node2 : node1; + + if (!at_disconnect) { + // Only deliver 'connect' messages if both nodes still exist. + // This way handlers can avoid having to deal with that ultra-rare + // corner case. + if (!node1 || !node2) { + return; + } + } else { + // Deliver 'disconnect' messages if the target node still exists + // even if the opposing one doesn't. Nodes should always know when + // they stop colliding even if it was through death. + if (!target_node) { + return; + } + } + + ScopedSetContext cp(target_node->context()); + scene->dynamics()->set_collide_message_state(true, target_other); + target_node->DispatchUserMessage(user_message_obj.get(), + "Material User-Message dispatch"); + scene->dynamics()->set_collide_message_state(false); +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/node_user_message_material_action.h b/src/ballistica/dynamics/material/node_user_message_material_action.h new file mode 100644 index 00000000..bed94691 --- /dev/null +++ b/src/ballistica/dynamics/material/node_user_message_material_action.h @@ -0,0 +1,30 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_NODE_USER_MESSAGE_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_NODE_USER_MESSAGE_MATERIAL_ACTION_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +// a user message - encapsulates a python object +class NodeUserMessageMaterialAction : public MaterialAction { + public: + NodeUserMessageMaterialAction(bool target_other, bool at_disconnect, + PyObject* user_message); + ~NodeUserMessageMaterialAction() override; + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + void Execute(Node* node1, Node* node2, Scene* scene) override; + bool target_other; + bool at_disconnect; + PythonRef user_message_obj; + auto GetType() const -> Type override { return Type::NODE_USER_MESSAGE; } +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_NODE_USER_MESSAGE_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/part_mod_material_action.cc b/src/ballistica/dynamics/material/part_mod_material_action.cc new file mode 100644 index 00000000..e5bb02c6 --- /dev/null +++ b/src/ballistica/dynamics/material/part_mod_material_action.cc @@ -0,0 +1,58 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/part_mod_material_action.h" + +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/generic/utils.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +auto PartModMaterialAction::GetType() const -> MaterialAction::Type { + return Type::PART_MOD; +} + +auto PartModMaterialAction::GetFlattenedSize() -> size_t { return 1 + 4; } + +void PartModMaterialAction::Flatten(char** buffer, GameStream* output_stream) { + Utils::EmbedInt8(buffer, static_cast(attr)); + Utils::EmbedFloat32(buffer, attr_val); +} + +void PartModMaterialAction::Restore(const char** buffer, ClientSession* cs) { + attr = static_cast(Utils::ExtractInt8(buffer)); + attr_val = Utils::ExtractFloat32(buffer); +} + +void PartModMaterialAction::Apply(MaterialContext* context, + const Part* src_part, const Part* dst_part, + const Object::Ref& p) { + // Go ahead and make our modification to the context. + switch (attr) { + case PartCollideAttr::kCollide: + context->collide = static_cast(attr_val); + break; + case PartCollideAttr::kUseNodeCollide: + context->use_node_collide = static_cast(attr_val); + break; + case PartCollideAttr::kPhysical: + context->physical = static_cast(attr_val); + break; + case PartCollideAttr::kFriction: + context->friction = attr_val; + break; + case PartCollideAttr::kStiffness: + context->stiffness = attr_val; + break; + case PartCollideAttr::kDamping: + context->damping = attr_val; + break; + case PartCollideAttr::kBounce: + context->bounce = attr_val; + break; + default: + throw Exception(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/part_mod_material_action.h b/src/ballistica/dynamics/material/part_mod_material_action.h new file mode 100644 index 00000000..151e0dde --- /dev/null +++ b/src/ballistica/dynamics/material/part_mod_material_action.h @@ -0,0 +1,28 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_PART_MOD_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_PART_MOD_MATERIAL_ACTION_H_ + +#include "ballistica/dynamics/material/material_action.h" + +namespace ballistica { + +class PartModMaterialAction : public MaterialAction { + public: + PartModMaterialAction() = default; + PartModMaterialAction(PartCollideAttr attr_in, float attr_val_in) + : attr(attr_in), attr_val(attr_val_in) {} + PartCollideAttr attr{}; + float attr_val{}; + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + auto GetType() const -> Type override; + auto GetFlattenedSize() -> size_t override; + void Flatten(char** buffer, GameStream* output_stream) override; + void Restore(const char** buffer, ClientSession* cs) override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_PART_MOD_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/python_call_material_action.cc b/src/ballistica/dynamics/material/python_call_material_action.cc new file mode 100644 index 00000000..d711b516 --- /dev/null +++ b/src/ballistica/dynamics/material/python_call_material_action.cc @@ -0,0 +1,51 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/python_call_material_action.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/dynamics/material/sound_material_action.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +PythonCallMaterialAction::PythonCallMaterialAction(bool at_disconnect_in, + PyObject* call_obj_in) + : at_disconnect(at_disconnect_in), + call(Object::New(call_obj_in)) {} + +void PythonCallMaterialAction::Apply(MaterialContext* context, + const Part* src_part, const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + if (at_disconnect) { + context->disconnect_actions.push_back(p); + } else { + context->connect_actions.push_back(p); + } +} + +void PythonCallMaterialAction::Execute(Node* node1, Node* node2, Scene* scene) { + scene->dynamics()->set_collide_message_state(true, false); + + // Only run connect commands if both nodes still exist. + // This way most collision commands can assume both + // members of the collision exist. + if (!at_disconnect) { + if (node1 && node2) { + call->Run(); + } + } else { + // Its a disconnect. Run it if the src node still exists + // (nodes should know if they've disconnected from others even if + // it was through death) + if (node1) { + call->Run(); + } + } + scene->dynamics()->set_collide_message_state(false); +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/python_call_material_action.h b/src/ballistica/dynamics/material/python_call_material_action.h new file mode 100644 index 00000000..0a0d86a8 --- /dev/null +++ b/src/ballistica/dynamics/material/python_call_material_action.h @@ -0,0 +1,26 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_PYTHON_CALL_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_PYTHON_CALL_MATERIAL_ACTION_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/python/python_context_call.h" + +namespace ballistica { + +class PythonCallMaterialAction : public MaterialAction { + public: + PythonCallMaterialAction(bool at_disconnect_in, PyObject* call_obj_in); + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + void Execute(Node* node1, Node* node2, Scene* scene) override; + bool at_disconnect; + Object::Ref call; + auto GetType() const -> Type override { return Type::SCRIPT_CALL; } +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_PYTHON_CALL_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/roll_sound_material_action.cc b/src/ballistica/dynamics/material/roll_sound_material_action.cc new file mode 100644 index 00000000..feffbaef --- /dev/null +++ b/src/ballistica/dynamics/material/roll_sound_material_action.cc @@ -0,0 +1,53 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/roll_sound_material_action.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/session/client_session.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +auto RollSoundMaterialAction::GetFlattenedSize() -> size_t { return 4 + 2 + 2; } + +void RollSoundMaterialAction::Flatten(char** buffer, + GameStream* output_stream) { + Utils::EmbedInt32NBO(buffer, static_cast_check_fit( + output_stream->GetSoundID(sound.get()))); + Utils::EmbedFloat16NBO(buffer, target_impulse); + Utils::EmbedFloat16NBO(buffer, volume); +} + +void RollSoundMaterialAction::Restore(const char** buffer, ClientSession* cs) { + sound = cs->GetSound(Utils::ExtractInt32NBO(buffer)); + target_impulse = Utils::ExtractFloat16NBO(buffer); + volume = Utils::ExtractFloat16NBO(buffer); +} + +void RollSoundMaterialAction::Apply(MaterialContext* context, + const Part* src_part, const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + assert(context->dynamics.exists()); + assert(context->dynamics->in_process()); + + // For now lets avoid this in low-quality graphics mode + // (should we make a low-quality sound mode?) + if (g_graphics && g_graphics_server->quality() < GraphicsQuality::kMedium) { + return; + } + + // Let's limit the amount of skid-sounds we spawn, otherwise we'll + // start using up all our sound resources on skids when things get messy + if (context->dynamics->getRollSoundCount() < 2) { + context->roll_sounds.emplace_back(context, sound.get(), target_impulse, + volume); + context->complex_sound = true; + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/roll_sound_material_action.h b/src/ballistica/dynamics/material/roll_sound_material_action.h new file mode 100644 index 00000000..93a373c2 --- /dev/null +++ b/src/ballistica/dynamics/material/roll_sound_material_action.h @@ -0,0 +1,32 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_ROLL_SOUND_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_ROLL_SOUND_MATERIAL_ACTION_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" + +namespace ballistica { + +// Sound created based on velocity perpendicular to the collision normal. +class RollSoundMaterialAction : public MaterialAction { + public: + RollSoundMaterialAction() = default; + RollSoundMaterialAction(Sound* sound_in, float target_impulse_in, + float volume_in) + : sound(sound_in), target_impulse(target_impulse_in), volume(volume_in) {} + Object::Ref sound; + float target_impulse{}; + float volume{}; + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + auto GetType() const -> Type override { return Type::ROLL_SOUND; } + auto GetFlattenedSize() -> size_t override; + void Flatten(char** buffer, GameStream* output_stream) override; + void Restore(const char** buffer, ClientSession* cs) override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_ROLL_SOUND_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/skid_sound_material_action.cc b/src/ballistica/dynamics/material/skid_sound_material_action.cc new file mode 100644 index 00000000..8cf6a3e3 --- /dev/null +++ b/src/ballistica/dynamics/material/skid_sound_material_action.cc @@ -0,0 +1,54 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/skid_sound_material_action.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/session/client_session.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +auto SkidSoundMaterialAction::GetFlattenedSize() -> size_t { return 4 + 2 + 2; } + +void SkidSoundMaterialAction::Flatten(char** buffer, + GameStream* output_stream) { + Utils::EmbedInt32NBO(buffer, static_cast_check_fit( + output_stream->GetSoundID(sound.get()))); + Utils::EmbedFloat16NBO(buffer, target_impulse); + Utils::EmbedFloat16NBO(buffer, volume); +} + +void SkidSoundMaterialAction::Restore(const char** buffer, ClientSession* cs) { + sound = cs->GetSound(Utils::ExtractInt32NBO(buffer)); + target_impulse = Utils::ExtractFloat16NBO(buffer); + volume = Utils::ExtractFloat16NBO(buffer); +} + +void SkidSoundMaterialAction::Apply(MaterialContext* context, + const Part* src_part, const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + assert(context->dynamics.exists()); + assert(context->dynamics->in_process()); + + // For now lets avoid this in low-quality graphics mode + // (should we make a low-quality sound mode?). + if (g_graphics_server + && g_graphics_server->quality() < GraphicsQuality::kMedium) { + return; + } + + // Let's limit the amount of skid-sounds we spawn, otherwise we'll start + // using up all our sound resources on skids when things get messy. + if (context->dynamics->skid_sound_count() < 2) { + context->skid_sounds.emplace_back(context, sound.get(), target_impulse, + volume); + context->complex_sound = true; + } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/skid_sound_material_action.h b/src/ballistica/dynamics/material/skid_sound_material_action.h new file mode 100644 index 00000000..2179e426 --- /dev/null +++ b/src/ballistica/dynamics/material/skid_sound_material_action.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_SKID_SOUND_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_SKID_SOUND_MATERIAL_ACTION_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +// sound created based on collision forces perpendicular to the collision normal +class SkidSoundMaterialAction : public MaterialAction { + public: + SkidSoundMaterialAction() = default; + SkidSoundMaterialAction(Sound* sound_in, float target_impulse_in, + float volume_in) + : sound(sound_in), target_impulse(target_impulse_in), volume(volume_in) {} + Object::Ref sound; + float target_impulse{}; + float volume{}; + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + auto GetType() const -> Type override { return Type::SKID_SOUND; } + auto GetFlattenedSize() -> size_t override; + void Flatten(char** buffer, GameStream* output_stream) override; + void Restore(const char** buffer, ClientSession* cs) override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_SKID_SOUND_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/material/sound_material_action.cc b/src/ballistica/dynamics/material/sound_material_action.cc new file mode 100644 index 00000000..e8fefff9 --- /dev/null +++ b/src/ballistica/dynamics/material/sound_material_action.cc @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/material/sound_material_action.h" + +#include "ballistica/dynamics/material/material_context.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/session/client_session.h" +#include "ballistica/generic/utils.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +void SoundMaterialAction::Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) { + assert(context && src_part && dst_part); + context->connect_sounds.emplace_back(sound_.get(), volume_); +} + +auto SoundMaterialAction::GetFlattenedSize() -> size_t { return 4 + 2; } + +void SoundMaterialAction::Flatten(char** buffer, GameStream* output_stream) { + Utils::EmbedInt32NBO(buffer, static_cast_check_fit( + output_stream->GetSoundID(sound_.get()))); + Utils::EmbedFloat16NBO(buffer, volume_); +} + +void SoundMaterialAction::Restore(const char** buffer, ClientSession* cs) { + sound_ = cs->GetSound(Utils::ExtractInt32NBO(buffer)); + volume_ = Utils::ExtractFloat16NBO(buffer); +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/material/sound_material_action.h b/src/ballistica/dynamics/material/sound_material_action.h new file mode 100644 index 00000000..ddd46745 --- /dev/null +++ b/src/ballistica/dynamics/material/sound_material_action.h @@ -0,0 +1,32 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_MATERIAL_SOUND_MATERIAL_ACTION_H_ +#define BALLISTICA_DYNAMICS_MATERIAL_SOUND_MATERIAL_ACTION_H_ + +#include "ballistica/ballistica.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/media/component/sound.h" + +namespace ballistica { + +class SoundMaterialAction : public MaterialAction { + public: + SoundMaterialAction() = default; + SoundMaterialAction(Sound* sound_in, float volume_in) + : sound_(sound_in), volume_(volume_in) {} + void Apply(MaterialContext* context, const Part* src_part, + const Part* dst_part, + const Object::Ref& p) override; + auto GetType() const -> Type override { return Type::SOUND; } + auto GetFlattenedSize() -> size_t override; + void Flatten(char** buffer, GameStream* output_stream) override; + void Restore(const char** buffer, ClientSession* cs) override; + + private: + Object::Ref sound_; + float volume_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_MATERIAL_SOUND_MATERIAL_ACTION_H_ diff --git a/src/ballistica/dynamics/part.cc b/src/ballistica/dynamics/part.cc new file mode 100644 index 00000000..2b7436b3 --- /dev/null +++ b/src/ballistica/dynamics/part.cc @@ -0,0 +1,131 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/part.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material.h" +#include "ballistica/generic/buffer.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +Part::Part(Node* node, bool default_collide) + : our_id_(node->AddPart(this)), + default_collides_(default_collide), + node_(node) { + assert(node_.exists()); + birth_time_ = node_->scene()->time(); + dynamics_ = node_->scene()->dynamics(); +} + +Part::~Part() = default; + +void Part::CheckBodies() { + for (auto&& i : rigid_bodies_) { + i->Check(); + } +} + +void Part::KillConstraints() { + for (auto&& i : rigid_bodies_) { + i->KillConstraints(); + } +} + +void Part::UpdateBirthTime() { birth_time_ = node_->scene()->time(); } + +auto Part::GetMaterials() const -> std::vector { + return RefsToPointers(materials_); +} + +void Part::SetMaterials(const std::vector& vals) { + assert(!Utils::HasNullMembers(vals)); + + // Hold strong refs to the materials passed. + materials_ = PointersToRefs(vals); + + // Wake us up in case our new materials make us stop colliding or whatnot. + // (we may be asleep resting on something we suddenly no longer hit) + Wake(); + + // Reset all of our active collisions so new collisions will take effect + // with the new materials. + for (auto&& i : collisions_) { + dynamics_->ResetCollision(node()->id(), id(), i.node, i.part); + } +} + +void Part::ApplyMaterials(MaterialContext* s, const Part* src_part, + const Part* dst_part) { + for (auto&& i : materials_) { + assert(i.exists()); + i->Apply(s, src_part, dst_part); + } +} + +auto Part::ContainsMaterial(const Material* m) const -> bool { + assert(m); + for (auto&& i : materials_) { + assert(i.exists()); + if (m == i.get()) { + return true; + } + } + return false; +} + +auto Part::IsCollidingWith(int64_t node, int part) const -> bool { + for (auto&& i : collisions_) { + if (i.node == node && i.part == part) return true; + } + return false; +} + +auto Part::IsCollidingWith(int64_t node) const -> bool { + for (auto&& i : collisions_) { + if (i.node == node) { + return true; + } + } + return false; +} + +void Part::SetCollidingWith(int64_t node_id, int part, bool colliding, + bool physical) { + if (colliding) { + // Add this to our list of collisions if its not on it. + for (auto&& i : collisions_) { + if (i.node == node_id && i.part == part) { + BA_PRECONDITION(node()); + Log("Error: Got SetCollidingWith for part already colliding with."); + return; + } + } + collisions_.emplace_back(node_id, part); + + } else { + // Make sure our bodies are awake - we may have been asleep + // resting on something that no longer exists. + if (physical) { + Wake(); + } + + // Remove the part from our colliding-with list. + for (auto i = collisions_.begin(); i != collisions_.end(); ++i) { + if (i->node == node_id && i->part == part) { + collisions_.erase(i); + return; + } + } + Log("Error: Got SetCollidingWith (separated) call for part we're " + "not colliding with."); + } +} + +auto Part::GetAge() const -> millisecs_t { + assert(node_.exists()); + assert(node_->scene()->time() >= birth_time_); + return node_->scene()->time() - birth_time_; +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/part.h b/src/ballistica/dynamics/part.h new file mode 100644 index 00000000..b0bc494f --- /dev/null +++ b/src/ballistica/dynamics/part.h @@ -0,0 +1,139 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_PART_H_ +#define BALLISTICA_DYNAMICS_PART_H_ + +#include + +#include "ballistica/core/object.h" +#include "ballistica/dynamics/rigid_body.h" + +namespace ballistica { + +// A categorized "part" of a node which contains collision and other grouping +// information for a set of rigid bodies composing the part. +// Each rigid body is contained in exactly one part. +class Part : public Object { + public: + explicit Part(Node* node, bool default_collide = true); + ~Part() override; + auto id() const -> int { return our_id_; } + + // Used by RigidBodies when adding themselves to the part. + void AddBody(RigidBody* rigid_body_in) { + rigid_bodies_.push_back(rigid_body_in); + } + + // Used by RigidBodies when removing themselves from the part. + void RemoveBody(RigidBody* rigid_body_in) { + for (auto i = rigid_bodies_.begin(); i != rigid_bodies_.end(); ++i) { + if (*i == rigid_body_in) { + rigid_bodies_.erase(i); + return; + } + } + throw Exception(); + } + + // Wakes up all rigid bodies in the part. + void Wake() { + for (auto&& i : rigid_bodies_) { + i->Wake(); + } + } + auto node() const -> Node* { + assert(node_.exists()); + return node_.get(); + } + + // Apply a set of materials to the part. + // Note than anytime a part's material set is changed, + // All collisions occurring between it and other parts are reset, + // so the old material set's separation commands will run and then + // the new material's collide commands will run (if there is still a + // collision) + void SetMaterials(const std::vector& vals); + auto GetMaterials() const -> std::vector; + + // Apply this part's materials to a context. + void ApplyMaterials(MaterialContext* s, const Part* src_part, + const Part* dst_part); + + // Returns true if the material is directly attached to the part + // note that having a material that calls the requested material does + // not count. + auto ContainsMaterial(const Material* m) const -> bool; + + // Returns whether the part is currently colliding with the specified node. + auto IsCollidingWith(int64_t node) const -> bool; + + // Returns whether the part is currently colliding with the specified + // node/part combo. + auto IsCollidingWith(int64_t node, int part) const -> bool; + + // Used by g_game to inform us we're now colliding with another part + // if colliding is false, we've stopped colliding with this part. + void SetCollidingWith(int64_t node_id, int part, bool colliding, + bool physical); + + // Kill constraints for all bodies in the part + // (useful when teleporting and things like that). + void KillConstraints(); + auto default_collides() const -> bool { return default_collides_; } + auto GetAge() const -> millisecs_t; + + // Birthtime can be used to prevent spawning or teleporting parts from + // colliding with things they are overlapping. + // Any part with teleporting parts should use this to + // reset their birth times. Nodes have a function to do so for all their + // contained parts as well. + void UpdateBirthTime(); + auto last_impact_sound_time() const -> millisecs_t { + return last_impact_sound_time_; + } + auto last_skid_sound_time() const -> millisecs_t { + return last_skid_sound_time_; + } + auto last_roll_sound_time() const -> millisecs_t { + return last_roll_sound_time_; + } + void set_last_impact_sound_time(millisecs_t t) { + last_impact_sound_time_ = t; + } + void set_last_skid_sound_time(millisecs_t t) { last_skid_sound_time_ = t; } + void set_last_roll_sound_time(millisecs_t t) { last_roll_sound_time_ = t; } + + auto rigid_bodies() const -> const std::vector& { + return rigid_bodies_; + } + + // Debugging: check for NaNs and whatnot. + void CheckBodies(); + + private: + Dynamics* dynamics_; + class Collision { + public: + int node; + int part; + Collision(int node_in, int part_in) : node(node_in), part(part_in) {} + }; + + // Collisions currently affecting us stored for quick access. + std::vector collisions_; + bool default_collides_; + millisecs_t birth_time_; + int our_id_; + Object::WeakRef node_; + std::vector > materials_; + std::vector rigid_bodies_; + + // Last time this part played a collide sound (used by the audio system). + millisecs_t last_impact_sound_time_ = 0; + millisecs_t last_skid_sound_time_ = 0; + millisecs_t last_roll_sound_time_ = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_PART_H_ diff --git a/src/ballistica/dynamics/rigid_body.cc b/src/ballistica/dynamics/rigid_body.cc new file mode 100644 index 00000000..95a70fa8 --- /dev/null +++ b/src/ballistica/dynamics/rigid_body.cc @@ -0,0 +1,693 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/dynamics/rigid_body.h" + +#include + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/part.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/scene/scene.h" +#include "ode/ode_collision_util.h" + +namespace ballistica { + +// whether to send our net states as half float format +#define USE_HALF_FLOATS 1 + +#define EMBED_POS_FLOAT Utils::EmbedFloat32 +#define EXTRACT_POS_FLOAT Utils::ExtractFloat32 +#define POS_FLOAT_DATA_SIZE 4 + +#if USE_HALF_FLOATS +#define FLOAT_DATA_SIZE 2 +#define EMBED_FLOAT Utils::EmbedFloat16NBO +#define EXTRACT_FLOAT Utils::ExtractFloat16NBO +#else +#define FLOAT_DATA_SIZE 4 +#define EMBED_FLOAT Utils::EmbedFloat32 +#define EXTRACT_FLOAT Utils::ExtractFloat32 +#endif + +#define ABSOLUTE_EPSILON 0.001f + +RigidBody::RigidBody(int id_in, Part* part_in, Type type_in, Shape shape_in, + uint32_t collide_type_in, uint32_t collide_mask_in, + CollideModel* collide_model_in, uint32_t flags) + : type_(type_in), + id_(id_in), + creation_time_(part_in->node()->scene()->time()), + shape_(shape_in), + part_(part_in), + collide_model_(collide_model_in), + collide_type_(collide_type_in), + collide_mask_(collide_mask_in), + flags_(flags) { + blend_time_ = creation_time_; + +#if BA_DEBUG_BUILD + for (int i = 0; i < 3; i++) { + prev_pos_[i] = prev_vel_[i] = prev_a_vel_[i] = 0.0f; + } +#endif // BA_DEBUG_BUILD + + assert(part_.exists()); + birth_time_ = part_->node()->scene()->stepnum(); + dynamics_ = part_->node()->scene()->dynamics(); + + // Add ourself to the part. + part_->AddBody(this); + + // Create the geom(s). + switch (shape_) { + case Shape::kSphere: { + dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.3f; + geoms_.resize(1); + geoms_[0] = dCreateSphere(dynamics_->space(), dimensions_[0]); + break; + } + + case Shape::kBox: { + dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.6f; + geoms_.resize(1); + geoms_[0] = dCreateBox(dynamics_->space(), dimensions_[0], dimensions_[1], + dimensions_[2]); + break; + } + + case Shape::kCapsule: { + dimensions_[0] = dimensions_[1] = 0.3f; + geoms_.resize(1); + geoms_[0] = + dCreateCCylinder(dynamics_->space(), dimensions_[0], dimensions_[1]); + break; + } + + case Shape::kCylinder: { + int sphere_count = 8; + float inc = 360.0f / static_cast(sphere_count); + + // Transform geom and sphere. + geoms_.resize(static_cast(2 * sphere_count + 1)); + dimensions_[0] = dimensions_[1] = 0.3f; + float sub_rad = dimensions_[1] * 0.5f; + float offset = dimensions_[0] - sub_rad; + for (int i = 0; i < sphere_count; i++) { + Vector3f p = + Matrix44fRotate(Vector3f(0, 1, 0), static_cast(i) * inc) + * Vector3f(offset, 0, 0); + geoms_[i * 2] = dCreateGeomTransform(dynamics_->space()); + geoms_[i * 2 + 1] = dCreateSphere(nullptr, sub_rad); + dGeomTransformSetGeom(geoms_[i * 2], geoms_[i * 2 + 1]); + dGeomSetPosition(geoms_[i * 2 + 1], p.v[0], p.v[1], p.v[2]); + } + + // One last center sphere to keep stuff from getting stuck in our middle. + geoms_[geoms_.size() - 1] = dCreateSphere(dynamics_->space(), sub_rad); + + break; + } + + case Shape::kTrimesh: { + // NOTE - we don't add trimeshes do the collision space - we handle them + // specially.. + dimensions_[0] = dimensions_[1] = dimensions_[2] = 0.6f; + assert(collide_model_.exists()); + collide_model_->collide_model_data()->Load(); + dGeomID g = dCreateTriMesh( + nullptr, collide_model_->collide_model_data()->GetMeshData(), nullptr, + nullptr, nullptr); + geoms_.push_back(g); + dynamics_->AddTrimesh(g); + break; + } + + default: + throw Exception(); + } + + for (auto&& i : geoms_) { + dGeomSetData(i, this); + } + + if (type_ == Type::kBody) { + assert(body_ == nullptr); + body_ = dBodyCreate(dynamics_->ode_world()); + + // For cylinders we only set the transform geoms, not the spheres. + if (shape_ == Shape::kCylinder) { + for (size_t i = 0; i < geoms_.size(); i += 2) { + dGeomSetBody(geoms_[i], body_); + } + // Our center sphere. + dGeomSetBody(geoms_[geoms_.size() - 1], body_); + } else { + dGeomSetBody(geoms_[0], body_); + } + } + SetDimensions(dimensions_[0], dimensions_[1], dimensions_[2]); +} + +void RigidBody::Check() { + if (type_ == Type::kBody) { + const dReal* p = dBodyGetPosition(body_); + const dReal* q = dBodyGetQuaternion(body_); + const dReal* lv = dBodyGetLinearVel(body_); + const dReal* av = dBodyGetAngularVel(body_); + bool err = false; + for (int i = 0; i < 3; i++) { + if (std::isnan(p[i]) || std::isnan(q[i]) || std::isnan(lv[i]) + || std::isnan(av[i])) { + err = true; + break; + } + if (std::abs(p[i]) > 9999) err = true; + if (std::abs(lv[i]) > 99999) err = true; + if (std::abs(av[i]) > 9999) err = true; + } + if (std::isnan(q[3])) err = true; + + if (err) { + Log("Error: Got error in rbd values!"); + } +#if BA_DEBUG_BUILD + for (int i = 0; i < 3; i++) { + prev_pos_[i] = p[i]; + prev_vel_[i] = lv[i]; + prev_a_vel_[i] = av[i]; + } +#endif + } +} + +RigidBody::~RigidBody() { + if (shape_ == Shape::kTrimesh) { + assert(geoms_.size() == 1); + dynamics_->RemoveTrimesh(geoms_[0]); + } + + // if we have any joints attached, kill them + KillConstraints(); + + // remove ourself from our parent part if we have one + if (part_.exists()) { + part_->RemoveBody(this); + } + if (type_ == Type::kBody) { + assert(body_); + dBodyDestroy(body_); + body_ = nullptr; + } + assert(!geoms_.empty()); + for (auto&& i : geoms_) { + dGeomDestroy(i); + } +} + +void RigidBody::KillConstraints() { + while (joints_.begin() != joints_.end()) { + (**joints_.begin()).Kill(); + } +} + +auto RigidBody::GetEmbeddedSizeFull() -> int { + assert(type_ == Type::kBody); + + const dReal* lv = dBodyGetLinearVel(body_); + const dReal* av = dBodyGetAngularVel(body_); + + // always have 3 position, 4 quaternion, and 1 flag + int full_size = 3 * POS_FLOAT_DATA_SIZE + FLOAT_DATA_SIZE * 4 + 1; + + // we only send velocity values that are non-zero - calculate how many of + // them we have + for (int i = 0; i < 3; i++) { + full_size += FLOAT_DATA_SIZE * (std::abs(lv[i] - 0) > ABSOLUTE_EPSILON); + full_size += FLOAT_DATA_SIZE * (std::abs(av[i] - 0) > ABSOLUTE_EPSILON); + } + return full_size; +} + +// store a body to a buffer +// FIXME - theoretically we should embed birth-time +// as this can affect collisions with this object +void RigidBody::EmbedFull(char** buffer) { + assert(type_ == Type::kBody); + + const dReal* p = dBodyGetPosition(body_); + const dReal* q = dBodyGetQuaternion(body_); + const dReal* lv = dBodyGetLinearVel(body_); + const dReal* av = dBodyGetAngularVel(body_); + bool enabled = static_cast(dBodyIsEnabled(body_)); + bool lv_changed[3]; + bool av_changed[3]; + + // only send velocities that are non-zero. + // we always send position/rotation since that's not likely to be zero + for (int i = 0; i < 3; i++) { + lv_changed[i] = (std::abs(lv[i] - 0) > ABSOLUTE_EPSILON); + av_changed[i] = (std::abs(av[i] - 0) > ABSOLUTE_EPSILON); + } + + // embed a byte containing our enabled state as well as what velocities need + // to be sent + Utils::EmbedBools(buffer, lv_changed[0], lv_changed[1], lv_changed[2], + av_changed[0], av_changed[1], av_changed[2], enabled); + + EMBED_POS_FLOAT(buffer, p[0]); + EMBED_POS_FLOAT(buffer, p[1]); + EMBED_POS_FLOAT(buffer, p[2]); + + EMBED_FLOAT(buffer, q[0]); + EMBED_FLOAT(buffer, q[1]); + EMBED_FLOAT(buffer, q[2]); + EMBED_FLOAT(buffer, q[3]); + + for (int i = 0; i < 3; i++) { + if (lv_changed[i]) { + EMBED_FLOAT(buffer, lv[i]); + } + if (av_changed[i]) { + EMBED_FLOAT(buffer, av[i]); + } + } +} + +// Position a body from buffer data. +void RigidBody::ExtractFull(const char** buffer) { + assert(type_ == Type::kBody); + + dReal p[3], lv[3], av[3]; + dQuaternion q; + + bool lv_changed[3]; + bool av_changed[3]; + bool enabled; + + // Extract our byte telling which velocities are contained here as well as our + // enable state. + Utils::ExtractBools(buffer, &lv_changed[0], &lv_changed[1], &lv_changed[2], + &av_changed[0], &av_changed[1], &av_changed[2], &enabled); + + p[0] = EXTRACT_POS_FLOAT(buffer); + p[1] = EXTRACT_POS_FLOAT(buffer); + p[2] = EXTRACT_POS_FLOAT(buffer); + + q[0] = EXTRACT_FLOAT(buffer); + q[1] = EXTRACT_FLOAT(buffer); + q[2] = EXTRACT_FLOAT(buffer); + q[3] = EXTRACT_FLOAT(buffer); + + for (int i = 0; i < 3; i++) { + if (lv_changed[i]) { + lv[i] = EXTRACT_FLOAT(buffer); + } else { + lv[i] = 0; + } + + if (av_changed[i]) { + av[i] = EXTRACT_FLOAT(buffer); + } else { + av[i] = 0; + } + } + + dBodySetPosition(body_, p[0], p[1], p[2]); + dBodySetQuaternion(body_, q); + dBodySetLinearVel(body_, lv[0], lv[1], lv[2]); + dBodySetAngularVel(body_, av[0], av[1], av[2]); + + if (enabled) { + dBodyEnable(body_); + } else { + dBodyDisable(body_); + } +} + +void RigidBody::Draw(RenderPass* pass, bool shaded) { + assert(pass); + RenderPass::Type pass_type = pass->type(); + // only passes we draw in are light_shadow and beauty + if (pass_type != RenderPass::Type::kLightShadowPass + && pass_type != RenderPass::Type::kBeautyPass) { + return; + } + // assume trimeshes are landscapes and shouldn't be in shadow passes.. + if (shape_ == Shape::kTrimesh + && (pass_type != RenderPass::Type::kBeautyPass)) { + return; + } +} + +void RigidBody::AddCallback(CollideCallbackFunc callbackIn, void* data_in) { + CollideCallback c{}; + c.callback = callbackIn; + c.data = data_in; + collide_callbacks_.push_back(c); +} + +auto RigidBody::CallCollideCallbacks(dContact* contacts, int count, + RigidBody* opposingbody) -> bool { + for (auto&& i : collide_callbacks_) { + if (!i.callback(contacts, count, this, opposingbody, i.data)) { + return false; + } + } + return true; +} + +void RigidBody::SetDimensions(float d1, float d2, float d3, float m1, float m2, + float m3, float density_mult) { + dimensions_[0] = d1; + dimensions_[1] = d2; + dimensions_[2] = d3; + + if (m1 == 0.0f) m1 = d1; + if (m2 == 0.0f) m2 = d2; + if (m3 == 0.0f) m3 = d3; + + float density = 5.0f * density_mult; + + switch (shape_) { + case Shape::kSphere: + dGeomSphereSetRadius(geoms_[0], dimensions_[0]); + break; + case Shape::kBox: + dGeomBoxSetLengths(geoms_[0], dimensions_[0], dimensions_[1], + dimensions_[2]); + break; + case Shape::kCapsule: + dGeomCCylinderSetParams(geoms_[0], dimensions_[0], dimensions_[1]); + break; + case Shape::kCylinder: { + int sphere_count = static_cast(geoms_.size() / 2); + float inc = 360.0f / static_cast(sphere_count); + float sub_rad = dimensions_[1] * 0.5f; + float offset = dimensions_[0] - sub_rad; + for (int i = 0; i < sphere_count; i++) { + Vector3f p = + Matrix44fRotate(Vector3f(0, 0, 1), static_cast(i) * inc) + * Vector3f(offset, 0, 0); + dGeomSphereSetRadius(geoms_[i * 2 + 1], sub_rad); + dGeomSetPosition(geoms_[i * 2 + 1], p.v[0], p.v[1], p.v[2]); + } + // Resize our center sphere. + dGeomSphereSetRadius(geoms_[geoms_.size() - 1], sub_rad); + } + // A cylinder is really just a bunch of spheres - we just need to set the + // length of their offsets. + // dGeomBoxSetLengths(geoms[0],dimensions[0],dimensions[0],dimensions[1]); + break; + case Shape::kTrimesh: + break; + default: + throw Exception(); + } + + // Create the body and set mass properties. + if (type_ == Type::kBody) { + dMass m; + switch (shape_) { + case Shape::kSphere: + dMassSetSphere(&m, density, m1); + break; + case Shape::kBox: + dMassSetBox(&m, density, m1, m2, m3); + break; + case Shape::kCapsule: + dMassSetCappedCylinder(&m, density, 3, m1, m2); + break; + case Shape::kCylinder: + dMassSetCylinder(&m, density, 3, m1, m2); + break; + case Shape::kTrimesh: // NOLINT(bugprone-branch-clone) + // Trimesh bodies not supported yet. + throw Exception(); + default: + throw Exception(); + } + + // Need to handle groups here. + assert(geoms_.size() == 1 || shape_ == Shape::kCylinder); + dBodySetMass(body_, &m); + } +} + +auto RigidBody::ApplyImpulse(float px, float py, float pz, float vx, float vy, + float vz, float fdirx, float fdiry, float fdirz, + float mag, float v_mag, float radius, + bool calc_only) -> float { + assert(body_); + float total_mag = 0.0f; + + dMass mass; + dBodyGetMass(body_, &mass); + + bool horizontal_only = false; + + // FIXME - some hard-coded tweaks for the hockey-puck + if (shape_ == Shape::kCylinder) { + py -= 0.3f; + if (v_mag > 0.0f) { + v_mag *= 0.06f; // punches + } else { + mag *= 3.0f; // amp up explosions + } + horizontal_only = true; + } + + if (radius <= 0.0f) { + // Damage based on velocity difference.. lets just plug in our + // center-of-mass velocity (otherwise we might get crazy large velocity + // diffs due to spinning). + + // Ok for now we're not taking our velocity into account. + dVector3 our_velocity = {0, 0, 0}; + + dVector3 v_diff = {vx - our_velocity[0], vy - our_velocity[1], + vz - our_velocity[2]}; + + dVector3 f = {fdirx, fdiry, fdirz}; + + // normalize.. + float fDirLen = sqrtf(fdirx * fdirx + fdiry * fdiry + fdirz * fdirz); + if (fDirLen > 0.0f) { + f[0] /= fDirLen; + f[1] /= fDirLen; + f[2] /= fDirLen; + } else { + f[0] = 1.0f; // just use (1,0,0) + } + + // Lets only take large velocity diffs into account. + // float vLen = std::max(0.0f,dVector3Length(v_diff)-2.0f); + float vLen = dVector3Length(v_diff); + + total_mag = mag + vLen * v_mag; + + f[0] *= total_mag; + f[1] *= total_mag; + f[2] *= total_mag; + + // Exaggerate the force we apply in y (but don't count it towards damage). + f[1] *= 2.0f; + + // General scale up. + f[0] *= 1.8f; + f[1] *= 1.8f; + f[2] *= 1.8f; + + if (horizontal_only) { + f[1] = 0.0f; + py = dBodyGetPosition(body_)[1]; + } + + if (!calc_only) { + dBodyEnable(body_); + dBodyAddForceAtPos(body_, f[0], f[1], f[2], px, py, pz); + } + + } else { + // With radius. + Vector3f us(dBodyGetPosition(body_)); + Vector3f them(px, py, pz); + if (them == us) { + them = us + Vector3f(0.0f, 0.001f, 0.0f); + } + Vector3f diff = them - us; + float len = (them - us).Length(); + if (len == 0.0f) { + len = 0.0001f; + } + + if (len < radius) { + float amt = 1.0f - (len / radius); + + if (v_mag > 0.0f) { + throw Exception("FIXME - handle vmag for radius>0 case"); + } + + // Factor in our mass so a given impulse affects various sized things + // equally. + float this_mag = (mag * amt) * mass.mass; + + // amt *= amt; // squared falloff.. + // amt = pow(amt, 1.5f); // biased falloff + + total_mag += this_mag; + + Vector3f f = diff * (-this_mag / len); + + // Randomize applied force a bit to keep things from looking too clean and + // simple. + const dReal* pos = dBodyGetPosition(body_); + dReal apply_pos[3] = {pos[0] + 0.6f * (RandomFloat() - 0.5f), + pos[1] + 0.6f * (RandomFloat() - 0.5f), + pos[2] + 0.6f * (RandomFloat() - 0.5f)}; + + if (horizontal_only) { + f.y = 0.0f; + apply_pos[1] = us.y; + } + + // Exaggerate up/down component. + f.x *= 0.5f; + if (f.y > 0.0f) { + f.y *= 2.0f; + } + f.z *= 0.5f; + + if (!calc_only) { + dBodyEnable(body_); + dBodyAddForceAtPos(body_, f.x, f.y, f.z, apply_pos[0], apply_pos[1], + apply_pos[2]); + } + } + } + return total_mag; +} + +void RigidBody::ApplyGlobalImpulse(float px, float py, float pz, float fx, + float fy, float fz) { + if (type_ != Type::kBody) { + return; + } + dBodyEnable(body_); + dBodyAddForceAtPos(body_, fx / kGameStepSeconds, fy / kGameStepSeconds, + fz / kGameStepSeconds, px, py, pz); +} + +RigidBody::Joint::Joint() = default; + +void RigidBody::Joint::SetJoint(dxJointFixed* id_in, Scene* scene) { + Kill(); + creation_time_ = scene->time(); + id_ = id_in; +} + +RigidBody::Joint::~Joint() { Kill(); } + +void RigidBody::Joint::AttachToBodies(RigidBody* b1_in, RigidBody* b2_in) { + assert(id_); + b1_ = b1_in; + b2_ = b2_in; + dBodyID b_id_1 = nullptr; + dBodyID b_id_2 = nullptr; + if (b1_) { + b1_->Wake(); + b1_->AddJoint(this); + b_id_1 = b1_->body(); + } + if (b2_) { + b2_->Wake(); + b2_->AddJoint(this); + b_id_2 = b2_->body(); + } + dJointAttach(id_, b_id_1, b_id_2); +} + +void RigidBody::Joint::Kill() { + if (id_) { + if (b1_) { + b1_->RemoveJoint(this); + + // Also wake the body (this joint could be suspending it motionless). + assert(b1_->body()); + dBodyEnable(b1_->body()); + } + if (b2_) { + b2_->RemoveJoint(this); + + // Also wake the body (this joint could be suspending it motionless). + assert(b2_->body()); + dBodyEnable(b2_->body()); + } + dJointDestroy(id_); + id_ = nullptr; + b1_ = b2_ = nullptr; + } +} + +auto RigidBody::GetTransform() -> Matrix44f { + Matrix44f matrix{kMatrix44fIdentity}; + const dReal* pos_in; + const dReal* r_in; + if (type() == RigidBody::Type::kBody) { + pos_in = dBodyGetPosition(body()); + r_in = dBodyGetRotation(body()); + } else { + pos_in = dGeomGetPosition(geom()); + r_in = dGeomGetRotation(geom()); + } + float pos[3]; + float r[12]; + for (int x = 0; x < 3; x++) { + pos[x] = pos_in[x]; + } + pos[0] += blend_offset().x; + pos[1] += blend_offset().y; + pos[2] += blend_offset().z; + for (int x = 0; x < 12; x++) { + r[x] = r_in[x]; + } + matrix.m[0] = r[0]; + matrix.m[1] = r[4]; + matrix.m[2] = r[8]; + matrix.m[3] = 0; + matrix.m[4] = r[1]; + matrix.m[5] = r[5]; + matrix.m[6] = r[9]; + matrix.m[7] = 0; + matrix.m[8] = r[2]; + matrix.m[9] = r[6]; + matrix.m[10] = r[10]; + matrix.m[11] = 0; + matrix.m[12] = pos[0]; + matrix.m[13] = pos[1]; + matrix.m[14] = pos[2]; + matrix.m[15] = 1; + return matrix; +} + +void RigidBody::AddBlendOffset(float x, float y, float z) { + // blend_offset_.x += x; + // blend_offset_.y += y; + // blend_offset_.z += z; +} + +void RigidBody::UpdateBlending() { + // FIXME - this seems broken. We never update blend_time_ currently + // and its also set to time whereas we're comparing it with steps. + // Should revisit. + // millisecs_t diff = part()->node()->scene()->stepnum() - blend_time_; + // diff = std::min(millisecs_t{10}, diff); + // for (millisecs_t i = 0; i < diff; i++) { + // blend_offset_.x *= 0.995f; + // blend_offset_.y *= 0.995f; + // blend_offset_.z *= 0.995f; + // } +} + +} // namespace ballistica diff --git a/src/ballistica/dynamics/rigid_body.h b/src/ballistica/dynamics/rigid_body.h new file mode 100644 index 00000000..0bbb70c3 --- /dev/null +++ b/src/ballistica/dynamics/rigid_body.h @@ -0,0 +1,215 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_DYNAMICS_RIGID_BODY_H_ +#define BALLISTICA_DYNAMICS_RIGID_BODY_H_ + +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/math/matrix44f.h" +#include "ode/ode.h" +#include "ode/ode_joint.h" + +namespace ballistica { + +// Wrapper for ode rigid bodies which implements collision tracking, +// flattening/restoring, and other extras. +class RigidBody : public Object { + public: + // Function type for low level collision callbacks. + // These callbacks are called just before collision constraints + // are being created between rigid bodies. These callback + // should be used only for contact adjustment - things like + // changing friction depending on what part of the body was hit, etc. + // Never use these callbacks to run script command or anything high-level. + // Return false to cancel all constraint creation. + typedef bool (*CollideCallbackFunc)(dContact* contacts, int count, + RigidBody* collide_body, + RigidBody* opposingbody, + void* custom_data); + enum class Type { + // Collidable but not dynamically affected object. + // Used to generate collisions. + kGeomOnly, + // Collidable as well as dynamically affected object. + kBody + }; + + // Used to determine what kind of surface a body has and what surfaces it will + // collide against a body defines its own collide type(s) and its mask for + // what it will collide against collisions will only occur if each body's + // collide mask includes the opposite body's type(s). + enum CollideType { + kCollideNone = 0, + // Static background objects such as landscapes + // These never move and generally never need to test for collisions against + // other landscapes + kCollideBackground = 0x01u, + // Regions - these generally only test for collisions with active bodies + kCollideRegion = 0x01u << 2u, + // Active bodies - these generally collide against everything + kCollideActive = 0x01u << 3u, + // encapsulates all collide types + kCollideAll = kCollideBackground | kCollideRegion | kCollideActive + }; + + // Different kinds of geometry a body can be. + enum class Shape { + // Simple sphere shape + kSphere, + // Simple cube shape + kBox, + // Capsule + kCapsule, + // cylinder made from 4 cubes (8 sides) + kCylinder, + // Trimesh + kTrimesh + }; + + enum Flag { + // The body is a 'bumper' - something that under-control character bodies + // might want to collide with but most other stuff won't want to. + kIsBumper = 1u << 0u, + kIsRoller = 1u << 1u, + kIsTerrain = 1u << 2u + }; + + // these are needed for full states + auto GetEmbeddedSizeFull() -> int; + void ExtractFull(const char** buffer); + void EmbedFull(char** buffer); + RigidBody(int id_in, Part* part_in, Type type_in, Shape shape_in, + uint32_t collide_type_in, uint32_t collide_mask_in, + CollideModel* collide_model_in = nullptr, uint32_t flags = 0); + ~RigidBody() override; + auto body() const -> dBodyID { return body_; } + auto geom(int i = 0) const -> dGeomID { return geoms_[i]; } + + // Draw a representation of the rigid body for debugging. + void Draw(RenderPass* pass, bool shaded = true); + auto part() const -> Part* { + assert(part_.exists()); + return part_.get(); + } + void Wake() { + if (body_) { + dBodyEnable(body_); + } + } + void AddCallback(CollideCallbackFunc callback_in, void* data_in); + auto CallCollideCallbacks(dContact* contacts, int count, + RigidBody* opposingbody) -> bool; + void SetDimensions( + float d1, float d2 = 0.0f, float d3 = 0.0f, // body dimensions + float m1 = 0.0f, float m2 = 0.0f, + float m3 = 0.0f, // Mass dimensions (default to regular if zero). + float density = 1.0f); + + // If geomWakeOnCollide is true, a GEOM_ONLY object colliding with a sleeping + // body will wake it up. Generally this should be true if the geom is moving + // or changing. + void set_geom_wake_on_collide(bool enable) { geom_wake_on_collide_ = enable; } + auto geom_wake_on_collide() const -> bool { return geom_wake_on_collide_; } + auto id() const -> int { return id_; } + void ApplyGlobalImpulse(float px, float py, float pz, float fx, float fy, + float fz); + auto ApplyImpulse(float px, float py, float pz, float vx, float vy, float vz, + float fdirx, float fdiry, float fdirz, float mag, + float v_mag, float radiusm, bool calc_only) -> float; + void KillConstraints(); + + // Rigid body joint wrapper. This takes ownership of joints it is passed + // all joints should use this mechanism so they are automatically + // cleaned up when bodies are destroyed. + class Joint { + public: + Joint(); + ~Joint(); + + // Attach this wrapper to a new ode joint. + // If already attached to a joint, that joint is first killed. + void SetJoint(dxJointFixed* id, Scene* sg); + + // Returns the ode joint id or nullptr if it has been killed + // (by the other body dying, etc). + auto joint() const -> dJointID { return id_; } + + // Always use this in place of dJointAttach to attach the joint to rigid + // bodies. + void AttachToBodies(RigidBody* b1, RigidBody* b2); + void Kill(); // Kills the joint if it is valid. + // Whether joint still exists. + auto IsAlive() const -> bool { return id_ != nullptr; } + + private: + millisecs_t creation_time_{}; + dxJointFixed* id_{}; + RigidBody* b1_{}; + RigidBody* b2_{}; + }; + + // Used by Joint. + void AddJoint(Joint* j) { joints_.push_back(j); } + void RemoveJoint(Joint* j) { + for (auto i = joints_.begin(); i != joints_.end(); i++) { + if ((*i) == j) { + joints_.erase(i); + return; + } + } + } + void Check(); + auto type() const -> Type { return type_; } + auto collide_type() const -> uint32_t { return collide_type_; } + auto collide_mask() const -> uint32_t { return collide_mask_; } + auto flags() const -> uint32_t { return flags_; } + void set_flags(uint32_t flags) { flags_ = flags; } + auto can_cause_impact_damage() const -> bool { + return can_cause_impact_damage_; + } + void set_can_cause_impact_damage(bool val) { can_cause_impact_damage_ = val; } + + // Applies to spheres. + auto radius() const -> float { return dimensions_[0]; } + auto GetTransform() -> Matrix44f; + void UpdateBlending(); + void AddBlendOffset([[maybe_unused]] float x, float y, float z); + auto blend_offset() const -> const Vector3f& { return blend_offset_; } + + private: + Vector3f blend_offset_{0.0f, 0.0f, 0.0f}; + millisecs_t blend_time_{}; +#if BA_DEBUG_BUILD + float prev_pos_[3]{}; + float prev_vel_[3]{}; + float prev_a_vel_[3]{}; +#endif + millisecs_t creation_time_{}; + bool can_cause_impact_damage_{}; + Dynamics* dynamics_{}; + uint32_t collide_type_{}; + uint32_t collide_mask_{}; + std::list joints_; + bool geom_wake_on_collide_{}; + int id_{}; + Object::Ref collide_model_; + float dimensions_[3]{}; + Type type_{}; + Shape shape_{}; + dBodyID body_{}; + std::vector geoms_; + millisecs_t birth_time_{}; + Object::WeakRef part_; + struct CollideCallback { + CollideCallbackFunc callback; + void* data; + }; + std::vector collide_callbacks_; + uint32_t flags_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_DYNAMICS_RIGID_BODY_H_ diff --git a/src/ballistica/game/connection/connection.h b/src/ballistica/game/connection/connection.h new file mode 100644 index 00000000..3629ac85 --- /dev/null +++ b/src/ballistica/game/connection/connection.h @@ -0,0 +1,145 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_CONNECTION_CONNECTION_H_ +#define BALLISTICA_GAME_CONNECTION_CONNECTION_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/game/player_spec.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +// Start near the top of the range to make sure looping works as expected. +const int kFirstConnectionStateNum = 65520; + +/// Connection to a remote session; either as a host or client. +class Connection : public Object { + public: + Connection(); + + // Send a reliable message to the client + // these will always be delivered in the order sent + void SendReliableMessage(const std::vector& data); + + // Send an unreliable message to the client; these are not guaranteed + // to be delivered, but when they are, they're delivered properly in order + // between other unreliable/reliable messages. + void SendUnreliableMessage(const std::vector& data); + + // Send a json-based reliable message. + void SendJMessage(cJSON* val); + virtual void Update(); + + // Called with raw packets as they come in from the network. + virtual void HandleGamePacket(const std::vector& buffer); + + // Called when the next in-order message is available. + virtual void HandleMessagePacket(const std::vector& buffer) = 0; + + // Request an orderly disconnect. + virtual void RequestDisconnect() = 0; + + auto GetBytesOutPerSecond() const -> int64_t { return last_bytes_out_; } + auto GetBytesOutPerSecondCompressed() const -> int64_t { + return last_bytes_out_compressed_; + } + auto GetMessagesOutPerSecond() const -> int64_t { + return last_packet_count_out_; + } + auto GetMessageResendsPerSecond() const -> int64_t { + return last_resend_packet_count_; + } + auto GetBytesInPerSecond() const -> int64_t { return last_bytes_in_; } + auto GetBytesInPerSecondCompressed() const -> int64_t { + return last_bytes_in_compressed_; + } + auto GetMessagesInPerSecond() const -> int64_t { + return last_packet_count_in_; + } + auto GetBytesResentPerSecond() const -> int64_t { + return last_resend_bytes_out_; + } + auto average_ping() const -> float { return average_ping_; } + auto can_communicate() const -> bool { return can_communicate_; } + auto peer_spec() const -> const PlayerSpec& { return peer_spec_; } + void HandleGamePacketCompressed(const std::vector& data); + auto errored() const -> bool { return errored_; } + auto creation_time() const -> millisecs_t { return creation_time_; } + auto multipart_buffer_size() const -> size_t { + return multipart_buffer_.size(); + } + + protected: + void SendGamePacket(const std::vector& data); + virtual void SendGamePacketCompressed(const std::vector& data) = 0; + void ErrorSilent() { Error(""); } + virtual void Error(const std::string& error_msg); + void set_peer_spec(const PlayerSpec& spec) { peer_spec_ = spec; } + void set_can_communicate(bool val) { can_communicate_ = val; } + void set_connection_dying(bool val) { connection_dying_ = val; } + void set_errored(bool val) { errored_ = val; } + + private: + void ProcessWaitingMessages(); + void HandleResends(millisecs_t real_time, const std::vector& data, + int offset); + void EmbedAcks(millisecs_t real_time, std::vector* data, int offset); + std::vector multipart_buffer_; + + struct ReliableMessageIn { + std::vector data; + millisecs_t arrival_time; + }; + + struct ReliableMessageOut { + std::vector data; + millisecs_t first_send_time; + millisecs_t last_send_time; + millisecs_t resend_time; + bool acked; + }; + + // Leaf classes should set this when they start dying. + // This prevents any SendGamePacketCompressed() calls from happening. + bool connection_dying_{}; + float average_ping_{}; + int64_t last_resend_bytes_out_{}; + int64_t last_bytes_out_{}; + int64_t last_bytes_out_compressed_{}; + int64_t bytes_out_{}; + int64_t bytes_out_compressed_{}; + int64_t resend_bytes_out_{}; + int64_t last_packet_count_out_{}; + int64_t last_resend_packet_count_{}; + int64_t resend_packet_count_{}; + int64_t packet_count_out_{}; + int64_t last_bytes_in_{}; + int64_t last_bytes_in_compressed_{}; + int64_t bytes_in_{}; + int64_t bytes_in_compressed_{}; + int64_t last_packet_count_in_{}; + int64_t packet_count_in_{}; + millisecs_t last_average_update_time_{}; + millisecs_t creation_time_{}; + PlayerSpec peer_spec_; // Name of the account/device on the other end. + std::map in_messages_; + std::map out_messages_; + bool can_communicate_{}; + bool errored_{}; + millisecs_t last_prune_time_{}; + millisecs_t last_ack_send_time_{}; + + // These are explicitly 16 bit values. + uint16_t next_out_message_num_ = kFirstConnectionStateNum; + uint16_t next_out_unreliable_message_num_{}; + uint16_t next_in_message_num_ = kFirstConnectionStateNum; + uint16_t next_in_unreliable_message_num_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_CONNECTION_CONNECTION_H_ diff --git a/src/ballistica/game/connection/connection_to_client.h b/src/ballistica/game/connection/connection_to_client.h new file mode 100644 index 00000000..c234bea5 --- /dev/null +++ b/src/ballistica/game/connection/connection_to_client.h @@ -0,0 +1,76 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_CONNECTION_CONNECTION_TO_CLIENT_H_ +#define BALLISTICA_GAME_CONNECTION_CONNECTION_TO_CLIENT_H_ + +#include +#include +#include + +#include "ballistica/game/connection/connection.h" + +namespace ballistica { + +/// Connection to a party client if we're the host. +class ConnectionToClient : public Connection { + public: + explicit ConnectionToClient(int id); + ~ConnectionToClient() override; + void Update() override; + void HandleMessagePacket(const std::vector& buffer) override; + void HandleGamePacket(const std::vector& buffer) override; + auto id() const -> int { return id_; } + + // More efficient than dynamic_cast (hmm do we still want this?). + virtual auto GetAsUDP() -> ConnectionToClientUDP*; + void SetController(ClientControllerInterface* c); + auto GetPlayerProfiles() const -> PyObject* { return player_profiles_.get(); } + auto build_number() const -> int { return build_number_; } + void SendScreenMessage(const std::string& s, float r = 1.0f, float g = 1.0f, + float b = 1.0f); + auto token() const -> const std::string& { return token_; } + void HandleMasterServerClientInfo(PyObject* info_obj); + + /// Return the public id for this client. If they have not been verified + /// by the master-server, returns an empty string. + auto peer_public_account_id() const -> const std::string& { + return peer_public_account_id_; + } + + /// Return whether this client is an admin. Will only return true once their + /// account id has been verified by the master server. + auto IsAdmin() const -> bool; + + private: + virtual auto ShouldPrintIncompatibleClientErrors() const -> bool; + // Returns a spec for this client that incorporates their player names + // or their peer name if they have no players. + auto GetCombinedSpec() -> PlayerSpec; + auto GetClientInputDevice(int remote_id) -> ClientInputDevice*; + void Error(const std::string& error_msg) override; + std::string our_handshake_player_spec_str_; + std::string our_handshake_salt_; + std::string peer_public_account_id_; + ClientControllerInterface* controller_ = nullptr; + std::map client_input_devices_; + millisecs_t last_hand_shake_send_time_ = 0; + int id_ = -1; + int build_number_ = 0; + bool got_client_info_ = false; + bool kick_voted_ = false; + bool kick_vote_choice_ = false; + std::string token_; + std::string peer_hash_; + PythonRef player_profiles_; + bool got_info_from_master_server_ = false; + std::vector last_chat_times_; + millisecs_t next_kick_vote_allow_time_ = 0; + millisecs_t chat_block_time_ = 0; + millisecs_t last_remove_player_time_ = -99999; + int next_chat_block_seconds_ = 10; + friend class Game; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_CONNECTION_CONNECTION_TO_CLIENT_H_ diff --git a/src/ballistica/game/connection/connection_to_client_udp.h b/src/ballistica/game/connection/connection_to_client_udp.h new file mode 100644 index 00000000..357017ed --- /dev/null +++ b/src/ballistica/game/connection/connection_to_client_udp.h @@ -0,0 +1,40 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_CONNECTION_CONNECTION_TO_CLIENT_UDP_H_ +#define BALLISTICA_GAME_CONNECTION_CONNECTION_TO_CLIENT_UDP_H_ + +#include +#include +#include + +#include "ballistica/game/connection/connection_to_client.h" +#include "ballistica/networking/networking.h" + +namespace ballistica { + +// Connection to a party client if we're the host. +class ConnectionToClientUDP : public ConnectionToClient { + public: + ConnectionToClientUDP(const SockAddr& addr, std::string client_name, + uint8_t request_id, int client_id); + ~ConnectionToClientUDP() override; + void Update() override; + void HandleGamePacket(const std::vector& buffer) override; + auto client_name() const -> const std::string& { return client_name_; } + auto GetAsUDP() -> ConnectionToClientUDP* override; + void RequestDisconnect() override; + + protected: + uint8_t request_id_; + std::unique_ptr addr_; + std::string client_name_; + bool did_die_; + void Die(); + void SendDisconnectRequest(); + millisecs_t last_client_response_time_; + void SendGamePacketCompressed(const std::vector& data) override; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_CONNECTION_CONNECTION_TO_CLIENT_UDP_H_ diff --git a/src/ballistica/game/connection/connection_to_host.h b/src/ballistica/game/connection/connection_to_host.h new file mode 100644 index 00000000..40b0e74b --- /dev/null +++ b/src/ballistica/game/connection/connection_to_host.h @@ -0,0 +1,47 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_CONNECTION_CONNECTION_TO_HOST_H_ +#define BALLISTICA_GAME_CONNECTION_CONNECTION_TO_HOST_H_ + +#include +#include + +#include "ballistica/game/connection/connection.h" + +namespace ballistica { + +// connection to the party host if we're a client +class ConnectionToHost : public Connection { + public: + ConnectionToHost(); + ~ConnectionToHost() override; + void Update() override; + void HandleMessagePacket(const std::vector& buffer) override; + void HandleGamePacket(const std::vector& buffer) override; + // more efficient than dynamic_cast?.. bad idea?.. + virtual auto GetAsUDP() -> ConnectionToHostUDP*; + auto build_number() const -> int { return build_number_; } + auto protocol_version() const -> int { return protocol_version_; } + void set_protocol_version(int val) { protocol_version_ = val; } + auto party_name() const -> std::string { + // FIXME should we return peer name as fallback?.. + return party_name_; + } + + private: + std::string party_name_; + std::string peer_hash_input_; + std::string peer_hash_; + bool printed_connect_message_ = false; + int protocol_version_ = kProtocolVersion; + int build_number_ = 0; + bool got_host_info_ = false; + // can remove once back-compat protocol is > 29 + bool ignore_old_attach_remote_player_packets_ = false; + // the client-session that we're driving + Object::WeakRef client_session_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_CONNECTION_CONNECTION_TO_HOST_H_ diff --git a/src/ballistica/game/connection/connection_to_host_udp.h b/src/ballistica/game/connection/connection_to_host_udp.h new file mode 100644 index 00000000..a56de77f --- /dev/null +++ b/src/ballistica/game/connection/connection_to_host_udp.h @@ -0,0 +1,50 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_GAME_CONNECTION_CONNECTION_TO_HOST_UDP_H_ +#define BALLISTICA_GAME_CONNECTION_CONNECTION_TO_HOST_UDP_H_ + +#include +#include +#include + +#include "ballistica/game/connection/connection_to_host.h" +#include "ballistica/networking/networking.h" + +namespace ballistica { + +class ConnectionToHostUDP : public ConnectionToHost { + public: + explicit ConnectionToHostUDP(const SockAddr& addr); + ~ConnectionToHostUDP() override; + void Update() override; + void HandleGamePacket(const std::vector& buffer) override; + auto GetAsUDP() -> ConnectionToHostUDP* override; + auto request_id() const -> uint8_t { return request_id_; } + void set_client_id(int val) { client_id_ = val; } + auto client_id() const -> int { return client_id_; } + + // Attempt connecting via a different protocol. If none are left to try, + // returns false. + auto SwitchProtocol() -> bool; + void RequestDisconnect() override; + + protected: + uint8_t request_id_{}; + std::unique_ptr addr_; + bool did_die_{}; + void Die(); + void SendDisconnectRequest(); + millisecs_t last_client_i_d_request_time_{}; + millisecs_t last_disconnect_request_time_{}; + int client_id_{}; + millisecs_t last_host_response_time_{}; + void SendGamePacketCompressed(const std::vector& data) override; + void Error(const std::string& error_msg) override; + + private: + void GetRequestID(); +}; + +} // namespace ballistica + +#endif // BALLISTICA_GAME_CONNECTION_CONNECTION_TO_HOST_UDP_H_ diff --git a/src/ballistica/platform/apple/platform_apple.h b/src/ballistica/platform/apple/platform_apple.h new file mode 100644 index 00000000..9d85341d --- /dev/null +++ b/src/ballistica/platform/apple/platform_apple.h @@ -0,0 +1,86 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_PLATFORM_APPLE_PLATFORM_APPLE_H_ +#define BALLISTICA_PLATFORM_APPLE_PLATFORM_APPLE_H_ +#if BA_OSTYPE_MACOS || BA_OSTYPE_IOS_TVOS + +#include +#include +#include +#include + +#include "ballistica/platform/platform.h" + +namespace ballistica { + +class PlatformApple : public Platform { + public: + PlatformApple(); + auto GetDeviceUUIDPrefix() -> std::string override; + auto GetRealDeviceUUID(std::string* uuid) -> bool override; + auto GenerateUUID() -> std::string override; + auto GetDefaultConfigDir() -> std::string override; + auto GetLocale() -> std::string override; + auto DoGetDeviceName() -> std::string override; + auto DoHasTouchScreen() -> bool override; + auto GetInterfaceType() -> UIScale override; + auto IsRunningOnDesktop() -> bool override; + void HandleLog(const std::string& msg) override; + void SetupDataDirectory() override; + void GetTextBoundsAndWidth(const std::string& text, Rect* r, + float* width) override; + void FreeTextTexture(void* tex) override; + auto CreateTextTexture(int width, int height, + const std::vector& strings, + const std::vector& positions, + const std::vector& widths, float scale) + -> void* override; + auto GetTextTextureData(void* tex) -> uint8_t* override; + void GetFriendScores(const std::string& game, const std::string& game_version, + void* py_callback) override; + void SubmitScore(const std::string& game, const std::string& version, + int64_t score) override; + void ReportAchievement(const std::string& achievement) override; + auto HaveLeaderboard(const std::string& game, const std::string& config) + -> bool override; + void ShowOnlineScoreUI(const std::string& show, const std::string& game, + const std::string& game_version) override; + void Purchase(const std::string& item) override; + void RestorePurchases() override; + auto NewAutoReleasePool() -> void* override; + void DrainAutoReleasePool(void* pool) override; + void DoOpenURL(const std::string& url) override; + void ResetAchievements() override; + void GameCenterLogin() override; + void PurchaseAck(const std::string& purchase, + const std::string& order_id) override; + auto IsOSPlayingMusic() -> bool override; + void SetHardwareCursorVisible(bool visible) override; + void QuitApp() override; + void GetScoresToBeat(const std::string& level, const std::string& config, + void* py_callback) override; + void OpenFileExternally(const std::string& path) override; + void OpenDirExternally(const std::string& path) override; + void MacMusicAppInit() override; + auto MacMusicAppGetVolume() -> int override; + void MacMusicAppSetVolume(int volume) override; + void MacMusicAppGetLibrarySource() override; + void MacMusicAppStop() override; + auto MacMusicAppPlayPlaylist(const std::string& playlist) -> bool override; + auto MacMusicAppGetPlaylists() -> std::list override; + void StartListeningForWiiRemotes() override; + void StopListeningForWiiRemotes() override; + auto IsEventPushMode() -> bool override; + auto ContainsPythonDist() -> bool override; + auto GetPlatformName() -> std::string override; + auto GetSubplatformName() -> std::string override; + + private: + // std::mutex log_mutex_; + // std::string log_line_; +}; + +} // namespace ballistica + +#endif // BA_XCODE_BUILD || BA_OSTYPE_MACOS +#endif // BALLISTICA_PLATFORM_APPLE_PLATFORM_APPLE_H_ diff --git a/src/ballistica/python/methods/python_methods_networking.cc b/src/ballistica/python/methods/python_methods_networking.cc deleted file mode 100644 index d74a6d9e..00000000 --- a/src/ballistica/python/methods/python_methods_networking.cc +++ /dev/null @@ -1,610 +0,0 @@ -// Released under the MIT License. See LICENSE for details. - -#include "ballistica/python/methods/python_methods_networking.h" - -#include -#include -#include - -#include "ballistica/app/app_globals.h" -#include "ballistica/game/connection/connection_to_host.h" -#include "ballistica/game/game.h" -#include "ballistica/math/vector3f.h" -#include "ballistica/networking/master_server_config.h" -#include "ballistica/networking/network_reader.h" -#include "ballistica/networking/networking.h" -#include "ballistica/networking/sockaddr.h" -#include "ballistica/networking/telnet_server.h" -#include "ballistica/platform/platform.h" -#include "ballistica/python/python.h" - -namespace ballistica { - -// Ignore signed bitwise stuff; python macros do it quite a bit. -#pragma clang diagnostic push -#pragma ide diagnostic ignored "hicpp-signed-bitwise" - -auto PyGetPublicPartyEnabled(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("getpublicpartyenabled"); - static const char* kwlist[] = {nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "", - const_cast(kwlist))) - return nullptr; - assert(g_python); - if (g_game->public_party_enabled()) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } - BA_PYTHON_CATCH; -} - -auto PySetPublicPartyEnabled(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("setpublicpartyenabled"); - int enable; - static const char* kwlist[] = {"enabled", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", - const_cast(kwlist), &enable)) { - return nullptr; - } - assert(g_python); - g_game->SetPublicPartyEnabled(static_cast(enable)); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PySetPublicPartyName(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("setpublicpartyname"); - PyObject* name_obj; - static const char* kwlist[] = {"name", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", - const_cast(kwlist), &name_obj)) { - return nullptr; - } - std::string name = Python::GetPyString(name_obj); - assert(g_python); - g_game->SetPublicPartyName(name); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PySetPublicPartyStatsURL(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("setpublicpartystatsurl"); - PyObject* url_obj; - static const char* kwlist[] = {"url", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", - const_cast(kwlist), &url_obj)) { - return nullptr; - } - // The call expects an empty string for the no-url option. - std::string url = (url_obj == Py_None) ? "" : Python::GetPyString(url_obj); - assert(g_python); - g_game->SetPublicPartyStatsURL(url); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyGetPublicPartyMaxSize(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("getpublicpartymaxsize"); - static const char* kwlist[] = {nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "", - const_cast(kwlist))) { - return nullptr; - } - assert(g_python); - return PyLong_FromLong(g_game->public_party_max_size()); - BA_PYTHON_CATCH; -} - -auto PySetPublicPartyMaxSize(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("setpublicpartymaxsize"); - int max_size; - static const char* kwlist[] = {"max_size", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "i", - const_cast(kwlist), &max_size)) { - return nullptr; - } - assert(g_python); - g_game->SetPublicPartyMaxSize(max_size); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PySetAuthenticateClients(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("set_authenticate_clients"); - int enable; - static const char* kwlist[] = {"enable", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", - const_cast(kwlist), &enable)) { - return nullptr; - } - assert(g_game); - g_game->set_require_client_authentication(static_cast(enable)); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PySetAdmins(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("set_admins"); - PyObject* admins_obj; - static const char* kwlist[] = {"admins", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", - const_cast(kwlist), &admins_obj)) { - return nullptr; - } - assert(g_game); - - auto admins = Python::GetPyStrings(admins_obj); - std::set adminset; - for (auto&& admin : admins) { - adminset.insert(admin); - } - g_game->set_admin_public_ids(adminset); - - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PySetEnableDefaultKickVoting(PyObject* self, PyObject* args, - PyObject* keywds) -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("set_enable_default_kick_voting"); - int enable; - static const char* kwlist[] = {"enable", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", - const_cast(kwlist), &enable)) { - return nullptr; - } - assert(g_game); - g_game->set_kick_voting_enabled(static_cast(enable)); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyConnectToParty(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("connect_to_party"); - std::string address; - PyObject* address_obj; - int port = kDefaultPort; - - // Whether we should print standard 'connecting...' and 'party full..' - // messages when false, only odd errors such as version incompatibility will - // be printed and most connection attempts will be silent todo: could - // generalize this to pass all results to a callback instead - int print_progress = 1; - static const char* kwlist[] = {"address", "port", "print_progress", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "O|ip", - const_cast(kwlist), &address_obj, - &port, &print_progress)) { - return nullptr; - } - address = Python::GetPyString(address_obj); - - // Disallow in headless build (people were using this for spam-bots). - - if (HeadlessMode()) { - throw Exception("Not available in headless mode."); - } - - SockAddr s; - try { - s = SockAddr(address, port); - - // HACK: CLion currently flags our catch clause as unreachable even - // though SockAddr constructor can throw exceptions. Work around that here. - if (explicit_bool(false)) { - throw Exception(); - } - } catch (const std::exception&) { - ScreenMessage(g_game->GetResourceString("invalidAddressErrorText"), - {1, 0, 0}); - Py_RETURN_NONE; - } - g_game->PushHostConnectedUDPCall(s, static_cast(print_progress)); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyAcceptPartyInvitation(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("accept_party_invitation"); - const char* invite_id; - static const char* kwlist[] = {"invite_id", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", - const_cast(kwlist), &invite_id)) { - return nullptr; - } - g_platform->AndroidGPGSPartyInviteAccept(invite_id); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyGetGooglePlayPartyClientCount(PyObject* self, PyObject* args, - PyObject* keywds) -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("get_google_play_party_client_count"); - BA_PRECONDITION(InGameThread()); -#if BA_GOOGLE_BUILD - return PyLong_FromLong(g_game->GetGooglePlayClientCount()); -#else - return PyLong_FromLong(0); -#endif - BA_PYTHON_CATCH; -} - -auto PyClientInfoQueryResponse(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("client_info_query_response"); - const char* token; - PyObject* response_obj; - static const char* kwlist[] = {"token", "response", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "sO", - const_cast(kwlist), &token, - &response_obj)) { - return nullptr; - } - g_game->SetClientInfoFromMasterServer(token, response_obj); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyGetConnectionToHostInfo(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("get_connection_to_host_info"); - static const char* kwlist[] = {nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "", - const_cast(kwlist))) { - return nullptr; - } - ConnectionToHost* hc = g_game->connection_to_host(); - if (hc) { - return Py_BuildValue("{sssi}", "name", hc->party_name().c_str(), - "build_number", hc->build_number()); - } else { - return Py_BuildValue("{}"); - } - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyDisconnectFromHost(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("disconnect_from_host"); - static const char* kwlist[] = {nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "", - const_cast(kwlist))) { - return nullptr; - } - g_game->PushDisconnectFromHostCall(); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyDisconnectClient(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("disconnect_client"); - int client_id; - int ban_time = 300; // Old default before we exposed this. - static const char* kwlist[] = {"client_id", "ban_time", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|i", - const_cast(kwlist), &client_id, - &ban_time)) { - return nullptr; - } - bool kickable = g_game->DisconnectClient(client_id, ban_time); - if (kickable) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } - BA_PYTHON_CATCH; -} - -auto PyGetGamePort(PyObject* self, PyObject* args) -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("get_game_port"); - int port = 0; - if (g_network_reader != nullptr) { - // hmmm; we're just fetching the ipv4 port here; - // 6 could be different.... - port = g_network_reader->port4(); - } - return Py_BuildValue("i", port); - BA_PYTHON_CATCH; -} - -auto PyGetMasterServerAddress(PyObject* self, PyObject* args) -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("get_master_server_address"); - int source = -1; // use default.. - if (!PyArg_ParseTuple(args, "|i", &source)) { - return nullptr; - } - // source -1 implies to use current one - if (source == -1) { - source = g_app_globals->master_server_source; - } - const char* addr; - if (source == 0) { - addr = BA_MASTER_SERVER_DEFAULT_ADDR; - } else if (source == 1) { - addr = BA_MASTER_SERVER_FALLBACK_ADDR; - } else { - BA_LOG_ONCE("Error: Got unexpected source: " + std::to_string(source) - + "."); - addr = BA_MASTER_SERVER_FALLBACK_ADDR; - } - return PyUnicode_FromString(addr); - BA_PYTHON_CATCH; -} - -auto PySetMasterServerSource(PyObject* self, PyObject* args) -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("set_master_server_source"); - int source; - if (!PyArg_ParseTuple(args, "i", &source)) return nullptr; - if (source != 0 && source != 1) { - BA_LOG_ONCE("Error: Invalid server source: " + std::to_string(source) - + "."); - source = 1; - } - g_app_globals->master_server_source = source; - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PySetTelnetAccessEnabled(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("set_telnet_access_enabled"); - assert(InGameThread()); - int enable; - static const char* kwlist[] = {"enable", nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "p", - const_cast(kwlist), &enable)) { - return nullptr; - } - if (g_app_globals->telnet_server) { - g_app_globals->telnet_server->SetAccessEnabled(static_cast(enable)); - } else { - throw Exception("Telnet server not enabled."); - } - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyHostScanCycle(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("host_scan_cycle"); - g_networking->HostScanCycle(); - std::vector results = - g_networking->GetScanResults(); - PyObject* py_list = PyList_New(0); - for (auto&& i : results) { - PyList_Append(py_list, Py_BuildValue("{ssss}", "display_string", - i.display_string.c_str(), "address", - i.address.c_str())); - } - return py_list; - BA_PYTHON_CATCH; -} - -auto PyEndHostScanning(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("end_host_scanning"); - g_networking->EndHostScanning(); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -auto PyHaveConnectedClients(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("have_connected_clients"); - if (g_game->GetConnectedClientCount() > 0) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } - BA_PYTHON_CATCH; -} - -auto PyInvitePlayers(PyObject* self, PyObject* args, PyObject* keywds) - -> PyObject* { - BA_PYTHON_TRY; - Platform::SetLastPyCall("invite_players"); - static const char* kwlist[] = {nullptr}; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "", - const_cast(kwlist))) { - return nullptr; - } - g_platform->AndroidGPGSPartyInvitePlayers(); - Py_RETURN_NONE; - BA_PYTHON_CATCH; -} - -PyMethodDef PythonMethodsNetworking::methods_def[] = { - {"invite_players", (PyCFunction)PyInvitePlayers, - METH_VARARGS | METH_KEYWORDS, - "invite_players() -> None\n" - "\n" - "(internal)" - "\n" - "Category: General Utility Functions"}, - - {"have_connected_clients", (PyCFunction)PyHaveConnectedClients, - METH_VARARGS | METH_KEYWORDS, - "have_connected_clients() -> bool\n" - "\n" - "(internal)\n" - "\n" - "Category: General Utility Functions"}, - - {"end_host_scanning", (PyCFunction)PyEndHostScanning, - METH_VARARGS | METH_KEYWORDS, - "end_host_scanning() -> None\n" - "\n" - "(internal)\n" - "\n" - "Category: General Utility Functions"}, - - {"host_scan_cycle", (PyCFunction)PyHostScanCycle, - METH_VARARGS | METH_KEYWORDS, - "host_scan_cycle() -> list\n" - "\n" - "(internal)"}, - - {"set_telnet_access_enabled", (PyCFunction)PySetTelnetAccessEnabled, - METH_VARARGS | METH_KEYWORDS, - "set_telnet_access_enabled(enable: bool)\n" - " -> None\n" - "\n" - "(internal)"}, - - {"set_master_server_source", PySetMasterServerSource, METH_VARARGS, - "set_master_server_source(source: int) -> None\n" - "\n" - "(internal)"}, - - {"get_master_server_address", PyGetMasterServerAddress, METH_VARARGS, - "get_master_server_address(source: int = -1) -> str\n" - "\n" - "(internal)\n" - "\n" - "Return the address of the master server."}, - - {"get_game_port", PyGetGamePort, METH_VARARGS, - "get_game_port() -> int\n" - "\n" - "(internal)\n" - "\n" - "Return the port ballistica is hosting on."}, - - {"disconnect_from_host", (PyCFunction)PyDisconnectFromHost, - METH_VARARGS | METH_KEYWORDS, - "disconnect_from_host() -> None\n" - "\n" - "(internal)\n" - "\n" - "Category: General Utility Functions"}, - - {"disconnect_client", (PyCFunction)PyDisconnectClient, - METH_VARARGS | METH_KEYWORDS, - "disconnect_client(client_id: int, ban_time: int = 300) -> bool\n" - "\n" - "(internal)"}, - - {"get_connection_to_host_info", (PyCFunction)PyGetConnectionToHostInfo, - METH_VARARGS | METH_KEYWORDS, - "get_connection_to_host_info() -> dict\n" - "\n" - "(internal)"}, - - {"client_info_query_response", (PyCFunction)PyClientInfoQueryResponse, - METH_VARARGS | METH_KEYWORDS, - "client_info_query_response(token: str, response: Any) -> None\n" - "\n" - "(internal)"}, - - {"get_google_play_party_client_count", - (PyCFunction)PyGetGooglePlayPartyClientCount, METH_VARARGS | METH_KEYWORDS, - "get_google_play_party_client_count() -> int\n" - "\n" - "(internal)"}, - - {"accept_party_invitation", (PyCFunction)PyAcceptPartyInvitation, - METH_VARARGS | METH_KEYWORDS, - "accept_party_invitation(invite_id: str) -> None\n" - "\n" - "(internal)"}, - - {"connect_to_party", (PyCFunction)PyConnectToParty, - METH_VARARGS | METH_KEYWORDS, - "connect_to_party(address: str, port: int = None,\n" - " print_progress: bool = True) -> None\n" - "\n" - "(internal)"}, - - {"set_authenticate_clients", (PyCFunction)PySetAuthenticateClients, - METH_VARARGS | METH_KEYWORDS, - "set_authenticate_clients(enable: bool) -> None\n" - "\n" - "(internal)"}, - - {"set_admins", (PyCFunction)PySetAdmins, METH_VARARGS | METH_KEYWORDS, - "set_admins(admins: List[str]) -> None\n" - "\n" - "(internal)"}, - - {"set_enable_default_kick_voting", - (PyCFunction)PySetEnableDefaultKickVoting, METH_VARARGS | METH_KEYWORDS, - "set_enable_default_kick_voting(enable: bool) -> None\n" - "\n" - "(internal)"}, - - {"set_public_party_max_size", (PyCFunction)PySetPublicPartyMaxSize, - METH_VARARGS | METH_KEYWORDS, - "set_public_party_max_size(max_size: int) -> None\n" - "\n" - "(internal)"}, - - {"get_public_party_max_size", (PyCFunction)PyGetPublicPartyMaxSize, - METH_VARARGS | METH_KEYWORDS, - "get_public_party_max_size() -> int\n" - "\n" - "(internal)"}, - - {"set_public_party_stats_url", (PyCFunction)PySetPublicPartyStatsURL, - METH_VARARGS | METH_KEYWORDS, - "set_public_party_stats_url(url: Optional[str]) -> None\n" - "\n" - "(internal)"}, - - {"set_public_party_name", (PyCFunction)PySetPublicPartyName, - METH_VARARGS | METH_KEYWORDS, - "set_public_party_name(name: str) -> None\n" - "\n" - "(internal)"}, - - {"set_public_party_enabled", (PyCFunction)PySetPublicPartyEnabled, - METH_VARARGS | METH_KEYWORDS, - "set_public_party_enabled(enabled: bool) -> None\n" - "\n" - "(internal)"}, - - {"get_public_party_enabled", (PyCFunction)PyGetPublicPartyEnabled, - METH_VARARGS | METH_KEYWORDS, - "get_public_party_enabled() -> bool\n" - "\n" - "(internal)"}, - - {nullptr, nullptr, 0, nullptr}}; - -#pragma clang diagnostic pop - -} // namespace ballistica diff --git a/src/ballistica/python/methods/python_methods_networking.h b/src/ballistica/python/methods/python_methods_networking.h deleted file mode 100644 index bb6a2c42..00000000 --- a/src/ballistica/python/methods/python_methods_networking.h +++ /dev/null @@ -1,18 +0,0 @@ -// Released under the MIT License. See LICENSE for details. - -#ifndef BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_NETWORKING_H_ -#define BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_NETWORKING_H_ - -#include "ballistica/python/python_sys.h" - -namespace ballistica { - -/// Networking related individual python methods for our module. -class PythonMethodsNetworking { - public: - static PyMethodDef methods_def[]; -}; - -} // namespace ballistica - -#endif // BALLISTICA_PYTHON_METHODS_PYTHON_METHODS_NETWORKING_H_ diff --git a/src/ballistica/scene/node/anim_curve_node.cc b/src/ballistica/scene/node/anim_curve_node.cc new file mode 100644 index 00000000..fb311f87 --- /dev/null +++ b/src/ballistica/scene/node/anim_curve_node.cc @@ -0,0 +1,136 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/anim_curve_node.h" + +#include +#include +#include + +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class AnimCurveNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS AnimCurveNode + BA_NODE_CREATE_CALL(CreateAnimCurve); + BA_FLOAT_ATTR(in, in, set_in); + BA_BOOL_ATTR(loop, loop, set_loop); + BA_INT64_ARRAY_ATTR(times, times, set_times); + BA_FLOAT_ARRAY_ATTR(values, values, set_values); + BA_FLOAT_ATTR(offset, offset, set_offset); + BA_FLOAT_ATTR_READONLY(out, GetOut); +#undef BA_NODE_TYPE_CLASS + + AnimCurveNodeType() + : NodeType("animcurve", CreateAnimCurve), + in(this), + loop(this), + times(this), + values(this), + offset(this), + out(this) {} +}; + +static NodeType* node_type{}; + +auto AnimCurveNode::InitType() -> NodeType* { + node_type = new AnimCurveNodeType(); + return node_type; +} + +AnimCurveNode::AnimCurveNode(Scene* scene) : Node(scene, node_type) {} + +AnimCurveNode::~AnimCurveNode() = default; + +auto AnimCurveNode::GetOut() -> float { + // Recreate our keyframes if need be. + if (keys_dirty_) { + keyframes_.clear(); + auto num = std::min(times_.size(), values_.size()); + if (num < 1) { + input_start_ = 0; + input_end_ = 0; + } + for (size_t i = 0; i < num; i++) { + if (i == 0) { + input_start_ = times_[i]; + } + if (i == (num - 1)) { + input_end_ = times_[i]; + } + keyframes_.emplace_back(times_[i], values_[i]); + } + keys_dirty_ = false; + out_dirty_ = true; + } + + // Now update out if need-be. + if (out_dirty_) { + float in_val = in_ - offset_; + if ((input_end_ - input_start_) > 0) { + if (keyframes_.size() < 2) { + assert(keyframes_.size() == 1); + out_ = keyframes_[0].value; + } else { + bool got; + if (loop_) { + in_val = fmodf(in_val, (input_end_ - input_start_)); + if (in_val < 0) in_val += (input_end_ - input_start_); + got = false; + } else { + if (in_val >= input_end_) { + out_ = keyframes_.back().value; + got = true; + } else if (in_val <= input_start_) { + out_ = keyframes_.front().value; + got = true; + } else { + got = false; + } + } + if (!got) { + out_ = keyframes_[0].value; + + // Ok we know we've got at least 2 keyframes. + auto i1 = keyframes_.begin(); + auto i2 = keyframes_.begin(); + auto i = keyframes_.begin(); + while (true) { + if (i == keyframes_.end()) { + break; + } + if (i->time < in_val) { + i++; + i1 = i2; + i2 = i; + } else { + break; + } + } + if (i2->time - i1->time == 0) { + out_ = i1->value; + } else { + out_ = i1->value + + ((in_val - i1->time) + / static_cast(i2->time - i1->time)) + * (i2->value - i1->value); + } + } + } + } else { + // No keyframes?.. hmm just go with 0. + if (keyframes_.empty()) { + out_ = 0.0f; + } else { + // We have one keyframe; hmm what to do. + out_ = keyframes_[0].value; + } + } + out_dirty_ = false; + } + return out_; +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/anim_curve_node.h b/src/ballistica/scene/node/anim_curve_node.h new file mode 100644 index 00000000..23ca037d --- /dev/null +++ b/src/ballistica/scene/node/anim_curve_node.h @@ -0,0 +1,75 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_ANIM_CURVE_NODE_H_ +#define BALLISTICA_SCENE_NODE_ANIM_CURVE_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// Node containing a keyframe graph associating an input value with an output +// value. +class AnimCurveNode : public Node { + public: + static auto InitType() -> NodeType*; + + explicit AnimCurveNode(Scene* scene); + ~AnimCurveNode() override; + + auto in() const -> float { return in_; } + void set_in(float value) { + in_ = value; + out_dirty_ = true; + } + + auto loop() const -> bool { return loop_; } + void set_loop(bool val) { + loop_ = val; + out_dirty_ = true; + } + + auto times() const -> const std::vector& { return times_; } + void set_times(const std::vector& vals) { + times_ = vals; + keys_dirty_ = true; + } + + auto values() const -> const std::vector& { return values_; } + void set_values(const std::vector& vals) { + values_ = vals; + keys_dirty_ = true; + } + + auto offset() const -> float { return offset_; } + void set_offset(float val) { + offset_ = val; + out_dirty_ = true; + } + + auto GetOut() -> float; + + private: + struct Keyframe { + Keyframe(uint32_t t, float v) : time(t), value(v) {} + uint32_t time; + float value; + }; + + float in_ = 0.0f; + std::vector times_; + std::vector values_; + bool keys_dirty_ = true; + bool out_dirty_ = true; + float out_ = 0.0f; + bool loop_ = true; + std::vector keyframes_; + float input_start_ = 0.0f; + float input_end_ = 0.0f; + float offset_ = 0.0f; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_ANIM_CURVE_NODE_H_ diff --git a/src/ballistica/scene/node/bomb_node.cc b/src/ballistica/scene/node/bomb_node.cc new file mode 100644 index 00000000..c39bfa3b --- /dev/null +++ b/src/ballistica/scene/node/bomb_node.cc @@ -0,0 +1,85 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/bomb_node.h" + +#include "ballistica/graphics/graphics.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +const float kFuseOffset = 0.35f; + +// Returns noise value between 0 and 1. +// TODO(ericf): Need to interpolate between 2 values. +static auto SimpleNoise(uint32_t x) -> float { + x = (x << 13u) ^ x; + return (0.5f + * static_cast((x * (x * x * 15731u + 789221u) + 1376312589u) + & 0x7fffffffu) + / 1073741824.0f); +} + +class BombNodeType : public PropNodeType { + public: +#define BA_NODE_TYPE_CLASS BombNode + BA_NODE_CREATE_CALL(CreateBomb); + BA_FLOAT_ATTR(fuse_length, fuse_length, set_fuse_length); +#undef BA_NODE_TYPE_CLASS + + BombNodeType() : PropNodeType("bomb", CreateBomb), fuse_length(this) {} +}; + +static NodeType* node_type{}; + +auto BombNode::InitType() -> NodeType* { + node_type = new BombNodeType(); + return node_type; +} + +BombNode::BombNode(Scene* scene) : PropNode(scene, node_type) {} + +void BombNode::OnCreate() { + // We can't do this in our constructor because + // it would prevent the user from setting density/etc attrs. + // (user attrs get applied after constructors fire) + SetBody("sphere"); +} + +void BombNode::Step() { + PropNode::Step(); + if (body_.exists()) { + // Update our fuse and light position. + dVector3 fuse_tip_pos; + dGeomGetRelPointPos(body_->geom(), 0, (fuse_length_ + kFuseOffset), 0, + fuse_tip_pos); + light_translate_ = fuse_tip_pos; + light_translate_.x += body_->blend_offset().x; + light_translate_.y += body_->blend_offset().y; + light_translate_.z += body_->blend_offset().z; +#if !BA_HEADLESS_BUILD + fuse_.SetTransform(Matrix44fTranslate(0, kFuseOffset * model_scale_, 0) + * body_->GetTransform()); + fuse_.SetLength(fuse_length_); +#endif // !BA_HEADLESS_BUILD + } +} + +void BombNode::Draw(FrameDef* frame_def) { +#if !BA_HEADLESS_BUILD + PropNode::Draw(frame_def); + float s_scale, s_density; + shadow_.GetValues(&s_scale, &s_density); + float intensity = SimpleNoise(static_cast(id() + scene()->time())) + * s_density * 0.2f; + float s = 4.0f * s_scale; + float r = 1.5f * intensity; + float g = 0.1f * intensity; + float b = 0.1f * intensity; + float a = 0.0f; + g_graphics->DrawBlotchSoft(light_translate_, s, r, g, b, a); + g_graphics->DrawBlotchSoftObj(light_translate_, s, r, g, b, a); +#endif // !BA_HEADLESS_BUILD +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/bomb_node.h b/src/ballistica/scene/node/bomb_node.h new file mode 100644 index 00000000..285a3586 --- /dev/null +++ b/src/ballistica/scene/node/bomb_node.h @@ -0,0 +1,31 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_BOMB_NODE_H_ +#define BALLISTICA_SCENE_NODE_BOMB_NODE_H_ + +#include "ballistica/dynamics/bg/bg_dynamics_fuse.h" +#include "ballistica/scene/node/prop_node.h" + +namespace ballistica { + +class BombNode : public PropNode { + public: + static auto InitType() -> NodeType*; + explicit BombNode(Scene* scene); + void Step() override; + void Draw(FrameDef* frame_def) override; + void OnCreate() override; + auto fuse_length() const -> float { return fuse_length_; } + void set_fuse_length(float val) { fuse_length_ = val; } + + protected: +#if !BA_HEADLESS_BUILD + BGDynamicsFuse fuse_; +#endif + float fuse_length_ = 1.0f; + Vector3f light_translate_ = {0.0f, 0.0f, 0.0f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_BOMB_NODE_H_ diff --git a/src/ballistica/scene/node/combine_node.cc b/src/ballistica/scene/node/combine_node.cc new file mode 100644 index 00000000..9109a80b --- /dev/null +++ b/src/ballistica/scene/node/combine_node.cc @@ -0,0 +1,68 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/combine_node.h" + +#include +#include + +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class CombineNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS CombineNode + BA_NODE_CREATE_CALL(CreateLocator); + BA_FLOAT_ATTR(input0, input_0, set_input_0); + BA_FLOAT_ATTR(input1, input_1, set_input_1); + BA_FLOAT_ATTR(input2, input_2, set_input_2); + BA_FLOAT_ATTR(input3, input_3, set_input_3); + BA_FLOAT_ARRAY_ATTR_READONLY(output, GetOutput); + BA_INT_ATTR(size, size, set_size); +#undef BA_NODE_TYPE_CLASS + CombineNodeType() + : NodeType("combine", CreateLocator), + input0(this), + input1(this), + input2(this), + input3(this), + output(this), + size(this) {} +}; + +static NodeType* node_type{}; + +auto CombineNode::InitType() -> NodeType* { + node_type = new CombineNodeType(); + return node_type; +} + +CombineNode::CombineNode(Scene* scene) : Node(scene, node_type) {} + +auto CombineNode::GetOutput() -> std::vector { + if (dirty_) { + if (do_size_unset_warning_) { + do_size_unset_warning_ = false; + BA_LOG_ONCE("ERROR: CombineNode size unset for " + label()); + } + int actual_size = std::min(4, std::max(0, size_)); + output_.resize(static_cast(actual_size)); + if (size_ > 0) { + output_[0] = input_0_; + } + if (size_ > 1) { + output_[1] = input_1_; + } + if (size_ > 2) { + output_[2] = input_2_; + } + if (size_ > 3) { + output_[3] = input_3_; + } + dirty_ = false; + } + return output_; +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/combine_node.h b/src/ballistica/scene/node/combine_node.h new file mode 100644 index 00000000..a547642f --- /dev/null +++ b/src/ballistica/scene/node/combine_node.h @@ -0,0 +1,58 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_COMBINE_NODE_H_ +#define BALLISTICA_SCENE_NODE_COMBINE_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// An node used to combine individual input values into one array output value +class CombineNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit CombineNode(Scene* scene); + auto size() const -> int { return size_; } + void set_size(int val) { + size_ = val; + dirty_ = true; + do_size_unset_warning_ = false; + } + auto input_0() const -> float { return input_0_; } + void set_input_0(float val) { + input_0_ = val; + dirty_ = true; + } + auto input_1() const -> float { return input_1_; } + void set_input_1(float val) { + input_1_ = val; + dirty_ = true; + } + auto input_2() const -> float { return input_2_; } + void set_input_2(float val) { + input_2_ = val; + dirty_ = true; + } + auto input_3() const -> float { return input_3_; } + void set_input_3(float val) { + input_3_ = val; + dirty_ = true; + } + auto GetOutput() -> std::vector; + + private: + bool do_size_unset_warning_ = true; + float input_0_ = 0.0f; + float input_1_ = 0.0f; + float input_2_ = 0.0f; + float input_3_ = 0.0f; + int size_ = 4; + std::vector output_; + bool dirty_ = true; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_COMBINE_NODE_H_ diff --git a/src/ballistica/scene/node/explosion_node.cc b/src/ballistica/scene/node/explosion_node.cc new file mode 100644 index 00000000..c37b71ba --- /dev/null +++ b/src/ballistica/scene/node/explosion_node.cc @@ -0,0 +1,224 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/explosion_node.h" + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/post_process_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class ExplosionNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS ExplosionNode + BA_NODE_CREATE_CALL(CreateExplosion); + BA_FLOAT_ARRAY_ATTR(position, position, set_position); + BA_FLOAT_ARRAY_ATTR(velocity, velocity, set_velocity); + BA_FLOAT_ATTR(radius, radius, set_radius); + BA_FLOAT_ARRAY_ATTR(color, color, set_color); + BA_BOOL_ATTR(big, big, set_big); +#undef BA_NODE_TYPE_CLASS + ExplosionNodeType() + : NodeType("explosion", CreateExplosion), + position(this), + velocity(this), + radius(this), + color(this), + big(this) {} +}; + +static NodeType* node_type{}; + +auto ExplosionNode::InitType() -> NodeType* { + node_type = new ExplosionNodeType(); + return node_type; +} + +ExplosionNode* gExplosionDistortLock = nullptr; + +ExplosionNode::ExplosionNode(Scene* scene) + : Node(scene, node_type), birth_time_(scene->time()) {} + +ExplosionNode::~ExplosionNode() { + if (draw_distortion_ && have_distortion_lock_) { + assert(gExplosionDistortLock == this); + gExplosionDistortLock = nullptr; + } +} + +void ExplosionNode::set_big(bool val) { + big_ = val; + + // big explosions try to steal the distortion pointer.. + if (big_) { + check_draw_distortion_ = true; + } +} + +void ExplosionNode::set_position(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of size 3 for position"); + position_ = vals; +} + +void ExplosionNode::set_velocity(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of size 3 for velocity"); + velocity_ = vals; +} + +void ExplosionNode::set_color(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of size 3 for color"); + color_ = vals; +} + +void ExplosionNode::Step() { + // update our position from our velocity + if (velocity_[0] != 0.0f || velocity_[1] != 0.0f || velocity_[2] != 0.0f) { + velocity_[0] *= 0.95f; + velocity_[1] *= 0.95f; + velocity_[2] *= 0.95f; + position_[0] += velocity_[0] * kGameStepSeconds; + position_[1] += velocity_[1] * kGameStepSeconds; + position_[2] += velocity_[2] * kGameStepSeconds; + } +} + +void ExplosionNode::Draw(FrameDef* frame_def) { + { + bool high_quality = (frame_def->quality() >= GraphicsQuality::kHigh); + // we only draw distortion if we're the only bomb.. + // (it gets expensive..) + if (check_draw_distortion_) { + check_draw_distortion_ = false; + { + if (big_) { + // Steal distortion handle. + if (gExplosionDistortLock != nullptr) { + gExplosionDistortLock->draw_distortion_ = false; + gExplosionDistortLock = this; + have_distortion_lock_ = true; + draw_distortion_ = true; + } + } else { + // Play nice and only distort if no one else currently is. + if (gExplosionDistortLock == nullptr) { + draw_distortion_ = true; + gExplosionDistortLock = this; + have_distortion_lock_ = true; + } else { + draw_distortion_ = false; + } + } + } + } + if (draw_distortion_) { + float age = scene()->time() - static_cast(birth_time_); + float amt = (1.0f - 0.00265f * age); + if (amt > 0.0001f) { + amt = pow(amt, 2.2f); + amt *= 2.0f; + if (big_) { + amt *= 4.0f; + } else { + amt *= 0.8f; + } + float s = 1.0f; + if (high_quality) { + PostProcessComponent c(frame_def->blit_pass()); + c.setNormalDistort(0.5f * amt); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(1.0f + s * 0.8f * 0.025f * age, + 1.0f + s * 0.8f * 0.0015f * age, + 1.0f + s * 0.8f * 0.025f * age); + c.Scale(0.7f, 0.7f, 0.7f); + c.DrawModel(g_media->GetModel(SystemModelID::kShockWave), + kModelDrawFlagNoReflection); + c.PopTransform(); + c.Submit(); + } else { + // simpler transparent shock wave + // draw our distortion wave in the overlay pass + ObjectComponent c(frame_def->beauty_pass()); + c.SetTransparent(true); + c.SetLightShadow(LightShadowType::kNone); + // eww hacky - the shock wave model uses color as distortion amount + c.SetColor(1.0f, 0.7f, 0.7f, 0.06f * amt); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(1.0f + s * 0.8f * 0.025f * age, + 1.0f + s * 0.8f * 0.0015f * age, + 1.0f + s * 0.8f * 0.025f * age); + c.Scale(0.7f, 0.7f, 0.7f); + c.DrawModel(g_media->GetModel(SystemModelID::kShockWave), + kModelDrawFlagNoReflection); + c.PopTransform(); + c.Submit(); + } + } + } + } + + float life = 1.0f * (big_ ? 350.0f : 260.0f); + float age = scene()->time() - static_cast(birth_time_); + if (age < life) { + float b = 2.0f; + if (big_) { + b = 2.0f; + } + float o = age / life; + if (big_) { + o = pow(1.0f - o, 1.4f); + } else { + o = pow(1.0f - o, 0.8f); + } + float s = 1.0f - (age / life); + s = 1.0f - (s * s); + s *= radius_; + if (big_) { + s *= 2.0f; + } else { + s *= 1.2f; + } + s *= 0.75f; + float cx, cy, cz; + g_graphics->camera()->get_position(&cx, &cy, &cz); + ObjectComponent c(frame_def->beauty_pass()); + c.SetTransparent(true); + c.SetLightShadow(LightShadowType::kNone); + c.SetPremultiplied(true); + c.SetTexture(g_media->GetTexture(SystemTextureID::kExplosion)); + c.SetColor(1.3f * o * color_[0] * b, o * color_[1] * b, o * color_[2] * b, + 0.0f); + c.PushTransform(); + Vector3f to_cam = + Vector3f(cx - position_[0], cy - position_[1], cz - position_[2]) + .Normalized(); + Matrix44f m = Matrix44fTranslate(position_[0], position_[1], position_[2]); + Vector3f right = Vector3f::Cross(to_cam, kVector3fY).Normalized(); + Vector3f up = Vector3f::Cross(right, to_cam).Normalized(); + Matrix44f om = Matrix44fOrient(right, to_cam, up); + c.MultMatrix((om * m).m); + c.Scale(0.9f * s, 0.9f * s, 0.9f * s); + c.DrawModel(g_media->GetModel(SystemModelID::kShield), + kModelDrawFlagNoReflection); + c.Scale(0.6f, 0.6f, 0.6f); + c.Rotate(33, 0, 1, 0); + c.SetColor(o * 7.0f * color_[0], o * 7.0f * color_[1], o * 7.0f * color_[2], + 0); + c.DrawModel(g_media->GetModel(SystemModelID::kShield), + kModelDrawFlagNoReflection); + c.PopTransform(); + c.Submit(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/explosion_node.h b/src/ballistica/scene/node/explosion_node.h new file mode 100644 index 00000000..05c8c7a7 --- /dev/null +++ b/src/ballistica/scene/node/explosion_node.h @@ -0,0 +1,44 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_EXPLOSION_NODE_H_ +#define BALLISTICA_SCENE_NODE_EXPLOSION_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class ExplosionNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit ExplosionNode(Scene* scene); + ~ExplosionNode() override; + void Draw(FrameDef* frame_def) override; + void Step() override; + auto position() const -> std::vector { return position_; } + void set_position(const std::vector& vals); + auto velocity() const -> std::vector { return velocity_; } + void set_velocity(const std::vector& vals); + auto radius() const -> float { return radius_; } + void set_radius(float val) { radius_ = val; } + auto color() const -> std::vector { return color_; } + void set_color(const std::vector& vals); + auto big() const -> bool { return big_; } + void set_big(bool val); + + private: + millisecs_t birth_time_; + bool check_draw_distortion_{true}; + bool big_{}; + bool draw_distortion_{}; + bool have_distortion_lock_{}; + float radius_{1.0f}; + std::vector position_{0.0f, 0.0f, 0.0f}; + std::vector velocity_{0.0f, 0.0f, 0.0f}; + std::vector color_{0.9f, 0.3f, 0.1f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_EXPLOSION_NODE_H_ diff --git a/src/ballistica/scene/node/flag_node.cc b/src/ballistica/scene/node/flag_node.cc new file mode 100644 index 00000000..88ed73a4 --- /dev/null +++ b/src/ballistica/scene/node/flag_node.cc @@ -0,0 +1,691 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/flag_node.h" + +#include + +#include "ballistica/dynamics/bg/bg_dynamics_shadow.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/area_of_interest.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +const int kFlagSizeX{5}; +const int kFlagSizeY{5}; + +const float kFlagCanvasWidth{1.0f}; +const float kFlagCanvasHeight{1.0f}; + +const float kFlagCanvasScaleX{kFlagCanvasWidth / kFlagSizeX}; +const float kFlagCanvasScaleY{kFlagCanvasHeight / kFlagSizeY}; + +// NOLINTNEXTLINE(cert-err58-cpp) +const float kFlagCanvasScaleDiagonal{ + sqrtf(kFlagCanvasScaleX * kFlagCanvasScaleX + + kFlagCanvasScaleY * kFlagCanvasScaleY)}; + +const float kFlagRadius{0.1f}; +const float kFlagHeight{1.5f}; + +const float kFlagMassRadius{0.3f}; +const float kFlagMassHeight{1.0f}; + +const float kFlagDensity{1.0f}; + +const float kStiffness{0.4f}; +const float kWindStrength{0.002f}; +const float kGravityStrength{0.0012f}; +const float kDampingStrength{0.0f}; +const float kDragStrength{0.1f}; + +#if !BA_HEADLESS_BUILD +class FlagNode::FullShadowSet : public Object { + public: + BGDynamicsShadow shadow_pole_bottom_; + BGDynamicsShadow shadow_pole_middle_; + BGDynamicsShadow shadow_pole_top_; + BGDynamicsShadow shadow_flag_; +}; +class FlagNode::SimpleShadowSet : public Object { + public: + BGDynamicsShadow shadow_; +}; +#endif // !BA_HEADLESS_BUILD + +class FlagNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS FlagNode + BA_NODE_CREATE_CALL(CreateFlag); + BA_BOOL_ATTR(is_area_of_interest, is_area_of_interest, SetIsAreaOfInterest); + BA_FLOAT_ARRAY_ATTR(position, getPosition, SetPosition); + BA_TEXTURE_ATTR(color_texture, color_texture, set_color_texture); + BA_BOOL_ATTR(lightWeight, light_weight, SetLightWeight); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_MATERIAL_ARRAY_ATTR(materials, GetMaterials, SetMaterials); +#undef BA_NODE_TYPE_CLASS + + FlagNodeType() + : NodeType("flag", CreateFlag), + is_area_of_interest(this), + position(this), + color_texture(this), + lightWeight(this), + color(this), + materials(this) {} +}; + +static NodeType* node_type{}; + +auto FlagNode::InitType() -> NodeType* { + node_type = new FlagNodeType(); + return node_type; +} + +enum FlagBodyType { kPoleBodyID }; + +FlagNode::FlagNode(Scene* scene) : Node(scene, node_type), part_(this) { + body_ = Object::New( + kPoleBodyID, &part_, RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + UpdateDimensions(); + dBodySetPosition(body_->body(), 0, 1.2f, 0); + dQuaternion iq; + dQFromAxisAndAngle(iq, 1, 0, 0, -90.0f * (kPi / 180.0f)); + dBodySetQuaternion(body_->body(), iq); + ResetFlagMesh(); + + // Set our mesh static data and indices once. + auto indices( + Object::New(6 * (kFlagSizeX - 1) * (kFlagSizeY - 1))); + uint16_t* index = &indices->elements[0]; + auto v_static(Object::New>(kFlagSizeX + * kFlagSizeY)); + VertexObjectSplitStatic* vs = &v_static->elements[0]; + + int x_inc = 65535 / (kFlagSizeX - 1); + int y_inc = 65535 / (kFlagSizeY - 1); + + for (int y = 0; y < kFlagSizeY - 1; y++) { + for (int x = 0; x < kFlagSizeX - 1; x++) { + *index++ = static_cast_check_fit(kFlagSizeX * y + x); + *index++ = static_cast_check_fit(kFlagSizeX * y + x + 1); + *index++ = static_cast_check_fit(kFlagSizeX * (y + 1) + x); + *index++ = static_cast_check_fit(kFlagSizeX * (y + 1) + x); + *index++ = static_cast_check_fit(kFlagSizeX * y + x + 1); + *index++ = static_cast_check_fit(kFlagSizeX * (y + 1) + x + 1); + } + } + for (int y = 0; y < kFlagSizeY; y++) { + for (int x = 0; x < kFlagSizeX; x++) { + vs[kFlagSizeX * y + x].uv[0] = static_cast_check_fit(x_inc * x); + vs[kFlagSizeX * y + x].uv[1] = static_cast_check_fit(y_inc * y); + } + } + + mesh_.SetIndexData(indices); + mesh_.SetStaticData(v_static); + + // Create our shadow set. + UpdateForGraphicsQuality(g_graphics_server->quality()); +} + +auto FlagNode::getPosition() const -> std::vector { + const dReal* p = dGeomGetPosition(body_->geom()); + std::vector f(3); + f[0] = p[0]; + f[1] = p[1]; + f[2] = p[2]; + return f; +} + +void FlagNode::SetColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for color"); + } + color_ = vals; +} + +void FlagNode::SetLightWeight(bool val) { + light_weight_ = val; + UpdateDimensions(); +} + +void FlagNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for position"); + } + dQuaternion iq; + dQFromAxisAndAngle(iq, 1, 0, 0, -90 * (kPi / 180.0f)); + dBodySetPosition(body_->body(), vals[0], vals[1], vals[2]); + dBodySetQuaternion(body_->body(), iq); + dBodySetLinearVel(body_->body(), 0, 0, 0); + dBodySetAngularVel(body_->body(), 0, 0, 0); + ResetFlagMesh(); +} + +void FlagNode::SetIsAreaOfInterest(bool val) { + if ((val && area_of_interest_ == nullptr) + || (!val && area_of_interest_ != nullptr)) { + // Either make one or kill the one we had. + if (val) { + assert(area_of_interest_ == nullptr); + area_of_interest_ = g_graphics->camera()->NewAreaOfInterest(false); + } else { + assert(area_of_interest_ != nullptr); + g_graphics->camera()->DeleteAreaOfInterest(area_of_interest_); + area_of_interest_ = nullptr; + } + } +} + +auto FlagNode::GetMaterials() const -> std::vector { + return part_.GetMaterials(); +} + +void FlagNode::SetMaterials(const std::vector& vals) { + part_.SetMaterials(vals); +} + +void FlagNode::UpdateDimensions() { + float density_scale = + (g_graphics->camera()->happy_thoughts_mode()) ? 0.3f : 1.0f; + body_->SetDimensions(kFlagRadius, kFlagHeight - 2 * kFlagRadius, 0, + kFlagMassRadius, kFlagMassHeight, 0.0f, + kFlagDensity * density_scale); +} + +FlagNode::~FlagNode() { + if (area_of_interest_) + g_graphics->camera()->DeleteAreaOfInterest(area_of_interest_); +} + +void FlagNode::HandleMessage(const char* data_in) { + const char* data = data_in; + bool handled = true; + + switch (extract_node_message_type(&data)) { + case NodeMessageType::kFooting: { + footing_ += Utils::ExtractInt8(&data); + break; + } + + case NodeMessageType::kImpulse: { + float px = Utils::ExtractFloat16NBO(&data); + float py = Utils::ExtractFloat16NBO(&data); + float pz = Utils::ExtractFloat16NBO(&data); + + float vx = Utils::ExtractFloat16NBO(&data); + float vy = Utils::ExtractFloat16NBO(&data); + float vz = Utils::ExtractFloat16NBO(&data); + + float mag = Utils::ExtractFloat16NBO(&data); + float velocity_mag = Utils::ExtractFloat16NBO(&data); + float radius = Utils::ExtractFloat16NBO(&data); + Utils::ExtractInt16NBO(&data); // calc-force-only + + float force_dir_x = Utils::ExtractFloat16NBO(&data); + float force_dir_y = Utils::ExtractFloat16NBO(&data); + float force_dir_z = Utils::ExtractFloat16NBO(&data); + + float applied_mag = body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, + 0.2f * mag, 0.2f * velocity_mag, radius, false); + + Vector3f to_flag = + Vector3f(px, py, pz) - Vector3f(dBodyGetPosition(body_->body())); + to_flag *= -0.0001f * applied_mag / to_flag.Length(); + + flag_impulse_add_x_ += to_flag.x; + flag_impulse_add_y_ += to_flag.y; + flag_impulse_add_z_ += to_flag.z; + + have_flag_impulse_ = true; + break; + } + default: + handled = false; + break; + } + if (!handled) Node::HandleMessage(data_in); +} + +void FlagNode::Draw(FrameDef* frame_def) { +#if !BA_HEADLESS_BUILD + + // Flag cloth. + { + // Update the dynamic portion of our mesh data. + // FIXME - should move this all to BG dynamics thread + auto v_dynamic(Object::New>(25)); + + VertexObjectSplitDynamic* vd = &v_dynamic->elements[0]; + for (int i = 0; i < 25; i++) { + vd[i].position[0] = flag_points_[i].x; + vd[i].position[1] = flag_points_[i].y; + vd[i].position[2] = flag_points_[i].z; + vd[i].normal[0] = static_cast_check_fit(std::max( + -32767, + std::min(32767, static_cast(flag_normals_[i].x * 32767.0f)))); + vd[i].normal[1] = static_cast_check_fit(std::max( + -32767, + std::min(32767, static_cast(flag_normals_[i].y * 32767.0f)))); + vd[i].normal[2] = static_cast_check_fit(std::max( + -32767, + std::min(32767, static_cast(flag_normals_[i].z * 32767.0f)))); + } + mesh_.SetDynamicData(v_dynamic); + + // Render a subtle sharp shadow in higher quality modes. + if (frame_def->quality() > GraphicsQuality::kLow) { + SimpleComponent c(frame_def->light_shadow_pass()); + c.SetTransparent(true); + c.SetColor(color_[0] * 0.1f, color_[1] * 0.1f, color_[2] * 0.1f, 0.02f); + c.SetDoubleSided(true); + c.DrawMesh(&mesh_); + c.Submit(); + } + + // Now beauty pass. + { + ObjectComponent c(frame_def->beauty_pass()); + c.SetWorldSpace(true); + c.SetColor(color_[0], color_[1], color_[2]); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.05f, 0.05f, 0.05f); + c.SetDoubleSided(true); + c.SetTexture(color_texture_); + c.DrawMesh(&mesh_); + c.Submit(); + } + + float s_scale, s_density; + SimpleComponent c(frame_def->light_shadow_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kShadow)); + c.SetTransparent(true); + + FullShadowSet* full_shadows = full_shadow_set_.get(); + + if (full_shadows) { + // Pole bottom. + { + full_shadows->shadow_pole_bottom_.GetValues(&s_scale, &s_density); + const Vector3f& p(full_shadows->shadow_pole_bottom_.GetPosition()); + g_graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0, s_density * 0.25f); + } + + // Pole middle. + { + full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density); + const Vector3f& p(full_shadows->shadow_pole_middle_.GetPosition()); + g_graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0, s_density * 0.25f); + } + + // Pole top. + { + full_shadows->shadow_pole_middle_.GetValues(&s_scale, &s_density); + const Vector3f& p(full_shadows->shadow_pole_top_.GetPosition()); + g_graphics->DrawBlotch(p, 0.4f * s_scale, 0, 0, 0, s_density * 0.25f); + } + + // Flag center. + { + full_shadows->shadow_flag_.GetValues(&s_scale, &s_density); + const Vector3f& p(full_shadows->shadow_flag_.GetPosition()); + g_graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0, s_density * 0.3f); + } + } else { + SimpleShadowSet* simple_shadows = simple_shadow_set_.get(); + assert(simple_shadows); + simple_shadows->shadow_.GetValues(&s_scale, &s_density); + const Vector3f& p(simple_shadows->shadow_.GetPosition()); + g_graphics->DrawBlotch(p, 0.8f * s_scale, 0, 0, 0, s_density * 0.5f); + } + c.Submit(); + } + + // Flag pole. + { + ObjectComponent c(frame_def->beauty_pass()); + c.SetTexture(g_media->GetTexture(SystemTextureID::kFlagPole)); + c.SetReflection(ReflectionType::kSharp); + c.SetReflectionScale(0.1f, 0.1f, 0.1f); + c.PushTransform(); + c.TransformToBody(*body_); + c.DrawModel(g_media->GetModel(SystemModelID::kFlagPole)); + c.PopTransform(); + c.Submit(); + } + +#endif // !BA_HEADLESS_BUILD +} + +void FlagNode::UpdateAreaOfInterest() { + AreaOfInterest* aoi = area_of_interest_; + if (!aoi) return; + assert(body_.exists()); + aoi->set_position(Vector3f(dGeomGetPosition(body_->geom()))); + aoi->SetRadius(5.0f); +} + +void FlagNode::Step() { + // On happy thoughts, keep us on the 2d plane. + if (g_graphics->camera()->happy_thoughts_mode() && body_.exists()) { + dBodyID b; + const dReal *p, *v; + b = body_->body(); + p = dBodyGetPosition(b); + float smoothing = 0.98f; + dBodySetPosition( + b, p[0], p[1], + p[2] * smoothing + (1.0f - smoothing) * kHappyThoughtsZPlane); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0], v[1], v[2] * smoothing); + } + + // update our area-of-interest if we have one + UpdateAreaOfInterest(); + + // FIXME: This should probably happen for RBDs automatically? + body_->UpdateBlending(); + + // Update our shadow objects. + dBodyID b = body_->body(); + assert(b); + +#if !BA_HEADLESS_BUILD + dVector3 p; + FullShadowSet* full_shadows = full_shadow_set_.get(); + if (full_shadows) { + full_shadows->shadow_flag_.SetPosition( + flag_points_[kFlagSizeX * (kFlagSizeY / 2) + (kFlagSizeX / 2)]); + dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.4f, p); + full_shadows->shadow_pole_bottom_.SetPosition(Vector3f(p)); + full_shadows->shadow_pole_middle_.SetPosition( + Vector3f(dBodyGetPosition(b))); + dBodyGetRelPointPos(b, 0, 0, kFlagHeight * 0.4f, p); + full_shadows->shadow_pole_top_.SetPosition(Vector3f(p)); + } else { + SimpleShadowSet* simple_shadows = simple_shadow_set_.get(); + assert(simple_shadows); + dBodyGetRelPointPos(b, 0, 0, kFlagHeight * -0.3f, p); + simple_shadows->shadow_.SetPosition(Vector3f(p)); + } +#endif // !BA_HEADLESS_BUILD + + if (dBodyIsEnabled(body_->body())) { + // Try to keep upright by pushing the top of the + // flag to be above the bottom. + { + float force_mag = 40.0f; + float force_max = 40.0f; + float min_dist = 0.05f; + + if (light_weight_) { + force_mag *= 0.3f; + force_max *= 0.3f; + } + dVector3 bottom, top; + dBodyGetRelPointPos(body_->body(), 0, 0, kFlagHeight / 2.0f, top); + dBodyGetRelPointPos(body_->body(), 0, 0, -kFlagHeight / 2.0f, bottom); + Vector3f top_v(top[0], top[1], top[2]); + Vector3f bot_v(bottom[0], bottom[1], bottom[2]); + Vector3f target_v(bot_v.x, bot_v.y + kFlagHeight, bot_v.z); + if ((std::abs(target_v.x - top_v.x) > min_dist) + || (std::abs(target_v.y - top_v.y) > min_dist) + || (std::abs(target_v.z - top_v.z) > min_dist)) { + dBodyEnable(body_->body()); + Vector3f fV((target_v - top_v) * force_mag); + float mag = fV.Length(); + if (mag > force_max) fV *= force_max / mag; + dBodyAddForceAtPos(body_->body(), fV.x, fV.y, fV.z, top_v.x, top_v.y, + top_v.z); + dBodyAddForceAtPos(body_->body(), -fV.x, -fV.y, -fV.z, bot_v.x, bot_v.y, + bot_v.z); + } + } + + // Apply damping force. + float linear_damping_x = 1.0f; + float linear_damping_y = 1.0f; + float linear_damping_z = 1.0f; + float rotational_damping_x = 1.0f; + float rotational_damping_y = 1.0f; + float rotational_damping_z = 1.0f; + + if (light_weight_) { + linear_damping_x *= 0.3f; + linear_damping_y *= 0.3f; + linear_damping_z *= 0.3f; + rotational_damping_x *= 0.3f; + rotational_damping_y *= 0.3f; + rotational_damping_z *= 0.3f; + } + + // Don't add forces if we're asleep otherwise we'll explode when we wake up. + dMass mass; + dBodyGetMass(body_->body(), &mass); + + const dReal* vel; + dReal force[3]; + vel = dBodyGetAngularVel(body_->body()); + force[0] = -1 * mass.mass * vel[0] * rotational_damping_x; + force[1] = -1 * mass.mass * vel[1] * rotational_damping_y; + force[2] = -1 * mass.mass * vel[2] * rotational_damping_z; + dBodyAddTorque(body_->body(), force[0], force[1], force[2]); + + vel = dBodyGetLinearVel(body_->body()); + force[0] = -1 * mass.mass * vel[0] * linear_damping_x; + force[1] = -1 * mass.mass * vel[1] * linear_damping_y; + force[2] = -1 * mass.mass * vel[2] * linear_damping_z; + dBodyAddForce(body_->body(), force[0], force[1], force[2]); + + // If we're out of bounds, arrange to have ourself informed. + { + const dReal* p2 = dBodyGetPosition(body_->body()); + if (scene()->IsOutOfBounds(p2[0], p2[1], p2[2])) { + scene()->AddOutOfBoundsNode(this); + } + } + } + UpdateFlagMesh(); +} + +auto FlagNode::GetRigidBody(int id) -> RigidBody* { return body_.get(); } + +static auto FlagPointIndex(int x, int y) -> int { + return kFlagSizeX * (y) + (x); +} + +void FlagNode::UpdateSpringPoint(int p1, int p2, float rest_length) { + Vector3f d = flag_points_[p2] - flag_points_[p1]; + float mag = d.Length(); + if (mag > (rest_length + 0.05f)) { + mag = rest_length + 0.05f; + } + Vector3f f = d / mag * kStiffness * (mag - rest_length); + flag_velocities_[p1] += f; + flag_velocities_[p2] -= f; + Vector3f vd = + kDampingStrength * (flag_velocities_[p1] - flag_velocities_[p2]); + flag_velocities_[p1] -= vd; + flag_velocities_[p2] += vd; +} + +void FlagNode::ResetFlagMesh() { + dVector3 up, side, top; + dBodyGetRelPointPos(body_->body(), 0, 0, kFlagHeight / 2, top); + dBodyVectorToWorld(body_->body(), 0, 0, 1, up); + dBodyVectorToWorld(body_->body(), 1, 0, 0, side); + Vector3f up_v(up); + Vector3f side_v(side); + Vector3f top_v(top); + up_v *= kFlagCanvasScaleY; + side_v *= kFlagCanvasScaleX; + for (int y = 0; y < kFlagSizeY; y++) { + for (int x = 0; x < kFlagSizeX; x++) { + int i = kFlagSizeX * y + x; + Vector3f p = + top_v - up_v * static_cast(y) + side_v * static_cast(x); + flag_points_[i].x = p.x; + flag_points_[i].y = p.y; + flag_points_[i].z = p.z; + flag_velocities_[i] = kVector3f0; + } + } + flag_impulse_add_x_ = flag_impulse_add_y_ = flag_impulse_add_z_ = 0; + have_flag_impulse_ = false; +} + +void FlagNode::UpdateFlagMesh() { + dVector3 up, top; + dBodyGetRelPointPos(body_->body(), 0, 0, kFlagHeight / 2, top); + dBodyVectorToWorld(body_->body(), 0, 0, 1, up); + Vector3f up_v(up); + Vector3f top_v(top); + up_v *= kFlagCanvasScaleY; + + // Move our attachment points into place. + for (int y = 0; y < kFlagSizeY; y++) { + int i = kFlagSizeX * y; + Vector3f p = top_v - up_v * static_cast(y); + flag_points_[i].x = p.x; + flag_points_[i].y = p.y; + flag_points_[i].z = p.z; + flag_velocities_[i] = kVector3f0; + } + + // Push our flag points around. + const dReal* flag_vel = dBodyGetLinearVel(body_->body()); + Vector3f wind_vec = {0.0f, 0.0f, 0.0f}; + bool do_wind = true; + if (RandomFloat() > 0.85f) { + wind_rand_x_ = 0.5f - RandomFloat(); + wind_rand_y_ = 0.5f - RandomFloat(); + if (scene()->stepnum() % 100 > 50) { + wind_rand_z_ = RandomFloat(); + } else { + wind_rand_z_ = -RandomFloat(); + } + wind_rand_ = static_cast(scene()->stepnum()); + } + + if (explicit_bool(do_wind)) { + wind_vec = -2.0f * Vector3f(flag_vel[0], flag_vel[1], flag_vel[2]); + + // If the flag is moving less than 1.0, add some ambient wind. + if (wind_vec.LengthSquared() < 1.0f) { + wind_vec += (1.0f - wind_vec.LengthSquared()) * Vector3f(5, 0, 0); + } + wind_vec += + 3.0f + * Vector3f(0.15f * wind_rand_x_, wind_rand_y_, 1.5f * wind_rand_z_); + } + + for (int y = 0; y < kFlagSizeY - 1; y++) { + for (int x = 0; x < kFlagSizeX - 1; x++) { + int top_left, top_right, bot_left, bot_right; + top_left = FlagPointIndex(x, y); + top_right = FlagPointIndex(x + 1, y); + bot_left = FlagPointIndex(x, y + 1); + bot_right = FlagPointIndex(x + 1, y + 1); + flag_velocities_[top_left].y -= kGravityStrength; + flag_velocities_[top_right].y -= kGravityStrength; + flag_velocities_[top_right].x *= (1.0f - kDragStrength); + flag_velocities_[top_right].y *= (1.0f - kDragStrength); + flag_velocities_[top_right].z *= (1.0f - kDragStrength); + if (have_flag_impulse_) { + flag_velocities_[top_left].x += flag_impulse_add_x_; + flag_velocities_[top_left].y += flag_impulse_add_y_; + flag_velocities_[top_left].z += flag_impulse_add_z_; + flag_velocities_[top_right].x += flag_impulse_add_x_; + flag_velocities_[top_right].y += flag_impulse_add_y_; + flag_velocities_[top_right].z += flag_impulse_add_z_; + } + + // Wind. + // FIXME - we can prolly move some of this out of the inner loop.. + if (explicit_bool(do_wind)) { + flag_velocities_[top_right].x += + wind_vec.x * kWindStrength + * (Utils::precalc_rands_1[wind_rand_ % kPrecalcRandsCount] - 0.3f); + flag_velocities_[top_right].y += + wind_vec.y * kWindStrength + * (Utils::precalc_rands_2[wind_rand_ % kPrecalcRandsCount] - 0.3f); + flag_velocities_[top_right].z += + wind_vec.z * kWindStrength + * (Utils::precalc_rands_3[wind_rand_ % kPrecalcRandsCount] - 0.3f); + } + UpdateSpringPoint(top_left, top_right, kFlagCanvasScaleX); + UpdateSpringPoint(bot_left, bot_right, kFlagCanvasScaleX); + UpdateSpringPoint(top_left, bot_left, kFlagCanvasScaleY); + UpdateSpringPoint(top_right, bot_right, kFlagCanvasScaleY); + UpdateSpringPoint(top_left, bot_right, kFlagCanvasScaleDiagonal); + UpdateSpringPoint(top_right, bot_left, kFlagCanvasScaleDiagonal); + } + } + + flag_impulse_add_x_ = flag_impulse_add_y_ = flag_impulse_add_z_ = 0; + + // Now update positions (except pole points). + for (int y = 0; y < kFlagSizeY; y++) { + for (int x = 0; x < kFlagSizeX; x++) { + int i = kFlagSizeX * y + x; + flag_points_[i] += flag_velocities_[i]; + } + } + + // Now calc normals. + for (int y = 0; y < kFlagSizeY; y++) { + for (int x = 0; x < kFlagSizeX; x++) { + // Calc the normal for this vert. + int xclamped = std::min(x, kFlagSizeX - 2); + int yclamped = std::min(y, kFlagSizeY - 2); + int i = kFlagSizeX * yclamped + xclamped; + flag_normals_[i] = + Vector3f::Cross(flag_points_[i + 1] - flag_points_[i], + flag_points_[i + kFlagSizeX] - flag_points_[i]) + .Normalized(); + } + } +} + +void FlagNode::GetRigidBodyPickupLocations(int id, float* obj, float* character, + float* hand1, float* hand2) { + obj[0] = 0; + obj[1] = 0; + obj[2] = -0.6f; + character[0] = 0; + character[1] = -0.4f; + character[2] = 0.3f; + hand1[0] = hand1[1] = hand1[2] = 0; + hand2[0] = hand2[1] = hand2[2] = 0; + hand2[0] = 0.05f; + hand2[2] = -0.1f; + hand1[0] = -0.05f; + hand1[2] = -0.05f; +} + +void FlagNode::OnGraphicsQualityChanged(GraphicsQuality q) { + UpdateForGraphicsQuality(q); +} + +void FlagNode::UpdateForGraphicsQuality(GraphicsQuality quality) { +#if !BA_HEADLESS_BUILD + if (quality >= GraphicsQuality::kMedium) { + full_shadow_set_ = Object::New(); + simple_shadow_set_.Clear(); + } else { + simple_shadow_set_ = Object::New(); + full_shadow_set_.Clear(); + } +#endif +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/flag_node.h b/src/ballistica/scene/node/flag_node.h new file mode 100644 index 00000000..19c19e8c --- /dev/null +++ b/src/ballistica/scene/node/flag_node.h @@ -0,0 +1,77 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_FLAG_NODE_H_ +#define BALLISTICA_SCENE_NODE_FLAG_NODE_H_ + +#include + +#include "ballistica/dynamics/part.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class FlagNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit FlagNode(Scene* scene); + ~FlagNode() override; + void HandleMessage(const char* data) override; + void Draw(FrameDef* frame_def) override; + void Step() override; + auto GetRigidBody(int id) -> RigidBody* override; + auto is_area_of_interest() const -> bool { + return (area_of_interest_ != nullptr); + } + void SetIsAreaOfInterest(bool val); + auto getPosition() const -> std::vector; + void SetPosition(const std::vector& vals); + auto color_texture() const -> Texture* { return color_texture_.get(); } + void set_color_texture(Texture* val) { color_texture_ = val; } + auto light_weight() const -> bool { return light_weight_; } + void SetLightWeight(bool val); + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& vals); + auto GetMaterials() const -> std::vector; + void SetMaterials(const std::vector& materials); + + private: + class FullShadowSet; + class SimpleShadowSet; + void UpdateAreaOfInterest(); + void GetRigidBodyPickupLocations(int id, float* obj, float* character, + float* hand1, float* hand2) override; + void UpdateDimensions(); + void ResetFlagMesh(); + void UpdateFlagMesh(); + void OnGraphicsQualityChanged(GraphicsQuality q) override; + void UpdateForGraphicsQuality(GraphicsQuality q); + void UpdateSpringPoint(int p1, int p2, float rest_length); + AreaOfInterest* area_of_interest_ = nullptr; + Part part_; + std::vector color_ = {1.0f, 1.0f, 1.0f}; + Object::Ref body_{nullptr}; + Object::Ref color_texture_; + MeshIndexedObjectSplit mesh_; +#if !BA_HEADLESS_BUILD + Object::Ref full_shadow_set_; + Object::Ref simple_shadow_set_; +#endif // !BA_HEADLESS_BUILD + int wind_rand_{}; + float wind_rand_x_{}; + float wind_rand_y_{}; + float wind_rand_z_{}; + float flag_impulse_add_x_{}; + float flag_impulse_add_y_{}; + float flag_impulse_add_z_{}; + bool have_flag_impulse_{}; + int footing_{}; + bool light_weight_{}; + Vector3f flag_points_[25]{}; + Vector3f flag_normals_[25]{}; + Vector3f flag_velocities_[25]{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_FLAG_NODE_H_ diff --git a/src/ballistica/scene/node/flash_node.cc b/src/ballistica/scene/node/flash_node.cc new file mode 100644 index 00000000..825ed2d7 --- /dev/null +++ b/src/ballistica/scene/node/flash_node.cc @@ -0,0 +1,60 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/flash_node.h" + +#include + +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class FlashNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS FlashNode + BA_NODE_CREATE_CALL(CreateFlash); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ATTR(size, size, set_size); + BA_FLOAT_ARRAY_ATTR(color, color, set_color); +#undef BA_NODE_TYPE_CLASS + + FlashNodeType() + : NodeType("flash", CreateFlash), + position(this), + size(this), + color(this) {} +}; +static NodeType* node_type{}; + +auto FlashNode::InitType() -> NodeType* { + node_type = new FlashNodeType(); + return node_type; +} + +FlashNode::FlashNode(Scene* scene) : Node(scene, node_type) {} + +FlashNode::~FlashNode() = default; + +void FlashNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for position"); + } + position_ = vals; +} + +void FlashNode::Draw(FrameDef* frame_def) { + ObjectComponent c(frame_def->beauty_pass()); + c.SetLightShadow(LightShadowType::kNone); + c.SetColor(color_[0], color_[1], color_[2], 1.0f); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(size_, size_, size_); + c.Rotate(RandomFloat() * 360.0f, 1, 1, 0); + c.DrawModel(g_media->GetModel(SystemModelID::kFlash)); + c.PopTransform(); + c.Submit(); +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/flash_node.h b/src/ballistica/scene/node/flash_node.h new file mode 100644 index 00000000..b86280ac --- /dev/null +++ b/src/ballistica/scene/node/flash_node.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_FLASH_NODE_H_ +#define BALLISTICA_SCENE_NODE_FLASH_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class FlashNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit FlashNode(Scene* scene); + ~FlashNode() override; + void Draw(FrameDef* frame_def) override; + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& vals); + auto size() const -> float { return size_; } + void set_size(float val) { size_ = val; } + auto color() const -> std::vector { return color_; } + void set_color(const std::vector& vals) { color_ = vals; } + + private: + std::vector position_ = {0.0f, 0.0f, 0.0f}; + float size_ = 1.0f; + std::vector color_ = {0.5f, 0.5f, 0.5f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_FLASH_NODE_H_ diff --git a/src/ballistica/scene/node/globals_node.cc b/src/ballistica/scene/node/globals_node.cc new file mode 100644 index 00000000..391dac28 --- /dev/null +++ b/src/ballistica/scene/node/globals_node.cc @@ -0,0 +1,444 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/globals_node.h" + +#include "ballistica/audio/audio.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/game/host_activity.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/vr_graphics.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class GlobalsNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS GlobalsNode + BA_NODE_CREATE_CALL(CreateGlobals); + BA_INT64_ATTR_READONLY(real_time, GetRealTime); + BA_INT64_ATTR_READONLY(time, GetTime); + BA_INT64_ATTR_READONLY(step, GetStep); + BA_FLOAT_ATTR(debris_friction, debris_friction, SetDebrisFriction); + BA_BOOL_ATTR(floor_reflection, floor_reflection, SetFloorReflection); + BA_FLOAT_ATTR(debris_kill_height, debris_kill_height, SetDebrisKillHeight); + BA_STRING_ATTR(camera_mode, GetCameraMode, SetCameraMode); + BA_BOOL_ATTR(happy_thoughts_mode, happy_thoughts_mode, SetHappyThoughtsMode); + BA_FLOAT_ARRAY_ATTR(shadow_scale, shadow_scale, SetShadowScale); + BA_FLOAT_ARRAY_ATTR(area_of_interest_bounds, area_of_interest_bounds, + set_area_of_interest_bounds); + BA_FLOAT_ARRAY_ATTR(shadow_range, shadow_range, SetShadowRange); + BA_FLOAT_ARRAY_ATTR(shadow_offset, shadow_offset, SetShadowOffset); + BA_BOOL_ATTR(shadow_ortho, shadow_ortho, SetShadowOrtho); + BA_FLOAT_ARRAY_ATTR(tint, tint, SetTint); + BA_FLOAT_ARRAY_ATTR(vr_overlay_center, vr_overlay_center, SetVROverlayCenter); + BA_BOOL_ATTR(vr_overlay_center_enabled, vr_overlay_center_enabled, + SetVROverlayCenterEnabled); + BA_FLOAT_ARRAY_ATTR(ambient_color, ambient_color, SetAmbientColor); + BA_FLOAT_ARRAY_ATTR(vignette_outer, vignette_outer, SetVignetteOuter); + BA_FLOAT_ARRAY_ATTR(vignette_inner, vignette_inner, SetVignetteInner); + BA_BOOL_ATTR(allow_kick_idle_players, allow_kick_idle_players, + SetAllowKickIdlePlayers); + BA_BOOL_ATTR(slow_motion, slow_motion, SetSlowMotion); + BA_BOOL_ATTR(paused, paused, SetPaused); + BA_FLOAT_ARRAY_ATTR(vr_camera_offset, vr_camera_offset, SetVRCameraOffset); + BA_BOOL_ATTR(use_fixed_vr_overlay, use_fixed_vr_overlay, + SetUseFixedVROverlay); + BA_FLOAT_ATTR(vr_near_clip, vr_near_clip, SetVRNearClip); + BA_BOOL_ATTR(music_continuous, music_continuous, set_music_continuous); + BA_STRING_ATTR(music, music, set_music); + BA_INT_ATTR(music_count, music_count, SetMusicCount); +#undef BA_NODE_TYPE_CLASS + + GlobalsNodeType() + : NodeType("globals", CreateGlobals), + real_time(this), + time(this), + step(this), + debris_friction(this), + floor_reflection(this), + debris_kill_height(this), + camera_mode(this), + happy_thoughts_mode(this), + shadow_scale(this), + area_of_interest_bounds(this), + shadow_range(this), + shadow_offset(this), + shadow_ortho(this), + tint(this), + vr_overlay_center(this), + vr_overlay_center_enabled(this), + ambient_color(this), + vignette_outer(this), + vignette_inner(this), + allow_kick_idle_players(this), + slow_motion(this), + paused(this), + vr_camera_offset(this), + use_fixed_vr_overlay(this), + vr_near_clip(this), + music_continuous(this), + music(this), + music_count(this) {} +}; + +static NodeType* node_type{}; + +auto GlobalsNode::InitType() -> NodeType* { + node_type = new GlobalsNodeType(); + return node_type; +} + +GlobalsNode::GlobalsNode(Scene* scene) : Node(scene, node_type) { + // Set ourself as the current globals node for our scene. + this->scene()->set_globals_node(this); + + // If we're being made in a host-activity, also set ourself as the current + // globals node for our activity. (there should only be one, so complain if + // there already is one). + // FIXME: Need to update this for non-host activities at some point. + if (HostActivity* ha = context().GetHostActivity()) { + if (ha->globals_node()) { + Log("WARNING: more than one globals node created in HostActivity; this " + "shouldn't happen"); + } + ha->globals_node_ = this; + + // Set some values we always drive even when not the singleton 'current' + // globals (stuff that only affects our activity/scene). + ha->SetGameSpeed(slow_motion_ ? 0.32f : 1.0f); + ha->SetPaused(paused_); + ha->set_allow_kick_idle_players(allow_kick_idle_players_); + this->scene()->set_use_fixed_vr_overlay(use_fixed_vr_overlay_); + } + + // If our scene is currently the game's foreground one, go ahead and + // push our values globally. + if (g_game->GetForegroundScene() == this->scene()) { + SetAsForeground(); + } +} + +GlobalsNode::~GlobalsNode() { + // If we are the current globals node for our scene, clear it out. + if (scene()->globals_node() == this) { + scene()->set_globals_node(nullptr); + } +} + +// Called when we're being made the one foreground node and should push our +// values to the global state (since there can be multiple scenes in +// existence, there has to be a single "foreground" globals node in control). +void GlobalsNode::SetAsForeground() { +#if !BA_HEADLESS_BUILD + g_bg_dynamics->SetDebrisFriction(debris_friction_); + g_bg_dynamics->SetDebrisKillHeight(debris_kill_height_); +#endif + g_graphics->set_floor_reflection(floor_reflection_); + g_graphics->camera()->SetMode(camera_mode_); + g_graphics->camera()->set_vr_offset(Vector3f(vr_camera_offset_)); + g_graphics->camera()->set_happy_thoughts_mode(happy_thoughts_mode_); + g_graphics->set_shadow_scale(shadow_scale_[0], shadow_scale_[1]); + g_graphics->camera()->set_area_of_interest_bounds( + area_of_interest_bounds_[0], area_of_interest_bounds_[1], + area_of_interest_bounds_[2], area_of_interest_bounds_[3], + area_of_interest_bounds_[4], area_of_interest_bounds_[5]); + g_graphics->SetShadowRange(shadow_range_[0], shadow_range_[1], + shadow_range_[2], shadow_range_[3]); + g_graphics->set_shadow_offset(Vector3f(shadow_offset_)); + g_graphics->set_shadow_ortho(shadow_ortho_); + g_graphics->set_tint(Vector3f(tint_)); + +#if BA_VR_BUILD + if (IsVRMode()) { + auto* vrgraphics = VRGraphics::get(); + vrgraphics->set_vr_near_clip(vr_near_clip_); + vrgraphics->set_vr_overlay_center(Vector3f(vr_overlay_center_)); + vrgraphics->set_vr_overlay_center_enabled(vr_overlay_center_enabled_); + } +#endif + + g_graphics->set_ambient_color(Vector3f(ambient_color_)); + g_graphics->set_vignette_outer(Vector3f(vignette_outer_)); + g_graphics->set_vignette_inner(Vector3f(vignette_inner_)); + + g_audio->SetSoundPitch(slow_motion_ ? 0.4f : 1.0f); + + // Tell the scripting layer to play our current music. + g_python->PlayMusic(music_, music_continuous_); +} + +auto GlobalsNode::IsCurrentGlobals() const -> bool { + // We're current if our scene is the foreground one and we're the globals + // node for our scene. + Scene* scene = this->scene(); + assert(scene); + return (g_game->GetForegroundScene() == this->scene() + && scene->globals_node() == this); +} + +auto GlobalsNode::GetRealTime() -> millisecs_t { + // Pull this from our scene so we return consistent values throughout a step. + return scene()->last_step_real_time(); +} + +auto GlobalsNode::GetTime() -> millisecs_t { return scene()->time(); } +auto GlobalsNode::GetStep() -> int64_t { return scene()->stepnum(); } + +void GlobalsNode::SetDebrisFriction(float val) { + debris_friction_ = val; + if (IsCurrentGlobals()) { +#if !BA_HEADLESS_BUILD + g_bg_dynamics->SetDebrisFriction(debris_friction_); +#endif // !BA_HEADLESS_BUILD + } +} + +void GlobalsNode::SetVRNearClip(float val) { + vr_near_clip_ = val; +#if BA_VR_BUILD + if (IsVRMode()) { + if (IsCurrentGlobals()) { + VRGraphics::get()->set_vr_near_clip(vr_near_clip_); + } + } +#endif +} + +void GlobalsNode::SetFloorReflection(bool val) { + floor_reflection_ = val; + if (IsCurrentGlobals()) { + g_graphics->set_floor_reflection(floor_reflection_); + } +} + +void GlobalsNode::SetDebrisKillHeight(float val) { + debris_kill_height_ = val; + if (IsCurrentGlobals()) { +#if !BA_HEADLESS_BUILD + g_bg_dynamics->SetDebrisKillHeight(debris_kill_height_); +#endif // !BA_HEADLESS_BUILD + } +} + +void GlobalsNode::SetHappyThoughtsMode(bool val) { + happy_thoughts_mode_ = val; + if (IsCurrentGlobals()) { + g_graphics->camera()->set_happy_thoughts_mode(happy_thoughts_mode_); + } +} + +void GlobalsNode::SetShadowScale(const std::vector& vals) { + if (vals.size() != 2) { + throw Exception("Expected float array of length 2 for shadow_scale"); + } + shadow_scale_ = vals; + if (IsCurrentGlobals()) { + g_graphics->set_shadow_scale(shadow_scale_[0], shadow_scale_[1]); + } +} + +void GlobalsNode::set_area_of_interest_bounds(const std::vector& vals) { + if (vals.size() != 6) { + throw Exception( + "Expected float array of length 6 for area_of_interest_bounds"); + } + area_of_interest_bounds_ = vals; + + assert(g_graphics->camera()); + if (IsCurrentGlobals()) { + g_graphics->camera()->set_area_of_interest_bounds( + area_of_interest_bounds_[0], area_of_interest_bounds_[1], + area_of_interest_bounds_[2], area_of_interest_bounds_[3], + area_of_interest_bounds_[4], area_of_interest_bounds_[5]); + } +} + +void GlobalsNode::SetShadowRange(const std::vector& vals) { + if (vals.size() != 4) { + throw Exception("Expected float array of length 4 for shadow_range"); + } + shadow_range_ = vals; + if (IsCurrentGlobals()) { + g_graphics->SetShadowRange(shadow_range_[0], shadow_range_[1], + shadow_range_[2], shadow_range_[3]); + } +} + +void GlobalsNode::SetShadowOffset(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for shadow_offset"); + } + shadow_offset_ = vals; + if (IsCurrentGlobals()) { + g_graphics->set_shadow_offset(Vector3f(shadow_offset_)); + } +} + +void GlobalsNode::SetVRCameraOffset(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for vr_camera_offset"); + } + vr_camera_offset_ = vals; + if (IsCurrentGlobals()) { + g_graphics->camera()->set_vr_offset(Vector3f(vr_camera_offset_)); + } +} + +void GlobalsNode::SetShadowOrtho(bool val) { + shadow_ortho_ = val; + if (IsCurrentGlobals()) { + g_graphics->set_shadow_ortho(shadow_ortho_); + } +} + +void GlobalsNode::SetTint(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for tint"); + } + tint_ = vals; + if (IsCurrentGlobals()) { + g_graphics->set_tint(Vector3f(tint_[0], tint_[1], tint_[2])); + } +} + +void GlobalsNode::SetVROverlayCenter(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for vr_overlay_center"); + } + vr_overlay_center_ = vals; +#if BA_VR_BUILD + if (IsCurrentGlobals()) { + VRGraphics::get()->set_vr_overlay_center(Vector3f(vr_overlay_center_)); + } +#endif +} + +void GlobalsNode::SetVROverlayCenterEnabled(bool val) { + vr_overlay_center_enabled_ = val; +#if BA_VR_BUILD + if (IsCurrentGlobals()) { + VRGraphics::get()->set_vr_overlay_center_enabled( + vr_overlay_center_enabled_); + } +#endif +} + +void GlobalsNode::SetAmbientColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for ambient_color"); + } + ambient_color_ = vals; + if (IsCurrentGlobals()) { + g_graphics->set_ambient_color(Vector3f(ambient_color_)); + } +} + +void GlobalsNode::SetVignetteOuter(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for vignette_outer"); + } + vignette_outer_ = vals; + if (IsCurrentGlobals()) { + g_graphics->set_vignette_outer(Vector3f(vignette_outer_)); + } +} + +void GlobalsNode::SetVignetteInner(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for vignette_inner"); + } + vignette_inner_ = vals; + if (IsCurrentGlobals()) { + g_graphics->set_vignette_inner(Vector3f(vignette_inner_)); + } +} + +auto GlobalsNode::GetCameraMode() const -> std::string { + switch (camera_mode_) { + case CameraMode::kOrbit: + return "rotate"; + case CameraMode::kFollow: + return "follow"; + default: + Log("ERROR: Globals: Unrecognized camera_mode_: " + + std::to_string(static_cast(camera_mode_))); + return "unknown"; + } +} + +void GlobalsNode::SetCameraMode(const std::string& val) { + if (val == "rotate") { + camera_mode_ = CameraMode::kOrbit; + } else if (val == "follow") { + camera_mode_ = CameraMode::kFollow; + } else { + throw Exception("Invalid camera mode: '" + val + + R"('; expected "rotate" or "follow")"); + } + if (IsCurrentGlobals()) g_graphics->camera()->SetMode(camera_mode_); +} + +void GlobalsNode::SetAllowKickIdlePlayers(bool val) { + allow_kick_idle_players_ = val; + + // This only means something if we're in a host-activity. + if (HostActivity* ha = context().GetHostActivity()) { + // Set speed on our activity even if we're not the current globals node. + if (ha->globals_node() == this) { + ha->set_allow_kick_idle_players(allow_kick_idle_players_); + } + } +} + +void GlobalsNode::SetSlowMotion(bool val) { + slow_motion_ = val; + + // This only matters if we're in a host-activity. + // (clients are just driven by whatever steps are in the input-stream) + if (HostActivity* ha = context().GetHostActivity()) { + // Set speed on *our* activity regardless of whether we're the current + // globals node. + if (ha->globals_node() == this) { + ha->SetGameSpeed(slow_motion_ ? 0.32f : 1.0f); + } + } + + // Only set pitch if we are the current globals node. + // (FIXME - need to make this per-sound or something) + if (IsCurrentGlobals()) { + g_audio->SetSoundPitch(slow_motion_ ? 0.4f : 1.0f); + } +} + +void GlobalsNode::SetPaused(bool val) { + paused_ = val; + + // This only matters in a host-activity. + // (clients are just driven by whatever steps are in the input-stream) + if (HostActivity* ha = context().GetHostActivity()) { + // Set speed on our activity even if we're not the current globals node. + if (ha->globals_node() == this) { + ha->SetPaused(paused_); + } + } +} + +void GlobalsNode::SetUseFixedVROverlay(bool val) { + use_fixed_vr_overlay_ = val; + + // Always apply this value to our scene. + scene()->set_use_fixed_vr_overlay(val); +} + +void GlobalsNode::SetMusicCount(int val) { + if (music_count_ != val && IsCurrentGlobals()) { + g_python->PlayMusic(music_, music_continuous_); + } + music_count_ = val; +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/globals_node.h b/src/ballistica/scene/node/globals_node.h new file mode 100644 index 00000000..4d73a74a --- /dev/null +++ b/src/ballistica/scene/node/globals_node.h @@ -0,0 +1,130 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_GLOBALS_NODE_H_ +#define BALLISTICA_SCENE_NODE_GLOBALS_NODE_H_ + +#include +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class GlobalsNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit GlobalsNode(Scene* scene); + ~GlobalsNode() override; + void SetAsForeground(); + auto IsCurrentGlobals() const -> bool; + auto GetRealTime() -> millisecs_t; + auto GetTime() -> millisecs_t; + auto GetStep() -> int64_t; + auto debris_friction() const -> float { return debris_friction_; } + void SetDebrisFriction(float val); + auto floor_reflection() const -> bool { return floor_reflection_; } + void SetFloorReflection(bool val); + auto debris_kill_height() const -> float { return debris_kill_height_; } + void SetDebrisKillHeight(float val); + auto GetCameraMode() const -> std::string; + void SetCameraMode(const std::string& val); + void SetHappyThoughtsMode(bool val); + auto happy_thoughts_mode() const -> bool { return happy_thoughts_mode_; } + auto shadow_scale() const -> const std::vector& { + return shadow_scale_; + } + void SetShadowScale(const std::vector& vals); + auto area_of_interest_bounds() const -> const std::vector& { + return area_of_interest_bounds_; + } + void set_area_of_interest_bounds(const std::vector& vals); + auto shadow_range() const -> const std::vector& { + return shadow_range_; + } + void SetShadowRange(const std::vector& vals); + auto shadow_offset() const -> const std::vector& { + return shadow_offset_; + } + void SetShadowOffset(const std::vector& vals); + auto shadow_ortho() const -> bool { return shadow_ortho_; } + void SetShadowOrtho(bool val); + auto tint() const -> const std::vector& { return tint_; } + void SetTint(const std::vector& vals); + auto vr_overlay_center() const -> const std::vector& { + return vr_overlay_center_; + } + void SetVROverlayCenter(const std::vector& vals); + auto vr_overlay_center_enabled() const -> bool { + return vr_overlay_center_enabled_; + } + void SetVROverlayCenterEnabled(bool); + auto ambient_color() const -> const std::vector& { + return ambient_color_; + } + void SetAmbientColor(const std::vector& vals); + auto vignette_outer() const -> const std::vector& { + return vignette_outer_; + } + void SetVignetteOuter(const std::vector& vals); + auto vignette_inner() const -> const std::vector& { + return vignette_inner_; + } + void SetVignetteInner(const std::vector& vals); + auto allow_kick_idle_players() const -> bool { + return allow_kick_idle_players_; + } + void SetAllowKickIdlePlayers(bool allow); + auto slow_motion() const -> bool { return slow_motion_; } + void SetSlowMotion(bool val); + auto paused() const -> bool { return paused_; } + void SetPaused(bool val); + auto vr_camera_offset() const -> const std::vector& { + return vr_camera_offset_; + } + void SetVRCameraOffset(const std::vector& vals); + auto use_fixed_vr_overlay() const -> bool { return use_fixed_vr_overlay_; } + void SetUseFixedVROverlay(bool val); + auto vr_near_clip() const -> float { return vr_near_clip_; } + void SetVRNearClip(float val); + auto music_continuous() const -> bool { return music_continuous_; } + void set_music_continuous(bool val) { music_continuous_ = val; } + auto music() const -> const std::string& { return music_; } + void set_music(const std::string& val) { music_ = val; } + + // We actually change the song only when this value changes + // (allows us to restart the same song) + auto music_count() const -> int { return music_count_; } + void SetMusicCount(int val); + + protected: + CameraMode camera_mode_{CameraMode::kFollow}; + float vr_near_clip_{4.0f}; + float debris_friction_{1.0f}; + bool floor_reflection_{}; + float debris_kill_height_{-50.0f}; + bool happy_thoughts_mode_{}; + bool use_fixed_vr_overlay_{}; + int music_count_{}; + bool music_continuous_{}; + std::string music_; + std::vector vr_camera_offset_{0.0f, 0.0f, 0.0f}; + std::vector shadow_scale_{1.0f, 1.0f}; + std::vector area_of_interest_bounds_{-9999.0f, -9999.0f, -9999.0f, + 9999.0f, 9999.0f, 9999.0f}; + std::vector shadow_range_{-4.0f, 0.0f, 10.0f, 15.0f}; + std::vector shadow_offset_{0.0f, 0.0f, 0.0f}; + bool shadow_ortho_{}; + bool vr_overlay_center_enabled_{}; + std::vector vr_overlay_center_{0.0f, 4.0f, -3.0f}; + std::vector tint_{1.1f, 1.0f, 0.9f}; + std::vector ambient_color_{1.0f, 1.0f, 1.0f}; + std::vector vignette_outer_{0.6f, 0.6f, 0.6f}; + std::vector vignette_inner_{0.95f, 0.95f, 0.95f}; + bool allow_kick_idle_players_{}; + bool slow_motion_{}; + bool paused_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_GLOBALS_NODE_H_ diff --git a/src/ballistica/scene/node/image_node.cc b/src/ballistica/scene/node/image_node.cc new file mode 100644 index 00000000..68c8cd63 --- /dev/null +++ b/src/ballistica/scene/node/image_node.cc @@ -0,0 +1,400 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/image_node.h" + +#include +#include + +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/media/component/model.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class ImageNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS ImageNode + BA_NODE_CREATE_CALL(CreateImage); + BA_FLOAT_ARRAY_ATTR(scale, scale, SetScale); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ATTR(opacity, opacity, set_opacity); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_FLOAT_ARRAY_ATTR(tint_color, tint_color, SetTintColor); + BA_FLOAT_ARRAY_ATTR(tint2_color, tint2_color, SetTint2Color); + BA_BOOL_ATTR(fill_screen, fill_screen, SetFillScreen); + BA_BOOL_ATTR(has_alpha_channel, has_alpha_channel, set_has_alpha_channel); + BA_BOOL_ATTR(absolute_scale, absolute_scale, set_absolute_scale); + BA_FLOAT_ATTR(tilt_translate, tilt_translate, set_tilt_translate); + BA_FLOAT_ATTR(rotate, rotate, set_rotate); + BA_BOOL_ATTR(premultiplied, premultiplied, set_premultiplied); + BA_STRING_ATTR(attach, GetAttach, SetAttach); + BA_TEXTURE_ATTR(texture, texture, set_texture); + BA_TEXTURE_ATTR(tint_texture, tint_texture, set_tint_texture); + BA_TEXTURE_ATTR(mask_texture, mask_texture, set_mask_texture); + BA_MODEL_ATTR(model_opaque, model_opaque, set_model_opaque); + BA_MODEL_ATTR(model_transparent, model_transparent, set_model_transparent); + BA_FLOAT_ATTR(vr_depth, vr_depth, set_vr_depth); + BA_BOOL_ATTR(host_only, host_only, set_host_only); + BA_BOOL_ATTR(front, front, set_front); +#undef BA_NODE_TYPE_CLASS + + ImageNodeType() + : NodeType("image", CreateImage), + scale(this), + position(this), + opacity(this), + color(this), + tint_color(this), + tint2_color(this), + fill_screen(this), + has_alpha_channel(this), + absolute_scale(this), + tilt_translate(this), + rotate(this), + premultiplied(this), + attach(this), + texture(this), + tint_texture(this), + mask_texture(this), + model_opaque(this), + model_transparent(this), + vr_depth(this), + host_only(this), + front(this) {} +}; +static NodeType* node_type{}; + +auto ImageNode::InitType() -> NodeType* { + node_type = new ImageNodeType(); + return node_type; +} + +ImageNode::ImageNode(Scene* scene) : Node(scene, node_type) {} + +ImageNode::~ImageNode() { + if (fill_screen_) scene()->decrement_bg_cover_count(); +} + +auto ImageNode::GetAttach() const -> std::string { + switch (attach_) { + case Attach::CENTER: + return "center"; + case Attach::TOP_LEFT: + return "topLeft"; + case Attach::TOP_CENTER: + return "topCenter"; + case Attach::TOP_RIGHT: + return "topRight"; + case Attach::CENTER_RIGHT: + return "centerRight"; + case Attach::BOTTOM_RIGHT: + return "bottomRight"; + case Attach::BOTTOM_CENTER: + return "bottomCenter"; + case Attach::BOTTOM_LEFT: + return "bottomLeft"; + case Attach::CENTER_LEFT: + return "centerLeft"; + default: + throw Exception("Invalid attach val in ImageNode " + + std::to_string(static_cast(attach_))); + } +} + +void ImageNode::SetAttach(const std::string& val) { + dirty_ = true; + if (val == "center") { + attach_ = Attach::CENTER; + } else if (val == "topLeft") { + attach_ = Attach::TOP_LEFT; + } else if (val == "topCenter") { + attach_ = Attach::TOP_CENTER; + } else if (val == "topRight") { + attach_ = Attach::TOP_RIGHT; + } else if (val == "centerRight") { + attach_ = Attach::CENTER_RIGHT; + } else if (val == "bottomRight") { + attach_ = Attach::BOTTOM_RIGHT; + } else if (val == "bottomCenter") { + attach_ = Attach::BOTTOM_CENTER; + } else if (val == "bottomLeft") { + attach_ = Attach::BOTTOM_LEFT; + } else if (val == "centerLeft") { + attach_ = Attach::CENTER_LEFT; + } else { + throw Exception("Invalid attach value for ImageNode: " + val); + } +} + +void ImageNode::SetTint2Color(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for tint2_color"); + } + tint2_color_ = vals; + tint2_red_ = tint2_color_[0]; + tint2_green_ = tint2_color_[1]; + tint2_blue_ = tint2_color_[2]; +} + +void ImageNode::SetTintColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for tint_color"); + } + tint_color_ = vals; + tint_red_ = tint_color_[0]; + tint_green_ = tint_color_[1]; + tint_blue_ = tint_color_[2]; +} + +void ImageNode::SetColor(const std::vector& vals) { + if (vals.size() != 3 && vals.size() != 4) { + throw Exception("Got " + std::to_string(vals.size()) + + " values for 'color'; expected 3 or 4."); + } + red_ = vals[0]; + green_ = vals[1]; + blue_ = vals[2]; + if (vals.size() == 4) { + alpha_ = vals[3]; + } else { + alpha_ = 1.0f; + } + color_ = vals; +} + +void ImageNode::SetScale(const std::vector& vals) { + if (vals.size() != 1 && vals.size() != 2) { + throw Exception("Expected float array of length 1 or 2 for scale"); + } + dirty_ = true; + scale_ = vals; +} + +void ImageNode::SetPosition(const std::vector& vals) { + if (vals.size() != 2) { + throw Exception("Expected float array of length 2 for position"); + } + dirty_ = true; + position_ = vals; +} + +void ImageNode::OnScreenSizeChange() { dirty_ = true; } + +void ImageNode::SetFillScreen(bool val) { + bool old = fill_screen_; + fill_screen_ = val; + dirty_ = true; + + // Help the scene keep track of stuff that covers the whole background + // (so it knows it doesnt have to clear). + if (!old && fill_screen_) scene()->increment_bg_cover_count(); + if (old && !fill_screen_) scene()->decrement_bg_cover_count(); + + // We keep track of how many full-screen images are present at any given time. + // vr-mode uses this to lock down the overlay layer's position in that case. +} + +void ImageNode::Draw(FrameDef* frame_def) { + if (host_only_ && !context().GetHostSession()) return; + bool vr = (IsVRMode()); + + // In vr mode we use the fixed overlay position if our scene + // is set for that. + bool vr_use_fixed = (scene()->use_fixed_vr_overlay()); + + // Currently front and vr-fixed are mutually-exclusive.. need to fix. + if (front_) { + vr_use_fixed = false; + } + + RenderPass& pass(*(vr_use_fixed ? frame_def->GetOverlayFixedPass() + : front_ ? frame_def->overlay_front_pass() + : frame_def->overlay_pass())); + + // If the pass we're drawing into changes dimensions, recalc. + // Otherwise we break if a window is resized. + float screen_width = pass.virtual_width(); + float screen_height = pass.virtual_height(); + if (dirty_) { + float width = absolute_scale_ ? scale_[0] : screen_height * scale_[0]; + float height = + (scale_.size() > 1) + ? (absolute_scale_ ? scale_[1] : screen_height * scale_[1]) + : width; + float center_x, center_y; + float scale_mult_x = absolute_scale_ ? 1.0f : screen_width; + float scale_mult_y = absolute_scale_ ? 1.0f : screen_height; + float screen_center_x = screen_width / 2; + float screen_center_y = screen_height / 2; + float tx = position_[0]; + float ty = position_[1]; + if (!absolute_scale_) { + tx *= scale_mult_x; + ty *= scale_mult_y; + } + switch (attach_) { + case Attach::BOTTOM_LEFT: + case Attach::BOTTOM_CENTER: + case Attach::BOTTOM_RIGHT: { + center_y = ty; + break; + } + case Attach::TOP_LEFT: + case Attach::TOP_CENTER: + case Attach::TOP_RIGHT: { + center_y = screen_height + ty; + break; + } + case Attach::CENTER_LEFT: + case Attach::CENTER_RIGHT: + case Attach::CENTER: { + center_y = screen_center_y + ty; + break; + } + } + + switch (attach_) { + case Attach::TOP_LEFT: + case Attach::CENTER_LEFT: + case Attach::BOTTOM_LEFT: { + center_x = tx; + break; + } + case Attach::TOP_CENTER: + case Attach::CENTER: + case Attach::BOTTOM_CENTER: { + center_x = screen_center_x + tx; + break; + } + case Attach::TOP_RIGHT: + case Attach::CENTER_RIGHT: + case Attach::BOTTOM_RIGHT: { + center_x = screen_width + tx; + break; + } + } + if (fill_screen_) { + width_ = screen_width; + height_ = screen_height; + center_x_ = width_ * 0.5f; + center_y_ = height_ * 0.5f; + } else { + center_x_ = center_x; + center_y_ = center_y; + width_ = width; + height_ = height; + } + dirty_ = false; + } + float fin_center_x = center_x_; + float fin_center_y = center_y_; + float fin_width = width_; + float fin_height = height_; + + // Tilt-translate doesn't happen in vr mode. + if (tilt_translate_ != 0.0f && !vr) { + Vector3f tilt = g_graphics->tilt(); + fin_center_x -= tilt.y * tilt_translate_; + fin_center_y += tilt.x * tilt_translate_; + + // If we're fullscreen and are tilting, crank our dimensions up + // slightly to account for tiltage. +#if BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + if (fill_screen_) { + float s = 1.0f - tilt_translate_ * 0.2f; + fin_width *= s; + fin_height *= s; + } +#endif // BA_OSTYPE_IOS_TVOS || BA_OSTYPE_ANDROID + } + + bool has_alpha_channel = has_alpha_channel_; + float alpha = opacity_ * alpha_; + if (alpha < 0) { + alpha = 0; + } + ModelData* model_opaque_used = nullptr; + if (model_opaque_.exists()) model_opaque_used = model_opaque_->model_data(); + ModelData* model_transparent_used = nullptr; + if (model_transparent_.exists()) { + model_transparent_used = model_transparent_->model_data(); + } + + // If no meshes were provided, use default image models. + if (!model_opaque_.exists() && !model_transparent_.exists()) { + if (vr && fill_screen_) { +#if BA_VR_BUILD + model_opaque_used = + g_media->GetModel(SystemModelID::kImage1x1VRFullScreen); +#else + throw Exception(); +#endif // BA_VR_BUILD + } else { + SystemModelID m = fill_screen_ ? SystemModelID::kImage1x1FullScreen + : SystemModelID::kImage1x1; + if (has_alpha_channel) { + model_transparent_used = g_media->GetModel(m); + } else { + model_opaque_used = g_media->GetModel(m); + } + } + } + + // Draw opaque portion either opaque or transparent depending on our + // global opacity. + if (model_opaque_used) { + // Draw in opaque pass if possible. + SimpleComponent c(&pass); + bool draw_transparent = (alpha < 0.999f); + + // Stuff in the fixed vr overlay pass may inadvertently + // obscure the non-fixed overlay pass, so lets just always draw + // transparent to avoid that. + c.SetTransparent(draw_transparent); + c.SetPremultiplied(premultiplied_); + c.SetTexture(texture_); + c.SetColor(red_, green_, blue_, alpha); + if (tint_texture_.exists()) { + c.SetColorizeTexture(tint_texture_); + c.SetColorizeColor(tint_red_, tint_green_, tint_blue_); + c.SetColorizeColor2(tint2_red_, tint2_green_, tint2_blue_); + } + c.SetMaskTexture(mask_texture_); + c.PushTransform(); + c.Translate(fin_center_x, fin_center_y, + vr ? vr_depth_ : g_graphics->overlay_node_z_depth()); + if (rotate_ != 0.0f) c.Rotate(rotate_, 0, 0, 1); + c.Scale(fin_width, fin_height, fin_width); + c.DrawModel(model_opaque_used); + c.PopTransform(); + c.Submit(); + } + // Transparent portion. + if (model_transparent_used) { + SimpleComponent c(&pass); + c.SetTransparent(true); + c.SetPremultiplied(premultiplied_); + c.SetTexture(texture_); + c.SetColor(red_, green_, blue_, alpha); + if (tint_texture_.exists()) { + c.SetColorizeTexture(tint_texture_); + c.SetColorizeColor(tint_red_, tint_green_, tint_blue_); + c.SetColorizeColor2(tint2_red_, tint2_green_, tint2_blue_); + } + c.SetMaskTexture(mask_texture_); + c.PushTransform(); + c.Translate(fin_center_x, fin_center_y, + vr ? vr_depth_ : g_graphics->overlay_node_z_depth()); + if (rotate_ != 0.0f) c.Rotate(rotate_, 0, 0, 1); + c.Scale(fin_width, fin_height, fin_width); + c.DrawModel(model_transparent_used); + c.PopTransform(); + c.Submit(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/image_node.h b/src/ballistica/scene/node/image_node.h new file mode 100644 index 00000000..813f9b5b --- /dev/null +++ b/src/ballistica/scene/node/image_node.h @@ -0,0 +1,124 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_IMAGE_NODE_H_ +#define BALLISTICA_SCENE_NODE_IMAGE_NODE_H_ + +#include +#include + +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// Node used to draw 2d image overlays on-screen. +class ImageNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit ImageNode(Scene* scene); + ~ImageNode() override; + void Draw(FrameDef* frame_def) override; + auto scale() const -> std::vector { return scale_; } + void SetScale(const std::vector& scale); + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& val); + auto opacity() const -> float { return opacity_; } + void set_opacity(float val) { opacity_ = val; } + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& val); + auto tint_color() const -> std::vector { return tint_color_; } + void SetTintColor(const std::vector& val); + auto tint2_color() const -> std::vector { return tint2_color_; } + void SetTint2Color(const std::vector& val); + auto fill_screen() const -> bool { return fill_screen_; } + void SetFillScreen(bool val); + auto has_alpha_channel() const -> bool { return has_alpha_channel_; } + void set_has_alpha_channel(bool val) { has_alpha_channel_ = val; } + auto absolute_scale() const -> bool { return absolute_scale_; } + void set_absolute_scale(bool val) { + absolute_scale_ = val; + dirty_ = true; + } + auto tilt_translate() const -> float { return tilt_translate_; } + void set_tilt_translate(float val) { tilt_translate_ = val; } + auto rotate() const -> float { return rotate_; } + void set_rotate(float val) { rotate_ = val; } + auto premultiplied() const -> bool { return premultiplied_; } + void set_premultiplied(bool val) { premultiplied_ = val; } + auto GetAttach() const -> std::string; + void SetAttach(const std::string& val); + auto texture() const -> Texture* { return texture_.get(); } + void set_texture(Texture* t) { texture_ = t; } + auto tint_texture() const -> Texture* { return tint_texture_.get(); } + void set_tint_texture(Texture* t) { tint_texture_ = t; } + auto mask_texture() const -> Texture* { return mask_texture_.get(); } + void set_mask_texture(Texture* t) { mask_texture_ = t; } + auto model_opaque() const -> Model* { return model_opaque_.get(); } + void set_model_opaque(Model* m) { model_opaque_ = m; } + auto model_transparent() const -> Model* { return model_transparent_.get(); } + void set_model_transparent(Model* m) { + model_transparent_ = m; + dirty_ = true; + } + auto vr_depth() const -> float { return vr_depth_; } + void set_vr_depth(float val) { vr_depth_ = val; } + void OnScreenSizeChange() override; + auto host_only() const -> bool { return host_only_; } + void set_host_only(bool val) { host_only_ = val; } + auto front() const -> bool { return front_; } + void set_front(bool val) { front_ = val; } + + private: + enum class Attach { + CENTER, + TOP_LEFT, + TOP_CENTER, + TOP_RIGHT, + CENTER_RIGHT, + BOTTOM_RIGHT, + BOTTOM_CENTER, + BOTTOM_LEFT, + CENTER_LEFT + }; + bool host_only_{}; + bool front_{}; + float vr_depth_{}; + std::vector scale_{1.0f, 1.0f}; + std::vector position_{0.0f, 0.0f}; + std::vector color_{1.0f, 1.0f, 1.0f}; + std::vector tint_color_{1.0f, 1.0f, 1.0f}; + std::vector tint2_color_{1.0f, 1.0f, 1.0f}; + Object::Ref texture_; + Object::Ref tint_texture_; + Object::Ref mask_texture_; + Object::Ref model_opaque_; + Object::Ref model_transparent_; + bool fill_screen_{}; + bool has_alpha_channel_{true}; + bool dirty_{true}; + float opacity_{1.0f}; + Attach attach_{Attach::CENTER}; + bool absolute_scale_{true}; + float center_x_{}; + float center_y_{}; + float width_{}; + float height_{}; + float tilt_translate_{}; + float rotate_{}; + bool premultiplied_{}; + float red_{1.0f}; + float green_{1.0f}; + float blue_{1.0f}; + float alpha_{1.0f}; + float tint_red_{1.0f}; + float tint_green_{1.0f}; + float tint_blue_{1.0f}; + float tint2_red_{1.0f}; + float tint2_green_{1.0f}; + float tint2_blue_{1.0f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_IMAGE_NODE_H_ diff --git a/src/ballistica/scene/node/light_node.cc b/src/ballistica/scene/node/light_node.cc new file mode 100644 index 00000000..cb9e6d86 --- /dev/null +++ b/src/ballistica/scene/node/light_node.cc @@ -0,0 +1,153 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/light_node.h" + +#include + +#include "ballistica/dynamics/bg/bg_dynamics_volume_light.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class LightNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS LightNode + BA_NODE_CREATE_CALL(CreateLight); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ATTR(intensity, intensity, SetIntensity); + BA_FLOAT_ATTR(volume_intensity_scale, volume_intensity_scale, + SetVolumeIntensityScale); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_FLOAT_ATTR(radius, radius, SetRadius); + BA_BOOL_ATTR(lights_volumes, lights_volumes, set_lights_volumes); + BA_BOOL_ATTR(height_attenuated, height_attenuated, set_height_attenuated); +#undef BA_NODE_TYPE_CLASS + LightNodeType() + : NodeType("light", CreateLight), + position(this), + intensity(this), + volume_intensity_scale(this), + color(this), + radius(this), + lights_volumes(this), + height_attenuated(this) {} +}; +static NodeType* node_type{}; + +auto LightNode::InitType() -> NodeType* { + node_type = new LightNodeType(); + return node_type; +} + +LightNode::LightNode(Scene* scene) : Node(scene, node_type) {} + +auto LightNode::GetVolumeLightIntensity() -> float { + return intensity_ * volume_intensity_scale_ * 0.02f; +} + +void LightNode::Step() { +#if !BA_HEADLESS_BUILD + // create or destroy our light-volume as needed + // (minimize redundant create/destroy/sets this way) + if (lights_volumes_ && !volume_light_.exists()) { + volume_light_ = Object::New(); + float i = GetVolumeLightIntensity(); + volume_light_->SetColor(color_[0] * i, color_[1] * i, color_[2] * i); + volume_light_->SetPosition( + Vector3f(position_[0], position_[1], position_[2])); + } else if (!lights_volumes_ && volume_light_.exists()) { + volume_light_.Clear(); + } +#endif // BA_HEADLESS_BUILD +} + +void LightNode::SetRadius(float val) { + radius_ = std::max(0.0f, val); +#if !BA_HEADLESS_BUILD + if (volume_light_.exists()) { + volume_light_->SetRadius(radius_); + } +#endif // BA_HEADLESS_BUILD +} + +void LightNode::SetColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("expected float array of size 3 for color"); + } + color_ = vals; +#if !BA_HEADLESS_BUILD + if (volume_light_.exists()) { + float i = GetVolumeLightIntensity(); + volume_light_->SetColor(color_[0] * i, color_[1] * i, color_[2] * i); + } +#endif // BA_HEADLESS_BUILD +} + +void LightNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("expected float array of size 3 for position"); + } + position_ = vals; + +#if !BA_HEADLESS_BUILD + shadow_.SetPosition(Vector3f(position_[0], position_[1], position_[2])); + if (volume_light_.exists()) { + volume_light_->SetPosition( + Vector3f(position_[0], position_[1], position_[2])); + } +#endif // BA_HEADLESS_BUILD +} + +void LightNode::SetIntensity(float val) { + intensity_ = std::max(0.0f, val); +#if !BA_HEADLESS_BUILD + if (volume_light_.exists()) { + float i = GetVolumeLightIntensity(); + volume_light_->SetColor(color_[0] * i, color_[1] * i, color_[2] * i); + } +#endif // BA_HEADLESS_BUILD +} + +void LightNode::SetVolumeIntensityScale(float val) { + volume_intensity_scale_ = std::max(0.0f, val); + +#if !BA_HEADLESS_BUILD + if (volume_light_.exists()) { + float i = GetVolumeLightIntensity(); + volume_light_->SetColor(color_[0] * i, color_[1] * i, color_[2] * i); + } +#endif // BA_HEADLESS_BUILD +} + +void LightNode::Draw(FrameDef* frame_def) { +#if !BA_HEADLESS_BUILD + // if we haven't gotten our initial attributes, dont draw + assert(position_.size() == 3); + // if (position_.size() == 0) return; + + float s_density, s_scale; + + if (height_attenuated_) { + shadow_.GetValues(&s_scale, &s_density); + } else { + s_density = 1.0f; + s_scale = 1.0f; + } + + float brightness = s_density * 0.65f * intensity_; + + // draw our light on both terrain and objects + g_graphics->DrawBlotchSoft(Vector3f(&position_[0]), 20.0f * radius_ * s_scale, + color_[0] * brightness, color_[1] * brightness, + color_[2] * brightness, 0.0f); + + g_graphics->DrawBlotchSoftObj(Vector3f(&position_[0]), + 20.0f * radius_ * s_scale, + color_[0] * brightness, color_[1] * brightness, + color_[2] * brightness, 0.0f); +#endif // BA_HEADLESS_BUILD +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/light_node.h b/src/ballistica/scene/node/light_node.h new file mode 100644 index 00000000..93a5a592 --- /dev/null +++ b/src/ballistica/scene/node/light_node.h @@ -0,0 +1,54 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_LIGHT_NODE_H_ +#define BALLISTICA_SCENE_NODE_LIGHT_NODE_H_ + +#include + +#include "ballistica/dynamics/bg/bg_dynamics_shadow.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// A light source +class LightNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit LightNode(Scene* scene); + void Draw(FrameDef* frame_def) override; + void Step() override; + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& val); + auto intensity() const -> float { return intensity_; } + void SetIntensity(float val); + auto volume_intensity_scale() const -> float { + return volume_intensity_scale_; + } + void SetVolumeIntensityScale(float val); + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& val); + auto radius() const -> float { return radius_; } + void SetRadius(float val); + auto lights_volumes() const -> bool { return lights_volumes_; } + void set_lights_volumes(bool val) { lights_volumes_ = val; } + auto height_attenuated() const -> bool { return height_attenuated_; } + void set_height_attenuated(bool val) { height_attenuated_ = val; } + + private: + auto GetVolumeLightIntensity() -> float; +#if !BA_HEADLESS_BUILD + BGDynamicsShadow shadow_{0.2f}; + Object::Ref volume_light_; +#endif + std::vector position_ = {0.0f, 0.0f, 0.0f}; + std::vector color_ = {1.0f, 1.0f, 1.0f}; + float intensity_ = 1.0f; + float volume_intensity_scale_ = 1.0f; + float radius_ = 0.5f; + bool height_attenuated_ = true; + bool lights_volumes_ = true; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_LIGHT_NODE_H_ diff --git a/src/ballistica/scene/node/locator_node.cc b/src/ballistica/scene/node/locator_node.cc new file mode 100644 index 00000000..88fbb508 --- /dev/null +++ b/src/ballistica/scene/node/locator_node.cc @@ -0,0 +1,179 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/locator_node.h" + +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class LocatorNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS LocatorNode + BA_NODE_CREATE_CALL(CreateLocator); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_BOOL_ATTR(visibility, visibility, set_visibility); + BA_FLOAT_ARRAY_ATTR(size, size, SetSize); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_FLOAT_ATTR(opacity, opacity, set_opacity); + BA_BOOL_ATTR(draw_beauty, draw_beauty, set_draw_beauty); + BA_BOOL_ATTR(drawShadow, getDrawShadow, setDrawShadow); + BA_STRING_ATTR(shape, getShape, SetShape); + BA_BOOL_ATTR(additive, getAdditive, setAdditive); +#undef BA_NODE_TYPE_CLASS + LocatorNodeType() + : NodeType("locator", CreateLocator), + position(this), + visibility(this), + size(this), + color(this), + opacity(this), + draw_beauty(this), + drawShadow(this), + shape(this), + additive(this) {} +}; +static NodeType* node_type{}; + +auto LocatorNode::InitType() -> NodeType* { + node_type = new LocatorNodeType(); + return node_type; +} + +LocatorNode::LocatorNode(Scene* scene) : Node(scene, node_type) {} + +auto LocatorNode::getShape() const -> std::string { + switch (shape_) { + case Shape::kBox: + return "box"; + case Shape::kCircle: + return "circle"; + case Shape::kCircleOutline: + return "circleOutline"; + case Shape::kLocator: + return "locator"; + default: + throw Exception("Invalid shape val: " + + std::to_string(static_cast(shape_))); + } +} + +void LocatorNode::SetShape(const std::string& val) { + if (val == "box") { + shape_ = Shape::kBox; + } else if (val == "circle") { + shape_ = Shape::kCircle; + } else if (val == "circleOutline") { + shape_ = Shape::kCircleOutline; + } else if (val == "locator") { + shape_ = Shape::kLocator; + } else { + throw Exception("invalid locator shape: " + val); + } +} + +void LocatorNode::SetColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for color"); + } + color_ = vals; +} + +void LocatorNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of size 3 for position"); + position_ = vals; +} + +void LocatorNode::SetSize(const std::vector& vals) { + if (vals.size() != 1 && vals.size() != 3) + throw Exception("Expected float array of size 1 or 3 for size"); + size_ = vals; + if (size_.size() == 1) { + size_.push_back(size_[0]); + size_.push_back(size_[0]); + } +} + +void LocatorNode::Draw(FrameDef* frame_def) { + SystemModelID model; + if (shape_ == Shape::kBox) { + model = SystemModelID::kLocatorBox; + } else if (shape_ == Shape::kCircle) { + model = SystemModelID::kLocatorCircle; + } else if (shape_ == Shape::kCircleOutline) { + model = SystemModelID::kLocatorCircleOutline; + } else { + model = SystemModelID::kLocator; + } + + SystemTextureID texture; + if (shape_ == Shape::kCircle) { + texture = + additive_ ? SystemTextureID::kCircleNoAlpha : SystemTextureID::kCircle; + } else if (shape_ == Shape::kCircleOutline) { + texture = additive_ ? SystemTextureID::kCircleOutlineNoAlpha + : SystemTextureID::kCircleOutline; + } else { + texture = SystemTextureID::kRGBStripes; + } + + bool transparent = false; + if (shape_ == Shape::kCircle || shape_ == Shape::kCircleOutline) + transparent = true; + + // beauty + if (draw_beauty_) { + SimpleComponent c(frame_def->beauty_pass()); + if (transparent) c.SetTransparent(true); + c.SetColor(color_[0], color_[1], color_[2], opacity_); + c.SetTexture(g_media->GetTexture(texture)); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(size_[0], size_[1], size_[2]); + c.DrawModel(g_media->GetModel(model)); + c.PopTransform(); + c.Submit(); + } + + if (draw_shadow_) { + // colored shadow for circle + if (shape_ == Shape::kCircle || shape_ == Shape::kCircleOutline) { + SimpleComponent c(frame_def->light_shadow_pass()); + if (transparent) { + c.SetTransparent(true); + if (additive_) { + c.SetPremultiplied(true); + } + } + if (additive_) { + c.SetColor(color_[0] * opacity_, color_[1] * opacity_, + color_[2] * opacity_, 0.0f); + } else { + c.SetColor(color_[0], color_[1], color_[2], opacity_); + } + c.SetTexture(g_media->GetTexture(texture)); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(size_[0], size_[1], size_[2]); + c.DrawModel(g_media->GetModel(model)); + c.PopTransform(); + c.Submit(); + } else { + // simple black shadow for locator/box + SimpleComponent c(frame_def->light_shadow_pass()); + c.SetTransparent(true); + c.SetColor(0.4f, 0.4f, 0.4f, 0.7f); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(size_[0], size_[1], size_[2]); + c.DrawModel(g_media->GetModel(model)); + c.PopTransform(); + c.Submit(); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/locator_node.h b/src/ballistica/scene/node/locator_node.h new file mode 100644 index 00000000..0f8fcdde --- /dev/null +++ b/src/ballistica/scene/node/locator_node.h @@ -0,0 +1,63 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_LOCATOR_NODE_H_ +#define BALLISTICA_SCENE_NODE_LOCATOR_NODE_H_ + +#include +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class LocatorNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit LocatorNode(Scene* scene); + + void Draw(FrameDef* frame_def) override; + + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& vals); + + auto visibility() const -> bool { return visibility_; } + void set_visibility(bool val) { visibility_ = val; } + + auto size() const -> std::vector { return size_; } + void SetSize(const std::vector& vals); + + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& vals); + + auto opacity() const -> float { return opacity_; } + void set_opacity(float val) { opacity_ = val; } + + auto draw_beauty() const -> bool { return draw_beauty_; } + void set_draw_beauty(bool val) { draw_beauty_ = val; } + + auto getDrawShadow() const -> bool { return draw_shadow_; } + void setDrawShadow(bool val) { draw_shadow_ = val; } + + auto getShape() const -> std::string; + void SetShape(const std::string& val); + + auto getAdditive() const -> bool { return additive_; } + void setAdditive(bool val) { additive_ = val; } + + private: + enum class Shape { kLocator, kBox, kCircle, kCircleOutline }; + + Shape shape_ = Shape::kLocator; + bool additive_ = false; + std::vector position_ = {0.0f, 0.0f, 0.0f}; + std::vector size_ = {1.0f, 1.0f, 1.0f}; + std::vector color_ = {1.0f, 1.0f, 1.0f}; + bool visibility_ = true; + float opacity_ = 1.0f; + bool draw_beauty_ = true; + bool draw_shadow_ = true; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_LOCATOR_NODE_H_ diff --git a/src/ballistica/scene/node/math_node.cc b/src/ballistica/scene/node/math_node.cc new file mode 100644 index 00000000..016eb702 --- /dev/null +++ b/src/ballistica/scene/node/math_node.cc @@ -0,0 +1,116 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/math_node.h" + +#include +#include + +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class MathNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS MathNode + BA_NODE_CREATE_CALL(CreateMath); + BA_FLOAT_ARRAY_ATTR_READONLY(output, GetOutput); + BA_FLOAT_ARRAY_ATTR(input1, input_1, set_input_1); + BA_FLOAT_ARRAY_ATTR(input2, input_2, set_input_2); + BA_STRING_ATTR(operation, GetOperation, SetOperation); +#undef BA_NODE_TYPE_CLASS + + MathNodeType() + : NodeType("math", CreateMath), + output(this), + input1(this), + input2(this), + operation(this) {} +}; + +static NodeType* node_type{}; + +auto MathNode::InitType() -> NodeType* { + node_type = new MathNodeType(); + return node_type; +} + +MathNode::MathNode(Scene* scene) : Node(scene, node_type) {} + +auto MathNode::GetOperation() const -> std::string { + switch (operation_) { + case Operation::kAdd: + return "add"; + case Operation::kSubtract: + return "subtract"; + case Operation::kMultiply: + return "multiply"; + case Operation::kDivide: + return "divide"; + case Operation::kSin: + return "sin"; + default: + throw Exception("invalid operation: " + + std::to_string(static_cast(operation_))); + } +} + +void MathNode::SetOperation(const std::string& val) { + if (val == "add") { + operation_ = Operation::kAdd; + } else if (val == "subtract") { + operation_ = Operation::kSubtract; + } else if (val == "multiply") { + operation_ = Operation::kMultiply; + } else if (val == "divide") { + operation_ = Operation::kDivide; + } else if (val == "sin") { + operation_ = Operation::kSin; + } else { + throw Exception("Invalid math node op '" + val + "'"); + } +} + +auto MathNode::GetOutput() -> std::vector { + size_t val_count = std::min(input_1_.size(), input_2_.size()); + std::vector outputs(val_count); + switch (operation_) { + case Operation::kAdd: { + for (size_t i = 0; i < val_count; i++) { + outputs[i] = (input_1_[i] + input_2_[i]); + } + break; + } + case Operation::kSubtract: { + for (size_t i = 0; i < val_count; i++) { + outputs[i] = (input_1_[i] - input_2_[i]); + } + break; + } + case Operation::kMultiply: { + for (size_t i = 0; i < val_count; i++) { + outputs[i] = (input_1_[i] * input_2_[i]); + } + break; + } + case Operation::kDivide: { + for (size_t i = 0; i < val_count; i++) { + outputs[i] = (input_1_[i] / input_2_[i]); + } + break; + } + case Operation::kSin: { + for (size_t i = 0; i < val_count; i++) { + outputs[i] = (sinf(input_1_[i])); + } + break; + } + default: + BA_LOG_ONCE("Error: invalid math op in getOutput(): " + + std::to_string(static_cast(operation_))); + break; + } + return outputs; +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/math_node.h b/src/ballistica/scene/node/math_node.h new file mode 100644 index 00000000..c9f7b5ca --- /dev/null +++ b/src/ballistica/scene/node/math_node.h @@ -0,0 +1,36 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_MATH_NODE_H_ +#define BALLISTICA_SCENE_NODE_MATH_NODE_H_ + +#include +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// An node used to create simple mathematical relationships via +// attribute connections +class MathNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit MathNode(Scene* scene); + auto GetOutput() -> std::vector; + auto input_1() const -> const std::vector& { return input_1_; } + void set_input_1(const std::vector& vals) { input_1_ = vals; } + auto input_2() const -> std::vector { return input_2_; } + void set_input_2(const std::vector& vals) { input_2_ = vals; } + auto GetOperation() const -> std::string; + void SetOperation(const std::string& val); + + private: + enum class Operation { kAdd, kSubtract, kMultiply, kDivide, kSin }; + std::vector input_1_; + std::vector input_2_; + Operation operation_ = Operation::kAdd; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_MATH_NODE_H_ diff --git a/src/ballistica/scene/node/node.cc b/src/ballistica/scene/node/node.cc new file mode 100644 index 00000000..d346544e --- /dev/null +++ b/src/ballistica/scene/node/node.cc @@ -0,0 +1,425 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/node.h" + +#include "ballistica/dynamics/part.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/python/class/python_class_node.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_attribute_connection.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +NodeType::~NodeType() { + Log("ERROR: SHOULD NOT BE DESTRUCTING A TYPE type=(" + name_ + ")"); +} + +Node::Node(Scene* scene_in, NodeType* node_type) + : node_type_(node_type), scene_(scene_in) {} +void Node::AddToScene(Scene* scene) { + // we should have already set our scene ptr in our constructor; + // now we add ourself to its lists.. + // (can't create strong refs in constructors) + assert(scene_ == scene); + assert(id_ == 0); + id_ = scene->next_node_id_++; + our_iterator = + scene->nodes_.insert(scene->nodes_.end(), Object::Ref(this)); + if (GameStream* os = scene->GetGameStream()) { + os->AddNode(this); + } +} + +Node::~Node() { + // Kill any incoming/outgoing attr connections. + for (auto& i : attribute_connections_incoming_) { + NodeAttributeConnection* a = i.second.get(); + assert(a && a->src_node.exists()); + + // Remove from src node's outgoing list. + a->src_node->attribute_connections_.erase(a->src_iterator); + } + + // Kill all refs on our side; this should kill the connections. + attribute_connections_incoming_.clear(); + for (auto& attribute_connection : attribute_connections_) { + NodeAttributeConnection* a = attribute_connection.get(); + assert(a && a->dst_node.exists()); + + // Remove from dst node's incoming list. + auto j = + a->dst_node->attribute_connections_incoming_.find(a->dst_attr_index); + assert(j != a->dst_node->attribute_connections_incoming_.end()); + a->dst_node->attribute_connections_incoming_.erase(j); + } + + // Kill all refs on our side; should kill the connections. + attribute_connections_.clear(); + + // NOTE: We no longer run death-actions or kill dependent-nodes here in our + // destructor; we allow the scene to do that to keep things cleaner. + + // Release our ref to ourself if we have one. + if (py_ref_) { + Py_DECREF(py_ref_); + } + + // If we were going to an output stream, inform them of our demise. + assert(scene()); + if (GameStream* output_stream = scene()->GetGameStream()) { + output_stream->RemoveNode(this); + } +} + +auto Node::GetResyncDataSize() -> int { return 0; } +auto Node::GetResyncData() -> std::vector { + return std::vector(); +} + +void Node::ApplyResyncData(const std::vector& data) {} + +void Node::Draw(FrameDef* frame_def) {} +void Node::OnCreate() {} + +auto Node::GetObjectDescription() const -> std::string { + return "name() : label()) + "\">"; +} + +auto Node::HasAttribute(const std::string& name) const -> bool { + return type()->HasAttribute(name); +} + +auto Node::GetAttribute(const std::string& name) -> NodeAttribute { + assert(type()); + return {this, type()->GetAttribute(name)}; +} + +auto Node::GetAttribute(int index) -> NodeAttribute { + assert(type()); + return {this, type()->GetAttribute(index)}; +} + +void Node::ConnectAttribute(NodeAttributeUnbound* src_attr, Node* dst_node, + NodeAttributeUnbound* dst_attr) { + // This is a no-op if the scene is shutting down. + if (scene() == nullptr || scene()->shutting_down()) { + return; + } + + assert(dst_node); + assert(src_attr && dst_attr); + assert(src_attr->node_type() == type()); + assert(dst_node->type() == dst_attr->node_type()); + assert(!scene()->in_step()); + + bool allow = false; + + // Currently limiting to certain types; + // Will wait and see on other types. + // A texture/etc attr might not behave well if updated with the same + // value every step.. hmmm. + { + switch (src_attr->type()) { + // Allow bools, ints, and floats to connect to each other + case NodeAttributeType::kBool: + case NodeAttributeType::kInt: + case NodeAttributeType::kFloat: + switch (dst_attr->type()) { + case NodeAttributeType::kBool: + case NodeAttributeType::kInt: + case NodeAttributeType::kFloat: + allow = true; + break; + default: + break; + } + break; + case NodeAttributeType::kString: + // Allow strings to connect to other strings (new in protocol 31). + if (dst_attr->type() == NodeAttributeType::kString) { + allow = true; + } + break; + case NodeAttributeType::kIntArray: + case NodeAttributeType::kFloatArray: + case NodeAttributeType::kTexture: + // Allow these types to connect to other attrs of the same type. + if (src_attr->type() == dst_attr->type()) allow = true; + break; + default: + break; + } + } + if (!allow) { + throw Exception("Attribute connections from " + src_attr->GetTypeName() + + " to " + dst_attr->GetTypeName() + + " attrs are not allowed."); + } + + // Ok lets do this. + + // Disconnect any existing connection to the dst attr. + dst_attr->DisconnectIncoming(dst_node); + + auto a(Object::New()); + + // Store refs to the connection with both the source and dst nodes. + a->src_iterator = + attribute_connections_.insert(attribute_connections_.end(), a); + dst_node->attribute_connections_incoming_[dst_attr->index()] = a; + a->src_node = this; + a->src_attr_index = src_attr->index(); + a->dst_node = dst_node; + a->dst_attr_index = dst_attr->index(); + a->Update(); +} + +void Node::UpdateConnections() { + for (auto& attribute_connection : attribute_connections_) { + // Connections should go away when either node dies; make sure that's + // working. + assert(attribute_connection->src_node.exists() + && attribute_connection->dst_node.exists()); + attribute_connection->Update(); + } +} + +void Node::AddNodeDeathAction(PyObject* call_obj) { + death_actions_.push_back(Object::New(call_obj)); +} + +void Node::AddDependentNode(Node* node) { + assert(node); + if (node->scene() != scene()) { + throw Exception("Nodes belong to different Scenes"); + } + + // While we're here lets prune any dead nodes from our list. + // (so if we add/destroy dependents repeatedly we don't build up a giant + // vector of dead ones) + if (!dependent_nodes_.empty()) { + std::vector > live_nodes; + for (auto& dependent_node : dependent_nodes_) { + if (dependent_node.exists()) live_nodes.push_back(dependent_node); + } + dependent_nodes_.swap(live_nodes); + } + dependent_nodes_.emplace_back(node); +} + +void Node::SetDelegate(PyObject* delegate_obj) { + if (delegate_obj != nullptr && delegate_obj != Py_None) { + delegate_.Steal(PyWeakref_NewRef(delegate_obj, nullptr)); + } else { + delegate_.Release(); + } +} + +auto Node::GetPyRef(bool new_ref) -> PyObject* { + assert(InGameThread()); + if (py_ref_ == nullptr) { + py_ref_ = PythonClassNode::Create(this); + } + if (new_ref) { + Py_INCREF(py_ref_); + } + return py_ref_; +} + +auto Node::GetDelegate() -> PyObject* { + PyObject* ref = delegate_.get(); + if (!ref) { + return nullptr; + } + return PyWeakref_GetObject(ref); +} + +void Node::DispatchNodeMessage(const char* buffer) { + assert(this); + assert(buffer); + if (scene_->shutting_down()) { + return; + } + + // If noone else has handled it, pass it to our low-level handler. + HandleMessage(buffer); +} + +void Node::DispatchOutOfBoundsMessage() { + PythonRef instance; + { + Python::ScopedCallLabel label("OutOfBoundsMessage instantiation"); + instance = g_python->obj(Python::ObjID::kOutOfBoundsMessageClass).Call(); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node OutOfBoundsMessage dispatch"); + } else { + Log("Error creating OutOfBoundsMessage"); + } +} + +void Node::DispatchPickUpMessage(Node* node) { + assert(node); + PythonRef args(Py_BuildValue("(O)", node->BorrowPyRef()), PythonRef::kSteal); + PythonRef instance; + { + Python::ScopedCallLabel label("PickUpMessage instantiation"); + instance = g_python->obj(Python::ObjID::kPickUpMessageClass).Call(args); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node PickUpMessage dispatch"); + } else { + Log("Error creating PickUpMessage"); + } +} + +void Node::DispatchDropMessage() { + PythonRef instance; + { + Python::ScopedCallLabel label("DropMessage instantiation"); + instance = g_python->obj(Python::ObjID::kDropMessageClass).Call(); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node DropMessage dispatch"); + } else { + Log("Error creating DropMessage"); + } +} + +void Node::DispatchPickedUpMessage(Node* by_node) { + assert(by_node); + PythonRef args(Py_BuildValue("(O)", by_node->BorrowPyRef()), + PythonRef::kSteal); + PythonRef instance; + { + Python::ScopedCallLabel label("PickedUpMessage instantiation"); + instance = g_python->obj(Python::ObjID::kPickedUpMessageClass).Call(args); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node PickedUpMessage dispatch"); + } else { + Log("Error creating PickedUpMessage"); + } +} + +void Node::DispatchDroppedMessage(Node* by_node) { + assert(by_node); + PythonRef args(Py_BuildValue("(O)", by_node->BorrowPyRef()), + PythonRef::kSteal); + PythonRef instance; + { + Python::ScopedCallLabel label("DroppedMessage instantiation"); + instance = g_python->obj(Python::ObjID::kDroppedMessageClass).Call(args); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node DroppedMessage dispatch"); + } else { + Log("Error creating DroppedMessage"); + } +} + +void Node::DispatchShouldShatterMessage() { + PythonRef instance; + { + Python::ScopedCallLabel label("ShouldShatterMessage instantiation"); + instance = g_python->obj(Python::ObjID::kShouldShatterMessageClass).Call(); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node ShouldShatterMessage dispatch"); + } else { + Log("Error creating ShouldShatterMessage"); + } +} + +void Node::DispatchImpactDamageMessage(float intensity) { + PythonRef args(Py_BuildValue("(f)", intensity), PythonRef::kSteal); + PythonRef instance; + { + Python::ScopedCallLabel label("ImpactDamageMessage instantiation"); + instance = + g_python->obj(Python::ObjID::kImpactDamageMessageClass).Call(args); + } + if (instance.exists()) { + DispatchUserMessage(instance.get(), "Node ImpactDamageMessage dispatch"); + } else { + Log("Error creating ImpactDamageMessage"); + } +} + +void Node::DispatchUserMessage(PyObject* obj, const char* label) { + assert(InGameThread()); + if (scene_->shutting_down()) { + return; + } + + ScopedSetContext cp(context()); + PyObject* delegate = GetDelegate(); + if (delegate && delegate != Py_None) { + try { + PyObject* handlemessage_obj = + PyObject_GetAttrString(delegate, "handlemessage"); + if (!handlemessage_obj) { + PyErr_Clear(); + throw Exception("No 'handlemessage' found on delegate object for '" + + type()->name() + "' node (" + + Python::ObjToString(delegate) + ")"); + } + PythonRef c(handlemessage_obj, PythonRef::kSteal); + { + Python::ScopedCallLabel lscope(label); + c.Call(PythonRef(Py_BuildValue("(O)", obj), PythonRef::kSteal)); + } + } catch (const std::exception& e) { + Log(std::string("Error in handlemessage() with message ") + + PythonRef(obj, PythonRef::kAcquire).Str() + ": '" + e.what() + "'"); + } + } +} + +void Node::HandleMessage(const char* data_in) {} + +void Node::UpdatePartBirthTimes() { + for (auto&& i : parts_) { + i->UpdateBirthTime(); + } +} + +void Node::CheckBodies() { + for (auto&& i : parts_) { + i->CheckBodies(); + } +} + +auto NodeType::GetAttributeNames() const -> std::vector { + std::vector names; + for (auto&& i : attributes_by_name_) { + names.push_back(i.second->name()); + } + return names; +} + +void Node::ListAttributes(std::list* attrs) { + attrs->clear(); + + // New attrs. + std::vector type_attrs = type()->GetAttributeNames(); + for (auto&& i : type_attrs) { + attrs->push_back(i); + } +} + +void Node::GetRigidBodyPickupLocations(int id, float* pos_obj, float* pos_char, + float* hand_offset_1, + float* hand_offset_2) { + pos_obj[0] = pos_obj[1] = pos_obj[2] = 0; + pos_char[0] = pos_char[1] = pos_char[2] = 0; + hand_offset_1[0] = hand_offset_1[1] = hand_offset_1[2] = 0; + hand_offset_2[0] = hand_offset_2[1] = hand_offset_2[2] = 0; +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/node.h b/src/ballistica/scene/node/node.h new file mode 100644 index 00000000..a3586d20 --- /dev/null +++ b/src/ballistica/scene/node/node.h @@ -0,0 +1,226 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_NODE_H_ +#define BALLISTICA_SCENE_NODE_NODE_H_ + +#include +#include +#include +#include + +#include "ballistica/ballistica.h" +#include "ballistica/core/context.h" +#include "ballistica/core/object.h" +#include "ballistica/python/python_ref.h" + +namespace ballistica { + +// Define a static creation call for this node type +#define BA_NODE_CREATE_CALL(FUNC) \ + static auto FUNC(Scene* sg)->Node* { \ + return Object::NewDeferred(sg); \ + } + +typedef std::list > NodeList; + +// Base node class. +class Node : public Object { + public: + Node(Scene* scene, NodeType* node_type); + ~Node() override; + auto id() const -> int64_t { + return id_; + } // Return the node's id in its scene. + virtual void Step() {} // Called for each step of the sim. + virtual void OnScreenSizeChange() {} // Called when screen size changes. + virtual void OnLanguageChange() {} // Called when the language changes. + virtual void OnGraphicsQualityChanged(GraphicsQuality q) {} + + // The node can rule out collisions between particular bodies using this. + virtual auto PreFilterCollision(RigidBody* b1, RigidBody* r2) -> bool { + return true; + } + + // Pull a node type out of a buffer. + static auto extract_node_message_type(const char** b) -> NodeMessageType { + auto t = static_cast(**b); + (*b) += 1; + return t; + } + + void ConnectAttribute(NodeAttributeUnbound* src_attr, Node* dst_node, + NodeAttributeUnbound* dst_attr); + + // Return an attribute by name. + auto GetAttribute(const std::string& name) -> NodeAttribute; + + // Return an attribute by index. + auto GetAttribute(int index) -> NodeAttribute; + + void SetDelegate(PyObject* delegate_obj); + + auto NewPyRef() -> PyObject* { return GetPyRef(true); } + auto BorrowPyRef() -> PyObject* { return GetPyRef(false); } + + // Return the delegate, or nullptr if it doesn't have one + // (or if the delegate has since died). + auto GetDelegate() -> PyObject*; + + void AddNodeDeathAction(PyObject* call_obj); + + // Add a node to auto-kill when this one dies. + void AddDependentNode(Node* node); + + // Update birth times for all the node's parts. + // This should be done when teleporting or otherwise spawning at + // a new location. + void UpdatePartBirthTimes(); + + // Retrieve an existing part from a node. + auto GetPart(unsigned int id) -> Part* { + assert(id < parts_.size()); + return parts_[id]; + } + + // Used by RigidBodies when adding themselves to the part. + auto AddPart(Part* part_in) -> int { + parts_.push_back(part_in); + return static_cast(parts_.size() - 1); + } + + // Used to send messages to a node + void DispatchNodeMessage(const char* buffer); + + // Used to send custom user messages to a node + // returns true if handled. + void DispatchUserMessage(PyObject* obj, const char* label); + void DispatchOutOfBoundsMessage(); + void DispatchPickedUpMessage(Node* n); + void DispatchDroppedMessage(Node* n); + void DispatchPickUpMessage(Node* n); + void DispatchDropMessage(); + void DispatchShouldShatterMessage(); + void DispatchImpactDamageMessage(float intensity); + + // Utility function to get a rigid body. + virtual auto GetRigidBody(int id) -> RigidBody* { return nullptr; } + + // Given a rigid body, return the relative position where it should be picked + // up from. + virtual void GetRigidBodyPickupLocations(int id, float* posObj, + float* pos_char, + float* hand_offset_1, + float* hand_offset_2); + + // Called for each Node when it should render itself. + virtual void Draw(FrameDef* frame_def); + + // Called for each node once construction is completed + // this can be a good time to create things from the initial attr set, etc + virtual void OnCreate(); + + auto scene() const -> Scene* { + assert(scene_); + return scene_; + } + + // Used to re-sync client versions of a node from the host version. + virtual auto GetResyncDataSize() -> int; + virtual auto GetResyncData() -> std::vector; + virtual void ApplyResyncData(const std::vector& data); + auto context() const -> const Context& { return context_; } + + // Node labels are purely for local debugging - they aren't unique or sent + // across the network or anything. + void set_label(const std::string& label) { label_ = label; } + auto label() const -> const std::string& { return label_; } + + void ListAttributes(std::list* attrs); + auto type() const -> NodeType* { + assert(node_type_); + return node_type_; + } + auto HasAttribute(const std::string& name) const -> bool; + auto has_py_ref() -> bool { return (py_ref_ != nullptr); } + void UpdateConnections(); + auto iterator() -> NodeList::iterator { return our_iterator; } + + void CheckBodies(); + +#if BA_DEBUG_BUILD +#define BA_DEBUG_CHECK_BODIES() CheckBodies() +#else +#define BA_DEBUG_CHECK_BODIES() ((void)0) +#endif + + auto GetObjectDescription() const -> std::string override; + + auto parts() const -> const std::vector& { return parts_; } + auto death_actions() const + -> const std::vector >& { + return death_actions_; + } + auto dependent_nodes() const -> const std::vector >& { + return dependent_nodes_; + } + auto attribute_connections() const + -> const std::list >& { + return attribute_connections_; + } + auto attribute_connections_incoming() const + -> const std::map >& { + return attribute_connections_incoming_; + } + + auto stream_id() const -> int64_t { return stream_id_; } + void set_stream_id(int64_t val) { + assert(stream_id_ == -1); + stream_id_ = val; + } + void clear_stream_id() { + assert(stream_id_ != -1); + stream_id_ = -1; + } + + // Return a reference to a python wrapper for this node, + // creating one if need be. + auto GetPyRef(bool new_ref = true) -> PyObject*; + + void AddToScene(Scene* scene); + + // Called for each message received by an Node. + virtual void HandleMessage(const char* buffer); + + private: + int64_t stream_id_{-1}; + NodeType* node_type_ = nullptr; + + PyObject* py_ref_ = nullptr; + + // FIXME - We can get by with *just* a pointer to our scene + // if we add a way to pull context from a scene. + Context context_; + Scene* scene_{}; + std::string label_; + std::vector > dependent_nodes_; + std::vector parts_; + int64_t id_{}; + NodeList::iterator our_iterator; + + // Put this stuff at the bottom so it gets killed first + PythonRef delegate_; + std::vector > death_actions_; + + // Outgoing attr connections in order created. + std::list > attribute_connections_; + + // Incoming attr connections by attr index. + std::map > + attribute_connections_incoming_; + + friend class NodeAttributeUnbound; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_NODE_H_ diff --git a/src/ballistica/scene/node/node_attribute.cc b/src/ballistica/scene/node/node_attribute.cc new file mode 100644 index 00000000..a8bdd109 --- /dev/null +++ b/src/ballistica/scene/node/node_attribute.cc @@ -0,0 +1,270 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/node_attribute.h" + +#include + +#include "ballistica/scene/node/node.h" +#include "ballistica/scene/node/node_attribute_connection.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +auto NodeAttributeUnbound::GetNodeAttributeTypeName(NodeAttributeType t) + -> std::string { + switch (t) { + case NodeAttributeType::kFloat: + return "float"; + case NodeAttributeType::kFloatArray: + return "float-array"; + case NodeAttributeType::kInt: + return "int"; + case NodeAttributeType::kIntArray: + return "int-array"; + case NodeAttributeType::kBool: + return "bool"; + case NodeAttributeType::kString: + return "string"; + case NodeAttributeType::kNode: + return "node"; + case NodeAttributeType::kNodeArray: + return "node-array"; + case NodeAttributeType::kPlayer: + return "player"; + case NodeAttributeType::kMaterialArray: + return "material-array"; + case NodeAttributeType::kTexture: + return "texture"; + case NodeAttributeType::kTextureArray: + return "texture-array"; + case NodeAttributeType::kSound: + return "sound"; + case NodeAttributeType::kSoundArray: + return "sound-array"; + case NodeAttributeType::kModel: + return "model"; + case NodeAttributeType::kModelArray: + return "model-array"; + case NodeAttributeType::kCollideModel: + return "collide-model"; + case NodeAttributeType::kCollideModelArray: + return "collide-model-array"; + default: + Log("Error: Unknown attr type name: " + + std::to_string(static_cast(t))); + return "unknown"; + } +} + +NodeAttributeUnbound::NodeAttributeUnbound(NodeType* node_type, + NodeAttributeType type, + std::string name, uint32_t flags) + : node_type_(node_type), + type_(type), + name_(std::move(name)), + flags_(flags) { + assert(node_type); + node_type->attributes_by_name_[name_] = this; + index_ = static_cast(node_type->attributes_by_index_.size()); + node_type->attributes_by_index_.push_back(this); +} + +void NodeAttributeUnbound::NotReadableError(Node* node) { + throw Exception("Attribute '" + name() + "' on " + node->type()->name() + + " node is not readable"); +} + +void NodeAttributeUnbound::NotWritableError(Node* node) { + throw Exception("Attribute '" + name() + "' on " + node->type()->name() + + " node is not writable"); +} + +void NodeAttributeUnbound::DisconnectIncoming(Node* node) { + assert(node); + auto i = node->attribute_connections_incoming().find(index()); + if (i != node->attribute_connections_incoming().end()) { + NodeAttributeConnection* a = i->second.get(); + +#if BA_DEBUG_BUILD + Object::WeakRef test_ref(a); +#endif + + assert(a && a->src_node.exists()); + + // Remove from src node's outgoing list. + a->src_node->attribute_connections_.erase(a->src_iterator); + + // Remove from our incoming list; this should kill the connection. + node->attribute_connections_incoming_.erase(i); + +#if BA_DEBUG_BUILD + if (test_ref.exists()) { + Log("Error: Attr connection still exists after ref releases!"); + } +#endif + } +} + +auto NodeAttributeUnbound::GetAsFloat(Node* node) -> float { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a float."); +} +void NodeAttributeUnbound::Set(Node* node, float value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a float."); +} +auto NodeAttributeUnbound::GetAsInt(Node* node) -> int64_t { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as an int."); +} +void NodeAttributeUnbound::Set(Node* node, int64_t value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as an int."); +} +auto NodeAttributeUnbound::GetAsBool(Node* node) -> bool { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a bool."); +} +void NodeAttributeUnbound::Set(Node* node, bool value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a bool."); +} +auto NodeAttributeUnbound::GetAsString(Node* node) -> std::string { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a string."); +} +void NodeAttributeUnbound::Set(Node* node, const std::string& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a string."); +} + +auto NodeAttributeUnbound::GetAsFloats(Node* node) -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a float array."); +} +void NodeAttributeUnbound::Set(Node* node, const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a float array."); +} +auto NodeAttributeUnbound::GetAsInts(Node* node) -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as an int array."); +} +void NodeAttributeUnbound::Set(Node* node, const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as an int array."); +} + +auto NodeAttributeUnbound::GetAsNode(Node* node) -> Node* { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a node."); +} +void NodeAttributeUnbound::Set(Node* node, Node* value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a node."); +} + +auto NodeAttributeUnbound::GetAsNodes(Node* node) -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a node array."); +} +void NodeAttributeUnbound::Set(Node* node, const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a node array."); +} + +auto NodeAttributeUnbound::GetAsPlayer(Node* node) -> Player* { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a player."); +} +void NodeAttributeUnbound::Set(Node* node, Player* value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a player."); +} + +auto NodeAttributeUnbound::GetAsMaterials(Node* node) + -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a material array."); +} +void NodeAttributeUnbound::Set(Node* node, + const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a material array."); +} + +auto NodeAttributeUnbound::GetAsTexture(Node* node) -> Texture* { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a texture."); +} +void NodeAttributeUnbound::Set(Node* node, Texture* value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a texture."); +} + +auto NodeAttributeUnbound::GetAsTextures(Node* node) -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a texture array."); +} +void NodeAttributeUnbound::Set(Node* node, const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a texture array."); +} + +auto NodeAttributeUnbound::GetAsSound(Node* node) -> Sound* { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a sound."); +} +void NodeAttributeUnbound::Set(Node* node, Sound* value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a sound."); +} + +auto NodeAttributeUnbound::GetAsSounds(Node* node) -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a sound array."); +} +void NodeAttributeUnbound::Set(Node* node, const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a sound array."); +} + +auto NodeAttributeUnbound::GetAsModel(Node* node) -> Model* { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a model."); +} +void NodeAttributeUnbound::Set(Node* node, Model* value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a model."); +} + +auto NodeAttributeUnbound::GetAsModels(Node* node) -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a model array."); +} +void NodeAttributeUnbound::Set(Node* node, const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a model array."); +} + +auto NodeAttributeUnbound::GetAsCollideModel(Node* node) -> CollideModel* { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a collide-model."); +} +void NodeAttributeUnbound::Set(Node* node, CollideModel* value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a collide-model."); +} + +auto NodeAttributeUnbound::GetAsCollideModels(Node* node) + -> std::vector { + throw Exception("Can't get attr '" + name() + "' on node type '" + + node_type()->name() + "' as a collide-model array."); +} +void NodeAttributeUnbound::Set(Node* node, + const std::vector& value) { + throw Exception("Can't set attr '" + name() + "' on node type '" + + node_type()->name() + "' as a collide-model array."); +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/node_attribute.h b/src/ballistica/scene/node/node_attribute.h new file mode 100644 index 00000000..92f73064 --- /dev/null +++ b/src/ballistica/scene/node/node_attribute.h @@ -0,0 +1,1016 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_NODE_ATTRIBUTE_H_ +#define BALLISTICA_SCENE_NODE_NODE_ATTRIBUTE_H_ + +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +#pragma clang diagnostic push +#pragma ide diagnostic ignored "OCUnusedMacroInspection" + +// Unbound node attribute; these are statically stored in a node type +// and contain logic to get/set a particular attribute on a node +// in various ways. +class NodeAttributeUnbound { + public: + static auto GetNodeAttributeTypeName(NodeAttributeType) -> std::string; + + NodeAttributeUnbound(NodeType* node_type, NodeAttributeType type, + std::string name, uint32_t flags); + + // Attrs should override the calls they support; by default + // these all raise exceptions. + // Generally attrs are get/set as their native type, + // but in cases of attr connections a 'get' corresponding + // to the native type of the dst attr is made on the src attr + // (so if connecting float attr foo to int attr bar, + // the update will essentially be: bar.set(foo.GetAsInt()) ) + virtual auto GetAsFloat(Node* node) -> float; + virtual void Set(Node* node, float value); + + virtual auto GetAsInt(Node* node) -> int64_t; + virtual void Set(Node* node, int64_t value); + + virtual auto GetAsBool(Node* node) -> bool; + virtual void Set(Node* node, bool value); + + virtual auto GetAsString(Node* node) -> std::string; + virtual void Set(Node* node, const std::string& value); + + virtual auto GetAsFloats(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& value); + + virtual auto GetAsInts(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& value); + + virtual auto GetAsNode(Node* node) -> Node*; + virtual void Set(Node* node, Node* value); + + virtual auto GetAsNodes(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& values); + + virtual auto GetAsPlayer(Node* node) -> Player*; + virtual void Set(Node* node, Player* value); + + virtual auto GetAsMaterials(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& value); + + virtual auto GetAsTexture(Node* node) -> Texture*; + virtual void Set(Node* node, Texture* value); + + virtual auto GetAsTextures(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& values); + + virtual auto GetAsSound(Node* node) -> Sound*; + virtual void Set(Node* node, Sound* value); + + virtual auto GetAsSounds(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& values); + + virtual auto GetAsModel(Node* node) -> Model*; + virtual void Set(Node* node, Model* value); + + virtual auto GetAsModels(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& values); + + virtual auto GetAsCollideModel(Node* node) -> CollideModel*; + virtual void Set(Node* node, CollideModel* value); + + virtual auto GetAsCollideModels(Node* node) -> std::vector; + virtual void Set(Node* node, const std::vector& values); + + auto is_read_only() const -> bool { + return static_cast(flags_ & kNodeAttributeFlagReadOnly); + } + auto type() const -> NodeAttributeType { return type_; } + auto GetTypeName() const -> std::string { + return GetNodeAttributeTypeName(type_); + } + auto name() const -> const std::string& { return name_; } + auto node_type() const -> NodeType* { return node_type_; } + auto index() const -> int { return index_; } + void DisconnectIncoming(Node* node); + + protected: + void NotReadableError(Node* node); + void NotWritableError(Node* node); + + private: + NodeType* node_type_; + NodeAttributeType type_; + std::string name_; + uint32_t flags_; + int index_; +}; + +// Simple node-attribute pair; used as a convenience measure. +// Note that this simply stores pointers; it does not check to +// ensure the node is still valid or anything like that. +class NodeAttribute { + public: + void assign(Node* node_in, NodeAttributeUnbound* attr_in) { + node = node_in; + attr = attr_in; + } + NodeAttribute() = default; + NodeAttribute(Node* node_in, NodeAttributeUnbound* attr_in) + : node(node_in), attr(attr_in) {} + Node* node = nullptr; + NodeAttributeUnbound* attr = nullptr; + auto type() const -> NodeAttributeType { return attr->type(); } + auto GetTypeName() const -> std::string { return attr->GetTypeName(); } + auto name() const -> const std::string& { return attr->name(); } + auto node_type() const -> NodeType* { return attr->node_type(); } + auto index() const -> int { return attr->index(); } + void DisconnectIncoming() { attr->DisconnectIncoming(node); } + auto is_read_only() const -> bool { return attr->is_read_only(); } + auto GetAsFloat() const -> float { return attr->GetAsFloat(node); } + void Set(float value) const { attr->Set(node, value); } + auto GetAsInt() const -> int64_t { return attr->GetAsInt(node); } + void Set(int64_t value) const { attr->Set(node, value); } + auto GetAsBool() const -> bool { return attr->GetAsBool(node); } + void Set(bool value) const { attr->Set(node, value); } + auto GetAsString() const -> std::string { return attr->GetAsString(node); } + void Set(const std::string& value) const { attr->Set(node, value); } + auto GetAsFloats() const -> std::vector { + return attr->GetAsFloats(node); + } + void Set(const std::vector& value) const { attr->Set(node, value); } + auto GetAsInts() const -> std::vector { + return attr->GetAsInts(node); + } + void Set(const std::vector& value) const { attr->Set(node, value); } + auto GetAsNode() const -> Node* { return attr->GetAsNode(node); } + void Set(Node* value) const { attr->Set(node, value); } + auto GetAsNodes() const -> std::vector { + return attr->GetAsNodes(node); + } + void Set(const std::vector& value) const { attr->Set(node, value); } + auto GetAsPlayer() const -> Player* { return attr->GetAsPlayer(node); } + void Set(Player* value) const { attr->Set(node, value); } + auto GetAsMaterials() const -> std::vector { + return attr->GetAsMaterials(node); + } + void Set(const std::vector& value) const { + attr->Set(node, value); + } + auto GetAsTexture() const -> Texture* { return attr->GetAsTexture(node); } + void Set(Texture* value) const { attr->Set(node, value); } + auto GetAsTextures() const -> std::vector { + return attr->GetAsTextures(node); + } + void Set(const std::vector& values) const { + attr->Set(node, values); + } + auto GetAsSound() const -> Sound* { return attr->GetAsSound(node); } + void Set(Sound* value) const { attr->Set(node, value); } + auto GetAsSounds() const -> std::vector { + return attr->GetAsSounds(node); + } + void Set(const std::vector& values) const { attr->Set(node, values); } + auto GetAsModel() const -> Model* { return attr->GetAsModel(node); } + void Set(Model* value) const { attr->Set(node, value); } + auto GetAsModels() const -> std::vector { + return attr->GetAsModels(node); + } + void Set(const std::vector& values) const { attr->Set(node, values); } + auto GetAsCollideModel() const -> CollideModel* { + return attr->GetAsCollideModel(node); + } + void Set(CollideModel* value) const { attr->Set(node, value); } + auto GetAsCollideModels() const -> std::vector { + return attr->GetAsCollideModels(node); + } + void Set(const std::vector& values) const { + attr->Set(node, values); + } +}; + +// Single float attr; subclasses just need to override float get/set +// and this will provide the other numeric get/sets based on that. +class NodeAttributeUnboundFloat : public NodeAttributeUnbound { + public: + NodeAttributeUnboundFloat(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kFloat, name, + flags) {} + + // Override these: + auto GetAsFloat(Node* node) -> float override { + NotReadableError(node); + return 0.0f; + } + void Set(Node* node, float val) override { NotWritableError(node); } + + // These are handled automatically: + auto GetAsInt(Node* node) -> int64_t final { + return static_cast(GetAsFloat(node)); + } + auto GetAsBool(Node* node) -> bool final { + return static_cast(GetAsFloat(node)); + } + void Set(Node* node, int64_t val) final { + Set(node, static_cast(val)); + } + void Set(Node* node, bool val) final { Set(node, static_cast(val)); } +}; + +// Float array attr. +class NodeAttributeUnboundFloatArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundFloatArray(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kFloatArray, name, + flags) {} + + // Override these: + auto GetAsFloats(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& vals) override { + NotWritableError(node); + } +}; + +// Single int attr; subclasses just need to override int get/set +// and this will provide the other numeric get/sets based on that. +class NodeAttributeUnboundInt : public NodeAttributeUnbound { + public: + NodeAttributeUnboundInt(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kInt, name, flags) {} + + // Override these: + auto GetAsInt(Node* node) -> int64_t override { + NotReadableError(node); + return 0; + } + void Set(Node* node, int64_t val) override { NotWritableError(node); } + + // These are handled automatically: + auto GetAsFloat(Node* node) -> float final { return GetAsInt(node); } + auto GetAsBool(Node* node) -> bool final { + return static_cast(GetAsInt(node)); + } + void Set(Node* node, float val) final { + Set(node, static_cast(val)); + } + void Set(Node* node, bool val) final { Set(node, static_cast(val)); } +}; + +// Int array attr. +class NodeAttributeUnboundIntArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundIntArray(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kIntArray, name, + flags) {} + + // Override these: + auto GetAsInts(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& vals) override = 0; +}; + +// Single bool attr; subclasses just need to override bool get/set +// and this will provide the other numeric get/sets based on that. +class NodeAttributeUnboundBool : public NodeAttributeUnbound { + public: + NodeAttributeUnboundBool(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kBool, name, flags) { + } + + // Override these: + auto GetAsBool(Node* node) -> bool override { + NotReadableError(node); + return false; + }; + void Set(Node* node, bool val) override { NotWritableError(node); } + + // These are handled automatically: + auto GetAsFloat(Node* node) -> float final { + return GetAsBool(node) ? 1.0f : 0.0f; + } + auto GetAsInt(Node* node) -> int64_t final { return GetAsBool(node) ? 1 : 0; } + void Set(Node* node, float val) final { Set(node, val != 0.0f); } + void Set(Node* node, int64_t val) final { Set(node, val != 0); } +}; + +// String attr. +class NodeAttributeUnboundString : public NodeAttributeUnbound { + public: + NodeAttributeUnboundString(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kString, name, + flags) {} + + // Override these: + auto GetAsString(Node* node) -> std::string override { + NotReadableError(node); + return ""; + }; + void Set(Node* node, const std::string& val) override { + NotWritableError(node); + } +}; + +// Node attr. +class NodeAttributeUnboundNode : public NodeAttributeUnbound { + public: + NodeAttributeUnboundNode(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kNode, name, flags) { + } + + // Override these: + auto GetAsNode(Node* node) -> Node* override { + NotReadableError(node); + return nullptr; + }; + void Set(Node* node, Node* val) override { NotWritableError(node); } +}; + +// Node array attr. +class NodeAttributeUnboundNodeArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundNodeArray(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kNodeArray, name, + flags) {} + // Override these: + auto GetAsNodes(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + }; + void Set(Node* node, const std::vector& vals) override { + NotWritableError(node); + } +}; + +// Player attr. +class NodeAttributeUnboundPlayer : public NodeAttributeUnbound { + public: + NodeAttributeUnboundPlayer(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kPlayer, name, + flags) {} + // override these: + auto GetAsPlayer(Node* node) -> Player* override { + NotReadableError(node); + return nullptr; + } + void Set(Node* node, Player* val) override { NotWritableError(node); } +}; + +// Material array attr. +class NodeAttributeUnboundMaterialArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundMaterialArray(NodeType* node_type, + const std::string& name, uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kMaterialArray, name, + flags) {} + // override these: + auto GetAsMaterials(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& materials) override { + NotWritableError(node); + } +}; + +// Texture attr. +class NodeAttributeUnboundTexture : public NodeAttributeUnbound { + public: + NodeAttributeUnboundTexture(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kTexture, name, + flags) {} + // Override these: + auto GetAsTexture(Node* node) -> Texture* override { + NotReadableError(node); + return nullptr; + } + void Set(Node* node, Texture* val) override { NotWritableError(node); } +}; + +// Texture array attr. +class NodeAttributeUnboundTextureArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundTextureArray(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kTextureArray, name, + flags) {} + // Override these: + auto GetAsTextures(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& vals) override { + NotWritableError(node); + } +}; + +// Sound attr. +class NodeAttributeUnboundSound : public NodeAttributeUnbound { + public: + NodeAttributeUnboundSound(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kSound, name, + flags) {} + // override these: + auto GetAsSound(Node* node) -> Sound* override { + NotReadableError(node); + return nullptr; + } + void Set(Node* node, Sound* val) override { NotWritableError(node); } +}; + +// Sound array attr. +class NodeAttributeUnboundSoundArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundSoundArray(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kSoundArray, name, + flags) {} + // Override these: + auto GetAsSounds(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& vals) override { + NotWritableError(node); + } +}; + +// Model attr. +class NodeAttributeUnboundModel : public NodeAttributeUnbound { + public: + NodeAttributeUnboundModel(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kModel, name, + flags) {} + // Override these: + auto GetAsModel(Node* node) -> Model* override { + NotReadableError(node); + return nullptr; + } + void Set(Node* node, Model* val) override { NotWritableError(node); } +}; + +// Model array attr. +class NodeAttributeUnboundModelArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundModelArray(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kModelArray, name, + flags) {} + // Override these: + auto GetAsModels(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& vals) override { + NotWritableError(node); + } +}; + +// Collide_model attr. +class NodeAttributeUnboundCollideModel : public NodeAttributeUnbound { + public: + NodeAttributeUnboundCollideModel(NodeType* node_type, const std::string& name, + uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kCollideModel, name, + flags) {} + // Override these: + auto GetAsCollideModel(Node* node) -> CollideModel* override { + NotReadableError(node); + return nullptr; + } + void Set(Node* node, CollideModel* val) override { NotWritableError(node); } +}; + +// Collide_model array attr. +class NodeAttributeUnboundCollideModelArray : public NodeAttributeUnbound { + public: + NodeAttributeUnboundCollideModelArray(NodeType* node_type, + const std::string& name, uint32_t flags) + : NodeAttributeUnbound(node_type, NodeAttributeType::kCollideModelArray, + name, flags) {} + // Override these: + auto GetAsCollideModels(Node* node) -> std::vector override { + NotReadableError(node); + return std::vector(); + } + void Set(Node* node, const std::vector& vals) override { + NotWritableError(node); + } +}; + +// Defines a float attr subclass that interfaces with specific getter/setter +// calls. +#define BA_FLOAT_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundFloat { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundFloat(node_type, #NAME, 0) {} \ + auto GetAsFloat(Node* node) -> float override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, float val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a float attr subclass that interfaces with specific getter/setter +// calls. +#define BA_FLOAT_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundFloat { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundFloat(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsFloat(Node* node) -> float override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a float-array attr subclass that interfaces with specific +// getter/setter calls. +#define BA_FLOAT_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundFloatArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundFloatArray(node_type, #NAME, 0) {} \ + auto GetAsFloats(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& vals) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(vals); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a float-array attr subclass that interfaces with specific +// getter/setter calls. +#define BA_FLOAT_ARRAY_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundFloatArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundFloatArray(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsFloats(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines an int attr subclass that interfaces with specific getter/setter +// calls. +#define BA_INT_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundInt { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundInt(node_type, #NAME, 0) {} \ + auto GetAsInt(Node* node) -> int64_t override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, int64_t val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(static_cast_check_fit(val)); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines an int attr subclass that interfaces with specific getter/setter +// calls. +#define BA_INT_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundInt { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundInt(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsInt(Node* node) -> int64_t override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines an int attr subclass that interfaces with specific getter/setter +// calls. +#define BA_INT64_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundInt { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundInt(node_type, #NAME, 0) {} \ + auto GetAsInt(Node* node) -> int64_t override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, int64_t val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines an int attr subclass that interfaces with specific getter/setter +// calls. +#define BA_INT64_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundInt { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundInt(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsInt(Node* node) -> int64_t override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines an int-array attr subclass that interfaces with specific +// getter/setter calls. +#define BA_INT64_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundIntArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundIntArray(node_type, #NAME, 0) {} \ + auto GetAsInts(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& vals) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(vals); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a bool attr subclass that interfaces with specific getter/setter +// calls. +#define BA_BOOL_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundBool { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundBool(node_type, #NAME, 0) {} \ + auto GetAsBool(Node* node) -> bool override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, bool val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a bool attr subclass that interfaces with specific getter/setter +// calls. +#define BA_BOOL_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundBool { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundBool(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsBool(Node* node) -> bool override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a string attr subclass that interfaces with specific getter/setter +// calls. +#define BA_STRING_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundString { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundString(node_type, #NAME, 0) {} \ + auto GetAsString(Node* node) -> std::string override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::string& val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a string attr subclass that interfaces with specific getter/setter +// calls. +#define BA_STRING_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundString { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundString(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsString(Node* node) -> std::string override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a node attr subclass that interfaces with specific getter/setter +// calls. +#define BA_NODE_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundNode { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundNode(node_type, #NAME, 0) {} \ + auto GetAsNode(Node* node) -> Node* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, Node* val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a node-array attr subclass that interfaces with specific +// getter/setter calls. +#define BA_NODE_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundNodeArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundNodeArray(node_type, #NAME, 0) {} \ + auto GetAsNodes(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a player attr subclass that interfaces with specific getter/setter +// calls. +#define BA_PLAYER_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundPlayer { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundPlayer(node_type, #NAME, 0) {} \ + auto GetAsPlayer(Node* node) -> Player* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, Player* val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a material-array attr subclass that interfaces with specific +// getter/setter calls. +#define BA_MATERIAL_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundMaterialArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundMaterialArray(node_type, #NAME, 0) {} \ + auto GetAsMaterials(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a texture attr subclass that interfaces with specific getter/setter +// calls. +#define BA_TEXTURE_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundTexture { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundTexture(node_type, #NAME, 0) {} \ + auto GetAsTexture(Node* node) -> Texture* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, Texture* val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a texture attr subclass that interfaces with specific getter/setter +// calls. +#define BA_TEXTURE_ATTR_READONLY(NAME, GETTER) \ + class Attr_##NAME : public NodeAttributeUnboundTexture { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundTexture(node_type, #NAME, \ + kNodeAttributeFlagReadOnly) {} \ + auto GetAsTexture(Node* node) -> Texture* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a texture attr subclass that interfaces with specific getter/setter +// calls. +#define BA_TEXTURE_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundTextureArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundTextureArray(node_type, #NAME, 0) {} \ + auto GetAsTextures(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& vals) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(vals); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a sound attr subclass that interfaces with specific getter/setter +// calls. +#define BA_SOUND_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundSound { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundSound(node_type, #NAME, 0) {} \ + auto GetAsSound(Node* node) -> Sound* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, Sound* val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a sound attr subclass that interfaces with specific getter/setter +// calls. +#define BA_SOUND_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundSoundArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundSoundArray(node_type, #NAME, 0) {} \ + auto GetAsSounds(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& vals) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(vals); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a model attr subclass that interfaces with specific getter/setter +// calls. +#define BA_MODEL_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundModel { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundModel(node_type, #NAME, 0) {} \ + auto GetAsModel(Node* node) -> Model* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, Model* val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a model attr subclass that interfaces with specific getter/setter +// calls. +#define BA_MODEL_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundModelArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundModelArray(node_type, #NAME, 0) {} \ + auto GetAsModels(Node* node) -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& vals) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(vals); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a collide_model attr subclass that interfaces with specific +// getter/setter calls. +#define BA_COLLIDE_MODEL_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundCollideModel { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundCollideModel(node_type, #NAME, 0) {} \ + auto GetAsCollideModel(Node* node) -> CollideModel* override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, CollideModel* val) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(val); \ + } \ + }; \ + Attr_##NAME NAME; + +// Defines a collide_model attr subclass that interfaces with specific +// getter/setter calls. +#define BA_COLLIDE_MODEL_ARRAY_ATTR(NAME, GETTER, SETTER) \ + class Attr_##NAME : public NodeAttributeUnboundCollideModelArray { \ + public: \ + explicit Attr_##NAME(NodeType* node_type) \ + : NodeAttributeUnboundCollideModelArray(node_type, #NAME, 0) {} \ + auto GetAsCollideModels(Node* node) \ + -> std::vector override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + return tnode->GETTER(); \ + } \ + void Set(Node* node, const std::vector& vals) override { \ + BA_NODE_TYPE_CLASS* tnode = static_cast(node); \ + assert(dynamic_cast(node) == tnode); \ + tnode->SETTER(vals); \ + } \ + }; \ + Attr_##NAME NAME; + +#pragma clang diagnostic pop + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_NODE_ATTRIBUTE_H_ diff --git a/src/ballistica/scene/node/node_attribute_connection.cc b/src/ballistica/scene/node/node_attribute_connection.cc new file mode 100644 index 00000000..c926e1fc --- /dev/null +++ b/src/ballistica/scene/node/node_attribute_connection.cc @@ -0,0 +1,108 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/node_attribute_connection.h" + +#include + +#include "ballistica/scene/node/node.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +void NodeAttributeConnection::Update() { + assert(src_node.exists() && dst_node.exists()); + auto* src_node_p{src_node.get()}; + + // We no longer update after errors now. + // (the constant stream of exceptions slows things down too much) + if (have_error) { + return; + } + + try { + // Pull data from the src to match the dst type. + NodeAttributeUnbound* src_attr = + src_node->type()->GetAttribute(src_attr_index); + assert(src_attr); + NodeAttributeUnbound* dst_attr = + dst_node->type()->GetAttribute(dst_attr_index); + assert(dst_attr); + switch (dst_attr->type()) { + case NodeAttributeType::kFloat: + dst_attr->Set(dst_node.get(), src_attr->GetAsFloat(src_node_p)); + break; + case NodeAttributeType::kInt: + dst_attr->Set(dst_node.get(), src_attr->GetAsInt(src_node_p)); + break; + case NodeAttributeType::kBool: + dst_attr->Set(dst_node.get(), src_attr->GetAsBool(src_node_p)); + break; + case NodeAttributeType::kString: + dst_attr->Set(dst_node.get(), src_attr->GetAsString(src_node_p)); + break; + case NodeAttributeType::kIntArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsInts(src_node_p)); + break; + case NodeAttributeType::kFloatArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsFloats(src_node_p)); + break; + case NodeAttributeType::kNode: + dst_attr->Set(dst_node.get(), src_attr->GetAsNode(src_node_p)); + break; + case NodeAttributeType::kNodeArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsNodes(src_node_p)); + break; + case NodeAttributeType::kPlayer: + dst_attr->Set(dst_node.get(), src_attr->GetAsPlayer(src_node_p)); + break; + case NodeAttributeType::kMaterialArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsMaterials(src_node_p)); + break; + case NodeAttributeType::kTexture: + dst_attr->Set(dst_node.get(), src_attr->GetAsTexture(src_node_p)); + break; + case NodeAttributeType::kTextureArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsTextures(src_node_p)); + break; + case NodeAttributeType::kSound: + dst_attr->Set(dst_node.get(), src_attr->GetAsSound(src_node_p)); + break; + case NodeAttributeType::kSoundArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsSounds(src_node_p)); + break; + case NodeAttributeType::kModel: + dst_attr->Set(dst_node.get(), src_attr->GetAsModel(src_node_p)); + break; + case NodeAttributeType::kModelArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsModels(src_node_p)); + break; + case NodeAttributeType::kCollideModel: + dst_attr->Set(dst_node.get(), src_attr->GetAsCollideModel(src_node_p)); + break; + case NodeAttributeType::kCollideModelArray: + dst_attr->Set(dst_node.get(), src_attr->GetAsCollideModels(src_node_p)); + break; + default: + throw Exception("FIXME: unimplemented for attr type: '" + + dst_attr->GetTypeName() + "'"); + } + } catch (const std::exception& e) { + // Print errors only once per connection to avoid overwhelming the logs. + // (though we now stop updating after an error so this is redundant). + if (!have_error) { + have_error = true; + NodeAttributeUnbound* src_attr = + src_node->type()->GetAttribute(src_attr_index); + NodeAttributeUnbound* dst_attr = + dst_node->type()->GetAttribute(dst_attr_index); + Log("ERROR: attribute connection update: " + std::string(e.what()) + + "; srcAttr='" + src_attr->name() + "', src_node='" + + src_node->type()->name() + "', srcNodeName='" + src_node->label() + + "', dstAttr='" + dst_attr->name() + "', dstNode='" + + dst_node->type()->name() + "', dstNodeName='" + dst_node->label() + + "'"); + } + } +} +} // namespace ballistica diff --git a/src/ballistica/scene/node/node_attribute_connection.h b/src/ballistica/scene/node/node_attribute_connection.h new file mode 100644 index 00000000..07b3737b --- /dev/null +++ b/src/ballistica/scene/node/node_attribute_connection.h @@ -0,0 +1,26 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_NODE_ATTRIBUTE_CONNECTION_H_ +#define BALLISTICA_SCENE_NODE_NODE_ATTRIBUTE_CONNECTION_H_ + +#include + +#include "ballistica/core/object.h" + +namespace ballistica { + +class NodeAttributeConnection : public Object { + public: + NodeAttributeConnection() = default; + void Update(); + Object::WeakRef src_node; + int src_attr_index{}; + Object::WeakRef dst_node; + int dst_attr_index{}; + bool have_error{}; + std::list >::iterator src_iterator; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_NODE_ATTRIBUTE_CONNECTION_H_ diff --git a/src/ballistica/scene/node/node_type.h b/src/ballistica/scene/node/node_type.h new file mode 100644 index 00000000..7237b500 --- /dev/null +++ b/src/ballistica/scene/node/node_type.h @@ -0,0 +1,82 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_NODE_TYPE_H_ +#define BALLISTICA_SCENE_NODE_NODE_TYPE_H_ + +#include +#include +#include +#include + +#include "ballistica/ballistica.h" + +namespace ballistica { + +// Type structure for a node, storing attribute lists and other static type +// data. +class NodeType { + public: + NodeType(std::string name, NodeCreateFunc* create_call) + : name_(std::move(name)), create_call_(create_call), id_(-1) {} + + /// Return an unbound attribute by name; if missing either throws an exception + /// or returns nullptr. + auto GetAttribute(const std::string& name, bool throw_if_missing = true) const + -> NodeAttributeUnbound* { + auto i = attributes_by_name_.find(name); + if (i == attributes_by_name_.end()) { + if (throw_if_missing) { + throw Exception("Attribute not found: '" + name + "'"); + } else { + return nullptr; + } + } + return i->second; + } + ~NodeType(); + + /// Return an unbound attribute by index. + auto GetAttribute(int index) const -> NodeAttributeUnbound* { + BA_PRECONDITION( + index >= 0 + && index < static_cast_check_fit(attributes_by_index_.size())); + return attributes_by_index_[index]; + } + + auto HasAttribute(const std::string& name) const -> bool { + return (GetAttribute(name, false) != nullptr); + } + + auto name() const -> std::string { return name_; } + + auto GetAttributeNames() const -> std::vector; + + auto Create(Scene* sg) -> Node* { + assert(create_call_); + return create_call_(sg); + } + + auto id() const -> int { + assert(id_ >= 0); + return id_; + } + + void set_id(int val) { id_ = val; } + auto attributes_by_index() const + -> const std::vector& { + return attributes_by_index_; + } + + private: + NodeCreateFunc* create_call_; + int id_; + std::string name_; + std::map attributes_by_name_; + std::vector attributes_by_index_; + friend class NodeAttributeUnbound; + friend class Node; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_NODE_TYPE_H_ diff --git a/src/ballistica/scene/node/null_node.cc b/src/ballistica/scene/node/null_node.cc new file mode 100644 index 00000000..e96f8cbd --- /dev/null +++ b/src/ballistica/scene/node/null_node.cc @@ -0,0 +1,29 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/null_node.h" + +#include "ballistica/game/game.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +// nothing to see here folks... move along +class NullNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS NullNode + BA_NODE_CREATE_CALL(CreateNull); +#undef BA_NODE_TYPE_CLASS + + NullNodeType() : NodeType("null", CreateNull) {} +}; + +static NodeType* node_type{}; + +auto NullNode::InitType() -> NodeType* { + node_type = new NullNodeType(); + return node_type; +} + +NullNode::NullNode(Scene* scene) : Node(scene, node_type) {} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/null_node.h b/src/ballistica/scene/node/null_node.h new file mode 100644 index 00000000..e135e113 --- /dev/null +++ b/src/ballistica/scene/node/null_node.h @@ -0,0 +1,22 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_NULL_NODE_H_ +#define BALLISTICA_SCENE_NODE_NULL_NODE_H_ + +#include "ballistica/scene/node/node.h" + +// empty node type - just used as a building block +namespace ballistica { + +class Scene; + +// An empty node. +class NullNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit NullNode(Scene* scene); +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_NULL_NODE_H_ diff --git a/src/ballistica/scene/node/player_node.cc b/src/ballistica/scene/node/player_node.cc new file mode 100644 index 00000000..e5b4eecb --- /dev/null +++ b/src/ballistica/scene/node/player_node.cc @@ -0,0 +1,48 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/player_node.h" + +#include + +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class PlayerNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS PlayerNode + BA_NODE_CREATE_CALL(CreatePlayer); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_INT_ATTR(playerID, player_id, SetPlayerID); +#undef BA_NODE_TYPE_CLASS + PlayerNodeType() + : NodeType("player", CreatePlayer), position(this), playerID(this) {} +}; + +static NodeType* node_type{}; + +auto PlayerNode::InitType() -> NodeType* { + node_type = new PlayerNodeType(); + return node_type; +} + +PlayerNode::PlayerNode(Scene* scene) : Node(scene, node_type) {} + +PlayerNode::~PlayerNode() = default; + +void PlayerNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for position"); + } + position_ = vals; +} + +void PlayerNode::SetPlayerID(int val) { + player_id_ = val; + // once this is set we also inform the scene of our existence.. + scene()->SetPlayerNode(player_id_, this); +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/player_node.h b/src/ballistica/scene/node/player_node.h new file mode 100644 index 00000000..45886b7e --- /dev/null +++ b/src/ballistica/scene/node/player_node.h @@ -0,0 +1,29 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_PLAYER_NODE_H_ +#define BALLISTICA_SCENE_NODE_PLAYER_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class PlayerNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit PlayerNode(Scene* scene); + ~PlayerNode() override; + auto position() const -> const std::vector& { return position_; } + void SetPosition(const std::vector& vals); + auto player_id() const -> int { return player_id_; } + void SetPlayerID(int val); + + private: + int player_id_{-1}; + std::vector position_{0.0f, 0.0f, 0.0f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_PLAYER_NODE_H_ diff --git a/src/ballistica/scene/node/prop_node.cc b/src/ballistica/scene/node/prop_node.cc new file mode 100644 index 00000000..a106a482 --- /dev/null +++ b/src/ballistica/scene/node/prop_node.cc @@ -0,0 +1,718 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/prop_node.h" + +#include + +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/area_of_interest.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/scene.h" +#include "ode/ode_joint.h" + +namespace ballistica { + +static void _doCalcERPCFM(float stiffness, float damping, float* erp, + float* cfm) { + if (stiffness <= 0.0f && damping <= 0.0f) { + (*erp) = 0.0f; + // (*cfm) = dInfinity; // doesn't seem to be happy... + (*cfm) = 9999999999.0f; + } else { + (*erp) = (kGameStepSeconds * stiffness) + / ((kGameStepSeconds * stiffness) + damping); + (*cfm) = 1.0f / ((kGameStepSeconds * stiffness) + damping); + } +} + +static NodeType* node_type{}; + +auto PropNode::InitType() -> NodeType* { + node_type = new PropNodeType(); + return node_type; +} + +PropNode::PropNode(Scene* scene, NodeType* override_node_type) + : Node(scene, override_node_type ? override_node_type : node_type), + part_(this) {} + +PropNode::~PropNode() { + if (area_of_interest_) { + g_graphics->camera()->DeleteAreaOfInterest( + static_cast(area_of_interest_)); + } +} + +void PropNode::SetExtraAcceleration(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("expected array of size 3 for extra_acceleration"); + } + extra_acceleration_ = vals; +} + +void PropNode::HandleMessage(const char* data_in) { + const char* data = data_in; + bool handled = true; + switch (extract_node_message_type(&data)) { + case NodeMessageType::kImpulse: { + float px = Utils::ExtractFloat16NBO(&data); + float py = Utils::ExtractFloat16NBO(&data); + float pz = Utils::ExtractFloat16NBO(&data); + float vx = Utils::ExtractFloat16NBO(&data); + float vy = Utils::ExtractFloat16NBO(&data); + float vz = Utils::ExtractFloat16NBO(&data); + float mag = Utils::ExtractFloat16NBO(&data); + float velocity_mag = Utils::ExtractFloat16NBO(&data); + float radius = Utils::ExtractFloat16NBO(&data); + Utils::ExtractInt16NBO(&data); // calc-force-only + float fdirx = Utils::ExtractFloat16NBO(&data); + float fdiry = Utils::ExtractFloat16NBO(&data); + float fdirz = Utils::ExtractFloat16NBO(&data); + body_->ApplyImpulse(px, py, pz, vx, vy, vz, fdirx, fdiry, fdirz, mag, + velocity_mag, radius, false); + break; + } + default: + handled = false; + break; + } + if (!handled) { + Node::HandleMessage(data_in); + } +} + +void PropNode::SetIsAreaOfInterest(bool val) { + if ((val && area_of_interest_ == nullptr) + || (!val && area_of_interest_ != nullptr)) { + // either make one or kill the one we had + if (val) { + assert(area_of_interest_ == nullptr); + area_of_interest_ = g_graphics->camera()->NewAreaOfInterest(false); + } else { + assert(area_of_interest_ != nullptr); + g_graphics->camera()->DeleteAreaOfInterest( + static_cast(area_of_interest_)); + area_of_interest_ = nullptr; + } + } +} + +void PropNode::Draw(FrameDef* frame_def) { +#if !BA_HEADLESS_BUILD + + // need our texture, model, and body to be present to draw.. + if ((!model_.exists()) || (!color_texture_.exists()) || (!body_.exists())) { + return; + } + + ObjectComponent c(frame_def->beauty_pass()); + c.SetTexture(color_texture_); + c.SetLightShadow(LightShadowType::kObject); + if (reflection_ != ReflectionType::kNone) { + c.SetReflection(reflection_); + c.SetReflectionScale(reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + } + if (flashing_ && frame_def->frame_number() % 10 < 5) { + c.SetColor(1.2f, 1.2f, 1.2f); + } + c.PushTransform(); + c.TransformToBody(*body_); + float s = model_scale_ * extra_model_scale_; + c.Scale(s, s, s); + c.DrawModel(model_->model_data()); + c.PopTransform(); + c.Submit(); + + { // shadow + assert(body_.exists()); + const dReal* pos_raw = dGeomGetPosition(body_->geom()); + float pos[3]; + pos[0] = pos_raw[0] + body_->blend_offset().x; + pos[1] = pos_raw[1] + body_->blend_offset().y; + pos[2] = pos_raw[2] + body_->blend_offset().z; + float s_scale, s_density; + shadow_.GetValues(&s_scale, &s_density); + if (body_type_ == BodyType::PUCK) { + s_density *= 2.4f; + s_scale *= 0.85f; + } else { + s_density *= 2.3f; + } + s_density *= 0.34f; + { + GraphicsQuality quality = frame_def->quality(); + + // fancy new cheap shadows + { + float rs = shadow_size_ * model_scale_ * extra_model_scale_ * s_scale; + float d = (quality == GraphicsQuality::kLow ? 1.1f : 0.8f) * s_density; + g_graphics->DrawBlotch(Vector3f(pos), rs * 2.0f, 0.22f * d, 0.16f * d, + 0.10f * d, d); + } + + if (quality > GraphicsQuality::kLow) { + // More sharp accurate shadow. + if (light_model_.exists()) { + SimpleComponent c2(frame_def->light_shadow_pass()); + c2.SetTransparent(true); + float dd = body_type_ == BodyType::LANDMINE ? 0.5f : 1.0f; + c2.SetColor(0.3f, 0.2f, 0.1f, 0.08f * s_density * dd); + c2.PushTransform(); + c2.TransformToBody(*body_); + float ss = body_type_ == BodyType::LANDMINE ? 0.9f : 1.0f; + for (int i = 0; i < 4; i++) { + c2.PushTransform(); + float s2 = ss * model_scale_ * extra_model_scale_ + * (1.3f - 0.08f * static_cast(i)); + c2.Scale(s2, s2, s2); + c2.DrawModel(light_model_->model_data()); + c2.PopTransform(); + } + c2.PopTransform(); + c2.Submit(); + } + + // In fancy-pants mode we can do a softened version of ourself + // for fake caustic effects. + if (light_model_.exists()) { + assert(color_texture_.exists()); + SimpleComponent c2(frame_def->light_shadow_pass()); + c2.SetTransparent(true); + c2.SetPremultiplied(true); + c2.SetTexture(color_texture_); + if (flashing_ && frame_def->frame_number() % 10 < 5) { + c2.SetColor(0.026f * s_density, 0.026f * s_density, + 0.026f * s_density, 0.0f); + } else { + c2.SetColor(0.022f * s_density, 0.022f * s_density, + 0.022f * s_density, 0.0f); + } + c2.PushTransform(); + c2.TransformToBody(*body_); + for (int i = 0; i < 4; i++) { + c2.PushTransform(); + float s2 = model_scale_ * extra_model_scale_ * 1.7f; + c2.Scale(s2, s2, s2); + c2.Rotate(-50.0f + 43.0f * static_cast(i), 0.2f, 0.4f, 0.6f); + c2.DrawModel(light_model_->model_data()); + c2.PopTransform(); + } + c2.PopTransform(); + c2.Submit(); + } + } + } + } +#endif // !BA_HEADLESS_BUILD +} + +auto PropNode::GetBody() const -> std::string { + switch (body_type_) { + case BodyType::UNSET: + return ""; + case BodyType::BOX: + return "box"; + case BodyType::SPHERE: + return "sphere"; + case BodyType::CRATE: + return "crate"; + case BodyType::LANDMINE: + return "landMine"; + case BodyType::CAPSULE: + return "capsule"; + case BodyType::PUCK: + return "puck"; + default: + throw Exception("Invalid body-type in prop-node: " + + std::to_string(static_cast(body_type_))); + } +} + +void PropNode::SetBodyScale(float val) { + // this can be set exactly once + if (body_.exists()) { + throw Exception("body_scale can't be set once body exists"); + } + body_scale_ = std::max(0.01f, val); +} + +void PropNode::SetBody(const std::string& val) { + BodyType body_type; + RigidBody::Shape shape; + if (val == "box") { + body_type = BodyType::BOX; + shape = RigidBody::Shape::kBox; + } else if (val == "sphere") { + body_type = BodyType::SPHERE; + shape = RigidBody::Shape::kSphere; + } else if (val == "crate") { + body_type = BodyType::CRATE; + shape = RigidBody::Shape::kBox; + } else if (val == "landMine") { + body_type = BodyType::LANDMINE; + shape = RigidBody::Shape::kBox; + } else if (val == "capsule") { + body_type = BodyType::CAPSULE; + shape = RigidBody::Shape::kCapsule; + } else if (val == "puck") { + body_type = BodyType::PUCK; + shape = RigidBody::Shape::kCylinder; + } else { + throw Exception("Invalid body type: '" + val + "'"); + } + + // we're ok with redundant sets, but complain/ignore if they try to switch.. + if (body_.exists()) { + if (body_type_ != body_type || shape_ != shape) { + Log("ERROR: body attr can not be changed from its initial value"); + return; + } + } + body_type_ = body_type; + shape_ = shape; + body_ = + Object::New(0, &part_, RigidBody::Type::kBody, shape_, + RigidBody::kCollideActive, RigidBody::kCollideAll); + + body_->set_can_cause_impact_damage(true); + body_->AddCallback(DoCollideCallback, this); + if (body_type_ == BodyType::LANDMINE) { + float bs1 = 0.7f * body_scale_; + float bs2 = 0.18f * body_scale_; + body_->SetDimensions(bs1, bs2, bs1, bs1, bs2, bs1, 2.0f * density_); + } else if (body_type_ == BodyType::CRATE) { + float s = 0.7f * body_scale_; + body_->SetDimensions(s, s, s, s, s, s, 0.7f * density_); + } else if (body_type_ == BodyType::SPHERE) { + float s = 0.3f * body_scale_; + body_->SetDimensions(s, 0, 0, s, 0, 0, density_); + } else if (body_type_ == BodyType::CAPSULE) { + float s = 0.3f * body_scale_; + body_->SetDimensions(s, s, 0, s, s, 0, density_); + } + + // in case we've had a translate or velocity set already.. + dBodySetPosition(body_->body(), position_[0], position_[1], position_[2]); + dBodySetLinearVel(body_->body(), velocity_[0], velocity_[1], velocity_[2]); + + // initial orientation: + // put pucks upright and make them big + if (body_type_ == BodyType::PUCK) { + dQuaternion iq; + dQFromAxisAndAngle(iq, 1, 0, 0, -90 * (kPi / 180.0f)); + dBodySetQuaternion(body_->body(), iq); + body_->SetDimensions(0.7f, 0.58f, 0, 0.7f, 0.48f, 0, 0.14f * density_); + } else { + // give other types random start rotations.. + dQuaternion iq; + int64_t gti = scene()->stepnum(); + dQFromAxisAndAngle( + iq, 0.05f, 1, 0, + Utils::precalc_rands_1[(stream_id() + gti) % kPrecalcRandsCount] + * 360.0f * (kPi / 180.0f)); + dBodySetQuaternion(body_->body(), iq); + } +} + +void PropNode::UpdateAreaOfInterest() { + auto* aoi = static_cast(area_of_interest_); + if (!aoi) { + return; + } + assert(body_.exists()); + aoi->set_position(Vector3f(dGeomGetPosition(body_->geom()))); + aoi->SetRadius(5.0f); +} + +void PropNode::SetReflectionScale(const std::vector& vals) { + if (vals.size() != 1 && vals.size() != 3) { + throw Exception( + "Expected float array of length" + " 1 or 3 for reflection_scale"); + } + reflection_scale_ = vals; + if (reflection_scale_.size() == 1) { + reflection_scale_r_ = reflection_scale_g_ = reflection_scale_b_ = + reflection_scale_[0]; + } else { + reflection_scale_r_ = reflection_scale_[0]; + reflection_scale_g_ = reflection_scale_[1]; + reflection_scale_b_ = reflection_scale_[2]; + } +} + +auto PropNode::GetReflection() const -> std::string { + return Graphics::StringFromReflectionType(reflection_); +} + +void PropNode::SetReflection(const std::string& val) { + reflection_ = Graphics::ReflectionTypeFromString(val); +} + +auto PropNode::GetMaterials() const -> std::vector { + return part_.GetMaterials(); +} + +void PropNode::SetMaterials(const std::vector& vals) { + part_.SetMaterials(vals); +} + +auto PropNode::GetVelocity() const -> std::vector { + // if we've got a body, return its velocity + if (body_.exists()) { + const dReal* v = dBodyGetLinearVel(body_->body()); + std::vector vv(3); + vv[0] = v[0]; + vv[1] = v[1]; + vv[2] = v[2]; + return vv; + } + // otherwise if we have an internally stored value, return that. + // (this way if we set velocity and then query it we'll get the right value + // even if the body hasn't been made yet) + return velocity_; +} + +void PropNode::SetVelocity(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for velocity"); + } + // if we've got a body, apply the velocity to that + if (body_.exists()) { + dBodySetLinearVel(body_->body(), vals[0], vals[1], vals[2]); + } else { + // otherwise just store it in our internal vector in + // case someone asks for it + velocity_ = vals; + } +} + +auto PropNode::GetPosition() const -> std::vector { + // if we've got a body, return its position + if (body_.exists()) { + const dReal* p = dGeomGetPosition(body_->geom()); + std::vector f(3); + f[0] = p[0]; + f[1] = p[1]; + f[2] = p[2]; + return f; + } + // otherwise if we have an internally stored value, return that. + // (this way if we set position and then query it we'll get the right value + // even if the body hasn't been made yet) + return position_; +} + +void PropNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for position (got " + + std::to_string(vals.size()) + ")"); + } + // if we've got a body, apply the position to that + if (body_.exists()) { + dBodySetPosition(body_->body(), vals[0], vals[1], vals[2]); + } else { + // otherwise just store it in our internal vector + // in case someone asks for it + position_ = vals; + } +} + +void PropNode::Step() { + if (body_type_ == BodyType::UNSET) { + if (!reported_unset_body_type_) { + reported_unset_body_type_ = true; + Log("ERROR: prop-node " + GetObjectDescription() + + " did not have its 'body' attr set."); + return; + } + } + BA_DEBUG_CHECK_BODIES(); + + assert(body_.exists()); + + // FIXME - this should probably happen for RBDs automatically?... + body_->UpdateBlending(); + + // on happy thoughts, keep us on the 2d plane.. + if (g_graphics->camera()->happy_thoughts_mode() && body_.exists()) { + dBodyID b; + const dReal *p, *v; + b = body_->body(); + p = dBodyGetPosition(b); + dBodySetPosition(b, p[0], p[1], kHappyThoughtsZPlane); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0], v[1], 0.0f); + } + + // update our area-of-interest if we have one + UpdateAreaOfInterest(); + + // update our shadow input positions + { +#if !BA_HEADLESS_BUILD + shadow_.SetPosition(Vector3f(dBodyGetPosition(body_->body()))); +#endif // !BA_HEADLESS_BUILD + } + + // clamp our max linear and angular velocities + { + dBodyID b = body_->body(); + float max_mag_squared = 400.f; + // float max_mag_squared_lin = 300.0f; + float max_mag_squared_lin = max_speed_ * max_speed_; + const dReal* aVel = dBodyGetAngularVel(b); + float mag_squared = + aVel[0] * aVel[0] + aVel[1] * aVel[1] + aVel[2] * aVel[2]; + if (mag_squared > max_mag_squared) { + float scale = max_mag_squared / mag_squared; + dBodySetAngularVel(b, aVel[0] * scale, aVel[1] * scale, aVel[2] * scale); + } + const dReal* lVel = dBodyGetLinearVel(b); + mag_squared = lVel[0] * lVel[0] + lVel[1] * lVel[1] + lVel[2] * lVel[2]; + if (mag_squared > max_mag_squared_lin) { + float scale = max_mag_squared_lin / mag_squared; + dBodySetLinearVel(b, lVel[0] * scale, lVel[1] * scale, lVel[2] * scale); + } + } + + // if we're out of bounds, arrange to have ourself informed + if (body_.exists()) { + const dReal* p = dBodyGetPosition(body_->body()); + if (scene()->IsOutOfBounds(p[0], p[1], p[2])) { + scene()->AddOutOfBoundsNode(this); + } + } + + // apply damping force + float rotationalDampingX = 0.02f; + float rotationalDampingY = 0.02f; + float rotationalDampingZ = 0.02f; + + // don't add forces if we're asleep otherwise we'll explode when we wake up + if (dBodyIsEnabled(body_->body())) { + dMass mass; + dBodyID b = body_->body(); + dBodyGetMass(b, &mass); + + const dReal* vel; + dReal force[3]; + vel = dBodyGetAngularVel(b); + force[0] = -1 * mass.mass * vel[0] * rotationalDampingX; + force[1] = -1 * mass.mass * vel[1] * rotationalDampingY; + force[2] = -1 * mass.mass * vel[2] * rotationalDampingZ; + dBodyAddTorque(b, force[0], force[1], force[2]); + if (damping_ > 0.0f) { + float damp = std::max(0.0f, 1.0f - damping_); + const dReal* vel2 = dBodyGetLinearVel(b); + dBodySetLinearVel(b, vel2[0] * damp, vel2[1] * damp, vel2[2] * damp); + } + if (extra_acceleration_[0] != 0.0f || extra_acceleration_[1] != 0.0f + || extra_acceleration_[2] != 0.0f) { + dBodyAddForce(b, extra_acceleration_[0] * mass.mass, + extra_acceleration_[1] * mass.mass, + extra_acceleration_[2] * mass.mass); + } + if (gravity_scale_ != 1.0f) { + dVector3 grav; + // the simplest way to do this is to just add a force to offset gravity + // to where we want it to be for this object.. + float amt = gravity_scale_ - 1.0f; + dWorldGetGravity(scene()->dynamics()->ode_world(), grav); + dBodyAddForce(b, mass.mass * amt * grav[0], mass.mass * amt * grav[1], + mass.mass * amt * grav[2]); + } + } + BA_DEBUG_CHECK_BODIES(); +} + +auto PropNode::GetRigidBody(int id) -> RigidBody* { + if (id == 0) { + return body_.get(); + } + return nullptr; +} + +auto PropNode::CollideCallback(dContact* c, int count, + RigidBody* colliding_body, + RigidBody* opposingbody) -> bool { + if (sticky_) { + uint32_t f = opposingbody->flags(); + + // dont collide at all with rollers.. + if (f & RigidBody::kIsRoller) { + return false; + } + // this should never happen, right?.. + assert(opposingbody->part()->node() != nullptr); + + if ((stick_to_owner_ || opposingbody->part()->node() != owner_.get()) + && !(f & RigidBody::kIsBumper)) { + if (body_.exists()) { + // stick to static stuff: + if (opposingbody->type() == RigidBody::Type::kGeomOnly) { + const dReal* v; + dBodyID b = body_->body(); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0] * 0.2f, v[1] * 0.2f, v[2] * 0.2f); + dBodySetAngularVel(b, 0, 0, 0); + } else { + // stick to dynamic stuff + dBodyID b2 = opposingbody->body(); + dBodyID b1 = body_->body(); + dBodyEnable(b1); // wake it up + dBodyEnable(b2); // wake it up + dMass m; + dBodyGetMass(b2, &m); + dJointID j = + dJointCreateFixed(scene()->dynamics()->ode_world(), + scene()->dynamics()->getContactGroup()); + dJointAttach(j, b1, b2); + dJointSetFixed(j); + dJointSetFixedSpringMode(j, 1, 1, false); + if (m.mass < 0.2f) { + dJointSetFixedParam(j, dParamLinearStiffness, 200); + dJointSetFixedParam(j, dParamLinearDamping, 0.2f); + dJointSetFixedParam(j, dParamAngularStiffness, 200); + dJointSetFixedParam(j, dParamAngularDamping, 0.2f); + } else { + dJointSetFixedParam(j, dParamLinearStiffness, 2000); + dJointSetFixedParam(j, dParamLinearDamping, 2); + dJointSetFixedParam(j, dParamAngularStiffness, 2000); + dJointSetFixedParam(j, dParamAngularDamping, 2); + } + + // ...now attractive forces. + // FIXME - currently we ignore small stuff like limb bits. + // We really should just vary our sticky strength based + // on the mass of what we're hitting though. + if (m.mass < 0.2f) { + return true; // Still collide; just not sticky. + } + + // Also exert a slight attractive force. + { + const dReal* p1 = dBodyGetPosition(b1); + const dReal* p2 = dBodyGetPosition(b2); + dReal f2[3]; + float stiffness = 200; + f2[0] = (p1[0] - p2[0]) * stiffness; + f2[1] = (p1[1] - p2[1]) * stiffness; + f2[2] = (p1[2] - p2[2]) * stiffness; + dBodyAddForce(b1, -f2[0], -f2[1], -f2[2]); + dBodyAddForce(b2, f2[0], f2[1], f2[2]); + } + } + } + } + } + + if (body_type_ == BodyType::CRATE) { + // Drop stiffness/damping/friction pretty low. + float stiffness = 800.0f; + float damping = 1.0f; + if (opposingbody->flags() & RigidBody::kIsTerrain) { + damping = 10.0f; + } + float erp, cfm; + _doCalcERPCFM(stiffness, damping, &erp, &cfm); + for (int i = 0; i < count; i++) { + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + c[i].surface.mu *= 0.7f; + } + } else if (body_type_ == BodyType::LANDMINE) { + // we wanna be laying flat down; if we're standing upright, topple over + dVector3 worldUp; + dBodyVectorToWorld(body_->body(), 0, 1, 0, worldUp); + if (std::abs(worldUp[1]) < 0.4f) { + float mag = -4.0f; + // push in the 2 horizontal axes only + const dReal* pos = dBodyGetPosition(body_->body()); + dBodyAddForceAtPos(body_->body(), mag * worldUp[0], 0, mag * worldUp[2], + pos[0], pos[1] + 1.0f, pos[2]); + dBodyAddForceAtPos(body_->body(), -mag * worldUp[0], 0, -mag * worldUp[2], + pos[0], pos[1] - 1.0f, pos[2]); + } + // drop stiffness/damping/friction pretty low.. + float stiffness = 1000.0f; + float damping = 10.0f; + float erp, cfm; + _doCalcERPCFM(stiffness, damping, &erp, &cfm); + + // if we're not lying flat, kill friction + float friction = 1.0f; + if (std::abs(worldUp[1]) < 0.7f) friction = 0.05f; + + for (int i = 0; i < count; i++) { + c[i].surface.mu *= friction; + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + } + + // lets also damp our velocity a tiny bit if we're hitting terrain + if (opposingbody->flags() & RigidBody::kIsTerrain) { + float damp = 0.98f; + const dReal* vel = dBodyGetLinearVel(body_->body()); + dBodySetLinearVel(body_->body(), vel[0] * damp, vel[1], vel[2] * damp); + } + } else { + // drop stiffness/damping/friction pretty low.. + float stiffness = 5000.0f; + float damping = 10.0f; + float erp, cfm; + _doCalcERPCFM(stiffness, damping, &erp, &cfm); + for (int i = 0; i < count; i++) { + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + c[i].surface.mu *= 0.2f; + } + } + + return true; +} + +void PropNode::GetRigidBodyPickupLocations(int id, float* obj, float* character, + float* hand1, float* hand2) { + if (body_type_ == BodyType::LANDMINE) { + obj[0] = 0; + obj[1] = -0.1f; + obj[2] = 0; + character[0] = character[1] = character[2] = 0.0f; + character[1] = -0.3f; + character[2] = 0; + hand1[0] = -0.15f; + hand1[1] = 0.00f; + hand1[2] = 0.0f; + hand2[0] = 0.15f; + hand2[1] = 0.00f; + hand2[2] = 0.0f; + } else { + obj[0] = 0; + obj[1] = -0.17f; + obj[2] = 0; + character[0] = character[1] = character[2] = 0.0f; + character[1] = -0.27f; + hand1[0] = -0.15f; + hand1[1] = 0.00f; + hand1[2] = 0.0f; + hand2[0] = 0.15f; + hand2[1] = 0.00f; + hand2[2] = 0.0f; + } +} + +void PropNode::SetDensity(float val) { + if (body_.exists()) { + throw Exception("can't set density after body has been set"); + } + density_ = std::max(0.01f, std::min(100.0f, val)); +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/prop_node.h b/src/ballistica/scene/node/prop_node.h new file mode 100644 index 00000000..b8ea5684 --- /dev/null +++ b/src/ballistica/scene/node/prop_node.h @@ -0,0 +1,188 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_PROP_NODE_H_ +#define BALLISTICA_SCENE_NODE_PROP_NODE_H_ + +#include +#include + +#include "ballistica/dynamics/bg/bg_dynamics_shadow.h" +#include "ballistica/dynamics/part.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/scene/node/node.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class PropNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit PropNode(Scene* scene, NodeType* node_type = nullptr); + ~PropNode() override; + void HandleMessage(const char* data) override; + void Draw(FrameDef* frame_def) override; + void Step() override; + auto GetRigidBody(int id) -> RigidBody* override; + auto is_area_of_interest() const -> bool { + return (area_of_interest_ != nullptr); + } + void SetIsAreaOfInterest(bool val); + auto reflection_scale() const -> std::vector { + return reflection_scale_; + } + void SetReflectionScale(const std::vector& vals); + auto GetReflection() const -> std::string; + void SetReflection(const std::string& val); + auto color_texture() const -> Texture* { return color_texture_.get(); } + void set_color_texture(Texture* val) { color_texture_ = val; } + auto GetModel() const -> Model* { return model_.get(); } + void set_model(Model* val) { model_ = val; } + auto light_model() const -> Model* { return light_model_.get(); } + void set_light_model(Model* val) { light_model_ = val; } + auto sticky() const -> bool { return sticky_; } + void set_sticky(bool val) { sticky_ = val; } + auto shadow_size() const -> float { return shadow_size_; } + void set_shadow_size(float val) { shadow_size_ = val; } + auto stick_to_owner() const -> bool { return stick_to_owner_; } + void set_stick_to_owner(bool val) { stick_to_owner_ = val; } + auto model_scale() const -> float { return model_scale_; } + void set_model_scale(float val) { model_scale_ = val; } + auto flashing() const -> bool { return flashing_; } + void set_flashing(bool val) { flashing_ = val; } + auto owner() const -> Node* { return owner_.get(); } + void set_owner(Node* val) { owner_ = val; } + auto GetMaterials() const -> std::vector; + void SetMaterials(const std::vector& materials); + auto GetVelocity() const -> std::vector; + void SetVelocity(const std::vector& vals); + auto GetPosition() const -> std::vector; + void SetPosition(const std::vector& vals); + auto extra_acceleration() const -> std::vector { + return extra_acceleration_; + } + void SetExtraAcceleration(const std::vector& vals); + auto GetBody() const -> std::string; + void SetBody(const std::string& val); + auto density() const -> float { return density_; } + void SetDensity(float val); + auto body_scale() const -> float { return body_scale_; } + void SetBodyScale(float val); + auto damping() const -> float { return damping_; } + void set_damping(float val) { damping_ = val; } + auto max_speed() const -> float { return max_speed_; } + void set_max_speed(float val) { max_speed_ = val; } + auto gravity_scale() const -> float { return gravity_scale_; } + void set_gravity_scale(float val) { gravity_scale_ = val; } + + protected: + // FIXME - need to make all this private and add protected getters/setters + // as necessary + enum class BodyType { UNSET, SPHERE, BOX, LANDMINE, CRATE, CAPSULE, PUCK }; + void UpdateAreaOfInterest(); +#if !BA_HEADLESS_BUILD + BGDynamicsShadow shadow_; +#endif + Part part_; + void* area_of_interest_{}; + float model_scale_{1.0f}; + float shadow_size_{1.0f}; + int color_texture_Val{}; + float gravity_scale_{1.0f}; + Object::Ref body_; + RigidBody::Shape shape_{RigidBody::Shape::kSphere}; + Object::Ref color_texture_; + Object::Ref model_; + Object::Ref light_model_; + float density_{1.0f}; + float body_scale_{1.0f}; + float damping_{}; + float max_speed_{20.0f}; + std::vector velocity_{0.0f, 0.0f, 0.0f}; + std::vector position_{0.0f, 0.0f, 0.0f}; + std::vector extra_acceleration_{0.0, 0.0, 0.0}; + float extra_model_scale_{1.0f}; // For use by subclasses. + bool sticky_{}; + Object::WeakRef owner_; + bool flashing_{}; + bool stick_to_owner_{}; + BodyType body_type_{BodyType::UNSET}; + bool reported_unset_body_type_{}; + ReflectionType reflection_{ReflectionType::kNone}; + std::vector reflection_scale_{1.0f, 1.0f, 1.0f}; + float reflection_scale_r_{1.0f}; + float reflection_scale_g_{1.0f}; + float reflection_scale_b_{1.0f}; + static auto DoCollideCallback(dContact* c, int count, + RigidBody* colliding_body, + RigidBody* opposingbody, void* data) -> bool { + auto* a = static_cast(data); + return a->CollideCallback(c, count, colliding_body, opposingbody); + } + auto CollideCallback(dContact* c, int count, RigidBody* colliding_body, + RigidBody* opposingbody) -> bool; + void GetRigidBodyPickupLocations(int id, float* obj, float* character, + float* hand1, float* hand2) override; +}; + +class PropNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS PropNode + BA_NODE_CREATE_CALL(CreateProp); + BA_BOOL_ATTR(is_area_of_interest, is_area_of_interest, SetIsAreaOfInterest); + BA_FLOAT_ARRAY_ATTR(reflection_scale, reflection_scale, SetReflectionScale); + BA_STRING_ATTR(reflection, GetReflection, SetReflection); + BA_TEXTURE_ATTR(color_texture, color_texture, set_color_texture); + BA_MODEL_ATTR(model, GetModel, set_model); + BA_MODEL_ATTR(light_model, light_model, set_light_model); + BA_BOOL_ATTR(sticky, sticky, set_sticky); + BA_FLOAT_ATTR(shadow_size, shadow_size, set_shadow_size); + BA_BOOL_ATTR(stick_to_owner, stick_to_owner, set_stick_to_owner); + BA_FLOAT_ATTR(model_scale, model_scale, set_model_scale); + BA_BOOL_ATTR(flashing, flashing, set_flashing); + BA_NODE_ATTR(owner, owner, set_owner); + BA_MATERIAL_ARRAY_ATTR(materials, GetMaterials, SetMaterials); + BA_FLOAT_ARRAY_ATTR(velocity, GetVelocity, SetVelocity); + BA_FLOAT_ARRAY_ATTR(position, GetPosition, SetPosition); + BA_FLOAT_ATTR(density, density, SetDensity); + BA_FLOAT_ATTR(damping, damping, set_damping); + BA_FLOAT_ATTR(body_scale, body_scale, SetBodyScale); + BA_FLOAT_ATTR(max_speed, max_speed, set_max_speed); + BA_FLOAT_ARRAY_ATTR(extra_acceleration, extra_acceleration, + SetExtraAcceleration); + BA_FLOAT_ATTR(gravity_scale, gravity_scale, set_gravity_scale); + BA_STRING_ATTR(body, GetBody, SetBody); +#undef BA_NODE_TYPE_CLASS + + explicit PropNodeType(const char* sub_type_name = nullptr, + NodeCreateFunc* sub_type_create = nullptr) + : NodeType(sub_type_name ? sub_type_name : "prop", + sub_type_create ? sub_type_create : CreateProp), + is_area_of_interest(this), + reflection_scale(this), + reflection(this), + color_texture(this), + model(this), + light_model(this), + sticky(this), + shadow_size(this), + stick_to_owner(this), + model_scale(this), + flashing(this), + owner(this), + materials(this), + velocity(this), + position(this), + density(this), + damping(this), + max_speed(this), + body_scale(this), + body(this), + extra_acceleration(this), + gravity_scale(this) {} +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_PROP_NODE_H_ diff --git a/src/ballistica/scene/node/region_node.cc b/src/ballistica/scene/node/region_node.cc new file mode 100644 index 00000000..a6663908 --- /dev/null +++ b/src/ballistica/scene/node/region_node.cc @@ -0,0 +1,106 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/region_node.h" + +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class RegionNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS RegionNode + BA_NODE_CREATE_CALL(CreateRegion); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ARRAY_ATTR(scale, scale, SetScale); + BA_MATERIAL_ARRAY_ATTR(materials, GetMaterials, SetMaterials); + BA_STRING_ATTR(type, region_type, SetRegionType); +#undef BA_NODE_TYPE_CLASS + + RegionNodeType() + : NodeType("region", CreateRegion), + position(this), + scale(this), + materials(this), + type(this) {} +}; + +static NodeType* node_type{}; + +auto RegionNode::InitType() -> NodeType* { + node_type = new RegionNodeType(); + return node_type; +} + +RegionNode::RegionNode(Scene* scene) + : Node(scene, node_type), part_(this, false) {} + +void RegionNode::Draw(FrameDef* frame_def) { + if (g_graphics_server->renderer()->debug_draw_mode()) { + // if (frame_def->renderer()->debug_draw_mode()) { + if (body_.exists()) { + body_->Draw(frame_def->beauty_pass(), false); + } + } +} + +void RegionNode::SetRegionType(const std::string& val) { + if (val == region_type_) { + return; + } + region_type_ = val; + body_.Clear(); // will be recreated next step +} + +auto RegionNode::GetMaterials() const -> std::vector { + return part_.GetMaterials(); +} + +void RegionNode::SetMaterials(const std::vector& vals) { + part_.SetMaterials(vals); +} + +void RegionNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for position"); + } + position_ = vals; + size_or_pos_dirty_ = true; +} + +void RegionNode::SetScale(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for scale"); + } + scale_ = vals; + size_or_pos_dirty_ = true; +} + +void RegionNode::Step() { + // create our body if we have none + if (!body_.exists()) { + if (region_type_ == "sphere") { + body_ = Object::New( + 0, &part_, RigidBody::Type::kGeomOnly, RigidBody::Shape::kSphere, + RigidBody::kCollideRegion, RigidBody::kCollideActive); + } else { + if (region_type_ != "box") { + BA_LOG_ONCE("got unexpected region type: " + region_type_); + } + body_ = Object::New( + 0, &part_, RigidBody::Type::kGeomOnly, RigidBody::Shape::kBox, + RigidBody::kCollideRegion, RigidBody::kCollideActive); + } + size_or_pos_dirty_ = true; // always needs updating after create + } + if (size_or_pos_dirty_) { + dGeomSetPosition(body_->geom(), position_[0], position_[1], position_[2]); + body_->SetDimensions(scale_[0], scale_[1], scale_[2]); + size_or_pos_dirty_ = false; + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/region_node.h b/src/ballistica/scene/node/region_node.h new file mode 100644 index 00000000..2f53b53e --- /dev/null +++ b/src/ballistica/scene/node/region_node.h @@ -0,0 +1,41 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_REGION_NODE_H_ +#define BALLISTICA_SCENE_NODE_REGION_NODE_H_ + +#include +#include + +#include "ballistica/dynamics/part.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// A region node - used to detect if an object is in a certain area +class RegionNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit RegionNode(Scene* scene); + void Draw(FrameDef* frame_def) override; + void Step() override; + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& vals); + auto scale() const -> std::vector { return scale_; } + void SetScale(const std::vector& vals); + auto GetMaterials() const -> std::vector; + void SetMaterials(const std::vector& vals); + auto region_type() const -> std::string { return region_type_; } + void SetRegionType(const std::string& val); + + private: + bool size_or_pos_dirty_ = true; + Part part_; + std::vector position_ = {0.0f, 0.0f, 0.0f}; + std::vector scale_ = {1.0f, 1.0f, 1.0f}; + std::string region_type_ = "box"; + Object::Ref body_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_REGION_NODE_H_ diff --git a/src/ballistica/scene/node/scorch_node.cc b/src/ballistica/scene/node/scorch_node.cc new file mode 100644 index 00000000..2b4d995b --- /dev/null +++ b/src/ballistica/scene/node/scorch_node.cc @@ -0,0 +1,80 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/scorch_node.h" + +#include + +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class ScorchNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS ScorchNode + BA_NODE_CREATE_CALL(CreateScorch); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ATTR(presence, presence, set_presence); + BA_FLOAT_ATTR(size, size, set_size); + BA_BOOL_ATTR(big, big, set_big); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); +#undef BA_NODE_TYPE_CLASS + ScorchNodeType() + : NodeType("scorch", CreateScorch), + position(this), + presence(this), + size(this), + big(this), + color(this) {} +}; + +static NodeType* node_type{}; + +auto ScorchNode::InitType() -> NodeType* { + node_type = new ScorchNodeType(); + return node_type; +} + +ScorchNode::ScorchNode(Scene* scene) : Node(scene, node_type) { + rand_size_[0] = 0.7f + RandomFloat() * 0.6f; + rand_size_[1] = 0.7f + RandomFloat() * 0.6f; + rand_size_[2] = 0.7f + RandomFloat() * 0.6f; +} + +ScorchNode::~ScorchNode() = default; + +void ScorchNode::SetColor(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of length 3 for color"); + color_ = vals; +} + +void ScorchNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of length 3 for position"); + position_ = vals; +} + +void ScorchNode::Draw(FrameDef* frame_def) { + float o = presence_; + // modulate opacity by local shadow density + o *= g_graphics->GetShadowDensity(position_[0], position_[1], position_[2]); + SimpleComponent c(frame_def->light_shadow_pass()); + c.SetTransparent(true); + c.SetColor(color_[0], color_[1], color_[2], o * 0.35f); + c.SetTexture(g_media->GetTexture(big_ ? SystemTextureID::kScorchBig + : SystemTextureID::kScorch)); + c.PushTransform(); + c.Translate(position_[0], position_[1], position_[2]); + c.Scale(o * size_ * rand_size_[0], o * size_ * rand_size_[1], + o * size_ * rand_size_[2]); + c.Rotate(Utils::precalc_rands_1[id() % kPrecalcRandsCount] * 360.0f, 0, 1, 0); + c.DrawModel(g_media->GetModel(SystemModelID::kScorch)); + c.PopTransform(); + c.Submit(); +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/scorch_node.h b/src/ballistica/scene/node/scorch_node.h new file mode 100644 index 00000000..3859d60f --- /dev/null +++ b/src/ballistica/scene/node/scorch_node.h @@ -0,0 +1,40 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_SCORCH_NODE_H_ +#define BALLISTICA_SCENE_NODE_SCORCH_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class ScorchNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit ScorchNode(Scene* scene); + ~ScorchNode() override; + void Draw(FrameDef* frame_def) override; + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& vals); + auto presence() const -> float { return presence_; } + void set_presence(float val) { presence_ = val; } + auto size() const -> float { return size_; } + void set_size(float val) { size_ = val; } + auto big() const -> bool { return big_; } + void set_big(bool val) { big_ = val; } + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& vals); + + private: + std::vector position_{0.0f, 0.0f, 0.0f}; + std::vector color_{0.07f, 0.03f, 0.0f}; + float presence_{1.0f}; + float size_{1.0f}; + bool big_{}; + float rand_size_[3]{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_SCORCH_NODE_H_ diff --git a/src/ballistica/scene/node/session_globals_node.cc b/src/ballistica/scene/node/session_globals_node.cc new file mode 100644 index 00000000..aa21c49d --- /dev/null +++ b/src/ballistica/scene/node/session_globals_node.cc @@ -0,0 +1,50 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/session_globals_node.h" + +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class SessionGlobalsNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS SessionGlobalsNode + BA_NODE_CREATE_CALL(CreateSessionGlobals); + BA_INT64_ATTR_READONLY(real_time, GetRealTime); + BA_INT64_ATTR_READONLY(time, GetTime); + BA_INT64_ATTR_READONLY(step, GetStep); +#undef BA_NODE_TYPE_CLASS + SessionGlobalsNodeType() + : NodeType("sessionglobals", CreateSessionGlobals), + real_time(this), + time(this), + step(this) {} +}; + +static NodeType* node_type{}; + +auto SessionGlobalsNode::InitType() -> NodeType* { + node_type = new SessionGlobalsNodeType(); + return node_type; +} + +SessionGlobalsNode::SessionGlobalsNode(Scene* scene) : Node(scene, node_type) { + // We don't expose this as an attr, but we tell our scene to display stuff in + // the fixed overlay position by default when doing vr. + this->scene()->set_use_fixed_vr_overlay(true); +} + +SessionGlobalsNode::~SessionGlobalsNode() = default; + +auto SessionGlobalsNode::GetRealTime() -> millisecs_t { + // Pull this from our scene so we return consistent values throughout a step. + return scene()->last_step_real_time(); +} + +auto SessionGlobalsNode::GetTime() -> millisecs_t { return scene()->time(); } + +auto SessionGlobalsNode::GetStep() -> int64_t { return scene()->stepnum(); } + +} // namespace ballistica diff --git a/src/ballistica/scene/node/session_globals_node.h b/src/ballistica/scene/node/session_globals_node.h new file mode 100644 index 00000000..4ed2c303 --- /dev/null +++ b/src/ballistica/scene/node/session_globals_node.h @@ -0,0 +1,22 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_SESSION_GLOBALS_NODE_H_ +#define BALLISTICA_SCENE_NODE_SESSION_GLOBALS_NODE_H_ + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class SessionGlobalsNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit SessionGlobalsNode(Scene* scene); + ~SessionGlobalsNode() override; + auto GetRealTime() -> millisecs_t; + auto GetTime() -> millisecs_t; + auto GetStep() -> int64_t; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_SESSION_GLOBALS_NODE_H_ diff --git a/src/ballistica/scene/node/shield_node.cc b/src/ballistica/scene/node/shield_node.cc new file mode 100644 index 00000000..11788c24 --- /dev/null +++ b/src/ballistica/scene/node/shield_node.cc @@ -0,0 +1,287 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/shield_node.h" + +#include +#include + +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/post_process_component.h" +#include "ballistica/graphics/component/shield_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class ShieldNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS ShieldNode + BA_NODE_CREATE_CALL(CreateShield); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ATTR(radius, radius, set_radius); + BA_FLOAT_ATTR(hurt, hurt, SetHurt); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_BOOL_ATTR(always_show_health_bar, always_show_health_bar, + set_always_show_health_bar); +#undef BA_NODE_TYPE_CLASS + + ShieldNodeType() + : NodeType("shield", CreateShield), + position(this), + radius(this), + hurt(this), + color(this), + always_show_health_bar(this) {} +}; +static NodeType* node_type{}; + +auto ShieldNode::InitType() -> NodeType* { + node_type = new ShieldNodeType(); + return node_type; +} + +ShieldNode::ShieldNode(Scene* scene) + : Node(scene, node_type) +#if !BA_HEADLESS_BUILD + , + shadow_(0.2f) +#endif // !BA_HEADLESS_BUILD +{ + last_hurt_change_time_ = scene->time(); +} + +ShieldNode::~ShieldNode() = default; + +void ShieldNode::SetColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for color"); + } + color_ = vals; +} + +void ShieldNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of length 3 for position"); + } + position_ = vals; +} + +void ShieldNode::SetHurt(float val) { + float old_hurt = hurt_; + hurt_ = val; + if (hurt_ != old_hurt) { + // Only flash if we change by a significant amount + // (avoids flashing during regular drain). + if (std::abs(hurt_ - old_hurt) > 0.05f) { + flash_ = 1.0f; + last_hurt_change_time_ = scene()->time(); + } + } +} + +void ShieldNode::Step() { + float smoothing = 0.94f; + d_r_scale_ = smoothing * d_r_scale_ + (1.0f - smoothing) * (1.0f - r_scale_); + r_scale_ += d_r_scale_; + d_r_scale_ *= 0.92f; + + // Move our smoothed hurt value a short time after we get hit. + if (scene()->time() - last_hurt_change_time_ > 400) { + if (hurt_smoothed_ < hurt_) { + hurt_smoothed_ = std::min(hurt_, hurt_smoothed_ + 0.03f); + } else { + hurt_smoothed_ = std::max(hurt_, hurt_smoothed_ - 0.03f); + } + } + + flash_ -= 0.04f; + if (flash_ < 0.0f) { + flash_ = 0.0f; + } + hurt_rand_ = RandomFloat(); + rot_count_ = (rot_count_ + 1) % 256; + +#if !BA_HEADLESS_BUILD + shadow_.SetPosition(Vector3f(position_[0], position_[1], position_[2])); +#endif // !BA_HEADLESS_BUILD +} + +void ShieldNode::Draw(FrameDef* frame_def) { +#if !BA_HEADLESS_BUILD + + { + float o = (1.0f - hurt_) * 1.0f + + hurt_ * (1.0f * hurt_rand_ * hurt_rand_ * hurt_rand_); + float s_density, s_scale; + shadow_.GetValues(&s_scale, &s_density); + float brightness = s_density * 0.8f * o; + if (flash_ > 0.0f) { + brightness *= (1.0f + 6.0f * flash_); + } + float rs = (0.6f + hurt_rand_ * 0.05f) * radius_ * s_scale * r_scale_; + + // draw our light on both terrain and objects + g_graphics->DrawBlotchSoft(Vector3f(&position_[0]), 3.4f * rs, + color_[0] * brightness, color_[1] * brightness, + color_[2] * brightness, 0.0f); + // draw our light on both terrain and objects + g_graphics->DrawBlotchSoftObj( + Vector3f(&position_[0]), 3.4f * rs, color_[0] * brightness * 0.4f, + color_[1] * brightness * 0.4f, color_[2] * brightness * 0.4f, 0.0f); + } + + // Life bar. + { + uint32_t fade_time = 2000; + + millisecs_t since_last_hurt_change = + scene()->time() - last_hurt_change_time_; + + if (since_last_hurt_change < fade_time || always_show_health_bar_) { + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.PushTransform(); + float o = 1.0f - static_cast(since_last_hurt_change) / fade_time; + if (always_show_health_bar_) { + o = std::max(o, 0.5f); + } + o *= o; + float p_left, p_right; + if (hurt_ < hurt_smoothed_) { + p_left = 1.0f - hurt_smoothed_; + p_right = 1.0f - hurt_; + } else { + p_right = 1.0f - hurt_smoothed_; + p_left = 1.0f - hurt_; + } + + // For the first moment start p_left at p_right so they can see a glimpse + // of green before it goes away. + if (since_last_hurt_change < 100) { + p_left += + (p_right - p_left) + * (1.0f - static_cast(since_last_hurt_change) / 100.0f); + } + c.Translate(position_[0] - 0.25f, position_[1] + 1.25f, position_[2]); + c.Scale(0.5f, 0.5f, 0.5f); + float height = 0.1f; + float half_height = height * 0.5f; + c.SetColor(0, 0, 0.3f, 0.3f * o); + c.PushTransform(); + c.Translate(0.5f, half_height); + c.Scale(1.1f, height + 0.1f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.SetColor(0.4f * o, 0.4f * o, 0.8f * o, 0.0f * o); + c.PushTransform(); + c.Translate(p_left * 0.5f, half_height); + c.Scale(p_left, height); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.SetColor(1.0f * o, 1.0f * o, 1.0f * o, 0.0f); + c.PushTransform(); + c.Translate((p_left + p_right) * 0.5f, half_height); + c.Scale(p_right - p_left, height); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.SetColor(0.1f * o, 0.1f * o, 0.2f * o, 0.4f * o); + c.PushTransform(); + c.Translate((p_right + 1.0f) * 0.5f, half_height); + c.Scale(1.0f - p_right, height); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.PopTransform(); + c.Submit(); + } + } + + // main bubble + float r = hurt_rand_; + float o = (1.0f - hurt_) * 1.0f + hurt_ * (1.0f * r * r * r); + o *= 0.3f; + float cx, cy, cz; + g_graphics->camera()->get_position(&cx, &cy, &cz); + float col[4]; + col[0] = color_[0] * o; + col[1] = color_[1] * o; + col[2] = color_[2] * o; + float distort = 0.05f + RandomFloat() * 0.06f; + if (flash_ > 0.0f) { + distort += 0.9f * (RandomFloat() - 0.4f) * flash_; + col[0] += flash_; + col[1] += flash_; + col[2] += flash_; + } + + { + ObjectComponent c(frame_def->beauty_pass()); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.SetLightShadow(LightShadowType::kNone); + c.SetReflection(ReflectionType::kSharp); + c.SetReflectionScale(0.34f * o, 0.34f * o, 0.34f * o); + c.SetTexture(g_media->GetTexture(SystemTextureID::kShield)); + c.SetColor(col[0], col[1], col[2], 0.13f * o); + c.PushTransform(); + Vector3f to_cam = + Vector3f(cx - position_[0], cy - position_[1], cz - position_[2]) + .Normalized(); + Matrix44f m = + Matrix44fTranslate(position_[0], position_[1] + 0.1f, position_[2]); + Vector3f right = Vector3f::Cross(to_cam, kVector3fY).Normalized(); + Vector3f up = Vector3f::Cross(right, to_cam).Normalized(); + Matrix44f om = Matrix44fOrient(right, to_cam, up); + c.MultMatrix((om * m).m); + float s = radius_ * 0.53f; + c.Scale(s, s, s); + c.Rotate(Utils::precalc_rands_1[rot_count_ % kPrecalcRandsCount] * 360, 0, + 1, 0); + float r2 = + r_scale_ + * (0.97f + + 0.05f * Utils::precalc_rands_2[rot_count_ % kPrecalcRandsCount]); + c.Scale(r2, r2, r2); + c.DrawModel(g_media->GetModel(SystemModelID::kShield), + kModelDrawFlagNoReflection); + c.PopTransform(); + c.Submit(); + + // Nifty intersection effects in fancy graphics mode. + if (frame_def->has_depth_texture()) { + ShieldComponent c2(frame_def->overlay_3d_pass()); + c2.PushTransform(); + c2.MultMatrix((om * m).m); + c2.Scale(s, s, s); + c2.Rotate(Utils::precalc_rands_1[rot_count_ % kPrecalcRandsCount] * 360, + 0, 1, 0); + c2.Scale(r2, r2, r2); + c2.DrawModel(g_media->GetModel(SystemModelID::kShield)); + c2.PopTransform(); + c2.Submit(); + } + if (frame_def->has_depth_texture()) { + PostProcessComponent c2(frame_def->blit_pass()); + c2.setNormalDistort(distort); + c2.PushTransform(); + c2.MultMatrix((om * m).m); + c2.Scale(s, s, s); + c2.Rotate(Utils::precalc_rands_1[rot_count_ % kPrecalcRandsCount] * 360, + 0, 1, 0); + float sc = r2 * 1.1f; + c2.Scale(sc, sc, sc); + c2.DrawModel(g_media->GetModel(SystemModelID::kShield)); + c2.PopTransform(); + c2.Submit(); + } + } +#endif // BA_HEADLESS_BUILD +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/shield_node.h b/src/ballistica/scene/node/shield_node.h new file mode 100644 index 00000000..44c317da --- /dev/null +++ b/src/ballistica/scene/node/shield_node.h @@ -0,0 +1,53 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_SHIELD_NODE_H_ +#define BALLISTICA_SCENE_NODE_SHIELD_NODE_H_ + +#include + +#include "ballistica/dynamics/bg/bg_dynamics_shadow.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class ShieldNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit ShieldNode(Scene* scene); + ~ShieldNode() override; + void Draw(FrameDef* frame_def) override; + void Step() override; + auto position() const -> std::vector { return position_; } + void SetPosition(const std::vector& vals); + auto radius() const -> float { return radius_; } + void set_radius(float val) { radius_ = val; } + auto hurt() const -> float { return hurt_; } + void SetHurt(float val); + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& vals); + auto always_show_health_bar() const -> bool { + return always_show_health_bar_; + } + void set_always_show_health_bar(bool val) { always_show_health_bar_ = val; } + + private: +#if !BA_HEADLESS_BUILD + BGDynamicsShadow shadow_; +#endif // BA_HEADLESS_BUILD + bool always_show_health_bar_ = false; + float hurt_smoothed_ = 1.0f; + millisecs_t last_hurt_change_time_ = 0; + float d_r_scale_ = 0.0f; + float r_scale_ = 0.0f; + std::vector position_ = {0.0f, 0.0f, 0.0f}; + std::vector color_ = {0.6f, 0.4f, 0.1f}; + float radius_ = 1.0f; + float hurt_ = 0.0f; + float flash_ = 0.0f; + float hurt_rand_ = 0.0f; + int rot_count_ = 0; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_SHIELD_NODE_H_ diff --git a/src/ballistica/scene/node/sound_node.cc b/src/ballistica/scene/node/sound_node.cc new file mode 100644 index 00000000..fe3f021b --- /dev/null +++ b/src/ballistica/scene/node/sound_node.cc @@ -0,0 +1,145 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/sound_node.h" + +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_source.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class SoundNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS SoundNode + BA_NODE_CREATE_CALL(CreateSound); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_FLOAT_ATTR(volume, volume, SetVolume); + BA_BOOL_ATTR(positional, positional, SetPositional); + BA_BOOL_ATTR(music, music, SetMusic); + BA_BOOL_ATTR(loop, loop, SetLoop); + BA_SOUND_ATTR(sound, sound, SetSound); +#undef BA_NODE_TYPE_CLASS + SoundNodeType() + : NodeType("sound", CreateSound), + position(this), + volume(this), + positional(this), + music(this), + loop(this), + sound(this) {} +}; +static NodeType* node_type{}; + +auto SoundNode::InitType() -> NodeType* { + node_type = new SoundNodeType(); + return node_type; +} + +SoundNode::SoundNode(Scene* scene) : Node(scene, node_type) {} + +SoundNode::~SoundNode() { + if (playing_) { + g_audio->PushSourceStopSoundCall(play_id_); + } +} + +void SoundNode::SetPosition(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of size 3 for position"); + position_ = vals; + + // We don't actually update here; we just mark our position as dirty + // and then update it every now and then. + position_dirty_ = true; +} + +void SoundNode::SetVolume(float val) { + if (val == volume_) { + return; + } + volume_ = val; + + // FIXME we could probably update this in an infrequent manner in case its + // being driven by another attr. + if (playing_) { + AudioSource* s = g_audio->SourceBeginExisting(play_id_, 106); + if (s) { + s->SetGain(volume_); + s->End(); + } + } +} + +void SoundNode::SetLoop(bool val) { + if (loop_ == val) return; + loop_ = val; + + // We don't actually update looping on a playing sound. + if (playing_) + BA_LOG_ONCE("Error: can't set 'loop' attr on already-playing sound."); +} + +void SoundNode::SetSound(Sound* s) { + if (s == sound_.get()) return; + sound_ = s; + + // We'll start playing in our next Step; this allows + // time for other setAttrs to go through first such as looping. + // (which can't happen after we start playing) +} + +void SoundNode::SetPositional(bool val) { + if (val == positional_) return; + positional_ = val; + if (playing_) + BA_LOG_ONCE("Error: can't set 'positional' attr on already-playing sound"); +} + +void SoundNode::SetMusic(bool val) { + if (val == music_) return; + music_ = val; + if (playing_) { + AudioSource* s = g_audio->SourceBeginExisting(play_id_, 104); + if (s) { + s->SetIsMusic(music_); + s->End(); + } + } +} + +void SoundNode::Step() { + // If we want to start playing, do so. + if (!playing_ && sound_.exists()) { + AudioSource* s = g_audio->SourceBeginNew(); + if (s) { + assert(position_.size() == 3); + s->SetPosition(position_[0], position_[1], position_[2]); + s->SetLooping(loop_); + s->SetPositional(positional_); + s->SetGain(volume_); + s->SetIsMusic(music_); + play_id_ = s->Play(sound_->GetSoundData()); + playing_ = true; + s->End(); + } + } + if (positional_ && position_dirty_ && playing_) { + millisecs_t t = GetRealTime(); + if (t - last_position_update_time_ > 100) { + AudioSource* s = g_audio->SourceBeginExisting(play_id_, 107); + if (s) { + s->SetPosition(position_[0], position_[1], position_[2]); + s->End(); + } + last_position_update_time_ = t; + position_dirty_ = false; + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/sound_node.h b/src/ballistica/scene/node/sound_node.h new file mode 100644 index 00000000..7921415e --- /dev/null +++ b/src/ballistica/scene/node/sound_node.h @@ -0,0 +1,46 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_SOUND_NODE_H_ +#define BALLISTICA_SCENE_NODE_SOUND_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class SoundNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit SoundNode(Scene* scene); + ~SoundNode() override; + void Step() override; + auto position() const -> const std::vector& { return position_; } + void SetPosition(const std::vector& vals); + auto volume() const -> float { return volume_; } + void SetVolume(float val); + auto positional() const -> bool { return positional_; } + void SetPositional(bool val); + auto music() const -> bool { return music_; } + void SetMusic(bool val); + auto loop() const -> bool { return loop_; } + void SetLoop(bool val); + auto sound() const -> Sound* { return sound_.get(); } + void SetSound(Sound* s); + + private: + Object::Ref sound_; + millisecs_t last_position_update_time_{}; + std::vector position_{0.0f, 0.0f, 0.0f}; + float volume_{1.0f}; + bool positional_{true}; + bool position_dirty_{true}; + bool music_{}; + bool loop_{true}; + uint32_t play_id_{}; + bool playing_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_SOUND_NODE_H_ diff --git a/src/ballistica/scene/node/spaz_node.cc b/src/ballistica/scene/node/spaz_node.cc new file mode 100644 index 00000000..e4eab570 --- /dev/null +++ b/src/ballistica/scene/node/spaz_node.cc @@ -0,0 +1,6817 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/spaz_node.h" + +#include +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/audio/audio_source.h" +#include "ballistica/dynamics/bg/bg_dynamics_shadow.h" +#include "ballistica/dynamics/collision.h" +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/material/material_action.h" +#include "ballistica/game/player.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/area_of_interest.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/component/post_process_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/graphics_server.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/math/matrix44f.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" +#include "ode/ode_collision_util.h" +#include "ode/ode_joint.h" + +namespace ballistica { + +// pull a random pointer from a ref-vector +template +auto GetRandomMedia(const std::vector >& list) -> T* { + if (list.empty()) return nullptr; + return list[rand() % list.size()].get(); // NOLINT yes I know; rand bad. +} + +const float kSantaEyeScale = 0.9f; +const float kSantaEyeTranslate = 0.03f; + +const float kRunJointLinearStiffness = 80.0f; +const float kRunJointLinearDamping = 2.0f; +const float kRunJointAngularStiffness = 0.2f; +const float kRunJointAngularDamping = 0.002f; + +const float kRollerBallLinearStiffness = 1000.0f; +const float kRollerBallLinearDamping = 0.2f; + +const float kPelvisDensity = 5.0f; +const float kPelvisLinearStiffness = 300.0f; +const float kPelvisLinearDamping = 20.0f; +const float kPelvisAngularStiffness = 1.5f; +const float kPelvisAngularDamping = 0.06f; + +const float kUpperLegDensity = 2.0f; +const float kUpperLegLinearStiffness = 300.0f; +const float kUpperLegLinearDamping = 5.0f; +const float kUpperLegAngularStiffness = 0.12f; +const float kUpperLegAngularDamping = 0.004f; +const float kUpperLegCollideStiffness = 100.0f; +const float kUpperLegCollideDamping = 100.0f; + +const float kLowerLegDensity = 2.0f; +const float kLowerLegLinearStiffness = 200.0f; +const float kLowerLegLinearDamping = 5.0f; +const float kLowerLegAngularStiffness = 0.12f; +const float kLowerLegAngularDamping = 0.004f; +const float kLowerLegCollideStiffness = 100.0f; +const float kLowerLegCollideDamping = 100.0f; + +const float kToesDensity = 0.5f; +const float kToesLinearStiffness = 50.0f; +const float kToesLinearDamping = 1.0f; +const float kToesAngularStiffness = 0.015f; +const float kToesAngularDamping = 0.0005f; +const float kToesCollideStiffness = 10.0f; +const float kToesCollideDamping = 10.0f; + +const float kUpperArmDensity = 2.0f; + +const float kUpperArmLinearStiffness = 30.0f; +const float kUpperArmLinearDamping = 1.2f; +const float kUpperArmAngularStiffness = 0.08f; +const float kUpperArmAngularDamping = 0.008f; + +const float kLowerArmDensity = 2.0f; +const float kLowerArmLinearStiffness = 80.0f; +const float kLowerArmLinearDamping = 1.0f; +const float kLowerArmAngularStiffness = 0.08f; +const float kLowerArmAngularDamping = 0.008f; + +const float kHairFrontLeftLinearStiffness = 0.2f; +const float kHairFrontLeftLinearDamping = 0.01f; +const float kHairFrontLeftAngularStiffness = 0.00025f; +const float kHairFrontLeftAngularDamping = 0.000001f; + +const float kHairFrontRightLinearStiffness = 0.2f; +const float kHairFrontRightLinearDamping = 0.01f; +const float kHairFrontRightAngularStiffness = 0.00025f; +const float kHairFrontRightAngularDamping = 0.000001f; + +const float kHairPonytailTopLinearStiffness = 1.0f; +const float kHairPonytailTopLinearDamping = 0.03f; +const float kHairPonytailTopAngularStiffness = 0.0015f; +const float kHairPonytailTopAngularDamping = 0.000003f; + +const float kHairPonytailBottomLinearStiffness = 0.4f; +const float kHairPonytailBottomLinearDamping = 0.02f; +const float kHairPonytailBottomAngularStiffness = 0.00025f; +const float kHairPonytailBottomAngularDamping = 0.000001f; + +const int kPunchDuration = 35; +const int kPickupCooldown = 40; + +const float kWingAttachX = 0.3f; +const float kWingAttachY = 0.0f; +const float kWingAttachZ = -0.45f; + +const float kWingAttachFlapX = 0.55f; +const float kWingAttachFlapY = 0.0f; +const float kWingAttachFlapZ = -0.35f; + +enum SpazBodyType { + kHeadBodyID, + kTorsoBodyID, + kPunchBodyID, + kPickupBodyID, + kPelvisBodyID, + kRollerBodyID, + kStandBodyID, + kUpperRightArmBodyID, + kLowerRightArmBodyID, + kUpperLeftArmBodyID, + kLowerLeftArmBodyID, + kUpperRightLegBodyID, + kLowerRightLegBodyID, + kUpperLeftLegBodyID, + kLowerLeftLegBodyID, + kLeftToesBodyID, + kRightToesBodyID, + kHairFrontRightBodyID, + kHairFrontLeftBodyID, + kHairPonyTailTopBodyID, + kHairPonyTailBottomBodyID +}; + +static auto AngleBetween2DVectors(dReal x1, dReal y1, dReal x2, dReal y2) + -> dReal { + dReal x1_norm, y1_norm, x2_norm, y2_norm; + dReal len1, len2; + len1 = sqrtf(x1 * x1 + y1 * y1); + len2 = sqrtf(x2 * x2 + y2 * y2); + x1_norm = x1 / len1; + y1_norm = y1 / len1; + x2_norm = x2 / len2; + y2_norm = y2 / len2; + dReal angle = atanf(y1_norm / x1_norm); + if (x1_norm < 0) { + if (y1_norm > 0.0f) { + angle = angle + 3.141592f; + } else { + angle = angle - 3.141592f; + } + } + dReal angle2 = atanf(y2_norm / x2_norm); + if (x2_norm < 0) { + if (y2_norm > 0.0f) { + angle2 = angle2 + 3.141592f; + } else { + angle2 = angle2 - 3.141592f; + } + } + dReal angle_diff = angle2 - angle; + if (angle_diff > 3.141592f) { + angle_diff -= 3.141592f * 2.0f; + } else if (angle_diff < -3.141592f) { + angle_diff += 3.141592f * 2.0f; + } + return angle_diff; +} + +static void RotationFrom2Axes(dMatrix3 r, dReal x_forward, dReal y_forward, + dReal z_forward, dReal x_up, dReal y_up, + dReal z_up) { + Vector3f forward(x_forward, y_forward, z_forward); + Vector3f up = Vector3f(x_up, y_up, z_up).Normalized(); + Vector3f side = Vector3f(Vector3f::Cross(forward, up)).Normalized(); + Vector3f forward2 = Vector3f::Cross(up, side); + r[0] = forward2.x; + r[4] = forward2.y; + r[8] = forward2.z; + r[1] = up.x; + r[5] = up.y; + r[9] = up.z; + r[2] = side.x; + r[6] = side.y; + r[10] = side.z; +} + +static void CalcERPCFM(float stiffness, float damping, float* erp, float* cfm) { + if (stiffness <= 0.0f && damping <= 0.0f) { + (*erp) = 0.0f; + // (*cfm) = dInfinity; // doesn't seem to be happy... + (*cfm) = 9999999999.0f; + } else { + (*erp) = (kGameStepSeconds * stiffness) + / ((kGameStepSeconds * stiffness) + damping); + (*cfm) = 1.0f / ((kGameStepSeconds * stiffness) + damping); + } +} + +struct JointFixedEF : public dxJoint { + dQuaternion qrel; // relative rotation body1 -> body2 + dVector3 anchor1; // anchor w.r.t first body + dVector3 anchor2; // anchor w.r.t second body + float linearStiffness; + float linearDamping; + float angularStiffness; + float angularDamping; + bool linearEnabled; + bool angularEnabled; +}; + +static void _fixedInit(JointFixedEF* j) { + dSetZero(j->qrel, 4); + dSetZero(j->anchor1, 3); + dSetZero(j->anchor2, 3); + j->linearStiffness = 0.0f; + j->linearDamping = 0.0f; + j->angularStiffness = 0.0f; + j->angularDamping = 0.0f; + + // testing + j->linearEnabled = true; + j->angularEnabled = true; +} + +static void _SetBall(JointFixedEF* joint, dxJoint::Info2* info, + dVector3 anchor1, dVector3 anchor2) { + assert(joint->node[1].body); + + // anchor points in global coordinates with respect to body PORs. + dVector3 a1, a2; + + int s = info->rowskip; + + // set jacobian + info->J1l[0] = 1; + info->J1l[s + 1] = 1; + info->J1l[2 * s + 2] = 1; + dMULTIPLY0_331(a1, joint->node[0].body->R, anchor1); + dCROSSMAT(info->J1a, a1, s, -, +); + info->J2l[0] = -1; + info->J2l[s + 1] = -1; + info->J2l[2 * s + 2] = -1; + dMULTIPLY0_331(a2, joint->node[1].body->R, anchor2); + dCROSSMAT(info->J2a, a2, s, +, -); + + // set right hand side + dReal k = info->fps * info->erp; + for (int j = 0; j < 3; j++) { + info->c[j] = k + * (a2[j] + joint->node[1].body->pos[j] - a1[j] + - joint->node[0].body->pos[j]); + } +} + +// FIXME this is duplicated a few times... +static void _SetFixedOrientation(JointFixedEF* joint, dxJoint::Info2* info, + dQuaternion qrel, int start_row) { + assert(joint->node[1].body); // we assume we're connected to 2 bodies.. + + int s = info->rowskip; + int start_index = start_row * s; + + // 3 rows to make body rotations equal + info->J1a[start_index] = 1; + info->J1a[start_index + s + 1] = 1; + info->J1a[start_index + s * 2 + 2] = 1; + info->J2a[start_index] = -1; + info->J2a[start_index + s + 1] = -1; + info->J2a[start_index + s * 2 + 2] = -1; + + // compute the right hand side. the first three elements will result in + // relative angular velocity of the two bodies - this is set to bring them + // back into alignment. the correcting angular velocity is + // |angular_velocity| = angle/time = erp*theta / stepsize + // = (erp*fps) * theta + // angular_velocity = |angular_velocity| * u + // = (erp*fps) * theta * u + // where rotation along unit length axis u by theta brings body 2's frame + // to qrel with respect to body 1's frame. using a small angle approximation + // for sin(), this gives + // angular_velocity = (erp*fps) * 2 * v + // where the quaternion of the relative rotation between the two bodies is + // q = [cos(theta/2) sin(theta/2)*u] = [s v] + + // get qerr = relative rotation (rotation error) between two bodies + dQuaternion qerr, e; + dQuaternion qq; + dQMultiply1(qq, joint->node[0].body->q, joint->node[1].body->q); + dQMultiply2(qerr, qq, qrel); + if (qerr[0] < 0) { + qerr[1] = -qerr[1]; // adjust sign of qerr to make theta small + qerr[2] = -qerr[2]; + qerr[3] = -qerr[3]; + } + dMULTIPLY0_331(e, joint->node[0].body->R, qerr + 1); // @@@ bad SIMD padding! + dReal k; + + k = info->fps * info->erp; + info->c[start_row] = 2 * k * e[0]; + info->c[start_row + 1] = 2 * k * e[1]; + info->c[start_row + 2] = 2 * k * e[2]; +} + +static void _fixedGetInfo1(JointFixedEF* j, dxJoint::Info1* info) { + info->m = 0; + info->nub = 0; + if (j->linearEnabled + && (j->linearStiffness > 0.0f || j->linearDamping > 0.0f)) { + info->m += 3; + info->nub += 3; + } + if (j->angularEnabled + && (j->angularStiffness > 0.0f || j->angularDamping > 0.0f)) { + info->m += 3; + info->nub += 3; + } +} + +static void _fixedGetInfo2(JointFixedEF* joint, dxJoint::Info2* info) { + assert(joint + && (joint->linearStiffness > 0.0f || joint->linearDamping > 0.0f + || joint->angularStiffness > 0.0f + || joint->angularDamping > 0.0f)); + dReal orig_erp = info->erp; + bool do_linear = + (joint->linearEnabled + && (joint->linearStiffness > 0.0f || joint->linearDamping > 0.0f)); + bool do_angular = + (joint->angularEnabled + && (joint->angularStiffness > 0.0f || joint->angularDamping > 0.0f)); + int offs = 0; + // linear component... + if (do_linear) { + float linear_erp = 0; + float linear_cfm = 0; + CalcERPCFM(joint->linearStiffness, joint->linearDamping, &linear_erp, + &linear_cfm); + info->erp = linear_erp; + _SetBall(joint, info, joint->anchor1, joint->anchor2); + info->cfm[0] = linear_cfm; + info->cfm[1] = linear_cfm; + info->cfm[2] = linear_cfm; + offs += 3; + } + // angular component... + if (do_angular) { + float angular_erp; + float angular_cfm; + CalcERPCFM(joint->angularStiffness, joint->angularDamping, &angular_erp, + &angular_cfm); + info->erp = angular_erp; + _SetFixedOrientation(joint, info, joint->qrel, offs); + info->cfm[offs] = angular_cfm; + info->cfm[offs + 1] = angular_cfm; + info->cfm[offs + 2] = angular_cfm; + } + info->erp = orig_erp; +} + +dxJoint::Vtable fixed_vtable_ = { + sizeof(JointFixedEF), (dxJoint::init_fn*)_fixedInit, + (dxJoint::getInfo1_fn*)_fixedGetInfo1, + (dxJoint::getInfo2_fn*)_fixedGetInfo2, dJointTypeNone}; + +#if !BA_HEADLESS_BUILD +class SpazNode::FullShadowSet : public Object { + public: + ~FullShadowSet() override = default; + BGDynamicsShadow torso_shadow_; + BGDynamicsShadow head_shadow_; + BGDynamicsShadow pelvis_shadow_; + BGDynamicsShadow lower_left_leg_shadow_; + BGDynamicsShadow lower_right_leg_shadow_; + BGDynamicsShadow upper_left_leg_shadow_; + BGDynamicsShadow upper_right_leg_shadow_; + BGDynamicsShadow lower_left_arm_shadow_; + BGDynamicsShadow lower_right_arm_shadow_; + BGDynamicsShadow upper_left_arm_shadow_; + BGDynamicsShadow upper_right_arm_shadow_; +}; + +class SpazNode::SimpleShadowSet : public Object { + public: + BGDynamicsShadow shadow_; +}; +#endif // !BA_HEADLESS_BUILD + +class SpazNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS SpazNode + BA_NODE_CREATE_CALL(CreateSpaz); + BA_BOOL_ATTR(fly, can_fly, set_can_fly); + BA_BOOL_ATTR(hockey, hockey, set_hockey); + BA_MATERIAL_ARRAY_ATTR(roller_materials, GetRollerMaterials, + SetRollerMaterials); + BA_MATERIAL_ARRAY_ATTR(extras_material, GetExtrasMaterials, + SetExtrasMaterials); + BA_MATERIAL_ARRAY_ATTR(punch_materials, GetPunchMaterials, SetPunchMaterials); + BA_MATERIAL_ARRAY_ATTR(pickup_materials, GetPickupMaterials, + SetPickupMaterials); + BA_MATERIAL_ARRAY_ATTR(materials, GetMaterials, SetMaterials); + BA_FLOAT_ATTR(area_of_interest_radius, area_of_interest_radius, + set_area_of_interest_radius); + BA_STRING_ATTR(name, name, set_name); + BA_STRING_ATTR(counter_text, counter_text, set_counter_text); + BA_TEXTURE_ATTR(mini_billboard_1_texture, mini_billboard_1_texture, + set_mini_billboard_1_texture); + BA_TEXTURE_ATTR(mini_billboard_2_texture, mini_billboard_2_texture, + set_mini_billboard_2_texture); + BA_TEXTURE_ATTR(mini_billboard_3_texture, mini_billboard_3_texture, + set_mini_billboard_3_texture); + BA_INT64_ATTR(mini_billboard_1_start_time, mini_billboard_1_start_time, + set_mini_billboard_1_start_time); + BA_INT64_ATTR(mini_billboard_1_end_time, mini_billboard_1_end_time, + set_mini_billboard_1_end_time); + BA_INT64_ATTR(mini_billboard_2_start_time, mini_billboard_2_start_time, + set_mini_billboard_2_start_time); + BA_INT64_ATTR(mini_billboard_2_end_time, mini_billboard_2_end_time, + set_mini_billboard_2_end_time); + BA_INT64_ATTR(mini_billboard_3_start_time, mini_billboard_3_start_time, + set_mini_billboard_3_start_time); + BA_INT64_ATTR(mini_billboard_3_end_time, mini_billboard_3_end_time, + set_mini_billboard_3_end_time); + BA_TEXTURE_ATTR(billboard_texture, billboard_texture, set_billboard_texture); + BA_FLOAT_ATTR(billboard_opacity, billboard_opacity, set_billboard_opacity); + BA_TEXTURE_ATTR(counter_texture, counter_texture, set_counter_texture); + BA_BOOL_ATTR(invincible, invincible, set_invincible); + BA_FLOAT_ARRAY_ATTR(name_color, name_color, SetNameColor); + BA_FLOAT_ARRAY_ATTR(highlight, highlight, set_highlight); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_FLOAT_ATTR(hurt, hurt, SetHurt); + BA_BOOL_ATTR(boxing_gloves_flashing, boxing_gloves_flashing, + set_boxing_gloves_flashing); + BA_PLAYER_ATTR(source_player, source_player, set_source_player); + BA_BOOL_ATTR(frozen, frozen, SetFrozen); + BA_BOOL_ATTR(boxing_gloves, have_boxing_gloves, SetHaveBoxingGloves); + BA_INT64_ATTR(curse_death_time, curse_death_time, SetCurseDeathTime); + BA_INT_ATTR(shattered, shattered, SetShattered); + BA_BOOL_ATTR(dead, dead, SetDead); + BA_STRING_ATTR(style, style, SetStyle); + BA_FLOAT_ATTR_READONLY(knockout, GetKnockout); + BA_FLOAT_ATTR_READONLY(punch_power, punch_power); + BA_FLOAT_ATTR_READONLY(punch_momentum_angular, GetPunchMomentumAngular); + BA_FLOAT_ARRAY_ATTR_READONLY(punch_momentum_linear, GetPunchMomentumLinear); + BA_FLOAT_ATTR_READONLY(damage, damage_out); + BA_FLOAT_ATTR_READONLY(damage_smoothed, damage_smoothed); + BA_FLOAT_ARRAY_ATTR_READONLY(punch_velocity, GetPunchVelocity); + BA_BOOL_ATTR(is_area_of_interest, is_area_of_interest, SetIsAreaOfInterest); + BA_FLOAT_ARRAY_ATTR_READONLY(velocity, GetVelocity); + BA_FLOAT_ARRAY_ATTR_READONLY(position_forward, GetPositionForward); + BA_FLOAT_ARRAY_ATTR_READONLY(position_center, GetPositionCenter); + BA_FLOAT_ARRAY_ATTR_READONLY(punch_position, GetPunchPosition); + BA_FLOAT_ARRAY_ATTR_READONLY(torso_position, GetTorsoPosition); + BA_FLOAT_ARRAY_ATTR_READONLY(position, GetPosition); + BA_INT_ATTR(hold_body, hold_body, set_hold_body); + BA_NODE_ATTR(hold_node, hold_node, SetHoldNode); + BA_SOUND_ARRAY_ATTR(jump_sounds, GetJumpSounds, SetJumpSounds); + BA_SOUND_ARRAY_ATTR(attack_sounds, GetAttackSounds, SetAttackSounds); + BA_SOUND_ARRAY_ATTR(impact_sounds, GetImpactSounds, SetImpactSounds); + BA_SOUND_ARRAY_ATTR(death_sounds, GetDeathSounds, SetDeathSounds); + BA_SOUND_ARRAY_ATTR(pickup_sounds, GetPickupSounds, SetPickupSounds); + BA_SOUND_ARRAY_ATTR(fall_sounds, GetFallSounds, SetFallSounds); + BA_TEXTURE_ATTR(color_texture, color_texture, set_color_texture); + BA_TEXTURE_ATTR(color_mask_texture, color_mask_texture, + set_color_mask_texture); + BA_MODEL_ATTR(head_model, head_model, set_head_model); + BA_MODEL_ATTR(torso_model, torso_model, set_torso_model); + BA_MODEL_ATTR(pelvis_model, pelvis_model, set_pelvis_model); + BA_MODEL_ATTR(upper_arm_model, upper_arm_model, set_upper_arm_model); + BA_MODEL_ATTR(forearm_model, forearm_model, set_forearm_model); + BA_MODEL_ATTR(hand_model, hand_model, set_hand_model); + BA_MODEL_ATTR(upper_leg_model, upper_leg_model, set_upper_leg_model); + BA_MODEL_ATTR(lower_leg_model, lower_leg_model, set_lower_leg_model); + BA_MODEL_ATTR(toes_model, toes_model, set_toes_model); + BA_BOOL_ATTR(billboard_cross_out, billboard_cross_out, + set_billboard_cross_out); + BA_BOOL_ATTR(jump_pressed, jump_pressed, SetJumpPressed); + BA_BOOL_ATTR(punch_pressed, punch_pressed, SetPunchPressed); + BA_BOOL_ATTR(bomb_pressed, bomb_pressed, SetBombPressed); + BA_FLOAT_ATTR(run, run, SetRun); + BA_BOOL_ATTR(fly_pressed, fly_pressed, SetFlyPressed); + BA_BOOL_ATTR(pickup_pressed, pickup_pressed, SetPickupPressed); + BA_BOOL_ATTR(hold_position_pressed, hold_position_pressed, + SetHoldPositionPressed); + BA_FLOAT_ATTR(move_left_right, move_left_right, SetMoveLeftRight); + BA_FLOAT_ATTR(move_up_down, move_up_down, SetMoveUpDown); + BA_BOOL_ATTR(demo_mode, demo_mode, set_demo_mode); + BA_INT_ATTR(behavior_version, behavior_version, set_behavior_version); +#undef BA_NODE_TYPE_CLASS + + SpazNodeType() + : NodeType("spaz", CreateSpaz), + fly(this), + hockey(this), + roller_materials(this), + extras_material(this), + punch_materials(this), + pickup_materials(this), + materials(this), + area_of_interest_radius(this), + name(this), + counter_text(this), + mini_billboard_1_texture(this), + mini_billboard_2_texture(this), + mini_billboard_3_texture(this), + mini_billboard_1_start_time(this), + mini_billboard_1_end_time(this), + mini_billboard_2_start_time(this), + mini_billboard_2_end_time(this), + mini_billboard_3_start_time(this), + mini_billboard_3_end_time(this), + billboard_texture(this), + billboard_opacity(this), + counter_texture(this), + invincible(this), + name_color(this), + highlight(this), + color(this), + hurt(this), + boxing_gloves_flashing(this), + source_player(this), + frozen(this), + boxing_gloves(this), + curse_death_time(this), + shattered(this), + dead(this), + style(this), + knockout(this), + punch_power(this), + punch_momentum_angular(this), + punch_momentum_linear(this), + damage(this), + damage_smoothed(this), + punch_velocity(this), + is_area_of_interest(this), + velocity(this), + position_forward(this), + position_center(this), + punch_position(this), + torso_position(this), + position(this), + hold_body(this), + hold_node(this), + jump_sounds(this), + attack_sounds(this), + impact_sounds(this), + death_sounds(this), + pickup_sounds(this), + fall_sounds(this), + color_texture(this), + color_mask_texture(this), + head_model(this), + torso_model(this), + pelvis_model(this), + upper_arm_model(this), + forearm_model(this), + hand_model(this), + upper_leg_model(this), + lower_leg_model(this), + toes_model(this), + billboard_cross_out(this), + jump_pressed(this), + punch_pressed(this), + bomb_pressed(this), + run(this), + fly_pressed(this), + pickup_pressed(this), + hold_position_pressed(this), + move_left_right(this), + move_up_down(this), + demo_mode(this), + behavior_version(this) {} +}; +static NodeType* node_type{}; + +auto SpazNode::InitType() -> NodeType* { + node_type = new SpazNodeType(); + return node_type; +} + +SpazNode::SpazNode(Scene* scene) + : Node(scene, node_type), + birth_time_(scene->time()), + spaz_part_(this), + hair_part_(this), + punch_part_(this, false), + pickup_part_(this, false), + extras_part_(this, false), + roller_part_(this, true), + limbs_part_upper_(this, true), + limbs_part_lower_(this, true) { + // Head + body_head_ = + Object::New(kHeadBodyID, &spaz_part_, RigidBody::Type::kBody, + RigidBody::Shape::kSphere, + RigidBody::kCollideActive, RigidBody::kCollideAll); + body_head_->SetDimensions(0.23f, 0, 0, 0.28f, 0, 0, 1.0f); + body_head_->AddCallback(StaticCollideCallback, this); + + // Torso + body_torso_ = + Object::New(kTorsoBodyID, &spaz_part_, RigidBody::Type::kBody, + RigidBody::Shape::kSphere, + RigidBody::kCollideActive, RigidBody::kCollideAll); + body_torso_->SetDimensions(0.11f, 0, 0, 0.2f, 0, 0, 3.0f); + body_torso_->AddCallback(StaticCollideCallback, this); + + // Pelvis + body_pelvis_ = + Object::New(kPelvisBodyID, &spaz_part_, RigidBody::Type::kBody, + RigidBody::Shape::kBox, RigidBody::kCollideActive, + RigidBody::kCollideAll); + body_pelvis_->AddCallback(StaticCollideCallback, this); + + // Roller Ball + body_roller_ = Object::New( + kRollerBodyID, &roller_part_, RigidBody::Type::kBody, + RigidBody::Shape::kSphere, RigidBody::kCollideActive, + RigidBody::kCollideAll, nullptr, RigidBody::kIsRoller); + + body_roller_->SetDimensions(0.3f, 0, 0, 0, 0, 0, 0.1f); + body_roller_->AddCallback(StaticCollideCallback, this); + + // Stand Body + stand_body_ = + Object::New(kStandBodyID, &extras_part_, + RigidBody::Type::kBody, RigidBody::Shape::kSphere, + RigidBody::kCollideNone, RigidBody::kCollideNone); + dBodySetGravityMode(stand_body_->body(), 0); + stand_body_->SetDimensions(0.3f, 0, 0, 0, 0, 0, 1000.0f); + + // Upper Right Arm + upper_right_arm_body_ = + Object::New(kUpperRightArmBodyID, &limbs_part_upper_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + upper_right_arm_body_->AddCallback(StaticCollideCallback, this); + upper_right_arm_body_->SetDimensions(0.06f, 0.16f, 0, 0, 0, 0, + kUpperArmDensity); + + // Lower Right Arm + lower_right_arm_body_ = + Object::New(kLowerRightArmBodyID, &limbs_part_lower_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + lower_right_arm_body_->AddCallback(StaticCollideCallback, this); + lower_right_arm_body_->SetDimensions(0.06f, 0.13f, 0, 0.06f, 0.16f, 0, + kLowerArmDensity); + + // Upper Left Arm + upper_left_arm_body_ = + Object::New(kUpperLeftArmBodyID, &limbs_part_upper_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + upper_left_arm_body_->AddCallback(StaticCollideCallback, this); + upper_left_arm_body_->SetDimensions(0.06f, 0.16f, 0, 0, 0, 0, + kUpperArmDensity); + + // Lower Left Arm + lower_left_arm_body_ = + Object::New(kLowerLeftArmBodyID, &limbs_part_lower_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + lower_left_arm_body_->AddCallback(StaticCollideCallback, this); + lower_left_arm_body_->SetDimensions(0.06f, 0.13f, 0, 0.06f, 0.16f, 0, + kLowerArmDensity); + + // Upper Right Leg + upper_right_leg_body_ = + Object::New(kUpperRightLegBodyID, &limbs_part_upper_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + upper_right_leg_body_->AddCallback(StaticCollideCallback, this); + + // Lower Right leg + lower_right_leg_body_ = + Object::New(kLowerRightLegBodyID, &limbs_part_lower_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + lower_right_leg_body_->AddCallback(StaticCollideCallback, this); + + right_toes_body_ = + Object::New(kRightToesBodyID, &limbs_part_lower_, + RigidBody::Type::kBody, RigidBody::Shape::kSphere, + RigidBody::kCollideActive, RigidBody::kCollideAll); + right_toes_body_->AddCallback(StaticCollideCallback, this); + right_toes_body_->SetDimensions(0.075f, 0, 0, 0, 0, 0, kToesDensity); + + // Upper Left Leg + upper_left_leg_body_ = + Object::New(kUpperLeftLegBodyID, &limbs_part_upper_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + upper_left_leg_body_->AddCallback(StaticCollideCallback, this); + + // Lower Left leg + lower_left_leg_body_ = + Object::New(kLowerLeftLegBodyID, &limbs_part_lower_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideActive, RigidBody::kCollideAll); + lower_left_leg_body_->AddCallback(StaticCollideCallback, this); + + // Left Toes + left_toes_body_ = + Object::New(kLeftToesBodyID, &limbs_part_lower_, + RigidBody::Type::kBody, RigidBody::Shape::kSphere, + RigidBody::kCollideActive, RigidBody::kCollideAll); + left_toes_body_->AddCallback(StaticCollideCallback, this); + left_toes_body_->SetDimensions(0.075f, 0, 0, 0, 0, 0, kToesDensity); + + UpdateBodiesForStyle(); + + Stand(0, 0, 0, 0); + + // Attach head to torso. + neck_joint_ = CreateFixedJoint(body_head_.get(), body_torso_.get(), 1000, + 1, // linear stiff/damp + 20.0f, 0.3f); // angular stiff/damp + + // Drop the y angular stiffness/damping on our neck so our head can whip + // left/right a bit easier move connection point up away from torso a bit. + neck_joint_->anchor1[1] += 0.2f; + neck_joint_->anchor2[1] += 0.2f; + + // Attach torso to pelvis. + pelvis_joint_ = CreateFixedJoint(body_pelvis_.get(), body_torso_.get(), 0, + 0, // lin stiff/damp + 0, 0); // ang stiff/damp + + // Move anchor down a bit from torso towards pelvis. + pelvis_joint_->anchor1[1] -= 0.05f; + pelvis_joint_->anchor2[1] -= 0.05f; + + // Move anchor point forward a tiny bit (like the curvature of a spine). + pelvis_joint_->anchor2[2] += 0.05f; + + // Attach upper right arm to torso. + upper_right_arm_joint_ = + CreateFixedJoint(body_torso_.get(), upper_right_arm_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + // Move anchor to top of arm. + upper_right_arm_joint_->anchor2[2] = -0.1f; + + // Move anchor slightly in towards torso. + upper_right_arm_joint_->anchor2[0] += 0.02f; + + // Attach lower right arm to upper right arm. + lower_right_arm_joint_ = CreateFixedJoint(upper_right_arm_body_.get(), + lower_right_arm_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + lower_right_arm_joint_->anchor2[2] = -0.08f; + + // Attach upper left arm to torso. + upper_left_arm_joint_ = CreateFixedJoint( + body_torso_.get(), upper_left_arm_body_.get(), 0, 0, // linear stiff/damp + 0, 0); // Angular stiff/damp. + + // Move anchor to top of arm. + upper_left_arm_joint_->anchor2[2] = -0.1f; + + // Move anchor slightly in towards torso. + upper_left_arm_joint_->anchor2[0] += -0.02f; + + // Attach lower arm to upper arm. + lower_left_arm_joint_ = CreateFixedJoint(upper_left_arm_body_.get(), + lower_left_arm_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + lower_left_arm_joint_->anchor2[2] = -0.08f; + + // Attach upper right leg to leg-mass. + upper_right_leg_joint_ = + CreateFixedJoint(body_pelvis_.get(), upper_right_leg_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + upper_right_leg_joint_->anchor2[2] = -0.05f; + + // Attach lower right leg to upper right leg. + lower_right_leg_joint_ = CreateFixedJoint(upper_right_leg_body_.get(), + lower_right_leg_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + lower_right_leg_joint_->anchor2[2] = -0.05f; + + // Attach bottom of lower leg to pelvis. + right_leg_ik_joint_ = + CreateFixedJoint(body_pelvis_.get(), lower_right_leg_body_.get(), 0.3f, + 0.001f, // linear stiff/damp + 0, 0); // angular stiff/damp + dQFromAxisAndAngle(right_leg_ik_joint_->qrel, 1, 0, 0, 1.0f); + + // Move the anchor to the tip of our leg. + right_leg_ik_joint_->anchor2[2] = 0.05f; + + right_leg_ik_joint_->anchor1[0] = -0.1f; + right_leg_ik_joint_->anchor1[1] = -0.4f; + right_leg_ik_joint_->anchor1[2] = 0.0f; + + // Attach toes to lower right foot. + right_toes_joint_ = + CreateFixedJoint(lower_right_leg_body_.get(), right_toes_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + right_toes_joint_->anchor1[1] += -0.0f; + right_toes_joint_->anchor2[1] += -0.04f; + + // And an anchor off to the side to make it hinge-like. + right_toes_joint_2_ = nullptr; + right_toes_joint_2_ = + CreateFixedJoint(lower_right_leg_body_.get(), right_toes_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + right_toes_joint_2_->anchor1[1] += -0.0f; + right_toes_joint_2_->anchor2[1] += -0.04f; + + right_toes_joint_2_->anchor1[0] += -0.1f; + right_toes_joint_2_->anchor2[0] += -0.1f; + + // Attach upper left leg to leg-mass. + upper_left_leg_joint_ = + CreateFixedJoint(body_pelvis_.get(), upper_left_leg_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + upper_left_leg_joint_->anchor2[2] = -0.05f; + + // Attach lower left leg to upper left leg. + lower_left_leg_joint_ = CreateFixedJoint(upper_left_leg_body_.get(), + lower_left_leg_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + lower_left_leg_joint_->anchor2[2] = -0.05f; + + // Attach bottom of lower leg to pelvis. + left_leg_ik_joint_ = + CreateFixedJoint(body_pelvis_.get(), lower_left_leg_body_.get(), 0.3f, + 0.001f, // linear stiff/damp + 0, 0); // angular stiff/damp + + dQFromAxisAndAngle(left_leg_ik_joint_->qrel, 1, 0, 0, 1.0f); + + // Move the anchor to the tip of our leg. + left_leg_ik_joint_->anchor2[2] = 0.05f; + + left_leg_ik_joint_->anchor1[0] = 0.1f; + left_leg_ik_joint_->anchor1[1] = -0.4f; + left_leg_ik_joint_->anchor1[2] = 0.0f; + + // Attach toes to lower left foot. + left_toes_joint_ = + CreateFixedJoint(lower_left_leg_body_.get(), left_toes_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + right_toes_joint_->anchor1[1] += -0.0f; + left_toes_joint_->anchor2[1] += -0.04f; + + // And an anchor off to the side to make it hinge-like. + left_toes_joint_2_ = nullptr; + left_toes_joint_2_ = + CreateFixedJoint(lower_left_leg_body_.get(), left_toes_body_.get(), 0, + 0, // linear stiff/damp + 0, 0); // angular stiff/damp + + left_toes_joint_2_->anchor1[1] += -0.0f; + left_toes_joint_2_->anchor2[1] += -0.04f; + left_toes_joint_2_->anchor1[0] += 0.1f; + left_toes_joint_2_->anchor2[0] += 0.1f; + + // Attach end of right arm to torso. + right_arm_ik_joint_ = + CreateFixedJoint(body_torso_.get(), lower_right_arm_body_.get(), 0.0f, + 0.0f, // linear stiff/damp + 0, 0, // angular stiff/damp + -0.2f, -0.2f, 0.1f, // anchor1 + 0, 0, 0.07f, // anchor2 + false); + + left_arm_ik_joint_ = + CreateFixedJoint(body_torso_.get(), lower_left_arm_body_.get(), 0.0f, + 0.0f, // linear stiff/damp + 0, 0, // angular stiff/damp + 0.2f, -0.2f, 0.1f, // anchor1 + 0.0f, 0.0f, 0.07f, // anchor2 + false); + + // Roller ball joint. + roller_ball_joint_ = CreateFixedJoint(body_torso_.get(), body_roller_.get(), + kRollerBallLinearStiffness, + kRollerBallLinearDamping, 0, 0); + base_pelvis_roller_anchor_offset_ = roller_ball_joint_->anchor1[1]; + + // Stand joint on our torso. + stand_joint_ = + CreateFixedJoint(body_torso_.get(), stand_body_.get(), 100, 1, 200, 10); + + // Roller motor. + a_motor_roller_ = dJointCreateAMotor(scene->dynamics()->ode_world(), nullptr); + dJointAttach(a_motor_roller_, body_roller_->body(), nullptr); + dJointSetAMotorNumAxes(a_motor_roller_, 3); + dJointSetAMotorAxis(a_motor_roller_, 0, 0, 1, 0, 0); + dJointSetAMotorAxis(a_motor_roller_, 1, 0, 0, 1, 0); + dJointSetAMotorAxis(a_motor_roller_, 2, 0, 0, 0, 1); + dJointSetAMotorParam(a_motor_roller_, dParamFMax, 3.0f); + dJointSetAMotorParam(a_motor_roller_, dParamFMax2, 3.0f); + dJointSetAMotorParam(a_motor_roller_, dParamFMax3, 3.0f); + dJointSetAMotorParam(a_motor_roller_, dParamVel, 0.0f); + dJointSetAMotorParam(a_motor_roller_, dParamVel2, 0.0f); + dJointSetAMotorParam(a_motor_roller_, dParamVel3, 1.0f); + + // Attach brakes between our roller ball and our leg mass. + a_motor_brakes_ = dJointCreateAMotor(scene->dynamics()->ode_world(), nullptr); + dJointAttach(a_motor_brakes_, body_torso_->body(), body_roller_->body()); + dJointSetAMotorMode(a_motor_brakes_, dAMotorUser); + dJointSetAMotorNumAxes(a_motor_brakes_, 3); + dJointSetAMotorAxis(a_motor_brakes_, 0, 1, 1, 0, 0); + dJointSetAMotorAxis(a_motor_brakes_, 1, 1, 0, 1, 0); + dJointSetAMotorAxis(a_motor_brakes_, 2, 1, 0, 0, 1); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax, 10.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax2, 10.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax3, 10.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamVel, 0); + dJointSetAMotorParam(a_motor_brakes_, dParamVel2, 0); + dJointSetAMotorParam(a_motor_brakes_, dParamVel3, 0); + + // give joints initial vals + UpdateJoints(); + + // FIXME should do this on draw + UpdateForGraphicsQuality(g_graphics_server->quality()); + + // we want to have an area of interest by default.. + SetIsAreaOfInterest(true); + + // we want to update each step + BA_DEBUG_CHECK_BODIES(); +} + +void SpazNode::SetPickupPressed(bool val) { + if (val == pickup_pressed_) return; + pickup_pressed_ = val; + + // press + if (pickup_pressed_) { + if (frozen_ || knockout_) { + return; + } + if (holding_something_) { + Throw(false); + } else { + if ((pickup_ == 0) && (!knockout_) && (!frozen_)) + pickup_ = kPickupCooldown + 4; + } + } else { + // release + } +} + +void SpazNode::SetHoldPositionPressed(bool val) { + if (val == hold_position_pressed_) return; + hold_position_pressed_ = val; +} + +void SpazNode::SetMoveLeftRight(float val) { + if (val == move_left_right_) { + return; + } + move_left_right_ = val; + lr_ = static_cast_check_fit( + std::max(-127, std::min(127, static_cast(127.0f * val)))); +} + +void SpazNode::SetMoveUpDown(float val) { + if (val == move_up_down_) { + return; + } + move_up_down_ = val; + ud_ = static_cast_check_fit( + std::max(-127, std::min(127, static_cast(127.0f * val)))); +} + +void SpazNode::SetFlyPressed(bool val) { + if (val == fly_pressed_) return; + fly_pressed_ = val; + + // Press. + if (fly_pressed_) { + DoFlyPress(); + } else { + // Release. + } +} + +void SpazNode::SetRun(float val) { + if (val == run_) { + return; + } + run_ = val; +} + +void SpazNode::SetBombPressed(bool val) { + if (val == bomb_pressed_) { + return; + } + bomb_pressed_ = val; + if (bomb_pressed_) { + if (frozen_ || knockout_) { + return; + } + if (holding_something_) { + throwing_with_bomb_button_ = true; + Throw(true); + } + } else { + // Released. + } +} + +void SpazNode::SetPunchPressed(bool val) { + if (val == punch_pressed_) { + return; + } + punch_pressed_ = val; + if (punch_pressed_) { + if (frozen_ || knockout_) { + return; + } + + // If we're holding something, throw it. + if (holding_something_) { + Throw(false); + } else { + if (!holding_something_ && (!knockout_) && (!frozen_)) { + punch_ = kPunchDuration; + + // Left or right punch is determined by our spin. + if (std::abs(a_vel_y_smoothed_) < 0.3f) { + // At low rotational speeds lets do random. + punch_right_ = (RandomFloat() > 0.5f); + } else { + punch_right_ = a_vel_y_smoothed_ > 0.0f; + } + last_punch_time_ = scene()->time(); + if (Sound* sound = GetRandomMedia(attack_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + const dReal* p_head = dGeomGetPosition(body_head_->geom()); + g_audio->PushSourceStopSoundCall(voice_play_id_); + source->SetPosition(p_head[0], p_head[1], p_head[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + source->End(); + } + } + } + } + } else { + // Release. + } +} + +void SpazNode::SetJumpPressed(bool val) { + if (val == jump_pressed_) { + return; + } + jump_pressed_ = val; + if (jump_pressed_) { + if (!can_fly_ && !knockout_ && !frozen_) { + if (Sound* sound = GetRandomMedia(jump_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + const dReal* p_top = dGeomGetPosition(body_head_->geom()); + g_audio->PushSourceStopSoundCall(voice_play_id_); + source->SetPosition(p_top[0], p_top[1], p_top[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + source->End(); + } + } + if (demo_mode_) { + jump_ = 5; + } else { + jump_ = 7; + } + last_jump_time_ = scene()->time(); + } + jump_pressed_ = true; + } else { + // Release. + jump_pressed_ = false; + } +} + +static void FreezeJointAngle(JointFixedEF* j) { + dQMultiply1(j->qrel, j->node[0].body->q, j->node[1].body->q); +} + +void SpazNode::UpdateJoints() { + // (neck joint gets set every step so no update here) + + float l_still_scale = 1.0f; + float l_damp_scale = 1.0f; + float a_stiff_scale = 1.0f; + float a_damp_scale = 1.0f; + float leg_a_damp_scale = 1.0f; + + // When frozen, lock to our orientations and get more stiff. + if (frozen_) { + l_still_scale *= 5.0f; + l_damp_scale *= 0.2f; + a_stiff_scale *= 1000.0f; + a_damp_scale *= 0.2f; + leg_a_damp_scale *= 1.0f; + + FreezeJointAngle(pelvis_joint_); + FreezeJointAngle(upper_right_arm_joint_); + FreezeJointAngle(lower_right_arm_joint_); + FreezeJointAngle(upper_left_arm_joint_); + FreezeJointAngle(lower_left_arm_joint_); + FreezeJointAngle(upper_right_leg_joint_); + FreezeJointAngle(lower_right_leg_joint_); + FreezeJointAngle(upper_left_leg_joint_); + FreezeJointAngle(lower_left_leg_joint_); + FreezeJointAngle(right_toes_joint_); + FreezeJointAngle(left_toes_joint_); + if (hair_front_right_joint_) { + FreezeJointAngle(hair_front_right_joint_); + } + if (hair_front_left_joint_) { + FreezeJointAngle(hair_front_left_joint_); + } + if (hair_ponytail_top_joint_) { + FreezeJointAngle(hair_ponytail_top_joint_); + } + if (hair_ponytail_bottom_joint_) { + FreezeJointAngle(hair_ponytail_bottom_joint_); + } + } else { + // Not frozen; just normal setup. + + // Set normal joint angles. + + dQFromAxisAndAngle(pelvis_joint_->qrel, 1, 0.0f, 0.0f, -0.4f); + + dQFromAxisAndAngle(upper_right_arm_joint_->qrel, 1, 0.0f, -0.0f, 2.0f); + dQFromAxisAndAngle(lower_right_arm_joint_->qrel, 1, 0, 0, -1.7f); + + dQFromAxisAndAngle(upper_left_arm_joint_->qrel, 1, -0.0f, 0.0f, 2.0f); + dQFromAxisAndAngle(lower_left_arm_joint_->qrel, 1, 0, 0, -1.7f); + + dQFromAxisAndAngle(upper_right_leg_joint_->qrel, 1, 0.2f, 0.2f, 0.5f); + dQFromAxisAndAngle(lower_right_leg_joint_->qrel, 1, 0, 0, 1.0f); + dQSetIdentity(right_toes_joint_->qrel); + + dQFromAxisAndAngle(upper_left_leg_joint_->qrel, 1, -0.2f, -0.2f, 0.5f); + dQFromAxisAndAngle(lower_left_leg_joint_->qrel, 1, 0, 0, 3.1415f / 2.0f); + dQSetIdentity(left_toes_joint_->qrel); + } + + pelvis_joint_->linearStiffness = kPelvisLinearStiffness * l_still_scale; + pelvis_joint_->linearDamping = kPelvisLinearDamping * l_damp_scale; + pelvis_joint_->angularStiffness = kPelvisAngularStiffness * a_stiff_scale; + pelvis_joint_->angularDamping = kPelvisAngularDamping * a_damp_scale; + + upper_right_leg_joint_->linearStiffness = + kUpperLegLinearStiffness * l_still_scale; + upper_right_leg_joint_->linearDamping = kUpperLegLinearDamping * l_damp_scale; + upper_right_leg_joint_->angularStiffness = + kUpperLegAngularStiffness * a_stiff_scale; + upper_right_leg_joint_->angularDamping = + kUpperLegAngularDamping * a_damp_scale * leg_a_damp_scale; + + lower_right_leg_joint_->linearStiffness = + kLowerLegLinearStiffness * l_still_scale; + lower_right_leg_joint_->linearDamping = kLowerLegLinearDamping * l_damp_scale; + lower_right_leg_joint_->angularStiffness = + kLowerLegAngularStiffness * a_stiff_scale; + lower_right_leg_joint_->angularDamping = + kLowerLegAngularDamping * a_damp_scale * leg_a_damp_scale; + + right_toes_joint_->linearStiffness = kToesLinearStiffness * l_still_scale; + right_toes_joint_->linearDamping = kToesLinearDamping * l_damp_scale; + right_toes_joint_->angularStiffness = kToesAngularStiffness * a_stiff_scale; + right_toes_joint_->angularDamping = kToesAngularDamping * a_damp_scale; + + right_toes_joint_2_->linearStiffness = kToesLinearStiffness * l_still_scale; + right_toes_joint_2_->linearDamping = kToesLinearDamping * l_damp_scale; + right_toes_joint_2_->angularStiffness = 0; + right_toes_joint_2_->angularDamping = 0; + + upper_left_leg_joint_->linearStiffness = + kUpperLegLinearStiffness * l_still_scale; + upper_left_leg_joint_->linearDamping = kUpperLegLinearDamping * l_damp_scale; + upper_left_leg_joint_->angularStiffness = + kUpperLegAngularStiffness * a_stiff_scale; + upper_left_leg_joint_->angularDamping = + kUpperLegAngularDamping * a_damp_scale * leg_a_damp_scale; + + lower_left_leg_joint_->linearStiffness = + kLowerLegLinearStiffness * l_still_scale; + lower_left_leg_joint_->linearDamping = kLowerLegLinearDamping * l_damp_scale; + lower_left_leg_joint_->angularStiffness = + kLowerLegAngularStiffness * a_stiff_scale; + lower_left_leg_joint_->angularDamping = + kLowerLegAngularDamping * a_damp_scale * leg_a_damp_scale; + + left_toes_joint_->linearStiffness = kToesLinearStiffness * l_still_scale; + left_toes_joint_->linearDamping = kToesLinearDamping * l_damp_scale; + left_toes_joint_->angularStiffness = kToesAngularStiffness * a_stiff_scale; + left_toes_joint_->angularDamping = kToesAngularDamping * a_damp_scale; + + left_toes_joint_2_->linearStiffness = kToesLinearStiffness * l_still_scale; + left_toes_joint_2_->linearDamping = kToesLinearDamping * l_damp_scale; + left_toes_joint_2_->angularStiffness = 0; + left_toes_joint_2_->angularDamping = 0; + + // hair + if (hair_front_right_joint_) { + hair_front_right_joint_->linearStiffness = + kHairFrontRightLinearStiffness * l_still_scale; + hair_front_right_joint_->linearDamping = + kHairFrontRightLinearDamping * l_damp_scale; + hair_front_right_joint_->angularStiffness = + kHairFrontRightAngularStiffness * a_stiff_scale; + hair_front_right_joint_->angularDamping = + kHairFrontRightAngularDamping * a_damp_scale; + } + if (hair_front_left_joint_) { + hair_front_left_joint_->linearStiffness = + kHairFrontLeftLinearStiffness * l_still_scale; + hair_front_left_joint_->linearDamping = + kHairFrontLeftLinearDamping * l_damp_scale; + hair_front_left_joint_->angularStiffness = + kHairFrontLeftAngularStiffness * a_stiff_scale; + hair_front_left_joint_->angularDamping = + kHairFrontLeftAngularDamping * a_damp_scale; + } + if (hair_ponytail_top_joint_) { + hair_ponytail_top_joint_->linearStiffness = + kHairPonytailTopLinearStiffness * l_still_scale; + hair_ponytail_top_joint_->linearDamping = + kHairPonytailTopLinearDamping * l_damp_scale; + hair_ponytail_top_joint_->angularStiffness = + kHairPonytailTopAngularStiffness * a_stiff_scale; + hair_ponytail_top_joint_->angularDamping = + kHairPonytailTopAngularDamping * a_damp_scale; + } + if (hair_ponytail_bottom_joint_) { + hair_ponytail_bottom_joint_->linearStiffness = + kHairPonytailBottomLinearStiffness * l_still_scale; + hair_ponytail_bottom_joint_->linearDamping = + kHairPonytailBottomLinearDamping * l_damp_scale; + hair_ponytail_bottom_joint_->angularStiffness = + kHairPonytailBottomAngularStiffness * a_stiff_scale; + hair_ponytail_bottom_joint_->angularDamping = + kHairPonytailBottomAngularDamping * a_damp_scale; + } +} + +void SpazNode::UpdateBodiesForStyle() { + // Create hair bodies/joints if need be. + if (female_hair_) { + CreateHair(); + } else { + DestroyHair(); + } + + // Adjust torso size. + body_torso_->SetDimensions(torso_radius_, 0, 0, 0.2f, 0, 0, 3.0f); + + // Adjust hip and leg size. + body_pelvis_->SetDimensions(0.25f, 0.16f, 0.10f, 0.25f, 0.16f, 0.16f, + kPelvisDensity); + + float thigh_rad = female_ ? 0.06f : 0.04f; + upper_left_leg_body_->SetDimensions(thigh_rad, 0.12f, 0, 0.05f, 0.12f, 0, + kUpperLegDensity); + upper_right_leg_body_->SetDimensions(thigh_rad, 0.12f, 0, 0.05f, 0.12f, 0, + kUpperLegDensity); + + float ankle_rad = female_ ? 0.045f : 0.07f; + lower_left_leg_body_->SetDimensions(ankle_rad, 0.26f - ankle_rad * 2.0f, 0, + 0.07f, 0.12f, 0, kLowerLegDensity); + lower_right_leg_body_->SetDimensions(ankle_rad, 0.26f - ankle_rad * 2.0f, 0, + 0.07f, 0.12f, 0, kLowerLegDensity); +} + +static void InitObject(dObject* obj, dxWorld* w) { + obj->world = w; + obj->next = nullptr; + obj->tome = nullptr; + obj->userdata = nullptr; + obj->tag = 0; +} + +static void AddObjectToList(dObject* obj, dObject** first) { + obj->next = *first; + obj->tome = first; + if (*first) (*first)->tome = &obj->next; + (*first) = obj; +} +static void JointInit(dxWorld* w, dxJoint* j) { + dIASSERT(w && j); + InitObject(j, w); + j->vtable = nullptr; + j->flags = 0; + j->node[0].joint = j; + j->node[0].body = nullptr; + j->node[0].next = nullptr; + j->node[1].joint = j; + j->node[1].body = nullptr; + j->node[1].next = nullptr; + dSetZero(j->lambda, 6); + AddObjectToList(j, reinterpret_cast(&w->firstjoint)); + w->nj++; +} + +static void _dJointSetFixed(JointFixedEF* joint) { + dUASSERT(joint, "bad joint argument"); + dUASSERT(joint->vtable == &fixed_vtable_, "joint is not fixed"); + + // This code is taken from sJointSetSliderAxis(), we should really put the + // common code in its own function. + // compute the offset between the bodies + if (joint->node[0].body) { + if (joint->node[1].body) { + dQMultiply1(joint->qrel, joint->node[0].body->q, joint->node[1].body->q); + } else { + } + } +} + +static void _setAnchors(dxJoint* j, dReal x, dReal y, dReal z, dVector3 anchor1, + dVector3 anchor2) { + if (j->node[0].body) { + dReal q[4]; + q[0] = x - j->node[0].body->pos[0]; + q[1] = y - j->node[0].body->pos[1]; + q[2] = z - j->node[0].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331(anchor1, j->node[0].body->R, q); + if (j->node[1].body) { + q[0] = x - j->node[1].body->pos[0]; + q[1] = y - j->node[1].body->pos[1]; + q[2] = z - j->node[1].body->pos[2]; + q[3] = 0; + dMULTIPLY1_331(anchor2, j->node[1].body->R, q); + } else { + anchor2[0] = x; + anchor2[1] = y; + anchor2[2] = z; + } + } + anchor1[3] = 0; + anchor2[3] = 0; +} + +// Position b relative to b2 based on. +void PositionBodyForJoint(JointFixedEF* j) { + dBodyID b1 = dJointGetBody(j, 0); + dBodyID b2 = dJointGetBody(j, 1); + assert(b1 && b2); + dBodySetQuaternion(b2, dBodyGetQuaternion(b1)); + dVector3 p; + dBodyGetRelPointPos(b1, j->anchor1[0] - j->anchor2[0], + j->anchor1[1] - j->anchor2[1], + j->anchor1[2] - j->anchor2[2], p); + dBodySetPosition(b2, p[0], p[1], p[2]); +} + +auto SpazNode::CreateFixedJoint(RigidBody* b1, RigidBody* b2, float ls, + float ld, float as, float ad) -> JointFixedEF* { + JointFixedEF* j; + j = static_cast( + dAlloc(static_cast(fixed_vtable_.size))); + JointInit(scene()->dynamics()->ode_world(), j); + j->vtable = &fixed_vtable_; + if (j->vtable->init) j->vtable->init(j); + j->feedback = nullptr; + + if (b1 && b2) { + dJointAttach(j, b1->body(), b2->body()); + _dJointSetFixed(j); + const dReal* p = dBodyGetPosition(b2->body()); + _setAnchors(j, p[0], p[1], p[2], j->anchor1, j->anchor2); + } + + j->linearStiffness = ls; + j->linearDamping = ld; + j->angularStiffness = as; + j->angularDamping = ad; + + return j; +} + +auto SpazNode::CreateFixedJoint(RigidBody* b1, RigidBody* b2, float ls, + float ld, float as, float ad, float a1x, + float a1y, float a1z, float a2x, float a2y, + float a2z, bool reposition) -> JointFixedEF* { + assert(b1 && b2); + + JointFixedEF* j; + j = static_cast( + dAlloc(static_cast(fixed_vtable_.size))); + JointInit(scene()->dynamics()->ode_world(), j); + j->vtable = &fixed_vtable_; + if (j->vtable->init) j->vtable->init(j); + j->feedback = nullptr; + + dJointAttach(j, b1->body(), b2->body()); + dQSetIdentity(j->qrel); + j->anchor1[0] = a1x; + j->anchor1[1] = a1y; + j->anchor1[2] = a1z; + j->anchor2[0] = a2x; + j->anchor2[1] = a2y; + j->anchor2[2] = a2z; + + // Ok lets move the second body to line up with the joint. + if (reposition) { + PositionBodyForJoint(j); + } + + j->linearStiffness = ls; + j->linearDamping = ld; + j->angularStiffness = as; + j->angularDamping = ad; + + return j; +} + +void SpazNode::UpdateAreaOfInterest() { + if (area_of_interest_) { + area_of_interest_->set_position( + Vector3f(dGeomGetPosition(body_head_->geom()))); + area_of_interest_->set_velocity( + Vector3f(dBodyGetLinearVel(body_head_->body()))); + area_of_interest_->SetRadius(area_of_interest_radius_); + } +} + +SpazNode::~SpazNode() { + // If we're holding something, tell that thing it's been dropped. + DropHeldObject(); + + if (area_of_interest_) { + g_graphics->camera()->DeleteAreaOfInterest(area_of_interest_); + area_of_interest_ = nullptr; + } + + DestroyHair(); + + dJointDestroy(neck_joint_); + + dJointDestroy(upper_right_arm_joint_); + dJointDestroy(lower_right_arm_joint_); + dJointDestroy(upper_left_arm_joint_); + dJointDestroy(lower_left_arm_joint_); + + dJointDestroy(upper_right_leg_joint_); + dJointDestroy(lower_right_leg_joint_); + dJointDestroy(right_leg_ik_joint_); + dJointDestroy(upper_left_leg_joint_); + dJointDestroy(lower_left_leg_joint_); + dJointDestroy(left_leg_ik_joint_); + dJointDestroy(right_arm_ik_joint_); + dJointDestroy(left_arm_ik_joint_); + dJointDestroy(left_toes_joint_); + if (left_toes_joint_2_) { + dJointDestroy(left_toes_joint_2_); + } + dJointDestroy(right_toes_joint_); + if (right_toes_joint_2_) { + dJointDestroy(right_toes_joint_2_); + } + + dJointDestroy(pelvis_joint_); + dJointDestroy(roller_ball_joint_); + dJointDestroy(a_motor_brakes_); + dJointDestroy(stand_joint_); + dJointDestroy(a_motor_roller_); + + // stop any sounds that may be looping.. + if (tick_play_id_ != 0xFFFFFFFF) { + g_audio->PushSourceStopSoundCall(tick_play_id_); + } + if (voice_play_id_ != 0xFFFFFFFF) { + g_audio->PushSourceStopSoundCall(voice_play_id_); + } +} + +void SpazNode::ApplyTorque(float x, float y, float z) { + dBodyAddTorque(body_roller_->body(), x, y, z); +} + +// given coords within a (-1,-1) to (1,1) box, +// convert them such that their length is never greater than 1 +static void BoxNormalizeToCircle(float* lr, float* ud) { + if (std::abs((*lr)) < 0.0001f || std::abs((*ud)) < 0.0001f) { + return; // not worth doing anything + } + + // project them out to hit the border + float s; + if (std::abs((*lr)) > std::abs((*ud))) { + s = 1.0f / std::abs((*lr)); + } else { + s = 1.0f / std::abs((*ud)); + } + float proj_lr = (*lr) * s; + float proj_ud = (*ud) * s; + float proj_len = sqrtf(proj_lr * proj_lr + proj_ud * proj_ud); + float fin_scale = 1.0f / proj_len; + (*lr) *= fin_scale; + (*ud) *= fin_scale; +} + +static void BoxClampToCircle(float* lr, float* ud) { + float len_squared = (*lr) * (*lr) + (*ud) * (*ud); + if (len_squared > 1.0f) { + float len = sqrtf(len_squared); + float mult = 1.0f / len; + (*lr) *= mult; + (*ud) *= mult; + } +} + +void SpazNode::Throw(bool with_bomb_button) { + throwing_with_bomb_button_ = with_bomb_button; + + if (holding_something_ && !throwing_) { + throw_start_ = scene()->time(); + have_thrown_ = true; + + if (Sound* sound = GetRandomMedia(attack_sounds_)) { + if (AudioSource* s = g_audio->SourceBeginNew()) { + const dReal* p = dGeomGetPosition(body_head_->geom()); + g_audio->PushSourceStopSoundCall(voice_play_id_); + s->SetPosition(p[0], p[1], p[2]); + voice_play_id_ = s->Play(sound->GetSoundData()); + s->End(); + } + } + + // our throw can't actually start until we've held the thing + // for our min amount of time + float lrf = lr_smooth_; + float udf = ud_smooth_; + if (clamp_move_values_to_circle_) { + BoxClampToCircle(&lrf, &udf); + } else { + BoxNormalizeToCircle(&lrf, &udf); + } + + float scale = std::abs(sqrtf(lrf * lrf + udf * udf)); + throw_power_ = 0.8f * (0.6f + 0.4f * scale); + + // if we *just* picked it up, scale down our throw power slightly + // (otherwise we'll get an extra boost from the pick-up constraint and + // it'll fly farther than normal) + auto since_pick_up = static_cast(throw_start_ - last_pickup_time_); + if (since_pick_up < 500.0f) { + throw_power_ *= 0.4f + 0.6f * (since_pick_up / 500.0f); + } + + // lock in our throw direction.. otherwise it smooths out + // to the axes with dpads and we lose our fuzzy in-between aiming + + throw_lr_ = lr_smooth_; + throw_ud_ = ud_smooth_; + + // make ourself a note to drop the item as soon as possible with this power + throwing_ = true; + } +} + +void SpazNode::HandleMessage(const char* data_in) { + const char* data = data_in; + bool handled = true; + NodeMessageType type = extract_node_message_type(&data); + switch (type) { + case NodeMessageType::kScreamSound: { + if (dead_ || invincible_) break; + force_scream_ = true; + last_force_scream_time_ = scene()->time(); + break; + } + case NodeMessageType::kPickedUp: { + // lets instantly lose our balance in this case... + balance_ = 0; + break; + } + case NodeMessageType::kHurtSound: { + PlayHurtSound(); + break; + } + case NodeMessageType::kAttackSound: { + if (knockout_ || frozen_) { + break; + } + if (Sound* sound = GetRandomMedia(attack_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + const dReal* p_top = dGeomGetPosition(body_head_->geom()); + g_audio->PushSourceStopSoundCall(voice_play_id_); + source->SetPosition(p_top[0], p_top[1], p_top[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + source->End(); + } + } + break; + } + case NodeMessageType::kJumpSound: { + if (knockout_ || frozen_) { + break; + } + if (Sound* sound = GetRandomMedia(jump_sounds_)) { + if (AudioSource* s = g_audio->SourceBeginNew()) { + const dReal* p_top = dGeomGetPosition(body_head_->geom()); + g_audio->PushSourceStopSoundCall(voice_play_id_); + s->SetPosition(p_top[0], p_top[1], p_top[2]); + voice_play_id_ = s->Play(sound->GetSoundData()); + s->End(); + } + } + break; + } + case NodeMessageType::kKnockout: { + float amt = Utils::ExtractFloat16NBO(&data); + knockout_ = static_cast_check_fit( + std::min(40, std::max(static_cast(knockout_), + static_cast(amt * 0.07f)))); + trying_to_fly_ = false; + break; + } + case NodeMessageType::kCelebrate: { + int duration = Utils::ExtractInt16NBO(&data); + celebrate_until_time_left_ = celebrate_until_time_right_ = + scene()->time() + duration; + break; + } + case NodeMessageType::kCelebrateL: { + int duration = Utils::ExtractInt16NBO(&data); + celebrate_until_time_left_ = scene()->time() + duration; + break; + } + case NodeMessageType::kCelebrateR: { + int duration = Utils::ExtractInt16NBO(&data); + celebrate_until_time_right_ = scene()->time() + duration; + break; + } + case NodeMessageType::kImpulse: { + last_external_impulse_time_ = scene()->time(); + float dmg = 0.0f; + float px = Utils::ExtractFloat16NBO(&data); + float py = Utils::ExtractFloat16NBO(&data); + float pz = Utils::ExtractFloat16NBO(&data); + float vx = Utils::ExtractFloat16NBO(&data); + float vy = Utils::ExtractFloat16NBO(&data); + float vz = Utils::ExtractFloat16NBO(&data); + float mag = Utils::ExtractFloat16NBO(&data); + float velocity_mag = Utils::ExtractFloat16NBO(&data); + float radius = Utils::ExtractFloat16NBO(&data); + auto calc_force_only = static_cast(Utils::ExtractInt16NBO(&data)); + float force_dir_x = Utils::ExtractFloat16NBO(&data); + float force_dir_y = Utils::ExtractFloat16NBO(&data); + float force_dir_z = Utils::ExtractFloat16NBO(&data); + + // area of affect impulses apply to everything.. + if (radius > 0.0f) { + last_hit_was_punch_ = false; + float head_mag = + 5.0f + * body_head_->ApplyImpulse(px, py, pz, vx, vy, vz, force_dir_x, + force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += head_mag; + float torso_mag = body_torso_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += torso_mag; + float pelvis_mag = body_pelvis_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += pelvis_mag; + dmg += upper_right_arm_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += lower_right_arm_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += upper_left_arm_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += lower_left_arm_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += upper_right_leg_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += lower_right_leg_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += upper_left_leg_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += lower_left_leg_body_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + } else { + // single impulse.. + last_hit_was_punch_ = true; + const dReal* head_pos = dBodyGetPosition(body_head_->body()); + const dReal* torso_pos = dBodyGetPosition(body_torso_->body()); + const dReal* pelvis_pos = dBodyGetPosition(body_pelvis_->body()); + dVector3 to_head = {px - head_pos[0], py - head_pos[1], + pz - head_pos[2]}; + dVector3 to_torso = {px - torso_pos[0], py - torso_pos[1], + pz - torso_pos[2]}; + dVector3 to_pelvis = {px - pelvis_pos[0], py - pelvis_pos[1], + pz - pelvis_pos[2]}; + float to_head_length = dVector3Length(to_head); + float to_torso_length = dVector3Length(to_torso); + float to_pelvis_length = dVector3Length(to_pelvis); + if (to_head_length < to_torso_length + && to_head_length < to_pelvis_length) { + float head_mag = + 5.0f + * body_head_->ApplyImpulse(px, py, pz, vx, vy, vz, force_dir_x, + force_dir_y, force_dir_z, mag, + velocity_mag, radius, calc_force_only); + dmg += head_mag; + } else { + float torso_mag = + 5.0f + * body_torso_->ApplyImpulse( + px, py, pz, vx, vy, vz, force_dir_x, force_dir_y, force_dir_z, + mag, velocity_mag, radius, calc_force_only); + dmg += torso_mag; + } + } + + // store this in our damage attr so the user can know how much an impulse + // hurt us + damage_out_ = dmg; + + // also add it to our smoothed damage attr for things like body-explosions + if (!calc_force_only) { + damage_smoothed_ += dmg; + } + + // update knockout if we're applying this.. + if (!calc_force_only) { + knockout_ = static_cast_check_fit( + std::min(40, std::max(static_cast(knockout_), + static_cast(dmg * 0.02f) - 20))); + trying_to_fly_ = false; + } + break; + } + case NodeMessageType::kStand: { + float x = Utils::ExtractFloat16NBO(&data); + float y = Utils::ExtractFloat16NBO(&data); + float z = Utils::ExtractFloat16NBO(&data); + float angle = Utils::ExtractFloat16NBO(&data); + Stand(x, y, z, angle); + UpdatePartBirthTimes(); + break; + } + case NodeMessageType::kFooting: { + footing_ += Utils::ExtractInt8(&data); + trying_to_fly_ = false; + break; + } + case NodeMessageType::kKickback: { + float pos_x = Utils::ExtractFloat16NBO(&data); + float pos_y = Utils::ExtractFloat16NBO(&data); + float pos_z = Utils::ExtractFloat16NBO(&data); + float dir_x = Utils::ExtractFloat16NBO(&data); + float dir_y = Utils::ExtractFloat16NBO(&data); + float dir_z = Utils::ExtractFloat16NBO(&data); + float mag = Utils::ExtractFloat16NBO(&data); + Vector3f v = Vector3f(dir_x, dir_y, dir_z).Normalized() * mag; + dBodyID b = body_torso_->body(); + dBodyEnable(b); + dBodyAddForceAtPos(b, v.x, v.y, v.z, pos_x, pos_y, pos_z); + break; + } + case NodeMessageType::kFlash: { + flashing_ = 10; + break; + } + default: + handled = false; + break; + } + + if (!handled) { + Node::HandleMessage(data_in); + } +} + +void SpazNode::DoFlyPress() { + if (can_fly_ && !knockout_ && !frozen_) { + fly_power_ += 25.0f; + last_fly_time_ = scene()->time(); + trying_to_fly_ = true; + + // keep from doing too many sparkles.. + static millisecs_t last_sparkle_time = 0; + millisecs_t t = GetRealTime(); + if (t - last_sparkle_time > 200) { + last_sparkle_time = t; + AudioSource* s = g_audio->SourceBeginNew(); + if (s) { + const dReal* p_torso = dGeomGetPosition(body_torso_->geom()); + s->SetPosition(p_torso[0], p_torso[1], p_torso[2]); + s->SetGain(0.3f); + SystemSoundID s_id; + int r = rand() % 100; // NOLINT + if (r < 33) { + s_id = SystemSoundID::kSparkle; + } else if (r < 66) { + s_id = SystemSoundID::kSparkle2; + } else { + s_id = SystemSoundID::kSparkle3; + } + s->Play(g_media->GetSound(s_id)); + s->End(); + } + } + } +} + +// void SpazNode::update(uint32_t flags) { +void SpazNode::Step() { + BA_DEBUG_CHECK_BODIES(); + + // update our body blending values + { + Object::Ref* bodies[] = {&body_head_, + &body_torso_, + &body_pelvis_, + &body_roller_, + &stand_body_, + &upper_right_arm_body_, + &lower_right_arm_body_, + &upper_left_arm_body_, + &lower_left_arm_body_, + &upper_right_leg_body_, + &lower_right_leg_body_, + &upper_left_leg_body_, + &lower_left_leg_body_, + &left_toes_body_, + &right_toes_body_, + &hair_front_right_body_, + &hair_front_left_body_, + &hair_ponytail_top_body_, + &hair_ponytail_bottom_body_, + nullptr}; + + for (Object::Ref** body = bodies; *body != nullptr; body++) { + if (RigidBody* bodyptr = (**body).get()) { + bodyptr->UpdateBlending(); + } + } + } + + step_count_++; + + const dReal* p_head = dGeomGetPosition(body_head_->geom()); + const dReal* p_torso = dGeomGetPosition(body_torso_->geom()); + + bool running_fast = false; + + // if we're associated with a player, let the game know where that player is + // FIXME: this should simply be an attr connection established on the + // python layer... + if (source_player_.exists()) { + source_player_->SetPosition(Vector3f(p_torso)); + } + + // move our smoothed hurt value a short time after we get hit + if (scene()->time() - last_hurt_change_time_ > 400) { + if (hurt_smoothed_ < hurt_) { + hurt_smoothed_ = std::min(hurt_, hurt_smoothed_ + 0.03f); + } else { + hurt_smoothed_ = std::max(hurt_, hurt_smoothed_ - 0.03f); + } + } + + // update our smooth ud/lr vals + { + // lets use smoothing if all our input values are either -127, 0, or 127.. + // that implies that we're getting non-analog input where smoothing is + // useful to have. (so that we can throw bombs in non-axis-aligned + // directions, etc) + float smoothing; + if ((ud_ == -127 || ud_ == 0 || ud_ == 127) + && (lr_ == -127 || lr_ == 0 || lr_ == 127)) { + if (demo_mode_) { + smoothing = 0.9f; + } else { + smoothing = 0.5f; + } + } else { + smoothing = 0.0f; + } + ud_smooth_ = + smoothing * ud_smooth_ + + (1.0f - smoothing) + * (hold_position_pressed_ ? 0.0f + : ((static_cast(ud_) / 127.0f))); + lr_smooth_ = + smoothing * lr_smooth_ + + (1.0f - smoothing) + * (hold_position_pressed_ ? 0.0f + : ((static_cast(lr_) / 127.0f))); + } + // update our normalized values + { + float prev_ud = ud_norm_; + float prev_lr = lr_norm_; + + float this_ud_norm = + (hold_position_pressed_ ? 0.0f : ((static_cast(ud_) / 127.0f))); + float this_lr_norm = + (hold_position_pressed_ ? 0.0f : ((static_cast(lr_) / 127.0f))); + if (clamp_move_values_to_circle_) { + BoxClampToCircle(&this_lr_norm, &this_ud_norm); + } else { + BoxNormalizeToCircle(&this_lr_norm, &this_ud_norm); + } + + raw_lr_norm_ = this_lr_norm; + raw_ud_norm_ = this_ud_norm; + + // determine if we're running.. + running_ = ((run_ > 0.0f) && !hold_position_pressed_ && !holding_something_ + && !hockey_ && (std::abs(lr_) > 0 || std::abs(ud_) > 0) + && (!have_thrown_ || (scene()->time() - throw_start_ > 200))); + + if (running_) { + float run_target = sqrtf(run_); + float mag = (lr_smooth_ * lr_smooth_ + ud_smooth_ * ud_smooth_); + if (mag < 0.3f) { + run_target *= (mag / 0.3f); + } + float smoothing = run_target > run_gas_ ? 0.95f : 0.5f; + run_gas_ = smoothing * run_gas_ + (1.0f - smoothing) * run_target; + } else { + run_gas_ = std::max(0.0f, run_gas_ - 0.02f); // 120hz update + } + + if (holding_something_) + run_gas_ = std::max(0.0f, run_gas_ - 0.05f); // 120hz update + + if (!footing_) run_gas_ = std::max(0.0f, run_gas_ - 0.05f); + + // as we're running faster we simply filter our input values to prevent fast + // adjustments + + if (run_ > 0.05f) { + // strip out any component of the vector that is more than 90 degrees off + // of our current direction.. otherwise, extreme opposite directions will + // have a minimal effect on our actual run direction (a run dir blended + // with its 180-degree opposite then re-normalized won't really change) + { + dVector3 cur_dir = {ud_norm_, lr_norm_, 0}; + dVector3 new_dir = {this_ud_norm, this_lr_norm, 0}; + float dot = dDOT(new_dir, cur_dir); + if (dot < 0.0f) { + this_ud_norm -= run_gas_ * (ud_norm_ * dot); + this_lr_norm -= run_gas_ * (lr_norm_ * dot); + if (this_ud_norm == 0.0f) this_ud_norm = -0.001f; + if (this_lr_norm == 0.0f) this_lr_norm = -0.001f; + } + } + float orig_len, target_len; + float this_ud_norm_norm = this_ud_norm; + float this_lr_norm_norm = this_lr_norm; + { + // push our input towards a length of 1 if we're holding down the gas + orig_len = sqrtf(this_ud_norm_norm * this_ud_norm_norm + + this_lr_norm_norm * this_lr_norm_norm); + target_len = run_gas_ * 1.0f + (1.0f - run_gas_) * orig_len; + float mult = orig_len == 0.0f ? 1.0f : target_len / orig_len; + this_ud_norm_norm *= mult; + this_lr_norm_norm *= mult; + } + + const dReal* vel = dBodyGetLinearVel(body_torso_->body()); + dVector3 v = {vel[0], vel[1], vel[2]}; + float speed = dVector3Length(v); + + // we use this later for looking angry and stuff.. + if (speed >= 5.0f) running_fast = true; + // float smoothing = 0.97f; + + float smoothing = 0.975f * (0.9f + 0.1f * run_gas_); // change for 120hz + if (speed < 2.0f) smoothing *= (speed / 2.0f); + + // blend it with previous results but then re-normalize + // (we want to prevent sudden direction changes but keep it + // full-speed-ahead) + ud_norm_ = smoothing * ud_norm_ + (1.0f - smoothing) * this_ud_norm_norm; + lr_norm_ = smoothing * lr_norm_ + (1.0f - smoothing) * this_lr_norm_norm; + // ..and renormalize + float new_len = sqrtf(ud_norm_ * ud_norm_ + lr_norm_ * lr_norm_); + float mult = new_len == 0.0f ? 1.0f : target_len / new_len; + ud_norm_ *= mult; + lr_norm_ *= mult; + } else { + // not running.. can save some calculations.. + ud_norm_ = this_ud_norm; + lr_norm_ = this_lr_norm; + } + + // a sharper one for walking + float smoothing_diff = 0.93f; + ud_diff_smooth_ = smoothing_diff * ud_diff_smooth_ + + (1.0f - smoothing_diff) * (ud_norm_ - prev_ud); + lr_diff_smooth_ = smoothing_diff * lr_diff_smooth_ + + (1.0f - smoothing_diff) * (lr_norm_ - prev_lr); + + // a softer one for running + float smoothering_diff = 0.983f; + ud_diff_smoother_ = smoothering_diff * ud_diff_smoother_ + + (1.0f - smoothering_diff) * (ud_norm_ - prev_ud); + lr_diff_smoother_ = smoothering_diff * lr_diff_smoother_ + + (1.0f - smoothering_diff) * (lr_norm_ - prev_lr); + } + + float vel_length; + + // update smoothed avels and stuff + { + float avel = dBodyGetAngularVel(body_torso_->body())[1]; + float smoothing = 0.7f; + a_vel_y_smoothed_ = + smoothing * a_vel_y_smoothed_ + (1.0f - smoothing) * avel; + smoothing = 0.92f; + a_vel_y_smoothed_more_ = + smoothing * a_vel_y_smoothed_more_ + (1.0f - smoothing) * avel; + + float abs_a_vel = std::min(25.0f, std::abs(avel)); + + // angular punch momentum.. this goes up as we spin fast + punch_momentum_angular_d_ += abs_a_vel * 0.0004f; + punch_momentum_angular_d_ *= + 0.965f; // so our up/down rate tops off at some point.. + punch_momentum_angular_ += punch_momentum_angular_d_; + punch_momentum_angular_ *= + 0.92f; // so our absolute val tops off at some point... + + // drop down fast if we're spinning slower than 10.. + if (abs_a_vel < 5.0f) { + punch_momentum_angular_ *= 0.8f + 0.2f * (abs_a_vel / 5.0f); + } + + const dReal* vel = dBodyGetLinearVel(body_torso_->body()); + vel_length = sqrtf(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]); + + punch_momentum_linear_d_ += vel_length * 0.004f; + punch_momentum_linear_d_ *= 0.95f; // suppress rate of upward change + punch_momentum_linear_ += punch_momentum_linear_d_; + punch_momentum_linear_ *= 0.96f; // suppress absolute value + if (vel_length < 5.0f) { + punch_momentum_linear_ *= 0.9f + 0.1f * (vel_length / 5.0f); + } + + millisecs_t since_last_punch = scene()->time() - last_punch_time_; + if (since_last_punch < 200) { + punch_power_ = (0.5f + + 0.5f + * (sinf((static_cast(since_last_punch) / 200) + * (2.0f * 3.1415f) + - (3.14159f * 0.5f)))); + // Let's go between 0.5f and 1 so there's a bit less variance. + punch_power_ = 0.7f + 0.3f * punch_power_; + } else { + punch_power_ = 0.0f; + } + } + + // Update shadows. +#if !BA_HEADLESS_BUILD + FullShadowSet* full_shadows = full_shadow_set_.get(); + if (full_shadows) { + full_shadows->torso_shadow_.SetPosition( + Vector3f(dBodyGetPosition(body_torso_->body()))); + full_shadows->head_shadow_.SetPosition( + Vector3f(dBodyGetPosition(body_head_->body()))); + full_shadows->pelvis_shadow_.SetPosition( + Vector3f(dBodyGetPosition(body_pelvis_->body()))); + full_shadows->lower_left_leg_shadow_.SetPosition( + Vector3f(dBodyGetPosition(lower_left_leg_body_->body()))); + full_shadows->lower_right_leg_shadow_.SetPosition( + Vector3f(dBodyGetPosition(lower_right_leg_body_->body()))); + full_shadows->upper_left_leg_shadow_.SetPosition( + Vector3f(dBodyGetPosition(upper_left_leg_body_->body()))); + full_shadows->upper_right_leg_shadow_.SetPosition( + Vector3f(dBodyGetPosition(upper_right_leg_body_->body()))); + full_shadows->lower_right_arm_shadow_.SetPosition( + Vector3f(dBodyGetPosition(lower_right_arm_body_->body()))); + full_shadows->upper_right_arm_shadow_.SetPosition( + Vector3f(dBodyGetPosition(upper_right_arm_body_->body()))); + full_shadows->lower_left_arm_shadow_.SetPosition( + Vector3f(dBodyGetPosition(lower_left_arm_body_->body()))); + full_shadows->upper_left_arm_shadow_.SetPosition( + Vector3f(dBodyGetPosition(upper_left_arm_body_->body()))); + } else { + SimpleShadowSet* simple_shadows = simple_shadow_set_.get(); + assert(simple_shadows); + simple_shadows->shadow_.SetPosition( + Vector3f(dBodyGetPosition(body_pelvis_->body()))); + } +#endif // !BA_HEADLESS_BUILD + + // Update wings if we've got 'em. + if (wings_) { + float maxDist = 0.8f; + Vector3f p_wing_l = {0.0f, 0.0f, 0.0f}; + Vector3f p_wing_r = {0.0f, 0.0f, 0.0f}; + float x, y, z; + millisecs_t cur_time = scene()->time(); + + // Left wing. + if ((flapping_ || jump_ > 0 || running_) && !frozen_ && !knockout_) { + flap_ = (cur_time % 200 < 100); + } + if (flap_) { + x = kWingAttachX; + y = kWingAttachY; + z = kWingAttachZ; + } else { + x = kWingAttachFlapX; + y = kWingAttachFlapY; + z = kWingAttachFlapZ; + } + dBodyGetRelPointPos(body_torso_->body(), x, y, z, p_wing_l.v); + Vector3f diff = (p_wing_l - wing_pos_left_); + if (diff.LengthSquared() > maxDist * maxDist) { + diff *= (maxDist / diff.Length()); + } + wing_vel_left_ += diff * 0.03f; + wing_vel_left_ *= 0.93f; + wing_pos_left_ += wing_vel_left_; + + // Right wing. + dBodyGetRelPointPos(body_torso_->body(), -x, y, z, p_wing_r.v); + diff = (p_wing_r - wing_pos_right_); + if (diff.LengthSquared() > maxDist * maxDist) { + diff *= (maxDist / diff.Length()); + } + + // Use slightly different values from left for some variation. + wing_vel_right_ += diff * 0.036f; + wing_vel_right_ *= 0.95f; + wing_pos_right_ += wing_vel_right_; + } + + // Toggle angular components of some joints off and on for increased + // efficiency 93 to 123. + + // Always on for punches or frozen. + bool always_on = (frozen_ || (scene()->time() - last_punch_time_ < 500)); + + if (always_on) { + upper_left_arm_joint_->angularEnabled = true; + upper_right_arm_joint_->angularEnabled = true; + lower_right_arm_joint_->angularEnabled = true; + lower_left_arm_joint_->angularEnabled = true; + + upper_right_leg_joint_->angularEnabled = true; + upper_left_leg_joint_->angularEnabled = true; + lower_right_leg_joint_->angularEnabled = true; + lower_left_leg_joint_->angularEnabled = true; + + right_toes_joint_->angularEnabled = true; + left_toes_joint_->angularEnabled = true; + + left_toes_joint_2_->linearEnabled = true; + right_toes_joint_2_->linearEnabled = true; + } else { + int64_t t = scene()->stepnum(); + + upper_left_arm_joint_->angularEnabled = (t % 2 == 0); + upper_right_arm_joint_->angularEnabled = (t % 2 == 1); + lower_right_arm_joint_->angularEnabled = (t % 2 == 1); + lower_left_arm_joint_->angularEnabled = (t % 2 == 0); + + upper_right_leg_joint_->angularEnabled = (t % 2 == 0); + upper_left_leg_joint_->angularEnabled = (t % 2 == 1); + lower_right_leg_joint_->angularEnabled = (t % 2 == 1); + lower_left_leg_joint_->angularEnabled = (t % 2 == 0); + + right_toes_joint_->angularEnabled = (t % 2 == 0); + left_toes_joint_->angularEnabled = (t % 2 == 1); + + left_toes_joint_2_->linearEnabled = (t % 3 == 0); + right_toes_joint_2_->linearEnabled = (t % 3 == 2); + } + + // Update our limb-self-collide value. + // In certain cases (such as slowly walking in a straight line) + // we can completely skip collision tests between ourself with no + // real visual difference. This is a nice efficiency boost. + + // (Turned this off at some point; don't remember why.) + // We inch self-collide down if we're moving steadily, not turning too + // fast, and not hurt or holding stuff. + // if (vel_length > 1.0f + // and (std::abs(lr_smooth_) > 0.5f or std::abs(ud_smooth_) > 0.5f)) { + // limb_self_collide_ -= 0.01f; + // } else { + // limb_self_collide_ += 0.1f; + // } + + // if (std::abs(_aVelYSmoothed) > 5.0f) limb_self_collide_ += 0.2f; + // if (knockout_ != 0 or holding_something_) limb_self_collide_ += 0.1f; + // limb_self_collide_ = std::min(1.0f,std::max(0.0f,limb_self_collide_)); + + // Keep track of how long we're off the ground. + if (footing_) { + fly_time_ = 0; + } else { + fly_time_++; + } + + // If we're not touching the ground and are moving fast enough, we can cause + // damage to things we hit. + { + const dReal* lVel = dBodyGetLinearVel(body_torso_->body()); + float mag_squared = + lVel[0] * lVel[0] + lVel[1] * lVel[1] + lVel[2] * lVel[2]; + bool can_damage = (mag_squared > 20 && fly_time_ > 60); + body_torso_->set_can_cause_impact_damage(can_damage); + body_pelvis_->set_can_cause_impact_damage(can_damage); + body_head_->set_can_cause_impact_damage(can_damage); + } + + // Make sure none of our bodies are spinning/moving too fast. + { + float max_mag_squared = 400.0f; + float max_mag_squared_lin = 300.0f; + + // Shattering frozen dudes always looks too fast. Let's keep it down. + if (frozen_ && shattered_) { + max_mag_squared_lin = 100.0f; + } + + dBodyID bodies[11]; + bodies[0] = body_head_->body(); + bodies[1] = body_torso_->body(); + bodies[2] = upper_right_arm_body_->body(); + bodies[3] = lower_right_arm_body_->body(); + bodies[4] = upper_left_arm_body_->body(); + bodies[5] = lower_left_arm_body_->body(); + bodies[6] = upper_right_leg_body_->body(); + bodies[7] = upper_left_leg_body_->body(); + bodies[8] = lower_right_leg_body_->body(); + bodies[9] = lower_left_leg_body_->body(); + bodies[10] = nullptr; + + for (dBodyID* body = bodies; *body != nullptr; body++) { + const dReal* aVel = dBodyGetAngularVel(*body); + float mag_squared = + aVel[0] * aVel[0] + aVel[1] * aVel[1] + aVel[2] * aVel[2]; + if (mag_squared > max_mag_squared) { + float scale = max_mag_squared / mag_squared; + dBodySetAngularVel(*body, aVel[0] * scale, aVel[1] * scale, + aVel[2] * scale); + } + const dReal* lVel = dBodyGetLinearVel(*body); + mag_squared = lVel[0] * lVel[0] + lVel[1] * lVel[1] + lVel[2] * lVel[2]; + if (mag_squared > max_mag_squared_lin) { + float scale = max_mag_squared_lin / mag_squared; + dBodySetLinearVel(*body, lVel[0] * scale, lVel[1] * scale, + lVel[2] * scale); + } + } + + { + // If we've got hair bodies, apply a wee bit of drag to them so it looks + // cool when we run + Object::Ref* bodies2[] = { + &hair_front_right_body_, &hair_front_left_body_, + &hair_ponytail_top_body_, &hair_ponytail_bottom_body_, nullptr}; + float drag = 0.94f; + for (Object::Ref** body = bodies2; *body != nullptr; body++) { + if ((**body).exists()) { + dBodyID b = (**body)->body(); + const dReal* lVel = dBodyGetLinearVel(b); + dBodySetLinearVel(b, lVel[0] * drag, lVel[1] * drag, lVel[2] * drag); + } + } + } + } + + // Update jolt stuff. If our head jolts suddenly we may knock ourself out for + // a bit or may shatter. + { + const dReal* head_vel = dBodyGetLinearVel(body_head_->body()); + + // TODO(ericf): average our jolt-head-vel towards the current vel a bit for + // smoothing. + dVector3 diff; + diff[0] = head_vel[0] - jolt_head_vel_[0]; + diff[1] = head_vel[1] - jolt_head_vel_[1]; + diff[2] = head_vel[2] - jolt_head_vel_[2]; + dReal len = dVector3Length(diff); + jolt_head_vel_[0] = head_vel[0]; + jolt_head_vel_[1] = head_vel[1]; + jolt_head_vel_[2] = head_vel[2]; + + millisecs_t cur_time = scene()->time(); + + // If we're jolting and have just been touched in the head and haven't been + // pushed on by anything external recently (explosion, punch, etc), lets add + // some shock damage to ourself. + if (len > 3.0f && cur_time - last_pickup_time_ >= 500 + && cur_time - last_head_collide_time_ <= 30 + && cur_time - last_external_impulse_time_ >= 300 + && cur_time - last_impact_damage_dispatch_time_ > 500) { + impact_damage_accum_ += len - 3.0f; + } else if (impact_damage_accum_ > 0.0f) { + // If we're no longer adding damage but have accumulated some, lets + // dispatch it. + DispatchImpactDamageMessage(impact_damage_accum_); + impact_damage_accum_ = 0.0f; + last_impact_damage_dispatch_time_ = cur_time; + } + + // Make it difficult (but not impossible) to shatter within the first second + // (so we hopefully survive falling over). + float shatter_len; + if (cur_time - last_shatter_test_time_ < 1000) { + shatter_len = 8.0f; + } else { + shatter_len = 2.0f; + } + + if (frozen_ && len > shatter_len) { + last_shatter_test_time_ = cur_time; + DispatchShouldShatterMessage(); + } + } + + bool head_turning = false; + + // If we're punching. + millisecs_t scenetime = scene()->time(); + millisecs_t since_last_punch = scenetime - last_punch_time_; + + // Breathing when not moving. + float breath = 0.0f; + if (!dead_ && !shattered_ && (hold_position_pressed_ || (!ud_ && !lr_))) { + breath = sinf(static_cast(scenetime) * 0.005f); + } + + // If we're shattered we just make sure our joints are ineffective. + if (shattered_) { + JointFixedEF* joints[20]; + + // Fill in our broken joints. + { + JointFixedEF** j = joints; + + *j = right_leg_ik_joint_; + j++; + *j = left_leg_ik_joint_; + j++; + *j = right_arm_ik_joint_; + j++; + *j = left_arm_ik_joint_; + j++; + if (shatter_damage_ & kUpperRightArmJointBroken) { + *j = upper_right_arm_joint_; + j++; + } + if (shatter_damage_ & kLowerRightArmJointBroken) { + *j = lower_right_arm_joint_; + j++; + } + if (shatter_damage_ & kUpperLeftArmJointBroken) { + *j = upper_left_arm_joint_; + j++; + } + if (shatter_damage_ & kLowerLeftArmJointBroken) { + *j = lower_left_arm_joint_; + j++; + } + if (shatter_damage_ & kUpperLeftLegJointBroken) { + *j = upper_left_leg_joint_; + j++; + } + if (shatter_damage_ & kLowerLeftLegJointBroken) { + *j = lower_left_leg_joint_; + j++; + } + if (shatter_damage_ & kUpperRightLegJointBroken) { + *j = upper_right_leg_joint_; + j++; + } + if (shatter_damage_ & kLowerRightLegJointBroken) { + *j = lower_right_leg_joint_; + j++; + } + if (shatter_damage_ & kNeckJointBroken) { + *j = neck_joint_; + j++; + } + if (shatter_damage_ & kPelvisJointBroken) { + *j = pelvis_joint_; + j++; + } + *j = nullptr; + } + + for (JointFixedEF** j = joints; *j != nullptr; j++) + (**j).linearStiffness = (**j).linearDamping = (**j).angularStiffness = + (**j).angularDamping = 0.0f; + + } else { + // Not shattered; do normal stuff. + + // Adjust neck strength. + { + JointFixedEF* j = neck_joint_; + if (j) { + if (knockout_) { + j->linearStiffness = 400.0f; + j->linearDamping = 1.0f; + j->angularStiffness = 5.0f; + j->angularDamping = 0.3f; + } else { + j->linearStiffness = 500.0f; + j->linearDamping = 1.0f; + j->angularStiffness = 13.0f; + j->angularDamping = 0.8f; + } + } + } + + // Update legs. + { + // Whether our feet are following the run ball or just hanging free. + if (knockout_ || balance_ == 0 || frozen_) { + // flail our legs when airborn and alive + if (!footing_ && balance_ == 0 && !dead_) { + left_leg_ik_joint_->linearStiffness = kRunJointLinearStiffness * 0.4f; + left_leg_ik_joint_->linearDamping = kRunJointLinearDamping * 0.2f; + left_leg_ik_joint_->angularStiffness = + kRunJointAngularStiffness * 0.2f; + left_leg_ik_joint_->angularDamping = kRunJointAngularDamping * 0.2f; + right_leg_ik_joint_->linearStiffness = + kRunJointLinearStiffness * 0.4f; + right_leg_ik_joint_->linearDamping = kRunJointLinearDamping * 0.2f; + right_leg_ik_joint_->angularStiffness = + kRunJointAngularStiffness * 0.2f; + right_leg_ik_joint_->angularDamping = kRunJointAngularDamping * 0.2f; + roll_amt_ -= 0.2f; + if (roll_amt_ < (-2.0f * 3.141592f)) { + roll_amt_ += 2.0f * 3.141592f; + } + float x = 0.1f; + float y = -0.3f; + float z = 0.22f * cosf(roll_amt_); + left_leg_ik_joint_->anchor1[0] = x; + left_leg_ik_joint_->anchor1[1] = y; + left_leg_ik_joint_->anchor1[2] = z; + right_leg_ik_joint_->anchor1[0] = -x; + right_leg_ik_joint_->anchor1[1] = y; + right_leg_ik_joint_->anchor1[2] = -z; + } else { + // we're frozen or knocked out; turn off run-joint connections... + left_leg_ik_joint_->linearStiffness = 0.0f; + left_leg_ik_joint_->linearDamping = 0.0f; + left_leg_ik_joint_->angularStiffness = 0.0f; + left_leg_ik_joint_->angularDamping = 0.0f; + right_leg_ik_joint_->linearStiffness = 0.0f; + right_leg_ik_joint_->linearDamping = 0.0f; + right_leg_ik_joint_->angularStiffness = 0.0f; + right_leg_ik_joint_->angularDamping = 0.0f; + } + } else { + // Do normal running updates. + + // In hockey mode lets transfer a bit of our momentum to the direction + // we're facing if our skates are on the ground. + if (hockey_ && footing_) { + const dReal* rollVel = dBodyGetLinearVel(body_roller_->body()); + + dVector3 rollVelNorm = {rollVel[0], rollVel[1], rollVel[2]}; + dNormalize3(rollVelNorm); + + dVector3 forward; + dBodyVectorToWorld(stand_body_->body(), 0, 0, 1, forward); + + float dot = dDOT(rollVelNorm, forward); + + float mag = -6.0f * std::abs(dot); + + dVector3 f = {mag * rollVel[0], mag * rollVel[1], mag * rollVel[2]}; + float fMag = dVector3Length(f); + + if (dot < 0.0f) fMag *= -1.0f; // if we're going backwards.. + + dBodyAddForce(body_roller_->body(), f[0], f[1], f[2]); + dBodyAddForce(body_roller_->body(), forward[0] * fMag, + forward[1] * fMag, forward[2] * fMag); + } + + left_leg_ik_joint_->linearStiffness = kRunJointLinearStiffness; + left_leg_ik_joint_->linearDamping = kRunJointLinearDamping; + left_leg_ik_joint_->angularStiffness = kRunJointAngularStiffness; + left_leg_ik_joint_->angularDamping = kRunJointAngularDamping; + right_leg_ik_joint_->linearStiffness = kRunJointLinearStiffness; + right_leg_ik_joint_->linearDamping = kRunJointLinearDamping; + right_leg_ik_joint_->angularStiffness = kRunJointAngularStiffness; + right_leg_ik_joint_->angularDamping = kRunJointAngularDamping; + + // Tighten things up for running. + left_leg_ik_joint_->linearStiffness *= + 2.0f * run_gas_ + (1.0f - run_gas_) * 1.0f; + left_leg_ik_joint_->linearDamping *= + 2.0f * run_gas_ + (1.0f - run_gas_) * 1.0f; + right_leg_ik_joint_->linearStiffness *= + 2.0f * run_gas_ + (1.0f - run_gas_) * 1.0f; + right_leg_ik_joint_->linearDamping *= + 2.0f * run_gas_ + (1.0f - run_gas_) * 1.0f; + + if (hockey_) { + if (hold_position_pressed_ || (!ud_ && !lr_)) { + left_leg_ik_joint_->linearStiffness *= 0.05f; + left_leg_ik_joint_->linearDamping *= 0.1f; + left_leg_ik_joint_->angularStiffness *= 0.05f; + left_leg_ik_joint_->angularDamping *= 0.1f; + right_leg_ik_joint_->linearStiffness *= 0.05f; + right_leg_ik_joint_->linearDamping *= 0.1f; + right_leg_ik_joint_->angularStiffness *= 0.05f; + right_leg_ik_joint_->angularDamping *= 0.1f; + } + } + + const dReal* ballAVel = dBodyGetAngularVel(body_roller_->body()); + const dReal aVelMag = + sqrtf(ballAVel[0] * ballAVel[0] + ballAVel[1] * ballAVel[1] + + ballAVel[2] * ballAVel[2]); + + // When we're stopped, press our feet downward. + float speed_stretch = std::min( + sqrtf(lr_norm_ * lr_norm_ + ud_norm_ * ud_norm_) * 2.0f, 1.0f); + + float rollScale = hockey_ ? 0.6f : 1.0f; + + // Push towards 0.8f when running. + rollScale = run_gas_ * 0.8f + (1.0f - run_gas_) * rollScale; + + // Clamp extremely low values so noise doesnt keep our feet moving + roll_amt_ -= rollScale * 0.021f * std::max(aVelMag - 0.1f, 0.0f); + + if (roll_amt_ < (-2.0f * 3.141592f)) { + roll_amt_ += 2.0f * 3.141592f; + } + + // We move our feet in a circle that is calculated + // relative to our stand-body; *not* our pelvis. + // this way our pelvis is free to sway and rotate and stuff + // in response to our feet without affecting their target arcs + + // LEFT LEG + float step_separation = female_ ? 0.03f : 0.08f; + if (ninja_) { + step_separation *= 0.7f; + } + { + // Take a point relative to stand-body and then find it in the space + // of our pelvis. *that* is our attach point for the constraint. + dVector3 p_world; + dVector3 p_pelvis; + float y = -0.4f + speed_stretch * 0.14f * sinf(roll_amt_) + + (1.0f - speed_stretch) * -0.2f; + if (jump_ > 0) y -= 0.3f; + float z = 0.22f * cosf(roll_amt_); + y += 0.06f * run_gas_; + z *= 1.4f * run_gas_ + (1.0f - run_gas_) * 1.0f; + dBodyGetRelPointPos(stand_body_->body(), step_separation, y, z, + p_world); + assert(body_pelvis_.exists()); + dBodyGetPosRelPoint(body_pelvis_->body(), p_world[0], p_world[1], + p_world[2], p_pelvis); + left_leg_ik_joint_->anchor1[0] = p_pelvis[0]; + left_leg_ik_joint_->anchor1[1] = p_pelvis[1]; + left_leg_ik_joint_->anchor1[2] = p_pelvis[2]; + } + // RIGHT LEG + { + // Take a point relative to stand-body and then find it in the space + // of our pelvis. *that* is our attach point for the constraint. + dVector3 p_world; + dVector3 p_pelvis; + float y = -0.4f + speed_stretch * 0.14f * -sinf(roll_amt_) + + (1.0f - speed_stretch) * -0.2f; + if (jump_ > 0) y -= 0.3f; + float z = 0.22f * -cosf(roll_amt_); + y += 0.05f * run_gas_; + z *= 1.3f * run_gas_ + (1.0f - run_gas_) * 1.0f; + dBodyGetRelPointPos(stand_body_->body(), -step_separation, y, z, + p_world); + assert(body_pelvis_.exists()); + dBodyGetPosRelPoint(body_pelvis_->body(), p_world[0], p_world[1], + p_world[2], p_pelvis); + right_leg_ik_joint_->anchor1[0] = p_pelvis[0]; + right_leg_ik_joint_->anchor1[1] = p_pelvis[1]; + right_leg_ik_joint_->anchor1[2] = p_pelvis[2]; + } + } + + // Arms. + { + // Adjust our joint strengths. + { + float l_still_scale = 1.0f; + float l_damp_scale = 1.0f; + float a_stiff_scale = 1.0f; + float a_damp_scale = 1.0f; + float lower_arm_a_scale = 1.0f; + + if (frozen_) { + l_still_scale *= 5.0f; + l_damp_scale *= 0.2f; + a_stiff_scale *= 1000.0f; + a_damp_scale *= 0.2f; + } else { + // Allow female arms to relax a bit more unless we're running. + if (female_) { + lower_arm_a_scale = + lower_arm_a_scale * run_gas_ + 0.2f * (1.0f - run_gas_); + } + + // Stiffen up during punches and celebrations. + if (since_last_punch < 500 || scenetime < celebrate_until_time_left_ + || scenetime < celebrate_until_time_right_) { + l_still_scale *= 2.0f; + a_stiff_scale *= 2.0f; + } + } + + upper_right_arm_joint_->linearStiffness = + kUpperArmLinearStiffness * l_still_scale; + upper_right_arm_joint_->linearDamping = + kUpperArmLinearDamping * l_damp_scale; + upper_right_arm_joint_->angularStiffness = + kUpperArmAngularStiffness * a_stiff_scale; + upper_right_arm_joint_->angularDamping = + kUpperArmAngularDamping * a_damp_scale; + + lower_right_arm_joint_->linearStiffness = + kLowerArmLinearStiffness * l_still_scale; + lower_right_arm_joint_->linearDamping = + kLowerArmLinearDamping * l_damp_scale; + lower_right_arm_joint_->angularStiffness = + kLowerArmAngularStiffness * a_stiff_scale * lower_arm_a_scale; + lower_right_arm_joint_->angularDamping = + kLowerArmAngularDamping * a_damp_scale * lower_arm_a_scale; + + upper_left_arm_joint_->linearStiffness = + kUpperArmLinearStiffness * l_still_scale; + upper_left_arm_joint_->linearDamping = + kUpperArmLinearDamping * l_damp_scale; + upper_left_arm_joint_->angularStiffness = + kUpperArmAngularStiffness * a_stiff_scale; + upper_left_arm_joint_->angularDamping = + kUpperArmAngularDamping * a_damp_scale; + + lower_left_arm_joint_->linearStiffness = + kLowerArmLinearStiffness * l_still_scale; + lower_left_arm_joint_->linearDamping = + kLowerArmLinearDamping * l_damp_scale; + lower_left_arm_joint_->angularStiffness = + kLowerArmAngularStiffness * a_stiff_scale * lower_arm_a_scale; + lower_left_arm_joint_->angularDamping = + kLowerArmAngularDamping * a_damp_scale * lower_arm_a_scale; + } + + // Adjust our shoulder position. + { + float x = -0.15f; + float y = 0.14f; + float z = 0.0f; + float leftZOffset = 0.0f; + float rightZOffset = 0.0f; + x += shoulder_offset_x_; + y += shoulder_offset_y_; + z += shoulder_offset_z_; + + if (punch_) { + if (punch_right_) { + leftZOffset = -0.05f; + rightZOffset = 0.05f; + } else { + leftZOffset = 0.05f; + rightZOffset = -0.05f; + } + } + + // Breathing if we're not moving. + if (!frozen_) y += breath * 0.012f; + + upper_right_arm_joint_->anchor1[0] = x; + upper_right_arm_joint_->anchor1[1] = y; + upper_right_arm_joint_->anchor1[2] = z + rightZOffset; + + upper_left_arm_joint_->anchor1[0] = -x; + upper_left_arm_joint_->anchor1[1] = y; + upper_left_arm_joint_->anchor1[2] = z + leftZOffset; + } + + // Now update ik stuff. + // If we're frozen, turn it all off. + + if (frozen_) { + right_arm_ik_joint_->linearStiffness = 0; + right_arm_ik_joint_->linearDamping = 0; + right_arm_ik_joint_->angularStiffness = 0; + right_arm_ik_joint_->angularDamping = 0; + left_arm_ik_joint_->linearStiffness = 0; + left_arm_ik_joint_->linearDamping = 0; + left_arm_ik_joint_->angularStiffness = 0; + left_arm_ik_joint_->angularDamping = 0; + } else { + bool haveHeldThing = false; + if (holding_something_ && hold_node_.exists()) { + Node* a = hold_node_.get(); + RigidBody* b = a->GetRigidBody(hold_body_); + if (b) { + haveHeldThing = true; + + right_arm_ik_joint_->linearStiffness = 40.0f; + right_arm_ik_joint_->linearDamping = 1.0f; + left_arm_ik_joint_->linearStiffness = 40.0f; + left_arm_ik_joint_->linearDamping = 1.0f; + JointFixedEF* jf; + + dBodyID heldBody = b->body(); + + // Find our target point relative to the held body and aim for + // that. + dVector3 p_world; + dVector3 p_torso2; + + jf = right_arm_ik_joint_; + dBodyGetRelPointPos(heldBody, hold_hand_offset_right_[0], + hold_hand_offset_right_[1], + hold_hand_offset_right_[2], p_world); + assert(body_torso_.exists()); + dBodyGetPosRelPoint(body_torso_->body(), p_world[0], p_world[1], + p_world[2], p_torso2); + jf->anchor1[0] = p_torso2[0]; + jf->anchor1[1] = p_torso2[1]; + jf->anchor1[2] = p_torso2[2]; + jf = left_arm_ik_joint_; + dBodyGetRelPointPos(heldBody, hold_hand_offset_left_[0], + hold_hand_offset_left_[1], + hold_hand_offset_left_[2], p_world); + assert(body_torso_.exists()); + dBodyGetPosRelPoint(body_torso_->body(), p_world[0], p_world[1], + p_world[2], p_torso2); + jf->anchor1[0] = p_torso2[0]; + jf->anchor1[1] = p_torso2[1]; + jf->anchor1[2] = p_torso2[2]; + } + } + + // Not holding something. + if (!haveHeldThing) { + // Punching. + if (since_last_punch < 300) { + JointFixedEF* punch_hand; + JointFixedEF* opposite_hand; + + JointFixedEF* shoulder_joint; + + float mirror_scale; + + if (punch_right_) { + punch_hand = right_arm_ik_joint_; + opposite_hand = left_arm_ik_joint_; + shoulder_joint = upper_right_arm_joint_; + mirror_scale = -1.0f; + } else { + punch_hand = left_arm_ik_joint_; + opposite_hand = right_arm_ik_joint_; + shoulder_joint = upper_left_arm_joint_; + mirror_scale = 1.0f; + } + + punch_hand->linearStiffness = 100.0f; + punch_hand->linearDamping = 1.0f; + opposite_hand->linearStiffness = 30.0f; + opposite_hand->linearDamping = 0.1f; + + // pull non-punch hand back.. + opposite_hand->anchor1[0] = -0.2f * mirror_scale; + opposite_hand->anchor1[1] = 0.1f; + opposite_hand->anchor1[2] = -0.0f; + + // anticipation + if (since_last_punch < 80) { + punch_hand->anchor1[0] = 0.4f * mirror_scale; + punch_hand->anchor1[1] = 0.0f; + punch_hand->anchor1[2] = -0.1f; + } else if (since_last_punch < 200) { + // Offset our punch-direction from our punch shoulder; that's + // our target point for our fist. + dVector3 p_world; + dVector3 p_torso2; + dBodyGetRelPointPos(body_torso_->body(), + shoulder_joint->anchor1[0], + shoulder_joint->anchor1[1], + shoulder_joint->anchor1[2], p_world); + + // Offset now that we're in world-space. + p_world[0] += punch_dir_x_ * 0.7f; + p_world[2] += punch_dir_z_ * 0.7f; + p_world[1] += 0.13f; + + // Now translate back to torso space for setting our anchor. + assert(body_torso_.exists()); + dBodyGetPosRelPoint(body_torso_->body(), p_world[0], p_world[1], + p_world[2], p_torso2); + + punch_hand->anchor1[0] = p_torso2[0]; + punch_hand->anchor1[1] = p_torso2[1]; + punch_hand->anchor1[2] = p_torso2[2]; + } + } else if (have_thrown_ && scenetime - throw_start_ < 100 + && scenetime >= throw_start_) { + // Pick-up gesture. + JointFixedEF* jf; + jf = left_arm_ik_joint_; + jf->anchor1[0] = 0.0f; + jf->anchor1[1] = 0.2f; + jf->anchor1[2] = 0.8f; + left_arm_ik_joint_->linearStiffness = 10.0f; + left_arm_ik_joint_->linearDamping = 0.1f; + + jf = right_arm_ik_joint_; + jf->anchor1[0] = -0.0f; + jf->anchor1[1] = 0.2f; + jf->anchor1[2] = 0.8f; + right_arm_ik_joint_->linearStiffness = 10.0f; + right_arm_ik_joint_->linearDamping = 0.1f; + } else if (!footing_ && balance_ == 0 && !dead_) { + // Wave arms when airborn. + float wave_amt = static_cast(scenetime) * -0.018f; + + left_arm_ik_joint_->linearStiffness = 6.0f; + left_arm_ik_joint_->linearDamping = 0.01f; + right_arm_ik_joint_->linearStiffness = 6.0f; + right_arm_ik_joint_->linearDamping = 0.01f; + + float v1 = sinf(wave_amt) * 0.34f; + float v2 = cosf(wave_amt) * 0.34f; + + JointFixedEF* jf; + jf = left_arm_ik_joint_; + jf->anchor1[0] = 0.4f; + jf->anchor1[1] = v1 + 0.6f; + jf->anchor1[2] = v2 + 0.2f; + + jf = right_arm_ik_joint_; + jf->anchor1[0] = -0.4f; + jf->anchor1[1] = -v1 + 0.6f; + jf->anchor1[2] = -v2 + 0.2f; + } else { + // Not airborn. + + // If we're looking to pick something up, wave our arms in front + // of us. + if (!knockout_ && pickup_ > 20) { + JointFixedEF* jf; + jf = left_arm_ik_joint_; + jf->anchor1[0] = 0.4f; + jf->anchor1[1] = 0.5f; + jf->anchor1[2] = 0.7f; + + jf = right_arm_ik_joint_; + jf->anchor1[0] = -0.4f; + jf->anchor1[1] = 0.2f; + jf->anchor1[2] = 0.7f; + + // Swipe across. + if (pickup_ < 30) { + left_arm_ik_joint_->anchor1[0] = -0.1f; + right_arm_ik_joint_->anchor1[0] = 0.1f; + } + + left_arm_ik_joint_->linearStiffness = 6.0f; + left_arm_ik_joint_->linearDamping = 0.1f; + right_arm_ik_joint_->linearStiffness = 6.0f; + right_arm_ik_joint_->linearDamping = 0.1f; + } else { + // Cursed - wave arms. + if (!knockout_ && curse_death_time_ != 0) { + left_arm_ik_joint_->linearStiffness = 30.0f; + left_arm_ik_joint_->linearDamping = 0.08f; + + right_arm_ik_joint_->linearStiffness = 30.0f; + right_arm_ik_joint_->linearDamping = 0.08f; + + float v1 = sinf(scenetime * 0.05f) * 0.12f; + float v2 = cosf(scenetime * 0.04f) * 0.12f; + + JointFixedEF* jf; + jf = left_arm_ik_joint_; + jf->anchor1[0] = 0.4f + v2; + jf->anchor1[1] = 0.4f; + jf->anchor1[2] = 0.3f + v1; + + jf = right_arm_ik_joint_; + jf->anchor1[0] = -0.4f - v2; + jf->anchor1[1] = 0.4f; + jf->anchor1[2] = 0.3f + v1; + } else if (!knockout_ + && (scenetime < celebrate_until_time_left_ + || scenetime < celebrate_until_time_right_)) { + // Celebrating - hold arms in air. + float v1 = sinf(scenetime * 0.04f) * 0.1f; + float v2 = cosf(scenetime * 0.03f) * 0.1f; + JointFixedEF* jf; + if (scenetime < celebrate_until_time_left_) { + left_arm_ik_joint_->linearStiffness = 30.0f; + left_arm_ik_joint_->linearDamping = 0.08f; + + jf = left_arm_ik_joint_; + jf->anchor1[0] = 0.4f + v2; + jf->anchor1[1] = 0.5f; + jf->anchor1[2] = 0.2f + v1; + } + if (scenetime < celebrate_until_time_right_) { + right_arm_ik_joint_->linearStiffness = 30.0f; + right_arm_ik_joint_->linearDamping = 0.08f; + + jf = right_arm_ik_joint_; + jf->anchor1[0] = -0.4f - v2; + jf->anchor1[1] = 0.5f; + jf->anchor1[2] = 0.2f + v1; + } + } else if (!knockout_ && !hold_position_pressed_ + && (ud_ || lr_)) { + // Sway arms gently when walking, and vigorously + // when running. + float blend = run_gas_ * run_gas_; + float inv_blend = 1.0f - run_gas_; + float wave_amt = roll_amt_; + + left_arm_ik_joint_->linearStiffness = + 14.0f * blend + 0.5f * inv_blend; + left_arm_ik_joint_->linearDamping = + 0.08f * blend + 0.001f * inv_blend; + + right_arm_ik_joint_->linearStiffness = + 14.0f * blend + 0.5f * inv_blend; + right_arm_ik_joint_->linearDamping = + 0.08f * blend + 0.001f * inv_blend; + + float v1run = sinf(wave_amt + 3.1415f * 0.5f) * 0.2f; + float v2run = cosf(wave_amt) * 0.3f; + float v1 = sinf(wave_amt) * 0.05f; + float v2 = cosf(wave_amt) * (female_ ? 0.3f : 0.6f); + + JointFixedEF* jf; + jf = left_arm_ik_joint_; + jf->anchor1[0] = 0.2f; + jf->anchor1[1] = + (-v1run - 0.15f) * blend + (-v1 - 0.1f) * inv_blend; + jf->anchor1[2] = + (-v2run + 0.15f) * blend + (-v2 + 0.1f) * inv_blend; + + jf = right_arm_ik_joint_; + jf->anchor1[0] = -0.2f; + jf->anchor1[1] = + (v1run - 0.15f) * blend + (v1 - 0.1f) * inv_blend; + jf->anchor1[2] = + (v2run + 0.15f) * blend + (v2 + 0.1f) * inv_blend; + } else { + // Hang freely. + left_arm_ik_joint_->linearStiffness = 0.0f; + left_arm_ik_joint_->linearDamping = 0.0f; + right_arm_ik_joint_->linearStiffness = 0.0f; + right_arm_ik_joint_->linearDamping = 0.0f; + } + } + } + } + } + } + + if (holding_something_) { + // look up to keep out of the way of our arms + dQFromAxisAndAngle(neck_joint_->qrel, 1, 0, 0, 0.5f); + head_back_ = true; + } else { + // if our head was back from holding something, whip it forward again.. + if (head_back_) { + dQSetIdentity(neck_joint_->qrel); + head_back_ = false; + } + + // if we're cursed, whip it about + if (curse_death_time_ != 0) { + if (scene()->stepnum() % 5 == 0 && RandomFloat() > 0.2f) { + head_turning = true; + dQFromAxisAndAngle(neck_joint_->qrel, RandomFloat() * 0.05f, + RandomFloat(), RandomFloat() * 0.08f, + 2.3f * (RandomFloat() - 0.5f)); + } + } else { + int64_t gti = scene()->stepnum(); + + // if we're moving or hurt, keep our head straight + if ((!hold_position_pressed_ && (ud_ || lr_)) || knockout_ + || frozen_) { + dQSetIdentity(neck_joint_->qrel); + + // rotate it slightly in the direction we're turning + dQFromAxisAndAngle( + neck_joint_->qrel, 0, 1, 0, + std::max(-1.0f, + std::min(1.0f, a_vel_y_smoothed_more_ * -0.14f))); + // dQFromAxisAndAngle(neck_joint_->qrel, + // 0,1,0, + // std::max(-0.5f,std::min(0.5f,a_vel_y_smoothed_more_*-0.07f))); + } else if (gti % 30 == 0 + && Utils::precalc_rands_1[(gti + stream_id() * 3 + 143) + % kPrecalcRandsCount] + > 0.9f) { + // otherwise, look around occasionally.. + // else if (getScene()->stepnum()%30 == 0 and + // RandomFloat() > 0.8f) { else if (gti%30 == 0 and + // g_utils->precalc_rands_1[(gti+stream_id_*3+143)%kPrecalcRandsCount] + // > 0.8f) { + + head_turning = true; + dQFromAxisAndAngle( + neck_joint_->qrel, + Utils::precalc_rands_1[(stream_id() - gti) + % (kPrecalcRandsCount - 3)] + * 0.05f, + Utils::precalc_rands_2[(stream_id() + 42 * gti) + % kPrecalcRandsCount], + Utils::precalc_rands_3[(stream_id() + 3 * gti) + % (kPrecalcRandsCount - 1)] + * 0.05f, + 1.5f + * (Utils::precalc_rands_2[(stream_id() + gti) + % kPrecalcRandsCount] + - 0.5f)); + // dQFromAxisAndAngle(neck_joint_->qrel, + // RandomFloat()*0.05f, + // RandomFloat(), + // RandomFloat()*0.05f, + // 1.5f*(RandomFloat()-0.5f)); + } + } + } + } + + // if we're flying, keep us on a 2d plane + if (can_fly_ && !dead_) { + // lets just force our few main bodies on to the plane we want + + dBodyID b; + const dReal *p, *v; + + b = body_torso_->body(); + p = dBodyGetPosition(b); + dBodySetPosition(b, p[0], p[1], kHappyThoughtsZPlane); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0], v[1], 0.0f); + + b = body_pelvis_->body(); + p = dBodyGetPosition(b); + dBodySetPosition(b, p[0], p[1], kHappyThoughtsZPlane); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0], v[1], 0.0f); + + b = body_head_->body(); + p = dBodyGetPosition(b); + dBodySetPosition(b, p[0], p[1], kHappyThoughtsZPlane); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0], v[1], 0.0f); + } + } + + // flap wings every now and then + if (wings_) { + if (scene()->stepnum() % 21 == 0 && RandomFloat() > 0.9f) { + flapping_ = true; + } + if (scene()->stepnum() % 20 == 0 && RandomFloat() > 0.7f) { + flapping_ = false; + } + } + + // update eyes.. + if (!frozen_) { + // Dart our eyes randomly (and always do it when we're turning our head. + bool spinning = (std::abs(a_vel_y_smoothed_) > 10.0f); + + if (scene()->stepnum() % 20 == 0 || head_turning || spinning) { + if (RandomFloat() > 0.7f || head_turning || spinning) { + eyes_ud_ = 20.0f * (RandomFloat() - 0.5f); + + // bias our eyes in the direction we're turning part of the time.. + float spinBias = RandomFloat() > 0.5f ? a_vel_y_smoothed_ * 0.16f : 0; + eyes_lr_ = + 70.0f + * std::max(-0.4f, + std::min(0.4f, ((RandomFloat() - 0.5f) + spinBias))); + } + } + if (scene()->stepnum() % 100 == 0 || head_turning) { + if (RandomFloat() > 0.7f || head_turning) { + eyelid_left_ud_ = 30.0f * (RandomFloat() - 0.5f); + eyelid_right_ud_ = 30.0f * (RandomFloat() - 0.5f); + } + } + // blink every now and then + if (scene()->stepnum() % 20 == 0 && RandomFloat() > 0.92f) { + blink_ = 2.0f; + } + + if (spinning) { + blink_ = 2.0f; + } + + // shut our eyes if we're knocked out (unless we're flying thru the air) + // if (knockout_ and footing_) blink_ = 2.0f; + if (knockout_) { + blink_ = 2.0f; + } + + if (dead_) { + blink_ = 2.0f; + } + + blink_ = std::max(0.0f, blink_ - 0.14f); + + blink_smooth_ += 0.25f * (std::min(1.0f, blink_) - blink_smooth_); + eyes_ud_smooth_ += 0.3f * (eyes_ud_ - eyes_ud_smooth_); + eyes_lr_smooth_ += 0.3f * (eyes_lr_ - eyes_lr_smooth_); + eyelid_left_ud_smooth_ += 0.1f * (eyelid_left_ud_ - eyelid_left_ud_smooth_); + eyelid_right_ud_smooth_ += + 0.1f * (eyelid_right_ud_ - eyelid_right_ud_smooth_); + + // eyelid tilt (angry look) + { + float smooth = 0.8f; + float this_angle; + if (running_fast || punch_) { + this_angle = 25.0f; + } else { + this_angle = default_eye_lid_angle_; + } + eye_lid_angle_ = smooth * eye_lid_angle_ + (1.0f - smooth) * this_angle; + } + } + + // if we're dead, fall over + if (dead_ && (knockout_ == 0)) { + knockout_ = 1; + } + + // so we dont get stuck up in the air if something under + // us goes away + if (footing_ == 0) { + dBodyEnable(body_head_->body()); + } + + // Newer behavior-versions have 'dizzy' functionality (we get knocked out if + // we spin too long) + if (behavior_version_ > 0) { + // Testing: lose balance while spinning fast. + if (std::abs(a_vel_y_smoothed_more_) > 10.0f) { + dizzy_ += 1; + if (dizzy_ > 120) { + dizzy_ = 0; + knockout_ = 40; + PlayHurtSound(); + } + } else { + dizzy_ = static_cast_check_fit( + std::max(0, static_cast(dizzy_) - 2)); + } + } + + if (knockout_ > 0 || frozen_) { + balance_ = 0; + } else { + if (footing_) { + if (balance_ < 100) { // NOLINT(bugprone-branch-clone) + balance_ += 20; + } else if (balance_ < 235) { + balance_ += 20; + } else if (balance_ < 255) { + balance_++; + } + } else { + if (balance_ > 100) { + balance_ -= 20; + } else if (balance_ > 10) { + balance_ -= 5; + } else if (balance_ > 0) { + balance_--; + } + } + } + + // knockout wears off more slowly if we're airborn + // (prevents landing on ones feet too much) + if (knockout_ > 0 && (scene()->stepnum() % (footing_ ? 5 : 10) == 0) + && !dead_) { + knockout_--; + if (knockout_ == 0) { + dBodyEnable(body_head_->body()); + } + } + + // if we're wanting to throw something... + if (throwing_) { + throwing_ = false; + DropHeldObject(); + } + + // if we're flying, spin based on the direction we're holding + if (can_fly_ && trying_to_fly_ && !footing_ && !frozen_ && !knockout_) { + const dReal* av = dBodyGetAngularVel(body_torso_->body()); + + float mag_scale = sqrtf(lr_smooth_ * lr_smooth_ + ud_smooth_ * ud_smooth_); + float mag; + if (mag_scale > 0.1f) { + float a = AngleBetween2DVectors(lr_smooth_, ud_smooth_, + (p_head[0] - p_torso[0]), + (p_head[1] - p_torso[1])); + if (a < 0) { + mag = mag_scale * 20.0f; + } else { + mag = -mag_scale * 20.0f; + } + if (std::abs(a) < 0.8f) { + mag *= std::abs(a) / 0.8f; + } + } else { + mag = 0.0f; + } + + mag += av[2] * -2.0f * mag_scale; // brakes + + dBodyAddTorque(body_torso_->body(), 0, 0, mag); + + // also slow down a bit in flight + dBodyID b; + const dReal* v; + + // get a velocity difference based on our speed and sub that from everything + // ...simpler than applying forces which might be uneven and spin us + float sub = dBodyGetLinearVel(body_torso_->body())[0] * -0.02f; + + b = body_torso_->body(); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0] + sub, v[1], v[2]); + + b = body_head_->body(); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0] + sub, v[1], v[2]); + + b = body_pelvis_->body(); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0] + sub, v[1], v[2]); + + b = body_roller_->body(); + v = dBodyGetLinearVel(b); + dBodySetLinearVel(b, v[0] + sub, v[1], v[2]); + } + + if (fly_power_ > 0.0001f && !knockout_) { + const dReal* p_top = dBodyGetPosition(body_torso_->body()); + const dReal* p_bot = dBodyGetPosition(body_roller_->body()); + dBodyEnable(body_torso_->body()); // wake it up + // float mag = 550*0.004f * fly_power_; + // float up_mag = 150*0.004f * fly_power_; + float mag = 550.0f * 0.005f * fly_power_; // 120hz change + float up_mag = 150.0f * 0.005f * fly_power_; // 120hz change + float fx = mag * (p_top[0] - p_bot[0]); + float fy = mag * (p_top[1] - p_bot[1]); + float head_scale = 0.5f; + dBodyAddForce(body_head_->body(), head_scale * fx, head_scale * fy, 0); + dBodyAddForce(body_head_->body(), 0, head_scale * up_mag, 0); + dBodyAddForce(body_torso_->body(), fx, fy, 0); + dBodyAddForce(body_torso_->body(), 0, up_mag, 0); + + // also add some force to what we're holding so popping out a bomb doesnt + // send us spiraling down to death + if (holding_something_) { + Node* a = hold_node_.get(); + if (a) { + float scale = 0.2f; + RigidBody* b = a->GetRigidBody(hold_body_); + if (b) { + dBodyAddForce(b->body(), fx * scale, fy * scale, 0); + dBodyAddForce(b->body(), 0, up_mag * scale, 0); + } + } + } + } + + // torso + { + dBodyID b = stand_body_->body(); + const dReal* p_torso2 = dBodyGetPosition(body_torso_->body()); + const dReal* p_bot = dBodyGetPosition(body_roller_->body()); + const dReal* lv = dBodyGetLinearVel(body_torso_->body()); + + dBodySetLinearVel(b, lv[0], lv[1], lv[2]); + dBodySetAngularVel(b, 0, 0, 0); + + // Update the orientation of our stand body. + // If we're pressing the joystick, that's the direction we use. + // The moment we stop, though, we instead use the direction our torso is + // pointing. (we dont wanna keep turning once we let off the joystick) The + // only alternative is to turn off angular stiffness on the constraint but + // then we spin and stuff. + + // Also let's calculate tilt. For this we guesstimate how fast we wanna be + // going given our UD/LR values and we tilt forward or back depending on + // where we are relative to that. + float tilt_lr, tilt_ud; + dBodySetPosition(b, p_torso2[0], p_bot[1] + 0.2f, p_torso2[2]); + + float rotate_tilt = 0.4f; + + if (hockey_) { + const dReal* b_vel_3 = dBodyGetLinearVel(body_roller_->body()); + float v_mag = std::max(5.0f, Vector3f(b_vel_3).Length()); + float accel_smoothing = 0.9f; + for (int i = 0; i < 3; i++) { + float avg_vel = (b_vel_3[i]); + accel_[i] = accel_smoothing * accel_[i] + + (1.0f - accel_smoothing) * (avg_vel - prev_vel_[i]); + prev_vel_[i] = avg_vel; + } + tilt_lr = std::min(1.0f, std::max(-1.0f, v_mag * accel_[0] * 1.4f)); + tilt_ud = std::min(1.0f, std::max(-1.0f, v_mag * accel_[2] * -1.4f)); + } else { + // non-hockey + + const dReal* b_vel_3 = dBodyGetLinearVel(body_roller_->body()); + float v_mag = std::max(7.0f, Vector3f(b_vel_3).Length()); + float accel_smoothing = 0.7f; + for (int i = 0; i < 3; i++) { + float avg_vel = (b_vel_3[i]); + accel_[i] = accel_smoothing * accel_[i] + + (1.0f - accel_smoothing) * (avg_vel - prev_vel_[i]); + prev_vel_[i] = avg_vel; + } + tilt_lr = (0.2f + 0.8f * run_gas_) + * std::min(0.9f, std::max(-0.9f, v_mag * accel_[0] * 0.3f)); + tilt_ud = (0.2f + 0.8f * run_gas_) + * std::min(0.9f, std::max(-0.9f, v_mag * accel_[2] * -0.3f)); + + float fast = std::min(1.0f, speed_smoothed_ / 5.0f); + + // A sharper tilt at low speeds (so we dont whiplash when walking). + tilt_lr += (1.0f - fast) * (lr_diff_smooth_ * 10.0f); + tilt_ud += (1.0f - fast) * (ud_diff_smooth_ * 10.0f); + + tilt_lr += fast * (lr_diff_smoother_ * 30.0f); + tilt_ud += fast * (ud_diff_smoother_ * 30.0f); + + rotate_tilt *= 1.2f; + } + if (holding_something_) { + rotate_tilt *= 0.5f; + } + + // Lean less if we're spinning. Otherwise we go jumping all crazy to the + // side. + const dReal spin = std::abs(dBodyGetAngularVel(body_torso_->body())[1]); + if (spin > 10.0f) { + rotate_tilt = 0.0f; + } + + float this_punch_dir_x{}; + float this_punch_dir_z{}; + + // If we're moving, we orient our stand-body to that exact direction. + if (lr_ || ud_) { + // If we're holding position we can't use lr_norm_/ud_norm_ here because + // they'll be zero (or close). So in that case just calc a normalized + // lr_/_ud here. + + float this_ud_norm, this_lr_norm; + if (hold_position_pressed_) { + this_ud_norm = (static_cast(ud_) / 127.0f); + this_lr_norm = (static_cast(lr_) / 127.0f); + if (clamp_move_values_to_circle_) { + BoxClampToCircle(&this_lr_norm, &this_ud_norm); + } else { + BoxNormalizeToCircle(&this_lr_norm, &this_ud_norm); + } + } else { + this_ud_norm = ud_norm_; + this_lr_norm = lr_norm_; + } + dMatrix3 r; + RotationFrom2Axes(r, -this_ud_norm, 0, -this_lr_norm, + rotate_tilt * tilt_lr, 1, -rotate_tilt * tilt_ud); + dBodySetRotation(b, r); + + // Also update our punch direction. + this_punch_dir_x = this_lr_norm; + this_punch_dir_z = -this_ud_norm; + } else { + // We're not moving; orient our stand body to match our torso. + dMatrix3 r; + dVector3 p_forward; + dBodyGetRelPointPos(body_torso_->body(), 1, 0, 0, p_forward); + + // Doing this repeatedly winds up turning us slowly in circles + // ..so lets recycle previous values if we haven't changed much. + float orientX = p_forward[0] - p_torso2[0]; + float orientZ = p_forward[2] - p_torso2[2]; + if (std::abs(orientX - last_stand_body_orient_x_) > 0.05f + || std::abs(orientZ - last_stand_body_orient_z_) > 0.05f) { + last_stand_body_orient_x_ = orientX; + last_stand_body_orient_z_ = orientZ; + } + + RotationFrom2Axes(r, last_stand_body_orient_x_, 0, + last_stand_body_orient_z_, rotate_tilt * tilt_lr, 1, + -rotate_tilt * tilt_ud); + + dBodySetRotation(b, r); + + this_punch_dir_z = (p_forward[0] - p_torso2[0]); + this_punch_dir_x = -(p_forward[2] - p_torso2[2]); + } + + // Update and re-normalize punch dir. + { + float blend = 0.5f; + punch_dir_x_ = (1.0f - blend) * this_punch_dir_x + blend * punch_dir_x_; + punch_dir_z_ = (1.0f - blend) * this_punch_dir_z + blend * punch_dir_z_; + + float len = + sqrtf(punch_dir_x_ * punch_dir_x_ + punch_dir_z_ * punch_dir_z_); + float mult = len == 0.0f ? 9999 : 1.0f / len; + punch_dir_x_ *= mult; + punch_dir_z_ *= mult; + } + + // Rotate our attach-point to give some sway while running. + { + float angle = + sinf(roll_amt_ - 3.141592f) + * (run_gas_ * 0.09f + (1.0f - run_gas_) * (female_ ? 0.02f : 0.05f)); + dQFromAxisAndAngle(stand_joint_->qrel, 0, 1, 1, angle); + } + + { + float bal = static_cast(balance_) / 255.0f; + + bal = 1.0f + - ((1.0f - bal) * (1.0f - bal) * (1.0f - bal) + * (1.0f - bal)); // push it towards 1 + float mult = bal; + + // Crank up our balance when we're holding something otherwise we get a + // bit soupy. + if (holding_something_) { + mult *= 0.9f; + } else { + mult *= 0.6f; + } + + { + stand_joint_->linearStiffness = 0.0f; + stand_joint_->linearDamping = 0.0f; + stand_joint_->angularStiffness = 180.0f * mult; + stand_joint_->angularDamping = 3.0f * mult; + } + + // Crank down angular forces at low speeds to keep from looking too stiff. + { + dVector3 f = {ud_norm_, 0, lr_norm_}; + float m = dVector3Length(f); + float blend_max = 1.0f; + if (m < blend_max) { + stand_joint_->angularDamping *= 0.3f + 0.7f * (m / blend_max); + stand_joint_->angularStiffness *= 0.6f + 0.4f * (m / blend_max); + } + } + } + } + + // Resize our run-ball based on our balance. + // (so when we're laying on the ground its not propping our legs up in the + // air) + { + if (knockout_ || frozen_) + ball_size_ = 0.0f; + else + ball_size_ = std::min(1.0f, ball_size_ + 0.05f); + + float sz = 0.1f + 0.9f * ball_size_; + body_roller_->SetDimensions( + 0.3f * sz, 0, 0, 0.3f, 0, + 0, // keep its mass the same as its full-size self though + 0.1f); + } + + // Push our roller-ball down for jumps and retract it when we're hurt. + { + // Retract it up as well so when it pops back up it doesnt start + // underground. + float offs = (1.0f - ball_size_) * 0.3f; + float ls_scale = 1.0f; + float ld_scale = 1.0f; + if (jump_ > 0 && !frozen_ && !knockout_) { + offs -= 0.3f; + ls_scale = 0.6f; + ld_scale = 0.2f; + } + roller_ball_joint_->linearStiffness = kRollerBallLinearStiffness * ls_scale; + roller_ball_joint_->linearDamping = kRollerBallLinearDamping * ld_scale; + offs -= breath * 0.02f; + roller_ball_joint_->anchor1[1] = base_pelvis_roller_anchor_offset_ + offs; + } + + // Roll our run-ball (new). + { + { + float mult; + if (frozen_ || hold_position_pressed_) { + mult = 0.0f; + } else { + mult = std::min(1.0f, static_cast(balance_) / 100.0f); + } + + // hockey.. + if (hockey_) { + dBodyEnable(body_roller_->body()); + dJointSetAMotorParam(a_motor_roller_, dParamFMax, 30.0f * mult); + dJointSetAMotorParam(a_motor_roller_, dParamFMax2, 10.0f * mult); + dJointSetAMotorParam(a_motor_roller_, dParamFMax3, 30.0f * mult); + dJointSetAMotorParam(a_motor_roller_, dParamVel, + -0.17f * 128.0f * ud_norm_); + dJointSetAMotorParam(a_motor_roller_, dParamVel2, 0.0f); + dJointSetAMotorParam(a_motor_roller_, dParamVel3, + -0.17f * 128.0f * lr_norm_); + } else { + const dReal* vel = dBodyGetLinearVel(body_roller_->body()); + dVector3 v = {vel[0], vel[1], vel[2]}; + + // Old settings to keep the demo working. + if (demo_mode_) { + // We want to speed up faster going downhill and slower going uphill + // (getting the base physics to do that leaves us with a + // hard-to-control character) + // So we fake it by skewing our smoothed speed faster on downhill + // and slower uphill. + float speed_scale = 1.0f; + float walk_scale; + + // Heading downhill: speed up. + if (v[1] < 0.0f) { + v[1] *= 2.0f; // just scale our downward component up to bias the + // speed calc + walk_scale = 1.0f - v[1] * 0.1f; + } else { + // Heading uphill: slow down. + speed_scale = std::max(0.0f, 1.0f - v[1] * 0.2f); + walk_scale = std::max(0.0f, 1.0f - v[1] * 0.2f); + v[1] = 0.0f; + } + + // Our smoothed spead increases slowly and decreases fast. + float speed = dVector3Length(v) * speed_scale; + float speed_smoothing = (speed > speed_smoothed_) ? 0.985f : 0.7f; + speed_smoothed_ = speed_smoothing * speed_smoothed_ + + (1.0f - speed_smoothing) * speed; + + float gear_high = std::min(1.0f, speed_smoothed_ / 7.0f); + float gear_low = 1.0f - gear_high; + + // As we 'shift up' in gears our max-force goes up and target velocity + // goes down. + float max_force = gear_low * 15.0f + gear_high * 15.0f; + float max_vel = walk_scale * 7.68f + gear_high * run_gas_ * 15.0f; + dBodyEnable(body_roller_->body()); + dJointSetAMotorParam(a_motor_roller_, dParamFMax, + max_force * mult); // change for 120hz + dJointSetAMotorParam(a_motor_roller_, dParamFMax2, + 500.0f * mult); // 120hz change + dJointSetAMotorParam(a_motor_roller_, dParamFMax3, + max_force * mult); // change for 120hz + dJointSetAMotorParam(a_motor_roller_, dParamVel, -max_vel * ud_norm_); + dJointSetAMotorParam(a_motor_roller_, dParamVel2, 0.0f); + dJointSetAMotorParam(a_motor_roller_, dParamVel3, + -max_vel * lr_norm_); + } else { + // We want to speed up faster going downhill and slower going uphill + // (getting the base physics to do that leaves us with a + // hard-to-control character) + // ...so we fake it by skewing our smoothed speed faster on downhill + // and slower uphill + float speed_scale = 1.0f; + float walk_scale = + 1.0f; // if we're just walking, how fast we'll go.. + // heading downhill - speed up + if (footing_) { + if (v[1] < 0.0f) { + v[1] *= 2.0f; // just scale our downward component up to bias the + // speed calc + walk_scale = 1.0f - v[1] * 0.1f; + } else { + // heading uphill - slow down + speed_scale = std::max(0.0f, 1.0f - v[1] * 0.2f); + walk_scale = std::max(0.0f, 1.0f - v[1] * 0.2f); + v[1] = 0.0f; // also don't count upward velocity towards our + // speed calc.. + } + } + + // our smoothed spead increases slowly and decreases fast + float speed = dVector3Length(v) * speed_scale; + float speed_smoothing = (speed > speed_smoothed_) ? 0.985f : 0.94f; + speed_smoothed_ = speed_smoothing * speed_smoothed_ + + (1.0f - speed_smoothing) * speed; + + float gear_high = std::min(1.0f, speed_smoothed_ / 7.0f); + float gear_low = 1.0f - gear_high; + + // as we 'shift up' in gears our max-force goes up and target velocity + // goes down + float max_force = gear_low * 15.0f + gear_high * 15.0f; + float max_vel = walk_scale * 7.68f + gear_high * run_gas_ * 15.0f; + dBodyEnable(body_roller_->body()); + dJointSetAMotorParam(a_motor_roller_, dParamFMax, + max_force * mult); // change for 120hz + dJointSetAMotorParam(a_motor_roller_, dParamFMax2, + 500.0f * mult); // 120hz change + dJointSetAMotorParam(a_motor_roller_, dParamFMax3, + max_force * mult); // change for 120hz + dJointSetAMotorParam(a_motor_roller_, dParamVel, -max_vel * ud_norm_); + dJointSetAMotorParam(a_motor_roller_, dParamVel2, 0.0f); + dJointSetAMotorParam(a_motor_roller_, dParamVel3, + -max_vel * lr_norm_); + } + } + } + } + + // Set brake motor strength. + if (footing_ || frozen_ || dead_) { + float amt; + // Full brakes if frozen. Otherwise crank up as our joystick magnitude goes + // down. + if (frozen_ || dead_) { + amt = 1.0f; + } else { + dVector3 f = {lr_norm_, 0, ud_norm_}; + amt = std::min(1.0f, dVector3Length(f) * 5.0f); + amt = 1.0f - (amt * amt * amt); + amt *= (1.0f - run_gas_); + amt *= 0.4f; + } + dJointSetAMotorParam(a_motor_brakes_, dParamFMax, 10.0f * amt); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax2, 10.0f * amt); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax3, 10.0f * amt); + dJointSetAMotorParam(a_motor_brakes_, dParamVel, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamVel2, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamVel3, 0.0f); + } else { + // if we're not on the ground we wanna just keep doing what we're doing + dJointSetAMotorParam(a_motor_brakes_, dParamFMax, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax2, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamFMax3, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamVel, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamVel2, 0.0f); + dJointSetAMotorParam(a_motor_brakes_, dParamVel3, 0.0f); + } + + // If we're knocked out, stop any mid-progress punch. + if (knockout_) { + punch_ = 0; + } + + if (punch_ > 0) { + if (!body_punch_.exists() && since_last_punch > 80 && !knockout_) { + body_punch_ = Object::New( + kPunchBodyID, &punch_part_, RigidBody::Type::kGeomOnly, + RigidBody::Shape::kSphere, RigidBody::kCollideRegion, + RigidBody::kCollideAll); + body_punch_->SetDimensions(0.25f); + } + + if (body_punch_.exists()) { + // Move the punch body to the end of our punching arm. + dBodyID fist_body = punch_right_ ? lower_right_arm_body_->body() + : lower_left_arm_body_->body(); + dVector3 p; + dBodyGetRelPointPos(fist_body, 0, 0, 0.01f, p); + + // Move it down a tiny bit since we're often trying to punch dudes laying + // on the ground. + p[1] -= 0.1f; + + dGeomSetPosition(body_punch_->geom(), p[0], p[1], p[2]); + } + + } else { + if (body_punch_.exists()) { + body_punch_.Clear(); + } + } + + // If we're flying through the air really fast (preferably not on purpose), + // scream. + const dReal* p_head_vel = dBodyGetLinearVel(body_head_->body()); + float vel_mag_squared = p_head_vel[0] * p_head_vel[0] + + p_head_vel[1] * p_head_vel[1] + + p_head_vel[2] * p_head_vel[2]; + + float scream_speed = can_fly_ ? 160.0f : 100.0f; + if ((force_scream_ && scene()->time() - last_force_scream_time_ < 3000) + || (scene()->time() - last_fly_time_ > 1000 + && vel_mag_squared > scream_speed && !footing_ + && std::abs(p_head_vel[1]) > 0.3f && !dead_)) { + if (scene()->time() - last_fall_time_ > 1000) { + // If we're not still screaming, start one up. + if (!(voice_play_id_ == fall_play_id_ + && g_audio->IsSoundPlaying(fall_play_id_))) { + if (Sound* sound = GetRandomMedia(fall_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + g_audio->PushSourceStopSoundCall(voice_play_id_); + source->SetPosition(p_head[0], p_head[1], p_head[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + fall_play_id_ = voice_play_id_; + source->End(); + } + } + } + last_fall_time_ = scene()->time(); + } + } + + // If theres a scream going on, update its position and stop it if we've + // slowed down alot. + if (voice_play_id_ == fall_play_id_) { + if ((footing_ && !force_scream_) + || (force_scream_ + && scene()->time() - last_force_scream_time_ > 2000)) { + g_audio->PushSourceStopSoundCall(voice_play_id_); + voice_play_id_ = 0xFFFFFFFF; + } else { + AudioSource* s = g_audio->SourceBeginExisting(fall_play_id_, 108); + if (s) { + s->SetPosition(p_head[0], p_head[1], p_head[2]); + s->End(); + } + } + } + + // Update ticking. + if (tick_play_id_ != 0xFFFFFFFF) { + AudioSource* s = g_audio->SourceBeginExisting(tick_play_id_, 109); + if (s) { + s->SetPosition(p_head[0], p_head[1], p_head[2]); + s->End(); + } + } + + // If we're in the process of throwing something + // ( we need to check have_thrown_ because otherwise we'll always think + // we're throwing at game-time 0 since throw_start_ inits to that.) + if (have_thrown_ && scene()->time() - throw_start_ < 50) { + Node* a = hold_node_.get(); + if (a) { + RigidBody* b = a->GetRigidBody(hold_body_); + if (b) { + dVector3 f; + float power; + if (throw_power_ < 0.1f) { + power = -0.2f - 1 * (0.1f - throw_power_); + } else { + power = (throw_power_ - 0.1f) * 1.0f; + } + + power *= 1.15f; // change for 120hz + dBodyVectorToWorld(body_torso_->body(), 0, 60, 60, f); + + // If we're pressing a direction, factor that in. + float lrf = throw_lr_; + float udf = throw_ud_; + if (clamp_move_values_to_circle_) { + BoxClampToCircle(&lrf, &udf); + } else { + BoxNormalizeToCircle(&lrf, &udf); + } + + // Blend based on magnitude of our locked in throw speed. + float d_len = sqrtf(lrf * lrf + udf * udf); + if (d_len > 0.0f) { + // Let's normalize our locked in throw direction. + // 'throwPower' should be our sole magnitude determinant. + float dist = sqrtf(throw_lr_ * throw_lr_ + throw_ud_ * throw_ud_); + float s = 1.0f / dist; + lrf *= s; + udf *= s; + + float f2[3]; + f2[0] = lrf * 50.0f; + f2[1] = 80.0f; + f2[2] = -udf * 50.0f; + if (d_len > 0.1f) { + f[0] = f2[0]; + f[1] = f2[1]; + f[2] = f2[2]; + } else { + float blend = d_len / 0.1f; + f[0] = blend * f2[0] + (1.0f - blend) * f[0]; + f[1] = blend * f2[1] + (1.0f - blend) * f[1]; + f[2] = blend * f2[2] + (1.0f - blend) * f[2]; + } + } + + dBodyEnable(body_torso_->body()); // wake it up + dBodyEnable(b->body()); // wake it up + const dReal* p = dBodyGetPosition(b->body()); + + float kick_back = -0.25f; + + // Pro trick: if we throw while still holding bomb down, we throw + // backwards lightly. + if (bomb_pressed_ && !throwing_with_bomb_button_) { + float neg = -0.2f; + dBodyAddForceAtPos(b->body(), neg * power * f[0], + std::abs(neg * power * f[1]), neg * power * f[2], + p[0], p[1] - 0.1f, p[2]); + dBodyAddForceAtPos(body_torso_->body(), -neg * power * f[0], + std::abs(-neg * power * f[1]), -neg * power * f[2], + p[0], p[1] - 0.1f, p[2]); + } else { + dBodyAddForceAtPos(b->body(), power * f[0], std::abs(power * f[1]), + power * f[2], p[0], p[1] - 0.1f, p[2]); + dBodyAddForceAtPos(body_torso_->body(), kick_back * power * f[0], + kick_back * (std::abs(power * f[1])), + kick_back * power * f[2], p[0], p[1] - 0.1f, p[2]); + } + } + } + } else { + // If we're no longer holding something and our throw is over, clear any ref + // we might have. + if (!holding_something_ && hold_node_.exists()) hold_node_.Clear(); + } + + if (pickup_ == kPickupCooldown - 4) { + if (!body_pickup_.exists()) { + body_pickup_ = Object::New( + kPickupBodyID, &pickup_part_, RigidBody::Type::kGeomOnly, + RigidBody::Shape::kSphere, RigidBody::kCollideRegion, + RigidBody::kCollideActive); + body_pickup_->SetDimensions(0.7f); + } + } else { + if (body_pickup_.exists()) { + body_pickup_.Clear(); + } + } + + if (body_pickup_.exists()) { + // A unit vector forward. + dVector3 f; + float z = 0.3f; + dBodyVectorToWorld(body_head_->body(), 0, 0, 1, f); + dGeomSetPosition(body_pickup_->geom(), + 0.5f * (p_head[0] + p_torso[0]) + z * f[0], + 0.5f * (p_head[1] + p_torso[1]) + z * f[1], + 0.5f * (p_head[2] + p_torso[2]) + z * f[2]); + } + + // If we're holding something and it died, tell userland. + if (holding_something_) { + if (!pickup_joint_.IsAlive()) { + holding_something_ = false; + DispatchDropMessage(); + } + } + + if (flashing_ > 0) flashing_--; + + if (jump_ > 0) { + // *always* reduce jump even if we're holding it. + jump_ -= 1; + // jump_ = std::max(0, static_cast(jump_) - 1); + // enforce a 'minimum-held-time' so that an instant press/release still + // results in a measurable jump (we tend to get these from remotes/etc) + // cout << "DIFF " << getScene().time()-last_jump_time_ << endl; + // if (!jump_pressed_ and (getScene().time()-last_jump_time_ > + // 1000)) jump_ = 0.0f; + } + + // Emit fairy dust if we're flying. +#if !BA_HEADLESS_BUILD + if (fly_power_ > 20.0f && scene()->stepnum() % 3 == 1) { + for (int i = 0; i < 1; i++) { + BGDynamicsEmission e; + e.emit_type = BGDynamicsEmitType::kFairyDust; + e.position = Vector3f(dGeomGetPosition(body_torso_->geom())); + e.velocity = Vector3f(dBodyGetLinearVel(body_torso_->body())); + e.count = 1; + e.scale = 1.0f; + e.spread = 1.0f; + g_bg_dynamics->Emit(e); + } + } +#endif // !BA_HEADLESS_BUILD + + fly_power_ *= 0.95f; + + if (punch_ > 0) { + punch_--; + } + if (pickup_ > 0) { + pickup_--; + } + + UpdateAreaOfInterest(); + + // Update our recent-damage tally. + damage_smoothed_ *= 0.8f; + + // If we're out of bounds, arrange to have ourself informed. + if (!dead_) { + const dReal* p = dBodyGetPosition(body_head_->body()); + if (scene()->IsOutOfBounds(p[0], p[1], p[2])) { + scene()->AddOutOfBoundsNode(this); + last_out_of_bounds_time_ = scene()->time(); + } + } + BA_DEBUG_CHECK_BODIES(); +} // NOLINT (yeah i know, this is too long) + +#if !BA_HEADLESS_BUILD +static void DrawShadow(const BGDynamicsShadow& shadow, float radius, + float density, const float* shadow_color) { + float s_scale, s_density; + shadow.GetValues(&s_scale, &s_density); + float d = s_density * density; + g_graphics->DrawBlotch(shadow.GetPosition(), radius * s_scale * 4.0f, + (0.08f + 0.04f * shadow_color[0]) * d, + (0.07f + 0.04f * shadow_color[1]) * d, + (0.065f + 0.04f * shadow_color[2]) * d, 0.32f * d); +} +static void DrawBrightSpot(const BGDynamicsShadow& shadow, float radius, + float density, const float* shadow_color) { + float s_scale, s_density; + shadow.GetValues(&s_scale, &s_density); + float d = s_density * density * 0.3f; + g_graphics->DrawBlotch(shadow.GetPosition(), radius * s_scale * 4.0f, + shadow_color[0] * d, shadow_color[1] * d, + shadow_color[2] * d, 0.0f); +} +#endif // !BA_HEADLESS_BUILD + +void SpazNode::DrawEyeBalls(RenderComponent* c, ObjectComponent* oc, + bool shading, float death_fade, float death_scale, + float* add_color) { + // Eyeballs. + if (blink_smooth_ < 0.9f) { + if (shading) { + oc->SetLightShadow(LightShadowType::kObject); + oc->SetTexture(g_media->GetTexture(SystemTextureID::kEye)); + oc->SetColorizeColor(eye_color_red_, eye_color_green_, eye_color_blue_); + oc->SetColorizeTexture(g_media->GetTexture(SystemTextureID::kEyeTint)); + oc->SetReflection(ReflectionType::kSharpest); + oc->SetReflectionScale(3, 3, 3); + oc->SetAddColor(add_color[0], add_color[1], add_color[2]); + oc->SetColor(eye_ball_color_red_, eye_ball_color_green_, + eye_ball_color_blue_); + } + c->PushTransform(); + c->TransformToBody(*body_head_); + if (eye_scale_ != 1.0f) c->Scale(eye_scale_, eye_scale_, eye_scale_); + c->PushTransform(); + c->Translate(eye_offset_x_, eye_offset_y_, eye_offset_z_); + c->Rotate(-10 + eyes_ud_smooth_, 1, 0, 0); + c->Rotate(eyes_lr_smooth_, 0, 1, 0); + c->Scale(0.09f, 0.09f, 0.09f); + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + + if (!frosty_ && !eyeless_) { + c->DrawModel(g_media->GetModel(SystemModelID::kEyeBall)); + if (shading) { + oc->SetReflectionScale(2, 2, 2); + } + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + c->DrawModel(g_media->GetModel(SystemModelID::kEyeBallIris)); + } + + c->PopTransform(); + + if (!pirate_ && !frosty_ && !eyeless_) { + if (shading) { + oc->SetReflectionScale(3, 3, 3); + } + c->PushTransform(); + c->Translate(-eye_offset_x_, eye_offset_y_, eye_offset_z_); + c->Rotate(-10 + eyes_ud_smooth_, 1, 0, 0); + c->Rotate(eyes_lr_smooth_, 0, 1, 0); + c->Scale(0.09f, 0.09f, 0.09f); + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + c->DrawModel(g_media->GetModel(SystemModelID::kEyeBall)); + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + if (shading) { + oc->SetReflectionScale(2, 2, 2); + } + c->DrawModel(g_media->GetModel(SystemModelID::kEyeBallIris)); + c->PopTransform(); + } + c->PopTransform(); + } +} + +void SpazNode::SetupEyeLidShading(ObjectComponent* c, float death_fade, + float* add_color) { + c->SetTexture(g_media->GetTexture(SystemTextureID::kEye)); + c->SetColorizeTexture(nullptr); + float r, g, b; + r = eye_lid_color_red_; + g = eye_lid_color_green_; + b = eye_lid_color_blue_; + + // Fade to reddish. + if (dead_ && !frozen_) { + r *= 0.3f + 0.7f * death_fade; + g *= 0.2f + 0.7f * (death_fade * 0.5f); + b *= 0.2f + 0.7f * (death_fade * 0.5f); + } + c->SetColor(r, g, b); + c->SetAddColor(add_color[0], add_color[1], add_color[2]); + c->SetReflection(ReflectionType::kChar); + c->SetReflectionScale(0.05f, 0.05f, 0.05f); +} + +void SpazNode::DrawEyeLids(RenderComponent* c, float death_fade, + float death_scale) { + if (!has_eyelids_ && blink_smooth_ < 0.1f) return; + + c->PushTransform(); + c->TransformToBody(*body_head_); + if (eye_scale_ != 1.0f) { + c->Scale(eye_scale_, eye_scale_, eye_scale_); + } + c->Translate(eye_offset_x_, eye_offset_y_, eye_offset_z_); + + float a = eyelid_left_ud_smooth_ + 0.5f * eyes_ud_smooth_; + if (blink_smooth_ > 0.001f) { + a = blink_smooth_ * 90.0f + (1.0f - blink_smooth_) * a; + } + c->Rotate(eye_lid_angle_, 0, 0, 1); + c->Rotate(a, 1, 0, 0); + c->Scale(0.09f, 0.09f, 0.09f); + + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + + if (!frosty_ && !eyeless_) { + c->DrawModel(g_media->GetModel(SystemModelID::kEyeLid)); + } + c->PopTransform(); + + // Left eyelid. + c->FlipCullFace(); + c->PushTransform(); + c->TransformToBody(*body_head_); + if (eye_scale_ != 1.0f) c->Scale(eye_scale_, eye_scale_, eye_scale_); + + c->Translate(-eye_offset_x_, eye_offset_y_, eye_offset_z_); + a = eyelid_right_ud_smooth_ + 0.5f * eyes_ud_smooth_; + if (blink_smooth_ > 0.001f) { + a = blink_smooth_ * 90.0f + (1.0f - blink_smooth_) * a; + } + c->Rotate(-eye_lid_angle_, 0, 0, 1); + c->Rotate(a, 1, 0, 0); + c->Scale(-0.09f, 0.09f, 0.09f); + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + if (!pirate_ && !frosty_ && !eyeless_) + c->DrawModel(g_media->GetModel(SystemModelID::kEyeLid)); + c->PopTransform(); + c->FlipCullFace(); // back to normal +} + +void SpazNode::DrawBodyParts(ObjectComponent* c, bool shading, float death_fade, + float death_scale, float* add_color) { + // Set up shading. + if (shading) { + c->SetTexture(color_texture_); + c->SetColorizeTexture(color_mask_texture_); + c->SetColorizeColor(color_[0], color_[1], color_[2]); + assert(highlight_.size() == 3); + c->SetColorizeColor2(highlight_[0], highlight_[1], highlight_[2]); + c->SetLightShadow(LightShadowType::kObject); + c->SetAddColor(add_color[0], add_color[1], add_color[2]); + + // Tint blueish when frozen. + if (frozen_) { + c->SetColor(0.9f, 0.9f, 1.2f); + } else if (dead_) { + // Fade to reddish when dead. + float r = 0.3f + 0.7f * death_fade; + float g = 0.1f + 0.5f * death_fade; + float b = 0.1f + 0.5f * death_fade; + c->SetColor(r, g, b); + } + + if (frozen_) { + c->SetReflection(ReflectionType::kSharper); + c->SetReflectionScale(1.5f, 1.5f, 1.5f); + } else { + if (dead_) { + // Go mostly matte when dead. + c->SetReflection(ReflectionType::kSoft); + c->SetReflectionScale(0.03f, 0.03f, 0.03f); + } else { + c->SetReflection(ReflectionType::kChar); + c->SetReflectionScale(reflection_scale_, reflection_scale_, + reflection_scale_); + } + } + } + + // Head. + c->PushTransform(); + c->TransformToBody(*body_head_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + if (head_model_.exists()) { + c->DrawModel(head_model_->model_data()); + } + c->PopTransform(); + + // Hair tuft 1. + if (hair_front_right_body_.exists()) { + c->PushTransform(); + c->TransformToBody(*hair_front_right_body_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + c->DrawModel(g_media->GetModel(SystemModelID::kHairTuft1)); + c->PopTransform(); + + // Hair tuft 1b; just reuse tuft 1 with some extra translating. + const dReal* m = dBodyGetRotation(body_head_->body()); + c->PushTransform(); + float offs[] = {-0.03f, 0.0f, -0.13f}; + c->Translate(offs[0] * m[0] + offs[1] * m[1] + offs[2] * m[2], + offs[0] * m[4] + offs[1] * m[5] + offs[2] * m[6], + offs[0] * m[8] + offs[1] * m[9] + offs[2] * m[10]); + c->TransformToBody(*hair_front_right_body_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + c->DrawModel(g_media->GetModel(SystemModelID::kHairTuft1b)); + c->PopTransform(); + } + + // Hair tuft 2. + if (hair_front_left_body_.exists()) { + c->PushTransform(); + c->TransformToBody(*hair_front_left_body_); + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + c->DrawModel(g_media->GetModel(SystemModelID::kHairTuft2)); + c->PopTransform(); + } + + // Hair tuft 3. + if (hair_ponytail_top_body_.exists()) { + c->PushTransform(); + c->TransformToBody(*hair_ponytail_top_body_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + c->DrawModel(g_media->GetModel(SystemModelID::kHairTuft3)); + c->PopTransform(); + } + + // Hair tuft 4. + if (hair_ponytail_bottom_body_.exists()) { + c->PushTransform(); + c->TransformToBody(*hair_ponytail_bottom_body_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + c->DrawModel(g_media->GetModel(SystemModelID::kHairTuft4)); + c->PopTransform(); + } + + // Torso. + c->PushTransform(); + c->TransformToBody(*body_torso_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + if (torso_model_.exists()) { + c->DrawModel(torso_model_->model_data()); + } + c->PopTransform(); + + // Pelvis. + c->PushTransform(); + c->TransformToBody(*body_pelvis_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + if (pelvis_model_.exists()) { + c->DrawModel(pelvis_model_->model_data()); + } + c->PopTransform(); + + // Right upper arm. + c->PushTransform(); + c->TransformToBody(*upper_right_arm_body_); + + // Get the distance between the shoulder joint socket and the fore-arm + // socket.. we'll use this to stretch our upper-arm to fill the gap. + float right_stretch = 1.0f; + + if (!shattered_) { + dVector3 p_shoulder; + dBodyGetRelPointPos(body_torso_->body(), upper_right_arm_joint_->anchor1[0], + upper_right_arm_joint_->anchor1[1], + upper_right_arm_joint_->anchor1[2], p_shoulder); + dVector3 p_forearm; + dBodyGetRelPointPos(lower_right_arm_body_->body(), + lower_right_arm_joint_->anchor2[0], + upper_right_arm_joint_->anchor2[1], + upper_right_arm_joint_->anchor2[2], p_forearm); + right_stretch = std::min( + 1.6f, (Vector3f(p_shoulder) - Vector3f(p_forearm)).Length() / 0.192f); + } + + // If we've got flippers instead of arms, shorten them if we've got gloves on + // so they don't intersect as badly. + if (flippers_ && have_boxing_gloves_) { + right_stretch *= 0.5f; + } + + c->Scale(1.0f, 1.0f, right_stretch); + + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (upper_arm_model_.exists()) { + c->DrawModel(upper_arm_model_->model_data()); + } + c->PopTransform(); + + // Right lower arm. + c->PushTransform(); + c->TransformToBody(*lower_right_arm_body_); + c->PushTransform(); + c->Translate(0, 0, 0.1f); + c->Scale(1.0f, 1.0f, right_stretch); + c->Translate(0.0f, 0.0f, -0.1f); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (forearm_model_.exists() && !flippers_) { + c->DrawModel(forearm_model_->model_data()); + } + c->PopTransform(); + if (!have_boxing_gloves_) { + c->Translate(0, 0, 0.04f); + if (holding_something_) { + c->Rotate(-50, 0, 1, 0); + } else { + c->Rotate(10, 0, 1, 0); + } + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (hand_model_.exists() && !flippers_) { + c->DrawModel(hand_model_->model_data()); + } + } + c->PopTransform(); + + // Right upper leg. + c->PushTransform(); + c->TransformToBody(*upper_right_leg_body_); + + // Apply stretching if still intact. + if (!shattered_) { + dVector3 p_pelvis; + dBodyGetRelPointPos(body_pelvis_->body(), + upper_right_leg_joint_->anchor1[0], + upper_right_leg_joint_->anchor1[1], + upper_right_leg_joint_->anchor1[2], p_pelvis); + dVector3 p_lower_leg; + dBodyGetRelPointPos(lower_right_leg_body_->body(), + lower_right_leg_joint_->anchor2[0], + upper_right_leg_joint_->anchor2[1], + upper_right_leg_joint_->anchor2[2], p_lower_leg); + float stretch = std::min( + 1.6f, (Vector3f(p_pelvis) - Vector3f(p_lower_leg)).Length() / 0.20f); + c->Scale(1.0f, 1.0f, stretch); + } + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (upper_leg_model_.exists()) { + c->DrawModel(upper_leg_model_->model_data()); + } + c->PopTransform(); + + // Right lower leg. + c->PushTransform(); + c->TransformToBody(*lower_right_leg_body_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (lower_leg_model_.exists()) { + c->DrawModel(lower_leg_model_->model_data()); + } + c->PopTransform(); + + c->PushTransform(); + c->TransformToBody(*right_toes_body_); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + if (toes_model_.exists()) { + c->DrawModel(toes_model_->model_data()); + } + c->PopTransform(); + + // OK NOW LEFT SIDE LIMBS: + c->FlipCullFace(); + + // Left upper arm. + c->PushTransform(); + c->TransformToBody(*upper_left_arm_body_); + float left_stretch = 1.0f; + + // Stretch if not shattered. + if (!shattered_) { + dVector3 p_shoulder; + dBodyGetRelPointPos(body_torso_->body(), upper_left_arm_joint_->anchor1[0], + upper_left_arm_joint_->anchor1[1], + upper_left_arm_joint_->anchor1[2], p_shoulder); + dVector3 p_forearm; + dBodyGetRelPointPos(lower_left_arm_body_->body(), + lower_left_arm_joint_->anchor2[0], + upper_left_arm_joint_->anchor2[1], + upper_left_arm_joint_->anchor2[2], p_forearm); + left_stretch = std::min( + 1.6f, (Vector3f(p_shoulder) - Vector3f(p_forearm)).Length() / 0.192f); + } + + // If we've got flippers instead of arms, shorten them if we've got gloves on + // so they don't intersect as badly. + if (flippers_ && have_boxing_gloves_) { + left_stretch *= 0.5f; + } + c->Scale(-1, 1, left_stretch); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (upper_arm_model_.exists()) c->DrawModel(upper_arm_model_->model_data()); + c->PopTransform(); + + // Left lower arm. + c->PushTransform(); + c->TransformToBody(*lower_left_arm_body_); + c->Scale(-1, 1, 1); + c->PushTransform(); + c->Translate(0, 0, 0.1f); + c->Scale(1, 1, left_stretch); + c->Translate(0, 0, -0.1f); + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + } + if (forearm_model_.exists() && !flippers_) { + c->DrawModel(forearm_model_->model_data()); + } + c->PopTransform(); + if (!have_boxing_gloves_) { + c->Translate(0, 0, 0.04f); + if (holding_something_) { + c->Rotate(-50, 0, 1, 0); + } else { + c->Rotate(10, 0, 1, 0); + } + if (death_scale != 1.0f) { + c->Scale(death_scale, death_scale, death_scale); + } + if (hand_model_.exists() && !flippers_) { + c->DrawModel(hand_model_->model_data()); + } + } + c->PopTransform(); + + // Left upper leg. + c->PushTransform(); + c->TransformToBody(*upper_left_leg_body_); + + // Stretch if not shattered. + if (!shattered_) { + dVector3 p_pelvis; + dBodyGetRelPointPos(body_pelvis_->body(), upper_left_leg_joint_->anchor1[0], + upper_left_leg_joint_->anchor1[1], + upper_left_leg_joint_->anchor1[2], p_pelvis); + dVector3 p_lower_leg; + dBodyGetRelPointPos(lower_left_leg_body_->body(), + lower_left_leg_joint_->anchor2[0], + upper_left_leg_joint_->anchor2[1], + upper_left_leg_joint_->anchor2[2], p_lower_leg); + float stretch = std::min( + 1.6f, (Vector3f(p_pelvis) - Vector3f(p_lower_leg)).Length() / 0.20f); + c->Scale(-1.0f, 1.0f, stretch); + } + if (death_scale != 1.0f) + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + if (upper_leg_model_.exists()) c->DrawModel(upper_leg_model_->model_data()); + c->PopTransform(); + + // Lower leg. + c->PushTransform(); + c->TransformToBody(*lower_left_leg_body_); + c->Scale(-1.0f, 1.0f, 1.0f); + if (death_scale != 1.0f) + c->Scale(death_scale, death_scale, 0.5f + death_scale * 0.5f); + if (lower_leg_model_.exists()) { + c->DrawModel(lower_leg_model_->model_data()); + } + c->PopTransform(); + + // Toes. + c->PushTransform(); + c->TransformToBody(*left_toes_body_); + c->Scale(-1, 1, 1); + if (death_scale != 1.0f) c->Scale(death_scale, death_scale, death_scale); + if (toes_model_.exists()) c->DrawModel(toes_model_->model_data()); + c->PopTransform(); + + // RESTORE CULL + c->FlipCullFace(); +} + +static void DrawRadialMeter(MeshIndexedSimpleFull* m, SimpleComponent* c, + float amt, bool flash) { + if (flash) { + c->SetColor(1, 1, 0.4f, 0.7f); + } else { + c->SetColor(1, 1, 1, 0.6f); + } + Graphics::DrawRadialMeter(m, amt); + c->DrawMesh(m); +} + +void SpazNode::Draw(FrameDef* frame_def) { +#if !BA_HEADLESS_BUILD + +#if BA_OSTYPE_MACOS + if (g_graphics_server->renderer()->debug_draw_mode()) { + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + c.SetDoubleSided(true); + c.SetColor(1, 0, 0, 0.5f); + + c.PushTransform(); + c.TransformToBody(*body_head_); + + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0.5f, 0); + c.Vertex(0, 0, 0.5f); + c.Vertex(0, 0, 0); + c.End(); + c.PopTransform(); + + c.PushTransform(); + c.TransformToBody(*body_torso_); + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0.2f, 0); + c.Vertex(0, 0, 0.2f); + c.Vertex(0, 0, 0); + c.End(); + c.PopTransform(); + + c.PushTransform(); + c.TransformToBody(*body_pelvis_); + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0.2f, 0); + c.Vertex(0, 0, 0.2f); + c.Vertex(0, 0, 0); + c.End(); + c.PopTransform(); + + c.SetColor(0.4f, 1.0f, 0.4f, 0.2f); + c.PushTransform(); + c.TransformToBody(*stand_body_); + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0.2f, 0); + c.Vertex(0, 0, 0.5f); + c.Vertex(0, 0, 0); + + c.Vertex(0, 2.0f, 0); + c.Vertex(0, 0, 0.1f); + c.Vertex(0, 0, 0); + + c.Vertex(0, 0.2f, 0); + c.Vertex(0.5f, 0, 0); + c.Vertex(0, 0, 0); + + c.Vertex(0, 2.0f, 0); + c.Vertex(0.1f, 0, 0.0f); + c.Vertex(0, 0, 0); + + c.End(); + c.PopTransform(); + + // Punch direction. + if (explicit_bool(true)) { + c.SetColor(1, 1, 0, 0.5f); + const dReal* p = dBodyGetPosition(body_torso_->body()); + c.PushTransform(); + c.Translate(p[0], p[1], p[2]); + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0, 0); + c.Vertex(2.0f * punch_dir_x_, 0, 2.0f * punch_dir_z_); + c.Vertex(0, 0.05f, 0); + c.Vertex(0, 0, 0); + c.Vertex(0, 0.05f, 0); + c.Vertex(2.0f * punch_dir_x_, 0, 2.0f * punch_dir_z_); + c.End(); + c.PopTransform(); + } + + // Run joint foot attach. + if (explicit_bool(true)) { + c.SetColor(1, 0, 0); + c.PushTransform(); + c.TransformToBody(*lower_left_leg_body_); + JointFixedEF* j = left_leg_ik_joint_; + c.Translate(j->anchor2[0], j->anchor2[1], j->anchor2[2]); + c.Rotate(90, 1, 0, 0); + c.Scale(0.5f, 0.5f, 0.5f); + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0.1f, 0.5f); + c.Vertex(0, 0, 0.5f); + c.Vertex(0, 0, 0); + c.Vertex(0, 0, 0); + c.Vertex(0, 0, 0.5f); + c.Vertex(0, 0.1f, 0.5f); + c.End(); + c.PopTransform(); + } + + // Run joint pelvis attach. + if (explicit_bool(true)) { + c.SetColor(0, 0, 1); + c.PushTransform(); + c.TransformToBody(*body_pelvis_); + JointFixedEF* j = left_leg_ik_joint_; + c.Translate(j->anchor1[0], j->anchor1[1], j->anchor1[2]); + c.Rotate(90, 1, 0, 0); + c.Scale(0.5f, 0.5f, 0.5f); + c.BeginDebugDrawTriangles(); + c.Vertex(0, 0.1f, 0.5f); + c.Vertex(0, 0, 0.5f); + c.Vertex(0, 0, 0); + c.Vertex(0, 0, 0); + c.Vertex(0, 0, 0.5f); + c.Vertex(0, 0.1f, 0.5f); + c.End(); + c.PopTransform(); + } + + c.Submit(); + } +#endif // BA_OSTYPE_MACOS + + millisecs_t scenetime = scene()->time(); + int64_t render_frame_count = frame_def->frame_number(); + RenderPass* beauty_pass = frame_def->beauty_pass(); + + float death_fade = 1.0f; + float death_scale = 1.0f; + millisecs_t since_death = 0; + float add_color[3] = {0, 0, 0}; + + if (dead_) { + since_death = scenetime - death_time_; + if (since_death > 2000) { + death_scale = 0.0f; + } else if (since_death > 1750) { + death_scale = 1.0f - (static_cast(since_death - 1750) / 250.0f); + } else { + death_scale = 1.0f; + } + + // Slowly fade down to black. + if (frozen_) { + death_fade = 1.0f; // except when frozen.. + } else { + if (since_death < 2000) { + death_fade = 1.0f - (static_cast(since_death) / 2000.0f); + } else { + death_fade = 0.0f; + } + } + } + + // Invincible! flash white. + if (invincible_) { + if (frame_def->frame_number() % 6 < 3) { + add_color[0] = 0.12f; + add_color[1] = 0.22f; + add_color[2] = 0.0f; + } + } else if (!dead_ && flashing_ > 0) { + // Flashing red. + float flash_amount = + 1.0f - std::abs(static_cast(flashing_) - 5.0f) / 5.0f; + add_color[0] = add_color[1] = 0.8f * flash_amount; + add_color[2] = 0.0f; + } else if (!dead_ && curse_death_time_ != 0) { + // Cursed. + if (scene()->stepnum() % (static_cast(100.0f - (90.0f * 1.0f))) < 5) { + if (frozen_) { + add_color[0] = 0.2f; + add_color[1] = 0.0f; + add_color[2] = 0.4f; + } else { + add_color[0] = 0.2f; + add_color[1] = 0.0f; + add_color[2] = 0.1f; + } + } else { + if (frozen_) { + add_color[0] = 0.15f; + add_color[1] = 0.15f; + add_color[2] = 0.5f; + } else { + add_color[0] = add_color[1] = add_color[2] = 0.0f; + } + } + } else if (!dead_ && (hurt_ > 0.0f) + && (scene()->stepnum() + % (static_cast(100.0f - (90.0f * hurt_))) + < 5)) { + // Flash red periodically when hurt but not dead. + if (frozen_) { + add_color[0] = 0.33f; + add_color[1] = 0.1f; + add_color[2] = 0.4f; + } else { + add_color[0] = 0.33f; + add_color[1] = 0.0f; + add_color[2] = 0.0f; + } + } else { + if (frozen_) { + if (dead_) { + // flash bright white momentarily when dying + // ..except when falling out of bounds.. its funnier to not flash then + // if ((since_death < 200) and (scene()->time() - + // last_out_of_bounds_time_ > 3000)) { + // if ((scene()->time() - last_fall_time_ < 3000) and + // (since_death < 50)) { + // } + if ((since_death < 200) + && (scene()->time() - last_out_of_bounds_time_ > 3000)) { + // if (since_death < 200) { + float flash = 1.0f - (static_cast(since_death) / 200.0f); + add_color[0] = 0.15f + flash * 0.9f; + add_color[1] = 0.15f + flash * 0.9f; + add_color[2] = 0.5f + flash * 0.6f; + } else { + add_color[0] = 0.15f; + add_color[1] = 0.15f; + add_color[2] = 0.6f; + } + } else { + // not dead.. just add a bit for frozen-ness + add_color[0] = 0.12f; + add_color[1] = 0.12f; + add_color[2] = 0.4f; + } + } else { + // not frozen. + if (dead_) { + if ((since_death < 300) + && (scene()->time() - last_out_of_bounds_time_ > 3000)) { + float flash_r = 1.0f - (static_cast(since_death) / 300.0f); + float flash_g = + std::max(0.0f, 1.0f - (static_cast(since_death) / 250.0f)); + float flash_b = + std::max(0.0f, 1.0f - (static_cast(since_death) / 170.0f)); + add_color[0] = 2.0f * flash_r; + add_color[1] = 0.25f * flash_g; + add_color[2] = 0.25f * flash_b; + } + } + } + } + + const dReal* torso_pos_raw = dBodyGetPosition(body_torso_->body()); + float torso_pos[3]; + torso_pos[0] = torso_pos_raw[0] + body_torso_->blend_offset().x; + torso_pos[1] = torso_pos_raw[1] + body_torso_->blend_offset().y; + torso_pos[2] = torso_pos_raw[2] + body_torso_->blend_offset().z; + + // Curse time. + if (curse_death_time_ > 0 && !dead_) { + millisecs_t diff = (curse_death_time_ - scenetime) / 1000 + 1; + if (diff < 9999 && diff > 0) { + char buffer[10]; + snprintf(buffer, sizeof(buffer), "%d", static_cast(diff)); + if (curse_timer_txt_ != buffer) { + curse_timer_txt_ = buffer; + curse_timer_text_group_.SetText(curse_timer_txt_); + } + float r, g, b; + if (render_frame_count % 6 < 3) { + r = 1.0f; + g = 0.7f; + b = 0.0f; + } else { + r = 0.5f; + g = 0.0f; + b = 0.0f; + } + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + c.SetColor(r, g, b); + + int elem_count = curse_timer_text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(curse_timer_text_group_.GetElementTexture(e)); + c.SetShadow(-0.004f * curse_timer_text_group_.GetElementUScale(e), + -0.004f * curse_timer_text_group_.GetElementVScale(e), 0.0f, + 0.3f); + c.SetMaskUV2Texture( + curse_timer_text_group_.GetElementMaskUV2Texture(e)); + c.SetFlatness(1.0f); + c.PushTransform(); + c.Translate(torso_pos[0] - 0.2f, torso_pos[1] + 0.8f, + torso_pos[2] - 0.2f); + c.Scale(0.02f, 0.02f, 0.02f); + c.DrawMesh(curse_timer_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + + // Mini billboard 1. + if (scenetime < mini_billboard_1_end_time_ && !dead_) { + float amt = static_cast(mini_billboard_1_end_time_ - scenetime) + / static_cast(mini_billboard_1_end_time_ + - mini_billboard_1_start_time_); + if (amt > 0.0001f && amt <= 1.0f) { + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + bool flash = (scenetime - mini_billboard_1_start_time_ < 200 + && render_frame_count % 6 < 3); + if (!flash) { + c.SetTexture(mini_billboard_1_texture_); + } + c.PushTransform(); + c.Translate(torso_pos[0] - 0.2f, torso_pos[1] + 1.2f, + torso_pos[2] - 0.2f); + c.Scale(0.08f, 0.08f, 0.08f); + DrawRadialMeter(&billboard_1_mesh_, &c, amt, flash); + c.PopTransform(); + c.Submit(); + } + } + // mini billboard 2 + if (scenetime < mini_billboard_2_end_time_ && !dead_) { + float amt = static_cast(mini_billboard_2_end_time_ - scenetime) + / static_cast(mini_billboard_2_end_time_ + - mini_billboard_2_start_time_); + if (amt > 0.0001f && amt <= 1.0f) { + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + bool flash = (scenetime - mini_billboard_2_start_time_ < 200 + && render_frame_count % 6 < 3); + // if (!flash) + // c.SetTexture(mediaSet->GetTexture(mini_billboard_2_texture_)); + if (!flash) c.SetTexture(mini_billboard_2_texture_); + c.PushTransform(); + c.Translate(torso_pos[0], torso_pos[1] + 1.2f, torso_pos[2] - 0.2f); + c.Scale(0.09f, 0.09f, 0.09f); + DrawRadialMeter(&billboard_2_mesh_, &c, amt, flash); + c.PopTransform(); + c.Submit(); + } + } + // mini billboard 3 + if (scenetime < mini_billboard_3_end_time_ && !dead_) { + float amt = static_cast(mini_billboard_3_end_time_ - scenetime) + / static_cast(mini_billboard_3_end_time_ + - mini_billboard_3_start_time_); + if (amt > 0.0001f && amt <= 1.0f) { + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + bool flash = (scenetime - mini_billboard_3_start_time_ < 200 + && render_frame_count % 6 < 3); + if (!flash) { + c.SetTexture(mini_billboard_3_texture_); + } + c.PushTransform(); + c.Translate(torso_pos[0] + 0.2f, torso_pos[1] + 1.2f, + torso_pos[2] - 0.2f); + c.Scale(0.08f, 0.08f, 0.08f); + DrawRadialMeter(&billboard_3_mesh_, &c, amt, flash); + c.PopTransform(); + c.Submit(); + } + } + + /// draw our counter + if (!counter_text_.empty() && !dead_) { + { // icon + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + c.SetTexture(counter_texture_); + c.PushTransform(); + c.Translate(torso_pos[0] - 0.3f, torso_pos[1] + 1.47f, + torso_pos[2] - 0.2f); + c.Scale(1.5f * 0.2f, 1.5f * 0.2f, 1.5f * 0.2f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + } + { // text + if (counter_mesh_text_ != counter_text_) { + counter_mesh_text_ = counter_text_; + counter_text_group_.SetText(counter_mesh_text_); + } + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + int elem_count = counter_text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(counter_text_group_.GetElementTexture(e)); + c.SetMaskUV2Texture(counter_text_group_.GetElementMaskUV2Texture(e)); + c.SetShadow(-0.004f * counter_text_group_.GetElementUScale(e), + -0.004f * counter_text_group_.GetElementVScale(e), 0.0f, + 0.3f); + c.SetFlatness(1.0f); + c.PushTransform(); + c.Translate(torso_pos[0] - 0.1f, torso_pos[1] + 1.34f, + torso_pos[2] - 0.2f); + c.Scale(0.01f, 0.01f, 0.01f); + c.DrawMesh(counter_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + + // draw our name + if (!name_.empty()) { + auto age = static_cast(scenetime - birth_time_); + if (explicit_bool(true)) { + if (name_mesh_txt_ != name_) { + name_mesh_txt_ = name_; + name_text_group_.SetText(name_mesh_txt_, TextMesh::HAlign::kCenter, + TextMesh::VAlign::kCenter); + } + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + float extra; + if (age < 200) { + extra = age / 200.0f; + } else { + extra = std::min(1.0f, std::max(0.0f, 1.0f - (age - 600.0f) / 200.0f)); + } + + // Make sure our max color channel is non-black. + assert(name_color_.size() == 3); + float r = name_color_[0]; + float g = name_color_[1]; + float b = name_color_[2]; + if (dead_) { + r = 0.45f + 0.2f * r; + g = 0.45f + 0.2f * g; + b = 0.45f + 0.2f * b; + } + c.SetColor(r, g, b, dead_ ? 0.7f : 1.0f); + + int elem_count = name_text_group_.GetElementCount(); + float s_extra = + (IsVRMode() || GetInterfaceType() == UIScale::kSmall) ? 1.2f : 1.0f; + + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureData* t = name_text_group_.GetElementTexture(e); + if (!t->preloaded()) continue; + c.SetTexture(t); + c.SetMaskUV2Texture(name_text_group_.GetElementMaskUV2Texture(e)); + c.SetShadow(-0.0035f * name_text_group_.GetElementUScale(e), + -0.0035f * name_text_group_.GetElementVScale(e), 0.0f, + dead_ ? 0.25f : 0.5f); + c.SetFlatness(1.0f); + c.PushTransform(); + c.Translate(torso_pos[0] - 0.0f, torso_pos[1] + 0.89f + 0.4f * extra, + torso_pos[2] - 0.2f); + float s = (0.01f + 0.01f * extra) * death_scale; + float w = g_text_graphics->GetStringWidth(name_.c_str()); + if (w > 100.0f) s *= (100.0f / w); + s *= s_extra; + c.Scale(s, s, s); + c.DrawMesh(name_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + + // Draw our big billboard. + if (billboard_opacity_ > 0.001f && !dead_) { + float o = billboard_opacity_; + float s = o; + if (billboard_cross_out_) o *= (render_frame_count % 14 < 7) ? 0.8f : 0.2f; + const dReal* pos = dBodyGetPosition(body_torso_->body()); + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + c.SetColor(1, 1, 1, o); + c.SetTexture(billboard_texture_); + c.PushTransform(); + c.Translate(pos[0], pos[1] + 1.6f, pos[2] - 0.2f); + c.Scale(2.3f * 0.2f * s, 2.3f * 0.2f * s, 2.3f * 0.2f * s); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + + // Draw a red cross over it if they want. + if (billboard_cross_out_) { + float o2 = + billboard_opacity_ * ((render_frame_count % 14 < 7) ? 0.4f : 0.1f); + SimpleComponent c2(frame_def->overlay_3d_pass()); + c2.SetTransparent(true); + c2.SetColor(1, 0, 0, o2); + c2.PushTransform(); + c2.Translate(pos[0], pos[1] + 1.6f, pos[2] - 0.2f); + c2.Scale(2.3f * 0.2f * s, 2.3f * 0.2f * s, 2.3f * 0.2f * s); + c2.DrawModel(g_media->GetModel(SystemModelID::kCrossOut)); + c2.PopTransform(); + c2.Submit(); + } + } + + // Draw life bar if our life has changed recently. + { + millisecs_t fade_time = shattered_ ? 1000 : 2000; + float o{1.0f}; + millisecs_t since_last_hurt_change = scenetime - last_hurt_change_time_; + if (since_last_hurt_change < fade_time) { + SimpleComponent c(frame_def->overlay_3d_pass()); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.PushTransform(); + + o = 1.0f - static_cast(since_last_hurt_change) / fade_time; + o *= o; + const dReal* pos = dBodyGetPosition(body_torso_->body()); + + float p_left, p_right; + if (hurt_ < hurt_smoothed_) { + p_left = 1.0f - hurt_smoothed_; + p_right = 1.0f - hurt_; + } else { + p_right = 1.0f - hurt_smoothed_; + p_left = 1.0f - hurt_; + } + + // For the first moment start p_left at p_right so they can see a glimpse + // of green before it goes away. + if (since_last_hurt_change < 100) { + p_left += + (p_right - p_left) + * (1.0f - static_cast(since_last_hurt_change) / 100.0f); + } + + c.Translate(pos[0] - 0.25f, pos[1] + 1.35f, pos[2] - 0.2f); + c.Scale(0.5f, 0.5f, 0.5f); + + float height = 0.1f; + float half_height = height * 0.5f; + c.SetColor(0, 0, 0, 0.3f * o); + + c.PushTransform(); + c.Translate(0.5f, half_height); + c.Scale(1.1f, height + 0.1f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + + c.SetColor(0, 0.35f * o, 0, 0.3f * o); + + c.PushTransform(); + c.Translate(p_left * 0.5f, half_height); + c.Scale(p_left, height); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + + if (dead_ && scene()->stepnum() % 10 < 5) { + c.SetColor(1 * o, 0.3f, 0.0f, 1.0f * o); + } else { + c.SetColor(1 * o, 0.0f * o, 0.0f * o, 1.0f * o); + } + + c.PushTransform(); + c.Translate((p_left + p_right) * 0.5f, half_height); + c.Scale(p_right - p_left, height); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + + c.SetColor((dead_ && scene()->stepnum() % 10 < 5) ? 0.55f * o : 0.01f * o, + 0, 0, 0.4f * o); + + c.PushTransform(); + c.Translate((p_right + 1.0f) * 0.5f, half_height); + c.Scale(1.0f - p_right, height); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + + c.PopTransform(); + c.Submit(); + } + } + + // Draw all body parts with normal shading. + { + { + ObjectComponent c(beauty_pass); + DrawBodyParts(&c, true, death_fade, death_scale, add_color); + SetupEyeLidShading(&c, death_fade, add_color); + DrawEyeLids(&c, death_fade, death_scale); + c.Submit(); + } + { + ObjectComponent c(beauty_pass); + DrawEyeBalls(&c, &c, true, death_fade, death_scale, add_color); + c.Submit(); + } + + // In higher-quality mode, blur our eyeballs and eyelids a bit to look more + // fleshy. + if (frame_def->quality() >= GraphicsQuality::kHigher) { + PostProcessComponent c(frame_def->blit_pass()); + c.setEyes(true); + DrawEyeLids(&c, death_fade, death_scale); + DrawEyeBalls(&c, nullptr, false, death_fade, death_scale, add_color); + c.Submit(); + } + } + + // Wings. + if (wings_) { + ObjectComponent c(beauty_pass); + c.SetTransparent(false); + c.SetColor(1, 1, 1, 1.0f); + c.SetReflection(ReflectionType::kSoft); + c.SetReflectionScale(0.4f, 0.4f, 0.4f); + c.SetTexture(g_media->GetTexture(SystemTextureID::kWings)); + + // Fade to reddish on death. + if (dead_ && !frozen_) { + float r = 0.3f + 0.7f * death_fade; + float g = 0.2f + 0.7f * (death_fade * 0.5f); + float b = 0.2f + 0.7f * (death_fade * 0.5f); + c.SetColor(r, g, b); + } + + // DEBUGGING: + if (explicit_bool(false)) { + dVector3 p_wing_l, p_wing_r; + + // Draw target. + dBodyGetRelPointPos(body_torso_->body(), kWingAttachX, kWingAttachY, + kWingAttachZ, p_wing_l); + c.PushTransform(); + c.Translate(p_wing_l[0], p_wing_l[1], p_wing_l[2]); + c.Scale(0.05f, 0.05f, 0.05f); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + + // Draw wing point. + c.PushTransform(); + c.Translate(wing_pos_left_.x, wing_pos_left_.y, wing_pos_left_.z); + c.Scale(0.1f, 0.1f, 0.1f); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + + // Draw target. + dBodyGetRelPointPos(body_torso_->body(), -kWingAttachX, kWingAttachY, + kWingAttachZ, p_wing_r); + c.PushTransform(); + c.Translate(p_wing_r[0], p_wing_r[1], p_wing_r[2]); + c.Scale(0.05f, 0.05f, 0.05f); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + + // Draw wing point. + c.PushTransform(); + c.Translate(wing_pos_right_.x, wing_pos_right_.y, wing_pos_right_.z); + c.Scale(0.1f, 0.1f, 0.1f); + c.DrawModel(g_media->GetModel(SystemModelID::kBox)); + c.PopTransform(); + } + + // To draw wings, we need a matrix positioned at our torso pointing at our + // wing points. + Vector3f torso_pos2(dBodyGetPosition(body_torso_->body())); + Vector3f torsoUp = {0.0f, 0.0f, 0.0f}; + dBodyGetRelPointPos(body_torso_->body(), 0.0f, 1.0f, 0.0f, torsoUp.v); + torsoUp -= torso_pos2; // needs to be relative to body + torsoUp.Normalize(); + + Vector3f to_left_wing = wing_pos_left_ - torso_pos2; + to_left_wing.Normalize(); + Vector3f left_wing_side = Vector3f::Cross(to_left_wing, torsoUp); + left_wing_side.Normalize(); + Vector3f left_wing_up = Vector3f::Cross(left_wing_side, to_left_wing); + left_wing_up.Normalize(); + + // Draw target. + c.PushTransform(); + c.Translate(torso_pos2.x, torso_pos2.y, torso_pos2.z); + c.MultMatrix(Matrix44fOrient(left_wing_side, left_wing_up, to_left_wing).m); + if (death_scale != 1.0f) { + c.Scale(death_scale, death_scale, death_scale); + } + c.DrawModel(g_media->GetModel(SystemModelID::kWing)); + c.PopTransform(); + + Vector3f to_right_wing = wing_pos_right_ - torso_pos2; + to_right_wing.Normalize(); + Vector3f right_wing_side = Vector3f::Cross(to_right_wing, torsoUp); + right_wing_side.Normalize(); + Vector3f right_wing_up = Vector3f::Cross(right_wing_side, to_right_wing); + right_wing_up.Normalize(); + + // Draw target. + c.PushTransform(); + c.Translate(torso_pos2.x, torso_pos2.y, torso_pos2.z); + c.MultMatrix( + Matrix44fOrient(right_wing_side, right_wing_up, to_right_wing).m); + if (death_scale != 1.0f) { + c.Scale(death_scale, death_scale, death_scale); + } + c.DrawModel(g_media->GetModel(SystemModelID::kWing)); + c.PopTransform(); + c.Submit(); + } + + // Boxing gloves. + if (have_boxing_gloves_) { + ObjectComponent c(beauty_pass); + if (frozen_) { + c.SetAddColor(0.1f, 0.1f, 0.4f); + c.SetReflection(ReflectionType::kSharper); + c.SetReflectionScale(1.4f, 1.4f, 1.4f); + } else { + c.SetReflection(ReflectionType::kChar); + c.SetReflectionScale(0.6f * death_fade, 0.55f * death_fade, + 0.55f * death_fade); + + // Add extra flash when we're new. + if (scenetime - last_got_boxing_gloves_time_ < 200) { + float amt = + (static_cast(scenetime - last_got_boxing_gloves_time_) + / 2000.0f); + amt = 1.0f - (amt * amt); + c.SetAddColor(add_color[0] + amt * 0.4f, add_color[1] + amt * 0.4f, + add_color[2] + amt * 0.1f); + c.SetColor(1.0f + amt * 6.0f, 1.0f + amt * 6.0f, 1.0f + amt * 3.0f); + } else { + c.SetAddColor(add_color[0], add_color[1], add_color[2]); + + if (boxing_gloves_flashing_ && render_frame_count % 6 < 2) { + c.SetColor(2.0f, 2.0f, 2.0f); + } else { + c.SetColor(death_fade, death_fade, death_fade); + } + } + } + c.SetLightShadow(LightShadowType::kObject); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBoxingGlove)); + + c.PushTransform(); + c.TransformToBody(*lower_right_arm_body_); + if (death_scale != 1.0f) { + c.Scale(death_scale, death_scale, death_scale); + } + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.PopTransform(); + + c.FlipCullFace(); + c.PushTransform(); + c.TransformToBody(*lower_left_arm_body_); + c.Scale(-1.0f, 1.0f, 1.0f); + if (death_scale != 1.0f) { + c.Scale(death_scale, death_scale, death_scale); + } + c.DrawModel(g_media->GetModel(SystemModelID::kBoxingGlove)); + c.FlipCullFace(); + c.PopTransform(); + c.Submit(); + } + + // Light/shadows. + { + float sc[3] = {shadow_color_[0], shadow_color_[1], shadow_color_[2]}; + + if (frozen_) { + float freeze_color[] = {0.3f, 0.3f, 0.7f}; + float weight = 0.7f; + sc[0] = weight * freeze_color[0] + (1.0f - weight) * sc[0]; + sc[1] = weight * freeze_color[1] + (1.0f - weight) * sc[1]; + sc[2] = weight * freeze_color[2] + (1.0f - weight) * sc[2]; + } + + FullShadowSet* full_shadows = full_shadow_set_.get(); + if (full_shadows) { + DrawBrightSpot(full_shadows->lower_left_leg_shadow_, 0.3f * death_scale, + death_fade * (frozen_ ? 0.3f : 0.2f), sc); + DrawBrightSpot(full_shadows->lower_right_leg_shadow_, 0.3f * death_scale, + death_fade * (frozen_ ? 0.3f : 0.2f), sc); + DrawBrightSpot(full_shadows->head_shadow_, 0.45f * death_scale, + death_fade * (frozen_ ? 0.8f : 0.14f), sc); + } + + if (full_shadows) { + DrawShadow(full_shadows->torso_shadow_, 0.19f * death_scale, 0.9f, sc); + DrawShadow(full_shadows->head_shadow_, 0.15f * death_scale, 0.7f, sc); + DrawShadow(full_shadows->pelvis_shadow_, 0.15f * death_scale, 0.7f, sc); + DrawShadow(full_shadows->lower_left_leg_shadow_, 0.08f * death_scale, + 1.0f, sc); + DrawShadow(full_shadows->lower_right_leg_shadow_, 0.08f * death_scale, + 1.0f, sc); + DrawShadow(full_shadows->upper_left_leg_shadow_, 0.08f * death_scale, + 1.0f, sc); + DrawShadow(full_shadows->upper_right_leg_shadow_, 0.08f * death_scale, + 1.0f, sc); + DrawShadow(full_shadows->upper_left_arm_shadow_, 0.08f * death_scale, + 0.5f, sc); + DrawShadow(full_shadows->lower_left_arm_shadow_, 0.08f * death_scale, + 0.3f, sc); + DrawShadow(full_shadows->lower_right_arm_shadow_, 0.08f * death_scale, + 0.3f, sc); + DrawShadow(full_shadows->upper_right_arm_shadow_, 0.08f * death_scale, + 0.5f, sc); + } else { + SimpleShadowSet* simple_shadows = simple_shadow_set_.get(); + assert(simple_shadows); + DrawShadow(simple_shadows->shadow_, 0.2f * death_scale, 2.0f, sc); + } + } +#endif // !BA_HEADLESS_BUILD +} // NOLINT (yes i know this is too big) + +void SpazNode::OnGraphicsQualityChanged(GraphicsQuality q) { + UpdateForGraphicsQuality(q); +} + +void SpazNode::UpdateForGraphicsQuality(GraphicsQuality quality) { +#if !BA_HEADLESS_BUILD + if (quality >= GraphicsQuality::kMedium) { + full_shadow_set_ = Object::New(); + simple_shadow_set_.Clear(); + } else { + simple_shadow_set_ = Object::New(); + full_shadow_set_.Clear(); + } +#endif // !BA_HEADLESS_BUILD +} + +auto SpazNode::IsBrokenBodyPart(int id) -> bool { + switch (id) { + case kHeadBodyID: + return static_cast(shatter_damage_ & kNeckJointBroken); + case kUpperRightArmBodyID: + return static_cast(shatter_damage_ & kUpperRightArmJointBroken); + case kLowerRightArmBodyID: + return static_cast(shatter_damage_ & kLowerRightArmJointBroken); + case kUpperLeftArmBodyID: + return static_cast(shatter_damage_ & kUpperLeftArmJointBroken); + case kLowerLeftArmBodyID: + return static_cast(shatter_damage_ & kLowerLeftArmJointBroken); + case kUpperRightLegBodyID: + return static_cast(shatter_damage_ & kUpperRightLegJointBroken); + case kLowerRightLegBodyID: + return static_cast(shatter_damage_ & kLowerRightLegJointBroken); + case kUpperLeftLegBodyID: + return static_cast(shatter_damage_ & kUpperLeftLegJointBroken); + case kLowerLeftLegBodyID: + return static_cast(shatter_damage_ & kLowerLeftLegJointBroken); + case kPelvisBodyID: + return static_cast(shatter_damage_ & kPelvisJointBroken); + default: + return false; + } +} + +auto SpazNode::PreFilterCollision(RigidBody* colliding_body, + RigidBody* opposingbody) -> bool { + assert(colliding_body->part()->node() == this); + if (opposingbody->part()->node() == this) { + // If self-collide has gone down to zero we can just skip this completely. + // if (!frozen_ and limb_self_collide_ < 0.01f) return false; + + int ourID = colliding_body->id(); + int theirID = opposingbody->id(); + + // Special case - if we're a broken off bodypart, collide with anything. + if (shattered_ && IsBrokenBodyPart(ourID)) { + return true; + } + + // Get nitpicky with our self-collisions. + switch (ourID) { + case kHeadBodyID: + case kTorsoBodyID: + // Head and torso will collide with anyone who wants to + // (leave the decision up to them). + return true; + break; + case kLowerLeftArmBodyID: + // Lower arms collide with head, torso, and upper legs + // and upper arms if shattered. + switch (theirID) { + case kHeadBodyID: + case kTorsoBodyID: + case kUpperLeftLegBodyID: + return true; + default: + return false; + } + break; + case kLowerRightArmBodyID: + // Lower arms collide with head, torso, and upper legs. + switch (theirID) { + case kHeadBodyID: + case kTorsoBodyID: + case kUpperRightLegBodyID: + return true; + default: + return false; + } + break; + case kUpperLeftArmBodyID: // NOLINT(bugprone-branch-clone) + return false; + break; + case kUpperRightArmBodyID: + return false; + break; + case kUpperLeftLegBodyID: + // Collide with lower arm. + switch (theirID) { // NOLINT + case kLowerLeftArmBodyID: + return true; + default: + return false; + } + break; + case kUpperRightLegBodyID: + // collide with lower arm + switch (theirID) { // NOLINT + case kLowerRightArmBodyID: + return true; + default: + return false; + } + break; + case kLowerLeftLegBodyID: + // collide with opposite lower leg + switch (theirID) { // NOLINT + case kLowerRightLegBodyID: + return true; + default: + return false; + } + break; + case kLowerRightLegBodyID: + // lower right leg collides with lower left leg + switch (theirID) { // NOLINT + case kLowerLeftLegBodyID: + return true; + default: + return false; + } + break; + default: + // default to no collisions elsewhere + return false; + break; + } + } else { + // Non-us opposing node. + + // We ignore bumpers if we're injured, frozen, or if a non-roller-ball part + // of us is hitting it. + { + uint32_t f = opposingbody->flags(); + if (f & RigidBody::kIsBumper) { + if ((knockout_) || (frozen_) || (balance_ < 50) + || colliding_body->part() != &roller_part_) + return false; + } + } + } + + if (colliding_body->id() == kRollerBodyID) { + // Never collide against shrunken roller-ball. + if (ball_size_ <= 0.0f) return false; + } + return true; +} + +auto SpazNode::CollideCallback(dContact* c, int count, + RigidBody* colliding_body, + RigidBody* opposingbody) -> bool { + // Keep track of whether our toes are touching something besides us + // if (colliding_body == left_toes_body_.get() and opposingbody->getNode() != + // this) _toesTouchingL = true; if (colliding_body == right_toes_body_.get() + // and opposingbody->getNode() != this) _toesTouchingR = true; _toesTouchingL + // = (colliding_body == left_toes_body_.get() and opposingbody->getNode() != + // this); _toesTouchingR = (colliding_body == right_toes_body_.get() and + // opposingbody->getNode() != this); + + // hair collide with most anything but weakly.. + if (colliding_body->part() == &hair_part_ + || opposingbody->part() == &hair_part_) { + // Hair doesnt collide with hair. + if (colliding_body->part() == opposingbody->part()) return false; + + // ignore bumpers.. + if (opposingbody->flags() & RigidBody::kIsBumper) return false; + + // drop stiffness/damping/friction pretty low.. + float stiffness = 200.0f; + float damping = 10.0f; + + float erp, cfm; + CalcERPCFM(stiffness, damping, &erp, &cfm); + for (int i = 0; i < count; i++) { + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + c[i].surface.mu = 0.1f; + } + return true; + } + + if (colliding_body->part() == &limbs_part_lower_) { + // Drop friction if lower arms are hitting upper legs. + if ((colliding_body == lower_left_arm_body_.get() + || colliding_body == lower_right_arm_body_.get()) + && !shattered_) { + for (int i = 0; i < count; i++) { + c[i].surface.mu = 0.0f; + } + } + + // Now drop collision forces across the board. + float stiffness = 10.0f; + float damping = 1.0f; + + if (colliding_body == left_toes_body_.get() + || colliding_body == right_toes_body_.get()) { + stiffness *= kToesCollideStiffness; + damping *= kToesCollideDamping; + + // Also drop friction on toes. + for (int i = 0; i < count; i++) { + c[i].surface.mu *= 0.1f; + } + } + if (colliding_body == lower_right_leg_body_.get() + || colliding_body == lower_left_leg_body_.get()) { + stiffness *= kLowerLegCollideStiffness; + damping *= kLowerLegCollideDamping; + } + if (shattered_) { + stiffness *= 100.0f; + damping *= 10.0f; + } + + // If we're hitting ourself, drop all forces based on our self-collide + // level. + if (opposingbody->part()->node() == this && !frozen_) { + for (int i = 0; i < count; i++) { + c[i].surface.mu = 0.0f; + } + } + + // If we're punching, lets crank up stiffness on our punching hand + // so it looks like its responding to stuff its hitting. + if (punch_ && !dead_) { + if ((colliding_body == lower_right_arm_body_.get() && punch_right_) + || (colliding_body == lower_left_arm_body_.get() && !punch_right_)) { + stiffness *= 200.0f; + damping *= 20.0f; + } + } + + float erp, cfm; + CalcERPCFM(stiffness, damping, &erp, &cfm); + for (int i = 0; i < count; i++) { + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + } + } else if (colliding_body->part() == &limbs_part_upper_) { + float stiffness = 10; + float damping = 1; + float erp, cfm; + if (colliding_body == upper_right_leg_body_.get() + || colliding_body == upper_left_leg_body_.get()) { + stiffness *= kUpperLegCollideStiffness; + damping *= kUpperLegCollideDamping; + } + + // Keeps our arms from pushing into our head. + stiffness *= 10.0f; + if (shattered_) { + stiffness *= 100.0f; + damping *= 10.0f; + } + CalcERPCFM(stiffness, damping, &erp, &cfm); + for (int i = 0; i < count; i++) { + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + } + } + + if (colliding_body->part() == &spaz_part_) { + float stiffness = 5000; + float damping = 0.001f; + float erp, cfm; + CalcERPCFM(stiffness, damping, &erp, &cfm); + for (int i = 0; i < count; i++) { + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + } + } + + // If we're frozen and shattered, lets slide! + if (frozen_) { + for (int i = 0; i < count; i++) { + c[i].surface.mu = 0.4f; + } + } + + // Muck with roller friction. + if (colliding_body->id() == kRollerBodyID) { + // For non-bumper collisions, drop collision forces on the side. + // (we want more friction on the bottom of our roller ball than on the + // sides). + uint32_t f = opposingbody->flags(); + if (!(f & RigidBody::kIsBumper)) { + for (int i = 0; i < count; i++) { + // Let's use world-down instead. + dVector3 down = {0, 1, 0}; + float dot = std::abs(dDOT(c[i].geom.normal, down)); + if (dot > 1) { + dot = 1; + } else if (dot < 0) { + dot = 0; + } + + if (dot < 0.6f) { + // give our roller a kick away from vertical terrain surfaces + if ((f & RigidBody::kIsTerrain)) { + dBodyID b = body_roller_->body(); + dBodyAddForce(b, c[i].geom.normal[0] * 100.0f, + c[i].geom.normal[1] * 100.0f, + c[i].geom.normal[2] * 100.0f); + } +#if 1 + // Override stiffness and damping on our little parts + float stiffness = 800.0f; + float damping = 0.001f; + float erp, cfm; + CalcERPCFM(stiffness, damping, &erp, &cfm); + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + c[i].surface.mu = 0.0f; +#endif + } else { + // trying to get a well-behaved floor-response... + if (!hockey_) { + float stiffness = 7000.0f; + float damping = 7.0f; + float erp, cfm; + CalcERPCFM(stiffness, damping, &erp, &cfm); + c[i].surface.soft_erp = erp; + c[i].surface.soft_cfm = cfm; + c[i].surface.mu *= 1.0f; + } + } + } + } + } else if (colliding_body->id() != kRollerBodyID) { + // Drop friction on all our non-roller-ball parts. + for (int i = 0; i < count; i++) { + c[i].surface.mu *= 0.3f; + } + } + + // Keep track of when stuff is hitting our head, so we know when to calc + // damage from head whiplash. + if (colliding_body == body_head_.get() && opposingbody->part()->node() != this + && opposingbody->can_cause_impact_damage()) { + last_head_collide_time_ = scene()->time(); + } + + return true; +} + +void SpazNode::Stand(float x, float y, float z, float angle) { + y -= 0.7f; + + // If we're getting teleported we dont wanna pull things along with us. + DropHeldObject(); + spaz_part_.KillConstraints(); + hair_part_.KillConstraints(); + punch_part_.KillConstraints(); + pickup_part_.KillConstraints(); + extras_part_.KillConstraints(); + roller_part_.KillConstraints(); + limbs_part_upper_.KillConstraints(); + limbs_part_lower_.KillConstraints(); + + // So this doesn't trip our jolt mechanisms. + jolt_head_vel_[0] = jolt_head_vel_[1] = jolt_head_vel_[2] = 0.0f; + + dQuaternion iq; + dQFromAxisAndAngle(iq, 0, 1, 0, angle * (kPi / 180.0f)); + + dBodyID b; + + // Head + b = body_head_->body(); + dBodyEnable(b); + dBodySetPosition(b, x, y + 2.25f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Torso + b = body_torso_->body(); + dBodyEnable(b); + dBodySetPosition(b, x, y + 1.8f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // pelvis + b = body_pelvis_->body(); + dBodyEnable(b); + dBodySetPosition(b, x, y + 1.66f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Roller + b = body_roller_->body(); + dBodyEnable(b); + dBodySetPosition(b, x, y + 1.6f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Stand + b = stand_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x, y + 1.8f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Upper Right Arm + b = upper_right_arm_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x - 0.17f, y + 1.9f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Lower Right Arm + b = lower_right_arm_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x - 0.17f, y + 1.9f, z + 0.07f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Upper Left Arm + b = upper_left_arm_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x + 0.17f, y + 1.9f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Lower Left Arm + b = lower_left_arm_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x + 0.17f, y + 1.9f, z + 0.07f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Upper Right Leg + b = upper_right_leg_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x - 0.1f, y + 1.65f, z); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Lower Right Leg + b = lower_right_leg_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x - 0.1f, y + 1.65f, z + 0.05f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Right Toes + b = right_toes_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x - 0.1f, y + 1.7f, z + 0.1f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Upper Left Leg + b = upper_left_leg_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x + 0.1f, y + 1.65f, z + 0.00f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Lower Left Leg + b = lower_left_leg_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x + 0.1f, y + 1.65f, z + 0.05f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // Left Toes + b = left_toes_body_->body(); + dBodyEnable(b); + dBodySetPosition(b, x + 0.1f, y + 1.7f, z + 0.1f); + dBodySetLinearVel(b, 0, 0, 0); + dBodySetAngularVel(b, 0, 0, 0); + dBodySetQuaternion(b, iq); + dBodySetForce(b, 0, 0, 0); + + // If we have hair. + if (hair_front_right_joint_) PositionBodyForJoint(hair_front_right_joint_); + if (hair_front_left_joint_) PositionBodyForJoint(hair_front_left_joint_); + if (hair_ponytail_top_joint_) PositionBodyForJoint(hair_ponytail_top_joint_); + if (hair_ponytail_bottom_joint_) + PositionBodyForJoint(hair_ponytail_bottom_joint_); +} + +auto SpazNode::GetRigidBody(int id) -> RigidBody* { + // Ewwww this should be automatic. + switch (id) { + case kHeadBodyID: + return body_head_.get(); + break; + case kTorsoBodyID: + return body_torso_.get(); + break; + case kPunchBodyID: + return body_punch_.get(); + break; + case kPickupBodyID: + return body_pickup_.get(); + break; + case kPelvisBodyID: + return body_pelvis_.get(); + break; + case kRollerBodyID: + return body_roller_.get(); + break; + case kStandBodyID: + return stand_body_.get(); + break; + case kUpperRightArmBodyID: + return upper_right_arm_body_.get(); + break; + case kLowerRightArmBodyID: + return lower_right_arm_body_.get(); + break; + case kUpperLeftArmBodyID: + return upper_left_arm_body_.get(); + break; + case kLowerLeftArmBodyID: + return lower_left_arm_body_.get(); + break; + case kUpperRightLegBodyID: + return upper_right_leg_body_.get(); + break; + case kLowerRightLegBodyID: + return lower_right_leg_body_.get(); + break; + case kUpperLeftLegBodyID: + return upper_left_leg_body_.get(); + break; + case kLowerLeftLegBodyID: + return lower_left_leg_body_.get(); + break; + case kLeftToesBodyID: + return left_toes_body_.get(); + break; + case kRightToesBodyID: + return right_toes_body_.get(); + break; + case kHairFrontRightBodyID: + return hair_front_right_body_.get(); + break; + case kHairFrontLeftBodyID: + return hair_front_left_body_.get(); + break; + case kHairPonyTailTopBodyID: + return hair_ponytail_top_body_.get(); + break; + case kHairPonyTailBottomBodyID: + return hair_ponytail_bottom_body_.get(); + break; + default: + Log("Error: Request for unknown spaz body: " + std::to_string(id)); + break; + } + + return nullptr; +} + +void SpazNode::GetRigidBodyPickupLocations(int id, float* obj, float* character, + float* hand1, float* hand2) { + if (id == kHeadBodyID) { + obj[0] = 0; + obj[1] = 0; + obj[2] = 0; + } else { + obj[0] = obj[1] = obj[2] = 0; + } + + character[0] = character[1] = character[2] = 0.0f; + character[1] = -0.15f; + character[2] = 0.05f; + + hand1[0] = hand1[1] = hand1[2] = 0.0f; + hand2[0] = hand2[1] = hand2[2] = 0.0f; +} +void SpazNode::DropHeldObject() { + if (holding_something_) { + if (hold_node_.exists()) { + assert(pickup_joint_.IsAlive()); + pickup_joint_.Kill(); + } + assert(!pickup_joint_.IsAlive()); + + holding_something_ = false; + hold_body_ = 0; + + // Dispatch user messages last now that all is in place. + if (hold_node_.exists()) { + hold_node_->DispatchDroppedMessage(this); + } + DispatchDropMessage(); + } +} + +void SpazNode::CreateHair() { + // Assume all already exists in this case. + if (hair_front_right_body_.exists()) return; + + // Front right tuft. + hair_front_right_body_ = + Object::New(kHairFrontRightBodyID, &hair_part_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideAll, RigidBody::kCollideAll); + hair_front_right_body_->AddCallback(StaticCollideCallback, this); + hair_front_right_body_->SetDimensions(0.07f, 0.13f, 0, 0, 0, 0, 0.01f); + + hair_front_right_joint_ = CreateFixedJoint( + body_head_.get(), hair_front_right_body_.get(), 0, 0, // lin stiff/damp + 0, 0, // ang stiff/damp + -0.17f, 0.19f, 0.18f, // b1 anchor + 0, -0.08f, -0.12f // b2 anchor + ); // NOLINT (whitespace/parens) + + // Rotate it right a bit. + dQFromAxisAndAngle(hair_front_right_joint_->qrel, 0, 1, 0, -1.1f); + + // Front left tuft. + hair_front_left_body_ = + Object::New(kHairFrontLeftBodyID, &hair_part_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideAll, RigidBody::kCollideAll); + hair_front_left_body_->AddCallback(StaticCollideCallback, this); + hair_front_left_body_->SetDimensions(0.04f, 0.13f, 0, 0.07f, 0.13f, 0, 0.01f); + + hair_front_left_joint_ = CreateFixedJoint( + body_head_.get(), hair_front_left_body_.get(), 0, 0, // lin stiff/damp + 0, 0, // ang stiff/damp + 0.13f, 0.11f, 0.13f, // b1 anchor + 0, -0.08f, -0.12f // b2 anchor + ); // NOLINT (whitespace/parens) + + // Rotate it left a bit. + dQFromAxisAndAngle(hair_front_left_joint_->qrel, 0, 1, 0, 1.1f); + + // Pony tail top. + hair_ponytail_top_body_ = + Object::New(kHairPonyTailTopBodyID, &hair_part_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideAll, RigidBody::kCollideAll); + hair_ponytail_top_body_->AddCallback(StaticCollideCallback, this); + hair_ponytail_top_body_->SetDimensions(0.09f, 0.1f, 0, 0, 0, 0, 0.01f); + + hair_ponytail_top_joint_ = CreateFixedJoint( + body_head_.get(), hair_ponytail_top_body_.get(), 0, 0, // lin stiff/damp + 0, 0, // ang stiff/damp + 0, 0.3f, -0.21f, // b1 anchor + 0, -0.01f, 0.1f // b2 anchor + ); // NOLINT (whitespace/parens) + // rotate it up a bit.. + dQFromAxisAndAngle(hair_ponytail_top_joint_->qrel, 1, 0, 0, 1.1f); + + // Pony tail bottom. + hair_ponytail_bottom_body_ = + Object::New(kHairPonyTailBottomBodyID, &hair_part_, + RigidBody::Type::kBody, RigidBody::Shape::kCapsule, + RigidBody::kCollideNone, RigidBody::kCollideNone); + hair_ponytail_bottom_body_->AddCallback(StaticCollideCallback, this); + hair_ponytail_bottom_body_->SetDimensions(0.09f, 0.13f, 0, 0, 0, 0, 0.01f); + + hair_ponytail_bottom_joint_ = CreateFixedJoint( + hair_ponytail_top_body_.get(), hair_ponytail_bottom_body_.get(), 0, + 0, // lin stiff/damp + 0, 0, // ang stiff/damp + 0, 0.01f, -0.1f, // b1 anchor + 0, -0.01f, 0.12f // b2 anchor + ); // NOLINT (whitespace/parens) + + // Set joint values. + UpdateJoints(); +} +void SpazNode::DestroyHair() { + if (hair_front_right_joint_) dJointDestroy(hair_front_right_joint_); + hair_front_right_joint_ = nullptr; + + if (hair_front_left_joint_) dJointDestroy(hair_front_left_joint_); + hair_front_left_joint_ = nullptr; + + if (hair_ponytail_top_joint_) dJointDestroy(hair_ponytail_top_joint_); + hair_ponytail_top_joint_ = nullptr; + + if (hair_ponytail_bottom_joint_) dJointDestroy(hair_ponytail_bottom_joint_); + hair_ponytail_bottom_joint_ = nullptr; +} + +auto SpazNode::GetRollerMaterials() const -> std::vector { + return roller_part_.GetMaterials(); +} + +void SpazNode::SetRollerMaterials(const std::vector& vals) { + roller_part_.SetMaterials(vals); +} + +auto SpazNode::GetExtrasMaterials() const -> std::vector { + return extras_part_.GetMaterials(); +} + +void SpazNode::SetExtrasMaterials(const std::vector& vals) { + extras_part_.SetMaterials(vals); + limbs_part_upper_.SetMaterials(vals); + limbs_part_lower_.SetMaterials(vals); + hair_part_.SetMaterials(vals); +} + +auto SpazNode::GetPunchMaterials() const -> std::vector { + return punch_part_.GetMaterials(); +} + +void SpazNode::SetPunchMaterials(const std::vector& vals) { + punch_part_.SetMaterials(vals); +} + +auto SpazNode::GetPickupMaterials() const -> std::vector { + return pickup_part_.GetMaterials(); +} + +void SpazNode::SetPickupMaterials(const std::vector& vals) { + pickup_part_.SetMaterials(vals); +} + +auto SpazNode::GetMaterials() const -> std::vector { + return spaz_part_.GetMaterials(); +} + +void SpazNode::SetMaterials(const std::vector& vals) { + spaz_part_.SetMaterials(vals); +} + +void SpazNode::SetNameColor(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of length 3 for name_color"); + name_color_ = vals; +} + +void SpazNode::set_highlight(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of length 3 for highlight"); + highlight_ = vals; +} + +void SpazNode::SetColor(const std::vector& vals) { + if (vals.size() != 3) + throw Exception("Expected float array of length 3 for color"); + color_ = vals; + + // If this gets changed, make sure to change shadow-color in the constructor + // to match. + assert(shadow_color_.size() == 3); + shadow_color_[0] = color_[0] * 0.5f; + shadow_color_[1] = color_[1] * 0.5f; + shadow_color_[2] = color_[2] * 0.5f; +} + +void SpazNode::SetHurt(float val) { + float prev_hurt = hurt_; + hurt_ = std::min(1.0f, val); + if (prev_hurt != hurt_) { + last_hurt_change_time_ = scene()->time(); + } +} + +void SpazNode::SetFrozen(bool val) { + frozen_ = val; + + // Hmm; dont remember why this is necessary. + if (!frozen_) { + dBodyEnable(body_head_->body()); + } + + // Mark the time when we're newly frozen. We don't + // shatter based on impulse for a short time thereafter. + last_shatter_test_time_ = scene()->time(); + UpdateJoints(); +} + +void SpazNode::SetHaveBoxingGloves(bool val) { + have_boxing_gloves_ = val; + + // If we just got them (and aren't new ourself) lets flash. + if (have_boxing_gloves_ && (scene()->time() - birth_time_ > 100)) { + last_got_boxing_gloves_time_ = scene()->time(); + } +} + +void SpazNode::SetIsAreaOfInterest(bool val) { + // Create if need be. + if (val && area_of_interest_ == nullptr) { + area_of_interest_ = g_graphics->camera()->NewAreaOfInterest(); + UpdateAreaOfInterest(); + } + + // Destroy if need be. + if (!val && area_of_interest_) { + g_graphics->camera()->DeleteAreaOfInterest(area_of_interest_); + area_of_interest_ = nullptr; + } +} + +void SpazNode::SetCurseDeathTime(millisecs_t val) { + curse_death_time_ = val; + + // Start ticking sound. + if (curse_death_time_ != 0) { + if (tick_play_id_ == 0xFFFFFFFF) { + AudioSource* s = g_audio->SourceBeginNew(); + if (s) { + s->SetLooping(true); + const dReal* p_head = dGeomGetPosition(body_head_->geom()); + s->SetPosition(p_head[0], p_head[1], p_head[2]); + tick_play_id_ = + s->Play(g_media->GetSound(SystemSoundID::kTickingCrazy)); + s->End(); + } + } + } else { + // Stop ticking sound. + if (tick_play_id_ != 0xFFFFFFFF) { + g_audio->PushSourceStopSoundCall(tick_play_id_); + tick_play_id_ = 0xFFFFFFFF; + } + } +} + +void SpazNode::SetShattered(int val) { + bool was_shattered = (shattered_ != 0); + shattered_ = val; + + if (shattered_) { + // Calc which parts are shattered. + shatter_damage_ = 0; + + float shatter_neck, shatter_pelvis, shatter_upper, shatter_lower; + // We have a few breakage patterns depending on how we died. + + // Shattering ice or curse explosions generally totally break us up. + bool extreme = (frozen_ || (shattered_ == 2)); + if (extreme) { + shatter_neck = 0.95f; + shatter_pelvis = 0.95f; + shatter_upper = 0.8f; + shatter_lower = 0.6f; + } else if (last_hit_was_punch_) { + // Punches mostly take heads off or break torsos in half. + if (Utils::precalc_rands_2[(stream_id() * 31 + 112) % kPrecalcRandsCount] + > 0.3f) { + shatter_neck = 0.9f; + shatter_pelvis = 0.1f; + } else { + shatter_neck = 0.1f; + shatter_pelvis = 0.9f; + } + shatter_upper = 0.05f; + shatter_lower = 0.025f; + } else { + shatter_neck = 0.9f; + shatter_pelvis = 0.8f; + shatter_upper = 0.4f; + shatter_lower = 0.07f; + } + + // in kid-friendly mode, don't shatter anything.. + if (explicit_bool(true)) { + float rand1 = + Utils::precalc_rands_1[(stream_id() * 3 + 1) % kPrecalcRandsCount]; + float rand2 = + Utils::precalc_rands_2[(stream_id() * 2 + 111) % kPrecalcRandsCount]; + float rand3 = + Utils::precalc_rands_3[(stream_id() * 4 + 7) % kPrecalcRandsCount]; + float rand4 = + Utils::precalc_rands_1[(stream_id() * 7 + 78) % kPrecalcRandsCount]; + float rand5 = Utils::precalc_rands_3[(stream_id()) % kPrecalcRandsCount]; + float rand6 = + Utils::precalc_rands_2[(stream_id() / 2 + 17) % kPrecalcRandsCount]; + float rand7 = + Utils::precalc_rands_1[(stream_id() * 10) % kPrecalcRandsCount]; + float rand8 = + Utils::precalc_rands_3[(stream_id() * 17 + 2) % kPrecalcRandsCount]; + float rand9 = + Utils::precalc_rands_2[(stream_id() * 13 + 22) % kPrecalcRandsCount]; + float rand10 = + Utils::precalc_rands_2[(stream_id() + 19) % kPrecalcRandsCount]; + + // Head/mid-torso are most common losses. + if (rand1 < shatter_neck) shatter_damage_ |= kNeckJointBroken; + if (rand2 < shatter_pelvis) shatter_damage_ |= kPelvisJointBroken; + + // Followed by upper arm/leg attaches. + if (rand3 < shatter_upper) shatter_damage_ |= kUpperRightArmJointBroken; + if (rand4 < shatter_upper) shatter_damage_ |= kUpperLeftArmJointBroken; + if (rand5 < shatter_upper) shatter_damage_ |= kUpperRightLegJointBroken; + if (rand6 < shatter_upper) shatter_damage_ |= kUpperLeftLegJointBroken; + + // Followed by mid arm/leg attaches. + if (rand7 < shatter_lower) shatter_damage_ |= kLowerRightArmJointBroken; + if (rand8 < shatter_lower) shatter_damage_ |= kLowerLeftArmJointBroken; + if (rand9 < shatter_lower) shatter_damage_ |= kLowerRightLegJointBroken; + if (rand10 < shatter_lower) shatter_damage_ |= kLowerLeftLegJointBroken; + } + + // Stop any sound we're making if we're shattering. + if (!was_shattered) { + g_audio->PushSourceStopSoundCall(voice_play_id_); + if (tick_play_id_ != 0xFFFFFFFF) { + g_audio->PushSourceStopSoundCall(tick_play_id_); + tick_play_id_ = 0xFFFFFFFF; + } + } + } +} + +void SpazNode::SetDead(bool val) { + bool was_dead = dead_; + dead_ = val; + if (dead_ && !was_dead) { + death_time_ = scene()->time(); + + // Lose our area-of-interest. + if (area_of_interest_) { + g_graphics->camera()->DeleteAreaOfInterest(area_of_interest_); + area_of_interest_ = nullptr; + } + + // Drop whatever we're holding. + DropHeldObject(); + + // Scream on death unless we're already doing our fall scream, + // in which case we just keep on doing that. + if (voice_play_id_ != fall_play_id_ + || !g_audio->IsSoundPlaying(fall_play_id_)) { + g_audio->PushSourceStopSoundCall(voice_play_id_); + + // Only make sound if we're not shattered. + if (!shattered_) { + if (Sound* sound = GetRandomMedia(death_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + const dReal* p_head = dGeomGetPosition(body_head_->geom()); + source->SetPosition(p_head[0], p_head[1], p_head[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + source->End(); + } + } + } + } + if (tick_play_id_ != 0xFFFFFFFF) { + g_audio->PushSourceStopSoundCall(tick_play_id_); + tick_play_id_ = 0xFFFFFFFF; + } + } +} + +void SpazNode::SetStyle(const std::string& val) { + style_ = val; + dull_reflection_ = (style_ == "ninja" || style_ == "kronk"); + ninja_ = (style_ == "ninja"); + fat_ = (style_ == "mel" || style_ == "pirate" || style_ == "frosty" + || style_ == "santa"); + pirate_ = (style_ == "pirate"); + frosty_ = (style_ == "frosty"); + + // Start with defaults. + female_ = false; + female_hair_ = false; + eye_ball_color_red_ = 0.46f; + eye_ball_color_green_ = 0.38f; + eye_ball_color_blue_ = 0.36f; + torso_radius_ = 0.15f; + shoulder_offset_x_ = 0.0f; + shoulder_offset_y_ = 0.0f; + shoulder_offset_z_ = 0.0f; + has_eyelids_ = true; + eye_scale_ = 1.0f; + eye_lid_color_red_ = 0.5f; + eye_lid_color_green_ = 0.3f; + eye_lid_color_blue_ = 0.2f; + reflection_scale_ = 0.1f; + default_eye_lid_angle_ = 0.0f; + eye_offset_x_ = 0.065f; + eye_offset_y_ = -0.036f; + eye_offset_z_ = 0.205f; + eye_color_red_ = 0.5f; + eye_color_green_ = 0.5f; + eye_color_blue_ = 1.2f; + flippers_ = false; + wings_ = false; + + if (style_ == "bear") { + eye_ball_color_red_ = 0.5f; + eye_ball_color_green_ = 0.5f; + eye_ball_color_blue_ = 0.5f; + eye_lid_color_red_ = 0.2f; + eye_lid_color_green_ = 0.1f; + eye_lid_color_blue_ = 0.1f; + eye_color_red_ = 0.0f; + eye_color_green_ = 0.0f; + eye_color_blue_ = 0.0f; + torso_radius_ = 0.25f; + shoulder_offset_x_ = -0.02f; + shoulder_offset_y_ = -0.01f; + shoulder_offset_z_ = 0.01f; + eye_scale_ = 0.73f; + has_eyelids_ = false; + eye_offset_y_ += 0.1f; + reflection_scale_ = 0.05f; + } else if (style_ == "penguin") { + flippers_ = true; + eye_ball_color_red_ = 0.5f; + eye_ball_color_green_ = 0.5f; + eye_ball_color_blue_ = 0.5f; + eye_lid_color_red_ = 0.1f; + eye_lid_color_green_ = 0.1f; + eye_lid_color_blue_ = 0.1f; + eye_color_red_ = 0.0f; + eye_color_green_ = 0.0f; + eye_color_blue_ = 0.0f; + torso_radius_ = 0.25f; + shoulder_offset_x_ = -0.02f; + shoulder_offset_y_ = -0.01f; + shoulder_offset_z_ = 0.00f; + eye_scale_ = 0.65f; + has_eyelids_ = false; + eye_offset_y_ += 0.05f; + eye_offset_z_ -= 0.05f; + reflection_scale_ = 0.2f; + } else if (style_ == "mel") { + torso_radius_ = 0.23f; + shoulder_offset_x_ = -0.04f; + shoulder_offset_y_ = 0.03f; + eye_ball_color_red_ = 0.63f; + eye_ball_color_green_ = 0.53f; + eye_ball_color_blue_ = 0.49f; + eye_lid_color_red_ = 0.8f; + eye_lid_color_green_ = 0.55f; + eye_lid_color_blue_ = 0.45f; + eye_offset_x_ += 0.01f; + eye_offset_y_ += 0.01f; + eye_offset_z_ -= 0.04f; + eye_scale_ = 1.05f; + } else if (style_ == "ninja") { + eye_lid_color_red_ = 0.5f; + eye_lid_color_green_ = 0.3f; + eye_lid_color_blue_ = 0.2f; + reflection_scale_ = 0.15f; + default_eye_lid_angle_ = 20.0f; // angry eyes + eye_color_red_ = 0.2f; + eye_color_green_ = 0.1f; + eye_color_blue_ = 0.0f; + } else if (style_ == "agent") { + eyeless_ = true; + reflection_scale_ = 0.2f; + } else if (style_ == "cyborg") { + eyeless_ = true; + reflection_scale_ = 0.85f; + } else if (style_ == "santa") { + eye_scale_ = kSantaEyeScale; + torso_radius_ = 0.2f; + shoulder_offset_x_ = -0.04f; + shoulder_offset_y_ = 0.03f; + eye_lid_color_red_ = 0.5f; + eye_lid_color_green_ = 0.4f; + eye_lid_color_blue_ = 0.3f; + eye_offset_y_ += 0.02f; + eye_offset_z_ += kSantaEyeTranslate; + } else if (style_ == "pirate") { + torso_radius_ = 0.25f; + shoulder_offset_x_ = -0.04f; + shoulder_offset_y_ = 0.03f; + eye_lid_color_red_ = 0.3f; + eye_lid_color_green_ = 0.2f; + eye_lid_color_blue_ = 0.15f; + } else if (style_ == "kronk") { + eye_scale_ = 0.8f; + torso_radius_ = 0.2f; + shoulder_offset_x_ = -0.03f; + eye_lid_color_red_ = 0.3f; + eye_lid_color_green_ = 0.2f; + eye_lid_color_blue_ = 0.1f; + default_eye_lid_angle_ = 20.0f; // angry eyes + } else if (style_ == "frosty") { + torso_radius_ = 0.3f; + shoulder_offset_x_ = -0.04f; + shoulder_offset_y_ = 0.03f; + } else if (style_ == "female") { + female_ = true; + female_hair_ = true; + torso_radius_ = 0.11f; + shoulder_offset_x_ = 0.03f; + shoulder_offset_z_ = -0.02f; + eye_lid_color_red_ = 0.6f; + eye_lid_color_green_ = 0.35f; + eye_lid_color_blue_ = 0.31f; + default_eye_lid_angle_ = 15.0f; // sorta angry eyes + eye_color_red_ = 1.1f; + eye_color_green_ = 0.6f; + eye_color_blue_ = 1.4f; + eye_ball_color_red_ = 0.54f; + eye_ball_color_green_ = 0.51f; + eye_ball_color_blue_ = 0.55f; + eye_color_red_ = 0.55f; + eye_color_green_ = 0.3f; + eye_color_blue_ = 0.7f; + eye_scale_ = 0.95f; + eye_offset_x_ = 0.08f; + } else if (style_ == "pixie") { + wings_ = true; + female_ = true; + torso_radius_ = 0.11f; + shoulder_offset_x_ = 0.03f; + shoulder_offset_z_ = -0.02f; + eye_ball_color_red_ = 0.58f; + eye_ball_color_green_ = 0.55f; + eye_ball_color_blue_ = 0.6f; + eye_lid_color_red_ = 0.73f; + eye_lid_color_green_ = 0.53f; + eye_lid_color_blue_ = 0.6f; + default_eye_lid_angle_ = 10.0f; // sorta angry eyes + eye_color_red_ = 0.1f; + eye_color_green_ = 0.3f; + eye_color_blue_ = 0.1f; + eye_scale_ = 0.85f; + eye_offset_z_ = 0.2f; + eye_offset_y_ = 0.004f; + eye_offset_x_ = 0.083f; + reflection_scale_ = 0.35f; + } else if (style_ == "bones") { + eyeless_ = true; + // defaults.. + } else if (style_ == "spaz") { + // defaults.. + } else if (style_ == "ali") { + // defaults.. + eyeless_ = true; + torso_radius_ = 0.11f; + shoulder_offset_x_ = 0.03f; + shoulder_offset_y_ = -0.05f; + reflection_scale_ = 0.25f; + } else if (style_ == "bunny") { + torso_radius_ = 0.13f; + eye_scale_ = 1.2f; + eye_offset_z_ = 0.05f; + eye_offset_y_ = -0.08f; + eye_offset_x_ = 0.07f; + eye_lid_color_red_ = 0.6f; + eye_lid_color_green_ = 0.5f; + eye_lid_color_blue_ = 0.5f; + eye_ball_color_red_ = 0.6f; + eye_ball_color_green_ = 0.6f; + eye_ball_color_blue_ = 0.6f; + default_eye_lid_angle_ = -5.0f; // sorta angry eyes + shoulder_offset_x_ = 0.03f; + shoulder_offset_y_ = -0.05f; + reflection_scale_ = 0.02f; + } else { + BA_LOG_ONCE("Error: Unrecognized spaz style: '" + style_ + "'"); + } + UpdateBodiesForStyle(); +} + +auto SpazNode::GetVelocity() const -> std::vector { + const dReal* v = dBodyGetLinearVel(body_torso_->body()); + std::vector vv(3); + vv[0] = v[0]; + vv[1] = v[1]; + vv[2] = v[2]; + return vv; +} + +auto SpazNode::GetPositionForward() const -> std::vector { + dVector3 p_forward; + dBodyGetRelPointPos(body_torso_->body(), 0, 0.2f, -0.2f, p_forward); + std::vector vals(3); + vals[0] = p_forward[0] + body_torso_->blend_offset().x; + vals[1] = p_forward[1] + body_torso_->blend_offset().y; + vals[2] = p_forward[2] + body_torso_->blend_offset().z; + return vals; +} + +auto SpazNode::GetPositionCenter() const -> std::vector { + const dReal* p2 = dGeomGetPosition(body_torso_->geom()); + const dReal* p3 = dGeomGetPosition(body_head_->geom()); + std::vector vals(3); + if (shattered_) { + vals[0] = p2[0] + body_torso_->blend_offset().x; + vals[1] = p2[1] + body_torso_->blend_offset().y; + vals[2] = p2[2] + body_torso_->blend_offset().z; + } else { + vals[0] = (p2[0] + body_torso_->blend_offset().x) * 0.7f + + (p3[0] + body_head_->blend_offset().x) * 0.3f; + vals[1] = (p2[1] + body_torso_->blend_offset().y) * 0.7f + + (p3[1] + body_head_->blend_offset().y) * 0.3f; + vals[2] = (p2[2] + body_torso_->blend_offset().z) * 0.7f + + (p3[2] + body_head_->blend_offset().z) * 0.3f; + } + return vals; +} + +auto SpazNode::GetPunchPosition() const -> std::vector { + if (!body_punch_.exists()) { + BA_LOG_PYTHON_TRACE_ONCE( + "WARNING: querying spaz punch_position without punch body"); + return std::vector(3, 0.0f); + } + std::vector vals(3); + const dReal* p = dGeomGetPosition(body_punch_->geom()); + vals[0] = p[0]; + vals[1] = p[1]; + vals[2] = p[2]; + return vals; +} + +auto SpazNode::GetPunchVelocity() const -> std::vector { + if (!body_punch_.exists()) { + BA_LOG_PYTHON_TRACE_ONCE( + "WARNING: querying spaz punch_velocity without punch body"); + return std::vector(3, 0.0f); + } + std::vector vals(3); + const dReal* p = dGeomGetPosition(body_punch_->geom()); + dVector3 v; + dBodyGetPointVel( + (punch_right_ ? lower_right_arm_body_ : lower_left_arm_body_)->body(), + p[0], p[1], p[2], v); + vals[0] = v[0]; + vals[1] = v[1]; + vals[2] = v[2]; + return vals; +} + +auto SpazNode::GetPunchMomentumLinear() const -> std::vector { + if (!body_punch_.exists()) { + BA_LOG_PYTHON_TRACE_ONCE( + "WARNING: querying spaz punch_velocity without punch body"); + return std::vector(3, 0.0f); + } + std::vector vals(3); + + // our linear punch momentum is our base velocity with punchmomentumlinear as + // magnitude + const dReal* vel = dBodyGetLinearVel(body_torso_->body()); + float vel_mag = sqrtf(vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]); + if (vel_mag < 0.01f) { + vals[0] = vals[1] = vals[2] = 0; + } else { + vel_mag = punch_momentum_linear_ / vel_mag; + vals[0] = vel[0] * vel_mag; + vals[1] = vel[1] * vel_mag; + vals[2] = vel[2] * vel_mag; + } + return vals; +} + +auto SpazNode::GetTorsoPosition() const -> std::vector { + const dReal* p = dGeomGetPosition(body_torso_->geom()); + std::vector vals(3); + vals[0] = p[0] + body_torso_->blend_offset().x; + vals[1] = p[1] + body_torso_->blend_offset().y; + vals[2] = p[2] + body_torso_->blend_offset().z; + return vals; +} + +auto SpazNode::GetPosition() const -> std::vector { + const dReal* p = dGeomGetPosition(body_roller_->geom()); + std::vector vals(3); + vals[0] = p[0] + body_roller_->blend_offset().x; + vals[1] = p[1] + body_roller_->blend_offset().y; + vals[2] = p[2] + body_roller_->blend_offset().z; + return vals; +} + +void SpazNode::SetHoldNode(Node* val) { + // they passed a node + if (val != nullptr) { + Node* a = val; + assert(a); + RigidBody* b = a->GetRigidBody(hold_body_); + if (!b) { + // print some debugging info on the active collision.. + { + Dynamics* dynamics = scene()->dynamics(); + assert(dynamics); + Collision* c = dynamics->active_collision(); + if (c) { + Log("SRC NODE: " + ObjToString(dynamics->GetActiveCollideSrcNode())); + Log("OPP NODE: " + ObjToString(dynamics->GetActiveCollideDstNode())); + Log("SRC BODY " + + std::to_string(dynamics->GetCollideMessageReverseOrder() + ? c->body_id_1 + : c->body_id_2)); + Log("OPP BODY " + + std::to_string(dynamics->GetCollideMessageReverseOrder() + ? c->body_id_2 + : c->body_id_1)); + Log("REVERSE " + + std::to_string(dynamics->GetCollideMessageReverseOrder())); + } else { + Log(""); + } + } + throw Exception("specified hold_body (" + std::to_string(hold_body_) + + ") not found on hold_node: " + + a->GetObjectDescription()); + } + + hold_node_ = val; + holding_something_ = true; + last_pickup_time_ = scene()->time(); + + assert(a && b); + { + g_audio->PushSourceStopSoundCall(voice_play_id_); + if (Sound* sound = GetRandomMedia(pickup_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + const dReal* p_head = dGeomGetPosition(body_head_->geom()); + source->SetPosition(p_head[0], p_head[1], p_head[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + source->End(); + } + } + + float hold_height = 1.08f; + float hold_forward = -0.05f; + float hold_handle[3]; + float hold_handle2[3]; + + dBodyID b1 = body_torso_->body(); + dBodyID b2 = b->body(); + const dReal* p1 = dBodyGetPosition(b1); + const dReal* p2 = dBodyGetPosition(b2); + const dReal* q1 = dBodyGetQuaternion(b1); + const dReal* q2 = dBodyGetQuaternion(b2); + dReal p1_old[3]; + dReal p2_old[3]; + dReal q1_old[4]; + dReal q2_old[4]; + for (int i = 0; i < 3; i++) { + p1_old[i] = p1[i]; + p2_old[i] = p2[i]; + } + for (int i = 0; i < 4; i++) { + q1_old[i] = q1[i]; + q2_old[i] = q2[i]; + } + + a->GetRigidBodyPickupLocations(hold_body_, hold_handle, hold_handle2, + hold_hand_offset_right_, + hold_hand_offset_left_); + + // hand locations are relative to object pickup location.. add that in + hold_hand_offset_right_[0] += hold_handle[0]; + hold_hand_offset_right_[1] += hold_handle[1]; + hold_hand_offset_right_[2] += hold_handle[2]; + hold_hand_offset_left_[0] += hold_handle[0]; + hold_hand_offset_left_[1] += hold_handle[1]; + hold_hand_offset_left_[2] += hold_handle[2]; + + dBodySetPosition(b1, -hold_handle2[0], -hold_handle2[1], + -hold_handle2[2]); + dBodySetPosition(b2, -hold_handle[0], hold_height - hold_handle[1], + hold_forward - hold_handle[2]); + dQuaternion q; + dQSetIdentity(q); + dBodySetQuaternion(b1, q); + dBodySetQuaternion(b2, q); + auto* j = static_cast( + dJointCreateFixed(scene()->dynamics()->ode_world(), nullptr)); + pickup_joint_.SetJoint(j, scene()); + + pickup_joint_.AttachToBodies(body_torso_.get(), b); + dJointSetFixed(j); + dJointSetFixedSpringMode(j, 1, 1, true); + dJointSetFixedAnchor(j, 0, hold_height, hold_forward, false); + dJointSetFixedParam(j, dParamLinearStiffness, 180); + dJointSetFixedParam(j, dParamLinearDamping, 10); + + dJointSetFixedParam(j, dParamAngularStiffness, 4.0f); + dJointSetFixedParam(j, dParamAngularDamping, 0.3f); + + { + pickup_pos_1_[0] = p1_old[0]; + pickup_pos_1_[1] = p1_old[1]; + pickup_pos_1_[2] = p1_old[2]; + pickup_pos_2_[0] = p2_old[0]; + pickup_pos_2_[1] = p2_old[1]; + pickup_pos_2_[2] = p2_old[2]; + for (int i = 0; i < 4; i++) { + pickup_q1_[i] = q1_old[i]; + pickup_q2_[i] = q2_old[i]; + } + } + + dBodySetPosition(b1, p1_old[0], p1_old[1], p1_old[2]); + dBodySetPosition(b2, p2_old[0], p2_old[1], p2_old[2]); + dBodySetQuaternion(b1, q1_old); + dBodySetQuaternion(b2, q2_old); + } + // inform userland objects that they're picking up or have been picked up + DispatchPickUpMessage(a); + a->DispatchPickedUpMessage(this); + } else { + // user is clearing hold-node; just drop whatever we're holding.. + DropHeldObject(); + } +} + +auto SpazNode::GetJumpSounds() const -> std::vector { + return RefsToPointers(jump_sounds_); +} +void SpazNode::SetJumpSounds(const std::vector& vals) { + jump_sounds_ = PointersToRefs(vals); +} +auto SpazNode::GetAttackSounds() const -> std::vector { + return RefsToPointers(attack_sounds_); +} +void SpazNode::SetAttackSounds(const std::vector& vals) { + attack_sounds_ = PointersToRefs(vals); +} +auto SpazNode::GetImpactSounds() const -> std::vector { + return RefsToPointers(impact_sounds_); +} +void SpazNode::SetImpactSounds(const std::vector& vals) { + impact_sounds_ = PointersToRefs(vals); +} +auto SpazNode::GetDeathSounds() const -> std::vector { + return RefsToPointers(death_sounds_); +} +void SpazNode::SetDeathSounds(const std::vector& vals) { + death_sounds_ = PointersToRefs(vals); +} + +auto SpazNode::GetPickupSounds() const -> std::vector { + return RefsToPointers(pickup_sounds_); +} +void SpazNode::SetPickupSounds(const std::vector& vals) { + pickup_sounds_ = PointersToRefs(vals); +} + +void SpazNode::SetFallSounds(const std::vector& vals) { + fall_sounds_ = PointersToRefs(vals); +} + +auto SpazNode::GetResyncDataSize() -> int { + // 1 float for roll_amt_ + return 4; +} + +auto SpazNode::GetResyncData() -> std::vector { + std::vector data(4, 0); + char* ptr = reinterpret_cast(&(data[0])); + Utils::EmbedFloat32(&ptr, roll_amt_); + return data; +} + +void SpazNode::ApplyResyncData(const std::vector& data) { + const char* ptr = reinterpret_cast(&(data[0])); + roll_amt_ = Utils::ExtractFloat32(&ptr); +} + +void SpazNode::PlayHurtSound() { + if (dead_ || invincible_) { + return; + } + if (Sound* sound = GetRandomMedia(impact_sounds_)) { + if (AudioSource* source = g_audio->SourceBeginNew()) { + const dReal* p_top = dGeomGetPosition(body_head_->geom()); + g_audio->PushSourceStopSoundCall(voice_play_id_); + source->SetPosition(p_top[0], p_top[1], p_top[2]); + voice_play_id_ = source->Play(sound->GetSoundData()); + source->End(); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/spaz_node.h b/src/ballistica/scene/node/spaz_node.h new file mode 100644 index 00000000..f1e76af5 --- /dev/null +++ b/src/ballistica/scene/node/spaz_node.h @@ -0,0 +1,570 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_SPAZ_NODE_H_ +#define BALLISTICA_SCENE_NODE_SPAZ_NODE_H_ + +#include +#include + +#include "ballistica/dynamics/part.h" +#include "ballistica/game/player.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +// Current player character spaz node. +class SpazNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit SpazNode(Scene* scene); + ~SpazNode() override; + void Step() override; + void HandleMessage(const char* data) override; + void Draw(FrameDef* frame_def) override; + auto GetRigidBody(int id) -> RigidBody* override; + void GetRigidBodyPickupLocations(int id, float* obj, float* character, + float* hand1, float* hand2) override; + auto GetResyncDataSize() -> int override; + auto GetResyncData() -> std::vector override; + void ApplyResyncData(const std::vector& data) override; + auto can_fly() const -> bool { return can_fly_; } + void set_can_fly(bool val) { can_fly_ = val; } + auto hockey() const -> bool { return hockey_; } + void set_hockey(bool val) { hockey_ = val; } + auto GetRollerMaterials() const -> std::vector; + void SetRollerMaterials(const std::vector& vals); + auto GetExtrasMaterials() const -> std::vector; + void SetExtrasMaterials(const std::vector& vals); + auto GetPunchMaterials() const -> std::vector; + void SetPunchMaterials(const std::vector& vals); + auto GetPickupMaterials() const -> std::vector; + void SetPickupMaterials(const std::vector& vals); + auto GetMaterials() const -> std::vector; + void SetMaterials(const std::vector& vals); + auto area_of_interest_radius() const -> float { + return area_of_interest_radius_; + } + void set_area_of_interest_radius(float val) { + area_of_interest_radius_ = val; + } + auto name() const -> std::string { return name_; } + void set_name(const std::string& val) { name_ = val; } + auto counter_text() const -> std::string { return counter_text_; } + void set_counter_text(const std::string& val) { counter_text_ = val; } + auto mini_billboard_1_texture() const -> Texture* { + return mini_billboard_1_texture_.get(); + } + void set_mini_billboard_1_texture(Texture* val) { + mini_billboard_1_texture_ = val; + } + auto mini_billboard_2_texture() const -> Texture* { + return mini_billboard_2_texture_.get(); + } + void set_mini_billboard_2_texture(Texture* val) { + mini_billboard_2_texture_ = val; + } + auto mini_billboard_3_texture() const -> Texture* { + return mini_billboard_3_texture_.get(); + } + void set_mini_billboard_3_texture(Texture* val) { + mini_billboard_3_texture_ = val; + } + auto mini_billboard_1_start_time() const -> millisecs_t { + return mini_billboard_1_start_time_; + } + void set_mini_billboard_1_start_time(millisecs_t val) { + mini_billboard_1_start_time_ = val; + } + auto mini_billboard_1_end_time() const -> millisecs_t { + return mini_billboard_1_end_time_; + } + void set_mini_billboard_1_end_time(millisecs_t val) { + mini_billboard_1_end_time_ = val; + } + auto mini_billboard_2_start_time() const -> millisecs_t { + return mini_billboard_2_start_time_; + } + void set_mini_billboard_2_start_time(millisecs_t val) { + mini_billboard_2_start_time_ = val; + } + auto mini_billboard_2_end_time() const -> millisecs_t { + return mini_billboard_2_end_time_; + } + void set_mini_billboard_2_end_time(millisecs_t val) { + mini_billboard_2_end_time_ = val; + } + auto mini_billboard_3_start_time() const -> millisecs_t { + return mini_billboard_3_start_time_; + } + void set_mini_billboard_3_start_time(millisecs_t val) { + mini_billboard_3_start_time_ = val; + } + auto mini_billboard_3_end_time() const -> millisecs_t { + return mini_billboard_3_end_time_; + } + void set_mini_billboard_3_end_time(millisecs_t val) { + mini_billboard_3_end_time_ = val; + } + auto billboard_texture() const -> Texture* { + return billboard_texture_.get(); + } + void set_billboard_texture(Texture* val) { billboard_texture_ = val; } + auto billboard_opacity() const -> float { return billboard_opacity_; } + void set_billboard_opacity(float val) { billboard_opacity_ = val; } + auto counter_texture() const -> Texture* { return counter_texture_.get(); } + void set_counter_texture(Texture* val) { counter_texture_ = val; } + auto invincible() const -> bool { return invincible_; } + void set_invincible(bool val) { invincible_ = val; } + auto name_color() const -> std::vector { return name_color_; } + void SetNameColor(const std::vector& vals); + auto highlight() const -> std::vector { return highlight_; } + void set_highlight(const std::vector& vals); + auto color() const -> std::vector { return color_; } + void SetColor(const std::vector& vals); + auto hurt() const -> float { return hurt_; } + void SetHurt(float val); + auto boxing_gloves_flashing() const -> bool { + return boxing_gloves_flashing_; + } + void set_boxing_gloves_flashing(bool val) { boxing_gloves_flashing_ = val; } + auto source_player() const -> Player* { return source_player_.get(); } + void set_source_player(Player* val) { source_player_ = val; } + auto frozen() const -> bool { return frozen_; } + void SetFrozen(bool val); + auto have_boxing_gloves() const -> bool { return have_boxing_gloves_; } + void SetHaveBoxingGloves(bool val); + auto is_area_of_interest() const -> bool { + return (area_of_interest_ != nullptr); + } + void SetIsAreaOfInterest(bool val); + auto curse_death_time() const -> millisecs_t { return curse_death_time_; } + void SetCurseDeathTime(millisecs_t val); + auto shattered() const -> int { return shattered_; } + void SetShattered(int val); + auto dead() const -> bool { return dead_; } + void SetDead(bool val); + auto style() const -> std::string { return style_; } + void SetStyle(const std::string& val); + auto GetKnockout() const -> float { + return static_cast(knockout_) / 255.0f; + } + auto punch_power() const -> float { return punch_power_; } + auto GetPunchMomentumAngular() const -> float { + return 0.2f + punch_momentum_angular_; + } + auto GetPunchMomentumLinear() const -> std::vector; + auto damage_out() const -> float { return damage_out_; } + auto damage_smoothed() const -> float { return damage_smoothed_; } + auto GetPunchVelocity() const -> std::vector; + auto GetVelocity() const -> std::vector; + auto GetPositionForward() const -> std::vector; + auto GetPositionCenter() const -> std::vector; + auto GetPunchPosition() const -> std::vector; + auto GetTorsoPosition() const -> std::vector; + auto GetPosition() const -> std::vector; + auto hold_body() const -> int { return hold_body_; } + void set_hold_body(int val) { hold_body_ = val; } + auto hold_node() const -> Node* { return hold_node_.get(); } + void SetHoldNode(Node* val); + auto GetJumpSounds() const -> std::vector; + void SetJumpSounds(const std::vector& vals); + auto GetAttackSounds() const -> std::vector; + void SetAttackSounds(const std::vector& vals); + auto GetImpactSounds() const -> std::vector; + void SetImpactSounds(const std::vector& vals); + auto GetDeathSounds() const -> std::vector; + void SetDeathSounds(const std::vector& vals); + auto GetPickupSounds() const -> std::vector; + void SetPickupSounds(const std::vector& vals); + auto GetFallSounds() const -> std::vector { + return RefsToPointers(fall_sounds_); + } + void SetFallSounds(const std::vector& vals); + auto color_texture() const -> Texture* { return color_texture_.get(); } + void set_color_texture(Texture* val) { color_texture_ = val; } + auto color_mask_texture() const -> Texture* { + return color_mask_texture_.get(); + } + void set_color_mask_texture(Texture* val) { color_mask_texture_ = val; } + auto head_model() const -> Model* { return head_model_.get(); } + void set_head_model(Model* val) { head_model_ = val; } + auto torso_model() const -> Model* { return torso_model_.get(); } + void set_torso_model(Model* val) { torso_model_ = val; } + auto pelvis_model() const -> Model* { return pelvis_model_.get(); } + void set_pelvis_model(Model* val) { pelvis_model_ = val; } + auto upper_arm_model() const -> Model* { return upper_arm_model_.get(); } + void set_upper_arm_model(Model* val) { upper_arm_model_ = val; } + auto forearm_model() const -> Model* { return forearm_model_.get(); } + void set_forearm_model(Model* val) { forearm_model_ = val; } + auto hand_model() const -> Model* { return hand_model_.get(); } + void set_hand_model(Model* val) { hand_model_ = val; } + auto upper_leg_model() const -> Model* { return upper_leg_model_.get(); } + void set_upper_leg_model(Model* val) { upper_leg_model_ = val; } + auto lower_leg_model() const -> Model* { return lower_leg_model_.get(); } + void set_lower_leg_model(Model* val) { lower_leg_model_ = val; } + auto toes_model() const -> Model* { return toes_model_.get(); } + void set_toes_model(Model* val) { toes_model_ = val; } + auto billboard_cross_out() const -> bool { return billboard_cross_out_; } + void set_billboard_cross_out(bool val) { billboard_cross_out_ = val; } + auto jump_pressed() const -> bool { return jump_pressed_; } + void SetJumpPressed(bool val); + auto punch_pressed() const -> bool { return punch_pressed_; } + void SetPunchPressed(bool val); + auto bomb_pressed() const -> bool { return bomb_pressed_; } + void SetBombPressed(bool val); + auto run() const -> float { return run_; } + void SetRun(float val); + auto fly_pressed() const -> bool { return fly_pressed_; } + void SetFlyPressed(bool val); + auto behavior_version() const -> int { return behavior_version_; } + void set_behavior_version(int val) { + behavior_version_ = static_cast_check_fit(val); + } + auto pickup_pressed() const -> bool { return pickup_pressed_; } + void SetPickupPressed(bool val); + auto hold_position_pressed() const -> bool { return hold_position_pressed_; } + void SetHoldPositionPressed(bool val); + auto move_left_right() const -> float { return move_left_right_; } + void SetMoveLeftRight(float val); + auto move_up_down() const -> float { return move_up_down_; } + void SetMoveUpDown(float val); + + // Preserve some old behavior so we dont have to re-code the demo. + auto demo_mode() const -> bool { return demo_mode_; } + void set_demo_mode(bool val) { demo_mode_ = val; } + + private: + enum ShatterDamage { + kNeckJointBroken = 1u << 0u, + kPelvisJointBroken = 1u << 1u, + kUpperLeftLegJointBroken = 1u << 2u, + kUpperRightLegJointBroken = 1u << 3u, + kLowerLeftLegJointBroken = 1u << 4u, + kLowerRightLegJointBroken = 1u << 5u, + kUpperLeftArmJointBroken = 1u << 6u, + kUpperRightArmJointBroken = 1u << 7u, + kLowerLeftArmJointBroken = 1u << 8u, + kLowerRightArmJointBroken = 1u << 9u + }; + void PlayHurtSound(); + void DrawBodyParts(ObjectComponent* c, bool shading, float death_fade, + float death_scale, float* add_color); + void SetupEyeLidShading(ObjectComponent* c, float death_fade, + float* add_color); + void DrawEyeLids(RenderComponent* c, float death_fade, float death_scale); + void DrawEyeBalls(RenderComponent* c, ObjectComponent* oc, bool shading, + float death_fade, float death_scale, float* add_color); + void DoFlyPress(); + + // Create a fixed joint between two bodies. + // The anchor is by default at the center of the first body. + auto CreateFixedJoint(RigidBody* b1, RigidBody* b2, float ls, float ld, + float as, float ad) -> JointFixedEF*; + + // Same but more explicit; provide anchor offsets for the two bodies. + // This also moves the second body based on those values so the anchor + // points line up. + auto CreateFixedJoint(RigidBody* b1, RigidBody* b2, float ls, float ld, + float as, float ad, float a1x, float a1y, float a1z, + float a2x, float a2y, float a2z, bool reposition = true) + -> JointFixedEF*; + void Throw(bool withBombButton); + + // Reset to a standing, non-moving state at the given point. + void Stand(float x, float y, float z, float angle); + void OnGraphicsQualityChanged(GraphicsQuality q) override; + void UpdateForGraphicsQuality(GraphicsQuality q); + void UpdateAreaOfInterest(); + auto CollideCallback(dContact* c, int count, RigidBody* colliding_body, + RigidBody* opposingbody) -> bool; + auto PreFilterCollision(RigidBody* r1, RigidBody* r2) -> bool override; + auto IsBrokenBodyPart(int id) -> bool; + static auto StaticCollideCallback(dContact* c, int count, + RigidBody* colliding_body, + RigidBody* opposingbody, void* data) + -> bool { + auto* a = static_cast(data); + return a->CollideCallback(c, count, colliding_body, opposingbody); + } + void DropHeldObject(); + void ApplyTorque(float x, float y, float z); + void CreateHair(); + void DestroyHair(); + void UpdateBodiesForStyle(); + void UpdateJoints(); +#if !BA_HEADLESS_BUILD + class FullShadowSet; + class SimpleShadowSet; + Object::Ref full_shadow_set_; + Object::Ref simple_shadow_set_; +#endif // !BA_HEADLESS_BUILD + float pickup_pos_1_[3]{0.0f, 0.0f, 0.0f}; + float pickup_pos_2_[3]{0.0f, 0.0f, 0.0f}; + float pickup_q1_[4]{0.0f, 0.0f, 0.0f, 0.0f}; + float pickup_q2_[4]{0.0f, 0.0f, 0.0f, 0.0f}; + uint32_t step_count_{}; + millisecs_t birth_time_{}; + Object::Ref color_texture_; + Object::Ref color_mask_texture_; + Object::Ref head_model_; + Object::Ref torso_model_; + Object::Ref pelvis_model_; + Object::Ref upper_arm_model_; + Object::Ref forearm_model_; + Object::Ref hand_model_; + Object::Ref upper_leg_model_; + Object::Ref lower_leg_model_; + Object::Ref toes_model_; + std::vector > jump_sounds_; + std::vector > attack_sounds_; + std::vector > impact_sounds_; + std::vector > death_sounds_; + std::vector > pickup_sounds_; + std::vector > fall_sounds_; + Object::WeakRef hold_node_; + std::string style_{"spaz"}; + Object::WeakRef source_player_; + bool clamp_move_values_to_circle_{true}; + bool demo_mode_{}; + std::string curse_timer_txt_; + TextGroup curse_timer_text_group_; + std::string counter_mesh_text_; + TextGroup counter_text_group_; + std::string counter_text_; + std::vector name_color_{1.0f, 1.0f, 1.0f}; + std::string name_; + std::string name_mesh_txt_; + TextGroup name_text_group_; + MeshIndexedSimpleFull billboard_1_mesh_; + MeshIndexedSimpleFull billboard_2_mesh_; + MeshIndexedSimpleFull billboard_3_mesh_; + float punch_power_{}; + float impact_damage_accum_{}; + Part spaz_part_; + Part hair_part_; + Part punch_part_; + Part pickup_part_; + Part roller_part_; + Part extras_part_; + Part limbs_part_upper_; + Part limbs_part_lower_; + bool dead_{}; + // 1 for partially-shattered, 2 for completely. + int shattered_{}; + bool invincible_{}; + bool trying_to_fly_{}; + bool throwing_with_bomb_button_{}; + bool can_fly_{}; + bool hockey_{}; + bool have_boxing_gloves_{}; + bool boxing_gloves_flashing_{}; + bool frozen_{}; + uint8_t flashing_{}; + float throw_power_{}; + millisecs_t throw_start_{}; + bool have_thrown_{}; + int hold_body_{}; + millisecs_t last_head_collide_time_{}; + millisecs_t last_external_impulse_time_{}; + millisecs_t last_impact_damage_dispatch_time_{}; + Object::Ref billboard_texture_; + float billboard_opacity_{}; + float area_of_interest_radius_{5.0f}; + Object::Ref counter_texture_; + Object::Ref mini_billboard_1_texture_; + millisecs_t mini_billboard_1_start_time_{}; + millisecs_t mini_billboard_1_end_time_{}; + Object::Ref mini_billboard_2_texture_; + millisecs_t mini_billboard_2_start_time_{}; + millisecs_t mini_billboard_2_end_time_{}; + Object::Ref mini_billboard_3_texture_; + millisecs_t mini_billboard_3_start_time_{}; + millisecs_t mini_billboard_3_end_time_{}; + millisecs_t curse_death_time_{}; + millisecs_t last_out_of_bounds_time_{}; + float base_pelvis_roller_anchor_offset_{}; + std::vector color_{1.0f, 1.0f, 1.0f}; + std::vector highlight_{0.5f, 0.5f, 0.5f}; + std::vector shadow_color_{0.5f, 0.5f, 0.5f}; + bool wings_{}; + Vector3f wing_pos_left_{0.0f, 0.0f, 0.0f}; + Vector3f wing_vel_left_{0.0f, 0.0f, 0.0f}; + Vector3f wing_pos_right_{0.0f, 0.0f, 0.0f}; + Vector3f wing_vel_right_{0.0f, 0.0f, 0.0f}; + uint32_t voice_play_id_{0xFFFFFFFF}; + uint32_t tick_play_id_{0xFFFFFFFF}; + millisecs_t last_fall_time_{}; + uint32_t fall_play_id_{}; + AreaOfInterest* area_of_interest_{}; + millisecs_t celebrate_until_time_left_{}; + millisecs_t celebrate_until_time_right_{}; + millisecs_t last_fly_time_{}; + int footing_{}; + int8_t lr_{}; + int8_t ud_{}; + float lr_norm_{}; + float raw_ud_norm_{}; + float raw_lr_norm_{}; + float ud_norm_{}; + float ud_smooth_{}; + float lr_smooth_{}; + float ud_diff_smooth_{}; + float lr_diff_smooth_{}; + float ud_diff_smoother_{}; + float lr_diff_smoother_{}; + float prev_vel_[3]{0.0f, 0.0f, 0.0f}; + float accel_[3]{0.0f, 0.0f, 0.0f}; + float throw_ud_{}; + float throw_lr_{}; + uint8_t behavior_version_{}; + uint8_t balance_{}; + uint8_t dizzy_{}; + uint8_t knockout_{}; + uint8_t jump_{}; + uint8_t punch_{}; + uint8_t pickup_{}; + float fly_power_{}; + float ball_size_{1.0f}; + float run_{}; + float move_left_right_{}; + float move_up_down_{}; + bool jump_pressed_{}; + bool punch_pressed_{}; + bool bomb_pressed_{}; + bool fly_pressed_{}; + bool pickup_pressed_{}; + bool hold_position_pressed_{}; + millisecs_t last_jump_time_{}; + RigidBody::Joint pickup_joint_; + float eyes_lr_{}; + float eyes_ud_{}; + float eyes_lr_smooth_{}; + float eyes_ud_smooth_{}; + float eyelid_left_ud_{}; + float eyelid_left_ud_smooth_{}; + float eyelid_right_ud_{}; + float eyelid_right_ud_smooth_{}; + float blink_{}; + float blink_smooth_{}; + bool flap_{}; + bool flapping_{}; + bool holding_something_{}; + millisecs_t last_pickup_time_{}; + millisecs_t last_punch_time_{}; + bool throwing_{}; + bool head_back_{}; + millisecs_t last_force_scream_time_{}; + bool force_scream_{}; + Object::Ref body_head_; + Object::Ref body_torso_; + Object::Ref body_pelvis_; + Object::Ref body_roller_; + Object::Ref body_punch_; + Object::Ref body_pickup_; + Object::Ref stand_body_; + Object::Ref upper_right_arm_body_; + Object::Ref lower_right_arm_body_; + Object::Ref upper_left_arm_body_; + Object::Ref lower_left_arm_body_; + Object::Ref upper_right_leg_body_; + Object::Ref lower_right_leg_body_; + Object::Ref upper_left_leg_body_; + Object::Ref lower_left_leg_body_; + Object::Ref left_toes_body_; + Object::Ref right_toes_body_; + JointFixedEF* upper_right_arm_joint_{}; + JointFixedEF* lower_right_arm_joint_{}; + JointFixedEF* upper_left_arm_joint_{}; + JointFixedEF* lower_left_arm_joint_{}; + JointFixedEF* upper_right_leg_joint_{}; + JointFixedEF* lower_right_leg_joint_{}; + JointFixedEF* upper_left_leg_joint_{}; + JointFixedEF* lower_left_leg_joint_{}; + JointFixedEF* left_toes_joint_{}; + JointFixedEF* left_toes_joint_2_{}; + JointFixedEF* right_toes_joint_{}; + JointFixedEF* right_toes_joint_2_{}; + JointFixedEF* right_leg_ik_joint_{}; + JointFixedEF* left_leg_ik_joint_{}; + JointFixedEF* right_arm_ik_joint_{}; + JointFixedEF* left_arm_ik_joint_{}; + float last_stand_body_orient_x_{}; + float last_stand_body_orient_z_{}; + JointFixedEF* neck_joint_{}; + JointFixedEF* pelvis_joint_{}; + JointFixedEF* roller_ball_joint_{}; + dJointID a_motor_brakes_{}; + JointFixedEF* stand_joint_{}; + dJointID a_motor_roller_{}; + bool female_{}; + bool female_hair_{}; + bool eyeless_{}; + bool fat_{}; + bool pirate_{}; + bool flippers_{}; + bool frosty_{}; + bool dull_reflection_{}; + bool ninja_{}; + bool punch_right_{}; + Object::Ref hair_front_right_body_; + JointFixedEF* hair_front_right_joint_{}; + Object::Ref hair_front_left_body_; + JointFixedEF* hair_front_left_joint_{}; + Object::Ref hair_ponytail_top_body_; + JointFixedEF* hair_ponytail_top_joint_{}; + Object::Ref hair_ponytail_bottom_body_; + JointFixedEF* hair_ponytail_bottom_joint_{}; + float hold_hand_offset_left_[3]{}; + float hold_hand_offset_right_[3]{}; + float jolt_head_vel_[3]{0.0f, 0.0f, 0.0f}; + millisecs_t last_shatter_test_time_{}; + float roll_amt_{}; + float damage_smoothed_{}; + float damage_out_{}; + float punch_dir_x_{1.0f}; + float punch_dir_z_{}; + float punch_momentum_angular_{}; + float punch_momentum_angular_d_{}; + float punch_momentum_linear_{}; + float punch_momentum_linear_d_{}; + float a_vel_y_smoothed_{}; + float a_vel_y_smoothed_more_{}; + float eye_lid_angle_{}; + bool last_hit_was_punch_{}; + int fly_time_{}; + float eye_ball_color_red_{0.5f}; + float eye_ball_color_green_{0.5f}; + float eye_ball_color_blue_{0.5f}; + float eye_lid_color_red_{0.5f}; + float eye_lid_color_green_{0.3f}; + float eye_lid_color_blue_{0.2f}; + float eye_color_red_{0.5f}; + float eye_color_green_{0.5f}; + float eye_color_blue_{1.2f}; + float torso_radius_{0.15f}; + float shoulder_offset_x_{}; + float shoulder_offset_y_{}; + float shoulder_offset_z_{}; + bool has_eyelids_{true}; + float eye_scale_{1.0f}; + float reflection_scale_{0.1f}; + float default_eye_lid_angle_{}; + float eye_offset_x_{}; + float eye_offset_y_{}; + float eye_offset_z_{}; + millisecs_t last_got_boxing_gloves_time_{}; + uint32_t shatter_damage_{}; + bool running_{}; + float speed_smoothed_{}; + float run_gas_{}; + float hurt_{}; + float hurt_smoothed_{}; + millisecs_t last_hurt_change_time_{}; + bool billboard_cross_out_{}; + millisecs_t death_time_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_SPAZ_NODE_H_ diff --git a/src/ballistica/scene/node/terrain_node.cc b/src/ballistica/scene/node/terrain_node.cc new file mode 100644 index 00000000..49fcd38a --- /dev/null +++ b/src/ballistica/scene/node/terrain_node.cc @@ -0,0 +1,259 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/terrain_node.h" + +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/dynamics/material/material.h" +#include "ballistica/graphics/component/object_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/media/component/collide_model.h" +#include "ballistica/media/component/model.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class TerrainNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS TerrainNode + BA_NODE_CREATE_CALL(createTerrain); + BA_BOOL_ATTR(visible_in_reflections, visible_in_reflections, + set_visible_in_reflections); + BA_BOOL_ATTR(affect_bg_dynamics, affects_bg_dynamics, + set_affects_bg_dynamics); + BA_BOOL_ATTR(bumper, bumper, SetBumper); + BA_BOOL_ATTR(background, background, set_background); + BA_BOOL_ATTR(overlay, overlay, set_overlay); + BA_FLOAT_ATTR(opacity, opacity, set_opacity); + BA_FLOAT_ATTR(opacity_in_low_or_medium_quality, + opacity_in_low_or_medium_quality, + set_opacity_in_low_or_medium_quality); + BA_STRING_ATTR(reflection, GetReflection, SetReflection); + BA_FLOAT_ARRAY_ATTR(reflection_scale, reflection_scale, SetReflectionScale); + BA_BOOL_ATTR(lighting, getLighting, setLighting); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_MODEL_ATTR(model, model, SetModel); + BA_TEXTURE_ATTR(color_texture, color_texture, SetColorTexture); + BA_COLLIDE_MODEL_ATTR(collide_model, collide_model, SetCollideModel); + BA_MATERIAL_ARRAY_ATTR(materials, GetMaterials, SetMaterials); + BA_BOOL_ATTR(vr_only, vr_only, set_vr_only); +#undef BA_NODE_TYPE_CLASS + + TerrainNodeType() + : NodeType("terrain", createTerrain), + visible_in_reflections(this), + affect_bg_dynamics(this), + bumper(this), + background(this), + overlay(this), + opacity(this), + opacity_in_low_or_medium_quality(this), + reflection(this), + reflection_scale(this), + lighting(this), + color(this), + model(this), + color_texture(this), + collide_model(this), + materials(this), + vr_only(this) {} +}; +static NodeType* node_type{}; + +auto TerrainNode::InitType() -> NodeType* { + node_type = new TerrainNodeType(); + return node_type; +} + +TerrainNode::TerrainNode(Scene* scene) + : Node(scene, node_type), + visible_in_reflections_(true), + opacity_(1.0f), + opacity_in_low_or_medium_quality_(-1.0f), + terrain_part_(this), + background_(false), + overlay_(false), + lighting_(true), + bumper_(false), + affect_bg_dynamics_(true), + bg_dynamics_collide_model_(nullptr), + reflection_(ReflectionType::kNone), + reflection_scale_(3, 1.0f), + reflection_scale_r_(1.0f), + reflection_scale_g_(1.0f), + reflection_scale_b_(1.0f), + color_(3, 1.0f), + color_r_(1.0f), + color_g_(1.0f), + color_b_(1.0f), + vr_only_(false) { + scene->increment_bg_cover_count(); +} + +TerrainNode::~TerrainNode() { + scene()->decrement_bg_cover_count(); + RemoveFromBGDynamics(); + + // If we've got a collide-model, this is a good time to mark + // it as used since it may be getting opened up to pruning + // without our reference. + if (collide_model_.exists()) { + collide_model_->collide_model_data()->set_last_used_time(GetRealTime()); + } +} + +auto TerrainNode::GetMaterials() const -> std::vector { + return RefsToPointers(materials_); +} + +void TerrainNode::SetMaterials(const std::vector& vals) { + materials_ = PointersToRefs(vals); + terrain_part_.SetMaterials(vals); +} + +void TerrainNode::SetModel(Model* val) { model_ = val; } + +void TerrainNode::SetCollideModel(CollideModel* val) { + // if we had an old one, mark its last-used time so caching works properly.. + if (collide_model_.exists()) { + collide_model_->collide_model_data()->set_last_used_time(GetRealTime()); + } + collide_model_ = val; + + // remove any existing.. + RemoveFromBGDynamics(); + + if (collide_model_.exists()) { + uint32_t flags = bumper_ ? RigidBody::kIsBumper : 0; + flags |= RigidBody::kIsTerrain; + body_ = Object::New( + 0, &terrain_part_, RigidBody::Type::kGeomOnly, + RigidBody::Shape::kTrimesh, RigidBody::kCollideBackground, + RigidBody::kCollideAll ^ RigidBody::kCollideBackground, + collide_model_.get(), flags); + body_->set_can_cause_impact_damage(true); + + // also ship it to the BG-Dynamics thread.. + if (!bumper_ && affect_bg_dynamics_) { + AddToBGDynamics(); + } + } else { + body_.Clear(); + } +} + +void TerrainNode::SetColorTexture(Texture* val) { color_texture_ = val; } + +void TerrainNode::SetReflectionScale(const std::vector& vals) { + if (vals.size() != 1 && vals.size() != 3) + throw Exception("Expected float array of size 1 or 3 for reflection_scale"); + reflection_scale_ = vals; + if (reflection_scale_.size() == 1) { + reflection_scale_r_ = reflection_scale_g_ = reflection_scale_b_ = + reflection_scale_[0]; + } else { + reflection_scale_r_ = reflection_scale_[0]; + reflection_scale_g_ = reflection_scale_[1]; + reflection_scale_b_ = reflection_scale_[2]; + } +} + +void TerrainNode::SetColor(const std::vector& vals) { + if (vals.size() != 1 && vals.size() != 3) + throw Exception("Expected float array of size 1 or 3 for color"); + color_ = vals; + if (color_.size() == 1) { + color_r_ = color_g_ = color_b_ = color_[0]; + } else { + color_r_ = color_[0]; + color_g_ = color_[1]; + color_b_ = color_[2]; + } +} + +auto TerrainNode::GetReflection() const -> std::string { + return Graphics::StringFromReflectionType(reflection_); +} +void TerrainNode::SetReflection(const std::string& val) { + reflection_ = Graphics::ReflectionTypeFromString(val); +} + +void TerrainNode::SetBumper(bool val) { + bumper_ = val; + if (body_.exists()) { + uint32_t is_bumper{RigidBody::kIsBumper}; + if (bumper_) { + body_->set_flags(body_->flags() | is_bumper); // on + } else { + body_->set_flags(body_->flags() & ~is_bumper); // off + } + } +} + +void TerrainNode::AddToBGDynamics() { + assert(bg_dynamics_collide_model_ == nullptr && collide_model_.exists() + && !bumper_ && affect_bg_dynamics_); + bg_dynamics_collide_model_ = collide_model_.get(); +#if !BA_HEADLESS_BUILD + g_bg_dynamics->AddTerrain(bg_dynamics_collide_model_->collide_model_data()); +#endif // !BA_HEADLESS_BUILD +} + +void TerrainNode::RemoveFromBGDynamics() { + if (bg_dynamics_collide_model_ != nullptr) { +#if !BA_HEADLESS_BUILD + g_bg_dynamics->RemoveTerrain( + bg_dynamics_collide_model_->collide_model_data()); +#endif // !BA_HEADLESS_BUILD + bg_dynamics_collide_model_ = nullptr; + } +} + +void TerrainNode::Draw(FrameDef* frame_def) { + if (!model_.exists()) { + return; + } + if (vr_only_ && !IsVRMode()) { + return; + } + ObjectComponent c(overlay_ ? frame_def->overlay_3d_pass() + : background_ ? frame_def->beauty_pass_bg() + : frame_def->beauty_pass()); + c.SetWorldSpace(true); + c.SetTexture(color_texture_); + if (lighting_) { + c.SetLightShadow(LightShadowType::kTerrain); + } else { + c.SetLightShadow(LightShadowType::kNone); + } + if (reflection_ != ReflectionType::kNone) { + c.SetReflection(reflection_); + c.SetReflectionScale(reflection_scale_r_, reflection_scale_g_, + reflection_scale_b_); + } + float opacity; + if (frame_def->quality() <= GraphicsQuality::kHigh + && opacity_in_low_or_medium_quality_ >= 0.0f) { + opacity = opacity_in_low_or_medium_quality_; + } else { + opacity = opacity_; + } + + // these options currently don't have a world-space-optimized version.. + if (opacity < 1.0f || overlay_) { + c.SetTransparent(true); + c.SetWorldSpace(false); + c.SetColor(color_r_, color_g_, color_b_, opacity); + } else { + c.SetColor(color_r_, color_g_, color_b_, 1.0f); + } + uint32_t drawFlags = 0; + if (!visible_in_reflections_) { + drawFlags |= kModelDrawFlagNoReflection; + } + c.DrawModel(model_->model_data(), drawFlags); + c.Submit(); +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/terrain_node.h b/src/ballistica/scene/node/terrain_node.h new file mode 100644 index 00000000..a8f2b87d --- /dev/null +++ b/src/ballistica/scene/node/terrain_node.h @@ -0,0 +1,89 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_TERRAIN_NODE_H_ +#define BALLISTICA_SCENE_NODE_TERRAIN_NODE_H_ + +#include +#include + +#include "ballistica/dynamics/part.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class TerrainNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit TerrainNode(Scene* scene); + ~TerrainNode() override; + void Draw(FrameDef* frame_def) override; + auto visible_in_reflections() const -> bool { + return visible_in_reflections_; + } + void set_visible_in_reflections(bool val) { visible_in_reflections_ = val; } + auto affects_bg_dynamics() const -> bool { return affect_bg_dynamics_; } + void set_affects_bg_dynamics(bool val) { affect_bg_dynamics_ = val; } + auto bumper() const -> bool { return bumper_; } + void SetBumper(bool val); + auto background() const -> bool { return background_; } + void set_background(bool val) { background_ = val; } + auto overlay() const -> bool { return overlay_; } + void set_overlay(bool val) { overlay_ = val; } + auto opacity() const -> float { return opacity_; } + void set_opacity(float val) { opacity_ = val; } + auto opacity_in_low_or_medium_quality() const -> float { + return opacity_in_low_or_medium_quality_; + } + void set_opacity_in_low_or_medium_quality(float val) { + opacity_in_low_or_medium_quality_ = val; + } + auto GetReflection() const -> std::string; + void SetReflection(const std::string& val); + auto reflection_scale() const -> std::vector { + return reflection_scale_; + } + void SetReflectionScale(const std::vector& vals); + auto getLighting() const -> bool { return lighting_; } + void setLighting(bool val) { lighting_ = val; } + auto color() const -> const std::vector& { return color_; } + void SetColor(const std::vector& vals); + auto model() const -> Model* { return model_.get(); } + void SetModel(Model* m); + auto color_texture() const -> Texture* { return color_texture_.get(); } + void SetColorTexture(Texture* val); + auto collide_model() const -> CollideModel* { return collide_model_.get(); } + void SetCollideModel(CollideModel* val); + auto GetMaterials() const -> std::vector; + void SetMaterials(const std::vector& vals); + auto vr_only() const -> bool { return vr_only_; } + void set_vr_only(bool val) { vr_only_ = val; } + + private: + void AddToBGDynamics(); + void RemoveFromBGDynamics(); + CollideModel* bg_dynamics_collide_model_; + bool vr_only_; + bool bumper_; + bool affect_bg_dynamics_; + bool lighting_; + bool background_; + bool overlay_; + float opacity_; + float opacity_in_low_or_medium_quality_; + Object::Ref model_; + Object::Ref collide_model_; + Object::Ref color_texture_; + std::vector > materials_; + Part terrain_part_; + Object::Ref body_; + bool visible_in_reflections_; + ReflectionType reflection_; + std::vector reflection_scale_; + float reflection_scale_r_, reflection_scale_g_, reflection_scale_b_; + std::vector color_; + float color_r_, color_g_, color_b_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_TERRAIN_NODE_H_ diff --git a/src/ballistica/scene/node/text_node.cc b/src/ballistica/scene/node/text_node.cc new file mode 100644 index 00000000..a5f1fc1d --- /dev/null +++ b/src/ballistica/scene/node/text_node.cc @@ -0,0 +1,646 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/text_node.h" + +#include + +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class TextNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS TextNode + BA_NODE_CREATE_CALL(CreateText); + BA_FLOAT_ATTR(opacity, opacity, set_opacity); + BA_FLOAT_ATTR(trail_opacity, trail_opacity, set_trail_opacity); + BA_FLOAT_ATTR(project_scale, project_scale, set_project_scale); + BA_FLOAT_ATTR(scale, scale, set_scale); + BA_FLOAT_ARRAY_ATTR(position, position, SetPosition); + BA_STRING_ATTR(text, getText, SetText); + BA_BOOL_ATTR(big, big, SetBig); + BA_BOOL_ATTR(trail, trail, set_trail); + BA_FLOAT_ARRAY_ATTR(color, color, SetColor); + BA_FLOAT_ARRAY_ATTR(trailcolor, trail_color, SetTrailColor); + BA_FLOAT_ATTR(trail_project_scale, trail_project_scale, + set_trail_project_scale); + BA_BOOL_ATTR(opacity_scales_shadow, opacity_scales_shadow, + set_opacity_scales_shadow); + BA_STRING_ATTR(h_align, GetHAlign, SetHAlign); + BA_STRING_ATTR(v_align, GetVAlign, SetVAlign); + BA_STRING_ATTR(h_attach, GetHAttach, SetHAttach); + BA_STRING_ATTR(v_attach, GetVAttach, SetVAttach); + BA_BOOL_ATTR(in_world, in_world, set_in_world); + BA_FLOAT_ATTR(tilt_translate, tilt_translate, set_tilt_translate); + BA_FLOAT_ATTR(maxwidth, max_width, set_max_width); + BA_FLOAT_ATTR(shadow, shadow, set_shadow); + BA_FLOAT_ATTR(flatness, flatness, set_flatness); + BA_BOOL_ATTR(client_only, client_only, set_client_only); + BA_BOOL_ATTR(host_only, host_only, set_host_only); + BA_FLOAT_ATTR(vr_depth, vr_depth, set_vr_depth); + BA_FLOAT_ATTR(rotate, rotate, set_rotate); + BA_BOOL_ATTR(front, front, set_front); +#undef BA_NODE_TYPE_CLASS + TextNodeType() + : NodeType("text", CreateText), + opacity(this), + trail_opacity(this), + project_scale(this), + scale(this), + position(this), + text(this), + big(this), + trail(this), + color(this), + trailcolor(this), + trail_project_scale(this), + opacity_scales_shadow(this), + h_align(this), + v_align(this), + h_attach(this), + v_attach(this), + in_world(this), + tilt_translate(this), + maxwidth(this), + shadow(this), + flatness(this), + client_only(this), + host_only(this), + vr_depth(this), + rotate(this), + front(this) {} +}; +static NodeType* node_type{}; + +auto TextNode::InitType() -> NodeType* { + node_type = new TextNodeType(); + return node_type; +} + +TextNode::TextNode(Scene* scene) : Node(scene, node_type) {} + +TextNode::~TextNode() = default; + +void TextNode::SetText(const std::string& val) { + if (text_raw_ != val) { + assert(Utils::IsValidUTF8(val)); + + // In some cases we want to make sure this is a valid resource-string + // since catching the error here is much more useful than if we catch + // it at draw-time. However this is expensive so we only do it for debug + // mode or if the string looks suspicious. + bool do_format_check{}; + bool print_false_positives{}; + + if (g_buildconfig.debug_build()) { + do_format_check = true; + } else { + if (val.size() > 1 && val[0] == '{' && val[val.size() - 1] == '}') { + // ok, its got bounds like json; now if its either missing quotes or a + // colon then let's check it.. + if (!strstr(val.c_str(), "\"") || !strstr(val.c_str(), ":")) { + do_format_check = true; + // we wanna avoid doing this check when we don't have to.. + // so lets print if we get a false positive + print_false_positives = true; + } + } + } + + if (do_format_check) { + bool valid; + g_game->CompileResourceString(val, "setText format check", &valid); + if (!valid) { + BA_LOG_ONCE("Invalid resource string: '" + val + "' on node '" + label() + + "'"); + Python::PrintStackTrace(); + } else if (print_false_positives) { + BA_LOG_ONCE("Got false positive for json check on '" + val + "'"); + Python::PrintStackTrace(); + } + } + text_translation_dirty_ = true; + text_raw_ = val; + } +} + +void TextNode::SetBig(bool val) { + big_ = val; + text_group_dirty_ = true; + text_width_dirty_ = true; +} + +auto TextNode::GetHAlign() const -> std::string { + if (h_align_ == HAlign::kLeft) { + return "left"; + } else if (h_align_ == HAlign::kRight) { + return "right"; + } else if (h_align_ == HAlign::kCenter) { + return "center"; + } else { + BA_LOG_ONCE("Error: Invalid h_align value in text-node: " + + std::to_string(static_cast(h_align_))); + return ""; + } +} + +void TextNode::SetHAlign(const std::string& val) { + text_group_dirty_ = true; + if (val == "left") { + h_align_ = HAlign::kLeft; + } else if (val == "right") { + h_align_ = HAlign::kRight; + } else if (val == "center") { + h_align_ = HAlign::kCenter; + } else { + throw Exception("Invalid h_align for text node: " + val); + } +} + +auto TextNode::GetVAlign() const -> std::string { + if (v_align_ == VAlign::kTop) { + return "top"; + } else if (v_align_ == VAlign::kBottom) { + return "bottom"; + } else if (v_align_ == VAlign::kCenter) { + return "center"; + } else if (v_align_ == VAlign::kNone) { + return "none"; + } else { + BA_LOG_ONCE("Error: Invalid v_align value in text-node: " + + std::to_string(static_cast(v_align_))); + return ""; + } +} + +void TextNode::SetVAlign(const std::string& val) { + text_group_dirty_ = true; + if (val == "top") { + v_align_ = VAlign::kTop; + } else if (val == "bottom") { + v_align_ = VAlign::kBottom; + } else if (val == "center") { + v_align_ = VAlign::kCenter; + } else if (val == "none") { + v_align_ = VAlign::kNone; + } else { + throw Exception("Invalid v_align for text node: " + val); + } +} + +auto TextNode::GetHAttach() const -> std::string { + if (h_attach_ == HAttach::kLeft) { + return "left"; + } else if (h_attach_ == HAttach::kRight) { + return "right"; + } else if (h_attach_ == HAttach::kCenter) { + return "center"; + } else { + BA_LOG_ONCE("Error: Invalid h_attach value in text-node: " + + std::to_string(static_cast(h_attach_))); + return ""; + } +} + +void TextNode::SetHAttach(const std::string& val) { + position_final_dirty_ = true; + if (val == "left") { + h_attach_ = HAttach::kLeft; + } else if (val == "right") { + h_attach_ = HAttach::kRight; + } else if (val == "center") { + h_attach_ = HAttach::kCenter; + } else { + throw Exception("Invalid h_attach for text node: " + val); + } +} + +auto TextNode::GetVAttach() const -> std::string { + if (v_attach_ == VAttach::kTop) { + return "top"; + } else if (v_attach_ == VAttach::kBottom) { + return "bottom"; + } else if (v_attach_ == VAttach::kCenter) { + return "center"; + } else { + BA_LOG_ONCE("Error: Invalid v_attach value in text-node: " + + std::to_string(static_cast(v_attach_))); + return ""; + } +} + +void TextNode::SetVAttach(const std::string& val) { + position_final_dirty_ = true; + if (val == "top") { + v_attach_ = VAttach::kTop; + } else if (val == "bottom") { + v_attach_ = VAttach::kBottom; + } else if (val == "center") { + v_attach_ = VAttach::kCenter; + } else { + throw Exception("Invalid v_attach for text node: " + val); + } +} + +void TextNode::SetColor(const std::vector& vals) { + if (vals.size() != 3 && vals.size() != 4) { + throw Exception("Expected float array of size 3 or 4 for color"); + } + color_ = vals; + if (color_.size() == 3) { + color_.push_back(1.0f); + } +} + +void TextNode::SetTrailColor(const std::vector& vals) { + if (vals.size() != 3) { + throw Exception("Expected float array of size 3 for trailcolor"); + } + trail_color_ = vals; +} + +void TextNode::SetPosition(const std::vector& val) { + if (val.size() != 2 && val.size() != 3) { + throw Exception("Expected float array of length 2 or 3 for position; got " + + std::to_string(val.size())); + } + position_ = val; + position_final_dirty_ = true; +} + +void TextNode::OnScreenSizeChange() { position_final_dirty_ = true; } + +void TextNode::Update() { + // Update our final translate if need be. + if (position_final_dirty_) { + float offset_h; + float offset_v; + + if (in_world_) { + offset_h = 0.0f; + offset_v = 0.0f; + } else { + // Screen space; apply alignment and stuff. + if (h_attach_ == HAttach::kLeft) { + offset_h = 0; + } else if (h_attach_ == HAttach::kRight) { + offset_h = g_graphics->screen_virtual_width(); + } else if (h_attach_ == HAttach::kCenter) { + offset_h = g_graphics->screen_virtual_width() / 2; + } else { + throw Exception("invalid h_attach"); + } + if (v_attach_ == VAttach::kTop) { + offset_v = g_graphics->screen_virtual_height(); + } else if (v_attach_ == VAttach::kBottom) { + offset_v = 0; + } else if (v_attach_ == VAttach::kCenter) { + offset_v = g_graphics->screen_virtual_height() / 2; + } else { + throw Exception("invalid v_attach"); + } + } + position_final_ = position_; + if (position_final_.size() == 2) { + position_final_.push_back(0.0f); + } + position_final_[0] += offset_h; + position_final_[1] += offset_v; + position_final_dirty_ = false; + } +} + +void TextNode::Draw(FrameDef* frame_def) { + if (client_only_ && context().GetHostSession()) { + return; + } + if (host_only_ && !context().GetHostSession()) { + return; + } + + // Apply subs/resources to get our actual text if need be. + if (text_translation_dirty_) { + text_translated_ = + g_game->CompileResourceString(text_raw_, "TextNode::OnDraw"); + text_translation_dirty_ = false; + text_group_dirty_ = true; + text_width_dirty_ = true; + } + + if (text_translated_.size() <= 0.0f) { + return; + } + + // recalc our text width if need be.. + if (text_width_dirty_) { + text_width_ = + g_text_graphics->GetStringWidth(text_translated_.c_str(), big_); + text_width_dirty_ = false; + } + + bool vr_2d_text = (IsVRMode() && !in_world_); + + // in vr mode we use the fixed overlay position if our scene is set for + // that + bool vr_use_fixed = (IsVRMode() && scene()->use_fixed_vr_overlay()); + + // FIXME - in VR, fixed and front are currently mutually exclusive; need to + // implement that. + if (front_) { + vr_use_fixed = false; + } + + // make sure we're up to date + Update(); + RenderPass& pass( + *(in_world_ ? frame_def->overlay_3d_pass() + : (vr_use_fixed ? frame_def->GetOverlayFixedPass() + : front_ ? frame_def->overlay_front_pass() + : frame_def->overlay_pass()))); + if (big_) { + if (text_group_dirty_) { + TextMesh::HAlign h_align; + switch (h_align_) { + case HAlign::kLeft: + h_align = TextMesh::HAlign::kLeft; + break; + case HAlign::kRight: + h_align = TextMesh::HAlign::kRight; + break; + case HAlign::kCenter: + h_align = TextMesh::HAlign::kCenter; + break; + default: + throw Exception(); + } + + TextMesh::VAlign v_align; + switch (v_align_) { + case VAlign::kNone: + v_align = TextMesh::VAlign::kNone; + break; + case VAlign::kCenter: + v_align = TextMesh::VAlign::kCenter; + break; + case VAlign::kTop: + v_align = TextMesh::VAlign::kTop; + break; + case VAlign::kBottom: + v_align = TextMesh::VAlign::kBottom; + break; + default: + throw Exception(); + } + + // update if need be + text_group_.SetText(text_translated_, h_align, v_align, true, 2.5f); + text_group_dirty_ = false; + } + + float z = vr_2d_text ? 0.0f : g_graphics->overlay_node_z_depth(); + + assert(!text_width_dirty_); + float tx = position_final_[0]; + float ty = position_final_[1]; + float tx_tilt = 0; + float ty_tilt = 0; + + // left/rigth shift from tilting the device + if (tilt_translate_ != 0.0f) { + Vector3f tilt = g_graphics->tilt(); + tx_tilt = -tilt.y * tilt_translate_; + ty_tilt = tilt.x * tilt_translate_; + } + + assert(!text_width_dirty_); + float extrascale; + float textWidth = text_width_; + float extrascale_2 = 3.5f; + + if (max_width_ > 0.0f && (textWidth * scale_ * extrascale_2) > max_width_) { + extrascale = max_width_ / (textWidth * scale_ * extrascale_2); + } else { + extrascale = 1.0f; + } + extrascale *= scale_; + + float pass_width = pass.virtual_width(); + float pass_height = pass.virtual_height(); + { + // new style + { + // draw trails.. + if (trail_) { + int passes = 2; + if (trail_project_scale_ != project_scale_) { + for (int i = 0; i < passes; i++) { + float o = trail_opacity_ * 0.5f; + { + auto i_f = static_cast(i); + auto passes_f = static_cast(passes); + float x = tx + tx_tilt * (i_f / passes_f) - pass_width / 2.0f; + float y = ty + ty_tilt * (i_f / passes_f) - pass_height / 2.0f; + float project_scale = + (trail_project_scale_ + + static_cast(i) + * (project_scale_ - trail_project_scale_) + / passes_f); + SimpleComponent c(&pass); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.SetColor(trail_color_[0] * o, trail_color_[1] * o, + trail_color_[2] * o, 0.0f); + c.setGlow(1.0f, 3.0f); + + // FIXME FIXME FIXME NEED A WAY TO BLUR IN THE SHADER + int elem_count = text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + // gracefully skip unloaded textures.. + TextureData* t = text_group_.GetElementTexture(e); + if (!t->preloaded()) continue; + c.SetTexture(t); + c.SetMaskUV2Texture(text_group_.GetElementMaskUV2Texture(e)); + c.PushTransform(); + if (vr_2d_text) { + c.Translate( + 0, 0, + vr_depth_ - 15.0f * static_cast(passes - i)); + } + + // Fudge factors to keep our old look.. ew. + c.Translate(pass_width / 2 + 7.0f, pass_height / 2 + 35.0f, + z); + c.Scale(project_scale, project_scale); + c.Translate(x, y + 70.0f, 0); + c.Scale(extrascale * extrascale_2, extrascale * extrascale_2); + c.DrawMesh(text_group_.GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + } + } + + SimpleComponent c(&pass); + c.SetTransparent(true); + c.SetColor(color_[0], color_[1], color_[2], color_[3] * opacity_); + + int elem_count = text_group_.GetElementCount(); + bool did_submit = false; + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureData* t = text_group_.GetElementTexture(e); + if (!t->preloaded()) continue; + c.SetTexture(t); + float shadow_opacity = shadow_; + if (opacity_scales_shadow_) { + float o = color_[3] * opacity_; + shadow_opacity *= o * o; + } + c.SetShadow(-0.002f * text_group_.GetElementUScale(e), + -0.002f * text_group_.GetElementVScale(e), 2.5f, + shadow_opacity); + if (shadow_opacity > 0) { + c.SetMaskUV2Texture(text_group_.GetElementMaskUV2Texture(e)); + } else { + c.clearMaskUV2Texture(); + } + + c.PushTransform(); + if (vr_2d_text) { + c.Translate(0, 0, vr_depth_); + } + + // Fudge factors to keep our old look.. ew. + c.Translate(pass_width / 2 + 7.0f, pass_height / 2 + 35.0f, z); + c.Scale(project_scale_, project_scale_); + c.Translate(tx + tx_tilt - pass_width / 2, + ty + ty_tilt - pass_height / 2 + 70.0f, 0); + c.Scale(extrascale * extrascale_2, extrascale * extrascale_2); + c.DrawMesh(text_group_.GetElementMesh(e)); + c.PopTransform(); + // Any reason why we submit inside the loop here but not further + // down? + c.Submit(); + did_submit = true; + } + if (!did_submit) { + // Make sure we've got at least one. + c.Submit(); + } + } + } + } else { + // small text + if (text_group_dirty_) { + TextMesh::HAlign h_align; + switch (h_align_) { + case HAlign::kLeft: + h_align = TextMesh::HAlign::kLeft; + break; + case HAlign::kRight: + h_align = TextMesh::HAlign::kRight; + break; + case HAlign::kCenter: + h_align = TextMesh::HAlign::kCenter; + break; + default: + throw Exception(); + } + + TextMesh::VAlign v_align; + switch (v_align_) { + case VAlign::kNone: + v_align = TextMesh::VAlign::kNone; + break; + case VAlign::kCenter: + v_align = TextMesh::VAlign::kCenter; + break; + case VAlign::kTop: + v_align = TextMesh::VAlign::kTop; + break; + case VAlign::kBottom: + v_align = TextMesh::VAlign::kBottom; + break; + default: + throw Exception(); + } + + // Update if need be. + text_group_.SetText(text_translated_, h_align, v_align); + text_group_dirty_ = false; + } + float z = vr_2d_text ? 0.0f + : (in_world_ ? position_final_[2] + : g_graphics->overlay_node_z_depth()); + + assert(!text_width_dirty_); + float extrascale; + if (max_width_ > 0.0f && text_width_ > max_width_) { + extrascale = max_width_ / text_width_; + } else { + extrascale = 1.0f; + } + + SimpleComponent c(&pass); + c.SetTransparent(true); + float fin_a = color_[3] * opacity_; + int elem_count = text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + // Gracefully skip unloaded textures. + TextureData* t = text_group_.GetElementTexture(e); + if (!t->preloaded()) continue; + c.SetTexture(t); + float shadow_opacity = shadow_; + if (opacity_scales_shadow_) { + float o = color_[3] * opacity_; + shadow_opacity *= o * o; + } + c.SetShadow(-0.004f * text_group_.GetElementUScale(e), + -0.004f * text_group_.GetElementVScale(e), 0.0f, + shadow_opacity); + if (shadow_opacity > 0) { + c.SetMaskUV2Texture(text_group_.GetElementMaskUV2Texture(e)); + } else { + c.clearMaskUV2Texture(); + } + if (text_group_.GetElementCanColor(e)) { + c.SetColor(color_[0], color_[1], color_[2], fin_a); + } else { + c.SetColor(1, 1, 1, fin_a); + } + if (IsVRMode()) { + c.SetFlatness(text_group_.GetElementMaxFlatness(e)); + } else { + c.SetFlatness( + std::min(text_group_.GetElementMaxFlatness(e), flatness_)); + } + c.PushTransform(); + if (vr_2d_text) { + c.Translate(0, 0, vr_depth_); + } + c.Translate(position_final_[0], position_final_[1], z); + if (rotate_ != 0.0f) c.Rotate(rotate_, 0, 0, 1); + c.Scale(scale_ * extrascale, scale_ * extrascale, 1.0f * extrascale); + c.DrawMesh(text_group_.GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } +} + +void TextNode::OnLanguageChange() { + // All we do here is mark our translated text dirty so it'll get remade at the + // next draw. + text_translation_dirty_ = true; +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/text_node.h b/src/ballistica/scene/node/text_node.h new file mode 100644 index 00000000..2b9a7ae3 --- /dev/null +++ b/src/ballistica/scene/node/text_node.h @@ -0,0 +1,122 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_TEXT_NODE_H_ +#define BALLISTICA_SCENE_NODE_TEXT_NODE_H_ + +#include +#include + +#include "ballistica/graphics/renderer.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class TextNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit TextNode(Scene* scene); + ~TextNode() override; + void Draw(FrameDef* frame_def) override; + void OnLanguageChange() override; + void OnScreenSizeChange() override; + auto opacity() const -> float { return opacity_; } + void set_opacity(float val) { opacity_ = val; } + auto trail_opacity() const -> float { return trail_opacity_; } + void set_trail_opacity(float val) { trail_opacity_ = val; } + auto project_scale() const -> float { return project_scale_; } + void set_project_scale(float val) { project_scale_ = val; } + auto scale() const -> float { return scale_; } + void set_scale(float val) { scale_ = val; } + auto trail_project_scale() const -> float { return trail_project_scale_; } + void set_trail_project_scale(float val) { trail_project_scale_ = val; } + auto position() const -> const std::vector& { return position_; } + void SetPosition(const std::vector& val); + auto opacity_scales_shadow() const -> bool { return opacity_scales_shadow_; } + void set_opacity_scales_shadow(bool val) { opacity_scales_shadow_ = val; } + auto big() const -> bool { return big_; } + void SetBig(bool val); + auto trail() const -> bool { return trail_; } + void set_trail(bool val) { trail_ = val; } + auto getText() const -> std::string { return text_raw_; } + void SetText(const std::string& val); + auto GetHAlign() const -> std::string; + void SetHAlign(const std::string& val); + auto GetHAttach() const -> std::string; + void SetHAttach(const std::string& val); + auto GetVAttach() const -> std::string; + void SetVAttach(const std::string& val); + auto GetVAlign() const -> std::string; + void SetVAlign(const std::string& val); + auto color() const -> const std::vector& { return color_; } + void SetColor(const std::vector& vals); + auto trail_color() const -> std::vector { return trail_color_; } + void SetTrailColor(const std::vector& vals); + auto in_world() const -> bool { return in_world_; } + void set_in_world(bool val) { + in_world_ = val; + position_final_dirty_ = true; + } + auto tilt_translate() const -> float { return tilt_translate_; } + void set_tilt_translate(float val) { tilt_translate_ = val; } + auto max_width() const -> float { return max_width_; } + void set_max_width(float val) { max_width_ = val; } + auto shadow() const -> float { return shadow_; } + void set_shadow(float val) { shadow_ = val; } + auto flatness() const -> float { return flatness_; } + void set_flatness(float val) { flatness_ = val; } + auto client_only() const -> bool { return client_only_; } + void set_client_only(bool val) { client_only_ = val; } + auto host_only() const -> bool { return host_only_; } + void set_host_only(bool val) { host_only_ = val; } + auto vr_depth() const -> float { return vr_depth_; } + void set_vr_depth(float val) { vr_depth_ = val; } + auto rotate() const -> float { return rotate_; } + void set_rotate(float val) { rotate_ = val; } + auto front() const -> bool { return front_; } + void set_front(bool val) { front_ = val; } + + private: + enum class HAlign { kLeft, kCenter, kRight }; + enum class VAlign { kNone, kTop, kCenter, kBottom }; + enum class HAttach { kLeft, kCenter, kRight }; + enum class VAttach { kTop, kCenter, kBottom }; + void Update(); + TextGroup text_group_; + bool text_group_dirty_ = true; + bool text_width_dirty_ = true; + bool text_translation_dirty_ = true; + bool opacity_scales_shadow_ = true; + bool client_only_ = false; + bool host_only_ = false; + HAlign h_align_ = HAlign::kLeft; + VAlign v_align_ = VAlign::kNone; + HAttach h_attach_ = HAttach::kCenter; + VAttach v_attach_ = VAttach::kCenter; + float vr_depth_ = 0.0f; + bool in_world_ = false; + std::string text_translated_; + std::string text_raw_; + std::vector position_ = {0.0f, 0.0f, 0.0f}; + std::vector position_final_; + bool position_final_dirty_ = true; + float scale_ = 1.0f; + float rotate_ = 0.0f; + bool front_ = false; + std::vector color_ = {1.0f, 1.0f, 1.0f, 1.0f}; + std::vector trail_color_ = {1.0f, 1.0f, 1.0f}; + float project_scale_ = 1.0f; + float trail_project_scale_ = 1.0f; + float opacity_ = 1.0f; + float trail_opacity_ = 1.0f; + float shadow_ = 0.0f; + float flatness_ = 0.0f; + bool trail_ = false; + bool big_ = false; + float tilt_translate_ = 0.0f; + float max_width_ = 0.0f; + float text_width_ = 0.0f; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_TEXT_NODE_H_ diff --git a/src/ballistica/scene/node/texture_sequence_node.cc b/src/ballistica/scene/node/texture_sequence_node.cc new file mode 100644 index 00000000..6644f9dd --- /dev/null +++ b/src/ballistica/scene/node/texture_sequence_node.cc @@ -0,0 +1,76 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/texture_sequence_node.h" + +#include "ballistica/media/component/texture.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/scene.h" + +namespace ballistica { + +class TextureSequenceNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS TextureSequenceNode + BA_NODE_CREATE_CALL(CreateTextureSequence); + BA_INT_ATTR(rate, rate, set_rate); + BA_TEXTURE_ARRAY_ATTR(input_textures, input_textures, set_input_textures); + BA_TEXTURE_ATTR_READONLY(output_texture, output_texture); +#undef BA_NODE_TYPE_CLASS + + TextureSequenceNodeType() + : NodeType("texture_sequence", CreateTextureSequence), + rate(this), + input_textures(this), + output_texture(this) {} +}; +static NodeType* node_type{}; + +auto TextureSequenceNode::InitType() -> NodeType* { + node_type = new TextureSequenceNodeType(); + return node_type; +} + +TextureSequenceNode::TextureSequenceNode(Scene* scene) + : Node(scene, node_type), index_(0), rate_(1000), sleep_count_(0) {} + +auto TextureSequenceNode::input_textures() const -> std::vector { + return RefsToPointers(input_textures_); +} + +void TextureSequenceNode::set_input_textures( + const std::vector& vals) { + input_textures_ = PointersToRefs(vals); + + // Make sure index_ doesnt go out of range. + if (!input_textures_.empty()) { + index_ = index_ % static_cast(input_textures_.size()); + } +} + +auto TextureSequenceNode::output_texture() const -> Texture* { + if (input_textures_.empty()) { + return nullptr; + } + assert(index_ < static_cast(input_textures_.size())); + return input_textures_[index_].get(); +} + +void TextureSequenceNode::Step() { + if (sleep_count_ <= 0) { + if (!input_textures_.empty()) { + index_ = (index_ + 1) % static_cast(input_textures_.size()); + } + sleep_count_ = rate_; + } + sleep_count_ -= kGameStepMilliseconds; +} + +void TextureSequenceNode::set_rate(int val) { + if (val != rate_) { + rate_ = val; + sleep_count_ = val; + } +} + +} // namespace ballistica diff --git a/src/ballistica/scene/node/texture_sequence_node.h b/src/ballistica/scene/node/texture_sequence_node.h new file mode 100644 index 00000000..72cf0ccd --- /dev/null +++ b/src/ballistica/scene/node/texture_sequence_node.h @@ -0,0 +1,33 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_TEXTURE_SEQUENCE_NODE_H_ +#define BALLISTICA_SCENE_NODE_TEXTURE_SEQUENCE_NODE_H_ + +#include + +#include "ballistica/ballistica.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class TextureSequenceNode : public Node { + public: + static auto InitType() -> NodeType*; + explicit TextureSequenceNode(Scene* scene); + void Step() override; + auto rate() const -> int { return rate_; } + void set_rate(int val); + auto input_textures() const -> std::vector; + void set_input_textures(const std::vector& vals); + auto output_texture() const -> Texture*; + + private: + int sleep_count_{}; + int index_{}; + int rate_{}; + std::vector > input_textures_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_TEXTURE_SEQUENCE_NODE_H_ diff --git a/src/ballistica/scene/node/time_display_node.cc b/src/ballistica/scene/node/time_display_node.cc new file mode 100644 index 00000000..0c8d768f --- /dev/null +++ b/src/ballistica/scene/node/time_display_node.cc @@ -0,0 +1,137 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/node/time_display_node.h" + +#include +#include + +#include "ballistica/game/game.h" +#include "ballistica/generic/utils.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_type.h" + +namespace ballistica { + +class TimeDisplayNodeType : public NodeType { + public: +#define BA_NODE_TYPE_CLASS TimeDisplayNode + BA_NODE_CREATE_CALL(CreateTimeDisplayNode); + BA_STRING_ATTR_READONLY(output, GetOutput); + BA_INT64_ATTR(time2, time2, set_time2); + BA_INT64_ATTR(time1, time1, set_time1); + BA_INT64_ATTR(timemin, time_min, set_time_min); + BA_INT64_ATTR(timemax, time_max, set_time_max); + BA_BOOL_ATTR(showsubseconds, show_sub_seconds, set_show_sub_seconds); +#undef BA_NODE_TYPE_CLASS + + TimeDisplayNodeType() + : NodeType("timedisplay", CreateTimeDisplayNode), + output(this), + time2(this), + time1(this), + timemin(this), + timemax(this), + showsubseconds(this) {} +}; + +static NodeType* node_type{}; + +auto TimeDisplayNode::InitType() -> NodeType* { + node_type = new TimeDisplayNodeType(); + return node_type; +} + +TimeDisplayNode::TimeDisplayNode(Scene* scene) : Node(scene, node_type) {} + +TimeDisplayNode::~TimeDisplayNode() = default; + +auto TimeDisplayNode::GetOutput() -> std::string { + assert(InGameThread()); + if (translations_dirty_) { + time_suffix_hours_ = + g_game->CompileResourceString(R"({"r":"timeSuffixHoursText"})", "tda"); + time_suffix_minutes_ = g_game->CompileResourceString( + R"({"r":"timeSuffixMinutesText"})", "tdb"); + time_suffix_seconds_ = g_game->CompileResourceString( + R"({"r":"timeSuffixSecondsText"})", "tdc"); + translations_dirty_ = false; + output_dirty_ = true; + } + if (output_dirty_) { + millisecs_t t = time2_ - time1_; + t = std::min(t, time_max_); + t = std::max(t, time_min_); + output_ = ""; + bool is_negative = false; + if (t < 0) { + t = -t; + is_negative = true; + } + + // Drop the last digit to better line up with in-game math. + t = (t / 10) * 10; + + // Hours. + int h = static_cast_check_fit((t / 1000) / (60 * 60)); + if (h != 0) { + std::string s = time_suffix_hours_; + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%d", h); + Utils::StringReplaceOne(&s, "${COUNT}", buffer); + if (!output_.empty()) { + output_ += " "; + } + output_ += s; + } + + // Minutes. + int m = static_cast_check_fit(((t / 1000) / 60) % 60); + if (m != 0) { + std::string s = time_suffix_minutes_; + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%d", m); + Utils::StringReplaceOne(&s, "${COUNT}", buffer); + if (!output_.empty()) { + output_ += " "; + } + output_ += s; + } + + // Seconds (with hundredths). + if (show_sub_seconds_) { + float sec = fmod(static_cast(t) / 1000.0f, 60.0f); + if (sec >= 0.005f || output_.empty()) { + std::string s = time_suffix_seconds_; + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%.2f", sec); + Utils::StringReplaceOne(&s, "${COUNT}", buffer); + if (!output_.empty()) { + output_ += " "; + } + output_ += s; + } + } else { + // Seconds (integer). + int sec = static_cast_check_fit(t / 1000 % 60); + if (sec != 0 || output_.empty()) { + std::string s = time_suffix_seconds_; + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%d", sec); + Utils::StringReplaceOne(&s, "${COUNT}", buffer); + if (!output_.empty()) { + output_ += " "; + } + output_ += s; + } + } + if (is_negative) { + output_ = "-" + output_; + } + output_dirty_ = false; + } + return output_; +} + +void TimeDisplayNode::OnLanguageChange() { translations_dirty_ = true; } + +} // namespace ballistica diff --git a/src/ballistica/scene/node/time_display_node.h b/src/ballistica/scene/node/time_display_node.h new file mode 100644 index 00000000..78cea7c9 --- /dev/null +++ b/src/ballistica/scene/node/time_display_node.h @@ -0,0 +1,71 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_NODE_TIME_DISPLAY_NODE_H_ +#define BALLISTICA_SCENE_NODE_TIME_DISPLAY_NODE_H_ + +#include + +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class TimeDisplayNode : public Node { + public: + static auto InitType() -> NodeType*; + auto GetOutput() -> std::string; + auto time2() const -> millisecs_t { return time2_; } + void set_time2(millisecs_t value) { + if (time2_ != value) { + time2_ = value; + output_dirty_ = true; + } + } + auto time1() const -> millisecs_t { return time1_; } + void set_time1(millisecs_t value) { + if (time1_ != value) { + time1_ = value; + output_dirty_ = true; + } + } + auto time_min() const -> millisecs_t { return time_min_; } + void set_time_min(millisecs_t val) { + if (time_min_ != val) { + time_min_ = val; + output_dirty_ = true; + } + } + auto time_max() const -> millisecs_t { return time_max_; } + void set_time_max(millisecs_t val) { + if (time_max_ != val) { + time_max_ = val; + output_dirty_ = true; + } + } + auto show_sub_seconds() const -> bool { return show_sub_seconds_; } + void set_show_sub_seconds(bool val) { + if (show_sub_seconds_ != val) { + show_sub_seconds_ = val; + output_dirty_ = true; + } + } + explicit TimeDisplayNode(Scene* scene); + ~TimeDisplayNode() override; + void OnLanguageChange() override; + + private: + bool output_dirty_ = true; + std::string output_; + millisecs_t time_min_ = -999999999; + millisecs_t time_max_ = 999999999; + millisecs_t time2_ = 0; + millisecs_t time1_ = 0; + bool show_sub_seconds_ = false; + std::string time_suffix_hours_; + std::string time_suffix_minutes_; + std::string time_suffix_seconds_; + bool translations_dirty_ = true; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_NODE_TIME_DISPLAY_NODE_H_ diff --git a/src/ballistica/scene/scene.cc b/src/ballistica/scene/scene.cc new file mode 100644 index 00000000..3d0038df --- /dev/null +++ b/src/ballistica/scene/scene.cc @@ -0,0 +1,624 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/scene/scene.h" + +#include +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/dynamics/bg/bg_dynamics.h" +#include "ballistica/dynamics/dynamics.h" +#include "ballistica/dynamics/part.h" +#include "ballistica/game/game_stream.h" +#include "ballistica/game/player.h" +#include "ballistica/graphics/camera.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/networking/networking.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/scene/node/anim_curve_node.h" +#include "ballistica/scene/node/bomb_node.h" +#include "ballistica/scene/node/combine_node.h" +#include "ballistica/scene/node/explosion_node.h" +#include "ballistica/scene/node/flag_node.h" +#include "ballistica/scene/node/flash_node.h" +#include "ballistica/scene/node/globals_node.h" +#include "ballistica/scene/node/image_node.h" +#include "ballistica/scene/node/light_node.h" +#include "ballistica/scene/node/locator_node.h" +#include "ballistica/scene/node/math_node.h" +#include "ballistica/scene/node/node_attribute.h" +#include "ballistica/scene/node/node_attribute_connection.h" +#include "ballistica/scene/node/node_type.h" +#include "ballistica/scene/node/null_node.h" +#include "ballistica/scene/node/player_node.h" +#include "ballistica/scene/node/prop_node.h" +#include "ballistica/scene/node/region_node.h" +#include "ballistica/scene/node/scorch_node.h" +#include "ballistica/scene/node/session_globals_node.h" +#include "ballistica/scene/node/shield_node.h" +#include "ballistica/scene/node/sound_node.h" +#include "ballistica/scene/node/spaz_node.h" +#include "ballistica/scene/node/terrain_node.h" +#include "ballistica/scene/node/text_node.h" +#include "ballistica/scene/node/texture_sequence_node.h" +#include "ballistica/scene/node/time_display_node.h" + +namespace ballistica { + +void Scene::Init() { + NodeType* node_types[] = {NullNode::InitType(), + GlobalsNode::InitType(), + SessionGlobalsNode::InitType(), + PropNode::InitType(), + FlagNode::InitType(), + BombNode::InitType(), + ExplosionNode::InitType(), + ShieldNode::InitType(), + LightNode::InitType(), + TextNode::InitType(), + AnimCurveNode::InitType(), + ImageNode::InitType(), + TerrainNode::InitType(), + MathNode::InitType(), + LocatorNode::InitType(), + PlayerNode::InitType(), + CombineNode::InitType(), + SoundNode::InitType(), + SpazNode::InitType(), + RegionNode::InitType(), + ScorchNode::InitType(), + FlashNode::InitType(), + TextureSequenceNode::InitType(), + TimeDisplayNode::InitType()}; + + int next_type_id = 0; + assert(g_app_globals != nullptr); + for (auto* t : node_types) { + g_app_globals->node_types[t->name()] = t; + g_app_globals->node_types_by_id[next_type_id] = t; + t->set_id(next_type_id++); + } + + // Types: I is 32 bit int, i is 16 bit int, c is 8 bit int, + // F is 32 bit float, f is 16 bit float, + // s is string, b is bool. + SetupNodeMessageType("flash", NodeMessageType::kFlash, ""); + SetupNodeMessageType("footing", NodeMessageType::kFooting, "c"); + SetupNodeMessageType("impulse", NodeMessageType::kImpulse, "fffffffffifff"); + SetupNodeMessageType("kick_back", NodeMessageType::kKickback, "fffffff"); + SetupNodeMessageType("celebrate", NodeMessageType::kCelebrate, "i"); + SetupNodeMessageType("celebrate_l", NodeMessageType::kCelebrateL, "i"); + SetupNodeMessageType("celebrate_r", NodeMessageType::kCelebrateR, "i"); + SetupNodeMessageType("knockout", NodeMessageType::kKnockout, "f"); + SetupNodeMessageType("hurt_sound", NodeMessageType::kHurtSound, ""); + SetupNodeMessageType("picked_up", NodeMessageType::kPickedUp, ""); + SetupNodeMessageType("jump_sound", NodeMessageType::kJumpSound, ""); + SetupNodeMessageType("attack_sound", NodeMessageType::kAttackSound, ""); + SetupNodeMessageType("scream_sound", NodeMessageType::kScreamSound, ""); + SetupNodeMessageType("stand", NodeMessageType::kStand, "ffff"); +} + +void Scene::SetupNodeMessageType(const std::string& name, NodeMessageType val, + const std::string& format) { + assert(g_app_globals != nullptr); + g_app_globals->node_message_types[name] = val; + assert(static_cast(val) >= 0); + if (g_app_globals->node_message_formats.size() <= static_cast(val)) { + g_app_globals->node_message_formats.resize(static_cast(val) + 1); + } + g_app_globals->node_message_formats[static_cast(val)] = format; +} + +auto Scene::GetGameStream() const -> GameStream* { + return output_stream_.get(); +} + +void Scene::SetMapBounds(float xmin, float ymin, float zmin, float xmax, + float ymax, float zmax) { + bounds_min_[0] = xmin; + bounds_min_[1] = ymin; + bounds_min_[2] = zmin; + bounds_max_[0] = xmax; + bounds_max_[1] = ymax; + bounds_max_[2] = zmax; +} + +Scene::Scene(millisecs_t start_time) + : time_(start_time), + stepnum_(start_time / kGameStepMilliseconds), + last_step_real_time_(GetRealTime()) { + dynamics_ = Object::New(this); + + // Reset world bounds to default. + bounds_min_[0] = -30; + bounds_max_[0] = 30; + bounds_min_[1] = -10; + bounds_max_[1] = 100; + bounds_min_[2] = -30; + bounds_max_[2] = 30; +} + +Scene::~Scene() { + // This may already be set to true by a host_activity/etc, but + // make sure it is at this point. + shutting_down_ = true; + + // Manually kill our nodes so they can remove all their own dynamics stuff + // before dynamics goes down. + nodes_.clear(); + + dynamics_.Clear(); + + // If we were associated with an output-stream, inform it of our demise. + if (output_stream_.exists()) { + output_stream_->RemoveScene(this); + } +} + +void Scene::PlaySoundAtPosition(Sound* sound, float volume, float x, float y, + float z, bool host_only) { + if (output_stream_.exists() && !host_only) { + output_stream_->PlaySoundAtPosition(sound, volume, x, y, z); + } + g_audio->PlaySoundAtPosition(sound->GetSoundData(), volume, x, y, z); +} + +void Scene::PlaySound(Sound* sound, float volume, bool host_only) { + if (output_stream_.exists() && !host_only) { + output_stream_->PlaySound(sound, volume); + } + g_audio->PlaySound(sound->GetSoundData(), volume); +} + +auto Scene::IsOutOfBounds(float x, float y, float z) -> bool { + if (std::isnan(x) || std::isnan(y) || std::isnan(z) || std::isinf(x) + || std::isinf(y) || std::isinf(z)) + BA_LOG_ONCE("ERROR: got INF/NAN value on IsOutOfBounds() check"); + + return ((x < bounds_min_[0]) || (x > bounds_max_[0]) || (y < bounds_min_[1]) + || (y > bounds_max_[1]) || (z < bounds_min_[2]) + || (z > bounds_max_[2]) || std::isnan(x) || std::isnan(y) + || std::isnan(z) || std::isinf(x) || std::isinf(y) || std::isinf(z)); +} + +void Scene::Draw(FrameDef* frame_def) { + // Draw our nodes. + for (auto&& i : nodes_) { + g_graphics->PreNodeDraw(); + i->Draw(frame_def); + g_graphics->PostNodeDraw(); + } + + // Draw any dynamics debugging extras. + dynamics_->Draw(frame_def); +} + +auto Scene::GetNodeMessageType(const std::string& type) -> NodeMessageType { + assert(g_app_globals != nullptr); + auto i = g_app_globals->node_message_types.find(type); + if (i == g_app_globals->node_message_types.end()) { + throw Exception("Invalid node-message type: '" + type + "'"); + } + return i->second; +} + +auto Scene::GetNodeMessageTypeName(NodeMessageType t) -> std::string { + assert(g_app_globals != nullptr); + for (auto&& i : g_app_globals->node_message_types) { + if (i.second == t) { + return i.first; + } + } + return ""; +} + +void Scene::SetPlayerNode(int id, PlayerNode* n) { player_nodes_[id] = n; } + +auto Scene::GetPlayerNode(int id) -> PlayerNode* { + auto i = player_nodes_.find(id); + if (i != player_nodes_.end()) { + return i->second.get(); + } + return nullptr; +} + +void Scene::Step() { + out_of_bounds_nodes_.clear(); + + // Step all our nodes. + { + in_step_ = true; + last_step_real_time_ = GetRealTime(); + for (auto&& i : nodes_) { + Node* node = i.get(); + node->Step(); + + // Now that it's stepped, pump new values to any nodes it's connected to. + node->UpdateConnections(); + } + in_step_ = false; + } + bool is_foreground = (g_game->GetForegroundScene() == this); + + // Add a step command to the output stream. + if (output_stream_.exists()) { + output_stream_->StepScene(this); + } + + // And step things locally. + if (is_foreground) { + Vector3f cam_pos = {0.0f, 0.0f, 0.0f}; + g_graphics->camera()->get_position(&cam_pos.x, &cam_pos.y, &cam_pos.z); +#if !BA_HEADLESS_BUILD + g_bg_dynamics->Step(cam_pos); +#endif // !BA_HEADLESS_BUILD + } + + // Lastly step our sim. + dynamics_->process(); + + time_ += kGameStepMilliseconds; + stepnum_++; +} + +void Scene::DeleteNode(Node* node) { + assert(node); + + if (in_step_) { + throw Exception( + "Cannot delete nodes within a sim step." + " Consider a deferred call or timer. Node=" + + node->GetObjectDescription()); + } + + // Copy refs to its death-actions and dependent-nodes; we'll deal with these + // after the node is dead so we're sure they don't muck with the node. + std::vector > death_actions = + node->death_actions(); + std::vector > dependent_nodes = node->dependent_nodes(); + + // Sanity test to make sure it dies when we ask. +#if BA_DEBUG_BUILD + Object::WeakRef temp_weak_ref(node); + BA_PRECONDITION(temp_weak_ref.exists()); +#endif + + // Copy a strong ref to this node to keep it alive until we've wiped it from + // the list. (so in its destructor it won't see itself on the list). + Object::Ref temp_ref(node); + nodes_.erase(node->iterator()); + + temp_ref.Clear(); + + // Sanity test: at this point the node should be dead. +#if BA_DEBUG_BUILD + if (temp_weak_ref.exists()) { + Log("Error: node still exists after ref release!!"); + } +#endif // BA_DEBUG_BUILD + + // Lastly run any death actions the node had and kill dependent nodes. + if (!shutting_down()) { + for (auto&& i : death_actions) { + i->Run(); + } + for (auto&& i : dependent_nodes) { + Node* node2 = i.get(); + if (node2) { + node2->scene()->DeleteNode(node2); + } + } + } +} + +void Scene::GraphicsQualityChanged(GraphicsQuality q) { + assert(InGameThread()); + for (auto&& i : nodes_) { + i->OnGraphicsQualityChanged(q); + } +} + +void Scene::ScreenSizeChanged() { + assert(InGameThread()); + for (auto&& i : nodes_) { + i->OnScreenSizeChange(); // New. + } +} + +void Scene::LanguageChanged() { + assert(InGameThread()); + for (auto&& i : nodes_) { + i->OnLanguageChange(); // New. + } +} + +auto Scene::GetNodeMessageFormat(NodeMessageType type) -> const char* { + assert(g_app_globals != nullptr); + if ((unsigned int)type >= g_app_globals->node_message_formats.size()) { + return nullptr; + } + return g_app_globals->node_message_formats[static_cast(type)].c_str(); +} + +auto Scene::NewNode(const std::string& type_string, const std::string& name, + PyObject* delegate) -> Node* { + assert(InGameThread()); + + if (in_step_) { + throw Exception( + "Cannot create nodes within a sim step." + " Consider a deferred call or timer."); + } + + // Should never change the scene while we're stepping it. + assert(!in_step_); + assert(g_app_globals != nullptr); + auto i = g_app_globals->node_types.find(type_string); + if (i == g_app_globals->node_types.end()) { + throw Exception("Invalid node type: '" + type_string + "'"); + } + auto node = Object::MakeRefCounted(i->second->Create(this)); + assert(node.exists()); + node->AddToScene(this); + node->set_label(name); + node->SetDelegate(delegate); + return node.get(); // NOLINT +} + +void Scene::Dump(GameStream* stream) { + assert(InGameThread()); + stream->AddScene(this); + + // If we're the foreground one, communicate that fact as well. + if (g_game->GetForegroundScene() == this) { + stream->SetForegroundScene(this); + } +} + +void Scene::DumpNodes(GameStream* out) { + // Dumps commands to the output stream to recreate scene's nodes + // in their current state. + + // First we go through and create all nodes. + // We have to do this all at once before setting attrs since any node + // can refer to any other in an attr set. + for (auto&& i : nodes_) { + Node* node = i.get(); + assert(node); + + // add the node + out->AddNode(node); + } + + std::vector > node_attr_sets; + + // Now go through and set *most* node attr values. + for (auto&& i1 : nodes_) { + Node* node = i1.get(); + assert(node); + + // Now we need to set *all* of its attrs in order. + // FIXME: Could be nice to send only ones that have changed from + // defaults; would need to add that functionality to NodeType. + NodeType* node_type = node->type(); + for (auto&& i2 : node_type->attributes_by_index()) { + NodeAttribute attr; + attr.assign(node, i2); + if (!attr.is_read_only()) { + switch (attr.type()) { + case NodeAttributeType::kFloat: { + out->SetNodeAttr(attr, attr.GetAsFloat()); + break; + } + case NodeAttributeType::kInt: { + out->SetNodeAttr(attr, attr.GetAsInt()); + break; + } + case NodeAttributeType::kBool: { + out->SetNodeAttr(attr, attr.GetAsBool()); + break; + } + case NodeAttributeType::kFloatArray: { + out->SetNodeAttr(attr, attr.GetAsFloats()); + break; + } + case NodeAttributeType::kIntArray: { + out->SetNodeAttr(attr, attr.GetAsInts()); + break; + } + case NodeAttributeType::kString: { + out->SetNodeAttr(attr, attr.GetAsString()); + break; + } + case NodeAttributeType::kNode: { + // Node-attrs are a special case - we can't set them until after + // nodes are fully constructed. so lets just make a list of them + // and do it at the end. + node_attr_sets.emplace_back(attr, attr.GetAsNode()); + break; + } + case NodeAttributeType::kPlayer: { + out->SetNodeAttr(attr, attr.GetAsPlayer()); + break; + } + case NodeAttributeType::kMaterialArray: { + out->SetNodeAttr(attr, attr.GetAsMaterials()); + break; + } + case NodeAttributeType::kTexture: { + out->SetNodeAttr(attr, attr.GetAsTexture()); + break; + } + case NodeAttributeType::kTextureArray: { + out->SetNodeAttr(attr, attr.GetAsTextures()); + break; + } + case NodeAttributeType::kSound: { + out->SetNodeAttr(attr, attr.GetAsSound()); + break; + } + case NodeAttributeType::kSoundArray: { + out->SetNodeAttr(attr, attr.GetAsSounds()); + break; + } + case NodeAttributeType::kModel: { + out->SetNodeAttr(attr, attr.GetAsModel()); + break; + } + case NodeAttributeType::kModelArray: { + out->SetNodeAttr(attr, attr.GetAsModels()); + break; + } + case NodeAttributeType::kCollideModel: { + out->SetNodeAttr(attr, attr.GetAsCollideModel()); + break; + } + case NodeAttributeType::kCollideModelArray: { + out->SetNodeAttr(attr, attr.GetAsCollideModels()); + break; + } + default: + Log("Invalid attr type for Scene::DumpNodes() attr set: " + + std::to_string(static_cast(attr.type()))); + break; + } + } + } + } + + // Now run through all nodes once more and add an OnCreate() call + // so they can do any post-create setup they need to. + for (auto&& i : nodes_) { + Node* node = i.get(); + assert(node); + out->NodeOnCreate(node); + } + + // Set any node-attribute values now that all nodes are fully constructed. + for (auto&& i : node_attr_sets) { + out->SetNodeAttr(i.first, i.second); + } + + // And lastly re-establish node attribute-connections. + for (auto&& i : nodes_) { + Node* node = i.get(); + assert(node); + for (auto&& j : node->attribute_connections()) { + assert(j.exists()); + Node* src_node = j->src_node.get(); + assert(src_node); + Node* dst_node = j->dst_node.get(); + assert(dst_node); + NodeAttributeUnbound* src_attr = + src_node->type()->GetAttribute(j->src_attr_index); + NodeAttributeUnbound* dst_attr = + dst_node->type()->GetAttribute(j->dst_attr_index); + out->ConnectNodeAttribute(src_node, src_attr, dst_node, dst_attr); + } + } +} + +auto Scene::GetCorrectionMessage(bool blended) -> std::vector { + // Let's loop over our nodes sending a bit of correction data. + + // Go through until we find at least 1 node to send corrections for, + // or until we loop all the way through. + + // 1 byte type, 1 byte blending, 2 byte node count + std::vector message(4); + message[0] = BA_MESSAGE_SESSION_DYNAMICS_CORRECTION; + message[1] = static_cast(blended); + int node_count = 0; + + std::vector dynamic_bodies; + + for (auto&& i : nodes_) { + Node* n = i.get(); + assert(n); + if (n && !n->parts().empty()) { + dynamic_bodies.clear(); + for (auto&& j : n->parts()) { + if (!j->rigid_bodies().empty()) { + for (auto&& k : j->rigid_bodies()) { + if (k->type() == RigidBody::Type::kBody) { + dynamic_bodies.push_back(k); + } + } + } + } + if (!dynamic_bodies.empty()) { + int node_embed_size = 5; // 4 byte node-ID and 1 byte body-count + int body_count = 0; + for (auto&& i2 : dynamic_bodies) { + node_embed_size += 3 + i2->GetEmbeddedSizeFull(); + body_count++; + } + + // Lastly add custom data. + node_embed_size += 2; // size + int resync_data_size = n->GetResyncDataSize(); + node_embed_size += resync_data_size; + + // If this size puts us over our max packet size (and we've got + // something in the packet already) just ship what we've got. + // We'll come back to this one next time. + { + node_count++; + size_t old_size = message.size(); + message.resize(old_size + node_embed_size); + + // Embed node id. + auto stream_id_val = static_cast_check_fit(n->stream_id()); + memcpy(message.data() + old_size, &stream_id_val, + sizeof(stream_id_val)); + + // Embed body count. + message[old_size + 4] = static_cast_check_fit(body_count); + size_t offset = old_size + 5; + for (auto&& i2 : dynamic_bodies) { + // Embed body id. + message[offset++] = static_cast_check_fit(i2->id()); + int body_embed_size = i2->GetEmbeddedSizeFull(); + + // Embed body size. + auto val = static_cast_check_fit(body_embed_size); + memcpy(message.data() + offset, &val, sizeof(val)); + offset += 2; + char* p1 = reinterpret_cast(&(message[offset])); + char* p2 = p1; + i2->EmbedFull(&p2); + assert(p2 - p1 == body_embed_size); + offset += body_embed_size; + } + + // Lastly embed custom data size and custom data. + auto val = static_cast_check_fit(resync_data_size); + memcpy(message.data() + offset, &val, sizeof(val)); + offset += 2; + if (resync_data_size > 0) { + std::vector resync_data = n->GetResyncData(); + assert(resync_data.size() == resync_data_size); + memcpy(message.data() + offset, &(resync_data[0]), + resync_data.size()); + offset += resync_data_size; + } + assert(offset == message.size()); + } + } + } + } + + // If we embedded any nodes, send. + // Store node count in packet. + auto val = static_cast_check_fit(node_count); + memcpy(message.data() + 2, &val, sizeof(val)); + + return message; +} + +void Scene::SetOutputStream(GameStream* val) { output_stream_ = val; } + +} // namespace ballistica diff --git a/src/ballistica/scene/scene.h b/src/ballistica/scene/scene.h new file mode 100644 index 00000000..1fd71c12 --- /dev/null +++ b/src/ballistica/scene/scene.h @@ -0,0 +1,111 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_SCENE_SCENE_H_ +#define BALLISTICA_SCENE_SCENE_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/game/game.h" +#include "ballistica/scene/node/node.h" + +namespace ballistica { + +class Scene : public Object { + public: + static void Init(); + explicit Scene(millisecs_t starttime); + ~Scene() override; + void Step(); + void Draw(FrameDef* frame_def); + auto NewNode(const std::string& type, const std::string& name, + PyObject* delegate) -> Node*; + void PlaySoundAtPosition(Sound* sound, float volume, float x, float y, + float z, bool host_only = false); + void PlaySound(Sound* sound, float volume, bool host_only = false); + static auto GetNodeMessageType(const std::string& type_name) + -> NodeMessageType; + static auto GetNodeMessageTypeName(NodeMessageType t) -> std::string; + static auto GetNodeMessageFormat(NodeMessageType type) -> const char*; + auto time() const -> millisecs_t { return time_; } + auto stepnum() const -> int64_t { return stepnum_; } + auto nodes() const -> const NodeList& { return nodes_; } + void AddOutOfBoundsNode(Node* n) { out_of_bounds_nodes_.emplace_back(n); } + auto IsOutOfBounds(float x, float y, float z) -> bool; + auto dynamics() const -> Dynamics* { + assert(dynamics_.exists()); + return dynamics_.get(); + } + auto in_step() const -> bool { return in_step_; } + void SetMapBounds(float x, float y, float z, float X, float Y, float Z); + void ScreenSizeChanged(); + void LanguageChanged(); + void GraphicsQualityChanged(GraphicsQuality q); + auto out_of_bounds_nodes() -> const std::vector >& { + return out_of_bounds_nodes_; + } + void DeleteNode(Node* node); + auto shutting_down() const -> bool { return shutting_down_; } + void set_shutting_down(bool val) { shutting_down_ = val; } + auto GetGameStream() const -> GameStream*; + void SetPlayerNode(int id, PlayerNode* n); + auto GetPlayerNode(int id) -> PlayerNode*; + auto use_fixed_vr_overlay() const -> bool { return use_fixed_vr_overlay_; } + void set_use_fixed_vr_overlay(bool val) { use_fixed_vr_overlay_ = val; } + void increment_bg_cover_count() { bg_cover_count_++; } + void decrement_bg_cover_count() { bg_cover_count_--; } + auto has_bg_cover() const -> bool { return (bg_cover_count_ > 0); } + void Dump(GameStream* out); + void DumpNodes(GameStream* out); + auto GetCorrectionMessage(bool blended) -> std::vector; + + void SetOutputStream(GameStream* val); + auto stream_id() const -> int64_t { return stream_id_; } + void set_stream_id(int64_t val) { + assert(stream_id_ == -1); + stream_id_ = val; + } + void clear_stream_id() { + assert(stream_id_ != -1); + stream_id_ = -1; + } + + auto last_step_real_time() const -> millisecs_t { + return last_step_real_time_; + } + auto globals_node() const -> GlobalsNode* { return globals_node_; } + void set_globals_node(GlobalsNode* node) { globals_node_ = node; } + + private: + static void SetupNodeMessageType(const std::string& name, NodeMessageType val, + const std::string& format); + + GlobalsNode* globals_node_{}; // Current globals node (if any). + std::map > player_nodes_; + int64_t stream_id_{-1}; + Object::WeakRef output_stream_; + bool use_fixed_vr_overlay_{}; + Context context_; // Context we were made in. + millisecs_t time_{}; + int64_t stepnum_{}; + bool in_step_{}; + int64_t next_node_id_{}; + + // For globals real_time attr (so is consistent through the step.) + millisecs_t last_step_real_time_{}; + int bg_cover_count_{}; + bool shutting_down_{}; + float bounds_min_[3]{}; + float bounds_max_[3]{}; + std::vector > out_of_bounds_nodes_; + NodeList nodes_; + Object::Ref dynamics_; + friend void Node::AddToScene(Scene*); + friend class ClientSession; +}; + +} // namespace ballistica + +#endif // BALLISTICA_SCENE_SCENE_H_ diff --git a/src/ballistica/ui/console.cc b/src/ballistica/ui/console.cc new file mode 100644 index 00000000..15422ac4 --- /dev/null +++ b/src/ballistica/ui/console.cc @@ -0,0 +1,364 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/console.h" + +#include + +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/game/game.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/text/text_graphics.h" +#include "ballistica/platform/min_sdl.h" + +namespace ballistica { + +// How much of the screen the console covers when it is at full size. +const float kConsoleSize = 0.9f; +const float kConsoleZDepth = 0.0f; +const int kConsoleLineLimit = 80; +const int kStringBreakUpSize = 1950; +const int kActivateKey1 = SDLK_BACKQUOTE; +const int kActivateKey2 = SDLK_F2; + +Console::Console() { + assert(InGameThread()); + std::string title = std::string("BallisticaCore ") + kAppVersion + " (" + + std::to_string(kAppBuildNumber) + ")"; + if (g_buildconfig.debug_build()) { + title += " (debug)"; + } + if (g_buildconfig.test_build()) { + title += " (test)"; + } + + title_text_group_.SetText(title); + built_text_group_.SetText("Built: " __DATE__ " " __TIME__); + prompt_text_group_.SetText(">"); + + // Print whatever is already in the log. + if (!g_app_globals->console_startup_messages.empty()) { + Print(g_app_globals->console_startup_messages); + g_app_globals->console_startup_messages = ""; + } +} + +Console::~Console() = default; + +auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool { + assert(InGameThread()); + + // Handle our toggle buttons no matter whether we're active. + switch (keysym->sym) { + case kActivateKey1: + case kActivateKey2: { + if (!g_buildconfig.demo_build() && !g_buildconfig.arcade_build()) { + // (reset input so characters don't continue walking and stuff) + g_game->ResetInput(); + g_game->ToggleConsole(); + } + return true; + } + default: + break; + } + + if (state_ == State::kInactive) { + return false; + } + + // The rest of these presses we only handle while active. + switch (keysym->sym) { + case SDLK_ESCAPE: + ToggleState(); + break; + case SDLK_BACKSPACE: + case SDLK_DELETE: { + std::vector unichars = + Utils::UnicodeFromUTF8(input_string_, "fjco38"); + if (!unichars.empty()) { + unichars.resize(unichars.size() - 1); + input_string_ = Utils::UTF8FromUnicode(unichars); + input_text_dirty_ = true; + } + break; + } + case SDLK_UP: + case SDLK_DOWN: { + if (input_history_.empty()) { + break; + } + if (keysym->sym == SDLK_UP) { + input_history_position_++; + } else { + input_history_position_--; + } + int input_history_position_used = + (input_history_position_ - 1) + % static_cast(input_history_.size()); + int j = 0; + for (auto& i : input_history_) { + if (j == input_history_position_used) { + input_string_ = i; + input_text_dirty_ = true; + break; + } + j++; + } + break; + } + case SDLK_KP_ENTER: + case SDLK_RETURN: { + input_history_position_ = 0; + if (input_string_ == "clear") { + last_line_.clear(); + lines_.clear(); + } else { + g_game->PushInGameConsoleScriptCommand(input_string_); + } + input_history_.push_front(input_string_); + if (input_history_.size() > 100) input_history_.pop_back(); + input_string_.resize(0); + input_text_dirty_ = true; + break; + } + default: { +#if BA_SDL2_BUILD || BA_MINSDL_BUILD + // (in SDL2/Non-SDL we dont' get chars from keypress events; + // they come through as text edit events) +#else // BA_SDL2_BUILD + if (keysym->unicode < 0x80 && keysym->unicode > 0) { + std::vector unichars = + Utils::UnicodeFromUTF8(input_string_, "cjofrh0"); + unichars.push_back(keysym->unicode); + input_string_ = Utils::GetValidUTF8( + Utils::UTF8FromUnicode(unichars).c_str(), "sdkr"); + input_text_dirty_ = true; + } +#endif // BA_SDL2_BUILD + break; + } + } + return true; +} + +void Console::ToggleState() { + switch (state_) { + case State::kInactive: + state_ = State::kMini; + break; + case State::kMini: + state_ = State::kFull; + break; + case State::kFull: + state_ = State::kInactive; + break; + } + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kBlip)); + transition_start_ = GetRealTime(); +} + +auto Console::HandleTextEditing(const std::string& text) -> bool { + assert(InGameThread()); + if (state_ == State::kInactive) { + return false; + } + + // Ignore back-tick because we use that key to toggle the console. + if (text == "`") { + return false; + } + input_string_ += text; + input_text_dirty_ = true; + return true; +} + +auto Console::HandleKeyRelease(const SDL_Keysym* keysym) -> bool { + // Always absorb our activate keys. + if (keysym->sym == kActivateKey1 || keysym->sym == kActivateKey2) { + return true; + } + + // Otherwise simply absorb all key-ups if we're active. + return state_ != State::kInactive; +} + +void Console::Print(const std::string& sIn) { + assert(InGameThread()); + std::string s = Utils::GetValidUTF8(sIn.c_str(), "cspr"); + last_line_ += s; + std::vector broken_up; + g_text_graphics->BreakUpString(last_line_.c_str(), kStringBreakUpSize, + &broken_up); + + // Spit out all completed lines and keep the last one as lastline. + for (size_t i = 0; i < broken_up.size() - 1; i++) { + lines_.emplace_back(broken_up[i], GetRealTime()); + if (lines_.size() > kConsoleLineLimit) lines_.pop_front(); + } + last_line_ = broken_up[broken_up.size() - 1]; + last_line_mesh_dirty_ = true; +} + +void Console::Draw(RenderPass* pass) { + millisecs_t transition_ticks = 100; + if ((transition_start_ != 0) + && (state_ != State::kInactive + || ((GetRealTime() - transition_start_) < transition_ticks))) { + float ratio = (static_cast(GetRealTime() - transition_start_) + / transition_ticks); + float bottom; + float mini_size = 90; + if (state_ == State::kMini) { + bottom = pass->virtual_height() - mini_size; + } else { + bottom = pass->virtual_height() - pass->virtual_height() * kConsoleSize; + } + if (GetRealTime() - transition_start_ < transition_ticks) { + if (state_ == State::kMini) { + bottom = pass->virtual_height() * (1.0f - ratio) + bottom * (ratio); + } else if (state_ == State::kFull) { + bottom = + (pass->virtual_height() - pass->virtual_height() * kConsoleSize) + * (ratio) + + (pass->virtual_height() - mini_size) * (1.0f - ratio); + } else { + bottom = pass->virtual_height() * ratio + bottom * (1.0f - ratio); + } + } + { + bg_mesh_.SetPositionAndSize(0, bottom, kConsoleZDepth, + pass->virtual_width(), + (pass->virtual_height() - bottom)); + stripe_mesh_.SetPositionAndSize(0, bottom + 15, kConsoleZDepth, + pass->virtual_width(), 15); + shadow_mesh_.SetPositionAndSize(0, bottom - 7, kConsoleZDepth, + pass->virtual_width(), 7); + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(0, 0, 0.1f, 0.9f); + c.DrawMesh(&bg_mesh_); + c.Submit(); + c.SetColor(1.0f, 1.0f, 1.0f, 0.1f); + c.DrawMesh(&stripe_mesh_); + c.Submit(); + c.SetColor(0, 0, 0, 0.1f); + c.DrawMesh(&shadow_mesh_); + c.Submit(); + } + if (input_text_dirty_) { + input_text_group_.SetText(input_string_); + input_text_dirty_ = false; + last_input_text_change_time_ = pass->frame_def()->real_time(); + } + { + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(0.5f, 0.5f, 0.7f, 1.0f); + int elem_count = built_text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(built_text_group_.GetElementTexture(e)); + c.PushTransform(); + c.Translate(pass->virtual_width() - 175.0f, bottom + 0, kConsoleZDepth); + c.Scale(0.5f, 0.5f, 0.5f); + c.DrawMesh(built_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + elem_count = title_text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(title_text_group_.GetElementTexture(e)); + c.PushTransform(); + c.Translate(20.0f, bottom + 0, kConsoleZDepth); + c.Scale(0.5f, 0.5f, 0.5f); + c.DrawMesh(title_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + elem_count = prompt_text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(prompt_text_group_.GetElementTexture(e)); + c.SetColor(1, 1, 1, 1); + c.PushTransform(); + c.Translate(5.0f, bottom + 15.0f, kConsoleZDepth); + c.Scale(0.5f, 0.5f, 0.5f); + c.DrawMesh(prompt_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + elem_count = input_text_group_.GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(input_text_group_.GetElementTexture(e)); + c.PushTransform(); + c.Translate(15.0f, bottom + 15.0f, kConsoleZDepth); + c.Scale(0.5f, 0.5f, 0.5f); + c.DrawMesh(input_text_group_.GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + + // Carat. + millisecs_t real_time = pass->frame_def()->real_time(); + if (real_time % 200 < 100 + || (real_time - last_input_text_change_time_ < 100)) { + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(1, 1, 1, 0.7f); + c.PushTransform(); + c.Translate(19.0f + g_text_graphics->GetStringWidth(input_string_) * 0.5f, + bottom + 23.0f, kConsoleZDepth); + c.Scale(5, 11, 1.0f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + } + + // Draw console messages. + { + float draw_scale = 0.5f; + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(1, 1, 1, 1); + float h = 0.5f + * (g_graphics->screen_virtual_width() + - (kStringBreakUpSize * draw_scale)); + float v = bottom + 32.0f; + if (!last_line_.empty()) { + if (last_line_mesh_dirty_) { + if (!last_line_mesh_group_.exists()) { + last_line_mesh_group_ = Object::New(); + } + last_line_mesh_group_->SetText(last_line_); + last_line_mesh_dirty_ = false; + } + int elem_count = last_line_mesh_group_->GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(last_line_mesh_group_->GetElementTexture(e)); + c.PushTransform(); + c.Translate(h, v + 2, kConsoleZDepth); + c.Scale(draw_scale, draw_scale); + c.DrawMesh(last_line_mesh_group_->GetElementMesh(e)); + c.PopTransform(); + } + v += 14; + } + for (auto i = lines_.rbegin(); i != lines_.rend(); i++) { + int elem_count = i->getText().GetElementCount(); + for (int e = 0; e < elem_count; e++) { + c.SetTexture(i->getText().GetElementTexture(e)); + c.PushTransform(); + c.Translate(h, v + 2, kConsoleZDepth); + c.Scale(draw_scale, draw_scale); + c.DrawMesh(i->getText().GetElementMesh(e)); + c.PopTransform(); + } + v += 14; + if (v > pass->virtual_height() + 14) { + break; + } + } + c.Submit(); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/ui/console.h b/src/ballistica/ui/console.h new file mode 100644 index 00000000..466eb20f --- /dev/null +++ b/src/ballistica/ui/console.h @@ -0,0 +1,70 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_CONSOLE_H_ +#define BALLISTICA_UI_CONSOLE_H_ + +#include +#include +#include + +#include "ballistica/core/object.h" +#include "ballistica/graphics/renderer.h" + +namespace ballistica { + +class Console { + public: + Console(); + ~Console(); + auto active() const -> bool { return (state_ != State::kInactive); } + enum class State { kInactive, kMini, kFull }; + auto transition_start() const -> millisecs_t { return transition_start_; } + auto HandleTextEditing(const std::string& text) -> bool; + auto HandleKeyPress(const SDL_Keysym* keysym) -> bool; + auto HandleKeyRelease(const SDL_Keysym* keysym) -> bool; + void ToggleState(); + void Print(const std::string& s); + void Draw(RenderPass* pass); + + private: + ImageMesh bg_mesh_; + ImageMesh stripe_mesh_; + ImageMesh shadow_mesh_; + TextGroup built_text_group_; + TextGroup title_text_group_; + TextGroup prompt_text_group_; + TextGroup input_text_group_; + millisecs_t last_input_text_change_time_{}; + bool input_text_dirty_{true}; + millisecs_t transition_start_{}; + State state_{State::kInactive}; + + class Message { + public: + Message(std::string s_in, millisecs_t c) + : creation_time(c), s(std::move(s_in)) {} + millisecs_t creation_time; + std::string s; + auto getText() -> TextGroup& { + if (!s_mesh_.exists()) { + s_mesh_ = Object::New(); + s_mesh_->SetText(s); + } + return *s_mesh_; + } + + private: + Object::Ref s_mesh_; + }; + std::string input_string_; + std::list input_history_; + int input_history_position_{}; + std::list lines_; + std::string last_line_; + Object::Ref last_line_mesh_group_; + bool last_line_mesh_dirty_{true}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_CONSOLE_H_ diff --git a/src/ballistica/ui/root_ui.cc b/src/ballistica/ui/root_ui.cc new file mode 100644 index 00000000..078f78f0 --- /dev/null +++ b/src/ballistica/ui/root_ui.cc @@ -0,0 +1,394 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/root_ui.h" + +#include +#include + +#include "ballistica/game/game.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/input/device/keyboard_input.h" +#include "ballistica/input/device/touch_input.h" +#include "ballistica/input/input.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/container_widget.h" + +namespace ballistica { + +// Phasing these out; replaced by buttons in our rootwidget. +#define DO_OLD_MENU_PARTY_BUTTONS (!BA_TOOLBAR_TEST) + +const float kMenuButtonSize = 40.0f; +const float kMenuButtonDrawDepth = -0.07f; + +RootUI::RootUI() { + float base_scale; + switch (GetInterfaceType()) { + case UIScale::kLarge: + base_scale = 1.0f; + break; + case UIScale::kMedium: + base_scale = 1.5f; + break; + case UIScale::kSmall: + base_scale = 2.0f; + break; + default: + base_scale = 1.0f; + break; + } + menu_button_size_ = kMenuButtonSize * base_scale; +} +RootUI::~RootUI() = default; + +void RootUI::TogglePartyWindowKeyPress() { + assert(InGameThread()); + if (g_game->GetPartySize() > 1 || g_game->connection_to_host() + || always_draw_party_icon()) { + ActivatePartyIcon(); + } +} + +void RootUI::ActivatePartyIcon() const { + assert(InGameThread()); + ScopedSetContext cp(g_game->GetUIContext()); + + // Originate from center of party icon. If menu button is shown, it is to the + // left of that. + float icon_pos_h = + g_graphics->screen_virtual_width() * 0.5f - menu_button_size_ * 0.5f; + float icon_pos_v = + g_graphics->screen_virtual_height() * 0.5f - menu_button_size_ * 0.5f; + bool menu_active = !(g_ui && g_ui->screen_root_widget() + && g_ui->screen_root_widget()->HasChildren()); + if (menu_active) { + icon_pos_h -= menu_button_size_; + } + g_python->obj(Python::ObjID::kPartyIconActivateCall) + .Call(Vector2f(icon_pos_h, icon_pos_v)); +} + +auto RootUI::HandleMouseButtonDown(float x, float y) -> bool { + // Whether the menu button is visible/active. + bool menu_active = !(g_ui && g_ui->screen_root_widget() + && g_ui->screen_root_widget()->HasChildren()); + + // Handle party button presses (need to do this before UI since it + // floats over the top). Party button is to the left of menu button. + if (explicit_bool(DO_OLD_MENU_PARTY_BUTTONS)) { + bool party_button_active = + (!party_window_open_ + && (g_game->GetConnectedClientCount() > 0 + || g_game->connection_to_host() || always_draw_party_icon())); + float party_button_left = + menu_active ? 2 * menu_button_size_ : menu_button_size_; + float party_button_right = menu_active ? menu_button_size_ : 0; + if (party_button_active + && (g_graphics->screen_virtual_width() - x < party_button_left) + && (g_graphics->screen_virtual_width() - x >= party_button_right) + && (g_graphics->screen_virtual_height() - y < menu_button_size_)) { + ActivatePartyIcon(); + return true; + } + } + // Menu button. + if (explicit_bool(DO_OLD_MENU_PARTY_BUTTONS)) { + if (menu_active + && (g_graphics->screen_virtual_width() - x < menu_button_size_) + && (g_graphics->screen_virtual_height() - y < menu_button_size_)) { + menu_button_pressed_ = true; + menu_button_hover_ = true; + return true; + } + } + + return false; +} + +void RootUI::HandleMouseButtonUp(float x, float y) { + if (menu_button_pressed_) { + menu_button_pressed_ = false; + menu_button_hover_ = false; + + // If we've got a touch input, bring the menu up in its name.. + // otherwise go with keyboard input. + InputDevice* input_device = nullptr; + auto* touch_input = g_input->touch_input(); + auto* keyboard_input = g_input->keyboard_input(); + if (touch_input) { + input_device = touch_input; + } else if (keyboard_input) { + input_device = keyboard_input; + } + if ((g_graphics->screen_virtual_width() - x < menu_button_size_) + && (g_graphics->screen_virtual_height() - y < menu_button_size_)) { + g_game->PushMainMenuPressCall(input_device); + last_menu_button_press_time_ = GetRealTime(); + } + } +} + +void RootUI::HandleMouseMotion(float x, float y) { + // Menu button hover. + if (menu_button_pressed_) { + menu_button_hover_ = + ((g_graphics->screen_virtual_width() - x < menu_button_size_) + && (g_graphics->screen_virtual_height() - y < menu_button_size_)); + } +} + +void RootUI::Draw(FrameDef* frame_def) { + if (explicit_bool(DO_OLD_MENU_PARTY_BUTTONS)) { + millisecs_t real_time = frame_def->real_time(); + + // Menu button. + // Update time-dependent stuff to this point. + bool active = !(g_ui && g_ui->screen_root_widget() + && g_ui->screen_root_widget()->HasChildren()); + if (real_time - menu_update_time_ > 500) { + menu_update_time_ = real_time - 500; + } + while (menu_update_time_ < real_time) { + menu_update_time_ += 10; + if (!active && (real_time - last_menu_button_press_time_ > 100)) { + menu_fade_ = std::max(0.0f, menu_fade_ - 0.05f); + } else { + menu_fade_ = std::min(1.0f, menu_fade_ + 0.05f); + } + } + + // Don't draw menu button on certain UIs such as TV or VR. + bool draw_menu_button = true; + + if (g_buildconfig.ostype_android()) { + // Draw if we have a touchscreen or are in desktop mode. + if (g_input->touch_input() == nullptr + && !g_platform->IsRunningOnDesktop()) { + draw_menu_button = false; + } + } else if (g_buildconfig.rift_build()) { + if (IsVRMode()) { + draw_menu_button = false; + } + } + + if (draw_menu_button) { + SimpleComponent c(frame_def->overlay_pass()); + c.SetTransparent(true); + c.SetTexture(g_media->GetTexture(SystemTextureID::kMenuButton)); + + // Draw menu button. + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + if ((menu_button_pressed_ && menu_button_hover_) + || real_time - last_menu_button_press_time_ < 100) { + c.SetColor(1, 2, 0.5f, 1); + } else { + c.SetColor(0.3f, 0.3f + 0.2f * menu_fade_, 0.2f, menu_fade_); + } + c.PushTransform(); + c.Translate(width - menu_button_size_ * 0.5f, + height - menu_button_size_ * 0.38f, kMenuButtonDrawDepth); + c.Scale(menu_button_size_ * 0.8f, menu_button_size_ * 0.8f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + } + + // To the left of the menu button, draw our connected-players indicator + // (this probably shouldn't live here). + bool draw_connected_players_icon = false; + int party_size = g_game->GetPartySize(); + bool is_host = (g_game->connection_to_host() == nullptr); + millisecs_t last_connection_to_client_join_time = + g_game->last_connection_to_client_join_time(); + + bool show_client_joined = + (is_host && last_connection_to_client_join_time != 0 + && real_time - last_connection_to_client_join_time < 5000); + + if (!party_window_open_ + && (party_size != 0 || g_game->connection_to_host() + || always_draw_party_icon_)) { + draw_connected_players_icon = true; + } + + if (draw_connected_players_icon) { + // Flash and show a message if we're in the main menu instructing the + // player to start a game. + bool flash = false; + HostSession* s = g_game->GetForegroundContext().GetHostSession(); + if (s && s->is_main_menu() && party_size > 0 && show_client_joined) + flash = true; + + SimpleComponent c(frame_def->overlay_pass()); + c.SetTransparent(true); + c.SetTexture(g_media->GetTexture(SystemTextureID::kUsersButton)); + + // Draw button. + float width = g_graphics->screen_virtual_width(); + float height = g_graphics->screen_virtual_height(); + c.PushTransform(); + float extra_offset = + (draw_menu_button && menu_fade_ > 0.0f) ? -menu_button_size_ : 0.0f; + { + float smoothing = 0.8f; + connected_client_extra_offset_smoothed_ = + smoothing * connected_client_extra_offset_smoothed_ + + (1.0f - smoothing) * extra_offset; + } + c.Translate(width - menu_button_size_ * 0.4f + + connected_client_extra_offset_smoothed_, + height - menu_button_size_ * 0.35f, kMenuButtonDrawDepth); + c.Scale(menu_button_size_ * 0.8f, menu_button_size_ * 0.8f); + if (flash && frame_def->base_time() % 250 < 125) { + c.SetColor(1.0f, 1.4f, 1.0f); + } + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + c.Submit(); + + // Based on who has menu control, we may show a key/button below the party + // icon. + if (!active) { + if (InputDevice* uiid = g_ui->GetUIInputDevice()) { + std::string party_button_name = uiid->GetPartyButtonName(); + if (!party_button_name.empty()) { + if (!party_button_text_group_.exists()) { + party_button_text_group_ = Object::New(); + } + if (party_button_name != party_button_text_group_->getText()) { + party_button_text_group_->SetText(party_button_name, + TextMesh::HAlign::kCenter, + TextMesh::VAlign::kTop); + } + int text_elem_count = party_button_text_group_->GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c.SetTexture(party_button_text_group_->GetElementTexture(e)); + c.SetMaskUV2Texture( + party_button_text_group_->GetElementMaskUV2Texture(e)); + c.SetShadow( + -0.003f * party_button_text_group_->GetElementUScale(e), + -0.003f * party_button_text_group_->GetElementVScale(e), 0.0f, + 1.0f); + c.SetFlatness(1.0f); + c.SetColor(0.8f, 1, 0.8f, 0.9f); + c.PushTransform(); + c.Translate(width - menu_button_size_ * 0.42f + + connected_client_extra_offset_smoothed_, + height - menu_button_size_ * 0.77f, + kMenuButtonDrawDepth); + c.Scale(menu_button_size_ * 0.015f, menu_button_size_ * 0.015f); + c.DrawMesh(party_button_text_group_->GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + } + + { + // Update party count text if party size has changed. + if (party_size_text_group_num_ != party_size) { + party_size_text_group_num_ = party_size; + if (!party_size_text_group_.exists()) { + party_size_text_group_ = Object::New(); + } + party_size_text_group_->SetText( + std::to_string(party_size_text_group_num_)); + + // ..we also may want to update our 'someone joined' message if we're + // host + if (is_host) { + if (!start_a_game_text_group_.exists()) { + start_a_game_text_group_ = Object::New(); + } + if (party_size == 2) { // (includes us as host) + start_a_game_text_group_->SetText( + g_game->GetResourceString("joinedPartyInstructionsText"), + TextMesh::HAlign::kRight, TextMesh::VAlign::kTop); + } else if (party_size > 2) { + start_a_game_text_group_->SetText( + std::to_string(party_size - 1) + + " friends have joined your party.\nGo to 'Play' to start " + "a game.", + TextMesh::HAlign::kRight, TextMesh::VAlign::kTop); + } + } + } + + // Draw party member count. + int text_elem_count = party_size_text_group_->GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c.SetTexture(party_size_text_group_->GetElementTexture(e)); + c.SetMaskUV2Texture( + party_size_text_group_->GetElementMaskUV2Texture(e)); + c.SetShadow(-0.003f * party_size_text_group_->GetElementUScale(e), + -0.003f * party_size_text_group_->GetElementVScale(e), + 0.0f, 1.0f); + c.SetFlatness(1.0f); + if (flash && frame_def->base_time() % 250 < 125) { + c.SetColor(1, 1, 0); + } else { + if (party_size > 0) { + c.SetColor(0.2f, 1.0f, 0.2f); + } else { + c.SetColor(0.5f, 0.65f, 0.5f); + } + } + c.PushTransform(); + c.Translate(width - menu_button_size_ * 0.49f + + connected_client_extra_offset_smoothed_, + height - menu_button_size_ * 0.6f, kMenuButtonDrawDepth); + c.Scale(menu_button_size_ * 0.01f, menu_button_size_ * 0.01f); + c.DrawMesh(party_size_text_group_->GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + + // Draw 'someone joined' text if applicable. + if (is_host) { + if (flash) { + float blend = 0.8f; + start_a_game_text_scale_ = + blend * start_a_game_text_scale_ + (1.0f - blend) * 1.0f; + } else { + float blend = 0.8f; + start_a_game_text_scale_ = + blend * start_a_game_text_scale_ + (1.0f - blend) * 0.0f; + } + + if (start_a_game_text_scale_ > 0.001f) { + // 'start a game' notice + int text_elem_count = start_a_game_text_group_->GetElementCount(); + for (int e = 0; e < text_elem_count; e++) { + c.SetTexture(start_a_game_text_group_->GetElementTexture(e)); + c.SetMaskUV2Texture( + start_a_game_text_group_->GetElementMaskUV2Texture(e)); + c.SetShadow(-0.003f * start_a_game_text_group_->GetElementUScale(e), + -0.003f * start_a_game_text_group_->GetElementVScale(e), + 0.0f, 1.0f); + c.SetFlatness(1.0f); + if (flash && frame_def->base_time() % 250 < 125) { + c.SetColor(1, 1, 0); + } else { + c.SetColor(0, 1, 0); + } + c.PushTransform(); + c.Translate(width - 10, height - menu_button_size_ * 0.7f, -0.07f); + c.Scale(start_a_game_text_scale_, start_a_game_text_scale_); + c.DrawMesh(start_a_game_text_group_->GetElementMesh(e)); + c.PopTransform(); + } + c.Submit(); + } + } + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/ui/root_ui.h b/src/ballistica/ui/root_ui.h new file mode 100644 index 00000000..77f81137 --- /dev/null +++ b/src/ballistica/ui/root_ui.h @@ -0,0 +1,49 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_ROOT_UI_H_ +#define BALLISTICA_UI_ROOT_UI_H_ + +#include "ballistica/graphics/frame_def.h" + +namespace ballistica { + +/// Manages root level UI such as the menu button, party button, etc. +/// This is set to be replaced by RootWidget. +class RootUI { + public: + RootUI(); + virtual ~RootUI(); + void Draw(FrameDef* frame_def); + + auto HandleMouseButtonDown(float x, float y) -> bool; + void HandleMouseButtonUp(float x, float y); + void HandleMouseMotion(float x, float y); + void set_party_window_open(bool val) { party_window_open_ = val; } + auto party_window_open() const -> bool { return party_window_open_; } + void set_always_draw_party_icon(bool val) { always_draw_party_icon_ = val; } + auto always_draw_party_icon() const -> bool { + return always_draw_party_icon_; + } + void TogglePartyWindowKeyPress(); + void ActivatePartyIcon() const; + + private: + millisecs_t last_menu_button_press_time_{}; + millisecs_t menu_update_time_{}; + bool menu_button_pressed_{}; + float menu_button_size_{}; + bool menu_button_hover_{}; + float menu_fade_{}; + bool party_window_open_{}; + bool always_draw_party_icon_{}; + float connected_client_extra_offset_smoothed_{}; + Object::Ref party_button_text_group_; + Object::Ref party_size_text_group_; + int party_size_text_group_num_{-1}; + Object::Ref start_a_game_text_group_; + float start_a_game_text_scale_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_ROOT_UI_H_ diff --git a/src/ballistica/ui/ui.cc b/src/ballistica/ui/ui.cc new file mode 100644 index 00000000..3a9b0727 --- /dev/null +++ b/src/ballistica/ui/ui.cc @@ -0,0 +1,454 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/ui.h" + +#include "ballistica/app/app_globals.h" +#include "ballistica/audio/audio.h" +#include "ballistica/generic/lambda_runnable.h" +#include "ballistica/graphics/component/empty_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/input/input.h" +#include "ballistica/media/component/data.h" +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/sound.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/python/python.h" +#include "ballistica/scene/scene.h" +#include "ballistica/ui/root_ui.h" +#include "ballistica/ui/widget/button_widget.h" +#include "ballistica/ui/widget/root_widget.h" +#include "ballistica/ui/widget/stack_widget.h" + +namespace ballistica { + +static const int kUIOwnerTimeoutSeconds = 30; + +UI::UI() { + // Figure out our interface type. + assert(g_platform); + + // Allow overriding via an environment variable. + auto* ui_override = getenv("BA_FORCE_UI_SCALE"); + bool force_test_small{}; + bool force_test_medium{}; + bool force_test_large{}; + if (ui_override) { + if (ui_override == std::string("small")) { + force_test_small = true; + } else if (ui_override == std::string("medium")) { + force_test_medium = true; + } else if (ui_override == std::string("large")) { + force_test_large = true; + } + } + if (force_test_small) { + g_app_globals->ui_scale = UIScale::kSmall; + } else if (force_test_medium) { + g_app_globals->ui_scale = UIScale::kMedium; + } else if (force_test_large) { + g_app_globals->ui_scale = UIScale::kLarge; + } else { + // Use automatic val. + if (g_buildconfig.iircade_build()) { + g_app_globals->ui_scale = UIScale::kMedium; + } else if (IsVRMode() || g_platform->IsRunningOnTV()) { + // VR and tv builds always use medium. + g_app_globals->ui_scale = UIScale::kMedium; + } else { + g_app_globals->ui_scale = g_platform->GetInterfaceType(); + } + } + + // Make sure we know when forced-ui-scale is enabled. + if (force_test_small) { + ScreenMessage("FORCING SMALL UI FOR TESTING", Vector3f(1, 0, 0)); + Log("FORCING SMALL UI FOR TESTING"); + } else if (force_test_medium) { + ScreenMessage("FORCING MEDIUM UI FOR TESTING", Vector3f(1, 0, 0)); + Log("FORCING MEDIUM UI FOR TESTING"); + } else if (force_test_large) { + ScreenMessage("FORCING LARGE UI FOR TESTING", Vector3f(1, 0, 0)); + Log("FORCING LARGE UI FOR TESTING"); + } + + step_scene_timer_ = + base_timers_.NewTimer(base_time_, kGameStepMilliseconds, 0, -1, + NewLambdaRunnable([this] { StepScene(); })); + scene_ = Object::New(0); + root_ui_ = new RootUI(); +} + +// Currently the UI never dies so we don't bother doing a clean tear-down.. +// (verifying scene cleanup, etc) +UI::~UI() { + assert(root_ui_); + delete root_ui_; +} + +auto UI::IsWindowPresent() const -> bool { + return ((screen_root_widget_.exists() && screen_root_widget_->HasChildren()) + || (overlay_root_widget_.exists() + && overlay_root_widget_->HasChildren())); +} + +void UI::SetUIInputDevice(InputDevice* input_device) { + assert(InGameThread()); + + ui_input_device_ = input_device; + + // So they dont get stolen from immediately. + last_input_device_use_time_ = GetRealTime(); +} + +UI::UILock::UILock(bool write) { + assert(g_ui); + assert(InGameThread()); + + if (write && g_ui->ui_lock_count_ != 0) { + BA_LOG_ERROR_TRACE_ONCE("Illegal operation: UI is locked"); + } + g_ui->ui_lock_count_++; +} + +UI::UILock::~UILock() { + g_ui->ui_lock_count_--; + if (g_ui->ui_lock_count_ < 0) { + BA_LOG_ERROR_TRACE_ONCE("ui_lock_count_ < 0"); + g_ui->ui_lock_count_ = 0; + } +} + +void UI::StepScene() { + auto s = scene(); + sim_timers_.Run(s->time()); + s->Step(); +} + +void UI::Update(millisecs_t time_advance) { + assert(InGameThread()); + + millisecs_t target_base_time = base_time_ + time_advance; + while (!base_timers_.empty() + && (base_time_ + base_timers_.GetTimeToNextExpire(base_time_) + <= target_base_time)) { + base_time_ += base_timers_.GetTimeToNextExpire(base_time_); + base_timers_.Run(base_time_); + } + base_time_ = target_base_time; + + // Periodically prune various dead refs. + if (base_time_ > next_prune_time_) { + PruneDeadMapRefs(&textures_); + PruneDeadMapRefs(&sounds_); + PruneDeadMapRefs(&models_); + next_prune_time_ = base_time_ + 4920; + + // Since we never clear our scene, we need to watch for leaks. + // If there's more than a few nodes in existence for an extended period of + // time, complain. + if (scene_->nodes().size() > 10) { + node_warning_count_++; + if (node_warning_count_ > 3) { + static bool complained = false; + if (!complained) { + Log(">10 nodes in UI context!"); + complained = true; + } + } + } else { + node_warning_count_ = 0; + } + } +} + +void UI::Reset() { + // Hmm; technically we don't need to recreate these each time we reset. + root_widget_.Clear(); + + // Kill our screen-root widget. + screen_root_widget_.Clear(); + + // (Re)create our screen-root widget. + auto sw(Object::New()); + sw->set_is_main_window_stack(true); + sw->SetWidth(g_graphics->screen_virtual_width()); + sw->SetHeight(g_graphics->screen_virtual_height()); + sw->set_translate(0, 0); + screen_root_widget_ = sw; + + // (Re)create our screen-overlay widget. + auto ow(Object::New()); + ow->set_is_overlay_window_stack(true); + ow->SetWidth(g_graphics->screen_virtual_width()); + ow->SetHeight(g_graphics->screen_virtual_height()); + ow->set_translate(0, 0); + overlay_root_widget_ = ow; + + // (Re)create our abs-root widget. + auto rw(Object::New()); + root_widget_ = rw; + rw->SetWidth(g_graphics->screen_virtual_width()); + rw->SetHeight(g_graphics->screen_virtual_height()); + rw->SetScreenWidget(sw.get()); + rw->Setup(); + rw->SetOverlayWidget(ow.get()); + + sw->GlobalSelect(); +} + +auto UI::ShouldHighlightWidgets() const -> bool { + // Show selection highlights only if we've got controllers connected and only + // when the main UI is visible (dont want a selection highlight for toolbar + // buttons during a game). + return ( + g_input->have_non_touch_inputs() + && ((screen_root_widget_.exists() && screen_root_widget_->HasChildren()) + || (overlay_root_widget_.exists() + && overlay_root_widget_->HasChildren()))); +} + +auto UI::ShouldShowButtonShortcuts() const -> bool { + return g_input->have_non_touch_inputs(); +} + +void UI::AddWidget(Widget* w, ContainerWidget* parent) { + assert(InGameThread()); + + BA_PRECONDITION(parent != nullptr); + + // If they're adding an initial window/dialog to our screen-stack, + // send a reset-local-input message so that characters who have lost focus + // will not get stuck running or whatnot. + if (screen_root_widget_.exists() && !screen_root_widget_->HasChildren() + && parent == &(*screen_root_widget_)) { + g_game->ResetInput(); + } + + parent->AddWidget(w); +} + +auto UI::SendWidgetMessage(const WidgetMessage& m) -> int { + if (!root_widget_.exists()) { + // Log("SendWidgetMessage() called before root widget created"); + return false; + } + return root_widget_->HandleMessage(m); +} + +void UI::DeleteWidget(Widget* widget) { + assert(widget); + if (widget) { + ContainerWidget* parent = widget->parent_widget(); + if (parent) { + parent->DeleteWidget(widget); + } + } +} + +void UI::ScreenSizeChanged() { + if (root_widget_.exists()) { + root_widget_->SetWidth(g_graphics->screen_virtual_width()); + root_widget_->SetHeight(g_graphics->screen_virtual_height()); + } +} + +auto UI::GetUIInputDevice() const -> InputDevice* { + assert(InGameThread()); + return ui_input_device_.get(); +} + +auto UI::GetWidgetForInput(InputDevice* input_device) -> Widget* { + assert(input_device); + assert(InGameThread()); + + // We only allow input-devices to control the UI when there's a window/dialog + // on the screen (even though our top/bottom bars still exist). + if ((!screen_root_widget_.exists() || (!screen_root_widget_->HasChildren())) + && (!overlay_root_widget_.exists() + || (!overlay_root_widget_->HasChildren()))) { + return nullptr; + } + + millisecs_t time = GetRealTime(); + + bool print_menu_owner = false; + Widget* ret_val; + + // Ok here's the deal: + // Because having 10 controllers attached to the UI is pure chaos, + // we only allow one input device at a time to control the menu. + // However, if no events are received by that device for a long time, + // it is up for grabs to the next device that requests it. + + if ((GetUIInputDevice() == nullptr) || (input_device == GetUIInputDevice()) + || (time - last_input_device_use_time_ > (1000 * kUIOwnerTimeoutSeconds)) + || !g_input->HaveManyLocalActiveInputDevices()) { + // Don't actually assign yet; only update times and owners if there's a + // widget to be had (we don't want some guy who moved his character 3 + // seconds ago to automatically own a newly created widget). + last_input_device_use_time_ = time; + ui_input_device_ = input_device; + ret_val = screen_root_widget_.get(); + } else { + // For rejected input devices, play error sounds sometimes so they know + // they're not the chosen one. + if (time - last_widget_input_reject_err_sound_time_ > 5000) { + last_widget_input_reject_err_sound_time_ = time; + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kErrorBeep)); + print_menu_owner = true; + } + ret_val = nullptr; // Rejected! + } + + if (print_menu_owner) { + InputDevice* input = GetUIInputDevice(); + + if (input) { + millisecs_t timeout = + kUIOwnerTimeoutSeconds - (time - last_input_device_use_time_) / 1000; + std::string time_out_str; + if (timeout > 0 && timeout < (kUIOwnerTimeoutSeconds - 10)) { + time_out_str = " " + g_game->GetResourceString("timeOutText"); + Utils::StringReplaceOne(&time_out_str, "${TIME}", + std::to_string(timeout)); + } else { + time_out_str = " " + g_game->GetResourceString("willTimeOutText"); + } + + std::string name; + if (input->GetDeviceName() == "Keyboard") { + name = g_game->GetResourceString("keyboardText"); + } else if (input->GetDeviceName() == "TouchScreen") { + name = g_game->GetResourceString("touchScreenText"); + } else { + // We used to use player names here, but that's kinda sloppy and random; + // lets just go with device names/numbers. + auto devicesWithName = + g_input->GetInputDevicesWithName(input->GetDeviceName()); + if (devicesWithName.size() == 1) { + // If there's just one, no need to tack on the '#2' or whatever. + name = input->GetDeviceName(); + } else { + name = + input->GetDeviceName() + " " + input->GetPersistentIdentifier(); + } + } + + std::string b = g_game->GetResourceString("hasMenuControlText"); + Utils::StringReplaceOne(&b, "${NAME}", name); + ScreenMessage(b + time_out_str, {0.45f, 0.4f, 0.5f}); + } + } + return ret_val; +} + +auto UI::GetModel(const std::string& name) -> Object::Ref { + return Media::GetMedia(&models_, name, scene()); +} + +auto UI::GetTexture(const std::string& name) -> Object::Ref { + return Media::GetMedia(&textures_, name, scene()); +} + +auto UI::GetSound(const std::string& name) -> Object::Ref { + return Media::GetMedia(&sounds_, name, scene()); +} + +auto UI::GetData(const std::string& name) -> Object::Ref { + return Media::GetMedia(&datas_, name, scene()); +} + +auto UI::GetAsUIContext() -> UI* { return this; } + +auto UI::GetMutableScene() -> Scene* { + Scene* sg = scene_.get(); + assert(sg); + return sg; +} + +auto UI::NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int { + // All of our stuff is just real-time; lets just map all timer options to + // that. + switch (timetype) { + case TimeType::kSim: + case TimeType::kBase: + case TimeType::kReal: + return g_game->NewRealTimer(length, repeat, runnable); + default: + // Fall back to default for descriptive error otherwise. + return ContextTarget::NewTimer(timetype, length, repeat, runnable); + } +} + +void UI::DeleteTimer(TimeType timetype, int timer_id) { + switch (timetype) { + case TimeType::kSim: + case TimeType::kBase: + case TimeType::kReal: + g_game->DeleteRealTimer(timer_id); + break; + default: + // Fall back to default for descriptive error otherwise. + ContextTarget::DeleteTimer(timetype, timer_id); + break; + } +} + +auto UI::Draw(FrameDef* frame_def) -> void { + RenderPass* overlay_flat_pass = frame_def->GetOverlayFlatPass(); + + // Draw interface elements. + auto* root_widget = root_widget_.get(); + + if (root_widget && root_widget->HasChildren()) { + // Draw our opaque and transparent parts separately. + // This way we can draw front-to-back for opaque and back-to-front for + // transparent. + + g_graphics->set_drawing_opaque_only(true); + + // Do a wee bit of shifting based on tilt just for fun. + Vector3f tilt = 0.1f * g_graphics->tilt(); + { + EmptyComponent c(overlay_flat_pass); + c.SetTransparent(false); + c.PushTransform(); + c.Translate(-tilt.y, tilt.x, -0.5f); + + // We want our widgets to cover 0.1f in z space. + c.Scale(1.0f, 1.0f, 0.1f); + c.Submit(); + root_widget->Draw(overlay_flat_pass, false); + c.PopTransform(); + c.Submit(); + } + + g_graphics->set_drawing_opaque_only(false); + g_graphics->set_drawing_transparent_only(true); + + { + EmptyComponent c(overlay_flat_pass); + c.SetTransparent(true); + c.PushTransform(); + c.Translate(-tilt.y, tilt.x, -0.5f); + + // We want our widgets to cover 0.1f in z space. + c.Scale(1.0f, 1.0f, 0.1f); + c.Submit(); + root_widget->Draw(overlay_flat_pass, true); + c.PopTransform(); + c.Submit(); + } + + g_graphics->set_drawing_transparent_only(false); + } + if (root_ui_) { + root_ui_->Draw(frame_def); + } +} + +void UI::DrawExtras(FrameDef* frame_def) { root_ui_->Draw(frame_def); } + +} // namespace ballistica diff --git a/src/ballistica/ui/ui.h b/src/ballistica/ui/ui.h new file mode 100644 index 00000000..ac37e0f9 --- /dev/null +++ b/src/ballistica/ui/ui.h @@ -0,0 +1,149 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_UI_H_ +#define BALLISTICA_UI_UI_H_ + +#include +#include + +#include "ballistica/core/context.h" +#include "ballistica/generic/timer_list.h" +#include "ballistica/ui/widget/widget.h" + +// UI-Locks: make sure widget-lists don't change under you. +// Use a read-lock if you just need to ensure lists remain intact but won't be +// changing anything. Use a write-lock whenever modifying a list. +#if BA_DEBUG_BUILD +#define BA_DEBUG_UI_READ_LOCK UI::UILock ui_lock(false) +#define BA_DEBUG_UI_WRITE_LOCK UI::UILock ui_lock(true) +#else +#define BA_DEBUG_UI_READ_LOCK +#define BA_DEBUG_UI_WRITE_LOCK +#endif +#define BA_UI_READ_LOCK UI::UILock ui_lock(false) +#define BA_UI_WRITE_LOCK UI::UILock ui_lock(true) + +namespace ballistica { + +// All this stuff must be called from the game module. +class UI : public ContextTarget { + public: + UI(); + ~UI() override; + void Reset(); + + // Return the root widget containing all windows & dialogs + // Whenever this contains children, the UI is considered to be in focus + auto screen_root_widget() -> ContainerWidget* { + return screen_root_widget_.get(); + } + + auto overlay_root_widget() -> ContainerWidget* { + return overlay_root_widget_.get(); + } + + // Returns true if there is UI present in either the main or overlay + // stacks. Generally this implies the focus should be on the UI. + auto IsWindowPresent() const -> bool; + + // Return the absolute root widget; this includes persistent UI + // bits such as the top/bottom bars + auto root_widget() -> RootWidget* { return root_widget_.get(); } + + auto Draw(FrameDef* frame_def) -> void; + + // Returns the widget an input should send commands to, if any. + // Also potentially locks other inputs out of controlling the UI, + // so only call this if you intend on sending a message to that widget. + auto GetWidgetForInput(InputDevice* input_device) -> Widget*; + + // Add a widget to a container. + // If a parent is provided, the widget is added to it; otherwise it is added + // to the root widget. + void AddWidget(Widget* w, ContainerWidget* to); + + // Send message to the active widget. + auto SendWidgetMessage(const WidgetMessage& msg) -> int; + + // Use this to destroy any named widget (even those in containers). + void DeleteWidget(Widget* widget); + + void ScreenSizeChanged(); + + void SetUIInputDevice(InputDevice* input_device); + + // Returns the input-device that currently owns the menu; otherwise nullptr. + auto GetUIInputDevice() const -> InputDevice*; + + // Returns whether currently selected widgets should flash. + // This will be false in some situations such as when only touch screen + // control is active. + auto ShouldHighlightWidgets() const -> bool; + + // Same except for button shortcuts; these generally only get shown + // if a joystick of some form is present. + auto ShouldShowButtonShortcuts() const -> bool; + + void DrawExtras(FrameDef* frame_def); + + // Used to ensure widgets are not created or destroyed at certain times + // (while traversing widget hierarchy, etc). + class UILock { + public: + explicit UILock(bool write); + ~UILock(); + + private: + BA_DISALLOW_CLASS_COPIES(UILock); + }; + + auto GetSound(const std::string& name) -> Object::Ref override; + auto GetData(const std::string& name) -> Object::Ref override; + auto GetModel(const std::string& name) -> Object::Ref override; + auto GetTexture(const std::string& name) -> Object::Ref override; + auto GetAsUIContext() -> UI* override; + auto scene() -> Scene* { + assert(scene_.exists()); + return scene_.get(); + } + void Update(millisecs_t time_advance); + auto GetMutableScene() -> Scene* override; + + // Context-target timer support. + auto NewTimer(TimeType timetype, TimerMedium length, bool repeat, + const Object::Ref& runnable) -> int override; + void DeleteTimer(TimeType timetype, int timer_id) override; + + RootUI* root_ui() const { + assert(root_ui_); + return root_ui_; + } + + private: + void StepScene(); + RootUI* root_ui_{}; + millisecs_t next_prune_time_{}; + int node_warning_count_{}; + Timer* step_scene_timer_{}; + millisecs_t base_time_{}; + TimerList sim_timers_; + TimerList base_timers_; + Object::Ref scene_; + Object::WeakRef ui_input_device_; + millisecs_t last_input_device_use_time_{}; + millisecs_t last_widget_input_reject_err_sound_time_{}; + Object::Ref screen_root_widget_; + Object::Ref overlay_root_widget_; + Object::Ref root_widget_; + int ui_lock_count_{}; + + // Media loaded in the UI context. + std::map > textures_; + std::map > sounds_; + std::map > datas_; + std::map > models_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_UI_H_ diff --git a/src/ballistica/ui/widget/button_widget.cc b/src/ballistica/ui/widget/button_widget.cc new file mode 100644 index 00000000..981ecc71 --- /dev/null +++ b/src/ballistica/ui/widget/button_widget.cc @@ -0,0 +1,594 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/button_widget.h" + +#include +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/generic/real_timer.h" +#include "ballistica/generic/utils.h" +#include "ballistica/graphics/component/empty_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/input/device/input_device.h" +#include "ballistica/input/input.h" +#include "ballistica/media/component/model.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +ButtonWidget::ButtonWidget() { + text_ = Object::New(); + SetText("Button"); + text_->set_valign(TextWidget::VAlign::kCenter); + text_->set_halign(TextWidget::HAlign::kCenter); + text_->SetWidth(0.0f); + text_->SetHeight(0.0f); + birth_time_ = g_game->master_time(); +} + +ButtonWidget::~ButtonWidget() = default; + +void ButtonWidget::SetTextResScale(float val) { text_->set_res_scale(val); } + +void ButtonWidget::set_on_activate_call(PyObject* call_obj) { + on_activate_call_ = Object::New(call_obj); +} + +void ButtonWidget::SetText(const std::string& text_in) { + std::string text = Utils::GetValidUTF8(text_in.c_str(), "bwst"); + text_->SetText(text); + + // Also cache our current text width; don't want to calc this with each draw + // (especially now that we may have to ask the OS to do it). + text_width_dirty_ = true; +} + +void ButtonWidget::SetTexture(Texture* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("texture is not from the UI context: " + ObjToString(val)); + } + texture_ = val; +} + +void ButtonWidget::SetMaskTexture(Texture* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("texture is not from the UI context: " + ObjToString(val)); + } + mask_texture_ = val; +} + +void ButtonWidget::SetTintTexture(Texture* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("texture is not from the UI context: " + ObjToString(val)); + } + tint_texture_ = val; +} + +void ButtonWidget::SetIcon(Texture* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("icon texture is not from the UI context: " + + val->GetObjectDescription()); + } + icon_ = val; +} + +void ButtonWidget::HandleRealTimerExpired(RealTimer* t) { + // Repeat our action unless we somehow lost focus but didn't get a mouse-up. + if (IsHierarchySelected() && pressed_) { + DoActivate(true); + + // Speed up repeats after the first. + t->SetLength(150); + } else { + repeat_timer_.Clear(); + } +} + +void ButtonWidget::SetModelOpaque(Model* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("model_opaque is not from the UI context"); + } + model_opaque_ = val; +} + +void ButtonWidget::SetModelTransparent(Model* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("model_transparent is not from the UI context"); + } + model_transparent_ = val; +} + +auto ButtonWidget::GetWidth() -> float { return width_; } +auto ButtonWidget::GetHeight() -> float { return height_; } + +auto ButtonWidget::GetMult(millisecs_t current_time) const -> float { + float mult = 1.0f; + if ((pressed_ && mouse_over_) || (current_time - last_activate_time_ < 200)) { + if (pressed_ && mouse_over_) { + mult = 3.0f; + } else { + float x = static_cast(current_time - last_activate_time_) / 200.0f; + mult = 1.0f + 3.0f * (1.0f - x * x); + } + } else if ((IsHierarchySelected() && g_ui->ShouldHighlightWidgets())) { + mult = + 0.8f + + std::abs(sinf(static_cast(current_time) * 0.006467f)) * 0.2f; + + if (!texture_.exists()) { + mult *= 1.7f; + } else { + // Let's make custom textures pulsate brighter since they can be dark/etc. + mult *= 2.0f; + } + } else { + if (!texture_.exists()) { + } else { + // In desktop mode we want image buttons to light up when we + // mouse over them. + if (!g_platform->IsRunningOnDesktop()) { + if (mouse_over_) { + mult = 1.4f; + } + } + } + } + return mult; +} + +auto ButtonWidget::GetDrawBrightness(millisecs_t time) const -> float { + return GetMult(time); +} + +void ButtonWidget::Draw(RenderPass* pass, bool draw_transparent) { + millisecs_t current_time = pass->frame_def()->base_time(); + + Vector3f tilt = 0.02f * g_graphics->tilt(); + float extra_offs_x = -tilt.y; + float extra_offs_y = tilt.x; + + assert(g_input); + bool show_icons = false; + + InputDevice* device = g_ui->GetUIInputDevice(); + + // If there's an explicit user-set icon we always show. + if (icon_.exists()) { + show_icons = true; + } + + bool ouya_icons = false; + bool remote_icons = false; + + // Phasing out ouya stuff. + if (explicit_bool(false)) { + ouya_icons = true; + } + if (icon_type_ == IconType::kCancel && device != nullptr + && device->IsRemoteControl()) { + remote_icons = true; + } + + // Simple transition. + float transition = (birth_time_ + transition_delay_) - current_time; + if (transition > 0) { + extra_offs_x -= transition * 4.0f; + } + + if (text_width_dirty_) { + text_width_ = text_->GetTextWidth(); + text_width_dirty_ = false; + } + + float string_scale = text_scale_; + + bool string_too_small_to_draw = false; + + // We should only need this in our transparent pass. + float string_width; + if (draw_transparent) { + string_width = std::max(0.0001f, text_width_); + + // Account for our icon if we have it. + float s_width_available = std::max(30.0f, width_ - 30); + if (show_icons) s_width_available -= (34.0f * icon_scale_); + + if ((string_width * string_scale) > s_width_available) { + float squish_scale = s_width_available / (string_width * string_scale); + if (squish_scale < 0.2f) string_too_small_to_draw = true; + string_scale *= squish_scale; + } + } else { + string_width = 0.0f; // Shouldn't be used. + } + + float mult = GetMult(current_time); + + { + float l = 0; + float r = l + width_; + float b = 0; + float t = b + height_; + + // Use these to pick styles so style doesnt + // change during mouse-over, etc. + float l_orig = l; + float r_orig = r; + float b_orig = b; + float t_orig = t; + + // For normal buttons we draw both transparent and opaque. + // With custom ones we only draw what we're given. + Object::Ref custom_model; + bool do_draw_model; + + // Normal buttons draw in both transparent and opaque passes. + if (!texture_.exists()) { + do_draw_model = true; + } else { + // If we're supplying any custom models, draw whichever is provided. + if (model_opaque_.exists() || model_transparent_.exists()) { + if (draw_transparent && model_transparent_.exists()) { + do_draw_model = true; + custom_model = model_transparent_; + } else if ((!draw_transparent) && model_opaque_.exists()) { + do_draw_model = true; + custom_model = model_opaque_; + } else { + do_draw_model = false; // Skip this pass. + } + } else { + // With no custom models we just draw a plain square in the + // transparent pass. + do_draw_model = draw_transparent; + } + } + + if (do_draw_model) { + SimpleComponent c(pass); + c.SetTransparent(draw_transparent); + + // We currently only support non-1.0 opacity values when using + // custom textures and no custom opaque model. + assert(opacity_ == 1.0f + || (texture_.exists() && !model_opaque_.exists())); + + c.SetColor(mult * color_red_, mult * color_green_, mult * color_blue_, + opacity_); + + float l_border, r_border, b_border, t_border; + + bool doDraw = true; + + ModelData* model; + + // Custom button texture. + if (texture_.exists()) { + if (!custom_model.exists()) { + model = g_media->GetModel(SystemModelID::kImage1x1); + } else { + model = custom_model->model_data(); + } + if (texture_->texture_data()->loaded() && model->loaded() + && (!mask_texture_.exists() + || mask_texture_->texture_data()->loaded()) + && (!tint_texture_.exists() + || tint_texture_->texture_data()->loaded())) { + c.SetTexture(texture_); + if (tint_texture_.exists()) { + c.SetColorizeTexture(tint_texture_); + c.SetColorizeColor(tint_color_red_, tint_color_green_, + tint_color_blue_); + c.SetColorizeColor2(tint2_color_red_, tint2_color_green_, + tint2_color_blue_); + } + c.SetMaskTexture(mask_texture_); + } else { + doDraw = false; + } + l_border = r_border = 0.04f * width_; + b_border = t_border = 0.04f * height_; + } else { + // Standard button texture. + SystemModelID model_id; + SystemTextureID tex_id; + + switch (style_) { + case Style::kBack: { + tex_id = SystemTextureID::kUIAtlas; + model_id = draw_transparent ? SystemModelID::kButtonBackTransparent + : SystemModelID::kButtonBackOpaque; + l_border = 10; + r_border = 6; + b_border = 6; + t_border = -1; + break; + } + case Style::kBackSmall: { + tex_id = SystemTextureID::kUIAtlas; + model_id = draw_transparent + ? SystemModelID::kButtonBackSmallTransparent + : SystemModelID::kButtonBackSmallOpaque; + l_border = 10; + r_border = 14; + b_border = 9; + t_border = 5; + break; + } + case Style::kTab: { + tex_id = SystemTextureID::kUIAtlas2; + model_id = draw_transparent ? SystemModelID::kButtonTabTransparent + : SystemModelID::kButtonTabOpaque; + l_border = 6; + r_border = 10; + b_border = 5; + t_border = 2; + break; + } + case Style::kSquare: { + tex_id = SystemTextureID::kButtonSquare; + model_id = draw_transparent + ? SystemModelID::kButtonSquareTransparent + : SystemModelID::kButtonSquareOpaque; + l_border = 6; + r_border = 9; + b_border = 6; + t_border = 6; + break; + } + default: { + if ((r_orig - l_orig) / (t_orig - b_orig) < 50.0f / 30.0f) { + tex_id = SystemTextureID::kUIAtlas; + model_id = draw_transparent + ? SystemModelID::kButtonSmallTransparent + : SystemModelID::kButtonSmallOpaque; + l_border = 10; + r_border = 14; + b_border = 9; + t_border = 5; + } else if ((r_orig - l_orig) / (t_orig - b_orig) < 200.0f / 35.0f) { + tex_id = SystemTextureID::kUIAtlas; + model_id = draw_transparent + ? SystemModelID::kButtonMediumTransparent + : SystemModelID::kButtonMediumOpaque; + l_border = 6; + r_border = 10; + b_border = 5; + t_border = 2; + } else if ((r_orig - l_orig) / (t_orig - b_orig) < 300.0f / 35.0f) { + tex_id = SystemTextureID::kUIAtlas; + model_id = draw_transparent + ? SystemModelID::kButtonLargeTransparent + : SystemModelID::kButtonLargeOpaque; + l_border = 7; + r_border = 10; + b_border = 10; + t_border = 5; + } else { + tex_id = SystemTextureID::kUIAtlas; + model_id = draw_transparent + ? SystemModelID::kButtonLargerTransparent + : SystemModelID::kButtonLargerOpaque; + l_border = 7; + r_border = 11; + b_border = 10; + t_border = 4; + } + break; + } + } + c.SetTexture(g_media->GetTexture(tex_id)); + model = g_media->GetModel(model_id); + } + if (doDraw) { + c.PushTransform(); + c.Translate((l - l_border + r + r_border) * 0.5f + extra_offs_x, + (b - b_border + t + t_border) * 0.5f + extra_offs_y, 0); + c.Scale(r - l + l_border + r_border, t - b + b_border + t_border, 1.0f); + c.DrawModel(model); + c.PopTransform(); + } + + // Draw icon. + if ((show_icons) && draw_transparent) { + bool doDrawIcon = true; + if (icon_type_ == IconType::kStart) { + c.SetColor(1.4f * mult * (color_red_), 1.4f * mult * (color_green_), + 1.4f * mult * (color_blue_), 1.0f); + c.SetTexture(g_media->GetTexture(SystemTextureID::kStartButton)); + } else if (icon_type_ == IconType::kCancel) { + if (remote_icons) { + c.SetColor(1.0f * mult * (1.0f), 1.0f * mult * (1.0f), + 1.0f * mult * (1.0f), 1.0f); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBackIcon)); + } else if (ouya_icons) { + c.SetColor(1.0f * mult * (1.0f), 1.0f * mult * (1.0f), + 1.0f * mult * (1.0f), 1.0f); + c.SetTexture(g_media->GetTexture(SystemTextureID::kOuyaAButton)); + } else { + c.SetColor(1.5f * mult * (color_red_), 1.5f * mult * (color_green_), + 1.5f * mult * (color_blue_), 1.0f); + c.SetTexture(g_media->GetTexture(SystemTextureID::kBombButton)); + } + } else if (icon_.exists()) { + c.SetColor(icon_color_red_ + * (icon_tint_ * (1.7f * mult * (color_red_)) + + (1.0f - icon_tint_) * mult), + icon_color_green_ + * (icon_tint_ * (1.7f * mult * (color_green_)) + + (1.0f - icon_tint_) * mult), + icon_color_blue_ + * (icon_tint_ * (1.7f * mult * (color_blue_)) + + (1.0f - icon_tint_) * mult), + icon_color_alpha_); + if (!icon_->texture_data()->loaded()) { + doDrawIcon = false; + } else { + c.SetTexture(icon_); + } + } else { + c.SetColor(1, 1, 1); + c.SetTexture(g_media->GetTexture(SystemTextureID::kCircle)); + } + if (doDrawIcon) { + c.PushTransform(); + c.Translate((l + r) * 0.5f + extra_offs_x + - (string_width * string_scale) * 0.5f - 5.0f, + (b + t) * 0.5f + extra_offs_y, 0.001f); + c.Scale(34.0f * icon_scale_, 34.f * icon_scale_, 1.0f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + c.PopTransform(); + } + } + c.Submit(); + } + } + + // Draw our text at z depth 0.5-1. + if (!string_too_small_to_draw) { + EmptyComponent c(pass); + c.SetTransparent(draw_transparent); + c.PushTransform(); + c.Translate(1.0f * extra_offs_x, 1.0f * extra_offs_y, 0.5f); + c.Scale(1, 1, 0.5f); + c.Translate(width_ * 0.5f, height_ * 0.5f); + + // Shift over for our icon if we have it. + if (show_icons) { + c.Translate(17.0f * icon_scale_, 0, 0); + } + if (string_scale != 1.0f) { + c.Scale(string_scale, string_scale); + } + c.Submit(); + + text_->set_color(mult * text_color_r_, mult * text_color_g_, + mult * text_color_b_, text_color_a_); + text_->set_flatness(text_flatness_); + text_->Draw(pass, draw_transparent); + c.PopTransform(); + c.Submit(); + } +} + +auto ButtonWidget::HandleMessage(const WidgetMessage& m) -> bool { + // How far outside button touches register. + float left_overlap, top_overlap, right_overlap, bottom_overlap; + if (g_platform->IsRunningOnDesktop()) { + left_overlap = 3.0f; + top_overlap = 1.0f; + right_overlap = 0.0f; + bottom_overlap = 0.0f; + } else { + left_overlap = 3.0f + 9.0f * extra_touch_border_scale_; + top_overlap = 1.0f + 5.0f * extra_touch_border_scale_; + right_overlap = 7.0f * extra_touch_border_scale_; + bottom_overlap = 7.0f * extra_touch_border_scale_; + } + + switch (m.type) { + case WidgetMessage::Type::kMouseMove: { + float x = m.fval1; + float y = m.fval2; + bool claimed = (m.fval3 > 0.0f); + if (claimed || !enabled_) { + mouse_over_ = false; + } else { + mouse_over_ = + ((x >= (-left_overlap)) && (x < (width_ + right_overlap)) + && (y >= (-bottom_overlap)) && (y < (height_ + top_overlap))); + } + + return mouse_over_; + } + case WidgetMessage::Type::kMouseDown: { + float x = m.fval1; + float y = m.fval2; + if (enabled_ && (x >= (-left_overlap)) && (x < (width_ + right_overlap)) + && (y >= (-bottom_overlap)) && (y < (height_ + top_overlap))) { + mouse_over_ = true; + pressed_ = true; + + if (repeat_) { + repeat_timer_ = Object::New>(300, true, this); + // If we're a repeat button we trigger immediately. + // (waiting till mouse up sort of defeats the purpose here) + Activate(); + } + if (selectable_) { + GlobalSelect(); + } + return true; + } else { + return false; + } + } + case WidgetMessage::Type::kMouseUp: { + float x = m.fval1; + float y = m.fval2; + bool claimed = (m.fval3 > 0.0f); + if (pressed_) { + pressed_ = false; + + // Stop any repeats. + repeat_timer_.Clear(); + + // For non-repeat buttons, non-claimed mouse-ups within the + // button region trigger the action. + if (!repeat_) { + if (enabled_ && (x >= (0 - left_overlap)) + && (x < (0 + width_ + right_overlap)) + && (y >= (0 - bottom_overlap)) + && (y < (0 + height_ + top_overlap)) && !claimed) { + Activate(); + } + } + return true; // Pressed buttons always claim mouse-ups. + } + break; + } + default: + break; + } + return false; +} + +void ButtonWidget::Activate() { DoActivate(); } + +void ButtonWidget::DoActivate(bool isRepeat) { + if (!enabled_) { + Log("WARNING: ButtonWidget::DoActivate() called on disabled button"); + return; + } + + // We dont want holding down a repeat-button to keep flashing it. + if (!isRepeat) { + last_activate_time_ = g_game->master_time(); + } + if (sound_enabled_) { + int r = rand() % 3; // NOLINT + if (r == 0) { + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kSwish)); + } else if (r == 1) { + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kSwish2)); + } else { + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kSwish3)); + } + } + if (on_activate_call_.exists()) { + // Call this in the next cycle (don't wanna risk mucking with UI from + // within a UI loop. + g_game->PushPythonWeakCall( + Object::WeakRef(on_activate_call_)); + return; + } +} + +void ButtonWidget::OnLanguageChange() { + text_->OnLanguageChange(); + text_width_dirty_ = true; +} + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/button_widget.h b/src/ballistica/ui/widget/button_widget.h new file mode 100644 index 00000000..ba170ee7 --- /dev/null +++ b/src/ballistica/ui/widget/button_widget.h @@ -0,0 +1,146 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_BUTTON_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_BUTTON_WIDGET_H_ + +#include + +#include "ballistica/ui/widget/text_widget.h" + +namespace ballistica { + +class ButtonWidget : public Widget { + public: + ButtonWidget(); + ~ButtonWidget() override; + void Draw(RenderPass* pass, bool transparent) override; + auto HandleMessage(const WidgetMessage& m) -> bool override; + void set_width(float width) { width_ = width; } + void set_height(float height) { height_ = height; } + auto GetWidth() -> float override; + auto GetHeight() -> float override; + void SetColor(float r, float g, float b) { + color_set_ = true; + color_red_ = r; + color_green_ = g; + color_blue_ = b; + } + void set_tint_color(float r, float g, float b) { + tint_color_red_ = r; + tint_color_green_ = g; + tint_color_blue_ = b; + } + void set_tint2_color(float r, float g, float b) { + tint2_color_red_ = r; + tint2_color_green_ = g; + tint2_color_blue_ = b; + } + void set_text_color(float r, float g, float b, float a) { + text_color_r_ = r; + text_color_g_ = g; + text_color_b_ = b; + text_color_a_ = a; + } + void set_icon_color(float r, float g, float b, float a) { + icon_color_red_ = r; + icon_color_green_ = g; + icon_color_blue_ = b; + icon_color_alpha_ = a; + } + void set_text_flatness(float f) { text_flatness_ = f; } + enum class Style { kRegular, kBack, kBackSmall, kTab, kSquare }; + void set_style(Style s) { style_ = s; } + enum class IconType { kNone, kCancel, kStart }; + void SetText(const std::string& text); + auto text() const -> std::string { return text_->text_raw(); } + void set_icon_type(IconType i) { icon_type_ = i; } + void set_repeat(bool repeat) { repeat_ = repeat; } + void set_text_scale(float val) { text_scale_ = val; } + void SetTexture(Texture* t); + void SetMaskTexture(Texture* t); + void SetTintTexture(Texture* val); + void SetIcon(Texture* t); + auto icon() const -> Texture* { return icon_.get(); } + void set_on_activate_call(PyObject* call_obj); + void Activate() override; + auto IsSelectable() -> bool override { return selectable_; } + auto GetWidgetTypeName() -> std::string override { return "button"; } + void set_enable_sound(bool enable) { sound_enabled_ = enable; } + void SetModelTransparent(Model* val); + void SetModelOpaque(Model* val); + void set_transition_delay(float val) { transition_delay_ = val; } + void HandleRealTimerExpired(RealTimer* t); + void set_extra_touch_border_scale(float scale) { + extra_touch_border_scale_ = scale; + } + void set_selectable(bool s) { selectable_ = s; } + void set_icon_scale(float s) { icon_scale_ = s; } + void set_icon_tint(float tint) { icon_tint_ = tint; } + void SetTextResScale(float val); + + // Disabled buttons can't be clicked or otherwise activated. + void set_enabled(bool val) { enabled_ = val; } + auto enabled() const -> bool { return enabled_; } + void set_opacity(float val) { opacity_ = val; } + auto GetDrawBrightness(millisecs_t time) const -> float override; + auto is_color_set() const -> bool { return color_set_; } + void OnLanguageChange() override; + + private: + bool text_width_dirty_ = true; + bool color_set_ = false; + void DoActivate(bool isRepeat = false); + auto GetMult(millisecs_t current_time) const -> float; + IconType icon_type_ = IconType::kNone; + bool enabled_ = true; + bool selectable_ = true; + float icon_tint_ = 0.0f; + Style style_ = Style::kRegular; + bool sound_enabled_ = true; + bool mouse_over_ = false; + bool repeat_ = false; + bool pressed_ = false; + float extra_touch_border_scale_ = 1.0f; + float width_ = 50.0f; + float height_ = 30.0f; + float text_scale_ = 1.0f; + float text_width_ = 0.0f; + float color_red_ = 0.5f; + float color_green_ = 0.7f; + float color_blue_ = 0.2f; + float icon_color_red_ = 1.0f; + float icon_color_green_ = 1.0f; + float icon_color_blue_ = 1.0f; + float icon_color_alpha_ = 1.0f; + Object::Ref texture_; + Object::Ref icon_; + Object::Ref tint_texture_; + Object::Ref mask_texture_; + Object::Ref model_transparent_; + Object::Ref model_opaque_; + float icon_scale_ = 1.0f; + millisecs_t last_activate_time_ = 0; + millisecs_t birth_time_ = 0; + float transition_delay_ = 0.0f; + float opacity_ = 1.0f; + float text_flatness_ = 0.5f; + float text_color_r_ = 0.75f; + float text_color_g_ = 1.0f; + float text_color_b_ = 0.7f; + float text_color_a_ = 1.0f; + float tint_color_red_ = 1.0f; + float tint_color_green_ = 1.0f; + float tint_color_blue_ = 1.0f; + float tint2_color_red_ = 1.0f; + float tint2_color_green_ = 1.0f; + float tint2_color_blue_ = 1.0f; + + // Keep these at the bottom so they're torn down first. + Object::Ref text_; + Object::Ref on_activate_call_; + Object::Ref > repeat_timer_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_WIDGET_BUTTON_WIDGET_H_ diff --git a/src/ballistica/ui/widget/check_box_widget.cc b/src/ballistica/ui/widget/check_box_widget.cc new file mode 100644 index 00000000..988ef58d --- /dev/null +++ b/src/ballistica/ui/widget/check_box_widget.cc @@ -0,0 +1,325 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/check_box_widget.h" + +#include "ballistica/audio/audio.h" +#include "ballistica/game/game.h" +#include "ballistica/graphics/component/empty_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/platform/platform.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/python/python_sys.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +CheckBoxWidget::CheckBoxWidget() { + SetText("CheckBox"); + text_.set_owner_widget(this); + text_.set_valign(TextWidget::VAlign::kCenter); + text_.set_halign(TextWidget::HAlign::kLeft); +} + +CheckBoxWidget::~CheckBoxWidget() = default; + +void CheckBoxWidget::SetOnValueChangeCall(PyObject* call_tuple) { + on_value_change_call_ = Object::New(call_tuple); +} + +void CheckBoxWidget::SetText(const std::string& text) { + text_.SetText(text); + have_text_ = (!text.empty()); +} + +void CheckBoxWidget::SetWidth(float width_in) { + highlight_dirty_ = box_dirty_ = check_dirty_ = true; + width_ = width_in; + text_.SetWidth(width_in - (2 * box_padding_ + box_size_ + 4)); +} + +void CheckBoxWidget::SetHeight(float height_in) { + highlight_dirty_ = box_dirty_ = check_dirty_ = true; + height_ = height_in; + text_.SetHeight(height_in); +} + +void CheckBoxWidget::Draw(RenderPass* pass, bool draw_transparent) { + millisecs_t real_time = GetRealTime(); + + have_drawn_ = true; + float l = 0.0f; + float r = l + width_; + float b = 0.0f; + float t = b + height_; + + Vector3f tilt = 0.01f * g_graphics->tilt(); + if (draw_control_parent()) { + tilt += 0.02f * g_graphics->tilt(); + } + float extra_offs_x = -tilt.y; + float extra_offs_y = tilt.x; + + if (have_text_ && draw_transparent + && ((selected() && g_ui->ShouldHighlightWidgets()) + || (pressed_ && mouse_over_))) { + // Draw glow (at depth 0.9f). + float m; + if (pressed_ && mouse_over_) { + m = 2.0f; + } else if (IsHierarchySelected()) { + m = 0.5f + + std::abs(sinf(static_cast(real_time) * 0.006467f) * 0.4f); + } else { + m = 0.25f; + } + + if (highlight_dirty_) { + float l_border, r_border, b_border, t_border; + l_border = 10.0f; + r_border = 0.0f; + b_border = 11.0f; + t_border = 11.0f; + highlight_width_ = r - l + l_border + r_border; + highlight_height_ = t - b + b_border + t_border; + highlight_center_x_ = l - l_border + highlight_width_ * 0.5f; + highlight_center_y_ = b - b_border + highlight_height_ * 0.5f; + highlight_dirty_ = false; + } + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.SetColor(0.25f * m, 0.3f * m, 0, 0.3f * m); + c.SetTexture(g_media->GetTexture(SystemTextureID::kGlow)); + c.PushTransform(); + c.Translate(highlight_center_x_, highlight_center_y_); + c.Scale(highlight_width_, highlight_height_); + c.DrawModel(g_media->GetModel(SystemModelID::kImage4x1)); + c.PopTransform(); + c.Submit(); + } + + float glow_amt = 1.0f; + + { + float box_l = l + box_padding_; + float box_r = box_l + box_size_; + float box_b = b + (t - b) / 2 - box_size_ / 2; + float box_t = box_b + box_size_; + + if (pressed_ && mouse_over_) { + glow_amt = 2.0f; + } else if (IsHierarchySelected() && g_ui->ShouldHighlightWidgets()) { + glow_amt = + 0.8f + + std::abs(sinf(static_cast(real_time) * 0.006467f) * 0.3f); + } + + // Button portion (depth 0.1f-0.5f). + { + if (box_dirty_) { + float l_border, r_border, b_border, t_border; + l_border = 8; + r_border = 12; + b_border = 6; + t_border = 6; + box_width_ = box_r - box_l + l_border + r_border; + box_height_ = box_t - box_b + b_border + t_border; + box_center_x_ = box_l - l_border + box_width_ * 0.5f; + box_center_y_ = box_b - b_border + box_height_ * 0.5f; + box_dirty_ = false; + } + + SimpleComponent c(pass); + c.SetTransparent(draw_transparent); + c.SetColor(glow_amt * color_r_, glow_amt * color_g_, glow_amt * color_b_, + 1); + c.SetTexture(g_media->GetTexture(SystemTextureID::kUIAtlas)); + c.PushTransform(); + c.Translate(box_center_x_ + extra_offs_x, box_center_y_ + extra_offs_y, + 0.1f); + c.Scale(box_width_, box_height_, 0.4f); + c.DrawModel(g_media->GetModel(draw_transparent + ? SystemModelID::kButtonSmallTransparent + : SystemModelID::kButtonSmallOpaque)); + c.PopTransform(); + c.Submit(); + } + + // Check portion. + if (draw_transparent) { + if (check_dirty_) { + float s = 1; + if (real_time - last_change_time_ < 100) { + s = static_cast(real_time - last_change_time_) / 100; + } + if (!checked_) s = 1.0f - s; + + float check_offset_h = -2; + float check_offset_v = -2; + + check_width_ = 45 * s; + check_height_ = 45 * s; + check_center_x_ = + box_l + 11 - 18 * s + check_offset_h + check_width_ * 0.5f; + check_center_y_ = + box_b + 10 - 18 * s + check_offset_v + check_height_ * 0.5f; + + // Only set clean once our transition is over. + if (real_time - last_change_time_ > 100) check_dirty_ = false; + } + + // Draw check in z depth from 0.5f to 1. + SimpleComponent c(pass); + c.SetTransparent(draw_transparent); + if (is_radio_button_) { + c.SetTexture(g_media->GetTexture(SystemTextureID::kNub)); + } else { + c.SetTexture(g_media->GetTexture(SystemTextureID::kUIAtlas)); + } + + if (mouse_over_ && g_platform->IsRunningOnDesktop()) { + c.SetColor(1.0f * glow_amt, 0.7f * glow_amt, 0, 1); + } else { + c.SetColor(1.0f * glow_amt, 0.6f * glow_amt, 0, 1); + } + c.PushTransform(); + + if (is_radio_button_) { + c.Translate(check_center_x_ + 1 + 3.0f * extra_offs_x, + check_center_y_ + 2 + 3.0f * extra_offs_y, 0.5f); + c.Scale(check_width_ * 0.45f, check_height_ * 0.45f, 0.5f); + c.Translate(-0.17f, -0.17f, 0.5f); + c.DrawModel(g_media->GetModel(SystemModelID::kImage1x1)); + } else { + c.Translate(check_center_x_ + 3.0f * extra_offs_x, + check_center_y_ + 3.0f * extra_offs_y, 0.5f); + c.Scale(check_width_, check_height_, 0.5f); + c.DrawModel(g_media->GetModel(SystemModelID::kCheckTransparent)); + } + c.PopTransform(); + c.Submit(); + } + } + + // Draw our text in z depth 0.5f to 1. + EmptyComponent c(pass); + c.SetTransparent(draw_transparent); + c.PushTransform(); + c.Translate(2 * box_padding_ + box_size_ + 10, 0, 0.5f); + c.Scale(1, 1, 0.5f); + c.Submit(); + float cs = glow_amt; + text_.set_color(cs * text_color_r_, cs * text_color_g_, cs * text_color_b_, + text_color_a_); + text_.Draw(pass, draw_transparent); + c.PopTransform(); + c.Submit(); +} + +// for our center we return something near center of the checkbox; not our text +void CheckBoxWidget::GetCenter(float* x, float* y) { + *x = tx() + scale() * GetWidth() * 0.2f; + *y = ty() + scale() * GetHeight() * 0.5f; +} + +void CheckBoxWidget::SetValue(bool value) { + if (value == checked_) { + return; + } + check_dirty_ = true; + + // Don't animate if we're setting initial values. + if (checked_ != value && have_drawn_) { + last_change_time_ = GetRealTime(); + } + checked_ = value; +} + +void CheckBoxWidget::Activate() { + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kSwish3)); + checked_ = !checked_; + check_dirty_ = true; + last_change_time_ = GetRealTime(); + if (on_value_change_call_.exists()) { + PythonRef args(Py_BuildValue("(O)", checked_ ? Py_True : Py_False), + PythonRef::kSteal); + + // Call this in the next cycle (don't wanna risk mucking with UI from within + // a UI loop) + g_game->PushPythonWeakCallArgs( + Object::WeakRef(on_value_change_call_), args); + } +} + +auto CheckBoxWidget::HandleMessage(const WidgetMessage& m) -> bool { + // How far outside button touches register. + float left_overlap, top_overlap, right_overlap, bottom_overlap; + if (g_platform->IsRunningOnDesktop()) { + left_overlap = 3.0f; + top_overlap = 1.0f; + right_overlap = 0.0f; + bottom_overlap = 0.0f; + } else { + left_overlap = 12.0f; + top_overlap = 10.0f; + right_overlap = 13.0f; + bottom_overlap = 15.0f; + } + + switch (m.type) { + case WidgetMessage::Type::kMouseMove: { + float x = m.fval1; + float y = m.fval2; + bool claimed = (m.fval3 > 0.0f); + if (claimed) + mouse_over_ = false; + else + mouse_over_ = + ((x >= (-left_overlap)) && (x < (width_ + right_overlap)) + && (y >= (-bottom_overlap)) && (y < (height_ + top_overlap))); + return mouse_over_; + } + case WidgetMessage::Type::kMouseDown: { + float x = m.fval1; + float y = m.fval2; + if ((x >= (-left_overlap)) && (x < (width_ + right_overlap)) + && (y >= (-bottom_overlap)) && (y < (height_ + top_overlap))) { + GlobalSelect(); + pressed_ = true; + return true; + } else { + return false; + } + } + case WidgetMessage::Type::kMouseUp: { + float x = m.fval1; + float y = m.fval2; + bool claimed = (m.fval3 > 0.0f); + + // Radio-style boxes can't be un-checked. + if (pressed_) { + pressed_ = false; + + // if they're still over us and unclaimed, toggle. + if ((x >= (-left_overlap)) && (x < (width_ + right_overlap)) + && (y >= (-bottom_overlap)) && (y < (height_ + top_overlap)) + && !claimed) { + // Radio-style buttons don't allow unchecking. + if (!is_radio_button_ || !checked_) { + Activate(); + } + } + return true; // If we're pressed, claim any mouse-ups presented to us. + } + break; + } + default: + break; + } + return false; +} + +void CheckBoxWidget::OnLanguageChange() { text_.OnLanguageChange(); } + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/check_box_widget.h b/src/ballistica/ui/widget/check_box_widget.h new file mode 100644 index 00000000..581ff724 --- /dev/null +++ b/src/ballistica/ui/widget/check_box_widget.h @@ -0,0 +1,92 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_CHECK_BOX_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_CHECK_BOX_WIDGET_H_ + +#include + +#include "ballistica/graphics/renderer.h" +#include "ballistica/ui/widget/text_widget.h" + +namespace ballistica { + +// Check box interface widget. +class CheckBoxWidget : public Widget { + public: + CheckBoxWidget(); + ~CheckBoxWidget() override; + void Draw(RenderPass* pass, bool transparent) override; + void SetWidth(float widthIn); + void SetHeight(float heightIn); + auto GetWidth() -> float override { return width_; } + auto GetHeight() -> float override { return height_; } + void SetText(const std::string& text); + void SetValue(bool value); + void SetMaxWidth(float w) { text_.set_max_width(w); } + void SetTextScale(float val) { text_.set_center_scale(val); } + void set_text_color(float r, float g, float b, float a) { + text_color_r_ = r; + text_color_g_ = g; + text_color_b_ = b; + text_color_a_ = a; + } + void set_color(float r, float g, float b) { + color_r_ = r; + color_g_ = g; + color_b_ = b; + } + auto HandleMessage(const WidgetMessage& m) -> bool override; + void Activate() override; + auto IsSelectable() -> bool override { return true; } + auto GetWidgetTypeName() -> std::string override { return "checkbox"; } + void SetOnValueChangeCall(PyObject* call_tuple); + void SetIsRadioButton(bool enabled) { is_radio_button_ = enabled; } + void GetCenter(float* x, float* y) override; + void OnLanguageChange() override; + + private: + bool have_text_{true}; + float text_color_r_{0.75f}; + float text_color_g_{1.0f}; + float text_color_b_{0.7f}; + float text_color_a_{1.0f}; + float color_r_{0.4f}; + float color_g_{0.6f}; + float color_b_{0.2f}; + ImageMesh box_image_mesh_; + float check_width_{}; + float check_height_{}; + float check_center_x_{}; + float check_center_y_{}; + float box_width_{}; + float box_height_{}; + float box_center_x_{}; + float box_center_y_{}; + float highlight_width_{}; + float highlight_height_{}; + float highlight_center_x_{}; + float highlight_center_y_{}; + bool highlight_dirty_{true}; + bool box_dirty_{true}; + bool check_dirty_{true}; + bool click_select_{}; + bool mouse_over_{}; + bool checked_{true}; + bool have_drawn_{}; + millisecs_t last_change_time_{}; + float box_size_{20.0f}; + float box_padding_{6.0f}; + float width_{400.0f}; + float height_{24.0f}; + TextWidget text_; + std::string command_; + bool pressed_{}; + bool is_radio_button_{}; + + // Keep these at the bottom so they're torn down first. + Object::Ref on_value_change_call_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_WIDGET_CHECK_BOX_WIDGET_H_ diff --git a/src/ballistica/ui/widget/column_widget.cc b/src/ballistica/ui/widget/column_widget.cc new file mode 100644 index 00000000..43488a12 --- /dev/null +++ b/src/ballistica/ui/widget/column_widget.cc @@ -0,0 +1,61 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/column_widget.h" + +#include "ballistica/ui/ui.h" + +namespace ballistica { + +ColumnWidget::ColumnWidget() { + set_background(false); // Influences default event handling; ew. + set_claims_left_right(false); + set_claims_tab(false); + set_draggable(false); + set_selection_loops(false); +} + +ColumnWidget::~ColumnWidget() = default; + +auto ColumnWidget::HandleMessage(const WidgetMessage& m) -> bool { + switch (m.type) { + case WidgetMessage::Type::kShow: { + // Told to show something.. send this along to our parent (we can't do + // anything). + Widget* w = parent_widget(); + if (w) { + w->HandleMessage(m); + } + return true; + } + default: + break; + } + return ContainerWidget::HandleMessage(m); +} + +void ColumnWidget::UpdateLayout() { + BA_DEBUG_UI_READ_LOCK; + + float total_height{2.0f * margin_}; + for (const auto& i : widgets()) { + float wh = (*i).GetHeight() * (*i).scale(); + total_height += 2.0f * border_ + wh + top_border_ + bottom_border_; + } + float b{total_height - margin_}; + float l{border_ + left_border_ + margin_}; + for (auto&& i : widgets()) { + float w_scale = (*i).scale(); + float wh = (*i).GetHeight() * w_scale; + b -= border_; + b -= top_border_; + b -= wh; + (*i).set_translate(l, b); + b -= bottom_border_; + b -= border_; + } + if (height() != total_height) { + set_height(total_height); + } +} + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/column_widget.h b/src/ballistica/ui/widget/column_widget.h new file mode 100644 index 00000000..91d2e432 --- /dev/null +++ b/src/ballistica/ui/widget/column_widget.h @@ -0,0 +1,42 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_COLUMN_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_COLUMN_WIDGET_H_ + +#include + +#include "ballistica/ui/widget/container_widget.h" + +namespace ballistica { + +// Widget that arranges its children in a column. +class ColumnWidget : public ContainerWidget { + public: + ColumnWidget(); + ~ColumnWidget() override; + auto HandleMessage(const WidgetMessage& m) -> bool override; + auto GetWidgetTypeName() -> std::string override { return "column"; } + + auto set_left_border(float val) { left_border_ = val; } + auto left_border() const { return left_border_; } + auto set_top_border(float val) { top_border_ = val; } + auto top_border() const { return top_border_; } + auto set_bottom_border(float val) { bottom_border_ = val; } + auto bottom_border() const { return bottom_border_; } + auto set_border(float val) { border_ = val; } + auto border() const { return border_; } + auto set_margin(float val) { margin_ = val; } + auto margin() const { return margin_; } + + protected: + void UpdateLayout() override; + float border_{}; + float margin_{10.0f}; + float left_border_{}; + float top_border_{}; + float bottom_border_{}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_WIDGET_COLUMN_WIDGET_H_ diff --git a/src/ballistica/ui/widget/container_widget.cc b/src/ballistica/ui/widget/container_widget.cc new file mode 100644 index 00000000..bf1ba4c7 --- /dev/null +++ b/src/ballistica/ui/widget/container_widget.cc @@ -0,0 +1,1965 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/container_widget.h" + +#include + +#include "ballistica/audio/audio.h" +#include "ballistica/game/game.h" +#include "ballistica/graphics/component/empty_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/input/input.h" +#include "ballistica/python/python.h" +#include "ballistica/python/python_context_call.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/button_widget.h" +#include "ballistica/ui/widget/root_widget.h" +#include "ballistica/ui/widget/stack_widget.h" +#include "ballistica/ui/widget/text_widget.h" + +namespace ballistica { + +// Set this to -100 or so to make sure culling is active +// (things should visibly pop in & out of existence in that case). +#define SIMPLE_CULLING_V_OFFSET 0 +#define SIMPLE_CULLING_H_OFFSET 0 + +#define AUTO_SELECT_SLOPE_CLAMP 4.0f +#define AUTO_SELECT_MIN_SLOPE 0.1f +#define AUTO_SELECT_SLOPE_OFFSET 1.0f +#define AUTO_SELECT_SLOPE_WEIGHT 0.5f + +#define TRANSITION_DURATION 120 + +ContainerWidget::ContainerWidget(float width_in, float height_in) + : width_(width_in), + height_(height_in), + dynamics_update_time_(g_game->master_time()) {} + +ContainerWidget::~ContainerWidget() { + BA_DEBUG_UI_READ_LOCK; + // Wipe out our children. + widgets_.clear(); +} + +void ContainerWidget::SetOnActivateCall(PyObject* c) { + on_activate_call_ = Object::New(c); +} + +void ContainerWidget::SetOnOutsideClickCall(PyObject* c) { + on_outside_click_call_ = Object::New(c); +} + +void ContainerWidget::DrawChildren(RenderPass* pass, bool draw_transparent, + float x_offset, float y_offset, + float scale) { + BA_DEBUG_UI_READ_LOCK; + + // We're expected to fill z space 0..1 when we draw... so we need to divide + // that space between our child widgets plus our bg layer. + float layer_thickness = 0.0f; + float layer_spacing = 0.0f; + float base_offset = 0.0f; + float layer_thickness1 = 0.0f; + float layer_thickness2 = 0.0f; + float layer_thickness3 = 0.0f; + float layer_spacing1 = 0.0f; + float layer_spacing2 = 0.0f; + float layer_spacing3 = 0.0f; + float base_offset1 = 0.0f; + float base_offset2 = 0.0f; + float base_offset3 = 0.0f; + + // In single-depth mode we draw all widgets at the same depth so they each get + // our full depth resolution. however they may overlap incorrectly. + if (background_) { + assert(!single_depth_root_); + if (single_depth_) { + // Reserve a sliver of 0.2 for our backing geometry. + layer_thickness = 0.8f; + base_offset = 0.2f; + layer_spacing = 0.0f; + } else { + layer_thickness = 1.0f / static_cast(widgets_.size() + 1); + layer_spacing = layer_thickness; + base_offset = layer_thickness; + } + } else { + if (single_depth_) { + // Single-depth-root is a special mode for our root container + // where the first child (the screen stack) gets most of the depth range, + // the last child (the overlay stack) gets a bit of the rest, and the + // remainder is shared between root widget children (toolbars, etc). + if (single_depth_root_) { + layer_thickness1 = 0.9f; + base_offset1 = 0.0f; + layer_spacing1 = 0.0f; + layer_thickness2 = 0.05f; + base_offset2 = 0.9f; + layer_spacing2 = 0.0f; + layer_thickness3 = 0.05f; + base_offset3 = 0.95f; + layer_spacing3 = 0.0f; + } else { + layer_thickness = 1.0f; + base_offset = 0.0f; + layer_spacing = 0.0f; + } + } else { + layer_thickness = 1.0f / (widgets_.size()); + layer_spacing = layer_thickness; + base_offset = 0; + } + } + + size_t w_count = widgets_.size(); + bool doing_culling_v = false; + bool doing_culling_h = false; + Widget* pw = parent_widget(); + float cull_top = 0.0f; + float cull_bottom = 0.0f; + float cull_left = 0.0f; + float cull_right = 0.0f; + float cull_offset_v = 0.0f; + float cull_offset_h = 0.0f; + + // FIXME: need to test/update this to support scaling. + if (pw && pw->simple_culling_v() >= 0.0f) { + doing_culling_v = true; + cull_top = pw->simple_culling_top() - ty(); + cull_bottom = pw->simple_culling_bottom() - ty(); + cull_offset_v = pw->simple_culling_v(); + } + if (pw && pw->simple_culling_h() >= 0.0f) { + doing_culling_h = true; + cull_right = pw->simple_culling_right() - tx(); + cull_left = pw->simple_culling_left() - tx(); + cull_offset_h = pw->simple_culling_h(); + } + + // In opaque mode, draw our child widgets immediately front-to-back to best + // make use of the z buffer. + if (draw_transparent) { + EmptyComponent c(pass); + c.SetTransparent(true); + + for (size_t i = 0; i < w_count; i++) { + if (single_depth_root_) { + if (i == 0) { + layer_thickness = layer_thickness1; + base_offset = base_offset1; + layer_spacing = layer_spacing1; + } else if (i == w_count - 1) { + layer_thickness = layer_thickness3; + base_offset = base_offset3; + layer_spacing = layer_spacing3; + } else { + layer_thickness = layer_thickness2; + base_offset = base_offset2; + layer_spacing = layer_spacing2; + } + } + + Widget& w(*widgets_[i]); + + if (!w.visible_in_container()) { + continue; + } + + float tx = w.tx(); + float ty = w.ty(); + float s = w.scale(); + + // Some bare-bones culling to keep large scroll areas responsive. + if (doing_culling_v) { + if ((y_offset + ty > cull_top + cull_offset_v + SIMPLE_CULLING_V_OFFSET) + || (y_offset + ty + s * w.GetHeight() + < cull_bottom - cull_offset_v - SIMPLE_CULLING_V_OFFSET)) { + continue; + } + } + if (doing_culling_h) { + if ((x_offset + tx + > cull_right + cull_offset_h + SIMPLE_CULLING_H_OFFSET) + || (x_offset + tx + s * w.GetWidth() + < cull_left - cull_offset_h - SIMPLE_CULLING_H_OFFSET)) { + continue; + } + } + c.PushTransform(); + float z_offs = base_offset + i * layer_spacing; + if (transition_scale_ != 1.0f) { + c.Translate(bg_center_x_, bg_center_y_, 0); + c.Scale(transition_scale_, transition_scale_, 1.0f); + c.Translate(-bg_center_x_, -bg_center_y_, 0); + } + + // Widgets can opt to use a subset of their allotted depth slice. + float d_min = w.depth_range_min(); + float d_max = w.depth_range_max(); + if (d_min != 0.0f || d_max != 1.0f) { + z_offs += layer_thickness * d_min; + layer_thickness *= (d_max - d_min); + } + c.Translate(x_offset + tx, y_offset + ty, z_offs); + c.Scale(s, s, layer_thickness); + c.Submit(); + w.Draw(pass, draw_transparent); + c.PopTransform(); + c.Submit(); + } + c.Submit(); + + } else { + EmptyComponent c(&(*pass)); + c.SetTransparent(false); + + for (int i = static_cast(w_count - 1); i >= 0; i--) { + if (single_depth_root_) { + if (i == 0) { + layer_thickness = layer_thickness1; + base_offset = base_offset1; + layer_spacing = layer_spacing1; + } else if (i == w_count - 1) { + layer_thickness = layer_thickness3; + base_offset = base_offset3; + layer_spacing = layer_spacing3; + } else { + layer_thickness = layer_thickness2; + base_offset = base_offset2; + layer_spacing = layer_spacing2; + } + } + + Widget& w(*widgets_[i]); + + if (!w.visible_in_container()) { + continue; + } + + float tx = w.tx(); + float ty = w.ty(); + float s = w.scale(); + + // Some bare-bones culling to keep large scroll areas responsive. + if (doing_culling_v) { + if ((y_offset + ty > cull_top + cull_offset_v + SIMPLE_CULLING_V_OFFSET) + || (y_offset + ty + s * w.GetHeight() + < cull_bottom - cull_offset_v - SIMPLE_CULLING_V_OFFSET)) { + continue; + } + } + if (doing_culling_h) { + if ((x_offset + tx + > cull_right + cull_offset_h + SIMPLE_CULLING_H_OFFSET) + || (x_offset + tx + s * w.GetWidth() + < cull_left - cull_offset_h - SIMPLE_CULLING_H_OFFSET)) { + continue; + } + } + + c.PushTransform(); + float z_offs = base_offset + static_cast(i) * layer_spacing; + if (transition_scale_ != 1.0f) { + c.Translate(bg_center_x_, bg_center_y_, 0); + c.Scale(transition_scale_, transition_scale_, 1.0f); + c.Translate(-bg_center_x_, -bg_center_y_, 0); + } + + // Widgets can opt to use a subset of their allotted depth slice. + float d_min = w.depth_range_min(); + float d_max = w.depth_range_max(); + if (d_min != 0.0f || d_max != 1.0f) { + z_offs += layer_thickness * d_min; + layer_thickness *= (d_max - d_min); + } + c.Translate(x_offset + tx, y_offset + ty, z_offs); + c.Scale(s, s, layer_thickness); + c.Submit(); + w.Draw(pass, draw_transparent); + c.PopTransform(); + c.Submit(); + } + c.Submit(); + } +} + +auto ContainerWidget::HandleMessage(const WidgetMessage& m) -> bool { + BA_DEBUG_UI_READ_LOCK; + + bool claimed = false; + if (ignore_input_) { + return claimed; + } + + switch (m.type) { + case WidgetMessage::Type::kTextInput: + case WidgetMessage::Type::kKey: + if (selected_widget_) { + bool val = selected_widget_->HandleMessage(m); + if (val != 0) { + return true; + } + } + break; + + // Ewww we dont want subclasses to do this + // but we need to ourself for standalone containers + // ...reaaaly need to make ba.container() a subclass. + case WidgetMessage::Type::kShow: { + // Told to show something.. send this along to our parent (we can't do + // anything). + Widget* w = parent_widget(); + if (w) { + w->HandleMessage(m); + } + return true; + break; + } + + case WidgetMessage::Type::kStart: { + if (selected_widget_) { + if (selected_widget_->HandleMessage(m)) { + claimed = true; + } + } + if (!claimed && start_button_.exists()) { + claimed = true; + start_button_->Activate(); + } + break; + } + + case WidgetMessage::Type::kCancel: { + if (selected_widget_) { + if (selected_widget_->HandleMessage(m)) { + claimed = true; + } + } + if (!claimed) { + if (cancel_button_.exists()) { + claimed = true; + cancel_button_->Activate(); + } else if (on_cancel_call_.exists()) { + claimed = true; + + // Call this in the next cycle (don't wanna risk mucking with UI from + // within a UI loop). + g_game->PushPythonWeakCall( + Object::WeakRef(on_cancel_call_)); + } else { + OnCancelCustom(); + } + } + break; + } + + case WidgetMessage::Type::kTabNext: + case WidgetMessage::Type::kMoveRight: + case WidgetMessage::Type::kMoveDown: { + if (m.type == WidgetMessage::Type::kTabNext && !claims_tab_) { + break; + } + if (m.type == WidgetMessage::Type::kMoveRight && !claims_left_right_) { + break; + } + if (m.type == WidgetMessage::Type::kMoveDown && !claims_up_down_) { + break; + } + if (selected_widget_) { + if (selected_widget_->HandleMessage(m)) { + claimed = true; + } + } + if (!claimed) { + if (!root_selectable_) { + if (m.type == WidgetMessage::Type::kMoveDown) { + SelectDownWidget(); + } else if (m.type == WidgetMessage::Type::kMoveRight) { + SelectRightWidget(); + } else { + SelectNextWidget(); + } + if (IsHierarchySelected()) { + ShowWidget(selected_widget()); + } + claimed = true; + } + } + break; + } + + case WidgetMessage::Type::kTabPrev: + case WidgetMessage::Type::kMoveLeft: + case WidgetMessage::Type::kMoveUp: { + if (m.type == WidgetMessage::Type::kTabPrev && !claims_tab_) { + break; + } + if (m.type == WidgetMessage::Type::kMoveLeft && !claims_left_right_) { + break; + } + if (m.type == WidgetMessage::Type::kMoveUp && !claims_up_down_) { + break; + } + if (selected_widget_) { + if (selected_widget_->HandleMessage(m)) { + claimed = true; + } + } + if (!claimed) { + if (!root_selectable_) { + if (m.type == WidgetMessage::Type::kMoveUp) { + SelectUpWidget(); + } else if (m.type == WidgetMessage::Type::kMoveLeft) { + SelectLeftWidget(); + } else { + SelectPrevWidget(); + } + if (IsHierarchySelected()) { + ShowWidget(selected_widget()); + } + claimed = true; + } + } + break; + } + + case WidgetMessage::Type::kActivate: { + if (root_selectable_) { + Activate(); + claimed = true; + } else { + if (selected_widget_) { + if (selected_widget_->HandleMessage(m)) { + claimed = true; + } + } + if (!claimed) { + if (selected_widget_) { + selected_widget_->Activate(); + } + claimed = true; + } + } + break; + } + + case WidgetMessage::Type::kMouseMove: { + CheckLayout(); + + // Ignore mouse stuff while transitioning out. + if (transitioning_ && transitioning_out_) break; + + float x = m.fval1; + float y = m.fval2; + float l = 0.0f; + float r = width_; + float b = 0.0f; + float t = height_; + + // If we're dragging, the drag claims all attention. + if (dragging_) { + bg_dirty_ = glow_dirty_ = true; + set_translate(tx() + (x - drag_x_) * scale(), + ty() + (y - drag_y_) * scale()); + break; + } + + if (!root_selectable_) { + // Go through all widgets backwards until one claims the cursor position + // (we still send it to other widgets even then though in case they + // case). + for (auto i = widgets_.rbegin(); i != widgets_.rend(); i++) { + float cx = x; + float cy = y; + TransformPointToChild(&cx, &cy, **i); + if ((**i).HandleMessage( + WidgetMessage(m.type, nullptr, cx, cy, claimed))) { + claimed = true; + } + if (modal_children_) { + break; + } + } + } + + // If its not yet claimed, see if its within our contained region, in + // which case we claim it (only for regular taps). + if (!claimed) { + if (background_ || root_selectable_) { + if (x >= l && x < r && y >= b && y < t) { + claimed = true; + mouse_over_ = true; + } else { + mouse_over_ = false; + } + } + } else { + mouse_over_ = false; + } + break; + } + + case WidgetMessage::Type::kMouseWheel: + case WidgetMessage::Type::kMouseWheelH: + case WidgetMessage::Type::kMouseWheelVelocity: + case WidgetMessage::Type::kMouseWheelVelocityH: { + CheckLayout(); + + // Ignore mouse stuff while transitioning. + if (transitioning_ && transitioning_out_) break; + + float x = m.fval1; + float y = m.fval2; + float amount = m.fval3; + float momentum = m.fval4; + + float l = 0; + float r = width_; + float b = 0; + float t = height_; + + // Go through all widgets backwards until one claims the wheel. + for (auto i = widgets_.rbegin(); i != widgets_.rend(); i++) { + float cx = x; + float cy = y; + TransformPointToChild(&cx, &cy, ((**i))); + if ((**i).HandleMessage( + WidgetMessage(m.type, nullptr, cx, cy, amount, momentum))) { + claimed = true; + break; + } + if (modal_children_) break; + } + + // If its not yet claimed, see if its within our contained region, in + // which case we claim it but do nothing. + if (!claimed) { + if (background_) { + if (x >= l && x < r && y >= b && y < t) { + claimed = true; + } + } + } + break; + } + case WidgetMessage::Type::kScrollMouseDown: + case WidgetMessage::Type::kMouseDown: { + CheckLayout(); + + // Ignore mouse stuff while transitioning. + if (transitioning_ && transitioning_out_) break; + + float x = m.fval1; + float y = m.fval2; + auto click_count = static_cast(m.fval3); + + float l = 0; + float r = width_; + float b = 0; + float t = height_; + + if (!root_selectable_) { + // Go through all widgets backwards until one claims the click. + for (auto i = widgets_.rbegin(); i != widgets_.rend(); i++) { + float cx = x; + float cy = y; + TransformPointToChild(&cx, &cy, **i); + if ((**i).HandleMessage( + WidgetMessage(m.type, nullptr, cx, cy, click_count))) { + claimed = true; + break; + } + if (modal_children_) { + claimed = true; + break; + } + } + } + + // If its not yet claimed, see if its within our contained region, in + // which case we claim it (only for regular mouse-downs). + if (!claimed && m.type == WidgetMessage::Type::kMouseDown) { + float bottom_overlap = 2; + float top_overlap = 2; + + if (background_ || root_selectable_) { + if (x >= l && x < r && y >= b - bottom_overlap + && y < t + top_overlap) { + claimed = true; + mouse_over_ = true; + + if (root_selectable_) { + GlobalSelect(); + + pressed_ = true; + + pressed_activate_ = click_count == 2 || click_activate_; + + // First click just selects. + if (click_count == 1) { + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + } + } else { + // Special case: If we've got a child text widget that's + // selected, clicking on our background de-selects it. This is a + // common way of getting rid of a screen keyboard on ios, etc. + if (dynamic_cast(selected_widget_) != nullptr) { + SelectWidget(nullptr); + } + + if (draggable_) { + dragging_ = true; + drag_x_ = x; + drag_y_ = y; + } + } + } + } + + // Call our outside-click callback if unclaimed. + if (!claimed && on_outside_click_call_.exists()) { + // Call this in the next cycle (don't wanna risk mucking with UI from + // within a UI loop). + g_game->PushPythonWeakCall( + Object::WeakRef(on_outside_click_call_)); + } + + // Always claim if they want. + if (claims_outside_clicks_) { + claimed = true; + } + } + break; + } + case WidgetMessage::Type::kMouseUp: { + CheckLayout(); + dragging_ = false; + float x = m.fval1; + float y = m.fval2; + claimed = (m.fval3 > 0.0f); + float l = 0; + float r = width_; + float b = 0; + float t = height_; + if (!root_selectable_) { + // Go through all widgets backwards until one claims the click. + // We then send it to everyone else too; just marking it as claimed. + // (this helps prevent widgets getting 'stuck' because someone else + // claimed their mouse-up). + for (auto i = widgets_.rbegin(); i != widgets_.rend(); i++) { + float cx = x; + float cy = y; + TransformPointToChild(&cx, &cy, ((**i))); + if ((**i).HandleMessage( + WidgetMessage(m.type, nullptr, cx, cy, claimed))) { + claimed = true; + } + if (modal_children_) { + break; + } + } + } + float bottom_overlap = 2; + float top_overlap = 2; + + // When pressed, we *always* claim mouse-ups. + if (pressed_) { + pressed_ = false; + + // If we're pressed, mouse-ups within our region trigger activation. + if (pressed_activate_ && !claimed && x >= l && x < r + && y >= b - bottom_overlap && y < t + top_overlap) { + Activate(); + pressed_activate_ = false; + } + return true; + } + // If its not yet claimed, see if its within our contained region, in + // which case we claim it but do nothing. + if (!claimed) { + if (background_) + if (x >= l && x < r && y >= b - bottom_overlap && y < t + top_overlap) + claimed = true; + } + break; + } + default: + break; + } + return claimed; +} + +auto ContainerWidget::GetMult(millisecs_t current_time, bool for_glow) const + -> float { + if (root_selectable_ && selected()) { + float m; + + // Only pulsate if regular widget highlighting is on and we're selected. + if (g_ui->ShouldHighlightWidgets()) { + if (IsHierarchySelected()) { + m = 0.5f + + std::abs(sinf(static_cast(current_time) * 0.006467f) + * 0.4f); + } else { + m = 0.7f; + } + } else { + m = 0.7f; + } + + // Extra brightness for draw dependents. + float m2 = 1.0f; + + // Current or recent presses jack things up. + if ((mouse_over_ && pressed_) + || (current_time - last_activate_time_ < 200)) { + m *= 1.7f; + m2 *= 1.1f; + } else if (g_ui->ShouldHighlightWidgets()) { + // Otherwise if we're supposed to always highlight all widgets, pulsate + // when directly selected and glow softly when indirectly. + if (IsHierarchySelected()) { + // Pulsate. + m = 0.5f + + std::abs(sinf(static_cast(current_time) * 0.006467f) + * 0.4f); + } else { + // Not directly selected; highlight only if we're always supposed to. + if (always_highlight_) { + m = 0.7f; + } else { + if (for_glow) + m = 0.0f; + else + m = 0.7f; + } + } + } else if (always_highlight_) { + // Otherwise if we're specifically set to always highlight, do so. + m *= 1.3f; + m2 *= 1.0f; + } else { + // Otherwise no glow. + // For glow we return 0 in this case. For other purposes 1. + if (for_glow) { + m = 0.0f; + } else { + m = 0.7f; + } + } + return (1.0f / 0.7f) * m * m2; // Anyone linked to us uses this. + } else { + return 1.0f; + } +} + +auto ContainerWidget::GetDrawBrightness(millisecs_t current_time) const + -> float { + return GetMult(current_time); +} + +void ContainerWidget::SetOnCancelCall(PyObject* call_tuple) { + on_cancel_call_ = Object::New(call_tuple); +} + +void ContainerWidget::SetRootSelectable(bool enable) { + root_selectable_ = enable; + + // If *we* are selectable, can't have selected children. + if (root_selectable_) { + SelectWidget(nullptr); + } +} + +void ContainerWidget::Draw(RenderPass* pass, bool draw_transparent) { + BA_DEBUG_UI_READ_LOCK; + + CheckLayout(); + millisecs_t net_time = pass->frame_def()->base_time(); + float offset_h = 0.0f; + + // If we're transitioning, update our offsets in the first (opaque) pass. + if (transitioning_) { + bg_dirty_ = true; + + if (!draw_transparent) { + if (transition_type_ == TRANSITION_IN_SCALE) { + if (net_time - dynamics_update_time_ > 1000) + dynamics_update_time_ = net_time - 1000; + while (net_time - dynamics_update_time_ > 5) { + dynamics_update_time_ += 5; + d_transition_scale_ += + std::min(0.2f, (1.0f - transition_scale_)) * 0.04f; + d_transition_scale_ *= 0.87f; + transition_scale_ += d_transition_scale_; + if (std::abs(transition_scale_ - 1.0f) < 0.001 + && std::abs(d_transition_scale_) < 0.0001f) { + transition_scale_ = 1.0f; + transitioning_ = false; + } + } + } else if (transition_type_ == TRANSITION_OUT_SCALE) { + if (net_time - dynamics_update_time_ > 1000) + dynamics_update_time_ = net_time - 1000; + while (net_time - dynamics_update_time_ > 5) { + dynamics_update_time_ += 5; + transition_scale_ -= 0.04f; + if (transition_scale_ <= 0.0f) { + transition_scale_ = 0.0f; + + // Probably not safe to delete ourself here since we're in + // the draw loop, but we can push a call to do it. + Object::WeakRef weakref(this); + g_game->PushCall([weakref] { + Widget* w = weakref.get(); + if (w) g_ui->DeleteWidget(w); + }); + return; + } + } + } else { + // Step our dynamics up to the present. + if (net_time - dynamics_update_time_ > 1000) + dynamics_update_time_ = net_time - 1000; + while (net_time - dynamics_update_time_ > 5) { + dynamics_update_time_ += 5; + + if (transitioning_) { + millisecs_t t = dynamics_update_time_; + if (t - transition_start_time_ < TRANSITION_DURATION) { + float amt = static_cast(t - transition_start_time_) + / TRANSITION_DURATION; + if (transitioning_out_) { + amt = pow(amt, 1.1f); + } else { + amt = 1.0f - pow(1.0f - amt, 1.1f); + } + transition_offset_x_ = transition_start_offset_ * (1.0f - amt) + + transition_target_offset_ * amt; + offset_h += transition_offset_x_; + } else { + // Transition is done when we come to a stop. + if (transitioning_out_) { + transition_offset_x_ = transition_target_offset_; + } else { + transition_offset_x_ = 0.0f; + } + + // If going out, we're done as soon. + bool done; + if (transitioning_out_) { + done = (std::abs(transition_offset_x_smoothed_ + - transition_offset_x_) + < 1000.0f); + } else { + done = ((std::abs(transition_offset_x_vel_) < 0.05f) + && (std::abs(transition_offset_y_vel_) < 0.05f) + && (std::abs(transition_offset_x_smoothed_) < 0.05f) + && (std::abs(transition_offset_y_smoothed_) < 0.05f)); + } + if (done) { + transitioning_ = false; + transition_offset_x_smoothed_ = 0.0f; + transition_offset_y_smoothed_ = 0.0f; + if (transitioning_out_) { + // Probably not safe to delete ourself here since we're in the + // draw loop, but we can set up an event to do it. + Object::WeakRef weakref(this); + g_game->PushCall([weakref] { + Widget* w = weakref.get(); + if (w) g_ui->DeleteWidget(w); + }); + return; + } + } + } + + // Update our springy smoothed values. + float diff = transition_offset_x_ - transition_offset_x_smoothed_; + if (transitioning_out_) { + transition_offset_x_vel_ += diff * 0.03f; + transition_offset_x_vel_ *= 0.5f; + } else { + transition_offset_x_vel_ += diff * 0.04f; + transition_offset_x_vel_ *= 0.805f; + } + transition_offset_x_smoothed_ += transition_offset_x_vel_; + diff = transition_offset_y_ - transition_offset_y_smoothed_; + transition_offset_y_vel_ += diff * 0.04f; + transition_offset_y_vel_ *= 0.98f; + transition_offset_y_smoothed_ += transition_offset_y_vel_; + } + } + } + + // If we're scaling in or out, update our transition offset + // (so we can zoom from a point somewhere else on screen). + if (transition_type_ == TRANSITION_IN_SCALE + || transition_type_ == TRANSITION_OUT_SCALE) { + // Add a fudge factor since our scale point isn't exactly in our center. + // :-( + float xdiff = scale_origin_stack_offset_x_ - stack_offset_x() + + GetWidth() * -0.05f; + float ydiff = scale_origin_stack_offset_y_ - stack_offset_y(); + transition_scale_offset_x_ = + ((1.0f - transition_scale_) * xdiff) / scale(); + transition_scale_offset_y_ = + ((1.0f - transition_scale_) * ydiff) / scale(); + } + } + } + + // Don't draw if we've fully transitioned out. + if (transitioning_out_ && !transitioning_) return; + + float l = transition_offset_x_smoothed_ + transition_scale_offset_x_; + float r = l + width_; + float b = transition_offset_y_smoothed_ + transition_scale_offset_y_; + float t = b + height_; + + float w = width_; + float h = height_; + + // Update bg vals if need be + // (we may need these even if bg is turned off so always calc them). + if (bg_dirty_) { + SystemTextureID tex_id; + float l_border, r_border, b_border, t_border; + float width = r - l; + float height = t - b; + if (height > width * 0.6f) { + tex_id = SystemTextureID::kWindowHSmallVMed; + bg_model_transparent_i_d_ = SystemModelID::kWindowHSmallVMedTransparent; + bg_model_opaque_i_d_ = SystemModelID::kWindowHSmallVMedOpaque; + l_border = width * 0.07f; + r_border = width * 0.19f; + b_border = height * 0.1f; + t_border = height * 0.07f; + } else { + tex_id = SystemTextureID::kWindowHSmallVSmall; + bg_model_transparent_i_d_ = SystemModelID::kWindowHSmallVSmallTransparent; + bg_model_opaque_i_d_ = SystemModelID::kWindowHSmallVSmallOpaque; + l_border = width * 0.12f; + r_border = width * 0.19f; + b_border = height * 0.45f; + t_border = height * 0.23f; + } + bg_width_ = r - l + l_border + r_border; + bg_height_ = t - b + b_border + t_border; + bg_center_x_ = l - l_border + bg_width_ * 0.5f; + bg_center_y_ = b - b_border + bg_height_ * 0.5f; + if (background_) { + tex_ = g_media->GetTexture(tex_id); + } + bg_dirty_ = false; + } + + // In opaque mode, draw our child widgets immediately front-to-back to best + // make use of the z buffer. + if (!draw_transparent) { + DrawChildren(pass, draw_transparent, l, b, transition_scale_); + } + + // Draw our window backing if we have one. + if ((w > 0) && (h > 0)) { + if (background_) { + SimpleComponent c(pass); + c.SetTransparent(draw_transparent); + float s = 1.0f; + if (transition_scale_ <= 0.9f && !transitioning_out_) { + float amt = transition_scale_ / 0.9f; + s = std::min((1.0f - amt) * 4.0f, 2.5f) + amt * 1.0f; + } + c.SetColor(red_ * s, green_ * s, blue_ * s, alpha_); + c.SetTexture(tex_.get()); + c.PushTransform(); + c.Translate(bg_center_x_, bg_center_y_); + c.Scale(bg_width_ * transition_scale_, bg_height_ * transition_scale_); + c.DrawModel(g_media->GetModel(draw_transparent ? bg_model_transparent_i_d_ + : bg_model_opaque_i_d_)); + c.PopTransform(); + c.Submit(); + } + } + + // Draw our widgets here back-to-front in transparent mode. + if (draw_transparent) { + DrawChildren(pass, draw_transparent, l, b, transition_scale_); + } + + // Draw overlay glow. + if (root_selectable_ && selected()) { + float m = GetMult(net_time, true); + if (draw_transparent) { + if (glow_dirty_) { + float l_border, r_border, b_border, t_border; + l_border = 18; + r_border = 10; + b_border = 18; + t_border = 18; + glow_width_ = r - l + l_border + r_border; + glow_height_ = t - b + b_border + t_border; + glow_center_x_ = l - l_border + glow_width_ * 0.5f; + glow_center_y_ = b - b_border + glow_height_ * 0.5f; + glow_dirty_ = false; + } + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.SetTexture(g_media->GetTexture(SystemTextureID::kGlow)); + c.SetColor(0.25f * m, 0.25f * m, 0, 0.3f * m); + c.PushTransform(); + c.Translate(glow_center_x_, glow_center_y_); + c.Scale(glow_width_, glow_height_); + c.DrawModel(g_media->GetModel(SystemModelID::kImage4x1)); + c.PopTransform(); + c.Submit(); + } + } +} + +void ContainerWidget::TransformPointToChild(float* x, float* y, + const Widget& child) const { + assert(child.parent_widget() == this); + if (child.scale() == 1.0f) { + (*x) -= child.tx(); + (*y) -= child.ty(); + } else { + (*x) -= child.tx(); + (*y) -= child.ty(); + (*x) /= child.scale(); + (*y) /= child.scale(); + } +} + +void ContainerWidget::TransformPointFromChild(float* x, float* y, + const Widget& child) const { + assert(child.parent_widget() == this); + if (child.scale() == 1.0f) { + (*x) += child.tx(); + (*y) += child.ty(); + } else { + (*x) *= child.scale(); + (*y) *= child.scale(); + (*x) += child.tx(); + (*y) += child.ty(); + } +} + +void ContainerWidget::Activate() { + last_activate_time_ = g_game->master_time(); + if (on_activate_call_.exists()) { + // Call this in the next cycle (don't wanna risk mucking with UI from within + // a UI loop). + g_game->PushPythonWeakCall( + Object::WeakRef(on_activate_call_)); + } +} + +void ContainerWidget::AddWidget(Widget* w) { + BA_PRECONDITION(InGameThread()); + Object::WeakRef weakthis(this); + { + BA_DEBUG_UI_WRITE_LOCK; + w->set_parent_widget(this); + widgets_.insert(widgets_.end(), Object::Ref(w)); + } + + // If we're not selectable ourself and our child is, select it. + if (!root_selectable_ + && ((selected_widget_ == nullptr) || is_window_stack_)) { + if (w->IsSelectable()) { + // A change on the main or overlay window stack changes the global + // selection (unless its on the main window stack and there's already + // something on the overlay stack) in all other cases we just shift our + // direct selected child (which may not affect the global selection). + if (is_window_stack_ + && (is_overlay_window_stack_ + || !g_ui->root_widget()->overlay_window_stack()->HasChildren())) { + w->GlobalSelect(); + + // Special case for the main window stack; whenever a window is added, + // update the toolbar state for the topmost living container. + if (is_main_window_stack_) { + g_ui->root_widget()->UpdateForFocusedWindow(); + } + } else { + SelectWidget(w); + } + } + } + + // Select actions we run above may trigger user code which may kill us. + if (!weakthis.exists()) { + return; + } + + MarkForUpdate(); +} + +auto ContainerWidget::IsAcceptingInput() const -> bool { + return (!ignore_input_); +} + +// Delete all widgets. +void ContainerWidget::Clear() { + BA_DEBUG_UI_WRITE_LOCK; + widgets_.clear(); + selected_widget_ = nullptr; + prev_selected_widget_ = nullptr; +} + +void ContainerWidget::SetCancelButton(ButtonWidget* button) { + assert(button); + + if (!button->is_color_set()) { + button->SetColor(0.7f, 0.4f, 0.34f); + button->set_text_color(0.9f, 0.9f, 1.0f, 1.0f); + } + cancel_button_ = button; + + // Don't give it a back icon if it has a custom assigned one.. + // FIXME: This should be dynamic. + if (button->icon() == nullptr) { + button->set_icon_type(ButtonWidget::IconType::kCancel); + } +} + +void ContainerWidget::SetStartButton(ButtonWidget* button) { + assert(button); + if (!button->is_color_set()) { + button->SetColor(0.2f, 0.8f, 0.55f); + } + start_button_ = button; + + button->set_icon_type(ButtonWidget::IconType::kStart); +} + +void ContainerWidget::SetTransition(TransitionType t) { + BA_DEBUG_UI_READ_LOCK; + + bg_dirty_ = glow_dirty_ = true; + ContainerWidget* parent = parent_widget(); + if (parent == nullptr) return; + parent->CheckLayout(); + millisecs_t net_time = g_game->master_time(); + transition_type_ = t; + + // Scale transitions are simpler. + if (t == TRANSITION_IN_SCALE) { + transition_start_time_ = net_time; + dynamics_update_time_ = net_time; + transitioning_ = true; + transitioning_out_ = false; + transition_scale_ = 0.0f; + d_transition_scale_ = 0.0f; + } else if (t == TRANSITION_OUT_SCALE) { + transition_start_time_ = net_time; + dynamics_update_time_ = net_time; + transitioning_ = true; + transitioning_out_ = true; + } else { + // Calculate the screen size in our own local space - we'll + // animate an offset to slide on/off screen. + float screen_min_x = 0.0f; + float screen_min_y = 0.0f; + float screen_max_x = g_graphics->screen_virtual_width(); + float screen_max_y = g_graphics->screen_virtual_height(); + ScreenPointToWidget(&screen_min_x, &screen_min_y); + ScreenPointToWidget(&screen_max_x, &screen_max_y); + + // In case we're mid-transition, this avoids hitches. + float y_offs = 2.0f; + if (t == TRANSITION_IN_LEFT) { + transition_start_time_ = net_time; + transition_start_offset_ = screen_min_x - width_ - 100; + transition_offset_x_smoothed_ = transition_start_offset_; + transition_offset_y_smoothed_ = (RandomFloat() > 0.5f) ? y_offs : -y_offs; + transition_target_offset_ = 0; + transitioning_ = true; + dynamics_update_time_ = net_time; + transitioning_out_ = false; + } else if (t == TRANSITION_IN_RIGHT) { + transition_start_time_ = net_time; + transition_start_offset_ = screen_max_x + 100; + transition_offset_x_smoothed_ = transition_start_offset_; + transition_offset_y_smoothed_ = (RandomFloat() > 0.5f) ? y_offs : -y_offs; + transition_target_offset_ = 0; + transitioning_ = true; + dynamics_update_time_ = net_time; + transitioning_out_ = false; + } else if (t == TRANSITION_OUT_LEFT) { + transition_start_time_ = net_time; + transition_start_offset_ = transition_offset_x_; + transition_target_offset_ = -2.0f * (screen_max_x - screen_min_x); + transition_offset_x_smoothed_ = transition_start_offset_; + transition_offset_y_smoothed_ = 0.0f; + transitioning_ = true; + dynamics_update_time_ = net_time; + transitioning_out_ = true; + ignore_input_ = true; + } else if (t == TRANSITION_OUT_RIGHT) { + transition_start_time_ = net_time; + transition_start_offset_ = transition_offset_x_; + transition_target_offset_ = 2.0f * (screen_max_x - screen_min_x); + transition_offset_x_smoothed_ = transition_start_offset_; + transition_offset_y_smoothed_ = 0.0f; + transitioning_ = true; + dynamics_update_time_ = net_time; + transitioning_out_ = true; + ignore_input_ = true; + } + } + + // If we're transitioning out in some way and our parent is the main window + // stack, update the toolbar for the new topmost input-accepting window + // *immediately* (otherwise we'd have to wait for our transition to complete + // before the toolbar switches). + if (transitioning_ && transitioning_out_ && parent != nullptr + && parent->is_main_window_stack_) { + g_ui->root_widget()->UpdateForFocusedWindow(); + } +} + +void ContainerWidget::ReselectLastSelectedWidget() { + if (prev_selected_widget_ != nullptr + && prev_selected_widget_ != selected_widget_) { + SelectWidget(prev_selected_widget_); + } +} + +// Remove the widget from our list which should kill it. +void ContainerWidget::DeleteWidget(Widget* w) { + bool found = false; + { + BA_DEBUG_UI_WRITE_LOCK; + // Hmmm couldn't we do this without having to iterate here? + // (at least in release build). + for (auto i = widgets_.begin(); i != widgets_.end(); i++) { + if (&(**i) == w) { + if (selected_widget_ == w) { + selected_widget_ = nullptr; + } + if (prev_selected_widget_ == w) { + prev_selected_widget_ = nullptr; + } + // Grab a ref until we clear it off the list to avoid funky recursion + // issues. + Object::Ref w2 = *i; + widgets_.erase(i); + found = true; + break; + } + } + } + + assert(found); + + // Special case: if we're the overlay stack and we've deleted our last widget, + // try to reselect whatever was last selected before the overlay stack. + if (is_overlay_window_stack_) { + if (widgets_.empty()) { + // Eww this logic should be in some sort of controller. + g_ui->root_widget()->ReselectLastSelectedWidget(); + return; + } + } + + // in some cases we want to auto select a new child widget + if (selected_widget_ == nullptr || is_window_stack_) { + BA_DEBUG_UI_READ_LOCK; + // no UI lock needed here.. we don't change anything until SelectWidget, + // at which point we exit the loop.. + for (auto i = widgets_.rbegin(); i != widgets_.rend(); i++) { + if ((**i).IsSelectable()) { + // A change on the main or overlay window stack changes the global + // selection (unless its on the main window stack and there's already + // something on the overlay stack) in all other cases we just shift our + // direct selected child (which may not affect the global selection). + if (is_window_stack_ + && (is_overlay_window_stack_ + || !g_ui->root_widget() + ->overlay_window_stack() + ->HasChildren())) { + (**i).GlobalSelect(); + } else { + SelectWidget(&(**i)); + } + break; + } + } + } + + // Special case: if we're the main window stack, + // update the active toolbar/etc. + if (is_main_window_stack_) { + g_ui->root_widget()->UpdateForFocusedWindow(); + } +} + +auto ContainerWidget::GetTopmostToolbarInfluencingWidget() -> Widget* { + // Look for the first window that is accepting input (filters out windows that + // are transitioning out) and also set to affect the toolbar state. + for (auto w = widgets_.rbegin(); w != widgets_.rend(); ++w) { + if ((**w).IsAcceptingInput() + && (**w).toolbar_visibility() != ToolbarVisibility::kInherit) { + return &(**w); + } + } + return nullptr; +} + +void ContainerWidget::ShowWidget(Widget* w) { + if (!w) { + return; + } + + // Hacky exception; scroll-widgets don't respond directly to this + // (it always arrives via a child's child.. need to clean this up) + // it causes double-shows to happen otherwise and odd jumpy behavior. + if (GetWidgetTypeName() == "scroll") { + return; + } + + CheckLayout(); + float s = scale(); + float buffer_top = w->show_buffer_top(); + float buffer_bottom = w->show_buffer_bottom(); + float buffer_right = w->show_buffer_right(); + float buffer_left = w->show_buffer_left(); + float tx = (w->tx() - buffer_left) * s; + float ty = (w->ty() - buffer_bottom) * s; + float width = (w->GetWidth() + buffer_left + buffer_right) * s; + float height = (w->GetHeight() + buffer_bottom + buffer_top) * s; + HandleMessage(WidgetMessage(WidgetMessage::Type::kShow, nullptr, tx, ty, + width, height)); +} + +void ContainerWidget::SelectWidget(Widget* w, SelectionCause c) { + BA_DEBUG_UI_READ_LOCK; + + if (w == nullptr) { + if (selected_widget_) { + prev_selected_widget_ = selected_widget_; + selected_widget_->SetSelected(false, SelectionCause::NONE); + selected_widget_ = nullptr; + } + } else { + if (root_selectable_) { + Log("Error: SelectWidget() called on a ContainerWidget which is itself " + "selectable. Ignoring."); + return; + } + for (auto& widget : widgets_) { + if (&(*widget) == w) { + Widget* prevSelectedWidget = selected_widget_; + + // Deactivate old selected widget. + if (selected_widget_) { + selected_widget_->SetSelected(false, SelectionCause::NONE); + selected_widget_ = nullptr; + } + if ((*widget).IsSelectable()) { + (*widget).SetSelected(true, c); + selected_widget_ = &(*widget); + + // Store the old one as prev-selected if its not the one we're + // selecting now. (otherwise re-selecting repeatedly kills our prev + // mechanism). + if (prevSelectedWidget != selected_widget_) { + prev_selected_widget_ = prevSelectedWidget; + } + } else { + static bool printed = false; + if (!printed) { + Log("Warning: SelectWidget called on unselectable widget: " + + w->GetWidgetTypeName()); + Python::PrintStackTrace(); + printed = true; + } + } + break; + } + } + } +} + +void ContainerWidget::SetSelected(bool s, SelectionCause cause) { + BA_DEBUG_UI_READ_LOCK; + + Widget::SetSelected(s, cause); + + // If we've got selection-looping-to-parent enabled, being selected via + // next/prev snaps our sub-selection to our first or last widget. + if (s) { + if (selection_loops_to_parent()) { + if (cause == SelectionCause::NEXT_SELECTED) { + for (auto& widget : widgets_) { + if ((*widget).IsSelectable()) { + ShowWidget(&(*widget)); + SelectWidget(&(*widget), cause); + break; + } + } + } else if (cause == SelectionCause::PREV_SELECTED) { + for (auto i = widgets_.rbegin(); i != widgets_.rend(); i++) { + if ((**i).IsSelectable()) { + ShowWidget(&(**i)); + SelectWidget(&(**i), cause); + break; + } + } + } + } + } else { + // if we're being deselected and we have a selected child, tell them they're + // deselected + // if (selected_widget_) { + // } + } +} + +auto ContainerWidget::GetClosestLeftWidget(float our_x, float our_y, + Widget* ignore_widget) -> Widget* { + Widget* w = nullptr; + float x, y; + float closest_val = 9999.0f; + for (auto i = widgets_.begin(); i != widgets_.end(); i++) { + assert(i->exists()); + (**i).GetCenter(&x, &y); + float slope = std::abs(x - our_x) / (std::max(0.001f, std::abs(y - our_y))); + slope = std::min( + slope, AUTO_SELECT_SLOPE_CLAMP); // Beyond this, just go by distance. + float slope_weighted = AUTO_SELECT_SLOPE_WEIGHT * slope + + (1.0f - AUTO_SELECT_SLOPE_WEIGHT) * 1.0f; + if (i->get() != ignore_widget && x < our_x && slope > AUTO_SELECT_MIN_SLOPE + && (**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + // Take distance diff and multiply by our slope. + float xdist = x - our_x; + float ydist = y - our_y; + float dist = sqrtf(xdist * xdist + ydist * ydist); + float val = + dist / std::max(0.001f, slope_weighted + AUTO_SELECT_SLOPE_OFFSET); + if (val < closest_val || w == nullptr) { + closest_val = val; + w = i->get(); + } + } + } + return w; +} + +auto ContainerWidget::GetClosestRightWidget(float our_x, float our_y, + Widget* ignore_widget) -> Widget* { + Widget* w = nullptr; + float x, y; + float closest_val = 9999.0f; + for (auto i = widgets_.begin(); i != widgets_.end(); i++) { + assert(i->exists()); + (**i).GetCenter(&x, &y); + float slope = std::abs(x - our_x) / (std::max(0.001f, std::abs(y - our_y))); + slope = std::min( + slope, AUTO_SELECT_SLOPE_CLAMP); // beyond this, just go by distance + float slopeWeighted = AUTO_SELECT_SLOPE_WEIGHT * slope + + (1.0f - AUTO_SELECT_SLOPE_WEIGHT) * 1.0f; + if (i->get() != ignore_widget && x > our_x && slope > AUTO_SELECT_MIN_SLOPE + && (**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + // Take distance diff and multiply by our slope. + float xDist = x - our_x; + float yDist = y - our_y; + float dist = sqrtf(xDist * xDist + yDist * yDist); + float val = + dist / std::max(0.001f, slopeWeighted + AUTO_SELECT_SLOPE_OFFSET); + if (val < closest_val || w == nullptr) { + closest_val = val; + w = i->get(); + } + } + } + return w; +} + +auto ContainerWidget::GetClosestUpWidget(float our_x, float our_y, + Widget* ignoreWidget) -> Widget* { + Widget* w = nullptr; + float x, y; + float closest_val = 9999.0f; + for (auto i = widgets_.begin(); i != widgets_.end(); i++) { + assert(i->exists()); + (**i).GetCenter(&x, &y); + float slope = std::abs(y - our_y) / (std::max(0.001f, std::abs(x - our_x))); + slope = std::min( + slope, AUTO_SELECT_SLOPE_CLAMP); // Beyond this, just go by distance. + float slopeWeighted = AUTO_SELECT_SLOPE_WEIGHT * slope + + (1.0f - AUTO_SELECT_SLOPE_WEIGHT) * 1.0f; + if (i->get() != ignoreWidget && y > our_y && slope > AUTO_SELECT_MIN_SLOPE + && (**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + // Take distance diff and multiply by our slope. + float xDist = x - our_x; + float yDist = y - our_y; + float dist = sqrtf(xDist * xDist + yDist * yDist); + float val = + dist / std::max(0.001f, slopeWeighted + AUTO_SELECT_SLOPE_OFFSET); + if (val < closest_val || w == nullptr) { + closest_val = val; + w = i->get(); + } + } + } + return w; +} + +auto ContainerWidget::GetClosestDownWidget(float our_x, float our_y, + Widget* ignoreWidget) -> Widget* { + Widget* w = nullptr; + float x, y; + float closest_val = 9999.0f; + for (auto i = widgets_.begin(); i != widgets_.end(); i++) { + assert(i->exists()); + (**i).GetCenter(&x, &y); + float slope = std::abs(y - our_y) / (std::max(0.001f, std::abs(x - our_x))); + slope = std::min( + slope, AUTO_SELECT_SLOPE_CLAMP); // Beyond this, just go by distance. + float slopeWeighted = AUTO_SELECT_SLOPE_WEIGHT * slope + + (1.0f - AUTO_SELECT_SLOPE_WEIGHT) * 1.0f; + if (i->get() != ignoreWidget && y < our_y && slope > AUTO_SELECT_MIN_SLOPE + && (**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + // Take distance diff and multiply by our slope. + float xDist = x - our_x; + float yDist = y - our_y; + float dist = sqrtf(xDist * xDist + yDist * yDist); + float val = + dist / std::max(0.001f, slopeWeighted + AUTO_SELECT_SLOPE_OFFSET); + if (val < closest_val || w == nullptr) { + closest_val = val; + w = i->get(); + } + } + } + return w; +} + +void ContainerWidget::SelectDownWidget() { + BA_DEBUG_UI_READ_LOCK; + + if (!g_ui || !g_ui->root_widget() || !g_ui->screen_root_widget()) { + BA_LOG_ONCE("SelectDownWidget called before UI init."); + return; + } + + // If the current widget has an explicit down-widget set, go to it. + if (selected_widget_) { + Widget* w = selected_widget_->down_widget(); + + // If its auto-select, find our closest child widget. + if (!w && selected_widget_->auto_select()) { + float our_x, our_y; + selected_widget_->GetCenter(&our_x, &our_y); + w = GetClosestDownWidget(our_x, our_y, selected_widget_); + if (!w) { + // If we found no viable children and we're under the main window stack, + // see if we should pass focus to a toolbar widget. + if (IsInMainStack()) { + float x = our_x; + float y = our_y; + WidgetPointToScreen(&x, &y); + g_ui->root_widget()->ScreenPointToWidget(&x, &y); + w = g_ui->root_widget()->GetClosestDownWidget( + x, y, g_ui->screen_root_widget()); + } + // When we find no viable targets for an autoselect widget we do + // nothing. + if (!w) { + return; + } + } + } + if (w) { + if (!w->IsSelectable()) { + Log("Error: Down_widget is not selectable."); + } else { + w->Show(); + // Avoid tap sounds and whatnot if we're just re-selecting ourself. + if (w != selected_widget_) { + w->GlobalSelect(); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + } + } + } else { + // Have a selected widget but no specific 'down' widget; revert to just + // doing 'next'. + SelectNextWidget(); + } + } else { + // If nothing is selected, either do a select-next if we have + // something selectable or call our parent's select-down otherwise. + if (HasKeySelectableChild()) { + SelectNextWidget(); + } else { + if (ContainerWidget* parent = parent_widget()) { + parent->SelectDownWidget(); + } + } + } +} + +void ContainerWidget::SelectUpWidget() { + BA_DEBUG_UI_READ_LOCK; + + if (!g_ui || !g_ui->root_widget() || !g_ui->screen_root_widget()) { + BA_LOG_ONCE("SelectUpWidget called before UI init."); + return; + } + + // If the current widget has an explicit up-widget set, go to it. + if (selected_widget_) { + Widget* w = selected_widget_->up_widget(); + + // If its auto-select, find the closest widget. + if (!w && selected_widget_->auto_select()) { + float our_x, our_y; + selected_widget_->GetCenter(&our_x, &our_y); + w = GetClosestUpWidget(our_x, our_y, selected_widget_); + if (!w) { + // If we found no viable children and we're on the main window stack, + // see if we should pass focus to a toolbar widget. + if (IsInMainStack()) { + float x = our_x; + float y = our_y; + WidgetPointToScreen(&x, &y); + g_ui->root_widget()->ScreenPointToWidget(&x, &y); + w = g_ui->root_widget()->GetClosestUpWidget( + x, y, g_ui->screen_root_widget()); + } + // When we find no viable targets for an autoselect widget we do + // nothing. + if (!w) { + return; + } + } + } + if (w) { + if (!w->IsSelectable()) { + Log("Error: up_widget is not selectable."); + } else { + w->Show(); + // Avoid tap sounds and whatnot if we're just re-selecting ourself. + if (w != selected_widget_) { + w->GlobalSelect(); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + } + } + } else { + // Have a selected widget but no specific 'up' widget; revert to just + // doing prev. + SelectPrevWidget(); + } + } else { + // If nothing is selected, either do a select-prev if we have + // something selectable or call our parent's select-up otherwise. + if (HasKeySelectableChild()) { + SelectPrevWidget(); + } else { + if (ContainerWidget* parent = parent_widget()) { + parent->SelectUpWidget(); + } + } + } +} + +void ContainerWidget::SelectLeftWidget() { + BA_DEBUG_UI_READ_LOCK; + + if (!g_ui || !g_ui->root_widget() || !g_ui->screen_root_widget()) { + BA_LOG_ONCE("SelectLeftWidget called before UI init."); + return; + } + + // If the current widget has an explicit left-widget set, go to it. + if (selected_widget_) { + Widget* w = selected_widget_->left_widget(); + + // If its auto-select, find the closest widget. + if (!w && selected_widget_->auto_select()) { + float our_x, our_y; + selected_widget_->GetCenter(&our_x, &our_y); + w = GetClosestLeftWidget(our_x, our_y, selected_widget_); + // When we find no viable targets for an autoselect widget we do nothing. + if (!w) { + return; + } + } + if (w) { + if (!w->IsSelectable()) { + Log("Error: left_widget is not selectable."); + } else { + w->Show(); + // Avoid tap sounds and whatnot if we're just re-selecting ourself. + if (w != selected_widget_) { + w->GlobalSelect(); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + } + } + } else { + // Have a selected widget but no specific 'left' widget; revert to just + // doing prev. + SelectPrevWidget(); + } + } else { + // If nothing is selected, either do a select-prev if we have + // something selectable or call our parent's select-left otherwise. + if (HasKeySelectableChild()) { + SelectPrevWidget(); + } else { + if (ContainerWidget* parent = parent_widget()) { + parent->SelectLeftWidget(); + } + } + } +} +void ContainerWidget::SelectRightWidget() { + BA_DEBUG_UI_READ_LOCK; + + if (!g_ui || !g_ui->root_widget() || !g_ui->screen_root_widget()) { + BA_LOG_ONCE("SelectRightWidget called before UI init."); + return; + } + + // If the current widget has an explicit right-widget set, go to it. + if (selected_widget_) { + Widget* w = selected_widget_->right_widget(); + + // If its auto-select, find the closest widget. + if (!w && selected_widget_->auto_select()) { + float our_x, our_y; + selected_widget_->GetCenter(&our_x, &our_y); + w = GetClosestRightWidget(our_x, our_y, selected_widget_); + + // For autoselect widgets, if we find no viable targets, we do nothing. + if (!w) { + return; + } + } + if (w) { + if (!w->IsSelectable()) { + Log("Error: right_widget is not selectable."); + } else { + w->Show(); + // Avoid tap sounds and whatnot if we're just re-selecting ourself. + if (w != selected_widget_) { + w->GlobalSelect(); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + } + } + } else { + // Have a selected widget but no specific 'right' widget; revert to just + // doing next. + SelectNextWidget(); + } + } else { + // If nothing is selected, either do a select-next if we have + // something selectable or call our parent's select-right otherwise. + if (HasKeySelectableChild()) { + SelectNextWidget(); + } else { + if (ContainerWidget* parent = parent_widget()) { + parent->SelectRightWidget(); + } + } + } +} + +void ContainerWidget::SelectNextWidget() { + BA_DEBUG_UI_READ_LOCK; + + if (!g_ui || !g_ui->root_widget() || !g_ui->screen_root_widget()) { + BA_LOG_ONCE("SelectNextWidget called before UI init."); + return; + } + + millisecs_t old_last_prev_next_time = last_prev_next_time_; + if (should_print_list_exit_instructions_) { + last_prev_next_time_ = g_game->master_time(); + } + + // Grab the iterator for our selected widget if possible. + auto i = widgets_.begin(); + if (selected_widget_) { + for (; i != widgets_.end(); i++) { + if ((&(**i) == selected_widget_)) { + break; + } + } + } + + if (selected_widget_) { + // If we have a selection we should have been able to find its iterator. + assert((&(**i) == selected_widget_)); + i++; + } + + while (true) { + if (i == widgets_.end()) { + // Loop around if we allow it; otherwise abort. + if (selection_loops_to_parent()) { + ContainerWidget* w = parent_widget(); + if (w) { + w->SelectNextWidget(); + w->ShowWidget(w->selected_widget()); + } + return; + } else if (selected_widget_ + == nullptr) { // NOLINT(bugprone-branch-clone) + // We've got no selection and we've scanned the whole list to no avail, + // fail. + PrintExitListInstructions(old_last_prev_next_time); + return; + } else if (selection_loops()) { + i = widgets_.begin(); + } else { + PrintExitListInstructions(old_last_prev_next_time); + return; + } + } + + // If we had a selection, we abort if we've looped back to it. + if (&(**i) == selected_widget_) { + return; + } + if ((**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + SelectWidget(&(**i), SelectionCause::NEXT_SELECTED); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + return; + } + i++; + } +} + +// FIXME: should kill this. +void ContainerWidget::PrintExitListInstructions( + millisecs_t old_last_prev_next_time) { + if (should_print_list_exit_instructions_) { + millisecs_t t = g_game->master_time(); + if ((t - old_last_prev_next_time > 250) + && (t - last_list_exit_instructions_print_time_ > 5000)) { + last_list_exit_instructions_print_time_ = t; + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kErrorBeep)); + std::string s = g_game->GetResourceString("arrowsToExitListText"); + { + // Left arrow. + Utils::StringReplaceOne(&s, "${LEFT}", + g_game->CharStr(SpecialChar::kLeftArrow)); + } + { + // Right arrow. + Utils::StringReplaceOne(&s, "${RIGHT}", + g_game->CharStr(SpecialChar::kRightArrow)); + } + ScreenMessage(s); + } + } +} + +void ContainerWidget::SelectPrevWidget() { + BA_DEBUG_UI_READ_LOCK; + + millisecs_t old_last_prev_next_time = last_prev_next_time_; + if (should_print_list_exit_instructions_) { + last_prev_next_time_ = g_game->master_time(); + } + + // Grab the iterator for our selected widget if possible. + auto i = widgets_.rbegin(); + if (selected_widget_) { + for (; i != widgets_.rend(); i++) { + if ((&(**i) == selected_widget_)) { + break; + } + } + } + + if (selected_widget_) { + // If we have a selection we should have been able to find its iterator. + assert(&(**i) == selected_widget_); + i++; // Start with next one if we had this selected. + } + + while (true) { + if (i == widgets_.rend()) { + // Loop around if we allow it; otherwise abort. + if (selection_loops_to_parent()) { + ContainerWidget* w = parent_widget(); + if (w) { + w->SelectPrevWidget(); + w->ShowWidget(w->selected_widget()); + } + return; + } else if (selected_widget_ + == nullptr) { // NOLINT(bugprone-branch-clone) + // If we've got no selection and we've scanned the whole list to no + // avail, fail. + PrintExitListInstructions(old_last_prev_next_time); + return; + } else if (selection_loops()) { + i = widgets_.rbegin(); + } else { + PrintExitListInstructions(old_last_prev_next_time); + return; + } + } + + // If we had a selection, we abort if we loop back to it. + if (&(**i) == selected_widget_) { + return; + } + + if ((**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + SelectWidget(&(**i), SelectionCause::PREV_SELECTED); + g_audio->PlaySound(g_media->GetSound(SystemSoundID::kTap)); + return; + } + i++; + } +} + +auto ContainerWidget::HasKeySelectableChild() const -> bool { + for (auto i = widgets_.begin(); i != widgets_.end(); i++) { + assert(i->exists()); + if ((**i).IsSelectable() && (**i).IsSelectableViaKeys()) { + return true; + } + } + return false; +} + +void ContainerWidget::CheckLayout() { + if (needs_update_) { + managed_ = false; + UpdateLayout(); + managed_ = true; + needs_update_ = false; + } +} + +void ContainerWidget::MarkForUpdate() { + ContainerWidget* w = this; + while (w) { + if (!w->managed_) { + return; + } + w->needs_update_ = true; + w = w->parent_widget(); + } +} + +void ContainerWidget::OnLanguageChange() { + for (auto&& widget : widgets_) { + if (widget.exists()) { + widget->OnLanguageChange(); + } + } +} + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/container_widget.h b/src/ballistica/ui/widget/container_widget.h new file mode 100644 index 00000000..b8fa92f7 --- /dev/null +++ b/src/ballistica/ui/widget/container_widget.h @@ -0,0 +1,277 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_CONTAINER_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_CONTAINER_WIDGET_H_ + +#include +#include + +#include "ballistica/ui/widget/widget.h" + +namespace ballistica { + +// Base class for widgets that contain other widgets. +class ContainerWidget : public Widget { + public: + explicit ContainerWidget(float width = 0, float height = 0); + ~ContainerWidget() override; + + void Draw(RenderPass* pass, bool transparent) override; + + auto HandleMessage(const WidgetMessage& m) -> bool override; + + enum TransitionType { + TRANSITION_OUT_LEFT, + TRANSITION_OUT_RIGHT, + TRANSITION_IN_LEFT, + TRANSITION_IN_RIGHT, + TRANSITION_IN_SCALE, + TRANSITION_OUT_SCALE + }; + + void SetTransition(TransitionType t); + void SetCancelButton(ButtonWidget* button); + void SetStartButton(ButtonWidget* button); + void SetOnCancelCall(PyObject* call_tuple); + + // Set a widget to selected (must already have been added to dialog) + // Pass nullptr to deselect widgets. + void SelectWidget(Widget* w, SelectionCause s = SelectionCause::NONE); + void ReselectLastSelectedWidget(); + void ShowWidget(Widget* w); + void set_background(bool enable) { background_ = enable; } + void SetRootSelectable(bool enable); + void set_selectable(bool val) { selectable_ = val; } + + virtual void SetWidth(float w) { + bg_dirty_ = glow_dirty_ = true; + width_ = w; + MarkForUpdate(); + } + virtual void SetHeight(float h) { + bg_dirty_ = glow_dirty_ = true; + height_ = h; + MarkForUpdate(); + } + + void SetScaleOriginStackOffset(float x, float y) { + scale_origin_stack_offset_x_ = x; + scale_origin_stack_offset_y_ = y; + } + + // Note: Don't call these on yourself from within your CheckLayout() func. + // (reason is obvious if you look) - just use your values directly in that + // case. + auto GetWidth() -> float override { + CheckLayout(); + return width_; + } + auto GetHeight() -> float override { + CheckLayout(); + return height_; + } + + auto IsSelectable() -> bool override { return selectable_; } + + auto HasKeySelectableChild() const -> bool; + + void set_is_window_stack(bool a) { is_window_stack_ = a; } + auto is_window_stack() const -> bool { return is_window_stack_; } + + auto GetChildCount() const -> int { + assert(InGameThread()); + return static_cast(widgets_.size()); + } + void Clear(); + + void Activate() override; + + // Add a newly allocated widget to the container. + // This widget is now owned by the container and will be disposed by it. + void AddWidget(Widget* w); + + // Remove a widget from the container. + void DeleteWidget(Widget* w); + + // Select the next widget in the container's list. + void SelectNextWidget(); + + // Select the previous widget in the container's list. + void SelectPrevWidget(); + + void SelectDownWidget(); + void SelectUpWidget(); + void SelectLeftWidget(); + void SelectRightWidget(); + + // Return the currently selected widget, or nullptr if none selected. + auto selected_widget() -> Widget* { return selected_widget_; } + + auto GetWidgetTypeName() -> std::string override { return "container"; } + auto HasChildren() const -> bool override { return (!widgets_.empty()); } + + // Whether hitting 'next' at the last widget should loop back to the first. + // (generally true but list containers may not want) + auto selection_loops() const -> bool { return selection_loops_; } + + // If the selection doesn't loop, returns whether a selection loop transfers + // the message to the parent instead. + auto selection_loops_to_parent() const -> bool { + return selection_loops_to_parent_; + } + + void SetOnActivateCall(PyObject* c); + void SetOnOutsideClickCall(PyObject* c); + + auto widgets() const -> const std::vector >& { + return widgets_; + } + + void set_draggable(bool d) { draggable_ = d; } + void set_claims_tab(bool c) { claims_tab_ = c; } + void set_claims_left_right(bool c) { claims_left_right_ = c; } + void set_claims_up_down(bool c) { claims_up_down_ = c; } + void set_selection_loops_to_parent(bool d) { selection_loops_to_parent_ = d; } + auto claims_tab() const -> bool { return claims_tab_; } + auto claims_left_right() const -> bool { return claims_left_right_; } + auto claims_up_down() const -> bool { return claims_up_down_; } + void set_single_depth(bool s) { single_depth_ = s; } + + // Translate a point in-place into the space of a given child widget. + void TransformPointToChild(float* x, float* y, const Widget& child) const; + void TransformPointFromChild(float* x, float* y, const Widget& child) const; + + void set_color(float r, float g, float b, float a) { + red_ = r; + green_ = g; + blue_ = b; + alpha_ = a; + } + void set_should_print_list_exit_instructions(bool v) { + should_print_list_exit_instructions_ = v; + } + void set_selection_loops(bool loops) { selection_loops_ = loops; } + void set_click_activate(bool enabled) { click_activate_ = enabled; } + void set_always_highlight(bool enable) { always_highlight_ = enable; } + auto GetDrawBrightness(millisecs_t time) const -> float override; + auto IsAcceptingInput() const -> bool override; + void set_claims_outside_clicks(bool val) { claims_outside_clicks_ = val; } + void OnLanguageChange() override; + + void set_is_overlay_window_stack(bool val) { is_overlay_window_stack_ = val; } + void set_is_main_window_stack(bool val) { is_main_window_stack_ = val; } + + // Return the topmost widget that is accepting input. + // (used for toolbar focusing; may not always equal selected widget + // if the topmost one is transitioning out, etc.) + auto GetTopmostToolbarInfluencingWidget() -> Widget*; + + protected: + virtual void OnCancelCustom() {} + void set_single_depth_root(bool s) { single_depth_root_ = s; } + + // Note that the offsets here are purely for visual transitions and things; + // the UI itself only knows about the standard widget transform values. + void DrawChildren(RenderPass* pass, bool transparent, float x_offset, + float y_offset, float scale); + void SetSelected(bool s, SelectionCause cause) override; + void MarkForUpdate(); + + // Move/resize the contained widgets. + virtual void UpdateLayout() {} + void CheckLayout(); + + void set_modal_children(bool val) { modal_children_ = val; } + + auto width() const -> float { return width_; } + auto height() const -> float { return height_; } + void set_width(float val) { width_ = val; } + void set_height(float val) { height_ = val; } + + private: + // Given a container and a point, returns a selectable widget in the downward + // direction or nullptr. + auto GetClosestDownWidget(float x, float y, Widget* ignoreWidget) -> Widget*; + auto GetClosestUpWidget(float x, float y, Widget* ignoreWidget) -> Widget*; + auto GetClosestRightWidget(float x, float y, Widget* ignoreWidget) -> Widget*; + auto GetClosestLeftWidget(float x, float y, Widget* ignoreWidget) -> Widget*; + auto GetMult(millisecs_t current_time, bool for_glow = false) const -> float; + void PrintExitListInstructions(millisecs_t old_last_prev_next_time); + std::vector > widgets_; + float width_{}; + float height_{}; + bool modal_children_{}; + bool selection_loops_{true}; + bool is_main_window_stack_{}; + bool is_overlay_window_stack_{}; + float scale_origin_stack_offset_x_{}; + float scale_origin_stack_offset_y_{}; + float transition_scale_offset_x_{}; + float transition_scale_offset_y_{}; + bool pressed_{}; + bool mouse_over_{}; + bool pressed_activate_{}; + bool always_highlight_{}; + bool click_activate_{}; + float red_{0.4f}; + float green_{0.37f}; + float blue_{0.49f}; + float alpha_{1.0f}; + Object::Ref tex_; + SystemModelID bg_model_transparent_i_d_{}; + SystemModelID bg_model_opaque_i_d_{}; + float glow_width_{}, glow_height_{}, glow_center_x_{}, glow_center_y_{}; + float bg_width_{}, bg_height_{}, bg_center_x_{}, bg_center_y_{}; + millisecs_t last_activate_time_{}; + millisecs_t transition_start_time_{}; + float transition_target_offset_{}; + float drag_x_{}, drag_y_{}; + float transition_offset_x_{}; + float transition_offset_x_vel_{}; + float transition_offset_x_smoothed_{}; + float transition_offset_y_{}; + float transition_offset_y_vel_{}; + float transition_offset_y_smoothed_{}; + float transition_start_offset_{}; + float transition_scale_{1.0f}; + float d_transition_scale_{}; + millisecs_t dynamics_update_time_{}; + bool bg_dirty_{true}; + bool glow_dirty_{true}; + bool transitioning_{}; + TransitionType transition_type_{}; + bool transitioning_out_{}; + bool draggable_{}; + bool dragging_{}; + bool managed_{true}; + bool needs_update_{}; + bool claims_tab_{true}; + bool claims_left_right_{true}; + bool claims_up_down_{true}; + bool selection_loops_to_parent_{}; + bool is_window_stack_{}; + bool background_{true}; + bool root_selectable_{}; + bool selectable_{true}; + bool ignore_input_{}; + bool single_depth_{true}; + bool single_depth_root_{}; + bool should_print_list_exit_instructions_{}; + millisecs_t last_prev_next_time_{}; + millisecs_t last_list_exit_instructions_print_time_{}; + Widget* selected_widget_{}; + Widget* prev_selected_widget_{}; + Object::WeakRef cancel_button_; + Object::WeakRef start_button_; + bool claims_outside_clicks_{}; + + // Keep these at the bottom so they're torn down first. + // ...hmm that seems fragile; should I add explicit code to kill them? + Object::Ref on_activate_call_; + Object::Ref on_outside_click_call_; + Object::Ref on_cancel_call_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_WIDGET_CONTAINER_WIDGET_H_ diff --git a/src/ballistica/ui/widget/h_scroll_widget.cc b/src/ballistica/ui/widget/h_scroll_widget.cc new file mode 100644 index 00000000..a970d86f --- /dev/null +++ b/src/ballistica/ui/widget/h_scroll_widget.cc @@ -0,0 +1,810 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/h_scroll_widget.h" + +#include + +#include "ballistica/generic/real_timer.h" +#include "ballistica/graphics/component/empty_component.h" +#include "ballistica/graphics/component/simple_component.h" +#include "ballistica/graphics/graphics.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/platform/platform.h" +#include "ballistica/ui/ui.h" + +namespace ballistica { + +const float kHMargin = 5.0f; + +HScrollWidget::HScrollWidget() + : touch_mode_(!g_platform->IsRunningOnDesktop()) { + set_draggable(false); + set_claims_left_right(false); + set_claims_tab(false); +} + +HScrollWidget::~HScrollWidget() = default; + +void HScrollWidget::HandleRealTimerExpired(RealTimer* t) { + if (touch_held_) { + // Pass a mouse-down event if we haven't moved. + if (!touch_is_scrolling_ && !touch_down_sent_) { + ContainerWidget::HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseDown, nullptr, touch_x_, + touch_y_, touch_held_click_count_)); + touch_down_sent_ = true; + } else { + } + } + + // Clean ourself out. + touch_delay_timer_.Clear(); +} + +void HScrollWidget::ClampThumb(bool velocity_clamp, bool position_clamp) { + BA_DEBUG_UI_READ_LOCK; + bool is_scrolling = (touch_held_ || !has_momentum_); + float strong_force; + float weak_force; + if (touch_mode_) { + strong_force = -0.12f; + weak_force = -0.004f; + } else { + strong_force = -0.012f; + weak_force = -0.004f; + } + auto i = widgets().begin(); + if (i != widgets().end()) { + float child_w = (**i).GetWidth(); + + if (velocity_clamp) { + if (child_offset_h_ < 0) { + // even in velocity case do some sane clamping + float diff = child_offset_h_; + inertia_scroll_rate_ += + diff * (is_scrolling ? strong_force : weak_force); + inertia_scroll_rate_ *= 0.9f; + + } else if (child_offset_h_ + > child_w - (width() - 2 * (border_width_ + kHMargin))) { + float diff = + child_offset_h_ + - (child_w + - std::min(child_w, (width() - 2 * (border_width_ + kHMargin)))); + inertia_scroll_rate_ += + diff * (is_scrolling ? strong_force : weak_force); + inertia_scroll_rate_ *= 0.9f; + } + } + + // hard clipping if we're dragging the scrollbar + if (position_clamp) { + if (child_offset_h_smoothed_ + > child_w - (width() - 2 * (border_width_ + kHMargin))) { + child_offset_h_smoothed_ = + child_w - (width() - 2 * (border_width_ + kHMargin)); + } + if (child_offset_h_smoothed_ < 0) { + child_offset_h_smoothed_ = 0; + } + if (child_offset_h_ + > child_w - (width() - 2 * (border_width_ + kHMargin))) { + child_offset_h_ = child_w - (width() - 2 * (border_width_ + kHMargin)); + } + if (child_offset_h_ < 0) { + child_offset_h_ = 0; + } + } + } +} + +auto HScrollWidget::HandleMessage(const WidgetMessage& m) -> bool { + BA_DEBUG_UI_READ_LOCK; + bool claimed = false; + bool pass = true; + float bottom_overlap = 3; + switch (m.type) { + case WidgetMessage::Type::kShow: { + claimed = true; + pass = false; + auto i = widgets().begin(); + if (i == widgets().end()) break; + float child_w = (**i).GetWidth(); + + // see where we'd have to scroll to get selection at left and right + float child_offset_left = + child_w - m.fval1 - (width() - 2 * (border_width_ + kHMargin)); + float child_offset_right = child_w - m.fval1 - m.fval3; + + // if we're in the middle, dont do anything + if (child_offset_h_ > child_offset_left + && child_offset_h_ < child_offset_right) { + } else { + float prev_child_offset = child_offset_h_; + // do whatever offset is less of a move + if (std::abs(child_offset_left - child_offset_h_) + < std::abs(child_offset_right - child_offset_h_)) { + child_offset_h_ = child_offset_left; + } else { + child_offset_h_ = child_offset_right; + } + + // if we're moving left, stop at the end + { + float max_val = child_w - (width() - 2 * (border_width_ + kHMargin)); + if (child_offset_h_ > max_val) child_offset_h_ = max_val; + } + // if we're moving right, stop at the top + { + if (child_offset_h_ < prev_child_offset) { + if (child_offset_h_ < 0) child_offset_h_ = 0; + } + } + } + + // Go into smooth mode momentarily. + smoothing_amount_ = 1.0f; + + // Snap our smoothed value to this *only* if we haven't drawn yet + // (keeps new widgets from inexplicably scrolling around). + if (!have_drawn_) { + child_offset_h_smoothed_ = child_offset_h_; + } + MarkForUpdate(); + break; + } + case WidgetMessage::Type::kMouseMove: { + float x = m.fval1; + float y = m.fval2; + bool claimed2 = (m.fval3 > 0.0f); + + if (touch_mode_) { + mouse_over_ = false; + } else { + mouse_over_ = + ((y >= 0.0f) && (y < height()) && (x >= 0.0f) && (x < width())); + } + + if (!mouse_over_) { + pass = false; + } + + if (claimed2) { + mouse_over_thumb_ = false; + } else { + if (touch_mode_) { + if (touch_held_) { + touch_x_ = x; + touch_y_ = y; + + // if this is a new scroll-touch, see which direction the drag is + // happening; if it's primarily vertical lets disown it so it can + // get handled by the scroll widget above us (presumably a vertical + // scroll widget) + if (new_scroll_touch_) { + float x_diff = std::abs(touch_x_ - touch_start_x_); + float y_diff = std::abs(touch_y_ - touch_start_y_); + + float dist = x_diff * x_diff + y_diff * y_diff; + + // if they're somehow equal, wait and look at the next one.. + if (x_diff != y_diff && dist > 30.0f) { + new_scroll_touch_ = false; + + // If they haven't moved far enough yet, ignore it. + if (x_diff < y_diff) { + return false; + } + } + } + + // Handle generating delayed press/releases. + if (static_cast(m.type)) { // <- FIXME WHAT IS THIS FOR?? + // If we move more than a slight amount it means our touch isn't a + // click. + if (!touch_is_scrolling_ + && ((std::abs(touch_x_ - touch_start_x_) > 10.0f) + || (std::abs(touch_y_ - touch_start_y_) > 10.0f))) { + touch_is_scrolling_ = true; + + // Go ahead and send a mouse-up to the sub-widgets; in their + // eyes the click is canceled. + if (touch_down_sent_ && !touch_up_sent_) { + ContainerWidget::HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseUp, nullptr, + m.fval1, m.fval2, true)); + touch_up_sent_ = true; + } + } + } + return true; + } + } + + if (touch_mode_) { + mouse_over_thumb_ = false; + } else { + float s_right = width() - border_width_; + float s_left = border_width_; + float sb_thumb_width = + amount_visible_ * (width() - 2.0f * border_width_); + float sb_thumb_right = s_right + - child_offset_h_ / child_max_offset_ + * (s_right - (s_left + sb_thumb_width)); + + mouse_over_thumb_ = + (((y >= 0) && (y < scroll_bar_height_ + bottom_overlap) + && x < sb_thumb_right && x >= sb_thumb_right - sb_thumb_width)); + } + } + + // If we're dragging. + if (mouse_held_thumb_) { + auto i = widgets().begin(); + if (i == widgets().end()) { + break; + } + float child_w = (**i).GetWidth(); + float sRight = width() - border_width_; + float sLeft = border_width_; + float rate = + (child_w - (sRight - sLeft)) + / ((1.0f - ((sRight - sLeft) / child_w)) * (sRight - sLeft)); + child_offset_h_ = thumb_click_start_child_offset_h_ + - rate * (x - thumb_click_start_h_); + + ClampThumb(false, true); + + MarkForUpdate(); + } + break; + } + case WidgetMessage::Type::kMouseUp: { + mouse_held_scroll_down_ = false; + mouse_held_scroll_up_ = false; + mouse_held_thumb_ = false; + mouse_held_page_down_ = false; + mouse_held_page_up_ = false; + + if (touch_mode_) { + if (touch_held_) { + bool m_claimed = (m.fval3 > 0.0f); + + touch_held_ = false; + + // If we moved at all, we mark it as claimed to keep + // sub-widgets from acting on it (since we used it for scrolling). + bool claimed2 = touch_is_scrolling_ || m_claimed; + + // If we're not claiming it and we haven't sent a mouse_down yet due + // to our delay, send that first. + if (!claimed2 && !touch_down_sent_) { + ContainerWidget::HandleMessage(WidgetMessage( + WidgetMessage::Type::kMouseDown, nullptr, m.fval1, m.fval2, + static_cast(touch_held_click_count_))); + touch_down_sent_ = true; + } + if (touch_down_sent_ && !touch_up_sent_) { + ContainerWidget::HandleMessage( + WidgetMessage(WidgetMessage::Type::kMouseUp, nullptr, m.fval1, + m.fval2, claimed2)); + touch_up_sent_ = true; + } + return true; + } + } + + // If coords are outside of our bounds, pass a mouse-up along for anyone + // tracking a drag, but mark it as claimed so it doesn't actually get + // acted on. + float x = m.fval1; + float y = m.fval2; + if (!((y >= 0.0f) && (y < height()) && (x >= 0.0f) && (x < width()))) { + pass = false; + ContainerWidget::HandleMessage(WidgetMessage( + WidgetMessage::Type::kMouseUp, nullptr, m.fval1, m.fval2, true)); + } + + break; + } + + case WidgetMessage::Type::kMouseWheelVelocityH: { + float x = m.fval1; + float y = m.fval2; + if ((x >= 0.0f) && (x < width()) && (y >= 0.0f) && (y < height())) { + claimed = true; + pass = false; + has_momentum_ = static_cast(m.fval4); + + // We only set velocity from events when not in momentum mode; we + // handle momentum ourself. + if (std::abs(m.fval3) > 0.001f && !has_momentum_) { + float scroll_speed = 2.2f; + float smoothing = 0.8f; + float new_val; + if (m.fval3 < 0.0f) { + // Apply less if we're past the end. + if (child_offset_h_ < 0) { + new_val = scroll_speed * 0.1f * m.fval3; + } else { + new_val = scroll_speed * m.fval3; + } + } else { + // Apply less if we're past the end. + bool past_end = false; + + // Calc our total height. + auto i = widgets().begin(); + if (i != widgets().end()) { + float child_h = (**i).GetWidth(); + float diff = + child_offset_h_ + - (child_h + - std::min(child_h, + (width() - 2 * (border_width_ + kHMargin)))); + if (diff > 0) past_end = true; + } + if (past_end) { + new_val = scroll_speed * 0.1f * m.fval3; + } else { + new_val = scroll_speed * m.fval3; + } + } + inertia_scroll_rate_ = + smoothing * inertia_scroll_rate_ + (1.0f - smoothing) * new_val; + } + last_velocity_event_time_ = g_game->master_time(); + MarkForUpdate(); + } else { + // Not within our widget; dont allow children to claim. + pass = false; + } + break; + } + case WidgetMessage::Type::kMouseWheelH: { + float x = m.fval1; + float y = m.fval2; + if ((x >= 0.0f) && (x < width()) && (y >= 0.0f) && (y < height())) { + claimed = true; + pass = false; + inertia_scroll_rate_ -= m.fval3 * 0.003f; + MarkForUpdate(); + } else { + // Not within our widget; dont allow children to claim. + pass = false; + } + break; + } + case WidgetMessage::Type::kScrollMouseDown: + case WidgetMessage::Type::kMouseDown: { + float x = m.fval1; + float y = m.fval2; + + // If its in our overall scroll region at all. + if ((y >= 0.0f) && (y < height()) && (x >= 0.0f) && (x < width())) { + // On touch devices, clicks begin scrolling, (and eventually can count + // as clicks if they don't move) + if (touch_mode_) { + touch_held_ = true; + auto click_count = static_cast(m.fval3); + touch_held_click_count_ = click_count; + touch_down_sent_ = false; + touch_up_sent_ = false; + touch_start_x_ = x; + touch_start_y_ = y; + touch_x_ = x; + touch_y_ = y; + touch_down_x_ = x - child_offset_h_; + touch_is_scrolling_ = false; + + // If there's significant scrolling happening we never pass touches. + // they're only used to scroll more/less. + if (std::abs(inertia_scroll_rate_) > 0.05f) { + touch_is_scrolling_ = true; + } + + pass = false; + claimed = true; + + // Top level touches eventually get passed as mouse-downs if no + // scrolling has started. + if (static_cast(m.type)) { + touch_delay_timer_ = + Object::New>(150, false, this); + } + + // If we're handling a scroll-touch, take note that we need to + // decide whether to disown the touch or not. + if (m.type == WidgetMessage::Type::kScrollMouseDown) { + new_scroll_touch_ = true; + } + } + + // On desktop, allow clicking on the scrollbar. + if (!touch_mode_) { + if (y <= scroll_bar_height_ + bottom_overlap) { + claimed = true; + pass = false; + + float sRight = width() - border_width_; + float sLeft = border_width_; + float sb_thumb_width = + amount_visible_ * (width() - 2 * border_width_); + float sb_thumb_right = sRight + - child_offset_h_ / child_max_offset_ + * (sRight - (sLeft + sb_thumb_width)); + + // To right of thumb (page-right). + if (x >= sb_thumb_right) { + smoothing_amount_ = 1.0f; // So we can see the transition. + child_offset_h_ -= (width() - 2 * (border_width_ + kHMargin)); + MarkForUpdate(); + ClampThumb(false, true); + } else if (x >= sb_thumb_right - sb_thumb_width) { + // On thumb. + mouse_held_thumb_ = true; + thumb_click_start_h_ = x; + thumb_click_start_child_offset_h_ = child_offset_h_; + } else if (x >= sLeft) { + // To left of thumb (page left). + smoothing_amount_ = 1.0f; // So we can see the transition. + child_offset_h_ += (width() - 2 * (border_width_ + kHMargin)); + MarkForUpdate(); + ClampThumb(false, true); + } + } + } + } else { + pass = false; // Not in the scroll box; dont allow children to claim. + } + break; + } + default: + break; + } + + // Normal container event handling. + if (pass) { + if (ContainerWidget::HandleMessage(m)) claimed = true; + } + + // If it was a mouse-down and we claimed it, set ourself as selected. + if (m.type == WidgetMessage::Type::kMouseDown && claimed) { + GlobalSelect(); + } + return claimed; +} + +void HScrollWidget::UpdateLayout() { + BA_DEBUG_UI_READ_LOCK; + + // Move everything based on our offset. + auto i = widgets().begin(); + if (i == widgets().end()) { + amount_visible_ = 0; + return; + } + float child_w = (**i).GetWidth(); + child_max_offset_ = child_w - (width() - 2 * (border_width_ + kHMargin)); + amount_visible_ = (width() - 2 * (border_width_ + kHMargin)) / child_w; + if (amount_visible_ > 1) { + amount_visible_ = 1; + if (center_small_content_) { + center_offset_x_ = child_max_offset_ * 0.5f; + } else { + center_offset_x_ = 0; + } + } else { + center_offset_x_ = 0; + } + if (mouse_held_thumb_) { + if (child_offset_h_ + > child_w - (width() - 2 * (border_width_ + kHMargin))) { + child_offset_h_ = child_w - (width() - 2 * (border_width_ + kHMargin)); + inertia_scroll_rate_ = 0; + } + if (child_offset_h_ < 0) { + child_offset_h_ = 0; + inertia_scroll_rate_ = 0; + } + } + (**i).set_translate(width() - (border_width_ + kHMargin) + + child_offset_h_smoothed_ - child_w + + center_offset_x_, + 4 + border_height_); + thumb_dirty_ = true; +} + +void HScrollWidget::Draw(RenderPass* pass, bool draw_transparent) { + have_drawn_ = true; + millisecs_t current_time = pass->frame_def()->base_time(); + float prev_child_offset_h_smoothed = child_offset_h_smoothed_; + + // Ok, lets update our inertial scrolling during the opaque pass. + // (we really should have some sort of update() function for this but widgets + // don't have that currently) + if (!draw_transparent) { + // (skip huge differences) + if (current_time - inertia_scroll_update_time_ > 1000) + inertia_scroll_update_time_ = current_time - 1000; + while (current_time - inertia_scroll_update_time_ > 5) { + inertia_scroll_update_time_ += 5; + + if (touch_mode_) { + if (touch_held_) { + float diff = (touch_x_ - child_offset_h_) - touch_down_x_; + float smoothing = 0.7f; + inertia_scroll_rate_ = smoothing * inertia_scroll_rate_ + + (1.0f - smoothing) * 0.2f * diff; + } else { + inertia_scroll_rate_ *= 0.98f; + } + } else { + inertia_scroll_rate_ *= 0.98f; + } + + ClampThumb(true, mouse_held_thumb_); + child_offset_h_ += inertia_scroll_rate_; + + if (!has_momentum_ + && (current_time - last_velocity_event_time_ > 1000 / 30)) { + inertia_scroll_rate_ = 0; + } + + // Lastly we apply smoothing so that if we're snapping to a specific place + // we don't go instantly there we blend between smoothed and non-smoothed + // depending on whats driving us (we dont want to add smoothing on top of + // inertial scrolling for example or it'll feel muddy) + float diff = child_offset_h_ - child_offset_h_smoothed_; + if (std::abs(diff) < 1.0f) + child_offset_h_smoothed_ = child_offset_h_; + else + child_offset_h_smoothed_ += (1.0f - 0.95f * smoothing_amount_) * diff; + smoothing_amount_ = std::max(0.0f, smoothing_amount_ - 0.005f); + } + + // Only re-layout our widgets if we've moved a significant amount. + if (std::abs(prev_child_offset_h_smoothed - child_offset_h_smoothed_) + > 0.01f) { + MarkForUpdate(); + } + } + + CheckLayout(); + + Vector3f tilt = 0.02f * g_graphics->tilt(); + float extra_offs_x = tilt.y; + float extra_offs_y = -tilt.x; + + float b = 0; + float t = b + height(); + float l = 0; + float r = l + width(); + + // Begin clipping for children. + { + EmptyComponent c(pass); + c.SetTransparent(draw_transparent); + c.ScissorPush(Rect(l + border_width_, b + border_height_ + 1, + l + (width() - border_width_ - 0), + b + (height() - border_height_) - 1)); + c.Submit(); + } + + set_simple_culling_left(l + border_width_); + set_simple_culling_right(l + (width() - border_height_)); + + // Draw all our widgets at our z level. + DrawChildren(pass, draw_transparent, l + extra_offs_x, b + extra_offs_y, + 1.0f); + + // End clipping. + { + EmptyComponent c(pass); + c.SetTransparent(draw_transparent); + c.ScissorPop(); + c.Submit(); + } + + // scroll trough (depth 0.7f to 0.8f) + if (draw_transparent && border_opacity_ > 0.0f) { + if (trough_dirty_) { + float b2 = b + 4; + float t2 = b2 + scroll_bar_height_; + float l2; + float r2; + l2 = l + (border_width_); + r2 = r - (border_width_); + float b_border, t_border, l_border, r_border; + b_border = 3; + t_border = 0; + l_border = width() * 0.006f; + r_border = width() * 0.002f; + trough_height_ = t2 - b2 + b_border + t_border; + trough_width_ = r2 - l2 + l_border + r_border; + trough_center_y_ = b2 - b_border + trough_height_ * 0.5f; + trough_center_x_ = l2 - l_border + trough_width_ * 0.5f; + trough_dirty_ = false; + } + + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(1, 1, 1, border_opacity_); + c.SetTexture(g_media->GetTexture(SystemTextureID::kUIAtlas)); + c.PushTransform(); + c.Translate(trough_center_x_, trough_center_y_, 0.7f); + c.Scale(trough_width_, trough_height_, 0.1f); + c.Rotate(-90, 0, 0, 1); + c.DrawModel(g_media->GetModel(SystemModelID::kScrollBarTroughTransparent)); + c.PopTransform(); + c.Submit(); + } + + // scroll bars + if (amount_visible_ > 0 && amount_visible_ < 1) { + // scroll thumb at depth 0.8f-0.9 + { + float sb_thumb_width = amount_visible_ * (width() - 2 * border_width_); + if (thumb_dirty_) { + float sb_thumb_right = + r - border_width_ + - ((width() - (border_width_ * 2) - sb_thumb_width) + * child_offset_h_smoothed_ / child_max_offset_); + float b2 = 4; + float t2 = b2 + scroll_bar_height_; + float r2 = sb_thumb_right; + float l2 = r2 - sb_thumb_width; + float b_border, t_border, l_border, r_border; + b_border = 6; + t_border = 3; + if (sb_thumb_width > 100) { + auto wd = r2 - l2; + l_border = wd * 0.04f; + r_border = wd * 0.06f; + } else { + auto wd = r2 - l2; + r_border = wd * 0.12f; + l_border = wd * 0.08f; + } + thumb_height_ = t2 - b2 + b_border + t_border; + thumb_width_ = r2 - l2 + l_border + r_border; + + thumb_center_y_ = b2 - b_border + thumb_height_ * 0.5f; + thumb_center_x_ = l2 - l_border + thumb_width_ * 0.5f; + thumb_dirty_ = false; + } + + SimpleComponent c(pass); + c.SetTransparent(draw_transparent); + // float c_scale = 1.0f; + // if (mouse_held_thumb_) { + // c_scale = 1.8f; + // } else if (mouse_over_thumb_) { + // c_scale = 1.25f; + // } + + bool smooth_diff = + (std::abs(child_offset_h_smoothed_ - child_offset_h_) > 0.01f); + if (touch_mode_) { + if (smooth_diff || (touch_held_ && touch_is_scrolling_) + || std::abs(inertia_scroll_rate_) > 1.0f) { + touch_fade_ = std::min(1.5f, touch_fade_ + 0.02f); + } else { + // FIXME: Shouldn't be frame based. + touch_fade_ = std::max(0.0f, touch_fade_ - 0.015f); + } + } else { + if (smooth_diff || (touch_held_ && touch_is_scrolling_) + || std::abs(inertia_scroll_rate_) > 1.0f || mouse_over_) { + touch_fade_ = std::min(1.5f, touch_fade_ + 0.02f); + } else { + // FIXME: Shouldn't be frame based. + touch_fade_ = std::max(0.0f, touch_fade_ - 0.015f); + } + } + c.SetColor(0, 0, 0, std::min(1.0f, 0.3f * touch_fade_)); + + c.ScissorPush(Rect(l + border_width_, b + border_height_ + 1, + l + (width()), b + (height() * 0.995f))); + c.PushTransform(); + c.Translate(thumb_center_x_, thumb_center_y_, 0.8f); + c.Scale(-thumb_width_, thumb_height_, 0.1f); + c.FlipCullFace(); + c.Rotate(-90, 0, 0, 1); + + // on touch, just draw these transiently +#if 1 + if (draw_transparent) { + c.DrawModel(g_media->GetModel( + sb_thumb_width > 100 ? SystemModelID::kScrollBarThumbSimple + : SystemModelID::kScrollBarThumbShortSimple)); + } +#else + if (draw_transparent) { + c.DrawModel(g_media->GetModel( + sb_thumb_width > 100 + ? Media::SCROLL_BAR_THUMB_TRANSPARENT_MODEL + : Media::SCROLL_BAR_THUMB_SHORT_TRANSPARENT_MODEL)); + } else { + c.DrawModel(g_media->GetModel( + sb_thumb_width > 100 ? Media::SCROLL_BAR_THUMB_OPAQUE_MODEL + : Media::SCROLL_BAR_THUMB_SHORT_OPAQUE_MODEL)); + } +#endif + + c.FlipCullFace(); + c.PopTransform(); + c.ScissorPop(); + c.Submit(); + } + } + + // outline shadow (depth 0.9 to 1.0) + if (draw_transparent && border_opacity_ > 0.0f) { + if (shadow_dirty_) { + float r2 = l + width(); + float l2 = l; + float b2 = b; + float t2 = t; + float l_border, r_border, b_border, t_border; + l_border = (r2 - l2) * 0.005f; + r_border = (r2 - l2) * 0.001f; + b_border = (t2 - b2) * 0.006f; + t_border = (t2 - b2) * 0.002f; + outline_width_ = r2 - l2 + l_border + r_border; + outline_height_ = t2 - b2 + b_border + t_border; + outline_center_x_ = l2 - l_border + 0.5f * outline_width_; + outline_center_y_ = b2 - b_border + 0.5f * outline_height_; + shadow_dirty_ = false; + } + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(1, 1, 1, border_opacity_); + c.SetTexture(g_media->GetTexture(SystemTextureID::kScrollWidget)); + c.PushTransform(); + c.Translate(outline_center_x_, outline_center_y_, 0.9f); + c.Scale(outline_width_, outline_height_, 0.1f); + c.DrawModel(g_media->GetModel(SystemModelID::kSoftEdgeOutside)); + c.PopTransform(); + c.Submit(); + } + + // if selected, do glow at depth 0.9-1.0 + if (draw_transparent && IsHierarchySelected() + && g_ui->ShouldHighlightWidgets() && highlight_ + && border_opacity_ > 0.0f) { + float m = 0.8f + + std::abs(sinf(static_cast(current_time) * 0.006467f)) + * 0.2f * border_opacity_; + + if (glow_dirty_) { + float r2 = l + width(); + float l2 = l; + float b2 = b; + float t2 = t; + float l_border, r_border, b_border, t_border; + l_border = (r2 - l2) * 0.02f; + r_border = (r2 - l2) * 0.02f; + b_border = (t2 - b2) * 0.015f; + t_border = (t2 - b2) * 0.01f; + glow_width_ = r2 - l2 + l_border + r_border; + glow_height_ = t2 - b2 + b_border + t_border; + glow_center_x_ = l2 - l_border + 0.5f * glow_width_; + glow_center_y_ = b2 - b_border + 0.5f * glow_height_; + glow_dirty_ = false; + } + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetPremultiplied(true); + c.SetColor(0.4f * m, 0.5f * m, 0.05f * m, 0.0f); + c.SetTexture(g_media->GetTexture(SystemTextureID::kScrollWidgetGlow)); + c.PushTransform(); + c.Translate(glow_center_x_, glow_center_y_, 0.9f); + c.Scale(glow_width_, glow_height_, 0.1f); + c.DrawModel(g_media->GetModel(SystemModelID::kSoftEdgeOutside)); + c.PopTransform(); + c.Submit(); + } +} + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/h_scroll_widget.h b/src/ballistica/ui/widget/h_scroll_widget.h new file mode 100644 index 00000000..6ff5a375 --- /dev/null +++ b/src/ballistica/ui/widget/h_scroll_widget.h @@ -0,0 +1,120 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_H_SCROLL_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_H_SCROLL_WIDGET_H_ + +#include + +#include "ballistica/ui/widget/container_widget.h" + +namespace ballistica { + +template +class RealTimer; + +// A scroll-box container widget. +class HScrollWidget : public ContainerWidget { + public: + HScrollWidget(); + ~HScrollWidget() override; + void Draw(RenderPass* pass, bool transparent) override; + auto HandleMessage(const WidgetMessage& m) -> bool override; + auto GetWidgetTypeName() -> std::string override { return "scroll"; } + void set_capture_arrows(bool val) { capture_arrows_ = val; } + void SetWidth(float w) override { + trough_dirty_ = shadow_dirty_ = glow_dirty_ = thumb_dirty_ = true; + set_width(w); + MarkForUpdate(); + } + void SetHeight(float h) override { + trough_dirty_ = shadow_dirty_ = glow_dirty_ = thumb_dirty_ = true; + set_height(h); + MarkForUpdate(); + } + void SetCenterSmallContent(bool val) { + center_small_content_ = val; + MarkForUpdate(); + } + void HandleRealTimerExpired(RealTimer* t); + void setColor(float r, float g, float b) { + color_red_ = r; + color_green_ = g; + color_blue_ = b; + } + void set_highlight(bool val) { highlight_ = val; } + auto highlight() const -> bool { return highlight_; } + void setBorderOpacity(float val) { border_opacity_ = val; } + auto getBorderOpacity() const -> float { return border_opacity_; } + + protected: + void UpdateLayout() override; + + private: + void ClampThumb(bool velocity_clamp, bool position_clamp); + + bool touch_mode_{}; + float color_red_{0.55f}; + float color_green_{0.47f}; + float color_blue_{0.67f}; + bool has_momentum_{true}; + bool trough_dirty_{true}; + bool shadow_dirty_{true}; + bool glow_dirty_{true}; + bool thumb_dirty_{true}; + millisecs_t last_velocity_event_time_{}; + float touch_fade_{}; + bool center_small_content_{}; + float center_offset_x_{}; + bool touch_held_{}; + int touch_held_click_count_{}; + float touch_down_x_{}; + float touch_x_{}; + float touch_y_{}; + float touch_start_x_{}; + float touch_start_y_{}; + bool touch_is_scrolling_{}; + bool touch_down_sent_{}; + bool touch_up_sent_{}; + bool new_scroll_touch_{}; + float trough_width_{}; + float trough_height_{}; + float trough_center_x_{}; + float trough_center_y_{}; + float thumb_width_{}, thumb_height_{}, thumb_center_x_{}, thumb_center_y_{}; + float smoothing_amount_{1.0f}; + bool highlight_{true}; + float glow_width_{}; + float glow_height_{}; + float glow_center_x_{}; + float glow_center_y_{}; + float outline_width_{}; + float outline_height_{}; + float outline_center_x_{}; + float outline_center_y_{}; + float border_opacity_{1.0f}; + bool capture_arrows_{}; + bool mouse_held_scroll_down_{}; + bool mouse_held_scroll_up_{}; + bool mouse_held_thumb_{}; + float thumb_click_start_h_{}; + float thumb_click_start_child_offset_h_{}; + bool mouse_held_page_down_{}; + bool mouse_held_page_up_{}; + bool mouse_over_thumb_{}; + bool mouse_over_{}; + float scroll_bar_height_{10.0f}; + float border_width_{2.0f}; + float border_height_{2.0f}; + float child_offset_h_{-9999.0f}; + float child_offset_h_smoothed_{}; + float child_max_offset_{}; + float amount_visible_{}; + bool have_drawn_{}; + millisecs_t inertia_scroll_update_time_{}; + float inertia_scroll_rate_{}; + Object::Ref > touch_delay_timer_; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_WIDGET_H_SCROLL_WIDGET_H_ diff --git a/src/ballistica/ui/widget/image_widget.cc b/src/ballistica/ui/widget/image_widget.cc new file mode 100644 index 00000000..906b7ff3 --- /dev/null +++ b/src/ballistica/ui/widget/image_widget.cc @@ -0,0 +1,180 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/image_widget.h" + +#include "ballistica/game/game.h" +#include "ballistica/graphics/component/simple_component.h" + +namespace ballistica { + +ImageWidget::ImageWidget() { birth_time_ = g_game->master_time(); } + +ImageWidget::~ImageWidget() = default; + +auto ImageWidget::GetWidth() -> float { return width_; } +auto ImageWidget::GetHeight() -> float { return height_; } + +void ImageWidget::Draw(RenderPass* pass, bool draw_transparent) { + if (opacity_ < 0.001f) { + return; + } + + millisecs_t current_time = pass->frame_def()->base_time(); + + Vector3f tilt = tilt_scale_ * 0.01f * g_graphics->tilt(); + if (draw_control_parent()) tilt += 0.02f * g_graphics->tilt(); + float extra_offs_x = -tilt.y; + float extra_offs_y = tilt.x; + + // Simple transition. + float transition = (birth_time_ + transition_delay_) - current_time; + if (transition > 0) { + extra_offs_x -= transition * 4.0f; + } + + float l = 0; + float r = l + width_; + float b = 0; + float t = b + height_; + + if (texture_.exists()) { + if (texture_->texture_data()->loaded() + && ((!tint_texture_.exists()) + || tint_texture_->texture_data()->loaded()) + && ((!mask_texture_.exists()) + || mask_texture_->texture_data()->loaded())) { + if (image_dirty_) { + image_width_ = r - l; + image_height_ = t - b; + image_center_x_ = l + image_width_ * 0.5f; + image_center_y_ = b + image_height_ * 0.5f; + image_dirty_ = false; + } + + Object::Ref model_opaque_used; + if (model_opaque_.exists()) { + model_opaque_used = model_opaque_->model_data(); + } + Object::Ref model_transparent_used; + if (model_transparent_.exists()) { + model_transparent_used = model_transparent_->model_data(); + } + + bool draw_radial_opaque = false; + bool draw_radial_transparent = false; + + // if no meshes were provided, use default image models + if ((!model_opaque_.exists()) && (!model_transparent_.exists())) { + if (has_alpha_channel_) { + if (radial_amount_ < 1.0f) { + draw_radial_transparent = true; + } else { + model_transparent_used = + g_media->GetModel(SystemModelID::kImage1x1); + } + } else { + if (radial_amount_ < 1.0f) { + draw_radial_opaque = true; + } else { + model_opaque_used = g_media->GetModel(SystemModelID::kImage1x1); + } + } + } + + // Draw brightness. + float db = 1.0f; + if (Widget* draw_controller = draw_control_parent()) { + db *= draw_controller->GetDrawBrightness(current_time); + } + + // Opaque portion may get drawn transparent or opaque depending on our + // global opacity. + if (model_opaque_used.exists() || draw_radial_opaque) { + bool should_draw = false; + bool should_draw_transparent = false; + + // Draw our opaque model in the opaque pass. + if (!draw_transparent && opacity_ > 0.999f) { + should_draw = true; + should_draw_transparent = false; + } else if (draw_transparent && opacity_ <= 0.999f) { + // Draw our opaque model in the transparent pass. + should_draw = true; + should_draw_transparent = true; + } + + if (should_draw) { + SimpleComponent c(pass); + c.SetTransparent(should_draw_transparent); + c.SetColor(color_red_ * db, color_green_ * db, color_blue_ * db, + opacity_); + c.SetTexture(texture_); + if (tint_texture_.exists()) { + c.SetColorizeTexture(tint_texture_); + c.SetColorizeColor(tint_color_red_, tint_color_green_, + tint_color_blue_); + c.SetColorizeColor2(tint2_color_red_, tint2_color_green_, + tint2_color_blue_); + } + c.SetMaskTexture(mask_texture_); + c.PushTransform(); + c.Translate(image_center_x_ + extra_offs_x, + image_center_y_ + extra_offs_y); + c.Scale(image_width_, image_height_, 1.0f); + if (draw_radial_opaque) { + if (!radial_mesh_.exists()) { + radial_mesh_ = Object::NewDeferred(); + } + Graphics::DrawRadialMeter(&(*radial_mesh_), radial_amount_); + c.Scale(0.5f, 0.5f, 1.0f); + c.DrawMesh(radial_mesh_.get()); + } else { + c.DrawModel(model_opaque_used.get()); + } + c.PopTransform(); + c.Submit(); + } + } + + // Always-transparent portion. + if ((model_transparent_used.exists() || draw_radial_transparent) + && draw_transparent) { + SimpleComponent c(pass); + c.SetTransparent(true); + c.SetColor(color_red_ * db, color_green_ * db, color_blue_ * db, + opacity_); + c.SetTexture(texture_); + if (tint_texture_.exists()) { + c.SetColorizeTexture(tint_texture_); + c.SetColorizeColor(tint_color_red_, tint_color_green_, + tint_color_blue_); + c.SetColorizeColor2(tint2_color_red_, tint2_color_green_, + tint2_color_blue_); + } + c.SetMaskTexture(mask_texture_); + c.PushTransform(); + c.Translate(image_center_x_ + extra_offs_x, + image_center_y_ + extra_offs_y); + c.Scale(image_width_, image_height_, 1.0f); + if (draw_radial_transparent) { + if (!radial_mesh_.exists()) { + radial_mesh_ = Object::New(); + } + Graphics::DrawRadialMeter(&(*radial_mesh_), radial_amount_); + c.Scale(0.5f, 0.5f, 1.0f); + c.DrawMesh(radial_mesh_.get()); + } else { + c.DrawModel(model_transparent_used.get()); + } + c.PopTransform(); + c.Submit(); + } + } + } +} + +auto ImageWidget::HandleMessage(const WidgetMessage& m) -> bool { + return false; +} + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/image_widget.h b/src/ballistica/ui/widget/image_widget.h new file mode 100644 index 00000000..00979437 --- /dev/null +++ b/src/ballistica/ui/widget/image_widget.h @@ -0,0 +1,118 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_IMAGE_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_IMAGE_WIDGET_H_ + +#include + +#include "ballistica/media/component/model.h" +#include "ballistica/media/component/texture.h" +#include "ballistica/ui/widget/widget.h" + +namespace ballistica { + +class ImageWidget : public Widget { + public: + ImageWidget(); + ~ImageWidget() override; + void Draw(RenderPass* pass, bool transparent) override; + auto HandleMessage(const WidgetMessage& m) -> bool override; + void set_width(float width) { + image_dirty_ = true; + width_ = width; + } + void set_height(float val) { + image_dirty_ = true; + height_ = val; + } + auto GetWidth() -> float override; + auto GetHeight() -> float override; + void set_has_alpha_channel(bool val) { has_alpha_channel_ = val; } + void set_color(float r, float g, float b) { + color_red_ = r; + color_green_ = g; + color_blue_ = b; + } + void set_tint_color(float r, float g, float b) { + tint_color_red_ = r; + tint_color_green_ = g; + tint_color_blue_ = b; + } + void set_tint2_color(float r, float g, float b) { + tint2_color_red_ = r; + tint2_color_green_ = g; + tint2_color_blue_ = b; + } + void set_opacity(float o) { opacity_ = o; } + void SetTexture(Texture* val) { + if (val && !val->IsFromUIContext()) + throw Exception("texture is not from the UI context: " + + val->GetObjectDescription()); + texture_ = val; + } + void SetTintTexture(Texture* val) { + if (val && !val->IsFromUIContext()) + throw Exception("texture is not from the UI context: " + + val->GetObjectDescription()); + tint_texture_ = val; + } + void SetMaskTexture(Texture* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("texture is not from the UI context: " + + val->GetObjectDescription()); + } + mask_texture_ = val; + } + void SetModelTransparent(Model* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("model_transparent is not from UI context"); + } + image_dirty_ = true; + model_transparent_ = val; + } + void SetModelOpaque(Model* val) { + if (val && !val->IsFromUIContext()) { + throw Exception("model_opaque is not from UI context"); + } + image_dirty_ = true; + model_opaque_ = val; + } + auto GetWidgetTypeName() -> std::string override { return "image"; } + void set_transition_delay(float val) { transition_delay_ = val; } + void set_tilt_scale(float s) { tilt_scale_ = s; } + void set_radial_amount(float val) { radial_amount_ = val; } + + private: + float tilt_scale_{1.0f}; + float transition_delay_{}; + millisecs_t birth_time_{}; + Object::Ref texture_; + Object::Ref tint_texture_; + Object::Ref mask_texture_; + Object::Ref model_transparent_; + Object::Ref model_opaque_; + Object::Ref radial_mesh_; + float image_width_{}; + float image_height_{}; + float image_center_x_{}; + float image_center_y_{}; + float radial_amount_{1.0f}; + bool image_dirty_{true}; + float width_{50.0f}; + float height_{30.0f}; + bool has_alpha_channel_{true}; + float color_red_{1.0f}; + float color_green_{1.0f}; + float color_blue_{1.0f}; + float tint_color_red_{1.0f}; + float tint_color_green_{1.0f}; + float tint_color_blue_{1.0f}; + float tint2_color_red_{1.0f}; + float tint2_color_green_{1.0f}; + float tint2_color_blue_{1.0f}; + float opacity_{1.0f}; +}; + +} // namespace ballistica + +#endif // BALLISTICA_UI_WIDGET_IMAGE_WIDGET_H_ diff --git a/src/ballistica/ui/widget/root_widget.cc b/src/ballistica/ui/widget/root_widget.cc new file mode 100644 index 00000000..af5738f9 --- /dev/null +++ b/src/ballistica/ui/widget/root_widget.cc @@ -0,0 +1,1138 @@ +// Released under the MIT License. See LICENSE for details. + +#include "ballistica/ui/widget/root_widget.h" + +#include + +#include "ballistica/game/game.h" +#include "ballistica/game/session/host_session.h" +#include "ballistica/graphics/renderer.h" +#include "ballistica/input/input.h" +#include "ballistica/python/python.h" +#include "ballistica/ui/ui.h" +#include "ballistica/ui/widget/button_widget.h" +#include "ballistica/ui/widget/image_widget.h" +#include "ballistica/ui/widget/stack_widget.h" + +namespace ballistica { + +// color we mult toolbars by in medium and large ui modes +// (in small mode we keep them more the normal window color since everything +// overlaps) +#define TOOLBAR_COLOR_R 0.75f +#define TOOLBAR_COLOR_G 0.85f +#define TOOLBAR_COLOR_B 0.85f + +#define TOOLBAR_BACK_COLOR_R 0.8f +#define TOOLBAR_BACK_COLOR_G 0.8f +#define TOOLBAR_BACK_COLOR_B 0.8f + +// opacity in med/large +#define TOOLBAR_OPACITY 1.0f + +// opacity in small +#define TOOLBAR_OPACITY_2 1.0f + +#define BOT_LEFT_COLOR_R 0.6 +#define BOT_LEFT_COLOR_G 0.6 +#define BOT_LEFT_COLOR_B 0.8 + +// for defining toolbar buttons. +struct RootWidget::ButtonDef { + float h_align{}; + VAlign v_align{VAlign::kTop}; + float x{}; + float y{}; + float width{100.0f}; + float height{30.0f}; + float scale{1.0f}; + float depth_min{}; + float depth_max{1.0f}; + std::string label; + std::string img; + std::string model_transparent; + std::string model_opaque; + Python::ObjID call{Python::ObjID::kEmptyCall}; + float color_r{1.0f}; + float color_g{1.0f}; + float color_b{1.0f}; + float opacity{1.0f}; + bool selectable{true}; + uint32_t visibility_mask{}; +}; + +struct RootWidget::Button { + Object::Ref widget; + float h_align{}; + VAlign v_align{VAlign::kTop}; + float x{}; // user provided x + float y{}; // user provided y + float x_target{}; // final target x (accounting for visibility, etc) + float y_target{}; // final target y (accounting for visibility, etc) + float x_smoothed{}; // current x (on way to target) + float y_smoothed{}; // current y (on way to target) + float width{100.0f}; + float height{30.0f}; + float scale{1.0f}; + bool selectable{true}; + int visibility_mask{}; +}; + +// for adding text label decorations to buttons +struct RootWidget::TextDef { + Button* button = nullptr; + float x = 0.0f; + float y = 0.0f; + float width = -1.0f; + float scale = 1.0f; + float depth_min = 0.0f; + float depth_max = 1.0f; + float color_r = 1.0f; + float color_g = 1.0f; + float color_b = 1.0f; + float color_a = 1.0f; + float flatness = 0.5f; + float shadow = 0.5f; + std::string text; +}; + +struct RootWidget::Text { + Button* button{}; + Object::Ref widget; + float x{}; + float y{}; +}; + +RootWidget::RootWidget() { + // we enable a special 'single-depth-root' mode + // in which we use most of our depth range for our first child + // (our screen stack) and the small remaining bit for the rest + set_single_depth(true); + set_single_depth_root(true); + set_background(false); +} + +RootWidget::~RootWidget() = default; + +auto RootWidget::AddCover(float h_align, VAlign v_align, float x, float y, + float w, float h, float o) -> RootWidget::Button* { + // currently just not doing these in vr mode + if (IsVRMode()) { + return nullptr; + } + + ButtonDef bd; + bd.h_align = h_align; + bd.v_align = v_align; + bd.width = w; + bd.height = h; + bd.x = x; + bd.y = y; + bd.img = "softRect"; + bd.selectable = false; + bd.color_r = 0.0f; + bd.color_g = 0.0f; + bd.color_b = 0.0f; + bd.opacity = o; + bd.call = Python::ObjID::kEmptyCall; + + bd.visibility_mask = + static_cast(Widget::ToolbarVisibility::kMenuFullRoot); + // when the user specifies no backing it means they intend to cover the screen + // with a flat-ish window texture.. however this only applies to phone-size; + // for other sizes we always draw a backing. + if (GetInterfaceType() != UIScale::kSmall) { + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuFull); + } + + Button* b = AddButton(bd); + return b; +} + +void RootWidget::AddMeter(float h_align, float x, int type, float r, float g, + float b, bool plus, const std::string& s) { + float yoffs = (GetInterfaceType() == UIScale::kSmall) ? 0.0f : -7.0f; + + float width = type == 1 ? 80.0f : 110.0f; + // bar + { + ButtonDef bd; + bd.h_align = h_align; + bd.v_align = VAlign::kTop; + bd.width = width; + bd.height = 36.0f; + bd.x = x; + bd.y = -36.0f + 10.0f + yoffs; + bd.img = "uiAtlas2"; + bd.model_transparent = "currencyMeter"; + bd.selectable = false; + bd.color_r = 0.32f; + bd.color_g = 0.30f; + bd.color_b = 0.4f; + if (GetInterfaceType() != UIScale::kSmall) { + bd.color_r *= TOOLBAR_COLOR_R; + bd.color_g *= TOOLBAR_COLOR_G; + bd.color_b *= TOOLBAR_COLOR_B; + } + bd.depth_min = 0.3f; + bd.call = Python::ObjID::kEmptyCall; + bd.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + + // show in currency mode + if (type == 2 || type == 3) { + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuCurrency); + } + Button* btn = AddButton(bd); + + // Bar value text. + { + TextDef td; + td.button = btn; + td.width = bd.width * 0.7f; + td.text = s; + td.scale = 0.8f; + td.flatness = 1.0f; + td.shadow = 1.0f; + td.depth_min = 0.3f; + AddText(td); + } + } + // Icon on left. + { + ButtonDef bd; + bd.h_align = h_align; + bd.v_align = VAlign::kTop; + bd.width = bd.height = 50.0f; + if (type == 0 || type == 1) { + bd.x = x - width * 0.5f - 10.0f; + } else { + bd.x = x + width * 0.5f + 10.0f; + } + bd.y = -32.0f + 7.0f + yoffs; + bd.color_r = r; + bd.color_g = g; + bd.color_b = b; + bd.depth_min = 0.3f; + switch (type) { + case 0: + bd.img = "levelIcon"; + bd.call = Python::ObjID::kLevelIconPressCall; + break; + case 1: + bd.img = "trophy"; + bd.call = Python::ObjID::kTrophyIconPressCall; + break; + case 2: + bd.img = "coin"; + bd.call = Python::ObjID::kCoinIconPressCall; + break; + case 3: + bd.img = "tickets"; + bd.call = Python::ObjID::kTicketIconPressCall; + break; + default: + break; + } + bd.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + // show in currency mode + if (type == 2 || type == 3) { + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuCurrency); + } + Button* btn = AddButton(bd); + switch (type) { // NOLINT + case 3: + tickets_info_button_ = btn; + break; + default: + break; + } + + // Level num. + if (type == 0) { + TextDef td; + td.button = btn; + td.width = bd.width * 0.8f; + td.text = "12"; + td.x = -1.6f; + td.y = 0.8f; + td.scale = 0.9f; + td.flatness = 1.0f; + td.shadow = 1.0f; + td.depth_min = 0.3f; + td.color_r = 1.0f; + td.color_g = 1.0f; + td.color_b = 1.0f; + AddText(td); + } + } + // plus button + if (plus) { + ButtonDef bd; + bd.h_align = h_align; + bd.v_align = VAlign::kTop; + bd.width = bd.height = 45.0f; + // bd.x = x + 72; + bd.x = x - 68; + bd.y = -36.0f + 11.0f + yoffs; + bd.img = "uiAtlas2"; + bd.model_transparent = "currencyPlusButton"; + bd.color_r = 0.35f; + bd.color_g = 0.35f; + bd.color_b = 0.55f; + if (GetInterfaceType() != UIScale::kSmall) { + bd.color_r *= TOOLBAR_COLOR_R; + bd.color_g *= TOOLBAR_COLOR_G; + bd.color_b *= TOOLBAR_COLOR_B; + } + bd.depth_min = 0.3f; + bd.call = Python::ObjID::kEmptyCall; + bd.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + + // Show in currency mode. + if (type == 2 || type == 3) { + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuCurrency); + } + Button* btn = AddButton(bd); + if (type == 3) { + tickets_plus_button_ = btn; + } + } +} + +void RootWidget::Setup() { +#if BA_TOOLBAR_TEST + + // back button + { + ButtonDef bd; + bd.h_align = 0.0f; + bd.v_align = VAlign::kTop; + bd.width = bd.height = 140.0f; + bd.color_r = 0.7f; + bd.color_g = 0.4f; + bd.color_b = 0.35f; + + bd.x = 40.0f; + bd.y = -40.0f; + bd.img = "nub"; + bd.call = Python::ObjID::kBackButtonPressCall; + bd.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuMinimal) + | static_cast(Widget::ToolbarVisibility::kMenuFull)); + Button* b = back_button_ = AddButton(bd); + + // clan + { + TextDef td; + td.button = b; + td.x = 5.0f; + td.y = 3.0f; + td.width = bd.width * 0.9f; + td.text = g_game->CharStr(SpecialChar::kBack); + td.color_a = 1.0f; + td.scale = 2.0f; + td.flatness = 0.0f; + td.shadow = 0.5f; + AddText(td); + } + } + + // widen this a bit in small mode so it just covers most of the top + // - that looks funny in medium/large mode though + // if (GetInterfaceType() == UIScale::kSmall) { + // AddCover(0.5f, VAlign::kTop, 0.0f, 320.0f, + // GetInterfaceType() == UIScale::kSmall ? 1000.0f : + // 1000.0f, 800.0f, 0.4f); + // } + // if (c) { + // c->visibility_mask |= + // static_cast(Widget::ToolbarVisibility::kMenuCurrency); + // } + + // top bar backing (currency only) + if (false) { + ButtonDef bd; + bd.h_align = 0.5f; + bd.v_align = VAlign::kTop; + bd.width = 370.0f; + // if (GetInterfaceType() != UIScale::kSmall) { + // bd.width = 950.0f; + // } + bd.height = 90.0f; + bd.x = 256.0f; + bd.y = -20.0f; + bd.img = "uiAtlas2"; + // if (GetInterfaceType() != UIScale::kSmall) { + // bd.model_transparent = "toolbarBackingTop"; + // } else { + bd.model_transparent = "toolbarBackingTop2"; + // } + bd.selectable = false; + bd.color_r = 0.44f; + bd.color_g = 0.41f; + bd.color_b = 0.56f; + bd.opacity = 1.0f; + // if (GetInterfaceType() != UIScale::kSmall) { + // bd.color_r *= TOOLBAR_COLOR_R; + // bd.color_g *= TOOLBAR_COLOR_G; + // bd.color_b *= TOOLBAR_COLOR_B; + // bd.opacity *= TOOLBAR_OPACITY; + // } else { + // bd.opacity *= TOOLBAR_OPACITY_2; + // } + bd.depth_min = 0.2f; + // bd.call = ""; + bd.call = Python::ObjID::kEmptyCall; + + // bd.visibility_mask = + // static_cast(Widget::ToolbarVisibility::kMenuFullRoot); + // bd.visibility_mask |= + // static_cast(Widget::ToolbarVisibility::kMenuFull); + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuCurrency); + AddButton(bd); + } + + // top bar backing + if (false) { + ButtonDef bd; + bd.h_align = 0.5f; + bd.v_align = VAlign::kTop; + bd.width = 850.0f; + if (GetInterfaceType() != UIScale::kSmall) { + bd.width = 850.0f; + } + bd.height = 90.0f; + bd.x = 0.0f; + bd.y = -20.0f; + bd.img = "uiAtlas2"; + if (GetInterfaceType() != UIScale::kSmall) { + bd.model_transparent = "toolbarBackingTop2"; + } else { + bd.model_transparent = "toolbarBackingTop2"; + } + bd.selectable = false; + bd.color_r = 0.44f; + bd.color_g = 0.41f; + bd.color_b = 0.56f; + bd.opacity = 1.0f; + if (GetInterfaceType() != UIScale::kSmall) { + bd.color_r *= TOOLBAR_COLOR_R * TOOLBAR_BACK_COLOR_R; + bd.color_g *= TOOLBAR_COLOR_G * TOOLBAR_BACK_COLOR_G; + bd.color_b *= TOOLBAR_COLOR_B * TOOLBAR_BACK_COLOR_B; + bd.opacity *= TOOLBAR_OPACITY; + } else { + bd.opacity *= TOOLBAR_OPACITY_2; + } + bd.depth_min = 0.2f; + // bd.call = ""; + bd.call = Python::ObjID::kEmptyCall; + bd.visibility_mask = + static_cast(Widget::ToolbarVisibility::kMenuFullRoot); + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuFull); + // bd.visibility_mask |= + // static_cast(Widget::ToolbarVisibility::kMenuCurrency); + AddButton(bd); + } + + float yoffs = (GetInterfaceType() == UIScale::kSmall) ? 0.0f : -10.0f; + + // account button + { + ButtonDef bd; + bd.h_align = 0.1f; + bd.v_align = VAlign::kTop; + bd.width = 160.0f; + bd.height = 60.0f; + bd.depth_min = 0.3f; + bd.x = (GetInterfaceType() == UIScale::kSmall) ? 100.0f : -50.0f; + bd.y = -24.0f + yoffs; + bd.color_r = 0.56f; + bd.color_g = 0.5f; + bd.color_b = 0.73f; + if (GetInterfaceType() != UIScale::kSmall) { + bd.color_r *= TOOLBAR_COLOR_R; + bd.color_g *= TOOLBAR_COLOR_G; + bd.color_b *= TOOLBAR_COLOR_B; + } + // bd.call = ""; + bd.call = Python::ObjID::kEmptyCall; + bd.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + + // on desktop, stick this in the top left corner + // if (GetInterfaceType() == UIScale::kLarge) { + // bd.h_align = 0.0f; + // bd.x = 120.0f; + // } + + Button* b = account_button_ = AddButton(bd); + + // player name + { + TextDef td; + td.button = b; + td.y = 9.0f; + td.width = bd.width * 0.9f; + td.text = "Player Name"; + td.scale = 1.2f; + td.depth_min = 0.3f; + td.color_r = 0.5f; + td.color_g = 0.8f; + td.color_b = 0.8f; + td.shadow = 1.0f; + AddText(td); + } + // clan + { + TextDef td; + td.button = b; + td.y = -12.0f; + td.width = bd.width * 0.9f; + td.depth_min = 0.3f; + td.text = "Clan Name"; + td.color_a = 0.6f; + td.scale = 0.6f; + td.flatness = 1.0f; + td.shadow = 0.0f; + AddText(td); + } + } + + float anchorx = (GetInterfaceType() == UIScale::kSmall) ? 0.3f : 0.25f; + + AddMeter(anchorx, 200.0f - 148.0f, 0, 1.0f, 1.0f, 1.0f, false, "456/1000"); + AddMeter(anchorx, 200.0f, 1, 1.0f, 1.0f, 1.0f, false, "123"); + + AddMeter(0.7f, -100.0f, 2, 1.0f, 1.0f, 1.0f, true, "12343"); + AddMeter(0.7f, -100.0f + 188.0f, 3, 1.0f, 1.0f, 1.0f, true, "123"); + + // party button + { + ButtonDef b; + b.h_align = 1.0f; + b.v_align = VAlign::kTop; + b.width = b.height = 70.0f; + b.x = -110.0f; + b.y = b.height * -0.41f; + b.img = "usersButton"; + b.call = Python::ObjID::kFriendsButtonPressCall; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kInGame) + | static_cast(Widget::ToolbarVisibility::kMenuMinimal) + | static_cast(Widget::ToolbarVisibility::kMenuMinimalNoBack) + | static_cast(Widget::ToolbarVisibility::kMenuCurrency) + | static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + party_button_ = AddButton(b); + } + + // menu button (only shows up when we're not in a menu) + // FIXME - this should never be visible on TV or VR UI modes + { + ButtonDef b; + b.h_align = 1.0f; + b.v_align = VAlign::kTop; + b.width = b.height = 65.0f; + b.x = -36.0f; + b.y = b.height * -0.48f; + b.img = "menuButton"; + b.call = Python::ObjID::kBackButtonPressCall; + b.color_r = 0.3f; + b.color_g = 0.5f; + b.color_b = 0.2f; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kInGame) + | static_cast(Widget::ToolbarVisibility::kMenuMinimal) + | static_cast(Widget::ToolbarVisibility::kMenuMinimalNoBack) + | static_cast(Widget::ToolbarVisibility::kMenuCurrency) + | static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + menu_button_ = AddButton(b); + } + + // bot-left cover + // AddCover(0.0f, VAlign::kBottom, 0.0f, -210.0f, 600.0f, 600.0f, 0.25f); + + float bx = 45.0f; + + // log button + { + ButtonDef b; + b.h_align = 0.0f; + b.v_align = VAlign::kBottom; + b.width = b.height = 50.0f; + b.x = bx; + b.y = b.height * 0.5f + 5; + b.color_r = BOT_LEFT_COLOR_R; + b.color_g = BOT_LEFT_COLOR_G; + b.color_b = BOT_LEFT_COLOR_B; + b.img = "logIcon"; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + AddButton(b); + } + + bx += 70.0f; + + // achievements button + { + ButtonDef b; + b.h_align = 0.0f; + b.v_align = VAlign::kBottom; + b.width = b.height = 50.0f; + b.x = bx; + b.y = b.height * 0.5f + 5; + b.color_r = BOT_LEFT_COLOR_R; + b.color_g = BOT_LEFT_COLOR_G; + b.color_b = BOT_LEFT_COLOR_B; + b.img = "achievementsIcon"; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + AddButton(b); + } + + bx += 70.0f; + + // leaderboards button + { + ButtonDef b; + b.h_align = 0.0f; + b.v_align = VAlign::kBottom; + b.width = b.height = 50.0f; + b.x = bx; + b.y = b.height * 0.5f + 5; + b.color_r = BOT_LEFT_COLOR_R; + b.color_g = BOT_LEFT_COLOR_G; + b.color_b = BOT_LEFT_COLOR_B; + b.img = "leaderboardsIcon"; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + AddButton(b); + } + + bx += 70.0f; + + // settings button + { + ButtonDef b; + b.h_align = 0.0f; + b.v_align = VAlign::kBottom; + b.width = b.height = 50.0f; + b.x = bx; + b.y = b.height * 0.58f; + b.color_r = BOT_LEFT_COLOR_R; + b.color_g = BOT_LEFT_COLOR_G; + b.color_b = BOT_LEFT_COLOR_B; + b.img = "settingsIcon"; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + settings_button_ = AddButton(b); + } + + // chests + { + // AddCover(0.5f, VAlign::kBottom, 0.0f, -180.0f, 600.0f, 550.0f, 0.35f); + + float backingR = 0.44f; + float backingG = 0.41f; + float backingB = 0.56f; + float backingCoverR = backingR; + float backingCoverG = backingG; + float backingCoverB = backingB; + float backingA = 1.0f; + if (GetInterfaceType() != UIScale::kSmall) { + backingR *= TOOLBAR_COLOR_R * TOOLBAR_BACK_COLOR_R; + backingG *= TOOLBAR_COLOR_G * TOOLBAR_BACK_COLOR_G; + backingB *= TOOLBAR_COLOR_B * TOOLBAR_BACK_COLOR_B; + backingCoverR *= TOOLBAR_COLOR_R; + backingCoverG *= TOOLBAR_COLOR_G; + backingCoverB *= TOOLBAR_COLOR_B; + backingA *= TOOLBAR_OPACITY; + } else { + backingR *= 1.1f; + backingG *= 1.1f; + backingB *= 1.1f; + backingCoverR *= 1.1f; + backingCoverG *= 1.1f; + backingCoverB *= 1.1f; + backingA *= TOOLBAR_OPACITY_2; + } + + // bar backing + { + ButtonDef bd; + bd.h_align = 0.5f; + bd.v_align = VAlign::kBottom; + bd.width = 550.0f; + bd.height = 110.0f; + bd.x = 0.0f; + bd.y = 41.0f; + bd.img = "uiAtlas2"; + if (GetInterfaceType() != UIScale::kSmall) { + bd.model_transparent = "toolbarBackingBottom2"; + } else { + bd.model_transparent = "toolbarBackingBottom2"; + } + bd.selectable = false; + bd.color_r = backingR; + bd.color_g = backingG; + bd.color_b = backingB; + bd.opacity = backingA; + + bd.depth_min = 0.2f; + // bd.call = ""; + bd.call = Python::ObjID::kEmptyCall; + bd.visibility_mask = + static_cast(Widget::ToolbarVisibility::kMenuFullRoot); + bd.visibility_mask |= + static_cast(Widget::ToolbarVisibility::kMenuFull); + + AddButton(bd); + } + + ButtonDef b; + b.h_align = 0.5f; + b.v_align = VAlign::kBottom; + b.width = b.height = 110.0f; + b.x = 0.0f; + b.y = b.height * 0.4f; + b.img = "chestIcon"; + b.depth_min = 0.3f; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + float spacing = 110.0f; + b.x = -2.0f * spacing; + AddButton(b); + + b.x = -1.0f * spacing; + b.img = "chestOpenIcon"; + b.y = b.height * 0.5f; + AddButton(b); + + // test - empty icons + b.y = b.height * 0.4f; + b.x = 0.0f; + b.img = "chestIconEmpty"; + b.width = b.height = 80.0f; + b.color_r = backingCoverR; + b.color_g = backingCoverG; + b.color_b = backingCoverB; + b.opacity = 1.0f; + AddButton(b); + b.x = 1.0f * spacing; + AddButton(b); + b.x = 2.0f * spacing; + + // test - multi-icon tile + b.img = "chestIconMulti"; + AddButton(b); + } + + // bot-right cover + // AddCover(1.0f, VAlign::kBottom, 0.0f, -210.0f, 600.0f, 600.0f, 0.25f); + + // // settings button + // { + // ButtonDef b; + // b.h_align = 1.0f; + // b.v_align = VAlign::kBottom; + // b.width = b.height = 50.0f; + // b.x = -225.0f; + // b.y = b.height * 0.5f + 10; + // b.img = "settingsIcon"; + // b.visibility_mask = + // (static_cast(Widget::ToolbarVisibility::kMenuFull) + // | + // static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + // AddButton(b); + // } + + // store button + { + ButtonDef b; + b.h_align = 1.0f; + b.v_align = VAlign::kBottom; + b.width = b.height = 85.0f; + b.x = -206.0f; + b.y = b.height * 0.5f; + b.img = "storeIcon"; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + AddButton(b); + } + + // inventory button + { + ButtonDef b; + b.h_align = 1.0f; + b.v_align = VAlign::kBottom; + b.width = b.height = 135.0f; + b.x = -80.0f; + b.y = b.height * 0.45f; + b.img = "inventoryIcon"; + b.visibility_mask = + (static_cast(Widget::ToolbarVisibility::kMenuFull) + | static_cast(Widget::ToolbarVisibility::kMenuFullRoot)); + AddButton(b); + } + +#endif // BA_TOOLBAR_TEST + + UpdateForFocusedWindow(nullptr); +} + +void RootWidget::Draw(RenderPass* pass, bool transparent) { + // Opaque pass gets drawn first; use that as an opportunity to step up our + // motion. + if (!transparent) { + millisecs_t current_time = pass->frame_def()->base_time(); + float time_diff = std::min(millisecs_t{100}, current_time - update_time_); + StepPositions(time_diff); + update_time_ = current_time; + } + ContainerWidget::Draw(pass, transparent); +} + +auto RootWidget::AddButton(const ButtonDef& def) -> RootWidget::Button* { + ScopedSetContext cp(g_game->GetUIContextTarget()); + buttons_.emplace_back(); + Button& b(buttons_.back()); + b.x = b.x_smoothed = b.x_target = def.x; + b.y = b.y_smoothed = b.y_target = def.y; + b.visibility_mask = def.visibility_mask; + b.scale = def.scale; + b.width = def.width; + b.height = def.height; + b.h_align = def.h_align; + b.v_align = def.v_align; + b.selectable = def.selectable; + b.widget = Object::New(); + b.widget->SetColor(def.color_r, def.color_g, def.color_b); + b.widget->set_opacity(def.opacity); + b.widget->set_auto_select(true); + b.widget->SetText(def.label); + b.widget->set_enabled(def.selectable); + b.widget->set_selectable(def.selectable); + b.widget->SetDepthRange(def.depth_min, def.depth_max); + + // make sure up/down moves focus into the main stack + assert(screen_stack_widget_ != nullptr); + assert(b.v_align != VAlign::kCenter); + if (b.v_align == VAlign::kTop) { + b.widget->set_down_widget(screen_stack_widget_); + } else { + b.widget->set_up_widget(screen_stack_widget_); + } + // we wanna prevent anyone from redirecting these to point to outside widgets + // since we'll probably outlive those outside widgets + b.widget->set_neighbors_locked(true); + + if (!def.img.empty()) { + b.widget->SetTexture(g_ui->GetTexture(def.img).get()); + } + if (!def.model_transparent.empty()) { + b.widget->SetModelTransparent(g_ui->GetModel(def.model_transparent).get()); + } + if (!def.model_opaque.empty()) { + b.widget->SetModelOpaque(g_ui->GetModel(def.model_opaque).get()); + } + if (Python::ObjID::kEmptyCall != def.call) { + b.widget->set_on_activate_call(g_python->obj(def.call).get()); + } + AddWidget(b.widget.get()); + return &b; +} + +auto RootWidget::AddText(const TextDef& def) -> RootWidget::Text* { + ScopedSetContext cp(g_game->GetUIContextTarget()); + texts_.emplace_back(); + Text& t(texts_.back()); + t.button = def.button; + t.widget = Object::New(); + t.widget->SetWidth(0.0f); + t.widget->SetHeight(0.0f); + t.widget->set_halign(TextWidget::HAlign::kCenter); + t.widget->set_valign(TextWidget::VAlign::kCenter); + t.widget->SetText(def.text); + t.widget->set_max_width(def.width); + t.widget->set_center_scale(def.scale); + t.widget->set_color(def.color_r, def.color_g, def.color_b, def.color_a); + t.widget->set_shadow(def.shadow); + t.widget->set_flatness(def.flatness); + t.widget->SetDepthRange(def.depth_min, def.depth_max); + assert(def.button->widget.exists()); + t.widget->set_draw_control_parent(def.button->widget.get()); + t.x = def.x; + t.y = def.y; + AddWidget(t.widget.get()); + return &t; +} + +void RootWidget::UpdateForFocusedWindow() { + UpdateForFocusedWindow( + screen_stack_widget_ != nullptr + ? screen_stack_widget_->GetTopmostToolbarInfluencingWidget() + : nullptr); +} + +void RootWidget::UpdateForFocusedWindow(Widget* widget) { + // Take note if the current session is the main menu; we do a few things + // differently there. + HostSession* s = g_game->GetForegroundContext().GetHostSession(); + in_main_menu_ = (s ? s->is_main_menu() : false); + + if (widget == nullptr) { + toolbar_visibility_ = ToolbarVisibility::kInGame; + } else { + toolbar_visibility_ = widget->toolbar_visibility(); + } + MarkForUpdate(); +} + +void RootWidget::StepPositions(float dt) { + if (!positions_dirty_) { + return; + } + + // Go through our buttons updating their target points and smooth values. + // If everything has arrived at its target point, mark us as not dirty. + bool have_dirty = false; + for (Button& b : buttons_) { + // Update our target position. + b.x_target = b.x; + b.y_target = b.y; + float disable_offset = + 110.0f * ((b.v_align == VAlign::kTop) ? 1.0f : -1.0f); + // float top_right_offset = 100.0f; + + // Can turn this down to debug visibility. + if (explicit_bool(false)) { + disable_offset *= 0.5f; + // top_right_offset *= 0.5f; + } + bool enable_button = + static_cast(static_cast(toolbar_visibility_) + & static_cast(b.visibility_mask)); + + // when we're in the main menu, always disable the menu button + // and shift the party button a bit to the right + if (in_main_menu_) { + if (&b == menu_button_) { + enable_button = false; + } + if (&b == party_button_) { + b.x_target += 70.0f; + } + } + if (&b == back_button_) { + // back button is always disabled in medium/large UI + if (GetInterfaceType() != UIScale::kSmall) { + enable_button = false; + } + + // whenever back button is enabled, left on account button should go to + // it; otherwise it goes nowhere. + Widget* ab = account_button_->widget.get(); + ab->set_neighbors_locked(false); + ab->set_left_widget(enable_button ? back_button_->widget.get() : ab); + account_button_->widget->set_neighbors_locked(true); + } + + if (!enable_button) { + b.y_target += disable_offset; + } + + // special case: we shift buttons on the top right to the right if the menu + // button is hidden (and also if the button is hidden; otherwise things come + // in diagonally) + // if (b.h_align == HAlign::kRight and b.v_align == VAlign::kTop + // if (b.h_align >= 1.0f and b.v_align == VAlign::kTop + // and (toolbar_visibility_ != ToolbarVisibility::kInGame or not + // enable_button)) { + // b.x_target += top_right_offset; + // } + + // Now push our smooth value towards our target value... + b.x_smoothed += (b.x_target - b.x_smoothed) * 0.015f * dt; + b.y_smoothed += (b.y_target - b.y_smoothed) * 0.015f * dt; + + // Snap in place once we reach the target; otherwise note + // that we need to keep going. + if (std::abs(b.x_target - b.x_smoothed) < 0.1f + && std::abs(b.y_target - b.y_smoothed) < 0.1f) { + b.x_smoothed = b.x_target; + b.y_smoothed = b.y_target; + + // Also flip off visibility if we're moving offscreen and have reached our + // target. + if (!enable_button) { + b.widget->set_visible_in_container(false); + } + } else { + have_dirty = true; + // Always remain visible while still moving. + b.widget->set_visible_in_container(true); + } + + // Now calc final abs x and y based on screen size, smoothed positions, etc. + float x, y; + x = width() * b.h_align + + base_scale_ * (b.x_smoothed - b.width * b.scale * 0.5f); + switch (b.v_align) { + case VAlign::kTop: + y = height() + base_scale_ * (b.y_smoothed - b.height * b.scale * 0.5f); + break; + case VAlign::kCenter: + y = height() * 0.5f + + base_scale_ * (b.y_smoothed - b.height * b.scale * 0.5f); + break; + case VAlign::kBottom: + y = base_scale_ * (b.y_smoothed - b.height * b.scale * 0.5f); + break; + } + b.widget->set_selectable(enable_button && b.selectable); + b.widget->set_enabled(enable_button && b.selectable); + b.widget->set_translate(x, y); + b.widget->set_width(b.width); + b.widget->set_height(b.height); + b.widget->set_scale(b.scale * base_scale_); + } + + for (Text& t : texts_) { + // Move the text widget to wherever its target button is (plus offset). + Button* b = t.button; + float x = + b->widget->tx() + base_scale_ * b->scale * (b->width * 0.5f + t.x); + float y = + b->widget->ty() + base_scale_ * b->scale * (b->height * 0.5f + t.y); + t.widget->set_translate(x, y); + t.widget->set_scale(base_scale_ * b->scale); + } + + positions_dirty_ = have_dirty; +} + +void RootWidget::UpdateLayout() { + // Now actually put things in place. + base_scale_ = 1.0f; + switch (GetInterfaceType()) { + case UIScale::kLarge: + base_scale_ = 0.6f; + break; + case UIScale::kMedium: + base_scale_ = 0.8f; + break; + default: + base_scale_ = 1.0f; + break; + } + + // TEST - cycle through our scales +#if 0 + { + int foo = time(nullptr) % 3; + if (foo == 0) { + base_scale_ = 1.0f; + } else if (foo == 1) { + base_scale_ = 0.75f; + } else { + base_scale_ = 0.5f; + } + } +#endif + + // Update the window stack. + BA_DEBUG_UI_READ_LOCK; + if (screen_stack_widget_ != nullptr) { + screen_stack_widget_->set_translate(0, 0); + screen_stack_widget_->SetWidth(width()); + screen_stack_widget_->SetHeight(height()); + } + if (overlay_stack_widget_ != nullptr) { + overlay_stack_widget_->set_translate(0, 0); + overlay_stack_widget_->SetWidth(width()); + overlay_stack_widget_->SetHeight(height()); + } + positions_dirty_ = true; + + // Run an immediate step to update things; (avoids jumpy positions if + // resizing game window)) + StepPositions(0.0f); +} + +auto RootWidget::HandleMessage(const WidgetMessage& m) -> bool { + // If a cancel message comes through and our back button is active, fire our + // back button. + // ..in all other cases just do the default. + if (m.type == WidgetMessage::Type::kCancel && back_button_ != nullptr + && back_button_->widget->enabled() + && !overlay_stack_widget_->HasChildren()) { + back_button_->widget->Activate(); + return true; + } else { + return ContainerWidget::HandleMessage(m); + } +} + +void RootWidget::SetScreenWidget(StackWidget* w) { + // this needs to happen before any buttons get added.. + assert(buttons_.empty()); + AddWidget(w); + screen_stack_widget_ = w; +} + +void RootWidget::SetOverlayWidget(StackWidget* w) { + // this needs to happen after our buttons and things get added.. +#if BA_TOOLBAR_TEST + assert(!buttons_.empty()); +#endif // BA_TOOLBAR_TEST + AddWidget(w); + overlay_stack_widget_ = w; +} + +void RootWidget::OnCancelCustom() { + // if we've got any toolbar buttons selected and hit cancel, flip back to the + // main screen stack SelectWidget(screen_stack_widget_); cout << "ROOT CUSTOM + // CANCEL" << endl; + g_input->HandleBackPress(true); +} + +auto RootWidget::GetSpecialWidget(const std::string& s) const -> Widget* { + if (s == "party_button") { + return party_button_ ? party_button_->widget.get() : nullptr; + } else if (s == "tickets_plus_button") { + return tickets_plus_button_ ? tickets_plus_button_->widget.get() : nullptr; + } else if (s == "back_button") { + return back_button_ ? back_button_->widget.get() : nullptr; + } else if (s == "account_button") { + return account_button_ ? account_button_->widget.get() : nullptr; + } else if (s == "settings_button") { + return settings_button_ ? settings_button_->widget.get() : nullptr; + } else if (s == "tickets_info_button") { + return tickets_info_button_ ? tickets_info_button_->widget.get() : nullptr; + } else if (s == "overlay_stack") { + return overlay_stack_widget_; + } + return nullptr; +} + +} // namespace ballistica diff --git a/src/ballistica/ui/widget/root_widget.h b/src/ballistica/ui/widget/root_widget.h new file mode 100644 index 00000000..3949f373 --- /dev/null +++ b/src/ballistica/ui/widget/root_widget.h @@ -0,0 +1,68 @@ +// Released under the MIT License. See LICENSE for details. + +#ifndef BALLISTICA_UI_WIDGET_ROOT_WIDGET_H_ +#define BALLISTICA_UI_WIDGET_ROOT_WIDGET_H_ + +#include +#include + +#include "ballistica/ui/widget/container_widget.h" + +namespace ballistica { + +// Root-level widget; contains a top-bar, screen-stack, bottom-bar, menu-button, +// etc. This is intended to replace RootUI. +class RootWidget : public ContainerWidget { + public: + RootWidget(); + ~RootWidget() override; + auto GetWidgetTypeName() -> std::string override { return "root"; } + void SetScreenWidget(StackWidget* w); + void SetOverlayWidget(StackWidget* w); + void UpdateForFocusedWindow(); + void Setup(); + auto HandleMessage(const WidgetMessage& m) -> bool override; + void Draw(RenderPass* pass, bool transparent) override; + auto GetSpecialWidget(const std::string& s) const -> Widget*; + auto base_scale() const -> float { return base_scale_; } + auto overlay_window_stack() const -> StackWidget* { + return overlay_stack_widget_; + } + + private: + struct ButtonDef; + struct Button; + struct TextDef; + struct Text; + enum class VAlign { kTop, kCenter, kBottom }; + void UpdateForFocusedWindow(Widget* widget); + void OnCancelCustom() override; + void UpdateLayout() override; + auto AddButton(const ButtonDef& def) -> Button*; + auto AddText(const TextDef& def) -> Text*; + void StepPositions(float dt); + void AddMeter(float h_align, float x, int type, float r, float g, float b, + bool plus, const std::string& s); + auto AddCover(float h_align, VAlign v_align, float x, float y, float w, + float h, float o) -> Button*; + StackWidget* screen_stack_widget_{}; + StackWidget* overlay_stack_widget_{}; + float base_scale_{1.0f}; + std::list